Rev 2 | Details | Compare with Previous | 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"; |