#define IDENTIFICATION "tm 1.22, made on 2008-01-30" // // Purpose: // // Exercise unix/c timevalues. // // Usage: // // See help(). // // Notes: // // MS C: // // mktime() on failure, returns -1 // localtime() on failure, returns NULL (prior to 1980) // gmtime() on failure, returns NULL (prior to 1980) // // HPUX C: Remember, -1 *is* a valid timeval for this guy... // // mktime() on failure, returns -1 and sets errno to ERANGE // localtime() doesn't fail // gmtime() doesn't fail // // Also, the ranges are different. See help(). // // Authors: // // William W. Patterson // // History: // // 2000-01-27 1.00 WWP Creation. // 2000-02-02 1.10 WWP Heavily modified for greater utility! // 2000-02-02 1.11 WWP Renamed getopt() to mygetopt() for hpux. // 2000-02-02 1.12 WWP Improved error messages. // 2000-02-02 1.20 WWP Earlier than 1980-01-01 is a problem for DOS. // 2008-01-30 1.21 WWP Use '-' instead of '.' in dates, per ISO. // 2008-01-30 1.22 WWP Use __GNUC__ predefined macro. // #include #include #include #include #include #include #include #include #ifdef _HPUX_SOURCE #include #endif #if !defined(_MSC_VER) && !defined(_HPUX_SOURCE) && !defined(__GNUC__) #error SOURCE MODIFICATION MAY BE NECESSARY! #endif int debugging = 0; char *daynames[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; #define CONVERSION 1 #define TABLE 2 unsigned long ujs[] = { 0x00000000L, 0x10000000L, 0x20000000L, 0x30000000L, 0x40000000L, 0x50000000L, 0x60000000L, 0x70000000L, 0x7fffffffL, 0x80000000L, 0x80000001L, 0x90000000L, 0xa0000000L, 0xb0000000L, 0xc0000000L, 0xd0000000L, 0xe0000000L, 0xf0000000L, 0xffffffffL }; //***************************************************************************** #define GETOPTERR(s,c) \ if (opterr) \ { \ char errbuf[2]; \ errbuf[0] = c; \ errbuf[1] = '\n'; \ (void) write(2,argv[0],(unsigned)strlen(argv[0])); \ (void) write(2,s,(unsigned)strlen(s)); \ (void) write(2,errbuf,2); \ } int opterr = 1; int optind = 1; int optopt; char *optarg; int mygetopt( int argc, char **argv, char *opts ) { static int sp = 1; register int c; register char *cp; if ( sp == 1 ) { if ( optind>=argc || argv[optind][0]!='-' || argv[optind][1]=='\0' ) { return(EOF); } else { if ( strcmp(argv[optind],"--") == (int)NULL ) /* 002 */ { ++optind; return(EOF); } } } optopt = c = argv[optind][sp]; if ( c==':' || (cp=strchr(opts,c))==NULL ) { GETOPTERR(": illegal option -- ", c); if ( argv[optind][++sp] == '\0' ) { ++optind; sp = 1; } return('?'); } if ( *++cp == ':' ) { if ( argv[optind][sp+1] != '\0' ) { optarg = &argv[optind++][sp+1]; } else { if ( ++optind >= argc ) { GETOPTERR(": option requires an argument -- ",c); sp = 1; return('?'); } else { optarg = argv[optind++]; } } sp = 1; } else { if ( argv[optind][++sp] == '\0' ) { sp = 1; ++optind; } optarg = NULL; } return(c); } //***************************************************************************** void help( char *errortext ) { printf("\n%s\n\n",IDENTIFICATION); puts("Quirks:\n"); puts("1. In HPUX, the usual, except that all timevals are legal and"); puts(" wrap back around to 1901 and then back to the base date."); puts("2. DOS version can't handle dates prior to 1980, but afterwards"); puts(" timeval is treated as unsigned, running until 2106."); puts("3. First Linux version is 1.22; behaves like the HPUX version.\n"); puts("usage: tm [options] [args]"); puts(" -h -? ? help"); puts(" -n show info for current time"); puts(" -d yyyymmddhhmmss show info for this local date/time"); puts(" -t n show info for this timeval"); puts(" -T show time table for this version"); puts(" -D show debug info\n"); if (*errortext) puts(errortext); exit(0); } //***************************************************************************** int main( int argc, char **argv ) { int j, n, opt; int jyear, jmonth, jday, jhour, jminute, jsecond; time_t jtime = -1; struct tm s_gmtime; struct tm s_localtime; struct tm *ptm; int mode = 0; while ( optind < argc ) { while ( ( opt = mygetopt(argc,argv,"?Dd:hnTt:") ) != EOF ) { switch(opt) { case 'D': debugging = 1; break; case 'T': mode = TABLE; break; case 'd': if ( 6 != sscanf(optarg,"%04d%02d%02d%02d%02d%02d",&jyear,&jmonth,&jday,&jhour,&jminute,&jsecond) ) help("INVALID DATE/TIME ARGUMENT"); s_localtime.tm_year = jyear - 1900; s_localtime.tm_mon = jmonth - 1; s_localtime.tm_mday = jday; s_localtime.tm_hour = jhour; s_localtime.tm_min = jminute; s_localtime.tm_sec = jsecond; s_localtime.tm_isdst = -1; #ifdef _HPUX_SOURCE errno = 0; #endif jtime = mktime(&s_localtime); #ifdef _HPUX_SOURCE if ( ERANGE == errno ) help("HPUXC INVALID DATE/TIME ARGUMENT"); #endif #if defined(_MSC_VER) || defined(__GNUC__) if ( -1 == jtime ) help("MSC INVALID DATE/TIME ARGUMENT"); #endif #if !defined(_MSC_VER) && !defined(_HPUX_SOURCE) && !defined(__GNUC__) #error ERROR CONDITION NOT HANDLED! #endif if (debugging) printf("user specified time value: %ld\n",jtime); mode = CONVERSION; break; case 'h': case '?': help(""); break; case 'n': time(&jtime); if (debugging) printf("using current time value: %ld\n",jtime); mode = CONVERSION; break; case 't': jtime = atol(optarg); if (debugging) printf("user specified time value: %ld\n",jtime); mode = CONVERSION; break; default: break; } } if ( optind < argc ) { switch(*argv[optind]) { case '?': help(""); break; default: printf("unrecognized argument: %s\n",argv[optind]); break; } ++optind; } } switch(mode) { case CONVERSION: ptm = localtime(&jtime); // The following error cannot happen in hpux... if ( (struct tm *)NULL == ptm ) help("MISSING OR INVALID ARGUMENTS"); memcpy(&s_localtime,ptm,sizeof(struct tm)); ptm = gmtime(&jtime); // The following error cannot happen in hpux... if ( (struct tm *)NULL == ptm ) help("MISSING OR INVALID ARGUMENTS"); memcpy(&s_gmtime,ptm,sizeof(struct tm)); printf("timevalue: %ld\n",jtime); printf("local%s %04d-%02d-%02d %02d:%02d:%02d %s", s_localtime.tm_isdst ? " dst:" : ": ", s_localtime.tm_year + 1900, s_localtime.tm_mon + 1, s_localtime.tm_mday, s_localtime.tm_hour, s_localtime.tm_min, s_localtime.tm_sec, daynames[s_localtime.tm_wday] ); puts(""); printf("gmt%s %04d-%02d-%02d %02d:%02d:%02d %s", s_gmtime.tm_isdst ? " dst:" : ": ", s_gmtime.tm_year + 1900, s_gmtime.tm_mon + 1, s_gmtime.tm_mday, s_gmtime.tm_hour, s_gmtime.tm_min, s_gmtime.tm_sec, daynames[s_gmtime.tm_wday] ); puts(""); break; case TABLE: if ( 4 != sizeof(long) ) { puts("this program was designed for 32-bit machines"); exit(0); } n = sizeof(ujs)/sizeof(ujs[0]); for ( j=0; j