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 if (singleton)
329 printh("\tstatic kobjop_t _m;");
330 else
331 printh("\tkobjop_t _m;");
332 if (ret != "void")
333 printh("\t" ret " rc;");
334 if (!static)
335 firstvar = "((kobj_t)" firstvar ")";
336 if (prolog != "")
337 printh(prolog);
338 if (singleton)
339 printh("\tif (_m == NULL)");
340 printh("\tKOBJOPLOOKUP(" firstvar "->ops," mname ");");
341 rceq = (ret != "void") ? "rc = " : "";
342 printh("\t" rceq "((" mname "_t *) _m)(" varname_list ");");
343 if (epilog != "")
344 printh(epilog);
345 if (ret != "void")
346 printh("\treturn (rc);");
347 printh("}\n");
348 }
349
350 #
351 # Begin of the main program.
352 #
353
354 BEGIN {
355
356 line_width = 80;
357 gerror = 0;
358
359 #
360 # Process the command line.
361 #
362
363 num_files = 0;
364
365 for (i = 1; i < ARGC; i++) {
366 if (ARGV[i] ~ /^-/) {
367 #
368 # awk doesn't have getopt(), so we have to do it ourselves.
369 # This is a bit clumsy, but it works.
370 #
371 for (j = 2; j <= length(ARGV[i]); j++) {
372 o = substr(ARGV[i], j, 1);
373 if (o == "c") opt_c = 1;
374 else if (o == "h") opt_h = 1;
375 else if (o == "p") opt_p = 1;
376 else if (o == "d") opt_d = 1;
377 else if (o == "l") {
378 if (length(ARGV[i]) > j) {
379 opt_l = substr(ARGV[i], j + 1);
380 break;
381 }
382 else {
383 if (++i < ARGC)
384 opt_l = ARGV[i];
385 else
386 usage();
387 }
388 }
389 else
390 usage();
391 }
392 }
393 else if (ARGV[i] ~ /\.m$/)
394 filenames[num_files++] = ARGV[i];
395 else
396 usage();
397 }
398
399 if (!num_files || !(opt_c || opt_h))
400 usage();
401
402 if (opt_p)
403 debug("Will produce files in original not in current directory");
404
405 if (opt_l) {
406 if (opt_l !~ /^[0-9]+$/ || opt_l < 1)
407 die("Invalid line width '" opt_l "'");
408 line_width = opt_l;
409 debug("Line width set to " line_width);
410 }
411
412 for (i = 0; i < num_files; i++)
413 debug("Filename: " filenames[i]);
414
415 for (file_i = 0; file_i < num_files; file_i++) {
416 src = filenames[file_i];
417 cfilename = hfilename = src;
418 sub(/\.m$/, ".c", cfilename);
419 sub(/\.m$/, ".h", hfilename);
420 if (!opt_p) {
421 sub(/^.*\//, "", cfilename);
422 sub(/^.*\//, "", hfilename);
423 }
424
425 debug("Processing from " src " to " cfilename " / " hfilename);
426
427 ctmpfilename = cfilename ".tmp";
428 htmpfilename = hfilename ".tmp";
429
430 # Avoid a literal generated file tag here.
431 generated = "@" "generated";
432
433 common_head = \
434 "/*\n" \
435 " * This file is " generated " automatically.\n" \
436 " * Do not modify anything in here by hand.\n" \
437 " *\n" \
438 " * Created from source file\n" \
439 " * " src "\n" \
440 " * with\n" \
441 " * makeobjops.awk\n" \
442 " *\n" \
443 " * See the source file for legal information\n" \
444 " */\n";
445
446 printc(common_head "\n" \
447 "#include <sys/param.h>\n" \
448 "#include <sys/queue.h>\n" \
449 "#include <sys/kernel.h>\n" \
450 "#include <sys/kobj.h>");
451
452 printh(common_head);
453
454 delete methods; # clear list of methods
455 intname = "";
456 lineno = 0;
457 error = 0; # to signal clean up and gerror setting
458 lastdoc = "";
459 prolog = "";
460 epilog = "";
461 singleton = 0;
462
463 while (!error && (getline < src) > 0) {
464 lineno++;
465
466 #
467 # Take special notice of include directives.
468 #
469 if (/^#[ ]*include[ ]+["<][^">]+[">]/) {
470 incld = $0;
471 sub(/^#[ ]*include[ ]+/, "", incld);
472 debug("Included file: " incld);
473 printc("#include " incld);
474 }
475
476 sub(/#.*/, ""); # remove comments
477 sub(/^[ ]+/, ""); # remove leading ...
478 sub(/[ ]+$/, ""); # ... and trailing whitespace
479
480 if (/^$/) { # skip empty lines
481 }
482 else if (/^\/\*\*/)
483 lastdoc = handle_doc();
484 else if (/^INTERFACE[ ]+[^ ;]*[ ]*;?[ ]*$/) {
485 printh(lastdoc);
486 lastdoc = "";
487 handle_interface();
488 } else if (/^CODE[ ]*{$/)
489 printc(handle_code());
490 else if (/^HEADER[ ]*{$/)
491 printh(handle_code());
492 else if (/^METHOD/) {
493 handle_method(0, lastdoc);
494 lastdoc = "";
495 prolog = "";
496 epilog = "";
497 } else if (/^STATICMETHOD/) {
498 handle_method(1, lastdoc);
499 lastdoc = "";
500 prolog = "";
501 epilog = "";
502 } else if (/^PROLOG[ ]*{$/)
503 prolog = handle_code();
504 else if (/^EPILOG[ ]*{$/)
505 epilog = handle_code();
506 else if (/^SINGLETON/)
507 singleton = 1;
508 else {
509 debug($0);
510 warnsrc("Invalid line encountered");
511 error = 1;
512 }
513 }
514
515 #
516 # Print the final '#endif' in the header file.
517 #
518 printh("#endif /* _" intname "_if_h_ */");
519
520 close (ctmpfilename);
521 close (htmpfilename);
522
523 if (error) {
524 warn("Output skipped");
525 system_check("rm -f " ctmpfilename " " htmpfilename);
526 gerror = 1;
527 }
528 else {
529 if (opt_c)
530 system_check("mv -f " ctmpfilename " " cfilename);
531 if (opt_h)
532 system_check("mv -f " htmpfilename " " hfilename);
533 }
534 }
535
536 exit gerror;
537
538 }
Cache object: 3e209326d3e24d597ac56119e3d2fce0
|