The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/tools/makeobjops.awk

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #!/usr/bin/awk -f
    2 
    3 #-
    4 # SPDX-License-Identifier: BSD-3-Clause
    5 #
    6 # Copyright (c) 1992, 1993
    7 #        The Regents of the University of California.  All rights reserved.
    8 #
    9 # Redistribution and use in source and binary forms, with or without
   10 # modification, are permitted provided that the following conditions
   11 # are met:
   12 # 1. Redistributions of source code must retain the above copyright
   13 #    notice, this list of conditions and the following disclaimer.
   14 # 2. Redistributions in binary form must reproduce the above copyright
   15 #    notice, this list of conditions and the following disclaimer in the
   16 #    documentation and/or other materials provided with the distribution.
   17 # 3. Neither the name of the University nor the names of its contributors
   18 #    may be used to endorse or promote products derived from this software
   19 #    without specific prior written permission.
   20 #
   21 # THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   22 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   23 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   24 # ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   25 # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   26 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   27 # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   28 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   30 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   31 # SUCH DAMAGE.
   32 #
   33 # From @(#)vnode_if.sh        8.1 (Berkeley) 6/10/93
   34 # From @(#)makedevops.sh 1.1 1998/06/14 13:53:12 dfr Exp $
   35 # From @(#)makedevops.sh ?.? 1998/10/05
   36 # From src/sys/kern/makedevops.pl,v 1.12 1999/11/22 14:40:04 n_hibma Exp
   37 # From src/sys/kern/makeobjops.pl,v 1.8 2001/11/16 02:02:42 joe Exp
   38 #
   39 # $FreeBSD$
   40 
   41 #
   42 #   Script to produce kobj front-end sugar.
   43 #
   44 
   45 function usage ()
   46 {
   47         print "usage: makeobjops.awk <srcfile.m> [-d] [-p] [-l <nr>] [-c|-h]";
   48         print "where -c   produce only .c files";
   49         print "      -h   produce only .h files";
   50         print "      -p   use the path component in the source file for destination dir";
   51         print "      -l   set line width for output files [80]";
   52         print "      -d   switch on debugging";
   53         exit 1;
   54 }
   55 
   56 function warn (msg)
   57 {
   58         print "makeobjops.awk:", msg > "/dev/stderr";
   59 }
   60 
   61 function warnsrc (msg)
   62 {
   63         warn(src ":" lineno ": " msg);
   64 }
   65 
   66 function debug (msg)
   67 {
   68         if (opt_d)
   69                 warn(msg);
   70 }
   71 
   72 function die (msg)
   73 {
   74         warn(msg);
   75         exit 1;
   76 }
   77 
   78 #   These are just for convenience ...
   79 function printc(s) {if (opt_c) print s > ctmpfilename;}
   80 function printh(s) {if (opt_h) print s > htmpfilename;}
   81 
   82 #
   83 #   If a line exceeds maxlength, split it into multiple
   84 #   lines at commas.  Subsequent lines are indented by
   85 #   the specified number of spaces.
   86 #
   87 #   In other words:  Lines are split by replacing ", "
   88 #   by ",\n" plus indent spaces.
   89 #
   90 
   91 function format_line (line, maxlength, indent)
   92 {
   93         rline = "";
   94 
   95         while (length(line) > maxlength) {
   96                 #
   97                 #   Find the rightmost ", " so that the part
   98                 #   to the left of it is just within maxlength.
   99                 #   If there is none, give up and leave it as-is.
  100                 #
  101                 if (!match(substr(line, 1, maxlength + 1), /^.*, /))
  102                         break;
  103                 rline = rline substr(line, 1, RLENGTH - 1) "\n";
  104                 line = sprintf("%*s", indent, "") substr(line, RLENGTH + 1);
  105         }
  106         return rline line;
  107 }
  108 
  109 #
  110 #   Join an array into a string.
  111 #
  112 
  113 function join (separator, array, num)
  114 {
  115         _result = ""
  116         if (num) {
  117                 while (num > 1)
  118                         _result = separator array[num--] _result;
  119                 _result = array[1] _result;
  120         }
  121         return _result;
  122 }
  123 
  124 #
  125 #   Execute a system command and report if it failed.
  126 #
  127 
  128 function system_check (cmd)
  129 {
  130         if ((rc = system(cmd)))
  131                 warn(cmd " failed (" rc ")");
  132 }
  133 
  134 #
  135 #   Handle "INTERFACE" line.
  136 #
  137 
  138 function handle_interface ()
  139 {
  140         intname = $2;
  141         sub(/;$/, "", intname);
  142         if (intname !~ /^[a-z_][a-z0-9_]*$/) {
  143                 debug($0);
  144                 warnsrc("Invalid interface name '" intname "', use [a-z_][a-z0-9_]*");
  145                 error = 1;
  146                 return;
  147         }
  148         if (!/;[        ]*$/)
  149                 warnsrc("Semicolon missing at end of line, no problem");
  150 
  151         debug("Interface " intname);
  152 
  153         printh("#ifndef _" intname "_if_h_");
  154         printh("#define _" intname "_if_h_\n");
  155         printc("#include \"" intname "_if.h\"\n");
  156 }
  157 
  158 #
  159 # Pass doc comments through to the C file
  160 #
  161 function handle_doc ()
  162 {
  163         doc = ""
  164         while (!/\*\//) {
  165                 doc = doc $0 "\n";
  166                 getline < src;
  167                 lineno++;
  168         }
  169         doc = doc $0 "\n";
  170         return doc;
  171 }
  172 
  173 #
  174 #   Handle "CODE" and "HEADER" sections.
  175 #   Returns the code as-is.
  176 #
  177 
  178 function handle_code ()
  179 {
  180         code = "\n";
  181         getline < src;
  182         indent = $0;
  183         sub(/[^  ].*$/, "", indent);    # find the indent used
  184         while (!/^}/) {
  185                 sub("^" indent, "");    # remove the indent
  186                 code = code $0 "\n";
  187                 getline < src;
  188                 lineno++;;
  189         }
  190         return code;
  191 }
  192 
  193 #
  194 #   Handle "METHOD" and "STATICMETHOD" sections.
  195 #
  196 
  197 function handle_method (static, doc)
  198 {
  199         #
  200         #   Get the return type and function name and delete that from
  201         #   the line. What is left is the possibly first function argument
  202         #   if it is on the same line.
  203         #
  204         if (!intname) {
  205                 warnsrc("No interface name defined");
  206                 error = 1;
  207                 return;
  208         }
  209         sub(/^[^        ]+[     ]+/, "");
  210         ret = $0;
  211         sub(/[  ]*\{.*$/, "", ret);
  212         name = ret;
  213         sub(/^.*[       ]/, "", name);  # last element is name of method
  214         sub(/[  ]+[^    ]+$/, "", ret); # return type
  215         debug("Method: name=" name " return type=" ret);
  216 
  217         sub(/^[^\{]*\{[  ]*/, "");
  218 
  219         if (!name || !ret) {
  220                 debug($0);
  221                 warnsrc("Invalid method specification");
  222                 error = 1;
  223                 return;
  224         }
  225 
  226         if (name !~ /^[a-z_][a-z_0-9]*$/) {
  227                 warnsrc("Invalid method name '" name "', use [a-z_][a-z0-9_]*");
  228                 error = 1;
  229                 return;
  230         }
  231 
  232         if (methods[name]) {
  233                 warnsrc("Duplicate method name");
  234                 error = 1;
  235                 return;
  236         }
  237         methods[name] = name;
  238 
  239         line = $0;
  240         while (line !~ /\}/ && (getline < src) > 0) {
  241                 line = line " " $0;
  242                 lineno++
  243         }
  244 
  245         default_function = "";
  246         if (!match(line, /\};?/)) {
  247                 warnsrc("Premature end of file");
  248                 error = 1;
  249                 return;
  250         }
  251         extra = substr(line, RSTART + RLENGTH);
  252         if (extra ~ /[   ]*DEFAULT[     ]*[a-zA-Z_][a-zA-Z_0-9]*[       ]*;/) {
  253                 default_function = extra;
  254                 sub(/.*DEFAULT[  ]*/, "", default_function);
  255                 sub(/[;         ]+.*$/, "", default_function);
  256         }
  257         else if (extra && opt_d) {
  258                 #   Warn about garbage at end of line.
  259                 warnsrc("Ignored '" extra "'");
  260         }
  261         sub(/\};?.*$/, "", line);
  262 
  263         #
  264         #   Create a list of variables without the types prepended.
  265         #
  266         sub(/^[  ]+/, "", line);        # remove leading ...
  267         sub(/[  ]+$/, "", line);        # ... and trailing whitespace
  268         gsub(/[  ]+/, " ", line);       # remove double spaces
  269 
  270         num_arguments = split(line, arguments, / *; */) - 1;
  271         delete varnames;                # list of varnames
  272         num_varnames = 0;
  273         for (i = 1; i <= num_arguments; i++) {
  274                 if (!arguments[i])
  275                         continue;       # skip argument if argument is empty
  276                 num_ar = split(arguments[i], ar, /[*    ]+/);
  277                 if (num_ar < 2) {       # only 1 word in argument?
  278                         warnsrc("no type for '" arguments[i] "'");
  279                         error = 1;
  280                         return;
  281                 }
  282                 #   Last element is name of variable.
  283                 varnames[++num_varnames] = ar[num_ar];
  284         }
  285 
  286         argument_list = join(", ", arguments, num_arguments);
  287         varname_list = join(", ", varnames, num_varnames);
  288 
  289         if (opt_d) {
  290                 warn("Arguments: " argument_list);
  291                 warn("Varnames: " varname_list);
  292         }
  293 
  294         mname = intname "_" name;       # method name
  295         umname = toupper(mname);        # uppercase method name
  296 
  297         firstvar = varnames[1];
  298 
  299         if (default_function == "")
  300                 default_function = "kobj_error_method";
  301 
  302         # the method description 
  303         printh("/** @brief Unique descriptor for the " umname "() method */");
  304         printh("extern struct kobjop_desc " mname "_desc;");
  305         # the method typedef
  306         printh("/** @brief A function implementing the " umname "() method */");
  307         prototype = "typedef " ret " " mname "_t(";
  308         printh(format_line(prototype argument_list ");",
  309             line_width, length(prototype)));
  310 
  311         # Print out the method desc
  312         printc("struct kobjop_desc " mname "_desc = {");
  313         printc("\t0, { &" mname "_desc, (kobjop_t)" default_function " }");
  314         printc("};\n");
  315 
  316         # Print out the method itself
  317         printh(doc);
  318         if (0) {                # haven't chosen the format yet
  319                 printh("static __inline " ret " " umname "(" varname_list ")");
  320                 printh("\t" join(";\n\t", arguments, num_arguments) ";");
  321         }
  322         else {
  323                 prototype = "static __inline " ret " " umname "(";
  324                 printh(format_line(prototype argument_list ")",
  325                     line_width, length(prototype)));
  326         }
  327         printh("{");
  328         printh("\tkobjop_t _m;");
  329         if (ret != "void")
  330                 printh("\t" ret " rc;");
  331         if (!static)
  332                 firstvar = "((kobj_t)" firstvar ")";
  333         if (prolog != "")
  334                 printh(prolog);
  335         printh("\tKOBJOPLOOKUP(" firstvar "->ops," mname ");");
  336         rceq = (ret != "void") ? "rc = " : "";
  337         printh("\t" rceq "((" mname "_t *) _m)(" varname_list ");");
  338         if (epilog != "")
  339                 printh(epilog);
  340         if (ret != "void")
  341                 printh("\treturn (rc);");
  342         printh("}\n");
  343 }
  344 
  345 #
  346 #   Begin of the main program.
  347 #
  348 
  349 BEGIN {
  350 
  351 line_width = 80;
  352 gerror = 0;
  353 
  354 #
  355 #   Process the command line.
  356 #
  357 
  358 num_files = 0;
  359 
  360 for (i = 1; i < ARGC; i++) {
  361         if (ARGV[i] ~ /^-/) {
  362                 #
  363                 #   awk doesn't have getopt(), so we have to do it ourselves.
  364                 #   This is a bit clumsy, but it works.
  365                 #
  366                 for (j = 2; j <= length(ARGV[i]); j++) {
  367                         o = substr(ARGV[i], j, 1);
  368                         if      (o == "c")      opt_c = 1;
  369                         else if (o == "h")      opt_h = 1;
  370                         else if (o == "p")      opt_p = 1;
  371                         else if (o == "d")      opt_d = 1;
  372                         else if (o == "l") {
  373                                 if (length(ARGV[i]) > j) {
  374                                         opt_l = substr(ARGV[i], j + 1);
  375                                         break;
  376                                 }
  377                                 else {
  378                                         if (++i < ARGC)
  379                                                 opt_l = ARGV[i];
  380                                         else
  381                                                 usage();
  382                                 }
  383                         }
  384                         else
  385                                 usage();
  386                 }
  387         }
  388         else if (ARGV[i] ~ /\.m$/)
  389                 filenames[num_files++] = ARGV[i];
  390         else
  391                 usage();
  392 }
  393 
  394 if (!num_files || !(opt_c || opt_h))
  395         usage();
  396 
  397 if (opt_p)
  398         debug("Will produce files in original not in current directory");
  399 
  400 if (opt_l) {
  401         if (opt_l !~ /^[0-9]+$/ || opt_l < 1)
  402                 die("Invalid line width '" opt_l "'");
  403         line_width = opt_l;
  404         debug("Line width set to " line_width);
  405 }
  406 
  407 for (i = 0; i < num_files; i++)
  408         debug("Filename: " filenames[i]);
  409 
  410 for (file_i = 0; file_i < num_files; file_i++) {
  411         src = filenames[file_i];
  412         cfilename = hfilename = src;
  413         sub(/\.m$/, ".c", cfilename);
  414         sub(/\.m$/, ".h", hfilename);
  415         if (!opt_p) {
  416                 sub(/^.*\//, "", cfilename);
  417                 sub(/^.*\//, "", hfilename);
  418         }
  419 
  420         debug("Processing from " src " to " cfilename " / " hfilename);
  421 
  422         ctmpfilename = cfilename ".tmp";
  423         htmpfilename = hfilename ".tmp";
  424 
  425         # Avoid a literal generated file tag here.
  426         generated = "@" "generated";
  427 
  428         common_head = \
  429             "/*\n" \
  430             " * This file is " generated " automatically.\n" \
  431             " * Do not modify anything in here by hand.\n" \
  432             " *\n" \
  433             " * Created from source file\n" \
  434             " *   " src "\n" \
  435             " * with\n" \
  436             " *   makeobjops.awk\n" \
  437             " *\n" \
  438             " * See the source file for legal information\n" \
  439             " */\n";
  440 
  441         printc(common_head "\n" \
  442             "#include <sys/param.h>\n" \
  443             "#include <sys/queue.h>\n" \
  444             "#include <sys/kernel.h>\n" \
  445             "#include <sys/kobj.h>");
  446 
  447         printh(common_head);
  448 
  449         delete methods;         # clear list of methods
  450         intname = "";
  451         lineno = 0;
  452         error = 0;              # to signal clean up and gerror setting
  453         lastdoc = "";
  454         prolog = "";
  455         epilog = "";
  456 
  457         while (!error && (getline < src) > 0) {
  458                 lineno++;
  459 
  460                 #
  461                 #   Take special notice of include directives.
  462                 #
  463                 if (/^#[        ]*include[      ]+["<][^">]+[">]/) {
  464                         incld = $0;
  465                         sub(/^#[        ]*include[      ]+/, "", incld);
  466                         debug("Included file: " incld);
  467                         printc("#include " incld);
  468                 }
  469                 else if (/^#[   ]*if/ || /^#[   ]*else/ || /^#[   ]*elif/ ||
  470                     /^#[   ]*endif/) {
  471                         printh($0);
  472                         printc($0);
  473                 }
  474 
  475                 sub(/#.*/, "");         # remove comments
  476                 sub(/^[  ]+/, "");      # remove leading ...
  477                 sub(/[  ]+$/, "");      # ... and trailing whitespace
  478 
  479                 if (/^$/) {             # skip empty lines
  480                 }
  481                 else if (/^\/\*\*/)
  482                         lastdoc = handle_doc();
  483                 else if (/^INTERFACE[   ]+[^    ;]*[    ]*;?[   ]*$/) {
  484                         printh(lastdoc);
  485                         lastdoc = "";
  486                         handle_interface();
  487                 } else if (/^CODE[      ]*{$/)
  488                         printc(handle_code());
  489                 else if (/^HEADER[       ]*{$/)
  490                         printh(handle_code());
  491                 else if (/^METHOD/) {
  492                         handle_method(0, lastdoc);
  493                         lastdoc = "";
  494                         prolog = "";
  495                         epilog = "";
  496                 } else if (/^STATICMETHOD/) {
  497                         handle_method(1, lastdoc);
  498                         lastdoc = "";
  499                         prolog = "";
  500                         epilog = "";
  501                 } else if (/^PROLOG[    ]*{$/)
  502                         prolog = handle_code();
  503                 else if (/^EPILOG[      ]*{$/)
  504                         epilog = handle_code();
  505                 else {
  506                         debug($0);
  507                         warnsrc("Invalid line encountered");
  508                         error = 1;
  509                 }
  510         }
  511 
  512         #
  513         #   Print the final '#endif' in the header file.
  514         #
  515         printh("#endif /* _" intname "_if_h_ */");
  516 
  517         close (ctmpfilename);
  518         close (htmpfilename);
  519 
  520         if (error) {
  521                 warn("Output skipped");
  522                 system_check("rm -f " ctmpfilename " " htmpfilename);
  523                 gerror = 1;
  524         }
  525         else {
  526                 if (opt_c)
  527                         system_check("mv -f " ctmpfilename " " cfilename);
  528                 if (opt_h)
  529                         system_check("mv -f " htmpfilename " " hfilename);
  530         }
  531 }
  532 
  533 exit gerror;
  534 
  535 }

Cache object: f71d2b29edcbe35a351f9c4d3d8a9b57


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.