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

Cache object: 4ce09d1a4c3852b7e615ee555c9ce6ab


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