/** * 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 "fortify.h" #include "sics.h" #include "exebuf.h" #include "exeman.h" #include "sdynar.h" #include "dynstring.h" #include "lld.h" #include "exeman.i" #include "splitter.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; } 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; } /*-------------------------------------------------------------------*/ 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->exeStackPtr--; 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){ pExeInfo self = (pExeInfo)pUser; char *name = (char *)pEvent; char pBueffel[132]; if(iEvent == BATCHSTART){ snprintf(pBueffel,131,"BATCHSTART=%s",name); SCWrite(self->pCon,pBueffel,eWarning); return 1; } if(iEvent == BATCHEND){ snprintf(pBueffel,131,"BATCHEND=%s",name); SCWrite(self->pCon,pBueffel,eWarning); 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(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,eWarning); 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); SCRegister(pCon,pSics, self->pCall,lID); lID = RegisterCallback(self->pCall, BATCHEND, BufferCallback, info, NULL); SCRegister(pCon,pSics, self->pCall,lID); lID = RegisterCallback(self->pCall, 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 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 uploadSave(pExeMan self, SConnection *pCon, int argc, char *argv[]){ int status; 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; } status = exeBufSave(self->uploadBuffer,argv[2]); if(status == 0){ SCWrite(pCon,"ERROR: failed to save exe buffer, destroyed...",eError); } exeBufDelete(self->uploadBuffer); self->uploadBuffer = NULL; return status; } /*=========================== 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; } } return 1; /* statement inserted, guessed return value M.Z. */ } 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; /* statement inserted, guessed return value M.Z. */ } } } /*=========================== 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; } while(fgets(pLine,511,fd) != NULL){ SCWrite(pCon,pLine,eValue); } fclose(fd); 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){ 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->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; self = (pExeMan)pData; assert(self != NULL); strncpy(pBufferName,argv[1],255); if(argc > 1){ 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],"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],"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 { 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; }