data.awk (3820B)
1 #!/bin/awk -f 2 BEGIN { 3 FS="\t" 4 SUBSEP="." 5 state = 0 6 # 0 read normal variables 7 # 1 seen start of field list, read titles 8 # 2 reading list values 9 # ident_re = /[a-zA-Z_][a-zA-Z0-9_]*/ 10 ident_re = "[a-zA-Z_][a-zA-Z0-9_]*" 11 } 12 13 $0 == "]" && state == 2 { 14 # end of field list 15 state = 0 16 next 17 } 18 19 state == 2 { 20 V[varname,++V[varname,"rows"]] = $0 21 next 22 } 23 24 state == 1 { 25 if((varname, "fields") in V) { 26 if(V[varname,"fields"] != $0) { 27 print "data.awk: differing field definition for '"varname"'" >"/dev/stderr" 28 print "previous: '"V[varname,"fields"]"'" >"/dev/stderr" 29 print "current: '"$0"'" >"/dev/stderr" 30 exit 1 31 } 32 } 33 V[varname,"fields"] = $0 34 state = 2 35 next 36 } 37 38 /^del[ \t].*[a-zA-Z_][a-zA-Z0-9_.]$/ { 39 del_pattern = substr($0, 5) 40 for(varname in V) { 41 if (match(varname, del_pattern)) { 42 delete V[varname] 43 } 44 } 45 } 46 47 /^[a-zA-Z_][a-zA-Z0-9_.]*=\[$/ { 48 # start of field list 49 state = 1 50 m = match($0, ident_re) 51 varname = substr($0, m, RLENGTH) 52 next 53 } 54 55 /^[a-zA-Z_][a-zA-Z0-9_.]*=/ { 56 m = match($0, ident_re) 57 varname = substr($0, m, RLENGTH) 58 V[varname] = substr($0, m+1+RLENGTH) 59 if(DEBUG) printf "got scalar: %s = %s (%d)\n", varname, V[varname], m >"/dev/stderr" 60 next 61 } 62 63 /^\t/ { 64 V[varname] = V[varname] "\n" substr($0, 1) 65 next 66 } 67 68 /^#/ { next } 69 /^$/ { next } 70 71 { 72 # TODO posix compliance 73 print "data.awk: unparseable line: '"$0"'" >"/dev/stderr" 74 exit 1 75 } 76 77 function data_not_found_error(varname, type) { 78 if(ENVIRON["DATA_AWK_EMPTY_GET"]) { 79 if(DEBUG) { 80 print type" not found: " varname >"/dev/stderr" 81 } 82 } else { 83 print "error: undefined "type" '"varname"'" >"/dev/stderr" 84 exit 1 85 } 86 } 87 88 function loop_start(varname, prefix, depth) { 89 if(!((varname, "fields") in V)) { 90 data_not_found_error(varname, "table") 91 } 92 depth = ++loop_stack["depth"] 93 loop_stack[depth,"row"] = 0 94 loop_stack[depth,"var"] = varname 95 loop_stack[depth,"pre"] = prefix 96 return depth 97 } 98 99 function loop_iter(depth) { 100 loop_stack[depth,"row"]++ 101 return (loop_stack[depth,"var"], loop_stack[depth,"row"]) in V 102 } 103 104 function loop_end() { 105 delete loop_stack[loop_stack["depth"], "row"] 106 delete loop_stack[loop_stack["depth"], "var"] 107 delete loop_stack[loop_stack["depth"], "pre"] 108 loop_stack["depth"]-- 109 } 110 111 function find(varname, i, n, names, values, loopvar, looprow, prefix) { 112 for(i=loop_stack["depth"]; i>0; i--) { 113 prefix = loop_stack[i, "pre"] 114 if(prefix) 115 if(substr(varname, 1, length(prefix)) != prefix) 116 continue 117 loopvar = loop_stack[i, "var"] 118 looprow = loop_stack[i, "row"] 119 if(varname == prefix"_index") { 120 found = looprow 121 return 1 122 } 123 if(varname == prefix"_index0") { 124 found = looprow - 1 125 return 1 126 } 127 if(varname == prefix"_revindex") { 128 found = V[loopvar, "rows"] - looprow + 1 129 return 1 130 } 131 if(varname == prefix"_revindex0") { 132 found = V[loopvar, "rows"] - looprow 133 return 1 134 } 135 if(varname == prefix"_first") { 136 found = looprow == 1 137 return 1 138 } 139 if(varname == prefix"_last") { 140 found = looprow == V[loopvar, "rows"] 141 return 1 142 } 143 if(varname == prefix"_length") { 144 found = V[loopvar, "rows"] 145 return 1 146 } 147 split(V[loopvar, "fields"], names) 148 for(n in names) { 149 if(varname == (prefix names[n])) { 150 split(V[loopvar, looprow], values) 151 found = values[n] 152 return 1 153 } 154 } 155 } 156 if(!(varname in V)) { 157 return 0 158 } 159 found = V[varname] 160 return 1 161 } 162 163 function get(varname) { 164 if(!find(varname)) { 165 data_not_found_error(varname, "scalar") 166 found = "" 167 } 168 if(DEBUG) { 169 print "get →" varname "← = →"found"←" >"/dev/stderr" 170 } 171 return found 172 } 173 174 function or_(a, b) { 175 return a ? a : b 176 } 177 178 END { 179 if(DEBUG) { 180 print "--- loaded keys ---" >"/dev/stderr" 181 for(key in V) { 182 printf("%s\t→%s←\n", key, V[key]) >"/dev/stderr" 183 printf(">> %d →%s←\n", find(key), found) >"/dev/stderr" 184 } 185 print "-------------------" >"/dev/stderr" 186 } 187 }