summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog111
-rw-r--r--Makefile.am15
-rw-r--r--Makefile.in17
-rw-r--r--README.git32
-rw-r--r--TODO.xgawk134
-rw-r--r--awk.h7
-rw-r--r--awkgram.y69
-rw-r--r--awklib/Makefile.in2
-rw-r--r--configure.ac8
-rw-r--r--doc/ChangeLog19
-rw-r--r--doc/Makefile.in2
-rw-r--r--doc/gawk.129
-rw-r--r--doc/gawk.texi114
-rw-r--r--eval.c22
-rw-r--r--ext.c3
-rw-r--r--extension/.gitignore3
-rw-r--r--extension/ChangeLog50
-rw-r--r--extension/Makefile.am57
-rw-r--r--extension/arrayparm.c2
-rw-r--r--extension/filefuncs.c189
-rw-r--r--extension/fork.c32
-rw-r--r--extension/readfile.c10
-rw-r--r--extension/rwarray.c4
-rw-r--r--gawkapi.h216
-rw-r--r--io.c116
-rw-r--r--main.c43
-rw-r--r--pc/ChangeLog4
-rw-r--r--pc/gawkmisc.pc2
-rw-r--r--posix/ChangeLog4
-rw-r--r--posix/gawkmisc.c1
-rw-r--r--test/ChangeLog33
-rw-r--r--test/Makefile.am42
-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
-rw-r--r--test/ordchr2.ok1
-rw-r--r--vms/ChangeLog4
-rw-r--r--vms/gawkmisc.vms1
43 files changed, 1284 insertions, 213 deletions
diff --git a/ChangeLog b/ChangeLog
index 6cbada6e..7f6c886f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,114 @@
+2012-04-09 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * eval.c (unset_ERRNO): Fix memory management bug -- need to use
+ dupnode with Nnull_string.
+
+2012-04-08 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (valgrind): Define VALGRIND instead of redefining AWK.
+ This allows test/Makefile.am to set up the command environment as
+ desired.
+ (valgrind-noleak): Ditto, plus set --leak-check=no instead of the
+ default summary setting.
+
+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.
+ * Makefile.am (valgrind-noleak): Add new valgrind rule that omits
+ the "--leak-check=full" option to help spot more serious problems.
+
+2012-04-01 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * TODO.xgawk: Move ERRNO item into "done" section.
+ * awk.h (update_ERRNO, update_ERRNO_saved): Remove declarations.
+ (update_ERRNO_int, enum errno_translate, update_ERRNO_string,
+ unset_ERRNO): Add new declarations.
+ * eval.c (update_ERRNO_saved): Renamed to update_ERRNO_int.
+ (update_ERRNO_string, unset_ERRNO): New functions.
+ * ext.c (do_ext): Use new update_ERRNO_string function.
+ * io.c (ERRNO_node): Remove redundant extern declaration (in awk.h).
+ (after_beginfile, nextfile): Replace update_ERRNO() with
+ update_ERRNO_int(errno).
+ (inrec): Replace update_ERRNO_saved with update_ERRNO_int.
+ (do_close): Use new function update_ERRNO_string.
+ (close_redir, do_getline_redir, do_getline): Replace update_ERRNO_saved
+ with update_ERRNO_int.
+
+2012-03-27 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * TODO.xgawk: Update to reflect debate about how to support Cygwin
+ and other platforms that cannot link shared libraries with unresolved
+ references.
+ * awkgram.y (add_srcfile): Minor bug fix: reverse sense of test
+ added by Arnold in last patch.
+ * configure.ac: AC_DISABLE_STATIC must come before AC_PROG_LIBTOOL.
+
+2012-03-26 Arnold D. Robbins <arnold@skeeve.com>
+
+ Some cleanups.
+
+ * awkgram.y (add_srcfile): Use whole messages, better for
+ translations.
+ * io.c (init_awkpath): Small style tweak.
+ * main.c (path_environ): Straighten out initial comment, fix
+ compiler warning by making `val' const char *.
+
+2012-03-25 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * configure.ac (AC_DISABLE_STATIC): Add this to avoid building useless
+ static extension libraries.
+
+2012-03-25 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * TODO.xgawk: New file listing completed and pending xgawk enhancements.
+
+2012-03-24 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * io.c (path_info): Fix white space.
+ (pi_awkpath, pi_awklibpath): Avoid structure initializers.
+ (do_find_source): Eliminate pointless parentheses.
+ (find_source): Leave a space after "&".
+ * main.c (load_environ): Fix typo in comment.
+
+2012-03-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * awkgram.y (LEX_LOAD): New token to support @load.
+ (grammar): Add rules to support @load.
+ (tokentab): Add "load".
+ (add_srcfile): Improve error message to distinguish between source files
+ and shared libraries.
+ (load_library): New function to load libraries specified with @load.
+ (yylex): Add support for LEX_LOAD (treated the same way as LEX_INCLUDE).
+
+2012-03-20 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (EXTRA_DIST): Remove extension.
+ (SUBDIRS): Add extension so libraries will be built.
+ (DEFS): Define DEFLIBPATH and SHLIBEXT so we can find shared libraries.
+ * awk.h (deflibpath): New extern declaration.
+ * configure.ac: Add support for building shared libraries by adding
+ AC_PROG_LIBTOOL and AC_SUBST for acl_shlibext and pkgextensiondir.
+ (AC_CONFIG_FILES): Add extension/Makefile.
+ * io.c (pi_awkpath, pi_awklibpath): New static structures to contain
+ path information.
+ (awkpath, max_pathlen): Remove static variables now inside pi_awkpath.
+ (init_awkpath): Operate on path_info structure to support both
+ AWKPATH and AWKLIBPATH. No need for max_path to be static, since
+ this should be called only once for each environment variable.
+ (do_find_source): Add a path_info arg to specify which path to search.
+ Check the try_cwd parameter to decide whether to search the current
+ directory (not desirable for AWKLIBPATH).
+ (find_source): Choose appropriate path_info structure based on value
+ of the is_extlib argument. Set EXTLIB_SUFFIX using SHLIBEXT define
+ instead of hardcoding ".so".
+ * main.c (path_environ): New function to add AWKPATH or AWKLIBPATH
+ to the ENVIRON array.
+ (load_environ): Call path_environ for AWKPATH and AWKLIBPATH.
+
2012-05-09 Arnold D. Robbins <arnold@skeeve.com>
* configure.ac: Added AC_HEADER_STDBOOL
diff --git a/Makefile.am b/Makefile.am
index 8f6ee12e..d92920b1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -48,7 +48,6 @@ EXTRA_DIST = \
config.rpath \
config.sub \
depcomp \
- extension \
m4 \
missing \
missing_d \
@@ -76,6 +75,7 @@ SUBDIRS = \
awklib \
doc \
po \
+ extension \
test
# what to make and install
@@ -137,7 +137,11 @@ pkgdatadir = $(datadir)/awk
# stuff for compiling gawk/pgawk
DEFPATH='".$(PATH_SEPARATOR)$(pkgdatadir)"'
-DEFS= -DDEFPATH=$(DEFPATH) -DHAVE_CONFIG_H -DGAWK -DLOCALEDIR='"$(datadir)/locale"'
+# shared library support:
+SHLIBEXT = "\"$(acl_shlibext)"\"
+DEFLIBPATH="\"$(pkgextensiondir)\""
+
+DEFS= -DDEFPATH=$(DEFPATH) -DDEFLIBPATH=$(DEFLIBPATH) -DSHLIBEXT=$(SHLIBEXT) -DHAVE_CONFIG_H -DGAWK -DLOCALEDIR='"$(datadir)/locale"'
# Get rid of core files when cleaning
CLEANFILES = core core.*
@@ -207,5 +211,10 @@ diffout valgrind-scan:
valgrind:
cd test; rm -f log.[0-9]*; \
- make check AWK="valgrind --leak-check=full --log-file=log.%p ../gawk"; \
+ make check VALGRIND="valgrind --leak-check=full --log-file=log.%p"; \
+ make valgrind-scan
+
+valgrind-noleak:
+ cd test; rm -f log.[0-9]*; \
+ make check VALGRIND="valgrind --leak-check=no --log-file=log.%p"; \
make valgrind-scan
diff --git a/Makefile.in b/Makefile.in
index 2d28a59c..79c9a008 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -209,7 +209,7 @@ CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
-DEFS = -DDEFPATH=$(DEFPATH) -DHAVE_CONFIG_H -DGAWK -DLOCALEDIR='"$(datadir)/locale"'
+DEFS = -DDEFPATH=$(DEFPATH) -DDEFLIBPATH=$(DEFLIBPATH) -DSHLIBEXT=$(SHLIBEXT) -DHAVE_CONFIG_H -DGAWK -DLOCALEDIR='"$(datadir)/locale"'
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
@@ -273,6 +273,7 @@ abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
+acl_shlibext = @acl_shlibext@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -307,6 +308,7 @@ mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
+pkgextensiondir = @pkgextensiondir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
@@ -344,7 +346,6 @@ EXTRA_DIST = \
config.rpath \
config.sub \
depcomp \
- extension \
m4 \
missing \
missing_d \
@@ -374,6 +375,7 @@ SUBDIRS = \
awklib \
doc \
po \
+ extension \
test
@@ -430,6 +432,10 @@ LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ @LIBMPFR@
# stuff for compiling gawk/pgawk
DEFPATH = '".$(PATH_SEPARATOR)$(pkgdatadir)"'
+# shared library support:
+SHLIBEXT = "\"$(acl_shlibext)"\"
+DEFLIBPATH = "\"$(pkgextensiondir)\""
+
# Get rid of core files when cleaning
CLEANFILES = core core.*
MAINTAINERCLEANFILES = version.c
@@ -1132,7 +1138,12 @@ diffout valgrind-scan:
valgrind:
cd test; rm -f log.[0-9]*; \
- make check AWK="valgrind --leak-check=full --log-file=log.%p ../gawk"; \
+ make check VALGRIND="valgrind --leak-check=full --log-file=log.%p"; \
+ make valgrind-scan
+
+valgrind-noleak:
+ cd test; rm -f log.[0-9]*; \
+ make check VALGRIND="valgrind --leak-check=no --log-file=log.%p"; \
make valgrind-scan
# Tell versions [3.59,3.63) of GNU make to not export all variables.
diff --git a/README.git b/README.git
index d7ff15b9..9de8575d 100644
--- a/README.git
+++ b/README.git
@@ -187,6 +187,13 @@ something to the repository.
git checkout my_stuff # change to branch my_stuff
git checkout -b my_stuff # create new branch my_stuff and change to it
+- How can I pull patches from a branch ?
+
+ git pull origin feature_branch
+
+The name of the branch can be omitted if your current branch is
+created to track the feature_branch ("git branch -t", see below).
+
- How can I create a branch ?
For each new feature to be considered for inclusion into future
@@ -195,7 +202,8 @@ branch shall be based on the master branch.
# make master branch the base
git checkout master
- git branch my_new_feature_branch
+ # create new feature branch and connect local to upstream branch
+ git branch -t my_new_feature_branch
touch my_new_file.c
git add my_new_file.c
git status
@@ -203,6 +211,18 @@ branch shall be based on the master branch.
git push -u origin my_new_feature_branch
git checkout my_new_feature_branch
+
+- How can I merge recent patches from the master branch ?
+
+My feature branch has been created as describe above (based on master).
+While I committed and pushed up my changes, the master branch has also changed.
+Now I want to catch up with recent changes in the master branch.
+
+ git diff origin/master # What is in master that I don't have ?
+ git merge origin/master # Merge all master patches into local rep
+ git push -u origin my_new_feature_branch # Push these local changes up
+
+
- How can I throw away an obsolete branch ?
git push origin :newfeature # remove remote branch
@@ -218,6 +238,10 @@ branch shall be based on the master branch.
If you have already committed the change and want back the
last pushed version, use "git reset" instead.
+- I have committed stupid changes, how can I undo the "git commit" ?
+
+ http://stackoverflow.com/questions/927358/git-undo-last-commit
+
- Who changed a specific line in my file ?
@@ -243,6 +267,12 @@ You can inspect the log history file-wise but also directory-wise.
git gc
+- How can I change settings with an editor (without "git xxx" command) ?
+
+This is useful for inspecting the settings of local and remote branches that track each other.
+
+ vi .git/config
+
- I'm a devoted user of Bazaar, and don't want to switch to git. Is
there any way for me to track Gawk development with bzr?
diff --git a/TODO.xgawk b/TODO.xgawk
new file mode 100644
index 00000000..421eae24
--- /dev/null
+++ b/TODO.xgawk
@@ -0,0 +1,134 @@
+To-do list for xgawk enhancements:
+
+
+Done:
+
+- Add AWKLIBPATH with default pointing to ${libexecdir}/$PACKAGE/$VERSION
+
+- Change default shared library extension from ".so" to ".$shlibext"
+
+- Patch build infrastructure so that the current code in the
+ extension subdirectory gets built and installed into the default $AWKLIBPATH
+ location.
+
+- Implement @load
+
+- Patch ERRNO handling to create a simple API for use by extensions:
+ extern void update_ERRNO_int(int)
+ enum errno_translate { TRANSLATE, DONT_TRANSLATE };
+ extern void update_ERRNO_string(const char *string, enum errno_translate);
+ extern void unset_ERRNO(void);
+
+- 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:
+ 1. Restructure gawk as a stub calling into a shared library.
+ 2. Move a subset of gawk interfaces into a shared library that can be
+ called by extensions.
+ 3. Change the interface between gawk and extensions so that gawk will
+ pass a pointer to a structure into dlload that contains the addresses
+ of all variables and functions to which the extension may need access.
+
+- Enable default ".awk" search in io.c:find_source(). The simple change
+ is to add this code inline in io.c:
+ #ifndef DEFAULT_FILETYPE
+ #define DEFAULT_FILETYPE ".awk"
+ #endif
+
+- Fix lint complaints about shared library functions being called without
+ having been defined. For example, try:
+ gawk --lint -lordchr 'BEGIN {print chr(65)}'
+ gawk: warning: function `chr' called but never defined
+ A
+ In ext.c, make_builtin needs to call awkgram.y:func_use. If done naively,
+ I think this would result in complaints about shared library functions
+ 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.
+
+- 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
+ belongs in a separate libgawk shared library:
+
+ typedef struct _strhash strhash;
+ extern strhash *strhash_create P((size_t min_table_size));
+ /* Find an entry in the hash table. If it is not found, the insert_if_missing
+ argument indicates whether a new entry should be created. The caller
+ may set the "data" field to any desired value. If it is a new entry,
+ "data" will be initialized to NULL. */
+ extern strhash_entry *strhash_get P((strhash *, const char *s, size_t len,
+ int insert_if_missing));
+ typedef void (*strhash_delete_func)(void *data, void *opaque,
+ strhash *, strhash_entry *);
+ extern int strhash_delete P((strhash *, const char *s, size_t len,
+ strhash_delete_func, void *opaque));
+ extern void strhash_destroy P((strhash *, strhash_delete_func, void *opaque));
+
+- Running "make install" should install the new libgawk shared library
+ as well as header files needed to build extensions under /usr/include/gawk.
+ The extensions include "awk.h", and that pulls in the following headers
+ (according to gcc -M) :
+ awk.h config.h custom.h gettext.h mbsupport.h protos.h getopt.h \
+ regex.h dfa.h
+ Most likely, most of this is not required. Arnold has suggested
+ creating a smaller header to define the public interface for use by shared
+ libraries. One could imagine having "awk-ext.h" that is included by "awk.h".
+
+
+Separate projects for major standalone extensions. Where should these
+be hosted?
+
+- Time. This defines sleep and gettimeofday. This one is quite trivial,
+ and I propose that it be included in the mainline gawk distro.
+
+- XML
+
+- PostgreSQL
+
+- GD
+
+- MPFR. Is this still useful if MPFR support will be integrated into gawk?
+
+
+Possible changes requiring (further) discussion:
+
+- Change from dlopen to using the libltdl library (i.e. lt_dlopen).
+ This may support more platforms.
+
+- Implement namespaces. Arnold suggested the following in an email:
+ - Extend the definition of an 'identifier' to include "." as a valid character
+ although an identifier can't start with it.
+ - Extension libraries install functions and global variables with names
+ that have a "." in them: XML.parse(), XML.name, whatever.
+ - Awk code can read/write such variables and call such functions, but they
+ cannot define such functions
+ function XML.foo() { .. } # error
+ or create a variable with such a name if it doesn't exist. This would
+ be a run-time error, not a parse-time error.
+ - This last rule may be too restrictive.
+ I don't want to get into fancy rules a la perl and file-scope visibility
+ etc, I'd like to keep things simple. But how we design this is going
+ to be very important.
+
+- Include a sample rpm spec file in a new packaging subdirectory.
+
+- Patch lexer for @include and @load to make quotes optional.
+
+- Add a -i (--include) option.
diff --git a/awk.h b/awk.h
index 438cca03..b1f61338 100644
--- a/awk.h
+++ b/awk.h
@@ -1146,6 +1146,7 @@ extern const char def_strftime_format[];
extern char quote;
extern char *defpath;
+extern char *deflibpath;
extern char envsep;
extern char casetable[]; /* for case-independent regexp matching */
@@ -1474,8 +1475,10 @@ extern void set_CONVFMT(void);
extern void set_BINMODE(void);
extern void set_LINT(void);
extern void set_TEXTDOMAIN(void);
-extern void update_ERRNO(void);
-extern void update_ERRNO_saved(int);
+extern void update_ERRNO_int(int);
+enum errno_translate { TRANSLATE, DONT_TRANSLATE };
+extern void update_ERRNO_string(const char *string, enum errno_translate);
+extern void unset_ERRNO(void);
extern void update_NR(void);
extern void update_NF(void);
extern void update_FNR(void);
diff --git a/awkgram.y b/awkgram.y
index 22d8889d..4145c5f5 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -52,6 +52,7 @@ static INSTRUCTION *make_assignable(INSTRUCTION *ip);
static void dumpintlstr(const char *str, size_t len);
static void dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2);
static int include_source(INSTRUCTION *file);
+static int load_library(INSTRUCTION *file);
static void next_sourcefile(void);
static char *tokexpand(void);
@@ -164,7 +165,7 @@ extern double fmod(double x, double y);
%token LEX_AND LEX_OR INCREMENT DECREMENT
%token LEX_BUILTIN LEX_LENGTH
%token LEX_EOF
-%token LEX_INCLUDE LEX_EVAL
+%token LEX_INCLUDE LEX_EVAL LEX_LOAD
%token NEWLINE
/* Lowest to highest */
@@ -239,6 +240,11 @@ rule
want_source = FALSE;
yyerrok;
}
+ | '@' LEX_LOAD library statement_term
+ {
+ want_source = FALSE;
+ yyerrok;
+ }
;
source
@@ -256,6 +262,21 @@ source
{ $$ = NULL; }
;
+library
+ : FILENAME
+ {
+ if (load_library($1) < 0)
+ YYABORT;
+ efree($1->lextok);
+ bcfree($1);
+ $$ = NULL;
+ }
+ | FILENAME error
+ { $$ = NULL; }
+ | error
+ { $$ = NULL; }
+ ;
+
pattern
: /* empty */
{ $$ = NULL; rule = Rule; }
@@ -2296,8 +2317,12 @@ add_srcfile(int stype, char *src, SRCFILE *thisfile, int *already_included, int
*errcode = errno_val;
return NULL;
}
- fatal(_("can't open source file `%s' for reading (%s)"),
- src, errno_val ? strerror(errno_val) : _("reason unknown"));
+ /* use full messages to ease translation */
+ fatal(stype != SRC_EXTLIB
+ ? _("can't open source file `%s' for reading (%s)")
+ : _("can't open shared library `%s' for reading (%s)"),
+ src,
+ errno_val ? strerror(errno_val) : _("reason unknown"));
}
for (s = srcfiles->next; s != srcfiles; s = s->next) {
@@ -2378,6 +2403,41 @@ include_source(INSTRUCTION *file)
return 0;
}
+/* load_library --- load a shared library */
+
+static int
+load_library(INSTRUCTION *file)
+{
+ SRCFILE *s;
+ char *src = file->lextok;
+ int errcode;
+ int already_included;
+
+ if (do_traditional || do_posix) {
+ error_ln(file->source_line, _("@load is a gawk extension"));
+ return -1;
+ }
+
+ if (strlen(src) == 0) {
+ if (do_lint)
+ lintwarn_ln(file->source_line, _("empty filename after @load"));
+ return 0;
+ }
+
+ s = add_srcfile(SRC_EXTLIB, src, sourcefile, &already_included, &errcode);
+ if (s == NULL) {
+ if (already_included)
+ return 0;
+ error_ln(file->source_line,
+ _("can't open shared library `%s' for reading (%s)"),
+ src, errcode ? strerror(errcode) : _("reason unknown"));
+ return -1;
+ }
+
+ (void) load_ext(s->fullpath, "dlload", NULL);
+ return 0;
+}
+
/* next_sourcefile --- read program from the next source in srcfiles */
static void
@@ -3504,7 +3564,7 @@ retry:
static int warntab[sizeof(tokentab) / sizeof(tokentab[0])];
int class = tokentab[mid].class;
- if ((class == LEX_INCLUDE || class == LEX_EVAL)
+ if ((class == LEX_INCLUDE || class == LEX_LOAD || class == LEX_EVAL)
&& lasttok != '@')
goto out;
@@ -3540,6 +3600,7 @@ retry:
switch (class) {
case LEX_INCLUDE:
+ case LEX_LOAD:
want_source = TRUE;
break;
case LEX_EVAL:
diff --git a/awklib/Makefile.in b/awklib/Makefile.in
index 793e8ee8..81f90a5f 100644
--- a/awklib/Makefile.in
+++ b/awklib/Makefile.in
@@ -227,6 +227,7 @@ abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
+acl_shlibext = @acl_shlibext@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -261,6 +262,7 @@ mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
+pkgextensiondir = @pkgextensiondir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
diff --git a/configure.ac b/configure.ac
index a13572bb..df7904a3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -67,6 +67,8 @@ AC_PROG_YACC
AC_PROG_LN_S
AC_PROG_CC
AC_PROG_CPP
+AC_DISABLE_STATIC
+AC_PROG_LIBTOOL
AC_OBJEXT
AC_EXEEXT
@@ -99,6 +101,11 @@ fi
AC_SUBST(CFLAGS)
+# shared library suffix for dynamic loading:
+AC_SUBST(acl_shlibext)
+# default shared library location
+AC_SUBST([pkgextensiondir], ['${pkglibdir}'/$VERSION])
+
dnl checks for systems
AC_ZOS_USS
AC_ISC_POSIX
@@ -364,6 +371,7 @@ AH_BOTTOM([#include "custom.h"])
AC_CONFIG_FILES(Makefile
awklib/Makefile
+ extension/Makefile
doc/Makefile
po/Makefile.in
test/Makefile)
diff --git a/doc/ChangeLog b/doc/ChangeLog
index 240ca756..a04db485 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,22 @@
+2012-04-01 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawk.texi: Replace documentation of removed functions update_ERRNO and
+ update_ERRNO_saved with descriptions new functions update_ERRNO_int,
+ update_ERRNO_string and unset_ERRNO. And fix a couple of examples
+ to use update_ERRNO_int instead of update_ERRNO.
+
+2012-03-26 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawk.texi: Minor style edits.
+
+2012-03-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawk.texi, gawk.1: Document new @load keyword.
+
+2012-03-20 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawk.texi, gawk.1: Add AWKLIBPATH.
+
2012-04-27 Arnold D. Robbins <arnold@skeeve.com>
* gawk.texi: Add that -b affects output.
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 70c6abe3..bf4b45a1 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -222,6 +222,7 @@ abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
+acl_shlibext = @acl_shlibext@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
@@ -256,6 +257,7 @@ mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
+pkgextensiondir = @pkgextensiondir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
diff --git a/doc/gawk.1 b/doc/gawk.1
index f01ffbfe..dbc2582b 100644
--- a/doc/gawk.1
+++ b/doc/gawk.1
@@ -330,11 +330,10 @@ these options cause an immediate, successful exit.)
Load a shared library
.IR lib .
This searches for the library using the
-.B AWKPATH
-environment variable. The suffix
-.I .so
-in the library name is optional, and
-the library initialization routine is expected to be named
+.B AWKLIBPATH
+environment variable. If the initial search fails, another attempt will
+be made after appending the default shared library suffix for the platform.
+The library initialization routine is expected to be named
.BR dlload() .
.TP
.PD 0
@@ -574,6 +573,9 @@ and optional function definitions.
.RS
.PP
\fB@include "\fIfilename\fB"
+.br
+\fB@load "\fIfilename\fB"
+.br
\fIpattern\fB { \fIaction statements\fB }\fR
.br
\fBfunction \fIname\fB(\fIparameter list\fB) { \fIstatements\fB }\fR
@@ -605,6 +607,13 @@ In addition, lines beginning with
may be used to include other source files into your program,
making library use even easier.
.PP
+Lines beginning with
+.B @load
+may be used to load shared libraries into your program. This is equivalent
+to using the
+.B \-l
+option.
+.PP
The environment variable
.B AWKPATH
specifies a search path to use when finding source files named with
@@ -3639,6 +3648,16 @@ and
options.
.PP
The
+.B AWKLIBPATH
+environment variable can be used to provide a list of directories that
+.I gawk
+searches when looking for files named via the
+.B \-l
+and
+.B \-\^\-load
+options.
+.PP
+The
.B GAWK_READ_TIMEOUT
environment variable can be used to specify a timeout
in milliseconds for reading input from a terminal, pipe
diff --git a/doc/gawk.texi b/doc/gawk.texi
index 22215d93..d3f5c672 100644
--- a/doc/gawk.texi
+++ b/doc/gawk.texi
@@ -355,9 +355,12 @@ particular records in a file and perform operations upon them.
uses.
* AWKPATH Variable:: Searching directories for @command{awk}
programs.
+* AWKLIBPATH Variable:: Searching directories for @command{awk}
+ shared libraries.
* Other Environment Variables:: The environment variables.
* Exit Status:: @command{gawk}'s exit status.
* Include Files:: Including other files into your program.
+* Loading Shared Libraries:: Loading shared libraries into your program.
* Obsolete:: Obsolete Options and/or features.
* Undocumented:: Undocumented Options and Features.
* Regexp Usage:: How to Use Regular Expressions.
@@ -2927,6 +2930,7 @@ things in this @value{CHAPTER} that don't interest you right now.
* Environment Variables:: The environment variables @command{gawk} uses.
* Exit Status:: @command{gawk}'s exit status.
* Include Files:: Including other files into your program.
+* Loading Shared Libraries:: Loading shared libraries into your program.
* Obsolete:: Obsolete Options and/or features.
* Undocumented:: Undocumented Options and Features.
@end menu
@@ -3212,9 +3216,12 @@ that @command{gawk} accepts and then exit.
@cindex @code{-l} option
@cindex @code{--load} option
@cindex loading, library
-Load a shared library @var{lib}. This searches for the library using the @env{AWKPATH}
-environment variable. The suffix @samp{.so} in the library name is optional.
+Load a shared library @var{lib}. This searches for the library using the @env{AWKLIBPATH}
+environment variable. The correct library suffix for your platform will be
+supplied by default, so it need not be specified in the library name.
The library initialization routine should be named @code{dlload()}.
+An alternative is to use the @samp{@@load} keyword inside the program to load
+a shared library.
@item -L @r{[}value@r{]}
@itemx --lint@r{[}=value@r{]}
@@ -3593,6 +3600,8 @@ behaves.
@menu
* AWKPATH Variable:: Searching directories for @command{awk}
programs.
+* AWKLIBPATH Variable:: Searching directories for @command{awk}
+ shared libraries.
* Other Environment Variables:: The environment variables.
@end menu
@@ -3668,6 +3677,21 @@ sense: the @env{AWKPATH} environment variable is used to find the program
source files. Once your program is running, all the files have been
found, and @command{gawk} no longer needs to use @env{AWKPATH}.
+@node AWKLIBPATH Variable
+@subsection The @env{AWKLIBPATH} Environment Variable
+@cindex @env{AWKLIBPATH} environment variable
+@cindex directories, searching
+@cindex search paths
+@cindex search paths, for shared libraries
+@cindex differences in @command{awk} and @command{gawk}, @code{AWKLIBPATH} environment variable
+
+The @env{AWKLIBPATH} environment variable is similar to the @env{AWKPATH}
+variable, but it is used to search for shared libraries specified
+with the @option{-l} option rather than for source files. If the library
+is not found, the path is searched again after adding the appropriate
+shared library suffix for the platform. For example, on GNU/Linux systems,
+the suffix @samp{.so} is used.
+
@node Other Environment Variables
@subsection Other Environment Variables
@@ -3876,6 +3900,41 @@ As mentioned in @ref{AWKPATH Variable}, the current directory is always
searched first for source files, before searching in @env{AWKPATH},
and this also applies to files named with @samp{@@include}.
+@node Loading Shared Libraries
+@section Loading Shared Libraries Into Your Program
+
+This @value{SECTION} describes a feature that is specific to @command{gawk}.
+
+The @samp{@@load} keyword can be used to read external @command{awk} shared
+libraries. This allows you to link in compiled code that may offer superior
+performance and/or give you access to extended capabilities not supported
+by the @command{awk} language. The @env{AWKLIBPATH} variable is used to
+search for the shared library. Using @samp{@@load} is completely equivalent
+to using the @option{-l} command-line option.
+
+If the shared library is not initially found in @env{AWKLIBPATH}, another
+search is conducted after appending the platform's default shared library
+suffix to the filename. For example, on GNU/Linux systems, the suffix
+@samp{.so} is used.
+
+@example
+$ @kbd{gawk '@@load "ordchr"; BEGIN @{print chr(65)@}'}
+@print{} A
+@end example
+
+@noindent
+This is equivalent to the following example:
+
+@example
+$ @kbd{gawk -lordchr 'BEGIN @{print chr(65)@}'}
+@print{} A
+@end example
+
+@noindent
+For command-line usage, the @option{-l} option is more convenient,
+but @samp{@@load} is useful for embedding inside an @command{awk} source file
+that requires access to a shared library.
+
@node Obsolete
@section Obsolete Options and/or Features
@@ -12797,7 +12856,9 @@ does not affect the environment passed on to any programs that
Some operating systems may not have environment variables.
On such systems, the @code{ENVIRON} array is empty (except for
@w{@code{ENVIRON["AWKPATH"]}},
-@pxref{AWKPATH Variable}).
+@pxref{AWKPATH Variable} and
+@w{@code{ENVIRON["AWKLIBPATH"]}},
+@pxref{AWKLIBPATH Variable}).
@cindex @command{gawk}, @code{ERRNO} variable in
@cindex @code{ERRNO} variable
@@ -27959,6 +28020,11 @@ the @option{-f} command-line option
(@pxref{Options}).
@item
+The @env{AWKLIBPATH} environment variable for specifying a path search for
+the @option{-l} command-line option
+(@pxref{Options}).
+
+@item
The ability to use GNU-style long-named options that start with @option{--}
and the
@option{--characters-as-bytes},
@@ -30328,21 +30394,29 @@ This is a convenience macro that calls @code{get_actual_argument()}.
@cindex functions, return values@comma{} setting
@cindex @code{ERRNO} variable
-@cindex @code{update_ERRNO()} internal function
-@cindex internal function, @code{update_ERRNO()}
-@item void update_ERRNO(void)
+@cindex @code{update_ERRNO_int()} internal function
+@cindex internal function, @code{update_ERRNO_int()}
+@item void update_ERRNO_int(int errno_saved)
This function is called from within a C extension function to set
-the value of @command{gawk}'s @code{ERRNO} variable, based on the current
-value of the C @code{errno} global variable.
+the value of @command{gawk}'s @code{ERRNO} variable, based on the error
+value provided as the argument.
It is provided as a convenience.
@cindex @code{ERRNO} variable
-@cindex @code{update_ERRNO_saved()} internal function
-@cindex internal function, @code{update_ERRNO_saved()}
-@item void update_ERRNO_saved(int errno_saved)
+@cindex @code{update_ERRNO_string()} internal function
+@cindex internal function, @code{update_ERRNO_string()}
+@item void update_ERRNO_string(const char *string, enum errno_translate)
This function is called from within a C extension function to set
-the value of @command{gawk}'s @code{ERRNO} variable, based on the error
-value provided as the argument.
+the value of @command{gawk}'s @code{ERRNO} variable to a given string.
+The second argument determines whether the string is translated before being
+installed into @code{ERRNO}. It is provided as a convenience.
+
+@cindex @code{ERRNO} variable
+@cindex @code{unset_ERRNO()} internal function
+@cindex internal function, @code{unset_ERRNO()}
+@item void unset_ERRNO(void)
+This function is called from within a C extension function to set
+the value of @command{gawk}'s @code{ERRNO} variable to a null string.
It is provided as a convenience.
@cindex @code{ENVIRON} array
@@ -30468,11 +30542,11 @@ anywhere in the program.
@command{gawk} has a list of directories where it searches for libraries.
By default, the list includes directories that depend upon how gawk was built
-and installed (@pxref{AWKPATH Variable}). If you want @command{gawk}
+and installed (@pxref{AWKLIBPATH Variable}). If you want @command{gawk}
to look for libraries in your private directory, you have to tell it.
-The way to do it is to set the @env{AWKPATH} environment variable
-(@pxref{AWKPATH Variable}).
-@command{gawk} supplies the default suffix @samp{.so} if it is not
+The way to do it is to set the @env{AWKLIBPATH} environment variable
+(@pxref{AWKLIBPATH Variable}).
+@command{gawk} supplies the default shared library platform suffix if it is not
present in the name of the library.
If the name of your library is @file{mylib.so}, you can simply type
@@ -30484,7 +30558,7 @@ and @command{gawk} will do everything necessary to load in your library,
and then call your @code{dlload()} routine.
You can always specify the library using an absolute pathname, in which
-case @command{gawk} will not use @env{AWKPATH} to search for it.
+case @command{gawk} will not use @env{AWKLIBPATH} to search for it.
@node Sample Library
@appendixsubsec Example: Directory and File Operation Built-ins
@@ -30706,7 +30780,7 @@ is updated.
(void) force_string(newdir);
ret = chdir(newdir->stptr);
if (ret < 0)
- update_ERRNO();
+ update_ERRNO_int(errno);
@end example
Finally, the function returns the return value to the @command{awk} level:
@@ -30775,7 +30849,7 @@ If there's an error, it sets @code{ERRNO} and returns:
(void) force_string(file);
ret = lstat(file->stptr, & sbuf);
if (ret < 0) @{
- update_ERRNO();
+ update_ERRNO_int(errno);
return make_number((AWKNUM) ret);
@}
@end example
diff --git a/eval.c b/eval.c
index 2305bbb3..d3e38f03 100644
--- a/eval.c
+++ b/eval.c
@@ -988,10 +988,10 @@ set_TEXTDOMAIN()
*/
}
-/* update_ERRNO_saved --- update the value of ERRNO based on argument */
+/* update_ERRNO_int --- update the value of ERRNO based on argument */
void
-update_ERRNO_saved(int errcode)
+update_ERRNO_int(int errcode)
{
char *cp;
@@ -1004,12 +1004,24 @@ update_ERRNO_saved(int errcode)
ERRNO_node->var_value = make_string(cp, strlen(cp));
}
-/* update_ERRNO --- update the value of ERRNO based on errno */
+/* update_ERRNO_string --- update ERRNO with optionally translated string */
void
-update_ERRNO()
+update_ERRNO_string(const char *string, enum errno_translate translate)
{
- update_ERRNO_saved(errno);
+ if (translate == TRANSLATE)
+ string = gettext(string);
+ unref(ERRNO_node->var_value);
+ ERRNO_node->var_value = make_string(string, strlen(string));
+}
+
+/* unset_ERRNO --- eliminate the value of ERRNO */
+
+void
+unset_ERRNO(void)
+{
+ unref(ERRNO_node->var_value);
+ ERRNO_node->var_value = dupnode(Nnull_string);
}
/* update_NR --- update the value of NR */
diff --git a/ext.c b/ext.c
index 0f56849d..0f74ad15 100644
--- a/ext.c
+++ b/ext.c
@@ -243,8 +243,7 @@ do_ext(int nargs)
{
const char *emsg = _("Operation Not Supported");
- unref(ERRNO_node->var_value);
- ERRNO_node->var_value = make_string(emsg, strlen(emsg));
+ update_ERRNO_string(emsg, DONT_TRANSLATE);
return make_number((AWKNUM) -1);
}
diff --git a/extension/.gitignore b/extension/.gitignore
new file mode 100644
index 00000000..ee95901f
--- /dev/null
+++ b/extension/.gitignore
@@ -0,0 +1,3 @@
+# ignore files created by libtool
+*.l[oa]
+.libs
diff --git a/extension/ChangeLog b/extension/ChangeLog
index 0b3053ed..7c6976de 100644
--- a/extension/ChangeLog
+++ b/extension/ChangeLog
@@ -1,3 +1,53 @@
+2012-04-11 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * filefuncs.c (array_set): New function to set an array element.
+ (do_set): Use new array_set function to reduce code duplication and
+ to make sure the memory management is handled properly.
+
+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
+ the pid values. And do so properly using make_number.
+ * readfile.c (do_readfile): Function should be static.
+
+2012-04-01 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * filefuncs.c (do_chdir, do_stat): Replace update_ERRNO() with
+ update_ERRNO_int(errno).
+ * fork.c (do_fork, do_waitpid): Ditto.
+ * readfile.c (do_readfile): Ditto.
+ * rwarray.c (do_writea, do_reada): Ditto.
+
+2012-03-25 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am: Major cleanup. Use libtool options -module and
+ -avoid-version to create the modules properly without my local hack
+ to override the default behavior.
+
+2012-03-25 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * .gitignore: New file to ignore files created by libtool (including
+ binaries and associated metadata).
+
+2012-03-21 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (INCLUDES): Remove -I$(top_srcdir)/intl.
+
+2012-03-20 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am: New file to build and install shared libraries.
+ * arrayparm.c (do_mkarray): Get it to compile by removing 2nd arg
+ to assoc_clear.
+ * filefuncs.c (do_stat): Ditto.
+
2011-08-31 John Haque <j.eh@mchsi.com>
* arrayparm.c, filefuncs.c, fork.c, ordchr.c, readfile.c,
diff --git a/extension/Makefile.am b/extension/Makefile.am
new file mode 100644
index 00000000..a2f47229
--- /dev/null
+++ b/extension/Makefile.am
@@ -0,0 +1,57 @@
+#
+# extension/Makefile.am --- automake input file for gawk
+#
+# Copyright (C) 1995-2006 the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+#
+
+## Process this file with automake to produce Makefile.in.
+
+INCLUDES = -I.. -I$(top_srcdir)
+
+# The arrayparm, zaxxon (dl), and testarg libraries do not do anything useful,
+# so do not build or install them.
+
+# Note: rwarray does not currently compile.
+
+pkgextension_LTLIBRARIES = \
+ filefuncs.la \
+ fork.la \
+ ordchr.la \
+ readfile.la
+
+MY_MODULE_FLAGS = -module -avoid-version
+
+filefuncs_la_SOURCES = filefuncs.c
+filefuncs_la_LDFLAGS = $(MY_MODULE_FLAGS)
+fork_la_SOURCES = fork.c
+fork_la_LDFLAGS = $(MY_MODULE_FLAGS)
+ordchr_la_SOURCES = ordchr.c
+ordchr_la_LDFLAGS = $(MY_MODULE_FLAGS)
+readfile_la_SOURCES = readfile.c
+readfile_la_LDFLAGS = $(MY_MODULE_FLAGS)
+#rwarray_la_SOURCES = rwarray.c
+#rwarray_la_LDFLAGS = $(MY_MODULE_FLAGS)
+
+EXTRA_DIST = \
+ ChangeLog \
+ ChangeLog.0 \
+ *.awk \
+ doit \
+ steps
diff --git a/extension/arrayparm.c b/extension/arrayparm.c
index b0aee33d..1e28811e 100644
--- a/extension/arrayparm.c
+++ b/extension/arrayparm.c
@@ -60,7 +60,7 @@ do_mkarray(int nargs)
printf("sub->type = %s\n", nodetype2str(sub->type));
printf("val->type = %s\n", nodetype2str(val->type));
- assoc_clear(var, NULL);
+ assoc_clear(var);
elemval = assoc_lookup(var, sub);
*elemval = dupnode(val);
diff --git a/extension/filefuncs.c b/extension/filefuncs.c
index 1a0a86ef..8e5e8daa 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 */
@@ -48,7 +46,7 @@ do_chdir(int nargs)
(void) force_string(newdir);
ret = chdir(newdir->stptr);
if (ret < 0)
- update_ERRNO();
+ update_ERRNO_int(errno);
return make_number((AWKNUM) ret);
}
@@ -157,15 +155,83 @@ 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;
+}
+
+/* array_set --- set an array element */
+
+static void
+array_set(NODE *array, const char *sub, NODE *value)
+{
+ NODE *tmp;
+ NODE **aptr;
+
+ tmp = make_string(sub, strlen(sub));
+ aptr = assoc_lookup(array, tmp);
+ unref(tmp);
+ unref(*aptr);
+ *aptr = value;
+}
+
/* do_stat --- provide a stat() function for gawk */
static NODE *
do_stat(int nargs)
{
- NODE *file, *array, *tmp;
+ NODE *file, *array;
struct stat sbuf;
int ret;
- NODE **aptr;
char *pmode; /* printable mode */
char *type = "unknown";
@@ -177,110 +243,55 @@ do_stat(int nargs)
array = get_array_argument(1, FALSE);
/* empty out the array */
- assoc_clear(array, NULL);
+ assoc_clear(array);
/* lstat the file, if error, set ERRNO and return */
(void) force_string(file);
ret = lstat(file->stptr, & sbuf);
if (ret < 0) {
- update_ERRNO();
+ update_ERRNO_int(errno);
return make_number((AWKNUM) ret);
}
/* fill in the array */
- aptr = assoc_lookup(array, tmp = make_string("name", 4));
- *aptr = dupnode(file);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("dev", 3));
- *aptr = make_number((AWKNUM) sbuf.st_dev);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("ino", 3));
- *aptr = make_number((AWKNUM) sbuf.st_ino);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("mode", 4));
- *aptr = make_number((AWKNUM) sbuf.st_mode);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("nlink", 5));
- *aptr = make_number((AWKNUM) sbuf.st_nlink);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("uid", 3));
- *aptr = make_number((AWKNUM) sbuf.st_uid);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("gid", 3));
- *aptr = make_number((AWKNUM) sbuf.st_gid);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("size", 4));
- *aptr = make_number((AWKNUM) sbuf.st_size);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("blocks", 6));
- *aptr = make_number((AWKNUM) sbuf.st_blocks);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("atime", 5));
- *aptr = make_number((AWKNUM) sbuf.st_atime);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("mtime", 5));
- *aptr = make_number((AWKNUM) sbuf.st_mtime);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("ctime", 5));
- *aptr = make_number((AWKNUM) sbuf.st_ctime);
- unref(tmp);
+ array_set(array, "name", dupnode(file));
+ array_set(array, "dev", make_number((AWKNUM) sbuf.st_dev));
+ array_set(array, "ino", make_number((AWKNUM) sbuf.st_ino));
+ array_set(array, "mode", make_number((AWKNUM) sbuf.st_mode));
+ array_set(array, "nlink", make_number((AWKNUM) sbuf.st_nlink));
+ array_set(array, "uid", make_number((AWKNUM) sbuf.st_uid));
+ array_set(array, "gid", make_number((AWKNUM) sbuf.st_gid));
+ array_set(array, "size", make_number((AWKNUM) sbuf.st_size));
+ array_set(array, "blocks", make_number((AWKNUM) sbuf.st_blocks));
+ array_set(array, "atime", make_number((AWKNUM) sbuf.st_atime));
+ array_set(array, "mtime", make_number((AWKNUM) sbuf.st_mtime));
+ array_set(array, "ctime", make_number((AWKNUM) sbuf.st_ctime));
/* for block and character devices, add rdev, major and minor numbers */
if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) {
- aptr = assoc_lookup(array, tmp = make_string("rdev", 4));
- *aptr = make_number((AWKNUM) sbuf.st_rdev);
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("major", 5));
- *aptr = make_number((AWKNUM) major(sbuf.st_rdev));
- unref(tmp);
-
- aptr = assoc_lookup(array, tmp = make_string("minor", 5));
- *aptr = make_number((AWKNUM) minor(sbuf.st_rdev));
- unref(tmp);
+ array_set(array, "rdev", make_number((AWKNUM) sbuf.st_rdev));
+ array_set(array, "major", make_number((AWKNUM) major(sbuf.st_rdev)));
+ array_set(array, "minor", make_number((AWKNUM) minor(sbuf.st_rdev)));
}
#ifdef HAVE_ST_BLKSIZE
- aptr = assoc_lookup(array, tmp = make_string("blksize", 7));
- *aptr = make_number((AWKNUM) sbuf.st_blksize);
- unref(tmp);
+ array_set(array, "blksize", make_number((AWKNUM) sbuf.st_blksize));
#endif /* HAVE_ST_BLKSIZE */
- aptr = assoc_lookup(array, tmp = make_string("pmode", 5));
pmode = format_mode(sbuf.st_mode);
- *aptr = make_string(pmode, strlen(pmode));
- unref(tmp);
+ array_set(array, "pmode", make_string(pmode, strlen(pmode)));
/* 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';
-
- aptr = assoc_lookup(array, tmp = make_string("linkval", 7));
- *aptr = make_str_node(buf, linksize, ALREADY_MALLOCED);
- unref(tmp);
- }
+ ssize_t linksize;
+
+ if ((buf = read_symlink(file->stptr, sbuf.st_size,
+ &linksize)) != NULL)
+ array_set(array, "linkval", make_str_node(buf, linksize, ALREADY_MALLOCED));
+ else
+ warning(_("unable to read symbolic link `%s'"),
+ file->stptr);
}
/* add a type field */
@@ -319,9 +330,7 @@ do_stat(int nargs)
#endif
}
- aptr = assoc_lookup(array, tmp = make_string("type", 4));
- *aptr = make_string(type, strlen(type));
- unref(tmp);
+ array_set(array, "type", make_string(type, strlen(type)));
return make_number((AWKNUM) ret);
}
diff --git a/extension/fork.c b/extension/fork.c
index 88353879..5a6e96d5 100644
--- a/extension/fork.c
+++ b/extension/fork.c
@@ -44,16 +44,18 @@ do_fork(int nargs)
ret = fork();
if (ret < 0)
- update_ERRNO();
- else if (ret == 0) {
+ update_ERRNO_int(errno);
+ else if (ret == 0 && PROCINFO_node != NULL) {
/* update PROCINFO in the child */
aptr = assoc_lookup(PROCINFO_node, tmp = make_string("pid", 3));
- (*aptr)->numbr = (AWKNUM) getpid();
+ unref(*aptr);
+ *aptr = make_number((AWKNUM) getpid());
unref(tmp);
aptr = assoc_lookup(PROCINFO_node, tmp = make_string("ppid", 4));
- (*aptr)->numbr = (AWKNUM) getppid();
+ unref(*aptr);
+ *aptr = make_number((AWKNUM) getppid());
unref(tmp);
}
@@ -83,7 +85,7 @@ do_waitpid(int nargs)
options = WNOHANG|WUNTRACED;
ret = waitpid(pid, NULL, options);
if (ret < 0)
- update_ERRNO();
+ update_ERRNO_int(errno);
} else if (do_lint)
lintwarn("wait: called with no arguments");
@@ -91,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 *
@@ -100,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/extension/readfile.c b/extension/readfile.c
index c9b1efc3..57cf6cdd 100644
--- a/extension/readfile.c
+++ b/extension/readfile.c
@@ -41,7 +41,7 @@ int plugin_is_GPL_compatible;
/* do_readfile --- read a file into memory */
-NODE *
+static NODE *
do_readfile(int nargs)
{
NODE *filename;
@@ -59,18 +59,18 @@ do_readfile(int nargs)
ret = stat(filename->stptr, & sbuf);
if (ret < 0) {
- update_ERRNO();
+ update_ERRNO_int(errno);
goto done;
} else if ((sbuf.st_mode & S_IFMT) != S_IFREG) {
errno = EINVAL;
ret = -1;
- update_ERRNO();
+ update_ERRNO_int(errno);
goto done;
}
if ((fd = open(filename->stptr, O_RDONLY|O_BINARY)) < 0) {
ret = -1;
- update_ERRNO();
+ update_ERRNO_int(errno);
goto done;
}
@@ -80,7 +80,7 @@ do_readfile(int nargs)
if ((ret = read(fd, text, sbuf.st_size)) != sbuf.st_size) {
(void) close(fd);
ret = -1;
- update_ERRNO();
+ update_ERRNO_int(errno);
goto done;
}
diff --git a/extension/rwarray.c b/extension/rwarray.c
index 8175c7c0..f4f8cd58 100644
--- a/extension/rwarray.c
+++ b/extension/rwarray.c
@@ -115,7 +115,7 @@ do_writea(int nargs)
done1:
ret = -1;
- update_ERRNO();
+ update_ERRNO_int(errno);
unlink(file->stptr);
done0:
@@ -297,7 +297,7 @@ do_reada(int nargs)
done1:
ret = -1;
- update_ERRNO();
+ update_ERRNO_int(errno);
done0:
close(fd);
diff --git a/gawkapi.h b/gawkapi.h
new file mode 100644
index 00000000..8361ab2c
--- /dev/null
+++ b/gawkapi.h
@@ -0,0 +1,216 @@
+/*
+ * gawkapi.h -- Definitions for use by extension functions calling into gawk.
+ */
+
+/*
+ * Copyright (C) 2012, the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ *
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/*
+ * N.B. You must include <sys/types.h> and <sys/stat.h>
+ * before including this file!
+ */
+
+#ifndef _GAWK_API_H
+#define _GAWK_API_H
+
+ /* Allow the use in C++ code. */
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ typedef struct iobuf {
+ const char *name; /* filename */
+ int fd; /* file descriptor */
+ struct stat sbuf; /* stat buf */
+ char *buf; /* start data buffer */
+ char *off; /* start of current record in buffer */
+ char *dataend; /* first byte in buffer to hold new data,
+ NULL if not read yet */
+ char *end; /* end of buffer */
+ size_t readsize; /* set from fstat call */
+ size_t size; /* buffer size */
+ ssize_t count; /* amount read last time */
+ size_t scanoff; /* where we were in the buffer when we had
+ to regrow/refill */
+ /*
+ * No argument prototype on read_func. See get_src_buf()
+ * in awkgram.y.
+ */
+ ssize_t (*read_func)();
+
+ void *opaque; /* private data for open hooks */
+ int (*get_record)(char **out, struct iobuf *, int *errcode);
+ void (*close_func)(struct iobuf *); /* open and close hooks */
+
+ int errcode;
+
+ int flag;
+# define IOP_IS_TTY 1
+# define IOP_NOFREE_OBJ 2
+# define IOP_AT_EOF 4
+# define IOP_CLOSED 8
+# define IOP_AT_START 16
+ } IOBUF;
+
+#define GAWK_API_MAJOR_VERSION 0
+#define GAWK_API_MINOR_VERSION 0
+
+#define DO_FLAGS_SIZE 6
+
+ typedef enum {
+ AWK_UNDEFINED,
+ AWK_NUMBER,
+ AWK_CONST_STRING,
+ AWK_STRING,
+ AWK_ARRAY
+ } awk_valtype_t;
+
+ typedef struct {
+ const char *const str;
+ const size_t len;
+ } awk_const_string_t;
+
+ typedef struct {
+ char *str;
+ size_t len;
+ } awk_string_t;
+
+ typedef struct {
+ awk_valtype_t val_type;
+ union {
+ awk_const_string cs;
+ awk_string s;
+ double d;
+ void* a;
+ } u;
+#define const_str_val u.cs
+#define str_val u.s
+#define num_val u.d
+#define array_cookie u.a
+ } awk_value_t;
+
+
+ typedef struct {
+ const char *name;
+ size_t num_args;
+ void (*function)(int num_args);
+ } awk_ext_func_t;
+
+ typedef struct gawk_api {
+ int major_version;
+ int minor_version;
+
+ int do_flags[DO_FLAGS_SIZE];
+ /* Use these as indices into do_flags[] array to check the values */
+#define gawk_do_lint 0
+#define gawk_do_traditional 1
+#define gawk_do_profile 2
+#define gawk_do_sandbox 3
+#define gawk_do_debug 4
+#define gawk_do_mpfr 5
+
+ /* get the number of arguments passed in function call */
+ /* FIXME: Needed? Won't we pass the count in the real call? */
+ size_t (*get_curfunc_arg_count)(void *ext_id);
+ awk_value_t *(*get_curfunc_param)(void *ext_id, size_t count);
+
+ /* functions to print messages */
+ void (*fatal)(void *ext_id, const char *format, ...);
+ void (*warning)(void *ext_id, const char *format, ...);
+ void (*lintwarn)(void *ext_id, const char *format, ...);
+
+ /* register an open hook; for opening files read-only */
+ int (*register_open_hook)(void *ext_id,
+ void* (*open_func)(IOBUF *));
+
+ /* functions to update ERRNO */
+ void (*update_ERRNO_int)(void *ext_id, int);
+ void (*update_ERRNO_string)(void *ext_id, const char *string,
+ int translate);
+ void (*unset_ERRNO)(void *ext_id);
+
+ /* check if a value received from gawk is the null string */
+ int (*is_null_string)(void *ext_id, void *value);
+
+ /* add a function to the interpreter */
+ int *(add_ext_func)(void *ext_id, const awk_ext_func_t *func);
+
+ /* add an exit call back */
+ void (*awk_atexit)(void *ext_id, void (*funcp)(void *data, int exit_status), void *arg0);
+
+ /* Symbol table access */
+ awk_value_t *(*sym_lookup)(void *ext_id, const char *name);
+ int (*sym_update)(void *ext_id, const char *name, awk_value_t *value);
+ int (*sym_remove)(void *ext_id, const char *name);
+
+ /* Array management */
+ awk_value_t *(*get_array_element)(void *ext_id, void *a_cookie, const awk_value_t* const index);
+ awk_value_t *(*set_array_element)(void *ext_id, void *a_cookie,
+ const awk_value_t* const index, const awk_value_t* const value);
+ awk_value_t *(*del_array_element)(void *ext_id, void *a_cookie, const awk_value_t* const index);
+ size_t (*get_element_count)(void *ext_id, void *a_cookie);
+
+ } gawk_api_t;
+
+#ifndef GAWK /* these are not for the gawk code itself */
+ /*
+ * Use these if you want to define a "global" variable named api
+ * to make the code a little easier to read.
+ */
+#define do_lint api->do_flags[gawk_do_lint]
+#define do_traditional api->do_flags[gawk_do_traditional]
+#define do_profile api->do_flags[gawk_do_profile]
+#define do_sandbox api->do_flags[gawk_do_sandbox]
+#define do_debug api->do_flags[gawk_do_debug]
+
+#define get_curfunc_arg_count api->get_curfunc_arg_count
+#define get_curfunc_param api->get_curfunc_param
+
+#define fatal api->fatal
+#define warning api->warning
+#define lintwarn api->lintwarn
+
+#define register_open_hook api->register_open_hook
+
+#define update_ERRNO_int api->update_ERRNO_int
+#define update_ERRNO_string api->update_ERRNO_string
+#define unset_ERRNO api->unset_ERRNO
+
+#define is_null_string api->is_null_string
+
+#define add_ext_func api->add_ext_func
+#define awk_atexit api->awk_atexit
+
+#define sym_lookup api->sym_lookup
+#define sym_update api->sym_update
+#define sym_remove api->sym_remove
+
+#define get_array_element api->get_array_element
+#define set_array_element api->set_array_element
+#define del_array_element api->del_array_element
+#define get_element_count api->get_element_count
+#endif /* GAWK */
+
+#ifdef __cplusplus
+}
+#endif /* C++ */
+
+#endif /* _GAWK_API_H */
diff --git a/io.c b/io.c
index 7e46cd9a..9c47bad6 100644
--- a/io.c
+++ b/io.c
@@ -240,6 +240,10 @@ int RS_is_null;
extern NODE *ARGC_node;
extern NODE *ARGV_node;
extern NODE *ARGIND_node;
+<<<<<<< HEAD
+=======
+extern NODE **fields_arr;
+>>>>>>> xgawk
/* init_io --- set up timeout related variables */
@@ -319,7 +323,7 @@ after_beginfile(IOBUF **curfile)
errcode = iop->errcode;
iop->errcode = 0;
errno = 0;
- update_ERRNO();
+ update_ERRNO_int(errno);
iop_close(iop);
*curfile = NULL;
if (errcode == EISDIR && ! do_traditional) {
@@ -396,7 +400,7 @@ nextfile(IOBUF **curfile, int skipping)
fd = devopen(fname, binmode("r"));
errcode = errno;
if (! do_traditional)
- update_ERRNO();
+ update_ERRNO_int(errno);
unref(FILENAME_node->var_value);
FILENAME_node->var_value = dupnode(arg);
@@ -421,7 +425,7 @@ nextfile(IOBUF **curfile, int skipping)
/* FNR is init'ed to 0 */
errno = 0;
if (! do_traditional)
- update_ERRNO();
+ update_ERRNO_int(errno);
unref(FILENAME_node->var_value);
FILENAME_node->var_value = make_string("-", 1);
FILENAME_node->var_value->flags |= MAYBE_NUM; /* be pedantic */
@@ -432,7 +436,7 @@ nextfile(IOBUF **curfile, int skipping)
if (iop->fd == INVALID_HANDLE) {
errcode = errno;
errno = 0;
- update_ERRNO();
+ update_ERRNO_int(errno);
(void) iop_close(iop);
*curfile = NULL;
fatal(_("cannot open file `%s' for reading (%s)"),
@@ -493,7 +497,7 @@ inrec(IOBUF *iop, int *errcode)
if (cnt == EOF) {
retval = 1;
if (*errcode > 0)
- update_ERRNO_saved(*errcode);
+ update_ERRNO_int(*errcode);
} else {
INCREMENT_REC(NR);
INCREMENT_REC(FNR);
@@ -1020,8 +1024,7 @@ do_close(int nargs)
if (! do_traditional) {
/* update ERRNO manually, using errno = ENOENT is a stretch. */
cp = _("close of redirection that was never opened");
- unref(ERRNO_node->var_value);
- ERRNO_node->var_value = make_string(cp, strlen(cp));
+ update_ERRNO_string(cp, DONT_TRANSLATE);
}
DEREF(tmp);
@@ -1143,7 +1146,7 @@ close_redir(struct redirect *rp, int exitwarn, two_way_close_type how)
if (! do_traditional) {
/* set ERRNO too so that program can get at it */
- update_ERRNO_saved(save_errno);
+ update_ERRNO_int(save_errno);
}
}
@@ -2263,7 +2266,7 @@ do_getline_redir(int into_variable, enum redirval redirtype)
if (rp == NULL) {
if (redir_error) { /* failed redirect */
if (! do_traditional)
- update_ERRNO_saved(redir_error);
+ update_ERRNO_int(redir_error);
}
return make_number((AWKNUM) -1.0);
}
@@ -2274,8 +2277,13 @@ do_getline_redir(int into_variable, enum redirval redirtype)
errcode = 0;
cnt = get_a_record(& s, iop, & errcode);
if (errcode != 0) {
+<<<<<<< HEAD
if (! do_traditional && errcode != -1)
update_ERRNO_saved(errcode);
+=======
+ if (! do_traditional && (errcode != -1))
+ update_ERRNO_int(errcode);
+>>>>>>> xgawk
return make_number((AWKNUM) -1.0);
}
@@ -2322,9 +2330,15 @@ do_getline(int into_variable, IOBUF *iop)
errcode = 0;
cnt = get_a_record(& s, iop, & errcode);
if (errcode != 0) {
+<<<<<<< HEAD
if (! do_traditional && errcode != -1)
update_ERRNO_saved(errcode);
if (into_variable)
+=======
+ if (! do_traditional && (errcode != -1))
+ update_ERRNO_int(errcode);
+ if (intovar)
+>>>>>>> xgawk
(void) POP_ADDRESS();
return make_number((AWKNUM) -1.0);
}
@@ -2346,35 +2360,45 @@ do_getline(int into_variable, IOBUF *iop)
return make_number((AWKNUM) 1.0);
}
+typedef struct {
+ const char *envname;
+ char **dfltp; /* pointer to address of default path */
+ char try_cwd; /* always search current directory? */
+ char **awkpath; /* array containing library search paths */
+ int max_pathlen; /* length of the longest item in awkpath */
+} path_info;
+
+static path_info pi_awkpath = {
+ /* envname */ "AWKPATH",
+ /* dfltp */ & defpath,
+ /* try_cwd */ TRUE,
+};
-static char **awkpath = NULL; /* array containing library search paths */
-static int max_pathlen; /* length of the longest item in awkpath */
+static path_info pi_awklibpath = {
+ /* envname */ "AWKLIBPATH",
+ /* dfltp */ & deflibpath,
+ /* try_cwd */ FALSE,
+};
/* init_awkpath --- split path(=$AWKPATH) into components */
static void
-init_awkpath(char *path)
+init_awkpath(path_info *pi)
{
+ char *path;
char *start, *end, *p;
int len, i;
- static int max_path = 0;
+ int max_path; /* (# of allocated paths)-1 */
#define INC_PATH 5
- max_pathlen = 0;
- if (path == NULL || *path == '\0')
- path = defpath;
-
- for (i = 0; i < max_path && awkpath[i]; i++) {
- efree(awkpath[i]);
- awkpath[i] = NULL;
- }
+ pi->max_pathlen = 0;
+ if ((path = getenv(pi->envname)) == NULL || *path == '\0')
+ path = pi->dfltp[0];
- if (max_path == 0) {
- max_path = INC_PATH;
- emalloc(awkpath, char **, (max_path + 1) * sizeof(char *), "init_awkpath");
- memset(awkpath, 0, (max_path + 1) * sizeof(char *));
- }
+ max_path = INC_PATH;
+ emalloc(pi->awkpath, char **, (max_path + 1) * sizeof(char *), "init_awkpath");
+ memset(pi->awkpath, 0, (max_path + 1) * sizeof(char *));
end = start = path;
i = 0;
@@ -2393,12 +2417,12 @@ init_awkpath(char *path)
if (i == max_path) {
max_path += INC_PATH;
- erealloc(awkpath, char **, (max_path + 1) * sizeof(char *), "init_awkpath");
- memset(awkpath + i, 0, (INC_PATH + 1) * sizeof(char *));
+ erealloc(pi->awkpath, char **, (max_path + 1) * sizeof(char *), "init_awkpath");
+ memset(pi->awkpath + i, 0, (INC_PATH + 1) * sizeof(char *));
}
- awkpath[i++] = p;
- if (len > max_pathlen)
- max_pathlen = len;
+ pi->awkpath[i++] = p;
+ if (len > pi->max_pathlen)
+ pi->max_pathlen = len;
}
/* skip one or more envsep char */
@@ -2406,7 +2430,7 @@ init_awkpath(char *path)
end++;
start = end;
}
- awkpath[i] = NULL;
+ pi->awkpath[i] = NULL;
#undef INC_PATH
}
@@ -2438,7 +2462,7 @@ get_cwd ()
/* do_find_source --- search $AWKPATH for file, return NULL if not found */
static char *
-do_find_source(const char *src, struct stat *stb, int *errcode)
+do_find_source(const char *src, struct stat *stb, int *errcode, path_info *pi)
{
char *path;
int i;
@@ -2457,7 +2481,7 @@ do_find_source(const char *src, struct stat *stb, int *errcode)
}
/* try current directory before $AWKPATH search */
- if (stat(src, stb) == 0) {
+ if (pi->try_cwd && stat(src, stb) == 0) {
path = get_cwd();
if (path == NULL) {
*errcode = errno;
@@ -2469,16 +2493,15 @@ do_find_source(const char *src, struct stat *stb, int *errcode)
return path;
}
- if (awkpath == NULL)
- init_awkpath(getenv("AWKPATH"));
+ if (pi->awkpath == NULL)
+ init_awkpath(pi);
- emalloc(path, char *, max_pathlen + strlen(src) + 1, "do_find_source");
- for (i = 0; awkpath[i] != NULL; i++) {
- if (strcmp(awkpath[i], "./") == 0 || strcmp(awkpath[i], ".") == 0) {
- /* FIXME: already tried CWD above; Why do it again ? */
+ emalloc(path, char *, pi->max_pathlen + strlen(src) + 1, "do_find_source");
+ for (i = 0; pi->awkpath[i] != NULL; i++) {
+ if (strcmp(pi->awkpath[i], "./") == 0 || strcmp(pi->awkpath[i], ".") == 0)
*path = '\0';
- } else
- strcpy(path, awkpath[i]);
+ else
+ strcpy(path, pi->awkpath[i]);
strcat(path, src);
if (stat(path, stb) == 0)
return path;
@@ -2496,11 +2519,12 @@ char *
find_source(const char *src, struct stat *stb, int *errcode, int is_extlib)
{
char *path;
+ path_info *pi = (is_extlib ? & pi_awklibpath : & pi_awkpath);
*errcode = 0;
if (src == NULL || *src == '\0')
return NULL;
- path = do_find_source(src, stb, errcode);
+ path = do_find_source(src, stb, errcode, pi);
if (path == NULL && is_extlib) {
char *file_ext;
@@ -2508,7 +2532,7 @@ find_source(const char *src, struct stat *stb, int *errcode, int is_extlib)
size_t src_len;
size_t suffix_len;
-#define EXTLIB_SUFFIX ".so"
+#define EXTLIB_SUFFIX "." SHLIBEXT
src_len = strlen(src);
suffix_len = strlen(EXTLIB_SUFFIX);
@@ -2520,7 +2544,7 @@ find_source(const char *src, struct stat *stb, int *errcode, int is_extlib)
save_errno = errno;
emalloc(file_ext, char *, src_len + suffix_len + 1, "find_source");
sprintf(file_ext, "%s%s", src, EXTLIB_SUFFIX);
- path = do_find_source(file_ext, stb, errcode);
+ path = do_find_source(file_ext, stb, errcode, pi);
efree(file_ext);
if (path == NULL)
errno = save_errno;
@@ -2540,7 +2564,7 @@ find_source(const char *src, struct stat *stb, int *errcode, int is_extlib)
emalloc(file_awk, char *, strlen(src) +
sizeof(DEFAULT_FILETYPE) + 1, "find_source");
sprintf(file_awk, "%s%s", src, DEFAULT_FILETYPE);
- path = do_find_source(file_awk, stb, errcode);
+ path = do_find_source(file_awk, stb, errcode, pi);
efree(file_awk);
if (path == NULL) {
errno = save_errno;
diff --git a/main.c b/main.c
index 8a38a760..2324d9a0 100644
--- a/main.c
+++ b/main.c
@@ -1004,6 +1004,31 @@ init_vars()
register_deferred_variable("ENVIRON", load_environ);
}
+/* path_environ --- put path variable into environment if not already there */
+
+static void
+path_environ(const char *pname, const char *dflt)
+{
+ const char *val;
+ NODE **aptr;
+ NODE *tmp;
+
+ tmp = make_string(pname, strlen(pname));
+ if (! in_array(ENVIRON_node, tmp)) {
+ /*
+ * On VMS, environ[] only holds a subset of what getenv() can
+ * find, so look AWKPATH up before resorting to default path.
+ */
+ val = getenv(pname);
+ if (val == NULL)
+ val = dflt;
+ aptr = assoc_lookup(ENVIRON_node, tmp);
+ unref(*aptr);
+ *aptr = make_string(val, strlen(val));
+ }
+ unref(tmp);
+}
+
/* load_environ --- populate the ENVIRON array */
static NODE *
@@ -1039,23 +1064,11 @@ load_environ()
*--val = '=';
}
/*
- * Put AWKPATH into ENVIRON if it's not there.
+ * Put AWKPATH and AWKLIBPATH into ENVIRON if not already there.
* This allows querying it from within awk programs.
*/
- tmp = make_string("AWKPATH", 7);
- if (! in_array(ENVIRON_node, tmp)) {
- /*
- * On VMS, environ[] only holds a subset of what getenv() can
- * find, so look AWKPATH up before resorting to default path.
- */
- val = getenv("AWKPATH");
- if (val == NULL)
- val = defpath;
- aptr = assoc_lookup(ENVIRON_node, tmp);
- unref(*aptr);
- *aptr = make_string(val, strlen(val));
- }
- unref(tmp);
+ path_environ("AWKPATH", defpath);
+ path_environ("AWKLIBPATH", deflibpath);
return ENVIRON_node;
}
diff --git a/pc/ChangeLog b/pc/ChangeLog
index 8af4752e..1eb51812 100644
--- a/pc/ChangeLog
+++ b/pc/ChangeLog
@@ -40,6 +40,10 @@
* config.h: Add definition for _Noreturn.
+2012-03-20 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkmisc.pc (deflibpath): New global variable.
+
2012-03-28 Arnold D. Robbins <arnold@skeeve.com>
* 4.0.1: Release tar ball made.
diff --git a/pc/gawkmisc.pc b/pc/gawkmisc.pc
index b2a67a50..b368e81f 100644
--- a/pc/gawkmisc.pc
+++ b/pc/gawkmisc.pc
@@ -31,6 +31,8 @@ char *defpath = DEFPATH;
# else
char *defpath = ".;c:\\lib\\awk;c:\\gnu\\lib\\awk";
# endif
+/* the Makefile should define DEFLIBPATH */
+char *deflibpath = DEFLIBPATH;
#ifdef __EMX__
#include<io.h>
diff --git a/posix/ChangeLog b/posix/ChangeLog
index d684afe9..425f1c91 100644
--- a/posix/ChangeLog
+++ b/posix/ChangeLog
@@ -1,3 +1,7 @@
+2012-03-20 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkmisc.c (deflibpath): New global variable.
+
2012-03-28 Arnold D. Robbins <arnold@skeeve.com>
* 4.0.1: Release tar ball made.
diff --git a/posix/gawkmisc.c b/posix/gawkmisc.c
index acc3c9d5..270872ac 100644
--- a/posix/gawkmisc.c
+++ b/posix/gawkmisc.c
@@ -26,6 +26,7 @@
char quote = '\'';
char *defpath = DEFPATH;
+char *deflibpath = DEFLIBPATH;
char envsep = ':';
#ifndef INVALID_HANDLE
diff --git a/test/ChangeLog b/test/ChangeLog
index e926adf1..45920dce 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,36 @@
+2012-04-08 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (VALGRIND): Set to empty to protect against random
+ values in the environment.
+
+2012-04-08 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (EXTRA_DIST): Add missing files fork.ok, fork2.ok
+ and ordchr2.ok.
+
+2012-04-08 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (AWK, PGAWK): Include new $(VALGRIND) variable in
+ command line (now passed in by top-level Makefile).
+
+2012-04-07 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (ordchr2, readfile): Fix so "make diffout" will work
+ properly.
+ * orchr2.ok: New file.
+
+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.
+
2012-05-09 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (jarebug): New test.
diff --git a/test/Makefile.am b/test/Makefile.am
index 4b0bf819..05b19a7a 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 \
@@ -233,6 +235,10 @@ EXTRA_DIST = \
fnparydl.awk \
fnparydl.ok \
fnparydl-mpfr.ok \
+ fork.awk \
+ fork.ok \
+ fork2.awk \
+ fork2.ok \
fpat1.awk \
fpat1.in \
fpat1.ok \
@@ -528,6 +534,9 @@ EXTRA_DIST = \
opasnidx.ok \
opasnslf.awk \
opasnslf.ok \
+ ordchr.awk \
+ ordchr.ok \
+ ordchr2.ok \
out1.ok \
out2.ok \
out3.ok \
@@ -864,6 +873,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 \
@@ -886,13 +897,17 @@ GENTESTS_UNUSED = Makefile.in gtlnbufv.awk printfloat.awk
CMP = cmp
AWKPROG = ../gawk$(EXEEXT)
+# Default for VALGRIND is empty unless overridden by a command-line argument.
+# This protects against cruft in the environment.
+VALGRIND =
+
# This business forces the locale to be C for running the tests,
# unless we override it to something else for testing.
#
# 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) $(AWKFLAGS)
+AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG) $(AWKFLAGS)
# Message stuff is to make it a little easier to follow.
# Make the pass-fail last and dependent on others to avoid
@@ -903,7 +918,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)
@@ -922,6 +938,8 @@ machine-tests: $(MACHINE_TESTS)
mpfr-tests: $(MPFR_TESTS)
+shlib-tests: $(SHLIB_TESTS)
+
msg::
@echo ''
@echo 'Any output from "cmp" is bad news, although some differences'
@@ -962,6 +980,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 $@
@@ -1512,6 +1536,16 @@ jarebug::
$(AWK) -f $(srcdir)/$@.awk $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
@-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
+ordchr2::
+ @echo $@
+ @$(AWK) -l ordchr 'BEGIN {print chr(ord("z"))}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@
+
+readfile::
+ @echo $@
+ @$(AWK) -l readfile 'BEGIN {printf "%s", readfile("Makefile")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) Makefile _$@ && rm -f _$@ || cp -p Makefile $@.ok
+
# Targets generated for other tests:
include Maketests
@@ -1551,8 +1585,8 @@ valgrind-scan:
function show() {if (cmd) {printf "%s: %s\n",FILENAME,cmd; cmd = ""}; \
printf "\t%s\n",$$0}; \
{$$1 = ""}; \
- /Prog and args are:/ {incmd = 1; cmd = ""; next}; \
- incmd {if (NF == 1) incmd = 0; else {cmd = (cmd $$0); next}}; \
+ $$2 == "Command:" {incmd = 1; $$2 = ""; cmd = $$0; next}; \
+ incmd {if (/Parent PID:/) incmd = 0; else {cmd = (cmd $$0); next}}; \
/ERROR SUMMARY:/ && !/: 0 errors from 0 contexts/ {show()}; \
/definitely lost:/ && !/: 0 bytes in 0 blocks/ {show()}; \
/possibly lost:/ && !/: 0 bytes in 0 blocks/ {show()}; \
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
diff --git a/test/ordchr2.ok b/test/ordchr2.ok
new file mode 100644
index 00000000..b6802534
--- /dev/null
+++ b/test/ordchr2.ok
@@ -0,0 +1 @@
+z
diff --git a/vms/ChangeLog b/vms/ChangeLog
index fa1fbd16..9988d34b 100644
--- a/vms/ChangeLog
+++ b/vms/ChangeLog
@@ -2,6 +2,10 @@
* config.h: Add definition for _Noreturn.
+2012-03-20 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * gawkmisc.vms (deflibpath): New global variable.
+
2012-03-28 Arnold D. Robbins <arnold@skeeve.com>
* 4.0.1: Release tar ball made.
diff --git a/vms/gawkmisc.vms b/vms/gawkmisc.vms
index 346a1e88..90b2530b 100644
--- a/vms/gawkmisc.vms
+++ b/vms/gawkmisc.vms
@@ -25,6 +25,7 @@
char quote = '\'';
char *defpath = DEFPATH;
+char *deflibpath = DEFLIBPATH;
char envsep = ',';
/* gawk_name --- pull out the "gawk" part from how the OS called us */