/** * 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 "commandlog.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] == '/'){ strncat(buffer,argv[2],511-strlen(buffer)); SCWrite(pCon,buffer,eValue); return 1; } pPtr = self->batchPath; pPtr = stptok(pPtr,pPath,131,":"); strncat(buffer,pPath,511-strlen(buffer)); strncat(buffer,"/",511-strlen(buffer)); strncat(buffer,argv[2],511-strlen(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); } /*--------------------------------------------------------------------*/ 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; } 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){ WriteToCommandLog("INTERNAL ERROR>>", "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; commandContext cc; writeFunc oldWrite; /* * 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); cc = SCGetContext(pCon); strncpy(cc.deviceID, name,255); strncpy(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); strncpy(bufferNode,name,511); oldWrite = SCGetWriteFunc(pCon); SCSetWriteFunc(pCon,SCHdbWrite); SCPushContext2(pCon,cc); status = exeBufProcess(buffer,pServ->pSics,pCon,NULL,0); SCSetWriteFunc(pCon,oldWrite); SCPopContext(pCon); 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; commandContext cc; writeFunc oldWrite; if(!SCMatchRights(pCon,usUser)) { 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 */ cc = SCGetContext(pCon); strcpy(cc.deviceID, pBueffel); /* * 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); strncpy(bufferNode,name,511); oldWrite = SCGetWriteFunc(pCon); SCSetWriteFunc(pCon,SCHdbWrite); SCPushContext2(pCon,cc); self->exeStackPtr++; DynarPut(self->exeStack,self->exeStackPtr,buffer); status = exeBufProcess(buffer,pSics,pCon,self->pCall,self->echo); self->exeStackPtr--; SCSetWriteFunc(pCon,oldWrite); SCPopContext(pCon); 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(strcmp(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]); SCSendOK(pCon); SCparChange(pCon); return 1; } else { snprintf(pBuffer,1023,"%s.batchpath = %s", argv[0],self->batchPath); SCWrite(pCon,pBuffer,eValue); return 1; } } if(strcmp(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 != 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; } pNew->pCon = pCon; pNew->exe = self; return pNew; } /*------------------------------------------------------------------*/ static int BufferCallback(int iEvent, void *pEvent, void *pUser, commandContext cc){ pExeInfo self = (pExeInfo)pUser; char *name = (char *)pEvent; char pBueffel[132]; if(iEvent == BATCHSTART){ snprintf(pBueffel,131,"BATCHSTART=%s",name); SCWriteInContext(self->pCon,pBueffel,eWarning,cc); return 1; } if(iEvent == BATCHEND){ snprintf(pBueffel,131,"BATCHEND=%s",name); SCWriteInContext(self->pCon,pBueffel,eWarning,cc); return 1; } return 0; } /*-------------------------------------------------------------------*/ static int LineCallBack(int iEvent, void *pEvent, void *pUser, commandContext cc){ pExeInfo self = (pExeInfo)pUser; char pBueffel[256]; int start, end, lineno; void *pPtr = NULL; pExeBuf buf = NULL; assert(self); 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); SCWriteInContext(self->pCon,pBueffel,eWarning,cc); 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, SCGetContext(pCon),BATCHSTART, BufferCallback, info, killExeInfo); SCRegister(pCon,pSics, self->pCall,lID); lID = RegisterCallback(self->pCall, SCGetContext(pCon),BATCHEND, BufferCallback, info, NULL); SCRegister(pCon,pSics, self->pCall,lID); lID = RegisterCallback(self->pCall, SCGetContext(pCon),BATCHAREA, LineCallBack, info, NULL); SCRegister(pCon,pSics, self->pCall,lID); } /*--------------------------------------------------------------------*/ 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); SCUnregisterID(pCon,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; } 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){ strcat(pPath,"/"); strcat(pPath,argv[2]); } else { strncpy(pPath,argv[2],255); } } else { strncpy(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 { strncpy(pPath,argv[2],255); } } else { strncpy(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 *stringToCheck++; *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) *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 { strtolower(argv[2]); if(strcmp(argv[2],"stack") == 0){ printExeStack(self,pCon); return 1; } else if(strcmp(argv[2],"range") == 0){ printExeRange(self,pCon,argc,argv); return 1; } else if(strcmp(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); SCStartBuffering(pCon); while(fgets(pLine,511,fd) != NULL){ SCWrite(pCon,pLine,eValue); } fclose(fd); filePath = SCEndBuffering(pCon); SCWrite(pCon,GetCharArray(filePath),eValue); 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){ SCWrite(pCon, "ERROR: cannot start queue while batch buffers are still running",eError); return 0; } if(!SCMatchRights(pCon,usUser)){ return 0; } 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); 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); return 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){ strncpy(pBufferName,argv[1],255); strtolower(argv[1]); status = handleBatchPath(self,pCon,argc,argv); if(status >= 0){ return status; } if(strcmp(argv[1],"interest") == 0){ registerCallbacks(pCon,pSics,self); SCSendOK(pCon); return 1; } else if(strcmp(argv[1],"uninterest") == 0){ unregisterCallbacks(pCon,self); SCSendOK(pCon); return 1; }else if(strcmp(argv[1],"upload") == 0){ status = startUpload(self,pCon); if(status){ SCSendOK(pCon); } return status; }else if(strcmp(argv[1],"append") == 0){ status = appendLine(self,pCon,argc,argv); if(status){ SCSendOK(pCon); } return status; }else if(strcmp(argv[1],"save") == 0){ status = uploadSave(self,pCon,argc,argv); if(status){ SCSendOK(pCon); } return status; }else if(strcmp(argv[1],"forcesave") == 0){ status = uploadForceSave(self,pCon,argc,argv); if(status){ SCSendOK(pCon); } return status; }else if(strcmp(argv[1],"clearupload") == 0){ status = clearUpload(self,pCon); if(status){ SCSendOK(pCon); } return status; }else if(strcmp(argv[1],"info") == 0){ status = infoHandler(self,pCon,argc,argv); return status; }else if(strcmp(argv[1],"print") == 0){ status = printBuffer(self,pCon,argc,argv); return status; }else if(strcmp(argv[1],"enqueue") == 0){ status = enqueueBuffer(self,pCon,argc,argv); if(status){ SCSendOK(pCon); } return status; } else if(strcmp(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(strcmp(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(strcmp(argv[1],"makepath") == 0){ return makeExePath(self,pCon,argc,argv); }else if(strcmp(argv[1],"clear") == 0){ clearQueue(self); SCSendOK(pCon); return 1; }else if(strcmp(argv[1],"queue") == 0){ printQueue(self,pCon); SCSendOK(pCon); return 1; }else if(strcmp(argv[1],"run") == 0){ status = execQueue(self,pCon,pSics); if(status){ SCSendOK(pCon); } return status; }else if(strcmp(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(strcmp(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; }