From efc8db208e601173342129ccc23dd7611d8e196a Mon Sep 17 00:00:00 2001 From: Chris Ahlstrom Date: Thu, 11 May 2023 12:24:35 -0400 Subject: [PATCH] Working out config-file issues with normal and NSM usage. --- INSTALL | 20 +++-- configure.ac | 4 +- include/config.h.in | 2 +- libseq66/include/cfg/rcsettings.hpp | 3 +- libseq66/include/sessions/smanager.hpp | 4 +- libseq66/src/cfg/cmdlineopts.cpp | 2 +- libseq66/src/cfg/midicontrolfile.cpp | 13 ++- libseq66/src/cfg/rcsettings.cpp | 110 +++++++++++++++---------- libseq66/src/cfg/usrfile.cpp | 3 +- libseq66/src/sessions/clinsmanager.cpp | 6 +- libseq66/src/sessions/smanager.cpp | 29 +++---- libseq66/src/util/filefunctions.cpp | 22 ++--- 12 files changed, 124 insertions(+), 94 deletions(-) diff --git a/INSTALL b/INSTALL index 44785396..9efb6eb4 100644 --- a/INSTALL +++ b/INSTALL @@ -1,6 +1,6 @@ INSTALL for Seq66 v. 0.99.5 and above Chris Ahlstrom -2015-09-10 to 2023-05-06 +2015-09-10 to 2023-05-10 Getting Seq66 requires building the code or going to "sequencer64-packages/seq66" on GitHub to get an installation package. The bootstrap setup is primarily @@ -518,10 +518,20 @@ DEPENDENCIES: Raspberry Pi: - A few notes while trying to get Seq66 built on a Raspberry Pi 3 Model - B+. The Raspian on this board, installed via NOOB, could ultimately not - load some Qt dependences. Ended up installing OpenSUSE, and installed - Qt Creator to save time. + A few notes while trying to get Seq66 built on a Raspberry Pi 3 Model + B+. The Raspian on this board, installed via NOOB, could ultimately + not load some Qt dependences. Ended up installing OpenSUSE, and + installed Qt Creator to save time. + + Windows Installer: + + One can build the Windows installer under Linux (see the "nsis" + sub-directory). To build it on Windows, install the NSIS 3 + program, available at + + https://sourceforge.net/projects/nsis/files/NSIS%203/3.08/nsis-3.08-setup.exe/download + + Be sure to add the location of makensis.exe to the Windows PATH. Runtime: diff --git a/configure.ac b/configure.ac index 298e7846..349b13e0 100644 --- a/configure.ac +++ b/configure.ac @@ -6,7 +6,7 @@ dnl \file configure.ac dnl \library Seq66 dnl \author Chris Ahlstrom dnl \date 2018-11-09 -dnl \update 2023-04-30 +dnl \update 2023-05-11 dnl \version $Revision$ dnl \license $XPC_SUITE_GPL_LICENSE$ dnl @@ -480,7 +480,7 @@ dnl automatically for us. AH_TOP( -#define VERSION_DATE_SHORT "2023-04-30" +#define VERSION_DATE_SHORT "2023-05-11" #define API_VERSION "0.99" #define VERSION "0.99.5" diff --git a/include/config.h.in b/include/config.h.in index 7d870a69..09dd8d9b 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -1,6 +1,6 @@ /* include/config.h.in. Generated from configure.ac by autoheader. */ -#define VERSION_DATE_SHORT "2023-04-30" +#define VERSION_DATE_SHORT "2023-05-11" #define API_VERSION "0.99" #define VERSION "0.99.5" diff --git a/libseq66/include/cfg/rcsettings.hpp b/libseq66/include/cfg/rcsettings.hpp index 6a6ab4bc..fc26a2c1 100644 --- a/libseq66/include/cfg/rcsettings.hpp +++ b/libseq66/include/cfg/rcsettings.hpp @@ -334,7 +334,8 @@ class rcsettings final : public basesettings /** * An optional appendage to the base configuration directory. It is - * appended to the default session/configuration path. It is set only + * appended to the default session/configuration path. The setter, + * config_subdirectory, is meant to work only once. It is set only * by the --home option. The boolean makes sure the appending is done only * once (due to processing command-line options multiple times, :-(.) */ diff --git a/libseq66/include/sessions/smanager.hpp b/libseq66/include/sessions/smanager.hpp index 1466d0bf..2571a1b2 100644 --- a/libseq66/include/sessions/smanager.hpp +++ b/libseq66/include/sessions/smanager.hpp @@ -28,7 +28,7 @@ * \library seq66 application * \author Chris Ahlstrom * \date 2020-05-30 - * \updates 2023-04-17 + * \updates 2023-05-11 * \license GNU GPLv2 or above * * This class provides a process for starting, running, restarting, and @@ -182,7 +182,7 @@ class smanager const std::string & path, std::string & outcfgpath, std::string & outmidipath, - const std::string & midisubdir = "" + const std::string & midisubdir = "midi" ); bool import_into_session ( diff --git a/libseq66/src/cfg/cmdlineopts.cpp b/libseq66/src/cfg/cmdlineopts.cpp index 5e9cd2ef..62d9e100 100644 --- a/libseq66/src/cfg/cmdlineopts.cpp +++ b/libseq66/src/cfg/cmdlineopts.cpp @@ -238,7 +238,7 @@ static const std::string s_help_1b = " -B, --buss b Covers the 'bus' versus 'buss' confusion.\n" " -l, --client-name label Use this name instead of 'seq66'. Overridden by a\n" " session manager.\n" -" -q, --ppqn qn Specify default PPQN to replace 192. The MIDI file\n" +" -q, --ppqn qn Specify default PPQN to replace 192. The MIDI file\n" " can specify its own PPQN.\n" " -p, --priority Run high priority, FIFO scheduler (needs root).\n" " -P, --pass-sysex Passes incoming SysEx messages to all outputs.\n" diff --git a/libseq66/src/cfg/midicontrolfile.cpp b/libseq66/src/cfg/midicontrolfile.cpp index 4d345114..c9f2aeea 100644 --- a/libseq66/src/cfg/midicontrolfile.cpp +++ b/libseq66/src/cfg/midicontrolfile.cpp @@ -25,7 +25,7 @@ * \library seq66 application * \author Chris Ahlstrom * \date 2018-11-13 - * \updates 2023-04-17 + * \updates 2023-05-11 * \license GNU GPLv2 or above * * This class handles the 'ctrl' file. @@ -422,8 +422,11 @@ midicontrolfile::parse () result = false; } else + { result = parse_stream(file); - + if (! result) + file_error("Read failed", name()); + } return result; } @@ -1206,11 +1209,7 @@ read_midi_control_file ) { midicontrolfile mcf(fname, rcs); - bool result = mcf.parse(); - if (! result) - file_error("Read failed", fname); - - return result; + return mcf.parse(); } /** diff --git a/libseq66/src/cfg/rcsettings.cpp b/libseq66/src/cfg/rcsettings.cpp index ad605606..db05cb5e 100644 --- a/libseq66/src/cfg/rcsettings.cpp +++ b/libseq66/src/cfg/rcsettings.cpp @@ -25,7 +25,7 @@ * \library seq66 application * \author Seq24 team; modifications by Chris Ahlstrom * \date 2015-09-22 - * \updates 2023-05-10 + * \updates 2023-05-11 * \license GNU GPLv2 or above * * Note that this module also sets the legacy global variables, so that @@ -86,7 +86,7 @@ rcsettings::rcsettings () : m_with_jack_master (false), m_with_jack_master_cond (false), #if defined SEQ66_RTMIDI_SUPPORT - m_with_jack_midi (true), + m_with_jack_midi (true), /* hmmmmmmmmmm */ #else m_with_jack_midi (false), #endif @@ -144,6 +144,7 @@ rcsettings::rcsettings () : m_playlist_filename += ".playlist"; m_notemap_filename += ".drums"; m_palette_filename += ".palette"; + set_config_files(seq_config_name()); /* ca 2023-05-11 */ } /** @@ -162,6 +163,15 @@ rcsettings::rcsettings () : void rcsettings::set_defaults () { + /* + * basesettings + * m_clocks + * m_inputs + * m_keycontainer + * m_midi_control_in + * m_midi_control_out + */ + m_metro_settings.set_defaults(); m_mute_group_save = mutegroups::saving::midi; m_drop_empty_in_controls = false; @@ -182,7 +192,7 @@ rcsettings::set_defaults () m_with_jack_master = false; m_with_jack_master_cond = false; #if defined SEQ66_RTMIDI_SUPPORT - m_with_jack_midi = true; + m_with_jack_midi = true; /* hmmmmmmmmmm */ #else m_with_jack_midi = false; #endif @@ -207,9 +217,8 @@ rcsettings::set_defaults () m_last_used_dir.clear(); /* double_quotes() */ m_session_directory = user_session(seq_client_name()); m_config_subdirectory_set = false; - m_config_subdirectory.clear(), + m_config_subdirectory.clear(); m_config_filename = seq_config_name(); - m_config_filename += ".rc"; m_full_config_directory.clear(); m_user_file_active = true; m_user_filename = seq_config_name(); @@ -475,16 +484,15 @@ rcsettings::home_config_directory () const { std::string home = default_session_path(); std::string result = home; - if (! home.empty()) + if (home.empty()) { - if (! m_config_subdirectory.empty()) - { - if (! m_config_subdirectory_set) - { - result = filename_concatenate(result, m_config_subdirectory); - m_config_subdirectory_set = true; - } - } + std::string temp = "Cannot find HOME!"; + result = set_error_message(temp); + } + else + { + if (m_config_subdirectory_set) + result = pathname_concatenate(result, m_config_subdirectory); bool ok = make_directory_path(result); if (ok) @@ -501,15 +509,10 @@ rcsettings::home_config_directory () const result.clear(); } } - else - { - std::string temp = "Cannot find HOME!"; - result = set_error_message(temp); - } return result; } else - return os_normalize_path(m_full_config_directory); + return normalize_path(m_full_config_directory); /* ca 2023-05-11 */ } /** @@ -1056,14 +1059,26 @@ rcsettings::session_directory (const std::string & value) * * \param value * The value to use to make the setting. This should be a relative path. + * If empty (should be a rare use case), then the config subdirectory + * is cleared. */ void rcsettings::config_subdirectory (const std::string & value) { - bool can_do = ! value.empty() && m_config_subdirectory.empty(); - if (can_do) - m_config_subdirectory = value; + if (value.empty()) + { + m_config_subdirectory_set = false; + m_config_subdirectory.clear(); + } + else + { + if (! m_config_subdirectory_set) + { + m_config_subdirectory_set = true; + m_config_subdirectory = value; + } + } } /** @@ -1088,9 +1103,13 @@ rcsettings::set_config_directory (const std::string & value) /** * \setter m_full_config_directory * - * Provides an alternate value to be returned by the - * home_config_directory() function. Please note that all configuration - * locates are relative to home. + * Provides an alternate value to be returned by the + * home_config_directory() function. Please note that all configuration + * locates are relative to home. + * + * This causes double concatenation. But we need to call it just + * once in the case where NSM has changed the default configuration + * directory. * * \param value * Provides the directory name, which should be an actual full path. @@ -1099,30 +1118,30 @@ rcsettings::set_config_directory (const std::string & value) void rcsettings::full_config_directory (const::std::string & value) { - std::string tv = value; - if (! m_config_subdirectory.empty()) + if (! value.empty()) { - if (! m_config_subdirectory_set) + std::string tv = value; + if (m_config_subdirectory_set) /* see the banner note */ { tv = pathname_concatenate(tv, m_config_subdirectory); - m_config_subdirectory_set = true; + m_config_subdirectory_set = false; + m_full_config_directory = normalize_path(tv, true, true); } - } - m_full_config_directory = normalize_path(tv, true, true); - std::string homedir = rc().home_config_directory(); - if (make_directory_path(homedir)) // REDUNDANT - { - /* - * This setting will convert the relative session directory - * to a full path. - */ + std::string homedir = rc().home_config_directory(); + if (make_directory_path(homedir)) // REDUNDANT + { + /* + * This setting will convert the relative session directory + * to a full path. + */ - file_message("Config directory", homedir); - session_directory(homedir); + file_message("Config directory", homedir); + session_directory(homedir); + } + else + file_error("Could not create", homedir); } - else - file_error("Could not create", homedir); } /** @@ -1131,9 +1150,14 @@ rcsettings::full_config_directory (const::std::string & value) * Implements the --config option to change both configuration files * ("rc" and "usr") with one option. * + * What about the "ctrl", "playlist", "mutes", "notemap", and "palette" + * files? They are defined in the "rc" file. + * * \param value * The value to use to make the setting, if the string is not empty. * If the value has an extension, it is stripped first. + * + * TODO: use value = file_extension_set(value); */ void diff --git a/libseq66/src/cfg/usrfile.cpp b/libseq66/src/cfg/usrfile.cpp index ab023ad5..d8d3ce33 100644 --- a/libseq66/src/cfg/usrfile.cpp +++ b/libseq66/src/cfg/usrfile.cpp @@ -900,8 +900,7 @@ usrfile::write () "# (Non/New Session Manager), or 'jack'. 'url' can be set to the value set by\n" "# nsmd when run by command-line. Set 'url' if running nsmd stand-alone; use\n" "# the --osc-port number. Seq66 detects if started in NSM. The visibility flag\n" -"# is used only by NSM to restore visibility. 'copy-config' indicates if the\n" -"# existing home configuration is copied to a new NSM session.\n" +"# is used only by NSM to restore visibility.\n" "\n[user-session]\n\n" ; write_string(file, "session", usr().session_manager_name()); diff --git a/libseq66/src/sessions/clinsmanager.cpp b/libseq66/src/sessions/clinsmanager.cpp index 393772d4..765371b8 100644 --- a/libseq66/src/sessions/clinsmanager.cpp +++ b/libseq66/src/sessions/clinsmanager.cpp @@ -165,7 +165,7 @@ clinsmanager::create_session (int argc, char * argv []) { std::string nsmfile = "dummy/file"; std::string nsmext = nsm::default_ext(); - rc().config_subdirectory("config"); /* NEW 2023-03-31 */ + rc().config_subdirectory("config"); /* appended to NSM path */ m_nsm_client.reset(create_nsmclient(*this, url, nsmfile, nsmext)); bool result = bool(m_nsm_client); if (result) @@ -174,8 +174,8 @@ clinsmanager::create_session (int argc, char * argv []) * Use the same name as provided when opening the JACK client. */ - std::string appname = seq_client_name(); /* "seq66" */ - std::string exename = seq_arg_0(); /* "qseq66" */ + std::string appname = seq_client_name(); /* "seq66", -l labl */ + std::string exename = seq_arg_0(); /* "qseq66", etc. */ result = m_nsm_client->announce(appname, exename, capabilities()); if (result) { diff --git a/libseq66/src/sessions/smanager.cpp b/libseq66/src/sessions/smanager.cpp index c5551bee..375ff2f1 100644 --- a/libseq66/src/sessions/smanager.cpp +++ b/libseq66/src/sessions/smanager.cpp @@ -25,7 +25,7 @@ * \library seq66 application * \author Chris Ahlstrom * \date 2020-03-22 - * \updates 2023-05-10 + * \updates 2023-05-11 * \license GNU GPLv2 or above * * Note that this module is part of the libseq66 library, not the libsessions @@ -984,8 +984,6 @@ smanager::create_configuration { session_message("Main path", mainpath); result = make_directory_path(cfgfilepath); - if (result) - rc().full_config_directory(cfgfilepath); } if (result && ! midifilepath.empty()) { @@ -997,15 +995,16 @@ smanager::create_configuration if (usr().in_nsm_session()) { usr().session_visibility(false); /* new session=hide */ - -#if defined NSM_DISABLE_LOAD_MOST_RECENT - rc().load_most_recent(false; /* don't load MIDI */ -#else rc().load_most_recent(true); /* issue #41 */ -#endif rc().jack_auto_connect(false); /* issue #48 */ } -#if defined DO_NOT_BELAY_UNTIL_EXIT + + /* + * The options files and other files are written at exit. + * We might provide a menu command to write them at any time. + */ + +#if defined WRITE_OPTIONS_FILES_AT_STARTUP if (result) { file_message("Saving session configuration", cfgfilepath); @@ -1164,7 +1163,7 @@ smanager::make_path_names const std::string & path, std::string & outcfgpath, std::string & outmidipath, - const std::string & midisubdir // why no configsubdir (for NSM)? + const std::string & midisubdir ) { bool result = ! path.empty(); @@ -1172,8 +1171,9 @@ smanager::make_path_names { std::string cfgpath = normalize_path(path); std::string midipath = cfgpath; - std::string subdir = midisubdir.empty() ? "midi" : midisubdir ; - midipath = pathname_concatenate(cfgpath, subdir); + if (! midisubdir.empty()) + midipath = pathname_concatenate(cfgpath, midisubdir); + outcfgpath = cfgpath; outmidipath = midipath; } @@ -1291,13 +1291,8 @@ smanager::import_configuration_items if (result) { -#if defined NSM_DISABLE_LOAD_MOST_RECENT - if (usr().in_nsm_session()) - rc().load_most_recent(false); /* don't load MIDI */ -#else if (usr().in_nsm_session()) rc().load_most_recent(true); /* issue #41 */ -#endif } } if (result) diff --git a/libseq66/src/util/filefunctions.cpp b/libseq66/src/util/filefunctions.cpp index d5666435..9657635a 100644 --- a/libseq66/src/util/filefunctions.cpp +++ b/libseq66/src/util/filefunctions.cpp @@ -25,7 +25,7 @@ * \library seq66 application * \author Chris Ahlstrom * \date 2015-11-20 - * \updates 2023-05-10 + * \updates 2023-05-11 * \version $Revision$ * * We basically include only the functions we need for Seq66, not @@ -1039,15 +1039,17 @@ name_has_path (const std::string & filename) } /** - * Detects if the filename is likely to contain a root path: + * Detects if the filename contains a root path, rather than a relative + * path. Using the circumflex (for /home/user) is treated as a root path. * \verbatim - /dir/dir2 ... - \dir\dir2 ... - x: + ~/dir/dir2 ... User's HOME directory. + /dir/dir2 ... System directory. + \dir\dir2 ... Windows root directory on current drive. + C:[\dir-or-file...] Windows root directory on specific drive. + \\server\volume... Windows Universal Naming Convention (UNC). \endverbatim * - * Also, using the circumflex (for /home/user) is treated as a root path. */ bool @@ -1058,17 +1060,17 @@ name_has_root_path (const std::string & filename) #if defined SEQ66_PLATFORM_WINDOWS if (! result) { - pos = filename.find_first_of("\\"); + pos = filename.find_first_of("\\"); /* UNC/current drive root */ result = pos != std::string::npos; } #endif if (result) - result = pos == 0; /* path starts with "/", "~", "\" */ + result = pos == 0; /* path starts with "/~\ */ #if defined SEQ66_PLATFORM_WINDOWS if (! result) { - pos = filename.find_first_of(":"); + pos = filename.find_first_of(":"); /* C: */ result = pos != std::string::npos; if (result) result = std::isalpha(filename[0]) && pos == 1; @@ -1165,7 +1167,7 @@ bool make_directory_path (const std::string & directory_name) { bool result = file_name_good(directory_name); - std::string dirname = normalize_path(directory_name); + std::string dirname = os_normalize_path(directory_name); /* ca 2023-05-11 */ if (result) { if (file_exists(dirname)) /* directory already exists */