424 lines
9.7 KiB
C
424 lines
9.7 KiB
C
/**
|
|
* Implementation file for the exe buffer buffer handling system.
|
|
*
|
|
* copyright: see file COPYRIGHT
|
|
*
|
|
* More information in exe.tex
|
|
*
|
|
* Mark Koennecke, November 2004
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <tcl.h>
|
|
#include "lld_str.h"
|
|
#include "fortify.h"
|
|
#include "sics.h"
|
|
#include "exebuf.h"
|
|
#include "dynstring.h"
|
|
#include "exebuf.i"
|
|
#include "status.h"
|
|
|
|
char *ConID(SConnection *pCon); /* in conman.c */
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
pExeBuf exeBufCreate(char *name)
|
|
{
|
|
pExeBuf pNew = NULL;
|
|
|
|
pNew = (pExeBuf) malloc(sizeof(ExeBuf));
|
|
if (pNew == NULL) {
|
|
return NULL;
|
|
}
|
|
memset(pNew, 0, sizeof(ExeBuf));
|
|
pNew->name = strdup(name);
|
|
pNew->bufferContent = CreateDynString(1024, 1024);
|
|
if (!pNew->bufferContent) {
|
|
return NULL;
|
|
}
|
|
return pNew;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
void exeBufKill(void *data)
|
|
{
|
|
exeBufDelete((pExeBuf) data);
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
void exeBufDelete(pExeBuf self)
|
|
{
|
|
if (self == NULL) {
|
|
return;
|
|
}
|
|
if (self->name != NULL) {
|
|
free(self->name);
|
|
self->name = NULL;
|
|
}
|
|
if (self->bufferContent != NULL) {
|
|
DeleteDynString(self->bufferContent);
|
|
self->bufferContent = NULL;
|
|
}
|
|
free(self);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
int exeBufAppend(pExeBuf self, char *line)
|
|
{
|
|
int status;
|
|
assert(self);
|
|
|
|
status = DynStringConcat(self->bufferContent, line);
|
|
if (strrchr(line, (int) '\n') == NULL) {
|
|
DynStringConcatChar(self->bufferContent, '\n');
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
static char *locateName(char *filename)
|
|
{
|
|
char *pPtr;
|
|
int i;
|
|
|
|
pPtr = filename + strlen(filename) - 1;
|
|
for (i = strlen(filename) - 1; i > 0; i--, pPtr--) {
|
|
if (*pPtr == '/') {
|
|
pPtr++;
|
|
return pPtr;
|
|
}
|
|
}
|
|
return filename;
|
|
}
|
|
/*----------------------------------------------------------------------
|
|
If this is MOUNTAINBATCH file, replace ocurrences of @nl@ with \n
|
|
------------------------------------------------------------------------*/
|
|
static void fixMountainBatch(pExeBuf self)
|
|
{
|
|
char *pPtr, *pData, *pNL;
|
|
|
|
pPtr = GetCharArray(self->bufferContent);
|
|
if(strstr(pPtr, "#MOUNTAINBATCH") != pPtr){
|
|
/*
|
|
nothing to do
|
|
*/
|
|
return;
|
|
}
|
|
pData = strdup(pPtr);
|
|
DynStringClear(self->bufferContent);
|
|
pPtr = pData;
|
|
while((pNL = strstr(pPtr,"@nl@")) != NULL){
|
|
*pNL = '\n';
|
|
*(pNL+1) = '\0';
|
|
DynStringConcat(self->bufferContent, pPtr);
|
|
pPtr = pNL +4;
|
|
}
|
|
DynStringConcat(self->bufferContent,pPtr);
|
|
free(pData);
|
|
|
|
}
|
|
/*-----------------------------------------------------------------------*/
|
|
int exeBufLoad(pExeBuf self, char *filename)
|
|
{
|
|
char line[256], *pPtr;
|
|
FILE *fd = NULL;
|
|
int status, idx, gtsebatch = 0;
|
|
|
|
assert(self);
|
|
fd = fopen(filename, "r");
|
|
if (fd == NULL) {
|
|
return 0;
|
|
}
|
|
while (fgets(line, 255, fd) != NULL) {
|
|
/* Do not use exeBufAppend here. Lines longer than 255 would get
|
|
newline characters within the line */
|
|
status = DynStringConcat(self->bufferContent, line);
|
|
if (status != 1) {
|
|
fclose(fd);
|
|
return 0;
|
|
}
|
|
}
|
|
fclose(fd);
|
|
|
|
/**
|
|
* make sure that there is a \n at the end
|
|
*/
|
|
idx = GetDynStringLength(self->bufferContent);
|
|
pPtr = GetCharArray(self->bufferContent);
|
|
if(pPtr[idx-1] != '\n'){
|
|
DynStringConcat(self->bufferContent,"\n");
|
|
}
|
|
|
|
if (self->name != NULL) {
|
|
free(self->name);
|
|
}
|
|
self->name = strdup(locateName(filename));
|
|
fixMountainBatch(self);
|
|
return 1;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
int exeBufSave(pExeBuf self, char *filename)
|
|
{
|
|
FILE *fd = NULL;
|
|
|
|
fd = fopen(filename, "w");
|
|
if (fd == NULL) {
|
|
return 0;
|
|
}
|
|
fputs(GetCharArray(self->bufferContent), fd);
|
|
fclose(fd);
|
|
self->name = strdup(locateName(filename));
|
|
return 1;
|
|
}
|
|
|
|
/*================ process batch buffer ==============================*/
|
|
static pDynString findBlockEnd(pExeBuf self)
|
|
{
|
|
pDynString command = NULL;
|
|
char *buffer = NULL;
|
|
int i, j;
|
|
|
|
assert(self);
|
|
|
|
command = CreateDynString(80, 80);
|
|
if (command == NULL) {
|
|
return NULL;
|
|
}
|
|
buffer = GetCharArray(self->bufferContent);
|
|
if (self->end != -1) {
|
|
self->start = self->end + 1;
|
|
}
|
|
j = strlen(buffer);
|
|
for (i = self->start; i < j; i++) {
|
|
DynStringConcatChar(command, buffer[i]);
|
|
if (buffer[i] == '\n') {
|
|
self->lineno++;
|
|
if (Tcl_CommandComplete(GetCharArray(command))) {
|
|
self->end = i;
|
|
return command;
|
|
}
|
|
}
|
|
}
|
|
DeleteDynString(command);
|
|
return NULL;
|
|
}
|
|
/*-----------------attempt at a faster version -------------------------------
|
|
* But this only saves on the ConcatChar side of things......
|
|
*
|
|
* */
|
|
static pDynString findBlockEndExp(pExeBuf self)
|
|
{
|
|
pDynString command = NULL;
|
|
char *buffer = NULL;
|
|
char *cStart, *cEnd;
|
|
int i, len;
|
|
|
|
assert(self);
|
|
|
|
command = CreateDynString(80, 80);
|
|
if (command == NULL) {
|
|
return NULL;
|
|
}
|
|
buffer = GetCharArray(self->bufferContent);
|
|
if (self->end != -1) {
|
|
self->start = self->end + 1;
|
|
}
|
|
cStart = buffer +self->start;
|
|
cEnd = strchr(cStart,'\n');
|
|
while(cEnd != NULL){
|
|
len = cEnd - cStart+1;
|
|
DynStringConcatBytes(command,cStart, len);
|
|
self->lineno++;
|
|
if (Tcl_CommandComplete(GetCharArray(command))) {
|
|
self->end += len;
|
|
return command;
|
|
}
|
|
cStart = cEnd+1;
|
|
cEnd = strchr(cStart,'\n');
|
|
}
|
|
|
|
DeleteDynString(command);
|
|
return NULL;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
int exeBufProcess(pExeBuf self, SicsInterp * pSics,
|
|
SConnection * pCon, pICallBack pCall, int echo)
|
|
{
|
|
pDynString command = NULL;
|
|
Tcl_Interp *pTcl = NULL;
|
|
int status;
|
|
|
|
static int weWantLogging = 1;
|
|
char *cmd;
|
|
char cmdName[128];
|
|
char *ende;
|
|
int l;
|
|
|
|
assert(self);
|
|
assert(pSics);
|
|
|
|
self->start = 0;
|
|
self->end = -1;
|
|
self->lineno = 0;
|
|
pTcl = InterpGetTcl(pSics);
|
|
|
|
if (pCall != NULL) {
|
|
InvokeCallBack(pCall, BATCHSTART, self->name);
|
|
}
|
|
|
|
if (echo) {
|
|
SCsetMacro(pCon, 0);
|
|
}
|
|
while ((command = findBlockEnd(self)) != NULL) {
|
|
if (pCall != NULL) {
|
|
InvokeCallBack(pCall, BATCHAREA, NULL);
|
|
}
|
|
cmd = GetCharArray(command);
|
|
|
|
if (echo) {
|
|
/* find first word */
|
|
while (*cmd == ' ') {
|
|
cmd++;
|
|
}
|
|
ende = cmd;
|
|
while (*ende > ' ') {
|
|
ende++;
|
|
}
|
|
l = ende - cmd;
|
|
if (l < sizeof cmdName) {
|
|
strncpy(cmdName, cmd, l);
|
|
cmdName[l] = '\0';
|
|
if (FindCommand(pSics, cmdName) != NULL) {
|
|
/* print only SICS commands */
|
|
SCPrintf(pCon, eLog, "%s:%d>> %s", self->name, self->lineno,
|
|
cmd);
|
|
} else {
|
|
/* debugging */
|
|
/* SCPrintf(pCon, eValue, "%s:%d>> %s",self->name,self->lineno,cmd); */
|
|
}
|
|
}
|
|
}
|
|
|
|
Log(INFO,"com","%s:batch:%s", ConID(pCon), cmd);
|
|
status = Tcl_Eval(pTcl, cmd);
|
|
if (status != TCL_OK) {
|
|
if (SCGetSicsError(pCon) == 0) {
|
|
/*
|
|
Tcl Error
|
|
*/
|
|
if (strlen(pTcl->result) >= 2) {
|
|
SCPrintf(pCon, eError, "ERROR: Tcl reported: %s",
|
|
pTcl->result);
|
|
}
|
|
} else {
|
|
SCWrite(pCon, pTcl->result, eError);
|
|
SCSetSicsError(pCon,0);
|
|
}
|
|
SCWrite(pCon, "ERROR: above error was in block:", eError);
|
|
SCWrite(pCon, cmd, eError);
|
|
SCWrite(pCon, "ERROR: end of Tcl error block", eError);
|
|
}
|
|
DeleteDynString(command);
|
|
if (SCGetInterrupt(pCon) >= eAbortBatch) {
|
|
SCWrite(pCon, "ERROR: batch processing interrupted", eError);
|
|
if (pCall != NULL) {
|
|
InvokeCallBack(pCall, BATCHEND, self->name);
|
|
}
|
|
return 0;
|
|
} else {
|
|
SCSetInterrupt(pCon, eContinue);
|
|
}
|
|
}
|
|
if (pCall != NULL) {
|
|
InvokeCallBack(pCall, BATCHEND, self->name);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*---------------------------------------------------------------------*/
|
|
int exeBufProcessErrList(pExeBuf self, SicsInterp * pSics,
|
|
SConnection * pCon, int errList)
|
|
{
|
|
pDynString command = NULL;
|
|
Tcl_Interp *pTcl = NULL;
|
|
int status;
|
|
|
|
static int weWantLogging = 1;
|
|
char *cmd;
|
|
char cmdName[128];
|
|
char *error;
|
|
char msg[132];
|
|
char *ende;
|
|
int l;
|
|
|
|
assert(self);
|
|
assert(pSics);
|
|
|
|
self->start = 0;
|
|
self->end = -1;
|
|
self->lineno = 0;
|
|
pTcl = InterpGetTcl(pSics);
|
|
|
|
while ((command = findBlockEnd(self)) != NULL) {
|
|
cmd = GetCharArray(command);
|
|
|
|
status = Tcl_Eval(pTcl, cmd);
|
|
if (status != TCL_OK) {
|
|
LLDstringAppend(errList, cmd);
|
|
error = (char *) Tcl_GetStringResult(pTcl);
|
|
snprintf(msg, sizeof msg, "#ERR: %s\n", error);
|
|
LLDstringAppend(errList, msg);
|
|
}
|
|
DeleteDynString(command);
|
|
if (SCGetInterrupt(pCon) >= eAbortBatch) {
|
|
SCWrite(pCon, "ERROR: batch processing interrupted", eError);
|
|
return 0;
|
|
} else {
|
|
SCSetInterrupt(pCon, eContinue);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
void exeBufRange(pExeBuf self, int *start, int *end, int *lineno)
|
|
{
|
|
assert(self);
|
|
*start = self->start;
|
|
*end = self->end;
|
|
*lineno = self->lineno;
|
|
}
|
|
|
|
/*------------------------------------------------------------------------*/
|
|
pDynString exeBufText(pExeBuf self, int start, int end)
|
|
{
|
|
pDynString result = NULL;
|
|
char *pPtr;
|
|
int i;
|
|
|
|
assert(self);
|
|
|
|
result = CreateDynString(256, 132);
|
|
if (result == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
pPtr = GetCharArray(self->bufferContent);
|
|
if (end >= strlen(pPtr)) {
|
|
end = strlen(pPtr) - 1;
|
|
}
|
|
for (i = start; i < end; i++) {
|
|
DynStringConcatChar(result, pPtr[i]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------*/
|
|
char *exeBufName(pExeBuf self)
|
|
{
|
|
assert(self);
|
|
return self->name;
|
|
}
|