[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
C.3.3.2 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:(83)
#include "awk.h" #include <sys/sysmacros.h> int plugin_is_GPL_compatible; /* do_chdir --- provide dynamically loaded chdir() builtin for gawk */ static NODE * do_chdir(int nargs) { 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(0, FALSE); |
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 ‘int’ argument, usually called nargs
, that
represents the number of defined arguments for the function. The newdir
variable represents the new directory to change to, retrieved
with get_scalar_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.
(void) force_string(newdir); ret = chdir(newdir->stptr); if (ret < 0) update_ERRNO(); |
Finally, the function returns the return value to the awk
level:
return make_number((AWKNUM) ret); } |
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(unsigned long fmode) { … } |
Next comes the do_stat()
function. It starts with
variable declarations and argument checking:
/* do_stat --- provide a stat() function for gawk */ static NODE * do_stat(int nargs) { NODE *file, *array, *tmp; 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, the function gets the arguments.
Then, it always clears the array.
The code use lstat()
(instead of stat()
)
to get the file information,
in case the file is a symbolic link.
If there’s an error, it sets ERRNO
and returns:
/* file is first arg, array to hold results is second */ file = get_scalar_argument(0, FALSE); array = get_array_argument(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(); return make_number((AWKNUM) ret); } |
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 = make_string("name", 4), FALSE); *aptr = dupnode(file); unref(tmp); aptr = assoc_lookup(array, tmp = make_string("mode", 4), FALSE); *aptr = make_number((AWKNUM) sbuf.st_mode); unref(tmp); aptr = assoc_lookup(array, tmp = make_string("pmode", 5), FALSE); pmode = format_mode(sbuf.st_mode); *aptr = make_string(pmode, strlen(pmode)); unref(tmp); |
When done, return the lstat()
return value:
return make_number((AWKNUM) ret); } |
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(NODE *tree, void *dl) { make_builtin("chdir", do_chdir, 1); make_builtin("stat", do_stat, 2); return make_number((AWKNUM) 0); } |
And that’s it! As an exercise, consider adding functions to
implement system calls such as chown()
, chmod()
,
and umask()
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |