# @(#)run 8.14 (Sleepycat) 11/6/97 # run -- # A mother of a shell script. It creates lists of functions which # can cause the public functions to fail. It depends on the code # using a Kernel Normal Form (KNF) coding style, but it shouldn't # be horrible to adapt to other styles. s=../../ TF="_1 _2 _3 _4 _5 _6 _7 _8 _9 _10 OK awk.out diff.out r_sub.1 r_sub.2" trap "rm -f $TF INPUT; exit 1" 1 2 3 13 15 rm -f $TF INPUT # Clean out the error file directory -- it must exist. edir=../../man/man.error [ ! -d $edir ] && { echo "$edir: no such directory." exit 1 } rm -f $edir/* # Clean out the debug directory if it exists. dd=./dd [ -d $dd ] && rm -f $dd/* # Find all the function calls. echo "find the function calls..." >_1 for i in btree common db dbm hash hsearch lock log mp mutex os txn; do cat $s/$i/*.c | sed -f func.sed >> _1 done # Tokenize, converting all whitespace and ^A characters into single # characters. echo "tokenize..." cat _1 | tr '[:space:]' '\n' | tr -s '\001' '\n' > _2 [ -d $dd ] && mv _1 $dd || rm -f _1 # Pull out all the tokens that interest us, i.e. the ones that have a ^B, # and then delete that character. echo "extract function names/calls..." cat _2 | egrep '' | tr -d '\002' > _3 [ -d $dd ] && mv _2 $dd || rm -f _2 # Delete the strings that we know can't be function calls in any package. # This has to happen before the next step so that we know that function # calls immediately precede their respective @START lines. echo "delete impossible function names/calls..." cat _3 | sed -f delete.sed > _4 [ -d $dd ] && mv _3 $dd || rm -f _3 # It's easy to end up with STOP lines that don't have matching START lines, # as it's not uncommon to find closing } characters on lines by themselves. # Delete anything between a STOP and the line before the next START. echo "delete singleton STOP lines..." cat _4 | awk -f stop.awk > _5 [ -d $dd ] && mv _4 $dd || rm -f _4 # Make adjustments for special DB names. echo "apply special DB corrections..." cat _5 | sed -f db.sed > _6 [ -d $dd ] && mv _5 $dd || rm -f _5 # Indent the function calls inside of the function names, and delete the # leading @ characters. echo "indent function call lines..." cat _6 | sed '/@START/,/@STOP/s/^/ !/' | tr -d '@' > _7 [ -d $dd ] && mv _6 $dd || rm -f _6 # Eliminate duplicate calls inside of each function. echo "eliminate duplicate function calls..." cat _7 | awk -f clean.awk > INPUT [ -d $dd ] && mv _7 $dd || rm -f _7 # Build a set of sed commands that will do substitution on the names. echo "build sed commands for substitution..." cat INPUT | sed -n -f sub.sed | tr '' '\012' > r_sub.1 # Put a list of the public names into _8. echo "extract public names..." awk -f pub.awk < INPUT > _8 [ -d $dd ] && mv INPUT $dd # Loop, substituting names until there are no more names to substitute. # # We can get into a place where we're just shuffling stuff and not making # any forward progress -- you'll see the reference count climb and then # drop, and eventually it's staying about the same over several iterations. # That's what OK is for. Create the OK file and we break out of the loop # and continue on. echo "loop, substituting inside public names..." echo "create file named \"OK\" to terminate loop." cnt=0 while (true); do cnt=`expr $cnt + 1` printf "run #%02d... " $cnt # Do a substitution pass, and then sort the names, eliminating # any duplicates. sed -f r_sub.1 < _8 | sed '/^$/d' | awk -f clean.awk > _9 # If you want to see what changed. # diff _8 _9 > diff.out # Print out a progress report. a=`egrep __ _8 | wc -l` b=`egrep __ _9 | wc -l` printf "unexpanded calls: orig: %d new: %d\n" $a $b # If no substitution was done, then we're finished. This never # happens, at least in DB, because we have places where A calls # B and B calls A, so we end up simply swapping call expansions # forever. Once the reference counts aren't getting any further, # create the file "OK" and the script will proceed. if cmp _8 _9 > /dev/null; then break; fi mv _9 _8 if [ -f OK ]; then break; fi done rm -f OK # Check for stuff we missed... #echo "Functions that were never resolved:" #egrep __ _8 # At this point, we're simply swapping calls between routines that call each # other and we're not making any forward progress. Strip out all of the DB # internal routines from the replacement process and do a final replacement # to finish up. echo "final substitution pass for co-routines..." sed -e '/^ /s/__.*\(.\)$/DISCARD\1/' < r_sub.1 > r_sub.2 sed -f r_sub.2 < _8 | sed -e '/DISCARD/d' -e '/^$/d' > _9 [ -d $dd ] && mv _8 $dd || rm -f _8 [ -d $dd ] && mv r_sub.1 $dd || rm -f r_sub.1 [ -d $dd ] && mv r_sub.2 $dd || rm -f r_sub.2 # Convert all of the entries into man page references. echo "convert to man page references..." sed -f conv.sed < _9 > _10 [ -d $dd ] && mv _9 $dd || rm -f _9 # Put each function's information into a separate file, which we include # from the actual man page. echo "create error return files..." cat _10 | while read one rest; do if [ "$one" = "FUNCTION" ]; then file=`echo "$rest" | sed 's/.*->//'` else echo "$one $rest" >> "$edir/$file" fi done [ -d $dd ] && mv _10 $dd || rm -f _10 # We translated all the special function names into xxxDB, convert them # back to the correct name here. echo "clean up DB names in error files..." for i in $edir/*; do sed -e 's/xxxDB/DB/g' < $i > _1 mv _1 $i done rm -f _1 # Create the C++ version of the file. echo "create c++ error files..." for i in $edir/*; do sed -f cxx.sed < $i > $i.cxx done # Sort the names in each file, eliminating duplicates. echo "sort and discard duplicates..." for i in $edir/*; do sort -u < $i > _1 mv _1 $i done rm -f _1 # Replace the last comma with a period. If it's more than a single entry, # add an "and" before the last line. echo "final cleanup of error files..." for i in $edir/*; do cnt=`wc -l $i | awk '{print $1}'` if [ $cnt -gt 1 ] ; then sed -e '1i\' -e '.na\' -e '.Nh' -e '$s/,/./' \ -e '$i\' -e 'and' -e '$a\' -e '.Hy\' -e '.ad' < $i > _1 else sed -e '1i\' -e '.na\' -e '.Nh' -e '$s/,/./' \ -e '$a\' -e '.Hy\' -e '.ad' < $i > _1 fi mv _1 $i done rm -f _1 # Set the permissions. chmod 444 $edir/* # Cleanup. rm -f $TF INPUT exit 0