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

Last change on this file since 4060 was 4060, checked in by ldelgass, 6 years ago

Add separate configure scripts for nanovis and vtkvis, remove them from the
vizservers configure (which now only configures nanoscale and pymolproxy).

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