Tabular(3pm)
π Tabular(3pm) β Getopt::Tabular π
okay bestie, welcome to the manual page for Tabular(3pm), filed under User Contributed Perl Documentation, and it's literally the Getopt::Tabular module: table-driven argument parsing for Perl 5. grab a snack, this one's a whole saga. π
β¨ NAME β¨
Getopt::Tabular β table-driven argument parsing for Perl 5. that's it, that's the name, and it ate. π
π SYNOPSIS π
use Getopt::Tabular;
(or)
use Getopt::Tabular qw/GetOptions
SetHelp SetHelpOption
SetError GetError/;
...
&Getopt::Tabular::SetHelp (long_help, usage_string);
@opt_table = (
[section_description, "section"],
[option, type, num_values, option_data, help_string],
...
);
&GetOptions (\@opt_table, \@ARGV [, \@newARGV]) || exit 1;
π DESCRIPTION π
So. Getopt::Tabular is a Perl 5 module for table-driven argument parsing, and it was vaguely inspired by John Ousterhout's Tk_ParseArgv. πΈ
The whole vibe? You build one little table describing all your command-line options, and then you call &GetOptions with three args: a reference to your option table, a reference to @ARGV (or something like it), and an optional third array reference (say, to @newARGV). That's it. &GetOptions processes every argument in @ARGV, and copies the leftovers β meaning anything that's not an option or an argument to some option β over into the @newARGV array. π«Ά And if you don't hand it the @newARGV argument, then GetOptions just replaces @ARGV with that stripped-down argument list. And if anything in there is invalid, GetOptions prints an error message and returns 0. no cap.
Before we get into why Getopt::Tabular is a whole wonderful thing, lemme define the terminology that keeps popping up here. iykyk. β¨
- argument β any single word that shows up on the command line, aka one element of the
@ARGVarray. - option β an argument that starts with a certain sequence of characters; the default is
-. (and if you're a GNU-style-options girlie, you can change this to--.) In most Getopt::Tabular-based applications, options can appear anywhere on the command line, and their order doesn't matter (unless one option overrides a previous option). Also, Getopt::Tabular will happily accept any non-ambiguous abbreviation of options. iconic behaviour honestly. - option argument (or value) β an argument that comes immediately after certain types of options. For example, if
-foois a scalar-valued integer option, and-foo 3is on the command line, then3is the argument to-foo. - option type β this controls how
GetOptionsdeals with an option and the arguments following it. (ngl, for most option types, the type interacts with thenum_valuesfield, which is what decides whether the option is scalar- or vector-valued. we'll get to all of that in due course, promise.)
π FEATURES π
okay now for the advertising section, aka why Getopt::Tabular is a good thing, bestie:
- Command-line arguments are carefully type-checked, both by pattern and by number β like, if an option requires two integers,
GetOptionsmakes sure that exactly two integers follow it. periodt. π₯ - The valid command-line arguments live in a data structure that's completely separate from the call to
GetOptions; this makes it way easier to have super long lists of options, and to parse options from multiple sources (e.g. the command line, an environment variable, and a configuration file). multi-source queen. π Getopt::Tabularcan intelligently generate help text based on your option descriptions. it's giving helpful. π- The type system is extensible, and if you can define your desired argument type using a single Perl regular expression, then extending it is particularly easy.
- To make your program look smarter, options can be abbreviated and can come in any order. π
- You can parse options in a "spoof" mode that has no side-effects β this is useful for making a validation pass over the command line without actually doing anything. π (validation without consequences? slay.)
In general, the author has found that Getopt::Tabular tends to encourage programs with long lists of sophisticated options, which leads to great flexibility, intelligent operation, and the potential for insanely long command lines. π¦
π§ BASIC OPERATION π§
The basic operation of Getopt::Tabular is driven by an option table, which is just a list of option descriptions (otherwise known as option table entries, or just entries). Each option description tells GetOptions everything it needs to know when it runs into a particular option on the command line. For instance:
["-foo", "integer", 2, \@Foo, "set the foo values"]
means that whenever -foo gets seen on the command line, GetOptions has to make sure the next two arguments are integers, and copy them into the caller's @Foo array. (well, technically into the @Foo array where the option table is defined. which is almost always the same as GetOptions' caller, though. π)
Typically, you'll group a bunch of option descriptions together like this:
@options =
(["-range", "integer", 2, \@Range,
"set the range of allowed values"],
["-file", "string", 1, \$File,
"set the output file"],
["-clobber", "boolean", 0, \$Clobber,
"clobber existing files"],
...
);
and then you call GetOptions like this:
&GetOptions (\@options, \@ARGV) || exit 1;
which replaces @ARGV with a brand new array containing all the arguments left over after options and their arguments have been removed. β¨
You can also call GetOptions with three arguments, like this:
&GetOptions (\@options, \@ARGV, \@newARGV) || exit 1;
in which case @ARGV is left untouched, and @newARGV gets the leftover arguments instead. π«Ά
In case of error,GetOptionsprints enough information for the user to figure out what's going wrong. And if you supply one, it'll even print out a brief usage message on error. So honestly it's enough to justexit 1whenGetOptionstells you there was an error by returning 0. π
Detailed descriptions of what goes in an option table entry are given next, followed by the complete run-down of available types, full details on error handling, and how help text gets generated. stay tuned bestie, there's so much more. π
β¨ OPTION TABLE ENTRIES β¨
okay so bestie, the fields in the option table? they're literally the blueprint for how your args get parsed, so you gotta understand every single one. π
First off, the format of entries is pretty rigid, even tho Perl doesn't really need it that way. It's like that to make the Getopt::Tabular code a lil easier; the downside? some entries end up with unused values (like num_values is never used for boolean options, but you still have to put something there as a place-holder). The fields go like this:
optionβ this is the option name, e.g.-verboseor-some_value. For most option types, it's just an option prefix followed by text; but for boolean options it can get a little more complicated. (The exact rules are under βOPTION TYPESβ.) And yes, even tho you tellGetopt::Tabularthe valid option prefixes, you still have to put one onto the option names in the table. periodt.typeβ the option type decides what action happens when this option shows up on the command line, and (if applicable) what sort of values it will accept. There are three broad classes: those that imply copying data from the command line into some variable in the caller's space; those that imply copying constant data into the caller's space without taking any more arguments from the command line; and those that imply some other action. The available option types are covered way more below (see βOPTION TYPESβ), but real quick:string,integer, andfloatall imply copying values from the command line to a variable;constant,boolean,copy,arrayconst, andhashconstall imply copying some pre-defined data into a variable;callandevallet you execute some arbitrary subroutine or chunk of code; andhelpoptions will causeGetOptionsto print out all available help text and return 0. iconic.num_valuesβ forstring,integer, andfloatoptions, this decides whether the option is a scalar (num_values= 1) or vector (num_values> 1) option. (Heads up: whether it's scalar- or vector-valued has a big influence on what you must supply in theoption_datafield!) Forconstant,copy,arrayconst, andhashconstoption types,num_valuesis a bit of a misnomer: it actually contains the value (or a reference to it, if array or hash) to be copied when the option is encountered. Forcalloptions,num_valuescan be used to supply extra arguments to the called subroutine. In any case, you can think ofnum_valuesas an input value. Forbooleanandevaloptions,num_valuesis ignored and should beundefor 0.option_dataβ forstring,integer,float,boolean,constant,copy,arrayconst, andhashconsttypes, this must be a reference to the variable into which you wantGetOptionsto copy the appropriate thing. The βappropriate thingβ is either the argument(s) following the option, the constant supplied asnum_values, or 1 or 0 (for boolean options).
For boolean, constant, copy, and scalar-valued string, integer, and float options, this must be a scalar reference. For vector-valued string, integer, and float options (num_values > 1), and for arrayconst options, this must be an array reference. For hashconst options, this must be a hash reference.
Finally, option_data is also used as an input value for call and eval options: for call, it should be a subroutine reference, and for eval options, it should be a string containing valid Perl code to evaluate when the option is seen. The subroutine called by a call option should take at least two arguments: a string, which is the actual option that triggered the call (because the same subroutine could be tied to many options), and an array reference, which contains all command line arguments after that option. (Further arguments can be supplied in the num_values field.) The subroutine may freely modify this array, and those modifications will affect the behaviour of GetOptions afterwards.
The chunk of code passed to an eval option is evaluated in the package from which GetOptions is called, and does not have access to any internal Getopt::Tabular data.
help_stringβ (optional) a brief description of the option. Don't worry about formatting it in any way; whenGetOptionshas to print out your help, it will do so quite nicely without any intervention. If the help string is not defined, then that option will not be included in the option help text. (However, you could supply an empty string β which is defined β to makeGetOptionsjust print out the option name, but nothing else.)arg_descβ (optional) an even briefer description of the values that you expect to follow your option. This is mainly used to supply place-holders in the help string, and is specified separately so thatGetOptionscan act fairly intelligently when formatting a help message. See βHELP TEXTβ for more information.
π₯ OPTION TYPES π₯
The option type field is the single-most important field in the table, bestie. The type for an option -foo determines (along with num_values) what action GetOptions takes when it sees -foo on the command line: how many following arguments become -foo's arguments, what regular expression those arguments must conform to, or whether some other action should be taken. π
As mentioned above, there are three main classes of argument types:
- argument-driven options β these are options that imply taking one or more option arguments from the command line after the option itself is taken. The arguments are then copied into some variable supplied (by reference) in the option table entry.
- constant-valued options β these are options that have a constant value associated with them; when the option is seen on the command line, that constant is copied to some variable in the caller's space. (Both the constant and the value are supplied in the option table entry.) Constants can be scalars, arrays, or hashes.
- other options β these imply some other action to be taken, usually supplied as a string to
evalor a subroutine to call.
π Argument-driven option types
πΈ string, integer, float
These are the option types that imply βoption argumentsβ, i.e. arguments after the option that will be consumed when that option is encountered on the command line and copied into the caller's space via some reference. For instance, if you want an option -foo to take a single string as an argument, with that string being copied to the scalar variable $Foo, then you would have this entry in your option table:
["-foo", "string", 1, \$Foo]
(For conciseness, I've omitted the help_string and argdesc entries in all of the example entries in this section. In reality, you should religiously supply help text in order to make your programs easier to use and easier to maintain.)
If num_values is some n greater than one, then the option_data field must be an array reference, and n arguments are copied from the command line into that array. (The array is clobbered each time -foo is encountered, not appended to.) In this case, -foo is referred to as a vector-valued option, as it must be followed by a fixed number of arguments. (Eventually, I plan to add list-valued options, which take a variable number of arguments.) For example an option table like
["-foo", "string", 3, \@Foo]
would result in the @Foo array being set to the three strings immediately following any -foo option on the command line.
The only difference between string, integer, and float options is how picky GetOptions is about the value(s) it will accept. For string options, anything is OK; for integer options, the values must look like integers (i.e., they must match /[+-]?\d+/); for float options, the values must look like C floating point numbers (trust me, you don't want to see the regexp for this). Note that since string options will accept anything, they might accidentally slurp up arguments that are meant to be further options, if the user forgets to put the correct string. For instance, if -foo and -bar are both scalar-valued string options, and the arguments -foo -bar are seen on the command-line, then -bar will become the argument to -foo, and never be processed as an option itself. (This could be construed as either a bug or a feature. If you feel really strongly that it's a bug, then complain and I'll consider doing something about it.)
If not enough arguments are found that match the required regular expression, GetOptions prints to standard error a clear and useful error message, followed by the usage summary (if you supplied one), and returns 0. The error messages look something like -foo option must be followed by an integer, or -foo option must be followed by 3 strings, so it really is enough for your program to exit 1 without printing any further message.
π§ User-defined patterns
Since the three option types described above are defined by nothing more than a regular expression, it's easy to define your own option types. For instance, let's say you want an option to accept only strings of upper-case letters. You could then call &Getopt::Tabular::AddPatternType as follows:
&Getopt::Tabular::AddPatternType
("upperstring", "[A-Z]+", "uppercase string")
Note that the third parameter is optional, and is only supplied to make error messages clearer. For instance, if you now have a scalar-valued option -zap of type upperstring:
["-zap", "upperstring", 1, \$Zap]
...and if the user gets it wrong and drops an argument that isn't all uppercase letters after -zap, then GetOptions will be like "um excuse me" and complain that -zap option must be followed by an uppercase string π
. And if you hadn't handed over that third argument to &AddType, the error would've been the slightly-less-helpful -zap option must be followed by an upperstring. Also you gotta think about how GetOptions pluralizes your description β rn it literally just adds an s, which slays most of the time, but not always. So alternatively you can pass a two-element list holding the singular and the plural:
&Getopt::Tabular::AddPatternType
("upperstring", "[A-Z]+",
["string of uppercase letters", "strings of uppercase letters"])
So if -zap instead expects three upperstrings and the user goofs, the error message would be (first example) -zap option must be followed by 3 uppercase strings, or (second example) -zap option must be followed by three strings of uppercase letters.
And honestly, if you're not planning on vector-valued options of your new type, pluralization is like... barely a thing, don't stress πΈ. Also, while this looks like a cute lil nod toward multi-lingual support, the error messages are still hard-coded English in other places. Maybe next version... π
π Constant-valued option types π
boolean
For boolean options, option_data must be a scalar reference, and num_values gets ignored (just set it to undef or 0, no biggie). Booleans are a lil weird in that every boolean option implies two possible arguments that'll be accepted on the command line β the positive and negative alternatives. The positive alternative (which is what you specify as the option name) gives you a true value, while the negative alternative gives you false. Most of the time you can just let GetOptions pick the negative alternative for you: it literally inserts no after the option prefix, so -clobber becomes -noclobber β¨. (More precisely: GetOptions tests all option prefixes until one of them matches at the beginning of the option name. Then it inserts no between that prefix and the rest of the string. So if you wanna support both GNU-style options like --clobber and one-hyphen options like -c, be sure to give -- first when setting the option patterns with &SetOptionPatterns. Otherwise the negative alternative to --clobber is gonna be -no-clobber, which might not be the vibe you wanted π.) Sometimes though you wanna explicitly specify the negative alternative β do that by putting both alternatives in the option name, separated by a vertical bar, e.g. -verbose|-quiet.
So like, the above two examples might be specified as
["-clobber", "boolean", undef, \$Clobber],
["-verbose|-quiet", "boolean", undef, \$Verbose],...);
If -clobber shows up on the command line, $Clobber gets set to 1; if -noclobber shows up, $Clobber gets set to 0. Same energy with -verbose setting $Verbose to 1, and -quiet setting $Verbose to 0. π
const
For const options, put a scalar value (not a reference!) in num_values, and a scalar reference in option_data. Like:
["-foo", "const", "hello there", \$Foo]
When -foo is encountered, GetOptions copies hello there into $Foo. Periodt. π«Ά
arrayconst
For arrayconst options, put an array reference (input) β not an array value β in num_values, and another array reference (output) in option_data. For example:
["-foo", "arrayconst", [3, 6, 2], \@Foo]
When -foo is encountered, GetOptions copies the array (3,6,2) into @Foo. Iconic behavior, no notes. π
hashconst
For hashconst options, put a hash reference (input) β again, not a hash value β in num_values, and another hash reference (output) in option_data. For example:
["-foo", "hashconst", { "Perl" => "Larry Wall",
"C" => "Dennis Ritchie",
"Pascal" => "Niklaus Wirth" },
\%Inventors]
When -foo is encountered, GetOptions copies into %Inventors a hash relating various programming languages to the culprits primarily responsible for their invention. History class but make it cunty π
copy
copy options act just like const options β except when num_values is undefined. In that case, the option name itself gets copied into the scalar referenced by option_data, rather than the undef value that'd get copied under these circumstances with a const option. This is so useful when one program accepts options that it just passes straight to a sub-program; for instance, if prog1 calls prog2, and prog2 might be run with the -foo option, then prog1's argument table might have this option:
["-foo", "copy", undef, \$Foo,
"run prog2 with the -foo option"]
and later on you'd run prog2 like this:
system ("prog2 $Foo ...");
That way, if -foo is never seen on prog1's command line, $Foo stays untouched and expands to the empty string when you're building the command line for prog2. Chef's kiss πβ¨
If num_values is anything other than undef, then copy options behave just like constant options. Simple as that.
π Other option types π
call
For call options, option_data must be a reference to a subroutine. That sub gets called with at least two arguments: a string containing the option that triggered the call (because the same sub might be activated by many options, iykyk), a reference to an array containing all the remaining command-line arguments after the option, and any other arguments specified using the num_values field. (For that to work, num_values must be an array reference; otherwise it's just ignored.) So like, you might define a sub
sub process_foo
{
my ($opt, $args, $dest) = @_;
$$dest = shift @$args; # not quite right! (see below)
}
with a corresponding option table entry:
["-foo", "call", [\$Foo], \&process_foo]
and then -foo would act just like a scalar-valued string option that copies into $Foo. (Well, almost ... read on π)
A subtle point you might miss from the code above: the value returned by &process_foo matters β if it's false, then GetOptions returns 0 to its caller, indicating failure π. To make sure the user gets a useful error message, you should supply one by calling SetError; doing that will stop GetOptions from printing out a rather mysterious (to the end user at least) message along the lines of subroutine call failed. The example above has two subtle problems: first, if the argument following -foo is an empty string, then process_foo returns the empty string β a false value β which makes GetOptions fail confusingly π. Second, if there are no arguments after -foo, then process_foo returns undef β again a false value β and again GetOptions fails.
To solve these problems, we have to define the requirements for the -foo option a lil more rigorously. Let's say any string (including the empty string) is valid, but there has to be something there. Then process_foo is written like this:
sub process_foo
{
my ($opt, $args, $dest) = @_;
$$dest = shift @$args;
(defined $$dest) && return 1;
&Getopt::Tabular::SetError
("bad_foo", "$opt option must be followed by a string");
return 0;
}
The SetError routine actually takes two arguments: an error class and an error message. That's explained fully in the ERROR HANDLING section, below. And if you find yourself writing a ton of routines like this, SetError is optionally exported from Getopt::Tabular, so of course you can import it into your main package like this:
use Getopt::Tabular qw/GetOptions SetError/;
eval
An eval option specifies a chunk of Perl code to be executed (eval'd) when the option is encountered on the command line. The code goes in as a string in the option_data field; and again, num_values is ignored. For example:
["-foo", "eval", undef,
'print "-foo seen on command line\n"']
will make GetOptions print out (via an eval) the string -foo seen on the command line\n when -foo is seen. No other action is taken apart from whatever you put in the eval string. The code gets evaluated in the package from which GetOptions was called, so you can access variables and subroutines in your program super easily. If any error happens in the eval, GetOptions complains loudly and returns 0 π’.
Note that the supplied code is always evaluated in ano strictenvironment β that's because Getopt::Tabular is itselfuse strict-compliant, and I didn't wanna force strictness on every quick hack that uses the module. (Especially since eval options seem to be used mostly in quick hacks.) (Anyone who knows how to fetch the strictness state for another package or scope is welcome to send me hints!) However, the-wstate is untouched.
section
section options are just used to help formatting the help text. See HELP TEXT below for more details. π
π ERROR HANDLING π
Okay so, error handling in the argument list is generally pretty transparent, bestie β like, it just works:
GetOptions (or one of its little minions) whips up an error message and assigns it an error class. GetOptions prints that message straight to standard error, and then returns 0. That's the whole ritual β¨
Wanna peek at what actually went sideways? Grab the error class and error message with the GetError routine:
($err_class, $err_msg) = &Getopt::Tabular::GetError ();
(Just like SetError, GetError can also be exported from Getopt::Tabular, so you don't have to type the whole blessed path every time, iykyk.)
The error message itself is pretty simple β it's an explanation for the end user of what went wrong, which is exactly why GetOptions just prints it out and then immediately forgets it exists π. The error class is the extra info that might actually be useful for your program. The current values are:
bad_optionβ set when something that looks like an option is found on the command line, but it's either unknown or an ambiguous abbreviation. Rude behavior, honestly.bad_valueβ set when an option is followed by an invalid argument (i.e., one that doesn't match the regexp for that type), or the wrong number of arguments.bad_callβ set when a subroutine called via a call option, or the code evaluated for an eval option, returns a false value. The subroutine or eval'd code can override this by callingSetErroritself.bad_evalβ set when the code evaluted for an eval option has an error in it.helpβ set when the user requests help π₯Ίβ¨
Note that most of these are errors on the end user's part, like bad or missing arguments. There are also errors that can be caused by you, the programmer, like bad or missing values in the option table; these generally result in GetOptions croaking so that your program dies immediately with enough information that you can figure out where the mistake is π. bad_eval is a borderline case; there are conceivably cases where the end user's input can result in bogus code to evaluate, so it got grouped into the "user errors" class.
Finally, asking for help isn't really an error, but the assumption is that you probably shouldn't continue normal processing after printing out the help β so GetOptions returns 0 in this case. You can always fetch the error class with GetError if you want to treat real errors differently from help requests π
π HELP TEXT π
One of Getopt::Tabular's niftier features is the ability to generate and format a whole pile of useful help text out of the little help snippets you tuck into your option table. The best way to show you is with a couple of brief examples, fr fr.
First, it's helpful to know how the user can even trigger a help display. And it's simple: by default, GetOptions always has a -help option, and the presence of that on the command line triggers a help display. (Actually, the help option is really your preferred option prefix plus help.) So, if you like to make GNU-style options take precedence as follows:
&Getopt::Tabular::SetOptionPatterns qw|(--)([\w-]+) (-)(\w+)|;
then the help option will be --help. There is only one help option available, and you can set it by calling &SetHelpOption (another optional export).
Note that in addition to the option help embedded in the option table, GetOptions can optionally print out two other messages: a descriptive text (usually a short paragraph giving a rough overview of what your program does, possibly referring the user to the fine manual page), and a usage text. These are both supplied by calling &SetHelp, e.g.
$Help = <<HELP;
This is the foo program. It reads one file (specified by -infile),
operates on it some unspecified way (possibly modified by
-threshold), and does absolutely nothing with the results.
(The utility of the -clobber option has yet to be established.)
HELP
$Usage = <<USAGE;
usage: foo [options]
foo -help to list options
USAGE
&Getopt::Tabular::SetHelp ($Help, $Usage)
Note that either of the long help or usage strings may be empty, in which case GetOptions simply won't print them. In the case where both are supplied, the long help message is printed first, followed by the option help summary, followed by the usage. GetOptions inserts enough blank lines to make the output look just fine on its own, so you shouldn't pad either the long help or usage message with blanks. (It looks best if each ends with a newline, though, so setting the help strings with here-documents β as in this example β is the recommended approach π«Ά)
As an example of the help display generated by a typical option table, let's take a look at the following:
$Verbose = 1;
$Clobber = 0;
undef $InFile;
@Threshold = (0, 1);
@argtbl = (["-verbose|-quiet", "boolean", 0, \$Verbose,
"be noisy"],
["-clobber", "boolean", 0, \$Clobber,
"overwrite existing files"],
["-infile", "string", 1, \$InFile,
"specify the input file from which to read a large " .
"and sundry variety of data, to which many " .
"interesting operations will be applied", "<f>"],
["-threshold", "float", 2, \@Threshold,
"only consider values between <v1> and <v2>",
"<v1> <v2>"]);
Assuming you haven't supplied long help or usage strings, then when GetOptions encounters the help option, it will immediately stop parsing arguments and print out the following option summary:
Summary of options:
-verbose be noisy [default]
-quiet opposite of -verbose
-clobber overwrite existing files
-noclobber opposite of -clobber [default]
-infile <f> specify the input file from which to read a large and
sundry variety of data, to which many interesting
operations will be applied
-threshold <v1> <v2>
only consider values between <v1> and <v2> [default: 0 1]
There are a number of interesting things to note here, bestie. First: there are three option table fields that affect the generation of help text β option, help_string, and argdesc. Note how the argdesc strings are simply option placeholders, usually used to 1) indicate how many values are expected to follow an option, 2) (possibly) imply what form they take (although that's not really shown here), and 3) explain the exact meaning of the values in the help text. argdesc is just a string like the help string; you can put whatever you like in it. What's shown above is just my personal preference (which may well evolve).
A new feature with version 0.3 of Getopt::Tabular is the inclusion of default values with the help for certain options. A number of conditions must be fulfilled for this to happen for a given option: first, the option type must be one of the "argument-driven" types, such as integer, float, string, or a user-defined type. Second, the option data field must refer either to a defined scalar value (for scalar-valued options) or to a list of one or more defined values (for vector-valued options). Thus, in the above example, the -infile option doesn't have its default printed because the $InFile scalar is undefined. Likewise, if the @Threshold array were the empty list (), or a list of undefined values (undef,undef), then the default value for -threshold also would not have been printed.
The formatting is done as follows: enough room is made on the right hand side for the longest option name, initially omitting the argument placeholders. Then, if an option has placeholders, and there is room for them in between the option and the help string, everything (option, placeholders, help string) is printed together. An example of this is the -infile option: here, -infile <f> is just small enough to fit in the 12-character column (10 characters because that is the length of the longest option, and 2 blanks), so the help text is placed right after it on the same line. However, the -threshold option becomes too long when its argument placeholders are appended to it, so the help text is pushed onto the next line.
In any event, the help string supplied by the caller starts at the same column, and is filled to make a nice paragraph of help. GetOptions will fill to the width of the terminal (or 80 columns if it fails to find the terminal width).
Finally, you can have pseudo entries of type section, which are important to make long option lists readable (and one consequence of using Getopt::Tabular is programs with ridiculously long option lists β not altogether a bad thing, I suppose). For example, this table fragment:
@argtbl = (...,
["-foo", "integer", 1, \$Foo,
"set the foo value", "f"],
["-enterfoomode", "call", 0, \&enter_foo_mode,
"enter foo mode"],
["Non-foo related options", "section"],
["-bar", "string", 2, \@Bar,
"set the bar strings (which have nothing whatsoever " .
"to do with foo", "<bar1> <bar2>"],
...);
results in the following chunk of help text:
-foo f set the foo value
-enterfoomode enter foo mode
-- Non-foo related options ---------------------------------
-bar b1 b2 set the bar strings (which have nothing
whatsoever to do with foo
(This example also illustrates a slightly different style of argument placeholder. Take your pick, or invent your own!)
β¨ SPOOF MODE β¨
okay so bestie, listen up π β callbacks from the command line (that's the "call" and "eval" options) can literally do anything, which means they might be super expensive. In certain cases, then, you might wanna make an initial pass over the command line to make sure everything is OK before parsing it βfor realβ and racking up all those expensive callbacks. So Getopt::Tabular provides a "spoof" mode for parsing a command line with no side-effects. In the simplest case, you can access spoof mode like this:
use Getopt::Tabular qw(SpoofGetOptions GetOptions);
.
.
.
&SpoofGetOptions (\@options, \@ARGV, \@newARGV) || exit 1;
and then later on, you'd call GetOptions with the original @ARGV (so it can do what SpoofGetOptions merely pretended to do):
&GetOptions (\@options, \@ARGV, \@newARGV) || exit 1;
For most option types, any errors that GetOptions would catch should also be caught by SpoofGetOptions β so you might initially think you can get away without that || exit 1 after calling GetOptions. However, it's a good idea for a couple of reasons. First, you might inadvertently changed @ARGV β this is usually a bug and a silly thing to do, so you'd probably want your program to crash loudly rather than fail mysteriously later on. Second, and more likely, some of those expensive operations that you're initially avoiding by using SpoofGetOptions might themselves fail β which would cause GetOptions to return false where SpoofGetOption completes without a problem. (Finally, there's the faint possiblity of bugs in Getopt::Tabular that would cause different behaviour in spoof mode and real mode β this really shouldn't happen, though.)
In reality, using spoof mode requires a bit more work. In particular, the whole reason for spoof argument parsing is to avoid expensive callbacks, but since callbacks can eat any number of command line arguments, you have to emulate them in some way. It's not possible for SpoofGetOptions to do this for you, so you have to help out by supplying "spoof" callbacks. As an example, let's say you have a callback option that eats one argument (a filename) and immediately reads that file:
@filedata = ();
sub read_file
{
my ($opt, $args) = @_;
warn ("$opt option requires an argument\n"), return 0 unless @$args;
my $file = shift @$args;
open (FILE, $file) ||
(warn ("$file: $!\n"), return 0);
push (@filedata, <FILE>);
close (FILE);
return 1;
}
@options =
(['-read_file', 'call', undef, \&read_file]);
Since -read_file could occur any number of times on the command line, we might end up reading an awful lot of files, and thus it might be a long time before we catch errors late in the command line. Thus, we'd like to do a "spoof" pass over the command line to catch all errors. A simplistic approach would be to supply a spoof callback that just eats one argument and returns success:
sub spoof_read_file
{
my ($opt, $args) = @_;
(warn ("$opt option requires an argument\n"), return 0)
unless @$args;
shift @$args;
return 1;
}
Then, you have to tell Getopt::Tabular about this alternate callback with no side-effects (apart from eating that one argument):
&Getopt::Tabular::SetSpoofCodes (-read_file => \&spoof_read_file);
(SetSpoofCodes just takes a list of key/value pairs, where the keys are "call" or "eval" options, and the values are the "no side-effects" callbacks. Naturally, the replacement callback for an "eval" option should be a string, and for a "call" option it should be a code reference. This is not actually checked, however, until you call SpoofGetOptions, because SetSpoofCodes doesn't know whether options are "call" or "eval" or what.)
A more useful spoof_read_file, however, would actually check if the requested file exists β i.e., we should try to catch as many errors as possible, as early as possible:
sub spoof_read_file
{
my ($opt, $args) = @_;
warn ("$opt option requires an argument\n"), return 0
unless @$args;
my $file = shift @$args;
warn ("$file does not exist or is not readable\n"), return 0
unless -r $file;
return 1;
}
Finally, you can frequently merge the "real" and "spoof" callback into one subroutine:
sub read_file
{
my ($opt, $args, $spoof) = @_;
warn ("$opt option requires an argument\n"), return 0 unless @$args;
my $file = shift @$args;
warn ("$file does not exist or is not readable\n"), return 0
unless -r $file;
return 1 if $spoof;
open (FILE, $file) ||
(warn ("$file: $!\n"), return 0);
push (@filedata, <FILE>);
close (FILE);
return 1;
}
And then, when specifying the replacement callback to SetSpoofCodes, just create an anonymous sub that calls read_file with $spoof true:
&Getopt::Tabular::SetSpoofCodes
(-read_file => sub { &read_file (@_[0,1], 1) });
Even though this means a bigger and more complicated callback, you only need one such callback β the alternative is to carry around both read_file and spoof_read_file, which might do redundant processing of the argument list.
π AUTHOR π
Greg Ward <greg@bic.mni.mcgill.ca>
Started in July, 1995 as ParseArgs.pm, with John Ousterhout's Tk_ParseArgv.c as a loose inspiration. Many many features added over the ensuing months; documentation written in a mad frenzy 16-18 April, 1996. Renamed to Getopt::Tabular, revamped, reorganized, and documentation expanded 8-11 November, 1996.
Copyright (c) 1995-97 Greg Ward. All rights reserved. This is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
π BUGS π
The documentation is bigger than the code, and I still haven't covered option patterns or extending the type system (apart from pattern types). Yow!
No support for list-valued options, although you can roll your own with call options. (See the demo program included with the distribution for an example.)
Error messages are hard-coded to English.
and that's the whole vibe, bestie π«Ά β this iconic page is serving perl v5.36.0, dated 2022-10-13, and it's Tabular(3pm) π
β¨ periodt.
π¦ where this page comes from
- ubuntu noble: libgetopt-tabular-perl 0.3-4 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libgetopt-tabular-perl 0.3-4 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libgetopt-tabular-perl 0.3-4 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms