1 | /*
|
---|
2 | * bltUtil.c --
|
---|
3 | *
|
---|
4 | * This module implements utility procedures for the BLT
|
---|
5 | * toolkit.
|
---|
6 | *
|
---|
7 | * Copyright 1991-1998 Lucent Technologies, Inc.
|
---|
8 | *
|
---|
9 | * Permission to use, copy, modify, and distribute this software and
|
---|
10 | * its documentation for any purpose and without fee is hereby
|
---|
11 | * granted, provided that the above copyright notice appear in all
|
---|
12 | * copies and that both that the copyright notice and warranty
|
---|
13 | * disclaimer appear in supporting documentation, and that the names
|
---|
14 | * of Lucent Technologies any of their entities not be used in
|
---|
15 | * advertising or publicity pertaining to distribution of the software
|
---|
16 | * without specific, written prior permission.
|
---|
17 | *
|
---|
18 | * Lucent Technologies disclaims all warranties with regard to this
|
---|
19 | * software, including all implied warranties of merchantability and
|
---|
20 | * fitness. In no event shall Lucent Technologies be liable for any
|
---|
21 | * special, indirect or consequential damages or any damages
|
---|
22 | * whatsoever resulting from loss of use, data or profits, whether in
|
---|
23 | * an action of contract, negligence or other tortuous action, arising
|
---|
24 | * out of or in connection with the use or performance of this
|
---|
25 | * software.
|
---|
26 | */
|
---|
27 |
|
---|
28 | #include "bltInt.h"
|
---|
29 | #if defined(__STDC__)
|
---|
30 | #include <stdarg.h>
|
---|
31 | #else
|
---|
32 | #include <varargs.h>
|
---|
33 | #endif
|
---|
34 | #include "bltHash.h"
|
---|
35 |
|
---|
36 | #ifndef HAVE_STRTOLOWER
|
---|
37 | void
|
---|
38 | strtolower(s)
|
---|
39 | register char *s;
|
---|
40 | {
|
---|
41 | while (*s != '\0') {
|
---|
42 | *s = tolower(UCHAR(*s));
|
---|
43 | s++;
|
---|
44 | }
|
---|
45 | }
|
---|
46 | #endif /* !HAVE_STRTOLOWER */
|
---|
47 |
|
---|
48 | #ifndef HAVE_STRCASECMP
|
---|
49 |
|
---|
50 | static unsigned char caseTable[] =
|
---|
51 | {
|
---|
52 | (unsigned char)'\000', (unsigned char)'\001',
|
---|
53 | (unsigned char)'\002', (unsigned char)'\003',
|
---|
54 | (unsigned char)'\004', (unsigned char)'\005',
|
---|
55 | (unsigned char)'\006', (unsigned char)'\007',
|
---|
56 | (unsigned char)'\010', (unsigned char)'\011',
|
---|
57 | (unsigned char)'\012', (unsigned char)'\013',
|
---|
58 | (unsigned char)'\014', (unsigned char)'\015',
|
---|
59 | (unsigned char)'\016', (unsigned char)'\017',
|
---|
60 | (unsigned char)'\020', (unsigned char)'\021',
|
---|
61 | (unsigned char)'\022', (unsigned char)'\023',
|
---|
62 | (unsigned char)'\024', (unsigned char)'\025',
|
---|
63 | (unsigned char)'\026', (unsigned char)'\027',
|
---|
64 | (unsigned char)'\030', (unsigned char)'\031',
|
---|
65 | (unsigned char)'\032', (unsigned char)'\033',
|
---|
66 | (unsigned char)'\034', (unsigned char)'\035',
|
---|
67 | (unsigned char)'\036', (unsigned char)'\037',
|
---|
68 | (unsigned char)'\040', (unsigned char)'\041',
|
---|
69 | (unsigned char)'\042', (unsigned char)'\043',
|
---|
70 | (unsigned char)'\044', (unsigned char)'\045',
|
---|
71 | (unsigned char)'\046', (unsigned char)'\047',
|
---|
72 | (unsigned char)'\050', (unsigned char)'\051',
|
---|
73 | (unsigned char)'\052', (unsigned char)'\053',
|
---|
74 | (unsigned char)'\054', (unsigned char)'\055',
|
---|
75 | (unsigned char)'\056', (unsigned char)'\057',
|
---|
76 | (unsigned char)'\060', (unsigned char)'\061',
|
---|
77 | (unsigned char)'\062', (unsigned char)'\063',
|
---|
78 | (unsigned char)'\064', (unsigned char)'\065',
|
---|
79 | (unsigned char)'\066', (unsigned char)'\067',
|
---|
80 | (unsigned char)'\070', (unsigned char)'\071',
|
---|
81 | (unsigned char)'\072', (unsigned char)'\073',
|
---|
82 | (unsigned char)'\074', (unsigned char)'\075',
|
---|
83 | (unsigned char)'\076', (unsigned char)'\077',
|
---|
84 | (unsigned char)'\100', (unsigned char)'\141',
|
---|
85 | (unsigned char)'\142', (unsigned char)'\143',
|
---|
86 | (unsigned char)'\144', (unsigned char)'\145',
|
---|
87 | (unsigned char)'\146', (unsigned char)'\147',
|
---|
88 | (unsigned char)'\150', (unsigned char)'\151',
|
---|
89 | (unsigned char)'\152', (unsigned char)'\153',
|
---|
90 | (unsigned char)'\154', (unsigned char)'\155',
|
---|
91 | (unsigned char)'\156', (unsigned char)'\157',
|
---|
92 | (unsigned char)'\160', (unsigned char)'\161',
|
---|
93 | (unsigned char)'\162', (unsigned char)'\163',
|
---|
94 | (unsigned char)'\164', (unsigned char)'\165',
|
---|
95 | (unsigned char)'\166', (unsigned char)'\167',
|
---|
96 | (unsigned char)'\170', (unsigned char)'\171',
|
---|
97 | (unsigned char)'\172', (unsigned char)'\133',
|
---|
98 | (unsigned char)'\134', (unsigned char)'\135',
|
---|
99 | (unsigned char)'\136', (unsigned char)'\137',
|
---|
100 | (unsigned char)'\140', (unsigned char)'\141',
|
---|
101 | (unsigned char)'\142', (unsigned char)'\143',
|
---|
102 | (unsigned char)'\144', (unsigned char)'\145',
|
---|
103 | (unsigned char)'\146', (unsigned char)'\147',
|
---|
104 | (unsigned char)'\150', (unsigned char)'\151',
|
---|
105 | (unsigned char)'\152', (unsigned char)'\153',
|
---|
106 | (unsigned char)'\154', (unsigned char)'\155',
|
---|
107 | (unsigned char)'\156', (unsigned char)'\157',
|
---|
108 | (unsigned char)'\160', (unsigned char)'\161',
|
---|
109 | (unsigned char)'\162', (unsigned char)'\163',
|
---|
110 | (unsigned char)'\164', (unsigned char)'\165',
|
---|
111 | (unsigned char)'\166', (unsigned char)'\167',
|
---|
112 | (unsigned char)'\170', (unsigned char)'\171',
|
---|
113 | (unsigned char)'\172', (unsigned char)'\173',
|
---|
114 | (unsigned char)'\174', (unsigned char)'\175',
|
---|
115 | (unsigned char)'\176', (unsigned char)'\177',
|
---|
116 | (unsigned char)'\200', (unsigned char)'\201',
|
---|
117 | (unsigned char)'\202', (unsigned char)'\203',
|
---|
118 | (unsigned char)'\204', (unsigned char)'\205',
|
---|
119 | (unsigned char)'\206', (unsigned char)'\207',
|
---|
120 | (unsigned char)'\210', (unsigned char)'\211',
|
---|
121 | (unsigned char)'\212', (unsigned char)'\213',
|
---|
122 | (unsigned char)'\214', (unsigned char)'\215',
|
---|
123 | (unsigned char)'\216', (unsigned char)'\217',
|
---|
124 | (unsigned char)'\220', (unsigned char)'\221',
|
---|
125 | (unsigned char)'\222', (unsigned char)'\223',
|
---|
126 | (unsigned char)'\224', (unsigned char)'\225',
|
---|
127 | (unsigned char)'\226', (unsigned char)'\227',
|
---|
128 | (unsigned char)'\230', (unsigned char)'\231',
|
---|
129 | (unsigned char)'\232', (unsigned char)'\233',
|
---|
130 | (unsigned char)'\234', (unsigned char)'\235',
|
---|
131 | (unsigned char)'\236', (unsigned char)'\237',
|
---|
132 | (unsigned char)'\240', (unsigned char)'\241',
|
---|
133 | (unsigned char)'\242', (unsigned char)'\243',
|
---|
134 | (unsigned char)'\244', (unsigned char)'\245',
|
---|
135 | (unsigned char)'\246', (unsigned char)'\247',
|
---|
136 | (unsigned char)'\250', (unsigned char)'\251',
|
---|
137 | (unsigned char)'\252', (unsigned char)'\253',
|
---|
138 | (unsigned char)'\254', (unsigned char)'\255',
|
---|
139 | (unsigned char)'\256', (unsigned char)'\257',
|
---|
140 | (unsigned char)'\260', (unsigned char)'\261',
|
---|
141 | (unsigned char)'\262', (unsigned char)'\263',
|
---|
142 | (unsigned char)'\264', (unsigned char)'\265',
|
---|
143 | (unsigned char)'\266', (unsigned char)'\267',
|
---|
144 | (unsigned char)'\270', (unsigned char)'\271',
|
---|
145 | (unsigned char)'\272', (unsigned char)'\273',
|
---|
146 | (unsigned char)'\274', (unsigned char)'\275',
|
---|
147 | (unsigned char)'\276', (unsigned char)'\277',
|
---|
148 | (unsigned char)'\300', (unsigned char)'\341',
|
---|
149 | (unsigned char)'\342', (unsigned char)'\343',
|
---|
150 | (unsigned char)'\344', (unsigned char)'\345',
|
---|
151 | (unsigned char)'\346', (unsigned char)'\347',
|
---|
152 | (unsigned char)'\350', (unsigned char)'\351',
|
---|
153 | (unsigned char)'\352', (unsigned char)'\353',
|
---|
154 | (unsigned char)'\354', (unsigned char)'\355',
|
---|
155 | (unsigned char)'\356', (unsigned char)'\357',
|
---|
156 | (unsigned char)'\360', (unsigned char)'\361',
|
---|
157 | (unsigned char)'\362', (unsigned char)'\363',
|
---|
158 | (unsigned char)'\364', (unsigned char)'\365',
|
---|
159 | (unsigned char)'\366', (unsigned char)'\367',
|
---|
160 | (unsigned char)'\370', (unsigned char)'\371',
|
---|
161 | (unsigned char)'\372', (unsigned char)'\333',
|
---|
162 | (unsigned char)'\334', (unsigned char)'\335',
|
---|
163 | (unsigned char)'\336', (unsigned char)'\337',
|
---|
164 | (unsigned char)'\340', (unsigned char)'\341',
|
---|
165 | (unsigned char)'\342', (unsigned char)'\343',
|
---|
166 | (unsigned char)'\344', (unsigned char)'\345',
|
---|
167 | (unsigned char)'\346', (unsigned char)'\347',
|
---|
168 | (unsigned char)'\350', (unsigned char)'\351',
|
---|
169 | (unsigned char)'\352', (unsigned char)'\353',
|
---|
170 | (unsigned char)'\354', (unsigned char)'\355',
|
---|
171 | (unsigned char)'\356', (unsigned char)'\357',
|
---|
172 | (unsigned char)'\360', (unsigned char)'\361',
|
---|
173 | (unsigned char)'\362', (unsigned char)'\363',
|
---|
174 | (unsigned char)'\364', (unsigned char)'\365',
|
---|
175 | (unsigned char)'\366', (unsigned char)'\367',
|
---|
176 | (unsigned char)'\370', (unsigned char)'\371',
|
---|
177 | (unsigned char)'\372', (unsigned char)'\373',
|
---|
178 | (unsigned char)'\374', (unsigned char)'\375',
|
---|
179 | (unsigned char)'\376', (unsigned char)'\377',
|
---|
180 | };
|
---|
181 |
|
---|
182 | /*
|
---|
183 | *----------------------------------------------------------------------
|
---|
184 | *
|
---|
185 | * strcasecmp --
|
---|
186 | *
|
---|
187 | * Compare two strings, disregarding case.
|
---|
188 | *
|
---|
189 | * Results:
|
---|
190 | * Returns a signed integer representing the following:
|
---|
191 | *
|
---|
192 | * zero - two strings are equal
|
---|
193 | * negative - first string is less than second
|
---|
194 | * positive - first string is greater than second
|
---|
195 | *
|
---|
196 | *----------------------------------------------------------------------
|
---|
197 | */
|
---|
198 | int
|
---|
199 | strcasecmp(s1, s2)
|
---|
200 | CONST char *s1;
|
---|
201 | CONST char *s2;
|
---|
202 | {
|
---|
203 | unsigned char *s = (unsigned char *)s1;
|
---|
204 | unsigned char *t = (unsigned char *)s2;
|
---|
205 |
|
---|
206 | for ( /* empty */ ; (caseTable[*s] == caseTable[*t]); s++, t++) {
|
---|
207 | if (*s == '\0') {
|
---|
208 | return 0;
|
---|
209 | }
|
---|
210 | }
|
---|
211 | return (caseTable[*s] - caseTable[*t]);
|
---|
212 | }
|
---|
213 |
|
---|
214 | /*
|
---|
215 | *----------------------------------------------------------------------
|
---|
216 | *
|
---|
217 | * strncasecmp --
|
---|
218 | *
|
---|
219 | * Compare two strings, disregarding case, up to a given length.
|
---|
220 | *
|
---|
221 | * Results:
|
---|
222 | * Returns a signed integer representing the following:
|
---|
223 | *
|
---|
224 | * zero - two strings are equal
|
---|
225 | * negative - first string is less than second
|
---|
226 | * positive - first string is greater than second
|
---|
227 | *
|
---|
228 | *----------------------------------------------------------------------
|
---|
229 | */
|
---|
230 | int
|
---|
231 | strncasecmp(s1, s2, length)
|
---|
232 | CONST char *s1;
|
---|
233 | CONST char *s2;
|
---|
234 | size_t length;
|
---|
235 | {
|
---|
236 | register unsigned char *s = (unsigned char *)s1;
|
---|
237 | register unsigned char *t = (unsigned char *)s2;
|
---|
238 |
|
---|
239 | for ( /* empty */ ; (length > 0); s++, t++, length--) {
|
---|
240 | if (caseTable[*s] != caseTable[*t]) {
|
---|
241 | return (caseTable[*s] - caseTable[*t]);
|
---|
242 | }
|
---|
243 | if (*s == '\0') {
|
---|
244 | return 0;
|
---|
245 | }
|
---|
246 | }
|
---|
247 | return 0;
|
---|
248 | }
|
---|
249 |
|
---|
250 | #endif /* !HAVE_STRCASECMP */
|
---|
251 |
|
---|
252 |
|
---|
253 | #if (TCL_VERSION_NUMBER < _VERSION(8,1,0)) && (TCL_MAJOR_VERSION > 7)
|
---|
254 |
|
---|
255 | char *
|
---|
256 | Tcl_GetString(Tcl_Obj *objPtr)
|
---|
257 | {
|
---|
258 | unsigned int dummy;
|
---|
259 |
|
---|
260 | return Tcl_GetStringFromObj(objPtr, &dummy);
|
---|
261 | }
|
---|
262 |
|
---|
263 | int
|
---|
264 | Tcl_EvalObjv(Tcl_Interp *interp, int objc, Tcl_Obj **objv, int flags)
|
---|
265 | {
|
---|
266 | Tcl_DString dString;
|
---|
267 | register int i;
|
---|
268 | int result;
|
---|
269 |
|
---|
270 | Tcl_DStringInit(&dString);
|
---|
271 | for (i = 0; i < objc; i++) {
|
---|
272 | Tcl_DStringAppendElement(&dString, Tcl_GetString(objv[i]));
|
---|
273 | }
|
---|
274 | result = Tcl_Eval(interp, Tcl_DStringValue(&dString));
|
---|
275 | Tcl_DStringFree(&dString);
|
---|
276 | return result;
|
---|
277 | }
|
---|
278 |
|
---|
279 | int
|
---|
280 | Tcl_WriteObj(Tcl_Channel channel, Tcl_Obj *objPtr)
|
---|
281 | {
|
---|
282 | char *data;
|
---|
283 | int nBytes;
|
---|
284 |
|
---|
285 | data = Tcl_GetStringFromObj(objPtr, &nBytes);
|
---|
286 | return Tcl_Write(channel, data, nBytes);
|
---|
287 | }
|
---|
288 |
|
---|
289 | char *
|
---|
290 | Tcl_SetVar2Ex(
|
---|
291 | Tcl_Interp *interp,
|
---|
292 | char *part1,
|
---|
293 | char *part2,
|
---|
294 | Tcl_Obj *objPtr,
|
---|
295 | int flags)
|
---|
296 | {
|
---|
297 | return Tcl_SetVar2(interp, part1, part2, Tcl_GetString(objPtr), flags);
|
---|
298 | }
|
---|
299 |
|
---|
300 | Tcl_Obj *
|
---|
301 | Tcl_GetVar2Ex(
|
---|
302 | Tcl_Interp *interp,
|
---|
303 | char *part1,
|
---|
304 | char *part2,
|
---|
305 | int flags)
|
---|
306 | {
|
---|
307 | char *result;
|
---|
308 |
|
---|
309 | result = Tcl_GetVar2(interp, part1, part2, flags);
|
---|
310 | if (result == NULL) {
|
---|
311 | return NULL;
|
---|
312 | }
|
---|
313 | return Tcl_NewStringObj(result, -1);
|
---|
314 | }
|
---|
315 |
|
---|
316 | #endif
|
---|
317 |
|
---|
318 | /*
|
---|
319 | *----------------------------------------------------------------------
|
---|
320 | *
|
---|
321 | * CompareByDictionary
|
---|
322 | *
|
---|
323 | * This function compares two strings as if they were being used in
|
---|
324 | * an index or card catalog. The case of alphabetic characters is
|
---|
325 | * ignored, except to break ties. Thus "B" comes before "b" but
|
---|
326 | * after "a". Also, integers embedded in the strings compare in
|
---|
327 | * numerical order. In other words, "x10y" comes after "x9y", not
|
---|
328 | * before it as it would when using strcmp().
|
---|
329 | *
|
---|
330 | * Results:
|
---|
331 | * A negative result means that the first element comes before the
|
---|
332 | * second, and a positive result means that the second element
|
---|
333 | * should come first. A result of zero means the two elements
|
---|
334 | * are equal and it doesn't matter which comes first.
|
---|
335 | *
|
---|
336 | * Side effects:
|
---|
337 | * None.
|
---|
338 | *
|
---|
339 | *----------------------------------------------------------------------
|
---|
340 | */
|
---|
341 |
|
---|
342 | #if HAVE_UTF
|
---|
343 | int
|
---|
344 | Blt_DictionaryCompare(left, right)
|
---|
345 | char *left, *right;
|
---|
346 | {
|
---|
347 | Tcl_UniChar uniLeft, uniRight, uniLeftLower, uniRightLower;
|
---|
348 | int diff, zeros;
|
---|
349 | int secondaryDiff = 0;
|
---|
350 |
|
---|
351 | for(;;) {
|
---|
352 | if ((isdigit(UCHAR(*right))) && (isdigit(UCHAR(*left)))) {
|
---|
353 | /*
|
---|
354 | * There are decimal numbers embedded in the two
|
---|
355 | * strings. Compare them as numbers, rather than
|
---|
356 | * strings. If one number has more leading zeros than
|
---|
357 | * the other, the number with more leading zeros sorts
|
---|
358 | * later, but only as a secondary choice.
|
---|
359 | */
|
---|
360 |
|
---|
361 | zeros = 0;
|
---|
362 | while ((*right == '0') && (isdigit(UCHAR(right[1])))) {
|
---|
363 | right++;
|
---|
364 | zeros--;
|
---|
365 | }
|
---|
366 | while ((*left == '0') && (isdigit(UCHAR(left[1])))) {
|
---|
367 | left++;
|
---|
368 | zeros++;
|
---|
369 | }
|
---|
370 | if (secondaryDiff == 0) {
|
---|
371 | secondaryDiff = zeros;
|
---|
372 | }
|
---|
373 |
|
---|
374 | /*
|
---|
375 | * The code below compares the numbers in the two
|
---|
376 | * strings without ever converting them to integers. It
|
---|
377 | * does this by first comparing the lengths of the
|
---|
378 | * numbers and then comparing the digit values.
|
---|
379 | */
|
---|
380 |
|
---|
381 | diff = 0;
|
---|
382 | for (;;) {
|
---|
383 | if (diff == 0) {
|
---|
384 | diff = UCHAR(*left) - UCHAR(*right);
|
---|
385 | }
|
---|
386 | right++;
|
---|
387 | left++;
|
---|
388 |
|
---|
389 | /* Ignore commas in numbers. */
|
---|
390 | if (*left == ',') {
|
---|
391 | left++;
|
---|
392 | }
|
---|
393 | if (*right == ',') {
|
---|
394 | right++;
|
---|
395 | }
|
---|
396 |
|
---|
397 | if (!isdigit(UCHAR(*right))) { /* INTL: digit */
|
---|
398 | if (isdigit(UCHAR(*left))) { /* INTL: digit */
|
---|
399 | return 1;
|
---|
400 | } else {
|
---|
401 | /*
|
---|
402 | * The two numbers have the same length. See
|
---|
403 | * if their values are different.
|
---|
404 | */
|
---|
405 |
|
---|
406 | if (diff != 0) {
|
---|
407 | return diff;
|
---|
408 | }
|
---|
409 | break;
|
---|
410 | }
|
---|
411 | } else if (!isdigit(UCHAR(*left))) { /* INTL: digit */
|
---|
412 | return -1;
|
---|
413 | }
|
---|
414 | }
|
---|
415 | continue;
|
---|
416 | }
|
---|
417 |
|
---|
418 | /*
|
---|
419 | * Convert character to Unicode for comparison purposes. If either
|
---|
420 | * string is at the terminating null, do a byte-wise comparison and
|
---|
421 | * bail out immediately.
|
---|
422 | */
|
---|
423 | if ((*left != '\0') && (*right != '\0')) {
|
---|
424 | left += Tcl_UtfToUniChar(left, &uniLeft);
|
---|
425 | right += Tcl_UtfToUniChar(right, &uniRight);
|
---|
426 | /*
|
---|
427 | * Convert both chars to lower for the comparison, because
|
---|
428 | * dictionary sorts are case insensitve. Convert to lower, not
|
---|
429 | * upper, so chars between Z and a will sort before A (where most
|
---|
430 | * other interesting punctuations occur)
|
---|
431 | */
|
---|
432 | uniLeftLower = Tcl_UniCharToLower(uniLeft);
|
---|
433 | uniRightLower = Tcl_UniCharToLower(uniRight);
|
---|
434 | } else {
|
---|
435 | diff = UCHAR(*left) - UCHAR(*right);
|
---|
436 | break;
|
---|
437 | }
|
---|
438 |
|
---|
439 | diff = uniLeftLower - uniRightLower;
|
---|
440 | if (diff) {
|
---|
441 | return diff;
|
---|
442 | } else if (secondaryDiff == 0) {
|
---|
443 | if (Tcl_UniCharIsUpper(uniLeft) &&
|
---|
444 | Tcl_UniCharIsLower(uniRight)) {
|
---|
445 | secondaryDiff = -1;
|
---|
446 | } else if (Tcl_UniCharIsUpper(uniRight)
|
---|
447 | && Tcl_UniCharIsLower(uniLeft)) {
|
---|
448 | secondaryDiff = 1;
|
---|
449 | }
|
---|
450 | }
|
---|
451 | }
|
---|
452 | if (diff == 0) {
|
---|
453 | diff = secondaryDiff;
|
---|
454 | }
|
---|
455 | return diff;
|
---|
456 | }
|
---|
457 |
|
---|
458 | #else
|
---|
459 |
|
---|
460 | int
|
---|
461 | Blt_DictionaryCompare(left, right)
|
---|
462 | char *left, *right; /* The strings to compare */
|
---|
463 | {
|
---|
464 | int diff, zeros;
|
---|
465 | int secondaryDiff = 0;
|
---|
466 |
|
---|
467 | while (1) {
|
---|
468 | if (isdigit(UCHAR(*right)) && isdigit(UCHAR(*left))) {
|
---|
469 | /*
|
---|
470 | * There are decimal numbers embedded in the two
|
---|
471 | * strings. Compare them as numbers, rather than
|
---|
472 | * strings. If one number has more leading zeros than
|
---|
473 | * the other, the number with more leading zeros sorts
|
---|
474 | * later, but only as a secondary choice.
|
---|
475 | */
|
---|
476 |
|
---|
477 | zeros = 0;
|
---|
478 | while ((*right == '0') && (isdigit(UCHAR(right[1])))) {
|
---|
479 | right++;
|
---|
480 | zeros--;
|
---|
481 | }
|
---|
482 | while ((*left == '0') && (isdigit(UCHAR(left[1])))) {
|
---|
483 | left++;
|
---|
484 | zeros++;
|
---|
485 | }
|
---|
486 | if (secondaryDiff == 0) {
|
---|
487 | secondaryDiff = zeros;
|
---|
488 | }
|
---|
489 |
|
---|
490 | /*
|
---|
491 | * The code below compares the numbers in the two
|
---|
492 | * strings without ever converting them to integers. It
|
---|
493 | * does this by first comparing the lengths of the
|
---|
494 | * numbers and then comparing the digit values.
|
---|
495 | */
|
---|
496 |
|
---|
497 | diff = 0;
|
---|
498 | while (1) {
|
---|
499 | if (diff == 0) {
|
---|
500 | diff = UCHAR(*left) - UCHAR(*right);
|
---|
501 | }
|
---|
502 | right++;
|
---|
503 | left++;
|
---|
504 | /* Ignore commas in numbers. */
|
---|
505 | if (*left == ',') {
|
---|
506 | left++;
|
---|
507 | }
|
---|
508 | if (*right == ',') {
|
---|
509 | right++;
|
---|
510 | }
|
---|
511 | if (!isdigit(UCHAR(*right))) {
|
---|
512 | if (isdigit(UCHAR(*left))) {
|
---|
513 | return 1;
|
---|
514 | } else {
|
---|
515 | /*
|
---|
516 | * The two numbers have the same length. See
|
---|
517 | * if their values are different.
|
---|
518 | */
|
---|
519 |
|
---|
520 | if (diff != 0) {
|
---|
521 | return diff;
|
---|
522 | }
|
---|
523 | break;
|
---|
524 | }
|
---|
525 | } else if (!isdigit(UCHAR(*left))) {
|
---|
526 | return -1;
|
---|
527 | }
|
---|
528 | }
|
---|
529 | continue;
|
---|
530 | }
|
---|
531 | diff = UCHAR(*left) - UCHAR(*right);
|
---|
532 | if (diff) {
|
---|
533 | if (isupper(UCHAR(*left)) && islower(UCHAR(*right))) {
|
---|
534 | diff = UCHAR(tolower(*left)) - UCHAR(*right);
|
---|
535 | if (diff) {
|
---|
536 | return diff;
|
---|
537 | } else if (secondaryDiff == 0) {
|
---|
538 | secondaryDiff = -1;
|
---|
539 | }
|
---|
540 | } else if (isupper(UCHAR(*right)) && islower(UCHAR(*left))) {
|
---|
541 | diff = UCHAR(*left) - UCHAR(tolower(UCHAR(*right)));
|
---|
542 | if (diff) {
|
---|
543 | return diff;
|
---|
544 | } else if (secondaryDiff == 0) {
|
---|
545 | secondaryDiff = 1;
|
---|
546 | }
|
---|
547 | } else {
|
---|
548 | return diff;
|
---|
549 | }
|
---|
550 | }
|
---|
551 | if (*left == 0) {
|
---|
552 | break;
|
---|
553 | }
|
---|
554 | left++;
|
---|
555 | right++;
|
---|
556 | }
|
---|
557 | if (diff == 0) {
|
---|
558 | diff = secondaryDiff;
|
---|
559 | }
|
---|
560 | return diff;
|
---|
561 | }
|
---|
562 | #endif
|
---|
563 |
|
---|
564 | #ifndef NDEBUG
|
---|
565 | void
|
---|
566 | Blt_Assert(testExpr, fileName, lineNumber)
|
---|
567 | char *testExpr;
|
---|
568 | char *fileName;
|
---|
569 | int lineNumber;
|
---|
570 | {
|
---|
571 | #ifdef WINDEBUG
|
---|
572 | PurifyPrintf("line %d of %s: Assert \"%s\" failed\n", lineNumber,
|
---|
573 | fileName, testExpr);
|
---|
574 | #endif
|
---|
575 | fprintf(stderr, "line %d of %s: Assert \"%s\" failed\n",
|
---|
576 | lineNumber, fileName, testExpr);
|
---|
577 | fflush(stderr);
|
---|
578 | abort();
|
---|
579 | }
|
---|
580 | #endif
|
---|
581 |
|
---|
582 | /*ARGSUSED*/
|
---|
583 | void
|
---|
584 | Blt_Panic TCL_VARARGS_DEF(char *, arg1)
|
---|
585 | {
|
---|
586 | va_list argList;
|
---|
587 | char *format;
|
---|
588 |
|
---|
589 | format = TCL_VARARGS_START(char *, arg1, argList);
|
---|
590 | vfprintf(stderr, format, argList);
|
---|
591 | fprintf(stderr, "\n");
|
---|
592 | fflush(stderr);
|
---|
593 | abort();
|
---|
594 | }
|
---|
595 |
|
---|
596 | void
|
---|
597 | Blt_DStringAppendElements
|
---|
598 | TCL_VARARGS_DEF(Tcl_DString *, arg1)
|
---|
599 | {
|
---|
600 | va_list argList;
|
---|
601 | Tcl_DString *dsPtr;
|
---|
602 | register char *elem;
|
---|
603 |
|
---|
604 | dsPtr = TCL_VARARGS_START(Tcl_DString *, arg1, argList);
|
---|
605 | while ((elem = va_arg(argList, char *)) != NULL) {
|
---|
606 | Tcl_DStringAppendElement(dsPtr, elem);
|
---|
607 | }
|
---|
608 | va_end(argList);
|
---|
609 | }
|
---|
610 |
|
---|
611 | static char stringRep[200];
|
---|
612 |
|
---|
613 | char *
|
---|
614 | Blt_Itoa(value)
|
---|
615 | int value;
|
---|
616 | {
|
---|
617 | sprintf(stringRep, "%d", value);
|
---|
618 | return stringRep;
|
---|
619 | }
|
---|
620 |
|
---|
621 | char *
|
---|
622 | Blt_Utoa(value)
|
---|
623 | unsigned int value;
|
---|
624 | {
|
---|
625 | sprintf(stringRep, "%u", value);
|
---|
626 | return stringRep;
|
---|
627 | }
|
---|
628 |
|
---|
629 | char *
|
---|
630 | Blt_Dtoa(interp, value)
|
---|
631 | Tcl_Interp *interp;
|
---|
632 | double value;
|
---|
633 | {
|
---|
634 | Tcl_PrintDouble(interp, value, stringRep);
|
---|
635 | return stringRep;
|
---|
636 | }
|
---|
637 |
|
---|
638 | #if HAVE_UTF
|
---|
639 |
|
---|
640 | #undef fopen
|
---|
641 | FILE *
|
---|
642 | Blt_OpenUtfFile(fileName, mode)
|
---|
643 | char *fileName, *mode;
|
---|
644 | {
|
---|
645 | Tcl_DString dString;
|
---|
646 | FILE *f;
|
---|
647 |
|
---|
648 | fileName = Tcl_UtfToExternalDString(NULL, fileName, -1, &dString);
|
---|
649 | f = fopen(fileName, mode);
|
---|
650 | Tcl_DStringFree(&dString);
|
---|
651 | return f;
|
---|
652 | }
|
---|
653 |
|
---|
654 | #endif /* HAVE_UTF */
|
---|
655 |
|
---|
656 | /*
|
---|
657 | *--------------------------------------------------------------
|
---|
658 | *
|
---|
659 | * Blt_InitHexTable --
|
---|
660 | *
|
---|
661 | * Table index for the hex values. Initialized once, first time.
|
---|
662 | * Used for translation value or delimiter significance lookup.
|
---|
663 | *
|
---|
664 | * We build the table at run time for several reasons:
|
---|
665 | *
|
---|
666 | * 1. portable to non-ASCII machines.
|
---|
667 | * 2. still reentrant since we set the init flag after setting
|
---|
668 | * table.
|
---|
669 | * 3. easier to extend.
|
---|
670 | * 4. less prone to bugs.
|
---|
671 | *
|
---|
672 | * Results:
|
---|
673 | * None.
|
---|
674 | *
|
---|
675 | *--------------------------------------------------------------
|
---|
676 | */
|
---|
677 | void
|
---|
678 | Blt_InitHexTable(hexTable)
|
---|
679 | char hexTable[];
|
---|
680 | {
|
---|
681 | hexTable['0'] = 0;
|
---|
682 | hexTable['1'] = 1;
|
---|
683 | hexTable['2'] = 2;
|
---|
684 | hexTable['3'] = 3;
|
---|
685 | hexTable['4'] = 4;
|
---|
686 | hexTable['5'] = 5;
|
---|
687 | hexTable['6'] = 6;
|
---|
688 | hexTable['7'] = 7;
|
---|
689 | hexTable['8'] = 8;
|
---|
690 | hexTable['9'] = 9;
|
---|
691 | hexTable['a'] = hexTable['A'] = 10;
|
---|
692 | hexTable['b'] = hexTable['B'] = 11;
|
---|
693 | hexTable['c'] = hexTable['C'] = 12;
|
---|
694 | hexTable['d'] = hexTable['D'] = 13;
|
---|
695 | hexTable['e'] = hexTable['E'] = 14;
|
---|
696 | hexTable['f'] = hexTable['F'] = 15;
|
---|
697 | }
|
---|
698 |
|
---|
699 | /*
|
---|
700 | *--------------------------------------------------------------
|
---|
701 | *
|
---|
702 | * Blt_GetPosition --
|
---|
703 | *
|
---|
704 | * Convert a string representing a numeric position.
|
---|
705 | * A position can be in one of the following forms.
|
---|
706 | *
|
---|
707 | * number - number of the item in the hierarchy, indexed
|
---|
708 | * from zero.
|
---|
709 | * "end" - last position in the hierarchy.
|
---|
710 | *
|
---|
711 | * Results:
|
---|
712 | * A standard Tcl result. If "string" is a valid index, then
|
---|
713 | * *indexPtr is filled with the corresponding numeric index.
|
---|
714 | * If "end" was selected then *indexPtr is set to -1.
|
---|
715 | * Otherwise an error message is left in interp->result.
|
---|
716 | *
|
---|
717 | * Side effects:
|
---|
718 | * None.
|
---|
719 | *
|
---|
720 | *--------------------------------------------------------------
|
---|
721 | */
|
---|
722 | int
|
---|
723 | Blt_GetPosition(interp, string, indexPtr)
|
---|
724 | Tcl_Interp *interp; /* Interpreter to report results back
|
---|
725 | * to. */
|
---|
726 | char *string; /* String representation of the index.
|
---|
727 | * Can be an integer or "end" to refer
|
---|
728 | * to the last index. */
|
---|
729 | int *indexPtr; /* Holds the converted index. */
|
---|
730 | {
|
---|
731 | if ((string[0] == 'e') && (strcmp(string, "end") == 0)) {
|
---|
732 | *indexPtr = -1; /* Indicates last position in hierarchy. */
|
---|
733 | } else {
|
---|
734 | int position;
|
---|
735 |
|
---|
736 | if (Tcl_GetInt(interp, string, &position) != TCL_OK) {
|
---|
737 | return TCL_ERROR;
|
---|
738 | }
|
---|
739 | if (position < 0) {
|
---|
740 | Tcl_AppendResult(interp, "bad position \"", string, "\"",
|
---|
741 | (char *)NULL);
|
---|
742 | return TCL_ERROR;
|
---|
743 | }
|
---|
744 | *indexPtr = position;
|
---|
745 | }
|
---|
746 | return TCL_OK;
|
---|
747 | }
|
---|
748 |
|
---|
749 | /*
|
---|
750 | * The hash table below is used to keep track of all the Blt_Uids created
|
---|
751 | * so far.
|
---|
752 | */
|
---|
753 | static Blt_HashTable uidTable;
|
---|
754 | static int uidInitialized = 0;
|
---|
755 |
|
---|
756 | /*
|
---|
757 | *----------------------------------------------------------------------
|
---|
758 | *
|
---|
759 | * Blt_GetUid --
|
---|
760 | *
|
---|
761 | * Given a string, returns a unique identifier for the string.
|
---|
762 | * A reference count is maintained, so that the identifier
|
---|
763 | * can be freed when it is not needed any more. This can be used
|
---|
764 | * in many places to replace Tcl_GetUid.
|
---|
765 | *
|
---|
766 | * Results:
|
---|
767 | * This procedure returns a Blt_Uid corresponding to the "string"
|
---|
768 | * argument. The Blt_Uid has a string value identical to string
|
---|
769 | * (strcmp will return 0), but it's guaranteed that any other
|
---|
770 | * calls to this procedure with a string equal to "string" will
|
---|
771 | * return exactly the same result (i.e. can compare Blt_Uid
|
---|
772 | * *values* directly, without having to call strcmp on what they
|
---|
773 | * point to).
|
---|
774 | *
|
---|
775 | * Side effects:
|
---|
776 | * New information may be entered into the identifier table.
|
---|
777 | *
|
---|
778 | *----------------------------------------------------------------------
|
---|
779 | */
|
---|
780 | Blt_Uid
|
---|
781 | Blt_GetUid(string)
|
---|
782 | char *string; /* String to convert. */
|
---|
783 | {
|
---|
784 | int isNew;
|
---|
785 | Blt_HashEntry *hPtr;
|
---|
786 | int refCount;
|
---|
787 |
|
---|
788 | if (!uidInitialized) {
|
---|
789 | Blt_InitHashTable(&uidTable, BLT_STRING_KEYS);
|
---|
790 | uidInitialized = 1;
|
---|
791 | }
|
---|
792 | hPtr = Blt_CreateHashEntry(&uidTable, string, &isNew);
|
---|
793 | if (isNew) {
|
---|
794 | refCount = 0;
|
---|
795 | } else {
|
---|
796 | refCount = (int)Blt_GetHashValue(hPtr);
|
---|
797 | }
|
---|
798 | refCount++;
|
---|
799 | Blt_SetHashValue(hPtr, (ClientData)refCount);
|
---|
800 | return (Blt_Uid)Blt_GetHashKey(&uidTable, hPtr);
|
---|
801 | }
|
---|
802 |
|
---|
803 | /*
|
---|
804 | *----------------------------------------------------------------------
|
---|
805 | *
|
---|
806 | * Blt_FreeUid --
|
---|
807 | *
|
---|
808 | * Frees the Blt_Uid if there are no more clients using this
|
---|
809 | * identifier.
|
---|
810 | *
|
---|
811 | * Results:
|
---|
812 | * None.
|
---|
813 | *
|
---|
814 | * Side effects:
|
---|
815 | * The identifier may be deleted from the identifier table.
|
---|
816 | *
|
---|
817 | *----------------------------------------------------------------------
|
---|
818 | */
|
---|
819 | void
|
---|
820 | Blt_FreeUid(uid)
|
---|
821 | Blt_Uid uid; /* Identifier to release. */
|
---|
822 | {
|
---|
823 | Blt_HashEntry *hPtr;
|
---|
824 |
|
---|
825 | if (!uidInitialized) {
|
---|
826 | Blt_InitHashTable(&uidTable, BLT_STRING_KEYS);
|
---|
827 | uidInitialized = 1;
|
---|
828 | }
|
---|
829 | hPtr = Blt_FindHashEntry(&uidTable, uid);
|
---|
830 | if (hPtr) {
|
---|
831 | int refCount;
|
---|
832 |
|
---|
833 | refCount = (int)Blt_GetHashValue(hPtr);
|
---|
834 | refCount--;
|
---|
835 | if (refCount == 0) {
|
---|
836 | Blt_DeleteHashEntry(&uidTable, hPtr);
|
---|
837 | } else {
|
---|
838 | Blt_SetHashValue(hPtr, (ClientData)refCount);
|
---|
839 | }
|
---|
840 | } else {
|
---|
841 | fprintf(stderr, "tried to release unknown identifier \"%s\"\n", uid);
|
---|
842 | }
|
---|
843 | }
|
---|
844 |
|
---|
845 | /*
|
---|
846 | *----------------------------------------------------------------------
|
---|
847 | *
|
---|
848 | * Blt_FindUid --
|
---|
849 | *
|
---|
850 | * Returns a Blt_Uid associated with a given string, if one exists.
|
---|
851 | *
|
---|
852 | * Results:
|
---|
853 | * A Blt_Uid for the string if one exists. Otherwise NULL.
|
---|
854 | *
|
---|
855 | *----------------------------------------------------------------------
|
---|
856 | */
|
---|
857 | Blt_Uid
|
---|
858 | Blt_FindUid(string)
|
---|
859 | char *string; /* String to find. */
|
---|
860 | {
|
---|
861 | Blt_HashEntry *hPtr;
|
---|
862 |
|
---|
863 | if (!uidInitialized) {
|
---|
864 | Blt_InitHashTable(&uidTable, BLT_STRING_KEYS);
|
---|
865 | uidInitialized = 1;
|
---|
866 | }
|
---|
867 | hPtr = Blt_FindHashEntry(&uidTable, string);
|
---|
868 | if (hPtr == NULL) {
|
---|
869 | return NULL;
|
---|
870 | }
|
---|
871 | return (Blt_Uid) Blt_GetHashKey(&uidTable, hPtr);
|
---|
872 | }
|
---|
873 |
|
---|
874 | /*
|
---|
875 | *----------------------------------------------------------------------
|
---|
876 | *
|
---|
877 | * BinaryOpSearch --
|
---|
878 | *
|
---|
879 | * Performs a binary search on the array of command operation
|
---|
880 | * specifications to find a partial, anchored match for the
|
---|
881 | * given operation string.
|
---|
882 | *
|
---|
883 | * Results:
|
---|
884 | * If the string matches unambiguously the index of the specification
|
---|
885 | * in the array is returned. If the string does not match, even
|
---|
886 | * as an abbreviation, any operation, -1 is returned. If the string
|
---|
887 | * matches, but ambiguously -2 is returned.
|
---|
888 | *
|
---|
889 | *----------------------------------------------------------------------
|
---|
890 | */
|
---|
891 | static int
|
---|
892 | BinaryOpSearch(specArr, nSpecs, string)
|
---|
893 | Blt_OpSpec specArr[];
|
---|
894 | int nSpecs;
|
---|
895 | char *string; /* Name of minor operation to search for */
|
---|
896 | {
|
---|
897 | Blt_OpSpec *specPtr;
|
---|
898 | char c;
|
---|
899 | register int high, low, median;
|
---|
900 | register int compare, length;
|
---|
901 |
|
---|
902 | low = 0;
|
---|
903 | high = nSpecs - 1;
|
---|
904 | c = string[0];
|
---|
905 | length = strlen(string);
|
---|
906 | while (low <= high) {
|
---|
907 | median = (low + high) >> 1;
|
---|
908 | specPtr = specArr + median;
|
---|
909 |
|
---|
910 | /* Test the first character */
|
---|
911 | compare = c - specPtr->name[0];
|
---|
912 | if (compare == 0) {
|
---|
913 | /* Now test the entire string */
|
---|
914 | compare = strncmp(string, specPtr->name, length);
|
---|
915 | if (compare == 0) {
|
---|
916 | if (length < specPtr->minChars) {
|
---|
917 | return -2; /* Ambiguous operation name */
|
---|
918 | }
|
---|
919 | }
|
---|
920 | }
|
---|
921 | if (compare < 0) {
|
---|
922 | high = median - 1;
|
---|
923 | } else if (compare > 0) {
|
---|
924 | low = median + 1;
|
---|
925 | } else {
|
---|
926 | return median; /* Op found. */
|
---|
927 | }
|
---|
928 | }
|
---|
929 | return -1; /* Can't find operation */
|
---|
930 | }
|
---|
931 |
|
---|
932 |
|
---|
933 | /*
|
---|
934 | *----------------------------------------------------------------------
|
---|
935 | *
|
---|
936 | * LinearOpSearch --
|
---|
937 | *
|
---|
938 | * Performs a binary search on the array of command operation
|
---|
939 | * specifications to find a partial, anchored match for the
|
---|
940 | * given operation string.
|
---|
941 | *
|
---|
942 | * Results:
|
---|
943 | * If the string matches unambiguously the index of the specification
|
---|
944 | * in the array is returned. If the string does not match, even
|
---|
945 | * as an abbreviation, any operation, -1 is returned. If the string
|
---|
946 | * matches, but ambiguously -2 is returned.
|
---|
947 | *
|
---|
948 | *----------------------------------------------------------------------
|
---|
949 | */
|
---|
950 | static int
|
---|
951 | LinearOpSearch(specArr, nSpecs, string)
|
---|
952 | Blt_OpSpec specArr[];
|
---|
953 | int nSpecs;
|
---|
954 | char *string; /* Name of minor operation to search for */
|
---|
955 | {
|
---|
956 | Blt_OpSpec *specPtr;
|
---|
957 | char c;
|
---|
958 | int length, nMatches, last;
|
---|
959 | register int i;
|
---|
960 |
|
---|
961 | c = string[0];
|
---|
962 | length = strlen(string);
|
---|
963 | nMatches = 0;
|
---|
964 | last = -1;
|
---|
965 | for (specPtr = specArr, i = 0; i < nSpecs; i++, specPtr++) {
|
---|
966 | if ((c == specPtr->name[0]) &&
|
---|
967 | (strncmp(string, specPtr->name, length) == 0)) {
|
---|
968 | last = i;
|
---|
969 | nMatches++;
|
---|
970 | if (length == specPtr->minChars) {
|
---|
971 | break;
|
---|
972 | }
|
---|
973 | }
|
---|
974 | }
|
---|
975 | if (nMatches > 1) {
|
---|
976 | return -2; /* Ambiguous operation name */
|
---|
977 | }
|
---|
978 | if (nMatches == 0) {
|
---|
979 | return -1; /* Can't find operation */
|
---|
980 | }
|
---|
981 | return last; /* Op found. */
|
---|
982 | }
|
---|
983 |
|
---|
984 | /*
|
---|
985 | *----------------------------------------------------------------------
|
---|
986 | *
|
---|
987 | * Blt_GetOp --
|
---|
988 | *
|
---|
989 | * Find the command operation given a string name. This is useful
|
---|
990 | * where a group of command operations have the same argument
|
---|
991 | * signature.
|
---|
992 | *
|
---|
993 | * Results:
|
---|
994 | * If found, a pointer to the procedure (function pointer) is
|
---|
995 | * returned. Otherwise NULL is returned and an error message
|
---|
996 | * containing a list of the possible commands is returned in
|
---|
997 | * interp->result.
|
---|
998 | *
|
---|
999 | *----------------------------------------------------------------------
|
---|
1000 | */
|
---|
1001 | Blt_Op
|
---|
1002 | Blt_GetOp(interp, nSpecs, specArr, operPos, argc, argv, flags)
|
---|
1003 | Tcl_Interp *interp; /* Interpreter to report errors to */
|
---|
1004 | int nSpecs; /* Number of specifications in array */
|
---|
1005 | Blt_OpSpec specArr[]; /* Op specification array */
|
---|
1006 | int operPos; /* Index of the operation name argument */
|
---|
1007 | int argc; /* Number of arguments in the argument vector.
|
---|
1008 | * This includes any prefixed arguments */
|
---|
1009 | char *argv[]; /* Argument vector */
|
---|
1010 | int flags; /* */
|
---|
1011 | {
|
---|
1012 | Blt_OpSpec *specPtr;
|
---|
1013 | char *string;
|
---|
1014 | register int i;
|
---|
1015 | register int n;
|
---|
1016 |
|
---|
1017 | if (argc <= operPos) { /* No operation argument */
|
---|
1018 | Tcl_AppendResult(interp, "wrong # args: ", (char *)NULL);
|
---|
1019 | usage:
|
---|
1020 | Tcl_AppendResult(interp, "should be one of...", (char *)NULL);
|
---|
1021 | for (n = 0; n < nSpecs; n++) {
|
---|
1022 | Tcl_AppendResult(interp, "\n ", (char *)NULL);
|
---|
1023 | for (i = 0; i < operPos; i++) {
|
---|
1024 | Tcl_AppendResult(interp, argv[i], " ", (char *)NULL);
|
---|
1025 | }
|
---|
1026 | specPtr = specArr + n;
|
---|
1027 | Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage,
|
---|
1028 | (char *)NULL);
|
---|
1029 | }
|
---|
1030 | return NULL;
|
---|
1031 | }
|
---|
1032 | string = argv[operPos];
|
---|
1033 | if (flags & BLT_OP_LINEAR_SEARCH) {
|
---|
1034 | n = LinearOpSearch(specArr, nSpecs, string);
|
---|
1035 | } else {
|
---|
1036 | n = BinaryOpSearch(specArr, nSpecs, string);
|
---|
1037 | }
|
---|
1038 | if (n == -2) {
|
---|
1039 | char c;
|
---|
1040 | int length;
|
---|
1041 |
|
---|
1042 | Tcl_AppendResult(interp, "ambiguous", (char *)NULL);
|
---|
1043 | if (operPos > 2) {
|
---|
1044 | Tcl_AppendResult(interp, " ", argv[operPos - 1], (char *)NULL);
|
---|
1045 | }
|
---|
1046 | Tcl_AppendResult(interp, " operation \"", string, "\" matches:",
|
---|
1047 | (char *)NULL);
|
---|
1048 |
|
---|
1049 | c = string[0];
|
---|
1050 | length = strlen(string);
|
---|
1051 | for (n = 0; n < nSpecs; n++) {
|
---|
1052 | specPtr = specArr + n;
|
---|
1053 | if ((c == specPtr->name[0]) &&
|
---|
1054 | (strncmp(string, specPtr->name, length) == 0)) {
|
---|
1055 | Tcl_AppendResult(interp, " ", specPtr->name, (char *)NULL);
|
---|
1056 | }
|
---|
1057 | }
|
---|
1058 | return NULL;
|
---|
1059 |
|
---|
1060 | } else if (n == -1) { /* Can't find operation, display help */
|
---|
1061 | Tcl_AppendResult(interp, "bad", (char *)NULL);
|
---|
1062 | if (operPos > 2) {
|
---|
1063 | Tcl_AppendResult(interp, " ", argv[operPos - 1], (char *)NULL);
|
---|
1064 | }
|
---|
1065 | Tcl_AppendResult(interp, " operation \"", string, "\": ",
|
---|
1066 | (char *)NULL);
|
---|
1067 | goto usage;
|
---|
1068 | }
|
---|
1069 | specPtr = specArr + n;
|
---|
1070 | if ((argc < specPtr->minArgs) || ((specPtr->maxArgs > 0) &&
|
---|
1071 | (argc > specPtr->maxArgs))) {
|
---|
1072 | Tcl_AppendResult(interp, "wrong # args: should be \"", (char *)NULL);
|
---|
1073 | for (i = 0; i < operPos; i++) {
|
---|
1074 | Tcl_AppendResult(interp, argv[i], " ", (char *)NULL);
|
---|
1075 | }
|
---|
1076 | Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage, "\"",
|
---|
1077 | (char *)NULL);
|
---|
1078 | return NULL;
|
---|
1079 | }
|
---|
1080 | return specPtr->proc;
|
---|
1081 | }
|
---|
1082 |
|
---|
1083 | #if (TCL_VERSION_NUMBER >= _VERSION(8,0,0))
|
---|
1084 |
|
---|
1085 | /*
|
---|
1086 | *----------------------------------------------------------------------
|
---|
1087 | *
|
---|
1088 | * Blt_GetOpFromObj --
|
---|
1089 | *
|
---|
1090 | * Find the command operation given a string name. This is useful
|
---|
1091 | * where a group of command operations have the same argument
|
---|
1092 | * signature.
|
---|
1093 | *
|
---|
1094 | * Results:
|
---|
1095 | * If found, a pointer to the procedure (function pointer) is
|
---|
1096 | * returned. Otherwise NULL is returned and an error message
|
---|
1097 | * containing a list of the possible commands is returned in
|
---|
1098 | * interp->result.
|
---|
1099 | *
|
---|
1100 | *----------------------------------------------------------------------
|
---|
1101 | */
|
---|
1102 | Blt_Op
|
---|
1103 | Blt_GetOpFromObj(interp, nSpecs, specArr, operPos, objc, objv, flags)
|
---|
1104 | Tcl_Interp *interp; /* Interpreter to report errors to */
|
---|
1105 | int nSpecs; /* Number of specifications in array */
|
---|
1106 | Blt_OpSpec specArr[]; /* Op specification array */
|
---|
1107 | int operPos; /* Position of operation in argument list. */
|
---|
1108 | int objc; /* Number of arguments in the argument vector.
|
---|
1109 | * This includes any prefixed arguments */
|
---|
1110 | Tcl_Obj *CONST objv[]; /* Argument vector */
|
---|
1111 | int flags;
|
---|
1112 | {
|
---|
1113 | Blt_OpSpec *specPtr;
|
---|
1114 | char *string;
|
---|
1115 | register int i;
|
---|
1116 | register int n;
|
---|
1117 |
|
---|
1118 | if (objc <= operPos) { /* No operation argument */
|
---|
1119 | Tcl_AppendResult(interp, "wrong # args: ", (char *)NULL);
|
---|
1120 | usage:
|
---|
1121 | Tcl_AppendResult(interp, "should be one of...", (char *)NULL);
|
---|
1122 | for (n = 0; n < nSpecs; n++) {
|
---|
1123 | Tcl_AppendResult(interp, "\n ", (char *)NULL);
|
---|
1124 | for (i = 0; i < operPos; i++) {
|
---|
1125 | Tcl_AppendResult(interp, Tcl_GetString(objv[i]), " ",
|
---|
1126 | (char *)NULL);
|
---|
1127 | }
|
---|
1128 | specPtr = specArr + n;
|
---|
1129 | Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage,
|
---|
1130 | (char *)NULL);
|
---|
1131 | }
|
---|
1132 | return NULL;
|
---|
1133 | }
|
---|
1134 | string = Tcl_GetString(objv[operPos]);
|
---|
1135 | if (flags & BLT_OP_LINEAR_SEARCH) {
|
---|
1136 | n = LinearOpSearch(specArr, nSpecs, string);
|
---|
1137 | } else {
|
---|
1138 | n = BinaryOpSearch(specArr, nSpecs, string);
|
---|
1139 | }
|
---|
1140 | if (n == -2) {
|
---|
1141 | char c;
|
---|
1142 | int length;
|
---|
1143 |
|
---|
1144 | Tcl_AppendResult(interp, "ambiguous", (char *)NULL);
|
---|
1145 | if (operPos > 2) {
|
---|
1146 | Tcl_AppendResult(interp, " ", Tcl_GetString(objv[operPos - 1]),
|
---|
1147 | (char *)NULL);
|
---|
1148 | }
|
---|
1149 | Tcl_AppendResult(interp, " operation \"", string, "\" matches:",
|
---|
1150 | (char *)NULL);
|
---|
1151 |
|
---|
1152 | c = string[0];
|
---|
1153 | length = strlen(string);
|
---|
1154 | for (n = 0; n < nSpecs; n++) {
|
---|
1155 | specPtr = specArr + n;
|
---|
1156 | if ((c == specPtr->name[0]) &&
|
---|
1157 | (strncmp(string, specPtr->name, length) == 0)) {
|
---|
1158 | Tcl_AppendResult(interp, " ", specPtr->name, (char *)NULL);
|
---|
1159 | }
|
---|
1160 | }
|
---|
1161 | return NULL;
|
---|
1162 |
|
---|
1163 | } else if (n == -1) { /* Can't find operation, display help */
|
---|
1164 | Tcl_AppendResult(interp, "bad", (char *)NULL);
|
---|
1165 | if (operPos > 2) {
|
---|
1166 | Tcl_AppendResult(interp, " ", Tcl_GetString(objv[operPos - 1]),
|
---|
1167 | (char *)NULL);
|
---|
1168 | }
|
---|
1169 | Tcl_AppendResult(interp, " operation \"", string, "\": ", (char *)NULL);
|
---|
1170 | goto usage;
|
---|
1171 | }
|
---|
1172 | specPtr = specArr + n;
|
---|
1173 | if ((objc < specPtr->minArgs) ||
|
---|
1174 | ((specPtr->maxArgs > 0) && (objc > specPtr->maxArgs))) {
|
---|
1175 | Tcl_AppendResult(interp, "wrong # args: should be \"", (char *)NULL);
|
---|
1176 | for (i = 0; i < operPos; i++) {
|
---|
1177 | Tcl_AppendResult(interp, Tcl_GetString(objv[i]), " ",
|
---|
1178 | (char *)NULL);
|
---|
1179 | }
|
---|
1180 | Tcl_AppendResult(interp, specPtr->name, " ", specPtr->usage, "\"",
|
---|
1181 | (char *)NULL);
|
---|
1182 | return NULL;
|
---|
1183 | }
|
---|
1184 | return specPtr->proc;
|
---|
1185 | }
|
---|
1186 |
|
---|
1187 | #endif
|
---|
1188 |
|
---|
1189 | #include <stdio.h>
|
---|
1190 |
|
---|
1191 | /* open a file
|
---|
1192 | * calculate the CRC32 of the entire contents
|
---|
1193 | * return the CRC
|
---|
1194 | * if there is an error rdet the global variable Crcerror
|
---|
1195 | */
|
---|
1196 |
|
---|
1197 | /* ---------------------------------------------------------------- */
|
---|
1198 |
|
---|
1199 | /* this is the CRC32 lookup table
|
---|
1200 | * thanks Gary S. Brown
|
---|
1201 | * 64 lines of 4 values for a 256 dword table (1024 bytes)
|
---|
1202 | */
|
---|
1203 | static unsigned long crcTab[256] =
|
---|
1204 | { /* CRC polynomial 0xedb88320 */
|
---|
1205 | 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL,
|
---|
1206 | 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL,
|
---|
1207 | 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL,
|
---|
1208 | 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL,
|
---|
1209 | 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
|
---|
1210 | 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL,
|
---|
1211 | 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL,
|
---|
1212 | 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL,
|
---|
1213 | 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL,
|
---|
1214 | 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
|
---|
1215 | 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL,
|
---|
1216 | 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL,
|
---|
1217 | 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL,
|
---|
1218 | 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL,
|
---|
1219 | 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
|
---|
1220 | 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL,
|
---|
1221 | 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL,
|
---|
1222 | 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL,
|
---|
1223 | 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL,
|
---|
1224 | 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
|
---|
1225 | 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL,
|
---|
1226 | 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL,
|
---|
1227 | 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL,
|
---|
1228 | 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL,
|
---|
1229 | 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
|
---|
1230 | 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL,
|
---|
1231 | 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL,
|
---|
1232 | 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL,
|
---|
1233 | 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL,
|
---|
1234 | 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
|
---|
1235 | 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL,
|
---|
1236 | 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL,
|
---|
1237 | 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL,
|
---|
1238 | 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL,
|
---|
1239 | 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
|
---|
1240 | 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL,
|
---|
1241 | 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL,
|
---|
1242 | 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL,
|
---|
1243 | 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL,
|
---|
1244 | 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
|
---|
1245 | 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL,
|
---|
1246 | 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL,
|
---|
1247 | 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL,
|
---|
1248 | 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL,
|
---|
1249 | 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
|
---|
1250 | 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL,
|
---|
1251 | 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL,
|
---|
1252 | 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL,
|
---|
1253 | 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL,
|
---|
1254 | 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
|
---|
1255 | 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL,
|
---|
1256 | 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL,
|
---|
1257 | 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL,
|
---|
1258 | 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL,
|
---|
1259 | 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
|
---|
1260 | 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL,
|
---|
1261 | 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL,
|
---|
1262 | 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL,
|
---|
1263 | 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL,
|
---|
1264 | 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
|
---|
1265 | 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL,
|
---|
1266 | 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL,
|
---|
1267 | 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL,
|
---|
1268 | 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL
|
---|
1269 | };
|
---|
1270 |
|
---|
1271 | #define CRC32(c, b) (crcTab[((int)(c) ^ (b)) & 0xff] ^ ((c) >> 8))
|
---|
1272 | #define DO1(buf) crc = CRC32(crc, *buf++)
|
---|
1273 | #define DO2(buf) DO1(buf); DO1(buf)
|
---|
1274 | #define DO4(buf) DO2(buf); DO2(buf)
|
---|
1275 | #define DO8(buf) DO4(buf); DO4(buf)
|
---|
1276 |
|
---|
1277 | static int
|
---|
1278 | Crc32Cmd(
|
---|
1279 | ClientData clientData,
|
---|
1280 | Tcl_Interp *interp,
|
---|
1281 | int argc, char **argv)
|
---|
1282 | {
|
---|
1283 | register unsigned int crc;
|
---|
1284 | char buf[200];
|
---|
1285 |
|
---|
1286 | crc = 0L;
|
---|
1287 | crc = crc ^ 0xffffffffL;
|
---|
1288 | if (strcmp(argv[1], "-data") == 0) {
|
---|
1289 | register char *p;
|
---|
1290 |
|
---|
1291 | if (argc != 3) {
|
---|
1292 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
---|
1293 | " ?fileName? ?-data dataString?", (char *)NULL);
|
---|
1294 | return TCL_ERROR;
|
---|
1295 | }
|
---|
1296 | for (p = argv[2]; *p != '\0'; p++) {
|
---|
1297 | crc = CRC32(crc, *p);
|
---|
1298 | }
|
---|
1299 | } else {
|
---|
1300 | register int c;
|
---|
1301 | FILE *f;
|
---|
1302 |
|
---|
1303 | if (argc != 2) {
|
---|
1304 | Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
---|
1305 | " ?fileName? ?-data dataString?", (char *)NULL);
|
---|
1306 | return TCL_ERROR;
|
---|
1307 | }
|
---|
1308 | f = fopen(argv[1], "rb");
|
---|
1309 | if (f == NULL) {
|
---|
1310 | Tcl_AppendResult(interp, "can't open file \"", argv[1], "\": ",
|
---|
1311 | Tcl_PosixError(interp), (char *)NULL);
|
---|
1312 | return TCL_ERROR;
|
---|
1313 | }
|
---|
1314 | while((c = getc(f)) != EOF) {
|
---|
1315 | crc = CRC32(crc, c);
|
---|
1316 | }
|
---|
1317 | fclose(f);
|
---|
1318 | }
|
---|
1319 | crc = crc ^ 0xffffffffL;
|
---|
1320 | sprintf(buf, "%x", crc);
|
---|
1321 | Tcl_SetResult(interp, buf, TCL_VOLATILE);
|
---|
1322 | return TCL_OK;
|
---|
1323 | }
|
---|
1324 |
|
---|
1325 | int
|
---|
1326 | Blt_Crc32Init(interp)
|
---|
1327 | Tcl_Interp *interp;
|
---|
1328 | {
|
---|
1329 | static Blt_CmdSpec cmdSpec = {"crc32", Crc32Cmd,};
|
---|
1330 |
|
---|
1331 | if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) {
|
---|
1332 | return TCL_ERROR;
|
---|
1333 | }
|
---|
1334 | return TCL_OK;
|
---|
1335 | }
|
---|
1336 |
|
---|