1#!/bin/sh
2#
3# MKlib_gen.sh -- generate sources from curses.h macro definitions
4#
5# ($Id: MKlib_gen.sh,v 1.12 2000/07/29 16:30:11 tom Exp $)
6#
7# The XSI Curses standard requires all curses entry points to exist as
8# functions, even though many definitions would normally be shadowed
9# by macros.  Rather than hand-hack all that code, we actually
10# generate functions from the macros.
11#
12# This script accepts a file of prototypes on standard input.  It discards
13# any that don't have a `generated' comment attached. It then parses each
14# prototype (relying on the fact that none of the macros take function
15# pointer or array arguments) and generates C source from it.
16#
17# Here is what the pipeline stages are doing:
18#
19# 1. sed: extract prototypes of generated functions
20# 2. sed: decorate prototypes with generated arguments a1. a2,...z
21# 3. awk: generate the calls with args matching the formals
22# 4. sed: prefix function names in prototypes so the preprocessor won't expand
23#         them.
24# 5. cpp: macro-expand the file so the macro calls turn into C calls
25# 6. awk: strip the expansion junk off the front and add the new header
26# 7. sed: squeeze spaces, strip off gen_ prefix, create needed #undef
27#
28
29preprocessor="$1 -I../include"
30AWK="$2"
31ED1=sed1$$.sed
32ED2=sed2$$.sed
33ED3=sed3$$.sed
34AW1=awk1$$.awk
35TMP=gen$$.c
36trap "rm -f $ED1 $ED2 $ED3 $AW1 $TMP" 0 1 2 5 15
37
38(cat <<EOF
39#include <ncurses_cfg.h>
40#include <curses.h>
41
42DECLARATIONS
43
44EOF
45cat >$ED1 <<EOF1
46/^extern.*generated/{
47	h
48	s/^.*generated:\([^ 	*]*\).*/P_#if_USE_\1_SUPPORT/p
49	g
50	s/^extern \([^;]*\);.*/\1/p
51	g
52	s/^.*generated:\([^ 	*]*\).*/P_#endif/p
53}
54EOF1
55
56cat >$ED2 <<EOF2
57/^P_/b nc
58/(void)/b nc
59	s/,/ a1% /
60	s/,/ a2% /
61	s/,/ a3% /
62	s/,/ a4% /
63	s/,/ a5% /
64	s/,/ a6% /
65	s/,/ a7% /
66	s/,/ a8% /
67	s/,/ a9% /
68	s/,/ a10% /
69	s/,/ a11% /
70	s/,/ a12% /
71	s/,/ a13% /
72	s/,/ a14% /
73	s/,/ a15% /
74	s/*/ * /g
75	s/%/ , /g
76	s/)/ z)/
77:nc
78	/(/s// ( /
79	s/)/ )/
80EOF2
81
82cat >$ED3 <<EOF3
83/^P_/{
84	s/^P_#if_/#if /
85	s/^P_//
86	b done
87}
88	s/		*/ /g
89	s/  */ /g
90	s/ ,/,/g
91	s/ )/)/g
92	s/ gen_/ /
93	s/^M_/#undef /
94	/^%%/s//	/
95:done
96EOF3
97
98cat >$AW1 <<\EOF1
99BEGIN	{
100		skip=0;
101	}
102	/^P_#if/ {
103		print "\n"
104		print $0
105		skip=0;
106	}
107	/^P_#endif/ {
108		print $0
109		skip=1;
110	}
111	$0 !~ /^P_/ {
112	if (skip)
113		print "\n"
114	skip=1;
115
116	if ( $1 == "chtype" ) {
117		returnType = "Char";
118	} else {
119		returnType = "Code";
120	}
121	print "M_" $2
122	print $0;
123	print "{";
124	argcount = 1;
125	if (NF == 5 && $4 == "void")
126		argcount = 0;
127	if (argcount != 0) {
128		for (i = 1; i <= NF; i++)
129			if ($i == ",")
130				argcount++;
131	}
132
133	# suppress trace-code for functions that we cannot do properly here,
134	# since they return data.
135	dotrace = 1;
136	if ($2 == "innstr")
137		dotrace = 0;
138
139	call = "%%T((T_CALLED(\""
140	args = ""
141	comma = ""
142	num = 0;
143	pointer = 0;
144	argtype = ""
145	for (i = 1; i <= NF; i++) {
146		ch = $i;
147		if ( ch == "*" )
148			pointer = 1;
149		else if ( ch == "va_list" )
150			pointer = 1;
151		else if ( ch == "char" )
152			argtype = "char";
153		else if ( ch == "int" )
154			argtype = "int";
155		else if ( ch == "short" )
156			argtype = "short";
157		else if ( ch == "chtype" )
158			argtype = "chtype";
159		else if ( ch == "attr_t" || ch == "NCURSES_ATTR_T" )
160			argtype = "attr";
161
162		if ( ch == "," || ch == ")" ) {
163			if (pointer) {
164				if ( argtype == "char" ) {
165					call = call "%s"
166					comma = comma "_nc_visbuf2(" num ","
167					pointer = 0;
168				} else
169					call = call "%p"
170			} else if (argcount != 0) {
171				if ( argtype == "int" || argtype == "short" ) {
172					call = call "%d"
173					argtype = ""
174				} else if ( argtype != "" ) {
175					call = call "%s"
176					comma = comma "_trace" argtype "2(" num ","
177				} else {
178					call = call "%#lx"
179					comma = comma "(long)"
180				}
181			}
182			if (ch == ",")
183				args = args comma "a" ++num;
184			else if (argcount != 0)
185				args = args comma "z"
186			call = call ch
187			if (pointer == 0 && argcount != 0 && argtype != "" )
188				args = args ")"
189			if (args != "")
190				comma = ", "
191			pointer = 0;
192			argtype = ""
193		}
194		if ( i == 2 || ch == "(" )
195			call = call ch
196	}
197	call = call "\")"
198	if (args != "")
199		call = call ", " args
200	call = call ")); "
201
202	if (dotrace)
203		printf "%s", call
204
205	if (match($0, "^void"))
206		call = ""
207	else if (dotrace)
208		call = sprintf("return%s( ", returnType);
209	else
210		call = "%%return ";
211
212	call = call $2 "(";
213	for (i = 1; i < argcount; i++)
214		call = call "a" i ", ";
215	if (argcount != 0)
216		call = call "z";
217	if (!match($0, "^void"))
218		call = call ") ";
219	if (dotrace)
220		call = call ")";
221	print call ";"
222
223	if (match($0, "^void"))
224		print "%%returnVoid;"
225	print "}";
226}
227EOF1
228
229sed -n -f $ED1 | sed -f $ED2 \
230| $AWK -f $AW1 ) \
231| sed \
232	-e '/^\([a-z_][a-z_]*\) /s//\1 gen_/' >$TMP
233  $preprocessor $TMP 2>/dev/null \
234| $AWK '
235BEGIN		{
236	print "/*"
237	print " * DO NOT EDIT THIS FILE BY HAND!"
238	print " * It is generated by MKlib_gen.sh."
239	print " *"
240	print " * This is a file of trivial functions generated from macro"
241	print " * definitions in curses.h to satisfy the XSI Curses requirement"
242	print " * that every macro also exist as a callable function."
243	print " *"
244	print " * It will never be linked unless you call one of the entry"
245	print " * points with its normal macro definition disabled.  In that"
246	print " * case, if you have no shared libraries, it will indirectly"
247	print " * pull most of the rest of the library into your link image."
248	print " */"
249	print "#include <curses.priv.h>"
250	print ""
251		}
252/^DECLARATIONS/	{start = 1; next;}
253		{if (start) print $0;}
254' \
255| sed -f $ED3 \
256| sed \
257	-e 's/^.*T_CALLED.*returnCode( \([a-z].*) \));/	return \1;/' \
258	-e 's/^.*T_CALLED.*returnCode( \((wmove.*) \));/	return \1;/'
259
260