150276Speter#!/bin/sh
250276Speter#
350276Speter# MKlib_gen.sh -- generate sources from curses.h macro definitions
450276Speter#
5184989Srafan# ($Id: MKlib_gen.sh,v 1.34 2008/08/30 19:20:50 tom Exp $)
650276Speter#
797049Speter##############################################################################
8176187Srafan# Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.                #
997049Speter#                                                                            #
1097049Speter# Permission is hereby granted, free of charge, to any person obtaining a    #
1197049Speter# copy of this software and associated documentation files (the "Software"), #
1297049Speter# to deal in the Software without restriction, including without limitation  #
1397049Speter# the rights to use, copy, modify, merge, publish, distribute, distribute    #
1497049Speter# with modifications, sublicense, and/or sell copies of the Software, and to #
1597049Speter# permit persons to whom the Software is furnished to do so, subject to the  #
1697049Speter# following conditions:                                                      #
1797049Speter#                                                                            #
1897049Speter# The above copyright notice and this permission notice shall be included in #
1997049Speter# all copies or substantial portions of the Software.                        #
2097049Speter#                                                                            #
2197049Speter# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
2297049Speter# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   #
2397049Speter# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    #
2497049Speter# THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER      #
2597049Speter# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING    #
2697049Speter# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER        #
2797049Speter# DEALINGS IN THE SOFTWARE.                                                  #
2897049Speter#                                                                            #
2997049Speter# Except as contained in this notice, the name(s) of the above copyright     #
3097049Speter# holders shall not be used in advertising or otherwise to promote the sale, #
3197049Speter# use or other dealings in this Software without prior written               #
3297049Speter# authorization.                                                             #
3397049Speter##############################################################################
3497049Speter#
3550276Speter# The XSI Curses standard requires all curses entry points to exist as
3650276Speter# functions, even though many definitions would normally be shadowed
3750276Speter# by macros.  Rather than hand-hack all that code, we actually
3850276Speter# generate functions from the macros.
3950276Speter#
4050276Speter# This script accepts a file of prototypes on standard input.  It discards
4150276Speter# any that don't have a `generated' comment attached. It then parses each
42166124Srafan# prototype (relying on the fact that none of the macros take function
4350276Speter# pointer or array arguments) and generates C source from it.
4450276Speter#
4550276Speter# Here is what the pipeline stages are doing:
4650276Speter#
4750276Speter# 1. sed: extract prototypes of generated functions
4850276Speter# 2. sed: decorate prototypes with generated arguments a1. a2,...z
49166124Srafan# 3. awk: generate the calls with args matching the formals
5050276Speter# 4. sed: prefix function names in prototypes so the preprocessor won't expand
5150276Speter#         them.
5250276Speter# 5. cpp: macro-expand the file so the macro calls turn into C calls
5350276Speter# 6. awk: strip the expansion junk off the front and add the new header
5450276Speter# 7. sed: squeeze spaces, strip off gen_ prefix, create needed #undef
5550276Speter#
5650276Speter
57166124Srafan# keep the editing independent of locale:
58166124Srafanif test "${LANGUAGE+set}"    = set; then LANGUAGE=C;    export LANGUAGE;    fi
59166124Srafanif test "${LANG+set}"        = set; then LANG=C;        export LANG;        fi
60166124Srafanif test "${LC_ALL+set}"      = set; then LC_ALL=C;      export LC_ALL;      fi
61166124Srafanif test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
62166124Srafanif test "${LC_CTYPE+set}"    = set; then LC_CTYPE=C;    export LC_CTYPE;    fi
63166124Srafanif test "${LC_COLLATE+set}"  = set; then LC_COLLATE=C;  export LC_COLLATE;  fi
64166124Srafan
65174993Srafanpreprocessor="$1 -DNCURSES_INTERNALS -I../include"
6650276SpeterAWK="$2"
6797049SpeterUSE="$3"
6850276Speter
6997049SpeterPID=$$
7097049SpeterED1=sed1_${PID}.sed
7197049SpeterED2=sed2_${PID}.sed
7297049SpeterED3=sed3_${PID}.sed
7397049SpeterED4=sed4_${PID}.sed
7497049SpeterAW1=awk1_${PID}.awk
7597049SpeterAW2=awk2_${PID}.awk
7697049SpeterTMP=gen__${PID}.c
7797049Spetertrap "rm -f $ED1 $ED2 $ED3 $ED4 $AW1 $AW2 $TMP" 0 1 2 5 15
7850276Speter
7997049SpeterALL=$USE
8097049Speterif test "$USE" = implemented ; then
8197049Speter	CALL="call_"
8297049Speter	cat >$ED1 <<EOF1
8397049Speter/^extern.*implemented/{
8497049Speter	h
85166124Srafan	s/^.*implemented:\([^ 	*]*\).*/P_POUNDCif_USE_\1_SUPPORT/p
8697049Speter	g
8797049Speter	s/^extern \([^;]*\);.*/\1/p
8897049Speter	g
89166124Srafan	s/^.*implemented:\([^ 	*]*\).*/P_POUNDCendif/p
9097049Speter}
9150276Speter/^extern.*generated/{
9250276Speter	h
93166124Srafan	s/^.*generated:\([^ 	*]*\).*/P_POUNDCif_USE_\1_SUPPORT/p
9450276Speter	g
9550276Speter	s/^extern \([^;]*\);.*/\1/p
9650276Speter	g
97166124Srafan	s/^.*generated:\([^ 	*]*\).*/P_POUNDCendif/p
9850276Speter}
9950276SpeterEOF1
10097049Speterelse
10197049Speter	CALL=""
10297049Speter	cat >$ED1 <<EOF1
10397049Speter/^extern.*${ALL}/{
10497049Speter	h
105166124Srafan	s/^.*${ALL}:\([^ 	*]*\).*/P_POUNDCif_USE_\1_SUPPORT/p
10697049Speter	g
10797049Speter	s/^extern \([^;]*\);.*/\1/p
10897049Speter	g
109166124Srafan	s/^.*${ALL}:\([^ 	*]*\).*/P_POUNDCendif/p
11097049Speter}
11197049SpeterEOF1
11297049Speterfi
11350276Speter
11450276Spetercat >$ED2 <<EOF2
11550276Speter/^P_/b nc
11650276Speter/(void)/b nc
11750276Speter	s/,/ a1% /
11850276Speter	s/,/ a2% /
11950276Speter	s/,/ a3% /
12050276Speter	s/,/ a4% /
12150276Speter	s/,/ a5% /
12250276Speter	s/,/ a6% /
12350276Speter	s/,/ a7% /
12450276Speter	s/,/ a8% /
12550276Speter	s/,/ a9% /
12650276Speter	s/,/ a10% /
12750276Speter	s/,/ a11% /
12850276Speter	s/,/ a12% /
12950276Speter	s/,/ a13% /
13050276Speter	s/,/ a14% /
13150276Speter	s/,/ a15% /
13250276Speter	s/*/ * /g
13350276Speter	s/%/ , /g
13450276Speter	s/)/ z)/
13597049Speter	s/\.\.\. z)/...)/
13650276Speter:nc
137166124Srafan	s/(/ ( /
13850276Speter	s/)/ )/
13950276SpeterEOF2
14050276Speter
14150276Spetercat >$ED3 <<EOF3
14250276Speter/^P_/{
143166124Srafan	s/^P_POUNDCif_/#if /
144166124Srafan	s/^P_POUNDCendif/#endif/
14550276Speter	s/^P_//
14650276Speter	b done
14750276Speter}
14850276Speter	s/		*/ /g
14950276Speter	s/  */ /g
15050276Speter	s/ ,/,/g
15197049Speter	s/( /(/g
15250276Speter	s/ )/)/g
15350276Speter	s/ gen_/ /
15450276Speter	s/^M_/#undef /
155184989Srafan	s/^[ 	]*@[ 	]*@[ 	]*/	/
15650276Speter:done
15750276SpeterEOF3
15850276Speter
15997049Speterif test "$USE" = generated ; then
16097049Spetercat >$ED4 <<EOF
16197049Speter	s/^\(.*\) \(.*\) (\(.*\))\$/NCURSES_EXPORT(\1) \2 (\3)/
16297049SpeterEOF
16397049Speterelse
16497049Spetercat >$ED4 <<EOF
16597049Speter/^\(.*\) \(.*\) (\(.*\))\$/ {
16697049Speter	h
16797049Speter	s/^\(.*\) \(.*\) (\(.*\))\$/extern \1 call_\2 (\3);/
16897049Speter	p
16997049Speter	g
17097049Speter	s/^\(.*\) \(.*\) (\(.*\))\$/\1 call_\2 (\3)/
17197049Speter	}
17297049SpeterEOF
17397049Speterfi
17497049Speter
17550276Spetercat >$AW1 <<\EOF1
17650276SpeterBEGIN	{
17750276Speter		skip=0;
17850276Speter	}
179166124Srafan/^P_POUNDCif/ {
18050276Speter		print "\n"
18150276Speter		print $0
18250276Speter		skip=0;
18397049Speter}
184166124Srafan/^P_POUNDCendif/ {
18550276Speter		print $0
18650276Speter		skip=1;
18797049Speter}
18897049Speter$0 !~ /^P_/ {
18950276Speter	if (skip)
19050276Speter		print "\n"
19150276Speter	skip=1;
19250276Speter
19397049Speter	first=$1
19497049Speter	for (i = 1; i <= NF; i++) {
19597049Speter		if ( $i != "NCURSES_CONST" ) {
19697049Speter			first = i;
19797049Speter			break;
19897049Speter		}
19997049Speter	}
20097049Speter	second = first + 1;
20197049Speter	if ( $first == "chtype" ) {
20266963Speter		returnType = "Char";
20397049Speter	} else if ( $first == "SCREEN" ) {
20497049Speter		returnType = "SP";
20597049Speter	} else if ( $first == "WINDOW" ) {
20697049Speter		returnType = "Win";
207166124Srafan	} else if ( $first == "attr_t" || $second == "attrset" || $second == "standout" || $second == "standend" || $second == "wattrset" || $second == "wstandout" || $second == "wstandend" ) {
208166124Srafan		returnType = "Attr";
209166124Srafan	} else if ( $first == "bool" || $first == "NCURSES_BOOL" ) {
210166124Srafan		returnType = "Bool";
21197049Speter	} else if ( $second == "*" ) {
21297049Speter		returnType = "Ptr";
21366963Speter	} else {
21466963Speter		returnType = "Code";
21566963Speter	}
21697049Speter	myfunc = second;
21797049Speter	for (i = second; i <= NF; i++) {
21897049Speter		if ($i != "*") {
21997049Speter			myfunc = i;
22097049Speter			break;
22197049Speter		}
22297049Speter	}
22397049Speter	if (using == "generated") {
22497049Speter		print "M_" $myfunc
22597049Speter	}
22650276Speter	print $0;
22750276Speter	print "{";
22850276Speter	argcount = 1;
22997049Speter	check = NF - 1;
23097049Speter	if ($check == "void")
23150276Speter		argcount = 0;
23250276Speter	if (argcount != 0) {
23350276Speter		for (i = 1; i <= NF; i++)
23450276Speter			if ($i == ",")
23550276Speter				argcount++;
23650276Speter	}
23750276Speter
23850276Speter	# suppress trace-code for functions that we cannot do properly here,
23950276Speter	# since they return data.
24050276Speter	dotrace = 1;
24197049Speter	if ($myfunc ~ /innstr/)
24250276Speter		dotrace = 0;
24397049Speter	if ($myfunc ~ /innwstr/)
24497049Speter		dotrace = 0;
24550276Speter
24697049Speter	# workaround functions that we do not parse properly
24797049Speter	if ($myfunc ~ /ripoffline/) {
24897049Speter		dotrace = 0;
24997049Speter		argcount = 2;
25097049Speter	}
25197049Speter	if ($myfunc ~ /wunctrl/) {
25297049Speter		dotrace = 0;
25397049Speter	}
25497049Speter
255184989Srafan	call = "@@T((T_CALLED(\""
25650276Speter	args = ""
25750276Speter	comma = ""
25850276Speter	num = 0;
25950276Speter	pointer = 0;
260166124Srafan	va_list = 0;
261166124Srafan	varargs = 0;
26250276Speter	argtype = ""
26397049Speter	for (i = myfunc; i <= NF; i++) {
26450276Speter		ch = $i;
26550276Speter		if ( ch == "*" )
26650276Speter			pointer = 1;
26750276Speter		else if ( ch == "va_list" )
268166124Srafan			va_list = 1;
269166124Srafan		else if ( ch == "..." )
270166124Srafan			varargs = 1;
27150276Speter		else if ( ch == "char" )
27250276Speter			argtype = "char";
27350276Speter		else if ( ch == "int" )
27450276Speter			argtype = "int";
27550276Speter		else if ( ch == "short" )
27650276Speter			argtype = "short";
27750276Speter		else if ( ch == "chtype" )
27850276Speter			argtype = "chtype";
27950276Speter		else if ( ch == "attr_t" || ch == "NCURSES_ATTR_T" )
28050276Speter			argtype = "attr";
28150276Speter
28250276Speter		if ( ch == "," || ch == ")" ) {
283166124Srafan			if (va_list) {
284166124Srafan				call = call "%s"
285166124Srafan			} else if (varargs) {
286166124Srafan				call = call "%s"
287166124Srafan			} else if (pointer) {
28850276Speter				if ( argtype == "char" ) {
28950276Speter					call = call "%s"
29050276Speter					comma = comma "_nc_visbuf2(" num ","
29150276Speter					pointer = 0;
29250276Speter				} else
29350276Speter					call = call "%p"
29450276Speter			} else if (argcount != 0) {
29550276Speter				if ( argtype == "int" || argtype == "short" ) {
29650276Speter					call = call "%d"
29750276Speter					argtype = ""
29850276Speter				} else if ( argtype != "" ) {
29950276Speter					call = call "%s"
30050276Speter					comma = comma "_trace" argtype "2(" num ","
30150276Speter				} else {
30250276Speter					call = call "%#lx"
30350276Speter					comma = comma "(long)"
30450276Speter				}
30550276Speter			}
306166124Srafan			if (ch == ",") {
30750276Speter				args = args comma "a" ++num;
308166124Srafan			} else if ( argcount != 0 ) {
309166124Srafan				if ( va_list ) {
310166124Srafan					args = args comma "\"va_list\""
311166124Srafan				} else if ( varargs ) {
312166124Srafan					args = args comma "\"...\""
313166124Srafan				} else {
314166124Srafan					args = args comma "z"
315166124Srafan				}
316166124Srafan			}
31750276Speter			call = call ch
31850276Speter			if (pointer == 0 && argcount != 0 && argtype != "" )
31950276Speter				args = args ")"
32050276Speter			if (args != "")
32150276Speter				comma = ", "
32250276Speter			pointer = 0;
32350276Speter			argtype = ""
32450276Speter		}
32550276Speter		if ( i == 2 || ch == "(" )
32650276Speter			call = call ch
32750276Speter	}
32850276Speter	call = call "\")"
32950276Speter	if (args != "")
33050276Speter		call = call ", " args
33150276Speter	call = call ")); "
33250276Speter
33350276Speter	if (dotrace)
33450276Speter		printf "%s", call
33550276Speter
33650276Speter	if (match($0, "^void"))
33750276Speter		call = ""
33850276Speter	else if (dotrace)
33966963Speter		call = sprintf("return%s( ", returnType);
34050276Speter	else
341184989Srafan		call = "@@return ";
34250276Speter
34397049Speter	call = call $myfunc "(";
34497049Speter	for (i = 1; i < argcount; i++) {
34597049Speter		if (i != 1)
34697049Speter			call = call ", ";
34797049Speter		call = call "a" i;
34897049Speter	}
34997049Speter	if ( argcount != 0 && $check != "..." ) {
35097049Speter		if (argcount != 1)
35197049Speter			call = call ", ";
35250276Speter		call = call "z";
35397049Speter	}
35450276Speter	if (!match($0, "^void"))
35550276Speter		call = call ") ";
35650276Speter	if (dotrace)
35750276Speter		call = call ")";
35850276Speter	print call ";"
35950276Speter
36050276Speter	if (match($0, "^void"))
361184989Srafan		print "@@returnVoid;"
36250276Speter	print "}";
36350276Speter}
36450276SpeterEOF1
36550276Speter
36697049Spetercat >$AW2 <<EOF1
36797049SpeterBEGIN		{
36897049Speter		print "/*"
36997049Speter		print " * DO NOT EDIT THIS FILE BY HAND!"
37097049Speter		printf " * It is generated by $0 %s.\n", "$USE"
37197049Speter		if ( "$USE" == "generated" ) {
37297049Speter			print " *"
37397049Speter			print " * This is a file of trivial functions generated from macro"
37497049Speter			print " * definitions in curses.h to satisfy the XSI Curses requirement"
37597049Speter			print " * that every macro also exist as a callable function."
37697049Speter			print " *"
37797049Speter			print " * It will never be linked unless you call one of the entry"
37897049Speter			print " * points with its normal macro definition disabled.  In that"
37997049Speter			print " * case, if you have no shared libraries, it will indirectly"
38097049Speter			print " * pull most of the rest of the library into your link image."
38197049Speter		}
38297049Speter		print " */"
383166124Srafan		print "#define NCURSES_ATTR_T int"
38497049Speter		print "#include <curses.priv.h>"
38597049Speter		print ""
38697049Speter		}
38797049Speter/^DECLARATIONS/	{start = 1; next;}
38897049Speter		{if (start) print \$0;}
38997049SpeterEND		{
39097049Speter		if ( "$USE" != "generated" ) {
39197049Speter			print "int main(void) { return 0; }"
39297049Speter		}
39397049Speter		}
39497049SpeterEOF1
39597049Speter
39697049Spetercat >$TMP <<EOF
39797049Speter#include <ncurses_cfg.h>
398166124Srafan#undef NCURSES_NOMACROS
39997049Speter#include <curses.h>
40097049Speter
40197049SpeterDECLARATIONS
40297049Speter
40397049SpeterEOF
40497049Speter
40576726Spetersed -n -f $ED1 \
40676726Speter| sed -e 's/NCURSES_EXPORT(\(.*\)) \(.*\) (\(.*\))/\1 \2(\3)/' \
40776726Speter| sed -f $ED2 \
40897049Speter| $AWK -f $AW1 using=$USE \
409174993Srafan| sed \
410174993Srafan	-e 's/ [ ]*$//g' \
411174993Srafan	-e 's/^\([a-zA-Z_][a-zA-Z_]*[ *]*\)/\1 gen_/' \
412174993Srafan	-e 's/gen_$//' \
413174993Srafan	-e 's/  / /g' >>$TMP
41497049Speter
41597049Speter$preprocessor $TMP 2>/dev/null \
416166124Srafan| sed \
417166124Srafan	-e 's/  / /g' \
418166124Srafan	-e 's/^ //' \
419184989Srafan	-e 's/_Bool/NCURSES_BOOL/g' \
42097049Speter| $AWK -f $AW2 \
42150276Speter| sed -f $ED3 \
42250276Speter| sed \
42350276Speter	-e 's/^.*T_CALLED.*returnCode( \([a-z].*) \));/	return \1;/' \
42476726Speter	-e 's/^.*T_CALLED.*returnCode( \((wmove.*) \));/	return \1;/' \
425176187Srafan	-e 's/gen_//' \
426184989Srafan	-e 's/^[ 	]*#/#/' \
427184989Srafan	-e '/#ident/d' \
428184989Srafan	-e '/#line/d' \
42997049Speter| sed -f $ED4
430