Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / lib / libast / tm / tmdate.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: tmdate.c /main/3 1995/11/01 18:53:46 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
29 *                          AT&T CORP.                          *
30 *                                                              *
31 *                Copyright (c) 1995 AT&T Corp.                 *
32 *                     All Rights Reserved                      *
33 *                                                              *
34 *           This software is licensed by AT&T Corp.            *
35 *       under the terms and conditions of the license in       *
36 *       http://www.research.att.com/orgs/ssr/book/reuse        *
37 *                                                              *
38 *               This software was created by the               *
39 *           Software Engineering Research Department           *
40 *                    AT&T Bell Laboratories                    *
41 *                                                              *
42 *               For further information contact                *
43 *                     gsf@research.att.com                     *
44 *                                                              *
45 ***************************************************************/
46
47 /* : : generated by proto : : */
48
49 #if !defined(__PROTO__)
50 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
51 #if defined(__cplusplus)
52 #define __MANGLE__      "C"
53 #else
54 #define __MANGLE__
55 #endif
56 #define __STDARG__
57 #define __PROTO__(x)    x
58 #define __OTORP__(x)
59 #define __PARAM__(n,o)  n
60 #if !defined(__STDC__) && !defined(__cplusplus)
61 #if !defined(c_plusplus)
62 #define const
63 #endif
64 #define signed
65 #define void            int
66 #define volatile
67 #define __V_            char
68 #else
69 #define __V_            void
70 #endif
71 #else
72 #define __PROTO__(x)    ()
73 #define __OTORP__(x)    x
74 #define __PARAM__(n,o)  o
75 #define __MANGLE__
76 #define __V_            char
77 #define const
78 #define signed
79 #define void            int
80 #define volatile
81 #endif
82 #if defined(__cplusplus) || defined(c_plusplus)
83 #define __VARARG__      ...
84 #else
85 #define __VARARG__
86 #endif
87 #if defined(__STDARG__)
88 #define __VA_START__(p,a)       va_start(p,a)
89 #else
90 #define __VA_START__(p,a)       va_start(p)
91 #endif
92 #endif
93 #include <ast.h>
94 #include <tm.h>
95 #include <ctype.h>
96
97 #define dig2(s,n)       ((n)=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0')
98 #define dig3(s,n)       ((n)=((*(s)++)-'0')*100,(n)+=((*(s)++)-'0')*10,(n)+=(*(s)++)-'0')
99
100 #define BREAK           (1<<0)
101 #define DAY             (1<<1)
102 #define EXACT           (1<<2)
103 #define HOLD            (1<<3)
104 #define HOUR            (1<<4)
105 #define LAST            (1<<5)
106 #define MDAY            (1<<6)
107 #define MONTH           (1<<7)
108 #define NEXT            (1<<8)
109 #define THIS            (1<<9)
110 #define YEAR            (1<<10)
111 #define YYMMDDHHMMSS    (1<<11)
112 #define ZONE            (1<<12)
113
114 /*
115  * parse date expression in s and return time_t value
116  *
117  * if non-null, e points to the first invalid sequence in s
118  * clock provides default values
119  */
120
121 time_t
122 tmdate __PARAM__((register const char* s, char** e, time_t* clock), (s, e, clock)) __OTORP__(register const char* s; char** e; time_t* clock;){
123         register Tm_t*  tm;
124         register int    n;
125         int             state;
126         time_t          now;
127         char*           t;
128         char*           last;
129         char*           type;
130         int             dst;
131         int             zone;
132         int             i;
133         int             j;
134         int             k;
135         int             l;
136         int             m;
137         Tm_zone_t*      zp;
138
139  reset:
140
141         /*
142          * use clock for defaults
143          */
144
145         tm = tmmake(clock);
146         tm_info.date = tm_info.zone;
147         dst = TM_DST;
148         state = 0;
149         type = 0;
150         zone = 0;
151
152         /*
153          * get <weekday year month day hour minutes seconds ?[ds]t [ap]m>
154          */
155
156         for (;;)
157         {
158                 state &= (state & HOLD) ? ~(HOLD) : ~(EXACT|LAST|NEXT|THIS);
159                 n = -1;
160                 while (isspace(*s) || *s == ',' || *s == '-') s++;
161                 if (!*(last = (char*)s)) break;
162                 if (*s == '#')
163                 {
164                         if (!isdigit(*++s)) break;
165                         now = strtol(s, &t, 0);
166                         clock = &now;
167                         s = t;
168                         goto reset;
169                 }
170                 if (isdigit(*s))
171                 {
172                         n = strtol(s, &t, 10);
173                         if (!(state & (LAST|NEXT|THIS)) && ((i = t - s) == 4 && *t == '.' || i > 4))
174                         {
175                                 /*
176                                  * various date(1) formats
177                                  *
178                                  *      [yy[mm]]ddhhmm[.ss]
179                                  *      yyddd
180                                  *      hhmm.ss
181                                  */
182
183                                 if (state & YYMMDDHHMMSS) break;
184                                 state |= YYMMDDHHMMSS;
185                                 if (i == 5 && !*t)
186                                 {
187                                         if (dig2(s, m) < 38) m += 100;
188                                         dig3(s, k);
189                                         l = 1;
190                                         j = 0;
191                                         i = 0;
192                                         n = 0;
193                                 }
194                                 else
195                                 {
196                                         if (i < 10) m = tm->tm_year;
197                                         else if (dig2(s, m) < 38) m += 100;
198                                         if ((t - s) < 8) l = tm->tm_mon;
199                                         else if (dig2(s, l) <= 0 || l > 12) break;
200                                         if ((t - s) < 6) k = tm->tm_mon;
201                                         else if (dig2(s, k) < 1 || k > 31) break;
202                                         if ((t - s) < 4) break;
203                                         if (dig2(s, j) > 24) break;
204                                         if (dig2(s, i) > 59) break;
205                                         if ((t - s) == 2) dig2(s, n);
206                                         else if (t - s) break;
207                                         else if (*t != '.') n = 0;
208                                         else n = strtol(t + 1, &t, 10);
209                                         if (n > (59 + TM_MAXLEAP)) break;
210                                 }
211                                 tm->tm_year = m;
212                                 tm->tm_mon = l - 1;
213                                 tm->tm_mday = k;
214                                 tm->tm_hour = j;
215                                 tm->tm_min = i;
216                                 tm->tm_sec = n;
217                                 s = t;
218                                 continue;
219                         }
220                         s = t;
221                         if (*s == ':')
222                         {
223                                 if ((state & HOUR) || n > 24 || *s++ != ':' || !isdigit(*s)) break;
224                                 i = n;
225                                 n = strtol(s, &t, 10);
226                                 s = t;
227                                 if (n > 59) break;
228                                 j = n;
229                                 if (*s == ':')
230                                 {
231                                         if (!isdigit(*++s)) break;
232                                         n = strtol(s, &t, 10);
233                                         s = t;
234                                         if (n > (59 + TM_MAXLEAP)) break;
235                                 }
236                                 else n = 0;
237                                 tm->tm_sec = n;
238                                 tm->tm_min = j;
239                                 tm->tm_hour = i;
240                                 continue;
241                         }
242                 }
243                 while (isspace(*s) || *s == ',' || *s == '-') s++;
244                 if (isalpha(*s) && n < 1000)
245                 {
246                         if ((j = tmlex(s, &t, tm_info.format, TM_NFORM, tm_info.format + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0)
247                         {
248                                 s = t;
249                                 switch (tm_data.lex[j])
250                                 {
251                                 case TM_EXACT:
252                                         state |= HOLD|EXACT;
253                                         continue;
254                                 case TM_LAST:
255                                         state |= HOLD|LAST;
256                                         continue;
257                                 case TM_THIS:
258                                         state |= HOLD|THIS;
259                                         n = 0;
260                                         continue;
261                                 case TM_NEXT:
262                                         state |= HOLD|NEXT;
263                                         continue;
264                                 case TM_MERIDIAN:
265                                         if (n > 0)
266                                         {
267                                                 if (n > 24) goto done;
268                                                 tm->tm_hour = n;
269                                         }
270                                         if (j == TM_MERIDIAN)
271                                         {
272                                                 if (tm->tm_hour == 12) tm->tm_hour = 0;
273                                         }
274                                         else if (tm->tm_hour < 12) tm->tm_hour += 12;
275                                         if (n > 0) goto clear_min;
276                                         continue;
277                                 case TM_DAY_3:
278                                         j += TM_DAY - TM_DAY_3;
279                                         /*FALLTHROUGH*/
280                                 case TM_DAY:
281                                 case TM_PARTS:
282                                 case TM_HOURS:
283                                 case TM_DAYS:
284                                         if (n == -1) n = 1;
285                                         if (!(state & (LAST|NEXT|THIS))) for (;;)
286                                         {
287                                                 while (isspace(*s) || *s == ',') s++;
288                                                 if ((k = tmlex(s, &t, tm_info.format + TM_LAST, TM_NOISE - TM_LAST, NiL, 0)) >= 0)
289                                                 {
290                                                         s = t;
291                                                         if (k <= 2) state |= LAST;
292                                                         else if (k <= 5) state |= THIS;
293                                                         else if (k <= 8) state |= NEXT;
294                                                         else state |= EXACT;
295                                                 }
296                                                 else break;
297                                         }
298                                         if (state & LAST) n = -n;
299                                         else if (!(state & NEXT)) n--;
300                                         switch (j)
301                                         {
302                                         case TM_DAYS+0:
303                                                 tm->tm_mday--;
304                                                 goto clear_hour;
305                                         case TM_DAYS+1:
306                                                 goto clear_hour;
307                                         case TM_DAYS+2:
308                                                 tm->tm_mday++;
309                                                 goto clear_hour;
310                                         case TM_PARTS+0:
311                                                 tm->tm_sec += n;
312                                                 continue;
313                                         case TM_PARTS+1:
314                                                 tm->tm_min += n;
315                                                 goto clear_sec;
316                                         case TM_PARTS+2:
317                                                 tm->tm_hour += n;
318                                                 goto clear_min;
319                                         case TM_PARTS+3:
320                                                 tm->tm_mday += n;
321                                                 goto clear_hour;
322                                         case TM_PARTS+4:
323                                                 tm->tm_mday += 7 * n - tm->tm_wday + 1;
324                                                 goto clear_hour;
325                                         case TM_PARTS+5:
326                                                 tm->tm_mon += n;
327                                                 goto clear_mday;
328                                         case TM_PARTS+6:
329                                                 tm->tm_year += n;
330                                                 goto clear_mon;
331                                         case TM_HOURS+0:
332                                                 tm->tm_mday += n;
333                                                 goto clear_hour;
334                                         case TM_HOURS+1:
335                                                 tm->tm_mday += n;
336                                                 tm->tm_hour = 6;
337                                                 goto clear_min;
338                                         case TM_HOURS+2:
339                                                 tm->tm_mday += n;
340                                                 tm->tm_hour = 12;
341                                                 goto clear_min;
342                                         case TM_HOURS+3:
343                                                 tm->tm_mday += n;
344                                                 tm->tm_hour = 18;
345                                                 goto clear_min;
346                                         default:
347                                                 j -= tm->tm_wday + TM_DAY;
348                                                 if (state & (LAST|NEXT|THIS))
349                                                 {
350                                                         if (j < 0) j += 7;
351                                                 }
352                                                 else if (j > 0) j -= 7;
353                                                 tm->tm_mday += j + n * 7;
354                                                 if (state & (LAST|NEXT|THIS)) goto clear_hour;
355                                                 continue;
356                                         }
357                                         break;
358                                 case TM_MONTH_3:
359                                         j += TM_MONTH - TM_MONTH_3;
360                                         /*FALLTHROUGH*/
361                                 case TM_MONTH:
362                                         if (state & MONTH) goto done;
363                                         state |= MONTH;
364                                         i = tm->tm_mon;
365                                         tm->tm_mon = j - TM_MONTH;
366                                         if (n < 0)
367                                         {
368                                                 while (isspace(*s) || *s == ',' || *s == '-') s++;
369                                                 if (isdigit(*s))
370                                                 {
371                                                         n = strtol(s, &t, 10);
372                                                         if (n <= 31) s = t;
373                                                         else n = -1;
374                                                 }
375                                         }
376                                         if (n >= 0)
377                                         {
378                                                 if (n > 31) goto done;
379                                                 state |= MDAY;
380                                                 tm->tm_mday = n;
381                                         }
382                                         if (state & (LAST|NEXT|THIS))
383                                         {
384                                                 n = i;
385                                                 goto rel_month;
386                                         }
387                                         continue;
388                                 case TM_UT:
389                                         if (state & ZONE) goto done;
390                                         state |= ZONE;
391                                         zone += tmgoff(s, &t, 0);
392                                         s = t;
393                                         continue;
394                                 case TM_DT:
395                                         if (!dst) goto done;
396                                         if (!(state & ZONE))
397                                         {
398                                                 dst = tm_info.zone->dst;
399                                                 zone = tm_info.zone->west;
400                                         }
401                                         zone += tmgoff(s, &t, dst);
402                                         s = t;
403                                         dst = 0;
404                                         state |= ZONE;
405                                         continue;
406                                 case TM_NOISE:
407                                         continue;
408                                 }
409                         }
410                         if (!(state & ZONE) && (zp = tmzone(s, &t, type, &dst)))
411                         {
412                                 s = t;
413                                 zone += zp->west + dst;
414                                 tm_info.date = zp;
415                                 state |= ZONE;
416                                 continue;
417                         }
418                         if (!type && (zp = tmtype(s, &t)))
419                         {
420                                 s = t;
421                                 type = zp->type;
422                                 continue;
423                         }
424                         state |= BREAK;
425                 }
426                 else if (*s == '/')
427                 {
428                         if (!isdigit(*++s) || (state & MONTH) || n == 0 || n > 12) break;
429                         i = n - 1;
430                         n = strtol(s, &t, 10);
431                         s = t;
432                         if (n <= 0 || n > 31) break;
433                         if (*s == '/' && !isdigit(*(s + 1))) break;
434                         state |= MONTH|MDAY;
435                         tm->tm_mday = n;
436                         n = tm->tm_mon;
437                         tm->tm_mon = i;
438                         if (*s == '/')
439                         {
440                                 n = strtol(s + 1, &t, 10);
441                                 s = t;
442                         }
443                         else
444                         {
445                                 if (state & (LAST|NEXT|THIS))
446                                 {
447                                 rel_month:
448                                         if (state & LAST) tm->tm_year -= (tm->tm_mon < n) ? 0 : 1;
449                                         else tm->tm_year += ((state & NEXT) ? 1 : 0) + ((tm->tm_mon < n) ? 1 : 0);
450                                         if (state & MDAY) goto clear_hour;
451                                         goto clear_mday;
452                                 }
453                                 continue;
454                         }
455                 }
456                 if (n < 0 || (state & YEAR)) break;
457                 state |= YEAR;
458                 if (n > 1900) n -= 1900;
459                 if (n < 38) n += 100;
460                 tm->tm_year = n;
461                 if (state & BREAK)
462                 {
463                         last = t;
464                         break;
465                 }
466                 continue;
467         clear_mon:
468                 if (state & EXACT) continue;
469                 tm->tm_mon = 0;
470         clear_mday:
471                 if (state & EXACT) continue;
472                 tm->tm_mday = 1;
473         clear_hour:
474                 if (state & EXACT) continue;
475                 tm->tm_hour = 0;
476         clear_min:
477                 if (state & EXACT) continue;
478                 tm->tm_min = 0;
479         clear_sec:
480                 if (state & EXACT) continue;
481                 tm->tm_sec = 0;
482         }
483  done:
484         if (e) *e = last;
485         return(tmtime(tmfix(tm), (state & ZONE) ? zone : TM_LOCALZONE));
486 }