static char const rcsid[] = "@(#) $Id: mktclapp.c,v 1.1.1.1 2003/11/04 23:35:00 mjames Exp $";
/*
** Copyright (c) 1998, 1999 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the GNU General Public
** License as published by the Free Software Foundation; either
** version 2 of the License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
** General Public License for more details.
**
** You should have received a copy of the GNU General Public
** License along with this library; if not, write to the
** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA 02111-1307, USA.
**
** Author contact information:
** drh@acm.org
** http://www.hwaci.com/drh/
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#if defined(_WIN32) || defined(WIN32)
#include <windows.h>
#if !defined(R_OK)
#define R_OK 4
#endif
#else
#include <unistd.h>
#endif
#include <assert.h>
#include <time.h>
/*
** Version information for this program
*/
static char zVersion[] = "mktclapp version 3.9. January 30, 2000";
/*
** Each new TCL commands discovered while scanning C/C++ source code is
** stored in an instance of the following structure.
*/
typedef struct EtCmd EtCmd;
struct EtCmd
{
char *zIf; /* Surrounding #if statement */
char *zName; /* Name of the command */
int isObj; /* True if this is a Tcl_Obj command */
EtCmd *pNext; /* Next command on a list of them all */
};
/*
** This is a list of all TCL commands in the scanned source
*/
static EtCmd *cmdList = 0;
/*
** Number of commands and object commands.
*/
static int nCmd = 0;
static int nObjCmd = 0;
/*
** Each nested "#if" statement is stored as an instance of the
** following structure.
*/
typedef struct IfStmt IfStmt;
struct IfStmt
{
char *zArg; /* Argument to the #if. Ex: "defined(DEBUG)" */
int invert; /* True to put a "!" in front */
int line; /* Line number of the original #if */
IfStmt *pNext; /* Next #if statement down on the stack */
};
/*
** The nested #if statements
*/
static IfStmt *ifStack = 0;
/*
** Name of this program.
*/
static char *Argv0 = "mktclapp";
/*
** Number of errors
*/
static int nError = 0;
/*
** Surround the call to Et_AppInit() with this #if
*/
static char *seenEtAppInit = "0";
/*
** Surround the call to Et_PreInit() with this #if
*/
static char *seenEtPreInit = "0";
/*
** Surround the implmentation of main() with the inverse of this #if
*/
static char *seenMain = "0";
/*
** Surround the call to Et_CustomMainLoop() with the inverse of this #if
*/
static char *seenEtCustomMainLoop = "0";
/*
** Allocate memory. Never fail. If not enough memory is available,
** print an error message and abort.
*/
void *SafeMalloc (int nByte)
{
if (p == 0)
{
fprintf (stderr
, "Out of memory. Can't allocate %d bytes\n", nByte
);
}
return p;
}
void *SafeRealloc (void *old, int nByte)
{
void *p;
if (old == 0)
return SafeMalloc (nByte);
if (p == 0)
{
fprintf (stderr
, "Out of memory. Can't allocate %d bytes\n", nByte
);
}
return p;
}
/*
** The opposite of SafeMalloc(). Free memory previously obtained.
*/
void SafeFree (void *pMem)
{
if (pMem)
}
/*
** Return TRUE if the given character can be part of a C identifier.
*/
static int IsIdent (int c)
{
}
/*
** Create an "#if" argument that captures the state of all nested
** "#if" statements, ORed with "zExtra". Space to hold
** the returned string is obtained from SafeMalloc and must be
** freed by the calling function.
**
** If the conditional is always TRUE, then NULL is returned.
*/
static char *IfString (char *zExtra)
{
int len = 0;
IfStmt *p;
char *z;
int i;
int isStackTrue = 1;
int isStackFalse = 0;
int isExtraFalse = 0;
char *zSep;
IfStmt *altStack;
if (zExtra && *zExtra)
{
if (zExtra[1] == 0 && zExtra[0] == '0')
{
isExtraFalse = 1;
}
else if (zExtra[1] == 0 && zExtra[0] == '1')
{
return 0;
}
}
else
{
len = 1;
isExtraFalse = 1;
}
for (p = ifStack; p; p = p->pNext)
{
if (p->zArg[0] == '0' && p->zArg[1] == 0)
{
if (!p->invert)
{
isStackFalse = 1;
isStackTrue = 0;
break;
}
}
else if (p->zArg[0] == '1' && p->zArg[1] == 0)
{
if (p->invert)
{
isStackFalse = 1;
isStackTrue = 0;
break;
}
}
else
{
isStackTrue = 0;
}
}
if (isStackTrue)
{
return 0;
}
else if (isStackFalse && isExtraFalse)
{
z = SafeMalloc (2);
return z;
}
z = SafeMalloc (len);
if (!isExtraFalse)
{
}
else
{
i = 0;
}
zSep = "";
altStack = 0;
while (ifStack)
{
p = ifStack;
ifStack = p->pNext;
p->pNext = altStack;
altStack = p;
}
for (p = altStack; p; p = p->pNext)
{
if (p->zArg[0] == '0' && p->zArg[1] == 0 && p->invert)
continue;
if (p->zArg[0] == '1' && p->zArg[1] == 0 && !p->invert)
continue;
if (p->invert)
{
sprintf (&z
[i
], "%s!%s", zSep
, p
->zArg
);
}
else
{
sprintf (&z
[i
], "%s%s", zSep
, p
->zArg
);
}
zSep = " && ";
}
while (altStack)
{
p = altStack;
altStack = p->pNext;
p->pNext = ifStack;
ifStack = p;
}
if (!isExtraFalse)
{
}
return z;
}
/*
** Push a new "#if" onto the if stack.
*/
static void PushIf (char *zArg, int line, int isNegated, int isDefined)
{
char *z;
IfStmt *p;
if (!isDefined)
{
int i;
z
= SafeMalloc
(strlen (zArg
) + 3);
for (i = 0; zArg[i] && IsIdent (zArg[i]); i++)
{
}
if (zArg[i] == 0)
{
}
else
{
}
}
else
{
z
= SafeMalloc
(strlen (zArg
) + 10);
}
p = SafeMalloc (sizeof (IfStmt));
p->zArg = z;
p->line = line;
p->invert = isNegated;
p->pNext = ifStack;
ifStack = p;
}
/*
** Extract the argument to an #if. Remove all leading and trailing
** space.
*/
static char *GetArg (const char *fileName, char *z, int *pI, int *pLine)
{
int i = *pI;
int line = *pLine;
int start;
char *zResult;
int j, k;
while (isspace (z
[i
]) && z
[i
] != '\n')
{
i++;
}
start = i;
if (z[i] == '\n' || z[i] == 0)
{
stderr, "%s: Missing argument to \"#if\" on line %d\n", fileName, *pLine);
nError++;
line++;
}
else
{
while (z[i] && z[i] != '\n')
{
if (z[i] == '\\' && z[i + 1] != 0)
{
i++;
}
if (z[i] == '\n')
{
line++;
}
i++;
}
}
zResult = SafeMalloc (i + 1 - start);
for (j = 0, k = start; k < i; k++)
{
{
/* Do nothing */
}
else if (z[k] == '\\' && z[k + 1] == '\n')
{
if (j
> 0 && !isspace (zResult
[j
- 1]))
{
zResult[j++] = ' ';
}
k++;
}
else if (z[k] == '\\')
{
zResult[j++] = z[k++];
}
zResult[j++] = z[k];
}
zResult[j] = 0;
while (j
> 0 && isspace (zResult
[j
- 1]))
{
j--;
zResult[j] = 0;
}
*pI = i;
*pLine = line;
return zResult;
}
/*
** Read the complete text of a file into memory. Return 0 if there
** is any kind of error.
*/
char *ReadFileIntoMemory (const char *fileName, int *pLength)
{
FILE *in; /* Input file stream */
char *textBuf; /* A buffer in which to put entire text of input */
int toRead; /* Amount of input file read to read */
int got; /* Amount read so far */
struct stat statBuf; /* Status buffer for the file */
if (stat (fileName, &statBuf) != 0)
{
fprintf (stderr
, "%s: no such file: %s\n", Argv0
, fileName
);
return 0;
}
textBuf = SafeMalloc (statBuf.st_size + 1);
in
= fopen (fileName
, "rb");
if (in == 0)
{
fprintf (stderr
, "%s: can't open for reading: %s\n", Argv0
, fileName
);
SafeFree (textBuf);
return 0;
}
textBuf[statBuf.st_size] = 0;
toRead = statBuf.st_size;
got = 0;
while (toRead)
{
int n
= fread (&textBuf
[got
], 1, toRead
, in
);
if (n <= 0)
break;
toRead -= n;
got += n;
}
textBuf[got] = 0;
if (pLength)
*pLength = got;
return textBuf;
}
/*
** Given the "aaaa" part of the name of an ET_COMMAND_aaaa function,
** compute the name of the corresponding Tcl command.
**
** The name is usually the same, except if there are two underscores
** in the middle of the command, they are changed to colons. This
** feature allows namespaces to be used. Example: The function
** named
**
** ET_COMMAND_space1__proc1(ET_TCLARGS){...}
**
** will generate a TCL command called
**
** space1::proc1
**
** Space to hold the TCL command name is obtained from malloc().
*/
static char *FuncToProc (char *zFunc)
{
char *zProc;
int i;
zProc
= SafeMalloc
(strlen (zFunc
) + 1);
for (i = 0; zProc[i]; i++)
{
if (i > 0 && zProc[i] == '_' && zProc[i + 1] == '_' &&
{
zProc[i] = ':';
zProc[i + 1] = ':';
}
}
return zProc;
}
/*
** Scan a source file looking for new TCL commands and/or the Et_AppInit()
** or Et_PreInit() functions.
**
** Skip all comments, and any text contained within "#if 0".."#endif"
*/
void ScanFile (const char *fileName)
{
char *z; /* Complete text of the file, NULL terminated. */
int i, j;
int inBrace = 0;
int line = 1;
z = ReadFileIntoMemory (fileName, 0);
if (z == 0)
{
nError++;
return;
}
for (i = 0; z[i]; i++)
{
switch (z[i])
{
case '\n':
line++;
break;
case '/':
/* This might be a comment. If it is, skip it. */
if (z[i + 1] == '*')
{
int start = line;
i += 2;
while (z[i] && (z[i] != '*' || z[i + 1] != '/'))
{
if (z[i] == '\n')
line++;
i++;
}
if (z[i] == 0)
{
stderr,
"%s: Unterminated comment beginning on line %d\n",
fileName,
start);
nError++;
}
else
{
i++;
}
}
else if (z[i + 1] == '/')
{
while (z[i] && z[i] != '\n')
{
i++;
}
if (z[i])
{
line++;
};
}
break;
case '\'':
{
/* Skip character literals */
int start = line;
for (i++; z[i] && z[i] != '\''; i++)
{
if (z[i] == '\n')
{
stderr,
"%s: Newline in character literal on line %d\n",
fileName,
start);
line++;
}
if (z[i] == '\\')
i++;
}
if (z[i] == 0)
{
stderr,
"%s: unterminate character literal on line %d\n",
fileName,
start);
nError++;
}
break;
}
case '"':
{
/* Skip over a string */
int start = line;
for (i++; z[i] && z[i] != '"'; i++)
{
if (z[i] == '\n')
{
stderr,
"%s: Newline in string literal on line %d\n",
fileName,
start);
line++;
}
if (z[i] == '\\')
i++;
}
if (z[i] == 0)
{
stderr,
"%s: unterminate string literal on line %d\n",
fileName,
start);
nError++;
}
break;
}
case '#':
/* This might be a preprocessor macro such as #if 0 or #endif */
if (i > 0 && z[i - 1] != '\n')
break;
for (j
= i
+ 1; isspace (z
[j
]); j
++)
{
}
if (strncmp (&z
[j
], "endif", 5) == 0)
{
if (ifStack == 0)
{
stderr,
"%s: Unmatched \"#endif\" on line %d\n",
fileName,
line);
nError++;
}
else
{
IfStmt *p = ifStack;
ifStack = p->pNext;
SafeFree (p->zArg);
SafeFree (p);
}
break;
}
if (strncmp (&z
[j
], "else", 4) == 0)
{
if (ifStack == 0)
{
stderr,
"%s: No \"#if\" to pair with \"#else\" on line "
"%d\n",
fileName,
line);
nError++;
}
else
{
ifStack->invert = !ifStack->invert;
}
break;
}
if (z[j] != 'i' || z[j + 1] != 'f')
break;
if (strncmp (&z
[j
+ 2], "ndef", 4) == 0)
{
char *zArg;
int start = line;
i = j + 6;
zArg = GetArg (fileName, z, &i, &line);
PushIf (zArg, start, 1, 1);
SafeFree (zArg);
}
else if (strncmp (&z
[j
+ 2], "def", 3) == 0)
{
char *zArg;
int start = line;
i = j + 5;
zArg = GetArg (fileName, z, &i, &line);
PushIf (zArg, start, 0, 1);
SafeFree (zArg);
}
else
{
char *zArg;
int start = line;
i = j + 2;
zArg = GetArg (fileName, z, &i, &line);
PushIf (zArg, start, 0, 0);
SafeFree (zArg);
}
break;
case '{':
inBrace++;
break;
case '}':
inBrace--;
break;
case 'm':
/* Check main() */
if (inBrace > 0)
break;
if (i > 0 && IsIdent (z[i - 1]))
break;
if (strncmp (&z
[i
], "main", 4) == 0 && !IsIdent
(z
[i
+ 4]))
{
seenMain = IfString (seenMain);
}
case 'E':
/* Check ET_COMMAND_... or Et_AppInit or Et_PreInit */
if (inBrace > 0)
break;
if (i > 0 && IsIdent (z[i - 1]))
break;
if (z
[i
+ 1] == 'T' && strncmp (&z
[i
], "ET_COMMAND_", 11) == 0)
{
EtCmd *p;
for (j = i + 11; IsIdent (z[j]); j++)
{
}
p = SafeMalloc (sizeof (EtCmd));
p->zIf = IfString (0);
p->zName = SafeMalloc (j - (i + 9));
sprintf (p
->zName
, "%.*s", j
- (i
+ 11), &z
[i
+ 11]);
p->pNext = cmdList;
cmdList = p;
nCmd++;
}
else if (z
[i
+ 1] == 'T' && strncmp (&z
[i
], "ET_OBJCOMMAND_", 14) == 0)
{
EtCmd *p;
for (j = i + 14; IsIdent (z[j]); j++)
{
}
p = SafeMalloc (sizeof (EtCmd));
p->zIf = IfString (0);
p->zName = SafeMalloc (j - (i + 9));
p->isObj = 1;
sprintf (p
->zName
, "%.*s", j
- (i
+ 14), &z
[i
+ 14]);
p->pNext = cmdList;
cmdList = p;
nObjCmd++;
}
else if (z[i + 1] == 't')
{
if (strncmp (&z
[i
], "Et_AppInit", 10) == 0 &&
!IsIdent (z[i + 10]))
{
seenEtAppInit = IfString (seenEtAppInit);
}
if (strncmp (&z
[i
], "Et_PreInit", 10) == 0 &&
!IsIdent (z[i + 10]))
{
seenEtPreInit = IfString (seenEtPreInit);
}
if (strncmp (&z
[i
], "Et_CustomMainLoop", 17) == 0 &&
!IsIdent (z[i + 17]))
{
seenEtCustomMainLoop = IfString (seenEtCustomMainLoop);
}
}
break;
default:
/* Do nothing. Continue to the next character */
break;
}
}
SafeFree (z);
while (ifStack)
{
IfStmt *p = ifStack;
fprintf (stderr
, "%s: unterminated \"#if\" on line %d\n", fileName
, p
->line
);
nError++;
ifStack = p->pNext;
SafeFree (p->zArg);
SafeFree (p);
}
}
/*
** Set a macro according to the value of an #if argument.
*/
static void SetMacro (char *zMacroName, char *zIf)
{
if (zIf == 0 || *zIf == 0)
{
printf ("#define %s 1\n", zMacroName
);
}
else if (zIf[0] == '0' && zIf[1] == 0)
{
printf ("#define %s 0\n", zMacroName
);
}
else
{
"#if %s\n"
"# define %s 1\n"
"#else\n"
"# define %s 0\n"
"#endif\n",
zIf,
zMacroName,
zMacroName);
}
}
/* Forward declaration...*/
static void WriteAsString (char *, int);
/*
** Set a string macro to the value given, if that value is not NULL.
*/
static void SetStringMacro (char *zMacroName, char *z)
{
if (z == 0 || *z == 0)
return;
printf ("#define %s ", zMacroName
);
WriteAsString (z, 0);
}
/*
** Look at the name of the file given and see if it is a Tcl file
** or a C or C++ source file. Return TRUE for TCL and FALSE for
** C or C++.
*/
static int IsTclFile (char *zFile)
{
static char *azCSuffix[] = {".c", ".cc", ".C", ".cpp", ".CPP", ".cxx", ".CXX"};
int i;
for (i = 0; i < sizeof (azCSuffix) / sizeof (azCSuffix[0]); i++)
{
int len2
= strlen (azCSuffix
[i
]);
if (len
> len2
&& strcmp (&zFile
[len
- len2
], azCSuffix
[i
]) == 0)
{
return 0;
}
}
return 1;
}
/*
** Compress a TCL script by removing comments and excess white-space
*/
static void CompressTcl (char *z)
{
int i, j, c;
int atLineStart = 1;
for (i = j = 0; (c = z[i]) != 0; i++)
{
switch (c)
{
case ' ':
case '\t':
case '\r':
if (atLineStart)
{
c = 0;
}
break;
case '#':
if (atLineStart
&& !isalpha (z
[i
+ 1]) &&
{
while (z[i] && z[i] != '\n')
{
if (z[i] == '\\')
{
i++;
if (z[i] == '\r' && z[i + 1] == '\n')
{
i++;
}
}
i++;
}
c = 0;
if (z[i] == 0)
{
i--;
}
}
else
{
atLineStart = 0;
}
break;
case '\n':
if (atLineStart)
{
c = 0;
}
else if (
(i > 0 && z[i - 1] == '\\') ||
(i > 1 && z[i - 1] == '\r' && z[i - 2] == '\\'))
{
/* The line continues. Do not compress.
** Compressing here breaks BWidgets... */
}
else
{
atLineStart = 1;
}
break;
default:
atLineStart = 0;
break;
}
if (c != 0)
{
z[j++] = c;
}
}
z[j] = 0;
}
/*
** Write the text of the given file as a string. Tcl-style comments
** are removed if the doCompress flag is true.
*/
static void WriteAsString (char *z, int shroud)
{
int c;
int priorc = 0;
int xor ;
int atLineStart = 1;
if (shroud > 0)
{
xor = shroud;
}
atLineStart = 0;
while ((c = *z) != 0)
{
z++;
if (c == '\r' && *z == '\n')
continue;
if (shroud > 0 && c >= 0x20)
{
c ^= xor;
xor = (xor+1) & 0x1f;
}
if (atLineStart)
{
atLineStart = 0;
}
switch (c)
{
case '?':
/* Prevent two "?" characters in a row, as this causes problems
** for compilers that interpret trigraphs */
if (c == priorc)
{
c = 0;
}
else
{
}
break;
case '"':
case '\\':
break;
case '\n':
atLineStart = 1;
break;
default:
if (c < ' ' || c > '~')
{
}
else
{
}
break;
}
priorc = c;
}
if (!atLineStart)
{
}
}
/*
** The header string.
*/
static char zHeader[] = "/* Automatically generated code */\n"
"/* DO NOT EDIT */\n"
"#ifndef ET_TCLARGS\n"
"#include <tcl.h>\n"
"#ifdef __cplusplus\n"
"# define ET_EXTERN extern \"C\"\n"
"#else\n"
"# define ET_EXTERN extern\n"
"#endif\n"
"ET_EXTERN char *mprintf(const char*,...);\n"
"ET_EXTERN char *vmprintf(const char*,...);\n"
"ET_EXTERN int Et_EvalF(Tcl_Interp*,const char *,...);\n"
"ET_EXTERN int Et_GlobalEvalF(Tcl_Interp*,const char *,...);\n"
"ET_EXTERN int Et_DStringAppendF(Tcl_DString*,const char*,...);\n"
"ET_EXTERN int Et_ResultF(Tcl_Interp*,const char*,...);\n"
"ET_EXTERN int Et_Init(int,char**);\n"
"ET_EXTERN Tcl_Interp *Et_Interp;\n"
"#if TCL_RELEASE_VERSION>=8\n"
"ET_EXTERN int Et_AppendObjF(Tcl_Obj*,const char*,...);\n"
"#endif\n"
"#define ET_TCLARGS "
"ClientData clientData,Tcl_Interp*interp,int argc,char**argv\n"
"#define ET_OBJARGS "
"ClientData clientData,Tcl_Interp*interp,int objc,Tcl_Obj *CONST "
"objv[]\n"
"#endif\n";
/*
** Print a usage comment and die
*/
static void Usage (char *argv0)
{
fprintf (stderr
, "Usage: %s arguments...\n", argv0
);
stderr,
" -version print the version number of mktclapp and exit\n"
" -header print a header file and exit\n"
" -srcdir DIR Prepend DIR to all relative pathnames\n"
" -notk built a Tcl-only program. No GUI\n"
" -extension NAME build a Tcl/Tk extension with the given name\n"
" -autofork automatically fork the program into the background\n"
" -strip-tcl remove comments and extra white-space from\n"
" subsequent TCL files\n"
" -dont-strip-tcl stop stripping TCL files\n"
" -tcl-library DIR directory holding the TCL script library\n"
" -tk-library DIR directory holding the TK script library\n"
" -main-script FILE run the script FILE after initialization\n"
" -read-stdin read standard input\n"
" -console create a console window\n"
" -shroud hide compile-in TCL from view\n"
" -enable-obj use TCL Obj commands where possible\n"
" -standalone make the \"source\" TCL command only work\n"
" for builtin scripts\n"
" -f FILE read more command-line parameters from FILE\n"
" -i FILE make the binary file FILE part of the C code\n"
" *.c scan this file for new TCL commands\n"
" *.tcl compile this file into the generated C code\n");
}
/*
** Read one or more characters form "in" that follow a \ and
** interpret them appropriately. Return the character that
** results from this interpretation.
*/
static int EscapeChar (FILE *in)
{
int c, d;
switch (c)
{
case 'n':
c = '\n';
break;
case 'r':
c = '\r';
break;
case 'f':
c = '\f';
break;
case 't':
c = '\t';
break;
case 'b':
c = '\b';
break;
case 'a':
c = '\a';
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
c -= '0';
if (d < '0' || d > '7')
{
break;
}
c = (c << 3) + (d - '0');
if (d < '0' || d > '7')
{
break;
}
c = (c << 3) + (d - '0');
break;
default:
break;
}
return c;
}
/* MS-Windows and MS-DOS both have the following serious OS bug: the
** length of a command line is severely restricted. But this program
** occasionally requires long command lines. Hence the following
** work around.
**
** If the parameters "-f FILENAME" appear anywhere on the command line,
** then the named file is scanned for additional command line arguments.
** These arguments are substituted in place of the "FILENAME" argument
** in the original argument list.
**
** This first parameter to this routine is the index of the "-f"
** parameter in the argv[] array. The argc and argv are passed by
** pointer so that they can be changed.
**
** Parsing of the parameters in the file is very simple. Parameters
** can be separated by any amount of white-space (including newlines
** and carriage returns.) " and ' can be used for quoting strings
** with embedded spaces. The \ character escapes the following character.
** The length of a token is limited to about 1000 characters.
*/
static void AddParameters (int index, int *pArgc, char ***pArgv)
{
int argc = *pArgc; /* The original argc value */
char **argv = *pArgv; /* The original argv value */
int newArgc; /* Value for argc after inserting new arguments */
char **zNew; /* The new argv after this routine is done */
char *zFile; /* Name of the input file */
int nNew = 0; /* Number of new entries in the argv[] file */
int nAlloc = 0; /* Space allocated for zNew[] */
int i; /* Loop counter */
int n; /* Number of characters in a new argument */
int c; /* Next character of input */
int startOfLine = 1; /* True if we are where '#' can start a comment */
FILE *in; /* The input file */
char zBuf[1000]; /* A single argument is accumulated here */
if (index + 1 == argc)
return;
zFile = argv[index + 1];
if (in == 0)
{
fprintf (stderr
, "Can't open input file \"%s\"\n", zFile
);
}
c = ' ';
while (c != EOF)
{
{
if (c == '\n')
{
startOfLine = 1;
}
if (startOfLine && c == '#')
{
while (c != EOF && c != '\n')
{
}
}
}
n = 0;
if (c == '\'' || c == '"')
{
int quote = c;
startOfLine = 0;
while (c != EOF && c != quote)
{
if (c == '\\')
c = EscapeChar (in);
if (n < sizeof (zBuf) - 1)
{
zBuf[n++] = c;
}
}
if (c != EOF)
}
else
{
{
if (c == '\\')
c = EscapeChar (in);
if (n < sizeof (zBuf) - 1)
{
zBuf[n++] = c;
}
startOfLine = 0;
}
}
zBuf[n] = 0;
if (n > 0)
{
nNew++;
if (nNew + argc >= nAlloc)
{
if (nAlloc == 0)
{
nAlloc = 100 + argc;
zNew
= malloc (sizeof (char *) * nAlloc
);
}
else
{
nAlloc *= 2;
zNew
= realloc (zNew
, sizeof (char *) * nAlloc
);
}
}
if (zNew)
{
int j = nNew + index;
if (zNew[j])
{
}
}
}
}
if (nNew > 0)
{
newArgc = argc + nNew - 1;
for (i = 0; i <= index; i++)
{
zNew[i] = argv[i];
}
}
else
{
zNew = argv;
}
for (i = nNew + index + 1; i < newArgc; i++)
{
zNew[i] = argv[i + 1 - nNew];
}
zNew[newArgc] = 0;
*pArgc = newArgc;
*pArgv = zNew;
}
int main (int argc, char **argv)
{
int i; /* Loop counter */
EtCmd *pCmd; /* A new TCL command found in C code */
int useTk = 1; /* False if the -notk flag is used */
int autoFork = 0; /* True if the -autofork flag is used */
int nTcl = 0; /* Number of TCL scripts */
char **azTcl; /* Name of all TCL scripts */
int *aDoCompress; /* Whether or not to compress each TCL script */
int nData = 0; /* Number of data files */
char **azData; /* Names of all data files */
int doCompress = 1; /* Current state of the compression flag */
char *zTclLib = 0; /* Name of the TCL library */
char *zTkLib = 0; /* Name of the TK library */
char *zMainScript = 0; /* Name of a script to run first */
int shroud = 0; /* True to encrypt the compiled-in TCL */
int readStdin = 0; /* True to read TCL commands from STDIN */
int enableObj = 0; /* Enable the use of object commands */
int standalone = 0; /* True to disable the "source" command */
int stringify = 0; /* True to output only strings of the scripts */
int console = 0; /* True to put up a debugging console */
char *zExtension = 0; /* Name of the extension. NULL if a complete app */
int nHash; /* Number of entries in hash table */
extern char zTail[];
if (argc
>= 2 && strcmp (argv
[1], "-header") == 0)
{
return 0;
}
if (argc
>= 2 && strcmp (argv
[1], "-version") == 0)
{
return 0;
}
azTcl = SafeMalloc (sizeof (char *) * (argc + 100));
azData = SafeMalloc (sizeof (char *) * (argc + 100));
aDoCompress = SafeMalloc (sizeof (int) * (argc + 100));
for (i = 1; i < argc; i++)
{
if (argv[i][0] == '-')
{
if (strcmp (argv
[i
], "-header") == 0)
{
return 0;
}
else if (strcmp (argv
[i
], "-notk") == 0)
{
useTk = 0;
}
else if (i
< argc
- 1 && strcmp (argv
[i
], "-extension") == 0)
{
zExtension = argv[++i];
}
else if (strcmp (argv
[i
], "-autofork") == 0)
{
autoFork = 1;
}
else if (strcmp (argv
[i
], "-read-stdin") == 0)
{
readStdin = 1;
}
else if (strcmp (argv
[i
], "-console") == 0)
{
console = 1;
}
else if (strcmp (argv
[i
], "-shroud") == 0)
{
shroud = 1;
}
else if (strcmp (argv
[i
], "-strip-tcl") == 0)
{
doCompress = 1;
}
else if (strcmp (argv
[i
], "-dont-strip-tcl") == 0)
{
doCompress = 0;
}
else if (strcmp (argv
[i
], "-enable-obj") == 0)
{
enableObj = 1;
}
else if (strcmp (argv
[i
], "-standalone") == 0)
{
standalone = 1;
}
else if (strcmp (argv
[i
], "-stringify") == 0)
{
stringify = 1;
}
else if (i
< argc
- 1 && strcmp (argv
[i
], "-srcdir") == 0)
{
chdir (argv[++i]);
}
else if (i
< argc
- 1 && strcmp (argv
[i
], "-main-script") == 0)
{
zMainScript = argv[++i];
}
else if (i
< argc
- 1 && strcmp (argv
[i
], "-tcl-library") == 0)
{
zTclLib = argv[++i];
}
else if (i
< argc
- 1 && strcmp (argv
[i
], "-tk-library") == 0)
{
zTkLib = argv[++i];
}
else if (i
< argc
- 1 && strcmp (argv
[i
], "-i") == 0)
{
i++;
if (access (argv[i], R_OK))
{
stderr,
"%s: can't open \"%s\" for reading\n",
Argv0,
argv[i]);
nError++;
}
else
{
azData[nData] = argv[i];
}
nData++;
}
else if (strcmp (argv
[i
], "-f") == 0)
{
AddParameters (i, &argc, &argv);
azTcl = SafeRealloc (azTcl, sizeof (char *) * (argc + 100));
azData = SafeRealloc (azData, sizeof (char *) * (argc + 100));
aDoCompress =
SafeRealloc (aDoCompress, sizeof (int) * (argc + 100));
}
else
{
Usage (argv[0]);
}
}
else if (IsTclFile (argv[i]))
{
if (access (argv[i], R_OK))
{
stderr,
"%s: can't open \"%s\" for reading\n",
Argv0,
argv[i]);
nError++;
}
else
{
azTcl[nTcl] = argv[i];
if (len
>= 9 && strcmp (&argv
[i
][len
- 9], "/tclIndex") == 0)
{
aDoCompress[nTcl] = 0;
}
else
{
aDoCompress[nTcl] = doCompress;
}
nTcl++;
}
}
else
{
ScanFile (argv[i]);
}
}
if (nError > 0)
return nError;
if (shroud > 0)
{
shroud
= time (0) % 31 + 1;
}
if (stringify)
{
for (i = 0; i < nTcl; i++)
{
char *z;
z = ReadFileIntoMemory (azTcl[i], 0);
if (z == 0)
continue;
if (aDoCompress[i])
CompressTcl (z);
WriteAsString (z, shroud);
SafeFree (z);
}
return 0;
}
if (nObjCmd > 0)
enableObj = 1;
printf ("/* This code is automatically generated by \"mktclapp\""
" version 3.9 */\n"
"/* DO NOT EDIT */\n"
"#include <tcl.h>\n"
"#define INTERFACE 1\n"
"#if INTERFACE\n"
"#define ET_TCLARGS "
"ClientData clientData,Tcl_Interp*interp,int argc,char**argv\n"
"#define ET_OBJARGS "
"ClientData clientData,Tcl_Interp*interp,int objc,Tcl_Obj*CONST objv[]\n"
"#endif\n");
printf ("#define ET_ENABLE_OBJ %d\n", enableObj
);
printf ("#define ET_ENABLE_TK %d\n", useTk
!= 0);
printf ("#define ET_AUTO_FORK %d\n", autoFork
!= 0);
printf ("#define ET_STANDALONE %d\n", standalone
!= 0);
printf ("#define ET_N_BUILTIN_SCRIPT %d\n", nTcl
);
printf ("#define ET_VERSION \"3.9\"\n");
SetMacro ("ET_HAVE_APPINIT", seenEtAppInit);
SetMacro ("ET_HAVE_PREINIT", seenEtPreInit);
SetMacro ("ET_HAVE_MAIN", seenMain);
SetMacro ("ET_HAVE_CUSTOM_MAINLOOP", seenEtCustomMainLoop);
SetStringMacro ("ET_TCL_LIBRARY", zTclLib);
SetStringMacro ("ET_TK_LIBRARY", zTkLib);
SetStringMacro ("ET_MAIN_SCRIPT", zMainScript);
if (zExtension)
{
int i;
{
zExtension
[0] = toupper (zExtension
[0]);
}
for (i = 1; zExtension[i]; i++)
{
{
zExtension
[i
] = tolower (zExtension
[i
]);
}
}
printf ("#define ET_EXTENSION_NAME %s_Init\n", zExtension
);
printf ("#define ET_SAFE_EXTENSION_NAME %s_SafeInit\n", zExtension
);
printf ("#define ET_EXTENSION 1\n");
}
else
{
printf ("#define ET_EXTENSION 0\n");
}
printf ("#define ET_SHROUD_KEY %d\n", shroud
);
printf ("#define ET_READ_STDIN %d\n", readStdin
);
printf ("#define ET_CONSOLE %d\n", console
);
for (pCmd = cmdList; pCmd; pCmd = pCmd->pNext)
{
if (pCmd->zIf && pCmd->zIf[0] == '0' && pCmd->zIf[1] == 0)
continue;
if (pCmd->isObj)
{
printf ("extern int ET_OBJCOMMAND_%s(ET_OBJARGS);\n", pCmd
->zName
);
}
else
{
printf ("extern int ET_COMMAND_%s(ET_TCLARGS);\n", pCmd
->zName
);
}
}
" char *zName;\n"
" int (*xProc)(ET_TCLARGS);\n"
"} Et_CmdSet[] = {\n");
for (pCmd = cmdList; pCmd; pCmd = pCmd->pNext)
{
char *zProc;
if (pCmd->isObj)
continue;
if (pCmd->zIf)
{
if (pCmd->zIf[0] == '0' && pCmd->zIf[1] == 0)
continue;
printf ("#if %s\n", pCmd
->zIf
);
}
zProc = FuncToProc (pCmd->zName);
printf (" { \"%s\", ET_COMMAND_%s },\n", zProc
, pCmd
->zName
);
SafeFree (zProc);
if (pCmd->zIf)
{
}
}
if (enableObj)
{
char *zProc;
" char *zName;\n"
" int (*xProc)(ET_OBJARGS);\n"
"} Et_ObjSet[] = {\n");
for (pCmd = cmdList; pCmd; pCmd = pCmd->pNext)
{
if (!pCmd->isObj)
continue;
if (pCmd->zIf)
{
if (pCmd->zIf[0] == '0' && pCmd->zIf[1] == 0)
continue;
printf ("#if %s\n", pCmd
->zIf
);
}
zProc = FuncToProc (pCmd->zName);
printf (" { \"%s\", ET_OBJCOMMAND_%s },\n", zProc
, pCmd
->zName
);
SafeFree (zProc);
if (pCmd->zIf)
{
}
}
}
for (i = 0; i < nTcl; i++)
{
char *z;
printf ("static char Et_zFile%d[] = \n", i
);
z = ReadFileIntoMemory (azTcl[i], 0);
if (z == 0)
continue;
if (aDoCompress[i])
CompressTcl (z);
WriteAsString (z, shroud);
SafeFree (z);
}
for (i = 0; i < nData; i++)
{
char *z;
int len, j, col;
printf ("static unsigned char Et_acData%d[] = {\n", i
);
z = ReadFileIntoMemory (azData[i], &len);
if (z == 0)
continue;
for (j = col = 0; j < len; j++)
{
printf (" 0x%02x,", z
[j
] & 0xff);
if (++col >= 12)
{
col = 0;
}
}
if (col > 0)
SafeFree (z);
}
" char *zName;\n"
" char *zData;\n"
" int nData;\n"
" int shrouded;\n"
" struct EtFile *pNext;\n"
"};\n"
"static struct EtFile Et_FileSet[] = {\n");
for (i = 0; i < nTcl; i++)
{
" { \"%s\", Et_zFile%d, sizeof(Et_zFile%d)-1, %d, 0 },\n",
azTcl[i],
i,
i,
shroud);
}
for (i = 0; i < nData; i++)
{
" { \"%s\", Et_acData%d, sizeof(Et_acData%d), 0, 0 },\n",
azData[i],
i,
i);
}
nHash = nTcl * 2 + 1;
if (nHash < 71)
{
nHash = 71;
}
"{0, 0}};\n"
"static struct EtFile *Et_FileHashTable[%d];\n"
"%s",
nHash,
zTail);
return nError;
}
char zTail[] =
"/* The following copyright notice applies to code generated by\n"
"** \"mktclapp\". The \"mktclapp\" program itself is covered by the\n"
"** GNU Public License.\n"
"**\n"
"** Copyright (c) 1998 D. Richard Hipp\n"
"**\n"
"** The author hereby grants permission to use, copy, modify, distribute,\n"
"** and license this software and its documentation for any purpose, provided\n"
"** that existing copyright notices are retained in all copies and that this\n"
"** notice is included verbatim in any distributions. No written agreement,\n"
"** license, or royalty fee is required for any of the authorized uses.\n"
"** Modifications to this software may be copyrighted by their authors\n"
"** and need not follow the licensing terms described here, provided that\n"
"** the new terms are clearly indicated on the first page of each file where\n"
"** they apply.\n"
"**\n"
"** In no event shall the author or the distributors be liable to any party\n"
"** for direct, indirect, special, incidental, or consequential damages\n"
"** arising out of the use of this software, its documentation, or any\n"
"** derivatives thereof, even if the author has been advised of the \n"
"** possibility of such damage. The author and distributors specifically\n"
"** disclaim any warranties, including but not limited to the implied\n"
"** warranties of merchantability, fitness for a particular purpose, and\n"
"** non-infringment. This software is provided at no fee on an\n"
"** \"as is\" basis. The author and/or distritutors have no obligation\n"
"** to provide maintenance, support, updates, enhancements and/or\n"
"** modifications.\n"
"**\n"
"** GOVERNMENT USE: If you are acquiring this software on behalf of the\n"
"** U.S. government, the Government shall have only \"Restricted Rights\"\n"
"** in the software and related documentation as defined in the Federal \n"
"** Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you\n"
"** are acquiring the software on behalf of the Department of Defense, the\n"
"** software shall be classified as \"Commercial Computer Software\" and the\n"
"** Government shall have only \"Restricted Rights\" as defined in Clause\n"
"** 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the\n"
"** author grants the U.S. Government and others acting in its behalf\n"
"** permission to use and distribute the software in accordance with the\n"
"** terms specified in this license. \n"
"*/\n"
"#include <ctype.h>\n"
"#include <string.h>\n"
"#include <stdarg.h>\n"
"#include <stdio.h>\n"
"#include <stdlib.h>\n"
"#include <sys/types.h>\n"
"#include <sys/stat.h>\n"
"#include <fcntl.h>\n"
"\n"
"/* Include either the Tcl or the Tk header file. Use the \"Internal\"\n"
"** version of the header file if and only if we are generating an\n"
"** extension that is linking against the Stub library.\n"
"** Many installations do not have the internal header files\n"
"** available, so using the internal headers only when absolutely\n"
"** necessary will help to reduce compilation problems.\n"
"*/\n"
"#if ET_EXTENSION && defined(TCL_USE_STUBS)\n"
"# if ET_ENABLE_TK\n"
"# include <tkInt.h>\n"
"# else\n"
"# include <tclInt.h>\n"
"# endif\n"
"#else\n"
"# if ET_ENABLE_TK\n"
"# include <tk.h>\n"
"# else\n"
"# include <tcl.h>\n"
"# endif\n"
"#endif\n"
"\n"
"/*\n"
"** ET_WIN32 is true if we are running Tk under windows. The\n"
"** <tcl.h> module will define __WIN32__ for us if we are compiling\n"
"** for windows.\n"
"*/\n"
"#if defined(__WIN32__) && ET_ENABLE_TK\n"
"# define ET_WIN32 1\n"
"# include <windows.h>\n"
"#else\n"
"# define ET_WIN32 0\n"
"#endif\n"
"\n"
"/*\n"
"** Always disable ET_AUTO_FORK under windows. Windows doesn't\n"
"** fork well.\n"
"*/\n"
"#if defined(__WIN32__)\n"
"# undef ET_AUTO_FORK\n"
"# define ET_AUTO_FORK 0\n"
"#endif\n"
"\n"
"/*\n"
"** Omit <unistd.h> under windows. But we need it for Unix.\n"
"*/\n"
"#if !defined(__WIN32__)\n"
"# include <unistd.h>\n"
"#endif\n"
"\n"
"/*\n"
"** The Tcl*InsertProc functions allow the system calls \"stat\",\n"
"** \"access\" and \"open\" to be overloaded. This in turns allows us\n"
"** to substituted compiled-in strings for files in the filesystem.\n"
"** But the Tcl*InsertProc functions are only available in Tcl8.0.3\n"
"** and later.\n"
"**\n"
"** Define the ET_HAVE_INSERTPROC macro if and only if we are dealing\n"
"** with Tcl8.0.3 or later.\n"
"*/\n"
"#if TCL_MAJOR_VERSION==8 && (TCL_MINOR_VERSION>0 || TCL_RELEASE_SERIAL>=3)\n"
"# define ET_HAVE_INSERTPROC\n"
"#endif\n"
"\n"
"/*\n"
"** If we are using the Tcl*InsertProc() functions, we should provide\n"
"** prototypes for them. But the prototypes are in the tclInt.h include\n"
"** file, which we don't want to require the user to have on hand. So\n"
"** we provide our own prototypes here.\n"
"**\n"
"** Note that if TCL_USE_STUBS is defined, then the tclInt.h is required\n"
"** anyway, so these prototypes are not included if TCL_USE_STUBS is\n"
"** defined. \n"
"*/\n"
"#if defined(ET_HAVE_INSERTPROC) && !defined(TCL_USE_STUBS)\n"
"#ifdef __cplusplus\n"
" extern \"C\" int TclStatInsertProc(int (*)(char*, struct stat *));\n"
" extern \"C\" int TclAccessInsertProc(int (*)(char*, int));\n"
" extern \"C\" int TclOpenFileChannelInsertProc(Tcl_Channel (*)(Tcl_Interp*,char*,\n"
" char*,int));\n"
"#else\n"
" extern int TclStatInsertProc(int (*)(char*, struct stat *));\n"
" extern int TclAccessInsertProc(int (*)(char*, int));\n"
" extern int TclOpenFileChannelInsertProc(Tcl_Channel (*)(Tcl_Interp*,char*,\n"
" char*,int));\n"
"#endif\n"
"#endif\n"
"\n"
"\n"
"/*\n"
"** Don't allow Win32 applications to read from stdin. Nor\n"
"** programs that automatically go into the background. Force\n"
"** the use of a console in these cases.\n"
"*/\n"
"#if (ET_WIN32 || ET_AUTO_FORK) && ET_READ_STDIN\n"
"# undef ET_READ_STDIN\n"
"# undef ET_CONSOLE\n"
"# define ET_READ_STDIN 0\n"
"# define ET_CONSOLE 1\n"
"#endif\n"
"\n"
"/*\n"
"** The console won't work without Tk.\n"
"*/\n"
"#if ET_ENABLE_TK==0 && ET_CONSOLE\n"
"# undef ET_CONSOLE\n"
"# define ET_CONSOLE 0\n"
"# undef ET_READ_STDIN\n"
"# define ET_READ_STDIN 1\n"
"#endif\n"
"\n"
"/*\n"
"** Set ET_HAVE_OBJ to true if we are able to link against the\n"
"** new Tcl_Obj interface. This is only the case for Tcl version\n"
"** 8.0 and later.\n"
"*/\n"
"#if ET_ENABLE_OBJ || TCL_MAJOR_VERSION>=8\n"
"# define ET_HAVE_OBJ 1\n"
"#else\n"
"# define ET_HAVE_OBJ 0\n"
"#endif\n"
"\n"
"/*\n"
"** The Tcl_GetByteArrayFromObj() only appears in Tcl version 8.1\n"
"** and later. Substitute Tcl_GetStringFromObj() in Tcl version 8.0.X\n"
"*/\n"
"#if ET_HAVE_OBJ && TCL_MINOR_VERSION==0\n"
"# define Tcl_GetByteArrayFromObj Tcl_GetStringFromObj\n"
"#endif\n"
"\n"
"/*\n"
"** Tcl code to implement the console.\n"
"**\n"
"** This code is written and tested separately, then run through\n"
"** \"mktclapp -stringify\" and then pasted in here.\n"
"*/\n"
"#if ET_ENABLE_TK && !ET_EXTENSION\n"
"static char zEtConsole[] =\n"
"\"proc console:create {w prompt title} {\\n\"\n"
"\"upvar #0 $w.t v\\n\"\n"
"\"if {[winfo exists $w]} {destroy $w}\\n\"\n"
"\"catch {unset v}\\n\"\n"
"\"toplevel $w\\n\"\n"
"\"wm title $w $title\\n\"\n"
"\"wm iconname $w $title\\n\"\n"
"\"frame $w.mb -bd 2 -relief raised\\n\"\n"
"\"pack $w.mb -side top -fill x\\n\"\n"
"\"menubutton $w.mb.file -text File -menu $w.mb.file.m\\n\"\n"
"\"menubutton $w.mb.edit -text Edit -menu $w.mb.edit.m\\n\"\n"
"\"pack $w.mb.file $w.mb.edit -side left -padx 8 -pady 1\\n\"\n"
"\"set m [menu $w.mb.file.m]\\n\"\n"
"\"$m add command -label {Source...} -command \\\"console:SourceFile $w.t\\\"\\n\"\n"
"\"$m add command -label {Save As...} -command \\\"console:SaveFile $w.t\\\"\\n\"\n"
"\"$m add separator\\n\"\n"
"\"$m add command -label {Close} -command \\\"destroy $w\\\"\\n\"\n"
"\"$m add command -label {Exit} -command exit\\n\"\n"
"\"set m [menu $w.mb.edit.m]\\n\"\n"
"\"$m add command -label Cut -command \\\"console:Cut $w.t\\\"\\n\"\n"
"\"$m add command -label Copy -command \\\"console:Copy $w.t\\\"\\n\"\n"
"\"$m add command -label Paste -command \\\"console:Paste $w.t\\\"\\n\"\n"
"\"$m add command -label {Clear Screen} -command \\\"console:Clear $w.t\\\"\\n\"\n"
"\"catch {$m config -postcommand \\\"console:EnableEditMenu $w\\\"}\\n\"\n"
"\"scrollbar $w.sb -orient vertical -command \\\"$w.t yview\\\"\\n\"\n"
"\"pack $w.sb -side right -fill y\\n\"\n"
"\"text $w.t -font fixed -yscrollcommand \\\"$w.sb set\\\"\\n\"\n"
"\"pack $w.t -side right -fill both -expand 1\\n\"\n"
"\"bindtags $w.t Console\\n\"\n"
"\"set v(text) $w.t\\n\"\n"
"\"set v(history) 0\\n\"\n"
"\"set v(historycnt) 0\\n\"\n"
"\"set v(current) -1\\n\"\n"
"\"set v(prompt) $prompt\\n\"\n"
"\"set v(prior) {}\\n\"\n"
"\"set v(plength) [string length $v(prompt)]\\n\"\n"
"\"set v(x) 0\\n\"\n"
"\"set v(y) 0\\n\"\n"
"\"$w.t mark set insert end\\n\"\n"
"\"$w.t tag config ok -foreground blue\\n\"\n"
"\"$w.t tag config err -foreground red\\n\"\n"
"\"$w.t insert end $v(prompt)\\n\"\n"
"\"$w.t mark set out 1.0\\n\"\n"
"\"catch {rename puts console:oldputs$w}\\n\"\n"
"\"proc puts args [format {\\n\"\n"
"\"if {![winfo exists %s]} {\\n\"\n"
"\"rename puts {}\\n\"\n"
"\"rename console:oldputs%s puts\\n\"\n"
"\"return [uplevel #0 puts $args]\\n\"\n"
"\"}\\n\"\n"
"\"switch -glob -- \\\"[llength $args] $args\\\" {\\n\"\n"
"\"{1 *} {\\n\"\n"
"\"set msg [lindex $args 0]\\\\n\\n\"\n"
"\"set tag ok\\n\"\n"
"\"}\\n\"\n"
"\"{2 stdout *} {\\n\"\n"
"\"set msg [lindex $args 1]\\\\n\\n\"\n"
"\"set tag ok\\n\"\n"
"\"}\\n\"\n"
"\"{2 stderr *} {\\n\"\n"
"\"set msg [lindex $args 1]\\\\n\\n\"\n"
"\"set tag err\\n\"\n"
"\"}\\n\"\n"
"\"{2 -nonewline *} {\\n\"\n"
"\"set msg [lindex $args 1]\\n\"\n"
"\"set tag ok\\n\"\n"
"\"}\\n\"\n"
"\"{3 -nonewline stdout *} {\\n\"\n"
"\"set msg [lindex $args 2]\\n\"\n"
"\"set tag ok\\n\"\n"
"\"}\\n\"\n"
"\"{3 -nonewline stderr *} {\\n\"\n"
"\"set msg [lindex $args 2]\\n\"\n"
"\"set tag err\\n\"\n"
"\"}\\n\"\n"
"\"default {\\n\"\n"
"\"uplevel #0 console:oldputs%s $args\\n\"\n"
"\"return\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"console:Puts %s $msg $tag\\n\"\n"
"\"} $w $w $w $w.t]\\n\"\n"
"\"after idle \\\"focus $w.t\\\"\\n\"\n"
"\"}\\n\"\n"
"\"bind Console <1> {console:Button1 %W %x %y}\\n\"\n"
"\"bind Console <B1-Motion> {console:B1Motion %W %x %y}\\n\"\n"
"\"bind Console <B1-Leave> {console:B1Leave %W %x %y}\\n\"\n"
"\"bind Console <B1-Enter> {console:cancelMotor %W}\\n\"\n"
"\"bind Console <ButtonRelease-1> {console:cancelMotor %W}\\n\"\n"
"\"bind Console <KeyPress> {console:Insert %W %A}\\n\"\n"
"\"bind Console <Left> {console:Left %W}\\n\"\n"
"\"bind Console <Control-b> {console:Left %W}\\n\"\n"
"\"bind Console <Right> {console:Right %W}\\n\"\n"
"\"bind Console <Control-f> {console:Right %W}\\n\"\n"
"\"bind Console <BackSpace> {console:Backspace %W}\\n\"\n"
"\"bind Console <Control-h> {console:Backspace %W}\\n\"\n"
"\"bind Console <Delete> {console:Delete %W}\\n\"\n"
"\"bind Console <Control-d> {console:Delete %W}\\n\"\n"
"\"bind Console <Home> {console:Home %W}\\n\"\n"
"\"bind Console <Control-a> {console:Home %W}\\n\"\n"
"\"bind Console <End> {console:End %W}\\n\"\n"
"\"bind Console <Control-e> {console:End %W}\\n\"\n"
"\"bind Console <Return> {console:Enter %W}\\n\"\n"
"\"bind Console <KP_Enter> {console:Enter %W}\\n\"\n"
"\"bind Console <Up> {console:Prior %W}\\n\"\n"
"\"bind Console <Control-p> {console:Prior %W}\\n\"\n"
"\"bind Console <Down> {console:Next %W}\\n\"\n"
"\"bind Console <Control-n> {console:Next %W}\\n\"\n"
"\"bind Console <Control-k> {console:EraseEOL %W}\\n\"\n"
"\"bind Console <<Cut>> {console:Cut %W}\\n\"\n"
"\"bind Console <<Copy>> {console:Copy %W}\\n\"\n"
"\"bind Console <<Paste>> {console:Paste %W}\\n\"\n"
"\"bind Console <<Clear>> {console:Clear %W}\\n\"\n"
"\"proc console:Puts {w t tag} {\\n\"\n"
"\"set nc [string length $t]\\n\"\n"
"\"set endc [string index $t [expr $nc-1]]\\n\"\n"
"\"if {$endc==\\\"\\\\n\\\"} {\\n\"\n"
"\"if {[$w index out]<[$w index {insert linestart}]} {\\n\"\n"
"\"$w insert out [string range $t 0 [expr $nc-2]] $tag\\n\"\n"
"\"$w mark set out {out linestart +1 lines}\\n\"\n"
"\"} else {\\n\"\n"
"\"$w insert out $t $tag\\n\"\n"
"\"}\\n\"\n"
"\"} else {\\n\"\n"
"\"if {[$w index out]<[$w index {insert linestart}]} {\\n\"\n"
"\"$w insert out $t $tag\\n\"\n"
"\"} else {\\n\"\n"
"\"$w insert out $t\\\\n $tag\\n\"\n"
"\"$w mark set out {out -1 char}\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"$w yview insert\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Insert {w a} {\\n\"\n"
"\"$w insert insert $a\\n\"\n"
"\"$w yview insert\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Left {w} {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"scan [$w index insert] %d.%d row col\\n\"\n"
"\"if {$col>$v(plength)} {\\n\"\n"
"\"$w mark set insert \\\"insert -1c\\\"\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Backspace {w} {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"scan [$w index insert] %d.%d row col\\n\"\n"
"\"if {$col>$v(plength)} {\\n\"\n"
"\"$w delete {insert -1c}\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:EraseEOL {w} {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"scan [$w index insert] %d.%d row col\\n\"\n"
"\"if {$col>=$v(plength)} {\\n\"\n"
"\"$w delete insert {insert lineend}\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Right {w} {\\n\"\n"
"\"$w mark set insert \\\"insert +1c\\\"\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Delete w {\\n\"\n"
"\"$w delete insert\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Home w {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"scan [$w index insert] %d.%d row col\\n\"\n"
"\"$w mark set insert $row.$v(plength)\\n\"\n"
"\"}\\n\"\n"
"\"proc console:End w {\\n\"\n"
"\"$w mark set insert {insert lineend}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Enter w {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"scan [$w index insert] %d.%d row col\\n\"\n"
"\"set start $row.$v(plength)\\n\"\n"
"\"set line [$w get $start \\\"$start lineend\\\"]\\n\"\n"
"\"if {$v(historycnt)>0} {\\n\"\n"
"\"set last [lindex $v(history) [expr $v(historycnt)-1]]\\n\"\n"
"\"if {[string compare $last $line]} {\\n\"\n"
"\"lappend v(history) $line\\n\"\n"
"\"incr v(historycnt)\\n\"\n"
"\"}\\n\"\n"
"\"} else {\\n\"\n"
"\"set v(history) [list $line]\\n\"\n"
"\"set v(historycnt) 1\\n\"\n"
"\"}\\n\"\n"
"\"set v(current) $v(historycnt)\\n\"\n"
"\"$w insert end \\\\n\\n\"\n"
"\"$w mark set out end\\n\"\n"
"\"if {$v(prior)==\\\"\\\"} {\\n\"\n"
"\"set cmd $line\\n\"\n"
"\"} else {\\n\"\n"
"\"set cmd $v(prior)\\\\n$line\\n\"\n"
"\"}\\n\"\n"
"\"if {[info complete $cmd]} {\\n\"\n"
"\"set rc [catch {uplevel #0 $cmd} res]\\n\"\n"
"\"if {![winfo exists $w]} return\\n\"\n"
"\"if {$rc} {\\n\"\n"
"\"$w insert end $res\\\\n err\\n\"\n"
"\"} elseif {[string length $res]>0} {\\n\"\n"
"\"$w insert end $res\\\\n ok\\n\"\n"
"\"}\\n\"\n"
"\"set v(prior) {}\\n\"\n"
"\"$w insert end $v(prompt)\\n\"\n"
"\"} else {\\n\"\n"
"\"set v(prior) $cmd\\n\"\n"
"\"regsub -all {[^ ]} $v(prompt) . x\\n\"\n"
"\"$w insert end $x\\n\"\n"
"\"}\\n\"\n"
"\"$w mark set insert end\\n\"\n"
"\"$w mark set out {insert linestart}\\n\"\n"
"\"$w yview insert\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Prior w {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"if {$v(current)<=0} return\\n\"\n"
"\"incr v(current) -1\\n\"\n"
"\"set line [lindex $v(history) $v(current)]\\n\"\n"
"\"console:SetLine $w $line\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Next w {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"if {$v(current)>=$v(historycnt)} return\\n\"\n"
"\"incr v(current) 1\\n\"\n"
"\"set line [lindex $v(history) $v(current)]\\n\"\n"
"\"console:SetLine $w $line\\n\"\n"
"\"}\\n\"\n"
"\"proc console:SetLine {w line} {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"scan [$w index insert] %d.%d row col\\n\"\n"
"\"set start $row.$v(plength)\\n\"\n"
"\"$w delete $start end\\n\"\n"
"\"$w insert end $line\\n\"\n"
"\"$w mark set insert end\\n\"\n"
"\"$w yview insert\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Button1 {w x y} {\\n\"\n"
"\"global tkPriv\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"set v(mouseMoved) 0\\n\"\n"
"\"set v(pressX) $x\\n\"\n"
"\"set p [console:nearestBoundry $w $x $y]\\n\"\n"
"\"scan [$w index insert] %d.%d ix iy\\n\"\n"
"\"scan $p %d.%d px py\\n\"\n"
"\"if {$px==$ix} {\\n\"\n"
"\"$w mark set insert $p\\n\"\n"
"\"}\\n\"\n"
"\"$w mark set anchor $p\\n\"\n"
"\"focus $w\\n\"\n"
"\"}\\n\"\n"
"\"proc console:nearestBoundry {w x y} {\\n\"\n"
"\"set p [$w index @$x,$y]\\n\"\n"
"\"set bb [$w bbox $p]\\n\"\n"
"\"if {![string compare $bb \\\"\\\"]} {return $p}\\n\"\n"
"\"if {($x-[lindex $bb 0])<([lindex $bb 2]/2)} {return $p}\\n\"\n"
"\"$w index \\\"$p + 1 char\\\"\\n\"\n"
"\"}\\n\"\n"
"\"proc console:SelectTo {w x y} {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"set cur [console:nearestBoundry $w $x $y]\\n\"\n"
"\"if {[catch {$w index anchor}]} {\\n\"\n"
"\"$w mark set anchor $cur\\n\"\n"
"\"}\\n\"\n"
"\"set anchor [$w index anchor]\\n\"\n"
"\"if {[$w compare $cur != $anchor] || (abs($v(pressX) - $x) >= 3)} {\\n\"\n"
"\"if {$v(mouseMoved)==0} {\\n\"\n"
"\"$w tag remove sel 0.0 end\\n\"\n"
"\"}\\n\"\n"
"\"set v(mouseMoved) 1\\n\"\n"
"\"}\\n\"\n"
"\"if {[$w compare $cur < anchor]} {\\n\"\n"
"\"set first $cur\\n\"\n"
"\"set last anchor\\n\"\n"
"\"} else {\\n\"\n"
"\"set first anchor\\n\"\n"
"\"set last $cur\\n\"\n"
"\"}\\n\"\n"
"\"if {$v(mouseMoved)} {\\n\"\n"
"\"$w tag remove sel 0.0 $first\\n\"\n"
"\"$w tag add sel $first $last\\n\"\n"
"\"$w tag remove sel $last end\\n\"\n"
"\"update idletasks\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:B1Motion {w x y} {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"set v(y) $y\\n\"\n"
"\"set v(x) $x\\n\"\n"
"\"console:SelectTo $w $x $y\\n\"\n"
"\"}\\n\"\n"
"\"proc console:B1Leave {w x y} {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"set v(y) $y\\n\"\n"
"\"set v(x) $x\\n\"\n"
"\"console:motor $w\\n\"\n"
"\"}\\n\"\n"
"\"proc console:motor w {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"if {![winfo exists $w]} return\\n\"\n"
"\"if {$v(y)>=[winfo height $w]} {\\n\"\n"
"\"$w yview scroll 1 units\\n\"\n"
"\"} elseif {$v(y)<0} {\\n\"\n"
"\"$w yview scroll -1 units\\n\"\n"
"\"} else {\\n\"\n"
"\"return\\n\"\n"
"\"}\\n\"\n"
"\"console:SelectTo $w $v(x) $v(y)\\n\"\n"
"\"set v(timer) [after 50 console:motor $w]\\n\"\n"
"\"}\\n\"\n"
"\"proc console:cancelMotor w {\\n\"\n"
"\"upvar #0 $w v\\n\"\n"
"\"catch {after cancel $v(timer)}\\n\"\n"
"\"catch {unset v(timer)}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Copy w {\\n\"\n"
"\"if {![catch {set text [$w get sel.first sel.last]}]} {\\n\"\n"
"\"clipboard clear -displayof $w\\n\"\n"
"\"clipboard append -displayof $w $text\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:canCut w {\\n\"\n"
"\"set r [catch {\\n\"\n"
"\"scan [$w index sel.first] %d.%d s1x s1y\\n\"\n"
"\"scan [$w index sel.last] %d.%d s2x s2y\\n\"\n"
"\"scan [$w index insert] %d.%d ix iy\\n\"\n"
"\"}]\\n\"\n"
"\"if {$r==1} {return 0}\\n\"\n"
"\"if {$s1x==$ix && $s2x==$ix} {return 1}\\n\"\n"
"\"return 2\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Cut w {\\n\"\n"
"\"if {[console:canCut $w]==1} {\\n\"\n"
"\"console:Copy $w\\n\"\n"
"\"$w delete sel.first sel.last\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Paste w {\\n\"\n"
"\"if {[console:canCut $w]==1} {\\n\"\n"
"\"$w delete sel.first sel.last\\n\"\n"
"\"}\\n\"\n"
"\"if {[catch {selection get -displayof $w -selection CLIPBOARD} topaste]} {\\n\"\n"
"\"return\\n\"\n"
"\"}\\n\"\n"
"\"set prior 0\\n\"\n"
"\"foreach line [split $topaste \\\\n] {\\n\"\n"
"\"if {$prior} {\\n\"\n"
"\"console:Enter $w\\n\"\n"
"\"update\\n\"\n"
"\"}\\n\"\n"
"\"set prior 1\\n\"\n"
"\"$w insert insert $line\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:EnableEditMenu w {\\n\"\n"
"\"set m $w.mb.edit.m\\n\"\n"
"\"switch [console:canCut $w.t] {\\n\"\n"
"\"0 {\\n\"\n"
"\"$m entryconf Copy -state disabled\\n\"\n"
"\"$m entryconf Cut -state disabled\\n\"\n"
"\"}\\n\"\n"
"\"1 {\\n\"\n"
"\"$m entryconf Copy -state normal\\n\"\n"
"\"$m entryconf Cut -state normal\\n\"\n"
"\"}\\n\"\n"
"\"2 {\\n\"\n"
"\"$m entryconf Copy -state normal\\n\"\n"
"\"$m entryconf Cut -state disabled\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:SourceFile w {\\n\"\n"
"\"set types {\\n\"\n"
"\"{{TCL Scripts} {.tcl}}\\n\"\n"
"\"{{All Files} *}\\n\"\n"
"\"}\\n\"\n"
"\"set f [tk_getOpenFile -filetypes $types -title \\\"TCL Script To Source...\\\"]\\n\"\n"
"\"if {$f!=\\\"\\\"} {\\n\"\n"
"\"uplevel #0 source $f\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:SaveFile w {\\n\"\n"
"\"set types {\\n\"\n"
"\"{{Text Files} {.txt}}\\n\"\n"
"\"{{All Files} *}\\n\"\n"
"\"}\\n\"\n"
"\"set f [tk_getSaveFile -filetypes $types -title \\\"Write Screen To...\\\"]\\n\"\n"
"\"if {$f!=\\\"\\\"} {\\n\"\n"
"\"if {[catch {open $f w} fd]} {\\n\"\n"
"\"tk_messageBox -type ok -icon error -message $fd\\n\"\n"
"\"} else {\\n\"\n"
"\"puts $fd [string trimright [$w get 1.0 end] \\\\n]\\n\"\n"
"\"close $fd\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"}\\n\"\n"
"\"proc console:Clear w {\\n\"\n"
"\"$w delete 1.0 {insert linestart}\\n\"\n"
"\"}\\n\"\n"
"; /* End of the console code */\n"
"#endif /* ET_ENABLE_TK */\n"
"\n"
"/*\n"
"** The \"printf\" code that follows dates from the 1980's. It is in\n"
"** the public domain. The original comments are included here for\n"
"** completeness. They are slightly out-of-date.\n"
"**\n"
"** The following modules is an enhanced replacement for the \"printf\" programs\n"
"** found in the standard library. The following enhancements are\n"
"** supported:\n"
"**\n"
"** + Additional functions. The standard set of \"printf\" functions\n"
"** includes printf, fprintf, sprintf, vprintf, vfprintf, and\n"
"** vsprintf. This module adds the following:\n"
"**\n"
"** * snprintf -- Works like sprintf, but has an extra argument\n"
"** which is the size of the buffer written to.\n"
"**\n"
"** * mprintf -- Similar to sprintf. Writes output to memory\n"
"** obtained from malloc.\n"
"**\n"
"** * xprintf -- Calls a function to dispose of output.\n"
"**\n"
"** * nprintf -- No output, but returns the number of characters\n"
"** that would have been output by printf.\n"
"**\n"
"** * A v- version (ex: vsnprintf) of every function is also\n"
"** supplied.\n"
"**\n"
"** + A few extensions to the formatting notation are supported:\n"
"**\n"
"** * The \"=\" flag (similar to \"-\") causes the output to be\n"
"** be centered in the appropriately sized field.\n"
"**\n"
"** * The %b field outputs an integer in binary notation.\n"
"**\n"
"** * The %c field now accepts a precision. The character output\n"
"** is repeated by the number of times the precision specifies.\n"
"**\n"
"** * The %' field works like %c, but takes as its character the\n"
"** next character of the format string, instead of the next\n"
"** argument. For example, printf(\"%.78'-\") prints 78 minus\n"
"** signs, the same as printf(\"%.78c\",'-').\n"
"**\n"
"** + When compiled using GCC on a SPARC, this version of printf is\n"
"** faster than the library printf for SUN OS 4.1.\n"
"**\n"
"** + All functions are fully reentrant.\n"
"**\n"
"*/\n"
"/*\n"
"** Undefine COMPATIBILITY to make some slight changes in the way things\n"
"** work. I think the changes are an improvement, but they are not\n"
"** backwards compatible.\n"
"*/\n"
"/* #define COMPATIBILITY / * Compatible with SUN OS 4.1 */\n"
"\n"
"/*\n"
"** Characters that need to be escaped inside a TCL string.\n"
"*/\n"
"static char NeedEsc[] = {\n"
" 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,\n"
" 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n"
" 0, 0, '\"', 0, '$', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n"
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n"
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n"
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[','\\\\', ']', 0, 0,\n"
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n"
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1,\n"
" 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n"
" 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n"
" 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n"
" 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n"
" 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n"
" 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n"
" 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n"
" 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,\n"
"};\n"
"\n"
"/*\n"
"** Conversion types fall into various categories as defined by the\n"
"** following enumeration.\n"
"*/\n"
"enum et_type { /* The type of the format field */\n"
" etRADIX, /* Integer types. %d, %x, %o, and so forth */\n"
" etFLOAT, /* Floating point. %f */\n"
" etEXP, /* Exponentional notation. %e and %E */\n"
" etGENERIC, /* Floating or exponential, depending on exponent. %g */\n"
" etSIZE, /* Return number of characters processed so far. %n */\n"
" etSTRING, /* Strings. %s */\n"
" etPERCENT, /* Percent symbol. %% */\n"
" etCHARX, /* Characters. %c */\n"
" etERROR, /* Used to indicate no such conversion type */\n"
"/* The rest are extensions, not normally found in printf() */\n"
" etCHARLIT, /* Literal characters. %' */\n"
" etTCLESCAPE, /* Strings with special characters escaped. %q */\n"
" etMEMSTRING, /* A string which should be deleted after use. %z */\n"
" etORDINAL /* 1st, 2nd, 3rd and so forth */\n"
"};\n"
"\n"
"/*\n"
"** Each builtin conversion character (ex: the 'd' in \"%d\") is described\n"
"** by an instance of the following structure\n"
"*/\n"
"typedef struct et_info { /* Information about each format field */\n"
" int fmttype; /* The format field code letter */\n"
" int base; /* The base for radix conversion */\n"
" char *charset; /* The character set for conversion */\n"
" int flag_signed; /* Is the quantity signed? */\n"
" char *prefix; /* Prefix on non-zero values in alt format */\n"
" enum et_type type; /* Conversion paradigm */\n"
"} et_info;\n"
"\n"
"/*\n"
"** The following table is searched linearly, so it is good to put the\n"
"** most frequently used conversion types first.\n"
"*/\n"
"static et_info fmtinfo[] = {\n"
" { 'd', 10, \"0123456789\", 1, 0, etRADIX, },\n"
" { 's', 0, 0, 0, 0, etSTRING, }, \n"
" { 'q', 0, 0, 0, 0, etTCLESCAPE, },\n"
" { 'z', 0, 0, 0, 0, etMEMSTRING, },\n"
" { 'c', 0, 0, 0, 0, etCHARX, },\n"
" { 'o', 8, \"01234567\", 0, \"0\", etRADIX, },\n"
" { 'u', 10, \"0123456789\", 0, 0, etRADIX, },\n"
" { 'x', 16, \"0123456789abcdef\", 0, \"x0\", etRADIX, },\n"
" { 'X', 16, \"0123456789ABCDEF\", 0, \"X0\", etRADIX, },\n"
" { 'r', 10, \"0123456789\", 0, 0, etORDINAL, },\n"
" { 'f', 0, 0, 1, 0, etFLOAT, },\n"
" { 'e', 0, \"e\", 1, 0, etEXP, },\n"
" { 'E', 0, \"E\", 1, 0, etEXP, },\n"
" { 'g', 0, \"e\", 1, 0, etGENERIC, },\n"
" { 'G', 0, \"E\", 1, 0, etGENERIC, },\n"
" { 'i', 10, \"0123456789\", 1, 0, etRADIX, },\n"
" { 'n', 0, 0, 0, 0, etSIZE, },\n"
" { '%', 0, 0, 0, 0, etPERCENT, },\n"
" { 'b', 2, \"01\", 0, \"b0\", etRADIX, }, /* Binary */\n"
" { 'p', 10, \"0123456789\", 0, 0, etRADIX, }, /* Pointers */\n"
" { '\\'', 0, 0, 0, 0, etCHARLIT, }, /* Literal char */\n"
"};\n"
"#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0]))\n"
"\n"
"/*\n"
"** If NOFLOATINGPOINT is defined, then none of the floating point\n"
"** conversions will work.\n"
"*/\n"
"#ifndef etNOFLOATINGPOINT\n"
"/*\n"
"** \"*val\" is a double such that 0.1 <= *val < 10.0\n"
"** Return the ascii code for the leading digit of *val, then\n"
"** multiply \"*val\" by 10.0 to renormalize.\n"
"**\n"
"** Example:\n"
"** input: *val = 3.14159\n"
"** output: *val = 1.4159 function return = '3'\n"
"**\n"
"** The counter *cnt is incremented each time. After counter exceeds\n"
"** 16 (the number of significant digits in a 64-bit float) '0' is\n"
"** always returned.\n"
"*/\n"
"static int et_getdigit(double *val, int *cnt){\n"
" int digit;\n"
" double d;\n"
" if( (*cnt)++ >= 16 ) return '0';\n"
" digit = (int)*val;\n"
" d = digit;\n"
" digit += '0';\n"
" *val = (*val - d)*10.0;\n"
" return digit;\n"
"}\n"
"#endif\n"
"\n"
"#define etBUFSIZE 1000 /* Size of the output buffer */\n"
"\n"
"/*\n"
"** The root program. All variations call this core.\n"
"**\n"
"** INPUTS:\n"
"** func This is a pointer to a function taking three arguments\n"
"** 1. A pointer to anything. Same as the \"arg\" parameter.\n"
"** 2. A pointer to the list of characters to be output\n"
"** (Note, this list is NOT null terminated.)\n"
"** 3. An integer number of characters to be output.\n"
"** (Note: This number might be zero.)\n"
"**\n"
"** arg This is the pointer to anything which will be passed as the\n"
"** first argument to \"func\". Use it for whatever you like.\n"
"**\n"
"** fmt This is the format string, as in the usual print.\n"
"**\n"
"** ap This is a pointer to a list of arguments. Same as in\n"
"** vfprint.\n"
"**\n"
"** OUTPUTS:\n"
"** The return value is the total number of characters sent to\n"
"** the function \"func\". Returns -1 on a error.\n"
"**\n"
"** Note that the order in which automatic variables are declared below\n"
"** seems to make a big difference in determining how fast this beast\n"
"** will run.\n"
"*/\n"
"int vxprintf(\n"
" void (*func)(void*,char*,int),\n"
" void *arg,\n"
" const char *format,\n"
" va_list ap\n"
"){\n"
" register const char *fmt; /* The format string. */\n"
" register int c; /* Next character in the format string */\n"
" register char *bufpt; /* Pointer to the conversion buffer */\n"
" register int precision; /* Precision of the current field */\n"
" register int length; /* Length of the field */\n"
" register int idx; /* A general purpose loop counter */\n"
" int count; /* Total number of characters output */\n"
" int width; /* Width of the current field */\n"
" int flag_leftjustify; /* True if \"-\" flag is present */\n"
" int flag_plussign; /* True if \"+\" flag is present */\n"
" int flag_blanksign; /* True if \" \" flag is present */\n"
" int flag_alternateform; /* True if \"#\" flag is present */\n"
" int flag_zeropad; /* True if field width constant starts with zero */\n"
" int flag_long; /* True if \"l\" flag is present */\n"
" int flag_center; /* True if \"=\" flag is present */\n"
" unsigned long longvalue; /* Value for integer types */\n"
" double realvalue; /* Value for real types */\n"
" et_info *infop; /* Pointer to the appropriate info structure */\n"
" char buf[etBUFSIZE]; /* Conversion buffer */\n"
" char prefix; /* Prefix character. \"+\" or \"-\" or \" \" or '\\0'. */\n"
" int errorflag = 0; /* True if an error is encountered */\n"
" enum et_type xtype; /* Conversion paradigm */\n"
" char *zMem; /* String to be freed */\n"
" char *zExtra; /* Extra memory used for etTCLESCAPE conversions */\n"
" static char spaces[] = \" \"\n"
" \" \";\n"
"#define etSPACESIZE (sizeof(spaces)-1)\n"
"#ifndef etNOFLOATINGPOINT\n"
" int exp; /* exponent of real numbers */\n"
" double rounder; /* Used for rounding floating point values */\n"
" int flag_dp; /* True if decimal point should be shown */\n"
" int flag_rtz; /* True if trailing zeros should be removed */\n"
" int flag_exp; /* True to force display of the exponent */\n"
" int nsd; /* Number of significant digits returned */\n"
"#endif\n"
"\n"
" fmt = format; /* Put in a register for speed */\n"
" count = length = 0;\n"
" bufpt = 0;\n"
" for(; (c=(*fmt))!=0; ++fmt){\n"
" if( c!='%' ){\n"
" register int amt;\n"
" bufpt = (char *)fmt;\n"
" amt = 1;\n"
" while( (c=(*++fmt))!='%' && c!=0 ) amt++;\n"
" (*func)(arg,bufpt,amt);\n"
" count += amt;\n"
" if( c==0 ) break;\n"
" }\n"
" if( (c=(*++fmt))==0 ){\n"
" errorflag = 1;\n"
" (*func)(arg,\"%\",1);\n"
" count++;\n"
" break;\n"
" }\n"
" /* Find out what flags are present */\n"
" flag_leftjustify = flag_plussign = flag_blanksign = \n"
" flag_alternateform = flag_zeropad = flag_center = 0;\n"
" do{\n"
" switch( c ){\n"
" case '-': flag_leftjustify = 1; c = 0; break;\n"
" case '+': flag_plussign = 1; c = 0; break;\n"
" case ' ': flag_blanksign = 1; c = 0; break;\n"
" case '#': flag_alternateform = 1; c = 0; break;\n"
" case '0': flag_zeropad = 1; c = 0; break;\n"
" case '=': flag_center = 1; c = 0; break;\n"
" default: break;\n"
" }\n"
" }while( c==0 && (c=(*++fmt))!=0 );\n"
" if( flag_center ) flag_leftjustify = 0;\n"
" /* Get the field width */\n"
" width = 0;\n"
" if( c=='*' ){\n"
" width = va_arg(ap,int);\n"
" if( width<0 ){\n"
" flag_leftjustify = 1;\n"
" width = -width;\n"
" }\n"
" c = *++fmt;\n"
" }else{\n"
" while( isdigit(c) ){\n"
" width = width*10 + c - '0';\n"
" c = *++fmt;\n"
" }\n"
" }\n"
" if( width > etBUFSIZE-10 ){\n"
" width = etBUFSIZE-10;\n"
" }\n"
" /* Get the precision */\n"
" if( c=='.' ){\n"
" precision = 0;\n"
" c = *++fmt;\n"
" if( c=='*' ){\n"
" precision = va_arg(ap,int);\n"
"#ifndef etCOMPATIBILITY\n"
" /* This is sensible, but SUN OS 4.1 doesn't do it. */\n"
" if( precision<0 ) precision = -precision;\n"
"#endif\n"
" c = *++fmt;\n"
" }else{\n"
" while( isdigit(c) ){\n"
" precision = precision*10 + c - '0';\n"
" c = *++fmt;\n"
" }\n"
" }\n"
" /* Limit the precision to prevent overflowing buf[] during conversion */\n"
" if( precision>etBUFSIZE-40 ) precision = etBUFSIZE-40;\n"
" }else{\n"
" precision = -1;\n"
" }\n"
" /* Get the conversion type modifier */\n"
" if( c=='l' ){\n"
" flag_long = 1;\n"
" c = *++fmt;\n"
" }else{\n"
" flag_long = 0;\n"
" }\n"
" /* Fetch the info entry for the field */\n"
" infop = 0;\n"
" for(idx=0; idx<etNINFO; idx++){\n"
" if( c==fmtinfo[idx].fmttype ){\n"
" infop = &fmtinfo[idx];\n"
" break;\n"
" }\n"
" }\n"
" /* No info entry found. It must be an error. */\n"
" if( infop==0 ){\n"
" xtype = etERROR;\n"
" }else{\n"
" xtype = infop->type;\n"
" }\n"
" zExtra = 0;\n"
"\n"
" /*\n"
" ** At this point, variables are initialized as follows:\n"
" **\n"
" ** flag_alternateform TRUE if a '#' is present.\n"
" ** flag_plussign TRUE if a '+' is present.\n"
" ** flag_leftjustify TRUE if a '-' is present or if the\n"
" ** field width was negative.\n"
" ** flag_zeropad TRUE if the width began with 0.\n"
" ** flag_long TRUE if the letter 'l' (ell) prefixed\n"
" ** the conversion character.\n"
" ** flag_blanksign TRUE if a ' ' is present.\n"
" ** width The specified field width. This is\n"
" ** always non-negative. Zero is the default.\n"
" ** precision The specified precision. The default\n"
" ** is -1.\n"
" ** xtype The class of the conversion.\n"
" ** infop Pointer to the appropriate info struct.\n"
" */\n"
" switch( xtype ){\n"
" case etORDINAL:\n"
" case etRADIX:\n"
" if( flag_long ) longvalue = va_arg(ap,long);\n"
" else longvalue = va_arg(ap,int);\n"
"#ifdef etCOMPATIBILITY\n"
" /* For the format %#x, the value zero is printed \"0\" not \"0x0\".\n"
" ** I think this is stupid. */\n"
" if( longvalue==0 ) flag_alternateform = 0;\n"
"#else\n"
" /* More sensible: turn off the prefix for octal (to prevent \"00\"),\n"
" ** but leave the prefix for hex. */\n"
" if( longvalue==0 && infop->base==8 ) flag_alternateform = 0;\n"
"#endif\n"
" if( infop->flag_signed ){\n"
" if( *(long*)&longvalue<0 ){\n"
" longvalue = -*(long*)&longvalue;\n"
" prefix = '-';\n"
" }else if( flag_plussign ) prefix = '+';\n"
" else if( flag_blanksign ) prefix = ' ';\n"
" else prefix = 0;\n"
" }else prefix = 0;\n"
" if( flag_zeropad && precision<width-(prefix!=0) ){\n"
" precision = width-(prefix!=0);\n"
" }\n"
" bufpt = &buf[etBUFSIZE];\n"
" if( xtype==etORDINAL ){\n"
" long a,b;\n"
" a = longvalue%10;\n"
" b = longvalue%100;\n"
" bufpt -= 2;\n"
" if( a==0 || a>3 || (b>10 && b<14) ){\n"
" bufpt[0] = 't';\n"
" bufpt[1] = 'h';\n"
" }else if( a==1 ){\n"
" bufpt[0] = 's';\n"
" bufpt[1] = 't';\n"
" }else if( a==2 ){\n"
" bufpt[0] = 'n';\n"
" bufpt[1] = 'd';\n"
" }else if( a==3 ){\n"
" bufpt[0] = 'r';\n"
" bufpt[1] = 'd';\n"
" }\n"
" }\n"
" {\n"
" register char *cset; /* Use registers for speed */\n"
" register int base;\n"
" cset = infop->charset;\n"
" base = infop->base;\n"
" do{ /* Convert to ascii */\n"
" *(--bufpt) = cset[longvalue%base];\n"
" longvalue = longvalue/base;\n"
" }while( longvalue>0 );\n"
" }\n"
" length = (long)&buf[etBUFSIZE]-(long)bufpt;\n"
" for(idx=precision-length; idx>0; idx--){\n"
" *(--bufpt) = '0'; /* Zero pad */\n"
" }\n"
" if( prefix ) *(--bufpt) = prefix; /* Add sign */\n"
" if( flag_alternateform && infop->prefix ){ /* Add \"0\" or \"0x\" */\n"
" char *pre, x;\n"
" pre = infop->prefix;\n"
" if( *bufpt!=pre[0] ){\n"
" for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x;\n"
" }\n"
" }\n"
" length = (long)&buf[etBUFSIZE]-(long)bufpt;\n"
" break;\n"
" case etFLOAT:\n"
" case etEXP:\n"
" case etGENERIC:\n"
" realvalue = va_arg(ap,double);\n"
"#ifndef etNOFLOATINGPOINT\n"
" if( precision<0 ) precision = 6; /* Set default precision */\n"
" if( precision>etBUFSIZE-10 ) precision = etBUFSIZE-10;\n"
" if( realvalue<0.0 ){\n"
" realvalue = -realvalue;\n"
" prefix = '-';\n"
" }else{\n"
" if( flag_plussign ) prefix = '+';\n"
" else if( flag_blanksign ) prefix = ' ';\n"
" else prefix = 0;\n"
" }\n"
" if( infop->type==etGENERIC && precision>0 ) precision--;\n"
" rounder = 0.0;\n"
"#ifdef COMPATIBILITY\n"
" /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */\n"
" for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1);\n"
"#else\n"
" /* It makes more sense to use 0.5 */\n"
" for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1);\n"
"#endif\n"
" if( infop->type==etFLOAT ) realvalue += rounder;\n"
" /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */\n"
" exp = 0;\n"
" if( realvalue>0.0 ){\n"
" int k = 0;\n"
" while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; }\n"
" while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; }\n"
" while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; }\n"
" while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; }\n"
" if( k>=100 ){\n"
" bufpt = \"NaN\";\n"
" length = 3;\n"
" break;\n"
" }\n"
" }\n"
" bufpt = buf;\n"
" /*\n"
" ** If the field type is etGENERIC, then convert to either etEXP\n"
" ** or etFLOAT, as appropriate.\n"
" */\n"
" flag_exp = xtype==etEXP;\n"
" if( xtype!=etFLOAT ){\n"
" realvalue += rounder;\n"
" if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }\n"
" }\n"
" if( xtype==etGENERIC ){\n"
" flag_rtz = !flag_alternateform;\n"
" if( exp<-4 || exp>precision ){\n"
" xtype = etEXP;\n"
" }else{\n"
" precision = precision - exp;\n"
" xtype = etFLOAT;\n"
" }\n"
" }else{\n"
" flag_rtz = 0;\n"
" }\n"
" /*\n"
" ** The \"exp+precision\" test causes output to be of type etEXP if\n"
" ** the precision is too large to fit in buf[].\n"
" */\n"
" nsd = 0;\n"
" if( xtype==etFLOAT && exp+precision<etBUFSIZE-30 ){\n"
" flag_dp = (precision>0 || flag_alternateform);\n"
" if( prefix ) *(bufpt++) = prefix; /* Sign */\n"
" if( exp<0 ) *(bufpt++) = '0'; /* Digits before \".\" */\n"
" else for(; exp>=0; exp--) *(bufpt++) = et_getdigit(&realvalue,&nsd);\n"
" if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */\n"
" for(exp++; exp<0 && precision>0; precision--, exp++){\n"
" *(bufpt++) = '0';\n"
" }\n"
" while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);\n"
" *(bufpt--) = 0; /* Null terminate */\n"
" if( flag_rtz && flag_dp ){ /* Remove trailing zeros and \".\" */\n"
" while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;\n"
" if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;\n"
" }\n"
" bufpt++; /* point to next free slot */\n"
" }else{ /* etEXP or etGENERIC */\n"
" flag_dp = (precision>0 || flag_alternateform);\n"
" if( prefix ) *(bufpt++) = prefix; /* Sign */\n"
" *(bufpt++) = et_getdigit(&realvalue,&nsd); /* First digit */\n"
" if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */\n"
" while( (precision--)>0 ) *(bufpt++) = et_getdigit(&realvalue,&nsd);\n"
" bufpt--; /* point to last digit */\n"
" if( flag_rtz && flag_dp ){ /* Remove tail zeros */\n"
" while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0;\n"
" if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0;\n"
" }\n"
" bufpt++; /* point to next free slot */\n"
" if( exp || flag_exp ){\n"
" *(bufpt++) = infop->charset[0];\n"
" if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */\n"
" else { *(bufpt++) = '+'; }\n"
" if( exp>=100 ){\n"
" *(bufpt++) = (exp/100)+'0'; /* 100's digit */\n"
" exp %= 100;\n"
" }\n"
" *(bufpt++) = exp/10+'0'; /* 10's digit */\n"
" *(bufpt++) = exp%10+'0'; /* 1's digit */\n"
" }\n"
" }\n"
" /* The converted number is in buf[] and zero terminated. Output it.\n"
" ** Note that the number is in the usual order, not reversed as with\n"
" ** integer conversions. */\n"
" length = (long)bufpt-(long)buf;\n"
" bufpt = buf;\n"
"\n"
" /* Special case: Add leading zeros if the flag_zeropad flag is\n"
" ** set and we are not left justified */\n"
" if( flag_zeropad && !flag_leftjustify && length < width){\n"
" int i;\n"
" int nPad = width - length;\n"
" for(i=width; i>=nPad; i--){\n"
" bufpt[i] = bufpt[i-nPad];\n"
" }\n"
" i = prefix!=0;\n"
" while( nPad-- ) bufpt[i++] = '0';\n"
" length = width;\n"
" }\n"
"#endif\n"
" break;\n"
" case etSIZE:\n"
" *(va_arg(ap,int*)) = count;\n"
" length = width = 0;\n"
" break;\n"
" case etPERCENT:\n"
" buf[0] = '%';\n"
" bufpt = buf;\n"
" length = 1;\n"
" break;\n"
" case etCHARLIT:\n"
" case etCHARX:\n"
" c = buf[0] = (xtype==etCHARX ? va_arg(ap,int) : *++fmt);\n"
" if( precision>=0 ){\n"
" for(idx=1; idx<precision; idx++) buf[idx] = c;\n"
" length = precision;\n"
" }else{\n"
" length =1;\n"
" }\n"
" bufpt = buf;\n"
" break;\n"
" case etSTRING:\n"
" case etMEMSTRING:\n"
" zMem = bufpt = va_arg(ap,char*);\n"
" if( bufpt==0 ) bufpt = \"(null)\";\n"
" length = strlen(bufpt);\n"
" if( precision>=0 && precision<length ) length = precision;\n"
" break;\n"
" case etTCLESCAPE:\n"
" {\n"
" int i, j, n, c, k;\n"
" char *arg = va_arg(ap,char*);\n"
" if( arg==0 ) arg = \"(NULL)\";\n"
" for(i=n=0; (c=arg[i])!=0; i++){\n"
" k = NeedEsc[c&0xff];\n"
" if( k==0 ){\n"
" n++;\n"
" }else if( k==1 ){\n"
" n+=4;\n"
" }else{\n"
" n+=2;\n"
" }\n"
" }\n"
" n++;\n"
" if( n>etBUFSIZE ){\n"
" bufpt = zExtra = Tcl_Alloc( n );\n"
" }else{\n"
" bufpt = buf;\n"
" }\n"
" for(i=j=0; (c=arg[i])!=0; i++){\n"
" k = NeedEsc[c&0xff];\n"
" if( k==0 ){\n"
" bufpt[j++] = c;\n"
" }else if( k==1 ){\n"
" bufpt[j++] = '\\\\';\n"
" bufpt[j++] = ((c>>6) & 3) + '0';\n"
" bufpt[j++] = ((c>>3) & 7) + '0';\n"
" bufpt[j++] = (c & 7) + '0';\n"
" }else{\n"
" bufpt[j++] = '\\\\';\n"
" bufpt[j++] = k;\n"
" }\n"
" }\n"
" bufpt[j] = 0;\n"
" length = j;\n"
" if( precision>=0 && precision<length ) length = precision;\n"
" }\n"
" break;\n"
" case etERROR:\n"
" buf[0] = '%';\n"
" buf[1] = c;\n"
" errorflag = 0;\n"
" idx = 1+(c!=0);\n"
" (*func)(arg,\"%\",idx);\n"
" count += idx;\n"
" if( c==0 ) fmt--;\n"
" break;\n"
" }/* End switch over the format type */\n"
" /*\n"
" ** The text of the conversion is pointed to by \"bufpt\" and is\n"
" ** \"length\" characters long. The field width is \"width\". Do\n"
" ** the output.\n"
" */\n"
" if( !flag_leftjustify ){\n"
" register int nspace;\n"
" nspace = width-length;\n"
" if( nspace>0 ){\n"
" if( flag_center ){\n"
" nspace = nspace/2;\n"
" width -= nspace;\n"
" flag_leftjustify = 1;\n"
" }\n"
" count += nspace;\n"
" while( nspace>=etSPACESIZE ){\n"
" (*func)(arg,spaces,etSPACESIZE);\n"
" nspace -= etSPACESIZE;\n"
" }\n"
" if( nspace>0 ) (*func)(arg,spaces,nspace);\n"
" }\n"
" }\n"
" if( length>0 ){\n"
" (*func)(arg,bufpt,length);\n"
" count += length;\n"
" }\n"
" if( xtype==etMEMSTRING && zMem ){\n"
" Tcl_Free(zMem);\n"
" }\n"
" if( flag_leftjustify ){\n"
" register int nspace;\n"
" nspace = width-length;\n"
" if( nspace>0 ){\n"
" count += nspace;\n"
" while( nspace>=etSPACESIZE ){\n"
" (*func)(arg,spaces,etSPACESIZE);\n"
" nspace -= etSPACESIZE;\n"
" }\n"
" if( nspace>0 ) (*func)(arg,spaces,nspace);\n"
" }\n"
" }\n"
" if( zExtra ){\n"
" Tcl_Free(zExtra);\n"
" }\n"
" }/* End for loop over the format string */\n"
" return errorflag ? -1 : count;\n"
"} /* End of function */\n"
"\n"
"/*\n"
"** The following section of code handles the mprintf routine, that\n"
"** writes to memory obtained from malloc().\n"
"*/\n"
"\n"
"/* This structure is used to store state information about the\n"
"** write to memory that is currently in progress.\n"
"*/\n"
"struct sgMprintf {\n"
" char *zBase; /* A base allocation */\n"
" char *zText; /* The string collected so far */\n"
" int nChar; /* Length of the string so far */\n"
" int nAlloc; /* Amount of space allocated in zText */\n"
"};\n"
"\n"
"/* \n"
"** The xprintf callback function. \n"
"**\n"
"** This routine add nNewChar characters of text in zNewText to\n"
"** the sgMprintf structure pointed to by \"arg\".\n"
"*/\n"
"static void mout(void *arg, char *zNewText, int nNewChar){\n"
" struct sgMprintf *pM = (struct sgMprintf*)arg;\n"
" if( pM->nChar + nNewChar + 1 > pM->nAlloc ){\n"
" pM->nAlloc = pM->nChar + nNewChar*2 + 1;\n"
" if( pM->zText==pM->zBase ){\n"
" pM->zText = Tcl_Alloc(pM->nAlloc);\n"
" if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar);\n"
" }else{\n"
" pM->zText = Tcl_Realloc(pM->zText, pM->nAlloc);\n"
" }\n"
" }\n"
" if( pM->zText ){\n"
" memcpy(&pM->zText[pM->nChar], zNewText, nNewChar);\n"
" pM->nChar += nNewChar;\n"
" pM->zText[pM->nChar] = 0;\n"
" }\n"
"}\n"
"\n"
"/*\n"
"** mprintf() works like printf(), but allocations memory to hold the\n"
"** resulting string and returns a pointer to the allocated memory.\n"
"*/\n"
"char *mprintf(const char *zFormat, ...){\n"
" va_list ap;\n"
" struct sgMprintf sMprintf;\n"
" char *zNew;\n"
" char zBuf[200];\n"
"\n"
" sMprintf.nChar = 0;\n"
" sMprintf.nAlloc = sizeof(zBuf);\n"
" sMprintf.zText = zBuf;\n"
" sMprintf.zBase = zBuf;\n"
" va_start(ap,zFormat);\n"
" vxprintf(mout,&sMprintf,zFormat,ap);\n"
" va_end(ap);\n"
" sMprintf.zText[sMprintf.nChar] = 0;\n"
" if( sMprintf.zText==sMprintf.zBase ){\n"
" zNew = Tcl_Alloc( sMprintf.nChar+1 );\n"
" if( zNew ) strcpy(zNew,zBuf);\n"
" }else{\n"
" zNew = Tcl_Realloc(sMprintf.zText,sMprintf.nChar+1);\n"
" }\n"
" return zNew;\n"
"}\n"
"\n"
"/* This is the varargs version of mprintf. \n"
"*/\n"
"char *vmprintf(const char *zFormat, va_list ap){\n"
" struct sgMprintf sMprintf;\n"
" char zBuf[200];\n"
" sMprintf.nChar = 0;\n"
" sMprintf.zText = zBuf;\n"
" sMprintf.nAlloc = sizeof(zBuf);\n"
" sMprintf.zBase = zBuf;\n"
" vxprintf(mout,&sMprintf,zFormat,ap);\n"
" sMprintf.zText[sMprintf.nChar] = 0;\n"
" if( sMprintf.zText==sMprintf.zBase ){\n"
" sMprintf.zText = Tcl_Alloc( strlen(zBuf)+1 );\n"
" if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf);\n"
" }else{\n"
" sMprintf.zText = Tcl_Realloc(sMprintf.zText,sMprintf.nChar+1);\n"
" }\n"
" return sMprintf.zText;\n"
"}\n"
"\n"
"/*\n"
"** Add text output to a Tcl_DString.\n"
"**\n"
"** This routine is called by vxprintf(). It's job is to add\n"
"** nNewChar characters of text from zNewText to the Tcl_DString\n"
"** that \"arg\" is pointing to.\n"
"*/\n"
"static void dstringout(void *arg, char *zNewText, int nNewChar){\n"
" Tcl_DString *str = (Tcl_DString*)arg;\n"
" Tcl_DStringAppend(str,zNewText,nNewChar);\n"
"}\n"
"\n"
"/*\n"
"** Append formatted output to a DString.\n"
"*/\n"
"char *Et_DStringAppendF(Tcl_DString *str, const char *zFormat, ...){\n"
" va_list ap;\n"
" va_start(ap,zFormat);\n"
" vxprintf(dstringout,str,zFormat,ap);\n"
" va_end(ap);\n"
" return Tcl_DStringValue(str);\n"
"}\n"
"\n"
"/*\n"
"** Make this variable true to trace all calls to EvalF\n"
"*/\n"
"int Et_EvalTrace = 0;\n"
"\n"
"/*\n"
"** Eval the results of a string.\n"
"*/\n"
"int Et_EvalF(Tcl_Interp *interp, const char *zFormat, ...){\n"
" char *zCmd;\n"
" va_list ap;\n"
" int result;\n"
" va_start(ap,zFormat);\n"
" zCmd = vmprintf(zFormat,ap);\n"
" if( Et_EvalTrace ) printf(\"%s\\n\",zCmd);\n"
" result = Tcl_Eval(interp,zCmd);\n"
" if( Et_EvalTrace ) printf(\"%d %s\\n\",result,interp->result);\n"
" Tcl_Free(zCmd);\n"
" return result;\n"
"}\n"
"int Et_GlobalEvalF(Tcl_Interp *interp, const char *zFormat, ...){\n"
" char *zCmd;\n"
" va_list ap;\n"
" int result;\n"
" va_start(ap,zFormat);\n"
" zCmd = vmprintf(zFormat,ap);\n"
" if( Et_EvalTrace ) printf(\"%s\\n\",zCmd);\n"
" result = Tcl_GlobalEval(interp,zCmd);\n"
" if( Et_EvalTrace ) printf(\"%d %s\\n\",result,interp->result);\n"
" Tcl_Free(zCmd);\n"
" return result;\n"
"}\n"
"\n"
"/*\n"
"** Set the result of an interpreter using printf-like arguments.\n"
"*/\n"
"void Et_ResultF(Tcl_Interp *interp, const char *zFormat, ...){\n"
" Tcl_DString str;\n"
" va_list ap;\n"
"\n"
" Tcl_DStringInit(&str);\n"
" va_start(ap,zFormat);\n"
" vxprintf(dstringout,&str,zFormat,ap);\n"
" va_end(ap);\n"
" Tcl_DStringResult(interp,&str); \n"
"}\n"
"\n"
"#if ET_HAVE_OBJ\n"
"/*\n"
"** Append text to a string object.\n"
"*/\n"
"int Et_AppendObjF(Tcl_Obj *pObj, const char *zFormat, ...){\n"
" va_list ap;\n"
" int rc;\n"
"\n"
" va_start(ap,zFormat);\n"
" rc = vxprintf((void(*)(void*,char*,int))Tcl_AppendToObj, pObj, zFormat, ap);\n"
" va_end(ap);\n"
" return rc;\n"
"}\n"
"#endif\n"
"\n"
"\n"
"#if ET_WIN32\n"
"/*\n"
"** This array translates all characters into themselves. Except\n"
"** for the \\ which gets translated into /. And all upper-case\n"
"** characters are translated into lower case. This is used for\n"
"** hashing and comparing filenames, to work around the Windows\n"
"** bug of ignoring filename case and using the wrong separator\n"
"** character for directories.\n"
"**\n"
"** The array is initialized by FilenameHashInit().\n"
"**\n"
"** We also define a macro ET_TRANS() that actually does\n"
"** the character translation. ET_TRANS() is a no-op under\n"
"** unix.\n"
"*/\n"
"static char charTrans[256];\n"
"#define ET_TRANS(X) (charTrans[0xff&(int)(X)])\n"
"#else\n"
"#define ET_TRANS(X) (X)\n"
"#endif\n"
"\n"
"/*\n"
"** Hash a filename. The value returned is appropriate for\n"
"** indexing into the Et_FileHashTable[] array.\n"
"*/\n"
"static int FilenameHash(char *zName){\n"
" int h = 0;\n"
" while( *zName ){\n"
" h = h ^ (h<<5) ^ ET_TRANS(*(zName++));\n"
" }\n"
" if( h<0 ) h = -h;\n"
" return h % (sizeof(Et_FileHashTable)/sizeof(Et_FileHashTable[0]));\n"
"}\n"
"\n"
"/*\n"
"** Compare two filenames. Return 0 if they are the same and\n"
"** non-zero if they are different.\n"
"*/\n"
"static int FilenameCmp(char *z1, char *z2){\n"
" int diff;\n"
" while( (diff = ET_TRANS(*z1)-ET_TRANS(*z2))==0 && *z1!=0){\n"
" z1++;\n"
" z2++;\n"
" }\n"
" return diff;\n"
"}\n"
"\n"
"/*\n"
"** Initialize the file hash table\n"
"*/\n"
"static void FilenameHashInit(void){\n"
" int i;\n"
"#if ET_WIN32\n"
" for(i=0; i<sizeof(charTrans); i++){\n"
" charTrans[i] = i;\n"
" }\n"
" for(i='A'; i<='Z'; i++){\n"
" charTrans[i] = i + 'a' - 'A';\n"
" }\n"
" charTrans['\\\\'] = '/';\n"
"#endif\n"
" for(i=0; i<sizeof(Et_FileSet)/sizeof(Et_FileSet[0]) - 1; i++){\n"
" struct EtFile *p;\n"
" int h;\n"
" p = &Et_FileSet[i];\n"
" h = FilenameHash(p->zName);\n"
" p->pNext = Et_FileHashTable[h];\n"
" Et_FileHashTable[h] = p;\n"
" }\n"
"}\n"
"\n"
"/*\n"
"** Locate the text of a built-in file given its name. \n"
"** Return 0 if not found. Return this size of the file (not\n"
"** counting the null-terminator) in *pSize if pSize!=NULL.\n"
"**\n"
"** If deshroud==1 and the file is shrouded, then descramble\n"
"** the text.\n"
"*/\n"
"static char *FindBuiltinFile(char *zName, int deshroud, int *pSize){\n"
" int h;\n"
" struct EtFile *p;\n"
"\n"
" h = FilenameHash(zName);\n"
" p = Et_FileHashTable[h];\n"
" while( p && FilenameCmp(p->zName,zName)!=0 ){ p = p->pNext; }\n"
"#if ET_SHROUD_KEY>0\n"
" if( p && p->shrouded && deshroud ){\n"
" char *z;\n"
" int xor = ET_SHROUD_KEY;\n"
" for(z=p->zData; *z; z++){\n"
" if( *z>=0x20 ){ *z ^= xor; xor = (xor+1)&0x1f; }\n"
" }\n"
" p->shrouded = 0;\n"
" }\n"
"#endif\n"
" if( p && pSize ){\n"
" *pSize = p->nData;\n"
" }\n"
" return p ? p->zData : 0;\n"
"}\n"
"\n"
"/*\n"
"** Add a new file to the list of built-in files.\n"
"**\n"
"** This routine makes a copy of zFilename. But it does NOT make\n"
"** a copy of zData. It just holds a pointer to zData and uses\n"
"** that for all file access. So after calling this routine,\n"
"** you should never change zData!\n"
"*/\n"
"void Et_NewBuiltinFile(\n"
" char *zFilename, /* Name of the new file */\n"
" char *zData, /* Data for the new file */\n"
" int nData /* Number of bytes in the new file */\n"
"){\n"
" int h;\n"
" struct EtFile *p;\n"
"\n"
" p = (struct EtFile*)Tcl_Alloc( sizeof(struct EtFile) + strlen(zFilename) + 1);\n"
" if( p==0 ) return;\n"
" p->zName = (char*)&p[1];\n"
" strcpy(p->zName, zFilename);\n"
" p->zData = zData;\n"
" p->nData = nData;\n"
" p->shrouded = 0;\n"
" h = FilenameHash(zFilename);\n"
" p->pNext = Et_FileHashTable[h];\n"
" Et_FileHashTable[h] = p;\n"
"}\n"
"\n"
"/*\n"
"** A TCL interface to the Et_NewBuiltinFile function. For Tcl8.0\n"
"** and later, we make this an Obj command so that it can deal with\n"
"** binary data.\n"
"*/\n"
"#if ET_HAVE_OBJ\n"
"static int Et_NewBuiltinFileCmd(ET_OBJARGS){\n"
" char *zData, *zNew;\n"
" int nData;\n"
" if( objc!=3 ){\n"
" Tcl_WrongNumArgs(interp, 1, objv, \"filename data\");\n"
" return TCL_ERROR;\n"
" }\n"
" zData = (char*)Tcl_GetByteArrayFromObj(objv[2], &nData);\n"
" zNew = Tcl_Alloc( nData + 1 );\n"
" if( zNew ){\n"
" memcpy(zNew, zData, nData);\n"
" zNew[nData] = 0;\n"
" Et_NewBuiltinFile(Tcl_GetStringFromObj(objv[1], 0), zNew, nData);\n"
" }\n"
" return TCL_OK;\n"
"}\n"
"#else\n"
"static int Et_NewBuiltinFileCmd(ET_TCLARGS){\n"
" char *zData;\n"
" int nData;\n"
" if( argc!=3 ){\n"
" Et_ResultF(interp,\"wrong # args: should be \\\"%s FILENAME DATA\\\"\", argv[0]);\n"
" return TCL_ERROR;\n"
" }\n"
" nData = strlen(argv[2]) + 1;\n"
" zData = Tcl_Alloc( nData );\n"
" if( zData ){\n"
" strcpy(zData, argv[2]);\n"
" Et_NewBuiltinFile(argv[1], zData, nData);\n"
" }\n"
" return TCL_OK;\n"
"}\n"
"#endif\n"
"\n"
"/*\n"
"** The following section implements the InsertProc functionality. The\n"
"** new InsertProc feature of Tcl8.0.3 and later allows us to overload\n"
"** the usual system call commands for file I/O and replace them with\n"
"** commands that operate on the built-in files.\n"
"*/\n"
"#ifdef ET_HAVE_INSERTPROC\n"
"\n"
"/* \n"
"** Each open channel to a built-in file is an instance of the\n"
"** following structure.\n"
"*/\n"
"typedef struct Et_FileStruct {\n"
" char *zData; /* All of the data */\n"
" int nData; /* Bytes of data, not counting the null terminator */\n"
" int cursor; /* How much of the data has been read so far */\n"
"} Et_FileStruct;\n"
"\n"
"/*\n"
"** Close a previously opened built-in file.\n"
"*/\n"
"static int Et_FileClose(ClientData instanceData, Tcl_Interp *interp){\n"
" Et_FileStruct *p = (Et_FileStruct*)instanceData;\n"
" Tcl_Free((char*)p);\n"
" return 0;\n"
"}\n"
"\n"
"/*\n"
"** Read from a built-in file.\n"
"*/\n"
"static int Et_FileInput(\n"
" ClientData instanceData, /* The file structure */\n"
" char *buf, /* Write the data read here */\n"
" int bufSize, /* Read this much data */\n"
" int *pErrorCode /* Write the error code here */\n"
"){\n"
" Et_FileStruct *p = (Et_FileStruct*)instanceData;\n"
" *pErrorCode = 0;\n"
" if( p->cursor+bufSize>p->nData ){\n"
" bufSize = p->nData - p->cursor;\n"
" }\n"
" memcpy(buf, &p->zData[p->cursor], bufSize);\n"
" p->cursor += bufSize;\n"
" return bufSize;\n"
"}\n"
"\n"
"/*\n"
"** Writes to a built-in file always return EOF.\n"
"*/\n"
"static int Et_FileOutput(\n"
" ClientData instanceData, /* The file structure */\n"
" char *buf, /* Read the data from here */\n"
" int toWrite, /* Write this much data */\n"
" int *pErrorCode /* Write the error code here */\n"
"){\n"
" *pErrorCode = 0;\n"
" return 0;\n"
"}\n"
"\n"
"/*\n"
"** Move the cursor around within the built-in file.\n"
"*/\n"
"static int Et_FileSeek(\n"
" ClientData instanceData, /* The file structure */\n"
" long offset, /* Offset to seek to */\n"
" int mode, /* One of SEEK_CUR, SEEK_SET or SEEK_END */\n"
" int *pErrorCode /* Write the error code here */\n"
"){\n"
" Et_FileStruct *p = (Et_FileStruct*)instanceData;\n"
" switch( mode ){\n"
" case SEEK_CUR: offset += p->cursor; break;\n"
" case SEEK_END: offset += p->nData; break;\n"
" default: break;\n"
" }\n"
" if( offset<0 ) offset = 0;\n"
" if( offset>p->nData ) offset = p->nData;\n"
" p->cursor = offset;\n"
" return offset;\n"
"}\n"
"\n"
"/*\n"
"** The Watch method is a no-op\n"
"*/\n"
"static void Et_FileWatch(ClientData instanceData, int mask){\n"
"}\n"
"\n"
"/*\n"
"** The Handle method always returns an error.\n"
"*/\n"
"static int Et_FileHandle(ClientData notUsed, int dir, ClientData *handlePtr){\n"
" return TCL_ERROR;\n"
"}\n"
"\n"
"/*\n"
"** This is the channel type that will access the built-in files.\n"
"*/\n"
"static Tcl_ChannelType builtinChannelType = {\n"
" \"builtin\", /* Type name. */\n"
" NULL, /* Always non-blocking.*/\n"
" Et_FileClose, /* Close proc. */\n"
" Et_FileInput, /* Input proc. */\n"
" Et_FileOutput, /* Output proc. */\n"
" Et_FileSeek, /* Seek proc. */\n"
" NULL, /* Set option proc. */\n"
" NULL, /* Get option proc. */\n"
" Et_FileWatch, /* Watch for events on console. */\n"
" Et_FileHandle, /* Get a handle from the device. */\n"
"};\n"
"\n"
"/*\n"
"** This routine attempts to do an open of a built-in file.\n"
"*/\n"
"static Tcl_Channel Et_FileOpen(\n"
" Tcl_Interp *interp, /* The TCL interpreter doing the open */\n"
" char *zFilename, /* Name of the file to open */\n"
" char *modeString, /* Mode string for the open (ignored) */\n"
" int permissions /* Permissions for a newly created file (ignored) */\n"
"){\n"
" char *zData;\n"
" Et_FileStruct *p;\n"
" int nData;\n"
" char zName[50];\n"
" Tcl_Channel chan;\n"
" static int count = 1;\n"
"\n"
" zData = FindBuiltinFile(zFilename, 1, &nData);\n"
" if( zData==0 ) return NULL;\n"
" p = (Et_FileStruct*)Tcl_Alloc( sizeof(Et_FileStruct) );\n"
" if( p==0 ) return NULL;\n"
" p->zData = zData;\n"
" p->nData = nData;\n"
" p->cursor = 0;\n"
" sprintf(zName,\"etbi_%x_%x\",((int)Et_FileOpen)>>12,count++);\n"
" chan = Tcl_CreateChannel(&builtinChannelType, zName, \n"
" (ClientData)p, TCL_READABLE);\n"
" return chan;\n"
"}\n"
"\n"
"/*\n"
"** This routine does a stat() system call for a built-in file.\n"
"*/\n"
"static int Et_FileStat(char *path, struct stat *buf){\n"
" char *zData;\n"
" int nData;\n"
"\n"
" zData = FindBuiltinFile(path, 0, &nData);\n"
" if( zData==0 ){\n"
" return -1;\n"
" }\n"
" memset(buf, 0, sizeof(*buf));\n"
" buf->st_mode = 0400;\n"
" buf->st_size = nData;\n"
" return 0;\n"
"}\n"
"\n"
"/*\n"
"** This routien does an access() system call for a built-in file.\n"
"*/\n"
"static int Et_FileAccess(char *path, int mode){\n"
" char *zData;\n"
"\n"
" if( mode & 3 ){\n"
" return -1;\n"
" }\n"
" zData = FindBuiltinFile(path, 0, 0);\n"
" if( zData==0 ){\n"
" return -1;\n"
" }\n"
" return 0; \n"
"}\n"
"#endif /* ET_HAVE_INSERTPROC */\n"
"\n"
"/*\n"
"** An overloaded version of \"source\". First check for the file\n"
"** is one of the built-ins. If it isn't a built-in, then check the\n"
"** disk. But if ET_STANDALONE is set (which corresponds to the\n"
"** \"Strict\" option in the user interface) then never check the disk.\n"
"** This gives us a quick way to check for the common error of\n"
"** sourcing a file that exists on the development by mistake, \n"
"** and only discovering the mistake when you move the program\n"
"** to your customer's machine.\n"
"*/\n"
"static int Et_Source(ET_TCLARGS){\n"
" char *z;\n"
"\n"
" if( argc!=2 ){\n"
" Et_ResultF(interp,\"wrong # args: should be \\\"%s FILENAME\\\"\", argv[0]);\n"
" return TCL_ERROR;\n"
" }\n"
" z = FindBuiltinFile(argv[1], 1, 0);\n"
" if( z ){\n"
" int rc;\n"
" rc = Tcl_Eval(interp,z);\n"
" if (rc == TCL_ERROR) {\n"
" char msg[200];\n"
" sprintf(msg, \"\\n (file \\\"%.150s\\\" line %d)\", argv[1],\n"
" interp->errorLine);\n"
" Tcl_AddErrorInfo(interp, msg);\n"
" } else {\n"
" rc = TCL_OK;\n"
" }\n"
" return rc;\n"
" }\n"
"#if ET_STANDALONE\n"
" Et_ResultF(interp,\"no such file: \\\"%s\\\"\", argv[1]);\n"
" return TCL_ERROR;\n"
"#else\n"
" return Tcl_EvalFile(interp,argv[1]);\n"
"#endif\n"
"}\n"
"\n"
"#ifndef ET_HAVE_INSERTPROC\n"
"/*\n"
"** An overloaded version of \"file exists\". First check for the file\n"
"** in the file table, then go to disk.\n"
"**\n"
"** We only overload \"file exists\" if we don't have InsertProc() \n"
"** procedures. If we do have InsertProc() procedures, they will\n"
"** handle this more efficiently.\n"
"*/\n"
"static int Et_FileExists(ET_TCLARGS){\n"
" int i, rc;\n"
" Tcl_DString str;\n"
" if( argc==3 && strncmp(argv[1],\"exis\",4)==0 ){\n"
" if( FindBuiltinFile(argv[2], 0, 0)!=0 ){\n"
" interp->result = \"1\";\n"
" return TCL_OK;\n"
" }\n"
" }\n"
" Tcl_DStringInit(&str);\n"
" Tcl_DStringAppendElement(&str,\"Et_FileCmd\");\n"
" for(i=1; i<argc; i++){\n"
" Tcl_DStringAppendElement(&str, argv[i]);\n"
" }\n"
" rc = Tcl_Eval(interp, Tcl_DStringValue(&str));\n"
" Tcl_DStringFree(&str);\n"
" return rc;\n"
"}\n"
"#endif\n"
"\n"
"/*\n"
"** This is the main Tcl interpreter. It's a global variable so it\n"
"** can be accessed easily from C code.\n"
"*/\n"
"Tcl_Interp *Et_Interp = 0;\n"
"\n"
"\n"
"#if ET_WIN32\n"
"/*\n"
"** Implement the Et_MessageBox command on Windows platforms. We\n"
"** use the MessageBox() function from the Win32 API so that the\n"
"** error message will be displayed as a dialog box. Writing to\n"
"** standard error doesn't do anything on windows.\n"
"*/\n"
"int Et_MessageBox(ET_TCLARGS){\n"
" char *zMsg = \"(Empty Message)\";\n"
" char *zTitle = \"Message...\";\n"
"\n"
" if( argc>1 ){\n"
" zTitle = argv[1];\n"
" }\n"
" if( argc>2 ){\n"
" zMsg = argv[2];\n"
" }\n"
" MessageBox(0, zMsg, zTitle, MB_ICONSTOP | MB_OK);\n"
" return TCL_OK;\n"
"}\n"
"#endif\n"
"\n"
"/*\n"
"** A default implementation for \"bgerror\"\n"
"*/\n"
"static char zBgerror[] = \n"
" \"proc Et_Bgerror err {\\n\"\n"
" \" global errorInfo tk_library\\n\"\n"
" \" if {[info exists errorInfo]} {\\n\"\n"
" \" set ei $errorInfo\\n\"\n"
" \" } else {\\n\"\n"
" \" set ei {}\\n\"\n"
" \" }\\n\"\n"
" \" if {[catch {bgerror $err}]==0} return\\n\"\n"
" \" if {[string length $ei]>0} {\\n\"\n"
" \" set err $ei\\n\"\n"
" \" }\\n\"\n"
" \" if {[catch {Et_MessageBox {Error} $err}]} {\\n\"\n"
" \" puts stderr $err\\n\"\n"
" \" }\\n\"\n"
" \" exit\\n\"\n"
" \"}\\n\"\n"
";\n"
"\n"
"/*\n"
"** Do the initialization.\n"
"**\n"
"** This routine is called after the interpreter is created, but\n"
"** before Et_PreInit() or Et_AppInit() have been run.\n"
"*/\n"
"static int Et_DoInit(Tcl_Interp *interp){\n"
" int i;\n"
" extern int Et_PreInit(Tcl_Interp*);\n"
" extern int Et_AppInit(Tcl_Interp*);\n"
"\n"
" /* Insert our alternative stat(), access() and open() procedures\n"
" ** so that any attempt to work with a file will check our built-in\n"
" ** scripts first.\n"
" */\n"
"#ifdef ET_HAVE_INSERTPROC\n"
" TclStatInsertProc(Et_FileStat);\n"
" TclAccessInsertProc(Et_FileAccess);\n"
" TclOpenFileChannelInsertProc(Et_FileOpen);\n"
"#endif\n"
"\n"
" /* Initialize the hash-table for built-in scripts\n"
" */\n"
" FilenameHashInit();\n"
"\n"
" /* The Et_NewBuiltFile command is inserted for use by FreeWrap\n"
" ** and similar tools.\n"
" */\n"
"#if ET_HAVE_OBJ\n"
" Tcl_CreateObjCommand(interp,\"Et_NewBuiltinFile\",Et_NewBuiltinFileCmd,0,0);\n"
"#else\n"
" Tcl_CreateCommand(interp,\"Et_NewBuiltinFile\",Et_NewBuiltinFileCmd,0,0);\n"
"#endif\n"
"\n"
" /* Overload the \"file\" and \"source\" commands\n"
" */\n"
"#ifndef ET_HAVE_INSERTPROC\n"
" {\n"
" static char zRename[] = \"rename file Et_FileCmd\";\n"
" Tcl_Eval(interp,zRename);\n"
" Tcl_CreateCommand(interp,\"file\",Et_FileExists,0,0);\n"
" }\n"
"#endif\n"
" Tcl_CreateCommand(interp,\"source\",Et_Source,0,0);\n"
"\n"
" Et_Interp = interp;\n"
"#ifdef ET_TCL_LIBRARY\n"
" Tcl_SetVar(interp,\"tcl_library\",ET_TCL_LIBRARY,TCL_GLOBAL_ONLY);\n"
" Tcl_SetVar(interp,\"tcl_libPath\",ET_TCL_LIBRARY,TCL_GLOBAL_ONLY);\n"
" Tcl_SetVar2(interp,\"env\",\"TCL_LIBRARY\",ET_TCL_LIBRARY,TCL_GLOBAL_ONLY);\n"
"#endif\n"
"#ifdef ET_TK_LIBRARY\n"
" Tcl_SetVar(interp,\"tk_library\",ET_TK_LIBRARY,TCL_GLOBAL_ONLY);\n"
" Tcl_SetVar2(interp,\"env\",\"TK_LIBRARY\",ET_TK_LIBRARY,TCL_GLOBAL_ONLY);\n"
"#endif\n"
"#if ET_WIN32\n"
" Tcl_CreateCommand(interp,\"Et_MessageBox\",Et_MessageBox, 0, 0);\n"
"#endif \n"
" Tcl_Eval(interp,zBgerror);\n"
"#if ET_HAVE_PREINIT\n"
" if( Et_PreInit(interp) == TCL_ERROR ){\n"
" goto initerr;\n"
" }\n"
"#endif\n"
" if( Tcl_Init(interp) == TCL_ERROR ){\n"
" goto initerr;\n"
" }\n"
" Et_GlobalEvalF(interp,\"set dir $tcl_library;source $dir/tclIndex;unset dir\");\n"
"#if ET_ENABLE_TK\n"
" if( Tk_Init(interp) == TCL_ERROR ){\n"
" goto initerr;\n"
" }\n"
" Tcl_StaticPackage(interp,\"Tk\", Tk_Init, 0);\n"
" Et_GlobalEvalF(interp,\"set dir $tk_library;source $dir/tclIndex;unset dir\");\n"
"#endif\n"
" /* Tcl_SetVar(interp, \"tcl_rcFileName\", \"~/.wishrc\", TCL_GLOBAL_ONLY); */\n"
" for(i=0; i<sizeof(Et_CmdSet)/sizeof(Et_CmdSet[0]) - 1; i++){\n"
" Tcl_CreateCommand(interp, Et_CmdSet[i].zName, Et_CmdSet[i].xProc, 0, 0);\n"
" }\n"
"#if ET_ENABLE_OBJ\n"
" for(i=0; i<sizeof(Et_ObjSet)/sizeof(Et_ObjSet[0]) - 1; i++){\n"
" Tcl_CreateObjCommand(interp, Et_ObjSet[i].zName, Et_ObjSet[i].xProc, 0, 0);\n"
" }\n"
"#endif\n"
" Tcl_LinkVar(interp,\"Et_EvalTrace\",(char*)&Et_EvalTrace,TCL_LINK_BOOLEAN);\n"
" Tcl_SetVar(interp,\"et_version\",ET_VERSION,TCL_GLOBAL_ONLY);\n"
"#if ET_HAVE_APPINIT\n"
" if( Et_AppInit(interp) == TCL_ERROR ){\n"
" goto initerr;\n"
" }\n"
"#endif\n"
"#if ET_ENABLE_TK && !ET_EXTENSION\n"
" Et_NewBuiltinFile(\"builtin:/console.tcl\", zEtConsole, sizeof(zEtConsole));\n"
"#if ET_CONSOLE\n"
" Tcl_Eval(interp,\n"
" \"source builtin:/console.tcl\\n\"\n"
" \"console:create {.@console} {% } {Tcl/Tk Console}\\n\"\n"
" );\n"
"#endif\n"
"#endif\n"
"#ifdef ET_MAIN_SCRIPT\n"
" if( Et_EvalF(interp,\"source \\\"%q\\\"\", ET_MAIN_SCRIPT)!=TCL_OK ){\n"
" goto initerr;\n"
" }\n"
"#endif\n"
" return TCL_OK;\n"
"\n"
"initerr:\n"
" Et_EvalF(interp,\"Et_Bgerror \\\"%q\\\"\", interp->result);\n"
" return TCL_ERROR;\n"
"}\n"
"\n"
"#if ET_READ_STDIN==0 || ET_AUTO_FORK!=0\n"
"/*\n"
"** Initialize everything.\n"
"*/\n"
"static int Et_Local_Init(int argc, char **argv){\n"
" Tcl_Interp *interp;\n"
" char *args;\n"
" char buf[100];\n"
"#if !ET_HAVE_CUSTOM_MAINLOOP\n"
" static char zWaitForever[] = \n"
"#if ET_ENABLE_TK\n"
" \"bind . <Destroy> {if {![winfo exists .]} exit}\\n\"\n"
"#endif\n"
" \"while 1 {vwait forever}\";\n"
"#endif\n"
"\n"
" Tcl_FindExecutable(argv[0]);\n"
" interp = Tcl_CreateInterp();\n"
" args = Tcl_Merge(argc-1, argv+1);\n"
" Tcl_SetVar(interp, \"argv\", args, TCL_GLOBAL_ONLY);\n"
" ckfree(args);\n"
" sprintf(buf, \"%d\", argc-1);\n"
" Tcl_SetVar(interp, \"argc\", buf, TCL_GLOBAL_ONLY);\n"
" Tcl_SetVar(interp, \"argv0\", argv[0], TCL_GLOBAL_ONLY);\n"
" Tcl_SetVar(interp, \"tcl_interactive\", \"0\", TCL_GLOBAL_ONLY);\n"
" Et_DoInit(interp);\n"
"#if ET_HAVE_CUSTOM_MAINLOOP\n"
" Et_CustomMainLoop(interp);\n"
"#else\n"
" Tcl_Eval(interp,zWaitForever);\n"
"#endif\n"
" return 0;\n"
"}\n"
"#endif\n"
"\n"
"/*\n"
"** This routine is called to do the complete initialization.\n"
"*/\n"
"int Et_Init(int argc, char **argv){\n"
"#ifdef ET_TCL_LIBRARY\n"
" putenv(\"TCL_LIBRARY=\" ET_TCL_LIBRARY);\n"
"#endif\n"
"#ifdef ET_TK_LIBRARY\n"
" putenv(\"TK_LIBRARY=\" ET_TK_LIBRARY);\n"
"#endif\n"
"#if ET_CONSOLE || !ET_READ_STDIN\n"
" Et_Local_Init(argc, argv);\n"
"#else\n"
"# if ET_ENABLE_TK\n"
" Tk_Main(argc,argv,Et_DoInit);\n"
"# else\n"
" Tcl_Main(argc, argv, Et_DoInit);\n"
"# endif\n"
"#endif\n"
" return 0;\n"
"}\n"
"\n"
"#if !ET_HAVE_MAIN && !ET_EXTENSION\n"
"/*\n"
"** Main routine for UNIX programs. If the user has supplied\n"
"** their own main() routine in a C module, then the ET_HAVE_MAIN\n"
"** macro will be set to 1 and this code will be skipped.\n"
"*/\n"
"int main(int argc, char **argv){\n"
"#if ET_AUTO_FORK\n"
" int rc = fork();\n"
" if( rc<0 ){\n"
" perror(\"can't fork\");\n"
" exit(1);\n"
" }\n"
" if( rc>0 ) return 0;\n"
" close(0);\n"
" open(\"/dev/null\",O_RDONLY);\n"
" close(1);\n"
" open(\"/dev/null\",O_WRONLY);\n"
"#endif\n"
" return Et_Init(argc,argv)!=TCL_OK;\n"
"}\n"
"#endif\n"
"\n"
"#if ET_EXTENSION\n"
"/*\n"
"** If the -extension flag is used, then generate code that will be\n"
"** turned into a loadable shared library or DLL, not a standalone\n"
"** executable.\n"
"*/\n"
"int ET_EXTENSION_NAME(Tcl_Interp *interp){\n"
" int i;\n"
"#ifndef ET_HAVE_INSERTPROC\n"
" Tcl_AppendResult(interp,\n"
" \"mktclapp can only generate extensions for Tcl/Tk version \"\n"
" \"8.0.3 and later. This is version \"\n"
" TCL_MAJOR_VERSION \".\" TCL_MINOR_VERSION \".\" TCL_RELEASE_SERIAL, 0);\n"
" return TCL_ERROR;\n"
"#endif\n"
"#ifdef ET_HAVE_INSERTPROC\n"
"#ifdef USE_TCL_STUBS\n"
" if( Tcl_InitStubs(interp,\"8.0\",0)==0 ){\n"
" return TCL_ERROR;\n"
" }\n"
" if( Tk_InitStubs(interp,\"8.0\",0)==0 ){\n"
" return TCL_ERROR;\n"
" }\n"
"#endif\n"
" Et_Interp = interp;\n"
" TclStatInsertProc(Et_FileStat);\n"
" TclAccessInsertProc(Et_FileAccess);\n"
" TclOpenFileChannelInsertProc(Et_FileOpen);\n"
" FilenameHashInit();\n"
" for(i=0; i<sizeof(Et_CmdSet)/sizeof(Et_CmdSet[0]) - 1; i++){\n"
" Tcl_CreateCommand(interp, Et_CmdSet[i].zName, Et_CmdSet[i].xProc, 0, 0);\n"
" }\n"
"#if ET_ENABLE_OBJ\n"
" for(i=0; i<sizeof(Et_ObjSet)/sizeof(Et_ObjSet[0]) - 1; i++){\n"
" Tcl_CreateObjCommand(interp, Et_ObjSet[i].zName, Et_ObjSet[i].xProc, 0, 0);\n"
" }\n"
"#endif\n"
" Tcl_LinkVar(interp,\"Et_EvalTrace\",(char*)&Et_EvalTrace,TCL_LINK_BOOLEAN);\n"
" Tcl_SetVar(interp,\"et_version\",ET_VERSION,TCL_GLOBAL_ONLY);\n"
"#if ET_HAVE_APPINIT\n"
" if( Et_AppInit(interp) == TCL_ERROR ){\n"
" return TCL_ERROR;\n"
" }\n"
"#endif\n"
"#ifdef ET_MAIN_SCRIPT\n"
" if( Et_EvalF(interp,\"source \\\"%q\\\"\", ET_MAIN_SCRIPT)!=TCL_OK ){\n"
" return TCL_ERROR;\n"
" }\n"
"#endif\n"
" return TCL_OK;\n"
"#endif /* ET_HAVE_INSERTPROC */\n"
"}\n"
"int ET_SAFE_EXTENSION_NAME(Tcl_Interp *interp){\n"
" return ET_EXTENSION_NAME(interp);\n"
"}\n"
"#endif\n";