[comp.os.minix] Minix ctime/localtime replacement

housel@ea.ecn.purdue.edu (Peter S. Housel) (01/16/88)

	Minix 1.1 had no ctime routine at all; the 1.2 updates included
a ctime.c file which 1) only understood Netherlands Daylight Savings Time
and 2) wouldn't work for lack of asctime() and ftime() routines. The first
is easy. The second, done correctly, is supposed to be a system call. The
problem of adding such a call, and maintaing the time zone information
it is supposed to return, I deemed "not a good idea."

	Also, as a purist, it bothered me to be entering local times when the
system asked for a date, and knowing that the system really wanted a GMT
time.

	The public-domain table-driven localtime package seems to be a good
solution. In addition to being smart enough to handle almost any sort of
timezone/savings time variation imaginable (fitting in well with the
international nature of Minix), it appears to be emerging as a new standard.
(I say this based on the evidence of only two Unix distributions, but one
is BSD 4.3-Plus).

	The following are mainly diffs for the comp.sources.unix distribution
of these routines, and a version of date.c which is compatible with them. 
Somebody may want to post the entire thing to comp.os.minix with patches
included; I didn't want to post that much.

Good luck!

Peter S. Housel		housel@ei.ecn.purdue.edu
			...!pur-ee!housel

#!/bin/sh
#---------------cut here---------------------
#
# This is a shell archive. Unpack with sh.
#
echo 'x - README.Minix'
sed 's/^X//' <<'**-README.Minix-EOF-**' >README.Minix
Xlocaltime routines for Minix
X----------------------------
X
X	These are the patches and auxilary files needed to use the
Xtable-driven timezone routines with the Minix operating system.
X
XWHAT YOU NEED
X	First, you need a copy of the routines themselves, which were
Xposted to comp.sources.unix as v08i085, v08i086, and v08i087. These
Xshar files can be obtained from your nearby comp.sources.unix archive
X(for example j.cc.purdue.edu).
X
X	Secondly, you probably need the patches to the above which were
Xalso posted to comp.os.unix, as v09i021.
X
X	Thirdly, you need to make a few fixes to the Minix libc routines.
XThese include the changes for exit()/_cleanup() as posted by Dr. Tanenbaum,
Xand the changes for scanf(), rmu4.s, and rmi4.s as posted by myself.
X"zic" will not work if scanf is not fixed, and nothing will work if rmu4.s
Xand rmi4.s are not changed.
X
XINSTALLATION
X
X1) install the time.h file in /usr/include.
X
X2) Replace "Makefile" with the one given here, and apply the other
Xdiff files using "fix". Most of these are because /lib/cpp can't handle
Xfiles with a lone "#" on them; the rest account for minor bugs in /lib/cem.
X
X3) make, following instructions in the standard README. Make sure you set
Xyour time zone correctly. (ex. WET for the Netherlands, US/East-Indiana for
Xmost of Indiana, etc.)
X
X4) Install ctime.s, localtime.s, asctime.s, dysize.s, and timemk.s at the
Xbeginning of your /usr/lib/libc.a file, in that order. (This is a hard one.)
X
X5) Install date in /bin or /usr/bin, wherever you normally keep it.
X
X6) The /etc/zoneinfo directory, and AT LEAST the /etc/zoneinfo/localtime
Xfile, need to be saved on your permaneant copy of the root filesystem
X(i.e. copied from ramdisk to your "root filesystem" floppy).
XThe other files in /etc/zoneinfo are optional and may be deleted.
X
X7) ls.c also needs to be patched so that local the -l listing will be
Xcorrect. Apply "ls.c.diff" using "fix". (Patch relative to 1.2)
X
X8) If you have a PC/AT, you can change the "date -q" in /etc/rc to "date -a".
XIf your machine is not AT compatible, the -a option will not work.
X
**-README.Minix-EOF-**
echo 'x - Makefile'
sed 's/^X//' <<'**-Makefile-EOF-**' >Makefile
X# @(#)Makefile	3.1
X
X# If you want something other than Eastern United States time used on your
X# system, change the line below (after finding the zone you want in the
X# time zone files, or adding it to a time zone file).
X# Alternately, if you discover you've got the wrong time zone, you can just
X#	zic -l rightzone
X
XLOCALTIME=	US/Eastern
X
X# Use an absolute path name for TZDIR unless you're just testing the software.
X
XTZDIR=		/etc/zoneinfo
X
X# You may want to change this define if you're just testing the software.
X# Alternatively, you can put these functions in /lib/libc.a, removing
X# the old "ctime.s" (and "timezone.s" on a BSD system).  This is the
X# ideal solution if you are able.  Build libz.a, extract the files, and
X# then add them to libc.a.
X
XTZLIB=		libz.a
X
X#
X# If you're running on a System V-style system and don't want lint grief,
X# add
X#	-DUSG
X# to the end of the "CFLAGS=" line.
X#
X# If you're running on a system where "strchr" is known as "index",
X# (for example, a 4.[012]BSD system), add
X#	-Dstrchr=index
X# to the end of the "CFLAGS=" line.
X#
X# If you want to use System V compatibility code, add
X#	-DUSG_COMPAT
X# to the end of the "CFLAGS=" line.
X#
X# If you want BSD compatibility code, add
X#	-DBSD_COMPAT
X# to the end of the "CFLAGS=" line.
X#
X# If you've used older versions of this software and want "tz_abbr"
X# compatibility code, add
X#	-DTZA_COMPAT
X# to the end of the "CFLAGS=" line.
X#
X# If you'd like to use Robert Elz's additions to the "struct tm" structure,
X# add a
X#	-DKRE_COMPAT
X# to the end of the "CFLAGS=" line, and add the structure elements
X#	long	tm_gmtoff;
X#	char *	tm_zone;
X# to the END of the "struct tm" structure defined in "/usr/include/time.h".
X#
X# If you want code inspired by certain emerging standards, add
X#	-DSTD_INSPIRED
X# to the end of the "CFLAGS=" line.
X#
X# If you want Source Code Control System ID's left out of object modules, add
X#	-DNOID
X# to the end of the "CFLAGS=" line.
X#
X# If you'll never want to handle solar-time-based time zones, add
X#	-DNOSOLAR
X# to the end of the "CFLAGS=" line
X# (and remove solar87 from the DATA= line below).
X#
X
XCFLAGS=-LIB -DSTD_INSPIRED -DNOID -DKRE_COMPAT -DNOSOLAR -Dstrchr=index
X
X# LINTFLAGS is set for 4.[123]BSD systems.
X# If you're using System V, you'll want to comment out the "LINTFLAGS=" line.
X
XLINTFLAGS=	-phbaaxc
X
X# BUNDLE was set to "bundle" in the original, "shar" is more universal
X
XBUNDLE=		shar
X
XLDFLAGS=
X
X################################################################################
X
XCC=		cc
X
XTZCSRCS=	zic.c localtime.c asctime.c scheck.c ialloc.c mkdir.c
XTZCOBJS=	zic.s localtime.s asctime.s scheck.s ialloc.s mkdir.s
XTZDSRCS=	zdump.c localtime.c asctime.c ialloc.c
XTZDOBJS=	zdump.s localtime.s asctime.s ialloc.s
XLIBSRCS=	localtime.c asctime.c ctime.c dysize.c timemk.c
XLIBOBJS=	ctime.s localtime.s asctime.s dysize.s timemk.s
XDOCS=		Theory README Makefile newctime.3 tzfile.5 zic.8 zdump.8
XSOURCES=	tzfile.h zic.c zdump.c \
X		localtime.c asctime.c ctime.c dysize.c timemk.c \
X		scheck.c ialloc.c mkdir.c
XDATA=		asia australasia europe etcetera northamerica \
X		pacificnew systemv
X
XENCHILADA=	$(DOCS) $(SOURCES) $(DATA)
X
Xall:		REDID_BINARIES zdump $(TZLIB) date
X
XREDID_BINARIES:	zic $(DATA)
X		./zic -l $(LOCALTIME) -d $(TZDIR) $(DATA)
X		touch $@
X
Xzdump:		$(TZDOBJS)
X		$(CC) $(CFLAGS) $(LDFLAGS) $(TZDOBJS) -o $@
X
X$(TZLIB):	$(LIBOBJS)
X		ar r $@ $(LIBOBJS)
X#		ranlib $@
X
Xzic:		$(TZCOBJS)
X		$(CC) $(CFLAGS) $(LDFLAGS) $(TZCOBJS) -o $@
X
XBUNDLES:	BUNDLE1 BUNDLE2 BUNDLE3
X
XBUNDLE1:	$(DOCS)
X		$(BUNDLE) $(DOCS) > $@
X
XBUNDLE2:	$(SOURCES)
X		$(BUNDLE) $(SOURCES) > $@
X
XBUNDLE3:	$(DATA)
X		$(BUNDLE) $(DATA) > $@
X
X#$(ENCHILADA):
X#		sccs get $(REL) $(REV) $@
X
Xsure:		$(TZCSRCS) $(TZDSRCS) tzfile.h
X		lint $(LINTFLAGS) $(CFLAGS) -DTZDIR=\"$(TZDIR)\" $(TZCSRCS)
X		lint $(LINTFLAGS) $(CFLAGS) -DTZDIR=\"$(TZDIR)\" $(TZDSRCS)
X		lint $(LINTFLAGS) $(CFLAGS) -DTZDIR=\"$(TZDIR)\" $(LIBSRCS)
X
Xclean:
X		rm -f core *.s *.sut REDID_BINARIES zdump zic BUNDLE* \#*
X
XCLEAN:		clean
X		sccs clean
X
Xlisting:	$(ENCHILADA)
X		pr $(ENCHILADA) | lpr
X
Xzdump.s zic.s newctime.s:	tzfile.h
X
Xdate:	date.c ports.s $(TZLIB)
X	cc -o date date.c ports.s $(TZLIB)
**-Makefile-EOF-**
echo 'x - date.man'
sed 's/^X//' <<'**-date.man-EOF-**' >date.man
XCommand: date - print or set the date and time
XSyntax:	 date [[[[YY]MM]DD]hhmm[.ss]]
XFlags:	 -q  Prompt for the date, and read from standard input
X	 -a  Read from PC/AT internal battery-backed clock
XExample: date 8801151944.40	# set date to Jan 15, 1988, 7:44:40 PM
X
X	With no arguments, date prints the current date and time. If the
X"-a" option is given, the date is set from the PC/AT internal clock.
X	The date format used for the time argument, or given as input
Xif "-q" is specified, is identical to the V7 format: YYMMDDhhmm.ss (as
Xopposed to the Minix format of MMDDYYhhmmss). This time is interpreted
Xas the local time, whose offset from GMT is determined from the TZ
Xvariable or /etc/zoneinfo/localtime. Only the superuser may set the date.
X	If date is compiled with "-DLOG", it will log date changes in
X/usr/adm/wtmp, provided this file exists.
**-date.man-EOF-**
echo 'x - date.c'
sed 's/^X//' <<'**-date.c-EOF-**' >date.c
X/* file: date.c
X** author: Peter S. Housel 01/01/88, 01/13/88
X** comments: this program is intended to replace the Minix "date"
X**	     program, for use with the comp.sources.unix replacement
X**	     ctime routines.
X**	     note that while the standard Minix date expects input in
X**	     the format "MMDDYYhhmmss", this program uses the same
X**	     format as V7/BSD (/SysV?) of "YYMMDDhhmm.ss", with all
X**	     but "hhmm" being optional.
X*/
X
X#include <stdio.h>
X#include <time.h>
X#include <ctype.h>
X
X#ifdef LOG
X#include <utmp.h>	/* define LOG to log date changes in /usr/adm/wtmp */
X
X#ifndef WTMP
X#define WTMP	"/usr/adm/wtmp"
X#endif !WTMP
X#endif LOG
X
Xextern char *ctime(), *asctime();
Xextern time_t timelocal();
Xextern struct tm *localtime();
X
Xmain(argc, argv)
Xint argc; char *argv[];
X{
X struct tm tmb;		/* struct tm buffer for dateconv */
X char buffer[80];
X int i;
X
X if(1 == argc)		/* no args - display date */
X   {
X    printdate();
X    exit(0);
X   }
X else if(2 == argc)
X   {
X    if(!strcmp(argv[1], "-a"))	/* set from AT battery-backed clock */
X      {
X       getat(&tmb);
X       printf("Setting date from AT clock: %s", asctime(&tmb) + 4);
X      }
X    else if(!strcmp(argv[1], "-q"))	/* query and set */
X      {
X       do
X	 {
X	  printf("The current time is ");
X	  printdate();
X	  printf("Enter time (YYMMDDhhmm.ss): ");
X	  if(NULL == gets(buffer))
X	     exit(0);
X	  if(0 != (i = dateconv(buffer, &tmb)))
X             printf("Illegal date string\n");
X         } while(i != 0);
X      }
X    else if(0 != dateconv(argv[1], &tmb))
X      {
X       usage();
X       exit(1);
X      }
X    exit(0 == settime(&tmb));	/* set time, possibly log change */
X   }  
X else
X   {
X    usage();
X    exit(1);
X   }
X}
X
X
Xusage()
X{
X fprintf(stderr, "usage: date [-q] [-a] [YYMMDDhhmm[.ss]\n");
X}
X
X
Xprintdate()	/* print current date/time in BSD(?) format */
X{
X time_t now;
X struct tm *timep;
X char *timestr;
X 
X time(&now);
X timep = localtime(&now);
X timestr = asctime(timep);
X printf("%.20s%s %s", timestr, timep->tm_zone, timestr + 20);
X}
X
X
Xdateconv(string, timep)	/* convert [[[yy]mm]dd]hhmm[.ss] to struct tm */
Xchar *string; struct tm *timep;
X{
X int numbers[6], i;
X time_t now;
X
X for(i = 0; i < 5; ++i)
X    {
X     if('.' == string[0] || '\0' == string[0])
X        break;
X
X     if(!isdigit(string[0]) || !isdigit(string[1]))
X	return -1;
X
X     numbers[i] = 10 * (*string++ - '0');
X     numbers[i] += (*string++ - '0');
X    }
X
X if(i < 2)	/* must have at least hhmm */
X    return -1;
X
X if(i < 5)	/* one of month, day, or year omitted */
X   {
X    time(&now);
X    *timep = *(localtime(&now));	/* fill in all fields */
X   }
X
X timep->tm_min = numbers[--i];
X timep->tm_hour = numbers[--i];
X
X if(i > 0)
X    timep->tm_mday = numbers[--i];
X
X if(i > 0)
X    timep->tm_mon = numbers[--i] - 1;
X
X if(i > 0)
X    timep->tm_year = numbers[--i];
X
X if('\0' == *string)
X   {
X    timep->tm_sec = 0;
X    return 0;
X   }
X else if('.' == string[0] && isdigit(string[1]) && isdigit(string[2])
X			  && '\0' == string[3])
X   {
X    timep->tm_sec = (string[1] - '0') * 10 + (string[2] - '0');
X    return 0;
X   }
X else
X    return -1;
X}
X
Xsettime(timep)
Xstruct tm *timep;
X{
X time_t now, new;
X#ifdef LOG
X struct utmp logentry;
X int fd;
X#endif
X
X time(&now);
X
X new = timelocal(timep);	/* convert struct tm to time_t */
X
X if(getuid() || stime(&new))	/* try to set system time */
X   {
X    fprintf(stderr, "date: only superuser can set date\n");
X    return -1;
X   }
X
X#ifdef LOG
X if((fd = open(WTMP, 1)) >= 0) && lseek(fd, 0L, 2) >= 0)
X   {
X    strncpy(logentry.ut_name, "", 8);
X
X    strncpy(logentry.ut_line, "|", 8);	/* 'before' entry */
X    logentry.ut_time = now;
X    write(fd, (char *)&logentry, sizeof logentry);
X
X    strncpy(logentry.ut_line, "}", 8);	/* 'after' entry */
X    logentry.ut_time = time(0);
X    write(fd, (char *)&logentry, sizeof logentry);
X   }
X#endif LOG
X return 0;
X}
X
X/* parts of the following code are either written by or inspired by
X** Karl Keyte (ESC1332@ESOC.BITNET), from article 460@louie.udel.EDU
X*/
X
X#define CMOS_INDEX	0x70		/* write-only location select port */
X#define CMOS_DATA	0x71		/* read/write data port */
X
X#define SEC_LOCN	0		/* seconds at CMOS RAM byte 0 */
X#define MIN_LOCN	2		/* minutes byte */
X#define HRS_LOCN	4		/* hours byte */
X#define DAY_LOCN	7		/* day-of-month byte */
X#define MON_LOCN	8		/* month number byte */
X#define YEAR_LOCN	9		/* year byte */
X
Xgetat(timep)		/* read CMOS clock, place result in struct tm */
Xstruct tm *timep;
X{
X getvalue(&timep->tm_sec, SEC_LOCN);
X getvalue(&timep->tm_min, MIN_LOCN);
X getvalue(&timep->tm_hour, HRS_LOCN);
X getvalue(&timep->tm_mday, DAY_LOCN);
X getvalue(&timep->tm_mon, MON_LOCN);
X --timep->tm_mon;			/* correct to struct tm convention */
X getvalue(&timep->tm_year, YEAR_LOCN);
X}
X
Xgetvalue(storage, loc)	/* read CMOS RAM location, convert BCD => int */
Xint *storage; int loc;
X{
X int temp = 0;
X
X *storage = 0xFF;
X
X while(*storage == 0xFF || *storage != temp)
X      {
X       port_out(CMOS_INDEX, loc);
X       port_in(CMOS_DATA, storage);
X
X       port_out(CMOS_INDEX, loc);
X       port_in(CMOS_DATA, &temp);
X      }
X
X *storage = 10 * (*storage >> 4) + (*storage & 0x0F);
X}
X
**-date.c-EOF-**
echo 'x - ports.s'
sed 's/^X//' <<'**-ports.s-EOF-**' >ports.s
X.define _port_out, _port_in
X
X|*===========================================================================*
X|*                              port_out                                     *
X|*===========================================================================*
X| port_out(port, value) writes 'value' on the I/O port 'port'.
X
X_port_out:
X        push bx                 | save bx
X        mov bx,sp               | index off bx
X        push ax                 | save ax
X        push dx                 | save dx
X        mov dx,4(bx)            | dx = port
X        mov ax,6(bx)            | ax = value
X        out                     | output 1 byte
X        pop dx                  | restore dx
X        pop ax                  | restore ax
X        pop bx                  | restore bx
X        ret                     | return to caller
X
X
X|*===========================================================================*
X|*                              port_in                                      *
X|*===========================================================================*
X| port_in(port, &value) reads from port 'port' and puts the result in 'value'.
X_port_in:
X        push bx                 | save bx
X        mov bx,sp               | index off bx
X        push ax                 | save ax
X        push dx                 | save dx
X        mov dx,4(bx)            | dx = port
X        in                      | input 1 byte
X        xorb ah,ah              | clear ah
X        mov bx,6(bx)            | fetch address where byte is to go
X        mov (bx),ax             | return byte to caller in param
X        pop dx                  | restore dx
X        pop ax                  | restore ax
X        pop bx                  | restore bx
X        ret                     | return to caller
**-ports.s-EOF-**
echo 'x - asctime.c.diff'
sed 's/^X//' <<'**-asctime.c.diff-EOF-**' >asctime.c.diff
X1,2d0
X< #
X< 
X28,31c26,29
X< 	static char	wday_name[DAYS_PER_WEEK][3] = {
X< 		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
X< 	};
X< 	static char	mon_name[MONS_PER_YEAR][3] = {
X---
X> 	static char *	wday_name[DAYS_PER_WEEK] = {
X> 		"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
X> 	};
X> 	static char *	mon_name[MONS_PER_YEAR] = {
**-asctime.c.diff-EOF-**
echo 'x - ctime.c.diff'
sed 's/^X//' <<'**-ctime.c.diff-EOF-**' >ctime.c.diff
X1,2d0
X< #
X< 
**-ctime.c.diff-EOF-**
echo 'x - dysize.c.diff'
sed 's/^X//' <<'**-dysize.c.diff-EOF-**' >dysize.c.diff
X1,2d0
X< #
X< 
**-dysize.c.diff-EOF-**
echo 'x - ialloc.c.diff'
sed 's/^X//' <<'**-ialloc.c.diff-EOF-**' >ialloc.c.diff
X1,2d0
X< #
X< 
**-ialloc.c.diff-EOF-**
echo 'x - ls.c.diff'
sed 's/^X//' <<'**-ls.c.diff-EOF-**' >ls.c.diff
X8a9
X> #include "time.h"
X501,544c502,512
X<   int i, year, day, month, hour, minute;
X<   long length, time(), original;
X< 
X<   year = 1970;
X<   original = t;
X<   while (t > 0) {
X< 	length = (year % 4 == 0 ? LYEAR : YEAR);
X< 	if ( t < length) break;
X< 	t -= length;
X< 	year++;
X<   }
X< 
X<   /* Year has now been determined.  Now the rest. */
X<   day = t/(24L * 3600L);
X<   t -= (long) day * 24L * 3600L;
X<   hour = t/3600L;
X<   t -= 3600L * (long) hour;
X<   minute = (int) t/60L;
X< 
X<   /* Determine the month and day of the month. */
X<   mo[1] = (year % 4 == 0 ? 29 : 28);
X<   month = 0;
X<   i = 0;
X<   while (day >= mo[i]) {
X< 	month++;
X< 	day -= mo[i];
X< 	i++;
X<   }
X< 
X<   /* At this point, 'year', 'month', 'day', 'hour', 'minute'  ok */
X<   if (curtime == 0) curtime = time( (long*)0);	/* approximate current time */
X<   fprintf(stdout, "%3s %2d ",moname[month], day+1);
X<   if (curtime - original >= YEAR/2L) {
X< 	fprintf(stdout, "%5d ",year);
X<   } else {
X< 	if (hour < 10)
X< 		fprintf(stdout, "0%d:",hour);
X< 	else
X< 		fprintf(stdout, "%2d:",hour);
X< 
X< 	if (minute < 10)
X< 		fprintf(stdout, "0%d ",minute);
X< 	else
X< 		fprintf(stdout, "%2d ",minute);
X---
X>   long time(), original;
X>   struct tm *timep, *localtime();
X> 
X>   timep = localtime(&t);
X> 
X>   if (curtime == 0) curtime = time( (long*)0);	/* approximate current time */
X>   fprintf(stdout, "%3s %2d ",moname[timep->tm_mon], timep->tm_mday);
X>   if (curtime - t >= YEAR/2L) {
X> 	fprintf(stdout, "%5d ", 1900 + timep->tm_year);
X>   } else {
X> 	fprintf(stdout, "%02d:%02d ", timep->tm_hour, timep->tm_min);
**-ls.c.diff-EOF-**
echo 'x - mkdir.c.diff'
sed 's/^X//' <<'**-mkdir.c.diff-EOF-**' >mkdir.c.diff
X1,2d0
X< #
X< 
**-mkdir.c.diff-EOF-**
echo 'x - scheck.c.diff'
sed 's/^X//' <<'**-scheck.c.diff-EOF-**' >scheck.c.diff
X1,2d0
X< #
X< 
**-scheck.c.diff-EOF-**
echo 'x - timemk.c.diff'
sed 's/^X//' <<'**-timemk.c.diff-EOF-**' >timemk.c.diff
X1,2d0
X< #
X< 
**-timemk.c.diff-EOF-**
echo 'x - zdump.c.diff'
sed 's/^X//' <<'**-zdump.c.diff-EOF-**' >zdump.c.diff
X1,2d0
X< #
X< 
**-zdump.c.diff-EOF-**
echo 'x - zic.c.diff'
sed 's/^X//' <<'**-zic.c.diff-EOF-**' >zic.c.diff
X1,2d0
X< #
X< 
X14c12
X< #include "sys/stat.h"
X---
X> #include "stat.h"
**-zic.c.diff-EOF-**
echo 'x - time.h'
sed 's/^X//' <<'**-time.h-EOF-**' >time.h
X/* time.h */
X
Xtypedef long time_t;
X
Xstruct tm  {
X  int	tm_sec;		/* second hand */
X  int	tm_min;		/* minute hand */
X  int	tm_hour;	/* hour hand (24-hour) */
X  int	tm_mday;	/* day of the month */
X  int	tm_mon;		/* month */
X  int	tm_year;	/* year */
X  int	tm_wday;	/* weekday */
X  int	tm_yday;	/* day of the year */
X  int	tm_isdst;	/* DST in effect? */
X  int	tm_gmtoff;	/* seconds east of DST */
X  char *tm_zone;	/* timezone name */
X};
X
Xstruct timeb {
X  time_t time;
X  unsigned short millitm;
X  short	timezone;
X  short	dstflag;
X};
X
Xextern struct tm *localtime(), *gmtime();
Xextern char *asctime(), *ctime();
Xextern time_t time();
X
**-time.h-EOF-**
exit 0