From e5261cf0bb2b565661e5e4d1be4a78c64c501b34 Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Mon, 6 Mar 2017 20:42:18 -0500 Subject: Create new extension readdir_test for testing new get_record field_width parsing. --- extension/readdir_test.c | 336 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 336 insertions(+) create mode 100644 extension/readdir_test.c (limited to 'extension/readdir_test.c') 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 +#endif + +#define _BSD_SOURCE +#include +#include +#include +#include +#include + +#include +#include + +#ifdef HAVE_LIMITS_H +#include +#endif + +#ifdef HAVE_DIRENT_H +#include +#else +#error Cannot compile the dirent extension on this system! +#endif + +#ifdef __MINGW32__ +#define WIN32_LEAN_AND_MEAN +#include +#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, "") -- cgit v1.2.3 From 39c46265139aa8faf87160b30710876bde4c6ba9 Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Thu, 9 Mar 2017 20:44:09 -0500 Subject: For API input field parsing, use an array of structs instead of an array of integers. --- extension/readdir_test.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'extension/readdir_test.c') diff --git a/extension/readdir_test.c b/extension/readdir_test.c index cc23081e..e023b67c 100644 --- a/extension/readdir_test.c +++ b/extension/readdir_test.c @@ -85,7 +85,7 @@ int plugin_is_GPL_compatible; typedef struct open_directory { DIR *dp; char *buf; - int field_width[7]; + awk_input_field_info_t field_width[4]; } open_directory_t; /* ftype --- return type of file as a single character string */ @@ -169,7 +169,8 @@ get_inode(struct dirent *entry, const char *dirname) 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) + char **rt_start, size_t *rt_len, + const awk_input_field_info_t **field_width) { DIR *dp; struct dirent *dirent; @@ -206,13 +207,13 @@ dir_get_record(char **out, awk_input_buf_t *iobuf, int *errcode, #else len = sprintf(the_dir->buf, "%llu", ino); #endif - the_dir->field_width[1] = len; + the_dir->field_width[0].len = len; len += (flen = sprintf(the_dir->buf + len, "/%s", dirent->d_name)); - the_dir->field_width[3] = flen-1; + the_dir->field_width[1].len = flen-1; ftstr = ftype(dirent, iobuf->name); len += (flen = sprintf(the_dir->buf + len, "/%s", ftstr)); - the_dir->field_width[5] = flen-1; + the_dir->field_width[2].len = flen-1; *out = the_dir->buf; @@ -284,10 +285,10 @@ dir_take_control_of(awk_input_buf_t *iobuf) 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 */ + the_dir->field_width[0].skip = 0; /* no leading space */ + the_dir->field_width[1].skip = 1; /* single '/' separator */ + the_dir->field_width[2].skip = 1; /* single '/' separator */ + the_dir->field_width[3].skip = -1; /* terminate after 3 fields */ size = sizeof(struct dirent) + 21 /* max digits in inode */ + 2 /* slashes */; emalloc(the_dir->buf, char *, size, "dir_take_control_of"); -- cgit v1.2.3 From d1bebd3cbf60fa25883271512cf63e0c3275e3ef Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Tue, 21 Mar 2017 13:22:18 -0400 Subject: Enhance FIELDWIDTHS syntax to support a skip prefix, and unify logic with API field parsing. --- extension/readdir_test.c | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'extension/readdir_test.c') diff --git a/extension/readdir_test.c b/extension/readdir_test.c index e023b67c..d21b4e97 100644 --- a/extension/readdir_test.c +++ b/extension/readdir_test.c @@ -85,8 +85,12 @@ int plugin_is_GPL_compatible; typedef struct open_directory { DIR *dp; char *buf; - awk_input_field_info_t field_width[4]; + union { + awk_fieldwidth_info_t fw; + char buf[awk_fieldwidth_info_size(3)]; + } u; } open_directory_t; +#define fw u.fw /* ftype --- return type of file as a single character string */ @@ -170,7 +174,7 @@ get_inode(struct dirent *entry, const char *dirname) static int dir_get_record(char **out, awk_input_buf_t *iobuf, int *errcode, char **rt_start, size_t *rt_len, - const awk_input_field_info_t **field_width) + const awk_fieldwidth_info_t **field_width) { DIR *dp; struct dirent *dirent; @@ -207,20 +211,20 @@ dir_get_record(char **out, awk_input_buf_t *iobuf, int *errcode, #else len = sprintf(the_dir->buf, "%llu", ino); #endif - the_dir->field_width[0].len = len; + the_dir->fw.fields[0].len = len; len += (flen = sprintf(the_dir->buf + len, "/%s", dirent->d_name)); - the_dir->field_width[1].len = flen-1; + the_dir->fw.fields[1].len = flen-1; ftstr = ftype(dirent, iobuf->name); len += (flen = sprintf(the_dir->buf + len, "/%s", ftstr)); - the_dir->field_width[2].len = flen-1; + the_dir->fw.fields[2].len = flen-1; *out = the_dir->buf; *rt_start = NULL; *rt_len = 0; /* set RT to "" */ if (field_width) - *field_width = the_dir->field_width; + *field_width = & the_dir->fw; return len; } @@ -284,11 +288,12 @@ dir_take_control_of(awk_input_buf_t *iobuf) 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].skip = 0; /* no leading space */ - the_dir->field_width[1].skip = 1; /* single '/' separator */ - the_dir->field_width[2].skip = 1; /* single '/' separator */ - the_dir->field_width[3].skip = -1; /* terminate after 3 fields */ + /* pre-populate the field_width struct with constant values: */ + the_dir->fw.use_chars = awk_false; + the_dir->fw.nf = 3; + the_dir->fw.fields[0].skip = 0; /* no leading space */ + the_dir->fw.fields[1].skip = 1; /* single '/' separator */ + the_dir->fw.fields[2].skip = 1; /* single '/' separator */ size = sizeof(struct dirent) + 21 /* max digits in inode */ + 2 /* slashes */; emalloc(the_dir->buf, char *, size, "dir_take_control_of"); -- cgit v1.2.3 From 61b4108f82f30deaabf03eb6dbc0e64edeffdb6e Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Mon, 27 Mar 2017 21:27:50 +0300 Subject: Minor edits in feature/api-parser prepatory to merging. --- extension/readdir_test.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'extension/readdir_test.c') diff --git a/extension/readdir_test.c b/extension/readdir_test.c index d21b4e97..6d6ee134 100644 --- a/extension/readdir_test.c +++ b/extension/readdir_test.c @@ -10,7 +10,7 @@ */ /* - * Copyright (C) 2012-2014 the Free Software Foundation, Inc. + * Copyright (C) 2012-2014, 2017 the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Programming Language. @@ -51,7 +51,7 @@ #ifdef HAVE_DIRENT_H #include #else -#error Cannot compile the dirent extension on this system! +#error Cannot compile the readdir extension on this system! #endif #ifdef __MINGW32__ @@ -73,7 +73,7 @@ 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 const char *ext_version = "readdir extension: version 2.0"; static awk_bool_t init_readdir(void); static awk_bool_t (*init_func)(void) = init_readdir; @@ -142,6 +142,7 @@ ftype(struct dirent *entry, const char *dirname) } /* get_inode --- get the inode of a file */ + static long long get_inode(struct dirent *entry, const char *dirname) { @@ -204,7 +205,7 @@ dir_get_record(char **out, awk_input_buf_t *iobuf, int *errcode, return EOF; } - ino = get_inode (dirent, iobuf->name); + ino = get_inode(dirent, iobuf->name); #if __MINGW32__ len = sprintf(the_dir->buf, "%I64u", ino); -- cgit v1.2.3