home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0040 - 0049 / ibm0040-0049 / ibm0040.tar / ibm0040 / ZINC_5.ZIP / WINSRC.ZIP / DATE.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-01  |  9.4 KB  |  388 lines

  1. //    Zinc Interface Library - DATE.CPP
  2. //    COPYRIGHT (C) 1990, 1991.  All Rights Reserved.
  3. //    Zinc Software Incorporated.  Pleasant Grove, Utah  USA
  4.  
  5. #include "ui_gen.hpp"
  6. #include <dos.h>
  7. #include <ctype.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11.  
  12. static int _daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  13.  
  14. static int TokenMatch(char *table, const char *token, int length)
  15. {
  16.     if (toupper(*table) != toupper(*token))
  17.         return 0;            // No match.
  18.     while (length)
  19.     {
  20.         while (*table && toupper(*table) != toupper(*token))
  21.             table++;
  22.         if (toupper(*table) == toupper(*token))
  23.         {
  24.             table++;
  25.             token++;
  26.         }
  27.         else
  28.             return 0;        // No match.
  29.         length--;
  30.     }
  31.     return 1;                // Partial match.
  32. }
  33.  
  34. int UI_DATE::DayOfWeek()
  35. {
  36.     if (dYear <= 0 || dMonth == 0 || dDay == 0)
  37.         return (0);
  38.     int day = dDay;
  39.     int month = dMonth;
  40.     int year = dYear - 1700 - (month < 3);
  41.     long julianDate = 365L * (year + (month < 3)) + year / 4 - year / 100 +
  42.         (year + 100) / 400 + (305 * (month - 1) - (month > 2) * 20 +
  43.         (month > 7) * 5 + 5) / 10 + day + 4;
  44.     return ((int)(julianDate % 7) + 1);
  45. }
  46.  
  47. int UI_DATE::DaysInMonth()
  48. {
  49.     if (dMonth == 2 && LeapYear())
  50.         return (29);
  51.     return(_daysInMonth[dMonth - 1]);
  52. }
  53.  
  54. int UI_DATE::DaysInYear()
  55. {
  56.     return(LeapYear() ? 366 : 365);
  57. }
  58.  
  59. void UI_DATE::Export()
  60. {
  61.     struct date info;
  62.     info.da_year = dYear;
  63.     info.da_mon = dMonth;
  64.     info.da_day = dDay;
  65.     setdate(&info);
  66. }
  67.  
  68. void UI_DATE::Export(int *packedDate)
  69. {
  70.     *packedDate = ((dYear - 1980) << 9) | (dMonth << 5) | dDay;
  71. }
  72.  
  73. void UI_DATE::Export(int *year, int *month, int *day, int *dayOfWeek)
  74. {
  75.     if (year) *year = dYear;
  76.     if (month) *month = dMonth;
  77.     if (day) *day = dDay;
  78.     if (dayOfWeek) *dayOfWeek = DayOfWeek();
  79. }
  80.  
  81. void UI_DATE::Export(char *string, int maxLength, USHORT dtFlags)
  82. {
  83.     int dayOfWeek = DayOfWeek();
  84.     /* Get the initial separators */
  85.     ui_getcountryinfo();
  86.     char dateFormat = _countryInfo.co_date;
  87.     if (FlagSet(dtFlags, DTF_US_FORMAT))
  88.         dateFormat = 0;
  89.     else if (FlagSet(dtFlags, DTF_EUROPEAN_FORMAT | DTF_MILITARY_FORMAT))
  90.         dateFormat = 1;
  91.     else if (FlagSet(dtFlags, DTF_JAPANESE_FORMAT))
  92.         dateFormat = 2;
  93.     char separator = _countryInfo.co_dtsep[0];
  94.     if (FlagSet(dtFlags, DTF_DASH))
  95.         separator = '-';
  96.     else if (FlagSet(dtFlags, DTF_SLASH))
  97.         separator = '/';
  98.     char yearSize = 1;
  99.     char alphaMonth = FlagSet(dtFlags, DTF_ALPHA_MONTH) ? 2 : 0;
  100.     char showDayOfWeek = FlagSet(dtFlags, DTF_DAY_OF_WEEK) ? 2 : 0;
  101.     char autoShorten = TRUE;
  102.     USHORT zeroFill = FlagSet(dtFlags, DTF_ZERO_FILL);
  103.     if (FlagSet(dtFlags, DTF_SHORT_YEAR))
  104.     {
  105.         autoShorten = FALSE;
  106.         yearSize = 0;
  107.     }
  108.     if (FlagSet(dtFlags, DTF_SHORT_MONTH))
  109.     {
  110.         autoShorten = FALSE;
  111.         alphaMonth = 1;
  112.     }
  113.     if (FlagSet(dtFlags, DTF_SHORT_DAY))
  114.     {
  115.         autoShorten = FALSE;
  116.         showDayOfWeek = 1;
  117.     }
  118.     for (;;)
  119.     {
  120.         char tempDate[64];
  121.         char *ptr = tempDate;
  122.         if (showDayOfWeek && dayOfWeek)
  123.         {
  124.             char *shortDay = dayTable[dayOfWeek - 1].shortName;
  125.             if (showDayOfWeek == 1 && shortDay)
  126.                 strcpy(tempDate, shortDay);
  127.             else
  128.                 strcpy(tempDate, dayTable[dayOfWeek - 1].longName);
  129.             strcat(tempDate, "  ");
  130.             ptr = strchr(tempDate, '\0');
  131.         }
  132.         char s_year[10];
  133.         sprintf(s_year, dYear ? "%d" : "", yearSize ? dYear : dYear % 100);
  134.         char s_month[15];
  135.         if (FlagSet(dtFlags, DTF_MILITARY_FORMAT) && dMonth)
  136.         {
  137.             memcpy(s_month, monthTable[dMonth - 1].longName, 3);
  138.             s_month[3] = '\0';
  139.         }
  140.         else if (alphaMonth && dMonth)
  141.         {
  142.             char *shortMonth = monthTable[dMonth - 1].shortName;
  143.             if (alphaMonth == 1 && shortMonth)
  144.                 strcpy(s_month, shortMonth);
  145.             else
  146.                 strcpy(s_month, monthTable[dMonth - 1].longName);
  147.         }
  148.         else
  149.             sprintf(s_month, dMonth ? (zeroFill ? "%02d" : "%d") : "", dMonth);
  150.         char s_day[10];
  151.         sprintf(s_day, dDay ? (zeroFill ? "%02d" : "%d") : "", dDay);
  152.         char realSeparator = (FlagSet(dtFlags, DTF_MILITARY_FORMAT) || alphaMonth) ?
  153.             ' ' : separator;
  154.         if (dateFormat == 1)                // European
  155.             sprintf(ptr, "%s%c%s%c%s",
  156.                 s_day, realSeparator, s_month, realSeparator, s_year);
  157.         else if (dateFormat == 2)            // Japan
  158.             sprintf(ptr, "%s%c%s%c%s",
  159.                 s_year, realSeparator, s_month, realSeparator, s_day);
  160.         else                                // U.S.
  161.         {
  162.             if (dMonth && dDay && dYear && alphaMonth)
  163.                 sprintf(ptr, "%s %s, %s", s_month, s_day, s_year);
  164.             else
  165.                 sprintf(ptr, "%s%c%s%c%s",
  166.                         s_month, realSeparator, s_day, realSeparator, s_year);
  167.         }
  168.         // Strip leading separators.
  169.         while (*ptr == realSeparator)
  170.             memmove(ptr, ptr + 1, strlen(ptr));
  171.         // Strip trailing separators and double separators.
  172.         while (*ptr)
  173.         {
  174.             if (*ptr == realSeparator &&
  175.                  (*(ptr + 1) == realSeparator || *(ptr + 1) == '\0'))
  176.                 memmove(ptr, ptr + 1, strlen(ptr));
  177.             else
  178.                 ptr++;
  179.         }
  180.         if (FlagSet(dtFlags, DTF_UPPER_CASE))
  181.             strupr(tempDate);
  182.         if (strlen(tempDate) <= maxLength)
  183.         {
  184.             strcpy(string, tempDate);
  185.             break;
  186.         }
  187.         if (autoShorten)
  188.         {
  189.             if (showDayOfWeek == 2)
  190.                 showDayOfWeek--;
  191.             else if (alphaMonth == 2)
  192.                 alphaMonth--;
  193.             else if (yearSize)
  194.                 yearSize--;
  195.             else if (showDayOfWeek)
  196.                 showDayOfWeek--;
  197.             else if (alphaMonth)
  198.                 alphaMonth--;
  199.             else
  200.                 autoShorten = FALSE;
  201.         }
  202.         else
  203.         {
  204.             strcpy(string, tempDate);
  205.             break;
  206.         }
  207.     }
  208. }
  209.  
  210. DTI_RESULT UI_DATE::Import()
  211. {
  212.     struct date info;
  213.     getdate(&info);
  214.     return(Import(info.da_year, info.da_mon, info.da_day));
  215. }
  216.  
  217. DTI_RESULT UI_DATE::Import(int date)
  218. {
  219.     return(Import(1980 + ((date & 0xFE00) >> 9), (date & 0x01E0) >> 5, date & 0x001F));
  220. }
  221.  
  222. DTI_RESULT UI_DATE::Import(int year, int month, int day)
  223. {
  224.     int tYear = dYear;
  225.     dYear = year;
  226.     int tMonth = dMonth;
  227.     dMonth = month;
  228.     int tDay = dDay;
  229.     dDay = day;
  230.     if (year <= 0 || month < 0 || month > 12 || day < 0)
  231.     {
  232.         dYear = tYear;
  233.         dMonth = tMonth;
  234.         dDay = tDay;
  235.         return (DTI_INVALID);
  236.     }
  237.     else if (day <= _daysInMonth[month-1] ||
  238.         (month == 2 && day == 29 && LeapYear()))
  239.         return (DTI_OK);
  240.     dYear = tYear;
  241.     dMonth = tMonth;
  242.     dDay = tDay;
  243.     return (DTI_INVALID);
  244. }
  245.  
  246. DTI_RESULT UI_DATE::Import(const char *string, USHORT dtFlags)
  247. {
  248.     int tYear = 0;
  249.     int tMonth = 0;
  250.     int tDay = 0;
  251.  
  252.     ui_getcountryinfo();
  253.  
  254.     //    NOTE:  For the purposes of the date string conversion algorithm, we
  255.     //    are only concerned with the respective order of the month and day
  256.     //    fields.  Therefore, the only significance to the dateFormat values is
  257.     //    whether the value equals 1 or not.  We save a line of code by calling
  258.     //    the JAPANESE_FORMAT a 0 even though it is really a 2.
  259.     char dateFormat = _countryInfo.co_date;
  260.     if (FlagSet(dtFlags, DTF_US_FORMAT | DTF_JAPANESE_FORMAT))
  261.         dateFormat = 0;
  262.     else if (FlagSet(dtFlags, DTF_EUROPEAN_FORMAT | DTF_MILITARY_FORMAT))
  263.         dateFormat = 1;
  264.     int alphaMonth = FALSE;
  265.     int isBlank = TRUE;
  266.     while (*string)
  267.     {
  268.         if (isalpha(*string))
  269.         {
  270.             int monthValue = TableLookup(monthTable, 12, string);
  271.             if (!tMonth && monthValue < 0 ||
  272.                 (alphaMonth && monthValue > 0 && monthValue != tMonth))
  273.                 return DTI_AMBIGUOUS;    // Ambiguous.
  274.             if (!tMonth && monthValue > 0)
  275.                 tMonth = monthValue;
  276.             else if (tMonth && !tDay && !alphaMonth && monthValue > 0)
  277.             {
  278.                 // The "month" we thought we had must have been the day.
  279.                 tDay = tMonth;
  280.                 tMonth = monthValue;
  281.             }
  282.             else if (TableLookup(dayTable, 7, string) == 0)
  283.                 return DTI_INVALID_NAME;     // Invalid month or week day name.
  284.             if (monthValue > 0)
  285.                 alphaMonth = TRUE;
  286.             while (isalpha(*string))
  287.                 string++;
  288.             isBlank = FALSE;
  289.         }
  290.         else if (isdigit(*string))
  291.         {
  292.             int value = atoi(string);
  293.             if (value <= 0)
  294.                 return DTI_INVALID;    // Bad number.
  295.             if (value > 31)                    // Must be the year.
  296.             {
  297.                 if (tYear)
  298.                     return DTI_INVALID;
  299.                 else
  300.                     tYear = value < 100 ? 1900 + value : value;
  301.             }
  302.             else if (value > 12 || tMonth ||
  303.                      FlagSet(dtFlags, DTF_FORCE_ALPHA_MONTH))
  304.             {                            // Must be the day.
  305.                 if (tDay)
  306.                     return DTI_INVALID;
  307.                 else
  308.                     tDay = value;
  309.             }
  310.             else if (tDay)                // Must be the month.
  311.             {
  312.                 if (tMonth || FlagSet(dtFlags, DTF_FORCE_ALPHA_MONTH))
  313.                     return DTI_INVALID;
  314.                 else
  315.                     tMonth = value;
  316.             }
  317.             else                        // Could be month or day.
  318.             {
  319.                 if (dateFormat == 1)
  320.                     tDay = value;
  321.                 else
  322.                     tMonth = value;
  323.             }
  324.             while (isdigit(*string))
  325.                 string++;
  326.             isBlank = FALSE;
  327.         }
  328.         else
  329.             string++;            // Ignore spaces and punctuation.
  330.     }
  331.     if (tMonth && !alphaMonth && !tDay)
  332.     {
  333.         tDay = tMonth;                // Single digit is a day.
  334.         tMonth = 0;
  335.     }
  336.     UI_DATE today;
  337.     if (isBlank)
  338.     {
  339.         if (FlagSet(dtFlags, DTF_SYSTEM))
  340.         {
  341.             tYear = today.dYear;
  342.             tMonth = today.dMonth;
  343.             tDay = today.dDay;
  344.         }
  345.         else
  346.         {
  347.             Import(0, 0, 0);                // Zero all fields.
  348.             return DTI_VALUE_MISSING;
  349.         }
  350.     }
  351.     return Import(tYear, tMonth, tDay);
  352. }
  353.  
  354. int UI_DATE::LeapYear()
  355. {
  356.     // Return TRUE if a leap year, else FALSE.
  357.     return((dYear % 400 == 0) || ((dYear % 4 == 0) && (dYear % 100 != 0)));
  358. }
  359.  
  360. int UI_DATE::TableLookup(NAME_PAIR *table, int tableLength,
  361.     const char *token)
  362. {
  363.     const char *ptr = token;
  364.     int length = 0;
  365.     int match = 0;
  366.  
  367.     while (isalpha(*ptr))
  368.     {
  369.         ptr++;
  370.         length++;
  371.     }
  372.     for (int i = 0; i < tableLength; i++)
  373.     {
  374.         int result = TokenMatch(table[i].longName, token, length);
  375.         if (result == 2)
  376.             return i + 1;                    // Full match.
  377.         else if (result)
  378.         {
  379.             if (match)
  380.                 return -1;                    // Ambiguous.
  381.             else
  382.                 match = i + 1;
  383.         }
  384.     }
  385.     return match;
  386. }
  387.  
  388.