From 06323619397520aba2fc2f8f983d67d06c6610fa Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Sun, 13 May 2012 16:39:35 -0400 Subject: Add comment to extension/filefuncs.c discussing unref on value from assoc_lookup. --- extension/filefuncs.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 9758ba8e..01f3fce2 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -220,6 +220,13 @@ array_set(NODE *array, const char *sub, NODE *value) tmp = make_string(sub, strlen(sub)); aptr = assoc_lookup(array, tmp); unref(tmp); + /* + * Note: since we initialized with assoc_clear, we know that aptr + * has been initialized with Nnull_string. Thus, the call to + * unref(*aptr) is not strictly necessary. However, I think it is + * generally more correct to call unref to maintain the proper + * reference count. + */ unref(*aptr); *aptr = value; } -- cgit v1.2.3 From 577c3fc31a2718461fba2e599d162de96fe838fa Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Thu, 24 May 2012 15:34:17 -0400 Subject: First working version of new API mechanism (probably has memory leaks). --- extension/filefuncs.c | 221 +++++++++++++++++++++++++++----------------------- 1 file changed, 118 insertions(+), 103 deletions(-) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 01f3fce2..74a086a9 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -7,7 +7,8 @@ */ /* - * Copyright (C) 2001, 2004, 2005, 2010, 2011 the Free Software Foundation, Inc. + * Copyright (C) 2001, 2004, 2005, 2010, 2011, 2012 + * the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Programming Language. @@ -27,28 +28,40 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -#include "awk.h" +#include +#include +#include +#include +#include + +#include +#include +#include "config.h" +#include "gawkapi.h" + +static const gawk_api_t *api; /* for convenience macros to work */ +static awk_ext_id_t *ext_id; int plugin_is_GPL_compatible; /* do_chdir --- provide dynamically loaded chdir() builtin for gawk */ -static NODE * -do_chdir(int nargs) +static awk_value_t * +do_chdir(int nargs, awk_value_t *result) { - NODE *newdir; + awk_value_t newdir; int ret = -1; if (do_lint && nargs != 1) - lintwarn("chdir: called with incorrect number of arguments"); + lintwarn(ext_id, "chdir: called with incorrect number of arguments"); - newdir = get_scalar_argument(0, false); - (void) force_string(newdir); - ret = chdir(newdir->stptr); - if (ret < 0) - update_ERRNO_int(errno); + if (get_curfunc_param(0, AWK_STRING, &newdir) != NULL) { + ret = chdir(newdir.str_value.str); + if (ret < 0) + update_ERRNO_int(errno); + } - return make_number((AWKNUM) ret); + return make_number(ret, result); } /* format_mode --- turn a stat mode field into something readable */ @@ -57,7 +70,15 @@ static char * format_mode(unsigned long fmode) { static char outbuf[12]; - int i; + static struct mode_map { + int mask; + int rep; + } map[] = { + { S_IRUSR, 'r' }, { S_IWUSR, 'w' }, { S_IXUSR, 'x' }, + { S_IRGRP, 'r' }, { S_IWGRP, 'w' }, { S_IXGRP, 'x' }, + { S_IROTH, 'r' }, { S_IWOTH, 'w' }, { S_IXOTH, 'x' }, + }; + int i, j, k; strcpy(outbuf, "----------"); /* first, get the file type */ @@ -97,39 +118,16 @@ format_mode(unsigned long fmode) #endif } - i++; - if ((fmode & S_IRUSR) != 0) - outbuf[i] = 'r'; - i++; - if ((fmode & S_IWUSR) != 0) - outbuf[i] = 'w'; - i++; - if ((fmode & S_IXUSR) != 0) - outbuf[i] = 'x'; - i++; - - if ((fmode & S_IRGRP) != 0) - outbuf[i] = 'r'; - i++; - if ((fmode & S_IWGRP) != 0) - outbuf[i] = 'w'; - i++; - if ((fmode & S_IXGRP) != 0) - outbuf[i] = 'x'; - i++; + for (j = 0, k = sizeof(map)/sizeof(map[0]); j < k; j++) { + i++; + if ((fmode & map[j].mask) != 0) + outbuf[i] = map[j].rep; + } - if ((fmode & S_IROTH) != 0) - outbuf[i] = 'r'; - i++; - if ((fmode & S_IWOTH) != 0) - outbuf[i] = 'w'; i++; - if ((fmode & S_IXOTH) != 0) - outbuf[i] = 'x'; - i++; - outbuf[i] = '\0'; + /* setuid bit */ if ((fmode & S_ISUID) != 0) { if (outbuf[3] == 'x') outbuf[3] = 's'; @@ -145,6 +143,7 @@ format_mode(unsigned long fmode) outbuf[6] = 'l'; } + /* the so-called "sticky" bit */ if ((fmode & S_ISVTX) != 0) { if (outbuf[9] == 'x') outbuf[9] = 't'; @@ -158,7 +157,7 @@ format_mode(unsigned long fmode) /* 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 + for example, on GNU/Linux in the /proc filesystem, where the symbolic link sizes are often 0. */ #ifndef SIZE_MAX @@ -176,10 +175,12 @@ read_symlink(const char *fname, size_t bufsize, ssize_t *linksize) if (bufsize) bufsize += 2; else - bufsize = BUFSIZ*2; + bufsize = BUFSIZ * 2; + /* Make sure that bufsize >= 2 and within range */ - if ((bufsize > MAXSIZE) || (bufsize < 2)) + if (bufsize > MAXSIZE || bufsize < 2) bufsize = MAXSIZE; + while (1) { char *buf; @@ -212,93 +213,106 @@ read_symlink(const char *fname, size_t bufsize, ssize_t *linksize) /* array_set --- set an array element */ static void -array_set(NODE *array, const char *sub, NODE *value) +array_set(awk_array_t array, const char *sub, awk_value_t *value) +{ + awk_element_t element; + awk_value_t tmp; + + memset(& element, 0, sizeof(element)); + + element.index = dup_string(sub, strlen(sub), & tmp)->str_value; + element.value = *value; + + set_array_element(array, & element); +} + +static void +array_set_numeric(awk_array_t array, const char *sub, double num) { - NODE *tmp; - NODE **aptr; - - tmp = make_string(sub, strlen(sub)); - aptr = assoc_lookup(array, tmp); - unref(tmp); - /* - * Note: since we initialized with assoc_clear, we know that aptr - * has been initialized with Nnull_string. Thus, the call to - * unref(*aptr) is not strictly necessary. However, I think it is - * generally more correct to call unref to maintain the proper - * reference count. - */ - unref(*aptr); - *aptr = value; + awk_value_t tmp; + return array_set(array, sub, make_number(num, & tmp)); } /* do_stat --- provide a stat() function for gawk */ -static NODE * -do_stat(int nargs) +static awk_value_t * +do_stat(int nargs, awk_value_t *result) { - NODE *file, *array; + awk_value_t file_param, array_param; + char *name; + awk_array_t array; struct stat sbuf; int ret; char *pmode; /* printable mode */ char *type = "unknown"; + awk_value_t tmp; - if (do_lint && nargs > 2) - lintwarn("stat: called with too many arguments"); + if (do_lint && nargs != 2) { + lintwarn(ext_id, "stat: called with wrong number of arguments"); + /* XXX previous version returned 0; why? */ + return make_number(-1, result); + } /* file is first arg, array to hold results is second */ - file = get_scalar_argument(0, false); - array = get_array_argument(1, false); + if (get_curfunc_param(0, AWK_STRING, &file_param) == NULL || + get_curfunc_param(1, AWK_ARRAY, &array_param) == NULL) { + warning(ext_id, "stat: bad parameters"); + /* XXX previous version returned 0; why? */ + return make_number(-1, result); + } + + name = file_param.str_value.str; + array = array_param.array_cookie; /* empty out the array */ - assoc_clear(array); + clear_array(array); /* lstat the file, if error, set ERRNO and return */ - (void) force_string(file); - ret = lstat(file->stptr, & sbuf); + ret = lstat(name, & sbuf); if (ret < 0) { update_ERRNO_int(errno); - return make_number((AWKNUM) ret); + /* XXX previous version returned 0; why? */ + return make_number(-1, result); } /* fill in the array */ - 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)); + array_set(array, "name", make_string(name, file_param.str_value.len, &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); /* for block and character devices, add rdev, major and minor numbers */ if (S_ISBLK(sbuf.st_mode) || S_ISCHR(sbuf.st_mode)) { - 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))); + 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(array, "blksize", make_number((AWKNUM) sbuf.st_blksize)); + array_set_numeric(array, "blksize", sbuf.st_blksize); #endif /* HAVE_ST_BLKSIZE */ pmode = format_mode(sbuf.st_mode); - array_set(array, "pmode", make_string(pmode, strlen(pmode))); + array_set(array, "pmode", make_string(pmode, strlen(pmode), &tmp)); /* for symbolic links, add a linkval field */ if (S_ISLNK(sbuf.st_mode)) { char *buf; ssize_t linksize; - if ((buf = read_symlink(file->stptr, sbuf.st_size, + if ((buf = read_symlink(name, sbuf.st_size, &linksize)) != NULL) - array_set(array, "linkval", make_str_node(buf, linksize, ALREADY_MALLOCED)); + array_set(array, "linkval", make_string(buf, linksize, &tmp)); else - warning(_("unable to read symbolic link `%s'"), - file->stptr); + warning(ext_id, "unable to read symbolic link `%s'", name); } /* add a type field */ @@ -337,18 +351,19 @@ do_stat(int nargs) #endif } - array_set(array, "type", make_string(type, strlen(type))); + array_set(array, "type", make_string(type, strlen(type), &tmp)); - return make_number((AWKNUM) ret); + ret = 1; /* success */ + + return make_number(ret, result); } -/* dlload --- load new builtins in this library */ +static awk_ext_func_t func_table[] = { + { "chdir", do_chdir, 1 }, + { "stat", do_stat, 2 }, +}; -NODE * -dlload(NODE *tree, void *dl) -{ - make_builtin("chdir", do_chdir, 1); - make_builtin("stat", do_stat, 2); - return make_number((AWKNUM) 0); -} +/* define the dl_load function using the boilerplate macro */ + +dl_load_func(func_table, filefuncs, "") -- cgit v1.2.3 From eec7101174a3b2807fb282272f75cc13d4b953c3 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Fri, 25 May 2012 15:18:43 +0300 Subject: Additional changes / some cleanups. --- extension/filefuncs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 74a086a9..fb19f2b3 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -230,7 +230,7 @@ static void array_set_numeric(awk_array_t array, const char *sub, double num) { awk_value_t tmp; - return array_set(array, sub, make_number(num, & tmp)); + array_set(array, sub, make_number(num, & tmp)); } /* do_stat --- provide a stat() function for gawk */ -- cgit v1.2.3 From 04dc190623f0d99d80387b33ca747b8cbad37724 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Tue, 29 May 2012 23:33:27 +0300 Subject: Further API work. --- extension/filefuncs.c | 187 +++++++++++++++++++++++--------------------------- 1 file changed, 87 insertions(+), 100 deletions(-) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index fb19f2b3..46b1596e 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -4,6 +4,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. */ /* @@ -36,6 +37,7 @@ #include #include + #include "config.h" #include "gawkapi.h" @@ -53,9 +55,9 @@ do_chdir(int nargs, awk_value_t *result) int ret = -1; if (do_lint && nargs != 1) - lintwarn(ext_id, "chdir: called with incorrect number of arguments"); + lintwarn(ext_id, "chdir: called with incorrect number of arguments, expecting 1"); - if (get_curfunc_param(0, AWK_STRING, &newdir) != NULL) { + if (get_curfunc_param(0, AWK_STRING, & newdir) != NULL) { ret = chdir(newdir.str_value.str); if (ret < 0) update_ERRNO_int(errno); @@ -70,6 +72,27 @@ static char * format_mode(unsigned long fmode) { static char outbuf[12]; + static struct ftype_map { + int mask; + int charval; + } ftype_map[] = { + { S_IFREG, '-' }, /* redundant */ + { S_IFBLK, 'b' }, + { S_IFCHR, 'c' }, + { S_IFDIR, 'd' }, +#ifdef S_IFSOCK + { S_IFSOCK, 's' }, +#endif +#ifdef S_IFIFO + { S_IFIFO, 'p' }, +#endif +#ifdef S_IFLNK + { S_IFLNK, 'l' }, +#endif +#ifdef S_IFDOOR /* Solaris weirdness */ + { S_IFDOOR, 'D' }, +#endif /* S_IFDOOR */ + }; static struct mode_map { int mask; int rep; @@ -78,46 +101,30 @@ format_mode(unsigned long fmode) { S_IRGRP, 'r' }, { S_IWGRP, 'w' }, { S_IXGRP, 'x' }, { S_IROTH, 'r' }, { S_IWOTH, 'w' }, { S_IXOTH, 'x' }, }; + static struct setuid_map { + int mask; + int index; + int small_rep; + int big_rep; + } setuid_map[] = { + { S_ISUID, 3, 's', 'S' }, /* setuid bit */ + { S_ISGID, 6, 's', 'l' }, /* setgid without execute == locking */ + { S_ISVTX, 9, 't', 'T' }, /* the so-called "sticky" bit */ + }; int i, j, k; strcpy(outbuf, "----------"); + /* first, get the file type */ i = 0; - switch (fmode & S_IFMT) { -#ifdef S_IFSOCK - case S_IFSOCK: - outbuf[i] = 's'; - break; -#endif -#ifdef S_IFLNK - case S_IFLNK: - outbuf[i] = 'l'; - break; -#endif - case S_IFREG: - outbuf[i] = '-'; /* redundant */ - break; - case S_IFBLK: - outbuf[i] = 'b'; - break; - case S_IFDIR: - outbuf[i] = 'd'; - break; -#ifdef S_IFDOOR /* Solaris weirdness */ - case S_IFDOOR: - outbuf[i] = 'D'; - break; -#endif /* S_IFDOOR */ - case S_IFCHR: - outbuf[i] = 'c'; - break; -#ifdef S_IFIFO - case S_IFIFO: - outbuf[i] = 'p'; - break; -#endif + for (j = 0, k = sizeof(ftype_map)/sizeof(ftype_map[0]); j < k; j++) { + if ((fmode & S_IFMT) == ftype_map[j].mask) { + outbuf[i] = ftype_map[j].charval; + break; + } } + /* now the permissions */ for (j = 0, k = sizeof(map)/sizeof(map[0]); j < k; j++) { i++; if ((fmode & map[j].mask) != 0) @@ -127,28 +134,14 @@ format_mode(unsigned long fmode) i++; outbuf[i] = '\0'; - /* setuid bit */ - if ((fmode & S_ISUID) != 0) { - if (outbuf[3] == 'x') - outbuf[3] = 's'; - else - outbuf[3] = 'S'; - } - - /* setgid without execute == locking */ - if ((fmode & S_ISGID) != 0) { - if (outbuf[6] == 'x') - outbuf[6] = 's'; - else - outbuf[6] = 'l'; - } - - /* the so-called "sticky" bit */ - if ((fmode & S_ISVTX) != 0) { - if (outbuf[9] == 'x') - outbuf[9] = 't'; - else - outbuf[9] = 'T'; + /* tweaks for the setuid / setgid / sticky bits */ + for (j = 0, k = sizeof(setuid_map)/sizeof(setuid_map[0]); j < k; j++) { + if (fmode & setuid_map[j].mask) { + if (outbuf[setuid_map[j].index] == 'x') + outbuf[setuid_map[j].index] = setuid_map[j].small_rep; + else + outbuf[setuid_map[j].index] = setuid_map[j].big_rep; + } } return outbuf; @@ -226,10 +219,13 @@ array_set(awk_array_t array, const char *sub, awk_value_t *value) set_array_element(array, & element); } +/* array_set_numeric --- set an array element with a number */ + static void array_set_numeric(awk_array_t array, const char *sub, double num) { awk_value_t tmp; + array_set(array, sub, make_number(num, & tmp)); } @@ -242,22 +238,41 @@ do_stat(int nargs, awk_value_t *result) char *name; awk_array_t array; struct stat sbuf; - int ret; + int ret, j, k; char *pmode; /* printable mode */ char *type = "unknown"; awk_value_t tmp; + static struct ftype_map { + int mask; + const char *type; + } ftype_map[] = { + { S_IFREG, "file" }, + { S_IFBLK, "blockdev" }, + { S_IFCHR, "chardev" }, + { S_IFDIR, "directory" }, +#ifdef S_IFSOCK + { S_IFSOCK, "socket" }, +#endif +#ifdef S_IFIFO + { S_IFIFO, "fifo" }, +#endif +#ifdef S_IFLNK + { S_IFLNK, "symlink" }, +#endif +#ifdef S_IFDOOR /* Solaris weirdness */ + { S_IFDOOR, "door" }, +#endif /* S_IFDOOR */ + }; if (do_lint && nargs != 2) { lintwarn(ext_id, "stat: called with wrong number of arguments"); - /* XXX previous version returned 0; why? */ return make_number(-1, result); } /* file is first arg, array to hold results is second */ - if (get_curfunc_param(0, AWK_STRING, &file_param) == NULL || - get_curfunc_param(1, AWK_ARRAY, &array_param) == NULL) { + if ( get_curfunc_param(0, AWK_STRING, & file_param) == NULL + || get_curfunc_param(1, AWK_ARRAY, & array_param) == NULL) { warning(ext_id, "stat: bad parameters"); - /* XXX previous version returned 0; why? */ return make_number(-1, result); } @@ -271,7 +286,6 @@ do_stat(int nargs, awk_value_t *result) ret = lstat(name, & sbuf); if (ret < 0) { update_ERRNO_int(errno); - /* XXX previous version returned 0; why? */ return make_number(-1, result); } @@ -301,7 +315,7 @@ do_stat(int nargs, awk_value_t *result) #endif /* HAVE_ST_BLKSIZE */ pmode = format_mode(sbuf.st_mode); - array_set(array, "pmode", make_string(pmode, strlen(pmode), &tmp)); + array_set(array, "pmode", make_string(pmode, strlen(pmode), & tmp)); /* for symbolic links, add a linkval field */ if (S_ISLNK(sbuf.st_mode)) { @@ -309,46 +323,19 @@ do_stat(int nargs, awk_value_t *result) ssize_t linksize; if ((buf = read_symlink(name, sbuf.st_size, - &linksize)) != NULL) - array_set(array, "linkval", make_string(buf, linksize, &tmp)); + & linksize)) != NULL) + array_set(array, "linkval", make_string(buf, linksize, & tmp)); else - warning(ext_id, "unable to read symbolic link `%s'", name); + warning(ext_id, "stat: unable to read symbolic link `%s'", name); } /* add a type field */ - switch (sbuf.st_mode & S_IFMT) { -#ifdef S_IFSOCK - case S_IFSOCK: - type = "socket"; - break; -#endif -#ifdef S_IFLNK - case S_IFLNK: - type = "symlink"; - break; -#endif - case S_IFREG: - type = "file"; - break; - case S_IFBLK: - type = "blockdev"; - break; - case S_IFDIR: - type = "directory"; - break; -#ifdef S_IFDOOR - case S_IFDOOR: - type = "door"; - break; -#endif - case S_IFCHR: - type = "chardev"; - break; -#ifdef S_IFIFO - case S_IFIFO: - type = "fifo"; - break; -#endif + 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) { + type = ftype_map[j].type; + break; + } } array_set(array, "type", make_string(type, strlen(type), &tmp)); -- cgit v1.2.3 From fcc37ab5b658388a6fa14bcd9c0254454418c96a Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Wed, 6 Jun 2012 20:03:29 +0300 Subject: Minor fixes for printf compile warnings. --- extension/filefuncs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 46b1596e..4d382005 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -240,7 +240,7 @@ do_stat(int nargs, awk_value_t *result) struct stat sbuf; int ret, j, k; char *pmode; /* printable mode */ - char *type = "unknown"; + const char *type = "unknown"; awk_value_t tmp; static struct ftype_map { int mask; -- cgit v1.2.3 From 820b6a2ccb7859e15ade36af6ac1d0d08c1da4b1 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Tue, 12 Jun 2012 22:10:31 +0300 Subject: Further cleanups and improvements in API. --- extension/filefuncs.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 4d382005..12f3acb6 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -57,7 +57,7 @@ do_chdir(int nargs, awk_value_t *result) if (do_lint && nargs != 1) lintwarn(ext_id, "chdir: called with incorrect number of arguments, expecting 1"); - if (get_curfunc_param(0, AWK_STRING, & newdir) != NULL) { + if (get_argument(0, AWK_STRING, & newdir)) { ret = chdir(newdir.str_value.str); if (ret < 0) update_ERRNO_int(errno); @@ -73,7 +73,7 @@ format_mode(unsigned long fmode) { static char outbuf[12]; static struct ftype_map { - int mask; + unsigned int mask; int charval; } ftype_map[] = { { S_IFREG, '-' }, /* redundant */ @@ -94,7 +94,7 @@ format_mode(unsigned long fmode) #endif /* S_IFDOOR */ }; static struct mode_map { - int mask; + unsigned int mask; int rep; } map[] = { { S_IRUSR, 'r' }, { S_IWUSR, 'w' }, { S_IXUSR, 'x' }, @@ -102,7 +102,7 @@ format_mode(unsigned long fmode) { S_IROTH, 'r' }, { S_IWOTH, 'w' }, { S_IXOTH, 'x' }, }; static struct setuid_map { - int mask; + unsigned int mask; int index; int small_rep; int big_rep; @@ -243,7 +243,7 @@ do_stat(int nargs, awk_value_t *result) const char *type = "unknown"; awk_value_t tmp; static struct ftype_map { - int mask; + unsigned int mask; const char *type; } ftype_map[] = { { S_IFREG, "file" }, @@ -270,8 +270,8 @@ do_stat(int nargs, awk_value_t *result) } /* file is first arg, array to hold results is second */ - if ( get_curfunc_param(0, AWK_STRING, & file_param) == NULL - || get_curfunc_param(1, AWK_ARRAY, & array_param) == NULL) { + if ( ! get_argument(0, AWK_STRING, & file_param) + || ! get_argument(1, AWK_ARRAY, & array_param)) { warning(ext_id, "stat: bad parameters"); return make_number(-1, result); } -- cgit v1.2.3 From 5e79fa8735ec2984fee9054cccd51d86fa939621 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Sun, 17 Jun 2012 20:47:50 +0300 Subject: Still more API and testext.c work. --- extension/filefuncs.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 12f3acb6..433a0ea9 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -30,6 +30,7 @@ */ #include +#include #include #include #include @@ -54,6 +55,8 @@ do_chdir(int nargs, awk_value_t *result) awk_value_t newdir; int ret = -1; + assert(result != NULL); + if (do_lint && nargs != 1) lintwarn(ext_id, "chdir: called with incorrect number of arguments, expecting 1"); @@ -264,6 +267,8 @@ do_stat(int nargs, awk_value_t *result) #endif /* S_IFDOOR */ }; + assert(result != NULL); + if (do_lint && nargs != 2) { lintwarn(ext_id, "stat: called with wrong number of arguments"); return make_number(-1, result); -- cgit v1.2.3 From 1e3ac8a49caeeb991d8163042a576a66db51c74b Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Mon, 18 Jun 2012 23:00:58 +0300 Subject: Get most of array flattening done. --- extension/filefuncs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 433a0ea9..d4e1b57c 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -216,7 +216,7 @@ array_set(awk_array_t array, const char *sub, awk_value_t *value) memset(& element, 0, sizeof(element)); - element.index = dup_string(sub, strlen(sub), & tmp)->str_value; + element.index = *make_string(sub, strlen(sub), & tmp); element.value = *value; set_array_element(array, & element); -- cgit v1.2.3 From 7d37bcd5a8066718b15de8c03725708819389931 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Mon, 9 Jul 2012 21:17:10 +0300 Subject: API: Update set_array_element(). Adjust extensions. --- extension/filefuncs.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index d4e1b57c..32a3cee6 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -211,15 +211,12 @@ read_symlink(const char *fname, size_t bufsize, ssize_t *linksize) static void array_set(awk_array_t array, const char *sub, awk_value_t *value) { - awk_element_t element; - awk_value_t tmp; - - memset(& element, 0, sizeof(element)); + awk_value_t index; - element.index = *make_string(sub, strlen(sub), & tmp); - element.value = *value; + set_array_element(array, + make_string(sub, strlen(sub), & index), + value); - set_array_element(array, & element); } /* array_set_numeric --- set an array element with a number */ -- cgit v1.2.3 From 6d1724214a95330b63a6a557f89fb9b40b4a521f Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Wed, 11 Jul 2012 21:26:37 +0300 Subject: API clean up and require strings to be malloced. --- extension/filefuncs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 32a3cee6..74af8b1b 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -214,7 +214,7 @@ array_set(awk_array_t array, const char *sub, awk_value_t *value) awk_value_t index; set_array_element(array, - make_string(sub, strlen(sub), & index), + make_const_string(sub, strlen(sub), & index), value); } @@ -292,7 +292,7 @@ do_stat(int nargs, awk_value_t *result) } /* fill in the array */ - array_set(array, "name", make_string(name, file_param.str_value.len, &tmp)); + array_set(array, "name", make_const_string(name, file_param.str_value.len, &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); @@ -317,7 +317,7 @@ do_stat(int nargs, awk_value_t *result) #endif /* HAVE_ST_BLKSIZE */ pmode = format_mode(sbuf.st_mode); - array_set(array, "pmode", make_string(pmode, strlen(pmode), & tmp)); + array_set(array, "pmode", make_const_string(pmode, strlen(pmode), & tmp)); /* for symbolic links, add a linkval field */ if (S_ISLNK(sbuf.st_mode)) { @@ -326,7 +326,7 @@ do_stat(int nargs, awk_value_t *result) if ((buf = read_symlink(name, sbuf.st_size, & linksize)) != NULL) - array_set(array, "linkval", make_string(buf, linksize, & tmp)); + array_set(array, "linkval", make_malloced_string(buf, linksize, & tmp)); else warning(ext_id, "stat: unable to read symbolic link `%s'", name); } @@ -340,7 +340,7 @@ do_stat(int nargs, awk_value_t *result) } } - array_set(array, "type", make_string(type, strlen(type), &tmp)); + array_set(array, "type", make_const_string(type, strlen(type), &tmp)); ret = 1; /* success */ -- cgit v1.2.3 From 73533707616e119778993fe18540098239ecbb2e Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Wed, 11 Jul 2012 21:41:54 +0300 Subject: Add ability to call an initialization routine. --- extension/filefuncs.c | 1 + 1 file changed, 1 insertion(+) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 74af8b1b..71387cb3 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -44,6 +44,7 @@ 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; int plugin_is_GPL_compatible; -- cgit v1.2.3 From 77036f5ae0d0c4e2e1551838c193dd2ca877a54e Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Fri, 13 Jul 2012 14:02:02 +0300 Subject: Refactoring filefuncs.c before fts changes. --- extension/filefuncs.c | 66 +++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 28 deletions(-) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 71387cb3..41783c85 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -230,18 +230,14 @@ array_set_numeric(awk_array_t array, const char *sub, double num) array_set(array, sub, make_number(num, & tmp)); } -/* do_stat --- provide a stat() function for gawk */ +/* fill_stat_array --- do the work to fill an array with stat info */ -static awk_value_t * -do_stat(int nargs, awk_value_t *result) +static int +fill_stat_array(const char *name, awk_array_t array) { - awk_value_t file_param, array_param; - char *name; - awk_array_t array; - struct stat sbuf; - int ret, j, k; char *pmode; /* printable mode */ const char *type = "unknown"; + struct stat sbuf; awk_value_t tmp; static struct ftype_map { unsigned int mask; @@ -264,23 +260,7 @@ do_stat(int nargs, awk_value_t *result) { S_IFDOOR, "door" }, #endif /* S_IFDOOR */ }; - - assert(result != NULL); - - if (do_lint && nargs != 2) { - lintwarn(ext_id, "stat: called with wrong number of arguments"); - return make_number(-1, result); - } - - /* file is first arg, array to hold results is second */ - if ( ! get_argument(0, AWK_STRING, & file_param) - || ! get_argument(1, AWK_ARRAY, & array_param)) { - warning(ext_id, "stat: bad parameters"); - return make_number(-1, result); - } - - name = file_param.str_value.str; - array = array_param.array_cookie; + int ret, j, k; /* empty out the array */ clear_array(array); @@ -289,11 +269,11 @@ do_stat(int nargs, awk_value_t *result) ret = lstat(name, & sbuf); if (ret < 0) { update_ERRNO_int(errno); - return make_number(-1, result); + return -1; } /* fill in the array */ - array_set(array, "name", make_const_string(name, file_param.str_value.len, &tmp)); + 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); @@ -343,7 +323,37 @@ do_stat(int nargs, awk_value_t *result) array_set(array, "type", make_const_string(type, strlen(type), &tmp)); - ret = 1; /* success */ + return 0; +} + +/* do_stat --- provide a stat() function for gawk */ + +static awk_value_t * +do_stat(int nargs, awk_value_t *result) +{ + awk_value_t file_param, array_param; + char *name; + awk_array_t array; + int ret; + + assert(result != NULL); + + if (do_lint && nargs != 2) { + lintwarn(ext_id, "stat: called with wrong number of arguments"); + return make_number(-1, result); + } + + /* file is first arg, array to hold results is second */ + if ( ! get_argument(0, AWK_STRING, & file_param) + || ! get_argument(1, AWK_ARRAY, & array_param)) { + warning(ext_id, "stat: bad parameters"); + return make_number(-1, result); + } + + name = file_param.str_value.str; + array = array_param.array_cookie; + + ret = fill_stat_array(name, array); return make_number(ret, result); } -- cgit v1.2.3 From 7e5b2a94ce3c089c50c5862168d1d917e5febcf4 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Wed, 25 Jul 2012 23:10:35 +0300 Subject: Add translation to the extensions. --- extension/filefuncs.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index 41783c85..e8c16e8f 100644 --- a/extension/filefuncs.c +++ b/extension/filefuncs.c @@ -42,6 +42,10 @@ #include "config.h" #include "gawkapi.h" +#include "gettext.h" +#define _(msgid) gettext(msgid) +#define N_(msgid) msgid + 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; @@ -59,7 +63,7 @@ do_chdir(int nargs, awk_value_t *result) assert(result != NULL); if (do_lint && nargs != 1) - lintwarn(ext_id, "chdir: called with incorrect number of arguments, expecting 1"); + lintwarn(ext_id, _("chdir: called with incorrect number of arguments, expecting 1")); if (get_argument(0, AWK_STRING, & newdir)) { ret = chdir(newdir.str_value.str); @@ -339,14 +343,14 @@ do_stat(int nargs, awk_value_t *result) assert(result != NULL); if (do_lint && nargs != 2) { - lintwarn(ext_id, "stat: called with wrong number of arguments"); + lintwarn(ext_id, _("stat: called with wrong number of arguments")); return make_number(-1, result); } /* file is first arg, array to hold results is second */ if ( ! get_argument(0, AWK_STRING, & file_param) || ! get_argument(1, AWK_ARRAY, & array_param)) { - warning(ext_id, "stat: bad parameters"); + warning(ext_id, _("stat: bad parameters")); return make_number(-1, result); } -- cgit v1.2.3 From 88e81c931345aa485e55c6d6c7f3ad61dc200fed Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Wed, 8 Aug 2012 22:37:55 +0300 Subject: Add fts() extension, support, doc, and test. --- extension/filefuncs.c | 429 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 395 insertions(+), 34 deletions(-) (limited to 'extension/filefuncs.c') diff --git a/extension/filefuncs.c b/extension/filefuncs.c index e8c16e8f..e27e51bf 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 +#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 }, }; -- cgit v1.2.3