www.delorie.com/gnu/docs/gawk/gawk_254.html   search  
 
Buy the book!


The GNU Awk User's Guide

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

C.3.2.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:(66)

 
#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] [ ? ]

  webmaster   donations   bookstore     delorie software   privacy  
  Copyright 2003   by The Free Software Foundation     Updated Jun 2003