source: branches/blt4/packages/vizservers/nanovis/CmdProc.cpp @ 1642

Last change on this file since 1642 was 1478, checked in by gah, 15 years ago

Fix volume management routines to handle deletion

File size: 6.4 KB
Line 
1#include <tcl.h>
2#include "CmdProc.h"
3#include <string.h>
4
5/*
6 *-------------------------------------------------------------------------------
7 *
8 * BinaryOpSearch --
9 *
10 *      Performs a binary search on the array of command operation
11 *      specifications to find a partial, anchored match for the given
12 *      operation string.
13 *
14 * Results:
15 *  If the string matches unambiguously the index of the specification in
16 *  the array is returned.  If the string does not match, even as an
17 *  abbreviation, any operation, -1 is returned.  If the string matches,
18 *  but ambiguously -2 is returned.
19 *
20 *-------------------------------------------------------------------------------
21 */
22static int
23BinaryOpSearch(
24    Rappture::CmdSpec *specs,
25    int nSpecs,
26    char *string)       /* Name of minor operation to search for */
27{
28    char c;
29    int high, low;
30    size_t length;
31
32    low = 0;
33    high = nSpecs - 1;
34    c = string[0];
35    length = strlen(string);
36    while (low <= high) {
37    Rappture::CmdSpec *specPtr;
38    int compare;
39    int median;
40   
41    median = (low + high) >> 1;
42    specPtr = specs + median;
43
44    /* Test the first character */
45    compare = c - specPtr->name[0];
46    if (compare == 0) {
47        /* Now test the entire string */
48        compare = strncmp(string, specPtr->name, length);
49        if (compare == 0) {
50        if ((int)length < specPtr->minChars) {
51            return -2;  /* Ambiguous operation name */
52        }
53        }
54    }
55    if (compare < 0) {
56        high = median - 1;
57    } else if (compare > 0) {
58        low = median + 1;
59    } else {
60        return median;  /* Op found. */
61    }
62    }
63    return -1;          /* Can't find operation */
64}
65
66
67/*
68 *-------------------------------------------------------------------------------
69 *
70 * LinearOpSearch --
71 *
72 *      Performs a binary search on the array of command operation
73 *      specifications to find a partial, anchored match for the given
74 *      operation string.
75 *
76 * Results:
77 *  If the string matches unambiguously the index of the specification in
78 *  the array is returned.  If the string does not match, even as an
79 *  abbreviation, any operation, -1 is returned.  If the string matches,
80 *  but ambiguously -2 is returned.
81 *
82 *-------------------------------------------------------------------------------
83 */
84static int
85LinearOpSearch(
86    Rappture::CmdSpec *specs,
87    int nSpecs,
88    char *string)       /* Name of minor operation to search for */
89{
90    Rappture::CmdSpec *specPtr;
91    char c;
92    size_t length;
93    int nMatches, last;
94    int i;
95
96    c = string[0];
97    length = strlen(string);
98    nMatches = 0;
99    last = -1;
100    for (specPtr = specs, i = 0; i < nSpecs; i++, specPtr++) {
101    if ((c == specPtr->name[0]) &&
102        (strncmp(string, specPtr->name, length) == 0)) {
103        last = i;
104        nMatches++;
105        if ((int)length == specPtr->minChars) {
106        break;
107        }
108    }
109    }
110    if (nMatches > 1) {
111    return -2;      /* Ambiguous operation name */
112    }
113    if (nMatches == 0) {
114    return -1;      /* Can't find operation */
115    }
116    return last;        /* Op found. */
117}
118
119/*
120 *-------------------------------------------------------------------------------
121 *
122 * GetOpFromObj --
123 *
124 *      Find the command operation given a string name.  This is useful where
125 *      a group of command operations have the same argument signature.
126 *
127 * Results:
128 *      If found, a pointer to the procedure (function pointer) is returned.
129 *      Otherwise NULL is returned and an error message containing a list of
130 *      the possible commands is returned in interp->result.
131 *
132 *-------------------------------------------------------------------------------
133 */
134Tcl_ObjCmdProc *
135Rappture::GetOpFromObj(
136    Tcl_Interp *interp,                 /* Interpreter to report errors to */
137    int nSpecs,                         /* Number of specifications in array */
138    CmdSpec *specs,                     /* Op specification array */
139    int operPos,                        /* Position of operation in argument
140                                         * list. */
141    int objc,                           /* Number of arguments in the argument
142                                         * vector.  This includes any prefixed
143                                         * arguments */
144    Tcl_Obj *CONST *objv,               /* Argument vector */
145    int flags)
146{
147    CmdSpec *specPtr;
148    char *string;
149    int n;
150
151    if (objc <= operPos) {  /* No operation argument */
152    Tcl_AppendResult(interp, "wrong # args: ", (char *)NULL);
153      usage:
154    Tcl_AppendResult(interp, "should be one of...", (char *)NULL);
155    for (n = 0; n < nSpecs; n++) {
156        int i;
157
158        Tcl_AppendResult(interp, "\n  ", (char *)NULL);
159        for (i = 0; i < operPos; i++) {
160        Tcl_AppendResult(interp, Tcl_GetString(objv[i]), " ",
161             (char *)NULL);
162        }
163        specPtr = specs + n;
164        Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage,
165        (char *)NULL);
166    }
167    return NULL;
168    }
169    string = Tcl_GetString(objv[operPos]);
170    if (flags & CMDSPEC_LINEAR_SEARCH) {
171    n = LinearOpSearch(specs, nSpecs, string);
172    } else {
173    n = BinaryOpSearch(specs, nSpecs, string);
174    }
175    if (n == -2) {
176    char c;
177    size_t length;
178
179    Tcl_AppendResult(interp, "ambiguous", (char *)NULL);
180    if (operPos > 2) {
181        Tcl_AppendResult(interp, " ", Tcl_GetString(objv[operPos - 1]),
182        (char *)NULL);
183    }
184    Tcl_AppendResult(interp, " operation \"", string, "\" matches: ",
185        (char *)NULL);
186
187    c = string[0];
188    length = strlen(string);
189    for (n = 0; n < nSpecs; n++) {
190        specPtr = specs + n;
191        if ((c == specPtr->name[0]) &&
192        (strncmp(string, specPtr->name, length) == 0)) {
193        Tcl_AppendResult(interp, " ", specPtr->name, (char *)NULL);
194        }
195    }
196    return NULL;
197
198    } else if (n == -1) {   /* Can't find operation, display help */
199    Tcl_AppendResult(interp, "bad", (char *)NULL);
200    if (operPos > 2) {
201        Tcl_AppendResult(interp, " ", Tcl_GetString(objv[operPos - 1]),
202        (char *)NULL);
203    }
204    Tcl_AppendResult(interp, " operation \"", string, "\": ", (char *)NULL);
205    goto usage;
206    }
207    specPtr = specs + n;
208    if ((objc < specPtr->minArgs) ||
209    ((specPtr->maxArgs > 0) && (objc > specPtr->maxArgs))) {
210    int i;
211
212    Tcl_AppendResult(interp, "wrong # args: should be \"", (char *)NULL);
213    for (i = 0; i < operPos; i++) {
214        Tcl_AppendResult(interp, Tcl_GetString(objv[i]), " ",
215        (char *)NULL);
216    }
217    Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage, "\"",
218        (char *)NULL);
219    return NULL;
220    }
221    return specPtr->proc;
222}
Note: See TracBrowser for help on using the repository browser.