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

Cache object: 7831d6bc5f39cb42b901f148c65ccd80


[ 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.