Node:Internal File Ops, Next:Using Internal File Ops, Previous:Internal File Description, Up:Sample Library
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
.
This version is edited
slightly for presentation. The complete version can be found in
extension/filefuncs.c
in the gawk
distribution.