Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/dsslib/time_t/time_t.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 2002-2011 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* *
19
***********************************************************************/
20
#pragma prototyped
21
/*
22
* dss time type library
23
*
24
* Glenn Fowler
25
* AT&T Research
26
*/
27
28
#include <dsslib.h>
29
#include <tmx.h>
30
31
#define NS 1000000000
32
33
#if TMX_FLOAT
34
#define SS 4294967296.0
35
#endif
36
37
typedef struct Precise_s
38
{
39
const char* format;
40
size_t size;
41
int shift;
42
} Precise_t;
43
44
static ssize_t
45
time_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
46
{
47
char* s;
48
time_t t;
49
50
if (!size)
51
return 40;
52
t = value->number;
53
s = tmfmt(buf, size, CXDETAILS(details, format, type, "%K"), &t);
54
if (s == (buf + size - 1))
55
return 2 * size;
56
return s - buf;
57
}
58
59
static ssize_t
60
time_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
61
{
62
char* e;
63
char* f;
64
65
buf = (const char*)cxcvt(cx, buf, size);
66
if (CXDETAILS(details, format, type, 0))
67
{
68
ret->value.number = tmscan(buf, &e, details, &f, NiL, 0);
69
if (!*f && e > (char*)buf)
70
return e - (char*)buf;
71
}
72
ret->value.number = tmdate(buf, &e, NiL);
73
return e - (char*)buf;
74
}
75
76
static void*
77
ns_init(void* data, Cxdisc_t* disc)
78
{
79
Precise_t* precise;
80
81
if (!(precise = newof(0, Precise_t, 1, 0)))
82
{
83
if (disc->errorf)
84
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
85
return 0;
86
}
87
precise->format = "%K.%9N";
88
precise->size = 40;
89
precise->shift = 0;
90
return precise;
91
}
92
93
static void*
94
stamp_init(void* data, Cxdisc_t* disc)
95
{
96
Precise_t* precise;
97
98
if (!(precise = newof(0, Precise_t, 1, 0)))
99
{
100
if (disc->errorf)
101
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
102
return 0;
103
}
104
precise->format = "%K.%N";
105
precise->size = 40;
106
precise->shift = 32;
107
return precise;
108
}
109
110
static Time_t
111
n2s(Time_t t, int s)
112
{
113
Time_t m;
114
115
#if TMX_FLOAT
116
m = t;
117
t /= NS;
118
t = (Tmxsec_t)t;
119
m -= t * NS;
120
t *= SS;
121
m *= SS;
122
#else
123
m = t % NS;
124
t /= NS;
125
t <<= s;
126
m <<= s;
127
#endif
128
m /= NS;
129
return t + m;
130
}
131
132
static Time_t
133
s2n(Time_t t, int s)
134
{
135
Time_t m;
136
137
#if TMX_FLOAT
138
m = t / SS;
139
m = (Tmxnsec_t)m;
140
m *= NS;
141
m = t - m;
142
m /= SS;
143
t /= SS;
144
t *= NS;
145
#else
146
m = 1;
147
m <<= s;
148
m--;
149
m &= t;
150
t >>= s;
151
t *= NS;
152
m *= NS;
153
m >>= s;
154
#endif
155
return t + m;
156
}
157
158
static ssize_t
159
precise_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
160
{
161
char* s;
162
Time_t t;
163
Precise_t* precise = (Precise_t*)type->data;
164
165
if (!size)
166
return precise->size;
167
t = value->number;
168
if (precise->shift)
169
t = s2n(t, precise->shift);
170
s = tmxfmt(buf, size, CXDETAILS(details, format, type, precise->format), t);
171
if (s == (buf + size - 1))
172
return 2 * size;
173
return s - buf;
174
}
175
176
static ssize_t
177
precise_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
178
{
179
char* e;
180
char* f;
181
Precise_t* precise = (Precise_t*)type->data;
182
Time_t now = TMX_NOW;
183
Time_t t;
184
185
buf = (const char*)cxcvt(cx, buf, size);
186
if (CXDETAILS(details, format, type, 0))
187
{
188
t = tmxscan(buf, &e, details, &f, now, 0);
189
if (*f || (e - (char*)buf) < size)
190
t = tmxdate(buf, &e, now);
191
}
192
else
193
t = tmxdate(buf, &e, now);
194
if (precise->shift)
195
t = n2s(t, precise->shift);
196
ret->value.number = t;
197
return e - (char*)buf;
198
}
199
200
static ssize_t
201
elapsed_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
202
{
203
char* s;
204
ssize_t n;
205
206
s = fmtelapsed((unsigned long)value->number, 1000);
207
n = strlen(s);
208
if ((n + 1) > size)
209
return n + 1;
210
memcpy(buf, s, n + 1);
211
return n;
212
}
213
214
static ssize_t
215
elapsed_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
216
{
217
char* e;
218
219
ret->value.number = strelapsed(buf, &e, 1000);
220
if (e == (char*)buf)
221
return -1;
222
return e - (char*)buf;
223
}
224
225
static ssize_t
226
tm_hour_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
227
{
228
char* s;
229
int v;
230
ssize_t n;
231
232
v = value->number;
233
CXDETAILS(details, format, type, "%d");
234
if (strchr(details, 's'))
235
{
236
s = tm_info.format[TM_MERIDIAN + (v >= 12)];
237
if (v > 12)
238
v -= 12;
239
n = strlen(s) + (v >= 10) + 2;
240
if ((n + 1) > size)
241
return n + 1;
242
n = sfsprintf(buf, size, "%d%s", v, s);
243
}
244
else
245
{
246
n = sfsprintf(buf, size, details, v);
247
if ((n + 1) > size)
248
n++;
249
}
250
return n;
251
}
252
253
static ssize_t
254
tm_hour_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
255
{
256
char* e;
257
258
ret->value.number = strntol(buf, size, &e, 10);
259
if (e == (char*)buf)
260
return -1;
261
if (tmlex(e, &e, tm_info.format + TM_MERIDIAN, TM_UT - TM_MERIDIAN, NiL, 0) == 1)
262
ret->value.number += 12;
263
return e - (char*)buf;
264
}
265
266
static ssize_t
267
tm_mon_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
268
{
269
char* s;
270
int v;
271
ssize_t n;
272
273
v = value->number;
274
if (v <= 0)
275
v = 0;
276
else
277
v %= 12;
278
CXDETAILS(details, format, type, "%d");
279
if (strchr(details, 's'))
280
{
281
s = tm_info.format[TM_MONTH + v];
282
n = strlen(s);
283
if ((n + 1) > size)
284
return n + 1;
285
strcpy(buf, s);
286
}
287
else
288
{
289
n = sfsprintf(buf, size, details, v + 1);
290
if ((n + 1) > size)
291
n++;
292
}
293
return n;
294
}
295
296
static ssize_t
297
tm_mon_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
298
{
299
char* e;
300
int v;
301
302
v = (int)strntol(buf, size, &e, 10);
303
if (e != (char*)buf)
304
{
305
if (v < 1 || v > 12)
306
return -1;
307
v--;
308
}
309
else if ((v = tmlex(buf, &e, tm_info.format + TM_MONTH_ABBREV, TM_DAY_ABBREV - TM_MONTH_ABBREV, NiL, 0)) < 0)
310
return -1;
311
else if (v >= 12)
312
v -= 12;
313
ret->value.number = v;
314
return e - (char*)buf;
315
}
316
317
static ssize_t
318
tm_wday_external(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxvalue_t* value, char* buf, size_t size, Cxdisc_t* disc)
319
{
320
char* s;
321
int v;
322
ssize_t n;
323
324
v = value->number;
325
if (v <= 0)
326
v = 0;
327
else
328
v %= 7;
329
CXDETAILS(details, format, type, "%d");
330
if (strchr(details, 's'))
331
{
332
s = tm_info.format[TM_DAY + v];
333
n = strlen(s);
334
if ((n + 1) > size)
335
return n + 1;
336
strcpy(buf, s);
337
}
338
else
339
{
340
n = sfsprintf(buf, size, details, v + 1);
341
if ((n + 1) > size)
342
n++;
343
}
344
return n;
345
}
346
347
static ssize_t
348
tm_wday_internal(Cx_t* cx, Cxtype_t* type, const char* details, Cxformat_t* format, Cxoperand_t* ret, const char* buf, size_t size, Vmalloc_t* vm, Cxdisc_t* disc)
349
{
350
char* e;
351
int v;
352
353
v = (int)strntol(buf, size, &e, 10);
354
if (e != (char*)buf)
355
{
356
if (v < 1 || v > 7)
357
return -1;
358
v--;
359
}
360
else if ((v = tmlex(buf, &e, tm_info.format + TM_DAY_ABBREV, TM_TIME - TM_DAY_ABBREV, NiL, 0)) < 0)
361
return -1;
362
else if (v >= 7)
363
v -= 7;
364
ret->value.number = v;
365
return e - (char*)buf;
366
}
367
368
#define TIME_T_sec 1
369
#define TIME_T_min 2
370
#define TIME_T_hour 3
371
#define TIME_T_mday 4
372
#define TIME_T_mon 5
373
#define TIME_T_year 6
374
#define TIME_T_wday 7
375
#define TIME_T_yday 8
376
#define TIME_T_isdst 9
377
#define TIME_T_ns 10
378
379
static Cxvariable_t tm_struct[] =
380
{
381
CXV("sec", "number", TIME_T_sec, "Seconds after the minute [0-61].")
382
CXV("min", "number", TIME_T_min, "Minutes after the hour [0-59].")
383
CXV("hour", "tm_hour_t",TIME_T_hour, "Hour since midnight [0-23].")
384
CXV("mday", "number", TIME_T_mday, "Day of the month [1-31].")
385
CXV("mon", "tm_mon_t", TIME_T_mon, "Months since January [0-11].")
386
CXV("year", "number", TIME_T_year, "4-digit year [1969-2038].")
387
CXV("wday", "tm_wday_t",TIME_T_wday, "Days since Sunday [0-6].")
388
CXV("yday", "number", TIME_T_yday, "Days since January 1 [0-365].")
389
CXV("isdst", "number", TIME_T_isdst, "Daylight savings time in effect [0-1].")
390
CXV("ns", "number", TIME_T_ns, "Residual nanoseconds [0-999999999].")
391
{0}
392
};
393
394
typedef struct Tm_state_s
395
{
396
Time_t t;
397
Tm_t tm;
398
} Tm_state_t;
399
400
static void*
401
tm_init(void* data, Cxdisc_t* disc)
402
{
403
Tm_state_t* state;
404
405
if (!(state = newof(0, Tm_state_t, 1, 0)))
406
{
407
if (disc->errorf)
408
(*disc->errorf)(NiL, disc, ERROR_SYSTEM|2, "out of space");
409
return 0;
410
}
411
state->tm = *tmxmake(state->t);
412
return state;
413
}
414
415
static int
416
tm_get(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
417
{
418
Tm_state_t* state = (Tm_state_t*)pc->data.variable->member->data;
419
Time_t t;
420
int shift;
421
422
t = r->value.number;
423
if (r->type && r->type->data)
424
{
425
if (shift = ((Precise_t*)r->type->data)->shift)
426
t = s2n(t, shift);
427
}
428
else if (b && b->type && b->type->data)
429
{
430
if (shift = ((Precise_t*)b->type->data)->shift)
431
t = s2n(t, shift);
432
}
433
else
434
t *= NS;
435
if (state->t != t)
436
{
437
state->t = t;
438
state->tm = *tmxmake(t);
439
}
440
switch (pc->data.variable->index)
441
{
442
case TIME_T_sec:
443
r->value.number = state->tm.tm_sec;
444
break;
445
case TIME_T_min:
446
r->value.number = state->tm.tm_min;
447
break;
448
case TIME_T_hour:
449
r->value.number = state->tm.tm_hour;
450
break;
451
case TIME_T_mday:
452
r->value.number = state->tm.tm_mday;
453
break;
454
case TIME_T_mon:
455
r->value.number = state->tm.tm_mon;
456
break;
457
case TIME_T_year:
458
r->value.number = 1900 + state->tm.tm_year;
459
break;
460
case TIME_T_wday:
461
r->value.number = state->tm.tm_wday;
462
break;
463
case TIME_T_yday:
464
r->value.number = state->tm.tm_yday;
465
break;
466
case TIME_T_isdst:
467
r->value.number = state->tm.tm_isdst;
468
break;
469
case TIME_T_ns:
470
r->value.number = state->tm.tm_nsec;
471
break;
472
default:
473
return -1;
474
}
475
return 0;
476
}
477
478
static int
479
tm_set(Cx_t* cx, Cxinstruction_t* pc, Cxoperand_t* r, Cxoperand_t* a, Cxoperand_t* b, void* data, Cxdisc_t* disc)
480
{
481
Tm_state_t* state = (Tm_state_t*)pc->data.variable->member->data;
482
Time_t t;
483
int i;
484
int shift;
485
486
t = r->value.number;
487
if (r->type && r->type->data)
488
{
489
if (shift = ((Precise_t*)r->type->data)->shift)
490
t = s2n(t, shift);
491
}
492
else if (b && b->type && b->type->data)
493
{
494
if (shift = ((Precise_t*)b->type->data)->shift)
495
t = s2n(t, shift);
496
}
497
else
498
{
499
shift = -1;
500
t *= NS;
501
}
502
if (state->t != t)
503
{
504
state->t = t;
505
state->tm = *tmxmake(t);
506
}
507
switch (pc->data.variable->index)
508
{
509
case TIME_T_sec:
510
state->tm.tm_sec = a->value.number;
511
break;
512
case TIME_T_min:
513
state->tm.tm_min = a->value.number;
514
break;
515
case TIME_T_hour:
516
state->tm.tm_hour = a->value.number;
517
break;
518
case TIME_T_mday:
519
state->tm.tm_mday = a->value.number;
520
break;
521
case TIME_T_mon:
522
state->tm.tm_mon = a->value.number;
523
break;
524
case TIME_T_year:
525
if ((state->tm.tm_year = a->value.number) >= 1900)
526
state->tm.tm_year -= 1900;
527
break;
528
case TIME_T_wday:
529
i = a->value.number;
530
if ((i -= state->tm.tm_wday) < 0)
531
i += 7;
532
state->tm.tm_mday += i;
533
state->tm.tm_wday = a->value.number;
534
break;
535
case TIME_T_yday:
536
i = a->value.number;
537
if ((i -= state->tm.tm_yday) < 0)
538
i += 365 + tmisleapyear(state->tm.tm_year);
539
state->tm.tm_mday += i;
540
state->tm.tm_yday = a->value.number;
541
break;
542
case TIME_T_isdst:
543
state->tm.tm_isdst = a->value.number;
544
break;
545
case TIME_T_ns:
546
state->tm.tm_nsec = a->value.number;
547
return -1;
548
default:
549
return -1;
550
}
551
state->t = t = tmxtime(&state->tm, TM_LOCALZONE);
552
if (shift < 0)
553
t /= NS;
554
else if (shift)
555
t = n2s(t, shift);
556
r->value.number = t;
557
return 0;
558
}
559
560
static Cxmember_t tm_member =
561
{
562
tm_get,
563
tm_set,
564
(Dt_t*)&tm_struct[0]
565
};
566
567
static Cxtype_t types[] =
568
{
569
{ "tm_hour_t", "Hour since midnight with optional meridian (AM/PM).", CXH, (Cxtype_t*)"number", 0, tm_hour_external, tm_hour_internal, 0, 0, 0, 0, { "The format details string is a \bprintf\b(3) format string.", "%d", CX_UNSIGNED|CX_INTEGER, 1 } },
570
{ "tm_mon_t", "Month name represented as a number [0-11], starting at January.", CXH, (Cxtype_t*)"number", 0, tm_mon_external, tm_mon_internal, 0, 0, 0, 0, { "The format details string is a \bprintf\b(3) format string.", "%s", CX_UNSIGNED|CX_INTEGER, 1 } },
571
{ "tm_wday_t", "Weekday name represented as a number [0-6], starting at Sunday.", CXH, (Cxtype_t*)"number", 0, tm_wday_external, tm_wday_internal, 0, 0, 0, 0, { "The format details string is a \bprintf\b(3) format string.", "%s", CX_UNSIGNED|CX_INTEGER, 1 } },
572
{ "tm_t", "Time parts.", CXH, (Cxtype_t*)"number", tm_init, 0, 0, 0, 0, 0, 0, { 0, 0, CX_UNSIGNED|CX_INTEGER, 4 }, 0, &tm_member },
573
{ "elapsed_t", "Elapsed time in milliseconds.", CXH, (Cxtype_t*)"number", 0, elapsed_external, elapsed_internal, 0, 0, 0, 0, { 0, 0, CX_INTEGER, 4 } },
574
{ "ns_t", "64 bit nanoseconds since the epoch.", CXH, (Cxtype_t*)"tm_t", ns_init, precise_external, precise_internal, 0, 0, 0, 0, { "The format details string is a \bstrftime\b(3)/\bstrptime\b(3) format string.", "%K.%9N", CX_UNSIGNED|CX_INTEGER, 8 } },
575
{ "stamp_t", "64 bit 1/2**32 seconds since the epoch.", CXH, (Cxtype_t*)"tm_t", stamp_init, precise_external, precise_internal, 0, 0, 0, 0, { "The format details string is a \bstrftime\b(3)/\bstrptime\b(3) format string.", "%K.%N", CX_UNSIGNED|CX_INTEGER, 8 } },
576
{ "time_t", "32 bit seconds since the epoch.", CXH, (Cxtype_t*)"tm_t", 0, time_external, time_internal, 0, 0, 0, 0, { "The format details string is a \bstrftime\b(3)/\bstrptime\b(3) format string.", "%K", CX_UNSIGNED|CX_INTEGER, 4 } },
577
{ 0, 0 }
578
};
579
580
Dsslib_t dss_lib_time_t =
581
{
582
"time_t",
583
"time type support"
584
"[-?\n@(#)$Id: dss time type library (AT&T Research) 2011-09-10 $\n]"
585
USAGE_LICENSE,
586
CXH,
587
0,
588
0,
589
&types[0],
590
};
591
592