Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 2 | mjames | 1 | static char const rcsid[] = "@(#) $Id: mktclapp.c,v 1.1.1.1 2003/11/04 23:35:00 mjames Exp $"; |
| 2 | /* |
||
| 3 | ** Copyright (c) 1998, 1999 D. Richard Hipp |
||
| 4 | ** |
||
| 5 | ** This program is free software; you can redistribute it and/or |
||
| 6 | ** modify it under the terms of the GNU General Public |
||
| 7 | ** License as published by the Free Software Foundation; either |
||
| 8 | ** version 2 of the License, or (at your option) any later version. |
||
| 9 | ** |
||
| 10 | ** This program is distributed in the hope that it will be useful, |
||
| 11 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
| 12 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||
| 13 | ** General Public License for more details. |
||
| 14 | ** |
||
| 15 | ** You should have received a copy of the GNU General Public |
||
| 16 | ** License along with this library; if not, write to the |
||
| 17 | ** Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
||
| 18 | ** Boston, MA 02111-1307, USA. |
||
| 19 | ** |
||
| 20 | ** Author contact information: |
||
| 21 | ** drh@acm.org |
||
| 22 | ** http://www.hwaci.com/drh/ |
||
| 23 | */ |
||
| 24 | #include <ctype.h> |
||
| 25 | #include <stdio.h> |
||
| 26 | #include <stdlib.h> |
||
| 27 | #include <string.h> |
||
| 28 | #include <sys/stat.h> |
||
| 29 | #if defined(_WIN32) || defined(WIN32) |
||
| 30 | #include <windows.h> |
||
| 31 | #if !defined(R_OK) |
||
| 32 | #define R_OK 4 |
||
| 33 | #endif |
||
| 34 | #else |
||
| 35 | #include <unistd.h> |
||
| 36 | #endif |
||
| 37 | #include <assert.h> |
||
| 38 | #include <time.h> |
||
| 39 | |||
| 40 | /* |
||
| 41 | ** Version information for this program |
||
| 42 | */ |
||
| 43 | static char zVersion[] = "mktclapp version 3.9. January 30, 2000"; |
||
| 44 | |||
| 45 | /* |
||
| 46 | ** Each new TCL commands discovered while scanning C/C++ source code is |
||
| 47 | ** stored in an instance of the following structure. |
||
| 48 | */ |
||
| 49 | typedef struct EtCmd EtCmd; |
||
| 50 | struct EtCmd |
||
| 51 | { |
||
| 52 | char *zIf; /* Surrounding #if statement */ |
||
| 53 | char *zName; /* Name of the command */ |
||
| 54 | int isObj; /* True if this is a Tcl_Obj command */ |
||
| 55 | EtCmd *pNext; /* Next command on a list of them all */ |
||
| 56 | }; |
||
| 57 | |||
| 58 | /* |
||
| 59 | ** This is a list of all TCL commands in the scanned source |
||
| 60 | */ |
||
| 61 | static EtCmd *cmdList = 0; |
||
| 62 | |||
| 63 | /* |
||
| 64 | ** Number of commands and object commands. |
||
| 65 | */ |
||
| 66 | static int nCmd = 0; |
||
| 67 | static int nObjCmd = 0; |
||
| 68 | |||
| 69 | /* |
||
| 70 | ** Each nested "#if" statement is stored as an instance of the |
||
| 71 | ** following structure. |
||
| 72 | */ |
||
| 73 | typedef struct IfStmt IfStmt; |
||
| 74 | struct IfStmt |
||
| 75 | { |
||
| 76 | char *zArg; /* Argument to the #if. Ex: "defined(DEBUG)" */ |
||
| 77 | int invert; /* True to put a "!" in front */ |
||
| 78 | int line; /* Line number of the original #if */ |
||
| 79 | IfStmt *pNext; /* Next #if statement down on the stack */ |
||
| 80 | }; |
||
| 81 | |||
| 82 | /* |
||
| 83 | ** The nested #if statements |
||
| 84 | */ |
||
| 85 | static IfStmt *ifStack = 0; |
||
| 86 | |||
| 87 | /* |
||
| 88 | ** Name of this program. |
||
| 89 | */ |
||
| 90 | static char *Argv0 = "mktclapp"; |
||
| 91 | |||
| 92 | /* |
||
| 93 | ** Number of errors |
||
| 94 | */ |
||
| 95 | static int nError = 0; |
||
| 96 | |||
| 97 | /* |
||
| 98 | ** Surround the call to Et_AppInit() with this #if |
||
| 99 | */ |
||
| 100 | static char *seenEtAppInit = "0"; |
||
| 101 | |||
| 102 | /* |
||
| 103 | ** Surround the call to Et_PreInit() with this #if |
||
| 104 | */ |
||
| 105 | static char *seenEtPreInit = "0"; |
||
| 106 | |||
| 107 | /* |
||
| 108 | ** Surround the implmentation of main() with the inverse of this #if |
||
| 109 | */ |
||
| 110 | static char *seenMain = "0"; |
||
| 111 | |||
| 112 | /* |
||
| 113 | ** Surround the call to Et_CustomMainLoop() with the inverse of this #if |
||
| 114 | */ |
||
| 115 | static char *seenEtCustomMainLoop = "0"; |
||
| 116 | |||
| 117 | /* |
||
| 118 | ** Allocate memory. Never fail. If not enough memory is available, |
||
| 119 | ** print an error message and abort. |
||
| 120 | */ |
||
| 121 | void *SafeMalloc (int nByte) |
||
| 122 | { |
||
| 123 | void *p = malloc (nByte); |
||
| 124 | if (p == 0) |
||
| 125 | { |
||
| 126 | fprintf (stderr, "Out of memory. Can't allocate %d bytes\n", nByte); |
||
| 127 | exit (1); |
||
| 128 | } |
||
| 129 | memset (p, 0, nByte); |
||
| 130 | return p; |
||
| 131 | } |
||
| 132 | void *SafeRealloc (void *old, int nByte) |
||
| 133 | { |
||
| 134 | void *p; |
||
| 135 | if (old == 0) |
||
| 136 | return SafeMalloc (nByte); |
||
| 137 | p = realloc (old, nByte); |
||
| 138 | if (p == 0) |
||
| 139 | { |
||
| 140 | fprintf (stderr, "Out of memory. Can't allocate %d bytes\n", nByte); |
||
| 141 | exit (1); |
||
| 142 | } |
||
| 143 | return p; |
||
| 144 | } |
||
| 145 | |||
| 146 | /* |
||
| 147 | ** The opposite of SafeMalloc(). Free memory previously obtained. |
||
| 148 | */ |
||
| 149 | void SafeFree (void *pMem) |
||
| 150 | { |
||
| 151 | if (pMem) |
||
| 152 | free (pMem); |
||
| 153 | } |
||
| 154 | |||
| 155 | /* |
||
| 156 | ** Return TRUE if the given character can be part of a C identifier. |
||
| 157 | */ |
||
| 158 | static int IsIdent (int c) |
||
| 159 | { |
||
| 160 | return isalnum (c) || c == '_'; |
||
| 161 | } |
||
| 162 | |||
| 163 | /* |
||
| 164 | ** Create an "#if" argument that captures the state of all nested |
||
| 165 | ** "#if" statements, ORed with "zExtra". Space to hold |
||
| 166 | ** the returned string is obtained from SafeMalloc and must be |
||
| 167 | ** freed by the calling function. |
||
| 168 | ** |
||
| 169 | ** If the conditional is always TRUE, then NULL is returned. |
||
| 170 | */ |
||
| 171 | static char *IfString (char *zExtra) |
||
| 172 | { |
||
| 173 | int len = 0; |
||
| 174 | IfStmt *p; |
||
| 175 | char *z; |
||
| 176 | int i; |
||
| 177 | int isStackTrue = 1; |
||
| 178 | int isStackFalse = 0; |
||
| 179 | int isExtraFalse = 0; |
||
| 180 | char *zSep; |
||
| 181 | IfStmt *altStack; |
||
| 182 | |||
| 183 | if (zExtra && *zExtra) |
||
| 184 | { |
||
| 185 | if (zExtra[1] == 0 && zExtra[0] == '0') |
||
| 186 | { |
||
| 187 | isExtraFalse = 1; |
||
| 188 | } |
||
| 189 | else if (zExtra[1] == 0 && zExtra[0] == '1') |
||
| 190 | { |
||
| 191 | return 0; |
||
| 192 | } |
||
| 193 | len = strlen (zExtra) + 10; |
||
| 194 | } |
||
| 195 | else |
||
| 196 | { |
||
| 197 | len = 1; |
||
| 198 | isExtraFalse = 1; |
||
| 199 | } |
||
| 200 | for (p = ifStack; p; p = p->pNext) |
||
| 201 | { |
||
| 202 | len += strlen (p->zArg) + 6; |
||
| 203 | if (p->zArg[0] == '0' && p->zArg[1] == 0) |
||
| 204 | { |
||
| 205 | if (!p->invert) |
||
| 206 | { |
||
| 207 | isStackFalse = 1; |
||
| 208 | isStackTrue = 0; |
||
| 209 | break; |
||
| 210 | } |
||
| 211 | } |
||
| 212 | else if (p->zArg[0] == '1' && p->zArg[1] == 0) |
||
| 213 | { |
||
| 214 | if (p->invert) |
||
| 215 | { |
||
| 216 | isStackFalse = 1; |
||
| 217 | isStackTrue = 0; |
||
| 218 | break; |
||
| 219 | } |
||
| 220 | } |
||
| 221 | else |
||
| 222 | { |
||
| 223 | isStackTrue = 0; |
||
| 224 | } |
||
| 225 | } |
||
| 226 | if (isStackTrue) |
||
| 227 | { |
||
| 228 | return 0; |
||
| 229 | } |
||
| 230 | else if (isStackFalse && isExtraFalse) |
||
| 231 | { |
||
| 232 | z = SafeMalloc (2); |
||
| 233 | strcpy (z, "0"); |
||
| 234 | return z; |
||
| 235 | } |
||
| 236 | z = SafeMalloc (len); |
||
| 237 | if (!isExtraFalse) |
||
| 238 | { |
||
| 239 | sprintf (z, "(%s) || (", zExtra); |
||
| 240 | i = strlen (z); |
||
| 241 | } |
||
| 242 | else |
||
| 243 | { |
||
| 244 | i = 0; |
||
| 245 | } |
||
| 246 | zSep = ""; |
||
| 247 | altStack = 0; |
||
| 248 | while (ifStack) |
||
| 249 | { |
||
| 250 | p = ifStack; |
||
| 251 | ifStack = p->pNext; |
||
| 252 | p->pNext = altStack; |
||
| 253 | altStack = p; |
||
| 254 | } |
||
| 255 | for (p = altStack; p; p = p->pNext) |
||
| 256 | { |
||
| 257 | if (p->zArg[0] == '0' && p->zArg[1] == 0 && p->invert) |
||
| 258 | continue; |
||
| 259 | if (p->zArg[0] == '1' && p->zArg[1] == 0 && !p->invert) |
||
| 260 | continue; |
||
| 261 | if (p->invert) |
||
| 262 | { |
||
| 263 | sprintf (&z[i], "%s!%s", zSep, p->zArg); |
||
| 264 | } |
||
| 265 | else |
||
| 266 | { |
||
| 267 | sprintf (&z[i], "%s%s", zSep, p->zArg); |
||
| 268 | } |
||
| 269 | i += strlen (&z[i]); |
||
| 270 | zSep = " && "; |
||
| 271 | } |
||
| 272 | while (altStack) |
||
| 273 | { |
||
| 274 | p = altStack; |
||
| 275 | altStack = p->pNext; |
||
| 276 | p->pNext = ifStack; |
||
| 277 | ifStack = p; |
||
| 278 | } |
||
| 279 | if (!isExtraFalse) |
||
| 280 | { |
||
| 281 | sprintf (&z[i], ")"); |
||
| 282 | } |
||
| 283 | return z; |
||
| 284 | } |
||
| 285 | |||
| 286 | /* |
||
| 287 | ** Push a new "#if" onto the if stack. |
||
| 288 | */ |
||
| 289 | static void PushIf (char *zArg, int line, int isNegated, int isDefined) |
||
| 290 | { |
||
| 291 | char *z; |
||
| 292 | IfStmt *p; |
||
| 293 | if (!isDefined) |
||
| 294 | { |
||
| 295 | int i; |
||
| 296 | z = SafeMalloc (strlen (zArg) + 3); |
||
| 297 | for (i = 0; zArg[i] && IsIdent (zArg[i]); i++) |
||
| 298 | { |
||
| 299 | } |
||
| 300 | if (zArg[i] == 0) |
||
| 301 | { |
||
| 302 | sprintf (z, "%s", zArg); |
||
| 303 | } |
||
| 304 | else |
||
| 305 | { |
||
| 306 | sprintf (z, "(%s)", zArg); |
||
| 307 | } |
||
| 308 | } |
||
| 309 | else |
||
| 310 | { |
||
| 311 | z = SafeMalloc (strlen (zArg) + 10); |
||
| 312 | sprintf (z, "defined(%s)", zArg); |
||
| 313 | } |
||
| 314 | p = SafeMalloc (sizeof (IfStmt)); |
||
| 315 | p->zArg = z; |
||
| 316 | p->line = line; |
||
| 317 | p->invert = isNegated; |
||
| 318 | p->pNext = ifStack; |
||
| 319 | ifStack = p; |
||
| 320 | } |
||
| 321 | |||
| 322 | /* |
||
| 323 | ** Extract the argument to an #if. Remove all leading and trailing |
||
| 324 | ** space. |
||
| 325 | */ |
||
| 326 | static char *GetArg (const char *fileName, char *z, int *pI, int *pLine) |
||
| 327 | { |
||
| 328 | int i = *pI; |
||
| 329 | int line = *pLine; |
||
| 330 | int start; |
||
| 331 | char *zResult; |
||
| 332 | int j, k; |
||
| 333 | |||
| 334 | while (isspace (z[i]) && z[i] != '\n') |
||
| 335 | { |
||
| 336 | i++; |
||
| 337 | } |
||
| 338 | start = i; |
||
| 339 | if (z[i] == '\n' || z[i] == 0) |
||
| 340 | { |
||
| 341 | fprintf ( |
||
| 342 | stderr, "%s: Missing argument to \"#if\" on line %d\n", fileName, *pLine); |
||
| 343 | nError++; |
||
| 344 | line++; |
||
| 345 | } |
||
| 346 | else |
||
| 347 | { |
||
| 348 | while (z[i] && z[i] != '\n') |
||
| 349 | { |
||
| 350 | if (z[i] == '\\' && z[i + 1] != 0) |
||
| 351 | { |
||
| 352 | i++; |
||
| 353 | } |
||
| 354 | if (z[i] == '\n') |
||
| 355 | { |
||
| 356 | line++; |
||
| 357 | } |
||
| 358 | i++; |
||
| 359 | } |
||
| 360 | } |
||
| 361 | zResult = SafeMalloc (i + 1 - start); |
||
| 362 | for (j = 0, k = start; k < i; k++) |
||
| 363 | { |
||
| 364 | if (isspace (z[k]) && j > 0 && isspace (zResult[j - 1])) |
||
| 365 | { |
||
| 366 | /* Do nothing */ |
||
| 367 | } |
||
| 368 | else if (z[k] == '\\' && z[k + 1] == '\n') |
||
| 369 | { |
||
| 370 | if (j > 0 && !isspace (zResult[j - 1])) |
||
| 371 | { |
||
| 372 | zResult[j++] = ' '; |
||
| 373 | } |
||
| 374 | k++; |
||
| 375 | } |
||
| 376 | else if (z[k] == '\\') |
||
| 377 | { |
||
| 378 | zResult[j++] = z[k++]; |
||
| 379 | } |
||
| 380 | zResult[j++] = z[k]; |
||
| 381 | } |
||
| 382 | zResult[j] = 0; |
||
| 383 | while (j > 0 && isspace (zResult[j - 1])) |
||
| 384 | { |
||
| 385 | j--; |
||
| 386 | zResult[j] = 0; |
||
| 387 | } |
||
| 388 | *pI = i; |
||
| 389 | *pLine = line; |
||
| 390 | return zResult; |
||
| 391 | } |
||
| 392 | |||
| 393 | /* |
||
| 394 | ** Read the complete text of a file into memory. Return 0 if there |
||
| 395 | ** is any kind of error. |
||
| 396 | */ |
||
| 397 | char *ReadFileIntoMemory (const char *fileName, int *pLength) |
||
| 398 | { |
||
| 399 | FILE *in; /* Input file stream */ |
||
| 400 | char *textBuf; /* A buffer in which to put entire text of input */ |
||
| 401 | int toRead; /* Amount of input file read to read */ |
||
| 402 | int got; /* Amount read so far */ |
||
| 403 | struct stat statBuf; /* Status buffer for the file */ |
||
| 404 | |||
| 405 | if (stat (fileName, &statBuf) != 0) |
||
| 406 | { |
||
| 407 | fprintf (stderr, "%s: no such file: %s\n", Argv0, fileName); |
||
| 408 | return 0; |
||
| 409 | } |
||
| 410 | textBuf = SafeMalloc (statBuf.st_size + 1); |
||
| 411 | in = fopen (fileName, "rb"); |
||
| 412 | if (in == 0) |
||
| 413 | { |
||
| 414 | fprintf (stderr, "%s: can't open for reading: %s\n", Argv0, fileName); |
||
| 415 | SafeFree (textBuf); |
||
| 416 | return 0; |
||
| 417 | } |
||
| 418 | textBuf[statBuf.st_size] = 0; |
||
| 419 | toRead = statBuf.st_size; |
||
| 420 | got = 0; |
||
| 421 | while (toRead) |
||
| 422 | { |
||
| 423 | int n = fread (&textBuf[got], 1, toRead, in); |
||
| 424 | if (n <= 0) |
||
| 425 | break; |
||
| 426 | toRead -= n; |
||
| 427 | got += n; |
||
| 428 | } |
||
| 429 | fclose (in); |
||
| 430 | textBuf[got] = 0; |
||
| 431 | if (pLength) |
||
| 432 | *pLength = got; |
||
| 433 | return textBuf; |
||
| 434 | } |
||
| 435 | |||
| 436 | /* |
||
| 437 | ** Given the "aaaa" part of the name of an ET_COMMAND_aaaa function, |
||
| 438 | ** compute the name of the corresponding Tcl command. |
||
| 439 | ** |
||
| 440 | ** The name is usually the same, except if there are two underscores |
||
| 441 | ** in the middle of the command, they are changed to colons. This |
||
| 442 | ** feature allows namespaces to be used. Example: The function |
||
| 443 | ** named |
||
| 444 | ** |
||
| 445 | ** ET_COMMAND_space1__proc1(ET_TCLARGS){...} |
||
| 446 | ** |
||
| 447 | ** will generate a TCL command called |
||
| 448 | ** |
||
| 449 | ** space1::proc1 |
||
| 450 | ** |
||
| 451 | ** Space to hold the TCL command name is obtained from malloc(). |
||
| 452 | */ |
||
| 453 | static char *FuncToProc (char *zFunc) |
||
| 454 | { |
||
| 455 | char *zProc; |
||
| 456 | int i; |
||
| 457 | |||
| 458 | zProc = SafeMalloc (strlen (zFunc) + 1); |
||
| 459 | strcpy (zProc, zFunc); |
||
| 460 | for (i = 0; zProc[i]; i++) |
||
| 461 | { |
||
| 462 | if (i > 0 && zProc[i] == '_' && zProc[i + 1] == '_' && |
||
| 463 | isalnum (zProc[i - 1]) && isalnum (zProc[i + 2])) |
||
| 464 | { |
||
| 465 | zProc[i] = ':'; |
||
| 466 | zProc[i + 1] = ':'; |
||
| 467 | } |
||
| 468 | } |
||
| 469 | return zProc; |
||
| 470 | } |
||
| 471 | |||
| 472 | /* |
||
| 473 | ** Scan a source file looking for new TCL commands and/or the Et_AppInit() |
||
| 474 | ** or Et_PreInit() functions. |
||
| 475 | ** |
||
| 476 | ** Skip all comments, and any text contained within "#if 0".."#endif" |
||
| 477 | */ |
||
| 478 | void ScanFile (const char *fileName) |
||
| 479 | { |
||
| 480 | char *z; /* Complete text of the file, NULL terminated. */ |
||
| 481 | int i, j; |
||
| 482 | int inBrace = 0; |
||
| 483 | int line = 1; |
||
| 484 | |||
| 485 | z = ReadFileIntoMemory (fileName, 0); |
||
| 486 | if (z == 0) |
||
| 487 | { |
||
| 488 | nError++; |
||
| 489 | return; |
||
| 490 | } |
||
| 491 | for (i = 0; z[i]; i++) |
||
| 492 | { |
||
| 493 | switch (z[i]) |
||
| 494 | { |
||
| 495 | case '\n': |
||
| 496 | line++; |
||
| 497 | break; |
||
| 498 | case '/': |
||
| 499 | /* This might be a comment. If it is, skip it. */ |
||
| 500 | if (z[i + 1] == '*') |
||
| 501 | { |
||
| 502 | int start = line; |
||
| 503 | i += 2; |
||
| 504 | while (z[i] && (z[i] != '*' || z[i + 1] != '/')) |
||
| 505 | { |
||
| 506 | if (z[i] == '\n') |
||
| 507 | line++; |
||
| 508 | i++; |
||
| 509 | } |
||
| 510 | if (z[i] == 0) |
||
| 511 | { |
||
| 512 | fprintf ( |
||
| 513 | stderr, |
||
| 514 | "%s: Unterminated comment beginning on line %d\n", |
||
| 515 | fileName, |
||
| 516 | start); |
||
| 517 | nError++; |
||
| 518 | } |
||
| 519 | else |
||
| 520 | { |
||
| 521 | i++; |
||
| 522 | } |
||
| 523 | } |
||
| 524 | else if (z[i + 1] == '/') |
||
| 525 | { |
||
| 526 | while (z[i] && z[i] != '\n') |
||
| 527 | { |
||
| 528 | i++; |
||
| 529 | } |
||
| 530 | if (z[i]) |
||
| 531 | { |
||
| 532 | line++; |
||
| 533 | }; |
||
| 534 | } |
||
| 535 | break; |
||
| 536 | case '\'': |
||
| 537 | { |
||
| 538 | /* Skip character literals */ |
||
| 539 | int start = line; |
||
| 540 | for (i++; z[i] && z[i] != '\''; i++) |
||
| 541 | { |
||
| 542 | if (z[i] == '\n') |
||
| 543 | { |
||
| 544 | fprintf ( |
||
| 545 | stderr, |
||
| 546 | "%s: Newline in character literal on line %d\n", |
||
| 547 | fileName, |
||
| 548 | start); |
||
| 549 | line++; |
||
| 550 | } |
||
| 551 | if (z[i] == '\\') |
||
| 552 | i++; |
||
| 553 | } |
||
| 554 | if (z[i] == 0) |
||
| 555 | { |
||
| 556 | fprintf ( |
||
| 557 | stderr, |
||
| 558 | "%s: unterminate character literal on line %d\n", |
||
| 559 | fileName, |
||
| 560 | start); |
||
| 561 | nError++; |
||
| 562 | } |
||
| 563 | break; |
||
| 564 | } |
||
| 565 | case '"': |
||
| 566 | { |
||
| 567 | /* Skip over a string */ |
||
| 568 | int start = line; |
||
| 569 | for (i++; z[i] && z[i] != '"'; i++) |
||
| 570 | { |
||
| 571 | if (z[i] == '\n') |
||
| 572 | { |
||
| 573 | fprintf ( |
||
| 574 | stderr, |
||
| 575 | "%s: Newline in string literal on line %d\n", |
||
| 576 | fileName, |
||
| 577 | start); |
||
| 578 | line++; |
||
| 579 | } |
||
| 580 | if (z[i] == '\\') |
||
| 581 | i++; |
||
| 582 | } |
||
| 583 | if (z[i] == 0) |
||
| 584 | { |
||
| 585 | fprintf ( |
||
| 586 | stderr, |
||
| 587 | "%s: unterminate string literal on line %d\n", |
||
| 588 | fileName, |
||
| 589 | start); |
||
| 590 | nError++; |
||
| 591 | } |
||
| 592 | break; |
||
| 593 | } |
||
| 594 | case '#': |
||
| 595 | /* This might be a preprocessor macro such as #if 0 or #endif */ |
||
| 596 | if (i > 0 && z[i - 1] != '\n') |
||
| 597 | break; |
||
| 598 | for (j = i + 1; isspace (z[j]); j++) |
||
| 599 | { |
||
| 600 | } |
||
| 601 | if (strncmp (&z[j], "endif", 5) == 0) |
||
| 602 | { |
||
| 603 | if (ifStack == 0) |
||
| 604 | { |
||
| 605 | fprintf ( |
||
| 606 | stderr, |
||
| 607 | "%s: Unmatched \"#endif\" on line %d\n", |
||
| 608 | fileName, |
||
| 609 | line); |
||
| 610 | nError++; |
||
| 611 | } |
||
| 612 | else |
||
| 613 | { |
||
| 614 | IfStmt *p = ifStack; |
||
| 615 | ifStack = p->pNext; |
||
| 616 | SafeFree (p->zArg); |
||
| 617 | SafeFree (p); |
||
| 618 | } |
||
| 619 | break; |
||
| 620 | } |
||
| 621 | if (strncmp (&z[j], "else", 4) == 0) |
||
| 622 | { |
||
| 623 | if (ifStack == 0) |
||
| 624 | { |
||
| 625 | fprintf ( |
||
| 626 | stderr, |
||
| 627 | "%s: No \"#if\" to pair with \"#else\" on line " |
||
| 628 | "%d\n", |
||
| 629 | fileName, |
||
| 630 | line); |
||
| 631 | nError++; |
||
| 632 | } |
||
| 633 | else |
||
| 634 | { |
||
| 635 | ifStack->invert = !ifStack->invert; |
||
| 636 | } |
||
| 637 | break; |
||
| 638 | } |
||
| 639 | if (z[j] != 'i' || z[j + 1] != 'f') |
||
| 640 | break; |
||
| 641 | if (strncmp (&z[j + 2], "ndef", 4) == 0) |
||
| 642 | { |
||
| 643 | char *zArg; |
||
| 644 | int start = line; |
||
| 645 | i = j + 6; |
||
| 646 | zArg = GetArg (fileName, z, &i, &line); |
||
| 647 | PushIf (zArg, start, 1, 1); |
||
| 648 | SafeFree (zArg); |
||
| 649 | } |
||
| 650 | else if (strncmp (&z[j + 2], "def", 3) == 0) |
||
| 651 | { |
||
| 652 | char *zArg; |
||
| 653 | int start = line; |
||
| 654 | i = j + 5; |
||
| 655 | zArg = GetArg (fileName, z, &i, &line); |
||
| 656 | PushIf (zArg, start, 0, 1); |
||
| 657 | SafeFree (zArg); |
||
| 658 | } |
||
| 659 | else |
||
| 660 | { |
||
| 661 | char *zArg; |
||
| 662 | int start = line; |
||
| 663 | i = j + 2; |
||
| 664 | zArg = GetArg (fileName, z, &i, &line); |
||
| 665 | PushIf (zArg, start, 0, 0); |
||
| 666 | SafeFree (zArg); |
||
| 667 | } |
||
| 668 | break; |
||
| 669 | case '{': |
||
| 670 | inBrace++; |
||
| 671 | break; |
||
| 672 | case '}': |
||
| 673 | inBrace--; |
||
| 674 | break; |
||
| 675 | case 'm': |
||
| 676 | /* Check main() */ |
||
| 677 | if (inBrace > 0) |
||
| 678 | break; |
||
| 679 | if (i > 0 && IsIdent (z[i - 1])) |
||
| 680 | break; |
||
| 681 | if (strncmp (&z[i], "main", 4) == 0 && !IsIdent (z[i + 4])) |
||
| 682 | { |
||
| 683 | seenMain = IfString (seenMain); |
||
| 684 | } |
||
| 685 | case 'E': |
||
| 686 | /* Check ET_COMMAND_... or Et_AppInit or Et_PreInit */ |
||
| 687 | if (inBrace > 0) |
||
| 688 | break; |
||
| 689 | if (i > 0 && IsIdent (z[i - 1])) |
||
| 690 | break; |
||
| 691 | if (z[i + 1] == 'T' && strncmp (&z[i], "ET_COMMAND_", 11) == 0) |
||
| 692 | { |
||
| 693 | EtCmd *p; |
||
| 694 | for (j = i + 11; IsIdent (z[j]); j++) |
||
| 695 | { |
||
| 696 | } |
||
| 697 | p = SafeMalloc (sizeof (EtCmd)); |
||
| 698 | p->zIf = IfString (0); |
||
| 699 | p->zName = SafeMalloc (j - (i + 9)); |
||
| 700 | sprintf (p->zName, "%.*s", j - (i + 11), &z[i + 11]); |
||
| 701 | p->pNext = cmdList; |
||
| 702 | cmdList = p; |
||
| 703 | nCmd++; |
||
| 704 | } |
||
| 705 | else if (z[i + 1] == 'T' && strncmp (&z[i], "ET_OBJCOMMAND_", 14) == 0) |
||
| 706 | { |
||
| 707 | EtCmd *p; |
||
| 708 | for (j = i + 14; IsIdent (z[j]); j++) |
||
| 709 | { |
||
| 710 | } |
||
| 711 | p = SafeMalloc (sizeof (EtCmd)); |
||
| 712 | p->zIf = IfString (0); |
||
| 713 | p->zName = SafeMalloc (j - (i + 9)); |
||
| 714 | p->isObj = 1; |
||
| 715 | sprintf (p->zName, "%.*s", j - (i + 14), &z[i + 14]); |
||
| 716 | p->pNext = cmdList; |
||
| 717 | cmdList = p; |
||
| 718 | nObjCmd++; |
||
| 719 | } |
||
| 720 | else if (z[i + 1] == 't') |
||
| 721 | { |
||
| 722 | if (strncmp (&z[i], "Et_AppInit", 10) == 0 && |
||
| 723 | !IsIdent (z[i + 10])) |
||
| 724 | { |
||
| 725 | seenEtAppInit = IfString (seenEtAppInit); |
||
| 726 | } |
||
| 727 | if (strncmp (&z[i], "Et_PreInit", 10) == 0 && |
||
| 728 | !IsIdent (z[i + 10])) |
||
| 729 | { |
||
| 730 | seenEtPreInit = IfString (seenEtPreInit); |
||
| 731 | } |
||
| 732 | if (strncmp (&z[i], "Et_CustomMainLoop", 17) == 0 && |
||
| 733 | !IsIdent (z[i + 17])) |
||
| 734 | { |
||
| 735 | seenEtCustomMainLoop = IfString (seenEtCustomMainLoop); |
||
| 736 | } |
||
| 737 | } |
||
| 738 | break; |
||
| 739 | default: |
||
| 740 | /* Do nothing. Continue to the next character */ |
||
| 741 | break; |
||
| 742 | } |
||
| 743 | } |
||
| 744 | SafeFree (z); |
||
| 745 | while (ifStack) |
||
| 746 | { |
||
| 747 | IfStmt *p = ifStack; |
||
| 748 | fprintf (stderr, "%s: unterminated \"#if\" on line %d\n", fileName, p->line); |
||
| 749 | nError++; |
||
| 750 | ifStack = p->pNext; |
||
| 751 | SafeFree (p->zArg); |
||
| 752 | SafeFree (p); |
||
| 753 | } |
||
| 754 | } |
||
| 755 | |||
| 756 | /* |
||
| 757 | ** Set a macro according to the value of an #if argument. |
||
| 758 | */ |
||
| 759 | static void SetMacro (char *zMacroName, char *zIf) |
||
| 760 | { |
||
| 761 | if (zIf == 0 || *zIf == 0) |
||
| 762 | { |
||
| 763 | printf ("#define %s 1\n", zMacroName); |
||
| 764 | } |
||
| 765 | else if (zIf[0] == '0' && zIf[1] == 0) |
||
| 766 | { |
||
| 767 | printf ("#define %s 0\n", zMacroName); |
||
| 768 | } |
||
| 769 | else |
||
| 770 | { |
||
| 771 | printf ( |
||
| 772 | "#if %s\n" |
||
| 773 | "# define %s 1\n" |
||
| 774 | "#else\n" |
||
| 775 | "# define %s 0\n" |
||
| 776 | "#endif\n", |
||
| 777 | zIf, |
||
| 778 | zMacroName, |
||
| 779 | zMacroName); |
||
| 780 | } |
||
| 781 | } |
||
| 782 | |||
| 783 | /* Forward declaration...*/ |
||
| 784 | static void WriteAsString (char *, int); |
||
| 785 | |||
| 786 | /* |
||
| 787 | ** Set a string macro to the value given, if that value is not NULL. |
||
| 788 | */ |
||
| 789 | static void SetStringMacro (char *zMacroName, char *z) |
||
| 790 | { |
||
| 791 | if (z == 0 || *z == 0) |
||
| 792 | return; |
||
| 793 | printf ("#define %s ", zMacroName); |
||
| 794 | WriteAsString (z, 0); |
||
| 795 | } |
||
| 796 | |||
| 797 | /* |
||
| 798 | ** Look at the name of the file given and see if it is a Tcl file |
||
| 799 | ** or a C or C++ source file. Return TRUE for TCL and FALSE for |
||
| 800 | ** C or C++. |
||
| 801 | */ |
||
| 802 | static int IsTclFile (char *zFile) |
||
| 803 | { |
||
| 804 | static char *azCSuffix[] = {".c", ".cc", ".C", ".cpp", ".CPP", ".cxx", ".CXX"}; |
||
| 805 | int len = strlen (zFile); |
||
| 806 | int i; |
||
| 807 | for (i = 0; i < sizeof (azCSuffix) / sizeof (azCSuffix[0]); i++) |
||
| 808 | { |
||
| 809 | int len2 = strlen (azCSuffix[i]); |
||
| 810 | if (len > len2 && strcmp (&zFile[len - len2], azCSuffix[i]) == 0) |
||
| 811 | { |
||
| 812 | return 0; |
||
| 813 | } |
||
| 814 | } |
||
| 815 | return 1; |
||
| 816 | } |
||
| 817 | |||
| 818 | /* |
||
| 819 | ** Compress a TCL script by removing comments and excess white-space |
||
| 820 | */ |
||
| 821 | static void CompressTcl (char *z) |
||
| 822 | { |
||
| 823 | int i, j, c; |
||
| 824 | int atLineStart = 1; |
||
| 825 | for (i = j = 0; (c = z[i]) != 0; i++) |
||
| 826 | { |
||
| 827 | switch (c) |
||
| 828 | { |
||
| 829 | case ' ': |
||
| 830 | case '\t': |
||
| 831 | case '\r': |
||
| 832 | if (atLineStart) |
||
| 833 | { |
||
| 834 | c = 0; |
||
| 835 | } |
||
| 836 | break; |
||
| 837 | case '#': |
||
| 838 | if (atLineStart && !isalpha (z[i + 1]) && |
||
| 839 | strncmp (z, "# @(#)", 6) != 0) |
||
| 840 | { |
||
| 841 | while (z[i] && z[i] != '\n') |
||
| 842 | { |
||
| 843 | if (z[i] == '\\') |
||
| 844 | { |
||
| 845 | i++; |
||
| 846 | if (z[i] == '\r' && z[i + 1] == '\n') |
||
| 847 | { |
||
| 848 | i++; |
||
| 849 | } |
||
| 850 | } |
||
| 851 | i++; |
||
| 852 | } |
||
| 853 | c = 0; |
||
| 854 | if (z[i] == 0) |
||
| 855 | { |
||
| 856 | i--; |
||
| 857 | } |
||
| 858 | } |
||
| 859 | else |
||
| 860 | { |
||
| 861 | atLineStart = 0; |
||
| 862 | } |
||
| 863 | break; |
||
| 864 | case '\n': |
||
| 865 | if (atLineStart) |
||
| 866 | { |
||
| 867 | c = 0; |
||
| 868 | } |
||
| 869 | else if ( |
||
| 870 | (i > 0 && z[i - 1] == '\\') || |
||
| 871 | (i > 1 && z[i - 1] == '\r' && z[i - 2] == '\\')) |
||
| 872 | { |
||
| 873 | /* The line continues. Do not compress. |
||
| 874 | ** Compressing here breaks BWidgets... */ |
||
| 875 | } |
||
| 876 | else |
||
| 877 | { |
||
| 878 | atLineStart = 1; |
||
| 879 | } |
||
| 880 | break; |
||
| 881 | default: |
||
| 882 | atLineStart = 0; |
||
| 883 | break; |
||
| 884 | } |
||
| 885 | if (c != 0) |
||
| 886 | { |
||
| 887 | z[j++] = c; |
||
| 888 | } |
||
| 889 | } |
||
| 890 | z[j] = 0; |
||
| 891 | } |
||
| 892 | |||
| 893 | /* |
||
| 894 | ** Write the text of the given file as a string. Tcl-style comments |
||
| 895 | ** are removed if the doCompress flag is true. |
||
| 896 | */ |
||
| 897 | static void WriteAsString (char *z, int shroud) |
||
| 898 | { |
||
| 899 | int c; |
||
| 900 | int priorc = 0; |
||
| 901 | int xor ; |
||
| 902 | int atLineStart = 1; |
||
| 903 | if (shroud > 0) |
||
| 904 | { |
||
| 905 | xor = shroud; |
||
| 906 | } |
||
| 907 | putchar ('"'); |
||
| 908 | atLineStart = 0; |
||
| 909 | while ((c = *z) != 0) |
||
| 910 | { |
||
| 911 | z++; |
||
| 912 | if (c == '\r' && *z == '\n') |
||
| 913 | continue; |
||
| 914 | if (shroud > 0 && c >= 0x20) |
||
| 915 | { |
||
| 916 | c ^= xor; |
||
| 917 | xor = (xor+1) & 0x1f; |
||
| 918 | } |
||
| 919 | if (atLineStart) |
||
| 920 | { |
||
| 921 | putchar ('"'); |
||
| 922 | atLineStart = 0; |
||
| 923 | } |
||
| 924 | switch (c) |
||
| 925 | { |
||
| 926 | case '?': |
||
| 927 | /* Prevent two "?" characters in a row, as this causes problems |
||
| 928 | ** for compilers that interpret trigraphs */ |
||
| 929 | if (c == priorc) |
||
| 930 | { |
||
| 931 | putchar ('\\'); |
||
| 932 | putchar (((c >> 6) & 3) + '0'); |
||
| 933 | putchar (((c >> 3) & 7) + '0'); |
||
| 934 | putchar ((c & 7) + '0'); |
||
| 935 | c = 0; |
||
| 936 | } |
||
| 937 | else |
||
| 938 | { |
||
| 939 | putchar (c); |
||
| 940 | } |
||
| 941 | break; |
||
| 942 | case '"': |
||
| 943 | case '\\': |
||
| 944 | putchar ('\\'); |
||
| 945 | putchar (c); |
||
| 946 | break; |
||
| 947 | case '\n': |
||
| 948 | putchar ('\\'); |
||
| 949 | putchar ('n'); |
||
| 950 | putchar ('"'); |
||
| 951 | putchar ('\n'); |
||
| 952 | atLineStart = 1; |
||
| 953 | break; |
||
| 954 | default: |
||
| 955 | if (c < ' ' || c > '~') |
||
| 956 | { |
||
| 957 | putchar ('\\'); |
||
| 958 | putchar (((c >> 6) & 3) + '0'); |
||
| 959 | putchar (((c >> 3) & 7) + '0'); |
||
| 960 | putchar ((c & 7) + '0'); |
||
| 961 | } |
||
| 962 | else |
||
| 963 | { |
||
| 964 | putchar (c); |
||
| 965 | } |
||
| 966 | break; |
||
| 967 | } |
||
| 968 | priorc = c; |
||
| 969 | } |
||
| 970 | if (!atLineStart) |
||
| 971 | { |
||
| 972 | putchar ('"'); |
||
| 973 | putchar ('\n'); |
||
| 974 | } |
||
| 975 | } |
||
| 976 | |||
| 977 | /* |
||
| 978 | ** The header string. |
||
| 979 | */ |
||
| 980 | static char zHeader[] = "/* Automatically generated code */\n" |
||
| 981 | "/* DO NOT EDIT */\n" |
||
| 982 | "#ifndef ET_TCLARGS\n" |
||
| 983 | "#include <tcl.h>\n" |
||
| 984 | "#ifdef __cplusplus\n" |
||
| 985 | "# define ET_EXTERN extern \"C\"\n" |
||
| 986 | "#else\n" |
||
| 987 | "# define ET_EXTERN extern\n" |
||
| 988 | "#endif\n" |
||
| 989 | "ET_EXTERN char *mprintf(const char*,...);\n" |
||
| 990 | "ET_EXTERN char *vmprintf(const char*,...);\n" |
||
| 991 | "ET_EXTERN int Et_EvalF(Tcl_Interp*,const char *,...);\n" |
||
| 992 | "ET_EXTERN int Et_GlobalEvalF(Tcl_Interp*,const char *,...);\n" |
||
| 993 | "ET_EXTERN int Et_DStringAppendF(Tcl_DString*,const char*,...);\n" |
||
| 994 | "ET_EXTERN int Et_ResultF(Tcl_Interp*,const char*,...);\n" |
||
| 995 | "ET_EXTERN int Et_Init(int,char**);\n" |
||
| 996 | "ET_EXTERN Tcl_Interp *Et_Interp;\n" |
||
| 997 | "#if TCL_RELEASE_VERSION>=8\n" |
||
| 998 | "ET_EXTERN int Et_AppendObjF(Tcl_Obj*,const char*,...);\n" |
||
| 999 | "#endif\n" |
||
| 1000 | "#define ET_TCLARGS " |
||
| 1001 | "ClientData clientData,Tcl_Interp*interp,int argc,char**argv\n" |
||
| 1002 | "#define ET_OBJARGS " |
||
| 1003 | "ClientData clientData,Tcl_Interp*interp,int objc,Tcl_Obj *CONST " |
||
| 1004 | "objv[]\n" |
||
| 1005 | "#endif\n"; |
||
| 1006 | |||
| 1007 | /* |
||
| 1008 | ** Print a usage comment and die |
||
| 1009 | */ |
||
| 1010 | static void Usage (char *argv0) |
||
| 1011 | { |
||
| 1012 | fprintf (stderr, "Usage: %s arguments...\n", argv0); |
||
| 1013 | fprintf ( |
||
| 1014 | stderr, |
||
| 1015 | " -version print the version number of mktclapp and exit\n" |
||
| 1016 | " -header print a header file and exit\n" |
||
| 1017 | " -srcdir DIR Prepend DIR to all relative pathnames\n" |
||
| 1018 | " -notk built a Tcl-only program. No GUI\n" |
||
| 1019 | " -extension NAME build a Tcl/Tk extension with the given name\n" |
||
| 1020 | " -autofork automatically fork the program into the background\n" |
||
| 1021 | " -strip-tcl remove comments and extra white-space from\n" |
||
| 1022 | " subsequent TCL files\n" |
||
| 1023 | " -dont-strip-tcl stop stripping TCL files\n" |
||
| 1024 | " -tcl-library DIR directory holding the TCL script library\n" |
||
| 1025 | " -tk-library DIR directory holding the TK script library\n" |
||
| 1026 | " -main-script FILE run the script FILE after initialization\n" |
||
| 1027 | " -read-stdin read standard input\n" |
||
| 1028 | " -console create a console window\n" |
||
| 1029 | " -shroud hide compile-in TCL from view\n" |
||
| 1030 | " -enable-obj use TCL Obj commands where possible\n" |
||
| 1031 | " -standalone make the \"source\" TCL command only work\n" |
||
| 1032 | " for builtin scripts\n" |
||
| 1033 | " -f FILE read more command-line parameters from FILE\n" |
||
| 1034 | " -i FILE make the binary file FILE part of the C code\n" |
||
| 1035 | " *.c scan this file for new TCL commands\n" |
||
| 1036 | " *.tcl compile this file into the generated C code\n"); |
||
| 1037 | exit (1); |
||
| 1038 | } |
||
| 1039 | |||
| 1040 | /* |
||
| 1041 | ** Read one or more characters form "in" that follow a \ and |
||
| 1042 | ** interpret them appropriately. Return the character that |
||
| 1043 | ** results from this interpretation. |
||
| 1044 | */ |
||
| 1045 | static int EscapeChar (FILE *in) |
||
| 1046 | { |
||
| 1047 | int c, d; |
||
| 1048 | c = getc (in); |
||
| 1049 | switch (c) |
||
| 1050 | { |
||
| 1051 | case 'n': |
||
| 1052 | c = '\n'; |
||
| 1053 | break; |
||
| 1054 | case 'r': |
||
| 1055 | c = '\r'; |
||
| 1056 | break; |
||
| 1057 | case 'f': |
||
| 1058 | c = '\f'; |
||
| 1059 | break; |
||
| 1060 | case 't': |
||
| 1061 | c = '\t'; |
||
| 1062 | break; |
||
| 1063 | case 'b': |
||
| 1064 | c = '\b'; |
||
| 1065 | break; |
||
| 1066 | case 'a': |
||
| 1067 | c = '\a'; |
||
| 1068 | break; |
||
| 1069 | case '0': |
||
| 1070 | case '1': |
||
| 1071 | case '2': |
||
| 1072 | case '3': |
||
| 1073 | case '4': |
||
| 1074 | case '5': |
||
| 1075 | case '6': |
||
| 1076 | case '7': |
||
| 1077 | c -= '0'; |
||
| 1078 | d = getc (in); |
||
| 1079 | if (d < '0' || d > '7') |
||
| 1080 | { |
||
| 1081 | ungetc (d, in); |
||
| 1082 | break; |
||
| 1083 | } |
||
| 1084 | c = (c << 3) + (d - '0'); |
||
| 1085 | if (d < '0' || d > '7') |
||
| 1086 | { |
||
| 1087 | ungetc (d, in); |
||
| 1088 | break; |
||
| 1089 | } |
||
| 1090 | c = (c << 3) + (d - '0'); |
||
| 1091 | break; |
||
| 1092 | default: |
||
| 1093 | break; |
||
| 1094 | } |
||
| 1095 | return c; |
||
| 1096 | } |
||
| 1097 | |||
| 1098 | /* MS-Windows and MS-DOS both have the following serious OS bug: the |
||
| 1099 | ** length of a command line is severely restricted. But this program |
||
| 1100 | ** occasionally requires long command lines. Hence the following |
||
| 1101 | ** work around. |
||
| 1102 | ** |
||
| 1103 | ** If the parameters "-f FILENAME" appear anywhere on the command line, |
||
| 1104 | ** then the named file is scanned for additional command line arguments. |
||
| 1105 | ** These arguments are substituted in place of the "FILENAME" argument |
||
| 1106 | ** in the original argument list. |
||
| 1107 | ** |
||
| 1108 | ** This first parameter to this routine is the index of the "-f" |
||
| 1109 | ** parameter in the argv[] array. The argc and argv are passed by |
||
| 1110 | ** pointer so that they can be changed. |
||
| 1111 | ** |
||
| 1112 | ** Parsing of the parameters in the file is very simple. Parameters |
||
| 1113 | ** can be separated by any amount of white-space (including newlines |
||
| 1114 | ** and carriage returns.) " and ' can be used for quoting strings |
||
| 1115 | ** with embedded spaces. The \ character escapes the following character. |
||
| 1116 | ** The length of a token is limited to about 1000 characters. |
||
| 1117 | */ |
||
| 1118 | static void AddParameters (int index, int *pArgc, char ***pArgv) |
||
| 1119 | { |
||
| 1120 | int argc = *pArgc; /* The original argc value */ |
||
| 1121 | char **argv = *pArgv; /* The original argv value */ |
||
| 1122 | int newArgc; /* Value for argc after inserting new arguments */ |
||
| 1123 | char **zNew; /* The new argv after this routine is done */ |
||
| 1124 | char *zFile; /* Name of the input file */ |
||
| 1125 | int nNew = 0; /* Number of new entries in the argv[] file */ |
||
| 1126 | int nAlloc = 0; /* Space allocated for zNew[] */ |
||
| 1127 | int i; /* Loop counter */ |
||
| 1128 | int n; /* Number of characters in a new argument */ |
||
| 1129 | int c; /* Next character of input */ |
||
| 1130 | int startOfLine = 1; /* True if we are where '#' can start a comment */ |
||
| 1131 | FILE *in; /* The input file */ |
||
| 1132 | char zBuf[1000]; /* A single argument is accumulated here */ |
||
| 1133 | |||
| 1134 | if (index + 1 == argc) |
||
| 1135 | return; |
||
| 1136 | zFile = argv[index + 1]; |
||
| 1137 | in = fopen (zFile, "r"); |
||
| 1138 | if (in == 0) |
||
| 1139 | { |
||
| 1140 | fprintf (stderr, "Can't open input file \"%s\"\n", zFile); |
||
| 1141 | exit (1); |
||
| 1142 | } |
||
| 1143 | c = ' '; |
||
| 1144 | while (c != EOF) |
||
| 1145 | { |
||
| 1146 | while (c != EOF && isspace (c)) |
||
| 1147 | { |
||
| 1148 | if (c == '\n') |
||
| 1149 | { |
||
| 1150 | startOfLine = 1; |
||
| 1151 | } |
||
| 1152 | c = getc (in); |
||
| 1153 | if (startOfLine && c == '#') |
||
| 1154 | { |
||
| 1155 | while (c != EOF && c != '\n') |
||
| 1156 | { |
||
| 1157 | c = getc (in); |
||
| 1158 | } |
||
| 1159 | } |
||
| 1160 | } |
||
| 1161 | n = 0; |
||
| 1162 | if (c == '\'' || c == '"') |
||
| 1163 | { |
||
| 1164 | int quote = c; |
||
| 1165 | c = getc (in); |
||
| 1166 | startOfLine = 0; |
||
| 1167 | while (c != EOF && c != quote) |
||
| 1168 | { |
||
| 1169 | if (c == '\\') |
||
| 1170 | c = EscapeChar (in); |
||
| 1171 | if (n < sizeof (zBuf) - 1) |
||
| 1172 | { |
||
| 1173 | zBuf[n++] = c; |
||
| 1174 | } |
||
| 1175 | c = getc (in); |
||
| 1176 | } |
||
| 1177 | if (c != EOF) |
||
| 1178 | c = getc (in); |
||
| 1179 | } |
||
| 1180 | else |
||
| 1181 | { |
||
| 1182 | while (c != EOF && !isspace (c)) |
||
| 1183 | { |
||
| 1184 | if (c == '\\') |
||
| 1185 | c = EscapeChar (in); |
||
| 1186 | if (n < sizeof (zBuf) - 1) |
||
| 1187 | { |
||
| 1188 | zBuf[n++] = c; |
||
| 1189 | } |
||
| 1190 | startOfLine = 0; |
||
| 1191 | c = getc (in); |
||
| 1192 | } |
||
| 1193 | } |
||
| 1194 | zBuf[n] = 0; |
||
| 1195 | if (n > 0) |
||
| 1196 | { |
||
| 1197 | nNew++; |
||
| 1198 | if (nNew + argc >= nAlloc) |
||
| 1199 | { |
||
| 1200 | if (nAlloc == 0) |
||
| 1201 | { |
||
| 1202 | nAlloc = 100 + argc; |
||
| 1203 | zNew = malloc (sizeof (char *) * nAlloc); |
||
| 1204 | } |
||
| 1205 | else |
||
| 1206 | { |
||
| 1207 | nAlloc *= 2; |
||
| 1208 | zNew = realloc (zNew, sizeof (char *) * nAlloc); |
||
| 1209 | } |
||
| 1210 | } |
||
| 1211 | if (zNew) |
||
| 1212 | { |
||
| 1213 | int j = nNew + index; |
||
| 1214 | zNew[j] = malloc (n + 1); |
||
| 1215 | if (zNew[j]) |
||
| 1216 | { |
||
| 1217 | strcpy (zNew[j], zBuf); |
||
| 1218 | } |
||
| 1219 | } |
||
| 1220 | } |
||
| 1221 | } |
||
| 1222 | if (nNew > 0) |
||
| 1223 | { |
||
| 1224 | newArgc = argc + nNew - 1; |
||
| 1225 | for (i = 0; i <= index; i++) |
||
| 1226 | { |
||
| 1227 | zNew[i] = argv[i]; |
||
| 1228 | } |
||
| 1229 | } |
||
| 1230 | else |
||
| 1231 | { |
||
| 1232 | zNew = argv; |
||
| 1233 | } |
||
| 1234 | for (i = nNew + index + 1; i < newArgc; i++) |
||
| 1235 | { |
||
| 1236 | zNew[i] = argv[i + 1 - nNew]; |
||
| 1237 | } |
||
| 1238 | zNew[newArgc] = 0; |
||
| 1239 | *pArgc = newArgc; |
||
| 1240 | *pArgv = zNew; |
||
| 1241 | } |
||
| 1242 | |||
| 1243 | int main (int argc, char **argv) |
||
| 1244 | { |
||
| 1245 | int i; /* Loop counter */ |
||
| 1246 | EtCmd *pCmd; /* A new TCL command found in C code */ |
||
| 1247 | int useTk = 1; /* False if the -notk flag is used */ |
||
| 1248 | int autoFork = 0; /* True if the -autofork flag is used */ |
||
| 1249 | int nTcl = 0; /* Number of TCL scripts */ |
||
| 1250 | char **azTcl; /* Name of all TCL scripts */ |
||
| 1251 | int *aDoCompress; /* Whether or not to compress each TCL script */ |
||
| 1252 | int nData = 0; /* Number of data files */ |
||
| 1253 | char **azData; /* Names of all data files */ |
||
| 1254 | int doCompress = 1; /* Current state of the compression flag */ |
||
| 1255 | char *zTclLib = 0; /* Name of the TCL library */ |
||
| 1256 | char *zTkLib = 0; /* Name of the TK library */ |
||
| 1257 | char *zMainScript = 0; /* Name of a script to run first */ |
||
| 1258 | int shroud = 0; /* True to encrypt the compiled-in TCL */ |
||
| 1259 | int readStdin = 0; /* True to read TCL commands from STDIN */ |
||
| 1260 | int enableObj = 0; /* Enable the use of object commands */ |
||
| 1261 | int standalone = 0; /* True to disable the "source" command */ |
||
| 1262 | int stringify = 0; /* True to output only strings of the scripts */ |
||
| 1263 | int console = 0; /* True to put up a debugging console */ |
||
| 1264 | char *zExtension = 0; /* Name of the extension. NULL if a complete app */ |
||
| 1265 | int nHash; /* Number of entries in hash table */ |
||
| 1266 | extern char zTail[]; |
||
| 1267 | |||
| 1268 | if (argc >= 2 && strcmp (argv[1], "-header") == 0) |
||
| 1269 | { |
||
| 1270 | printf ("%s", zHeader); |
||
| 1271 | return 0; |
||
| 1272 | } |
||
| 1273 | if (argc >= 2 && strcmp (argv[1], "-version") == 0) |
||
| 1274 | { |
||
| 1275 | printf ("%s\n", zVersion); |
||
| 1276 | return 0; |
||
| 1277 | } |
||
| 1278 | azTcl = SafeMalloc (sizeof (char *) * (argc + 100)); |
||
| 1279 | azData = SafeMalloc (sizeof (char *) * (argc + 100)); |
||
| 1280 | aDoCompress = SafeMalloc (sizeof (int) * (argc + 100)); |
||
| 1281 | for (i = 1; i < argc; i++) |
||
| 1282 | { |
||
| 1283 | if (argv[i][0] == '-') |
||
| 1284 | { |
||
| 1285 | if (strcmp (argv[i], "-header") == 0) |
||
| 1286 | { |
||
| 1287 | printf ("%s", zHeader); |
||
| 1288 | return 0; |
||
| 1289 | } |
||
| 1290 | else if (strcmp (argv[i], "-notk") == 0) |
||
| 1291 | { |
||
| 1292 | useTk = 0; |
||
| 1293 | } |
||
| 1294 | else if (i < argc - 1 && strcmp (argv[i], "-extension") == 0) |
||
| 1295 | { |
||
| 1296 | zExtension = argv[++i]; |
||
| 1297 | } |
||
| 1298 | else if (strcmp (argv[i], "-autofork") == 0) |
||
| 1299 | { |
||
| 1300 | autoFork = 1; |
||
| 1301 | } |
||
| 1302 | else if (strcmp (argv[i], "-read-stdin") == 0) |
||
| 1303 | { |
||
| 1304 | readStdin = 1; |
||
| 1305 | } |
||
| 1306 | else if (strcmp (argv[i], "-console") == 0) |
||
| 1307 | { |
||
| 1308 | console = 1; |
||
| 1309 | } |
||
| 1310 | else if (strcmp (argv[i], "-shroud") == 0) |
||
| 1311 | { |
||
| 1312 | shroud = 1; |
||
| 1313 | } |
||
| 1314 | else if (strcmp (argv[i], "-strip-tcl") == 0) |
||
| 1315 | { |
||
| 1316 | doCompress = 1; |
||
| 1317 | } |
||
| 1318 | else if (strcmp (argv[i], "-dont-strip-tcl") == 0) |
||
| 1319 | { |
||
| 1320 | doCompress = 0; |
||
| 1321 | } |
||
| 1322 | else if (strcmp (argv[i], "-enable-obj") == 0) |
||
| 1323 | { |
||
| 1324 | enableObj = 1; |
||
| 1325 | } |
||
| 1326 | else if (strcmp (argv[i], "-standalone") == 0) |
||
| 1327 | { |
||
| 1328 | standalone = 1; |
||
| 1329 | } |
||
| 1330 | else if (strcmp (argv[i], "-stringify") == 0) |
||
| 1331 | { |
||
| 1332 | stringify = 1; |
||
| 1333 | } |
||
| 1334 | else if (i < argc - 1 && strcmp (argv[i], "-srcdir") == 0) |
||
| 1335 | { |
||
| 1336 | chdir (argv[++i]); |
||
| 1337 | } |
||
| 1338 | else if (i < argc - 1 && strcmp (argv[i], "-main-script") == 0) |
||
| 1339 | { |
||
| 1340 | zMainScript = argv[++i]; |
||
| 1341 | } |
||
| 1342 | else if (i < argc - 1 && strcmp (argv[i], "-tcl-library") == 0) |
||
| 1343 | { |
||
| 1344 | zTclLib = argv[++i]; |
||
| 1345 | } |
||
| 1346 | else if (i < argc - 1 && strcmp (argv[i], "-tk-library") == 0) |
||
| 1347 | { |
||
| 1348 | zTkLib = argv[++i]; |
||
| 1349 | } |
||
| 1350 | else if (i < argc - 1 && strcmp (argv[i], "-i") == 0) |
||
| 1351 | { |
||
| 1352 | i++; |
||
| 1353 | if (access (argv[i], R_OK)) |
||
| 1354 | { |
||
| 1355 | fprintf ( |
||
| 1356 | stderr, |
||
| 1357 | "%s: can't open \"%s\" for reading\n", |
||
| 1358 | Argv0, |
||
| 1359 | argv[i]); |
||
| 1360 | nError++; |
||
| 1361 | } |
||
| 1362 | else |
||
| 1363 | { |
||
| 1364 | azData[nData] = argv[i]; |
||
| 1365 | } |
||
| 1366 | nData++; |
||
| 1367 | } |
||
| 1368 | else if (strcmp (argv[i], "-f") == 0) |
||
| 1369 | { |
||
| 1370 | AddParameters (i, &argc, &argv); |
||
| 1371 | azTcl = SafeRealloc (azTcl, sizeof (char *) * (argc + 100)); |
||
| 1372 | azData = SafeRealloc (azData, sizeof (char *) * (argc + 100)); |
||
| 1373 | aDoCompress = |
||
| 1374 | SafeRealloc (aDoCompress, sizeof (int) * (argc + 100)); |
||
| 1375 | } |
||
| 1376 | else |
||
| 1377 | { |
||
| 1378 | Usage (argv[0]); |
||
| 1379 | } |
||
| 1380 | } |
||
| 1381 | else if (IsTclFile (argv[i])) |
||
| 1382 | { |
||
| 1383 | if (access (argv[i], R_OK)) |
||
| 1384 | { |
||
| 1385 | fprintf ( |
||
| 1386 | stderr, |
||
| 1387 | "%s: can't open \"%s\" for reading\n", |
||
| 1388 | Argv0, |
||
| 1389 | argv[i]); |
||
| 1390 | nError++; |
||
| 1391 | } |
||
| 1392 | else |
||
| 1393 | { |
||
| 1394 | int len = strlen (argv[i]); |
||
| 1395 | azTcl[nTcl] = argv[i]; |
||
| 1396 | if (len >= 9 && strcmp (&argv[i][len - 9], "/tclIndex") == 0) |
||
| 1397 | { |
||
| 1398 | aDoCompress[nTcl] = 0; |
||
| 1399 | } |
||
| 1400 | else |
||
| 1401 | { |
||
| 1402 | aDoCompress[nTcl] = doCompress; |
||
| 1403 | } |
||
| 1404 | nTcl++; |
||
| 1405 | } |
||
| 1406 | } |
||
| 1407 | else |
||
| 1408 | { |
||
| 1409 | ScanFile (argv[i]); |
||
| 1410 | } |
||
| 1411 | } |
||
| 1412 | if (nError > 0) |
||
| 1413 | return nError; |
||
| 1414 | if (shroud > 0) |
||
| 1415 | { |
||
| 1416 | shroud = time (0) % 31 + 1; |
||
| 1417 | } |
||
| 1418 | if (stringify) |
||
| 1419 | { |
||
| 1420 | for (i = 0; i < nTcl; i++) |
||
| 1421 | { |
||
| 1422 | char *z; |
||
| 1423 | z = ReadFileIntoMemory (azTcl[i], 0); |
||
| 1424 | if (z == 0) |
||
| 1425 | continue; |
||
| 1426 | if (aDoCompress[i]) |
||
| 1427 | CompressTcl (z); |
||
| 1428 | WriteAsString (z, shroud); |
||
| 1429 | printf (";\n"); |
||
| 1430 | SafeFree (z); |
||
| 1431 | } |
||
| 1432 | return 0; |
||
| 1433 | } |
||
| 1434 | if (nObjCmd > 0) |
||
| 1435 | enableObj = 1; |
||
| 1436 | printf ("/* This code is automatically generated by \"mktclapp\"" |
||
| 1437 | " version 3.9 */\n" |
||
| 1438 | "/* DO NOT EDIT */\n" |
||
| 1439 | "#include <tcl.h>\n" |
||
| 1440 | "#define INTERFACE 1\n" |
||
| 1441 | "#if INTERFACE\n" |
||
| 1442 | "#define ET_TCLARGS " |
||
| 1443 | "ClientData clientData,Tcl_Interp*interp,int argc,char**argv\n" |
||
| 1444 | "#define ET_OBJARGS " |
||
| 1445 | "ClientData clientData,Tcl_Interp*interp,int objc,Tcl_Obj*CONST objv[]\n" |
||
| 1446 | "#endif\n"); |
||
| 1447 | printf ("#define ET_ENABLE_OBJ %d\n", enableObj); |
||
| 1448 | printf ("#define ET_ENABLE_TK %d\n", useTk != 0); |
||
| 1449 | printf ("#define ET_AUTO_FORK %d\n", autoFork != 0); |
||
| 1450 | printf ("#define ET_STANDALONE %d\n", standalone != 0); |
||
| 1451 | printf ("#define ET_N_BUILTIN_SCRIPT %d\n", nTcl); |
||
| 1452 | printf ("#define ET_VERSION \"3.9\"\n"); |
||
| 1453 | SetMacro ("ET_HAVE_APPINIT", seenEtAppInit); |
||
| 1454 | SetMacro ("ET_HAVE_PREINIT", seenEtPreInit); |
||
| 1455 | SetMacro ("ET_HAVE_MAIN", seenMain); |
||
| 1456 | SetMacro ("ET_HAVE_CUSTOM_MAINLOOP", seenEtCustomMainLoop); |
||
| 1457 | SetStringMacro ("ET_TCL_LIBRARY", zTclLib); |
||
| 1458 | SetStringMacro ("ET_TK_LIBRARY", zTkLib); |
||
| 1459 | SetStringMacro ("ET_MAIN_SCRIPT", zMainScript); |
||
| 1460 | if (zExtension) |
||
| 1461 | { |
||
| 1462 | int i; |
||
| 1463 | if (islower (zExtension[0])) |
||
| 1464 | { |
||
| 1465 | zExtension[0] = toupper (zExtension[0]); |
||
| 1466 | } |
||
| 1467 | for (i = 1; zExtension[i]; i++) |
||
| 1468 | { |
||
| 1469 | if (isupper (zExtension[i])) |
||
| 1470 | { |
||
| 1471 | zExtension[i] = tolower (zExtension[i]); |
||
| 1472 | } |
||
| 1473 | } |
||
| 1474 | printf ("#define ET_EXTENSION_NAME %s_Init\n", zExtension); |
||
| 1475 | printf ("#define ET_SAFE_EXTENSION_NAME %s_SafeInit\n", zExtension); |
||
| 1476 | printf ("#define ET_EXTENSION 1\n"); |
||
| 1477 | } |
||
| 1478 | else |
||
| 1479 | { |
||
| 1480 | printf ("#define ET_EXTENSION 0\n"); |
||
| 1481 | } |
||
| 1482 | printf ("#define ET_SHROUD_KEY %d\n", shroud); |
||
| 1483 | printf ("#define ET_READ_STDIN %d\n", readStdin); |
||
| 1484 | printf ("#define ET_CONSOLE %d\n", console); |
||
| 1485 | for (pCmd = cmdList; pCmd; pCmd = pCmd->pNext) |
||
| 1486 | { |
||
| 1487 | if (pCmd->zIf && pCmd->zIf[0] == '0' && pCmd->zIf[1] == 0) |
||
| 1488 | continue; |
||
| 1489 | if (pCmd->isObj) |
||
| 1490 | { |
||
| 1491 | printf ("extern int ET_OBJCOMMAND_%s(ET_OBJARGS);\n", pCmd->zName); |
||
| 1492 | } |
||
| 1493 | else |
||
| 1494 | { |
||
| 1495 | printf ("extern int ET_COMMAND_%s(ET_TCLARGS);\n", pCmd->zName); |
||
| 1496 | } |
||
| 1497 | } |
||
| 1498 | printf ("static struct {\n" |
||
| 1499 | " char *zName;\n" |
||
| 1500 | " int (*xProc)(ET_TCLARGS);\n" |
||
| 1501 | "} Et_CmdSet[] = {\n"); |
||
| 1502 | for (pCmd = cmdList; pCmd; pCmd = pCmd->pNext) |
||
| 1503 | { |
||
| 1504 | char *zProc; |
||
| 1505 | if (pCmd->isObj) |
||
| 1506 | continue; |
||
| 1507 | if (pCmd->zIf) |
||
| 1508 | { |
||
| 1509 | if (pCmd->zIf[0] == '0' && pCmd->zIf[1] == 0) |
||
| 1510 | continue; |
||
| 1511 | printf ("#if %s\n", pCmd->zIf); |
||
| 1512 | } |
||
| 1513 | zProc = FuncToProc (pCmd->zName); |
||
| 1514 | printf (" { \"%s\", ET_COMMAND_%s },\n", zProc, pCmd->zName); |
||
| 1515 | SafeFree (zProc); |
||
| 1516 | if (pCmd->zIf) |
||
| 1517 | { |
||
| 1518 | printf ("#endif\n"); |
||
| 1519 | } |
||
| 1520 | } |
||
| 1521 | printf ("{0, 0}};\n"); |
||
| 1522 | if (enableObj) |
||
| 1523 | { |
||
| 1524 | char *zProc; |
||
| 1525 | printf ("static struct {\n" |
||
| 1526 | " char *zName;\n" |
||
| 1527 | " int (*xProc)(ET_OBJARGS);\n" |
||
| 1528 | "} Et_ObjSet[] = {\n"); |
||
| 1529 | for (pCmd = cmdList; pCmd; pCmd = pCmd->pNext) |
||
| 1530 | { |
||
| 1531 | if (!pCmd->isObj) |
||
| 1532 | continue; |
||
| 1533 | if (pCmd->zIf) |
||
| 1534 | { |
||
| 1535 | if (pCmd->zIf[0] == '0' && pCmd->zIf[1] == 0) |
||
| 1536 | continue; |
||
| 1537 | printf ("#if %s\n", pCmd->zIf); |
||
| 1538 | } |
||
| 1539 | zProc = FuncToProc (pCmd->zName); |
||
| 1540 | printf (" { \"%s\", ET_OBJCOMMAND_%s },\n", zProc, pCmd->zName); |
||
| 1541 | SafeFree (zProc); |
||
| 1542 | if (pCmd->zIf) |
||
| 1543 | { |
||
| 1544 | printf ("#endif\n"); |
||
| 1545 | } |
||
| 1546 | } |
||
| 1547 | printf ("{0, 0}};\n"); |
||
| 1548 | } |
||
| 1549 | for (i = 0; i < nTcl; i++) |
||
| 1550 | { |
||
| 1551 | char *z; |
||
| 1552 | printf ("static char Et_zFile%d[] = \n", i); |
||
| 1553 | z = ReadFileIntoMemory (azTcl[i], 0); |
||
| 1554 | if (z == 0) |
||
| 1555 | continue; |
||
| 1556 | if (aDoCompress[i]) |
||
| 1557 | CompressTcl (z); |
||
| 1558 | WriteAsString (z, shroud); |
||
| 1559 | printf (";\n"); |
||
| 1560 | SafeFree (z); |
||
| 1561 | } |
||
| 1562 | for (i = 0; i < nData; i++) |
||
| 1563 | { |
||
| 1564 | char *z; |
||
| 1565 | int len, j, col; |
||
| 1566 | printf ("static unsigned char Et_acData%d[] = {\n", i); |
||
| 1567 | z = ReadFileIntoMemory (azData[i], &len); |
||
| 1568 | if (z == 0) |
||
| 1569 | continue; |
||
| 1570 | for (j = col = 0; j < len; j++) |
||
| 1571 | { |
||
| 1572 | printf (" 0x%02x,", z[j] & 0xff); |
||
| 1573 | if (++col >= 12) |
||
| 1574 | { |
||
| 1575 | printf ("\n"); |
||
| 1576 | col = 0; |
||
| 1577 | } |
||
| 1578 | } |
||
| 1579 | if (col > 0) |
||
| 1580 | printf ("\n"); |
||
| 1581 | printf ("};\n"); |
||
| 1582 | SafeFree (z); |
||
| 1583 | } |
||
| 1584 | printf ("struct EtFile {\n" |
||
| 1585 | " char *zName;\n" |
||
| 1586 | " char *zData;\n" |
||
| 1587 | " int nData;\n" |
||
| 1588 | " int shrouded;\n" |
||
| 1589 | " struct EtFile *pNext;\n" |
||
| 1590 | "};\n" |
||
| 1591 | "static struct EtFile Et_FileSet[] = {\n"); |
||
| 1592 | for (i = 0; i < nTcl; i++) |
||
| 1593 | { |
||
| 1594 | printf ( |
||
| 1595 | " { \"%s\", Et_zFile%d, sizeof(Et_zFile%d)-1, %d, 0 },\n", |
||
| 1596 | azTcl[i], |
||
| 1597 | i, |
||
| 1598 | i, |
||
| 1599 | shroud); |
||
| 1600 | } |
||
| 1601 | for (i = 0; i < nData; i++) |
||
| 1602 | { |
||
| 1603 | printf ( |
||
| 1604 | " { \"%s\", Et_acData%d, sizeof(Et_acData%d), 0, 0 },\n", |
||
| 1605 | azData[i], |
||
| 1606 | i, |
||
| 1607 | i); |
||
| 1608 | } |
||
| 1609 | fflush (stdout); |
||
| 1610 | nHash = nTcl * 2 + 1; |
||
| 1611 | if (nHash < 71) |
||
| 1612 | { |
||
| 1613 | nHash = 71; |
||
| 1614 | } |
||
| 1615 | printf ( |
||
| 1616 | "{0, 0}};\n" |
||
| 1617 | "static struct EtFile *Et_FileHashTable[%d];\n" |
||
| 1618 | "%s", |
||
| 1619 | nHash, |
||
| 1620 | zTail); |
||
| 1621 | return nError; |
||
| 1622 | } |
||
| 1623 | |||
| 1624 | char zTail[] = |
||
| 1625 | "/* The following copyright notice applies to code generated by\n" |
||
| 1626 | "** \"mktclapp\". The \"mktclapp\" program itself is covered by the\n" |
||
| 1627 | "** GNU Public License.\n" |
||
| 1628 | "**\n" |
||
| 1629 | "** Copyright (c) 1998 D. Richard Hipp\n" |
||
| 1630 | "**\n" |
||
| 1631 | "** The author hereby grants permission to use, copy, modify, distribute,\n" |
||
| 1632 | "** and license this software and its documentation for any purpose, provided\n" |
||
| 1633 | "** that existing copyright notices are retained in all copies and that this\n" |
||
| 1634 | "** notice is included verbatim in any distributions. No written agreement,\n" |
||
| 1635 | "** license, or royalty fee is required for any of the authorized uses.\n" |
||
| 1636 | "** Modifications to this software may be copyrighted by their authors\n" |
||
| 1637 | "** and need not follow the licensing terms described here, provided that\n" |
||
| 1638 | "** the new terms are clearly indicated on the first page of each file where\n" |
||
| 1639 | "** they apply.\n" |
||
| 1640 | "**\n" |
||
| 1641 | "** In no event shall the author or the distributors be liable to any party\n" |
||
| 1642 | "** for direct, indirect, special, incidental, or consequential damages\n" |
||
| 1643 | "** arising out of the use of this software, its documentation, or any\n" |
||
| 1644 | "** derivatives thereof, even if the author has been advised of the \n" |
||
| 1645 | "** possibility of such damage. The author and distributors specifically\n" |
||
| 1646 | "** disclaim any warranties, including but not limited to the implied\n" |
||
| 1647 | "** warranties of merchantability, fitness for a particular purpose, and\n" |
||
| 1648 | "** non-infringment. This software is provided at no fee on an\n" |
||
| 1649 | "** \"as is\" basis. The author and/or distritutors have no obligation\n" |
||
| 1650 | "** to provide maintenance, support, updates, enhancements and/or\n" |
||
| 1651 | "** modifications.\n" |
||
| 1652 | "**\n" |
||
| 1653 | "** GOVERNMENT USE: If you are acquiring this software on behalf of the\n" |
||
| 1654 | "** U.S. government, the Government shall have only \"Restricted Rights\"\n" |
||
| 1655 | "** in the software and related documentation as defined in the Federal \n" |
||
| 1656 | "** Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you\n" |
||
| 1657 | "** are acquiring the software on behalf of the Department of Defense, the\n" |
||
| 1658 | "** software shall be classified as \"Commercial Computer Software\" and the\n" |
||
| 1659 | "** Government shall have only \"Restricted Rights\" as defined in Clause\n" |
||
| 1660 | "** 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the\n" |
||
| 1661 | "** author grants the U.S. Government and others acting in its behalf\n" |
||
| 1662 | "** permission to use and distribute the software in accordance with the\n" |
||
| 1663 | "** terms specified in this license. \n" |
||
| 1664 | "*/\n" |
||
| 1665 | "#include <ctype.h>\n" |
||
| 1666 | "#include <string.h>\n" |
||
| 1667 | "#include <stdarg.h>\n" |
||
| 1668 | "#include <stdio.h>\n" |
||
| 1669 | "#include <stdlib.h>\n" |
||
| 1670 | "#include <sys/types.h>\n" |
||
| 1671 | "#include <sys/stat.h>\n" |
||
| 1672 | "#include <fcntl.h>\n" |
||
| 1673 | "\n" |
||
| 1674 | "/* Include either the Tcl or the Tk header file. Use the \"Internal\"\n" |
||
| 1675 | "** version of the header file if and only if we are generating an\n" |
||
| 1676 | "** extension that is linking against the Stub library.\n" |
||
| 1677 | "** Many installations do not have the internal header files\n" |
||
| 1678 | "** available, so using the internal headers only when absolutely\n" |
||
| 1679 | "** necessary will help to reduce compilation problems.\n" |
||
| 1680 | "*/\n" |
||
| 1681 | "#if ET_EXTENSION && defined(TCL_USE_STUBS)\n" |
||
| 1682 | "# if ET_ENABLE_TK\n" |
||
| 1683 | "# include <tkInt.h>\n" |
||
| 1684 | "# else\n" |
||
| 1685 | "# include <tclInt.h>\n" |
||
| 1686 | "# endif\n" |
||
| 1687 | "#else\n" |
||
| 1688 | "# if ET_ENABLE_TK\n" |
||
| 1689 | "# include <tk.h>\n" |
||
| 1690 | "# else\n" |
||
| 1691 | "# include <tcl.h>\n" |
||
| 1692 | "# endif\n" |
||
| 1693 | "#endif\n" |
||
| 1694 | "\n" |
||
| 1695 | "/*\n" |
||
| 1696 | "** ET_WIN32 is true if we are running Tk under windows. The\n" |
||
| 1697 | "** <tcl.h> module will define __WIN32__ for us if we are compiling\n" |
||
| 1698 | "** for windows.\n" |
||
| 1699 | "*/\n" |
||
| 1700 | "#if defined(__WIN32__) && ET_ENABLE_TK\n" |
||
| 1701 | "# define ET_WIN32 1\n" |
||
| 1702 | "# include <windows.h>\n" |
||
| 1703 | "#else\n" |
||
| 1704 | "# define ET_WIN32 0\n" |
||
| 1705 | "#endif\n" |
||
| 1706 | "\n" |
||
| 1707 | "/*\n" |
||
| 1708 | "** Always disable ET_AUTO_FORK under windows. Windows doesn't\n" |
||
| 1709 | "** fork well.\n" |
||
| 1710 | "*/\n" |
||
| 1711 | "#if defined(__WIN32__)\n" |
||
| 1712 | "# undef ET_AUTO_FORK\n" |
||
| 1713 | "# define ET_AUTO_FORK 0\n" |
||
| 1714 | "#endif\n" |
||
| 1715 | "\n" |
||
| 1716 | "/*\n" |
||
| 1717 | "** Omit <unistd.h> under windows. But we need it for Unix.\n" |
||
| 1718 | "*/\n" |
||
| 1719 | "#if !defined(__WIN32__)\n" |
||
| 1720 | "# include <unistd.h>\n" |
||
| 1721 | "#endif\n" |
||
| 1722 | "\n" |
||
| 1723 | "/*\n" |
||
| 1724 | "** The Tcl*InsertProc functions allow the system calls \"stat\",\n" |
||
| 1725 | "** \"access\" and \"open\" to be overloaded. This in turns allows us\n" |
||
| 1726 | "** to substituted compiled-in strings for files in the filesystem.\n" |
||
| 1727 | "** But the Tcl*InsertProc functions are only available in Tcl8.0.3\n" |
||
| 1728 | "** and later.\n" |
||
| 1729 | "**\n" |
||
| 1730 | "** Define the ET_HAVE_INSERTPROC macro if and only if we are dealing\n" |
||
| 1731 | "** with Tcl8.0.3 or later.\n" |
||
| 1732 | "*/\n" |
||
| 1733 | "#if TCL_MAJOR_VERSION==8 && (TCL_MINOR_VERSION>0 || TCL_RELEASE_SERIAL>=3)\n" |
||
| 1734 | "# define ET_HAVE_INSERTPROC\n" |
||
| 1735 | "#endif\n" |
||
| 1736 | "\n" |
||
| 1737 | "/*\n" |
||
| 1738 | "** If we are using the Tcl*InsertProc() functions, we should provide\n" |
||
| 1739 | "** prototypes for them. But the prototypes are in the tclInt.h include\n" |
||
| 1740 | "** file, which we don't want to require the user to have on hand. So\n" |
||
| 1741 | "** we provide our own prototypes here.\n" |
||
| 1742 | "**\n" |
||
| 1743 | "** Note that if TCL_USE_STUBS is defined, then the tclInt.h is required\n" |
||
| 1744 | "** anyway, so these prototypes are not included if TCL_USE_STUBS is\n" |
||
| 1745 | "** defined. \n" |
||
| 1746 | "*/\n" |
||
| 1747 | "#if defined(ET_HAVE_INSERTPROC) && !defined(TCL_USE_STUBS)\n" |
||
| 1748 | "#ifdef __cplusplus\n" |
||
| 1749 | " extern \"C\" int TclStatInsertProc(int (*)(char*, struct stat *));\n" |
||
| 1750 | " extern \"C\" int TclAccessInsertProc(int (*)(char*, int));\n" |
||
| 1751 | " extern \"C\" int TclOpenFileChannelInsertProc(Tcl_Channel (*)(Tcl_Interp*,char*,\n" |
||
| 1752 | " char*,int));\n" |
||
| 1753 | "#else\n" |
||
| 1754 | " extern int TclStatInsertProc(int (*)(char*, struct stat *));\n" |
||
| 1755 | " extern int TclAccessInsertProc(int (*)(char*, int));\n" |
||
| 1756 | " extern int TclOpenFileChannelInsertProc(Tcl_Channel (*)(Tcl_Interp*,char*,\n" |
||
| 1757 | " char*,int));\n" |
||
| 1758 | "#endif\n" |
||
| 1759 | "#endif\n" |
||
| 1760 | "\n" |
||
| 1761 | "\n" |
||
| 1762 | "/*\n" |
||
| 1763 | "** Don't allow Win32 applications to read from stdin. Nor\n" |
||
| 1764 | "** programs that automatically go into the background. Force\n" |
||
| 1765 | "** the use of a console in these cases.\n" |
||
| 1766 | "*/\n" |
||
| 1767 | "#if (ET_WIN32 || ET_AUTO_FORK) && ET_READ_STDIN\n" |
||
| 1768 | "# undef ET_READ_STDIN\n" |
||
| 1769 | "# undef ET_CONSOLE\n" |
||
| 1770 | "# define ET_READ_STDIN 0\n" |
||
| 1771 | "# define ET_CONSOLE 1\n" |
||
| 1772 | "#endif\n" |
||
| 1773 | "\n" |
||
| 1774 | "/*\n" |
||
| 1775 | "** The console won't work without Tk.\n" |
||
| 1776 | "*/\n" |
||
| 1777 | "#if ET_ENABLE_TK==0 && ET_CONSOLE\n" |
||
| 1778 | "# undef ET_CONSOLE\n" |
||
| 1779 | "# define ET_CONSOLE 0\n" |
||
| 1780 | "# undef ET_READ_STDIN\n" |
||
| 1781 | "# define ET_READ_STDIN 1\n" |
||
| 1782 | "#endif\n" |
||
| 1783 | "\n" |
||
| 1784 | "/*\n" |
||
| 1785 | "** Set ET_HAVE_OBJ to true if we are able to link against the\n" |
||
| 1786 | "** new Tcl_Obj interface. This is only the case for Tcl version\n" |
||
| 1787 | "** 8.0 and later.\n" |
||
| 1788 | "*/\n" |
||
| 1789 | "#if ET_ENABLE_OBJ || TCL_MAJOR_VERSION>=8\n" |
||
| 1790 | "# define ET_HAVE_OBJ 1\n" |
||
| 1791 | "#else\n" |
||
| 1792 | "# define ET_HAVE_OBJ 0\n" |
||
| 1793 | "#endif\n" |
||
| 1794 | "\n" |
||
| 1795 | "/*\n" |
||
| 1796 | "** The Tcl_GetByteArrayFromObj() only appears in Tcl version 8.1\n" |
||
| 1797 | "** and later. Substitute Tcl_GetStringFromObj() in Tcl version 8.0.X\n" |
||
| 1798 | "*/\n" |
||
| 1799 | "#if ET_HAVE_OBJ && TCL_MINOR_VERSION==0\n" |
||
| 1800 | "# define Tcl_GetByteArrayFromObj Tcl_GetStringFromObj\n" |
||
| 1801 | "#endif\n" |
||
| 1802 | "\n" |
||
| 1803 | "/*\n" |
||
| 1804 | "** Tcl code to implement the console.\n" |
||
| 1805 | "**\n" |
||
| 1806 | "** This code is written and tested separately, then run through\n" |
||
| 1807 | "** \"mktclapp -stringify\" and then pasted in here.\n" |
||
| 1808 | "*/\n" |
||
| 1809 | "#if ET_ENABLE_TK && !ET_EXTENSION\n" |
||
| 1810 | "static char zEtConsole[] =\n" |
||
| 1811 | "\"proc console:create {w prompt title} {\\n\"\n" |
||
| 1812 | "\"upvar #0 $w.t v\\n\"\n" |
||
| 1813 | "\"if {[winfo exists $w]} {destroy $w}\\n\"\n" |
||
| 1814 | "\"catch {unset v}\\n\"\n" |
||
| 1815 | "\"toplevel $w\\n\"\n" |
||
| 1816 | "\"wm title $w $title\\n\"\n" |
||
| 1817 | "\"wm iconname $w $title\\n\"\n" |
||
| 1818 | "\"frame $w.mb -bd 2 -relief raised\\n\"\n" |
||
| 1819 | "\"pack $w.mb -side top -fill x\\n\"\n" |
||
| 1820 | "\"menubutton $w.mb.file -text File -menu $w.mb.file.m\\n\"\n" |
||
| 1821 | "\"menubutton $w.mb.edit -text Edit -menu $w.mb.edit.m\\n\"\n" |
||
| 1822 | "\"pack $w.mb.file $w.mb.edit -side left -padx 8 -pady 1\\n\"\n" |
||
| 1823 | "\"set m [menu $w.mb.file.m]\\n\"\n" |
||
| 1824 | "\"$m add command -label {Source...} -command \\\"console:SourceFile $w.t\\\"\\n\"\n" |
||
| 1825 | "\"$m add command -label {Save As...} -command \\\"console:SaveFile $w.t\\\"\\n\"\n" |
||
| 1826 | "\"$m add separator\\n\"\n" |
||
| 1827 | "\"$m add command -label {Close} -command \\\"destroy $w\\\"\\n\"\n" |
||
| 1828 | "\"$m add command -label {Exit} -command exit\\n\"\n" |
||
| 1829 | "\"set m [menu $w.mb.edit.m]\\n\"\n" |
||
| 1830 | "\"$m add command -label Cut -command \\\"console:Cut $w.t\\\"\\n\"\n" |
||
| 1831 | "\"$m add command -label Copy -command \\\"console:Copy $w.t\\\"\\n\"\n" |
||
| 1832 | "\"$m add command -label Paste -command \\\"console:Paste $w.t\\\"\\n\"\n" |
||
| 1833 | "\"$m add command -label {Clear Screen} -command \\\"console:Clear $w.t\\\"\\n\"\n" |
||
| 1834 | "\"catch {$m config -postcommand \\\"console:EnableEditMenu $w\\\"}\\n\"\n" |
||
| 1835 | "\"scrollbar $w.sb -orient vertical -command \\\"$w.t yview\\\"\\n\"\n" |
||
| 1836 | "\"pack $w.sb -side right -fill y\\n\"\n" |
||
| 1837 | "\"text $w.t -font fixed -yscrollcommand \\\"$w.sb set\\\"\\n\"\n" |
||
| 1838 | "\"pack $w.t -side right -fill both -expand 1\\n\"\n" |
||
| 1839 | "\"bindtags $w.t Console\\n\"\n" |
||
| 1840 | "\"set v(text) $w.t\\n\"\n" |
||
| 1841 | "\"set v(history) 0\\n\"\n" |
||
| 1842 | "\"set v(historycnt) 0\\n\"\n" |
||
| 1843 | "\"set v(current) -1\\n\"\n" |
||
| 1844 | "\"set v(prompt) $prompt\\n\"\n" |
||
| 1845 | "\"set v(prior) {}\\n\"\n" |
||
| 1846 | "\"set v(plength) [string length $v(prompt)]\\n\"\n" |
||
| 1847 | "\"set v(x) 0\\n\"\n" |
||
| 1848 | "\"set v(y) 0\\n\"\n" |
||
| 1849 | "\"$w.t mark set insert end\\n\"\n" |
||
| 1850 | "\"$w.t tag config ok -foreground blue\\n\"\n" |
||
| 1851 | "\"$w.t tag config err -foreground red\\n\"\n" |
||
| 1852 | "\"$w.t insert end $v(prompt)\\n\"\n" |
||
| 1853 | "\"$w.t mark set out 1.0\\n\"\n" |
||
| 1854 | "\"catch {rename puts console:oldputs$w}\\n\"\n" |
||
| 1855 | "\"proc puts args [format {\\n\"\n" |
||
| 1856 | "\"if {![winfo exists %s]} {\\n\"\n" |
||
| 1857 | "\"rename puts {}\\n\"\n" |
||
| 1858 | "\"rename console:oldputs%s puts\\n\"\n" |
||
| 1859 | "\"return [uplevel #0 puts $args]\\n\"\n" |
||
| 1860 | "\"}\\n\"\n" |
||
| 1861 | "\"switch -glob -- \\\"[llength $args] $args\\\" {\\n\"\n" |
||
| 1862 | "\"{1 *} {\\n\"\n" |
||
| 1863 | "\"set msg [lindex $args 0]\\\\n\\n\"\n" |
||
| 1864 | "\"set tag ok\\n\"\n" |
||
| 1865 | "\"}\\n\"\n" |
||
| 1866 | "\"{2 stdout *} {\\n\"\n" |
||
| 1867 | "\"set msg [lindex $args 1]\\\\n\\n\"\n" |
||
| 1868 | "\"set tag ok\\n\"\n" |
||
| 1869 | "\"}\\n\"\n" |
||
| 1870 | "\"{2 stderr *} {\\n\"\n" |
||
| 1871 | "\"set msg [lindex $args 1]\\\\n\\n\"\n" |
||
| 1872 | "\"set tag err\\n\"\n" |
||
| 1873 | "\"}\\n\"\n" |
||
| 1874 | "\"{2 -nonewline *} {\\n\"\n" |
||
| 1875 | "\"set msg [lindex $args 1]\\n\"\n" |
||
| 1876 | "\"set tag ok\\n\"\n" |
||
| 1877 | "\"}\\n\"\n" |
||
| 1878 | "\"{3 -nonewline stdout *} {\\n\"\n" |
||
| 1879 | "\"set msg [lindex $args 2]\\n\"\n" |
||
| 1880 | "\"set tag ok\\n\"\n" |
||
| 1881 | "\"}\\n\"\n" |
||
| 1882 | "\"{3 -nonewline stderr *} {\\n\"\n" |
||
| 1883 | "\"set msg [lindex $args 2]\\n\"\n" |
||
| 1884 | "\"set tag err\\n\"\n" |
||
| 1885 | "\"}\\n\"\n" |
||
| 1886 | "\"default {\\n\"\n" |
||
| 1887 | "\"uplevel #0 console:oldputs%s $args\\n\"\n" |
||
| 1888 | "\"return\\n\"\n" |
||
| 1889 | "\"}\\n\"\n" |
||
| 1890 | "\"}\\n\"\n" |
||
| 1891 | "\"console:Puts %s $msg $tag\\n\"\n" |
||
| 1892 | "\"} $w $w $w $w.t]\\n\"\n" |
||
| 1893 | "\"after idle \\\"focus $w.t\\\"\\n\"\n" |
||
| 1894 | "\"}\\n\"\n" |
||
| 1895 | "\"bind Console <1> {console:Button1 %W %x %y}\\n\"\n" |
||
| 1896 | "\"bind Console <B1-Motion> {console:B1Motion %W %x %y}\\n\"\n" |
||
| 1897 | "\"bind Console <B1-Leave> {console:B1Leave %W %x %y}\\n\"\n" |
||
| 1898 | "\"bind Console <B1-Enter> {console:cancelMotor %W}\\n\"\n" |
||
| 1899 | "\"bind Console <ButtonRelease-1> {console:cancelMotor %W}\\n\"\n" |
||
| 1900 | "\"bind Console <KeyPress> {console:Insert %W %A}\\n\"\n" |
||
| 1901 | "\"bind Console <Left> {console:Left %W}\\n\"\n" |
||
| 1902 | "\"bind Console <Control-b> {console:Left %W}\\n\"\n" |
||
| 1903 | "\"bind Console <Right> {console:Right %W}\\n\"\n" |
||
| 1904 | "\"bind Console <Control-f> {console:Right %W}\\n\"\n" |
||
| 1905 | "\"bind Console <BackSpace> {console:Backspace %W}\\n\"\n" |
||
| 1906 | "\"bind Console <Control-h> {console:Backspace %W}\\n\"\n" |
||
| 1907 | "\"bind Console <Delete> {console:Delete %W}\\n\"\n" |
||
| 1908 | "\"bind Console <Control-d> {console:Delete %W}\\n\"\n" |
||
| 1909 | "\"bind Console <Home> {console:Home %W}\\n\"\n" |
||
| 1910 | "\"bind Console <Control-a> {console:Home %W}\\n\"\n" |
||
| 1911 | "\"bind Console <End> {console:End %W}\\n\"\n" |
||
| 1912 | "\"bind Console <Control-e> {console:End %W}\\n\"\n" |
||
| 1913 | "\"bind Console <Return> {console:Enter %W}\\n\"\n" |
||
| 1914 | "\"bind Console <KP_Enter> {console:Enter %W}\\n\"\n" |
||
| 1915 | "\"bind Console <Up> {console:Prior %W}\\n\"\n" |
||
| 1916 | "\"bind Console <Control-p> {console:Prior %W}\\n\"\n" |
||
| 1917 | "\"bind Console <Down> {console:Next %W}\\n\"\n" |
||
| 1918 | "\"bind Console <Control-n> {console:Next %W}\\n\"\n" |
||
| 1919 | "\"bind Console <Control-k> {console:EraseEOL %W}\\n\"\n" |
||
| 1920 | "\"bind Console <<Cut>> {console:Cut %W}\\n\"\n" |
||
| 1921 | "\"bind Console <<Copy>> {console:Copy %W}\\n\"\n" |
||
| 1922 | "\"bind Console <<Paste>> {console:Paste %W}\\n\"\n" |
||
| 1923 | "\"bind Console <<Clear>> {console:Clear %W}\\n\"\n" |
||
| 1924 | "\"proc console:Puts {w t tag} {\\n\"\n" |
||
| 1925 | "\"set nc [string length $t]\\n\"\n" |
||
| 1926 | "\"set endc [string index $t [expr $nc-1]]\\n\"\n" |
||
| 1927 | "\"if {$endc==\\\"\\\\n\\\"} {\\n\"\n" |
||
| 1928 | "\"if {[$w index out]<[$w index {insert linestart}]} {\\n\"\n" |
||
| 1929 | "\"$w insert out [string range $t 0 [expr $nc-2]] $tag\\n\"\n" |
||
| 1930 | "\"$w mark set out {out linestart +1 lines}\\n\"\n" |
||
| 1931 | "\"} else {\\n\"\n" |
||
| 1932 | "\"$w insert out $t $tag\\n\"\n" |
||
| 1933 | "\"}\\n\"\n" |
||
| 1934 | "\"} else {\\n\"\n" |
||
| 1935 | "\"if {[$w index out]<[$w index {insert linestart}]} {\\n\"\n" |
||
| 1936 | "\"$w insert out $t $tag\\n\"\n" |
||
| 1937 | "\"} else {\\n\"\n" |
||
| 1938 | "\"$w insert out $t\\\\n $tag\\n\"\n" |
||
| 1939 | "\"$w mark set out {out -1 char}\\n\"\n" |
||
| 1940 | "\"}\\n\"\n" |
||
| 1941 | "\"}\\n\"\n" |
||
| 1942 | "\"$w yview insert\\n\"\n" |
||
| 1943 | "\"}\\n\"\n" |
||
| 1944 | "\"proc console:Insert {w a} {\\n\"\n" |
||
| 1945 | "\"$w insert insert $a\\n\"\n" |
||
| 1946 | "\"$w yview insert\\n\"\n" |
||
| 1947 | "\"}\\n\"\n" |
||
| 1948 | "\"proc console:Left {w} {\\n\"\n" |
||
| 1949 | "\"upvar #0 $w v\\n\"\n" |
||
| 1950 | "\"scan [$w index insert] %d.%d row col\\n\"\n" |
||
| 1951 | "\"if {$col>$v(plength)} {\\n\"\n" |
||
| 1952 | "\"$w mark set insert \\\"insert -1c\\\"\\n\"\n" |
||
| 1953 | "\"}\\n\"\n" |
||
| 1954 | "\"}\\n\"\n" |
||
| 1955 | "\"proc console:Backspace {w} {\\n\"\n" |
||
| 1956 | "\"upvar #0 $w v\\n\"\n" |
||
| 1957 | "\"scan [$w index insert] %d.%d row col\\n\"\n" |
||
| 1958 | "\"if {$col>$v(plength)} {\\n\"\n" |
||
| 1959 | "\"$w delete {insert -1c}\\n\"\n" |
||
| 1960 | "\"}\\n\"\n" |
||
| 1961 | "\"}\\n\"\n" |
||
| 1962 | "\"proc console:EraseEOL {w} {\\n\"\n" |
||
| 1963 | "\"upvar #0 $w v\\n\"\n" |
||
| 1964 | "\"scan [$w index insert] %d.%d row col\\n\"\n" |
||
| 1965 | "\"if {$col>=$v(plength)} {\\n\"\n" |
||
| 1966 | "\"$w delete insert {insert lineend}\\n\"\n" |
||
| 1967 | "\"}\\n\"\n" |
||
| 1968 | "\"}\\n\"\n" |
||
| 1969 | "\"proc console:Right {w} {\\n\"\n" |
||
| 1970 | "\"$w mark set insert \\\"insert +1c\\\"\\n\"\n" |
||
| 1971 | "\"}\\n\"\n" |
||
| 1972 | "\"proc console:Delete w {\\n\"\n" |
||
| 1973 | "\"$w delete insert\\n\"\n" |
||
| 1974 | "\"}\\n\"\n" |
||
| 1975 | "\"proc console:Home w {\\n\"\n" |
||
| 1976 | "\"upvar #0 $w v\\n\"\n" |
||
| 1977 | "\"scan [$w index insert] %d.%d row col\\n\"\n" |
||
| 1978 | "\"$w mark set insert $row.$v(plength)\\n\"\n" |
||
| 1979 | "\"}\\n\"\n" |
||
| 1980 | "\"proc console:End w {\\n\"\n" |
||
| 1981 | "\"$w mark set insert {insert lineend}\\n\"\n" |
||
| 1982 | "\"}\\n\"\n" |
||
| 1983 | "\"proc console:Enter w {\\n\"\n" |
||
| 1984 | "\"upvar #0 $w v\\n\"\n" |
||
| 1985 | "\"scan [$w index insert] %d.%d row col\\n\"\n" |
||
| 1986 | "\"set start $row.$v(plength)\\n\"\n" |
||
| 1987 | "\"set line [$w get $start \\\"$start lineend\\\"]\\n\"\n" |
||
| 1988 | "\"if {$v(historycnt)>0} {\\n\"\n" |
||
| 1989 | "\"set last [lindex $v(history) [expr $v(historycnt)-1]]\\n\"\n" |
||
| 1990 | "\"if {[string compare $last $line]} {\\n\"\n" |
||
| 1991 | "\"lappend v(history) $line\\n\"\n" |
||
| 1992 | "\"incr v(historycnt)\\n\"\n" |
||
| 1993 | "\"}\\n\"\n" |
||
| 1994 | "\"} else {\\n\"\n" |
||
| 1995 | "\"set v(history) [list $line]\\n\"\n" |
||
| 1996 | "\"set v(historycnt) 1\\n\"\n" |
||
| 1997 | "\"}\\n\"\n" |
||
| 1998 | "\"set v(current) $v(historycnt)\\n\"\n" |
||
| 1999 | "\"$w insert end \\\\n\\n\"\n" |
||
| 2000 | "\"$w mark set out end\\n\"\n" |
||
| 2001 | "\"if {$v(prior)==\\\"\\\"} {\\n\"\n" |
||
| 2002 | "\"set cmd $line\\n\"\n" |
||
| 2003 | "\"} else {\\n\"\n" |
||
| 2004 | "\"set cmd $v(prior)\\\\n$line\\n\"\n" |
||
| 2005 | "\"}\\n\"\n" |
||
| 2006 | "\"if {[info complete $cmd]} {\\n\"\n" |
||
| 2007 | "\"set rc [catch {uplevel #0 $cmd} res]\\n\"\n" |
||
| 2008 | "\"if {![winfo exists $w]} return\\n\"\n" |
||
| 2009 | "\"if {$rc} {\\n\"\n" |
||
| 2010 | "\"$w insert end $res\\\\n err\\n\"\n" |
||
| 2011 | "\"} elseif {[string length $res]>0} {\\n\"\n" |
||
| 2012 | "\"$w insert end $res\\\\n ok\\n\"\n" |
||
| 2013 | "\"}\\n\"\n" |
||
| 2014 | "\"set v(prior) {}\\n\"\n" |
||
| 2015 | "\"$w insert end $v(prompt)\\n\"\n" |
||
| 2016 | "\"} else {\\n\"\n" |
||
| 2017 | "\"set v(prior) $cmd\\n\"\n" |
||
| 2018 | "\"regsub -all {[^ ]} $v(prompt) . x\\n\"\n" |
||
| 2019 | "\"$w insert end $x\\n\"\n" |
||
| 2020 | "\"}\\n\"\n" |
||
| 2021 | "\"$w mark set insert end\\n\"\n" |
||
| 2022 | "\"$w mark set out {insert linestart}\\n\"\n" |
||
| 2023 | "\"$w yview insert\\n\"\n" |
||
| 2024 | "\"}\\n\"\n" |
||
| 2025 | "\"proc console:Prior w {\\n\"\n" |
||
| 2026 | "\"upvar #0 $w v\\n\"\n" |
||
| 2027 | "\"if {$v(current)<=0} return\\n\"\n" |
||
| 2028 | "\"incr v(current) -1\\n\"\n" |
||
| 2029 | "\"set line [lindex $v(history) $v(current)]\\n\"\n" |
||
| 2030 | "\"console:SetLine $w $line\\n\"\n" |
||
| 2031 | "\"}\\n\"\n" |
||
| 2032 | "\"proc console:Next w {\\n\"\n" |
||
| 2033 | "\"upvar #0 $w v\\n\"\n" |
||
| 2034 | "\"if {$v(current)>=$v(historycnt)} return\\n\"\n" |
||
| 2035 | "\"incr v(current) 1\\n\"\n" |
||
| 2036 | "\"set line [lindex $v(history) $v(current)]\\n\"\n" |
||
| 2037 | "\"console:SetLine $w $line\\n\"\n" |
||
| 2038 | "\"}\\n\"\n" |
||
| 2039 | "\"proc console:SetLine {w line} {\\n\"\n" |
||
| 2040 | "\"upvar #0 $w v\\n\"\n" |
||
| 2041 | "\"scan [$w index insert] %d.%d row col\\n\"\n" |
||
| 2042 | "\"set start $row.$v(plength)\\n\"\n" |
||
| 2043 | "\"$w delete $start end\\n\"\n" |
||
| 2044 | "\"$w insert end $line\\n\"\n" |
||
| 2045 | "\"$w mark set insert end\\n\"\n" |
||
| 2046 | "\"$w yview insert\\n\"\n" |
||
| 2047 | "\"}\\n\"\n" |
||
| 2048 | "\"proc console:Button1 {w x y} {\\n\"\n" |
||
| 2049 | "\"global tkPriv\\n\"\n" |
||
| 2050 | "\"upvar #0 $w v\\n\"\n" |
||
| 2051 | "\"set v(mouseMoved) 0\\n\"\n" |
||
| 2052 | "\"set v(pressX) $x\\n\"\n" |
||
| 2053 | "\"set p [console:nearestBoundry $w $x $y]\\n\"\n" |
||
| 2054 | "\"scan [$w index insert] %d.%d ix iy\\n\"\n" |
||
| 2055 | "\"scan $p %d.%d px py\\n\"\n" |
||
| 2056 | "\"if {$px==$ix} {\\n\"\n" |
||
| 2057 | "\"$w mark set insert $p\\n\"\n" |
||
| 2058 | "\"}\\n\"\n" |
||
| 2059 | "\"$w mark set anchor $p\\n\"\n" |
||
| 2060 | "\"focus $w\\n\"\n" |
||
| 2061 | "\"}\\n\"\n" |
||
| 2062 | "\"proc console:nearestBoundry {w x y} {\\n\"\n" |
||
| 2063 | "\"set p [$w index @$x,$y]\\n\"\n" |
||
| 2064 | "\"set bb [$w bbox $p]\\n\"\n" |
||
| 2065 | "\"if {![string compare $bb \\\"\\\"]} {return $p}\\n\"\n" |
||
| 2066 | "\"if {($x-[lindex $bb 0])<([lindex $bb 2]/2)} {return $p}\\n\"\n" |
||
| 2067 | "\"$w index \\\"$p + 1 char\\\"\\n\"\n" |
||
| 2068 | "\"}\\n\"\n" |
||
| 2069 | "\"proc console:SelectTo {w x y} {\\n\"\n" |
||
| 2070 | "\"upvar #0 $w v\\n\"\n" |
||
| 2071 | "\"set cur [console:nearestBoundry $w $x $y]\\n\"\n" |
||
| 2072 | "\"if {[catch {$w index anchor}]} {\\n\"\n" |
||
| 2073 | "\"$w mark set anchor $cur\\n\"\n" |
||
| 2074 | "\"}\\n\"\n" |
||
| 2075 | "\"set anchor [$w index anchor]\\n\"\n" |
||
| 2076 | "\"if {[$w compare $cur != $anchor] || (abs($v(pressX) - $x) >= 3)} {\\n\"\n" |
||
| 2077 | "\"if {$v(mouseMoved)==0} {\\n\"\n" |
||
| 2078 | "\"$w tag remove sel 0.0 end\\n\"\n" |
||
| 2079 | "\"}\\n\"\n" |
||
| 2080 | "\"set v(mouseMoved) 1\\n\"\n" |
||
| 2081 | "\"}\\n\"\n" |
||
| 2082 | "\"if {[$w compare $cur < anchor]} {\\n\"\n" |
||
| 2083 | "\"set first $cur\\n\"\n" |
||
| 2084 | "\"set last anchor\\n\"\n" |
||
| 2085 | "\"} else {\\n\"\n" |
||
| 2086 | "\"set first anchor\\n\"\n" |
||
| 2087 | "\"set last $cur\\n\"\n" |
||
| 2088 | "\"}\\n\"\n" |
||
| 2089 | "\"if {$v(mouseMoved)} {\\n\"\n" |
||
| 2090 | "\"$w tag remove sel 0.0 $first\\n\"\n" |
||
| 2091 | "\"$w tag add sel $first $last\\n\"\n" |
||
| 2092 | "\"$w tag remove sel $last end\\n\"\n" |
||
| 2093 | "\"update idletasks\\n\"\n" |
||
| 2094 | "\"}\\n\"\n" |
||
| 2095 | "\"}\\n\"\n" |
||
| 2096 | "\"proc console:B1Motion {w x y} {\\n\"\n" |
||
| 2097 | "\"upvar #0 $w v\\n\"\n" |
||
| 2098 | "\"set v(y) $y\\n\"\n" |
||
| 2099 | "\"set v(x) $x\\n\"\n" |
||
| 2100 | "\"console:SelectTo $w $x $y\\n\"\n" |
||
| 2101 | "\"}\\n\"\n" |
||
| 2102 | "\"proc console:B1Leave {w x y} {\\n\"\n" |
||
| 2103 | "\"upvar #0 $w v\\n\"\n" |
||
| 2104 | "\"set v(y) $y\\n\"\n" |
||
| 2105 | "\"set v(x) $x\\n\"\n" |
||
| 2106 | "\"console:motor $w\\n\"\n" |
||
| 2107 | "\"}\\n\"\n" |
||
| 2108 | "\"proc console:motor w {\\n\"\n" |
||
| 2109 | "\"upvar #0 $w v\\n\"\n" |
||
| 2110 | "\"if {![winfo exists $w]} return\\n\"\n" |
||
| 2111 | "\"if {$v(y)>=[winfo height $w]} {\\n\"\n" |
||
| 2112 | "\"$w yview scroll 1 units\\n\"\n" |
||
| 2113 | "\"} elseif {$v(y)<0} {\\n\"\n" |
||
| 2114 | "\"$w yview scroll -1 units\\n\"\n" |
||
| 2115 | "\"} else {\\n\"\n" |
||
| 2116 | "\"return\\n\"\n" |
||
| 2117 | "\"}\\n\"\n" |
||
| 2118 | "\"console:SelectTo $w $v(x) $v(y)\\n\"\n" |
||
| 2119 | "\"set v(timer) [after 50 console:motor $w]\\n\"\n" |
||
| 2120 | "\"}\\n\"\n" |
||
| 2121 | "\"proc console:cancelMotor w {\\n\"\n" |
||
| 2122 | "\"upvar #0 $w v\\n\"\n" |
||
| 2123 | "\"catch {after cancel $v(timer)}\\n\"\n" |
||
| 2124 | "\"catch {unset v(timer)}\\n\"\n" |
||
| 2125 | "\"}\\n\"\n" |
||
| 2126 | "\"proc console:Copy w {\\n\"\n" |
||
| 2127 | "\"if {![catch {set text [$w get sel.first sel.last]}]} {\\n\"\n" |
||
| 2128 | "\"clipboard clear -displayof $w\\n\"\n" |
||
| 2129 | "\"clipboard append -displayof $w $text\\n\"\n" |
||
| 2130 | "\"}\\n\"\n" |
||
| 2131 | "\"}\\n\"\n" |
||
| 2132 | "\"proc console:canCut w {\\n\"\n" |
||
| 2133 | "\"set r [catch {\\n\"\n" |
||
| 2134 | "\"scan [$w index sel.first] %d.%d s1x s1y\\n\"\n" |
||
| 2135 | "\"scan [$w index sel.last] %d.%d s2x s2y\\n\"\n" |
||
| 2136 | "\"scan [$w index insert] %d.%d ix iy\\n\"\n" |
||
| 2137 | "\"}]\\n\"\n" |
||
| 2138 | "\"if {$r==1} {return 0}\\n\"\n" |
||
| 2139 | "\"if {$s1x==$ix && $s2x==$ix} {return 1}\\n\"\n" |
||
| 2140 | "\"return 2\\n\"\n" |
||
| 2141 | "\"}\\n\"\n" |
||
| 2142 | "\"proc console:Cut w {\\n\"\n" |
||
| 2143 | "\"if {[console:canCut $w]==1} {\\n\"\n" |
||
| 2144 | "\"console:Copy $w\\n\"\n" |
||
| 2145 | "\"$w delete sel.first sel.last\\n\"\n" |
||
| 2146 | "\"}\\n\"\n" |
||
| 2147 | "\"}\\n\"\n" |
||
| 2148 | "\"proc console:Paste w {\\n\"\n" |
||
| 2149 | "\"if {[console:canCut $w]==1} {\\n\"\n" |
||
| 2150 | "\"$w delete sel.first sel.last\\n\"\n" |
||
| 2151 | "\"}\\n\"\n" |
||
| 2152 | "\"if {[catch {selection get -displayof $w -selection CLIPBOARD} topaste]} {\\n\"\n" |
||
| 2153 | "\"return\\n\"\n" |
||
| 2154 | "\"}\\n\"\n" |
||
| 2155 | "\"set prior 0\\n\"\n" |
||
| 2156 | "\"foreach line [split $topaste \\\\n] {\\n\"\n" |
||
| 2157 | "\"if {$prior} {\\n\"\n" |
||
| 2158 | "\"console:Enter $w\\n\"\n" |
||
| 2159 | "\"update\\n\"\n" |
||
| 2160 | "\"}\\n\"\n" |
||
| 2161 | "\"set prior 1\\n\"\n" |
||
| 2162 | "\"$w insert insert $line\\n\"\n" |
||
| 2163 | "\"}\\n\"\n" |
||
| 2164 | "\"}\\n\"\n" |
||
| 2165 | "\"proc console:EnableEditMenu w {\\n\"\n" |
||
| 2166 | "\"set m $w.mb.edit.m\\n\"\n" |
||
| 2167 | "\"switch [console:canCut $w.t] {\\n\"\n" |
||
| 2168 | "\"0 {\\n\"\n" |
||
| 2169 | "\"$m entryconf Copy -state disabled\\n\"\n" |
||
| 2170 | "\"$m entryconf Cut -state disabled\\n\"\n" |
||
| 2171 | "\"}\\n\"\n" |
||
| 2172 | "\"1 {\\n\"\n" |
||
| 2173 | "\"$m entryconf Copy -state normal\\n\"\n" |
||
| 2174 | "\"$m entryconf Cut -state normal\\n\"\n" |
||
| 2175 | "\"}\\n\"\n" |
||
| 2176 | "\"2 {\\n\"\n" |
||
| 2177 | "\"$m entryconf Copy -state normal\\n\"\n" |
||
| 2178 | "\"$m entryconf Cut -state disabled\\n\"\n" |
||
| 2179 | "\"}\\n\"\n" |
||
| 2180 | "\"}\\n\"\n" |
||
| 2181 | "\"}\\n\"\n" |
||
| 2182 | "\"proc console:SourceFile w {\\n\"\n" |
||
| 2183 | "\"set types {\\n\"\n" |
||
| 2184 | "\"{{TCL Scripts} {.tcl}}\\n\"\n" |
||
| 2185 | "\"{{All Files} *}\\n\"\n" |
||
| 2186 | "\"}\\n\"\n" |
||
| 2187 | "\"set f [tk_getOpenFile -filetypes $types -title \\\"TCL Script To Source...\\\"]\\n\"\n" |
||
| 2188 | "\"if {$f!=\\\"\\\"} {\\n\"\n" |
||
| 2189 | "\"uplevel #0 source $f\\n\"\n" |
||
| 2190 | "\"}\\n\"\n" |
||
| 2191 | "\"}\\n\"\n" |
||
| 2192 | "\"proc console:SaveFile w {\\n\"\n" |
||
| 2193 | "\"set types {\\n\"\n" |
||
| 2194 | "\"{{Text Files} {.txt}}\\n\"\n" |
||
| 2195 | "\"{{All Files} *}\\n\"\n" |
||
| 2196 | "\"}\\n\"\n" |
||
| 2197 | "\"set f [tk_getSaveFile -filetypes $types -title \\\"Write Screen To...\\\"]\\n\"\n" |
||
| 2198 | "\"if {$f!=\\\"\\\"} {\\n\"\n" |
||
| 2199 | "\"if {[catch {open $f w} fd]} {\\n\"\n" |
||
| 2200 | "\"tk_messageBox -type ok -icon error -message $fd\\n\"\n" |
||
| 2201 | "\"} else {\\n\"\n" |
||
| 2202 | "\"puts $fd [string trimright [$w get 1.0 end] \\\\n]\\n\"\n" |
||
| 2203 | "\"close $fd\\n\"\n" |
||
| 2204 | "\"}\\n\"\n" |
||
| 2205 | "\"}\\n\"\n" |
||
| 2206 | "\"}\\n\"\n" |
||
| 2207 | "\"proc console:Clear w {\\n\"\n" |
||
| 2208 | "\"$w delete 1.0 {insert linestart}\\n\"\n" |
||
| 2209 | "\"}\\n\"\n" |
||
| 2210 | "; /* End of the console code */\n" |
||
| 2211 | "#endif /* ET_ENABLE_TK */\n" |
||
| 2212 | "\n" |
||
| 2213 | "/*\n" |
||
| 2214 | "** The \"printf\" code that follows dates from the 1980's. It is in\n" |
||
| 2215 | "** the public domain. The original comments are included here for\n" |
||
| 2216 | "** completeness. They are slightly out-of-date.\n" |
||
| 2217 | "**\n" |
||
| 2218 | "** The following modules is an enhanced replacement for the \"printf\" programs\n" |
||
| 2219 | "** found in the standard library. The following enhancements are\n" |
||
| 2220 | "** supported:\n" |
||
| 2221 | "**\n" |
||
| 2222 | "** + Additional functions. The standard set of \"printf\" functions\n" |
||
| 2223 | "** includes printf, fprintf, sprintf, vprintf, vfprintf, and\n" |
||
| 2224 | "** vsprintf. This module adds the following:\n" |
||
| 2225 | "**\n" |
||
| 2226 | "** * snprintf -- Works like sprintf, but has an extra argument\n" |
||
| 2227 | "** which is the size of the buffer written to.\n" |
||
| 2228 | "**\n" |
||
| 2229 | "** * mprintf -- Similar to sprintf. Writes output to memory\n" |
||
| 2230 | "** obtained from malloc.\n" |
||
| 2231 | "**\n" |
||
| 2232 | "** * xprintf -- Calls a function to dispose of output.\n" |
||
| 2233 | "**\n" |
||
| 2234 | "** * nprintf -- No output, but returns the number of characters\n" |
||
| 2235 | "** that would have been output by printf.\n" |
||
| 2236 | "**\n" |
||
| 2237 | "** * A v- version (ex: vsnprintf) of every function is also\n" |
||
| 2238 | "** supplied.\n" |
||
| 2239 | "**\n" |
||
| 2240 | "** + A few extensions to the formatting notation are supported:\n" |
||
| 2241 | "**\n" |
||
| 2242 | "** * The \"=\" flag (similar to \"-\") causes the output to be\n" |
||
| 2243 | "** be centered in the appropriately sized field.\n" |
||
| 2244 | "**\n" |
||
| 2245 | "** * The %b field outputs an integer in binary notation.\n" |
||
| 2246 | "**\n" |
||
| 2247 | "** * The %c field now accepts a precision. The character output\n" |
||
| 2248 | "** is repeated by the number of times the precision specifies.\n" |
||
| 2249 | "**\n" |
||
| 2250 | "** * The %' field works like %c, but takes as its character the\n" |
||
| 2251 | "** next character of the format string, instead of the next\n" |
||
| 2252 | "** argument. For example, printf(\"%.78'-\") prints 78 minus\n" |
||
| 2253 | "** signs, the same as printf(\"%.78c\",'-').\n" |
||
| 2254 | "**\n" |
||
| 2255 | "** + When compiled using GCC on a SPARC, this version of printf is\n" |
||
| 2256 | "** faster than the library printf for SUN OS 4.1.\n" |
||
| 2257 | "**\n" |
||
| 2258 | "** + All functions are fully reentrant.\n" |
||
| 2259 | "**\n" |
||
| 2260 | "*/\n" |
||
| 2261 | "/*\n" |
||
| 2262 | "** Undefine COMPATIBILITY to make some slight changes in the way things\n" |
||
| 2263 | "** work. I think the changes are an improvement, but they are not\n" |
||
| 2264 | "** backwards compatible.\n" |
||
| 2265 | "*/\n" |
||
| 2266 | "/* #define COMPATIBILITY / * Compatible with SUN OS 4.1 */\n" |
||
| 2267 | "\n" |
||
| 2268 | "/*\n" |
||
| 2269 | "** Characters that need to be escaped inside a TCL string.\n" |
||
| 2270 | "*/\n" |
||
| 2271 | "static char NeedEsc[] = {\n" |
||
| 2272 | " 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,\n" |
||
| 2273 | " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" |
||
| 2274 | " 0, 0, '\"', 0, '$', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n" |
||
| 2275 | " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n" |
||
| 2276 | " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n" |
||
| 2277 | " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[','\\\\', ']', 0, 0,\n" |
||
| 2278 | " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n" |
||
| 2279 | " 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,\n" |
||
| 2280 | " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" |
||
| 2281 | " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" |
||
| 2282 | " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" |
||
| 2283 | " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" |
||
| 2284 | " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" |
||
| 2285 | " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" |
||
| 2286 | " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" |
||
| 2287 | " 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n" |
||
| 2288 | "};\n" |
||
| 2289 | "\n" |
||
| 2290 | "/*\n" |
||
| 2291 | "** Conversion types fall into various categories as defined by the\n" |
||
| 2292 | "** following enumeration.\n" |
||
| 2293 | "*/\n" |
||
| 2294 | "enum et_type { /* The type of the format field */\n" |
||
| 2295 | " etRADIX, /* Integer types. %d, %x, %o, and so forth */\n" |
||
| 2296 | " etFLOAT, /* Floating point. %f */\n" |
||
| 2297 | " etEXP, /* Exponentional notation. %e and %E */\n" |
||
| 2298 | " etGENERIC, /* Floating or exponential, depending on exponent. %g */\n" |
||
| 2299 | " etSIZE, /* Return number of characters processed so far. %n */\n" |
||
| 2300 | " etSTRING, /* Strings. %s */\n" |
||
| 2301 | " etPERCENT, /* Percent symbol. %% */\n" |
||
| 2302 | " etCHARX, /* Characters. %c */\n" |
||
| 2303 | " etERROR, /* Used to indicate no such conversion type */\n" |
||
| 2304 | "/* The rest are extensions, not normally found in printf() */\n" |
||
| 2305 | " etCHARLIT, /* Literal characters. %' */\n" |
||
| 2306 | " etTCLESCAPE, /* Strings with special characters escaped. %q */\n" |
||
| 2307 | " etMEMSTRING, /* A string which should be deleted after use. %z */\n" |
||
| 2308 | " etORDINAL /* 1st, 2nd, 3rd and so forth */\n" |
||
| 2309 | "};\n" |
||
| 2310 | "\n" |
||
| 2311 | "/*\n" |
||
| 2312 | "** Each builtin conversion character (ex: the 'd' in \"%d\") is described\n" |
||
| 2313 | "** by an instance of the following structure\n" |
||
| 2314 | "*/\n" |
||
| 2315 | "typedef struct et_info { /* Information about each format field */\n" |
||
| 2316 | " int fmttype; /* The format field code letter */\n" |
||
| 2317 | " int base; /* The base for radix conversion */\n" |
||
| 2318 | " char *charset; /* The character set for conversion */\n" |
||
| 2319 | " int flag_signed; /* Is the quantity signed? */\n" |
||
| 2320 | " char *prefix; /* Prefix on non-zero values in alt format */\n" |
||
| 2321 | " enum et_type type; /* Conversion paradigm */\n" |
||
| 2322 | "} et_info;\n" |
||
| 2323 | "\n" |
||
| 2324 | "/*\n" |
||
| 2325 | "** The following table is searched linearly, so it is good to put the\n" |
||
| 2326 | "** most frequently used conversion types first.\n" |
||
| 2327 | "*/\n" |
||
| 2328 | "static et_info fmtinfo[] = {\n" |
||
| 2329 | " { 'd', 10, \"0123456789\", 1, 0, etRADIX, },\n" |
||
| 2330 | " { 's', 0, 0, 0, 0, etSTRING, }, \n" |
||
| 2331 | " { 'q', 0, 0, 0, 0, etTCLESCAPE, },\n" |
||
| 2332 | " { 'z', 0, 0, 0, 0, etMEMSTRING, },\n" |
||
| 2333 | " { 'c', 0, 0, 0, 0, etCHARX, },\n" |
||
| 2334 | " { 'o', 8, \"01234567\", 0, \"0\", etRADIX, },\n" |
||
| 2335 | " { 'u', 10, \"0123456789\", 0, 0, etRADIX, },\n" |
||
| 2336 | " { 'x', 16, \"0123456789abcdef\", 0, \"x0\", etRADIX, },\n" |
||
| 2337 | " { 'X', 16, \"0123456789ABCDEF\", 0, \"X0\", etRADIX, },\n" |
||
| 2338 | " { 'r', 10, \"0123456789\", 0, 0, etORDINAL, },\n" |
||
| 2339 | " { 'f', 0, 0, 1, 0, etFLOAT, },\n" |
||
| 2340 | " { 'e', 0, \"e\", 1, 0, etEXP, },\n" |
||
| 2341 | " { 'E', 0, \"E\", 1, 0, etEXP, },\n" |
||
| 2342 | " { 'g', 0, \"e\", 1, 0, etGENERIC, },\n" |
||
| 2343 | " { 'G', 0, \"E\", 1, 0, etGENERIC, },\n" |
||
| 2344 | " { 'i', 10, \"0123456789\", 1, 0, etRADIX, },\n" |
||
| 2345 | " { 'n', 0, 0, 0, 0, etSIZE, },\n" |
||
| 2346 | " { '%', 0, 0, 0, 0, etPERCENT, },\n" |
||
| 2347 | " { 'b', 2, \"01\", 0, \"b0\", etRADIX, }, /* Binary */\n" |
||
| 2348 | " { 'p', 10, \"0123456789\", 0, 0, etRADIX, }, /* Pointers */\n" |
||
| 2349 | " { '\\'', 0, 0, 0, 0, etCHARLIT, }, /* Literal char */\n" |
||
| 2350 | "};\n" |
||
| 2351 | "#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))\n" |
||
| 2352 | "\n" |
||
| 2353 | "/*\n" |
||
| 2354 | "** If NOFLOATINGPOINT is defined, then none of the floating point\n" |
||
| 2355 | "** conversions will work.\n" |
||
| 2356 | "*/\n" |
||
| 2357 | "#ifndef etNOFLOATINGPOINT\n" |
||
| 2358 | "/*\n" |
||
| 2359 | "** \"*val\" is a double such that 0.1 <= *val < 10.0\n" |
||
| 2360 | "** Return the ascii code for the leading digit of *val, then\n" |
||
| 2361 | "** multiply \"*val\" by 10.0 to renormalize.\n" |
||
| 2362 | "**\n" |
||
| 2363 | "** Example:\n" |
||
| 2364 | "** input: *val = 3.14159\n" |
||
| 2365 | "** output: *val = 1.4159 function return = '3'\n" |
||
| 2366 | "**\n" |
||
| 2367 | "** The counter *cnt is incremented each time. After counter exceeds\n" |
||
| 2368 | "** 16 (the number of significant digits in a 64-bit float) '0' is\n" |
||
| 2369 | "** always returned.\n" |
||
| 2370 | "*/\n" |
||
| 2371 | "static int et_getdigit(double *val, int *cnt){\n" |
||
| 2372 | " int digit;\n" |
||
| 2373 | " double d;\n" |
||
| 2374 | " if( (*cnt)++ >= 16 ) return '0';\n" |
||
| 2375 | " digit = (int)*val;\n" |
||
| 2376 | " d = digit;\n" |
||
| 2377 | " digit += '0';\n" |
||
| 2378 | " *val = (*val - d)*10.0;\n" |
||
| 2379 | " return digit;\n" |
||
| 2380 | "}\n" |
||
| 2381 | "#endif\n" |
||
| 2382 | "\n" |
||
| 2383 | "#define etBUFSIZE 1000 /* Size of the output buffer */\n" |
||
| 2384 | "\n" |
||
| 2385 | "/*\n" |
||
| 2386 | "** The root program. All variations call this core.\n" |
||
| 2387 | "**\n" |
||
| 2388 | "** INPUTS:\n" |
||
| 2389 | "** func This is a pointer to a function taking three arguments\n" |
||
| 2390 | "** 1. A pointer to anything. Same as the \"arg\" parameter.\n" |
||
| 2391 | "** 2. A pointer to the list of characters to be output\n" |
||
| 2392 | "** (Note, this list is NOT null terminated.)\n" |
||
| 2393 | "** 3. An integer number of characters to be output.\n" |
||
| 2394 | "** (Note: This number might be zero.)\n" |
||
| 2395 | "**\n" |
||
| 2396 | "** arg This is the pointer to anything which will be passed as the\n" |
||
| 2397 | "** first argument to \"func\". Use it for whatever you like.\n" |
||
| 2398 | "**\n" |
||
| 2399 | "** fmt This is the format string, as in the usual print.\n" |
||
| 2400 | "**\n" |
||
| 2401 | "** ap This is a pointer to a list of arguments. Same as in\n" |
||
| 2402 | "** vfprint.\n" |
||
| 2403 | "**\n" |
||
| 2404 | "** OUTPUTS:\n" |
||
| 2405 | "** The return value is the total number of characters sent to\n" |
||
| 2406 | "** the function \"func\". Returns -1 on a error.\n" |
||
| 2407 | "**\n" |
||
| 2408 | "** Note that the order in which automatic variables are declared below\n" |
||
| 2409 | "** seems to make a big difference in determining how fast this beast\n" |
||
| 2410 | "** will run.\n" |
||
| 2411 | "*/\n" |
||
| 2412 | "int vxprintf(\n" |
||
| 2413 | " void (*func)(void*,char*,int),\n" |
||
| 2414 | " void *arg,\n" |
||
| 2415 | " const char *format,\n" |
||
| 2416 | " va_list ap\n" |
||
| 2417 | "){\n" |
||
| 2418 | " register const char *fmt; /* The format string. */\n" |
||
| 2419 | " register int c; /* Next character in the format string */\n" |
||
| 2420 | " register char *bufpt; /* Pointer to the conversion buffer */\n" |
||
| 2421 | " register int precision; /* Precision of the current field */\n" |
||
| 2422 | " register int length; /* Length of the field */\n" |
||
| 2423 | " register int idx; /* A general purpose loop counter */\n" |
||
| 2424 | " int count; /* Total number of characters output */\n" |
||
| 2425 | " int width; /* Width of the current field */\n" |
||
| 2426 | " int flag_leftjustify; /* True if \"-\" flag is present */\n" |
||
| 2427 | " int flag_plussign; /* True if \"+\" flag is present */\n" |
||
| 2428 | " int flag_blanksign; /* True if \" \" flag is present */\n" |
||
| 2429 | " int flag_alternateform; /* True if \"#\" flag is present */\n" |
||
| 2430 | " int flag_zeropad; /* True if field width constant starts with zero */\n" |
||
| 2431 | " int flag_long; /* True if \"l\" flag is present */\n" |
||
| 2432 | " int flag_center; /* True if \"=\" flag is present */\n" |
||
| 2433 | " unsigned long longvalue; /* Value for integer types */\n" |
||
| 2434 | " double realvalue; /* Value for real types */\n" |
||
| 2435 | " et_info *infop; /* Pointer to the appropriate info structure */\n" |
||
| 2436 | " char buf[etBUFSIZE]; /* Conversion buffer */\n" |
||
| 2437 | " char prefix; /* Prefix character. \"+\" or \"-\" or \" \" or '\\0'. */\n" |
||
| 2438 | " int errorflag = 0; /* True if an error is encountered */\n" |
||
| 2439 | " enum et_type xtype; /* Conversion paradigm */\n" |
||
| 2440 | " char *zMem; /* String to be freed */\n" |
||
| 2441 | " char *zExtra; /* Extra memory used for etTCLESCAPE conversions */\n" |
||
| 2442 | " static char spaces[] = \" \"\n" |
||
| 2443 | " \" \";\n" |
||
| 2444 | "#define etSPACESIZE (sizeof(spaces)-1)\n" |
||
| 2445 | "#ifndef etNOFLOATINGPOINT\n" |
||
| 2446 | " int exp; /* exponent of real numbers */\n" |
||
| 2447 | " double rounder; /* Used for rounding floating point values */\n" |
||
| 2448 | " int flag_dp; /* True if decimal point should be shown */\n" |
||
| 2449 | " int flag_rtz; /* True if trailing zeros should be removed */\n" |
||
| 2450 | " int flag_exp; /* True to force display of the exponent */\n" |
||
| 2451 | " int nsd; /* Number of significant digits returned */\n" |
||
| 2452 | "#endif\n" |
||
| 2453 | "\n" |
||
| 2454 | " fmt = format; /* Put in a register for speed */\n" |
||
| 2455 | " count = length = 0;\n" |
||
| 2456 | " bufpt = 0;\n" |
||
| 2457 | " for(; (c=(*fmt))!=0; ++fmt){\n" |
||
| 2458 | " if( c!='%' ){\n" |
||
| 2459 | " register int amt;\n" |
||
| 2460 | " bufpt = (char *)fmt;\n" |
||
| 2461 | " amt = 1;\n" |
||
| 2462 | " while( (c=(*++fmt))!='%' && c!=0 ) amt++;\n" |
||
| 2463 | " (*func)(arg,bufpt,amt);\n" |
||
| 2464 | " count += amt;\n" |
||
| 2465 | " if( c==0 ) break;\n" |
||
| 2466 | " }\n" |
||
| 2467 | " if( (c=(*++fmt))==0 ){\n" |
||
| 2468 | " errorflag = 1;\n" |
||
| 2469 | " (*func)(arg,\"%\",1);\n" |
||
| 2470 | " count++;\n" |
||
| 2471 | " break;\n" |
||
| 2472 | " }\n" |
||
| 2473 | " /* Find out what flags are present */\n" |
||
| 2474 | " flag_leftjustify = flag_plussign = flag_blanksign = \n" |
||
| 2475 | " flag_alternateform = flag_zeropad = flag_center = 0;\n" |
||
| 2476 | " do{\n" |
||
| 2477 | " switch( c ){\n" |
||
| 2478 | " case '-': flag_leftjustify = 1; c = 0; break;\n" |
||
| 2479 | " case '+': flag_plussign = 1; c = 0; break;\n" |
||
| 2480 | " case ' ': flag_blanksign = 1; c = 0; break;\n" |
||
| 2481 | " case '#': flag_alternateform = 1; c = 0; break;\n" |
||
| 2482 | " case '0': flag_zeropad = 1; c = 0; break;\n" |
||
| 2483 | " case '=': flag_center = 1; c = 0; break;\n" |
||
| 2484 | " default: break;\n" |
||
| 2485 | " }\n" |
||
| 2486 | " }while( c==0 && (c=(*++fmt))!=0 );\n" |
||
| 2487 | " if( flag_center ) flag_leftjustify = 0;\n" |
||
| 2488 | " /* Get the field width */\n" |
||
| 2489 | " width = 0;\n" |
||
| 2490 | " if( c=='*' ){\n" |
||
| 2491 | " width = va_arg(ap,int);\n" |
||
| 2492 | " if( width<0 ){\n" |
||
| 2493 | " flag_leftjustify = 1;\n" |
||
| 2494 | " width = -width;\n" |
||
| 2495 | " }\n" |
||
| 2496 | " c = *++fmt;\n" |
||
| 2497 | " }else{\n" |
||
| 2498 | " while( isdigit(c) ){\n" |
||
| 2499 | " width = width*10 + c - '0';\n" |
||
| 2500 | " c = *++fmt;\n" |
||
| 2501 | " }\n" |
||
| 2502 | " }\n" |
||
| 2503 | " if( width > etBUFSIZE-10 ){\n" |
||
| 2504 | " width = etBUFSIZE-10;\n" |
||
| 2505 | " }\n" |
||
| 2506 | " /* Get the precision */\n" |
||
| 2507 | " if( c=='.' ){\n" |
||
| 2508 | " precision = 0;\n" |
||
| 2509 | " c = *++fmt;\n" |
||
| 2510 | " if( c=='*' ){\n" |
||
| 2511 | " precision = va_arg(ap,int);\n" |
||
| 2512 | "#ifndef etCOMPATIBILITY\n" |
||
| 2513 | " /* This is sensible, but SUN OS 4.1 doesn't do it. */\n" |
||
| 2514 | " if( precision<0 ) precision = -precision;\n" |
||
| 2515 | "#endif\n" |
||
| 2516 | " c = *++fmt;\n" |
||
| 2517 | " }else{\n" |
||
| 2518 | " while( isdigit(c) ){\n" |
||
| 2519 | " precision = precision*10 + c - '0';\n" |
||
| 2520 | " c = *++fmt;\n" |
||
| 2521 | " }\n" |
||
| 2522 | " }\n" |
||
| 2523 | " /* Limit the precision to prevent overflowing buf[] during conversion */\n" |
||
| 2524 | " if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40;\n" |
||
| 2525 | " }else{\n" |
||
| 2526 | " precision = -1;\n" |
||
| 2527 | " }\n" |
||
| 2528 | " /* Get the conversion type modifier */\n" |
||
| 2529 | " if( c=='l' ){\n" |
||
| 2530 | " flag_long = 1;\n" |
||
| 2531 | " c = *++fmt;\n" |
||
| 2532 | " }else{\n" |
||
| 2533 | " flag_long = 0;\n" |
||
| 2534 | " }\n" |
||
| 2535 | " /* Fetch the info entry for the field */\n" |
||
| 2536 | " infop = 0;\n" |
||
| 2537 | " for(idx=0; idx<etNINFO; idx++){\n" |
||
| 2538 | " if( c==fmtinfo[idx].fmttype ){\n" |
||
| 2539 | " infop = &fmtinfo[idx];\n" |
||
| 2540 | " break;\n" |
||
| 2541 | " }\n" |
||
| 2542 | " }\n" |
||
| 2543 | " /* No info entry found. It must be an error. */\n" |
||
| 2544 | " if( infop==0 ){\n" |
||
| 2545 | " xtype = etERROR;\n" |
||
| 2546 | " }else{\n" |
||
| 2547 | " xtype = infop->type;\n" |
||
| 2548 | " }\n" |
||
| 2549 | " zExtra = 0;\n" |
||
| 2550 | "\n" |
||
| 2551 | " /*\n" |
||
| 2552 | " ** At this point, variables are initialized as follows:\n" |
||
| 2553 | " **\n" |
||
| 2554 | " ** flag_alternateform TRUE if a '#' is present.\n" |
||
| 2555 | " ** flag_plussign TRUE if a '+' is present.\n" |
||
| 2556 | " ** flag_leftjustify TRUE if a '-' is present or if the\n" |
||
| 2557 | " ** field width was negative.\n" |
||
| 2558 | " ** flag_zeropad TRUE if the width began with 0.\n" |
||
| 2559 | " ** flag_long TRUE if the letter 'l' (ell) prefixed\n" |
||
| 2560 | " ** the conversion character.\n" |
||
| 2561 | " ** flag_blanksign TRUE if a ' ' is present.\n" |
||
| 2562 | " ** width The specified field width. This is\n" |
||
| 2563 | " ** always non-negative. Zero is the default.\n" |
||
| 2564 | " ** precision The specified precision. The default\n" |
||
| 2565 | " ** is -1.\n" |
||
| 2566 | " ** xtype The class of the conversion.\n" |
||
| 2567 | " ** infop Pointer to the appropriate info struct.\n" |
||
| 2568 | " */\n" |
||
| 2569 | " switch( xtype ){\n" |
||
| 2570 | " case etORDINAL:\n" |
||
| 2571 | " case etRADIX:\n" |
||
| 2572 | " if( flag_long ) longvalue = va_arg(ap,long);\n" |
||
| 2573 | " else longvalue = va_arg(ap,int);\n" |
||
| 2574 | "#ifdef etCOMPATIBILITY\n" |
||
| 2575 | " /* For the format %#x, the value zero is printed \"0\" not \"0x0\".\n" |
||
| 2576 | " ** I think this is stupid. */\n" |
||
| 2577 | " if( longvalue==0 ) flag_alternateform = 0;\n" |
||
| 2578 | "#else\n" |
||
| 2579 | " /* More sensible: turn off the prefix for octal (to prevent \"00\"),\n" |
||
| 2580 | " ** but leave the prefix for hex. */\n" |
||
| 2581 | " if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;\n" |
||
| 2582 | "#endif\n" |
||
| 2583 | " if( infop->flag_signed ){\n" |
||
| 2584 | " if( *(long*)&longvalue<0 ){\n" |
||
| 2585 | " longvalue = -*(long*)&longvalue;\n" |
||
| 2586 | " prefix = '-';\n" |
||
| 2587 | " }else if( flag_plussign ) prefix = '+';\n" |
||
| 2588 | " else if( flag_blanksign ) prefix = ' ';\n" |
||
| 2589 | " else prefix = 0;\n" |
||
| 2590 | " }else prefix = 0;\n" |
||
| 2591 | " if( flag_zeropad && precision<width-(prefix!=0) ){\n" |
||
| 2592 | " precision = width-(prefix!=0);\n" |
||
| 2593 | " }\n" |
||
| 2594 | " bufpt = &buf[etBUFSIZE];\n" |
||
| 2595 | " if( xtype==etORDINAL ){\n" |
||
| 2596 | " long a,b;\n" |
||
| 2597 | " a = longvalue%10;\n" |
||
| 2598 | " b = longvalue%100;\n" |
||
| 2599 | " bufpt -= 2;\n" |
||
| 2600 | " if( a==0 || a>3 || (b>10 && b<14) ){\n" |
||
| 2601 | " bufpt[0] = 't';\n" |
||
| 2602 | " bufpt[1] = 'h';\n" |
||
| 2603 | " }else if( a==1 ){\n" |
||
| 2604 | " bufpt[0] = 's';\n" |
||
| 2605 | " bufpt[1] = 't';\n" |
||
| 2606 | " }else if( a==2 ){\n" |
||
| 2607 | " bufpt[0] = 'n';\n" |
||
| 2608 | " bufpt[1] = 'd';\n" |
||
| 2609 | " }else if( a==3 ){\n" |
||
| 2610 | " bufpt[0] = 'r';\n" |
||
| 2611 | " bufpt[1] = 'd';\n" |
||
| 2612 | " }\n" |
||
| 2613 | " }\n" |
||
| 2614 | " {\n" |
||
| 2615 | " register char *cset; /* Use registers for speed */\n" |
||
| 2616 | " register int base;\n" |
||
| 2617 | " cset = infop->charset;\n" |
||
| 2618 | " base = infop->base;\n" |
||
| 2619 | " do{ /* Convert to ascii */\n" |
||
| 2620 | " *(--bufpt) = cset[longvalue%base];\n" |
||
| 2621 | " longvalue = longvalue/base;\n" |
||
| 2622 | " }while( longvalue>0 );\n" |
||
| 2623 | " }\n" |
||
| 2624 | " length = (long)&buf[etBUFSIZE]-(long)bufpt;\n" |
||
| 2625 | " for(idx=precision-length; idx>0; idx--){\n" |
||
| 2626 | " *(--bufpt) = '0'; /* Zero pad */\n" |
||
| 2627 | " }\n" |
||
| 2628 | " if( prefix ) *(--bufpt) = prefix; /* Add sign */\n" |
||
| 2629 | " if( flag_alternateform && infop->prefix ){ /* Add \"0\" or \"0x\" */\n" |
||
| 2630 | " char *pre, x;\n" |
||
| 2631 | " pre = infop->prefix;\n" |
||
| 2632 | " if( *bufpt!=pre[0] ){\n" |
||
| 2633 | " for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;\n" |
||
| 2634 | " }\n" |
||
| 2635 | " }\n" |
||
| 2636 | " length = (long)&buf[etBUFSIZE]-(long)bufpt;\n" |
||
| 2637 | " break;\n" |
||
| 2638 | " case etFLOAT:\n" |
||
| 2639 | " case etEXP:\n" |
||
| 2640 | " case etGENERIC:\n" |
||
| 2641 | " realvalue = va_arg(ap,double);\n" |
||
| 2642 | "#ifndef etNOFLOATINGPOINT\n" |
||
| 2643 | " if( precision<0 ) precision = 6; /* Set default precision */\n" |
||
| 2644 | " if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10;\n" |
||
| 2645 | " if( realvalue<0.0 ){\n" |
||
| 2646 | " realvalue = -realvalue;\n" |
||
| 2647 | " prefix = '-';\n" |
||
| 2648 | " }else{\n" |
||
| 2649 | " if( flag_plussign ) prefix = '+';\n" |
||
| 2650 | " else if( flag_blanksign ) prefix = ' ';\n" |
||
| 2651 | " else prefix = 0;\n" |
||
| 2652 | " }\n" |
||
| 2653 | " if( infop->type==etGENERIC && precision>0 ) precision--;\n" |
||
| 2654 | " rounder = 0.0;\n" |
||
| 2655 | "#ifdef COMPATIBILITY\n" |
||
| 2656 | " /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */\n" |
||
| 2657 | " for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);\n" |
||
| 2658 | "#else\n" |
||
| 2659 | " /* It makes more sense to use 0.5 */\n" |
||
| 2660 | " for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);\n" |
||
| 2661 | "#endif\n" |
||
| 2662 | " if( infop->type==etFLOAT ) realvalue += rounder;\n" |
||
| 2663 | " /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */\n" |
||
| 2664 | " exp = 0;\n" |
||
| 2665 | " if( realvalue>0.0 ){\n" |
||
| 2666 | " int k = 0;\n" |
||
| 2667 | " while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; }\n" |
||
| 2668 | " while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; }\n" |
||
| 2669 | " while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; }\n" |
||
| 2670 | " while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; }\n" |
||
| 2671 | " if( k>=100 ){\n" |
||
| 2672 | " bufpt = \"NaN\";\n" |
||
| 2673 | " length = 3;\n" |
||
| 2674 | " break;\n" |
||
| 2675 | " }\n" |
||
| 2676 | " }\n" |
||
| 2677 | " bufpt = buf;\n" |
||
| 2678 | " /*\n" |
||
| 2679 | " ** If the field type is etGENERIC, then convert to either etEXP\n" |
||
| 2680 | " ** or etFLOAT, as appropriate.\n" |
||
| 2681 | " */\n" |
||
| 2682 | " flag_exp = xtype==etEXP;\n" |
||
| 2683 | " if( xtype!=etFLOAT ){\n" |
||
| 2684 | " realvalue += rounder;\n" |
||
| 2685 | " if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }\n" |
||
| 2686 | " }\n" |
||
| 2687 | " if( xtype==etGENERIC ){\n" |
||
| 2688 | " flag_rtz = !flag_alternateform;\n" |
||
| 2689 | " if( exp<-4 || exp>precision ){\n" |
||
| 2690 | " xtype = etEXP;\n" |
||
| 2691 | " }else{\n" |
||
| 2692 | " precision = precision - exp;\n" |
||
| 2693 | " xtype = etFLOAT;\n" |
||
| 2694 | " }\n" |
||
| 2695 | " }else{\n" |
||
| 2696 | " flag_rtz = 0;\n" |
||
| 2697 | " }\n" |
||
| 2698 | " /*\n" |
||
| 2699 | " ** The \"exp+precision\" test causes output to be of type etEXP if\n" |
||
| 2700 | " ** the precision is too large to fit in buf[].\n" |
||
| 2701 | " */\n" |
||
| 2702 | " nsd = 0;\n" |
||
| 2703 | " if( xtype==etFLOAT && exp+precision<etBUFSIZE-30 ){\n" |
||
| 2704 | " flag_dp = (precision>0 || flag_alternateform);\n" |
||
| 2705 | " if( prefix ) *(bufpt++) = prefix; /* Sign */\n" |
||
| 2706 | " if( exp<0 ) *(bufpt++) = '0'; /* Digits before \".\" */\n" |
||
| 2707 | " else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd);\n" |
||
| 2708 | " if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */\n" |
||
| 2709 | " for(exp++; exp<0 && precision>0; precision--, exp++){\n" |
||
| 2710 | " *(bufpt++) = '0';\n" |
||
| 2711 | " }\n" |
||
| 2712 | " while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);\n" |
||
| 2713 | " *(bufpt--) = 0; /* Null terminate */\n" |
||
| 2714 | " if( flag_rtz && flag_dp ){ /* Remove trailing zeros and \".\" */\n" |
||
| 2715 | " while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;\n" |
||
| 2716 | " if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;\n" |
||
| 2717 | " }\n" |
||
| 2718 | " bufpt++; /* point to next free slot */\n" |
||
| 2719 | " }else{ /* etEXP or etGENERIC */\n" |
||
| 2720 | " flag_dp = (precision>0 || flag_alternateform);\n" |
||
| 2721 | " if( prefix ) *(bufpt++) = prefix; /* Sign */\n" |
||
| 2722 | " *(bufpt++) = et_getdigit(&realvalue,&nsd); /* First digit */\n" |
||
| 2723 | " if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */\n" |
||
| 2724 | " while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);\n" |
||
| 2725 | " bufpt--; /* point to last digit */\n" |
||
| 2726 | " if( flag_rtz && flag_dp ){ /* Remove tail zeros */\n" |
||
| 2727 | " while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;\n" |
||
| 2728 | " if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;\n" |
||
| 2729 | " }\n" |
||
| 2730 | " bufpt++; /* point to next free slot */\n" |
||
| 2731 | " if( exp || flag_exp ){\n" |
||
| 2732 | " *(bufpt++) = infop->charset[0];\n" |
||
| 2733 | " if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */\n" |
||
| 2734 | " else { *(bufpt++) = '+'; }\n" |
||
| 2735 | " if( exp>=100 ){\n" |
||
| 2736 | " *(bufpt++) = (exp/100)+'0'; /* 100's digit */\n" |
||
| 2737 | " exp %= 100;\n" |
||
| 2738 | " }\n" |
||
| 2739 | " *(bufpt++) = exp/10+'0'; /* 10's digit */\n" |
||
| 2740 | " *(bufpt++) = exp%10+'0'; /* 1's digit */\n" |
||
| 2741 | " }\n" |
||
| 2742 | " }\n" |
||
| 2743 | " /* The converted number is in buf[] and zero terminated. Output it.\n" |
||
| 2744 | " ** Note that the number is in the usual order, not reversed as with\n" |
||
| 2745 | " ** integer conversions. */\n" |
||
| 2746 | " length = (long)bufpt-(long)buf;\n" |
||
| 2747 | " bufpt = buf;\n" |
||
| 2748 | "\n" |
||
| 2749 | " /* Special case: Add leading zeros if the flag_zeropad flag is\n" |
||
| 2750 | " ** set and we are not left justified */\n" |
||
| 2751 | " if( flag_zeropad && !flag_leftjustify && length < width){\n" |
||
| 2752 | " int i;\n" |
||
| 2753 | " int nPad = width - length;\n" |
||
| 2754 | " for(i=width; i>=nPad; i--){\n" |
||
| 2755 | " bufpt[i] = bufpt[i-nPad];\n" |
||
| 2756 | " }\n" |
||
| 2757 | " i = prefix!=0;\n" |
||
| 2758 | " while( nPad-- ) bufpt[i++] = '0';\n" |
||
| 2759 | " length = width;\n" |
||
| 2760 | " }\n" |
||
| 2761 | "#endif\n" |
||
| 2762 | " break;\n" |
||
| 2763 | " case etSIZE:\n" |
||
| 2764 | " *(va_arg(ap,int*)) = count;\n" |
||
| 2765 | " length = width = 0;\n" |
||
| 2766 | " break;\n" |
||
| 2767 | " case etPERCENT:\n" |
||
| 2768 | " buf[0] = '%';\n" |
||
| 2769 | " bufpt = buf;\n" |
||
| 2770 | " length = 1;\n" |
||
| 2771 | " break;\n" |
||
| 2772 | " case etCHARLIT:\n" |
||
| 2773 | " case etCHARX:\n" |
||
| 2774 | " c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);\n" |
||
| 2775 | " if( precision>=0 ){\n" |
||
| 2776 | " for(idx=1; idx<precision; idx++) buf[idx] = c;\n" |
||
| 2777 | " length = precision;\n" |
||
| 2778 | " }else{\n" |
||
| 2779 | " length =1;\n" |
||
| 2780 | " }\n" |
||
| 2781 | " bufpt = buf;\n" |
||
| 2782 | " break;\n" |
||
| 2783 | " case etSTRING:\n" |
||
| 2784 | " case etMEMSTRING:\n" |
||
| 2785 | " zMem = bufpt = va_arg(ap,char*);\n" |
||
| 2786 | " if( bufpt==0 ) bufpt = \"(null)\";\n" |
||
| 2787 | " length = strlen(bufpt);\n" |
||
| 2788 | " if( precision>=0 && precision<length ) length = precision;\n" |
||
| 2789 | " break;\n" |
||
| 2790 | " case etTCLESCAPE:\n" |
||
| 2791 | " {\n" |
||
| 2792 | " int i, j, n, c, k;\n" |
||
| 2793 | " char *arg = va_arg(ap,char*);\n" |
||
| 2794 | " if( arg==0 ) arg = \"(NULL)\";\n" |
||
| 2795 | " for(i=n=0; (c=arg[i])!=0; i++){\n" |
||
| 2796 | " k = NeedEsc[c&0xff];\n" |
||
| 2797 | " if( k==0 ){\n" |
||
| 2798 | " n++;\n" |
||
| 2799 | " }else if( k==1 ){\n" |
||
| 2800 | " n+=4;\n" |
||
| 2801 | " }else{\n" |
||
| 2802 | " n+=2;\n" |
||
| 2803 | " }\n" |
||
| 2804 | " }\n" |
||
| 2805 | " n++;\n" |
||
| 2806 | " if( n>etBUFSIZE ){\n" |
||
| 2807 | " bufpt = zExtra = Tcl_Alloc( n );\n" |
||
| 2808 | " }else{\n" |
||
| 2809 | " bufpt = buf;\n" |
||
| 2810 | " }\n" |
||
| 2811 | " for(i=j=0; (c=arg[i])!=0; i++){\n" |
||
| 2812 | " k = NeedEsc[c&0xff];\n" |
||
| 2813 | " if( k==0 ){\n" |
||
| 2814 | " bufpt[j++] = c;\n" |
||
| 2815 | " }else if( k==1 ){\n" |
||
| 2816 | " bufpt[j++] = '\\\\';\n" |
||
| 2817 | " bufpt[j++] = ((c>>6) & 3) + '0';\n" |
||
| 2818 | " bufpt[j++] = ((c>>3) & 7) + '0';\n" |
||
| 2819 | " bufpt[j++] = (c & 7) + '0';\n" |
||
| 2820 | " }else{\n" |
||
| 2821 | " bufpt[j++] = '\\\\';\n" |
||
| 2822 | " bufpt[j++] = k;\n" |
||
| 2823 | " }\n" |
||
| 2824 | " }\n" |
||
| 2825 | " bufpt[j] = 0;\n" |
||
| 2826 | " length = j;\n" |
||
| 2827 | " if( precision>=0 && precision<length ) length = precision;\n" |
||
| 2828 | " }\n" |
||
| 2829 | " break;\n" |
||
| 2830 | " case etERROR:\n" |
||
| 2831 | " buf[0] = '%';\n" |
||
| 2832 | " buf[1] = c;\n" |
||
| 2833 | " errorflag = 0;\n" |
||
| 2834 | " idx = 1+(c!=0);\n" |
||
| 2835 | " (*func)(arg,\"%\",idx);\n" |
||
| 2836 | " count += idx;\n" |
||
| 2837 | " if( c==0 ) fmt--;\n" |
||
| 2838 | " break;\n" |
||
| 2839 | " }/* End switch over the format type */\n" |
||
| 2840 | " /*\n" |
||
| 2841 | " ** The text of the conversion is pointed to by \"bufpt\" and is\n" |
||
| 2842 | " ** \"length\" characters long. The field width is \"width\". Do\n" |
||
| 2843 | " ** the output.\n" |
||
| 2844 | " */\n" |
||
| 2845 | " if( !flag_leftjustify ){\n" |
||
| 2846 | " register int nspace;\n" |
||
| 2847 | " nspace = width-length;\n" |
||
| 2848 | " if( nspace>0 ){\n" |
||
| 2849 | " if( flag_center ){\n" |
||
| 2850 | " nspace = nspace/2;\n" |
||
| 2851 | " width -= nspace;\n" |
||
| 2852 | " flag_leftjustify = 1;\n" |
||
| 2853 | " }\n" |
||
| 2854 | " count += nspace;\n" |
||
| 2855 | " while( nspace>=etSPACESIZE ){\n" |
||
| 2856 | " (*func)(arg,spaces,etSPACESIZE);\n" |
||
| 2857 | " nspace -= etSPACESIZE;\n" |
||
| 2858 | " }\n" |
||
| 2859 | " if( nspace>0 ) (*func)(arg,spaces,nspace);\n" |
||
| 2860 | " }\n" |
||
| 2861 | " }\n" |
||
| 2862 | " if( length>0 ){\n" |
||
| 2863 | " (*func)(arg,bufpt,length);\n" |
||
| 2864 | " count += length;\n" |
||
| 2865 | " }\n" |
||
| 2866 | " if( xtype==etMEMSTRING && zMem ){\n" |
||
| 2867 | " Tcl_Free(zMem);\n" |
||
| 2868 | " }\n" |
||
| 2869 | " if( flag_leftjustify ){\n" |
||
| 2870 | " register int nspace;\n" |
||
| 2871 | " nspace = width-length;\n" |
||
| 2872 | " if( nspace>0 ){\n" |
||
| 2873 | " count += nspace;\n" |
||
| 2874 | " while( nspace>=etSPACESIZE ){\n" |
||
| 2875 | " (*func)(arg,spaces,etSPACESIZE);\n" |
||
| 2876 | " nspace -= etSPACESIZE;\n" |
||
| 2877 | " }\n" |
||
| 2878 | " if( nspace>0 ) (*func)(arg,spaces,nspace);\n" |
||
| 2879 | " }\n" |
||
| 2880 | " }\n" |
||
| 2881 | " if( zExtra ){\n" |
||
| 2882 | " Tcl_Free(zExtra);\n" |
||
| 2883 | " }\n" |
||
| 2884 | " }/* End for loop over the format string */\n" |
||
| 2885 | " return errorflag ? -1 : count;\n" |
||
| 2886 | "} /* End of function */\n" |
||
| 2887 | "\n" |
||
| 2888 | "/*\n" |
||
| 2889 | "** The following section of code handles the mprintf routine, that\n" |
||
| 2890 | "** writes to memory obtained from malloc().\n" |
||
| 2891 | "*/\n" |
||
| 2892 | "\n" |
||
| 2893 | "/* This structure is used to store state information about the\n" |
||
| 2894 | "** write to memory that is currently in progress.\n" |
||
| 2895 | "*/\n" |
||
| 2896 | "struct sgMprintf {\n" |
||
| 2897 | " char *zBase; /* A base allocation */\n" |
||
| 2898 | " char *zText; /* The string collected so far */\n" |
||
| 2899 | " int nChar; /* Length of the string so far */\n" |
||
| 2900 | " int nAlloc; /* Amount of space allocated in zText */\n" |
||
| 2901 | "};\n" |
||
| 2902 | "\n" |
||
| 2903 | "/* \n" |
||
| 2904 | "** The xprintf callback function. \n" |
||
| 2905 | "**\n" |
||
| 2906 | "** This routine add nNewChar characters of text in zNewText to\n" |
||
| 2907 | "** the sgMprintf structure pointed to by \"arg\".\n" |
||
| 2908 | "*/\n" |
||
| 2909 | "static void mout(void *arg, char *zNewText, int nNewChar){\n" |
||
| 2910 | " struct sgMprintf *pM = (struct sgMprintf*)arg;\n" |
||
| 2911 | " if( pM->nChar + nNewChar + 1 > pM->nAlloc ){\n" |
||
| 2912 | " pM->nAlloc = pM->nChar + nNewChar*2 + 1;\n" |
||
| 2913 | " if( pM->zText==pM->zBase ){\n" |
||
| 2914 | " pM->zText = Tcl_Alloc(pM->nAlloc);\n" |
||
| 2915 | " if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar);\n" |
||
| 2916 | " }else{\n" |
||
| 2917 | " pM->zText = Tcl_Realloc(pM->zText, pM->nAlloc);\n" |
||
| 2918 | " }\n" |
||
| 2919 | " }\n" |
||
| 2920 | " if( pM->zText ){\n" |
||
| 2921 | " memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);\n" |
||
| 2922 | " pM->nChar += nNewChar;\n" |
||
| 2923 | " pM->zText[pM->nChar] = 0;\n" |
||
| 2924 | " }\n" |
||
| 2925 | "}\n" |
||
| 2926 | "\n" |
||
| 2927 | "/*\n" |
||
| 2928 | "** mprintf() works like printf(), but allocations memory to hold the\n" |
||
| 2929 | "** resulting string and returns a pointer to the allocated memory.\n" |
||
| 2930 | "*/\n" |
||
| 2931 | "char *mprintf(const char *zFormat, ...){\n" |
||
| 2932 | " va_list ap;\n" |
||
| 2933 | " struct sgMprintf sMprintf;\n" |
||
| 2934 | " char *zNew;\n" |
||
| 2935 | " char zBuf[200];\n" |
||
| 2936 | "\n" |
||
| 2937 | " sMprintf.nChar = 0;\n" |
||
| 2938 | " sMprintf.nAlloc = sizeof(zBuf);\n" |
||
| 2939 | " sMprintf.zText = zBuf;\n" |
||
| 2940 | " sMprintf.zBase = zBuf;\n" |
||
| 2941 | " va_start(ap,zFormat);\n" |
||
| 2942 | " vxprintf(mout,&sMprintf,zFormat,ap);\n" |
||
| 2943 | " va_end(ap);\n" |
||
| 2944 | " sMprintf.zText[sMprintf.nChar] = 0;\n" |
||
| 2945 | " if( sMprintf.zText==sMprintf.zBase ){\n" |
||
| 2946 | " zNew = Tcl_Alloc( sMprintf.nChar+1 );\n" |
||
| 2947 | " if( zNew ) strcpy(zNew,zBuf);\n" |
||
| 2948 | " }else{\n" |
||
| 2949 | " zNew = Tcl_Realloc(sMprintf.zText,sMprintf.nChar+1);\n" |
||
| 2950 | " }\n" |
||
| 2951 | " return zNew;\n" |
||
| 2952 | "}\n" |
||
| 2953 | "\n" |
||
| 2954 | "/* This is the varargs version of mprintf. \n" |
||
| 2955 | "*/\n" |
||
| 2956 | "char *vmprintf(const char *zFormat, va_list ap){\n" |
||
| 2957 | " struct sgMprintf sMprintf;\n" |
||
| 2958 | " char zBuf[200];\n" |
||
| 2959 | " sMprintf.nChar = 0;\n" |
||
| 2960 | " sMprintf.zText = zBuf;\n" |
||
| 2961 | " sMprintf.nAlloc = sizeof(zBuf);\n" |
||
| 2962 | " sMprintf.zBase = zBuf;\n" |
||
| 2963 | " vxprintf(mout,&sMprintf,zFormat,ap);\n" |
||
| 2964 | " sMprintf.zText[sMprintf.nChar] = 0;\n" |
||
| 2965 | " if( sMprintf.zText==sMprintf.zBase ){\n" |
||
| 2966 | " sMprintf.zText = Tcl_Alloc( strlen(zBuf)+1 );\n" |
||
| 2967 | " if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf);\n" |
||
| 2968 | " }else{\n" |
||
| 2969 | " sMprintf.zText = Tcl_Realloc(sMprintf.zText,sMprintf.nChar+1);\n" |
||
| 2970 | " }\n" |
||
| 2971 | " return sMprintf.zText;\n" |
||
| 2972 | "}\n" |
||
| 2973 | "\n" |
||
| 2974 | "/*\n" |
||
| 2975 | "** Add text output to a Tcl_DString.\n" |
||
| 2976 | "**\n" |
||
| 2977 | "** This routine is called by vxprintf(). It's job is to add\n" |
||
| 2978 | "** nNewChar characters of text from zNewText to the Tcl_DString\n" |
||
| 2979 | "** that \"arg\" is pointing to.\n" |
||
| 2980 | "*/\n" |
||
| 2981 | "static void dstringout(void *arg, char *zNewText, int nNewChar){\n" |
||
| 2982 | " Tcl_DString *str = (Tcl_DString*)arg;\n" |
||
| 2983 | " Tcl_DStringAppend(str,zNewText,nNewChar);\n" |
||
| 2984 | "}\n" |
||
| 2985 | "\n" |
||
| 2986 | "/*\n" |
||
| 2987 | "** Append formatted output to a DString.\n" |
||
| 2988 | "*/\n" |
||
| 2989 | "char *Et_DStringAppendF(Tcl_DString *str, const char *zFormat, ...){\n" |
||
| 2990 | " va_list ap;\n" |
||
| 2991 | " va_start(ap,zFormat);\n" |
||
| 2992 | " vxprintf(dstringout,str,zFormat,ap);\n" |
||
| 2993 | " va_end(ap);\n" |
||
| 2994 | " return Tcl_DStringValue(str);\n" |
||
| 2995 | "}\n" |
||
| 2996 | "\n" |
||
| 2997 | "/*\n" |
||
| 2998 | "** Make this variable true to trace all calls to EvalF\n" |
||
| 2999 | "*/\n" |
||
| 3000 | "int Et_EvalTrace = 0;\n" |
||
| 3001 | "\n" |
||
| 3002 | "/*\n" |
||
| 3003 | "** Eval the results of a string.\n" |
||
| 3004 | "*/\n" |
||
| 3005 | "int Et_EvalF(Tcl_Interp *interp, const char *zFormat, ...){\n" |
||
| 3006 | " char *zCmd;\n" |
||
| 3007 | " va_list ap;\n" |
||
| 3008 | " int result;\n" |
||
| 3009 | " va_start(ap,zFormat);\n" |
||
| 3010 | " zCmd = vmprintf(zFormat,ap);\n" |
||
| 3011 | " if( Et_EvalTrace ) printf(\"%s\\n\",zCmd);\n" |
||
| 3012 | " result = Tcl_Eval(interp,zCmd);\n" |
||
| 3013 | " if( Et_EvalTrace ) printf(\"%d %s\\n\",result,interp->result);\n" |
||
| 3014 | " Tcl_Free(zCmd);\n" |
||
| 3015 | " return result;\n" |
||
| 3016 | "}\n" |
||
| 3017 | "int Et_GlobalEvalF(Tcl_Interp *interp, const char *zFormat, ...){\n" |
||
| 3018 | " char *zCmd;\n" |
||
| 3019 | " va_list ap;\n" |
||
| 3020 | " int result;\n" |
||
| 3021 | " va_start(ap,zFormat);\n" |
||
| 3022 | " zCmd = vmprintf(zFormat,ap);\n" |
||
| 3023 | " if( Et_EvalTrace ) printf(\"%s\\n\",zCmd);\n" |
||
| 3024 | " result = Tcl_GlobalEval(interp,zCmd);\n" |
||
| 3025 | " if( Et_EvalTrace ) printf(\"%d %s\\n\",result,interp->result);\n" |
||
| 3026 | " Tcl_Free(zCmd);\n" |
||
| 3027 | " return result;\n" |
||
| 3028 | "}\n" |
||
| 3029 | "\n" |
||
| 3030 | "/*\n" |
||
| 3031 | "** Set the result of an interpreter using printf-like arguments.\n" |
||
| 3032 | "*/\n" |
||
| 3033 | "void Et_ResultF(Tcl_Interp *interp, const char *zFormat, ...){\n" |
||
| 3034 | " Tcl_DString str;\n" |
||
| 3035 | " va_list ap;\n" |
||
| 3036 | "\n" |
||
| 3037 | " Tcl_DStringInit(&str);\n" |
||
| 3038 | " va_start(ap,zFormat);\n" |
||
| 3039 | " vxprintf(dstringout,&str,zFormat,ap);\n" |
||
| 3040 | " va_end(ap);\n" |
||
| 3041 | " Tcl_DStringResult(interp,&str); \n" |
||
| 3042 | "}\n" |
||
| 3043 | "\n" |
||
| 3044 | "#if ET_HAVE_OBJ\n" |
||
| 3045 | "/*\n" |
||
| 3046 | "** Append text to a string object.\n" |
||
| 3047 | "*/\n" |
||
| 3048 | "int Et_AppendObjF(Tcl_Obj *pObj, const char *zFormat, ...){\n" |
||
| 3049 | " va_list ap;\n" |
||
| 3050 | " int rc;\n" |
||
| 3051 | "\n" |
||
| 3052 | " va_start(ap,zFormat);\n" |
||
| 3053 | " rc = vxprintf((void(*)(void*,char*,int))Tcl_AppendToObj, pObj, zFormat, ap);\n" |
||
| 3054 | " va_end(ap);\n" |
||
| 3055 | " return rc;\n" |
||
| 3056 | "}\n" |
||
| 3057 | "#endif\n" |
||
| 3058 | "\n" |
||
| 3059 | "\n" |
||
| 3060 | "#if ET_WIN32\n" |
||
| 3061 | "/*\n" |
||
| 3062 | "** This array translates all characters into themselves. Except\n" |
||
| 3063 | "** for the \\ which gets translated into /. And all upper-case\n" |
||
| 3064 | "** characters are translated into lower case. This is used for\n" |
||
| 3065 | "** hashing and comparing filenames, to work around the Windows\n" |
||
| 3066 | "** bug of ignoring filename case and using the wrong separator\n" |
||
| 3067 | "** character for directories.\n" |
||
| 3068 | "**\n" |
||
| 3069 | "** The array is initialized by FilenameHashInit().\n" |
||
| 3070 | "**\n" |
||
| 3071 | "** We also define a macro ET_TRANS() that actually does\n" |
||
| 3072 | "** the character translation. ET_TRANS() is a no-op under\n" |
||
| 3073 | "** unix.\n" |
||
| 3074 | "*/\n" |
||
| 3075 | "static char charTrans[256];\n" |
||
| 3076 | "#define ET_TRANS(X) (charTrans[0xff&(int)(X)])\n" |
||
| 3077 | "#else\n" |
||
| 3078 | "#define ET_TRANS(X) (X)\n" |
||
| 3079 | "#endif\n" |
||
| 3080 | "\n" |
||
| 3081 | "/*\n" |
||
| 3082 | "** Hash a filename. The value returned is appropriate for\n" |
||
| 3083 | "** indexing into the Et_FileHashTable[] array.\n" |
||
| 3084 | "*/\n" |
||
| 3085 | "static int FilenameHash(char *zName){\n" |
||
| 3086 | " int h = 0;\n" |
||
| 3087 | " while( *zName ){\n" |
||
| 3088 | " h = h ^ (h<<5) ^ ET_TRANS(*(zName++));\n" |
||
| 3089 | " }\n" |
||
| 3090 | " if( h<0 ) h = -h;\n" |
||
| 3091 | " return h % (sizeof(Et_FileHashTable)/sizeof(Et_FileHashTable[0]));\n" |
||
| 3092 | "}\n" |
||
| 3093 | "\n" |
||
| 3094 | "/*\n" |
||
| 3095 | "** Compare two filenames. Return 0 if they are the same and\n" |
||
| 3096 | "** non-zero if they are different.\n" |
||
| 3097 | "*/\n" |
||
| 3098 | "static int FilenameCmp(char *z1, char *z2){\n" |
||
| 3099 | " int diff;\n" |
||
| 3100 | " while( (diff = ET_TRANS(*z1)-ET_TRANS(*z2))==0 && *z1!=0){\n" |
||
| 3101 | " z1++;\n" |
||
| 3102 | " z2++;\n" |
||
| 3103 | " }\n" |
||
| 3104 | " return diff;\n" |
||
| 3105 | "}\n" |
||
| 3106 | "\n" |
||
| 3107 | "/*\n" |
||
| 3108 | "** Initialize the file hash table\n" |
||
| 3109 | "*/\n" |
||
| 3110 | "static void FilenameHashInit(void){\n" |
||
| 3111 | " int i;\n" |
||
| 3112 | "#if ET_WIN32\n" |
||
| 3113 | " for(i=0; i<sizeof(charTrans); i++){\n" |
||
| 3114 | " charTrans[i] = i;\n" |
||
| 3115 | " }\n" |
||
| 3116 | " for(i='A'; i<='Z'; i++){\n" |
||
| 3117 | " charTrans[i] = i + 'a' - 'A';\n" |
||
| 3118 | " }\n" |
||
| 3119 | " charTrans['\\\\'] = '/';\n" |
||
| 3120 | "#endif\n" |
||
| 3121 | " for(i=0; i<sizeof(Et_FileSet)/sizeof(Et_FileSet[0]) - 1; i++){\n" |
||
| 3122 | " struct EtFile *p;\n" |
||
| 3123 | " int h;\n" |
||
| 3124 | " p = &Et_FileSet[i];\n" |
||
| 3125 | " h = FilenameHash(p->zName);\n" |
||
| 3126 | " p->pNext = Et_FileHashTable[h];\n" |
||
| 3127 | " Et_FileHashTable[h] = p;\n" |
||
| 3128 | " }\n" |
||
| 3129 | "}\n" |
||
| 3130 | "\n" |
||
| 3131 | "/*\n" |
||
| 3132 | "** Locate the text of a built-in file given its name. \n" |
||
| 3133 | "** Return 0 if not found. Return this size of the file (not\n" |
||
| 3134 | "** counting the null-terminator) in *pSize if pSize!=NULL.\n" |
||
| 3135 | "**\n" |
||
| 3136 | "** If deshroud==1 and the file is shrouded, then descramble\n" |
||
| 3137 | "** the text.\n" |
||
| 3138 | "*/\n" |
||
| 3139 | "static char *FindBuiltinFile(char *zName, int deshroud, int *pSize){\n" |
||
| 3140 | " int h;\n" |
||
| 3141 | " struct EtFile *p;\n" |
||
| 3142 | "\n" |
||
| 3143 | " h = FilenameHash(zName);\n" |
||
| 3144 | " p = Et_FileHashTable[h];\n" |
||
| 3145 | " while( p && FilenameCmp(p->zName,zName)!=0 ){ p = p->pNext; }\n" |
||
| 3146 | "#if ET_SHROUD_KEY>0\n" |
||
| 3147 | " if( p && p->shrouded && deshroud ){\n" |
||
| 3148 | " char *z;\n" |
||
| 3149 | " int xor = ET_SHROUD_KEY;\n" |
||
| 3150 | " for(z=p->zData; *z; z++){\n" |
||
| 3151 | " if( *z>=0x20 ){ *z ^= xor; xor = (xor+1)&0x1f; }\n" |
||
| 3152 | " }\n" |
||
| 3153 | " p->shrouded = 0;\n" |
||
| 3154 | " }\n" |
||
| 3155 | "#endif\n" |
||
| 3156 | " if( p && pSize ){\n" |
||
| 3157 | " *pSize = p->nData;\n" |
||
| 3158 | " }\n" |
||
| 3159 | " return p ? p->zData : 0;\n" |
||
| 3160 | "}\n" |
||
| 3161 | "\n" |
||
| 3162 | "/*\n" |
||
| 3163 | "** Add a new file to the list of built-in files.\n" |
||
| 3164 | "**\n" |
||
| 3165 | "** This routine makes a copy of zFilename. But it does NOT make\n" |
||
| 3166 | "** a copy of zData. It just holds a pointer to zData and uses\n" |
||
| 3167 | "** that for all file access. So after calling this routine,\n" |
||
| 3168 | "** you should never change zData!\n" |
||
| 3169 | "*/\n" |
||
| 3170 | "void Et_NewBuiltinFile(\n" |
||
| 3171 | " char *zFilename, /* Name of the new file */\n" |
||
| 3172 | " char *zData, /* Data for the new file */\n" |
||
| 3173 | " int nData /* Number of bytes in the new file */\n" |
||
| 3174 | "){\n" |
||
| 3175 | " int h;\n" |
||
| 3176 | " struct EtFile *p;\n" |
||
| 3177 | "\n" |
||
| 3178 | " p = (struct EtFile*)Tcl_Alloc( sizeof(struct EtFile) + strlen(zFilename) + 1);\n" |
||
| 3179 | " if( p==0 ) return;\n" |
||
| 3180 | " p->zName = (char*)&p[1];\n" |
||
| 3181 | " strcpy(p->zName, zFilename);\n" |
||
| 3182 | " p->zData = zData;\n" |
||
| 3183 | " p->nData = nData;\n" |
||
| 3184 | " p->shrouded = 0;\n" |
||
| 3185 | " h = FilenameHash(zFilename);\n" |
||
| 3186 | " p->pNext = Et_FileHashTable[h];\n" |
||
| 3187 | " Et_FileHashTable[h] = p;\n" |
||
| 3188 | "}\n" |
||
| 3189 | "\n" |
||
| 3190 | "/*\n" |
||
| 3191 | "** A TCL interface to the Et_NewBuiltinFile function. For Tcl8.0\n" |
||
| 3192 | "** and later, we make this an Obj command so that it can deal with\n" |
||
| 3193 | "** binary data.\n" |
||
| 3194 | "*/\n" |
||
| 3195 | "#if ET_HAVE_OBJ\n" |
||
| 3196 | "static int Et_NewBuiltinFileCmd(ET_OBJARGS){\n" |
||
| 3197 | " char *zData, *zNew;\n" |
||
| 3198 | " int nData;\n" |
||
| 3199 | " if( objc!=3 ){\n" |
||
| 3200 | " Tcl_WrongNumArgs(interp, 1, objv, \"filename data\");\n" |
||
| 3201 | " return TCL_ERROR;\n" |
||
| 3202 | " }\n" |
||
| 3203 | " zData = (char*)Tcl_GetByteArrayFromObj(objv[2], &nData);\n" |
||
| 3204 | " zNew = Tcl_Alloc( nData + 1 );\n" |
||
| 3205 | " if( zNew ){\n" |
||
| 3206 | " memcpy(zNew, zData, nData);\n" |
||
| 3207 | " zNew[nData] = 0;\n" |
||
| 3208 | " Et_NewBuiltinFile(Tcl_GetStringFromObj(objv[1], 0), zNew, nData);\n" |
||
| 3209 | " }\n" |
||
| 3210 | " return TCL_OK;\n" |
||
| 3211 | "}\n" |
||
| 3212 | "#else\n" |
||
| 3213 | "static int Et_NewBuiltinFileCmd(ET_TCLARGS){\n" |
||
| 3214 | " char *zData;\n" |
||
| 3215 | " int nData;\n" |
||
| 3216 | " if( argc!=3 ){\n" |
||
| 3217 | " Et_ResultF(interp,\"wrong # args: should be \\\"%s FILENAME DATA\\\"\", argv[0]);\n" |
||
| 3218 | " return TCL_ERROR;\n" |
||
| 3219 | " }\n" |
||
| 3220 | " nData = strlen(argv[2]) + 1;\n" |
||
| 3221 | " zData = Tcl_Alloc( nData );\n" |
||
| 3222 | " if( zData ){\n" |
||
| 3223 | " strcpy(zData, argv[2]);\n" |
||
| 3224 | " Et_NewBuiltinFile(argv[1], zData, nData);\n" |
||
| 3225 | " }\n" |
||
| 3226 | " return TCL_OK;\n" |
||
| 3227 | "}\n" |
||
| 3228 | "#endif\n" |
||
| 3229 | "\n" |
||
| 3230 | "/*\n" |
||
| 3231 | "** The following section implements the InsertProc functionality. The\n" |
||
| 3232 | "** new InsertProc feature of Tcl8.0.3 and later allows us to overload\n" |
||
| 3233 | "** the usual system call commands for file I/O and replace them with\n" |
||
| 3234 | "** commands that operate on the built-in files.\n" |
||
| 3235 | "*/\n" |
||
| 3236 | "#ifdef ET_HAVE_INSERTPROC\n" |
||
| 3237 | "\n" |
||
| 3238 | "/* \n" |
||
| 3239 | "** Each open channel to a built-in file is an instance of the\n" |
||
| 3240 | "** following structure.\n" |
||
| 3241 | "*/\n" |
||
| 3242 | "typedef struct Et_FileStruct {\n" |
||
| 3243 | " char *zData; /* All of the data */\n" |
||
| 3244 | " int nData; /* Bytes of data, not counting the null terminator */\n" |
||
| 3245 | " int cursor; /* How much of the data has been read so far */\n" |
||
| 3246 | "} Et_FileStruct;\n" |
||
| 3247 | "\n" |
||
| 3248 | "/*\n" |
||
| 3249 | "** Close a previously opened built-in file.\n" |
||
| 3250 | "*/\n" |
||
| 3251 | "static int Et_FileClose(ClientData instanceData, Tcl_Interp *interp){\n" |
||
| 3252 | " Et_FileStruct *p = (Et_FileStruct*)instanceData;\n" |
||
| 3253 | " Tcl_Free((char*)p);\n" |
||
| 3254 | " return 0;\n" |
||
| 3255 | "}\n" |
||
| 3256 | "\n" |
||
| 3257 | "/*\n" |
||
| 3258 | "** Read from a built-in file.\n" |
||
| 3259 | "*/\n" |
||
| 3260 | "static int Et_FileInput(\n" |
||
| 3261 | " ClientData instanceData, /* The file structure */\n" |
||
| 3262 | " char *buf, /* Write the data read here */\n" |
||
| 3263 | " int bufSize, /* Read this much data */\n" |
||
| 3264 | " int *pErrorCode /* Write the error code here */\n" |
||
| 3265 | "){\n" |
||
| 3266 | " Et_FileStruct *p = (Et_FileStruct*)instanceData;\n" |
||
| 3267 | " *pErrorCode = 0;\n" |
||
| 3268 | " if( p->cursor+bufSize>p->nData ){\n" |
||
| 3269 | " bufSize = p->nData - p->cursor;\n" |
||
| 3270 | " }\n" |
||
| 3271 | " memcpy(buf, &p->zData[p->cursor], bufSize);\n" |
||
| 3272 | " p->cursor += bufSize;\n" |
||
| 3273 | " return bufSize;\n" |
||
| 3274 | "}\n" |
||
| 3275 | "\n" |
||
| 3276 | "/*\n" |
||
| 3277 | "** Writes to a built-in file always return EOF.\n" |
||
| 3278 | "*/\n" |
||
| 3279 | "static int Et_FileOutput(\n" |
||
| 3280 | " ClientData instanceData, /* The file structure */\n" |
||
| 3281 | " char *buf, /* Read the data from here */\n" |
||
| 3282 | " int toWrite, /* Write this much data */\n" |
||
| 3283 | " int *pErrorCode /* Write the error code here */\n" |
||
| 3284 | "){\n" |
||
| 3285 | " *pErrorCode = 0;\n" |
||
| 3286 | " return 0;\n" |
||
| 3287 | "}\n" |
||
| 3288 | "\n" |
||
| 3289 | "/*\n" |
||
| 3290 | "** Move the cursor around within the built-in file.\n" |
||
| 3291 | "*/\n" |
||
| 3292 | "static int Et_FileSeek(\n" |
||
| 3293 | " ClientData instanceData, /* The file structure */\n" |
||
| 3294 | " long offset, /* Offset to seek to */\n" |
||
| 3295 | " int mode, /* One of SEEK_CUR, SEEK_SET or SEEK_END */\n" |
||
| 3296 | " int *pErrorCode /* Write the error code here */\n" |
||
| 3297 | "){\n" |
||
| 3298 | " Et_FileStruct *p = (Et_FileStruct*)instanceData;\n" |
||
| 3299 | " switch( mode ){\n" |
||
| 3300 | " case SEEK_CUR: offset += p->cursor; break;\n" |
||
| 3301 | " case SEEK_END: offset += p->nData; break;\n" |
||
| 3302 | " default: break;\n" |
||
| 3303 | " }\n" |
||
| 3304 | " if( offset<0 ) offset = 0;\n" |
||
| 3305 | " if( offset>p->nData ) offset = p->nData;\n" |
||
| 3306 | " p->cursor = offset;\n" |
||
| 3307 | " return offset;\n" |
||
| 3308 | "}\n" |
||
| 3309 | "\n" |
||
| 3310 | "/*\n" |
||
| 3311 | "** The Watch method is a no-op\n" |
||
| 3312 | "*/\n" |
||
| 3313 | "static void Et_FileWatch(ClientData instanceData, int mask){\n" |
||
| 3314 | "}\n" |
||
| 3315 | "\n" |
||
| 3316 | "/*\n" |
||
| 3317 | "** The Handle method always returns an error.\n" |
||
| 3318 | "*/\n" |
||
| 3319 | "static int Et_FileHandle(ClientData notUsed, int dir, ClientData *handlePtr){\n" |
||
| 3320 | " return TCL_ERROR;\n" |
||
| 3321 | "}\n" |
||
| 3322 | "\n" |
||
| 3323 | "/*\n" |
||
| 3324 | "** This is the channel type that will access the built-in files.\n" |
||
| 3325 | "*/\n" |
||
| 3326 | "static Tcl_ChannelType builtinChannelType = {\n" |
||
| 3327 | " \"builtin\", /* Type name. */\n" |
||
| 3328 | " NULL, /* Always non-blocking.*/\n" |
||
| 3329 | " Et_FileClose, /* Close proc. */\n" |
||
| 3330 | " Et_FileInput, /* Input proc. */\n" |
||
| 3331 | " Et_FileOutput, /* Output proc. */\n" |
||
| 3332 | " Et_FileSeek, /* Seek proc. */\n" |
||
| 3333 | " NULL, /* Set option proc. */\n" |
||
| 3334 | " NULL, /* Get option proc. */\n" |
||
| 3335 | " Et_FileWatch, /* Watch for events on console. */\n" |
||
| 3336 | " Et_FileHandle, /* Get a handle from the device. */\n" |
||
| 3337 | "};\n" |
||
| 3338 | "\n" |
||
| 3339 | "/*\n" |
||
| 3340 | "** This routine attempts to do an open of a built-in file.\n" |
||
| 3341 | "*/\n" |
||
| 3342 | "static Tcl_Channel Et_FileOpen(\n" |
||
| 3343 | " Tcl_Interp *interp, /* The TCL interpreter doing the open */\n" |
||
| 3344 | " char *zFilename, /* Name of the file to open */\n" |
||
| 3345 | " char *modeString, /* Mode string for the open (ignored) */\n" |
||
| 3346 | " int permissions /* Permissions for a newly created file (ignored) */\n" |
||
| 3347 | "){\n" |
||
| 3348 | " char *zData;\n" |
||
| 3349 | " Et_FileStruct *p;\n" |
||
| 3350 | " int nData;\n" |
||
| 3351 | " char zName[50];\n" |
||
| 3352 | " Tcl_Channel chan;\n" |
||
| 3353 | " static int count = 1;\n" |
||
| 3354 | "\n" |
||
| 3355 | " zData = FindBuiltinFile(zFilename, 1, &nData);\n" |
||
| 3356 | " if( zData==0 ) return NULL;\n" |
||
| 3357 | " p = (Et_FileStruct*)Tcl_Alloc( sizeof(Et_FileStruct) );\n" |
||
| 3358 | " if( p==0 ) return NULL;\n" |
||
| 3359 | " p->zData = zData;\n" |
||
| 3360 | " p->nData = nData;\n" |
||
| 3361 | " p->cursor = 0;\n" |
||
| 3362 | " sprintf(zName,\"etbi_%x_%x\",((int)Et_FileOpen)>>12,count++);\n" |
||
| 3363 | " chan = Tcl_CreateChannel(&builtinChannelType, zName, \n" |
||
| 3364 | " (ClientData)p, TCL_READABLE);\n" |
||
| 3365 | " return chan;\n" |
||
| 3366 | "}\n" |
||
| 3367 | "\n" |
||
| 3368 | "/*\n" |
||
| 3369 | "** This routine does a stat() system call for a built-in file.\n" |
||
| 3370 | "*/\n" |
||
| 3371 | "static int Et_FileStat(char *path, struct stat *buf){\n" |
||
| 3372 | " char *zData;\n" |
||
| 3373 | " int nData;\n" |
||
| 3374 | "\n" |
||
| 3375 | " zData = FindBuiltinFile(path, 0, &nData);\n" |
||
| 3376 | " if( zData==0 ){\n" |
||
| 3377 | " return -1;\n" |
||
| 3378 | " }\n" |
||
| 3379 | " memset(buf, 0, sizeof(*buf));\n" |
||
| 3380 | " buf->st_mode = 0400;\n" |
||
| 3381 | " buf->st_size = nData;\n" |
||
| 3382 | " return 0;\n" |
||
| 3383 | "}\n" |
||
| 3384 | "\n" |
||
| 3385 | "/*\n" |
||
| 3386 | "** This routien does an access() system call for a built-in file.\n" |
||
| 3387 | "*/\n" |
||
| 3388 | "static int Et_FileAccess(char *path, int mode){\n" |
||
| 3389 | " char *zData;\n" |
||
| 3390 | "\n" |
||
| 3391 | " if( mode & 3 ){\n" |
||
| 3392 | " return -1;\n" |
||
| 3393 | " }\n" |
||
| 3394 | " zData = FindBuiltinFile(path, 0, 0);\n" |
||
| 3395 | " if( zData==0 ){\n" |
||
| 3396 | " return -1;\n" |
||
| 3397 | " }\n" |
||
| 3398 | " return 0; \n" |
||
| 3399 | "}\n" |
||
| 3400 | "#endif /* ET_HAVE_INSERTPROC */\n" |
||
| 3401 | "\n" |
||
| 3402 | "/*\n" |
||
| 3403 | "** An overloaded version of \"source\". First check for the file\n" |
||
| 3404 | "** is one of the built-ins. If it isn't a built-in, then check the\n" |
||
| 3405 | "** disk. But if ET_STANDALONE is set (which corresponds to the\n" |
||
| 3406 | "** \"Strict\" option in the user interface) then never check the disk.\n" |
||
| 3407 | "** This gives us a quick way to check for the common error of\n" |
||
| 3408 | "** sourcing a file that exists on the development by mistake, \n" |
||
| 3409 | "** and only discovering the mistake when you move the program\n" |
||
| 3410 | "** to your customer's machine.\n" |
||
| 3411 | "*/\n" |
||
| 3412 | "static int Et_Source(ET_TCLARGS){\n" |
||
| 3413 | " char *z;\n" |
||
| 3414 | "\n" |
||
| 3415 | " if( argc!=2 ){\n" |
||
| 3416 | " Et_ResultF(interp,\"wrong # args: should be \\\"%s FILENAME\\\"\", argv[0]);\n" |
||
| 3417 | " return TCL_ERROR;\n" |
||
| 3418 | " }\n" |
||
| 3419 | " z = FindBuiltinFile(argv[1], 1, 0);\n" |
||
| 3420 | " if( z ){\n" |
||
| 3421 | " int rc;\n" |
||
| 3422 | " rc = Tcl_Eval(interp,z);\n" |
||
| 3423 | " if (rc == TCL_ERROR) {\n" |
||
| 3424 | " char msg[200];\n" |
||
| 3425 | " sprintf(msg, \"\\n (file \\\"%.150s\\\" line %d)\", argv[1],\n" |
||
| 3426 | " interp->errorLine);\n" |
||
| 3427 | " Tcl_AddErrorInfo(interp, msg);\n" |
||
| 3428 | " } else {\n" |
||
| 3429 | " rc = TCL_OK;\n" |
||
| 3430 | " }\n" |
||
| 3431 | " return rc;\n" |
||
| 3432 | " }\n" |
||
| 3433 | "#if ET_STANDALONE\n" |
||
| 3434 | " Et_ResultF(interp,\"no such file: \\\"%s\\\"\", argv[1]);\n" |
||
| 3435 | " return TCL_ERROR;\n" |
||
| 3436 | "#else\n" |
||
| 3437 | " return Tcl_EvalFile(interp,argv[1]);\n" |
||
| 3438 | "#endif\n" |
||
| 3439 | "}\n" |
||
| 3440 | "\n" |
||
| 3441 | "#ifndef ET_HAVE_INSERTPROC\n" |
||
| 3442 | "/*\n" |
||
| 3443 | "** An overloaded version of \"file exists\". First check for the file\n" |
||
| 3444 | "** in the file table, then go to disk.\n" |
||
| 3445 | "**\n" |
||
| 3446 | "** We only overload \"file exists\" if we don't have InsertProc() \n" |
||
| 3447 | "** procedures. If we do have InsertProc() procedures, they will\n" |
||
| 3448 | "** handle this more efficiently.\n" |
||
| 3449 | "*/\n" |
||
| 3450 | "static int Et_FileExists(ET_TCLARGS){\n" |
||
| 3451 | " int i, rc;\n" |
||
| 3452 | " Tcl_DString str;\n" |
||
| 3453 | " if( argc==3 && strncmp(argv[1],\"exis\",4)==0 ){\n" |
||
| 3454 | " if( FindBuiltinFile(argv[2], 0, 0)!=0 ){\n" |
||
| 3455 | " interp->result = \"1\";\n" |
||
| 3456 | " return TCL_OK;\n" |
||
| 3457 | " }\n" |
||
| 3458 | " }\n" |
||
| 3459 | " Tcl_DStringInit(&str);\n" |
||
| 3460 | " Tcl_DStringAppendElement(&str,\"Et_FileCmd\");\n" |
||
| 3461 | " for(i=1; i<argc; i++){\n" |
||
| 3462 | " Tcl_DStringAppendElement(&str, argv[i]);\n" |
||
| 3463 | " }\n" |
||
| 3464 | " rc = Tcl_Eval(interp, Tcl_DStringValue(&str));\n" |
||
| 3465 | " Tcl_DStringFree(&str);\n" |
||
| 3466 | " return rc;\n" |
||
| 3467 | "}\n" |
||
| 3468 | "#endif\n" |
||
| 3469 | "\n" |
||
| 3470 | "/*\n" |
||
| 3471 | "** This is the main Tcl interpreter. It's a global variable so it\n" |
||
| 3472 | "** can be accessed easily from C code.\n" |
||
| 3473 | "*/\n" |
||
| 3474 | "Tcl_Interp *Et_Interp = 0;\n" |
||
| 3475 | "\n" |
||
| 3476 | "\n" |
||
| 3477 | "#if ET_WIN32\n" |
||
| 3478 | "/*\n" |
||
| 3479 | "** Implement the Et_MessageBox command on Windows platforms. We\n" |
||
| 3480 | "** use the MessageBox() function from the Win32 API so that the\n" |
||
| 3481 | "** error message will be displayed as a dialog box. Writing to\n" |
||
| 3482 | "** standard error doesn't do anything on windows.\n" |
||
| 3483 | "*/\n" |
||
| 3484 | "int Et_MessageBox(ET_TCLARGS){\n" |
||
| 3485 | " char *zMsg = \"(Empty Message)\";\n" |
||
| 3486 | " char *zTitle = \"Message...\";\n" |
||
| 3487 | "\n" |
||
| 3488 | " if( argc>1 ){\n" |
||
| 3489 | " zTitle = argv[1];\n" |
||
| 3490 | " }\n" |
||
| 3491 | " if( argc>2 ){\n" |
||
| 3492 | " zMsg = argv[2];\n" |
||
| 3493 | " }\n" |
||
| 3494 | " MessageBox(0, zMsg, zTitle, MB_ICONSTOP | MB_OK);\n" |
||
| 3495 | " return TCL_OK;\n" |
||
| 3496 | "}\n" |
||
| 3497 | "#endif\n" |
||
| 3498 | "\n" |
||
| 3499 | "/*\n" |
||
| 3500 | "** A default implementation for \"bgerror\"\n" |
||
| 3501 | "*/\n" |
||
| 3502 | "static char zBgerror[] = \n" |
||
| 3503 | " \"proc Et_Bgerror err {\\n\"\n" |
||
| 3504 | " \" global errorInfo tk_library\\n\"\n" |
||
| 3505 | " \" if {[info exists errorInfo]} {\\n\"\n" |
||
| 3506 | " \" set ei $errorInfo\\n\"\n" |
||
| 3507 | " \" } else {\\n\"\n" |
||
| 3508 | " \" set ei {}\\n\"\n" |
||
| 3509 | " \" }\\n\"\n" |
||
| 3510 | " \" if {[catch {bgerror $err}]==0} return\\n\"\n" |
||
| 3511 | " \" if {[string length $ei]>0} {\\n\"\n" |
||
| 3512 | " \" set err $ei\\n\"\n" |
||
| 3513 | " \" }\\n\"\n" |
||
| 3514 | " \" if {[catch {Et_MessageBox {Error} $err}]} {\\n\"\n" |
||
| 3515 | " \" puts stderr $err\\n\"\n" |
||
| 3516 | " \" }\\n\"\n" |
||
| 3517 | " \" exit\\n\"\n" |
||
| 3518 | " \"}\\n\"\n" |
||
| 3519 | ";\n" |
||
| 3520 | "\n" |
||
| 3521 | "/*\n" |
||
| 3522 | "** Do the initialization.\n" |
||
| 3523 | "**\n" |
||
| 3524 | "** This routine is called after the interpreter is created, but\n" |
||
| 3525 | "** before Et_PreInit() or Et_AppInit() have been run.\n" |
||
| 3526 | "*/\n" |
||
| 3527 | "static int Et_DoInit(Tcl_Interp *interp){\n" |
||
| 3528 | " int i;\n" |
||
| 3529 | " extern int Et_PreInit(Tcl_Interp*);\n" |
||
| 3530 | " extern int Et_AppInit(Tcl_Interp*);\n" |
||
| 3531 | "\n" |
||
| 3532 | " /* Insert our alternative stat(), access() and open() procedures\n" |
||
| 3533 | " ** so that any attempt to work with a file will check our built-in\n" |
||
| 3534 | " ** scripts first.\n" |
||
| 3535 | " */\n" |
||
| 3536 | "#ifdef ET_HAVE_INSERTPROC\n" |
||
| 3537 | " TclStatInsertProc(Et_FileStat);\n" |
||
| 3538 | " TclAccessInsertProc(Et_FileAccess);\n" |
||
| 3539 | " TclOpenFileChannelInsertProc(Et_FileOpen);\n" |
||
| 3540 | "#endif\n" |
||
| 3541 | "\n" |
||
| 3542 | " /* Initialize the hash-table for built-in scripts\n" |
||
| 3543 | " */\n" |
||
| 3544 | " FilenameHashInit();\n" |
||
| 3545 | "\n" |
||
| 3546 | " /* The Et_NewBuiltFile command is inserted for use by FreeWrap\n" |
||
| 3547 | " ** and similar tools.\n" |
||
| 3548 | " */\n" |
||
| 3549 | "#if ET_HAVE_OBJ\n" |
||
| 3550 | " Tcl_CreateObjCommand(interp,\"Et_NewBuiltinFile\",Et_NewBuiltinFileCmd,0,0);\n" |
||
| 3551 | "#else\n" |
||
| 3552 | " Tcl_CreateCommand(interp,\"Et_NewBuiltinFile\",Et_NewBuiltinFileCmd,0,0);\n" |
||
| 3553 | "#endif\n" |
||
| 3554 | "\n" |
||
| 3555 | " /* Overload the \"file\" and \"source\" commands\n" |
||
| 3556 | " */\n" |
||
| 3557 | "#ifndef ET_HAVE_INSERTPROC\n" |
||
| 3558 | " {\n" |
||
| 3559 | " static char zRename[] = \"rename file Et_FileCmd\";\n" |
||
| 3560 | " Tcl_Eval(interp,zRename);\n" |
||
| 3561 | " Tcl_CreateCommand(interp,\"file\",Et_FileExists,0,0);\n" |
||
| 3562 | " }\n" |
||
| 3563 | "#endif\n" |
||
| 3564 | " Tcl_CreateCommand(interp,\"source\",Et_Source,0,0);\n" |
||
| 3565 | "\n" |
||
| 3566 | " Et_Interp = interp;\n" |
||
| 3567 | "#ifdef ET_TCL_LIBRARY\n" |
||
| 3568 | " Tcl_SetVar(interp,\"tcl_library\",ET_TCL_LIBRARY,TCL_GLOBAL_ONLY);\n" |
||
| 3569 | " Tcl_SetVar(interp,\"tcl_libPath\",ET_TCL_LIBRARY,TCL_GLOBAL_ONLY);\n" |
||
| 3570 | " Tcl_SetVar2(interp,\"env\",\"TCL_LIBRARY\",ET_TCL_LIBRARY,TCL_GLOBAL_ONLY);\n" |
||
| 3571 | "#endif\n" |
||
| 3572 | "#ifdef ET_TK_LIBRARY\n" |
||
| 3573 | " Tcl_SetVar(interp,\"tk_library\",ET_TK_LIBRARY,TCL_GLOBAL_ONLY);\n" |
||
| 3574 | " Tcl_SetVar2(interp,\"env\",\"TK_LIBRARY\",ET_TK_LIBRARY,TCL_GLOBAL_ONLY);\n" |
||
| 3575 | "#endif\n" |
||
| 3576 | "#if ET_WIN32\n" |
||
| 3577 | " Tcl_CreateCommand(interp,\"Et_MessageBox\",Et_MessageBox, 0, 0);\n" |
||
| 3578 | "#endif \n" |
||
| 3579 | " Tcl_Eval(interp,zBgerror);\n" |
||
| 3580 | "#if ET_HAVE_PREINIT\n" |
||
| 3581 | " if( Et_PreInit(interp) == TCL_ERROR ){\n" |
||
| 3582 | " goto initerr;\n" |
||
| 3583 | " }\n" |
||
| 3584 | "#endif\n" |
||
| 3585 | " if( Tcl_Init(interp) == TCL_ERROR ){\n" |
||
| 3586 | " goto initerr;\n" |
||
| 3587 | " }\n" |
||
| 3588 | " Et_GlobalEvalF(interp,\"set dir $tcl_library;source $dir/tclIndex;unset dir\");\n" |
||
| 3589 | "#if ET_ENABLE_TK\n" |
||
| 3590 | " if( Tk_Init(interp) == TCL_ERROR ){\n" |
||
| 3591 | " goto initerr;\n" |
||
| 3592 | " }\n" |
||
| 3593 | " Tcl_StaticPackage(interp,\"Tk\", Tk_Init, 0);\n" |
||
| 3594 | " Et_GlobalEvalF(interp,\"set dir $tk_library;source $dir/tclIndex;unset dir\");\n" |
||
| 3595 | "#endif\n" |
||
| 3596 | " /* Tcl_SetVar(interp, \"tcl_rcFileName\", \"~/.wishrc\", TCL_GLOBAL_ONLY); */\n" |
||
| 3597 | " for(i=0; i<sizeof(Et_CmdSet)/sizeof(Et_CmdSet[0]) - 1; i++){\n" |
||
| 3598 | " Tcl_CreateCommand(interp, Et_CmdSet[i].zName, Et_CmdSet[i].xProc, 0, 0);\n" |
||
| 3599 | " }\n" |
||
| 3600 | "#if ET_ENABLE_OBJ\n" |
||
| 3601 | " for(i=0; i<sizeof(Et_ObjSet)/sizeof(Et_ObjSet[0]) - 1; i++){\n" |
||
| 3602 | " Tcl_CreateObjCommand(interp, Et_ObjSet[i].zName, Et_ObjSet[i].xProc, 0, 0);\n" |
||
| 3603 | " }\n" |
||
| 3604 | "#endif\n" |
||
| 3605 | " Tcl_LinkVar(interp,\"Et_EvalTrace\",(char*)&Et_EvalTrace,TCL_LINK_BOOLEAN);\n" |
||
| 3606 | " Tcl_SetVar(interp,\"et_version\",ET_VERSION,TCL_GLOBAL_ONLY);\n" |
||
| 3607 | "#if ET_HAVE_APPINIT\n" |
||
| 3608 | " if( Et_AppInit(interp) == TCL_ERROR ){\n" |
||
| 3609 | " goto initerr;\n" |
||
| 3610 | " }\n" |
||
| 3611 | "#endif\n" |
||
| 3612 | "#if ET_ENABLE_TK && !ET_EXTENSION\n" |
||
| 3613 | " Et_NewBuiltinFile(\"builtin:/console.tcl\", zEtConsole, sizeof(zEtConsole));\n" |
||
| 3614 | "#if ET_CONSOLE\n" |
||
| 3615 | " Tcl_Eval(interp,\n" |
||
| 3616 | " \"source builtin:/console.tcl\\n\"\n" |
||
| 3617 | " \"console:create {.@console} {% } {Tcl/Tk Console}\\n\"\n" |
||
| 3618 | " );\n" |
||
| 3619 | "#endif\n" |
||
| 3620 | "#endif\n" |
||
| 3621 | "#ifdef ET_MAIN_SCRIPT\n" |
||
| 3622 | " if( Et_EvalF(interp,\"source \\\"%q\\\"\", ET_MAIN_SCRIPT)!=TCL_OK ){\n" |
||
| 3623 | " goto initerr;\n" |
||
| 3624 | " }\n" |
||
| 3625 | "#endif\n" |
||
| 3626 | " return TCL_OK;\n" |
||
| 3627 | "\n" |
||
| 3628 | "initerr:\n" |
||
| 3629 | " Et_EvalF(interp,\"Et_Bgerror \\\"%q\\\"\", interp->result);\n" |
||
| 3630 | " return TCL_ERROR;\n" |
||
| 3631 | "}\n" |
||
| 3632 | "\n" |
||
| 3633 | "#if ET_READ_STDIN==0 || ET_AUTO_FORK!=0\n" |
||
| 3634 | "/*\n" |
||
| 3635 | "** Initialize everything.\n" |
||
| 3636 | "*/\n" |
||
| 3637 | "static int Et_Local_Init(int argc, char **argv){\n" |
||
| 3638 | " Tcl_Interp *interp;\n" |
||
| 3639 | " char *args;\n" |
||
| 3640 | " char buf[100];\n" |
||
| 3641 | "#if !ET_HAVE_CUSTOM_MAINLOOP\n" |
||
| 3642 | " static char zWaitForever[] = \n" |
||
| 3643 | "#if ET_ENABLE_TK\n" |
||
| 3644 | " \"bind . <Destroy> {if {![winfo exists .]} exit}\\n\"\n" |
||
| 3645 | "#endif\n" |
||
| 3646 | " \"while 1 {vwait forever}\";\n" |
||
| 3647 | "#endif\n" |
||
| 3648 | "\n" |
||
| 3649 | " Tcl_FindExecutable(argv[0]);\n" |
||
| 3650 | " interp = Tcl_CreateInterp();\n" |
||
| 3651 | " args = Tcl_Merge(argc-1, argv+1);\n" |
||
| 3652 | " Tcl_SetVar(interp, \"argv\", args, TCL_GLOBAL_ONLY);\n" |
||
| 3653 | " ckfree(args);\n" |
||
| 3654 | " sprintf(buf, \"%d\", argc-1);\n" |
||
| 3655 | " Tcl_SetVar(interp, \"argc\", buf, TCL_GLOBAL_ONLY);\n" |
||
| 3656 | " Tcl_SetVar(interp, \"argv0\", argv[0], TCL_GLOBAL_ONLY);\n" |
||
| 3657 | " Tcl_SetVar(interp, \"tcl_interactive\", \"0\", TCL_GLOBAL_ONLY);\n" |
||
| 3658 | " Et_DoInit(interp);\n" |
||
| 3659 | "#if ET_HAVE_CUSTOM_MAINLOOP\n" |
||
| 3660 | " Et_CustomMainLoop(interp);\n" |
||
| 3661 | "#else\n" |
||
| 3662 | " Tcl_Eval(interp,zWaitForever);\n" |
||
| 3663 | "#endif\n" |
||
| 3664 | " return 0;\n" |
||
| 3665 | "}\n" |
||
| 3666 | "#endif\n" |
||
| 3667 | "\n" |
||
| 3668 | "/*\n" |
||
| 3669 | "** This routine is called to do the complete initialization.\n" |
||
| 3670 | "*/\n" |
||
| 3671 | "int Et_Init(int argc, char **argv){\n" |
||
| 3672 | "#ifdef ET_TCL_LIBRARY\n" |
||
| 3673 | " putenv(\"TCL_LIBRARY=\" ET_TCL_LIBRARY);\n" |
||
| 3674 | "#endif\n" |
||
| 3675 | "#ifdef ET_TK_LIBRARY\n" |
||
| 3676 | " putenv(\"TK_LIBRARY=\" ET_TK_LIBRARY);\n" |
||
| 3677 | "#endif\n" |
||
| 3678 | "#if ET_CONSOLE || !ET_READ_STDIN\n" |
||
| 3679 | " Et_Local_Init(argc, argv);\n" |
||
| 3680 | "#else\n" |
||
| 3681 | "# if ET_ENABLE_TK\n" |
||
| 3682 | " Tk_Main(argc,argv,Et_DoInit);\n" |
||
| 3683 | "# else\n" |
||
| 3684 | " Tcl_Main(argc, argv, Et_DoInit);\n" |
||
| 3685 | "# endif\n" |
||
| 3686 | "#endif\n" |
||
| 3687 | " return 0;\n" |
||
| 3688 | "}\n" |
||
| 3689 | "\n" |
||
| 3690 | "#if !ET_HAVE_MAIN && !ET_EXTENSION\n" |
||
| 3691 | "/*\n" |
||
| 3692 | "** Main routine for UNIX programs. If the user has supplied\n" |
||
| 3693 | "** their own main() routine in a C module, then the ET_HAVE_MAIN\n" |
||
| 3694 | "** macro will be set to 1 and this code will be skipped.\n" |
||
| 3695 | "*/\n" |
||
| 3696 | "int main(int argc, char **argv){\n" |
||
| 3697 | "#if ET_AUTO_FORK\n" |
||
| 3698 | " int rc = fork();\n" |
||
| 3699 | " if( rc<0 ){\n" |
||
| 3700 | " perror(\"can't fork\");\n" |
||
| 3701 | " exit(1);\n" |
||
| 3702 | " }\n" |
||
| 3703 | " if( rc>0 ) return 0;\n" |
||
| 3704 | " close(0);\n" |
||
| 3705 | " open(\"/dev/null\",O_RDONLY);\n" |
||
| 3706 | " close(1);\n" |
||
| 3707 | " open(\"/dev/null\",O_WRONLY);\n" |
||
| 3708 | "#endif\n" |
||
| 3709 | " return Et_Init(argc,argv)!=TCL_OK;\n" |
||
| 3710 | "}\n" |
||
| 3711 | "#endif\n" |
||
| 3712 | "\n" |
||
| 3713 | "#if ET_EXTENSION\n" |
||
| 3714 | "/*\n" |
||
| 3715 | "** If the -extension flag is used, then generate code that will be\n" |
||
| 3716 | "** turned into a loadable shared library or DLL, not a standalone\n" |
||
| 3717 | "** executable.\n" |
||
| 3718 | "*/\n" |
||
| 3719 | "int ET_EXTENSION_NAME(Tcl_Interp *interp){\n" |
||
| 3720 | " int i;\n" |
||
| 3721 | "#ifndef ET_HAVE_INSERTPROC\n" |
||
| 3722 | " Tcl_AppendResult(interp,\n" |
||
| 3723 | " \"mktclapp can only generate extensions for Tcl/Tk version \"\n" |
||
| 3724 | " \"8.0.3 and later. This is version \"\n" |
||
| 3725 | " TCL_MAJOR_VERSION \".\" TCL_MINOR_VERSION \".\" TCL_RELEASE_SERIAL, 0);\n" |
||
| 3726 | " return TCL_ERROR;\n" |
||
| 3727 | "#endif\n" |
||
| 3728 | "#ifdef ET_HAVE_INSERTPROC\n" |
||
| 3729 | "#ifdef USE_TCL_STUBS\n" |
||
| 3730 | " if( Tcl_InitStubs(interp,\"8.0\",0)==0 ){\n" |
||
| 3731 | " return TCL_ERROR;\n" |
||
| 3732 | " }\n" |
||
| 3733 | " if( Tk_InitStubs(interp,\"8.0\",0)==0 ){\n" |
||
| 3734 | " return TCL_ERROR;\n" |
||
| 3735 | " }\n" |
||
| 3736 | "#endif\n" |
||
| 3737 | " Et_Interp = interp;\n" |
||
| 3738 | " TclStatInsertProc(Et_FileStat);\n" |
||
| 3739 | " TclAccessInsertProc(Et_FileAccess);\n" |
||
| 3740 | " TclOpenFileChannelInsertProc(Et_FileOpen);\n" |
||
| 3741 | " FilenameHashInit();\n" |
||
| 3742 | " for(i=0; i<sizeof(Et_CmdSet)/sizeof(Et_CmdSet[0]) - 1; i++){\n" |
||
| 3743 | " Tcl_CreateCommand(interp, Et_CmdSet[i].zName, Et_CmdSet[i].xProc, 0, 0);\n" |
||
| 3744 | " }\n" |
||
| 3745 | "#if ET_ENABLE_OBJ\n" |
||
| 3746 | " for(i=0; i<sizeof(Et_ObjSet)/sizeof(Et_ObjSet[0]) - 1; i++){\n" |
||
| 3747 | " Tcl_CreateObjCommand(interp, Et_ObjSet[i].zName, Et_ObjSet[i].xProc, 0, 0);\n" |
||
| 3748 | " }\n" |
||
| 3749 | "#endif\n" |
||
| 3750 | " Tcl_LinkVar(interp,\"Et_EvalTrace\",(char*)&Et_EvalTrace,TCL_LINK_BOOLEAN);\n" |
||
| 3751 | " Tcl_SetVar(interp,\"et_version\",ET_VERSION,TCL_GLOBAL_ONLY);\n" |
||
| 3752 | "#if ET_HAVE_APPINIT\n" |
||
| 3753 | " if( Et_AppInit(interp) == TCL_ERROR ){\n" |
||
| 3754 | " return TCL_ERROR;\n" |
||
| 3755 | " }\n" |
||
| 3756 | "#endif\n" |
||
| 3757 | "#ifdef ET_MAIN_SCRIPT\n" |
||
| 3758 | " if( Et_EvalF(interp,\"source \\\"%q\\\"\", ET_MAIN_SCRIPT)!=TCL_OK ){\n" |
||
| 3759 | " return TCL_ERROR;\n" |
||
| 3760 | " }\n" |
||
| 3761 | "#endif\n" |
||
| 3762 | " return TCL_OK;\n" |
||
| 3763 | "#endif /* ET_HAVE_INSERTPROC */\n" |
||
| 3764 | "}\n" |
||
| 3765 | "int ET_SAFE_EXTENSION_NAME(Tcl_Interp *interp){\n" |
||
| 3766 | " return ET_EXTENSION_NAME(interp);\n" |
||
| 3767 | "}\n" |
||
| 3768 | "#endif\n"; |