1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2013 Garrett D'Amore <garrett@damore.org> 14 * Copyright 2017 Nexenta Systems, Inc. 15 */ 16 17 /* 18 * LC_TIME database generation routines for localedef. 19 */ 20 21 #include <stdio.h> 22 #include <stdlib.h> 23 #include <errno.h> 24 #include <sys/types.h> 25 #include <string.h> 26 #include <unistd.h> 27 #include "localedef.h" 28 #include "parser.tab.h" 29 #include "timelocal.h" 30 31 struct lc_time tm; 32 33 void 34 init_time(void) 35 { 36 (void) memset(&tm, 0, sizeof (tm)); 37 } 38 39 void 40 add_time_str(wchar_t *wcs) 41 { 42 char *str; 43 44 if ((str = to_mb_string(wcs)) == NULL) { 45 INTERR; 46 return; 47 } 48 free(wcs); 49 50 switch (last_kw) { 51 case T_D_T_FMT: 52 tm.c_fmt = str; 53 break; 54 case T_D_FMT: 55 tm.x_fmt = str; 56 break; 57 case T_T_FMT: 58 tm.X_fmt = str; 59 break; 60 case T_T_FMT_AMPM: 61 tm.ampm_fmt = str; 62 break; 63 case T_DATE_FMT: 64 /* 65 * This one is a Solaris extension. Too bad date just 66 * doesn't use %c, which would be simpler. 67 */ 68 tm.date_fmt = str; 69 break; 70 case T_ERA_D_FMT: 71 case T_ERA_T_FMT: 72 case T_ERA_D_T_FMT: 73 /* Silently ignore it. */ 74 free(str); 75 break; 76 default: 77 free(str); 78 INTERR; 79 break; 80 } 81 } 82 83 static void 84 add_list(const char *ptr[], char *str, int limit) 85 { 86 int i; 87 for (i = 0; i < limit; i++) { 88 if (ptr[i] == NULL) { 89 ptr[i] = str; 90 return; 91 } 92 } 93 errf(_("too many list elements")); 94 } 95 96 void 97 add_time_list(wchar_t *wcs) 98 { 99 char *str; 100 101 if ((str = to_mb_string(wcs)) == NULL) { 102 INTERR; 103 return; 104 } 105 free(wcs); 106 107 switch (last_kw) { 108 case T_ABMON: 109 add_list(tm.mon, str, 12); 110 break; 111 case T_MON: 112 add_list(tm.month, str, 12); 113 break; 114 case T_ABDAY: 115 add_list(tm.wday, str, 7); 116 break; 117 case T_DAY: 118 add_list(tm.weekday, str, 7); 119 break; 120 case T_AM_PM: 121 if (tm.am == NULL) { 122 tm.am = str; 123 } else if (tm.pm == NULL) { 124 tm.pm = str; 125 } else { 126 errf(_("too many list elements")); 127 free(str); 128 } 129 break; 130 case T_ALT_DIGITS: 131 case T_ERA: 132 free(str); 133 break; 134 default: 135 free(str); 136 INTERR; 137 break; 138 } 139 } 140 141 void 142 check_time_list(void) 143 { 144 switch (last_kw) { 145 case T_ABMON: 146 if (tm.mon[11] != NULL) 147 return; 148 break; 149 case T_MON: 150 if (tm.month[11] != NULL) 151 return; 152 break; 153 case T_ABDAY: 154 if (tm.wday[6] != NULL) 155 return; 156 break; 157 case T_DAY: 158 if (tm.weekday[6] != NULL) 159 return; 160 break; 161 case T_AM_PM: 162 if (tm.pm != NULL) 163 return; 164 break; 165 case T_ERA: 166 case T_ALT_DIGITS: 167 return; 168 default: 169 errf(_("unknown list")); 170 break; 171 } 172 173 errf(_("too few items in list (%d)"), last_kw); 174 } 175 176 void 177 reset_time_list(void) 178 { 179 int i; 180 switch (last_kw) { 181 case T_ABMON: 182 for (i = 0; i < 12; i++) { 183 free((char *)tm.mon[i]); 184 tm.mon[i] = NULL; 185 } 186 break; 187 case T_MON: 188 for (i = 0; i < 12; i++) { 189 free((char *)tm.month[i]); 190 tm.month[i] = NULL; 191 } 192 break; 193 case T_ABDAY: 194 for (i = 0; i < 7; i++) { 195 free((char *)tm.wday[i]); 196 tm.wday[i] = NULL; 197 } 198 break; 199 case T_DAY: 200 for (i = 0; i < 7; i++) { 201 free((char *)tm.weekday[i]); 202 tm.weekday[i] = NULL; 203 } 204 break; 205 case T_AM_PM: 206 free((char *)tm.am); 207 tm.am = NULL; 208 free((char *)tm.pm); 209 tm.pm = NULL; 210 break; 211 } 212 } 213 214 215 void 216 dump_time(void) 217 { 218 FILE *f; 219 int i; 220 221 if ((f = open_category()) == NULL) { 222 return; 223 } 224 225 for (i = 0; i < 12; i++) { 226 if (putl_category(tm.mon[i], f) == EOF) { 227 return; 228 } 229 } 230 for (i = 0; i < 12; i++) { 231 if (putl_category(tm.month[i], f) == EOF) { 232 return; 233 } 234 } 235 for (i = 0; i < 7; i++) { 236 if (putl_category(tm.wday[i], f) == EOF) { 237 return; 238 } 239 } 240 for (i = 0; i < 7; i++) { 241 if (putl_category(tm.weekday[i], f) == EOF) { 242 return; 243 } 244 } 245 246 /* 247 * NOTE: If date_fmt is not specified, then we'll default to 248 * using the %c for date. This is reasonable for most 249 * locales, although for reasons that I don't understand 250 * Solaris historically has had a separate format for date. 251 */ 252 if ((putl_category(tm.X_fmt, f) == EOF) || 253 (putl_category(tm.x_fmt, f) == EOF) || 254 (putl_category(tm.c_fmt, f) == EOF) || 255 (putl_category(tm.am, f) == EOF) || 256 (putl_category(tm.pm, f) == EOF) || 257 (putl_category(tm.date_fmt ? tm.date_fmt : tm.c_fmt, f) == EOF) || 258 (putl_category(tm.ampm_fmt, f) == EOF)) { 259 return; 260 } 261 close_category(f); 262 } 263