aboutsummaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2019-02-20 06:40:52 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2019-02-20 06:40:52 +0000
commitadedf5ee31dfb93f5b5f535f12a3ee0b8a24e955 (patch)
tree43807c4ed18a9e1ecfaeb2d25c3b8b663780c946 /usr.bin
parent748f247a449469df15b435999eacb5a85601c280 (diff)
downloadsrc-adedf5ee31dfb93f5b5f535f12a3ee0b8a24e955.tar.gz
src-adedf5ee31dfb93f5b5f535f12a3ee0b8a24e955.zip
calendar: use iconv to respect the output encoding
calendar(1) can have input in various encoding, specifying LANG=<locale_name> to enable calendar(1) to determine which one to use. The problem is the content of the calendar itself is exposed as is making it unreadable in many cases. For example french calendar which is encoded ISO8859-1 is rendered badly in a fr_FR.UTF-8 environment. Using iconv allows to solve this issue. This will also allow to keep only 1 encoding in base for those files without breaking user existing setup Reported by: many MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D19221
Notes
Notes: svn path=/head/; revision=344340
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/calendar/Makefile4
-rw-r--r--usr.bin/calendar/calendar.c10
-rw-r--r--usr.bin/calendar/calendar.h7
-rw-r--r--usr.bin/calendar/events.c134
-rw-r--r--usr.bin/calendar/io.c3
5 files changed, 143 insertions, 15 deletions
diff --git a/usr.bin/calendar/Makefile b/usr.bin/calendar/Makefile
index 81401f57b8ee..2a51b3319a39 100644
--- a/usr.bin/calendar/Makefile
+++ b/usr.bin/calendar/Makefile
@@ -13,6 +13,10 @@ INTER= de_AT.ISO_8859-15 de_DE.ISO8859-1 fr_FR.ISO8859-1 \
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 \
diff --git a/usr.bin/calendar/calendar.c b/usr.bin/calendar/calendar.c
index d0c42f424267..a9e6c19e9a0d 100644
--- a/usr.bin/calendar/calendar.c
+++ b/usr.bin/calendar/calendar.c
@@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
#include <err.h>
#include <errno.h>
#include <locale.h>
+#include <langinfo.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@@ -66,6 +67,9 @@ static char *DEBUG = NULL;
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 @@ main(int argc, char *argv[])
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) {
diff --git a/usr.bin/calendar/calendar.h b/usr.bin/calendar/calendar.h
index 2b00a66f248e..2604568352b5 100644
--- a/usr.bin/calendar/calendar.h
+++ b/usr.bin/calendar/calendar.h
@@ -59,6 +59,9 @@ extern struct fixs neaster, npaskha, ncny, nfullmoon, nnewmoon;
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 fpom(int year, double utcoffset, double *ffms, double *fnms);
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
diff --git a/usr.bin/calendar/events.c b/usr.bin/calendar/events.c
index 113962bc8a03..84f8f2b41a8b 100644
--- a/usr.bin/calendar/events.c
+++ b/usr.bin/calendar/events.c
@@ -35,10 +35,120 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifdef WITH_ICONV
+#include <iconv.h>
+#include <errno.h>
+#include <langinfo.h>
+
+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 @@ event_add(int year, int month, int day, char *date, int var, char *txt,
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 @@ event_add(int year, int month, int day, char *date, int var, char *txt,
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;
diff --git a/usr.bin/calendar/io.c b/usr.bin/calendar/io.c
index 0b894f0b8945..191c86bd7706 100644
--- a/usr.bin/calendar/io.c
+++ b/usr.bin/calendar/io.c
@@ -294,6 +294,9 @@ cal_parse(FILE *in, FILE *out)
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;
}