aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew J. Schorr <aschorr@telemetry-investments.com>2012-04-07 16:30:50 -0400
committerAndrew J. Schorr <aschorr@telemetry-investments.com>2012-04-07 16:30:50 -0400
commitbc9ed3fd239984429613095e6cfc142092f036c4 (patch)
treea005a7ca9054b90af87d2a7b4d8b11a0607e80b8
parentaa23de50eb7c81a3e8f94769c5288aecfeb52b4c (diff)
downloadegawk-bc9ed3fd239984429613095e6cfc142092f036c4.tar.gz
egawk-bc9ed3fd239984429613095e6cfc142092f036c4.tar.bz2
egawk-bc9ed3fd239984429613095e6cfc142092f036c4.zip
Extension enhancements and tests.
-rw-r--r--ChangeLog4
-rw-r--r--TODO.xgawk17
-rw-r--r--extension/ChangeLog8
-rw-r--r--extension/filefuncs.c73
-rw-r--r--extension/fork.c20
-rw-r--r--test/ChangeLog8
-rw-r--r--test/Makefile.am35
-rw-r--r--test/filefuncs.awk25
-rw-r--r--test/filefuncs.ok0
-rw-r--r--test/fork.awk33
-rw-r--r--test/fork.ok0
-rw-r--r--test/fork2.awk35
-rw-r--r--test/fork2.ok0
-rw-r--r--test/ordchr.awk5
-rw-r--r--test/ordchr.ok1
15 files changed, 243 insertions, 21 deletions
diff --git a/ChangeLog b/ChangeLog
index ec3279ea..16febe5e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/TODO.xgawk b/TODO.xgawk
index 7a06b0fb..421eae24 100644
--- a/TODO.xgawk
+++ b/TODO.xgawk
@@ -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