home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.bin / SourceCode / libcs / fdate.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-11  |  10.5 KB  |  456 lines

  1. /*
  2.  * Copyright (c) 1990 Carnegie Mellon University
  3.  * All Rights Reserved.
  4.  * 
  5.  * Permission to use, copy, modify and distribute this software and its
  6.  * documentation is hereby granted, provided that both the copyright
  7.  * notice and this permission notice appear in all copies of the
  8.  * software, derivative works or modified versions, and any portions
  9.  * thereof, and that both notices appear in supporting documentation.
  10.  *
  11.  * THE SOFTWARE IS PROVIDED "AS IS" AND CARNEGIE MELLON UNIVERSITY
  12.  * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  13.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT
  14.  * SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE FOR ANY SPECIAL, DIRECT,
  15.  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  16.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
  17.  * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  18.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19.  *
  20.  * Users of this software agree to return to Carnegie Mellon any
  21.  * improvements or extensions that they make and grant Carnegie the
  22.  * rights to redistribute these changes.
  23.  *
  24.  * Export of this software is permitted only after complying with the
  25.  * regulations of the U.S. Deptartment of Commerce relating to the
  26.  * Export of Technical Data.
  27.  */
  28. # include <sys/types.h>
  29. # include <sys/time.h>
  30.  
  31. /* 
  32.  *  HISTORY
  33.  * $Log:    fdate.c,v $
  34.  * Revision 1.2  90/12/11  17:52:25  mja
  35.  *     Add copyright/disclaimer for distribution.
  36.  * 
  37.  * 30-Apr-85  Steven Shafer (sas) at Carnegie-Mellon University
  38.  *    Adapted for 4.2 BSD UNIX:  macro file name changed.
  39.  *
  40.  * 
  41.  *  March 1984 - Leonard Hamey (lgh) at Carnegie-Mellon University
  42.  *     Created.
  43.  */
  44.  
  45. # define TEXT 1
  46. # define FAIL 2
  47. # define OPTIONAL 3
  48. # define SUCCEED 4
  49.  
  50. # define YES 1
  51. # define NO 0
  52. # define MAYBE 2
  53.  
  54. # define SMONTHS 0
  55. # define SWDAYS 12
  56. # define SNOON 19
  57. # define SMIDNIGHT 20
  58. # define SAM 21
  59. # define SPM 22
  60. # define STH 23
  61. # define SST 24
  62. # define SND 25
  63. # define SRD 26
  64.  
  65. # define NOON 0
  66. # define HOUR 1
  67. # define AM 2
  68. # define MIN 3
  69. # define SEC 4
  70. # define WDAY 5
  71. # define DAY 6
  72. # define TH 7
  73. # define NMONTH 8
  74. # define MONTH 9
  75. # define YEAR 10
  76. # define YDAY 11
  77. # define MIDNIGHT 12
  78. # define TIME 13
  79.  
  80. static char *strings[] =
  81. { "jan*uary", "feb*ruary", "mar*ch", "apr*il", "may", "jun*e",
  82.   "jul*y", "aug*ust", "sep*tember", "oct*ober", "nov*ember", "dec*ember",
  83.   "sun*day", "mon*day", "tue*s*day", "wed*nesday", "thu*r*s*day",
  84.   "fri*day", "sat*urday",
  85.   "noon", "00:00", "am", "pm", "th", "st", "nd", "rd"
  86. };
  87.  
  88. static char *keys[] =
  89. { "noon", "hour", "am", "min", "sec",
  90.   "wday", "day", "th", "nmonth", "month", "year", "yday",
  91.   "midnight", "time",
  92.   0
  93. };
  94.  
  95. /* The following is a macro definition of %time. */
  96.  
  97. static char *mactime =
  98.   "[%midnight|%noon|%0hour:%min:%?sec|{%hour{:%?min}%am}]";
  99.  
  100. static char *p;
  101. static int resp;
  102. static char *result;
  103.  
  104. char *fdate (resb, patt, tm)
  105. char *resb, *patt;
  106. struct tm *tm;
  107. { result = resb;
  108.   resp = 0;
  109.   p = patt;
  110.   dofield (' ', tm);
  111.   result[resp] = '\0';
  112.   return (result);
  113. }
  114.  
  115. static dofield (doing, tm)
  116. char doing;
  117. struct tm *tm;
  118. { int ndep, s, sresp, sresp2;
  119.   int fail;
  120.   char ch;
  121.   fail = MAYBE;
  122.   sresp = resp;
  123.   while (*p)
  124.   { if (*p == '{' || *p == '[')
  125.     { ch = *p++;
  126.       s = dofield (ch, tm);
  127.       if (s == FAIL && doing == '[')
  128.     fail = YES;
  129.       else if (s == SUCCEED && doing == '{')
  130.     fail = NO;
  131.     }
  132.     else if (*p == '}' || *p == ']' || *p == '|')
  133.     { if (doing == '{' && fail == MAYBE)
  134.     fail = YES;
  135.       if (fail == YES)
  136.       { resp = sresp;
  137.         if (*p == '|')
  138.         { p++;
  139.       fail = MAYBE;                  /* try next */
  140.       continue;
  141.         }
  142.     p++;
  143.       }
  144.       else if (*p == '|')
  145.       { /* Scan to matching bracket/brace */
  146.     ndep = 1;
  147.     while (ndep > 0)
  148.     { if (*p == '{' || *p == '[')
  149.         ndep++;
  150.       else if (*p == '}' || *p == ']')
  151.         ndep--;
  152.       p++;
  153.     }
  154.       }
  155.       else
  156.     p++;
  157.       return (fail == YES ? FAIL : SUCCEED);
  158.     }
  159.     else if (*p == '%')
  160.     { sresp2 = resp;
  161.       s = percent (tm);
  162.       if (doing == '{')
  163.       { if (s == FAIL)             /* Discard failure results */
  164.       resp = sresp2;
  165.     else if (s == SUCCEED)
  166.       fail = NO;
  167.       }
  168.       else if (doing == '[')
  169.       { if (s == FAIL)
  170.       fail = YES;
  171.       }
  172.     }
  173.     else
  174.     { result[resp++] = *p;
  175.       p++;
  176.     }
  177.     if (fail == YES)
  178.     { /* Failure: scan for barline or closing bracket/brace; leave ptr there */
  179.       resp = sresp;
  180.       ndep = 1;
  181.       while (ndep > 0)
  182.       { if (*p == '|' && ndep == 1)
  183.       break;
  184.     if (*p == '[' | *p == '{')
  185.       ndep++;
  186.     else if (*p == ']' || *p == '}')
  187.     { ndep--;
  188.       if (ndep == 0)
  189.         return (FAIL);
  190.     }
  191.     p++;
  192.       }
  193.     }
  194.   }
  195.   return (SUCCEED);
  196. }
  197.  
  198. static percent (tm)
  199. struct tm *tm;
  200. { register char *pp;
  201.   char *spp;
  202.   int query, lead0, prec, upcase, sresp, s;
  203.   char *savep;
  204.   register int ks;
  205.   register char *k;
  206.   char foldc ();
  207.   int formfld ();
  208.   char *fldp;
  209.   pp = p + 1;
  210.   if (*pp == '%' || *pp == '{' || *pp == '}' || *pp == '|' ||
  211.     *pp == '[' || *pp == ']')
  212.   { p += 2;
  213.     result[resp++] = *pp;
  214.     return (TEXT);                  /* Was just text */
  215.   }
  216.   query = *pp == '?';                  /* Query? */
  217.   if (query)
  218.     pp++;
  219.   lead0 = *pp == '0';                  /* Leading zero? */
  220.   if (lead0)
  221.     pp++;
  222.   if (*pp >= '1' && *pp <= '9')          /* Precision? */
  223.   { prec = *pp - '0';
  224.     pp++;
  225.   }
  226.   else
  227.     prec = 0;
  228.   upcase = 0;                      /* Case? */
  229.   if (*pp >= 'A' && *pp <= 'Z')
  230.     upcase = 1;
  231.   if (pp[1] >= 'A' && pp[1] <= 'Z')
  232.     upcase = 2;
  233.  
  234.   spp = pp;
  235.   for (ks = 0; keys[ks]; ks++)          /* Check for keyword */
  236.   { for (k = keys[ks], pp = spp; *k; k++, pp++)
  237.       if (foldc (*k) != foldc (*pp))
  238.         break;
  239.     if (! *k)                      /* Match found */
  240.       break;
  241.   }
  242.   if (! keys[ks])                  /* No match */
  243.   { result[resp++] = '%';              /* Treat as text */
  244.     p++;
  245.     return (TEXT);
  246.   }
  247.   p = pp;
  248.   if (ks == TIME)                  /* Macro */
  249.   { savep = p;
  250.     sresp = resp;
  251.     p = mactime + 1;                  /* Skip leading bracket */
  252.     s = dofield (mactime[0], tm);
  253.     p = savep;
  254.     return (s);
  255.   }
  256.   /* Match found */
  257.   s = formfld (tm, ks, lead0, prec, &fldp);
  258.   sresp = resp;
  259.   if (s == OPTIONAL)
  260.   { if (query)
  261.       s = FAIL;
  262.     else
  263.       s = SUCCEED;
  264.   }
  265.   if (s == SUCCEED)
  266.   { for (; *fldp; fldp++)
  267.       result[resp++] = *fldp;
  268.     casefix (&result[sresp], upcase);
  269.   }
  270.   return (s);
  271. }
  272.  
  273. static char foldc (c)
  274. char c;
  275. { return (c < 'a' || c > 'z' ? c : c - 'a' + 'A');
  276. }
  277.  
  278. static char nstr[30];
  279. static char sfield[30];
  280. static int thmem;
  281.  
  282. static formfld (tm, field, lead0, prec, result)
  283. struct tm *tm;
  284. int field, lead0, prec;
  285. char **result;
  286. { int fld, ddiff, s;
  287.   struct tm ctm, *localtime ();
  288.   long ctime, time ();
  289.   sfield[0] = '\0';
  290.   *result = sfield;
  291.   if (field != TH)
  292.     thmem = -1;
  293.   switch (field)
  294.   { case NOON:
  295.       if (tm->tm_hour == 12 && tm->tm_min == 0 && tm->tm_sec == 0)
  296.       { *result = strings[SNOON];
  297.     return (SUCCEED);
  298.       }
  299.       return (FAIL);
  300.  
  301.     case HOUR:
  302.       for (; prec > 2; prec--)
  303.     strcat (sfield, " ");
  304.       if (lead0)
  305.         sprintf (nstr, "%02d", tm->tm_hour);
  306.       else if (prec < 2)
  307.     sprintf (nstr, "%d", (tm->tm_hour + 11) % 12 + 1);
  308.       else
  309.     sprintf (nstr, "%2d", (tm->tm_hour + 11) % 12 + 1);
  310.       strcat (sfield, nstr);
  311.       thmem = tm->tm_hour;
  312.       return (tm->tm_hour >= 0 ? SUCCEED : FAIL);
  313.  
  314.     case MIN:
  315.       fld = tm->tm_min;
  316.     case SEC:
  317.       if (field == SEC)
  318.     fld = tm->tm_sec;
  319.       if (prec == 0)
  320.     prec = 2;
  321.       for (; prec > 2; prec--)
  322.     strcat (sfield, " ");
  323.       if (prec < 2)
  324.     sprintf (nstr, "%d", fld);
  325.       else
  326.     sprintf (nstr, "%02d", fld);
  327.       strcat (sfield, nstr);
  328.       thmem = fld;
  329.       return (fld > 0 ? SUCCEED : (fld == 0 ? OPTIONAL : FAIL));
  330.  
  331.     case AM:
  332.       if (tm->tm_hour >= 12)
  333.     *result = strings[SPM];
  334.       else if (tm->tm_hour >= 0)
  335.     *result = strings[SAM];
  336.       return (tm->tm_hour >= 0 ? SUCCEED : FAIL);
  337.  
  338.     case WDAY:
  339.       if (tm->tm_wday >= 0 && tm->tm_wday < 7)
  340.       { copyword (sfield, strings[SWDAYS + tm->tm_wday], prec);
  341.     return (SUCCEED);
  342.       }
  343.       return (FAIL);
  344.  
  345.     case MONTH:
  346.       if (tm->tm_mon >= 0 && tm->tm_mon < 12)
  347.       { copyword (sfield, strings[SMONTHS + tm->tm_mon], prec);
  348.     return (SUCCEED);
  349.       }
  350.       return (FAIL);
  351.  
  352.     case DAY:
  353.       fld = tm->tm_mday;
  354.     case NMONTH:
  355.     case YDAY:
  356.       if (field == NMONTH)
  357.     fld = tm->tm_mon + 1;
  358.       else if (field == YDAY)
  359.     fld = tm->tm_yday;
  360.       if (prec == 0)
  361.     prec = 1;
  362.       if (lead0)
  363.       { strcpy (nstr, "%09d");
  364.     nstr[2] = prec + '0';
  365.       }
  366.       else
  367.       { strcpy (nstr, "%9d");
  368.     nstr[1] = prec + '0';
  369.       }
  370.       sprintf (sfield, nstr, fld);
  371.       thmem = fld;
  372.       return (fld >= 0 ? SUCCEED : FAIL);
  373.  
  374.     case TH:
  375.       if (thmem >= 0)
  376.       { if ((thmem / 10) % 10 == 1)
  377.       *result = strings[STH];
  378.     else if (thmem % 10 == 1)
  379.       *result = strings[SST];
  380.     else if (thmem % 10 == 2)
  381.       *result = strings[SND];
  382.     else if (thmem % 10 == 3)
  383.       *result = strings[SRD];
  384.     else
  385.       *result = strings[STH];
  386.     return (SUCCEED);
  387.       }
  388.       return (FAIL);
  389.  
  390.     case YEAR:
  391.       ctime = time (0);
  392.       ctm = *localtime (&ctime);
  393.       ddiff = (tm->tm_year - ctm.tm_year) * 366 + tm->tm_yday - ctm.tm_yday;
  394.       if (tm->tm_year >= -1900)
  395.       { if (prec == 0 || prec > 3)
  396.       sprintf (nstr, "%04d", tm->tm_year + 1900);
  397.     else
  398.       sprintf (nstr, "%02d", (tm->tm_year + 1900) % 100);
  399.     *result = nstr;
  400.     return (ddiff < 0 || ddiff > 300 ? SUCCEED : OPTIONAL);
  401.       }
  402.       return (FAIL);
  403.  
  404.     case MIDNIGHT:
  405.       if (tm->tm_hour == 0 && tm->tm_min == 0 && tm->tm_sec == 0)
  406.       { *result = strings[SMIDNIGHT];
  407.     return (SUCCEED);
  408.       }
  409.       return (FAIL);
  410.   }
  411. }
  412.  
  413. /* copyword: Copy <from> to <to> subject to precision <prec>. Asterisks in
  414.  * <from> mark valid truncation points. The longest string no longer than
  415.  * <prec> and broken at a valid truncation point is returned in <to>. Note
  416.  * that the result may exceed <prec> in length only if there are no valid
  417.  * truncation points short enough. The shortest is then taken.
  418.  * 
  419.  * e.g. Tue*s*day.  Precision 1-3 -> Tue,  Precision 4-6 -> Tues,
  420.  *      Precision 0 and 7... -> Tuesday.
  421.  */
  422.  
  423. static copyword (to, from, prec)
  424. char *to, *from;
  425. int prec;
  426. { int ast = 0, top = 0;
  427.   if (prec == 0)
  428.     prec = 999;
  429.   for (; *from; from++)
  430.   { if (*from == '*')
  431.       ast = top;
  432.     else
  433.     { to[top] = *from;
  434.       top++;
  435.     }
  436.     if (top > prec && ast > 0)
  437.     { /* Required precision exceeded and asterisk found */
  438.       to[ast] = '\0';                  /* Truncate at asterisk */
  439.       return;
  440.     }
  441.   }
  442.   to[top] = '\0';
  443.   return;
  444. }
  445.  
  446. /* casefix: select case of word. 1: first letter raised. 2: all raised. */
  447.  
  448. static casefix (text, upcase)
  449. char *text;
  450. int upcase;
  451. { if (upcase == 1)
  452.     *text = foldc (*text);
  453.   else if (upcase > 0)
  454.     foldup (text, text);
  455. }
  456.