aboutsummaryrefslogtreecommitdiffstats
path: root/extension/filefuncs.c
diff options
context:
space:
mode:
Diffstat (limited to 'extension/filefuncs.c')
-rw-r--r--extension/filefuncs.c221
1 files changed, 118 insertions, 103 deletions
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 <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#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, "")