[comp.sources.unix] v24i015: CVS upgrade for RCS5.5 support, Part02/02

rsalz@bbn.com (Rich Salz) (02/26/91)

Submitted-by: Brian Berliner <berliner@central.sun.com>
Posting-number: Volume 24, Issue 15
Archive-name: cvs1.2upgrade/part02

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
# Contents:  Patch02.02
# Wrapped by rsalz@litchi.bbn.com on Mon Feb 25 16:05:39 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
echo If this archive is complete, you will see the following message:
echo '          "shar: End of archive 2 (of 2)."'
if test -f 'Patch02.02' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Patch02.02'\"
else
  echo shar: Extracting \"'Patch02.02'\" \(48942 characters\)
  sed "s/^X//" >'Patch02.02' <<'END_OF_FILE'
X!  * Initial revision
X!  * 
X!  */
X  
X! /* minimal changes needed to get this file to work for CVS rather than RCS */
X! /* #include "rcsbase.h" */
X! #include <ctype.h>
X! #include <time.h>
X! #include "cvs.h"
X! #define libId(x,y) static char x[] = y;
X! #define P(x) ()
X! #if !__STDC__
X! #	define const
X  #endif
X+ /* see also `RCS' in comment below */
X+ 
X+ libId(partId, "$Id: partime.c,v 1.1.1.1 91/01/18 12:18:12 berliner Exp $")
X  
X+ #define given(v) (0 <= (v))
X+ #define TMNULL (-1) /* Items not given are given this value */
X+ #define TZ_OFFSET (24*60) /* TMNULL  <  zone_offset - TZ_OFFSET */
X+ 
X  struct tmwent {
X! 	const char *went;
X! 	short wval;
X  	char wflgs;
X  	char wtype;
X  };
X  	/* wflgs */
X  #define TWTIME 02	/* Word is a time value (absence implies date) */
X  #define TWDST  04	/* Word is a DST-type timezone */
X! 	/* wtype */
X! #define TM_MON	1	/* month name */
X! #define TM_WDAY	2	/* weekday name */
X! #define TM_ZON	3	/* time zone name */
X! #define TM_LT	4	/* local time */
X! #define TM_DST	5	/* daylight savings time */
X! #define TM_12	6	/* AM, PM, NOON, or MIDNIGHT */
X! 	/* wval (for wtype==TM_12) */
X! #define T12_AM 1
X! #define T12_PM 2
X! #define T12_NOON 12
X! #define T12_MIDNIGHT 0
X  
X! static const struct tmwent tmwords [] = {
X  	{"january",      0, 0, TM_MON},
X  	{"february",     1, 0, TM_MON},
X  	{"march",        2, 0, TM_MON},
X***************
X*** 75,119 ****
X  	{"saturday",     6, 0, TM_WDAY},
X  
X  	{"gmt",          0*60, TWTIME, TM_ZON},   /* Greenwich */
X! 	{"gst",          0*60, TWTIME, TM_ZON},
X! 	{"gdt",          0*60, TWTIME+TWDST, TM_ZON},     /* ?? */
X  
X  	{"ast",          4*60, TWTIME, TM_ZON},   /* Atlantic */
X  	{"est",          5*60, TWTIME, TM_ZON},   /* Eastern */
X  	{"cst",          6*60, TWTIME, TM_ZON},   /* Central */
X  	{"mst",          7*60, TWTIME, TM_ZON},   /* Mountain */
X  	{"pst",          8*60, TWTIME, TM_ZON},   /* Pacific */
X! 	{"yst",          9*60, TWTIME, TM_ZON},   /* Yukon */
X  	{"hst",          10*60, TWTIME, TM_ZON},  /* Hawaii */
X! 	{"bst",          11*60, TWTIME, TM_ZON},  /* Bering */
X  
X  	{"adt",          4*60, TWTIME+TWDST, TM_ZON},     /* Atlantic */
X  	{"edt",          5*60, TWTIME+TWDST, TM_ZON},     /* Eastern */
X  	{"cdt",          6*60, TWTIME+TWDST, TM_ZON},     /* Central */
X  	{"mdt",          7*60, TWTIME+TWDST, TM_ZON},     /* Mountain */
X  	{"pdt",          8*60, TWTIME+TWDST, TM_ZON},     /* Pacific */
X! 	{"ydt",          9*60, TWTIME+TWDST, TM_ZON},     /* Yukon */
X! 	{"hdt",          10*60, TWTIME+TWDST, TM_ZON},    /* Hawaii */
X! 	{"bdt",          11*60, TWTIME+TWDST, TM_ZON},    /* Bering */
X! 
X! 	{"daylight",     1, TWTIME+TWDST, TM_ZON},        /* Local Daylight */
X! 	{"standard",     1, TWTIME, TM_ZON},      /* Local Standard */
X! 	{"std",          1, TWTIME, TM_ZON},      /*   "       "    */
X! 
X! 	{"am",           1, TWTIME, TM_AMPM},
X! 	{"pm",           2, TWTIME, TM_AMPM},
X! 	{"noon",         12,TWTIME+TW1200, 0},    /* Special frobs */
X! 	{"midnight",     0, TWTIME+TW1200, 0},
X! 	{"at",           (long)ptnoise, TWSPEC, 0},    /* Noise word */
X  
X  	{0, 0, 0, 0},             /* Zero entry to terminate searches */
X  };
X  
X- #define TMWILD (-2)	/* Value meaning item specified as wild-card */
X- 			/* (May use someday...) */
X- 
X  struct token {
X! 	char *tcp;	/* pointer to string */
X  	int tcnt;	/* # chars */
X  	char tbrk;	/* "break" char */
X  	char tbrkl;	/* last break char */
X--- 123,230 ----
X  	{"saturday",     6, 0, TM_WDAY},
X  
X  	{"gmt",          0*60, TWTIME, TM_ZON},   /* Greenwich */
X! 	{"utc",          0*60, TWTIME, TM_ZON},
X! 	{"ut",           0*60, TWTIME, TM_ZON},
X  
X+ 	{"nzst",        -12*60, TWTIME, TM_ZON},  /* New Zealand */
X+ 	{"jst",         -9*60, TWTIME, TM_ZON},   /* Japan */
X+ 	{"kst",         -9*60, TWTIME, TM_ZON},   /* Korea */
X+ 	{"ist",         -5*60-30, TWTIME, TM_ZON},/* India */
X+ 	{"eet",         -2*60, TWTIME, TM_ZON},   /* Eastern Europe */
X+ 	{"cet",         -1*60, TWTIME, TM_ZON},   /* Central Europe */
X+ 	{"met",         -1*60, TWTIME, TM_ZON},   /* Middle Europe */
X+ 	{"wet",          0*60, TWTIME, TM_ZON},   /* Western Europe */
X+ 	{"nst",          3*60+30, TWTIME, TM_ZON},/* Newfoundland */
X  	{"ast",          4*60, TWTIME, TM_ZON},   /* Atlantic */
X  	{"est",          5*60, TWTIME, TM_ZON},   /* Eastern */
X  	{"cst",          6*60, TWTIME, TM_ZON},   /* Central */
X  	{"mst",          7*60, TWTIME, TM_ZON},   /* Mountain */
X  	{"pst",          8*60, TWTIME, TM_ZON},   /* Pacific */
X! 	{"akst",         9*60, TWTIME, TM_ZON},   /* Alaska */
X! 	{"hast",         10*60, TWTIME, TM_ZON},  /* Hawaii-Aleutian */
X  	{"hst",          10*60, TWTIME, TM_ZON},  /* Hawaii */
X! 	{"sst",          11*60, TWTIME, TM_ZON},  /* Samoa */
X  
X+ 	{"nzdt",        -12*60, TWTIME+TWDST, TM_ZON},    /* New Zealand */
X+ 	{"kdt",         -9*60, TWTIME+TWDST, TM_ZON},     /* Korea */
X+ 	{"bst",          0*60, TWTIME+TWDST, TM_ZON},     /* Britain */
X+ 	{"ndt",          2*60+30, TWTIME+TWDST, TM_ZON}, /*Newfoundland (DDST)*/
X  	{"adt",          4*60, TWTIME+TWDST, TM_ZON},     /* Atlantic */
X  	{"edt",          5*60, TWTIME+TWDST, TM_ZON},     /* Eastern */
X  	{"cdt",          6*60, TWTIME+TWDST, TM_ZON},     /* Central */
X  	{"mdt",          7*60, TWTIME+TWDST, TM_ZON},     /* Mountain */
X  	{"pdt",          8*60, TWTIME+TWDST, TM_ZON},     /* Pacific */
X! 	{"akdt",         9*60, TWTIME+TWDST, TM_ZON},     /* Alaska */
X! 	{"hadt",         10*60, TWTIME+TWDST, TM_ZON},    /* Hawaii-Aleutian */
X! 
X! #if 0
X! 	/*
X! 	 * The following names are duplicates or are not well attested.
X! 	 * A standard is needed.
X! 	 */
X! 	{"?st",         -13*60, TWTIME, TM_ZON},  /* Uelen */
X! 	{"?st",         -11*60, TWTIME, TM_ZON},  /* Magadan */
X! 	{"east",        -10*60, TWTIME, TM_ZON},  /* Eastern Australia */
X! 	{"cast",        -9*60-30, TWTIME, TM_ZON},/* Central Australia */
X! 	{"cst",         -8*60, TWTIME, TM_ZON},   /* China */
X! 	{"hkt",         -8*60, TWTIME, TM_ZON},   /* Hong Kong */
X! 	{"sst",         -8*60, TWTIME, TM_ZON},   /* Singapore */
X! 	{"wast",        -8*60, TWTIME, TM_ZON},   /* Western Australia */
X! 	{"?st",         -7*60, TWTIME, TM_ZON},   /* Novosibirsk */
X! 	{"jt",          -7*60-30, TWTIME, TM_ZON},/* Java */
X! 	{"nst",         -6*60-30, TWTIME, TM_ZON},/* North Sumatra */
X! 	{"?st",         -6*60, TWTIME, TM_ZON},   /* Tashkent */
X! 	{"?st",         -5*60, TWTIME, TM_ZON},	  /* Sverdlovsk */
X! 	{"?",           -4*60-30, TWTIME, TM_ZON},/* Afghanistan */
X! 	{"?st",         -4*60, TWTIME, TM_ZON},	  /* Rostov */
X! 	{"it",          -3*60-30, TWTIME, TM_ZON},/* Iran */
X! 	{"?st",         -3*60, TWTIME, TM_ZON},   /* Moscow */
X! 	{"ist",         -2*60, TWTIME, TM_ZON},   /* Israel */
X! 	{"ast",          1*60, TWTIME, TM_ZON},   /* Azores */
X! 	{"fst",          2*60, TWTIME, TM_ZON},   /* Fernando de Noronha */
X! 	{"bst",          3*60, TWTIME, TM_ZON},   /* Brazil */
X! 	{"wst",          4*60, TWTIME, TM_ZON},   /* Western Brazil */
X! 	{"ast",          5*60, TWTIME, TM_ZON},   /* Acre Brazil */
X! 	{"?",            9*60+30, TWTIME, TM_ZON},/* Marquesas */
X! 	{"?st",          12*60, TWTIME, TM_ZON},  /* Kwajalein */
X! 
X! 	{"?dt",         -13*60, TWTIME+TWDST, TM_ZON},	  /* Uelen */
X! 	{"?dt",         -11*60, TWTIME+TWDST, TM_ZON},	  /* Magadan */
X! 	{"eadt",        -10*60, TWTIME+TWDST, TM_ZON},    /* Eastern Australia */
X! 	{"cadt",        -9*60-30, TWTIME+TWDST, TM_ZON},  /* Central Australia */
X! 	{"cdt",         -8*60, TWTIME+TWDST, TM_ZON},     /* China */
X! 	{"wadt",        -8*60, TWTIME+TWDST, TM_ZON},     /* Western Australia */
X! 	{"?dt",         -7*60, TWTIME+TWDST, TM_ZON},	  /* Novosibirsk */
X! 	{"?dt",         -6*60, TWTIME+TWDST, TM_ZON},	  /* Tashkent */
X! 	{"?dt",         -5*60, TWTIME+TWDST, TM_ZON},	  /* Sverdlovsk */
X! 	{"?dt",         -4*60, TWTIME+TWDST, TM_ZON},	  /* Rostov */
X! 	{"?dt",         -3*60, TWTIME+TWDST, TM_ZON},     /* Moscow */
X! 	{"idt",         -2*60, TWTIME+TWDST, TM_ZON},     /* Israel */
X! 	{"eest",        -2*60, TWTIME+TWDST, TM_ZON},     /* Eastern Europe */
X! 	{"cest",        -1*60, TWTIME+TWDST, TM_ZON},     /* Central Europe */
X! 	{"mest",        -1*60, TWTIME+TWDST, TM_ZON},     /* Middle Europe */
X! 	{"west",         0*60, TWTIME+TWDST, TM_ZON},     /* Western Europe */
X! 	{"adt",          1*60, TWTIME+TWDST, TM_ZON},	  /* Azores */
X! 	{"fdt",          2*60, TWTIME+TWDST, TM_ZON},     /* Fernando de Noronha */
X! 	{"edt",          3*60, TWTIME+TWDST, TM_ZON},     /* Eastern Brazil */
X! 	{"wdt",          4*60, TWTIME+TWDST, TM_ZON},     /* Western Brazil */
X! 	{"adt",          5*60, TWTIME+TWDST, TM_ZON},     /* Acre Brazil */
X! #endif
X! 
X! 	{"lt",           0, TWTIME, TM_LT},       /* local time */
X! 	{"dst",          1*60, TWTIME, TM_DST},      /* daylight savings time */
X! 	{"ddst",         2*60, TWTIME, TM_DST},      /* double dst */
X! 
X! 	{"am",           T12_AM,	TWTIME, TM_12},
X! 	{"pm",           T12_PM,	TWTIME, TM_12},
X! 	{"noon",         T12_NOON,	TWTIME, TM_12},
X! 	{"midnight",     T12_MIDNIGHT,	TWTIME, TM_12},
X  
X  	{0, 0, 0, 0},             /* Zero entry to terminate searches */
X  };
X  
X  struct token {
X! 	const char *tcp;/* pointer to string */
X  	int tcnt;	/* # chars */
X  	char tbrk;	/* "break" char */
X  	char tbrkl;	/* last break char */
X***************
X*** 120,227 ****
X  	char tflg;	/* 0 = alpha, 1 = numeric */
X  	union {         /* Resulting value; */
X  		int tnum;/* either a #, or */
X! 		struct tmwent *ttmw;/* ptr to a tmwent. */
X  	} tval;
X  };
X  
X! partime(astr, atm)
X! char *astr;
X! struct tm *atm;
X! {	register int *tp;
X! 	register struct tmwent *twp;
X! 	register int i;
X! 	struct token btoken, atoken;
X! 	char *cp, ch;
X! 	int ord, midnoon;
X! 	int (*aproc)();
X! 
X! 	tp = (int *)atm;
X! 	zaptime(tp);			 /* Initialize the TM structure */
X! 	midnoon = TMNULL;		/* and our own temp stuff */
X! 	btoken.tcnt = btoken.tbrkl = 0;
X! 	btoken.tcp = astr;
X  
X! domore:
X! 	if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken))	/* Get a token */
X  	  {     if(btoken.tval.tnum) return(0);         /* Read error? */
X! 		if(midnoon != TMNULL)			/* EOF, wrap up */
X! 			return(pt12hack(tp, midnoon));
X! 		return(1);				/* Win return! */
X  	  }
X  	if(btoken.tflg == 0)		/* Alpha? */
X! 	  {     twp = btoken.tval.ttmw;         /* Yes, get ptr to entry */
X! 		if(twp->wflgs&TWSPEC)		/* Special alpha crock */
X! 		  {     aproc = (int (*) ()) (twp->wval);
X! 			if(!(*aproc)(tp, twp, &btoken))
X! 				return(0);	/* ERR: special word err */
X! 			goto domore;
X! 		  }
X! 		if(twp->wflgs&TW1200)
X! 			if(ptstash(&midnoon,(int)twp->wval))
X! 				return(0);	/* ERR: noon/midnite clash */
X! 			else goto domore;
X! 		if(ptstash(&tp[twp->wtype],(int)twp->wval))
X  			return(0);		/* ERR: val already set */
X! 		if(twp->wtype == TM_ZON)	/* If was zone, hack DST */
X! 			if(ptstash(&tp[TM_ISDST],(twp->wflgs&TWDST)))
X! 				return(0);	/* ERR: DST conflict */
X! 		goto domore;
X  	  }
X  
X  	/* Token is number.  Lots of hairy heuristics. */
X! 	if(btoken.tcnt >= 7)	/* More than 6 digits in string? */
X! 		return(0);	/* ERR: number too big */
X! 	if(btoken.tcnt == 6)	/* 6 digits = HHMMSS.  Needs special crock */
X! 	  {			/* since 6 digits are too big for integer! */
X! 		i = (btoken.tcp[0]-'0')*10	/* Gobble 1st 2 digits */
X! 		   + btoken.tcp[1]-'0';
X! 		btoken.tcnt = 2;		/* re-read last 4 chars */
X! 		goto coltime;
X! 	  }
X  
X  	i = btoken.tval.tnum;   /* Value now known to be valid; get it. */
X! 	if( btoken.tcnt == 5	/*  5 digits = HMMSS */
X! 	 || btoken.tcnt == 3)	/*  3 digits = HMM   */
X! 	  {	if(btoken.tcnt != 3)
X! 			if(ptstash(&tp[TM_SEC], i%100))
X! 				return(0);	/* ERR: sec conflict */
X! 			else i /= 100;
X! hhmm4:		if(ptstash(&tp[TM_MIN], i%100))
X  			return(0);		/* ERR: min conflict */
X  		i /= 100;
X! hh2:            if(ptstash(&tp[TM_HOUR], i))
X  			return(0);		/* ERR: hour conflict */
X! 		goto domore;
X  	  }
X  
X  	if(btoken.tcnt == 4)	/* 4 digits = YEAR or HHMM */
X! 	  {	if(tp[TM_YEAR] != TMNULL) goto hhmm4;	/* Already got yr? */
X! 		if(tp[TM_HOUR] != TMNULL) goto year4;	/* Already got hr? */
X! 		if((i%100) > 59) goto year4;		/* MM >= 60? */
X  		if(btoken.tbrk == ':')			/* HHMM:SS ? */
X! 			if( ptstash(&tp[TM_HOUR],i/100)
X! 			 || ptstash(&tp[TM_MIN], i%100))
X  				return(0);		/* ERR: hr/min clash */
X  			else goto coltm2;		/* Go handle SS */
X  		if(btoken.tbrk != ',' && btoken.tbrk != '/'
X! 		  && ptitoken(btoken.tcp+btoken.tcnt,&atoken)	/* Peek */
X! 		  && atoken.tflg == 0			/* alpha */
X! 		  && (atoken.tval.ttmw->wflgs&TWTIME))  /* HHMM-ZON */
X  			goto hhmm4;
X! 		if(btoken.tbrkl == '-'		/* DD-Mon-YYYY */
X! 		  || btoken.tbrkl == ','	/* Mon DD, YYYY */
X! 		  || btoken.tbrkl == '/'	/* MM/DD/YYYY */
X! 		  || btoken.tbrkl == '.'	/* DD.MM.YYYY */
X! 		  || btoken.tbrk == '-'		/* YYYY-MM-DD */
X! 			) goto year4;
X! 		goto hhmm4;			/* Give up, assume HHMM. */
X  	  }
X  
X  	/* From this point on, assume tcnt == 1 or 2 */
X! 	/* 2 digits = YY, MM, DD, or HH (MM and SS caught at coltime) */
X  	if(btoken.tbrk == ':')		/* HH:MM[:SS] */
X  		goto coltime;		/*  must be part of time. */
X! 	if(i > 31) goto yy2;		/* If >= 32, only YY poss. */
X  
X  	/* Check for numerical-format date */
X  	for (cp = "/-."; ch = *cp++;)
X--- 231,398 ----
X  	char tflg;	/* 0 = alpha, 1 = numeric */
X  	union {         /* Resulting value; */
X  		int tnum;/* either a #, or */
X! 		const struct tmwent *ttmw;/* ptr to a tmwent. */
X  	} tval;
X  };
X  
X! static const struct tmwent*ptmatchstr P((const char*,int,const struct tmwent*));
X! static int pt12hack P((struct tm *,int));
X! static int ptitoken P((struct token *));
X! static int ptstash P((int *,int));
X! static int pttoken P((struct token *));
X! 
X! 	static int
X! goodzone(t, offset, am)
X! 	register const struct token *t;
X! 	int offset;
X! 	int *am;
X! {
X! 	register int m;
X! 	if (
X! 		t->tflg  &&
X! 		t->tcnt == 4+offset  &&
X! 		(m = t->tval.tnum) <= 2400  &&
X! 		isdigit(t->tcp[offset]) &&
X! 		(m%=100) < 60
X! 	) {
X! 		m += t->tval.tnum/100 * 60;
X! 		if (t->tcp[offset-1]=='+')
X! 			m = -m;
X! 		*am = m;
X! 		return 1;
X! 	}
X! 	return 0;
X! }
X! 
X!     int
X! partime(astr, atm, zone)
X! const char *astr;
X! register struct tm *atm;
X! int *zone;
X! {
X!     register int i;
X!     struct token btoken, atoken;
X!     int zone_offset; /* minutes west of GMT, plus TZ_OFFSET */
X!     register const char *cp;
X!     register char ch;
X!     int ord, midnoon;
X!     int *atmfield, dst, m;
X!     int got1 = 0;
X! 
X!     atm->tm_sec = TMNULL;
X!     atm->tm_min = TMNULL;
X!     atm->tm_hour = TMNULL;
X!     atm->tm_mday = TMNULL;
X!     atm->tm_mon = TMNULL;
X!     atm->tm_year = TMNULL;
X!     atm->tm_wday = TMNULL;
X!     atm->tm_yday = TMNULL;
X!     midnoon = TMNULL;		/* and our own temp stuff */
X!     zone_offset = TMNULL;
X!     dst = TMNULL;
X!     btoken.tcnt = btoken.tbrk = 0;
X!     btoken.tcp = astr;
X  
X!     for (;; got1=1) {
X! 	if (!ptitoken(&btoken))				/* Get a token */
X  	  {     if(btoken.tval.tnum) return(0);         /* Read error? */
X! 		if (given(midnoon))			/* EOF, wrap up */
X! 			if (!pt12hack(atm, midnoon))
X! 				return 0;
X! 		if (!given(atm->tm_min))
X! 			atm->tm_min = 0;
X! 		*zone  =
X! 				(given(zone_offset) ? zone_offset-TZ_OFFSET : 0)
X! 			-	(given(dst) ? dst : 0);
X! 		return got1;
X  	  }
X  	if(btoken.tflg == 0)		/* Alpha? */
X! 	  {     i = btoken.tval.ttmw->wval;
X! 		switch (btoken.tval.ttmw->wtype) {
X! 		  default:
X! 			return 0;
X! 		  case TM_MON:
X! 			atmfield = &atm->tm_mon;
X! 			break;
X! 		  case TM_WDAY:
X! 			atmfield = &atm->tm_wday;
X! 			break;
X! 		  case TM_DST:
X! 			atmfield = &dst;
X! 			break;
X! 		  case TM_LT:
X! 			if (ptstash(&dst, 0))
X! 				return 0;
X! 			i = 48*60; /* local time magic number -- see maketime() */
X! 			/* fall into */
X! 		  case TM_ZON:
X! 			i += TZ_OFFSET;
X! 			if (btoken.tval.ttmw->wflgs & TWDST)
X! 				if (ptstash(&dst, 60))
X! 					return 0;
X! 			/* Peek ahead for offset immediately afterwards. */
X! 			if (
X! 			    (btoken.tbrk=='-' || btoken.tbrk=='+') &&
X! 			    (atoken=btoken, ++atoken.tcnt, ptitoken(&atoken)) &&
X! 			    goodzone(&atoken, 0, &m)
X! 			) {
X! 				i += m;
X! 				btoken = atoken;
X! 			}
X! 			atmfield = &zone_offset;
X! 			break;
X! 		  case TM_12:
X! 			atmfield = &midnoon;
X! 		}
X! 		if (ptstash(atmfield, i))
X  			return(0);		/* ERR: val already set */
X! 		continue;
X  	  }
X  
X  	/* Token is number.  Lots of hairy heuristics. */
X! 	if (!isdigit(*btoken.tcp)) {
X! 		if (!goodzone(&btoken, 1, &m))
X! 			return 0;
X! 		zone_offset = TZ_OFFSET + m;
X! 		continue;
X! 	}
X  
X  	i = btoken.tval.tnum;   /* Value now known to be valid; get it. */
X! 	if (btoken.tcnt == 3)	/*  3 digits = HMM   */
X! 	  {
X! hhmm4:		if (ptstash(&atm->tm_min, i%100))
X  			return(0);		/* ERR: min conflict */
X  		i /= 100;
X! hh2:            if (ptstash(&atm->tm_hour, i))
X  			return(0);		/* ERR: hour conflict */
X! 		continue;
X  	  }
X  
X+ 	if (4 < btoken.tcnt)
X+ 		goto year4; /* far in the future */
X  	if(btoken.tcnt == 4)	/* 4 digits = YEAR or HHMM */
X! 	  {	if (given(atm->tm_year)) goto hhmm4;	/* Already got yr? */
X! 		if (given(atm->tm_hour)) goto year4;	/* Already got hr? */
X  		if(btoken.tbrk == ':')			/* HHMM:SS ? */
X! 			if ( ptstash(&atm->tm_hour, i/100)
X! 			  || ptstash(&atm->tm_min, i%100))
X  				return(0);		/* ERR: hr/min clash */
X  			else goto coltm2;		/* Go handle SS */
X  		if(btoken.tbrk != ',' && btoken.tbrk != '/'
X! 		  && (atoken=btoken, ptitoken(&atoken))	/* Peek */
X! 		  && ( atoken.tflg
X! 		     ? !isdigit(*atoken.tcp)
X! 		     : atoken.tval.ttmw->wflgs & TWTIME)) /* HHMM-ZON */
X  			goto hhmm4;
X! 		goto year4;			/* Give up, assume year. */
X  	  }
X  
X  	/* From this point on, assume tcnt == 1 or 2 */
X! 	/* 2 digits = MM, DD, or HH (MM and SS caught at coltime) */
X  	if(btoken.tbrk == ':')		/* HH:MM[:SS] */
X  		goto coltime;		/*  must be part of time. */
X! 	if (31 < i)
X! 		return 0;
X  
X  	/* Check for numerical-format date */
X  	for (cp = "/-."; ch = *cp++;)
X***************
X*** 228,416 ****
X  	  {	ord = (ch == '.' ? 0 : 1);	/* n/m = D/M or M/D */
X  		if(btoken.tbrk == ch)			/* "NN-" */
X  		  {	if(btoken.tbrkl != ch)
X! 			  {	if(ptitoken(btoken.tcp+btoken.tcnt,&atoken)
X  				  && atoken.tflg == 0
X  				  && atoken.tval.ttmw->wtype == TM_MON)
X  					goto dd2;
X  				if(ord)goto mm2; else goto dd2; /* "NN-" */
X  			  }				/* "-NN-" */
X! 			if(tp[TM_DAY] == TMNULL
X! 			&& tp[TM_YEAR] != TMNULL)	/* If "YY-NN-" */
X  				goto mm2;		/* then always MM */
X  			if(ord)goto dd2; else goto mm2;
X  		  }
X  		if(btoken.tbrkl == ch			/* "-NN" */
X! 		  && tp[ord ? TM_MON : TM_DAY] != TMNULL)
X! 			if(tp[ord ? TM_DAY : TM_MON] == TMNULL)	/* MM/DD */
X  				if(ord)goto dd2; else goto mm2;
X- 			else goto yy2;			/* "-YY" */
X  	  }
X  
X- 	/* At this point only YY, DD, and HH are left.
X- 	 * YY is very unlikely since value is <= 32 and there was
X- 	 * no numerical format date.  Make one last try at YY
X- 	 * before dropping through to DD vs HH code.
X- 	 */
X- 	if(btoken.tcnt == 2		/* If 2 digits */
X- 	  && tp[TM_HOUR] != TMNULL	/* and already have hour */
X- 	  && tp[TM_DAY] != TMNULL	/* and day, but  */
X- 	  && tp[TM_YEAR] == TMNULL)	/* no year, then assume */
X- 		goto yy2;		/* that's what we have. */
X- 
X  	/* Now reduced to choice between HH and DD */
X! 	if(tp[TM_HOUR] != TMNULL) goto dd2;	/* Have hour? Assume day. */
X! 	if(tp[TM_DAY] != TMNULL) goto hh2;	/* Have day? Assume hour. */
X  	if(i > 24) goto dd2;			/* Impossible HH means DD */
X! 	if(!ptitoken(btoken.tcp+btoken.tcnt, &atoken))	/* Read ahead! */
X  		if(atoken.tval.tnum) return(0); /* ERR: bad token */
X  		else goto dd2;			/* EOF, assume day. */
X! 	if( atoken.tflg == 0		/* If next token is an alpha */
X! 	 && atoken.tval.ttmw->wflgs&TWTIME)  /* time-spec, assume hour */
X  		goto hh2;		/* e.g. "3 PM", "11-EDT"  */
X  
X! dd2:	if(ptstash(&tp[TM_DAY],i))	/* Store day (1 based) */
X  		return(0);
X! 	goto domore;
X  
X! mm2:	if(ptstash(&tp[TM_MON], i-1))	/* Store month (make zero based) */
X  		return(0);
X! 	goto domore;
X  
X! yy2:	i += 1900;
X! year4:	if(ptstash(&tp[TM_YEAR],i))	/* Store year (full number) */
X  		return(0);		/* ERR: year conflict */
X! 	goto domore;
X  
X  	/* Hack HH:MM[[:]SS] */
X  coltime:
X! 	if(ptstash(&tp[TM_HOUR],i)) return(0);
X! 	if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken))
X  		return(!btoken.tval.tnum);
X  	if(!btoken.tflg) return(0);	/* ERR: HH:<alpha> */
X  	if(btoken.tcnt == 4)		/* MMSS */
X! 		if(ptstash(&tp[TM_MIN],btoken.tval.tnum/100)
X! 		  || ptstash(&tp[TM_SEC],btoken.tval.tnum%100))
X  			return(0);
X! 		else goto domore;
X  	if(btoken.tcnt != 2
X! 	  || ptstash(&tp[TM_MIN],btoken.tval.tnum))
X  		return(0);		/* ERR: MM bad */
X! 	if(btoken.tbrk != ':') goto domore;	/* Seconds follow? */
X! coltm2:	if(!ptitoken(btoken.tcp+btoken.tcnt,&btoken))
X  		return(!btoken.tval.tnum);
X  	if(!btoken.tflg || btoken.tcnt != 2	/* Verify SS */
X! 	  || ptstash(&tp[TM_SEC], btoken.tval.tnum))
X  		return(0);		/* ERR: SS bad */
X! 	goto domore;
X  }
X  
X  /* Store date/time value, return 0 if successful.
X!  * Fails if entry already set to a different value.
X   */
X  ptstash(adr,val)
X  int *adr;
X  {	register int *a;
X! 	if( *(a=adr) != TMNULL)
X! 		return(*a != val);
X  	*a = val;
X  	return(0);
X  }
X  
X! /* This subroutine is invoked for NOON or MIDNIGHT when wrapping up
X   * just prior to returning from partime.
X   */
X! pt12hack(atp, aval)
X! int *atp, aval;
X! {	register int *tp, i, h;
X! 	tp = atp;
X! 	if (((i=tp[TM_MIN]) && i != TMNULL)	/* Ensure mins, secs */
X! 	 || ((i=tp[TM_SEC]) && i != TMNULL))	/* are 0 or unspec'd */
X! 		return(0);			/* ERR: MM:SS not 00:00 */
X! 	i = aval;			/* Get 0 or 12 (midnite or noon) */
X! 	if ((h = tp[TM_HOUR]) == TMNULL	/* If hour unspec'd, win */
X! 	 || h == 12)			/* or if 12:00 (matches either) */
X! 		tp[TM_HOUR] = i;	/* Then set time */
X! 	else if(!(i == 0		/* Nope, but if midnight and */
X! 		&&(h == 0 || h == 24)))	/* time matches, can pass. */
X! 			return(0);	/* ERR: HH conflicts */
X! 	tp[TM_AMPM] = TMNULL;		/* Always reset this value if won */
X! 	return(1);
X  }
X  
X- /* Null routine for no-op tokens */
X- 
X- ptnoise() { return(1); }
X- 
X  /* Get a token and identify it to some degree.
X   * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise
X   * hit error of some sort
X   */
X  
X! ptitoken(astr, tkp)
X  register struct token *tkp;
X- char *astr;
X  {
X! 	register char *cp;
X! 	register int i;
X  
X! 	tkp->tval.tnum = 0;
X! 	if(pttoken(astr,tkp) == 0)
X  #ifdef DEBUG
X! 	VOID printf("EOF\n");
X! #endif DEBUG
X  		return(0);
X  	cp = tkp->tcp;
X  
X  #ifdef DEBUG
X! 	i = cp[tkp->tcnt];
X! 	cp[tkp->tcnt] = 0;
X! 	VOID printf("Token: \"%s\" ",cp);
X! 	cp[tkp->tcnt] = i;
X! #endif DEBUG
X! 
X! 	if(tkp->tflg)
X! 		for(i = tkp->tcnt; i > 0; i--)
X! 			tkp->tval.tnum = (int)tkp->tval.tnum*10 + ((*cp++)-'0');
X! 	else
X! 	  {     i = ptmatchstr(cp, tkp->tcnt, tmwords);
X! 		tkp->tval.tnum = i ? i : -1;         /* Set -1 for error */
X  
X  #ifdef DEBUG
X! 		if(!i) VOID printf("Not found!\n");
X! #endif DEBUG
X! 
X! 		if(!i) return(0);
X  	  }
X  
X  #ifdef DEBUG
X  	if(tkp->tflg)
X  		VOID printf("Val: %d.\n",tkp->tval.tnum);
X! 	else VOID printf("Found: \"%s\", val: %d., type %d\n",
X  		tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype);
X! #endif DEBUG
X  
X  	return(1);
X  }
X  
X  /* Read token from input string into token structure */
X! pttoken(astr,tkp)
X  register struct token *tkp;
X- char *astr;
X  {
X! 	register char *cp;
X  	register int c;
X  
X! 	tkp->tcp = cp = astr;
X  	tkp->tbrkl = tkp->tbrk;		/* Set "last break" */
X  	tkp->tcnt = tkp->tbrk = tkp->tflg = 0;
X  
X  	while(c = *cp++)
X  	  {	switch(c)
X  		  {	case ' ': case '\t':	/* Flush all whitespace */
X! 				while((c = *cp++) && isspace(c));
X! 				cp--;		/* Drop thru to handle brk */
X  			case '(': case ')':	/* Perhaps any non-alphanum */
X  			case '-': case ',':	/* shd qualify as break? */
X  			case '/': case ':': case '.':	/* Break chars */
X  				if(tkp->tcnt == 0)	/* If no token yet */
X  				  {	tkp->tcp = cp;	/* ignore the brk */
X--- 399,606 ----
X  	  {	ord = (ch == '.' ? 0 : 1);	/* n/m = D/M or M/D */
X  		if(btoken.tbrk == ch)			/* "NN-" */
X  		  {	if(btoken.tbrkl != ch)
X! 			  {
X! 				atoken = btoken;
X! 				atoken.tcnt++;
X! 				if (ptitoken(&atoken)
X  				  && atoken.tflg == 0
X  				  && atoken.tval.ttmw->wtype == TM_MON)
X  					goto dd2;
X  				if(ord)goto mm2; else goto dd2; /* "NN-" */
X  			  }				/* "-NN-" */
X! 			if (!given(atm->tm_mday)
X! 			  && given(atm->tm_year))	/* If "YYYY-NN-" */
X  				goto mm2;		/* then always MM */
X  			if(ord)goto dd2; else goto mm2;
X  		  }
X  		if(btoken.tbrkl == ch			/* "-NN" */
X! 		  && given(ord ? atm->tm_mon : atm->tm_mday))
X! 			if (!given(ord ? atm->tm_mday : atm->tm_mon)) /* MM/DD */
X  				if(ord)goto dd2; else goto mm2;
X  	  }
X  
X  	/* Now reduced to choice between HH and DD */
X! 	if (given(atm->tm_hour)) goto dd2;	/* Have hour? Assume day. */
X! 	if (given(atm->tm_mday)) goto hh2;	/* Have day? Assume hour. */
X! 	if (given(atm->tm_mon)) goto dd2;	/* Have month? Assume day. */
X  	if(i > 24) goto dd2;			/* Impossible HH means DD */
X! 	atoken = btoken;
X! 	if (!ptitoken(&atoken))			/* Read ahead! */
X  		if(atoken.tval.tnum) return(0); /* ERR: bad token */
X  		else goto dd2;			/* EOF, assume day. */
X! 	if ( atoken.tflg
X! 	   ? !isdigit(*atoken.tcp)
X! 	   : atoken.tval.ttmw->wflgs & TWTIME)
X! 		/* If next token is a time spec, assume hour */
X  		goto hh2;		/* e.g. "3 PM", "11-EDT"  */
X  
X! dd2:	if (ptstash(&atm->tm_mday, i))	/* Store day (1 based) */
X  		return(0);
X! 	continue;
X  
X! mm2:	if (ptstash(&atm->tm_mon, i-1))	/* Store month (make zero based) */
X  		return(0);
X! 	continue;
X  
X! year4:	if ((i-=1900) < 0  ||  ptstash(&atm->tm_year, i)) /* Store year-1900 */
X  		return(0);		/* ERR: year conflict */
X! 	continue;
X  
X  	/* Hack HH:MM[[:]SS] */
X  coltime:
X! 	if (ptstash(&atm->tm_hour, i)) return 0;
X! 	if (!ptitoken(&btoken))
X  		return(!btoken.tval.tnum);
X  	if(!btoken.tflg) return(0);	/* ERR: HH:<alpha> */
X  	if(btoken.tcnt == 4)		/* MMSS */
X! 		if (ptstash(&atm->tm_min, btoken.tval.tnum/100)
X! 		  || ptstash(&atm->tm_sec, btoken.tval.tnum%100))
X  			return(0);
X! 		else continue;
X  	if(btoken.tcnt != 2
X! 	  || ptstash(&atm->tm_min, btoken.tval.tnum))
X  		return(0);		/* ERR: MM bad */
X! 	if (btoken.tbrk != ':') continue;	/* Seconds follow? */
X! coltm2:	if (!ptitoken(&btoken))
X  		return(!btoken.tval.tnum);
X  	if(!btoken.tflg || btoken.tcnt != 2	/* Verify SS */
X! 	  || ptstash(&atm->tm_sec, btoken.tval.tnum))
X  		return(0);		/* ERR: SS bad */
X!     }
X  }
X  
X  /* Store date/time value, return 0 if successful.
X!  * Fail if entry is already set.
X   */
X+ 	static int
X  ptstash(adr,val)
X  int *adr;
X+ int val;
X  {	register int *a;
X! 	if (given(*(a=adr)))
X! 		return 1;
X  	*a = val;
X  	return(0);
X  }
X  
X! /* This subroutine is invoked for AM, PM, NOON and MIDNIGHT when wrapping up
X   * just prior to returning from partime.
X   */
X! 	static int
X! pt12hack(tm, aval)
X! register struct tm *tm;
X! register int aval;
X! {	register int h = tm->tm_hour;
X! 	switch (aval) {
X! 	  case T12_AM:
X! 	  case T12_PM:
X! 		if (h > 12)
X! 			return 0;
X! 		if (h == 12)
X! 			tm->tm_hour = 0;
X! 		if (aval == T12_PM)
X! 			tm->tm_hour += 12;
X! 		break;
X! 	  default:
X! 		if (0 < tm->tm_min  ||  0 < tm->tm_sec)
X! 			return 0;
X! 		if (!given(h) || h==12)
X! 			tm->tm_hour = aval;
X! 		else if (aval==T12_MIDNIGHT  &&  (h==0 || h==24))
X! 			return 0;
X! 	}
X! 	return 1;
X  }
X  
X  /* Get a token and identify it to some degree.
X   * Returns 0 on failure; token.tval will be 0 for normal EOF, otherwise
X   * hit error of some sort
X   */
X  
X! 	static int
X! ptitoken(tkp)
X  register struct token *tkp;
X  {
X! 	register const char *cp;
X! 	register int i, j, k;
X  
X! 	if (!pttoken(tkp))
X  #ifdef DEBUG
X! 	    {
X! 		VOID printf("EOF\n");
X! 		return(0);
X! 	    }
X! #else
X  		return(0);
X+ #endif	
X  	cp = tkp->tcp;
X  
X  #ifdef DEBUG
X! 	VOID printf("Token: \"%.*s\" ", tkp->tcnt, cp);
X! #endif
X  
X+ 	if (tkp->tflg) {
X+ 		i = tkp->tcnt;
X+ 		if (*cp == '+' || *cp == '-') {
X+ 			cp++;
X+ 			i--;
X+ 		}
X+ 		while (0 <= --i) {
X+ 			j = tkp->tval.tnum*10;
X+ 			k = j + (*cp++ - '0');
X+ 			if (j/10 != tkp->tval.tnum  ||  k < j) {
X+ 				/* arithmetic overflow */
X+ 				tkp->tval.tnum = 1;
X+ 				return 0;
X+ 			}
X+ 			tkp->tval.tnum = k;
X+ 		}
X+ 	} else if (!(tkp->tval.ttmw  =  ptmatchstr(cp, tkp->tcnt, tmwords)))
X+ 	  {
X  #ifdef DEBUG
X! 		VOID printf("Not found!\n");
X! #endif
X! 		tkp->tval.tnum = 1;
X! 		return 0;
X  	  }
X  
X  #ifdef DEBUG
X  	if(tkp->tflg)
X  		VOID printf("Val: %d.\n",tkp->tval.tnum);
X! 	else VOID printf("Found: \"%s\", val: %d, type %d\n",
X  		tkp->tval.ttmw->went,tkp->tval.ttmw->wval,tkp->tval.ttmw->wtype);
X! #endif
X  
X  	return(1);
X  }
X  
X  /* Read token from input string into token structure */
X! 	static int
X! pttoken(tkp)
X  register struct token *tkp;
X  {
X! 	register const char *cp;
X  	register int c;
X+ 	const char *astr;
X  
X! 	tkp->tcp = astr = cp = tkp->tcp + tkp->tcnt;
X  	tkp->tbrkl = tkp->tbrk;		/* Set "last break" */
X  	tkp->tcnt = tkp->tbrk = tkp->tflg = 0;
X+ 	tkp->tval.tnum = 0;
X  
X  	while(c = *cp++)
X  	  {	switch(c)
X  		  {	case ' ': case '\t':	/* Flush all whitespace */
X! 			case '\r': case '\n':
X! 			case '\v': case '\f':
X! 				if (!tkp->tcnt) {	/* If no token yet */
X! 					tkp->tcp = cp;	/* ignore the brk */
X! 					continue;	/* and go on. */
X! 				}
X! 				/* fall into */
X  			case '(': case ')':	/* Perhaps any non-alphanum */
X  			case '-': case ',':	/* shd qualify as break? */
X+ 			case '+':
X  			case '/': case ':': case '.':	/* Break chars */
X  				if(tkp->tcnt == 0)	/* If no token yet */
X  				  {	tkp->tcp = cp;	/* ignore the brk */
X***************
X*** 420,476 ****
X  				tkp->tbrk = c;
X  				return(tkp->tcnt);
X  		  }
X! 		if(tkp->tcnt == 0)		/* If first char of token, */
X! 			tkp->tflg = isdigit(c);	/*    determine type */
X! 	  	if(( isdigit(c) &&  tkp->tflg)	/* If not first, make sure */
X! 		 ||(!isdigit(c) && !tkp->tflg))	/*    char matches type */
X! 			tkp->tcnt++;		/* Win, add to token. */
X! 		else {
X! 			cp--;			/* Wrong type, back up */
X  			tkp->tbrk = c;
X! 			return(tkp->tcnt);
X! 		  }
X  	  }
X  	return(tkp->tcnt);		/* When hit EOF */
X  }
X  
X  
X  ptmatchstr(astr,cnt,astruc)
X! char *astr;
X! int cnt;
X! struct tmwent *astruc;
X! {	register char *cp, *mp;
X  	register int c;
X! 	struct tmwent *lastptr;
X! 	struct integ { int word; };   /* For getting at array ptr */
X  	int i;
X  
X  	lastptr = 0;
X! 	for(;mp = (char *)((struct integ *)astruc)->word; astruc += 1)
X  	  {	cp = astr;
X  		for(i = cnt; i > 0; i--)
X! 		  {	switch((c = *cp++) ^ *mp++)	/* XOR the chars */
X  			  {	case 0: continue;	/* Exact match */
X! 				case 040: if(isalpha(c))
X  					continue;
X  			  }
X  			break;
X  		  }
X  		if(i==0)
X! 			if(*mp == 0) return((unsigned int)astruc);    /* Exact match */
X  			else if(lastptr) return(0);	/* Ambig/
X  	  }
X! 	return((unsigned int)lastptr);
X! }
X! 
X! 
X! 
X! zaptime(tp)
X! register int *tp;
X! /* clears tm structure pointed to by tp */
X! {	register int i;
X! 	i = (sizeof (struct tm))/(sizeof (int));
X! 	do *tp++ = TMNULL;		/* Set entry to "unspecified" */
X! 	while(--i);			/* Faster than FOR */
X  }
X--- 610,662 ----
X  				tkp->tbrk = c;
X  				return(tkp->tcnt);
X  		  }
X! 		if (!tkp->tcnt++) {		/* If first char of token, */
X! 			if (isdigit(c)) {
X! 				tkp->tflg = 1;
X! 				if (astr<cp-2 && (cp[-2]=='-'||cp[-2]=='+')) {
X! 					/* timezone is break+sign+digit */
X! 					tkp->tcp--;
X! 					tkp->tcnt++;
X! 				}
X! 			}
X! 		} else if ((isdigit(c)!=0) != tkp->tflg) { /* else check type */
X  			tkp->tbrk = c;
X! 			return --tkp->tcnt;	/* Wrong type, back up */
X! 		}
X  	  }
X  	return(tkp->tcnt);		/* When hit EOF */
X  }
X  
X  
X+ 	static const struct tmwent *
X  ptmatchstr(astr,cnt,astruc)
X! 	const char *astr;
X! 	int cnt;
X! 	const struct tmwent *astruc;
X! {
X! 	register const char *cp, *mp;
X  	register int c;
X! 	const struct tmwent *lastptr;
X  	int i;
X  
X  	lastptr = 0;
X! 	for(;mp = astruc->went; astruc += 1)
X  	  {	cp = astr;
X  		for(i = cnt; i > 0; i--)
X! 		  {
X! 			switch (*cp++ - (c = *mp++))
X  			  {	case 0: continue;	/* Exact match */
X! 				case 'A'-'a':
X! 				    /* `if (ctab[c]==Letter)' in RCS */
X! 				    if (islower(c))
X  					continue;
X  			  }
X  			break;
X  		  }
X  		if(i==0)
X! 			if (!*mp) return astruc;	/* Exact match */
X  			else if(lastptr) return(0);	/* Ambiguous */
X  			else lastptr = astruc;		/* 1st ambig */
X  	  }
X! 	return lastptr;
X  }
Xdiff -c src/patch.c:1.6 src/patch.c:1.6.1.1
X*** src/patch.c:1.6	Wed Feb  6 11:32:13 1991
X--- src/patch.c	Wed Feb  6 11:32:14 1991
X***************
X*** 1,5 ****
X  #ifndef lint
X! static char rcsid[] = "$Id: patch.c,v 1.6 90/02/14 10:01:33 berliner Exp $";
X  #endif !lint
X  
X  /*
X--- 1,5 ----
X  #ifndef lint
X! static char rcsid[] = "$Id: patch.c,v 1.6.1.1 91/01/18 12:18:45 berliner Exp $";
X  #endif !lint
X  
X  /*
X***************
X*** 22,29 ****
X  #include <ctype.h>
X  #include "cvs.h"
X  
X- extern long maketime();
X- 
X  extern char update_dir[];
X  extern DBM *open_module();
X  extern int force_tag_match;
X--- 22,27 ----
X***************
X*** 106,112 ****
X  	error(0, "must specify at least one revision/date!");
X      }
X      if (date1[0] != '\0' && date2[0] != '\0') {
X! 	if (strcmp(date1, date2) >= 0)
X  	    error(0, "second date must come after first date!");
X      }
X      (void) signal(SIGHUP, patch_cleanup);
X--- 104,110 ----
X  	error(0, "must specify at least one revision/date!");
X      }
X      if (date1[0] != '\0' && date2[0] != '\0') {
X! 	if (datecmp(date1, date2) >= 0)
X  	    error(0, "second date must come after first date!");
X      }
X      (void) signal(SIGHUP, patch_cleanup);
X***************
X*** 379,395 ****
X  	    if (*cp && (semi = index(cp, ';')) != NULL) {
X  		ret = 0;
X  		*semi = '\0';
X! 		ftm = &tm;
X! 		zaptime((int *)ftm);
X! 		(void) sscanf(cp, DATEFORM, &ftm->tm_year, &ftm->tm_mon,
X! 			      &ftm->tm_mday, &ftm->tm_hour, &ftm->tm_min,
X! 			      &ftm->tm_sec);
X! 		ftm->tm_mon--;
X! 		revdate = (time_t)maketime(ftm) - 1;
X! 		ftm = localtime(&revdate);
X! 		(void) sprintf(date, DATEFORM, ftm->tm_year, ftm->tm_mon+1,
X! 			       ftm->tm_mday, ftm->tm_hour, ftm->tm_min,
X! 			       ftm->tm_sec);
X  	    }
X  	    break;
X  	}
X--- 377,383 ----
X  	    if (*cp && (semi = index(cp, ';')) != NULL) {
X  		ret = 0;
X  		*semi = '\0';
X! 		semi[-1]--;	/* This works even if semi[-1] was '0'.  */
X  	    }
X  	    break;
X  	}
Xdiff -c src/patchlevel.h:1.1 src/patchlevel.h:1.1.1.1
X*** src/patchlevel.h:1.1	Wed Feb  6 11:32:12 1991
X--- src/patchlevel.h	Wed Feb  6 11:32:12 1991
X***************
X*** 1,3 ****
X! /*	$Id: patchlevel.h,v 1.1 89/11/20 00:06:30 berliner Exp $	*/
X  
X! #define	PATCHLEVEL	0
X--- 1,3 ----
X! /*	$Id: patchlevel.h,v 1.1.1.1 91/01/18 12:19:46 berliner Exp $	*/
X  
X! #define	PATCHLEVEL	2
Xdiff -c src/rcstime.h:1.1 src/rcstime.h:removed
X*** src/rcstime.h:1.1	Wed Feb  6 11:32:08 1991
X--- src/rcstime.h	Wed Feb  6 11:32:08 1991
X***************
X*** 1,42 ****
X- #define TIMEID "$Id: rcstime.h,v 1.1 89/05/09 11:51:03 berliner Exp $"
X- 
X- /* Structure for use by time manipulating subroutines.
X-  * The following library routines use it:
X-  *	libc: ctime, localtime, gmtime, asctime
X-  *	libcx: partime, maketime (may not be installed yet)
X-  */
X- 
X- struct tm {     /* See defines below for allowable ranges */
X- 	int tm_sec;
X- 	int tm_min;
X- 	int tm_hour;
X- 	int tm_mday;
X- 	int tm_mon;
X- 	int tm_year;
X- 	int tm_wday;
X- 	int tm_yday;
X- 	int tm_isdst;
X- 	int tm_zon;	/* NEW: mins westward of Greenwich */
X- 	int tm_ampm;	/* NEW: 1 if AM, 2 if PM */
X- };
X- 
X- #define LCLZONE (5*60)	/* Until V7 ftime(2) works, this defines local zone*/
X- #define TMNULL (-1)	/* Items not specified are given this value
X- 			 * in order to distinguish null specs from zero
X- 			 * specs.  This is only used by partime and
X- 			 * maketime. */
X- 
X- 	/* Indices into TM structure */
X- #define TM_SEC 0	/* 0-59			*/
X- #define TM_MIN 1	/* 0-59			*/
X- #define TM_HOUR 2	/* 0-23			*/
X- #define TM_MDAY 3	/* 1-31			day of month */
X- #define TM_DAY TM_MDAY	/*  "			synonym      */
X- #define TM_MON 4	/* 0-11			*/
X- #define TM_YEAR 5	/* (year-1900) (year)	*/
X- #define TM_WDAY 6	/* 0-6			day of week (0 = Sunday) */
X- #define TM_YDAY 7	/* 0-365		day of year */
X- #define TM_ISDST 8	/* 0 Std, 1 DST		*/
X- 	/* New stuff */
X- #define TM_ZON 9	/* 0-(24*60) minutes west of Greenwich */
X- #define TM_AMPM 10	/* 1 AM, 2 PM		*/
X--- 0 ----
Xdiff -c src/subr.c:1.14 src/subr.c:1.14.1.2
X*** src/subr.c:1.14	Wed Feb  6 11:32:11 1991
X--- src/subr.c	Wed Feb  6 11:32:11 1991
X***************
X*** 1,5 ****
X  #ifndef lint
X! static char rcsid[] = "$Id: subr.c,v 1.14 89/11/20 09:51:10 berliner Exp $";
X  #endif !lint
X  
X  /*
X--- 1,5 ----
X  #ifndef lint
X! static char rcsid[] = "$Id: subr.c,v 1.14.1.2 91/01/29 19:46:20 berliner Exp $";
X  #endif !lint
X  
X  /*
X***************
X*** 114,120 ****
X  
X      if (stat(file, &sb) < 0)
X  	return (0);
X!     return ((sb.st_mode & S_IFMT) & S_IFDIR);
X  }
X  
X  /*
X--- 114,120 ----
X  
X      if (stat(file, &sb) < 0)
X  	return (0);
X!     return ((sb.st_mode & S_IFMT) == S_IFDIR);
X  }
X  
X  /*
X***************
X*** 125,133 ****
X  {
X      struct stat sb;
X  
X      if (lstat(file, &sb) < 0)
X  	return (0);
X!     return ((sb.st_mode & S_IFMT) & S_IFLNK);
X  }
X  
X  /*
X--- 125,137 ----
X  {
X      struct stat sb;
X  
X+ #ifdef S_IFLNK
X      if (lstat(file, &sb) < 0)
X  	return (0);
X!     return ((sb.st_mode & S_IFMT) == S_IFLNK);
X! #else
X!     return (0);
X! #endif
X  }
X  
X  /*
Xdiff -c src/tag.c:1.19 src/tag.c:1.19.1.2
X*** src/tag.c:1.19	Wed Feb  6 11:32:10 1991
X--- src/tag.c	Wed Feb  6 11:32:10 1991
X***************
X*** 1,5 ****
X  #ifndef lint
X! static char rcsid[] = "$Id: tag.c,v 1.19 89/11/19 23:40:46 berliner Exp $";
X  #endif !lint
X  
X  /*
X--- 1,5 ----
X  #ifndef lint
X! static char rcsid[] = "$Id: tag.c,v 1.19.1.2 91/01/29 19:45:54 berliner Exp $";
X  #endif !lint
X  
X  /*
X***************
X*** 180,185 ****
X--- 180,205 ----
X  {
X      char version[50];
X  
X+ #ifdef S_IFLNK
X+     /*
X+      * Ooops..  if there is a symbolic link in the source repository
X+      * which points to a normal file, rcs will do its file renaming
X+      * mumbo-jumbo and blow away the symbolic link; this is essentially
X+      * like a copy-on-commit RCS revision control file, but I consider
X+      * it a bug.  Instead, read the contents of the link and recursively
X+      * tag the link contents (which may be a symlink itself...).
X+      */
X+     if (islink(rcs) && isfile(rcs)) {
X+ 	char link_name[MAXPATHLEN];
X+ 	int count;
X+ 
X+ 	if ((count = readlink(rcs, link_name, sizeof(link_name))) != -1) {
X+ 	    link_name[count] = '\0';
X+ 	    return (tag_file(link_name));
X+ 	}
X+     }
X+ #endif
X+ 
X      if (delete) {
X  	/*
X  	 * If -d is specified, "force_tag_match" is set, so that this call
X***************
X*** 210,220 ****
X      }
X      Version_Number(rcs, numtag, Date, version);
X      if (version[0] == '\0') {
X! 	if (!really_quiet) {
X  	    warn(0, "cannot find tag '%s' for %s", numtag[0] ? numtag : "head",
X  		 rcs);
X  	}
X! 	return (1);
X      }
X      if (isdigit(numtag[0]) && strcmp(numtag, version) != 0) {
X  	/*
X--- 230,241 ----
X      }
X      Version_Number(rcs, numtag, Date, version);
X      if (version[0] == '\0') {
X! 	if (!quiet) {
X  	    warn(0, "cannot find tag '%s' for %s", numtag[0] ? numtag : "head",
X  		 rcs);
X+ 	    return (1);
X  	}
X! 	return (0);
X      }
X      if (isdigit(numtag[0]) && strcmp(numtag, version) != 0) {
X  	/*
Xdiff -c src/update.c:1.27 src/update.c:1.27.1.2
X*** src/update.c:1.27	Wed Feb  6 11:32:16 1991
X--- src/update.c	Wed Feb  6 11:32:16 1991
X***************
X*** 1,5 ****
X  #ifndef lint
X! static char rcsid[] = "$Id: update.c,v 1.27 89/11/19 23:40:48 berliner Exp $";
X  #endif !lint
X  
X  /*
X--- 1,5 ----
X  #ifndef lint
X! static char rcsid[] = "$Id: update.c,v 1.27.1.2 91/02/06 18:30:07 berliner Exp $";
X  #endif !lint
X  
X  /*
X***************
X*** 111,117 ****
X      if (!isdir(CVSADM)) {
X  	if (!quiet)
X  	    warn(0, "warning: no %s directory found", CVSADM);
X! 	err += update_descend(update_recursive);
X  	return (err);
X      }
X      Name_Repository();
X--- 111,132 ----
X      if (!isdir(CVSADM)) {
X  	if (!quiet)
X  	    warn(0, "warning: no %s directory found", CVSADM);
X! 	if (argc <= 0) {
X! 	    err += update_descend(update_recursive);
X! 	} else {
X! 	    int i;
X! 
X! 	    for (i = 0; i < argc; i++) {
X! 		if (isdir(argv[i])) {
X! 		    (void) strcat(Dlist, " ");
X! 		    (void) strcat(Dlist, argv[i]);
X! 		} else {
X! 		    warn(0, "nothing known about %s", argv[i]);
X! 		    err++;
X! 		}
X! 	    }
X! 	    err += update_process_lists();
X! 	}
X  	return (err);
X      }
X      Name_Repository();
X***************
X*** 175,180 ****
X--- 190,196 ----
X  	update_Files = 1;
X  	(void) strcpy(User, cp);
X  	Scratch_Entry(User);
X+ 	(void) unlink(User);
X      }
X      /*
X       * Olist is the "needs checking out" list.
X***************
X*** 349,359 ****
X  		strcmp(dp->d_name, CVSLCK) == 0)
X  		continue;
X  	    (void) sprintf(fname, "%s/%s", Repository, dp->d_name);
X  	    if (!isdir(fname))
X  		continue;
X! 	    if (isdir(dp->d_name))
X  		continue;
X! 	    if (isfile(dp->d_name)) {
X  		warn(0, "file %s should be a directory; please move it", dp->d_name);
X  		err++;
X  	    } else {
X--- 365,376 ----
X  		strcmp(dp->d_name, CVSLCK) == 0)
X  		continue;
X  	    (void) sprintf(fname, "%s/%s", Repository, dp->d_name);
X+ 	    (void) sprintf(tmp, "%s/%s", dp->d_name, CVSADM);
X  	    if (!isdir(fname))
X  		continue;
X! 	    if (islink(dp->d_name) || isdir(tmp))
X  		continue;
X! 	    if (!isdir(dp->d_name) && isfile(dp->d_name)) {
X  		warn(0, "file %s should be a directory; please move it", dp->d_name);
X  		err++;
X  	    } else {
Xdiff -c src/version_number.c:1.16 src/version_number.c:1.16.1.2
X*** src/version_number.c:1.16	Wed Feb  6 11:32:09 1991
X--- src/version_number.c	Wed Feb  6 11:32:09 1991
X***************
X*** 1,5 ****
X  #ifndef lint
X! static char rcsid[] = "$Id: version_number.c,v 1.16 89/11/19 23:20:35 berliner Exp $";
X  #endif !lint
X  
X  /*
X--- 1,5 ----
X  #ifndef lint
X! static char rcsid[] = "$Id: version_number.c,v 1.16.1.2 91/01/29 07:20:26 berliner Exp $";
X  #endif !lint
X  
X  /*
X***************
X*** 67,72 ****
X--- 67,73 ----
X  		(void) strcpy(vers, rev);
X  	    }
X  	} else {
X+ 	    if (!force_tag_match)
X  		(void) strcpy(vers, rev);
X  	}
X      }
X***************
X*** 100,105 ****
X--- 101,107 ----
X      if (fgets(line, sizeof(line), fp) == NULL)
X  	return;
X      if (strncmp(line, RCSHEAD, sizeof(RCSHEAD) - 1) != 0 ||
X+ 	!isspace(line[sizeof(RCSHEAD) - 1]) ||
X  	(cp = rindex(line, ';')) == NULL)
X  	return;
X      *cp = '\0';				/* strip the ';' */
X***************
X*** 119,124 ****
X--- 121,127 ----
X      if (fgets(line, sizeof(line), fp) == NULL)
X  	return;
X      if (strncmp(line, RCSBRANCH, sizeof(RCSBRANCH) - 1) == 0 &&
X+ 	isspace(line[sizeof(RCSBRANCH) - 1]) &&
X  	(cp = rindex(line, ';')) != NULL) {
X  	*cp = '\0';			/* strip the ';' */
X  	if ((cp = rindex(line, ' ')) == NULL &&
X***************
X*** 149,156 ****
X       * the highest numbered branch off "rev", if necessary.
X       */
X      get_branch(fp, rev);
X!     if (tag[0] == '\0' || isdigit(tag[0]) || symtag_matched < 0)
X! 	(void) strcpy(vers, rev);
X  }
X  
X  /*
X--- 152,161 ----
X       * the highest numbered branch off "rev", if necessary.
X       */
X      get_branch(fp, rev);
X!     if (tag[0] == '\0' || isdigit(tag[0]) || symtag_matched < 0) {
X! 	if ((numdots(rev) & 1) != 0)
X! 	    (void) strcpy(vers, rev);
X!     }
X  }
X  
X  /*
X***************
X*** 172,196 ****
X      char *rev;
X      char *vers;
X  {
X!     char line[MAXLINELEN], tagdot[50];
X      char *cp, *cprev;
X-     int tagdots, tagdotlen;
X  
X      if (isdigit(tag[0])) {
X! 	while (tag[strlen(tag)] == '.')
X! 	    tag[strlen(tag)] = '\0';	/* strip trailing dots */
X! 	(void) sprintf(tagdot, "%s.", tag);
X! 	tagdotlen = strlen(tagdot);
X! 	tagdots = numdots(tag);
X      }
X      while (fgets(line, sizeof(line), fp) != NULL) {
X  	if (strncmp(line, RCSDESC, sizeof(RCSDESC) - 1) == 0) {
X- 	    /*
X- 	     * Use head, or a partial branch match found with the strncmp
X- 	     * call with tagdot below
X- 	     */
X  	    rewind(fp);
X! 	    return (1);
X  	}
X  	/*
X  	 * For numeric tags, the RCS file contains the revision
X--- 177,197 ----
X      char *rev;
X      char *vers;
X  {
X!     char line[MAXLINELEN];
X      char *cp, *cprev;
X  
X      if (isdigit(tag[0])) {
X! 	while (tag[strlen(tag)-1] == '.')
X! 	    tag[strlen(tag)-1] = '\0';	/* strip trailing dots */
X! 	if ((numdots(tag) & 1) == 0) {
X! 	    (void) strcpy(rev, tag);
X! 	    return (1);			/* let get_branch() figure it out */
X! 	}
X      }
X      while (fgets(line, sizeof(line), fp) != NULL) {
X  	if (strncmp(line, RCSDESC, sizeof(RCSDESC) - 1) == 0) {
X  	    rewind(fp);
X! 	    return (1);			/* use head */
X  	}
X  	/*
X  	 * For numeric tags, the RCS file contains the revision
X***************
X*** 204,221 ****
X  		(void) strcpy(vers, line);
X  		return (0);		/* a match for a numeric tag */
X  	    }
X- 	    if (strncmp(tagdot, line, tagdotlen) == 0) {
X- 		if ((tagdots & 1) == 0 && numdots(line) == tagdots+1)
X- 		    (void) strcpy(rev, line);
X- 	    }
X  	    continue;
X  	}
X  	if (strncmp(line, RCSSYMBOL, sizeof(RCSSYMBOL)-1)!=0 ||
X! 	    (cp = rindex(line, ';')) == NULL)
X! 	    continue;
X! 	*cp = ' ';			/* strip the ';' */
X! 	if ((cp = index(line, ' ')) == NULL &&
X! 	    (cp = index(line, '\t')) == NULL)
X  	    continue;
X  	/*
X  	 * A rather ugly loop to process the "symbols" line.  I would
X--- 205,214 ----
X  		(void) strcpy(vers, line);
X  		return (0);		/* a match for a numeric tag */
X  	    }
X  	    continue;
X  	}
X  	if (strncmp(line, RCSSYMBOL, sizeof(RCSSYMBOL)-1)!=0 ||
X! 	    !isspace(line[sizeof(RCSSYMBOL) - 1]))
X  	    continue;
X  	/*
X  	 * A rather ugly loop to process the "symbols" line.  I would
X***************
X*** 222,233 ****
X  	 * really rather use strtok(), but other above me already are,
X  	 * and strtok() blows up in this case.
X  	 */
X! 	while (cp && *cp) {
X  	    while (isspace(*cp))
X  		cp++;
X  	    /* symbols and revisions are separated by a colon */
X  	    if ((cprev = index(cp, ':')) == NULL) {
X! 		while (*cp && !isspace(*cp))
X  		    cp++;
X  		continue;
X  	    }
X--- 215,234 ----
X  	 * really rather use strtok(), but other above me already are,
X  	 * and strtok() blows up in this case.
X  	 */
X! 	for (cp = line + sizeof(RCSSYMBOL);  cp;  ) {
X  	    while (isspace(*cp))
X  		cp++;
X+ 	    if (*cp == ';')
X+ 		break;
X+ 	    if (!*cp) {
X+     		if (fgets(line, sizeof(line), fp) == NULL)
X+ 		    return 0;
X+ 		cp = line;
X+ 		continue;
X+ 	    }
X  	    /* symbols and revisions are separated by a colon */
X  	    if ((cprev = index(cp, ':')) == NULL) {
X! 		while (*cp && !isspace(*cp) && *cp!=';')
X  		    cp++;
X  		continue;
X  	    }
X***************
X*** 245,253 ****
X  		(void) strcpy(rev, cprev);
X  		return (-1);		/* look for branches off rev */
X  	    } else {
X! 		while (!isspace(*cp))
X  		    cp++;
X- 		cp++;
X  	    }
X  	}
X  	return (1);
X--- 246,253 ----
X  		(void) strcpy(rev, cprev);
X  		return (-1);		/* look for branches off rev */
X  	    } else {
X! 		while (!isspace(*cp) && *cp!=';')
X  		    cp++;
X  	    }
X  	}
X  	return (1);
X***************
X*** 282,288 ****
X  		*cp = '\0';		/* strip the newline */
X  	    if (numdots(line) == dots+1 &&
X  		strncmp(line, branch, len) == 0) {
X! 		if (strcmp(branch, line) <= 0)
X  		    (void) strcpy(rev, line);
X  	    }
X  	}
X--- 282,288 ----
X  		*cp = '\0';		/* strip the newline */
X  	    if (numdots(line) == dots+1 &&
X  		strncmp(line, branch, len) == 0) {
X! 		if ((numdots(rev) & 1) == 0 || strcmp(rev, line) <= 0)
X  		    (void) strcpy(rev, line);
X  	    }
X  	}
X***************
X*** 342,348 ****
X      char *cp, *semi;
X  
X      last_rev[0] = '\0';
X!     (void) strcpy(curdate, "00");	/* what happens at 2000 ad? */
X      (void) sprintf(date_dot, "%s.", rev);
X      date_dotlen = strlen(date_dot);
X      date_dots = numdots(rev);
X--- 342,348 ----
X      char *cp, *semi;
X  
X      last_rev[0] = '\0';
X!     curdate[0] = '\0';
X      (void) sprintf(date_dot, "%s.", rev);
X      date_dotlen = strlen(date_dot);
X      date_dots = numdots(rev);
X***************
X*** 360,365 ****
X--- 360,366 ----
X  	    continue;
X  	}
X  	if (strncmp(line, RCSDATE, sizeof(RCSDATE) - 1) == 0 &&
X+ 	    isspace(line[sizeof(RCSDATE) - 1]) &&
X  	    last_rev[0] != '\0') {
X  	    for (cp = line; *cp && !isspace(*cp); cp++)
X  		;
X***************
X*** 367,373 ****
X  		cp++;
X  	    if (*cp && (semi = index(cp, ';')) != NULL) {
X  		*semi = '\0';		/* strip the semicolon */
X! 		if (strcmp(cp, date) <= 0 && strcmp(cp, curdate) >= 0) {
X  		    (void) strcpy(curdate, cp);
X  		    (void) strcpy(version, last_rev);
X  		}
X--- 368,374 ----
X  		cp++;
X  	    if (*cp && (semi = index(cp, ';')) != NULL) {
X  		*semi = '\0';		/* strip the semicolon */
X! 		if (datecmp(cp, date) <= 0 && datecmp(cp, curdate) >= 0) {
X  		    (void) strcpy(curdate, cp);
X  		    (void) strcpy(version, last_rev);
X  		}
X***************
X*** 374,377 ****
X--- 375,391 ----
X  	    }
X  	}
X      }
X+ }
X+ 
X+ /*
X+  * Compare two dates in RCS format.
X+  * Beware the change in format on January 1, 2000,
X+  * when years go from 2-digit to full format.
X+  */
X+ int
X+ datecmp(date1, date2)
X+     char *date1, *date2;
X+ {
X+     int length_diff = strlen(date1) - strlen(date2);
X+     return length_diff ? length_diff : strcmp(date1, date2);
X  }
X
END_OF_FILE
  if test 48942 -ne `wc -c <'Patch02.02'`; then
    echo shar: \"'Patch02.02'\" unpacked with wrong size!
  fi
  # end of 'Patch02.02'
fi
echo shar: End of archive 2 \(of 2\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked both archives.
    rm -f ark[1-9]isdone
else
    echo You still must unpack the following archives:
    echo "        " ${MISSING}
fi
exit 0
exit 0 # Just in case...
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.