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