PageRenderTime 28ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

/src/com/mobileread/ixtab/kindlelauncher/resources/parse.awk

https://bitbucket.org/ixtab/kindlelauncher
AWK | 1264 lines | 1262 code | 0 blank | 2 comment | 0 complexity | 5632bb4f77489c99c4f59d76660baf8a MD5 | raw file
  1. #!/usr/bin/awk -f
  2. # aloop-v2.awk - version 20130523,a stepk
  3. BEGIN {
  4. VERSION="20130523,a"
  5. ERRORS = BAILOUT = CACHE_SENT = IN_MEMORY_CACHE_INVALID = PARSED_OK_COUNTER = 0
  6. SELF_BUTTONS_INSERT = SELF_BUTTONS_FILTER = SELF_BUTTONS_APPEND = ""
  7. if (1 < ARGC) {
  8. print "usage!" > "/dev/stderr"
  9. BAILOUT=1
  10. exit
  11. }
  12. while (0 < getline < "/dev/stdin") {
  13. if (NF) { ARGV[++ARGC]=$0 } else break
  14. }
  15. srand()
  16. RS="n/o/m/a/t/c/h" substr(rand(),3)
  17. init()
  18. if (0 == cache_send(CACHEPATH)) {
  19. close("/dev/stdout")
  20. CACHE_SENT=1
  21. } else {
  22. config_send("/dev/stdout")
  23. }
  24. if (1 >= ARGC) {
  25. ARGC = find_menu_fullpathnames(EXTENSIONDIR, ARGV, ARGC-1)
  26. if (1 > ARGC && "" != SCRIPTPATH) {
  27. ARGV[ARGC] = ""
  28. ++ERRORS
  29. ++IN_MEMORY_CACHE_INVALID
  30. SELF_BUTTONS_INSERT = SELF_BUTTONS_INSERT ",+add_ext"
  31. SELF_BUTTONS_FILTER = SELF_BUTTONS_FILTER ",-sort_menu"
  32. }
  33. if("" != ARGV[ARGC]) ++ARGC
  34. }
  35. BRIEF=1;
  36. STREAM=0;
  37. delete FAILS
  38. }
  39. {
  40. reset()
  41. SVNJPATHS = 0+NJPATHS
  42. tokenize($0)
  43. if (0 == (status = parse())) {
  44. ++VALID_PARSED_FILES
  45. status = jp2np(JPATHS, NJPATHS, VALID_PARSED_FILES, FILENAME)
  46. match(FILENAME, /(\/[^\/]+){2,2}$/)
  47. x = substr(FILENAME, RSTART+1, RLENGTH)
  48. LOADED_EXTENSIONS[substr(x, 1, index(x, "/") - 1)] = 1
  49. } else {
  50. while(NJPATHS > SVNJPATHS) {
  51. delete JPATHS[NJPATHS--]
  52. }
  53. }
  54. if (status) ++ERRORS
  55. }
  56. END {
  57. if (BAILOUT) {
  58. teardown()
  59. exit(BAILOUT)
  60. }
  61. if (CACHE_SENT) {
  62. if (0 != cache_update()) {
  63. scream(SenCantUpdateCache)
  64. ++ERRORS
  65. }
  66. teardown()
  67. exit(ERRORS)
  68. }
  69. json_emit_self_menu_and_parsing_errors(0+PARENT_ERRORS)
  70. delete MENUS; NMENUS=0
  71. if (0 != np2mn(NPATHS, NNPATHS)) {
  72. scream("error (np2mn)")
  73. ++ERRORS
  74. } else {
  75. if (0 != formatter(MENUS, NMENUS, OPT_FMT, "/dev/stdout")) {
  76. scream(SenCantSendToKindlet)
  77. ++ERRORS
  78. }
  79. close("/dev/stdout")
  80. if (0 != cache_save()) {
  81. scream(SenCantWriteCache)
  82. ++ERRORS
  83. }
  84. }
  85. teardown()
  86. exit(ERRORS)
  87. }
  88. function init( x) {
  89. if ("" == EXTENSIONDIR) EXTENSIONDIR="/mnt/us/extensions"
  90. if ("" == PRODUCTNAME) PRODUCTNAME="KUAL"
  91. if ("" == CONFIGFILE) CONFIGFILE=PRODUCTNAME".cfg"
  92. if ("" == (CONFIGPATH = config_full_path())) CONFIGPATH = "/dev/null"
  93. config_read(CONFIGPATH)
  94. CONFIG["model"] = get_model()
  95. x = "/bin/busybox "
  96. CONFIG["NCbbawk"] = x"awk"
  97. CONFIG["NCbbfind"] = x"find"
  98. CONFIG["NCbbmd5sum"] = x"md5sum"
  99. CONFIG["NCbbsort"] = x"sort"
  100. if (""==OPT_FMT) OPT_FMT="multiline"
  101. if (""==OPT_SORT) OPT_SORT= "" != (x = config_get("sort_mode")) ? x : "ABC"
  102. delete COUNTER
  103. COUNTER["nameNull"]=0
  104. SEP="\x01"
  105. CACHEPATH = (x = "/var/tmp/" PRODUCTNAME) ".cache"
  106. if (""==SCREAM_LOG) SCREAM_LOG = x ".log"
  107. SCRIPTPATH = x ".sh"
  108. MBXPATH = x ".mbx"
  109. system("rm -f '"MBXPATH"'")
  110. SELF_MENU_NAME = PRODUCTNAME
  111. VALID_KEYS["action"]=K_action=0x00
  112. VALID_KEYS["internal"]=K_internal=0x01
  113. VALID_KEYS["params"]=K_params=0x02
  114. VALID_KEYS["priority"]=K_priority=0x03
  115. VALID_KEYS["if"]=K_if=0x04
  116. VALID_KEYS["exitmenu"]=K_exitmenu=0x05
  117. VALID_KEYS["checked"]=K_checked=0x06
  118. VALID_KEYS["refresh"]=K_refresh=0x07
  119. VALID_KEYS["status"]=K_status=0x08
  120. VALID_KEYS["date"]=K_date=0x09
  121. VALID_KEYS["hidden"]=K_hidden=0x0a
  122. VALID_KEYS["name"]=K_name=0x0b
  123. VALID_KEYS["items"]=K_items=0xff
  124. VALID_KEYS["ERROR"]="??"
  125. sK_name=sprintf("%02x", K_name)
  126. sK_items=sprintf("%02x", K_items)
  127. xRESERVED=0xff
  128. sRESERVED="ff"
  129. sRESERVED_len=2
  130. NPATH_len=48
  131. FFS="ffffffffffffffffffffffffffffffffffffffffffffffff"
  132. NBSP0="&nbsp;"
  133. NBSP1="\xC2\xA0"
  134. CROSS="\xC3\x97"
  135. ATTN="\xE2\x97\x8F"
  136. MAX_LABEL_LEN=40
  137. XenErrSyntax="Syntax"
  138. XenParentErrors="Startup error"
  139. XenNoExtensionsFound=ATTN" No extensions found"
  140. SenCantChangeSortMode="can't change sorting mode"
  141. SenCantFindMenuFiles="can't find menu files"
  142. SenCantHashCache="can't hash cache file"
  143. SenCantSendToKindlet="can't send menu to Kindlet"
  144. SenCantSort="can't sort"
  145. SenCantUpdateCache="can't update cached menu"
  146. SenCantWriteCache="can't cache menu"
  147. TFL="/var/tmp/--" PRODUCTNAME "--"
  148. INTERNAL_ACTIONS["breadcrumb"]="A"
  149. INTERNAL_ACTIONS["status"]="B"
  150. }
  151. function teardown( i) {
  152. system("cd /var/tmp && rm -f \"" TFL "\"* 2>/dev/null")
  153. }
  154. function cache_file_delete() {
  155. system("rm -f '"CACHEPATH"'")
  156. }
  157. function cache_save( errors,hash1,hash2,cmd) { # {{{ << globals IN_MEMORY_CACHE_INVALID,CACHEPATH,MENUS[],NMENUS,CONFIG[]; return
  158. errors = 0
  159. if (IN_MEMORY_CACHE_INVALID) {
  160. cache_file_delete()
  161. return 0
  162. }
  163. cmd = CONFIG["NCbbmd5sum"]" '"CACHEPATH"' 2>/dev/null"
  164. if (-1 < getline hash1 < CACHEPATH) {
  165. close(CACHEPATH)
  166. cmd | getline hash1
  167. if (close(cmd)) {
  168. scream(SenCantHashCache)
  169. hash1 = 0
  170. }
  171. }
  172. printf "" >CACHEPATH
  173. errors += config_send(CACHEPATH)
  174. errors += formatter(MENUS, NMENUS, "multiline", CACHEPATH)
  175. if (-1 == close(CACHEPATH)) {
  176. ++errors
  177. } else {
  178. cmd | getline hash2
  179. if (close(cmd)) {
  180. scream(SenCantHashCache)
  181. hash2 = 0
  182. }
  183. }
  184. if (hash1 && hash2 && hash1 != hash2) {
  185. if (! errors) {
  186. print "1 "CACHEPATH >MBXPATH
  187. close(MBXPATH)
  188. }
  189. }
  190. return errors
  191. }
  192. function cache_send(cachepath, # {{{ << globals MENUS[],NMENUS,CONFIG[]; >>global IN_MEMORY_CACHE_INVALID; return
  193. slurp,version) {
  194. if (0 <= (getline slurp < cachepath))
  195. close(cachepath)
  196. if ("" != slurp) {
  197. version = substr(slurp, index(slurp, "\n") + 1)
  198. version = substr(version, 1, index(version, "\n") - 1)
  199. if (version != VERSION) {
  200. cache_file_delete()
  201. return 1
  202. }
  203. printf "%s", slurp
  204. return 0
  205. }
  206. return 1
  207. }
  208. function cache_update( errors) { # {{{ >> globals NPATHS[],NNPATHS,IN_MEMORY_CACHE_INVALID,MENUS[],NMENUS,CONFIG[]; cache_save(); return
  209. errors = 0
  210. json_emit_self_menu_and_parsing_errors(0+PARENT_ERRORS)
  211. delete MENUS; NMENUS=0
  212. if (0 != np2mn(NPATHS, NNPATHS)) {
  213. scream("error (np2mn)")
  214. ++errors
  215. } else {
  216. IN_MEMORY_CACHE_INVALID = 0
  217. if (0 != cache_save()) {
  218. scream(SenCantWriteCache)
  219. ++errors
  220. }
  221. }
  222. return errors
  223. }
  224. function config_full_path(create,
  225. i,ary,nary,x) {
  226. nary = split(EXTENSIONDIR, ary, /;/)
  227. for (i = 1; i <= nary; i++) {
  228. cfp = ary[i]"/"CONFIGFILE
  229. if (0 <= (getline x < cfp)) {
  230. close(cfp)
  231. break
  232. }
  233. }
  234. if ("" != x)
  235. return cfp
  236. if ("create" == create) {
  237. cfp=ary[1]"/"CONFIGFILE
  238. "date" | getline x
  239. close("date")
  240. print "# "CONFIGFILE" - created on "x > cfp
  241. close(cfp)
  242. return cfp
  243. }
  244. return ""
  245. }
  246. function config_get(key) {
  247. return key in CONFIG ? CONFIG[key] : ""
  248. }
  249. function config_read(configfullpath,
  250. ary,nary,slurp,k,v,p,count) {
  251. if (0 <= (getline slurp < configfullpath))
  252. close(configfullpath)
  253. if ("" != slurp) {
  254. nary = split(slurp, ary, /\n/)
  255. if (nary) --nary
  256. for (i = 1; i <= nary; i++) {
  257. if (ary[i] ~ "^\\s*"PRODUCTNAME"_\\w+=") {
  258. k = ary[i]
  259. gsub(/^\s+|\s+$/, "", k)
  260. k = substr(k,1+index(k,"_"))
  261. p = index(k, "=")
  262. v = substr(k,p+1)
  263. if (match(v, /^".*"$/))
  264. v = substr(v, 2, RLENGTH - 2)
  265. CONFIG[substr(k,1,p-1)] = v
  266. ++count
  267. }
  268. }
  269. }
  270. return 0+count
  271. }
  272. function config_send(outfile, k,n) {
  273. for (k in CONFIG)
  274. if(k !~ /^NC/)
  275. ++n
  276. printf "%d\n%s\n%s\n%d\n", 2, VERSION, MBXPATH, n >>outfile
  277. for (k in CONFIG)
  278. if(k !~ /^NC/)
  279. print k"="CONFIG[k] >>outfile
  280. }
  281. function collate(ary, nary,
  282. maxdepth,depth,i,saved_self_menu_name,
  283. rec_lvlsnpath,rec_level,rec_snpath,rec_name,rec_type,
  284. key,seen,seenary,new_root,
  285. childrenary,nchildrenary,
  286. x,xary,nxary,y,z,trace) {
  287. maxdepth = menu2Dsplit(0, ary, nary)
  288. saved_self_menu_name = ary[1"nm"]
  289. ary[1"nm"] = SELF_MENU_NAME
  290. menu2Dimplode(1, ary, nary)
  291. nchildrenary = children_map(ary, nary, 0, childrenary)
  292. for (depth = 0; depth <= maxdepth; depth++) {
  293. for (i = 1; i <= nary; i++) if (i"ls" in ary) {
  294. rec_level = ary[i"lv"]
  295. if (depth != rec_level)
  296. continue
  297. rec_lvlsnpath = x = ary[i"ls"]
  298. rec_snpath = ary[i"sn"]
  299. rec_type = ary[i"ty"]
  300. if (1 == rec_type) {
  301. rec_name = ary[i"nm"]
  302. key = rec_level "_" rec_name
  303. if (! (key in seenary)) {
  304. seenary[key] = i
  305. continue
  306. }
  307. new_root = 0
  308. nxary = split(seenary[key], xary, " ")
  309. for (z = 1; z <= nxary; z++) {
  310. seen = xary[z]
  311. seen_lvlsnpath = ary[seen"ls"]
  312. seen_level = ary[seen"lv"]
  313. seen_snpath = ary[seen"sn"]
  314. if ((x = substr(substr(rec_snpath, 1, length(rec_snpath)-6), 5)) \
  315. != (y = substr(substr(seen_snpath, 1, length(seen_snpath)-6), 5))) {
  316. seenary[key] = seenary[key]" "i
  317. } else {
  318. new_root = seen
  319. }
  320. }
  321. if (0 == new_root) {
  322. continue
  323. }
  324. move_node(i, new_root, "", ary, nary, childrenary , key ~ trace)
  325. childrenary[new_root] = childrenary[new_root] " " childrenary[i]
  326. x = ary[new_root"nm"]
  327. y = substr(x, length(x))
  328. if ("+" != y) {
  329. ary[new_root"nm"] = x "+"
  330. menu2Dimplode(seen, ary, nary)
  331. }
  332. ary[i] = ary[i"sn"] = childrenary[i] = 0
  333. }
  334. }
  335. }
  336. x = ary[1"nm"]
  337. y = substr(x, length(x))
  338. ary[1"nm"] = (saved_self_menu_name) ("+" == y ? "+" : "")
  339. menu2Dimplode(1, ary, nary)
  340. }
  341. function move_node(src_i, dst_i, dst_path, ary, nary, childrenary, trace,
  342. offset,sst,dst_snpath, ncary,cary,child, c,x,y,to,len, dbgind) {
  343. offset = calc_snpath_offset(childrenary[dst_i], ary)
  344. sst = npath_s_this_(K_items, ary[dst_i"sn"])
  345. ncary = split(childrenary[src_i], cary, " ")
  346. for (c = 1; c <= ncary; c++) {
  347. child = cary[c]
  348. dst_snpath = dst_path ? dst_path : ary[dst_i"sn"]
  349. x = substr(dst_snpath, 1, length(dst_snpath) - 2)
  350. to = x sK_items sprintf("%02x", offset + c)
  351. len = length(to)
  352. if (0 == ary[child"ty"]) {
  353. ary[child"st"] = sst substr(ary[child"st"], length(sst) + 1)
  354. ary[child"ls"] = ary[child"lv"] ":" (ary[child"sn"] = to substr(ary[child"sn"], len + 1))
  355. menu2Dimplode(child, ary, nary)
  356. } else {
  357. move_node(child, dst_i, to sK_name, ary, nary, childrenary, trace)
  358. }
  359. }
  360. if (dst_path) {
  361. to = substr(dst_snpath, 1, length(dst_snpath) - 2)
  362. len = length(to)
  363. sst = substr(sst, 1, length(sst) - 4)
  364. ary[src_i"st"] = sst substr(ary[src_i"st"], length(sst) + 1)
  365. ary[src_i"ls"] = ary[src_i"lv"] ":" (ary[src_i"sn"] = to substr(ary[src_i"sn"], len + 1))
  366. if (1 == ary[src_i"ty"]) {
  367. y = ary[src_i"ac"]
  368. ary[src_i"ac"] = substr(y, 1, x = index(y,":")) to substr(y, x + len + 1)
  369. }
  370. menu2Dimplode(src_i, ary, nary)
  371. }
  372. }
  373. function menu2Dsplit(idx, ary, nary,
  374. imin,imax,i,x,y,z,lump,rec,xary,nxary,maxlevel) {
  375. if (idx) {
  376. imin = imax = idx
  377. } else {
  378. imin = 1; imax = nary
  379. }
  380. maxlevel = 0
  381. for (i = imin; i <= imax; i++) if (i in ary) {
  382. nxary = split(ary[i], xary, SEP)
  383. ary[i"st"] = xary[1]
  384. lump = xary[2]
  385. lump = (lump SEP) (x = xary[3])
  386. lump = (lump) (x == 3 ? "" : SEP xary[4])
  387. ary[i"l1"] = lump
  388. ary[i"ls"] = x = xary[nxary - 2]
  389. ary[i"lv"] = z = substr(x, 1, (y = index(x, ":")) - 1)
  390. if (z > maxlevel) maxlevel = z
  391. ary[i"sn"] = substr(x, y + 1)
  392. ary[i"nm"] = xary[nxary - 1]
  393. ary[i"ac"] = x = xary[nxary]
  394. ary[i"ty"] = submenu_actionQ(x) ? 1 : 0
  395. }
  396. return maxlevel
  397. }
  398. function menu2Dimplode(idx, ary, nary,
  399. imin,imax,i) {
  400. if (idx) {
  401. imin = imax = idx
  402. } else {
  403. imin = 1; imax = nary
  404. }
  405. for (i = imin; i <= imax; i++) if (ary[i"sn"]) {
  406. ary[i] = ary[i"st"] SEP ary[i"l1"] SEP ary[i"lv"] ":" ary[i"sn"] SEP ary[i"nm"] SEP ary[i"ac"]
  407. }
  408. return imax
  409. }
  410. function children_map(ary, nary, idx, map,
  411. i,min,max) {
  412. if (0 == idx) {
  413. min = 1
  414. max = nary
  415. } else {
  416. mix = max = idx
  417. }
  418. for (i = min; i <= max; i++) if (i"lv" in ary) {
  419. if (1 == ary[i"ty"])
  420. map[i] = menu_children(ary[i"ac"], ary, nary)
  421. }
  422. return nary
  423. }
  424. function menu_children(matcher, ary, nary,
  425. i,list) {
  426. for (j = 1; j <= nary; j++) {
  427. if (ary[j"ls"] ~ matcher) {
  428. list = list " " j
  429. }
  430. }
  431. return substr(list, 2)
  432. }
  433. function calc_snpath_offset(list, ary, # {{{
  434. x,nxary,xary) {
  435. if (list) {
  436. nxary = split(list, xary, " ")
  437. x = get_items_index(xary[nxary], ary)
  438. } else {
  439. x = -1
  440. }
  441. return x
  442. }
  443. function get_items_index(i, ary, # {{{
  444. x,y) {
  445. if (! i in ary)
  446. return -1
  447. y = ary[i"ls"]
  448. x = length(y)
  449. x = 0 + ("0x" substr(y, x-3, 2))
  450. return x
  451. }
  452. function escs2chars(s) {
  453. if (!match(s,/\\/)) return s
  454. gsub(/\\\\/,"\x01",s)
  455. gsub(/\\\"/,"\"",s)
  456. gsub(/\\b/,"\b",s)
  457. gsub(/\\f/,"\f",s)
  458. gsub(/\\n/,"\n",s)
  459. gsub(/\\r/,"\r",s)
  460. gsub(/\\t/,"\t",s)
  461. gsub(/\x01/,"\\",s)
  462. return s
  463. }
  464. function find_menu_fullpathnames(dirs, return_ary, base,
  465. pj,nj,follow,depth,paths,slurp,i,ary,nary,menu,cmd) {
  466. follow = "true" == config_get("nofollow") ? "" : "-follow"
  467. depth = config_get("search_depth")
  468. depth = "-maxdepth " (""==depth ? 2 : 0+depth)
  469. paths = config_get("search_exclude_paths")
  470. paths = "-path "dirs"/" (""==paths ? "system" : paths)
  471. gsub(/;/," -o -path "dirs"/",paths)
  472. cmd = config_get("NCbbfind")" "dirs" "follow" "depth" \\( "paths" \\) \\( -prune -type f \\) -o \\( -name config.xml -type f \\) 2>/dev/null"
  473. cmd | getline slurp
  474. if (close(cmd)) {
  475. scream(SenCantFindMenuFiles)
  476. return base
  477. }
  478. nary = split(slurp, ary, /\n/)
  479. if (nary) --nary
  480. for (i=1; i <= nary; i++) {
  481. menu = pathjson = pathxml = ""
  482. if (0 <= (getline slurp < ary[i]))
  483. close(ary[i])
  484. if (slurp ~ /<extension>.+<\/extension>/) {
  485. if (match(slurp, /<menu\>[^>]+\<type="json"[^>]*>[^<]+<\/menu>/)) {
  486. slurp = substr(slurp,RSTART,RLENGTH-7)
  487. menu = substr(slurp,1+index(slurp,">"))
  488. }
  489. }
  490. if ("" != menu) {
  491. if ("^/" !~ menu) {
  492. match(ary[i], /^.*\//)
  493. menu = substr(ary[i],RSTART,RLENGTH) menu
  494. }
  495. if (0 <= (getline x < menu)) {
  496. return_ary[++base] = menu
  497. close(menu)
  498. }
  499. }
  500. }
  501. return base
  502. }
  503. function format_action_internal(internal,
  504. p,keyword,cmd) {
  505. cmd = ""
  506. p = index(internal" "," ")
  507. keyword = substr(internal, 1, p - 1)
  508. if (keyword in INTERNAL_ACTIONS) {
  509. cmd = INTERNAL_ACTIONS[keyword]
  510. internal = substr(internal, p + 1)
  511. cmd = cmd length(internal) "#" internal # <internal id char> <length> `
  512. }
  513. return cmd
  514. }
  515. function format_action_item(action, params, internal,
  516. p,cmd,x) {
  517. p = index(action, ";")
  518. cmd = substr(action, p+1)
  519. if (x = format_action_internal(internal)) {
  520. action = "#" x action
  521. }
  522. return (action) ("" != params ? " " : "") (params)
  523. }
  524. function format_action_submenu(level, items_path) {
  525. return "^" (level+1) ":" npath_wo_reserved(items_path) ".." sK_name "$"
  526. }
  527. function json_emit_self_menu_and_parsing_errors(parent_errors,
  528. json,name,sname,msg,ary,nary) {
  529. json=json_self_menu(SELF_BUTTONS_INSERT, SELF_BUTTONS_FILTER, SELF_BUTTONS_APPEND)
  530. if (parent_errors) {
  531. ++ERRORS
  532. json=json "," json_error_button(fit_button(ATTN" "XenParentErrors, ""))
  533. }
  534. for(name in FAILS) {
  535. json=json "," json_error_button(fit_button(ATTN" "XenErrSyntax" ", shortpathname(name)))
  536. }
  537. if (json) {
  538. name = SELF_MENU_NAME
  539. if (ERRORS)
  540. name = name " " ATTN " " ERRORS
  541. json="{\"items\":[{\"name\":\"" name \
  542. "\",\"items\":[" \
  543. substr(json,2) "]}]}"
  544. delete TOKENS; NTOKENS = ITOKENS = 0
  545. tokenize(json)
  546. parse()
  547. jp2np(JPATHS, NJPATHS, 0, "/var/tmp/.")
  548. }
  549. }
  550. function json_error_button(message) {
  551. return "{\"priority\": -1000, \"name\": \"" \
  552. message \
  553. "\", \"action\": \":\", \"internal\": \"breadcrumb [more info in "PRODUCTNAME" log]\", \"exitmenu\": false}"
  554. }
  555. function json_self_menu(extra_insert, standard_filter, extra_append,
  556. json,show,b,ary,nary,verb,btnpath,bak,x,y,slurp) {
  557. if (0 == (show = config_get("show_KUAL_buttons")))
  558. return ""
  559. if ("" == show) show="2 3 99"
  560. show = "0 " show
  561. standard_filter = ","standard_filter","
  562. ORIGIN = PRODUCTNAME " menu"
  563. json = ""
  564. if (nary = split(extra_insert, ary, /,/)) {
  565. for (b = 1; b <= nary; b++) {
  566. if ("+add_ext" == ary[b]) {
  567. json = json "," json_self_menu_button( \
  568. XenNoExtensionsFound, \
  569. ":", "", "breadcrumb help @ http://bit.ly/kualit", \
  570. -200, "", "e")
  571. }
  572. }
  573. }
  574. if (nary = split(show, ary, /\s+/)) {
  575. for (b = 1; b <= nary; b++) {
  576. if (1 == ary[b]) {
  577. } else if (2 == ary[b] && ! index(standard_filter,",-sort_menu," ) ) {
  578. verb = OPT_SORT ~ /^ABC|abc$/ ? "123" : "ABC"
  579. x = "BEGIN{nf=1} /^\\\\s*KUAL_sort_mode=/{sub(/=.*/,\\\"=\\\\\\\""verb"\\\\\\\"\\\");nf=0} {print} END{if(nf) print \\\"KUAL_sort_mode=\\\\\\\""verb"\\\\\\\"\\\"}"
  580. x = "awk '"x"' '"CONFIGPATH"'"
  581. x = "s=$("x") && [ 0 != ${#s} ] && echo \\\"$s\\\" >'"CONFIGPATH"'"
  582. x = "[ -r '"CONFIGPATH"' ] || echo \\\"# "CONFIGPATH" - created on `date`\\\" >'"CONFIGPATH"';" x
  583. json=json "," json_self_menu_button( \
  584. "Sort menu "verb" on restart", \
  585. x, "", \
  586. "", 2, "", "ecsd")
  587. } else if (3 == ary[b]) {
  588. x = "mv '"SCREAM_LOG"' \\\"/mnt/us/documents/"PRODUCTNAME"-`date -u -Iminutes | sed s/:/./g`.txt\\\";dbus-send --system /default com.lab126.powerd.resuming int32:1"
  589. json=json "," json_self_menu_button( \
  590. "Save and reset "PRODUCTNAME" log", \
  591. x, "", \
  592. "", 3, "\"\\\""SCREAM_LOG"\\\" -z!\"", "ecsd")
  593. } else if (99 == ary[b]) {
  594. json=json "," json_self_menu_button( \
  595. CROSS" Quit", \
  596. ":", "", \
  597. "", 99)
  598. }
  599. }
  600. }
  601. return json
  602. }
  603. function json_self_menu_button(name, action, params, internal, priority, xif, non_default_options) {
  604. return "{\"name\": \"" name "\"" \
  605. ", \"action\": \"" action "\"" \
  606. ("" != params ? ", \"params\": \"" params "\"" : "") \
  607. ("" != internal ? ", \"internal\": \"" internal "\"" : "") \
  608. ("" != priority ? ", \"priority\": " priority : "") \
  609. ("" != xif ? ", \"if\": " xif : "") \
  610. (index(non_default_options, "e") ? ", \"exitmenu\": false" : "") \
  611. (index(non_default_options, "c") ? ", \"checked\": true" : "") \
  612. (index(non_default_options, "r") ? ", \"refresh\": true" : "") \
  613. (index(non_default_options, "s") ? ", \"status\": false" : "") \
  614. (index(non_default_options, "d") ? ", \"date\": true" : "") \
  615. (index(non_default_options, "h") ? ", \"hidden\": true" : "") \
  616. "}"
  617. }
  618. function jp2np(ary, size, serial, menufilepathname,
  619. i,x,npath,apath,jpath,key,value,level,errors) {
  620. errors=0
  621. apath=menufilepathname; sub(/\/[^\/]+$/, "", apath)
  622. while (jp2np_LAST_SEEN <= size) {
  623. line=ary[jp2np_LAST_SEEN++] # {
  624. if (line ~ /[]}]$/) {
  625. continue
  626. }
  627. x=index(line,"\t")
  628. jpath=substr(line, 1, x-1)
  629. value=substr(line, x+1)
  630. key = match(jpath, /"[^"]+"]$/) ? substr(jpath, 1+RSTART,RLENGTH-3) : "ERROR"
  631. if (key !~ /^(name|action|params|internal|priority|if|exitmenu|hidden|checked|refresh|status|date)$/) {
  632. continue
  633. }
  634. key=VALID_KEYS[key]
  635. x = jpath
  636. level = gsub(/"items",/, "&", x)
  637. if (0 == level) {
  638. continue
  639. }
  640. --level
  641. npath = npath_new(jpath, serial)
  642. if (2 == gsub(/^"|"$/, "", value)) {
  643. value = escs2chars(value)
  644. }
  645. if (K_name == key) {
  646. gsub(NBSP0, NBSP1, value)
  647. } else if (K_action == key) {
  648. value=apath ";" value
  649. }
  650. NPATHS[++NNPATHS]=level SEP npath SEP key SEP value
  651. }
  652. return errors
  653. }
  654. function np2mn(ary, size,
  655. i,x,slurp,lines,nlines,iline,errors,
  656. npary,level,npath,key,value,options,
  657. npath_s_this_items,select_level,needle,snpath,last_action ) {
  658. errors=0
  659. sort(ary, size, "-k2."(1+sRESERVED_len)",2 -k1,1 -k3,3")
  660. if ("" == SORTED_DATA) {
  661. scream("np2mn can't sort 1")
  662. ++errors
  663. } else {
  664. sort_criteria_init(OPT_SORT)
  665. new_item()
  666. new_submenu()
  667. select_level[0] = npath_wo_reserved(npath_new("",0))
  668. if (0 < (nlines = split(SORTED_DATA,lines, /\n/))) {
  669. for(iline = 1; iline < nlines; iline++) {
  670. split(lines[iline], npary, SEP)
  671. level = npary[1]; npath = npary[2]; key = npary[3]; value = npary[4]
  672. snpath = npath_get_short(npath)
  673. if (K_action == key) {
  674. ITEM[key] = value
  675. last_action = snpath
  676. } else if (K_name == key) {
  677. if ("" == value)
  678. value = "??"(++COUNTER["nameNull"])
  679. if (submenu_pathQ(snpath, last_action)) {
  680. ITEM[key]=value
  681. x = substr(ITEM[K_action], 1, index(ITEM[K_action],";")-1)
  682. if (RPN_if(ITEM[K_if], x)) {
  683. sortable_tag=select_level[level]
  684. MENUS[++NMENUS] = work_record( \
  685. sortable_record(sortable_tag, OPT_SORT),
  686. kindlet_options(),
  687. level,npath_s_this_(K_name, snpath),
  688. ITEM[K_name],
  689. format_action_item(ITEM[K_action], ITEM[K_params], ITEM[K_internal]))
  690. }
  691. new_item()
  692. } else {
  693. ITEM[key]=value MMRK
  694. npath_s_this_items = npath_s_this_(K_items, snpath)
  695. select_level[level+1] = npath_wo_reserved(npath_padded(npath_s_this_items))
  696. sortable_tag = select_level[level]
  697. MENUS[++NMENUS] = work_record( \
  698. sortable_record(sortable_tag, OPT_SORT),
  699. kindlet_options(),
  700. level,snpath,
  701. ITEM[K_name],
  702. format_action_submenu(level, npath_s_this_items))
  703. new_submenu()
  704. }
  705. } else if (K_priority == key || K_params == key || K_internal == key || K_if == key || K_exitmenu == key || K_checked == key || K_refresh == key || K_status == key || K_date == key || K_hidden == key) {
  706. ITEM[key] = value
  707. } else {
  708. scream("unexpected key <"key"> (np2mu)")
  709. ++errors
  710. }
  711. }
  712. }
  713. }
  714. if ("false" != config_get("collate"))
  715. collate(MENUS, NMENUS)
  716. sort_for_user(MENUS, NMENUS, OPT_SORT)
  717. if ("" == SORTED_DATA) {
  718. scream("np2mn can't sort 2")
  719. ++errors
  720. }
  721. delete MENUS; NMENUS=0
  722. NMENUS = sort_criteria_cut(MENUS, OPT_SORT)
  723. return errors
  724. }
  725. function kindlet_options( x) { # {{{
  726. x = (ITEM[K_exitmenu] ~ /^(0|false)$/ ? "e" : "") \
  727. (ITEM[K_checked] ~ /^(1|true)$/ ? "c" : "") \
  728. (ITEM[K_refresh] ~ /^(1|true)$/ ? "r" : "") \
  729. (ITEM[K_status] ~ /^(0|false)$/ ? "s" : "") \
  730. (ITEM[K_date] ~ /^(1|true)$/ ? "d" : "") \
  731. (ITEM[K_hidden] ~ /^(1|true)$/ ? "h" : "")
  732. return "" == x ? "" : x SEP
  733. }
  734. function new_item() {
  735. ITEM[K_name] = ITEM[K_action] = ITEM[K_params] = ITEM[K_internal] = ITEM[K_if] = ITEM[K_exitmenu] = ITEM[K_checked] = ITEM[K_refresh] = ITEM[K_status] = ITEM[K_date] = ITEM[K_hidden] = ""; ITEM[K_priority] = 0;
  736. }
  737. function new_submenu() {
  738. ITEM[K_name] = ITEM[K_if] = ITEM[K_hidden] = ""; ITEM[K_priority] = 0;
  739. }
  740. function npath_from_jpath(jpath, serial,
  741. items,key,snpath,ary,nary,i) {
  742. items = sprintf("%02x", K_items)
  743. snpath = npath_reserved() sprintf("%s%02x", items, serial)
  744. jpath=substr(jpath,2,length(jpath)-2)
  745. nary=split(jpath, ary, /\"items\"/)
  746. key=ary[nary]
  747. sub(/^.+,/, "", key);
  748. key=substr(key, 2, length(key)-2)
  749. sub(/\".+$/, "", ary[nary])
  750. for(i=2; i<=nary; i++) {
  751. snpath = snpath items sprintf("%02x", substr(ary[i],2,length(ary[i])-2))
  752. }
  753. snpath = snpath sprintf("%02x", VALID_KEYS[key])
  754. return npath_padded(snpath)
  755. }
  756. function npath_new(jpath, serial,
  757. key,npath,snpath) {
  758. key = jpath SEP serial
  759. if (key in NPATH_MAP)
  760. return NPATH_MAP[key]
  761. npath = snpath = npath_from_jpath(jpath, serial)
  762. sub(/(ff)+$/, "", snpath)
  763. return NPATH_MAP[key] = NPATH_MAP[npath_wo_reserved(npath)] = NPATH_MAP[npath_wo_reserved(snpath)] = npath
  764. }
  765. function npath_get(path,
  766. upath,npath) {
  767. upath = npath_wo_reserved(path)
  768. return upath in NPATH_MAP ? NPATH_MAP[upath] : (npath_reserved() "NON-EXISTENT:npath_get("path")")
  769. }
  770. function npath_get_short(path,
  771. upath,snpath) {
  772. upath = npath_wo_reserved(path)
  773. if (upath in NPATH_MAP) {
  774. snpath = NPATH_MAP[upath]
  775. sub(/(ff)+$/, "", snpath)
  776. return snpath
  777. }
  778. return (npath_reserved() "NON-EXISTENT:npath_get_short("path")")
  779. }
  780. function npath_padded(path) {
  781. return substr(path FFS, 1, NPATH_len)
  782. }
  783. function npath_reserved(path) {
  784. return "" == path ? sRESERVED : substring(path, 1, sRESERVED_len)
  785. }
  786. function npath_wo_reserved(path, x) {
  787. return substr(path,1+sRESERVED_len)
  788. }
  789. function npath_s_KUAL_menu() {
  790. return npath_get_short(npath_new("[\"[items\",0,\"items\",0,\"name\"]", 0))
  791. }
  792. function npath_s_this_(key, snpath) {
  793. return substr(snpath,1,length(snpath)-2) sprintf("%02x", key)
  794. }
  795. function RPN_if(expr, source,
  796. x,token,nxary,xary) {
  797. if ("" == expr) return 1
  798. RPN_sp = 0
  799. RPN_err = ""
  800. nxary = RPN_tokenize(expr, xary)
  801. for(x = 1; x <= nxary; x++) {
  802. token = xary[x]
  803. if (match(token, /^\".*\"$/))
  804. token = substr(token, 2, RLENGTH - 2)
  805. RPN_eval_bool(token)
  806. if(RPN_err) {
  807. scream(RPN_msg(expr, source, RPN_err))
  808. return 1
  809. }
  810. }
  811. if (1 != RPN_sp) {
  812. scream(RPN_msg(expr, source, "invalid expression"))
  813. return 1
  814. }
  815. return RPN_top()
  816. }
  817. function RPN_eval_bool(token,
  818. x,y,z) {
  819. if (token !~ /^(-e|-ext|-f|-gg?!?|-o|-z!|!|&&|\|\|)$/) {
  820. RPN_push(token)
  821. } else {
  822. x = RPN_stack[RPN_sp]
  823. RPN_pop();
  824. if (token == "!") {
  825. RPN_push(! x)
  826. } else if (token == "-f" || token == "-z!") {
  827. z = isRegularFileEmpty(x)
  828. RPN_push(token == "-f" && -1 != z || token == "-z!" && 0 < z)
  829. } else if (token == "-e") {
  830. RPN_push(!system("test -e \""x"\""))
  831. } else if (token == "-ext") {
  832. RPN_push(x in LOADED_EXTENSIONS)
  833. } else {
  834. y = RPN_stack[RPN_sp]
  835. RPN_pop()
  836. if (token == "&&") {
  837. RPN_push(x && y)
  838. } else if (token == "||") {
  839. RPN_push(x || y)
  840. } else if (token ~ "-gg?!?") {
  841. if ( -1 == (z = RPN_grep(x, y, index(token, "!")))) {
  842. if (index(token, "gg")) {
  843. RPN_push(0)
  844. } else {
  845. RPN_err = "not found: \""y"\""
  846. }
  847. } else {
  848. RPN_push(z)
  849. }
  850. } else if (token == "-o") {
  851. RPN_push((z = config_get(y)) == x)
  852. } else {
  853. RPN_err = "invalid operator: " + token
  854. }
  855. }
  856. }
  857. }
  858. function RPN_push(x) { RPN_stack[++RPN_sp] = x }
  859. function RPN_pop() { if(RPN_sp > 0) {RPN_sp--} else {RPN_err = "Stack underflow"} }
  860. function RPN_top() { return RPN_sp > 0 ? RPN_stack[RPN_sp] : "--empty stack--" }
  861. function RPN_grep(pattern, file, vflag,
  862. x, xary, nxary, found) {
  863. if (0 < (getline x < file)) {
  864. close(file)
  865. nxary = split(x, xary, /\n/)
  866. if (vflag) {
  867. found = 0
  868. for (x = 1; x <= nxary; x++) {
  869. if (xary[x] ~ pattern) {
  870. found = 1
  871. }
  872. }
  873. return ! found
  874. } else {
  875. for (x = 1; x <= nxary; x++) {
  876. if (xary[x] ~ pattern) {
  877. return 1
  878. }
  879. }
  880. return 0
  881. }
  882. } else {
  883. return -1
  884. }
  885. return split(a1, ary, /\n/)
  886. }
  887. function RPN_msg(expr, source, text) {
  888. return "\""source"\": JSON \"if\": "expr" : "text
  889. }
  890. function RPN_tokenize(a1, ary,
  891. SPACE) {
  892. SPACE="[[:space:]]+"
  893. gsub(/\"[^[:cntrl:]\"\\]*((\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})[^[:cntrl:]\"\\]*)*\"|-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?|-e|-ext|-f|-gg?!?|-o|-z!|!|&&|\|\||[[:space:]]+|./, "\n&", a1)
  894. gsub("\n" SPACE, "\n", a1)
  895. sub(/^\n/, "", a1)
  896. return split(a1, ary, /\n/)
  897. }
  898. function sort(ary, nary, sort_options,
  899. tfl,i,cmd,rec) {
  900. SORTED_DATA = ""
  901. if (0 == nary) return
  902. tfl=TFL"-sort" substr(rand(),3)
  903. for (i=1; i<=nary; i++) {
  904. if (rec = ary[i]) print rec > tfl
  905. }
  906. close(tfl)
  907. cmd = config_get("NCbbsort")" -t \""SEP"\" "sort_options" < \""tfl"\""
  908. cmd | getline SORTED_DATA
  909. if (close(cmd))
  910. scream(SenCantSort)
  911. }
  912. function sort_criteria_init(opt_sort) {
  913. if ("ABC" == toupper(opt_sort)) {
  914. SORT_CRITERIA=1
  915. SORT_FIELDS=2
  916. } else if ("ABC!" == toupper(opt_sort)) {
  917. SORT_CRITERIA=2
  918. SORT_FIELDS=2
  919. } else if ("123" == toupper(opt_sort)) {
  920. SORT_CRITERIA=3
  921. SORT_FIELDS=2
  922. } else {
  923. SORT_CRITERIA = SORT_FIELDS = 0
  924. }
  925. }
  926. function sortable_record(sortable_tag, opt_sort) {
  927. if (1 == SORT_CRITERIA || 2 == SORT_CRITERIA ) {
  928. return sortable_tag SEP ITEM[K_name] SEP
  929. } else if (3 == SORT_CRITERIA) {
  930. return sortable_tag SEP ITEM[K_priority] SEP
  931. }
  932. return ""
  933. }
  934. function sort_criteria_cut(ary, opt_sort,
  935. nary,p,x,i) {
  936. i = nary = split(SORTED_DATA, ary, /\n/)
  937. if (0 < SORT_CRITERIA) {
  938. if(2 == SORT_FIELDS) {
  939. while (i > 0) {
  940. x = ary[i]
  941. p = index(x, SEP)
  942. p += index(substr(x, p+1), SEP)
  943. ary[i] = substr(x, p+1)
  944. --i
  945. }
  946. } else {
  947. scream("SORT_FIELDS != 2 not implemented")
  948. ++ERRORS
  949. }
  950. } else {
  951. }
  952. return nary
  953. }
  954. function sort_for_user(ary, nary, opt_sort, # {{{
  955. cherry,i,ary0,nary0,non_zero,rec) {
  956. cherry = SEP "0:" npath_wo_reserved(npath_s_KUAL_menu()) SEP
  957. for (i = 1; i <= nary; i++) {
  958. if (index(ary[i], cherry)) {
  959. cherry = ary[i]
  960. ary[i] = 0
  961. break
  962. }
  963. }
  964. if (i > nary) {
  965. cherry=""
  966. scream("can't select "PRODUCTNAME" menu entry")
  967. }
  968. SORTED_DATA=""
  969. if (1 == SORT_CRITERIA) {
  970. nary0 = 0
  971. non_zero = ""
  972. for (i = 1; i <= nary; i++) {
  973. if (rec = ary[i]) {
  974. if (rec ~ SEP"0:")
  975. ary0[++nary0] = rec
  976. else
  977. non_zero = non_zero "/" i
  978. }
  979. }
  980. sort(ary0, nary0, "-s -f -k1,1 -k2,2")
  981. non_zero = non_zero "/"
  982. for (i = 1; i <= nary; i++) {
  983. if (index(non_zero, "/"i"/"))
  984. SORTED_DATA = SORTED_DATA "\n" ary[i]
  985. }
  986. } else if (3 == SORT_CRITERIA) {
  987. sort(ary, nary, "-s -k1,1 -k2,2n")
  988. } else if (2 == SORT_CRITERIA) {
  989. sort(ary, nary, "-s -f -k1,1 -k2,2")
  990. } else {
  991. SORTED_DATA=MENUS[1]
  992. for(i=2; i<=NMENUS; i++) {
  993. SORTED_DATA = SORTED_DATA "\n" MENUS[i]
  994. }
  995. }
  996. if ("" != cherry) {
  997. SORTED_DATA = cherry "\n" SORTED_DATA
  998. }
  999. }
  1000. function submenu_actionQ(action) {
  1001. return "^" == substr(action, 1, 1) && "$" == substr(action, length(action))
  1002. }
  1003. function submenu_pathQ(snpath, last_action, x,y) {
  1004. x = npath_wo_reserved(snpath)
  1005. y = npath_wo_reserved(last_action)
  1006. return substr(x,1,length(x)-2) == substr(y,1,length(y)-2)
  1007. }
  1008. function work_record(sortable_record, options, level,snpath, name, action,
  1009. lvlsnpath) {
  1010. lvlsnpath = level ":" npath_wo_reserved(snpath)
  1011. return sprintf("%s%s"SEP"%s%s"SEP"%s"SEP"%s",
  1012. sortable_record,
  1013. "" == options ? 3 : 4,
  1014. options,
  1015. lvlsnpath, name, action)
  1016. }
  1017. function fit_button(left, right, len,rlen,cut) {
  1018. len=MAX_LABEL_LEN - length(left)
  1019. if (len < (rlen=length(right))) {
  1020. right=substr(right,rlen-len+1)
  1021. right=" .."substr(right,4)
  1022. }
  1023. return left right
  1024. }
  1025. function formatter(ary, nary, fmt_name, outfile, # {{{
  1026. fmt,i,rec,x,n,errors) {
  1027. errors = 0
  1028. if ("multiline" == fmt_name) {
  1029. for (i = 1; i <= nary; i++) {
  1030. if (rec = ary[i]) {
  1031. gsub(SEP,"\n",rec)
  1032. print rec >>outfile
  1033. }
  1034. }
  1035. } else if ("tbl" == fmt_name) {
  1036. fmt="%-4.4s|%-24.24s|%-20.20s|%-33.33s\n"
  1037. for (i = 1; i <= nary; i++) {
  1038. if (rec = ary[i]) {
  1039. n = split(rec, x, SEP)
  1040. if (n-1 != x[1]) {
  1041. scream("wrong record size <"x[1]"> in record # "i" (formatter)")
  1042. ++errors
  1043. print rec >>outfile
  1044. }
  1045. if (4 == n) {
  1046. printf fmt, "", x[2], x[3], x[4]
  1047. } else if (5 == n) {
  1048. printf fmt, x[2], x[3], x[4], x[5]
  1049. } else {
  1050. scream("wrong argument count "n" in record # "i" (formatter)")
  1051. ++errors
  1052. print rec >>outfile
  1053. }
  1054. }
  1055. }
  1056. } else if ("tab" == fmt_name) {
  1057. for (i = 1; i <= nary; i++) {
  1058. if (rec = ary[i]) {
  1059. gsub(SEP,"\t",rec)
  1060. print rec >>outfile
  1061. }
  1062. }
  1063. } else {
  1064. for (i = 1; i <= nary; i++) {
  1065. if (rec = ary[i])
  1066. print rec >>outfile
  1067. }
  1068. }
  1069. return errors
  1070. }
  1071. function shortpathname(pathname, ary,nary) {
  1072. return (nary = split(pathname, ary, /\//)) \
  1073. ? ary[nary-1] "/" ary[nary] : pathname
  1074. }
  1075. function get_model( x,
  1076. y,z,xary,nxary,cpu_mod) {
  1077. if (MODEL) return MODEL
  1078. MODEL = "Unknown"
  1079. cpu_mod = ""
  1080. y = "/proc/cpuinfo"
  1081. if (0 <= (getline x < y)) {
  1082. close(y)
  1083. if (nxary = split(x, xary, /\n/)) {
  1084. for (x = 1; x <= nxary; x++) {
  1085. z = xary[x]
  1086. if (match(z, /MX[0-9]+/)) {
  1087. cpu_mod = substr(z, RSTART, RLENGTH)
  1088. break
  1089. }
  1090. if (z ~ "Hardware : Mario Platform") {
  1091. MODEL = "KindleDXG"
  1092. break
  1093. }
  1094. }
  1095. }
  1096. }
  1097. if (cpu_mod == "MX50") {
  1098. if (! system("test -e \"/sys/devices/system/fl_tps6116x/fl_tps6116x0/fl_intensity\""))
  1099. MODEL = "KindlePaperWhite"
  1100. else if (! system("test -e \"/sys/devices/platform/whitney-button\""))
  1101. MODEL = "KindleTouch"
  1102. else
  1103. MODEL = "Kindle4"
  1104. } else if (cpu_mod == "MX35") {
  1105. MODEL = "Kindle3"
  1106. } else if (cpu_mod == "MX3") {
  1107. MODEL = "Kindle2"
  1108. }
  1109. return MODEL
  1110. }
  1111. function isRegularFileEmpty (x,
  1112. y,z) {
  1113. z = (getline y < x)
  1114. if (0 <= z) close(x)
  1115. return z
  1116. }
  1117. function get_token() {
  1118. TOKEN = TOKENS[++ITOKENS]
  1119. return ITOKENS < NTOKENS
  1120. }
  1121. function parse_array(a1, idx,ary,ret) {
  1122. idx=0
  1123. ary=""
  1124. get_token()
  1125. if (TOKEN != "]") {
  1126. while (1) {
  1127. if (ret = parse_value(a1, idx)) {
  1128. return ret
  1129. }
  1130. idx=idx+1
  1131. ary=ary VALUE
  1132. get_token()
  1133. if (TOKEN == "]") {
  1134. break
  1135. } else if (TOKEN == ",") {
  1136. ary = ary ","
  1137. } else {
  1138. report(", or ]", TOKEN ? TOKEN : "EOF")
  1139. return 2
  1140. }
  1141. get_token()
  1142. }
  1143. }
  1144. if (1 != BRIEF) {
  1145. VALUE=sprintf("[%s]", ary)
  1146. } else {
  1147. VALUE=""
  1148. }
  1149. return 0
  1150. }
  1151. function parse_object(a1, key,obj) {
  1152. obj=""
  1153. get_token()
  1154. if (TOKEN != "}") {
  1155. while (1) {
  1156. if (TOKEN ~ /^".*"$/) {
  1157. key=TOKEN
  1158. } else {
  1159. report("string", TOKEN ? TOKEN : "EOF")
  1160. return 3
  1161. }
  1162. get_token()
  1163. if (TOKEN != ":") {
  1164. report(":", TOKEN ? TOKEN : "EOF")
  1165. return 4
  1166. }
  1167. get_token()
  1168. if (parse_value(a1, key)) {
  1169. return 5
  1170. }
  1171. obj=obj key ":" VALUE
  1172. get_token()
  1173. if (TOKEN == "}") {
  1174. break
  1175. } else if (TOKEN == ",") {
  1176. obj=obj ","
  1177. } else {
  1178. report(", or }", TOKEN ? TOKEN : "EOF")
  1179. return 6
  1180. }
  1181. get_token()
  1182. }
  1183. }
  1184. if (1 != BRIEF) {
  1185. VALUE=sprintf("{%s}", obj)
  1186. } else {
  1187. VALUE=""
  1188. }
  1189. return 0
  1190. }
  1191. function parse_value(a1, a2, jpath,ret,x) {
  1192. jpath=(a1!="" ? a1 "," : "") a2
  1193. if (TOKEN == "{") {
  1194. if (parse_object(jpath)) {
  1195. return 7
  1196. }
  1197. } else if (TOKEN == "[") {
  1198. if (ret = parse_array(jpath)) {
  1199. return ret
  1200. }
  1201. } else if (TOKEN ~ /^(|[^0-9])$/) {
  1202. report("value", TOKEN!="" ? TOKEN : "EOF")
  1203. return 9
  1204. } else {
  1205. VALUE=TOKEN
  1206. }
  1207. if (! (1 == BRIEF && ("" == jpath || "" == VALUE))) {
  1208. x=sprintf("[%s]\t%s", jpath, VALUE)
  1209. if(0 == STREAM) {
  1210. JPATHS[++NJPATHS] = x
  1211. } else {
  1212. print x
  1213. }
  1214. }
  1215. return 0
  1216. }
  1217. function parse( ret) {
  1218. get_token()
  1219. if (ret = parse_value()) {
  1220. return ret
  1221. }
  1222. if (get_token()) {
  1223. report("EOF", TOKEN)
  1224. return 11
  1225. }
  1226. return 0
  1227. }
  1228. function report(expected, got, i,from,to,context) {
  1229. from = ITOKENS - 10; if (from < 1) from = 1
  1230. to = ITOKENS + 10; if (to > NTOKENS) to = NTOKENS
  1231. for (i = from; i < ITOKENS; i++)
  1232. context = context sprintf("%s ", TOKENS[i])
  1233. context = context "<<" got ">> "
  1234. for (i = ITOKENS + 1; i <= to; i++)
  1235. context = context sprintf("%s ", TOKENS[i])
  1236. scream("expected <" expected "> but got <" got "> at input token " ITOKENS "\n" context,
  1237. "" != ORIGIN ? ORIGIN : FILENAME)
  1238. }
  1239. function reset() {
  1240. TOKEN=""; delete TOKENS; NTOKENS=ITOKENS=0
  1241. VALUE=""
  1242. }
  1243. function scream(msg, origin,
  1244. x) {
  1245. if ("" == origin)
  1246. origin=PRODUCTNAME
  1247. if (! SCREAMED_BEFORE) {
  1248. ++SCREAMED_BEFORE
  1249. "date" | getline x
  1250. close("date")
  1251. printf "\n%s: ***** started on %s", PRODUCTNAME, x >> SCREAM_LOG
  1252. }
  1253. FAILS[origin] = FAILS[origin] (FAILS[origin]!="" ? "\n" : "") msg
  1254. msg = origin ": " msg
  1255. print msg >> SCREAM_LOG
  1256. }
  1257. function tokenize(a1, pq,pb,ESCAPE,CHAR,STRING,NUMBER,KEYWORD,SPACE) {
  1258. SPACE="[[:space:]]+"
  1259. gsub(/\"[^[:cntrl:]\"\\]*((\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})[^[:cntrl:]\"\\]*)*\"|-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?|null|false|true|[[:space:]]+|./, "\n&", a1)
  1260. gsub("\n" SPACE, "\n", a1)
  1261. sub(/^\n/, "", a1)
  1262. ITOKENS=0
  1263. return NTOKENS = split(a1, TOKENS, /\n/)
  1264. }