fileset

git mirror of https://ccx.te2000.cz/bzr/fileset
git clone https://ccx.te2000.cz/git/fileset
Log | Files | Refs | README

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 }