Browse Source

stdlib: StdChans, TimeString, wrapclock, wraptime, wrapc

Adds the gm2/ISO channel-and-time wrappers that can be expressed in the
current dialect, plus their shim helpers:
- StdChans (settable current channels over IOChan);
- TimeString.GetTimeString (strftime %c via the shim);
- wrapclock (opaque timespec + timezone/daylight/tzname);
- wraptime (opaque timeval/timezone/tm + accessors + LocalTime);
- wrapc (rand range, signbit/isfinite/isnan, seek constants, uid/gid).

The shim gains m2timestring and underscore-free m2wc*/m2wt*/m2c*
helpers (classic identifiers have no '_').

Deviations: wrapc.ReadOnly/WriteOnly return CARDINAL, not BITSET --
BITSET is not supported as a function-result type; wraptime's
localtime_r is spelled LocalTime for the same reason.

ChanConsts/StreamFile are not included: their FlagSet{...} constants
need typed set constructors, which the frontend does not support yet.

Tests: wrapprog.mod (session) exercises all five modules; exit 42.
Suite 176/176; fixpoint OK (2,899,706 bytes).
Eric Streit 1 week ago
parent
commit
05d9bd0417

+ 9 - 0
compiler/run_tests.sh

@@ -256,6 +256,15 @@ expect_run_files DOpaqueProg 55 d_opaque.def d_opaque.mod d_opaque_prog.mod
 expect_run_files TString 42 d_string.def d_string.mod t_string.mod
 expect_run_files FioProg 42 ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod ../runtime/syslib/FileIO.def ../runtime/syslib/FileIO.mod fio_prog.mod
 expect_run_files StorageProg 42 ../stdlib/storage.def ../stdlib/storage.mod storage_prog.mod
+expect_run_files WrapProg 42 \
+  ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod \
+  ../stdlib/iochan.def ../stdlib/iochan.mod \
+  ../stdlib/stdchans.def ../stdlib/stdchans.mod \
+  ../stdlib/timestring.def ../stdlib/timestring.mod \
+  ../stdlib/wrapclock.def ../stdlib/wrapclock.mod \
+  ../stdlib/wraptime.def ../stdlib/wraptime.mod \
+  ../stdlib/wrapc.def ../stdlib/wrapc.mod \
+  wrapprog.mod
 expect_run_files Library1 42 \
   ../runtime/syslib/SysShim.def ../runtime/syslib/SysShim.mod \
   ../stdlib/convtypes.def ../stdlib/convtypes.mod \

+ 55 - 0
compiler/tests/wrapprog.mod

@@ -0,0 +1,55 @@
+MODULE WrapProg;
+// Smoke test for the new wrapper/time modules: StdChans, TimeString,
+// wrapclock, wraptime, wrapc.  Exit 42.
+IMPORT StdChans, TimeString, wrapclock, wraptime, wrapc;
+IMPORT IOChan;
+FROM SYSTEM IMPORT ADDRESS;
+
+VAR ExitCode : INTEGER;
+VAR s, t : ARRAY [0..63] OF CHAR;
+VAR ts : wrapclock.timespec;
+VAR tv : wraptime.timeval;
+VAR tm : wraptime.tm;
+VAR sec, nano : LONGCARD;
+VAR ok : INTEGER;
+VAR n : INTEGER;
+VAR out : IOChan.ChanId;
+
+BEGIN
+  (* StdChans: the current output channel is the standard one *)
+  out := StdChans.OutChan();
+  IOChan.WriteString(out, "wrappers ");
+  IOChan.WriteLn(out);
+
+  (* TimeString: a non-empty time string *)
+  TimeString.GetTimeString(s);
+  ok := 0;
+  IF s[0] # CHR(0) THEN INC(ok) END;
+
+  (* wrapclock: a timespec, read back *)
+  ts := wrapclock.InitTimespec();
+  ok := ok + wrapclock.GetTimeRealtime(ts);
+  ok := ok + wrapclock.GetTimespec(ts, sec, nano);
+  ok := ok + wrapclock.SetTimespec(ts, 5, 7);
+  ok := ok + wrapclock.GetTimespec(ts, sec, nano);
+  IF (sec = 5) AND (nano = 7) THEN INC(ok) END;
+  ts := wrapclock.KillTimespec(ts);
+
+  (* wraptime: timeval + localtime + field accessors *)
+  tv := wraptime.InitTimeval();
+  tm := wraptime.InitTM();
+  ok := ok + wraptime.gettimeofday(tv, NIL);
+  wraptime.SetTimeval(tv, 0, 0);
+  IF wraptime.LocalTime(tv, tm) # NIL THEN INC(ok) END;
+  IF wraptime.GetYear(tm) >= 1970 THEN INC(ok) END;
+  tm := wraptime.KillTM(tm);
+  tv := wraptime.KillTimeval(tv);
+
+  (* wrapc: rand range, signbit, isfinite *)
+  n := wrapc.getrand(10);
+  IF (n >= 0) AND (n < 10) THEN INC(ok) END;
+  IF wrapc.signbit(-1.0) = 1 THEN INC(ok) END;
+  IF wrapc.isfinite(1.0) = 1 THEN INC(ok) END;
+
+  IF ok >= 7 THEN ExitCode := 42 ELSE ExitCode := ok END
+END WrapProg.

