.BSET - parse a string into arguments.

Usage:

B:
   parsed = .bset( string, [ buffer, size, options ] );

Where:

parsed
is a word whose value is "argc<<18 | argv". "argv" is a pointer to a vector of argument descriptors; an additional word with the value -1 marks the end of this vector. "argc" is the number of elements in "argv"; since "argv[0]" is the first argument, "argv[argc]" is the word which contains the terminating -1.
string
is the string to be parsed. When .BSET is called by the B initialization routines (before execution of MAIN begins), the string to be parsed is the command line.
buffer
is a work area used to hold the vector of argument descriptors and the data for those arguments which have values (see below). If "buffer" is not specified, .BSET will create its own buffer by calling GETVEC to obtain a vector of 100 words (maximum subscript 99).
size
is the size of the work buffer. If the "size" argument is not specified, .BSET expects the required value to be found in "buffer[-1]". (This is where the buffer size will be found if, for example, the buffer was obtained using ALLOCATE.)
options
is a table of keywords and options whose format is discussed below. If no "options" table is specified, .BSET will look for an external vector named ".optab".

Description:

The .BSET function was designed to help with the process of scanning a command line. C programmers should use the similar function "parse" instead of .BSET.

.BSET will first take a string and break it up into arguments separated by blanks or tabs. You can specify an argument containing blanks or tabs by enclosing the argument in single or double quotes; any quotes which appear in the command line are stripped away by .BSET before being passed to your program. When .BSET has broken up the command line, it will return a vector of descriptors for the arguments which appeared on the line. In the simplest case, the vector of descriptors is a vector of pointers to the arguments themselves. To use .BSET for more sophisticated scanning processes, you can pass the function an options vector, either with the argument "options" or with the external vector ".optab".

Normally .BSET is invoked by the B initialization routines, and the resulting "argc" and "argv" are passed as the arguments of MAIN. .BSET is then released after it has processed the command line. However, .BSET can also be made available to your program for general use. This is done by setting the external variable ".keep" to the value one with a declaration of the form:

.keep {1};

in your program's source. If ".keep" is not given a non-zero value, .BSET will be released.

When calling .BSET, you may omit optional trailing arguments if you so choose (as in ".bset(string,buffer)"). You may omit internal arguments by specifying the value 0400000000000 in place of the missing argument. You may not omit the argument "buffer" if you specify "size".

In addition to "argc" and "argv" .BSET also builds an external vector ".argtype" which contains a type entry for each element of "argv". For more details see "expl b lib external .argtype".

I/O redirection:

.BSET will interpret arguments beginning with '<', '>' and '>>' as input/output redirection commands, and will not place them in "argv". An argument of the form "<filename" will cause .BSET to open "filename" for read on unit 0 (standard input). ">filename" opens "filename" for write on unit 1 (standard output). ">>filename" is similar except that "filename" is opened for append. Automatic redirection may be suppressed by use of the external variable ".process". For details see "expl b lib external .process".

The Option Table:

.BSET has powerful facilities for recognizing options and keywords of certain forms in the given string. To have .BSET recognize a keyword or an option containing a keyword, you must describe the keyword in the "options" vector or in the external vector ".optab". This vector is made up of two-word entries and is terminated by a word containing -1. Each two-word entry consists of a pointer to a string containing the keyword, and a constant specifying the form in which the keyword may appear. An argument matches a keyword entry if the argument is of the specified keyword form and consists of the given keyword (or a reasonable abbreviation).

"b/manif/.bset" lists manifest constants for each keyword form. These manifests are

COMM_KWD
Command name keyword: this can only match the first argument in the input string.
DASH_KWD
This matches arguments of the form -<keyword>.
PLUS_KWD
This matches arguments of the form +<keyword>.
BLNK_KWD
This matches arguments of the form <keyword>.

The above three manifests may be or'd together in any combination to indicate that a keyword will be recognized in the given variety of forms. For any descriptor in "argv", the form matched may be determined by examining the corresponding entry in ".argtype".

DVAL_KWD
Decimal value keyword: This matches an argument of the form "<keyword>=<number>". The number is interpreted as a decimal number.
OVAL_KWD
Octal value keyword: This is similar to DVAL_KWD except that the number is interpreted as an octal number.
NVAL_KWD
Numeric value keyword: This is similar to the above two types, but the first digit is used to determine whether the number is interpreted as octal or decimal. If the first digit is '0' the number is taken as octal; otherwise it is taken as decimal.
MNVL_KWD
Multiple numeric value keyword: this matches keywords of the forms
<keyword>=<number>[,<number>]*
       or
<keyword>="<number>[ <number>]*"

For example,

<keyword>=1,2,3,4,5
<keyword>="1 2 3 4 5"

are equivalent. The numbers are interpreted as octal or decimal according to the first digit rule described above.

MDVL_KWD
Multiple decimal value keyword: This is similar to MNVL_KWD, but the numbers are interpreted in decimal.
MOVL_KWD
Multiple octal value keyword: This is similar to MNVL_KWD, but the numbers are interpreted in octal.
SVAL_KWD
String-valued keyword: this matches keywords of the form "<keyword>=<string>", where <string> is enclosed in single or double quotes (which are stripped).

Keywords must be specified in full in the options vector. .BSET calls the library function .ABBRV to determine if an argument in the input line is a valid abbreviation of a keyword in the options vector. Thus you must specify keywords in the format used by .ABBRV (see "expl b lib .abbrv").

