DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH
 

(gawk.info.gz) Internal File Ops

Info Catalog (gawk.info.gz) Internal File Description (gawk.info.gz) Sample Library (gawk.info.gz) Using Internal File Ops
 
 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.
 
Info Catalog (gawk.info.gz) Internal File Description (gawk.info.gz) Sample Library (gawk.info.gz) Using Internal File Ops
automatically generated byinfo2html