diff options
author | Arnold D. Robbins <arnold@skeeve.com> | 2012-05-09 20:31:35 +0300 |
---|---|---|
committer | Arnold D. Robbins <arnold@skeeve.com> | 2012-05-09 20:31:35 +0300 |
commit | a59319732d89feda419acab674ea580c95db7d4a (patch) | |
tree | 3d30595e8f50cb1b486c9f61f93a498834c22842 | |
parent | 8ff0b4eaa7592280b5a55087c0326c6ef1f88db5 (diff) | |
parent | c41908d0b02f7746a67ab7aa2e54058e5b66439a (diff) | |
download | egawk-a59319732d89feda419acab674ea580c95db7d4a.tar.gz egawk-a59319732d89feda419acab674ea580c95db7d4a.tar.bz2 egawk-a59319732d89feda419acab674ea580c95db7d4a.zip |
Merge branch 'xgawk'
43 files changed, 1284 insertions, 213 deletions
@@ -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. @@ -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. @@ -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); @@ -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@ @@ -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 @@ -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 */ @@ -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 */ @@ -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; @@ -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 */ |