/** * Implementation file for the exe buffer buffer manager. * * copyright: see file COPYRIGHT * * More information in exe.tex * * Mark Koennecke, November 2004 */ #include #include #include #include #include #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; }