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

Last change on this file since 2936 was 2936, checked in by gah, 12 years ago

sync back with trunk

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