1 %pointer
2 %s LABEL ECHOING QUOTED COMMENT
3 
4 %{
5 
6 /*
7  * $Id: bat-filt.l,v 1.37 2016/12/11 16:04:15 tom Exp $
8  *
9  * Filter to add vile "attribution" sequences to selected bits of DOS (and
10  * similar, such as W95, NT) batch file.
11  */
12 
13 #include <filters.h>
14 
15 DefineFilter(bat);
16 
17 static char *Action_attr;
18 static char *Comment_attr;
19 static char *Error_attr;
20 static char *Ident2_attr;
21 static char *String_attr;
22 
23 static int setting;
24 
25 static const char *variable_attr(char *text);
26 static void write_label(char *text, int length);
27 
28 %}
29 
30 TEXT		[^\r\n]
31 BLANK		[ \t\r]
32 
33 IDENT		[[:alpha:]_.][[:alnum:]_.]*
34 
35 PARAM		%[[:digit:]*]
36 VARIABLE	%%{IDENT}|%{IDENT}%
37 IDENT2		({PARAM}|{VARIABLE})
38 
39 %%
40 
41 <INITIAL>^{BLANK}*@		{ WriteToken(Action_attr); }
42 <INITIAL>\032			{ WriteToken(Action_attr); }
43 
44 <ECHOING>[^\r\n]*		{ WriteToken(String_attr); BEGIN(INITIAL); }
45 <ECHOING>\n			{ ECHO; BEGIN(INITIAL); }
46 
47 <INITIAL>=			{ ECHO; setting=0; }
48 <INITIAL>\"			{ BEGIN(QUOTED);
49 				  flt_bfr_begin(String_attr);
50 				  flt_bfr_append(yytext, yyleng);
51 				}
52 
53 <INITIAL>^{BLANK}*:		{ WriteToken(Action_attr); BEGIN(LABEL); }
54 <LABEL>{BLANK}+			{ ECHO; }
55 <LABEL>{IDENT}			{ write_label(yytext, yyleng); BEGIN(INITIAL); }
56 <LABEL>[\r\n]			{ ECHO; BEGIN(INITIAL); }
57 <LABEL>.			{ WriteToken("U"); BEGIN(INITIAL); }
58 
59 <INITIAL>{IDENT}		{ const char *temp = lowercase_of(yytext);
60 				  char *type = strrchr(temp, '.');
61 				  const char *attr;
62 				  int echoing = 0;
63 
64 				  /* "echo." is a legal "echo", and the "."
65 				   * is not echoed.  So we highlight it as
66 				   * part of the name.
67 				   */
68 				  if (type != 0)
69 				      *type = '\0';
70 				  attr = get_keyword_attr(temp);
71 				  if (!strcmp(temp, "echo")) {
72 					BEGIN(ECHOING);
73 					echoing = 1;
74 				  } else if (!strcmp(temp, "goto")) {
75 					BEGIN(LABEL);
76 				  } else if (attr != 0 && Comment_attr == attr) {
77 					BEGIN(COMMENT);
78 				  } else if (!strcmp(temp, "set")) {
79 					setting = 1;
80 				  }
81 				  if (type != 0 && echoing) {
82 				      int len = (int) (type - temp) + 1;
83 
84 				      flt_puts(yytext, len, attr);
85 				      flt_puts(yytext + len, yyleng - len, String_attr);
86 				  } else {
87 				      flt_puts(yytext, yyleng, attr);
88 				  }
89 				}
90 
91 <INITIAL>({IDENT2})		{ WriteToken(Ident2_attr); }
92 
93 <COMMENT>{TEXT}*		{ WriteToken(Comment_attr); }
94 <COMMENT>\n			{ ECHO; BEGIN(INITIAL); }
95 
96 <INITIAL>\n			{ ECHO; setting = 0; }
97 
98 <QUOTED>{IDENT2}		{ flt_bfr_embed(yytext, yyleng, variable_attr(yytext)); }
99 <QUOTED>(\\\"|[^\r\n\"])+	{ flt_bfr_append(yytext, yyleng); }
100 <QUOTED>(.|\n)			{ flt_bfr_append(yytext, yyleng);
101 				  flt_bfr_finish();
102 				  BEGIN(INITIAL);
103 				}
104 %%
105 
106 static const char *
107 variable_attr(char *text)
108 {
109     const char *attr = get_keyword_attr(text);
110     int isvar = (setting || *text == '%');
111 
112     if (isEmpty(attr) && isvar) {
113 	attr = Ident2_attr;
114 	insert_keyword(text, attr, 0);
115     } else if (isvar) {
116 	attr = Ident2_attr;
117     }
118     return attr;
119 }
120 
121 #define MAX_LABEL 8		/* labels are unique to only 8 chars */
122 
123 static void
124 write_label(char *text, int length)
125 {
126     char *next = skip_blanks(skip_blanks(text));
127     size_t len = strlen(next);
128     int limit = ((len <= MAX_LABEL)
129 		 ? length
130 		 : (MAX_LABEL + (int) (next - text)));
131 
132     flt_puts(text, limit, Ident2_attr);
133     if (len > MAX_LABEL) {
134 	flt_error("label too long");
135 	flt_puts(next + MAX_LABEL, (int) strlen(next + MAX_LABEL), Error_attr);
136     }
137 }
138 
139 static void
140 init_filter(int before GCC_UNUSED)
141 {
142     (void) before;
143 }
144 
145 static void
146 do_filter(FILE *inputs)
147 {
148     InitLEX(inputs);
149 
150     setting = 0;
151     Action_attr = class_attr(NAME_ACTION);
152     Comment_attr = class_attr(NAME_COMMENT);
153     Error_attr = class_attr(NAME_ERROR);
154     Ident2_attr = class_attr(NAME_IDENT2);
155     String_attr = class_attr(NAME_LITERAL);
156 
157     BEGIN(INITIAL);
158     RunLEX();
159     flt_bfr_error();
160 }
161 
162 #if NO_LEAKS
163 static void
164 free_filter(void)
165 {
166     USE_LEXFREE;
167 }
168 #endif
169