# This TAWK program attempts to automatically create function prototypes # from C program source files. # Use it like this: awk -f mkextern.awk *.c > extern.h BEGIN { # pflag is 1 to include full function prototypes, # or 0 to include simple extern return value declarations. pflag = 1 FUNARG = "\\([a-zA-Z0-9_* \\t]*\\)[ \\t]*\\([ \\t]*\\)" OTHERARG = "[a-zA-Z0-9_* \t]+" ANYARG = "(" FUNARG "|" OTHERARG "|" "[ \\t,]" ")" ANYARGS = ANYARG "*" FUNDEF = ANYARGS "\\(" ANYARGS "\\)" } # These were used for debugging this script: # $0 ~ "^" FUNARG "$" { print "matched FUNARG" } # $0 ~ "^" OTHERARG "$" { print "matched OTHERARG" } # $0 ~ "^" ANYARG "$" { print "matched ANYARG" } # $0 ~ "^" ANYARGS "$" { print "matched ANYARGS" } # $0 ~ "^" FUNDEF "$" { print "matched FUNDEF" } FNR == 1 { if (NR != 1) print "" print "/* From",FILENAME print " */" } # The following pattern skips over obvious procedure bodies, # allowing this AWK program to run much faster. # The curly braces must appear in column 1. # If you use a different convention for procedure bodies you can remove this. /^{/ { inparens = 1; next } /^}/ { inparens = 0; next } inparens { next } # Skip any line that begins with a comment. /^[ ]*\/\*/ { next } # Skip over pre-processor lines. /^#/ { next } # Added 10-91: Attempt to detect a function decl that is # more than one line long. Continue to next rule. /^[a-zA-Z_]+[a-zA-Z0-9_* \t]*\([a-zA-Z0-9_*, \t]*$/ { getline nextline $0 = $0 nextline } # A function definition begins in column one and is followed # by a parenthesized list not followed by a semi-colon. # If you use a different convention for function definitions # you will have to change this. # OLD: /^[^ ]/ && /^[^;\/]*\([^)]*\)[^,;]*$/ # /^[a-zA-Z_]+[a-zA-Z0-9_* \t]*\([a-zA-Z0-9_*, \t]*\)[ \t]*$/ { $0 ~ ("^[a-zA-Z_]" FUNDEF "[ \\t]*$") { decl = substr($0,1,index($0,"(") - 1) if (decl ~ /\"/) next # Skip strings sub(/[ \t]*$/,"",decl) n = split(decl,va,"[ \t*]+") if (va[1] == "static") next; # Skip static functions. # If not doing prototypes and no interesting type information, skip it. if (pflag == 0 && n == 1) next; # Sometimes functions sneak into the output, so eliminate obvious garbage. rtnname = va[n] if (rtnname == "if") next if (rtnname == "do") next if (rtnname == "while") next if (rtnname == "switch") next if (rtnname == "main") next # Changed 10-91 to provide full MSC function prototypes # 7-92: Include support for multi-line decls. if (pflag == 0) { print "extern",decl "();"; next } decls = "" while (1) { if (getline aline <= 0) { print "mkextern: error: unexpected end of file:",FILENAME > "CON" exit } if (incomment) { if (sub(/.*\*\//,"",aline)) { incomment = 0 aline = savealine } else { continue; } } gsub(/\/\*.*\*\//s,"",aline) # Remove comments if (sub(/\/\*.*/,"",aline)) { savealine = aline incomment = 1; continue; } if (aline ~ /{/) { inparens = 1; break } gsub(/^[ \t]*|[ \t]*$/,"",aline) # Remove extra spaces # Skip blank lines if (! index(aline,";")) continue # Handle multiple decls on a line. # for example: int argc; char **argv; # xtmp[1] would be "int argc" and xtmp[2] would be "char **argv" sub(/;[ \t]*$/,"",aline) split(aline,xtmp,";") for (i in xtmp) { decl1 = xtmp[i] #print "***DECL1:",decl1 > "CON" # Check for multiple decls separated by commas, # things like this: code *this,*that; if (index(decl1,",")) { # Locate the local variable name in the first declaration. match(decl1,"\\**[ \t]*[a-zA-Z0-9_]+[ \t]*,") # typepart is the type part of the first variable declaration. typepart = substr(decl1,1,RSTART-1) nn = split(decl1,ytmp,",") decls = (decls?decls",":"") ytmp[1] for (i = 2; i <= nn; i++) { decls = (decls?decls",":"") typepart " " ytmp[i] } } else { decls = (decls?decls",":"") decl1 } } } if (decls) { sub(/\(.*\)/,"",$0) $0 = $0 "(" decls ")" } sub(/\(\)/,"(void)",$0) gsub(/[ \t]+/," ",$0) # Squeeze adjacent spaces print "extern",$0 ";" } # Ignore all other lines { next }