source: trunk/packages/vizservers/vtkvis/CmdProc.cpp @ 3177

Last change on this file since 3177 was 3177, checked in by mmc, 12 years ago

Updated all of the copyright notices to reference the transfer to
the new HUBzero Foundation, LLC.

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