vkoskiv
/MacNTP
/amendments
/17
Store UTC offset as string and change some rsrc IDs
Moved the STR resource IDs to the range recommended in literature for
use with cdevs, and stuck them in a header to share between the cdev
and INIT.
We now also store the UTC offset as a full string, rather than just
the minutes as a string. The cdev validates before saving, and the
INIT also checks it before using it.
The cdev now also computes an offset and updates the system clock when
setting the UTC offset, since we don't check it again until reboot,
and even then only if the clock is obviously wrong.
vkoskiv made amendment 17 11 months ago
--- cdev.c Wed Sep 13 23:03:35 2023
+++ cdev.c Sun Sep 17 23:52:40 2023
@@ -14,6 +14,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "rsrcid.h"
+#include <OSUtils.h>
+
/*
A basic cdev skeleton + implementation in pure C
For some reason, Symantec decided to embrace OOP for all their
@@ -47,6 +50,8 @@ void got_resource_error(void);
int validate_ntp_url(Str255 utc_str);
int validate_utc(Str255 utc_str);
+int utcstr_to_mins(Str255 utc, long *out);
+
void *got_initDev(void *storage, DialogPtr dialog, short nitems);
void *got_hitDev(void *storage, short item);
void *got_closeDev(void *storage);
@@ -88,9 +93,9 @@ void *got_initDev(void *storage, DialogPtr dialog, sho
SysBeep(1);
}
s = *(struct state **)storage;
- s->ntp1 = GetString(131);
- s->ntp2 = GetString(132);
- s->utc = GetString(133);
+ s->ntp1 = GetString(NTP1_STR_ID);
+ s->ntp2 = GetString(NTP2_STR_ID);
+ s->utc = GetString(UTC_STR_ID);
s->dialog = dialog;
if (!s->ntp1 || !s->ntp2 || !s->utc) {
SysBeep(1);
@@ -135,24 +140,64 @@ int validate_ntp_url(Str255 utc_str) {
return true;
}
+int is_number(char c) {
+ return c >> 4 == 3 && (c & 0x0F) < 0xA;
+}
+
int validate_utc(Str255 utc_str) {
- // TODO
+ // Str255 is a pointer to a pascal string, where
+ // the first byte is the string length.
+ char scratch[6];
+ short strlen;
+ char *str;
+ strlen = utc_str[0];
+ str = (char *)&utc_str[1];
+ if (strlen != 6) return false;
+ if (str[0] != '+' && str[0] != '-') return false;
+ if (!is_number(str[1]) || !is_number(str[2])) return false;
+ if (str[3] != ':') return false;
+ if (!is_number(str[4]) || !is_number(str[5])) return false;
+
return true;
}
+int utcstr_to_mins(Str255 utc, long *out) {
+ long minutes;
+ if (!validate_utc(utc)) return false;
+ minutes = 0;
+ minutes += ((utc[2] - 0x30) * 10) * 60;
+ minutes += (utc[3] - 0x30) * 60;
+ minutes += (utc[5] - 0x30) * 10;
+ minutes += (utc[6] - 0x30);
+ if (utc[1] == '-')
+ minutes = -minutes;
+ if (out) *out = minutes;
+ return true;
+}
+
void *got_hitDev(void *storage, short item) {
Str255 ntp1_text;
Str255 ntp2_text;
Str255 utc_text;
+ long old_utc_offset;
+ long new_utc_offset;
+ long diff_secs;
+ unsigned long systime;
+ int updated;
struct state *s = *(struct state **)storage;
+ updated = false;
if (item == 9) {
GetIText(s->ntp1_textbox.handle, ntp1_text);
GetIText(s->ntp2_textbox.handle, ntp2_text);
GetIText(s->utc_textbox.handle, utc_text);
if (!validate_ntp_url(ntp1_text)) return storage;
if (!validate_ntp_url(ntp2_text)) return storage;
- if (!validate_utc(utc_text)) return storage;
+ if (!validate_utc(utc_text)) {
+ SysBeep(1);
+ SysBeep(1);
+ return storage;
+ }
// All good to go, let's store these settings.
/*
Steps:
@@ -163,19 +208,39 @@ void *got_hitDev(void *storage, short item) {
system clock.
*/
- SetString(s->ntp1, ntp1_text);
- ChangedResource(s->ntp1);
- ReleaseResource(s->ntp1);
- SetString(s->ntp2, ntp2_text);
- ChangedResource(s->ntp2);
- ReleaseResource(s->ntp2);
- SetString(s->utc, utc_text);
- ChangedResource(s->utc);
- ReleaseResource(s->utc);
+ if (!EqualString(s->ntp1, ntp1_text, true, true)) {
+ SetString(s->ntp1, ntp1_text);
+ ChangedResource(s->ntp1);
+ ReleaseResource(s->ntp1);
+ updated = true;
+ }
- UpdateResFile(CurResFile());
- if (ResError()) {
- //DebugStr("\pUpdateResFile failed");
+ if (!EqualString(s->ntp2, ntp2_text, true, true)) {
+ SetString(s->ntp2, ntp2_text);
+ ChangedResource(s->ntp2);
+ ReleaseResource(s->ntp2);
+ updated = true;
+ }
+
+ // Update the utc offset, and tweak system clock if need be
+ if (!EqualString(s->utc, utc_text, true, true)) {
+ if (!utcstr_to_mins(utc_text, &new_utc_offset)) return storage;
+ if (!utcstr_to_mins(*s->utc, &old_utc_offset)) return storage;
+ SetString(s->utc, utc_text);
+ ChangedResource(s->utc);
+ ReleaseResource(s->utc);
+ updated = true;
+ diff_secs = (new_utc_offset - old_utc_offset) * 60;
+ ReadDateTime((unsigned long *)&systime);
+ systime += diff_secs;
+ SetDateTime(systime);
+ }
+
+ if (updated) {
+ UpdateResFile(CurResFile());
+ if (ResError()) {
+ //DebugStr("\pUpdateResFile failed");
+ }
}
}
return storage;
--- MacNTP.π.r Wed Sep 13 22:30:50 2023
+++ MacNTP.π.r Mon Sep 18 00:15:38 2023
@@ -1,12 +1,12 @@
-data 'STR ' (131, "NTP1", sysheap) {
+data 'STR ' (-4048, "NTP1", sysheap) {
$"0F74 696D 652E 676F 6F67 6C65 2E63 6F6D" /* .time.google.com */
};
-data 'STR ' (133, "UTCOFFSETMINUTES", sysheap) {
- $"0331 3830" /* .180 */
+data 'STR ' (-4046, "UTCOFFSET", sysheap) {
+ $"062B 3033 3A30 30" /* .+03:00 */
};
-data 'STR ' (132, "NTP2", sysheap) {
+data 'STR ' (-4047, "NTP2", sysheap) {
$"0E74 696D 652E 6170 706C 652E 636F 6D" /* .time.apple.com */
};
--- main.c Wed Sep 13 22:59:24 2023
+++ main.c Mon Sep 18 00:10:25 2023
@@ -24,6 +24,7 @@ TODO:
#include <SetUpA4.h>
#include "MacNTP.h"
#include "ShowInitIcon.h"
+#include "rsrcid.h"
// This enables DebugStr() printouts to aid development.
// This also disables the system time check, so it tries NTP
@@ -32,18 +33,14 @@ TODO:
void dump_error(enum MacNTPError error, OSErr oserror);
int TryMacNTP(Str255 ntp1, Str255 ntp2, Str255 utc);
+int is_number(char c);
+int validate_utc(Str255 utc_str);
+int utcstr_to_mins(Str255 utc, long *out);
#define SECONDS_TO_02_09_1996 2924510400ul
-#define MACNTP_ICN_ID_PENDING 128
-#define MACNTP_ICN_ID_SUCCESS -4064 // Also used for cdev
-#define MACNTP_ICN_ID_FAILURE 130
Handle g_mtcp_init_handle;
-#define NTP1_URL_STR_ID 131
-#define NTP2_URL_STR_ID 132
-#define UTC_OFFSET_STR_ID 133
-
#ifdef DEBUGGING
void dump_error(enum MacNTPError error, OSErr oserror) {
Str255 numstr;
@@ -96,6 +93,43 @@ void dump_error(enum MacNTPError error, OSErr oserror)
}
#endif
+//FIXME: This is duplicated from cdev.c, but I didn't want to
+//make a library and all the extra build steps just for this.
+//Maybe we'll just stick it in MacNTPLib and figure out linkage somehow
+int is_number(char c) {
+ return c >> 4 == 3 && (c & 0x0F) < 0xA;
+}
+
+int validate_utc(Str255 utc_str) {
+ // Str255 is a pointer to a pascal string, where
+ // the first byte is the string length.
+ char scratch[6];
+ short strlen;
+ char *str;
+ strlen = utc_str[0];
+ str = (char *)&utc_str[1];
+ if (strlen != 6) return false;
+ if (str[0] != '+' && str[0] != '-') return false;
+ if (!is_number(str[1]) || !is_number(str[2])) return false;
+ if (str[3] != ':') return false;
+ if (!is_number(str[4]) || !is_number(str[5])) return false;
+
+ return true;
+}
+int utcstr_to_mins(Str255 utc, long *out) {
+ long minutes;
+ if (!validate_utc(utc)) return false;
+ minutes = 0;
+ minutes += ((utc[2] - 0x30) * 10) * 60;
+ minutes += (utc[3] - 0x30) * 60;
+ minutes += (utc[5] - 0x30) * 10;
+ minutes += (utc[6] - 0x30);
+ if (utc[1] == '-')
+ minutes = -minutes;
+ if (out) *out = minutes;
+ return true;
+}
+
int TryMacNTP(Str255 ntp1, Str255 ntp2, Str255 utc) {
struct ntp_packet payload;
enum MacNTPError error;
@@ -103,7 +137,7 @@ int TryMacNTP(Str255 ntp1, Str255 ntp2, Str255 utc) {
minutes_t utc_offset;
if (!utc[0]) return 1;
- StringToNum(utc, &utc_offset);
+ if (!utcstr_to_mins(utc, &utc_offset)) return 1;
if (!ntp1[0]) return 1;
PtoCstr(ntp1);
@@ -145,9 +179,9 @@ void main() {
// This is already locked in the resource attrs
g_mtcp_init_handle = RecoverHandle(our_init_ptr);
- ntp1 = GetString(NTP1_URL_STR_ID);
- ntp2 = GetString(NTP2_URL_STR_ID);
- utc = GetString(UTC_OFFSET_STR_ID);
+ ntp1 = GetString(NTP1_STR_ID);
+ ntp2 = GetString(NTP2_STR_ID);
+ utc = GetString(UTC_STR_ID);
if (!ntp1 || !ntp2 || !utc) {
#ifdef DEBUGGING
DebugStr("\pSTR rsrcs missing");
--- README Wed Sep 13 23:04:20 2023
+++ README Mon Sep 18 00:17:49 2023
@@ -21,7 +21,7 @@ Prerequisites:
Setup:
Think C 5 doesn't support the kind of multi-target project that combines both an INIT and a cdev, so we have to work around it. We need two projects, and we will first build a cdev (Control Panel Document), and then build a second project to inject the INIT resource into our cdev.
1. Create new Think C project, name it "MacNTP.π" (option+p gets you π)
-2. To this project, add only cdev.c.
+2. To this project, add only cdev.c and MacTraps from Think C's Mac Libraries.
3. Set the project settings like this:
- Select Code Resource.
- File Type = "cdev"
--- rsrcid.h Thu Sep 14 00:29:06 2023
+++ rsrcid.h Thu Sep 14 00:29:06 2023
@@ -0,0 +1,11 @@
+// Resource IDs, shared between INIT and cdev
+
+// STR resources are used in both the INIT and the cdev
+// and cdevs require them to be in the range of -4048 and -4033
+#define NTP1_STR_ID -4048
+#define NTP2_STR_ID -4047
+#define UTC_STR_ID -4046
+
+#define MACNTP_ICN_ID_PENDING 128
+#define MACNTP_ICN_ID_SUCCESS -4064 // Also used for cdev
+#define MACNTP_ICN_ID_FAILURE 130