From 4431f67f755ebfe300144760c04d82859b67e557 Mon Sep 17 00:00:00 2001 From: Carsten Larsen Date: Tue, 12 Jan 2021 23:02:29 +0100 Subject: [PATCH] Release 1.10 --- .vscode/c_cpp_properties.json | 18 + .vscode/launch.json | 23 + .vscode/settings.json | 19 + .vscode/tasks.json | 16 + ChangeLog | 9 +- LICENSE | 2 +- Makefile.m68k | 81 +- TimeKeeper.guide | 555 +++++++++- TimeKeeper.readme | 68 +- amiga.c | 12 +- amiga.h | 6 +- bin/bgdbserver | Bin 0 -> 18988 bytes broker.c | 575 ++++++---- compiler.h | 9 +- config.h | 62 +- dist/TimeKeeper | Bin 0 -> 94252 bytes dist/TimeKeeper.map | 1686 ++++++++++++++++++++++++++++++ dist/TimeLogger | Bin 0 -> 21164 bytes dist/TimeLogger.map | 935 +++++++++++++++++ dist/tz | 1 + fd/screennotify_lib.fd | 17 + fd/screennotify_lib.sfd | 24 + fd/screennotify_protos.h | 24 + global.c | 36 + global.h | 47 + include/clib/screennotify.h | 47 + include/inline/screennotify.h | 47 + include/libraries/screennotify.h | 41 + include/proto/screennotify.h | 34 + library.c | 440 ++++---- locale.c | 184 ++++ locale.h | 59 ++ log.c | 230 +--- log.h | 19 +- logger.c | 158 +++ logger.h | 61 ++ logmod.h | 36 + main.c | 60 +- mem.c | 532 ++++++---- mem.h | 21 +- message.c | 133 ++- message.h | 36 +- net.c | 30 +- net.h | 117 +++ net_getaddrinfo.c | 181 +--- net_getaddrinfo.h | 15 +- net_poll.c | 7 +- notify.c | 142 +++ notify.h | 34 + ptz.c | 171 +-- ptz.h | 30 +- setting.c | 678 ++++++++++++ setting.h | 106 ++ shutdown.c | 126 +++ shutdown.h | 46 + sntp.c | 49 +- sntp.h | 3 +- string.c | 8 +- string.h | 4 +- sync.c | 585 +++++++++++ sync.h | 37 + timer.c | 366 +++++++ timer.h | 45 + tz.c | 297 ++++++ tz.h | 43 + val.c | 187 ++-- win.h | 41 +- win_gad.c | 282 +++-- win_main.c | 268 +++-- 69 files changed, 8410 insertions(+), 1851 deletions(-) create mode 100644 .vscode/c_cpp_properties.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 bin/bgdbserver create mode 100644 dist/TimeKeeper create mode 100644 dist/TimeKeeper.map create mode 100644 dist/TimeLogger create mode 100644 dist/TimeLogger.map create mode 100644 dist/tz create mode 100644 fd/screennotify_lib.fd create mode 100644 fd/screennotify_lib.sfd create mode 100644 fd/screennotify_protos.h create mode 100644 global.c create mode 100644 global.h create mode 100644 include/clib/screennotify.h create mode 100644 include/inline/screennotify.h create mode 100644 include/libraries/screennotify.h create mode 100644 include/proto/screennotify.h create mode 100644 locale.c create mode 100644 locale.h create mode 100644 logger.c create mode 100644 logger.h create mode 100644 logmod.h create mode 100644 net.h create mode 100644 notify.c create mode 100644 notify.h create mode 100644 setting.c create mode 100644 setting.h create mode 100644 shutdown.c create mode 100644 shutdown.h create mode 100644 sync.c create mode 100644 sync.h create mode 100644 timer.c create mode 100644 timer.h create mode 100644 tz.c create mode 100644 tz.h diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..a139190 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,18 @@ +{ + "configurations": [ + { + "name": "amiga", + "includePath": [ + "/opt/amiga/m68k-amigaos/ndk-include/", + "/opt/amiga/m68k-amigaos/clib2/include/" + ], + "defines": [], + "compilerPath": "/opt/amiga/bin/m68k-amigaos-gcc", + "cStandard": "c99", + "cppStandard": "c++98", + "intelliSenseMode": "${default}", + "compilerArgs": [] + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..55000b3 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,23 @@ +// Debug with remote gdbserver for AmigaOS: +// http://aminet.net/package/dev/debug/bgdbserver + +// Start in FSUAE with: +// >bgdbserver TimeKeeper + +// AmigaOS GCC & GDB: +// https://github.com/bebbo/amiga-gcc +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to gdbserver", + "type": "gdb", + "request": "attach", + "executable": "obj/TimeKeeper", + "target": "localhost:2345", + "remote": true, + "cwd": "${workspaceRoot}", + "gdbpath": "/opt/amiga/bin/m68k-amigaos-gdb", + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..bac7e36 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,19 @@ +{ + "cSpell.words": [ + "Sonne", + "TZ", + "TZONE" + ], + "files.associations": { + "alib_protos.h": "c", + "timer.h": "c", + "timer_protos.h": "c", + "shutdown.h": "c", + "gfxbase.h": "c", + "type_traits": "cpp", + "typeinfo": "c", + "dos.h": "c", + "commodities.h": "c", + "battclock.h": "c" + } +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..8b3b249 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,16 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Logger", + "type": "shell", + "command": "make -f Makefile.m68k", + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} \ No newline at end of file diff --git a/ChangeLog b/ChangeLog index 8ffea31..9182ab9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ AmiTimeKeeper Change Log +v1.10 20.03.2020 + - RTC is no longer required during startup + - When time zone changes it is now recognized + - Several bugs affecting time zone logic fixed + - Documentation updated with POSIX TZ examples + - Compiled with upgraded GCC, version 6.2 + v1.09 14.07.2019 - Initial DST support using POSIX TZ and Amiga TZONE variable - Restart synchronizer processes on DNS lookup failures @@ -8,7 +15,7 @@ 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 + - Timer bug causing infinitive loop fixed - Memory leak in settings window fixed v1.07 15.02.2019 diff --git a/LICENSE b/LICENSE index 8031509..cdb5519 100644 --- a/LICENSE +++ b/LICENSE @@ -1,7 +1,7 @@ Copyright (c) 2001, 02 Motoyuki Kasahara Copyright (c) 2007 TANDBERG Telecom AS Copyright (c) 2008-2009 Dag-Erling Smørgrav -Copyright (c) 2017-2019 Carsten Sonne Larsen +Copyright (c) 2017-2020 Carsten Sonne Larsen All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/Makefile.m68k b/Makefile.m68k index e1e3aed..805a3e3 100644 --- a/Makefile.m68k +++ b/Makefile.m68k @@ -1,28 +1,39 @@ -all: timekeeper +all: timekeeper timelogger + mkdir -p obj/ + mv *.o obj/ -CC = /opt/m68k-amigaos/bin/m68k-amigaos-gcc +# GCC 6.x +# https://github.com/bebbo/amiga-gcc +# +CC = /opt/amiga/bin/m68k-amigaos-gcc +CFLAGS = -O0 -DAOS3 -DLIB_HOST -Iinclude -mcrt=clib2 -Wall +LFLAGS1 = -s -Wl,--cref,-M,-Map=TimeKeeper.map +LFLAGS2 = -s -Wl,--cref,-M,-Map=TimeLogger.map +#CFLAGS = -O0 -g -DAOS3 -DLIB_HOST -Iinclude -mcrt=clib2 -Wall +#LFLAGS = -Wl,--cref,-M,-Map=TimeKeeper.map -# clib2 -#CFLAGS = -O2 -DAOS3 -Iinclude -mcrt=clib2 -m68020 -fbaserel32 -Wall -#LFALGS = -Wl,--cref,-M,-Map=TimeKeeper.map -#LDLIBS = -lnet +OBJECTS = broker.o global.o library.o log.o locale.o main.o mem.o message.o \ + net_getaddrinfo.o net_poll.o net.o notify.o ptz.o setting.o shutdown.o \ + sntp.o string.o sync.o timer.o tz.o val.o win_main.o \ + win_gad.o -# libnix -#CFLAGS = -O2 -DAOS3 -fomit-frame-pointer -fno-stack-check -Iinclude -noixemul -Wall -CFLAGS = -O2 -DAOS3 -fno-stack-check -Iinclude -noixemul -Wall -LFLAGS = -Wl,--cref,-M,-Map=TimeKeeper.map -LDLIBS = +OBJLOG = logger.o string.o +.PHONY: broker.o: compiler.h config.h message.h win.h -com.o: compiler.h config.h message.h state.h time.h sntp.h mem.h +global.o: global.h -library.o: compiler.h config.h time.h mem.h +com.o: compiler.h config.h message.h setting.h timer.h sntp.h mem.h + +library.o: compiler.h config.h timer.h mem.h log.o: compiler.h config.h log.h mem.h -main.o: compiler.h config.h state.h time.h mem.h +locale.o: locale.h mem.h + +main.o: compiler.h config.h setting.h timer.h mem.h mem.o: compiler.h config.h mem.h @@ -34,29 +45,49 @@ net_poll.o: compiler.h config.h mem.h net.o: compiler.h config.h net_getaddrinfo.h message.h mem.h +notify.o: compiler.h notify.h config.h + ptz.o: compiler.h config.h ptz.h -sntp.o: compiler.h config.h sntp.h time.h net_getaddrinfo.h message.h mem.h +setting.o: compiler.h config.h setting.h mem.h -state.o: compiler.h config.h state.h mem.h +shutdown.o: shutdown.h message.h + +sntp.o: compiler.h config.h sntp.h timer.h net_getaddrinfo.h message.h mem.h string.o: compiler.h config.h string.h mem.h -time.o: compiler.h config.h time.h mem.h +time.o: compiler.h config.h ptz.h timer.h mem.h -val.o: compiler.h config.h state.h message.h log.h +tz.o: compiler.h config.h ptz.h timer.h mem.h -win_main.o: compiler.h config.h message.h state.h time.h mem.h win.h +val.o: compiler.h config.h setting.h message.h log.h -win_gad.o: compiler.h config.h message.h state.h time.h mem.h win.h +win_main.o: compiler.h config.h message.h setting.h timer.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 ptz.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 ptz.o sntp.o state.o time.o string.o val.o win_main.o win_gad.o \ - ${LDLIBS} +win_gad.o: compiler.h config.h message.h setting.h timer.h mem.h win.h + +logger.o: compiler.h + +timekeeper: ${OBJECTS} + ${CC} ${CFLAGS} ${LFLAGS1} -o TimeKeeper ${OBJECTS} ${LDLIBS} + mkdir -p obj/ + mv TimeKeeper obj/ + mv TimeKeeper.map obj/ + +timelogger: ${OBJLOG} + ${CC} ${CFLAGS} ${LFLAGS2} -o TimeLogger ${OBJLOG} ${LDLIBS} + mkdir -p obj/ + mv TimeLogger obj/ + mv TimeLogger.map obj/ 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 ptz.o settings.o sntp.o state.o time.o string.o val.o win_main.o win_gad.o TimeKeeper.map + rm -Rf *.o + rm -Rf TimeLogger + rm -Rf TimeLogger.map + rm -Rf TimeKeeper + rm -Rf TimeKeeper.map + rm -Rf obj depend: @echo Dependencies already done diff --git a/TimeKeeper.guide b/TimeKeeper.guide index 6759ce3..9aaabbc 100644 --- a/TimeKeeper.guide +++ b/TimeKeeper.guide @@ -1,9 +1,9 @@ @database TimeKeeper.guide -@$VER: TimeKeeper.guide 1.09 (2019-07-14) -@(c) 2017-2019 Carsten Sonne Larsen +@$VER: TimeKeeper.guide 1.10 (20.03.2020) +@(c) 2017-2020 Carsten Sonne Larsen @author Carsten Sonne Larsen -@rem Copyright (c) 2017-2019 Carsten Sonne Larsen +@rem Copyright (c) 2017-2020 Carsten Sonne Larsen @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or without @@ -41,14 +41,17 @@ either directly from the command line or by using the tool types 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. +or a similar tool. In AmigaOS 3.1 and 3.9 this is available through +the Locale Preferences Editor. Daylight saving time is only supported +through the POSIX TZ environment variable. @{"Configuring the client" Link "Configuring the client"} @{"Using tooltypes of an icon" Link "Using tooltypes of an icon"} @{"Saving preferences" Link "Saving preferences"} +@{"The POSIX TZ environment variable" Link "The POSIX TZ environment variable"} @{"Change Log / Change History" Link "Change Log"} @{"Software License" Link "Software License"} +@{"Credits and donations" Link "Credits and donations"} @{"Contacting the author" Link "Contacting the author"} @EndNode @@ -81,7 +84,7 @@ 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. +is the NTP server port different from 123. @{b}Interval between requests@{ub} @@ -111,7 +114,7 @@ setup and other time related parameters. @{b}Expert mode@{ub} -Advanced settings are hidden from the settings windown when expert mode +Advanced settings are hidden from the settings window when expert mode is not enabled. The advanced settings are server port, interval between requests, adjustment threshold, connection timeout, verbosity level and commodity priority. @@ -124,17 +127,18 @@ 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 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 -3 is equal to maximum verbosity. - @{b}Log file@{ub} It is possible to send log messages to a file instead of sending them to a console window. +@{b}Caveats@{ub} + +AmiTimeKeeper does not start as a background process. When started in the +startup-sequence it will by default block execution. Use the run command +to avoid this behaviour: +> RUN >NIL: TimeKeeper + @EndNode @Node "Using tooltypes of an icon" "TimeKeeper.guide/Using tooltypes of an icon" @@ -162,8 +166,6 @@ CX_PRIORITY | Commodity priority READONLY | Do not set clock EXPERT | Show advanced options TIMEOUT | Connection Timeout -VERBOSE | Log verbosity -LOGFILE | Log file location @{b}Caveats@{ub} @@ -177,12 +179,16 @@ 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. +When using WBStartup folder or a similar system, remember to add the +mandatory tooltype DONOTWAIT. Otherwise the startup execution will be +blocked. + @EndNode @Node "Saving preferences" "TimeKeeper.guide/Saving preferences" @Toc "Main" @Prev "Using tooltypes of an icon" -@Next "Change Log" +@Next "The POSIX TZ environment variable" Preferences from the setting window are saved in the file ENV:timekeeper.prefs @@ -200,17 +206,470 @@ SERVER=de.pool.ntp.org PORT=123 TIMEOUT=5000 INTERVAL=17500 -VERBOSE=3 READONLY=NO EXPERT=NO -LOGFILE=RAM:log 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). +Not only visible settings in the settings window are saved to the +preference file. All setting are saved includes default settings and +settings from CLI and icon tooltype. + +@EndNode + +@Node "The POSIX TZ environment variable" "TimeKeeper.guide/The POSIX TZ environment variable" +@Toc "Main" +@Prev "Saving preferences" +@Next "Change Log" + +This is a list of time zone information for locations around the globe. +Information is represented in the POSIX TZ environment variable format. +The list originates from the IANA time zone database version 2019b. + +A formal definition of the POSIX TZ environment variable is available +to the public from The GNU C Library Reference Manual and The Open Group +Library. + +The POSIX TZ environment variable is described in dept by for example +The Open Group Base Specifications Issue 7, 2018 edition and The GNU C +Library Reference Manual. + +Set the TZ environment variable to Central Europe Time: +> SETENV TZ CET-1 + +Set the TZ environment variable to Central Europe Summer Time: +> SETENV TZ CET-1CEST + +Set the TZ environment variable for Paris: +> SETENV TZ CET-1CEST,M3.5.0,M10.5.0/3 + +Save the TZ environment to the current system disk: +> COPY ENV:TZ ENVARC:TZ + +Africa/Abidjan TZ GMT0 +Africa/Accra TZ GMT0 +Africa/Addis Ababa TZ EAT-3 +Africa/Algiers TZ CET-1 +Africa/Asmara TZ EAT-3 +Africa/Asmera TZ EAT-3 +Africa/Bamako TZ GMT0 +Africa/Bangui TZ WAT-1 +Africa/Banjul TZ GMT0 +Africa/Bissau TZ GMT0 +Africa/Blantyre TZ CAT-2 +Africa/Brazzaville TZ WAT-1 +Africa/Bujumbura TZ CAT-2 +Africa/Cairo TZ EET-2 +Africa/Casablanca TZ -1 +Africa/Ceuta TZ CET-1CEST,M3.5.0,M10.5.0/3 +Africa/Conakry TZ GMT0 +Africa/Dakar TZ GMT0 +Africa/Dar es Salaam TZ EAT-3 +Africa/Djibouti TZ EAT-3 +Africa/Douala TZ WAT-1 +Africa/El Aaiun TZ -1 +Africa/Freetown TZ GMT0 +Africa/Gaborone TZ CAT-2 +Africa/Harare TZ CAT-2 +Africa/Johannesburg TZ SAST-2 +Africa/Juba TZ EAT-3 +Africa/Kampala TZ EAT-3 +Africa/Khartoum TZ CAT-2 +Africa/Kigali TZ CAT-2 +Africa/Kinshasa TZ WAT-1 +Africa/Lagos TZ WAT-1 +Africa/Libreville TZ WAT-1 +Africa/Lome TZ GMT0 +Africa/Luanda TZ WAT-1 +Africa/Lubumbashi TZ CAT-2 +Africa/Lusaka TZ CAT-2 +Africa/Malabo TZ WAT-1 +Africa/Maputo TZ CAT-2 +Africa/Maseru TZ SAST-2 +Africa/Mbabane TZ SAST-2 +Africa/Mogadishu TZ EAT-3 +Africa/Monrovia TZ GMT0 +Africa/Nairobi TZ EAT-3 +Africa/Ndjamena TZ WAT-1 +Africa/Niamey TZ WAT-1 +Africa/Nouakchott TZ GMT0 +Africa/Ouagadougou TZ GMT0 +Africa/Porto-Novo TZ WAT-1 +Africa/Sao Tome TZ GMT0 +Africa/Timbuktu TZ GMT0 +Africa/Tripoli TZ EET-2 +Africa/Tunis TZ CET-1 +Africa/Windhoek TZ CAT-2 +America/Adak TZ HST10HDT,M3.2.0,M11.1.0 +America/Anchorage TZ AKST9AKDT,M3.2.0,M11.1.0 +America/Anguilla TZ AST4 +America/Antigua TZ AST4 +America/Araguaina TZ +3 +America/Argentina/Buenos Aires TZ +3 +America/Argentina/Catamarca TZ +3 +America/Argentina/Cordoba TZ +3 +America/Argentina/Jujuy TZ +3 +America/Argentina/La Rioja TZ +3 +America/Argentina/Mendoza TZ +3 +America/Argentina/Rio Gallegos TZ +3 +America/Argentina/Salta TZ +3 +America/Argentina/San Juan TZ +3 +America/Argentina/San Luis TZ +3 +America/Argentina/Tucuman TZ +3 +America/Argentina/Ushuaia TZ +3 +America/Aruba TZ AST4 +America/Asuncion TZ +4 +America/Atikokan TZ EST5 +America/Bahia TZ +3 +America/Bahia Banderas TZ CST6CDT,M4.1.0,M10.5.0 +America/Barbados TZ AST4 +America/Belem TZ +3 +America/Belize TZ CST6 +America/Blanc-Sablon TZ AST4 +America/Boa Vista TZ +4 +America/Bogota TZ +5 +America/Boise TZ MST7MDT,M3.2.0,M11.1.0 +America/Cambridge Bay TZ MST7MDT,M3.2.0,M11.1.0 +America/Campo Grande TZ +4 +America/Cancun TZ EST5 +America/Caracas TZ +4 +America/Cayenne TZ +3 +America/Cayman TZ EST5 +America/Chicago TZ CST6CDT,M3.2.0,M11.1.0 +America/Chihuahua TZ MST7MDT,M4.1.0,M10.5.0 +America/Costa Rica TZ CST6 +America/Creston TZ MST7 +America/Cuiaba TZ +4 +America/Curacao TZ AST4 +America/Danmarkshavn TZ GMT0 +America/Dawson TZ PST8PDT,M3.2.0,M11.1.0 +America/Dawson Creek TZ MST7 +America/Denver TZ MST7MDT,M3.2.0,M11.1.0 +America/Detroit TZ EST5EDT,M3.2.0,M11.1.0 +America/Dominica TZ AST4 +America/Edmonton TZ MST7MDT,M3.2.0,M11.1.0 +America/Eirunepe TZ +5 +America/El Salvador TZ CST6 +America/Fort Nelson TZ MST7 +America/Fortaleza TZ +3 +America/Glace Bay TZ AST4ADT,M3.2.0,M11.1.0 +America/Goose Bay TZ AST4ADT,M3.2.0,M11.1.0 +America/Grand Turk TZ EST5EDT,M3.2.0,M11.1.0 +America/Grenada TZ AST4 +America/Guadeloupe TZ AST4 +America/Guatemala TZ CST6 +America/Guayaquil TZ +5 +America/Guyana TZ +4 +America/Halifax TZ AST4ADT,M3.2.0,M11.1.0 +America/Havana TZ CST5CDT,M3.2.0/0,M11.1.0/1 +America/Hermosillo TZ MST7 +America/Indiana/Indianapolis TZ EST5EDT,M3.2.0,M11.1.0 +America/Indiana/Knox TZ CST6CDT,M3.2.0,M11.1.0 +America/Indiana/Marengo TZ EST5EDT,M3.2.0,M11.1.0 +America/Indiana/Petersburg TZ EST5EDT,M3.2.0,M11.1.0 +America/Indiana/Tell City TZ CST6CDT,M3.2.0,M11.1.0 +America/Indiana/Vevay TZ EST5EDT,M3.2.0,M11.1.0 +America/Indiana/Vincennes TZ EST5EDT,M3.2.0,M11.1.0 +America/Indiana/Winamac TZ EST5EDT,M3.2.0,M11.1.0 +America/Inuvik TZ MST7MDT,M3.2.0,M11.1.0 +America/Iqaluit TZ EST5EDT,M3.2.0,M11.1.0 +America/Jamaica TZ EST5 +America/Juneau TZ AKST9AKDT,M3.2.0,M11.1.0 +America/Kentucky/Louisville TZ EST5EDT,M3.2.0,M11.1.0 +America/Kentucky/Monticello TZ EST5EDT,M3.2.0,M11.1.0 +America/Kralendijk TZ AST4 +America/La Paz TZ +4 +America/Lima TZ +5 +America/Los Angeles TZ PST8PDT,M3.2.0,M11.1.0 +America/Lower Princes TZ AST4 +America/Maceio TZ +3 +America/Managua TZ CST6 +America/Manaus TZ +4 +America/Marigot TZ AST4 +America/Martinique TZ AST4 +America/Matamoros TZ CST6CDT,M3.2.0,M11.1.0 +America/Mazatlan TZ MST7MDT,M4.1.0,M10.5.0 +America/Menominee TZ CST6CDT,M3.2.0,M11.1.0 +America/Merida TZ CST6CDT,M4.1.0,M10.5.0 +America/Metlakatla TZ AKST9AKDT,M3.2.0,M11.1.0 +America/Mexico City TZ CST6CDT,M4.1.0,M10.5.0 +America/Miquelon TZ +3 +America/Moncton TZ AST4ADT,M3.2.0,M11.1.0 +America/Monterrey TZ CST6CDT,M4.1.0,M10.5.0 +America/Montevideo TZ +3 +America/Montserrat TZ AST4 +America/Nassau TZ EST5EDT,M3.2.0,M11.1.0 +America/New York TZ EST5EDT,M3.2.0,M11.1.0 +America/Nipigon TZ EST5EDT,M3.2.0,M11.1.0 +America/Nome TZ AKST9AKDT,M3.2.0,M11.1.0 +America/Noronha TZ +2 +America/North Dakota/Beulah TZ CST6CDT,M3.2.0,M11.1.0 +America/North Dakota/Center TZ CST6CDT,M3.2.0,M11.1.0 +America/North Dakota/New Salem TZ CST6CDT,M3.2.0,M11.1.0 +America/Ojinaga TZ MST7MDT,M3.2.0,M11.1.0 +America/Panama TZ EST5 +America/Pangnirtung TZ EST5EDT,M3.2.0,M11.1.0 +America/Paramaribo TZ +3 +America/Phoenix TZ MST7 +America/Port-au-Prince TZ EST5EDT,M3.2.0,M11.1.0 +America/Port of Spain TZ AST4 +America/Porto Velho TZ +4 +America/Puerto Rico TZ AST4 +America/Punta Arenas TZ +3 +America/Rainy River TZ CST6CDT,M3.2.0,M11.1.0 +America/Rankin Inlet TZ CST6CDT,M3.2.0,M11.1.0 +America/Recife TZ +3 +America/Regina TZ CST6 +America/Resolute TZ CST6CDT,M3.2.0,M11.1.0 +America/Rio Branco TZ +5 +America/Santarem TZ +3 +America/Santo Domingo TZ AST4 +America/Sao Paulo TZ +3 +America/Scoresbysund TZ +1 +America/Sitka TZ AKST9AKDT,M3.2.0,M11.1.0 +America/St Barthelemy TZ AST4 +America/St Johns TZ NST3 +America/St Kitts TZ AST4 +America/St Lucia TZ AST4 +America/St Thomas TZ AST4 +America/St Vincent TZ AST4 +America/Swift Current TZ CST6 +America/Tegucigalpa TZ CST6 +America/Thule TZ AST4ADT,M3.2.0,M11.1.0 +America/Thunder Bay TZ EST5EDT,M3.2.0,M11.1.0 +America/Tijuana TZ PST8PDT,M3.2.0,M11.1.0 +America/Toronto TZ EST5EDT,M3.2.0,M11.1.0 +America/Tortola TZ AST4 +America/Vancouver TZ PST8PDT,M3.2.0,M11.1.0 +America/Whitehorse TZ PST8PDT,M3.2.0,M11.1.0 +America/Winnipeg TZ CST6CDT,M3.2.0,M11.1.0 +America/Yakutat TZ AKST9AKDT,M3.2.0,M11.1.0 +America/Yellowknife TZ MST7MDT,M3.2.0,M11.1.0 +Antarctica/Casey TZ -8 +Antarctica/Davis TZ -7 +Antarctica/DumontDUrville TZ -10 +Antarctica/Macquarie TZ -11 +Antarctica/Mawson TZ -5 +Antarctica/McMurdo TZ NZST-12NZDT,M9.5.0,M4.1.0/3 +Antarctica/Palmer TZ +3 +Antarctica/Rothera TZ +3 +Antarctica/Syowa TZ -3 +Antarctica/Troll TZ 0 +Antarctica/Vostok TZ -6 +Arctic/Longyearbyen TZ CET-1CEST,M3.5.0,M10.5.0/3 +Asia/Aden TZ -3 +Asia/Almaty TZ -6 +Asia/Amman TZ EET-2EEST,M3.5.4/24,M10.5.5/1 +Asia/Anadyr TZ -12 +Asia/Aqtau TZ -5 +Asia/Aqtobe TZ -5 +Asia/Ashgabat TZ -5 +Asia/Atyrau TZ -5 +Asia/Baghdad TZ -3 +Asia/Bahrain TZ -3 +Asia/Baku TZ -4 +Asia/Bangkok TZ -7 +Asia/Barnaul TZ -7 +Asia/Beirut TZ EET-2EEST,M3.5.0/0,M10.5.0/0 +Asia/Bishkek TZ -6 +Asia/Brunei TZ -8 +Asia/Chita TZ -9 +Asia/Choibalsan TZ -8 +Asia/Colombo TZ -5 +Asia/Damascus TZ EET-2EEST,M3.5.5/0,M10.5.5/0 +Asia/Dhaka TZ -6 +Asia/Dili TZ -9 +Asia/Dubai TZ -4 +Asia/Dushanbe TZ -5 +Asia/Famagusta TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Asia/Gaza TZ EET-2EEST,M3.5.5/0,M10.5.6/1 +Asia/Hebron TZ EET-2EEST,M3.5.5/0,M10.5.6/1 +Asia/Ho Chi Minh TZ -7 +Asia/Hong Kong TZ HKT-8 +Asia/Hovd TZ -7 +Asia/Irkutsk TZ -8 +Asia/Istanbul TZ -3 +Asia/Jakarta TZ WIB-7 +Asia/Jayapura TZ WIT-9 +Asia/Kabul TZ -4 +Asia/Kamchatka TZ -12 +Asia/Karachi TZ PKT-5 +Asia/Kathmandu TZ -5 +Asia/Khandyga TZ -9 +Asia/Kolkata TZ IST-5 +Asia/Krasnoyarsk TZ -7 +Asia/Kuala Lumpur TZ -8 +Asia/Kuching TZ -8 +Asia/Kuwait TZ -3 +Asia/Macau TZ CST-8 +Asia/Magadan TZ -11 +Asia/Makassar TZ WITA-8 +Asia/Manila TZ PST-8 +Asia/Muscat TZ -4 +Asia/Nicosia TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Asia/Novokuznetsk TZ -7 +Asia/Novosibirsk TZ -7 +Asia/Omsk TZ -6 +Asia/Oral TZ -5 +Asia/Phnom Penh TZ -7 +Asia/Pontianak TZ WIB-7 +Asia/Pyongyang TZ KST-9 +Asia/Qatar TZ -3 +Asia/Qostanay TZ -6 +Asia/Qyzylorda TZ -5 +Asia/Riyadh TZ -3 +Asia/Sakhalin TZ -11 +Asia/Samarkand TZ -5 +Asia/Seoul TZ KST-9 +Asia/Shanghai TZ CST-8 +Asia/Singapore TZ -8 +Asia/Srednekolymsk TZ -11 +Asia/Taipei TZ CST-8 +Asia/Tashkent TZ -5 +Asia/Tbilisi TZ -4 +Asia/Tehran TZ -3 +Asia/Thimphu TZ -6 +Asia/Tokyo TZ JST-9 +Asia/Tomsk TZ -7 +Asia/Ulaanbaatar TZ -8 +Asia/Urumqi TZ -6 +Asia/Ust-Nera TZ -10 +Asia/Vientiane TZ -7 +Asia/Vladivostok TZ -10 +Asia/Yakutsk TZ -9 +Asia/Yangon TZ -6 +Asia/Yekaterinburg TZ -5 +Asia/Yerevan TZ -4 +Atlantic/Azores TZ +1 +Atlantic/Bermuda TZ AST4ADT,M3.2.0,M11.1.0 +Atlantic/Canary TZ WET0WEST,M3.5.0/1,M10.5.0 +Atlantic/Cape Verde TZ +1 +Atlantic/Faroe TZ WET0WEST,M3.5.0/1,M10.5.0 +Atlantic/Madeira TZ WET0WEST,M3.5.0/1,M10.5.0 +Atlantic/Reykjavik TZ GMT0 +Atlantic/South Georgia TZ +2 +Atlantic/St Helena TZ GMT0 +Atlantic/Stanley TZ +3 +Australia/Adelaide TZ ACST-9 +Australia/Brisbane TZ AEST-10 +Australia/Broken Hill TZ ACST-9 +Australia/Currie TZ AEST-10AEDT,M10.1.0,M4.1.0/3 +Australia/Darwin TZ ACST-9 +Australia/Eucla TZ -8 +Australia/Hobart TZ AEST-10AEDT,M10.1.0,M4.1.0/3 +Australia/Lindeman TZ AEST-10 +Australia/Lord Howe TZ -10 +Australia/Melbourne TZ AEST-10AEDT,M10.1.0,M4.1.0/3 +Australia/Perth TZ AWST-8 +Australia/Sydney TZ AEST-10AEDT,M10.1.0,M4.1.0/3 +Europe/Amsterdam TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Andorra TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Astrakhan TZ -4 +Europe/Athens TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Belgrade TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Berlin TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Bratislava TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Brussels TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Bucharest TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Budapest TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Busingen TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Chisinau TZ EET-2EEST,M3.5.0,M10.5.0/3 +Europe/Copenhagen TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Dublin TZ IST-1GMT0,M10.5.0,M3.5.0/1 +Europe/Gibraltar TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Guernsey TZ GMT0BST,M3.5.0/1,M10.5.0 +Europe/Helsinki TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Isle of Man TZ GMT0BST,M3.5.0/1,M10.5.0 +Europe/Istanbul TZ -3 +Europe/Jersey TZ GMT0BST,M3.5.0/1,M10.5.0 +Europe/Kaliningrad TZ EET-2 +Europe/Kiev TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Kirov TZ -3 +Europe/Lisbon TZ WET0WEST,M3.5.0/1,M10.5.0 +Europe/Ljubljana TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/London TZ GMT0BST,M3.5.0/1,M10.5.0 +Europe/Luxembourg TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Madrid TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Malta TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Mariehamn TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Minsk TZ -3 +Europe/Monaco TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Moscow TZ MSK-3 +Europe/Nicosia TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Oslo TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Paris TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Podgorica TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Prague TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Riga TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Rome TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Samara TZ -4 +Europe/San Marino TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Sarajevo TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Saratov TZ -4 +Europe/Simferopol TZ MSK-3 +Europe/Skopje TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Sofia TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Stockholm TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Tallinn TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Tirane TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Ulyanovsk TZ -4 +Europe/Uzhgorod TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Vaduz TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Vatican TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Vienna TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Vilnius TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Volgograd TZ -4 +Europe/Warsaw TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Zagreb TZ CET-1CEST,M3.5.0,M10.5.0/3 +Europe/Zaporozhye TZ EET-2EEST,M3.5.0/3,M10.5.0/4 +Europe/Zurich TZ CET-1CEST,M3.5.0,M10.5.0/3 +Indian/Antananarivo TZ EAT-3 +Indian/Chagos TZ -6 +Indian/Christmas TZ -7 +Indian/Cocos TZ -6 +Indian/Comoro TZ EAT-3 +Indian/Kerguelen TZ -5 +Indian/Mahe TZ -4 +Indian/Maldives TZ -5 +Indian/Mauritius TZ -4 +Indian/Mayotte TZ EAT-3 +Indian/Reunion TZ -4 +Pacific/Apia TZ -13 +Pacific/Auckland TZ NZST-12NZDT,M9.5.0,M4.1.0/3 +Pacific/Bougainville TZ -11 +Pacific/Chatham TZ -12 +Pacific/Chuuk TZ -10 +Pacific/Efate TZ -11 +Pacific/Enderbury TZ -13 +Pacific/Fakaofo TZ -13 +Pacific/Funafuti TZ -12 +Pacific/Galapagos TZ +6 +Pacific/Gambier TZ +9 +Pacific/Guadalcanal TZ -11 +Pacific/Honolulu TZ HST10 +Pacific/Kiritimati TZ -14 +Pacific/Kosrae TZ -11 +Pacific/Kwajalein TZ -12 +Pacific/Majuro TZ -12 +Pacific/Marquesas TZ +9 +Pacific/Midway TZ SST11 +Pacific/Nauru TZ -12 +Pacific/Niue TZ +11 +Pacific/Norfolk TZ -11 +Pacific/Noumea TZ -11 +Pacific/Pago Pago TZ SST11 +Pacific/Palau TZ -9 +Pacific/Pitcairn TZ +8 +Pacific/Pohnpei TZ -11 +Pacific/Port Moresby TZ -10 +Pacific/Rarotonga TZ +10 +Pacific/Tahiti TZ +10 +Pacific/Tarawa TZ -12 +Pacific/Tongatapu TZ -13 +Pacific/Wake TZ -12 +Pacific/Wallis TZ -12 @EndNode @@ -219,13 +678,12 @@ 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.10 20.03.2020@{ub} + - RTC is no longer required during startup + - When time zone changes it is now recognized + - Several bugs affecting time zone logic fixed + - Documentation updated with POSIX TZ examples + - Compiled with upgraded GCC, version 6.2 @{b}v1.09 14.07.2019@{ub} - Initial DST support using POSIX TZ and Amiga TZONE variable @@ -235,7 +693,7 @@ build. - 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 + - Timer bug causing infinitive loop fixed - Memory leak in settings window fixed @{b}v1.07 15.02.2019@{ub} @@ -281,7 +739,7 @@ build. @Node "Software License" "TimeKeeper.guide/Software License" @Prev "Change Log" -@Next "Contacting the author" +@Next "Credits and donations" @Toc "Main" @{b}Simplified BSD License / 2-clause BSD license@{ub} @@ -289,7 +747,7 @@ build. Copyright (c) 2001, 02 Motoyuki Kasahara Copyright (c) 2007 TANDBERG Telecom AS Copyright (c) 2008-2009 Dag-Erling Smørgrav -Copyright (c) 2017-2019 Carsten Sonne Larsen +Copyright (c) 2017-2020 Carsten Sonne Larsen All rights reserved. Redistribution and use in source and binary forms, with or without @@ -314,20 +772,43 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. @EndNode -@Node "Contacting the author" "TimeKeeper.guide/Contacting the author" -@Toc "Main" +@Node "Credits and donations" "TimeKeeper.guide/Credits and donations" @Prev "Software License" +@Next "Contacting the author" +@Toc "Main" -The author of AmiTimeKeeper can be contacted using the following -email addresses: or . +A custom version has been integrated into the Icaros Desktop system. +The author encourages all developers with an interest to make their own +build. -Please notice is a member of several high volume -mailing lists and should not be used under normal circumstances. +The following people have contributed with bug reports, comments, +suggestions and donations: + +* aPEX from a1k.org +* Paolo Besser +* Knut Hansen +* Greg Donner +* Thomas Blatt +* Bartosz Makara +* Benny Damsgaard +* Neil Pearson + +If you like this software you can also consider to make a small +donation to the PayPal account . + +@EndNode + +@Node "Contacting the author" "TimeKeeper.guide/Contacting the author" +@Prev "Credits and donations" +@Toc "Main" + +The author of AmiTimeKeeper can be contacted using the email address +. Feel free to send suggestions, feature request and bug reports. General comment and questions are also welcome. Carsten Sonne Larsen -February 2019 +February 2020 @EndNode diff --git a/TimeKeeper.readme b/TimeKeeper.readme index f83959e..257ac1d 100644 --- a/TimeKeeper.readme +++ b/TimeKeeper.readme @@ -2,7 +2,7 @@ Short: Keep your time right Author: Carsten Larsen (carsten.larsen@mail.com) Uploader: Carsten Larsen (carsten.larsen@mail.com) Type: util/cdity -Version: 1.09 +Version: 1.10 Architecture: m68k-amigaos AmiTimeKeeper is a small program which keeps the time right on your @@ -18,60 +18,14 @@ 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. +The local time zone needs to be configured using Workbench preferences +or a similar tool. In AmigaOS 3.1 and 3.9 this is available through +the Locale Preferences Editor. Daylight saving time is only supported +through the POSIX TZ environment variable. -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.09 14.07.2019 - - Initial DST support using POSIX TZ and Amiga TZONE variable - - Restart synchronizer processes on DNS lookup failures - -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 +v1.10 20.03.2020 + - RTC is no longer required during startup + - When time zone changes it is now recognized + - Several bugs affecting time zone logic fixed + - Documentation updated with POSIX TZ examples + - Compiled with upgraded GCC, version 6.2 diff --git a/amiga.c b/amiga.c index dad1a0b..5bfd163 100644 --- a/amiga.c +++ b/amiga.c @@ -318,9 +318,9 @@ int daylight_c(void) return daylight; } -long timezone_c(void) +long Timezone_c(void) { - return timezone; + return Timezone; } long altzone_c(void) @@ -340,11 +340,11 @@ struct lc_time_T *_current_locale() } size_t -_strftime(const timezone_t sp, char *const s, const size_t maxsize, +_strftime(const Timezone_t sp, char *const s, const size_t maxsize, const char *const format, const struct tm *const t, struct lc_time_T *loc); size_t -strftime_lz(const timezone_t sp, char *const s, const size_t maxsize, +strftime_lz(const Timezone_t sp, char *const s, const size_t maxsize, const char *const format, const struct tm *const t, locale_t locale) { size_t res; @@ -422,7 +422,7 @@ void CurrentTimeGmt(ULONG *seconds, ULONG *micros) { ULONG sec, mic; CurrentTime(&sec, &mic); - *seconds = sec + (daylight ? altzone : timezone); + *seconds = sec + (daylight ? altzone : Timezone); *micros = mic; } @@ -446,7 +446,7 @@ struct tm *AmigaLocalTime(ULONG *seconds, struct tm *tm) return tm; } -struct tm *AmigaLocalTimeZ(ULONG *seconds, struct tm *tm, const timezone_t tz) +struct tm *AmigaLocalTimeZ(ULONG *seconds, struct tm *tm, const Timezone_t tz) { time_t time; if (tm == NULL) diff --git a/amiga.h b/amiga.h index 3a361ea..c6bcb99 100644 --- a/amiga.h +++ b/amiga.h @@ -50,7 +50,7 @@ "(" DATE_TEXT ")" #define TZVARIABLE1 "TZ" -#define TZVARIABLE2 "timezone.prefs" +#define TZVARIABLE2 "Timezone.prefs" #define TZVARIABLE TZVARIABLE1 #define ENVSIZE 128 @@ -110,7 +110,7 @@ struct lc_time_T /* amiga.c tz functions */ int daylight_c(void); -long timezone_c(void); +long Timezone_c(void); long altzone_c(void); char **tzname_c(void); int getsystime(struct timeval *tv); @@ -122,7 +122,7 @@ int settimeofday(const struct timeval *tv, void *tz); struct lc_time_T *openlc(locale_t locale); void closelc(struct lc_time_T *lc); extern const struct lc_time_T C_time_locale; -extern long timezone; +extern long Timezone; extern long altzone; extern int daylight; extern struct SignalSemaphore *TimerSemaphore; diff --git a/bin/bgdbserver b/bin/bgdbserver new file mode 100644 index 0000000000000000000000000000000000000000..ba3b8695e54c237c48aeac97c9e132062b681f6b GIT binary patch literal 18988 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 M)CbUO`z!wbKkl=H^8f$< literal 0 HcmV?d00001 diff --git a/broker.c b/broker.c index bd8ab70..ee6812e 100644 --- a/broker.c +++ b/broker.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,16 +25,35 @@ */ #include "config.h" +#include "global.h" +#include "notify.h" #include "message.h" +#include "setting.h" +#include "shutdown.h" +#include "sync.h" #include "mem.h" #include "win.h" +#include "tz.h" +#include "libraries/screennotify.h" + +#include "logmod.h" +#define MODULENAME "Main" #define EVT_HOTKEY 1L -static void ProcessMsg(void); -static void InitBroker(void); +static void MsgLoop(void); static void CleanupBroker(void); +struct AppBroker +{ + CxObj *Object; + struct MsgPort *BrokerPort; + struct MsgPort *NotifyPort; + struct MsgPort *ScreenPort; + APTR screenNotifyWB; + APTR screenNotifyPub; +}; + static struct NewBroker newBroker = { NB_VERSION, (STRPTR)APP_SHORT_NAME, @@ -44,50 +63,68 @@ static struct NewBroker newBroker = { COF_SHOW_HIDE, 0, 0, 0}; +static struct AppBroker Broker; +static volatile bool BrokerRunning = false; + void StartBroker(void) { LONG error; - struct Message *msg; CxObj *filter, *sender, *translate; - InitBroker(); + LogTrace("Initializing"); + Broker.Object = NULL; + Broker.BrokerPort = NULL; + Broker.NotifyPort = NULL; + Broker.ScreenPort = NULL; + Broker.screenNotifyWB = NULL; + Broker.screenNotifyPub = NULL; + Ports.BrokerPort = NULL; + Ports.MemoryPort = NULL; - Globals->Broker->BrokerPort = CreateMsgPort(); - if (Globals->Broker->BrokerPort == NULL) + Broker.BrokerPort = CreateMsgPort(); + if (Broker.BrokerPort == NULL) { LogError("Could not allocate broker port"); return; } - Globals->Broker->UserPort = CreateMsgPort(); - if (Globals->Broker->UserPort == NULL) + Ports.BrokerPort = CreateMsgPort(); + if (Ports.BrokerPort == NULL) { LogError("Could not allocate broker user port"); CleanupBroker(); return; } - Globals->Broker->ReplyPort = CreateMsgPort(); - if (Globals->Broker->ReplyPort == NULL) + Broker.NotifyPort = CreateMsgPort(); + if (Broker.NotifyPort == NULL) + { + LogError("Could not allocate broker notify port"); + CleanupBroker(); + return; + } + + Broker.ScreenPort = CreateMsgPort(); + if (Broker.ScreenPort == NULL) + { + LogError("Could not allocate broker screen port"); + CleanupBroker(); + return; + } + + Ports.MemoryPort = CreateMsgPort(); + if (Ports.MemoryPort == NULL) { LogError("Could not allocate broker reply port"); CleanupBroker(); return; } - Globals->Broker->ShutdownSigBit = AllocSignal(-1); - if (Globals->Broker->ShutdownSigBit == -1) - { - SendErrorMessage("Could not allocate signal for broker"); - CleanupBroker(); - return; - } + newBroker.nb_Port = Broker.BrokerPort; + newBroker.nb_Pri = Settings->Priority; - newBroker.nb_Port = Globals->Broker->BrokerPort; - newBroker.nb_Pri = Globals->Settings->Priority; - - Globals->Broker->Object = CxBroker(&newBroker, &error); - if (!Globals->Broker->Object) + Broker.Object = CxBroker(&newBroker, &error); + if (!Broker.Object) { switch (error) { @@ -95,7 +132,7 @@ void StartBroker(void) LogError("System problems (CBERR_SYSERR). Could not allocate broker object"); break; case CBERR_DUP: - LogWarning(APP_SHORT_NAME " is already running"); + LogWarn(APP_SHORT_NAME " is already running"); break; default: LogError("Could not allocate broker object (error code: %ld)", error); @@ -106,7 +143,7 @@ void StartBroker(void) return; } - filter = CxFilter(Globals->Settings->PopKey); + filter = CxFilter(Settings->PopKey); if (filter == NULL) { LogError("Could not allocate broker filter object"); @@ -114,9 +151,9 @@ void StartBroker(void) return; } - AttachCxObj(Globals->Broker->Object, filter); + AttachCxObj(Broker.Object, filter); - sender = CxSender(Globals->Broker->BrokerPort, EVT_HOTKEY); + sender = CxSender(Broker.BrokerPort, EVT_HOTKEY); if (sender == NULL) { LogError("Could not allocate broker sender object"); @@ -142,273 +179,385 @@ void StartBroker(void) switch (error) { case CBERR_SYSERR: - LogWarning("Commodity filter problems (CBERR_SYSERR)"); + LogWarn("Commodity filter problems (CBERR_SYSERR)"); break; case COERR_BADFILTER: - LogWarning("Commodity HOTKEY error"); + LogWarn("Commodity HOTKEY error"); break; default: - LogWarning("Commodity filter error (error code: %ld)", error); + LogWarn("Commodity filter error (error code: %ld)", error); break; } } - Globals->Broker->Task = FindTask(NULL); + if (ScreenNotifyBase != NULL) + { + Broker.screenNotifyWB = AddWorkbenchClient(Broker.ScreenPort, 0); + Broker.screenNotifyPub = AddPubScreenClient(Broker.ScreenPort, 0); + LogTrace("AddWorkbenchClient"); + } - StartCom(); - ProcessMsg(); + ActivateNotifyPort(Broker.NotifyPort); + StartSynchronizer(); - while ((msg = GetMsg(Globals->Broker->BrokerPort))) - ReplyMsg(msg); - - while ((msg = GetMsg(Globals->Broker->UserPort))) - ReplyMsg(msg); - - while ((msg = GetMsg(Globals->Broker->ReplyPort))) - ReplyMsg(msg); + MsgLoop(); CleanupBroker(); } -void ShutdownBroker(void) +bool IsBrokerRunning(void) { - Signal((struct Task *)Globals->Broker->Task, - (1 << Globals->Broker->ShutdownSigBit)); + return BrokerRunning; } - void SetBrokerPriority(int priority) { - SetCxObjPri(Globals->Broker->Object, priority); -} - -static void Activate(void) -{ - LogWarning("ACTIVE changed: 1 -> 0"); - ActivateCxObj(Globals->Broker->Object, 0); - Globals->Active = false; - StopComAsync(); - while (!CheckComClosed()) - Delay(1); + SetCxObjPri(Broker.Object, priority); } static void Deactivate(void) { - LogWarning("ACTIVE changed: 0 -> 1"); - ActivateCxObj(Globals->Broker->Object, 1); - Globals->Active = true; - StartCom(); + LogDebug("ACTIVE changed: 1 -> 0"); + LogWarn("Disabling time synchronization"); + SendMessageWait(Ports.SyncerPort, ATK_DISABLE); + ActivateCxObj(Broker.Object, 0); } -static void StopSubProcesses(void) +static void Activate(void) { - Forbid(); - Globals->ShuttingDown = true; - Permit(); - - HideSettingWindow(); - while (!CheckSettingWindowClosed()) - Delay(10); - - StopComAsync(); - while (!CheckComClosed()) - Delay(10); + LogDebug("ACTIVE changed: 0 -> 1"); + LogWarn("Enabling time synchronization"); + ActivateCxObj(Broker.Object, 1); + StartSynchronizer(); } -static void ProcessMsg(void) +static void ChangeTimezone(void) { - bool run = true; - ULONG sigmask = SIGBREAKF_CTRL_C | - (1 << Globals->Broker->ShutdownSigBit) | - (1 << Globals->Broker->BrokerPort->mp_SigBit) | - (1 << Globals->Broker->UserPort->mp_SigBit) | - (1 << Globals->Broker->ReplyPort->mp_SigBit); + // TODO: Make thread safe + CleanupTimezone(); + InitTimezone(); + SendMessageTo(Ports.WindowPort, Ports.MemoryPort, ATK_TZ_CHANGED); +} - ActivateCxObj(Globals->Broker->Object, 1); - Globals->Active = true; +static void ChangeTimezoneDelayedProc(void) +{ + // TODO: Make thread safe + Delay(15 * 50); + ReopenLocale(); + ChangeTimezone(); + SendMessageTo(Ports.WindowPort, Ports.MemoryPort, ATK_TZ_CHANGED); +} - if (Globals->Settings->Popup) +static void ChangeTimezoneDelayed(void) +{ + CreateNewProcTags( + NP_Entry, (IPTR)ChangeTimezoneDelayedProc, + NP_StackSize, 16 * 1024, + NP_Name, 0, + NP_Input, 0, + NP_Output, 0, + NP_Error, 0, + NP_CloseInput, FALSE, + NP_CloseOutput, FALSE, + NP_CloseError, FALSE, + NP_WindowPtr, 0, + NP_ConsoleTask, 0, + NP_Cli, FALSE, + TAG_DONE); +} + +static bool HandleBrokerMessage(LONG msgid, ULONG msgtype) +{ + switch (msgtype) + { + case CXM_IEVENT: + switch (msgid) + { + case EVT_HOTKEY: + LogDebug("Show window"); + ShowSettingWindow(); + break; + default: + break; + } + break; + case CXM_COMMAND: + switch (msgid) + { + case CXCMD_DISABLE: + Deactivate(); + break; + case CXCMD_ENABLE: + Activate(); + break; + case CXCMD_KILL: + LogInfo("Received shut down from commodity"); + return false; + break; + case CXCMD_UNIQUE: + LogWarn("Commodity duplicate detected"); + LogDebug("Show window"); + ShowSettingWindow(); + break; + case CXCMD_APPEAR: + LogDebug("Show window"); + ShowSettingWindow(); + break; + case CXCMD_DISAPPEAR: + LogDebug("Hide window"); + SendMessageTo(Ports.WindowPort, Ports.MemoryPort, ATK_SHUTDOWN); + break; + default: + break; + } + } + + return true; +} + +static bool HandleUserMessage(long msg) +{ + switch (msg) + { + case ATK_STORE: + SaveSettings(true); + SaveSettings(false); + SendMessageTo(Ports.WindowPort, Ports.MemoryPort, ATK_SHUTDOWN); + break; + case ATK_APPLY: + SaveSettings(false); + SendMessageTo(Ports.WindowPort, Ports.MemoryPort, ATK_SHUTDOWN); + break; + case ATK_UNDO: + ApplyAppSettings(WindowSettings, true); + SendMessageTo(Ports.WindowPort, Ports.MemoryPort, ATK_SHUTDOWN); + break; + case ATK_RESTART: + SendMessageWait(Ports.SyncerPort, ATK_RESTART); + break; + case ATK_DISABLE: + Activate(); + break; + case ATK_ENABLE: + Deactivate(); + break; + case ATK_READONLY: + LogDebug("READONLY changed: 1 -> 0"); + LogWarn("Entering read only mode. Clock is not adjusted in read-only mode"); + break; + case ATK_READWRITE: + LogDebug("READONLY changed: 0 -> 1"); + LogWarn("Leaving read only mode. Clock is adjusted again"); + break; + case ATK_SHUTDOWN: + return false; + break; + default: + break; + } + + return true; +} + +static void MsgLoop(void) +{ + bool reopenWindow = false; + bool loop = true; + long shutdown = LOOP_RUNNING; + ULONG brokerSigMask = (1 << Broker.BrokerPort->mp_SigBit); + ULONG userSigMask = (1 << Ports.BrokerPort->mp_SigBit); + ULONG replySigMask = (1 << Ports.MemoryPort->mp_SigBit); + ULONG notifySigMask = (1 << Broker.NotifyPort->mp_SigBit); + ULONG screenSigMask = (1 << Broker.ScreenPort->mp_SigBit); + ULONG sigMask = brokerSigMask | notifySigMask | userSigMask | + screenSigMask | replySigMask | SIGBREAKF_CTRL_C; + + BrokerRunning = true; + LogTrace("Loop started"); + + ActivateCxObj(Broker.Object, 1); + + if (Settings->Popup) { ShowSettingWindow(); } do { - ULONG sigrcvd = Wait(sigmask); - - if (sigrcvd & (1 << Globals->Broker->BrokerPort->mp_SigBit)) + ULONG sigrcvd = Wait(sigMask); + if (sigrcvd & brokerSigMask) { CxMsg *msg; - while ((msg = (CxMsg *)GetMsg(Globals->Broker->BrokerPort))) + while ((msg = (CxMsg *)GetMsg(Broker.BrokerPort))) { - LONG msgid = CxMsgID(msg); - ULONG msgtype = CxMsgType(msg); + bool cont; + LONG msgId = CxMsgID(msg); + ULONG msgType = CxMsgType(msg); ReplyMsg((struct Message *)msg); - switch (msgtype) + cont = HandleBrokerMessage(msgId, msgType); + if (!cont) { - case CXM_IEVENT: - switch (msgid) - { - case EVT_HOTKEY: - LogTrace("Show window"); - ShowSettingWindow(); - break; - } - break; - case CXM_COMMAND: - switch (msgid) - { - case CXCMD_DISABLE: - Activate(); - break; - case CXCMD_ENABLE: - Deactivate(); - break; - case CXCMD_KILL: - LogInfo("Received shut down from commodity"); - StopSubProcesses(); - run = false; - break; - case CXCMD_UNIQUE: - LogWarning("Commodity duplicate detected"); - LogTrace("Show window"); - ShowSettingWindow(); - break; - case CXCMD_APPEAR: - LogTrace("Show window"); - ShowSettingWindow(); - break; - case CXCMD_DISAPPEAR: - LogTrace("Hide window"); - HideSettingWindow(); - break; - } + shutdown = SHUTDOWN_REQUEST; } } } - if (sigrcvd & (1 << Globals->Broker->UserPort->mp_SigBit)) + if (sigrcvd & userSigMask) { - struct AppWindowMessage *msg; - while ((msg = (struct AppWindowMessage *)GetMsg(Globals->Broker->UserPort))) + struct ApplicationMesage *msg; + while ((msg = (struct ApplicationMesage *)GetMsg(Ports.BrokerPort))) { - switch (msg->Type) + bool cont; + long msgId = msg->MsgId; + ReplyMsg((struct Message *)msg); + + cont = HandleUserMessage(msgId); + if (!cont) { - case ATK_LOGERROR: - LogError(msg->Text); + loop = false; + } + } + } + + if (sigrcvd & notifySigMask) + { + struct NotifyMessage *msg; + while ((msg = (struct NotifyMessage *)GetMsg(Broker.NotifyPort))) + { + long msgType = msg->nm_NReq->nr_UserData; + ReplyMsg((struct Message *)msg); + switch (msgType) + { + case ATK_TZ_CHANGED: + LogDebug("TZ changed"); + ChangeTimezone(); break; - case ATK_LOGWARN: - LogWarning(msg->Text); + case ATK_TZONE_CHANGED: + LogDebug("TZONE changed"); + ChangeTimezone(); break; - case ATK_LOGINFO: - LogInfo(msg->Text); - break; - case ATK_LOGTRACE: - LogTrace(msg->Text); - break; - case ATK_STORE: - SaveSettings(true); - SaveSettings(false); - break; - case ATK_APPLY: - SaveSettings(false); - break; - case ATK_UNDO: - ApplyAppSettings(Globals->Window->Settings, true); - break; - case ATK_RESTART: - RestartSntpAsync(); - break; - case ATK_REFRESH: - // Broker cannot refresh - break; - case ATK_DISABLE: - Activate(); - break; - case ATK_ENABLE: - Deactivate(); - break; - case ATK_READONLY: - LogWarning("READONLY changed: 1 -> 0"); - break; - case ATK_READWRITE: - LogWarning("READONLY changed: 0 -> 1"); - break; - default: + case ATK_LOCALE_CHANGED: + LogError("Locale changed"); + ChangeTimezoneDelayed(); break; } + break; + } + } + + if (sigrcvd & screenSigMask) + { + struct ScreenNotifyMessage *msg; + while ((msg = (struct ScreenNotifyMessage *)GetMsg(Broker.ScreenPort))) + { + LogDebug("ScreenNotifyMessage"); + if (msg->snm_Type == SCREENNOTIFY_TYPE_WORKBENCH) + { + if (msg->snm_Value == NULL) + { + LogDebug("WB Close"); + LogDebug("Hide window"); + SendMessageTo(Ports.WindowPort, + Ports.MemoryPort, + ATK_DISABLE); + reopenWindow = WindowProcRunning; + } + else + { + LogDebug("WB Open"); + if (reopenWindow) + { + ShowSettingWindow(); + } + ReopenLocale(); + ChangeTimezone(); + reopenWindow = false; + } + } ReplyMsg((struct Message *)msg); } } - if (sigrcvd & (1 << Globals->Broker->ReplyPort->mp_SigBit)) + if (sigrcvd & replySigMask) { - struct AppWindowMessage *msg; - while ((msg = (struct AppWindowMessage *)GetMsg(Globals->Broker->ReplyPort))) + struct ApplicationMesage *msg; + while ((msg = (struct ApplicationMesage *)GetMsg(Ports.MemoryPort))) { - if (msg->Text != NULL) - { - FreeMemSafe(msg->Text, __FUNCTION__); - } - FreeMemSafe(msg, __FUNCTION__); + FreeMemSafe(msg); } } - if (sigrcvd & (1 << Globals->Broker->ShutdownSigBit)) - { - LogInfo("Received shut down from setting window"); - StopSubProcesses(); - run = false; - } - if (sigrcvd & SIGBREAKF_CTRL_C) { LogInfo("Received CTRL + C"); - StopSubProcesses(); - run = false; + shutdown = SHUTDOWN_REQUEST; } - } while (run); -} -static void InitBroker(void) -{ - Globals->Broker->Object = NULL; - Globals->Broker->ShutdownSigBit = -1; - Globals->Broker->Task = NULL; - Globals->Broker->BrokerPort = NULL; - Globals->Broker->UserPort = NULL; - Globals->Broker->ReplyPort = NULL; + if (shutdown == SHUTDOWN_REQUEST) + { + struct ShutdownInfo si; + si.BrokerPort = Ports.BrokerPort; + si.SynchronizerPort = Ports.SyncerPort; + si.SettingWindowPort = Ports.WindowPort; + si.ShutdownMessage = ATK_SHUTDOWN; + shutdown = SHUTTING_DOWN; + StartShutdown(&si); + } + } while (loop); + + BrokerRunning = false; + LogTrace("Loop exited"); } static void CleanupBroker(void) { - if (Globals->Broker->Object != NULL) + struct ApplicationMesage *msg; + + if (Broker.screenNotifyWB != NULL) { - DeleteCxObjAll(Globals->Broker->Object); - Globals->Broker->Object = NULL; + LogTrace("ScreenNotify WB cleared"); + while (!RemWorkbenchClient(Broker.screenNotifyWB)) + { + Delay(10); + } } - if (Globals->Broker->ShutdownSigBit != -1) + if (Broker.screenNotifyPub != NULL) { - FreeSignal(Globals->Broker->ShutdownSigBit); - Globals->Broker->ShutdownSigBit = -1; + LogTrace("ScreenNotify PubScreen cleared"); + while (!RemPubScreenClient(Broker.screenNotifyPub)) + { + Delay(10); + } } - if (Globals->Broker->BrokerPort != NULL) + CleanupNotifications(); + + if (Broker.Object != NULL) { - DeleteMsgPort(Globals->Broker->BrokerPort); - Globals->Broker->BrokerPort = NULL; + DeleteCxObjAll(Broker.Object); + Broker.Object = NULL; + LogTrace("CxObj cleared"); } - if (Globals->Broker->UserPort != NULL) - { - DeleteMsgPort(Globals->Broker->UserPort); - Globals->Broker->UserPort = NULL; - } + CleanupMsgPort(&Broker.BrokerPort); + LogTrace("BrokerPort cleared"); - if (Globals->Broker->ReplyPort != NULL) + CleanupMsgPort(&Broker.NotifyPort); + LogTrace("NotifyPort cleared"); + + CleanupMsgPort(&Broker.ScreenPort); + LogTrace("ScreenPort cleared"); + + CleanupVolMsgPort(&Ports.BrokerPort); + LogTrace("UserPort cleared"); + + while ((msg = (struct ApplicationMesage *)GetMsg(Ports.MemoryPort))) { - DeleteMsgPort(Globals->Broker->ReplyPort); - Globals->Broker->ReplyPort = NULL; + FreeMemSafe(msg); } + LogTrace("ReplyPort Msg cleared"); + + CleanupVolMsgPort(&Ports.MemoryPort); + LogTrace("ReplyPort cleared"); } diff --git a/compiler.h b/compiler.h index 826816d..6392cb6 100644 --- a/compiler.h +++ b/compiler.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2014-2019 Carsten Sonne Larsen + * Copyright (c) 2014-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,17 +21,22 @@ * 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. - * + * */ #ifndef COMPILER_H_INCLUDED #define COMPILER_H_INCLUDED +#include +#include + #ifndef __cplusplus +#ifndef bool typedef int bool; #define true 1 #define false 0 #endif +#endif #ifdef __GNUC__ #ifndef REG diff --git a/config.h b/config.h index 753e37b..901b622 100644 --- a/config.h +++ b/config.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,7 +50,6 @@ #include #include #include -#include #include #include @@ -59,7 +58,7 @@ #include "compiler.h" -//#define DEBUG_BUILD 1 +#define DEBUG_BUILD 1 #if defined(AROS) || defined(__CLIB2__) #include @@ -75,15 +74,20 @@ typedef uint32_t uintptr_t; #if defined(__CLIB2__) #define __NO_NET_API -#define NO_INLINE_STDARG +//define NO_INLINE_STDARG +//#define MISSING_ADDRINFO +#include +#include #endif -#if defined(AROS) || defined(__CLIB2__) +#if defined(AROS) +#include #include #include #endif #if defined(__libnix__) +#include #include #include "clib/amitcp_protos.h" #endif @@ -100,6 +104,9 @@ typedef uint32_t uintptr_t; #include #endif +#include "clib/screennotify.h" +#include "proto/screennotify.h" + #ifdef MAXPATHLEN #undef MAXPATHLEN #endif @@ -113,7 +120,7 @@ typedef uint32_t uintptr_t; #define MAXFILELEN 256 #define MAXFILEPATHLEN MAXPATHLEN + MAXFILELEN #define MAXDOSERRORLEN 256 -#define SETTINGMESSAGELEN 128 +#define LOGMESSAGELEN 128 #ifndef HAVE_POLL #define POLLIN 0x0001 @@ -142,24 +149,23 @@ int poll(struct pollfd *, nfds_t, int); #define COM_ERROR -1 #ifdef AROS -#define APP_SHORT_NAME "ArosTimeKeeper" +#define APP_SHORT_NAME "TimeKeeper" #define APP_LONG_NAME "AROS Time Keeper" #else -#define APP_SHORT_NAME "AmiTimeKeeper" +#define APP_SHORT_NAME "TimeKeeper" #define APP_LONG_NAME "Amiga Time Keeper" #endif -#define APP_VERSION "1.09" -#define APP_DATE_VERSION "1.09 (14.07.2019)" +#define APP_VERSION "1.10" +#define APP_DATE_VERSION "1.10 (20.03.2020)" #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 #include "log.h" -#include "state.h" #include "string.h" -#define KEYWORD_COUNT 12 +#define KEYWORD_COUNT 10 #define KEYWORD_SERVER "SERVER" #define KEYWORD_PORT "PORT" #define KEYWORD_THRESHOLD "THRESHOLD" @@ -170,8 +176,6 @@ int poll(struct pollfd *, nfds_t, int); #define KEYWORD_READONLY "READONLY" #define KEYWORD_EXPERT "EXPERT" #define KEYWORD_TIMEOUT "TIMEOUT" -#define KEYWORD_VERBOSE "VERBOSE" -#define KEYWORD_LOGFILE "LOGFILE" #define SERVER_DEF "pool.ntp.org" #define PORT_DEF "123" @@ -187,47 +191,25 @@ int poll(struct pollfd *, nfds_t, int); #define TIMEOUT_MIN 100 #define TIMEOUT_DEF 5000 #define TIMEOUT_MAX 30000 -#define VERBOSE_MIN 0 -#define VERBOSE_DEF 0 -#define VERBOSE_MAX 3 -#define LOGFILE_DEF NULL #define POPKEY_DEF "lshift control t" #define POPUP_DEF 0 #define KEYWORD_TEMPLATE_1 KEYWORD_READONLY "/S," KEYWORD_EXPERT "/S," KEYWORD_SERVER "/K," KEYWORD_PORT "/K," KEYWORD_TIMEOUT "/N/K," -#define KEYWORD_TEMPLATE_2 KEYWORD_THRESHOLD "/K," KEYWORD_INTERVAL "/N/K," KEYWORD_VERBOSE "/N/K," -#define KEYWORD_TEMPLATE_3 KEYWORD_PRIORITY "/N/K," KEYWORD_POPKEY "/K," KEYWORD_POPUP "/K," KEYWORD_LOGFILE "/K" +#define KEYWORD_TEMPLATE_2 KEYWORD_THRESHOLD "/K," KEYWORD_INTERVAL "/N/K," +#define KEYWORD_TEMPLATE_3 KEYWORD_PRIORITY "/N/K," KEYWORD_POPKEY "/K," KEYWORD_POPUP "/K," #define KEYWORD_TEMPLATE KEYWORD_TEMPLATE_1 KEYWORD_TEMPLATE_2 KEYWORD_TEMPLATE_3 /* broker.c */ void StartBroker(void); +bool IsBrokerRunning(void); void SetBrokerPriority(int); -void ShutdownBroker(void); - -/* com.c */ -void StartCom(void); -void StopComAsync(void); -void RestartSntpAsync(void); -bool CheckComClosed(void); - -/* win_main.c */ -void ShowSettingWindow(void); -void HideSettingWindow(void); /* libraries.c */ int OpenLibraries(void); void CloseLibraries(void); +void ReopenLocale(void); /* val.c */ void SanitizeSettings(void); -/* net.c */ -int OpenSocketLibrary(void); -void CloseSocketLibrary(void); -const char *GetErrorText(void); -const char *GetHostErrorText(void); -int GetErrorNo(void); -int GetHostErrorNo(void); -extern struct Library *SocketBase; - #endif diff --git a/dist/TimeKeeper b/dist/TimeKeeper new file mode 100644 index 0000000000000000000000000000000000000000..c9118acc42458515aca559ebb2816ca535f7b025 GIT binary patch literal 94252 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 literal 0 HcmV?d00001 diff --git a/dist/TimeLogger.map b/dist/TimeLogger.map new file mode 100644 index 0000000..4802d97 --- /dev/null +++ b/dist/TimeLogger.map @@ -0,0 +1,935 @@ +Archive member included to satisfy reference by file (symbol) + +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_dosbase.o) + logger.o (DOSBase) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) + /opt/amiga/m68k-amigaos/clib2/lib/ncrt0.o (_main) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_osliberror.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__minimum_os_lib_error) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_oslibversion.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__minimum_os_lib_version) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_priority.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__priority) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_process_name.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__process_name) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_setjmp.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (setjmp) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_set_process_window.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__set_process_window) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_showerror.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__show_error) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_stacksize.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__stack_size) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__argv) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_swapstack.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__swap_stack_and_call) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_sysbase.o) + logger.o (SysBase) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_utilitybase.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__UtilityBase) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_udivsi3.o) + string.o (__udivsi3) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_udivsi4.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_udivsi3.o) (__udivsi4) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_umodsi3.o) + string.o (__umodsi3) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_memmove.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) (memmove) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_strlen.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) (strlen) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_data.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__check_abort_enabled) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush_all_files.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__flush_all_files) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flushiobwritebuffer.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush_all_files.o) (__flush_iob_write_buffer) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush_all_files.o) (__iob) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__WBenchMsg) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_iobhookentry.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) (__iob_hook_entry) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_nostdio.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__no_standard_io) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_checkdetach.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__check_detach) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor_begin.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (_init) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_destructor.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor_begin.o) (__DTOR_LIST__) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_detach.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__detach) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_disablerequesters.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__disable_dos_requesters) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (exit) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) (free) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_getdefstacksize.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__get_default_stack_size) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_isresident.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) (__is_resident) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) (malloc) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) (__program_name) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_set_errno.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flushiobwritebuffer.o) (__set_errno) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_shell_escape.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) (__shell_escape_character) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) (__slab_allocate) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab_max_size.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) (__slab_max_size) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab_purge_threshold.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) (__slab_purge_threshold) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_stdio_window_spec.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) (__stdio_window_specification) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_threshold.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) (__free_memory_threshold) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_memset.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) (memset) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_strcat.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) (strcat) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_strcpy.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) (strcpy) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) (__original_current_directory) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(errno_data.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) (errno) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(fcntl_close.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) (close) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_checkabort.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flushiobwritebuffer.o) (__check_abort) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_mask.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_checkabort.o) (__break_signal_mask) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_checkabort.o) (raise) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fclose.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) (fclose) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) (__fd_hook_entry) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_get_file_descriptor.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_iobhookentry.o) (__get_file_descriptor) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growfdtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) (__grow_fd_table) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growiobtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) (__grow_iob_table) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_initializefd.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) (__initialize_fd) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_initializeiob.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) (__initialize_iob) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_parent_of_fh.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) (__safe_parent_of_file_handle) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_remove_fd_alias.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) (__remove_fd_alias) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_translateioerror.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) (__translate_io_error_to_errno) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_abort.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) (abort) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_alloca_cleanup.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) (__alloca_cleanup) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_atexit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) (__exit_trap_trigger) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor_begin.o) (__CTOR_LIST__) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_default_pool_size.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) (__default_pool_size) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_default_puddle_size.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) (__default_puddle_size) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_termination_message.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) (__print_termination_message) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_examine_fh.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) (__safe_examine_file_handle) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_termination_message.o) (fputc) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputs.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_termination_message.o) (fputs) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_dropiobreadbuffer.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputc.o) (__drop_iob_read_buffer) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputs.o) (__flush) +/opt/amiga/m68k-amigaos/clib2/lib/libamiga.a(amiga_newlist.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) (NewList) +/opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_udivdi3.o) + string.o (__udivdi3) +/opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_umoddi3.o) + string.o (__umoddi3) +/opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_clz.o) + /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_udivdi3.o) (__clz_tab) +/opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_mulsi3.o) + /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_udivdi3.o) (__mulsi3) + +Set Symbol + +___EXIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o):stdio_init_exit.o:(.text+0x88) +___EXIT_LIST__ ** ABS ** +___EXIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o):stdio_file_init.o:(.text+0x0) +___EXIT_LIST__ ** ABS ** +___EXIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o):stdlib_malloc.o:(.text+0x162) +___EXIT_LIST__ ** ABS ** +___EXIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o):stdlib_program_name.o:(.text+0x0) +___EXIT_LIST__ ** ABS ** +___EXIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o):unistd_chdir_exit.o:(.text+0x0) +___EXIT_LIST__ ** ABS ** +___INIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o):stdlib_arg.o:(.text+0x26) +___INIT_LIST__ ** ABS ** +___INIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o):stdio_init_exit.o:(.text+0x8e) +___INIT_LIST__ ** ABS ** +___INIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o):stdio_file_init.o:(.text+0x9c) +___INIT_LIST__ ** ABS ** +___INIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o):stdlib_malloc.o:(.text+0x1dc) +___INIT_LIST__ ** ABS ** +___INIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o):stdlib_program_name.o:(.text+0x28) +___INIT_LIST__ ** ABS ** + +Memory Configuration + +Name Origin Length Attributes +*default* 0x0000000000000000 0xffffffffffffffff + +Linker script and memory map + +LOAD /opt/amiga/m68k-amigaos/clib2/lib/ncrt0.o +LOAD logger.o +LOAD string.o +START GROUP +LOAD /opt/amiga/m68k-amigaos/clib2/lib/libc.a +LOAD /opt/amiga/m68k-amigaos/clib2/lib/libdebug.a +LOAD /opt/amiga/m68k-amigaos/clib2/lib/libamiga.a +LOAD /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a +END GROUP + [!provide] PROVIDE (___machtype = 0x0) + 0x0000000000000000 . = 0x0 + +.text 0x0000000000000000 0x47c8 + 0x0000000000000000 __stext = . + *(.text) + .text 0x0000000000000000 0x14 /opt/amiga/m68k-amigaos/clib2/lib/ncrt0.o + 0x0000000000000006 geta4 + 0x0000000000000006 __restore_a4 + 0x0000000000000008 __get_a4 + 0x000000000000000c __set_a4 + .text 0x0000000000000014 0x48c logger.o + 0x0000000000000074 main + .text 0x00000000000004a0 0x800 string.o + 0x00000000000004b0 StrLen + 0x00000000000004e6 StrCopy + 0x000000000000052e AppendText + 0x0000000000000580 TrimRight + 0x000000000000060c StrChr + 0x0000000000000656 StrRChr + 0x00000000000006a6 StartsWith + 0x0000000000000702 EndsWith + 0x000000000000078c LongToStr + 0x0000000000000888 LongLongToStr + 0x00000000000009ce StrToLongLong + 0x0000000000000ad6 TryParseLong + 0x0000000000000b32 TryParseLongLong + 0x0000000000000be4 VSNPrintf + 0x0000000000000c6a SNPrintf + .text 0x0000000000000ca0 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_dosbase.o) + .text 0x0000000000000ca0 0x58c /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) + 0x0000000000000e22 _main + .text 0x000000000000122c 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_osliberror.o) + .text 0x000000000000122c 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_oslibversion.o) + .text 0x000000000000122c 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_priority.o) + .text 0x000000000000122c 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_process_name.o) + .text 0x000000000000122c 0x40 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_setjmp.o) + 0x000000000000122c setjmp + 0x0000000000001248 longjmp + .text 0x000000000000126c 0x20 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_set_process_window.o) + 0x000000000000126c __set_process_window + .text 0x000000000000128c 0x1c4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_showerror.o) + 0x00000000000012b8 __show_error + .text 0x0000000000001450 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_stacksize.o) + .text 0x0000000000001450 0x284 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + 0x0000000000001476 __ctor_arg_init + .text 0x00000000000016d4 0x2c /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_swapstack.o) + 0x00000000000016d4 __swap_stack_and_call + .text 0x0000000000001700 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_sysbase.o) + .text 0x0000000000001700 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_utilitybase.o) + .text 0x0000000000001700 0xc /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_udivsi3.o) + 0x0000000000001700 __udivsi3 + .text 0x000000000000170c 0xc /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_udivsi4.o) + 0x000000000000170c __udivsi4 + .text 0x0000000000001718 0x10 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_umodsi3.o) + 0x0000000000001718 __umodsi3 + .text 0x0000000000001728 0x258 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_memmove.o) + 0x0000000000001728 memmove + .text 0x0000000000001980 0x14 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_strlen.o) + 0x0000000000001980 strlen + .text 0x0000000000001994 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_data.o) + .text 0x0000000000001994 0x7c /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush_all_files.o) + 0x0000000000001994 __flush_all_files + .text 0x0000000000001a10 0x80 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flushiobwritebuffer.o) + 0x0000000000001a10 __flush_iob_write_buffer + .text 0x0000000000001a90 0xbc /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + 0x0000000000001a90 __close_all_files + 0x0000000000001b18 __dtor_stdio_exit + 0x0000000000001b1e __ctor_stdio_init + .text 0x0000000000001b4c 0x458 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + 0x0000000000001b4c __dtor_workbench_exit + 0x0000000000001be8 __ctor_stdio_file_init + .text 0x0000000000001fa4 0x5c /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_iobhookentry.o) + 0x0000000000001fa4 __iob_hook_entry + .text 0x0000000000002000 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_nostdio.o) + .text 0x0000000000002000 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_checkdetach.o) + .text 0x0000000000002000 0x160 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor_begin.o) + 0x000000000000204e _init + 0x00000000000020d4 _fini + .text 0x0000000000002160 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_destructor.o) + .text 0x0000000000002160 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_detach.o) + .text 0x0000000000002160 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_disablerequesters.o) + .text 0x0000000000002160 0x50 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) + 0x0000000000002160 _exit + 0x0000000000002182 _Exit + 0x0000000000002196 exit + .text 0x00000000000021b0 0xd0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) + 0x00000000000021b0 __find_memory_node + 0x0000000000002224 __free_memory_node + 0x000000000000222e __free_memory + 0x0000000000002252 free + .text 0x0000000000002280 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_getdefstacksize.o) + .text 0x0000000000002280 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_isresident.o) + .text 0x0000000000002280 0x230 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + 0x0000000000002280 __allocate_memory + 0x00000000000023bc malloc + 0x00000000000023e2 __dtor_stdlib_memory_exit + 0x000000000000245c __ctor_stdlib_memory_init + .text 0x00000000000024b0 0x8c /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + 0x00000000000024b0 __dtor_stdlib_program_name_exit + 0x00000000000024d8 __ctor_stdlib_program_name_init + .text 0x000000000000253c 0xc /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_set_errno.o) + 0x000000000000253c __set_errno + .text 0x0000000000002548 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_shell_escape.o) + .text 0x0000000000002548 0x43c /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) + 0x0000000000002548 __slab_allocate + 0x00000000000027b6 __slab_free + 0x0000000000002888 __slab_init + 0x0000000000002918 __slab_exit + .text 0x0000000000002984 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab_max_size.o) + .text 0x0000000000002984 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab_purge_threshold.o) + .text 0x0000000000002984 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_stdio_window_spec.o) + .text 0x0000000000002984 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_threshold.o) + .text 0x0000000000002984 0xf4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_memset.o) + 0x0000000000002984 memset + .text 0x0000000000002a78 0x20 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_strcat.o) + 0x0000000000002a78 strcat + .text 0x0000000000002a98 0x14 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_strcpy.o) + 0x0000000000002a98 strcpy + .text 0x0000000000002aac 0x40 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) + 0x0000000000002aac __dtor___chdir_exit + .text 0x0000000000002aec 0x8 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(errno_data.o) + 0x0000000000002aec __errno + .text 0x0000000000002af4 0x64 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(fcntl_close.o) + 0x0000000000002af4 close + .text 0x0000000000002b58 0x3c /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_checkabort.o) + 0x0000000000002b58 __check_abort + .text 0x0000000000002b94 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_mask.o) + .text 0x0000000000002b94 0xc0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) + 0x0000000000002b94 raise + .text 0x0000000000002c54 0x104 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fclose.o) + 0x0000000000002c54 fclose + .text 0x0000000000002d58 0x450 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) + 0x0000000000002d58 __fd_hook_entry + .text 0x00000000000031a8 0x60 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_get_file_descriptor.o) + 0x00000000000031ec __get_file_descriptor + 0x00000000000031fa __get_file_descriptor_dont_resolve + .text 0x0000000000003208 0x114 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growfdtable.o) + 0x0000000000003208 __grow_fd_table + .text 0x000000000000331c 0x114 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growiobtable.o) + 0x000000000000331c __grow_iob_table + .text 0x0000000000003430 0x3c /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_initializefd.o) + 0x0000000000003430 __initialize_fd + .text 0x000000000000346c 0x4c /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_initializeiob.o) + 0x000000000000346c __initialize_iob + .text 0x00000000000034b8 0x34 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_parent_of_fh.o) + 0x00000000000034b8 __safe_parent_of_file_handle + .text 0x00000000000034ec 0x74 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_remove_fd_alias.o) + 0x00000000000034ec __remove_fd_alias + .text 0x0000000000003560 0x188 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_translateioerror.o) + 0x0000000000003560 __translate_io_error_to_errno + 0x0000000000003596 __translate_access_io_error_to_errno + .text 0x00000000000036e8 0x28 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_abort.o) + 0x00000000000036e8 abort + .text 0x0000000000003710 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_alloca_cleanup.o) + .text 0x0000000000003710 0xe8 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_atexit.o) + 0x0000000000003710 atexit + 0x00000000000037ac __exit_trap_trigger + .text 0x00000000000037f8 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor.o) + .text 0x00000000000037f8 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_default_pool_size.o) + .text 0x00000000000037f8 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_default_puddle_size.o) + .text 0x00000000000037f8 0x80 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_termination_message.o) + 0x0000000000003816 __print_termination_message + .text 0x0000000000003878 0x40 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_examine_fh.o) + 0x0000000000003878 __safe_examine_file_handle + .text 0x00000000000038b8 0x11c /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputc.o) + 0x00000000000038b8 __fputc_check + 0x000000000000391a __fputc + 0x0000000000003990 fputc + .text 0x00000000000039d4 0xf4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputs.o) + 0x00000000000039d4 fputs + .text 0x0000000000003ac8 0xa8 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_dropiobreadbuffer.o) + 0x0000000000003ac8 __drop_iob_read_buffer + .text 0x0000000000003b70 0x44 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush.o) + 0x0000000000003b70 __flush + .text 0x0000000000003bb4 0x14 /opt/amiga/m68k-amigaos/clib2/lib/libamiga.a(amiga_newlist.o) + 0x0000000000003bb4 NewList + .text 0x0000000000003bc8 0x5b0 /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_udivdi3.o) + 0x0000000000003bc8 __udivdi3 + .text 0x0000000000004178 0x540 /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_umoddi3.o) + 0x0000000000004178 __umoddi3 + .text 0x00000000000046b8 0x100 /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_clz.o) + 0x00000000000046b8 __clz_tab + .text 0x00000000000047b8 0x10 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_mulsi3.o) + 0x00000000000047b8 __mulsi3 + 0x00000000000047c8 ___datadata_relocs = . + 0x00000000000047c8 __etext = . + 0x00000000000047c8 ___text_size = SIZEOF (.text) + 0x00000000000047c8 . = ALIGN (0x0) + +.data 0x00000000000047c8 0xd8 + 0x00000000000047c8 __sdata = . + CONSTRUCTORS + 0x00000000000047c8 . = ALIGN (0x4) + 0x00000000000047c8 ___EXIT_LIST__ = . + 0x00000000000047c8 0x4 xLONG 0xa + 0x00000000000047cc 0x4 RELOC RELOC32 .text+0x88 + 0x00000000000047d0 0x4 xLONG 0x7 *ABS*+0x7 + 0x00000000000047d4 0x4 RELOC RELOC32 .text+0x0 + 0x00000000000047d8 0x4 xLONG 0x6 *ABS*+0x6 + 0x00000000000047dc 0x4 RELOC RELOC32 .text+0x162 + 0x00000000000047e0 0x4 xLONG 0x9 *ABS*+0x9 + 0x00000000000047e4 0x4 RELOC RELOC32 .text+0x0 + 0x00000000000047e8 0x4 xLONG 0x9 *ABS*+0x9 + 0x00000000000047ec 0x4 RELOC RELOC32 .text+0x0 + 0x00000000000047f0 0x4 xLONG 0x2 *ABS*+0x2 + 0x00000000000047f4 0x4 xLONG 0x0 + 0x00000000000047f8 . = ALIGN (0x4) + 0x00000000000047f8 ___INIT_LIST__ = . + 0x00000000000047f8 0x4 xLONG 0xa + 0x00000000000047fc 0x4 RELOC RELOC32 .text+0x26 + 0x0000000000004800 0x4 xLONG 0x3 *ABS*+0x3 + 0x0000000000004804 0x4 RELOC RELOC32 .text+0x8e + 0x0000000000004808 0x4 xLONG 0x7 *ABS*+0x7 + 0x000000000000480c 0x4 RELOC RELOC32 .text+0x9c + 0x0000000000004810 0x4 xLONG 0x6 *ABS*+0x6 + 0x0000000000004814 0x4 RELOC RELOC32 .text+0x1dc + 0x0000000000004818 0x4 xLONG 0x9 *ABS*+0x9 + 0x000000000000481c 0x4 RELOC RELOC32 .text+0x28 + 0x0000000000004820 0x4 xLONG 0x9 *ABS*+0x9 + 0x0000000000004824 0x4 xLONG 0x0 + *(.data) + .data 0x0000000000004828 0x8 logger.o + 0x000000000000482c vers + .data 0x0000000000004830 0x4 string.o + .data 0x0000000000004834 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_priority.o) + 0x0000000000004834 __priority + .data 0x0000000000004838 0x30 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_showerror.o) + .data 0x0000000000004868 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + .data 0x0000000000004868 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_data.o) + 0x0000000000004868 __check_abort_enabled + .data 0x000000000000486c 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + .data 0x000000000000486c 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + 0x000000000000486c __cache_line_size + .data 0x0000000000004870 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) + 0x0000000000004870 __exit_value + .data 0x0000000000004874 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + .data 0x0000000000004874 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + .data 0x0000000000004874 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_shell_escape.o) + 0x0000000000004874 __shell_escape_character + .data 0x0000000000004878 0x0 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) + .data 0x0000000000004878 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(errno_data.o) + 0x0000000000004878 _impure_ptr + .data 0x000000000000487c 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_mask.o) + 0x000000000000487c __break_signal_mask + .data 0x0000000000004880 0x18 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) + 0x0000000000004880 __signal_handler_table + .data 0x0000000000004898 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_default_pool_size.o) + 0x0000000000004898 __default_pool_size + .data 0x000000000000489c 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_default_puddle_size.o) + 0x000000000000489c __default_puddle_size + 0x000000000000c7c6 ___a4_init = 0x7ffe + 0x00000000000048a0 __edata = . + 0x00000000000000d8 ___data_size = SIZEOF (.data) + +.bss 0x00000000000048a0 0x40c + 0x00000000000048a0 __bss_start = . + *(.bss) + .bss 0x00000000000048a0 0x4 logger.o + .bss 0x00000000000048a4 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_dosbase.o) + 0x00000000000048a4 DOSBase + .bss 0x00000000000048a8 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) + 0x00000000000048a8 __stack_overflow + .bss 0x00000000000048ac 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_osliberror.o) + 0x00000000000048ac __minimum_os_lib_error + .bss 0x00000000000048b0 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_oslibversion.o) + 0x00000000000048b0 __minimum_os_lib_version + .bss 0x00000000000048b4 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_process_name.o) + 0x00000000000048b4 __process_name + .bss 0x00000000000048b8 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_stacksize.o) + 0x00000000000048b8 __stack_size + .bss 0x00000000000048bc 0x8 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + 0x00000000000048bc __argv + 0x00000000000048c0 __argc + .bss 0x00000000000048c4 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_sysbase.o) + 0x00000000000048c4 SysBase + .bss 0x00000000000048c8 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_utilitybase.o) + 0x00000000000048c8 __UtilityBase + .bss 0x00000000000048cc 0x10 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + 0x00000000000048cc __iob + 0x00000000000048d0 __num_iob + 0x00000000000048d4 __fd + 0x00000000000048d8 __num_fd + .bss 0x00000000000048dc 0x1c /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + 0x00000000000048dc __WBenchMsg + .bss 0x00000000000048f8 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_nostdio.o) + 0x00000000000048f8 __no_standard_io + .bss 0x00000000000048fc 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_checkdetach.o) + 0x00000000000048fc __check_detach + .bss 0x0000000000004900 0x8 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor_begin.o) + .bss 0x0000000000004908 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_destructor.o) + 0x0000000000004908 __DTOR_LIST__ + .bss 0x000000000000490c 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_detach.o) + 0x000000000000490c __detach + .bss 0x0000000000004910 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_disablerequesters.o) + 0x0000000000004910 __disable_dos_requesters + .bss 0x0000000000004914 0xa4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) + 0x0000000000004914 __exit_jmp_buf + 0x00000000000049b4 __exit_blocked + .bss 0x00000000000049b8 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_getdefstacksize.o) + 0x00000000000049b8 __get_default_stack_size + .bss 0x00000000000049bc 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_isresident.o) + 0x00000000000049bc __is_resident + .bss 0x00000000000049c0 0x20 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + 0x00000000000049c0 __maximum_memory_allocated + 0x00000000000049c4 __current_memory_allocated + 0x00000000000049c8 __maximum_num_memory_chunks_allocated + 0x00000000000049cc __current_num_memory_chunks_allocated + 0x00000000000049d0 __memory_pool + 0x00000000000049d4 __memory_list + .bss 0x00000000000049e0 0x8 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + 0x00000000000049e0 __program_name + .bss 0x00000000000049e8 0xf4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) + 0x00000000000049e8 __slab_data + .bss 0x0000000000004adc 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab_max_size.o) + 0x0000000000004adc __slab_max_size + .bss 0x0000000000004ae0 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab_purge_threshold.o) + 0x0000000000004ae0 __slab_purge_threshold + .bss 0x0000000000004ae4 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_stdio_window_spec.o) + 0x0000000000004ae4 __stdio_window_specification + .bss 0x0000000000004ae8 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_threshold.o) + 0x0000000000004ae8 __free_memory_threshold + .bss 0x0000000000004aec 0x8 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) + 0x0000000000004aec __original_current_directory + 0x0000000000004af0 __current_directory_changed + 0x0000000000004af2 __unlock_current_directory + .bss 0x0000000000004af4 0x10 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(errno_data.o) + 0x0000000000004af4 errno + .bss 0x0000000000004b04 0x8 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) + 0x0000000000004b04 __signals_blocked + .bss 0x0000000000004b0c 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_alloca_cleanup.o) + 0x0000000000004b0c __alloca_cleanup + .bss 0x0000000000004b10 0x194 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_atexit.o) + .bss 0x0000000000004ca4 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor.o) + 0x0000000000004ca4 __CTOR_LIST__ + .bss 0x0000000000004ca8 0x4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_termination_message.o) + *(COMMON) + 0x0000000000004cac __end = . + 0x000000000000040c ___bss_size = SIZEOF (.bss) + +.data_chip + *(.data_chip) + +.bss_chip + *(.bss_chip) +OUTPUT(TimeLogger amiga) + +.stab 0x0000000000000000 0xf0 + .stab 0x0000000000000000 0x18 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + .stab 0x0000000000000018 0x30 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + .stab 0x0000000000000048 0x30 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + .stab 0x0000000000000078 0x30 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + .stab 0x00000000000000a8 0x30 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + .stab 0x00000000000000d8 0x18 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) + +.stabstr 0x0000000000000000 0x140 + .stabstr 0x0000000000000000 0x20 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + .stabstr 0x0000000000000020 0x40 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + .stabstr 0x0000000000000060 0x40 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + .stabstr 0x00000000000000a0 0x40 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + .stabstr 0x00000000000000e0 0x40 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + .stabstr 0x0000000000000120 0x20 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) + +Cross Reference Table + +Symbol File +AppendText string.o +DOSBase /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_dosbase.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_examine_fh.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_parent_of_fh.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fclose.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) + string.o + logger.o +EndsWith string.o +LVOStackSwap /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_swapstack.o) +LongLongToStr string.o +LongToStr string.o +NewList /opt/amiga/m68k-amigaos/clib2/lib/libamiga.a(amiga_newlist.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_atexit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +SNPrintf string.o + logger.o +StartsWith string.o +StrChr string.o +StrCopy string.o +StrLen string.o +StrRChr string.o +StrToLongLong string.o +SysBase /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_sysbase.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_atexit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_checkabort.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_swapstack.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_showerror.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_set_process_window.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) + string.o + logger.o +TrimRight string.o + logger.o +TryParseLong string.o +TryParseLongLong string.o +VSNPrintf string.o +_Exit /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) +__CTOR_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor_begin.o) +__DTOR_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_destructor.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor_begin.o) +__EXIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor_begin.o) +__INIT_LIST__ /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor_begin.o) +__UtilityBase /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_utilitybase.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_mulsi3.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_udivsi4.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__WBenchMsg /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_showerror.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__alloca_cleanup /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_alloca_cleanup.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) +__allocate_memory /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__argc /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__argv /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__break_signal_mask /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_mask.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_checkabort.o) +__cache_line_size /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +__check_abort /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_checkabort.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_dropiobreadbuffer.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputs.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fclose.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(fcntl_close.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flushiobwritebuffer.o) +__check_abort_enabled /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_data.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_dropiobreadbuffer.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputs.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_abort.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fclose.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_checkabort.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(fcntl_close.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flushiobwritebuffer.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__check_detach /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_checkdetach.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__close_all_files /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) +__clz_tab /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_clz.o) + /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_umoddi3.o) + /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_udivdi3.o) +__ctor_arg_init /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) +__ctor_stdio_file_init /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +__ctor_stdio_init /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) +__ctor_stdlib_memory_init /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__ctor_stdlib_program_name_init /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) +__current_directory_changed /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +__current_memory_allocated /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) +__current_num_memory_chunks_allocated /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) +__default_pool_size /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_default_pool_size.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__default_puddle_size /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_default_puddle_size.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__detach /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_detach.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__disable_dos_requesters /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_disablerequesters.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__drop_iob_read_buffer /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_dropiobreadbuffer.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputc.o) +__dtor___chdir_exit /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) +__dtor_stdio_exit /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) +__dtor_stdlib_memory_exit /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__dtor_stdlib_program_name_exit /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) +__dtor_workbench_exit /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +__errno /opt/amiga/m68k-amigaos/clib2/lib/libc.a(errno_data.o) +__exit_blocked /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) +__exit_jmp_buf /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__exit_trap_trigger /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_atexit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) +__exit_value /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__fd /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growfdtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_get_file_descriptor.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +__fd_hook_entry /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +__find_memory_node /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) +__flush /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputs.o) +__flush_all_files /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush_all_files.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__flush_iob_write_buffer /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flushiobwritebuffer.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputs.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fclose.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush_all_files.o) +__fputc /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputs.o) +__fputc_check /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputs.o) +__free_memory /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) +__free_memory_node /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__free_memory_threshold /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_threshold.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__get_a4 /opt/amiga/m68k-amigaos/clib2/lib/ncrt0.o +__get_default_stack_size /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_getdefstacksize.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__get_file_descriptor /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_get_file_descriptor.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_iobhookentry.o) +__get_file_descriptor_dont_resolve /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_get_file_descriptor.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(fcntl_close.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_iobhookentry.o) +__grow_fd_table /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growfdtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) +__grow_iob_table /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growiobtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) +__initialize_fd /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_initializefd.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +__initialize_iob /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_initializeiob.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +__iob /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_termination_message.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growiobtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush_all_files.o) +__iob_hook_entry /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_iobhookentry.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +__is_resident /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_isresident.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__maximum_memory_allocated /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__maximum_num_memory_chunks_allocated /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__memory_list /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__memory_pool /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) +__minimum_os_lib_error /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_osliberror.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__minimum_os_lib_version /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_oslibversion.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__mulsi3 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_mulsi3.o) + /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_umoddi3.o) + /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_udivdi3.o) +__no_standard_io /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_nostdio.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_termination_message.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_showerror.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__num_fd /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growfdtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_get_file_descriptor.o) +__num_iob /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_termination_message.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growiobtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flush_all_files.o) +__original_current_directory /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +__print_termination_message /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_termination_message.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_abort.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) +__priority /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_priority.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__process_name /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_process_name.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__program_name /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) +__remove_fd_alias /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_remove_fd_alias.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) +__restore_a4 /opt/amiga/m68k-amigaos/clib2/lib/ncrt0.o +__safe_examine_file_handle /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_examine_fh.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) +__safe_parent_of_file_handle /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_parent_of_fh.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) +__set_a4 /opt/amiga/m68k-amigaos/clib2/lib/ncrt0.o +__set_errno /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_set_errno.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_dropiobreadbuffer.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_atexit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growiobtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growfdtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fclose.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(fcntl_close.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_flushiobwritebuffer.o) +__set_process_window /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_set_process_window.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__shell_escape_character /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_shell_escape.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) +__show_error /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_showerror.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__signal_handler_table /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) +__signals_blocked /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) +__slab_allocate /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__slab_data /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) +__slab_exit /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__slab_free /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) +__slab_init /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__slab_max_size /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab_max_size.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) +__slab_purge_threshold /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab_purge_threshold.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) +__stack_overflow /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__stack_size /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_stacksize.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__stdio_window_specification /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_stdio_window_spec.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +__swap_stack_and_call /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_swapstack.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +__translate_access_io_error_to_errno /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_translateioerror.o) +__translate_io_error_to_errno /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_translateioerror.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) +__udivdi3 /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_udivdi3.o) + string.o +__udivsi3 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_udivsi3.o) + /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_umoddi3.o) + /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_udivdi3.o) + string.o +__udivsi4 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_udivsi4.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_umodsi3.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_udivsi3.o) +__umoddi3 /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_umoddi3.o) + string.o +__umodsi3 /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_umodsi3.o) + /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_umoddi3.o) + /opt/amiga/lib/gcc/m68k-amigaos/6.5.0b/libgcc.a(_udivdi3.o) + string.o +__unlock_current_directory /opt/amiga/m68k-amigaos/clib2/lib/libc.a(unistd_chdir_exit.o) +_exit /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_abort.o) +_fini /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor_begin.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +_impure_ptr /opt/amiga/m68k-amigaos/clib2/lib/libc.a(errno_data.o) +_init /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_constructor_begin.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +_main /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) + /opt/amiga/m68k-amigaos/clib2/lib/ncrt0.o +abort /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_abort.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) +atexit /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_atexit.o) +close /opt/amiga/m68k-amigaos/clib2/lib/libc.a(fcntl_close.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) +errno /opt/amiga/m68k-amigaos/clib2/lib/libc.a(errno_data.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_set_errno.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +exit /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_program_name.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +fclose /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fclose.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_init_exit.o) +fputc /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_termination_message.o) +fputs /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fputs.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_termination_message.o) +free /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_free.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growiobtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growfdtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fclose.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +geta4 /opt/amiga/m68k-amigaos/clib2/lib/ncrt0.o +longjmp /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_setjmp.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_exit.o) +main logger.o + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +malloc /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_malloc.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_atexit.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growiobtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growfdtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) +memmove /opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_memmove.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) +memset /opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_memset.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_initializeiob.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_initializefd.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growiobtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_growfdtable.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fdhookentry.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_fclose.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_slab.o) +raise /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_raise.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_abort.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(signal_checkabort.o) +setjmp /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_setjmp.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_main.o) +strcat /opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_strcat.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +strcpy /opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_strcpy.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) +strlen /opt/amiga/m68k-amigaos/clib2/lib/libc.a(string_strlen.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdio_file_init.o) + /opt/amiga/m68k-amigaos/clib2/lib/libc.a(stdlib_arg.o) +vers logger.o diff --git a/dist/tz b/dist/tz new file mode 100644 index 0000000..f916f35 --- /dev/null +++ b/dist/tz @@ -0,0 +1 @@ +SetEnv TZ CET-1CEST,M3.5.0/2,M10.5.0/3 diff --git a/fd/screennotify_lib.fd b/fd/screennotify_lib.fd new file mode 100644 index 0000000..e736aba --- /dev/null +++ b/fd/screennotify_lib.fd @@ -0,0 +1,17 @@ +##base _ScreenNotifyBase +##bias 30 +* +* fd/screennotify_lib.fd +* +* Function definitions for screennotify.library +* +* $VER: screennotify_lib.fd 1.0 (26.03.95) +* +##public +AddCloseScreenClient(screen,port,pri)(a0,a1,d0) +RemCloseScreenClient(handle)(a0) +AddPubScreenClient(port,pri)(a0,d0) +RemPubScreenClient(handle)(a0) +AddWorkbenchClient(port,pri)(a0,d0) +RemWorkbenchClient(handle)(a0) +##end diff --git a/fd/screennotify_lib.sfd b/fd/screennotify_lib.sfd new file mode 100644 index 0000000..6971a72 --- /dev/null +++ b/fd/screennotify_lib.sfd @@ -0,0 +1,24 @@ +* This SFD file was automatically generated by fd2sfd from +* fd/screennotify_lib.fd and +* include/clib/screennotify_protos.h. +==base _ScreenNotifyBase +==basetype struct Library * +==libname screennotify.library +==include +==include +* +* fd/screennotify_lib.fd +* +* Function definitions for screennotify.library +* +* $VER: screennotify_lib.fd 1.0 (26.03.95) +* +==bias 30 +==public +APTR AddCloseScreenClient(struct Screen * screen, struct MsgPort * port, BYTE pri) (a0,a1,d0) +BOOL RemCloseScreenClient(APTR handle) (a0) +APTR AddPubScreenClient(struct MsgPort * port, BYTE pri) (a0,d0) +BOOL RemPubScreenClient(APTR handle) (a0) +APTR AddWorkbenchClient(struct MsgPort * port, BYTE pri) (a0,d0) +BOOL RemWorkbenchClient(APTR handle) (a0) +==end diff --git a/fd/screennotify_protos.h b/fd/screennotify_protos.h new file mode 100644 index 0000000..aa4788c --- /dev/null +++ b/fd/screennotify_protos.h @@ -0,0 +1,24 @@ +#ifndef CLIB_SCREENNOTIFY_H +#define CLIB_SCREENNOTIFY_H + +/* + * clib/screennotify_protos.h + * + * ANSI C prototypes for screennotify.library functions + * + * $VER: screennotify_protos.h 1.0 (26.03.95) + * + */ + +#ifndef EXEC_TYPES_H +#include +#endif + +APTR AddCloseScreenClient(struct Screen *, struct MsgPort *, BYTE); +APTR AddPubScreenClient(struct MsgPort *, BYTE); +APTR AddWorkbenchClient(struct MsgPort *, BYTE); +BOOL RemCloseScreenClient(APTR); +BOOL RemPubScreenClient(APTR); +BOOL RemWorkbenchClient(APTR); + +#endif diff --git a/global.c b/global.c new file mode 100644 index 0000000..e7db161 --- /dev/null +++ b/global.c @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 2017-2020 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 "global.h" +#include "locale.h" +#include "log.h" +#include "mem.h" + +struct AppLocale *AppLocale; +struct PosixTimezone *Timezone; +struct PosixTransitionTime *NextTransition; + +volatile struct AppPorts Ports = { NULL, NULL, NULL, NULL }; diff --git a/global.h b/global.h new file mode 100644 index 0000000..cb808f2 --- /dev/null +++ b/global.h @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2017-2020 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. + * + */ + +#ifndef GLOBAL_H_INCLUDED +#define GLOBAL_H_INCLUDED + +#include +#include "locale.h" + +struct AppPorts +{ + struct MsgPort *BrokerPort; + struct MsgPort *SyncerPort; + struct MsgPort *WindowPort; + struct MsgPort *MemoryPort; +}; + +extern struct AppLocale *AppLocale; +extern struct PosixTimezone *Timezone; +extern struct PosixTransitionTime *NextTransition; +extern volatile struct AppPorts Ports; +extern struct Library *BattClockBase; + +#endif diff --git a/include/clib/screennotify.h b/include/clib/screennotify.h new file mode 100644 index 0000000..f901bda --- /dev/null +++ b/include/clib/screennotify.h @@ -0,0 +1,47 @@ +/* Automatically generated header (sfdc 1.11)! Do not edit! */ + +#ifndef CLIB_SCREENNOTIFY_PROTOS_H +#define CLIB_SCREENNOTIFY_PROTOS_H + +/* +** $VER: screennotify_protos.h +** +** C prototypes. For use with 32 bit integers only. +** +** Copyright (c) 2001 Amiga, Inc. +** All Rights Reserved +*/ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* This SFD file was automatically generated by fd2sfd from */ +/* fd/screennotify_lib.fd and */ +/* include/clib/screennotify_protos.h. */ +/* + fd/screennotify_lib.fd +*/ +/* + Function definitions for screennotify.library +*/ +/* + $VER: screennotify_lib.fd 1.0 (26.03.95) +*/ + +APTR AddCloseScreenClient(struct Screen * screen, struct MsgPort * port, BYTE pri); +BOOL RemCloseScreenClient(APTR handle); +APTR AddPubScreenClient(struct MsgPort * port, BYTE pri); +BOOL RemPubScreenClient(APTR handle); +APTR AddWorkbenchClient(struct MsgPort * port, BYTE pri); +BOOL RemWorkbenchClient(APTR handle); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* CLIB_SCREENNOTIFY_PROTOS_H */ diff --git a/include/inline/screennotify.h b/include/inline/screennotify.h new file mode 100644 index 0000000..f302047 --- /dev/null +++ b/include/inline/screennotify.h @@ -0,0 +1,47 @@ +/* Automatically generated header (sfdc 1.11)! Do not edit! */ + +#ifndef _INLINE_SCREENNOTIFY_H +#define _INLINE_SCREENNOTIFY_H + +#ifndef _SFDC_VARARG_DEFINED +#define _SFDC_VARARG_DEFINED +#ifdef __HAVE_IPTR_ATTR__ +typedef APTR _sfdc_vararg __attribute__((iptr)); +#else +typedef ULONG _sfdc_vararg; +#endif /* __HAVE_IPTR_ATTR__ */ +#endif /* _SFDC_VARARG_DEFINED */ + +#ifndef __INLINE_MACROS_H +#include +#endif /* !__INLINE_MACROS_H */ + +#ifndef SCREENNOTIFY_BASE_NAME +#define SCREENNOTIFY_BASE_NAME ScreenNotifyBase +#endif /* !SCREENNOTIFY_BASE_NAME */ + +#define AddCloseScreenClient(___screen, ___port, ___pri) \ + LP3(0x1e, APTR, AddCloseScreenClient , struct Screen *, ___screen, a0, struct MsgPort *, ___port, a1, BYTE, ___pri, d0,\ + , SCREENNOTIFY_BASE_NAME) + +#define RemCloseScreenClient(___handle) \ + LP1(0x24, BOOL, RemCloseScreenClient , APTR, ___handle, a0,\ + , SCREENNOTIFY_BASE_NAME) + +#define AddPubScreenClient(___port, ___pri) \ + LP2(0x2a, APTR, AddPubScreenClient , struct MsgPort *, ___port, a0, BYTE, ___pri, d0,\ + , SCREENNOTIFY_BASE_NAME) + +#define RemPubScreenClient(___handle) \ + LP1(0x30, BOOL, RemPubScreenClient , APTR, ___handle, a0,\ + , SCREENNOTIFY_BASE_NAME) + +#define AddWorkbenchClient(___port, ___pri) \ + LP2(0x36, APTR, AddWorkbenchClient , struct MsgPort *, ___port, a0, BYTE, ___pri, d0,\ + , SCREENNOTIFY_BASE_NAME) + +#define RemWorkbenchClient(___handle) \ + LP1(0x3c, BOOL, RemWorkbenchClient , APTR, ___handle, a0,\ + , SCREENNOTIFY_BASE_NAME) + +#endif /* !_INLINE_SCREENNOTIFY_H */ diff --git a/include/libraries/screennotify.h b/include/libraries/screennotify.h new file mode 100644 index 0000000..2f132c5 --- /dev/null +++ b/include/libraries/screennotify.h @@ -0,0 +1,41 @@ +#ifndef LIBRARIES_SCREENNOTIFY_H +#define LIBRARIES_SCREENNOTIFY_H + +/* + * libraries/screennotify_protos.h + * + * Include file for screennotify.library + * + * $VER: screennotify.h 1.0 (26.03.95) + * + */ + +#ifndef EXEC_PORTS_H +#include +#endif + +/* Name and version */ +#define SCREENNOTIFY_NAME "screennotify.library" +#define SCREENNOTIFY_VERSION 1 + +/* Message sent to clients */ +struct ScreenNotifyMessage { + struct Message snm_Message; + ULONG snm_Type; /* READ ONLY!! */ + APTR snm_Value; /* READ ONLY!! */ +}; + +/* Values for snm_Type */ +#define SCREENNOTIFY_TYPE_CLOSESCREEN 0 /* CloseScreen() called, snm_Value contains */ + /* pointer to Screen structure */ +#define SCREENNOTIFY_TYPE_PUBLICSCREEN 1 /* PubScreenStatus() called to make screen */ + /* public, snm_Value contains pointer to */ + /* PubScreenNode structure */ +#define SCREENNOTIFY_TYPE_PRIVATESCREEN 2 /* PubScreenStatus() called to make screen */ + /* private, snm_Value contains pointer to */ + /* PubScreenNode structure */ +#define SCREENNOTIFY_TYPE_WORKBENCH 3 /* snm_Value == FALSE (0): CloseWorkBench() */ + /* called, please close windows on WB */ + /* snm_Value == TRUE (1): OpenWorkBench() */ + /* called, windows can be opened again */ +#endif diff --git a/include/proto/screennotify.h b/include/proto/screennotify.h new file mode 100644 index 0000000..2f1bf31 --- /dev/null +++ b/include/proto/screennotify.h @@ -0,0 +1,34 @@ +/* Automatically generated header (sfdc 1.11)! Do not edit! */ + +#ifndef PROTO_SCREENNOTIFY_H +#define PROTO_SCREENNOTIFY_H + +#include + +#ifndef _NO_INLINE +# if defined(__GNUC__) +# ifdef __AROS__ +# include +# else +# include +# endif +# else +# include +# endif +#endif /* _NO_INLINE */ + +#ifdef __amigaos4__ +# include +# ifndef __NOGLOBALIFACE__ + extern struct ScreenNotifyIFace *IScreenNotify; +# endif /* __NOGLOBALIFACE__*/ +#endif /* !__amigaos4__ */ +#ifndef __NOLIBBASE__ + extern struct Library * +# ifdef __CONSTLIBBASEDECL__ + __CONSTLIBBASEDECL__ +# endif /* __CONSTLIBBASEDECL__ */ + ScreenNotifyBase; +#endif /* !__NOLIBBASE__ */ + +#endif /* !PROTO_SCREENNOTIFY_H */ diff --git a/library.c b/library.c index 1a902c0..f7b2a04 100644 --- a/library.c +++ b/library.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,108 +25,124 @@ */ #include "config.h" -#include "time.h" +#include "global.h" +#include "timer.h" #include "ptz.h" #include "mem.h" -/* Library identifiers */ -static const char *dosName = "dos.library"; -static const char *aslName = "asl.library"; -static const char *gfxName = "graphics.library"; -static const char *iconName = "icon.library"; -static const char *commoditiesName = "commodities.library"; -static const char *localeName = "locale.library"; -static const char *utilityName = "utility.library"; -static const char *gadgetName = "gadtools.library"; -static const char *intuitionName = "intuition.library"; -static const char *mathName = "mathieeedoubbas.library"; +#include +#include +#include +#include +#include +#include +#include +#include -#if !defined(LIB_HOST) -/* Use fake bases */ -#define DOSBase __FX_DOSBase -#define LocaleBase __FX_LocaleBase -#define UtilityBase __FX_UtilityBase -#define IntuitionBase __FX_IntuitionBase -#define CxBase __FX_CxBase -#define GfxBase __FX_GfxBase -#define AslBase __FX_AslBase -#define IconBase __FX_IconBase -#define GadToolsBase __FX_GadToolsBase -#define __MathIeeeDoubBasBase __FX__MathIeeeDoubBasBase -#define __UtilityBase __FX__UtilityBase +#include "libraries/screennotify.h" + +#include "logmod.h" +#define MODULENAME "Library" + +/* Library and resource identifiers */ +#ifndef DOSNAME +#define DOSNAME "dos.library" +#endif +#ifndef UTILITYNAME +#define UTILITYNAME "utility.library" +#endif +#ifndef COMMODITIESNAME +#define COMMODITIESNAME "commodities.library" +#endif +#ifndef INTUITIONNAME +#define INTUITIONNAME "intuition.library" +#endif +#ifndef GADTOOLSNAME +#define GADTOOLSNAME "gadtools.library" +#endif +#ifndef ICONNAME +#define ICONNAME "icon.library" +#endif +#ifndef GRAPHICSNAME +#define GRAPHICSNAME "graphics.library" +#endif +#ifndef LOCALENAME +#define LOCALENAME "locale.library" +#endif +#ifndef BATTCLOCKNAME +#define BATTCLOCKNAME "battclock.resource" +#endif +#ifndef TIMERNAME +#define TIMERNAME "timer.device" +#endif +#ifndef LIBREV +#define LIBREV 38L #endif -/* Library addresses */ -//struct ExecBase *SysBase = (struct ExecBase *)4L; -struct DosLibrary *DOSBase = NULL; -struct LocaleBase *LocaleBase = NULL; +#ifndef CURRENTLOCALE +#define CURRENTLOCALE "Current Locale Info" +#endif +#ifndef NORTCCLOCK +#define NORTCCLOCK "No RTC found" +#endif + +struct DosLibrary *DOSBase2 = NULL; struct UtilityBase *UtilityBase = NULL; -struct IntuitionBase *IntuitionBase = NULL; struct Library *CxBase = NULL; -struct Library *GfxBase = NULL; -struct Library *AslBase = NULL; -struct Library *IconBase = NULL; +struct IntuitionBase *IntuitionBase = NULL; struct Library *GadToolsBase = NULL; -struct Library *__MathIeeeDoubBasBase = NULL; -struct UtilityBase *__UtilityBase = NULL; - -#define DOSLIB_NAME ((STRPTR)dosName) -#define DOSLIB_REV 36L -#define ASLLIB_NAME ((STRPTR)aslName) -#define ASLLIB_REV 37L -#define GFXLIB_NAME ((STRPTR)gfxName) -#define GFXLIB_REV 37L -#define ICONLIB_NAME ((STRPTR)iconName) -#define ICONLIB_REV 36L -#define COMMODLIB_NAME ((STRPTR)commoditiesName) -#define COMMODLIB_REV 37L -#define INTUITIONLIB_NAME ((STRPTR)intuitionName) -#define INTUITIONLIB_REV 37L -#define LOCALELIB_NAME ((STRPTR)localeName) -#define LOCALELIB_REV 37L -#define UTILLIB_NAME ((STRPTR)utilityName) -#define UTILLIB_REV 37L -#define GADGETLIB_NAME ((STRPTR)gadgetName) -#define GADGETLIB_REV 37L -#define MATHLIB_NAME ((STRPTR)mathName) -#define MATHLIB_REV 34L - -// RTC Clock -static const char *batteryClockName = "battclock.resource"; -#define BATTCLOCK_NAME ((STRPTR)batteryClockName) +struct Library *IconBase = NULL; +struct GfxBase *GfxBase = NULL; +struct LocaleBase *LocaleBase = NULL; +struct Library *ScreenNotifyBase = NULL; struct Library *BattClockBase = NULL; +struct Device *TimerDevice = NULL; -static struct Device *TimerDevice = NULL; -static const char *currentLocale = "Current Locale"; - -static void OpenLibrarySuccess(STRPTR name) +static void OpenLibrarySuccess(char *name, char *ident) { - LogTrace("Opened %s", name); + if (ident == NULL) + { + LogDebug("Opened %s", name); + } + else + { + LogDebug("Opened %s", ident); + } } -static void OpenLibraryError(STRPTR name, long version) +static void OpenLibraryError(char *name, long version) { - LogError("Cannot open %s %ld.0", name, version); + char message[64]; + SNPrintf(message, 63, "Cannot open %s %ld.0", name, version); + Printf((STRPTR)message); + LogError(message); } -static void ClosingLibrary(STRPTR name) +static void ClosingLibrary(char *name, char *ident) { - LogTrace("Closing %s", name); + if (ident == NULL) + { + LogDebug("Closing %s", name); + } + else + { + LogDebug("Closing %s", ident); + } } -static void OpenResourceSuccess(const char *name) +static void OpenResourceSuccess(char *name) { - LogTrace("Opened %s", name); + LogDebug("Opened %s", name); } -static void OpenResourceError(const char *name) +static void OpenResourceError(char *name) { LogError("Cannot open %s", name); } -static void ClosingResource(const char *name) +static void ClosingResource(char *name) { - LogTrace("Closing %s", name); + LogDebug("Closing %s", name); } int OpenLibraries(void) @@ -134,123 +150,76 @@ int OpenLibraries(void) LogInfo("Starting up"); // DOS Library - if (!(DOSBase = (struct DosLibrary *)OpenLibrary((STRPTR)DOSLIB_NAME, DOSLIB_REV))) + if (!(DOSBase2 = (struct DosLibrary *)OpenLibrary((STRPTR)DOSNAME, LIBREV))) { - OpenLibraryError(DOSLIB_NAME, DOSLIB_REV); + OpenLibraryError(DOSNAME, LIBREV); return LIB_ERROR; } - -#ifdef AOS3 - // Library does not always provide IdString - OpenResourceSuccess(DOSLIB_NAME); -#else - OpenLibrarySuccess(((struct Library *)DOSBase)->lib_IdString); -#endif - - // Math Library - if (!(__MathIeeeDoubBasBase = OpenLibrary((STRPTR)MATHLIB_NAME, MATHLIB_REV))) - { - OpenLibraryError(MATHLIB_NAME, MATHLIB_REV); - return LIB_ERROR; - } - -#ifdef AOS3 - // Library does not always provide IdString - OpenResourceSuccess(MATHLIB_NAME); -#else - OpenLibrarySuccess(((struct Library *)__MathIeeeDoubBasBase)->lib_IdString); -#endif - - // Commodities Library - if (!(CxBase = OpenLibrary((STRPTR)COMMODLIB_NAME, COMMODLIB_REV))) - { - OpenLibraryError(COMMODLIB_NAME, COMMODLIB_REV); - return LIB_ERROR; - } - - OpenLibrarySuccess(CxBase->lib_IdString); - - // Intuition Library - if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary((STRPTR)INTUITIONLIB_NAME, INTUITIONLIB_REV))) - { - OpenLibraryError(INTUITIONLIB_NAME, INTUITIONLIB_REV); - return LIB_ERROR; - } - - OpenLibrarySuccess(((struct Library *)IntuitionBase)->lib_IdString); - - // Icon Library - if (!(IconBase = OpenLibrary((STRPTR)ICONLIB_NAME, ICONLIB_REV))) - { - OpenLibraryError(ICONLIB_NAME, ICONLIB_REV); - return LIB_ERROR; - } - - OpenLibrarySuccess(IconBase->lib_IdString); - - // Icon Library - if (!(AslBase = OpenLibrary((STRPTR)ASLLIB_NAME, ASLLIB_REV))) - { - OpenLibraryError(ASLLIB_NAME, ASLLIB_REV); - return LIB_ERROR; - } - - OpenLibrarySuccess(AslBase->lib_IdString); - - // Locale Library - if (!(LocaleBase = (struct LocaleBase *)OpenLibrary((STRPTR)LOCALELIB_NAME, LOCALELIB_REV))) - { - OpenLibraryError(LOCALELIB_NAME, LOCALELIB_REV); - return LIB_ERROR; - } - - OpenLibrarySuccess(((struct Library *)LocaleBase)->lib_IdString); + OpenLibrarySuccess(DOSNAME, DOSBase2->dl_lib.lib_IdString); // Utility Library - if (!(UtilityBase = (struct UtilityBase *)OpenLibrary((STRPTR)UTILLIB_NAME, UTILLIB_REV))) + if (!(UtilityBase = (struct UtilityBase *)OpenLibrary((STRPTR)UTILITYNAME, LIBREV))) { - OpenLibraryError(UTILLIB_NAME, UTILLIB_REV); + OpenLibraryError(UTILITYNAME, LIBREV); return LIB_ERROR; } + OpenLibrarySuccess(UTILITYNAME, UtilityBase->ub_LibNode.lib_IdString); - __UtilityBase = UtilityBase; - OpenLibrarySuccess(((struct Library *)UtilityBase)->lib_IdString); + // Commodity Library + if (!(CxBase = OpenLibrary((STRPTR)COMMODITIESNAME, LIBREV))) + { + OpenLibraryError(COMMODITIESNAME, LIBREV); + return LIB_ERROR; + } + OpenLibrarySuccess(COMMODITIESNAME, CxBase->lib_IdString); + + // Intuition Library + if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary((STRPTR)INTUITIONNAME, LIBREV))) + { + OpenLibraryError(INTUITIONNAME, LIBREV); + return LIB_ERROR; + } + OpenLibrarySuccess(INTUITIONNAME, IntuitionBase->LibNode.lib_IdString); // Gadget Library - if (!(GadToolsBase = OpenLibrary((STRPTR)GADGETLIB_NAME, GADGETLIB_REV))) + if (!(GadToolsBase = OpenLibrary((STRPTR)GADTOOLSNAME, LIBREV))) { - OpenLibraryError(GADGETLIB_NAME, GADGETLIB_REV); + OpenLibraryError(GADTOOLSNAME, LIBREV); return LIB_ERROR; } + OpenLibrarySuccess(GADTOOLSNAME, GadToolsBase->lib_IdString); - OpenLibrarySuccess(GadToolsBase->lib_IdString); + // Icon Library + if (!(IconBase = OpenLibrary((STRPTR)ICONNAME, LIBREV))) + { + OpenLibraryError(ICONNAME, LIBREV); + return LIB_ERROR; + } + OpenLibrarySuccess(ICONNAME, IconBase->lib_IdString); // Graphics Library - if (!(GfxBase = OpenLibrary((STRPTR)GFXLIB_NAME, GFXLIB_REV))) + if (!(GfxBase = (struct GfxBase *)OpenLibrary((STRPTR)GRAPHICSNAME, LIBREV))) { - OpenLibraryError(GFXLIB_NAME, GFXLIB_REV); + OpenLibraryError(GRAPHICSNAME, LIBREV); return LIB_ERROR; } + OpenLibrarySuccess(GRAPHICSNAME, GfxBase->LibNode.lib_IdString); - OpenLibrarySuccess(GfxBase->lib_IdString); + // Locale Library + if (!(LocaleBase = (struct LocaleBase *)OpenLibrary((STRPTR)LOCALENAME, LIBREV))) + { + OpenLibraryError(LOCALENAME, LIBREV); + return LIB_ERROR; + } + OpenLibrarySuccess(LOCALENAME, LocaleBase->lb_LibNode.lib_IdString); // Locale - if (!(Globals->Locale = OpenLocale(NULL))) + if (!(AppLocale = OpenAppLocale(NULL))) { - OpenResourceError(currentLocale); + OpenResourceError(CURRENTLOCALE); return LIB_ERROR; } - - OpenResourceSuccess((const char *)Globals->Locale->loc_LocaleName); - - // RTC Clock - if (!(BattClockBase = OpenResource((STRPTR)BATTCLOCK_NAME))) - { - OpenResourceError((const char *)BATTCLOCK_NAME); - return LIB_ERROR; - } - - OpenResourceSuccess((const char *)BATTCLOCK_NAME); + OpenResourceSuccess((char *)AppLocale->AmigaLocale->loc_LocaleName); // Timer Device if (!(TimerDevice = OpenTimerBase())) @@ -258,9 +227,25 @@ int OpenLibraries(void) OpenResourceError(TIMERNAME); return LIB_ERROR; } - OpenResourceSuccess(TIMERNAME); + // RTC Clock + BattClockBase = OpenResource((STRPTR)BATTCLOCKNAME); + if (BattClockBase != NULL) + { + OpenResourceSuccess(BATTCLOCKNAME); + } + else + { + LogDebug(NORTCCLOCK); + } + + ScreenNotifyBase = OpenLibrary((STRPTR)SCREENNOTIFY_NAME, SCREENNOTIFY_VERSION); + if (ScreenNotifyBase != NULL) + { + LogDebug("Found %s", SCREENNOTIFY_NAME); + } + SeedRandom(); return LIB_OK; @@ -268,102 +253,103 @@ int OpenLibraries(void) void CloseLibraries(void) { - LogInfo("Shutting down"); - - CleanupTimezone(); - if (TimerDevice != NULL) { - ClosingResource((const char *)TIMERNAME); + ClosingResource(TIMERNAME); CloseTimerBase(); TimerDevice = NULL; } - if (Globals->Locale != NULL) + if (AppLocale != NULL) { - ClosingResource((const char *)Globals->Locale->loc_LocaleName); - CloseLocale(Globals->Locale); - Globals->Locale = NULL; + ClosingResource((char *)AppLocale->AmigaLocale->loc_LocaleName); + CloseAppLocale(AppLocale); + AppLocale = NULL; } - if (CxBase != NULL) + if (ScreenNotifyBase != NULL) { - ClosingLibrary(CxBase->lib_IdString); - CloseLibrary(CxBase); - CxBase = NULL; - } - - if (AslBase != NULL) - { - ClosingLibrary(AslBase->lib_IdString); - CloseLibrary(AslBase); - AslBase = NULL; - } - - if (IconBase != NULL) - { - ClosingLibrary(IconBase->lib_IdString); - CloseLibrary(IconBase); - IconBase = NULL; + ClosingLibrary(SCREENNOTIFY_NAME, ScreenNotifyBase->lib_IdString); + CloseLibrary(ScreenNotifyBase); + ScreenNotifyBase = NULL; } if (LocaleBase != NULL) { - ClosingLibrary(((struct Library *)LocaleBase)->lib_IdString); + ClosingLibrary(LOCALENAME, LocaleBase->lb_LibNode.lib_IdString); CloseLibrary((struct Library *)LocaleBase); LocaleBase = NULL; } - if (UtilityBase != NULL) + if (GfxBase != NULL) { - ClosingLibrary(((struct Library *)UtilityBase)->lib_IdString); - CloseLibrary((struct Library *)UtilityBase); - UtilityBase = NULL; - __UtilityBase = NULL; + ClosingLibrary(GRAPHICSNAME, GfxBase->LibNode.lib_IdString); + CloseLibrary((struct Library *)GfxBase); + GfxBase = NULL; + } + + if (IconBase != NULL) + { + ClosingLibrary(ICONNAME, IconBase->lib_IdString); + CloseLibrary(IconBase); + IconBase = NULL; } if (GadToolsBase != NULL) { - ClosingLibrary(GadToolsBase->lib_IdString); + ClosingLibrary(GADTOOLSNAME, GadToolsBase->lib_IdString); CloseLibrary(GadToolsBase); GadToolsBase = NULL; } - if (GfxBase != NULL) - { - ClosingLibrary(GfxBase->lib_IdString); - CloseLibrary(GfxBase); - GfxBase = NULL; - } - if (IntuitionBase != NULL) { - ClosingLibrary(((struct Library *)IntuitionBase)->lib_IdString); + ClosingLibrary(INTUITIONNAME, IntuitionBase->LibNode.lib_IdString); CloseLibrary((struct Library *)IntuitionBase); IntuitionBase = NULL; } - if (DOSBase != NULL) + if (CxBase != NULL) { -#ifdef AOS3 - // Library does not always provide IdString - ClosingResource(DOSLIB_NAME); -#else - ClosingLibrary(((struct Library *)DOSBase)->lib_IdString); -#endif - CloseLibrary((struct Library *)DOSBase); - DOSBase = NULL; + ClosingLibrary(COMMODITIESNAME, CxBase->lib_IdString); + CloseLibrary(CxBase); + CxBase = NULL; } - if (__MathIeeeDoubBasBase != NULL) + if (UtilityBase != NULL) { -#ifdef AOS3 - // Library does not always provide IdString - ClosingResource(MATHLIB_NAME); -#else - ClosingLibrary(((struct Library *)__MathIeeeDoubBasBase)->lib_IdString); -#endif - CloseLibrary((struct Library *)__MathIeeeDoubBasBase); - __MathIeeeDoubBasBase = NULL; + ClosingLibrary(UTILITYNAME, UtilityBase->ub_LibNode.lib_IdString); + CloseLibrary((struct Library *)UtilityBase); + UtilityBase = NULL; + } + + if (DOSBase2 != NULL) + { + ClosingLibrary(DOSNAME, DOSBase2->dl_lib.lib_IdString); + CloseLibrary((struct Library *)DOSBase2); + DOSBase2 = NULL; + } + + LogWarn("Shutdown complete"); +} + +void ReopenLocale(void) +{ + struct AppLocale *locale, *temp; + + if (!(locale = OpenAppLocale(NULL))) + { + OpenResourceError(CURRENTLOCALE); + } + else + { + temp = AppLocale; + AppLocale = locale; + + if (temp != NULL) + { + ClosingResource((char *)temp->AmigaLocale->loc_LocaleName); + CloseAppLocale(temp); + } } } diff --git a/locale.c b/locale.c new file mode 100644 index 0000000..7e81044 --- /dev/null +++ b/locale.c @@ -0,0 +1,184 @@ +/*- + * Copyright (c) 2020 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 "locale.h" +#include "global.h" +#include "string.h" +#include "ptz.h" +#include "mem.h" + +#include +#include +#include + +struct AppLocale *OpenAppLocale(struct Locale *locale) +{ + int i, j; + struct AppLocale *l = AllocStructSafe(struct AppLocale); + struct Locale *loc = locale; + + if (!loc) + { + loc = OpenLocale(NULL); + } + + if (loc == NULL) + { + return NULL; + } + + l->X_fmt = (const char *)loc->loc_TimeFormat; + l->x_fmt = (const char *)loc->loc_ShortDateFormat; + l->c_fmt = (const char *)loc->loc_DateTimeFormat; + l->am = (const char *)GetLocaleStr(loc, AM_STR); + l->pm = (const char *)GetLocaleStr(loc, PM_STR); + l->date_fmt = "%a %b %e %H:%M:%S %Z %Y"; + + j = 0; + for (i = 1; i < 8; i++) + { + l->weekday[j++] = (const char *)GetLocaleStr(loc, i); + } + + j = 0; + for (i = 8; i < 15; i++) + { + l->wday[j++] = (const char *)GetLocaleStr(loc, i); + } + + j = 0; + for (i = 15; i < 27; i++) + { + l->month[j++] = (const char *)GetLocaleStr(loc, i); + } + + j = 0; + for (i = 27; i < 39; i++) + { + l->mon[j++] = (const char *)GetLocaleStr(loc, i); + } + + l->AmigaLocale = loc; + return l; +} + +void CloseAppLocale(struct AppLocale *lc) +{ + if (lc->AmigaLocale) + { + CloseLocale(lc->AmigaLocale); + } + + FreeMemSafe(lc); +} + +void GetTimezoneText(struct AppLocale *loc, char *text, long parens) +{ + if (loc == NULL || text == NULL) + { + return; + } + + if (Timezone == NULL) + { + long hoursOffset = (loc->AmigaLocale->loc_GMTOffset / -60L); + long minutsOffset = (loc->AmigaLocale->loc_GMTOffset % -60L); + SNPrintf(text, TIMEZONE_TEXT_LEN, "UTC%s%02ld:%02ld", + (loc->AmigaLocale->loc_GMTOffset < 0L) ? "+" : "", + hoursOffset, + minutsOffset); + } + else if (parens == ZONE_IN_PARENS) + { + SNPrintf(text, TIMEZONE_TEXT_LEN, "UTC%s%02ld:%02ld (%s)", + PosixTimezoneSignChar(&Timezone->current), + Timezone->current.offset.hours, + Timezone->current.offset.minutes, + Timezone->current.abbreviation); + } + else if (parens == OFFSET_IN_PARENS) + { + SNPrintf(text, TIMEZONE_TEXT_LEN, "%s (UTC%s%02ld:%02ld)", + Timezone->current.abbreviation, + PosixTimezoneSignChar(&Timezone->current), + Timezone->current.offset.hours, + Timezone->current.offset.minutes); + } +} + +char* GetTimeText(struct AppLocale *loc, ULONG time) +{ + char *out; + struct ClockData cd; + struct timeval tv; + ULONG t = time; + + out = AllocStringSafe(128); + if (loc == NULL) + { + return out; + } + + if (t == LOCAL_TIME_NOW) + { + GetSysTime(&tv); + t = (ULONG)tv.tv_secs; + } + + Amiga2Date(t, &cd); + + if (Timezone == NULL) + { + long hoursOffset = (loc->AmigaLocale->loc_GMTOffset / -60L); + long minutsOffset = (loc->AmigaLocale->loc_GMTOffset % -60L); + + SNPrintf(out, 128, "%s %02ld %s %02ld:%02ld:%02ld%s%02ld%02ld %ld", + loc->weekday[cd.wday], + (long)cd.mday, + loc->month[cd.month - 1], + (long)cd.hour, + (long)cd.min, + (long)cd.sec, + (loc->AmigaLocale->loc_GMTOffset < 0L) ? "+" : "", + hoursOffset, + minutsOffset, + (long)cd.year); + } + else + { + SNPrintf(out, 128, "%s %02ld %s %02ld:%02ld:%02ld %s %ld", + loc->weekday[cd.wday], + (long)cd.mday, + loc->month[cd.month - 1], + (long)cd.hour, + (long)cd.min, + (long)cd.sec, + Timezone->current.abbreviation, + (long)cd.year); + } + + return out; +} diff --git a/locale.h b/locale.h new file mode 100644 index 0000000..950bcd3 --- /dev/null +++ b/locale.h @@ -0,0 +1,59 @@ +/*- + * Copyright (c) 2020 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. + * + */ + +#ifndef LOCALE_H_INCLUDED +#define LOCALE_H_INCLUDED + +#include + +struct AppLocale +{ + const char *mon[12]; + const char *month[12]; + const char *wday[7]; + const char *weekday[7]; + const char *X_fmt; + const char *x_fmt; + const char *c_fmt; + const char *t_fmt_ampm; + const char *am; + const char *pm; + const char *am_pm[2]; + const char *date_fmt; + struct Locale *AmigaLocale; +}; + +#define LOCAL_TIME_NOW 0 +#define ZONE_IN_PARENS 0 +#define OFFSET_IN_PARENS 1 +#define TIMEZONE_TEXT_LEN 32 + +struct AppLocale *OpenAppLocale(struct Locale *); +void CloseAppLocale(struct AppLocale *); +char* GetTimeText(struct AppLocale *, ULONG); +void GetTimezoneText(struct AppLocale *, char *, long); + +#endif diff --git a/log.c b/log.c index 77feafc..f10422e 100644 --- a/log.c +++ b/log.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,224 +24,96 @@ * */ -#include "config.h" -#include "log.h" -#include "mem.h" +#include +#include +#include #include -#define MAXLOGLINESIZE 255 +#include "log.h" +#include "string.h" +#include "logger.h" -enum LogSeverity +static void VLogLine(enum LogSeverity level, const char *module, const char *format, va_list ap) { - ErrorMessage = 5, - WarningMessage = 10, - InfoMessage = 20, - TraceMessage = 30 -}; + struct MsgPort *port, *replyPort; + struct LogMessage message; -struct LogEntry -{ - enum LogSeverity level; - char *line; - struct LogEntry *next; -}; - -static bool logDisabled = false; -static bool bufferLog = false; -static BPTR logFile = NULL; -static struct LogEntry *firstEntry = NULL; -static struct LogEntry *lastEntry = NULL; - -void OpenLogFile(void) -{ - BPTR lock; - bool deleteFirst = false; - - if (Globals->Settings->LogFile == NULL) + replyPort = CreateMsgPort(); + if (replyPort == NULL) { return; } - lock = Lock((STRPTR)Globals->Settings->LogFile, ACCESS_READ); - if (lock) + message.Msg.mn_Node.ln_Type = NT_MESSAGE; + message.Msg.mn_Length = sizeof(struct LogMessage); + message.Msg.mn_ReplyPort = replyPort; + message.Type = LogMessageText; + message.Severity = level; + StrCopy(message.Module, module); + VSNPrintf(message.Text, MAXLOGLINESIZE - 1, format, ap); + VSNPrintf(message.Text, MAXLOGLINESIZE - 1, format, ap); + + Forbid(); + port = FindPort((CONST_STRPTR)LOGGER_PORT_NAME); + if (port != NULL) { - deleteFirst = true; - UnLock(lock); + PutMsg(port, (struct Message *)&message); + } + Permit(); + + if (port != NULL) + { + WaitPort(replyPort); + GetMsg(replyPort); } - if (deleteFirst) - { - bool success; - LogWarning("Deleting existing log file %s", Globals->Settings->LogFile); - success = DeleteFile((STRPTR)Globals->Settings->LogFile); - if (!success) - { - char message[MAXDOSERRORLEN]; - long error = IoErr(); - Fault(error, (STRPTR) "Cannot delete existing log file %s", (STRPTR)message, MAXDOSERRORLEN); - LogWarning(message); - logFile = NULL; - return; - } - } - - LogInfo("Opening log file %s", Globals->Settings->LogFile); - logFile = Open((STRPTR)Globals->Settings->LogFile, MODE_READWRITE); - if (!logFile) - { - char message[MAXDOSERRORLEN]; - long error = IoErr(); - Fault(error, (STRPTR) "Cannot open log file %s", (STRPTR)message, MAXDOSERRORLEN); - LogWarning(message); - logFile = NULL; - return; - } + DeleteMsgPort(replyPort); } -void CloseLogFile(void) -{ - if (logFile == NULL) - { - return; - } - - LogTrace("Closing log file %s", Globals->Settings->LogFile); - Close(logFile); - logFile = NULL; - logDisabled = true; -} - -bool TraceLogging(void) -{ - return Globals->Settings->Verbose * 10 >= (int)TraceMessage - ? true - : false; -} - -static void VLogLine(enum LogSeverity level, const char *format, va_list ap) -{ - struct LogEntry *entry; - char line[MAXLOGLINESIZE + 1]; - - if (logDisabled) - { - return; - } - - if (bufferLog || Globals->Settings->Verbose * 10 >= (int)level) - { - int len; - VSNPrintf(line, MAXLOGLINESIZE - 1, format, ap); - len = TrimRight(line); - if (len != 0) - { - line[len++] = '\n'; - line[len] = '\0'; - } - } - - if (bufferLog) - { - entry = (struct LogEntry *)AllocMemSafe(sizeof(struct LogEntry)); - entry->level = level; - entry->line = StrDupSafe(line); - entry->next = NULL; - - if (firstEntry == NULL) - { - firstEntry = entry; - lastEntry = entry; - } - else - { - lastEntry->next = entry; - lastEntry = entry; - } - return; - } - - if (Globals->Settings->Verbose * 10 >= (int)level) - { - if (logFile != NULL) - { - FPuts(logFile, (STRPTR)line); - Flush(logFile); - } - else - { - Printf((STRPTR)line); - } - } -} - -void LogTrace(const char *format, ...) +void LogMemTrace(const char *module, const char *format, ...) { va_list args; va_start(args, format); - VLogLine(TraceMessage, format, args); + VLogLine(MemTraceMessage, module, format, args); va_end(args); } -void LogInfo(const char *format, ...) +void LogDebug(const char *module, const char *format, ...) { va_list args; va_start(args, format); - VLogLine(InfoMessage, format, args); + VLogLine(DebugMessage, module, format, args); va_end(args); } -void LogWarning(const char *format, ...) +void LogTrace(const char *module, const char *format, ...) { va_list args; va_start(args, format); - VLogLine(WarningMessage, format, args); + VLogLine(TraceMessage, module, format, args); va_end(args); } -void LogError(const char *format, ...) +void LogInfo(const char *module, const char *format, ...) { va_list args; va_start(args, format); - VLogLine(ErrorMessage, format, args); + VLogLine(InfoMessage, module, format, args); va_end(args); } -void SetLogBuffer(void) +void LogWarn(const char *module, const char *format, ...) { - bufferLog = true; + va_list args; + va_start(args, format); + VLogLine(WarningMessage, module, format, args); + va_end(args); } -void FlushLogBuffer(void) +void LogError(const char *module, const char *format, ...) { - struct LogEntry *current; - - if (!bufferLog) - return; - - current = firstEntry; - while (current != NULL) - { - struct LogEntry *last; - if (Globals->Settings->Verbose * 10 >= (int)current->level) - { - if (logFile != NULL) - { - FPuts(logFile, (STRPTR)current->line); - } - else - { - Printf((STRPTR)current->line); - } - } - - last = current; - current = current->next; - - FreeMemSafe(last->line, __FUNCTION__); - FreeMemSafe(last, __FUNCTION__); - } - - bufferLog = false; - firstEntry = NULL; - lastEntry = NULL; + va_list args; + va_start(args, format); + VLogLine(ErrorMessage, module, format, args); + va_end(args); } diff --git a/log.h b/log.h index 5eb1a4f..d7ec432 100644 --- a/log.h +++ b/log.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,7 +21,7 @@ * 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. - * + * */ #ifndef LOG_H_INCLUDED @@ -29,14 +29,11 @@ #include "compiler.h" -void LogTrace(const char *format, ...); -void LogInfo(const char *format, ...); -void LogWarning(const char *format, ...); -void LogError(const char *format, ...); -bool TraceLogging(void); -void OpenLogFile(void); -void CloseLogFile(void); -void SetLogBuffer(void); -void FlushLogBuffer(void); +void LogMemTrace(const char *module, const char *format, ...); +void LogDebug(const char *module, const char *format, ...); +void LogTrace(const char *module, const char *format, ...); +void LogInfo(const char *module, const char *format, ...); +void LogWarn(const char *module, const char *format, ...); +void LogError(const char *module, const char *format, ...); #endif diff --git a/logger.c b/logger.c new file mode 100644 index 0000000..9900e0d --- /dev/null +++ b/logger.c @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 2017-2020 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 +#include +#include + +#include +#include +#include +#include + +#include "logger.h" +#include "string.h" + +static void MsgLoop(void); + +static int VerboseLevel = 10; +static struct MsgPort *LoggerPort; + +const char *vers = "\0$VER: TimeLogger 1.10 (20.03.2020)"; + +/* +struct LogMessage +{ + struct timeval time; + enum LogSeverity severity; + const char *module; + const char *message; + struct LogMessage *next; +}; +*/ + +int main(int argc, char **argv) +{ + Printf((STRPTR) "Starting TimeLogger.\n"); + + LoggerPort = CreateMsgPort(); + if (LoggerPort == NULL) + { + Printf((STRPTR) "Could not message port\n"); + return 10; + } + + LoggerPort->mp_Node.ln_Name = LOGGER_PORT_NAME; + LoggerPort->mp_Node.ln_Pri = 0; + + AddPort(LoggerPort); + MsgLoop(); + RemPort(LoggerPort); + + DeleteMsgPort(LoggerPort); + return 0; +} + +static const char *SeverityText(enum LogSeverity level) +{ + switch (level) + { + case ErrorMessage: + return "[Error]"; + case WarningMessage: + return "[Warn ]"; + case InfoMessage: + return "[Info ]"; + case DebugMessage: + return "[Debug]"; + case TraceMessage: + case MemTraceMessage: + return "[Trace]"; + default: + return "[Trace]"; + } +} + +static void LogMessage(enum LogSeverity level, const char *module, const char *log) +{ + if (VerboseLevel * 10 >= (int)level) + { + char line[MAXLOGLINESIZE + 32]; + const char *severity = SeverityText(level); + SNPrintf(line, MAXLOGLINESIZE + 32, "%s[%s] %s", severity, module, log); + TrimRight(line); + + // TODO: Option to log using a file + + if (Output() != (BPTR)0) + { + Printf((STRPTR)line); + Printf((STRPTR) "\n"); + } + } +} + +static void MsgLoop(void) +{ + bool loop = true; + ULONG loggerSigMask = (1 << LoggerPort->mp_SigBit); + ULONG sigMask = loggerSigMask | SIGBREAKF_CTRL_C; + + Printf((STRPTR) "Waiting for log messages ...\n"); + + do + { + ULONG sigrcvd = Wait(sigMask); + if (sigrcvd & sigMask) + { + struct LogMessage *msg; + while ((msg = (struct LogMessage *)GetMsg(LoggerPort))) + { + struct LogMessage copy; + CopyMem(msg, ©, sizeof(struct LogMessage)); + ReplyMsg((struct Message *)msg); + + switch (copy.Type) + { + case LogMessageText: + LogMessage(copy.Severity, copy.Module, copy.Text); + break; + case LogMessageShutdown: + loop = false; + break; + default: + break; + } + } + } + + if (sigrcvd & SIGBREAKF_CTRL_C) + { + Printf((STRPTR) "Shutting down\n"); + loop = false; + } + } while (loop); +} diff --git a/logger.h b/logger.h new file mode 100644 index 0000000..f4464c7 --- /dev/null +++ b/logger.h @@ -0,0 +1,61 @@ +/*- + * Copyright (c) 2017-2020 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. + * + */ + +#ifndef LOGGER_H_INCLUDED +#define LOGGER_H_INCLUDED + +#include + +#define LOGGER_PORT_NAME "TimeLoggerIn" +#define MODULENAMESIZE 20 +#define MAXLOGLINESIZE 255 + +enum LogSeverity +{ + ErrorMessage = 5, + WarningMessage = 10, + InfoMessage = 20, + DebugMessage = 30, + TraceMessage = 40, + MemTraceMessage = 90 +}; + +enum LogMessageType +{ + LogMessageText = 1, + LogMessageShutdown = 2 +}; + +struct LogMessage +{ + struct Message Msg; + enum LogMessageType Type; + enum LogSeverity Severity; + char Module[MODULENAMESIZE]; + char Text[MAXLOGLINESIZE]; +}; + +#endif diff --git a/logmod.h b/logmod.h new file mode 100644 index 0000000..4938519 --- /dev/null +++ b/logmod.h @@ -0,0 +1,36 @@ + +/*- + * Copyright (c) 2017-2020 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. + * + */ + +#ifdef MODULENAME +#undef MODULENAME +#endif + +#define LogDebug(...) LogDebug(MODULENAME, __VA_ARGS__) +#define LogTrace(...) LogTrace(MODULENAME, __VA_ARGS__) +#define LogInfo(...) LogInfo(MODULENAME, __VA_ARGS__) +#define LogWarn(...) LogWarn(MODULENAME, __VA_ARGS__) +#define LogError(...) LogError(MODULENAME, __VA_ARGS__) \ No newline at end of file diff --git a/main.c b/main.c index bf7ec2c..f9d0438 100644 --- a/main.c +++ b/main.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,37 +25,48 @@ */ #include "config.h" -#include "state.h" -#include "time.h" +#include "global.h" +#include "setting.h" +#include "timer.h" +#include "net.h" #include "mem.h" +#include "ptz.h" +#include "tz.h" #include -#include "ptz.h" +#include "logmod.h" +#define MODULENAME "Main" const char *vers = "\0$VER: " APP_ID; static const char *template = KEYWORD_TEMPLATE; -static void LogStartMessage(void); -static void LogLocalTime(void); static void GetCliSettings(void); static void GetWbSettings(struct WBStartup *); +static void ShowLocalTime(void) +{ + char *time = GetTimeText(AppLocale, LOCAL_TIME_NOW); + LogInfo("Local time is %s", time); + FreeMemSafe(time); +} + int main(int argc, char **argv) { - InitState(); - SetLogBuffer(); - LogStartMessage(); - LogLocalTime(); + InitMemSafe(); + InitSettings(); + + LogInfo("%s", APP_TITLE); if (OpenLibraries() != 0) { CloseLibraries(); - DestroyState(); + CleanupSettings(); FreeAllSafe(); return RETURN_ERROR; } + InitTimezone(); LoadSettings(); if (argc != 0) @@ -66,17 +77,14 @@ int main(int argc, char **argv) ApplySettings(); SanitizeSettings(); ShowSettings(); - OpenLogFile(); - FlushLogBuffer(); - InitUtcOffset(); StartBroker(); - LogLocalTime(); + ShowLocalTime(); + CleanupTimezone(); CloseSocketLibrary(); CloseLibraries(); - CloseLogFile(); - DestroyState(); + CleanupSettings(); FreeAllSafe(); return RETURN_OK; @@ -93,7 +101,6 @@ static void GetCliSettings(void) args[i] = 0; settings = CreateSettings(CliSettingType); - settings->Verbose = 1; inArgs = ReadArgs((void *)template, (void *)&args, NULL); if (inArgs) @@ -120,7 +127,7 @@ static void GetWbSettings(struct WBStartup *wbs) BPTR oldDir; int argNo, i; - filename = (STRPTR)AllocMemSafe(MAXFILEPATHLEN); + filename = (STRPTR)AllocStringSafe(MAXFILEPATHLEN); settings = CreateSettings(WbSettingType); for (argNo = 0; argNo < wbs->sm_NumArgs; ++argNo) @@ -146,18 +153,5 @@ static void GetWbSettings(struct WBStartup *wbs) } CacheSettings(settings); - FreeMemSafe(filename, __FUNCTION__); -} - -static void LogStartMessage(void) -{ - LogWarning("%s", APP_TITLE); -} - -static void LogLocalTime(void) -{ - // TODO - 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); + FreeMemSafe(filename); } diff --git a/mem.c b/mem.c index 56504e1..936d841 100644 --- a/mem.c +++ b/mem.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2014-2019 Carsten Sonne Larsen + * Copyright (c) 2014-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,6 +25,7 @@ */ #include +#include #include #include #include @@ -32,8 +33,15 @@ #define ALLOC_MEM(x) AllocVec(x, MEMF_ANY | MEMF_CLEAR) #define FREE_MEM(x) FreeVec(x) +#include "mem.h" #include "compiler.h" #include "log.h" + +#include "logmod.h" +#define MODULENAME "Memory" +#define LogMemTrace(...) LogMemTrace(MODULENAME, __VA_ARGS__) +//#define MEM_TRACE 1 + int StrLen(const char *); #if defined(__x86_64__) || defined(__aarch64__) || \ @@ -42,22 +50,21 @@ int StrLen(const char *); #define P64BIT #endif -#ifdef DEBUG_BUILD -#define MEM_TRACE 1 -#endif - -/** - * @brief Block of allocated memory. +/* + * Block of allocated memory. */ struct MemoryBlock { struct MemoryBlock *next; size_t size; void *address; + char *file; + char *function; + int line; }; -/** - * @brief List of allocated memory. Uses the LIFO principle. +/* + * List of allocated memory. Uses the LIFO principle. */ struct MemoryList { @@ -67,200 +74,13 @@ struct MemoryList long count; }; -/** - * @brief Global list of allocated memory. +/* + * Global list of allocated memory. */ -static struct MemoryList *list = NULL; +volatile static struct MemoryList *list = NULL; -void AllocationError(char *, size_t); -void DeAllocationError(char *, char*, void *); - -/** - * @brief Allocate memory and add it to the global memory list. - */ -void *AllocMemSafe(size_t size) -{ - struct MemoryBlock *newblock; - size_t allocsize; - - Forbid(); - if (list == NULL) - { - list = (struct MemoryList *)ALLOC_MEM(sizeof(struct MemoryList)); - if (!list) - { - AllocationError("list", sizeof(struct MemoryList)); - return 0; - } - - list->first = NULL; - list->peak = 0; - list->size = 0; - list->count = 0; - } - -#ifdef P64BIT - // Align to bytes of 8 - allocsize = (size + 7) & ~0x07; -#else - // Align to bytes of 4 - allocsize = (size + 3) & ~0x03; -#endif - - newblock = (struct MemoryBlock *)ALLOC_MEM(sizeof(struct MemoryBlock)); - if (!newblock) - { - AllocationError("block", sizeof(struct MemoryBlock)); - return 0; - } - - newblock->address = (struct MemoryBlock *)ALLOC_MEM(allocsize); - if (!newblock->address) - { - FREE_MEM(newblock); - AllocationError("memory", allocsize); - return 0; - } - - newblock->size = allocsize; - newblock->next = list->first; - list->first = newblock; - list->size += allocsize; - list->count++; - - if (list->size > list->peak) - { - list->peak = list->size; - } - Permit(); - -#ifdef MEM_TRACE - Printf("Allocated memory block off %ld bytes at 0x%lx\n", - newblock->size, newblock->address); -#endif - - // Memory allocated - return newblock->address; -} - -void RemoveMemSafe(void *block, char *name, bool deallocate) -{ - struct MemoryBlock *current, *previous; - - Forbid(); - if (list == NULL || block == NULL) - { - DeAllocationError("list", name, 0); - return; - } - - if (block == NULL) - { - DeAllocationError("memory", name, 0); - return; - } - - previous = NULL; - current = list->first; - while (current != NULL && current->address != block) - { - previous = current; - current = current->next; - } - - if (current == NULL) - { - DeAllocationError("address not found", name, block); - return; - } - - if (previous == NULL) - { - list->first = current->next; - } - else - { - previous->next = current->next; - } - - list->size -= current->size; - list->count--; - - if (deallocate) - { - FREE_MEM(current->address); - } - - current->address = NULL; - current->next = NULL; - current->size = 0; - FREE_MEM(current); - Permit(); -} - -/** - * @brief Deallocate memory from the global memory list. - */ -void FreeMemSafe(void *block, char *name) -{ - RemoveMemSafe(block, name, true); -} - -void *MemDupSafe(const void *s1, size_t len) -{ - char *dup; - dup = AllocMemSafe(len); - CopyMem((void *)s1, dup, len); - return dup; -} - -char *StrDupSafe(const char *s1) -{ - char *s2; - size_t len = s1 != NULL ? StrLen(s1) : 1; - s2 = AllocMemSafe(++len); - - if (s2 == NULL) - { - return NULL; - } - - CopyMem((void *)s1, s2, --len); - return s2; -} - -/** - * @brief Deallocate all memory in the global memory list. - */ -void FreeAllSafe(void) -{ - struct MemoryBlock *current, *next; - - Forbid(); - if (list == NULL) - { - return; - } - - current = list->first; - while (current != NULL) - { - LogTrace("Released forgotten memory block on %ld bytes at 0x%lx", - (long)current->size, - (unsigned long)current->address); - next = current->next; - FREE_MEM(current->address); - FREE_MEM(current); - current = next; - } - - FREE_MEM(list); - list = NULL; - Permit(); -} - -/** - * @brief Get memory usage in the global memory list. +/* + * Get memory usage in the global memory list. */ void MemUsage(long *blocks, long *size, long *peak) { @@ -280,18 +100,312 @@ void MemUsage(long *blocks, long *size, long *peak) } } -/** - * @brief Log a memory allocation error. +/* + * Log a memory allocation error. */ -void AllocationError(char *descr, size_t size) +static void AllocationError(const char *descr, size_t size, const char *file, const char *function, int line) { - LogTrace("Memory allocation error (%s) with size (%ld)", descr, (long)size); + LogDebug("Memory allocation error (%s) from %s, %s, line %ld, %ld bytes", + descr, function, file, line, (long)size); } -/** - * @brief Log a memory deallocation error. +/* + * Log a memory deallocation error. */ -void DeAllocationError(char *descr, char *name, void *p) +static void DeAllocationError(const char *descr, void *p, const char *file, const char *function, int line) { - LogTrace("Memory deallocation error from %s (%s) at 0x%lx", name, descr, p); + LogDebug("Memory deallocation error (%s) from %s, %s, line %ld at 0x%lx", + descr, function, file, line, p); +} + +static char *StrDupRaw(const char *s1) +{ + char *s2; + size_t len = s1 != NULL ? StrLen(s1) : 1; + s2 = ALLOC_MEM(++len); + + if (s2 == NULL) + { + return NULL; + } + + CopyMem((void *)s1, s2, --len); + return s2; +} + +static void MemZero(void *address, size_t size) +{ + if (address == NULL || size == 0) + { + return; + } + + char *c = (char *)address; + int n = size; + do + { + *c++ = '\0'; + } while (--n); +} + +void InitMemSafe(void) +{ + volatile struct MemoryList *m = (volatile struct MemoryList *)ALLOC_MEM(sizeof(struct MemoryList)); + bool newList = false; + + if (m == NULL) + { + return; + } + + Forbid(); + if (list == NULL) + { + list = m; + ; + list->first = NULL; + list->peak = 0; + list->size = 0; + list->count = 0; + newList = true; + } + Permit(); + + if (newList && !list) + { + AllocationError("list", sizeof(struct MemoryList), __FILE__, __FUNCTION__, __LINE__); + } + + if (!newList) + { + FREE_MEM((void *)m); + } +} + +/* + * Allocate memory and add it to the global memory list. + */ +void *AllocMemTraced(size_t size, const char *file, const char *function, int line, bool trace) +{ + struct MemoryBlock *newblock; +#ifdef P64BIT // Align to bytes of 8 + size_t allocsize = (size + 7) & ~0x07; +#else // Align to bytes of 4 + size_t allocsize = (size + 3) & ~0x03; +#endif + + newblock = (struct MemoryBlock *)ALLOC_MEM(sizeof(struct MemoryBlock)); + if (!newblock) + { + AllocationError("block", sizeof(struct MemoryBlock), file, function, line); + return 0; + } + + newblock->address = (struct MemoryBlock *)ALLOC_MEM(allocsize); + if (!newblock->address) + { + FREE_MEM(newblock); + AllocationError("memory", allocsize, file, function, line); + return 0; + } + + newblock->size = allocsize; + newblock->file = StrDupRaw(file); + newblock->function = StrDupRaw(function); + newblock->line = line; + + Forbid(); + newblock->next = list->first; + list->first = newblock; + list->size += allocsize; + list->count++; + if (list->size > list->peak) + { + list->peak = list->size; + } + Permit(); + +#ifdef MEM_TRACE + if (trace) + { + LogMemTrace("[Memory] Allocated memory block from %s, %s, line %ld, %ld bytes at 0x%lx", + newblock->function, newblock->file, newblock->line, + newblock->size, newblock->address); + } +#endif + + // Memory allocated + return newblock->address; +} + +static void RemoveMemSafe(void *block, const char *file, const char *function, int line, bool deallocate) +{ + struct MemoryBlock *current, *previous; + bool found = true; + + if (list == NULL) + { + DeAllocationError("list", 0, file, function, line); + return; + } + + if (block == NULL) + { + DeAllocationError("block", 0, file, function, line); + return; + } + + Forbid(); + previous = NULL; + current = list->first; + while (current != NULL && current->address != block) + { + previous = current; + current = current->next; + } + + if (current != NULL) + { + if (previous == NULL) + { + list->first = current->next; + } + else + { + previous->next = current->next; + } + + list->size -= current->size; + list->count--; + } + else + { + found = false; + } + Permit(); + + if (found) + { +#ifdef MEM_TRACE + LogMemTrace("[Memory] Deallocated memory block from %s, %s, line %ld, %ld bytes at 0x%lx", + current->function, current->file, current->line, + current->size, current->address); +#endif + + if (deallocate) + { + MemZero(current->address, current->size); + FREE_MEM(current->address); + } + + if (current->file != NULL) + { + MemZero(current->file, StrLen(current->file)); + FREE_MEM(current->file); + } + + if (current->function != NULL) + { + MemZero(current->function, StrLen(current->function)); + FREE_MEM(current->function); + } + + MemZero(current, sizeof(struct MemoryBlock)); + FREE_MEM(current); + } + else + { + DeAllocationError("address not found", block, file, function, line); + } +} + +/* + * Deallocate memory from the global memory list. + */ +void FreeMemTraced(void *block, const char *file, const char *function, int line) +{ + RemoveMemSafe(block, file, function, line, true); +} + +void *MemDupTraced(const void *s1, size_t len, const char *file, const char *function, int line, bool trace) +{ + char *dup; + dup = AllocMemTraced(len, file, function, line, trace); + CopyMem((void *)s1, dup, len); + return dup; +} + +char *StrDupTraced(const char *s1, const char *file, const char *function, int line, bool trace) +{ + char *s2; + size_t len = s1 != NULL ? StrLen(s1) : 1; + s2 = AllocMemTraced(++len, file, function, line, trace); + + if (s2 == NULL) + { + return NULL; + } + + CopyMem((void *)s1, s2, --len); + return s2; +} + +/* + * Deallocate all memory in the global memory list. + */ +void FreeAllSafe(void) +{ + volatile struct MemoryList *m; + struct MemoryBlock *current, *next; + + Forbid(); + m = list; + list = NULL; + Permit(); + + if (m == NULL) + { + return; + } + + current = m->first; + while (current != NULL) + { + if (current->file && current->function) + { + LogDebug("Released forgotten memory block from %s, %s, line %ld, %ld bytes at 0x%lx", + current->function, current->file, current->line, + (long)current->size, current->address); + } + else + { + LogDebug("Released forgotten memory block on %ld bytes at 0x%lx", + (long)current->size, + current->address); + } + + next = current->next; + + MemZero(current->address, current->size); + FREE_MEM(current->address); + + if (current->file != NULL) + { + MemZero(current->file, StrLen(current->file)); + FREE_MEM(current->file); + } + + if (current->function != NULL) + { + MemZero(current->function, StrLen(current->function)); + FREE_MEM(current->function); + } + + MemZero(current->file, sizeof(struct MemoryBlock)); + FREE_MEM(current); + + current = next; + } + + FREE_MEM((void *)m); } diff --git a/mem.h b/mem.h index 5be9ecd..8df72b1 100644 --- a/mem.h +++ b/mem.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2014-2019 Carsten Sonne Larsen + * Copyright (c) 2014-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,12 +28,23 @@ #define MEM_H_INCLUDED #include +#include -void *AllocMemSafe(size_t); -char *StrDupSafe(const char *); -void *MemDupSafe(const void *s1, size_t len); -void FreeMemSafe(void *, char*); +void InitMemSafe(void); void FreeAllSafe(void); void MemUsage(long *, long *, long *); +void *AllocMemTraced(size_t, const char *, const char *, int, bool); +char *StrDupTraced(const char *, const char *, const char *, int, bool); +void *MemDupTraced(const void *s1, size_t len, const char *, const char *, int, bool); +void FreeMemTraced(void *, const char *, const char *, int); + +#define AllocStringSafe(size) (char *)AllocMemTraced(size, __FILE__, __FUNCTION__, __LINE__, true) +#define AllocStructSafe(type) (type *)AllocMemTraced(sizeof(type), __FILE__, __FUNCTION__, __LINE__, true) +#define StrDupSafe(string) StrDupTraced(string, __FILE__, __FUNCTION__, __LINE__, true) +#define MemDupSafe(string, len) MemDupTraced(string, len, __FILE__, __FUNCTION__, __LINE__, true) +#define FreeMemSafe(block) FreeMemTraced(block, __FILE__, __FUNCTION__, __LINE__) +#define AllocStructNoTrace(type) (type *)AllocMemTraced(sizeof(type), __FILE__, __FUNCTION__, __LINE__, false) +#define StrDupNoTrace(string) StrDupTraced(string, __FILE__, __FUNCTION__, __LINE__, false) +#define MemDupNoTrace(string, len) MemDupTraced(string, len, __FILE__, __FUNCTION__, __LINE__, false) #endif diff --git a/message.c b/message.c index 8f70902..4dc467c 100644 --- a/message.c +++ b/message.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,77 +21,100 @@ * 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 "global.h" #include "message.h" #include "mem.h" -static void SendTextMessage(char *text, long type) -{ - Forbid(); - if (!Globals->ShuttingDown) - { - struct AppWindowMessage *message = (struct AppWindowMessage *)AllocMemSafe(sizeof(struct AppWindowMessage)); - message->Msg.mn_Node.ln_Type = NT_MESSAGE; - message->Msg.mn_Length = sizeof(struct AppWindowMessage); - message->Msg.mn_ReplyPort = Globals->Broker->ReplyPort; - message->Type = type; - message->Text = StrDupSafe(text); - PutMsg(Globals->Broker->UserPort, (struct Message *)message); - } - Permit(); -} - -void SendErrorMessage(char *text) -{ - SendTextMessage(text, ATK_LOGERROR); -} - -void SendWarningMessage(char *text) -{ - SendTextMessage(text, ATK_LOGWARN); -} - -void SendInfoMessage(char *text) -{ - SendTextMessage(text, ATK_LOGINFO); -} - -void SendTraceMessage(char *text) -{ - SendTextMessage(text, ATK_LOGTRACE); -} - void SendMessage(long type) { - Forbid(); - if (!Globals->ShuttingDown) - { - struct AppWindowMessage *message = (struct AppWindowMessage *)AllocMemSafe(sizeof(struct AppWindowMessage)); - message->Msg.mn_Node.ln_Type = NT_MESSAGE; - message->Msg.mn_Length = sizeof(struct AppWindowMessage); - message->Msg.mn_ReplyPort = Globals->Broker->ReplyPort; - message->Type = type; - message->Text = NULL; - PutMsg(Globals->Broker->UserPort, (struct Message *)message); - } - Permit(); + SendMessageTo(Ports.BrokerPort, Ports.MemoryPort, type); } void SendMessageTo(struct MsgPort *dest, struct MsgPort *reply, long type) { Forbid(); - if (!Globals->ShuttingDown) + if (dest != NULL && reply != NULL) { - struct AppWindowMessage *message = (struct AppWindowMessage *)AllocMemSafe(sizeof(struct AppWindowMessage)); + struct ApplicationMesage *message = AllocStructSafe(struct ApplicationMesage); message->Msg.mn_Node.ln_Type = NT_MESSAGE; - message->Msg.mn_Length = sizeof(struct AppWindowMessage); + message->Msg.mn_Length = sizeof(struct ApplicationMesage); message->Msg.mn_ReplyPort = reply; - message->Type = type; - message->Text = NULL; + message->MsgType = MSGTYPE_APP; + message->MsgId = type; PutMsg(dest, (struct Message *)message); } Permit(); } + +void SendMessageWait(struct MsgPort *dest, long type) +{ + struct MsgPort *replyPort; + + if (dest == NULL) + { + return; + } + + replyPort = CreateMsgPort(); + if (replyPort) + { + struct Message *msg; + SendMessageTo(dest, replyPort, type); + WaitPort(replyPort); + msg = GetMsg(replyPort); + DeleteMsgPort(replyPort); + FreeMemSafe(msg); + } +} + +void CleanupVolMsgPort(struct MsgPort *volatile *port) +{ + struct MsgPort *msgPort; + bool exist = true; + + Forbid(); + if (*port == NULL) + { + exist = false; + } + else + { + msgPort = *port; + *port = NULL; + } + Permit(); + + if (exist) + { + struct Message *msg; + while ((msg = GetMsg(msgPort))) + { + ReplyMsg(msg); + } + DeleteMsgPort(msgPort); + } +} + +void CleanupMsgPort(struct MsgPort **port) +{ + struct Message *msg; + struct MsgPort *msgPort = *port; + + if (*port == NULL) + { + return; + } + + *port = NULL; + + while ((msg = GetMsg(msgPort))) + { + ReplyMsg(msg); + } + + DeleteMsgPort(msgPort); +} diff --git a/message.h b/message.h index 4044809..9cf460a 100644 --- a/message.h +++ b/message.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,7 +21,7 @@ * 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. - * + * */ #ifndef MESSAGE_H_INCLUDED @@ -29,10 +29,10 @@ #include "config.h" -#define ATK_LOGERROR 1 -#define ATK_LOGWARN 2 -#define ATK_LOGINFO 3 -#define ATK_LOGTRACE 4 +#define MSGTYPE_APP 1 +#define MSGTYPE_TIMEVAL 2 + +#define ATK_LASTSYNC 1 #define ATK_RESTART 10 #define ATK_REFRESH 11 #define ATK_STORE 13 @@ -42,19 +42,27 @@ #define ATK_DISABLE 21 #define ATK_READONLY 22 #define ATK_READWRITE 23 +#define ATK_SHUTDOWN 30 +#define ATK_TZ_CHANGED 40 +#define ATK_TZONE_CHANGED 41 +#define ATK_LOCALE_CHANGED 42 -struct AppWindowMessage +struct ApplicationMesage { struct Message Msg; - long Type; - char *Text; + long MsgType; + long MsgId; +}; + +struct TimeMessage +{ + struct ApplicationMesage AppMsg; + struct timeval TimeVal; }; void SendMessage(long); -void SendErrorMessage(char *); -void SendWarningMessage(char *); -void SendInfoMessage(char *); -void SendTraceMessage(char *); void SendMessageTo(struct MsgPort *, struct MsgPort *, long); - +void SendMessageWait(struct MsgPort *, long); +void CleanupMsgPort(struct MsgPort **); +void CleanupVolMsgPort(struct MsgPort *volatile *); #endif diff --git a/net.c b/net.c index 79078fd..dac6357 100644 --- a/net.c +++ b/net.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,13 +21,17 @@ * 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 "net.h" #include "net_getaddrinfo.h" #include "message.h" +#include "logmod.h" +#define MODULENAME "Network" + int errno; int gai_h_errno; @@ -36,7 +40,7 @@ int h_errno; #endif static const char *bsdSocketName = "bsdsocket.library"; -static const char *openSocketLibraryError = "Cannot open %s %ld.0"; +static const char *openSocketLibraryError = "No TCP/IP Stack running!"; static const char *openSocketResourceError = "Cannot open %s"; struct Library *SocketBase = NULL; @@ -45,8 +49,6 @@ struct Library *SocketBase = NULL; int OpenSocketLibrary(void) { - char message[SETTINGMESSAGELEN]; - if (SocketBase != NULL) { return LIB_OK; @@ -54,19 +56,17 @@ int OpenSocketLibrary(void) if (!(SocketBase = OpenLibrary((STRPTR)BSDLIB_NAME, BSDLIB_REV))) { - SNPrintf(message, SETTINGMESSAGELEN, openSocketLibraryError, BSDLIB_NAME, BSDLIB_REV); - SendErrorMessage(message); + LogError(openSocketLibraryError, BSDLIB_NAME, BSDLIB_REV); return LIB_ERROR; } - SNPrintf(message, SETTINGMESSAGELEN, "Opened %s", (char *)SocketBase->lib_IdString); - SendTraceMessage(message); + LogDebug("Opened %s", (char *)SocketBase->lib_IdString); if (SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (int)&errno, + SBTM_SETVAL(SBTC_LOGTAGPTR), (IPTR)APP_SHORT_NAME, SBTM_SETVAL(SBTC_HERRNOLONGPTR), (int)&h_errno, TAG_DONE)) { - SNPrintf(message, SETTINGMESSAGELEN, openSocketResourceError, BSDLIB_NAME); - SendErrorMessage(message); + LogError(openSocketResourceError, BSDLIB_NAME); CloseLibrary(SocketBase); return LIB_ERROR; } @@ -78,9 +78,7 @@ void CloseSocketLibrary(void) { if (SocketBase != NULL) { - char message[SETTINGMESSAGELEN]; - SNPrintf(message, SETTINGMESSAGELEN, "Closing %s", (char *)SocketBase->lib_IdString); - SendTraceMessage(message); + LogDebug("Closing %s", (char *)SocketBase->lib_IdString); CloseLibrary(SocketBase); SocketBase = NULL; } @@ -150,8 +148,8 @@ const char *GetHostErrorText(void) if (gai_h_errno != 0) { return gai_h_errno == EAI_SYSTEM - ? GetErrorText() - : gai_strerror(gai_h_errno); + ? (const char *)GetErrorText() + : (const char *)gai_strerror(gai_h_errno); } switch (h_errno) diff --git a/net.h b/net.h new file mode 100644 index 0000000..bb37944 --- /dev/null +++ b/net.h @@ -0,0 +1,117 @@ +/*- + * Copyright (c) 2017-2020 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. + * + */ + +#ifndef NET_H_INCLUDED +#define NET_H_INCLUDED + +#ifndef ENOTSOCK +#define ENOTSOCK 38 +#endif +#ifndef EDESTADDRREQ +#define EDESTADDRREQ 39 +#endif +#ifndef EMSGSIZE +#define EMSGSIZE 40 +#endif +#ifndef EPROTOTYPE +#define EPROTOTYPE 41 +#endif +#ifndef ENOPROTOOPT +#define ENOPROTOOPT 42 +#endif +#ifndef EPROTONOSUPPORT +#define EPROTONOSUPPORT 43 +#endif +#ifndef ESOCKTNOSUPPORT +#define ESOCKTNOSUPPORT 44 +#endif +#ifndef EOPNOTSUPP +#define EOPNOTSUPP 45 +#endif +#ifndef EPFNOSUPPORT +#define EPFNOSUPPORT 46 +#endif +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT 47 +#endif +#ifndef EADDRINUSE +#define EADDRINUSE 48 +#endif +#ifndef EADDRNOTAVAIL +#define EADDRNOTAVAIL 49 +#endif +#ifndef ENETDOWN +#define ENETDOWN 50 +#endif +#ifndef ENETUNREACH +#define ENETUNREACH 51 +#endif +#ifndef ENETRESET +#define ENETRESET 52 +#endif +#ifndef ECONNABORTED +#define ECONNABORTED 53 +#endif +#ifndef ECONNRESET +#define ECONNRESET 54 +#endif +#ifndef ENOBUFS +#define ENOBUFS 55 +#endif +#ifndef EISCONN +#define EISCONN 56 +#endif +#ifndef ENOTCONN +#define ENOTCONN 57 +#endif +#ifndef ESHUTDOWN +#define ESHUTDOWN 58 +#endif +#ifndef ETOOMANYREFS +#define ETOOMANYREFS 59 +#endif +#ifndef ETIMEDOUT +#define ETIMEDOUT 60 +#endif +#ifndef ECONNREFUSED +#define ECONNREFUSED 61 +#endif +#ifndef EHOSTDOWN +#define EHOSTDOWN 64 +#endif +#ifndef EHOSTUNREACH +#define EHOSTUNREACH 65 +#endif + +int OpenSocketLibrary(void); +void CloseSocketLibrary(void); +const char *GetErrorText(void); +const char *GetHostErrorText(void); +int GetErrorNo(void); +int GetHostErrorNo(void); +extern struct Library *SocketBase; + +#endif diff --git a/net_getaddrinfo.c b/net_getaddrinfo.c index aa8b13f..8494900 100644 --- a/net_getaddrinfo.c +++ b/net_getaddrinfo.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2001, 02 Motoyuki Kasahara - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -52,6 +52,9 @@ #include "net_getaddrinfo.h" #include "mem.h" +#include "logmod.h" +#define MODULENAME "Network" + #define gettext(string) (string) #define _(string) (string) #define N_(string) (string) @@ -139,11 +142,11 @@ void freeaddrinfo(struct addrinfo *ai) while (ai != NULL) { if (ai->ai_canonname != NULL) - FreeMemSafe(ai->ai_canonname, __FUNCTION__); + FreeMemSafe(ai->ai_canonname); if (ai->ai_addr != NULL) - FreeMemSafe(ai->ai_addr, __FUNCTION__); + FreeMemSafe(ai->ai_addr); next_ai = ai->ai_next; - FreeMemSafe(ai, __FUNCTION__); + FreeMemSafe(ai); ai = next_ai; } } @@ -224,10 +227,6 @@ int getaddrinfo( int saved_h_errno; int result = 0; -#ifdef ENABLE_THREAD - ObtainSemaphore(&getaddrinfoSemaphore); -#endif - saved_h_errno = h_errno; if (nodename == NULL && servname == NULL) @@ -305,12 +304,11 @@ int getaddrinfo( if (hints->ai_flags & AI_CANONNAME && !(hints->ai_flags & AI_NUMERICHOST)) { - hostent = gethostbyaddr((char *)&addr_buf, - sizeof(struct in_addr), AF_INET); + hostent = gethostbyaddr((const char *)&addr_buf, sizeof(struct in_addr), AF_INET); if (hostent != NULL) - canonname = hostent->h_name; + canonname = (const char *)hostent->h_name; else - canonname = nodename; + canonname = (const char *)nodename; } } else @@ -357,7 +355,7 @@ int getaddrinfo( for (ap = addr_list; *ap != NULL; ap++) { - new_res = (struct addrinfo *)AllocMemSafe(sizeof(struct addrinfo)); + new_res = AllocStructSafe(struct addrinfo); if (new_res == NULL) { if (head_res != NULL) @@ -374,11 +372,10 @@ int getaddrinfo( new_res->ai_canonname = NULL; new_res->ai_next = NULL; - new_res->ai_addr = (struct sockaddr *) - AllocMemSafe(sizeof(struct sockaddr_in)); + new_res->ai_addr = (struct sockaddr *)AllocStructSafe(struct sockaddr_in); if (new_res->ai_addr == NULL) { - FreeMemSafe(new_res, __FUNCTION__); + FreeMemSafe(new_res); if (head_res != NULL) freeaddrinfo(head_res); result = EAI_MEMORY; @@ -400,7 +397,7 @@ int getaddrinfo( if (canonname != NULL && head_res != NULL) { - head_res->ai_canonname = (char *)AllocMemSafe(StrLen(canonname) + 1); + head_res->ai_canonname = AllocStringSafe(StrLen(canonname) + 1); if (head_res->ai_canonname != NULL) StrCopy(head_res->ai_canonname, canonname); } @@ -410,155 +407,5 @@ int getaddrinfo( end: h_errno = saved_h_errno; gai_h_errno = result; -#ifdef ENABLE_THREAD - ReleaseSemaphore(&getaddrinfoSemaphore); -#endif return result; } - -#if 0 -/* - * Calcurate length of the string `s', where `s' is set by - * sprintf(s, "%d", n). - */ -static int -itoa_length(int n) -{ - int result = 1; - - if (n < 0) - { - n = -n; - result++; - } - - while (n >= 10) - { - result++; - n /= 10; - } - - return result; -} - -#if defined(__CLIB2__) -LONG getnameinfo( - struct sockaddr *sa, - ULONG salen, - STRPTR node, - ULONG nodelen, - STRPTR serv, - ULONG servlen, - ULONG flags) -#else -int getnameinfo( - const struct sockaddr *sa, - socklen_t salen, - char *node, - socklen_t nodelen, - char *serv, - socklen_t servlen, - int flags) -#endif -{ - const struct sockaddr_in *sa_in = (const struct sockaddr_in *)sa; - struct hostent *hostent; - struct servent *servent; - char *ntoa_address; - int saved_h_errno; - int result = 0; - -#ifdef ENABLE_PTHREAD - pthread_mutex_lock(&gai_mutex); -#endif - - saved_h_errno = h_errno; - - if (sa_in->sin_family != PF_INET) - { - result = EAI_FAMILY; - goto end; - } - else if (node == NULL && serv == NULL) - { - result = EAI_NONAME; - goto end; - } - - if (serv != NULL && servlen > 0) - { - if (flags & NI_NUMERICSERV) - servent = NULL; - else if (flags & NI_DGRAM) - servent = getservbyport(sa_in->sin_port, "udp"); - else - servent = getservbyport(sa_in->sin_port, "tcp"); - - if (servent != NULL) - { - if (servlen <= StrLen(servent->s_name)) - { - result = EAI_OVERFLOW; - goto end; - } - StrCopy(serv, servent->s_name); - } - else - { - if (servlen <= itoa_length(ntohs(sa_in->sin_port))) - { - result = EAI_OVERFLOW; - goto end; - } - LongToStr((long)ntohs(sa_in->sin_port), serv); - } - } - - if (node != NULL && nodelen > 0) - { - if (flags & NI_NUMERICHOST) - hostent = NULL; - else - { - hostent = gethostbyaddr((char *)&sa_in->sin_addr, - sizeof(struct in_addr), AF_INET); - } - if (hostent != NULL) - { - if (nodelen <= StrLen(hostent->h_name)) - { - result = EAI_OVERFLOW; - goto end; - } - StrCopy(node, hostent->h_name); - } - else - { - if (flags & NI_NAMEREQD) - { - result = EAI_NONAME; - goto end; - } -#ifndef __libnix__ - ntoa_address = inet_ntoa(sa_in->sin_addr); -#else - ntoa_address = inet_ntoa((LONG)sa_in->sin_addr.s_addr); -#endif - if (nodelen <= StrLen(ntoa_address)) - { - result = EAI_OVERFLOW; - goto end; - } - StrCopy(node, ntoa_address); - } - } - -end: - h_errno = saved_h_errno; - gai_h_errno = result; -#ifdef ENABLE_PTHREAD - pthread_mutex_unlock(&gai_mutex); -#endif - return result; -} -#endif diff --git a/net_getaddrinfo.h b/net_getaddrinfo.h index b78bc7c..38b3fe7 100644 --- a/net_getaddrinfo.h +++ b/net_getaddrinfo.h @@ -1,6 +1,6 @@ /* * Copyright (c) 2001, 02 Motoyuki Kasahara - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -194,6 +194,19 @@ typedef uint16_t in_port_t; #endif +#if defined(MISSING_ADDRINFO) +struct addrinfo { + int ai_flags; /* input flags */ + int ai_family; /* protocol family for socket */ + int ai_socktype; /* socket type */ + int ai_protocol; /* protocol for socket */ + socklen_t ai_addrlen; /* length of socket-address */ + struct sockaddr *ai_addr; /* socket-address for socket */ + char *ai_canonname; /* canonical name for service location (iff req) */ + struct addrinfo *ai_next; /* pointer to next in list */ +}; +#endif + #if defined(__CLIB2__) STRPTR gai_strerror(LONG); LONG getaddrinfo(STRPTR, STRPTR, struct addrinfo *, struct addrinfo **); diff --git a/net_poll.c b/net_poll.c index a297082..8e4e8a2 100644 --- a/net_poll.c +++ b/net_poll.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,7 +21,7 @@ * 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" @@ -31,6 +31,9 @@ #include #endif +#include "logmod.h" +#define MODULENAME "Network" + int poll(struct pollfd *fds, nfds_t nfds, int timeout) { unsigned int i; diff --git a/notify.c b/notify.c new file mode 100644 index 0000000..c1dea1c --- /dev/null +++ b/notify.c @@ -0,0 +1,142 @@ +/*- + * Copyright (c) 2017-2020 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 +#include + +#include "config.h" +#include "mem.h" + +#include "logmod.h" +#define MODULENAME "Notify" + +struct NotifyRequestNode +{ + long Registered; + struct NotifyRequest *Request; + volatile struct NotifyRequestNode *Next; +}; + +volatile static struct NotifyRequestNode *Last = NULL; + +static void AddRequest(struct NotifyRequest *request) +{ + volatile struct NotifyRequestNode *node; + + node = AllocStructSafe(struct NotifyRequestNode); + if (node == NULL) + { + return; + } + + node->Request = request; + node->Next = NULL; + + // Add to list + Forbid(); + if (Last == NULL) + { + Last = node; + } + else + { + node->Next = Last; + Last = node; + } + Permit(); +} + +void ActivateNotifyPort(struct MsgPort *port) +{ + volatile struct NotifyRequestNode *current; + + if (port == NULL) + { + return; + } + + current = Last; + while (current != NULL) + { + if (current->Registered != DOSTRUE) + { + current->Request->nr_stuff.nr_Msg.nr_Port = port; + current->Registered = StartNotify(current->Request); + + if (current->Registered == DOSTRUE) + { + LogInfo("Watching for changes in %s", current->Request->nr_Name); + } + else + { + LogWarn("Could not get notifications from %s", current->Request->nr_Name); + } + } + current = current->Next; + } +} + +void WatchFile(char *file, long type) +{ + struct NotifyRequest *request; + + request = AllocStructSafe(struct NotifyRequest); + if (request == NULL) + { + return; + } + + request->nr_Name = (UBYTE *)StrDupSafe(file); + if (request->nr_Name == NULL) + { + return; + } + + request->nr_Flags = NRF_SEND_MESSAGE | NRB_WAIT_REPLY; + request->nr_UserData = type; + + AddRequest(request); +} + +void CleanupNotifications(void) +{ + volatile struct NotifyRequestNode *current, *next; + + current = Last; + while (current != NULL) + { + if (current->Registered == DOSTRUE) + { + EndNotify(current->Request); + } + FreeMemSafe((void *)current->Request->nr_Name); + FreeMemSafe((void *)current->Request); + + next = current->Next; + FreeMemSafe((void *)current); + current = next; + } +} \ No newline at end of file diff --git a/notify.h b/notify.h new file mode 100644 index 0000000..fe9b27d --- /dev/null +++ b/notify.h @@ -0,0 +1,34 @@ +/*- + * Copyright (c) 2017-2020 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. + * + */ + +#ifndef NOTIFY_H_INCLUDED +#define NOTIFY_H_INCLUDED + +void ActivateNotifyPort(struct MsgPort *port); +void WatchFile(char *file, long type); +void CleanupNotifications(void); + +#endif diff --git a/ptz.c b/ptz.c index db6256a..a93a40c 100644 --- a/ptz.c +++ b/ptz.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,15 +33,18 @@ #include "ptz.h" #include "string.h" -#include "state.h" +#include "global.h" #include "mem.h" +#include "logmod.h" +#define MODULENAME "Posix TZ" + /* * Parse integers in POSIX TZ string. */ static const char *ParseInt(const char *p, int min, int max, int *result) { - char *start = (char *)p; + CONST_STRPTR start = (CONST_STRPTR)p; LONG c, value; c = StrToLong(start, &value); @@ -50,8 +53,7 @@ static const char *ParseInt(const char *p, int min, int max, int *result) return NULL; *result = (int)value; - - return (start + c); + return (const char *)(start + c); } /* @@ -63,13 +65,14 @@ static const char *ParseAbbr(const char *p, char **result) if (*p == '<') { + start++; while (*++p != '>') { if (*p == '\0') return NULL; } - *result = (char *)AllocMemSafe(p - start); + *result = AllocStringSafe(p - start); CopyMem((APTR)start, *result, p - start); return ++p; @@ -81,7 +84,7 @@ static const char *ParseAbbr(const char *p, char **result) if (p - start < 3) return NULL; - *result = (char *)AllocMemSafe(p - start + 1); + *result = AllocStringSafe(p - start + 1); CopyMem((APTR)start, *result, p - start); return p; @@ -91,7 +94,7 @@ static const char *ParseAbbr(const char *p, char **result) * Parse time part of POSIX TZ string in format: * [+|-]hh[:mm[:ss]] */ -static const char *ParseTime(const char *p, int min_hour, int max_hour, int sign, struct PosixTimeZoneOffset *result) +static const char *ParseTime(const char *p, int min_hour, int max_hour, int sign, struct PosixTimezoneOffset *result) { int seconds = 0; int minutes = 0; @@ -132,11 +135,6 @@ static const char *ParseTime(const char *p, int min_hour, int max_hour, int sign result->minutes = minutes; result->hours = hours; - result->time = seconds; - result->time += minutes * 60; - result->time += hours * 60 * 60; - result->time *= sign; - return p; } @@ -197,7 +195,6 @@ static const char *ParseTransition(const char *p, struct PosixTransition *result result->offset.hours = 2; result->offset.minutes = 0; result->offset.seconds = 0; - result->offset.time = 2 * 60 * 60; if (*p == '/') { @@ -212,7 +209,7 @@ static const char *ParseTransition(const char *p, struct PosixTransition *result * Parse POSIX TZ string in format: * std offset dst [offset],start[/time],end[/time] */ -static bool ParsePosixTz(const char *tz, struct PosixTimeZone *result) +static bool ParsePosixTz(const char *tz, struct PosixTimezone *result) { const char *p = tz; if (*p == ':') @@ -233,10 +230,11 @@ static bool ParsePosixTz(const char *tz, struct PosixTimeZone *result) // Default is one hour ahead of std result->dst.offset.sign = result->std.offset.sign; - result->dst.offset.hours = result->std.offset.hours + 1; + result->dst.offset.hours = (result->dst.offset.sign < 0) + ? result->std.offset.hours - 1 + : result->std.offset.hours + 1; result->dst.offset.minutes = result->std.offset.minutes; result->dst.offset.seconds = result->std.offset.seconds; - result->dst.offset.time = result->std.offset.time + 60 * 60; if (*p == '\0') return true; @@ -252,6 +250,29 @@ static bool ParsePosixTz(const char *tz, struct PosixTimeZone *result) return p != NULL && *p == '\0'; } +char *PosixTimezoneSignChar(struct PosixLocalTimezone *ptz) +{ + static char *positive = "+"; + static char *negative = "-"; + + if (ptz == NULL) + { + return positive; + } + + if (ptz->offset.hours == 0 && ptz->offset.minutes == 0 && ptz->offset.seconds == 0) + { + return positive; + } + + if (ptz->offset.sign >= 0) + { + return positive; + } + + return negative; +} + static int FindWeekDay(int year, int month, int day) { int h = 0; @@ -366,7 +387,12 @@ static ULONG FindTransitionTime(int year, struct PosixTransition *transition) break; } - transitionTime += transition->offset.time; + // TODO: Validate sign + transitionTime += + (transition->offset.sign < 0 ? -1 : 1) * + (transition->offset.hours * 60 * 60 + + transition->offset.minutes * 60 + + transition->offset.seconds * 60); return transitionTime; } @@ -375,17 +401,17 @@ struct PosixTransitionTime *FindNextTransition(time_t now) { int i = 0; - if (Globals->Timezone->start.type == 0) + if (Timezone->start.type == 0) { return NULL; } - while (Globals->Timezone->transitions[i].time < now) + while (Timezone->transitions[i].time < now) { i++; } - return &Globals->Timezone->transitions[i]; + return &Timezone->transitions[i]; } static char *GetVariable(const char *variable) @@ -393,7 +419,7 @@ static char *GetVariable(const char *variable) unsigned long memsize = 256; STRPTR var = (STRPTR)variable; - STRPTR buf = (char *)AllocMemSafe(memsize); + STRPTR buf = (STRPTR)AllocStringSafe(memsize); if (!buf) { return NULL; @@ -401,43 +427,43 @@ static char *GetVariable(const char *variable) if (GetVar(var, buf, memsize - 1, GVF_GLOBAL_ONLY) > 0) { - return buf; + return (char *)buf; } - FreeMemSafe(buf, __FUNCTION__); + FreeMemSafe(buf); return NULL; } -void CleanupTimezone(void) +void CleanupPosixTimezone(void) { - if (Globals->Timezone != NULL) + if (Timezone != NULL) { - if (Globals->Timezone->std.abbreviation != NULL) + if (Timezone->std.abbreviation != NULL) { - FreeMemSafe(Globals->Timezone->std.abbreviation, __FUNCTION__); + FreeMemSafe(Timezone->std.abbreviation); } - if (Globals->Timezone->dst.abbreviation != NULL) + if (Timezone->dst.abbreviation != NULL) { - FreeMemSafe(Globals->Timezone->dst.abbreviation, __FUNCTION__); + FreeMemSafe(Timezone->dst.abbreviation); } - FreeMemSafe(Globals->Timezone, __FUNCTION__); - Globals->Timezone = NULL; + FreeMemSafe(Timezone); + Timezone = NULL; } } static void InitFromTZone(void) { - if (Globals->Timezone->dst.abbreviation != NULL) + if (Timezone->dst.abbreviation != NULL) { // DST is present - Globals->Timezone->current.abbreviation = Globals->Timezone->dst.abbreviation; - Globals->Timezone->current.offset = Globals->Timezone->dst.offset; + Timezone->current.abbreviation = Timezone->dst.abbreviation; + Timezone->current.offset = Timezone->dst.offset; } else { - Globals->Timezone->current.abbreviation = Globals->Timezone->std.abbreviation; - Globals->Timezone->current.offset = Globals->Timezone->std.offset; + Timezone->current.abbreviation = Timezone->std.abbreviation; + Timezone->current.offset = Timezone->std.offset; } } @@ -447,14 +473,14 @@ static void BuildTransitionMap() bool isdst = false; bool north; - switch (Globals->Timezone->start.type) + switch (Timezone->start.type) { case JulianDay: case JulianDayLeap: - isdst = Globals->Timezone->start.day > Globals->Timezone->end.day; + isdst = Timezone->start.day > Timezone->end.day; break; case DayWeekMonth: - isdst = Globals->Timezone->start.month > Globals->Timezone->end.month; + isdst = Timezone->start.month > Timezone->end.month; break; default: return; @@ -463,8 +489,8 @@ static void BuildTransitionMap() north = isdst ? false : true; - Globals->Timezone->transitions[0].time = 0; - Globals->Timezone->transitions[0].isdst = isdst; + Timezone->transitions[0].time = 0; + Timezone->transitions[0].isdst = isdst; for (i = 0; i < 138 / 2; i++) { @@ -472,37 +498,37 @@ static void BuildTransitionMap() isdst = isdst ? false : true; time = north - ? FindTransitionTime(i + 1978, &Globals->Timezone->start) - : FindTransitionTime(i + 1978, &Globals->Timezone->end); + ? FindTransitionTime(i + 1978, &Timezone->start) + : FindTransitionTime(i + 1978, &Timezone->end); - Globals->Timezone->transitions[i * 2 + 1].time = time; - Globals->Timezone->transitions[i * 2 + 1].isdst = isdst; + Timezone->transitions[i * 2 + 1].time = time; + Timezone->transitions[i * 2 + 1].isdst = isdst; isdst = isdst ? false : true; time = north - ? FindTransitionTime(i + 1978, &Globals->Timezone->end) - : FindTransitionTime(i + 1978, &Globals->Timezone->start); + ? FindTransitionTime(i + 1978, &Timezone->end) + : FindTransitionTime(i + 1978, &Timezone->start); - Globals->Timezone->transitions[i * 2 + 2].time = time; - Globals->Timezone->transitions[i * 2 + 2].isdst = isdst; + Timezone->transitions[i * 2 + 2].time = time; + Timezone->transitions[i * 2 + 2].isdst = isdst; } - Globals->Timezone->transitions[137].time = 2147483647; - Globals->Timezone->transitions[137].isdst = false; + Timezone->transitions[137].time = 2147483647; + Timezone->transitions[137].isdst = false; } -int InitTimezone(void) +int InitPosixTimezone(char **variable) { - int result = 4; + int result = 5; char *var; - Globals->Timezone = NULL; + Timezone = NULL; var = GetVariable("TZ"); if (var == NULL) { var = GetVariable("TZONE"); - result = 3; + result = 4; } if (var == NULL) @@ -510,18 +536,19 @@ int InitTimezone(void) return 1; } - Globals->Timezone = AllocMemSafe(sizeof(struct PosixTimeZone)); + *variable = StrDupSafe(var); + Timezone = AllocStructSafe(struct PosixTimezone); - if (!ParsePosixTz(var, Globals->Timezone)) + if (!ParsePosixTz(var, Timezone)) { - FreeMemSafe(var, __FUNCTION__); - CleanupTimezone(); - return 2; + FreeMemSafe(var); + CleanupPosixTimezone(); + return result - 2; } - FreeMemSafe(var, __FUNCTION__); + FreeMemSafe(var); - if (Globals->Timezone->start.type == 0) + if (Timezone->start.type == 0) { InitFromTZone(); } @@ -533,32 +560,32 @@ int InitTimezone(void) return result; } -bool SetTimezone(struct timeval *tv) +bool SetPosixTimezone(struct timeval *tv) { int i = 0; - if (Globals->Timezone->start.type == 0) + if (Timezone->start.type == 0) { return false; } - while (Globals->Timezone->transitions[i].time <= tv->tv_secs) + while (Timezone->transitions[i].time <= tv->tv_secs) { i++; } i--; - if (Globals->Timezone->transitions[i].isdst) + if (Timezone->transitions[i].isdst) { - Globals->Timezone->current.abbreviation = Globals->Timezone->dst.abbreviation; - Globals->Timezone->current.offset = Globals->Timezone->dst.offset; + Timezone->current.abbreviation = Timezone->dst.abbreviation; + Timezone->current.offset = Timezone->dst.offset; } else { - Globals->Timezone->current.abbreviation = Globals->Timezone->std.abbreviation; - Globals->Timezone->current.offset = Globals->Timezone->std.offset; + Timezone->current.abbreviation = Timezone->std.abbreviation; + Timezone->current.offset = Timezone->std.offset; } return true; -} \ No newline at end of file +} diff --git a/ptz.h b/ptz.h index 8e6a293..a11286d 100644 --- a/ptz.h +++ b/ptz.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,19 +27,22 @@ #ifndef POSIXTZ_H_INCLUDED #define POSIXTZ_H_INCLUDED +#include +#include +#include #include +#include #define JulianDay 1 #define JulianDayLeap 2 #define DayWeekMonth 3 -struct PosixTimeZoneOffset +struct PosixTimezoneOffset { int sign; // before/after 00:00:00, -1 or 1 int hours; // hours before/after 00:00:00 [0:167] int minutes; // minutes before/after 00:00:00 [0:59] int seconds; // seconds before/after 00:00:00 [0:59] - time_t time; }; struct PosixTransition @@ -49,7 +52,7 @@ struct PosixTransition int weekday; // day of week [0:6] int week; // week of month [1:5] int month; // month of year [1:12] - struct PosixTimeZoneOffset offset; + struct PosixTimezoneOffset offset; }; struct PosixTransitionTime @@ -58,25 +61,26 @@ struct PosixTransitionTime time_t time; }; -struct PosixLocalTimeZone +struct PosixLocalTimezone { char *abbreviation; - struct PosixTimeZoneOffset offset; + struct PosixTimezoneOffset offset; }; -struct PosixTimeZone +struct PosixTimezone { - struct PosixLocalTimeZone current; - struct PosixLocalTimeZone std; - struct PosixLocalTimeZone dst; + struct PosixLocalTimezone current; + struct PosixLocalTimezone std; + struct PosixLocalTimezone dst; struct PosixTransition start; struct PosixTransition end; struct PosixTransitionTime transitions[138]; }; -int InitTimezone(void); -void CleanupTimezone(void); -bool SetTimezone(struct timeval *tv); +int InitPosixTimezone(char **); +void CleanupPosixTimezone(void); +bool SetPosixTimezone(struct timeval *tv); struct PosixTransitionTime *FindNextTransition(time_t); +char* PosixTimezoneSignChar(struct PosixLocalTimezone *); #endif diff --git a/setting.c b/setting.c new file mode 100644 index 0000000..5a0ee28 --- /dev/null +++ b/setting.c @@ -0,0 +1,678 @@ +/*- + * Copyright (c) 2017-2020 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 "setting.h" +#include "global.h" +#include "mem.h" + +#include "logmod.h" +#define MODULENAME "Settings" + +struct AppSettings *Settings; +struct AppSettingKeys *SettingKeys; + +static const struct AppSettingKeys SettingKeyStruct = { + .DestinationAddress = KEYWORD_SERVER, + .DestinationPort = KEYWORD_PORT, + .Threshold = KEYWORD_THRESHOLD, + .Interval = KEYWORD_INTERVAL, + .Priority = KEYWORD_PRIORITY, + .PopKey = KEYWORD_POPKEY, + .Popup = KEYWORD_POPUP, + .Readonly = KEYWORD_READONLY, + .Expert = KEYWORD_EXPERT, + .Timeout = KEYWORD_TIMEOUT}; + +const struct AppSettings DefaultSettings = { + .Type = DefaultSettingType, + .DestinationAddress = (char *)SERVER_DEF, + .DestinationPort = (char *)PORT_DEF, + .Timeout = TIMEOUT_DEF, + .Interval = INTERVAL_DEF, + .PopKey = POPKEY_DEF, + .Popup = POPUP_DEF, + .Readonly = READONLY_DEF, + .Expert = EXPERT_DEF, + .Priority = PRIORITY_DEF, + .Threshold = THRESHOLD_DEF, + .Values = 0xFFFF}; + +static void SetPrioritySetting(struct AppSettings *, void *); +static void SetIntervalSetting(struct AppSettings *, void *); +static void SetTimeoutSetting(struct AppSettings *, void *); +static void SetThresholdSetting(struct AppSettings *, void *); +static void SetDestinationAddressSetting(struct AppSettings *, void *); +static void SetDestinationPortSetting(struct AppSettings *, void *); +static void SetReadOnlySetting(struct AppSettings *, void *); +static void SetExpertSetting(struct AppSettings *, void *); +static void SetPopupSetting(struct AppSettings *, void *); +static void SetPopKeySetting(struct AppSettings *, void *); + +// Keyword order in settingFunctions needs to match order in keyword template +const struct SettingFunc settingFunctions[] = { + {KEYWORD_READONLY, SetReadOnlySetting}, + {KEYWORD_EXPERT, SetExpertSetting}, + {KEYWORD_SERVER, SetDestinationAddressSetting}, + {KEYWORD_PORT, SetDestinationPortSetting}, + {KEYWORD_TIMEOUT, SetTimeoutSetting}, + {KEYWORD_THRESHOLD, SetThresholdSetting}, + {KEYWORD_INTERVAL, SetIntervalSetting}, + {KEYWORD_PRIORITY, SetPrioritySetting}, + {KEYWORD_POPKEY, SetPopKeySetting}, + {KEYWORD_POPUP, SetPopupSetting}}; + +static const char *prefsFile = "ENV:timekeeper.prefs"; +static const char *persistentPrefsFile = "ENVARC:timekeeper.prefs"; +static const char *prefsFileSearch = "Searching for preference in %s"; +static const char *prefsFileFound = "Found preference file"; +static const char *prefsFileNotFound = "Preference file not found"; +static const char *prefsFileSave = "Saving preferences in %s"; +static const char *fileOpenError = "Could not open preference file"; +static const char *fileSaveError = "Could not save preference file"; +static const char *fileReadError = "Error while reading file"; +static const char *fileWriteError = "Error while writing file"; +static const char *unknownSetting = "Found unknown setting in preference file: %s"; +static const char *foundSetting = "Found %s in preference file"; +static const char *foundWbSetting = "Found tooltype from icon: %s"; +static const char *foundCliSetting = "Got %s from CLI"; +static const char *integerError = "Value should be an integer: %s"; +static const char *yesNoError = "Value should be YES or NO: %s"; +static const char *applyDefaultSettings = "Applying default values"; +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 *settingChangedLong = "%s changed: %ld -> %ld"; +static const char *settingChangedString = "%s changed: %s -> %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"; +static const char *saveValueString = "%s=%s\n"; +static const char *noValueString = "NO"; +static const char *yesValueString = "YES"; + +#define MAXSETTINGLINELEN 256 + +static struct AppSettings *fileSettings; +static struct AppSettings *cachedSettings; + +void InitSettings(void) +{ + Settings = CreateSettings(GlobalSettingType); + SettingKeys = (struct AppSettingKeys *)&SettingKeyStruct; +} + +void CleanupSettings(void) +{ + FreeSettings(Settings); +} + +static char *BooleanAsText(bool value) +{ + return (char *)(value ? yesValueString : noValueString); +} + +void ShowAppSettings(struct AppSettings *settings) +{ + char low[MAXLONGLONGCHARSIZE]; + + LongLongToStr(settings->Threshold, low); + LogDebug(settingValueString, SettingKeys->Popup, BooleanAsText(settings->Popup)); + LogDebug(settingValueString, SettingKeys->PopKey, settings->PopKey); + LogDebug(settingValueLong, SettingKeys->Priority, settings->Priority); + LogDebug(settingValueString, SettingKeys->Threshold, low); + LogDebug(settingValueString, SettingKeys->DestinationAddress, settings->DestinationAddress); + LogDebug(settingValueString, SettingKeys->DestinationPort, settings->DestinationPort); + LogDebug(settingValueLong, SettingKeys->Timeout, settings->Timeout); + LogDebug(settingValueLong, SettingKeys->Interval, settings->Interval); + LogDebug(settingValueString, SettingKeys->Readonly, BooleanAsText(settings->Readonly)); + LogDebug(settingValueString, SettingKeys->Expert, BooleanAsText(settings->Expert)); +} + +void ShowSettings(void) +{ + LogDebug(effectiveSettings); + ShowAppSettings(Settings); +} + +void LogFoundSetting(long type, const char *name) +{ + switch (type) + { + case PrefsSettingType: + LogDebug(foundSetting, name); + break; + case CliSettingType: + LogDebug(foundCliSetting, name); + break; + case WbSettingType: + LogDebug(foundWbSetting, name); + break; + default: + break; + } +} + +static void ParseLongSetting( + struct AppSettings *settings, + long flag, + const char *keyword, + long *valueField, + void *value) +{ + LogFoundSetting(settings->Type, keyword); + if (settings->Type == CliSettingType) + { + *valueField = *(long *)value; + settings->Values |= flag; + return; + } + + if (TryParseLong((char *)value, valueField)) + { + settings->Values |= flag; + return; + } + + LogWarn(integerError, value); +} + +static void ParseBooleanSetting( + struct AppSettings *settings, + long flag, + const char *keyword, + long *valueField, + void *value, + bool yesNo) +{ + LogFoundSetting(settings->Type, keyword); + + // CLI switch is always a long value + if (settings->Type == CliSettingType && !yesNo) + { + *valueField = (*valueField != 0 ? true : false); + settings->Values |= flag; + return; + } + + if (value == NULL || *((const char *)value) == '\0') + { + LogWarn(yesNoError, '\0'); + return; + } + + if (Stricmp((CONST_STRPTR)noValueString, (CONST_STRPTR)value) == 0 || + Stricmp((CONST_STRPTR) "0", (CONST_STRPTR)value) == 0) + { + *valueField = false; + settings->Values |= flag; + return; + } + + if (Stricmp((CONST_STRPTR)yesValueString, (CONST_STRPTR)value) == 0 || + Stricmp((CONST_STRPTR) "1", (CONST_STRPTR)value) == 0) + { + *valueField = true; + settings->Values |= flag; + return; + } + + LogWarn(yesNoError, value); +} + +static void SetPrioritySetting(struct AppSettings *settings, void *value) +{ + ParseLongSetting(settings, PrioritySet, SettingKeys->Priority, + &settings->Priority, value); +} + +static void SetIntervalSetting(struct AppSettings *settings, void *value) +{ + ParseLongSetting(settings, IntervalSet, SettingKeys->Interval, + &settings->Interval, value); +} + +static void SetTimeoutSetting(struct AppSettings *settings, void *value) +{ + ParseLongSetting(settings, TimeoutSet, SettingKeys->Timeout, + &settings->Timeout, value); +} + +static void SetThresholdSetting(struct AppSettings *settings, void *value) +{ + LogFoundSetting(settings->Type, SettingKeys->Threshold); + if (TryParseLongLong((char *)value, &settings->Threshold)) + { + settings->Values |= ThresholdSet; + return; + } + + LogWarn(integerError, value); +} + +static void SetDestinationAddressSetting(struct AppSettings *settings, void *value) +{ + LogFoundSetting(settings->Type, SettingKeys->DestinationAddress); + settings->DestinationAddress = StrDupSafe((const char *)value); + settings->Values |= DestinationAddressSet; +} + +static void SetPopKeySetting(struct AppSettings *settings, void *value) +{ + LogFoundSetting(settings->Type, SettingKeys->PopKey); + settings->PopKey = StrDupSafe((const char *)value); + settings->Values |= PopKeySet; +} + +static void SetDestinationPortSetting(struct AppSettings *settings, void *value) +{ + LogFoundSetting(settings->Type, SettingKeys->DestinationPort); + settings->DestinationPort = StrDupSafe((const char *)value); + settings->Values |= DestinationPortSet; +} + +static void SetReadOnlySetting(struct AppSettings *settings, void *value) +{ + ParseBooleanSetting(settings, ReadonlySet, SettingKeys->Readonly, + &settings->Readonly, value, true); +} + +static void SetExpertSetting(struct AppSettings *settings, void *value) +{ + ParseBooleanSetting(settings, ExpertSet, SettingKeys->Expert, + &settings->Expert, value, true); +} + +static void SetPopupSetting(struct AppSettings *settings, void *value) +{ + ParseBooleanSetting(settings, PopUpSet, SettingKeys->Popup, + &settings->Popup, value, false); +} + +static void ParseSetting(struct AppSettings *settings, char *line) +{ + char *value; + char *end; + int i; + + value = StrChr(line, '=', MAXSETTINGLINELEN); + if (value == NULL) + { + LogWarn(unknownSetting, "No assignment"); + return; + } + + end = StrChr(value, '\n', MAXSETTINGLINELEN); + if (end == NULL) + { + LogWarn(unknownSetting, "No end of line"); + return; + } + + *value++ = '\0'; + *end = '\0'; + + for (i = 0; i < KEYWORD_COUNT; i++) + { + if (Stricmp((STRPTR)settingFunctions[i].Name, (STRPTR)line) == 0) + { + settingFunctions[i].Function(settings, (void *)value); + return; + } + } + + LogWarn(unknownSetting, line); +} + +void LoadSettings(void) +{ + struct AppSettings *settings; + const int maxLines = 25; + char line[MAXSETTINGLINELEN]; + char message[MAXDOSERRORLEN]; + bool eof = false; + int count = 0; + long error; + BPTR file; + + LogDebug(prefsFileSearch, prefsFile); + file = Open((STRPTR)prefsFile, MODE_OLDFILE); + + if (!file) + { + error = IoErr(); + if (error == ERROR_OBJECT_NOT_FOUND) + { + LogWarn(prefsFileNotFound); + } + else + { + Fault(error, (STRPTR)fileOpenError, (STRPTR)message, MAXDOSERRORLEN); + LogWarn(message); + } + return; + } + + LogInfo(prefsFileFound); + + settings = CreateSettings(PrefsSettingType); + + do + { + char *c = (char *)FGets(file, (STRPTR)line, MAXSETTINGLINELEN); + eof = (c == NULL); + + if (!eof) + { + ParseSetting(settings, line); + count++; + } + } while (!eof && count < maxLines); + + // If NULL is returned for an EOF, IoErr() will return 0. + error = IoErr(); + if (error != 0) + { + Fault(error, (STRPTR)fileReadError, (STRPTR)message, MAXDOSERRORLEN); + LogError(message); + } + + Close(file); + fileSettings = settings; +} + +static void WriteSetting(BPTR file, const char *format, ...) +{ + long count; + va_list args; + va_start(args, format); + count = VFPrintf(file, (void *)format, (void *)args); + va_end(args); + + if (count <= 0) + { + long error = IoErr(); + if (error != 0) + { + char message[MAXDOSERRORLEN]; + Fault(error, (STRPTR)fileWriteError, (STRPTR)message, MAXDOSERRORLEN); + LogError(message); + } + } +} + +void SaveSettings(bool persist) +{ + char low[MAXLONGLONGCHARSIZE]; + const char *fileName = persist ? persistentPrefsFile : prefsFile; + BPTR file = Open((STRPTR)fileName, MODE_NEWFILE); + if (!file) + { + char message[MAXDOSERRORLEN]; + long error = IoErr(); + Fault(error, (STRPTR)fileSaveError, (STRPTR)message, MAXDOSERRORLEN); + LogWarn(message); + return; + } + + LogInfo(prefsFileSave, fileName); + + LongLongToStr(Settings->Threshold, low); + WriteSetting(file, saveValueString, SettingKeys->Popup, BooleanAsText(Settings->Popup)); + WriteSetting(file, saveValueString, SettingKeys->PopKey, Settings->PopKey); + WriteSetting(file, saveValueLong, SettingKeys->Priority, Settings->Priority); + WriteSetting(file, saveValueString, SettingKeys->Threshold, low); + WriteSetting(file, saveValueString, SettingKeys->DestinationAddress, Settings->DestinationAddress); + WriteSetting(file, saveValueString, SettingKeys->DestinationPort, Settings->DestinationPort); + WriteSetting(file, saveValueLong, SettingKeys->Timeout, Settings->Timeout); + WriteSetting(file, saveValueLong, SettingKeys->Interval, Settings->Interval); + WriteSetting(file, saveValueString, SettingKeys->Readonly, BooleanAsText(Settings->Readonly)); + WriteSetting(file, saveValueString, SettingKeys->Expert, BooleanAsText(Settings->Expert)); + + Close(file); +} + +struct AppSettings *CreateSettings(long type) +{ + struct AppSettings *settings; + settings = AllocStructSafe(struct AppSettings); + settings->Type = type; + return settings; +} + +struct AppSettings *CopySettings(const struct AppSettings *settings) +{ + struct AppSettings *s = CreateSettings(settings->Type); + CopyMem((void *)settings, s, sizeof(struct AppSettings)); + s->DestinationAddress = StrDupSafe(settings->DestinationAddress); + s->DestinationPort = StrDupSafe(settings->DestinationPort); + s->PopKey = StrDupSafe(settings->PopKey); + s->Values = 0xFFFF; + return s; +} + +void FreeSettings(struct AppSettings *settings) +{ + if (settings->DestinationAddress != NULL) + { + FreeMemSafe(settings->DestinationAddress); + } + + if (settings->DestinationPort != NULL) + { + FreeMemSafe(settings->DestinationPort); + } + + if (settings->PopKey != NULL) + { + FreeMemSafe(settings->PopKey); + } + + FreeMemSafe(settings); +} + +static void ApplyLongSetting( + struct AppSettings *settings, + long flag, + const char *keyword, + long *curValue, + long *newValue, + bool quiet) +{ + if ((settings->Values & flag) == flag) + { + if (settings->Type == DefaultSettingType) + { + LogDebug(settingValueLong, keyword, *newValue); + } + else if (*curValue != *newValue) + { + LogInfo(settingChangedLong, keyword, *curValue, *newValue); + } + else if (!quiet) + { + LogDebug(settingSetLong, keyword, *newValue); + } + *curValue = *newValue; + } +} + +static void ApplyBooleanSetting( + struct AppSettings *settings, + long flag, + const char *keyword, + long *curValue, + long *newValue, + bool quiet) +{ + if ((settings->Values & flag) == flag) + { + if (settings->Type == DefaultSettingType) + { + LogDebug(settingValueString, keyword, BooleanAsText(*newValue)); + } + else if (*curValue != *newValue) + { + LogInfo(settingChangedString, keyword, BooleanAsText(*curValue), BooleanAsText(*newValue)); + } + else if (!quiet) + { + LogDebug(settingSetString, keyword, BooleanAsText(*newValue)); + } + *curValue = *newValue; + } +} + +static void ApplyStringSetting( + struct AppSettings *settings, + long flag, + const char *keyword, + char **curValue, + char *newValue, + bool quiet) +{ + if ((settings->Values & flag) == flag) + { + if (settings->Type == DefaultSettingType) + { + LogDebug(settingValueString, keyword, newValue); + } + else if (Stricmp((STRPTR)*curValue, (STRPTR)newValue) != 0) + { + LogInfo(settingChangedString, keyword, *curValue, newValue); + } + else if (!quiet) + { + LogDebug(settingSetString, keyword, newValue); + } + + if (*curValue != NULL) + { + FreeMemSafe(*curValue); + } + *curValue = StrDupSafe(newValue); + } +} + +void ApplyAppSettings(struct AppSettings *settings, bool quiet) +{ + switch (settings->Type) + { + case DefaultSettingType: + LogInfo(applyDefaultSettings); + break; + case PrefsSettingType: + LogInfo(applyFileSettings); + break; + case CliSettingType: + LogInfo(applyCliSettings); + break; + case WbSettingType: + LogInfo(applyWbSettings); + break; + default: + break; + } + + ApplyBooleanSetting(settings, PopUpSet, SettingKeys->Popup, + &Settings->Popup, &settings->Popup, quiet); + + ApplyStringSetting(settings, PopKeySet, SettingKeys->PopKey, + &Settings->PopKey, settings->PopKey, quiet); + + ApplyLongSetting(settings, PrioritySet, SettingKeys->Priority, + &Settings->Priority, &settings->Priority, quiet); + + ApplyLongSetting(settings, TimeoutSet, SettingKeys->Timeout, + &Settings->Timeout, &settings->Timeout, quiet); + + ApplyLongSetting(settings, IntervalSet, SettingKeys->Interval, + &Settings->Interval, &settings->Interval, quiet); + + ApplyBooleanSetting(settings, ReadonlySet, SettingKeys->Readonly, + &Settings->Readonly, &settings->Readonly, quiet); + + ApplyBooleanSetting(settings, ExpertSet, SettingKeys->Expert, + &Settings->Expert, &settings->Expert, quiet); + + ApplyStringSetting(settings, DestinationAddressSet, SettingKeys->DestinationAddress, + &Settings->DestinationAddress, settings->DestinationAddress, quiet); + + ApplyStringSetting(settings, DestinationPortSet, SettingKeys->DestinationPort, + &Settings->DestinationPort, settings->DestinationPort, quiet); + + if ((settings->Values & ThresholdSet) == ThresholdSet) + { + char before[MAXLONGLONGCHARSIZE]; + char after[MAXLONGLONGCHARSIZE]; + + if (settings->Type == DefaultSettingType) + { + LongLongToStr(settings->Threshold, after); + LogDebug(settingValueString, SettingKeys->Threshold, after); + } + else if (Settings->Threshold != settings->Threshold) + { + LongLongToStr(Settings->Threshold, before); + LongLongToStr(settings->Threshold, after); + LogInfo(settingChangedString, SettingKeys->Threshold, before, after); + } + else if (!quiet) + { + LongLongToStr(Settings->Threshold, before); + LogDebug(settingSetString, SettingKeys->Threshold, before); + } + Settings->Threshold = settings->Threshold; + } +} + +void CacheSettings(struct AppSettings *settings) +{ + if (cachedSettings != NULL) + { + FreeSettings(cachedSettings); + } + cachedSettings = settings; +} + +void ApplySettings() +{ + ApplyAppSettings((struct AppSettings *)&DefaultSettings, false); + + if (fileSettings != NULL) + { + ApplyAppSettings(fileSettings, false); + FreeSettings(fileSettings); + } + + if (cachedSettings != NULL) + { + ApplyAppSettings(cachedSettings, false); + FreeSettings(cachedSettings); + } +} diff --git a/setting.h b/setting.h new file mode 100644 index 0000000..42f767f --- /dev/null +++ b/setting.h @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 2017-2020 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. + * + */ + +#ifndef STATE_H_INCLUDED +#define STATE_H_INCLUDED + +#include "config.h" +#include "locale.h" + +#define PrioritySet 0x001 +#define TimeoutSet 0x004 +#define IntervalSet 0x008 +#define ReadonlySet 0x010 +#define ExpertSet 0x020 +#define DestinationAddressSet 0x040 +#define DestinationPortSet 0x080 +#define ThresholdSet 0x100 +#define PopKeySet 0x200 +#define PopUpSet 0x400 + +#define DefaultSettingType 0x01 +#define PrefsSettingType 0x02 +#define CliSettingType 0x03 +#define WbSettingType 0x04 +#define GlobalSettingType 0x10 + +struct AppSettings +{ + long Priority; + long Timeout; + long Interval; + long Readonly; + long Expert; + long long Threshold; + char *DestinationAddress; + char *DestinationPort; + char *PopKey; + long Popup; + long Values; + long Type; +}; + +struct AppSettingKeys +{ + const char *Priority; + const char *Timeout; + const char *Interval; + const char *Readonly; + const char *Expert; + const char *DestinationAddress; + const char *DestinationPort; + const char *Threshold; + const char *PopKey; + const char *Popup; +}; + +typedef void (*ParseSettingFunction)(struct AppSettings *, void *); + +struct SettingFunc +{ + const char *Name; + ParseSettingFunction Function; +}; + +extern struct AppSettings *Settings; +extern struct AppSettingKeys *SettingKeys; +extern const struct SettingFunc settingFunctions[]; +extern const struct AppSettings DefaultSettings; + +void InitSettings(void); +void CleanupSettings(void); +void ShowSettings(void); +void LoadSettings(void); +void SaveSettings(bool); + +struct AppSettings *CreateSettings(long); +struct AppSettings *CopySettings(const struct AppSettings *); +void ApplyAppSettings(struct AppSettings *, bool); +void FreeSettings(struct AppSettings *); +void CacheSettings(struct AppSettings *); +void ApplySettings(void); + +#endif diff --git a/shutdown.c b/shutdown.c new file mode 100644 index 0000000..933d7ff --- /dev/null +++ b/shutdown.c @@ -0,0 +1,126 @@ +/*- + * Copyright (c) 2017-2020 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 "shutdown.h" +#include "message.h" +#include "sync.h" +#include "win.h" + +#include "logmod.h" +#define MODULENAME "Shutdown" + +static volatile struct ShutdownInfo *info; +static volatile bool ShutdownInProgress = false; + +static void ShutdownSettingsWindow(void) +{ + int count = 0; + + LogTrace("Requesting settings window to close"); + SendMessageWait(info->SettingWindowPort, info->ShutdownMessage); + + LogTrace("Waiting for settings window to close ..."); + while (WindowProcRunning) + { + count++; + if (count % 10 == 0) + { + LogTrace("Waiting for settings window to close ..."); + } + Delay(50); + } + + LogTrace("Settings window closed"); +} + +static void ShutdownSynchronizerProcess(void) +{ + int count = 0; + + LogTrace("Requesting synchronizer process to stop"); + SendMessageWait(info->SynchronizerPort, info->ShutdownMessage); + + LogTrace("Waiting for synchronizer process to exit ..."); + while (SynchronizerRunning) + { + count++; + if (count % 10 == 0) + { + LogTrace("Waiting for synchronizer process to exit ..."); + } + Delay(50); + } + + LogTrace("Synchronizer process exited"); +} + +static void ShutdownProc(void) +{ + LogDebug("Waiting for synchronizer process to exit"); + ShutdownSettingsWindow(); + + LogDebug("Waiting for synchronizer process to exit"); + ShutdownSynchronizerProcess(); + + LogTrace("Complete"); + SendMessageWait(info->BrokerPort, info->ShutdownMessage); +} + +void StartShutdown(struct ShutdownInfo *shutdownInfo) +{ + struct Task *task; + + if (ShutdownInProgress) + { + LogWarn("Shutdown already in progress"); + return; + } + + ShutdownInProgress = true; + info = shutdownInfo; + LogWarn("Initiating shutdown"); + + task = (struct Task *)CreateNewProcTags( + NP_Entry, (IPTR)ShutdownProc, + NP_StackSize, 32 * 1024, + NP_Name, 0, + NP_Input, 0, + NP_Output, 0, + NP_Error, 0, + NP_CloseInput, FALSE, + NP_CloseOutput, FALSE, + NP_CloseError, FALSE, + NP_WindowPtr, 0, + NP_ConsoleTask, 0, + NP_Cli, FALSE, + TAG_DONE); + + if (task == NULL) + { + LogError("Could not start shutdown procedure"); + } +} diff --git a/shutdown.h b/shutdown.h new file mode 100644 index 0000000..90a84df --- /dev/null +++ b/shutdown.h @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2017-2020 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. + * + */ + +#ifndef SHUTDOWN_H_INCLUDED +#define SHUTDOWN_H_INCLUDED + +#include + +#define LOOP_RUNNING 0 +#define SHUTDOWN_REQUEST 1 +#define SHUTTING_DOWN 2 + +struct ShutdownInfo +{ + struct MsgPort *BrokerPort; + struct MsgPort *SynchronizerPort; + struct MsgPort *SettingWindowPort; + long ShutdownMessage; +}; + +void StartShutdown(struct ShutdownInfo *); + +#endif diff --git a/sntp.c b/sntp.c index c74bd2c..24609e9 100644 --- a/sntp.c +++ b/sntp.c @@ -1,7 +1,7 @@ /*- * Copyright (c) 2007 TANDBERG Telecom AS * Copyright (c) 2008-2009 Dag-Erling Smørgrav - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,12 +28,15 @@ */ #include "config.h" -#include "time.h" +#include "timer.h" #include "sntp.h" #include "mem.h" #include "net_getaddrinfo.h" #include "message.h" +#include "logmod.h" +#define MODULENAME "SNTP" + /* * Convert a struct timeval to an NTP timestamp */ @@ -86,10 +89,10 @@ void h2n_ntp(struct ntptime *nt) struct sntp { /* parameters from sntp_create() */ - char *srcaddr; - char *srcport; - char *dstaddr; - char *dstport; + STRPTR srcaddr; + STRPTR srcport; + STRPTR dstaddr; + STRPTR dstport; /* DNS data */ int family; @@ -122,13 +125,12 @@ sntp_create(const char *dstaddr, const char *dstport, const char *srcaddr, const char *srcport) { struct sntp *sntp; - sntp = AllocMemSafe(sizeof(struct sntp)); + sntp = AllocStructSafe(struct sntp); sntp->sd = -1; - - sntp->srcaddr = srcaddr ? StrDupSafe(srcaddr) : NULL; - sntp->srcport = StrDupSafe(srcport ? srcport : "123"); - sntp->dstaddr = StrDupSafe(dstaddr); - sntp->dstport = StrDupSafe(dstport ? dstport : "123"); + sntp->srcaddr = (STRPTR)((srcaddr != NULL) ? StrDupSafe(srcaddr) : NULL); + sntp->srcport = (STRPTR)StrDupSafe((srcport != NULL) ? srcport : "123"); + sntp->dstaddr = (STRPTR)StrDupSafe(dstaddr); + sntp->dstport = (STRPTR)StrDupSafe((dstport != NULL) ? dstport : "123"); /* good to go */ return (sntp); @@ -172,7 +174,7 @@ int sntp_open(struct sntp *sntp) if (sntp->sd == -1) { - SendWarningMessage("Could not get socket descriptor"); + LogWarn("Could not get socket descriptor"); freeaddrinfo(aiv); return (SNTP_SYSERR); } @@ -216,7 +218,7 @@ int sntp_open(struct sntp *sntp) if (connect(sntp->sd, sntp->raddr, sntp->raddrlen) != 0) { - SendWarningMessage("Could not connect socket"); + LogWarn("Could not connect socket"); sntp_close(sntp); return (SNTP_SYSERR); } @@ -246,11 +248,11 @@ void sntp_close(struct sntp *sntp) sntp->protocol = 0; if (sntp->laddr) - FreeMemSafe(sntp->laddr, __FUNCTION__); + FreeMemSafe(sntp->laddr); sntp->laddrlen = 0; if (sntp->raddr) - FreeMemSafe(sntp->raddr, __FUNCTION__); + FreeMemSafe(sntp->raddr); sntp->raddrlen = 0; if (sntp->sd != -1) @@ -271,22 +273,22 @@ void sntp_destroy(struct sntp *sntp) (void)sntp_close(sntp); if (sntp->srcaddr) - FreeMemSafe(sntp->srcaddr, __FUNCTION__); + FreeMemSafe(sntp->srcaddr); sntp->srcaddr = 0; if (sntp->srcport) - FreeMemSafe(sntp->srcport, __FUNCTION__); + FreeMemSafe(sntp->srcport); sntp->srcport = 0; if (sntp->dstaddr) - FreeMemSafe(sntp->dstaddr, __FUNCTION__); + FreeMemSafe(sntp->dstaddr); sntp->dstaddr = 0; if (sntp->dstport) - FreeMemSafe(sntp->dstport, __FUNCTION__); + FreeMemSafe(sntp->dstport); sntp->dstport = 0; - FreeMemSafe(sntp, __FUNCTION__); + FreeMemSafe(sntp); } /* @@ -428,10 +430,7 @@ sntp_recv(struct sntp *sntp, struct ntptime *nt, int *statum) /* look for kiss packet */ if (msg.flags == 0xe4 && msg.stratum == 0) { - char message[SETTINGMESSAGELEN]; - SNPrintf(message, SETTINGMESSAGELEN, - "KoD: %.4s", msg.reference_id); - SendWarningMessage(message); + LogWarn("KoD: %.4s", msg.reference_id); /* NOTICE: Consider taking a closer look at the kiss code */ return (SNTP_BACKOFF); } diff --git a/sntp.h b/sntp.h index 0384dbc..f47322e 100644 --- a/sntp.h +++ b/sntp.h @@ -1,7 +1,7 @@ /*- * Copyright (c) 2007 TANDBERG Telecom AS * Copyright (c) 2008-2009 Dag-Erling Smørgrav - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,6 +31,7 @@ #define SNTP_H_INCLUDED #include "config.h" +#include "tz.h" struct sntp; diff --git a/string.c b/string.c index 7c78bcb..b68b18e 100644 --- a/string.c +++ b/string.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,7 +21,7 @@ * 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" @@ -141,7 +141,7 @@ char *StrRChr(const char *start, const char c, int len) /* * Determine if a prefix occurs at the start of a string. - */ + */ bool StartsWith(const char *string, const char *prefix) { char *i = (char *)string; @@ -161,7 +161,7 @@ bool StartsWith(const char *string, const char *prefix) /* * Determine if a suffix occurs at the end of a string. - */ + */ bool EndsWith(const char *string, const char *suffix) { int a = 0; diff --git a/string.h b/string.h index e2fad9e..d66ccdd 100644 --- a/string.h +++ b/string.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,7 +21,7 @@ * 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. - * + * */ #ifndef STRING_H_INCLUDED diff --git a/sync.c b/sync.c new file mode 100644 index 0000000..e27242d --- /dev/null +++ b/sync.c @@ -0,0 +1,585 @@ +/*- + * Copyright (c) 2017-2020 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 +#include + +#include "sync.h" + +#include "config.h" +#include "global.h" +#include "setting.h" +#include "message.h" +#include "timer.h" +#include "sntp.h" +#include "ptz.h" +#include "mem.h" +#include "net.h" +#include "tz.h" + +#include "logmod.h" +#define MODULENAME "Syncer" + +#define SYNCPROCNAME APP_SHORT_NAME " Synchronizer" +#define POOLSUFFIX "pool.ntp.org" +#define POOLPORT "123" + +struct AppCom +{ + struct TimerInfo *TimerInfo; + struct sntp *Client; + int TimerSigBit; + bool Restart; + bool FirstRun; + bool SocketOpen; + int RunCount; + int FailCount; + int PoolServerNumber; + char *ServerName; + char *ServerPort; +}; + +static void SyncProc(void); +static void ComOpen(void); +static void ComInit(void); +static int SyncClock(void); +static void ShowStats(void); +static void CheckTimezone(void); +static const char *SntpErrorText(enum sntp_err error); + +static struct AppCom Synchronizer; +volatile bool SynchronizerRunning = false; +volatile struct timeval LastSync = {0, 0}; + +void StartSynchronizer(void) +{ + bool running; + struct Task *task; + + Forbid(); + running = SynchronizerRunning; + if (!running) + { + task = (struct Task *)CreateNewProcTags( + NP_Entry, (IPTR)SyncProc, + NP_Name, (IPTR)SYNCPROCNAME, + NP_StackSize, 64 * 1024, + NP_Input, 0, + NP_Output, 0, + NP_Error, 0, + NP_CloseInput, FALSE, + NP_CloseOutput, FALSE, + NP_CloseError, FALSE, + NP_WindowPtr, 0, + NP_ConsoleTask, 0, + NP_Cli, FALSE, + TAG_DONE); + SynchronizerRunning = (task != NULL); + } + Permit(); + + if (running) + { + LogDebug("Synchronizer process is already running"); + } + else if (task != NULL) + { + LogDebug("Created synchronizer process"); + } + else + { + LogError("Failed to create synchronizer process"); + } +} + +static void ComDestroy(void) +{ + if (Synchronizer.Client != NULL) + { + sntp_destroy(Synchronizer.Client); + Synchronizer.Client = NULL; + } +} + +static void ShowLocalTime(void) +{ + char *time = GetTimeText(AppLocale, LOCAL_TIME_NOW); + LogInfo("Local time is %s", time); + FreeMemSafe(time); +} + +static void MsgLoop(void) +{ + bool loop = true; + bool restart = false; + ULONG userPortSigMask = (1 << Ports.SyncerPort->mp_SigBit); + ULONG timerSigMask = (1 << Synchronizer.TimerSigBit); + ULONG sigMask = userPortSigMask | timerSigMask; + + ComOpen(); + + do + { + ULONG sigrcvd = Wait(sigMask); + + if (sigrcvd & timerSigMask) + { + ComOpen(); + ShowStats(); + } + + if (sigrcvd & userPortSigMask) + { + struct ApplicationMesage *msg; + while ((msg = (struct ApplicationMesage *)GetMsg(Ports.SyncerPort))) + { + switch (msg->MsgId) + { + case ATK_SHUTDOWN: + loop = false; + break; + case ATK_RESTART: + restart = true; + break; + default: + break; + } + ReplyMsg((struct Message *)msg); + } + } + + if (loop && restart) + { + struct timeval tv; + tv.tv_secs = Settings->Interval / 1000; + tv.tv_micro = Settings->Interval % 1000; + SetInterruptTimerInterval(Synchronizer.TimerInfo, &tv); + + ComDestroy(); + Synchronizer.Restart = true; + ComOpen(); + ShowStats(); + restart = false; + } + } while (loop); + + ComDestroy(); +} + +static void SyncProc(void) +{ + struct timeval tv; + + Synchronizer.TimerInfo = NULL; + Synchronizer.Client = NULL; + Synchronizer.TimerSigBit = -1; + Synchronizer.Restart = false; + Synchronizer.FirstRun = true; + Synchronizer.SocketOpen = false; + Synchronizer.RunCount = 0; + Synchronizer.FailCount = 0; + Synchronizer.PoolServerNumber = -1; + Synchronizer.ServerName = NULL; + Synchronizer.ServerPort = NULL; + + Synchronizer.TimerSigBit = AllocSignal(-1); + if (Synchronizer.TimerSigBit == -1) + { + LogError("Could not allocate signal for synchronizer"); + return; + } + + Ports.SyncerPort = CreateMsgPort(); + if (Ports.SyncerPort == NULL) + { + LogError("Could not allocate port for synchronizer"); + FreeSignal(Synchronizer.TimerSigBit); + return; + } + + Synchronizer.TimerInfo = CreateInterruptTimer( + FindTask(NULL), Synchronizer.TimerSigBit); + + if (Synchronizer.TimerInfo == NULL) + { + LogError("Could not create timer for synchronizer"); + FreeSignal(Synchronizer.TimerSigBit); + DeleteMsgPort(Ports.SyncerPort); + Ports.SyncerPort = NULL; + return; + } + + tv.tv_secs = Settings->Interval / 1000; + tv.tv_micro = Settings->Interval % 1000; + SetInterruptTimerInterval(Synchronizer.TimerInfo, &tv); + StartInterruptTimer(Synchronizer.TimerInfo); + + MsgLoop(); + + LogTrace("Loop exiting"); + + DeleteTimer(Synchronizer.TimerInfo); + FreeSignal(Synchronizer.TimerSigBit); + CloseSocketLibrary(); + CleanupVolMsgPort(&Ports.SyncerPort); + + if (Synchronizer.ServerName != NULL) + { + FreeMemSafe(Synchronizer.ServerName); + Synchronizer.ServerName = NULL; + LogTrace("ServerName cleared"); + } + + if (Synchronizer.ServerPort != NULL) + { + FreeMemSafe(Synchronizer.ServerPort); + Synchronizer.ServerPort = NULL; + LogTrace("ServerPort cleared"); + } + + Synchronizer.TimerInfo = NULL; + LogTrace("Loop exited"); + SynchronizerRunning = false; +} + +static void ComOpen(void) +{ + if (OpenSocketLibrary() != LIB_OK) + { + Synchronizer.SocketOpen = false; + return; + } + + Synchronizer.SocketOpen = true; + + if (Synchronizer.FirstRun) + { + LogInfo("Starting SNTP client"); + ComInit(); + Synchronizer.FirstRun = false; + } + + if (Synchronizer.Restart) + { + LogInfo("Restart SNTP client"); + ComInit(); + Synchronizer.Restart = false; + } + + if (SyncClock() == COM_OK) + { + Synchronizer.FailCount = 0; + } + else + { + Synchronizer.FailCount++; + } + + if (Synchronizer.FailCount != 0 && Synchronizer.FailCount % 5 == 0) + { + ComDestroy(); + Synchronizer.Restart = true; + } + + if (Synchronizer.FailCount == 10) + { + LogInfo("Reinitialize socket library"); + ComDestroy(); + CloseSocketLibrary(); + Synchronizer.FailCount = 0; + } +} + +static void ShowStats(void) +{ + if (Synchronizer.SocketOpen) + { + LogDebug("Sending next NTP request in %ld milliseconds", + Settings->Interval); + } + else + { + LogDebug("Retry in %ld milliseconds", Settings->Interval); + } + + Synchronizer.RunCount++; + + if (Synchronizer.RunCount % 10 == 0) + { + ShowLocalTime(); + } + + if (Synchronizer.RunCount % 25 == 0) + { + long blocks, size; + MemUsage(&blocks, &size, NULL); + LogInfo("Currently using %ld bytes in %ld blocks on heap", size, blocks); + } +} + +static void ChooseServer(void) +{ + int i; + char *server = Settings->DestinationAddress; + int len = StrLen(server); + bool isPool = EndsWith(server, POOLSUFFIX) && + !StartsWith(server, "0.") && + !StartsWith(server, "1.") && + !StartsWith(server, "2.") && + !StartsWith(server, "3."); + + if (Synchronizer.ServerName != NULL) + { + FreeMemSafe(Synchronizer.ServerName); + } + + if (Synchronizer.ServerPort != NULL) + { + FreeMemSafe(Synchronizer.ServerPort); + } + + if (!isPool) + { + Synchronizer.ServerName = StrDupSafe(server); + Synchronizer.ServerPort = StrDupSafe(Settings->DestinationPort); + return; + } + + Synchronizer.ServerName = AllocStringSafe(len + 3); + Synchronizer.ServerPort = StrDupSafe(POOLPORT); + + do + { + i = RandomFast() % 4; + } while (i < 0 || i == Synchronizer.PoolServerNumber); + + Synchronizer.PoolServerNumber = i; + SNPrintf(Synchronizer.ServerName, len + 3, "%ld.%s", i, server); + LogWarn("Choosing pool server %s", Synchronizer.ServerName); +} + +static void ComInit(void) +{ + if (Synchronizer.Client != NULL) + { + sntp_destroy(Synchronizer.Client); + Synchronizer.Client = NULL; + } + + ChooseServer(); + Synchronizer.Client = sntp_create( + Synchronizer.ServerName, + Synchronizer.ServerPort, + NULL, + NULL); + + if (Synchronizer.Client == NULL) + { + LogWarn("Could not create SNTP client"); + return; + } +} + +static void UpdateWindow(void) +{ + bool send = false; + struct TimeMessage *message = AllocStructSafe(struct TimeMessage); + + Forbid(); + if (Ports.WindowPort != NULL && Ports.MemoryPort != NULL) + { + message->AppMsg.Msg.mn_Node.ln_Type = NT_MESSAGE; + message->AppMsg.Msg.mn_Length = sizeof(struct TimeMessage); + message->AppMsg.Msg.mn_ReplyPort = Ports.MemoryPort; + message->AppMsg.MsgType = MSGTYPE_TIMEVAL; + message->TimeVal = LastSync; + PutMsg(Ports.WindowPort, (struct Message *)message); + send = true; + } + Permit(); + + if (!send) + { + FreeMemSafe(message); + } +} + +static int SyncClock(void) +{ + struct timeval rtv, ltv, tv; + long long lt, rt, dt, adt, th; + struct ntptime nt; + bool readOnly; + int ret; + int stratum; + + th = Settings->Threshold; + readOnly = Settings->Readonly; + + LogInfo("Sending request to %s:%s", + Synchronizer.ServerName, + Synchronizer.ServerPort); + + ret = sntp_send(Synchronizer.Client); + if (ret != SNTP_OK) + { + LogInfo("SNTP send failed: %s", SntpErrorText(ret)); + if (ret == SNTP_DNSERR || ret == SNTP_SYSERR) + { + Synchronizer.Restart = true; + } + return COM_ERROR; + } + + ret = sntp_poll(Synchronizer.Client, Settings->Timeout); + if (ret != SNTP_OK) + { + LogWarn("SNTP poll failed: %s", SntpErrorText(ret)); + return COM_ERROR; + } + + ret = sntp_recv(Synchronizer.Client, &nt, &stratum); + if (ret != SNTP_OK) + { + LogWarn("SNTP recieve failed: %s", SntpErrorText(ret)); + if (ret == SNTP_BACKOFF) + { + LogWarn("Increasing polling interval: %ld -> %ld", + Settings->Interval, + Settings->Interval * 2); + Settings->Interval *= 2; + } + return COM_ERROR; + } + + nt2tv(&nt, &rtv); + GetTimeOfDay(<v); + + lt = 1000000LL * ltv.tv_secs + ltv.tv_micro; + rt = 1000000LL * rtv.tv_secs + rtv.tv_micro; + dt = rt - lt; + adt = dt < 0 ? -dt : dt; + + if (!readOnly && adt < th) + { + static char out[MAXLONGLONGCHARSIZE]; + static char out2[MAXLONGLONGCHARSIZE]; + LogDebug("Stratum %ld server", (unsigned long)stratum); + LongLongToStr(adt, out); + LongLongToStr(th, out2); + LogInfo("%s us < %s us, not setting clock", out, out2); + } + else if (!readOnly) + { + LogDebug("Stratum %ld server", (unsigned long)stratum); + + tv.tv_secs = rt / 1000000; + tv.tv_micro = rt % 1000000; + SetTimeOfDay(Synchronizer.TimerInfo, &tv); + + { // Log after setting clock + static char out[MAXLONGLONGCHARSIZE]; + static char out2[MAXLONGLONGCHARSIZE]; + LongLongToStr(adt, out); + LongLongToStr(th, out2); + LogWarn("%s us > %s us, setting software clock", out, out2); + if (BattClockBase != NULL) + { + LogWarn("Setting hardware clock"); + SaveTimeOfDay(&tv); + } + } + } + + { + static char out[MAXLONGLONGCHARSIZE]; + LongLongToStr(rt, out); + LogDebug("True time %s", out); + LongLongToStr(lt, out); + LogDebug("Kernel time %s", out); + LongLongToStr(dt, out); + LogDebug("Delta %s", out); + } + + LastSync = rtv; + UpdateWindow(); + CheckTimezone(); + + return COM_OK; +} + +static void CheckTimezone(void) +{ + struct timeval tv; + ULONG now; + + if (NextTransition == NULL) + { + return; + } + + GetSysTime(&tv); + now = (ULONG)(tv.tv_secs); + + if (now > NextTransition->time) + { + char Timezone[TIMEZONE_TEXT_LEN]; + GetTimezoneText(AppLocale, Timezone, OFFSET_IN_PARENS); + ShowLocalTime(); + LogWarn("Current Timezone is %s", Timezone); + LogWarn("Changing Timezone"); + // TODO: Make thread safe + ShowLocalTime(); + InitTimezoneShift(); + SendMessageTo(Ports.WindowPort, Ports.MemoryPort, ATK_TZ_CHANGED); + } +} + +static const char *SntpErrorText(enum sntp_err error) +{ + switch (error) + { + case SNTP_OK: + return "OK"; + case SNTP_SYSERR: + return GetErrorText(); + case SNTP_DNSERR: + return GetHostErrorText(); + case SNTP_NOREQ: + return "No request sent"; + case SNTP_NORESP: + return "No response received"; + case SNTP_BADRESP: + return "Invalid response received"; + case SNTP_LAME: + return "Server is lame / unsynchronized"; + case SNTP_BACKOFF: + return "Polling too frequently"; + default: + return "Unknown error"; + } + return "Unknown error"; +} diff --git a/sync.h b/sync.h new file mode 100644 index 0000000..c65fc08 --- /dev/null +++ b/sync.h @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2017-2020 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. + * + */ + +#ifndef SYNC_H_INCLUDED +#define SYNC_H_INCLUDED + +#include + +void StartSynchronizer(void); + +extern volatile bool SynchronizerRunning; +extern volatile struct timeval LastSync; + +#endif diff --git a/timer.c b/timer.c new file mode 100644 index 0000000..d078dda --- /dev/null +++ b/timer.c @@ -0,0 +1,366 @@ +/*- + * Copyright (c) 2017-2020 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 "ptz.h" +#include "timer.h" +#include "mem.h" +#include "tz.h" + +#include +#include + +#include + +#include "logmod.h" +#define MODULENAME "Timer" + +#define TIMER_ERROR 10 +#define TIMER_OK 0 + +#define TIMER_INTERRUPT_ON 1 +#define TIMER_INTERRUPT_OFF 2 +#define TIMER_INTERRUPT_STOPPED 3 + +struct TimerInfo +{ + bool InterruptTimer; + bool Trigger; + bool Restart; + long TimerFlag; + struct timeval 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; + +// Only one interrupt timer is allowed +struct TimerInfo *InterruptInfo; + +/* + * Set up pointer for timer functions. + */ +struct Device *OpenTimerBase(void) +{ + LONG error; + + TimerIO = AllocStructSafe(struct timerequest); + if (TimerIO == NULL) + { + return NULL; + } + + error = OpenDevice((STRPTR)TIMERNAME, UNIT_MICROHZ, (struct IORequest *)TimerIO, 0); + if (error != 0) + { + FreeMemSafe(TimerIO); + TimerIO = NULL; + return NULL; + } + + TimerBase = TimerIO->tr_node.io_Device; + return TimerBase; +} + +void CloseTimerBase(void) +{ + if (TimerBase != NULL && TimerIO != NULL) + { + CloseDevice((struct IORequest *)TimerIO); + } + + if (TimerIO != NULL) + { + FreeMemSafe(TimerIO); + } +} + +void SetTime(const struct timeval *tv) +{ + assert(tv != NULL); + + // Notice: Method is not thread safe. + TimerIO->tr_node.io_Command = TR_SETSYSTIME; + TimerIO->tr_time.tv_secs = (long)tv->tv_secs; + TimerIO->tr_time.tv_micro = tv->tv_micro; + DoIO((struct IORequest *)TimerIO); +} + +static void TimerInterruptCode(void) +{ + struct TimerInfo *info; + struct timerequest *tr; + + info = InterruptInfo; + tr = (struct timerequest *)GetMsg(info->TimerPort); + + if ((tr) && (info->TimerFlag == TIMER_INTERRUPT_ON)) + { + if (info->Restart) + { + info->Counter = 0; + info->Trigger = false; + info->Restart = false; + tr->tr_time.tv_secs = 1; + tr->tr_time.tv_micro = 0; + } + else if (info->Trigger) + { + Signal(info->InterruptTask, info->InterruptSigBit); + info->Counter = 0; + info->Trigger = false; + tr->tr_time.tv_secs = 1; + tr->tr_time.tv_micro = 0; + } + else + { + info->Counter++; + if (info->Counter == info->Interval.tv_secs) + { + tr->tr_time.tv_secs = 0; + tr->tr_time.tv_micro = info->Interval.tv_micro; + info->Trigger = true; + } + else + { + tr->tr_time.tv_secs = 1; + tr->tr_time.tv_micro = 0; + } + } + + tr->tr_node.io_Command = TR_ADDREQUEST; + BeginIO((struct IORequest *)tr); + } + else + { + info->TimerFlag = TIMER_INTERRUPT_STOPPED; + } +} + +void SetInterruptTimerInterval(struct TimerInfo *info, struct timeval *tv) +{ + info->Interval.tv_secs = tv->tv_secs; + info->Interval.tv_micro = tv->tv_micro; + + if (info->Interval.tv_micro == 0) + { + info->Interval.tv_micro = 2; + } + info->Restart = true; +} + +void StartInterruptTimer(struct TimerInfo *info) +{ + assert(info != NULL); + + if (!info->InterruptTimer) + { + return; + } + + info->TimerFlag = TIMER_INTERRUPT_ON; + info->Trigger = false; + info->Restart = false; + info->TimerIO->tr_node.io_Command = TR_ADDREQUEST; + info->TimerIO->tr_time.tv_secs = 1; + info->TimerIO->tr_time.tv_micro = 0; + BeginIO((struct IORequest *)info->TimerIO); +} + +/* + * Create a Timer device software interrupt as described 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 *CreateInterruptTimer(struct Task *task, short sigBit) +{ + LONG error; + struct TimerInfo *info = AllocStructSafe(struct TimerInfo); + if (info == NULL) + return NULL; + + info->InterruptTimer = true; + info->InterruptTask = task; + info->InterruptSigBit = 1 << sigBit; + + info->TimerPort = AllocStructSafe(struct MsgPort); + if (info->TimerPort == NULL) + { + DeleteTimer(info); + return NULL; + } + + info->TimerInterrupt = AllocStructSafe(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"; + struct TimerInfo *info = AllocStructSafe(struct TimerInfo); + if (info == NULL) + return NULL; + + info->TimerPort = CreateMsgPort(); + if (info->TimerPort == NULL) + { + DeleteTimer(info); + return NULL; + } + + info->TimerPort->mp_Node.ln_Name = (char *)name; + info->TimerPort->mp_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; + } + + return info; +} + +void DeleteTimer(struct TimerInfo *info) +{ + if (info == NULL) + { + return; + } + + if (info->TimerIO != NULL) + { + if (info->TimerInterrupt) + { + info->TimerFlag = TIMER_INTERRUPT_OFF; + while (info->TimerFlag != TIMER_INTERRUPT_STOPPED) + { + Delay(10); + } + } + else + { + if (!(CheckIO((struct IORequest *)info->TimerIO))) + { + AbortIO((struct IORequest *)info->TimerIO); + } + WaitIO((struct IORequest *)info->TimerIO); + } + + CloseDevice((struct IORequest *)info->TimerIO); + DeleteExtIO((struct IORequest *)info->TimerIO); + info->TimerIO = NULL; + } + + if (info->TimerPort != NULL) + { + if (info->InterruptTimer) + { + FreeMemSafe(info->TimerPort); + } + else + { + DeleteMsgPort(info->TimerPort); + } + } + + if (info->TimerInterrupt != NULL) + { + FreeMemSafe(info->TimerInterrupt); + } + + FreeMemSafe(info); +} + +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/timer.h b/timer.h new file mode 100644 index 0000000..fae8801 --- /dev/null +++ b/timer.h @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2017-2020 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. + * + */ + +#ifndef TIME_H_INCLUDED +#define TIME_H_INCLUDED + +#include "config.h" + +struct TimerInfo; + +struct Device *OpenTimerBase(void); +void CloseTimerBase(void); +struct TimerInfo *CreateTimer(void); +struct TimerInfo *CreateInterruptTimer(struct Task *, short); +void StartInterruptTimer(struct TimerInfo *); +void SetInterruptTimerInterval(struct TimerInfo *, struct timeval *); +void DeleteTimer(struct TimerInfo *); +void SetTime(const struct timeval *); +void SeedRandom(void); +int RandomFast(void); + +#endif diff --git a/tz.c b/tz.c new file mode 100644 index 0000000..a86f6dd --- /dev/null +++ b/tz.c @@ -0,0 +1,297 @@ +/*- + * Copyright (c) 2017-2020 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 "notify.h" +#include "global.h" +#include "message.h" +#include "ptz.h" +#include "timer.h" +#include "mem.h" +#include "tz.h" + +#include + +#include "logmod.h" +#define MODULENAME "Timezone" + +/* + * 2922 is the number of days between 1.1.1970 and 1.1.1978 + * (2 leap years and 6 normal) + * 2922 * 24 * 60 * 60 = 252460800 + */ +#define AMIGA_OFFSET 252460800 +#define SECONDSPERDAY 86400 + +static long unixEpochOffset = 0; + +void LogTzInfo() +{ + if (Timezone == NULL) + { + return; + } + + if (Timezone->dst.abbreviation != NULL) + { + LogInfo("Standard Timezone is %s (UTC%s%02ld:%02ld)", + Timezone->std.abbreviation, + PosixTimezoneSignChar(&Timezone->std), + (long)Timezone->std.offset.hours, + (long)Timezone->std.offset.minutes); + + LogInfo("DST Timezone is %s (UTC%s%02ld:%02ld)", + Timezone->dst.abbreviation, + PosixTimezoneSignChar(&Timezone->dst), + (long)Timezone->dst.offset.hours, + (long)Timezone->dst.offset.minutes); + } + else + { + LogInfo("Timezone is %s (UTC%s%02ld:%02ld)", + Timezone->std.abbreviation, + PosixTimezoneSignChar(&Timezone->std), + (long)Timezone->std.offset.hours, + (long)Timezone->std.offset.minutes); + } +} + +void InitTimezone(void) +{ + char TimezoneText[TIMEZONE_TEXT_LEN]; + char *tz; + int result; + + WatchFile("ENV:TZ", ATK_TZ_CHANGED); + WatchFile("ENV:TZONE", ATK_TZONE_CHANGED); + WatchFile("ENV:Sys/locale.prefs", ATK_LOCALE_CHANGED); + + tz = NULL; + result = InitPosixTimezone(&tz); + switch (result) + { + case 1: + LogInfo("No TZ or TZONE variable found"); + break; + case 2: + LogInfo("Found unknown TZONE variable"); + LogDebug("TZONE = %s", tz); + break; + case 3: + LogInfo("Found unknown TZ variable"); + LogDebug("TZ = %s", tz); + break; + case 4: + LogInfo("Found valid TZONE variable"); + LogDebug("TZONE = %s", tz); + break; + case 5: + LogInfo("Found valid TZ variable"); + LogDebug("TZ = %s", tz); + break; + default: + LogWarn("Unknown TZ or TZONE code"); + break; + } + + if (tz != NULL) + { + FreeMemSafe(tz); + } + + if (result == 4 || result == 5) + { + struct timeval tv; + GetSysTime(&tv); + SetPosixTimezone(&tv); + LogTzInfo(); + unixEpochOffset = + (Timezone->current.offset.sign < 0 ? +1 : -1) * + (Timezone->current.offset.hours * 60 * 60 + + Timezone->current.offset.minutes * 60 + + Timezone->current.offset.seconds); + unixEpochOffset += AMIGA_OFFSET; + GetTimezoneText(AppLocale, TimezoneText, OFFSET_IN_PARENS); + LogWarn("Current Timezone is %s", TimezoneText); + } + else + { + unixEpochOffset = AppLocale->AmigaLocale->loc_GMTOffset * 60 + AMIGA_OFFSET; + GetTimezoneText(AppLocale, TimezoneText, OFFSET_IN_PARENS); + LogWarn("Current Timezone is %s", TimezoneText); + } + + InitTimezoneShift(); +} + +void Amiga2DateStamp(time_t *time, struct DateStamp *date) +{ + long t, d, m, q; + + t = *time; + d = t / SECONDSPERDAY; + m = (t - SECONDSPERDAY * d) / 60; + q = (t - SECONDSPERDAY * d - m * 60) * 60; + + date->ds_Days = d; + date->ds_Minute = m; + date->ds_Tick = q; +} + +void InitTimezoneShift(void) +{ + struct PosixTransitionTime *transition; + struct timeval tv; + char *nextTime; + char *nextTrans; + time_t next; + ULONG now; + + if (Timezone == NULL || Timezone->start.type == 0) + { + NextTransition = NULL; + return; + } + + /* + { + int i; + for (i = 0; i < 138; i++) + { + transition = &Timezone->transitions[i]; + next = transition->time; + Amiga2DateStamp(&next, &ds); + DateTimeString(&ds, timeString, dateString, dayString); + LogWarn("XChanging (%ld) to %s time on %s %s at %s %s", + next, + transition->isdst ? "DST" : "standard", + dayString, dateString, timeString, + transition->isdst + ? Timezone->std.abbreviation + : Timezone->dst.abbreviation); + } + } + */ + + GetSysTime(&tv); + now = (ULONG)(tv.tv_secs); + transition = FindNextTransition(now); + + if (transition == NULL) + { + NextTransition = NULL; + return; + } + + if (NextTransition != NULL) + { + FreeMemSafe(NextTransition); + } + + NextTransition = transition; + next = transition->time; + + nextTime = GetTimeText(AppLocale, next); + nextTrans = transition->isdst ? "DST" : "standard time"; + LogWarn("Changing to %s on %s", nextTrans, nextTime); + FreeMemSafe(nextTime); +} + +void CleanupTimezone(void) +{ + CleanupPosixTimezone(); +} + +void Unix2Amiga(struct timeval *unix, struct timeval *tv) +{ + assert(unix != NULL); + assert(tv != NULL); + + tv->tv_secs = unix->tv_secs + AMIGA_OFFSET; + tv->tv_micro = unix->tv_micro; +} + +void Utc2Local(struct timeval *utc, struct timeval *tv) +{ + assert(utc != NULL); + assert(tv != NULL); + + // TODO: Validate + tv->tv_secs = utc->tv_secs - (unixEpochOffset - AMIGA_OFFSET); + tv->tv_micro = utc->tv_micro; +} + +void GetTimeOfDay(struct timeval *tv) +{ + assert(tv != NULL); + + GetSysTime(tv); + tv->tv_secs = tv->tv_secs + unixEpochOffset; +} + +void GetLocalTimeOfDay(struct timeval *tv) +{ + assert(tv != NULL); + + GetSysTime(tv); +} + +void SetTimeOfDay(const struct TimerInfo *info, const struct timeval *tv) +{ + struct timeval t; + + assert(tv != NULL); + + t.tv_secs = tv->tv_secs - unixEpochOffset; + t.tv_micro = tv->tv_micro; + SetTime(&t); +} + +void SaveTimeOfDay(const struct timeval *tv) +{ + assert(tv != NULL); + + WriteBattClock((long)tv->tv_secs - unixEpochOffset); +} + +void DateTimeString(struct DateStamp *ds, char *time, char *date, char *day) +{ + struct DateTime dt; + + assert(ds != NULL); + assert(time != NULL); + assert(date != NULL); + assert(day != NULL); + + dt.dat_Stamp = *ds; + dt.dat_Format = FORMAT_DOS; + dt.dat_Flags = 0; + dt.dat_StrDay = (void *)day; + dt.dat_StrDate = (void *)date; + dt.dat_StrTime = (void *)time; + + DateToStr(&dt); +} diff --git a/tz.h b/tz.h new file mode 100644 index 0000000..ea74d22 --- /dev/null +++ b/tz.h @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2017-2020 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. + * + */ + +#ifndef TZ_H_INCLUDED +#define TZ_H_INCLUDED + +#include "config.h" +#include "timer.h" + +void InitTimezone(void); +void InitTimezoneShift(void); +void CleanupTimezone(void); +void GetTimeOfDay(struct timeval *); +void SetTimeOfDay(const struct TimerInfo *, const struct timeval *); +void SaveTimeOfDay(const struct timeval *); +void GetLocalTimeOfDay(struct timeval *); +void Unix2Amiga(struct timeval *, struct timeval *); +void Utc2Local(struct timeval *, struct timeval *t); + +#endif diff --git a/val.c b/val.c index fa1cee2..d38e769 100644 --- a/val.c +++ b/val.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,163 +21,115 @@ * 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 "setting.h" #include "log.h" -#include + +#include "logmod.h" +#define MODULENAME "Validation" 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) + if (Settings->Interval < INTERVAL_MIN) { - LogValidation(settingTooLow, - SettingKeys->Interval, - INTERVAL_MIN); - LogValidation(settingChangedLong, - SettingKeys->Interval, - Globals->Settings->Interval, - INTERVAL_MIN); - Globals->Settings->Interval = INTERVAL_MIN; + LogInfo(settingTooLow, + SettingKeys->Interval, + INTERVAL_MIN); + LogInfo(settingChangedLong, + SettingKeys->Interval, + Settings->Interval, + INTERVAL_MIN); + Settings->Interval = INTERVAL_MIN; } } static void ValidateTimeout(void) { - if (Globals->Settings->Timeout < TIMEOUT_MIN) + if (Settings->Timeout < TIMEOUT_MIN) { - LogValidation(settingTooLow, - SettingKeys->Timeout, - TIMEOUT_MIN); - LogValidation(settingChangedLong, - SettingKeys->Timeout, - Globals->Settings->Timeout, - TIMEOUT_MIN); - Globals->Settings->Timeout = TIMEOUT_MIN; + LogInfo(settingTooLow, + SettingKeys->Timeout, + TIMEOUT_MIN); + LogInfo(settingChangedLong, + SettingKeys->Timeout, + Settings->Timeout, + TIMEOUT_MIN); + Settings->Timeout = TIMEOUT_MIN; } - if (Globals->Settings->Timeout > Globals->Settings->Interval / 2) + if (Settings->Timeout > 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; + LogInfo(settingGreaterThan, + SettingKeys->Timeout, + SettingKeys->Interval); + LogInfo(settingChangedLong, + SettingKeys->Timeout, + Settings->Timeout, + Settings->Interval / 2); + Settings->Timeout = Settings->Interval / 2; } - if (Globals->Settings->Timeout > TIMEOUT_MAX) + if (Settings->Timeout > TIMEOUT_MAX) { - LogValidation(settingTooHigh, - SettingKeys->Timeout, - TIMEOUT_MAX); - LogValidation(settingChangedLong, - SettingKeys->Timeout, - Globals->Settings->Timeout, - TIMEOUT_MAX); - Globals->Settings->Timeout = TIMEOUT_MAX; + LogInfo(settingTooHigh, + SettingKeys->Timeout, + TIMEOUT_MAX); + LogInfo(settingChangedLong, + SettingKeys->Timeout, + Settings->Timeout, + TIMEOUT_MAX); + Settings->Timeout = TIMEOUT_MAX; } } static void ValidatePriority(void) { - if (Globals->Settings->Priority < PRIORITY_MIN) + if (Settings->Priority < PRIORITY_MIN) { - LogValidation(settingTooLow, - SettingKeys->Priority, - PRIORITY_MIN); - LogValidation(settingChangedLong, - SettingKeys->Priority, - Globals->Settings->Priority, - PRIORITY_MIN); - Globals->Settings->Priority = PRIORITY_MIN; + LogInfo(settingTooLow, + SettingKeys->Priority, + PRIORITY_MIN); + LogInfo(settingChangedLong, + SettingKeys->Priority, + Settings->Priority, + PRIORITY_MIN); + Settings->Priority = PRIORITY_MIN; } - if (Globals->Settings->Priority > PRIORITY_MAX) + if (Settings->Priority > PRIORITY_MAX) { - LogValidation(settingTooHigh, - SettingKeys->Priority, - PRIORITY_MAX); - LogValidation(settingChangedLong, - SettingKeys->Priority, - Globals->Settings->Priority, - PRIORITY_MAX); - Globals->Settings->Priority = PRIORITY_MAX; + LogInfo(settingTooHigh, + SettingKeys->Priority, + PRIORITY_MAX); + LogInfo(settingChangedLong, + SettingKeys->Priority, + Settings->Priority, + PRIORITY_MAX); + Settings->Priority = PRIORITY_MAX; } } static void ValidateThreshold(void) { - if (Globals->Settings->Threshold < THRESHOLD_MIN) + if (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; + LogInfo(settingTooLow, + SettingKeys->Threshold, + THRESHOLD_MIN); + LogInfo(settingChangedLong, + SettingKeys->Threshold, + Settings->Threshold, + THRESHOLD_MIN); + Settings->Threshold = THRESHOLD_MIN; } } @@ -187,5 +139,4 @@ void SanitizeSettings(void) ValidateTimeout(); ValidatePriority(); ValidateThreshold(); - ValidateVerbose(); } diff --git a/win.h b/win.h index 10dea53..b915c1d 100644 --- a/win.h +++ b/win.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -21,15 +21,15 @@ * 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. - * + * */ #ifndef WIN_H_INCLUDED #define WIN_H_INCLUDED +#include #include #include -#include #include #define GID_SERVER 1001 @@ -37,17 +37,28 @@ #define GID_TIMEOUT 1003 #define GID_INTERVAL 1004 #define GID_THRESHOLD 1005 -#define GID_VERBOSE 1006 -#define GID_READONLY 1007 -#define GID_PRIORITY 1008 -#define GID_SAVE 1009 -#define GID_USE 1010 -#define GID_CANCEL 1011 +#define GID_READONLY 1006 +#define GID_PRIORITY 1007 +#define GID_SAVE 1008 +#define GID_USE 1009 +#define GID_CANCEL 1010 + +struct AppSettingWindow +{ + struct Screen *Screen; + struct Window *Window; + struct Gadget *GadgetList; + void *VisualInfo; + char *PriorityText; + char *ThresholdText; + char *TimezoneText; + long Width; + long Height; + struct AppSettingWindowGadgets *Gadgets; +}; /* win_main.c */ void ShowSettingWindow(void); -void HideSettingWindow(void); -bool CheckSettingWindowClosed(void); /* win_gad.c */ bool CreateGadgets(void); @@ -57,9 +68,13 @@ void SetPort(void); void SetTimeout(void); void SetInterval(void); void SetThreshold(void); -void SetVerbose(void); void SetCxPriority(void); -void ShowLastSync(void); +void ShowLastSync(struct timeval *tv); void SetDefaultSettings(void); +void ShowNewTimezone(void); + +extern volatile bool WindowProcRunning; +extern struct AppSettings *WindowSettings; +extern struct AppSettingWindow SettingWindow; #endif diff --git a/win_gad.c b/win_gad.c index 87a6363..84d93e9 100644 --- a/win_gad.c +++ b/win_gad.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,11 +25,16 @@ */ #include "config.h" +#include "global.h" #include "message.h" -#include "state.h" -#include "time.h" +#include "setting.h" +#include "timer.h" #include "mem.h" #include "win.h" +#include "tz.h" + +#include "logmod.h" +#define MODULENAME "Window" struct AppSettingWindowGadgets { @@ -38,9 +43,8 @@ struct AppSettingWindowGadgets struct Gadget *TimeoutGadget; struct Gadget *IntervalGadget; struct Gadget *ThresholdGadget; - struct Gadget *VerboseGadget; struct Gadget *PriorityGadget; - struct Gadget *TimeZoneGadget; + struct Gadget *TimezoneGadget; struct Gadget *LastSyncGadget; }; @@ -49,9 +53,8 @@ static const char *portLabel = "Server port"; static const char *timeoutLabel = "Timeout (ms)"; static const char *intervalLabel = "Interval (ms)"; static const char *thresholdLabel = "Threshold (us)"; -static const char *verboseLabel = "Verbose level"; static const char *priorityLabel = "CX priority"; -static const char *timeZoneLabel = "Time zone"; +static const char *TimezoneLabel = "Time zone"; static const char *lastSyncLabel = "Last sync"; static const char *saveLabel = "Save"; static const char *useLabel = "Use"; @@ -63,19 +66,11 @@ static const char **textLabels[] = { &timeoutLabel, &intervalLabel, &thresholdLabel, - &verboseLabel, &priorityLabel, - &timeZoneLabel, + &TimezoneLabel, &lastSyncLabel, NULL}; -static char *verboseLevel[] = { - "Show none (0)", - "Show some (1)", - "Show more (2)", - "Show all (3)", - NULL}; - int GetLabelWidth(struct RastPort *rp) { int len, max = 0; @@ -85,7 +80,7 @@ int GetLabelWidth(struct RastPort *rp) while (**label != NULL) { c = StrLen(*label); - len = TextLength(rp, *label, c); + len = TextLength(rp, (CONST_STRPTR)*label, c); if (len > max) { max = len; @@ -108,29 +103,27 @@ bool CreateGadgets(void) long labelId; long tmp1, tmp2; - Globals->Window->Gadgets = (struct AppSettingWindowGadgets *) - AllocMemSafe(sizeof(struct AppSettingWindowGadgets)); - - ng = (struct NewGadget *)AllocMemSafe(sizeof(struct NewGadget)); + SettingWindow.Gadgets = AllocStructSafe(struct AppSettingWindowGadgets); + ng = AllocStructSafe(struct NewGadget); if (!ng) return false; - gadget = CreateContext(&Globals->Window->GadgetList); + gadget = CreateContext(&SettingWindow.GadgetList); if (!gadget) return false; - ng->ng_VisualInfo = Globals->Window->VisualInfo; - ng->ng_TextAttr = Globals->Window->Screen->Font; + ng->ng_VisualInfo = SettingWindow.VisualInfo; + ng->ng_TextAttr = SettingWindow.Screen->Font; ng->ng_Flags = 0; - h = Globals->Window->Screen->RastPort.TxHeight; - x = Globals->Window->Screen->WBorLeft + 8; - y = Globals->Window->Screen->WBorTop + h + 9; + h = SettingWindow.Screen->RastPort.TxHeight; + x = SettingWindow.Screen->WBorLeft + 8; + y = SettingWindow.Screen->WBorTop + h + 9; - labelWidth = GetLabelWidth(&Globals->Window->Screen->RastPort); + labelWidth = GetLabelWidth(&SettingWindow.Screen->RastPort); col1 = x; - textWidth = labelWidth + Globals->Window->Screen->RastPort.TxWidth / 2; + textWidth = labelWidth + SettingWindow.Screen->RastPort.TxWidth / 2; col2 = col1 + textWidth; boxWidth = labelWidth; @@ -156,14 +149,14 @@ bool CreateGadgets(void) ng->ng_GadgetID = GID_SERVER; gadget = CreateGadget( STRING_KIND, gadget, ng, - GTST_String, (IPTR)Globals->Settings->DestinationAddress, + GTST_String, (IPTR)Settings->DestinationAddress, TAG_END); if (!gadget) return false; - Globals->Window->Gadgets->ServerGadget = gadget; + SettingWindow.Gadgets->ServerGadget = gadget; - if (Globals->Settings->Expert) + if (Settings->Expert) { // Port ng->ng_LeftEdge = col1; @@ -182,12 +175,12 @@ bool CreateGadgets(void) ng->ng_GadgetID = GID_PORT; gadget = CreateGadget( STRING_KIND, gadget, ng, - GTST_String, (IPTR)Globals->Settings->DestinationPort, + GTST_String, (IPTR)Settings->DestinationPort, TAG_END); if (!gadget) return false; - Globals->Window->Gadgets->PortGadget = gadget; + SettingWindow.Gadgets->PortGadget = gadget; // Interval ng->ng_LeftEdge = col1; @@ -208,13 +201,13 @@ bool CreateGadgets(void) gadget = CreateGadget( INTEGER_KIND, gadget, ng, GTNM_MaxNumberLen, 8, - GTIN_Number, Globals->Settings->Interval, + GTIN_Number, Settings->Interval, TAG_END); if (!gadget) return false; gadget->Flags |= GFLG_TABCYCLE; - Globals->Window->Gadgets->IntervalGadget = gadget; + SettingWindow.Gadgets->IntervalGadget = gadget; // Timeout ng->ng_LeftEdge = col1; @@ -234,13 +227,13 @@ bool CreateGadgets(void) gadget = CreateGadget( INTEGER_KIND, gadget, ng, GTNM_MaxNumberLen, 8, - GTIN_Number, Globals->Settings->Timeout, + GTIN_Number, Settings->Timeout, TAG_END); if (!gadget) return false; gadget->Flags |= GFLG_TABCYCLE; - Globals->Window->Gadgets->TimeoutGadget = gadget; + SettingWindow.Gadgets->TimeoutGadget = gadget; // Threshold ng->ng_LeftEdge = col1; @@ -259,39 +252,13 @@ bool CreateGadgets(void) ng->ng_GadgetID = GID_THRESHOLD; gadget = CreateGadget( STRING_KIND, gadget, ng, - GTST_String, (IPTR)Globals->Window->ThresholdText, + GTST_String, (IPTR)SettingWindow.ThresholdText, TAG_END); if (!gadget) return false; gadget->Flags |= GFLG_TABCYCLE; - Globals->Window->Gadgets->ThresholdGadget = gadget; - - // Verbose - ng->ng_LeftEdge = col1; - ng->ng_TopEdge += ng->ng_Height + 4; - ng->ng_Width = textWidth; - ng->ng_GadgetID = labelId++; - gadget = CreateGadget( - TEXT_KIND, gadget, ng, - GTTX_Text, (IPTR)verboseLabel, - TAG_END); - if (!gadget) - return false; - - ng->ng_LeftEdge = col2; - ng->ng_Width = boxWidth + 20; - ng->ng_GadgetID = GID_VERBOSE; - gadget = CreateGadget( - CYCLE_KIND, gadget, ng, - GTCY_Labels, (IPTR)verboseLevel, - GTCY_Active, Globals->Settings->Verbose, - TAG_END); - if (!gadget) - return false; - - gadget->Flags |= GFLG_TABCYCLE; - Globals->Window->Gadgets->VerboseGadget = gadget; + SettingWindow.Gadgets->ThresholdGadget = gadget; // Priority ng->ng_LeftEdge = col1; @@ -311,13 +278,13 @@ bool CreateGadgets(void) gadget = CreateGadget( STRING_KIND, gadget, ng, - GTST_String, (IPTR)Globals->Window->PriorityText, + GTST_String, (IPTR)SettingWindow.PriorityText, TAG_END); if (!gadget) return false; gadget->Flags |= GFLG_TABCYCLE; - Globals->Window->Gadgets->PriorityGadget = gadget; + SettingWindow.Gadgets->PriorityGadget = gadget; } // Time zone @@ -327,7 +294,7 @@ bool CreateGadgets(void) ng->ng_GadgetID = labelId++; gadget = CreateGadget( TEXT_KIND, gadget, ng, - GTTX_Text, (IPTR)timeZoneLabel, + GTTX_Text, (IPTR)TimezoneLabel, TAG_END); if (!gadget) return false; @@ -337,12 +304,12 @@ bool CreateGadgets(void) ng->ng_GadgetID = labelId++; gadget = CreateGadget( TEXT_KIND, gadget, ng, - GTTX_Text, (IPTR)Globals->Window->TimeZoneText, + GTTX_Text, (IPTR)SettingWindow.TimezoneText, TAG_END); if (!gadget) return false; - Globals->Window->Gadgets->TimeZoneGadget = gadget; + SettingWindow.Gadgets->TimezoneGadget = gadget; // Last sync ng->ng_LeftEdge = col1; @@ -365,7 +332,7 @@ bool CreateGadgets(void) if (!gadget) return false; - Globals->Window->Gadgets->LastSyncGadget = gadget; + SettingWindow.Gadgets->LastSyncGadget = gadget; tmp1 = ng->ng_LeftEdge + ng->ng_Width - 18; // Why is this 18? tmp2 = tmp1 / 3; @@ -394,10 +361,10 @@ bool CreateGadgets(void) if (!gadget) return false; - Globals->Window->Height = ng->ng_TopEdge + ng->ng_Height; - Globals->Window->Width = textWidth + boxWidth; + SettingWindow.Height = ng->ng_TopEdge + ng->ng_Height; + SettingWindow.Width = textWidth + boxWidth; - FreeMemSafe(ng, __FUNCTION__); + FreeMemSafe(ng); return true; } @@ -405,7 +372,7 @@ static char *BuildLogText(const char *setting, char *oldValue, char *newValue) { static const char *txt1 = " changed: "; static const char *txt2 = " -> "; - char *p = AllocMemSafe(SETTINGMESSAGELEN); + char *p = AllocStringSafe(LOGMESSAGELEN); char *s = p; p = AppendText(p, (char *)setting); p = AppendText(p, (char *)txt1); @@ -417,12 +384,12 @@ static char *BuildLogText(const char *setting, char *oldValue, char *newValue) void UseSettings(void) { + LogInfo("Apply new settings"); SetServer(); SetPort(); SetInterval(); SetTimeout(); SetThreshold(); - SetVerbose(); SetCxPriority(); } @@ -431,21 +398,21 @@ void SetServer(void) char *server, *text; GT_GetGadgetAttrs( - Globals->Window->Gadgets->ServerGadget, - Globals->Window->SettingWindow, NULL, + SettingWindow.Gadgets->ServerGadget, + SettingWindow.Window, NULL, GTST_String, (IPTR)&server, TAG_END); - if (Stricmp((STRPTR)server, (STRPTR)Globals->Settings->DestinationAddress) == 0) + if (Stricmp((STRPTR)server, (STRPTR)Settings->DestinationAddress) == 0) return; text = BuildLogText(SettingKeys->DestinationAddress, - Globals->Settings->DestinationAddress, + Settings->DestinationAddress, server); - FreeMemSafe(Globals->Settings->DestinationAddress, __FUNCTION__); - Globals->Settings->DestinationAddress = StrDupSafe(server); - SendInfoMessage(text); - FreeMemSafe(text, __FUNCTION__); + FreeMemSafe(Settings->DestinationAddress); + Settings->DestinationAddress = StrDupSafe(server); + LogInfo(text); + FreeMemSafe(text); SendMessage(ATK_RESTART); } @@ -453,25 +420,25 @@ void SetPort(void) { char *port, *text; - if (Globals->Window->Gadgets->PortGadget == NULL) + if (SettingWindow.Gadgets->PortGadget == NULL) return; GT_GetGadgetAttrs( - Globals->Window->Gadgets->PortGadget, - Globals->Window->SettingWindow, NULL, + SettingWindow.Gadgets->PortGadget, + SettingWindow.Window, NULL, GTST_String, (IPTR)&port, TAG_END); - if (Stricmp((STRPTR)port, (STRPTR)Globals->Settings->DestinationPort) == 0) + if (Stricmp((STRPTR)port, (STRPTR)Settings->DestinationPort) == 0) return; text = BuildLogText(SettingKeys->DestinationPort, - Globals->Settings->DestinationPort, + Settings->DestinationPort, port); - FreeMemSafe(Globals->Settings->DestinationPort, __FUNCTION__); - Globals->Settings->DestinationPort = StrDupSafe(port); - SendInfoMessage(text); - FreeMemSafe(text, __FUNCTION__); + FreeMemSafe(Settings->DestinationPort); + Settings->DestinationPort = StrDupSafe(port); + LogInfo(text); + FreeMemSafe(text); SendMessage(ATK_RESTART); } @@ -479,27 +446,27 @@ void SetInterval(void) { unsigned long value; - if (Globals->Window->Gadgets->IntervalGadget == NULL) + if (SettingWindow.Gadgets->IntervalGadget == NULL) return; GT_GetGadgetAttrs( - Globals->Window->Gadgets->IntervalGadget, - Globals->Window->SettingWindow, NULL, + SettingWindow.Gadgets->IntervalGadget, + SettingWindow.Window, NULL, GTIN_Number, (IPTR)&value, TAG_END); - if (Globals->Settings->Interval != value) + if (Settings->Interval != value) { char *text; char newValue[MAXLONGCHARSIZE]; char oldValue[MAXLONGCHARSIZE]; - LongToStr(Globals->Settings->Interval, oldValue); + LongToStr(Settings->Interval, oldValue); LongToStr(value, newValue); - Globals->Settings->Interval = value; + Settings->Interval = value; text = BuildLogText(SettingKeys->Interval, oldValue, newValue); - SendInfoMessage(text); - FreeMemSafe(text, __FUNCTION__); + LogInfo(text); + FreeMemSafe(text); SendMessage(ATK_RESTART); SanitizeSettings(); } @@ -509,27 +476,27 @@ void SetTimeout(void) { unsigned long value; - if (Globals->Window->Gadgets->TimeoutGadget == NULL) + if (SettingWindow.Gadgets->TimeoutGadget == NULL) return; GT_GetGadgetAttrs( - Globals->Window->Gadgets->TimeoutGadget, - Globals->Window->SettingWindow, NULL, + SettingWindow.Gadgets->TimeoutGadget, + SettingWindow.Window, NULL, GTIN_Number, (IPTR)&value, TAG_END); - if (Globals->Settings->Timeout != value) + if (Settings->Timeout != value) { char *text; char newValue[MAXLONGCHARSIZE]; char oldValue[MAXLONGCHARSIZE]; - LongToStr(Globals->Settings->Timeout, oldValue); + LongToStr(Settings->Timeout, oldValue); LongToStr(value, newValue); - Globals->Settings->Timeout = value; + Settings->Timeout = value; text = BuildLogText(SettingKeys->Timeout, oldValue, newValue); - SendInfoMessage(text); - FreeMemSafe(text, __FUNCTION__); + LogInfo(text); + FreeMemSafe(text); SendMessage(ATK_RESTART); SanitizeSettings(); } @@ -541,74 +508,45 @@ void SetThreshold(void) char *tempString; int result; - if (Globals->Window->Gadgets->ThresholdGadget == NULL) + if (SettingWindow.Gadgets->ThresholdGadget == NULL) return; GT_GetGadgetAttrs( - Globals->Window->Gadgets->ThresholdGadget, - Globals->Window->SettingWindow, NULL, + SettingWindow.Gadgets->ThresholdGadget, + SettingWindow.Window, NULL, GTST_String, (IPTR)&tempString, TAG_END); result = StrToLongLong(tempString, &value); - if (result != -1 && Globals->Settings->Threshold != value) + if (result != -1 && Settings->Threshold != value) { char *text; char newValue[MAXLONGLONGCHARSIZE]; char oldValue[MAXLONGLONGCHARSIZE]; - LongLongToStr(Globals->Settings->Threshold, oldValue); + LongLongToStr(Settings->Threshold, oldValue); LongLongToStr(value, newValue); - Globals->Settings->Threshold = value; + Settings->Threshold = value; text = BuildLogText(SettingKeys->Threshold, oldValue, newValue); - SendInfoMessage(text); - FreeMemSafe(text, __FUNCTION__); + LogInfo(text); + FreeMemSafe(text); SendMessage(ATK_RESTART); SanitizeSettings(); } } -void SetVerbose(void) -{ - long value; - - if (Globals->Window->Gadgets->VerboseGadget == NULL) - return; - - GT_GetGadgetAttrs( - Globals->Window->Gadgets->VerboseGadget, - Globals->Window->SettingWindow, NULL, - GTCY_Active, (IPTR)&value, - TAG_END); - - if (Globals->Settings->Verbose != value) - { - char *text; - char newValue[MAXLONGCHARSIZE]; - char oldValue[MAXLONGCHARSIZE]; - - LongToStr(Globals->Settings->Verbose, oldValue); - LongToStr(value, newValue); - text = BuildLogText(SettingKeys->Verbose, oldValue, newValue); - SendInfoMessage(text); - FreeMemSafe(text, __FUNCTION__); - Globals->Settings->Verbose = value; - SanitizeSettings(); - } -} - void SetCxPriority(void) { LONG value; char *tempString; int result; - if (Globals->Window->Gadgets->PriorityGadget == NULL) + if (SettingWindow.Gadgets->PriorityGadget == NULL) return; GT_GetGadgetAttrs( - Globals->Window->Gadgets->PriorityGadget, - Globals->Window->SettingWindow, NULL, + SettingWindow.Gadgets->PriorityGadget, + SettingWindow.Window, NULL, GTST_String, (IPTR)&tempString, TAG_END); @@ -620,24 +558,24 @@ void SetCxPriority(void) else if (value > PRIORITY_MAX) value = PRIORITY_MAX; - if (Globals->Settings->Priority != value) + if (Settings->Priority != value) { char *text; char newValue[MAXLONGCHARSIZE]; char oldValue[MAXLONGCHARSIZE]; - LongToStr(Globals->Settings->Priority, oldValue); + LongToStr(Settings->Priority, oldValue); LongToStr(value, newValue); - Globals->Settings->Priority = value; + Settings->Priority = value; text = BuildLogText(SettingKeys->Priority, oldValue, newValue); SetBrokerPriority(value); - SendInfoMessage(text); - FreeMemSafe(text, __FUNCTION__); + LogInfo(text); + FreeMemSafe(text); } } } -void ShowLastSync(void) +void ShowLastSync(struct timeval *tv) { static char label[10]; struct timeval nowLocal, last, lastLocal; @@ -651,12 +589,12 @@ void ShowLastSync(void) .dat_StrTime = (STRPTR)label}; long seconds; - if (Globals->LastNtpSync.tv_secs == 0) + if (tv->tv_secs == 0) { static const char *never = "Not synced yet"; GT_SetGadgetAttrs( - Globals->Window->Gadgets->LastSyncGadget, - Globals->Window->SettingWindow, NULL, + SettingWindow.Gadgets->LastSyncGadget, + SettingWindow.Window, NULL, GTTX_Text, (IPTR)never, TAG_END); @@ -664,7 +602,7 @@ void ShowLastSync(void) } GetLocalTimeOfDay(&nowLocal); - Unix2Amiga(&Globals->LastNtpSync, &last); + Unix2Amiga(tv, &last); Utc2Local(&last, &lastLocal); seconds = nowLocal.tv_secs - lastLocal.tv_secs; @@ -672,8 +610,8 @@ void ShowLastSync(void) { static const char *tooOld = "> 24 hours"; GT_SetGadgetAttrs( - Globals->Window->Gadgets->LastSyncGadget, - Globals->Window->SettingWindow, NULL, + SettingWindow.Gadgets->LastSyncGadget, + SettingWindow.Window, NULL, GTTX_Text, (IPTR)tooOld, TAG_END); @@ -686,8 +624,24 @@ void ShowLastSync(void) DateToStr(&dateTime); GT_SetGadgetAttrs( - Globals->Window->Gadgets->LastSyncGadget, - Globals->Window->SettingWindow, NULL, + SettingWindow.Gadgets->LastSyncGadget, + SettingWindow.Window, NULL, GTTX_Text, (IPTR)label, TAG_END); } + +void ShowNewTimezone(void) +{ + char *temp = SettingWindow.TimezoneText; + char *new = AllocStringSafe(TIMEZONE_TEXT_LEN); + + GetTimezoneText(AppLocale, new, ZONE_IN_PARENS); + GT_SetGadgetAttrs( + SettingWindow.Gadgets->TimezoneGadget, + SettingWindow.Window, NULL, + GTTX_Text, (IPTR) new, + TAG_END); + + SettingWindow.TimezoneText = new; + FreeMemSafe(temp); +} \ No newline at end of file diff --git a/win_main.c b/win_main.c index 167c546..b54343d 100644 --- a/win_main.c +++ b/win_main.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2017-2019 Carsten Sonne Larsen + * Copyright (c) 2017-2020 Carsten Sonne Larsen * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,41 +25,51 @@ */ #include "config.h" +#include "global.h" #include "message.h" -#include "state.h" -#include "time.h" +#include "setting.h" +#include "timer.h" +#include "sync.h" #include "mem.h" #include "win.h" +#include "logmod.h" +#define MODULENAME "Window" +#define WINPROCNAME APP_SHORT_NAME " Window" + static void SettingsProc(void); -static void ProcessMsg(void); +static void MsgLoop(void); static void HandleGadgetUp(struct Gadget *); +volatile bool WindowProcRunning = false; +struct AppSettings *WindowSettings = NULL; +struct AppSettingWindow SettingWindow; + void ShowSettingWindow(void) { bool running; + struct Task *task; Forbid(); - running = Globals->Window->Task != NULL; - if (!running) + running = WindowProcRunning; + if (!WindowProcRunning) { - Globals->Window->Task = CreateNewProcTags( + task = (struct Task *)CreateNewProcTags( NP_Entry, (IPTR)SettingsProc, - NP_Name, (IPTR)APP_SHORT_NAME " Window", + NP_Name, (IPTR)WINPROCNAME, NP_StackSize, 64 * 1024, TAG_DONE); + WindowProcRunning = (task != NULL); } Permit(); if (running) { - LogTrace("Setting process is already running"); - return; + LogDebug("Setting process is already running"); } - - if (Globals->Window->Task != NULL) + else if (task != NULL) { - LogTrace("Created setting process"); + LogDebug("Created setting process"); } else { @@ -67,129 +77,117 @@ void ShowSettingWindow(void) } } -void HideSettingWindow(void) -{ - Forbid(); - if (Globals->Window->Task != NULL) - { - Signal((void *)Globals->Window->Task, SIGBREAKF_CTRL_C); - } - Permit(); -} - -bool CheckSettingWindowClosed(void) -{ - return (Globals->Window->Task == NULL); -} - static bool InitWindow(void) { - Globals->Window->Screen = LockPubScreen(NULL); - if (!Globals->Window->Screen) + LogTrace("Initializing"); + SettingWindow.Screen = NULL; + SettingWindow.Window = NULL; + SettingWindow.GadgetList = NULL; + SettingWindow.VisualInfo = NULL; + SettingWindow.PriorityText = NULL; + SettingWindow.ThresholdText = NULL; + SettingWindow.TimezoneText = NULL; + SettingWindow.Width = 0; + SettingWindow.Height = 0; + SettingWindow.Gadgets = NULL; + + Ports.WindowPort = CreateMsgPort(); + if (Ports.WindowPort == NULL) { return false; } - Globals->Window->UserPort = CreateMsgPort(); - if (Globals->Window->UserPort == NULL) + SettingWindow.Screen = LockPubScreen(NULL); + if (!SettingWindow.Screen) { return false; } - Globals->Window->VisualInfo = GetVisualInfo(Globals->Window->Screen, NULL); - if (Globals->Window->VisualInfo == NULL) + SettingWindow.VisualInfo = GetVisualInfo(SettingWindow.Screen, NULL); + if (SettingWindow.VisualInfo == NULL) { return false; } - Globals->Window->PriorityText = AllocMemSafe(15); - Globals->Window->TimeZoneText = AllocMemSafe(10); - Globals->Window->ThresholdText = AllocMemSafe(MAXLONGLONGCHARSIZE); - if (Globals->Window->PriorityText == NULL || - Globals->Window->TimeZoneText == NULL || - Globals->Window->ThresholdText == NULL) + SettingWindow.PriorityText = AllocStringSafe(15); + SettingWindow.TimezoneText = AllocStringSafe(TIMEZONE_TEXT_LEN); + SettingWindow.ThresholdText = AllocStringSafe(MAXLONGLONGCHARSIZE); + if (SettingWindow.PriorityText == NULL || + SettingWindow.TimezoneText == NULL || + SettingWindow.ThresholdText == NULL) { return false; } - LongToStr(Globals->Settings->Priority, Globals->Window->PriorityText); - LongLongToStr(Globals->Settings->Threshold, Globals->Window->ThresholdText); - GetTimeZoneText(Globals->Window->TimeZoneText, true); + LongToStr(Settings->Priority, SettingWindow.PriorityText); + LongLongToStr(Settings->Threshold, SettingWindow.ThresholdText); + GetTimezoneText(AppLocale, SettingWindow.TimezoneText, ZONE_IN_PARENS); return true; } static void DestroyWindow(void) { - if (Globals->Window->SettingWindow != NULL) + LogTrace("Clean up"); + CleanupVolMsgPort(&Ports.WindowPort); + + if (SettingWindow.Window != NULL) { struct Message *msg; - while ((msg = GetMsg(Globals->Window->SettingWindow->UserPort))) + while ((msg = GetMsg(SettingWindow.Window->UserPort))) ReplyMsg(msg); - CloseWindow(Globals->Window->SettingWindow); - Globals->Window->SettingWindow = NULL; + CloseWindow(SettingWindow.Window); + SettingWindow.Window = NULL; } - if (Globals->Window->GadgetList != NULL) + if (SettingWindow.GadgetList != NULL) { - FreeGadgets(Globals->Window->GadgetList); - Globals->Window->GadgetList = NULL; + FreeGadgets(SettingWindow.GadgetList); + SettingWindow.GadgetList = NULL; } - if (Globals->Window->VisualInfo != NULL) + if (SettingWindow.VisualInfo != NULL) { - FreeVisualInfo(Globals->Window->VisualInfo); - Globals->Window->VisualInfo = NULL; + FreeVisualInfo(SettingWindow.VisualInfo); + SettingWindow.VisualInfo = NULL; } - if (Globals->Window->UserPort != NULL) + if (SettingWindow.Screen != NULL) { - struct Message *msg; - while ((msg = GetMsg(Globals->Window->UserPort))) - ReplyMsg(msg); - - DeleteMsgPort(Globals->Window->UserPort); - Globals->Window->UserPort = NULL; + UnlockPubScreen(NULL, SettingWindow.Screen); + SettingWindow.Screen = NULL; } - if (Globals->Window->Screen != NULL) - { - UnlockPubScreen(NULL, Globals->Window->Screen); - Globals->Window->Screen = NULL; - } + FreeSettings(WindowSettings); + WindowSettings = NULL; - FreeSettings(Globals->Window->Settings); - FreeMemSafe(Globals->Window->Gadgets, __FUNCTION__); - FreeMemSafe(Globals->Window->PriorityText, __FUNCTION__); - FreeMemSafe(Globals->Window->ThresholdText, __FUNCTION__); - FreeMemSafe(Globals->Window->TimeZoneText, __FUNCTION__); - Globals->Window->Gadgets = NULL; - Globals->Window->PriorityText = NULL; - Globals->Window->ThresholdText = NULL; - Globals->Window->TimeZoneText = NULL; - - Forbid(); - Globals->Window->Task = NULL; - Permit(); + FreeMemSafe(SettingWindow.Gadgets); + FreeMemSafe(SettingWindow.PriorityText); + FreeMemSafe(SettingWindow.ThresholdText); + FreeMemSafe(SettingWindow.TimezoneText); + SettingWindow.Gadgets = NULL; + SettingWindow.PriorityText = NULL; + SettingWindow.ThresholdText = NULL; + SettingWindow.TimezoneText = NULL; } static bool CreateWindow(void) { - long w = Globals->Window->Screen->WBorLeft + Globals->Window->Screen->WBorRight + Globals->Window->Width + 38; // Why is this 38? - long h = Globals->Window->Height + 8 + Globals->Window->Screen->WBorBottom; + long w = SettingWindow.Screen->WBorLeft + SettingWindow.Screen->WBorRight + SettingWindow.Width + 38; // Why is this 38? + long h = SettingWindow.Height + 8 + SettingWindow.Screen->WBorBottom; struct Window *x = OpenWindowTags(NULL, WA_Width, w, WA_Height, h, - WA_Left, (Globals->Window->Screen->Width - w) / 2, - WA_Top, (Globals->Window->Screen->Height - h) / 2, - WA_PubScreen, (IPTR)Globals->Window->Screen, + WA_Left, (SettingWindow.Screen->Width - w) / 2, + WA_Top, (SettingWindow.Screen->Height - h) / 2, + WA_PubScreen, (IPTR)SettingWindow.Screen, WA_Title, (IPTR)APP_LONG_NAME, WA_Flags, WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_ACTIVATE | WFLG_SIMPLE_REFRESH, WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW | IDCMP_VANILLAKEY | IDCMP_GADGETUP | IDCMP_MENUPICK, - WA_Gadgets, (IPTR)Globals->Window->GadgetList, + WA_Gadgets, (IPTR)SettingWindow.GadgetList, TAG_END); - Globals->Window->SettingWindow = x; + SettingWindow.Window = x; if (!x) { return false; @@ -200,26 +198,11 @@ static bool CreateWindow(void) static void InitWindowSettings() { - if (Globals->Window->Settings != NULL) + if (WindowSettings != NULL) { - FreeSettings(Globals->Window->Settings); - } - Globals->Window->Settings = CopySettings(Globals->Settings); -} - -static void SyncExit() -{ - if (!Globals->ShuttingDown) - { - struct MsgPort *replyPort = CreateMsgPort(); - if (replyPort) - { - SendMessageTo(Globals->Broker->UserPort, replyPort, ATK_UNDO); - WaitPort(replyPort); - GetMsg(replyPort); - DeleteMsgPort(replyPort); - } + FreeSettings(WindowSettings); } + WindowSettings = CopySettings(Settings); } static void SettingsProc(void) @@ -227,75 +210,92 @@ static void SettingsProc(void) if (!InitWindow() || !CreateGadgets() || !CreateWindow()) { DestroyWindow(); + WindowProcRunning = false; return; } InitWindowSettings(); - ShowLastSync(); - ProcessMsg(); - SyncExit(); + ShowLastSync((struct timeval *)&LastSync); + MsgLoop(); + + SendMessageWait(Ports.BrokerPort, ATK_UNDO); DestroyWindow(); + WindowProcRunning = false; } -static void ProcessMsg(void) +static void MsgLoop(void) { bool loop = true; + ULONG userPortSigMask = (1 << Ports.WindowPort->mp_SigBit); + ULONG windowSigMask = (1 << SettingWindow.Window->UserPort->mp_SigBit); + ULONG sigMask = userPortSigMask | windowSigMask; - GT_RefreshWindow(Globals->Window->SettingWindow, NULL); + GT_RefreshWindow(SettingWindow.Window, NULL); do { - ULONG sigrcvd = Wait(SIGBREAKF_CTRL_C | - (1 << Globals->Window->UserPort->mp_SigBit) | - (1 << Globals->Window->SettingWindow->UserPort->mp_SigBit)); - - if (sigrcvd & (1 << Globals->Window->SettingWindow->UserPort->mp_SigBit)) + ULONG sigrcvd = Wait(sigMask); + if (sigrcvd & windowSigMask) { struct IntuiMessage *msg; - while ((msg = GT_GetIMsg(Globals->Window->SettingWindow->UserPort))) + while ((msg = GT_GetIMsg(SettingWindow.Window->UserPort))) { switch (msg->Class) { case IDCMP_REFRESHWINDOW: - GT_BeginRefresh(Globals->Window->SettingWindow); - GT_EndRefresh(Globals->Window->SettingWindow, TRUE); + GT_BeginRefresh(SettingWindow.Window); + GT_EndRefresh(SettingWindow.Window, TRUE); break; case IDCMP_GADGETUP: HandleGadgetUp((struct Gadget *)msg->IAddress); break; case IDCMP_VANILLAKEY: if (msg->Code == 0x1b) + { loop = false; + } break; case IDCMP_CLOSEWINDOW: loop = false; break; } - GT_ReplyIMsg(msg); } } - if (sigrcvd & (1 << Globals->Window->UserPort->mp_SigBit)) + if (sigrcvd & userPortSigMask) { - struct AppWindowMessage *msg; - while ((msg = (struct AppWindowMessage *)GetMsg(Globals->Window->UserPort))) + struct ApplicationMesage *msg; + while ((msg = (struct ApplicationMesage *)GetMsg(Ports.WindowPort))) { - switch (msg->Type) + long msgType = msg->MsgType; + long msgId = msg->MsgId; + struct timeval tv; + if (msgType == MSGTYPE_TIMEVAL) { - case ATK_REFRESH: - ShowLastSync(); - break; - default: - break; + struct TimeMessage *timeMsg = (struct TimeMessage *)msg; + tv = timeMsg->TimeVal; } ReplyMsg((struct Message *)msg); - } - } - if (sigrcvd & SIGBREAKF_CTRL_C) - { - loop = false; + if (msgType == MSGTYPE_TIMEVAL) + { + ShowLastSync(&tv); + } + else + { + switch (msgId) + { + case ATK_SHUTDOWN: + loop = false; + break; + case ATK_TZ_CHANGED: + ShowNewTimezone(); + default: + break; + } + } + } } } while (loop); } @@ -319,13 +319,12 @@ static void HandleGadgetUp(struct Gadget *gadget) case GID_THRESHOLD: SetThreshold(); break; - case GID_VERBOSE: - SetVerbose(); - break; case GID_PRIORITY: SetCxPriority(); break; case GID_SAVE: + UseSettings(); + InitWindowSettings(); SendMessage(ATK_STORE); break; case GID_USE: @@ -335,7 +334,6 @@ static void HandleGadgetUp(struct Gadget *gadget) break; case GID_CANCEL: SendMessage(ATK_UNDO); - HideSettingWindow(); break; default: break;