+ 107 - 0
runtime/syslib/shim.c

@@ -830,3 +830,110 @@ long m2dstrimpostfix(char *s)
     }
     return (long)s;
 }
+
+/* ---------------- TimeString / wrapclock / wraptime / wrapc -------- */
+
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <pwd.h>
+#include <math.h>
+#include <fcntl.h>
+
+long m2timestring(long *desc)
+{
+    char buf[128];
+    char *dst = (char *)(desc + 1);
+    long cap = desc[0], n;
+    time_t t = time(NULL);
+    struct tm tmv;
+    localtime_r(&t, &tmv);
+    if (strftime(buf, sizeof buf, "%c", &tmv) == 0) buf[0] = 0;
+    n = (long)strlen(buf);
+    if (cap < 0) cap = 0;
+    if (n > cap) n = cap;
+    memcpy(dst, buf, (size_t)n);
+    dst[n] = 0;
+    return n;
+}
+
+long m2wctimezone(void)   { return (long)timezone; }
+long m2wcistimezone(void) { return 1; }
+long m2wcdaylight(void)   { return (long)daylight; }
+long m2wcisdst(void)      { return 1; }
+long m2wctzname(long d)   { return (long)(d ? tzname[1] : tzname[0]); }
+void *m2wctsnew(void)     { return calloc(1, sizeof(struct timespec)); }
+void *m2wctskill(void *ts){ free(ts); return NULL; }
+long m2wctsget(void *ts, long *sec, long *nano)
+{
+    struct timespec *t = (struct timespec *)ts;
+    if (t == NULL) return -1;
+    *sec = (long)t->tv_sec; *nano = (long)t->tv_nsec; return 0;
+}
+long m2wctsset(void *ts, long sec, long nano)
+{
+    struct timespec *t = (struct timespec *)ts;
+    if (t == NULL) return -1;
+    t->tv_sec = (time_t)sec; t->tv_nsec = (long)nano; return 0;
+}
+long m2wctsrealtime(void *ts)
+{ return clock_gettime(CLOCK_REALTIME, (struct timespec *)ts); }
+long m2wctssetrealtime(void *ts)
+{ return clock_settime(CLOCK_REALTIME, (struct timespec *)ts); }
+
+void *m2wttvnew(void) { return calloc(1, sizeof(struct timeval)); }
+void *m2wttvkill(void *p) { free(p); return NULL; }
+void *m2wttznew(void) { return calloc(1, sizeof(struct timezone)); }
+void *m2wttzkill(void *p) { free(p); return NULL; }
+void *m2wttmnew(void) { return calloc(1, sizeof(struct tm)); }
+void *m2wttmkill(void *p) { free(p); return NULL; }
+long m2wtgettimeofday(void *tv, void *tz)
+{ return gettimeofday((struct timeval *)tv, (struct timezone *)tz); }
+long m2wtsettimeofday(void *tv, void *tz)
+{ return settimeofday((struct timeval *)tv, (struct timezone *)tz); }
+long m2wtfractions(void *tv)
+{ struct timeval *t = (struct timeval *)tv; return t ? (long)t->tv_usec : 0; }
+void *m2wtlocaltime(void *tv, void *tm)
+{ struct timeval *t = (struct timeval *)tv; return localtime_r(&t->tv_sec, (struct tm *)tm); }
+long m2wtyear(void *m)   { return ((struct tm *)m)->tm_year + 1900; }
+long m2wtmonth(void *m)  { return ((struct tm *)m)->tm_mon + 1; }
+long m2wtday(void *m)    { return ((struct tm *)m)->tm_mday; }
+long m2wthour(void *m)   { return ((struct tm *)m)->tm_hour; }
+long m2wtminute(void *m) { return ((struct tm *)m)->tm_min; }
+long m2wtsecond(void *m) { return ((struct tm *)m)->tm_sec; }
+void m2wttvset(void *tv, long sec, long usec)
+{ struct timeval *t = (struct timeval *)tv; t->tv_sec = (time_t)sec; t->tv_usec = (long)usec; }
+void m2wttzset(void *tz, long minuteswest, long dsttime)
+{ struct timezone *z = (struct timezone *)tz; z->tz_minuteswest = (int)minuteswest; z->tz_dsttime = (int)dsttime; }
+
+long m2cstrtime(void) { time_t t = time(NULL); return (long)ctime(&t); }
+long m2cfilesize(long f, long *low, long *high)
+{
+    struct stat st;
+    if (fstat((int)f, &st) != 0) { *low = 0; *high = 0; return -1; }
+    *low = (long)(st.st_size & 0xffffffffL);
+    *high = (long)((unsigned long long)st.st_size >> 32);
+    return 0;
+}
+long m2cfileinode(long f, long *low, long *high)
+{
+    struct stat st;
+    if (fstat((int)f, &st) != 0) { *low = 0; *high = 0; return -1; }
+    *low = (long)(st.st_ino & 0xffffffffL);
+    *high = (long)((unsigned long long)st.st_ino >> 32);
+    return 0;
+}
+long m2cfilemtime(long f)
+{ struct stat st; if (fstat((int)f, &st) != 0) return -1; return (long)st.st_mtime; }
+long m2cgetrand(long n) { return n <= 0 ? 0 : (long)(random() % n); }
+long m2cgetusername(void)
+{ struct passwd *pw = getpwuid(getuid()); return pw ? (long)pw->pw_name : (long)""; }
+void m2cgetnameuidgid(long name, long *uid, long *gid)
+{ struct passwd *pw = getpwnam((const char *)name);
+  if (pw == NULL) { *uid = -1; *gid = -1; } else { *uid = (long)pw->pw_uid; *gid = (long)pw->pw_gid; } }
+long m2csignbit(double r)  { return signbit(r) ? 1 : 0; }
+long m2cisfinite(double x) { return isfinite(x) ? 1 : 0; }
+long m2cisnan(double x)    { return isnan(x) ? 1 : 0; }
+long m2cseekset(void)      { return (long)SEEK_SET; }
+long m2cseekend(void)      { return (long)SEEK_END; }
+long m2creadonly(void)     { return (long)O_RDONLY; }
+long m2cwriteonly(void)    { return (long)O_WRONLY; }

