#include "tclInt.h"
#include "tclPort.h"
char *tclExecutableName = NULL;
static Tcl_Interp *sortInterp = NULL;
static enum {ASCII, INTEGER, REAL, COMMAND} sortMode;
static Tcl_DString sortCmd;
static int sortIncreasing;
static int sortCode;
static int SortCompareProc _ANSI_ARGS_((CONST VOID *first,
CONST VOID *second));
int
Tcl_IfCmd(dummy, interp, argc, argv)
ClientData dummy;
Tcl_Interp *interp;
int argc;
char **argv;
{
int i, result, value;
i = 1;
while (1) {
if (i >= argc) {
Tcl_AppendResult(interp, "wrong # args: no expression after \"",
argv[i-1], "\" argument", (char *) NULL);
return TCL_ERROR;
}
result = Tcl_ExprBoolean(interp, argv[i], &value);
if (result != TCL_OK) {
return result;
}
i++;
if ((i < argc) && (strcmp(argv[i], "then") == 0)) {
i++;
}
if (i >= argc) {
Tcl_AppendResult(interp, "wrong # args: no script following \"",
argv[i-1], "\" argument", (char *) NULL);
return TCL_ERROR;
}
if (value) {
return Tcl_Eval(interp, argv[i]);
}
i++;
if (i >= argc) {
return TCL_OK;
}
if ((argv[i][0] == 'e') && (strcmp(argv[i], "elseif") == 0)) {
i++;
continue;
}
break;
}
if (strcmp(argv[i], "else") == 0) {
i++;
if (i >= argc) {
Tcl_AppendResult(interp,
"wrong # args: no script following \"else\" argument",
(char *) NULL);
return TCL_ERROR;
}
}
return Tcl_Eval(interp, argv[i]);
}
int
Tcl_IncrCmd(dummy, interp, argc, argv)
ClientData dummy;
Tcl_Interp *interp;
int argc;
char **argv;
{
int value;
char *oldString, *result;
char newString[30];
if ((argc != 2) && (argc != 3)) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" varName ?increment?\"", (char *) NULL);
return TCL_ERROR;
}
oldString = Tcl_GetVar(interp, argv[1], TCL_LEAVE_ERR_MSG);
if (oldString == NULL) {
return TCL_ERROR;
}
if (Tcl_GetInt(interp, oldString, &value) != TCL_OK) {
Tcl_AddErrorInfo(interp,
"\n (reading value of variable to increment)");
return TCL_ERROR;
}
if (argc == 2) {
value += 1;
} else {
int increment;
if (Tcl_GetInt(interp, argv[2], &increment) != TCL_OK) {
Tcl_AddErrorInfo(interp,
"\n (reading increment)");
return TCL_ERROR;
}
value += increment;
}
sprintf(newString, "%d", value);
result = Tcl_SetVar(interp, argv[1], newString, TCL_LEAVE_ERR_MSG);
if (result == NULL) {
return TCL_ERROR;
}
interp->result = result;
return TCL_OK;
}
int
Tcl_JoinCmd(dummy, interp, argc, argv)
ClientData dummy;
Tcl_Interp *interp;
int argc;
char **argv;
{
char *joinString;
char **listArgv;
int listArgc, i;
if (argc == 2) {
joinString = " ";
} else if (argc == 3) {
joinString = argv[2];
} else {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" list ?joinString?\"", (char *) NULL);
return TCL_ERROR;
}
if (Tcl_SplitList(interp, argv[1], &listArgc, &listArgv) != TCL_OK) {
return TCL_ERROR;
}
for (i = 0; i < listArgc; i++) {
if (i == 0) {
Tcl_AppendResult(interp, listArgv[0], (char *) NULL);
} else {
Tcl_AppendResult(interp, joinString, listArgv[i], (char *) NULL);
}
}
ckfree((char *) listArgv);
return TCL_OK;
}
int
Tcl_LindexCmd(dummy, interp, argc, argv)
ClientData dummy;
Tcl_Interp *interp;
int argc;
char **argv;
{
char *p, *element, *next;
int index, size, parenthesized, result, returnLast;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" list index\"", (char *) NULL);
return TCL_ERROR;
}
if ((*argv[2] == 'e') && (strncmp(argv[2], "end", strlen(argv[2])) == 0)) {
returnLast = 1;
index = INT_MAX;
} else {
returnLast = 0;
if (Tcl_GetInt(interp, argv[2], &index) != TCL_OK) {
return TCL_ERROR;
}
}
if (index < 0) {
return TCL_OK;
}
for (p = argv[1] ; index >= 0; index--) {
result = TclFindElement(interp, p, &element, &next, &size,
&parenthesized);
if (result != TCL_OK) {
return result;
}
if ((*next == 0) && returnLast) {
break;
}
p = next;
}
if (size == 0) {
return TCL_OK;
}
if (size >= TCL_RESULT_SIZE) {
interp->result = (char *) ckalloc((unsigned) size+1);
interp->freeProc = TCL_DYNAMIC;
}
if (parenthesized) {
memcpy((VOID *) interp->result, (VOID *) element, (size_t) size);
interp->result[size] = 0;
} else {
TclCopyAndCollapse(size, element, interp->result);
}
return TCL_OK;
}
int
Tcl_LinsertCmd(dummy, interp, argc, argv)
ClientData dummy;
Tcl_Interp *interp;
int argc;
char **argv;
{
char *p, *element, savedChar;
int i, index, count, result, size;
if (argc < 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" list index element ?element ...?\"", (char *) NULL);
return TCL_ERROR;
}
if ((*argv[2] == 'e') && (strncmp(argv[2], "end", strlen(argv[2])) == 0)) {
index = INT_MAX;
} else if (Tcl_GetInt(interp, argv[2], &index) != TCL_OK) {
return TCL_ERROR;
}
size = 0;
element = argv[1];
for (count = 0, p = argv[1]; (count < index) && (*p != 0); count++) {
result = TclFindElement(interp, p, &element, &p, &size, (int *) NULL);
if (result != TCL_OK) {
return result;
}
}
if (*p == 0) {
Tcl_AppendResult(interp, argv[1], (char *) NULL);
} else {
char *end;
end = element+size;
if (element != argv[1]) {
while ((*end != 0) && !isspace(UCHAR(*end))) {
end++;
}
}
savedChar = *end;
*end = 0;
Tcl_AppendResult(interp, argv[1], (char *) NULL);
*end = savedChar;
}
for (i = 3; i < argc; i++) {
Tcl_AppendElement(interp, argv[i]);
}
if (*p != 0) {
Tcl_AppendResult(interp, " ", p, (char *) NULL);
}
return TCL_OK;
}
int
Tcl_ListCmd(dummy, interp, argc, argv)
ClientData dummy;
Tcl_Interp *interp;
int argc;
char **argv;
{
if (argc >= 2) {
interp->result = Tcl_Merge(argc-1, argv+1);
interp->freeProc = TCL_DYNAMIC;
}
return TCL_OK;
}
int
Tcl_LlengthCmd(dummy, interp, argc, argv)
ClientData dummy;
Tcl_Interp *interp;
int argc;
char **argv;
{
int count, result;
char *element, *p;
if (argc != 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" list\"", (char *) NULL);
return TCL_ERROR;
}
for (count = 0, p = argv[1]; *p != 0 ; count++) {
result = TclFindElement(interp, p, &element, &p, (int *) NULL,
(int *) NULL);
if (result != TCL_OK) {
return result;
}
if (*element == 0) {
break;
}
}
sprintf(interp->result, "%d", count);
return TCL_OK;
}
int
Tcl_LrangeCmd(notUsed, interp, argc, argv)
ClientData notUsed;
Tcl_Interp *interp;
int argc;
char **argv;
{
int first, last, result;
char *begin, *end, c, *dummy, *next;
int count, firstIsEnd;
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" list first last\"", (char *) NULL);
return TCL_ERROR;
}
if ((*argv[2] == 'e') && (strncmp(argv[2], "end", strlen(argv[2])) == 0)) {
firstIsEnd = 1;
first = INT_MAX;
} else {
firstIsEnd = 0;
if (Tcl_GetInt(interp, argv[2], &first) != TCL_OK) {
return TCL_ERROR;
}
}
if (first < 0) {
first = 0;
}
if ((*argv[3] == 'e') && (strncmp(argv[3], "end", strlen(argv[3])) == 0)) {
last = INT_MAX;
} else {
if (Tcl_GetInt(interp, argv[3], &last) != TCL_OK) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "expected integer or \"end\" but got \"",
argv[3], "\"", (char *) NULL);
return TCL_ERROR;
}
}
if ((first > last) && !firstIsEnd) {
return TCL_OK;
}
for (count = 0, begin = argv[1]; count < first; begin = next, count++) {
result = TclFindElement(interp, begin, &dummy, &next, (int *) NULL,
(int *) NULL);
if (result != TCL_OK) {
return result;
}
if (*next == 0) {
if (firstIsEnd) {
first = count;
} else {
begin = next;
}
break;
}
}
for (count = first, end = begin; (count <= last) && (*end != 0);
count++) {
result = TclFindElement(interp, end, &dummy, &end, (int *) NULL,
(int *) NULL);
if (result != TCL_OK) {
return result;
}
}
if (end == begin) {
return TCL_OK;
}
while ((end != begin) && (isspace(UCHAR(end[-1])))
&& (((end-1) == begin) || (end[-2] != '\\'))) {
end--;
}
c = *end;
*end = 0;
Tcl_SetResult(interp, begin, TCL_VOLATILE);
*end = c;
return TCL_OK;
}
int
Tcl_LreplaceCmd(notUsed, interp, argc, argv)
ClientData notUsed;
Tcl_Interp *interp;
int argc;
char **argv;
{
char *p1, *p2, *element, savedChar, *dummy, *next;
int i, first, last, count, result, size, firstIsEnd;
if (argc < 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" list first last ?element element ...?\"", (char *) NULL);
return TCL_ERROR;
}
if ((*argv[2] == 'e') && (strncmp(argv[2], "end", strlen(argv[2])) == 0)) {
firstIsEnd = 1;
first = INT_MAX;
} else {
firstIsEnd = 0;
if (Tcl_GetInt(interp, argv[2], &first) != TCL_OK) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "bad index \"", argv[2],
"\": must be integer or \"end\"", (char *) NULL);
return TCL_ERROR;
}
}
if ((*argv[3] == 'e') && (strncmp(argv[3], "end", strlen(argv[3])) == 0)) {
last = INT_MAX;
} else {
if (Tcl_GetInt(interp, argv[3], &last) != TCL_OK) {
Tcl_ResetResult(interp);
Tcl_AppendResult(interp, "bad index \"", argv[3],
"\": must be integer or \"end\"", (char *) NULL);
return TCL_ERROR;
}
}
if (first < 0) {
first = 0;
}
size = 0;
element = argv[1];
for (count = 0, p1 = argv[1]; (count < first) && (*p1 != 0); count++) {
result = TclFindElement(interp, p1, &element, &next, &size,
(int *) NULL);
if (result != TCL_OK) {
return result;
}
if ((*next == 0) && firstIsEnd) {
break;
}
p1 = next;
}
if (*p1 == 0) {
Tcl_AppendResult(interp, "list doesn't contain element ",
argv[2], (char *) NULL);
return TCL_ERROR;
}
for (p2 = p1 ; (count <= last) && (*p2 != 0); count++) {
result = TclFindElement(interp, p2, &dummy, &p2, (int *) NULL,
(int *) NULL);
if (result != TCL_OK) {
return result;
}
}
while ((p1 != argv[1]) && (isspace(UCHAR(p1[-1])))
&& (((p1-1) == argv[1]) || (p1[-2] != '\\'))) {
p1--;
}
savedChar = *p1;
*p1 = 0;
Tcl_AppendResult(interp, argv[1], (char *) NULL);
*p1 = savedChar;
for (i = 4; i < argc; i++) {
Tcl_AppendElement(interp, argv[i]);
}
if (*p2 != 0) {
if (*interp->result == 0) {
Tcl_SetResult(interp, p2, TCL_VOLATILE);
} else {
Tcl_AppendResult(interp, " ", p2, (char *) NULL);
}
}
return TCL_OK;
}
int
Tcl_LsearchCmd(notUsed, interp, argc, argv)
ClientData notUsed;
Tcl_Interp *interp;
int argc;
char **argv;
{
#define EXACT 0
#define GLOB 1
#define REGEXP 2
int listArgc;
char **listArgv;
int i, match, mode, index;
mode = GLOB;
if (argc == 4) {
if (strcmp(argv[1], "-exact") == 0) {
mode = EXACT;
} else if (strcmp(argv[1], "-glob") == 0) {
mode = GLOB;
} else if (strcmp(argv[1], "-regexp") == 0) {
mode = REGEXP;
} else {
Tcl_AppendResult(interp, "bad search mode \"", argv[1],
"\": must be -exact, -glob, or -regexp", (char *) NULL);
return TCL_ERROR;
}
} else if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ?mode? list pattern\"", (char *) NULL);
return TCL_ERROR;
}
if (Tcl_SplitList(interp, argv[argc-2], &listArgc, &listArgv) != TCL_OK) {
return TCL_ERROR;
}
index = -1;
for (i = 0; i < listArgc; i++) {
match = 0;
switch (mode) {
case EXACT:
match = (strcmp(listArgv[i], argv[argc-1]) == 0);
break;
case GLOB:
match = Tcl_StringMatch(listArgv[i], argv[argc-1]);
break;
case REGEXP:
match = Tcl_RegExpMatch(interp, listArgv[i], argv[argc-1]);
if (match < 0) {
ckfree((char *) listArgv);
return TCL_ERROR;
}
break;
}
if (match) {
index = i;
break;
}
}
sprintf(interp->result, "%d", index);
ckfree((char *) listArgv);
return TCL_OK;
}
int
Tcl_LsortCmd(notUsed, interp, argc, argv)
ClientData notUsed;
Tcl_Interp *interp;
int argc;
char **argv;
{
int listArgc, i, c;
size_t length;
char **listArgv;
char *command = NULL;
if (argc < 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
" ?-ascii? ?-integer? ?-real? ?-increasing? ?-decreasing?",
" ?-command string? list\"", (char *) NULL);
return TCL_ERROR;
}
if (sortInterp != NULL) {
interp->result = "can't invoke \"lsort\" recursively";
return TCL_ERROR;
}
sortInterp = interp;
sortMode = ASCII;
sortIncreasing = 1;
sortCode = TCL_OK;
for (i = 1; i < argc-1; i++) {
length = strlen(argv[i]);
if (length < 2) {
badSwitch:
Tcl_AppendResult(interp, "bad switch \"", argv[i],
"\": must be -ascii, -integer, -real, -increasing",
" -decreasing, or -command", (char *) NULL);
sortCode = TCL_ERROR;
goto done;
}
c = argv[i][1];
if ((c == 'a') && (strncmp(argv[i], "-ascii", length) == 0)) {
sortMode = ASCII;
} else if ((c == 'c') && (strncmp(argv[i], "-command", length) == 0)) {
if (i == argc-2) {
Tcl_AppendResult(interp, "\"-command\" must be",
" followed by comparison command", (char *) NULL);
sortCode = TCL_ERROR;
goto done;
}
sortMode = COMMAND;
command = argv[i+1];
i++;
} else if ((c == 'd')
&& (strncmp(argv[i], "-decreasing", length) == 0)) {
sortIncreasing = 0;
} else if ((c == 'i') && (length >= 4)
&& (strncmp(argv[i], "-increasing", length) == 0)) {
sortIncreasing = 1;
} else if ((c == 'i') && (length >= 4)
&& (strncmp(argv[i], "-integer", length) == 0)) {
sortMode = INTEGER;
} else if ((c == 'r')
&& (strncmp(argv[i], "-real", length) == 0)) {
sortMode = REAL;
} else {
goto badSwitch;
}
}
if (sortMode == COMMAND) {
Tcl_DStringInit(&sortCmd);
Tcl_DStringAppend(&sortCmd, command, -1);
}
if (Tcl_SplitList(interp, argv[argc-1], &listArgc, &listArgv) != TCL_OK) {
sortCode = TCL_ERROR;
goto done;
}
qsort((VOID *) listArgv, (size_t) listArgc, sizeof (char *),
SortCompareProc);
if (sortCode == TCL_OK) {
Tcl_ResetResult(interp);
interp->result = Tcl_Merge(listArgc, listArgv);
interp->freeProc = TCL_DYNAMIC;
}
if (sortMode == COMMAND) {
Tcl_DStringFree(&sortCmd);
}
ckfree((char *) listArgv);
done:
sortInterp = NULL;
return sortCode;
}
static int
SortCompareProc(first, second)
CONST VOID *first, *second;
{
int order;
char *firstString = *((char **) first);
char *secondString = *((char **) second);
order = 0;
if (sortCode != TCL_OK) {
return order;
}
if (sortMode == ASCII) {
order = strcmp(firstString, secondString);
} else if (sortMode == INTEGER) {
int a, b;
if ((Tcl_GetInt(sortInterp, firstString, &a) != TCL_OK)
|| (Tcl_GetInt(sortInterp, secondString, &b) != TCL_OK)) {
Tcl_AddErrorInfo(sortInterp,
"\n (converting list element from string to integer)");
sortCode = TCL_ERROR;
return order;
}
if (a > b) {
order = 1;
} else if (b > a) {
order = -1;
}
} else if (sortMode == REAL) {
double a, b;
if ((Tcl_GetDouble(sortInterp, firstString, &a) != TCL_OK)
|| (Tcl_GetDouble(sortInterp, secondString, &b) != TCL_OK)) {
Tcl_AddErrorInfo(sortInterp,
"\n (converting list element from string to real)");
sortCode = TCL_ERROR;
return order;
}
if (a > b) {
order = 1;
} else if (b > a) {
order = -1;
}
} else {
int oldLength;
char *end;
oldLength = Tcl_DStringLength(&sortCmd);
Tcl_DStringAppendElement(&sortCmd, firstString);
Tcl_DStringAppendElement(&sortCmd, secondString);
sortCode = Tcl_Eval(sortInterp, Tcl_DStringValue(&sortCmd));
Tcl_DStringTrunc(&sortCmd, oldLength);
if (sortCode != TCL_OK) {
Tcl_AddErrorInfo(sortInterp,
"\n (user-defined comparison command)");
return order;
}
order = strtol(sortInterp->result, &end, 0);
if ((end == sortInterp->result) || (*end != 0)) {
Tcl_ResetResult(sortInterp);
Tcl_AppendResult(sortInterp,
"comparison command returned non-numeric result",
(char *) NULL);
sortCode = TCL_ERROR;
return order;
}
}
if (!sortIncreasing) {
order = -order;
}
return order;
}