"argv" Entries with Options Table:

When .BSET discovers an argument which matches a keyword, it sets the upper half of the argument's descriptor in "argv" to the number of the keyword in the options table. Numbering begins at one; thus if a given argument matches the third keyword, the upper half of that argument's descriptor would be set to three (even though the two-word entry for the keyword would begin in the fifth word of the vector).

If the matching keyword is in one of the forms which has an associated value (e.g. NVAL_KWD, MNVL_KWD, SVAL_KWD, etc.), .BSET will put a pointer to the value in the lower half of the argument's descriptor in "argv". For a string-valued keyword, the pointer is to the string. For a numeric value keyword, the pointer is to a word containing the given number. (Thus if an argument is of the form "key=10", the lower half of the argument's descriptor will point to a word containing the decimal constant 10.) For a multiple numeric value keyword, the pointer is to a word containing a count of the number of values supplied. Immediately following the "count" word in memory are words containing the specified numbers in numeric form. (Thus if an argument is of the form "keys=10,20,30", the lower half of the argument's descriptor would point to a vector of four words; the zero'th word of the vector would contain the number three, and the following three words would contain the numbers 10, 20, and 30, respectively.)

If an argument is a simple string (no leading '+' or '-' sign and no imbedded '=') or a quoted string, the "argv" entry consists only of a pointer to the argument in the lower half of the word (as usual).

If an argument looks like an option (i.e. it is of the form "-arg" "+arg" or "arg=str") but does not match any keyword in the options table, the lower half of the argument descriptor is a pointer to a string containing the argument and the upper half of the descriptor contains a number which is ONE MORE than the number of keyword entries in the options table. This arrangement is intended to facilitate the identification of unrecognized options. If automatic I/O redirection is suppressed with ".process" arguments of the form ">str", ">>str" and "<str" show up as unrecognized options.

Sample code:

/* define manifests for option table */
%b/manif/.bset

/*
 * define options used by this command.
 */
.optab[] {
    "Example", COMM_KWD,
    "Verbose", PLUS_KWD,
    "Brief", PLUS_KWD,
    "Messages", PLUS_KWD | DASH_KWD,
    "Banner", SVAL_KWD,
    "Heading", SVAL_KWD,
    "Coresize", NVAL_KWD,
    "Library", SVAL_KWD,
    "Select", MNVL_KWD,
    -1 /* end of list */
};

/*
 * define a set of our own manifest constants for the
 * option index numbers returned by .bset
 */
STRING = 0;
EXAMPLE = 1;
VERBOSE = 2;
BRIEF = 3;
MESSAGE = 4;
BANNER = 5;
HEADING = 6;
CORESIZE = 7;
LIBRARY = 8;
SELECT = 9;

main( argc, argv ) {
   auto info, verbose_sw, title, libfile, coresz;
   auto i, j, nselect, selects[20];
   extrn .argtype;

/*
 * loop on each table entry until end-of-table.
 * switch on the option index number, and act according
 * to the option type defined in option table
 */
   for( i = 0; i < argc; ++i) {
       info = argv[i] & 0777777;
       switch ( argv[i]>>18 ) {
           case EXAMPLE:
               break;
           /*
            * Dash options, set switch accordingly
            */
           case VERBOSE
               verbose_sw = 1;
               break;
           case BRIEF:
               verbose_sw = 0;
               break;
           case MESSAGE:  /* plus or dash keyword */
               switch( .argtype[i] ){  /* find out which */
                   case '+':
                       verbose_sw = 1; break;
                   case '-':
                       verbose_sw = 0; break;
               }
               break;
           /*
            * String-valued option, so save the string
            */
           case BANNER:
           case HEADING:
               title = info;
               break;
           case CORESIZE: /* number, so save binary value */
               coresz = *info;
               break;
           case LIBRARY: /* save filename */
               libfile = info;
               break;
           case SELECT:
               /* many valued keyword, pick up each value */
               nselect = *info;
                    /* save count of values */
               for( j = 0; j < nselect; ++j )
                   selects[j] = *++info;
               break;
           case STRING:
               /*
                * not an option, but an argument of the
                * command. This might be a file to compile,
                * or a snumb, userid, or any other string
                * argument for the command to work with.
                */
               break;
           default:  /* option not found in table */
               error( "%s unknown option*n", info );
           }
       }
   /*
    *  the rest of the program would use the variables to
    *  perform its functions
    */
   }

Command Line Examples:

example +verbose l=/mylib
turns verbose switch on and sets library file to /mylib
example +brief cor=12 banner="look out"
turns verbose switch off, sets core size to 12, and sets banner to the string "look out"
example +mess l=tlib
turns verbose switch on and sets library file to tlib
example -msg l=tlib
turns verbose switch off and sets library file to tlib
example +b hdg="look out"
note abbreviation of "+Brief" and "Heading"
example sel=1,2,3,5,8,13 junk
the vector named "selects" gets six numbers; "junk" is a string argument
example c=12
keyword "Coresize" gets value 12
example b=error
this will cause an error; .BSET will not mistake this for the "+Brief" option, since it is able to distinguish between flag and value keywords

See Also:

expl b entry

expl b lib .abbrv

expl b lib external .keep

expl b lib external .process

Copyright © 1996, Thinkage Ltd.