/* newlisp.c --- enrty point and main functions for newLISP
Copyright (C) 2016 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 .
*/
#include "newlisp.h"
#include "protos.h"
#include "primes.h"
#ifdef WINDOWS
#include
#else
#include
#endif
#ifdef READLINE
#include
/* take following line out on Slackware Linux */
#include
#endif /* end READLINE */
#ifdef SUPPORT_UTF8
#include
#endif
#define freeMemory free
#define INIT_FILE "init.lsp"
#ifdef WINDOWS
#define fprintf win_fprintf
#define fgets win_fgets
#define fclose win_fclose
#endif
#ifdef LIBRARY
extern STREAM libStrStream;
int newlispLibConsoleFlag = 0;
#endif
#ifdef LINUX
#ifdef ANDROID
int opsys = 11;
#else
int opsys = 1;
#endif
#endif
#ifdef _BSD
int opsys = 2;
#endif
#ifdef MAC_OSX
#ifdef EMSCRIPTEN
int opsys = 11;
#else
int opsys = 3;
#endif
#endif
#ifdef SOLARIS
int opsys = 4;
#endif
#ifdef WINDOWS
int opsys = 6;
#endif
#ifdef OS2
int opsys = 7;
#endif
#ifdef CYGWIN
int opsys = 8;
#endif
#ifdef TRU64
int opsys = 9;
#endif
#ifdef AIX
int opsys = 10;
#endif
/* opsys = 11 taken for ANDROID; see LINUX */
int bigEndian = 1; /* gets set in main() */
int version = 10700;
char copyright[]=
"\nnewLISP v.10.7.0 Copyright (c) 2016 Lutz Mueller. All rights reserved.\n\n%s\n\n";
#ifndef NEWLISP64
#ifdef SUPPORT_UTF8
char banner[]=
"newLISP v.10.7.0 32-bit on %s IPv4/6 UTF-8%s%s\n\n";
#else
char banner[]=
"newLISP v.10.7.0 32-bit on %s IPv4/6%s%s\n\n";
#endif
#else /* NEWLISP64 */
#ifdef SUPPORT_UTF8
char banner[]=
"newLISP v.10.7.0 64-bit on %s IPv4/6 UTF-8%s%s\n\n";
#else
char banner[]=
"newLISP v.10.7.0 64-bit on %s IPv4/6%s%s\n\n";
#endif
#endif /* NEWLISP64 */
char banner2[]= ", options: newlisp -h";
void linkSource(char *, char *, char *);
char linkOffset[] = "&&&&@@@@";
char preLoad[] =
#ifdef EMSCRIPTEN
"(set (global 'module) (fn ($x) (load (append {/newlisp-js/} $x))))"
#else
"(set (global 'module) (fn ($x) (load (append (env {NEWLISPDIR}) {/modules/} $x))))"
#endif
"(context 'Tree) (constant 'Tree:Tree) (context MAIN)"
"(define (Class:Class) (cons (context) (args)))";
void printHelpText(void);
#ifdef READLINE
char ** newlisp_completion (char * text, int start, int end);
#endif
/* --------------------- globals -------------------------------------- */
/* interactive command line */
int isTTY = FALSE;
int daemonMode = 0;
int noPromptMode = 0;
int forcePromptMode = 0;
int httpMode = 0;
int evalSilent = 0;
#ifdef WINDOWS
int IOchannelIsSocketStream = 0;
#endif
FILE * IOchannel;
char * IOdomain = NULL;
int IOport = 0;
int connectionTimeout = 0;
int logTraffic = 0;
#define LOG_LESS 1
#define LOG_MORE 2
/* initialization */
int MAX_CPU_STACK = 0x800;
int MAX_ENV_STACK;
int MAX_RESULT_STACK;
#define MAX_OBJECT_STACK 64
#ifndef NEWLISP64
INT MAX_CELL_COUNT = 0x10000000;
#else
INT MAX_CELL_COUNT = 0x800000000000000LL;
#endif
INT blockCount = 0;
CELL * firstFreeCell = NULL;
CELL * nilCell;
CELL * trueCell;
CELL * lastCellCopied;
CELL * countCell;
SYMBOL * nilSymbol;
SYMBOL * trueSymbol;
SYMBOL * starSymbol;
SYMBOL * plusSymbol;
SYMBOL * questionSymbol;
SYMBOL * atSymbol;
SYMBOL * currentFunc;
SYMBOL * argsSymbol;
SYMBOL * mainArgsSymbol;
SYMBOL * listIdxSymbol;
SYMBOL * itSymbol;
SYMBOL * sysxSymbol;
SYMBOL * countSymbol;
SYMBOL * beginSymbol;
SYMBOL * expandSymbol;
SYMBOL * sysSymbol[MAX_REGEX_EXP];
SYMBOL * currentContext = NULL;
SYMBOL * mainContext = NULL;
SYMBOL * errorEvent;
SYMBOL * timerEvent;
SYMBOL * promptEvent;
SYMBOL * commandEvent;
SYMBOL * transferEvent;
SYMBOL * readerEvent;
SYMBOL * symHandler[32];
int currentSignal = 0;
SYMBOL * symbolCheck = NULL;
CELL * stringCell = NULL;
void * stringIndexPtr = NULL;
jmp_buf errorJump;
char lc_decimal_point;
/* error and exception handling */
#define EXCEPTION_THROW -1
int errorReg = 0;
CELL * throwResult;
/* buffers for read-line and error reporting */
STREAM readLineStream;
STREAM errorStream;
/* compiler */
size_t cellCount = 0;
size_t symbolCount = 0;
int parStackCounter = 0;
/* expression evaluation */
static CELL * (*evalFunc)(CELL *) = NULL;
UINT * envStack = NULL;
UINT * envStackIdx;
UINT * envStackTop;
UINT * resultStack = NULL;
UINT * resultStackIdx;
UINT * resultStackTop;
UINT * lambdaStack = NULL;
UINT * lambdaStackIdx;
/* internal dummy to carry FOOP object */
SYMBOL objSymbol = {SYMBOL_GLOBAL | SYMBOL_BUILTIN,
0, "container of (self)", 0, NULL, NULL, NULL, NULL};
CELL * objCell;
extern PRIMITIVE primitive[];
/* debugger in nl-debug.c */
extern char debugPreStr[];
extern char debugPostStr[];
extern CELL * debugPrintCell;
int traceFlag = 0;
int evalCatchFlag = 0;
int recursionCount = 0;
int prettyPrintPars = 0;
int prettyPrintCurrent = 0;
int prettyPrintFlags = 0;
int prettyPrintLength = 0;
char * prettyPrintTab = " ";
char * prettyPrintFloat = "%1.16g";
#define MAX_PRETTY_PRINT_LENGTH 80
UINT prettyPrintMaxLength = MAX_PRETTY_PRINT_LENGTH;
int stringOutputRaw = TRUE;
#define pushLambda(A) (*(lambdaStackIdx++) = (UINT)(A))
int pushResultFlag = TRUE;
char startupDir[PATH_MAX]; /* start up directory, if defined via -w */
char * tempDir; /* /tmp on unix or geten("TMP") on Windows */
char logFile[PATH_MAX]; /* logFile, is define with -l, -L */
/* nl-filesys.c */
int pagesize;
/* ============================== MAIN ================================ */
#ifndef EMSCRIPTEN
/*
void setupSignalHandler(int sig, void (* handler)(int))
{
static struct sigaction sig_act;
sig_act.sa_handler = handler;
sigemptyset(&sig_act.sa_mask);
sig_act.sa_flags = SA_RESTART | SA_NOCLDSTOP;
if(sigaction(sig, &sig_act, 0) != 0)
printf("Error setting signal:%d handler\n", sig);
}
*/
void setupSignalHandler(int sig, void (* handler)(int))
{
if(signal(sig, handler) == SIG_ERR)
printf("Error setting signal:%d handler\n", sig);
}
#if defined(SOLARIS) || defined(TRU64) || defined(AIX)
void sigpipe_handler(int sig)
{
setupSignalHandler(SIGPIPE, sigpipe_handler);
}
void sigchld_handler(int sig)
{
waitpid(-1, (int *)0, WNOHANG);
}
void ctrlC_handler(int sig)
{
char chr;
setupSignalHandler(SIGINT, ctrlC_handler);
traceFlag |= TRACE_SIGINT;
printErrorMessage(ERR_SIGINT, NULL, 0);
printf("%s", "(c)ontinue, e(x)it, (r)eset:");
fflush(NULL);
chr = getchar();
if(chr == 'x') exit(1);
if(chr == 'c') traceFlag &= ~TRACE_SIGINT;
}
void sigalrm_handler(int sig)
{
setupSignalHandler(sig, sigalrm_handler);
/* check if not sitting idle */
if(recursionCount)
traceFlag |= TRACE_TIMER;
else /* if idle */
executeSymbol(timerEvent, NULL, NULL);
}
#endif /* SOLARIS, TRUE64, AIX */
void setupAllSignals(void)
{
#if defined(SOLARIS) || defined(TRU64) || defined(AIX)
setupSignalHandler(SIGINT, ctrlC_handler);
#else
setupSignalHandler(SIGINT, signal_handler);
#endif
#ifndef WINDOWS
#if defined(SOLARIS) || defined(TRU64) || defined(AIX)
setupSignalHandler(SIGALRM, sigalrm_handler);
setupSignalHandler(SIGVTALRM, sigalrm_handler);
setupSignalHandler(SIGPROF, sigalrm_handler);
setupSignalHandler(SIGPIPE, sigpipe_handler);
setupSignalHandler(SIGCHLD, sigchld_handler);
#else
setupSignalHandler(SIGALRM, signal_handler);
setupSignalHandler(SIGVTALRM, signal_handler);
setupSignalHandler(SIGPROF, signal_handler);
setupSignalHandler(SIGPIPE, signal_handler);
setupSignalHandler(SIGCHLD, signal_handler);
#endif
#endif
}
void signal_handler(int sig)
{
#ifndef WINDOWS
char chr;
#endif
if(sig > 32 || sig < 1) return;
#if defined(SOLARIS) || defined(TRU64) || defined(AIX)
switch(sig)
{
case SIGALRM:
case SIGVTALRM:
case SIGPROF:
setupSignalHandler(sig, sigalrm_handler);
break;
case SIGPIPE:
setupSignalHandler(SIGPIPE, sigpipe_handler);
break;
case SIGCHLD:
setupSignalHandler(SIGCHLD, sigchld_handler);
break;
}
#else
setupSignalHandler(sig, signal_handler);
#endif
if(symHandler[sig - 1] != nilSymbol)
{
if(recursionCount)
{
currentSignal = sig;
traceFlag |= TRACE_SIGNAL;
return;
}
else
{
executeSymbol(symHandler[sig-1], stuffInteger(sig), NULL);
return;
}
}
switch(sig)
{
case SIGINT:
printErrorMessage(ERR_SIGINT, NULL, 0);
#ifdef WINDOWS
traceFlag |= TRACE_SIGINT;
#else
printf("%s", "\n(c)ontinue, (d)ebug, e(x)it, (r)eset:");
fflush(NULL);
chr = getchar();
if(chr == 'x') exit(1);
if(chr == 'd')
{
traceFlag &= ~TRACE_SIGINT;
openTrace();
}
if(chr == 'r') traceFlag |= TRACE_SIGINT;
break;
case SIGPIPE:
break;
case SIGALRM:
case SIGVTALRM:
case SIGPROF:
/* check if not sitting idle */
if(recursionCount)
traceFlag |= TRACE_TIMER;
else /* if idle */
executeSymbol(timerEvent, NULL, NULL);
break;
case SIGCHLD:
waitpid(-1, (int *)0, WNOHANG);
#endif
break;
default:
return;
}
}
#endif /* no EMSCRIPTEN */
char * which(char * name, char * buff)
{
char *path_list, *test, *tmp, *path_parsed;
struct stat filestat;
int count = 1;
int i, len, nlen;
int found = FALSE;
path_list = getenv("PATH");
if (!path_list) path_list = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin";
len = strlen(path_list);
nlen = strlen(name);
path_parsed = alloca(len + 1);
strncpy(path_parsed, path_list, len + 1);
test = path_parsed;
while (TRUE)
{
#ifdef WINDOWS
tmp = strchr(test, ';');
#else
tmp = strchr(test, ':');
#endif
if (tmp == NULL) break;
*tmp = 0;
test = tmp + 1;
count++;
}
test = path_parsed;
for (i = 0; i < count; i++)
{
len = strlen(test);
if((len + nlen + 2) > PATH_MAX)
return(NULL);
strncpy(buff, test, len + 1);
buff[len] = '/';
memcpy(buff + len + 1, name, nlen);
buff[len + 1 + nlen] = 0;
if (stat (buff, &filestat) == 0 && filestat.st_mode & S_IXUSR)
{
found = TRUE;
break;
}
test += (len + 1);
}
if(!found) return(NULL);
errno = 0;
return(buff);
}
#ifndef LIBRARY
void loadStartup(char * name)
{
char initFile[PATH_MAX];
char * envPtr;
int len;
/* normal newLISP start up */
if(strncmp(linkOffset + 4, "@@@@", 4) == 0)
{
if(getenv("HOME"))
strncpy(initFile, getenv("HOME"), PATH_MAX - 16);
else if(getenv("USERPROFILE"))
strncpy(initFile, getenv("USERPROFILE"), PATH_MAX - 16);
else if(getenv("DOCUMENT_ROOT"))
strncpy(initFile, getenv("DOCUMENT_ROOT"), PATH_MAX - 16);
len = strlen(initFile);
memcpy(initFile + len, "/.", 2);
memcpy(initFile + len + 2, INIT_FILE, 8);
initFile[len + 2 + 8] = 0;
if(loadFile(initFile, 0, 0, mainContext) == NULL)
{
envPtr = getenv("NEWLISPDIR");
if(envPtr)
{
strncpy(initFile, envPtr, PATH_MAX - 16);
len = strlen(envPtr);
memcpy(initFile + len, "/", 1);
memcpy(initFile + len + 1, INIT_FILE, 8);
initFile[len + 1 + 8] = 0;
loadFile(initFile, 0, 0, mainContext);
}
}
}
/* load part at offset no init.lsp or .init.lsp is loaded */
else
{
#ifdef WINDOWS
name = win_getExePath(alloca(MAX_PATH));
loadFile(name, *(unsigned int *)linkOffset, 1, mainContext);
#else /* if not Win32 get full pathname of file in name */
if(strchr(name, '/') == NULL)
if((name = which(name, alloca(PATH_MAX))) == NULL)
{
printf("%s: %s\n", strerror(ENOENT), name);
exit(ENOENT);
}
loadFile(name, *(unsigned int *)linkOffset, 1, mainContext);
#endif
}
}
#endif /* LIBRARY */
#ifdef _BSD
struct lconv *localeconv(void);
char *setlocale(int, const char *);
#endif
void initLocale(void)
{
#ifndef ANDROID
struct lconv * lc;
#endif
char * locale;
#ifndef SUPPORT_UTF8
locale = setlocale(LC_ALL, "C");
#else
locale = setlocale(LC_ALL, "");
#endif
if (locale != NULL)
stringOutputRaw = (strcmp(locale, "C") == 0);
#ifdef ANDROID
lc_decimal_point = '.';
#else
lc = localeconv();
lc_decimal_point = *lc->decimal_point;
#endif
}
/* set NEWLISPDIR only if not set already */
void initNewlispDir(void)
{
#ifdef WINDOWS
char * varValue;
char * newlispDir;
int len;
if(getenv("NEWLISPDIR") == NULL)
{
newlispDir = alloca(MAX_PATH);
varValue = getenv("PROGRAMFILES");
if(varValue != NULL)
{
len = strlen(varValue);
strncpy(newlispDir, varValue, MAX_PATH - 12);
memcpy(newlispDir + len, "/newlisp", 8);
newlispDir[len + 8] = 0;
setenv("NEWLISPDIR", newlispDir, TRUE);
}
else setenv("NEWLISPDIR", "newlisp", TRUE);
}
#else
if(getenv("NEWLISPDIR") == NULL)
setenv("NEWLISPDIR", NEWLISPDIR, TRUE);
#endif
}
void initTempDir()
{
#ifdef WINDOWS
if((tempDir = getenv("TMP")) == NULL)
{
printf("Environment variable TMP not set, assuming /tmp .");
tempDir = "/tmp";
}
#else
#ifdef ANDROID
tempDir = "/data/tmp";
#else /* all UNIX */
tempDir = "/tmp";
#endif
#endif
return;
}
#ifndef LIBRARY
char * getArg(char * * arg, int argc, int * index)
{
if(strlen(arg[*index]) > 2)
return(arg[*index] + 2);
if(*index >= (argc - 1))
{
printf("missing parameter for %s\n", arg[*index]);
exit(-1);
}
*index = *index + 1;
return(arg[*index]);
}
#ifndef WINDOWS
char ** MainArgs;
#endif
CELL * getMainArgs(char * mainArgs[])
{
CELL * argList;
int idx = 0;
#ifndef WINDOWS
MainArgs = mainArgs;
#endif
argList = getCell(CELL_EXPRESSION);
while(mainArgs[idx] != NULL)
addList(argList, stuffString(mainArgs[idx++]));
return(argList);
}
char * getCommandLine(int batchMode, int * length);
int main(int argc, char * argv[])
{
char command[MAX_COMMAND_LINE];
STREAM cmdStream = {NULL, NULL, 0, 0, 0};
char * cmd;
int idx;
#ifdef WINDOWS
WSADATA WSAData;
if(WSAStartup(MAKEWORD(2,2), &WSAData) != 0)
{
printf("Winsocket initialization failed\n");
exit(-1);
}
pagesize = 4096;
/* replace '_CRT_fmode = _O_BINARY' in nl-filesys.c for 10.4.8, thanks to Kosh */
_setmode(_fileno(stdin), _O_BINARY);
_setmode(_fileno(stdout), _O_BINARY);
_setmode(_fileno(stderr), _O_BINARY);
#endif
#ifdef SUPPORT_UTF8
opsys += 128;
#endif
#ifdef NEWLISP64
opsys += 256;
#endif
#ifdef FFI
opsys += 1024;
initFFI();
#endif
#ifndef WINDOWS
#ifndef OS2
pagesize = getpagesize();
#endif
tzset();
#endif
#ifdef OS2
/* Reset the floating point coprocessor */
_fpreset();
#endif
initLocale();
initNewlispDir();
initTempDir();
IOchannel = stdin;
bigEndian = (*((char *)&bigEndian) == 0);
initStacks();
initialize();
initDefaultInAddr();
#ifdef WINDOWS
#ifdef SUPPORT_UTF8
{
/*
command line parameter is MBCS.
MBCS -> Unicode(UTF-16) -> UTF-8
*/
char **argv_utf8 = allocMemory((argc + 1)* sizeof(char *)) ;
{
for(idx = 0 ; idxcontents = (UINT)getMainArgs(argv);
if((errorReg = setjmp(errorJump)) != 0)
{
if((errorEvent != nilSymbol) || (errorReg == ERR_USER_RESET))
executeSymbol(errorEvent, NULL, NULL);
else exit(-1);
goto AFTER_ERROR_ENTRY;
}
setupAllSignals();
sysEvalString(preLoad, mainContext, nilCell, EVAL_STRING);
/* loading of init.lsp can be suppressed with -n as first option
but is never done when program is link.lsp'd */
if(argc < 2 || strncmp(argv[1], "-n", 2))
{
if(!(argc >= 2 && strcmp(argv[1], "-x") == 0))
loadStartup(argv[0]);
}
errno = 0;
if(realpath(".", startupDir) == NULL)
fatalError(ERR_IO_ERROR, 0, 0);
for(idx = 1; idx < argc; idx++)
{
if(strncmp(argv[idx], "-c", 2) == 0)
{
noPromptMode = TRUE;
continue;
}
if(strncmp(argv[idx], "-C", 2) == 0)
{
forcePromptMode = TRUE;
continue;
}
if(strncmp(argv[idx], "-http", 5) == 0)
{
noPromptMode = TRUE;
httpMode = TRUE;
continue;
}
if(strncmp(argv[idx], "-s", 2) == 0)
{
MAX_CPU_STACK = atoi(getArg(argv, argc, &idx));
if(MAX_CPU_STACK < 1024) MAX_CPU_STACK = 1024;
initStacks();
continue;
}
if(strncmp(argv[idx], "-p", 2) == 0 || strncmp(argv[idx], "-d", 2) == 0 )
{
if(strncmp(argv[idx], "-d", 2) == 0)
daemonMode = TRUE;
IOdomain = getArg(argv, argc, &idx);
IOport = atoi(IOdomain);
setupServer(0);
continue;
}
if(strncmp(argv[idx], "-t", 2) == 0)
{
connectionTimeout = atoi(getArg(argv, argc, &idx));
continue;
}
if(strncmp(argv[idx], "-l", 2) == 0 || strncmp(argv[idx], "-L", 2) == 0)
{
logTraffic = (strncmp(argv[idx], "-L", 2) == 0) ? LOG_MORE : LOG_LESS;
if(realpath(getArg(argv, argc, &idx), logFile) == NULL)
close(openFile(logFile, "w", 0));
continue;
}
if(strncmp(argv[idx], "-m", 2) == 0)
{
#ifndef NEWLISP64
MAX_CELL_COUNT = abs(0x0010000 * atoi(getArg(argv, argc, &idx)));
#else
MAX_CELL_COUNT = abs(0x0008000 * atoi(getArg(argv, argc, &idx)));
#endif
continue;
}
if(strncmp(argv[idx], "-w", 2) == 0)
{
if(realpath(getArg(argv, argc, &idx), startupDir) == NULL
|| chdir(startupDir) < 0)
fatalError(ERR_WORKING_DIR, 0, 0);
continue;
}
if(strcmp(argv[idx], "-6") == 0)
{
ADDR_FAMILY = AF_INET6;
initDefaultInAddr();
continue;
}
if(strcmp(argv[idx], "-v") == 0)
{
varPrintf(OUT_CONSOLE, banner, OSTYPE, LIBFFI, ".");
exit(0);
}
if(strncmp(argv[idx], "-e", 2) == 0)
{
executeCommandLine(getArg(argv, argc, &idx), OUT_CONSOLE, &cmdStream);
exit(0);
}
if(strncmp(argv[idx], "-x", 2) == 0)
{
if(argc == 4)
linkSource(argv[0], argv[idx + 1], argv[idx + 2]);
exit(0);
}
if(strcmp(argv[idx], "-h") == 0)
{
printHelpText();
exit(0);
}
loadFile(argv[idx], 0, 0, mainContext);
}
AFTER_ERROR_ENTRY:
if(isatty(fileno(IOchannel)))
{
isTTY = TRUE;
if(!noPromptMode)
varPrintf(OUT_CONSOLE, banner, OSTYPE, LIBFFI, banner2);
}
else
{
#ifdef WINDOWS
if(!IOchannelIsSocketStream)
#endif
setbuf(IOchannel,0);
if(forcePromptMode)
varPrintf(OUT_CONSOLE, banner, OSTYPE, LIBFFI, banner2);
}
/* ======================= main entry on reset ====================== */
errorReg = setjmp(errorJump);
setupAllSignals();
reset();
initStacks();
if(errorReg && !isNil((CELL*)errorEvent->contents) )
executeSymbol(errorEvent, NULL, NULL);
#ifdef READLINE
rl_readline_name = "newlisp";
rl_attempted_completion_function = (char ** (*) (const char *, int, int))newlisp_completion;
#if defined(LINUX) || defined(_BSD)
/* in Bash .inputrc put 'set blink-matching-paren on' */
rl_set_paren_blink_timeout(300000); /* 300 ms */
#endif
#endif
while(TRUE)
{
cleanupResults(resultStack);
if(isTTY)
{
cmd = getCommandLine(FALSE, NULL);
executeCommandLine(cmd, OUT_CONSOLE, &cmdStream);
free(cmd);
continue;
}
if(IOchannel != stdin || forcePromptMode)
varPrintf(OUT_CONSOLE, "%s", prompt());
/* daemon mode timeout if nothing read after accepting connection */
if(connectionTimeout && IOchannel && daemonMode)
{
#ifdef WINDOWS
if(IOchannelIsSocketStream)
if(wait_ready(getSocket(IOchannel), connectionTimeout, 0) == 0)
#else
if(wait_ready(fileno(IOchannel), connectionTimeout, 0) == 0)
#endif
{
fclose(IOchannel);
setupServer(1);
continue;
}
}
if(IOchannel == NULL || fgets(command, MAX_COMMAND_LINE - 1, IOchannel) == NULL)
{
if(!daemonMode) exit(1);
if(IOchannel != NULL) fclose(IOchannel);
setupServer(1);
continue;
}
executeCommandLine(command, OUT_CONSOLE, &cmdStream);
}
#ifndef WINDOWS
return 0;
#endif
}
#endif /* not LIBRARY */
#ifdef READLINE
char * command_generator(char * text, int state)
{
static int list_index, len, clen;
char * name;
if (!state)
{
list_index = 0;
len = strlen (text);
}
while((name = primitive[list_index].name))
{
list_index++;
if (strncmp (name, text, len) == 0)
{
clen = strlen(name) + 1;
return(strncpy(malloc(clen), name, clen));
}
}
return ((char *)NULL);
}
char ** completion_matches(const char * text, char * (*commands)(const char *, int));
char ** newlisp_completion (char * text, int start, int end)
{
return(completion_matches(text, (char * (*) (const char *, int) )command_generator));
}
#endif /* READLINE */
char * getCommandLine(int batchMode, int * length)
{
char * cmd;
int len;
#ifndef READLINE
if(!batchMode) varPrintf(OUT_CONSOLE, "%s", prompt());
cmd = calloc(MAX_COMMAND_LINE + 4, 1);
if(fgets(cmd, MAX_COMMAND_LINE - 1, IOchannel) == NULL)
{
puts("");
exit(0);
}
len = strlen(cmd);
/* cut off line terminators left by fgets */
*(cmd + len - LINE_FEED_LEN) = 0;
len -= LINE_FEED_LEN; /* v.10.6.2 */
#else /* READLINE */
int errnoSave = errno;
if((cmd = readline(batchMode ? "" : prompt())) == NULL)
{
puts("");
exit(0);
}
errno = errnoSave; /* reset errno, set by readline() */
len = strlen(cmd);
if(len > 0)
add_history(cmd);
#endif
if(length != NULL) *length = len;
return(cmd);
}
#ifndef LIBRARY
void printHelpText(void)
{
varPrintf(OUT_CONSOLE, copyright,
"usage: newlisp [file | url ...] [options ...] [file | url ...]\n\noptions:");
varPrintf(OUT_CONSOLE,
"%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n\n",
" -h this help",
" -n no init.lsp (must be first)",
" -x