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