home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d128 / mrbackup.lha / MRBackup / MRDates.c < prev    next >
C/C++ Source or Header  |  1988-01-02  |  10KB  |  422 lines

  1.  
  2. /* General routines to provide date support for the DateStamp
  3.  * date format.
  4.  *
  5.  * Author:        Mark R. Rinfret    (mark@unisec.usi.com)
  6.  * Date:        07/18/87
  7.  *
  8.  * This source is released to the public domain by the author, without
  9.  * restrictions.  However, it is requested that you give credit where
  10.  * credit is due and share any bug fixes or enhancements with him.
  11.  *
  12.  * History:        (most recent change first)
  13.  *
  14.  * 08/20/87 -MRR- Gack!  I wrote this?  In the interests of orthogonality,
  15.  *                I have replaced SetDateStamp with PackDS, the inverse
  16.  *                of UnpackDS.  I have also renamed the package MRDates
  17.  *                to provide a unique name, hopefully relieving conflicts
  18.  *                with other packages providing date/time functions.  The
  19.  *                  UnpackedDS type is now defined in MRDates.h and can
  20.  *                be included by modules which require PackDS and UnpackDS.
  21.  */
  22.  
  23. /* The following #define MUST be set to inhibit certain declarations in
  24.  * the include file MRDates.h:
  25.  */
  26.  
  27. #define MRDATES
  28.  
  29. #include <libraries/dos.h>
  30. #include <exec/memory.h>
  31. #include <ctype.h>
  32. #include <functions.h>
  33. #include "MRDates.h"
  34.  
  35. /* #define DEBUG */
  36.  
  37.  
  38. char *daynames[] = {
  39.     "Sunday", "Monday", "Tuesday", "Wednesday", 
  40.     "Thursday", "Friday", "Saturday"
  41.     };
  42.  
  43. USHORT monthdays[12] =  {0,31,59,90,120,151,181,212,243,273,304,334};
  44.  
  45. char *monthnames[12] = {
  46.     "January", "February", "March", "April", "May", "June",
  47.     "July", "August", "September", "October", "November", "December"
  48.     };
  49.  
  50. /* Compare two DateStamp values.
  51.  * Called with:
  52.  *        d1,d2:        pointers to DateStamp structs
  53.  * 
  54.  * Returns:
  55.  *        < 0 => d1 < d2
  56.  *          0 => d1 == d2
  57.  *        > 0 => d1 > d2
  58.  *
  59.  * Note:
  60.  *        This routine makes an assumption about the DateStamp structure,
  61.  *        specifically that it can be viewed as an array of 3 long integers
  62.  *        in days, minutes and ticks order.
  63.  */
  64.  
  65. int 
  66. CompareDS(d1, d2)
  67.     long *d1, *d2;
  68. {
  69.     USHORT i;
  70.     long compare;
  71.  
  72.     for (i = 0; i < 3; ++i) {
  73.         if (compare = (d1[i] - d2[i])) {
  74.             if (compare < 0) return -1;
  75.             return 1;
  76.         }
  77.     }
  78.     return 0;                        /* dates match */
  79. }
  80.  
  81. /* Convert a DateStamp to a formatted string.
  82.  * Called with:
  83.  *        fmt:    format string
  84.  *            The format of the format string is very similar to that
  85.  *            for printf, with the exception that the following letters
  86.  *            have special significance:
  87.  *                y => year minus 1900
  88.  *                Y => full year value
  89.  *                m => month value as integer
  90.  *                M => month name
  91.  *                d => day of month (1..31)
  92.  *                D => day name ("Monday".."Sunday")
  93.  *                h => hour in twenty-four hour notation
  94.  *                H => hour in twelve hour notation
  95.  *                i => 12 hour indicator for H notation (AM or PM)
  96.  *                I => same as i
  97.  *                n => minutes    (sorry...conflict with m = months)
  98.  *                N => same as n
  99.  *                s => seconds
  100.  *                S => same as s
  101.  *
  102.  *            All other characters are passed through as part of the normal
  103.  *            formatting process.  The following are some examples with
  104.  *            Saturday, July 18, 1987, 13:53 as an input date:
  105.  *
  106.  *                "%y/%m/%d"            => 87/7/18
  107.  *                "%02m/%02d/%2y"        => 07/18/87
  108.  *                "%D, %M %d, %Y"        => Saturday, July 18, 1987
  109.  *                "%02H:%02m i"        => 01:53 PM
  110.  *                "Time now: %h%m"    => Time now: 13:53
  111.  *
  112.  *        str:    string to write date on
  113.  *        d:        pointer to DateStamp structure
  114.  *        
  115.  */
  116. void
  117. DS2Str(str,fmt,d)
  118.     char *str, *fmt; struct DateStamp *d;
  119. {
  120.     UnpackedDS date;
  121.     char fc,*fs,*out;
  122.     USHORT ivalue;
  123.     char new_fmt[256];            /* make it big to be "safe" */
  124.     USHORT new_fmt_lng;
  125.     char *svalue;
  126.  
  127.     UnpackDS(d, &date);            /* convert DateStamp to unpacked format */
  128.  
  129.     *str = '\0';                /* insure output is empty */
  130.     out = str;
  131.     fs = fmt;                    /* make copy of format string pointer */
  132.  
  133.     while (fc = *fs++) {        /* get format characters */
  134.         if (fc == '%') {        /* formatting meta-character? */
  135.             new_fmt_lng = 0;
  136.             new_fmt[new_fmt_lng++] = fc;
  137.             /* copy width information */
  138.             while (isdigit(fc = *fs++) || fc == '-')
  139.                 new_fmt[new_fmt_lng++] = fc;
  140.  
  141.             switch (fc) {        /* what are we trying to do? */
  142.             case 'y':            /* year - 1980 */
  143.                 ivalue = date.year - 1900;
  144. write_int:
  145.                 new_fmt[new_fmt_lng++] = 'd';
  146.                 new_fmt[new_fmt_lng] = '\0';
  147.                 sprintf(out,new_fmt,ivalue);
  148.                 out = str + strlen(str);
  149.                 break;
  150.             case 'Y':            /* full year value */
  151.                 ivalue = date.year;
  152.                 goto write_int;
  153.  
  154.             case 'm':            /* month */
  155.                 ivalue = date.month;
  156.                 goto write_int;
  157.  
  158.             case 'M':            /* month name */
  159.                 svalue = monthnames[date.month - 1];
  160. write_str:
  161.                 new_fmt[new_fmt_lng++] = 's';
  162.                 new_fmt[new_fmt_lng] = '\0';
  163.                 sprintf(out,new_fmt,svalue);
  164.                 out = str + strlen(str);
  165.                 break;
  166.  
  167.             case 'd':            /* day */
  168.                 ivalue = date.day;
  169.                 goto write_int;
  170.  
  171.             case 'D':            /* day name */
  172.                 svalue = daynames[d->ds_Days % 7];
  173.                 goto write_str;
  174.  
  175.             case 'h':            /* hour */
  176.                 ivalue = date.hour;
  177.                 goto write_int;
  178.  
  179.             case 'H':            /* hour in 12 hour notation */
  180.                 ivalue = date.hour;
  181.                 if (ivalue >= 12) ivalue -= 12;
  182.                 goto write_int;
  183.  
  184.             case 'i':            /* AM/PM indicator */
  185.             case 'I':
  186.                 if (date.hour >= 12)
  187.                     svalue = "PM";
  188.                 else
  189.                     svalue = "AM";
  190.                 goto write_str;
  191.  
  192.             case 'n':            /* minutes */
  193.             case 'N':
  194.                 ivalue = date.minute;
  195.                 goto write_int;
  196.  
  197.             case 's':            /* seconds */
  198.             case 'S':
  199.                 ivalue = date.second;
  200.                 goto write_int;
  201.  
  202.             default:
  203.                 /* We are in deep caca - don't know what to do with this
  204.                  * format character.  Copy the raw format string to the
  205.                  * output as debugging information.
  206.                  */
  207.                 new_fmt[new_fmt_lng++] = fc;
  208.                 new_fmt[new_fmt_lng] = '\0';
  209.                 strcat(out, new_fmt);
  210.                 out = out + strlen(out);    /* advance string pointer */
  211.                 break;
  212.             }
  213.         }
  214.         else
  215.             *out++ = fc;        /* copy literal character */
  216.     }
  217.     *out = '\0';                /* terminating null */
  218. }
  219.  
  220. /* Convert a string to a DateStamp.
  221.  * Called with:
  222.  *        str:    string containing date in MM/DD/YY format        
  223.  *        d:        pointer to DateStamp structure
  224.  * Returns:
  225.  *        status code (0 => success, 1 => failure)
  226.  */
  227.  
  228. int
  229. Str2DS(str, d)
  230.     char *str; struct DateStamp *d;
  231. {
  232.     register char c;
  233.     int count;
  234.     int i, item;
  235.     UnpackedDS upd;                /* unpacked DateStamp */
  236.     char *s;
  237.  
  238.     int values[3];
  239.     int value;
  240.     
  241.  
  242.     s = str;
  243.     for (item = 0; item < 2; ++item) {    /* item = date, then time */
  244.         for (i = 0; i < 3; ++i) values[i] = 0;
  245.         count = 0;
  246.         while (c = *s++) {            /* get date value */
  247.             if (c <= ' ') 
  248.                 break;
  249.  
  250.             if (isdigit(c)) {
  251.                 value = 0;
  252.                 do {
  253.                     value = value*10 + c - '0';
  254.                     c = *s++;
  255.                 } while (isdigit(c));
  256.                 if (count == 3) {
  257.     bad_value:
  258. #ifdef DEBUG
  259.                     puts("Error in date-time format.\n");
  260.                     printf("at %s: values(%d) = %d, %d, %d\n",
  261.                         s, count, values[0], values[1], values[2]);
  262. #endif
  263.                     return 1;
  264.                 }
  265.                 values[count++] = value;
  266.                 if (c <= ' ')
  267.                     break;
  268.             }
  269.         }                            /* end while */
  270.         if (item) {                    /* getting time? */
  271.             upd.hour = values[0];
  272.             upd.minute = values[1];
  273.             upd.second = values[2];
  274.         }
  275.         else {                        /* getting date? */
  276.  
  277. /* It's OK to have a null date string, but it's not OK to specify only
  278.  * 1 or 2 of the date components.
  279.  */
  280.             if (count && count != 3)
  281.                 goto bad_value;
  282.             upd.month = values[0];
  283.             upd.day = values[1];
  284.             upd.year = values[2];
  285.         }
  286.     }                                /* end for */
  287.     PackDS(d,&upd);
  288.     return 0;
  289. }
  290.  
  291.  
  292. /* Set a DateStamp structure, given the date/time components.
  293.  * Called with:
  294.  *        d:            pointer to DateStamp
  295.  *      upd:        pointer to UnpackedDS
  296.  */
  297. PackDS(d,upd)
  298.     struct DateStamp *d; UnpackedDS *upd;
  299. {
  300.     USHORT leapyear;
  301.     short year,month,day,hour,minute,second;
  302.  
  303.     year = upd->year;            /* copy date components to locals */
  304.     month = upd->month;
  305.     day = upd->day;
  306.     hour = upd->hour;
  307.     minute = upd->minute;
  308.     second = upd->second;
  309.  
  310.     if (year > 1900)
  311.         year = year - 1900;
  312.  
  313.     leapyear = (year % 4 ? 0 : 1);
  314.  
  315.     year = year - 78;
  316.     if (month < 1 || month > 12)    /* somebody goofed? */
  317.         month = 1;
  318.  
  319.     day = day - 1 + monthdays[month-1];
  320.     if (leapyear && (month > 2))
  321.         ++day;
  322.  
  323.     d->ds_Days = year * 365 + (year + 1) / 4 + day;
  324.     d->ds_Minute = hour * 60 + minute;
  325.     d->ds_Tick = second * TICKS_PER_SECOND;
  326. }
  327.  
  328. /* Unpack a DateStamp structure into an UnpackedDS structure. 
  329.  * Called with:
  330.  *        ds:        pointer to DateStamp structure
  331.  *        du:        pointer to UnpackedDS structure
  332.  */
  333. UnpackDS(ds, du)
  334.     struct DateStamp *ds; UnpackedDS *du;
  335. {
  336.     USHORT i, leap_years, leap, temp, test_value;
  337.  
  338.     du->year = ds->ds_Days / 365 + 1978;
  339.     
  340.     /* is current year a leapyear? */
  341.     leap = ( (du->year % 4) == 0); 
  342.  
  343.     /* how many leap years since "beginning of time"? */
  344.     leap_years = (du->year - 1976 - 1) / 4;
  345.  
  346.     /* get days remaining in year */
  347.     temp = ds->ds_Days % 365 - leap_years;
  348.  
  349.     /* find month */
  350.  
  351.     du->month = 0;
  352.     du->day = 0;
  353.     for (i = 11; i >= 0; --i) {
  354.         test_value = monthdays[i];
  355.         if (i > 2) test_value += leap;
  356.         if (temp >= test_value) {
  357.             du->month = i + 1;
  358.             du->day = temp - test_value + 1;
  359.             break;
  360.         }
  361.     }
  362.  
  363.     du->hour = ds->ds_Minute / 60;
  364.     du->minute = ds->ds_Minute % 60;
  365.     du->second = ds->ds_Tick / TICKS_PER_SECOND;
  366. }
  367.  
  368.  
  369. #ifdef DEBUG
  370. main()
  371. {
  372.     int compflag;
  373.     char datestr[81], instr[81];
  374.     struct DateStamp *ds, *now;
  375.     UnpackedDS du;
  376.  
  377.     now = (struct DateStamp *) 
  378.         AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC);
  379.  
  380.     ds = (struct DateStamp *) 
  381.         AllocMem((long) sizeof(struct DateStamp), MEMF_PUBLIC);
  382.  
  383.     puts("Enter a date string and I will convert it.  To quit, hit RETURN");
  384.     while (1) {
  385.         DateStamp(now);
  386.         UnpackDS(now, &du);
  387.  
  388.         printf("\nCurrent date and time: %02d/%02d/%02d %02d:%02d:%02d\n",
  389.             du.month,du.day,du.year,du.hour,du.minute,du.second);
  390.  
  391.         puts("\nEnter the date [and time]:");
  392.         gets(instr);
  393.         if (*instr == '\0') break;
  394.         if (Str2DS(instr,ds))
  395.             puts("Error encountered in input string");
  396.         else {
  397.             DS2Str(datestr, "%02m/%02d/%02y %02h:%02n:%02s", ds);
  398.             puts(datestr);
  399.  
  400.             DS2Str(datestr, "%D, %M %d, %Y", ds);
  401.             puts(datestr);
  402.  
  403.             DS2Str(datestr, "The time entered is %02H:%02N %i", ds);
  404.             puts(datestr);
  405.  
  406.             compflag = CompareDS(ds,now);
  407.             printf("The date input is ");
  408.             if (compflag < 0)
  409.                 printf("earlier than");
  410.             else if (compflag == 0)
  411.                 printf("the same as");
  412.             else
  413.                 printf("later than");
  414.             puts(" the current date.");
  415.         }
  416.     }
  417.  
  418.     FreeMem(ds, (long) sizeof(struct DateStamp));
  419.     FreeMem(now, (long) sizeof(struct DateStamp));
  420. }
  421. #endif
  422.