home *** CD-ROM | disk | FTP | other *** search
/ Chip 1995 March / CHIP3.mdf / slackwar / a / util / util-lin.2 / util-lin / util-linux-2.2 / misc-utils / cal.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-22  |  11.6 KB  |  451 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. #include <locale.h>
  57. #include <localeinfo.h>
  58.  
  59. #define    THURSDAY        4        /* for reformation */
  60. #define    SATURDAY         6        /* 1 Jan 1 was a Saturday */
  61.  
  62. #define    FIRST_MISSING_DAY     639787        /* 3 Sep 1752 */
  63. #define    NUMBER_MISSING_DAYS     11        /* 11 day correction */
  64.  
  65. #define    MAXDAYS            42        /* max slots in a month array */
  66. #define    SPACE            -1        /* used in day array */
  67.  
  68. static int days_in_month[2][13] = {
  69.     {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  70.     {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
  71. };
  72.  
  73. int sep1752[MAXDAYS] = {
  74.     SPACE,    SPACE,    1,    2,    14,    15,    16,
  75.     17,    18,    19,    20,    21,    22,    23,
  76.     24,    25,    26,    27,    28,    29,    30,
  77.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  78.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  79.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  80. }, j_sep1752[MAXDAYS] = {
  81.     SPACE,    SPACE,    245,    246,    258,    259,    260,
  82.     261,    262,    263,    264,    265,    266,    267,
  83.     268,    269,    270,    271,    272,    273,    274,
  84.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  85.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  86.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  87. }, empty[MAXDAYS] = {
  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.     SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,    SPACE,
  94. };
  95.  
  96. char *day_headings = " S  M Tu  W Th  F  S ";
  97. char *j_day_headings = "  S   M  Tu   W  Th   F   S ";
  98.  
  99. /* leap year -- account for gregorian reformation in 1752 */
  100. #define    leap_year(yr) \
  101.     ((yr) <= 1752 ? !((yr) % 4) : \
  102.     !((yr) % 4) && ((yr) % 100) || !((yr) % 400))
  103.  
  104. /* number of centuries since 1700, not inclusive */
  105. #define    centuries_since_1700(yr) \
  106.     ((yr) > 1700 ? (yr) / 100 - 17 : 0)
  107.  
  108. /* number of centuries since 1700 whose modulo of 400 is 0 */
  109. #define    quad_centuries_since_1700(yr) \
  110.     ((yr) > 1600 ? ((yr) - 1600) / 400 : 0)
  111.  
  112. /* number of leap years between year 1 and this year, not inclusive */
  113. #define    leap_years_since_year_1(yr) \
  114.     ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
  115.  
  116. int julian;
  117.  
  118. void    ascii_day __P((char *, int));
  119. void    center __P((char *, int, int));
  120. void    day_array __P((int, int, int *));
  121. int    day_in_week __P((int, int, int));
  122. int    day_in_year __P((int, int, int));
  123. void    j_yearly __P((int));
  124. void    monthly __P((int, int));
  125. void    trim_trailing_spaces __P((char *));
  126. void    usage __P((void));
  127. void    yearly __P((int));
  128. void    headers_init(void);
  129.  
  130. int
  131. main(argc, argv)
  132.     int argc;
  133.     char **argv;
  134. {
  135.     struct tm *local_time;
  136.     time_t now;
  137.     int ch, month, year, yflag;
  138.  
  139. #ifdef __linux__
  140.     extern char *__progname;
  141.     __progname = argv[0];
  142. #endif
  143.  
  144.     setlocale(LC_ALL,"");
  145.     headers_init();
  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    21        /* 7 days * 3 characters */
  195. #define    J_WEEK_LEN    28        /* 7 days * 4 characters */
  196. #define    HEAD_SEP    2        /* spaces between day headings */
  197. #define    J_HEAD_SEP    2
  198.  
  199. void headers_init(void)
  200. {
  201.   int i;
  202.  
  203.   strcpy(day_headings,"");
  204.   for(i = 0 ; i < 7 ; i++ )
  205.     {
  206.       strncat(day_headings,_time_info->abbrev_wkday[i],2);
  207.       strcat(day_headings," ");
  208.     }
  209.   strcpy(j_day_headings,"");
  210.   for(i = 0 ; i < 7 ; i++ )
  211.     {
  212.       strcat(j_day_headings,_time_info->abbrev_wkday[i]);
  213.       strcat(j_day_headings," ");
  214.     } 
  215. }
  216.  
  217. void
  218. monthly(month, year)
  219.     int month, year;
  220. {
  221.     int col, row, len, days[MAXDAYS];
  222.     char *p, lineout[30];
  223.  
  224.     day_array(month, year, days);
  225.     len = sprintf(lineout, "%s %d", _time_info->full_month[month - 1], year);
  226.     (void)printf("%*s%s\n%s\n",
  227.         ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "",
  228.         lineout, julian ? j_day_headings : day_headings);
  229.     for (row = 0; row < 6; row++) {
  230.         for (col = 0, p = lineout; col < 7; col++,
  231.             p += julian ? J_DAY_LEN : DAY_LEN)
  232.             ascii_day(p, days[row * 7 + col]);
  233.         *p = '\0';
  234.         trim_trailing_spaces(lineout);
  235.         (void)printf("%s\n", lineout);
  236.     }
  237. }
  238.  
  239. void
  240. j_yearly(year)
  241.     int year;
  242. {
  243.     int col, *dp, i, month, row, which_cal;
  244.     int days[12][MAXDAYS];
  245.     char *p, lineout[80];
  246.  
  247.     (void)sprintf(lineout, "%d", year);
  248.     center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0);
  249.     (void)printf("\n\n");
  250.     for (i = 0; i < 12; i++)
  251.         day_array(i + 1, year, days[i]);
  252.     (void)memset(lineout, ' ', sizeof(lineout) - 1);
  253.     lineout[sizeof(lineout) - 1] = '\0';
  254.     for (month = 0; month < 12; month += 2) {
  255.         center(_time_info->full_month[month], J_WEEK_LEN, J_HEAD_SEP);
  256.         center(_time_info->full_month[month + 1], J_WEEK_LEN, 0);
  257.         (void)printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "",
  258.             j_day_headings);
  259.         for (row = 0; row < 6; row++) {
  260.             for (which_cal = 0; which_cal < 2; which_cal++) {
  261.                 p = lineout + which_cal * (J_WEEK_LEN + 2);
  262.                 dp = &days[month + which_cal][row * 7];
  263.                 for (col = 0; col < 7; col++, p += J_DAY_LEN)
  264.                     ascii_day(p, *dp++);
  265.             }
  266.             *p = '\0';
  267.             trim_trailing_spaces(lineout);
  268.             (void)printf("%s\n", lineout);
  269.         }
  270.     }
  271.     (void)printf("\n");
  272. }
  273.  
  274. void
  275. yearly(year)
  276.     int year;
  277. {
  278.     int col, *dp, i, month, row, which_cal;
  279.     int days[12][MAXDAYS];
  280.     char *p, lineout[80];
  281.  
  282.     (void)sprintf(lineout, "%d", year);
  283.     center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0);
  284.     (void)printf("\n\n");
  285.     for (i = 0; i < 12; i++)
  286.         day_array(i + 1, year, days[i]);
  287.     (void)memset(lineout, ' ', sizeof(lineout) - 1);
  288.     lineout[sizeof(lineout) - 1] = '\0';
  289.     for (month = 0; month < 12; month += 3) {
  290.         center(_time_info->full_month[month], WEEK_LEN, HEAD_SEP);
  291.         center(_time_info->full_month[month + 1], WEEK_LEN, HEAD_SEP);
  292.         center(_time_info->full_month[month + 2], WEEK_LEN, 0);
  293.         (void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP,
  294.             "", day_headings, HEAD_SEP, "", day_headings);
  295.         for (row = 0; row < 6; row++) {
  296.             for (which_cal = 0; which_cal < 3; which_cal++) {
  297.                 p = lineout + which_cal * (WEEK_LEN + 2);
  298.                 dp = &days[month + which_cal][row * 7];
  299.                 for (col = 0; col < 7; col++, p += DAY_LEN)
  300.                     ascii_day(p, *dp++);
  301.             }
  302.             *p = '\0';
  303.             trim_trailing_spaces(lineout);
  304.             (void)printf("%s\n", lineout);
  305.         }
  306.     }
  307.     (void)printf("\n");
  308. }
  309.  
  310. /*
  311.  * day_array --
  312.  *    Fill in an array of 42 integers with a calendar.  Assume for a moment
  313.  *    that you took the (maximum) 6 rows in a calendar and stretched them
  314.  *    out end to end.  You would have 42 numbers or spaces.  This routine
  315.  *    builds that array for any month from Jan. 1 through Dec. 9999.
  316.  */
  317. void
  318. day_array(month, year, days)
  319.     int month, year;
  320.     int *days;
  321. {
  322.     int day, dw, dm;
  323.  
  324.     if (month == 9 && year == 1752) {
  325.         memmove(days,
  326.             julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int));
  327.         return;
  328.     }
  329.     memmove(days, empty, MAXDAYS * sizeof(int));
  330.     dm = days_in_month[leap_year(year)][month];
  331.     dw = day_in_week(1, month, year);
  332.     day = julian ? day_in_year(1, month, year) : 1;
  333.     while (dm--)
  334.         days[dw++] = day++;
  335. }
  336.  
  337. /*
  338.  * day_in_year --
  339.  *    return the 1 based day number within the year
  340.  */
  341. int
  342. day_in_year(day, month, year)
  343.     int day, month, year;
  344. {
  345.     int i, leap;
  346.  
  347.     leap = leap_year(year);
  348.     for (i = 1; i < month; i++)
  349.         day += days_in_month[leap][i];
  350.     return (day);
  351. }
  352.  
  353. /*
  354.  * day_in_week
  355.  *    return the 0 based day number for any date from 1 Jan. 1 to
  356.  *    31 Dec. 9999.  Assumes the Gregorian reformation eliminates
  357.  *    3 Sep. 1752 through 13 Sep. 1752.  Returns Thursday for all
  358.  *    missing days.
  359.  */
  360. int
  361. day_in_week(day, month, year)
  362.     int day, month, year;
  363. {
  364.     long temp;
  365.  
  366.     temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1)
  367.         + day_in_year(day, month, year);
  368.     if (temp < FIRST_MISSING_DAY)
  369.         return ((temp - 1 + SATURDAY) % 7);
  370.     if (temp >= (FIRST_MISSING_DAY + NUMBER_MISSING_DAYS))
  371.         return (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7);
  372.     return (THURSDAY);
  373. }
  374.  
  375. void
  376. ascii_day(p, day)
  377.     char *p;
  378.     int day;
  379. {
  380.     int display, val;
  381.     static char *aday[] = {
  382.         "",
  383.         " 1", " 2", " 3", " 4", " 5", " 6", " 7",
  384.         " 8", " 9", "10", "11", "12", "13", "14",
  385.         "15", "16", "17", "18", "19", "20", "21",
  386.         "22", "23", "24", "25", "26", "27", "28",
  387.         "29", "30", "31",
  388.     };
  389.  
  390.     if (day == SPACE) {
  391.         memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN);
  392.         return;
  393.     }
  394.     if (julian) {
  395.         if (val = day / 100) {
  396.             day %= 100;
  397.             *p++ = val + '0';
  398.             display = 1;
  399.         } else {
  400.             *p++ = ' ';
  401.             display = 0;
  402.         }
  403.         val = day / 10;
  404.         if (val || display)
  405.             *p++ = val + '0';
  406.         else
  407.             *p++ = ' ';
  408.         *p++ = day % 10 + '0';
  409.     } else {
  410.         *p++ = aday[day][0];
  411.         *p++ = aday[day][1];
  412.     }
  413.     *p = ' ';
  414. }
  415.  
  416. void
  417. trim_trailing_spaces(s)
  418.     char *s;
  419. {
  420.     char *p;
  421.  
  422.     for (p = s; *p; ++p)
  423.         continue;
  424.     while (p > s && isspace(*--p))
  425.         continue;
  426.     if (p > s)
  427.         ++p;
  428.     *p = '\0';
  429. }
  430.  
  431. void
  432. center(str, len, separate)
  433.     char *str;
  434.     int len;
  435.     int separate;
  436. {
  437.  
  438.     len -= strlen(str);
  439.     (void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, "");
  440.     if (separate)
  441.         (void)printf("%*s", separate, "");
  442. }
  443.  
  444. void
  445. usage()
  446. {
  447.  
  448.     (void)fprintf(stderr, "usage: cal [-jy] [[month] year]\n");
  449.     exit(1);
  450. }
  451.