Files
sics/exeman.c
Koennecke Mark 66466c1c0f This is the first working version of the new logging system. Some work
in fine tuning still needs to be done. But is reasonably OK now.
2016-02-11 13:40:31 +01:00

1456 lines
38 KiB
C

/**
* Implementation file for the exe buffer buffer manager.
*
* copyright: see file COPYRIGHT
*
* More information in exe.tex
*
* Mark Koennecke, November 2004
*/
#include <stdio.h>
#include <assert.h>
#include <tcl.h>
#include <dirent.h>
#include <ctype.h>
#include "fortify.h"
#include "sics.h"
#include "sdynar.h"
#include "dynstring.h"
#include "lld.h"
#include "splitter.h"
#include "exebuf.h"
#include "exeman.i"
#include "exeman.h"
#include "sicshipadaba.h"
#include "protocol.h"
/*-------------------------------------------------------------------*/
static void KillExeMan(void *data)
{
pExeMan self = (pExeMan) data;
if (!self) {
return;
}
if (self->pDes) {
DeleteDescriptor(self->pDes);
}
if (self->pCall) {
DeleteCallBackInterface(self->pCall);
}
if (self->batchPath) {
free(self->batchPath);
}
if (self->sysPath) {
free(self->sysPath);
}
if (self->exeStack) {
DeleteDynar(self->exeStack);
}
LLDdelete(self->runList);
free(self);
}
/*-----------------------------------------------------------------*/
static int SaveExeMan(void *data, char *name, FILE * fd)
{
pExeMan self = (pExeMan) data;
if (!self) {
return 0;
}
fprintf(fd, "%s batchpath %s\n", name, self->batchPath);
fprintf(fd, "%s syspath %s\n", name, self->sysPath);
return 1;
}
/*-----------------------------------------------------------------*/
static void *ExeManInterface(void *data, int interfaceID)
{
pExeMan self = (pExeMan) data;
if (self == NULL) {
return NULL;
}
if (interfaceID == CALLBACKINTERFACE) {
return self->pCall;
}
return NULL;
}
/*------------------------------------------------------------------*/
int MakeExeManager(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pExeMan pNew = NULL;
int status;
pNew = (pExeMan) malloc(sizeof(ExeMan));
if (!pNew) {
SCWrite(pCon, "ERROR: out of memory creating exe Manager", eError);
return 0;
}
memset(pNew, 0, sizeof(ExeMan));
pNew->pDes = CreateDescriptor("ExeManager");
pNew->pCall = CreateCallBackInterface();
pNew->sysPath = strdup("./");
pNew->batchPath = strdup("./");
pNew->exeStack = CreateDynar(1, 10, 10, exeBufKill);
pNew->exeStackPtr = -1;
pNew->runList = LLDcreate(sizeof(pExeBuf));
if (!pNew->pDes || !pNew->pCall || !pNew->batchPath ||
!pNew->exeStack || pNew->runList < 0) {
SCWrite(pCon, "ERROR: out of memory creating exe Manager", eError);
return 0;
}
pNew->pDes->SaveStatus = SaveExeMan;
pNew->pDes->GetInterface = ExeManInterface;
if (argc > 1) {
status = AddCommand(pSics,
argv[1], ExeManagerWrapper, KillExeMan, pNew);
} else {
status = AddCommand(pSics, "exe", ExeManagerWrapper, KillExeMan, pNew);
}
if (status != 1) {
SCWrite(pCon, "ERROR: duplicate exe manager not created", eError);
return 0;
}
return 1;
}
/*======================== buffer execution ==========================*/
static int fileExists(char *path)
{
FILE *fd = NULL;
int status = 0;
fd = fopen(path, "r");
if (fd != NULL) {
fclose(fd);
status = 1;
}
return status;
}
/*--------------------------------------------------------------------*/
extern char *stptok(char *s, char *t, int len, char *brk);
static pDynString locateBatchBuffer(pExeMan self, char *name)
{
pDynString result = NULL;
char pPath[132], *pPtr = NULL;
result = CreateDynString(256, 256);
if (!result) {
return NULL;
}
/*
do not try to convert absolute paths
*/
if (name[0] == '/') {
DynStringCopy(result, name);
if (fileExists(GetCharArray(result))) {
return result;
} else {
return NULL;
}
}
pPtr = self->batchPath;
while ((pPtr = stptok(pPtr, pPath, 131, ":")) != NULL) {
DynStringCopy(result, pPath);
DynStringConcatChar(result, '/');
DynStringConcat(result, name);
if (fileExists(GetCharArray(result))) {
return result;
}
}
pPtr = self->sysPath;
while ((pPtr = stptok(pPtr, pPath, 131, ":")) != NULL) {
DynStringCopy(result, pPath);
DynStringConcatChar(result, '/');
DynStringConcat(result, name);
if (fileExists(GetCharArray(result))) {
return result;
}
}
DeleteDynString(result);
return NULL;
}
/*-------------------------------------------------------------------
* Generate a full path name for the argument in the first
* directory of batch path
* -------------------------------------------------------------------*/
static int makeExePath(pExeMan self, SConnection * pCon, int argc,
char *argv[])
{
char buffer[512], *pPtr = NULL, pPath[132];
if (argc < 3) {
SCWrite(pCon, "ERROR: require a file name for makepath", eError);
return 0;
}
strcpy(buffer, "exe.makepath = ");
/*
* do nothing to absolute path
*/
if (argv[2][0] == '/') {
strlcat(buffer, argv[2], sizeof buffer);
SCWrite(pCon, buffer, eValue);
return 1;
}
pPtr = self->batchPath;
pPtr = stptok(pPtr, pPath, 131, ":");
strlcat(buffer, pPath, sizeof buffer);
strlcat(buffer, "/", sizeof buffer);
strlcat(buffer, argv[2], sizeof buffer);
SCWrite(pCon, buffer, eValue);
return 1;
}
/*--------------------------------------------------------------------*/
pDynString findBatchFile(SicsInterp * pSics, char *name)
{
pExeMan self = (pExeMan) FindCommandData(pSics, "exe", "ExeManager");
if (self == NULL) {
return NULL;
}
return locateBatchBuffer(self, name);
}
/*--------------------------------------------------------------------*/
int isBatchRunning()
{
pExeMan self = (pExeMan) FindCommandData(pServ->pSics, "exe", "ExeManager");
if(self != NULL && self->exeStackPtr > 0){
return 1;
} else {
return 0;
}
}
/*--------------------------------------------------------------------*/
static int runBatchBuffer(pExeMan self, SConnection * pCon,
SicsInterp * pSics, char *name)
{
pDynString filePath = NULL;
char pBueffel[256];
pExeBuf buffer = NULL;
int status;
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
if (self->runCon != NULL && self->runCon != pCon) {
SCWrite(pCon, "ERROR: another batch buffer is already runnig", eError);
return 0;
}
filePath = locateBatchBuffer(self, name);
if (filePath == NULL) {
snprintf(pBueffel, 255, "ERROR: batch buffer %s not found in path",
name);
SCWrite(pCon, pBueffel, eError);
return 0;
}
buffer = exeBufCreate(name);
if (!buffer) {
DeleteDynString(filePath);
SCWrite(pCon, "ERROR: out of memory creating batch buffer", eError);
return 0;
}
status = exeBufLoad(buffer, GetCharArray(filePath));
if (!status) {
DeleteDynString(filePath);
SCWrite(pCon, "ERROR: failed to load batch buffer", eError);
return 0;
}
DeleteDynString(filePath);
self->exeStackPtr++;
DynarPut(self->exeStack, self->exeStackPtr, buffer);
status = exeBufProcess(buffer, pSics, pCon, self->pCall, self->echo);
self->exeStackPtr--;
return status;
}
/*-------------------------------------------------------------------*/
static char bufferNode[512];
static int SCHdbWrite(SConnection * self, char *message, int outCode)
{
pHdb node = NULL;
char pBueffel[512];
commandContext cc;
hdbValue v;
pDynString val = NULL;
writeFunc defWrite = NULL;
cc = SCGetContext(self);
node = GetHipadabaNode(GetHipadabaRoot(), cc.deviceID);
if (node == NULL || strstr(cc.deviceID, bufferNode) == NULL) {
/*
* this means the deviceId is wrong and the output is for another
* operation.
*/
defWrite = GetProtocolWriteFunc(self);
if (defWrite == NULL) {
defWrite = SCNormalWrite;
}
defWrite(self, message, outCode);
return 1;
}
SCFileWrite(self, message, outCode);
if (SCinMacro(self) && (outCode != eError && outCode != eWarning)) {
return 1;
}
v = MakeHdbText(strdup(""));
GetHipadabaPar(node, &v, NULL);
v.dataType = HIPTEXT;
val = CreateDynString(128, 128);
if (val == NULL) {
Log(ERROR,"sys","%s", "No memory to append to log in SCHdbWrite");
return 0;
}
if (v.v.text != NULL) {
DynStringConcat(val, v.v.text);
if (strrchr(v.v.text, (int) '\n') == NULL && strlen(v.v.text) > 1) {
DynStringConcatChar(val, '\n');
}
}
DynStringConcat(val, message);
if (strrchr(message, (int) '\n') == NULL && strlen(message) > 1) {
DynStringConcatChar(val, '\n');
}
if (v.v.text != NULL) {
free(v.v.text);
}
v.v.text = GetCharArray(val);
UpdateHipadabaPar(node, v, NULL);
DeleteDynString(val);
return 1;
}
/*--------------------------------------------------------------------*/
int exeHdbNode(pHdb exeNode, SConnection * pCon)
{
char pBueffel[512], *name = NULL;
pHdb node = NULL, log = NULL;
pExeBuf buffer = NULL;
hdbValue v;
int status;
SConnection *conCon = NULL;
/*
* clear log buffer
*/
log = GetHipadabaNode(exeNode, "log");
if (log == NULL) {
SCWrite(pCon, "ERROR: Hdb node not found or in wrong format", eError);
return 0;
}
v = MakeHdbText(strdup(""));
UpdateHipadabaPar(log, v, pCon);
/*
* prepare context
*/
name = GetHipadabaPath(log);
conCon = SCCopyConnection(pCon);
if (conCon == NULL) {
SCWrite(pCon, "ERROR: out of memory in exehdbNode", eError);
return 0;
}
strlcpy(conCon->deviceID, name, 255);
strlcpy(bufferNode, name, 511);
/*
* load commands into buffer
*/
node = GetHipadabaNode(exeNode, "commands");
if (node == NULL) {
SCWrite(pCon, "ERROR: Hdb node not found or in wrong format", eError);
return 0;
}
GetHipadabaPar(node, &v, pCon);
if (v.dataType != HIPTEXT || v.v.text == NULL) {
SCWrite(pCon, "ERROR: Hdb node is of wrong type or contains no data",
eError);
return 0;
}
buffer = exeBufCreate(name);
if (!buffer) {
SCWrite(pCon, "ERROR: out of memory creating batch buffer", eError);
return 0;
}
exeBufAppend(buffer, v.v.text);
strlcpy(bufferNode, name, 511);
SCSetWriteFunc(conCon, SCHdbWrite);
status = exeBufProcess(buffer, pServ->pSics, conCon, NULL, 0);
SCDeleteConnection(conCon);
exeBufDelete(buffer);
free(name);
if (strlen(log->value.v.text) < 2) {
v = MakeHdbText(strdup("OK\n"));
UpdateHipadabaPar(log, v, pCon);
ReleaseHdbValue(&v);
}
return status;
}
/*--------------------------------------------------------------------*/
static int runHdbBuffer(pExeMan self, SConnection * pCon,
SicsInterp * pSics, char *name)
{
char pBueffel[512];
pExeBuf buffer = NULL;
pHdb node = NULL;
hdbValue v;
int status;
SConnection *conCon = NULL;
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
if (self->runCon != NULL && self->runCon != pCon) {
SCWrite(pCon, "ERROR: another bacth buffer is still running", eError);
return 0;
}
/*
* clear log buffer
*/
snprintf(pBueffel, 511, "%s/log", name);
node = GetHipadabaNode(GetHipadabaRoot(), pBueffel);
if (node == NULL) {
SCWrite(pCon, "ERROR: Hdb node not found or in wrong format", eError);
return 0;
}
v = MakeHdbText(strdup(""));
UpdateHipadabaPar(node, v, pCon);
/*
* prepare context
*/
conCon = SCCopyConnection(pCon);
strlcpy(conCon->deviceID, pBueffel,255);
/*
* load commands into buffer
*/
snprintf(pBueffel, 511, "%s/commands", name);
node = GetHipadabaNode(GetHipadabaRoot(), pBueffel);
if (node == NULL) {
SCWrite(pCon, "ERROR: Hdb node not found or in wrong format", eError);
return 0;
}
GetHipadabaPar(node, &v, pCon);
if (v.dataType != HIPTEXT || v.v.text == NULL) {
SCWrite(pCon, "ERROR: Hdb node is of wrong type or contains no data",
eError);
return 0;
}
buffer = exeBufCreate(name);
if (!buffer) {
SCWrite(pCon, "ERROR: out of memory creating batch buffer", eError);
return 0;
}
exeBufAppend(buffer, v.v.text);
strlcpy(bufferNode, name, 511);
SCSetWriteFunc(conCon, SCHdbWrite);
self->exeStackPtr++;
self->runCon = conCon;
DynarPut(self->exeStack, self->exeStackPtr, buffer);
status = exeBufProcess(buffer, pSics, conCon, self->pCall, self->echo);
self->exeStackPtr--;
self->runCon = NULL;
SCDeleteConnection(conCon);
return status;
}
/*--------------------------------------------------------------------*/
int exeHdbBuffer(SConnection * pCon, SicsInterp * pSics, char *name)
{
pExeMan self = (pExeMan) FindCommandData(pSics, "exe", "ExeManager");
if (self != NULL) {
return runHdbBuffer(self, pCon, pSics, name);
}
return 0;
}
/*-------------------------------------------------------------------*/
int runExeBatchBuffer(void *pData, SConnection * pCon,
SicsInterp * pSics, char *name)
{
int status, oldEcho;
pExeMan self = (pExeMan) pData;
oldEcho = self->echo;
self->echo = 1;
status = runBatchBuffer(self, pCon, pSics, name);
self->echo = oldEcho;
return status;
}
/*========================== path management ========================*/
static int handleBatchPath(pExeMan self, SConnection * pCon, int argc,
char *argv[])
{
char pBuffer[1024];
if (strcasecmp(argv[1], "batchpath") == 0) {
if (argc > 2) {
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
if (self->batchPath != NULL) {
free(self->batchPath);
}
self->batchPath = strdup(argv[2]);
if(self->batchPath[0] != '/'){
SCPrintf(pCon,eLog, "WARNING: batchpath %s not an absolute path", argv[2]);
} else {
SCSendOK(pCon);
}
SCparChange(pCon);
return 1;
} else {
snprintf(pBuffer, 1023, "%s.batchpath = %s", argv[0],
self->batchPath);
SCWrite(pCon, pBuffer, eValue);
return 1;
}
}
if (strcasecmp(argv[1], "syspath") == 0) {
if (argc > 2) {
if (!SCMatchRights(pCon, usMugger)) {
return 0;
}
if (self->sysPath != NULL) {
free(self->sysPath);
}
self->sysPath = strdup(argv[2]);
SCSendOK(pCon);
SCparChange(pCon);
return 1;
} else {
snprintf(pBuffer, 1023, "%s.syspath = %s", argv[0], self->sysPath);
SCWrite(pCon, pBuffer, eValue);
return 1;
}
}
return -1;
}
/*=========================== callbacks ==============================*/
typedef struct {
SConnection *pCon;
pExeMan exe;
} exeInfo, *pExeInfo;
/*------------------------------------------------------------------*/
static void killExeInfo(void *pData)
{
pExeInfo self = (pExeInfo) pData;
if (self->pCon != NULL) {
SCDeleteConnection(self->pCon);
}
if (self != NULL) {
free(self);
}
}
/*-----------------------------------------------------------------*/
static pExeInfo makeExeInfo(SConnection * pCon, pExeMan self)
{
pExeInfo pNew = NULL;
pNew = malloc(sizeof(exeInfo));
if (pNew == NULL) {
SCWrite(pCon,
"ERROR: failed to allocate info structure for registering callbacks",
eError);
return NULL;
}
memset(pNew, 0, sizeof(exeInfo));
pNew->pCon = SCCopyConnection(pCon);
if (pNew->pCon == NULL) {
SCWrite(pCon,
"ERROR: failed to allocate info structure for registering callbacks",
eError);
return NULL;
}
pNew->exe = self;
return pNew;
}
/*------------------------------------------------------------------*/
static int BufferCallback(int iEvent, void *pEvent, void *pUser)
{
pExeInfo self = (pExeInfo) pUser;
char *name = (char *) pEvent;
char pBueffel[132];
if (!SCisConnected(self->pCon)) {
return -1;
}
if (iEvent == BATCHSTART) {
snprintf(pBueffel, 131, "BATCHSTART=%s", name);
SCWrite(self->pCon, pBueffel, eLog);
return 1;
}
if (iEvent == BATCHEND) {
snprintf(pBueffel, 131, "BATCHEND=%s", name);
SCWrite(self->pCon, pBueffel, eLog);
return 1;
}
return 0;
}
/*-------------------------------------------------------------------*/
static int LineCallBack(int iEvent, void *pEvent, void *pUser)
{
pExeInfo self = (pExeInfo) pUser;
char pBueffel[256];
int start, end, lineno;
void *pPtr = NULL;
pExeBuf buf = NULL;
assert(self);
if (!SCisConnected(self->pCon)) {
return -1;
}
if (iEvent == BATCHAREA) {
DynarGet(self->exe->exeStack, self->exe->exeStackPtr, &pPtr);
buf = (pExeBuf) pPtr;
assert(buf);
exeBufRange(buf, &start, &end, &lineno);
snprintf(pBueffel, 255, "%s.range = %d = %d", exeBufName(buf),
start, end);
SCWrite(self->pCon, pBueffel, eLog);
return 1;
}
return 0;
}
/*--------------------------------------------------------------------*/
static void registerCallbacks(SConnection * pCon, SicsInterp * pSics,
pExeMan self)
{
pExeInfo info = NULL;
long lID;
info = makeExeInfo(pCon, self);
if (info == NULL) {
return;
}
lID = RegisterCallback(self->pCall, BATCHSTART, BufferCallback,
info, killExeInfo);
lID = RegisterCallback(self->pCall, BATCHEND, BufferCallback,
info, NULL);
lID = RegisterCallback(self->pCall, BATCHAREA, LineCallBack, info, NULL);
}
/*--------------------------------------------------------------------*/
static void unregisterCallbacks(SConnection * pCon, pExeMan self)
{
long lID;
int i;
for (i = 0; i < 3; i++) {
lID = SCgetCallbackID(pCon, self->pCall);
if (lID >= 0) {
RemoveCallback(self->pCall, lID);
}
}
}
/*========================= uploading ===============================*/
static int startUpload(pExeMan self, SConnection * pCon)
{
if (SCGetRights(pCon) > usUser) {
SCWrite(pCon, "ERROR: no permission to upload buffers", eError);
return 0;
}
if (self->uploadBuffer != NULL) {
SCWrite(pCon, "ERRO: another upload is still in progress", eError);
return 0;
}
self->uploadBuffer = exeBufCreate("upload");
if (self->uploadBuffer == NULL) {
SCWrite(pCon, "ERROR: failed to create upload buffer", eError);
return 0;
}
return 1;
}
/*-------------------------------------------------------------------*/
static int clearUpload(pExeMan self, SConnection * pCon)
{
if (SCGetRights(pCon) > usUser) {
SCWrite(pCon, "ERROR: no permission to clear buffer upload", eError);
return 0;
}
if (self->uploadBuffer != NULL) {
exeBufDelete(self->uploadBuffer);
self->uploadBuffer = NULL;
}
return 1;
}
/*---------------------------------------------------------------------*/
static int appendLine(pExeMan self, SConnection * pCon,
int argc, char *argv[])
{
char pLine[1024];
if (SCGetRights(pCon) > usUser) {
SCWrite(pCon, "ERROR: no permission to upload buffers", eError);
return 0;
}
if (self->uploadBuffer == NULL) {
SCWrite(pCon, "ERROR: no upload in operation", eError);
return 0;
}
memset(pLine,0,sizeof(pLine));
Arg2Text(argc - 2, &argv[2], pLine, 1023);
exeBufAppend(self->uploadBuffer, pLine);
return 1;
}
/*--------------------------------------------------------------------*/
static int uploadForceSave(pExeMan self, SConnection * pCon,
int argc, char *argv[])
{
int status;
char pPath[256], *pPtr;
if (SCGetRights(pCon) > usUser) {
SCWrite(pCon, "ERROR: no permission to save buffers", eError);
return 0;
}
if (argc < 3) {
SCWrite(pCon, "ERROR: no file given to save upload buffer to", eError);
return 0;
}
if (self->uploadBuffer == NULL) {
SCWrite(pCon, "ERROR: no upload buffer to save exists", eError);
return 0;
}
if (argv[2][0] != '/') {
pPtr = self->batchPath;
pPtr = stptok(pPtr, pPath, 131, ":");
if (strlen(pPath) + 1 + strlen(argv[2]) <= 256) {
strlcat(pPath, "/",255);
strlcat(pPath, argv[2],255);
} else {
strlcpy(pPath, argv[2], 255);
}
} else {
strlcpy(pPath, argv[2], 131);
}
status = exeBufSave(self->uploadBuffer, pPath);
if (status == 0) {
SCWrite(pCon, "ERROR: failed to save exe buffer, destroyed...",
eError);
}
exeBufDelete(self->uploadBuffer);
self->uploadBuffer = NULL;
return status;
}
/*--------------------------------------------------------------------*/
static int uploadSave(pExeMan self, SConnection * pCon,
int argc, char *argv[])
{
int status;
char pPath[256], *pPtr;
if (SCGetRights(pCon) > usUser) {
SCWrite(pCon, "ERROR: no permission to save buffers", eError);
return 0;
}
if (argc < 3) {
SCWrite(pCon, "ERROR: no file given to save upload buffer to", eError);
return 0;
}
if (self->uploadBuffer == NULL) {
SCWrite(pCon, "ERROR: no upload buffer to save exists", eError);
return 0;
}
if (argv[2][0] != '/') {
pPtr = self->batchPath;
pPtr = stptok(pPtr, pPath, 131, ":");
if (strlen(pPath) + 1 + strlen(argv[2]) <= 256) {
strcat(pPath, "/");
strcat(pPath, argv[2]);
} else {
strlcpy(pPath, argv[2], 255);
}
} else {
strlcpy(pPath, argv[2], 131);
}
if (fileExists(pPath)) {
SCWrite(pCon, "ERROR: file exists", eError);
return 0;
}
status = exeBufSave(self->uploadBuffer, pPath);
if (status == 0) {
SCWrite(pCon, "ERROR: failed to save exe buffer, destroyed...",
eError);
}
exeBufDelete(self->uploadBuffer);
self->uploadBuffer = NULL;
return status;
}
/*---------------------------------------------------------------------------------*/
/* See if a string matches a wildcard specification that uses * or ?
(like "*.txt"), and return TRUE or FALSE, depending on the result.
There's also a TRUE/FALSE parameter you use to indicate whether
the match should be case-sensitive or not.
*/
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
/*--------------------------------------------------------------------------------*/
static int IsWildcardMatch(char *wildcardString, char *stringToCheck,
int caseSensitive)
{
char wcChar;
char strChar;
// use the starMatchesZero variable to determine whether an asterisk
// matches zero or more characters (TRUE) or one or more characters
// (FALSE)
int starMatchesZero = TRUE;
while ((strChar = *stringToCheck) && (wcChar = *wildcardString)) {
// we only want to advance the pointers if we successfully assigned
// both of our char variables, so we'll do it here rather than in the
// loop condition itself
(void)*stringToCheck++;
(void)*wildcardString++;
// if this isn't a case-sensitive match, make both chars uppercase
// (thanks to David John Fielder (Konan) at http://innuendo.ev.ca
// for pointing out an error here in the original code)
if (!caseSensitive) {
wcChar = toupper(wcChar);
strChar = toupper(strChar);
}
// check the wcChar against our wildcard list
switch (wcChar) {
// an asterisk matches zero or more characters
case '*':
// do a recursive call against the rest of the string,
// until we've either found a match or the string has
// ended
if (starMatchesZero)
(void)*stringToCheck--;
while (*stringToCheck) {
if (IsWildcardMatch
(wildcardString, stringToCheck++, caseSensitive))
return TRUE;
}
break;
// a question mark matches any single character
case '?':
break;
// if we fell through, we want an exact match
default:
if (wcChar != strChar)
return FALSE;
break;
}
}
// if we have any asterisks left at the end of the wildcard string, we can
// advance past them if starMatchesZero is TRUE (so "blah*" will match "blah")
while ((*wildcardString) && (starMatchesZero)) {
if (*wildcardString == '*')
wildcardString++;
else
break;
}
// if we got to the end but there's still stuff left in either of our strings,
// return false; otherwise, we have a match
if ((*stringToCheck) || (*wildcardString))
return FALSE;
else
return TRUE;
}
/*----------------------------------------------------------------------------*/
static int wwmatch(char *pattern, char *name)
{
return IsWildcardMatch(pattern, name, 1);
}
/*--------------------------------------------------------------------
search the directory pPath for file matching pattern. Successfull
files will be appended to result
-----------------------------------------------------------------------*/
static void searchDir(char *pPath, char *pattern, pDynString result)
{
DIR *currentdir = NULL;
struct dirent *currentFile = NULL;
currentdir = opendir(pPath);
if (currentdir == NULL) {
return;
}
currentFile = readdir(currentdir);
while (currentFile != NULL) {
if (wwmatch(pattern, currentFile->d_name)) {
DynStringConcat(result, currentFile->d_name);
DynStringConcatChar(result, '\n');
}
currentFile = readdir(currentdir);
}
closedir(currentdir);
}
/*--------------------------------------------------------------------*/
static pDynString findDirEntries(pExeMan self, char *pattern)
{
pDynString result = NULL;
char pPath[132], *pPtr = NULL;
result = CreateDynString(256, 256);
if (!result) {
return NULL;
}
pPtr = self->batchPath;
while ((pPtr = stptok(pPtr, pPath, 131, ":")) != NULL) {
searchDir(pPath, pattern, result);
}
pPtr = self->sysPath;
while ((pPtr = stptok(pPtr, pPath, 131, ":")) != NULL) {
searchDir(pPath, pattern, result);
}
return result;
}
/*=========================== info ===================================*/
static void printExeStack(pExeMan self, SConnection * pCon)
{
int i, j;
pDynString txt = NULL;
pExeBuf buf;
void *pPtr = NULL;
txt = CreateDynString(80, 80);
if (txt == NULL) {
SCWrite(pCon, "ERROR: failed to allocate memory in printExeStack",
eError);
return;
}
for (i = 0; i <= self->exeStackPtr; i++) {
DynarGet(self->exeStack, i, &pPtr);
buf = (pExeBuf) pPtr;
assert(buf);
for (j = 0; j < i; j++) {
DynStringConcat(txt, " ");
}
DynStringConcat(txt, exeBufName(buf));
DynStringConcatChar(txt, '\n');
}
SCWrite(pCon, GetCharArray(txt), eValue);
DeleteDynString(txt);
}
/*-----------------------------------------------------------------*/
static int locateBuffer(pExeMan self, char *name)
{
int i;
pExeBuf buf;
void *pPtr = NULL;
for (i = 0; i <= self->exeStackPtr; i++) {
DynarGet(self->exeStack, i, &pPtr);
buf = (pExeBuf) pPtr;
if (strcmp(name, exeBufName(buf)) == 0) {
return i;
}
}
return -1;
}
/*------------------------------------------------------------------*/
static void printExeRange(pExeMan self, SConnection * pCon,
int argc, char *argv[])
{
int start, end, lineno, bufNo;
pExeBuf buf;
void *pPtr = NULL;
char pBueffel[256];
if (argc > 3) {
bufNo = locateBuffer(self, argv[3]);
} else {
bufNo = self->exeStackPtr;
}
if (bufNo < 0) {
SCWrite(pCon, "ERROR: named buffer not found", eError);
return;
}
DynarGet(self->exeStack, bufNo, &pPtr);
buf = (pExeBuf) pPtr;
assert(buf);
exeBufRange(buf, &start, &end, &lineno);
snprintf(pBueffel, 255, "%s.range = %d = %d = %d", exeBufName(buf),
start, end, lineno);
SCWrite(pCon, pBueffel, eValue);
}
/*------------------------------------------------------------------*/
static void printExeText(pExeMan self, SConnection * pCon,
int argc, char *argv[])
{
int start, end, lineno, bufNo;
pExeBuf buf;
void *pPtr = NULL;
pDynString txt;
if (argc > 3) {
bufNo = locateBuffer(self, argv[3]);
} else {
bufNo = self->exeStackPtr;
}
if (bufNo < 0) {
SCWrite(pCon, "ERROR: named buffer not found", eError);
return;
}
DynarGet(self->exeStack, bufNo, &pPtr);
buf = (pExeBuf) pPtr;
assert(buf);
exeBufRange(buf, &start, &end, &lineno);
txt = exeBufText(buf, start, end);
if (txt != NULL) {
SCWrite(pCon, GetCharArray(txt), eValue);
DeleteDynString(txt);
} else {
SCWrite(pCon, "ERROR: failed to allocate text buffer for operation",
eError);
}
}
/*------------------------------------------------------------------*/
static void printQueue(pExeMan self, SConnection * pCon)
{
pExeBuf buf = NULL;
pDynString text = NULL;
int status;
text = CreateDynString(80, 80);
if (text == NULL) {
SCWrite(pCon, "ERROR: out of memory", eError);
return;
}
status = LLDnodePtr2First(self->runList);
while (status != 0) {
LLDnodeDataTo(self->runList, &buf);
if (buf != NULL) {
DynStringConcat(text, exeBufName(buf));
DynStringConcatChar(text, '\n');
}
status = LLDnodePtr2Next(self->runList);
}
SCWrite(pCon, GetCharArray(text), eValue);
DeleteDynString(text);
}
/*-------------------------------------------------------------------*/
static int infoHandler(pExeMan self, SConnection * pCon,
int argc, char *argv[])
{
char pBueffel[256];
pExeBuf buf;
void *pPtr = NULL;
if (self->exeStackPtr < 0) {
SCWrite(pCon, "Idle", eValue);
return 1;
}
if (argc < 3) {
if (self->exeStackPtr >= 0) {
DynarGet(self->exeStack, self->exeStackPtr, &pPtr);
buf = (pExeBuf) pPtr;
if (buf != NULL) {
snprintf(pBueffel, 255, "Executing %s", exeBufName(buf));
SCWrite(pCon, pBueffel, eValue);
return 1;
}
}
SCWrite(pCon, "Nothing to execute", eValue);
return 1;
} else {
/*
argv must no be modifed, use strcasecmp instead M.Z.
strtolower(argv[2]);
*/
if (strcasecmp(argv[2], "stack") == 0) {
printExeStack(self, pCon);
return 1;
} else if (strcasecmp(argv[2], "range") == 0) {
printExeRange(self, pCon, argc, argv);
return 1;
} else if (strcasecmp(argv[2], "text") == 0) {
printExeText(self, pCon, argc, argv);
return 1;
} else {
SCWrite(pCon, "ERROR: subcommand to info unknown", eError);
return 0;
}
}
}
/*=========================== print ==================================*/
static int printBuffer(pExeMan self, SConnection * pCon,
int argc, char *argv[])
{
pDynString filePath = NULL;
char pLine[512];
pExeBuf buf;
void *pPtr = NULL;
FILE *fd = NULL;
if (argc < 3) {
if (self->exeStackPtr >= 0) {
DynarGet(self->exeStack, self->exeStackPtr, &pPtr);
buf = (pExeBuf) pPtr;
if (buf != NULL) {
filePath = locateBatchBuffer(self, exeBufName(buf));
}
} else {
SCWrite(pCon, "ERROR: no default buffer to print, argument required",
eError);
return 0;
}
} else {
filePath = locateBatchBuffer(self, argv[2]);
}
if (filePath == NULL) {
snprintf(pLine, 255, "ERROR: batch buffer %s not found in path",
argv[2]);
SCWrite(pCon, pLine, eError);
return 0;
}
fd = fopen(GetCharArray(filePath), "r");
if (fd == NULL) {
SCWrite(pCon, "ERROR: failed to open file for printing", eError);
DeleteDynString(filePath);
return 0;
}
DeleteDynString(filePath);
filePath = CreateDynString(256,256);
if(filePath == NULL){
SCWrite(pCon,"ERROR: out of memory printing buffer",eError);
return 0;
}
while (fgets(pLine, 511, fd) != NULL) {
DynStringConcat(filePath, pLine);
if(strrchr(pLine,(int)'\n') == NULL){
DynStringConcatChar(filePath,'\n');
}
}
fclose(fd);
SCWrite(pCon, GetCharArray(filePath), eValue);
DeleteDynString(filePath);
return 1;
}
/*========================== run stack ===============================*/
static int enqueueBuffer(pExeMan self, SConnection * pCon,
int argc, char *argv[])
{
pExeBuf buf = NULL;
int status;
pDynString filePath = NULL;
if (SCGetRights(pCon) > usUser) {
SCWrite(pCon, "ERROR: no permission to enque buffers", eError);
return 0;
}
if (argc < 3) {
SCWrite(pCon, "ERROR: no buffer file given to enqueue ", eError);
return 0;
}
filePath = locateBatchBuffer(self, argv[2]);
if (filePath == NULL) {
SCWrite(pCon, "ERROR: failed to locate buffer to enqueue", eError);
return 0;
}
buf = exeBufCreate("enqueue");
if (buf == NULL) {
SCWrite(pCon, "ERROR: out of memory", eError);
return 0;
}
status = exeBufLoad(buf, GetCharArray(filePath));
DeleteDynString(filePath);
if (status != 1) {
SCWrite(pCon, "ERROR: failed to load buffer", eError);
return 0;
}
LLDnodeAppendFrom(self->runList, &buf);
return 1;
}
/*--------------------------------------------------------------------*/
static void clearQueue(pExeMan self)
{
pExeBuf buf = NULL;
int status;
status = LLDnodePtr2First(self->runList);
while (status != 0) {
LLDnodeDataTo(self->runList, &buf);
if (buf != NULL) {
exeBufDelete(buf);
}
LLDnodeDelete(self->runList);
status = LLDnodePtr2Next(self->runList);
}
/*
A second time round. This is a workaround for some
dodgy behaviour of the list system.
*/
status = LLDnodePtr2First(self->runList);
while (status != 0) {
LLDnodeDataTo(self->runList, &buf);
if (buf != NULL) {
exeBufDelete(buf);
}
LLDnodeDelete(self->runList);
status = LLDnodePtr2Next(self->runList);
}
}
/*--------------------------------------------------------------------*/
static int execQueue(pExeMan self, SConnection * pCon, SicsInterp * pSics)
{
pExeBuf buf = NULL;
int status;
if (self->exeStackPtr >= 0
|| (self->runCon != NULL && self->runCon != pCon)) {
SCWrite(pCon,
"ERROR: cannot start queue while batch buffers are still running",
eError);
return 0;
}
if (!SCMatchRights(pCon, usUser)) {
return 0;
}
self->runCon = pCon;
while (LLDnodePtr2First(self->runList) != 0) {
LLDnodeDataTo(self->runList, &buf);
LLDnodeDelete(self->runList);
self->exeStackPtr++;
if (buf == NULL) {
SCWrite(pCon,
"ERROR: serious trouble, buffer not in queue, inform programmer",
eError);
self->runCon = NULL;
return 0;
}
DynarPut(self->exeStack, self->exeStackPtr, buf);
status = exeBufProcess(buf, pSics, pCon, self->pCall, self->echo);
self->exeStackPtr--;
if (SCGetInterrupt(pCon) >= eAbortBatch) {
SCWrite(pCon, "ERROR: queue processing interrupted", eError);
self->runCon = NULL;
return 0;
}
}
self->runCon = 0;
return 1;
}
/*========================== interpreter action =======================*/
int ExeManagerWrapper(SConnection * pCon, SicsInterp * pSics, void *pData,
int argc, char *argv[])
{
pExeMan self = NULL;
char pBufferName[256];
int status;
pDynString dirList = NULL;
pDynString fullPath = NULL;
self = (pExeMan) pData;
assert(self != NULL);
if (argc > 1) {
strlcpy(pBufferName, argv[1], 255);
/*
argv must no be modifed, use strcasecmp instead M.Z.
strtolower(argv[1]);
*/
status = handleBatchPath(self, pCon, argc, argv);
if (status >= 0) {
return status;
}
if (strcasecmp(argv[1], "interest") == 0) {
registerCallbacks(pCon, pSics, self);
SCSendOK(pCon);
return 1;
} else if (strcasecmp(argv[1], "uninterest") == 0) {
unregisterCallbacks(pCon, self);
SCSendOK(pCon);
return 1;
} else if (strcasecmp(argv[1], "upload") == 0) {
status = startUpload(self, pCon);
if (status) {
SCSendOK(pCon);
}
return status;
} else if (strcasecmp(argv[1], "append") == 0) {
status = appendLine(self, pCon, argc, argv);
if (status) {
SCSendOK(pCon);
}
return status;
} else if (strcasecmp(argv[1], "save") == 0) {
status = uploadSave(self, pCon, argc, argv);
if (status) {
SCSendOK(pCon);
}
return status;
} else if (strcasecmp(argv[1], "forcesave") == 0) {
status = uploadForceSave(self, pCon, argc, argv);
if (status) {
SCSendOK(pCon);
}
return status;
} else if (strcasecmp(argv[1], "clearupload") == 0) {
status = clearUpload(self, pCon);
if (status) {
SCSendOK(pCon);
}
return status;
} else if (strcasecmp(argv[1], "info") == 0) {
status = infoHandler(self, pCon, argc, argv);
return status;
} else if (strcasecmp(argv[1], "print") == 0) {
status = printBuffer(self, pCon, argc, argv);
return status;
} else if (strcasecmp(argv[1], "enqueue") == 0) {
status = enqueueBuffer(self, pCon, argc, argv);
if (status) {
SCSendOK(pCon);
}
return status;
} else if (strcasecmp(argv[1], "dir") == 0) {
if (argc <= 2) {
dirList = findDirEntries(self, "*");
} else {
dirList = findDirEntries(self, argv[2]);
}
if (dirList != NULL) {
SCWrite(pCon, GetCharArray(dirList), eValue);
DeleteDynString(dirList);
} else {
SCWrite(pCon, "Nothing found", eValue);
}
return 1;
} else if (strcasecmp(argv[1], "fullpath") == 0) {
if (argc < 2) {
SCWrite(pCon, "ERROR: not enough arguments to exe fullpath",
eError);
return 0;
}
fullPath = locateBatchBuffer(self, argv[2]);
if (fullPath == NULL) {
SCWrite(pCon, "ERROR: buffer NOT found", eError);
return 0;
} else {
DynStringInsert(fullPath, "exe.fullpath=", 0);
SCWrite(pCon, GetCharArray(fullPath), eValue);
DeleteDynString(fullPath);
return 1;
}
return 1;
} else if (strcasecmp(argv[1], "makepath") == 0) {
return makeExePath(self, pCon, argc, argv);
} else if (strcasecmp(argv[1], "clear") == 0) {
clearQueue(self);
SCSendOK(pCon);
return 1;
} else if (strcasecmp(argv[1], "queue") == 0) {
printQueue(self, pCon);
SCSendOK(pCon);
return 1;
} else if (strcasecmp(argv[1], "run") == 0) {
status = execQueue(self, pCon, pSics);
if (status) {
SCSendOK(pCon);
}
return status;
} else if (strcasecmp(argv[1], "echo") == 0) {
if (argc > 2) {
self->echo = atoi(argv[2]) != 0;
SCSendOK(pCon);
} else {
SCPrintf(pCon, eValue, "exe echo = %d", self->echo);
}
return 1;
} else if (strcasecmp(argv[1], "runhdb") == 0) {
if (argc < 2) {
SCWrite(pCon, "ERROR: require path to root of queue node", eError);
SCSendOK(pCon);
}
status = runHdbBuffer(self, pCon, pSics, argv[2]);
if (self->exeStackPtr < 0) {
SCWrite(pCon, "EXE TERMINATED", eWarning);
}
return status;
} else {
status = runBatchBuffer(self, pCon, pSics, pBufferName);
if (self->exeStackPtr < 0) {
SCWrite(pCon, "EXE TERMINATED", eWarning);
}
return status;
}
} else {
SCWrite(pCon, "ERROR: need argument to manage batch buffers", eError);
return 0;
}
return 1;
}