aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jim-aio.c2
-rw-r--r--jim-eventloop.h10
-rw-r--r--jim-exec.c928
-rw-r--r--jim-file.c677
-rw-r--r--jim-subcmd.c194
-rw-r--r--jim-subcmd.h68
-rw-r--r--jim.h300
-rw-r--r--jimsh.c4
8 files changed, 2003 insertions, 180 deletions
diff --git a/jim-aio.c b/jim-aio.c
index 73df769..1f55441 100644
--- a/jim-aio.c
+++ b/jim-aio.c
@@ -712,7 +712,7 @@ static int JimAioAcceptHelper(Jim_Interp *interp, AioFile *serv_af )
return JIM_OK;
}
-DLLEXPORT int
+int
Jim_AioInit(Jim_Interp *interp)
{
if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG) != JIM_OK)
diff --git a/jim-eventloop.h b/jim-eventloop.h
index 05e8c59..39be1c2 100644
--- a/jim-eventloop.h
+++ b/jim-eventloop.h
@@ -63,17 +63,17 @@ typedef void Jim_EventFinalizerProc(Jim_Interp *interp, void *clientData);
#define JIM_EVENT_EXCEPTION 4
#define JIM_EVENT_FEOF 8
-JIM_EXPORT void JIM_API(Jim_CreateFileHandler) (Jim_Interp *interp,
+JIM_EXPORT void Jim_CreateFileHandler (Jim_Interp *interp,
void *handle, int mask,
Jim_FileProc *proc, void *clientData,
Jim_EventFinalizerProc *finalizerProc);
-JIM_EXPORT void JIM_API(Jim_DeleteFileHandler) (Jim_Interp *interp,
+JIM_EXPORT void Jim_DeleteFileHandler (Jim_Interp *interp,
void *handle);
-JIM_EXPORT jim_wide JIM_API(Jim_CreateTimeHandler) (Jim_Interp *interp,
+JIM_EXPORT jim_wide Jim_CreateTimeHandler (Jim_Interp *interp,
jim_wide milliseconds,
Jim_TimeProc *proc, void *clientData,
Jim_EventFinalizerProc *finalizerProc);
-JIM_EXPORT jim_wide JIM_API(Jim_DeleteTimeHandler) (Jim_Interp *interp, jim_wide id);
-JIM_EXPORT int JIM_API(Jim_ProcessEvents) (Jim_Interp *interp, int flags);
+JIM_EXPORT jim_wide Jim_DeleteTimeHandler (Jim_Interp *interp, jim_wide id);
+JIM_EXPORT int Jim_ProcessEvents (Jim_Interp *interp, int flags);
#endif /* __JIM_EVENTLOOP_H__ */
diff --git a/jim-exec.c b/jim-exec.c
new file mode 100644
index 0000000..4ed70a9
--- /dev/null
+++ b/jim-exec.c
@@ -0,0 +1,928 @@
+/*
+ * (c) 2008 Steve Bennett <steveb@workware.net.au>
+ *
+ * Implements the exec command for Jim
+ *
+ * Based on code originally from Tcl 6.7:
+ *
+ * Copyright 1987-1991 Regents of the University of California
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies. The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <string.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "jim.h"
+#include "jim-subcmd.h"
+
+static int Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
+ int **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr);
+static void Jim_DetachPids(Jim_Interp *interp, int numPids, int *pidPtr);
+static int
+Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int errorId);
+
+static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
+{
+ Jim_SetResultString(interp, "", 0);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), msg, ": ", strerror(errno), NULL);
+}
+
+/**
+ * Read from 'fd' and append the data to strObj
+ */
+static int append_fd_to_string(Jim_Interp *interp, int fd, Jim_Obj *strObj)
+{
+ while (1) {
+ char buffer[256];
+ int count;
+
+ count = read(fd, buffer, sizeof(buffer));
+
+ if (count == 0) {
+ return JIM_OK;
+ }
+ if (count < 0) {
+ return JIM_ERR;
+ }
+ Jim_AppendString(interp, strObj, buffer, count);
+ }
+}
+
+static int
+Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int outputId; /* File id for output pipe. -1
+ * means command overrode. */
+ int errorId; /* File id for temporary file
+ * containing error output. */
+ int *pidPtr;
+ int numPids, result;
+
+ /*
+ * See if the command is to be run in background; if so, create
+ * the command, detach it, and return.
+ */
+ if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
+ argc--;
+ numPids = Jim_CreatePipeline(interp, argc-1, argv+1, &pidPtr, NULL, NULL, NULL);
+ if (numPids < 0) {
+ return JIM_ERR;
+ }
+ Jim_DetachPids(interp, numPids, pidPtr);
+ Jim_Free(pidPtr);
+ return JIM_OK;
+ }
+
+ /*
+ * Create the command's pipeline.
+ */
+ numPids = Jim_CreatePipeline(interp, argc-1, argv+1, &pidPtr, (int *) NULL, &outputId, &errorId);
+ if (numPids < 0) {
+ return JIM_ERR;
+ }
+
+ /*
+ * Read the child's output (if any) and put it into the result.
+ */
+ Jim_SetResultString(interp, "", 0);
+
+ result = JIM_OK;
+ if (outputId != -1) {
+ result = append_fd_to_string(interp, outputId, Jim_GetResult(interp));
+ if (result < 0) {
+ Jim_SetResultErrno(interp, "error reading from output pipe");
+ }
+ }
+ close(outputId);
+
+ if (Jim_CleanupChildren(interp, numPids, pidPtr, errorId) != JIM_OK) {
+ result = JIM_ERR;
+ }
+ return result;
+}
+
+/*
+ * Data structures of the following type are used by Jim_Fork and
+ * Jim_WaitPids to keep track of child processes.
+ */
+
+typedef struct {
+ int pid; /* Process id of child. */
+ int status; /* Status returned when child exited or suspended. */
+ int flags; /* Various flag bits; see below for definitions. */
+} WaitInfo;
+
+/*
+ * Flag bits in WaitInfo structures:
+ *
+ * WI_READY - Non-zero means process has exited or
+ * suspended since it was forked or last
+ * returned by Jim_WaitPids.
+ * WI_DETACHED - Non-zero means no-one cares about the
+ * process anymore. Ignore it until it
+ * exits, then forget about it.
+ */
+
+#define WI_READY 1
+#define WI_DETACHED 2
+
+static WaitInfo *waitTable = NULL;
+static int waitTableSize = 0; /* Total number of entries available in waitTable. */
+static int waitTableUsed = 0; /* Number of entries in waitTable that
+ * are actually in use right now. Active
+ * entries are always at the beginning
+ * of the table. */
+#define WAIT_TABLE_GROW_BY 4
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Jim_Fork --
+ *
+ * Create a new process using the vfork system call, and keep
+ * track of it for "safe" waiting with Jim_WaitPids.
+ *
+ * Results:
+ * The return value is the value returned by the vfork system
+ * call (0 means child, > 0 means parent (value is child id),
+ * < 0 means error).
+ *
+ * Side effects:
+ * A new process is created, and an entry is added to an internal
+ * table of child processes if the process is created successfully.
+ *
+ *----------------------------------------------------------------------
+ */
+int
+Jim_Fork(void)
+{
+ WaitInfo *waitPtr;
+ pid_t pid;
+
+ /*
+ * Disable SIGPIPE signals: if they were allowed, this process
+ * might go away unexpectedly if children misbehave. This code
+ * can potentially interfere with other application code that
+ * expects to handle SIGPIPEs; what's really needed is an
+ * arbiter for signals to allow them to be "shared".
+ */
+ if (waitTable == NULL) {
+ (void) signal(SIGPIPE, SIG_IGN);
+ }
+
+ /*
+ * Enlarge the wait table if there isn't enough space for a new
+ * entry.
+ */
+ if (waitTableUsed == waitTableSize) {
+ waitTableSize += WAIT_TABLE_GROW_BY;
+ waitTable = (WaitInfo *)realloc(waitTable, waitTableSize * sizeof(WaitInfo));
+ }
+
+ /*
+ * Make a new process and enter it into the table if the fork
+ * is successful.
+ */
+
+ waitPtr = &waitTable[waitTableUsed];
+ pid = fork();
+ if (pid > 0) {
+ waitPtr->pid = pid;
+ waitPtr->flags = 0;
+ waitTableUsed++;
+ }
+ return pid;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Jim_WaitPids --
+ *
+ * This procedure is used to wait for one or more processes created
+ * by Jim_Fork to exit or suspend. It records information about
+ * all processes that exit or suspend, even those not waited for,
+ * so that later waits for them will be able to get the status
+ * information.
+ *
+ * Results:
+ * -1 is returned if there is an error in the wait kernel call.
+ * Otherwise the pid of an exited/suspended process from *pidPtr
+ * is returned and *statusPtr is set to the status value returned
+ * by the wait kernel call.
+ *
+ * Side effects:
+ * Doesn't return until one of the pids at *pidPtr exits or suspends.
+ *
+ *----------------------------------------------------------------------
+ */
+int
+Jim_WaitPids(int numPids, int *pidPtr, int *statusPtr)
+{
+ int i, count, pid;
+ WaitInfo *waitPtr;
+ int anyProcesses;
+ int status;
+
+ while (1) {
+ /*
+ * Scan the table of child processes to see if one of the
+ * specified children has already exited or suspended. If so,
+ * remove it from the table and return its status.
+ */
+
+ anyProcesses = 0;
+ for (waitPtr = waitTable, count = waitTableUsed; count > 0; waitPtr++, count--) {
+ for (i = 0; i < numPids; i++) {
+ if (pidPtr[i] != waitPtr->pid) {
+ continue;
+ }
+ anyProcesses = 1;
+ if (waitPtr->flags & WI_READY) {
+ *statusPtr = *((int *) &waitPtr->status);
+ pid = waitPtr->pid;
+ if (WIFEXITED(waitPtr->status) || WIFSIGNALED(waitPtr->status)) {
+ *waitPtr = waitTable[waitTableUsed-1];
+ waitTableUsed--;
+ }
+ else {
+ waitPtr->flags &= ~WI_READY;
+ }
+ return pid;
+ }
+ }
+ }
+
+ /*
+ * Make sure that the caller at least specified one valid
+ * process to wait for.
+ */
+ if (!anyProcesses) {
+ errno = ECHILD;
+ return -1;
+ }
+
+ /*
+ * Wait for a process to exit or suspend, then update its
+ * entry in the table and go back to the beginning of the
+ * loop to see if it's one of the desired processes.
+ */
+
+ pid = wait(&status);
+ if (pid < 0) {
+ return pid;
+ }
+ for (waitPtr = waitTable, count = waitTableUsed; ; waitPtr++, count--) {
+ if (count == 0) {
+ break; /* Ignore unknown processes. */
+ }
+ if (pid != waitPtr->pid) {
+ continue;
+ }
+
+ /*
+ * If the process has been detached, then ignore anything
+ * other than an exit, and drop the entry on exit.
+ */
+ if (waitPtr->flags & WI_DETACHED) {
+ if (WIFEXITED(status) || WIFSIGNALED(status)) {
+ *waitPtr = waitTable[waitTableUsed-1];
+ waitTableUsed--;
+ }
+ } else {
+ waitPtr->status = status;
+ waitPtr->flags |= WI_READY;
+ }
+ break;
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Jim_DetachPids --
+ *
+ * This procedure is called to indicate that one or more child
+ * processes have been placed in background and are no longer
+ * cared about. They should be ignored in future calls to
+ * Jim_WaitPids.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void Jim_DetachPids(Jim_Interp *interp, int numPids, int *pidPtr)
+{
+ WaitInfo *waitPtr;
+ int i, count, pid;
+
+ for (i = 0; i < numPids; i++) {
+ pid = pidPtr[i];
+ for (waitPtr = waitTable, count = waitTableUsed; count > 0; waitPtr++, count--) {
+ if (pid != waitPtr->pid) {
+ continue;
+ }
+
+ /*
+ * If the process has already exited then destroy its
+ * table entry now.
+ */
+
+ if ((waitPtr->flags & WI_READY) && (WIFEXITED(waitPtr->status) || WIFSIGNALED(waitPtr->status))) {
+ *waitPtr = waitTable[waitTableUsed-1];
+ waitTableUsed--;
+ } else {
+ waitPtr->flags |= WI_DETACHED;
+ }
+ goto nextPid;
+ }
+ Jim_Panic(interp, "Jim_Detach couldn't find process");
+
+ nextPid:
+ continue;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Jim_CreatePipeline --
+ *
+ * Given an argc/argv array, instantiate a pipeline of processes
+ * as described by the argv.
+ *
+ * Results:
+ * The return value is a count of the number of new processes
+ * created, or -1 if an error occurred while creating the pipeline.
+ * *pidArrayPtr is filled in with the address of a dynamically
+ * allocated array giving the ids of all of the processes. It
+ * is up to the caller to free this array when it isn't needed
+ * anymore. If inPipePtr is non-NULL, *inPipePtr is filled in
+ * with the file id for the input pipe for the pipeline (if any):
+ * the caller must eventually close this file. If outPipePtr
+ * isn't NULL, then *outPipePtr is filled in with the file id
+ * for the output pipe from the pipeline: the caller must close
+ * this file. If errFilePtr isn't NULL, then *errFilePtr is filled
+ * with a file id that may be used to read error output after the
+ * pipeline completes.
+ *
+ * Side effects:
+ * Processes and pipes are created.
+ *
+ *----------------------------------------------------------------------
+ */
+static int
+Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr)
+{
+ int *pidPtr = NULL; /* Points to malloc-ed array holding all
+ * the pids of child processes. */
+ int numPids = 0; /* Actual number of processes that exist
+ * at *pidPtr right now. */
+ int cmdCount; /* Count of number of distinct commands
+ * found in argc/argv. */
+ const char *input = NULL; /* Describes input for pipeline, depending
+ * on "inputFile". NULL means take input
+ * from stdin/pipe. */
+
+#define FILE_NAME 0 /* input/output: filename */
+#define FILE_APPEND 1 /* output only: filename, append */
+#define FILE_HANDLE 2 /* input/output: filehandle */
+#define FILE_TEXT 3 /* input only: input is actual text */
+
+ int inputFile = FILE_NAME; /* 1 means input is name of input file.
+ * 2 means input is filehandle name.
+ * 0 means input holds actual
+ * text to be input to command. */
+
+ int outputFile = FILE_NAME; /* 0 means output is the name of output file.
+ * 1 means output is the name of output file, and append.
+ * 2 means output is filehandle name.
+ * All this is ignored if output is NULL
+ */
+ int errorFile = FILE_NAME; /* 0 means error is the name of error file.
+ * 1 means error is the name of error file, and append.
+ * 2 means error is filehandle name.
+ * All this is ignored if error is NULL
+ */
+ const char *output = NULL; /* Holds name of output file to pipe to,
+ * or NULL if output goes to stdout/pipe. */
+ const char *error = NULL; /* Holds name of stderr file to pipe to,
+ * or NULL if stderr goes to stderr/pipe. */
+ int inputId = -1; /* Readable file id input to current command in
+ * pipeline (could be file or pipe). -1
+ * means use stdin. */
+ int outputId = -1; /* Writable file id for output from current
+ * command in pipeline (could be file or pipe).
+ * -1 means use stdout. */
+ int errorId = -1; /* Writable file id for all standard error
+ * output from all commands in pipeline. -1
+ * means use stderr. */
+ int lastOutputId = -1; /* Write file id for output from last command
+ * in pipeline (could be file or pipe).
+ * -1 means use stdout. */
+ int pipeIds[2]; /* File ids for pipe that's being created. */
+ int firstArg, lastArg; /* Indexes of first and last arguments in
+ * current command. */
+ int lastBar;
+ char *execName;
+ int i, pid;
+
+ /* Holds the args which will be used to exec */
+ char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
+ int arg_count = 0;
+
+ if (inPipePtr != NULL) {
+ *inPipePtr = -1;
+ }
+ if (outPipePtr != NULL) {
+ *outPipePtr = -1;
+ }
+ if (errFilePtr != NULL) {
+ *errFilePtr = -1;
+ }
+ pipeIds[0] = pipeIds[1] = -1;
+
+ /*
+ * First, scan through all the arguments to figure out the structure
+ * of the pipeline. Count the number of distinct processes (it's the
+ * number of "|" arguments). If there are "<", "<<", or ">" arguments
+ * then make note of input and output redirection and remove these
+ * arguments and the arguments that follow them.
+ */
+ cmdCount = 1;
+ lastBar = -1;
+ for (i = 0; i < argc; i++) {
+ const char *arg = Jim_GetString(argv[i], NULL);
+
+ if (arg[0] == '<') {
+ input = arg + 1;
+ if (*input == '<') {
+ inputFile = FILE_TEXT;
+ input++;
+ }
+ else if (*input == '@') {
+ inputFile = FILE_HANDLE;
+ input++;
+ }
+
+ if (!*input) {
+ input = Jim_GetString(argv[++i], NULL);
+ }
+ }
+ else if (arg[0] == '>') {
+ output = arg + 1;
+ if (*output == '@') {
+ outputFile = FILE_HANDLE;
+ output++;
+ }
+ else if (*output == '>') {
+ outputFile = FILE_APPEND;
+ output++;
+ }
+ if (!*output) {
+ output = Jim_GetString(argv[++i], NULL);
+ }
+ }
+ else if (arg[0] == '2' && arg[1] == '>') {
+ error = arg + 2;
+ if (*error == '@') {
+ errorFile = FILE_HANDLE;
+ error++;
+ }
+ else if (*error == '>') {
+ errorFile = FILE_APPEND;
+ error++;
+ }
+ if (!*error) {
+ error = Jim_GetString(argv[++i], NULL);
+ }
+ }
+ else {
+ if (arg[0] == '|' && arg[1] == 0) {
+ if (i == lastBar + 1 || i == argc - 1) {
+ Jim_SetResultString(interp, "illegal use of | in command", -1);
+ Jim_Free(arg_array);
+ return -1;
+ }
+ lastBar = i;
+ cmdCount++;
+ }
+ /* Either | or a "normal" arg, so store it in the arg array */
+ arg_array[arg_count++] = (char *)arg;
+ continue;
+ }
+
+ if (i > argc) {
+ Jim_SetResultString(interp, "", 0);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "can't specify \"", arg, "\" as last word in command", NULL);
+ Jim_Free(arg_array);
+ return -1;
+ }
+ }
+
+ if (arg_count == 0) {
+ Jim_SetResultString(interp, "didn't specify command to execute", -1);
+ Jim_Free(arg_array);
+ return -1;
+ }
+
+ /*
+ * Set up the redirected input source for the pipeline, if
+ * so requested.
+ */
+ if (input != NULL) {
+ if (inputFile == FILE_TEXT) {
+ /*
+ * Immediate data in command. Create temporary file and
+ * put data into file.
+ */
+
+#define TMP_STDIN_NAME "/tmp/tcl.in.XXXXXX"
+ char inName[sizeof(TMP_STDIN_NAME) + 1];
+ int length;
+
+ strcpy(inName, TMP_STDIN_NAME);
+ inputId = mkstemp(inName);
+ if (inputId < 0) {
+ Jim_SetResultErrno(interp, "couldn't create input file for command");
+ goto error;
+ }
+ length = strlen(input);
+ if (write(inputId, input, length) != length) {
+ Jim_SetResultErrno(interp, "couldn't write file input for command");
+ goto error;
+ }
+ if (lseek(inputId, 0L, SEEK_SET) == -1 || unlink(inName) == -1) {
+ Jim_SetResultErrno(interp, "couldn't reset or remove input file for command");
+ goto error;
+ }
+ }
+ else if (inputFile == FILE_HANDLE) {
+ /* Should be a file descriptor */
+ /* REVISIT: Validate fd */
+ inputId = dup(atoi(input));
+ }
+ else {
+ /*
+ * File redirection. Just open the file.
+ */
+ inputId = open(input, O_RDONLY, 0);
+ if (inputId < 0) {
+ Jim_SetResultString(interp, "", 0);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "couldn't read file \"", input, "\": ", strerror(errno), NULL);
+ goto error;
+ }
+ }
+ }
+ else if (inPipePtr != NULL) {
+ if (pipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create input pipe for command");
+ goto error;
+ }
+ inputId = pipeIds[0];
+ *inPipePtr = pipeIds[1];
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+
+ /*
+ * Set up the redirected output sink for the pipeline from one
+ * of two places, if requested.
+ */
+ if (output != NULL) {
+ if (outputFile == FILE_HANDLE) {
+ /* Should be a file descriptor */
+ /* REVISIT: Validate fd */
+ lastOutputId = dup(atoi(output));
+
+ /* REVISIT: ideally should flush output first */
+ /* Will aio.fd do this? */
+ }
+ else {
+ /*
+ * Output is to go to a file.
+ */
+ int mode = O_WRONLY|O_CREAT|O_TRUNC;
+
+ if (outputFile == FILE_APPEND) {
+ mode = O_WRONLY|O_CREAT|O_APPEND;
+ }
+
+ lastOutputId = open(output, mode, 0666);
+ if (lastOutputId < 0) {
+ Jim_SetResultString(interp, "", 0);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "couldn't write file \"", output, "\": ", strerror(errno), NULL);
+ goto error;
+ }
+ }
+ }
+ else if (outPipePtr != NULL) {
+ /*
+ * Output is to go to a pipe.
+ */
+ if (pipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create output pipe");
+ goto error;
+ }
+ lastOutputId = pipeIds[1];
+ *outPipePtr = pipeIds[0];
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+
+ /* If we are redirecting stderr with 2>filename or 2>@fileId, then we ignore errFilePtr */
+ if (error != NULL) {
+ if (errorFile == FILE_HANDLE) {
+ /* Should be a file descriptor */
+ /* REVISIT: Validate fd */
+ errorId = dup(atoi(error));
+
+ /* REVISIT: ideally should flush output first */
+ /* Will aio.fd do this? */
+ }
+ else {
+ /*
+ * Output is to go to a file.
+ */
+ int mode = O_WRONLY|O_CREAT|O_TRUNC;
+
+ if (errorFile == FILE_APPEND) {
+ mode = O_WRONLY|O_CREAT|O_APPEND;
+ }
+
+ errorId = open(error, mode, 0666);
+ if (errorId < 0) {
+ Jim_SetResultString(interp, "", 0);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "couldn't write file \"", error, "\": ", strerror(errno), NULL);
+ }
+ }
+ }
+ else if (errFilePtr != NULL) {
+ /*
+ * Set up the standard error output sink for the pipeline, if
+ * requested. Use a temporary file which is opened, then deleted.
+ * Could potentially just use pipe, but if it filled up it could
+ * cause the pipeline to deadlock: we'd be waiting for processes
+ * to complete before reading stderr, and processes couldn't complete
+ * because stderr was backed up.
+ */
+
+ #define TMP_STDERR_NAME "/tmp/tcl.err.XXXXXX"
+ char errName[sizeof(TMP_STDERR_NAME) + 1];
+
+ strcpy(errName, TMP_STDERR_NAME);
+ errorId = mkstemp(errName);
+ if (errorId < 0) {
+ errFileError:
+ Jim_SetResultErrno(interp, "couldn't create error file for command");
+ goto error;
+ }
+ *errFilePtr = open(errName, O_RDONLY, 0);
+ if (*errFilePtr < 0) {
+ goto errFileError;
+ }
+ if (unlink(errName) == -1) {
+ Jim_SetResultErrno(interp, "couldn't remove error file for command");
+ goto error;
+ }
+ }
+
+ /*
+ * Scan through the argc array, forking off a process for each
+ * group of arguments between "|" arguments.
+ */
+
+ pidPtr = (int *)Jim_Alloc(cmdCount * sizeof(*pidPtr));
+ for (i = 0; i < numPids; i++) {
+ pidPtr[i] = -1;
+ }
+ for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg+1) {
+ for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
+ if (strcmp(arg_array[lastArg], "|") == 0) {
+ break;
+ }
+ }
+ /* Replace | with NULL for execv() */
+ arg_array[lastArg] = NULL;
+ if (lastArg == arg_count) {
+ outputId = lastOutputId;
+ }
+ else {
+ if (pipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create pipe");
+ goto error;
+ }
+ outputId = pipeIds[1];
+ }
+ execName = arg_array[firstArg];
+ pid = Jim_Fork();
+ if (pid == -1) {
+ Jim_SetResultErrno(interp, "couldn't fork child process");
+ goto error;
+ }
+ if (pid == 0) {
+ char errSpace[200];
+
+ if ((inputId != -1 && dup2(inputId, 0) == -1)
+ || (outputId != -1 && dup2(outputId, 1) == -1)
+ || (errorId != -1 &&(dup2(errorId, 2) == -1))) {
+
+ static const char err[] = "forked process couldn't set up input/output\n";
+ write(errorId < 0 ? 2 : errorId, err, strlen(err));
+ _exit(1);
+ }
+ for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) {
+ close(i);
+ }
+ execvp(execName, &arg_array[firstArg]);
+ sprintf(errSpace, "couldn't find \"%.150s\" to execute\n", arg_array[firstArg]);
+ write(2, errSpace, strlen(errSpace));
+ _exit(1);
+ }
+ else {
+ pidPtr[numPids] = pid;
+ }
+
+ /*
+ * Close off our copies of file descriptors that were set up for
+ * this child, then set up the input for the next child.
+ */
+
+ if (inputId != -1) {
+ close(inputId);
+ }
+ if (outputId != -1) {
+ close(outputId);
+ }
+ inputId = pipeIds[0];
+ pipeIds[0] = pipeIds[1] = -1;
+ }
+ *pidArrayPtr = pidPtr;
+
+ /*
+ * All done. Cleanup open files lying around and then return.
+ */
+
+ cleanup:
+ if (inputId != -1) {
+ close(inputId);
+ }
+ if (lastOutputId != -1) {
+ close(lastOutputId);
+ }
+ if (errorId != -1) {
+ close(errorId);
+ }
+ Jim_Free(arg_array);
+
+ return numPids;
+
+ /*
+ * An error occurred. There could have been extra files open, such
+ * as pipes between children. Clean them all up. Detach any child
+ * processes that have been created.
+ */
+
+ error:
+ if ((inPipePtr != NULL) && (*inPipePtr != -1)) {
+ close(*inPipePtr);
+ *inPipePtr = -1;
+ }
+ if ((outPipePtr != NULL) && (*outPipePtr != -1)) {
+ close(*outPipePtr);
+ *outPipePtr = -1;
+ }
+ if ((errFilePtr != NULL) && (*errFilePtr != -1)) {
+ close(*errFilePtr);
+ *errFilePtr = -1;
+ }
+ if (pipeIds[0] != -1) {
+ close(pipeIds[0]);
+ }
+ if (pipeIds[1] != -1) {
+ close(pipeIds[1]);
+ }
+ if (pidPtr != NULL) {
+ for (i = 0; i < numPids; i++) {
+ if (pidPtr[i] != -1) {
+ Jim_DetachPids(interp, 1, &pidPtr[i]);
+ }
+ }
+ Jim_Free(pidPtr);
+ }
+ numPids = -1;
+ goto cleanup;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * CleanupChildren --
+ *
+ * This is a utility procedure used to wait for child processes
+ * to exit, record information about abnormal exits, and then
+ * collect any stderr output generated by them.
+ *
+ * Results:
+ * The return value is a standard Tcl result. If anything at
+ * weird happened with the child processes, JIM_ERROR is returned
+ * and a message is left in interp->result.
+ *
+ * Side effects:
+ * If the last character of interp->result is a newline, then it
+ * is removed. File errorId gets closed, and pidPtr is freed
+ * back to the storage allocator.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int
+Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int errorId)
+{
+ int result = JIM_OK;
+ int i, pid;
+ int waitStatus;
+ int len;
+ const char *p;
+
+ for (i = 0; i < numPids; i++) {
+ pid = Jim_WaitPids(1, &pidPtr[i], (int *) &waitStatus);
+ if (pid == -1) {
+ /* This can happen if the process was already reaped, so just ignore it */
+ continue;
+ }
+
+ /*
+ * Create error messages for unusual process exits. An
+ * extra newline gets appended to each error message, but
+ * it gets removed below (in the same fashion that an
+ * extra newline in the command's output is removed).
+ */
+
+ if (!WIFEXITED(waitStatus) || (WEXITSTATUS(waitStatus) != 0)) {
+ result = JIM_ERR;
+ if (WIFEXITED(waitStatus)) {
+ /* Nothing */
+ } else if (WIFSIGNALED(waitStatus)) {
+ /* REVISIT: Name the signal */
+ Jim_SetResultString(interp, "child killed by signal", -1);
+ } else if (WIFSTOPPED(waitStatus)) {
+ Jim_SetResultString(interp, "child suspended", -1);
+ }
+ }
+ }
+ Jim_Free(pidPtr);
+
+ /*
+ * Read the standard error file. If there's anything there,
+ * then return an error and add the file's contents to the result
+ * string.
+ */
+
+ if (errorId >= 0) {
+ if (errorId >= 0) {
+ result = append_fd_to_string(interp, errorId, Jim_GetResult(interp));
+ if (result < 0) {
+ Jim_SetResultErrno(interp, "error reading from stderr output file");
+ }
+ }
+ }
+
+ /*
+ * If the last character of interp->result is a newline, then remove
+ * the newline character (the newline would just confuse things).
+ *
+ * Note: Ideally we could do this by just reducing the length of stringrep
+ * by 1, but there is not API for this :-(
+ */
+
+ p = Jim_GetString(Jim_GetResult(interp), &len);
+ if (len > 0 && p[len - 1] == '\n') {
+ Jim_SetResultString(interp, p, len - 1);
+ }
+
+ return result;
+}
+
+int Jim_ExecInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
+ return JIM_OK;
+}
diff --git a/jim-file.c b/jim-file.c
new file mode 100644
index 0000000..beb7147
--- /dev/null
+++ b/jim-file.c
@@ -0,0 +1,677 @@
+/*
+ * (c) 2008 Steve Bennett <steveb@workware.net.au>
+ *
+ * Implements the file command for jim
+ *
+ * The FreeBSD license
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ * Based on code originally from Tcl 6.7:
+ *
+ * Copyright 1987-1991 Regents of the University of California
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies. The University of California
+ * makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without
+ * express or implied warranty.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+
+#include "jim.h"
+#include "jim-subcmd.h"
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetFileType --
+ *
+ * Given a mode word, returns a string identifying the type of a
+ * file.
+ *
+ * Results:
+ * A static text string giving the file type from mode.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static const char *GetFileType(int mode)
+{
+ if (S_ISREG(mode)) {
+ return "file";
+ } else if (S_ISDIR(mode)) {
+ return "directory";
+ } else if (S_ISCHR(mode)) {
+ return "characterSpecial";
+ } else if (S_ISBLK(mode)) {
+ return "blockSpecial";
+ } else if (S_ISFIFO(mode)) {
+ return "fifo";
+ } else if (S_ISLNK(mode)) {
+ return "link";
+ } else if (S_ISSOCK(mode)) {
+ return "socket";
+ }
+ return "unknown";
+}
+
+static void Jim_SetIntResult(Jim_Interp *interp, jim_wide wide)
+{
+ Jim_SetResult(interp, Jim_NewIntObj(interp, wide));
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * StoreStatData --
+ *
+ * This is a utility procedure that breaks out the fields of a
+ * "stat" structure and stores them in textual form into the
+ * elements of an associative array.
+ *
+ * Results:
+ * Returns a standard Tcl return value. If an error occurs then
+ * a message is left in interp->result.
+ *
+ * Side effects:
+ * Elements of the associative array given by "varName" are modified.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static int set_array_int_value(Jim_Interp *interp, Jim_Obj *container, const char *key, jim_wide value)
+{
+ Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1);
+ Jim_Obj *valobj = Jim_NewWideObj(interp, value);
+
+ if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj) != JIM_OK) {
+ Jim_FreeObj(interp, nameobj);
+ Jim_FreeObj(interp, valobj);
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int set_array_string_value(Jim_Interp *interp, Jim_Obj *container, const char *key, const char *value)
+{
+ Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1);
+ Jim_Obj *valobj = Jim_NewStringObj(interp, value, -1);
+
+ if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj) != JIM_OK) {
+ Jim_FreeObj(interp, nameobj);
+ Jim_FreeObj(interp, valobj);
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int
+StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb)
+{
+ if (set_array_int_value(interp, varName, "dev", sb->st_dev) != JIM_OK) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "can't set \"", Jim_GetString(varName, NULL), "(dev)\": variable isn't array", NULL);
+ return JIM_ERR;
+ }
+ set_array_int_value(interp, varName, "ino", sb->st_ino);
+ set_array_int_value(interp, varName, "mode", sb->st_mode);
+ set_array_int_value(interp, varName, "nlink", sb->st_nlink);
+ set_array_int_value(interp, varName, "uid", sb->st_uid);
+ set_array_int_value(interp, varName, "gid", sb->st_gid);
+ set_array_int_value(interp, varName, "size", sb->st_size);
+ set_array_int_value(interp, varName, "atime", sb->st_atime);
+ set_array_int_value(interp, varName, "mtime", sb->st_mtime);
+ set_array_int_value(interp, varName, "ctime", sb->st_ctime);
+ set_array_string_value(interp, varName, "type", GetFileType((int) sb->st_mode));
+
+ /* And also return the value */
+ Jim_SetResult(interp, Jim_GetVariable(interp, varName, 0));
+
+ return JIM_OK;
+}
+
+static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_GetString(argv[0], NULL);
+ const char *p = strrchr(path, '/');
+ if (!p) {
+ Jim_SetResultString(interp, ".", -1);
+ }
+ else if (p == path) {
+ Jim_SetResultString(interp, "/", -1);
+ }
+ else {
+ Jim_SetResultString(interp, path, p - path);
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_GetString(argv[0], NULL);
+ const char *lastSlash = strrchr(path, '/');
+ const char *p = strrchr(path, '.');
+ if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
+ Jim_SetResult(interp, argv[0]);
+ }
+ else {
+ Jim_SetResultString(interp, path, p - path);
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_GetString(argv[0], NULL);
+ const char *lastSlash = strrchr(path, '/');
+ const char *p = strrchr(path, '.');
+
+ if (p == NULL || (lastSlash != NULL && lastSlash >= p)) {
+ p = "";
+ }
+ Jim_SetResultString(interp, p, -1);
+ return JIM_OK;
+}
+
+static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_GetString(argv[0], NULL);
+ const char *lastSlash = strrchr(path, '/');
+
+ if (lastSlash) {
+ Jim_SetResultString(interp, lastSlash + 1, -1);
+ }
+ else {
+ Jim_SetResult(interp, argv[0]);
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_GetString(argv[0], NULL);
+ char *newname = Jim_Alloc(MAXPATHLEN + 1);
+
+ if (realpath(path, newname)) {
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1));
+ }
+ else {
+ Jim_Free(newname);
+ Jim_SetResult(interp, argv[0]);
+ }
+ return JIM_OK;
+}
+
+static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode)
+{
+ const char *path = Jim_GetString(filename, NULL);
+ int rc = access(path, mode);
+
+ Jim_SetResult(interp, Jim_NewIntObj(interp, rc != -1));
+
+ return JIM_OK;
+}
+
+static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], R_OK);
+}
+
+static int file_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], W_OK);
+}
+
+static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], X_OK);
+}
+
+static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], F_OK);
+}
+
+static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ while (argc--) {
+ const char *path = Jim_GetString(argv[0], NULL);
+ if (unlink(path) == -1 && errno != ENOENT) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "couldn't delete \"", path, "\"", NULL);
+ return JIM_ERR;
+ }
+ argv++;
+ }
+ return JIM_OK;
+}
+
+static int mkdir_all(const char *path)
+{
+ /* REVISIT: create intermediate dirs if necessary */
+ mkdir(path, 0755);
+ return 0;
+}
+
+static int file_cmd_mkdir(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ while (argc--) {
+ mkdir_all(Jim_GetString(argv[0], NULL));
+ argv++;
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *source = Jim_GetString(argv[0], NULL);
+ const char *dest;
+ int force = 0;
+
+ if (argc == 3) {
+ if (strcmp(source, "-force") != 0) {
+ return -1;
+ }
+ force++;
+ source = Jim_GetString(argv[1], NULL);
+ }
+ dest = Jim_GetString(argv[force + 1], NULL);
+
+ if (!force && access(dest, F_OK) == 0) {
+ Jim_SetResultString(interp, "", 0);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "error renaming \"", source, "\" to \"", dest, "\": ", strerror(errno), NULL);
+ return JIM_ERR;
+ }
+
+ if (rename(source, dest) != 0) {
+ Jim_SetResultString(interp, "", 0);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "error renaming \"", source, "\": ", strerror(errno), NULL);
+ return JIM_ERR;
+ }
+
+ return JIM_OK;
+}
+
+static int file_stat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)
+{
+ const char *path = Jim_GetString(filename, NULL);
+ if (stat(path, sb) == -1) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "could not read \"", path, "\": ", strerror(errno), NULL);
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)
+{
+ const char *path = Jim_GetString(filename, NULL);
+ if (lstat(path, sb) == -1) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "could not read \"", path, "\": ", strerror(errno), NULL);
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetIntResult(interp, sb.st_atime);
+ return JIM_OK;
+}
+
+static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetIntResult(interp, sb.st_mtime);
+ return JIM_OK;
+}
+
+static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetIntResult(interp, sb.st_size);
+ return JIM_OK;
+}
+
+static int file_cmd_isdirectory(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = S_ISDIR(sb.st_mode);
+ }
+ Jim_SetIntResult(interp, ret);
+ return JIM_OK;
+}
+
+static int file_cmd_isfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = S_ISREG(sb.st_mode);
+ }
+ Jim_SetIntResult(interp, ret);
+ return JIM_OK;
+}
+
+static int file_cmd_owned(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = (geteuid() == sb.st_uid);
+ }
+ Jim_SetIntResult(interp, ret);
+ return JIM_OK;
+}
+
+#ifdef S_IFLNK
+static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_GetString(argv[0], NULL);
+ char *linkValue = Jim_Alloc(MAXPATHLEN + 1);
+
+ int linkLength = readlink(path, linkValue, MAXPATHLEN);
+ if (linkLength == -1) {
+ Jim_Free(linkValue);
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "couldn't readlink \"", path, "\"", NULL);
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, linkValue, linkLength));
+ return JIM_OK;
+}
+#endif
+
+static int file_cmd_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetIntResult(interp, sb.st_mode);
+ return JIM_OK;
+}
+
+static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return StoreStatData(interp, argv[1], &sb);
+}
+
+static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return StoreStatData(interp, argv[1], &sb);
+}
+
+static const jim_subcmd_type command_table[] = {
+ { .cmd = "atime",
+ .args = "name",
+ .function = file_cmd_atime,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Last access time"
+ },
+ { .cmd = "mtime",
+ .args = "name",
+ .function = file_cmd_mtime,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Last modification time"
+ },
+ { .cmd = "dirname",
+ .args = "name",
+ .function = file_cmd_dirname,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Directory part of the name"
+ },
+ { .cmd = "rootname",
+ .args = "name",
+ .function = file_cmd_rootname,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Name without any extension"
+ },
+ { .cmd = "extension",
+ .args = "name",
+ .function = file_cmd_extension,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Last extension including the dot"
+ },
+ { .cmd = "tail",
+ .args = "name",
+ .function = file_cmd_tail,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Last component of the name"
+ },
+ { .cmd = "normalize",
+ .args = "name",
+ .function = file_cmd_normalize,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Normalized path of name"
+ },
+ { .cmd = "readable",
+ .args = "name",
+ .function = file_cmd_readable,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Is file readable"
+ },
+ { .cmd = "writable",
+ .args = "name",
+ .function = file_cmd_writable,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Is file writable"
+ },
+ { .cmd = "executable",
+ .args = "name",
+ .function = file_cmd_executable,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Is file executable"
+ },
+ { .cmd = "exists",
+ .args = "name",
+ .function = file_cmd_exists,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Does file exist"
+ },
+ { .cmd = "delete",
+ .args = "name ...",
+ .function = file_cmd_delete,
+ .minargs = 1,
+ .maxargs = -1,
+ .description = "Deletes the file(s)"
+ },
+ { .cmd = "mkdir",
+ .args = "dir ...",
+ .function = file_cmd_mkdir,
+ .minargs = 1,
+ .maxargs = -1,
+ .description = "Creates the directories"
+ },
+ { .cmd = "rename",
+ .args = "?-force? source dest",
+ .function = file_cmd_rename,
+ .minargs = 2,
+ .maxargs = 3,
+ .description = "Renames a file"
+ },
+#ifdef S_IFLNK
+ { .cmd = "readlink",
+ .args = "name",
+ .function = file_cmd_readlink,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Value of the symbolic link"
+ },
+#endif
+ { .cmd = "size",
+ .args = "name",
+ .function = file_cmd_size,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Size of file"
+ },
+ { .cmd = "stat",
+ .args = "name var",
+ .function = file_cmd_stat,
+ .minargs = 2,
+ .maxargs = 2,
+ .description = "Stores results of stat in var array"
+ },
+ { .cmd = "lstat",
+ .args = "name var",
+ .function = file_cmd_lstat,
+ .minargs = 2,
+ .maxargs = 2,
+ .description = "Stores results of lstat in var array"
+ },
+ { .cmd = "type",
+ .args = "name",
+ .function = file_cmd_type,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Returns type of the file"
+ },
+ { .cmd = "owned",
+ .args = "name",
+ .function = file_cmd_owned,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Returns 1 if owned by the current owner"
+ },
+ { .cmd = "isdirectory",
+ .args = "name",
+ .function = file_cmd_isdirectory,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Returns 1 if name is a directory"
+ },
+ { .cmd = "isfile",
+ .args = "name",
+ .function = file_cmd_isfile,
+ .minargs = 1,
+ .maxargs = 1,
+ .description = "Returns 1 if name is a file"
+ },
+ {
+ .cmd = 0
+ }
+};
+
+static int Jim_CdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path;
+
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "dirname");
+ return JIM_ERR;
+ }
+
+ path = Jim_GetString(argv[1], NULL);
+
+ if (chdir(path) != 0) {
+ Jim_SetResultString(interp, "", 0);
+ Jim_AppendStrings(interp, Jim_GetResult(interp),
+ "couldn't change working directory to \"", path, "\": ", strerror(errno), NULL);
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const int cwd_len=2048;
+ char *cwd=malloc(cwd_len);
+ getcwd(cwd, cwd_len);
+
+ Jim_SetResultString(interp, cwd, -1);
+
+ free(cwd);
+ return JIM_OK;
+}
+
+int Jim_FileInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "file", "1.0", JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)command_table, NULL);
+ Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
+ Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
+ return JIM_OK;
+}
diff --git a/jim-subcmd.c b/jim-subcmd.c
new file mode 100644
index 0000000..7c2ce03
--- /dev/null
+++ b/jim-subcmd.c
@@ -0,0 +1,194 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "jim-subcmd.h"
+
+/**
+ * Implements the common 'commands' subcommand
+ */
+static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ /* Nothing to do, since the result has already been created */
+ return JIM_OK;
+}
+
+/**
+ * Do-nothing command to support -commands and -usage
+ */
+static const jim_subcmd_type dummy_subcmd = {
+ .cmd = "dummy",
+ .function = subcmd_null,
+ .flags = JIM_MODFLAG_HIDDEN,
+};
+
+static void add_commands(Jim_Interp *interp, const jim_subcmd_type *ct, const char *sep)
+{
+ const char *s = "";
+
+ for (; ct->cmd; ct++) {
+ if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), s, ct->cmd, 0);
+ s = sep;
+ }
+ }
+}
+
+static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type *command_table, const char *type, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_GetString(argv[0], NULL), ", ", type, " command \"", Jim_GetString(argv[1], NULL), "\": should be ", NULL);
+ add_commands(interp, command_table, ", ");
+}
+
+static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_GetString(argv[0], NULL), " command ... \", where command is one of: ", NULL);
+ add_commands(interp, command_table, ", ");
+}
+
+static void add_subcmd_usage(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv)
+{
+ Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_GetString(argv[0], NULL), " ", ct->cmd, NULL);
+
+ if (ct->args && *ct->args) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL);
+ }
+}
+
+static void show_full_usage(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ for (; ct->cmd; ct++) {
+ if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
+ add_subcmd_usage(interp, ct, argc, argv);
+ if (ct->description) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n ", ct->description, 0);
+ }
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", 0);
+ }
+ }
+}
+
+const jim_subcmd_type *
+Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv)
+{
+ const jim_subcmd_type *ct;
+ const jim_subcmd_type *partial = 0;
+ int cmdlen;
+ Jim_Obj *cmd;
+ const char *cmdstr;
+ const char *cmdname;
+ int help = 0;
+
+ cmdname = Jim_GetString(argv[0], NULL);
+
+ if (argc < 2) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "wrong # args: should be \"", cmdname, " command ...\"\n", 0);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdname, " -help\" or \"", cmdname, " -help command\" for help", 0);
+ return 0;
+ }
+
+ cmd = argv[1];
+
+ if (argc == 2 && Jim_CompareStringImmediate(interp, cmd, "-usage")) {
+ /* Show full usage */
+ show_full_usage(interp, command_table, argc, argv);
+ return &dummy_subcmd;
+ }
+
+ /* Check for the help command */
+ if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
+ if (argc == 2) {
+ /* Usage for the command, not the subcommand */
+ show_cmd_usage(interp, command_table, argc, argv);
+ return 0;
+ }
+ help = 1;
+
+ /* Skip the 'help' command */
+ cmd = argv[2];
+ }
+
+ /* Check for special builtin '-commands' command first */
+ if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
+ /* Build the result here */
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ add_commands(interp, command_table, " ");
+ return &dummy_subcmd;
+ }
+
+ cmdstr = Jim_GetString(cmd, &cmdlen);
+
+ for (ct = command_table; ct->cmd; ct++) {
+ if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
+ /* Found an exact match */
+ break;
+ }
+ if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
+ if (partial) {
+ /* Ambiguous */
+ bad_subcmd(interp, command_table, "ambiguous", argc, argv);
+ return 0;
+ }
+ partial = ct;
+ }
+ continue;
+ }
+
+ /* If we had an unambiguous partial match */
+ if (partial && !ct->cmd) {
+ ct = partial;
+ }
+
+ if (!ct->cmd) {
+ /* No matching command */
+ bad_subcmd(interp, command_table, "unknown", argc, argv);
+ return 0;
+ }
+
+ if (help) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ add_subcmd_usage(interp, ct, argc, argv);
+ if (ct->description) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", ct->description, 0);
+ }
+ return 0;
+ }
+
+ /* Check the number of args */
+ if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2> ct->maxargs)) {
+ Jim_SetResultString(interp, "wrong # args: should be \"", -1);
+ add_subcmd_usage(interp, ct, argc, argv);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+
+ return 0;
+ }
+
+ /* Good command */
+ return ct;
+}
+
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv)
+{
+ int ret = JIM_ERR;
+
+ if (ct) {
+ ret = ct->function(interp, argc - 2, argv + 2);
+ if (ret < 0) {
+ Jim_SetResultString(interp, "wrong # args: should be \"", -1);
+ add_subcmd_usage(interp, ct, argc, argv);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+ ret = JIM_ERR;
+ }
+ }
+ return ret;
+}
+
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv);
+
+ return Jim_CallSubCmd(interp, ct, argc, argv);
+}
diff --git a/jim-subcmd.h b/jim-subcmd.h
new file mode 100644
index 0000000..973d80c
--- /dev/null
+++ b/jim-subcmd.h
@@ -0,0 +1,68 @@
+/* Provides a common approach to implementing Tcl commands
+ * which implement subcommands
+ */
+#ifndef JIM_SUBCMD_H
+#define JIM_SUBCMD_H
+
+#include <jim.h>
+
+#define JIM_MODFLAG_HIDDEN 0x0001 /* Don't show the subcommand in usage or commands */
+
+/* Custom flags start at 0x0100 */
+
+/**
+ * Returns JIM_OK if OK, JIM_ERR (etc.) on error, break, continue, etc.
+ * Returns -1 if invalid args.
+ */
+typedef int tclmod_cmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+typedef struct {
+ const char *cmd; /* Name of the (sub)command */
+ const char *args; /* Textual description of allowed args */
+ tclmod_cmd_function *function; /* Function implementing the subcommand */
+ short minargs; /* Minimum required arguments */
+ short maxargs; /* Maximum allowed arguments or -1 if no limit */
+ unsigned flags; /* JIM_MODFLAG_... plus custom flags */
+ const char *description; /* Description of the subcommand */
+} jim_subcmd_type;
+
+/**
+ * Looks up the appropriate subcommand in the given command table and return
+ * the command function which implements the subcommand.
+ * NULL will be returned and an appropriate error will be set if the subcommand or
+ * arguments are invalid.
+ *
+ * Typical usage is:
+ * {
+ * const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, command_table, argc, argv);
+ *
+ * return Jim_CallSubCmd(interp, ct, argc, argv);
+ * }
+ *
+ */
+const jim_subcmd_type *
+Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
+
+/**
+ * Parses the args against the given command table and executes the subcommand if found
+ * or sets an appropriate error if the subcommand or arguments is invalid.
+ *
+ * Can be used directly with Jim_CreateCommand() where the ClientData is the command table.
+ *
+ * e.g. Jim_CreateCommand(interp, "mycmd", Jim_SubCmdProc, command_table, NULL);
+ */
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+/**
+ * Invokes the given subcmd with the given args as returned
+ * by Jim_ParseSubCmd()
+ *
+ * If ct is NULL, returns JIM_ERR, leaving any message.
+ * Otherwise invokes ct->function
+ *
+ * If ct->function returns -1, sets an error message and returns JIM_ERR.
+ * Otherwise returns the result of ct->function.
+ */
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv);
+
+#endif
diff --git a/jim.h b/jim.h
index c10887e..b7384a4 100644
--- a/jim.h
+++ b/jim.h
@@ -100,34 +100,17 @@ extern "C" {
* Compiler specific fixes.
* ---------------------------------------------------------------------------*/
-/* MSC has _stricmp instead of strcasecmp */
-#ifdef _MSC_VER
-# define strcasecmp _stricmp
-#endif /* _MSC_VER */
-
/* Long Long type and related issues */
#ifdef HAVE_LONG_LONG
-# ifdef _MSC_VER /* MSC compiler */
-# define jim_wide _int64
-# ifndef LLONG_MAX
-# define LLONG_MAX 9223372036854775807I64
-# endif
-# ifndef LLONG_MIN
-# define LLONG_MIN (-LLONG_MAX - 1I64)
-# endif
-# define JIM_WIDE_MIN LLONG_MIN
-# define JIM_WIDE_MAX LLONG_MAX
-# else /* Other compilers (mainly GCC) */
-# define jim_wide long long
-# ifndef LLONG_MAX
-# define LLONG_MAX 9223372036854775807LL
-# endif
-# ifndef LLONG_MIN
-# define LLONG_MIN (-LLONG_MAX - 1LL)
-# endif
-# define JIM_WIDE_MIN LLONG_MIN
-# define JIM_WIDE_MAX LLONG_MAX
+# define jim_wide long long
+# ifndef LLONG_MAX
+# define LLONG_MAX 9223372036854775807LL
+# endif
+# ifndef LLONG_MIN
+# define LLONG_MIN (-LLONG_MAX - 1LL)
# endif
+# define JIM_WIDE_MIN LLONG_MIN
+# define JIM_WIDE_MAX LLONG_MAX
#else
# define jim_wide long
# define JIM_WIDE_MIN LONG_MIN
@@ -139,13 +122,9 @@ extern "C" {
* ---------------------------------------------------------------------------*/
#ifdef HAVE_LONG_LONG
-# if defined(_MSC_VER) || defined(__MSVCRT__)
-# define JIM_WIDE_MODIFIER "I64d"
-# else
-# define JIM_WIDE_MODIFIER "lld"
-# endif
+# define JIM_WIDE_MODIFIER "lld"
#else
-# define JIM_WIDE_MODIFIER "ld"
+# define JIM_WIDE_MODIFIER "ld"
#endif
/* -----------------------------------------------------------------------------
@@ -194,14 +173,6 @@ extern "C" {
#define JIM_NL "\n"
#endif
-#if defined(__WIN32__) || defined(_WIN32)
-#define DLLEXPORT __declspec(dllexport)
-#define DLLIMPORT __declspec(dllimport)
-#else
-#define DLLEXPORT
-#define DLLIMPORT
-#endif
-
/* -----------------------------------------------------------------------------
* Stack
* ---------------------------------------------------------------------------*/
@@ -546,16 +517,6 @@ typedef struct Jim_Interp {
struct Jim_HashTable assocData; /* per-interp storage for use by packages */
Jim_PrngState *prngState; /* per interpreter Random Number Gen. state. */
struct Jim_HashTable packages; /* Provided packages hash table */
-#if 0
- void *cookie_stdin; /* input file pointer, 'stdin' by default */
- void *cookie_stdout; /* output file pointer, 'stdout' by default */
- void *cookie_stderr; /* errors file pointer, 'stderr' by default */
- int (*cb_vfprintf)( void *cookie, const char *fmt, va_list ap);
- size_t (*cb_fwrite )( const void *ptr, size_t size, size_t n, void *cookie );
- size_t (*cb_fread )( void *ptr, size_t size, size_t n, void *cookie );
- int (*cb_fflush )( void *cookie );
- char *(*cb_fgets )( char *s, int size, void *cookie );
-#endif
} Jim_Interp;
/* Currently provided as macro that performs the increment.
@@ -608,268 +569,259 @@ typedef struct Jim_Reference {
#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
#define JIM_EXPORT
-#define JIM_API(X) X
/* Memory allocation */
-JIM_EXPORT void * JIM_API(Jim_Alloc) (int size);
-JIM_EXPORT void JIM_API(Jim_Free) (void *ptr);
-JIM_EXPORT char * JIM_API(Jim_StrDup) (const char *s);
+JIM_EXPORT void * Jim_Alloc (int size);
+JIM_EXPORT void Jim_Free (void *ptr);
+JIM_EXPORT char * Jim_StrDup (const char *s);
/* evaluation */
-JIM_EXPORT int JIM_API(Jim_Eval)(Jim_Interp *interp, const char *script);
+JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
/* in C code, you can do this and get better error messages */
/* Jim_Eval_Named( interp, "some tcl commands", __FILE__, __LINE__ ); */
-JIM_EXPORT int JIM_API(Jim_Eval_Named)(Jim_Interp *interp, const char *script,const char *filename, int lineno);
-JIM_EXPORT int JIM_API(Jim_EvalGlobal)(Jim_Interp *interp, const char *script);
-JIM_EXPORT int JIM_API(Jim_EvalFile)(Jim_Interp *interp, const char *filename);
-JIM_EXPORT int JIM_API(Jim_EvalObj) (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
-JIM_EXPORT int JIM_API(Jim_EvalObjBackground) (Jim_Interp *interp,
+JIM_EXPORT int Jim_Eval_Named(Jim_Interp *interp, const char *script,const char *filename, int lineno);
+JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script);
+JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
+JIM_EXPORT int Jim_EvalObjBackground (Jim_Interp *interp,
Jim_Obj *scriptObjPtr);
-JIM_EXPORT int JIM_API(Jim_EvalObjVector) (Jim_Interp *interp, int objc,
+JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc,
Jim_Obj *const *objv);
-JIM_EXPORT int JIM_API(Jim_SubstObj) (Jim_Interp *interp, Jim_Obj *substObjPtr,
+JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
Jim_Obj **resObjPtrPtr, int flags);
/* stack */
-JIM_EXPORT void JIM_API(Jim_InitStack)(Jim_Stack *stack);
-JIM_EXPORT void JIM_API(Jim_FreeStack)(Jim_Stack *stack);
-JIM_EXPORT int JIM_API(Jim_StackLen)(Jim_Stack *stack);
-JIM_EXPORT void JIM_API(Jim_StackPush)(Jim_Stack *stack, void *element);
-JIM_EXPORT void * JIM_API(Jim_StackPop)(Jim_Stack *stack);
-JIM_EXPORT void * JIM_API(Jim_StackPeek)(Jim_Stack *stack);
-JIM_EXPORT void JIM_API(Jim_FreeStackElements)(Jim_Stack *stack, void (*freeFunc)(void *ptr));
+JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
+JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
+JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element);
+JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack);
+JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr));
/* hash table */
-JIM_EXPORT int JIM_API(Jim_InitHashTable) (Jim_HashTable *ht,
+JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht,
Jim_HashTableType *type, void *privdata);
-JIM_EXPORT int JIM_API(Jim_ExpandHashTable) (Jim_HashTable *ht,
+JIM_EXPORT int Jim_ExpandHashTable (Jim_HashTable *ht,
unsigned int size);
-JIM_EXPORT int JIM_API(Jim_AddHashEntry) (Jim_HashTable *ht, const void *key,
+JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key,
void *val);
-JIM_EXPORT int JIM_API(Jim_ReplaceHashEntry) (Jim_HashTable *ht,
+JIM_EXPORT int Jim_ReplaceHashEntry (Jim_HashTable *ht,
const void *key, void *val);
-JIM_EXPORT int JIM_API(Jim_DeleteHashEntry) (Jim_HashTable *ht,
+JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht,
const void *key);
-JIM_EXPORT int JIM_API(Jim_FreeHashTable) (Jim_HashTable *ht);
-JIM_EXPORT Jim_HashEntry * JIM_API(Jim_FindHashEntry) (Jim_HashTable *ht,
+JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht,
const void *key);
-JIM_EXPORT int JIM_API(Jim_ResizeHashTable) (Jim_HashTable *ht);
-JIM_EXPORT Jim_HashTableIterator *JIM_API(Jim_GetHashTableIterator)
+JIM_EXPORT int Jim_ResizeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
(Jim_HashTable *ht);
-JIM_EXPORT Jim_HashEntry * JIM_API(Jim_NextHashEntry)
+JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
(Jim_HashTableIterator *iter);
/* objects */
-JIM_EXPORT Jim_Obj * JIM_API(Jim_NewObj) (Jim_Interp *interp);
-JIM_EXPORT void JIM_API(Jim_FreeObj) (Jim_Interp *interp, Jim_Obj *objPtr);
-JIM_EXPORT void JIM_API(Jim_InvalidateStringRep) (Jim_Obj *objPtr);
-JIM_EXPORT void JIM_API(Jim_InitStringRep) (Jim_Obj *objPtr, const char *bytes,
+JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
+JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InitStringRep (Jim_Obj *objPtr, const char *bytes,
int length);
-JIM_EXPORT Jim_Obj * JIM_API(Jim_DuplicateObj) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
Jim_Obj *objPtr);
-JIM_EXPORT const char * JIM_API(Jim_GetString)(Jim_Obj *objPtr,
+JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
int *lenPtr);
-JIM_EXPORT int JIM_API(Jim_Length)(Jim_Obj *objPtr);
+JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
/* string object */
-JIM_EXPORT Jim_Obj * JIM_API(Jim_NewStringObj) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp,
const char *s, int len);
-JIM_EXPORT Jim_Obj * JIM_API(Jim_NewStringObjNoAlloc) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp,
char *s, int len);
-JIM_EXPORT void JIM_API(Jim_AppendString) (Jim_Interp *interp, Jim_Obj *objPtr,
+JIM_EXPORT void Jim_AppendString (Jim_Interp *interp, Jim_Obj *objPtr,
const char *str, int len);
-JIM_EXPORT void JIM_API(Jim_AppendString_sprintf) (Jim_Interp *interp, Jim_Obj *objPtr,
- const char *fmt, ... );
-JIM_EXPORT void JIM_API(Jim_AppendObj) (Jim_Interp *interp, Jim_Obj *objPtr,
+JIM_EXPORT void Jim_AppendString_sprintf (Jim_Interp *interp, Jim_Obj *objPtr,
+ const char *fmt, ... );
+JIM_EXPORT void Jim_AppendObj (Jim_Interp *interp, Jim_Obj *objPtr,
Jim_Obj *appendObjPtr);
-JIM_EXPORT void JIM_API(Jim_AppendStrings) (Jim_Interp *interp,
+JIM_EXPORT void Jim_AppendStrings (Jim_Interp *interp,
Jim_Obj *objPtr, ...);
-JIM_EXPORT int JIM_API(Jim_StringEqObj) (Jim_Obj *aObjPtr,
+JIM_EXPORT int Jim_StringEqObj (Jim_Obj *aObjPtr,
Jim_Obj *bObjPtr, int nocase);
-JIM_EXPORT int JIM_API(Jim_StringMatchObj) (Jim_Obj *patternObjPtr,
+JIM_EXPORT int Jim_StringMatchObj (Jim_Obj *patternObjPtr,
Jim_Obj *objPtr, int nocase);
-JIM_EXPORT Jim_Obj * JIM_API(Jim_StringRangeObj) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_StringRangeObj (Jim_Interp *interp,
Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr,
Jim_Obj *lastObjPtr);
-JIM_EXPORT Jim_Obj * JIM_API(Jim_FormatString) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_FormatString (Jim_Interp *interp,
Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv);
-JIM_EXPORT Jim_Obj * JIM_API(Jim_ScanString) (Jim_Interp *interp, Jim_Obj *strObjPtr,
+JIM_EXPORT Jim_Obj * Jim_ScanString (Jim_Interp *interp, Jim_Obj *strObjPtr,
Jim_Obj *fmtObjPtr, int flags);
-JIM_EXPORT int JIM_API(Jim_CompareStringImmediate) (Jim_Interp *interp,
+JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp,
Jim_Obj *objPtr, const char *str);
/* reference object */
-JIM_EXPORT Jim_Obj * JIM_API(Jim_NewReference) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp,
Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
-JIM_EXPORT Jim_Reference * JIM_API(Jim_GetReference) (Jim_Interp *interp,
+JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp,
Jim_Obj *objPtr);
-JIM_EXPORT int JIM_API(Jim_SetFinalizer) (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
-JIM_EXPORT int JIM_API(Jim_GetFinalizer) (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
+JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
/* interpreter */
-JIM_EXPORT Jim_Interp * JIM_API(Jim_CreateInterp) (void);
-JIM_EXPORT void JIM_API(Jim_FreeInterp) (Jim_Interp *i);
-JIM_EXPORT int JIM_API(Jim_GetExitCode) (Jim_Interp *interp);
-JIM_EXPORT void * JIM_API(Jim_SetStdin) (Jim_Interp *interp, void *fp);
-JIM_EXPORT void * JIM_API(Jim_SetStdout) (Jim_Interp *interp, void *fp);
-JIM_EXPORT void * JIM_API(Jim_SetStderr) (Jim_Interp *interp, void *fp);
+JIM_EXPORT Jim_Interp * Jim_CreateInterp (void);
+JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i);
+JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp);
+JIM_EXPORT void * Jim_SetStdin (Jim_Interp *interp, void *fp);
+JIM_EXPORT void * Jim_SetStdout (Jim_Interp *interp, void *fp);
+JIM_EXPORT void * Jim_SetStderr (Jim_Interp *interp, void *fp);
/* commands */
-JIM_EXPORT void JIM_API(Jim_RegisterCoreCommands) (Jim_Interp *interp);
-JIM_EXPORT int JIM_API(Jim_CreateCommand) (Jim_Interp *interp,
+JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp);
+JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp,
const char *cmdName, Jim_CmdProc cmdProc, void *privData,
Jim_DelCmdProc delProc);
-JIM_EXPORT int JIM_API(Jim_CreateProcedure) (Jim_Interp *interp,
+JIM_EXPORT int Jim_CreateProcedure (Jim_Interp *interp,
const char *cmdName, Jim_Obj *argListObjPtr, Jim_Obj *staticsListObjPtr,
Jim_Obj *bodyObjPtr, int arityMin, int arityMax);
-JIM_EXPORT int JIM_API(Jim_DeleteCommand) (Jim_Interp *interp,
+JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp,
const char *cmdName);
-JIM_EXPORT int JIM_API(Jim_RenameCommand) (Jim_Interp *interp,
+JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
const char *oldName, const char *newName);
-JIM_EXPORT Jim_Cmd * JIM_API(Jim_GetCommand) (Jim_Interp *interp,
+JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
Jim_Obj *objPtr, int flags);
-JIM_EXPORT int JIM_API(Jim_SetVariable) (Jim_Interp *interp,
+JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
-JIM_EXPORT int JIM_API(Jim_SetVariableStr) (Jim_Interp *interp,
+JIM_EXPORT int Jim_SetVariableStr (Jim_Interp *interp,
const char *name, Jim_Obj *objPtr);
-JIM_EXPORT int JIM_API(Jim_SetGlobalVariableStr) (Jim_Interp *interp,
+JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
const char *name, Jim_Obj *objPtr);
-JIM_EXPORT int JIM_API(Jim_SetVariableStrWithStr) (Jim_Interp *interp,
+JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
const char *name, const char *val);
-JIM_EXPORT int JIM_API(Jim_SetVariableLink) (Jim_Interp *interp,
+JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
Jim_CallFrame *targetCallFrame);
-JIM_EXPORT Jim_Obj * JIM_API(Jim_GetVariable) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp,
Jim_Obj *nameObjPtr, int flags);
-JIM_EXPORT Jim_Obj * JIM_API(Jim_GetGlobalVariable) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp,
Jim_Obj *nameObjPtr, int flags);
-JIM_EXPORT Jim_Obj * JIM_API(Jim_GetVariableStr) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp,
const char *name, int flags);
-JIM_EXPORT Jim_Obj * JIM_API(Jim_GetGlobalVariableStr) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
const char *name, int flags);
-JIM_EXPORT int JIM_API(Jim_UnsetVariable) (Jim_Interp *interp,
+JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp,
Jim_Obj *nameObjPtr, int flags);
/* call frame */
-JIM_EXPORT int JIM_API(Jim_GetCallFrameByLevel) (Jim_Interp *interp,
+JIM_EXPORT int Jim_GetCallFrameByLevel (Jim_Interp *interp,
Jim_Obj *levelObjPtr, Jim_CallFrame **framePtrPtr,
int *newLevelPtr);
/* garbage collection */
-JIM_EXPORT int JIM_API(Jim_Collect) (Jim_Interp *interp);
-JIM_EXPORT void JIM_API(Jim_CollectIfNeeded) (Jim_Interp *interp);
+JIM_EXPORT int Jim_Collect (Jim_Interp *interp);
+JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp);
/* index object */
-JIM_EXPORT int JIM_API(Jim_GetIndex) (Jim_Interp *interp, Jim_Obj *objPtr,
+JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr,
int *indexPtr);
/* list object */
-JIM_EXPORT Jim_Obj * JIM_API(Jim_NewListObj) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp,
Jim_Obj *const *elements, int len);
-JIM_EXPORT void JIM_API(Jim_ListInsertElements) (Jim_Interp *interp,
+JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp,
Jim_Obj *listPtr, int index, int objc, Jim_Obj *const *objVec);
-JIM_EXPORT void JIM_API(Jim_ListAppendElement) (Jim_Interp *interp,
+JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp,
Jim_Obj *listPtr, Jim_Obj *objPtr);
-JIM_EXPORT void JIM_API(Jim_ListAppendList) (Jim_Interp *interp,
+JIM_EXPORT void Jim_ListAppendList (Jim_Interp *interp,
Jim_Obj *listPtr, Jim_Obj *appendListPtr);
-JIM_EXPORT void JIM_API(Jim_ListLength) (Jim_Interp *interp, Jim_Obj *listPtr,
+JIM_EXPORT void Jim_ListLength (Jim_Interp *interp, Jim_Obj *listPtr,
int *intPtr);
-JIM_EXPORT int JIM_API(Jim_ListIndex) (Jim_Interp *interp, Jim_Obj *listPrt,
+JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt,
int index, Jim_Obj **objPtrPtr, int seterr);
-JIM_EXPORT int JIM_API(Jim_SetListIndex) (Jim_Interp *interp,
+JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp,
Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
Jim_Obj *newObjPtr);
-JIM_EXPORT Jim_Obj * JIM_API(Jim_ConcatObj) (Jim_Interp *interp, int objc,
+JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc,
Jim_Obj *const *objv);
/* dict object */
-JIM_EXPORT Jim_Obj * JIM_API(Jim_NewDictObj) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp,
Jim_Obj *const *elements, int len);
-JIM_EXPORT int JIM_API(Jim_DictKey) (Jim_Interp *interp, Jim_Obj *dictPtr,
+JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr,
Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
-JIM_EXPORT int JIM_API(Jim_DictKeysVector) (Jim_Interp *interp,
+JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
Jim_Obj **objPtrPtr, int flags);
-JIM_EXPORT int JIM_API(Jim_SetDictKeysVector) (Jim_Interp *interp,
+JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp,
Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
Jim_Obj *newObjPtr);
/* return code object */
-JIM_EXPORT int JIM_API(Jim_GetReturnCode) (Jim_Interp *interp, Jim_Obj *objPtr,
+JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
int *intPtr);
/* expression object */
-JIM_EXPORT int JIM_API(Jim_EvalExpression) (Jim_Interp *interp,
+JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr);
-JIM_EXPORT int JIM_API(Jim_GetBoolFromExpr) (Jim_Interp *interp,
+JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
Jim_Obj *exprObjPtr, int *boolPtr);
/* integer object */
-JIM_EXPORT int JIM_API(Jim_GetWide) (Jim_Interp *interp, Jim_Obj *objPtr,
+JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
jim_wide *widePtr);
-JIM_EXPORT int JIM_API(Jim_GetLong) (Jim_Interp *interp, Jim_Obj *objPtr,
+JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
long *longPtr);
-JIM_EXPORT void JIM_API(Jim_SetWide) (Jim_Interp *interp, Jim_Obj *objPtr,
+JIM_EXPORT void Jim_SetWide (Jim_Interp *interp, Jim_Obj *objPtr,
jim_wide wideValue);
#define Jim_NewWideObj Jim_NewIntObj
-JIM_EXPORT Jim_Obj * JIM_API(Jim_NewIntObj) (Jim_Interp *interp,
+JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp,
jim_wide wideValue);
/* double object */
-JIM_EXPORT int JIM_API(Jim_GetDouble)(Jim_Interp *interp, Jim_Obj *objPtr,
+JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
double *doublePtr);
-JIM_EXPORT void JIM_API(Jim_SetDouble)(Jim_Interp *interp, Jim_Obj *objPtr,
+JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
double doubleValue);
-JIM_EXPORT Jim_Obj * JIM_API(Jim_NewDoubleObj)(Jim_Interp *interp, double doubleValue);
+JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue);
/* shared strings */
-JIM_EXPORT const char * JIM_API(Jim_GetSharedString) (Jim_Interp *interp,
+JIM_EXPORT const char * Jim_GetSharedString (Jim_Interp *interp,
const char *str);
-JIM_EXPORT void JIM_API(Jim_ReleaseSharedString) (Jim_Interp *interp,
+JIM_EXPORT void Jim_ReleaseSharedString (Jim_Interp *interp,
const char *str);
/* commands utilities */
-JIM_EXPORT void JIM_API(Jim_WrongNumArgs) (Jim_Interp *interp, int argc,
+JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
Jim_Obj *const *argv, const char *msg);
-JIM_EXPORT int JIM_API(Jim_GetEnum) (Jim_Interp *interp, Jim_Obj *objPtr,
+JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
const char * const *tablePtr, int *indexPtr, const char *name, int flags);
-JIM_EXPORT int JIM_API(Jim_ScriptIsComplete) (const char *s, int len,
+JIM_EXPORT int Jim_ScriptIsComplete (const char *s, int len,
char *stateCharPtr);
/* package utilities */
typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
-JIM_EXPORT void * JIM_API(Jim_GetAssocData)(Jim_Interp *interp, const char *key);
-JIM_EXPORT int JIM_API(Jim_SetAssocData)(Jim_Interp *interp, const char *key,
+JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
+JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
Jim_InterpDeleteProc *delProc, void *data);
-JIM_EXPORT int JIM_API(Jim_DeleteAssocData)(Jim_Interp *interp, const char *key);
+JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
/* Packages C API */
-JIM_EXPORT int JIM_API(Jim_PackageProvide) (Jim_Interp *interp,
+/* jim-package.c */
+JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp,
const char *name, const char *ver, int flags);
-JIM_EXPORT const char * JIM_API(Jim_PackageRequire) (Jim_Interp *interp,
+JIM_EXPORT const char * Jim_PackageRequire (Jim_Interp *interp,
const char *name, const char *ver, int flags);
/* error messages */
-JIM_EXPORT void JIM_API(Jim_PrintErrorMessage) (Jim_Interp *interp);
+JIM_EXPORT void Jim_PrintErrorMessage (Jim_Interp *interp);
/* interactive mode */
-JIM_EXPORT int JIM_API(Jim_InteractivePrompt) (Jim_Interp *interp);
+JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
/* Misc */
-JIM_EXPORT void JIM_API(Jim_Panic) (Jim_Interp *interp, const char *fmt, ...);
+JIM_EXPORT void Jim_Panic (Jim_Interp *interp, const char *fmt, ...);
int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
-int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
-
-/* Jim's STDIO */
-JIM_EXPORT int JIM_API( Jim_fprintf )( Jim_Interp *interp, void *cookie, const char *fmt, ... );
-JIM_EXPORT int JIM_API( Jim_vfprintf )( Jim_Interp *interp, void *cookie, const char *fmt, va_list ap );
-#if 0
-JIM_EXPORT size_t JIM_API( Jim_fwrite )( Jim_Interp *interp, const void *ptr, size_t size, size_t nmeb, void *cookie );
-JIM_EXPORT size_t JIM_API( Jim_fread )( Jim_Interp *interp, void *ptr, size_t size, size_t nmeb, void *cookie );
-JIM_EXPORT int JIM_API( Jim_fflush )( Jim_Interp *interp, void *cookie );
-JIM_EXPORT char * JIM_API( Jim_fgets )( Jim_Interp *interp, char *s, int size, void *cookie );
-#endif
+/* jim-load.c */
+int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
#ifdef __cplusplus
}
diff --git a/jimsh.c b/jimsh.c
index 838cbb2..6944280 100644
--- a/jimsh.c
+++ b/jimsh.c
@@ -124,6 +124,8 @@ extern void Jim_AioInit(Jim_Interp *interp);
extern void Jim_EventloopInit(Jim_Interp *interp);
extern void Jim_RegexpInit(Jim_Interp *interp);
extern void Jim_ReaddirInit(Jim_Interp *interp);
+extern void Jim_FileInit(Jim_Interp *interp);
+extern void Jim_ExecInit(Jim_Interp *interp);
int main(int argc, char *const argv[])
{
@@ -140,6 +142,8 @@ int main(int argc, char *const argv[])
Jim_EventloopInit(interp);
Jim_RegexpInit(interp);
Jim_ReaddirInit(interp);
+ Jim_FileInit(interp);
+ Jim_ExecInit(interp);
/* Append the path where the executed Jim binary is contained
* in the jim_libpath list. */