#!/usr/local/bin/perl # Geoffrey Furnish # Institute for Fusion Studies # University of Texas at Austin # 27 June 1995 # # This script is used to automatically generate most of the functions needed # to implement the PLplot Tcl API. It reads a file which specifies the # PLplot API command arguments and return value (basically like a C # prototype, but easier to parse) and generates a Tcl command procedure to # call that function. # # Currently it can support arguments of type PLINT, PLFLT, char *, PLINT& # and PLFLT& where the last two are used for the 'g' series functions which # provide data to the caller. # # What is not supported at this time, but needs to be, is support for (those # few) PLplot API functions with non-void return types, and (the many) # PLplot API functions which accept arrays (PLFLT *, etc). The latter can # in many cases be correctly treated as 1-d Tcl Matricies. The code for # using these should be sufficiently perfunctory to be amenable to an # approach like that used here. Automatic support for the 2-d API is # probably unrealistic. ############################################################################### require "getopts.pl"; &Getopts('v'); $verbose = $opt_v; # Find the source tree directory that must be specified on the command line. $sourcedir = $ARGV[0]; $specfile = "$sourcedir/plapi.tpl"; # PLplot API template specification file. $genfile = "tclgen.c"; # Generated functions go here. $genhead = "tclgen.h"; # Prototypes for generated functions. $genstruct= "tclgen_s.h"; # Initializers for CmdInfo struct. $cmdfile = "$sourcedir/tclcmd.tpl"; # Template file for generated functions. open( SPECFILE, "<$specfile") || die "Can't open PLplot API spec file."; open( GENFILE, ">$genfile" ) || die "Can't open output file."; open( GENHEAD, ">$genhead" ) || die "Can't open output header file."; open( GENSTRUCT,">$genstruct")|| die "Can't open second output header file."; # Scan the PLplot API template specification file looking for function # "prototypes". These are introduced with the token "pltclcmd". When # we find one, go process it. Anything other than a comment or a # valid function "prototype" is considered an error, and is printed to # stdout. while( ) { chomp; # skip the \n. if (/([^\#]*)\#.*/) { # Discard # to end of line. $_ = $1; } next if /^\s*$/; # Discard empty lines. if (/^pltclcmd (\w+) (.*)/) { $cmd = $1; $rtype = $2; &process_pltclcmd( $cmd, $rtype ); next; } # Just print the unrecognized output to stdout. print "$_\n"; } # Process a function "prototype". Suck up the args, then perform the # needed substitutions to the Tcl command procedure template. # Generate the three outputs needed for use in tclAPI.c: the C # function prototype, the CmdInfo structure initializer, and the # actual function definition. sub process_pltclcmd { local( $cmd, $rtype ) = @_; local( $i, $refargs ); local( $vname, $vtype ); local( $args ); print "autogenerating Tcl command proc for $rtype $cmd ()\n" if $verbose; print GENHEAD "static int ${cmd}Cmd( ClientData, Tcl_Interp *, int, char **);\n"; print GENSTRUCT " {\"$cmd\", ${cmd}Cmd},\n"; $args = ""; $nargs = 0; $ndefs = 0; $refargs = 0; while( ) { chomp; last if /^$/; if (/^(\w+)\s+(.*)$/) { $vname = $1; $vtype = $2; $defval = ""; print "vname=$vname vtype=$vtype\n" if $verbose; if ($vtype =~ /\s*(.*)\s+Def:\s+(.*)/) { $vtype = $1; $defval= $2; print "default arg: vtype=$vtype defval=$defval\n" if $verbose; } $argname[ $nargs ] = $vname; $argtype[ $nargs ] = $vtype; $argdef[ $nargs ] = $defval; $argref[ $nargs ] = 0; # default. # Check to see if this arg is for fetching something from PLplot. if ($vtype =~ /&/ || $vtype eq "char *") { $refargs = 1; $argref[ $nargs ] = 1; } if ($nargs == 0) { $args .= "$vname"; } else { $args .= " $vname"; } $ndefs++ if $defval ne ""; $nargs++; next; } # Unrecognized output. print "bogus: $_\n"; } if ($verbose) { print "There are $nargs arguments, $ndefs are defaultable.\n"; for( $i=0; $i < $nargs; $i++ ) { print "$argtype[$i] $argname[$i]\n"; } print "return string required.\n" if $refargs; } open( TEMPLATE, "<$cmdfile" ) || die "Can't open tcl cmd template file."; while(