| [175] | 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 | 
 | 
|---|