From: Mark Wooding Date: Thu, 1 Jan 2009 17:21:59 +0000 (+0000) Subject: maint-utils/keysubst: A monstrously unpleasant sed hack. X-Git-Tag: 1.0.0pre8~30 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/commitdiff_plain/44e2927917faa9ab4ad4f3e4931d746192a241b0 maint-utils/keysubst: A monstrously unpleasant sed hack. This parses tripe-admin(5)-format key/value pairs and converts them into sh(1)-style variable assignments, which can be interpreted using the eval builtin. --- diff --git a/maint-utils/keysubst b/maint-utils/keysubst new file mode 100644 index 00000000..6d7b5f1e --- /dev/null +++ b/maint-utils/keysubst @@ -0,0 +1,84 @@ +#! /bin/sh + +## This sed(1) script takes key/value pairs in tripe-admin(5) format as +## input; it writes sh(1) variable assignments as output. The idea is that +## you can say +## +## eval $(tripectl algs | sed "$keysubst") +## +## and have shell variables set from the output of the command. The shell +## variable names are worked out from the key names, with sequences of +## nonalphanumerics replaced by single underscores. Quoting is handled +## correctly, both on input and output. +## +## Theory of operation: firstly, ! and @ characters in the input are replaced +## by !e and !a respectively; this is a reversible transformation, which we +## undo at the end. We now know that the input does not contain @. We use a +## string of the form [lr][nqQ]@ as a cursor to move across the input from +## left to right. The letters on the left of the @ are state markers: l +## means left of =, r means right; n means not in quotes; q means single- +## quoted; Q means double-quoted. +## +## This is a particularly awful hack. I'm so sorry. +keysubst=' + ## Initial transformation. + s/!/!e/g'$p' + s/@/!a/g'$p' + + ## Initial state: left-hand side, not quoted + s/^/ln@/'$p' + +:loop + ## Reached the end: exit. + /@$/ b end + + ## Enter or leave quoted state as necessary. + s/\(.\)n@'\''/\1q@/'$p' + s/\(.\)n@"/\1Q@/'$p' + s/\(.\)q@'\''/\1n@/'$p' + s/\(.\)Q@"/\1n@/'$p' + t loop + + ## Leave backslashed things alone. + /\(..\)@\\/ { + s//\1@/ + b lit + } + + ## Unquotes spaces delimit key/value pairs. + s/\(rn\)@[ ]\+/'\'' ln@/'$p' + + ## An = sign separates left and right sides. + s/l\(.\)@=/='\''r\1@/'$p' + + ## Single quotes on the right-hand side need special care. + t loop + s/r\(.\)@'\'/\''\\'\'\''r\1@/'$p' + + ## Sequences of alphanumerics are always easy. + s/\(..\)@\([[:alnum:]]\+\)/\2\1@/'$p' + +:lit + ## Convert bad left-hand-side characters to underscores. + t loop + s/l\(.\)@\(!.\|[^=![:alnum:]]\)\+/_l\1@/'$p' + + ## Convert sequences of nonproblematic right-hand-side characters. + t loop + s/\(r.\)@\([^ '\''"`]\+\)/\2\1@/'$p' + + ## And anything else is probably OK. + s/\(..\)@\(.\)/\2\1@/'$p' + b loop + +:end + ## Unquote the end appropriately. + s/r.@/'\''/'$p' + s/..@//'$p' + + ## And undo the initial transformation. + s/!a/@/g'$p' + s/!e/!/g'$p' +' + +sed "$keysubst"