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