8987 bootadm: add bootfile fallback to unix
[unleashed.git] / usr / src / cmd / msgfmt / gnu_check.c
blob5fb624c1edae5c9637a75fb911715cbe32831ae7
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include "gnu_msgfmt.h"
31 #define OPT_L 0x01
32 #define OPT_l 0x02
33 #define OPT_ll 0x04
34 #define OPT_w 0x08
35 #define OPT_h 0x10
36 #define OPT_hh 0x20
37 #define OPT_j 0x40
39 static int
40 extract_format(char *norm, const char *sfmt, size_t sz)
42 const unsigned char *fmt = (const unsigned char *)sfmt;
43 unsigned char c;
44 int t, arg, ap;
45 int dotseen;
46 char flag, conv;
47 int lastarg = -1;
48 int prevarg;
49 int max = 0;
50 int lflag;
52 for (; *fmt; fmt++) {
53 if (*fmt == '%') {
54 if (*++fmt == '%')
55 continue;
56 if (!*fmt)
57 break;
58 prevarg = lastarg;
59 arg = ++lastarg;
61 t = 0;
62 while (*fmt && isdigit(*fmt))
63 t = t * 10 + *fmt++ - '0';
65 if (*fmt == '$') {
66 lastarg = arg = t - 1;
67 fmt++;
70 if (!*fmt)
71 goto end;
73 dotseen = 0;
74 flag = 0;
75 lflag = 0;
76 again:
77 /* Skip flags */
78 while ((c = *fmt) != '\0') {
79 if (c == '\'' || c == '+' || c == '-' ||
80 c == ' ' || c == '#' || c == '0') {
81 fmt++;
82 continue;
84 break;
87 while (*fmt && isdigit(*fmt))
88 fmt++;
90 if (*fmt == '*') {
91 if (isdigit(*(fmt + 1))) {
92 fmt++;
93 t = 0;
94 while (*fmt && isdigit(*fmt))
95 t = t * 10 + *fmt++ - '0';
97 if (*fmt == '$') {
99 * %*4$
101 ap = t - 1;
102 if ((ap * 2 + 1 >= sz) ||
103 (norm[ap * 2] &&
104 norm[ap * 2] != '*')) {
105 /* error in format */
106 return (-1);
107 } else {
108 if (ap >= max)
109 max = ap + 1;
110 norm[ap * 2] = '*';
114 * If digits follow a '*', it is
115 * not loaded as an argument, the
116 * digits are used instead.
118 } else {
120 * %*
122 if (*(fmt + 1) == '$') {
123 fmt++;
124 } else {
125 ap = arg;
126 prevarg = arg;
127 lastarg = ++arg;
128 if ((ap * 2 + 1 >= sz) ||
129 (norm[ap * 2] &&
130 norm[ap * 2] != '*')) {
131 /* error in format */
132 return (-1);
133 } else {
134 if (ap >= max)
135 max = ap + 1;
136 norm[ap * 2] = '*';
140 fmt++;
143 if ((*fmt == '.') || (*fmt == '*')) {
144 if (dotseen)
145 return (-1);
146 dotseen = 1;
147 fmt++;
148 goto again;
151 if (!*fmt)
152 goto end;
154 while (*fmt) {
155 switch (*fmt) {
156 case 'l':
157 if (!(flag & OPT_ll)) {
158 if (lflag) {
159 flag &= ~OPT_l;
160 flag |= OPT_ll;
161 } else {
162 flag |= OPT_l;
165 lflag++;
166 break;
167 case 'L':
168 flag |= OPT_L;
169 break;
170 case 'w':
171 flag |= OPT_w;
172 break;
173 case 'h':
174 if (flag & (OPT_h|OPT_hh))
175 flag |= OPT_hh;
176 else
177 flag |= OPT_h;
178 break;
179 case 'j':
180 flag |= OPT_j;
181 break;
182 case 'z':
183 case 't':
184 if (!(flag & OPT_ll)) {
185 flag |= OPT_l;
187 break;
188 case '\'':
189 case '+':
190 case '-':
191 case ' ':
192 case '#':
193 case '.':
194 case '*':
195 goto again;
196 default:
197 if (isdigit(*fmt))
198 goto again;
199 else
200 goto done;
202 fmt++;
204 done:
205 if (!*fmt)
206 goto end;
208 if ((c = *fmt) == 'C') {
209 flag |= OPT_l;
210 conv = 'c';
211 } else if (c == 'd') {
212 conv = 'd';
213 } else if (c == 'S') {
214 flag |= OPT_l;
215 conv = 's';
216 } else if (c == 's') {
217 conv = 's';
218 } else if (c == 'i') {
219 conv = 'i';
220 } else if (c == 'o') {
221 conv = 'o';
222 } else if (c == 'u') {
223 conv = 'u';
224 } else if (c == 'c') {
225 conv = 'c';
226 } else if (c == 'x') {
227 conv = 'x';
228 } else if (c == 'X') {
229 conv = 'X';
230 } else if (c == 'e') {
231 conv = 'e';
232 } else if (c == 'E') {
233 conv = 'E';
234 } else if (c == 'f') {
235 conv = 'f';
236 } else if (c == 'F') {
237 conv = 'F';
238 } else if (c == 'a') {
239 conv = 'a';
240 } else if (c == 'A') {
241 conv = 'A';
242 } else if (c == 'g') {
243 conv = 'g';
244 } else if (c == 'G') {
245 conv = 'G';
246 } else if (c == 'p') {
247 conv = 'p';
248 } else if (c == 'n') {
249 conv = 'n';
250 } else {
251 lastarg = prevarg;
252 continue;
255 if ((arg * 2 + 1 >= sz) ||
256 (norm[arg * 2] &&
257 (norm[arg * 2] != conv))) {
258 return (-1);
259 } else {
260 if (arg >= max)
261 max = arg + 1;
262 norm[arg * 2] = conv;
264 norm[arg * 2 + 1] = flag;
268 end:
269 for (arg = 0; arg < max; arg++) {
270 if (norm[arg * 2] == '\0')
271 return (-1);
274 return (max);
278 void
279 check_format(struct entry *id, struct entry *str, int is_c_format)
281 int i, n;
282 int id_b_newline, id_e_newline;
283 int plural_b_newline, plural_e_newline;
284 int str_b_newline, str_e_newline;
285 int id_fmt, plural_fmt, str_fmt;
286 int *pstr_fmt;
287 char *msgid, *plural, *msgstr;
288 char *id_norm, *plural_norm, *str_norm;
289 char **pstr_norm;
290 size_t id_len, id_num;
291 size_t plural_off, plural_len, plural_num;
292 size_t str_len, str_num;
293 size_t osz, nsz;
294 struct loc *p;
296 if (id->len == 1) {
298 * null string: header entry
299 * no check is performed
301 return;
304 msgid = id->str;
305 id_num = id->num;
306 msgstr = str->str;
307 if (id->no > 1) {
308 /* plural */
309 id_len = id->pos[0].len;
310 plural_off = id->pos[1].off;
311 plural_len = id->pos[1].len;
312 plural_num = id->pos[1].num;
313 plural = msgid + plural_off;
314 } else {
315 /* no plural form */
316 id_len = id->len;
317 str_len = str->len;
318 str_num = str->num;
319 plural = NULL;
323 * First checking the newline
326 if (!plural) {
327 /* no plural form */
328 id_b_newline = (msgid[0] == '\n');
329 id_e_newline = (msgid[id_len - 1 - 1] == '\n');
331 str_b_newline = (msgstr[0] == '\n');
332 str_e_newline = (msgstr[str_len - 1 - 1] == '\n');
333 if (id_b_newline && !str_b_newline) {
334 diag(gettext(ERR_BEGIN_NEWLINE_1),
335 id_num, str_num, cur_po);
336 po_error++;
337 } else if (!id_b_newline && str_b_newline) {
338 diag(gettext(ERR_BEGIN_NEWLINE_2),
339 id_num, str_num, cur_po);
340 po_error++;
342 if (id_e_newline && !str_e_newline) {
343 diag(gettext(ERR_END_NEWLINE_1),
344 id_num, str_num, cur_po);
345 po_error++;
346 } else if (!id_e_newline && str_e_newline) {
347 diag(gettext(ERR_END_NEWLINE_2),
348 id_num, str_num, cur_po);
349 po_error++;
351 } else {
352 /* plural form */
353 id_b_newline = (msgid[0] == '\n');
354 id_e_newline = (msgid[id_len - 1 - 1] == '\n');
356 plural_b_newline = (plural[0] == '\n');
357 plural_e_newline = (plural[plural_len - 1 -1 ] == '\n');
359 /* between msgid and msgid_plural */
360 if (id_b_newline && !plural_b_newline) {
361 diag(gettext(ERR_BEGIN_NEWLINE_3),
362 id_num, plural_num, cur_po);
363 po_error++;
364 } else if (!id_b_newline && plural_b_newline) {
365 diag(gettext(ERR_BEGIN_NEWLINE_4),
366 id_num, plural_num, cur_po);
367 po_error++;
369 if (id_e_newline && !plural_e_newline) {
370 diag(gettext(ERR_END_NEWLINE_3),
371 id_num, plural_num, cur_po);
372 po_error++;
373 } else if (!id_e_newline && plural_e_newline) {
374 diag(gettext(ERR_END_NEWLINE_4),
375 id_num, plural_num, cur_po);
376 po_error++;
379 for (i = 0; i < str->no; i++) {
380 p = str->pos + i;
381 str_b_newline = (msgstr[p->off] == '\n');
382 str_e_newline =
383 (msgstr[p->off + p->len - 1 - 1] == '\n');
385 if (id_b_newline && !str_b_newline) {
386 diag(gettext(ERR_BEGIN_NEWLINE_5),
387 id_num, p->num, cur_po, i);
388 po_error++;
389 } else if (!id_b_newline && str_b_newline) {
390 diag(gettext(ERR_BEGIN_NEWLINE_6),
391 id_num, p->num, cur_po, i);
392 po_error++;
395 if (id_e_newline && !str_e_newline) {
396 diag(gettext(ERR_END_NEWLINE_5),
397 id_num, p->num, cur_po, i);
398 po_error++;
399 } else if (!id_e_newline && str_e_newline) {
400 diag(gettext(ERR_END_NEWLINE_6),
401 id_num, p->num, cur_po, i);
402 po_error++;
408 * if c-format is not specified, no printf-format check
409 * is performed.
411 if (!is_c_format) {
412 return;
415 osz = id_len * 2;
416 id_norm = (char *)Xcalloc(1, osz);
417 id_fmt = extract_format(id_norm, msgid, osz);
418 if (id_fmt == -1) {
419 diag(gettext(ERR_INVALID_FMT), id_num, cur_po);
420 po_error++;
423 if (!plural) {
424 /* no plural */
426 nsz = str_len * 2;
427 str_norm = (char *)Xcalloc(1, nsz);
428 str_fmt = extract_format(str_norm, msgstr, nsz);
429 if (str_fmt == -1) {
430 diag(gettext(ERR_INVALID_FMT), str_num, cur_po);
431 po_error++;
434 if (id_fmt != str_fmt) {
435 diag(gettext(ERR_INCMP_FMT),
436 id_num, str_num, cur_po);
437 diag(gettext(ERR_INCMP_FMT_DIFF_1),
438 id_fmt, str_fmt);
439 po_error++;
440 } else {
441 for (n = 0; n < id_fmt; n++) {
442 if ((id_norm[n * 2] !=
443 str_norm[n * 2]) ||
444 (id_norm[n * 2 + 1] !=
445 str_norm[n * 2 + 1])) {
446 diag(gettext(ERR_INCMP_FMT),
447 id_num, str_num, cur_po);
448 diag(gettext(ERR_INCMP_FMT_DIFF_2),
449 n + 1);
450 po_error++;
454 free(str_norm);
455 free(id_norm);
457 return;
460 /* plural */
461 nsz = plural_len * 2;
462 plural_norm = (char *)Xcalloc(1, nsz);
463 plural_fmt = extract_format(plural_norm, plural, nsz);
464 if (plural_fmt == -1) {
465 diag(gettext(ERR_INVALID_FMT), plural_num, cur_po);
466 po_error++;
469 pstr_norm = (char **)Xcalloc(str->no, sizeof (char *));
470 pstr_fmt = (int *)Xcalloc(str->no, sizeof (int));
471 for (i = 0; i < str->no; i++) {
472 p = str->pos + i;
473 nsz = p->len * 2;
474 pstr_norm[i] = (char *)Xcalloc(1, nsz);
475 pstr_fmt[i] = extract_format(pstr_norm[i],
476 msgstr + p->off, nsz);
477 if (pstr_fmt[i] == -1) {
478 diag(gettext(ERR_INVALID_FMT),
479 p->num, cur_po);
480 po_error++;
484 /* between msgid and msgid_plural */
485 if (id_fmt != plural_fmt) {
486 diag(gettext(ERR_INCMP_FMT),
487 id_num, plural_num, cur_po);
488 diag(gettext(ERR_INCMP_FMT_DIFF_1),
489 id_fmt, plural_fmt);
490 po_error++;
491 } else {
492 for (n = 0; n < id_fmt; n++) {
493 if ((id_norm[n * 2] !=
494 plural_norm[n * 2]) ||
495 (id_norm[n * 2 + 1] !=
496 plural_norm[n * 2 + 1])) {
497 diag(gettext(ERR_INCMP_FMT),
498 id_num, plural_num, cur_po);
499 diag(gettext(ERR_INCMP_FMT_DIFF_2),
500 n + 1);
501 po_error++;
505 free(plural_norm);
507 /* between msgid and msgstr */
508 for (i = 0; i < str->no; i++) {
509 p = str->pos + i;
510 if (id_fmt != pstr_fmt[i]) {
511 diag(gettext(ERR_INCMP_FMT),
512 id_num, p->num, cur_po);
513 diag(gettext(ERR_INCMP_FMT_DIFF_1),
514 id_fmt, pstr_fmt[i]);
515 po_error++;
516 } else {
517 for (n = 0; n < id_fmt; n++) {
518 if ((id_norm[n * 2] !=
519 pstr_norm[i][n * 2]) ||
520 (id_norm[n * 2 + 1] !=
521 pstr_norm[i][n * 2 + 1])) {
522 diag(gettext(ERR_INCMP_FMT),
523 id_num, p->num, cur_po);
524 diag(gettext(ERR_INCMP_FMT_DIFF_2),
525 n + 1);
526 po_error++;
530 free(pstr_norm[i]);
532 free(pstr_norm);
533 free(pstr_fmt);
534 free(id_norm);