bin/100535: cal and ncal does not take into account multibyte locale strings

Kęstas Paulikas kestas at elen.ktu.lt
Wed Jul 19 13:50:17 UTC 2006


>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 at 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 <sysexits.h>
 #include <time.h>
 #include <unistd.h>
+#include <wchar.h>
 
 /* 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:


More information about the freebsd-bugs mailing list