xref: /illumos-gate/usr/src/cmd/genmsg/genmsg.l (revision 03831d35)
1 %{
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License, Version 1.0 only
7  * (the "License").  You may not use this file except in compliance
8  * with the License.
9  *
10  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11  * or http://www.opensolaris.org/os/licensing.
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  *
23  * Copyright (c) 1995 by Sun Microsystems, Inc.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <limits.h>
31 #include <string.h>
32 #include <libintl.h>
33 #include <locale.h>
34 #include "genmsg.h"
35 #include "y.tab.h"
36 
37 extern int is_cat_found;	/* from main.c */
38 extern void add_comment(Mode, char *);/* from util.c */
39 
40 int lineno = 1;
41 
42 /*
43  * msg_line stores the line number where a msgid is to be replaced.
44  */
45 int msg_line = 0;
46 
47 int end_of_cat = TRUE;
48 
49 /*
50  * In preprocessor mode, genmsg has to parse both the original
51  * soruce code and the code which a preprocessor generates.
52  * While genmsg is parsing the original source code,  'pound_is_mine'
53  * is set to TRUE.
54  */
55 int pound_is_mine = FALSE;
56 
57 void warning(char *);
58 
59 #define NOLINEMSG	-2
60 
61 void set_linemsgid(int, int);
62 int get_linemsgid(int);
63 
64 /*
65  * cat_field indicates which token is currently parsed by lex.
66  */
67 #define	CatdField	0
68 #define	SetidField	1
69 #define	MsgidField	2
70 #define StrField	3
71 
72 static int cat_field;
73 
74 /*
75  * This will be turned on when '-' is found in the catgets message
76  * number field.
77  */
78 static int save_minus = FALSE;
79 
80 static char *skip_quoted(int skip_ch);
81 static char *skip_comment(void);
82 static void parse_cppline(char *);
83 %}
84 %s CAT
85 %%
86 
87 [0-9a-zA-Z\_\.]catgets	{
88 			if (IsActiveMode(ReplaceMode)) {
89 				fprintf(newfp, "%s", yytext);
90 			}
91 		}
92 
93 catgets[0-9a-zA-Z\_\.]	{
94 			if (IsActiveMode(ReplaceMode)) {
95 				fprintf(newfp, "%s", yytext);
96 			}
97 		}
98 
99 catgets		{
100 			if (end_of_cat) { /* If the previous catgets
101 					   * state is on, turn it off
102 					   * first.
103 					   */
104 				BEGIN 0;
105 			}
106 			if (IsActiveMode(ReplaceMode)) {
107 				fprintf(newfp, "%s", yytext);
108 			}
109 			if (IsActiveMode(ReplaceMode) &&
110 				IsActiveMode(PreProcessMode)) {
111 				; /* Okay, do nothing in this mode. */
112 			} else {
113 				BEGIN CAT;
114 				end_of_cat = FALSE;
115 				cat_field = CatdField;
116 				return CATGETS;
117 			}
118 		}
119 
120 <CAT>\,		{	/* punctuation */
121 			cat_field++;
122 			if (IsActiveMode(ReplaceMode)) {
123 				fprintf(newfp, "%c", yytext[0]);
124 			}
125 			if (end_of_cat) {
126 				BEGIN 0;
127 			} else {
128 				return yytext[0];
129 			}
130 		}
131 
132 <CAT>[+*/();>]	{	/* punctuation */
133 			if (IsActiveMode(ReplaceMode)) {
134 				fprintf(newfp, "%c", yytext[0]);
135 			}
136 			if (end_of_cat) {
137 				BEGIN 0;
138 			} else {
139 				return yytext[0];
140 			}
141 		}
142 
143 <CAT>const	{
144 			if (IsActiveMode(ReplaceMode)) {
145 				fprintf(newfp, "%s", yytext);
146 			}
147 			if (end_of_cat) {
148 				BEGIN 0;
149 			} else {
150 				return CONST;
151 			}
152 		}
153 
154 <CAT>nl_catd	{
155 			if (IsActiveMode(ReplaceMode)) {
156 				fprintf(newfp, "%s", yytext);
157 			}
158 			if (end_of_cat) {
159 				BEGIN 0;
160 			} else {
161 				return CATD;
162 			}
163 		}
164 
165 <CAT>char	{
166 			if (IsActiveMode(ReplaceMode)) {
167 				fprintf(newfp, "%s", yytext);
168 			}
169 			if (end_of_cat) {
170 				BEGIN 0;
171 			} else {
172 				return CHAR;
173 			}
174 		}
175 
176 <CAT>int	{
177 			if (IsActiveMode(ReplaceMode)) {
178 				fprintf(newfp, "%s", yytext);
179 			}
180 			if (end_of_cat) {
181 				BEGIN 0;
182 			} else {
183 				return INT;
184 			}
185 		}
186 
187 <CAT>\+\+	{
188 			if (IsActiveMode(ReplaceMode)) {
189 				fprintf(newfp, "%s", yytext);
190 			}
191 			if (end_of_cat) {
192 				BEGIN 0;
193 			} else {
194 				return INC;
195 			}
196 		}
197 
198 <CAT>\-\-	{
199 			if (IsActiveMode(ReplaceMode)) {
200 				fprintf(newfp, "%s", yytext);
201 			}
202 			if (end_of_cat) {
203 				BEGIN 0;
204 			} else {
205 				return INC;
206 			}
207 		}
208 
209 <CAT>\"		{	/* extract quoted string */
210 			yylval.str = skip_quoted('"');
211 			if (IsActiveMode(ReplaceMode)) {
212 				fprintf(newfp, "\"%s\"", yylval.str);
213 			}
214 			if (end_of_cat) { /* just in case */
215 				BEGIN 0;
216 				free(yylval.str);
217 			} else {
218 				return QSTR;
219 			}
220 		}
221 
222 <CAT>-		{	/* punctuation */
223 			if (IsActiveMode(ReplaceMode)) {
224 				if (cat_field == MsgidField &&
225 					get_linemsgid(lineno) != NOLINEMSG) {
226 					save_minus = TRUE; /*  be replaced. */
227 				} else {
228 					fprintf(newfp, "%c", yytext[0]);
229 				}
230                         }
231 			if (end_of_cat) { /* just in case */
232 				BEGIN 0;
233 			} else {
234 				return yytext[0];
235 			}
236 		}
237 
238 <CAT>[0-9]+	{	/* numbers */
239 			switch (cat_field) {
240 			case SetidField:
241 				yylval.id = atoi(yytext);
242 				if (IsActiveMode(ReplaceMode)) {
243 					fprintf(newfp, "%s", yytext);
244 				}
245 				if (end_of_cat) {
246 					BEGIN 0;
247 				} else {
248 					return SETID;
249 				}
250 			case MsgidField:
251 				yylval.id = atoi(yytext);
252 				if (IsActiveMode(ReplaceMode)) {
253 					int id = get_linemsgid(lineno);
254 					if (id == NOLINEMSG) {
255 						fprintf(newfp, "%s", yytext);
256 					} else if (id == NOMSGID &&
257 						IsActiveMode(ReverseMode)) {
258 						fprintf(newfp, "%d", NOMSGID);
259 					} else if (save_minus == TRUE &&
260 						yylval.id == 1) {
261 						fprintf(newfp, "%d",id);
262 					} else { /* just in case */
263 						fprintf(newfp, "%s", yytext);
264 					}
265 					save_minus = FALSE;
266 				} else {
267 					msg_line = lineno;
268 				}
269 				if (end_of_cat) {
270 					BEGIN 0;
271 				} else {
272 					return MSGID;
273 				}
274 			default:
275 				yylval.id = atoi(yytext);
276 				if (IsActiveMode(ReplaceMode)) {
277 					fprintf(newfp, "%s", yytext);
278 				}
279 				if (end_of_cat) {
280 					BEGIN 0;
281 				} else {
282 					return DIGIT;
283 				}
284 			}
285 		}
286 
287 <CAT>[a-zA-Z0-9_\&][a-zA-Z0-9_\>\&\.]*	{
288 			if (IsActiveMode(ReplaceMode)) {
289 				fprintf(newfp, "%s", yytext);
290 			}
291 			if (end_of_cat) {
292 				BEGIN 0;
293 			} else {
294 				return STR;
295 			}
296 		}
297 
298 <CAT>\n		{
299 			lineno++;
300 			if (IsActiveMode(ReplaceMode)) {
301 				fprintf(newfp, "\n");
302 			}
303 			if (end_of_cat) {
304 				BEGIN 0;
305 			}
306 		}
307 
308 <CAT>.		{	/* not interested */
309 			if (IsActiveMode(ReplaceMode)) {
310 				fprintf(newfp, "%c", yytext[0]);
311 			}
312 			if (end_of_cat) {
313 				BEGIN 0;
314 			}
315 		}
316 
317 -((([ \t]+)1)|1) {	/* -1 */
318 			if (end_of_cat == FALSE) {
319 				REJECT;
320 			} else if (IsActiveMode(ReplaceMode)) {
321 				if (IsActiveMode(PreProcessMode)) {
322 					int id = get_linemsgid(lineno);
323 					if (id == NOLINEMSG) {
324 						fprintf(newfp, "%s", yytext);
325 					} else { /* could be -1. */
326 						fprintf(newfp, "%d", id);
327 					}
328 				} else {
329 					fprintf(newfp, "%s", yytext);
330 				}
331 			}
332 		}
333 
334 [0-9]+		{
335 			if (IsActiveMode(ReplaceMode)) {
336 				if (IsActiveMode(PreProcessMode) &&
337 					IsActiveMode(ReverseMode)) {
338 					int id = get_linemsgid(lineno);
339 					if (id == NOLINEMSG) {
340 						fprintf(newfp, "%s", yytext);
341 					} else if (id == NOMSGID) {
342 						fprintf(newfp, "%d", id);
343 					}
344 				} else {
345 					fprintf(newfp, "%s", yytext);
346 				}
347 			}
348 		}
349 
350 ^#[ \t]*[0-9]+.*\n	{	/* pound for c-preprocessor */
351 			if (IsActiveMode(PreProcessMode)) {
352 				if (IsActiveMode(ReplaceMode)) {
353 					fprintf(newfp, "%s", yytext);
354 				} else {
355 					parse_cppline(yytext);
356 				}
357 			} else if (IsActiveMode(ReplaceMode)) {
358 				fprintf(newfp, "%s", yytext);
359 			}
360 			lineno++;
361 		}
362 
363 "/*"		{	/* skip a comment block */
364 			char *comment = skip_comment();
365 			if (IsActiveMode(ReplaceMode)) {
366 				fprintf(newfp, "%s", comment);
367 			} else {
368 				if (IsActiveMode(MsgCommentMode)) {
369 					add_comment(MsgCommentMode, comment);
370 				}
371 				if (IsActiveMode(SetCommentMode)) {
372 					add_comment(SetCommentMode, comment);
373 				}
374 			}
375 			free(comment);
376 		}
377 
378 "//".*\n	{	/* skip a c++ comment */
379 			if (IsActiveMode(ReplaceMode)) {
380 				fprintf(newfp, "%s", yytext);
381 			} else {
382 				if (IsActiveMode(MsgCommentMode)) {
383 					add_comment(MsgCommentMode, yytext);
384 				}
385 				if (IsActiveMode(SetCommentMode)) {
386 					add_comment(SetCommentMode, yytext);
387 				}
388 			}
389 			lineno++;
390 		}
391 
392 \"		{	/* skip quoted string */
393 			char *qstr = skip_quoted('"');
394 			if (IsActiveMode(ReplaceMode)) {
395 				fprintf(newfp, "\"%s\"", qstr);
396 			}
397 			free(qstr);
398 		}
399 
400 \'		{	/* skip single-quoted character */
401 			char *qchr = skip_quoted('\'');
402 			if (IsActiveMode(ReplaceMode)) {
403 				fprintf(newfp, "\'%s\'", qchr);
404 			}
405 			free(qchr);
406 		}
407 
408 \n		{
409 			if (IsActiveMode(ReplaceMode)) {
410 				fprintf(newfp, "\n");
411 			}
412 			lineno++;
413 		}
414 
415 .		{
416 			if (IsActiveMode(ReplaceMode)) {
417 				fprintf(newfp, "%c", yytext[0]);
418 			}
419 		}
420 
421 %%
422 
423 static char *
424 skip_quoted(int skip_ch)
425 {
426 	char *buf, *ptr;	/* saved buffer and its pointer */
427 	int bsize = BUFSIZ;	/* growing buffer size */
428 	int i = 0;		/* counter */
429 	int c, old = 0;		/* input character */
430 
431 	if ((buf = ptr = (char *) malloc(bsize)) == NULL) {
432 		prg_err(gettext("fatal: out of memory"));
433 		exit(EXIT_FAILURE);
434 	}
435 	for (;; i++) {
436 		if (i == bsize) {
437 			bsize += BUFSIZ;
438 			if ((buf = (char *) realloc((void *) buf,
439 				bsize)) == NULL) {
440 				prg_err(gettext("fatal: out of memory"));
441 				exit(EXIT_FAILURE);
442 			}
443 			ptr = buf + i;
444 		}
445 		c = input();
446 		if (c == skip_ch && old != '\\') {
447 			break;
448 		} else if (c == '\n') {
449 			lineno++;
450 		} else if (c == 0) {
451 			if (skip_ch == '"') {
452 				warning(gettext("warning: unmatched \""));
453 			} else if (skip_ch == '\'') {
454 				warning(gettext("warning: unmatched '"));
455 			} else {
456 				/* Should not happen */
457 				warning(gettext("warning: unmatched \
458 character"));
459 			}
460 			break;
461 		}
462 		*ptr++ = c;
463 		if (old == '\\') {
464 			old = '\0';
465 		} else {
466 			old = c;
467 		}
468 	}
469 	*ptr = '\0';
470 	return buf;
471 }
472 
473 static char *
474 skip_comment(void)
475 {
476 	char *buf, *ptr;	/* saved buffer and its pointer */
477 	int bsize = BUFSIZ;	/* growing buffer size */
478 	int i = 0;		/* counter */
479 	int c, old = 0;		/* input character */
480 
481 	if ((buf = ptr = (char *) malloc(bsize)) == NULL) {
482 		prg_err(gettext("fatal: out of memory"));
483 		exit(EXIT_FAILURE);
484 	}
485 	*ptr++ = '/';	i++;
486 	*ptr++ = '*';	i++;
487 	for (;; i++) {
488 		if (i == bsize) {
489 			bsize += BUFSIZ;
490 			if ((buf = (char *) realloc((void *) buf,
491 				bsize)) == NULL) {
492 				prg_err(gettext("fatal: out of memory"));
493 				exit(EXIT_FAILURE);
494 			}
495 			ptr = buf + i;
496 		}
497 		c = input();
498 		if (c == '/' && old == '*') {
499 			*ptr++ = c;
500 			break;
501 		} else if (c == '\n') {
502 			lineno++;
503 		} else if (c == 0) {
504 			warning(gettext("warning: unmatched /*"));
505 			break;
506 		}
507 		*ptr++ = old = c;
508 	}
509 	*ptr = '\0';
510 	return buf;
511 }
512 
513 /*
514  * parse_cppline() parses the line control information that a C
515  * preprocessor generates to indicate the location in the original
516  * file.  See the cpp man in the details.
517  */
518 static void
519 parse_cppline(char *str)
520 {
521 	int n, line, len;
522 	char ch;
523 	char file[LINE_MAX];
524 	char *pfile = &file[0];
525 
526 	n = sscanf(str, "%c%d%s", &ch, &line, file);
527 
528 	/* 'file' is a quoted string but 'srcfile' is not. */
529 	len = strlen(file) - 2;
530 	pfile++;
531 	if (n == 3 && (strncmp(pfile, srcfile, len) == 0)) {
532 		pound_is_mine = TRUE;
533 		lineno = line - 1;
534 	} else if (n == 2 && (pound_is_mine == TRUE)) {
535 		lineno = line - 1;
536 	} else {
537 		pound_is_mine = FALSE;
538 	}
539 }
540 
541 typedef struct {
542 	int line;
543 	int msgid;
544 } LineMsgID;
545 
546 static LineMsgID line_msgid[NL_MSGMAX];
547 static int line_msgcnt;
548 
549 void
550 init_lex(void)
551 {
552 	lineno = 1;
553 	end_of_cat = TRUE;
554 	pound_is_mine = FALSE;
555 }
556 
557 void
558 init_linemsgid(void)
559 {
560 	line_msgcnt = 0;
561 	memset(line_msgid, 0, sizeof(LineMsgID) * NL_MSGMAX);
562 }
563 
564 void
565 set_linemsgid(int line, int msgid)
566 {
567 	if (line_msgcnt >= NL_MSGMAX) {
568 		return; /* oops */
569 	}
570 	line_msgid[line_msgcnt].line = line;
571 	line_msgid[line_msgcnt].msgid = msgid;
572 	line_msgcnt++;
573 }
574 
575 int
576 get_linemsgid(int line)
577 {
578 	register int i, left, right;
579 	left = 0;
580 	right = line_msgcnt - 1;
581 	while (left <= right) {
582 		i = (left + right) >> 1;
583 		if ( line < line_msgid[i].line) {
584 			right = i - 1;
585 		} else if (line > line_msgid[i].line) {
586 			left = i + 1;
587 		} else {
588 			return line_msgid[i].msgid;
589 		}
590 	}
591 	return NOLINEMSG;
592 }
593 
594 void
595 yyerror(char *s)
596 {
597 	if ((IsActiveMode(PreProcessMode) && pound_is_mine == FALSE) ||
598 		IsActiveMode(ReplaceMode)) {
599 		return;
600 	}
601 	src_err(srcfile, lineno, gettext("%s before or at: %s"), s, yytext);
602 }
603 
604 void
605 warning(char *s)
606 {
607 	if ((IsActiveMode(PreProcessMode) && pound_is_mine == FALSE) ||
608 		IsActiveMode(ReplaceMode)) {
609 		return;
610 	}
611 	src_err(srcfile, lineno, "%s", s);
612 }
613