aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jim-aio.c49
-rw-r--r--jim_tcl.txt36
-rw-r--r--tests/aio.test30
3 files changed, 112 insertions, 3 deletions
diff --git a/jim-aio.c b/jim-aio.c
index 6d0e612..5c46966 100644
--- a/jim-aio.c
+++ b/jim-aio.c
@@ -1853,8 +1853,9 @@ static int JimAioOpenCommand(Jim_Interp *interp, int argc,
Jim_Obj *const *argv)
{
const char *mode;
- FILE *fh;
+ FILE *fh = NULL;
const char *filename;
+ int fd = -1;
if (argc != 2 && argc != 3) {
Jim_WrongNumArgs(interp, 1, argv, "filename ?mode?");
@@ -1879,15 +1880,57 @@ static int JimAioOpenCommand(Jim_Interp *interp, int argc,
}
}
#endif
+#ifndef JIM_ANSIC
+ if (*mode == 'R' || *mode == 'W') {
+ /* POSIX flags */
+ static const char * const modetypes[] = {
+ "RDONLY", "WRONLY", "RDWR", "APPEND", "BINARY", "CREAT", "EXCL", "NOCTTY", "TRUNC", NULL
+ };
+ static const char * const simplemodes[] = {
+ "r", "w", "w+"
+ };
+ static const int modeflags[] = {
+ O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, 0, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC,
+ };
+ int posixflags = 0;
+ int len = Jim_ListLength(interp, argv[2]);
+ int i;
+ int opt;
- fh = fopen(filename, mode);
+ mode = NULL;
+
+ for (i = 0; i < len; i++) {
+ Jim_Obj *objPtr = Jim_ListGetIndex(interp, argv[2], i);
+ if (Jim_GetEnum(interp, objPtr, modetypes, &opt, "access mode", JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (opt < 3) {
+ mode = simplemodes[opt];
+ }
+ posixflags |= modeflags[opt];
+ }
+ /* mode must be set here if it started with 'R' or 'W' and passed the enum check above */
+ assert(mode);
+ fd = open(filename, posixflags, 0666);
+ if (fd >= 0) {
+ fh = fdopen(fd, mode);
+ if (fh == NULL) {
+ close(fd);
+ }
+ }
+ }
+ else
+#endif
+ {
+ fh = fopen(filename, mode);
+ }
if (fh == NULL) {
JimAioSetError(interp, argv[1]);
return JIM_ERR;
}
- return JimMakeChannel(interp, fh, -1, argv[1], "aio.handle%ld", 0, mode, 0) ? JIM_OK : JIM_ERR;
+ return JimMakeChannel(interp, fh, fd, argv[1], "aio.handle%ld", 0, mode, 0) ? JIM_OK : JIM_ERR;
}
#if defined(JIM_SSL) && !defined(JIM_BOOTSTRAP)
diff --git a/jim_tcl.txt b/jim_tcl.txt
index 1889ac9..88b62f5 100644
--- a/jim_tcl.txt
+++ b/jim_tcl.txt
@@ -64,6 +64,7 @@ Changes since 0.80
7. Add support for `lsearch -index` and `lsearch -stride`, the latter per TIP 351
8. `lsort -index` now supports multiple indices
9. Add support for `lsort -stride`
+10. `open` now supports POSIX-style access arguments
Changes between 0.79 and 0.80
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -3506,6 +3507,41 @@ It may have any of the following values:
+'access'+ defaults to 'r'.
+Additionally, if POSIX mode is supported by the underlying system,
+then access may insted of consistent of a list of any of the following
+flags, all of which have the standard POSIX meanings. In this case,
+the first flag *must* be one of RDONLY, WRONLY or RDWR.
+
++RDONLY+::
+ Open the file for reading only.
+
++WRONLY+::
+ Open the file for writing only.
+
++RDWR+::
+ Open the file for both reading and writing.
+
++APPEND+::
+ Set the file pointer to the end of the file prior to each write.
+
++BINARY+::
+ Ignored.
+
++CREAT+::
+ Create the file if it does not already exist (without this flag
+ it is an error for the file not to exist).
+
++EXCL+::
+ If CREAT is also specified, an error is returned if the file
+ already exists.
+
++NOCTTY+::
+ If the file is a terminal device, this flag prevents the file
+ from becoming the controlling terminal of the process.
+
++TRUNC+::
+ If the file exists it is truncated to zero length.
+
If a file is opened for both reading and writing, then `seek`
must be invoked between a read and a write, or vice versa.
diff --git a/tests/aio.test b/tests/aio.test
index 4b04dbd..12e41ab 100644
--- a/tests/aio.test
+++ b/tests/aio.test
@@ -2,6 +2,7 @@ source [file dirname [info script]]/testing.tcl
needs constraint jim
testCmdConstraints socket
+testConstraint unix [expr {$tcl_platform(platform) eq {unix}}]
# Create and open in binary mode for compatibility between Windows and Unix
set f [open testdata.in wb]
@@ -11,6 +12,7 @@ set f [open testdata.in rb]
defer {
$f close
+ file delete testdata.in
}
test aio-1.1 {seek usage} -body {
@@ -126,4 +128,32 @@ test aio-8.1 {filename} {
$f filename
} testdata.in
+test aio-9.1 {open: posix modes} -constraints unix -body {
+ set in [open testdata.in RDONLY]
+ set buf [$in gets]
+ $in close
+ set buf
+} -result {test-data}
+
+test aio-9.2 {open: posix modes, bad modes} -constraints unix -body {
+ open testdata.in {CREAT TRUNC}
+} -returnCodes error -result {testdata.in: Invalid argument}
+
+test aio-9.3 {open: posix modes, bad modes} -constraints unix -body {
+ open testdata.in {WRONG TRUNC}
+} -returnCodes error -result {bad access mode "WRONG": must be APPEND, BINARY, CREAT, EXCL, NOCTTY, RDONLY, RDWR, TRUNC, or WRONLY}
+
+test aio-9.4 {open: posix modes} -constraints unix -cleanup {
+ file delete testdata.out
+} -body {
+ set out [open testdata.out {WRONLY CREAT TRUNC}]
+ $out puts write-data
+ $out close
+ # Now open for readwrite without truncate
+ set io [open testdata.out {RDWR CREAT}]
+ set buf [$io gets]
+ $io close
+ set buf
+} -result {write-data}
+
testreport