xref: /titanic_44/usr/src/cmd/genmsg/genmsg.l (revision e1c679fa4b0ab8c4bcaa6263974ca0c46e5b027f)
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