Release 1.12

This commit is contained in:
2021-01-31 20:10:59 +01:00
parent 7f7b1173c0
commit c048b79a21
62 changed files with 2962 additions and 2102 deletions
+11
View File
@@ -1,5 +1,16 @@
AmiTimeKeeper Change Log
v1.12 31.01.2021
- New options to specify the local time zone
- New ARexx commands, parameters and error variables
- New option to start without active time synchronization
- New deactivate logging option for performance saving
- More bugs in calculation of time zone transition fixed
- Sanity check on value for interval between requests
- Updated ARexx documentation and script
- Honour ARexx result flag (RXFF_RESULT)
- Various minor bug fixes and improvements
v1.11 11.01.2021
- New dedicated external control utility
- New ARexx port with a diverse set of commands
View File
+382 -124
View File
@@ -1,5 +1,5 @@
@database TimeKeeper.guide
@$VER: TimeKeeper.guide 1.11 (11.01.2021)
@$VER: TimeKeeper.guide 1.12 (31.01.2021)
@(c) 2017-2021 Carsten Sonne Larsen <cs@innolan.net>
@author Carsten Sonne Larsen
@@ -26,46 +26,50 @@
@rem (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
@rem THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@Width 74
@Width 67
@Node Main "TimeKeeper.guide"
@Next "Configuring the client"
@Index "Index"
@Smartwrap
AmiTimeKeeper is a small program which keeps the time right on your
machine. No installation is required. It is operated as a commodity
and is controlled by AmigaOS. An AmiTCP compatible TCP/IP stack is
required for AmiTimeKeeper to work.
@{par}
AmiTimeKeeper is a small program which keeps the time right on
your machine. No installation is required. It is operated as a
commodity and is controlled by AmigaOS. An AmiTCP compatible
TCP/IP stack is required for AmiTimeKeeper to work.
@{par}
Several settings determine the behaviour. The settings are passed
either directly from the command line or by using the tool types of
an icon. Preferences can also be saved between reboots. A utility
for small tasks like starting and stopping is also included.
Comprehensive control is possible using ARexx.
either directly from the command line or by using the tool types
of an icon. Preferences can also be saved between reboots.
A utility for small tasks like starting and stopping is also
included. Comprehensive control is possible using ARexx.
@{par}
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. Use a fixed pool server by prefixing the domain, for example,
1.pool.ntp.org.
try visiting support.ntp.org or one of the other sites listing
time servers. Use a fixed pool server by prefixing the domain,
for example, 1.pool.ntp.org.
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.
@{par}
The time zone needs to be configured using Workbench preferences
or a similar tool. In Amiga OS this is available through the
Locale Preferences Editor. The local time zone and daylight saving
time are optionally specified manually or using a POSIX TZ
variable style.
This version (1.11) has two known issues:
- Settings window in AROS is broken (and disabled in this version)
- Setting Popkey is not supported in ARexx
@{"Configuring the client" Link "Configuring the client"}
@{"Using tooltypes of an icon" Link "Using tooltypes of an icon"}
@{"Saving preferences" Link "Saving preferences"}
@{"ARexx interface" Link "ARexx interface"}
@{"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"}
@{par}
@{"Configuring the client" Link "Configuring the client"}@{line}
@{"Using tooltypes of an icon" Link "Using tooltypes of an icon"}@{line}
@{"Local time zone" Link "Local time zone"}@{line}
@{"Saving preferences" Link "Saving preferences"}@{line}
@{"ARexx interface" Link "ARexx interface"}@{line}
@{"POSIX TZ environment variable" Link "POSIX TZ environment variable"}@{line}
@{"Change Log / Change History" Link "Change Log"}@{line}
@{"Software License" Link "Software License"}@{line}
@{"Credits and donations" Link "Credits and donations"}@{line}
@{"Contacting the author" Link "Contacting the author"}@{line}
@EndNode
@@ -103,53 +107,101 @@ is the NTP server port different from 123.
@{b}Interval between requests@{ub}
The Amiga hardware clock will slowly drift away from true time. The
drift is determined by several factors and is small, but the drift is not
insignificant. Request are repeatedly sent to the NTP server in order to
keep the Amiga hardware clock as close to true time as possible.
drift is determined by several factors and is small, but the drift
is not insignificant. Request are repeatedly sent to the NTP server
in order to keep the Amiga hardware clock as close to true time as
possible.
The requests are sent in certain intervals defined by the interval
parameter. The interval should be specified using milliseconds. One
thousand (1.000) milliseconds are equal to one second.
thousand (1.000) milliseconds are equal to one second. The max value
is 172.800.000 equal to 48 hours.
@{b}Adjustment threshold@{ub}
Due to the accuracy of NTP servers and the nature of Amiga CPUs it does
not make sense to adjust the Amiga clock on every response from the NTP
server. Processing the response could take longer time than anticipated.
The amount of accepted inaccuracy is set using the threshold parameter.
The threshold should be specified using microsecond. One million
microseconds (1.000.000) are equal to one second.
Due to the accuracy of NTP servers and the nature of Amiga CPUs
it does not make sense to adjust the Amiga clock on every response
from the NTP server. Processing the response could take longer time
than anticipated. The amount of accepted inaccuracy is set using the
threshold parameter. The threshold should be specified using micro-
seconds. One million microseconds (1.000.000) are equal to one
second.
@{b}Start with synchronization active@{ub}
Maybe some related settings or the network connection are not ready
from the beginning. The commodity can then be started in a preparation
mode. Activation is possible from within AmigaOS, through the control
utility @{i}TimeCtrl@{ui}, or through the ARexx interface.
@{b}Read only@{ub}
It is possible to send request to the NTP server without setting the
Amiga hardware clock. This option can be handy when debugging time zone
setup and other time related parameters.
Amiga hardware clock. This option can be handy when debugging time
zone setup and other time related parameters.
@{b}Expert mode@{ub}
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.
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.
@{b}Connection timeout@{ub}
@{b}Connection time out@{ub}
In some cases, a connection to the NTP server cannot be established or
the NTP server simply does respond. To avoid an infinitive wait for a
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.
In some cases, a connection to the NTP server cannot be established
or the NTP server simply does respond. To avoid an infinitive wait
for a 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. The max value is half
of the value of interval between requests.
@{b}Logging@{ub}
It is possible view log messages using the supplied tool TimeLogger.
It is possible view log messages using the supplied tool @{i}TimeLogger@{ui}.
The logger facility can be turned off with the NOLOG switch.
@{b}Automatically synchronization@{ub}
Sometimes it is feasible to start without synchronization. The clock
is synchronized in the background, only when synchronization is
active. By default synchronization is not active.
@{b}Time zone display@{ub}
Different options for displaying the current time zone exists. The
most common is a combination of time zone name and time zone offset
from GMT. The ARexx documentation describes the time zone display
methods in details.
@{b}Time zone@{ub}
If the local time zone is expressed as a POSIX TZ compatible string,
an optional setting is available.
@{b}Time zone value@{ub}
The most simple way to expressed the local time zone is in hours
and minutes from Greenwich Mean Time (GMT) or UTC. One hour ahead
is equal to 100. One hour behind is equal to -100. Two and a half
hour ahead is equal to 230.
@{b}Time zone abbreviation@{ub}
If no name is given for the local time zone, the time zone is shown
as hours and minutes from Greenwich Mean Time (GMT). It is possible
to specify a time zone abbreviation for better readability.
@{b}Daylight saving time@{ub}
Sometimes is feasible to force a standard one hour ahead daylight
saving time (DST). Use this option if needed.
@{b}Caveats@{ub}
TimeKeeper 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:
TimeKeeper 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
@@ -158,18 +210,18 @@ to avoid this behaviour:
@Toc "Main"
@Index "Index"
@Prev "Configuring the client"
@Next "Saving preferences"
@Next "Local time zone"
Settings can be changes by setting tooltypes in the TimeKeeper icon.
Add the following line to the icon tooltypes in order to set the server
to an European pool server:
Settings can be changes by setting tooltypes in the TimeKeeper
icon. Add the following line to the icon tooltypes in order to
set the server to an European pool server:
SERVER=europe.pool.ntp.org
The available tooltypes are the same as the available command line
parameters.
The available tooltypes are the same as the available command
line parameters.
@{b}Parameter@{ub} | @{b}Short description@{ub}
-------------------------------------------------
-----------------------------------------------------------
SERVER | NTP server Address
PORT | NTP server Port
THRESHOLD | Adjustment threshold
@@ -180,6 +232,13 @@ CX_PRIORITY | Commodity priority
READONLY | Do not set clock
EXPERT | Show advanced options
TIMEOUT | Connection Timeout
ACTIVE | Automatically start time synchronization
NOLOG | deactivate logger facility
TZD | Time zone display mode i settings window
TZ | Optional TZ POSIX string
TZVALUE | Optional time zone value
TZNAME | Optional time zone abbreviation
TZDST | Optionally force day light saving time
@{b}Caveats@{ub}
@@ -187,50 +246,90 @@ Settings can be overridden and are set in the following order:
1. Preference file
2. Icon tooltypes / CLI parameters
CLI parameters and icon tooltypes has highest precedence and will
always override settings from the preference file.
CLI parameters and icon tooltypes has highest precedence and
will always override settings from the preference file.
Settings from icon tooltypes are used when starting from Workbench.
Settings from CLI are used only when starting from shell.
When using WBStartup folder or a similar system, remember to add the
mandatory tooltype DONOTWAIT. Otherwise the startup execution will be
blocked.
When using WBStartup folder or a similar system, remember to add
the mandatory tool type DONOTWAIT. Otherwise the startup execution
will be blocked.
@EndNode
@Node "Local time zone" "TimeKeeper.guide/Local time zone"
@Toc "Main"
@Index "Index"
@Prev "Using tooltypes of an icon"
@Next "Saving preferences"
@{b}Selecting time zone@{ub}
The local time zone is selected from 5 different options, in
the following order:
1. TZVALUE setting
2. TZ setting
3. Global TZ environment variable
4. Global TZONE environment variable
5. Workbench Locale Preferences
@{b}TZVALUE setting@{ub}
The local time zone value setting is available from CLI, icon
tool types and ARexx. The value is specified in hours and minutes
from GMT or UTC. One hour ahead is equal to 100. One hour
behind is equal to -100.
@{b}TZ setting@{ub}
The TZ setting is available from CLI, icon tool types and ARexx.
@{b}Global TZ environment variable@{ub}
The Amiga DOS global environment variable TZ containing a POSIX
TZ compliant string.
@{b}Global TZONE environment variable@{ub}
The Amiga DOS environment global variable TZONE containing a
POSIX TZ compliant string.
@{b}Workbench Locale Preferences@{ub}
Amiga OS / Workbench Locale Preferences Editor
@EndNode
@Node "Saving preferences" "TimeKeeper.guide/Saving preferences"
@Toc "Main"
@Index "Index"
@Prev "Using tooltypes of an icon"
@Prev "Local time zone"
@Next "ARexx interface"
Preferences from the setting window are saved in the file
ENV:timekeeper.prefs
Preferences are saved in the file
ENV:AmiTimeKeeper/timekeeper.prefs
Preferences are also persisted between reboots in the file
ENVARC:timekeeper.prefs
ENVARC:AmiTimeKeeper/timekeeper.prefs
Depending on the setup the content of timekeeper.prefs could be:
CX_POPUP=NO
CX_POPKEY=lshift control t
CX_PRIORITY=25
CX_PRIORITY=5
THRESHOLD=1000000
SERVER=de.pool.ntp.org
PORT=123
TIMEOUT=5000
TIMEOUT=1000
INTERVAL=17500
READONLY=NO
EXPERT=NO
ACTIVE=YES
NOLOG=YES
The preference file should not be edited under normal circumstances.
@{b}Caveats@{ub}
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 tooltypes.
preference file. All setting are saved includes default settings
and settings from CLI and icon tooltypes.
@EndNode
@@ -238,7 +337,7 @@ settings from CLI and icon tooltypes.
@Toc "Main"
@Index "Index"
@Prev "Saving preferences"
@Next "The POSIX TZ environment variable"
@Next "POSIX TZ environment variable"
TimeKeeper provides an ARexx port with a diverse set of commands.
The ARexx address is 'TIMEKEEPER.1'.
@@ -251,17 +350,77 @@ HELP | Get a list of ARexx commands and a short description
STATUS | Get current synchronization status
TIMEZONE | Get current time zone
LASTSYNC | Get time of last synchronization operation
LASTAD | Get time of last clock adjustment
LASTADJ | Get time of last clock adjustment
GET | Get a runtime configuration value
SET | Set a runtime configuration value
NOW | Get current time and date
SHOW | Show settings window
HIDE | Hide settings window
START | Start the time synchronization process
STOP | Stop the time synchronization process
SHUTDOWN | Shutdown TimeKeeper
LOGTRANS | Emit time zone transition map to log
-----------------------------------------------------------------
@{b}Examples@{ub}
@{b}Parameters@{ub}
STATUS accepts NUMBER as parameter. Result is instead formatted
as binary value.
TIMEZONE accepts a code as parameter. The code determines how
the result is formatted:
1 Seconds ahead of UTC (+[s])
2 Minutes ahead of UTC (+[m])
3 TZ style long format (UTC-[hh]:[mm])
4 TZ style short format (-[hh]:[mm])
5 ISO 8601 style (+[hh][mm])
6 ISO 8601 style (+[hh]:[mm])
7 ISO 8601 short style (+[h])
8 Common identifier (GMT+[hh]:[mm])
9 Common identifier, offset with name in parens
10 Common identifier, name with offset in parens
11 Standard time zone
12 DST time zone
NOW, LASTSYNC and LASTADJ accepts DOS, ASCII, DATE, TIME, RFC850,
RFC1123, RFC2822, RFC3339 or ISO8601 as first parameter. DOS is
assumed if parameter is not specified.
DOS AmigaDOS style
ASCII C ASCII style
DATE ARexx formatted as sorted date
TIME Time in seconds since midnight
LOCAL and UTC are accepted as second parameter. LOCAL is assumed
if second parameter is not specified. RFC850 and RFC1123 are always
GMT.
GET accepts SERVER, PORT, THRESHOLD, INTERVAL, CX_PRIORITY,
CX_POPKEY, CX_POPUP, READONLY, EXPERT, TIMEOUT, ACTIVE, NOLOG,
TZD, TZ, TZNAME, TZVALUE and TZDST as parameter. CX_POPUP,
READONLY, EXPERT, ACTIVE and NOLOG accepts NUMBER as parameter.
SET accepts the same parameters as GET, except CX_POPKEY, and an
addition value parameter.
ID, VERSION, HELP, SHOW, HIDE, START, STOP, SHUTDOWN and LOGTRANS
does not accept parameters.
@{b}Error handling@{ub}
The local variables TIMEKEEPER.ERRORCODE and TIMEKEEPER.ERRORTEXT
are set on each call too ARexx.
There is a number of possible error codes.
0 No errors
10 Unknown ARexx command
11 Unknown parameter
12 Parameter is missing
13 Invalid parameter value
18 Clock has not been adjusted
19 No responses from NTP server
20 Synchronization is already active
21 Synchronization is already deactivated
@{b}ARexx examples@{ub}
Stop the the time synchronization process with:
@{"Address TIMEKEEPER.1 stop" rxs "Address TIMEKEEPER.1 stop"}
@@ -276,13 +435,15 @@ The arexx folder contains a set of sample scripts.
@{b}TimeCtrl@{ub}
Controlling TimeKeeper without using ARexx is done through the
control utility TimeCtrl. The following commands are available.
control utility @{i}TimeCtrl@{ui}. The following commands are available.
@{b}Command@{ub} | @{b}Description@{ub}
-----------------------------------------------------------------
ID | Get application identifier
VERSION | Get application version number
STATUS | Get current synchronization status
TIME | Get current time and date
ZONE | Get current time zone
START | Start the time synchronization process
STOP | Stop the time synchronization process
SHOW | Show settings window
@@ -292,23 +453,24 @@ SHUTDOWN | Shutdown TimeKeeper
@EndNode
@Node "The POSIX TZ environment variable" "TimeKeeper.guide/The POSIX TZ environment variable"
@Node "POSIX TZ environment variable" "TimeKeeper.guide/POSIX TZ environment variable"
@Toc "Main"
@Index "Index"
@Prev "ARexx interface"
@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.
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.
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.
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
@@ -753,6 +915,17 @@ Pacific/Wallis TZ <GMT+12>-12
@Prev "Saving preferences"
@Next "Software License"
@{b}v1.12 31.01.2021@{ub}
- New options to specify the local time zone
- New ARexx commands, parameters and error variables
- New option to start without active time synchronization
- New deactivate logging option for performance saving
- More bugs in calculation of time zone transition fixed
- Sanity check on value for interval between requests
- Updated ARexx documentation and script
- Honour ARexx result flag (RXFF_RESULT)
- Various minor bug fixes and improvements
@{b}v1.11 11.01.2021@{ub}
- New dedicated external control utility
- New ARexx port with a diverse set of commands
@@ -833,6 +1006,11 @@ Pacific/Wallis TZ <GMT+12>-12
@Toc "Main"
@Index "Index"
@{b}Bug reports@{ub}
Please report bugs and other issues by sending a mail or using:
https://ranger.innolan.net/rainlance/AmiTimeKeeper
@{b}Simplified BSD License / 2-clause BSD license@{ub}
Copyright (c) 2001, 02 Motoyuki Kasahara
@@ -869,17 +1047,13 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@Toc "Main"
@Index "Index"
A custom version has been integrated into the Icaros Desktop system.
The author encourages all developers with an interest to make their own
build.
The following people have contributed with bug reports, comments,
suggestions and donations:
* aPEX from a1k.org
* Greg Donner
* Paolo Besser
* Knut Hansen
* Greg Donner
* Thomas Blatt
* Bartosz Makara
* Benny Damsgaard
@@ -911,52 +1085,136 @@ January 2021
@{b}A@{ub}
@{"ARexx interface" Link "ARexx interface"}
@{"Adjustment threshold" Link "Configuring the client" 40 }
@{"ARexx interface" Link "ARexx interface" 1 }
@{"Automatically synchronization" Link "Configuring the client" 84 }
@{b}C@{ub}
@{"Configution" Link "Configuring the client"}
@{"CLI" Link "Using tooltypes of an icon"}
@{"Configution" Link "Configuring the client" 1 }
@{"Connection time out" Link "Configuring the client" 70 }
@{"CLI" Link "Using tooltypes of an icon" 7 }
@{b}D@{ub}
@{"Daylight saving time" Link "Configuring the client" 113 }
@{b}E@{ub}
@{"Environment variable" Link "Local time zone" 20 }
@{"Expert mode" Link "Configuring the client" 63 }
@{b}I@{ub}
@{"Interval between requests" Link "Configuring the client" 27 }
@{"ISO8601" Link "ARexx interface" 44 }
@{b}K@{ub}
@{"Keywords" Link "ARexx" 1 }
@{"ACTIVE - Automatically synchronization" Link "Configuring the client" 84 }
@{"ASCII" Link "ARexx interface" 44 }
@{"CX_POPKEY" Link "Using tooltypes of an icon" 17 }
@{"CX_POPUP" Link "Using tooltypes of an icon" 16 }
@{"CX_PRIORITY" Link "Using tooltypes of an icon" 18 }
@{"DATE" Link "ARexx interface" 44 }
@{"DONOTWAIT" Link "Using tooltypes of an icon" 42 }
@{"DOS" Link "ARexx interface" 44 }
@{"DST - Daylight saving time" Link "Configuring the client" 113 }
@{"EXPERT - Expert mode" Link "Configuring the client" 63 }
@{"INTERVAL - Interval between requests" Link "Configuring the client" 27 }
@{"ISO8601" Link "ARexx interface" 44 }
@{"LOCAL" Link "ARexx interface" 52 }
@{"NOLOG - Logging" Link "Configuring the client" 79 }
@{"NUMBER" Link "ARexx interface" 56 }
@{"POPUP" Link "Configuring the client"}
@{"PORT - Server port" Link "Configuring the client" 22 }
@{"READONLY" Link "Configuring the client" 57 }
@{"RFC850" Link "ARexx interface" 44 }
@{"RFC1123" Link "ARexx interface" 44 }
@{"RFC2822" Link "ARexx interface" 44 }
@{"RFC3339" Link "ARexx interface" 44 }
@{"SERVER - Server address" Link "Configuring the client" 1 }
@{"THRESHOLD - Adjustment threshold" Link "Configuring the client" 40 }
@{"TIME" Link "ARexx interface" 44 }
@{"TIMEOUT - Connection time out" Link "Configuring the client" 70 }
@{"TIMEZONE - Time zone" Link "Configuring the client" 97 }
@{"TIMEZONEABBREVIATION - Time zone abbreviation" Link "Configuring the client" 104 }
@{"TIMEZONEDISPLAY - Time zone display" Link "Configuring the client" 90 }
@{"TIMEZONEVALUE - Time zone value" Link "Configuring the client" 109 }
@{"TZ - Time zone" Link "Configuring the client" 97 }
@{"TZD - Time zone display" Link "Configuring the client" 90 }
@{"TZDST - Daylight saving time" Link "Configuring the client" 113 }
@{"TZNAME - Time zone abbreviation" Link "Configuring the client" 104 }
@{"TZVALUE - Time zone value" Link "Configuring the client" 109 }
@{"UTC" Link "ARexx interface" 52 }
@{b}L@{ub}
@{"Logging" Link "Configuring the client"}
@{"Logging" Link "Configuring the client" 79 }
@{b}N@{ub}
@{"Network Time Foundation" Link "Configuring the client"}
@{"Network Time Foundation" Link "Configuring the client" 4 }
@{b}P@{ub}
@{"Pool servers" Link "Configuring the client"}
@{"Posix" Link "The POSIX TZ environment variable"}
@{"Preferences" Link "Saving preferences"}
@{"Pool servers" Link "Configuring the client" 9 }
@{"Popkey" Link "Using tooltypes of an icon" 17 }
@{"Popup" Link "Using tooltypes of an icon" 16 }
@{"Posix" Link "POSIX TZ environment variable" 1 }
@{"Preferences" Link "Saving preferences" 1 }
@{"Priority" Link "Using tooltypes of an icon" 18 }
@{b}R@{ub}
@{"Read only" Link "Configuring the client" 57 }
@{"RFC850" Link "ARexx interface" 44 }
@{"RFC1123" Link "ARexx interface" 44 }
@{"RFC2822" Link "ARexx interface" 44 }
@{"RFC3339" Link "ARexx interface" 44 }
@{b}S@{ub}
@{"Settings" Link "Configuring the client"}
@{"Connection timeout" Link "Configuring the client"}
@{"Expert mode " Link "Configuring the client"}
@{"Interval" Link "Configuring the client"}
@{"Logging" Link "Configuring the client"}
@{"Popkey" Link "Configuring the client"}
@{"Popup" Link "Configuring the client"}
@{"Priority" Link "Configuring the client"}
@{"Read only" Link "Configuring the client"}
@{"Server address" Link "Configuring the client"}
@{"Server port" Link "Configuring the client"}
@{"Threshold" Link "Configuring the client"}
@{"Standard time" Link "The POSIX TZ environment variable"}
@{"Summer time" Link "The POSIX TZ environment variable"}
@{"Server address" Link "Configuring the client" 1 }
@{"Server port" Link "Configuring the client" 22 }
@{"Settings" Link "Configuring the client" 1 }
@{"Automatically synchronization" Link "Configuring the client" 84 }
@{"Connection time out" Link "Configuring the client" 70}
@{"Daylight saving time" Link "Configuring the client" 113 }
@{"Expert mode " Link "Configuring the client" 63 }
@{"Interval between requests" Link "Configuring the client" 27 }
@{"Logging" Link "Configuring the client" 79 }
@{"Popkey" Link "Using tooltypes of an icon" 17 }
@{"Popup" Link "Using tooltypes of an icon" 16 }
@{"Priority" Link "Using tooltypes of an icon" 18 }
@{"Read only" Link "Configuring the client" 57 }
@{"Server address" Link "Configuring the client" 1 }
@{"Server port" Link "Configuring the client" 22 }
@{"Threshold" Link "Configuring the client" 40 }
@{"Time zone" Link "Configuring the client" 97 }
@{"Time zone abbreviation" Link "Configuring the client" 104 }
@{"Time zone display" Link "Configuring the client" 90 }
@{"Time zone value" Link "Configuring the client" 109 }
@{"Standard time" Link "Configuring the client" 113 }
@{"Startup Sequence" Link "Configuring the client" 120 }
@{"Summer time" Link "Configuring the client" 113 }
@{b}T@{ub}
@{"TimeCtrl" Link "ARexx interface"}
@{"TimeLogger" Link "Configuring the client"}
@{"Time zone" Link "Main"}
@{"Getting" Link "ARexx interface"}
@{"Setting" Link "Main"}
@{"Tool types" Link "Using tooltypes of an icon"}
@{"TZ" Link "The POSIX TZ environment variable"}
@{"Threshold" Link "Configuring the client" 40 }
@{"TimeCtrl" Link "ARexx interface" 95 }
@{"TimeLogger" Link "Configuring the client" 81 }
@{"Time zone" Link "Local time zone" 1 }
@{"Getting" Link "ARexx interface" 29 }
@{"Setting" Link "Local time zone" 1 }
@{"Time zone abbreviation" Link "Configuring the client" 104 }
@{"Time zone display" Link "Configuring the client" 90 }
@{"Time zone value" Link "Local time zone" 109 }
@{"Tool types" Link "Using tooltypes of an icon" 1 }
@{"TZ" Link "Local time zone" 18 }
@{"Content" Link "POSIX TZ environment variable" 7 }
@{"Setting" Link "Local time zone" 1 }
@{"TZONE" Link "Local time zone" 25 }
@EndNode
+353 -96
View File
@@ -9,36 +9,39 @@
<p><a>Contents</a> <a href="#index">Index</a> <a>Help</a> <a>Prev</a> <a href="#configuring+the+client">Next</a> </p>
<pre>
AmiTimeKeeper is a small program which keeps the time right on your
machine. No installation is required. It is operated as a commodity
and is controlled by AmigaOS. An AmiTCP compatible TCP/IP stack is
required for AmiTimeKeeper to work.
AmiTimeKeeper is a small program which keeps the time right on
your machine. No installation is required. It is operated as a
commodity and is controlled by AmigaOS. An AmiTCP compatible
TCP/IP stack is required for AmiTimeKeeper to work.
Several settings determine the behaviour. The settings are passed
either directly from the command line or by using the tool types of
an icon. Preferences can also be saved between reboots. A utility
for small tasks like starting and stopping is also included.
Comprehensive control is possible using ARexx.
either directly from the command line or by using the tool types
of an icon. Preferences can also be saved between reboots.
A utility for small tasks like starting and stopping is also
included. Comprehensive control is possible using ARexx.
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. Use a fixed pool server by prefixing the domain, for example,
1.pool.ntp.org.
try visiting support.ntp.org or one of the other sites listing
time servers. Use a fixed pool server by prefixing the domain,
for example, 1.pool.ntp.org.
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.
This version (1.11) has two known issues:
- Settings window in AROS is broken (and disabled in this version)
- Setting Popkey is not supported in ARexx
The time zone needs to be configured using Workbench preferences
or a similar tool. In Amiga OS this is available through the
Locale Preferences Editor. The local time zone and daylight saving
time are optionally specified manually or using a POSIX TZ
variable style.
<a href="#configuring+the+client">Configuring the client</a>
<a href="#using+tooltypes+of+an+icon">Using tooltypes of an icon</a>
<a href="#local+time+zone">Local time zone</a>
<a href="#saving+preferences">Saving preferences</a>
<a href="#arexx+interface">ARexx interface</a>
<a href="#the+posix+tz+environment+variable">The POSIX TZ environment variable</a>
<a href="#posix+tz+environment+variable">POSIX TZ environment variable</a>
<a href="#change+log">Change Log / Change History</a>
<a href="#software+license">Software License</a>
<a href="#credits+and+donations">Credits and donations</a>
@@ -80,53 +83,101 @@ is the NTP server port different from 123.
<b>Interval between requests</b>
The Amiga hardware clock will slowly drift away from true time. The
drift is determined by several factors and is small, but the drift is not
insignificant. Request are repeatedly sent to the NTP server in order to
keep the Amiga hardware clock as close to true time as possible.
drift is determined by several factors and is small, but the drift
is not insignificant. Request are repeatedly sent to the NTP server
in order to keep the Amiga hardware clock as close to true time as
possible.
The requests are sent in certain intervals defined by the interval
parameter. The interval should be specified using milliseconds. One
thousand (1.000) milliseconds are equal to one second.
thousand (1.000) milliseconds are equal to one second. The max value
is 172.800.000 equal to 48 hours.
<b>Adjustment threshold</b>
Due to the accuracy of NTP servers and the nature of Amiga CPUs it does
not make sense to adjust the Amiga clock on every response from the NTP
server. Processing the response could take longer time than anticipated.
The amount of accepted inaccuracy is set using the threshold parameter.
The threshold should be specified using microsecond. One million
microseconds (1.000.000) are equal to one second.
Due to the accuracy of NTP servers and the nature of Amiga CPUs
it does not make sense to adjust the Amiga clock on every response
from the NTP server. Processing the response could take longer time
than anticipated. The amount of accepted inaccuracy is set using the
threshold parameter. The threshold should be specified using micro-
seconds. One million microseconds (1.000.000) are equal to one
second.
<b>Start with synchronization active</b>
Maybe some related settings or the network connection are not ready
from the beginning. The commodity can then be started in a preparation
mode. Activation is possible from within AmigaOS, through the control
utility <i>TimeCtrl</i>, or through the ARexx interface.
<b>Read only</b>
It is possible to send request to the NTP server without setting the
Amiga hardware clock. This option can be handy when debugging time zone
setup and other time related parameters.
Amiga hardware clock. This option can be handy when debugging time
zone setup and other time related parameters.
<b>Expert mode</b>
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.
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.
<b>Connection timeout</b>
<b>Connection time out</b>
In some cases, a connection to the NTP server cannot be established or
the NTP server simply does respond. To avoid an infinitive wait for a
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.
In some cases, a connection to the NTP server cannot be established
or the NTP server simply does respond. To avoid an infinitive wait
for a 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. The max value is half
of the value of interval between requests.
<b>Logging</b>
It is possible view log messages using the supplied tool TimeLogger.
It is possible view log messages using the supplied tool <i>TimeLogger</i>.
The logger facility can be turned off with the NOLOG switch.
<b>Automatically synchronization</b>
Sometimes it is feasible to start without synchronization. The clock
is synchronized in the background, only when synchronization is
active. By default synchronization is not active.
<b>Time zone display</b>
Different options for displaying the current time zone exists. The
most common is a combination of time zone name and time zone offset
from GMT. The ARexx documentation describes the time zone display
methods in details.
<b>Time zone</b>
If the local time zone is expressed as a POSIX TZ compatible string,
an optional setting is available.
<b>Time zone value</b>
The most simple way to expressed the local time zone is in hours
and minutes from Greenwich Mean Time (GMT) or UTC. One hour ahead
is equal to 100. One hour behind is equal to -100. Two and a half
hour ahead is equal to 230.
<b>Time zone abbreviation</b>
If no name is given for the local time zone, the time zone is shown
as hours and minutes from Greenwich Mean Time (GMT). It is possible
to specify a time zone abbreviation for better readability.
<b>Daylight saving time</b>
Sometimes is feasible to force a standard one hour ahead daylight
saving time (DST). Use this option if needed.
<b>Caveats</b>
TimeKeeper 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:
TimeKeeper 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
</pre>
@@ -134,19 +185,19 @@ to avoid this behaviour:
<div id="using+tooltypes+of+an+icon">
<hr/>
<p><b>TimeKeeper.guide/Using tooltypes of an icon</b></p>
<p><a href="#main">Contents</a> <a href="#index">Index</a> <a>Help</a> <a href="#configuring+the+client">Prev</a> <a href="#saving+preferences">Next</a> </p>
<p><a href="#main">Contents</a> <a href="#index">Index</a> <a>Help</a> <a href="#configuring+the+client">Prev</a> <a href="#local+time+zone">Next</a> </p>
<pre>
Settings can be changes by setting tooltypes in the TimeKeeper icon.
Add the following line to the icon tooltypes in order to set the server
to an European pool server:
Settings can be changes by setting tooltypes in the TimeKeeper
icon. Add the following line to the icon tooltypes in order to
set the server to an European pool server:
SERVER=europe.pool.ntp.org
The available tooltypes are the same as the available command line
parameters.
The available tooltypes are the same as the available command
line parameters.
<b>Parameter</b> | <b>Short description</b>
-------------------------------------------------
-----------------------------------------------------------
SERVER | NTP server Address
PORT | NTP server Port
THRESHOLD | Adjustment threshold
@@ -157,6 +208,13 @@ CX_PRIORITY | Commodity priority
READONLY | Do not set clock
EXPERT | Show advanced options
TIMEOUT | Connection Timeout
ACTIVE | Automatically start time synchronization
NOLOG | deactivate logger facility
TZD | Time zone display mode i settings window
TZ | Optional TZ POSIX string
TZVALUE | Optional time zone value
TZNAME | Optional time zone abbreviation
TZDST | Optionally force day light saving time
<b>Caveats</b>
@@ -164,57 +222,97 @@ Settings can be overridden and are set in the following order:
1. Preference file
2. Icon tooltypes / CLI parameters
CLI parameters and icon tooltypes has highest precedence and will
always override settings from the preference file.
CLI parameters and icon tooltypes has highest precedence and
will always override settings from the preference file.
Settings from icon tooltypes are used when starting from Workbench.
Settings from CLI are used only when starting from shell.
When using WBStartup folder or a similar system, remember to add the
mandatory tooltype DONOTWAIT. Otherwise the startup execution will be
blocked.
When using WBStartup folder or a similar system, remember to add
the mandatory tool type DONOTWAIT. Otherwise the startup execution
will be blocked.
</pre>
</div>
<div id="local+time+zone">
<hr/>
<p><b>TimeKeeper.guide/Local time zone</b></p>
<p><a href="#main">Contents</a> <a href="#index">Index</a> <a>Help</a> <a href="#using+tooltypes+of+an+icon">Prev</a> <a href="#saving+preferences">Next</a> </p>
<pre>
<b>Selecting time zone</b>
The local time zone is selected from 5 different options, in
the following order:
1. TZVALUE setting
2. TZ setting
3. Global TZ environment variable
4. Global TZONE environment variable
5. Workbench Locale Preferences
<b>TZVALUE setting</b>
The local time zone value setting is available from CLI, icon
tool types and ARexx. The value is specified in hours and minutes
from GMT or UTC. One hour ahead is equal to 100. One hour
behind is equal to -100.
<b>TZ setting</b>
The TZ setting is available from CLI, icon tool types and ARexx.
<b>Global TZ environment variable</b>
The Amiga DOS global environment variable TZ containing a POSIX
TZ compliant string.
<b>Global TZONE environment variable</b>
The Amiga DOS environment global variable TZONE containing a
POSIX TZ compliant string.
<b>Workbench Locale Preferences</b>
Amiga OS / Workbench Locale Preferences Editor
</pre>
</div>
<div id="saving+preferences">
<hr/>
<p><b>TimeKeeper.guide/Saving preferences</b></p>
<p><a href="#main">Contents</a> <a href="#index">Index</a> <a>Help</a> <a href="#using+tooltypes+of+an+icon">Prev</a> <a href="#arexx+interface">Next</a> </p>
<p><a href="#main">Contents</a> <a href="#index">Index</a> <a>Help</a> <a href="#local+time+zone">Prev</a> <a href="#arexx+interface">Next</a> </p>
<pre>
Preferences from the setting window are saved in the file
ENV:timekeeper.prefs
Preferences are saved in the file
ENV:AmiTimeKeeper/timekeeper.prefs
Preferences are also persisted between reboots in the file
ENVARC:timekeeper.prefs
ENVARC:AmiTimeKeeper/timekeeper.prefs
Depending on the setup the content of timekeeper.prefs could be:
CX_POPUP=NO
CX_POPKEY=lshift control t
CX_PRIORITY=25
CX_PRIORITY=5
THRESHOLD=1000000
SERVER=de.pool.ntp.org
PORT=123
TIMEOUT=5000
TIMEOUT=1000
INTERVAL=17500
READONLY=NO
EXPERT=NO
ACTIVE=YES
NOLOG=YES
The preference file should not be edited under normal circumstances.
<b>Caveats</b>
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 tooltypes.
preference file. All setting are saved includes default settings
and settings from CLI and icon tooltypes.
</pre>
</div>
<div id="arexx+interface">
<hr/>
<p><b>TimeKeeper.guide/ARexx interface</b></p>
<p><a href="#main">Contents</a> <a href="#index">Index</a> <a>Help</a> <a href="#saving+preferences">Prev</a> <a href="#the+posix+tz+environment+variable">Next</a> </p>
<p><a href="#main">Contents</a> <a href="#index">Index</a> <a>Help</a> <a href="#saving+preferences">Prev</a> <a href="#posix+tz+environment+variable">Next</a> </p>
<pre>
TimeKeeper provides an ARexx port with a diverse set of commands.
@@ -228,17 +326,77 @@ HELP | Get a list of ARexx commands and a short description
STATUS | Get current synchronization status
TIMEZONE | Get current time zone
LASTSYNC | Get time of last synchronization operation
LASTAD | Get time of last clock adjustment
LASTADJ | Get time of last clock adjustment
GET | Get a runtime configuration value
SET | Set a runtime configuration value
NOW | Get current time and date
SHOW | Show settings window
HIDE | Hide settings window
START | Start the time synchronization process
STOP | Stop the time synchronization process
SHUTDOWN | Shutdown TimeKeeper
LOGTRANS | Emit time zone transition map to log
-----------------------------------------------------------------
<b>Examples</b>
<b>Parameters</b>
STATUS accepts NUMBER as parameter. Result is instead formatted
as binary value.
TIMEZONE accepts a code as parameter. The code determines how
the result is formatted:
1 Seconds ahead of UTC (+[s])
2 Minutes ahead of UTC (+[m])
3 TZ style long format (UTC-[hh]:[mm])
4 TZ style short format (-[hh]:[mm])
5 ISO 8601 style (+[hh][mm])
6 ISO 8601 style (+[hh]:[mm])
7 ISO 8601 short style (+[h])
8 Common identifier (GMT+[hh]:[mm])
9 Common identifier, offset with name in parens
10 Common identifier, name with offset in parens
11 Standard time zone
12 DST time zone
NOW, LASTSYNC and LASTADJ accepts DOS, ASCII, DATE, TIME, RFC850,
RFC1123, RFC2822, RFC3339 or ISO8601 as first parameter. DOS is
assumed if parameter is not specified.
DOS AmigaDOS style
ASCII C ASCII style
DATE ARexx formatted as sorted date
TIME Time in seconds since midnight
LOCAL and UTC are accepted as second parameter. LOCAL is assumed
if second parameter is not specified. RFC850 and RFC1123 are always
GMT.
GET accepts SERVER, PORT, THRESHOLD, INTERVAL, CX_PRIORITY,
CX_POPKEY, CX_POPUP, READONLY, EXPERT, TIMEOUT, ACTIVE, NOLOG,
TZD, TZ, TZNAME, TZVALUE and TZDST as parameter. CX_POPUP,
READONLY, EXPERT, ACTIVE and NOLOG accepts NUMBER as parameter.
SET accepts the same parameters as GET, except CX_POPKEY, and an
addition value parameter.
ID, VERSION, HELP, SHOW, HIDE, START, STOP, SHUTDOWN and LOGTRANS
does not accept parameters.
<b>Error handling</b>
The local variables TIMEKEEPER.ERRORCODE and TIMEKEEPER.ERRORTEXT
are set on each call too ARexx.
There is a number of possible error codes.
0 No errors
10 Unknown ARexx command
11 Unknown parameter
12 Parameter is missing
13 Invalid parameter value
18 Clock has not been adjusted
19 No responses from NTP server
20 Synchronization is already active
21 Synchronization is already deactivated
<b>ARexx examples</b>
Stop the the time synchronization process with:
Address TIMEKEEPER.1 stop
@@ -253,13 +411,15 @@ The arexx folder contains a set of sample scripts.
<b>TimeCtrl</b>
Controlling TimeKeeper without using ARexx is done through the
control utility TimeCtrl. The following commands are available.
control utility <i>TimeCtrl</i>. The following commands are available.
<b>Command</b> | <b>Description</b>
-----------------------------------------------------------------
ID | Get application identifier
VERSION | Get application version number
STATUS | Get current synchronization status
TIME | Get current time and date
ZONE | Get current time zone
START | Start the time synchronization process
STOP | Stop the time synchronization process
SHOW | Show settings window
@@ -269,23 +429,24 @@ SHUTDOWN | Shutdown TimeKeeper
</pre>
</div>
<div id="the+posix+tz+environment+variable">
<div id="posix+tz+environment+variable">
<hr/>
<p><b>TimeKeeper.guide/The POSIX TZ environment variable</b></p>
<p><b>TimeKeeper.guide/POSIX TZ environment variable</b></p>
<p><a href="#main">Contents</a> <a href="#index">Index</a> <a>Help</a> <a href="#arexx+interface">Prev</a> <a href="#change+log">Next</a> </p>
<pre>
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.
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.
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.
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
@@ -730,6 +891,17 @@ Pacific/Wallis TZ &lt;GMT+12>-12
<p><a href="#main">Contents</a> <a href="#index">Index</a> <a>Help</a> <a href="#saving+preferences">Prev</a> <a href="#software+license">Next</a> </p>
<pre>
<b>v1.12 31.01.2021</b>
- New options to specify the local time zone
- New ARexx commands, parameters and error variables
- New option to start without active time synchronization
- New deactivate logging option for performance saving
- More bugs in calculation of time zone transition fixed
- Sanity check on value for interval between requests
- Updated ARexx documentation and script
- Honour ARexx result flag (RXFF_RESULT)
- Various minor bug fixes and improvements
<b>v1.11 11.01.2021</b>
- New dedicated external control utility
- New ARexx port with a diverse set of commands
@@ -810,6 +982,11 @@ Pacific/Wallis TZ &lt;GMT+12>-12
<p><a href="#main">Contents</a> <a href="#index">Index</a> <a>Help</a> <a href="#change+log">Prev</a> <a href="#credits+and+donations">Next</a> </p>
<pre>
<b>Bug reports</b>
Please report bugs and other issues by sending a mail or using:
https://ranger.innolan.net/rainlance/AmiTimeKeeper
<b>Simplified BSD License / 2-clause BSD license</b>
Copyright (c) 2001, 02 Motoyuki Kasahara
@@ -846,17 +1023,13 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<p><a href="#main">Contents</a> <a href="#index">Index</a> <a>Help</a> <a href="#software+license">Prev</a> <a href="#contacting+the+author">Next</a> </p>
<pre>
A custom version has been integrated into the Icaros Desktop system.
The author encourages all developers with an interest to make their own
build.
The following people have contributed with bug reports, comments,
suggestions and donations:
* aPEX from a1k.org
* Greg Donner
* Paolo Besser
* Knut Hansen
* Greg Donner
* Thomas Blatt
* Bartosz Makara
* Benny Damsgaard
@@ -892,13 +1065,70 @@ January 2021
<b>A</b>
<a href="#configuring+the+client">Adjustment threshold</a>
<a href="#arexx+interface">ARexx interface</a>
<a href="#configuring+the+client">Automatically synchronization</a>
<b>C</b>
<a href="#configuring+the+client">Configution</a>
<a href="#configuring+the+client">Connection time out</a>
<a href="#using+tooltypes+of+an+icon">CLI</a>
<b>D</b>
<a href="#configuring+the+client">Daylight saving time</a>
<b>E</b>
<a href="#local+time+zone">Environment variable</a>
<a href="#configuring+the+client">Expert mode</a>
<b>I</b>
<a href="#configuring+the+client">Interval between requests</a>
<a href="#arexx+interface">ISO8601</a>
<b>K</b>
<a href="#arexx">Keywords</a>
<a href="#configuring+the+client">ACTIVE - Automatically synchronization</a>
<a href="#arexx+interface">ASCII</a>
<a href="#using+tooltypes+of+an+icon">CX_POPKEY</a>
<a href="#using+tooltypes+of+an+icon">CX_POPUP</a>
<a href="#using+tooltypes+of+an+icon">CX_PRIORITY</a>
<a href="#arexx+interface">DATE</a>
<a href="#using+tooltypes+of+an+icon">DONOTWAIT</a>
<a href="#arexx+interface">DOS</a>
<a href="#configuring+the+client">DST - Daylight saving time</a>
<a href="#configuring+the+client">EXPERT - Expert mode</a>
<a href="#configuring+the+client">INTERVAL - Interval between requests</a>
<a href="#arexx+interface">ISO8601</a>
<a href="#arexx+interface">LOCAL</a>
<a href="#configuring+the+client">NOLOG - Logging</a>
<a href="#arexx+interface">NUMBER</a>
<a href="#configuring+the+client">POPUP</a>
<a href="#configuring+the+client">PORT - Server port</a>
<a href="#configuring+the+client">READONLY</a>
<a href="#arexx+interface">RFC850</a>
<a href="#arexx+interface">RFC1123</a>
<a href="#arexx+interface">RFC2822</a>
<a href="#arexx+interface">RFC3339</a>
<a href="#configuring+the+client">SERVER - Server address</a>
<a href="#configuring+the+client">THRESHOLD - Adjustment threshold</a>
<a href="#arexx+interface">TIME</a>
<a href="#configuring+the+client">TIMEOUT - Connection time out</a>
<a href="#configuring+the+client">TIMEZONE - Time zone</a>
<a href="#configuring+the+client">TIMEZONEABBREVIATION - Time zone abbreviation</a>
<a href="#configuring+the+client">TIMEZONEDISPLAY - Time zone display</a>
<a href="#configuring+the+client">TIMEZONEVALUE - Time zone value</a>
<a href="#configuring+the+client">TZ - Time zone</a>
<a href="#configuring+the+client">TZD - Time zone display</a>
<a href="#configuring+the+client">TZDST - Daylight saving time</a>
<a href="#configuring+the+client">TZNAME - Time zone abbreviation</a>
<a href="#configuring+the+client">TZVALUE - Time zone value</a>
<a href="#arexx+interface">UTC</a>
<b>L</b>
<a href="#configuring+the+client">Logging</a>
@@ -910,35 +1140,62 @@ January 2021
<b>P</b>
<a href="#configuring+the+client">Pool servers</a>
<a href="#the+posix+tz+environment+variable">Posix</a>
<a href="#using+tooltypes+of+an+icon">Popkey</a>
<a href="#using+tooltypes+of+an+icon">Popup</a>
<a href="#posix+tz+environment+variable">Posix</a>
<a href="#saving+preferences">Preferences</a>
<a href="#using+tooltypes+of+an+icon">Priority</a>
<b>R</b>
<a href="#configuring+the+client">Read only</a>
<a href="#arexx+interface">RFC850</a>
<a href="#arexx+interface">RFC1123</a>
<a href="#arexx+interface">RFC2822</a>
<a href="#arexx+interface">RFC3339</a>
<b>S</b>
<a href="#configuring+the+client">Server address</a>
<a href="#configuring+the+client">Server port</a>
<a href="#configuring+the+client">Settings</a>
<a href="#configuring+the+client">Connection timeout</a>
<a href="#configuring+the+client">Automatically synchronization</a>
<a href="#configuring+the+client">Connection time out</a>
<a href="#configuring+the+client">Daylight saving time</a>
<a href="#configuring+the+client">Expert mode </a>
<a href="#configuring+the+client">Interval</a>
<a href="#configuring+the+client">Interval between requests</a>
<a href="#configuring+the+client">Logging</a>
<a href="#configuring+the+client">Popkey</a>
<a href="#configuring+the+client">Popup</a>
<a href="#configuring+the+client">Priority</a>
<a href="#using+tooltypes+of+an+icon">Popkey</a>
<a href="#using+tooltypes+of+an+icon">Popup</a>
<a href="#using+tooltypes+of+an+icon">Priority</a>
<a href="#configuring+the+client">Read only</a>
<a href="#configuring+the+client">Server address</a>
<a href="#configuring+the+client">Server port</a>
<a href="#configuring+the+client">Threshold</a>
<a href="#the+posix+tz+environment+variable">Standard time</a>
<a href="#the+posix+tz+environment+variable">Summer time</a>
<a href="#configuring+the+client">Time zone</a>
<a href="#configuring+the+client">Time zone abbreviation</a>
<a href="#configuring+the+client">Time zone display</a>
<a href="#configuring+the+client">Time zone value</a>
<a href="#configuring+the+client">Standard time</a>
<a href="#configuring+the+client">Startup Sequence</a>
<a href="#configuring+the+client">Summer time</a>
<b>T</b>
<a href="#configuring+the+client">Threshold</a>
<a href="#arexx+interface">TimeCtrl</a>
<a href="#configuring+the+client">TimeLogger</a>
<a href="#main">Time zone</a>
<a href="#local+time+zone">Time zone</a>
<a href="#arexx+interface">Getting</a>
<a href="#main">Setting</a>
<a href="#local+time+zone">Setting</a>
<a href="#configuring+the+client">Time zone abbreviation</a>
<a href="#configuring+the+client">Time zone display</a>
<a href="#local+time+zone">Time zone value</a>
<a href="#using+tooltypes+of+an+icon">Tool types</a>
<a href="#the+posix+tz+environment+variable">TZ</a>
<a href="#local+time+zone">TZ</a>
<a href="#posix+tz+environment+variable">Content</a>
<a href="#local+time+zone">Setting</a>
<a href="#local+time+zone">TZONE</a>
</pre>
</div>
+16 -20
View File
@@ -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.11
Version: 1.12
Architecture: m68k-amigaos
AmiTimeKeeper is a small program which keeps the time right on your
@@ -21,29 +21,25 @@ try visiting support.ntp.org or one of the other sites listing time
servers. Use a fixed pool server by prefixing the domain, for example,
1.pool.ntp.org.
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.
The time zone needs to be configured using Workbench preferences or
a similar tool. In Amiga OS this is available through the Locale
Preferences Editor. The local time zone and daylight saving time are
optionally specified manually or using a POSIX TZ variable style.
The Icaros Desktop system is distributed with a custom build version of
AmiTimeKeeper. The author encourages everyone with an interest to build
their own version.
Version 1.11 has two known issues:
- Settings window in AROS is broken (and disabled in this version)
- Setting Popkey is not supported in ARexx
Please report bugs and other issues by sending a mail or using:
https://ranger.innolan.net/rainlance/AmiTimeKeeper
Changes in v1.11, 11.01.2021
- New dedicated external control utility
- New ARexx port with a diverse set of commands
- Rewritten logger facility with more verbose output
- Bug preventing commodity to shutdown fixed
- Bug in CLI SWITCH parameters reporting wrong values fixed
- Support AmigaOS 1.3 (v34) but without settings window
- Time zone information displayed using GMT instead of UTC
- Only watch current env variable for time zone changes
- Improved validation of application settings
- Several dead and duplicated code blocks removed
v1.12 31.01.2021
- New options to specify the local time zone
- New ARexx commands, parameters and error variables
- New option to start without active time synchronization
- New deactivate logging option for performance saving
- More bugs in calculation of time zone transition fixed
- Sanity check on value for interval between requests
- Updated ARexx documentation and script
- Honour ARexx result flag (RXFF_RESULT)
- Various minor bug fixes and improvements
- Documentation in HTML format
-743
View File
@@ -1,743 +0,0 @@
/*
** This file is in the public domain.
*/
#include "amiga.h"
#include "private.h"
#include <dos/var.h>
#include <devices/timer.h>
#include <libraries/locale.h>
#include <utility/date.h>
/* Amiga convert functions */
void Amiga2Tm(ULONG seconds, struct tm *tm);
ULONG Tm2Amiga(struct tm *tm);
ULONG Unix2Amiga(time_t t);
time_t Amiga2Unix(ULONG t);
void Tm2DateStamp(struct tm *tm, struct DateStamp *date);
void DateStamp2Tm(struct DateStamp *date, struct tm *tm);
void Unix2DateStamp(time_t *time, struct DateStamp *date);
void DateStamp2Unix(struct DateStamp *date, time_t *time);
void Tm2Date(struct tm *tm, struct ClockData *date);
void Date2Tm(struct ClockData *date, struct tm *tm);
void Date2Unix(struct ClockData *date, time_t *time);
void Unix2Date(time_t *time, struct ClockData *date);
static struct timerequest *TimeRequest;
static struct MsgPort *TimerPort;
const struct lc_time_T C_time_locale = {
{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"},
{"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"},
{"Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat"},
{"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"},
/* X_fmt */
"%H:%M:%S",
/*
** x_fmt
** C99 requires this format.
** Using just numbers (as here) makes Quakers happier;
** it's also compatible with SVR4.
*/
"%m/%d/%y",
/*
** c_fmt
** C99 requires this format.
** Previously this code used "%D %X", but we now conform to C99.
** Note that
** "%a %b %d %H:%M:%S %Y"
** is used by Solaris 2.3.
*/
"%a %b %e %T %Y",
/* t_fmt_ampm */
"TODO",
/* am */
"AM",
/* pm */
"PM",
/* am_pm */
{ "TODOAM", "TODOPM"},
/* date_fmt */
"%a %b %e %H:%M:%S %Z %Y"};
static int
CreateTimer()
{
int error;
TimerPort = CreateMsgPort();
if (TimerPort == NULL)
{
return 1;
}
TimeRequest = (struct timerequest *)CreateIORequest(
TimerPort,
sizeof(struct timerequest));
if (TimeRequest == NULL)
{
DeleteMsgPort(TimerPort);
return 2;
}
error = OpenDevice(
(STRPTR)TIMERNAME,
UNIT_MICROHZ,
(struct IORequest *)TimeRequest,
0);
if (error != 0)
{
DeleteIORequest((struct IORequest *)TimeRequest);
DeleteMsgPort(TimerPort);
return 3;
}
TimerBase = (struct Device *)TimeRequest->tr_node.io_Device;
return 0;
}
static void
DeleteTimer()
{
TimerBase = NULL;
if (TimeRequest != NULL)
{
if (!CheckIO((struct IORequest *)TimeRequest))
{
WaitIO((struct IORequest *)TimeRequest);
}
CloseDevice((struct IORequest *)TimeRequest);
DeleteIORequest((struct IORequest *)TimeRequest);
TimeRequest = NULL;
}
if (TimerPort != NULL)
{
DeleteMsgPort(TimerPort);
TimerPort = NULL;
}
}
int gmtoffset(time_t locale_time)
{
struct tm tm;
time_t time = locale_time;
localtime_r(&time, &tm);
return tm.tm_gmtoff;
}
int gettimeofday(struct timeval *tv, void *tz)
{
long zone;
if (tv == NULL)
{
return -1;
}
if (TimerSemaphore != NULL)
{
ObtainSemaphore(TimerSemaphore);
}
if (CreateTimer() != 0)
{
if (TimerSemaphore != NULL)
{
ReleaseSemaphore(TimerSemaphore);
}
return -1;
}
zone = gmtoffset(tv->tv_secs);
TimeRequest->tr_node.io_Command = TR_GETSYSTIME;
DoIO((struct IORequest *)TimeRequest);
tv->tv_secs = (long)TimeRequest->tr_time.tv_secs + EPOCH_OFFSET + zone;
tv->tv_micro = TimeRequest->tr_time.tv_micro;
DeleteTimer();
if (TimerSemaphore != NULL)
{
ReleaseSemaphore(TimerSemaphore);
}
return 0;
}
int settimeofday(const struct timeval *tv, void *tz)
{
long zone;
if (tv == NULL)
{
return -1;
}
if (TimerSemaphore != NULL)
{
ObtainSemaphore(TimerSemaphore);
}
if (CreateTimer() != 0)
{
if (TimerSemaphore != NULL)
{
ReleaseSemaphore(TimerSemaphore);
}
return -1;
}
zone = gmtoffset(tv->tv_secs);
TimeRequest->tr_node.io_Command = TR_SETSYSTIME;
TimeRequest->tr_time.tv_secs = (long)tv->tv_secs - EPOCH_OFFSET - zone;
TimeRequest->tr_time.tv_micro = tv->tv_micro;
DoIO((struct IORequest *)TimeRequest);
DeleteTimer();
if (TimerSemaphore != NULL)
{
ReleaseSemaphore(TimerSemaphore);
}
return 0;
}
int getsystime(struct timeval *tv)
{
if (tv == NULL)
{
return -1;
}
if (TimerSemaphore != NULL)
{
ObtainSemaphore(TimerSemaphore);
}
if (CreateTimer() != 0)
{
if (TimerSemaphore != NULL)
{
ReleaseSemaphore(TimerSemaphore);
}
tv->tv_secs = 0;
tv->tv_micro = 0;
return -1;
}
#ifdef AROS
TimeRequest->tr_node.io_Command = TR_GETSYSTIME;
DoIO((struct IORequest *)TimeRequest);
tv->tv_secs = TimeRequest->tr_time.tv_secs;
tv->tv_micro = 0;
#else
{
struct timeval tv1;
GetSysTime(&tv1);
*tv = tv1;
}
#endif
DeleteTimer();
if (TimerSemaphore != NULL)
{
ReleaseSemaphore(TimerSemaphore);
}
return 0;
}
int setsystime(struct timeval *tv)
{
if (tv == NULL)
{
return -1;
}
if (TimerSemaphore != NULL)
{
ObtainSemaphore(TimerSemaphore);
}
if (CreateTimer() != 0)
{
if (TimerSemaphore != NULL)
{
ReleaseSemaphore(TimerSemaphore);
}
return -1;
}
TimeRequest->tr_node.io_Command = TR_SETSYSTIME;
TimeRequest->tr_time.tv_secs = (long)tv->tv_secs;
TimeRequest->tr_time.tv_micro = tv->tv_micro;
DoIO((struct IORequest *)TimeRequest);
DeleteTimer();
if (TimerSemaphore != NULL)
{
ReleaseSemaphore(TimerSemaphore);
}
return 0;
}
#if defined(__AROS__)
int *__stdc_geterrnoptr(void)
{
return &errno;
}
#endif
int daylight_c(void)
{
return daylight;
}
long Timezone_c(void)
{
return Timezone;
}
long altzone_c(void)
{
return altzone;
}
char **tzname_c(void)
{
return (char **)tzname;
}
/*
struct lc_time_T *_current_locale()
{
return (struct lc_time_T *)&C_time_locale;
}
size_t
_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,
const char *const format, const struct tm *const t, locale_t locale)
{
size_t res;
struct lc_time_T *l = openlc(locale);
res = _strftime(sp, s, maxsize, format, t, l);
closelc(l);
return res;
}
*/
struct lc_time_T *openlc(locale_t locale)
{
int i, j;
struct lc_time_T *l = (struct lc_time_T *)AllocMem(
sizeof(struct lc_time_T),
MEMF_ANY | MEMF_CLEAR);
struct Locale *loc = locale;
if (!loc)
{
loc = OpenLocale(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->locale = loc;
return l;
}
void closelc(struct lc_time_T *lc)
{
if (lc->locale)
{
CloseLocale(lc->locale);
}
FreeMem(lc, sizeof(struct lc_time_T));
}
/* Similar to intuition.library CurrentTime */
void CurrentTimeGmt(ULONG *seconds, ULONG *micros)
{
ULONG sec, mic;
CurrentTime(&sec, &mic);
*seconds = sec + (daylight ? altzone : Timezone);
*micros = mic;
}
struct tm *AmigaLocalTime(ULONG *seconds, struct tm *tm)
{
time_t time;
if (tm == NULL)
{
return NULL;
}
if (seconds == NULL)
{
/* Amiga Epoch time */
Date2Tm(NULL, tm);
return tm;
}
time = Amiga2Unix(*seconds);
localtime_r(&time, tm);
return tm;
}
struct tm *AmigaLocalTimeZ(ULONG *seconds, struct tm *tm, const Timezone_t tz)
{
time_t time;
if (tm == NULL)
{
return NULL;
}
if (seconds == NULL)
{
/* Amiga Epoch time */
Date2Tm(NULL, tm);
return tm;
}
time = Amiga2Unix(*seconds);
localtime_rz(tz, &time, tm);
return tm;
}
/* Similar to locale.library FormatDate */
void FormatDateTm(char *const s, const char *format, struct tm *tm,
char *buffer, long maxsize)
{
strftime(s, maxsize, format, tm);
}
/* Similar to locale.library ParseDate */
int ParseDateTm(struct Locale *locale, const char *format, struct tm *tm,
const char *string)
{
// TODO
return 0;
}
/* Similar to utility.library Amiga2Date.
Fills in a tm structure with the date and time calculated
from a ULONG containing the number of seconds from 01-Jan-1978
to the date. */
void Amiga2Tm(ULONG seconds, struct tm *tm)
{
struct tm tmp;
time_t t;
if (tm == NULL)
{
return;
}
t = seconds + EPOCH_OFFSET;
localtime_r(&t, &tmp);
t = seconds + EPOCH_OFFSET - tmp.tm_gmtoff;
localtime_r(&t, tm);
}
/* Similar to utility.library Date2Amiga.
Calculates the number of seconds from 01-Jan-1978 to the date
specified in the tm structure. */
ULONG Tm2Amiga(struct tm *tm)
{
time_t time;
if (tm == NULL)
{
/* Amiga Epoch time */
return 0;
}
time = timelocal(tm);
return time - EPOCH_OFFSET;
}
/* Convert between Unix Time Epoch and Amiga Time Epoch */
ULONG Unix2Amiga(time_t t)
{
return t - EPOCH_OFFSET;
}
time_t Amiga2Unix(ULONG t)
{
return t + EPOCH_OFFSET;
}
/* Convert to and from DateStamp */
void Tm2DateStamp(struct tm *tm, struct DateStamp *date)
{
time_t time;
struct tm tmp = *tm;
if (date == NULL)
{
return;
}
if (tm == NULL)
{
/* UNIX Epoch time */
time = 0;
}
else
{
time = mktime(&tmp);
}
Unix2DateStamp(&time, date);
}
void DateStamp2Tm(struct DateStamp *date, struct tm *tm)
{
time_t time;
if (tm == NULL)
{
return;
}
if (date == NULL)
{
Date2Tm(NULL, tm);
return;
}
DateStamp2Unix(date, &time);
gmtime_r(&time, tm);
}
void Unix2DateStamp(time_t *time, struct DateStamp *date)
{
long t, d, m, q;
if (date == NULL)
{
return;
}
if (time == NULL)
{
/* Amiga Epoch time */
date->ds_Days = 0;
date->ds_Minute = 0;
date->ds_Tick = 0;
return;
}
t = *time - EPOCH_OFFSET;
d = t / SECONDSPERDAY;
m = (t - SECONDSPERDAY * d) / 60;
q = (t - SECONDSPERDAY * d - m * 60) * 60; // TODO: Ticks = 50
date->ds_Days = d;
date->ds_Minute = m;
date->ds_Tick = q;
}
void DateStamp2Unix(struct DateStamp *date, time_t *time)
{
if (time == NULL)
{
return;
}
if (date == NULL)
{
/* Amiga Epoch time */
*time = EPOCH_OFFSET;
return;
}
*time = date->ds_Days * SECONDSPERDAY +
date->ds_Minute * 60 +
date->ds_Tick / 60 +
EPOCH_OFFSET;
}
/* Convert from tm to ClockData */
void Tm2Date(struct tm *tm, struct ClockData *date)
{
if (date == NULL)
{
return;
}
if (tm == NULL)
{
/* UNIX Epoch time */
date->sec = 0;
date->min = 0;
date->hour = 0;
date->mday = 1;
date->month = 1;
date->year = EPOCH_YEAR;
date->wday = EPOCH_WDAY;
return;
}
date->sec = (UWORD)tm->tm_sec;
date->min = (UWORD)tm->tm_min;
date->hour = (UWORD)tm->tm_hour;
date->mday = (UWORD)tm->tm_mday;
date->month = (UWORD)tm->tm_mon + 1;
date->year = (UWORD)tm->tm_year + TM_YEAR_BASE + EPOCH_OFFSET_YEAR;
date->wday = (UWORD)tm->tm_wday;
/* tm allow seconds in interval [0-61] */
if (date->sec > 59)
{
date->sec = 59;
}
}
/* Convert from ClockData to tm */
void Date2Tm(struct ClockData *date, struct tm *tm)
{
if (tm == NULL)
{
return;
}
if (date == NULL)
{
/* Amiga Epoch time */
tm->tm_sec = 0;
tm->tm_min = 0;
tm->tm_hour = 0;
tm->tm_mday = 1;
tm->tm_mon = 0;
tm->tm_year = EPOCH_YEAR + EPOCH_OFFSET_YEAR - TM_YEAR_BASE;
mktime(tm);
return;
}
tm->tm_sec = (int)date->sec;
tm->tm_min = (int)date->min;
tm->tm_hour = (int)date->hour;
tm->tm_mday = (int)date->mday;
tm->tm_mon = (int)date->month - 1;
tm->tm_year = (int)date->year - TM_YEAR_BASE - EPOCH_OFFSET_YEAR;
tm->tm_wday = (int)date->wday;
mktime(tm);
}
void Date2Unix(struct ClockData *date, time_t *time)
{
struct tm tm;
if (time == NULL)
{
return;
}
if (date == NULL)
{
/* UNIX Epoch time */
*time = 0;
return;
}
Date2Tm(date, &tm);
mktime(&tm);
}
void Unix2Date(time_t *time, struct ClockData *date)
{
struct tm tm;
time_t t;
if (date == NULL)
{
return;
}
if (time == NULL)
{
/* UNIX Epoch time */
Tm2Date(NULL, date);
return;
}
t = *time;
gmtime_r(&t, &tm);
Tm2Date(&tm, date);
}
#undef time
#undef time_t
time_t
time(time_t *x)
{
time_t tloc;
ULONG sec, mic;
CurrentTime(&sec, &mic);
tloc = (time_t)(sec);
if (x)
{
*x = tloc;
}
return tloc;
}
-157
View File
@@ -1,157 +0,0 @@
/*
** This file is in the public domain.
*/
#ifndef AMIGA_H
#define AMIGA_H
/* Used by localtime.c but not by amiga */
#define O_CLOEXEC 0
#define _DIAGASSERT(x)
#define __aconst
/* Used by amiga.c */
#define SECONDSPERDAY 86400
/*
* The following macro is used to remove const cast-away warnings
* from gcc -Wcast-qual; it should be used with caution because it
* can hide valid errors; in particular most valid uses are in
* situations where the API requires it, not to cast away string
* constants. We don't use *intptr_t on purpose here and we are
* explicit about unsigned long so that we don't have additional
* dependencies.
*/
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#define NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU 1
#define HAVE_STRFTIME_L 0
/* Thread safety */
#define rwlock_wrlock(x)
#define rwlock_unlock(x)
#define TIME_MAX ULONG_MAX
#include <stdarg.h>
#include <stddef.h>
#include "mem.h"
#define TZLIB_NAME "tz.library"
#define VERSION_NO 7
#define VERSION_TEXT "7"
#define REVISION_NO 00
#define REVISION_TEXT "00"
#define DATE_TEXT "10.01.2018"
#define VERS TZLIB_NAME " " VERSION_TEXT "." REVISION_TEXT
#define VSTRING TZLIB_NAME " " VERSION_TEXT "." REVISION_TEXT \
"(" DATE_TEXT ")\r\n"
#define VERSTAG "\0$VER: " TZLIB_NAME " " VERSION_TEXT "." REVISION_TEXT \
"(" DATE_TEXT ")"
#define TZVARIABLE1 "TZ"
#define TZVARIABLE2 "Timezone.prefs"
#define TZVARIABLE TZVARIABLE1
#define ENVSIZE 128
#include <exec/io.h>
#include <proto/exec.h>
#include <inline/exec.h>
#include <proto/dos.h>
#include <inline/dos.h>
#include <proto/locale.h>
#include <inline/locale.h>
#include <proto/timer.h>
#include <inline/timer.h>
#include <proto/intuition.h>
#include <inline/intuition.h>
#ifndef REG
#define REG(reg, arg) arg __asm(#reg)
#endif
#ifndef UNUSED
#define UNUSED __attribute__((unused))
#endif
typedef struct Locale *locale_t;
struct lc_time_T
{
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; // TODO
const char *am;
const char *pm;
const char *am_pm[2]; // TODO
const char *date_fmt;
locale_t locale;
};
#undef ctime_rz
#define ctime_rz tz_ctime_rz
#undef tzgetgmtoff
#define tzgetgmtoff tz_tzgetgmtoff
#undef timelocal_z
#define timelocal_z tz_timelocal_z
#undef tzgetname
#define tzgetname tz_tzgetname
#undef offtime_r
#define offtime_r tz_offtime_r
#undef tzgetlocation
#define tzgetlocation tz_tzgetlocation
#undef snprintf
#define snprintf SNPrintf
/* amiga.c tz functions */
int daylight_c(void);
long Timezone_c(void);
long altzone_c(void);
char **tzname_c(void);
int getsystime(struct timeval *tv);
int setsystime(struct timeval *tv);
int gettimeofday(struct timeval *tv, void *tz);
int settimeofday(const struct timeval *tv, void *tz);
/* amiga.c internals */
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 altzone;
extern int daylight;
extern struct SignalSemaphore *TimerSemaphore;
/* string.c */
void bcopy(const void *src, void *dest, size_t len); // <string.h>
void *memmove(void *dest, const void *src, size_t len); // <string.h>
size_t strlen(const char *string); // <string.h>
char *strcpy(char *dest, const char *src); // <string.h>
char *strcat(char *dest, const char *src); // <string.h>
int strcmp(const char *s1, const char *s2); // <string.h>
char *strchr(const char *s, int c); // <string.h>
int strncmp(const char *s1, const char *s2, size_t n); // <string.h>
char *getenv(const char *name); // <stdlib.h>
int isdigit(char c);
int isspace(char c);
int isalpha(char c);
int toupper(char c);
int strncasecmp(const char *_s1, const char *_s2, size_t n);
int SNPrintf(char *str, size_t size, const char *format, ...);
#if defined(__GNUC__) && (__GNUC__ < 3)
void *memcpy(void *dst, const void *src, unsigned long len);
#else
void *memcpy(void *dst, const void *src, size_t len);
#endif
void *memset(void *str, int c, size_t n);
extern struct ExecBase *SysBase;
extern int errno;
#endif
+458 -168
View File
@@ -38,6 +38,8 @@
#include "tz.h"
#include <proto/rexxsyslib.h>
#include <proto/alib.h>
#include <rexx/errors.h>
#include <rexx/storage.h>
#include <rexx/rxslib.h>
@@ -46,64 +48,66 @@
static char *arexxHelpText = NULL;
typedef void (*ArexxCommand)(struct RexxMsg *, char **);
typedef void (*ARexxCommand)(struct RexxMsg *, char **);
struct ArexxCommandDef
struct ARexxCommandDef
{
/* Unique numeric command identifier */
const int Identifier;
/* Command name as exposed in ARexx interface */
const char *Name;
/* Short description of command purpose */
const char *Description;
ArexxCommand Command;
/* Function pointer to action code */
ARexxCommand Command;
/* True if command only return a result. False is command is an action */
bool ResultCommand;
/* Number of parameters / arguments */
int Parameters;
};
struct ArexxParameterDef
struct ARexxParameterDef
{
const int Identifier;
const char *Keyword;
};
static void ArexxIdentifierCommand(struct RexxMsg *, char **);
static void ArexxVersionCommand(struct RexxMsg *, char **);
static void ArexxHelpCommand(struct RexxMsg *, char **);
static void ArexxStatusCommand(struct RexxMsg *, char **);
static void ArexxTimezoneCommand(struct RexxMsg *msg, char **);
static void ArexxLastSyncCommand(struct RexxMsg *msg, char **);
static void ArexxLastAdjustCommand(struct RexxMsg *msg, char **);
static void ArexxGetValueCommand(struct RexxMsg *, char **);
static void ArexxSetValueCommand(struct RexxMsg *, char **);
static void ArexxShowCommand(struct RexxMsg *, char **);
static void ArexxHideCommand(struct RexxMsg *, char **);
static void ArexxStartCommand(struct RexxMsg *, char **);
static void ArexxStopCommand(struct RexxMsg *, char **);
static void ArexxShutdownCommand(struct RexxMsg *, char **);
static void ARexxIdentifierCommand(struct RexxMsg *, char **);
static void ARexxVersionCommand(struct RexxMsg *, char **);
static void ARexxHelpCommand(struct RexxMsg *, char **);
static void ARexxStatusCommand(struct RexxMsg *, char **);
static void ARexxTimezoneCommand(struct RexxMsg *msg, char **);
static void ARexxLastSyncCommand(struct RexxMsg *msg, char **);
static void ARexxLastAdjustCommand(struct RexxMsg *msg, char **);
static void ARexxGetValueCommand(struct RexxMsg *, char **);
static void ARexxSetValueCommand(struct RexxMsg *, char **);
static void ARexxNowCommand(struct RexxMsg *, char **);
static void ARexxShowCommand(struct RexxMsg *, char **);
static void ARexxHideCommand(struct RexxMsg *, char **);
static void ARexxStartCommand(struct RexxMsg *, char **);
static void ARexxStopCommand(struct RexxMsg *, char **);
static void ARexxShutdownCommand(struct RexxMsg *, char **);
static void ARexxLogTransitionsCommand(struct RexxMsg *, char **);
#define AREXX_COMMAND_OK 0
#define AREXX_COMMAND_ERROR 1
#define AREXX_COMMAND_UNKNOWN 10
#define AREXX_COMMAND_PARM_UNKNOWN 11
#define AREXX_COMMAND_PARM_INVALID 12
#define AREXX_COMMAND_SHUTDOWN 99
#define AREXX_COMMAND_COUNT 16
static struct ARexxCommandDef arexxCommands[] = {
{1, "ID", "Get application identifier", ARexxIdentifierCommand, true, 0},
{2, "VERSION", "Get application version number", ARexxVersionCommand, true, 0},
{3, "HELP", "Get a list of ARexx commands and a short description", ARexxHelpCommand, true, 0},
{4, "STATUS", "Get current synchronization status", ARexxStatusCommand, true, 1},
{5, "TIMEZONE", "Get current time zone", ARexxTimezoneCommand, true, 1},
{6, "LASTSYNC", "Get time of last synchronization operation", ARexxLastSyncCommand, true, 2},
{7, "LASTADJ", "Get time of last clock adjustment", ARexxLastAdjustCommand, true, 2},
{8, "GET", "Get a runtime configuration value", ARexxGetValueCommand, true, 1},
{9, "SET", "Set a runtime configuration value", ARexxSetValueCommand, false, 2},
{10, "NOW", "Get current time and date", ARexxNowCommand, false, 2},
{11, "SHOW", "Show settings window", ARexxShowCommand, false, 0},
{12, "HIDE", "Hide settings window", ARexxHideCommand, false, 0},
{13, "START", "Start the time synchronization process", ARexxStartCommand, false, 0},
{14, "STOP", "Stop the time synchronization process", ARexxStopCommand, false, 0},
{15, "SHUTDOWN", "Shutdown " APP_SHORT_NAME, ARexxShutdownCommand, false, 0},
{16, "LOGTRANS", "Emit time zone transition map to log", ARexxLogTransitionsCommand, false, 0}};
static struct ArexxCommandDef arexxCommands[] = {
{1, "ID", "Get application identifier", ArexxIdentifierCommand, 0},
{2, "VERSION", "Get application version number", ArexxVersionCommand},
{3, "HELP", "Get a list of ARexx commands and a short description", ArexxHelpCommand, 0},
{4, "STATUS", "Get current synchronization status", ArexxStatusCommand, 0},
{5, "TIMEZONE", "Get current time zone", ArexxTimezoneCommand, 0},
{6, "LASTSYNC", "Get time of last synchronization operation", ArexxLastSyncCommand, 0},
{7, "LASTADJ", "Get time of last clock adjustment", ArexxLastAdjustCommand, 0},
{8, "GET", "Get a runtime configuration value", ArexxGetValueCommand, 1},
{9, "SET", "Set a runtime configuration value", ArexxSetValueCommand, 2},
{10, "SHOW", "Show settings window", ArexxShowCommand, 0},
{11, "HIDE", "Hide settings window", ArexxHideCommand, 0},
{12, "START", "Start the time synchronization process", ArexxStartCommand, 0},
{13, "STOP", "Stop the time synchronization process", ArexxStopCommand, 0},
{14, "SHUTDOWN", "Shutdown " APP_SHORT_NAME, ArexxShutdownCommand, 0}};
#define AREXX_COMMAND_COUNT 14
#define AREXX_PARAMETER_UNKNOWN 0
#define AREXX_PARAMETER_SERVER 1
#define AREXX_PARAMETER_PORT 2
#define AREXX_PARAMETER_THRESHOLD 3
@@ -114,8 +118,21 @@ static struct ArexxCommandDef arexxCommands[] = {
#define AREXX_PARAMETER_READONLY 8
#define AREXX_PARAMETER_EXPERT 9
#define AREXX_PARAMETER_TIMEOUT 10
#define AREXX_PARAMETER_ACTIVE 11
#define AREXX_PARAMETER_NOLOG 12
#define AREXX_PARAMETER_TZ 13
#define AREXX_PARAMETER_TZD 14
#define AREXX_PARAMETER_TZNAME 15
#define AREXX_PARAMETER_TZVALUE 16
#define AREXX_PARAMETER_TZDST 17
#define AREXX_PARAMETER_LAST 17
static struct ArexxParameterDef arexxParameters[] = {
#define AREXX_PARAMETER_UNKNOWN 90
#define AREXX_PARAMETER_MISSING 91
#define AREXX_PARAMETER_SHUTDOWN 92
#define AREXX_PARAMETER_COUNT AREXX_PARAMETER_LAST
static struct ARexxParameterDef arexxParameters[] = {
{AREXX_PARAMETER_SERVER, KEYWORD_SERVER},
{AREXX_PARAMETER_PORT, KEYWORD_PORT},
{AREXX_PARAMETER_THRESHOLD, KEYWORD_THRESHOLD},
@@ -125,12 +142,43 @@ static struct ArexxParameterDef arexxParameters[] = {
{AREXX_PARAMETER_POPUP, KEYWORD_POPUP},
{AREXX_PARAMETER_READONLY, KEYWORD_READONLY},
{AREXX_PARAMETER_EXPERT, KEYWORD_EXPERT},
{AREXX_PARAMETER_TIMEOUT, KEYWORD_TIMEOUT}};
#define AREXX_PARAMETER_COUNT 10
{AREXX_PARAMETER_TIMEOUT, KEYWORD_TIMEOUT},
{AREXX_PARAMETER_ACTIVE, KEYWORD_ACTIVE},
{AREXX_PARAMETER_NOLOG, KEYWORD_NOLOG},
{AREXX_PARAMETER_TZ, KEYWORD_TZ},
{AREXX_PARAMETER_TZD, KEYWORD_TZD},
{AREXX_PARAMETER_TZNAME, KEYWORD_TZNAME},
{AREXX_PARAMETER_TZVALUE, KEYWORD_TZVALUE},
{AREXX_PARAMETER_TZDST, KEYWORD_TZDST}};
#define AREXX_MAX_ARGS_COUNT 8
struct ARexxErrorDef
{
const long Code;
const char **Text;
};
#define AREXX_ERROR_UNKNOWN_CMD 10 /* Unknown ARexx command */
#define AREXX_ERROR_UNKNOWN_PARM 11 /* Unknown parameter */
#define AREXX_ERROR_PARM_MISS 12 /* Parameter is missing */
#define AREXX_ERROR_PARM_INV 13 /* Invalid parameter value */
#define AREXX_ERROR_CLOCK_INV 18 /* Clock has not been adjusted */
#define AREXX_ERROR_SYNC_INV 19 /* No responses from NTP server */
#define AREXX_ERROR_SYNC_ON 20 /* Synchronization is already active */
#define AREXX_ERROR_SYNC_OFF 21 /*Synchronization is already deactivated */
#define AREXX_ERROR_COUNT 8
static struct ARexxErrorDef arexxErrors[] = {
{AREXX_ERROR_UNKNOWN_CMD, &TextARexxCmdUnknown},
{AREXX_ERROR_UNKNOWN_PARM, &TextARexxParmUnknown},
{AREXX_ERROR_PARM_MISS, &TextARexxParmMiss},
{AREXX_ERROR_PARM_INV, &TextARexxParmInvalid},
{AREXX_ERROR_CLOCK_INV, &TextNoClockAdjust},
{AREXX_ERROR_SYNC_INV, &TextNoResponses},
{AREXX_ERROR_SYNC_ON, &TextSyncAlreadyOn},
{AREXX_ERROR_SYNC_OFF, &TextSyncAlreadyOff}};
static void SplitAndTerminate(char *string, char **res)
{
char *p = string;
@@ -164,7 +212,7 @@ static void SplitAndTerminate(char *string, char **res)
}
}
static void BuildArexxHelpText(void)
static void BuildARexxHelpText(void)
{
char *p;
int i, line, len = 0;
@@ -172,8 +220,9 @@ static void BuildArexxHelpText(void)
if (arexxHelpText != NULL)
return;
len += 26; // Header
len += 71 * 2; // Spacer
len += 26; // Header
len += 71 * 2; // Spacer
len += StrLen(AREXX_ERROR_VAR_CODE) + StrLen(AREXX_ERROR_VAR_TEXT) + 32; // Footer
for (i = 0; i < AREXX_COMMAND_COUNT; i++)
{
@@ -201,9 +250,15 @@ static void BuildArexxHelpText(void)
}
p = AppendChar(p, '-', 70);
p = AppendChar(p, '\n', 1);
p = AppendText(p, "Error status is set in ");
p = AppendText(p, AREXX_ERROR_VAR_CODE);
p = AppendText(p, " and ");
p = AppendText(p, AREXX_ERROR_VAR_TEXT);
}
void CleanupArexx(void)
void CleanupARexx(void)
{
if (arexxHelpText != NULL)
{
@@ -212,75 +267,209 @@ void CleanupArexx(void)
}
}
static void ArexxIdentifierCommand(struct RexxMsg *msg, char **parms)
static void SetARexxVar(struct RexxMsg *msg, const char *var, const char *text)
{
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)APP_TITLE, (LONG)StrLen(APP_TITLE));
}
static void ArexxVersionCommand(struct RexxMsg *msg, char **parms)
{
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)APP_VERSION, (LONG)StrLen(APP_VERSION));
}
static void ArexxHelpCommand(struct RexxMsg *msg, char **parms)
{
BuildArexxHelpText();
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)arexxHelpText, (LONG)StrLen(arexxHelpText));
}
static void ArexxStatusCommand(struct RexxMsg *msg, char **parms)
{
if (SynchronizerRunning)
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)TextSyncOn, (LONG)StrLen(TextSyncOn));
LONG error = SetRexxVar(msg, (CONST_STRPTR)var, (CONST_STRPTR)text, (LONG)StrLen(text));
if (error != 0)
{
LogWarn(TextARexxVarError, (long)error);
LogWarn(TextARexxVarValue, var, text);
}
else
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)TextSyncOff, (LONG)StrLen(TextSyncOff));
{
LogTrace(TextARexxVarValue, var, text);
}
}
static void ArexxTimezoneCommand(struct RexxMsg *msg, char **parms)
static void ARexxErrorClear(struct RexxMsg *msg)
{
char Timezone[TIMEZONE_TEXT_LEN];
GetTimezoneText(AppLocale, Timezone, UTC_NO_PARENS);
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)Timezone, (LONG)StrLen(Timezone));
SetARexxVar(msg, AREXX_ERROR_VAR_CODE, "0");
SetARexxVar(msg, AREXX_ERROR_VAR_TEXT, "");
}
static void ArexxLastSyncCommand(struct RexxMsg *msg, char **parms)
static void ARexxError(struct RexxMsg *msg, long code)
{
char errorCode[MAXLONGCHARSIZE];
LongToStr(code, errorCode);
SetARexxVar(msg, AREXX_ERROR_VAR_CODE, errorCode);
int i;
for (i = 0; i < AREXX_ERROR_COUNT; i++)
{
if (arexxErrors[i].Code == code)
{
const char *text = *(arexxErrors[i].Text);
SetARexxVar(msg, AREXX_ERROR_VAR_TEXT, text);
break;
}
}
}
static void ARexxResult(struct RexxMsg *msg, const char *text)
{
if (msg->rm_Action & RXFF_RESULT)
{
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)text, (LONG)StrLen(text));
}
LogTrace(TextARexxResult, text);
ARexxErrorClear(msg);
}
static void ARexxResultLong(struct RexxMsg *msg, long value)
{
char text[MAXLONGCHARSIZE];
SNPrintf(text, MAXLONGCHARSIZE, "%ld", value);
ARexxResult(msg, text);
}
static void ARexxResultBool(struct RexxMsg *msg, char *parm, long value)
{
char text[MAXBOOLCHARSIZE];
if (Stricmp((STRPTR)parm, (STRPTR)KEYWORD_NUMBER) == 0)
BoolToStrNum(value, text);
else
BoolToStr(value, text);
ARexxResult(msg, text);
}
static void ARexxTimeResult(struct RexxMsg *msg, char **parms, struct timeval *utv, long error)
{
if (utv->tv_secs == 0 && utv->tv_micro == 0)
{
ARexxError(msg, error);
return;
}
bool utc;
STRPTR format = (STRPTR)*parms++;
if (Stricmp((STRPTR)*parms, (STRPTR)KEYWORD_UTC) == 0)
{
utc = true;
}
else if (*parms == NULL || Stricmp((STRPTR)*parms, (STRPTR)KEYWORD_LOCAL) == 0)
{
utc = false;
}
else
{
ARexxError(msg, AREXX_ERROR_PARM_INV);
return;
}
char result[DATETIME_TEXT_LEN + 1];
if (format == NULL || Stricmp(format, (STRPTR)KEYWORD_DOS) == 0)
Utc2DOS(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_ASCII) == 0)
Utc2ASCII(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_DATE) == 0)
Utc2ARexxDate(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_TIME) == 0)
Utc2ARexxTime(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_RFC850) == 0)
Utc2RFC850(utv, result);
else if (Stricmp(format, (STRPTR)KEYWORD_RFC1123) == 0)
Utc2RFC1123(utv, result);
else if (Stricmp(format, (STRPTR)KEYWORD_RFC2822) == 0)
Utc2RFC2822(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_RFC3339) == 0)
Utc2RFC3339(utv, result, utc);
else if (Stricmp(format, (STRPTR)KEYWORD_ISO8601) == 0)
Utc2ISO8601(utv, result, utc);
else
{
ARexxError(msg, AREXX_ERROR_PARM_INV);
return;
}
ARexxResult(msg, result);
}
static void ARexxIdentifierCommand(struct RexxMsg *msg, char **parms)
{
ARexxResult(msg, APP_TITLE);
}
static void ARexxVersionCommand(struct RexxMsg *msg, char **parms)
{
ARexxResult(msg, APP_VERSION);
}
static void ARexxHelpCommand(struct RexxMsg *msg, char **parms)
{
BuildARexxHelpText();
ARexxResult(msg, arexxHelpText);
}
static void ARexxStatusCommand(struct RexxMsg *msg, char **parms)
{
if (Stricmp((STRPTR)*parms, (STRPTR)KEYWORD_NUMBER) == 0)
{
char buf[4];
BoolToStrNum(SynchronizerRunning, buf);
ARexxResult(msg, buf);
}
else if (*parms == NULL)
{
const char *result = SynchronizerRunning ? TextSyncOn : TextSyncOff;
ARexxResult(msg, result);
}
else
{
ARexxError(msg, AREXX_ERROR_PARM_INV);
}
}
static void ARexxTimezoneCommand(struct RexxMsg *msg, char **parms)
{
long val;
if (parms == NULL)
{
ARexxError(msg, AREXX_ERROR_PARM_MISS);
}
else if (!TryParseLong(*parms, &val))
{
ARexxError(msg, AREXX_ERROR_PARM_INV);
}
else if (val < 1 || val > 12)
{
ARexxError(msg, AREXX_ERROR_PARM_INV);
}
else
{
char buf[TIMEZONE_TEXT_LEN];
GetTimezoneText(buf, val);
ARexxResult(msg, buf);
}
}
static void ARexxNowCommand(struct RexxMsg *msg, char **parms)
{
struct timeval tv;
GetTimeOfDay(&tv);
ARexxTimeResult(msg, parms, &tv, AREXX_ERROR_SYNC_INV);
}
static void ARexxLastSyncCommand(struct RexxMsg *msg, char **parms)
{
struct timeval tv = LastSync;
if (tv.tv_sec == 0 && tv.tv_micro == 0)
{
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)TextNoResponses, (LONG)StrLen(TextNoResponses));
}
else
{
char result[64];
Utc2Str(&tv, result);
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)result, (LONG)StrLen(result));
}
ARexxTimeResult(msg, parms, &tv, AREXX_ERROR_SYNC_INV);
}
static void ArexxLastAdjustCommand(struct RexxMsg *msg, char **parms)
static void ARexxLastAdjustCommand(struct RexxMsg *msg, char **parms)
{
struct timeval tv = LastAdjust;
if (tv.tv_sec == 0 && tv.tv_micro == 0)
{
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)TextNoClockAdjust, (LONG)StrLen(TextNoClockAdjust));
}
else
{
char result[64];
Utc2Str(&tv, result);
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)result, (LONG)StrLen(result));
}
ARexxTimeResult(msg, parms, &tv, AREXX_ERROR_CLOCK_INV);
}
static int ArexxFindParameter(char **parms)
static int ARexxFindParameter(char **parms)
{
int i;
char *parm = parms[0];
if (parm == NULL || *parm == '\0')
{
return AREXX_PARAMETER_UNKNOWN;
return AREXX_PARAMETER_MISSING;
}
for (i = 0; i < AREXX_PARAMETER_COUNT; i++)
@@ -294,68 +483,84 @@ static int ArexxFindParameter(char **parms)
return AREXX_PARAMETER_UNKNOWN;
}
static void ArexxGetValueCommand(struct RexxMsg *msg, char **parms)
static void ARexxGetValueCommand(struct RexxMsg *msg, char **parms)
{
char buf[MAXLONGLONGCHARSIZE];
char *res;
int param = ArexxFindParameter(parms);
int param = ARexxFindParameter(parms++);
switch (param)
{
case AREXX_PARAMETER_UNKNOWN:
msg->rm_Result1 = AREXX_COMMAND_PARM_UNKNOWN;
ARexxError(msg, AREXX_ERROR_UNKNOWN_PARM);
break;
case AREXX_PARAMETER_MISSING:
ARexxError(msg, AREXX_ERROR_PARM_MISS);
break;
case AREXX_PARAMETER_SERVER:
res = Settings->DestinationAddress;
ARexxResult(msg, Settings->DestinationAddress);
break;
case AREXX_PARAMETER_PORT:
res = Settings->DestinationPort;
break;
case AREXX_PARAMETER_THRESHOLD:
LongLongToStr(Settings->Threshold, buf);
res = buf;
ARexxResult(msg, Settings->DestinationPort);
break;
case AREXX_PARAMETER_INTERVAL:
LongToStr(Settings->Interval, buf);
res = buf;
ARexxResultLong(msg, Settings->Interval);
break;
case AREXX_PARAMETER_PRIORITY:
LongToStr(Settings->Priority, buf);
res = buf;
ARexxResultLong(msg, Settings->Priority);
break;
case AREXX_PARAMETER_POPKEY:
res = Settings->PopKey;
ARexxResult(msg, Settings->PopKey);
break;
case AREXX_PARAMETER_POPUP:
BoolToStr(Settings->Popup, buf);
res = buf;
ARexxResultBool(msg, *parms, Settings->Popup);
break;
case AREXX_PARAMETER_READONLY:
BoolToStr(Settings->Readonly, buf);
res = buf;
ARexxResultBool(msg, *parms, Settings->Readonly);
break;
case AREXX_PARAMETER_EXPERT:
BoolToStr(Settings->Expert, buf);
res = buf;
ARexxResultBool(msg, *parms, Settings->Expert);
break;
case AREXX_PARAMETER_TIMEOUT:
LongToStr(Settings->Timeout, buf);
res = buf;
ARexxResultLong(msg, Settings->Timeout);
break;
default:
msg->rm_Result1 = AREXX_COMMAND_PARM_UNKNOWN;
case AREXX_PARAMETER_ACTIVE:
ARexxResultBool(msg, *parms, SynchronizerRunning);
break;
}
if (msg->rm_Result1 != AREXX_COMMAND_PARM_UNKNOWN)
case AREXX_PARAMETER_NOLOG:
ARexxResultBool(msg, *parms, Settings->NoLog);
break;
case AREXX_PARAMETER_TZ:
ARexxResult(msg, Settings->TZ);
break;
case AREXX_PARAMETER_TZD:
ARexxResultLong(msg, Settings->TimeZoneDisplay);
break;
case AREXX_PARAMETER_TZNAME:
ARexxResult(msg, Settings->TimeZoneName);
break;
case AREXX_PARAMETER_TZVALUE:
if (Settings->TimeZoneValue != TZVALUE_DEF)
ARexxResultLong(msg, Settings->TimeZoneValue);
else
ARexxResult(msg, "");
break;
case AREXX_PARAMETER_TZDST:
ARexxResultLong(msg, Settings->TimeZoneDst);
break;
case AREXX_PARAMETER_THRESHOLD:
{
msg->rm_Result2 = (LONG)CreateArgstring((STRPTR)res, (LONG)StrLen(res));
char buf[MAXLONGLONGCHARSIZE];
LongLongToStr(Settings->Threshold, buf);
ARexxResult(msg, buf);
}
break;
default:
ARexxError(msg, AREXX_ERROR_UNKNOWN_PARM);
break;
}
}
static void ArexxSetValueCommand(struct RexxMsg *msg, char **parms)
static void ARexxSetValueCommand(struct RexxMsg *msg, char **parms)
{
int param = ArexxFindParameter(parms++);
int param = ARexxFindParameter(parms++);
char *valueString = *parms;
long long longlongValue;
long longValue;
@@ -364,47 +569,68 @@ static void ArexxSetValueCommand(struct RexxMsg *msg, char **parms)
switch (param)
{
case AREXX_PARAMETER_UNKNOWN:
msg->rm_Result1 = AREXX_COMMAND_PARM_UNKNOWN;
ARexxError(msg, AREXX_ERROR_UNKNOWN_PARM);
break;
case AREXX_PARAMETER_MISSING:
ARexxError(msg, AREXX_ERROR_PARM_MISS);
break;
case AREXX_PARAMETER_SERVER:
SetServer(valueString, APPLY_VALUE);
ARexxErrorClear(msg);
break;
case AREXX_PARAMETER_PORT:
SetPort(valueString, APPLY_VALUE);
ARexxErrorClear(msg);
break;
case AREXX_PARAMETER_THRESHOLD:
if (TryParseLongLong(valueString, &longlongValue))
{
SetThreshold(valueString, APPLY_VALUE);
ARexxErrorClear(msg);
}
else
msg->rm_Result1 = AREXX_COMMAND_PARM_INVALID;
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_INTERVAL:
if (TryParseLong(valueString, &longValue))
{
SetInterval(longValue, APPLY_VALUE);
ARexxErrorClear(msg);
}
else
msg->rm_Result1 = AREXX_COMMAND_PARM_INVALID;
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_PRIORITY:
if (TryParseLong(valueString, &longValue))
{
SetPriority(valueString, APPLY_VALUE);
ARexxErrorClear(msg);
}
else
msg->rm_Result1 = AREXX_COMMAND_PARM_INVALID;
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_POPKEY:
// TODO: Remove CX filter object and add new filter (Settings->PopKey)
// http://amigadev.elowar.com/read/ADCD_2.1/Libraries_Manual_guide/node0587.html
ARexxError(msg, AREXX_ERROR_UNKNOWN_PARM);
break;
case AREXX_PARAMETER_POPUP:
if (TryParseBoolean(valueString, &boolValue))
{
Settings->Popup = boolValue;
ARexxErrorClear(msg);
}
else
msg->rm_Result1 = AREXX_COMMAND_PARM_INVALID;
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_READONLY:
if (TryParseBoolean(valueString, &boolValue))
{
Settings->Readonly = boolValue;
ARexxErrorClear(msg);
}
else
msg->rm_Result1 = AREXX_COMMAND_PARM_INVALID;
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_EXPERT:
if (TryParseBoolean(valueString, &boolValue))
@@ -412,80 +638,138 @@ static void ArexxSetValueCommand(struct RexxMsg *msg, char **parms)
Settings->Expert = boolValue;
SendWindowMessage(ATK_SHUTDOWN);
ShowSettingWindow();
ARexxErrorClear(msg);
}
else
msg->rm_Result1 = AREXX_COMMAND_PARM_INVALID;
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_TIMEOUT:
if (TryParseLong(valueString, &longValue))
{
SetTimeout(longValue, APPLY_VALUE);
ARexxErrorClear(msg);
}
else
msg->rm_Result1 = AREXX_COMMAND_PARM_INVALID;
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_ACTIVE:
if (TryParseBoolean(valueString, &boolValue))
{
if (boolValue)
ARexxStartCommand(msg, NULL);
else
ARexxStopCommand(msg, NULL);
}
else
ARexxError(msg, AREXX_ERROR_PARM_INV);
break;
case AREXX_PARAMETER_NOLOG:
if (TryParseBoolean(valueString, &boolValue))
{
Settings->NoLog = boolValue;
ARexxErrorClear(msg);
}
else
ARexxError(msg, AREXX_ERROR_PARM_INV);
case AREXX_PARAMETER_TZ:
SetTimeZoneSetting(SettingKeys->TZ, &Settings->TZ, valueString, APPLY_VALUE);
break;
case AREXX_PARAMETER_TZD:
SetTimeZoneSettingLong(SettingKeys->TimeZoneDisplay, &Settings->TimeZoneDisplay, valueString, APPLY_VALUE);
break;
case AREXX_PARAMETER_TZNAME:
SetTimeZoneSetting(SettingKeys->TimeZoneName, &Settings->TimeZoneName, valueString, APPLY_VALUE);
break;
case AREXX_PARAMETER_TZVALUE:
SetTimeZoneSettingLong(SettingKeys->TimeZoneValue, &Settings->TimeZoneValue, valueString, APPLY_VALUE);
break;
case AREXX_PARAMETER_TZDST:
SetTimeZoneSettingLong(SettingKeys->TimeZoneDst, &Settings->TimeZoneDst, valueString, APPLY_VALUE);
break;
default:
msg->rm_Result1 = AREXX_COMMAND_PARM_UNKNOWN;
ARexxError(msg, AREXX_ERROR_UNKNOWN_PARM);
break;
}
}
static void ArexxShowCommand(struct RexxMsg *msg, char **parms)
static void ARexxShowCommand(struct RexxMsg *msg, char **parms)
{
ShowSettingWindow();
ARexxErrorClear(msg);
}
static void ArexxHideCommand(struct RexxMsg *msg, char **parms)
static void ARexxHideCommand(struct RexxMsg *msg, char **parms)
{
SendWindowMessage(ATK_SHUTDOWN);
ARexxErrorClear(msg);
}
static void ArexxStartCommand(struct RexxMsg *msg, char **parms)
static void ARexxStartCommand(struct RexxMsg *msg, char **parms)
{
if (!SynchronizerRunning)
{
Activate();
ARexxErrorClear(msg);
}
else
{
// TODO: Set error text
msg->rm_Result1 = AREXX_COMMAND_ERROR;
ARexxError(msg, AREXX_ERROR_SYNC_ON);
}
}
static void ArexxStopCommand(struct RexxMsg *msg, char **parms)
static void ARexxStopCommand(struct RexxMsg *msg, char **parms)
{
if (SynchronizerRunning)
{
Deactivate();
ARexxErrorClear(msg);
}
else
{
// TODO: Set error text
msg->rm_Result1 = AREXX_COMMAND_ERROR;
ARexxError(msg, AREXX_ERROR_SYNC_OFF);
}
}
static void ArexxShutdownCommand(struct RexxMsg *msg, char **parms)
static void ARexxShutdownCommand(struct RexxMsg *msg, char **parms)
{
LogWarn("Requesting shutdown");
msg->rm_Result1 = AREXX_COMMAND_SHUTDOWN;
LogWarn(TextARexxShutdown);
msg->rm_Result1 = AREXX_PARAMETER_SHUTDOWN;
ARexxErrorClear(msg);
}
static bool HandleArexxMessage(struct RexxMsg *msg)
static void ARexxLogTransitionsCommand(struct RexxMsg *msg, char **parms)
{
LogTransitionMap();
ARexxErrorClear(msg);
}
static void ExecuteARexxCommand(struct RexxMsg *msg, struct ARexxCommandDef *cmd, char **parms)
{
LogNotice(TextARexxReceived, cmd->Name);
bool execute = !cmd->ResultCommand || (cmd->ResultCommand && (msg->rm_Action & RXFF_RESULT));
if (execute)
{
if (parms == NULL)
LogTrace(TextARexxExecute1, cmd->Name);
else
LogTrace(TextARexxExecute2, cmd->Name, *parms);
cmd->Command(msg, parms);
}
}
static bool HandleARexxMessage(struct RexxMsg *msg)
{
int i;
bool found = false;
bool cont = true;
msg->rm_Result1 = AREXX_COMMAND_UNKNOWN;
msg->rm_Result2 = 0;
for (i = 0; i < AREXX_COMMAND_COUNT; i++)
{
if (arexxCommands[i].Parameters == 0 && Stricmp((STRPTR)msg->rm_Args[0], (STRPTR)arexxCommands[i].Name) == 0)
struct ARexxCommandDef *cmd = &arexxCommands[i];
if (cmd->Parameters == 0 && Stricmp((STRPTR)msg->rm_Args[0], (STRPTR)cmd->Name) == 0)
{
LogNotice("Received %s", arexxCommands[i].Name);
msg->rm_Result1 = AREXX_COMMAND_OK;
arexxCommands[i].Command(msg, NULL);
ExecuteARexxCommand(msg, cmd, NULL);
found = true;
break;
}
@@ -497,7 +781,7 @@ static bool HandleArexxMessage(struct RexxMsg *msg)
char *buf = AllocStringSafe(StrLen(msg->rm_Args[0]) + 1);
StrCopy(buf, msg->rm_Args[0]);
for (i = 1; i < AREXX_MAX_ARGS_COUNT; i++)
for (i = 0; i < AREXX_MAX_ARGS_COUNT; i++)
{
args[i] = NULL;
}
@@ -505,11 +789,10 @@ static bool HandleArexxMessage(struct RexxMsg *msg)
SplitAndTerminate(buf, args);
for (i = 0; i < AREXX_COMMAND_COUNT; i++)
{
if (arexxCommands[i].Parameters > 0 && Stricmp((STRPTR)buf, (STRPTR)arexxCommands[i].Name) == 0)
struct ARexxCommandDef *cmd = &arexxCommands[i];
if (cmd->Parameters > 0 && Stricmp((STRPTR)buf, (STRPTR)cmd->Name) == 0)
{
LogNotice("Received %s", arexxCommands[i].Name);
msg->rm_Result1 = AREXX_COMMAND_OK;
arexxCommands[i].Command(msg, args);
ExecuteARexxCommand(msg, cmd, args);
found = true;
break;
}
@@ -518,9 +801,12 @@ static bool HandleArexxMessage(struct RexxMsg *msg)
FreeMemSafe(buf);
}
if (msg->rm_Result1 == AREXX_COMMAND_SHUTDOWN)
if (!found)
{
ARexxError(msg, AREXX_ERROR_UNKNOWN_CMD);
}
else if (msg->rm_Result1 == AREXX_PARAMETER_SHUTDOWN)
{
msg->rm_Result1 = AREXX_COMMAND_OK;
cont = false;
}
@@ -534,7 +820,11 @@ bool HandleARexxMessages(void)
while ((msg = (struct RexxMsg *)GetNewMessage(MSGPORT_AREXX)))
{
cont &= HandleArexxMessage(msg);
if (CheckRexxMsg(msg))
{
cont &= HandleARexxMessage(msg);
msg->rm_Result1 = RC_OK;
}
ReplyMsg((struct Message *)msg);
}
+3
View File
@@ -0,0 +1,3 @@
/* Set TZ to Australian Central time zone */
SAY ('Changing to Australian Central time zone ...')
Address TIMEKEEPER.1 'SET TZ ACST-9'
+3
View File
@@ -0,0 +1,3 @@
/* Set TZ to Central European time zone */
SAY ('Changing to Central European time zone ...')
Address TIMEKEEPER.1 'SET TZ CET-1CEST,M3.5.0,M10.5.0/3'
+3
View File
@@ -0,0 +1,3 @@
/* Set TZ to Australian Eastern time zone */
SAY ('Changing to Australian Eastern time zone ...')
Address TIMEKEEPER.1 'SET TZ AEST-10AEDT,M10.1.0,M4.1.0/3'
+3
View File
@@ -0,0 +1,3 @@
/* Set TZ to North East American time zone */
SAY ('Changing to North East American time zone ...')
Address TIMEKEEPER.1 'SET TZ EST5EDT,M3.2.0,M11.1.0'
+23
View File
@@ -0,0 +1,23 @@
/* Test time zone settings */
SAY ('Testing time zone values ...')
Address TIMEKEEPER.1 SET TZ
Address TIMEKEEPER.1'SET TZ CET-1'
Address TIMEKEEPER.1'SET TZ CET-1CEST'
Address TIMEKEEPER.1'SET TZ <GMT+3>-3'
Address TIMEKEEPER.1 'SET TZ CST6CDT,M3.2.0,M11.1.0'
Address TIMEKEEPER.1 'SET TZ MST7MDT,M3.2.0,M11.1.0'
Address TIMEKEEPER.1 'SET TZ AEST-10AEDT,M10.1.0,M4.1.0/3'
Address TIMEKEEPER.1 'SET TZ NZST-12NZDT,M9.5.0,M4.1.0/3'
Address TIMEKEEPER.1'SET TZ GMT0'
Address TIMEKEEPER.1 SET TZVALUE 10000
Address TIMEKEEPER.1 'SET TZVALUE -10000'
Address TIMEKEEPER.1 SET TZVALUE 200
Address TIMEKEEPER.1 'SET TZVALUE -200'
Address TIMEKEEPER.1 'SET TZDST -1'
Address TIMEKEEPER.1 SET TZDST 0
Address TIMEKEEPER.1 SET TZDST 1
Address TIMEKEEPER.1 'SET TZDST -1'
+4
View File
@@ -0,0 +1,4 @@
/* Show TimeKeeper synchronization status */
Options RESULTS
Address TIMEKEEPER.1 'GET ACTIVE'; SAY ('ACTIVE (YES/NO):' RESULT);
Address TIMEKEEPER.1 'GET ACTIVE NUMBER'; SAY ('ACTIVE (0/1):' RESULT);
+5
View File
@@ -0,0 +1,5 @@
/* Show the NTP server address in use */
Options RESULTS
Address TIMEKEEPER.1 'GET SERVER';
IF TIMEKEEPER.ERRORCODE == 0 THEN SAY (RESULT)
ELSE SAY (TIMEKEEPER.ERRORTEXT)
+1 -1
View File
@@ -1,4 +1,4 @@
/* Show the ARexx commands supported by TimeKeeper */
Options RESULTS
Address TIMEKEEPER.1 'help'
Address TIMEKEEPER.1 HELP
SAY (RESULT)
+2
View File
@@ -0,0 +1,2 @@
/* Hide TimeKeeper settings window */
Address TIMEKEEPER.1 HIDE
+17 -1
View File
@@ -1,3 +1,19 @@
/* Show when the last response from a NTP server was received */
Options RESULTS
Address TIMEKEEPER.1 'LastSync'; SAY (RESULT)
Address TIMEKEEPER.1 'LastSync'
IF TIMEKEEPER.ERRORCODE == 0 THEN SAY (RESULT)
ELSE SAY (TIMEKEEPER.ERRORTEXT)
Address TIMEKEEPER.1 LASTSYNC RFC3339
IF TIMEKEEPER.ERRORCODE == 0 THEN SAY ('Time and date in RFC 3339 format:' RESULT)
ELSE SAY (TIMEKEEPER.ERRORTEXT)
Address TIMEKEEPER.1 LASTSYNC DATE
IF TIMEKEEPER.ERRORCODE == 0 THEN SAY ('Sorted date (in the form YYYYMMDD):' RESULT)
ELSE SAY (TIMEKEEPER.ERRORTEXT)
Address TIMEKEEPER.1 LASTSYNC TIME
IF TIMEKEEPER.ERRORCODE == 0 THEN SAY ('Time in seconds since midnight:' RESULT)
ELSE SAY (TIMEKEEPER.ERRORTEXT)
+10 -3
View File
@@ -9,6 +9,13 @@ Address TIMEKEEPER.1 'get threshold'; SAY ('THRESHOLD =' RESULT 'microseconds')
Address TIMEKEEPER.1 'get ReadOnly'; SAY ('READONLY =' RESULT)
Address TIMEKEEPER.1 'get Expert'; SAY ('EXPERT =' RESULT)
Address TIMEKEEPER.1 'get timeout'; SAY ('TIMEOUT =' RESULT 'milliseconds')
Address TIMEKEEPER.1 'get CX_POPUP'; SAY ('POPUP =' RESULT)
Address TIMEKEEPER.1 'get CX_POPKEY'; SAY ('POPKEY =' RESULT)
Address TIMEKEEPER.1 'get CX_PRIORITY'; SAY ('PRIORITY =' RESULT)
Address TIMEKEEPER.1 GET CX_POPUP; SAY ('POPUP =' RESULT)
Address TIMEKEEPER.1 GET CX_POPKEY; SAY ('POPKEY =' RESULT)
Address TIMEKEEPER.1 GET CX_PRIORITY; SAY ('PRIORITY =' RESULT)
Address TIMEKEEPER.1 GET ACTIVE; SAY ('ACTIVE =' RESULT)
Address TIMEKEEPER.1 GET NOLOG; SAY ('NOLOG =' RESULT)
Address TIMEKEEPER.1 GET TZD; SAY ('TZD =' RESULT)
Address TIMEKEEPER.1 GET TZ; SAY ('TZ =' RESULT)
Address TIMEKEEPER.1 GET TZNAME; SAY ('TZNAME =' RESULT)
Address TIMEKEEPER.1 GET TZVALUE; SAY ('TZVALUE =' RESULT)
Address TIMEKEEPER.1 GET TZDST; SAY ('TZDST =' RESULT)
+2 -1
View File
@@ -1,3 +1,4 @@
/* Start TimeKeeper synchronization */
SAY ('Starting TimeKeeper synchronization ...')
Address TIMEKEEPER.1 'start'
Address TIMEKEEPER.1 START
IF TIMEKEEPER.ERRORCODE ~= 0 THEN SAY (TIMEKEEPER.ERRORTEXT)
+9 -2
View File
@@ -1,5 +1,12 @@
/* Show TimeKeeper synchronization status */
Options RESULTS
Address TIMEKEEPER.1 'status'; SAY (RESULT)
Address TIMEKEEPER.1 'LastSync'; SAY ('Last response from NTP server was:' RESULT)
Address TIMEKEEPER.1 'LastAdjust'; SAY ('Last clock adjustment was:' RESULT)
Address TIMEKEEPER.1 'LastSync'
IF TIMEKEEPER.ERRORCODE == 0 THEN SAY ('Last response from NTP server was:' RESULT)
ELSE SAY ('LastSync:' TIMEKEEPER.ERRORTEXT)
Address TIMEKEEPER.1 'LastAdj'
IF TIMEKEEPER.ERRORCODE == 0 THEN SAY ('Last clock adjustment was:' RESULT)
ELSE SAY ('LastAdj:' TIMEKEEPER.ERRORTEXT)
+2 -1
View File
@@ -1,3 +1,4 @@
/* Stop TimeKeeper synchronization */
SAY ('Stopping TimeKeeper synchronization ...')
Address TIMEKEEPER.1 'stop'
Address TIMEKEEPER.1 STOP
IF TIMEKEEPER.ERRORCODE ~= 0 THEN SAY (TIMEKEEPER.ERRORTEXT)
+19
View File
@@ -0,0 +1,19 @@
/* Show current date and time */
Options RESULTS
Address TIMEKEEPER.1 NOW ASCII LOCAL; SAY ('ASCII style:' RESULT)
Address TIMEKEEPER.1 NOW ASCII UTC; SAY ('ASCII style (UTC):' RESULT)
Address TIMEKEEPER.1 NOW DOS LOCAL; SAY ('DOS style:' RESULT)
Address TIMEKEEPER.1 NOW DOS UTC; SAY ('DOS style (UTC):' RESULT)
Address TIMEKEEPER.1 NOW RFC850; SAY ('RFC850:' RESULT)
Address TIMEKEEPER.1 NOW RFC1123; SAY ('RFC1123:' RESULT)
Address TIMEKEEPER.1 NOW RFC2822 LOCAL; SAY ('RFC2822:' RESULT)
Address TIMEKEEPER.1 NOW RFC2822 UTC; SAY ('RFC2822:' RESULT)
Address TIMEKEEPER.1 NOW RFC3339 LOCAL; SAY ('RFC3339:' RESULT)
Address TIMEKEEPER.1 NOW RFC3339 UTC; SAY ('RFC3339:' RESULT)
Address TIMEKEEPER.1 NOW ISO8601 LOCAL; SAY ('ISO8601:' RESULT)
Address TIMEKEEPER.1 NOW ISO8601 UTC; SAY ('ISO8601:' RESULT)
Address TIMEKEEPER.1 NOW DATE LOCAL; SAY ('ARexx compatible sorted date:' RESULT)
Address TIMEKEEPER.1 NOW DATE UTC; SAY ('ARexx compatible sorted date (UTC):' RESULT)
Address TIMEKEEPER.1 NOW TIME LOCAL; SAY ('ARexx compatible time in seconds since midnight:' RESULT)
Address TIMEKEEPER.1 NOW TIME UTC; SAY ('ARexx compatible time in seconds since midnight (UTC):' RESULT)
+12 -1
View File
@@ -1,3 +1,14 @@
/* Show current timezone in TimeKeeper */
Options RESULTS
Address TIMEKEEPER.1 'timezone'; SAY (RESULT)
Address TIMEKEEPER.1 TIMEZONE 1; SAY (' 1:' RESULT)
Address TIMEKEEPER.1 TIMEZONE 2; SAY (' 2:' RESULT)
Address TIMEKEEPER.1 TIMEZONE 3; SAY (' 3:' RESULT)
Address TIMEKEEPER.1 TIMEZONE 4; SAY (' 4:' RESULT)
Address TIMEKEEPER.1 TIMEZONE 5; SAY (' 5:' RESULT)
Address TIMEKEEPER.1 TIMEZONE 6; SAY (' 6:' RESULT)
Address TIMEKEEPER.1 TIMEZONE 7; SAY (' 7:' RESULT)
Address TIMEKEEPER.1 TIMEZONE 8; SAY (' 8:' RESULT)
Address TIMEKEEPER.1 TIMEZONE 9; SAY (' 9:' RESULT)
Address TIMEKEEPER.1 TIMEZONE 10; SAY ('10:' RESULT)
Address TIMEKEEPER.1 TIMEZONE 11; SAY ('11:' RESULT)
Address TIMEKEEPER.1 TIMEZONE 12; SAY ('12:' RESULT)
+3
View File
@@ -0,0 +1,3 @@
/* Show time zone transition map in log */
SAY ('Writing time zone transition map to log')
Address TIMEKEEPER.1 LOGTRANS
+12 -14
View File
@@ -118,7 +118,7 @@ void StartBroker(void)
LogError("System problems (CBERR_SYSERR). Could not allocate broker object");
break;
case CBERR_DUP:
LogWarn(APP_SHORT_NAME " is already running");
LogWarn(Text2P, APP_SHORT_NAME, TextAlreadyRunning);
break;
default:
LogError("Could not allocate broker object (error code: %ld)", error);
@@ -186,7 +186,12 @@ void StartBroker(void)
#endif
ActivateNotifyPort(Broker.NotifyPort);
StartSynchronizer();
if (Settings->Active)
{
ActivateCxObj(Broker.Object, 1);
StartSynchronizer();
}
MsgLoop();
@@ -207,14 +212,14 @@ void Deactivate(void)
{
if (SynchronizerRunning)
{
LogNotice("ACTIVE changed: 1 -> 0");
LogNotice(KEYWORD_ACTIVE " changed: 1 -> 0");
LogWarn("Disabling time synchronization");
SendMessageWait(MSGPORT_SYNCER, ATK_DISABLE);
ActivateCxObj(Broker.Object, 0);
}
else
{
LogError("Synchronization is already deactivated");
LogError(TextSyncAlreadyOff);
}
}
@@ -222,30 +227,26 @@ void Activate(void)
{
if (!SynchronizerRunning)
{
LogNotice("ACTIVE changed: 0 -> 1");
LogNotice(KEYWORD_ACTIVE " changed: 0 -> 1");
LogWarn("Enabling time synchronization");
ActivateCxObj(Broker.Object, 1);
StartSynchronizer();
}
else
{
LogError("Synchronization is already active");
LogError(TextSyncAlreadyOn);
}
}
static void ChangeTimezone(void)
{
// TODO: Make thread safe
CleanupTimezone();
InitTimezone();
SendWindowMessage(ATK_TZ_CHANGED);
}
static void ChangeTimezoneDelayedProc(void)
{
// TODO: Make thread safe
Delay(15 * 50);
ReopenLocale();
ChangeTimezone();
SendWindowMessage(ATK_TZ_CHANGED);
}
@@ -382,9 +383,7 @@ static void MsgLoop(void)
BrokerRunning = true;
LogTrace("Loop started");
ActivateCxObj(Broker.Object, 1);
if (Settings->Popup)
if (Settings->Popup || Settings->PopupOnStart)
{
ShowSettingWindow();
}
@@ -486,7 +485,6 @@ static void MsgLoop(void)
{
ShowSettingWindow();
}
ReopenLocale();
ChangeTimezone();
reopenWindow = false;
}
+3 -2
View File
@@ -58,7 +58,8 @@ typedef int bool;
#define StrCopy(dest, src) strcpy((char *)dest, (const char *)src)
#endif
#define MAXLONGCHARSIZE 12
#define MAXLONGLONGCHARSIZE 22
#define MAXLONGCHARSIZE 13
#define MAXLONGLONGCHARSIZE 23
#define MAXBOOLCHARSIZE 4
#endif
+83 -9
View File
@@ -160,8 +160,8 @@ int poll(struct pollfd *, nfds_t, int);
#define APP_LONG_NAME "Amiga Time Keeper"
#endif
#define APP_VERSION "1.11"
#define APP_DATE_VERSION "1.11 (11.01.2021)"
#define APP_VERSION "1.12"
#define APP_DATE_VERSION "1.12 (31.01.2021)"
#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
@@ -169,7 +169,7 @@ int poll(struct pollfd *, nfds_t, int);
#include "log.h"
#include "string.h"
#define KEYWORD_COUNT 10
#define KEYWORD_COUNT 18
#define KEYWORD_SERVER "SERVER"
#define KEYWORD_PORT "PORT"
#define KEYWORD_THRESHOLD "THRESHOLD"
@@ -180,6 +180,35 @@ int poll(struct pollfd *, nfds_t, int);
#define KEYWORD_READONLY "READONLY"
#define KEYWORD_EXPERT "EXPERT"
#define KEYWORD_TIMEOUT "TIMEOUT"
#define KEYWORD_ACTIVE "ACTIVE"
#define KEYWORD_NOLOG "NOLOG"
#define KEYWORD_TZ "TZ"
#define KEYWORD_TZD "TZD"
#define KEYWORD_TZNAME "TZNAME"
#define KEYWORD_TZVALUE "TZVALUE"
#define KEYWORD_TZDST "TZDST"
#define KEYWORD_POPUP2 "POPUP"
#define KEYWORD_FROM "FROM"
#define KEYWORD_TZ_ALIAS "TIMEZONE"
#define KEYWORD_TZD_ALIAS "TIMEZONEDISPLAY"
#define KEYWORD_TZNAME_ALIAS "TIMEZONEABBREVIATION"
#define KEYWORD_TZVALUE_ALIAS "TIMEZONEVALUE"
#define KEYWORD_TZDST_ALIAS "DST"
#define KEYWORD_NUMBER "NUMBER"
#define KEYWORD_DATE "DATE"
#define KEYWORD_TIME "TIME"
#define KEYWORD_DOS "DOS"
#define KEYWORD_ASCII "ASCII"
#define KEYWORD_RFC850 "RFC850"
#define KEYWORD_RFC1123 "RFC1123"
#define KEYWORD_RFC2822 "RFC2822"
#define KEYWORD_RFC3339 "RFC3339"
#define KEYWORD_ISO8601 "ISO8601"
#define KEYWORD_LOCAL "LOCAL"
#define KEYWORD_UTC "UTC"
#define SERVER_DEF "pool.ntp.org"
#define PORT_DEF "123"
@@ -187,27 +216,73 @@ int poll(struct pollfd *, nfds_t, int);
#define THRESHOLD_DEF 1000000LL
#define INTERVAL_MIN 500
#define INTERVAL_DEF 17500
#define INTERVAL_MAX 2 * 24 * 60 * 60 * 1000
#define PRIORITY_MIN -128
#define PRIORITY_DEF 25
#define PRIORITY_MAX 127
#define READONLY_DEF 0
#define EXPERT_DEF 0
#define ACTIVE_DEF 0
#define NOLOG_DEF 0
#define TIMEOUT_MIN 100
#define TIMEOUT_DEF 5000
#define TIMEOUT_MAX 30000
#define POPKEY_DEF "lshift control t"
#define POPUP_DEF 0
#define TZ_DEF ""
#define TZD_MIN 1
#define TZD_DEF 9
#define TZD_MAX 10
#define TZNAME_DEF ""
#define TZVALUE_MIN -2400
#define TZVALUE_DEF 16800
#define TZVALUE_MAX 2400
#define TZDST_DEF -1
#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,"
#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
#define KWD_TMPL_01 KEYWORD_READONLY "/S,"
#define KWD_TMPL_02 KEYWORD_EXPERT "/S,"
#define KWD_TMPL_03 KEYWORD_ACTIVE "/S,"
#define KWD_TMPL_04 KEYWORD_NOLOG "/S,"
#define KWD_TMPL_05 KEYWORD_SERVER "/K,"
#define KWD_TMPL_06 KEYWORD_PORT "/K,"
#define KWD_TMPL_07 KEYWORD_TIMEOUT "/N/K,"
#define KWD_TMPL_08 KEYWORD_THRESHOLD "/K,"
#define KWD_TMPL_09 KEYWORD_INTERVAL "/N/K,"
#define KWD_TMPL_10 KEYWORD_PRIORITY "/N/K,"
#define KWD_TMPL_11 KEYWORD_POPKEY "/K,"
#define KWD_TMPL_12 KEYWORD_POPUP "/K,"
#define KWD_TMPL_13 KEYWORD_TZ_ALIAS "=" KEYWORD_TZ "/K,"
#define KWD_TMPL_14 KEYWORD_TZD_ALIAS "=" KEYWORD_TZD "/N/K,"
#define KWD_TMPL_15 KEYWORD_TZNAME_ALIAS "=" KEYWORD_TZNAME "/K,"
#define KWD_TMPL_16 KEYWORD_TZVALUE_ALIAS "=" KEYWORD_TZVALUE "/N/K,"
#define KWD_TMPL_17 KEYWORD_TZDST_ALIAS "=" KEYWORD_TZDST "/N/K,"
#define KWD_TMPL_18 KEYWORD_POPUP2 "/S"
#define KWD_TMPL \
KWD_TMPL_01 \
KWD_TMPL_02 \
KWD_TMPL_03 \
KWD_TMPL_04 \
KWD_TMPL_05 \
KWD_TMPL_06 \
KWD_TMPL_07 \
KWD_TMPL_08 \
KWD_TMPL_09 \
KWD_TMPL_10 \
KWD_TMPL_11 \
KWD_TMPL_12 \
KWD_TMPL_13 \
KWD_TMPL_14 \
KWD_TMPL_15 \
KWD_TMPL_16 \
KWD_TMPL_17 \
KWD_TMPL_18
struct ControlMesage;
/* arexx.c */
bool HandleARexxMessages(void);
void CleanupArexx(void);
void CleanupARexx(void);
/* broker.c */
void StartBroker(void);
@@ -222,6 +297,5 @@ bool HandleControlMessages(void);
/* libraries.c */
int OpenLibraries(void);
void CloseLibraries(void);
void ReopenLocale(void);
#endif
+19
View File
@@ -109,6 +109,25 @@ int BoolToStr(bool value, char *string)
return count;
}
/*
* Convert a boolean to a null terminated numeral string.
*/
int BoolToStrNum(bool value, char *string)
{
char *s = string;
if (s == NULL)
return 0;
if (value)
*s++ = '1';
else
*s++ = '0';
*s = '\0';
return 1;
}
/*
* Convert a long to a null terminated string.
*/
+1
View File
@@ -33,6 +33,7 @@ bool TryParseBoolean(char *, bool *);
bool TryParseLong(char *, long *);
bool TryParseLongLong(char *, long long *);
int BoolToStr(bool, char *);
int BoolToStrNum(bool, char *);
int LongToStr(signed long, char *);
int LongLongToStr(signed long long, char *);
int StrToLongLong(char *, unsigned long long *);
+20 -4
View File
@@ -37,9 +37,9 @@
#include "message.h"
#include "string.h"
const char *vers = "\0$VER: TimeControl 1.11 (11.01.2021)";
const char *vers = "\0$VER: TimeControl 1.12 (31.01.2021)";
#define ARGSFORMAT "ID/S,VERSION/S,STATUS/S,START/S,STOP/S,SHOW/S,HIDE/S,SHUTDOWN/S"
#define ARGSFORMAT "ID/S,VERSION/S,STATUS/S,TIME/S,ZONE/S,START/S,STOP/S,SHOW/S,HIDE/S,SHUTDOWN/S"
struct RDArgs *rdargs = NULL;
struct MsgPort *replyPort = NULL;
@@ -50,6 +50,8 @@ struct progargs
long id;
long version;
long status;
long time;
long timezone;
long start;
long stop;
long show;
@@ -62,6 +64,8 @@ void InitializeArgs(struct progargs *args)
args->id = FALSE;
args->version = FALSE;
args->status = FALSE;
args->time = FALSE;
args->timezone = FALSE;
args->start = FALSE;
args->stop = FALSE;
args->show = FALSE;
@@ -107,7 +111,7 @@ void SendControlMessage(struct ControlMesage *message)
if (message->Code == ATK_CTRL_UNKNOWN)
{
Printf((STRPTR) APP_SHORT_NAME " could not process control command.\n");
Printf((STRPTR)APP_SHORT_NAME " could not process control command.\n");
}
else if (*message->Result != '\0')
{
@@ -195,6 +199,18 @@ void ProcessArgs(struct progargs *args)
processed = TRUE;
}
if (args->time)
{
SendSimpleMessage(ATK_TIME);
processed = TRUE;
}
if (args->timezone)
{
SendSimpleMessage(ATK_TIMEZONE);
processed = TRUE;
}
if (args->show)
{
SendSimpleMessage(ATK_SHOW);
@@ -262,7 +278,7 @@ int main(int argc, char **argv)
port = FindPort((CONST_STRPTR)CONTROL_PORT_NAME);
if (port == NULL)
{
Printf((STRPTR) APP_SHORT_NAME " is not running.\n");
Printf((STRPTR)APP_SHORT_NAME " is not running.\n");
Cleanup();
exit(1);
}
+19
View File
@@ -26,9 +26,12 @@
#include "config.h"
#include "message.h"
#include "global.h"
#include "locale.h"
#include "text.h"
#include "sync.h"
#include "win.h"
#include "mem.h"
#include "logmod.h"
#define MODULENAME "Control"
@@ -49,6 +52,22 @@ static bool HandleControlMessage(struct ControlMesage *msg)
StrCopy(msg->Result, APP_VERSION);
msg->Code = ATK_CTRL_OK;
break;
case ATK_TIME:
LogDebug("Time request");
char *time = GetTimeText(LOCAL_TIME_NOW);
StrCopy(msg->Result, time);
FreeMemSafe(time);
msg->Code = ATK_CTRL_OK;
break;
case ATK_TIMEZONE:
LogDebug("Timezone request");
{
char buf[TIMEZONE_TEXT_LEN];
GetTimezoneText(buf, TZD_SECONDS_AHEAD);
StrCopy(msg->Result, buf);
}
msg->Code = ATK_CTRL_OK;
break;
case ATK_STATUS:
LogDebug("Status request");
if (SynchronizerRunning)
-1
View File
@@ -32,6 +32,5 @@
#include <proto/exec.h>
struct AppLocale *AppLocale;
struct PosixTimezone *Timezone;
struct PosixTransitionTime *NextTransition;
-1
View File
@@ -30,7 +30,6 @@
#include <exec/ports.h>
#include "locale.h"
extern struct AppLocale *AppLocale;
extern struct PosixTimezone *Timezone;
extern struct PosixTransitionTime *NextTransition;
extern struct Library *BattClockBase;
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+14 -81
View File
@@ -27,6 +27,7 @@
#include "config.h"
#include "global.h"
#include "timer.h"
#include "text.h"
#include "ptz.h"
#include "mem.h"
@@ -85,9 +86,6 @@
#define LIBREV 34L
#endif
#ifndef CURRENTLOCALE
#define CURRENTLOCALE "Current Locale Info"
#endif
#ifndef NOAREXX
#define NOAREXX "No ARexx library found"
#endif
@@ -110,54 +108,25 @@ struct Device *TimerDevice = NULL;
static void OpenLibrarySuccess(char *name, char *ident)
{
if (ident == NULL)
{
LogDebug("Opened %s", name);
}
else
{
LogDebug("Opened %s", ident);
}
}
static void OpenLibraryError(char *name, long version)
{
char message[64];
SNPrintf(message, 63, "Cannot open %s %ld.0", name, version);
Printf((STRPTR)message);
LogError(message);
LogDebug(Text2P, TextOpened, (ident == NULL ? name : ident));
}
static void ClosingLibrary(char *name, char *ident)
{
if (ident == NULL)
{
LogDebug("Closing %s", name);
}
else
{
LogDebug("Closing %s", ident);
}
LogDebug(Text2P, TextClosing, (ident == NULL ? name : ident));
}
static void OpenResourceSuccess(char *name)
static void OpenLibraryError(char *name, long version)
{
LogDebug("Opened %s", name);
}
static void OpenResourceError(char *name)
{
LogError("Cannot open %s", name);
}
static void ClosingResource(char *name)
{
LogDebug("Closing %s", name);
char message[128];
SNPrintf(message, 127, "%s %s %ld.0", TextNoOpen, name, version);
Printf((STRPTR)message);
LogError(message);
}
int OpenLibraries(void)
{
LogInfo("Starting up");
LogInfo(Text2P, TextStarting, "up");
// DOS Library
if (!(DOSBase2 = (struct DosLibrary *)OpenLibrary((STRPTR)DOSNAME, LIBREV)))
@@ -234,27 +203,19 @@ int OpenLibraries(void)
LogWarn(NOAREXX);
}
// Locale
if (!(AppLocale = OpenAppLocale(NULL)))
{
OpenResourceError(CURRENTLOCALE);
return LIB_ERROR;
}
OpenResourceSuccess((char *)AppLocale->AmigaLocale->loc_LocaleName);
// Timer Device
if (!(TimerDevice = OpenTimerBase()))
{
OpenResourceError(TIMERNAME);
LogError(Text2P, TextNoOpen, TIMERNAME);
return LIB_ERROR;
}
OpenResourceSuccess(TIMERNAME);
LogDebug(Text2P, TextOpened, TIMERNAME);
// RTC Clock
BattClockBase = OpenResource((STRPTR)BATTCLOCKNAME);
if (BattClockBase != NULL)
{
OpenResourceSuccess(BATTCLOCKNAME);
LogDebug(Text2P, TextOpened, BATTCLOCKNAME);
}
else
{
@@ -265,7 +226,7 @@ int OpenLibraries(void)
ScreenNotifyBase = OpenLibrary((STRPTR)SCREENNOTIFY_NAME, SCREENNOTIFY_VERSION);
if (ScreenNotifyBase != NULL)
{
LogNotice("Found %s", SCREENNOTIFY_NAME);
LogNotice(Text2P, TextFound, SCREENNOTIFY_NAME);
}
#endif
@@ -278,18 +239,11 @@ void CloseLibraries(void)
{
if (TimerDevice != NULL)
{
ClosingResource(TIMERNAME);
LogDebug(Text2P, TextClosing, TIMERNAME);
CloseTimerBase();
TimerDevice = NULL;
}
if (AppLocale != NULL)
{
ClosingResource((char *)AppLocale->AmigaLocale->loc_LocaleName);
CloseAppLocale(AppLocale);
AppLocale = NULL;
}
#if defined(SCREENNOTIFY)
if (ScreenNotifyBase != NULL)
{
@@ -362,24 +316,3 @@ void CloseLibraries(void)
DOSBase2 = NULL;
}
}
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);
}
}
}
+343 -133
View File
@@ -26,130 +26,130 @@
#include "locale.h"
#include "global.h"
#include "string.h"
#include "setting.h"
#include "conv.h"
#include "text.h"
#include "ptz.h"
#include "mem.h"
#include "tz.h"
#include <proto/dos.h>
#include <proto/timer.h>
#include <proto/locale.h>
#include <proto/utility.h>
struct AppLocale *OpenAppLocale(struct Locale *locale)
#include <assert.h>
#define SECONDSPERDAY 86400
static const char *WeekdayShort[] = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
static const char *WeekdayLong[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
static const char *Month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
static void GetTimezoneCommon(char *text, struct PosixLocalTimezone *tz, long opt)
{
int i, j;
struct AppLocale *l = AllocStructSafe(struct AppLocale);
struct Locale *loc = locale;
if (!loc)
if (tz->abbreviation[0] == 'G' && tz->abbreviation[1] == 'M' && tz->abbreviation[2] == 'T')
{
loc = OpenLocale(NULL);
if (tz->offset.minutes == 0)
SNPrintf(text, TIMEZONE_TEXT_LEN, "GMT%s%d", TimezoneSignChar(tz), tz->offset.hours);
else
SNPrintf(text, TIMEZONE_TEXT_LEN, "GMT%s%d:%02d",
TimezoneSignChar(tz), tz->offset.hours, tz->offset.minutes);
}
if (loc == NULL)
else if (opt == TZD_ZONE_IN_PARENS)
{
return NULL;
if (tz->offset.minutes == 0)
SNPrintf(text, TIMEZONE_TEXT_LEN, "%s (GMT%s%d)",
tz->abbreviation, TimezoneSignChar(tz), tz->offset.hours);
else
SNPrintf(text, TIMEZONE_TEXT_LEN, "%s (GMT%s%d:%02d)",
tz->abbreviation, TimezoneSignChar(tz), tz->offset.hours, tz->offset.minutes);
}
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++)
else if (opt == TZD_OFFSET_IN_PARENS)
{
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 opt)
{
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, "%s%s%02ld:%02ld",
(opt == UTC_NO_PARENS) ? "UTC" : "GMT",
(loc->AmigaLocale->loc_GMTOffset < 0L) ? "+" : "",
hoursOffset,
minutsOffset);
}
else if (opt == ZONE_IN_PARENS)
{
SNPrintf(text, TIMEZONE_TEXT_LEN, "GMT%s%02d:%02d (%s)",
PosixTimezoneSignChar(&Timezone->current),
Timezone->current.offset.hours,
Timezone->current.offset.minutes,
Timezone->current.abbreviation);
}
else if (opt == OFFSET_IN_PARENS)
{
SNPrintf(text, TIMEZONE_TEXT_LEN, "%s (GMT%s%02d:%02d)",
Timezone->current.abbreviation,
PosixTimezoneSignChar(&Timezone->current),
Timezone->current.offset.hours,
Timezone->current.offset.minutes);
}
else if (opt == UTC_NO_PARENS)
{
SNPrintf(text, TIMEZONE_TEXT_LEN, "UTC%s%02d:%02d",
PosixTimezoneSignChar(&Timezone->current),
Timezone->current.offset.hours,
Timezone->current.offset.minutes);
if (tz->offset.minutes == 0)
SNPrintf(text, TIMEZONE_TEXT_LEN, "GMT%s%d (%s)",
TimezoneSignChar(tz), tz->offset.hours, tz->abbreviation);
else
SNPrintf(text, TIMEZONE_TEXT_LEN, "GMT%s%d:%02d (%s)",
TimezoneSignChar(tz), tz->offset.hours, tz->offset.minutes, tz->abbreviation);
}
}
char *GetTimeText(struct AppLocale *loc, ULONG time)
void GetTimezoneText(char *text, long opt)
{
char *out;
long offset = -GetUtcOffsetValue();
char *tzSign = (offset <= 0 ? "+" : "-");
switch (opt)
{
case TZD_SECONDS_AHEAD:
SNPrintf(text, TIMEZONE_TEXT_LEN, "%ld", offset);
break;
case TZD_MINUTES_AHEAD:
SNPrintf(text, TIMEZONE_TEXT_LEN, "%ld", offset / 60);
break;
case TZD_TZ_LONG:
if (Timezone->current.offset.minutes == 0)
SNPrintf(text, TIMEZONE_TEXT_LEN, "UTC%s%d", tzSign, Timezone->current.offset.hours);
else
SNPrintf(text, TIMEZONE_TEXT_LEN, "UTC%s%d:%02d",
tzSign, Timezone->current.offset.hours, Timezone->current.offset.minutes);
break;
case TZD_TZ_SHORT:
{
if (Timezone->current.offset.minutes == 0)
SNPrintf(text, TIMEZONE_TEXT_LEN, "%s%d", tzSign, Timezone->current.offset.hours);
else
SNPrintf(text, TIMEZONE_TEXT_LEN, "%s%d:%02d",
tzSign, Timezone->current.offset.hours, Timezone->current.offset.minutes);
}
break;
case TZD_ISO8601_NO_COLON:
SNPrintf(text, TIMEZONE_TEXT_LEN, "%s%02d%02d", TimezoneSignChar(&Timezone->current),
Timezone->current.offset.hours, Timezone->current.offset.minutes);
break;
case TZD_ISO8601_COLON:
SNPrintf(text, TIMEZONE_TEXT_LEN, "%s%02d:%02d", TimezoneSignChar(&Timezone->current),
Timezone->current.offset.hours, Timezone->current.offset.minutes);
break;
case TZD_ISO8601_SHORT:
if (offset % 60 == 0)
SNPrintf(text, TIMEZONE_TEXT_LEN, "%s%d",
TimezoneSignChar(&Timezone->current), Timezone->current.offset.hours);
else
SNPrintf(text, TIMEZONE_TEXT_LEN, "%s%d:%02d", TimezoneSignChar(&Timezone->current),
Timezone->current.offset.hours, Timezone->current.offset.minutes);
break;
case TZD_COMMON:
SNPrintf(text, TIMEZONE_TEXT_LEN, "GMT%s%02d:%02d", TimezoneSignChar(&Timezone->current),
Timezone->current.offset.hours, Timezone->current.offset.minutes);
break;
case TZD_ZONE_IN_PARENS:
GetTimezoneCommon(text, &Timezone->current, TZD_ZONE_IN_PARENS);
break;
case TZD_OFFSET_IN_PARENS:
GetTimezoneCommon(text, &Timezone->current, TZD_OFFSET_IN_PARENS);
break;
case TZD_STD:
GetTimezoneCommon(text, &Timezone->std, TZD_OFFSET_IN_PARENS);
break;
case TZD_DST:
GetTimezoneCommon(text, &Timezone->dst, TZD_OFFSET_IN_PARENS);
break;
default:
text = '\0';
break;
}
}
char *GetTimeText(ULONG time)
{
char *out = AllocStringSafe(128);
struct ClockData cd;
struct timeval tv;
ULONG t = time;
out = AllocStringSafe(128);
if (loc == NULL)
{
return out;
}
if (t == LOCAL_TIME_NOW)
{
GetSysTime(&tv);
@@ -157,36 +157,246 @@ char *GetTimeText(struct AppLocale *loc, ULONG time)
}
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);
}
int weekday = (cd.wday == 0 ? 7 : cd.wday) - 1;
SNPrintf(out, 128, "%s %02ld %s %02ld:%02ld:%02ld %s %ld",
WeekdayLong[weekday],
(long)cd.mday,
Month[cd.month - 1],
(long)cd.hour,
(long)cd.min,
(long)cd.sec,
Timezone->current.abbreviation,
(long)cd.year);
return out;
}
static 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) * 50;
date->ds_Days = d;
date->ds_Minute = m;
date->ds_Tick = q;
}
static 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);
}
void Utc2DOS(struct timeval *utv, char *buffer, bool showUtc)
{
char timeString[20];
char dateString[20];
char dayString[20];
struct DateStamp ds;
struct timeval tv;
if (showUtc)
Unix2Amiga(utv, &tv);
else
UnixUtc2AmigaLocal(utv, &tv);
time_t time = tv.tv_secs;
Amiga2DateStamp(&time, &ds);
DateTimeString(&ds, timeString, dateString, dayString);
SNPrintf(buffer, 64, "%s %s %s", dayString, dateString, timeString);
}
void Utc2ARexxDate(struct timeval *utv, char *buffer, bool showUtc)
{
struct timeval tv;
struct ClockData cd;
if (showUtc)
Unix2Amiga(utv, &tv);
else
UnixUtc2AmigaLocal(utv, &tv);
Amiga2Date(tv.tv_secs, &cd);
SNPrintf(buffer, 10, "%04ld%02ld%02ld", (long)cd.year, (long)cd.month, (long)cd.mday);
}
void Utc2ARexxTime(struct timeval *utv, char *buffer, bool showUtc)
{
struct timeval tv;
if (showUtc)
Unix2Amiga(utv, &tv);
else
UnixUtc2AmigaLocal(utv, &tv);
long time = tv.tv_secs % (24 * 60 * 60);
LongToStr(time, buffer);
}
void Utc2ASCII(struct timeval *utv, char *buffer, bool showUtc)
{
struct timeval tv;
struct ClockData cd;
if (showUtc)
Unix2Amiga(utv, &tv);
else
UnixUtc2AmigaLocal(utv, &tv);
Amiga2Date(tv.tv_secs, &cd);
SNPrintf(buffer, DATETIME_TEXT_LEN, ASCIITEMPLATE,
WeekdayShort[cd.wday - 1], Month[cd.month - 1], (long)cd.mday,
(long)cd.hour, (long)cd.min, (long)cd.sec, (long)cd.year);
}
void Utc2RFC850(struct timeval *utv, char *buffer)
{
struct timeval tv;
struct ClockData cd;
Unix2Amiga(utv, &tv);
Amiga2Date(tv.tv_secs, &cd);
SNPrintf(buffer, DATETIME_TEXT_LEN, RFC850TEMPLATE,
WeekdayLong[cd.wday - 1], (long)cd.mday,
Month[cd.month - 1], (long)cd.year % 100,
(long)cd.hour, (long)cd.min, (long)cd.sec);
}
void Utc2RFC1123(struct timeval *utv, char *buffer)
{
struct timeval tv;
struct ClockData cd;
Unix2Amiga(utv, &tv);
Amiga2Date(tv.tv_secs, &cd);
SNPrintf(buffer, DATETIME_TEXT_LEN, RFC1123TEMPLATE,
WeekdayShort[cd.wday - 1], (long)cd.mday,
Month[cd.month - 1], (long)cd.year,
(long)cd.hour, (long)cd.min, (long)cd.sec);
}
void Utc2RFC2822(struct timeval *utv, char *buffer, bool showUtc)
{
struct timeval tv;
struct ClockData cd;
if (showUtc)
{
Unix2Amiga(utv, &tv);
Amiga2Date(tv.tv_secs, &cd);
SNPrintf(buffer, DATETIME_TEXT_LEN, RFC2822TEMPLATE,
(long)cd.mday, Month[cd.month - 1], (long)cd.year,
(long)cd.hour, (long)cd.min, (long)cd.sec,
"+", 0L, 0L);
}
else
{
UnixUtc2AmigaLocal(utv, &tv);
Amiga2Date(tv.tv_secs, &cd);
SNPrintf(buffer, DATETIME_TEXT_LEN, RFC2822TEMPLATE,
(long)cd.mday, Month[cd.month - 1], (long)cd.year,
(long)cd.hour, (long)cd.min, (long)cd.sec,
TimezoneSignChar(&Timezone->current),
(long)Timezone->current.offset.hours,
(long)Timezone->current.offset.minutes);
}
}
void Utc2RFC3339(struct timeval *utv, char *buffer, bool showUtc)
{
struct timeval tv;
struct ClockData cd;
if (showUtc)
{
Unix2Amiga(utv, &tv);
Amiga2Date(tv.tv_secs, &cd);
SNPrintf(buffer, DATETIME_TEXT_LEN, RFC3339TEMPLATEUTC,
(long)cd.year, (long)cd.month, (long)cd.mday,
(long)cd.hour, (long)cd.min, (long)cd.sec,
(long)(tv.tv_micro / 10000));
}
else
{
UnixUtc2AmigaLocal(utv, &tv);
Amiga2Date(tv.tv_secs, &cd);
SNPrintf(buffer, DATETIME_TEXT_LEN, RFC3339TEMPLATELOC,
(long)cd.year, (long)cd.month, (long)cd.mday,
(long)cd.hour, (long)cd.min, (long)cd.sec,
(long)(tv.tv_micro / 10000),
TimezoneSignChar(&Timezone->current),
(long)Timezone->current.offset.hours,
(long)Timezone->current.offset.minutes);
}
}
void Utc2ISO8601(struct timeval *utv, char *buffer, bool showUtc)
{
struct timeval tv;
struct ClockData cd;
if (showUtc)
{
Unix2Amiga(utv, &tv);
Amiga2Date(tv.tv_secs, &cd);
SNPrintf(buffer, DATETIME_TEXT_LEN, ISO8601TEMPLATEUTC,
(long)cd.year, (long)cd.month, (long)cd.mday,
(long)cd.hour, (long)cd.min, (long)cd.sec);
}
else
{
UnixUtc2AmigaLocal(utv, &tv);
Amiga2Date(tv.tv_secs, &cd);
SNPrintf(buffer, DATETIME_TEXT_LEN, ISO8601TEMPLATELOC,
(long)cd.year, (long)cd.month, (long)cd.mday,
(long)cd.hour, (long)cd.min, (long)cd.sec,
TimezoneSignChar(&Timezone->current),
(long)Timezone->current.offset.hours,
(long)Timezone->current.offset.minutes);
}
}
void LogTransitionMap(void)
{
struct PosixTransitionTime *transition;
struct DateStamp ds;
time_t next;
char timeString[20];
char dateString[20];
char dayString[20];
int i;
for (i = 0; i < 138; i++)
{
transition = &Timezone->transitions[i];
next = transition->time;
Amiga2DateStamp(&next, &ds);
DateTimeString(&ds, timeString, dateString, dayString);
LogNoticeMsg("Timezone",
"Changing (%010ld) to %s time on %s %s at %s %s",
(long)next,
transition->isdst ? tzDstAbbr : tzStdAbbr,
dayString, dateString, timeString,
transition->isdst
? Timezone->std.abbreviation
: Timezone->dst.abbreviation);
}
}
+39 -24
View File
@@ -27,34 +27,49 @@
#ifndef LOCALE_H_INCLUDED
#define LOCALE_H_INCLUDED
#include <libraries/locale.h>
#include "compiler.h"
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;
};
#include <libraries/locale.h>
#include <devices/timer.h>
#define LOCAL_TIME_NOW 0
#define ZONE_IN_PARENS 0
#define OFFSET_IN_PARENS 1
#define UTC_NO_PARENS 2
#define TZD_SECONDS_AHEAD 1
#define TZD_MINUTES_AHEAD 2
#define TZD_TZ_LONG 3
#define TZD_TZ_SHORT 4
#define TZD_ISO8601_NO_COLON 5
#define TZD_ISO8601_COLON 6
#define TZD_ISO8601_SHORT 7
#define TZD_COMMON 8
#define TZD_ZONE_IN_PARENS 9
#define TZD_OFFSET_IN_PARENS 10
#define TZD_STD 11
#define TZD_DST 12
#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);
#define DATETIME_TEXT_LEN 40
#define ASCIITEMPLATE "%s %s %ld %02ld:%02ld:%02ld %04ld"
#define RFC850TEMPLATE "%s, %02ld-%s-%02ld %02ld:%02ld:%02ld GMT"
#define RFC1123TEMPLATE "%s, %02ld %s %04ld %02ld:%02ld:%02ld GMT"
#define RFC2822TEMPLATE "%02ld. %s %04ld %02ld:%02ld:%02ld %s%02ld%02ld"
#define RFC3339TEMPLATEUTC "%04ld-%02ld-%02ld %02ld:%02ld:%02ld.%02ldZ"
#define RFC3339TEMPLATELOC "%04ld-%02ld-%02ld %02ld:%02ld:%02ld.%02ld%s%02ld:%02ld"
#define ISO8601TEMPLATEUTC "%04ld%02ld%02ldT%02ld%02ld%02ldZ"
#define ISO8601TEMPLATELOC "%04ld-%02ld-%02ldT%02ld:%02ld:%02ld%s%02ld:%02ld"
char *GetTimeText(ULONG);
void GetTimezoneText(char *, long);
void LogTransitionMap(void);
void Utc2ASCII(struct timeval *, char *, bool);
void Utc2DOS(struct timeval *, char *, bool);
void Utc2ARexxDate(struct timeval *, char *, bool);
void Utc2ARexxTime(struct timeval *, char *, bool);
void Utc2RFC850(struct timeval *, char *);
void Utc2RFC1123(struct timeval *, char *);
void Utc2RFC2822(struct timeval *, char *, bool);
void Utc2RFC3339(struct timeval *, char *, bool);
void Utc2ISO8601(struct timeval *, char *, bool);
#endif
+22
View File
@@ -34,6 +34,7 @@
#include "string.h"
#include "global.h"
#include "message.h"
#include "setting.h"
static void VLogLine(enum LogSeverity level, const char *module, const char *format, va_list ap)
{
@@ -49,6 +50,9 @@ static void VLogLine(enum LogSeverity level, const char *module, const char *for
void LogMemTraceMsg(const char *module, const char *format, ...)
{
if (Settings->NoLog)
return;
va_list args;
va_start(args, format);
VLogLine(MemTraceMessage, module, format, args);
@@ -57,6 +61,9 @@ void LogMemTraceMsg(const char *module, const char *format, ...)
void LogDebugMsg(const char *module, const char *format, ...)
{
if (Settings->NoLog)
return;
va_list args;
va_start(args, format);
VLogLine(DebugMessage, module, format, args);
@@ -65,6 +72,9 @@ void LogDebugMsg(const char *module, const char *format, ...)
void LogTraceMsg(const char *module, const char *format, ...)
{
if (Settings->NoLog)
return;
va_list args;
va_start(args, format);
VLogLine(TraceMessage, module, format, args);
@@ -73,6 +83,9 @@ void LogTraceMsg(const char *module, const char *format, ...)
void LogInfoMsg(const char *module, const char *format, ...)
{
if (Settings->NoLog)
return;
va_list args;
va_start(args, format);
VLogLine(InfoMessage, module, format, args);
@@ -81,6 +94,9 @@ void LogInfoMsg(const char *module, const char *format, ...)
void LogNoticeMsg(const char *module, const char *format, ...)
{
if (Settings->NoLog)
return;
va_list args;
va_start(args, format);
VLogLine(NoticeMessage, module, format, args);
@@ -89,6 +105,9 @@ void LogNoticeMsg(const char *module, const char *format, ...)
void LogWarnMsg(const char *module, const char *format, ...)
{
if (Settings->NoLog)
return;
va_list args;
va_start(args, format);
VLogLine(WarningMessage, module, format, args);
@@ -97,6 +116,9 @@ void LogWarnMsg(const char *module, const char *format, ...)
void LogErrorMsg(const char *module, const char *format, ...)
{
if (Settings->NoLog)
return;
va_list args;
va_start(args, format);
VLogLine(ErrorMessage, module, format, args);
+1 -1
View File
@@ -45,7 +45,7 @@
#define UTILITYNAME "utility.library"
#endif
#define TIMELOGGER "TimeLogger 1.11 (11.01.2021)"
#define TIMELOGGER "TimeLogger 1.12 (31.01.2021)"
#define ARGSFORMAT "D=DEBUG/K/N,M=MODULEOFF/S,S=SEVERITYOFF/S,H=HELP/S"
#define MODULENAME "Logger"
+15 -18
View File
@@ -41,18 +41,11 @@
#define MODULENAME "Main"
const char *vers = "\0$VER: " APP_ID;
static const char *template = KEYWORD_TEMPLATE;
static const char *template = KWD_TMPL;
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)
{
InitMemSafe();
@@ -69,10 +62,9 @@ int main(int argc, char **argv)
return RETURN_FAIL;
}
InitTimezone();
LoadSettings();
if (argc != 0)
if (Cli() != NULL)
GetCliSettings();
else
GetWbSettings((struct WBStartup *)argv);
@@ -81,14 +73,15 @@ int main(int argc, char **argv)
SanitizeSettings();
ShowSettings();
InitTimezone();
StartBroker();
ShowLocalTime();
CleanupTimezone();
StopTimezoneCheck();
CloseSocketLibrary();
CloseLibraries();
CleanupSettings();
CleanupArexx();
CleanupARexx();
FreePosixTimezone(Timezone);
FreeAllSafe();
LogNotice("Shutdown complete");
@@ -99,23 +92,25 @@ static void GetCliSettings(void)
{
struct AppSettings *settings;
struct RDArgs *inArgs;
long args[KEYWORD_COUNT];
LONG args[KEYWORD_COUNT];
int i;
LogTrace("Parsing CLI settings");
for (i = 0; i < KEYWORD_COUNT; i++)
args[i] = 0;
settings = CreateSettings(CliSettingType);
inArgs = ReadArgs((void *)template, (void *)&args, NULL);
inArgs = ReadArgs((CONST_STRPTR) template, (LONG *)&args, NULL);
if (inArgs)
{
// Keyword order in template needs to match order in settingFunctions
for (i = 0; i < KEYWORD_COUNT; i++)
{
if (args[i] != 0)
LONG j = FindArg((STRPTR) template, (STRPTR)settingFunctions[i].Name);
if (j != -1 && args[j] != 0)
{
settingFunctions[i].Function(settings, (void *)args[i]);
settingFunctions[i].Function(settings, (void *)args[j]);
}
}
FreeArgs(inArgs);
@@ -132,6 +127,8 @@ static void GetWbSettings(struct WBStartup *wbs)
BPTR oldDir;
int argNo, i;
LogTrace("Parsing Workbench settings");
filename = (STRPTR)AllocStringSafe(MAXFILEPATHLEN);
settings = CreateSettings(WbSettingType);
+6 -6
View File
@@ -40,7 +40,7 @@ struct MsgPort *volatile SyncerPort;
struct MsgPort *volatile WindowPort;
struct MsgPort *volatile MemoryPort;
struct MsgPort *volatile ControlPort;
struct MsgPort *volatile ArexxPort;
struct MsgPort *volatile ARexxPort;
int outstanding;
static void PublishPort(long, char *);
@@ -52,7 +52,7 @@ void InitMessages(void)
WindowPort = NULL;
MemoryPort = NULL;
ControlPort = NULL;
ArexxPort = NULL;
ARexxPort = NULL;
outstanding = 0;
CreateMessagePort(MSGPORT_MEMORY);
@@ -93,9 +93,9 @@ void CleanupPorts(void)
DestroyMessagePort(MSGPORT_CONTROL);
}
if (ArexxPort != NULL)
if (ARexxPort != NULL)
{
RemPort((struct MsgPort *)ArexxPort);
RemPort((struct MsgPort *)ARexxPort);
DestroyMessagePort(MSGPORT_AREXX);
}
@@ -130,7 +130,7 @@ static struct MsgPort *FindMessagePort(long port)
return (struct MsgPort *)ControlPort;
break;
case MSGPORT_AREXX:
return (struct MsgPort *)ArexxPort;
return (struct MsgPort *)ARexxPort;
break;
default:
return NULL;
@@ -167,7 +167,7 @@ static struct MsgPort *volatile *FindMessagePortAddress(long port, char **name)
s = "Control";
break;
case MSGPORT_AREXX:
p = &ArexxPort;
p = &ARexxPort;
s = "ARexx";
break;
default:
+4
View File
@@ -33,6 +33,8 @@
#define LOGGER_PORT_NAME "TimeLoggerIn"
#define CONTROL_PORT_NAME "TimeKeeperCtrl"
#define AREXX_PORT_NAME "TIMEKEEPER.1"
#define AREXX_ERROR_VAR_CODE "TIMEKEEPER.ERRORCODE"
#define AREXX_ERROR_VAR_TEXT "TIMEKEEPER.ERRORTEXT"
#define ATK_DEFAULT 0
#define ATK_LASTSYNC 1
@@ -54,6 +56,8 @@
#define ATK_ID 50
#define ATK_VERSION 51
#define ATK_STATUS 52
#define ATK_TIME 53
#define ATK_TIMEZONE 54
#define ATK_CTRL_OK 0
#define ATK_CTRL_ERROR 10
+13 -14
View File
@@ -26,6 +26,7 @@
#include <dos/dos.h>
#include <dos/notify.h>
#include <assert.h>
#include "config.h"
#include "mem.h"
@@ -37,21 +38,21 @@ struct NotifyRequestNode
{
long Registered;
struct NotifyRequest *Request;
volatile struct NotifyRequestNode *Next;
struct NotifyRequestNode *Next;
};
volatile static struct NotifyRequestNode *Last = NULL;
static struct NotifyRequestNode *Last = NULL;
static void AddRequest(struct NotifyRequest *request)
{
volatile struct NotifyRequestNode *node;
node = AllocStructSafe(struct NotifyRequestNode);
struct NotifyRequestNode *node = AllocStructSafe(struct NotifyRequestNode);
if (node == NULL)
{
return;
}
// Init node
node->Registered = DOSFALSE;
node->Request = request;
node->Next = NULL;
@@ -71,14 +72,9 @@ static void AddRequest(struct NotifyRequest *request)
void ActivateNotifyPort(struct MsgPort *port)
{
volatile struct NotifyRequestNode *current;
assert(port != NULL);
if (port == NULL)
{
return;
}
current = Last;
struct NotifyRequestNode *current = Last;
while (current != NULL)
{
if (current->Registered != DOSTRUE)
@@ -92,7 +88,7 @@ void ActivateNotifyPort(struct MsgPort *port)
}
else
{
LogWarn("Could not get notifications from %s", current->Request->nr_Name);
LogWarn("Could not get notifications for %s", current->Request->nr_Name);
}
}
current = current->Next;
@@ -115,7 +111,7 @@ void WatchFile(char *file, long type)
return;
}
request->nr_Flags = NRF_SEND_MESSAGE | NRB_WAIT_REPLY;
request->nr_Flags = NRF_SEND_MESSAGE | NRF_WAIT_REPLY;
request->nr_UserData = type;
AddRequest(request);
@@ -130,6 +126,7 @@ void CleanupNotifications(void)
{
if (current->Registered == DOSTRUE)
{
LogTrace("Removing notification for %s", current->Request->nr_Name);
EndNotify(current->Request);
}
FreeMemSafe((void *)current->Request->nr_Name);
@@ -139,4 +136,6 @@ void CleanupNotifications(void)
FreeMemSafe((void *)current);
current = next;
}
Last = NULL;
}
+109 -178
View File
@@ -32,9 +32,8 @@
#include <proto/utility.h>
#include "ptz.h"
#include "string.h"
#include "global.h"
#include "mem.h"
#include "string.h"
#include "logmod.h"
#define MODULENAME "Posix TZ"
@@ -59,7 +58,7 @@ static const char *ParseInt(const char *p, int min, int max, int *result)
/*
* Parse abbreviation part of POSIX TZ string.
*/
static const char *ParseAbbr(const char *p, char **result)
static const char *ParseAbbr(const char *p, char *result)
{
const char *start = p;
@@ -72,8 +71,8 @@ static const char *ParseAbbr(const char *p, char **result)
return NULL;
}
*result = AllocStringSafe(p - start);
CopyMem((APTR)start, *result, p - start);
int l = (p - start > MAX_ABBR - 1 ? MAX_ABBR - 1 : p - start);
CopyMem((APTR)start, (APTR)result, (ULONG)l);
return ++p;
}
@@ -84,8 +83,8 @@ static const char *ParseAbbr(const char *p, char **result)
if (p - start < 3)
return NULL;
*result = AllocStringSafe(p - start + 1);
CopyMem((APTR)start, *result, p - start);
int l = (p - start > MAX_ABBR - 1 ? MAX_ABBR - 1 : p - start);
CopyMem((APTR)start, (APTR)result, (ULONG)l);
return p;
}
@@ -215,7 +214,7 @@ static bool ParsePosixTz(const char *tz, struct PosixTimezone *result)
if (*p == ':')
return false;
p = ParseAbbr(p, &result->std.abbreviation);
p = ParseAbbr(p, result->std.abbreviation);
p = ParseTime(p, 0, 24, -1, &result->std.offset);
if (p == NULL)
@@ -224,15 +223,15 @@ static bool ParsePosixTz(const char *tz, struct PosixTimezone *result)
if (*p == '\0')
return true;
p = ParseAbbr(p, &result->dst.abbreviation);
p = ParseAbbr(p, result->dst.abbreviation);
if (p == NULL)
return false;
// Default is one hour ahead of std
result->dst.offset.sign = result->std.offset.sign;
result->dst.offset.hours = (result->dst.offset.sign < 0)
? result->std.offset.hours - 1
: 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;
@@ -250,29 +249,6 @@ 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;
@@ -315,7 +291,19 @@ static int FindDay(int year, int month, int week, int day)
days = 29;
}
if (week == 5)
if (week == 1)
{
int i;
for (i = 1; i <= days; i++)
{
int a = FindWeekDay(year, month, i);
if (day == a)
{
return i;
}
}
}
else if (week == 5)
{
int i;
for (i = (days - 6); i <= days; i++)
@@ -334,25 +322,26 @@ static int FindDay(int year, int month, int week, int day)
for (i = 1; i <= days; i++)
{
int a = FindWeekDay(year, month, i);
if (a == 0 && i != 1)
{
j++;
}
if (day == a && week == j)
{
return i;
}
if (a == 0 && i != 1)
{
j++;
}
}
}
return -1;
LogError("Failed to find transition date");
return 1;
}
static ULONG FindTransitionTime(int year, struct PosixTransition *transition)
static time_t FindTransitionTime(int year, struct PosixTransition *transition)
{
struct ClockData day;
ULONG transitionTime = 0;
signed long transitionTime = 0;
day.sec = 0;
day.min = 0;
@@ -387,7 +376,6 @@ static ULONG FindTransitionTime(int year, struct PosixTransition *transition)
break;
}
// TODO: Validate sign
transitionTime +=
(transition->offset.sign < 0 ? -1 : 1) *
(transition->offset.hours * 60 * 60 +
@@ -397,90 +385,20 @@ static ULONG FindTransitionTime(int year, struct PosixTransition *transition)
return transitionTime;
}
struct PosixTransitionTime *FindNextTransition(time_t now)
{
int i = 0;
if (Timezone->start.type == 0)
{
return NULL;
}
while (Timezone->transitions[i].time < now)
{
i++;
}
return &Timezone->transitions[i];
}
static char *GetVariable(const char *variable)
{
unsigned long memsize = 256;
STRPTR var = (STRPTR)variable;
STRPTR buf = (STRPTR)AllocStringSafe(memsize);
if (!buf)
{
return NULL;
}
if (GetVar(var, buf, memsize - 1, GVF_GLOBAL_ONLY) > 0)
{
return (char *)buf;
}
FreeMemSafe(buf);
return NULL;
}
void CleanupPosixTimezone(void)
{
if (Timezone != NULL)
{
if (Timezone->std.abbreviation != NULL)
{
FreeMemSafe(Timezone->std.abbreviation);
}
if (Timezone->dst.abbreviation != NULL)
{
FreeMemSafe(Timezone->dst.abbreviation);
}
FreeMemSafe(Timezone);
Timezone = NULL;
}
}
static void InitFromTZone(void)
{
if (Timezone->dst.abbreviation != NULL)
{
// DST is present
Timezone->current.abbreviation = Timezone->dst.abbreviation;
Timezone->current.offset = Timezone->dst.offset;
}
else
{
Timezone->current.abbreviation = Timezone->std.abbreviation;
Timezone->current.offset = Timezone->std.offset;
}
}
static void BuildTransitionMap()
static void BuildTransitionMap(struct PosixTimezone *ptz)
{
int i = 0;
bool isdst = false;
bool north;
switch (Timezone->start.type)
switch (ptz->start.type)
{
case JulianDay:
case JulianDayLeap:
isdst = Timezone->start.day > Timezone->end.day;
isdst = ptz->start.day > ptz->end.day;
break;
case DayWeekMonth:
isdst = Timezone->start.month > Timezone->end.month;
isdst = ptz->start.month > ptz->end.month;
break;
default:
return;
@@ -489,103 +407,116 @@ static void BuildTransitionMap()
north = isdst ? false : true;
Timezone->transitions[0].time = 0;
Timezone->transitions[0].isdst = isdst;
ptz->transitions[0].time = 0;
ptz->transitions[0].isdst = isdst;
for (i = 0; i < 138 / 2; i++)
for (i = 0; i < MAX_TRANSITIONS / 2 - 1; i++)
{
ULONG time;
time_t time;
isdst = isdst ? false : true;
time = north
? FindTransitionTime(i + 1978, &ptz->start)
: FindTransitionTime(i + 1978, &ptz->end);
ptz->transitions[i * 2 + 1].time = time;
ptz->transitions[i * 2 + 1].isdst = isdst;
isdst = isdst ? false : true;
time = north
? FindTransitionTime(i + 1978, &Timezone->start)
: FindTransitionTime(i + 1978, &Timezone->end);
? FindTransitionTime(i + 1978, &ptz->end)
: FindTransitionTime(i + 1978, &ptz->start);
Timezone->transitions[i * 2 + 1].time = time;
Timezone->transitions[i * 2 + 1].isdst = isdst;
isdst = isdst ? false : true;
time = north
? FindTransitionTime(i + 1978, &Timezone->end)
: FindTransitionTime(i + 1978, &Timezone->start);
Timezone->transitions[i * 2 + 2].time = time;
Timezone->transitions[i * 2 + 2].isdst = isdst;
ptz->transitions[i * 2 + 2].time = time;
ptz->transitions[i * 2 + 2].isdst = isdst;
}
Timezone->transitions[137].time = 2147483647;
Timezone->transitions[137].isdst = false;
ptz->transitions[MAX_TRANSITIONS - 1].time = 2147483647;
ptz->transitions[MAX_TRANSITIONS - 1].isdst = false;
}
int InitPosixTimezone(char **variable)
char *TimezoneSignChar(struct PosixLocalTimezone *ptz)
{
int result = 5;
char *var;
static char *positive = "+";
static char *negative = "-";
Timezone = NULL;
var = GetVariable("TZ");
if (var == NULL)
if (ptz == NULL)
{
var = GetVariable("TZONE");
result = 4;
return positive;
}
if (var == NULL)
if (ptz->offset.hours == 0 && ptz->offset.minutes == 0 && ptz->offset.seconds == 0)
{
return 1;
return positive;
}
*variable = StrDupSafe(var);
Timezone = AllocStructSafe(struct PosixTimezone);
if (!ParsePosixTz(var, Timezone))
if (ptz->offset.sign >= 0)
{
FreeMemSafe(var);
CleanupPosixTimezone();
return result - 2;
return positive;
}
FreeMemSafe(var);
return negative;
}
if (Timezone->start.type == 0)
void FreePosixTimezone(struct PosixTimezone *ptz)
{
if (ptz == NULL)
return;
FreeMemSafe(ptz);
}
struct PosixTimezone *InitPosixTimezone(char *variable)
{
struct PosixTimezone *ptz = AllocStructSafe(struct PosixTimezone);
ptz->source = PosixTypeTimezone;
if (ParsePosixTz(variable, ptz))
{
InitFromTZone();
if (ptz->start.type != 0)
{
BuildTransitionMap(ptz);
}
}
else
{
BuildTransitionMap();
FreePosixTimezone(ptz);
ptz = NULL;
}
return result;
return ptz;
}
bool SetPosixTimezone(struct timeval *tv)
void SetPosixTimezone(struct PosixTimezone *ptz, struct timeval *tv)
{
if (ptz == NULL || ptz->start.type == 0)
return;
int i = 0;
if (Timezone->start.type == 0)
{
return false;
}
while (Timezone->transitions[i].time <= tv->tv_secs)
{
time_t time = (time_t)tv->tv_secs;
while (i < MAX_TRANSITIONS && ptz->transitions[i].time <= time)
i++;
}
i--;
if (Timezone->transitions[i].isdst)
if (ptz->transitions[--i].isdst)
{
Timezone->current.abbreviation = Timezone->dst.abbreviation;
Timezone->current.offset = Timezone->dst.offset;
StrCopy(ptz->current.abbreviation, ptz->dst.abbreviation);
ptz->current.offset = ptz->dst.offset;
}
else
{
Timezone->current.abbreviation = Timezone->std.abbreviation;
Timezone->current.offset = Timezone->std.offset;
StrCopy(ptz->current.abbreviation, ptz->std.abbreviation);
ptz->current.offset = ptz->std.offset;
}
}
return true;
struct PosixTransitionTime *FindNextTransition(struct PosixTimezone *ptz, struct timeval *tv)
{
if (ptz->start.type == 0)
return NULL;
int i = 0;
time_t time = (time_t)tv->tv_secs;
while (i < MAX_TRANSITIONS && ptz->transitions[i].time < time)
i++;
return &ptz->transitions[i];
}
+15 -8
View File
@@ -37,6 +37,12 @@
#define JulianDayLeap 2
#define DayWeekMonth 3
#define CustomTypeTimezone 1
#define PosixTypeTimezone 2
#define MAX_ABBR 10
#define MAX_TRANSITIONS 138
struct PosixTimezoneOffset
{
int sign; // before/after 00:00:00, -1 or 1
@@ -47,7 +53,7 @@ struct PosixTimezoneOffset
struct PosixTransition
{
int type; // type of transistion [0:2]
int type; // type of transistion [0:3]
int day; // day of year (leap or non-leap) [0:365]
int weekday; // day of week [0:6]
int week; // week of month [1:5]
@@ -63,24 +69,25 @@ struct PosixTransitionTime
struct PosixLocalTimezone
{
char *abbreviation;
char abbreviation[MAX_ABBR];
struct PosixTimezoneOffset offset;
};
struct PosixTimezone
{
int source; // time zone source [1:2]
struct PosixLocalTimezone current;
struct PosixLocalTimezone std;
struct PosixLocalTimezone dst;
struct PosixTransition start;
struct PosixTransition end;
struct PosixTransitionTime transitions[138];
struct PosixTransitionTime transitions[MAX_TRANSITIONS];
};
int InitPosixTimezone(char **);
void CleanupPosixTimezone(void);
bool SetPosixTimezone(struct timeval *tv);
struct PosixTransitionTime *FindNextTransition(time_t);
char* PosixTimezoneSignChar(struct PosixLocalTimezone *);
char *TimezoneSignChar(struct PosixLocalTimezone *);
struct PosixTimezone *InitPosixTimezone(char *);
void FreePosixTimezone(struct PosixTimezone *);
void SetPosixTimezone(struct PosixTimezone *, struct timeval *);
struct PosixTransitionTime *FindNextTransition(struct PosixTimezone *, struct timeval *);
#endif
+11
View File
@@ -0,0 +1,11 @@
; Set TZ to North East American time zone
; Start with 'EXECUTE SetTZCentralEurope'
;
ECHO "Changing to Central European time zone ..."
SETENV TZ CET-1CEST,M3.5.0,M10.5.0/3
ECHO "To take effect restart AmiTimeKeeper first"
; Save between reboots with :
; COPY CLONE ENV:TZ ENVARC:TZ
+11
View File
@@ -0,0 +1,11 @@
; Set TZ to North East American time zone
; Start with 'EXECUTE SetTZNorthEastAmerica'
;
ECHO "Changing to North East American time zone ..."
SETENV TZ EST5EDT,M3.2.0,M11.1.0
ECHO "To take effect restart AmiTimeKeeper first"
; Save between reboots with :
; COPY CLONE ENV:TZ ENVARC:TZ
+147 -11
View File
@@ -46,7 +46,15 @@ static const struct AppSettingKeys SettingKeyStruct = {
.Popup = KEYWORD_POPUP,
.Readonly = KEYWORD_READONLY,
.Expert = KEYWORD_EXPERT,
.Timeout = KEYWORD_TIMEOUT};
.Timeout = KEYWORD_TIMEOUT,
.Active = KEYWORD_ACTIVE,
.NoLog = KEYWORD_NOLOG,
.TZ = KEYWORD_TZ,
.TimeZoneDisplay = KEYWORD_TZD,
.TimeZoneName = KEYWORD_TZNAME,
.TimeZoneValue = KEYWORD_TZVALUE,
.TimeZoneDst = KEYWORD_TZDST,
.PopupOnStart = KEYWORD_POPUP2};
const struct AppSettings DefaultSettings = {
.Type = DefaultSettingType,
@@ -60,7 +68,15 @@ const struct AppSettings DefaultSettings = {
.Expert = EXPERT_DEF,
.Priority = PRIORITY_DEF,
.Threshold = THRESHOLD_DEF,
.Values = 0xFFFF};
.Active = ACTIVE_DEF,
.NoLog = NOLOG_DEF,
.TZ = TZ_DEF,
.TimeZoneDisplay = TZD_DEF,
.TimeZoneName = TZNAME_DEF,
.TimeZoneValue = TZVALUE_DEF,
.TimeZoneDst = TZDST_DEF,
.Values = 0xFFFFF,
.PopupOnStart = false};
static void SetPrioritySetting(struct AppSettings *, void *);
static void SetIntervalSetting(struct AppSettings *, void *);
@@ -72,11 +88,20 @@ static void SetReadOnlySetting(struct AppSettings *, void *);
static void SetExpertSetting(struct AppSettings *, void *);
static void SetPopupSetting(struct AppSettings *, void *);
static void SetPopKeySetting(struct AppSettings *, void *);
static void SetActiveSetting(struct AppSettings *, void *);
static void SetNoLogSetting(struct AppSettings *, void *);
static void SetTZSetting(struct AppSettings *, void *);
static void SetTimeZoneDisplaySetting(struct AppSettings *, void *);
static void SetTimeZoneNameSetting(struct AppSettings *, void *);
static void SetTimeZoneValueSetting(struct AppSettings *, void *);
static void SetTimeZoneDstSetting(struct AppSettings *, void *);
static void ExecutePopupFunction(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_ACTIVE, SetActiveSetting},
{KEYWORD_NOLOG, SetNoLogSetting},
{KEYWORD_SERVER, SetDestinationAddressSetting},
{KEYWORD_PORT, SetDestinationPortSetting},
{KEYWORD_TIMEOUT, SetTimeoutSetting},
@@ -84,7 +109,13 @@ const struct SettingFunc settingFunctions[] = {
{KEYWORD_INTERVAL, SetIntervalSetting},
{KEYWORD_PRIORITY, SetPrioritySetting},
{KEYWORD_POPKEY, SetPopKeySetting},
{KEYWORD_POPUP, SetPopupSetting}};
{KEYWORD_POPUP, SetPopupSetting},
{KEYWORD_TZ, SetTZSetting},
{KEYWORD_TZD, SetTimeZoneDisplaySetting},
{KEYWORD_TZNAME, SetTimeZoneNameSetting},
{KEYWORD_TZVALUE, SetTimeZoneValueSetting},
{KEYWORD_TZDST, SetTimeZoneDstSetting},
{KEYWORD_POPUP2, ExecutePopupFunction}};
#define MAXSETTINGLINELEN 256
@@ -122,6 +153,13 @@ void ShowAppSettings(struct AppSettings *settings)
LogDebug(settingValueLong, SettingKeys->Interval, settings->Interval);
LogDebug(settingValueString, SettingKeys->Readonly, BooleanAsText(settings->Readonly));
LogDebug(settingValueString, SettingKeys->Expert, BooleanAsText(settings->Expert));
LogDebug(settingValueString, SettingKeys->Active, BooleanAsText(settings->Active));
LogDebug(settingValueString, SettingKeys->NoLog, BooleanAsText(settings->NoLog));
LogDebug(settingValueString, SettingKeys->TZ, settings->TZ);
LogDebug(settingValueString, SettingKeys->TimeZoneName, settings->TimeZoneName);
LogDebug(settingValueLong, SettingKeys->TimeZoneValue, settings->TimeZoneValue);
LogDebug(settingValueLong, SettingKeys->TimeZoneDisplay, settings->TimeZoneDisplay);
LogDebug(settingValueLong, SettingKeys->TimeZoneDst, settings->TimeZoneDst);
}
void ShowSettings(void)
@@ -278,12 +316,63 @@ static void SetExpertSetting(struct AppSettings *settings, void *value)
&settings->Expert, value, true);
}
static void SetActiveSetting(struct AppSettings *settings, void *value)
{
ParseBooleanSetting(settings, ActiveSet, SettingKeys->Active,
&settings->Active, value, true);
}
static void SetNoLogSetting(struct AppSettings *settings, void *value)
{
ParseBooleanSetting(settings, NoLogSet, SettingKeys->NoLog,
&settings->NoLog, value, true);
}
static void SetPopupSetting(struct AppSettings *settings, void *value)
{
ParseBooleanSetting(settings, PopUpSet, SettingKeys->Popup,
&settings->Popup, value, false);
}
static void SetTZSetting(struct AppSettings *settings, void *value)
{
LogFoundSetting(settings->Type, SettingKeys->TZ);
settings->TZ = StrDupSafe((const char *)value);
settings->Values |= TzSet;
}
static void SetTimeZoneDisplaySetting(struct AppSettings *settings, void *value)
{
ParseLongSetting(settings, TimeZoneDisplaySet, SettingKeys->TimeZoneDisplay,
&settings->TimeZoneDisplay, value);
}
static void SetTimeZoneNameSetting(struct AppSettings *settings, void *value)
{
LogFoundSetting(settings->Type, SettingKeys->TimeZoneName);
settings->TimeZoneName = StrDupSafe((const char *)value);
settings->Values |= TimeZoneNameSet;
}
static void SetTimeZoneValueSetting(struct AppSettings *settings, void *value)
{
ParseLongSetting(settings, TimeZoneValueSet, SettingKeys->TimeZoneValue,
&settings->TimeZoneValue, value);
}
static void SetTimeZoneDstSetting(struct AppSettings *settings, void *value)
{
ParseLongSetting(settings, TimeZoneDstSet, SettingKeys->TimeZoneDst,
&settings->TimeZoneDst, value);
}
static void ExecutePopupFunction(struct AppSettings *settings, void *value)
{
// Run-time switch. Show settings window when starting
LogFoundSetting(settings->Type, SettingKeys->PopupOnStart);
settings->PopupOnStart = true;
}
static void ParseSetting(struct AppSettings *settings, char *line)
{
char *value;
@@ -399,7 +488,13 @@ static void WriteSetting(BPTR file, const char *format, ...)
void SaveSettings(bool persist)
{
char low[MAXLONGLONGCHARSIZE];
const char *dirName = persist ? persistentPrefsDir : prefsDir;
const char *fileName = persist ? persistentPrefsFile : prefsFile;
BPTR lock = CreateDir((STRPTR)dirName);
if (lock != NULL)
UnLock(lock);
BPTR file = Open((STRPTR)fileName, MODE_NEWFILE);
if (!file)
{
@@ -423,6 +518,21 @@ void SaveSettings(bool persist)
WriteSetting(file, saveValueLong, SettingKeys->Interval, Settings->Interval);
WriteSetting(file, saveValueString, SettingKeys->Readonly, BooleanAsText(Settings->Readonly));
WriteSetting(file, saveValueString, SettingKeys->Expert, BooleanAsText(Settings->Expert));
WriteSetting(file, saveValueString, SettingKeys->Active, BooleanAsText(Settings->Active));
WriteSetting(file, saveValueString, SettingKeys->NoLog, BooleanAsText(Settings->NoLog));
WriteSetting(file, saveValueLong, SettingKeys->TimeZoneDisplay, Settings->TimeZoneDisplay);
if (Settings->TZ != NULL && *Settings->TZ != '\0')
WriteSetting(file, saveValueString, SettingKeys->TZ, Settings->TZ);
if (Settings->TimeZoneName != NULL && *Settings->TimeZoneName != '\0')
WriteSetting(file, saveValueString, SettingKeys->TimeZoneName, Settings->TimeZoneName);
if (Settings->TimeZoneValue != TZVALUE_DEF)
WriteSetting(file, saveValueLong, SettingKeys->TimeZoneValue, Settings->TimeZoneValue);
if (Settings->TimeZoneDst != TZDST_DEF)
WriteSetting(file, saveValueLong, SettingKeys->TimeZoneDst, Settings->TimeZoneDst);
Close(file);
}
@@ -442,26 +552,28 @@ struct AppSettings *CopySettings(const struct AppSettings *settings)
s->DestinationAddress = StrDupSafe(settings->DestinationAddress);
s->DestinationPort = StrDupSafe(settings->DestinationPort);
s->PopKey = StrDupSafe(settings->PopKey);
s->Values = 0xFFFF;
s->TZ = StrDupSafe(settings->TZ);
s->TimeZoneName = StrDupSafe(settings->TimeZoneName);
s->Values = 0xFFFFF;
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);
}
if (settings->TZ != NULL)
FreeMemSafe(settings->TZ);
if (settings->TimeZoneName != NULL)
FreeMemSafe(settings->TimeZoneName);
FreeMemSafe(settings);
}
@@ -569,6 +681,21 @@ void ApplyAppSettings(struct AppSettings *settings, bool quiet)
break;
}
if (settings->Type == CliSettingType || settings->Type == WbSettingType)
Settings->PopupOnStart = settings->PopupOnStart;
ApplyStringSetting(settings, TzSet, SettingKeys->TZ,
&Settings->TZ, settings->TZ, quiet);
ApplyLongSetting(settings, TimeZoneDisplaySet, SettingKeys->TimeZoneDisplay,
&Settings->TimeZoneDisplay, &settings->TimeZoneDisplay, quiet);
ApplyStringSetting(settings, TimeZoneNameSet, SettingKeys->TimeZoneName,
&Settings->TimeZoneName, settings->TimeZoneName, quiet);
ApplyLongSetting(settings, TimeZoneValueSet, SettingKeys->TimeZoneValue,
&Settings->TimeZoneValue, &settings->TimeZoneValue, quiet);
ApplyBooleanSetting(settings, PopUpSet, SettingKeys->Popup,
&Settings->Popup, &settings->Popup, quiet);
@@ -584,12 +711,21 @@ void ApplyAppSettings(struct AppSettings *settings, bool quiet)
ApplyLongSetting(settings, IntervalSet, SettingKeys->Interval,
&Settings->Interval, &settings->Interval, quiet);
ApplyLongSetting(settings, TimeZoneDstSet, SettingKeys->TimeZoneDst,
&Settings->TimeZoneDst, &settings->TimeZoneDst, quiet);
ApplyBooleanSetting(settings, ReadonlySet, SettingKeys->Readonly,
&Settings->Readonly, &settings->Readonly, quiet);
ApplyBooleanSetting(settings, ExpertSet, SettingKeys->Expert,
&Settings->Expert, &settings->Expert, quiet);
ApplyBooleanSetting(settings, ActiveSet, SettingKeys->Active,
&Settings->Active, &settings->Active, quiet);
ApplyBooleanSetting(settings, NoLogSet, SettingKeys->NoLog,
&Settings->NoLog, &settings->NoLog, quiet);
ApplyStringSetting(settings, DestinationAddressSet, SettingKeys->DestinationAddress,
&Settings->DestinationAddress, settings->DestinationAddress, quiet);
+33 -10
View File
@@ -30,16 +30,23 @@
#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 PrioritySet 0x0001
#define TimeoutSet 0x0002
#define IntervalSet 0x0004
#define ReadonlySet 0x0008
#define ExpertSet 0x0010
#define DestinationAddressSet 0x0020
#define DestinationPortSet 0x0040
#define ThresholdSet 0x0080
#define PopKeySet 0x0100
#define PopUpSet 0x0200
#define ActiveSet 0x0400
#define NoLogSet 0x0800
#define TzSet 0x1000
#define TimeZoneDisplaySet 0x2000
#define TimeZoneNameSet 0x4000
#define TimeZoneValueSet 0x8000
#define TimeZoneDstSet 0x10000
#define DefaultSettingType 0x01
#define PrefsSettingType 0x02
@@ -59,8 +66,16 @@ struct AppSettings
char *DestinationPort;
char *PopKey;
long Popup;
long Active;
long NoLog;
char *TZ;
long TimeZoneDisplay;
char *TimeZoneName;
long TimeZoneValue;
long TimeZoneDst;
long Values;
long Type;
long PopupOnStart;
};
struct AppSettingKeys
@@ -75,6 +90,14 @@ struct AppSettingKeys
const char *Threshold;
const char *PopKey;
const char *Popup;
const char *Active;
const char *NoLog;
const char *TZ;
const char *TimeZoneDisplay;
const char *TimeZoneName;
const char *TimeZoneValue;
const char *TimeZoneDst;
const char *PopupOnStart;
};
typedef void (*ParseSettingFunction)(struct AppSettings *, void *);
+2 -56
View File
@@ -36,6 +36,7 @@
#include "timer.h"
#include "conv.h"
#include "sntp.h"
#include "text.h"
#include "ptz.h"
#include "mem.h"
#include "net.h"
@@ -54,7 +55,6 @@ struct AppCom
struct sntp *Client;
int TimerSigBit;
bool Restart;
int RunCount;
int PoolServerNumber;
char *ServerName;
char *ServerPort;
@@ -63,7 +63,6 @@ struct AppCom
static void SyncProc(void);
static int SyncClock(void);
static void ChooseServer(void);
static void CheckTimezone(void);
static const char *SntpErrorText(enum sntp_err error);
static struct AppCom Synchronizer;
@@ -100,7 +99,7 @@ void StartSynchronizer(void)
if (running)
{
LogDebug("Synchronizer process is already running");
LogDebug(Text2P, "Synchronizer", TextAlreadyRunning);
}
else if (task != NULL)
{
@@ -112,13 +111,6 @@ void StartSynchronizer(void)
}
}
static void ShowLocalTime(void)
{
char *time = GetTimeText(AppLocale, LOCAL_TIME_NOW);
LogNotice("Local time is %s", time);
FreeMemSafe(time);
}
static int ComInit(void)
{
if (OpenSocketLibrary() != LIB_OK)
@@ -164,26 +156,9 @@ static void SendSync(void)
if (ComInit() == COM_OK)
{
if (SyncClock() == COM_OK)
{
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);
}
}
ComDestroy();
@@ -250,7 +225,6 @@ static void SyncProc(void)
Synchronizer.Client = NULL;
Synchronizer.TimerSigBit = -1;
Synchronizer.Restart = false;
Synchronizer.RunCount = 0;
Synchronizer.PoolServerNumber = -1;
Synchronizer.ServerName = NULL;
Synchronizer.ServerPort = NULL;
@@ -454,38 +428,10 @@ static int SyncClock(void)
LastSync = rtv;
SendWindowMessage(ATK_LASTSYNC);
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();
LogNotice("Current time zone is %s", Timezone);
LogWarn("Changing time zone");
// TODO: Make thread safe
ShowLocalTime();
InitTimezoneShift();
SendWindowMessage(ATK_TZ_CHANGED);
}
}
static const char *SntpErrorText(enum sntp_err error)
{
switch (error)
+53 -2
View File
@@ -27,8 +27,10 @@
#include "text.h"
// Settings
const char *prefsFile = "ENV:timekeeper.prefs";
const char *persistentPrefsFile = "ENVARC:timekeeper.prefs";
const char *prefsDir = "ENV:AmiTimeKeeper";
const char *prefsFile = "ENV:AmiTimeKeeper/timekeeper.prefs";
const char *persistentPrefsDir = "ENVARC:AmiTimeKeeper";
const char *persistentPrefsFile = "ENVARC:AmiTimeKeeper/timekeeper.prefs";
const char *prefsFileSearch = "Searching for preference in %s";
const char *prefsFileFound = "Found preference file";
const char *prefsFileNotFound = "Preference file not found";
@@ -52,6 +54,10 @@ const char *settingChangedLong = "%s changed: %ld -> %ld";
const char *settingChangedString = "%s changed: %s -> %s";
const char *settingSetLong = "%s is already set to %ld";
const char *settingSetString = "%s is already set to %s";
const char *settingTooLow = "%s < %ld (too low)";
const char *settingTooHigh = "%s > %ld (too high)";
const char *settingGreaterThan = "%s * 2 > %s";
const char *settingInvalid = "%s is invalid (%ld)";
const char *settingValueLong = "%s=%ld";
const char *settingValueString = "%s=%s";
const char *saveValueLong = "%s=%ld\n";
@@ -60,9 +66,43 @@ const char *noValueString = "NO";
const char *yesValueString = "YES";
const char *falseValueString = "TRUE";
const char *trueValueString = "FALSE";
const char *validatingSettings = "Validating settings";
const char *validatedSettings = "Settings validated";
// Time zone
const char *applyTimeZone = "Setting local time zone from %s %s";
const char *tzSettingValid = "Found valid %s %s";
const char *tzSettingInvalid = "Found unknown %s %s";
const char *tzFromEnv = "environment variable";
const char *tzFromSet = "setting value in";
const char *tzWorkbench = "Workbench";
const char *tzPreferences = "preferences";
const char *tzChange = "Changing to %s on %s";
const char *tzDstAbbr = "DST";
const char *tzStdAbbr = "standard time";
const char *timezoneCur = "Current time zone is %s";
const char *timezoneStd = "Standard time zone is %s";
const char *timezoneDst = "DST time zone is %s";
const char *timezoneNoTrans = "There are no time zone transitions";
const char *tzChecker = "Timezone Checker";
const char *tzCheck = "Checking for time zone transition";
const char *tzTrans = "Performing time zone transition";
// Concat text
const char *Text2P = "%s %s";
// Common text
const char *TextEmpty = "Empty";
const char *TextStarting = "Starting";
const char *TextRestarting = "Restarting";
const char *TextStarted = "started";
const char *TextStopped = "stopped";
const char *TextAlreadyRunning = "is already running";
const char *TextNoStart = "Could not start";
const char *TextClosing = "Closing";
const char *TextOpened = "Opened";
const char *TextNoOpen = "Cannot open";
const char *TextFound = "Found";
// Error / debug messages
const char *TextPortInitError = "%s message port failed to initialize";
@@ -78,3 +118,14 @@ const char *TextSyncAlreadyOn = "Synchronization is already active";
const char *TextSyncAlreadyOff = "Synchronization is already deactivated";
const char *TextNoResponses = "No responses from NTP server";
const char *TextNoClockAdjust = "Clock has not been adjusted";
const char *TextARexxCmdUnknown = "Unknown ARexx command";
const char *TextARexxParmUnknown = "Unknown parameter";
const char *TextARexxParmInvalid = "Invalid parameter value";
const char *TextARexxParmMiss = "Parameter is missing";
const char *TextARexxVarError = "Could not set ARexx variable: %ld";
const char *TextARexxVarValue = "ARexx variable %s = %s";
const char *TextARexxResult = "ARexx result: %s";
const char *TextARexxExecute1 = "Executing %s";
const char *TextARexxExecute2 = "Executing %s %s";
const char *TextARexxReceived = "Received %s";
const char *TextARexxShutdown = "Requesting shutdown";
+53
View File
@@ -30,7 +30,9 @@
#include "config.h"
// Settings
const char *prefsDir;
const char *prefsFile;
const char *persistentPrefsDir;
const char *persistentPrefsFile;
const char *prefsFileSearch;
const char *prefsFileFound;
@@ -55,6 +57,10 @@ const char *settingChangedLong;
const char *settingChangedString;
const char *settingSetLong;
const char *settingSetString;
const char *settingTooLow;
const char *settingTooHigh;
const char *settingGreaterThan;
const char *settingInvalid;
const char *settingValueLong;
const char *settingValueString;
const char *saveValueLong;
@@ -63,9 +69,45 @@ const char *noValueString;
const char *yesValueString;
const char *falseValueString;
const char *trueValueString;
const char *validatingSettings;
const char *validatedSettings;
// Library
// Time zone
const char *applyTimeZone;
const char *tzSettingValid;
const char *tzSettingInvalid;
const char *tzFromEnv;
const char *tzFromSet;
const char *tzWorkbench;
const char *tzPreferences;
const char *tzChange;
const char *tzDstAbbr;
const char *tzStdAbbr;
const char *timezoneCur;
const char *timezoneStd;
const char *timezoneDst;
const char *timezoneNoTrans;
const char *tzChecker;
const char *tzCheck;
const char *tzTrans;
// Concat text
const char *Text2P;
// Common text
const char *TextEmpty;
const char *TextStarting;
const char *TextRestarting;
const char *TextStarted;
const char *TextStopped;
const char *TextAlreadyRunning;
const char *TextNoStart;
const char *TextClosing;
const char *TextOpened;
const char *TextNoOpen;
const char *TextFound;
// Error / debug messages
const char *TextPortInitError;
@@ -81,5 +123,16 @@ const char *TextSyncAlreadyOn;
const char *TextSyncAlreadyOff;
const char *TextNoResponses;
const char *TextNoClockAdjust;
const char *TextARexxCmdUnknown;
const char *TextARexxParmUnknown;
const char *TextARexxParmInvalid;
const char *TextARexxParmMiss;
const char *TextARexxVarError;
const char *TextARexxVarValue;
const char *TextARexxResult;
const char *TextARexxExecute1;
const char *TextARexxExecute2;
const char *TextARexxReceived;
const char *TextARexxShutdown;
#endif
+390 -182
View File
@@ -28,206 +28,330 @@
#include "notify.h"
#include "global.h"
#include "message.h"
#include "setting.h"
#include "conv.h"
#include "text.h"
#include "ptz.h"
#include "timer.h"
#include "mem.h"
#include "tz.h"
#include <assert.h>
#include <utility/date.h>
#include "logmod.h"
#define MODULENAME "Timezone"
#define EnvTZTimezone 1
#define EnvTZOneTimezone 2
#define SetTZEnvTimezone 3
#define SetTZValTimezone 4
#define PrefsTimezone 5
#define TIMEZONE_STD 1
#define TIMEZONE_DST 2
#define ENV_TZ "TZ"
#define ENV_TZONE "TZONE"
#define ENV_TZ_FILE "ENV:TZ"
#define ENV_TZONE_FILE "ENV:TZONE"
#define ENV_PREFS_FILE "ENV:Sys/locale.prefs"
/*
* 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;
static volatile bool TimezoneCheckerRunning = false;
static volatile bool TimezoneCheckerRestart = false;
static volatile bool TimezoneCheckerShutdown = false;
static volatile long TimezoneSource = 0;
static volatile long unixEpochOffset = 0;
void LogTzInfo()
static void StartTimezoneCheck(void);
static void BuildTimezone(struct PosixLocalTimezone *timezone, int offset, bool std)
{
if (Timezone == NULL)
{
return;
}
long sign = (offset < 0 ? -1 : +1);
long offsetPositive = (offset < 0 ? -offset : offset);
long hoursOffset = (offsetPositive / 60L);
long minutsOffset = (offsetPositive % 60L);
if (Timezone->dst.abbreviation != NULL)
if (Settings->TimeZoneName != NULL && *Settings->TimeZoneName != '\0' &&
((Settings->TimeZoneDst <= 0 && std) || (Settings->TimeZoneDst == 1 && !std)))
SNPrintf(timezone->abbreviation, MAX_ABBR - 1, "%s", Settings->TimeZoneName);
else if (minutsOffset == 0)
{
LogInfo("Standard time zone is %s (GMT%s%02ld:%02ld)",
Timezone->std.abbreviation,
PosixTimezoneSignChar(&Timezone->std),
(long)Timezone->std.offset.hours,
(long)Timezone->std.offset.minutes);
LogInfo("DST time zone is %s (GMT%s%02ld:%02ld)",
Timezone->dst.abbreviation,
PosixTimezoneSignChar(&Timezone->dst),
(long)Timezone->dst.offset.hours,
(long)Timezone->dst.offset.minutes);
SNPrintf(timezone->abbreviation, MAX_ABBR - 1, "GMT%s%ld",
(sign <= 0 ? "+" : "-"), hoursOffset);
}
else
{
LogInfo("time zone is %s (GMT%s%02ld:%02ld)",
Timezone->std.abbreviation,
PosixTimezoneSignChar(&Timezone->std),
(long)Timezone->std.offset.hours,
(long)Timezone->std.offset.minutes);
SNPrintf(timezone->abbreviation, MAX_ABBR - 1, "GMT%s%ld:%02ld",
(sign <= 0 ? "+" : "-"), hoursOffset, minutsOffset);
}
timezone->offset.hours = hoursOffset;
timezone->offset.minutes = minutsOffset;
timezone->offset.seconds = 0;
timezone->offset.sign = -sign;
}
static void FindCurrentTimezone(struct PosixTimezone *timezone, long opt)
{
if (opt == TIMEZONE_STD)
{
StrCopy(timezone->current.abbreviation, timezone->std.abbreviation);
timezone->current.offset = timezone->std.offset;
}
else if (opt == TIMEZONE_DST)
{
StrCopy(timezone->current.abbreviation, timezone->dst.abbreviation);
timezone->current.offset = timezone->dst.offset;
}
}
static void SetCurrentTimezone(struct PosixTimezone *timezone)
{
if (Settings->TimeZoneDst == 0)
FindCurrentTimezone(timezone, TIMEZONE_STD);
else if (Settings->TimeZoneDst == 1)
FindCurrentTimezone(timezone, TIMEZONE_DST);
else if (timezone->source == PosixTypeTimezone &&
timezone->dst.abbreviation == NULL)
FindCurrentTimezone(timezone, TIMEZONE_DST);
else
FindCurrentTimezone(timezone, TIMEZONE_STD);
}
static struct PosixTimezone *BuildAmigaTimezone(struct Locale *locale)
{
struct PosixTimezone *tz = AllocStructSafe(struct PosixTimezone);
tz->source = CustomTypeTimezone;
long offset = (locale != NULL ? locale->loc_GMTOffset : 0);
BuildTimezone(&tz->std, offset, true);
BuildTimezone(&tz->dst, offset - 60, false);
SetCurrentTimezone(tz);
return tz;
}
static struct PosixTimezone *BuildSettingsTimezone(void)
{
struct PosixTimezone *tz = AllocStructSafe(struct PosixTimezone);
tz->source = CustomTypeTimezone;
long value = Settings->TimeZoneValue;
long hours = (value != TZVALUE_DEF ? (value / -100) : 0);
long minutes = (value != TZVALUE_DEF ? (value % -100) : 0);
long offset = hours * 60 + minutes;
BuildTimezone(&tz->std, offset, true);
BuildTimezone(&tz->dst, offset - 60, false);
SetCurrentTimezone(tz);
return tz;
}
static void ShowTimezones(void)
{
char timezone[TIMEZONE_TEXT_LEN];
GetTimezoneText(timezone, TZD_STD);
LogInfo(timezoneStd, timezone);
GetTimezoneText(timezone, TZD_DST);
LogInfo(timezoneDst, timezone);
GetTimezoneText(timezone, TZD_OFFSET_IN_PARENS);
LogNotice(timezoneCur, timezone);
}
static char *GetVariable(const char *variable)
{
unsigned long memsize = 256;
STRPTR var = (STRPTR)variable;
STRPTR buf = (STRPTR)AllocStringSafe(memsize);
if (!buf)
{
return NULL;
}
if (GetVar(var, buf, memsize - 1, GVF_GLOBAL_ONLY) > 0)
{
return (char *)buf;
}
FreeMemSafe(buf);
return NULL;
}
static struct PosixTimezone *ParseSettingsTZ()
{
struct PosixTimezone *timezone = NULL;
if (Settings->TZ != NULL && *Settings->TZ != '\0')
{
timezone = InitPosixTimezone(Settings->TZ);
if (timezone != NULL)
LogInfo(tzSettingValid, tzFromSet, SettingKeys->TZ);
else
LogInfo(tzSettingInvalid, tzFromSet, SettingKeys->TZ);
LogDebug(settingValueString, SettingKeys->TZ, Settings->TZ);
}
return timezone;
}
static struct PosixTimezone *ParseEnvTZ(const char *tz)
{
struct PosixTimezone *timezone = NULL;
char *var = GetVariable(tz);
if (var != NULL)
{
timezone = InitPosixTimezone(var);
if (timezone != NULL)
LogInfo(tzSettingValid, tzFromEnv, tz);
else
LogInfo(tzSettingInvalid, tzFromEnv, tz);
LogDebug(settingValueString, tz, var);
FreeMemSafe(var);
}
return timezone;
}
static void ShowTimezoneSource(void)
{
switch (TimezoneSource)
{
case SetTZValTimezone:
LogNotice(applyTimeZone, tzFromSet, SettingKeys->TimeZoneValue);
break;
case SetTZEnvTimezone:
LogNotice(applyTimeZone, tzFromSet, SettingKeys->TZ);
break;
case EnvTZTimezone:
LogNotice(applyTimeZone, tzFromEnv, ENV_TZ);
break;
case EnvTZOneTimezone:
LogNotice(applyTimeZone, tzFromEnv, ENV_TZONE);
break;
case PrefsTimezone:
LogNotice(applyTimeZone, tzWorkbench, tzPreferences);
break;
default:
break;
}
}
static void ShowNextTransition(void)
{
if (NextTransition != NULL)
{
char *nextTime = GetTimeText((ULONG)NextTransition->time);
const char *nextTrans = NextTransition->isdst ? tzDstAbbr : tzStdAbbr;
LogWarn(tzChange, nextTrans, nextTime);
FreeMemSafe(nextTime);
}
}
void InitTimezone(void)
{
char TimezoneText[TIMEZONE_TEXT_LEN];
char *tz;
int result;
CleanupNotifications();
tz = NULL;
result = InitPosixTimezone(&tz);
switch (result)
struct Locale *locale = OpenLocale(NULL);
struct PosixTimezone *set1Timezone = ParseSettingsTZ();
struct PosixTimezone *set2Timezone = BuildSettingsTimezone();
struct PosixTimezone *env1Timezone = ParseEnvTZ(ENV_TZ);
struct PosixTimezone *env2Timezone = ParseEnvTZ(ENV_TZONE);
struct PosixTimezone *prefTimezone = BuildAmigaTimezone(locale);
CloseLocale(locale);
struct timeval tv;
GetSysTime(&tv);
SetPosixTimezone(set1Timezone, &tv);
SetPosixTimezone(env1Timezone, &tv);
SetPosixTimezone(env2Timezone, &tv);
long source = 0;
struct PosixTimezone *timezone = NULL;
if (Settings->TimeZoneValue != TZVALUE_DEF)
{
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");
LogNotice("Using local time zone from the TZONE variable");
LogDebug("TZONE = %s", tz);
WatchFile("ENV:TZONE", ATK_TZONE_CHANGED);
break;
case 5:
LogInfo("Found valid TZ variable");
LogNotice("Using local time zone from the TZ variable");
LogDebug("TZ = %s", tz);
WatchFile("ENV:TZ", ATK_TZ_CHANGED);
break;
default:
LogWarn("Unknown TZ or TZONE code");
break;
source = SetTZValTimezone;
timezone = set2Timezone;
}
if (tz != NULL)
else if (set1Timezone != NULL)
{
FreeMemSafe(tz);
source = SetTZEnvTimezone;
timezone = set1Timezone;
}
if (result == 4 || result == 5)
else if (env1Timezone != NULL)
{
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);
LogNotice("Current time zone is %s", TimezoneText);
source = EnvTZTimezone;
timezone = env1Timezone;
}
else if (env2Timezone != NULL)
{
source = EnvTZOneTimezone;
timezone = env2Timezone;
}
else
{
LogNotice("Using local time zone from Workbench preferences");
WatchFile("ENV:Sys/locale.prefs", ATK_LOCALE_CHANGED);
unixEpochOffset = AppLocale->AmigaLocale->loc_GMTOffset * 60 + AMIGA_OFFSET;
GetTimezoneText(AppLocale, TimezoneText, OFFSET_IN_PARENS);
LogNotice("Current time zone is %s", TimezoneText);
source = PrefsTimezone;
timezone = prefTimezone;
}
InitTimezoneShift();
struct PosixTimezone *activeTimezone = AllocStructSafe(struct PosixTimezone);
CopyMem(timezone, activeTimezone, sizeof(struct PosixTimezone));
FreePosixTimezone(set1Timezone);
FreePosixTimezone(set2Timezone);
FreePosixTimezone(env1Timezone);
FreePosixTimezone(env2Timezone);
FreePosixTimezone(prefTimezone);
struct PosixTransitionTime *activeTransition = FindNextTransition(activeTimezone, &tv);
long offset = (activeTimezone->current.offset.sign < 0 ? +1 : -1) *
(activeTimezone->current.offset.hours * 60 * 60 +
activeTimezone->current.offset.minutes * 60 +
activeTimezone->current.offset.seconds);
offset += AMIGA_OFFSET;
// Switch global time zone variables
Forbid();
struct PosixTimezone *lastTimezone = Timezone;
Timezone = activeTimezone;
TimezoneSource = source;
NextTransition = activeTransition;
unixEpochOffset = offset;
Permit();
switch (source)
{
case EnvTZTimezone:
WatchFile(ENV_TZ_FILE, ATK_TZ_CHANGED);
break;
case EnvTZOneTimezone:
WatchFile(ENV_TZONE_FILE, ATK_TZONE_CHANGED);
break;
case PrefsTimezone:
WatchFile(ENV_PREFS_FILE, ATK_LOCALE_CHANGED);
break;
default:
break;
}
ShowTimezoneSource();
ShowTimezones();
ShowNextTransition();
StartTimezoneCheck();
FreePosixTimezone(lastTimezone);
}
void Amiga2DateStamp(time_t *time, struct DateStamp *date)
void Unix2Amiga(struct timeval *utc, struct timeval *tv)
{
long t, d, m, q;
assert(utc != NULL);
assert(tv != NULL);
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;
tv->tv_secs = utc->tv_secs - AMIGA_OFFSET;
tv->tv_micro = utc->tv_micro;
}
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 Utc2Local(struct timeval *utc, struct timeval *tv)
void UnixUtc2AmigaLocal(struct timeval *utc, struct timeval *tv)
{
assert(utc != NULL);
assert(tv != NULL);
@@ -251,6 +375,11 @@ void GetLocalTimeOfDay(struct timeval *tv)
GetSysTime(tv);
}
long GetUtcOffsetValue(void)
{
return (unixEpochOffset - AMIGA_OFFSET);
}
void SetTimeOfDay(const struct TimerInfo *info, const struct timeval *tv)
{
struct timeval t;
@@ -269,39 +398,118 @@ void SaveTimeOfDay(const struct timeval *tv)
WriteBattClock((long)tv->tv_secs - unixEpochOffset);
}
void DateTimeString(struct DateStamp *ds, char *time, char *date, char *day)
static long GetNextTransition(void)
{
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);
time_t next = (NextTransition != NULL ? NextTransition->time : 2147483647);
return (long)next;
}
void Utc2Str(struct timeval *tv, char *buffer)
static long GetNextTransitionCheck(long now)
{
char timeString[20];
char dateString[20];
char dayString[20];
long diff = GetNextTransition() - now;
diff = (diff > 60 ? 60 : diff);
return diff;
}
struct DateStamp ds;
struct timeval last;
time_t time;
static void CheckTransition(void)
{
TimezoneCheckerShutdown = false;
TimezoneCheckerRestart = false;
Utc2Local(tv, &last);
time = last.tv_secs;
if (NextTransition == NULL)
{
LogNotice(timezoneNoTrans);
LogInfo(Text2P, tzChecker, TextStopped);
TimezoneCheckerRunning = false;
return;
}
Amiga2DateStamp(&time, &ds);
DateTimeString(&ds, timeString, dateString, dayString);
SNPrintf(buffer, 64, "%s %s %s", dayString, dateString, timeString);
LogInfo(Text2P, tzChecker, TextStarted);
struct timeval tv;
GetSysTime(&tv);
ULONG next, now = (ULONG)(tv.tv_secs);
long diff = GetNextTransitionCheck(now);
while (!TimezoneCheckerShutdown)
{
if (diff < 0)
{
LogTrace(tzCheck);
GetSysTime(&tv);
now = (ULONG)(tv.tv_secs);
next = GetNextTransition();
if (now > next)
{
ShowTimezones();
LogNotice(tzTrans);
Forbid();
SetPosixTimezone(Timezone, &tv);
NextTransition = FindNextTransition(Timezone, &tv);
Permit();
ShowTimezones();
SendWindowMessage(ATK_TZ_CHANGED);
}
diff = GetNextTransitionCheck(now);
}
diff--;
Delay(50);
if (TimezoneCheckerRestart)
{
LogInfo(Text2P, TextRestarting, tzChecker);
TimezoneCheckerRestart = false;
diff = -1;
}
}
LogInfo(Text2P, tzChecker, TextStopped);
TimezoneCheckerRunning = false;
TimezoneCheckerShutdown = false;
}
void StopTimezoneCheck(void)
{
TimezoneCheckerShutdown = true;
while (TimezoneCheckerRunning)
Delay(10);
}
static void StartTimezoneCheck(void)
{
if (TimezoneCheckerRunning)
{
LogTrace(Text2P, tzChecker, TextAlreadyRunning);
TimezoneCheckerRestart = true;
return;
}
TimezoneCheckerRunning = true;
LogNotice(Text2P, TextStarting, tzChecker);
struct Task *task = (struct Task *)CreateNewProcTags(
NP_Entry, (IPTR)CheckTransition,
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(Text2P, TextNoStart, tzChecker);
TimezoneCheckerRunning = false;
}
}
+4 -5
View File
@@ -31,14 +31,13 @@
#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 Amiga2DateStamp(time_t *, struct DateStamp *);
void Utc2Local(struct timeval *, struct timeval *);
void Utc2Str(struct timeval *, char *);
long GetUtcOffsetValue(void);
void UnixUtc2AmigaLocal(struct timeval *, struct timeval *);
void Unix2Amiga(struct timeval *, struct timeval *);
void StopTimezoneCheck(void);
#endif
+159 -19
View File
@@ -27,21 +27,18 @@
#include "config.h"
#include "message.h"
#include "setting.h"
#include "text.h"
#include "conv.h"
#include "sync.h"
#include "log.h"
#include "mem.h"
#include "val.h"
#include "win.h"
#include "tz.h"
#include "logmod.h"
#define MODULENAME "Settings"
static const char *settingChangedLong = "%s changed: %ld -> %ld";
static const char *settingChangedString = "%s changed: %s -> %s";
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 ValidateInterval(void)
{
if (Settings->Interval < INTERVAL_MIN)
@@ -55,6 +52,17 @@ static void ValidateInterval(void)
INTERVAL_MIN);
Settings->Interval = INTERVAL_MIN;
}
else if (Settings->Interval > INTERVAL_MAX)
{
LogInfo(settingTooHigh,
SettingKeys->Interval,
INTERVAL_MAX);
LogNotice(settingChangedLong,
SettingKeys->Interval,
Settings->Interval,
INTERVAL_MAX);
Settings->Interval = INTERVAL_MAX;
}
}
static void ValidateTimeout(void)
@@ -126,17 +134,59 @@ static void ValidateThreshold(void)
{
if (Settings->Threshold < THRESHOLD_MIN)
{
LogInfo(settingTooLow,
SettingKeys->Threshold,
THRESHOLD_MIN);
LogNotice(settingChangedLong,
SettingKeys->Threshold,
Settings->Threshold,
THRESHOLD_MIN);
LogInfo(settingTooLow, SettingKeys->Threshold, THRESHOLD_MIN);
LogNotice(settingChangedLong, SettingKeys->Threshold,
Settings->Threshold, THRESHOLD_MIN);
Settings->Threshold = THRESHOLD_MIN;
}
}
static void ValidateTimeZoneDisplay(void)
{
if (Settings->TimeZoneDisplay < TZD_MIN)
{
LogInfo(settingTooLow, SettingKeys->TimeZoneDisplay, TZD_MIN);
LogNotice(settingChangedLong, SettingKeys->TimeZoneDisplay,
Settings->TimeZoneDisplay, TZD_MIN);
Settings->TimeZoneDisplay = TZD_MIN;
}
else if (Settings->TimeZoneDisplay > TZD_MAX)
{
LogInfo(settingTooHigh, SettingKeys->TimeZoneDisplay, TZD_MAX);
LogNotice(settingChangedLong, SettingKeys->TimeZoneDisplay,
Settings->TimeZoneDisplay, TZD_MAX);
Settings->TimeZoneDisplay = TZD_MAX;
}
}
static void ValidateTimeZoneValue(void)
{
if (Settings->TimeZoneValue < TZVALUE_MIN)
{
LogInfo(settingTooLow, SettingKeys->TimeZoneValue, TZVALUE_MIN);
LogNotice(settingChangedLong, SettingKeys->TimeZoneValue,
Settings->TimeZoneValue, TZVALUE_MIN);
Settings->TimeZoneValue = TZVALUE_MIN;
}
else if (Settings->TimeZoneValue != TZVALUE_DEF &&
Settings->TimeZoneValue > TZVALUE_MAX)
{
LogInfo(settingTooHigh, SettingKeys->TimeZoneValue, TZVALUE_MAX);
LogNotice(settingChangedLong, SettingKeys->TimeZoneValue,
Settings->TimeZoneValue, TZVALUE_MAX);
Settings->TimeZoneValue = TZVALUE_MAX;
}
if (Settings->TimeZoneValue % 60 >= 60)
{
long oldValue = Settings->TimeZoneValue;
Settings->TimeZoneValue = (Settings->TimeZoneValue / 60) * 60;
LogInfo(settingInvalid, SettingKeys->TimeZoneValue, oldValue);
LogNotice(settingChangedLong, SettingKeys->TimeZoneValue,
oldValue, Settings->TimeZoneValue);
}
}
static bool ValidateServer(char *name)
{
return true;
@@ -149,12 +199,14 @@ static bool ValidatePort(char *name)
void SanitizeSettings(void)
{
LogTrace("Validating settings");
LogDebug(validatingSettings);
ValidateInterval();
ValidateTimeout();
ValidatePriority();
ValidateThreshold();
LogTrace("Settings validated");
ValidateTimeZoneDisplay();
ValidateTimeZoneValue();
LogTrace(validatedSettings);
}
void SetInterval(long value, long opt)
@@ -323,7 +375,8 @@ void SetServer(char *valueString, long opt)
valueString);
FreeMemSafe(oldValue);
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME)
bool active = SynchronizerRunning;
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME && active)
{
Deactivate();
}
@@ -359,8 +412,10 @@ void SetServer(char *valueString, long opt)
WriteUiServer();
}
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME)
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME && active)
{
while (SynchronizerRunning)
Delay(10);
Activate();
}
}
@@ -386,7 +441,8 @@ void SetPort(char *valueString, long opt)
valueString);
FreeMemSafe(oldValue);
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME)
bool active = SynchronizerRunning;
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME && active)
{
Deactivate();
}
@@ -422,8 +478,92 @@ void SetPort(char *valueString, long opt)
WriteUiPort();
}
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME)
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME && active)
{
while (SynchronizerRunning)
Delay(10);
Activate();
}
}
void SetTimeZoneSetting(const char *settingKey, char **setting, char *valueString, long opt)
{
char *oldSettingValue, *newSettingValue;
char *oldValue;
oldValue = StrDupSafe(*setting);
if (Stricmp((STRPTR)oldValue, (STRPTR)valueString) == 0)
{
FreeMemSafe(oldValue);
return;
}
LogNotice(settingChangedString,
settingKey,
oldValue,
valueString);
FreeMemSafe(oldValue);
bool active = SynchronizerRunning;
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME && active)
{
Deactivate();
}
newSettingValue = StrDupSafe(valueString);
Forbid();
oldSettingValue = *setting;
*setting = newSettingValue;
Permit();
FreeMemSafe(oldSettingValue);
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME && settingKey == SettingKeys->TZ)
{
InitTimezone();
}
if ((opt & APPLY_UI_FRONT) == APPLY_UI_FRONT)
{
SendWindowMessage(ATK_TZ_CHANGED);
}
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME && active)
{
while (SynchronizerRunning)
Delay(10);
Activate();
}
}
void SetTimeZoneSettingLong(const char *settingKey, long *setting, char *valueString, long opt)
{
LONG value, oldValue = *setting;
int p = StrToLong((STRPTR)valueString, &value);
if (p != -1 && oldValue != value)
{
LogNotice(settingChangedLong,
settingKey,
oldValue,
value);
*setting = value;
}
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME)
{
if (settingKey == SettingKeys->TimeZoneValue || settingKey == SettingKeys->TimeZoneDst)
{
InitTimezone();
}
}
if ((opt & APPLY_UI_FRONT) == APPLY_UI_FRONT)
{
SendWindowMessage(ATK_TZ_CHANGED);
}
if ((opt & APPLY_RUNTIME) == APPLY_RUNTIME)
{
SendBrokerMessage(ATK_RESTART);
}
}
+2
View File
@@ -46,5 +46,7 @@ void SetInterval(long, long);
void SetTimeout(long, long);
void SetThreshold(char *, long);
void SetPriority(char *, long);
void SetTimeZoneSetting(const char *, char **, char *, long);
void SetTimeZoneSettingLong(const char *, long *, char *, long);
#endif
+2 -2
View File
@@ -583,7 +583,7 @@ void ShowLastSync(struct timeval *tv)
}
GetLocalTimeOfDay(&nowLocal);
Utc2Local(tv, &lastLocal);
UnixUtc2AmigaLocal(tv, &lastLocal);
seconds = nowLocal.tv_secs - lastLocal.tv_secs;
if (seconds > 60 * 60 * 24)
@@ -615,7 +615,7 @@ void ShowNewTimezone(void)
char *temp = SettingWindow.TimezoneText;
char *new = AllocStringSafe(TIMEZONE_TEXT_LEN);
GetTimezoneText(AppLocale, new, ZONE_IN_PARENS);
GetTimezoneText(new, TZD_ZONE_IN_PARENS);
GT_SetGadgetAttrs(
SettingWindow.Gadgets->TimezoneGadget,
SettingWindow.Window, NULL,
+16 -3
View File
@@ -52,10 +52,12 @@ volatile bool WindowProcRunning = false;
struct AppSettings *WindowSettings = NULL;
struct AppSettingWindow SettingWindow;
static APTR OrgWindowPtr = NULL;
void ShowSettingWindow(void)
{
bool running;
struct Task *task;
struct Task *task = NULL;
if (GadToolsBase == NULL)
{
@@ -84,7 +86,7 @@ void ShowSettingWindow(void)
if (running)
{
LogDebug("Setting process is already running");
LogDebug(Text2P, "Setting process", TextAlreadyRunning);
SendWindowMessage(ATK_SHOW);
}
else if (task != NULL)
@@ -143,7 +145,7 @@ static bool InitWindow(void)
LongToStr(Settings->Priority, SettingWindow.PriorityText);
LongLongToStr(Settings->Threshold, SettingWindow.ThresholdText);
GetTimezoneText(AppLocale, SettingWindow.TimezoneText, ZONE_IN_PARENS);
GetTimezoneText(SettingWindow.TimezoneText, Settings->TimeZoneDisplay);
return true;
}
@@ -159,6 +161,11 @@ static void DestroyWindow(void)
while ((msg = GetMsg(SettingWindow.Window->UserPort)))
ReplyMsg(msg);
Forbid();
struct Process *proc = (struct Process *)FindTask(NULL);
proc->pr_WindowPtr = OrgWindowPtr;
Permit();
CloseWindow(SettingWindow.Window);
SettingWindow.Window = NULL;
}
@@ -215,6 +222,12 @@ static bool CreateWindow(void)
return false;
}
Forbid();
struct Process *proc = (struct Process *)FindTask(NULL);
OrgWindowPtr = proc->pr_WindowPtr;
proc->pr_WindowPtr = x;
Permit();
return true;
}