Path: tut!draken!kth!enea!mcvax!hp4nl!botter!star.cs.vu.nl!ast
From: ast@cs.vu.nl (Andy Tanenbaum)
Newsgroups: comp.os.minix
Subject: Re: commands/date.c bug + fix
Message-ID: <1855@ast.cs.vu.nl>
Date: 3 Jan 89 20:54:24 GMT
References: <321@cstw01.UUCP>
Reply-To: ast@cs.vu.nl (Andy Tanenbaum)
Organization: VU Informatica, Amsterdam
Lines: 256

In article <321@cstw01.UUCP> meulenbr@cst.UUCP () writes:
>Happy New Year with much minix!
>
>As probably all people dedicated to minix have noticed there is a bug in
>the date program from minix (at least in the ST version, but I think
>that it appears in the PC version as well).

The bug was discovered and fixed after MINIX-ST went to press, but it has
been fixed in 1.3.  In the interest of keeping date-ST == date-PC, here is
date-PC etc.

Andy Tanenbaum

: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
: --------------------------- cut here --------------------------
PATH=/bin:/usr/bin:/usr/ucb
echo Extracting '/local/ast/minix/tape3/commands/date.c'
sed 's/^X//' > '/local/ast/minix/tape3/commands/date.c' << '+ END-OF-FILE ''/local/ast/minix/tape3/commands/date.c'
X/* date - print or set time and date		Author: Jan Looyen */
X
X#include <stdio.h>
X#include <time.h>
X
X#define	MIN	60L		/* # seconds in a minute */
X#define	HOUR	(60 * MIN)	/* # seconds in an hour */
X#define	DAY	(24 * HOUR)	/* # seconds in a day */
X#define	YEAR	(365 * DAY)	/* # seconds in a year */
X
Xchar *ctime();
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X  int qflag;
X  long t, time();
X  char time_buf[15];
X
X  if (argc  > 2) usage();
X  if (argc == 2) {
X	if (*argv[1] == '-' && (argv[1][1] | 0x60) == 'q') {
X		freopen(stdin, "/dev/tty0", "r");
X		printf("\nPlease enter date: MMDDYYhhmmss. Then hit RETURN.\n");
X		gets(time_buf);
X		set_time(time_buf);
X	}
X	else
X		set_time(argv[1]);
X  }
X  time(&t);
X  printf("%s", ctime(&t)); 
X  exit(0);
X}
X
X
Xset_time(t)
Xchar *t;
X{
X  char *tp;
X  long ct, time();
X  int len;
X  static int days_per_month[] = {
X	  31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
X  };
X  struct tm *p, *localtime();
X
X  time(&ct);
X  p = localtime(&ct);
X  p->tm_year -= 1970;
X  p->tm_mon++;
X  len = strlen(t);
X  if (len != 12 && len != 10 && len != 6 && len != 4) usage();
X  tp = t;
X  while (*tp)
X	if (!isdigit(*tp++))
X		bad();
X  if (len == 6 || len == 12) 
X  	p->tm_sec = conv(&tp, 59);
X  p->tm_min = conv(&tp, 59);
X  p->tm_hour = conv(&tp, 23);
X  if (len == 12 || len == 10) {
X  	p->tm_year = conv(&tp, 99);
X  	p->tm_mday = conv(&tp, 31);
X  	p->tm_mon = conv(&tp, 12);
X  	p->tm_year -= 70;
X	if (p->tm_year < 0)
X		p->tm_year += 100;
X  }
X  ct = p->tm_year * YEAR;
X  ct += ((p->tm_year + 1) / 4) * DAY;
X  days_per_month[1] = 28;
X  if (((p->tm_year + 2) % 4) == 0)
X	days_per_month[1]++;
X  len = 0;
X  p->tm_mon--;
X  while (len < p->tm_mon)
X	ct += days_per_month[len++] * DAY;
X  ct += --p->tm_mday * DAY;
X  ct += p->tm_hour * HOUR;
X  ct += p->tm_min * MIN;
X  ct += p->tm_sec;
X  if (stime(&ct))
X	fprintf(stderr, "Set date not allowed\n");
X}
X
Xconv(ptr, max)
Xchar **ptr;
Xint max;
X{
X  int buf;
X
X  *ptr -=2;
X  buf = atoi(*ptr);
X  **ptr = 0;
X  if (buf < 0 || buf > max)
X	bad();
X  return(buf);
X}
X
Xbad()
X{
X  fprintf(stderr, "Date: bad conversion\n");
X  exit(1);
X}
X
Xusage()
X{
X  fprintf(stderr, "Usage: date [-q] [[MMDDYY]hhmm[ss]]\n");
X  exit(1);
X}
X
Xisdigit(c)
Xchar c;
X{
X  if (c >= '0' && c <= '9')
X	return(1);
X  else
X	return(0);
X}
+ END-OF-FILE /local/ast/minix/tape3/commands/date.c
chmod 'u=r,g=r,o=r' '/local/ast/minix/tape3/commands/date.c'
set `wc -c '/local/ast/minix/tape3/commands/date.c'`
count=$1
case $count in
2223)	:;;
*)	echo 'Bad character count in ''/local/ast/minix/tape3/commands/date.c' >&2
		echo 'Count should be 2223' >&2
