/* nl-liststr.c --- newLISP primitives handling lists and strings
Copyright (C) 2007 Lutz Mueller
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "newlisp.h"
#include "pcre.h"
#include "protos.h"
extern CELL * firstFreeCell;
extern CELL * lastCellCopied;
extern SYMBOL * sysSymbol[];
size_t adjustNegativeIndex(ssize_t index, size_t length)
{
if(index < 0) index = length + index;
else if((index+1) > length) index = length -1;
return(index < 0 ? 0 : index);
}
size_t adjustCount(ssize_t count, ssize_t length)
{
if(length <= 1 || count == 0 || length == count)
return(0);
if(count > 0)
count = count % length;
else
{
count = -count % length;
count = length - count;
}
return(count);
}
#ifdef LINUX
extern char * strcasestr(char * haystack, char * needle);
#endif
CELL * p_member(CELL * params)
{
CELL * key;
CELL * list;
CELL * member;
long options = -1;
char * ptr;
ssize_t pos;
key = evaluateExpression(params);
params = params->next;
list = evaluateExpression(params);
if(params->next != nilCell)
getInteger(params->next, (UINT *)&options);
if(isList(list->type))
list = (CELL *)list->contents;
else if (list->type == CELL_STRING)
{
if(key->type != CELL_STRING)
return(errorProcExt(ERR_STRING_EXPECTED, params));
if(options == -1)
{
ptr = strstr((char *)list->contents, (char *) key->contents);
if(ptr) return(stuffString(ptr));
}
else
{
pos = searchBufferRegex((char*)list->contents, 0, (char *)key->contents, list->aux - 1, options, 0);
if(pos != -1) return(stuffString((char *)list->contents + pos));
}
return(nilCell);
}
else
return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, params->next));
while(list != nilCell)
{
if(compareCells(key, list) == 0) break;
list = list->next;
}
if(list == nilCell) return(nilCell);
member = getCell(CELL_EXPRESSION);
member->contents = (UINT)copyList(list);
return(member);
}
CELL * p_length(CELL * params)
{
size_t length;
SYMBOL * symbol;
params = evaluateExpression(params);
length = 0;
switch(params->type)
{
case CELL_LONG:
length = sizeof(UINT); break;
#ifndef NEWLISP64
case CELL_INT64:
length = sizeof(INT64); break;
#endif
case CELL_FLOAT:
length = sizeof(double); break;
case CELL_STRING:
length = params->aux - 1; break;
case CELL_CONTEXT:
case CELL_SYMBOL:
symbol = (SYMBOL *)params->contents;
length = strlen(symbol->name);
break;
case CELL_DYN_SYMBOL:
length = strlen((char *)params->contents);
break;
case CELL_EXPRESSION:
case CELL_LAMBDA:
case CELL_MACRO:
length = listlen((CELL *)params->contents);
break;
case CELL_ARRAY:
length = (params->aux - 1) / sizeof(UINT);
default:
break;
}
return(stuffInteger(length));
}
CELL * p_append(CELL * params)
{
CELL * list = NULL;
CELL * firstCell = NULL;
CELL * copy = NULL;
CELL * cell;
while(params != nilCell)
{
cell = evaluateExpression(params);
if(!isList(cell->type))
{
if(copy == NULL)
{
if(cell->type == CELL_STRING)
return(appendString(cell, params->next, NULL, 0, FALSE, TRUE));
else if(cell->type == CELL_ARRAY)
return(appendArray(cell, params->next));
return(errorProcExt(ERR_ARRAY_LIST_OR_STRING_EXPECTED, params));
}
return(errorProcExt(ERR_LIST_EXPECTED, params));
}
if(list == NULL)
list = getCell(cell->type);
copy = copyList((CELL *)cell->contents);
params = params->next;
if(copy == nilCell) continue;
if(firstCell == NULL) list->contents = (UINT)copy;
else firstCell->next = copy;
firstCell = lastCellCopied;
}
if(list == NULL)
return(getCell(CELL_EXPRESSION));
return(list);
}
CELL * appendString(CELL * cell, CELL * list, char * joint, size_t jointLen, int trailJoint, int evalFlag)
{
CELL * result;
STREAM stream;
char * sPtr;
size_t len;
openStrStream(&stream, MAX_LINE, 0);
writeStreamStr(&stream, (char *)cell->contents, cell->aux - 1);
while(list != nilCell)
{
if(joint == NULL)
{
list = getStringSize(list, &sPtr, &len, evalFlag);
writeStreamStr(&stream, sPtr, len);
}
else
{
list = getStringSize(list, &sPtr, &len, FALSE);
if(jointLen) writeStreamStr(&stream, joint, jointLen);
writeStreamStr(&stream, sPtr, len);
}
}
if(trailJoint)
writeStreamStr(&stream, joint, jointLen);
result = getCell(CELL_STRING);
result->contents = (UINT)allocMemory(stream.position + 1);
*((char *)result->contents + stream.position) = 0;
result->aux = stream.position + 1;
memcpy((void *)result->contents, stream.buffer, stream.position);
closeStrStream(&stream);
return(result);
}
CELL * p_chop(CELL * params)
{
size_t number = 1;
size_t length = 0;
CELL * next;
#ifdef SUPPORT_UTF8
char * ptr;
#endif
next = params->next;
params = evaluateExpression(params);
if(next != nilCell)
getInteger(next, (UINT *)&number);
if(params->type == CELL_STRING)
{
#ifndef SUPPORT_UTF8
length = params->aux - 1;
if(number > length) number = length;
length = length - number;
return stuffStringN((char *)params->contents, length);
#else
length = utf8_wlen((char *)params->contents);
if(number > length) number = length;
length = length - number;
ptr = (char *)params->contents;
while(length--)
ptr += utf8_1st_len(ptr);
return stuffStringN((char *)params->contents, ptr - (char *)params->contents);
#endif
}
if(!isList(params->type))
return(errorProc(ERR_LIST_OR_STRING_EXPECTED));
length = listlen((CELL *)params->contents);
if(number > length) number = length;
return(sublist((CELL *)params->contents, 0, length - number));
}
CELL * setNthStr(CELL * cellStr, CELL * new, ssize_t index, int typeFlag);
CELL * setNth(CELL * params, int typeFlag);
CELL * p_nth(CELL * params) {return setNth(params, 0);}
CELL * p_nthSet(CELL * params) {return setNth(params, 1);}
CELL * p_setNth(CELL * params) {return setNth(params, 2);}
CELL * setNth(CELL * params, int typeFlag)
{
ssize_t index;
CELL * list;
CELL * next;
CELL * cell = NULL;
SYMBOL * sPtr = NULL;
/* new syntax, distinguished by type of first arg and number of args */
next = params->next;
if( (params->type == CELL_EXPRESSION) &&
( (!typeFlag && next == nilCell) || (typeFlag && next->next == nilCell) ))
{
list = (CELL *)params->contents;
params = list->next;
if(isSymbol(list->type))
{
if(list->type == CELL_SYMBOL)
sPtr = (SYMBOL *)list->contents;
else
sPtr = getDynamicSymbol(list);
list = (CELL *)sPtr->contents;
if(list->type == CELL_CONTEXT)
{
sPtr = (translateCreateSymbol(
((SYMBOL*)list->contents)->name,
CELL_NIL,
(SYMBOL*)list->contents,
TRUE));
list = (CELL *)sPtr->contents;
}
if(isProtected(sPtr->flags) && typeFlag)
return(errorProcExt2(ERR_SYMBOL_PROTECTED, stuffSymbol(sPtr)));
}
else
{
if(typeFlag)
list = evalCheckProtected(list, NULL);
else
list = evaluateExpression(list);
}
NTH_EVAL_IMPLICIT:
if(isList(list->type))
{
if(!typeFlag)
return(copyCell(implicitIndexList(list, params)));
else if(typeFlag == 1)
return(updateCell(implicitIndexList(list, params), next));
else
{
deleteList(updateCell(implicitIndexList(list, params), next));
return(copyCell(list));
}
}
else if(list->type == CELL_ARRAY)
{
if(!typeFlag)
return(copyCell(implicitIndexArray(list, params)));
else if(typeFlag == 1)
return(updateCell(implicitIndexArray(list, params), next));
else
{
deleteList(updateCell(implicitIndexArray(list, params), next));
return(copyCell(list));
}
}
else if(list->type == CELL_STRING)
{
getInteger(params, (UINT *)&index);
return(setNthStr(list, next, index, typeFlag));
}
return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, list));
}
list = evaluateExpression(params);
if(!isNumber(list->type))
return(errorProcExt(ERR_NUMBER_EXPECTED, params));
while(isNumber(list->type))
{
if(cell == NULL)
{
cell = getCell(CELL_EXPRESSION);
cell->contents = (UINT)copyCell(list);
next = (CELL *)cell->contents;
}
else
{
next->next = copyCell(list);
next = next->next;
}
params = params->next;
if(typeFlag)
list = evalCheckProtected(params, NULL);
else
list = evaluateExpression(params);
}
next = params->next;
if(list->type == CELL_STRING)
{
getInteger((CELL *)cell->contents, (UINT *)&index);
deleteList(cell);
return(setNthStr(list, next, index, typeFlag));
}
params = getCell(CELL_QUOTE);
params->contents = (UINT)cell;
pushResult(params);
goto NTH_EVAL_IMPLICIT;
}
CELL * updateCell(CELL * cell, CELL * val)
{
CELL * prev;
CELL * new;
if(cell == nilCell) return(nilCell);
deleteList((CELL*)sysSymbol[0]->contents);
sysSymbol[0]->contents = (UINT)copyCell(cell);
new = copyCell(evaluateExpression(val));
/* save previous content */
prev = getCell(cell->type);
prev->aux = cell->aux;
prev->contents = cell->contents;
cell->type = new->type;
cell->aux = new->aux;
cell->contents = new->contents;
/* free the cell */
new->type = CELL_FREE;
new->aux = 0;
new->contents = 0;
new->next = firstFreeCell;
firstFreeCell = new;
--cellCount;
return(prev);
}
#define INSERT_BEFORE 0
#define INSERT_AFTER 1
#define INSERT_END 2
CELL * p_push(CELL * params)
{
CELL * newCell;
CELL * list;
CELL * cell = NULL;
SYMBOL * sPtr;
int insert = 0, evalFlag = 0;
ssize_t index;
newCell = evaluateExpression(params);
params = params->next;
if(isSymbol(params->type))
{
if(params->type == CELL_SYMBOL)
sPtr = (SYMBOL *)params->contents;
else
sPtr = getDynamicSymbol(params);
if(isProtected(sPtr->flags))
return(errorProcExt(ERR_SYMBOL_PROTECTED, params));
if(!isList(((CELL*)sPtr->contents)->type))
{
if(isNil((CELL *)sPtr->contents))
{
deleteList((CELL*)sPtr->contents);
list = getCell(CELL_EXPRESSION);
sPtr->contents = (UINT)list; }
}
list = (CELL*)sPtr->contents;
}
else
list = evalCheckProtected(params, NULL);
if(!isList(list->type))
{
if(list->type == CELL_STRING)
return(pushOnString(newCell, list, params->next));
else
return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, params));
}
if(params->next == nilCell)
{
params = params->next;
index = 0;
}
else
{
cell = ((CELL*)params->next)->next;
params = evaluateExpression(params->next);
if(isList(params->type))
{
evalFlag = FALSE;
params = getIntegerExt((CELL*)params->contents, (UINT*)&index, FALSE);
}
else
{
evalFlag = TRUE;
getIntegerExt(params, (UINT*)&index, FALSE);
params = cell;
}
}
if(index == -1)
{
if(params == nilCell)
{
newCell = copyCell(newCell);
cell = (CELL*)list->aux;
list->aux = (UINT)newCell;
if(cell != nilCell && cell != trueCell)
{
cell->next = newCell;
return(copyCell(newCell));
}
if(list->contents == (UINT)nilCell)
{
list->contents = (UINT)newCell;
return(copyCell(newCell));
}
list = (CELL *)list->contents;
while(list->next != nilCell)
list = list->next;
list->next = newCell;
return(copyCell(newCell));
}
index = MAX_LONG;
}
list->aux = (UINT)nilCell; /* undo push optimization */
while(isList(list->type))
{
cell = list;
list = (CELL *)list->contents;
if(index < 0)
{
index = listlen(list) + index;
if(index < 0)
{
index = 0;
insert = INSERT_BEFORE;
}
else insert = INSERT_AFTER;
}
else insert = INSERT_BEFORE;
while(index--)
{
if(list->next == nilCell)
{
insert = INSERT_END;
break;
}
cell = list;
list = list->next;
}
if(params == nilCell || !isList(list->type)) break;
params = getIntegerExt(params, (UINT*)&index, evalFlag);
}
newCell = copyCell(newCell);
if(insert == INSERT_BEFORE || list == nilCell)
{
if(list == (CELL*)cell->contents)
{
cell->contents = (UINT)newCell;
newCell->next = list;
}
else
{
cell->next = newCell;
newCell->next = list;
}
}
else if(insert == INSERT_AFTER || insert == INSERT_END)
{
cell = list->next;
list->next = newCell;
newCell->next = cell;
}
return(copyCell(newCell));
}
CELL * p_pop(CELL * params)
{
CELL * list;
CELL * cell = NULL;
ssize_t index;
int evalFlag = FALSE;
list = evalCheckProtected(params, NULL);
if(!isList(list->type))
{
if(list->type == CELL_STRING)
return(popString(list, params->next));
else
return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, params));
}
/* leave push optimization if popping first for queues */
if(params->next == nilCell)
{
cell = (CELL *)list->contents;
list->contents = (UINT)cell->next;
if(cell->next == nilCell) /* check if only one element in list */
list->aux = (UINT)nilCell; /* undo push optimization */
cell->next = nilCell;
return(cell);
}
else
{
list->aux = (UINT)nilCell; /* undo push optimization */
cell = ((CELL*)params->next)->next;
params = evaluateExpression(params->next);
if(isList(params->type))
{
evalFlag = FALSE;
params = getIntegerExt((CELL*)params->contents, (UINT*)&index, FALSE);
}
else
{
evalFlag = TRUE;
getIntegerExt(params, (UINT*)&index, FALSE);
params = cell;
}
}
while(isList(list->type))
{
cell = list;
list = (CELL *)list->contents;
if(index < 0) index = convertNegativeOffset(index, list);
while(index--)
{
if(list->next == nilCell) break;
cell = list;
list = list->next;
}
if(params == nilCell || !isList(list->type)) break;
params = getIntegerExt(params, (UINT*)&index, evalFlag);
}
if(list == (CELL*)cell->contents)
cell->contents = (UINT)list->next;
else
cell->next = list->next;
list->next = nilCell;
return(list);
}
CELL * setNthStr(CELL * cellStr, CELL * new, ssize_t index, int typeFlag)
{
char * newStr;
char * oldStr;
size_t newLen, oldLen, len;
char * str;
oldStr = (char*)cellStr->contents;
oldLen = cellStr->aux - 1;
if(oldLen == 0) return(copyCell(cellStr));
#ifndef SUPPORT_UTF8
index = adjustNegativeIndex(index, oldLen);
if(!typeFlag)
return(stuffStringN(oldStr + index, 1));
deleteList((CELL*)sysSymbol[0]->contents);
sysSymbol[0]->contents = (UINT)stuffStringN(oldStr + index, 1);
len = 1;
#else
index = adjustNegativeIndex(index, utf8_wlen((char *)cellStr->contents));
str = oldStr;
while(index--)
{
len = utf8_1st_len(str);
str += len;
}
len = utf8_1st_len(str);
if(!typeFlag)
return(stuffStringN(str, len));
deleteList((CELL*)sysSymbol[0]->contents);
sysSymbol[0]->contents = (UINT)stuffStringN(str, len);
index = str - oldStr;
#endif
getStringSize(new, &newStr, &newLen, TRUE);
/* get back oldStr in case it changed during eval of replacement */
oldStr = (char *)cellStr->contents;
oldLen = cellStr->aux - 1;
if(oldLen == 0) return(copyCell(cellStr));
index = adjustNegativeIndex(index, oldLen);
str = allocMemory(oldLen + newLen - len + 1);
*(str + oldLen + newLen - len) = 0;
memcpy(str, oldStr, index);
memcpy(str + index, newStr, newLen);
memcpy(str + index + newLen, oldStr + index + len, oldLen - index - len);
cellStr->contents = (UINT)str;
cellStr->aux = oldLen + newLen - len + 1;
if(typeFlag != 2)
{
new = stuffStringN(oldStr + index, len);
freeMemory(oldStr);
return(new);
}
freeMemory(oldStr);
return(copyCell(cellStr));
}
CELL * popString(CELL * str, CELL * params)
{
char * ptr;
char * newPtr;
ssize_t index = 0;
ssize_t len = 1;
CELL * result;
if(str->aux < 2)
return(stuffString(""));
if(params != nilCell)
{
params = getInteger(params, (UINT*)&index);
if(params != nilCell)
{
getInteger(params, (UINT*)&len);
if(len < 1) len = 0;
}
}
ptr = (char *)str->contents;
#ifndef SUPPORT_UTF8
index = adjustNegativeIndex(index, str->aux - 1);
#else
index = adjustNegativeIndex(index, utf8_wlen(ptr));
#endif
if((index + len) > (str->aux - 2))
len = str->aux - 1 - index;
newPtr = callocMemory(str->aux - len);
memcpy(newPtr, ptr, index);
memcpy(newPtr + index, ptr + index + len, str->aux - len - index);
str->aux = str->aux - len;
str->contents = (UINT)newPtr;
result = stuffStringN(ptr + index, len);
free(ptr);
return(result);
}
CELL * pushOnString(CELL * newStr, CELL * str, CELL * idx)
{
ssize_t index = 0;
char * ptr;
char * newPtr;
int minusFlag;
int len;
#ifdef SUPPORT_UTF8
char * sptr;
int wChar;
#endif
if(idx != nilCell) getInteger(idx, (UINT*)&index);
ptr = (char *)str->contents;
if(newStr->type != CELL_STRING)
return(errorProcExt(ERR_STRING_EXPECTED, newStr));
if(index == -1)
{
appendCellString(str, (char *)newStr->contents, newStr->aux - 1);
return(copyCell(newStr));
}
minusFlag = (index < 0);
#ifndef SUPPORT_UTF8
len = str->aux - 1;
#else
len = utf8_wlen(ptr);
#endif
/* convert index into characters to skip before the new one is inserted */
if(index < 0) index = len + index + 1;
else if(index > len) index = len;
if(index < 0) index = 0;
newPtr = callocMemory(str->aux + newStr->aux - 1);
#ifndef SUPPORT_UTF8
memcpy(newPtr, ptr, index);
memcpy(newPtr + index, (char*)newStr->contents, newStr->aux - 1);
memcpy(newPtr + index + newStr->aux - 1, ptr + index, str->aux - index);
#else
sptr = ptr;
while(index--) /* skip characters to split point) */
sptr = utf8_wchar(sptr, &wChar);
memcpy(newPtr, ptr, sptr - ptr);
memcpy(newPtr + (sptr - ptr), (char*)newStr->contents, newStr->aux - 1);
memcpy(newPtr + (sptr - ptr) + newStr->aux - 1, sptr, str->aux - (sptr - ptr) );
#endif
str->contents = (UINT)newPtr;
str->aux = str->aux + newStr->aux - 1;
*(newPtr + str->aux - 1) = 0;
free(ptr);
return(copyCell(newStr));
}
CELL * p_select(CELL * params)
{
size_t n = 0, idx = 0;
ssize_t index;
CELL * list, * cell;
CELL * result = NULL;
CELL * head;
int evalFlag = TRUE;
char * str, * newStr;
#ifdef SUPPORT_UTF8
int * wstr;
int * wnewStr;
size_t len;
#endif
head = evaluateExpression(params);
params = params->next;
cell = evaluateExpression(params);
if(isList(cell->type))
{
evalFlag = FALSE;
cell = params = (CELL *)cell->contents;
}
if(head->type == CELL_STRING)
{
if((n = listlen(params)) == 0) return(stuffString(""));
str = (char *)head->contents;
#ifndef SUPPORT_UTF8
newStr = (char *)allocMemory(n + 1);
idx = 0;
while(params->type != CELL_NIL)
{
if(idx == 0)
{
getIntegerExt(cell, (UINT *)&index, FALSE);
params = params->next;
}
else
params = getIntegerExt(params, (UINT *)&index, evalFlag);
index = adjustNegativeIndex(index, head->aux -1);
*(newStr + idx++) = *(str + index);
}
*(newStr + n) = 0;
#else
wstr = allocMemory(head->aux * sizeof(int));
len = utf8_wstr(wstr, str, head->aux - 1);
wnewStr = allocMemory((n + 1) * sizeof(int));
idx = 0;
while(params->type != CELL_NIL)
{
if(idx == 0)
{
getIntegerExt(cell, (UINT *)&index, FALSE);
params = params->next;
}
else
params = getIntegerExt(params, (UINT *)&index, evalFlag);
index = adjustNegativeIndex(index, len);
*(wnewStr + idx++) = *(wstr + index);
}
*(wnewStr + n) = 0;
newStr = allocMemory(UTF8_MAX_BYTES * n + 1);
n = wstr_utf8(newStr, wnewStr, UTF8_MAX_BYTES * n);
newStr = reallocMemory(newStr, n + 1);
#endif
result = getCell(CELL_STRING);
result->aux = n + 1;
result->contents = (UINT)newStr;
return(result);
}
if(!isList(head->type))
return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, head));
head = (CELL *)head->contents;
list = head;
n = 0;
while(params->type != CELL_NIL)
{
if(n++ == 0)
{
getIntegerExt(cell, (UINT *)&index, FALSE);
params = params->next;
}
else
params = getIntegerExt(params, (UINT *)&index, evalFlag);
if(index < 0) index = convertNegativeOffset(index, head);
if(index < idx) list = head, idx = 0;
while(idx < index && list->next != nilCell) list = list->next, idx++;
if(result == NULL)
{
result = getCell(CELL_EXPRESSION);
cell = copyCell(list);
result->contents = (UINT)cell;
}
else
{
cell->next = copyCell(list);
cell = cell->next;
}
}
return((result == NULL) ? getCell(CELL_EXPRESSION) : result);
}
CELL * p_slice(CELL * params)
{
CELL * cell;
ssize_t offset;
ssize_t length;
cell = evaluateExpression(params);
params = getInteger(params->next, (UINT *)&offset);
if(params != nilCell)
getInteger(params, (UINT *)&length);
else
length = MAX_LONG;
if(isList(cell->type))
return(sublist((CELL *)cell->contents, offset, length));
else if(cell->type == CELL_STRING)
return(substring((char *)cell->contents, cell->aux - 1, offset, length));
else if(cell->type == CELL_ARRAY)
return(subarray(cell, offset, length));
return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, params));
}
CELL * sublist(CELL * list, ssize_t offset, ssize_t length)
{
CELL * subList;
CELL * cell;
if(offset < 0)
offset = convertNegativeOffset(offset, list);
if(length < 0)
{
length = listlen(list) - offset + length;
if(length < 0) length = 0;
}
subList = getCell(CELL_EXPRESSION);
if(length == 0) return(subList);
while(offset-- && list != nilCell)
list = list->next;
if(list == nilCell) return(subList);
cell = copyCell(list);
subList->contents = (UINT)cell;
--length;
while(length--)
{
list = list->next;
if(list == nilCell) break;
cell->next = copyCell(list);
cell = cell->next;
}
return(subList);
}
CELL * p_reverse(CELL * params)
{
CELL * cell;
CELL * previous;
CELL * next;
char * str;
size_t len, tmp;
char * left;
char * right;
cell = params;
params = evalCheckProtected(params, NULL);
if(isList(params->type))
{
params->aux = (UINT)nilCell; /* undo push optimization */
previous = cell = (CELL*)params->contents;
next = cell->next;
cell->next = nilCell;
while(cell!= nilCell)
{
previous = cell;
cell = next;
next = cell->next;
if(cell != nilCell) cell->next = previous;
}
params->contents = (UINT)previous;
}
else if(params->type == CELL_STRING)
{
str = (char *)params->contents;
len = params->aux - 1;
left = str;
right = left + len - 1;
while(left < right)
{
tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
else return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, cell));
return(copyCell(params));
}
CELL * p_join(CELL * params)
{
char * joint = NULL;
CELL * list;
size_t jointLen = 0;
int trailJoint = 0;
params = getListHead(params, &list);
if(list == nilCell)
return(stuffString(""));
if(list->type != CELL_STRING)
return(errorProcExt(ERR_STRING_EXPECTED, list));
if(params != nilCell)
{
params = getStringSize(params, &joint, &jointLen, TRUE);
trailJoint = getFlag(params);
}
return(appendString(list, list->next, joint, jointLen, trailJoint, FALSE));
}
CELL * p_find(CELL * params)
{
char * key;
char * second;
ssize_t found;
CELL * next;
CELL * keyCell;
CELL * funcCell;
size_t size;
long options;
keyCell = evaluateExpression(params);
params = params->next;
next = evaluateExpression(params);
if(keyCell->type == CELL_STRING && next->type == CELL_STRING)
{
key = (char *)keyCell->contents;
second = (char *)next->contents;
size = next->aux - 1;
if(params->next != nilCell)
{
params = getInteger(params->next, (UINT*)&options);
found = searchBufferRegex(second, 0, key, (int)size, options, NULL);
if(found == -1) return(nilCell);
}
else
{
found = searchBuffer(second, size, key, keyCell->aux - 1, TRUE);
if(found == -1) return(nilCell);
}
}
else
{
/* list mode with optional functor */
if(!isList(next->type)) return(nilCell);
next = (CELL *)next->contents;
found = 0;
if(params->next != nilCell)
funcCell = evaluateExpression(params->next);
else funcCell = NULL;
/* do regex when first arg is string and option# is present */
if(funcCell && isNumber(funcCell->type) && keyCell->type == CELL_STRING)
{
getIntegerExt(funcCell, (UINT*)&options, FALSE);
key = (char *)keyCell->contents;
while(next != nilCell)
{
if(next->type == CELL_STRING)
{
second = (char *)next->contents;
if(searchBufferRegex(second, 0, key, next->aux - 1 , options, NULL) != -1)
break;
}
found++;
next = next->next;
}
if(next == nilCell) return(nilCell);
else return(stuffInteger(found));
}
while(next != nilCell)
{
if(compareFunc(keyCell, next, funcCell) == 0) break;
found++;
next = next->next;
}
if(next == nilCell) return(nilCell);
}
return(stuffInteger(found));
}
void swap(UINT * left, UINT * right)
{
UINT tmp;
tmp = *left;
*left = *right;
*right = tmp;
}
SYMBOL * getSymbolCheckProtected(CELL * params)
{
SYMBOL * sPtr = NULL;
if(params->type == CELL_DYN_SYMBOL)
sPtr = getDynamicSymbol(params);
else if(params->type == CELL_SYMBOL)
sPtr = (SYMBOL *)params->contents;
else fatalError(ERR_SYMBOL_EXPECTED, params, FALSE);
if(isProtected(sPtr->flags))
fatalError(ERR_SYMBOL_PROTECTED, params, FALSE);
return sPtr;
}
CELL * p_swap(CELL * params)
{
size_t first, second, num;
char * str;
CELL * envelope;
CELL * list;
CELL * firstCell;
CELL * secondCell;
SYMBOL * lsym;
SYMBOL * rsym;
if(((CELL *)params->next)->next == nilCell)
{
lsym = getSymbolCheckProtected(params);
rsym = getSymbolCheckProtected(params->next);
swap(&lsym->contents, &rsym->contents);
return(copyCell((CELL*)rsym->contents));
}
params = getInteger(params, (UINT*)&first);
params = getInteger(params, (UINT*)&second);
envelope = evalCheckProtected(params, NULL);
if(envelope->type == CELL_STRING)
{
first = adjustNegativeIndex(first, envelope->aux - 1);
second = adjustNegativeIndex(second, envelope->aux - 1);
str = (char *)envelope->contents;
num = str[first];
str[first] = str[second];
str[second] = num;
return(copyCell(envelope));
}
if(!isList(envelope->type))
return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, params));
envelope->aux = (UINT)nilCell; /* undo push optimization */
list = (CELL *)envelope->contents;
if(first < 0) first = convertNegativeOffset(first, list);
if(second < 0) second = convertNegativeOffset(second, list);
if(first > second) swap((UINT*)&first, (UINT*)&second);
second = second - first;
firstCell = list;
while(first--)
{
if(firstCell->next == nilCell) break;
firstCell = firstCell->next;
}
secondCell = firstCell;
while(second--)
{
if(secondCell->next == nilCell) break;
secondCell = secondCell->next;
}
swap(&firstCell->type, &secondCell->type);
swap(&firstCell->contents, &secondCell->contents);
swap(&firstCell->aux, &secondCell->aux);
return(copyCell(envelope));
}
CELL * p_dup(CELL * params)
{
CELL * list;
CELL * expr;
char * str;
ssize_t n, len;
expr = evaluateExpression(params);
params = params->next;
getInteger(params, (UINT *)&n);
if(n < 0) n = 0;
if(expr->type == CELL_STRING && !getFlag(params->next) )
{
len = expr->aux - 1;
list = getCell(CELL_STRING);
str = allocMemory(len * n + 1);
list->contents = (UINT)str;
list->aux = (len * n + 1);
*(str + len * n) = 0;
while(n--)
{
memcpy(str, (char *)expr->contents, len);
str += len;
}
return(list);
}
list = getCell(CELL_EXPRESSION);
if(n-- > 0)
{
list->contents = (UINT)copyCell(expr);
params = (CELL *)list->contents;
while(n--)
{
params->next = copyCell(expr);
params = params->next;
}
}
return(list);
}
#define STARTS_WITH 0
#define ENDS_WITH 1
CELL * startsEndsWith(CELL * params, int type)
{
char * string;
char * key;
char * keydollar;
long options = -1;
size_t slen, pos;
int klen;
CELL * cell, * list;
cell = params->next;
list = evaluateExpression(params);
if(list->type == CELL_STRING)
{
string = (char *)list->contents;
getString(cell, &key);
}
else
{
if(!isList(list->type))
errorProcExt(ERR_LIST_OR_STRING_EXPECTED, params);
cell = evaluateExpression(cell);
list = (CELL *)list->contents;
if(type == ENDS_WITH)
while(list->next != nilCell) list = list->next;
if(compareCells(list, cell) == 0) return(trueCell);
else return(nilCell);
}
if(cell->next != nilCell)
{
if(evaluateExpression(cell->next)->type == CELL_NIL)
options = 1;
else
getIntegerExt(cell->next, (UINT*)&options, FALSE);
}
klen = strlen(key);
slen = strlen(string);
if(type == STARTS_WITH)
{
if(options == -1)
{
if(strncmp(string, key, (size_t)klen) == 0)
return(trueCell);
}
else
{
if(searchBufferRegex(string, 0, key, slen, options, 0) == 0)
return(trueCell);
}
return(nilCell);
}
if((options == -1) && (klen > slen)) return(nilCell);
if(options == -1)
{
if(strncmp(string + slen - klen, key, klen) == 0)
return(trueCell);
}
else
{
/* append $ to the pattern for anchoring at the end */
keydollar = alloca(klen + 2);
memcpy(keydollar, key, klen);
*(keydollar + klen) = '$';
*(keydollar + klen + 1) = 0;
klen = klen + 1;
if((pos = searchBufferRegex(string, 0, keydollar, slen, options, &klen)) != -1)
{
if(pos + klen == slen)
return(trueCell);
}
}
return(nilCell);
}
CELL * p_startsWith(CELL * params) { return startsEndsWith(params, STARTS_WITH); }
CELL * p_endsWith(CELL * params) { return startsEndsWith(params, ENDS_WITH); }
CELL * p_replace(CELL * params)
{
CELL * keyCell;
CELL * repCell;
CELL * funcCell = NULL;
CELL * list;
CELL * cell;
CELL * newList;
char * keyStr;
char * buff;
char * newBuff;
UINT cnt;
size_t newLen;
long options;
int resultIdxSave;
keyCell = evaluateExpression(params);
params = params->next;
newList = cell = evalCheckProtected(params, NULL);
cnt = 0;
resultIdxSave = resultStackIdx;
if(isList(cell->type))
{
cell->aux = (UINT)nilCell; /* undo push optimization */
list = (CELL *)cell->contents;
if(params->next != nilCell)
{
params = params->next;
repCell = params;
if(params->next != nilCell)
funcCell = evaluateExpression(params->next);
}
else
repCell = NULL;
COMPARE_START:
if(compareFunc(keyCell, list, funcCell) == 0)
{
if(repCell != NULL)
{
deleteList((CELL*)sysSymbol[0]->contents);
sysSymbol[0]->contents = (UINT)copyCell(list);
cell->contents = (UINT)copyCell(evaluateExpression(repCell));
cell = (CELL*)cell->contents;
cell->next = list->next;
}
else /* remove mode */
cell->contents = (UINT)list->next;
list->next = nilCell;
deleteList(list);
cnt++;
if(repCell != NULL)
list = cell;
else /* remove mode */
{
list = (CELL*)cell->contents;
goto COMPARE_START;
}
}
while(list->next != nilCell)
{
if(compareFunc(keyCell, list->next, funcCell) == 0)
{
cell = list->next; /* cell = old elmnt */
if(repCell != NULL)
{
deleteList((CELL*)sysSymbol[0]->contents);
sysSymbol[0]->contents = (UINT)copyCell(cell);
list->next = copyCell(evaluateExpression(repCell));
list = list->next;
}
list->next = cell->next;
cell->next = nilCell;
deleteList(cell);
cnt++;
}
else
list = list->next;
cleanupResults(resultIdxSave);
}
deleteList((CELL*)sysSymbol[0]->contents);
sysSymbol[0]->contents = (UINT)stuffInteger(cnt);
return(copyCell(newList));
}
if(cell->type == CELL_STRING)
{
if(keyCell->type != CELL_STRING)
return(errorProc(ERR_STRING_EXPECTED));
keyStr = (char *)keyCell->contents;
buff = (char *)cell->contents;
repCell = params->next;
if(repCell == nilCell)
return(errorProc(ERR_MISSING_ARGUMENT));
options = -1;
if(repCell->next != nilCell)
getInteger(repCell->next, (UINT*)&options);
newBuff = replaceString(keyStr, keyCell->aux - 1,
buff, (size_t)cell->aux -1, repCell, &cnt, options, &newLen);
if(newBuff != NULL)
{
freeMemory(buff);
cell->contents = (UINT)newBuff;
cell->aux = newLen + 1;
}
deleteList((CELL*)sysSymbol[0]->contents);
sysSymbol[0]->contents = (UINT)stuffInteger(cnt);
return(copyCell(cell));
}
return(errorProcExt(ERR_LIST_OR_STRING_EXPECTED, params));
}
CELL * p_rotate(CELL * params)
{
CELL * cell;
CELL * previous;
CELL * last = NULL;
size_t length, index;
size_t count;
cell = params;
if(cell->next != nilCell) getInteger(cell->next, (UINT *)&count);
else count = 1;
params = evalCheckProtected(params, NULL);
if(params->type == CELL_STRING)
{
cell = copyCell(params);
length = params->aux - 1;
if((count = adjustCount(count, length)) == 0) return(cell);
memcpy((char*)cell->contents, (char *)(params->contents + length - count), count);
memcpy((char*)(cell->contents + count), (char *)params->contents, length - count);
memcpy((char*)params->contents, (char*)cell->contents, length);
return(cell);
}
if(!isList(params->type))
return(errorProcExt(ERR_LIST_EXPECTED, cell));
params->aux = (UINT)nilCell; /* undo push optimization */
cell = (CELL *)params->contents;
length = 0;
while(cell != nilCell)
{
++length;
last = cell;
cell = cell->next;
}
if((count = adjustCount(count, length))== 0)
return(copyCell(params));
index = length - count;
previous = cell = (CELL *)params->contents;
while(index--)
{
previous = cell;
cell = cell->next;
}
previous->next = nilCell;
last->next = (CELL *)params->contents;
params->contents = (UINT)cell;
return(copyCell(params));
}
/* eof */
syntax highlighted by Code2HTML, v. 0.9.1