#include "expect_cf.h"
#include <stdio.h>
#include "tclInt.h"
#ifdef NO_STDLIB_H
#include "../compat/stdlib.h"
#else
#include <stdlib.h>
#endif
#include <ctype.h>
#include "expect_comm.h"
#include "exp_int.h"
#include "exp_rename.h"
#include "exp_command.h"
#include "exp_log.h"
typedef struct ThreadSpecificData {
Tcl_Channel diagChannel;
Tcl_DString diagFilename;
int diagToStderr;
Tcl_Channel logChannel;
Tcl_DString logFilename;
int logAppend;
int logLeaveOpen;
int logAll;
int logUser;
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
static char bigbuf[2000];
int
expWriteBytesAndLogIfTtyU(esPtr,buf,lenBytes)
ExpState *esPtr;
char *buf;
int lenBytes;
{
int wc;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (esPtr->valid)
wc = Tcl_WriteChars(esPtr->channel,buf,lenBytes);
if (tsdPtr->logChannel && ((esPtr->fdout == 1) || expDevttyIs(esPtr))) {
Tcl_WriteChars(tsdPtr->logChannel,buf,lenBytes);
}
return wc;
}
void
expLogDiagU(buf)
char *buf;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
expDiagWriteChars(buf,-1);
if (tsdPtr->logChannel) {
Tcl_WriteChars(tsdPtr->logChannel, buf, -1);
}
}
void
expLogInteractionU(esPtr,buf)
ExpState *esPtr;
char *buf;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (tsdPtr->logAll || (tsdPtr->logUser && tsdPtr->logChannel)) {
Tcl_WriteChars(tsdPtr->logChannel,buf,-1);
}
if (tsdPtr->logUser && (!expStdinoutIs(esPtr)) && (!expDevttyIs(esPtr))) {
ExpState *stdinout = expStdinoutGet();
if (stdinout->valid) {
Tcl_WriteChars(stdinout->channel,buf,-1);
}
}
expDiagWriteChars(buf,-1);
}
#define LOGUSER (tsdPtr->logUser || force_stdout)
void
expStdoutLog TCL_VARARGS_DEF(int,arg1)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
int force_stdout;
char *fmt;
va_list args;
force_stdout = TCL_VARARGS_START(int,arg1,args);
fmt = va_arg(args,char *);
if ((!tsdPtr->logUser) && (!force_stdout) && (!tsdPtr->logAll)) return;
(void) vsprintf(bigbuf,fmt,args);
expDiagWriteBytes(bigbuf,-1);
if (tsdPtr->logAll || (LOGUSER && tsdPtr->logChannel)) Tcl_WriteChars(tsdPtr->logChannel,bigbuf,-1);
if (LOGUSER) fprintf(stdout,"%s",bigbuf);
va_end(args);
}
void
expStdoutLogU(buf,force_stdout)
char *buf;
int force_stdout;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
int length;
if ((!tsdPtr->logUser) && (!force_stdout) && (!tsdPtr->logAll)) return;
length = strlen(buf);
expDiagWriteBytes(buf,length);
if (tsdPtr->logAll || (LOGUSER && tsdPtr->logChannel)) Tcl_WriteChars(tsdPtr->logChannel,bigbuf,-1);
if (LOGUSER) {
#if (TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1))
Tcl_WriteChars (Tcl_GetStdChannel (TCL_STDOUT), buf, length);
Tcl_Flush (Tcl_GetStdChannel (TCL_STDOUT));
#else
fwrite(buf,1,length,stdout);
#endif
}
}
void
expErrorLog TCL_VARARGS_DEF(char *,arg1)
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
char *fmt;
va_list args;
fmt = TCL_VARARGS_START(char *,arg1,args);
(void) vsprintf(bigbuf,fmt,args);
expDiagWriteChars(bigbuf,-1);
fprintf(stderr,"%s",bigbuf);
if (tsdPtr->logChannel) Tcl_WriteChars(tsdPtr->logChannel,bigbuf,-1);
va_end(args);
}
void
expErrorLogU(buf)
char *buf;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
int length = strlen(buf);
fwrite(buf,1,length,stderr);
expDiagWriteChars(buf,-1);
if (tsdPtr->logChannel) Tcl_WriteChars(tsdPtr->logChannel,buf,-1);
}
void
expDiagLog TCL_VARARGS_DEF(char *,arg1)
{
char *fmt;
va_list args;
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if ((tsdPtr->diagToStderr == 0) && (tsdPtr->diagChannel == 0)) return;
fmt = TCL_VARARGS_START(char *,arg1,args);
(void) vsprintf(bigbuf,fmt,args);
expDiagWriteBytes(bigbuf,-1);
if (tsdPtr->diagToStderr) {
fprintf(stderr,"%s",bigbuf);
if (tsdPtr->logChannel) Tcl_WriteChars(tsdPtr->logChannel,bigbuf,-1);
}
va_end(args);
}
void
expDiagLogU(str)
char *str;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if ((tsdPtr->diagToStderr == 0) && (tsdPtr->diagChannel == 0)) return;
expDiagWriteBytes(str,-1);
if (tsdPtr->diagToStderr) {
fprintf(stderr,"%s",str);
if (tsdPtr->logChannel) Tcl_WriteChars(tsdPtr->logChannel,str,-1);
}
}
void
expDiagToStderrSet(val)
int val;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->diagToStderr = val;
}
int
expDiagToStderrGet() {
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return tsdPtr->diagToStderr;
}
Tcl_Channel
expDiagChannelGet()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return tsdPtr->diagChannel;
}
void
expDiagChannelClose(interp)
Tcl_Interp *interp;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->diagChannel) return;
Tcl_UnregisterChannel(interp,tsdPtr->diagChannel);
Tcl_DStringFree(&tsdPtr->diagFilename);
tsdPtr->diagChannel = 0;
}
int
expDiagChannelOpen(interp,filename)
Tcl_Interp *interp;
char *filename;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
char *newfilename;
Tcl_ResetResult(interp);
newfilename = Tcl_TranslateFileName(interp,filename,&tsdPtr->diagFilename);
if (!newfilename) return TCL_ERROR;
if (Tcl_DStringValue(&tsdPtr->diagFilename)[0] == '\0') {
Tcl_DStringAppend(&tsdPtr->diagFilename,filename,-1);
}
tsdPtr->diagChannel = Tcl_OpenFileChannel(interp,newfilename,"a",0777);
if (!tsdPtr->diagChannel) {
Tcl_DStringFree(&tsdPtr->diagFilename);
return TCL_ERROR;
}
Tcl_RegisterChannel(interp,tsdPtr->diagChannel);
Tcl_SetChannelOption(interp,tsdPtr->diagChannel,"-buffering","none");
return TCL_OK;
}
void
expDiagWriteObj(obj)
Tcl_Obj *obj;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->diagChannel) return;
Tcl_WriteObj(tsdPtr->diagChannel,obj);
}
void
expDiagWriteBytes(str,len)
char *str;
int len;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->diagChannel) return;
Tcl_Write(tsdPtr->diagChannel,str,len);
}
void
expDiagWriteChars(str,len)
char *str;
int len;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->diagChannel) return;
Tcl_WriteChars(tsdPtr->diagChannel,str,len);
}
char *
expDiagFilename()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return Tcl_DStringValue(&tsdPtr->diagFilename);
}
void
expLogChannelClose(interp)
Tcl_Interp *interp;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if (!tsdPtr->logChannel) return;
if (Tcl_DStringLength(&tsdPtr->logFilename)) {
Tcl_UnregisterChannel(interp,tsdPtr->logChannel);
Tcl_DStringFree(&tsdPtr->logFilename);
} else {
if (!tsdPtr->logLeaveOpen) {
Tcl_UnregisterChannel(interp,tsdPtr->logChannel);
}
}
tsdPtr->logChannel = 0;
tsdPtr->logAll = 0;
}
int
expLogChannelOpen(interp,filename,append)
Tcl_Interp *interp;
char *filename;
int append;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
char *newfilename;
char mode[2];
if (append) {
strcpy(mode,"a");
} else {
strcpy(mode,"w");
}
Tcl_ResetResult(interp);
newfilename = Tcl_TranslateFileName(interp,filename,&tsdPtr->logFilename);
if (!newfilename) return TCL_ERROR;
if (Tcl_DStringValue(&tsdPtr->logFilename)[0] == '\0') {
Tcl_DStringAppend(&tsdPtr->logFilename,filename,-1);
}
tsdPtr->logChannel = Tcl_OpenFileChannel(interp,newfilename,mode,0777);
if (!tsdPtr->logChannel) {
Tcl_DStringFree(&tsdPtr->logFilename);
return TCL_ERROR;
}
Tcl_RegisterChannel(interp,tsdPtr->logChannel);
Tcl_SetChannelOption(interp,tsdPtr->logChannel,"-buffering","none");
return TCL_OK;
}
int
expLogAppendGet()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return tsdPtr->logAppend;
}
void
expLogAppendSet(app)
int app;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->logAppend = app;
}
int
expLogAllGet()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return tsdPtr->logAll;
}
void
expLogAllSet(app)
int app;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->logAll = app;
}
int
expLogToStdoutGet()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return tsdPtr->logUser;
}
void
expLogToStdoutSet(app)
int app;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->logUser = app;
}
int
expLogLeaveOpenGet()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return tsdPtr->logLeaveOpen;
}
void
expLogLeaveOpenSet(app)
int app;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->logLeaveOpen = app;
}
Tcl_Channel
expLogChannelGet()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return tsdPtr->logChannel;
}
int
expLogChannelSet(interp,name)
Tcl_Interp *interp;
char *name;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
int mode;
if (0 == (tsdPtr->logChannel = Tcl_GetChannel(interp,name,&mode))) {
return TCL_ERROR;
}
if (!(mode & TCL_WRITABLE)) {
tsdPtr->logChannel = 0;
Tcl_SetResult(interp,"channel is not writable",TCL_VOLATILE);
return TCL_ERROR;
}
return TCL_OK;
}
char *
expLogFilenameGet()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return Tcl_DStringValue(&tsdPtr->logFilename);
}
int
expLogUserGet()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
return tsdPtr->logUser;
}
void
expLogUserSet(logUser)
int logUser;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
tsdPtr->logUser = logUser;
}
static char *
expPrintifyReal(s)
char *s;
{
static int destlen = 0;
static char *dest = 0;
char *d;
unsigned int need;
Tcl_UniChar ch;
if (s == 0) return("<null>");
need = strlen(s)*6 + 1;
if (need > destlen) {
if (dest) ckfree(dest);
dest = ckalloc(need);
destlen = need;
}
for (d = dest;*s;) {
s += Tcl_UtfToUniChar(s, &ch);
if (ch == '\r') {
strcpy(d,"\\r"); d += 2;
} else if (ch == '\n') {
strcpy(d,"\\n"); d += 2;
} else if (ch == '\t') {
strcpy(d,"\\t"); d += 2;
} else if ((ch < 0x80) && isprint(UCHAR(ch))) {
*d = (char)ch; d += 1;
} else {
sprintf(d,"\\u%04x",ch); d += 6;
}
}
*d = '\0';
return(dest);
}
char *
expPrintifyObj(obj)
Tcl_Obj *obj;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if ((!tsdPtr->diagToStderr) && (!tsdPtr->diagChannel)) return((char *)0);
return expPrintifyReal(Tcl_GetString(obj));
}
char *
expPrintify(s)
char *s;
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
if ((!tsdPtr->diagToStderr) && (!tsdPtr->diagChannel)) return((char *)0);
return expPrintifyReal(s);
}
void
expDiagInit()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_DStringInit(&tsdPtr->diagFilename);
tsdPtr->diagChannel = 0;
tsdPtr->diagToStderr = 0;
}
void
expLogInit()
{
ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
Tcl_DStringInit(&tsdPtr->logFilename);
tsdPtr->logChannel = 0;
tsdPtr->logAll = FALSE;
tsdPtr->logUser = TRUE;
}