Argument parsing in Traffic Server plugins
When you write a new Traffic Server plugin, you have to choose whether to write a remap plugin, a global plugin or both. There are different plugin entry points for global and remap plugins and you will find yourself having to parse command-line argument from two different entry points:
tsapi void TSPluginInit(int argc, const char* argv[]);
tsapi TSReturnCode TSRemapNewInstance(int argc, char* argv[], void** ih, char* errbuf, int errbuf_size);
Since we are parsing command-line options, it makes sense to use getopt
or getopt_long
to do the parsing. I prefer to use getopt_long
because I find long options more legible and memorable.
However, TSPluginInit
and TSRemapNewInstance
do not pass the same
argument vector, so if you are unwary you will process arguments
incorrectly. The TSPluginInit
argument vector is the plugin name
followed by the arguments, whereas the TSRemapNewInstance
argument
vector contains the to and from URLs from the remap rule, followed by the
remaining arguments. Since getopt_long
expects the first argument to
be the program name, it’s ok with the TSPluginInit
argument vector,
but you need to massage the TSRemapNewInstance
one. I usually just
increment it, because it really doesn’t matter what you pass in the
first entry, just as long as there is one.
The final trap is to remember that optind
is a global variable and you
have to reset it before you call getopt_long
for the second time. Since
it’s harmless to reset it each time, my code just always sets it. For
a plugin that supports both global and remap modes, you should end up
with something like this:
optind = 0;
for (;;) {
int opt;
opt = getopt_long(argc, (char * const *)argv, "", longopt, NULL);
switch (opt) {
/* TODO: check flags */
default:
snprintf(errbuf, errbuf_size, "invalid option '%d'", opt);
return TS_ERROR;
}
if (opt == -1) {
break;
}
}