chdir and statHere 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;
if (do_lint && get_curfunc_arg_count() != 1)
lintwarn("chdir: called with incorrect number of arguments");
newdir = get_scalar_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:
(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;
NODE **aptr;
char *pmode; /* printable mode */
char *type = "unknown";
if (do_lint && get_curfunc_arg_count() > 2)
lintwarn("stat: called with too many arguments");
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_scalar_argument(tree, 0, FALSE);
array = get_array_argument(tree, 1, FALSE);
/* 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.
[1] This version is edited slightly for presentation. The complete version can be found in extension/filefuncs.c in the gawk distribution.