Node:Internal File Ops, Next:Using Internal File Ops, Previous:Internal File Description, Up:Sample Library
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;
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.