home *** CD-ROM | disk | FTP | other *** search
/ back2roots/padua / padua.7z / padua / misc / cal.lha / cal.c next >
Encoding:
C/C++ Source or Header  |  1992-03-17  |  12.1 KB  |  485 lines

  1. /*
  2.  * Copyright (c) 1989 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Kim Letkeman.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifndef lint
  38. char copyright[] =
  39. "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
  40.  All rights reserved.\n";
  41. #endif /* not lint */
  42.  
  43. #ifndef lint
  44. static char sccsid[] = "@(#)cal.c    5.2 (Berkeley) 4/19/91";
  45. #endif /* not lint */
  46.  
  47. #include <sys/types.h>
  48. #ifdef AMIGA
  49. #include <time.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #else
  53. #include <sys/time.h>
  54. #endif
  55. #include <stdio.h>
  56. #include <ctype.h>
  57.  
  58. #define    THURSDAY        4        /* for reformation */
  59. #define    SATURDAY         6        /* 1 Jan 1 was a Saturday */
  60.  
  61. #define    FIRST_MISSING_DAY     639787        /* 3 Sep 1752 */
  62. #define    NUMBER_MISSING_DAYS     11        /* 11 day correction */
  63.  
  64. #define    MAXDAYS            42        /* max slots in a month array */
  65. #define    SPACE            -1        /* used in day array */
  66.  
  67. static int days_in_month[2][13] = {
  68.     {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  69.     {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  70. };
  71.  
  72. int sep1752[MAXDAYS] = {
  73.     SPACE,    SPACE,    1,    2,    14,    15,    16,
  74.     17,    18,    19,    20,    21,    22,    23,
  75.     24,    25,    26,    27,    28,    29,    30,
  76.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  77.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  78.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  79. }, j_sep1752[MAXDAYS] = {
  80.     SPACE,    SPACE,    245,    246,    258,    259,    260,
  81.     261,    262,    263,    264,    265,    266,    267,
  82.     268,    269,    270,    271,    272,    273,    274,
  83.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  84.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  85.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  86. }, empty[MAXDAYS] = {
  87.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  88.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  89.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  90.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  91.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  92.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  93. };
  94.  
  95. char *month_names[12] = {
  96.     "January", "February", "March", "April", "May", "June",
  97.     "July", "August", "September", "October", "November", "December",
  98. };
  99.  
  100. char *day_headings = " S  M Tu  W Th  F  S";
  101. char *j_day_headings = "  S   M  Tu   W  Th   F   S";
  102.  
  103. /* leap year -- account for gregorian reformation in 1752 */
  104. #define    leap_year(yr) \
  105.     ((yr) <= 1752 ? !((yr) % 4) : \
  106.     !((yr) % 4) && ((yr) % 100) || !((yr) % 400))
  107.  
  108. /* number of centuries since 1700, not inclusive */
  109. #define    centuries_since_1700(yr) \
  110.     ((yr) > 1700 ? (yr) / 100 - 17 : 0)
  111.  
  112. /* number of centuries since 1700 whose modulo of 400 is 0 */
  113. #define    quad_centuries_since_1700(yr) \
  114.     ((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
  115.  
  116. /* number of leap years between year 1 and this year, not inclusive */
  117. #define    leap_years_since_year_1(yr) \
  118.     ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
  119.  
  120. int julian;
  121.  
  122. #ifdef AMIGA
  123.  
  124. /* prototypes */
  125.  
  126. void monthly(int,int);
  127. void j_yearly(int);
  128. void yearly(int);
  129. void day_array(int,int,int *);
  130. int day_in_year(int,int,int);
  131. int day_in_week(int,int,int);
  132. void ascii_day(char *,int);
  133. void trim_trailing_spaces(char *);
  134. void center(char *,int,int);
  135. void usage(void);
  136.  
  137. #define bcopy(f,t,l) memcpy(t,f,l)
  138. #include "opt_utils.c"
  139.  
  140. /* main */
  141.  
  142. int main(int argc, char *argv[])
  143. #else
  144. main(argc, argv)
  145.     int argc;
  146.     char **argv;
  147. #endif
  148. {
  149.     extern char *optarg;
  150.     extern int optind;
  151.     struct tm *local_time;
  152.     time_t now, time();
  153.     int ch, month, year, yflag;
  154.  
  155.     yflag = 0;
  156.     while ((ch = getopt(argc, argv, "jy")) != EOF)
  157.         switch(ch) {
  158.         case 'j':
  159.             julian = 1;
  160.             break;
  161.         case 'y':
  162.             yflag = 1;
  163.             break;
  164.         case '?':
  165.         default:
  166.             usage();
  167.         }
  168.     argc -= optind;
  169.     argv += optind;
  170.  
  171.     month = 0;
  172.     switch(argc) {
  173.     case 2:
  174.         if ((month = atoi(*argv++)) <= 0 || month > 12) {
  175.             (void)fprintf(stderr,
  176.                 "cal: illegal month value: use 0-12\n");
  177.             exit(1);
  178.         }
  179.         /* FALLTHROUGH */
  180.     case 1:
  181.         if ((year = atoi(*argv)) <= 0 || year > 9999) {
  182.             (void)fprintf(stderr,
  183.                 "cal: illegal year value: use 0-9999\n");
  184.             exit(1);
  185.         }
  186.         break;
  187.     case 0:
  188.         (void)time(&now);
  189.         local_time = localtime(&now);
  190.         year = local_time->tm_year + 1900;
  191.         if (!yflag)
  192.             month = local_time->tm_mon + 1;
  193.         break;
  194.     default:
  195.         usage();
  196.     }
  197.  
  198.     if (month)
  199.         monthly(month, year);
  200.     else if (julian)
  201.         j_yearly(year);
  202.     else
  203.         yearly(year);
  204.     exit(0);
  205. }
  206.  
  207. #define    DAY_LEN        3        /* 3 spaces per day */
  208. #define    J_DAY_LEN    4        /* 4 spaces per day */
  209. #define    WEEK_LEN    20        /* 7 * 3 - one space at the end */
  210. #define    J_WEEK_LEN    27        /* 7 * 4 - one space at the end */
  211. #define    HEAD_SEP    2        /* spaces between day headings */
  212. #define    J_HEAD_SEP    2
  213.  
  214. #ifdef AMIGA
  215. void monthly(int month, int year)
  216. #else
  217. monthly(month, year)
  218.     int month, year;
  219. #endif
  220. {
  221.     register int col, row;
  222.     register char *p;
  223.     int len, days[MAXDAYS];
  224.     char lineout[30];
  225.  
  226.     day_array(month, year, days);
  227.     len = sprintf(lineout, "%s %d", month_names[month - 1], year);
  228.     (void)printf("%*s%s\n%s\n",
  229.         ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "",
  230.         lineout, julian ? j_day_headings : day_headings);
  231.     for (row = 0; row < 6; row++) {
  232.         for (col = 0, p = lineout; col < 7; col++,
  233.             p += julian ? J_DAY_LEN : DAY_LEN)
  234.             ascii_day(p, days[row * 7 + col]);
  235. #ifdef AMIGA
  236.         *p = '\0';
  237. #endif
  238.         trim_trailing_spaces(lineout);
  239.         (void)printf("%s\n", lineout);
  240.     }
  241. }
  242.  
  243. #ifdef AMIGA
  244. void j_yearly(int year)
  245. #else
  246. j_yearly(year)
  247.     int year;
  248. #endif
  249. {
  250.     register int col, *dp, i, month, row, which_cal;
  251.     register char *p;
  252.     int days[12][MAXDAYS];
  253.     char lineout[80];
  254.  
  255.     (void)sprintf(lineout, "%d", year);
  256.     center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0);
  257.     (void)printf("\n\n");
  258.     for (i = 0; i < 12; i++)
  259.         day_array(i + 1, year, days[i]);
  260.     (void)memset(lineout, ' ', sizeof(lineout) - 1);
  261.     lineout[sizeof(lineout) - 1] = '\0';
  262.     for (month = 0; month < 12; month += 2) {
  263.         center(month_names[month], J_WEEK_LEN, J_HEAD_SEP);
  264.         center(month_names[month + 1], J_WEEK_LEN, 0);
  265.         (void)printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "",
  266.             j_day_headings);
  267.         for (row = 0; row < 6; row++) {
  268.             for (which_cal = 0; which_cal < 2; which_cal++) {
  269.                 p = lineout + which_cal * (J_WEEK_LEN + 2);
  270.                 dp = &days[month + which_cal][row * 7];
  271.                 for (col = 0; col < 7; col++, p += J_DAY_LEN)
  272.                     ascii_day(p, *dp++);
  273.             }
  274. #ifdef AMIGA
  275.             *p = '\0';
  276. #endif
  277.             trim_trailing_spaces(lineout);
  278.             (void)printf("%s\n", lineout);
  279.         }
  280.     }
  281.     (void)printf("\n");
  282. }
  283.  
  284. #ifdef AMIGA
  285. void yearly(int year)
  286. #else
  287. yearly(year)
  288.     int year;
  289. #endif
  290. {
  291.     register int col, *dp, i, month, row, which_cal;
  292.     register char *p;
  293.     int days[12][MAXDAYS];
  294.     char lineout[80];
  295.  
  296.     (void)sprintf(lineout, "%d", year);
  297.     center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0);
  298.     (void)printf("\n\n");
  299.     for (i = 0; i < 12; i++)
  300.         day_array(i + 1, year, days[i]);
  301.     (void)memset(lineout, ' ', sizeof(lineout) - 1);
  302.     lineout[sizeof(lineout) - 1] = '\0';
  303.     for (month = 0; month < 12; month += 3) {
  304.         center(month_names[month], WEEK_LEN, HEAD_SEP);
  305.         center(month_names[month + 1], WEEK_LEN, HEAD_SEP);
  306.         center(month_names[month + 2], WEEK_LEN, 0);
  307.         (void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP,
  308.             "", day_headings, HEAD_SEP, "", day_headings);
  309.         for (row = 0; row < 6; row++) {
  310.             for (which_cal = 0; which_cal < 3; which_cal++) {
  311.                 p = lineout + which_cal * (WEEK_LEN + 2);
  312.                 dp = &days[month + which_cal][row * 7];
  313.                 for (col = 0; col < 7; col++, p += DAY_LEN)
  314.                     ascii_day(p, *dp++);
  315.             }
  316. #ifdef AMIGA
  317.             *p = '\0';
  318. #endif
  319.             trim_trailing_spaces(lineout);
  320.             (void)printf("%s\n", lineout);
  321.         }
  322.     }
  323.     (void)printf("\n");
  324. }
  325.  
  326. /*
  327.  * day_array --
  328.  *    Fill in an array of 42 integers with a calendar.  Assume for a moment
  329.  *    that you took the (maximum) 6 rows in a calendar and stretched them
  330.  *    out end to end.  You would have 42 numbers or spaces.  This routine
  331.  *    builds that array for any month from Jan. 1 through Dec. 9999.
  332.  */
  333. #ifdef AMIGA
  334. void day_array(int month, int year, int *days)
  335. #else
  336. day_array(month, year, days)
  337.     register int *days;
  338.     int month, year;
  339. #endif
  340. {
  341.     register int day, dw, dm;
  342.  
  343.     if (month == 9 && year == 1752) {
  344.         bcopy(julian ? j_sep1752 : sep1752,
  345.             days, MAXDAYS * sizeof(int));
  346.         return;
  347.     }
  348.     bcopy(empty, days, MAXDAYS * sizeof(int));
  349.     dm = days_in_month[leap_year(year)][month];
  350.     dw = day_in_week(1, month, year);
  351.     day = julian ? day_in_year(1, month, year) : 1;
  352.     while (dm--)
  353.         days[dw++] = day++;
  354. }
  355.  
  356. /*
  357.  * day_in_year --
  358.  *    return the 1 based day number within the year
  359.  */
  360. #ifdef AMIGA
  361. int day_in_year(int day, int month, int year)
  362. #else
  363. day_in_year(day, month, year)
  364.     register int day, month;
  365.     int year;
  366. #endif
  367. {
  368.     register int i, leap;
  369.  
  370.     leap = leap_year(year);
  371.     for (i = 1; i < month; i++)
  372.         day += days_in_month[leap][i];
  373.     return(day);
  374. }
  375.  
  376. /*
  377.  * day_in_week
  378.  *    return the 0 based day number for any date from 1 Jan. 1 to
  379.  *    31 Dec. 9999.  Assumes the Gregorian reformation eliminates
  380.  *    3 Sep. 1752 through 13 Sep. 1752.  Returns Thursday for all
  381.  *    missing days.
  382.  */
  383. #ifdef AMIGA
  384. int day_in_week(int day, int month, int year)
  385. #else
  386. day_in_week(day, month, year)
  387.     int day, month, year;
  388. #endif
  389. {
  390.     long temp;
  391.  
  392.     temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
  393.         + day_in_year(day, month, year);
  394.     if (temp < FIRST_MISSING_DAY)
  395.         return((temp - 1 + SATURDAY) % 7);
  396.     if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
  397.         return(((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
  398.     return(THURSDAY);
  399. }
  400.  
  401. #ifdef AMIGA
  402. void ascii_day(char *p, int day)
  403. #else
  404. ascii_day(p, day)
  405.     register char *p;
  406.     register int day;
  407. #endif
  408. {
  409.     register int display, val;
  410.     static char *aday[] = {
  411.         "",
  412.         " 1", " 2", " 3", " 4", " 5", " 6", " 7",
  413.         " 8", " 9", "10", "11", "12", "13", "14",
  414.         "15", "16", "17", "18", "19", "20", "21",
  415.         "22", "23", "24", "25", "26", "27", "28",
  416.         "29", "30", "31",
  417.     };
  418.  
  419.     if (day == SPACE) {
  420.         memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
  421.         return;
  422.     }
  423.     if (julian) {
  424.         if (val = day / 100) {
  425.             day %= 100;
  426.             *p++ = val + '0';
  427.             display = 1;
  428.         } else {
  429.             *p++ = ' ';
  430.             display = 0;
  431.         }
  432.         val = day / 10;
  433.         if (val || display)
  434.             *p++ = val + '0';
  435.         else
  436.             *p++ = ' ';
  437.         *p++ = day % 10 + '0';
  438.     } else {
  439.         *p++ = aday[day][0];
  440.         *p++ = aday[day][1];
  441.     }
  442.     *p = ' ';
  443. }
  444.  
  445. #ifdef AMIGA
  446. void trim_trailing_spaces(char *s)
  447. #else
  448. trim_trailing_spaces(s)
  449.     register char *s;
  450. #endif
  451. {
  452.     register char *p;
  453.  
  454.     for (p = s; *p; ++p);
  455.     while (p > s && isspace(*--p));
  456.     if (p > s)
  457.         ++p;
  458.     *p = '\0';
  459. }
  460.  
  461. #ifdef AMIGA
  462. void center(char *str, int len, int separate)
  463. #else
  464. center(str, len, separate)
  465.     char *str;
  466.     register int len;
  467.     int separate;
  468. #endif
  469. {
  470.     len -= strlen(str);
  471.     (void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
  472.     if (separate)
  473.         (void)printf("%*s", separate, "");
  474. }
  475.  
  476. #ifdef AMIGA
  477. void usage(void)
  478. #else
  479. usage()
  480. #endif
  481. {
  482.     (void)fprintf(stderr, "usage: cal [-jy] [[month] year]\n");
  483.     exit(1);
  484. }
  485.