Index: head/usr.bin/calendar/Makefile =================================================================== --- head/usr.bin/calendar/Makefile +++ head/usr.bin/calendar/Makefile @@ -13,6 +13,10 @@ DE_LINKS= de_DE.ISO8859-15 FR_LINKS= fr_FR.ISO8859-15 +.if ${MK_ICONV} == "yes" +CFLAGS+= -DWITH_ICONV +.endif + FILESGROUPS+= CALS CALS= calendars/calendar.all \ calendars/calendar.australia \ Index: head/usr.bin/calendar/calendar.h =================================================================== --- head/usr.bin/calendar/calendar.h +++ head/usr.bin/calendar/calendar.h @@ -59,6 +59,9 @@ extern struct fixs nmarequinox, nsepequinox, njunsolstice, ndecsolstice; extern double UTCOffset; extern int EastLongitude; +#ifdef WITH_ICONV +extern const char *outputEncoding; +#endif #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) @@ -197,3 +200,7 @@ void equinoxsolstice(int year, double UTCoffset, int *equinoxdays, int *solsticedays); void fequinoxsolstice(int year, double UTCoffset, double *equinoxdays, double *solsticedays); int calculatesunlongitude30(int year, int degreeGMToffset, int *ichinesemonths); + +#ifdef WITH_ICONV +void set_new_encoding(void); +#endif Index: head/usr.bin/calendar/calendar.c =================================================================== --- head/usr.bin/calendar/calendar.c +++ head/usr.bin/calendar/calendar.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,9 @@ static time_t f_time = 0; double UTCOffset = UTCOFFSET_NOTSET; int EastLongitude = LONGITUDE_NOTSET; +#ifdef WITH_ICONV +const char *outputEncoding; +#endif static void usage(void) __dead2; @@ -80,6 +84,12 @@ struct tm tp1, tp2; (void)setlocale(LC_ALL, ""); +#ifdef WITH_ICONV + /* save the information about the encoding used in the terminal */ + outputEncoding = strdup(nl_langinfo(CODESET)); + if (outputEncoding == NULL) + errx(1, "cannot allocate memory"); +#endif while ((ch = getopt(argc, argv, "-A:aB:D:dF:f:l:t:U:W:?")) != -1) switch (ch) { Index: head/usr.bin/calendar/events.c =================================================================== --- head/usr.bin/calendar/events.c +++ head/usr.bin/calendar/events.c @@ -35,10 +35,120 @@ #include #include #include +#ifdef WITH_ICONV +#include +#include +#include +static iconv_t conv = (iconv_t)-1; +static char *currentEncoding = NULL; + +#endif + #include "pathnames.h" #include "calendar.h" +#ifdef WITH_ICONV +void +set_new_encoding(void) +{ + const char *newenc; + + newenc = nl_langinfo(CODESET); + if (currentEncoding == NULL) { + currentEncoding = strdup(newenc); + if (currentEncoding == NULL) + errx(1, "set_new_encoding: cannot allocate memory"); + return; + } + if (strcmp(currentEncoding, newenc) == 0) + return; + free(currentEncoding); + currentEncoding = strdup(newenc); + if (currentEncoding == NULL) + errx(1, "set_new_encoding: cannot allocate memory"); + if (conv != (iconv_t) -1) { + iconv_close(conv); + conv = (iconv_t) -1; + } +} +#endif + +static char * +convert(char *input) +{ + char *output; +#ifdef WITH_ICONV + size_t inleft, outleft, converted = 0; + char *outbuf, *tmp; + char *inbuf; + size_t outlen; + + if (currentEncoding == NULL) { + output = strdup(input); + if (output == NULL) + errx(1, "convert: cannot allocate memory"); + return (output); + } + if (conv == (iconv_t)-1) { + conv = iconv_open(outputEncoding, currentEncoding); + if (conv == (iconv_t)-1) { + if (errno == EINVAL) + errx(1, "Conversion is not supported"); + else + err(1, "Initialization failure"); + } + } + + inleft = strlen(input); + inbuf = input; + + outlen = inleft; + if ((output = malloc(outlen + 1)) == NULL) + errx(1, "convert: cannot allocate memory"); + + for (;;) { + errno = 0; + outbuf = output + converted; + outleft = outlen - converted; + + converted = iconv(conv, (char **) &inbuf, &inleft, &outbuf, &outleft); + if (converted != (size_t) -1 || errno == EINVAL) { + /* finished or invalid multibyte, so truncate and ignore */ + break; + } + + if (errno != E2BIG) { + free(output); + err(1, "convert"); + } + + converted = outbuf - output; + outlen += inleft * 2; + + if ((tmp = realloc(output, outlen + 1)) == NULL) { + free(output); + errx(1, "convert: cannot allocate memory"); + } + + output = tmp; + outbuf = output + converted; + } + + /* flush the iconv conversion */ + iconv(conv, NULL, NULL, &outbuf, &outleft); + + /* null terminate the string */ + *outbuf = '\0'; +#else + output = strdup(input); + if (output == NULL) + errx(1, "convert: cannot allocate memory"); +#endif + + return (output); +} + struct event * event_add(int year, int month, int day, char *date, int var, char *txt, char *extra) @@ -58,15 +168,15 @@ e->month = month; e->day = day; e->var = var; - e->date = strdup(date); + e->date = convert(date); if (e->date == NULL) errx(1, "event_add: cannot allocate memory"); - e->text = strdup(txt); + e->text = convert(txt); if (e->text == NULL) errx(1, "event_add: cannot allocate memory"); e->extra = NULL; if (extra != NULL && extra[0] != '\0') - e->extra = strdup(extra); + e->extra = convert(extra); addtodate(e, year, month, day); return (e); } @@ -74,23 +184,17 @@ void event_continue(struct event *e, char *txt) { - char *text; + char *oldtext, *text; - /* - * Adding text to the event: - * - Save a copy of the old text (unknown length, so strdup()) - * - Allocate enough space for old text + \n + new text + 0 - * - Store the old text + \n + new text - * - Destroy the saved copy. - */ - text = strdup(e->text); - if (text == NULL) + text = convert(txt); + oldtext = e->text; + if (oldtext == NULL) errx(1, "event_continue: cannot allocate memory"); - free(e->text); - asprintf(&e->text, "%s\n%s", text, txt); + asprintf(&e->text, "%s\n%s", oldtext, text); if (e->text == NULL) errx(1, "event_continue: cannot allocate memory"); + free(oldtext); free(text); return; Index: head/usr.bin/calendar/io.c =================================================================== --- head/usr.bin/calendar/io.c +++ head/usr.bin/calendar/io.c @@ -294,6 +294,9 @@ if (strncmp(buf, "LANG=", 5) == 0) { (void)setlocale(LC_ALL, buf + 5); d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); +#ifdef WITH_ICONV + set_new_encoding(); +#endif setnnames(); continue; }