source: trunk/packages/vizservers/nanovis/CmdProc.cpp @ 2800

Last change on this file since 2800 was 2798, checked in by ldelgass, 12 years ago

Add emacs mode magic line in preparation for indentation cleanup

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