parse_spec.awk 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. # AWK file for parsing uci specification files
  2. #
  3. # Copyright (C) 2006 by Fokus Fraunhofer <[email protected]>
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. # General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. #
  19. #
  20. # general: unfortunately, the development was done using gawk providing
  21. # a different match() functions than e.g. mawk on debian systems
  22. # - therefore, the script was changed to run on most awk's
  23. # - even things like [:space:] are not used
  24. #
  25. # - script parses the config section definition contained in one
  26. # specification file
  27. # global variables:
  28. # * section - contains the current config section name
  29. # * var - contains the name of the current config option
  30. # * type - contains the type of the current config option
  31. # * required - contains the requirements of the current config option
  32. # * optional - contains the optional scope of the current config option
  33. # * vars[] - array, contains the name of all config options valid within
  34. # a certain config section, format: csv
  35. #
  36. # XXX todo: more than one config option with the same in different section
  37. # will clash for the following tables
  38. # * types[] - contains the type of a config option
  39. # * reqs[] - contains the requirements of a config option
  40. # * opts[] - contains the optional scope of a config option
  41. #
  42. BEGIN {
  43. section_count=1
  44. section = ""
  45. simple_types = "int|ip|netmask|string|wep|hostname|mac|port|ports|wpapsk"
  46. }
  47. # function print_specification
  48. # - prints all information about the created tables containing the
  49. # specification
  50. function print_specification() {
  51. for (section in vars) {
  52. printf("%s\n",section);
  53. split(vars[section],arr,",")
  54. for (idx in arr) {
  55. printf("\t%s[%s]",arr[idx],types[section "_" arr[idx]]);
  56. if (length(reqs[section "_" arr[idx]])) {
  57. if (reqs[section "_" arr[idx]]==1) {
  58. printf(",req");
  59. }else{
  60. printf(", req(%s)", reqs[section "_" arr[idx]]);
  61. }
  62. }
  63. if (length(opts[section "_" arr[idx]])) {
  64. printf(", opt(%s)", opts[section "_" arr[idx]]);
  65. }
  66. printf("\n");
  67. }
  68. }
  69. }
  70. function reset_option() {
  71. # just set global variables parsed on one line back to defaults
  72. var = ""
  73. type = ""
  74. required = ""
  75. optional = ""
  76. found = 0
  77. }
  78. function store_option() {
  79. # save all information about a config option parsed from the spec file
  80. # to the relevant tables for future use
  81. # first check minimum requirements for storing information
  82. if (!length(section)) {
  83. print STDERR "line " NR ": section definition missing"
  84. exit 1
  85. }
  86. if (!length(var)) {
  87. print STDERR "line " NR ": invalid config option name"
  88. exit 1
  89. }
  90. if (!length(type)) {
  91. print STDERR "line " NR ": invalid config option type"
  92. exit 1
  93. }
  94. # add config options to the names of options available for this
  95. # section
  96. if (exists[section]!=1) {
  97. section_names[section_count] = section
  98. section_count++
  99. exists[section] = 1
  100. vars[section] = var
  101. } else {
  102. vars[section] = vars[section] "," var
  103. }
  104. # save the type, the requirements and the optional scope of the
  105. # config option
  106. types[section "_" var] = type
  107. reqs[section "_" var] = required
  108. opts[section "_" var] = optional
  109. }
  110. /^declare -x|^export/ {
  111. sub(/^declare -x /,"")
  112. sub(/^export /,"")
  113. split($0,arr,"=")
  114. val=substr(arr[2],2,length(arr[2])-2)
  115. ENVIRON[arr[1]] = val
  116. next
  117. }
  118. # main parsing function
  119. # this is done in one function block to allow multiple semicolon separated
  120. # definitions on one line
  121. {
  122. # replace leading/trailing white space
  123. gsub("^[ \t\n]+","");
  124. gsub("[ \t\n]+$","");
  125. # comments are removed
  126. # XXX todo: check for quoted comments??
  127. if (match($0,/[^#]*/)) {
  128. rest=substr($0,RSTART,RLENGTH)
  129. } else {
  130. rest=$0
  131. }
  132. # match the config section "<section> {"
  133. if (match(rest,/^[^ \t\n{]+[ \t\n]*\{/)) {
  134. match(rest,/^[^ \t\n{]+/)
  135. section = substr(rest,RSTART,RLENGTH)
  136. rest=substr($0,RSTART+RLENGTH);
  137. match(rest,/[ \t\n]*\{/)
  138. rest=substr(rest,RSTART+RLENGTH)
  139. # check for array indication
  140. if (match(section,/\[[ \t\n]*\]/)) {
  141. section=substr(section,1,RSTART-1)
  142. multiple[section] = 1
  143. } else {
  144. multiple[section] = 0
  145. }
  146. }
  147. reset_option()
  148. # parse the remaing line as long as there is something to parse
  149. while (rest ~ "[^ \t\n}]+") {
  150. found = 0
  151. # get option name and option type
  152. # first, check for "simple" datatype definitions
  153. if (match(rest,"[^: \t\n]+[ \t\n]*:[ \t\n]*(" \
  154. simple_types ")")){
  155. match(rest,"[^: \t\n]+")
  156. var=substr(rest,RSTART,RLENGTH)
  157. rest=substr(rest,RSTART+RLENGTH)
  158. match(rest,"[ \t\n]*:[ \t\n]*")
  159. rest=substr(rest,RSTART+RLENGTH)
  160. match(rest,"(" simple_types ")")
  161. type=substr(rest,RSTART,RLENGTH)
  162. rest = substr(rest,RSTART+RLENGTH)
  163. found = 1
  164. # next, check for enum definitions
  165. } else if (match(rest,/[^: \t\n]+[ \t\n]*:[ \t\n]*enum\([^\)]+\)/ )) {
  166. match(rest,"[^: \t\n]+")
  167. var=substr(rest,RSTART,RLENGTH)
  168. rest=substr(rest,RSTART+RLENGTH)
  169. match(rest,/[ \t\n]*:[ \t\n]*enum\(/)
  170. rest=substr(rest,RSTART+RLENGTH)
  171. match(rest,/[^\)]+/)
  172. type="enum," substr(rest,RSTART,RLENGTH)
  173. rest = substr(rest,RSTART+RLENGTH+1)
  174. found=1
  175. }
  176. # after the name and the type,
  177. # get the option requirements/scope
  178. if (match(rest,/[^,]*,[ \t\n]*required\[[^]]+\]/)) {
  179. match(rest,"[^,]*")
  180. save=substr(rest,RSTART,RLENGTH)
  181. rest=substr(rest,RSTART+RLENGTH)
  182. match(rest,/,[ \t\n]*required\[/);
  183. rest=substr(rest,RSTART+RLENGTH)
  184. match(rest,/[^]]+\]/)
  185. required=substr(rest,RSTART,RLENGTH-1)
  186. save=save substr(rest,RSTART+RLENGTH)
  187. rest=save
  188. found=1
  189. } else if (match(rest,/[^,]*,[ \t\n]*required/)) {
  190. match(rest,"[^,]*")
  191. save=substr(rest,RSTART,RLENGTH)
  192. rest=substr(rest,RSTART+RLENGTH)
  193. match(rest,",[ \t\n]*required");
  194. rest=substr(rest,RSTART+RLENGTH)
  195. required=1
  196. save=save substr(rest,RSTART+RLENGTH)
  197. rest=save
  198. found=1
  199. }
  200. if (match(rest,/[^,]*,[ \t\n]*optional\[[^]]+\]/)) {
  201. match(rest,"[^,]*")
  202. save=substr(rest,RSTART,RLENGTH)
  203. rest=substr(rest,RSTART+RLENGTH)
  204. match(rest,/,[ \t\n]*optional\[/);
  205. rest=substr(rest,RSTART+RLENGTH)
  206. match(rest,/[^]]+\]/)
  207. optional=substr(rest,RSTART,RLENGTH-1)
  208. save=save substr(rest,RSTART+RLENGTH)
  209. rest=save
  210. found=1
  211. }
  212. # if the remaining line contains a semicolon, complete the
  213. # specification of the config options
  214. if (match(rest, "^[ \t\n]*;(.*)")) {
  215. match(rest,"^[ \t\n]*;")
  216. rest=substr(rest,RSTART+RLENGTH)
  217. if (found==1) {
  218. store_option()
  219. }
  220. reset_option()
  221. # if nothing matched on this line, clear the rest
  222. } else if (!found) {
  223. rest = ""
  224. }
  225. }
  226. # after the line is pared, store the configuration option in the
  227. # table if any has been defined
  228. if (length(var)) {
  229. store_option()
  230. reset_option()
  231. }
  232. # close the section if the line contained a closing section bracket,
  233. # XXX todo: check if this has to be done more intelligent
  234. if ($0 ~ /\}/) {
  235. section=""
  236. }
  237. }