diff options
author | Andrew J. Schorr <aschorr@telemetry-investments.com> | 2012-04-07 16:30:50 -0400 |
---|---|---|
committer | Andrew J. Schorr <aschorr@telemetry-investments.com> | 2012-04-07 16:30:50 -0400 |
commit | bc9ed3fd239984429613095e6cfc142092f036c4 (patch) | |
tree | a005a7ca9054b90af87d2a7b4d8b11a0607e80b8 | |
parent | aa23de50eb7c81a3e8f94769c5288aecfeb52b4c (diff) | |
download | egawk-bc9ed3fd239984429613095e6cfc142092f036c4.tar.gz egawk-bc9ed3fd239984429613095e6cfc142092f036c4.tar.bz2 egawk-bc9ed3fd239984429613095e6cfc142092f036c4.zip |
Extension enhancements and tests.
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | TODO.xgawk | 17 | ||||
-rw-r--r-- | extension/ChangeLog | 8 | ||||
-rw-r--r-- | extension/filefuncs.c | 73 | ||||
-rw-r--r-- | extension/fork.c | 20 | ||||
-rw-r--r-- | test/ChangeLog | 8 | ||||
-rw-r--r-- | test/Makefile.am | 35 | ||||
-rw-r--r-- | test/filefuncs.awk | 25 | ||||
-rw-r--r-- | test/filefuncs.ok | 0 | ||||
-rw-r--r-- | test/fork.awk | 33 | ||||
-rw-r--r-- | test/fork.ok | 0 | ||||
-rw-r--r-- | test/fork2.awk | 35 | ||||
-rw-r--r-- | test/fork2.ok | 0 | ||||
-rw-r--r-- | test/ordchr.awk | 5 | ||||
-rw-r--r-- | test/ordchr.ok | 1 |
15 files changed, 243 insertions, 21 deletions
@@ -1,3 +1,7 @@ +2012-04-07 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * TODO.xgawk: Update to reflect progress. + 2012-04-01 Andrew J. Schorr <aschorr@telemetry-investments.com> * TODO.xgawk: Move valgrind-noleak item into "done" section. @@ -21,9 +21,21 @@ Done: - Add valgrind-noleak target. +- Fix minor bug in fork extension, and add wait function. + +- Patch filefuncs extension to read symbolic links more robustly. + +- Add shared library tests. + To do (not necessarily in this order): +- Enhance extension/fork.c waitpid to allow the caller to specify the options. + And add an optional array argument to wait and waitpid in which to return + exit status information. + +- Maybe add more shared library tests. + - Figure out how to support xgawk on platforms such as Cygwin where a DLL cannot be linked with unresolved references. There are currently 3 possible solutions: @@ -50,11 +62,6 @@ To do (not necessarily in this order): defined but not used. So there should probably be an enhancement to func_use and ftable to indicate if it's a shared library function. -- Patch standard extensions to work properly. For example, fork is broken. - And I think we made a few improvements in the xgawk versions. - -- Add tests for standard extensions. - - Develop a libgawk shared library for use by extensions. In particular, a few existing extensions use a hash API for mapping string handles to structures. In xgawk, we had this API inside array.c, but it probably diff --git a/extension/ChangeLog b/extension/ChangeLog index 287ce309..994b3c92 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -1,3 +1,11 @@ +2012-04-07 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * filefuncs.c: Remove unnecessary #include <sys/sysmacros.h>. + (read_symlink): New function to read symbolic links more robustly. + (do_stat): Use read_symlink instead of readlink. + * fork.c (do_wait): new function. + (dlload): Call make_builtin to add "wait" function. + 2012-04-02 Andrew J. Schorr <aschorr@telemetry-investments.com> * fork.c (do_fork): Test whether PROCINFO_node exists before updating diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 63010c35..6d46c5e5 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -29,8 +29,6 @@ #include "awk.h" -#include <sys/sysmacros.h> - int plugin_is_GPL_compatible; /* do_chdir --- provide dynamically loaded chdir() builtin for gawk */ @@ -157,6 +155,60 @@ format_mode(unsigned long fmode) return outbuf; } +/* read_symlink -- read a symbolic link into an allocated buffer. + This is based on xreadlink; the basic problem is that lstat cannot be relied + upon to return the proper size for a symbolic link. This happens, + for example, on linux in the /proc filesystem, where the symbolic link + sizes are often 0. */ + +#ifndef SIZE_MAX +# define SIZE_MAX ((size_t) -1) +#endif +#ifndef SSIZE_MAX +# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) +#endif + +#define MAXSIZE (SIZE_MAX < SSIZE_MAX ? SIZE_MAX : SSIZE_MAX) + +static char * +read_symlink(const char *fname, size_t bufsize, ssize_t *linksize) +{ + if (bufsize) + bufsize += 2; + else + bufsize = BUFSIZ*2; + /* Make sure that bufsize >= 2 and within range */ + if ((bufsize > MAXSIZE) || (bufsize < 2)) + bufsize = MAXSIZE; + while (1) { + char *buf; + + emalloc(buf, char *, bufsize, "read_symlink"); + if ((*linksize = readlink(fname, buf, bufsize)) < 0) { + /* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink + returns -1 with errno == ERANGE if the buffer is + too small. */ + if (errno != ERANGE) { + free(buf); + return NULL; + } + } + /* N.B. This test is safe because bufsize must be >= 2 */ + else if ((size_t)*linksize <= bufsize-2) { + buf[*linksize] = '\0'; + return buf; + } + free(buf); + if (bufsize <= MAXSIZE/2) + bufsize *= 2; + else if (bufsize < MAXSIZE) + bufsize = MAXSIZE; + else + return NULL; + } + return NULL; +} + /* do_stat --- provide a stat() function for gawk */ static NODE * @@ -265,22 +317,17 @@ do_stat(int nargs) /* for symbolic links, add a linkval field */ if (S_ISLNK(sbuf.st_mode)) { char *buf; - int linksize; - - emalloc(buf, char *, sbuf.st_size + 2, "do_stat"); - if (((linksize = readlink(file->stptr, buf, - sbuf.st_size + 2)) >= 0) && - (linksize <= sbuf.st_size)) { - /* - * set the linkval field only if we are able to - * retrieve the entire link value successfully. - */ - buf[linksize] = '\0'; + ssize_t linksize; + if ((buf = read_symlink(file->stptr, sbuf.st_size, + &linksize)) != NULL) { aptr = assoc_lookup(array, tmp = make_string("linkval", 7)); *aptr = make_str_node(buf, linksize, ALREADY_MALLOCED); unref(tmp); } + else + warning(_("unable to read symbolic link `%s'"), + file->stptr); } /* add a type field */ diff --git a/extension/fork.c b/extension/fork.c index 7d6ab362..5a6e96d5 100644 --- a/extension/fork.c +++ b/extension/fork.c @@ -93,6 +93,25 @@ do_waitpid(int nargs) return make_number((AWKNUM) ret); } + +/* do_wait --- provide dynamically loaded wait() builtin for gawk */ + +static NODE * +do_wait(int nargs) +{ + int ret; + + if (do_lint && nargs > 0) + lintwarn("wait: called with too many arguments"); + + ret = wait(NULL); + if (ret < 0) + update_ERRNO_int(errno); + + /* Set the return value */ + return make_number((AWKNUM) ret); +} + /* dlload --- load new builtins in this library */ NODE * @@ -102,5 +121,6 @@ void *dl; { make_builtin("fork", do_fork, 0); make_builtin("waitpid", do_waitpid, 1); + make_builtin("wait", do_wait, 0); return make_number((AWKNUM) 0); } diff --git a/test/ChangeLog b/test/ChangeLog index 236288e2..5993ca23 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,11 @@ +2012-04-07 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * Makefile.am (check): Add new shlib-tests target. + (SHLIB_TESTS): Add tests ordchr, ordchr2, fork, fork2, readfile and + filefuncs. + * ordchr.awk, ordchr.ok, fork.awk, fork.ok, fork2.awk, fork2.ok, + filefuncs.awk, filefuncs.ok: New files. + 2012-04-01 Andrew J. Schorr <aschorr@telemetry-investments.com> * Makefile.am (valgrind-scan): Update to match modern valgrind output. diff --git a/test/Makefile.am b/test/Makefile.am index afd98299..854a8f7c 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -201,6 +201,8 @@ EXTRA_DIST = \ fieldwdth.awk \ fieldwdth.in \ fieldwdth.ok \ + filefuncs.awk \ + filefuncs.ok \ fldchg.awk \ fldchg.in \ fldchg.ok \ @@ -230,6 +232,8 @@ EXTRA_DIST = \ fnmisc.ok \ fnparydl.awk \ fnparydl.ok \ + fork.awk \ + fork2.awk \ fpat1.awk \ fpat1.in \ fpat1.ok \ @@ -522,6 +526,8 @@ EXTRA_DIST = \ opasnidx.ok \ opasnslf.awk \ opasnslf.ok \ + ordchr.awk \ + ordchr.ok \ out1.ok \ out2.ok \ out3.ok \ @@ -846,6 +852,8 @@ LOCALE_CHARSET_TESTS = \ asort asorti fmttest fnarydel fnparydl lc_num1 mbfw1 \ mbprintf1 mbprintf2 mbprintf3 rebt8b2 rtlenmb sort1 sprintfc +SHLIB_TESTS = ordchr ordchr2 fork fork2 readfile filefuncs + # List of the tests which should be run with --lint option: NEED_LINT = \ defref fmtspcl lintwarn noeffect nofmtch shadow \ @@ -870,8 +878,10 @@ PGAWKPROG = ../pgawk$(EXEEXT) # # This can also be done in individual tests where we wish to # check things specifically not in the C locale. -AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG) -PGAWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(PGAWKPROG) +# +# And we set AWKLIBPATH to find the extension libraries we built. +AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} AWKLIBPATH=../extension/.libs $(AWKPROG) +PGAWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} AWKLIBPATH=../extension/.libs $(PGAWKPROG) # Message stuff is to make it a little easier to follow. # Make the pass-fail last and dependent on others to avoid @@ -882,7 +892,8 @@ check: msg \ unix-msg-start unix-tests unix-msg-end \ extend-msg-start gawk-extensions extend-msg-end \ machine-msg-start machine-tests machine-msg-end \ - charset-msg-start charset-tests charset-msg-end + charset-msg-start charset-tests charset-msg-end \ + shlib-msg-start shlib-tests shlib-msg-end @$(MAKE) pass-fail basic: $(BASIC_TESTS) @@ -899,6 +910,8 @@ inet: inetmesg $(INET_TESTS) machine-tests: $(MACHINE_TESTS) +shlib-tests: $(SHLIB_TESTS) + msg:: @echo '' @echo 'Any output from "cmp" is bad news, although some differences' @@ -939,6 +952,12 @@ charset-msg-start: charset-msg-end: @echo "======== Done with tests that can vary based on character set or locale support ========" +shlib-msg-start: + @echo "======== Starting shared library tests ========" + +shlib-msg-end: + @echo "======== Done with shared library tests ========" + lc_num1: @echo $@ @@ -1444,6 +1463,16 @@ rri1:: AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ +ordchr2:: + @echo $@ + @$(AWK) -l ordchr 'BEGIN {print chr(ord("A"))}' >_$@ 2>&1 + @-$(CMP) $(srcdir)/ordchr.ok _$@ && rm -f _$@ + +readfile:: + @echo $@ + @$(AWK) -l readfile 'BEGIN {printf "%s", readfile("Makefile")}' 2>&1 \ + | $(CMP) Makefile - + # Targets generated for other tests: include Maketests diff --git a/test/filefuncs.awk b/test/filefuncs.awk new file mode 100644 index 00000000..aa532741 --- /dev/null +++ b/test/filefuncs.awk @@ -0,0 +1,25 @@ +@load "filefuncs" + +BEGIN { + if (chdir("..") < 0) { + printf "Error: chdir failed with ERRNO %s\n", ERRNO + exit 1 + } + + if (stat(ARGV[0], st) < 0) { + printf "Error: stat(%s) failed with ERRNO %s\n", ARGV[0], ERRNO + exit 1 + } + + nf = split("name dev ino mode nlink uid gid size blocks atime mtime ctime pmode type", f) + + for (i = 1; i <= nf; i++) { + if (!(f[i] in st)) { + printf "stat value for %s is missing\n",f[i] + rc = 1 + } + else + delete st[f[i]] + } + exit rc+0 +} diff --git a/test/filefuncs.ok b/test/filefuncs.ok new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/filefuncs.ok diff --git a/test/fork.awk b/test/fork.awk new file mode 100644 index 00000000..0b29f9ff --- /dev/null +++ b/test/fork.awk @@ -0,0 +1,33 @@ +@load "fork" + +BEGIN { + fn = ("fork.tmp." PROCINFO["pid"]) + switch (pid = fork()) { + case -1: + printf "Error: fork failed with ERRNO %s\n", ERRNO + exit 1 + case 0: + # child + printf "pid %s ppid %s\n", PROCINFO["pid"], PROCINFO["ppid"] > fn + exit 0 + default: + # parent + erc = 1 + if ((rc = wait()) < 0) + printf "Error: wait failed with ERRNO %s\n", ERRNO + else if (rc != pid) + printf "Error: wait returned %s instead of child pid %s\n", rc, pid + else if ((getline x < fn) != 1) + printf "Error: getline failed on temp file %s\n", fn + else { + expected = ("pid " pid " ppid " PROCINFO["pid"]) + if (x != expected) + printf "Error: child data (%s) != expected (%s)\n", x, expected + else if ((rc = system("rm " fn)) != 0) + printf "Error removing temp file %s with ERRNO %s\n", fn, ERRNO + else + erc = 0 + } + exit erc + } +} diff --git a/test/fork.ok b/test/fork.ok new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/fork.ok diff --git a/test/fork2.awk b/test/fork2.awk new file mode 100644 index 00000000..bd364286 --- /dev/null +++ b/test/fork2.awk @@ -0,0 +1,35 @@ +@load "fork" + +BEGIN { + # avoid instantiating PROCINFO prior to the fork + switch (pid = fork()) { + case -1: + printf "Error: fork failed with ERRNO %s\n", ERRNO + exit 1 + case 0: + # child + fn = ("fork.tmp." PROCINFO["pid"]) + printf "pid %s ppid %s\n", PROCINFO["pid"], PROCINFO["ppid"] > fn + exit 0 + default: + # parent + erc = 1 + fn = ("fork.tmp." pid) + if ((rc = wait()) < 0) + printf "Error: wait failed with ERRNO %s\n", ERRNO + else if (rc != pid) + printf "Error: wait returned %s instead of child pid %s\n", rc, pid + else if ((getline x < fn) != 1) + printf "Error: getline failed on temp file %s\n", fn + else { + expected = ("pid " pid " ppid " PROCINFO["pid"]) + if (x != expected) + printf "Error: child data (%s) != expected (%s)\n", x, expected + else if ((rc = system("rm " fn)) != 0) + printf "Error removing temp file %s with ERRNO %s\n", fn, ERRNO + else + erc = 0 + } + exit erc + } +} diff --git a/test/fork2.ok b/test/fork2.ok new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/fork2.ok diff --git a/test/ordchr.awk b/test/ordchr.awk new file mode 100644 index 00000000..abb793a0 --- /dev/null +++ b/test/ordchr.awk @@ -0,0 +1,5 @@ +@load "ordchr" + +BEGIN { + print chr(ord("A")) +} diff --git a/test/ordchr.ok b/test/ordchr.ok new file mode 100644 index 00000000..f70f10e4 --- /dev/null +++ b/test/ordchr.ok @@ -0,0 +1 @@ +A |