[comp.os.minix] commands/date.c bug + fix

meulenbr@cstw01.UUCP (Frans Meulenbroeks) (01/02/89)

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 problem is that date does not work properly on 12/31 on leap years.
(like 12/31/88). This is due to a bug in the cv_time module.
The (untested) shar at the end cures this problem.

I got also a bug report that cc would not work properly on this day.
I have not been able to verify this. The person who told me about this,
said that it happened on an ST. I'm unsure if this happens on a PC as
well.

Something unrelated:
Is someone aware of a PD SCCS/RCS clone/alternative?
Any pointers would be appreciated greatly.

Frans (.sig at end)

#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	date.cdiff
# This archive created: Mon Jan  2 09:51:45 1989
sed 's/^X//' << \SHAR_EOF > date.cdiff
X*** date.c.orig	Mon Jan  2 09:46:53 1989
X--- date.c	Mon Jan  2 09:47:48 1989
X*************** long t
X*** 65,72 ****
X    while (t >= s_p_year) {
X  	if (((tm.year + 2) % 4) == 0)
X  		t -= s_p_day;
X! 	tm.year += 1;
X! 	t -= s_p_year;
X    }
X    if (((tm.year + 2) % 4) == 0)
X  	days_per_month[1]++;
X--- 65,74 ----
X    while (t >= s_p_year) {
X  	if (((tm.year + 2) % 4) == 0)
X  		t -= s_p_day;
X!   	if (t >= s_p_year) {
X! 		tm.year += 1;
X! 		t -= s_p_year;
X! 	}
X    }
X    if (((tm.year + 2) % 4) == 0)
X  	days_per_month[1]++;
SHAR_EOF
#	End of shell archive
exit 0
-- 
Frans Meulenbroeks        (meulenbr@cst.prl.philips.nl)
	Centre for Software Technology
	( or try: ...!mcvax!philmds!prle!cst!meulenbr)

meulenbr@cst.UUCP (Frans Meulenbroeks) (01/03/89)

Oops I goofed. As I said I sent an untested shar. Well I learned to do
this never again. I've canceled the original article. Here is it again
but now with a proper and tested fix. Sorry, Frans.

>Happy New Year with much minix!
>
>As probably all people dedicated to minix have noticed there is a bug in
		meant was: addicted
>the date program from minix (at least in the ST version, but I think
>that it appears in the PC version as well).
>
>The problem is that date does not work properly on 12/31 on leap years.
>(like 12/31/88). This is due to a bug in the cv_time module.
>The (untested) shar at the end cures this problem.
now it is tested, and it works
>
>I got also a bug report that cc would not work properly on this day.
>I have not been able to verify this. The person who told me about this,
>said that it happened on an ST. I'm unsure if this happens on a PC as
>well.

I could repeat this. /usr/lib/cem crashes with signal 11.
This only happens on 12/31 on leap years. No explanation. No fix, since
I do not have source from cem. Perhaps the same problem as above.
Perhaps this problem only exist in Minix/ST.
>
>Something unrelated:
>Is someone aware of a PD SCCS/RCS clone/alternative?
>Any pointers would be appreciated greatly.
>
>Frans (.sig at end)
>
#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
-----cut here-----cut here-----cut here-----cut here-----
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	date.cdiff
# This archive created: Mon Jan  2 19:28:48 1989
sed 's/^X//' << \SHAR_EOF > date.cdiff
X*** date.c.orig	Tue Sep  6 21:30:13 1988
X--- date.c	Sat Dec 31 12:43:35 1988
X***************
X*** 63,70 ****
X    tm.min = 0;
X    tm.sec = 0;
X    while (t >= s_p_year) {
X! 	if (((tm.year + 2) % 4) == 0)
X! 		t -= s_p_day;
X  	tm.year += 1;
X  	t -= s_p_year;
X    }
X--- 63,75 ----
X    tm.min = 0;
X    tm.sec = 0;
X    while (t >= s_p_year) {
X! 	if (((tm.year + 2) % 4) == 0) 
X! 	{
X! 		if (t >= s_p_year + s_p_day) {
X! 			t -= s_p_day;
X! 		}
X! 		else break; /* 12/3 in a leap year */
X! 	}
X  	tm.year += 1;
X  	t -= s_p_year;
X    }
SHAR_EOF
#	End of shell archive
exit 0
-- 
Frans Meulenbroeks        (meulenbr@cst.prl.philips.nl)
	Centre for Software Technology
	( or try: ...!mcvax!philmds!prle!cst!meulenbr)

ast@cs.vu.nl (Andy Tanenbaum) (01/04/89)

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

ast@cs.vu.nl (Andy Tanenbaum) (01/04/89)

In article <321@cstw01.UUCP> meulenbr@cst.UUCP () writes:
>Happy New Year with much minix!

Indeed.  On my system this was message number 4000.  I am not sure if we
have gotten all of them, but 4000 messages from all over the world in < 2 years
is a milestone of sorts.  Unlike many newsgroups, I regard the signal to noise
ratio of this group as being quite good.  If we can just keep the PDP-11/45
memory management unit from rearing its ugly head in 1989, we'll be in good 
shape.

Andy Tanenbaum (ast@cs.vu.nl)

ncoverby@ndsuvax.UUCP (Glen Overby) (01/04/89)

In article <324@cst.UUCP> meulenbr@cst.UUCP (Frans Meulenbroeks) writes:
>Oops I goofed. As I said I sent an untested shar. Well I learned to do
>this never again.

I hope so.  Getting untested bug fixes scares me; there is no way that you
can truly say that the purported bugs are fixed.  Or that the "fix" didn't
break something else.  So far I haven't noticed any real problems with
this.  We've been lucky.

Another thing I find lacking in this group which I enjoy from
comp.sources.bugs and comp.bugs.{4bsd,sysv,...} is an explanation of what
the bug is and how to duplicate it.  I like to know WHAT is wrong so I can
be on the lookout for any other problems like it.

>>I got also a bug report that cc would not work properly on this day.
>>I have not been able to verify this. The person who told me about this,
>>said that it happened on an ST. I'm unsure if this happens on a PC as
>>well.

>I could repeat this. /usr/lib/cem crashes with signal 11.
>This only happens on 12/31 on leap years. No explanation. No fix, since
>I do not have source from cem. Perhaps the same problem as above.
>Perhaps this problem only exist in Minix/ST.

I burned a LOT of CPU time on the 31st compiling under Minix-PC ("1.3d" with
1.2 compiler binaries) and did not encounter any compiler crashes.  Not all
of the output code worked, but that was my fault :-)

>>Something unrelated:
>>Is someone aware of a PD SCCS/RCS clone/alternative?
>>Any pointers would be appreciated greatly.

Why an RCS clone?  You can get the real thing from arthur.cs.purdue.edu via
anonymous FTP, and GNU has a diff3.  I haven't tried putting the two
together under Minix (I keep all my RCS stuff on a VAX).

Glen Overby     ncoverby@plains.nodak.edu
uunet!ndsuvax!ncoverby
ncoverby@ndsuvax (Bitnet)