diff options
-rw-r--r-- | Makefile.in | 11 | ||||
-rw-r--r-- | jim-aio.c | 9 | ||||
-rw-r--r-- | jim-bio.c | 90 | ||||
-rw-r--r-- | jim-exec.c | 179 | ||||
-rw-r--r-- | jim-posix.c | 5 | ||||
-rw-r--r-- | jim.c | 2 | ||||
-rw-r--r-- | make-jim-load-extensions.sh | 18 | ||||
-rw-r--r-- | tcltests/test_bio.tcl | 52 | ||||
-rw-r--r-- | tcltests/test_exec.tcl | 17 |
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: @@ -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; @@ -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 } }; @@ -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, @@ -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 |