GNU Info

Info Node: (gawk.info)Internal File Ops

(gawk.info)Internal File Ops


Next: Using Internal File Ops Prev: Internal File Description Up: Sample Library
Enter node , (file) or (file)node

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:(1)

     #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'.

   ---------- Footnotes ----------

   (1) This version is edited slightly for presentation.  The complete
version can be found in `extension/filefuncs.c' in the `gawk'
distribution.


automatically generated by info2www version 1.2.2.9