195841Sobrien#!/usr/bin/awk -f
2139825Simp
3139825Simp#-
495841Sobrien# Copyright (c) 1992, 1993
595841Sobrien#        The Regents of the University of California.  All rights reserved.
695841Sobrien#
795841Sobrien# Redistribution and use in source and binary forms, with or without
895841Sobrien# modification, are permitted provided that the following conditions
995841Sobrien# are met:
1095841Sobrien# 1. Redistributions of source code must retain the above copyright
1195841Sobrien#    notice, this list of conditions and the following disclaimer.
1295841Sobrien# 2. Redistributions in binary form must reproduce the above copyright
1395841Sobrien#    notice, this list of conditions and the following disclaimer in the
1495841Sobrien#    documentation and/or other materials provided with the distribution.
1595841Sobrien# 4. Neither the name of the University nor the names of its contributors
1695841Sobrien#    may be used to endorse or promote products derived from this software
1795841Sobrien#    without specific prior written permission.
1895841Sobrien#
1995841Sobrien# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2095841Sobrien# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2195841Sobrien# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2295841Sobrien# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2395841Sobrien# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2495841Sobrien# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2595841Sobrien# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2695841Sobrien# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2795841Sobrien# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2895841Sobrien# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2995841Sobrien# SUCH DAMAGE.
3095841Sobrien#
3195841Sobrien# From @(#)vnode_if.sh        8.1 (Berkeley) 6/10/93
3295841Sobrien# From @(#)makedevops.sh 1.1 1998/06/14 13:53:12 dfr Exp $
3395841Sobrien# From @(#)makedevops.sh ?.? 1998/10/05
3495841Sobrien# From src/sys/kern/makedevops.pl,v 1.12 1999/11/22 14:40:04 n_hibma Exp
3595841Sobrien# From src/sys/kern/makeobjops.pl,v 1.8 2001/11/16 02:02:42 joe Exp
3695841Sobrien#
3795841Sobrien# $FreeBSD$
3895841Sobrien
3995841Sobrien#
4095841Sobrien#   Script to produce kobj front-end sugar.
4195841Sobrien#
4295841Sobrien
4395841Sobrienfunction usage ()
4495841Sobrien{
4595841Sobrien	print "usage: makeobjops.awk <srcfile.m> [-d] [-p] [-l <nr>] [-c|-h]";
4695841Sobrien	print "where -c   produce only .c files";
4795841Sobrien	print "      -h   produce only .h files";
4895841Sobrien	print "      -p   use the path component in the source file for destination dir";
4995841Sobrien	print "      -l   set line width for output files [80]";
5095841Sobrien	print "      -d   switch on debugging";
5195841Sobrien	exit 1;
5295841Sobrien}
5395841Sobrien
5495841Sobrienfunction warn (msg)
5595841Sobrien{
5695841Sobrien	print "makeobjops.awk:", msg > "/dev/stderr";
5795841Sobrien}
5895841Sobrien
5995841Sobrienfunction warnsrc (msg)
6095841Sobrien{
6195841Sobrien	warn(src ":" lineno ": " msg);
6295841Sobrien}
6395841Sobrien
6495841Sobrienfunction debug (msg)
6595841Sobrien{
6695841Sobrien	if (opt_d)
6795841Sobrien		warn(msg);
6895841Sobrien}
6995841Sobrien
7095841Sobrienfunction die (msg)
7195841Sobrien{
7295841Sobrien	warn(msg);
7395841Sobrien	exit 1;
7495841Sobrien}
7595841Sobrien
7695841Sobrien#   These are just for convenience ...
7795841Sobrienfunction printc(s) {if (opt_c) print s > ctmpfilename;}
7895841Sobrienfunction printh(s) {if (opt_h) print s > htmpfilename;}
7995841Sobrien
8095841Sobrien#
8195841Sobrien#   If a line exceeds maxlength, split it into multiple
8295841Sobrien#   lines at commas.  Subsequent lines are indented by
8395841Sobrien#   the specified number of spaces.
8495841Sobrien#
8595841Sobrien#   In other words:  Lines are split by replacing ", "
8695841Sobrien#   by ",\n" plus indent spaces.
8795841Sobrien#
8895841Sobrien
8995841Sobrienfunction format_line (line, maxlength, indent)
9095841Sobrien{
9195841Sobrien	rline = "";
9295841Sobrien
9395841Sobrien	while (length(line) > maxlength) {
9495841Sobrien		#
9595841Sobrien		#   Find the rightmost ", " so that the part
9695841Sobrien		#   to the left of it is just within maxlength.
9795841Sobrien		#   If there is none, give up and leave it as-is.
9895841Sobrien		#
9995841Sobrien		if (!match(substr(line, 1, maxlength + 1), /^.*, /))
10095841Sobrien			break;
10195841Sobrien		rline = rline substr(line, 1, RLENGTH - 1) "\n";
10295841Sobrien		line = sprintf("%*s", indent, "") substr(line, RLENGTH + 1);
10395841Sobrien	}
10495841Sobrien	return rline line;
10595841Sobrien}
10695841Sobrien
10795841Sobrien#
10895841Sobrien#   Join an array into a string.
10995841Sobrien#
11095841Sobrien
11195841Sobrienfunction join (separator, array, num)
11295841Sobrien{
11395841Sobrien	_result = ""
11495841Sobrien	if (num) {
11595841Sobrien		while (num > 1)
11695841Sobrien			_result = separator array[num--] _result;
11795841Sobrien		_result = array[1] _result;
11895841Sobrien	}
11995841Sobrien	return _result;
12095841Sobrien}
12195841Sobrien
12295841Sobrien#
12395841Sobrien#   Execute a system command and report if it failed.
12495841Sobrien#
12595841Sobrien
12695841Sobrienfunction system_check (cmd)
12795841Sobrien{
12895841Sobrien	if ((rc = system(cmd)))
12995841Sobrien		warn(cmd " failed (" rc ")");
13095841Sobrien}
13195841Sobrien
13295841Sobrien#
13395841Sobrien#   Handle "INTERFACE" line.
13495841Sobrien#
13595841Sobrien
13695841Sobrienfunction handle_interface ()
13795841Sobrien{
13895841Sobrien	intname = $2;
13995841Sobrien	sub(/;$/, "", intname);
14095841Sobrien	if (intname !~ /^[a-z_][a-z0-9_]*$/) {
14195841Sobrien		debug($0);
14295841Sobrien		warnsrc("Invalid interface name '" intname "', use [a-z_][a-z0-9_]*");
14395841Sobrien		error = 1;
14495841Sobrien		return;
14595841Sobrien	}
14695841Sobrien	if (!/;[ 	]*$/)
14795841Sobrien		warnsrc("Semicolon missing at end of line, no problem");
14895841Sobrien
14995841Sobrien	debug("Interface " intname);
15095841Sobrien
15195841Sobrien	printh("#ifndef _" intname "_if_h_");
15295841Sobrien	printh("#define _" intname "_if_h_\n");
15395841Sobrien	printc("#include \"" intname "_if.h\"\n");
15495841Sobrien}
15595841Sobrien
15695841Sobrien#
157131987Sdfr# Pass doc comments through to the C file
158131987Sdfr#
159131987Sdfrfunction handle_doc ()
160131987Sdfr{
161131987Sdfr	doc = ""
162131987Sdfr	while (!/\*\//) {
163131987Sdfr		doc = doc $0 "\n";
164131987Sdfr		getline < src;
165131987Sdfr		lineno++;
166131987Sdfr	}
167131987Sdfr	doc = doc $0 "\n";
168131987Sdfr	return doc;
169131987Sdfr}
170131987Sdfr
171131987Sdfr#
17295841Sobrien#   Handle "CODE" and "HEADER" sections.
17395841Sobrien#   Returns the code as-is.
17495841Sobrien#
17595841Sobrien
17695841Sobrienfunction handle_code ()
17795841Sobrien{
17895841Sobrien	code = "\n";
17995841Sobrien	getline < src;
18095841Sobrien	indent = $0;
18195841Sobrien	sub(/[^	 ].*$/, "", indent);	# find the indent used
18295841Sobrien	while (!/^}/) {
18395841Sobrien		sub("^" indent, "");	# remove the indent
18495841Sobrien		code = code $0 "\n";
18595841Sobrien		getline < src;
18695841Sobrien		lineno++;;
18795841Sobrien	}
18895841Sobrien	return code;
18995841Sobrien}
19095841Sobrien
19195841Sobrien#
19295841Sobrien#   Handle "METHOD" and "STATICMETHOD" sections.
19395841Sobrien#
19495841Sobrien
195131987Sdfrfunction handle_method (static, doc)
19695841Sobrien{
19795841Sobrien	#
19895841Sobrien	#   Get the return type and function name and delete that from
19995841Sobrien	#   the line. What is left is the possibly first function argument
20095841Sobrien	#   if it is on the same line.
20195841Sobrien	#
20295841Sobrien	if (!intname) {
20395841Sobrien		warnsrc("No interface name defined");
20495841Sobrien		error = 1;
20595841Sobrien		return;
20695841Sobrien	}
20795841Sobrien	sub(/^[^ 	]+[ 	]+/, "");
20895841Sobrien	ret = $0;
20995841Sobrien	sub(/[ 	]*\{.*$/, "", ret);
21095841Sobrien	name = ret;
21195841Sobrien	sub(/^.*[ 	]/, "", name);	# last element is name of method
21295841Sobrien	sub(/[ 	]+[^ 	]+$/, "", ret);	# return type
21395841Sobrien	debug("Method: name=" name " return type=" ret);
21495841Sobrien
21595841Sobrien	sub(/^[^\{]*\{[	 ]*/, "");
21695841Sobrien
21795841Sobrien	if (!name || !ret) {
21895841Sobrien		debug($0);
21995841Sobrien		warnsrc("Invalid method specification");
22095841Sobrien		error = 1;
22195841Sobrien		return;
22295841Sobrien	}
22395841Sobrien
22495841Sobrien	if (name !~ /^[a-z_][a-z_0-9]*$/) {
22595841Sobrien		warnsrc("Invalid method name '" name "', use [a-z_][a-z0-9_]*");
22695841Sobrien		error = 1;
22795841Sobrien		return;
22895841Sobrien	}
22995841Sobrien
23095841Sobrien	if (methods[name]) {
23195841Sobrien		warnsrc("Duplicate method name");
23295841Sobrien		error = 1;
23395841Sobrien		return;
23495841Sobrien	}
23595841Sobrien	methods[name] = name;
23695841Sobrien
23795841Sobrien	line = $0;
23895841Sobrien	while (line !~ /\}/ && (getline < src) > 0) {
23995841Sobrien		line = line " " $0;
24095841Sobrien		lineno++
24195841Sobrien	}
24295841Sobrien
243198374Semaste	default_function = "";
24495841Sobrien	if (!match(line, /\};?/)) {
24595841Sobrien		warnsrc("Premature end of file");
24695841Sobrien		error = 1;
24795841Sobrien		return;
24895841Sobrien	}
24995841Sobrien	extra = substr(line, RSTART + RLENGTH);
25095841Sobrien	if (extra ~ /[	 ]*DEFAULT[ 	]*[a-zA-Z_][a-zA-Z_0-9]*[ 	]*;/) {
251198374Semaste		default_function = extra;
252198374Semaste		sub(/.*DEFAULT[	 ]*/, "", default_function);
253198374Semaste		sub(/[; 	]+.*$/, "", default_function);
25495841Sobrien	}
25595841Sobrien	else if (extra && opt_d) {
25695841Sobrien		#   Warn about garbage at end of line.
25795841Sobrien		warnsrc("Ignored '" extra "'");
25895841Sobrien	}
25995841Sobrien	sub(/\};?.*$/, "", line);
26095841Sobrien
26195841Sobrien	#
26295841Sobrien	#   Create a list of variables without the types prepended.
26395841Sobrien	#
26495841Sobrien	sub(/^[	 ]+/, "", line);	# remove leading ...
26595841Sobrien	sub(/[ 	]+$/, "", line);	# ... and trailing whitespace
26695841Sobrien	gsub(/[	 ]+/, " ", line);	# remove double spaces
26795841Sobrien
26895841Sobrien	num_arguments = split(line, arguments, / *; */) - 1;
26995841Sobrien	delete varnames;		# list of varnames
27095841Sobrien	num_varnames = 0;
27195841Sobrien	for (i = 1; i <= num_arguments; i++) {
27295841Sobrien		if (!arguments[i])
27395841Sobrien			continue;	# skip argument if argument is empty
27495841Sobrien		num_ar = split(arguments[i], ar, /[* 	]+/);
27595841Sobrien		if (num_ar < 2) {	# only 1 word in argument?
27695841Sobrien			warnsrc("no type for '" arguments[i] "'");
27795841Sobrien			error = 1;
27895841Sobrien			return;
27995841Sobrien		}
28095841Sobrien		#   Last element is name of variable.
28195841Sobrien		varnames[++num_varnames] = ar[num_ar];
28295841Sobrien	}
28395841Sobrien
28495841Sobrien	argument_list = join(", ", arguments, num_arguments);
28595841Sobrien	varname_list = join(", ", varnames, num_varnames);
28695841Sobrien
28795841Sobrien	if (opt_d) {
28895841Sobrien		warn("Arguments: " argument_list);
28995841Sobrien		warn("Varnames: " varname_list);
29095841Sobrien	}
29195841Sobrien
29295841Sobrien	mname = intname "_" name;	# method name
29395841Sobrien	umname = toupper(mname);	# uppercase method name
29495841Sobrien
29595841Sobrien	firstvar = varnames[1];
29695841Sobrien
297198374Semaste	if (default_function == "")
298198374Semaste		default_function = "kobj_error_method";
29995841Sobrien
30095841Sobrien	# the method description 
301131987Sdfr	printh("/** @brief Unique descriptor for the " umname "() method */");
30295841Sobrien	printh("extern struct kobjop_desc " mname "_desc;");
30395841Sobrien	# the method typedef
304131987Sdfr	printh("/** @brief A function implementing the " umname "() method */");
30595841Sobrien	prototype = "typedef " ret " " mname "_t(";
30695841Sobrien	printh(format_line(prototype argument_list ");",
30795841Sobrien	    line_width, length(prototype)));
30895841Sobrien
309227385Sed	# Print out the method desc
31095841Sobrien	printc("struct kobjop_desc " mname "_desc = {");
311227384Sed	printc("\t0, { &" mname "_desc, (kobjop_t)" default_function " }");
31295841Sobrien	printc("};\n");
31395841Sobrien
31495841Sobrien	# Print out the method itself
315131987Sdfr	printh(doc);
31695841Sobrien	if (0) {		# haven't chosen the format yet
31795841Sobrien		printh("static __inline " ret " " umname "(" varname_list ")");
31895841Sobrien		printh("\t" join(";\n\t", arguments, num_arguments) ";");
31995841Sobrien	}
32095841Sobrien	else {
32195841Sobrien		prototype = "static __inline " ret " " umname "(";
32295841Sobrien		printh(format_line(prototype argument_list ")",
32395841Sobrien		    line_width, length(prototype)));
32495841Sobrien	}
32595841Sobrien	printh("{");
32695841Sobrien	printh("\tkobjop_t _m;");
32795841Sobrien	if (!static)
32895841Sobrien		firstvar = "((kobj_t)" firstvar ")";
32995841Sobrien	printh("\tKOBJOPLOOKUP(" firstvar "->ops," mname ");");
33095841Sobrien	retrn =  (ret != "void") ? "return " : "";
33195841Sobrien	printh("\t" retrn "((" mname "_t *) _m)(" varname_list ");");
33295841Sobrien	printh("}\n");
33395841Sobrien}
33495841Sobrien
33595841Sobrien#
33695841Sobrien#   Begin of the main program.
33795841Sobrien#
33895841Sobrien
33995841SobrienBEGIN {
34095841Sobrien
34195841Sobrienline_width = 80;
34295841Sobriengerror = 0;
34395841Sobrien
34495841Sobrien#
34595841Sobrien#   Process the command line.
34695841Sobrien#
34795841Sobrien
34895841Sobriennum_files = 0;
34995841Sobrien
35095841Sobrienfor (i = 1; i < ARGC; i++) {
35195841Sobrien	if (ARGV[i] ~ /^-/) {
35295841Sobrien		#
35395841Sobrien		#   awk doesn't have getopt(), so we have to do it ourselves.
35495841Sobrien		#   This is a bit clumsy, but it works.
35595841Sobrien		#
35695841Sobrien		for (j = 2; j <= length(ARGV[i]); j++) {
35795841Sobrien			o = substr(ARGV[i], j, 1);
35895841Sobrien			if	(o == "c")	opt_c = 1;
35995841Sobrien			else if	(o == "h")	opt_h = 1;
36095841Sobrien			else if	(o == "p")	opt_p = 1;
36195841Sobrien			else if	(o == "d")	opt_d = 1;
36295841Sobrien			else if	(o == "l") {
36395841Sobrien				if (length(ARGV[i]) > j) {
36495841Sobrien					opt_l = substr(ARGV[i], j + 1);
36595841Sobrien					break;
36695841Sobrien				}
36795841Sobrien				else {
36895841Sobrien					if (++i < ARGC)
36995841Sobrien						opt_l = ARGV[i];
37095841Sobrien					else
37195841Sobrien						usage();
37295841Sobrien				}
37395841Sobrien			}
37495841Sobrien			else
37595841Sobrien				usage();
37695841Sobrien		}
37795841Sobrien	}
37895841Sobrien	else if (ARGV[i] ~ /\.m$/)
37995841Sobrien		filenames[num_files++] = ARGV[i];
38095841Sobrien	else
38195841Sobrien		usage();
38295841Sobrien}
38395841Sobrien
38495841Sobrienif (!num_files || !(opt_c || opt_h))
38595841Sobrien	usage();
38695841Sobrien
38795841Sobrienif (opt_p)
38895841Sobrien	debug("Will produce files in original not in current directory");
38995841Sobrien
39095841Sobrienif (opt_l) {
39195841Sobrien	if (opt_l !~ /^[0-9]+$/ || opt_l < 1)
39295841Sobrien		die("Invalid line width '" opt_l "'");
39395841Sobrien	line_width = opt_l;
39495841Sobrien	debug("Line width set to " line_width);
39595841Sobrien}
39695841Sobrien
39795841Sobrienfor (i = 0; i < num_files; i++)
39895841Sobrien	debug("Filename: " filenames[i]);
39995841Sobrien
40095841Sobrienfor (file_i = 0; file_i < num_files; file_i++) {
40195841Sobrien	src = filenames[file_i];
40295841Sobrien	cfilename = hfilename = src;
40395841Sobrien	sub(/\.m$/, ".c", cfilename);
40495841Sobrien	sub(/\.m$/, ".h", hfilename);
40595841Sobrien	if (!opt_p) {
40695841Sobrien		sub(/^.*\//, "", cfilename);
40795841Sobrien		sub(/^.*\//, "", hfilename);
40895841Sobrien	}
40995841Sobrien
41095841Sobrien	debug("Processing from " src " to " cfilename " / " hfilename);
41195841Sobrien
41295841Sobrien	ctmpfilename = cfilename ".tmp";
41395841Sobrien	htmpfilename = hfilename ".tmp";
41495841Sobrien
41595841Sobrien	common_head = \
41695841Sobrien	    "/*\n" \
41795841Sobrien	    " * This file is produced automatically.\n" \
41895841Sobrien	    " * Do not modify anything in here by hand.\n" \
41995841Sobrien	    " *\n" \
42095841Sobrien	    " * Created from source file\n" \
42195841Sobrien	    " *   " src "\n" \
42295841Sobrien	    " * with\n" \
42395841Sobrien	    " *   makeobjops.awk\n" \
42495841Sobrien	    " *\n" \
42595841Sobrien	    " * See the source file for legal information\n" \
42695841Sobrien	    " */\n";
42795841Sobrien
42895841Sobrien	printc(common_head "\n" \
42995841Sobrien	    "#include <sys/param.h>\n" \
43095841Sobrien	    "#include <sys/queue.h>\n" \
43195841Sobrien	    "#include <sys/kernel.h>\n" \
43295841Sobrien	    "#include <sys/kobj.h>");
43395841Sobrien
43495841Sobrien	printh(common_head);
43595841Sobrien
43695841Sobrien	delete methods;		# clear list of methods
43795841Sobrien	intname = "";
43895841Sobrien	lineno = 0;
43995841Sobrien	error = 0;		# to signal clean up and gerror setting
440131987Sdfr	lastdoc = "";
44195841Sobrien
44295841Sobrien	while (!error && (getline < src) > 0) {
44395841Sobrien		lineno++;
44495841Sobrien
44595841Sobrien		#
44695841Sobrien		#   Take special notice of include directives.
44795841Sobrien		#
44895841Sobrien		if (/^#[ 	]*include[ 	]+["<][^">]+[">]/) {
44995841Sobrien			incld = $0;
45095841Sobrien			sub(/^#[ 	]*include[ 	]+/, "", incld);
45195841Sobrien			debug("Included file: " incld);
45295841Sobrien			printc("#include " incld);
45395841Sobrien		}
45495841Sobrien
45595841Sobrien		sub(/#.*/, "");		# remove comments
45695841Sobrien		sub(/^[	 ]+/, "");	# remove leading ...
45795841Sobrien		sub(/[ 	]+$/, "");	# ... and trailing whitespace
45895841Sobrien
45995841Sobrien		if (/^$/) {		# skip empty lines
46095841Sobrien		}
461131987Sdfr		else if (/^\/\*\*/)
462131987Sdfr			lastdoc = handle_doc();
463131987Sdfr		else if (/^INTERFACE[ 	]+[^ 	;]*[ 	]*;?[ 	]*$/) {
464131987Sdfr			printh(lastdoc);
465131987Sdfr			lastdoc = "";
46695841Sobrien			handle_interface();
467131987Sdfr		} else if (/^CODE[ 	]*{$/)
46895841Sobrien			printc(handle_code());
46995841Sobrien		else if (/^HEADER[	 ]*{$/)
47095841Sobrien			printh(handle_code());
471131987Sdfr		else if (/^METHOD/) {
472131987Sdfr			handle_method(0, lastdoc);
473131987Sdfr			lastdoc = "";
474131987Sdfr		} else if (/^STATICMETHOD/) {
475131987Sdfr			handle_method(1, lastdoc);
476131987Sdfr			lastdoc = "";
477131987Sdfr		} else {
47895841Sobrien			debug($0);
47995841Sobrien			warnsrc("Invalid line encountered");
48095841Sobrien			error = 1;
48195841Sobrien		}
48295841Sobrien	}
48395841Sobrien
48495841Sobrien	#
48595841Sobrien	#   Print the final '#endif' in the header file.
48695841Sobrien	#
48795841Sobrien	printh("#endif /* _" intname "_if_h_ */");
48895841Sobrien
48995841Sobrien	close (ctmpfilename);
49095841Sobrien	close (htmpfilename);
49195841Sobrien
49295841Sobrien	if (error) {
49395841Sobrien		warn("Output skipped");
49495841Sobrien		system_check("rm -f " ctmpfilename " " htmpfilename);
49595841Sobrien		gerror = 1;
49695841Sobrien	}
49795841Sobrien	else {
49895841Sobrien		if (opt_c)
499102164Sobrien			system_check("mv -f " ctmpfilename " " cfilename);
50095841Sobrien		if (opt_h)
501102164Sobrien			system_check("mv -f " htmpfilename " " hfilename);
50295841Sobrien	}
50395841Sobrien}
50495841Sobrien
50595841Sobrienexit gerror;
50695841Sobrien
50795841Sobrien}
508