source: nanovis/branches/1.1/CmdProc.cpp @ 4804

Last change on this file since 4804 was 3502, checked in by ldelgass, 7 years ago

Add basic VTK structured points reader to nanovis, update copyright dates.

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