1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 __FBSDID("$FreeBSD$"); 32 33 #include <sys/time.h> 34 #include <err.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #ifdef WITH_ICONV 39 #include <iconv.h> 40 #include <errno.h> 41 #include <langinfo.h> 42 #include <locale.h> 43 44 static iconv_t conv = (iconv_t)-1; 45 static char *currentEncoding = NULL; 46 47 #endif 48 49 #include "pathnames.h" 50 #include "calendar.h" 51 52 #ifdef WITH_ICONV 53 void 54 set_new_encoding(void) 55 { 56 const char *newenc; 57 58 newenc = nl_langinfo(CODESET); 59 if (currentEncoding == NULL) { 60 currentEncoding = strdup(newenc); 61 if (currentEncoding == NULL) 62 errx(1, "set_new_encoding: cannot allocate memory"); 63 return; 64 } 65 if (strcmp(currentEncoding, newenc) == 0) 66 return; 67 free(currentEncoding); 68 currentEncoding = strdup(newenc); 69 if (currentEncoding == NULL) 70 errx(1, "set_new_encoding: cannot allocate memory"); 71 if (conv != (iconv_t) -1) { 72 iconv_close(conv); 73 conv = (iconv_t) -1; 74 } 75 } 76 #endif 77 78 static char * 79 convert(char *input) 80 { 81 char *output; 82 #ifdef WITH_ICONV 83 size_t inleft, outleft, converted = 0; 84 char *outbuf, *tmp; 85 char *inbuf; 86 size_t outlen; 87 88 if (currentEncoding == NULL) { 89 output = strdup(input); 90 if (output == NULL) 91 errx(1, "convert: cannot allocate memory"); 92 return (output); 93 } 94 if (conv == (iconv_t)-1) { 95 conv = iconv_open(outputEncoding, currentEncoding); 96 if (conv == (iconv_t)-1) { 97 if (errno == EINVAL) 98 errx(1, "Conversion is not supported"); 99 else 100 err(1, "Initialization failure"); 101 } 102 } 103 104 inleft = strlen(input); 105 inbuf = input; 106 107 outlen = inleft; 108 if ((output = malloc(outlen + 1)) == NULL) 109 errx(1, "convert: cannot allocate memory"); 110 111 for (;;) { 112 errno = 0; 113 outbuf = output + converted; 114 outleft = outlen - converted; 115 116 converted = iconv(conv, (char **) &inbuf, &inleft, &outbuf, &outleft); 117 if (converted != (size_t) -1 || errno == EINVAL) { 118 /* finished or invalid multibyte, so truncate and ignore */ 119 break; 120 } 121 122 if (errno != E2BIG) { 123 free(output); 124 err(1, "convert"); 125 } 126 127 converted = outbuf - output; 128 outlen += inleft * 2; 129 130 if ((tmp = realloc(output, outlen + 1)) == NULL) { 131 free(output); 132 errx(1, "convert: cannot allocate memory"); 133 } 134 135 output = tmp; 136 outbuf = output + converted; 137 } 138 139 /* flush the iconv conversion */ 140 iconv(conv, NULL, NULL, &outbuf, &outleft); 141 142 /* null terminate the string */ 143 *outbuf = '\0'; 144 #else 145 output = strdup(input); 146 if (output == NULL) 147 errx(1, "convert: cannot allocate memory"); 148 #endif 149 150 return (output); 151 } 152 153 struct event * 154 event_add(int year, int month, int day, int var, char *txt, char *extra) 155 { 156 struct event *e; 157 158 /* 159 * Creating a new event: 160 * - Create a new event 161 * - Copy the machine readable day and month 162 * - Copy the text of the event 163 */ 164 e = (struct event *)calloc(1, sizeof(struct event)); 165 if (e == NULL) 166 errx(1, "event_add: cannot allocate memory"); 167 e->year = year; 168 e->month = month; 169 e->day = day; 170 e->var = var; 171 e->text = convert(txt); 172 if (e->text == NULL) 173 errx(1, "event_add: cannot allocate memory"); 174 e->extra = NULL; 175 if (extra != NULL && extra[0] != '\0') 176 e->extra = convert(extra); 177 addtodate(e); 178 return (e); 179 } 180 181 void 182 event_continue(struct event *e, char *txt) 183 { 184 char *oldtext, *text; 185 186 text = convert(txt); 187 oldtext = e->text; 188 if (oldtext == NULL) 189 errx(1, "event_continue: cannot allocate memory"); 190 191 asprintf(&e->text, "%s\n%s", oldtext, text); 192 if (e->text == NULL) 193 errx(1, "event_continue: cannot allocate memory"); 194 free(oldtext); 195 free(text); 196 197 return; 198 } 199 200 void 201 event_print_all(FILE *fp) 202 { 203 struct event *e; 204 struct tm tm; 205 char dbuf[80]; 206 static int d_first; 207 const char *lang; 208 209 lang = getenv("LANG"); 210 if (lang == NULL) 211 lang = "C"; 212 if (setlocale(LC_ALL, lang) == NULL) 213 (void)setlocale(LC_ALL, "C"); 214 d_first = (*nl_langinfo(D_MD_ORDER) == 'd'); 215 216 while (walkthrough_dates(&e) != 0) { 217 if (e) { 218 #ifdef DEBUG 219 fprintf(stderr, "event_print_all month: %d, day: %d\n", 220 e->month, e->day); 221 #endif 222 memset(&tm, 0, sizeof(struct tm)); 223 tm.tm_mday = e->day; 224 tm.tm_mon = e->month - 1; 225 tm.tm_year = e->year - 1900; 226 (void)strftime(dbuf, sizeof(dbuf), d_first ? "%e %b" : "%b %e", &tm); 227 } 228 229 /* 230 * Go through all events and print the text of the matching 231 * dates 232 */ 233 while (e != NULL) { 234 (void)fprintf(fp, "%s%c%s%s%s%s\n", dbuf, 235 e->var ? '*' : ' ', e->text, 236 e->extra != NULL ? " (" : "", 237 e->extra != NULL ? e->extra : "", 238 e->extra != NULL ? ")" : "" 239 ); 240 241 e = e->next; 242 } 243 } 244 } 245