#!/usr/bin/awk -f ########################################################################## ## ^FILE: parseargs.awk - parseargs for awk programs ## ## ^DESCRIPTION: ## This file defines an awk function named parseargs to parse ## command-line arguments for awk scripts. It also contains a ## bare-bones template of what such an awk-script might contain. ## ## ^HISTORY: ## 02/21/91 Brad Appleton Created ###^^##################################################################### ######### ## ^FUNCTION: parseargs - parse command-line argument vectors ## ## ^SYNOPSIS: ## parseargs( argc, argv, argd, arr ) ## ## ^PARAMETERS: ## argc -- the number of elements in argv (usually ARGC-1). ## argv -- the vector of command-line arguments (usually ARGV). ## argd -- the argument-description string ## arr -- the associative array to assign command-line values from ## ## ^DESCRIPTION: ## Parseargs will invoke parseargs(1) to parse the command-line given ## in for the command defined by . The resulting values ## will be assigned to elements of the associative array given by . ## Values are assigned using using the syntax: arr [ "argname" ] = value; ## The exception to this is that if the is "ARGV" then the global ## array ARGV is reset to the given array (using tab separated fields). ## ## ^REQUIREMENTS: ## Any desired initial values for items in should be assigned BEFORE ## calling this function (using the syntax: arr[ "argname" ] = initial-val). ## ## The following global variables may be assigned before calling parseargs: ## ## PROGNAME -- name of the current awk script (default= ARGV[0]) ## PARSEOPTS -- any extra options to pass toi parseargs() (default="-ul") ## PARSEINPUT -- input file for parseargs(1) (default=unique-name) ## PARSEOUTPUT -- output file for parseargs(1) (default=unique-name) ## ## ^SIDE-EFFECTS: ## The files PARSEINPUT and PARSEOUTPUT are created and then deleted. ## ## The return value from parseargs(1) will be stored in the global-variable ## named PARSESTATUS. ## ## The global variable PARSEARGS will contain the command-line used to ## invoke parseargs(1). ## ## ARGV and ARGC may be reset, all other values are (re)set in . ## ## ^RETURN-VALUE: ## The exit code returned by parseargs(1). ## ## ^BUGS: ## Due to the limited ability of awk, scripts using parseargs(1) cannot ## use short-options (with a dash '-') because awk will attempt to interpret ## any such arguments as options to awk and remove them from ARGV (regardless ## of whether or not they are valid awk-options). Keyword options (with a ## plus sign '+') may still be used without this difficulty. Dash-options ## may be successfully processed if they did not first appear on the command ## to the awk-script, so the full syntax of unix-style options could be ## provided in an array other than ARGV. ## ## ^ALGORITHM: ## - set defaults for PROGNAME, PARSEOPTS, PARSEINPUT, and PARSEOUTPUT. ## - build the parseargs command (dont forget to quote arguments). ## - redirect input and output of the parseargs command. ## - run parseargs(1) ## - assign the exit-code from parseargs(1) to PARSESTATUS ## - remove PARSEINPUT ## - if PARSESTATUS != 0 ## - save RS and FS and reset RS = "" and FS = "\n" ## - for each record in PARSEOUTPUT ## - $1 is the argname and $2 is the value ## - if $1 is "ARGV" reset ARGV and ARGC ($2 is a tab separated array) ## - else assign arr[ $1 ] = $2 ## end-for ## - restore RS and FS to previous values ## - remove PARSEOUTPUT ## - return PARSESTATUS ###^^#### function parseargs(argc, argv, argd, arr) { ## set defaults -- use $$ to get a unique suffix string if ( ! PROGNAME ) PROGNAME = ARGV[0]; if ( ! PARSEOPTS ) PARSEOPTS = "-u -l"; "echo ${TMP:-/tmp}/parseargs.${$}_" | getline TMPFILE; if ( ! PARSEINPUT ) PARSEINPUT = TMPFILE "in"; if ( ! PARSEOUTPUT ) PARSEOUTPUT = TMPFILE "out"; ## build the options and required arguments for parseargs(1) PARSEARGS = sprintf( "parseargs -s awk %s -- '%s'", PARSEOPTS, PROGNAME ); ## quote each elemnt in argv and append it to the parseargs-command for ( i = 1 ; i <= argc ; i++ ) { arg = argv[i]; gsub( /'/, "'\\''", arg ); PARSEARGS = PARSEARGS " '" arg "'"; } ## set up i/o redirection PARSEARGS = PARSEARGS " <" PARSEINPUT " >" PARSEOUTPUT; print argd > PARSEINPUT; ## invoke parseargs(1) and save the status PARSESTATUS = system( PARSEARGS ); system( "/bin/rm -f " PARSEINPUT ); ## dont need input anymore ## if successful status, read the result if ( PARSESTATUS == 0 ) { save_RS = RS; save_FS = FS; RS = ""; FS = "\n"; while ( getline < PARSEOUTPUT > 0 ) { gsub( /\034/, "\n" ); if ( $1 == "ARGV" ) { ARGC = 1 + split( $2, ARGV, "\t" ); ARGV[0] = PROGNAME; } else arr[ $1 ] = $2; } RS = save_RS; FS = save_FS; } system( "/bin/rm -f " PARSEOUTPUT ); return PARSESTATUS; } BEGIN { PROGNAME = "test.awk"; ARGD = sprintf( "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s", "'?', ARGHIDDEN, argUsage, NULL, 'Help : print usage and exit'" , "'S', ARGVALOPT, argStr, string, 'STRing : optional string arg'" , "'g', ARGLIST, argStr, groups, 'newsGROUPS : groups to test'" , "'r', ARGOPT, argInt, count, 'REPcount : group repeat count'" , "'d', ARGOPT, argStr, dirname, 'DIRectory : working directory'" , "'x', ARGOPT, argBool, xflag, 'Xflag : turn on X-mode'" , "'y', ARGOPT, argUBool, yflag, 'Yflag : turn off Y-mode'" , "'s', ARGOPT, argChar, sepch, 'SEPchar : field separator'" , "'f', ARGLIST, argStr, files, 'files : files to process'" , "' ', ARGREQ, argStr, name, 'name : name to use'" , "' ', ARGLIST, argStr, argv, 'argv : any remaining arguments'" , "ENDOFARGS" ); Args[ "count" ] = 1; Args[ "dirname" ] = "."; Args[ "sepch" ] = ","; Args[ "yflag" ] = "TRUE"; rc = parseargs( ARGC-1, ARGV, ARGD, Args ); if ( rc != 0 ) exit( rc ); ## print the parsed arguments (use defaults if not defined) print "ARGUMENTS:"; print "=========="; for ( i in Args ) printf( "Args[\"%s\"] = \"%s\"\n", i, Args[i] ); argc = split( Args[ "argv" ], argv, "\t" ); for ( i = 1 ; i <= argc ; i++ ) printf( "argv[%d] = \"%s\"\n", i, argv[i] ); }