gawk-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gawk-diffs] [SCM] gawk branch, extgawk, updated. 88e81c931345aa485e55c6


From: Arnold Robbins
Subject: [gawk-diffs] [SCM] gawk branch, extgawk, updated. 88e81c931345aa485e55c6d6c7f3ad61dc200fed
Date: Wed, 08 Aug 2012 19:38:33 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gawk".

The branch, extgawk has been updated
       via  88e81c931345aa485e55c6d6c7f3ad61dc200fed (commit)
       via  30bb821bad107a676c1d0f0688f90b2b7e6c7505 (commit)
      from  66693943a96ef1d0c0a991c3780dabc0071d6233 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=88e81c931345aa485e55c6d6c7f3ad61dc200fed

commit 88e81c931345aa485e55c6d6c7f3ad61dc200fed
Author: Arnold D. Robbins <address@hidden>
Date:   Wed Aug 8 22:37:55 2012 +0300

    Add fts() extension, support, doc, and test.

diff --git a/ChangeLog b/ChangeLog
index 1c686d0..f0f5ff2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,10 @@
 
        * configure.ac: Add -DNDEBUG to remove asserts if not developing.
 
+       * gawkapi.h: Document how to build up arrays.
+       * gawkapi.c (api_sym_update): For an array, pass the new cookie
+       back out to the extension.
+
 2012-08-01         Arnold D. Robbins     <address@hidden>
 
        * io.c (iop_finish): New function.
diff --git a/extension/ChangeLog b/extension/ChangeLog
index f5167c0..6b7c2bc 100644
--- a/extension/ChangeLog
+++ b/extension/ChangeLog
@@ -1,3 +1,13 @@
+2012-08-08         Arnold D. Robbins     <address@hidden>
+
+       Add fts() to filefuncs.
+
+       * filefuncs.3am: Update doc.
+       * filefuncs.c: Lots of new code.
+       * configure.ac: Add checks for appropriate headers and functions.
+       * stack.h, stack.c: New files.
+       * Makefile.am: Update list of files.
+
 2012-08-03         Andrew J. Schorr     <address@hidden>
 
        * readdir.c (dir_get_record): Fix for systems where ino_t is
diff --git a/extension/Makefile.am b/extension/Makefile.am
index 2e6a523..bf9a715 100644
--- a/extension/Makefile.am
+++ b/extension/Makefile.am
@@ -46,7 +46,7 @@ MY_MODULE_FLAGS = -module -avoid-version -no-undefined
 # on Cygwin, gettext requires that we link with -lintl 
 MY_LIBS = $(LIBINTL)
 
-filefuncs_la_SOURCES  = filefuncs.c
+filefuncs_la_SOURCES  = filefuncs.c stack.h stack.c
 filefuncs_la_LDFLAGS  = $(MY_MODULE_FLAGS)
 filefuncs_la_LIBADD   = $(MY_LIBS)
 fnmatch_la_SOURCES    = fnmatch.c
diff --git a/extension/Makefile.in b/extension/Makefile.in
index e64fb88..1679cab 100644
--- a/extension/Makefile.in
+++ b/extension/Makefile.in
@@ -139,7 +139,7 @@ LTLIBRARIES = $(pkgextension_LTLIBRARIES)
 am__DEPENDENCIES_1 =
 am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
 filefuncs_la_DEPENDENCIES = $(am__DEPENDENCIES_2)
-am_filefuncs_la_OBJECTS = filefuncs.lo
+am_filefuncs_la_OBJECTS = filefuncs.lo stack.lo
 filefuncs_la_OBJECTS = $(am_filefuncs_la_OBJECTS)
 filefuncs_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
        $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
@@ -430,7 +430,7 @@ pkgextension_LTLIBRARIES = \
 MY_MODULE_FLAGS = -module -avoid-version -no-undefined
 # on Cygwin, gettext requires that we link with -lintl 
 MY_LIBS = $(LIBINTL)
-filefuncs_la_SOURCES = filefuncs.c
+filefuncs_la_SOURCES = filefuncs.c stack.h stack.c
 filefuncs_la_LDFLAGS = $(MY_MODULE_FLAGS)
 filefuncs_la_LIBADD = $(MY_LIBS)
 fnmatch_la_SOURCES = fnmatch.c
@@ -588,6 +588,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 
diff --git a/extension/configh.in b/extension/configh.in
index aae3484..73ce026 100644
--- a/extension/configh.in
+++ b/extension/configh.in
@@ -23,6 +23,15 @@
 /* Define to 1 if you have the <fnmatch.h> header file. */
 #undef HAVE_FNMATCH_H
 
+/* Define to 1 if you have the <fts.h> header file. */
+#undef HAVE_FTS_H
+
+/* Define to 1 if you have the `fts_open' function. */
+#undef HAVE_FTS_OPEN
+
+/* Define to 1 if you have the `fts_read' function. */
+#undef HAVE_FTS_READ
+
 /* Define to 1 if you have the `GetSystemTimeAsFileTime' function. */
 #undef HAVE_GETSYSTEMTIMEASFILETIME
 
diff --git a/extension/configure b/extension/configure
index f7f6ab9..9335a25 100755
--- a/extension/configure
+++ b/extension/configure
@@ -13438,7 +13438,7 @@ then
        CFLAGS="$CFLAGS -Wall -Wextra"
 fi
 
