From 82fd462f875c0291a2451f54bb11bcdd96222703 Mon Sep 17 00:00:00 2001 From: Carsten Larsen Date: Tue, 12 Jan 2021 22:55:34 +0100 Subject: [PATCH] Release 1.08 --- ChangeLog | 9 ++- Makefile.m68k | 8 ++- Manual | 88 ++++++++++++++++------- Readme | 73 +++++++++++++++++++ broker.c | 3 - com.c | 161 ++++++++++++++++++++++++++++++++++-------- config.h | 7 +- library.c | 2 + main.c | 6 +- state.c | 142 ++----------------------------------- state.h | 1 - string.c | 58 +++++++++++++++ string.h | 2 + time.c | 192 +++++++++++++++++++++++++++++++++++++++++++------- time.h | 13 ++-- val.c | 191 +++++++++++++++++++++++++++++++++++++++++++++++++ win_gad.c | 27 ++++--- win_main.c | 2 +- 18 files changed, 735 insertions(+), 250 deletions(-) create mode 100644 Readme create mode 100644 val.c diff --git a/ChangeLog b/ChangeLog index 81748a6..c5febca 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,15 @@ AmiTimeKeeper Change Log +v1.08 18.05.2019 + - When using pool server cycle with prefix 0 to 3 + - Display of wrong signes in time zone fixed + - Faulty log messages about settings fixed + - Timer bug causing infitive loop fixed + - Memory leak in settings window fixed + v1.07 15.02.2019 - Support commodity hotkey and popup options - - Hide advanced setting with new expert option + - Hide advanced settings with new expert option v1.06 08.02.2019 - Adjust layout in settings window diff --git a/Makefile.m68k b/Makefile.m68k index dd33844..790f357 100644 --- a/Makefile.m68k +++ b/Makefile.m68k @@ -42,17 +42,19 @@ string.o: compiler.h config.h string.h mem.h time.o: compiler.h config.h time.h mem.h +val.o: compiler.h config.h state.h message.h log.h + win_main.o: compiler.h config.h message.h state.h time.h mem.h win.h win_gad.o: compiler.h config.h message.h state.h time.h mem.h win.h -timekeeper: broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o win_main.o win_gad.o +timekeeper: broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o val.o win_main.o win_gad.o ${CC} ${CFLAGS} ${LFLAGS} -s -o TimeKeeper \ - broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o win_main.o win_gad.o \ + broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o sntp.o state.o time.o string.o val.o win_main.o win_gad.o \ ${LDLIBS} clean: - rm -f TimeKeeper broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o settings.o sntp.o state.o time.o string.o win_main.o win_gad.o TimeKeeper.map + rm -f TimeKeeper broker.o com.o library.o log.o main.o mem.o message.o net_getaddrinfo.o net_poll.o net.o settings.o sntp.o state.o time.o string.o val.o win_main.o win_gad.o TimeKeeper.map depend: @echo Dependencies already done diff --git a/Manual b/Manual index 7dd8a6d..2290385 100644 --- a/Manual +++ b/Manual @@ -1,5 +1,5 @@ @database TimeKeeper.guide -@$VER: TimeKeeper.guide 1.06 (2019-02-08) +@$VER: TimeKeeper.guide 1.08 (2019-05-18) @(c) 2017-2019 Carsten Sonne Larsen @author Carsten Sonne Larsen @@ -32,14 +32,17 @@ @Next "Configuring the client" AmiTimeKeeper is a small program which keeps the time right on your -machine. No installation is required. +machine. No installation is required. It is operated as a commodity +and is controlled by AmigaOS. An AmiTCP compatible TCP/IP stack is +required for AmiTimeKeeper to work. -AmiTimeKeeper is operated as a commodity and is controlled by AmigaOS. -An AmiTCP compatible TCP/IP stack is required for AmiTimeKeeper to work. +Several settings determine the behaviour. The settings are passed +either directly from the command line or by using the tool types of +an icon. Preferences can also be saved between reboots. -AmiTimeKeeper can be configured through several settings. This can be -done either directly from the command line or by using the tooltypes -of an icon. Preferences can also be saved between reboots. +The local time zone needs to be configured using Workbench preferences +or a similar tool. in regular AmigaOS this is available through the +Locale Preferences Editor. @{"Configuring the client" Link "Configuring the client"} @{"Using tooltypes of an icon" Link "Using tooltypes of an icon"} @@ -54,7 +57,7 @@ of an icon. Preferences can also be saved between reboots. @Toc "Main" @Prev "Main" @Next "Using tooltypes of an icon" -@{b}Server Address@{ub} +@{b}Server address@{ub} NTP servers are managed by several organizations. The pool.ntp.org project and Network Time Foundation are probably the two most famous. @@ -72,7 +75,10 @@ the address should be ch.pool.ntp.org. Network Time Foundation has a website on http://support.ntp.org/ The pool.ntp.org project website is located at https://www.ntppool.org/ -@{b}Server Port@{ub} +Pool server addresses will automatically be prefixed with 0, 1, 2 or 3 +in order to lower the risk of choosing a none-responsive server. + +@{b}Server port@{ub} NTP servers use port 123 as default. Only under special circumstances are the NTP server port different from 123. @@ -88,7 +94,7 @@ The requests are sent in certain intervals defined by the interval parameter. The interval should be specified using milliseconds. One thousand (1.000) milliseconds are equal to one second. -@{b}Threshold@{ub} +@{b}Adjustment threshold@{ub} Due to the accuracy of NTP servers and the nature of Amiga CPUs it does not make sense to adjust the Amiga clock on every response from the NTP @@ -97,13 +103,20 @@ The amount of accepted inaccuracy is set using the threshold parameter. The threshold should be specified using microsecond. One million microseconds (1.000.000) are equal to one second. -@{b}Read Only@{ub} +@{b}Read only@{ub} It is possible to send request to the NTP server without setting the Amiga hardware clock. This option can be handy when debugging time zone setup and other time related parameters. -@{b}Connection Timeout@{ub} +@{b}Expert mode@{ub} + +Advanced settings are hidden from the settings windown when expert mode +is not enabled. The advanced settings are server port, interval between +requests, adjustment threshold, connection timeout, verbosity level and +commodity priority. + +@{b}Connection timeout@{ub} In some cases, a connection to the NTP server cannot be established or the NTP server simply does respond. To avoid an infinitive wait for a @@ -111,7 +124,7 @@ response the connection will instead make a time out. The timeout interval should be specified using milliseconds. One thousand (1.000) milliseconds are equal to one second. -@{b}Verbosity@{ub} +@{b}Verbosity level@{ub} The level of logging can be adjusted from none to all. Expressed as a numeric value verbose can be 0, 1, 2 or 3, where 0 is equal to none and @@ -138,13 +151,16 @@ The available tooltypes are the same as the available command line parameters. @{b}Parameter@{ub} | @{b}Short description@{ub} ------------------------------------------ -SERVER | Server Address -PORT | Server Port +------------------------------------------------- +SERVER | NTP server Address +PORT | NTP server Port THRESHOLD | Adjustment threshold INTERVAL | Interval between requests +CX_POPUP | Show settings window on startup +CX_POPKEY | Settings window keyboard shortcut CX_PRIORITY | Commodity priority -READONLY | Read only option +READONLY | Do not set clock +EXPERT | Show advanced options TIMEOUT | Connection Timeout VERBOSE | Log verbosity LOGFILE | Log file location @@ -153,11 +169,13 @@ LOGFILE | Log file location Settings can be overridden and are set in the following order: 1. Preference file -2. Icon tooltypes -3. CLI parameters +2. Icon tooltypes / CLI parameters -CLI parameters has highest precedence and will always override settings -from icon tooltypes and from the preference file. +CLI parameters and icon tooltypes has highest precedence and will +always override settings from the preference file. + +Settings from icon tooltypes are used when starting from Workbench. +Settings from CLI are used only when starting from shell. @EndNode @@ -174,6 +192,8 @@ ENVARC:timekeeper.prefs Depending on the setup the content of timekeeper.prefs could be: +CX_POPUP=NO +CX_POPKEY=lshift control t CX_PRIORITY=25 THRESHOLD=1000000 SERVER=de.pool.ntp.org @@ -181,7 +201,8 @@ PORT=123 TIMEOUT=5000 INTERVAL=17500 VERBOSE=3 -READONLY=0 +READONLY=NO +EXPERT=NO LOGFILE=RAM:log The preference file should not be edited under normal circumstances. @@ -189,7 +210,7 @@ The preference file should not be edited under normal circumstances. @{b}Caveats@{ub} If LOGFILE is set in the preference file, no messages will be emitted -to screen (unless overridden by CLI or Icon tooltype with LOGFILE=NO). +to screen (unless overridden by CLI or icon tooltype with LOGFILE=NO). @EndNode @@ -198,10 +219,29 @@ to screen (unless overridden by CLI or Icon tooltype with LOGFILE=NO). @Prev "Saving preferences" @Next "Software License" +Version 1.05, dated 06.08.2018, has proved itself to be a stable version +and has been promoted to Long Term Support. It is distributed along with +the latest version of AmiTimeKeeper. + +A custom build version has been integrated into the Icaros Desktop system. +The author encourages all developers with an interest to make their own +build. + +@{b}v1.08 18.05.2019@{ub} + - When using pool server cycle with prefix 0 to 3 + - Display of wrong signes in time zone fixed + - Faulty log messages about settings fixed + - Timer bug causing infitive loop fixed + - Memory leak in settings window fixed + +@{b}v1.07 15.02.2019@{ub} + - Support commodity hotkey and popup options + - Hide advanced settings with new expert option + @{b}v1.06 08.02.2019@{ub} - Adjust layout in settings window -@{b}v1.05 06.08.2018@{ub} +@{b}v1.05 06.08.2018 LTS@{ub} - Preferences can now be saved from settings window - Time zone is shown as UTC offset in settings window - Running multiple instances no longer create zombie processes diff --git a/Readme b/Readme new file mode 100644 index 0000000..b7e0199 --- /dev/null +++ b/Readme @@ -0,0 +1,73 @@ +Short: Keep your time right +Author: Carsten Larsen (carsten.larsen@mail.com) +Uploader: Carsten Larsen (carsten.larsen@mail.com) +Type: util/cdity +Version: 1.08 +Architecture: m68k-amigaos + +AmiTimeKeeper is a small program which keeps the time right on your +machine. No installation is required. It is operated as a commodity +and is controlled by AmigaOS. An AmiTCP compatible TCP/IP stack is +required for AmiTimeKeeper to work. + +Several settings determine the behaviour. The settings are passed +either directly from the command line or by using the tool types of +an icon. Preferences can also be saved between reboots. + +The default server address is pool.ntp.org. To find another server +try visiting support.ntp.org or one of the other sites listing time +servers. + +Version 1.05 has proved itself to be a stable version and has been +promoted to Long Term Support. It is distributed along with the +latest version. + +A custom build version has been integrated into the Icaros Desktop +system. The author encourages all developers with an interest to +make their own build. + +v1.08 18.05.2019 + - When using pool server cycle with prefix 0 to 3 + - Display of wrong signes in time zone fixed + - Faulty log messages about settings fixed + - Timer bug causing infitive loop fixed + - Memory leak in settings window fixed + +v1.07 15.02.2019 + - Support commodity hotkey and popup options + - Hide advanced settings with new expert option + +v1.06 08.02.2019 + - Adjust layout in settings window + +v1.05 06.08.2018 LTS + - Preferences can now be saved from settings window + - Time zone is shown as UTC offset in settings window + - Running multiple instances no longer creates zombie processes + - Low water option renamed to threshold and high water option removed + - New option for sending log messages to file instead of to screen + - Some incorrect NTP log messages no longer appears + - Read-only option is now applied consistently + - Potential race condition in memory allocation fixed + - Other minor enhancements + +v1.04 15.12.2017 + - Default settings adjusted to comply better with AmigaOS + - Bugs in threshold settings (high/low water) fixed + - Bugs in opening and closing of libraries fixed + - New and more accurate error and log messages + +v1.03 09.12.2017 + - Settings window + +v1.02 29.11.2017 + - AROS code compliance + +v1.01 28.11.2017 + - Handle network disconnection + - Fix infinity timeout problem + - Support hardware clock + - Improved error messages + +v1.00 26.11.2017 + - First public release diff --git a/broker.c b/broker.c index 6ebc75e..b57ec72 100644 --- a/broker.c +++ b/broker.c @@ -266,7 +266,6 @@ static void ProcessMsg(void) break; case CXCMD_KILL: LogInfo("Received shut down from commodity"); - LogWarning("Shutting down"); StopSubProcesses(); run = false; break; @@ -358,7 +357,6 @@ static void ProcessMsg(void) if (sigrcvd & (1 << Globals->Broker->ShutdownSigBit)) { LogInfo("Received shut down from setting window"); - LogWarning("Shutting down"); StopSubProcesses(); run = false; } @@ -366,7 +364,6 @@ static void ProcessMsg(void) if (sigrcvd & SIGBREAKF_CTRL_C) { LogInfo("Received CTRL + C"); - LogWarning("Shutting down"); StopSubProcesses(); run = false; } diff --git a/com.c b/com.c index cb1aa3f..9acc291 100644 --- a/com.c +++ b/com.c @@ -31,18 +31,26 @@ #include "sntp.h" #include "mem.h" +#define POOLSUFFIX "pool.ntp.org" +#define POOLPORT "123" + struct AppCom { bool Run; bool Restart; bool Exited; + short TimerSigBit; + short RestartSigBit; struct Process *Task; struct TimerInfo *TimerInfo; struct sntp *Client; - short RestartSigBit; bool FirstRun; + bool SocketOpen; int RunCount; int FailCount; + int PoolServerNumber; + char *ServerName; + char *ServerPort; }; static void SyncProc(void); @@ -91,8 +99,13 @@ void StartCom(void) Globals->Syncer->Restart = false; Globals->Syncer->Exited = false; Globals->Syncer->FirstRun = true; + Globals->Syncer->SocketOpen = false; Globals->Syncer->RunCount = 0; Globals->Syncer->FailCount = 0; + Globals->Syncer->PoolServerNumber = -1; + Globals->Syncer->ServerName = NULL; + Globals->Syncer->ServerPort = NULL; + Globals->Syncer->TimerInfo = NULL; Forbid(); Globals->Syncer->Task = CreateNewProcTags( @@ -112,6 +125,11 @@ void StartCom(void) } } +static ULONG GetTimerSigMask(void) +{ + return (1 << Globals->Syncer->TimerSigBit); +} + static ULONG GetSntpRestartSigMask(void) { return (1 << Globals->Syncer->RestartSigBit); @@ -126,25 +144,12 @@ static void ComDestroy(void) } } -static void Sync(void) -{ - char message[SETTINGMESSAGELEN]; - ComOpen(); - SetTimer(Globals->Syncer->TimerInfo); - SNPrintf(message, SETTINGMESSAGELEN, - "Sending next NTP request in %ld milliseconds", - Globals->Settings->Interval); - SendTraceMessage(message); - ShowStats(); - Globals->Syncer->RunCount++; -} - static void SyncProc(void) { - Globals->Syncer->TimerInfo = CreateTimer(false); - if (Globals->Syncer->TimerInfo == NULL) + Globals->Syncer->TimerSigBit = AllocSignal(-1); + if (Globals->Syncer->TimerSigBit == -1) { - SendErrorMessage("Could not create timer for synchronizer"); + SendErrorMessage("Could not allocate signal for synchronizer"); Globals->Syncer->Exited = true; return; } @@ -153,23 +158,37 @@ static void SyncProc(void) if (Globals->Syncer->RestartSigBit == -1) { SendErrorMessage("Could not allocate signal for synchronizer"); - DeleteTimer(Globals->Syncer->TimerInfo); Globals->Syncer->Exited = true; + FreeSignal(Globals->Syncer->TimerSigBit); return; } - Sync(); + Globals->Syncer->TimerInfo = CreateInterruptTimer( + (struct Task *)Globals->Syncer->Task, + Globals->Syncer->TimerSigBit); + if (Globals->Syncer->TimerInfo == NULL) + { + SendErrorMessage("Could not create timer for synchronizer"); + Globals->Syncer->Exited = true; + FreeSignal(Globals->Syncer->TimerSigBit); + FreeSignal(Globals->Syncer->RestartSigBit); + return; + } + + ComOpen(); + StartInterruptTimer(Globals->Syncer->TimerInfo); do { - ULONG sigtime = GetTimerSigMask(Globals->Syncer->TimerInfo); + ULONG sigtime = GetTimerSigMask(); ULONG sigrest = GetSntpRestartSigMask(); ULONG sigmask = SIGBREAKF_CTRL_C | sigtime | sigrest; ULONG sigrcvd = Wait(sigmask); if (sigrcvd & sigtime) { - Sync(); + ComOpen(); + ShowStats(); } if (sigrcvd & sigrest) @@ -177,6 +196,7 @@ static void SyncProc(void) ComDestroy(); Globals->Syncer->Restart = true; ComOpen(); + ShowStats(); } if (sigrcvd & SIGBREAKF_CTRL_C) @@ -186,6 +206,8 @@ static void SyncProc(void) } while (Globals->Syncer->Run); ComDestroy(); + StopInterruptTimer(Globals->Syncer->TimerInfo); + FreeSignal(Globals->Syncer->TimerSigBit); FreeSignal(Globals->Syncer->RestartSigBit); DeleteTimer(Globals->Syncer->TimerInfo); CloseSocketLibrary(); @@ -195,6 +217,18 @@ static void SyncProc(void) SendWarningMessage("Exited synchronizer process"); } + if (Globals->Syncer->ServerName != NULL) + { + FreeMemSafe(Globals->Syncer->ServerName); + Globals->Syncer->ServerName = NULL; + } + + if (Globals->Syncer->ServerPort != NULL) + { + FreeMemSafe(Globals->Syncer->ServerPort); + Globals->Syncer->ServerPort = NULL; + } + Globals->Syncer->TimerInfo = NULL; Globals->Syncer->Task = NULL; Globals->Syncer->Exited = true; @@ -204,10 +238,12 @@ static void ComOpen(void) { if (OpenSocketLibrary() != LIB_OK) { - // Make sure socket library is open + Globals->Syncer->SocketOpen = false; return; } + Globals->Syncer->SocketOpen = true; + if (Globals->Syncer->FirstRun) { SendInfoMessage("Starting SNTP client"); @@ -248,14 +284,33 @@ static void ComOpen(void) static void ShowStats(void) { + if (Globals->Syncer->SocketOpen) + { + char message[SETTINGMESSAGELEN]; + SNPrintf(message, SETTINGMESSAGELEN, + "Sending next NTP request in %ld milliseconds", + Globals->Settings->Interval); + SendTraceMessage(message); + } + else + { + char message[SETTINGMESSAGELEN]; + SNPrintf(message, SETTINGMESSAGELEN, + "Retry in %ld milliseconds", + Globals->Settings->Interval); + SendTraceMessage(message); + } + + Globals->Syncer->RunCount++; + if (Globals->Syncer->RunCount % 10 == 0) { char message[SETTINGMESSAGELEN]; - char timeString[10], dateString[10], dayString[10]; - SystemTimeString(timeString, dateString, dayString); + char timeString[10], dateString[10], dayString[10], zoneString[10]; + SystemTimeString(timeString, dateString, dayString, zoneString); SNPrintf(message, SETTINGMESSAGELEN, - "Local time is %s %s %s", - dayString, dateString, timeString); + "Local time is %s %s %s%s", + dayString, dateString, timeString, zoneString); SendInfoMessage(message); } @@ -271,6 +326,51 @@ static void ShowStats(void) } } +static void ChooseServer(void) +{ + char message[SETTINGMESSAGELEN]; + int i; + char *server = Globals->Settings->DestinationAddress; + int len = StrLen(server); + bool isPool = EndsWith(server, POOLSUFFIX) && + !StartsWith(server, "0.") && + !StartsWith(server, "1.") && + !StartsWith(server, "2.") && + !StartsWith(server, "3."); + + if (Globals->Syncer->ServerName != NULL) + { + FreeMemSafe(Globals->Syncer->ServerName); + } + + if (Globals->Syncer->ServerPort != NULL) + { + FreeMemSafe(Globals->Syncer->ServerPort); + } + + if (!isPool) + { + Globals->Syncer->ServerName = StrDupSafe(server); + Globals->Syncer->ServerPort = StrDupSafe(Globals->Settings->DestinationPort); + return; + } + + Globals->Syncer->ServerName = (char *)AllocMemSafe(len + 3); + Globals->Syncer->ServerPort = StrDupSafe(POOLPORT); + + do + { + i = RandomFast() % 4; + } while (i < 0 || i == Globals->Syncer->PoolServerNumber); + Globals->Syncer->PoolServerNumber = i; + SNPrintf(Globals->Syncer->ServerName, len + 3, + "%ld.%s", i, server); + + SNPrintf(message, SETTINGMESSAGELEN, + "Choosing pool server %s", Globals->Syncer->ServerName); + SendWarningMessage(message); +} + static void ComInit(void) { if (Globals->Syncer->Client != NULL) @@ -279,9 +379,10 @@ static void ComInit(void) Globals->Syncer->Client = NULL; } + ChooseServer(); Globals->Syncer->Client = sntp_create( - Globals->Settings->DestinationAddress, - Globals->Settings->DestinationPort, + Globals->Syncer->ServerName, + Globals->Syncer->ServerPort, NULL, NULL); @@ -307,8 +408,8 @@ static int SyncClock(void) SNPrintf(message, SETTINGMESSAGELEN, "Sending request to %s:%s", - Globals->Settings->DestinationAddress, - Globals->Settings->DestinationPort); + Globals->Syncer->ServerName, + Globals->Syncer->ServerPort); SendInfoMessage(message); ret = sntp_send(Globals->Syncer->Client); diff --git a/config.h b/config.h index c42948a..a34ee7b 100644 --- a/config.h +++ b/config.h @@ -149,8 +149,8 @@ int poll(struct pollfd *, nfds_t, int); #define APP_LONG_NAME "Amiga Time Keeper" #endif -#define APP_VERSION "1.07" -#define APP_DATE_VERSION "1.07 (15.02.2019)" +#define APP_VERSION "1.08" +#define APP_DATE_VERSION "1.08 (18.05.2019)" #define APP_ID APP_SHORT_NAME " " APP_DATE_VERSION #define APP_TITLE APP_LONG_NAME " " APP_DATE_VERSION #define APP_TITLE_VERSION APP_LONG_NAME " " APP_VERSION @@ -218,6 +218,9 @@ void HideSettingWindow(void); int OpenLibraries(void); void CloseLibraries(void); +/* val.c */ +void SanitizeSettings(void); + /* net.c */ int OpenSocketLibrary(void); void CloseSocketLibrary(void); diff --git a/library.c b/library.c index 64a9bde..26421e1 100644 --- a/library.c +++ b/library.c @@ -262,6 +262,8 @@ int OpenLibraries(void) InitUtcOffset(); + SeedRandom(); + return LIB_OK; } diff --git a/main.c b/main.c index 8d81259..7294ae6 100644 --- a/main.c +++ b/main.c @@ -148,7 +148,7 @@ static void LogStartMessage(void) static void LogLocalTime(void) { - char timeString[10], dateString[10], dayString[10]; - SystemTimeString(timeString, dateString, dayString); - LogWarning("Local time is %s %s %s", dayString, dateString, timeString); + char timeString[10], dateString[10], dayString[10], zoneString[10]; + SystemTimeString(timeString, dateString, dayString, zoneString); + LogWarning("Local time is %s %s %s%s", dayString, dateString, timeString, zoneString); } diff --git a/state.c b/state.c index f2c6d4f..5c46cbc 100644 --- a/state.c +++ b/state.c @@ -109,13 +109,10 @@ static const char *applyFileSettings = "Applying values from preference file"; static const char *applyCliSettings = "Applying values from CLI"; static const char *applyWbSettings = "Applying values from tooltypes"; static const char *effectiveSettings = "Listing runtime values"; -static const char *settingTooLow = "%s < %ld (too low)"; -static const char *settingTooHigh = "%s > %ld (too high)"; -static const char *settingGreaterThan = "%s > %s"; static const char *settingChangedLong = "%s changed: %ld -> %ld"; static const char *settingChangedString = "%s changed: %s -> %s"; -static const char *settingSetLong = "%s already set to %ld"; -static const char *settingSetString = "%s already set to %s"; +static const char *settingSetLong = "%s is already set to %ld"; +static const char *settingSetString = "%s is already set to %s"; static const char *settingValueLong = "%s=%ld"; static const char *settingValueString = "%s=%s"; static const char *saveValueLong = "%s=%ld\n"; @@ -236,7 +233,7 @@ static void ParseBooleanSetting( void *value, bool yesNo) { - LogFoundSetting(settings->Type, SettingKeys->Popup); + LogFoundSetting(settings->Type, keyword); // CLI switch is always a long value if (settings->Type == CliSettingType && !yesNo) @@ -600,7 +597,7 @@ static void ApplyBooleanSetting( } else if (!quiet) { - LogTrace(settingValueString, keyword, BooleanAsText(*newValue)); + LogTrace(settingSetString, keyword, BooleanAsText(*newValue)); } *curValue = *newValue; } @@ -770,134 +767,3 @@ void ApplySettings() } } -static void ValidateInterval(void) -{ - if (Globals->Settings->Interval < INTERVAL_MIN) - { - LogInfo(settingTooLow, - SettingKeys->Interval, - INTERVAL_MIN); - LogInfo(settingChangedLong, - SettingKeys->Interval, - Globals->Settings->Interval, - INTERVAL_MIN); - Globals->Settings->Interval = INTERVAL_MIN; - } -} - -static void ValidateTimeout(void) -{ - if (Globals->Settings->Timeout < TIMEOUT_MIN) - { - LogInfo(settingTooLow, - SettingKeys->Timeout, - TIMEOUT_MIN); - LogInfo(settingChangedLong, - SettingKeys->Timeout, - Globals->Settings->Timeout, - TIMEOUT_MIN); - Globals->Settings->Timeout = TIMEOUT_MIN; - } - - if (Globals->Settings->Timeout > Globals->Settings->Interval) - { - LogInfo(settingGreaterThan, - SettingKeys->Timeout, - SettingKeys->Interval); - LogInfo(settingChangedLong, - SettingKeys->Timeout, - Globals->Settings->Timeout, - Globals->Settings->Interval); - Globals->Settings->Timeout = Globals->Settings->Interval; - } - - if (Globals->Settings->Timeout > TIMEOUT_MAX) - { - LogInfo(settingTooHigh, - SettingKeys->Timeout, - TIMEOUT_MAX); - LogInfo(settingChangedLong, - SettingKeys->Timeout, - Globals->Settings->Timeout, - TIMEOUT_MAX); - Globals->Settings->Timeout = TIMEOUT_MAX; - } -} - -static void ValidatePriority(void) -{ - if (Globals->Settings->Priority < PRIORITY_MIN) - { - LogInfo(settingTooLow, - SettingKeys->Priority, - PRIORITY_MIN); - LogInfo(settingChangedLong, - SettingKeys->Priority, - Globals->Settings->Priority, - PRIORITY_MIN); - Globals->Settings->Priority = PRIORITY_MIN; - } - - if (Globals->Settings->Priority > PRIORITY_MAX) - { - LogInfo(settingTooHigh, - SettingKeys->Priority, - PRIORITY_MAX); - LogInfo(settingChangedLong, - SettingKeys->Priority, - Globals->Settings->Priority, - PRIORITY_MAX); - Globals->Settings->Priority = PRIORITY_MAX; - } -} - -static void ValidateThreshold(void) -{ - if (Globals->Settings->Threshold < THRESHOLD_MIN) - { - LogInfo(settingTooLow, - SettingKeys->Threshold, - THRESHOLD_MIN); - LogInfo(settingChangedLong, - SettingKeys->Threshold, - Globals->Settings->Threshold, - THRESHOLD_MIN); - Globals->Settings->Threshold = THRESHOLD_MIN; - } -} - -static void ValidateVerbose(void) -{ - if (Globals->Settings->Verbose < VERBOSE_MIN) - { - LogInfo(settingTooLow, - SettingKeys->Verbose, - VERBOSE_MIN); - LogInfo(settingChangedLong, - SettingKeys->Verbose, - Globals->Settings->Verbose, - VERBOSE_MIN); - Globals->Settings->Verbose = VERBOSE_MIN; - } - - if (Globals->Settings->Verbose > VERBOSE_MAX) - { - LogInfo(settingTooHigh, - SettingKeys->Verbose, - VERBOSE_MAX); - LogInfo(settingChangedLong, - SettingKeys->Verbose, - Globals->Settings->Verbose, - VERBOSE_MAX); - Globals->Settings->Verbose = VERBOSE_MAX; - } -} - -void SanitizeSettings(void) -{ - ValidateInterval(); - ValidateTimeout(); - ValidatePriority(); - ValidateThreshold(); - ValidateVerbose(); -} diff --git a/state.h b/state.h index 382fe1e..0ec1d7e 100644 --- a/state.h +++ b/state.h @@ -140,7 +140,6 @@ extern const struct AppSettings DefaultSettings; void InitState(void); void DestroyState(void); -void SanitizeSettings(void); void ShowSettings(void); void LoadSettings(void); void SaveSettings(bool); diff --git a/string.c b/string.c index 355279e..7c78bcb 100644 --- a/string.c +++ b/string.c @@ -139,6 +139,64 @@ char *StrRChr(const char *start, const char c, int len) return l; } +/* + * Determine if a prefix occurs at the start of a string. + */ +bool StartsWith(const char *string, const char *prefix) +{ + char *i = (char *)string; + char *j = (char *)prefix; + + if (i == NULL || j == NULL) + return false; + + while (*i == *j && *i != '\0' && *j != '\0') + { + i++; + j++; + } + + return (*j == '\0' ? true : false); +} + +/* + * Determine if a suffix occurs at the end of a string. + */ +bool EndsWith(const char *string, const char *suffix) +{ + int a = 0; + int b = 0; + char *i = (char *)string; + char *j = (char *)suffix; + + if (i == NULL || j == NULL) + return false; + + while (*i) + { + i++; + a++; + } + + while (*j) + { + j++; + b++; + } + + if (b > a) + return false; + + while (*i == *j && b != 0) + { + i--; + j--; + b--; + } + + return (b == 0) ? true : false; +} + /* * Convert a long to a null terminated string. */ diff --git a/string.h b/string.h index 5b1f977..e2fad9e 100644 --- a/string.h +++ b/string.h @@ -42,6 +42,8 @@ int LongLongToStr(signed long long, char *); int StrToLongLong(char *, unsigned long long *); bool TryParseLong(char *, long *); bool TryParseLongLong(char *, long long *); +bool StartsWith(const char *, const char *); +bool EndsWith(const char *, const char *); int VSNPrintf(char *, size_t, const char *, va_list); int SNPrintf(char *, size_t, const char *, ...); void SplitFileName(const char *, char *, char *); diff --git a/time.c b/time.c index 6171217..7ad9bed 100644 --- a/time.c +++ b/time.c @@ -28,6 +28,7 @@ #include "time.h" #include "mem.h" +#include #include /* @@ -41,15 +42,26 @@ struct TimerInfo { - bool TimerTrigged; + bool InterruptTimer; + bool TimerStarted; + bool TimerActive; + bool TimerExited; + long Interval; + long Counter; struct MsgPort *TimerPort; + struct Interrupt *TimerInterrupt; struct timerequest *TimerIO; + struct Task *InterruptTask; + ULONG InterruptSigBit; }; struct Device *TimerBase = NULL; static struct timerequest *TimerIO = NULL; static long utcOffset = 0; +// Only one interrupt timer is allowed +struct TimerInfo *InterruptInfo; + /* * Set up pointer for timer functions. */ @@ -88,10 +100,119 @@ void CloseTimerBase(void) } } +void TimerInterruptCode(void) +{ + struct TimerInfo *info = InterruptInfo; + struct timerequest *tr = (struct timerequest *)GetMsg(info->TimerPort); + + if (!info->TimerActive) + { + info->TimerExited = true; + return; + } + + info->Counter++; + Signal(info->InterruptTask, info->InterruptSigBit); + + tr->tr_node.io_Command = TR_ADDREQUEST; + tr->tr_time.tv_secs = Globals->Settings->Interval / 1000; + tr->tr_time.tv_micro = Globals->Settings->Interval % 1000; + + BeginIO((struct IORequest *)tr); +} + +void StartInterruptTimer(struct TimerInfo *info) +{ + info->TimerStarted = true; + info->TimerActive = true; + info->TimerIO->tr_node.io_Command = TR_ADDREQUEST; + info->TimerIO->tr_time.tv_secs = Globals->Settings->Interval / 1000; + info->TimerIO->tr_time.tv_micro = Globals->Settings->Interval % 1000; + BeginIO((struct IORequest *)info->TimerIO); +} + +void StopInterruptTimer(struct TimerInfo *info) +{ + info->TimerActive = false; + + AbortIO((struct IORequest *)info->TimerIO); + if (info->TimerStarted) + { + WaitIO((struct IORequest *)info->TimerIO); + } + + while (!info->TimerExited) + { + Delay(10); + } +} + /* - * Open a timer device with UNIT_VBLANK. + * Create a Timer device software interrupt as descibed on wiki.amigaos.net: + * https://wiki.amigaos.net/wiki/Exec_Interrupts#Software_Interrupts + * and Amiga Developer Docs 2.1, lib_examples/timersoftint.c */ -struct TimerInfo *CreateTimer(bool setTimerBase) +struct TimerInfo *CreateInterruptTimer(struct Task *task, short sigBit) +{ + LONG error; + struct TimerInfo *info = (struct TimerInfo *)AllocMemSafe(sizeof(struct TimerInfo)); + if (info == NULL) + return NULL; + + info->InterruptTimer = true; + info->InterruptTask = task; + info->InterruptSigBit = 1 << sigBit; + + info->TimerPort = (struct MsgPort *)AllocMemSafe(sizeof(struct MsgPort)); + if (info->TimerPort == NULL) + { + DeleteTimer(info); + return NULL; + } + + info->TimerInterrupt = (struct Interrupt *)AllocMemSafe(sizeof(struct Interrupt)); + if (info->TimerInterrupt == NULL) + { + DeleteTimer(info); + return NULL; + } + + NewList(&(info->TimerPort->mp_MsgList)); + info->TimerPort->mp_Node.ln_Type = NT_MSGPORT; + info->TimerPort->mp_Flags = PA_SOFTINT; + info->TimerPort->mp_SigTask = (struct Task *)info->TimerInterrupt; + + info->TimerInterrupt->is_Code = TimerInterruptCode; + info->TimerInterrupt->is_Data = info; + info->TimerInterrupt->is_Node.ln_Pri = 0; + + info->TimerIO = (struct timerequest *)CreateExtIO(info->TimerPort, sizeof(struct timerequest)); + if (info->TimerIO == NULL) + { + DeleteTimer(info); + return NULL; + } + + error = OpenDevice( + (STRPTR)TIMERNAME, UNIT_MICROHZ, + (struct IORequest *)info->TimerIO, 0); + + if (error != 0) + { + DeleteTimer(info); + return NULL; + } + + // Only one interrupt timer is supported + InterruptInfo = info; + + return info; +} + +/* + * Open a timer device with UNIT_MICROHZ. + */ +struct TimerInfo *CreateTimer(void) { LONG error; static const char *name = APP_SHORT_NAME " Timer Message Port"; @@ -129,26 +250,15 @@ struct TimerInfo *CreateTimer(bool setTimerBase) return info; } -void SetTimer(struct TimerInfo *info) -{ - info->TimerIO->tr_node.io_Command = TR_ADDREQUEST; - info->TimerIO->tr_time.tv_secs = Globals->Settings->Interval / 1000; - info->TimerIO->tr_time.tv_micro = Globals->Settings->Interval % 1000; - SendIO((struct IORequest *)info->TimerIO); - info->TimerTrigged = true; -} - -ULONG GetTimerSigMask(struct TimerInfo *info) -{ - return (1 << info->TimerPort->mp_SigBit); -} - void DeleteTimer(struct TimerInfo *info) { + if (info == NULL) + return; + if (info->TimerIO != NULL) { AbortIO((struct IORequest *)info->TimerIO); - if (info->TimerTrigged) + if (info->TimerStarted) { WaitIO((struct IORequest *)info->TimerIO); } @@ -159,7 +269,19 @@ void DeleteTimer(struct TimerInfo *info) if (info->TimerPort != NULL) { - DeleteMsgPort(info->TimerPort); + if (info->InterruptTimer) + { + FreeMemSafe(info->TimerPort); + } + else + { + DeleteMsgPort(info->TimerPort); + } + } + + if (info->TimerInterrupt != NULL) + { + FreeMemSafe(info->TimerInterrupt); } FreeMemSafe(info); @@ -170,16 +292,17 @@ void InitUtcOffset(void) char timeZone[10]; int gmtoffset = Globals->Locale->loc_GMTOffset * 60; utcOffset = gmtoffset + AMIGA_OFFSET; - GetTimeZoneText(timeZone); + GetTimeZoneText(timeZone, true); LogWarning("Local time zone is %s", timeZone); } -void GetTimeZoneText(char *text) +void GetTimeZoneText(char *text, bool includeUtc) { - SNPrintf(text, 10, "UTC%s%ld:%02ld", - -Globals->Locale->loc_GMTOffset > 0 ? "+" : "", - (long)-Globals->Locale->loc_GMTOffset / 60, - (long)-Globals->Locale->loc_GMTOffset % 60); + SNPrintf(text, 10, "%s%s%ld:%02ld", + includeUtc ? "UTC" : "", + (Globals->Locale->loc_GMTOffset < 0L) ? "+" : "", + (long)(Globals->Locale->loc_GMTOffset / -60L), + (long)(Globals->Locale->loc_GMTOffset % -60L)); } void Unix2Amiga(struct timeval *unix, struct timeval *tv) @@ -219,7 +342,7 @@ void SaveTimeOfDay(const struct timeval *tv) WriteBattClock((long)tv->tv_secs - utcOffset); } -void SystemTimeString(char *time, char *date, char *day) +void SystemTimeString(char *time, char *date, char *day, char *zone) { struct DateTime dt; @@ -232,4 +355,21 @@ void SystemTimeString(char *time, char *date, char *day) dt.dat_StrTime = (void *)time; DateToStr(&dt); + + GetTimeZoneText(zone, false); +} + +static int seed = 123456789; + +void SeedRandom(void) +{ + struct timeval tv; + GetLocalTimeOfDay(&tv); + seed = tv.tv_micro; +} + +int RandomFast(void) +{ + seed = (1103515245 * seed + 12345) % 0x7fffffff; + return seed; } diff --git a/time.h b/time.h index dbea268..89ed214 100644 --- a/time.h +++ b/time.h @@ -33,19 +33,24 @@ struct TimerInfo; struct Device *OpenTimerBase(void); void CloseTimerBase(void); -struct TimerInfo *CreateTimer(bool); +struct TimerInfo *CreateTimer(void); +struct TimerInfo *CreateInterruptTimer(struct Task *, short); void SetTimer(struct TimerInfo *); void DeleteTimer(struct TimerInfo *); -ULONG GetTimerSigMask(struct TimerInfo *info); +void StartInterruptTimer(struct TimerInfo *); +void StopInterruptTimer(struct TimerInfo *); void InitUtcOffset(void); -void GetTimeZoneText(char *text); +void GetTimeZoneText(char *text, bool includeUtc); void GetTimeOfDay(struct timeval *tv); void SetTimeOfDay(const struct TimerInfo *, const struct timeval *tv); void SaveTimeOfDay(const struct timeval *tv); void GetLocalTimeOfDay(struct timeval *tv); void Unix2Amiga(struct timeval *unix, struct timeval *tv); void Utc2Local(struct timeval *utc, struct timeval *tv); -void SystemTimeString(char *time, char *date, char *day); +void SystemTimeString(char *time, char *date, char *day, char *zone); + +void SeedRandom(void); +int RandomFast(void); #endif diff --git a/val.c b/val.c new file mode 100644 index 0000000..fa1cee2 --- /dev/null +++ b/val.c @@ -0,0 +1,191 @@ +/*- + * Copyright (c) 2017-2019 Carsten Sonne Larsen + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" +#include "state.h" +#include "message.h" +#include "log.h" +#include + +static const char *settingChangedLong = "%s changed: %ld -> %ld"; +static const char *settingTooLow = "%s < %ld (too low)"; +static const char *settingTooHigh = "%s > %ld (too high)"; +static const char *settingGreaterThan = "%s * 2 > %s"; + +static void LogValidationLine(const char *format, va_list ap) +{ + char message[SETTINGMESSAGELEN]; + VSNPrintf(message, SETTINGMESSAGELEN - 1, format, ap); + + if (Globals->Broker->Task == NULL || FindTask(NULL) == Globals->Broker->Task) + { + LogInfo(message); + } + else + { + SendInfoMessage(message); + } +} + +static void LogValidation(const char *format, ...) +{ + va_list args; + va_start(args, format); + LogValidationLine(format, args); + va_end(args); +} + +static void ValidateInterval(void) +{ + if (Globals->Settings->Interval < INTERVAL_MIN) + { + LogValidation(settingTooLow, + SettingKeys->Interval, + INTERVAL_MIN); + LogValidation(settingChangedLong, + SettingKeys->Interval, + Globals->Settings->Interval, + INTERVAL_MIN); + Globals->Settings->Interval = INTERVAL_MIN; + } +} + +static void ValidateTimeout(void) +{ + if (Globals->Settings->Timeout < TIMEOUT_MIN) + { + LogValidation(settingTooLow, + SettingKeys->Timeout, + TIMEOUT_MIN); + LogValidation(settingChangedLong, + SettingKeys->Timeout, + Globals->Settings->Timeout, + TIMEOUT_MIN); + Globals->Settings->Timeout = TIMEOUT_MIN; + } + + if (Globals->Settings->Timeout > Globals->Settings->Interval / 2) + { + LogValidation(settingGreaterThan, + SettingKeys->Timeout, + SettingKeys->Interval); + LogValidation(settingChangedLong, + SettingKeys->Timeout, + Globals->Settings->Timeout, + Globals->Settings->Interval / 2); + Globals->Settings->Timeout = Globals->Settings->Interval / 2; + } + + if (Globals->Settings->Timeout > TIMEOUT_MAX) + { + LogValidation(settingTooHigh, + SettingKeys->Timeout, + TIMEOUT_MAX); + LogValidation(settingChangedLong, + SettingKeys->Timeout, + Globals->Settings->Timeout, + TIMEOUT_MAX); + Globals->Settings->Timeout = TIMEOUT_MAX; + } +} + +static void ValidatePriority(void) +{ + if (Globals->Settings->Priority < PRIORITY_MIN) + { + LogValidation(settingTooLow, + SettingKeys->Priority, + PRIORITY_MIN); + LogValidation(settingChangedLong, + SettingKeys->Priority, + Globals->Settings->Priority, + PRIORITY_MIN); + Globals->Settings->Priority = PRIORITY_MIN; + } + + if (Globals->Settings->Priority > PRIORITY_MAX) + { + LogValidation(settingTooHigh, + SettingKeys->Priority, + PRIORITY_MAX); + LogValidation(settingChangedLong, + SettingKeys->Priority, + Globals->Settings->Priority, + PRIORITY_MAX); + Globals->Settings->Priority = PRIORITY_MAX; + } +} + +static void ValidateThreshold(void) +{ + if (Globals->Settings->Threshold < THRESHOLD_MIN) + { + LogValidation(settingTooLow, + SettingKeys->Threshold, + THRESHOLD_MIN); + LogValidation(settingChangedLong, + SettingKeys->Threshold, + Globals->Settings->Threshold, + THRESHOLD_MIN); + Globals->Settings->Threshold = THRESHOLD_MIN; + } +} + +static void ValidateVerbose(void) +{ + if (Globals->Settings->Verbose < VERBOSE_MIN) + { + LogValidation(settingTooLow, + SettingKeys->Verbose, + VERBOSE_MIN); + LogValidation(settingChangedLong, + SettingKeys->Verbose, + Globals->Settings->Verbose, + VERBOSE_MIN); + Globals->Settings->Verbose = VERBOSE_MIN; + } + + if (Globals->Settings->Verbose > VERBOSE_MAX) + { + LogValidation(settingTooHigh, + SettingKeys->Verbose, + VERBOSE_MAX); + LogValidation(settingChangedLong, + SettingKeys->Verbose, + Globals->Settings->Verbose, + VERBOSE_MAX); + Globals->Settings->Verbose = VERBOSE_MAX; + } +} + +void SanitizeSettings(void) +{ + ValidateInterval(); + ValidateTimeout(); + ValidatePriority(); + ValidateThreshold(); + ValidateVerbose(); +} diff --git a/win_gad.c b/win_gad.c index ad84fbb..2e08652 100644 --- a/win_gad.c +++ b/win_gad.c @@ -163,7 +163,6 @@ bool CreateGadgets(void) Globals->Window->Gadgets->ServerGadget = gadget; - if (Globals->Settings->Expert) { // Port @@ -446,6 +445,7 @@ void SetServer(void) FreeMemSafe(Globals->Settings->DestinationAddress); Globals->Settings->DestinationAddress = StrDupSafe(server); SendInfoMessage(text); + FreeMemSafe(text); SendMessage(ATK_RESTART); } @@ -471,6 +471,7 @@ void SetPort(void) FreeMemSafe(Globals->Settings->DestinationPort); Globals->Settings->DestinationPort = StrDupSafe(port); SendInfoMessage(text); + FreeMemSafe(text); SendMessage(ATK_RESTART); } @@ -487,9 +488,6 @@ void SetInterval(void) GTIN_Number, (IPTR)&value, TAG_END); - if (value < INTERVAL_MIN) - value = INTERVAL_MIN; - if (Globals->Settings->Interval != value) { char *text; @@ -501,6 +499,9 @@ void SetInterval(void) Globals->Settings->Interval = value; text = BuildLogText(SettingKeys->Interval, oldValue, newValue); SendInfoMessage(text); + FreeMemSafe(text); + SendMessage(ATK_RESTART); + SanitizeSettings(); } } @@ -517,11 +518,6 @@ void SetTimeout(void) GTIN_Number, (IPTR)&value, TAG_END); - if (value < TIMEOUT_MIN) - value = TIMEOUT_MIN; - else if (value > TIMEOUT_MAX) - value = TIMEOUT_MAX; - if (Globals->Settings->Timeout != value) { char *text; @@ -533,6 +529,9 @@ void SetTimeout(void) Globals->Settings->Timeout = value; text = BuildLogText(SettingKeys->Timeout, oldValue, newValue); SendInfoMessage(text); + FreeMemSafe(text); + SendMessage(ATK_RESTART); + SanitizeSettings(); } } @@ -563,7 +562,9 @@ void SetThreshold(void) Globals->Settings->Threshold = value; text = BuildLogText(SettingKeys->Threshold, oldValue, newValue); SendInfoMessage(text); + FreeMemSafe(text); SendMessage(ATK_RESTART); + SanitizeSettings(); } } @@ -580,11 +581,6 @@ void SetVerbose(void) GTCY_Active, (IPTR)&value, TAG_END); - if (value < VERBOSE_MIN) - value = VERBOSE_MIN; - else if (value > VERBOSE_MAX) - value = VERBOSE_MAX; - if (Globals->Settings->Verbose != value) { char *text; @@ -595,7 +591,9 @@ void SetVerbose(void) LongToStr(value, newValue); text = BuildLogText(SettingKeys->Verbose, oldValue, newValue); SendInfoMessage(text); + FreeMemSafe(text); Globals->Settings->Verbose = value; + SanitizeSettings(); } } @@ -634,6 +632,7 @@ void SetCxPriority(void) text = BuildLogText(SettingKeys->Priority, oldValue, newValue); SetBrokerPriority(value); SendInfoMessage(text); + FreeMemSafe(text); } } } diff --git a/win_main.c b/win_main.c index eb8eb0f..44a120e 100644 --- a/win_main.c +++ b/win_main.c @@ -114,7 +114,7 @@ static bool InitWindow(void) LongToStr(Globals->Settings->Priority, Globals->Window->PriorityText); LongLongToStr(Globals->Settings->Threshold, Globals->Window->ThresholdText); - GetTimeZoneText(Globals->Window->TimeZoneText); + GetTimeZoneText(Globals->Window->TimeZoneText, true); return true; }