Subversion Repositories Vertical

Rev

Details | Last modification | View Log | RSS feed

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