home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.10 / util-lin / util-linux-1.10 / cal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-05  |  11.2 KB  |  433 lines

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