MKlib_gen.sh revision 97049
1105665Srwatson#!/bin/sh
2126256Srwatson#
3126256Srwatson# MKlib_gen.sh -- generate sources from curses.h macro definitions
4105665Srwatson#
5105665Srwatson# ($Id: MKlib_gen.sh,v 1.18 2002/04/30 00:37:55 tom Exp $)
6105665Srwatson#
7105665Srwatson##############################################################################
8105665Srwatson# Copyright (c) 1998-2001,2002 Free Software Foundation, Inc.                #
9105665Srwatson#                                                                            #
10105665Srwatson# Permission is hereby granted, free of charge, to any person obtaining a    #
11105665Srwatson# copy of this software and associated documentation files (the "Software"), #
12105665Srwatson# to deal in the Software without restriction, including without limitation  #
13105665Srwatson# the rights to use, copy, modify, merge, publish, distribute, distribute    #
14105665Srwatson# with modifications, sublicense, and/or sell copies of the Software, and to #
15105665Srwatson# permit persons to whom the Software is furnished to do so, subject to the  #
16105665Srwatson# following conditions:                                                      #
17105665Srwatson#                                                                            #
18105665Srwatson# The above copyright notice and this permission notice shall be included in #
19105665Srwatson# all copies or substantial portions of the Software.                        #
20105665Srwatson#                                                                            #
21105665Srwatson# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
22105665Srwatson# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   #
23105665Srwatson# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    #
24105665Srwatson# THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      #
25105665Srwatson# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    #
26105665Srwatson# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        #
27105665Srwatson# DEALINGS IN THE SOFTWARE.                                                  #
28105665Srwatson#                                                                            #
29105665Srwatson# Except as contained in this notice, the name(s) of the above copyright     #
30105665Srwatson# holders shall not be used in advertising or otherwise to promote the sale, #
31105665Srwatson# use or other dealings in this Software without prior written               #
32105665Srwatson# authorization.                                                             #
33105665Srwatson##############################################################################
34105665Srwatson#
35105665Srwatson# The XSI Curses standard requires all curses entry points to exist as
36285873Strasz# functions, even though many definitions would normally be shadowed
37107780Sru# by macros.  Rather than hand-hack all that code, we actually
38105665Srwatson# generate functions from the macros.
39105665Srwatson#
40105665Srwatson# This script accepts a file of prototypes on standard input.  It discards
41105665Srwatson# any that don't have a `generated' comment attached. It then parses each
42105665Srwatson# prototype (relying on the fact that none of the macros take function 
43105665Srwatson# pointer or array arguments) and generates C source from it.
44105665Srwatson#
45105665Srwatson# Here is what the pipeline stages are doing:
46105665Srwatson#
47105665Srwatson# 1. sed: extract prototypes of generated functions
48105665Srwatson# 2. sed: decorate prototypes with generated arguments a1. a2,...z
49105665Srwatson# 3. awk: generate the calls with args matching the formals 
50105665Srwatson# 4. sed: prefix function names in prototypes so the preprocessor won't expand
51107780Sru#         them.
52107780Sru# 5. cpp: macro-expand the file so the macro calls turn into C calls
53107780Sru# 6. awk: strip the expansion junk off the front and add the new header
54105665Srwatson# 7. sed: squeeze spaces, strip off gen_ prefix, create needed #undef
55105665Srwatson#
56105665Srwatson
57105665Srwatsonpreprocessor="$1 -I../include"
58105665SrwatsonAWK="$2"
59105665SrwatsonUSE="$3"
60105665Srwatson
61105665SrwatsonPID=$$
62105665SrwatsonED1=sed1_${PID}.sed
63105665SrwatsonED2=sed2_${PID}.sed
64105665SrwatsonED3=sed3_${PID}.sed
65107780SruED4=sed4_${PID}.sed
66105665SrwatsonAW1=awk1_${PID}.awk
67105665SrwatsonAW2=awk2_${PID}.awk
68107780SruTMP=gen__${PID}.c
69105665Srwatsontrap "rm -f $ED1 $ED2 $ED3 $ED4 $AW1 $AW2 $TMP" 0 1 2 5 15
70107780Sru
71107780SruALL=$USE
72107780Sruif test "$USE" = implemented ; then
73105665Srwatson	CALL="call_"
74105665Srwatson	cat >$ED1 <<EOF1
75105665Srwatson/^extern.*implemented/{
76105665Srwatson	h
77105665Srwatson	s/^.*implemented:\([^ 	*]*\).*/P_#if_USE_\1_SUPPORT/p
78105665Srwatson	g
79105665Srwatson	s/^extern \([^;]*\);.*/\1/p
80105665Srwatson	g
81105665Srwatson	s/^.*implemented:\([^ 	*]*\).*/P_#endif/p
82105665Srwatson}
83105665Srwatson/^extern.*generated/{
84105665Srwatson	h
85105665Srwatson	s/^.*generated:\([^ 	*]*\).*/P_#if_USE_\1_SUPPORT/p
86105665Srwatson	g
87105665Srwatson	s/^extern \([^;]*\);.*/\1/p
88105665Srwatson	g
89105665Srwatson	s/^.*generated:\([^ 	*]*\).*/P_#endif/p
90105665Srwatson}
91105665SrwatsonEOF1
92105665Srwatsonelse
93105665Srwatson	CALL=""
94105665Srwatson	cat >$ED1 <<EOF1
95105665Srwatson/^extern.*${ALL}/{
96105665Srwatson	h
97105665Srwatson	s/^.*${ALL}:\([^ 	*]*\).*/P_#if_USE_\1_SUPPORT/p
98105665Srwatson	g
99105665Srwatson	s/^extern \([^;]*\);.*/\1/p
100105665Srwatson	g
101105665Srwatson	s/^.*${ALL}:\([^ 	*]*\).*/P_#endif/p
102107780Sru}
103107780SruEOF1
104105665Srwatsonfi
105105665Srwatson
106105665Srwatsoncat >$ED2 <<EOF2
107105665Srwatson/^P_/b nc
108105665Srwatson/(void)/b nc
109105665Srwatson	s/,/ a1% /
110105665Srwatson	s/,/ a2% /
111105665Srwatson	s/,/ a3% /
112105665Srwatson	s/,/ a4% /
113105665Srwatson	s/,/ a5% /
114105665Srwatson	s/,/ a6% /
115105665Srwatson	s/,/ a7% /
116105665Srwatson	s/,/ a8% /
117105665Srwatson	s/,/ a9% /
118105665Srwatson	s/,/ a10% /
119105665Srwatson	s/,/ a11% /
120105665Srwatson	s/,/ a12% /
121105665Srwatson	s/,/ a13% /
122105665Srwatson	s/,/ a14% /
123105665Srwatson	s/,/ a15% /
124105665Srwatson	s/*/ * /g
125105665Srwatson	s/%/ , /g
126105665Srwatson	s/)/ z)/
127105665Srwatson	s/\.\.\. z)/...)/
128105665Srwatson:nc
129105665Srwatson	/(/s// ( /
130105665Srwatson	s/)/ )/
131105665SrwatsonEOF2
132105665Srwatson
133105665Srwatsoncat >$ED3 <<EOF3
134105665Srwatson/^P_/{
135105665Srwatson	s/^P_#if_/#if /
136105665Srwatson	s/^P_//
137105665Srwatson	b done
138105665Srwatson}
139105665Srwatson	s/		*/ /g
140105665Srwatson	s/  */ /g
141105665Srwatson	s/ ,/,/g
142105665Srwatson	s/( /(/g
143105665Srwatson	s/ )/)/g
144105665Srwatson	s/ gen_/ /
145105665Srwatson	s/^M_/#undef /
146107780Sru	/^%%/s//	/
147160261Sjoel:done
148107780SruEOF3
149105665Srwatson
150105665Srwatsonif test "$USE" = generated ; then
151105665Srwatsoncat >$ED4 <<EOF
152107780Sru	s/^\(.*\) \(.*\) (\(.*\))\$/NCURSES_EXPORT(\1) \2 (\3)/
153107795SchrisEOF
154107795Schriselse
155107795Schriscat >$ED4 <<EOF
156141355Sbrueffer/^\(.*\) \(.*\) (\(.*\))\$/ {
157107795Schris	h
158107795Schris	s/^\(.*\) \(.*\) (\(.*\))\$/extern \1 call_\2 (\3);/
159107795Schris	p
160107795Schris	g
161107795Schris	s/^\(.*\) \(.*\) (\(.*\))\$/\1 call_\2 (\3)/
162105665Srwatson	}
163105665SrwatsonEOF
164105665Srwatsonfi
165107780Sru
166108936Schriscat >$AW1 <<\EOF1
167160247SjoelBEGIN	{
168202386Sru		skip=0;
169108936Schris	}
170140561Sru/^P_#if/ {
171140561Sru		print "\n"
172140561Sru		print $0
173140561Sru		skip=0;
174140561Sru}
175105665Srwatson/^P_#endif/ {
176147647Shmp		print $0
177105665Srwatson		skip=1;
178105665Srwatson}
179105665Srwatson$0 !~ /^P_/ {
180105665Srwatson	if (skip)
181131530Sru		print "\n"
182107780Sru	skip=1;
183107780Sru
184107780Sru	first=$1
185105665Srwatson	for (i = 1; i <= NF; i++) {
186105665Srwatson		if ( $i != "NCURSES_CONST" ) {
187107780Sru			first = i;
188107780Sru			break;
189107780Sru		}
190105665Srwatson	}
191105665Srwatson	second = first + 1;
192108317Sschweikh	if ( $first == "chtype" ) {
193105665Srwatson		returnType = "Char";
194105665Srwatson	} else if ( $first == "SCREEN" ) {
195105665Srwatson		returnType = "SP";
196105665Srwatson	} else if ( $first == "WINDOW" ) {
197105665Srwatson		returnType = "Win";
198126256Srwatson	} else if ( $second == "*" ) {
199105665Srwatson		returnType = "Ptr";
200105665Srwatson	} else {
201105665Srwatson		returnType = "Code";
202105665Srwatson	}
203105665Srwatson	myfunc = second;
204126256Srwatson	for (i = second; i <= NF; i++) {
205105665Srwatson		if ($i != "*") {
206105665Srwatson			myfunc = i;
207105665Srwatson			break;
208105665Srwatson		}
209105665Srwatson	}
210105665Srwatson	if (using == "generated") {
211105665Srwatson		print "M_" $myfunc
212105665Srwatson	}
213105665Srwatson	print $0;
214124963Sdes	print "{";
215105665Srwatson	argcount = 1;
216105665Srwatson	check = NF - 1;
217130582Sru	if ($check == "void")
218105665Srwatson		argcount = 0;
219105665Srwatson	if (argcount != 0) {
220126256Srwatson		for (i = 1; i <= NF; i++)
221126256Srwatson			if ($i == ",")
222105665Srwatson				argcount++;
223126256Srwatson	}
224105665Srwatson
225126256Srwatson	# suppress trace-code for functions that we cannot do properly here,
226106419Srwatson	# since they return data.
227106419Srwatson	dotrace = 1;
228107478Schris	if ($myfunc ~ /innstr/)
229106419Srwatson		dotrace = 0;
230106419Srwatson	if ($myfunc ~ /innwstr/)
231106419Srwatson		dotrace = 0;
232
233	# workaround functions that we do not parse properly
234	if ($myfunc ~ /ripoffline/) {
235		dotrace = 0;
236		argcount = 2;
237	}
238	if ($myfunc ~ /wunctrl/) {
239		dotrace = 0;
240	}
241
242	call = "%%T((T_CALLED(\""
243	args = ""
244	comma = ""
245	num = 0;
246	pointer = 0;
247	argtype = ""
248	for (i = myfunc; i <= NF; i++) {
249		ch = $i;
250		if ( ch == "*" )
251			pointer = 1;
252		else if ( ch == "va_list" )
253			pointer = 1;
254		else if ( ch == "char" )
255			argtype = "char";
256		else if ( ch == "int" )
257			argtype = "int";
258		else if ( ch == "short" )
259			argtype = "short";
260		else if ( ch == "chtype" )
261			argtype = "chtype";
262		else if ( ch == "attr_t" || ch == "NCURSES_ATTR_T" )
263			argtype = "attr";
264
265		if ( ch == "," || ch == ")" ) {
266			if (pointer) {
267				if ( argtype == "char" ) {
268					call = call "%s"
269					comma = comma "_nc_visbuf2(" num ","
270					pointer = 0;
271				} else
272					call = call "%p"
273			} else if (argcount != 0) {
274				if ( argtype == "int" || argtype == "short" ) {
275					call = call "%d"
276					argtype = ""
277				} else if ( argtype != "" ) {
278					call = call "%s"
279					comma = comma "_trace" argtype "2(" num ","
280				} else {
281					call = call "%#lx"
282					comma = comma "(long)"
283				}
284			}
285			if (ch == ",")
286				args = args comma "a" ++num;
287			else if ( argcount != 0 && $check != "..." )
288				args = args comma "z"
289			call = call ch
290			if (pointer == 0 && argcount != 0 && argtype != "" )
291				args = args ")"
292			if (args != "")
293				comma = ", "
294			pointer = 0;
295			argtype = ""
296		}
297		if ( i == 2 || ch == "(" )
298			call = call ch
299	}
300	call = call "\")"
301	if (args != "")
302		call = call ", " args
303	call = call ")); "
304
305	if (dotrace)
306		printf "%s", call
307
308	if (match($0, "^void"))
309		call = ""
310	else if (dotrace)
311		call = sprintf("return%s( ", returnType);
312	else
313		call = "%%return ";
314
315	call = call $myfunc "(";
316	for (i = 1; i < argcount; i++) {
317		if (i != 1)
318			call = call ", ";
319		call = call "a" i;
320	}
321	if ( argcount != 0 && $check != "..." ) {
322		if (argcount != 1)
323			call = call ", ";
324		call = call "z";
325	}
326	if (!match($0, "^void"))
327		call = call ") ";
328	if (dotrace)
329		call = call ")";
330	print call ";"
331
332	if (match($0, "^void"))
333		print "%%returnVoid;"
334	print "}";
335}
336EOF1
337
338cat >$AW2 <<EOF1
339BEGIN		{
340		print "/*"
341		print " * DO NOT EDIT THIS FILE BY HAND!"
342		printf " * It is generated by $0 %s.\n", "$USE"
343		if ( "$USE" == "generated" ) {
344			print " *"
345			print " * This is a file of trivial functions generated from macro"
346			print " * definitions in curses.h to satisfy the XSI Curses requirement"
347			print " * that every macro also exist as a callable function."
348			print " *"
349			print " * It will never be linked unless you call one of the entry"
350			print " * points with its normal macro definition disabled.  In that"
351			print " * case, if you have no shared libraries, it will indirectly"
352			print " * pull most of the rest of the library into your link image."
353		}
354		print " */"
355		print "#include <curses.priv.h>"
356		print ""
357		}
358/^DECLARATIONS/	{start = 1; next;}
359		{if (start) print \$0;}
360END		{
361		if ( "$USE" != "generated" ) {
362			print "int main(void) { return 0; }"
363		}
364		}
365EOF1
366
367cat >$TMP <<EOF
368#include <ncurses_cfg.h>
369#include <curses.h>
370
371DECLARATIONS
372
373EOF
374
375sed -n -f $ED1 \
376| sed -e 's/NCURSES_EXPORT(\(.*\)) \(.*\) (\(.*\))/\1 \2(\3)/' \
377| sed -f $ED2 \
378| $AWK -f $AW1 using=$USE \
379| sed -e 's/^\([a-z_][a-z_]*[ *]*\)/\1 gen_/' -e 's/  / /g' >>$TMP
380
381$preprocessor $TMP 2>/dev/null \
382| sed -e 's/  / /g' -e 's/^ //' \
383| $AWK -f $AW2 \
384| sed -f $ED3 \
385| sed \
386	-e 's/^.*T_CALLED.*returnCode( \([a-z].*) \));/	return \1;/' \
387	-e 's/^.*T_CALLED.*returnCode( \((wmove.*) \));/	return \1;/' \
388| sed -f $ED4
389