fileset.awk (6511B)
1 #!/bin/awk -f 2 BEGIN { 3 fname="\"$fname\"" # constants so I don't have to write it out 4 # dirname="\"$dirname\"" 5 or_die="|| exit $?" 6 7 if ("RSFILTER" in ENVIRON) { 8 # clean the filter file 9 printf "" >ENVIRON["RSFILTER"] 10 } 11 12 func_num=0 13 has_cond="" 14 } 15 16 function escaped(str) { 17 gsub(/\\/, "\\\\", str) 18 # gsub(/\n/, "\\n", str) 19 gsub(/([\\\t"`${}\[\]])/, "\\\\&", str) 20 return str 21 } 22 23 function quoted(str) { 24 if(str ~ "^[a-zA-Z0-9_./]+$") 25 return str 26 gsub(/'/, "'\\''", str) 27 return "'" str "'" 28 # return "\"" escaped(str) "\"" 29 } 30 31 function print_i(str) { # print with indent 32 print indent str 33 } 34 35 function print_d(str) { # print or die 36 print indent str " " or_die 37 } 38 39 function print_b(str) { # print begin block 40 print indent str 41 indent = indent "\t" 42 } 43 44 function print_m(str) { # print mid-block deindented 45 print substr(indent, 2) str 46 } 47 48 function print_e(str) { # print end block 49 indent = substr(indent, 2) 50 print indent str 51 } 52 53 function print_cond(statement, suffix) { # TODO 54 if(has_cond == "") { 55 print_b("if ! $check_only; then") 56 print_d("{ "statement"\n}"suffix) 57 print_e("fi") 58 } else { 59 if(suffix) { 60 funcs["do_" has_cond] = "{ "statement"\n}"suffix 61 } else { 62 funcs["do_" has_cond] = statement 63 } 64 print_d("req " has_cond) 65 has_cond = "" 66 } 67 } 68 69 function print_rsfilter(str) { 70 if ("RSFILTER" in ENVIRON) { 71 print str >>ENVIRON["RSFILTER"] 72 # } else { 73 # print str >>"/dev/stderr" 74 } 75 } 76 77 # take tab-delimited token from statement variable and return it 78 function get_till_tab( result) { 79 if(match(statement, /\t/)) { 80 result = substr(statement, 1, RSTART-1) 81 statement = substr(statement, RSTART+1) 82 } else { 83 result = statement 84 statement = "" 85 } 86 return result 87 } 88 89 function get_argument(whole_statement, result) { 90 if(whole_statement) { 91 result = statement 92 statement = "" 93 } else { 94 result = get_till_tab() 95 } 96 return result 97 } 98 99 function shellfunc(fun, flags) { 100 print_d("flags "quoted(flags)"; "fun) 101 } 102 103 function process_statement() { 104 while(statement) { 105 command = get_till_tab() 106 if(!command) continue 107 cchar = substr(command, 1, 1) 108 crest = substr(command, 2) 109 110 # check before the command is processed if we have dangling "?" 111 if(cchar != "!" && has_cond != "") { 112 printf "%s:%s: ? is not followed by ! (superfluous condition): %s\n", FILENAME, FNR, \ 113 cchar crest " '" statement "'" >"/dev/stderr" 114 if(!WARN_ONLY) { 115 exit 1 116 } 117 } 118 119 # set current fname all subsequent operations will be performed on 120 if(cchar == "/") { 121 curpath = crest 122 # fix up the path 123 if(match(crest, "/+$")) { 124 crest = substr(crest, 1, length(crest) - RLENGTH) 125 } 126 crest = "./" crest 127 128 print "" 129 print_i("fname=" quoted(crest)) 130 match(crest, /.*\//) 131 # print_i("dirname=" quoted(substr(crest, 1, RLENGTH-1))) 132 continue 133 } 134 135 if(cchar == "+") { 136 print_rsfilter("+ /" curpath crest) 137 continue 138 } 139 140 if(cchar == "-") { 141 print_rsfilter("- /" curpath crest) 142 continue 143 } 144 145 if(cchar == "o") { 146 print_i("o "crest) 147 continue 148 } 149 150 if(cchar == "m") { 151 print_i("m "crest) 152 continue 153 } 154 155 if(cchar == "u") { 156 print_i("umask "crest) 157 continue 158 } 159 160 # remove 161 if(cchar == "r") { 162 shellfunc("r", crest) 163 continue 164 } 165 166 # create file 167 if(cchar == "f") { 168 shellfunc("f", crest) 169 continue 170 } 171 172 # symbolic link 173 if(cchar ~ /[lL]/) { 174 shellfunc("l "quoted(get_argument(cchar == "L")), crest) 175 continue 176 } 177 178 # directory 179 if(cchar == "d") { 180 shellfunc("d", crest) 181 continue 182 } 183 184 # Cat, Copy, Content; eats rest of statement and puts it into the file 185 # Binary, Base64; decodes the arguments and changes file content 186 # heXdump; decodes the arguments and replaces file content 187 if(cchar ~ /[bBcCX]/) { 188 shellfunc("f 1", crest) 189 content = get_argument(cchar ~ /[BCX]/) 190 191 func_name = "fn" func_num++ 192 193 if(cchar ~ /[bB]/) { 194 funcs[func_name] = "\tbase64 -d <<<"quoted(content) 195 } else if(cchar ~ /[X]/) { 196 funcs[func_name] = "\txxd -r <<<"quoted(content) 197 } else { 198 # unless disabled with the N flag, append newline at the end of 199 # last line, if not already present 200 printf_fmt = ( \ 201 crest ~ /n/ || (crest !~ /N/ && content !~ /\n$/) \ 202 ) ? "%s\\n" : "%s" 203 if(printf_fmt == "%s" || length(content) < 1800) { 204 # TODO: split into several when needed 205 funcs[func_name] = "\tprintf '"printf_fmt"' "quoted(content) 206 } else { 207 funcs[func_name] = "\tcat <<<"quoted(content) 208 } 209 } 210 211 if(crest ~ /a/) { 212 print_cond(func_name, ">>"fname) 213 } else if(has_cond == "") { 214 print_i("c " func_name) 215 } else { 216 print_cond("c "func_name) 217 } 218 continue 219 } 220 221 # run shell command 222 if(cchar == "!") { 223 # use as Filter 224 if(crest ~ /f/) { 225 if(crest ~ /c/) { 226 shellfunc("f", crest) 227 } else { 228 shellfunc("req type_or_missing f", crest) 229 } 230 print_cond("\n" \ 231 "\t{ "statement"\n} <"fname" >"fname".tmp.$$ " or_die "\n" \ 232 "\tc cat "fname".tmp.$$\n" \ 233 "\trm "fname".tmp.$$ " or_die "\n") 234 # use file as Input 235 } else if(crest ~ /i/) { 236 print_cond(statement, "<"fname) 237 # use file as Output 238 } else if(crest ~ /o/) { 239 shellfunc("req type_or_missing f", crest) 240 print_cond(statement, ">"fname) 241 # Append to file 242 } else if(crest ~ /a/) { 243 shellfunc("req type_or_missing f", crest) 244 print_cond(statement, ">>"fname) 245 # do nothing special with file 246 } else { 247 print_cond(statement) 248 } 249 statement = "" 250 continue 251 } 252 253 # shell condition 254 if(cchar == "?") { 255 has_cond = func_num++ 256 if(crest ~ /i/) { 257 funcs["check_" has_cond] = ( \ 258 "{ "statement"\n} <"fname \ 259 ) 260 } else { 261 funcs["check_" has_cond] = statement 262 } 263 statement = "" 264 continue 265 } 266 267 # if none above matched 268 printf "%s:%s: unrecognised statement: %s\n", FILENAME, FNR, \ 269 cchar crest " '" statement "'" >"/dev/stderr" 270 if(!WARN_ONLY) { 271 exit 1 272 } 273 statement = "" 274 } 275 } 276 277 function parse_line(line) { 278 if(!line) { # empty line, ignore 279 return 280 } 281 if(line ~ /^#/) { # comment, ignore 282 return 283 } 284 if(line ~ /^\t/) { # continuation, append to statement 285 statement = statement "\n" substr(line, 2) 286 } else { # new statement 287 process_statement() 288 statement = line 289 } 290 } 291 292 function print_functions() { 293 for( func_name in funcs ) { 294 print func_name "(){\n" funcs[func_name] "\n}\n" 295 } 296 } 297 298 BEGIN { 299 print_b("check_main() {") 300 } 301 302 { parse_line($0) } 303 304 END { 305 process_statement() 306 print_e("}") 307 print_b("do_main() {") 308 print_i("true") 309 print_e("}") 310 print "" 311 print_functions() 312 print_i("req main") 313 }