vixie@wrl.dec.com (Paul Vixie) (05/04/90)
Submitted-by: vixie@wrl.dec.com (Paul Vixie) Posting-number: Volume 7, Issue 25 Archive-name: awl/part11 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 11 (of 17)." # Contents: sysrtns.c # Wrapped by vixie@jove.pa.dec.com on Mon Apr 30 01:25:25 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'sysrtns.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'sysrtns.c'\" else echo shar: Extracting \"'sysrtns.c'\" \(35683 characters\) sed "s/^X//" >'sysrtns.c' <<'END_OF_FILE' X#ifndef lint static char *rcsid = "$Header: /usr/src/local/awl/RCS/sysrtns.c,v 2.1 90/04/19 20:05:56 jkh Exp $"; X#endif X X/* X * X * Copyright 1989 X * Jordan K. Hubbard X * X * PCS Computer Systeme, GmbH. X * Munich, West Germany X * X * X * This file is part of AWL. X * X * AWL is free software; you can redistribute it and/or modify X * it under the terms of the GNU General Public License as published by X * the Free Software Foundation; either version 1, or (at your option) X * any later version. X * X * AWL is distributed in the hope that it will be useful, X * but WITHOUT ANY WARRANTY; without even the implied warranty of X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the X * GNU General Public License for more details. X * X * You should have received a copy of the GNU General Public License X * along with AWL; see the file COPYING. If not, write to X * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. X * X * X */ X X/* X * This file contains all the system (UNIX) specific built-ins and X * a few awl utility functions. X * X * Note that mathrtns.c also uses some UNIX dependant features X * to handle floating point traps. X * X * $Log: sysrtns.c,v $ X * Revision 2.1 90/04/19 20:05:56 jkh X * Alpha checkin. X * X * Revision 2.0 90/03/26 01:43:52 jkh X * pre-beta check-in X * X */ X X#include "AwlP.h" X#include "y.tab.h" X#include <dirent.h> X#include <grp.h> X#include <pwd.h> X X/* global signal table */ Import Symbol *_procSignalTable; X Local Value arg, arg2, arg3; Local int doit(), print_value(); Local void illfmt(); Local char *ctor(); Local Value get_value(); X X#ifndef MAXPATHLEN X#define MAXPATHLEN 1024 /* take a guess */ X#endif X X/********************************* X * AWL "internal" utilities * X * (i.e. not UNIX counterparts) * X *********************************/ X X/* X * _argc(): X * Returns number of args passed to function. X */ DEFUN(_argc) X{ X value_set(arg, DATA, INT, int, value_int(awl_stack(aw)[awl_fp(aw) - 1])); X return(arg); X} X X/* X * _argv(INT): X * Returns a specific arg number. This is VERY awl specific (I.E. if you X * change awl's basic frame layout, this will break). X */ DEFUN(_argv) X{ X arg = get_arg(aw, 1, INT, TRUE); X if (value_type(arg)) { X int old_nparms = value_int(awl_stack(aw)[awl_fp(aw) - 1]); X debug(aw, "_argv: fetching arg #%d from frame.", value_int(arg)); X if (value_int(arg) > old_nparms) { X exec_warn(aw, "_argv: Requested arg #%d > %d passed", X value_int(arg), old_nparms); X value_clear(arg); X } X else { X /* X * We can't simply use FRAME_OFFSET here because we're X * loading the value from the previous stack frame, not the X * current one. X */ X arg = do_load(aw, X awl_stack(aw)[value_int(awl_stack(aw)[awl_fp(aw)]) X - ((old_nparms X - value_int(arg)) X + FRAME_REG_SIZE)], X TRUE); X } X } X return(arg); X} X X/* X * assign(FDESC, NAME): X * Redirect stdin, stdout or stderr. X */ DEFUN(assign) X{ X arg = get_arg(aw, 1, ANY, FALSE); X if (is_filedesc_type(value_type(arg))) { X FILE *ifp = (value_type(arg) != FILEPDESC ? value_file(arg) X : proc_in(value_any(arg))), X *ofp = (value_type(arg) != FILEPDESC ? value_file(arg) X : proc_out(value_any(arg))); X X arg2 = get_arg(aw, 2, STRING, TRUE); X if (!stricomp(value_string(arg2), "stdin")) X awl_in(aw) = ifp; X else if (!stricomp(value_string(arg2), "stdout")) X awl_out(aw) = ofp; X else if (!stricomp(value_string(arg2), "stderr")) X awl_err(aw) = ofp; X else X exec_warn("assign: Expected stdin, stdout or stderr. Got: %s", X value_string(arg2)); X } X else { X exec_warn("assign: Expected type file descriptor, got '%s'", X type_name(value_type(arg))); X value_clear(arg); X } X return(arg); X} X X/* X * classid(name): X * Returns class id (as int) for name. X */ DEFUN(classid) X{ X String name; X X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X name = value_string(arg); X value_set(arg, DATA, INT, int, map_resword_to_token(name, T_CLASS)); X } X return(arg); X} X X/* X * classof(value): X * Returns class of value as an int. X */ DEFUN(classof) X{ X int tmp; X X arg = get_arg(aw, 1, ANY, FALSE); X tmp = value_class(arg); X value_set(arg, DATA, INT, int, tmp); X return(arg); X} X X/* X * get(type): X * Get formatted input of "type" from input. If "type" is ANY, try to X * intuit type. X */ DEFUN(get) X{ X arg = get_arg(aw, 1, INT, TRUE); X arg2 = get_value(aw, arg); X return(arg2); X} X X/* X * input(value, type): X * Prints "value" to stdout and waits for data of type "type" on stdin. X * Basically a convenience function for the often used print()/get() X * pair. X */ DEFUN(input) X{ X print_value(aw, get_arg(aw, 1, ANY, FALSE)); X return(get_value(aw, get_arg(aw, 2, INT, TRUE))); X} X X/* X * length(type): X * Returns the length of a string, list or file (coercing expression to X * a string if necessary). X */ DEFUN(length) X{ X arg = get_arg(aw, 1, ANY, FALSE); X if (value_type(arg) == STRING) X value_set(arg, DATA, INT, int, strlen(value_string(arg))); X else if (value_type(arg) == LIST) X value_set(arg, DATA, INT, int, list_len(value_list(arg))); X else if (is_filedesc_type(value_type(arg))) { X struct stat sb; X FILE *fp; X Import int fstat(); X if (value_type(arg) == FILEDESC) X fp = value_file(arg); X else X fp = (proc_in(value_any(arg)) ? proc_in(value_any(arg)) X : proc_out(value_any(arg))); X X fstat(fileno(fp), &sb); X value_set(arg, DATA, INT, int, sb.st_size); X } X else { X Value x; X X x = coerce(aw, arg, STRING); X value_set(arg, DATA, INT, int, strlen(value_string(x))); X } X return(arg); X} X X/* X * load(STRING): X * Load awl code from file STRING. Return 0 if successful, 1 if failure. X */ DEFUN(load) X{ X arg = get_arg(aw, 1, STRING, TRUE); X if (value_any(arg)) { X String file = value_string(arg); X X value_set(arg, DATA, INT, int, parseFile(aw, file)); X } X return(arg); X} X X/* X * print(n...n1): X * Print values from the stack. This is a good example of a routine X * handling a variable number of arguments. X */ DEFUN(print) X{ X int i, len = 0; X X for (i = 1; i <= awl_nparms(aw); i++) { X arg = get_arg(aw, i, ANY, FALSE); X len += print_value(aw, arg); X } X fflush(awl_out(aw)); X value_set(arg, DATA, INT, int, len); X return(arg); X} X X/* X * println(n..n1): X * same as print but with a newline automatically appended. X */ DEFUN(println) X{ X arg = awl_print(aw); X fputc('\n', awl_out(aw)); X ++value_int(arg); X return(arg); X} X X/* X * printname(INT): X * Returns printable version of type/class INT X */ DEFUN(printname) X{ X String result; X X arg = get_arg(aw, 1, INT, FALSE); X result = map_token_to_resword(value_int(arg), T_ALL); X if (result) X value_set(arg, DATA, STRING, aobj, new_aobj(XtNewString(result))); X else X value_set(arg, DATA, INT, int, 0); X return(arg); X} X X/* X * setbuf(FILE, STRING): X * Set the buffer for a file descriptor. X */ DEFUN(setbuf) X{ X arg = get_arg(aw, 1, ANY, FALSE); X if (value_type(arg) == FILEDESC || value_type(arg) == FILEPDESC) { X arg2 = get_arg(aw, 2, ANY, FALSE); X if (value_type(arg2) == STRING || value_type(arg2) == INT X || value_type(arg2) == ANY) { X Generic buf1 = (value_type(arg2) == STRING X ? (Generic)value_string(arg2) X : value_any(arg2)); X X if (value_type(arg) == FILEDESC) X setbuf(value_file(arg), buf1); X else { X if (proc_in(value_any(arg)) && proc_out(value_any(arg))) { X arg3 = get_arg(aw, 3, ANY, FALSE); X if (value_type(arg3) == STRING X || value_type(arg3) == INT X || value_type(arg3) == ANY) { X Generic buf2 = (value_type(arg3) == STRING X ? (Generic)value_string(arg3) X : value_any(arg3)); X setbuf(proc_in(value_any(arg)), buf1); X setbuf(proc_out(value_any(arg)), buf2); X } X else X exec_error(aw, "Need 2 buffers for this process descriptor"); X } X else if (proc_in(value_any(arg))) X setbuf(proc_in(value_any(arg)), buf1); X else if (proc_out(value_any(arg))) X setbuf(proc_out(value_any(arg)), buf1); X else X exec_error(aw, "Process has no open descriptors!"); X } X } X else X exec_error(aw, "Illegal buffer argument for setbuf"); X } X else X exec_error(aw, "Expected file descriptor, got '%s'", X type_name(value_type(arg))); X return(arg); X} X X/* X * symbol(STRING): X * Look for a symbol named STRING and return it as-is. X */ DEFUN(symbol) X{ X arg = get_arg(aw, 1, STRING, TRUE); X if (value_any(arg)) { X String s = value_string(arg); X value_set(arg, DATA, SYMBOL, symbol, symbol_find(aw, s)); X } X return(arg); X} X X/* X * typeid(name): X * Returns type id (as int) for name. X */ DEFUN(typeid) X{ X String name; X X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X name = value_string(arg); X value_set(arg, DATA, INT, int, map_resword_to_token(name, T_TYPE)); X } X return(arg); X} X X/* X * typeof(value): X * Returns type of value as an int. X */ DEFUN(typeof) X{ X int tmp; X X arg = get_arg(aw, 1, ANY, FALSE); X tmp = value_type(arg); X value_set(arg, DATA, INT, int, tmp); X return(arg); X} X X X/************************************ X * UNIX interface functions * X ************************************/ X X/* X * chdir(STRING): X * Do a chdir(STRING). X */ DEFUN(chdir) X{ X Import int chdir(); X int status = -1; X X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) X status = chdir(value_string(arg)); X value_set(arg, DATA, INT, int, status); X return(arg); X} X X/* X * chmod(STRING, INT): X * chmod() file STRING to mode INT. X */ DEFUN(chmod) X{ X int status = -1; X Import int chmod(); X X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X arg2 = get_arg(aw, 2, INT, TRUE); X if (value_type(arg2)) X status = chmod(value_string(arg), value_int(arg2)); X } X value_set(arg, DATA, INT, int, status); X return(arg); X} X X/* X * chown(STRING, INT1, INT2): X * chown() file STRING to user INT1 and group INT2. X */ DEFUN(chown) X{ X int status = -1; X Import int chown(), fchown(); X X arg = get_arg(aw, 1, ANY, FALSE); X if (value_type(arg) == STRING || value_type(arg) == FILEDESC) { X arg2 = get_arg(aw, 2, INT, TRUE); X if (value_type(arg2)) { X arg3 = get_arg(aw, 3, INT, TRUE); X if (value_type(arg3)) { X if (value_type(arg) == STRING) X status = chown(value_string(arg), X value_int(arg2), X value_int(arg3)); X else X status = fchown(fileno(value_file(arg)), X value_int(arg2), X value_int(arg3)); X } X } X } X else { X exec_warn(aw, "chown: Expected file name or descriptor, got '%s'", X type_name(value_type(arg))); X } X value_set(arg, DATA, INT, int, status); X return(arg); X} X X/* X * chroot(STRING): X * Change root directory to STRING. X */ DEFUN(chroot) X{ X int status = -1; X Import int chroot(); X X arg = get_arg(aw, 1, STRING, TRUE); X if (type_name(arg)) { X status = chroot(value_string(arg)); X } X value_set(arg, DATA, INT, int, status); X return(arg); X} X X/* X * close(FDESC): X * close() a file descriptor or process. X */ DEFUN(close) X{ X int status = EOF; X X arg = get_arg(aw, 1, ANY, FALSE); X if (value_type(arg) == FILEDESC) X status = fclose(value_file(arg)); X else if (value_type(arg) == FILEPDESC) X status = p_pclose(aw, value_any(arg)); X else X exec_warn("close: Expected file descriptor, got '%s'", X type_name(value_type(arg))); X value_set(arg, DATA, INT, int, status); X return(arg); X} X X/* X * exec(STRING, LIST): X * execvp() file STRING with arguments LIST. X */ DEFUN(exec) X{ X Import int execvp(); X X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X arg2 = get_arg(aw, 2, LIST, TRUE); X if (value_type(arg2)) { X execvp(value_string(arg), value_list(arg2)); X value_set(arg, DATA, INT, int, -1); /* we failed */ X } X } X return(arg); /* maybe */ X} X X/* X * exit(INT): X * exit() with return code (INT)expr. X */ DEFUN(exit) X{ X arg = get_arg(aw, 1, INT, FALSE); X exit(value_int(arg)); X return(arg); /* sure hope not! */ X} X X/* X * fork(): X * fork() a process. Wheee... This may get you into trouble X * if you don't handle your file descriptors properly. X */ DEFUN(fork) X{ X Import int fork(); X X value_set(arg, DATA, INT, int, fork()); X return(arg); X} X X/* X * free(value): X * Free's previously malloc'd value. X */ DEFUN(free) X{ X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X if (value_class(arg) != ALLOCATED) X exec_warn(aw, "attempt to free non-malloc'd variable"); X else { X if (--aobj_cnt(value_aobj(arg)) <= 0) { X XtFree(value_string(arg)); X XtFree(value_aobj(arg)); X value_clear(arg); X } X } X } X return(arg); X} X X/* X * fmt_time(fmt, time): X * Format time description according to fmt. X */ DEFUN(fmt_time) X{ X String res; X X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X arg2 = get_arg(aw, 2, ANY, FALSE); X if ((res = format_time(value_string(arg), value_any(arg2))) != NULL) X value_set(arg, DATA, STRING, aobj, new_aobj(res)); X else X value_clear(arg); X } X return(arg); X} X X/* X * getenv(STRING): X * Returns environment variable STRING. X */ DEFUN(getenv) X{ X String cp = NULL; X Import String getenv(); X X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X if ((cp = getenv(value_string(arg))) != NULL) X cp = XtNewString(cp); X } X if (cp) X value_set(arg, DATA, STRING, aobj, new_aobj(cp)); X else X value_clear(arg); X return(arg); X} X X/* X * getegid(): X * Return our effective GID. X */ DEFUN(getegid) X{ X Import int getegid(); X X value_set(arg, DATA, INT, int, getegid()); X return(arg); X} X X/* X * geteuid(): X * Return our effective UID. X */ DEFUN(geteuid) X{ X Import int geteuid(); X X value_set(arg, DATA, INT, int, geteuid()); X return(arg); X} X X/* X * getgid(): X * Return our GID. X */ DEFUN(getgid) X{ X Import int getgid(); X X value_set(arg, DATA, INT, int, getgid()); X return(arg); X} X X/* X * getpid() X * Return our PID. X */ DEFUN(getpid) X{ X Import int getpid(); X X value_set(arg, DATA, INT, int, getpid()); X return(arg); X} X X/* X * getuid(): X * Return our UID. X */ DEFUN(getuid) X{ X Import int getuid(); X X value_set(arg, DATA, INT, int, getuid()); X return(arg); X} X X/* X * getwd(): X * return the current working directory. X */ DEFUN(getwd) X{ X Import String getwd(); X char name[MAXPATHLEN + 1]; X String cp = NULL; X X if (getwd(name)) X cp = XtNewString(name); X if (cp) X value_set(arg, DATA, STRING, aobj, new_aobj(cp)); X else X value_clear(arg); X return(arg); X} X X/* X * group(ANY): X * Return the group name for group ID or group ID for group name. X */ DEFUN(group) X{ X Import struct group *getgrnam(), *getgrgid(); X struct group *id = NULL; X int typ; X X arg = get_arg(aw, 1, ANY, FALSE); X typ = value_type(arg); X X if (typ == STRING) X id = getgrnam(value_string(arg)); X else if (typ == INT) { X int x = value_int(arg); X X if (x < 0) X x = -x; X id = getgrgid(x); X } X if (id) { X if (typ == STRING) X value_set(arg, DATA, INT, int, id->gr_gid); X else if (typ == INT) { X if (value_int(arg) < 0) X value_set(arg, DATA, LIST, aobj, X new_aobj(list_dup(aw, id->gr_mem))); X else X value_set(arg, DATA, STRING, aobj, X new_aobj(XtNewString(id->gr_name))); X } X } X return(arg); X} X X/* X * kill(proc, sig): X * Try to send sig to pid/process file desc. X */ DEFUN(kill) X{ X Import int kill(); X X arg = get_arg(aw, 1, ANY, FALSE); X if (value_type(arg) == INT || value_type(arg) == FILEPDESC) { X arg2 = get_arg(aw, 2, INT, TRUE); X if (value_type(arg2)) { X int pid = (value_type(arg) == INT ? value_int(arg) X : proc_pid(value_any(arg))); X X value_set(arg, DATA, INT, int, kill(pid, value_int(arg2))); X } X } X else X exec_warn(aw, "kill: expected pid or process file desc. Got '%s'", X type_name(value_type(arg))); X return(arg); X} X X/* X * malloc(INT): X * Returns INT bytes of allocated space. X */ DEFUN(malloc) X{ X String cp; X int size; X X arg = get_arg(aw, 1, INT, TRUE); X if (value_type(arg)) { X size = value_int(arg); X if ((cp = XtMalloc(size)) != NULL) { X bzero(cp, size); X value_set(arg, ALLOCATED, STRING, aobj, new_aobj(cp)); X } X else X value_clear(arg); X } X return(arg); X} X X/* X * open(NAME, MODE): X * open() a file or process with a given mode. X */ DEFUN(open) X{ X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X arg2 = get_arg(aw, 2, STRING, TRUE); X if (value_type(arg2)) { X FILE *fp; X int type; X char mode[3]; X X strncpy(mode, value_string(arg2), 2); X mode[2] = '\0'; X if (mode[1] == 'p') { X mode[1] = '\0'; X value_set(arg, DATA, FILEPDESC, any, X p_popen(aw, value_string(arg), mode)); X } X else { X value_set(arg, DATA, FILEDESC, file, X fopen(value_string(arg), mode)); X } X } X } X return(arg); X} X X/* X * perror(STRING): X * Call perror(STRING). X */ DEFUN(perror) X{ X Import void perror(); X X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X perror(value_string(arg)); X } X return(arg); X} X X/* X * printf(format [,arg] ...) X * Do a printf() using our own sprintf() call. X */ DEFUN(printf) X{ X int cnt; X Import Value awl_sprintf(); X X arg = awl_sprintf(aw); X cnt = fprintf(awl_out(aw), value_string(arg)); X do_free(&arg); X value_set(arg, DATA, INT, int, cnt); X return(arg); X} X X/* X * read(dest, cnt): X * read cnt bytes from stdin, storing in dest. X */ DEFUN(read) X{ X int result; X X arg = get_arg(aw, 1, ANY, FALSE); X arg2 = get_arg(aw, 2, INT, TRUE); X if (value_type(arg) == STRING) X result = fread(value_string(arg), 1, value_int(arg2), awl_in(aw)); X else X result = fread(value_any(arg), 1, value_int(arg2), awl_in(aw)); X value_set(arg, DATA, INT, int, result); X return(arg); X} X X/* X * readdir(STRING): X * Slurp in directory STRING and return list of files therein. X * (note: This does *not* match the behaviour of its unix namesake, but X * I like this approach better). X */ X X#define LIST_HUNK 32 X DEFUN(readdir) X{ X DIR *frobozz; X struct dirent *dp; X int lsize, lmax; X String *ll; X X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X frobozz = opendir(value_string(arg)); X if (frobozz) { X lsize = lmax = 0; X while ((dp = readdir(frobozz)) != NULL) { X if (!lmax) { X lmax = LIST_HUNK; X ll = (String *)XtMalloc(lmax * sizeof(String *)); X } X else if (lsize == lmax) { X lmax += LIST_HUNK; X ll = (String *)XtRealloc(ll, lmax * sizeof(String *)); X } X ll[lsize++] = XtNewString(dp->d_name); X } X ll[lsize] = NULL; X closedir(frobozz); X value_set(arg, DATA, LIST, aobj, new_aobj(ll)); X } X else X value_clear(arg); X } X else X value_clear(arg); X return(arg); X} X X/* X * setgid(INT): X * Do a setgid() call. X */ DEFUN(setgid) X{ X Import int setgid(); X X arg = get_arg(aw, 1, INT, TRUE); X if (value_type(arg)) { X int gid = value_int(arg); X X value_set(arg, DATA, INT, int, setgid(gid)); X } X return(arg); X} X X/* X * setuid(INT): X * Do a setuid() call. X */ DEFUN(setuid) X{ X Import int setuid(); X X arg = get_arg(aw, 1, INT, TRUE); X if (value_type(arg)) { X int uid = value_int(arg); X X value_set(arg, DATA, INT, int, setuid(uid)); X } X return(arg); X} X X/* X * signal(INT, sym): X * Set signal routine for a given signal INT. X */ DEFUN(signal) X{ X Symbol oldval = (Symbol)NULL; X X arg = get_arg(aw, 1, INT, TRUE); X if (value_type(arg)) { X int signo = value_int(arg); X X if (signo < 0 || signo >= MAXSIG) X exec_warn(aw, "Illegal signal number %d", value_int(arg)); X else { X arg2 = get_arg(aw, 2, ANY, FALSE); X if (!_procSignalTable) { X _procSignalTable = X (Symbol *)XtMalloc(sizeof(Symbol) * MAXSIG); X bzero(_procSignalTable, sizeof(Symbol) * MAXSIG); X } X oldval = _procSignalTable[signo]; X /* X * Since signals are process global and there is no limit on X * the number of awl widgets a process may have, we warn the X * user of any conflicts between awl widget instances using X * the signal mechanism. X */ X if (oldval > (Symbol)MY_SIG_IGN && aw != symbol_root(oldval)) X exec_warn(aw, "Widget %x usurping handler for signal %d", X signo); X if (value_type(arg2) == INT) { X if (value_int(arg2) == MY_SIG_IGN) X signal(signo, SIG_IGN); X else if (value_int(arg2) == MY_SIG_DFL) X signal(signo, SIG_DFL); X else X exec_error(aw, "Illegal int passed as signal func"); X _procSignalTable[signo] = (Symbol)value_int(arg2); X } X else if (value_type(arg2) == SYMBOL) { X if (symbol_is_function(value_symbol(arg2))) { X _procSignalTable[signo] = value_symbol(arg2); X signal(signo, do_signal_user); X } X else X exec_error(aw, "Signal handler is not a function"); X } X else X exec_error(aw, "Signal handler must be a function symbol"); X } X } X value_set(arg, DATA, SYMBOL, symbol, oldval); X return(arg); X} X X/* X * sleep(INT): X * sleep() for INT seconds. X */ DEFUN(sleep) X{ X Import unsigned int sleep(); X X arg = get_arg(aw, 1, INT, TRUE); X if (value_type(arg)) X sleep(value_int(arg)); X return(arg); X} X X/* X * sprintf(var, format [,arg] ...) X * Do a sprintf to "var". X * X * This routine was taken almost verbatim from Chris Torek and Fred Blonder's X * Uncopyrighted "shell printf()" code. See the man page. X * X */ DEFUN(sprintf) X{ X register String cp, convp, targstr; X register int ch, ndyn, flags; X char cbuf[BUFSIZ]; /* separates each conversion */ X Local char hasmod[] = "has integer length modifier"; X Value target; X int tindex, aa, nargs, tsize; X X /* flags */ X#define LONG 1 X#define SHORT 2 X X nargs = awl_nparms(aw); X if (nargs < 1) { X value_set(arg, DATA, INT, int, 0); X return(arg); X } X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X /* try to guess how much space we'll need */ X tsize = strlen(value_string(arg)); X for (aa = 1; aa <= nargs; aa++) { X target = get_arg(aw, aa, ANY, FALSE); X if (value_type(target) == STRING && value_string(target)) X tsize += strlen(value_string(target)); X else /* guesstimate generously */ X tsize += 28; X } X targstr = XtMalloc(tsize); X bzero(targstr, tsize); X value_set(target, DATA, STRING, aobj, new_aobj(targstr)); X X aa = 1; X tindex = 0; X cp = value_string(arg); X X /* X * Scan format string for conversion specifications. X * (The labels would be loops, but then everything falls X * off the right.) X */ scan: X while ((ch = *(cp++)) != '%') { X if (ch == '\0') X return(target); X targstr[tindex++] = ch; X } X X ++aa; X ndyn = 0; X flags = 0; X convp = cbuf; X *(convp++) = ch; X X /* scan for conversion character */ cvt: X switch (ch = *(cp++)) { X X case '\0': /* unterminated conversion */ X targstr[tindex] = '\0'; X return(target); X X /* string or character format */ X case 'c': case 's': X if (flags) { X illfmt(aw, cbuf, convp, ch, hasmod); X targstr[tindex] = '\0'; X return(target); X } X if (!doit(aw, cbuf, convp, aa, nargs, targstr, &tindex, X ndyn, ch, ch)) { X targstr[tindex] = '\0'; X return(target); X } X goto scan; X X /* integer formats */ X case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': X if ((flags & (LONG|SHORT)) == (LONG|SHORT)) { X illfmt(aw, cbuf, convp, ch, "is both long and short"); X targstr[tindex] = '\0'; X return(target); X } X if (!doit(aw, cbuf, convp, aa, nargs, targstr, &tindex, X ndyn, ch, (flags & LONG ? 'l' : flags & SHORT ? 'h' : X 'i'))) { X targstr[tindex] = '\0'; X return(target); X } X goto scan; X X /* floating point formats */ X case 'e': case 'E': case 'f': case 'g': case 'G': X if (flags) { X illfmt(aw, cbuf, convp, ch, hasmod); X targstr[tindex] = '\0'; X return(target); X } X if (!doit(aw, cbuf, convp, aa, nargs, targstr, &tindex, X ndyn, ch, 'f')) { X targstr[tindex] = '\0'; X return(target); X } X goto scan; X X /* Roman (well, why not?) */ X case 'r': case 'R': X if (flags) { X illfmt(aw, cbuf, convp, ch, hasmod); X targstr[tindex] = '\0'; X return(target); X } X if (!doit(aw, cbuf, convp, aa, nargs, targstr, &tindex, X ndyn, 's', ch)) { X targstr[tindex] = '\0'; X return(target); X } X goto scan; X X case '%': /* boring */ X targstr[tindex++] = '%'; X goto scan; X X /* short integers */ X case 'h': X flags |= SHORT; X break; X X /* long integers */ X case 'l': X flags |= LONG; X break; X X /* field-width or precision specifier, or flag: keep scanning */ X case '.': case '#': case '-': case '+': case ' ': X case '0': case '1': case '2': case '3': case '4': X case '5': case '6': case '7': case '8': case '9': X break; X X /* dynamic field width or precision: count it */ X case '*': X ndyn++; X break; X X default: /* something we cannot handle */ X if (isascii(ch) && isprint(ch)) X cbuf[0] = ch, cbuf[1] = 0; X else X (void)sprintf(cbuf, "\\%03o", (unsigned char)ch); X exec_warn(aw, "vprintf: illegal conversion character `%s'", X cbuf); X targstr[tindex] = '\0'; X return(target); X /* NOTREACHED */ X } X X /* 2 leaves room for ultimate conversion char and for \0 */ X if (convp >= &cbuf[sizeof(cbuf) - 2]) { X exec_warn(aw, "vprintf: conversion string too long"); X targstr[tindex] = '\0'; X return(target); X } X *(convp++) = ch; X goto cvt; X } X return(target); X} X X/* X * stat(FMT, FILE): X * Stat a file name or file descriptor, returning stat information according X * to format string. X */ DEFUN(stat) X{ X struct stat sb; X Value ret; X Import int stat(), fstat(); X X value_clear(ret); X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X arg2 = get_arg(aw, 2, ANY, FALSE); X if (value_type(arg2) == STRING) { X if (!stat(value_string(arg2), &sb)) X value_set(ret, DATA, STRING, aobj, X new_aobj(stat_expand(aw, value_string(arg2), X value_string(arg), &sb))); X } X else if (is_filedesc_type(value_type(arg2))) { X FILE *fp; X char name[80]; X X fp = (value_type(arg2) == FILEDESC ? value_file(arg2) X : (proc_in(value_any(arg2)) ? proc_in(value_any(arg2)) X : proc_out(value_any(arg2)))); X X if (!fstat(fileno(fp), &sb)) { X sprintf(name, "<fdesc#%d>", value_file(arg2)); X value_set(ret, DATA, STRING, aobj, X new_aobj(stat_expand(aw, name, X value_string(arg), &sb))); X } X } X else X exec_warn(aw, "stat: Expected file name or descriptor, got %s", X type_name(value_type(arg2))); X } X return(ret); X} X X/* X * system(STRING): X * Do a system(STRING) call. X */ DEFUN(system) X{ X arg = get_arg(aw, 1, STRING, TRUE); X if (value_type(arg)) { X int status = system(value_string(arg)); X value_set(arg, DATA, INT, int, status); X } X return(arg); X} X X/* X * time(): X * Return the time in seconds since 00:00:00 GMT, January 1, 1970. X */ DEFUN(time) X{ X time_t ret; X Import time_t time(); X X ret = time(0); X value_set(arg, DATA, ANY, any, (Generic)ret); X return(arg); X} X X/* X * user(ANY): X * Return user name for user ID or user ID for user name. X */ DEFUN(user) X{ X int typ; X Import struct passwd *getpwnam(), *getpwuid(); X struct passwd *pw = NULL; X X arg = get_arg(aw, 1, ANY, FALSE); X typ = value_type(arg); X X if (typ == STRING) X pw = getpwnam(value_string(arg)); X else if (typ == INT) X pw = getpwuid(value_int(arg)); X if (pw) { X if (typ == STRING) X value_set(arg, DATA, INT, int, pw->pw_uid); X else if (typ == INT) X value_set(arg, DATA, STRING, aobj, X new_aobj(XtNewString(pw->pw_name))); X } X return(arg); X} X X/* X * write(dest, cnt): X * write cnt bytes from dest to stdout. X */ DEFUN(write) X{ X int result; X X arg = get_arg(aw, 1, ANY, FALSE); X arg2 = get_arg(aw, 2, INT, TRUE); X if (value_type(arg) == STRING) X result = fwrite(value_string(arg), 1, value_int(arg2), awl_out(aw)); X else X result = fwrite(value_any(arg), 1, value_int(arg2), awl_out(aw)); X value_set(arg, DATA, INT, int, result); X return(arg); X} X X X/****************************************** X * Various local work functions needed * X * by the systems interface * X ******************************************/ X X/* X * These next two functions are for sprintf/printf. X */ Local void illfmt(aw, cbuf, convp, ch, why) AwlWidget aw; char *cbuf, *convp; int ch; char *why; X{ X X *(convp++) = ch; X *convp = 0; X exec_warn(aw, "vprintf: format `%s' illegal: %s", cbuf, why); X} X X/* X * Emit a conversion. cch holds the printf format character for X * this conversion; cty holds a simplified version (all integer X * conversions, e.g., are represented as 'i'). X */ Local int doit(aw, cbuf, convp, argn, nargs, targ, tidx, ndyn, cch, cty) AwlWidget aw; char *cbuf, *convp; int argn, nargs; String targ; int *tidx, ndyn; int cch, cty; X{ X char *s; X union { /* four basic conversion types */ X int i; X long l; X FTYPE d; X String str; X } arg; X int a1, a2; /* dynamic width and/or precision */ X X /* finish off the conversion string */ X s = convp; X *(s++) = cch; X *s = 0; X s = cbuf; X X /* verify number of arguments */ X if (argn > nargs) { X exec_warn(aw, "vprintf: not enough args for format `%s'", s); X return(0); X } X X /* pick up dynamic specifiers */ X if (ndyn) { X a1 = value_int(get_arg(aw, argn, INT, FALSE)); X if (ndyn > 1) X a2 = value_int(get_arg(aw, argn, INT, FALSE)); X if (ndyn > 2) { X exec_warn(aw, "vprintf: too many `*'s in `%s'", s); X return(0); X } X } X X#define PRINTF(what) \ X if (ndyn == 0) \ X *tidx += sprintf(targ + *tidx, s, what); \ X else if (ndyn == 1) \ X *tidx += sprintf(targ + *tidx, s, a1, what); \ X else \ X *tidx += sprintf(targ + *tidx, s, a1, a2, what); X X /* emit the appropriate conversion */ X switch (cty) { X X /* string */ X case 's': X arg.str = value_string(get_arg(aw, argn, STRING, FALSE)); X if (arg.str) X backslash_eliminate(arg.str, NORMAL_ELIMINATE, 0); X else X arg.str = "(null)"; X goto string; X X /* roman (much like string) */ X case 'r': case 'R': X arg.str = ctor(value_int(get_arg(aw, argn, INT, FALSE)), cty == 'R'); X goto string; X X string: X PRINTF(arg.str); X break; X X /* floating point */ X case 'f': X arg.d = value_float(get_arg(aw, argn, FLOAT, FALSE)); X PRINTF(arg.d); X break; X X /* character */ X case 'c': X arg.i = (int)value_char(get_arg(aw, argn, CHAR, FALSE)); X goto integer; X X /* short integer */ X case 'h': X arg.i = (short)value_int(get_arg(aw, argn, INT, FALSE)); X goto integer; X X /* integer */ X case 'i': X arg.i = value_int(get_arg(aw, argn, INT, FALSE)); X goto integer; X X integer: X PRINTF(arg.i); X break; X X /* long integer */ X case 'l': X arg.l = (long)value_int(get_arg(aw, argn, INT, FALSE)); X PRINTF(arg.l); X break; X } X return (1); X} X/* X * Convert integer to Roman Numerals. (How have you survived without it?) X * [That's a very good question, Chris..] X */ Local char *ctor(x, caps) int x, caps; X{ X Local char buf[BUFSIZ]; X register char *outp = buf; X register unsigned n = x; X register int u, v; X register char *p, *q; X X if ((int)n < 0) { X *(outp++) = '-'; X n = -n; X } X p = caps ? "M\2D\5C\2L\5X\2V\5I" : "m\2d\5c\2l\5x\2v\5i"; X v = 1000; X if (n >= v * BUFSIZ / 2) /* conservative */ X return ("[abortive Roman numeral]"); X for (;;) { X while (n >= v) X *(outp++) = *p, n -= v; X if (n == 0) X break; X q = p + 1; X u = v / *q; X if (*q == 2) /* magic */ X u /= *(q += 2); X if (n + u >= v) { X *(outp++) = *(++q); X n += u; X } else { X p++; X v /= *(p++); X } X } X *outp = 0; X return (buf); X} X X/* For get() and input() */ Local Value get_value(aw, arg) AwlWidget aw; Value arg; X{ X register char ch; X String inbuf = NULL; X int i = 0, max = 0; X Value ret; X Import Boolean isValidDigit(); X#ifndef toupper X Import char toupper(); X#endif X X switch (value_int(arg)) { X case ANY: X while ((ch = fgetc(awl_in(aw))) != EOF && ch != awl_sep(aw)[0]) X append_string(&inbuf, &max, i++, ch); X append_string(&inbuf, &max, i, '\0'); X if (isValidDigit(aw, *inbuf, ANY)) { X if (index(inbuf, '.')) X value_set(ret, DATA, FLOAT, float, atof(inbuf)); X else X value_set(ret, DATA, INT, int, atonum(aw, inbuf, 0)); X XtFree(inbuf); X } X else { X if (i || ch == awl_sep(aw)[0]) X value_set(ret, DATA, STRING, aobj, new_aobj(inbuf)); X else { X value_set(ret, DATA, INT, int, 0); X XtFree(inbuf); X } X } X break; X X case INT: X while ((ch = fgetc(awl_in(aw))) != EOF) { X if (isspace(ch) && !i) X continue; X else if (isValidDigit(aw, ch, INT)) X append_string(&inbuf, &max, i++, ch); X else if (ch == '.') X exec_warn(aw, "decimal point ignored for INT get/input"); X else X break; X } X append_string(&inbuf, &max, i, '\0'); X value_set(ret, DATA, INT, int, atonum(aw, inbuf, 0)); X XtFree(inbuf); X break; X X case CHAR: X value_set(ret, DATA, CHAR, char, fgetc(awl_in(aw))); X break; X X case FLOAT: X while ((ch = fgetc(awl_in(aw))) != EOF) { X if (isspace(ch) && !i) X continue; X else if (isValidDigit(aw, ch, FLOAT)) X append_string(&inbuf, &max, i++, ch); X else X break; X } X append_string(&inbuf, &max, i, '\0'); X value_set(ret, DATA, FLOAT, float, atof(inbuf)); X XtFree(inbuf); X break; X X case STRING: X while ((ch = fgetc(awl_in(aw))) != EOF && ch != awl_sep(aw)[0]) X append_string(&inbuf, &max, i++, ch); X append_string(&inbuf, &max, i, '\0'); X if (i || ch == awl_sep(aw)[0]) X value_set(ret, DATA, STRING, aobj, new_aobj(inbuf)); X else { X value_set(ret, DATA, INT, int, 0); X XtFree(inbuf); X } X break; X X default: X exec_error(aw, "Illegal type '%s' for get/input", value_string(arg)); X break; X } X return(ret); X} X X/* For print()/println()/input() */ Local int print_value(aw, arg) AwlWidget aw; Value arg; X{ X String tmp; X int ret = 0; X X if (value_type(arg) == LIST) { X String *v = value_list(arg); X X if (!v) X fprintf(awl_out(aw), "(null list)"); X else while (*v) { X ret += (strlen(*v) + 1); X fprintf(awl_out(aw), "%s", *(v++)); X fputs(awl_sep(aw), awl_out(aw)); X } X } X else { X tmp = value_string_value(aw, arg); X ret += strlen(tmp); X fprintf(awl_out(aw), "%s", tmp); X } X return(ret); X} END_OF_FILE if test 35683 -ne `wc -c <'sysrtns.c'`; then echo shar: \"'sysrtns.c'\" unpacked with wrong size! fi # end of 'sysrtns.c' fi echo shar: End of archive 11 \(of 17\). cp /dev/null ark11isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 17 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 dan ---------------------------------------------------- O'Reilly && Associates argv@sun.com / argv@ora.com Opinions expressed reflect those of the author only.