TIP #265: A Convenient C-side Command Option Parser for Tcl
_____________________________________________________________________________
TIP:	265
Title:	A Convenient C-side Command Option Parser for Tcl
Version:	$Revision: 1.7 $
Authors:	Sam Bromley <sam@sambromley.com>
State:	Final
Type:	Project
Tcl-Version:	8.6
Vote:	Done
Created:	Mon Apr 03 00:00:00 UTC 2006
Keywords:	Command line parsing, C implementation
Abstract
The Tk C library provides developers with a Tk_ParseArgv() function that allows command line parsing of options of the "-option" form. Archived discussions on news:comp.lang.tcl and on the Wiki indicate that a desire for similar functionality without Tk has arisen several times in the past. This TIP presents a Tk-free implementation of Tk_ParseArgv() named Tcl_ParseArgvObj, that developers can use to parse "-option" style command options in C implementations of Tcl commands using the Tcl_Obj interface.
Rationale
While the parsing of command options can be readily accomplished on the Tcl side, a uniform method for parsing "-option" formed options does not exist on the C side. Many developers are familiar with the ease of use of libpopt-style command line parsing, but a similarly clean method does not currently exist in Tcl. The common approach is to use Tcl_GetIndexFromObj(), yet this method alone does not allow the flexibilty and ease of use of libpopt-style parsing.
One drawback of the classical Tcl_GetIndexFromObj()-only approach is the need to handle the specifies of your command option parsing for each unique command. This leads to significant code duplication. A libpopt-style approach is to bundle all of your parsing specifics into a single array of structures capturing the details, and then let a specific parsing routine handle the parsing of every option for you. The Tcl_ParseArgvObj() routine introduced in this TIP provides this functionality, thereby allowing the removal of all parsing specifics from the command implimentation other than that necessary to describe each optional argument.
Additionally, a function Tcl_ParseArgsObjv is provided to provide the functionality of Tk_ParseArgs() to those who desire it. A discussion in 2002 on news:comp.lang.tcl [http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/c4fea8f0346cf8ae/036961bf476a3b99?q=tcl_parseargv&rnum=2#036961bf476a3b99] indicated that this is a desired feature. Arguments against a Tcl_ParseArgsObjv implementation include that it is better to do all command line parsing on the Tcl side. However, this implies writing two wrapper functions: (i) A C implementation of a Tcl command; and (ii) A Tcl wrapper that pre-parses the options before calling the C command. This can lead to significant duplication of effort when porting a large project to a Tcl enabled version. This point is particularly relevent in the context of Tcl_ParseArgvObj(), as then one is not assuming that one can simply replace the main() routine with Tcl, but rather that one is truly embedding the C side in a larger system.
Tcl_ParseArgvObj() offers a clean method to enable flexible command line parsing to C implementations of Tcl commands.
Specification
This document proposes adding Tcl_ParseArgsObjv, whose arguments shall be:
int Tcl_ParseArgsObjv(Tcl_Interp *interp, const Tcl_ArgvInfo *argTable, int *objcPtr, Tcl_Obj *const *objv, Tcl_Obj ***remainingObjv)
Note that the count of arguments (referred to by objcPtr) will be modified, and a modified array will be returned via remainingObjv (and need ckfreeing). The input array of objects will not be modified.
Reference Implementation
A working implementation has been submitted to the Feature Request Tracker at SourceForge [https://sourceforge.net/support/tracker.php?&aid=1446696].
Example of Use
#include <tcl.h>
#include <tclArgv.h> /* not needed if subsumed into core */

int g_test_cmd(ClientData clientData, Tcl_Interp *interp,
    int objc, Tcl_Obj *CONST objv[])

  char *gname,*filename;
  int i;
  int numRepeat;
  double scalar;
  int doErase = 0;
  size_t size;

  /* this table specifies the possible options, all in one place.*/
  Tcl_ArgvInfo argTable[] = 
    "-erase", TCL_ARGV_CONSTANT, (void *) 1, &doErase,
      "erase image before plotting",
    "-numRepeat", TCL_ARGV_INT, NULL, &numRepeat,
      "number of times to repeat test",
    "-scalar", TCL_ARGV_FLOAT, NULL, &scalar,
      "scalar multiple to use for test",
    "-outfile", TCL_ARGV_STRING, NULL, &filename,
      "name of file to which to dump result",
    NULL, TCL_ARGV_END, NULL, NULL, NULL
  ;

  /* Call Tcl_ParseArgObjv to do all the parsing! */
  if (Tcl_ParseArgsObjv(interp,argTable,&objc,objv,&private_objv) != TCL_OK) 
     return TCL_ERROR;

  /* Should recheck objc here */

  /* at this point, any unhandled options are repacked in private_objv */
  gname = Tcl_GetString(private_obj[1]);

  /* all done */
  ckfree(private_objv);

  /* rest of code continues here...*/

  return TCL_OK;

Copyright
This document has been placed in the public domain.
_____________________________________________________________________________
Colophon
TIP AutoGenerator - written by Donal K. Fellows