+ 22 - 0
stdlib/stdchans.def

@@ -0,0 +1,22 @@
+DEFINITION MODULE StdChans;
+(* ISO 10514-1: the standard channels, with settable current
+   in/out/err channels. *)
+
+IMPORT IOChan;
+
+TYPE
+  ChanId = IOChan.ChanId;
+
+PROCEDURE StdInChan () : ChanId;
+PROCEDURE StdOutChan () : ChanId;
+PROCEDURE StdErrChan () : ChanId;
+PROCEDURE NullChan () : ChanId;
+
+PROCEDURE InChan () : ChanId;
+PROCEDURE OutChan () : ChanId;
+PROCEDURE ErrChan () : ChanId;
+PROCEDURE SetInChan (cid : ChanId);
+PROCEDURE SetOutChan (cid : ChanId);
+PROCEDURE SetErrChan (cid : ChanId);
+
+END StdChans.

+ 39 - 0
stdlib/stdchans.mod

@@ -0,0 +1,39 @@
+IMPLEMENTATION MODULE StdChans;
+(* The standard channels are IOChan's; the "current" channels are
+   settable, defaulting to the standards.  NullChan is a closed
+   channel (all operations are safe no-ops). *)
+
+IMPORT IOChan;
+
+VAR
+  inChan, outChan, errChan : IOChan.ChanId;
+
+PROCEDURE StdInChan () : IOChan.ChanId;
+BEGIN RETURN IOChan.StdInChan() END StdInChan;
+PROCEDURE StdOutChan () : IOChan.ChanId;
+BEGIN RETURN IOChan.StdOutChan() END StdOutChan;
+PROCEDURE StdErrChan () : IOChan.ChanId;
+BEGIN RETURN IOChan.StdErrChan() END StdErrChan;
+
+PROCEDURE NullChan () : IOChan.ChanId;
+BEGIN RETURN IOChan.MakeChan(NIL) END NullChan;
+
+PROCEDURE InChan () : IOChan.ChanId;
+BEGIN RETURN inChan END InChan;
+PROCEDURE OutChan () : IOChan.ChanId;
+BEGIN RETURN outChan END OutChan;
+PROCEDURE ErrChan () : IOChan.ChanId;
+BEGIN RETURN errChan END ErrChan;
+
+PROCEDURE SetInChan (cid : IOChan.ChanId);
+BEGIN inChan := cid END SetInChan;
+PROCEDURE SetOutChan (cid : IOChan.ChanId);
+BEGIN outChan := cid END SetOutChan;
+PROCEDURE SetErrChan (cid : IOChan.ChanId);
+BEGIN errChan := cid END SetErrChan;
+
+BEGIN
+  inChan := IOChan.StdInChan();
+  outChan := IOChan.StdOutChan();
+  errChan := IOChan.StdErrChan()
+END StdChans.

+ 6 - 0
stdlib/timestring.def

@@ -0,0 +1,6 @@
+DEFINITION MODULE TimeString;
+(* gm2-compatible: place the current time in ASCII form into a. *)
+
+PROCEDURE GetTimeString (VAR a : ARRAY OF CHAR);
+
+END TimeString.

+ 12 - 0
stdlib/timestring.mod

@@ -0,0 +1,12 @@
+IMPLEMENTATION MODULE TimeString;
+(* Formats the current local time via the shim (strftime "%c"). *)
+
+PROCEDURE m2timestring (VAR a : ARRAY OF CHAR);
+  EXTERNAL;
+
+PROCEDURE GetTimeString (VAR a : ARRAY OF CHAR);
+BEGIN
+  m2timestring(a)
+END GetTimeString;
+
+END TimeString.

+ 27 - 0
stdlib/wrapc.def

@@ -0,0 +1,27 @@
+DEFINITION MODULE wrapc;
+(* gm2-compatible: assorted C-library wrappers. *)
+
+FROM SYSTEM IMPORT ADDRESS;
+
+PROCEDURE strtime () : ADDRESS;
+PROCEDURE filesize (f : INTEGER; VAR low, high : CARDINAL) : INTEGER;
+PROCEDURE fileinode (f : INTEGER; VAR low, high : CARDINAL) : INTEGER;
+PROCEDURE filemtime (f : INTEGER) : INTEGER;
+PROCEDURE getrand (n : INTEGER) : INTEGER;
+PROCEDURE getusername () : ADDRESS;
+PROCEDURE getnameuidgid (name : ADDRESS; VAR uid, gid : INTEGER);
+PROCEDURE signbit (r : REAL) : INTEGER;
+PROCEDURE signbitf (s : SHORTREAL) : INTEGER;
+PROCEDURE signbitl (l : LONGREAL) : INTEGER;
+PROCEDURE isfinite (x : REAL) : INTEGER;
+PROCEDURE isfinitef (x : SHORTREAL) : INTEGER;
+PROCEDURE isfinitel (x : LONGREAL) : INTEGER;
+PROCEDURE isnan (x : REAL) : INTEGER;
+PROCEDURE isnanf (x : SHORTREAL) : INTEGER;
+PROCEDURE isnanl (x : LONGREAL) : INTEGER;
+PROCEDURE SeekSet () : INTEGER;
+PROCEDURE SeekEnd () : INTEGER;
+PROCEDURE ReadOnly () : CARDINAL;
+PROCEDURE WriteOnly () : CARDINAL;
+
+END wrapc.

