source: trunk/video/RpOp.c @ 4503

Last change on this file since 4503 was 2890, checked in by gah, 9 years ago

created video package

File size: 7.1 KB
Line 
1
2/*
3 * RpOp.c --
4 *
5 * This module implements utility procedures for the BLT toolkit.
6 *
7 *      Copyright 1991-2004 George A Howlett.
8 *
9 *      Permission is hereby granted, free of charge, to any person
10 *      obtaining a copy of this software and associated documentation
11 *      files (the "Software"), to deal in the Software without
12 *      restriction, including without limitation the rights to use,
13 *      copy, modify, merge, publish, distribute, sublicense, and/or
14 *      sell copies of the Software, and to permit persons to whom the
15 *      Software is furnished to do so, subject to the following
16 *      conditions:
17 *
18 *      The above copyright notice and this permission notice shall be
19 *      included in all copies or substantial portions of the
20 *      Software.
21 *
22 *      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
23 *      KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
24 *      WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 *      PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
26 *      OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
27 *      OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
28 *      OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 *      SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 */
31
32#include <tcl.h>
33#include <string.h>
34#include "RpOp.h"
35/*
36 *---------------------------------------------------------------------------
37 *
38 * BinaryOpSearch --
39 *
40 *      Performs a binary search on the array of command operation
41 *      specifications to find a partial, anchored match for the given
42 *      operation string.
43 *
44 * Results:
45 *      If the string matches unambiguously the index of the specification in
46 *      the array is returned.  If the string does not match, even as an
47 *      abbreviation, any operation, -1 is returned.  If the string matches,
48 *      but ambiguously -2 is returned.
49 *
50 *---------------------------------------------------------------------------
51 */
52static int
53BinaryOpSearch(
54    Rp_OpSpec *specs,
55    int nSpecs,
56    char *string)               /* Name of minor operation to search for */
57{
58    char c;
59    int high, low;
60    size_t length;
61
62    low = 0;
63    high = nSpecs - 1;
64    c = string[0];
65    length = strlen(string);
66    while (low <= high) {
67        Rp_OpSpec *specPtr;
68        int compare;
69        int median;
70       
71        median = (low + high) >> 1;
72        specPtr = specs + median;
73
74        /* Test the first character */
75        compare = c - specPtr->name[0];
76        if (compare == 0) {
77            /* Now test the entire string */
78            compare = strncmp(string, specPtr->name, length);
79            if (compare == 0) {
80                if ((int)length < specPtr->minChars) {
81                    return -2;  /* Ambiguous operation name */
82                }
83            }
84        }
85        if (compare < 0) {
86            high = median - 1;
87        } else if (compare > 0) {
88            low = median + 1;
89        } else {
90            return median;      /* Op found. */
91        }
92    }
93    return -1;                  /* Can't find operation */
94}
95
96/*
97 *---------------------------------------------------------------------------
98 *
99 * LinearOpSearch --
100 *
101 *      Performs a binary search on the array of command operation
102 *      specifications to find a partial, anchored match for the given
103 *      operation string.
104 *
105 * Results:
106 *      If the string matches unambiguously the index of the specification in
107 *      the array is returned.  If the string does not match, even as an
108 *      abbreviation, any operation, -1 is returned.  If the string matches,
109 *      but ambiguously -2 is returned.
110 *
111 *---------------------------------------------------------------------------
112 */
113static int
114LinearOpSearch(
115    Rp_OpSpec *specs,
116    int nSpecs,
117    char *string)               /* Name of minor operation to search for */
118{
119    Rp_OpSpec *specPtr;
120    char c;
121    size_t length;
122    int nMatches, last;
123    int i;
124
125    c = string[0];
126    length = strlen(string);
127    nMatches = 0;
128    last = -1;
129    for (specPtr = specs, i = 0; i < nSpecs; i++, specPtr++) {
130        if ((c == specPtr->name[0]) &&
131            (strncmp(string, specPtr->name, length) == 0)) {
132            last = i;
133            nMatches++;
134            if ((int)length == specPtr->minChars) {
135                break;
136            }
137        }
138    }
139    if (nMatches > 1) {
140        return -2;              /* Ambiguous operation name */
141    }
142    if (nMatches == 0) {
143        return -1;              /* Can't find operation */
144    }
145    return last;                /* Op found. */
146}
147
148/*
149 *---------------------------------------------------------------------------
150 *
151 * Rp_GetOpFromObj --
152 *
153 *      Find the command operation given a string name.  This is useful where
154 *      a group of command operations have the same argument signature.
155 *
156 * Results:
157 *      If found, a pointer to the procedure (function pointer) is returned.
158 *      Otherwise NULL is returned and an error message containing a list of
159 *      the possible commands is returned in interp->result.
160 *
161 *---------------------------------------------------------------------------
162 */
163void *
164Rp_GetOpFromObj(
165    Tcl_Interp *interp,         /* Interpreter to report errors to */
166    int nSpecs,                 /* Number of specifications in array */
167    Rp_OpSpec *specs,           /* Op specification array */
168    int operPos,                /* Position of operation in argument list. */
169    int objc,                   /* Number of arguments in the argument vector.
170                                 * This includes any prefixed arguments */
171    Tcl_Obj *const *objv,       /* Argument vector */
172    int flags)
173{
174    Rp_OpSpec *specPtr;
175    char *string;
176    int n;
177
178    if (objc <= operPos) {      /* No operation argument */
179        Tcl_AppendResult(interp, "wrong # args: ", (char *)NULL);
180      usage:
181        Tcl_AppendResult(interp, "should be one of...", (char *)NULL);
182        for (n = 0; n < nSpecs; n++) {
183            int i;
184
185            Tcl_AppendResult(interp, "\n  ", (char *)NULL);
186            for (i = 0; i < operPos; i++) {
187                Tcl_AppendResult(interp, Tcl_GetString(objv[i]), " ",
188                         (char *)NULL);
189            }
190            specPtr = specs + n;
191            Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage,
192                (char *)NULL);
193        }
194        return NULL;
195    }
196    string = Tcl_GetString(objv[operPos]);
197    if (flags & RP_OP_LINEAR_SEARCH) {
198        n = LinearOpSearch(specs, nSpecs, string);
199    } else {
200        n = BinaryOpSearch(specs, nSpecs, string);
201    }
202    if (n == -2) {
203        char c;
204        size_t length;
205
206        Tcl_AppendResult(interp, "ambiguous", (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, "\" matches: ",
212            (char *)NULL);
213
214        c = string[0];
215        length = strlen(string);
216        for (n = 0; n < nSpecs; n++) {
217            specPtr = specs + n;
218            if ((c == specPtr->name[0]) &&
219                (strncmp(string, specPtr->name, length) == 0)) {
220                Tcl_AppendResult(interp, " ", specPtr->name, (char *)NULL);
221            }
222        }
223        return NULL;
224
225    } else if (n == -1) {       /* Can't find operation, display help */
226        Tcl_AppendResult(interp, "bad", (char *)NULL);
227        if (operPos > 2) {
228            Tcl_AppendResult(interp, " ", Tcl_GetString(objv[operPos - 1]),
229                (char *)NULL);
230        }
231        Tcl_AppendResult(interp, " operation \"", string, "\": ", (char *)NULL);
232        goto usage;
233    }
234    specPtr = specs + n;
235    if ((objc < specPtr->minArgs) ||
236        ((specPtr->maxArgs > 0) && (objc > specPtr->maxArgs))) {
237        int i;
238
239        Tcl_AppendResult(interp, "wrong # args: should be \"", (char *)NULL);
240        for (i = 0; i < operPos; i++) {
241            Tcl_AppendResult(interp, Tcl_GetString(objv[i]), " ",
242                (char *)NULL);
243        }
244        Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage, "\"",
245            (char *)NULL);
246        return NULL;
247    }
248    return specPtr->proc;
249}
Note: See TracBrowser for help on using the repository browser.