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