summaryrefslogtreecommitdiffstats
path: root/src/bltSwitch.C
diff options
context:
space:
mode:
authorjoye <joye>2013-08-27 18:44:24 (GMT)
committerjoye <joye>2013-08-27 18:44:24 (GMT)
commit48974a09f23839821ca95f228fc0f3f53bb1cefa (patch)
tree9d5cfa1305ef57b69c9b1dd09dc3ffe536c0777d /src/bltSwitch.C
parent05d8c009040abfcb5f62644fbb99c8ff453d4519 (diff)
downloadblt-48974a09f23839821ca95f228fc0f3f53bb1cefa.zip
blt-48974a09f23839821ca95f228fc0f3f53bb1cefa.tar.gz
blt-48974a09f23839821ca95f228fc0f3f53bb1cefa.tar.bz2
*** empty log message ***
Diffstat (limited to 'src/bltSwitch.C')
-rw-r--r--src/bltSwitch.C554
1 files changed, 554 insertions, 0 deletions
diff --git a/src/bltSwitch.C b/src/bltSwitch.C
new file mode 100644
index 0000000..35228d1
--- /dev/null
+++ b/src/bltSwitch.C
@@ -0,0 +1,554 @@
+
+/*
+ * bltSwitch.c --
+ *
+ * This module implements command/argument switch parsing procedures for the
+ * BLT toolkit.
+ *
+ * Copyright 1991-2004 George A Howlett.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "bltInt.h"
+#include <stdarg.h>
+
+#include "bltSwitch.h"
+
+static void
+DoHelp(Tcl_Interp *interp, Blt_SwitchSpec *specs)
+{
+ Tcl_DString ds;
+ Blt_SwitchSpec *sp;
+
+ Tcl_DStringInit(&ds);
+ Tcl_DStringAppend(&ds, "following switches are available:", -1);
+ for (sp = specs; sp->type != BLT_SWITCH_END; sp++) {
+ Tcl_DStringAppend(&ds, "\n ", 4);
+ Tcl_DStringAppend(&ds, sp->switchName, -1);
+ Tcl_DStringAppend(&ds, " ", 1);
+ Tcl_DStringAppend(&ds, sp->help, -1);
+ }
+ Tcl_AppendResult(interp, Tcl_DStringValue(&ds), (char *)NULL);
+ Tcl_DStringFree(&ds);
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * FindSwitchSpec --
+ *
+ * Search through a table of configuration specs, looking for one that
+ * matches a given argvName.
+ *
+ * Results:
+ * The return value is a pointer to the matching entry, or NULL if
+ * nothing matched. In that case an error message is left in the
+ * interp's result.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+static Blt_SwitchSpec *
+FindSwitchSpec(
+ Tcl_Interp *interp, /* Used for reporting errors. */
+ Blt_SwitchSpec *specs, /* Pointer to table of configuration
+ * specifications for a widget. */
+ const char *name, /* Name identifying a particular switch. */
+ int length, /* Length of name. */
+ int needFlags, /* Flags that must be present in matching
+ * entry. */
+ int hateFlags) /* Flags that must NOT be present in matching
+ * entry. */
+{
+ Blt_SwitchSpec *sp;
+ char c; /* First character of current argument. */
+ Blt_SwitchSpec *matchPtr; /* Matching spec, or NULL. */
+
+ c = name[1];
+ matchPtr = NULL;
+ for (sp = specs; sp->type != BLT_SWITCH_END; sp++) {
+ if (sp->switchName == NULL) {
+ continue;
+ }
+ if (((sp->flags & needFlags) != needFlags) || (sp->flags & hateFlags)) {
+ continue;
+ }
+ if ((sp->switchName[1] != c) ||
+ (strncmp(sp->switchName, name, length) != 0)) {
+ continue;
+ }
+ if (sp->switchName[length] == '\0') {
+ return sp; /* Stop on a perfect match. */
+ }
+ if (matchPtr != NULL) {
+ Tcl_AppendResult(interp, "ambiguous switch \"", name, "\"\n",
+ (char *) NULL);
+ DoHelp(interp, specs);
+ return NULL;
+ }
+ matchPtr = sp;
+ }
+ if (strcmp(name, "-help") == 0) {
+ DoHelp(interp, specs);
+ return NULL;
+ }
+ if (matchPtr == NULL) {
+ Tcl_AppendResult(interp, "unknown switch \"", name, "\"\n",
+ (char *)NULL);
+ DoHelp(interp, specs);
+ return NULL;
+ }
+ return matchPtr;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * DoSwitch --
+ *
+ * This procedure applies a single configuration switch to a widget
+ * record.
+ *
+ * Results:
+ * A standard TCL return value.
+ *
+ * Side effects:
+ * WidgRec is modified as indicated by specPtr and value. The old value
+ * is recycled, if that is appropriate for the value type.
+ *
+ *---------------------------------------------------------------------------
+ */
+static int
+DoSwitch(
+ Tcl_Interp *interp, /* Interpreter for error reporting. */
+ Blt_SwitchSpec *sp, /* Specifier to apply. */
+ Tcl_Obj *objPtr, /* Value to use to fill in widgRec. */
+ void *record) /* Record whose fields are to be modified.
+ * Values must be properly initialized. */
+{
+ do {
+ char *ptr;
+
+ ptr = (char *)record + sp->offset;
+ switch (sp->type) {
+ case BLT_SWITCH_BOOLEAN:
+ {
+ int bool;
+
+ if (Tcl_GetBooleanFromObj(interp, objPtr, &bool) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ if (sp->mask > 0) {
+ if (bool) {
+ *((int *)ptr) |= sp->mask;
+ } else {
+ *((int *)ptr) &= ~sp->mask;
+ }
+ } else {
+ *((int *)ptr) = bool;
+ }
+ }
+ break;
+
+ case BLT_SWITCH_DOUBLE:
+ if (Tcl_GetDoubleFromObj(interp, objPtr, (double *)ptr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ break;
+
+ case BLT_SWITCH_OBJ:
+ Tcl_IncrRefCount(objPtr);
+ *(Tcl_Obj **)ptr = objPtr;
+ break;
+
+ case BLT_SWITCH_FLOAT:
+ {
+ double value;
+
+ if (Tcl_GetDoubleFromObj(interp, objPtr, &value) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ *(float *)ptr = (float)value;
+ }
+ break;
+
+ case BLT_SWITCH_INT:
+ if (Tcl_GetIntFromObj(interp, objPtr, (int *)ptr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ break;
+
+ case BLT_SWITCH_INT_NNEG:
+ {
+ long value;
+
+ if (Blt_GetCountFromObj(interp, objPtr, COUNT_NNEG,
+ &value) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ *(int *)ptr = (int)value;
+ }
+ break;
+
+ case BLT_SWITCH_INT_POS:
+ {
+ long value;
+
+ if (Blt_GetCountFromObj(interp, objPtr, COUNT_POS,
+ &value) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ *(int *)ptr = (int)value;
+ }
+ break;
+
+ case BLT_SWITCH_LIST:
+ {
+ int argc;
+
+ if (Tcl_SplitList(interp, Tcl_GetString(objPtr), &argc,
+ (const char ***)ptr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ }
+ break;
+
+ case BLT_SWITCH_LONG:
+ if (Tcl_GetLongFromObj(interp, objPtr, (long *)ptr) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ break;
+
+ case BLT_SWITCH_LONG_NNEG:
+ {
+ long value;
+
+ if (Blt_GetCountFromObj(interp, objPtr, COUNT_NNEG,
+ &value) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ *(long *)ptr = value;
+ }
+ break;
+
+ case BLT_SWITCH_LONG_POS:
+ {
+ long value;
+
+ if (Blt_GetCountFromObj(interp, objPtr, COUNT_POS, &value)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ *(long *)ptr = value;
+ }
+ break;
+
+ case BLT_SWITCH_STRING:
+ {
+ char *value;
+
+ value = Tcl_GetString(objPtr);
+ value = (*value == '\0') ? NULL : Blt_AssertStrdup(value);
+ if (*(char **)ptr != NULL) {
+ Blt_Free(*(char **)ptr);
+ }
+ *(char **)ptr = value;
+ }
+#ifdef notdef
+ {
+ char *old, *new, **strPtr;
+ char *string;
+
+ string = Tcl_GetString(objPtr);
+ strPtr = (char **)ptr;
+ new = ((*string == '\0') && (sp->flags & BLT_SWITCH_NULL_OK))
+ ? NULL : Blt_AssertStrdup(string);
+ old = *strPtr;
+ if (old != NULL) {
+ Blt_Free(old);
+ }
+ *strPtr = new;
+ }
+#endif
+ break;
+
+ case BLT_SWITCH_CUSTOM:
+ assert(sp->customPtr != NULL);
+ if ((*sp->customPtr->parseProc)(sp->customPtr->clientData, interp,
+ sp->switchName, objPtr, (char *)record, sp->offset, sp->flags)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ break;
+
+ default:
+ Tcl_AppendResult(interp, "bad switch table: unknown type \"",
+ Blt_Itoa(sp->type), "\"", (char *)NULL);
+ return TCL_ERROR;
+ }
+ sp++;
+ } while ((sp->switchName == NULL) && (sp->type != BLT_SWITCH_END));
+ return TCL_OK;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Blt_ParseSwitches --
+ *
+ * Process command-line switches to fill in fields of a record with
+ * resources and other parameters.
+ *
+ * Results:
+ * Returns the number of arguments comsumed by parsing the command line.
+ * If an error occurred, -1 will be returned and an error messages can be
+ * found as the interpreter result.
+ *
+ * Side effects:
+ * The fields of widgRec get filled in with information from argc/argv.
+ * Old information in widgRec's fields gets recycled.
+ *
+ *---------------------------------------------------------------------------
+ */
+int
+Blt_ParseSwitches(
+ Tcl_Interp *interp, /* Interpreter for error reporting. */
+ Blt_SwitchSpec *specs, /* Describes legal switches. */
+ int objc, /* Number of elements in argv. */
+ Tcl_Obj *const *objv, /* Command-line switches. */
+ void *record, /* Record whose fields are to be modified.
+ * Values must be properly initialized. */
+ int flags) /* Used to specify additional flags that must
+ * be present in switch specs for them to be
+ * considered. */
+{
+ Blt_SwitchSpec *sp;
+ int count;
+ int needFlags; /* Specs must contain this set of flags or
+ * else they are not considered. */
+ int hateFlags; /* If a spec contains any bits here, it's not
+ * considered. */
+
+ needFlags = flags & ~(BLT_SWITCH_USER_BIT - 1);
+ hateFlags = 0;
+
+ /*
+ * Pass 1: Clear the change flags on all the specs so that we
+ * can check it later.
+ */
+ for (sp = specs; sp->type != BLT_SWITCH_END; sp++) {
+ sp->flags &= ~BLT_SWITCH_SPECIFIED;
+ }
+ /*
+ * Pass 2: Process the arguments that match entries in the specs.
+ * It's an error if the argument doesn't match anything.
+ */
+ for (count = 0; count < objc; count++) {
+ char *arg;
+ int length;
+
+ arg = Tcl_GetStringFromObj(objv[count], &length);
+ if (flags & BLT_SWITCH_OBJV_PARTIAL) {
+ /*
+ * If the argument doesn't start with a '-' (not a switch) or is
+ * '--', stop processing and return the number of arguments
+ * comsumed.
+ */
+ if (arg[0] != '-') {
+ return count;
+ }
+ if ((arg[1] == '-') && (arg[2] == '\0')) {
+ return count + 1; /* include the "--" in the count. */
+ }
+ }
+ sp = FindSwitchSpec(interp, specs, arg, length, needFlags, hateFlags);
+ if (sp == NULL) {
+ return -1;
+ }
+ if (sp->type == BLT_SWITCH_BITMASK) {
+ char *ptr;
+
+ ptr = (char *)record + sp->offset;
+ *((int *)ptr) |= sp->mask;
+ } else if (sp->type == BLT_SWITCH_BITMASK_INVERT) {
+ char *ptr;
+
+ ptr = (char *)record + sp->offset;
+ *((int *)ptr) &= ~sp->mask;
+ } else if (sp->type == BLT_SWITCH_VALUE) {
+ char *ptr;
+
+ ptr = (char *)record + sp->offset;
+ *((int *)ptr) = sp->mask;
+ } else {
+ count++;
+ if (count == objc) {
+ Tcl_AppendResult(interp, "value for \"", arg, "\" missing",
+ (char *) NULL);
+ return -1;
+ }
+ if (DoSwitch(interp, sp, objv[count], record) != TCL_OK) {
+ char msg[200];
+
+ sprintf_s(msg, 200, "\n (processing \"%.40s\" switch)",
+ sp->switchName);
+ Tcl_AddErrorInfo(interp, msg);
+ return -1;
+ }
+ }
+ sp->flags |= BLT_SWITCH_SPECIFIED;
+ }
+ return count;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Blt_FreeSwitches --
+ *
+ * Free up all resources associated with switches.
+ *
+ * Results:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+/* ARGSUSED */
+void
+Blt_FreeSwitches(
+ Blt_SwitchSpec *specs, /* Describes legal switches. */
+ void *record, /* Record whose fields contain current values
+ * for switches. */
+ int needFlags) /* Used to specify additional flags that must
+ * be present in config specs for them to be
+ * considered. */
+{
+ Blt_SwitchSpec *sp;
+
+ for (sp = specs; sp->type != BLT_SWITCH_END; sp++) {
+ if ((sp->flags & needFlags) == needFlags) {
+ char *ptr;
+
+ ptr = (char *)record + sp->offset;
+ switch (sp->type) {
+ case BLT_SWITCH_STRING:
+ case BLT_SWITCH_LIST:
+ if (*((char **) ptr) != NULL) {
+ Blt_Free(*((char **) ptr));
+ *((char **) ptr) = NULL;
+ }
+ break;
+
+ case BLT_SWITCH_OBJ:
+ if (*((Tcl_Obj **) ptr) != NULL) {
+ Tcl_DecrRefCount(*((Tcl_Obj **)ptr));
+ *((Tcl_Obj **) ptr) = NULL;
+ }
+ break;
+
+ case BLT_SWITCH_CUSTOM:
+ assert(sp->customPtr != NULL);
+ if ((*(char **)ptr != NULL) &&
+ (sp->customPtr->freeProc != NULL)) {
+ (*sp->customPtr->freeProc)((char *)record, sp->offset,
+ sp->flags);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * Blt_SwitchModified --
+ *
+ * Given the configuration specifications and one or more switch patterns
+ * (terminated by a NULL), indicate if any of the matching switches has
+ * been reset.
+ *
+ * Results:
+ * Returns 1 if one of the switches have changed, 0 otherwise.
+ *
+ *---------------------------------------------------------------------------
+ */
+int
+Blt_SwitchChanged TCL_VARARGS_DEF(Blt_SwitchSpec *, arg1)
+{
+ va_list argList;
+ Blt_SwitchSpec *specs;
+ Blt_SwitchSpec *sp;
+ char *switchName;
+
+ specs = TCL_VARARGS_START(Blt_SwitchSpec *, arg1, argList);
+ while ((switchName = va_arg(argList, char *)) != NULL) {
+ for (sp = specs; sp->type != BLT_SWITCH_END; sp++) {
+ if ((Tcl_StringMatch(sp->switchName, switchName)) &&
+ (sp->flags & BLT_SWITCH_SPECIFIED)) {
+ va_end(argList);
+ return 1;
+ }
+ }
+ }
+ va_end(argList);
+ return 0;
+}
+
+int
+Blt_ExprDoubleFromObj(Tcl_Interp *interp, Tcl_Obj *objPtr, double *valuePtr)
+{
+ /* First try to extract the value as a double precision number. */
+ if (Tcl_GetDoubleFromObj((Tcl_Interp *)NULL, objPtr, valuePtr) == TCL_OK) {
+ return TCL_OK;
+ }
+ /* Then try to parse it as an expression. */
+ if (Tcl_ExprDouble(interp, Tcl_GetString(objPtr), valuePtr) == TCL_OK) {
+ return TCL_OK;
+ }
+ return TCL_ERROR;
+}
+
+int
+Blt_ExprIntFromObj(
+ Tcl_Interp *interp,
+ Tcl_Obj *objPtr,
+ int *valuePtr)
+{
+ long lvalue;
+
+ /* First try to extract the value as a simple integer. */
+ if (Tcl_GetIntFromObj((Tcl_Interp *)NULL, objPtr, valuePtr) == TCL_OK) {
+ return TCL_OK;
+ }
+ /* Otherwise try to parse it as an expression. */
+ if (Tcl_ExprLong(interp, Tcl_GetString(objPtr), &lvalue) == TCL_OK) {
+ *valuePtr = lvalue;
+ return TCL_OK;
+ }
+ return TCL_ERROR;
+}
+