diff -Naur util-linux-2.12i/configure util-linux-2.12i-cal/configure --- util-linux-2.12i/configure 2004-11-04 17:27:05.000000000 +0000 +++ util-linux-2.12i-cal/configure 2004-11-16 18:26:37.000000000 +0000 @@ -418,6 +418,7 @@ echo "You don't have ncurses - I will not make ul and setterm." else echo "LIBCURSES=-lncurses" >> make_include + echo "#define HAVE_ncurses" >> defines.h fi # diff -Naur util-linux-2.12i/misc-utils/Makefile util-linux-2.12i-cal/misc-utils/Makefile --- util-linux-2.12i/misc-utils/Makefile 2004-03-26 15:54:34.000000000 +0000 +++ util-linux-2.12i-cal/misc-utils/Makefile 2004-11-16 18:26:37.000000000 +0000 @@ -51,7 +51,6 @@ endif # Programs requiring special compilation - NEEDS_CURSES= setterm NEEDS_OPENPTY= script @@ -64,6 +63,16 @@ @echo $@ not made since it requires ncurses endif +ifeq "$(HAVE_NCURSES)" "yes" +cal: + $(CC) $(LDFLAGS) $^ -o $@ $(LIBCURSES) +else +ifeq "$(HAVE_TERMCAP)" "yes" +cal: + $(CC) $(LDFLAGS) $^ -o $@ $(LIBTERMCAP) +endif +endif + $(NEEDS_OPENPTY): $(CC) $(LDFLAGS) $^ -o $@ $(LIBPTY) diff -Naur util-linux-2.12i/misc-utils/cal.c util-linux-2.12i-cal/misc-utils/cal.c --- util-linux-2.12i/misc-utils/cal.c 2002-10-31 15:36:04.000000000 +0000 +++ util-linux-2.12i-cal/misc-utils/cal.c 2004-11-16 18:26:42.000000000 +0000 @@ -35,11 +35,11 @@ */ /* 1999-02-01 Jean-Francois Bignolles: added option '-m' to display - * monday as the first day of the week. + * monday as the first day of the week. * 1999-02-22 Arkadiusz Mi¶kiewicz * - added Native Language Support * - * 2000-09-01 Michael Charles Pruznick + * 2000-09-01 Michael Charles Pruznick * 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 @@ -68,6 +68,57 @@ #include "nls.h" #include "../defines.h" +#if defined(HAVE_ncurses) + +#if NCH +#include +#else +#include +#endif +#include /* include after */ + +static void +my_setupterm(const char *term, int fildes, int *errret) { + setupterm((char*)term, fildes, errret); +} + +static void +my_putstring(char *s) { + putp(s); +} + +static char * +my_tgetstr(char *s, char *ss) { + return tigetstr(ss); +} + +#elif defined(HAVE_termcap) + +#include + +char termbuffer[4096]; +char tcbuffer[4096]; +char *strbuf = termbuffer; + +static void +my_setupterm(const char *term, int fildes, int *errret) { + *errret = tgetent(tcbuffer, term); +} + +static void +my_putstring(char *s) { + tputs (s, 1, putchar); +} + +static char * +my_tgetstr(char *s, char *ss) { + return tgetstr(s, &strbuf); +} + +#endif +const char *term=""; +const char *Senter="", *Sexit="";/* enter and exit standout mode */ + #ifdef HAVE_langinfo_h # include #else @@ -77,7 +128,7 @@ #include "widechar.h" #define SIZE(a) (sizeof(a)/sizeof((a)[0])) - + /* allow compile-time define to over-ride default */ #ifndef NUM_MONTHS #define NUM_MONTHS 1 @@ -88,10 +139,10 @@ #endif #define THURSDAY 4 /* for reformation */ -#define SATURDAY 6 /* 1 Jan 1 was a Saturday */ +#define SATURDAY 6 /* 1 Jan 1 was a Saturday */ -#define FIRST_MISSING_DAY 639799 /* 3 Sep 1752 */ -#define NUMBER_MISSING_DAYS 11 /* 11 day correction */ +#define FIRST_MISSING_DAY 639799 /* 3 Sep 1752 */ +#define NUMBER_MISSING_DAYS 11 /* 11 day correction */ #define MAXDAYS 43 /* max slots in a month array */ #define SPACE -1 /* used in day array */ @@ -162,6 +213,8 @@ int week1stday=0; int julian; +#define TODAY_FLAG 0x400 /* flag day for highlighting */ + #define FMT_ST_LINES 8 #define FMT_ST_CHARS 300 /* 90 suffices in most locales */ struct fmt_st @@ -169,26 +222,27 @@ 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); +char * ascii_day(char *, int); +void center_str(const char* src, char* dest, size_t dest_size, int width); +void center(const char *, int, int); +void day_array(int, int, int, int *); +int day_in_week(int, int, int); +int day_in_year(int, int, int); +void yearly(int, int); +void j_yearly(int, int); +void do_monthly(int, int, int, struct fmt_st*); +void monthly(int, int, int); +void monthly3(int, int, int); +void trim_trailing_spaces(char *); +void usage(void); +void headers_init(void); extern char *__progname; int main(int argc, char **argv) { struct tm *local_time; time_t now; - int ch, month, year, yflag; + int ch, day, month, year, yflag; char *progname, *p; int num_months = NUM_MONTHS; @@ -201,6 +255,17 @@ bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); +#if defined(HAVE_ncurses) || defined(HAVE_termcap) + if ((term = getenv("TERM"))) { + int ret; + my_setupterm(term, 1, &ret); + if (ret > 0) { + Senter = my_tgetstr("so","smso"); + Sexit = my_tgetstr("se","rmso"); + } + } +#endif + #if 0 /* setting week1stday is against man page */ /* * What *is* the first day of the week? Note that glibc does not @@ -214,7 +279,7 @@ * * The traditional Unix cal utility starts at Sunday. * We start at Sunday and have an option -m for starting at Monday. - * + * * At some future time this may become -s for Sunday, -m for Monday, * no option for glibc-determined locale-dependent version. */ @@ -222,16 +287,16 @@ week1stday = (int)(nl_langinfo(_NL_TIME_FIRST_WEEKDAY))[0]; #endif #endif - + yflag = 0; while ((ch = getopt(argc, argv, "13mjsyV")) != -1) switch(ch) { - case '1': - num_months = 1; /* default */ - break; - case '3': - num_months = 3; - break; + case '1': + num_months = 1; /* default */ + break; + case '3': + num_months = 3; + break; case 's': week1stday = 0; /* default */ break; @@ -255,7 +320,7 @@ argc -= optind; argv += optind; - month = year = 0; + day = month = year = 0; switch(argc) { case 2: if ((month = atoi(*argv++)) < 1 || month > 12) @@ -268,6 +333,8 @@ case 0: (void)time(&now); local_time = localtime(&now); + if (isatty(1)) + day = local_time->tm_yday + 1; year = local_time->tm_year + 1900; if (!yflag) month = local_time->tm_mon + 1; @@ -278,13 +345,13 @@ headers_init(); if (month && num_months == 1) - monthly(month, year); + monthly(day, month, year); else if (month && num_months == 3) - monthly3(month, year); + monthly3(day, month, year); else if (julian) - j_yearly(year); + j_yearly(day, year); else - yearly(year); + yearly(day, year); exit(0); } @@ -316,7 +383,7 @@ #else # define weekday(wd) _time_info->abbrev_wkday[wd] #endif - + for(i = 0 ; i < 7 ; i++ ) { wd = (i + week1stday) % 7; #ifdef ENABLE_WIDECHAR @@ -342,8 +409,10 @@ wcstombs(j_day_headings,j_day_headings_wc,sizeof(j_day_headings)); #endif + trim_trailing_spaces(day_headings); + trim_trailing_spaces(j_day_headings); #undef weekday - + for (i = 0; i < 12; i++) { #ifdef HAVE_langinfo_h full_month[i] = nl_langinfo(MON_1+i); @@ -354,62 +423,51 @@ } void -do_monthly(month, year, out) - int month, year; - struct fmt_st* out; -{ +do_monthly(int day, int month, int year, struct fmt_st *out) { int col, row, len, days[MAXDAYS]; - char *p, lineout[300]; -#ifdef ENABLE_WIDECHAR - wchar_t lineout_wc[300]; -#endif - - day_array(month, year, days); - /* %s is the month name, %d the year number. + char *p, lineout[FMT_ST_CHARS]; + int width = (julian ? J_WEEK_LEN : WEEK_LEN) - 1; + + day_array(day, month, year, days); + + /* + * %s is the month name, %d the year number. * you can change the order and/or add something here; eg for * Basque the translation should be: "%2$dko %1$s", and * the Vietnamese should be "%s na(m %d", etc. */ len = sprintf(lineout, _("%s %d"), full_month[month - 1], year); -#ifdef ENABLE_WIDECHAR - if (mbstowcs(lineout_wc,lineout,len) > 0) { - len = wcswidth(lineout_wc,len); - } else { - len = strlen(lineout); - } -#endif - (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); + center_str(lineout, out->s[0], SIZE(out->s[0]), width); + + 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]); + for (col = 0, p = lineout; col < 7; col++) + p = ascii_day(p, days[row * 7 + col]); *p = '\0'; trim_trailing_spaces(lineout); - (void)sprintf(out->s[row+2],"%s", lineout); + sprintf(out->s[row+2], "%s", lineout); } } void -monthly(month, year) - int month, year; -{ +monthly(int day, int month, int 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]); + do_monthly(day, month, year, &out); + for (i = 0; i < FMT_ST_LINES; i++) { +#if defined(HAVE_ncurses) || defined(HAVE_termcap) + my_putstring(out.s[i]);putchar('\n'); +#else + puts(out.s[i]); +#endif } } void -monthly3(month, year) - int month, year; -{ +monthly3(int day, int month, int year) { + char lineout[FMT_ST_CHARS]; int i; int width; struct fmt_st out_prev; @@ -418,109 +476,117 @@ 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; + if (month == 1) { + prev_month = 12; + prev_year = year - 1; + } else { + prev_month = month - 1; + prev_year = year; } - else - { - next_month = month + 1; - next_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] ); + do_monthly(day, prev_month, prev_year, &out_prev); + do_monthly(day, month, year, &out_curm); + do_monthly(day, next_month, next_year, &out_next); + width = (julian ? J_WEEK_LEN : WEEK_LEN) -1; + for (i = 0; i < 2; i++) + printf("%s %s %s\n", out_prev.s[i], out_curm.s[i], out_next.s[i]); + for (i = 2; i < FMT_ST_LINES; i++) { + snprintf(lineout, SIZE(lineout), "%-*s %-*s %-*s\n", + width, out_prev.s[i], + width, out_curm.s[i], + width, out_next.s[i]); +#if defined(HAVE_ncurses) || defined(HAVE_termcap) + my_putstring(lineout); +#else + fputs(lineout,stdout); +#endif } } void -j_yearly(year) - int year; -{ +j_yearly(int day, int year) { int col, *dp, i, month, row, which_cal; int days[12][MAXDAYS]; char *p, lineout[80]; - (void)sprintf(lineout, "%d", year); + sprintf(lineout, "%d", year); center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0); - (void)printf("\n\n"); + printf("\n\n"); + for (i = 0; i < 12; i++) - day_array(i + 1, year, days[i]); - (void)memset(lineout, ' ', sizeof(lineout) - 1); + day_array(day, i + 1, year, days[i]); + memset(lineout, ' ', sizeof(lineout) - 1); lineout[sizeof(lineout) - 1] = '\0'; for (month = 0; month < 12; month += 2) { center(full_month[month], J_WEEK_LEN, J_HEAD_SEP); center(full_month[month + 1], J_WEEK_LEN, 0); - (void)printf("\n%s%*s%s\n", j_day_headings, J_HEAD_SEP, "", + printf("\n%s%*s %s\n", j_day_headings, J_HEAD_SEP, "", j_day_headings); for (row = 0; row < 6; row++) { + p = lineout; for (which_cal = 0; which_cal < 2; which_cal++) { - p = lineout + which_cal * (J_WEEK_LEN + 2); dp = &days[month + which_cal][row * 7]; - for (col = 0; col < 7; col++, p += J_DAY_LEN) - ascii_day(p, *dp++); + for (col = 0; col < 7; col++) + p = ascii_day(p, *dp++); + p += sprintf(p, " "); } *p = '\0'; trim_trailing_spaces(lineout); - (void)printf("%s\n", lineout); +#if defined(HAVE_ncurses) || defined(HAVE_termcap) + my_putstring(lineout);putchar('\n'); +#else + puts(lineout); +#endif } } - (void)printf("\n"); + printf("\n"); } void -yearly(year) - int year; -{ +yearly(int day, int year) { int col, *dp, i, month, row, which_cal; int days[12][MAXDAYS]; - char *p, lineout[80]; + char *p, lineout[100]; - (void)sprintf(lineout, "%d", year); + sprintf(lineout, "%d", year); center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0); - (void)printf("\n\n"); + printf("\n\n"); + for (i = 0; i < 12; i++) - day_array(i + 1, year, days[i]); - (void)memset(lineout, ' ', sizeof(lineout) - 1); + day_array(day, i + 1, year, days[i]); + memset(lineout, ' ', sizeof(lineout) - 1); lineout[sizeof(lineout) - 1] = '\0'; for (month = 0; month < 12; month += 3) { center(full_month[month], WEEK_LEN, HEAD_SEP); center(full_month[month + 1], WEEK_LEN, HEAD_SEP); center(full_month[month + 2], WEEK_LEN, 0); - (void)printf("\n%s%*s%s%*s%s\n", day_headings, HEAD_SEP, + printf("\n%s%*s %s%*s %s\n", day_headings, HEAD_SEP, "", day_headings, HEAD_SEP, "", day_headings); for (row = 0; row < 6; row++) { + p = lineout; for (which_cal = 0; which_cal < 3; which_cal++) { - p = lineout + which_cal * (WEEK_LEN + 2); dp = &days[month + which_cal][row * 7]; - for (col = 0; col < 7; col++, p += DAY_LEN) - ascii_day(p, *dp++); + for (col = 0; col < 7; col++) + p = ascii_day(p, *dp++); + p += sprintf(p, " "); } *p = '\0'; trim_trailing_spaces(lineout); - (void)printf("%s\n", lineout); +#if defined(HAVE_ncurses) || defined(HAVE_termcap) + my_putstring(lineout);putchar('\n'); +#else + puts(lineout); +#endif } } - (void)printf("\n"); + printf("\n"); } /* @@ -531,11 +597,8 @@ * builds that array for any month from Jan. 1 through Dec. 9999. */ void -day_array(month, year, days) - int month, year; - int *days; -{ - int day, dw, dm; +day_array(int day, int month, int year, int *days) { + int julday, daynum, dw, dm; int *d_sep1752; if (month == 9 && year == 1752) { @@ -546,9 +609,14 @@ memcpy(days, empty, MAXDAYS * sizeof(int)); dm = days_in_month[leap_year(year)][month]; dw = (day_in_week(1, month, year) - week1stday + 7) % 7; - day = julian ? day_in_year(1, month, year) : 1; - while (dm--) - days[dw++] = day++; + julday = day_in_year(1, month, year); + daynum = julian ? julday : 1; + while (dm--) { + days[dw] = daynum++; + if (julday++ == day) + days[dw] |= TODAY_FLAG; + dw++; + } } /* @@ -556,15 +624,13 @@ * return the 1 based day number within the year */ int -day_in_year(day, month, year) - int day, month, year; -{ +day_in_year(int day, int month, int year) { int i, leap; leap = leap_year(year); for (i = 1; i < month; i++) day += days_in_month[leap][i]; - return (day); + return day; } /* @@ -575,9 +641,7 @@ * missing days. */ int -day_in_week(day, month, year) - int day, month, year; -{ +day_in_week(int day, int month, int year) { long temp; temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1) @@ -589,12 +653,10 @@ return (THURSDAY); } -void -ascii_day(p, day) - char *p; - int day; -{ +char * +ascii_day(char *p, int day) { int display, val; + int highlight = 0; static char *aday[] = { "", " 1", " 2", " 3", " 4", " 5", " 6", " 7", @@ -605,8 +667,14 @@ }; if (day == SPACE) { - memset(p, ' ', julian ? J_DAY_LEN : DAY_LEN); - return; + int len = julian ? J_DAY_LEN : DAY_LEN; + memset(p, ' ', len); + return p+len; + } + if (day & TODAY_FLAG) { + day &= ~TODAY_FLAG; + p += sprintf(p, Senter); + highlight = 1; } if (julian) { if ((val = day / 100)) { @@ -627,7 +695,10 @@ *p++ = aday[day][0]; *p++ = aday[day][1]; } - *p = ' '; + if (highlight) + p += sprintf(p, Sexit); + *p++ = ' '; + return p; } void @@ -645,26 +716,59 @@ *p = '\0'; } +/* + * Center string, handling multibyte characters appropriately. + * In addition if the string is too large for the width it's truncated. + */ +void +center_str(const char* src, char* dest, size_t dest_size, int width) +{ +#ifdef ENABLE_WIDECHAR + wchar_t str_wc[FMT_ST_CHARS]; +#endif + char str[FMT_ST_CHARS]; + const char* str_to_print=src; + int len, spaces, wide_char_enabled=0; + + len = strlen(src); + +#ifdef ENABLE_WIDECHAR + if (mbstowcs(str_wc, src, FMT_ST_CHARS) > 0) { + wide_char_enabled = 1; + len = wcswidth(str_wc, SIZE(str_wc)); + } +#endif + if (len > width) { + str_to_print=str; + if (wide_char_enabled) { +#ifdef ENABLE_WIDECHAR + str_wc[width]=L'\0'; + wcstombs(str, str_wc, SIZE(str)); +#endif + } else { + strncpy(str, src, SIZE(str)); + str[width]='\0'; + } + } + + spaces = width - len; + spaces = ( spaces < 0 ? 0 : spaces ); + + snprintf(dest, dest_size, "%*s%s%*s", + spaces / 2, "", + str_to_print, + spaces / 2 + spaces % 2, "" ); +} + void center(str, len, separate) const char *str; int len; int separate; { -#ifdef ENABLE_WIDECHAR - wchar_t str_wc[300]; - int str_len; - - if (mbstowcs(str_wc,str,300) > 0) { - str_len = wcswidth(str_wc,300); - } else { - str_len = strlen(str); - } - len -= str_len; -#else - len -= strlen(str); -#endif - (void)printf("%*s%s%*s", len / 2, "", str, len / 2 + len % 2, ""); + char lineout[FMT_ST_CHARS]; + center_str(str, lineout, SIZE(lineout), len); + fputs(lineout, stdout); if (separate) (void)printf("%*s", separate, ""); }