]> git.ipfire.org Git - thirdparty/util-linux.git/blobdiff - misc-utils/cal.c
Imported from util-linux-2.10s tarball.
[thirdparty/util-linux.git] / misc-utils / cal.c
index 87ab71df637c07df91710aced0f9e56b13ce20e8..aba1b6f061fd53638ce77814d2ec18bf433788eb 100644 (file)
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1989, 1993, 1994\n\
-       The Regents of the University of California.  All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
-static char sccsid[] = "@(#)cal.c      8.4 (Berkeley) 4/2/94";
-#endif /* not lint */
+/* 1999-02-01  Jean-Francois Bignolles: added option '-m' to display
+ *             monday as the first day of the week.
+ * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
+ * - added Native Language Support
+ *
+ * 2000-09-01  Michael Charles Pruznick <dummy@netwiz.net> 
+ *             Added "-3" option to print prev/next month with current.
+ *             Added over-ridable default NUM_MONTHS and "-1" option to
+ *             get traditional output when -3 is the default.  I hope that
+ *             enough people will like -3 as the default that one day the
+ *             product can be shipped that way.
+ */
 
 #include <sys/types.h>
 
 #include <ctype.h>
-#include <err.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 #include <locale.h>
+#include "errs.h"
+#include "nls.h"
+#include "../defines.h"
 
-#if defined(__linux__) && _LINUX_C_LIB_VERSION_MAJOR > 4
+#ifdef HAVE_langinfo_h
 # include <langinfo.h>
 #else
-# include <localeinfo.h>
+# include <localeinfo.h>       /* libc4 only */
+#endif
+
+/* allow compile-time define to over-ride default */
+#ifndef NUM_MONTHS
+#define NUM_MONTHS 1
+#endif
+
+#if ( NUM_MONTHS != 1 && NUM_MONTHS !=3 )
+#error NUM_MONTHS must be 1 or 3
 #endif
 
 #define        THURSDAY                4               /* for reformation */
 #define        SATURDAY                6               /* 1 Jan 1 was a Saturday */
 
-#define        FIRST_MISSING_DAY       639787          /* 3 Sep 1752 */
+#define        FIRST_MISSING_DAY       639799          /* 3 Sep 1752 */
 #define        NUMBER_MISSING_DAYS     11              /* 11 day correction */
 
