From owner-freebsd-bugs@FreeBSD.ORG Wed Jul 19 13:50:17 2006 Return-Path: X-Original-To: freebsd-bugs@hub.freebsd.org Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 1DEA816A4E2 for ; Wed, 19 Jul 2006 13:50:17 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 4925B43D49 for ; Wed, 19 Jul 2006 13:50:16 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.13.4/8.13.4) with ESMTP id k6JDoG1F059223 for ; Wed, 19 Jul 2006 13:50:16 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.13.4/8.13.4/Submit) id k6JDoGNQ059219; Wed, 19 Jul 2006 13:50:16 GMT (envelope-from gnats) Resent-Date: Wed, 19 Jul 2006 13:50:16 GMT Resent-Message-Id: <200607191350.k6JDoGNQ059219@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, "Kęstas Paulikas" Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 0481A16A4E5 for ; Wed, 19 Jul 2006 13:49:31 +0000 (UTC) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (www.freebsd.org [216.136.204.117]) by mx1.FreeBSD.org (Postfix) with ESMTP id 504A643D46 for ; Wed, 19 Jul 2006 13:49:30 +0000 (GMT) (envelope-from nobody@FreeBSD.org) Received: from www.freebsd.org (localhost [127.0.0.1]) by www.freebsd.org (8.13.1/8.13.1) with ESMTP id k6JDnTuv078415 for ; Wed, 19 Jul 2006 13:49:29 GMT (envelope-from nobody@www.freebsd.org) Received: (from nobody@localhost) by www.freebsd.org (8.13.1/8.13.1/Submit) id k6JDnTKH078401; Wed, 19 Jul 2006 13:49:29 GMT (envelope-from nobody) Message-Id: <200607191349.k6JDnTKH078401@www.freebsd.org> Date: Wed, 19 Jul 2006 13:49:29 GMT From: "Kęstas Paulikas" To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-2.3 Cc: Subject: bin/100535: cal and ncal does not take into account multibyte locale strings X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 19 Jul 2006 13:50:17 -0000 >Number: 100535 >Category: bin >Synopsis: cal and ncal does not take into account multibyte locale strings >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Jul 19 13:50:15 GMT 2006 >Closed-Date: >Last-Modified: >Originator: Kęstas Paulikas >Release: FreeBSD 6.1-RELEASE i386 >Organization: Kaunas University of Technology >Environment: FreeBSD silke.prudas.lt 6.1-RELEASE FreeBSD 6.1-RELEASE #0: Wed Jun 7 17:04:57 EEST 2006 root@silke.prudas.lt:/usr/obj/usr/src/sys/SILKE i386 >Description: cal and ncal utilities do not handle multibyte (utf8) locale strings correctly, producing incorectly aligned output. >How-To-Repeat: setenv LANG lt_LT.UTF-8 ncal ncal -y cal -y Short weekday name for Saturday length is 1 instead of 2, day numbers are shifted left. Month names are incorrectly alligned. >Fix: Here is patch. Please review it for errors :) --- src/usr.bin/ncal/ncal.c.orig Wed Nov 24 00:57:17 2004 +++ src/usr.bin/ncal/ncal.c Sun Jul 16 01:03:07 2006 @@ -40,6 +40,7 @@ #include #include #include +#include /* Width of one month with backward compatibility */ #define MONTH_WIDTH_B_J 27 @@ -53,13 +54,13 @@ typedef struct date date; struct monthlines { - char name[MAX_WIDTH + 1]; + wchar_t name[MAX_WIDTH + 1]; char lines[7][MAX_WIDTH + 1]; char weeks[MAX_WIDTH + 1]; }; struct weekdays { - char names[7][4]; + wchar_t names[7][4]; }; /* The switches from Julian to Gregorian in some countries */ @@ -159,6 +160,7 @@ int nswitchb; /* switch date for backward compatibility */ char *center(char *s, char *t, int w); +wchar_t* wcenter(wchar_t *s, wchar_t *t, int w); void mkmonth(int year, int month, int jd_flag, struct monthlines * monthl); void mkmonthb(int year, int month, int jd_flag, struct monthlines * monthl); void mkweekdays(struct weekdays * wds); @@ -418,9 +420,9 @@ mkmonth(y, m - 1, jd_flag, &month); mkweekdays(&wds); - printf(" %s %d\n", month.name, y); + wprintf(L" %S %d\n", month.name, y); for (i = 0; i != 7; i++) - printf("%.2s%s\n", wds.names[i], month.lines[i]); + wprintf(L"%.2S%s\n", wds.names[i], month.lines[i]); if (flag_weeks) printf(" %s\n", month.weeks); } @@ -430,7 +432,7 @@ { struct monthlines month; struct weekdays wds; - char s[MAX_WIDTH], t[MAX_WIDTH]; + wchar_t s[MAX_WIDTH], t[MAX_WIDTH]; int i; int mw; @@ -439,15 +441,15 @@ mw = jd_flag ? MONTH_WIDTH_B_J : MONTH_WIDTH_B; - sprintf(s, "%s %d", month.name, y); - printf("%s\n", center(t, s, mw)); + swprintf(s, MAX_WIDTH, L"%S %d", month.name, y); + wprintf(L"%S\n", wcenter(t, s, mw)); if (jd_flag) - printf(" %s %s %s %s %s %s %.2s\n", wds.names[6], wds.names[0], + wprintf(L" %S %S %S %S %S %S %.2S\n", wds.names[6], wds.names[0], wds.names[1], wds.names[2], wds.names[3], wds.names[4], wds.names[5]); else - printf("%s%s%s%s%s%s%.2s\n", wds.names[6], wds.names[0], + wprintf(L"%S%S%S%S%S%S%.2S\n", wds.names[6], wds.names[0], wds.names[1], wds.names[2], wds.names[3], wds.names[4], wds.names[5]); @@ -475,17 +477,17 @@ printf("%s\n", center(t, s, mpl * mw)); for (j = 0; j != 12; j += mpl) { - printf(" %-*s%-*s", + wprintf(L" %-*S%-*S", mw, year[j].name, mw, year[j + 1].name); if (mpl == 3) - printf("%s\n", year[j + 2].name); + wprintf(L"%S\n", year[j + 2].name); else - printf("%-*s%s\n", + wprintf(L"%-*S%S\n", mw, year[j + 2].name, year[j + 3].name); for (i = 0; i != 7; i++) { - printf("%.2s%-*s%-*s", + wprintf(L"%.2S%-*s%-*s", wds.names[i], mw, year[j].lines[i], mw, year[j + 1].lines[i]); @@ -518,6 +520,7 @@ struct monthlines year[12]; struct weekdays wds; char s[80], t[80]; + wchar_t wcs[80], wct[80]; int i, j; int mpl; int mw; @@ -532,17 +535,17 @@ printf("%s\n\n", center(t, s, mw * mpl + mpl)); for (j = 0; j != 12; j += mpl) { - printf("%-*s ", mw, center(s, year[j].name, mw)); + wprintf(L"%-*S ", mw, wcenter(wcs, year[j].name, mw)); if (mpl == 2) - printf("%s\n", center(s, year[j + 1].name, mw)); + wprintf(L"%S\n", wcenter(wcs, year[j + 1].name, mw)); else - printf("%-*s %s\n", mw, - center(s, year[j + 1].name, mw), - center(t, year[j + 2].name, mw)); + wprintf(L"%-*S %S\n", mw, + wcenter(wcs, year[j + 1].name, mw), + wcenter(wct, year[j + 2].name, mw)); if (mpl == 2) - printf(" %s %s %s %s %s %s %s " - " %s %s %s %s %s %s %.2s\n", + wprintf(L" %S %S %S %S %S %S %S " + " %S %S %S %S %S %S %.2S\n", wds.names[6], wds.names[0], wds.names[1], wds.names[2], wds.names[3], wds.names[4], wds.names[5], @@ -550,9 +553,9 @@ wds.names[2], wds.names[3], wds.names[4], wds.names[5]); else - printf("%s%s%s%s%s%s%s " - "%s%s%s%s%s%s%s " - "%s%s%s%s%s%s%.2s\n", + wprintf(L"%S%S%S%S%S%S%S " + "%S%S%S%S%S%S%S " + "%S%S%S%S%S%S%.2S\n", wds.names[6], wds.names[0], wds.names[1], wds.names[2], wds.names[3], wds.names[4], wds.names[5], @@ -596,8 +599,8 @@ /* Set name of month. */ memset(&tm, 0, sizeof(tm)); tm.tm_mon = m; - strftime(mlines->name, sizeof(mlines->name), "%OB", &tm); - mlines->name[0] = toupper((unsigned char)mlines->name[0]); + wcsftime(mlines->name, sizeof(mlines->name)/sizeof(mlines->name[0]), L"%OB", &tm); + mlines->name[0] = towupper((wint_t)mlines->name[0]); /* * Set first and last to the day number of the first day of this @@ -688,8 +691,8 @@ /* Set name of month centered */ memset(&tm, 0, sizeof(tm)); tm.tm_mon = m; - strftime(mlines->name, sizeof(mlines->name), "%OB", &tm); - mlines->name[0] = toupper((unsigned char)mlines->name[0]); + wcsftime(mlines->name, sizeof(mlines->name)/sizeof(mlines->name[0]), L"%OB", &tm); + mlines->name[0] = towupper((wint_t)mlines->name[0]); /* * Set first and last to the day number of the first day of this @@ -754,18 +757,18 @@ { int i, len; struct tm tm; - char buf[20]; + wchar_t buf[20]; memset(&tm, 0, sizeof(tm)); for (i = 0; i != 7; i++) { tm.tm_wday = (i+1) % 7; - strftime(buf, sizeof(buf), "%a", &tm); - len = strlen(buf); + wcsftime(buf, sizeof(buf)/sizeof(buf[0]), L"%a", &tm); + len = wcslen(buf); if (len > 2) len = 2; - strcpy(wds->names[i], " "); - strncpy(wds->names[i] + 2 - len, buf, len); + wcscpy(wds->names[i], L" "); + wcsncpy(wds->names[i] + 2 - len, buf, len); } } @@ -855,6 +858,17 @@ memset(blanks, ' ', sizeof(blanks)); sprintf(s, "%.*s%s", (int)(w - strlen(t)) / 2, blanks, t); + return (s); +} + +/* Center string t in string s of length w by putting enough leading blanks (wchar_t version) */ +wchar_t * +wcenter(wchar_t *s, wchar_t *t, int w) +{ + char blanks[80]; + + memset(blanks, ' ', sizeof(blanks)); + swprintf(s, 80, L"%.*s%S", (int)(w - wcslen(t)) / 2, blanks, t); return (s); } >Release-Note: >Audit-Trail: >Unformatted: