home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 3 / 3066 / util.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-03-15  |  9.7 KB  |  472 lines

  1. /*
  2.  *    util.c : Some miscellaneous routines for handling dates.
  3.  *
  4.  *    George Ferguson, ferguson@cs.rochester.edu, 27 Oct 1990.
  5.  *    Version 1.1 - 27 Feb 1991.
  6.  *
  7.  *      $Id: util.c,v 2.2 91/03/13 13:31:41 ferguson Exp $
  8.  *
  9.  */
  10.  
  11. #include <sys/time.h>
  12. #include <ctype.h>
  13. #include "date-strings.h"        /* for parseDate() */
  14. #include "app-resources.h"        /* for appsUseAmPm, etc. */
  15. extern char *getenv();            /* for $HOME */
  16. extern char *program;            /* for error messages */
  17.  
  18. /*
  19.  * Functions defined here:
  20.  */
  21. int computeDOW(), firstDOW(), lastDay();
  22. void nextDay(),prevDay(),getCurrentDate();
  23. int parseDate();
  24. void parseLine();
  25. char *expandFilename();
  26. int strtotime();
  27. char *timetostr();
  28.  
  29. /*
  30.  * Data defined here:
  31.  */
  32. static int mon_max[] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
  33. static char filename[1024];
  34.  
  35. /*    -    -    -    -    -    -    -    -    */
  36. /*
  37.  *    computeDOW(day,mon,year) : Returns the day of the week for the
  38.  *        requested date (1=Sunday, 2=Monday, etc).
  39.  *        This newer, faster, method is courtesy findeis@alberta.
  40.  */
  41. int
  42. computeDOW(d,m,y)
  43. int d,m,y;
  44. {
  45.     static int dp [12] = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
  46.     register int y4, s;
  47.  
  48.     y = y - 1901;
  49.     s = (y/4) * 5;
  50.     y4 = y % 4;
  51.     if ((y4 == 3) && (m>2)) s++;
  52.     s = s + y4 + dp[m-1] + d + 1;
  53.     return (s % 7 + 1);
  54. }
  55.  
  56. /*
  57.  *    firstDOW(mon,year) : Returns the day of the week for the first
  58.  *        day of the given month and year.
  59.  */
  60. int
  61. firstDOW(mon,year)
  62. int mon,year;
  63. {
  64.     return(computeDOW(1,mon,year));
  65. }
  66.  
  67. /*
  68.  *    lastDay(mon,year) : Returns the last day of the requested
  69.  *        month (and handles leap years, etc).
  70.  */
  71. int
  72. lastDay(mon,year)
  73. int mon,year;
  74. {
  75.     if ((mon == 1)&&(dysize(year) == 366))
  76.         return(29);
  77.     else return(mon_max[mon-1]);
  78. }
  79.  
  80. /*
  81.  *    nextDay(d,m,y) : Increment d,m,y to the next day
  82.  */
  83. void
  84. nextDay(dp,mp,yp)
  85. int *dp,*mp,*yp;
  86. {
  87.     if (*dp != lastDay(*mp,*yp))
  88.     *dp += 1;
  89.     else {
  90.     *dp = 1;
  91.     if (*mp != 12)
  92.         *mp += 1;
  93.     else {
  94.         *yp += 1;
  95.         *mp = 1;
  96.     }
  97.     }
  98. }
  99.  
  100. /*
  101.  *    prevDay(d,m,y) : Decrement d,m,y to the previous day
  102.  */
  103. void
  104. prevDay(dp,mp,yp)
  105. int *dp,*mp,*yp;
  106. {
  107.     if (*dp != 1)
  108.     *dp -= 1;
  109.     else {
  110.     if (*mp != 1)
  111.         *mp -= 1;
  112.     else {
  113.         *yp -= 1;
  114.         *mp = 12;
  115.     }
  116.     *dp = lastDay(*mp,*yp);
  117.     }
  118. }
  119.  
  120. /*    -    -    -    -    -    -    -    -    */
  121. /*
  122.  *    getCurrentDate() : Day is 1-31, Month is 1-12, Year is 1900-.
  123.  */
  124. void
  125. getCurrentDate(dp,mp,yp)
  126. int *dp,*mp,*yp;
  127. {
  128.   struct timeval t;
  129.   struct timezone tz;
  130.   struct tm *r;
  131.  
  132.   gettimeofday(&t,&tz);
  133.   r = localtime(&(t.tv_sec));
  134.   *dp = r->tm_mday;
  135.   *mp = r->tm_mon+1;
  136.   *yp = r->tm_year+1900;
  137. }
  138.  
  139. /*    -    -    -    -    -    -    -    -    */
  140. /*
  141.  *    parseDate(text,dp,mp,yp) : Parse the string text into a date which is
  142.  *        either an absolute or a relative date as follows:
  143.  *
  144.  *    rel date = [+-]{<num>[dmy]}*
  145.  *    abs date = [<day><mon><year>]* where <day> = <num> less than 32
  146.  *                         <mon> = <string>
  147.  *                         <year>= <num> greater than 32
  148.  *    The variables pointed to by dp,mp,yp should contain the current date
  149.  *    and are filled in with the new date.
  150.  *    Whitespace is skipped.
  151.  *    Returns -1 if the date was garbled, else 0.
  152.  */
  153. int
  154. parseDate(text,dp,mp,yp)
  155. char *text;
  156. int *dp,*mp,*yp;
  157. {
  158.     int day,mon,year,last,num,sign;
  159.  
  160.     day = mon = year = 0;
  161.     last = lastDay(*mp,*yp);
  162.     if (*text == '+' || *text == '-') {    /* relative date */
  163.     sign = *text++;            /* save sign */
  164.     while (*text) {            /* parse string... */
  165.         while (isspace(*text))            /* skip white space */
  166.         text += 1;
  167.         num = 0;
  168.         while (*text >= '0' && *text <= '9') {    /* get a number */
  169.         num = num * 10 + *text - '0';
  170.         text += 1;
  171.         }
  172.         switch(*text) {                /* and a specifier */
  173.         case '\0':        /* no specifier => days */
  174.         case 'D' :
  175.         case 'd' : day = num;
  176.                break;
  177.         case 'M' :
  178.         case 'm' : mon = num;
  179.                break;
  180.         case 'Y' :
  181.         case 'y' : year = num;
  182.                break;
  183.         default: return(-1);
  184.         }
  185.         if (*text != '\0')            /* continue unless at end */
  186.         text += 1;
  187.     }
  188.     if (sign == '+') {        /* now set the `current' date */
  189.         *dp += day;
  190.         if (*dp > last) {
  191.         *dp -= last;
  192.         *mp += 1;
  193.         }
  194.         *mp += mon;
  195.         if (*mp > 12) {
  196.         *mp -= 12;
  197.         *yp += 1;
  198.         }
  199.         *yp += year;
  200.     } else {
  201.         *yp -= year;
  202.         *mp -= mon;
  203.         if (*mp < 1) {
  204.         *mp += 12;
  205.         *yp -= 1;
  206.         }
  207.         *dp -= day;
  208.         if (*dp < 1) {
  209.         *mp -= 1;
  210.         if (*mp < 1) {
  211.             *mp = 12;
  212.             *yp -= 1;
  213.         }
  214.         *dp += last;
  215.         }
  216.     }
  217.     } else {                /* absolute date, use parser */
  218.     int dow,y,m,d,h,mins,l;
  219.     char *t;
  220.  
  221.     parseLine(text,&dow,&y,&m,&d,&h,&mins,&t,&l);
  222.     if (y != 0)
  223.         *yp = y;
  224.     if (m != 0)
  225.         *mp = m;
  226.     if (d != 0)
  227.         *dp = d;
  228.     }
  229.     return(0);
  230. }
  231.  
  232. /*
  233.  * parseLine() : Given a text buffer presumed to be a (possibly incomplete)
  234.  *    date spec followed by the text of the reminder, this function
  235.  *    parses it as best it can and sets the various parameters. The
  236.  *    following are understood (where # is any consecutive run of digits):
  237.  *        #:#    =    hours:mins (24hr)
  238.  *        #:#am    =    hours:mins
  239.  *        #:#pm    =    hours+12:mins
  240.  *        #/#    =    month/day (depends on daySlashMonth)
  241.  *        #/#/#    =    month/day/year ("   "        "     )
  242.  *        #am    =    hours
  243.  *        #pm    =    hours (+12)
  244.  *        # <= 31    =    day
  245.  *        # > 31    =    year
  246.  *        @#@    =    level (depends on levelDelim)
  247.  *    Also, either the long or short forms of months and days of the week
  248.  *    set the appropriate parameter. Parsing stops (and the text is assumed
  249.  *    to start) at the first non-numerical string which cannot be
  250.  *    interpreted as one of these.
  251.  *
  252.  *    If parameters weren't set, they are set to 0, except hours and mins
  253.  *    which are set to -1 (since 0 is a valid value).
  254.  */
  255. void
  256. parseLine(buf,dowp,yp,mp,dp,hp,minsp,tp,lp)
  257. char buf[];
  258. int *dowp,*yp,*mp,*dp,*hp,*minsp;
  259. char **tp;
  260. int *lp;
  261. {
  262.     int i,j,n;
  263.     char word[32];
  264.  
  265.     *dowp = *yp = *mp = *dp = *lp = 0;
  266.     *hp = *minsp = -1;
  267.     *tp = NULL;
  268.     i = 0;
  269.     while (buf[i]) {
  270.     while (isspace(buf[i]))
  271.         i += 1;
  272.     if (!buf[i]) {
  273.         break;
  274.     } else if (isdigit(buf[i])) {
  275.         n = 0;
  276.         while (isdigit(buf[i]))
  277.         n = n * 10 + buf[i++] - '0';
  278.         if (buf[i] == ':') {
  279.         *hp = n;
  280.         i += 1;
  281.         *minsp = 0;
  282.         while (isdigit(buf[i]))
  283.             *minsp = *minsp * 10 + buf[i++] - '0';
  284.         if (buf[i] == 'p' && buf[i+1] == 'm' && *hp < 12) {
  285.             *hp += 12;
  286.             i += 2;
  287.         } else if (buf[i] == 'a' && buf[i+1] == 'm')
  288.             i += 2;
  289.         } else if (buf[i] == 'p' && buf[i+1] == 'm') {
  290.         *hp = n + 12;
  291.         *minsp = 0;
  292.         i += 2;
  293.         } else if (buf[i] == 'a' && buf[i+1] == 'm') {
  294.         *hp = n;
  295.         *minsp = 0;
  296.         i += 2;
  297.         } else if (buf[i] == '/') {
  298.         *mp = n;
  299.         i += 1;
  300.         *dp = 0;
  301.         while (isdigit(buf[i]))
  302.             *dp = *dp * 10 + buf[i++] - '0';
  303.         if (buf[i] == '/') {
  304.             i += 1;
  305.             *yp = 0;
  306.             while (isdigit(buf[i]))
  307.             *yp = *yp * 10 + buf[i++] - '0';
  308.         }
  309.         if (appResources.daySlashMonth && *dp <= 12) {
  310.             n = *mp;
  311.             *mp = *dp;
  312.             *dp = n;
  313.         }
  314.         } else if (n <= 31) {
  315.         *dp = n;
  316.         } else {
  317.         *yp = n;
  318.         }
  319.     } else if (buf[i] == *(appResources.levelDelim)) {
  320.         i += 1;
  321.         *lp = 0;
  322.         while (isdigit(buf[i]))
  323.         *lp = *lp * 10 + buf[i++] - '0';
  324.         i += 1;
  325.     } else {        /* !isdigit(buf[i]) */
  326.         j = 0;
  327.         do {
  328.         word[j++] = buf[i++];
  329.         } while (isalpha(buf[i]) && j < 32);
  330.         word[j] = '\0';
  331.         if (strcasecmp(word, appResources.noonStr) == 0) {
  332.         *hp = 12;
  333.         *minsp = 0;
  334.         continue;
  335.         } else if (strcasecmp(word, appResources.midnightStr) == 0) {
  336.         *hp = *minsp = 0;
  337.         continue;
  338.         }
  339.         for (j = 0; j < 7; j++)
  340.         if (strcasecmp(word, longDowStr[j]) == 0)
  341.             break;
  342.         if (j != 7) {
  343.         *dowp = j + 1;
  344.         continue;
  345.         }
  346.         for (j = 0; j < 12; j++)
  347.         if (strcasecmp(word, longMonthStr[j]) == 0)
  348.             break;
  349.         if (j != 12) {
  350.         *mp = j + 1;
  351.         continue;
  352.         }
  353.         for (j = 0; j < 7; j++)
  354.         if (strcasecmp(word, shortDowStr[j]) == 0)
  355.             break;
  356.         if (j != 7) {
  357.         *dowp = j + 1;
  358.         if (buf[i] == '.')
  359.             i += 1;
  360.         continue;
  361.         }
  362.         for (j = 0; j < 12; j++)
  363.         if (strcasecmp(word, shortMonthStr[j]) == 0)
  364.             break;
  365.         if (j != 12) {
  366.         *mp = j + 1;
  367.         if (buf[i] == '.')
  368.             i += 1;
  369.         continue;
  370.         }
  371.         *tp = buf + i - strlen(word);
  372.         break;        /* start of text, apparently */
  373.     }
  374.     }
  375. }
  376.  
  377.  
  378. /*    -    -    -    -    -    -    -    -    */
  379. /*
  380.  * expandFilename() : Replaces a leading tilde by the value of $HOME,
  381.  *    and returns a pointer to the resulting filename.
  382.  */
  383. char *
  384. expandFilename(name)
  385. char *name;
  386. {
  387.     char *s;
  388.  
  389.     if (*name == '~') {
  390.     if ((s=getenv("HOME")) == NULL) {
  391.         strcpy(filename,name);
  392.     } else {
  393.         strcpy(filename,s);
  394.         strcat(filename,name+1);
  395.     }
  396.     } else {
  397.     strcpy(filename,name);
  398.     }
  399.     return(filename);
  400. }
  401.  
  402. /*    -    -    -    -    -    -    -    -    */
  403. /* Minutes to/from ascii conversions */
  404.  
  405. /*
  406.  * strtotime(s) : Returns number of minutes in s, allowing "#:#" and am/pm,
  407.  *    "noon", and "midnight". Skips leading white space, doesn't errorcheck
  408.  *    at all.
  409.  */
  410. int
  411. strtotime(s)
  412. char *s;
  413. {
  414.     int h,m;
  415.     char *t;
  416.  
  417.     while (isspace(*s))
  418.     s += 1;
  419.     if (strncasecmp(s,appResources.noonStr,
  420.                 strlen(appResources.noonStr)) == 0)
  421.     return(12*60);
  422.     else if (strncasecmp(s,appResources.midnightStr,
  423.                 strlen(appResources.midnightStr)) == 0)
  424.     return(0);
  425.     t = s;
  426.     h = (int)strtol(s,&s,10);
  427.     if (*s == ':') {
  428.     s += 1;
  429.     m = (int)strtol(s,&s,10);
  430.     } else
  431.     m = 0;
  432.     if (s == t)        /* no numbers, some trash */
  433.     return(-1);
  434.     if (*s == 'p')    /* otherwise it's 'a' or '\0' so okay */
  435.     h += 12;
  436.     return(h*60+m);
  437. }
  438.  
  439. /*
  440.  * timetostr(t) : Formats t minutes into hh:mm, possibly with am/pm, and
  441.  *    possibly with noonStr or midnightStr.
  442.  *    Returns a pointer to the static string.
  443.  */
  444. char *
  445. timetostr(t)
  446. int t;
  447. {
  448.     static char *s = "XX:XXxxyy";
  449.     int h,m;
  450.  
  451.     h = t / 60;
  452.     m = t % 60;
  453.     if (appResources.appsUseAmPm)
  454.     if (h == 12)
  455.         if (m == 0)
  456.         sprintf(s,appResources.noonStr);
  457.         else
  458.         sprintf(s,"12:%02dpm",m);
  459.     else if (h == 0)
  460.         if (m == 0)
  461.         sprintf(s,appResources.midnightStr);
  462.         else
  463.         sprintf(s,"00:%02dam",m);
  464.     else if (h > 12)
  465.         sprintf(s,"%2d:%02dpm",h-12,m);
  466.     else
  467.         sprintf(s,"%2d:%02dam",h,m);
  468.     else
  469.     sprintf(s,"%2d:%02d",h,m);
  470.     return(s);
  471. }
  472.