-#define        MAXDAYS                 42              /* max slots in a month array */
+#define        MAXDAYS                 43              /* max slots in a month array */
 #define        SPACE                   -1              /* used in day array */
 
 static int days_in_month[2][13] = {
@@ -82,6 +96,7 @@ int sep1752[MAXDAYS] = {
        SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,
        SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,
        SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,
+       SPACE
 }, j_sep1752[MAXDAYS] = {
        SPACE,  SPACE,  245,    246,    258,    259,    260,
        261,    262,    263,    264,    265,    266,    267,
@@ -89,6 +104,7 @@ int sep1752[MAXDAYS] = {
        SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,
        SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,
        SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,
+       SPACE
 }, empty[MAXDAYS] = {
        SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,
        SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,
@@ -96,10 +112,13 @@ int sep1752[MAXDAYS] = {
        SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,
        SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,
        SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,  SPACE,
+       SPACE
 };
 
 char day_headings[]   = " S  M Tu  W Th  F  S ";
-char j_day_headings[] = "  S   M  Tu   W  Th   F   S ";
+/* week1stday = 1  =>   " M Tu  W Th  F  S  S " */
+char j_day_headings[] = "Sun Mon Tue Wed Thu Fri Sat ";
+/* week1stday = 1  =>   "  M  Tu   W  Th   F   S   S " */
 const char *full_month[12];
 
 /* leap year -- account for gregorian reformation in 1752 */
@@ -119,45 +138,71 @@ const char *full_month[12];
 #define        leap_years_since_year_1(yr) \
        ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr))
 
+/* 0 => sunday (default), 1 => monday */
+int week1stday;
 int julian;
 
+#define FMT_ST_LINES 8
+#define FMT_ST_CHARS 300       /* 90 suffices in most locales */
+struct fmt_st
+{
+  char s[FMT_ST_LINES][FMT_ST_CHARS];
+};
+
 void   ascii_day __P((char *, int));
 void   center __P((const char *, int, int));
 void   day_array __P((int, int, int *));
 int    day_in_week __P((int, int, int));
 int    day_in_year __P((int, int, int));
 void   j_yearly __P((int));
+void   do_monthly __P((int, int, struct fmt_st*));
 void   monthly __P((int, int));
+void   monthly3 __P((int, int));
 void   trim_trailing_spaces __P((char *));
 void   usage __P((void));
 void   yearly __P((int));
 void    headers_init(void);
+extern char *__progname;
 
 int
-main(argc, argv)
-       int argc;
-       char **argv;
-{
+main(int argc, char **argv) {
        struct tm *local_time;
        time_t now;
        int ch, month, year, yflag;
-
-#ifdef __linux__
-       extern char *__progname;
-       __progname = argv[0];
-#endif
-
-       setlocale(LC_ALL,"");
-       headers_init();
+       char *progname, *p;
+       int num_months = NUM_MONTHS;
+
+       progname = argv[0];
+       if ((p = strrchr(progname, '/')) != NULL)
+               progname = p+1;
+       __progname = progname;
+
+       setlocale(LC_ALL, "");
+       bindtextdomain(PACKAGE, LOCALEDIR);
+       textdomain(PACKAGE);
+       
        yflag = 0;
-       while ((ch = getopt(argc, argv, "jy")) != EOF)
+       while ((ch = getopt(argc, argv, "13mjyV")) != EOF)
                switch(ch) {
+               case '1':
+                       num_months = 1;
+                       break;
+               case '3':
+                       num_months = 3;
+                       break;
+               case 'm':
+                       week1stday = 1;
+                       break;
                case 'j':
                        julian = 1;
                        break;
                case 'y':
                        yflag = 1;
                        break;
+               case 'V':
+                       printf(_("%s from %s\n"),
+                              progname, util_linux_version);
+                       return 0;
                case '?':
                default:
                        usage();
@@ -165,15 +210,15 @@ main(argc, argv)
        argc -= optind;
        argv += optind;
 
-       month = 0;
+       month = year = 0;
        switch(argc) {
        case 2:
                if ((month = atoi(*argv++)) < 1 || month > 12)
-                       errx(1, "illegal month value: use 1-12");
+                       errx(1, _("illegal month value: use 1-12"));
                /* FALLTHROUGH */
        case 1:
                if ((year = atoi(*argv)) < 1 || year > 9999)
-                       errx(1, "illegal year value: use 1-9999");
+                       errx(1, _("illegal year value: use 1-9999"));
                break;
        case 0:
                (void)time(&now);
@@ -185,9 +230,12 @@ main(argc, argv)
        default:
                usage();
        }
+       headers_init();
 
-       if (month)
+       if (month && num_months == 1)
                monthly(month, year);
+       else if (month && num_months == 3)
+               monthly3(month, year);
        else if (julian)
                j_yearly(year);
        else
@@ -204,25 +252,31 @@ main(argc, argv)
 
 void headers_init(void)
 {
-  int i;
+  int i, wd;
 
   strcpy(day_headings,"");
   strcpy(j_day_headings,"");
-  
-  for(i = 0 ; i < 7 ; i++ ) {
-#if defined(__linux__) && _LINUX_C_LIB_VERSION_MAJOR > 4
-     strncat(day_headings,nl_langinfo(ABDAY_1+i),2);
-     strcat(j_day_headings,nl_langinfo(ABDAY_1+i));
+
+#ifdef HAVE_langinfo_h
+# define weekday(wd)   nl_langinfo(ABDAY_1+wd)
 #else
-     strncat(day_headings,_time_info->abbrev_wkday[i],2);
-     strcat(j_day_headings,_time_info->abbrev_wkday[i]);
+# define weekday(wd)   _time_info->abbrev_wkday[wd]
 #endif
+  
+  for(i = 0 ; i < 7 ; i++ ) {
+     wd = (i + week1stday) % 7;
+     strncat(day_headings,weekday(wd),2);
+     strncat(j_day_headings,weekday(wd),3);
+     if (strlen(weekday(wd)) == 2)
+       strcat(j_day_headings," ");
      strcat(day_headings," ");
      strcat(j_day_headings," ");
   }
+
+#undef weekday
   
   for (i = 0; i < 12; i++) {
-#if defined(__linux__) && _LINUX_C_LIB_VERSION_MAJOR > 4
+#ifdef HAVE_langinfo_h
      full_month[i] = nl_langinfo(MON_1+i);
 #else
      full_month[i] = _time_info->full_month[i];
@@ -231,24 +285,86 @@ void headers_init(void)
 }
 
 void
-monthly(month, year)
+do_monthly(month, year, out)
        int month, year;
+       struct fmt_st* out;
 {
        int col, row, len, days[MAXDAYS];
-       char *p, lineout[30];
+       char *p, lineout[300];
 
        day_array(month, year, days);
        len = sprintf(lineout, "%s %d", full_month[month - 1], year);
-       (void)printf("%*s%s\n%s\n",
-           ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "",
-           lineout, julian ? j_day_headings : day_headings);
+       (void)sprintf(out->s[0],"%*s%s",
+           ((julian ? J_WEEK_LEN : WEEK_LEN) - len) / 2, "", lineout );
+       (void)sprintf(out->s[1],"%s",
+           julian ? j_day_headings : day_headings);
        for (row = 0; row < 6; row++) {
                for (col = 0, p = lineout; col < 7; col++,
                    p += julian ? J_DAY_LEN : DAY_LEN)
                        ascii_day(p, days[row * 7 + col]);
                *p = '\0';
                trim_trailing_spaces(lineout);
-               (void)printf("%s\n", lineout);
+               (void)sprintf(out->s[row+2],"%s", lineout);
+       }
+}
+
+void
+monthly(month, year)
+       int month, year;
+{
+       int i;
+       struct fmt_st out;
+
+       do_monthly(month, year, &out);
+       for ( i = 0; i < FMT_ST_LINES; i++ )
+       {
+         printf("%s\n", out.s[i]);
+       }
+}
+
+void
+monthly3(month, year)
+       int month, year;
+{
+       int i;
+       int width;
+       struct fmt_st out_prev;
+       struct fmt_st out_curm;
+       struct fmt_st out_next;
+       int prev_month, prev_year;
+       int next_month, next_year;
+
+       if ( month == 1 )
+       {
+         prev_month = 12;
+         prev_year  = year - 1;
+       }
+       else
+       {
+         prev_month = month - 1;
+         prev_year  = year;
+       }
+       if ( month == 12 )
+       {
+         next_month = 1;
+         next_year  = year + 1;
+       }
+       else
+       {
+         next_month = month + 1;
+         next_year  = year;
+       }
+
+       do_monthly(prev_month, prev_year, &out_prev);
+       do_monthly(month,      year,      &out_curm);
+       do_monthly(next_month, next_year, &out_next);
+        width = (julian ? J_WEEK_LEN : WEEK_LEN);
+       for ( i = 0; i < FMT_ST_LINES; i++ )
+       {
+         printf("%-*.*s %-*.*s %-*.*s\n", 
+             width, width, out_prev.s[i], 
+             width, width, out_curm.s[i], 
+             width, width, out_next.s[i] );
        }
 }
 
@@ -336,15 +452,16 @@ day_array(month, year, days)
        int *days;
 {
        int day, dw, dm;
+       int *d_sep1752;
 
        if (month == 9 && year == 1752) {
-               memmove(days,
-                       julian ? j_sep1752 : sep1752, MAXDAYS * sizeof(int));
+               d_sep1752 = julian ? j_sep1752 : sep1752;
+               memcpy(days, d_sep1752 + week1stday, MAXDAYS * sizeof(int));
                return;
        }
-       memmove(days, empty, MAXDAYS * sizeof(int));
+       memcpy(days, empty, MAXDAYS * sizeof(int));
        dm = days_in_month[leap_year(year)][month];
-       dw = day_in_week(1, month, year);
+       dw = (day_in_week(1, month, year) - week1stday + 7) % 7;
        day = julian ? day_in_year(1, month, year) : 1;
        while (dm--)
                days[dw++] = day++;
@@ -461,6 +578,6 @@ void
 usage()
 {
 
-       (void)fprintf(stderr, "usage: cal [-jy] [[month] year]\n");
+       (void)fprintf(stderr, _("usage: cal [-mjyV] [[month] year]\n"));
        exit(1);
 }