Copyright (C) 2000-2012 |
GNU Info (gawk.info)Internal File OpsC 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. automatically generated by info2www version 1.2.2.9 |