1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 1992-2009 Edwin Groothuis <edwin@FreeBSD.org>.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30#include <sys/cdefs.h>
31#include <sys/time.h>
32#include <err.h>
33#include <langinfo.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37#ifdef WITH_ICONV
38#include <iconv.h>
39#include <errno.h>
40
41static iconv_t conv = (iconv_t)-1;
42static char *currentEncoding = NULL;
43
44#endif
45
46#include "pathnames.h"
47#include "calendar.h"
48
49#ifdef WITH_ICONV
50void
51set_new_encoding(void)
52{
53	const char *newenc;
54
55	newenc = nl_langinfo(CODESET);
56	if (currentEncoding == NULL) {
57		currentEncoding = strdup(newenc);
58		if (currentEncoding == NULL)
59			errx(1, "set_new_encoding: cannot allocate memory");
60		return;
61	}
62	if (strcmp(currentEncoding, newenc) == 0)
63		return;
64	free(currentEncoding);
65	currentEncoding = strdup(newenc);
66	if (currentEncoding == NULL)
67		errx(1, "set_new_encoding: cannot allocate memory");
68	if (conv != (iconv_t) -1) {
69		iconv_close(conv);
70		conv = (iconv_t) -1;
71	}
72}
73#endif
74
75static char *
76convert(char *input)
77{
78	char *output;
79#ifdef WITH_ICONV
80	size_t inleft, outleft, converted = 0;
81	char *outbuf, *tmp;
82	char *inbuf;
83	size_t outlen;
84
85	if (currentEncoding == NULL) {
86		output = strdup(input);
87		if (output == NULL)
88			errx(1, "convert: cannot allocate memory");
89		return (output);
90	}
91	if (conv == (iconv_t)-1) {
92		conv = iconv_open(outputEncoding, currentEncoding);
93		if (conv == (iconv_t)-1) {
94			if (errno == EINVAL)
95				errx(1, "Conversion is not supported");
96			else
97				err(1, "Initialization failure");
98		}
99	}
100
101	inleft = strlen(input);
102	inbuf = input;
103
104	outlen = inleft;
105	if ((output = malloc(outlen + 1)) == NULL)
106		errx(1, "convert: cannot allocate memory");
107
108	for (;;) {
109		errno = 0;
110		outbuf = output + converted;
111		outleft = outlen - converted;
112
113		converted = iconv(conv, (char **) &inbuf, &inleft, &outbuf, &outleft);
114		if (converted != (size_t) -1 || errno == EINVAL) {
115			/* finished or invalid multibyte, so truncate and ignore */
116			break;
117		}
118
119		if (errno != E2BIG) {
120			free(output);
121			err(1, "convert");
122		}
123
124		converted = outbuf - output;
125		outlen += inleft * 2;
126
127		if ((tmp = realloc(output, outlen + 1)) == NULL) {
128			free(output);
129			errx(1, "convert: cannot allocate memory");
130		}
131
132		output = tmp;
133		outbuf = output + converted;
134	}
135
136	/* flush the iconv conversion */
137	iconv(conv, NULL, NULL, &outbuf, &outleft);
138
139	/* null terminate the string */
140	*outbuf = '\0';
141#else
142	output = strdup(input);
143	if (output == NULL)
144		errx(1, "convert: cannot allocate memory");
145#endif
146
147	return (output);
148}
149
150struct event *
151event_add(int year, int month, int day, int var, char *txt, char *extra)
152{
153	struct event *e;
154
155	/*
156	 * Creating a new event:
157	 * - Create a new event
158	 * - Copy the machine readable day and month
159	 * - Copy the text of the event
160	 */
161	e = (struct event *)calloc(1, sizeof(struct event));
162	if (e == NULL)
163		errx(1, "event_add: cannot allocate memory");
164	e->year = year;
165	e->month = month;
166	e->day = day;
167	e->var = var;
168	e->text = convert(txt);
169	if (e->text == NULL)
170		errx(1, "event_add: cannot allocate memory");
171	e->extra = NULL;
172	if (extra != NULL && extra[0] != '\0')
173		e->extra = convert(extra);
174	addtodate(e);
175	return (e);
176}
177
178void
179event_continue(struct event *e, char *txt)
180{
181	char *oldtext, *text;
182
183	text = convert(txt);
184	oldtext = e->text;
185	if (oldtext == NULL)
186		errx(1, "event_continue: cannot allocate memory");
187
188	asprintf(&e->text, "%s\n%s", oldtext, text);
189	if (e->text == NULL)
190		errx(1, "event_continue: cannot allocate memory");
191	free(oldtext);
192	free(text);
193
194	return;
195}
196
197void
198event_print_all(FILE *fp)
199{
200	struct event *e;
201	struct tm tm;
202	char dbuf[80];
203	static int d_first;
204
205	d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
206
207	while (walkthrough_dates(&e) != 0) {
208		if (e) {
209#ifdef DEBUG
210			fprintf(stderr, "event_print_all month: %d, day: %d\n",
211			    e->month, e->day);
212#endif
213			memset(&tm, 0, sizeof(struct tm));
214			tm.tm_mday = e->day;
215			tm.tm_mon = e->month - 1;
216			tm.tm_year = e->year - 1900;
217			(void)strftime(dbuf, sizeof(dbuf), d_first ? "%e %b" : "%b %e", &tm);
218		}
219
220		/*
221		 * Go through all events and print the text of the matching
222		 * dates
223		 */
224		while (e != NULL) {
225			(void)fprintf(fp, "%s%c%s%s%s%s\n", dbuf,
226			    e->var ? '*' : ' ', e->text,
227			    e->extra != NULL ? " (" : "",
228			    e->extra != NULL ? e->extra : "",
229			    e->extra != NULL ? ")" : ""
230			);
231
232			e = e->next;
233		}
234	}
235}
236