1: #include <stdio.h> 2: #include <time.h> 3: #include <ctype.h> 4: 5: /* 6: ** promptdate 7: ** prompt user for a date specification which can be quite minimal 8: ** and print it in a form suitable for parsing by MH 9: */ 10: 11: #define MAXLINE 128 12: 13: char *mname[12] ={ 14: "Jan","Feb","Mar","Apr","May","Jun", 15: "Jul","Aug","Sep","Oct","Nov","Dec"}; 16: char *dname[7] ={ 17: "Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; 18: struct tm now; 19: int dayspast = 0; 20: int monthlen[2][12] ={ 21: 31,28,31,30,31,30,31,31,30,31,30,31, 22: 31,29,31,30,31,30,31,31,30,31,30,31}; 23: char *defaultformat = "%d %N %y 00:00"; 24: 25: main(argc, argv) 26: int argc; 27: char **argv; 28: { 29: register int c; 30: struct tm then; 31: extern int optind; /* defined in getopt */ 32: extern char *optarg; /* defined in getopt */ 33: int getopt(); 34: long secsfr70(); 35: 36: while ((c = getopt (argc, argv, "f:")) != EOF) 37: { 38: switch (c) 39: { 40: case 'f': 41: defaultformat = optarg; 42: break; 43: default: 44: fprintf(stderr, "usage: %s [-f format] [datespec]\n", argv[0]); 45: exit (1); 46: } 47: } 48: argc -= optind; 49: argv += optind; 50: 51: finddate(&now, dayspast = (int)(secsfr70()/86400L)); 52: 53: if (argc <= 0) /* get from user */ 54: { 55: if (!promptdate(&then)) 56: exit(1); 57: printdate(&then, defaultformat); 58: } 59: else /* get from command line */ 60: { 61: if (!decodedate(argv[0], &then)) 62: exit(1); 63: printdate(&then, defaultformat); 64: } 65: exit(0); 66: } 67: 68: int promptdate(when) 69: struct tm *when; 70: { 71: char line[MAXLINE]; 72: int decodedate(); 73: char *gets(); 74: 75: for (;;) 76: { 77: fprintf(stderr, "When? "); 78: if (gets(line) == NULL) 79: { 80: fprintf(stderr, "\n"); 81: return (0); 82: } 83: if (decodedate(line, when)) 84: return (1); 85: } 86: /*NOTREACHED*/ 87: } 88: 89: int decodedate(line, when) 90: char *line; 91: struct tm *when; 92: /* 93: ** accept spec for date in several forms 94: ** legal are: sun,mon,tue,wed,thu,fri,sat,today,tomorrow, 95: ** <date><month>,+<relative number of days> 96: ** <month> should be alpha 97: ** upper case accepted too 98: */ 99: { 100: char s[4]; 101: register int i,targetdate; 102: int tem; 103: register char *lptr; 104: 105: when->tm_year = now.tm_year; 106: when->tm_mon = now.tm_mon; 107: targetdate = dayspast; 108: for (lptr = line; isspace(*lptr); lptr++) 109: ; 110: if (isdigit(*lptr)) 111: { 112: i = sscanf(lptr, "%d%3s%d", &when->tm_mday, s, &tem); 113: switch(i) 114: { 115: case 3: 116: when->tm_year = tem; 117: case 2: 118: fold(s); 119: when->tm_mon = monthofyear(s); 120: if (i == 3) 121: break; 122: if (when->tm_mday != 0 && when->tm_mon != 0 && daysfr70(when) < dayspast) 123: when->tm_year++; 124: break; 125: case 1: 126: if (when->tm_mday != 0 && when->tm_mday < now.tm_mday) 127: { 128: if (++when->tm_mon > 12) 129: { 130: when->tm_mon = 1; 131: when->tm_year++; 132: } 133: } 134: } 135: return (validate(when)); 136: } 137: if (isalpha(*lptr)) 138: { 139: sscanf(lptr, "%3s", s); 140: fold(s); 141: if ((tem = dayofweek(s)) >= 0) 142: targetdate += (tem -= now.tm_wday) <= 0 ? tem + 7 : tem; 143: else if (strcmp(s, "Tom") == 0) 144: targetdate++; 145: else if (strcmp(s, "Tod") == 0) 146: ; 147: else /* mistake */ 148: return (0); 149: } 150: else if (*lptr == '+') 151: { 152: if (sscanf(++lptr, "%d", &tem) == 0 || tem < 0) /* mistake */ 153: return (0); 154: targetdate += tem; 155: } 156: else /* mistake by default */ 157: return (0); 158: finddate(when, targetdate); 159: return (when->tm_mday != 0); 160: } 161: 162: int validate(datetm) 163: /* 164: ** check that a given date and month combination is legal 165: ** datetm->tm_year must hold the year in question 166: */ 167: register struct tm *datetm; 168: { 169: 170: return (datetm->tm_mday <= monthlen[leapyear(datetm->tm_year)] 171: [datetm->tm_mon] && datetm->tm_mday > 0); 172: } 173: 174: finddate(datetm, df70) 175: /* 176: ** convert days from 1 jan 1970 to a date in struct datetm 177: */ 178: register int df70; 179: register struct tm *datetm; 180: { 181: register struct tm *tdtm; 182: long longtime; 183: struct tm *gmtime(); 184: 185: longtime = df70 * 86400L; 186: tdtm = gmtime(&longtime); 187: datetm->tm_yday = tdtm->tm_yday; 188: datetm->tm_wday = tdtm->tm_wday; 189: datetm->tm_year = tdtm->tm_year + 1900; 190: datetm->tm_mon = tdtm->tm_mon; 191: datetm->tm_mday = tdtm->tm_mday; 192: datetm->tm_hour = tdtm->tm_hour; 193: datetm->tm_min = tdtm->tm_min; 194: datetm->tm_sec = tdtm->tm_sec; 195: } 196: 197: fold(s) 198: /* 199: ** convert first character to uppercase 200: ** convert rest of string from uppercase to lower case 201: */ 202: register char *s; 203: { 204: register char c; 205: 206: if ((c = *s) != '\0') 207: *s++ += islower(c) ? 'A' - 'a' : 0; 208: while ((c = *s) != '\0') 209: *s++ += isupper(c) ? 'a' - 'A' : 0; 210: } 211: 212: int leapyear(y) 213: /* 214: ** returns 1 if leapyear 0 otherwise 215: */ 216: register int y; 217: { 218: 219: return (((y % 4) == 0 && (y % 100) != 0) || (y % 400) == 0); 220: } 221: 222: int daysfr70(datetm) 223: /* 224: ** returns the number of days from 1 Jan 1970 225: ** no checking for illegal date at all 226: */ 227: register struct tm *datetm; 228: { 229: register int i, totdays; 230: 231: 232: totdays = 0; 233: for (i = 1970; i <= 2050 && i < datetm->tm_year; i++) /* prevent overflow */ 234: totdays += 365 + leapyear(i); 235: for (i = 0; i < 12 && i < datetm->tm_mon; i++) 236: totdays += monthlen[leapyear(datetm->tm_year)][i]; 237: totdays += datetm->tm_mday - 1; 238: return (totdays); 239: } 240: 241: int monthofyear(s) 242: /* 243: ** returns month of year in numeric form when given 244: ** the first three letters 245: */ 246: register char *s; 247: { 248: register int i; 249: 250: fold(s); 251: for (i = 12; i-- && strcmp(s,mname[i]); ) 252: ; 253: return (i); 254: } 255: 256: int dayofweek(s) 257: /* 258: ** sunday = 0,...,saturday = 6, nomatch = -1 259: */ 260: register char *s; 261: { 262: register int i; 263: 264: fold(s); 265: for (i = 7; i-- && strcmp(s,dname[i]); ) 266: ; 267: return (i); 268: } 269: 270: printdate(date, format) 271: /* 272: ** print date in MH acceptable format 273: ** kludge - general formats are not implemented 274: */ 275: struct tm *date; 276: char *format; 277: { 278: printf("%d %s %d 00:00\n", 279: date->tm_mday, mname[date->tm_mon], date->tm_year); 280: } 281: 282: long secsfr70() 283: /* 284: ** This is system dependent 285: */ 286: { 287: register int dst; 288: struct timeval tv; 289: struct timezone tz; 290: struct tm *localtime(); 291: 292: gettimeofday(&tv, &tz); 293: dst = localtime(&tv.tv_sec)->tm_isdst; 294: return (tv.tv_sec - tz.tz_minuteswest * 60 + (dst ? 3600 : 0)); 295: }