diff options
author | Pádraig Brady | 2008-01-04 11:44:53 +0100 |
---|---|---|
committer | Karel Zak | 2008-01-17 02:21:53 +0100 |
commit | ff87defc0d92c2e95e24e04e1e2b73fc09f7a89f (patch) | |
tree | c2ea29c113d4a13b46633ab6af7473e75e8a3de2 /misc-utils/cal.c | |
parent | fdisk: calculate +size{K,M,G} in 2^N (diff) | |
download | kernel-qcow2-util-linux-ff87defc0d92c2e95e24e04e1e2b73fc09f7a89f.tar.gz kernel-qcow2-util-linux-ff87defc0d92c2e95e24e04e1e2b73fc09f7a89f.tar.xz kernel-qcow2-util-linux-ff87defc0d92c2e95e24e04e1e2b73fc09f7a89f.zip |
cal: fix weekday alignment for certain locales
For example this had too much padding: LANG=zh_CN.utf8 cal -j
while this had too little padding: LANG=hu_HU.utf8 cal
This had invalid chars: LANG=li_BE.utf8 cal
This had too few chars: LANG=si_LK.utf8 cal
Note some locales may display with slightly worse alignment
(fa_IR.utf8 for example), but that is only because the terminal
is not merging the combining characters. This happens on
gnome-terminal-2.18.3-1.fc8 at least.
Signed-off-by: Pádraig Brady <P@draigBrady.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'misc-utils/cal.c')
-rw-r--r-- | misc-utils/cal.c | 149 |
1 files changed, 86 insertions, 63 deletions
diff --git a/misc-utils/cal.c b/misc-utils/cal.c index fd2700f98..ec6abf493 100644 --- a/misc-utils/cal.c +++ b/misc-utils/cal.c @@ -241,7 +241,7 @@ struct fmt_st }; char * ascii_day(char *, int); -void center_str(const char* src, char* dest, size_t dest_size, int width); +int 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); @@ -387,25 +387,11 @@ main(int argc, char **argv) { exit(0); } -#ifndef HAVE_WIDECHAR -static char *eos(char *s) { - while (s && *s) - s++; - return s; -} -#endif - void headers_init(void) { int i, wd; -#ifdef HAVE_WIDECHAR - wchar_t day_headings_wc[22],j_day_headings_wc[29]; char *cur_dh = day_headings, *cur_j_dh = j_day_headings; - wcscpy(day_headings_wc, L""); - wcscpy(j_day_headings_wc, L""); -#endif - strcpy(day_headings,""); strcpy(j_day_headings,""); @@ -418,27 +404,22 @@ void headers_init(void) for(i = 0 ; i < 7 ; i++ ) { ssize_t space_left; wd = (i + week1stday) % 7; -#ifdef HAVE_WIDECHAR - swprintf(day_headings_wc, SIZE(day_headings_wc), L"%1.2s ", weekday(wd)); - swprintf(j_day_headings_wc, SIZE(j_day_headings_wc), L"%3.3s ", weekday(wd)); + if (i) + strcat(cur_dh++, " "); space_left = sizeof(day_headings) - (cur_dh - day_headings); - if(space_left <= 0) - break; - cur_dh += wcstombs(cur_dh, day_headings_wc, space_left); - - space_left = sizeof(j_day_headings)-(cur_j_dh-j_day_headings); - if(space_left <= 0) - break; - cur_j_dh += wcstombs(cur_j_dh,j_day_headings_wc, space_left); -#else - sprintf(eos(day_headings), "%2.2s ", weekday(wd)); - sprintf(eos(j_day_headings), "%3.3s ", weekday(wd)); -#endif + if(space_left <= 2) + break; + cur_dh += center_str(weekday(wd), cur_dh, space_left, 2); + + if (i) + strcat(cur_j_dh++, " "); + space_left = sizeof(j_day_headings) - (cur_j_dh - j_day_headings); + if(space_left <= 3) + break; + cur_j_dh += center_str(weekday(wd), cur_j_dh, space_left, 3); } - trim_trailing_spaces(day_headings); - trim_trailing_spaces(j_day_headings); #undef weekday for (i = 0; i < 12; i++) { @@ -452,7 +433,7 @@ void headers_init(void) void do_monthly(int day, int month, int year, struct fmt_st *out) { - int col, row, len, days[MAXDAYS]; + int col, row, days[MAXDAYS]; char *p, lineout[FMT_ST_CHARS]; int width = (julian ? J_WEEK_LEN : WEEK_LEN) - 1; @@ -464,10 +445,11 @@ do_monthly(int day, int month, int year, struct fmt_st *out) { * 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); + snprintf(lineout, sizeof(lineout), _("%s %d"), + full_month[month - 1], year); center_str(lineout, out->s[0], SIZE(out->s[0]), width); - sprintf(out->s[1],"%s", + snprintf(out->s[1], FMT_ST_CHARS, "%s", julian ? j_day_headings : day_headings); for (row = 0; row < 6; row++) { int has_hl = 0; @@ -479,7 +461,7 @@ do_monthly(int day, int month, int year, struct fmt_st *out) { } *p = '\0'; trim_trailing_spaces(lineout); - sprintf(out->s[row+2], "%s", lineout); + snprintf(out->s[row+2], FMT_ST_CHARS, "%s", lineout); if (has_hl) Hrow = out->s[row+2]; } @@ -555,8 +537,8 @@ j_yearly(int day, int year) { int days[12][MAXDAYS]; char *p, lineout[80]; - sprintf(lineout, "%d", year); - center(lineout, J_WEEK_LEN * 2 + J_HEAD_SEP, 0); + snprintf(lineout, sizeof(lineout), "%d", year); + center(lineout, J_WEEK_LEN*2 + J_HEAD_SEP - 1, 0); printf("\n\n"); for (i = 0; i < 12; i++) @@ -564,8 +546,8 @@ j_yearly(int day, int year) { 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); + center(full_month[month], J_WEEK_LEN-1, J_HEAD_SEP+1); + center(full_month[month + 1], J_WEEK_LEN-1, 0); printf("\n%s%*s %s\n", j_day_headings, J_HEAD_SEP, "", j_day_headings); for (row = 0; row < 6; row++) { @@ -591,8 +573,8 @@ yearly(int day, int year) { int days[12][MAXDAYS]; char *p, lineout[100]; - sprintf(lineout, "%d", year); - center(lineout, WEEK_LEN * 3 + HEAD_SEP * 2, 0); + snprintf(lineout, sizeof(lineout), "%d", year); + center(lineout, WEEK_LEN*3 + HEAD_SEP*2 - 1, 0); printf("\n\n"); for (i = 0; i < 12; i++) @@ -600,9 +582,9 @@ yearly(int day, int year) { 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); + center(full_month[month], WEEK_LEN-1, HEAD_SEP+1); + center(full_month[month + 1], WEEK_LEN-1, HEAD_SEP+1); + center(full_month[month + 2], WEEK_LEN-1, 0); printf("\n%s%*s %s%*s %s\n", day_headings, HEAD_SEP, "", day_headings, HEAD_SEP, "", day_headings); for (row = 0; row < 6; row++) { @@ -752,11 +734,49 @@ trim_trailing_spaces(s) *p = '\0'; } +#ifdef HAVE_WIDECHAR +/* replace non printable chars. + * return 1 if replacement made, 0 otherwise */ +int wc_ensure_printable(wchar_t* wchars) +{ + int replaced=0; + wchar_t* wc = wchars; + while (*wc) { + if (!iswprint((wint_t) *wc)) { + *wc=L'\uFFFD'; + replaced=1; + } + wc++; + } + return replaced; +} + +/* truncate wchar string to width cells. + * returns number of cells used. */ +size_t wc_truncate(wchar_t* wchars, size_t width, size_t minchars) +{ + int wc=0; + int cells=0; + while (*(wchars+wc)) { + cells = wcswidth(wchars, wc+1); + if (cells > width) { + if (wc >= minchars) { + break; + } + } + wc++; + } + wchars[wc]=L'\0'; + return cells; +} +#endif + /* * Center string, handling multibyte characters appropriately. * In addition if the string is too large for the width it's truncated. + * The number of trailing spaces may be 1 less than the number of leading spaces. */ -void +int center_str(const char* src, char* dest, size_t dest_size, int width) { #ifdef HAVE_WIDECHAR @@ -764,36 +784,39 @@ center_str(const char* src, char* dest, size_t dest_size, int width) #endif char str[FMT_ST_CHARS]; const char* str_to_print=src; - int len, spaces, wide_char_enabled=0; - - len = strlen(src); + int used, spaces, wc_conversion=0, wc_enabled=0; #ifdef HAVE_WIDECHAR - if (mbstowcs(str_wc, src, FMT_ST_CHARS) > 0) { - wide_char_enabled = 1; - len = wcswidth(str_wc, SIZE(str_wc)); + if (mbstowcs(str_wc, src, SIZE(str_wc)) > 0) { + str_wc[SIZE(str_wc)-1]=L'\0'; + wc_enabled=1; + wc_conversion = wc_ensure_printable(str_wc); + used = wcswidth(str_wc, SIZE(str_wc)); } + else #endif - if (len > width) { + used = strlen(src); + + if (wc_conversion || used > width) { str_to_print=str; - if (wide_char_enabled) { + if (wc_enabled) { #ifdef HAVE_WIDECHAR - str_wc[width]=L'\0'; + used = wc_truncate(str_wc, width, 1); wcstombs(str, str_wc, SIZE(str)); #endif } else { - strncpy(str, src, SIZE(str)); + memcpy(str, src, width); str[width]='\0'; } } - spaces = width - len; + spaces = width - used; spaces = ( spaces < 0 ? 0 : spaces ); - snprintf(dest, dest_size, "%*s%s%*s", - spaces / 2, "", - str_to_print, - spaces / 2 + spaces % 2, "" ); + return snprintf(dest, dest_size, "%*s%s%*s", + spaces / 2 + spaces % 2, "", + str_to_print, + spaces / 2, "" ); } void @@ -806,13 +829,13 @@ center(str, len, separate) center_str(str, lineout, SIZE(lineout), len); fputs(lineout, stdout); if (separate) - (void)printf("%*s", separate, ""); + printf("%*s", separate, ""); } void usage() { - (void)fprintf(stderr, _("usage: cal [-13smjyV] [[[day] month] year]\n")); + fprintf(stderr, _("usage: cal [-13smjyV] [[[day] month] year]\n")); exit(1); } |