Personal tools
You are here: Home Projects C++ Cfront releases Release 3.0.3 source libSC Time tm tmdate.c
Document Actions

tmdate.c

by Michael L Powell last modified 2007-01-26 03:24

Click here to get the file

Size 8.5 kB - File type text/plain

File contents

/*ident	"@(#)Time:tm/tmdate.c	3.1" */
/******************************************************************************
*
* C++ Standard Components, Release 3.0.
*
* Copyright (c) 1991, 1992 AT&T and Unix System Laboratories, Inc.
* Copyright (c) 1988, 1989, 1990 AT&T.  All Rights Reserved.
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T and Unix System
* Laboratories, Inc.  The copyright notice above does not evidence
* any actual or intended publication of such source code.
*
******************************************************************************/

#include <tm.h>
#include <ctype.h>

#define twodig(s,n)	(n = (*s++ - '0') * 10, n += *s++ - '0')

#define BREAK		(1<<0)
#define DAY		(1<<1)
#define HOLD		(1<<2)
#define HOUR		(1<<3)
#define LAST		(1<<4)
#define MDAY		(1<<5)
#define MONTH		(1<<6)
#define NEXT		(1<<7)
#define THIS		(1<<8)
#define YEAR		(1<<9)
#define YYMMDDHHMMSS	(1<<10)
#define ZONE		(1<<11)

#define EXACT		(1<<12)

/*
 * parse date expression in s and return time_t value
 *
 * if non-null, e points to the first invalid sequence in s
 * clock provides default values
 */

