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