• Home
  • History
  • Annotate
  • only in this directory
MKlib_gen.sh revision 1.4
1#!/bin/sh
2#
3# MKlib_gen.sh -- generate sources from curses.h macro definitions
4#
5# $OpenBSD: MKlib_gen.sh,v 1.4 2010/01/12 23:22:05 nicm Exp $
6# ($Id: MKlib_gen.sh,v 1.4 2010/01/12 23:22:05 nicm Exp $)
7#
8##############################################################################
9# Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.                #
10#                                                                            #
11# Permission is hereby granted, free of charge, to any person obtaining a    #
12# copy of this software and associated documentation files (the "Software"), #
13# to deal in the Software without restriction, including without limitation  #
14# the rights to use, copy, modify, merge, publish, distribute, distribute    #
15# with modifications, sublicense, and/or sell copies of the Software, and to #
16# permit persons to whom the Software is furnished to do so, subject to the  #
17# following conditions:                                                      #
18#                                                                            #
19# The above copyright notice and this permission notice shall be included in #
20# all copies or substantial portions of the Software.                        #
21#                                                                            #
22# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
23# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   #
24# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    #
25# THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      #
26# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    #
27# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        #
28# DEALINGS IN THE SOFTWARE.                                                  #
29#                                                                            #
30# Except as contained in this notice, the name(s) of the above copyright     #
31# holders shall not be used in advertising or otherwise to promote the sale, #
32# use or other dealings in this Software without prior written               #
33# authorization.                                                             #
34##############################################################################
35#
36# The XSI Curses standard requires all curses entry points to exist as
37# functions, even though many definitions would normally be shadowed
38# by macros.  Rather than hand-hack all that code, we actually
39# generate functions from the macros.
40#
41# This script accepts a file of prototypes on standard input.  It discards
42# any that don't have a `generated' comment attached. It then parses each
43# prototype (relying on the fact that none of the macros take function
44# pointer or array arguments) and generates C source from it.
45#
46# Here is what the pipeline stages are doing:
47#
48# 1. sed: extract prototypes of generated functions
49# 2. sed: decorate prototypes with generated arguments a1. a2,...z
50# 3. awk: generate the calls with args matching the formals
51# 4. sed: prefix function names in prototypes so the preprocessor won't expand
52#         them.
53# 5. cpp: macro-expand the file so the macro calls turn into C calls
54# 6. awk: strip the expansion junk off the front and add the new header
55# 7. sed: squeeze spaces, strip off gen_ prefix, create needed #undef
56#
57
58# keep the editing independent of locale:
59if test "${LANGUAGE+set}"    = set; then LANGUAGE=C;    export LANGUAGE;    fi
60if test "${LANG+set}"        = set; then LANG=C;        export LANG;        fi
61if test "${LC_ALL+set}"      = set; then LC_ALL=C;      export LC_ALL;      fi
62if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
63if test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
64if test "${LC_COLLATE+set}"  = set; then LC_COLLATE=C;  export LC_COLLATE;  fi
65
66preprocessor="$1 -DNCURSES_INTERNALS -I../include"
67AWK="$2"
68USE="$3"
69
70PID=$$
71ED1=sed1_${PID}.sed
72ED2=sed2_${PID}.sed
73ED3=sed3_${PID}.sed
74ED4=sed4_${PID}.sed
75AW1=awk1_${PID}.awk
76AW2=awk2_${PID}.awk
77TMP=gen__${PID}.c
78trap "rm -f $ED1 $ED2 $ED3 $ED4 $AW1 $AW2 $TMP" 0 1 2 5 15
79
80ALL=$USE
81if test "$USE" = implemented ; then
82	CALL="call_"
83	cat >$ED1 <<EOF1
84/^extern.*implemented/{
85	h
86	s/^.*implemented:\([^ 	*]*\).*/P_POUNDCif_USE_\1_SUPPORT/p
87	g
88	s/^extern \([^;]*\);.*/\1/p
89	g
90	s/^.*implemented:\([^ 	*]*\).*/P_POUNDCendif/p
91}
92/^extern.*generated/{
93	h
94	s/^.*generated:\([^ 	*]*\).*/P_POUNDCif_USE_\1_SUPPORT/p
95	g
96	s/^extern \([^;]*\);.*/\1/p
97	g
98	s/^.*generated:\([^ 	*]*\).*/P_POUNDCendif/p
99}
100EOF1
101else
102	CALL=""
103	cat >$ED1 <<EOF1
104/^extern.*${ALL}/{
105	h
106	s/^.*${ALL}:\([^ 	*]*\).*/P_POUNDCif_USE_\1_SUPPORT/p
107	g
108	s/^extern \([^;]*\);.*/\1/p
109	g
110	s/^.*${ALL}:\([^ 	*]*\).*/P_POUNDCendif/p
111}
112EOF1
113fi
114
115cat >$ED2 <<EOF2
116/^P_/b nc
117/(void)/b nc
118	s/,/ a1% /
119	s/,/ a2% /
120	s/,/ a3% /
121	s/,/ a4% /
122	s/,/ a5% /
123	s/,/ a6% /
124	s/,/ a7% /
125	s/,/ a8% /
126	s/,/ a9% /
127	s/,/ a10% /
128	s/,/ a11% /
129	s/,/ a12% /
130	s/,/ a13% /
131	s/,/ a14% /
132	s/,/ a15% /
133	s/*/ * /g
134	s/%/ , /g
135	s/)/ z)/
136	s/\.\.\. z)/...)/
137:nc
138	s/(/ ( /
139	s/)/ )/
140EOF2
141
142cat >$ED3 <<EOF3
143/^P_/{
144	s/^P_POUNDCif_/#if /
145	s/^P_POUNDCendif/#endif/
146	s/^P_//
147	b done
148}
149	s/		*/ /g
150	s/  */ /g
151	s/ ,/,/g
152	s/( /(/g
153	s/ )/)/g
154	s/ gen_/ /
155	s/^M_/#undef /
156	s/^[ 	]*@[ 	]*@[ 	]*/	/
157:done
158EOF3
159
160if test "$USE" = generated ; then
161cat >$ED4 <<EOF
162	s/^\(.*\) \(.*\) (\(.*\))\$/NCURSES_EXPORT(\1) \2 (\3)/
163EOF
164else
165cat >$ED4 <<EOF
166/^\(.*\) \(.*\) (\(.*\))\$/ {
167	h
168	s/^\(.*\) \(.*\) (\(.*\))\$/extern \1 call_\2 (\3);/
169	p
170	g
171	s/^\(.*\) \(.*\) (\(.*\))\$/\1 call_\2 (\3)/
172	}
173EOF
174fi
175
176cat >$AW1 <<\EOF1
177BEGIN	{
178		skip=0;
179	}
180/^P_POUNDCif/ {
181		print "\n"
182		print $0
183		skip=0;
184}
185/^P_POUNDCendif/ {
186		print $0
187		skip=1;
188}
189$0 !~ /^P_/ {
190	if (skip)
191		print "\n"
192	skip=1;
193
194	first=$1
195	for (i = 1; i <= NF; i++) {
196		if ( $i != "NCURSES_CONST" ) {
197			first = i;
198			break;
199		}
200	}
201	second = first + 1;
202	if ( $first == "chtype" ) {
203		returnType = "Char";
204	} else if ( $first == "SCREEN" ) {
205		returnType = "SP";
206	} else if ( $first == "WINDOW" ) {
207		returnType = "Win";
208	} else if ( $first == "attr_t" || $second == "attrset" || $second == "standout" || $second == "standend" || $second == "wattrset" || $second == "wstandout" || $second == "wstandend" ) {
209		returnType = "Attr";
210	} else if ( $first == "bool" || $first == "NCURSES_BOOL" ) {
211		returnType = "Bool";
212	} else if ( $second == "*" ) {
213		returnType = "Ptr";
214	} else {
215		returnType = "Code";
216	}
217	myfunc = second;
218	for (i = second; i <= NF; i++) {
219		if ($i != "*") {
220			myfunc = i;
221			break;
222		}
223	}
224	if (using == "generated") {
225		print "M_" $myfunc
226	}
227	print $0;
228	print "{";
229	argcount = 1;
230	check = NF - 1;
231	if ($check == "void")
232		argcount = 0;
233	if (argcount != 0) {
234		for (i = 1; i <= NF; i++)
235			if ($i == ",")
236				argcount++;
237	}
238
239	# suppress trace-code for functions that we cannot do properly here,
240	# since they return data.
241	dotrace = 1;
242	if ($myfunc ~ /innstr/)
243		dotrace = 0;
244	if ($myfunc ~ /innwstr/)
245		dotrace = 0;
246
247	# workaround functions that we do not parse properly
248	if ($myfunc ~ /ripoffline/) {
249		dotrace = 0;
250		argcount = 2;
251	}
252	if ($myfunc ~ /wunctrl/) {
253		dotrace = 0;
254	}
255
256	call = "@@T((T_CALLED(\""
257	args = ""
258	comma = ""
259	num = 0;
260	pointer = 0;
261	va_list = 0;
262	varargs = 0;
263	argtype = ""
264	for (i = myfunc; i <= NF; i++) {
265		ch = $i;
266		if ( ch == "*" )
267			pointer = 1;
268		else if ( ch == "va_list" )
269			va_list = 1;
270		else if ( ch == "..." )
271			varargs = 1;
272		else if ( ch == "char" )
273			argtype = "char";
274		else if ( ch == "int" )
275			argtype = "int";
276		else if ( ch == "short" )
277			argtype = "short";
278		else if ( ch == "chtype" )
279			argtype = "chtype";
280		else if ( ch == "attr_t" || ch == "NCURSES_ATTR_T" )
281			argtype = "attr";
282
283		if ( ch == "," || ch == ")" ) {
284			if (va_list) {
285				call = call "%s"
286			} else if (varargs) {
287				call = call "%s"
288			} else if (pointer) {
289				if ( argtype == "char" ) {
290					call = call "%s"
291					comma = comma "_nc_visbuf2(" num ","
292					pointer = 0;
293				} else
294					call = call "%p"
295			} else if (argcount != 0) {
296				if ( argtype == "int" || argtype == "short" ) {
297					call = call "%d"
298					argtype = ""
299				} else if ( argtype != "" ) {
300					call = call "%s"
301					comma = comma "_trace" argtype "2(" num ","
302				} else {
303					call = call "%#lx"
304					comma = comma "(long)"
305				}
306			}
307			if (ch == ",") {
308				args = args comma "a" ++num;
309			} else if ( argcount != 0 ) {
310				if ( va_list ) {
311					args = args comma "\"va_list\""
312				} else if ( varargs ) {
313					args = args comma "\"...\""
314				} else {
315					args = args comma "z"
316				}
317			}
318			call = call ch
319			if (pointer == 0 && argcount != 0 && argtype != "" )
320				args = args ")"
321			if (args != "")
322				comma = ", "
323			pointer = 0;
324			argtype = ""
325		}
326		if ( i == 2 || ch == "(" )
327			call = call ch
328	}
329	call = call "\")"
330	if (args != "")
331		call = call ", " args
332	call = call ")); "
333
334	if (dotrace)
335		printf "%s", call
336
337	if (match($0, "^void"))
338		call = ""
339	else if (dotrace)
340		call = sprintf("return%s( ", returnType);
341	else
342		call = "@@return ";
343
344	call = call $myfunc "(";
345	for (i = 1; i < argcount; i++) {
346		if (i != 1)
347			call = call ", ";
348		call = call "a" i;
349	}
350	if ( argcount != 0 && $check != "..." ) {
351		if (argcount != 1)
352			call = call ", ";
353		call = call "z";
354	}
355	if (!match($0, "^void"))
356		call = call ") ";
357	if (dotrace)
358		call = call ")";
359	print call ";"
360
361	if (match($0, "^void"))
362		print "@@returnVoid;"
363	print "}";
364}
365EOF1
366
367cat >$AW2 <<EOF1
368BEGIN		{
369		print "/*"
370		print " * DO NOT EDIT THIS FILE BY HAND!"
371		printf " * It is generated by $0 %s.\n", "$USE"
372		if ( "$USE" == "generated" ) {
373			print " *"
374			print " * This is a file of trivial functions generated from macro"
375			print " * definitions in curses.h to satisfy the XSI Curses requirement"
376			print " * that every macro also exist as a callable function."
377			print " *"
378			print " * It will never be linked unless you call one of the entry"
379			print " * points with its normal macro definition disabled.  In that"
380			print " * case, if you have no shared libraries, it will indirectly"
381			print " * pull most of the rest of the library into your link image."
382		}
383		print " */"
384		print "#define NCURSES_ATTR_T int"
385		print "#include <curses.priv.h>"
386		print ""
387		}
388/^DECLARATIONS/	{start = 1; next;}
389		{if (start) print \$0;}
390END		{
391		if ( "$USE" != "generated" ) {
392			print "int main(void) { return 0; }"
393		}
394		}
395EOF1
396
397cat >$TMP <<EOF
398#include <ncurses_cfg.h>
399#undef NCURSES_NOMACROS
400#include <curses.h>
401
402DECLARATIONS
403
404EOF
405
406sed -n -f $ED1 \
407| sed -e 's/NCURSES_EXPORT(\(.*\)) \(.*\) (\(.*\))/\1 \2(\3)/' \
408| sed -f $ED2 \
409| $AWK -f $AW1 using=$USE \
410| sed \
411	-e 's/ [ ]*$//g' \
412	-e 's/^\([a-zA-Z_][a-zA-Z_]*[ *]*\)/\1 gen_/' \
413	-e 's/gen_$//' \
414	-e 's/  / /g' >>$TMP
415
416$preprocessor $TMP 2>/dev/null \
417| sed \
418	-e 's/  / /g' \
419	-e 's/^ //' \
420	-e 's/_Bool/NCURSES_BOOL/g' \
421| $AWK -f $AW2 \
422| sed -f $ED3 \
423| sed \
424	-e 's/^.*T_CALLED.*returnCode( \([a-z].*) \));/	return \1;/' \
425	-e 's/^.*T_CALLED.*returnCode( \((wmove.*) \));/	return \1;/' \
426	-e 's/gen_//' \
427	-e 's/^[ 	]*#/#/' \
428	-e '/#ident/d' \
429	-e '/#line/d' \
430| sed -f $ED4
431