diff options
author | Andrew J. Schorr <aschorr@telemetry-investments.com> | 2017-03-06 20:42:18 -0500 |
---|---|---|
committer | Andrew J. Schorr <aschorr@telemetry-investments.com> | 2017-03-06 20:42:18 -0500 |
commit | e5261cf0bb2b565661e5e4d1be4a78c64c501b34 (patch) | |
tree | ab5122d5df514aa8e78b557c22d9c14cf170ec22 | |
parent | 54efcb6f4ce81ed0ad2f90e27252f1d8532dd0b5 (diff) | |
download | egawk-e5261cf0bb2b565661e5e4d1be4a78c64c501b34.tar.gz egawk-e5261cf0bb2b565661e5e4d1be4a78c64c501b34.tar.bz2 egawk-e5261cf0bb2b565661e5e4d1be4a78c64c501b34.zip |
Create new extension readdir_test for testing new get_record field_width parsing.
-rw-r--r-- | extension/ChangeLog | 7 | ||||
-rw-r--r-- | extension/Makefile.am | 10 | ||||
-rw-r--r-- | extension/Makefile.in | 73 | ||||
-rw-r--r-- | extension/readdir_test.c | 336 |
4 files changed, 407 insertions, 19 deletions
diff --git a/extension/ChangeLog b/extension/ChangeLog index 89be82da..44fccd5e 100644 --- a/extension/ChangeLog +++ b/extension/ChangeLog @@ -1,3 +1,10 @@ +2017-03-06 Andrew J. Schorr <aschorr@telemetry-investments.com> + + * readdir_test.c: Test extension using new get_record field_width + parsing feature. + * Makefile.am (noinst_LTLIBRARIES): Add readdir_test.la. + (readdir_test_la_*): Configure building of new extension library. + 2017-01-21 Eli Zaretskii <eliz@gnu.org> * testext.c (getuid) [__MINGW32__]: New function, mirrors what diff --git a/extension/Makefile.am b/extension/Makefile.am index 59c5cb8e..d1cd225c 100644 --- a/extension/Makefile.am +++ b/extension/Makefile.am @@ -48,6 +48,9 @@ pkgextension_LTLIBRARIES = \ testext.la \ time.la +noinst_LTLIBRARIES = \ + readdir_test.la + MY_MODULE_FLAGS = -module -avoid-version -no-undefined # on Cygwin, gettext requires that we link with -lintl MY_LIBS = $(LTLIBINTL) @@ -101,6 +104,13 @@ testext_la_SOURCES = testext.c testext_la_LDFLAGS = $(MY_MODULE_FLAGS) testext_la_LIBADD = $(MY_LIBS) +# N.B. Because we are not installing readdir_test, we must specify -rpath in +# LDFLAGS to get automake to build a shared library, since it needs +# an installation path. +readdir_test_la_SOURCES = readdir_test.c +readdir_test_la_LDFLAGS = $(MY_MODULE_FLAGS) -rpath /foo +readdir_test_la_LIBADD = $(MY_LIBS) + install-data-hook: for i in $(pkgextension_LTLIBRARIES) ; do \ $(RM) $(DESTDIR)$(pkgextensiondir)/$$i ; \ diff --git a/extension/Makefile.in b/extension/Makefile.in index 23bb5cf1..5d82045c 100644 --- a/extension/Makefile.in +++ b/extension/Makefile.in @@ -157,7 +157,7 @@ am__uninstall_files_from_dir = { \ } am__installdirs = "$(DESTDIR)$(pkgextensiondir)" \ "$(DESTDIR)$(man3dir)" -LTLIBRARIES = $(pkgextension_LTLIBRARIES) +LTLIBRARIES = $(noinst_LTLIBRARIES) $(pkgextension_LTLIBRARIES) am__DEPENDENCIES_1 = filefuncs_la_DEPENDENCIES = $(am__DEPENDENCIES_1) am_filefuncs_la_OBJECTS = filefuncs.lo stack.lo gawkfts.lo @@ -199,6 +199,13 @@ readdir_la_OBJECTS = $(am_readdir_la_OBJECTS) readdir_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(readdir_la_LDFLAGS) $(LDFLAGS) -o $@ +readdir_test_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am_readdir_test_la_OBJECTS = readdir_test.lo +readdir_test_la_OBJECTS = $(am_readdir_test_la_OBJECTS) +readdir_test_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(readdir_test_la_LDFLAGS) $(LDFLAGS) \ + -o $@ readfile_la_DEPENDENCIES = $(am__DEPENDENCIES_1) am_readfile_la_OBJECTS = readfile.lo readfile_la_OBJECTS = $(am_readfile_la_OBJECTS) @@ -271,14 +278,16 @@ am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(filefuncs_la_SOURCES) $(fnmatch_la_SOURCES) \ $(fork_la_SOURCES) $(inplace_la_SOURCES) $(ordchr_la_SOURCES) \ - $(readdir_la_SOURCES) $(readfile_la_SOURCES) \ - $(revoutput_la_SOURCES) $(revtwoway_la_SOURCES) \ - $(rwarray_la_SOURCES) $(testext_la_SOURCES) $(time_la_SOURCES) + $(readdir_la_SOURCES) $(readdir_test_la_SOURCES) \ + $(readfile_la_SOURCES) $(revoutput_la_SOURCES) \ + $(revtwoway_la_SOURCES) $(rwarray_la_SOURCES) \ + $(testext_la_SOURCES) $(time_la_SOURCES) DIST_SOURCES = $(filefuncs_la_SOURCES) $(fnmatch_la_SOURCES) \ $(fork_la_SOURCES) $(inplace_la_SOURCES) $(ordchr_la_SOURCES) \ - $(readdir_la_SOURCES) $(readfile_la_SOURCES) \ - $(revoutput_la_SOURCES) $(revtwoway_la_SOURCES) \ - $(rwarray_la_SOURCES) $(testext_la_SOURCES) $(time_la_SOURCES) + $(readdir_la_SOURCES) $(readdir_test_la_SOURCES) \ + $(readfile_la_SOURCES) $(revoutput_la_SOURCES) \ + $(revtwoway_la_SOURCES) $(rwarray_la_SOURCES) \ + $(testext_la_SOURCES) $(time_la_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ @@ -517,9 +526,12 @@ pkgextension_LTLIBRARIES = \ revoutput.la \ revtwoway.la \ rwarray.la \ - testext.la \ time.la +noinst_LTLIBRARIES = \ + readdir_test.la \ + testext.la + MY_MODULE_FLAGS = -module -avoid-version -no-undefined # on Cygwin, gettext requires that we link with -lintl MY_LIBS = $(LTLIBINTL) @@ -558,9 +570,16 @@ rwarray_la_LIBADD = $(MY_LIBS) time_la_SOURCES = time.c time_la_LDFLAGS = $(MY_MODULE_FLAGS) time_la_LIBADD = $(MY_LIBS) + +# N.B. Because we are not installing testext, we must specify -rpath in +# LDFLAGS to get automake to build a shared library, since it needs +# an installation path. testext_la_SOURCES = testext.c -testext_la_LDFLAGS = $(MY_MODULE_FLAGS) +testext_la_LDFLAGS = $(MY_MODULE_FLAGS) -rpath /foo testext_la_LIBADD = $(MY_LIBS) +readdir_test_la_SOURCES = readdir_test.c +readdir_test_la_LDFLAGS = $(MY_MODULE_FLAGS) -rpath /foo +readdir_test_la_LIBADD = $(MY_LIBS) EXTRA_DIST = build-aux/config.rpath \ ChangeLog \ ChangeLog.0 \ @@ -632,6 +651,17 @@ $(srcdir)/configh.in: $(am__configure_deps) distclean-hdr: -rm -f config.h stamp-h1 +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + install-pkgextensionLTLIBRARIES: $(pkgextension_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(pkgextension_LTLIBRARIES)'; test -n "$(pkgextensiondir)" || list=; \ @@ -685,6 +715,9 @@ ordchr.la: $(ordchr_la_OBJECTS) $(ordchr_la_DEPENDENCIES) $(EXTRA_ordchr_la_DEPE readdir.la: $(readdir_la_OBJECTS) $(readdir_la_DEPENDENCIES) $(EXTRA_readdir_la_DEPENDENCIES) $(AM_V_CCLD)$(readdir_la_LINK) -rpath $(pkgextensiondir) $(readdir_la_OBJECTS) $(readdir_la_LIBADD) $(LIBS) +readdir_test.la: $(readdir_test_la_OBJECTS) $(readdir_test_la_DEPENDENCIES) $(EXTRA_readdir_test_la_DEPENDENCIES) + $(AM_V_CCLD)$(readdir_test_la_LINK) $(readdir_test_la_OBJECTS) $(readdir_test_la_LIBADD) $(LIBS) + readfile.la: $(readfile_la_OBJECTS) $(readfile_la_DEPENDENCIES) $(EXTRA_readfile_la_DEPENDENCIES) $(AM_V_CCLD)$(readfile_la_LINK) -rpath $(pkgextensiondir) $(readfile_la_OBJECTS) $(readfile_la_LIBADD) $(LIBS) @@ -698,7 +731,7 @@ rwarray.la: $(rwarray_la_OBJECTS) $(rwarray_la_DEPENDENCIES) $(EXTRA_rwarray_la_ $(AM_V_CCLD)$(rwarray_la_LINK) -rpath $(pkgextensiondir) $(rwarray_la_OBJECTS) $(rwarray_la_LIBADD) $(LIBS) testext.la: $(testext_la_OBJECTS) $(testext_la_DEPENDENCIES) $(EXTRA_testext_la_DEPENDENCIES) - $(AM_V_CCLD)$(testext_la_LINK) -rpath $(pkgextensiondir) $(testext_la_OBJECTS) $(testext_la_LIBADD) $(LIBS) + $(AM_V_CCLD)$(testext_la_LINK) $(testext_la_OBJECTS) $(testext_la_LIBADD) $(LIBS) time.la: $(time_la_OBJECTS) $(time_la_DEPENDENCIES) $(EXTRA_time_la_DEPENDENCIES) $(AM_V_CCLD)$(time_la_LINK) -rpath $(pkgextensiondir) $(time_la_OBJECTS) $(time_la_LIBADD) $(LIBS) @@ -716,6 +749,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inplace.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ordchr.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readdir.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readdir_test.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readfile.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/revoutput.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/revtwoway.Plo@am__quote@ @@ -1131,8 +1165,8 @@ maintainer-clean-generic: @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive -clean-am: clean-generic clean-libtool clean-pkgextensionLTLIBRARIES \ - mostlyclean-am +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + clean-pkgextensionLTLIBRARIES mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) @@ -1211,13 +1245,14 @@ uninstall-man: uninstall-man3 .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ - clean-libtool clean-pkgextensionLTLIBRARIES cscope \ - cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ - dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ - distcheck distclean distclean-compile distclean-generic \ - distclean-hdr distclean-libtool distclean-tags distcleancheck \ - distdir distuninstallcheck dvi dvi-am html html-am info \ - info-am install install-am install-data install-data-am \ + clean-libtool clean-noinstLTLIBRARIES \ + clean-pkgextensionLTLIBRARIES cscope cscopelist-am ctags \ + ctags-am dist dist-all dist-bzip2 dist-gzip dist-lzip \ + dist-shar dist-tarZ dist-xz dist-zip distcheck distclean \ + distclean-compile distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ install-data-hook install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-man3 install-pdf \ diff --git a/extension/readdir_test.c b/extension/readdir_test.c new file mode 100644 index 00000000..cc23081e --- /dev/null +++ b/extension/readdir_test.c @@ -0,0 +1,336 @@ +/* + * readdir.c --- Provide an input parser to read directories + * + * Arnold Robbins + * arnold@skeeve.com + * Written 7/2012 + * + * Andrew Schorr and Arnold Robbins: further fixes 8/2012. + * Simplified 11/2012. + */ + +/* + * Copyright (C) 2012-2014 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 + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#define _BSD_SOURCE +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + +#ifdef HAVE_DIRENT_H +#include <dirent.h> +#else +#error Cannot compile the dirent extension on this system! +#endif + +#ifdef __MINGW32__ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif + +#include "gawkapi.h" + +#include "gawkdirfd.h" + +#include "gettext.h" +#define _(msgid) gettext(msgid) +#define N_(msgid) msgid + +#ifndef PATH_MAX +#define PATH_MAX 1024 /* a good guess */ +#endif + +static const gawk_api_t *api; /* for convenience macros to work */ +static awk_ext_id_t *ext_id; +static const char *ext_version = "readdir extension: version 1.0"; + +static awk_bool_t init_readdir(void); +static awk_bool_t (*init_func)(void) = init_readdir; + +int plugin_is_GPL_compatible; + +/* data type for the opaque pointer: */ + +typedef struct open_directory { + DIR *dp; + char *buf; + int field_width[7]; +} open_directory_t; + +/* ftype --- return type of file as a single character string */ + +static const char * +ftype(struct dirent *entry, const char *dirname) +{ +#ifdef DT_BLK + (void) dirname; /* silence warnings */ + switch (entry->d_type) { + case DT_BLK: return "b"; + case DT_CHR: return "c"; + case DT_DIR: return "d"; + case DT_FIFO: return "p"; + case DT_LNK: return "l"; + case DT_REG: return "f"; + case DT_SOCK: return "s"; + default: + case DT_UNKNOWN: return "u"; + } +#else + char fname[PATH_MAX]; + struct stat sbuf; + + strcpy(fname, dirname); + strcat(fname, "/"); + strcat(fname, entry->d_name); + if (stat(fname, &sbuf) == 0) { + if (S_ISBLK(sbuf.st_mode)) + return "b"; + if (S_ISCHR(sbuf.st_mode)) + return "c"; + if (S_ISDIR(sbuf.st_mode)) + return "d"; + if (S_ISFIFO(sbuf.st_mode)) + return "p"; + if (S_ISREG(sbuf.st_mode)) + return "f"; +#ifdef S_ISLNK + if (S_ISLNK(sbuf.st_mode)) + return "l"; +#endif +#ifdef S_ISSOCK + if (S_ISSOCK(sbuf.st_mode)) + return "s"; +#endif + } + return "u"; +#endif +} + +/* get_inode --- get the inode of a file */ +static long long +get_inode(struct dirent *entry, const char *dirname) +{ +#ifdef __MINGW32__ + char fname[PATH_MAX]; + HANDLE fh; + BY_HANDLE_FILE_INFORMATION info; + + sprintf(fname, "%s\\%s", dirname, entry->d_name); + fh = CreateFile(fname, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (fh == INVALID_HANDLE_VALUE) + return 0; + if (GetFileInformationByHandle(fh, &info)) { + long long inode = info.nFileIndexHigh; + + inode <<= 32; + inode += info.nFileIndexLow; + return inode; + } + return 0; +#else + (void) dirname; /* silence warnings */ + return entry->d_ino; +#endif +} + +/* dir_get_record --- get one record at a time out of a directory */ + +static int +dir_get_record(char **out, awk_input_buf_t *iobuf, int *errcode, + char **rt_start, size_t *rt_len, const int **field_width) +{ + DIR *dp; + struct dirent *dirent; + int len, flen; + open_directory_t *the_dir; + const char *ftstr; + unsigned long long ino; + + /* + * The caller sets *errcode to 0, so we should set it only if an + * error occurs. + */ + + if (out == NULL || iobuf == NULL || iobuf->opaque == NULL) + return EOF; + + the_dir = (open_directory_t *) iobuf->opaque; + dp = the_dir->dp; + + /* + * Initialize errno, since readdir does not set it to zero on EOF. + */ + errno = 0; + dirent = readdir(dp); + if (dirent == NULL) { + *errcode = errno; /* in case there was an error */ + return EOF; + } + + ino = get_inode (dirent, iobuf->name); + +#if __MINGW32__ + len = sprintf(the_dir->buf, "%I64u", ino); +#else + len = sprintf(the_dir->buf, "%llu", ino); +#endif + the_dir->field_width[1] = len; + len += (flen = sprintf(the_dir->buf + len, "/%s", dirent->d_name)); + the_dir->field_width[3] = flen-1; + + ftstr = ftype(dirent, iobuf->name); + len += (flen = sprintf(the_dir->buf + len, "/%s", ftstr)); + the_dir->field_width[5] = flen-1; + + *out = the_dir->buf; + + *rt_start = NULL; + *rt_len = 0; /* set RT to "" */ + if (field_width) + *field_width = the_dir->field_width; + return len; +} + +/* dir_close --- close up when done */ + +static void +dir_close(awk_input_buf_t *iobuf) +{ + open_directory_t *the_dir; + + if (iobuf == NULL || iobuf->opaque == NULL) + return; + + the_dir = (open_directory_t *) iobuf->opaque; + + closedir(the_dir->dp); + gawk_free(the_dir->buf); + gawk_free(the_dir); + + iobuf->fd = -1; +} + +/* dir_can_take_file --- return true if we want the file */ + +static awk_bool_t +dir_can_take_file(const awk_input_buf_t *iobuf) +{ + if (iobuf == NULL) + return awk_false; + + return (iobuf->fd != INVALID_HANDLE && S_ISDIR(iobuf->sbuf.st_mode)); +} + +/* + * dir_take_control_of --- set up input parser. + * We can assume that dir_can_take_file just returned true, + * and no state has changed since then. + */ + +static awk_bool_t +dir_take_control_of(awk_input_buf_t *iobuf) +{ + DIR *dp; + open_directory_t *the_dir; + size_t size; + + errno = 0; +#ifdef HAVE_FDOPENDIR + dp = fdopendir(iobuf->fd); +#else + dp = opendir(iobuf->name); + if (dp != NULL) + iobuf->fd = dirfd(dp); +#endif + if (dp == NULL) { + warning(ext_id, _("dir_take_control_of: opendir/fdopendir failed: %s"), + strerror(errno)); + update_ERRNO_int(errno); + return awk_false; + } + + emalloc(the_dir, open_directory_t *, sizeof(open_directory_t), "dir_take_control_of"); + the_dir->dp = dp; + /* pre-populate the field_width array with constant values: */ + the_dir->field_width[0] = 0; /* no leading space */ + the_dir->field_width[2] = 1; /* single slash sign separator*/ + the_dir->field_width[4] = 1; /* single slash sign separator*/ + the_dir->field_width[6] = -1; /* terminate it after 3 fields */ + size = sizeof(struct dirent) + 21 /* max digits in inode */ + 2 /* slashes */; + emalloc(the_dir->buf, char *, size, "dir_take_control_of"); + + iobuf->opaque = the_dir; + iobuf->get_record = dir_get_record; + iobuf->close_func = dir_close; + + return awk_true; +} + +static awk_input_parser_t readdir_parser = { + "readdir", + dir_can_take_file, + dir_take_control_of, + NULL +}; + +#ifdef TEST_DUPLICATE +static awk_input_parser_t readdir_parser2 = { + "readdir2", + dir_can_take_file, + dir_take_control_of, + NULL +}; +#endif + +/* init_readdir --- set things ups */ + +static awk_bool_t +init_readdir() +{ + register_input_parser(& readdir_parser); +#ifdef TEST_DUPLICATE + register_input_parser(& readdir_parser2); +#endif + + return awk_true; +} + +static awk_ext_func_t func_table[] = { + { NULL, NULL, 0, 0, awk_false, NULL } +}; + +/* define the dl_load function using the boilerplate macro */ + +dl_load_func(func_table, readdir, "") |