Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libast/tm/tmxscan.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1985-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
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
20
* *
21
***********************************************************************/
22
#pragma prototyped
23
/*
24
* Glenn Fowler
25
* AT&T Research
26
*
27
* Time_t conversion support
28
*
29
* scan date expression in s using format
30
* if non-null, e points to the first invalid sequence in s
31
* if non-null, f points to the first unused format char
32
* t provides default values
33
*/
34
35
#include <tmx.h>
36
#include <ctype.h>
37
38
typedef struct
39
{
40
int32_t nsec;
41
int year;
42
int mon;
43
int week;
44
int weektype;
45
int yday;
46
int mday;
47
int wday;
48
int hour;
49
int min;
50
int sec;
51
int meridian;
52
int zone;
53
} Set_t;
54
55
#define CLEAR(s) (s.year=s.mon=s.week=s.weektype=s.yday=s.mday=s.wday=s.hour=s.min=s.sec=s.meridian=(-1),s.nsec=1000000000L,s.zone=TM_LOCALZONE)
56
57
#define INDEX(m,x) (((n)>=((x)-(m)))?((n)-=((x)-(m))):(n))
58
59
#define NUMBER(d,m,x) do \
60
{ \
61
n = 0; \
62
u = (char*)s; \
63
while (s < (const char*)(u + d) && *s >= '0' && *s <= '9') \
64
n = n * 10 + *s++ - '0'; \
65
if (u == (char*)s || n < m || n > x) \
66
goto next; \
67
} while (0)
68
69
/*
70
* generate a Time_t from tm + set
71
*/
72
73
static Time_t
74
gen(register Tm_t* tm, register Set_t* set)
75
{
76
register int n;
77
int z;
78
Time_t t;
79
80
if (set->year >= 0)
81
tm->tm_year = set->year;
82
if (set->mon >= 0)
83
{
84
if (set->year < 0 && set->mon < tm->tm_mon)
85
tm->tm_year++;
86
tm->tm_mon = set->mon;
87
if (set->yday < 0 && set->mday < 0)
88
tm->tm_mday = set->mday = 1;
89
}
90
if (set->week >= 0)
91
{
92
if (set->mon < 0)
93
{
94
tmweek(tm, set->weektype, set->week, set->wday);
95
set->wday = -1;
96
}
97
}
98
else if (set->yday >= 0)
99
{
100
if (set->mon < 0)
101
{
102
tm->tm_mon = 0;
103
tm->tm_mday = set->yday + 1;
104
}
105
}
106
else if (set->mday >= 0)
107
tm->tm_mday = set->mday;
108
if (set->hour >= 0)
109
{
110
if (set->hour < tm->tm_hour && set->yday < 0 && set->mday < 0 && set->wday < 0)
111
tm->tm_mday++;
112
tm->tm_hour = set->hour;
113
tm->tm_min = (set->min >= 0) ? set->min : 0;
114
tm->tm_sec = (set->sec >= 0) ? set->sec : 0;
115
}
116
else if (set->min >= 0)
117
{
118
tm->tm_min = set->min;
119
tm->tm_sec = (set->sec >= 0) ? set->sec : 0;
120
}
121
else if (set->sec >= 0)
122
tm->tm_sec = set->sec;
123
if (set->nsec < 1000000000L)
124
tm->tm_nsec = set->nsec;
125
if (set->meridian > 0)
126
{
127
if (tm->tm_hour < 12)
128
tm->tm_hour += 12;
129
}
130
else if (set->meridian == 0)
131
{
132
if (tm->tm_hour >= 12)
133
tm->tm_hour -= 12;
134
}
135
t = tmxtime(tm, set->zone);
136
if (set->yday >= 0)
137
{
138
z = 1;
139
tm = tmxtm(tm, t, tm->tm_zone);
140
tm->tm_mday += set->yday - tm->tm_yday;
141
}
142
else if (set->wday >= 0)
143
{
144
z = 1;
145
tm = tmxtm(tm, t, tm->tm_zone);
146
if ((n = set->wday - tm->tm_wday) < 0)
147
n += 7;
148
tm->tm_mday += n;
149
}
150
else
151
z = 0;
152
if (set->nsec < 1000000000L)
153
{
154
if (!z)
155
{
156
z = 1;
157
tm = tmxtm(tm, t, tm->tm_zone);
158
}
159
tm->tm_nsec = set->nsec;
160
}
161
return z ? tmxtime(tm, set->zone) : t;
162
}
163
164
/*
165
* the format scan workhorse
166
*/
167
168
static Time_t
169
scan(register const char* s, char** e, const char* format, char** f, Time_t t, long flags)
170
{
171
register int d;
172
register int n;
173
register char* p;
174
register Tm_t* tm;
175
const char* b;
176
char* u;
177
char* stack[4];
178
int m;
179
int hi;
180
int lo;
181
int pedantic;
182
Time_t x;
183
Set_t set;
184
Tm_zone_t* zp;
185
Tm_t ts;
186
187
char** sp = &stack[0];
188
189
while (isspace(*s))
190
s++;
191
b = s;
192
again:
193
CLEAR(set);
194
tm = tmxtm(&ts, t, NiL);
195
pedantic = (flags & TM_PEDANTIC) != 0;
196
for (;;)
197
{
198
if (!(d = *format++))
199
{
200
if (sp <= &stack[0])
201
{
202
format--;
203
break;
204
}
205
format = (const char*)*--sp;
206
}
207
else if (!*s)
208
{
209
format--;
210
break;
211
}
212
else if (d == '%' && (d = *format) && format++ && d != '%')
213
{
214
more:
215
switch (d)
216
{
217
case 'a':
218
lo = TM_DAY_ABBREV;
219
hi = pedantic ? TM_DAY : TM_TIME;
220
goto get_wday;
221
case 'A':
222
lo = pedantic ? TM_DAY : TM_DAY_ABBREV;
223
hi = TM_TIME;
224
get_wday:
225
if ((n = tmlex(s, &u, tm_info.format + lo, hi - lo, NiL, 0)) < 0)
226
goto next;
227
s = u;
228
INDEX(TM_DAY_ABBREV, TM_DAY);
229
set.wday = n;
230
continue;
231
case 'b':
232
case 'h':
233
lo = TM_MONTH_ABBREV;
234
hi = pedantic ? TM_MONTH : TM_DAY_ABBREV;
235
goto get_mon;
236
case 'B':
237
lo = pedantic ? TM_MONTH : TM_MONTH_ABBREV;
238
hi = TM_DAY_ABBREV;
239
get_mon:
240
if ((n = tmlex(s, &u, tm_info.format + lo, hi - lo, NiL, 0)) < 0)
241
goto next;
242
s = u;
243
INDEX(TM_MONTH_ABBREV, TM_MONTH);
244
set.mon = n;
245
continue;
246
case 'c':
247
p = "%a %b %e %T %Y";
248
break;
249
case 'C':
250
NUMBER(2, 19, 99);
251
set.year = (n - 19) * 100 + tm->tm_year % 100;
252
continue;
253
case 'd':
254
if (pedantic && !isdigit(*s))
255
goto next;
256
/*FALLTHROUGH*/
257
case 'e':
258
NUMBER(2, 1, 31);
259
set.mday = n;
260
continue;
261
case 'D':
262
p = "%m/%d/%y";
263
break;
264
case 'E':
265
case 'O':
266
if (*format)
267
{
268
d = *format++;
269
goto more;
270
}
271
continue;
272
case 'F':
273
p = "%Y-%m-%d";
274
break;
275
case 'H':
276
case 'k':
277
NUMBER(2, 0, 23);
278
set.hour = n;
279
continue;
280
case 'I':
281
case 'l':
282
NUMBER(2, 1, 12);
283
set.hour = n;
284
continue;
285
case 'j':
286
NUMBER(3, 1, 366);
287
set.yday = n - 1;
288
continue;
289
case 'm':
290
NUMBER(2, 1, 12);
291
set.mon = n - 1;
292
continue;
293
case 'M':
294
NUMBER(2, 0, 59);
295
set.min = n;
296
continue;
297
case 'n':
298
if (pedantic)
299
while (*s == '\n')
300
s++;
301
else
302
while (isspace(*s))
303
s++;
304
continue;
305
case 'N':
306
NUMBER(9, 0, 999999999L);
307
set.nsec = n;
308
continue;
309
case 'p':
310
if ((n = tmlex(s, &u, tm_info.format + TM_MERIDIAN, TM_UT - TM_MERIDIAN, NiL, 0)) < 0)
311
goto next;
312
set.meridian = n;
313
s = u;
314
continue;
315
case 'r':
316
p = "%I:%M:%S %p";
317
break;
318
case 'R':
319
p = "%H:%M:%S";
320
break;
321
case 's':
322
x = strtoul(s, &u, 0);
323
if (s == u)
324
goto next;
325
tm = tmxtm(tm, tmxsns(x, 0), tm->tm_zone);
326
s = u;
327
CLEAR(set);
328
continue;
329
case 'S':
330
NUMBER(2, 0, 61);
331
set.sec = n;
332
continue;
333
case 'u':
334
NUMBER(2, 1, 7);
335
set.wday = n % 7;
336
continue;
337
case 'U':
338
NUMBER(2, 0, 52);
339
set.week = n;
340
set.weektype = 0;
341
continue;
342
case 'V':
343
NUMBER(2, 1, 53);
344
set.week = n;
345
set.weektype = 2;
346
continue;
347
case 'w':
348
NUMBER(2, 0, 6);
349
set.wday = n;
350
continue;
351
case 'W':
352
NUMBER(2, 0, 52);
353
set.week = n;
354
set.weektype = 1;
355
continue;
356
case 'x':
357
p = tm_info.format[TM_DATE];
358
break;
359
case 'X':
360
p = tm_info.format[TM_TIME];
361
break;
362
case 'y':
363
NUMBER(2, 0, 99);
364
if (n < TM_WINDOW)
365
n += 100;
366
set.year = n;
367
continue;
368
case 'Y':
369
NUMBER(4, 1969, 2100);
370
set.year = n - 1900;
371
continue;
372
case 'Z':
373
case 'q':
374
if (zp = tmtype(s, &u))
375
{
376
s = u;
377
u = zp->type;
378
}
379
else
380
u = 0;
381
if (d == 'q')
382
continue;
383
case 'z':
384
if ((zp = tmzone(s, &u, u, &m)))
385
{
386
s = u;
387
set.zone = zp->west + m;
388
tm_info.date = zp;
389
}
390
continue;
391
case '|':
392
s = b;
393
goto again;
394
case '&':
395
x = gen(tm, &set);
396
x = tmxdate(s, e, t);
397
if (s == (const char*)*e)
398
goto next;
399
t = x;
400
s = (const char*)*e;
401
if (!*format || *format == '%' && *(format + 1) == '|')
402
goto done;
403
goto again;
404
default:
405
goto next;
406
}
407
if (sp >= &stack[elementsof(stack)])
408
goto next;
409
*sp++ = (char*)format;
410
format = (const char*)p;
411
}
412
else if (isspace(d))
413
while (isspace(*s))
414
s++;
415
else if (*s != d)
416
break;
417
else
418
s++;
419
}
420
next:
421
if (sp > &stack[0])
422
format = (const char*)stack[0];
423
if (*format)
424
{
425
p = (char*)format;
426
if (!*s && *p == '%' && *(p + 1) == '|')
427
format += strlen(format);
428
else
429
while (*p)
430
if (*p++ == '%' && *p && *p++ == '|' && *p)
431
{
432
format = (const char*)p;
433
s = b;
434
goto again;
435
}
436
}
437
t = gen(tm, &set);
438
done:
439
if (e)
440
{
441
while (isspace(*s))
442
s++;
443
*e = (char*)s;
444
}
445
if (f)
446
{
447
while (isspace(*format))
448
format++;
449
*f = (char*)format;
450
}
451
return t;
452
}
453
454
/*
455
* format==0 DATEMSK
456
* *format==0 DATEMSK and tmxdate()
457
* *format!=0 format
458
*/
459
460
Time_t
461
tmxscan(const char* s, char** e, const char* format, char** f, Time_t t, long flags)
462
{
463
register char* v;
464
register char** p;
465
char* q;
466
char* r;
467
Time_t x;
468
469
static int initialized;
470
static char** datemask;
471
472
tmlocale();
473
if (!format || !*format)
474
{
475
if (!initialized)
476
{
477
register Sfio_t* sp;
478
register int n;
479
off_t m;
480
481
initialized = 1;
482
if ((v = getenv("DATEMSK")) && *v && (sp = sfopen(NiL, v, "r")))
483
{
484
for (n = 1; sfgetr(sp, '\n', 0); n++);
485
m = sfseek(sp, 0L, SEEK_CUR);
486
if (p = newof(0, char*, n, m))
487
{
488
sfseek(sp, 0L, SEEK_SET);
489
v = (char*)(p + n);
490
if (sfread(sp, v, m) != m)
491
{
492
free(p);
493
p = 0;
494
}
495
else
496
{
497
datemask = p;
498
v[m] = 0;
499
while (*v)
500
{
501
*p++ = v;
502
if (!(v = strchr(v, '\n')))
503
break;
504
*v++ = 0;
505
}
506
*p = 0;
507
}
508
}
509
}
510
}
511
if (p = datemask)
512
while (v = *p++)
513
{
514
x = scan(s, &q, v, &r, t, flags);
515
if (!*q && !*r)
516
{
517
if (e)
518
*e = q;
519
if (f)
520
*f = r;
521
return x;
522
}
523
}
524
if (f)
525
*f = (char*)format;
526
if (format)
527
return tmxdate(s, e, t);
528
if (e)
529
*e = (char*)s;
530
return 0;
531
}
532
return scan(s, e, format, f, t, flags);
533
}
534
535