home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: InfoMgt / InfoMgt.zip / CAL32.ZIP / cal.c < prev    next >
Text File  |  1992-09-06  |  10KB  |  366 lines

  1.  
  2. #include <sys/types.h>
  3. #include <sys/time.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <ctype.h>
  7.  
  8. #define    THURSDAY        4        /* for reformation */
  9. #define    SATURDAY         6        /* 1 Jan 1 was a Saturday */
  10.  
  11. #define    FIRST_MISSING_DAY     639787        /* 3 Sep 1752 */
  12. #define    NUMBER_MISSING_DAYS     11        /* 11 day correction */
  13.  
  14. #define    MAXDAYS            42        /* max slots in a month array */
  15. #define    SPACE            -1        /* used in day array */
  16.  
  17. static int days_in_month[2][13] = {
  18.     {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  19.     {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  20. };
  21.  
  22. int sep1752[MAXDAYS] = {
  23.     SPACE,    SPACE,    1,    2,    14,    15,    16,
  24.     17,    18,    19,    20,    21,    22,    23,
  25.     24,    25,    26,    27,    28,    29,    30,
  26.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  27.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  28.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  29. }, j_sep1752[MAXDAYS] = {
  30.     SPACE,    SPACE,    245,    246,    258,    259,    260,
  31.     261,    262,    263,    264,    265,    266,    267,
  32.     268,    269,    270,    271,    272,    273,    274,
  33.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  34.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  35.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  36. }, empty[MAXDAYS] = {
  37.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  38.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  39.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  40.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  41.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  42.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  43. };
  44.  
  45. char *month_names[12] = {
  46.     "January", "February", "March", "April", "May", "June",
  47.     "July", "August", "September", "October", "November", "December",
  48. };
  49.  
  50. char *day_headings = " S  M Tu  W Th  F  S";
  51. char *j_day_headings = "  S   M  Tu   W  Th   F   S";
  52.  
  53. /* leap year -- account for gregorian reformation in 1752 */
  54. #define    leap_year(yr) \
  55.     ((yr) <= 1752 ? !((yr) % 4) : \
  56.     !((yr) % 4) && ((yr) % 100) || !((yr) % 400))
  57.  
  58. /* number of centuries since 1700, not inclusive */
  59. #define    centuries_since_1700(yr) \
  60.     ((yr) > 1700 ? (yr) / 100 - 17 : 0)
  61.  
  62. /* number of centuries since 1700 whose modulo of 400 is 0 */
  63. #define    quad_centuries_since_1700(yr) \
  64.     ((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
  65.  
  66. /* number of leap years between year 1 and this year, not inclusive */
  67. #define    leap_years_since_year_1(yr) \
  68.     ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
  69.  
  70. int julian;
  71.  
  72. void
  73. main(argc, argv)
  74.     int argc;
  75.     char **argv;
  76. {
  77.     extern char *optarg;
  78.     extern int optind;
  79.     struct tm *local_time;
  80.     time_t now, time();
  81.     int ch, month, year, yflag;
  82.  
  83.     yflag = 0;
  84.     while ((ch = getopt(argc, argv, "jy")) != EOF)
  85.         switch(ch) {
  86.         case 'j':
  87.             julian = 1;
  88.             break;
  89.         case 'y':
  90.             yflag = 1;
  91.             break;
  92.         case '?':
  93.         default:
  94.             usage();
  95.         }
  96.     argc -= optind;
  97.     argv += optind;
  98.  
  99.     month = 0;
  100.     switch(argc) {
  101.     case 2:
  102.         if ((month = atoi(*argv++)) <= 0 || month > 12) {
  103.             (void)fprintf(stderr,
  104.                 "cal: illegal month value: use 0-12\n");
  105.             exit(1);
  106.         }
  107.         /* FALLTHROUGH */
  108.     case 1:
  109.         if ((year = atoi(*argv)) <= 0 || year > 9999) {
  110.             (void)fprintf(stderr,
  111.                 "cal: illegal year value: use 0-9999\n");
  112.             exit(1);
  113.         }
  114.         break;
  115.     case 0:
  116.         (void)time(&now);
  117.         local_time = localtime(&now);
  118.         year = local_time->tm_year + 1900;
  119.         if (!yflag)
  120.             month = local_time->tm_mon + 1;
  121.         break;
  122.     default:
  123.         usage();
  124.     }
  125.  
  126.     if (month)
  127.         monthly(month, year);
  128.     else if (julian)
  129.         j_yearly(year);
  130.     else
  131.         yearly(year);
  132.     exit(0);
  133. }
  134.  
  135. #define    DAY_LEN    3        /* 3 spaces per day */
  136. #define    J_DAY_LEN    4        /* 4 spaces per day */
  137. #define    WEEK_LEN    20        /* 7 * 3 - one space at the end */
  138. #define    J_WEEK_LEN    27        /* 7 * 4 - one space at the end */
  139. #define    HEAD_SEP    2        /* spaces between day headings */
  140. #define    J_HEAD_SEP    2
  141.  
  142. monthly(month, year)
  143.     int month, year;
  144. {
  145.     register int col, row;
  146.     register char *p;
  147.     int len, days[MAXDAYS];
  148.     char lineout[30];
  149.  
  150.     (void)memset(lineout, ' ', sizeof(lineout) - 1);
  151.     lineout[sizeof(lineout) - 1] = '\0';
  152.     day_array(month, year, days);
  153.     len = sprintf(lineout, "%s %d", month_names[month - 1], year);
  154.     (void)printf("%*s%s\n%s\n",
  155.         ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "",
  156.         lineout, julian ? j_day_headings : day_headings);
  157.     for (row = 0; row < 6; row++) {
  158.         for (col = 0, p = lineout; col < 7; col++,
  159.             p += julian ? J_DAY_LEN : DAY_LEN)
  160.             ascii_day(p, days[row * 7 + col]);
  161.         trim_trailing_spaces(lineout);
  162.         (void)printf("%s\n", lineout);
  163.     }
  164. }
  165.  
  166. j_yearly(year)
  167.     int year;
  168. {
  169.     register int col, *dp, i, month, row, which_cal;
  170.     register char *p;
  171.     int days[12][MAXDAYS];
  172.     char lineout[80];
  173.  
  174.     (void)sprintf(lineout, "%d", year);
  175.     center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0);
  176.     (void)printf("\n\n");
  177.     for (i = 0; i < 12; i++)
  178.         day_array(i + 1, year, days[i]);
  179.     (void)memset(lineout, ' ', sizeof(lineout) - 1);
  180.     lineout[sizeof(lineout) - 1] = '\0';
  181.     for (month = 0; month < 12; month += 2) {
  182.         center(month_names[month], J_WEEK_LEN, J_HEAD_SEP);
  183.         center(month_names[month + 1], J_WEEK_LEN, 0);
  184.         (void)printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "",
  185.             j_day_headings);
  186.         for (row = 0; row < 6; row++) {
  187.             for (which_cal = 0; which_cal < 2; which_cal++) {
  188.                 p = lineout + which_cal * (J_WEEK_LEN + 2);
  189.                 dp = &days[month + which_cal][row * 7];
  190.                 for (col = 0; col < 7; col++, p += J_DAY_LEN)
  191.                     ascii_day(p, *dp++);
  192.             }
  193.             trim_trailing_spaces(lineout);
  194.             (void)printf("%s\n", lineout);
  195.         }
  196.     }
  197.     (void)printf("\n");
  198. }
  199.  
  200. yearly(year)
  201.     int year;
  202. {
  203.     register int col, *dp, i, month, row, which_cal;
  204.     register char *p;
  205.     int days[12][MAXDAYS];
  206.     char lineout[80];
  207.  
  208.     (void)sprintf(lineout, "%d", year);
  209.     center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0);
  210.     (void)printf("\n\n");
  211.     for (i = 0; i < 12; i++)
  212.         day_array(i + 1, year, days[i]);
  213.     (void)memset(lineout, ' ', sizeof(lineout) - 1);
  214.     lineout[sizeof(lineout) - 1] = '\0';
  215.     for (month = 0; month < 12; month += 3) {
  216.         center(month_names[month], WEEK_LEN, HEAD_SEP);
  217.         center(month_names[month + 1], WEEK_LEN, HEAD_SEP);
  218.         center(month_names[month + 2], WEEK_LEN, 0);
  219.         (void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP,
  220.             "", day_headings, HEAD_SEP, "", day_headings);
  221.         for (row = 0; row < 6; row++) {
  222.             for (which_cal = 0; which_cal < 3; which_cal++) {
  223.                 p = lineout + which_cal * (WEEK_LEN + 2);
  224.                 dp = &days[month + which_cal][row * 7];
  225.                 for (col = 0; col < 7; col++, p += DAY_LEN)
  226.                     ascii_day(p, *dp++);
  227.             }
  228.             trim_trailing_spaces(lineout);
  229.             (void)printf("%s\n", lineout);
  230.         }
  231.     }
  232.     (void)printf("\n");
  233. }
  234.  
  235. /*
  236.  * day_array --
  237.  *    Fill in an array of 42 integers with a calendar.  Assume for a moment
  238.  *    that you took the (maximum) 6 rows in a calendar and stretched them
  239.  *    out end to end.  You would have 42 numbers or spaces.  This routine
  240.  *    builds that array for any month from Jan. 1 through Dec. 9999.
  241.  */
  242. day_array(month, year, days)
  243.     register int *days;
  244.     int month, year;
  245. {
  246.     register int i, day, dw, dm;
  247.  
  248.     if (month == 9 && year == 1752) {
  249.         bcopy(julian ? j_sep1752 : sep1752,
  250.             days, MAXDAYS * sizeof(int));
  251.         return;
  252.     }
  253.     bcopy(empty, days, MAXDAYS * sizeof(int));
  254.     dm = days_in_month[leap_year(year)][month];
  255.     dw = day_in_week(1, month, year);
  256.     day = julian ? day_in_year(1, month, year) : 1;
  257.     while (dm--)
  258.         days[dw++] = day++;
  259. }
  260.  
  261. /*
  262.  * day_in_year --
  263.  *    return the 1 based day number within the year
  264.  */
  265. day_in_year(day, month, year)
  266.     register int day, month;
  267.     int year;
  268. {
  269.     register int i, leap;
  270.  
  271.     leap = leap_year(year);
  272.     for (i = 1; i < month; i++)
  273.         day += days_in_month[leap][i];
  274.     return(day);
  275. }
  276.  
  277. /*
  278.  * day_in_week
  279.  *    return the 0 based day number for any date from 1 Jan. 1 to
  280.  *    31 Dec. 9999.  Assumes the Gregorian reformation eliminates
  281.  *    3 Sep. 1752 through 13 Sep. 1752.  Returns Thursday for all
  282.  *    missing days.
  283.  */
  284. day_in_week(day, month, year)
  285.     int day, month, year;
  286. {
  287.     long temp;
  288.  
  289.     temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
  290.         + day_in_year(day, month, year);
  291.     if (temp < FIRST_MISSING_DAY)
  292.         return((temp - 1 + SATURDAY) % 7);
  293.     if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
  294.         return(((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
  295.     return(THURSDAY);
  296. }
  297.  
  298. ascii_day(p, day)
  299.     register char *p;
  300.     register int day;
  301. {
  302.     register int display, val;
  303.     static char *aday[] = {
  304.         "",
  305.         " 1", " 2", " 3", " 4", " 5", " 6", " 7",
  306.         " 8", " 9", "10", "11", "12", "13", "14",
  307.         "15", "16", "17", "18", "19", "20", "21",
  308.         "22", "23", "24", "25", "26", "27", "28",
  309.         "29", "30", "31",
  310.     };
  311.  
  312.     if (day == SPACE) {
  313.         memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
  314.         return;
  315.     }
  316.     if (julian) {
  317.         if (val = day / 100) {
  318.             day %= 100;
  319.             *p++ = val + '0';
  320.             display = 1;
  321.         } else {
  322.             *p++ = ' ';
  323.             display = 0;
  324.         }
  325.         val = day / 10;
  326.         if (val || display)
  327.             *p++ = val + '0';
  328.         else
  329.             *p++ = ' ';
  330.         *p++ = day % 10 + '0';
  331.     } else {
  332.         *p++ = aday[day][0];
  333.         *p++ = aday[day][1];
  334.     }
  335.     *p = ' ';
  336. }
  337.  
  338. trim_trailing_spaces(s)
  339.     register char *s;
  340. {
  341.     register char *p;
  342.  
  343.     for (p = s; *p; ++p);
  344.     while (p > s && isspace(*--p));
  345.     if (p > s)
  346.         ++p;
  347.     *p = '\0';
  348. }
  349.  
  350. center(str, len, separate)
  351.     char *str;
  352.     register int len;
  353.     int separate;
  354. {
  355.     len -= strlen(str);
  356.     (void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
  357.     if (separate)
  358.         (void)printf("%*s", separate, "");
  359. }
  360.  
  361. usage()
  362. {
  363.     (void)fprintf(stderr, "usage: cal [-jy] [[month] year]\n");
  364.     exit(1);
  365. }
  366.