xref: /illumos-gate/usr/src/cmd/localedef/time.c (revision 2d08521b)
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 2010 Nexenta Systems, Inc.  All rights reserved.
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 		break;
75 	default:
76 		free(str);
77 		INTERR;
78 		break;
79 	}
80 }
81 
82 static void
83 add_list(const char *ptr[], char *str, int limit)
84 {
85 	int	i;
86 	for (i = 0; i < limit; i++) {
87 		if (ptr[i] == NULL) {
88 			ptr[i] = str;
89 			return;
90 		}
91 	}
92 	errf(_("too many list elements"));
93 }
94 
95 void
96 add_time_list(wchar_t *wcs)
97 {
98 	char *str;
99 
100 	if ((str = to_mb_string(wcs)) == NULL) {
101 		INTERR;
102 		return;
103 	}
104 	free(wcs);
105 
106 	switch (last_kw) {
107 	case T_ABMON:
108 		add_list(tm.mon, str, 12);
109 		break;
110 	case T_MON:
111 		add_list(tm.month, str, 12);
112 		break;
113 	case T_ABDAY:
114 		add_list(tm.wday, str, 7);
115 		break;
116 	case T_DAY:
117 		add_list(tm.weekday, str, 7);
118 		break;
119 	case T_AM_PM:
120 		if (tm.am == NULL) {
121 			tm.am = str;
122 		} else if (tm.pm == NULL) {
123 			tm.pm = str;
124 		} else {
125 			errf(_("too many list elements"));
126 		}
127 		break;
128 	case T_ALT_DIGITS:
129 	case T_ERA:
130 		free(str);
131 		break;
132 	default:
133 		free(str);
134 		INTERR;
135 		break;
136 	}
137 }
138 
139 void
140 check_time_list(void)
141 {
142 	switch (last_kw) {
143 	case T_ABMON:
144 		if (tm.mon[11] != NULL)
145 			return;
146 		break;
147 	case T_MON:
148 		if (tm.month[11] != NULL)
149 			return;
150 		break;
151 	case T_ABDAY:
152 		if (tm.wday[6] != NULL)
153 			return;
154 		break;
155 	case T_DAY:
156 		if (tm.weekday[6] != NULL)
157 			return;
158 		break;
159 	case T_AM_PM:
160 		if (tm.pm != NULL)
161 			return;
162 		break;
163 	case T_ERA:
164 	case T_ALT_DIGITS:
165 		return;
166 	default:
167 		errf(_("unknown list"));
168 		break;
169 	}
170 
171 	errf(_("too few items in list (%d)"), last_kw);
172 }
173 
174 void
175 reset_time_list(void)
176 {
177 	int i;
178 	switch (last_kw) {
179 	case T_ABMON:
180 		for (i = 0; i < 12; i++) {
181 			free((char *)tm.mon[i]);
182 			tm.mon[i] = NULL;
183 		}
184 		break;
185 	case T_MON:
186 		for (i = 0; i < 12; i++) {
187 			free((char *)tm.month[i]);
188 			tm.month[i] = NULL;
189 		}
190 		break;
191 	case T_ABDAY:
192 		for (i = 0; i < 7; i++) {
193 			free((char *)tm.wday[i]);
194 			tm.wday[i] = NULL;
195 		}
196 		break;
197 	case T_DAY:
198 		for (i = 0; i < 7; i++) {
199 			free((char *)tm.weekday[i]);
200 			tm.weekday[i] = NULL;
201 		}
202 		break;
203 	case T_AM_PM:
204 		free((char *)tm.am);
205 		tm.am = NULL;
206 		free((char *)tm.pm);
207 		tm.pm = NULL;
208 		break;
209 	}
210 }
211 
212 
213 void
214 dump_time(void)
215 {
216 	FILE *f;
217 	int i;
218 
219 	if ((f = open_category()) == NULL) {
220 		return;
221 	}
222 
223 	for (i = 0; i < 12; i++) {
224 		if (putl_category(tm.mon[i], f) == EOF) {
225 			return;
226 		}
227 	}
228 	for (i = 0; i < 12; i++) {
229 		if (putl_category(tm.month[i], f) == EOF) {
230 			return;
231 		}
232 	}
233 	for (i = 0; i < 7; i++) {
234 		if (putl_category(tm.wday[i], f) == EOF) {
235 			return;
236 		}
237 	}
238 	for (i = 0; i < 7; i++) {
239 		if (putl_category(tm.weekday[i], f) == EOF) {
240 			return;
241 		}
242 	}
243 
244 	/*
245 	 * NOTE: If date_fmt is not specified, then we'll default to
246 	 * using the %c for date.  This is reasonable for most
247 	 * locales, although for reasons that I don't understand
248 	 * Solaris historically has had a seperate format for date.
249 	 */
250 	if ((putl_category(tm.X_fmt, f) == EOF) ||
251 	    (putl_category(tm.x_fmt, f) == EOF) ||
252 	    (putl_category(tm.c_fmt, f) == EOF) ||
253 	    (putl_category(tm.am, f) == EOF) ||
254 	    (putl_category(tm.pm, f) == EOF) ||
255 	    (putl_category(tm.date_fmt ? tm.date_fmt : tm.c_fmt, f) == EOF) ||
256 	    (putl_category(tm.ampm_fmt, f) == EOF)) {
257 		return;
258 	}
259 	close_category(f);
260 }
261