+ 79 - 0
stdlib/wrapc.mod

@@ -0,0 +1,79 @@
+IMPLEMENTATION MODULE wrapc;
+(* Bound to m2c* helpers in the shim.  SHORTREAL/LONGREAL widen to REAL
+   in V3, so the f/l float variants share the double implementations. *)
+
+FROM SYSTEM IMPORT ADDRESS;
+
+PROCEDURE m2cstrtime () : ADDRESS;
+  EXTERNAL;
+PROCEDURE m2cfilesize (f : INTEGER; VAR low, high : CARDINAL) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2cfileinode (f : INTEGER; VAR low, high : CARDINAL) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2cfilemtime (f : INTEGER) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2cgetrand (n : INTEGER) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2cgetusername () : ADDRESS;
+  EXTERNAL;
+PROCEDURE m2cgetnameuidgid (name : ADDRESS; VAR uid, gid : INTEGER);
+  EXTERNAL;
+PROCEDURE m2csignbit (r : REAL) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2cisfinite (x : REAL) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2cisnan (x : REAL) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2cseekset () : INTEGER;
+  EXTERNAL;
+PROCEDURE m2cseekend () : INTEGER;
+  EXTERNAL;
+PROCEDURE m2creadonly () : CARDINAL;
+  EXTERNAL;
+PROCEDURE m2cwriteonly () : CARDINAL;
+  EXTERNAL;
+
+PROCEDURE strtime () : ADDRESS;
+BEGIN RETURN m2cstrtime() END strtime;
+PROCEDURE filesize (f : INTEGER; VAR low, high : CARDINAL) : INTEGER;
+BEGIN RETURN m2cfilesize(f, low, high) END filesize;
+PROCEDURE fileinode (f : INTEGER; VAR low, high : CARDINAL) : INTEGER;
+BEGIN RETURN m2cfileinode(f, low, high) END fileinode;
+PROCEDURE filemtime (f : INTEGER) : INTEGER;
+BEGIN RETURN m2cfilemtime(f) END filemtime;
+PROCEDURE getrand (n : INTEGER) : INTEGER;
+BEGIN RETURN m2cgetrand(n) END getrand;
+PROCEDURE getusername () : ADDRESS;
+BEGIN RETURN m2cgetusername() END getusername;
+PROCEDURE getnameuidgid (name : ADDRESS; VAR uid, gid : INTEGER);
+BEGIN m2cgetnameuidgid(name, uid, gid) END getnameuidgid;
+
+PROCEDURE signbit (r : REAL) : INTEGER;
+BEGIN RETURN m2csignbit(r) END signbit;
+PROCEDURE signbitf (s : SHORTREAL) : INTEGER;
+BEGIN RETURN m2csignbit(s) END signbitf;
+PROCEDURE signbitl (l : LONGREAL) : INTEGER;
+BEGIN RETURN m2csignbit(l) END signbitl;
+PROCEDURE isfinite (x : REAL) : INTEGER;
+BEGIN RETURN m2cisfinite(x) END isfinite;
+PROCEDURE isfinitef (x : SHORTREAL) : INTEGER;
+BEGIN RETURN m2cisfinite(x) END isfinitef;
+PROCEDURE isfinitel (x : LONGREAL) : INTEGER;
+BEGIN RETURN m2cisfinite(x) END isfinitel;
+PROCEDURE isnan (x : REAL) : INTEGER;
+BEGIN RETURN m2cisnan(x) END isnan;
+PROCEDURE isnanf (x : SHORTREAL) : INTEGER;
+BEGIN RETURN m2cisnan(x) END isnanf;
+PROCEDURE isnanl (x : LONGREAL) : INTEGER;
+BEGIN RETURN m2cisnan(x) END isnanl;
+
+PROCEDURE SeekSet () : INTEGER;
+BEGIN RETURN m2cseekset() END SeekSet;
+PROCEDURE SeekEnd () : INTEGER;
+BEGIN RETURN m2cseekend() END SeekEnd;
+PROCEDURE ReadOnly () : CARDINAL;
+BEGIN RETURN m2creadonly() END ReadOnly;
+PROCEDURE WriteOnly () : CARDINAL;
+BEGIN RETURN m2cwriteonly() END WriteOnly;
+
+END wrapc.

