manpagez: man pages & more
info gawk
Home | html | info | man
[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

C.3.3.2 C Code for chdir() and stat()

Here is the C code for these extensions. They were written for GNU/Linux. The code needs some more work for complete portability to other POSIX-compliant systems:(83)

 
#include "awk.h"

#include <sys/sysmacros.h>

int plugin_is_GPL_compatible;

/*  do_chdir --- provide dynamically loaded chdir() builtin for gawk */

static NODE *
do_chdir(int nargs)
{
    NODE *newdir;
    int ret = -1;

    if (do_lint && get_curfunc_arg_count() != 1)
        lintwarn("chdir: called with incorrect number of arguments");

    newdir = get_scalar_argument(0, FALSE);

The file includes the "awk.h" header file for definitions for the gawk internals. It includes <sys/sysmacros.h> for access to the major() and minor() macros.

By convention, for an awk function foo, the function that implements it is called ‘do_foo’. The function should take a ‘int’ argument, usually called nargs, that represents the number of defined arguments for the function. The newdir variable represents the new directory to change to, retrieved with get_scalar_argument(). Note that the first argument is numbered zero.

This code actually accomplishes the chdir(). It first forces the argument to be a string and passes the string value to the chdir() system call. If the chdir() fails, ERRNO is updated.

 
    (void) force_string(newdir);
    ret = chdir(newdir->stptr);
    if (ret < 0)
        update_ERRNO();

Finally, the function returns the return value to the awk level:

 
    return make_number((AWKNUM) ret);
}

The stat() built-in is more involved. First comes a function that turns a numeric mode into a printable representation (e.g., 644 becomes ‘-rw-r--r--’). This is omitted here for brevity:

 
/* format_mode --- turn a stat mode field into something readable */

static char *
format_mode(unsigned long fmode)
{
    …
}

Next comes the do_stat() function. It starts with variable declarations and argument checking:

 
/* do_stat --- provide a stat() function for gawk */

static NODE *
do_stat(int nargs)
{
    NODE *file, *array, *tmp;
    struct stat sbuf;
    int ret;
    NODE **aptr;
    char *pmode;    /* printable mode */
    char *type = "unknown";

    if (do_lint && get_curfunc_arg_count() > 2)
        lintwarn("stat: called with too many arguments");

Then comes the actual work. First, the function gets the arguments. Then, it always clears the array. The code use lstat() (instead of stat()) to get the file information, in case the file is a symbolic link. If there’s an error, it sets ERRNO and returns:

 
    /* file is first arg, array to hold results is second */
    file = get_scalar_argument(0, FALSE);
    array = get_array_argument(1, FALSE);

    /* empty out the array */
    assoc_clear(array);

    /* lstat the file, if error, set ERRNO and return */
    (void) force_string(file);
    ret = lstat(file->stptr, & sbuf);
    if (ret < 0) {
        update_ERRNO();
        return make_number((AWKNUM) ret);
    }

Now comes the tedious part: filling in the array. Only a few of the calls are shown here, since they all follow the same pattern:

 
    /* fill in the array */
    aptr = assoc_lookup(array, tmp = make_string("name", 4), FALSE);
    *aptr = dupnode(file);
    unref(tmp);

    aptr = assoc_lookup(array, tmp = make_string("mode", 4), FALSE);
    *aptr = make_number((AWKNUM) sbuf.st_mode);
    unref(tmp);

    aptr = assoc_lookup(array, tmp = make_string("pmode", 5), FALSE);
    pmode = format_mode(sbuf.st_mode);
    *aptr = make_string(pmode, strlen(pmode));
    unref(tmp);

When done, return the lstat() return value:

 
    return make_number((AWKNUM) ret);
}

Finally, it’s necessary to provide the “glue” that loads the new function(s) into gawk. By convention, each library has a routine named dlload() that does the job:

 
/* dlload --- load new builtins in this library */

NODE *
dlload(NODE *tree, void *dl)
{
    make_builtin("chdir", do_chdir, 1);
    make_builtin("stat", do_stat, 2);
    return make_number((AWKNUM) 0);
}

And that’s it! As an exercise, consider adding functions to implement system calls such as chown(), chmod(), and umask().


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]
© manpagez.com 2000-2024
Individual documents may contain additional copyright information.