#include "tkInt.h"
static Tk_ArgvInfo defaultTable[] = {
{"-help", TK_ARGV_HELP, (char *) NULL, (char *) NULL,
"Print summary of command-line options and abort"},
{NULL, TK_ARGV_END, (char *) NULL, (char *) NULL,
(char *) NULL}
};
static void PrintUsage _ANSI_ARGS_((Tcl_Interp *interp,
Tk_ArgvInfo *argTable, int flags));
int
Tk_ParseArgv(interp, tkwin, argcPtr, argv, argTable, flags)
Tcl_Interp *interp;
Tk_Window tkwin;
int *argcPtr;
char **argv;
Tk_ArgvInfo *argTable;
int flags;
{
register Tk_ArgvInfo *infoPtr;
Tk_ArgvInfo *matchPtr;
char *curArg;
register char c;
int srcIndex;
int dstIndex;
int argc;
size_t length;
int i;
if (flags & TK_ARGV_DONT_SKIP_FIRST_ARG) {
srcIndex = dstIndex = 0;
argc = *argcPtr;
} else {
srcIndex = dstIndex = 1;
argc = *argcPtr-1;
}
while (argc > 0) {
curArg = argv[srcIndex];
srcIndex++;
argc--;
length = strlen(curArg);
if (length > 0) {
c = curArg[1];
} else {
c = 0;
}
matchPtr = NULL;
for (i = 0; i < 2; i++) {
if (i == 0) {
infoPtr = argTable;
} else {
infoPtr = defaultTable;
}
for (; (infoPtr != NULL) && (infoPtr->type != TK_ARGV_END);
infoPtr++) {
if (infoPtr->key == NULL) {
continue;
}
if ((infoPtr->key[1] != c)
|| (strncmp(infoPtr->key, curArg, length) != 0)) {
continue;
}
if ((tkwin == NULL)
&& ((infoPtr->type == TK_ARGV_CONST_OPTION)
|| (infoPtr->type == TK_ARGV_OPTION_VALUE)
|| (infoPtr->type == TK_ARGV_OPTION_NAME_VALUE))) {
continue;
}
if (infoPtr->key[length] == 0) {
matchPtr = infoPtr;
goto gotMatch;
}
if (flags & TK_ARGV_NO_ABBREV) {
continue;
}
if (matchPtr != NULL) {
Tcl_AppendResult(interp, "ambiguous option \"", curArg,
"\"", (char *) NULL);
return TCL_ERROR;
}
matchPtr = infoPtr;
}
}
if (matchPtr == NULL) {
if (flags & TK_ARGV_NO_LEFTOVERS) {
Tcl_AppendResult(interp, "unrecognized argument \"",
curArg, "\"", (char *) NULL);
return TCL_ERROR;
}
argv[dstIndex] = curArg;
dstIndex++;
continue;
}
gotMatch:
infoPtr = matchPtr;
switch (infoPtr->type) {
case TK_ARGV_CONSTANT:
*((int *) infoPtr->dst) = (int) infoPtr->src;
break;
case TK_ARGV_INT:
if (argc == 0) {
goto missingArg;
} else {
char *endPtr;
*((int *) infoPtr->dst) =
strtol(argv[srcIndex], &endPtr, 0);
if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
Tcl_AppendResult(interp, "expected integer argument ",
"for \"", infoPtr->key, "\" but got \"",
argv[srcIndex], "\"", (char *) NULL);
return TCL_ERROR;
}
srcIndex++;
argc--;
}
break;
case TK_ARGV_STRING:
if (argc == 0) {
goto missingArg;
} else {
*((char **)infoPtr->dst) = argv[srcIndex];
srcIndex++;
argc--;
}
break;
case TK_ARGV_UID:
if (argc == 0) {
goto missingArg;
} else {
*((Tk_Uid *)infoPtr->dst) = Tk_GetUid(argv[srcIndex]);
srcIndex++;
argc--;
}
break;
case TK_ARGV_REST:
*((int *) infoPtr->dst) = dstIndex;
goto argsDone;
case TK_ARGV_FLOAT:
if (argc == 0) {
goto missingArg;
} else {
char *endPtr;
*((double *) infoPtr->dst) =
strtod(argv[srcIndex], &endPtr);
if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
Tcl_AppendResult(interp, "expected floating-point ",
"argument for \"", infoPtr->key,
"\" but got \"", argv[srcIndex], "\"",
(char *) NULL);
return TCL_ERROR;
}
srcIndex++;
argc--;
}
break;
case TK_ARGV_FUNC: {
int (*handlerProc)();
handlerProc = (int (*)())infoPtr->src;
if ((*handlerProc)(infoPtr->dst, infoPtr->key,
argv[srcIndex])) {
srcIndex += 1;
argc -= 1;
}
break;
}
case TK_ARGV_GENFUNC: {
int (*handlerProc)();
handlerProc = (int (*)())infoPtr->src;
argc = (*handlerProc)(infoPtr->dst, interp, infoPtr->key,
argc, argv+srcIndex);
if (argc < 0) {
return TCL_ERROR;
}
break;
}
case TK_ARGV_HELP:
PrintUsage (interp, argTable, flags);
return TCL_ERROR;
case TK_ARGV_CONST_OPTION:
Tk_AddOption(tkwin, infoPtr->dst, infoPtr->src,
TK_INTERACTIVE_PRIO);
break;
case TK_ARGV_OPTION_VALUE:
if (argc < 1) {
goto missingArg;
}
Tk_AddOption(tkwin, infoPtr->dst, argv[srcIndex],
TK_INTERACTIVE_PRIO);
srcIndex++;
argc--;
break;
case TK_ARGV_OPTION_NAME_VALUE:
if (argc < 2) {
Tcl_AppendResult(interp, "\"", curArg,
"\" option requires two following arguments",
(char *) NULL);
return TCL_ERROR;
}
Tk_AddOption(tkwin, argv[srcIndex], argv[srcIndex+1],
TK_INTERACTIVE_PRIO);
srcIndex += 2;
argc -= 2;
break;
default:
sprintf(interp->result, "bad argument type %d in Tk_ArgvInfo",
infoPtr->type);
return TCL_ERROR;
}
}
argsDone:
while (argc) {
argv[dstIndex] = argv[srcIndex];
srcIndex++;
dstIndex++;
argc--;
}
argv[dstIndex] = (char *) NULL;
*argcPtr = dstIndex;
return TCL_OK;
missingArg:
Tcl_AppendResult(interp, "\"", curArg,
"\" option requires an additional argument", (char *) NULL);
return TCL_ERROR;
}
static void
PrintUsage(interp, argTable, flags)
Tcl_Interp *interp;
Tk_ArgvInfo *argTable;
int flags;
{
register Tk_ArgvInfo *infoPtr;
int width, i, numSpaces;
#define NUM_SPACES 20
static char spaces[] = " ";
char tmp[30];
width = 4;
for (i = 0; i < 2; i++) {
for (infoPtr = i ? defaultTable : argTable;
infoPtr->type != TK_ARGV_END; infoPtr++) {
int length;
if (infoPtr->key == NULL) {
continue;
}
length = strlen(infoPtr->key);
if (length > width) {
width = length;
}
}
}
Tcl_AppendResult(interp, "Command-specific options:", (char *) NULL);
for (i = 0; ; i++) {
for (infoPtr = i ? defaultTable : argTable;
infoPtr->type != TK_ARGV_END; infoPtr++) {
if ((infoPtr->type == TK_ARGV_HELP) && (infoPtr->key == NULL)) {
Tcl_AppendResult(interp, "\n", infoPtr->help, (char *) NULL);
continue;
}
Tcl_AppendResult(interp, "\n ", infoPtr->key, ":", (char *) NULL);
numSpaces = width + 1 - strlen(infoPtr->key);
while (numSpaces > 0) {
if (numSpaces >= NUM_SPACES) {
Tcl_AppendResult(interp, spaces, (char *) NULL);
} else {
Tcl_AppendResult(interp, spaces+NUM_SPACES-numSpaces,
(char *) NULL);
}
numSpaces -= NUM_SPACES;
}
Tcl_AppendResult(interp, infoPtr->help, (char *) NULL);
switch (infoPtr->type) {
case TK_ARGV_INT: {
sprintf(tmp, "%d", *((int *) infoPtr->dst));
Tcl_AppendResult(interp, "\n\t\tDefault value: ",
tmp, (char *) NULL);
break;
}
case TK_ARGV_FLOAT: {
sprintf(tmp, "%g", *((double *) infoPtr->dst));
Tcl_AppendResult(interp, "\n\t\tDefault value: ",
tmp, (char *) NULL);
break;
}
case TK_ARGV_STRING: {
char *string;
string = *((char **) infoPtr->dst);
if (string != NULL) {
Tcl_AppendResult(interp, "\n\t\tDefault value: \"",
string, "\"", (char *) NULL);
}
break;
}
default: {
break;
}
}
}
if ((flags & TK_ARGV_NO_DEFAULTS) || (i > 0)) {
break;
}
Tcl_AppendResult(interp, "\nGeneric options for all commands:",
(char *) NULL);
}
}