/libsofia-sip-ua/msg/msg_parser.awk
AWK | 660 lines | 503 code | 96 blank | 61 comment | 0 complexity | f1dbd060c71be3443e68c2c95640951d MD5 | raw file
Possible License(s): LGPL-2.1
- #! /usr/bin/env awk
- #
- # This script recreates C files containing header-specific boilerplate stuff
- # using the given list of headers (usually obtained from the master structure).
- #
- # It can also create a parser table.
- #
- # --------------------------------------------------------------------
- #
- # This file is part of the Sofia-SIP package
- #
- # Copyright (C) 2005 Nokia Corporation.
- #
- # Contact: Pekka Pessi <pekka.pessi@nokia.com>
- #
- # This library is free software; you can redistribute it and/or
- # modify it under the terms of the GNU Lesser General Public License
- # as published by the Free Software Foundation; either version 2.1 of
- # the License, or (at your option) any later version.
- #
- # This library is distributed in the hope that it will be useful, but
- # WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- # Lesser General Public License for more details.
- #
- # You should have received a copy of the GNU Lesser General Public
- # License along with this library; if not, write to the Free Software
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- # 02110-1301 USA
- #
- # --------------------------------------------------------------------
- #
- # Contributor(s): Pekka.Pessi@nokia.com.
- #
- # Created: Fri Apr 6 12:59:59 2001 ppessi
- #
- BEGIN {
- "date '+%a %b %e %H:%M:%S %Y'" | getline date;
- ascii = \
- " " \
- " !\"#$%&'()*+,-./0123456789:;<=>?" \
- "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" \
- "`abcdefghijklmnopqrstuvwxyz{|}~";
- lower_case = "abcdefghijklmnopqrstuvwxyz";
- N=0;
- # Initialize these as arrays
- split("", symbols);
- split("", names);
- split("", comments);
- split("", hashes);
- split("", NAMES);
- split("", Comments);
- split("", COMMENTS);
- # indexed by the C name of the header
- split("", Since); # Non-NUL if extra
- split("", Extra); # Offset in extra headers
- total = 0;
- ordinary = 0;
- basic = 0;
- extra = 0;
- without_experimental = 0;
- template="";
- template1="";
- template2="";
- template3="";
- prefix="";
- tprefix="";
- failed=0;
- success=0;
- ERRNO="error";
- }
- function name_hash (name)
- {
- hash = 0;
- len = length(name);
- for (i = 1; i <= len; i++) {
- c = tolower(substr(name, i, 1));
- hash = (38501 * (hash + index(ascii, c))) % 65536;
- }
- if (hash == 0) {
- print "*** msg_parser.awk: calculating hash failed\n";
- exit(5);
- }
- if (0) {
- # Test that hash algorithm above agrees with the C version
- pipe = ("../msg/msg_name_hash " name);
- pipe | getline;
- close(pipe);
- if (hash != $0) {
- print name ": " hash " != " $0 > "/dev/stderr";
- }
- }
- return hash "";
- }
- #
- # Replace magic patterns in template p with header-specific values
- #
- function protos (name, comment, hash, since)
- {
- NAME=toupper(name);
- sub(/.*[\/][*][*][<][ ]*/, "", comment);
- sub(/[ ]*[*][\/].*/, "", comment);
- sub(/[ ]+/, " ", comment);
- short = match(comment, /[(][a-z][)]/);
- if (short) {
- short = substr(comment, short + 1, 1);
- sub(/ *[(][a-z][)]/, "", comment);
- shorts[index(lower_case, short)] = name;
- }
- do_hash = hash == 0;
- if (do_hash) {
- split(comment, parts, " ");
- name2 = tolower(parts[1]);
- gsub(/-/, "_", name2);
- if (name2 != name && name2 != tprefix "_" name) {
- print name " mismatch with " comment " (" real ")" > "/dev/stderr";
- }
- hash = name_hash(parts[1]);
- hashed[name] = hash;
- if (comment !~ /header/) {
- comment = comment " header";
- }
- }
- Comment = comment;
- if (!do_hash) {
- comment = tolower(comment);
- }
- COMMENT = toupper(comment);
- # Store the various forms into an array for the footer processing
- N++;
- hashes[N] = hash;
- names[N] = name;
- NAMES[N] = NAME;
- comments[N] = comment;
- Comments[N] = comment;
- COMMENTS[N] = COMMENT;
- symbols[name] = comment;
- if (since) {
- Since[name] = since;
- }
- expr = (without_experimental > 0 && do_hash);
- if (expr) {
- printf "%s is experimental\n", Comment;
- }
- experimental[N] = expr;
- if (PR) {
- if (expr) {
- print "#if SU_HAVE_EXPERIMENTAL" > PR;
- }
- replace(template, hash, name, NAME, comment, Comment, COMMENT, since);
- replace(template1, hash, name, NAME, comment, Comment, COMMENT, since);
- replace(template2, hash, name, NAME, comment, Comment, COMMENT, since);
- replace(template3, hash, name, NAME, comment, Comment, COMMENT, since);
- if (expr) {
- print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
- }
- }
- }
- function replace (p, hash, name, NAME, comment, Comment, COMMENT, since)
- {
- #
- # Replace various forms of header name in template, print it out
- #
- if (p) {
- gsub(/#hash#/, hash, p);
- gsub(/#xxxxxx#/, name, p);
- gsub(/#XXXXXX#/, NAME, p);
- gsub(/#xxxxxxx_xxxxxxx#/, comment, p);
- gsub(/#Xxxxxxx_Xxxxxxx#/, Comment, p);
- gsub(/#XXXXXXX_XXXXXXX#/, COMMENT, p);
- if (since) {
- gsub(/#version#/, since, p);
- }
- else {
- # Remove line with #version#
- gsub(/\n[^#\n]*#version#[^\n]*/, "", p);
- }
- print p > PR;
- }
- }
- #
- # Repeat each line in the footer containing the magic replacement
- # pattern with an instance of all headers
- #
- function process_footer (text)
- {
- if (!match(tolower(text), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) {
- n = length(text);
- while (substr(text, n) == "\n") {
- n = n - 1;
- text = substr(text, 1, n);
- }
- if (n > 0)
- print text > PR;
- return;
- }
- n = split(text, lines, RS);
- for (i = 1; i <= n; i++) {
- l = lines[i];
- if (match(tolower(l), /#(xxxxxx(x_xxxxxxx)?|hash)#/)) {
- expr = 0;
- for (j = 1; j <= N; j++) {
- l = lines[i];
- if (expr != experimental[j]) {
- expr = experimental[j];
- if (expr) {
- print "#if SU_HAVE_EXPERIMENTAL" > PR;
- }
- else {
- print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
- }
- }
- gsub(/#hash#/, hashes[j], l);
- gsub(/#xxxxxxx_xxxxxxx#/, comments[j], l);
- gsub(/#Xxxxxxx_Xxxxxxx#/, Comments[j], l);
- gsub(/#XXXXXXX_XXXXXXX#/, COMMENTS[j], l);
- gsub(/#xxxxxx#/, names[j], l);
- gsub(/#XXXXXX#/, NAMES[j], l);
- print l > PR;
- }
- if (expr) {
- print "#endif /* SU_HAVE_EXPERIMENTAL */" > PR;
- }
- } else {
- print l > PR;
- }
- }
- }
- #
- # Read flags used with headers
- #
- function read_header_flags (flagfile, line, tokens, name, value)
- {
- while ((getline line < flagfile) > 0) {
- sub(/^[ \t]+/, "", line);
- sub(/[ \t]+$/, "", line);
- if (line ~ /^#/ || line ~ /^$/)
- continue;
- split(line, tokens, /[ \t]*=[ \t]*/);
- name = tolower(tokens[1]);
- gsub(/-/, "_", name);
- gsub(/,/, " ", name);
- # print "FLAG: " name " = " tokens[2]
- if (header_flags[name]) {
- print flagfile ": already defined " tokens[1];
- }
- else if (!symbols[name]) {
- print flagfile ": unknown header \"" tokens[1] "\"";
- }
- else {
- header_flags[name] = tokens[2];
- }
- }
- close(flagfile);
- }
- #
- # Read in templates
- #
- function templates ()
- {
- if (!auto) {
- auto = FILENAME;
- if (!prefix) { prefix = module; }
- if (!tprefix) { tprefix = prefix; }
- sub(/.*\//, "", auto);
- auto = "This file is automatically generated from <" auto "> by msg_parser.awk.";
- if (PR) {
- if (TEMPLATE == "") { TEMPLATE = PR ".in"; }
- RS0=RS; RS="\f\n";
- if ((getline theader < TEMPLATE) < 0) {
- print ( TEMPLATE ": " ERRNO );
- failed=1;
- exit(1);
- }
- getline header < TEMPLATE;
- getline template < TEMPLATE;
- getline footer < TEMPLATE;
- if (TEMPLATE1) {
- if ((getline dummy < TEMPLATE1) < 0) {
- print(TEMPLATE1 ": " ERRNO);
- failed=1;
- exit(1);
- }
- getline dummy < TEMPLATE1;
- getline template1 < TEMPLATE1;
- getline dummy < TEMPLATE1;
- }
- if (TEMPLATE2) {
- if ((getline dummy < TEMPLATE2) < 0) {
- print( TEMPLATE2 ": " ERRNO );
- failed=1;
- exit(1);
- }
- getline dummy < TEMPLATE2;
- getline template2 < TEMPLATE2;
- getline dummy < TEMPLATE2;
- }
- if (TEMPLATE3) {
- if ((getline dummy < TEMPLATE3) < 0) {
- print( TEMPLATE3 ": " ERRNO );
- failed=1;
- exit(1);
- }
- getline dummy < TEMPLATE3;
- getline template3 < TEMPLATE3;
- getline dummy < TEMPLATE3;
- }
- sub(/.*[\/]/, "", TEMPLATE);
- gsub(/#AUTO#/, auto, header);
- gsub(/#DATE#/, "@date Generated: " date, header);
- if (PACKAGE_NAME) gsub(/#PACKAGE_NAME#/, PACKAGE_NAME, header);
- if (PACKAGE_VERSION) gsub(/#PACKAGE_VERSION#/, PACKAGE_VERSION, header);
- print header > PR;
- RS=RS0;
- }
- if (!NO_FIRST) {
- protos("request", "/**< Request line */", -1);
- protos("status", "/**< Status line */", -2);
- }
- }
- }
- /^#### EXTRA HEADER LIST STARTS HERE ####$/ { HLIST=1; templates(); }
- HLIST && /^#### DEFAULT HEADER LIST ENDS HERE ####$/ { basic=total; }
- HLIST && /^#### EXPERIMENTAL HEADER LIST STARTS HERE ####$/ {
- without_experimental = total; }
- HLIST && /^[a-z]/ { protos($1, $0, 0, $2);
- headers[total++] = $1;
- Extra[$1] = extra++;
- }
- /^#### EXTRA HEADER LIST ENDS HERE ####$/ { HLIST=0; }
- /^ *\/\* === Headers start here \*\// { in_header_list=1; templates(); }
- /^ *\/\* === Headers end here \*\// { in_header_list=0; }
- PT && /^ *\/\* === Hash headers end here \*\// { in_header_list=0;}
- in_header_list && /^ (sip|rtsp|http|msg|mp)_[a-z_0-9]+_t/ {
- n=$0
- sub(/;.*$/, "", n);
- sub(/^ *(sip|rtsp|http|msg|mp)_[a-z0-9_]*_t[ ]*/, "", n);
- sub(/^[*](sip|rtsp|http|msg|mp)_/, "", n);
- if ($0 !~ /[\/][*][*][<]/) {
- getline;
- }
- if ($0 !~ /[\/][*][*][<]/) {
- printf "msg_protos.awk: header %s is malformed\n", n;
- failed=1;
- exit 1;
- }
- if (!NO_MIDDLE)
- protos(n, $0, 0);
- headers[total] = n; total++; ordinary++;
- }
- function print_parser_table(struct, scope, name, N, N_EXPERIMENTAL)
- {
- if (PT) {
- if (N > ordinary) {
- printf("/* Ordinary %u, extra %u, experimental %u */\n",
- ordinary, N - ordinary, N_EXPERIMENTAL - N) > PT;
- printf("struct %s {\n", struct) > PT;
- printf(" %s_t base;\n", module) > PT;
- printf(" msg_header_t *extra[%u];\n", N - ordinary) > PT;
- if (N != N_EXPERIMENTAL) {
- print "#if SU_HAVE_EXPERIMENTAL" > PT;
- printf(" msg_header_t *extra[%u];\n", N_EXPERIMENTAL - N) > PT;
- print "#endif" > PT;
- }
- printf("};\n\n") > PT;
- }
- printf("%s\n", scope) > PT;
- printf("msg_mclass_t const %s[1] = \n{{\n", name) > PT;
- printf("# if defined (%s_HCLASS)\n", toupper(module)) > PT;
- printf(" %s_HCLASS,\n", toupper(module)) > PT;
- printf("#else\n") > PT;
- printf(" {{ 0 }},\n") > PT;
- printf("#endif\n") > PT;
- printf(" %s_VERSION_CURRENT,\n", toupper(module)) > PT;
- printf(" %s_PROTOCOL_TAG,\n", toupper(module)) > PT;
- printf("#if defined (%s_PARSER_FLAGS)\n", toupper(module)) > PT;
- printf(" %s_PARSER_FLAGS,\n", toupper(module)) > PT;
- printf("#else\n") > PT;
- printf(" 0,\n") > PT;
- printf("#endif\n") > PT;
- if (N > ordinary) {
- printf(" sizeof (struct %s),\n", struct) > PT;
- }
- else {
- printf(" sizeof (%s_t),\n", module) > PT;
- }
- printf(" %s_extract_body,\n", module) > PT;
- len = split("request status separator payload unknown error", unnamed, " ");
- for (i = 1; i <= len; i++) {
- printf(" {{ %s_%s_class, msg_offsetof(%s_t, %s_%s) }},\n",
- tprefix, unnamed[i], module, prefix, unnamed[i]) > PT;
- }
- if (multipart) {
- printf(" {{ %s_class, msg_offsetof(%s_t, %s_multipart) }},\n",
- multipart, module, prefix) > PT;
- } else {
- printf(" {{ NULL, 0 }},\n") > PT;
- }
- if (MC_SHORT_SIZE) {
- printf(" %s_short_forms, \n", module) > PT;
- }
- else {
- printf(" NULL, \n") > PT;
- }
- printf(" %d, \n", MC_HASH_SIZE) > PT;
- if (N != N_EXPERIMENTAL) {
- print "#if SU_HAVE_EXPERIMENTAL" > PT;
- printf(" %d,\n", N_EXPERIMENTAL) > PT;
- print "#else" > PT;
- }
- printf(" %d,\n", N) > PT;
- if (N != N_EXPERIMENTAL) {
- print "#endif" > PT;
- }
- printf(" {\n") > PT;
- for (j = 0; j < MC_HASH_SIZE; j++) {
- c = (j + 1 == MC_HASH_SIZE) ? "" : ",";
- if (j in header_hash) {
- n = header_hash[j];
- i = index_hash[j];
- flags = header_flags[n]; if (flags) flags = ",\n " flags;
- if (i >= N) {
- print "#if SU_HAVE_EXPERIMENTAL" > PT;
- }
- if (i >= ordinary) {
- printf(" { %s_%s_class,\n" \
- " msg_offsetof(struct %s, extra[%u])%s }%s\n",
- tprefix, n, struct, Extra[n], flags, c) > PT;
- }
- else {
- printf(" { %s_%s_class, msg_offsetof(%s_t, %s_%s)%s }%s\n",
- tprefix, n, module, prefix, n, flags, c) > PT;
- }
- if (i >= N) {
- printf("#else\n { NULL, 0 }%s\n#endif\n", c) > PT;
- }
- }
- else {
- printf(" { NULL, 0 }%s\n", c) > PT;
- }
- }
- printf(" }\n}};\n\n") > PT;
- }
- }
- END {
- if (failed) { exit };
- if (!NO_LAST) {
- protos("unknown", "/**< Unknown headers */", -3);
- protos("error", "/**< Erroneous headers */", -4);
- protos("separator", "/**< Separator line between headers and body */", -5);
- protos("payload", "/**< Message payload */", -6);
- if (multipart)
- protos("multipart", "/**< Multipart payload */", -7);
- }
- if (PR) {
- process_footer(footer);
- }
- else if (PT) {
- if (FLAGFILE)
- read_header_flags(FLAGFILE);
- if (TEMPLATE == "") { TEMPLATE = PT ".in"; }
- RS0=RS; RS="\n";
- getline theader < TEMPLATE;
- getline header < TEMPLATE;
- getline template < TEMPLATE;
- getline footer < TEMPLATE;
- RS=RS0;
- sub(/.*[\/]/, "", TEMPLATE);
- gsub(/#AUTO#/, auto, header);
- gsub(/#DATE#/, "@date Generated: " date, header);
- print header > PT;
- print "" > PT;
- print "#define msg_offsetof(s, f) ((unsigned short)offsetof(s ,f))" > PT;
- print "" > PT;
- if (MC_SHORT_SIZE) {
- printf("static msg_href_t const " \
- "%s_short_forms[MC_SHORT_SIZE] = \n{\n",
- module) > PT;
- for (i = 1; i <= MC_SHORT_SIZE; i = i + 1) {
- c = (i == MC_SHORT_SIZE) ? "" : ",";
- if (i in shorts) {
- n = shorts[i];
- flags = header_flags[n]; if (flags) flags = ",\n " flags;
- printf(" { /* %s */ %s_%s_class, msg_offsetof(%s_t, %s_%s)%s }%s\n",
- substr(lower_case, i, 1),
- tprefix, n, module, prefix, n, flags, c) \
- > PT;
- }
- else {
- printf(" { NULL }%s\n", c) \
- > PT;
- }
- }
- printf("};\n\n") > PT;
- }
- # printf("extern msg_hclass_t msg_multipart_class[];\n\n") > PT;
- if (basic == 0) basic = total;
- if (without_experimental == 0) without_experimental = total;
- split("", header_hash);
- split("", index_hash);
- for (i = 0; i < basic; i++) {
- n = headers[i];
- h = hashed[n];
- if (h < 0)
- continue;
- j = h % MC_HASH_SIZE; if (j == -0) j = 0;
- for (; j in header_hash;) {
- if (++j == MC_HASH_SIZE) {
- j = 0;
- }
- }
- header_hash[j] = n;
- index_hash[j] = i;
- }
- m = module "_mclass";
- s = "_d_" module "_t";
- # Add basic headers
- if (ordinary == basic) {
- print_parser_table(s, "", m, basic, basic);
- }
- else if (basic < without_experimental) {
- print_parser_table(s, "", m, basic, basic);
- }
- else {
- print_parser_table(s, "", m, without_experimental, basic);
- }
- if (0) {
- # Hash extra headers
- for (i = basic; i < total; i++) {
- n = headers[i];
- h = hashed[n];
- if (h < 0)
- continue;
- j = h % MC_HASH_SIZE; if (j == -0) j = 0;
- for (; j in header_hash;) {
- if (++j == MC_HASH_SIZE) {
- j = 0;
- }
- }
- header_hash[j] = n;
- index_hash[j] = i;
- }
- if (basic < total) {
- m = module "_ext_mclass";
- s = "_e_" module "_s";
- print_parser_table(s, "static", m, without_experimental, total);
- }
- printf("msg_mclass_t const * %s_extended_mclass = %s;\n\n", module, m) > PT;
- }
- if (basic < total) {
- printf("msg_hclass_t * const %s_extensions[] = {\n", module) > PT;
- for (i = basic; i < total; i++) {
- if (i == without_experimental) {
- print "#if SU_HAVE_EXPERIMENTAL" > PT;
- }
- printf(" %s_%s_class,\n", module, headers[i]) > PT;
- }
- if (total != without_experimental)
- print "#endif" > PT;
- print " NULL\n};\n\n" > PT;
- }
- }
- exit success;
- }