src/generic/varchannel.c (208 lines of code) (raw):

/* * varchannel.c - simple channel implementation to write to var * nca-073-9 * * Copyright (c) 1996-2000 by Netcetera AG. * Copyright (c) 2001 by Apache Software Foundation. * All rights reserved. * * See the file "license.terms" for information on usage and * redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. * * @(#) $Id$ * */ #include <stdio.h> #ifdef WIN32 #include <errno.h> #else #include <sys/errno.h> #endif #include <tcl.h> #include "varchannel.h" #include "webout.h" /* belongs to output module of websh */ /* ---------------------------------------------------------------------------- * close var channel * ------------------------------------------------------------------------- */ int varchannelCloseProc(ClientData clientData, Tcl_Interp * interp) { /* printf("DBG varchannelCloseProc\n"); fflush(stdout); */ destroyVarChannel(clientData, interp); /* nothign to do - var is managed by interp */ return 0; } /* ---------------------------------------------------------------------------- * input from var channel * ------------------------------------------------------------------------- */ int varchannelInputProc(ClientData clientData, char *buf, int bufSize, int *errorCodePtr) { char *str = NULL; int strLen = 0; int remains = 0; VarChannel *varChannel = NULL; int isNew = 0; Tcl_Obj *var = NULL; if ((clientData == NULL) || (buf == NULL)) return -1; varChannel = (VarChannel *) clientData; if (varChannel->varName == NULL) return -1; /* -------------------------------------------------------------------------- * get var * ----------------------------------------------------------------------- */ var = Web_GetOrCreateGlobalVar(varChannel->interp, varChannel->varName, &isNew); if (var == NULL) return -1; if (isNew) varChannel->readCursor = 0; /* str = Tcl_GetStringFromObj(var,&strLen); */ str = (char *) Tcl_GetByteArrayFromObj(var, &strLen); if (varChannel->readCursor < strLen) { remains = strLen - varChannel->readCursor; if (bufSize < remains) { strncpy(buf, &(str[varChannel->readCursor]), bufSize); varChannel->readCursor += bufSize; if (isNew) Tcl_DecrRefCount(var); return bufSize; } else { strncpy(buf, &(str[varChannel->readCursor]), remains); varChannel->readCursor += remains; if (isNew) Tcl_DecrRefCount(var); return remains; } } if (isNew) Tcl_DecrRefCount(var); return 0; } /* ---------------------------------------------------------------------------- * output to var channel * ------------------------------------------------------------------------- */ int varchannelOutputProc(ClientData clientData, TCLCONST char *buf, int toWrite, int *errorCodePtr) { VarChannel *varChannel = NULL; int res = -1; int destLen = 0; char *dest = NULL; int bytesConv = 0; Tcl_Obj *tmp = NULL; int isNew = 0; Tcl_Obj *var = NULL; /* sanity */ if ((clientData == NULL) || (buf == NULL)) return res; /* get interna */ varChannel = (VarChannel *) clientData; if (varChannel->varName == NULL) return -1; /* -------------------------------------------------------------------------- * get var * ----------------------------------------------------------------------- */ var = Web_GetOrCreateGlobalVar(varChannel->interp, varChannel->varName, &isNew); if (var == NULL) return -1; if (isNew) { varChannel->readCursor = 0; Tcl_DecrRefCount(var); } /* the conversion * * what we get from Tcl is the string in the encoding of this channel. * Since we are writing to a variable, we need to back-translate * the string to the encding currently in use by Tcl. */ /* convert to UTF */ destLen = (toWrite + 1) * TCL_UTF_MAX + 1; dest = Tcl_Alloc(destLen); if (dest == NULL) return -1; res = Tcl_ExternalToUtf(NULL, NULL, buf, toWrite, 0, NULL, dest, destLen, NULL, &bytesConv, NULL); if (res != TCL_OK) { Tcl_Free(dest); return -1; } /* now put UTF into Tcl_object */ tmp = Tcl_NewStringObj(dest, bytesConv); if (tmp == NULL) { Tcl_Free(dest); return -1; } Tcl_IncrRefCount(tmp); /* and append it to the global var */ var = Tcl_ObjSetVar2(varChannel->interp, varChannel->varName, NULL, tmp, TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LEAVE_ERR_MSG); /* cleanup */ Tcl_Free(dest); Tcl_DecrRefCount(tmp); if (var == NULL) return -1; return toWrite; } /* ---------------------------------------------------------------------------- * watch var channel * ------------------------------------------------------------------------- */ void varchannelWatchProc(ClientData clientData, int mask) { } /* ---------------------------------------------------------------------------- * getHandle for var channel * ------------------------------------------------------------------------- */ int varchannelGetHandleProc(ClientData clientData, int direction, ClientData * handlePtr) { /* "not implemented" */ return EINVAL; } /* ---------------------------------------------------------------------------- * varchannelType * ------------------------------------------------------------------------- */ static Tcl_ChannelType varchannelType = { "varchannel", /* Type name. */ NULL, /* Set blocking/nonblocking mode. */ varchannelCloseProc, /* Close proc. */ varchannelInputProc, /* Input proc. */ varchannelOutputProc, /* Output proc. */ NULL, /* Seek proc. */ NULL, /* Set option proc. */ NULL, /* Get option proc. */ varchannelWatchProc, /* Initialize notifier. */ varchannelGetHandleProc, /* Get OS handles out of channel. */ }; /* ---------------------------------------------------------------------------- * createVarChannel * ------------------------------------------------------------------------- */ VarChannel *createVarChannel() { VarChannel *varChannel = NULL; varChannel = WebAllocInternalData(VarChannel); if (varChannel != NULL) { varChannel->varName = NULL; varChannel->interp = NULL; varChannel->readCursor = 0; } return varChannel; } /* ---------------------------------------------------------------------------- * destroyVarChannel * ------------------------------------------------------------------------- */ int destroyVarChannel(ClientData clientData, Tcl_Interp * interp) { VarChannel *varChannel = NULL; /* printf("DBG - destroyVarChannel\n"); fflush(stdout); */ if (clientData != NULL) { varChannel = (VarChannel *) clientData; WebDecrRefCountIfNotNull(varChannel->varName); Tcl_Free((char *) varChannel); } return TCL_OK; } /* ---------------------------------------------------------------------------- * Web_GetChannelOrVarChannel - Tcl_GetChannel alike * ------------------------------------------------------------------------- */ Tcl_Channel Web_GetChannelOrVarChannel(Tcl_Interp * interp, char *name, int *mode) { Tcl_Channel channel = NULL; if ((interp == NULL) || (name == NULL) || (mode == NULL)) return NULL; if (name[0] == '#') { /* get varchannel */ channel = Web_GetVarChannel(interp, name, mode); } else { /* get normal channel */ channel = Tcl_GetChannel(interp, name, mode); } return channel; } /* ---------------------------------------------------------------------------- * Web_GetVarChannel - Tcl_GetChannel alike * ------------------------------------------------------------------------- */ Tcl_Channel Web_GetVarChannel(Tcl_Interp * interp, char *name, int *mode) { Tcl_Obj *varNameObj = NULL; Tcl_Obj *var = NULL; VarChannel *varChannel = NULL; Tcl_Channel channel = NULL; int isNew = 0; /* -------------------------------------------------------------------------- * expect two characters at least * ----------------------------------------------------------------------- */ if (strlen(name) < 2) return NULL; /* -------------------------------------------------------------------------- * does channel already exist - good * ----------------------------------------------------------------------- */ channel = Tcl_GetChannel(interp, name, mode); if (channel != NULL) return channel; /* -------------------------------------------------------------------------- * unset Tcl_Result (we are not intetested, thank you) * ----------------------------------------------------------------------- */ Tcl_ResetResult(interp); /* -------------------------------------------------------------------------- * create VarChannel * ----------------------------------------------------------------------- */ varChannel = createVarChannel(); if (varChannel == NULL) return NULL; /* -------------------------------------------------------------------------- * create name * ----------------------------------------------------------------------- */ varNameObj = Tcl_NewStringObj(&name[1], -1); Tcl_IncrRefCount(varNameObj); varChannel->varName = varNameObj; varChannel->interp = interp; /* -------------------------------------------------------------------------- * create name * ----------------------------------------------------------------------- */ var = Web_GetOrCreateGlobalVar(varChannel->interp, varChannel->varName, &isNew); if (isNew) Tcl_DecrRefCount(var); /* -------------------------------------------------------------------------- * create channel * ----------------------------------------------------------------------- */ *mode = TCL_READABLE | TCL_WRITABLE; channel = Tcl_CreateChannel(&varchannelType, name, (ClientData) varChannel, *mode); /* printf("DBG Web_GetVarChannel - gonna register '%s'\n",name); fflush(stdout); */ Tcl_RegisterChannel(interp, channel); return channel; } /* ---------------------------------------------------------------------------- * Web_UnregisterVarChannel - Tcl_UnregisterChannel * ------------------------------------------------------------------------- */ int Web_UnregisterVarChannel(Tcl_Interp * interp, char *name, Tcl_Channel channel) { if ((interp == NULL) || (name == NULL)) return TCL_ERROR; /* if name does not start with # we don't care */ if (name[0] != '#') return TCL_OK; if (channel == NULL) { int mode = 0; channel = Tcl_GetChannel(interp, name, &mode); if (channel == NULL) return TCL_ERROR; } return Tcl_UnregisterChannel(interp, channel); }