ncurses 4.1
[ncurses.git] / ncurses / MKlib_gen.sh
1 #!/bin/sh
2 #
3 # MKlib_gen.sh -- generate sources from curses.h macro definitions
4 #
5 # ($Id: MKlib_gen.sh,v 1.9 1997/05/10 23:48:19 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
29 preprocessor="$1 -I../include"
30 AWK="$2"
31 TMP=gen$$.c
32 trap "rm -f $TMP" 0 1 2 5 15
33
34 (cat <<EOF
35 #include <ncurses_cfg.h>
36 #include <curses.h>
37
38 DECLARATIONS
39
40 EOF
41 sed -n -e "/^extern.*generated/s/^extern \([^;]*\);.*/\1/p" \
42 | sed \
43         -e "/(void)/b nc" \
44         -e "s/,/ a1% /" \
45         -e "s/,/ a2% /" \
46         -e "s/,/ a3% /" \
47         -e "s/,/ a4% /" \
48         -e "s/,/ a5% /" \
49         -e "s/,/ a6% /" \
50         -e "s/,/ a7% /" \
51         -e "s/,/ a8% /" \
52         -e "s/,/ a9% /" \
53         -e "s/,/ a10% /" \
54         -e "s/,/ a11% /" \
55         -e "s/,/ a12% /" \
56         -e "s/,/ a13% /" \
57         -e "s/,/ a14% /" \
58         -e "s/,/ a15% /" \
59         -e "s/*/ * /g" \
60         -e "s/%/ , /g" \
61         -e "s/)/ z)/" \
62         -e ":nc" \
63         -e "/(/s// ( /" \
64         -e "s/)/ )/" \
65 | $AWK '{
66         print "\n"
67
68         print "M_" $2
69         print $0;
70         print "{";
71         argcount = 1;
72         if (NF == 5 && $4 == "void")
73                 argcount = 0;
74         if (argcount != 0) {
75                 for (i = 1; i <= NF; i++)
76                         if ($i == ",")
77                                 argcount++;
78         }
79
80         # suppress trace-code for functions that we cannot do properly here,
81         # since they return data.
82         dotrace = 1;
83         if ($2 == "innstr")
84                 dotrace = 0;
85
86         call = "%%T((T_CALLED(\""
87         args = ""
88         comma = ""
89         num = 0;
90         pointer = 0;
91         argtype = ""
92         for (i = 1; i <= NF; i++) {
93                 ch = $i;
94                 if ( ch == "*" )
95                         pointer = 1;
96                 else if ( ch == "va_list" )
97                         pointer = 1;
98                 else if ( ch == "char" )
99                         argtype = "char";
100                 else if ( ch == "int" )
101                         argtype = "int";
102                 else if ( ch == "short" )
103                         argtype = "short";
104                 else if ( ch == "chtype" )
105                         argtype = "chtype";
106                 else if ( ch == "attr_t" || ch == "NCURSES_ATTR_T" )
107                         argtype = "attr";
108
109                 if ( ch == "," || ch == ")" ) {
110                         if (pointer) {
111                                 if ( argtype == "char" ) {
112                                         call = call "%s"
113                                         comma = comma "_nc_visbuf2(" num ","
114                                         pointer = 0;
115                                 } else
116                                         call = call "%p"
117                         } else if (argcount != 0) {
118                                 if ( argtype == "int" || argtype == "short" ) {
119                                         call = call "%d"
120                                         argtype = ""
121                                 } else if ( argtype != "" ) {
122                                         call = call "%s"
123                                         comma = comma "_trace" argtype "2(" num ","
124                                 } else {
125                                         call = call "%#lx"
126                                         comma = comma "(long)"
127                                 }
128                         }
129                         if (ch == ",")
130                                 args = args comma "a" ++num;
131                         else if (argcount != 0)
132                                 args = args comma "z"
133                         call = call ch
134                         if (pointer == 0 && argcount != 0 && argtype != "" )
135                                 args = args ")"
136                         if (args != "")
137                                 comma = ", "
138                         pointer = 0;
139                         argtype = ""
140                 }
141                 if ( i == 2 || ch == "(" )
142                         call = call ch
143         }
144         call = call "\")"
145         if (args != "")
146                 call = call ", " args
147         call = call ")); "
148
149         if (dotrace)
150                 printf "%s", call
151
152         if (match($0, "^void"))
153                 call = ""
154         else if (dotrace)
155                 call = "returnCode( ";
156         else
157                 call = "%%return ";
158
159         call = call $2 "(";
160         for (i = 1; i < argcount; i++)
161                 call = call "a" i ", ";
162         if (argcount != 0)
163                 call = call "z";
164         if (!match($0, "^void"))
165                 call = call ") ";
166         if (dotrace)
167                 call = call ")";
168         print call ";"
169
170         if (match($0, "^void"))
171                 print "%%returnVoid;"
172         print "}";
173 }
174 ' ) \
175 | sed \
176         -e '/^\([a-z_][a-z_]*\) /s//\1 gen_/' >$TMP
177   $preprocessor $TMP 2>/dev/null \
178 | $AWK '
179 BEGIN           {
180         print "/*"
181         print " * DO NOT EDIT THIS FILE BY HAND!"
182         print " * It is generated by MKlib_gen.sh."
183         print " *"
184         print " * This is a file of trivial functions generated from macro"
185         print " * definitions in curses.h in order to satisfy the XSI Curses"
186         print " * requirement that every macro also exist as a callable"
187         print " * function."
188         print " *"
189         print " * It will never be linked unless you call one of the entry"
190         print " * points with its normal macro definition disabled.  In that"
191         print " * case, if you have no shared libraries, it will indirectly"
192         print " * pull most of the rest of the library into your link image."
193         print " * Cope with it."
194         print " */"
195         print "#include <curses.priv.h>"
196         print ""
197                 }
198 /^DECLARATIONS/ {start = 1; next;}
199                 {if (start) print $0;}
200 ' \
201 | sed \
202         -e 's/          */ /g' \
203         -e 's/  */ /g' \
204         -e 's/ ,/,/g' \
205         -e 's/ )/)/g' \
206         -e 's/ gen_/ /' \
207         -e 's/^M_/#undef /' \
208         -e '/^%%/s//    /' \
209 | sed \
210         -e 's/^.*T_CALLED.*returnCode( \([a-z].*) \));/ return \1;/' \
211         -e 's/^.*T_CALLED.*returnCode( \((wmove.*) \));/        return \1;/'
212