#!/usr/bin/awk -f # This software is distrubted under the GPL # autofunc 0.1: grab function prototypes from a C++ header file, and paste # into corresponding .cc file if they are not already present # return the substr matched function getsub(str, pat) { match(str, pat) return substr(str, RSTART, RLENGTH) } # remove unnecessary whitespace so as not to fuck up our parsing function remspace() { gsub(/[ \t]+/, " ") # squeeze white space to a single space # remove space before and after operators gsub(/ *:: */, "::") gsub(/ *& */, "&") gsub(/ *\* */, "*") } # return number of consecutive spaces (tabs=8spaces) from start of line # (ie, the indent level) function getindent(str, x) { x = str; gsub(/\t/, " ", x) if (match(x, "^" space)) { if (RLENGTH > imax) imax = RLENGTH return RLENGTH } return 0 } # return the function name given a string that is thought a function function getfuncname(str, f, i, c) { f = getsub(str, type id optspace "\(") f = getsub(f, id optspace "\(") if (!f) return "" f = getsub(f, id) return f } # return a string of class names for prepending to a funcname # ie, Outer::Middle::Inner:: function getclassnames( c) { c = "" for (i=0; i <= bmax; i++) { if (classes[i]) { c = c classes[i] "::" } } return c } # get parameter list with variable names removed function getparams(str, p, ps, i, Ts) { p = getsub(str, paramlist) split(p, Ts, "[(),]") for (i in Ts) { sub("^" space, "", Ts[i]) if (Ts[i]) { p = getsub(Ts[i], type) sub(space "$", "", p) if (ps) ps = ps "," p else ps = p } } return ps } # remove the function at index i from the list function remfunc(rem, i,j) { delete func_name[rem] delete func_params[rem] delete func_pretty[rem] } # check if str matches a function in the function list function matchfunc(str, i, ps) { for (i in func_name) { if (match(str, func_name[i])) { # matches the function name - now match the params ps = getparams(str) if (ps == func_params[i]) return i } } return 0 } # adds function declarations to the .cc file function addfuncs(file, i) { while (getline > file print "{\n}\n" >> file print progname ": added to " file ": " func_pretty[i] } print progname ": done processing " file close(file) } # ends processing of an .h file function endfile() { if (basename) { addfuncs(basename cc_ext) } brace = 0 delete classes delete func_name delete func_params delete func_pretty } BEGIN { progname = "autofunc" cc_ext = ".cc" id = "[_A-Za-z~][_A-Za-z0-9]*" keyword = "(const|signed|unsigned|static|virtual)" type = "(" keyword "[ \t]+)?" "[_A-Za-z][_A-Za-z0-9]*[ \t*&]*" space = "[ \t]+" optspace = "[ \t]*" paramlist = "\([^)]*\)" hfile_rx = "\.(h|hh|hpp|hxx|H)$" } # if FNR==1, a new file has begun FNR==1 { endfile() if (!match(FILENAME, hfile_rx)) { print progname ": filename must have in a valid C++ header extension" exit 1 } basename = FILENAME sub(hfile_rx, "", basename) } # get the class name # support for nested classes $0 ~ "(class|struct)" space id { ilevel = getindent($0) for (i=1; i <= NF; i++) { if ($i == "class" || $i == "struct") { classes[brace] = $(i+1) break } } } # class ended /};/ { classes[brace-1] = "" } # keep track of braces so we know when the current function ends /[{}]/ { tmp = $0 while (tmp ~ /{/) { brace++ sub(/{/, "", tmp) } while (tmp ~ /}/) { brace-- sub(/}/, "", tmp) } if (brace > bmax) bmax = brace } # matches a function decl $0 ~ ("\)" optspace "(const)?" optspace ";" optspace "$") { # make sure we're not matching part of a function body if (brace > 0 && classes[brace-1] == "") next gsub("/\*([^*]|\*[^/])*(\*/|$)" , " ") # remove comments gsub("//.*" , " ") # remove comments pretty = $0 remspace() funcname = getfuncname($0) if (!funcname) next params = getparams($0) # the pretty version of the function: for use in the .cc file # get rid of the ;, post-const, virtual/static, leading space, and # default parameter values. prepend class names gsub("[ \t]+", " ", pretty) sub("\)" optspace "(const)?" optspace ";", ")", pretty) sub(funcname, getclassnames() funcname, pretty) gsub("(virtual|static)", "", pretty) gsub("=[^,)]+", "", pretty) sub("^[ \t]+", "", pretty) funcs++ # start at 1 func_name[funcs] = getclassnames() funcname func_params[funcs] = params func_pretty[funcs] = pretty } END { endfile() }