-for ac_header in dirent.h fnmatch.h time.h sys/time.h sys/select.h
+for ac_header in dirent.h fnmatch.h fts.h time.h sys/time.h sys/select.h
 do :
   as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
 ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" 
"$ac_includes_default"
@@ -13452,7 +13452,8 @@ fi
 done
 
 
-for ac_func in fdopendir fnmatch gettimeofday nanosleep select 
GetSystemTimeAsFileTime
+for ac_func in fdopendir fnmatch fts_open fts_read gettimeofday \
+               nanosleep select GetSystemTimeAsFileTime
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/extension/configure.ac b/extension/configure.ac
index 895572c..3300961 100644
--- a/extension/configure.ac
+++ b/extension/configure.ac
@@ -48,9 +48,10 @@ then
        CFLAGS="$CFLAGS -Wall -Wextra"
 fi
 
-AC_CHECK_HEADERS(dirent.h fnmatch.h time.h sys/time.h sys/select.h)
+AC_CHECK_HEADERS(dirent.h fnmatch.h fts.h time.h sys/time.h sys/select.h)
 
-AC_CHECK_FUNCS(fdopendir fnmatch gettimeofday nanosleep select 
GetSystemTimeAsFileTime)
+AC_CHECK_FUNCS(fdopendir fnmatch fts_open fts_read gettimeofday \
+               nanosleep select GetSystemTimeAsFileTime)
 
 dnl checks for compiler characteristics
 AC_C_INLINE
diff --git a/extension/filefuncs.3am b/extension/filefuncs.3am
index bdb8fe5..7969437 100644
--- a/extension/filefuncs.3am
+++ b/extension/filefuncs.3am
@@ -187,17 +187,22 @@ or
 .B FTS_PHYSICAL
 must be provided; otherwise
 .B fts()
-returns an error value.
+returns an error value and sets
+.BR ERRNO .
 .RS
 .TP
 .B FTS_LOGICAL
 Do a ``logical'' file traversal, where the information returned for
 a symbolic link refers to the linked-to file, and not to the
 symbolic link itself.
+This flag is mutually exclusive with
+.BR FTS_PHYSICAL .
 .TP
 .B FTS_PHYSICAL
 Do a ``physical'' file traversal, where the information returned for
 a symbolic link refers to the symbolic link itself.
+This flag is mutually exclusive with
+.BR FTS_LOGICAL .
 .TP
 .B FTS_NOCHDIR
 As a performance optimization, the
@@ -240,7 +245,7 @@ There are two cases.
 .RS
 .TP
 The path is a file.
-In this case, the array contains at two or three elements:
+In this case, the array contains two or three elements:
 .RS
 .TP
 \fB"path"\fP
diff --git a/extension/filefuncs.c b/extension/filefuncs.c
index e8c16e8..e27e51b 100644
--- a/extension/filefuncs.c
+++ b/extension/filefuncs.c
@@ -5,6 +5,7 @@
  * Arnold Robbins, update for 3.1, Mon Nov 23 12:53:39 EST 1998
  * Arnold Robbins and John Haque, update for 3.1.4, applied Mon Jun 14 
13:55:30 IDT 2004
  * Arnold Robbins and Andrew Schorr, revised for new extension API, May 2012.
+ * Arnold Robbins, add fts(), August 2012
  */
 
 /*
@@ -46,9 +47,20 @@
 #define _(msgid)  gettext(msgid)
 #define N_(msgid) msgid
 
+#if defined(HAVE_FTS_H) && defined(HAVE_FTS_OPEN) && defined(HAVE_FTS_READ)
+#define HAVE_FTS_ROUTINES
+#endif
+
+
+#ifdef HAVE_FTS_ROUTINES
+#include <fts.h>
+#include "stack.h"
+#endif
+
 static const gawk_api_t *api;  /* for convenience macros to work */
 static awk_ext_id_t *ext_id;
-static awk_bool_t (*init_func)(void) = NULL;
+static awk_bool_t init_filefuncs(void);
+static awk_bool_t (*init_func)(void) = init_filefuncs;
 
 int plugin_is_GPL_compatible;
 
@@ -237,11 +249,10 @@ array_set_numeric(awk_array_t array, const char *sub, 
double num)
 /* fill_stat_array --- do the work to fill an array with stat info */
 
 static int
