1 /*- 2 * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 3 * Copyright 2015 John Marino <draco@marino.st> 4 * 5 * This source code is derived from the illumos localedef command, and 6 * provided under BSD-style license terms by Nexenta Systems, Inc. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 /* 32 * LC_TIME database generation routines for localedef. 33 */ 34 #include <sys/cdefs.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <errno.h> 38 #include <sys/types.h> 39 #include <string.h> 40 #include <unistd.h> 41 #include "localedef.h" 42 #include "parser.h" 43 #include "timelocal.h" 44 45 struct lc_time_T tm; 46 47 void 48 init_time(void) 49 { 50 (void) memset(&tm, 0, sizeof (tm)); 51 } 52 53 void 54 add_time_str(wchar_t *wcs) 55 { 56 char *str; 57 58 if ((str = to_mb_string(wcs)) == NULL) { 59 INTERR; 60 return; 61 } 62 free(wcs); 63 64 switch (last_kw) { 65 case T_D_T_FMT: 66 tm.c_fmt = str; 67 break; 68 case T_D_FMT: 69 tm.x_fmt = str; 70 break; 71 case T_T_FMT: 72 tm.X_fmt = str; 73 break; 74 case T_T_FMT_AMPM: 75 tm.ampm_fmt = str; 76 break; 77 case T_DATE_FMT: 78 /* 79 * This one is a Solaris extension, Too bad date just 80 * doesn't use %c, which would be simpler. 81 */ 82 tm.date_fmt = str; 83 break; 84 case T_ERA_D_FMT: 85 case T_ERA_T_FMT: 86 case T_ERA_D_T_FMT: 87 /* Silently ignore it. */ 88 free(str); 89 break; 90 default: 91 free(str); 92 INTERR; 93 break; 94 } 95 } 96 97 static void 98 add_list(const char *ptr[], char *str, int limit) 99 { 100 int i; 101 for (i = 0; i < limit; i++) { 102 if (ptr[i] == NULL) { 103 ptr[i] = str; 104 return; 105 } 106 } 107 fprintf(stderr,"too many list elements\n"); 108 } 109 110 void 111 add_time_list(wchar_t *wcs) 112 { 113 char *str; 114 115 if ((str = to_mb_string(wcs)) == NULL) { 116 INTERR; 117 return; 118 } 119 free(wcs); 120 121 switch (last_kw) { 122 case T_ABMON: 123 add_list(tm.mon, str, 12); 124 break; 125 case T_MON: 126 add_list(tm.month, str, 12); 127 break; 128 case T_ABDAY: 129 add_list(tm.wday, str, 7); 130 break; 131 case T_DAY: 132 add_list(tm.weekday, str, 7); 133 break; 134 case T_AM_PM: 135 if (tm.am == NULL) { 136 tm.am = str; 137 } else if (tm.pm == NULL) { 138 tm.pm = str; 139 } else { 140 fprintf(stderr,"too many list elements\n"); 141 free(str); 142 } 143 break; 144 case T_ALT_DIGITS: 145 case T_ERA: 146 free(str); 147 break; 148 default: 149 free(str); 150 INTERR; 151 break; 152 } 153 } 154 155 void 156 check_time_list(void) 157 { 158 switch (last_kw) { 159 case T_ABMON: 160 if (tm.mon[11] != NULL) 161 return; 162 break; 163 case T_MON: 164 if (tm.month[11] != NULL) 165 return; 166 break; 167 case T_ABDAY: 168 if (tm.wday[6] != NULL) 169 return; 170 break; 171 case T_DAY: 172 if (tm.weekday[6] != NULL) 173 return; 174 break; 175 case T_AM_PM: 176 if (tm.pm != NULL) 177 return; 178 break; 179 case T_ERA: 180 case T_ALT_DIGITS: 181 return; 182 default: 183 fprintf(stderr,"unknown list\n"); 184 break; 185 } 186 187 fprintf(stderr,"too few items in list (%d)\n", last_kw); 188 } 189 190 void 191 reset_time_list(void) 192 { 193 int i; 194 switch (last_kw) { 195 case T_ABMON: 196 for (i = 0; i < 12; i++) { 197 free((char *)tm.mon[i]); 198 tm.mon[i] = NULL; 199 } 200 break; 201 case T_MON: 202 for (i = 0; i < 12; i++) { 203 free((char *)tm.month[i]); 204 tm.month[i] = NULL; 205 } 206 break; 207 case T_ABDAY: 208 for (i = 0; i < 7; i++) { 209 free((char *)tm.wday[i]); 210 tm.wday[i] = NULL; 211 } 212 break; 213 case T_DAY: 214 for (i = 0; i < 7; i++) { 215 free((char *)tm.weekday[i]); 216 tm.weekday[i] = NULL; 217 } 218 break; 219 case T_AM_PM: 220 free((char *)tm.am); 221 tm.am = NULL; 222 free((char *)tm.pm); 223 tm.pm = NULL; 224 break; 225 } 226 } 227 228 void 229 dump_time(void) 230 { 231 FILE *f; 232 int i; 233 234 if ((f = open_category()) == NULL) { 235 return; 236 } 237 238 for (i = 0; i < 12; i++) { 239 if (putl_category(tm.mon[i], f) == EOF) { 240 return; 241 } 242 } 243 for (i = 0; i < 12; i++) { 244 if (putl_category(tm.month[i], f) == EOF) { 245 return; 246 } 247 } 248 for (i = 0; i < 7; i++) { 249 if (putl_category(tm.wday[i], f) == EOF) { 250 return; 251 } 252 } 253 for (i = 0; i < 7; i++) { 254 if (putl_category(tm.weekday[i], f) == EOF) { 255 return; 256 } 257 } 258 259 /* 260 * NOTE: If date_fmt is not specified, then we'll default to 261 * using the %c for date. This is reasonable for most 262 * locales, although for reasons that I don't understand 263 * Solaris historically has had a separate format for date. 264 */ 265 if ((putl_category(tm.X_fmt, f) == EOF) || 266 (putl_category(tm.x_fmt, f) == EOF) || 267 (putl_category(tm.c_fmt, f) == EOF) || 268 (putl_category(tm.am, f) == EOF) || 269 (putl_category(tm.pm, f) == EOF) || 270 (putl_category(tm.date_fmt ? tm.date_fmt : tm.c_fmt, f) == EOF) || 271 (putl_category(tm.ampm_fmt, f) == EOF)) { 272 return; 273 } 274 close_category(f); 275 } 276