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