PageRenderTime 61ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/libsofia-sip-ua/msg/msg_parser.awk

https://bitbucket.org/oisinglynn/sofia-sip
AWK | 660 lines | 503 code | 96 blank | 61 comment | 0 complexity | f1dbd060c71be3443e68c2c95640951d MD5 | raw file
Possible License(s): LGPL-2.1
  1. #! /usr/bin/env awk
  2. #
  3. # This script recreates C files containing header-specific boilerplate stuff
  4. # using the given list of headers (usually obtained from the master structure).
  5. #
  6. # It can also create a parser table.
  7. #
  8. # --------------------------------------------------------------------
  9. #
  10. # This file is part of the Sofia-SIP package
  11. #
  12. # Copyright (C) 2005 Nokia Corporation.
  13. #
  14. # Contact: Pekka Pessi <pekka.pessi@nokia.com>
  15. #
  16. # This library is free software; you can redistribute it and/or
  17. # modify it under the terms of the GNU Lesser General Public License
  18. # as published by the Free Software Foundation; either version 2.1 of
  19. # the License, or (at your option) any later version.
  20. #
  21. # This library is distributed in the hope that it will be useful, but
  22. # WITHOUT ANY WARRANTY; without even the implied warranty of
  23. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  24. # Lesser General Public License for more details.
  25. #
  26. # You should have received a copy of the GNU Lesser General Public
  27. # License along with this library; if not, write to the Free Software
  28. # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  29. # 02110-1301 USA
  30. #
  31. # --------------------------------------------------------------------
  32. #
  33. # Contributor(s): Pekka.Pessi@nokia.com.
  34. #
  35. # Created: Fri Apr 6 12:59:59 2001 ppessi
  36. #
  37. BEGIN {
  38. "date '+%a %b %e %H:%M:%S %Y'" | getline date;
  39. ascii = \
  40. " " \
  41. " !\"#$%&'()*+,-./0123456789:;<=>?" \
  42. "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" \
  43. "`abcdefghijklmnopqrstuvwxyz{|}~";
  44. lower_case = "abcdefghijklmnopqrstuvwxyz";
  45. N=0;
  46. # Initialize these as arrays
  47. split("", symbols);
  48. split("", names);
  49. split("", comments);
  50. split("", hashes);
  51. split("", NAMES);
  52. split("", Comments);
  53. split("", COMMENTS);
  54. # indexed by the C name of the header
  55. split("", Since); # Non-NUL if extra
  56. split("", Extra); # Offset in extra headers
  57. total = 0;
  58. ordinary = 0;
  59. basic = 0;
  60. extra = 0;
  61. without_experimental = 0;
  62. template="";
  63. template1="";
  64. template2="";
  65. template3="";
  66. prefix="";
  67. tprefix="";
  68. failed=0;
  69. success=0;
  70. ERRNO="error";
  71. }
  72. function name_hash (name)
  73. {
  74. hash = 0;
  75. len = length(name);
  76. for (i = 1; i <= len; i++) {
  77. c = tolower(substr(name, i, 1));
  78. hash = (38501 * (hash + index(ascii, c))) % 65536;
  79. }
  80. if (hash == 0) {
  81. print "*** msg_parser.awk: calculating hash failed\n";
  82. exit(5);
  83. }
  84. if (0) {
  85. # Test that hash algorithm above agrees with the C version
  86. pipe = ("../msg/msg_name_hash " name);
  87. pipe | getline;
  88. close(pipe);
  89. if (hash != $0) {
  90. print name ": " hash " != " $0 > "/dev/stderr";
  91. }
  92. }
  93. return hash "";
  94. }
  95. #
  96. # Replace magic patterns in template p with header-specific values
  97. #
  98. function protos (name, comment, hash, since)
  99. {
  100. NAME=toupper(name);
  101. sub(/.*[\/][*][*][<][ ]*/, "", comment);
  102. sub(/[ ]*[*][\/].*/, "", comment);
  103. sub(/[ ]+/, " ", comment);
  104. short = match(comment, /[(][a-z][)]/);
  105. if (short) {
  106. short = substr(comment, short + 1, 1);
  107. sub(/ *[(][a-z][)]/, "", comment);
  108. shorts[index(lower_case, short)] = name;
  109. }
  110. do_hash = hash == 0;
  111. if (do_hash) {
  112. split(comment, parts, " ");
  113. name2 = tolower(parts[1]);
  114. gsub(/-/, "_", name2);
  115. if (name2 != name && name2 != tprefix "_" name) {
  116. print name " mismatch with " comment " (" real ")" > "/dev/stderr";
  117. }
  118. hash = name_hash(parts[1]);
  119. hashed[name] = hash;
  120. if (comment !~ /header/) {
  121. comment = comment " header";
  122. }
  123. }
  124. Comment = comment;
  125. if (!do_hash) {
  126. comment = tolower(comment);
  127. }
  128. COMMENT = toupper(comment);
  129. # Store the various forms into an array for the footer processing
  130. N++;
  131. hashes[N] = hash;
  132. names[N] = name;
  133. NAMES[N] = NAME;
  134. comments[N] = comment;
  135. Comments[N] = comment;
  136. COMMENTS[N] = COMMENT;
  137. symbols[name] = comment;
  138. if (since) {
  139. Since[name] = since;
  140. }
  141. expr = (without_experimental > 0 && do_hash);
  142. if (expr) {
  143. printf "%s is experimental\n", Comment;
  144. }
  145. experimental[N] = expr;
  146. if (PR) {
  147. if (expr) {
  148. print "#if SU_HAVE_EXPERIMENTAL" > PR;
  149. }
  150. replace(template, hash, name, NAME, comment, Comment, COMMENT, since);
  151. replace(template1, hash, name, NAME, comment, Comment, COMMENT, since);
  152. replace(template2, hash, name, NAME, comment, Comment, COMMENT, since);
  153. replace(template3, hash, name, NAME, comment, Comment, COMMENT, since);
  154. if (expr) {
  155. print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
  156. }
  157. }
  158. }
  159. function replace (p, hash, name, NAME, comment, Comment, COMMENT, since)
  160. {
  161. #
  162. # Replace various forms of header name in template, print it out
  163. #
  164. if (p) {
  165. gsub(/#hash#/, hash, p);
  166. gsub(/#xxxxxx#/, name, p);
  167. gsub(/#XXXXXX#/, NAME, p);
  168. gsub(/#xxxxxxx_xxxxxxx#/, comment, p);
  169. gsub(/#Xxxxxxx_Xxxxxxx#/, Comment, p);
  170. gsub(/#XXXXXXX_XXXXXXX#/, COMMENT, p);
  171. if (since) {
  172. gsub(/#version#/, since, p);
  173. }
  174. else {
  175. # Remove line with #version#
  176. gsub(/\n[^#\n]*#version#[^\n]*/, "", p);
  177. }
  178. print p > PR;
  179. }
  180. }
  181. #
  182. # Repeat each line in the footer containing the magic replacement
  183. # pattern with an instance of all headers
  184. #
  185. function process_footer (text)
  186. {
  187. if (!match(tolower(text), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) {
  188. n = length(text);
  189. while (substr(text, n) == "\n") {
  190. n = n - 1;
  191. text = substr(text, 1, n);
  192. }
  193. if (n > 0)
  194. print text > PR;
  195. return;
  196. }
  197. n = split(text, lines, RS);
  198. for (i = 1; i <= n; i++) {
  199. l = lines[i];
  200. if (match(tolower(l), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) {
  201. expr = 0;
  202. for (j = 1; j <= N; j++) {
  203. l = lines[i];
  204. if (expr != experimental[j]) {
  205. expr = experimental[j];
  206. if (expr) {
  207. print "#if SU_HAVE_EXPERIMENTAL" > PR;
  208. }
  209. else {
  210. print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
  211. }
  212. }
  213. gsub(/#hash#/, hashes[j], l);
  214. gsub(/#xxxxxxx_xxxxxxx#/, comments[j], l);
  215. gsub(/#Xxxxxxx_Xxxxxxx#/, Comments[j], l);
  216. gsub(/#XXXXXXX_XXXXXXX#/, COMMENTS[j], l);
  217. gsub(/#xxxxxx#/, names[j], l);
  218. gsub(/#XXXXXX#/, NAMES[j], l);
  219. print l > PR;
  220. }
  221. if (expr) {
  222. print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
  223. }
  224. } else {
  225. print l > PR;
  226. }
  227. }
  228. }
  229. #
  230. # Read flags used with headers
  231. #
  232. function read_header_flags (flagfile, line, tokens, name, value)
  233. {
  234. while ((getline line < flagfile) > 0) {
  235. sub(/^[ \t]+/, "", line);
  236. sub(/[ \t]+$/, "", line);
  237. if (line ~ /^#/ || line ~ /^$/)
  238. continue;
  239. split(line, tokens, /[ \t]*=[ \t]*/);
  240. name = tolower(tokens[1]);
  241. gsub(/-/, "_", name);
  242. gsub(/,/, " ", name);
  243. # print "FLAG: " name " = " tokens[2]
  244. if (header_flags[name]) {
  245. print flagfile ": already defined " tokens[1];
  246. }
  247. else if (!symbols[name]) {
  248. print flagfile ": unknown header \"" tokens[1] "\"";
  249. }
  250. else {
  251. header_flags[name] = tokens[2];
  252. }
  253. }
  254. close(flagfile);
  255. }
  256. #
  257. # Read in templates
  258. #
  259. function templates ()
  260. {
  261. if (!auto) {
  262. auto = FILENAME;
  263. if (!prefix) { prefix = module; }
  264. if (!tprefix) { tprefix = prefix; }
  265. sub(/.*\//, "", auto);
  266. auto = "This file is automatically generated from <" auto "> by msg_parser.awk.";
  267. if (PR) {
  268. if (TEMPLATE == "") { TEMPLATE = PR ".in"; }
  269. RS0=RS; RS="\f\n";
  270. if ((getline theader < TEMPLATE) < 0) {
  271. print ( TEMPLATE ": " ERRNO );
  272. failed=1;
  273. exit(1);
  274. }
  275. getline header < TEMPLATE;
  276. getline template < TEMPLATE;
  277. getline footer < TEMPLATE;
  278. if (TEMPLATE1) {
  279. if ((getline dummy < TEMPLATE1) < 0) {
  280. print(TEMPLATE1 ": " ERRNO);
  281. failed=1;
  282. exit(1);
  283. }
  284. getline dummy < TEMPLATE1;
  285. getline template1 < TEMPLATE1;
  286. getline dummy < TEMPLATE1;
  287. }
  288. if (TEMPLATE2) {
  289. if ((getline dummy < TEMPLATE2) < 0) {
  290. print( TEMPLATE2 ": " ERRNO );
  291. failed=1;
  292. exit(1);
  293. }
  294. getline dummy < TEMPLATE2;
  295. getline template2 < TEMPLATE2;
  296. getline dummy < TEMPLATE2;
  297. }
  298. if (TEMPLATE3) {
  299. if ((getline dummy < TEMPLATE3) < 0) {
  300. print( TEMPLATE3 ": " ERRNO );
  301. failed=1;
  302. exit(1);
  303. }
  304. getline dummy < TEMPLATE3;
  305. getline template3 < TEMPLATE3;
  306. getline dummy < TEMPLATE3;
  307. }
  308. sub(/.*[\/]/, "", TEMPLATE);
  309. gsub(/#AUTO#/, auto, header);
  310. gsub(/#DATE#/, "@date Generated: " date, header);
  311. if (PACKAGE_NAME) gsub(/#PACKAGE_NAME#/, PACKAGE_NAME, header);
  312. if (PACKAGE_VERSION) gsub(/#PACKAGE_VERSION#/, PACKAGE_VERSION, header);
  313. print header > PR;
  314. RS=RS0;
  315. }
  316. if (!NO_FIRST) {
  317. protos("request", "/**< Request line */", -1);
  318. protos("status", "/**< Status line */", -2);
  319. }
  320. }
  321. }
  322. /^#### EXTRA HEADER LIST STARTS HERE ####$/ { HLIST=1; templates(); }
  323. HLIST && /^#### DEFAULT HEADER LIST ENDS HERE ####$/ { basic=total; }
  324. HLIST && /^#### EXPERIMENTAL HEADER LIST STARTS HERE ####$/ {
  325. without_experimental = total; }
  326. HLIST && /^[a-z]/ { protos($1, $0, 0, $2);
  327. headers[total++] = $1;
  328. Extra[$1] = extra++;
  329. }
  330. /^#### EXTRA HEADER LIST ENDS HERE ####$/ { HLIST=0; }
  331. /^ *\/\* === Headers start here \*\// { in_header_list=1; templates(); }
  332. /^ *\/\* === Headers end here \*\// { in_header_list=0; }
  333. PT && /^ *\/\* === Hash headers end here \*\// { in_header_list=0;}
  334. in_header_list && /^ (sip|rtsp|http|msg|mp)_[a-z_0-9]+_t/ {
  335. n=$0
  336. sub(/;.*$/, "", n);
  337. sub(/^ *(sip|rtsp|http|msg|mp)_[a-z0-9_]*_t[ ]*/, "", n);
  338. sub(/^[*](sip|rtsp|http|msg|mp)_/, "", n);
  339. if ($0 !~ /[\/][*][*][<]/) {
  340. getline;
  341. }
  342. if ($0 !~ /[\/][*][*][<]/) {
  343. printf "msg_protos.awk: header %s is malformed\n", n;
  344. failed=1;
  345. exit 1;
  346. }
  347. if (!NO_MIDDLE)
  348. protos(n, $0, 0);
  349. headers[total] = n; total++; ordinary++;
  350. }
  351. function print_parser_table(struct, scope, name, N, N_EXPERIMENTAL)
  352. {
  353. if (PT) {
  354. if (N > ordinary) {
  355. printf("/* Ordinary %u, extra %u, experimental %u */\n",
  356. ordinary, N - ordinary, N_EXPERIMENTAL - N) > PT;
  357. printf("struct %s {\n", struct) > PT;
  358. printf(" %s_t base;\n", module) > PT;
  359. printf(" msg_header_t *extra[%u];\n", N - ordinary) > PT;
  360. if (N != N_EXPERIMENTAL) {
  361. print "#if SU_HAVE_EXPERIMENTAL" > PT;
  362. printf(" msg_header_t *extra[%u];\n", N_EXPERIMENTAL - N) > PT;
  363. print "#endif" > PT;
  364. }
  365. printf("};\n\n") > PT;
  366. }
  367. printf("%s\n", scope) > PT;
  368. printf("msg_mclass_t const %s[1] = \n{{\n", name) > PT;
  369. printf("# if defined (%s_HCLASS)\n", toupper(module)) > PT;
  370. printf(" %s_HCLASS,\n", toupper(module)) > PT;
  371. printf("#else\n") > PT;
  372. printf(" {{ 0 }},\n") > PT;
  373. printf("#endif\n") > PT;
  374. printf(" %s_VERSION_CURRENT,\n", toupper(module)) > PT;
  375. printf(" %s_PROTOCOL_TAG,\n", toupper(module)) > PT;
  376. printf("#if defined (%s_PARSER_FLAGS)\n", toupper(module)) > PT;
  377. printf(" %s_PARSER_FLAGS,\n", toupper(module)) > PT;
  378. printf("#else\n") > PT;
  379. printf(" 0,\n") > PT;
  380. printf("#endif\n") > PT;
  381. if (N > ordinary) {
  382. printf(" sizeof (struct %s),\n", struct) > PT;
  383. }
  384. else {
  385. printf(" sizeof (%s_t),\n", module) > PT;
  386. }
  387. printf(" %s_extract_body,\n", module) > PT;
  388. len = split("request status separator payload unknown error", unnamed, " ");
  389. for (i = 1; i <= len; i++) {
  390. printf(" {{ %s_%s_class, msg_offsetof(%s_t, %s_%s) }},\n",
  391. tprefix, unnamed[i], module, prefix, unnamed[i]) > PT;
  392. }
  393. if (multipart) {
  394. printf(" {{ %s_class, msg_offsetof(%s_t, %s_multipart) }},\n",
  395. multipart, module, prefix) > PT;
  396. } else {
  397. printf(" {{ NULL, 0 }},\n") > PT;
  398. }
  399. if (MC_SHORT_SIZE) {
  400. printf(" %s_short_forms, \n", module) > PT;
  401. }
  402. else {
  403. printf(" NULL, \n") > PT;
  404. }
  405. printf(" %d, \n", MC_HASH_SIZE) > PT;
  406. if (N != N_EXPERIMENTAL) {
  407. print "#if SU_HAVE_EXPERIMENTAL" > PT;
  408. printf(" %d,\n", N_EXPERIMENTAL) > PT;
  409. print "#else" > PT;
  410. }
  411. printf(" %d,\n", N) > PT;
  412. if (N != N_EXPERIMENTAL) {
  413. print "#endif" > PT;
  414. }
  415. printf(" {\n") > PT;
  416. for (j = 0; j < MC_HASH_SIZE; j++) {
  417. c = (j + 1 == MC_HASH_SIZE) ? "" : ",";
  418. if (j in header_hash) {
  419. n = header_hash[j];
  420. i = index_hash[j];
  421. flags = header_flags[n]; if (flags) flags = ",\n " flags;
  422. if (i >= N) {
  423. print "#if SU_HAVE_EXPERIMENTAL" > PT;
  424. }
  425. if (i >= ordinary) {
  426. printf(" { %s_%s_class,\n" \
  427. " msg_offsetof(struct %s, extra[%u])%s }%s\n",
  428. tprefix, n, struct, Extra[n], flags, c) > PT;
  429. }
  430. else {
  431. printf(" { %s_%s_class, msg_offsetof(%s_t, %s_%s)%s }%s\n",
  432. tprefix, n, module, prefix, n, flags, c) > PT;
  433. }
  434. if (i >= N) {
  435. printf("#else\n { NULL, 0 }%s\n#endif\n", c) > PT;
  436. }
  437. }
  438. else {
  439. printf(" { NULL, 0 }%s\n", c) > PT;
  440. }
  441. }
  442. printf(" }\n}};\n\n") > PT;
  443. }
  444. }
  445. END {
  446. if (failed) { exit };
  447. if (!NO_LAST) {
  448. protos("unknown", "/**< Unknown headers */", -3);
  449. protos("error", "/**< Erroneous headers */", -4);
  450. protos("separator", "/**< Separator line between headers and body */", -5);
  451. protos("payload", "/**< Message payload */", -6);
  452. if (multipart)
  453. protos("multipart", "/**< Multipart payload */", -7);
  454. }
  455. if (PR) {
  456. process_footer(footer);
  457. }
  458. else if (PT) {
  459. if (FLAGFILE)
  460. read_header_flags(FLAGFILE);
  461. if (TEMPLATE == "") { TEMPLATE = PT ".in"; }
  462. RS0=RS; RS=" \n";
  463. getline theader < TEMPLATE;
  464. getline header < TEMPLATE;
  465. getline template < TEMPLATE;
  466. getline footer < TEMPLATE;
  467. RS=RS0;
  468. sub(/.*[\/]/, "", TEMPLATE);
  469. gsub(/#AUTO#/, auto, header);
  470. gsub(/#DATE#/, "@date Generated: " date, header);
  471. print header > PT;
  472. print "" > PT;
  473. print "#define msg_offsetof(s, f) ((unsigned short)offsetof(s ,f))" > PT;
  474. print "" > PT;
  475. if (MC_SHORT_SIZE) {
  476. printf("static msg_href_t const " \
  477. "%s_short_forms[MC_SHORT_SIZE] = \n{\n",
  478. module) > PT;
  479. for (i = 1; i <= MC_SHORT_SIZE; i = i + 1) {
  480. c = (i == MC_SHORT_SIZE) ? "" : ",";
  481. if (i in shorts) {
  482. n = shorts[i];
  483. flags = header_flags[n]; if (flags) flags = ",\n " flags;
  484. printf(" { /* %s */ %s_%s_class, msg_offsetof(%s_t, %s_%s)%s }%s\n",
  485. substr(lower_case, i, 1),
  486. tprefix, n, module, prefix, n, flags, c) \
  487. > PT;
  488. }
  489. else {
  490. printf(" { NULL }%s\n", c) \
  491. > PT;
  492. }
  493. }
  494. printf("};\n\n") > PT;
  495. }
  496. # printf("extern msg_hclass_t msg_multipart_class[];\n\n") > PT;
  497. if (basic == 0) basic = total;
  498. if (without_experimental == 0) without_experimental = total;
  499. split("", header_hash);
  500. split("", index_hash);
  501. for (i = 0; i < basic; i++) {
  502. n = headers[i];
  503. h = hashed[n];
  504. if (h < 0)
  505. continue;
  506. j = h % MC_HASH_SIZE; if (j == -0) j = 0;
  507. for (; j in header_hash;) {
  508. if (++j == MC_HASH_SIZE) {
  509. j = 0;
  510. }
  511. }
  512. header_hash[j] = n;
  513. index_hash[j] = i;
  514. }
  515. m = module "_mclass";
  516. s = "_d_" module "_t";
  517. # Add basic headers
  518. if (ordinary == basic) {
  519. print_parser_table(s, "", m, basic, basic);
  520. }
  521. else if (basic < without_experimental) {
  522. print_parser_table(s, "", m, basic, basic);
  523. }
  524. else {
  525. print_parser_table(s, "", m, without_experimental, basic);
  526. }
  527. if (0) {
  528. # Hash extra headers
  529. for (i = basic; i < total; i++) {
  530. n = headers[i];
  531. h = hashed[n];
  532. if (h < 0)
  533. continue;
  534. j = h % MC_HASH_SIZE; if (j == -0) j = 0;
  535. for (; j in header_hash;) {
  536. if (++j == MC_HASH_SIZE) {
  537. j = 0;
  538. }
  539. }
  540. header_hash[j] = n;
  541. index_hash[j] = i;
  542. }
  543. if (basic < total) {
  544. m = module "_ext_mclass";
  545. s = "_e_" module "_s";
  546. print_parser_table(s, "static", m, without_experimental, total);
  547. }
  548. printf("msg_mclass_t const * %s_extended_mclass = %s;\n\n", module, m) > PT;
  549. }
  550. if (basic < total) {
  551. printf("msg_hclass_t * const %s_extensions[] = {\n", module) > PT;
  552. for (i = basic; i < total; i++) {
  553. if (i == without_experimental) {
  554. print "#if SU_HAVE_EXPERIMENTAL" > PT;
  555. }
  556. printf(" %s_%s_class,\n", module, headers[i]) > PT;
  557. }
  558. if (total != without_experimental)
  559. print "#endif" > PT;
  560. print " NULL\n};\n\n" > PT;
  561. }
  562. }
  563. exit success;
  564. }