home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / OS2MNX1.ZIP / CAL.C next >
C/C++ Source or Header  |  1989-12-28  |  9KB  |  347 lines

  1. /* $Header: D:/RCS/RCS/cal.c 1.1 89/12/26 22:57:46 RCA Exp $
  2.  * $Log:    cal.c $
  3.  * Revision 1.1  89/12/26  22:57:46  RCA
  4.  * Initial revision
  5.  * 
  6.  */
  7.  
  8. /* cal - print a calendar               Author: Martin Minow */
  9.  
  10. #include <stdio.h>
  11.  
  12. #define do3months    domonth
  13. #define    IO_SUCCESS    0
  14. #define    IO_ERROR    1
  15. #define    EOS    0
  16.  
  17. #define    ENTRY_SIZE    3
  18. #define DAYS_PER_WEEK    7
  19. #define    WEEKS_PER_MONTH    6
  20. #define    MONTHS_PER_LINE    3
  21. #define    MONTH_SPACE    3
  22.  
  23. char   *badarg = {"Bad argument\n"};
  24. char   *how = {"Usage: cal [month] year (4 digits)\n"};
  25. /*
  26.  * calendar() stuffs data into layout[], output() copies from
  27.  * layout[] to outline[], (then trims blanks). 
  28.  */
  29. char    layout[MONTHS_PER_LINE][WEEKS_PER_MONTH][DAYS_PER_WEEK][ENTRY_SIZE];
  30. char    outline[(MONTHS_PER_LINE * DAYS_PER_WEEK * ENTRY_SIZE)
  31.         +       (MONTHS_PER_LINE * MONTH_SPACE)
  32.         +       1];
  33.  
  34. char   *weekday = " S  M Tu  W Th  F  S";
  35. char   *monthname[] = {
  36.                "???",    /* No month 0     */
  37.                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  38.                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  39. };
  40. main(argc, argv)
  41.    int     argc;
  42.    char   *argv[];
  43. {
  44. register int month;
  45. register int year;
  46.  
  47. register int arg1val;
  48. int     arg1len;
  49. int     arg2val;
  50.    if (argc <= 1)
  51.    {
  52.       usage(how);
  53.    } else
  54.    {
  55.       arg1val = atoi(argv[1]);
  56.       arg1len = strlen(argv[1]);
  57.       if (argc == 2)
  58.       {
  59.       /*
  60.        * Only one argument, if small, it's a month.  If large,
  61.        * it's a year.  Note: cal    0082    Year 0082 cal 82
  62.        * Year 0082 
  63.        */
  64.      if (arg1len <= 2 && arg1val <= 12)
  65.         do3months(year, arg1val);
  66.      else
  67.         doyear(arg1val);
  68.       } else
  69.       {
  70.       /*
  71.        * Two arguments, allow 1980 12 or 12 1980 
  72.        */
  73.      arg2val = atoi(argv[2]);
  74.      if (arg1len > 2)
  75.         do3months(arg1val, arg2val);
  76.      else
  77.         do3months(arg2val, arg1val);
  78.       }
  79.    }
  80.    exit(IO_SUCCESS);
  81. }
  82. doyear(year)
  83.    int     year;
  84. /*
  85.  * Print the calendar for an entire year. 
  86.  */
  87. {
  88. register int month;
  89.    if (year < 1 || year > 9999)
  90.       usage(badarg);
  91.    if (year < 100)
  92.       printf("\n\n\n                                 00%2d\n\n", year);
  93.    else
  94.       printf("\n\n\n%35d\n\n", year);
  95.    for (month = 1; month <= 12; month += MONTHS_PER_LINE)
  96.    {
  97.       printf("%12s%23s%23s\n",
  98.          monthname[month],
  99.          monthname[month + 1],
  100.          monthname[month + 2]);
  101.       printf("%s   %s   %s\n", weekday, weekday, weekday);
  102.       calendar(year, month + 0, 0);
  103.       calendar(year, month + 1, 1);
  104.       calendar(year, month + 2, 2);
  105.       output(3);
  106. #if MONTHS_PER_LINE != 3
  107.       <<error, the above won 't work >>
  108. #endif
  109.    }
  110.    printf("\n\n\n");
  111. }
  112. domonth(year, month)
  113.    int     year;
  114.    int     month;
  115. /*
  116.  * Do one specific month -- note: no longer used 
  117.  */
  118. {
  119.    if (year < 1 || year > 9999)
  120.       usage(badarg);
  121.    if (month <= 0 || month > 12)
  122.       usage(badarg);
  123.    printf("%9s%5d\n\n%s\n", monthname[month], year, weekday);
  124.    calendar(year, month, 0);
  125.    output(1);
  126.    printf("\n\n");
  127. }
  128. output(nmonths)
  129.    int     nmonths;    /* Number of months to do     */
  130. /*
  131.  * Clean up and output the text. 
  132.  */
  133. {
  134. register int week;
  135. register int month;
  136. register char *outp;
  137. int     i;
  138. char    tmpbuf[21], *p;
  139.    for (week = 0; week < WEEKS_PER_MONTH; week++)
  140.    {
  141.       outp = outline;
  142.       for (month = 0; month < nmonths; month++)
  143.       {
  144.       /*
  145.        * The -1 in the following removes the unwanted leading
  146.        * blank from the entry for Sunday. 
  147.        */
  148.      p = &layout[month][week][0][1];
  149.      for (i = 0; i < 20; i++)
  150.         tmpbuf[i] = *p++;
  151.      tmpbuf[20] = 0;
  152.      sprintf(outp, "%s   ", tmpbuf);
  153.      outp += (DAYS_PER_WEEK * ENTRY_SIZE) + MONTH_SPACE - 1;
  154.       }
  155.       while (outp > outline && outp[-1] == ' ')
  156.      outp--;
  157.       *outp = EOS;
  158.       puts(outline);
  159.    }
  160. }
  161. calendar(year, month, index)
  162.    int     year;
  163.    int     month;
  164.    int     index;    /* Which of the three months         */
  165. /*
  166.  * Actually build the calendar for this month. 
  167.  */
  168. {
  169. register char *tp;
  170. int     week;
  171. register int wday;
  172. register int today;
  173.    setmonth(year, month);
  174.    for (week = 0; week < WEEKS_PER_MONTH; week++)
  175.    {
  176.       for (wday = 0; wday < DAYS_PER_WEEK; wday++)
  177.       {
  178.      tp = &layout[index][week][wday][0];
  179.      *tp++ = ' ';
  180.      today = getdate(week, wday);
  181.      if (today <= 0)
  182.      {
  183.         *tp++ = ' ';
  184.         *tp++ = ' ';
  185.      } else
  186.      if (today < 10)
  187.      {
  188.         *tp++ = ' ';
  189.         *tp = (today + '0');
  190.      } else
  191.      {
  192.         *tp++ = (today / 10) + '0';
  193.         *tp = (today % 10) + '0';
  194.      }
  195.       }
  196.    }
  197. }
  198. usage(s)
  199.    char   *s;
  200. {
  201. /* Fatal parameter error. */
  202.  
  203.    fprintf(stderr, "%s", s);
  204.    exit(IO_ERROR);
  205. }
  206. /*
  207.  * Calendar routines, intended for eventual porting to TeX 
  208.  *
  209.  * date(year, month, week, wday) Returns the date on this week (0 is
  210.  * first, 5 last possible) and day of the week (Sunday == 0)
  211.  * Note: January is month 1. 
  212.  *
  213.  * setmonth(year, month) Parameters are as above, sets getdate() for
  214.  * this month. 
  215.  *
  216.  * int getdate(week, wday) Parameters are as above, uses the data
  217.  * set by setmonth() 
  218.  */
  219. /*
  220.  * This structure is used to pass data between setmonth() and
  221.  * getdate(). It needs considerable expansion if the
  222.  * Julian->Gregorian change is to be extended to other countries. 
  223.  */
  224.  
  225. static struct
  226. {
  227.    int     this_month;    /* month number used in 1752 checking     */
  228.    int     feb;        /* Days in February for this month     */
  229.    int     sept;    /* Days in September for this month     */
  230.    int     days_in_month;    /* Number of days in this month         */
  231.    int     dow_first;    /* Day of week of the 1st day in month     */
  232. }       info;
  233.  
  234. static int day_month[] = {    /* 30 days hath September...         */
  235.            0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  236. };
  237.  
  238. int
  239. date(year, month, week, wday)
  240.    int     year;    /* Calendar date being computed         */
  241.    int     month;    /* January == 1                 */
  242.    int     week;    /* Week in the month 0..5 inclusive     */
  243.    int     wday;    /* Weekday, Sunday == 0             */
  244. /*
  245.  * Return the date of the month that fell on this week and
  246.  * weekday. Return zero if it's out of range. 
  247.  */
  248. {
  249.    setmonth(year, month);
  250.    return (getdate(week, wday));
  251. }
  252. setmonth(year, month)
  253.    int     year;    /* Year to compute         */
  254.    int     month;    /* Month, January is month 1     */
  255. /*
  256.  * Setup the parameters needed to compute this month (stored in
  257.  * the info structure). 
  258.  */
  259. {
  260. register int i;
  261.    if (month < 1 || month > 12)
  262.    {                /* Verify caller's parameters     */
  263.       info.days_in_month = 0;    /* Garbage flag             */
  264.       return;
  265.    }
  266.    info.this_month = month;    /* used in 1752    checking     */
  267.    info.dow_first = Jan1(year);    /* Day of January 1st for now     */
  268.    info.feb = 29;        /* Assume leap year         */
  269.    info.sept = 30;        /* Assume normal year         */
  270. /*
  271.  * Determine whether it's an ordinary year, a leap year or the
  272.  * magical calendar switch year of 1752. 
  273.  */
  274.    switch ((Jan1(year + 1) + 7 - info.dow_first) % 7)
  275.    {
  276.    case 1:            /* Not a leap year         */
  277.       info.feb = 28;
  278.    case 2:            /* Ordinary leap year         */
  279.       break;
  280.  
  281.    default:            /* The magical moment arrives     */
  282.       info.sept = 19;        /* 19 days hath September     */
  283.       break;
  284.    }
  285.    info.days_in_month =
  286.        (month == 2) ? info.feb
  287.        : (month == 9) ? info.sept
  288.        : day_month[month];
  289.    for (i = 1; i < month; i++)
  290.    {
  291.       switch (i)
  292.       {                /* Special months?         */
  293.       case 2:            /* February             */
  294.      info.dow_first += info.feb;
  295.      break;
  296.  
  297.       case 9:
  298.      info.dow_first += info.sept;
  299.      break;
  300.  
  301.       default:
  302.      info.dow_first += day_month[i];
  303.      break;
  304.       }
  305.    }
  306.    info.dow_first %= 7;        /* Now it's Sunday to Saturday     */
  307. }
  308.  
  309. int
  310. getdate(week, wday)
  311.    int     week;
  312.    int     wday;
  313. {
  314. register int today;
  315. /*
  316.  * Get a first guess at today's date and make sure it's in range. 
  317.  */
  318.    today = (week * 7) + wday - info.dow_first + 1;
  319.    if (today <= 0 || today > info.days_in_month)
  320.       return (0);
  321.    else
  322.       if (info.sept == 19 && info.this_month == 9
  323.       && today >= 3)    /* The magical month?     */
  324.       return (today + 11);    /* If so, some dates changed     */
  325.    else                /* Otherwise,             */
  326.       return (today);        /* Return the date         */
  327. }
  328.  
  329. static int
  330. Jan1(year)
  331.    int     year;
  332. /*
  333.  * Return day of the week for Jan 1 of the specified year. 
  334.  */
  335. {
  336. register int day;
  337.    day = year + 4 + ((year + 3) / 4);    /* Julian Calendar     */
  338.    if (year > 1800)
  339.    {                /* If it's recent, do     */
  340.       day -= ((year - 1701) / 100);    /* Clavian correction     */
  341.       day += ((year - 1601) / 400);    /* Gregorian correction     */
  342.    }
  343.    if (year > 1752)        /* Adjust for Gregorian     */
  344.       day += 3;            /* calendar         */
  345.    return (day % 7);
  346. }
  347.