esac
echo Extracting '/local/ast/minix/tape3/lib/ctime.c'
sed 's/^X//' > '/local/ast/minix/tape3/lib/ctime.c' << '+ END-OF-FILE ''/local/ast/minix/tape3/lib/ctime.c'
X#include <time.h>
X
Xstatic int days_per_month[] = {
X	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
X};
Xstatic char *months[] = { 
X	"Jan", "Feb", "Mar", "Apr", "May", "Jun",
X	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
X};
Xstatic char *days[] = {
X	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
X};
X
X#define	MIN	60L		/* # seconds in a minute */
X#define	HOUR	(60 * MIN)	/* # seconds in an hour */
X#define	DAY	(24 * HOUR)	/* # seconds in a day */
X#define	YEAR	(365 * DAY)	/* # seconds in a year */
X
Xstatic struct tm tm;
Xstatic char buf[26];
X
Xchar *ctime(pt)
Xlong *pt;
X{
X	register long t = *pt;
X
X	long year;
X
X	tm.tm_year = 0;
X	tm.tm_mon = 0;
X	tm.tm_mday = 1;
X	tm.tm_hour = 0;
X	tm.tm_min = 0;
X	tm.tm_sec = 0;
X
X	/* t is elapsed time in seconds since Jan 1, 1970. */
X	tm.tm_wday = (int) (t/DAY + 4L) % 7;	/* Jan 1, 1970 is 4th wday */
X	while (t >= (year=((tm.tm_year%4)==2) ? YEAR+DAY : YEAR)) {
X		tm.tm_year += 1;
X		t -= year;
X	}
X	tm.tm_year += 1970;
X
X	/* t is now the offset into the current year, in seconds. */
X	tm.tm_yday = (t/DAY);		/* day # of the year, Jan 1 = 0 */
X
X	days_per_month[1] = 28;
X	if ((tm.tm_year % 4) == 0)	/* check for leap year */
X		days_per_month[1]++;
X
X	/* Compute month. */
X	while (t >= (days_per_month[tm.tm_mon] * DAY))
X		t -= days_per_month[tm.tm_mon++] * DAY;
X
X	/* Month established, now compute day of the month */
X	while (t >= DAY) {
X		t -= DAY;
X		tm.tm_mday++;
X	}
X
X	/* Day established, now do hour. */
X	while (t >= HOUR) {
X		t -= HOUR;
X		tm.tm_hour++;
X	}
X
X	/* Hour established, now do minute. */
X	while (t >= MIN) {
X		t -= MIN;
X		tm.tm_min++;
X	}
X
X	/* Residual time is # seconds. */
X	tm.tm_sec = (int) t;
X
X	/* Generate output in ASCII in buf. */
X	sprintf(buf, "%s %s %2d %02d:%02d:%02d %d\n",
X		days[tm.tm_wday], months[tm.tm_mon],
X		tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_year); 
X	return buf;
X}
X
Xstruct tm *localtime(pt)
Xlong *pt;
X{
X  ctime(pt);
X  return &tm;
X}
X
Xstruct tm *gmtime(pt)
Xlong *pt;
X{
X  ctime(pt);
X  return &tm;
X}
+ END-OF-FILE /local/ast/minix/tape3/lib/ctime.c
chmod 'u=r,g=r,o=r' '/local/ast/minix/tape3/lib/ctime.c'
set `wc -c '/local/ast/minix/tape3/lib/ctime.c'`
count=$1
case $count in
1960)	:;;
*)	echo 'Bad character count in ''/local/ast/minix/tape3/lib/ctime.c' >&2
		echo 'Count should be 1960' >&2
esac
exit 0