+ 23 - 0
stdlib/wrapclock.def

@@ -0,0 +1,23 @@
+DEFINITION MODULE wrapclock;
+(* gm2-compatible: clock primitives (a thin layer over the C library).
+   timespec is opaque (a heap STRUCT). *)
+
+FROM SYSTEM IMPORT ADDRESS;
+
+TYPE
+  timespec = ADDRESS;
+
+PROCEDURE timezone () : LONGINT;
+PROCEDURE istimezone () : INTEGER;
+PROCEDURE daylight () : INTEGER;
+PROCEDURE isdst () : INTEGER;
+PROCEDURE tzname (daylight : INTEGER) : ADDRESS;
+
+PROCEDURE InitTimespec () : timespec;
+PROCEDURE KillTimespec (ts : timespec) : timespec;
+PROCEDURE GetTimespec (ts : timespec; VAR sec, nano : LONGCARD) : INTEGER;
+PROCEDURE SetTimespec (ts : timespec; sec, nano : LONGCARD) : INTEGER;
+PROCEDURE GetTimeRealtime (ts : timespec) : INTEGER;
+PROCEDURE SetTimeRealtime (ts : timespec) : INTEGER;
+
+END wrapclock.

+ 54 - 0
stdlib/wrapclock.mod

@@ -0,0 +1,54 @@
+IMPLEMENTATION MODULE wrapclock;
+(* Bound to m2wc* helpers in the shim (C struct timespec on the heap).
+   Helper names avoid underscores (classic Modula-2 identifiers). *)
+
+FROM SYSTEM IMPORT ADDRESS;
+
+PROCEDURE m2wctimezone () : LONGINT;
+  EXTERNAL;
+PROCEDURE m2wcistimezone () : INTEGER;
+  EXTERNAL;
+PROCEDURE m2wcdaylight () : INTEGER;
+  EXTERNAL;
+PROCEDURE m2wcisdst () : INTEGER;
+  EXTERNAL;
+PROCEDURE m2wctzname (d : INTEGER) : ADDRESS;
+  EXTERNAL;
+PROCEDURE m2wctsnew () : ADDRESS;
+  EXTERNAL;
+PROCEDURE m2wctskill (ts : ADDRESS) : ADDRESS;
+  EXTERNAL;
+PROCEDURE m2wctsget (ts : ADDRESS; VAR sec, nano : LONGCARD) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2wctsset (ts : ADDRESS; sec, nano : LONGCARD) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2wctsrealtime (ts : ADDRESS) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2wctssetrealtime (ts : ADDRESS) : INTEGER;
+  EXTERNAL;
+
+PROCEDURE timezone () : LONGINT;
+BEGIN RETURN m2wctimezone() END timezone;
+PROCEDURE istimezone () : INTEGER;
+BEGIN RETURN m2wcistimezone() END istimezone;
+PROCEDURE daylight () : INTEGER;
+BEGIN RETURN m2wcdaylight() END daylight;
+PROCEDURE isdst () : INTEGER;
+BEGIN RETURN m2wcisdst() END isdst;
+PROCEDURE tzname (daylight : INTEGER) : ADDRESS;
+BEGIN RETURN m2wctzname(daylight) END tzname;
+
+PROCEDURE InitTimespec () : timespec;
+BEGIN RETURN m2wctsnew() END InitTimespec;
+PROCEDURE KillTimespec (ts : timespec) : timespec;
+BEGIN RETURN m2wctskill(ts) END KillTimespec;
+PROCEDURE GetTimespec (ts : timespec; VAR sec, nano : LONGCARD) : INTEGER;
+BEGIN RETURN m2wctsget(ts, sec, nano) END GetTimespec;
+PROCEDURE SetTimespec (ts : timespec; sec, nano : LONGCARD) : INTEGER;
+BEGIN RETURN m2wctsset(ts, sec, nano) END SetTimespec;
+PROCEDURE GetTimeRealtime (ts : timespec) : INTEGER;
+BEGIN RETURN m2wctsrealtime(ts) END GetTimeRealtime;
+PROCEDURE SetTimeRealtime (ts : timespec) : INTEGER;
+BEGIN RETURN m2wctssetrealtime(ts) END SetTimeRealtime;
+
+END wrapclock.

+ 33 - 0
stdlib/wraptime.def

@@ -0,0 +1,33 @@
+DEFINITION MODULE wraptime;
+(* gm2-compatible: time primitives (C library structs are opaque). *)
+
+FROM SYSTEM IMPORT ADDRESS;
+
+TYPE
+  timeval  = ADDRESS;
+  timezone = ADDRESS;
+  tm       = ADDRESS;
+
+PROCEDURE InitTimeval () : timeval;
+PROCEDURE KillTimeval (tv : timeval) : timeval;
+PROCEDURE InitTimezone () : timezone;
+PROCEDURE KillTimezone (tz : timezone) : timezone;
+PROCEDURE InitTM () : tm;
+PROCEDURE KillTM (t : tm) : tm;
+
+PROCEDURE gettimeofday (tv : timeval; tz : timezone) : INTEGER;
+PROCEDURE settimeofday (tv : timeval; tz : timezone) : INTEGER;
+PROCEDURE GetFractions (tv : timeval) : CARDINAL;
+PROCEDURE LocalTime (tv : timeval; m : tm) : tm;
+
+PROCEDURE GetYear (m : tm) : CARDINAL;
+PROCEDURE GetMonth (m : tm) : CARDINAL;
+PROCEDURE GetDay (m : tm) : CARDINAL;
+PROCEDURE GetHour (m : tm) : CARDINAL;
+PROCEDURE GetMinute (m : tm) : CARDINAL;
+PROCEDURE GetSecond (m : tm) : CARDINAL;
+
+PROCEDURE SetTimeval (tv : timeval; sec, usec : LONGCARD);
+PROCEDURE SetTimezone (tz : timezone; minuteswest, dsttime : INTEGER);
+
+END wraptime.

+ 87 - 0
stdlib/wraptime.mod

@@ -0,0 +1,87 @@
+IMPLEMENTATION MODULE wraptime;
+(* Bound to m2wt* helpers (struct timeval / struct tm on the heap).
+   Field accessors live in C to avoid struct-layout assumptions here. *)
+
+FROM SYSTEM IMPORT ADDRESS;
+
+PROCEDURE m2wttvnew () : ADDRESS;
+  EXTERNAL;
+PROCEDURE m2wttvkill (tv : ADDRESS) : ADDRESS;
+  EXTERNAL;
+PROCEDURE m2wttznew () : ADDRESS;
+  EXTERNAL;
+PROCEDURE m2wttzkill (tz : ADDRESS) : ADDRESS;
+  EXTERNAL;
+PROCEDURE m2wttmnew () : ADDRESS;
+  EXTERNAL;
+PROCEDURE m2wttmkill (t : ADDRESS) : ADDRESS;
+  EXTERNAL;
+
+PROCEDURE m2wtgettimeofday (tv, tz : ADDRESS) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2wtsettimeofday (tv, tz : ADDRESS) : INTEGER;
+  EXTERNAL;
+PROCEDURE m2wtfractions (tv : ADDRESS) : CARDINAL;
+  EXTERNAL;
+PROCEDURE m2wtlocaltime (tv, t : ADDRESS) : ADDRESS;
+  EXTERNAL;
+
+PROCEDURE m2wtyear (t : ADDRESS) : CARDINAL;
+  EXTERNAL;
+PROCEDURE m2wtmonth (t : ADDRESS) : CARDINAL;
+  EXTERNAL;
+PROCEDURE m2wtday (t : ADDRESS) : CARDINAL;
+  EXTERNAL;
+PROCEDURE m2wthour (t : ADDRESS) : CARDINAL;
+  EXTERNAL;
+PROCEDURE m2wtminute (t : ADDRESS) : CARDINAL;
+  EXTERNAL;
+PROCEDURE m2wtsecond (t : ADDRESS) : CARDINAL;
+  EXTERNAL;
+
+PROCEDURE m2wttvset (tv : ADDRESS; sec, usec : LONGCARD);
+  EXTERNAL;
+PROCEDURE m2wttzset (tz : ADDRESS; minuteswest, dsttime : INTEGER);
+  EXTERNAL;
+
+PROCEDURE InitTimeval () : timeval;
+BEGIN RETURN m2wttvnew() END InitTimeval;
+PROCEDURE KillTimeval (tv : timeval) : timeval;
+BEGIN RETURN m2wttvkill(tv) END KillTimeval;
+PROCEDURE InitTimezone () : timezone;
+BEGIN RETURN m2wttznew() END InitTimezone;
+PROCEDURE KillTimezone (tz : timezone) : timezone;
+BEGIN RETURN m2wttzkill(tz) END KillTimezone;
+PROCEDURE InitTM () : tm;
+BEGIN RETURN m2wttmnew() END InitTM;
+PROCEDURE KillTM (t : tm) : tm;
+BEGIN RETURN m2wttmkill(t) END KillTM;
+
+PROCEDURE gettimeofday (tv : timeval; tz : timezone) : INTEGER;
+BEGIN RETURN m2wtgettimeofday(tv, tz) END gettimeofday;
+PROCEDURE settimeofday (tv : timeval; tz : timezone) : INTEGER;
+BEGIN RETURN m2wtsettimeofday(tv, tz) END settimeofday;
+PROCEDURE GetFractions (tv : timeval) : CARDINAL;
+BEGIN RETURN m2wtfractions(tv) END GetFractions;
+PROCEDURE LocalTime (tv : timeval; m : tm) : tm;
+BEGIN RETURN m2wtlocaltime(tv, m) END LocalTime;
+
+PROCEDURE GetYear (m : tm) : CARDINAL;
+BEGIN RETURN m2wtyear(m) END GetYear;
+PROCEDURE GetMonth (m : tm) : CARDINAL;
+BEGIN RETURN m2wtmonth(m) END GetMonth;
+PROCEDURE GetDay (m : tm) : CARDINAL;
+BEGIN RETURN m2wtday(m) END GetDay;
+PROCEDURE GetHour (m : tm) : CARDINAL;
+BEGIN RETURN m2wthour(m) END GetHour;
+PROCEDURE GetMinute (m : tm) : CARDINAL;
+BEGIN RETURN m2wtminute(m) END GetMinute;
+PROCEDURE GetSecond (m : tm) : CARDINAL;
+BEGIN RETURN m2wtsecond(m) END GetSecond;
+
+PROCEDURE SetTimeval (tv : timeval; sec, usec : LONGCARD);
+BEGIN m2wttvset(tv, sec, usec) END SetTimeval;
+PROCEDURE SetTimezone (tz : timezone; minuteswest, dsttime : INTEGER);
+BEGIN m2wttzset(tz, minuteswest, dsttime) END SetTimezone;
+
+END wraptime.