-fill_stat_array(const char *name, awk_array_t array)
+fill_stat_array(const char *name, awk_array_t array, struct stat *sbuf)
 {
        char *pmode;    /* printable mode */
        const char *type = "unknown";
-       struct stat sbuf;
        awk_value_t tmp;
        static struct ftype_map {
                unsigned int mask;
@@ -264,52 +275,45 @@ fill_stat_array(const char *name, awk_array_t array)
                { S_IFDOOR, "door" },
 #endif /* S_IFDOOR */
        };
-       int ret, j, k;
+       int j, k;
 
        /* empty out the array */
        clear_array(array);
 
-       /* lstat the file, if error, set ERRNO and return */
-       ret = lstat(name, & sbuf);
-       if (ret < 0) {
-               update_ERRNO_int(errno);
-               return -1;
-       }
-
        /* fill in the array */
        array_set(array, "name", make_const_string(name, strlen(name), & tmp));
-       array_set_numeric(array, "dev", sbuf.st_dev);
-       array_set_numeric(array, "ino", sbuf.st_ino);
-       array_set_numeric(array, "mode", sbuf.st_mode);
-       array_set_numeric(array, "nlink", sbuf.st_nlink);
-       array_set_numeric(array, "uid", sbuf.st_uid);
-       array_set_numeric(array, "gid", sbuf.st_gid);
-       array_set_numeric(array, "size", sbuf.st_size);
-       array_set_numeric(array, "blocks", sbuf.st_blocks);
-       array_set_numeric(array, "atime", sbuf.st_atime);
-       array_set_numeric(array, "mtime", sbuf.st_mtime);
-       array_set_numeric(array, "ctime", sbuf.st_ctime);
+       array_set_numeric(array, "dev", sbuf->st_dev);
+       array_set_numeric(array, "ino", sbuf->st_ino);
+       array_set_numeric(array, "mode", sbuf->st_mode);
+       array_set_numeric(array, "nlink", sbuf->st_nlink);
+       array_set_numeric(array, "uid", sbuf->st_uid);
+       array_set_numeric(array, "gid", sbuf->st_gid);
+       array_set_numeric(array, "size", sbuf->st_size);
+       array_set_numeric(array, "blocks", sbuf->st_blocks);
+       array_set_numeric(array, "atime", sbuf->st_atime);
+       array_set_numeric(array, "mtime", sbuf->st_mtime);
+       array_set_numeric(array, "ctime", 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)) {
-               array_set_numeric(array, "rdev", sbuf.st_rdev);
-               array_set_numeric(array, "major", major(sbuf.st_rdev));
-               array_set_numeric(array, "minor", minor(sbuf.st_rdev));
+       if (S_ISBLK(sbuf->st_mode) || S_ISCHR(sbuf->st_mode)) {
+               array_set_numeric(array, "rdev", sbuf->st_rdev);
+               array_set_numeric(array, "major", major(sbuf->st_rdev));
+               array_set_numeric(array, "minor", minor(sbuf->st_rdev));
        }
 
 #ifdef HAVE_ST_BLKSIZE
-       array_set_numeric(array, "blksize", sbuf.st_blksize);
+       array_set_numeric(array, "blksize", sbuf->st_blksize);
 #endif /* HAVE_ST_BLKSIZE */
 
-       pmode = format_mode(sbuf.st_mode);
+       pmode = format_mode(sbuf->st_mode);
        array_set(array, "pmode", make_const_string(pmode, strlen(pmode), & 
tmp));
 
        /* for symbolic links, add a linkval field */
-       if (S_ISLNK(sbuf.st_mode)) {
+       if (S_ISLNK(sbuf->st_mode)) {
                char *buf;
                ssize_t linksize;
 
-               if ((buf = read_symlink(name, sbuf.st_size,
+               if ((buf = read_symlink(name, sbuf->st_size,
                                        & linksize)) != NULL)
                        array_set(array, "linkval", make_malloced_string(buf, 
linksize, & tmp));
                else
@@ -319,7 +323,7 @@ fill_stat_array(const char *name, awk_array_t array)
        /* add a type field */
        type = "unknown";       /* shouldn't happen */
        for (j = 0, k = sizeof(ftype_map)/sizeof(ftype_map[0]); j < k; j++) {
-               if ((sbuf.st_mode & S_IFMT) == ftype_map[j].mask) {
+               if ((sbuf->st_mode & S_IFMT) == ftype_map[j].mask) {
                        type = ftype_map[j].type;
                        break;
                }
@@ -339,6 +343,7 @@ do_stat(int nargs, awk_value_t *result)
        char *name;
        awk_array_t array;
        int ret;
+       struct stat sbuf;
 
        assert(result != NULL);
 
@@ -357,14 +362,370 @@ do_stat(int nargs, awk_value_t *result)
        name = file_param.str_value.str;
        array = array_param.array_cookie;
 
-       ret = fill_stat_array(name, array);
+       /* lstat the file, if error, set ERRNO and return */
+       ret = lstat(name, & sbuf);
+       if (ret < 0) {
+               update_ERRNO_int(errno);
+               return make_number(ret, result);
+       }
+
+       ret = fill_stat_array(name, array, & sbuf);
 
        return make_number(ret, result);
 }
 
+/* init_filefuncs --- initialization routine */
+
+static awk_bool_t
+init_filefuncs(void)
+{
+       int errors = 0;
+
+       /* at least right now, only FTS needs initializing */
+#ifdef HAVE_FTS_ROUTINES
+       int i;
+       awk_value_t value;
+
+       static struct flagtab {
+               const char *name;
+               int value;
+       } opentab[] = {
+#define ENTRY(x)       { #x, x }
+               ENTRY(FTS_COMFOLLOW),
+               ENTRY(FTS_LOGICAL),
+               ENTRY(FTS_NOCHDIR),
+               ENTRY(FTS_PHYSICAL),
+               ENTRY(FTS_SEEDOT),
+               ENTRY(FTS_XDEV),
+               { NULL, 0 }
+       };
+
+       for (i = 0; opentab[i].name != NULL; i++) {
+               (void) make_number(opentab[i].value, & value);
+               if (! sym_constant(opentab[i].name, & value)) {
+                       warning(ext_id, "fts init: could not create constant 
%s",
+                                       opentab[i].name);
+                       errors++;
+               }
+       }
+#endif
+       return errors == 0;
+}
+
+#ifdef HAVE_FTS_ROUTINES
+static int fts_errors = 0;
+
+/* fill_stat_element --- fill in stat element of array */
+
+static void
+fill_stat_element(awk_array_t element_array, const char *name, struct stat 
*sbuf)
+{
+       awk_value_t index, value;
+       awk_array_t stat_array;
+
+       stat_array = create_array();
+       if (stat_array == NULL) {
+               warning(ext_id, _("fill_stat_element: could not create array"));
+               fts_errors++;
+               return;
+       }
+       fill_stat_array(name, stat_array, sbuf);
+       (void) make_const_string("stat", 4, & index);
+       value.val_type = AWK_ARRAY;
+       value.array_cookie = stat_array;
+       if (! set_array_element(element_array, & index, & value)) {
+               warning(ext_id, _("fill_stat_element: could not set element"));
+               fts_errors++;
+       }
+}
+
+/* fill_path_element --- fill in path element of array */
+
+static void
+fill_path_element(awk_array_t element_array, const char *path)
+{
+       awk_value_t index, value;
+
+       (void) make_const_string("path", 4, & index);
+       (void) make_const_string(path, strlen(path), & value);
+       if (! set_array_element(element_array, & index, & value)) {
+               warning(ext_id, _("fill_path_element: could not set element"));
+               fts_errors++;
+       }
+}
+
+/* fill_error_element --- fill in error element of array */
+
+static void
+fill_error_element(awk_array_t element_array, const int errcode)
+{
+       awk_value_t index, value;
+       const char *err = strerror(errcode);
+
+       (void) make_const_string("error", 5, & index);
+       (void) make_const_string(err, strlen(err), & value);
+       if (! set_array_element(element_array, & index, & value)) {
+               warning(ext_id, _("fill_error_element: could not set element"));
+               fts_errors++;
+       }
+}
+
+/* fill_default_elements --- fill in stat and path elements */
+
+static void
+fill_default_elements(awk_array_t element_array, const FTSENT *const fentry, 
int bad_ret)
+{
+       /* full path */
+       fill_path_element(element_array, fentry->fts_path);
+
+       /* stat info */
+       if (! bad_ret) {
+               fill_stat_element(element_array,
+                               fentry->fts_name,
+                               fentry->fts_statp);
+       }
+
+       /* error info */
+       if (bad_ret || fentry->fts_errno != 0) {
+               fill_error_element(element_array, fentry->fts_errno);
+       }
+}
+
+/* process --- process the heirarchy */
+
+static void
+process(FTS *heirarchy, awk_array_t destarray, int seedot)
+{
+       FTSENT *fentry;
+       awk_value_t index, value;
+       awk_array_t element_array, newdir_array, dot_array;
+       int bad_ret = 0;
+
+       /* path is full path,  pathlen is length thereof */
+       /* name is name in directory, namelen is length thereof */
+       while ((fentry = fts_read(heirarchy)) != NULL) {
+               bad_ret = 0;
+
+               switch (fentry->fts_info) {
+               case FTS_D:
+                       /* directory */
+                       /* create array to hold entries */
+                       newdir_array = create_array();
+                       if (newdir_array == NULL) {
+                               warning(ext_id, _("fts-process: could not 
create array"));
+                               fts_errors++;
+                               break;
+                       }
+
+                       /* store new directory in its parent directory */
+                       (void) make_const_string(fentry->fts_name, 
fentry->fts_namelen, & index);
+                       value.val_type = AWK_ARRAY;
+                       value.array_cookie = newdir_array;
+                       if (! set_array_element(destarray, & index, & value)) {
+                               warning(ext_id, _("fts-process: could not set 
element"));
+                               fts_errors++;
+                               break;
+                       }
+                       newdir_array = value.array_cookie;
+
+                       /* push current directory */
+                       stack_push(destarray);
+
+                       /* new directory becomes current */
+                       destarray = newdir_array;
+                       break;
+
+               case FTS_DNR:
+               case FTS_DC:
+               case FTS_ERR:
+               case FTS_NS:
+                       /* error */
+                       bad_ret = 1;
+                       /* fall through */
+
+               case FTS_NSOK:
+               case FTS_SL:
+               case FTS_SLNONE:
+               case FTS_F:
+               case FTS_DOT:
+                       /* if see dot, skip "." */
+                       if (seedot && strcmp(fentry->fts_name, ".") == 0)
+                               break;
+
+                       /*
+                        * File case.
+                        * destarray is the directory we're reading.
+                        * step 1: create new empty array
+                        */
+                       element_array = create_array();
+                       if (element_array == NULL) {
+                               warning(ext_id, _("fts-process: could not 
create array"));
+                               fts_errors++;
+                               break;
+                       }
+
+                       /* step 2: add element array to parent array */
+                       (void) make_const_string(fentry->fts_name, 
fentry->fts_namelen, & index);
+                       value.val_type = AWK_ARRAY;
+                       value.array_cookie = element_array;
+                       if (! set_array_element(destarray, & index, & value)) {
+                               warning(ext_id, _("fts-process: could not set 
element"));
+                               fts_errors++;
+                               break;
+                       }
+
+                       /* step 3: fill in path, stat, error elements */
+                       fill_default_elements(element_array, fentry, bad_ret);
+                       break;
+
+               case FTS_DP:
+                       /* create "." subarray */
+                       dot_array = create_array();
+
+                       /* add it to parent */
+                       (void) make_const_string(".", 1, & index);
+                       value.val_type = AWK_ARRAY;
+                       value.array_cookie = dot_array;
+                       if (! set_array_element(destarray, & index, & value)) {
+                               warning(ext_id, _("fts-process: could not set 
element"));
+                               fts_errors++;
+                               break;
+                       }
+
+                       /* fill it in with path, stat, error elements */
+                       fill_default_elements(dot_array, fentry, bad_ret);
+
+                       /* now pop the parent directory off the stack */
+                       if (! stack_empty()) {
+                               /* pop stack */
+                               destarray = stack_pop();
+                       }
+
+                       break;
+
+               case FTS_DEFAULT:
+                       /* nothing to do */
+                       break;
+               }
+       }
+}
+#endif
+
+/*  do_fts --- walk a heirarchy and fill in an array */
+
+/*
+ * Usage from awk:
+ *     flags = or(FTS_PHYSICAL, ...)
+ *     result = fts(pathlist, flags, filedata)
+ */
+
+static awk_value_t *
+do_fts(int nargs, awk_value_t *result)
+{
+#ifdef HAVE_FTS_ROUTINES
+       awk_value_t pathlist, flagval, dest;
+       awk_flat_array_t *path_array = NULL;
+       char **pathvector = NULL;
+       FTS *heirarchy;
+       int flags;
+       size_t i, count;
+       int ret = -1;
+       static const int mask = (
+                 FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOCHDIR | FTS_PHYSICAL
+               | FTS_SEEDOT | FTS_XDEV);
+
+       assert(result != NULL);
+       fts_errors = 0;         /* ensure a fresh start */
+
+       if (do_lint && nargs != 3)
+               lintwarn(ext_id, _("fts: called with incorrect number of 
arguments, expecting 3"));
+
+       if (! get_argument(0, AWK_ARRAY, & pathlist)) {
+               warning(ext_id, _("fts: bad first parameter"));
+               update_ERRNO_int(EINVAL);
+               goto out;
+       }
+
+       if (! get_argument(1, AWK_NUMBER, & flagval)) {
+               warning(ext_id, _("fts: bad second parameter"));
+               update_ERRNO_int(EINVAL);
+               goto out;
+       }
+
+       if (! get_argument(2, AWK_ARRAY, & dest)) {
+               warning(ext_id, _("fts: bad third parameter"));
+               update_ERRNO_int(EINVAL);
+               goto out;
+       }
+
+       /* flatten pathlist */
+       if (! flatten_array(pathlist.array_cookie, & path_array)) {
+               warning(ext_id, _("fts: could not flatten array\n"));
+               goto out;
+       }
+
+       /* check the flags first, before the array flattening */
+
+       /* get flags */
+       flags = flagval.num_value;
+
+       /* enforce physical or logical but not both, and not no_stat */
+       if ((flags & (FTS_PHYSICAL|FTS_LOGICAL)) == 0
+           || (flags & (FTS_PHYSICAL|FTS_LOGICAL)) == 
(FTS_PHYSICAL|FTS_LOGICAL)) {
+               update_ERRNO_int(EINVAL);
+               goto out;
+       }
+       if ((flags & FTS_NOSTAT) != 0) {
+               flags &= ~FTS_NOSTAT;
+               if (do_lint)
+                       lintwarn(ext_id, _("fts: ignoring sneaky FTS_NOSTAT 
flag. nyah, nyah, nyah."));
+       }
+       flags &= mask;  /* turn off anything else */
+
+       /* make pathvector */
+       count = path_array->count + 1;
+       emalloc(pathvector, char **, count * sizeof(char *), "do_fts");
+       memset(pathvector, 0, count * sizeof(char *));
+
+       /* fill it in */
+       count--;        /* ignore final NULL at end of vector */
+       for (i = 0; i < count; i++)
+               pathvector[i] = path_array->elements[i].value.str_value.str;
+
+
+       /* clear dest array */
+       if (! clear_array(dest.array_cookie)) {
+               warning(ext_id, _("fts: clear_array failed\n"));
+               goto out;
+       }
+
+       /* let's do it! */
+       if ((heirarchy = fts_open(pathvector, flags, NULL)) != NULL) {
+               process(heirarchy, dest.array_cookie, (flags & FTS_SEEDOT) != 
0);
+               fts_close(heirarchy);
+
+               if (fts_errors == 0)
+                       ret = 0;
+       } else
+               update_ERRNO_int(errno);
+
+out:
+       if (pathvector != NULL)
+               free(pathvector);
+       if (path_array != NULL)
+               (void) release_flattened_array(pathlist.array_cookie, 
path_array);
+
+       return make_number(ret, result);
+#else
+       update_ERRNO_int(EINVAL);
+       return make_number(-1, result);
+#endif
+}
+
 static awk_ext_func_t func_table[] = {
-       { "chdir", do_chdir, 1 },
-       { "stat", do_stat, 2 },
+       { "chdir",      do_chdir, 1 },
+       { "stat",       do_stat, 2 },
+       { "fts",        do_fts, 3 },
 };
 
 
diff --git a/extension/stack.c b/extension/stack.c
new file mode 100644
index 0000000..ec994c6
--- /dev/null
+++ b/extension/stack.c
@@ -0,0 +1,90 @@
+/*
+ * stack.c -- Implementation for stack functions for use by extensions.
+ */
+
+/* 
+ * 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
+ */
+
+#include <stdlib.h>
+
+#include "stack.h"
+
+#define INITIAL_STACK  20
+
+static size_t size;
+static void **stack;
+static int index = -1;
+
+/* stack_empty --- return true if stack is empty */
+
+int
+stack_empty()
+{
+       return index < 0;
+}
+
+/* stack_top --- return top object on the stack */
+
+void *
+stack_top()
+{
+       if (stack_empty() || stack == NULL)
+               return NULL;
+
+       return stack[index];
+}
+
+/* stack_pop --- pop top object and return it */
+
+void *
+stack_pop()
+{
+       if (stack_empty() || stack == NULL)
+               return NULL;
+
+       return stack[index--];
+}
+
+/* stack_push --- push an object onto the stack */
+
+int stack_push(void *object)
+{
+       void **new_stack;
+       size_t new_size = 2 * size;
+
+       if (stack == NULL) {
+               stack = (void **) malloc(INITIAL_STACK * sizeof(void *));
+               if (stack == NULL)
+                       return 0;
+               size = INITIAL_STACK;
+       } else if (index + 1 >= size) {
+               if (new_size < size)
+                       return 0;
+               new_stack = realloc(stack, new_size * sizeof(void *));
+               if (new_stack == NULL)
+                       return 0;
+               size = new_size;
+               stack = new_stack;
+       }
+
+       stack[++index] = object;
+       return 1;
+}
diff --git a/extension/stack.h b/extension/stack.h
new file mode 100644
index 0000000..8fc06e7
--- /dev/null
+++ b/extension/stack.h
@@ -0,0 +1,31 @@
+/*
+ * stack.h -- Definitions for stack functions for use by extensions.
+ */
+
+/* 
+ * 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
+ */
+
+extern int stack_empty();      /* return true if stack is empty */
+extern void *stack_top();      /* return top object on the stack */
+extern void *stack_pop();      /* pop top object and return it */
+extern int stack_push(void *); /* push an object onto the stack,
+                                * return 0 if failed, 1 if success 
+                                */
diff --git a/gawkapi.c b/gawkapi.c
index 721d69d..c34b52b 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -517,6 +517,7 @@ sym_update_real(awk_ext_id_t id,
                        array_node->vname = node->vname;
                        *node = *array_node;
                        freenode(array_node);
+                       value->array_cookie = node;     /* pass new cookie back 
to extension */
                } else {
                        /* regular variable */
                        node = install_symbol(estrdup((char *) name, 
strlen(name)),
diff --git a/gawkapi.h b/gawkapi.h
index 7e20d3d..f345d07 100644
--- a/gawkapi.h
+++ b/gawkapi.h
@@ -51,17 +51,37 @@
  * and reuse it directly, even for something that is conceptually pass
  * by value.
  *
- * 2. The correct way to create new arrays is to work "bottom up".
+ * 2. Due to gawk internals, after using sym_update() to install an array
+ * into gawk, you have to retrieve the array cookie from the value
+ * passed in to sym_update().  Like so:
  *
  *     new_array = create_array();
- *     // fill in new array with lots of subscripts and values
  *     val.val_type = AWK_ARRAY;
  *     val.array_cookie = new_array;
- *     sym_update("array", &val);      // install array in the symbol table
+ *     sym_update("array", & val);     // install array in the symbol table
+ *
+ *     new_array = val.array_cookie;   // MUST DO THIS
+ *
+ *     // fill in new array with lots of subscripts and values
+ *
+ * Similarly, if installing a new array as a subarray of an existing
+ * array, you must add the new array to its parent before adding any
+ * elements to it.
+ *
+ * You must also retrieve the value of the array_cookie after the call
+ * to set_element().
+ *
+ * Thus, the correct way to build an array is to work "top down".
+ * Create the array, and immediately install it in gawk's symbol table
+ * using sym_update(), or install it as an element in a previously
+ * existing array using set_element().
  *
- * After doing so, do NOT make further use of the new_array variable;
- * instead use sym_lookup to get the array_cookie if you need to do further
- * manipulation of the array.
+ * The new array must ultimately be rooted in a global symbol. This is
+ * necessary before installing any subarrays in it, due to gawk's
+ * internal implementation.  Strictly speaking, this is required only
+ * for arrays that will have subarrays as elements; however it is
+ * a good idea to always do this.  This restriction may be relaxed
+ * in a subsequent revision of the API.
  */
 
 /* Allow use in C++ code.  */
@@ -249,15 +269,15 @@ typedef void *awk_ext_id_t;       /* opaque type for 
extension id */
  * logically organized.
  */
 typedef struct gawk_api {
-       int major_version;
-       int minor_version;
+       awk_const int major_version;
+       awk_const int minor_version;
 
        /*
         * These can change on the fly as things happen within gawk.
         * Currently only do_lint is prone to change, but we reserve
         * the right to allow the others also.
         */
-       int do_flags[DO_FLAGS_SIZE];
+       awk_const 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
diff --git a/test/ChangeLog b/test/ChangeLog
index c012513..2b1ac64 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,8 @@
+2012-08-08         Arnold D. Robbins     <address@hidden>
+
+       * Makefile.am (fts): New test.
+       * fts.awk: New file.
+
 2012-07-30         Arnold D. Robbins     <address@hidden>
 
        * Makefile.am (assignconst): Use AWKPATH to get results that will
diff --git a/test/Makefile.am b/test/Makefile.am
index 270cc2f..3a8e48c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -275,6 +275,7 @@ EXTRA_DIST = \
        fstabplus.awk \
        fstabplus.in \
        fstabplus.ok \
+       fts.awk \
        funlen.awk \
        funlen.in \
        funlen.ok \
@@ -895,7 +896,7 @@ LOCALE_CHARSET_TESTS = \
        mbprintf1 mbprintf2 mbprintf3 rebt8b2 rtlenmb sort1 sprintfc
 
 SHLIB_TESTS = \
-       assignconst fnmatch filefuncs fork fork2 ordchr ordchr2 \
+       assignconst fnmatch filefuncs fork fork2 fts ordchr ordchr2 \
        readdir readfile rwarray testext time
 
 # List of the tests which should be run with --lint option:
@@ -1612,6 +1613,11 @@ readdir:
        @$(AWK) -f $(srcdir)/readdir.awk . > address@hidden
        @-$(CMP) address@hidden address@hidden && rm -f address@hidden
 
+fts:
+       @echo $@
+       @$(AWK) -f $(srcdir)/fts.awk
+       @-$(CMP) address@hidden address@hidden && rm -f address@hidden
+
 # Targets generated for other tests:
 include Maketests
 
@@ -1620,7 +1626,7 @@ $(srcdir)/Maketests: $(srcdir)/Makefile.am 
$(srcdir)/Gentests
        $(AWK) -f $(srcdir)/Gentests "$(srcdir)/Makefile.am" $$files > 
$(srcdir)/Maketests
 
 clean:
-       rm -fr _* core core.* fmtspcl.ok junk out1 out2 out3 strftime.ok test1 
test2 seq *~ readfile.ok fork.tmp.* testext.awk
+       rm -fr _* core core.* fmtspcl.ok junk out1 out2 out3 strftime.ok test1 
test2 seq *~ readfile.ok fork.tmp.* testext.awk fts.out1 fts.out2
 
 # An attempt to print something that can be grepped for in build logs
 pass-fail:
diff --git a/test/Makefile.in b/test/Makefile.in
index 4b6d543..0ba7c5c 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -488,6 +488,7 @@ EXTRA_DIST = \
        fstabplus.awk \
        fstabplus.in \
        fstabplus.ok \
+       fts.awk \
        funlen.awk \
        funlen.in \
        funlen.ok \
@@ -1104,7 +1105,7 @@ LOCALE_CHARSET_TESTS = \
        mbprintf1 mbprintf2 mbprintf3 rebt8b2 rtlenmb sort1 sprintfc
 
 SHLIB_TESTS = \
-       assignconst fnmatch filefuncs fork fork2 ordchr ordchr2 \
+       assignconst fnmatch filefuncs fork fork2 fts ordchr ordchr2 \
        readdir readfile rwarray testext time
 
 
@@ -1994,6 +1995,11 @@ readdir:
        @ls -fli | sed 1d | $(AWK) -f $(srcdir)/readdir0.awk > address@hidden
        @$(AWK) -f $(srcdir)/readdir.awk . > address@hidden
        @-$(CMP) address@hidden address@hidden && rm -f address@hidden
+
+fts:
+       @echo $@
+       @$(AWK) -f $(srcdir)/fts.awk
+       @-$(CMP) address@hidden address@hidden && rm -f address@hidden
 Gt-dummy:
 # file Maketests, generated from Makefile.am by the Gentests program
 addcomma:
@@ -3239,7 +3245,7 @@ $(srcdir)/Maketests: $(srcdir)/Makefile.am 
$(srcdir)/Gentests
        $(AWK) -f $(srcdir)/Gentests "$(srcdir)/Makefile.am" $$files > 
$(srcdir)/Maketests
 
 clean:
-       rm -fr _* core core.* fmtspcl.ok junk out1 out2 out3 strftime.ok test1 
test2 seq *~ readfile.ok fork.tmp.* testext.awk
+       rm -fr _* core core.* fmtspcl.ok junk out1 out2 out3 strftime.ok test1 
test2 seq *~ readfile.ok fork.tmp.* testext.awk fts.out1 fts.out2
 
 # An attempt to print something that can be grepped for in build logs
 pass-fail:
diff --git a/test/fts.awk b/test/fts.awk
new file mode 100644
index 0000000..b90adfb
--- /dev/null
+++ b/test/fts.awk
@@ -0,0 +1,121 @@
address@hidden "filefuncs"
+
+BEGIN {
+       Level = 0
+
+       system("rm -fr d1 d2")
+       system("mkdir d1 d2 ; touch d1/f1 d1/f2 d2/f1 d2/f2")
+       pathlist[1] = "d1"
+       pathlist[2] = "d2"
+       flags = FTS_PHYSICAL
+       fts(pathlist, flags, data)
+
+       output = "fts.out1"
+       traverse(data)
+       close(output)
+
+       ftswalk(pathlist, data2)
+       output = "fts.out2"
+       traverse(data2)
+       close(output)
+
+       system("rm -fr d1 d2")
+}
+
+function indent(        i)
+{
+       for (i = 1; i <= Level; i++)
+               printf("\t") > output
+}
+
+function sort_traverse(data,   sorted, i)
+{
+       asorti(data, sorted)
+       for (i = 1; i in sorted; i++) {
+               indent()
+               printf("%s --> %s\n", sorted[i], data[sorted[i]]) > output
+       }
+}
+
+function traverse(data,         i)
+{
+       for (i in data) {
+               if (isarray(data[i])) {
+                       indent()
+                       printf("%s:\n", i) > output
+
+                       Level++
+                       if (("mtime" in data[i]) && ! isarray(data[i][mtime])) {
+                               sort_traverse(data[i])
+                       } else {
+                               traverse(data[i])
+                       }
+                       Level--
+               } else {
+                       indent()
+                       printf("%s --> %s\n", i, data[i]) > output
+               }
+       }
+}
+
+
+function ftswalk(pathlist, data,       i, toppath)
+{
+       delete data
+       for (i = 1; i in pathlist; i++) {
+               toppath = pathlist[i]
+               data[toppath]["junk"]++ # create array
+               delete data[toppath]["junk"]
+               process(pathlist[i], data)
+       }
+}
+
+# enter process with pathname, array for that path already created but
+# empty
+
+function process(pathname, data_array,
+               stat_data, i, direntry, command, shortname)     # locals
+{
+       stat(pathname, stat_data)
+       if (stat_data["type"] == "file") {
+               shortname = strrstr(pathname, "/")
+               data_array["path"] = pathname
+               for (i in stat_data) {
+                       if (i == "name")
+                               data_array["stat"][i] = shortname
+                       else
+                               data_array["stat"][i] = stat_data[i]
+               }
+
+               return
+       }
+
+       # stuff for a directory
+
+       data_array[pathname]["."]["path"] = pathname
+       for (i in stat_data)
+               data_array[pathname]["."]["stat"][i] = stat_data[i]
+
+       command = ("ls -f " pathname)
+       while ((command | getline direntry) > 0) {
+               if (direntry == "." || direntry == "..")
+                       continue
+               data_array[pathname][direntry]["junk"]++
+               delete data_array[pathname][direntry]["junk"]
+               process(pathname "/" direntry,
+                       data_array[pathname][direntry])
+       }
+       close(command)
+}
+
+function strrstr(string, delim,                ind)
+{
+       if ((ind = index(string, delim)) == 0)
+               return string
+
+       do {
+               string = substr(string, ind + 1)
+       } while ((ind = index(string, delim)) > 0)
+
+       return string
+}

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=30bb821bad107a676c1d0f0688f90b2b7e6c7505

commit 30bb821bad107a676c1d0f0688f90b2b7e6c7505
Author: Arnold D. Robbins <address@hidden>
Date:   Wed Aug 8 22:06:25 2012 +0300

    Remove asserts for production build.

diff --git a/ChangeLog b/ChangeLog
index 3c8a72f..1c686d0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2012-08-08         Arnold D. Robbins     <address@hidden>
+
+       * configure.ac: Add -DNDEBUG to remove asserts if not developing.
+
 2012-08-01         Arnold D. Robbins     <address@hidden>
 
        * io.c (iop_finish): New function.
diff --git a/configure b/configure
index c45d0cd..5640996 100755
--- a/configure
+++ b/configure
@@ -5553,6 +5553,7 @@ $as_echo "yes" >&6; }
 else
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
+       CFLAGS="$CFLAGS -DNDEBUG"       # turn off assertions
 fi
 
 
diff --git a/configure.ac b/configure.ac
index f3cf677..bb81f80 100644
--- a/configure.ac
+++ b/configure.ac
@@ -95,6 +95,7 @@ then
        AC_MSG_RESULT([yes])
 else
        AC_MSG_RESULT([no])
+       CFLAGS="$CFLAGS -DNDEBUG"       # turn off assertions
 fi
 
 AC_SUBST(CFLAGS)

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                 |    8 +
 configure                                 |    1 +
 configure.ac                              |    1 +
 extension/ChangeLog                       |   10 +
 extension/Makefile.am                     |    2 +-
 extension/Makefile.in                     |    5 +-
 extension/configh.in                      |    9 +
 extension/configure                       |    5 +-
 extension/configure.ac                    |    5 +-
 extension/filefuncs.3am                   |    9 +-
 extension/filefuncs.c                     |  429 ++++++++++++++++++++++++++---
 extension/stack.c                         |   90 ++++++
 missing_d/gawkbool.h => extension/stack.h |   23 +-
 gawkapi.c                                 |    1 +
 gawkapi.h                                 |   38 ++-
 test/ChangeLog                            |    5 +
 test/Makefile.am                          |   10 +-
 test/Makefile.in                          |   10 +-
 test/fts.awk                              |  121 ++++++++
 19 files changed, 710 insertions(+), 72 deletions(-)
 create mode 100644 extension/stack.c
 copy missing_d/gawkbool.h => extension/stack.h (70%)
 create mode 100644 test/fts.awk


hooks/post-receive
-- 
gawk



reply via email to

[Prev in Thread] Current Thread [Next in Thread]