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 38BEGIN { 39 "date '+%a %b %e %H:%M:%S %Y'" | getline date; 40 41 ascii = \ 42 " " \ 43 " !\"#$%&'()*+,-./0123456789:;<=>?" \ 44 "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" \ 45 "`abcdefghijklmnopqrstuvwxyz{|}~"; 46 lower_case = "abcdefghijklmnopqrstuvwxyz"; 47 48 N=0; 49 # Initialize these as arrays 50 split("", symbols); 51 split("", names); 52 split("", comments); 53 split("", hashes); 54 split("", NAMES); 55 split("", Comments); 56 split("", COMMENTS); 57 58 # indexed by the C name of the header 59 split("", Since); # Non-NUL if extra 60 split("", Extra); # Offset in extra headers 61 62 total = 0; 63 ordinary = 0; 64 basic = 0; 65 extra = 0; 66 without_experimental = 0; 67 68 template=""; 69 template1=""; 70 template2=""; 71 template3=""; 72 prefix=""; 73 tprefix=""; 74 failed=0; 75 success=0; 76 77 ERRNO="error"; 78} 79 80function name_hash (name) 81{ 82 hash = 0; 83 84 len = length(name); 85 86 for (i = 1; i <= len; i++) { 87 c = tolower(substr(name, i, 1)); 88 hash = (38501 * (hash + index(ascii, c))) % 65536; 89 } 90 91 if (hash == 0) { 92 print "*** msg_parser.awk: calculating hash failed\n"; 93 exit(5); 94 } 95 96 if (0) { 97 # Test that hash algorithm above agrees with the C version 98 pipe = ("../msg/msg_name_hash " name); 99 pipe | getline; 100 close(pipe); 101 if (hash != $0) { 102 print name ": " hash " != " $0 > "/dev/stderr"; 103 } 104 } 105 106 return hash ""; 107} 108 109# 110# Replace magic patterns in template p with header-specific values 111# 112function protos (name, comment, hash, since) 113{ 114 NAME=toupper(name); 115 sub(/.*[\/][*][*][<][ ]*/, "", comment); 116 sub(/[ ]*[*][\/].*/, "", comment); 117 sub(/[ ]+/, " ", comment); 118 119 short = match(comment, /[(][a-z][)]/); 120 if (short) { 121 short = substr(comment, short + 1, 1); 122 sub(/ *[(][a-z][)]/, "", comment); 123 shorts[index(lower_case, short)] = name; 124 } 125 126 do_hash = hash == 0; 127 128 if (do_hash) { 129 split(comment, parts, " "); 130 name2 = tolower(parts[1]); 131 gsub(/-/, "_", name2); 132 if (name2 != name && name2 != tprefix "_" name) { 133 print name " mismatch with " comment " (" real ")" > "/dev/stderr"; 134 } 135 136 hash = name_hash(parts[1]); 137 138 hashed[name] = hash; 139 140 if (comment !~ /header/) { 141 comment = comment " header"; 142 } 143 } 144 145 Comment = comment; 146 if (!do_hash) { 147 comment = tolower(comment); 148 } 149 COMMENT = toupper(comment); 150 151 # Store the various forms into an array for the footer processing 152 N++; 153 hashes[N] = hash; 154 names[N] = name; 155 NAMES[N] = NAME; 156 comments[N] = comment; 157 Comments[N] = comment; 158 COMMENTS[N] = COMMENT; 159 160 symbols[name] = comment; 161 if (since) { 162 Since[name] = since; 163 } 164 165 expr = (without_experimental > 0 && do_hash); 166 if (expr) { 167 printf "%s is experimental\n", Comment; 168 } 169 170 experimental[N] = expr; 171 172 if (PR) { 173 if (expr) { 174 print "#if SU_HAVE_EXPERIMENTAL" > PR; 175 } 176 replace(template, hash, name, NAME, comment, Comment, COMMENT, since); 177 replace(template1, hash, name, NAME, comment, Comment, COMMENT, since); 178 replace(template2, hash, name, NAME, comment, Comment, COMMENT, since); 179 replace(template3, hash, name, NAME, comment, Comment, COMMENT, since); 180 if (expr) { 181 print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR; 182 } 183 } 184} 185 186function replace (p, hash, name, NAME, comment, Comment, COMMENT, since) 187{ 188 # 189 # Replace various forms of header name in template, print it out 190 # 191 if (p) { 192 gsub(/#hash#/, hash, p); 193 gsub(/#xxxxxx#/, name, p); 194 gsub(/#XXXXXX#/, NAME, p); 195 gsub(/#xxxxxxx_xxxxxxx#/, comment, p); 196 gsub(/#Xxxxxxx_Xxxxxxx#/, Comment, p); 197 gsub(/#XXXXXXX_XXXXXXX#/, COMMENT, p); 198 199 if (since) { 200 gsub(/#version#/, since, p); 201 } 202 else { 203 # Remove line with #version# 204 gsub(/\n[^#\n]*#version#[^\n]*/, "", p); 205 } 206 207 print p > PR; 208 } 209} 210 211# 212# Repeat each line in the footer containing the magic replacement 213# pattern with an instance of all headers 214# 215function process_footer (text) 216{ 217 if (!match(tolower(text), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) { 218 n = length(text); 219 while (substr(text, n) == "\n") { 220 n = n - 1; 221 text = substr(text, 1, n); 222 } 223 if (n > 0) 224 print text > PR; 225 return; 226 } 227 228 n = split(text, lines, RS); 229 230 for (i = 1; i <= n; i++) { 231 l = lines[i]; 232 if (match(tolower(l), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) { 233 expr = 0; 234 235 for (j = 1; j <= N; j++) { 236 l = lines[i]; 237 if (expr != experimental[j]) { 238 expr = experimental[j]; 239 if (expr) { 240 print "#if SU_HAVE_EXPERIMENTAL" > PR; 241 } 242 else { 243 print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR; 244 } 245 } 246 gsub(/#hash#/, hashes[j], l); 247 gsub(/#xxxxxxx_xxxxxxx#/, comments[j], l); 248 gsub(/#Xxxxxxx_Xxxxxxx#/, Comments[j], l); 249 gsub(/#XXXXXXX_XXXXXXX#/, COMMENTS[j], l); 250 gsub(/#xxxxxx#/, names[j], l); 251 gsub(/#XXXXXX#/, NAMES[j], l); 252 print l > PR; 253 } 254 255 if (expr) { 256 print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR; 257 } 258 } else { 259 print l > PR; 260 } 261 } 262} 263 264# 265# Read flags used with headers 266# 267function read_header_flags (flagfile, line, tokens, name, value) 268{ 269 while ((getline line < flagfile) > 0) { 270 sub(/^[ \t]+/, "", line); 271 sub(/[ \t]+$/, "", line); 272 if (line ~ /^#/ || line ~ /^$/) 273 continue; 274 275 split(line, tokens, /[ \t]*=[ \t]*/); 276 name = tolower(tokens[1]); 277 gsub(/-/, "_", name); 278 gsub(/,/, " ", name); 279 # print "FLAG: " name " = " tokens[2] 280 281 if (header_flags[name]) { 282 print flagfile ": already defined " tokens[1]; 283 } 284 else if (!symbols[name]) { 285 print flagfile ": unknown header \"" tokens[1] "\""; 286 } 287 else { 288 header_flags[name] = tokens[2]; 289 } 290 } 291 close(flagfile); 292} 293 294# 295# Read in templates 296# 297function templates () 298{ 299 if (!auto) { 300 auto = FILENAME; 301 302 if (!prefix) { prefix = module; } 303 if (!tprefix) { tprefix = prefix; } 304 305 sub(/.*\//, "", auto); 306 auto = "This file is automatically generated from <" auto "> by msg_parser.awk."; 307 308 if (PR) { 309 if (TEMPLATE == "") { TEMPLATE = PR ".in"; } 310 RS0=RS; RS="\f\n"; 311 if ((getline theader < TEMPLATE) < 0) { 312 print ( TEMPLATE ": " ERRNO ); 313 failed=1; 314 exit(1); 315 } 316 getline header < TEMPLATE; 317 getline template < TEMPLATE; 318 getline footer < TEMPLATE; 319 320 if (TEMPLATE1) { 321 if ((getline dummy < TEMPLATE1) < 0) { 322 print(TEMPLATE1 ": " ERRNO); 323 failed=1; 324 exit(1); 325 } 326 getline dummy < TEMPLATE1; 327 getline template1 < TEMPLATE1; 328 getline dummy < TEMPLATE1; 329 } 330 331 if (TEMPLATE2) { 332 if ((getline dummy < TEMPLATE2) < 0) { 333 print( TEMPLATE2 ": " ERRNO ); 334 failed=1; 335 exit(1); 336 } 337 getline dummy < TEMPLATE2; 338 getline template2 < TEMPLATE2; 339 getline dummy < TEMPLATE2; 340 } 341 342 if (TEMPLATE3) { 343 if ((getline dummy < TEMPLATE3) < 0) { 344 print( TEMPLATE3 ": " ERRNO ); 345 failed=1; 346 exit(1); 347 } 348 getline dummy < TEMPLATE3; 349 getline template3 < TEMPLATE3; 350 getline dummy < TEMPLATE3; 351 } 352 353 sub(/.*[\/]/, "", TEMPLATE); 354 gsub(/#AUTO#/, auto, header); 355 gsub(/#DATE#/, "@date Generated: " date, header); 356 if (PACKAGE_NAME) gsub(/#PACKAGE_NAME#/, PACKAGE_NAME, header); 357 if (PACKAGE_VERSION) gsub(/#PACKAGE_VERSION#/, PACKAGE_VERSION, header); 358 print header > PR; 359 360 RS=RS0; 361 } 362 363 if (!NO_FIRST) { 364 protos("request", "/**< Request line */", -1); 365 protos("status", "/**< Status line */", -2); 366 } 367 } 368} 369 370/^#### EXTRA HEADER LIST STARTS HERE ####$/ { HLIST=1; templates(); } 371HLIST && /^#### DEFAULT HEADER LIST ENDS HERE ####$/ { basic=total; } 372HLIST && /^#### EXPERIMENTAL HEADER LIST STARTS HERE ####$/ { 373 without_experimental = total; } 374 375HLIST && /^[a-z]/ { protos($1, $0, 0, $2); 376 headers[total++] = $1; 377 Extra[$1] = extra++; 378} 379/^#### EXTRA HEADER LIST ENDS HERE ####$/ { HLIST=0; } 380 381/^ *\/\* === Headers start here \*\// { in_header_list=1; templates(); } 382/^ *\/\* === Headers end here \*\// { in_header_list=0; } 383 384PT && /^ *\/\* === Hash headers end here \*\// { in_header_list=0;} 385 386in_header_list && /^ (sip|rtsp|http|msg|mp)_[a-z_0-9]+_t/ { 387 n=$0 388 sub(/;.*$/, "", n); 389 sub(/^ *(sip|rtsp|http|msg|mp)_[a-z0-9_]*_t[ ]*/, "", n); 390 sub(/^[*](sip|rtsp|http|msg|mp)_/, "", n); 391 392 if ($0 !~ /[\/][*][*][<]/) { 393 getline; 394 } 395 if ($0 !~ /[\/][*][*][<]/) { 396 printf "msg_protos.awk: header %s is malformed\n", n; 397 failed=1; 398 exit 1; 399 } 400 401 if (!NO_MIDDLE) 402 protos(n, $0, 0); 403 404 headers[total] = n; total++; ordinary++; 405} 406 407function print_parser_table(struct, scope, name, N, N_EXPERIMENTAL) 408{ 409 if (PT) { 410 if (N > ordinary) { 411 printf("/* Ordinary %u, extra %u, experimental %u */\n", 412 ordinary, N - ordinary, N_EXPERIMENTAL - N) > PT; 413 printf("struct %s {\n", struct) > PT; 414 printf(" %s_t base;\n", module) > PT; 415 printf(" msg_header_t *extra[%u];\n", N - ordinary) > PT; 416 if (N != N_EXPERIMENTAL) { 417 print "#if SU_HAVE_EXPERIMENTAL" > PT; 418 printf(" msg_header_t *extra[%u];\n", N_EXPERIMENTAL - N) > PT; 419 print "#endif" > PT; 420 } 421 printf("};\n\n") > PT; 422 } 423 424 printf("%s\n", scope) > PT; 425 printf("msg_mclass_t const %s[1] = \n{{\n", name) > PT; 426 printf("# if defined (%s_HCLASS)\n", toupper(module)) > PT; 427 printf(" %s_HCLASS,\n", toupper(module)) > PT; 428 printf("#else\n") > PT; 429 printf(" {{ 0 }},\n") > PT; 430 printf("#endif\n") > PT; 431 printf(" %s_VERSION_CURRENT,\n", toupper(module)) > PT; 432 printf(" %s_PROTOCOL_TAG,\n", toupper(module)) > PT; 433 printf("#if defined (%s_PARSER_FLAGS)\n", toupper(module)) > PT; 434 printf(" %s_PARSER_FLAGS,\n", toupper(module)) > PT; 435 printf("#else\n") > PT; 436 printf(" 0,\n") > PT; 437 printf("#endif\n") > PT; 438 if (N > ordinary) { 439 printf(" sizeof (struct %s),\n", struct) > PT; 440 } 441 else { 442 printf(" sizeof (%s_t),\n", module) > PT; 443 } 444 printf(" %s_extract_body,\n", module) > PT; 445 446 len = split("request status separator payload unknown error", unnamed, " "); 447 448 for (i = 1; i <= len; i++) { 449 printf(" {{ %s_%s_class, msg_offsetof(%s_t, %s_%s) }},\n", 450 tprefix, unnamed[i], module, prefix, unnamed[i]) > PT; 451 } 452 if (multipart) { 453 printf(" {{ %s_class, msg_offsetof(%s_t, %s_multipart) }},\n", 454 multipart, module, prefix) > PT; 455 } else { 456 printf(" {{ NULL, 0 }},\n") > PT; 457 } 458 if (MC_SHORT_SIZE) { 459 printf(" %s_short_forms, \n", module) > PT; 460 } 461 else { 462 printf(" NULL, \n") > PT; 463 } 464 printf(" %d, \n", MC_HASH_SIZE) > PT; 465 if (N != N_EXPERIMENTAL) { 466 print "#if SU_HAVE_EXPERIMENTAL" > PT; 467 printf(" %d,\n", N_EXPERIMENTAL) > PT; 468 print "#else" > PT; 469 } 470 printf(" %d,\n", N) > PT; 471 if (N != N_EXPERIMENTAL) { 472 print "#endif" > PT; 473 } 474 475 printf(" {\n") > PT; 476 477 for (j = 0; j < MC_HASH_SIZE; j++) { 478 c = (j + 1 == MC_HASH_SIZE) ? "" : ","; 479 if (j in header_hash) { 480 n = header_hash[j]; 481 i = index_hash[j]; 482 483 flags = header_flags[n]; if (flags) flags = ",\n " flags; 484 485 if (i >= N) { 486 print "#if SU_HAVE_EXPERIMENTAL" > PT; 487 } 488 489 if (i >= ordinary) { 490 printf(" { %s_%s_class,\n" \ 491 " msg_offsetof(struct %s, extra[%u])%s }%s\n", 492 tprefix, n, struct, Extra[n], flags, c) > PT; 493 } 494 else { 495 printf(" { %s_%s_class, msg_offsetof(%s_t, %s_%s)%s }%s\n", 496 tprefix, n, module, prefix, n, flags, c) > PT; 497 } 498 499 if (i >= N) { 500 printf("#else\n { NULL, 0 }%s\n#endif\n", c) > PT; 501 } 502 } 503 else { 504 printf(" { NULL, 0 }%s\n", c) > PT; 505 } 506 } 507 printf(" }\n}};\n\n") > PT; 508 509 } 510} 511 512END { 513 if (failed) { exit }; 514 515 if (!NO_LAST) { 516 protos("unknown", "/**< Unknown headers */", -3); 517 protos("error", "/**< Erroneous headers */", -4); 518 protos("separator", "/**< Separator line between headers and body */", -5); 519 protos("payload", "/**< Message payload */", -6); 520 if (multipart) 521 protos("multipart", "/**< Multipart payload */", -7); 522 } 523 524 if (PR) { 525 process_footer(footer); 526 } 527 else if (PT) { 528 if (FLAGFILE) 529 read_header_flags(FLAGFILE); 530 531 if (TEMPLATE == "") { TEMPLATE = PT ".in"; } 532 RS0=RS; RS="\n"; 533 getline theader < TEMPLATE; 534 getline header < TEMPLATE; 535 getline template < TEMPLATE; 536 getline footer < TEMPLATE; 537 RS=RS0; 538 539 sub(/.*[\/]/, "", TEMPLATE); 540 gsub(/#AUTO#/, auto, header); 541 gsub(/#DATE#/, "@date Generated: " date, header); 542 print header > PT; 543 544 print "" > PT; 545 print "#define msg_offsetof(s, f) ((unsigned short)offsetof(s ,f))" > PT; 546 print "" > PT; 547 548 if (MC_SHORT_SIZE) { 549 printf("static msg_href_t const " \ 550 "%s_short_forms[MC_SHORT_SIZE] = \n{\n", 551 module) > PT; 552 553 for (i = 1; i <= MC_SHORT_SIZE; i = i + 1) { 554 c = (i == MC_SHORT_SIZE) ? "" : ","; 555 if (i in shorts) { 556 n = shorts[i]; 557 flags = header_flags[n]; if (flags) flags = ",\n " flags; 558 559 printf(" { /* %s */ %s_%s_class, msg_offsetof(%s_t, %s_%s)%s }%s\n", 560 substr(lower_case, i, 1), 561 tprefix, n, module, prefix, n, flags, c) \ 562 > PT; 563 } 564 else { 565 printf(" { NULL }%s\n", c) \ 566 > PT; 567 } 568 } 569 printf("};\n\n") > PT; 570 } 571 572 # printf("extern msg_hclass_t msg_multipart_class[];\n\n") > PT; 573 574 if (basic == 0) basic = total; 575 if (without_experimental == 0) without_experimental = total; 576 577 split("", header_hash); 578 split("", index_hash); 579 580 for (i = 0; i < basic; i++) { 581 n = headers[i]; 582 h = hashed[n]; 583 584 if (h < 0) 585 continue; 586 587 j = h % MC_HASH_SIZE; if (j == -0) j = 0; 588 589 for (; j in header_hash;) { 590 if (++j == MC_HASH_SIZE) { 591 j = 0; 592 } 593 } 594 595 header_hash[j] = n; 596 index_hash[j] = i; 597 } 598 599 m = module "_mclass"; 600 s = "_d_" module "_t"; 601 602 # Add basic headers 603 if (ordinary == basic) { 604 print_parser_table(s, "", m, basic, basic); 605 } 606 else if (basic < without_experimental) { 607 print_parser_table(s, "", m, basic, basic); 608 } 609 else { 610 print_parser_table(s, "", m, without_experimental, basic); 611 } 612 613 if (0) { 614 615 # Hash extra headers 616 for (i = basic; i < total; i++) { 617 n = headers[i]; 618 h = hashed[n]; 619 620 if (h < 0) 621 continue; 622 623 j = h % MC_HASH_SIZE; if (j == -0) j = 0; 624 625 for (; j in header_hash;) { 626 if (++j == MC_HASH_SIZE) { 627 j = 0; 628 } 629 } 630 631 header_hash[j] = n; 632 index_hash[j] = i; 633 } 634 635 if (basic < total) { 636 m = module "_ext_mclass"; 637 s = "_e_" module "_s"; 638 print_parser_table(s, "static", m, without_experimental, total); 639 } 640 641 printf("msg_mclass_t const * %s_extended_mclass = %s;\n\n", module, m) > PT; 642 643 } 644 645 if (basic < total) { 646 printf("msg_hclass_t * const %s_extensions[] = {\n", module) > PT; 647 for (i = basic; i < total; i++) { 648 if (i == without_experimental) { 649 print "#if SU_HAVE_EXPERIMENTAL" > PT; 650 } 651 printf(" %s_%s_class,\n", module, headers[i]) > PT; 652 } 653 if (total != without_experimental) 654 print "#endif" > PT; 655 print " NULL\n};\n\n" > PT; 656 } 657 } 658 659 exit success; 660} 661