time_t tmdate_ATTLC(register const char* sss, char** e, time_t* clock) {
	register struct tm*	tm;
	register int		n;
	int			state;
	time_t			now;
	char*			t;
	char*			last;
	char*			type;
	int			dst;
	int			zone;
	int			i;
	int			j;
	int			k;
	int			l;
	int			m;
	char*                   s=(char*)sss;

 reset:

	/*
	 * use clock for defaults
	 */

	tm = tmmake_ATTLC(clock);
	dst = TM_DST;
	state = HOLD|EXACT;        // cludge for EXACT
	type = 0;
	zone = 0;

	/*
	 * get <weekday year month day hour minutes seconds ?[ds]t [ap]m>
	 */

	for (;;)
	{
		state &= (state & HOLD) ? ~(HOLD) : ~(EXACT|LAST|NEXT|THIS);
		n = -1;
		while (isspace(*s) || *s == ',' || *s == '-') s++;
		if (!*(last = (char*)s)) break;
		if (*s == '#')
		{
			if (!isdigit(*++s)) break;
			now = strtol(s, &t, 0);
			clock = &now;
			s = t;
			goto reset;
		}
		if (isdigit(*s))
		{
			n = (int)strtol(s, &t, 10);
			if (!(state & (LAST|NEXT|THIS)) && (!*t && (t - s) > 4 || *t == '.' && (t - s) == 4))
			{
				/*
				 * old date(1) format
				 *
				 *	[yy[mm]]ddhhmm[.ss]
				 *	hhmm.ss
				 */

				if (state & YYMMDDHHMMSS) break;
				state |= YYMMDDHHMMSS;
				if ((t - s) < 10) m = tm->tm_year;
				else if (twodig(s, m) < 38) m += 100;
				if ((t - s) < 8) l = tm->tm_mon;
				else if (twodig(s, l) <= 0 || l > 12) break;
				if ((t - s) < 6) k = tm->tm_mon;
				else if (twodig(s, k) < 1 || k > 31) break;
				if ((t - s) < 4) break;
				if (twodig(s, j) > 24) break;
				if (twodig(s, i) > 59) break;
				if ((t - s) == 2) twodig(s, n);
				else if (t - s) break;
				else if (*t != '.') n = 0;
				else n = (int)strtol(t + 1, &t, 10);
				if (n > (59 + TM_MAXLEAP)) break;
				tm->tm_year = m;
				tm->tm_mon = l - 1;
				tm->tm_mday = k;
				tm->tm_hour = j;
				tm->tm_min = i;
				tm->tm_sec = n;
				s = t;
				continue;
			}
			s = t;
			if (*s == ':')
			{
				if ((state & HOUR) || n > 24 || *s++ != ':' || !isdigit(*s)) break;
				i = n;
				n = (int)strtol(s, &t, 10);
				s = t;
				if (n > 59) break;
				j = n;
				if (*s == ':')
				{
					if (!isdigit(*++s)) break;
					n = (int)strtol(s, &t, 10);
					s = t;
					if (n > (59 + TM_MAXLEAP)) break;
				}
				else n = 0;
				tm->tm_sec = n;
				tm->tm_min = j;
				tm->tm_hour = i;
				continue;
			}
		}
		while (isspace(*s) || *s == ',' || *s == '-') s++;
		if (isalpha(*s))
		{
			if ((j = tmlex_ATTLC(s, &t, tm_form_ATTLC, TM_NFORM, tm_form_ATTLC + TM_SUFFIXES, TM_PARTS - TM_SUFFIXES)) >= 0)
			{
				s = t;
				switch (tm_lex_ATTLC[j])
				{
/*
				case TM_EXACT:
					state |= HOLD|EXACT;
					continue;
*/
				case TM_LAST:
					state |= HOLD|LAST;
					continue;
				case TM_THIS:
					state |= HOLD|THIS;
					n = 0;
					continue;
				case TM_NEXT:
					state |= HOLD|NEXT;
					continue;
				case TM_MERIDIAN:
					if (n > 0)
					{
						if (n > 24) goto done;
						tm->tm_hour = n;
					}
					if (j == TM_MERIDIAN)
					{
						if (tm->tm_hour == 12) tm->tm_hour = 0;
					}
					else if (tm->tm_hour < 12) tm->tm_hour += 12;
					if (n > 0) goto clear_min;
					continue;
				case TM_DAY_3:
					j += TM_DAY - TM_DAY_3;
					/*FALLTHROUGH*/
				case TM_DAY:
				case TM_PARTS:
				case TM_HOURS:
				case TM_DAYS:
					if (n == -1) n = 1;
					if (!(state & (LAST|NEXT|THIS))) for (;;)
					{
						while (isspace(*s) || *s == ',') s++;
						if ((k = tmlex_ATTLC(s, &t, tm_form_ATTLC + TM_LAST, TM_NOISE - TM_LAST, (char**)0, 0)) >= 0)
						{
							s = t;
							if (k <= 2) state |= LAST;
							else if (k <= 5) state |= THIS;
							else if (k <= 8) state |= NEXT;
							else state |= EXACT;
						}
						else break;
					}
					if (state & LAST) n = -n;
					else if (!(state & NEXT)) n--;
					switch (j)
					{
					case TM_DAYS+0:
						tm->tm_mday--;
						goto clear_hour;
					case TM_DAYS+1:
						goto clear_hour;
					case TM_DAYS+2:
						tm->tm_mday++;
						goto clear_hour;
					case TM_PARTS+0:
						tm->tm_sec += n;
						continue;
					case TM_PARTS+1:
						tm->tm_min += n;
						goto clear_sec;
					case TM_PARTS+2:
						tm->tm_hour += n;
						goto clear_min;
					case TM_PARTS+3:
						tm->tm_mday += n;
						goto clear_hour;
					case TM_PARTS+4:
						tm->tm_mday += 7 * n - tm->tm_wday + 1;
						goto clear_hour;
					case TM_PARTS+5:
						tm->tm_mon += n;
						goto clear_mday;
					case TM_PARTS+6:
						tm->tm_year += n;
						goto clear_mon;
					case TM_HOURS+0:
						tm->tm_mday += n;
						goto clear_hour;
					case TM_HOURS+1:
						tm->tm_mday += n;
						tm->tm_hour = 6;
						goto clear_min;
					case TM_HOURS+2:
						tm->tm_mday += n;
						tm->tm_hour = 12;
						goto clear_min;
					case TM_HOURS+3:
						tm->tm_mday += n;
						tm->tm_hour = 18;
						goto clear_min;
					default:
						j -= tm->tm_wday + TM_DAY;
						if (state & (LAST|NEXT|THIS))
						{
							if (j < 0) j += 7;
						}
						else if (j > 0) j -= 7;
						tm->tm_mday += j + n * 7;
						if (state & (LAST|NEXT|THIS)) goto clear_hour;
						continue;
					}
					/*break;*/ /* unreachable */
				case TM_MONTH_3:
					j += TM_MONTH - TM_MONTH_3;
					/*FALLTHROUGH*/
				case TM_MONTH:
					if (state & MONTH) goto done;
					state |= MONTH;
					i = tm->tm_mon;
					tm->tm_mon = j - TM_MONTH;
					if (n < 0)
					{
						while (isspace(*s) || *s == ',' || *s == '-') s++;
						if (isdigit(*s))
						{
							n = (int)strtol(s, &t, 10);
							if (n <= 31) s = t;
							else n = -1;
						}
					}
					if (n >= 0)
					{
						if (n > 31) goto done;
						state |= MDAY;
						tm->tm_mday = n;
					}
					if (state & (LAST|NEXT|THIS))
					{
						n = i;
						goto rel_month;
					}
					continue;
				case TM_UT:
					if (state & ZONE) goto done;
					state |= ZONE;
					zone += tmgoff_ATTLC(s, &t, 0);
					s = t;
					continue;
				case TM_DT:
					if (!dst) goto done;
					if (!(state & ZONE))
					{
						dst = tm_local_ATTLC->dst;
						zone = tm_local_ATTLC->west;
					}
					zone += tmgoff_ATTLC(s, &t, dst);
					s = t;
					dst = 0;
					state |= ZONE;
					continue;
				case TM_NOISE:
					continue;
				}
			}
			if (!(state & ZONE) && (j = tmzone_ATTLC(s, &t, type, &dst)) != TM_LOCALZONE)
			{
				s = t;
				zone += j;
				state |= ZONE;
				continue;
			}
			if (!type && (type = tmtype_ATTLC(s, &t)))
			{
				s = t;
				continue;
			}
			state |= BREAK;
		}
		else if (*s == '/')
		{
			if (!isdigit(*++s) || (state & MONTH) || n == 0 || n > 12) break;
			i = n - 1;
			n = (int)strtol(s, &t, 10);
			s = t;
			if (n <= 0 || n > 31) break;
			if (*s == '/' && !isdigit(*(s + 1))) break;
			state |= MONTH|MDAY;
			tm->tm_mday = n;
			n = tm->tm_mon;
			tm->tm_mon = i;
			if (*s == '/')
			{
				n = (int)strtol(s + 1, &t, 10);
				s = t;
			}
			else
			{
				if (state & (LAST|NEXT|THIS))
				{
				rel_month:
					if (state & LAST) tm->tm_year -= (tm->tm_mon < n) ? 0 : 1;
					else tm->tm_year += ((state & NEXT) ? 1 : 0) + ((tm->tm_mon < n) ? 1 : 0);
					if (state & MDAY) goto clear_hour;
					goto clear_mday;
				}
				continue;
			}
		}
		if (n < 0 || (state & YEAR)) break;
		state |= YEAR;
		if (n > 1900) n -= 1900;
		if (n < 38) n += 100;
		tm->tm_year = n;
		if (state & BREAK)
		{
			last = t;
			break;
		}
		continue;
	clear_mon:
		if (state & EXACT) continue;
		tm->tm_mon = 0;
	clear_mday:
		if (state & EXACT) continue;
		tm->tm_mday = 1;
	clear_hour:
		if (state & EXACT) continue;
		tm->tm_hour = 0;
	clear_min:
		if (state & EXACT) continue;
		tm->tm_min = 0;
	clear_sec:
		if (state & EXACT) continue;
		tm->tm_sec = 0;
	}
 done:
	if (e) *e = last;
	return(tmtime_ATTLC(tmfix_ATTLC(tm), (state & ZONE) ? zone : TM_LOCALZONE));
}
« April 2024 »
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
 

Powered by Plone CMS, the Open Source Content Management System

This site conforms to the following standards: