aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in11
-rw-r--r--jim-aio.c9
-rw-r--r--jim-bio.c90
-rw-r--r--jim-exec.c179
-rw-r--r--jim-posix.c5
-rw-r--r--jim.c2
-rw-r--r--make-jim-load-extensions.sh18
-rw-r--r--tcltests/test_bio.tcl52
-rw-r--r--tcltests/test_exec.tcl17
9 files changed, 248 insertions, 135 deletions
diff --git a/Makefile.in b/Makefile.in
index 7794bad..bf172e3 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -12,7 +12,9 @@ CFLAGS += -DTCL_LIBRARY=\"/lib/tcl6\"
CFLAGS += -DJIM_TCL_COMPAT
-STATIC_LIBTCL := libtcl6.a
+# Emulate tinytcl
+LIBJIM := libtcl6.a
+
CFLAGS += -Wall -g -Os -I. @EXTRA_CFLAGS@
.EXPORT_ALL_VARIABLES:
@@ -30,9 +32,6 @@ jim-%.c: %.tcl
echo $@ >>.clean
tclsh make-c-ext.tcl $@ $*.tcl
-# Emulate tinytcl
-LIBJIM := libtcl6.a
-
ifdef jim_nofork
CFLAGS += -DNO_FORK
endif
@@ -51,8 +50,8 @@ $(LIBJIM): $(OBJS) $(EXTENSIONS_OBJS)
$(AR) cr $@ $^
$(RANLIB) $@
-load_extensions.c: make-load-extensions.sh
- sh make-load-extensions.sh $@ $(EXTENSIONS)
+load_extensions.c: make-jim-load-extensions.sh
+ sh make-jim-load-extensions.sh $@ $(EXTENSIONS)
install:
diff --git a/jim-aio.c b/jim-aio.c
index 0d334df..cb8db31 100644
--- a/jim-aio.c
+++ b/jim-aio.c
@@ -64,6 +64,7 @@
typedef struct AioFile {
FILE *fp;
+ Jim_Obj *filename;
int type;
int OpenFlags; /* AIO_KEEPOPEN? keep FILE*, AIO_FDOPEN? FILE* created via fdopen */
int fd;
@@ -87,6 +88,8 @@ static void JimAioDelProc(Jim_Interp *interp, void *privData)
AioFile *af = privData;
JIM_NOTUSED(interp);
+ Jim_DecrRefCount(interp, af->filename);
+
if (!(af->OpenFlags & AIO_KEEPOPEN)) {
fclose(af->fp);
}
@@ -358,6 +361,8 @@ static int aio_cmd_accept(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
/* Create the file command */
af = Jim_Alloc(sizeof(*af));
af->fd = sock;
+ af->filename = Jim_NewStringObj(interp, "accept", -1);
+ Jim_IncrRefCount(af->filename);
af->fp = fdopen(sock,"r+");
af->OpenFlags = AIO_FDOPEN;
af->flags = fcntl(af->fd,F_GETFL);
@@ -611,6 +616,8 @@ static int JimAioOpenCommand(Jim_Interp *interp, int argc,
af->fp = fp;
af->fd = fileno(fp);
af->flags = fcntl(af->fd,F_GETFL);
+ af->filename = argv[1];
+ Jim_IncrRefCount(af->filename);
af->OpenFlags = OpenFlags;
af->rEvent = NULL;
af->wEvent = NULL;
@@ -750,6 +757,8 @@ static int JimAioSockCommand(Jim_Interp *interp, int argc,
af->fp = fp;
af->fd = sock;
af->OpenFlags = AIO_FDOPEN;
+ af->filename = argv[1];
+ Jim_IncrRefCount(af->filename);
af->flags = fcntl(af->fd,F_GETFL);
af->rEvent = NULL;
af->wEvent = NULL;
diff --git a/jim-bio.c b/jim-bio.c
index fa44903..290093b 100644
--- a/jim-bio.c
+++ b/jim-bio.c
@@ -16,9 +16,7 @@
*
* Returns the number of chars written (if no error)
*
- * For the default binary encoding:
- * - 0x00 -> 0x01, 0x30
- * - 0x01 -> 0x01, 0x31
+ * Note that by default no encoding is actually done since Jim supports strings containing nulls!
*
* Alternatively, if -hex is specified, the data is read and written as ascii hex
*/
@@ -27,6 +25,7 @@
#include <string.h>
#include <stdio.h>
#include <time.h>
+#include <errno.h>
#include <jim.h>
#include <jim-subcmd.h>
@@ -81,7 +80,7 @@ static int bio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
Jim_Obj *result = Jim_NewStringObj(interp, "", 0);
- /* Read one char at a time, escaping 0x00 and 0xFF as necessary */
+ /* Read one char at a time */
while (len > 0) {
int ch = fgetc(fh);
if (ch == EOF) {
@@ -94,18 +93,12 @@ static int bio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
count += 2;
}
else {
- if (ch == 0 || ch == 1) {
- buf[count++] = 1;
- ch = ch + '0';
- }
buf[count++] = ch;
}
- /* Allow space for the null termination, plus escaping of one char */
- if (count >= sizeof(buf) - 2) {
+ if (count >= sizeof(buf)) {
/* Buffer is full, so append it */
Jim_AppendString(interp, result, buf, count);
-
count = 0;
}
len--;
@@ -117,6 +110,7 @@ static int bio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_ERR;
}
+ /* Add anything still pending */
Jim_AppendString(interp, result, buf, count);
if (Jim_SetVariable(interp, argv[1], result) != JIM_OK) {
@@ -128,62 +122,50 @@ static int bio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_OK;
}
-#if 0
static int bio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
- OpenFile *infilePtr;
- OpenFile *outfilePtr;
- int count = 0;
- int maxlen = 0;
+ long count = 0;
+ long maxlen = LONG_MAX;
- if (TclGetOpenFile(interp, argv[0], &infilePtr) != JIM_OK) {
- return TCL_ERROR;
- }
- if (!infilePtr->readable) {
- Jim_AppendResult(interp, "\"", argv[0],
- "\" wasn't opened for reading", (char *) NULL);
- return TCL_ERROR;
- }
- if (TclGetOpenFile(interp, argv[1], &outfilePtr) != JIM_OK) {
- return TCL_ERROR;
- }
- if (!outfilePtr->writable) {
- Jim_AppendResult(interp, "\"", argv[1],
- "\" wasn't opened for writing", (char *) NULL);
- return TCL_ERROR;
+ FILE *infh = Jim_AioFilehandle(interp, argv[0]);
+ FILE *outfh = Jim_AioFilehandle(interp, argv[1]);
+
+ if (infh == NULL || outfh == NULL) {
+ return JIM_ERR;
}
if (argc == 3) {
- if (Jim_GetInt(interp, argv[2], &maxlen) != JIM_OK) {
- return TCL_ERROR;
+ if (Jim_GetLong(interp, argv[2], &maxlen) != JIM_OK) {
+ return JIM_ERR;
}
}
- while (maxlen == 0 || count < maxlen) {
- int ch = fgetc(infilePtr->f);
- if (ch == EOF || fputc(ch, outfilePtr->f) == EOF) {
+ while (count < maxlen) {
+ int ch = fgetc(infh);
+ if (ch == EOF || fputc(ch, outfh) == EOF) {
break;
}
count++;
}
- if (ferror(infilePtr->f)) {
- Jim_AppendResult(interp, "error reading \"", argv[0], "\": ", Jim_UnixError(interp), 0);
- clearerr(infilePtr->f);
- return TCL_ERROR;
+ if (ferror(infh)) {
+ Jim_SetResultString(interp, "", 0);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "error reading \"", Jim_GetString(argv[0], NULL), "\": ", strerror(errno), 0);
+ clearerr(infh);
+ return JIM_ERR;
}
- if (ferror(outfilePtr->f)) {
- Jim_AppendResult(interp, "error writing \"", argv[0], "\": ", Jim_UnixError(interp), 0);
- clearerr(outfilePtr->f);
- return TCL_ERROR;
+ if (ferror(outfh)) {
+ Jim_SetResultString(interp, "", 0);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "error writing \"", Jim_GetString(argv[1], NULL), "\": ", strerror(errno), 0);
+ clearerr(outfh);
+ return JIM_ERR;
}
Jim_SetResultInt(interp, count);
return JIM_OK;
}
-#endif
static int bio_cmd_write(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
@@ -191,6 +173,7 @@ static int bio_cmd_write(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
const char *pt;
int hex = 0;
long total = 0;
+ int len;
if (Jim_CompareStringImmediate(interp, argv[0], "-hex")) {
@@ -203,20 +186,21 @@ static int bio_cmd_write(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
}
fh = Jim_AioFilehandle(interp, argv[0]);
+ if (fh == NULL) {
+ return JIM_ERR;
+ }
- for (pt = Jim_GetString(argv[1], NULL); *pt; pt++) {
+ pt = Jim_GetString(argv[1], &len);
+ while (len-- > 0) {
int ch;
if (hex) {
ch = hex2char(pt);
- pt++;
+ pt += 2;
+ len--;
}
else {
- ch = *pt;
- if (ch == 1) {
- pt++;
- ch = *pt - '0';
- }
+ ch = *pt++;
}
if (fputc(ch, fh) == EOF) {
break;
@@ -250,7 +234,6 @@ static const jim_subcmd_type command_table[] = {
.maxargs = 3,
.description = "Write an encoded string as binary bytes"
},
-#if 0
{ .cmd = "copy",
.function = bio_cmd_copy,
.args = "fromfd tofd ?bytes?",
@@ -258,7 +241,6 @@ static const jim_subcmd_type command_table[] = {
.maxargs = 3,
.description = "Read from one fd and write to another"
},
-#endif
{ 0 }
};
diff --git a/jim-exec.c b/jim-exec.c
index 5226094..42056fa 100644
--- a/jim-exec.c
+++ b/jim-exec.c
@@ -25,22 +25,29 @@
#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);
-
+/* These two could be moved into the Tcl core */
static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
{
Jim_SetResultString(interp, "", 0);
Jim_AppendStrings(interp, Jim_GetResult(interp), msg, ": ", strerror(errno), NULL);
}
+static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
+{
+ int len;
+ const char *s = Jim_GetString(objPtr, &len);
+
+ if (len > 0 && s[len-1] == '\n') {
+ objPtr->length--;
+ objPtr->bytes[objPtr->length] = '\0';
+ }
+}
+
/**
* Read from 'fd' and append the data to strObj
+ * Returns JIM_OK if OK, or JIM_ERR on error.
*/
-static int append_fd_to_string(Jim_Interp *interp, int fd, Jim_Obj *strObj)
+static int Jim_AppendStreamToString(Jim_Interp *interp, int fd, Jim_Obj *strObj)
{
while (1) {
char buffer[256];
@@ -49,6 +56,7 @@ static int append_fd_to_string(Jim_Interp *interp, int fd, Jim_Obj *strObj)
count = read(fd, buffer, sizeof(buffer));
if (count == 0) {
+ Jim_RemoveTrailingNewline(strObj);
return JIM_OK;
}
if (count < 0) {
@@ -58,6 +66,13 @@ static int append_fd_to_string(Jim_Interp *interp, int fd, Jim_Obj *strObj)
}
}
+#ifndef NO_FORK
+static int Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
+ int **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr);
+static void JimDetachPids(Jim_Interp *interp, int numPids, int *pidPtr);
+static int
+Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int errorId);
+
static int
Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
@@ -78,7 +93,7 @@ Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
if (numPids < 0) {
return JIM_ERR;
}
- Jim_DetachPids(interp, numPids, pidPtr);
+ JimDetachPids(interp, numPids, pidPtr);
Jim_Free(pidPtr);
return JIM_OK;
}
@@ -98,7 +113,7 @@ Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
result = JIM_OK;
if (outputId != -1) {
- result = append_fd_to_string(interp, outputId, Jim_GetResult(interp));
+ result = Jim_AppendStreamToString(interp, outputId, Jim_GetResult(interp));
if (result < 0) {
Jim_SetResultErrno(interp, "error reading from output pipe");
}
@@ -112,8 +127,8 @@ Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
}
/*
- * Data structures of the following type are used by Jim_Fork and
- * Jim_WaitPids to keep track of child processes.
+ * Data structures of the following type are used by JimFork and
+ * JimWaitPids to keep track of child processes.
*/
typedef struct {
@@ -127,7 +142,7 @@ typedef struct {
*
* WI_READY - Non-zero means process has exited or
* suspended since it was forked or last
- * returned by Jim_WaitPids.
+ * returned by JimWaitPids.
* WI_DETACHED - Non-zero means no-one cares about the
* process anymore. Ignore it until it
* exits, then forget about it.
@@ -136,6 +151,7 @@ typedef struct {
#define WI_READY 1
#define WI_DETACHED 2
+/* REVISIT: Should be per-interpreter */
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
@@ -147,10 +163,10 @@ static int waitTableUsed = 0; /* Number of entries in waitTable that
/*
*----------------------------------------------------------------------
*
- * Jim_Fork --
+ * JimFork --
*
* Create a new process using the vfork system call, and keep
- * track of it for "safe" waiting with Jim_WaitPids.
+ * track of it for "safe" waiting with JimWaitPids.
*
* Results:
* The return value is the value returned by the vfork system
@@ -163,8 +179,8 @@ static int waitTableUsed = 0; /* Number of entries in waitTable that
*
*----------------------------------------------------------------------
*/
-int
-Jim_Fork(void)
+static int
+JimFork(void)
{
WaitInfo *waitPtr;
pid_t pid;
@@ -207,10 +223,10 @@ Jim_Fork(void)
/*
*----------------------------------------------------------------------
*
- * Jim_WaitPids --
+ * JimWaitPids --
*
* This procedure is used to wait for one or more processes created
- * by Jim_Fork to exit or suspend. It records information about
+ * by JimFork 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.
@@ -226,8 +242,8 @@ Jim_Fork(void)
*
*----------------------------------------------------------------------
*/
-int
-Jim_WaitPids(int numPids, int *pidPtr, int *statusPtr)
+static int
+JimWaitPids(int numPids, int *pidPtr, int *statusPtr)
{
int i, count, pid;
WaitInfo *waitPtr;
@@ -311,12 +327,12 @@ Jim_WaitPids(int numPids, int *pidPtr, int *statusPtr)
/*
*----------------------------------------------------------------------
*
- * Jim_DetachPids --
+ * JimDetachPids --
*
* 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.
+ * JimWaitPids.
*
* Results:
* None.
@@ -327,7 +343,7 @@ Jim_WaitPids(int numPids, int *pidPtr, int *statusPtr)
*----------------------------------------------------------------------
*/
-static void Jim_DetachPids(Jim_Interp *interp, int numPids, int *pidPtr)
+static void JimDetachPids(Jim_Interp *interp, int numPids, int *pidPtr)
{
WaitInfo *waitPtr;
int i, count, pid;
@@ -575,8 +591,13 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid
}
else if (inputFile == FILE_HANDLE) {
/* Should be a file descriptor */
- /* REVISIT: Validate fd */
- inputId = dup(atoi(input));
+ Jim_Obj *fhObj = Jim_NewStringObj(interp, input, -1);
+ FILE *fh = Jim_AioFilehandle(interp, fhObj);
+ Jim_FreeNewObj(interp, fhObj);
+ if (fh == NULL) {
+ goto error;
+ }
+ inputId = dup(fileno(fh));
}
else {
/*
@@ -606,12 +627,14 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid
*/
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? */
+ Jim_Obj *fhObj = Jim_NewStringObj(interp, output, -1);
+ FILE *fh = Jim_AioFilehandle(interp, fhObj);
+ Jim_FreeNewObj(interp, fhObj);
+ if (fh == NULL) {
+ goto error;
+ }
+ fflush(fh);
+ lastOutputId = dup(fileno(fh));
}
else {
/*
@@ -647,12 +670,14 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid
/* 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? */
+ Jim_Obj *fhObj = Jim_NewStringObj(interp, error, -1);
+ FILE *fh = Jim_AioFilehandle(interp, fhObj);
+ Jim_FreeNewObj(interp, fhObj);
+ if (fh == NULL) {
+ goto error;
+ }
+ fflush(fh);
+ errorId = dup(fileno(fh));
}
else {
/*
@@ -729,7 +754,7 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid
outputId = pipeIds[1];
}
execName = arg_array[firstArg];
- pid = Jim_Fork();
+ pid = JimFork();
if (pid == -1) {
Jim_SetResultErrno(interp, "couldn't fork child process");
goto error;
@@ -820,7 +845,7 @@ Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pid
if (pidPtr != NULL) {
for (i = 0; i < numPids; i++) {
if (pidPtr[i] != -1) {
- Jim_DetachPids(interp, 1, &pidPtr[i]);
+ JimDetachPids(interp, 1, &pidPtr[i]);
}
}
Jim_Free(pidPtr);
@@ -856,12 +881,12 @@ 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);
+ int waitStatus = 0;
+ pid = JimWaitPids(1, &pidPtr[i], &waitStatus);
if (pid == -1) {
/* This can happen if the process was already reaped, so just ignore it */
continue;
@@ -896,7 +921,7 @@ Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int errorId)
if (errorId >= 0) {
if (errorId >= 0) {
- result = append_fd_to_string(interp, errorId, Jim_GetResult(interp));
+ result = Jim_AppendStreamToString(interp, errorId, Jim_GetResult(interp));
if (result < 0) {
Jim_SetResultErrno(interp, "error reading from stderr output file");
}
@@ -918,6 +943,76 @@ Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int errorId)
return result;
}
+#else /* NO_FORK */
+static int
+Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int pid;
+ int tmpfd;
+ int status;
+ int result;
+ char **nargv;
+ int i;
+
+#define TMP_NAME "/tmp/tcl.exec.XXXXXX"
+ char tmpname[sizeof(TMP_NAME) + 1];
+
+
+ /* Create a temporary file for the output from our exec command */
+ strcpy(tmpname, TMP_NAME);
+ tmpfd = mkstemp(tmpname);
+ if (tmpfd < 0) {
+ Jim_SetResultErrno(interp, "couldn't create temp file file for exec");
+ return JIM_ERR;
+ }
+
+ nargv = Jim_Alloc(sizeof(*nargv) * argc);
+ for (i = 1; i < argc; i++) {
+ nargv[i - 1] = (char *)Jim_GetString(argv[i], NULL);
+ }
+ nargv[i - 1] = NULL;
+
+ /*printf("Writing output to %s, fd=%d\n", tmpname, tmpfd);*/
+ unlink(tmpname);
+
+ /* Use vfork and send output to this temporary file */
+ pid = vfork();
+ if (pid == 0) {
+ close(0);
+ open("/dev/null", O_RDONLY);
+ close(1);
+ dup(tmpfd);
+ close(2);
+ /*open("/dev/null", O_WRONLY);*/
+ dup(tmpfd);
+ close(tmpfd);
+ execvp(nargv[0], nargv);
+ _exit(127);
+ }
+
+ Jim_Free(nargv);
+
+ /* Wait for the child to exit */
+ do {
+ waitpid(pid, &status, 0);
+ } while (!WIFEXITED(status));
+
+ /*
+ * Read the child's output (if any) and put it into the result.
+ */
+ lseek(tmpfd, 0L, SEEK_SET);
+
+ Jim_SetResultString(interp, "", 0);
+
+ result = Jim_AppendStreamToString(interp, tmpfd, Jim_GetResult(interp));
+ if (result < 0) {
+ Jim_SetResultErrno(interp, "error reading result");
+ }
+ close(tmpfd);
+
+ return result;
+}
+#endif
int Jim_execInit(Jim_Interp *interp)
{
diff --git a/jim-posix.c b/jim-posix.c
index a7dba75..e8cb6e6 100644
--- a/jim-posix.c
+++ b/jim-posix.c
@@ -35,6 +35,10 @@ static void Jim_PosixSetError(Jim_Interp *interp)
static int Jim_PosixForkCommand(Jim_Interp *interp, int argc,
Jim_Obj *const *argv)
{
+#ifdef NO_FORK
+ Jim_SetResultString(interp, "Not supported", -1);
+ return JIM_ERR;
+#else
pid_t pid;
JIM_NOTUSED(argv);
@@ -48,6 +52,7 @@ static int Jim_PosixForkCommand(Jim_Interp *interp, int argc,
}
Jim_SetResult(interp, Jim_NewIntObj(interp, (jim_wide)pid));
return JIM_OK;
+#endif
}
static int Jim_PosixGetidsCommand(Jim_Interp *interp, int argc,
diff --git a/jim.c b/jim.c
index 60b353f..03fcb43 100644
--- a/jim.c
+++ b/jim.c
@@ -2522,7 +2522,7 @@ static Jim_Obj *Jim_FormatString_Inner(Jim_Interp *interp, Jim_Obj *fmtObjPtr,
return NULL;
}
buflen = snprintf( sprintf_buf, JIM_MAX_FMT, fmt_str, doubleValue );
- snprintf( sprintf_buf, JIM_MAX_FMT, fmt_str, doubleValue );
+ break;
case 'b':
case 'd':
case 'o':
diff --git a/make-jim-load-extensions.sh b/make-jim-load-extensions.sh
new file mode 100644
index 0000000..c9b25cc
--- /dev/null
+++ b/make-jim-load-extensions.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+exec >$1
+
+shift
+
+exts=$(echo "$@" | sed -e 's@[^ ]*jim-@@g' -e 's@[.]c@@g')
+
+echo '#include "jim.h"'
+for name in $exts; do
+ echo "extern int Jim_${name}Init(Jim_Interp *interp);"
+done
+echo "int Jim_InitStaticExtensions(Jim_Interp *interp) {"
+for name in $exts; do
+ echo "if (Jim_${name}Init(interp) != JIM_OK) return JIM_ERR;"
+done
+ echo "return JIM_OK;"
+echo "}"
diff --git a/tcltests/test_bio.tcl b/tcltests/test_bio.tcl
index 16a40ae..c35977d 100644
--- a/tcltests/test_bio.tcl
+++ b/tcltests/test_bio.tcl
@@ -1,6 +1,9 @@
if {[info commands bio] eq ""} {
return "noimpl"
}
+if {[info commands verbose] eq ""} {
+ proc verbose {msg} {puts $msg}
+}
proc copy_binary_file {infile outfile} {
set in [open $infile r]
@@ -12,6 +15,14 @@ proc copy_binary_file {infile outfile} {
close $out
}
+proc copy_binary_file_direct {infile outfile} {
+ set in [open $infile r]
+ set out [open $outfile w]
+ bio copy $in $out
+ close $in
+ close $out
+}
+
proc copy_file {infile outfile} {
set in [open $infile r]
set out [open $outfile w]
@@ -37,46 +48,22 @@ proc copy_binary_file_hex {infile outfile} {
}
proc check_file {message filename} {
- set expected {
- 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d
- 1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b
- 3c3d3e3f404142434445464748494a4b4c4d4e4f50515253545556575859
- 5a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071727374757677
- 78797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495
- 969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3
- b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1
- d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef
- f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102
- }
-
# Does it look OK?
- set line 0
- exec xxd -p $filename >tmp.1
- set f [open "tmp.1" r]
- while {[gets $f buf] >= 0} {
- if {[lindex $expected $line] != $buf} {
- incr line
- puts $message
- puts "=========================================="
- puts "Failed match on line $line"
- puts "Exp: {[lindex $expected $line]}"
- puts "Got: {$buf}"
- error failed
- }
- incr line
+ set rc [catch {exec cmp -s $filename test.bin} error]
+ if {$rc != 0} {
+ puts "$message ($error)"
+ puts "=========================================="
+ puts "Did not match: $filename test.bin"
+ error failed
}
- close $f
verbose "$message -- ok"
}
# First create a binary file with the chars 0 - 255
set f [open bio.test w]
-bio write $f "\0010"
-bio write $f "\0011"
-for {set i 2} {$i < 256} {incr i} {
+for {set i 0} {$i < 256} {incr i} {
puts -nonewline $f [format %c $i]
}
-bio write $f "\0010\0011\002"
close $f
check_file "Create binary file from std encoding" bio.test
@@ -85,7 +72,6 @@ set hex ""
for {set i 0} {$i < 256} {incr i} {
append hex [format %02x $i]
}
-append hex 000102
set f [open bio.test w]
bio write -hex $f $hex
close $f
@@ -93,6 +79,8 @@ check_file "Create binary file from hex encoding" bio.test
copy_binary_file bio.test bio.copy
check_file "Copy binary file with std encoding" bio.copy
+copy_binary_file_direct bio.test bio.copy
+check_file "Copy binary file with bio copy" bio.copy
copy_binary_file_hex bio.test bio.copy
check_file "Copy binary file with hex encoding" bio.copy
copy_file bio.test bio.copy
diff --git a/tcltests/test_exec.tcl b/tcltests/test_exec.tcl
new file mode 100644
index 0000000..bb9dbc8
--- /dev/null
+++ b/tcltests/test_exec.tcl
@@ -0,0 +1,17 @@
+if {[info commands exec] eq ""} {
+ return "noimpl"
+}
+if {[info commands verbose] eq ""} {
+ proc verbose {msg} {puts $msg}
+}
+
+set infile [open Makefile]
+set outfile [open exec.out w]
+
+exec cat <@$infile >@$outfile
+close $infile
+close $outfile
+
+exec cmp -s Makefile exec.out
+
+file delete exec.out