| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] | 
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:(65)
#include "awk.h"
#include <sys/sysmacros.h>
/*  do_chdir --- provide dynamically loaded
                 chdir() builtin for gawk */
static NODE *
do_chdir(tree)
NODE *tree;
{
    NODE *newdir;
    int ret = -1;
    newdir = get_argument(tree, 0);
 | 
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 `NODE *' argument, usually called tree, that
represents the argument list to the function.  The newdir
variable represents the new directory to change to, retrieved
with get_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.
The result of force_string has to be freed with free_temp:
    if (newdir != NULL) {
        (void) force_string(newdir);
        ret = chdir(newdir->stptr);
        if (ret < 0)
            update_ERRNO();
        free_temp(newdir);
    }
 | 
Finally, the function returns the return value to the awk level,
using set_value. Then it must return a value from the call to
the new built-in (this value ignored by the interpreter):
    /* Set the return value */
    set_value(tmp_number((AWKNUM) ret));
    /* Just to make the interpreter happy */
    return tmp_number((AWKNUM) 0);
}
 | 
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(fmode)
unsigned long fmode;
{
    ...
}
 | 
Next comes the actual do_stat function itself.  First come the
variable declarations and argument checking:
/* do_stat --- provide a stat() function for gawk */
static NODE *
do_stat(tree)
NODE *tree;
{
    NODE *file, *array;
    struct stat sbuf;
    int ret;
    char *msg;
    NODE **aptr;
    char *pmode;    /* printable mode */
    char *type = "unknown";
    /* check arg count */
    if (tree->param_cnt != 2)
        fatal(
    "stat: called with %d arguments, should be 2",
            tree->param_cnt);
 | 
Then comes the actual work. First, we get the arguments.
Then, we always clear the array.  To get the file information,
we use lstat, in case the file is a symbolic link.
If there's an error, we set ERRNO and return:
    /*
     * directory is first arg,
     * array to hold results is second
     */
    file = get_argument(tree, 0);
    array = get_argument(tree, 1);
    /* 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();
        set_value(tmp_number((AWKNUM) ret));
        free_temp(file);
        return tmp_number((AWKNUM) 0);
    }
 | 
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_string("name", 4), FALSE);
    *aptr = dupnode(file);
    aptr = assoc_lookup(array, tmp_string("mode", 4), FALSE);
    *aptr = make_number((AWKNUM) sbuf.st_mode);
    aptr = assoc_lookup(array, tmp_string("pmode", 5), FALSE);
    pmode = format_mode(sbuf.st_mode);
    *aptr = make_string(pmode, strlen(pmode));
 | 
When done, we free the temporary value containing the file name, set the return value, and return:
    free_temp(file);
    /* Set the return value */
    set_value(tmp_number((AWKNUM) ret));
    /* Just to make the interpreter happy */
    return tmp_number((AWKNUM) 0);
}
 | 
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(tree, dl)
NODE *tree;
void *dl;
{
    make_builtin("chdir", do_chdir, 1);
    make_builtin("stat", do_stat, 2);
    return tmp_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] | [ ? ] |