B: parsed = .bset( string, [ buffer, size, options ] );
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".
.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".
.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
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".
<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.
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").
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.
/* 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 */ }
Copyright © 1996, Thinkage Ltd.