[comp.sources.misc] v18i021: perl - The perl programming language, Part03/36

lwall@netlabs.com (Larry Wall) (04/15/91)

Submitted-by: Larry Wall <lwall@netlabs.com>
Posting-number: Volume 18, Issue 21
Archive-name: perl/part03

[There are 36 kits for perl version 4.0.]

#! /bin/sh

# Make a new directory for the perl sources, cd to it, and run kits 1
# thru 36 through sh.  When all 36 kits have been run, read README.

echo "This is perl 4.0 kit 3 (of 36).  If kit 3 is complete, the line"
echo '"'"End of kit 3 (of 36)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
mkdir  2>/dev/null
echo Extracting doio.c:AA
sed >doio.c:AA <<'!STUFFY!FUNK!' -e 's/X//'
X/* $RCSfile: doio.c,v $$Revision: 4.0.1.1 $$Date: 91/04/11 17:41:06 $
X *
X *    Copyright (c) 1989, Larry Wall
X *
X *    You may distribute under the terms of the GNU General Public License
X *    as specified in the README file that comes with the perl 3.0 kit.
X *
X * $Log:	doio.c,v $
X * Revision 4.0.1.1  91/04/11  17:41:06  lwall
X * patch1: hopefully straightened out some of the Xenix mess
X * 
X * Revision 4.0  91/03/20  01:07:06  lwall
X * 4.0 baseline.
X * 
X */
X
X#include "EXTERN.h"
X#include "perl.h"
X
X#ifdef HAS_SOCKET
X#include <sys/socket.h>
X#include <netdb.h>
X#endif
X
X#ifdef HAS_SELECT
X#ifdef I_SYS_SELECT
X#ifndef I_SYS_TIME
X#include <sys/select.h>
X#endif
X#endif
X#endif
X
X#if defined(HAS_MSG) || defined(HAS_SEM) || defined(HAS_SHM)
X#include <sys/ipc.h>
X#ifdef HAS_MSG
X#include <sys/msg.h>
X#endif
X#ifdef HAS_SEM
X#include <sys/sem.h>
X#endif
X#ifdef HAS_SHM
X#include <sys/shm.h>
X#endif
X#endif
X
X#ifdef I_PWD
X#include <pwd.h>
X#endif
X#ifdef I_GRP
X#include <grp.h>
X#endif
X#ifdef I_UTIME
X#include <utime.h>
X#endif
X#ifdef I_FCNTL
X#include <fcntl.h>
X#endif
X#ifdef I_SYS_FILE
X#include <sys/file.h>
X#endif
X
Xint laststatval = -1;
Xint laststype = O_STAT;
X
Xbool
Xdo_open(stab,name,len)
XSTAB *stab;
Xregister char *name;
Xint len;
X{
X    FILE *fp;
X    register STIO *stio = stab_io(stab);
X    char *myname = savestr(name);
X    int result;
X    int fd;
X    int writing = 0;
X    char mode[3];		/* stdio file mode ("r\0" or "r+\0") */
X
X    name = myname;
X    forkprocess = 1;		/* assume true if no fork */
X    while (len && isspace(name[len-1]))
X	name[--len] = '\0';
X    if (!stio)
X	stio = stab_io(stab) = stio_new();
X    else if (stio->ifp) {
X	fd = fileno(stio->ifp);
X	if (stio->type == '|')
X	    result = mypclose(stio->ifp);
X	else if (stio->type == '-')
X	    result = 0;
X	else if (stio->ifp != stio->ofp) {
X	    if (stio->ofp) {
X		result = fclose(stio->ofp);
X		fclose(stio->ifp);	/* clear stdio, fd already closed */
X	    }
X	    else
X		result = fclose(stio->ifp);
X	}
X	else
X	    result = fclose(stio->ifp);
X	if (result == EOF && fd > 2)
X	    fprintf(stderr,"Warning: unable to close filehandle %s properly.\n",
X	      stab_name(stab));
X	stio->ofp = stio->ifp = Nullfp;
X    }
X    if (*name == '+' && len > 1 && name[len-1] != '|') {	/* scary */
X	mode[1] = *name++;
X	mode[2] = '\0';
X	--len;
X	writing = 1;
X    }
X    else  {
X	mode[1] = '\0';
X    }
X    stio->type = *name;
X    if (*name == '|') {
X	for (name++; isspace(*name); name++) ;
X#ifdef TAINT
X	taintenv();
X	taintproper("Insecure dependency in piped open");
X#endif
X	fp = mypopen(name,"w");
X	writing = 1;
X    }
X    else if (*name == '>') {
X#ifdef TAINT
X	taintproper("Insecure dependency in open");
X#endif
X	name++;
X	if (*name == '>') {
X	    mode[0] = stio->type = 'a';
X	    name++;
X	}
X	else
X	    mode[0] = 'w';
X	writing = 1;
X	if (*name == '&') {
X	  duplicity:
X	    name++;
X	    while (isspace(*name))
X		name++;
X	    if (isdigit(*name))
X		fd = atoi(name);
X	    else {
X		stab = stabent(name,FALSE);
X		if (!stab || !stab_io(stab))
X		    return FALSE;
X		if (stab_io(stab) && stab_io(stab)->ifp) {
X		    fd = fileno(stab_io(stab)->ifp);
X		    if (stab_io(stab)->type == 's')
X			stio->type = 's';
X		}
X		else
X		    fd = -1;
X	    }
X	    if (!(fp = fdopen(fd = dup(fd),mode))) {
X		close(fd);
X	    }
X	}
X	else {
X	    while (isspace(*name))
X		name++;
X	    if (strEQ(name,"-")) {
X		fp = stdout;
X		stio->type = '-';
X	    }
X	    else  {
X		fp = fopen(name,mode);
X	    }
X	}
X    }
X    else {
X	if (*name == '<') {
X	    mode[0] = 'r';
X	    name++;
X	    while (isspace(*name))
X		name++;
X	    if (*name == '&')
X		goto duplicity;
X	    if (strEQ(name,"-")) {
X		fp = stdin;
X		stio->type = '-';
X	    }
X	    else
X		fp = fopen(name,mode);
X	}
X	else if (name[len-1] == '|') {
X#ifdef TAINT
X	    taintenv();
X	    taintproper("Insecure dependency in piped open");
X#endif
X	    name[--len] = '\0';
X	    while (len && isspace(name[len-1]))
X		name[--len] = '\0';
X	    for (; isspace(*name); name++) ;
X	    fp = mypopen(name,"r");
X	    stio->type = '|';
X	}
X	else {
X	    stio->type = '<';
X	    for (; isspace(*name); name++) ;
X	    if (strEQ(name,"-")) {
X		fp = stdin;
X		stio->type = '-';
X	    }
X	    else
X		fp = fopen(name,"r");
X	}
X    }
X    Safefree(myname);
X    if (!fp)
X	return FALSE;
X    if (stio->type &&
X      stio->type != '|' && stio->type != '-') {
X	if (fstat(fileno(fp),&statbuf) < 0) {
X	    (void)fclose(fp);
X	    return FALSE;
X	}
X	if (S_ISSOCK(statbuf.st_mode))
X	    stio->type = 's';	/* in case a socket was passed in to us */
X#ifdef S_IFMT
X	else if (!(statbuf.st_mode & S_IFMT))
X	    stio->type = 's';	/* some OS's return 0 on fstat()ed socket */
X#endif
X    }
X#if defined(HAS_FCNTL) && defined(F_SETFD)
X    fd = fileno(fp);
X    fcntl(fd,F_SETFD,fd >= 3);
X#endif
X    stio->ifp = fp;
X    if (writing) {
X	if (stio->type != 's')
X	    stio->ofp = fp;
X	else
X	    if (!(stio->ofp = fdopen(fileno(fp),"w"))) {
X		fclose(fp);
X		stio->ifp = Nullfp;
X	    }
X    }
X    return TRUE;
X}
X
XFILE *
Xnextargv(stab)
Xregister STAB *stab;
X{
X    register STR *str;
X    int filedev;
X    int fileino;
X    int fileuid;
X    int filegid;
X    static int filemode = 0;
X    static int lastfd;
X    static char *oldname;
X
X    if (!argvoutstab)
X	argvoutstab = stabent("ARGVOUT",TRUE);
X    if (filemode & (S_ISUID|S_ISGID)) {
X	fflush(stab_io(argvoutstab)->ifp);  /* chmod must follow last write */
X#ifdef HAS_FCHMOD
X	(void)fchmod(lastfd,filemode);
X#else
X	(void)chmod(oldname,filemode);
X#endif
X    }
X    filemode = 0;
X    while (alen(stab_xarray(stab)) >= 0) {
X	str = ashift(stab_xarray(stab));
X	str_sset(stab_val(stab),str);
X	STABSET(stab_val(stab));
X	oldname = str_get(stab_val(stab));
X	if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
X	    if (inplace) {
X#ifdef TAINT
X		taintproper("Insecure dependency in inplace open");
X#endif
X		if (strEQ(oldname,"-")) {
X		    str_free(str);
X		    defoutstab = stabent("STDOUT",TRUE);
X		    return stab_io(stab)->ifp;
X		}
X		filedev = statbuf.st_dev;
X		fileino = statbuf.st_ino;
X		filemode = statbuf.st_mode;
X		fileuid = statbuf.st_uid;
X		filegid = statbuf.st_gid;
X		if (!S_ISREG(filemode)) {
X		    warn("Can't do inplace edit: %s is not a regular file",
X		      oldname );
X		    do_close(stab,FALSE);
X		    str_free(str);
X		    continue;
X		}
X		if (*inplace) {
X#ifdef SUFFIX
X		    add_suffix(str,inplace);
X#else
X		    str_cat(str,inplace);
X#endif
X#ifndef FLEXFILENAMES
X		    if (stat(str->str_ptr,&statbuf) >= 0
X		      && statbuf.st_dev == filedev
X		      && statbuf.st_ino == fileino ) {
X			warn("Can't do inplace edit: %s > 14 characters",
X			  str->str_ptr );
X			do_close(stab,FALSE);
X			str_free(str);
X			continue;
X		    }
X#endif
X#ifdef HAS_RENAME
X#ifndef MSDOS
X		    if (rename(oldname,str->str_ptr) < 0) {
X			warn("Can't rename %s to %s: %s, skipping file",
X			  oldname, str->str_ptr, strerror(errno) );
X			do_close(stab,FALSE);
X			str_free(str);
X			continue;
X		    }
X#else
X		    do_close(stab,FALSE);
X		    (void)unlink(str->str_ptr);
X		    (void)rename(oldname,str->str_ptr);
X		    do_open(stab,str->str_ptr,stab_val(stab)->str_cur);
X#endif /* MSDOS */
X#else
X		    (void)UNLINK(str->str_ptr);
X		    if (link(oldname,str->str_ptr) < 0) {
X			warn("Can't rename %s to %s: %s, skipping file",
X			  oldname, str->str_ptr, strerror(errno) );
X			do_close(stab,FALSE);
X			str_free(str);
X			continue;
X		    }
X		    (void)UNLINK(oldname);
X#endif
X		}
X		else {
X#ifndef MSDOS
X		    if (UNLINK(oldname) < 0) {
X			warn("Can't rename %s to %s: %s, skipping file",
X			  oldname, str->str_ptr, strerror(errno) );
X			do_close(stab,FALSE);
X			str_free(str);
X			continue;
X		    }
X#else
X		    fatal("Can't do inplace edit without backup");
X#endif
X		}
X
X		str_nset(str,">",1);
X		str_cat(str,oldname);
X		errno = 0;		/* in case sprintf set errno */
X		if (!do_open(argvoutstab,str->str_ptr,str->str_cur)) {
X		    warn("Can't do inplace edit on %s: %s",
X		      oldname, strerror(errno) );
X		    do_close(stab,FALSE);
X		    str_free(str);
X		    continue;
X		}
X		defoutstab = argvoutstab;
X		lastfd = fileno(stab_io(argvoutstab)->ifp);
X		(void)fstat(lastfd,&statbuf);
X#ifdef HAS_FCHMOD
X		(void)fchmod(lastfd,filemode);
X#else
X		(void)chmod(oldname,filemode);
X#endif
X		if (fileuid != statbuf.st_uid || filegid != statbuf.st_gid) {
X#ifdef HAS_FCHOWN
X		    (void)fchown(lastfd,fileuid,filegid);
X#else
X#ifdef HAS_CHOWN
X		    (void)chown(oldname,fileuid,filegid);
X#endif
X#endif
X		}
X	    }
X	    str_free(str);
X	    return stab_io(stab)->ifp;
X	}
X	else
X	    fprintf(stderr,"Can't open %s: %s\n",str_get(str), strerror(errno));
X	str_free(str);
X    }
X    if (inplace) {
X	(void)do_close(argvoutstab,FALSE);
X	defoutstab = stabent("STDOUT",TRUE);
X    }
X    return Nullfp;
X}
X
X#ifdef HAS_PIPE
Xvoid
Xdo_pipe(str, rstab, wstab)
XSTR *str;
XSTAB *rstab;
XSTAB *wstab;
X{
X    register STIO *rstio;
X    register STIO *wstio;
X    int fd[2];
X
X    if (!rstab)
X	goto badexit;
X    if (!wstab)
X	goto badexit;
X
X    rstio = stab_io(rstab);
X    wstio = stab_io(wstab);
X
X    if (!rstio)
X	rstio = stab_io(rstab) = stio_new();
X    else if (rstio->ifp)
X	do_close(rstab,FALSE);
X    if (!wstio)
X	wstio = stab_io(wstab) = stio_new();
X    else if (wstio->ifp)
X	do_close(wstab,FALSE);
X
X    if (pipe(fd) < 0)
X	goto badexit;
X    rstio->ifp = fdopen(fd[0], "r");
X    wstio->ofp = fdopen(fd[1], "w");
X    wstio->ifp = wstio->ofp;
X    rstio->type = '<';
X    wstio->type = '>';
X    if (!rstio->ifp || !wstio->ofp) {
X	if (rstio->ifp) fclose(rstio->ifp);
X	else close(fd[0]);
X	if (wstio->ofp) fclose(wstio->ofp);
X	else close(fd[1]);
X	goto badexit;
X    }
X
X    str_sset(str,&str_yes);
X    return;
X
Xbadexit:
X    str_sset(str,&str_undef);
X    return;
X}
X#endif
X
Xbool
Xdo_close(stab,explicit)
XSTAB *stab;
Xbool explicit;
X{
X    bool retval = FALSE;
X    register STIO *stio;
X    int status;
X
X    if (!stab)
X	stab = argvstab;
X    if (!stab)
X	return FALSE;
X    stio = stab_io(stab);
X    if (!stio) {		/* never opened */
X	if (dowarn && explicit)
X	    warn("Close on unopened file <%s>",stab_name(stab));
X	return FALSE;
X    }
X    if (stio->ifp) {
X	if (stio->type == '|') {
X	    status = mypclose(stio->ifp);
X	    retval = (status == 0);
X	    statusvalue = (unsigned short)status & 0xffff;
X	}
X	else if (stio->type == '-')
X	    retval = TRUE;
X	else {
X	    if (stio->ofp && stio->ofp != stio->ifp) {		/* a socket */
X		retval = (fclose(stio->ofp) != EOF);
X		fclose(stio->ifp);	/* clear stdio, fd already closed */
X	    }
X	    else
X		retval = (fclose(stio->ifp) != EOF);
X	}
X	stio->ofp = stio->ifp = Nullfp;
X    }
X    if (explicit)
X	stio->lines = 0;
X    stio->type = ' ';
X    return retval;
X}
X
Xbool
Xdo_eof(stab)
XSTAB *stab;
X{
X    register STIO *stio;
X    int ch;
X
X    if (!stab) {			/* eof() */
X	if (argvstab)
X	    stio = stab_io(argvstab);
X	else
X	    return TRUE;
X    }
X    else
X	stio = stab_io(stab);
X
X    if (!stio)
X	return TRUE;
X
X    while (stio->ifp) {
X
X#ifdef STDSTDIO			/* (the code works without this) */
X	if (stio->ifp->_cnt > 0)	/* cheat a little, since */
X	    return FALSE;		/* this is the most usual case */
X#endif
X
X	ch = getc(stio->ifp);
X	if (ch != EOF) {
X	    (void)ungetc(ch, stio->ifp);
X	    return FALSE;
X	}
X#ifdef STDSTDIO
X	if (stio->ifp->_cnt < -1)
X	    stio->ifp->_cnt = -1;
X#endif
X	if (!stab) {			/* not necessarily a real EOF yet? */
X	    if (!nextargv(argvstab))	/* get another fp handy */
X		return TRUE;
X	}
X	else
X	    return TRUE;		/* normal fp, definitely end of file */
X    }
X    return TRUE;
X}
X
Xlong
Xdo_tell(stab)
XSTAB *stab;
X{
X    register STIO *stio;
X
X    if (!stab)
X	goto phooey;
X
X    stio = stab_io(stab);
X    if (!stio || !stio->ifp)
X	goto phooey;
X
X    if (feof(stio->ifp))
X	(void)fseek (stio->ifp, 0L, 2);		/* ultrix 1.2 workaround */
X
X    return ftell(stio->ifp);
X
Xphooey:
X    if (dowarn)
X	warn("tell() on unopened file");
X    return -1L;
X}
X
Xbool
Xdo_seek(stab, pos, whence)
XSTAB *stab;
Xlong pos;
Xint whence;
X{
X    register STIO *stio;
X
X    if (!stab)
X	goto nuts;
X
X    stio = stab_io(stab);
X    if (!stio || !stio->ifp)
X	goto nuts;
X
X    if (feof(stio->ifp))
X	(void)fseek (stio->ifp, 0L, 2);		/* ultrix 1.2 workaround */
X
X    return fseek(stio->ifp, pos, whence) >= 0;
X
Xnuts:
X    if (dowarn)
X	warn("seek() on unopened file");
X    return FALSE;
X}
X
Xint
Xdo_ctl(optype,stab,func,argstr)
Xint optype;
XSTAB *stab;
Xint func;
XSTR *argstr;
X{
X    register STIO *stio;
X    register char *s;
X    int retval;
X
X    if (!stab || !argstr)
X	return -1;
X    stio = stab_io(stab);
X    if (!stio)
X	return -1;
X
X    if (argstr->str_pok || !argstr->str_nok) {
X	if (!argstr->str_pok)
X	    s = str_get(argstr);
X
X#ifdef IOCPARM_MASK
X#ifndef IOCPARM_LEN
X#define IOCPARM_LEN(x)  (((x) >> 16) & IOCPARM_MASK)
X#endif
X#endif
X#ifdef IOCPARM_LEN
X	retval = IOCPARM_LEN(func);	/* on BSDish systes we're safe */
X#else
X	retval = 256;			/* otherwise guess at what's safe */
X#endif
X	if (argstr->str_cur < retval) {
X	    Str_Grow(argstr,retval+1);
X	    argstr->str_cur = retval;
X	}
X
X	s = argstr->str_ptr;
X	s[argstr->str_cur] = 17;	/* a little sanity check here */
X    }
X    else {
X	retval = (int)str_gnum(argstr);
X#ifdef MSDOS
X	s = (char*)(long)retval;		/* ouch */
X#else
X	s = (char*)retval;		/* ouch */
X#endif
X    }
X
X#ifndef lint
X    if (optype == O_IOCTL)
X	retval = ioctl(fileno(stio->ifp), func, s);
X    else
X#ifdef MSDOS
X	fatal("fcntl is not implemented");
X#else
X#ifdef HAS_FCNTL
X	retval = fcntl(fileno(stio->ifp), func, s);
X#else
X	fatal("fcntl is not implemented");
X#endif
X#endif
X#else /* lint */
X    retval = 0;
X#endif /* lint */
X
X    if (argstr->str_pok) {
X	if (s[argstr->str_cur] != 17)
X	    fatal("Return value overflowed string");
X	s[argstr->str_cur] = 0;		/* put our null back */
X    }
X    return retval;
X}
X
Xint
Xdo_stat(str,arg,gimme,arglast)
XSTR *str;
Xregister ARG *arg;
Xint gimme;
Xint *arglast;
X{
X    register ARRAY *ary = stack;
X    register int sp = arglast[0] + 1;
X    int max = 13;
X
X    if ((arg[1].arg_type & A_MASK) == A_WORD) {
X	tmpstab = arg[1].arg_ptr.arg_stab;
X	if (tmpstab != defstab) {
X	    laststype = O_STAT;
X	    statstab = tmpstab;
X	    str_set(statname,"");
X	    if (!stab_io(tmpstab) || !stab_io(tmpstab)->ifp ||
X	      fstat(fileno(stab_io(tmpstab)->ifp),&statcache) < 0) {
X		max = 0;
X		laststatval = -1;
X	    }
X	}
X	else if (laststatval < 0)
X	    max = 0;
X    }
X    else {
X	str_set(statname,str_get(ary->ary_array[sp]));
X	statstab = Nullstab;
X#ifdef HAS_LSTAT
X	laststype = arg->arg_type;
X	if (arg->arg_type == O_LSTAT)
X	    laststatval = lstat(str_get(statname),&statcache);
X	else
X#endif
X	    laststatval = stat(str_get(statname),&statcache);
X	if (laststatval < 0)
X	    max = 0;
X    }
X
X    if (gimme != G_ARRAY) {
X	if (max)
X	    str_sset(str,&str_yes);
X	else
X	    str_sset(str,&str_undef);
X	STABSET(str);
X	ary->ary_array[sp] = str;
X	return sp;
X    }
X    sp--;
X    if (max) {
X#ifndef lint
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_dev)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_ino)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_mode)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_nlink)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_uid)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_gid)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_rdev)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_size)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_atime)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_mtime)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_ctime)));
X#ifdef STATBLOCKS
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_blksize)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_nmake((double)statcache.st_blocks)));
X#else
X	(void)astore(ary,++sp,
X	  str_2mortal(str_make("",0)));
X	(void)astore(ary,++sp,
X	  str_2mortal(str_make("",0)));
X#endif
X#else /* lint */
X	(void)astore(ary,++sp,str_nmake(0.0));
X#endif /* lint */
X    }
X    return sp;
X}
X
X#if !defined(HAS_TRUNCATE) && !defined(HAS_CHSIZE) && defined(F_FREESP)
X	/* code courtesy of William Kucharski */
X#define HAS_CHSIZE
X
Xint chsize(fd, length)
Xint fd;			/* file descriptor */
Xoff_t length;		/* length to set file to */
X{
X    extern long lseek();
X    struct flock fl;
X    struct stat filebuf;
X
X    if (fstat(fd, &filebuf) < 0)
X	return -1;
X
X    if (filebuf.st_size < length) {
X
X	/* extend file length */
X
X	if ((lseek(fd, (length - 1), 0)) < 0)
X	    return -1;
X
X	/* write a "0" byte */
X
X	if ((write(fd, "", 1)) != 1)
X	    return -1;
X    }
X    else {
X	/* truncate length */
X
X	fl.l_whence = 0;
X	fl.l_len = 0;
X	fl.l_start = length;
X	fl.l_type = F_WRLCK;    /* write lock on file space */
X
X	/*
X	* This relies on the UNDOCUMENTED F_FREESP argument to
X	* fcntl(2), which truncates the file so that it ends at the
X	* position indicated by fl.l_start.
X	*
X	* Will minor miracles never cease?
X	*/
X
X	if (fcntl(fd, F_FREESP, &fl) < 0)
X	    return -1;
X
X    }
X
X    return 0;
X}
X#endif /* F_FREESP */
X
Xint
Xdo_truncate(str,arg,gimme,arglast)
XSTR *str;
Xregister ARG *arg;
Xint gimme;
Xint *arglast;
X{
X    register ARRAY *ary = stack;
X    register int sp = arglast[0] + 1;
X    off_t len = (off_t)str_gnum(ary->ary_array[sp+1]);
X    int result = 1;
X    STAB *tmpstab;
X
X#if defined(HAS_TRUNCATE) || defined(HAS_CHSIZE)
X#ifdef HAS_TRUNCATE
X    if ((arg[1].arg_type & A_MASK) == A_WORD) {
X	tmpstab = arg[1].arg_ptr.arg_stab;
X	if (!stab_io(tmpstab) ||
X	  ftruncate(fileno(stab_io(tmpstab)->ifp), len) < 0)
X	    result = 0;
X    }
X    else if (truncate(str_get(ary->ary_array[sp]), len) < 0)
X	result = 0;
X#else
X    if ((arg[1].arg_type & A_MASK) == A_WORD) {
X	tmpstab = arg[1].arg_ptr.arg_stab;
X	if (!stab_io(tmpstab) ||
X	  chsize(fileno(stab_io(tmpstab)->ifp), len) < 0)
X	    result = 0;
X    }
X    else {
X	int tmpfd;
X
X	if ((tmpfd = open(str_get(ary->ary_array[sp]), 0)) < 0)
X	    result = 0;
X	else {
X	    if (chsize(tmpfd, len) < 0)
X		result = 0;
X	    close(tmpfd);
X	}
X    }
X#endif
X
X    if (result)
X	str_sset(str,&str_yes);
X    else
X	str_sset(str,&str_undef);
X    STABSET(str);
X    ary->ary_array[sp] = str;
X    return sp;
X#else
X    fatal("truncate not implemented");
X#endif
X}
X
Xint
Xlooks_like_number(str)
XSTR *str;
X{
X    register char *s;
X    register char *send;
X
X    if (!str->str_pok)
X	return TRUE;
X    s = str->str_ptr; 
X    send = s + str->str_cur;
X    while (isspace(*s))
X	s++;
X    if (s >= send)
X	return FALSE;
X    if (*s == '+' || *s == '-')
X	s++;
X    while (isdigit(*s))
X	s++;
X    if (s == send)
X	return TRUE;
X    if (*s == '.') 
X	s++;
X    else if (s == str->str_ptr)
X	return FALSE;
X    while (isdigit(*s))
X	s++;
X    if (s == send)
X	return TRUE;
X    if (*s == 'e' || *s == 'E') {
X	s++;
X	if (*s == '+' || *s == '-')
X	    s++;
X	while (isdigit(*s))
X	    s++;
X    }
X    while (isspace(*s))
X	s++;
X    if (s >= send)
X	return TRUE;
X    return FALSE;
X}
X
Xbool
Xdo_print(str,fp)
Xregister STR *str;
XFILE *fp;
X{
X    register char *tmps;
X
X    if (!fp) {
X	if (dowarn)
X	    warn("print to unopened file");
X	return FALSE;
X    }
X    if (!str)
X	return TRUE;
X    if (ofmt &&
X      ((str->str_nok && str->str_u.str_nval != 0.0)
X       || (looks_like_number(str) && str_gnum(str) != 0.0) ) ) {
X	fprintf(fp, ofmt, str->str_u.str_nval);
X	return !ferror(fp);
X    }
X    else {
X	tmps = str_get(str);
X	if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'B' && tmps[3] == '\0'
X	  && str->str_cur == sizeof(STBP) && strlen(tmps) < str->str_cur) {
X	    STR *tmpstr = str_mortal(&str_undef);
X	    stab_fullname(tmpstr,((STAB*)str));/* a stab value, be nice */
X	    str = tmpstr;
X	    tmps = str->str_ptr;
X	    putc('*',fp);
X	}
X	if (str->str_cur && (fwrite(tmps,1,str->str_cur,fp) == 0 || ferror(fp)))
X	    return FALSE;
X    }
X    return TRUE;
X}
X
Xbool
Xdo_aprint(arg,fp,arglast)
Xregister ARG *arg;
Xregister FILE *fp;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[1];
X    register int retval;
X    register int items = arglast[2] - sp;
X
X    if (!fp) {
X	if (dowarn)
X	    warn("print to unopened file");
X	return FALSE;
X    }
X    st += ++sp;
X    if (arg->arg_type == O_PRTF) {
X	do_sprintf(arg->arg_ptr.arg_str,items,st);
X	retval = do_print(arg->arg_ptr.arg_str,fp);
X    }
X    else {
X	retval = (items <= 0);
X	for (; items > 0; items--,st++) {
X	    if (retval && ofslen) {
X		if (fwrite(ofs, 1, ofslen, fp) == 0 || ferror(fp)) {
X		    retval = FALSE;
X		    break;
X		}
X	    }
X	    if (!(retval = do_print(*st, fp)))
X		break;
X	}
X	if (retval && orslen)
X	    if (fwrite(ors, 1, orslen, fp) == 0 || ferror(fp))
X		retval = FALSE;
X    }
X    return retval;
X}
X
Xint
Xmystat(arg,str)
XARG *arg;
XSTR *str;
X{
X    STIO *stio;
X
X    laststype = O_STAT;
X    if (arg[1].arg_type & A_DONT) {
X	stio = stab_io(arg[1].arg_ptr.arg_stab);
X	if (stio && stio->ifp) {
X	    statstab = arg[1].arg_ptr.arg_stab;
X	    str_set(statname,"");
X	    return (laststatval = fstat(fileno(stio->ifp), &statcache));
X	}
X	else {
X	    if (arg[1].arg_ptr.arg_stab == defstab)
X		return laststatval;
X	    if (dowarn)
X		warn("Stat on unopened file <%s>",
X		  stab_name(arg[1].arg_ptr.arg_stab));
X	    statstab = Nullstab;
X	    str_set(statname,"");
X	    return (laststatval = -1);
X	}
X    }
X    else {
X	statstab = Nullstab;
X	str_set(statname,str_get(str));
X	return (laststatval = stat(str_get(str),&statcache));
X    }
X}
X
Xint
Xmylstat(arg,str)
XARG *arg;
XSTR *str;
X{
X    if (arg[1].arg_type & A_DONT) {
X	if (arg[1].arg_ptr.arg_stab == defstab) {
X	    if (laststype != O_LSTAT)
X		fatal("The stat preceding -l _ wasn't an lstat");
X	    return laststatval;
X	}
X	fatal("You can't use -l on a filehandle");
X    }
X
X    laststype = O_LSTAT;
X    statstab = Nullstab;
X    str_set(statname,str_get(str));
X#ifdef HAS_LSTAT
X    return (laststatval = lstat(str_get(str),&statcache));
X#else
X    return (laststatval = stat(str_get(str),&statcache));
X#endif
X}
X
XSTR *
Xdo_fttext(arg,str)
Xregister ARG *arg;
XSTR *str;
X{
X    int i;
X    int len;
X    int odd = 0;
X    STDCHAR tbuf[512];
X    register STDCHAR *s;
X    register STIO *stio;
X
X    if (arg[1].arg_type & A_DONT) {
X	if (arg[1].arg_ptr.arg_stab == defstab) {
X	    if (statstab)
X		stio = stab_io(statstab);
X	    else {
X		str = statname;
X		goto really_filename;
X	    }
X	}
X	else {
X	    statstab = arg[1].arg_ptr.arg_stab;
X	    str_set(statname,"");
X	    stio = stab_io(statstab);
X	}
X	if (stio && stio->ifp) {
X#ifdef STDSTDIO
X	    fstat(fileno(stio->ifp),&statcache);
X	    if (stio->ifp->_cnt <= 0) {
X		i = getc(stio->ifp);
X		if (i != EOF)
X		    (void)ungetc(i,stio->ifp);
X	    }
X	    if (stio->ifp->_cnt <= 0)	/* null file is anything */
X		return &str_yes;
X	    len = stio->ifp->_cnt + (stio->ifp->_ptr - stio->ifp->_base);
X	    s = stio->ifp->_base;
X#else
X	    fatal("-T and -B not implemented on filehandles\n");
X#endif
X	}
X	else {
X	    if (dowarn)
X		warn("Test on unopened file <%s>",
X		  stab_name(arg[1].arg_ptr.arg_stab));
X	    return &str_undef;
X	}
X    }
X    else {
X	statstab = Nullstab;
X	str_set(statname,str_get(str));
X      really_filename:
X	i = open(str_get(str),0);
X	if (i < 0)
X	    return &str_undef;
X	fstat(i,&statcache);
X	len = read(i,tbuf,512);
X	(void)close(i);
X	if (len <= 0)		/* null file is anything */
X	    return &str_yes;
X	s = tbuf;
X    }
X
X    /* now scan s to look for textiness */
X
X    for (i = 0; i < len; i++,s++) {
X	if (!*s) {			/* null never allowed in text */
X	    odd += len;
X	    break;
X	}
X	else if (*s & 128)
X	    odd++;
X	else if (*s < 32 &&
X	  *s != '\n' && *s != '\r' && *s != '\b' &&
X	  *s != '\t' && *s != '\f' && *s != 27)
X	    odd++;
X    }
X
X    if ((odd * 10 > len) == (arg->arg_type == O_FTTEXT)) /* allow 10% odd */
X	return &str_no;
X    else
X	return &str_yes;
X}
X
Xbool
Xdo_aexec(really,arglast)
XSTR *really;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[1];
X    register int items = arglast[2] - sp;
X    register char **a;
X    char **argv;
X    char *tmps;
X
X    if (items) {
X	New(401,argv, items+1, char*);
X	a = argv;
X	for (st += ++sp; items > 0; items--,st++) {
X	    if (*st)
X		*a++ = str_get(*st);
X	    else
X		*a++ = "";
X	}
X	*a = Nullch;
X#ifdef TAINT
X	if (*argv[0] != '/')	/* will execvp use PATH? */
X	    taintenv();		/* testing IFS here is overkill, probably */
X#endif
X	if (really && *(tmps = str_get(really)))
X	    execvp(tmps,argv);
X	else
X	    execvp(argv[0],argv);
X	Safefree(argv);
X    }
X    return FALSE;
X}
X
Xstatic char **Argv = Null(char **);
Xstatic char *Cmd = Nullch;
X
Xvoid
Xdo_execfree()
X{
X    if (Argv) {
X	Safefree(Argv);
X	Argv = Null(char **);
X    }
X    if (Cmd) {
X	Safefree(Cmd);
X	Cmd = Nullch;
X    }
X}
X
Xbool
Xdo_exec(cmd)
Xchar *cmd;
X{
X    register char **a;
X    register char *s;
X    char flags[10];
X
X#ifdef TAINT
X    taintenv();
X    taintproper("Insecure dependency in exec");
X#endif
X
X    /* save an extra exec if possible */
X
X#ifdef CSH
X    if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
X	strcpy(flags,"-c");
X	s = cmd+cshlen+3;
X	if (*s == 'f') {
X	    s++;
X	    strcat(flags,"f");
X	}
X	if (*s == ' ')
X	    s++;
X	if (*s++ == '\'') {
X	    char *ncmd = s;
X
X	    while (*s)
X		s++;
X	    if (s[-1] == '\n')
X		*--s = '\0';
X	    if (s[-1] == '\'') {
X		*--s = '\0';
X		execl(cshname,"csh", flags,ncmd,(char*)0);
X		*s = '\'';
X		return FALSE;
X	    }
X	}
X    }
X#endif /* CSH */
X
X    /* see if there are shell metacharacters in it */
X
X    for (s = cmd; *s && isalpha(*s); s++) ;	/* catch VAR=val gizmo */
X    if (*s == '=')
X	goto doshell;
X    for (s = cmd; *s; s++) {
X	if (*s != ' ' && !isalpha(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
X	    if (*s == '\n' && !s[1]) {
X		*s = '\0';
X		break;
X	    }
X	  doshell:
X	    execl("/bin/sh","sh","-c",cmd,(char*)0);
X	    return FALSE;
X	}
X    }
X    New(402,Argv, (s - cmd) / 2 + 2, char*);
X    Cmd = nsavestr(cmd, s-cmd);
X    a = Argv;
X    for (s = Cmd; *s;) {
X	while (*s && isspace(*s)) s++;
X	if (*s)
X	    *(a++) = s;
X	while (*s && !isspace(*s)) s++;
X	if (*s)
X	    *s++ = '\0';
X    }
X    *a = Nullch;
X    if (Argv[0]) {
X	execvp(Argv[0],Argv);
X	if (errno == ENOEXEC) {		/* for system V NIH syndrome */
X	    do_execfree();
X	    goto doshell;
X	}
X    }
X    do_execfree();
X    return FALSE;
X}
X
X#ifdef HAS_SOCKET
Xint
Xdo_socket(stab, arglast)
XSTAB *stab;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[1];
X    register STIO *stio;
X    int domain, type, protocol, fd;
X
X    if (!stab)
X	return FALSE;
X
X    stio = stab_io(stab);
X    if (!stio)
X	stio = stab_io(stab) = stio_new();
X    else if (stio->ifp)
X	do_close(stab,FALSE);
X
X    domain = (int)str_gnum(st[++sp]);
X    type = (int)str_gnum(st[++sp]);
X    protocol = (int)str_gnum(st[++sp]);
X#ifdef TAINT
X    taintproper("Insecure dependency in socket");
X#endif
X    fd = socket(domain,type,protocol);
X    if (fd < 0)
X	return FALSE;
X    stio->ifp = fdopen(fd, "r");	/* stdio gets confused about sockets */
X    stio->ofp = fdopen(fd, "w");
X    stio->type = 's';
X    if (!stio->ifp || !stio->ofp) {
X	if (stio->ifp) fclose(stio->ifp);
X	if (stio->ofp) fclose(stio->ofp);
X	if (!stio->ifp && !stio->ofp) close(fd);
X	return FALSE;
X    }
X
X    return TRUE;
X}
X
Xint
Xdo_bind(stab, arglast)
XSTAB *stab;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[1];
X    register STIO *stio;
X    char *addr;
X
X    if (!stab)
X	goto nuts;
X
X    stio = stab_io(stab);
X    if (!stio || !stio->ifp)
X	goto nuts;
X
X    addr = str_get(st[++sp]);
X#ifdef TAINT
X    taintproper("Insecure dependency in bind");
X#endif
X    return bind(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
X
Xnuts:
X    if (dowarn)
X	warn("bind() on closed fd");
X    return FALSE;
X
X}
X
Xint
Xdo_connect(stab, arglast)
XSTAB *stab;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[1];
X    register STIO *stio;
X    char *addr;
X
X    if (!stab)
X	goto nuts;
X
X    stio = stab_io(stab);
X    if (!stio || !stio->ifp)
X	goto nuts;
X
X    addr = str_get(st[++sp]);
X#ifdef TAINT
X    taintproper("Insecure dependency in connect");
X#endif
X    return connect(fileno(stio->ifp), addr, st[sp]->str_cur) >= 0;
X
Xnuts:
X    if (dowarn)
X	warn("connect() on closed fd");
X    return FALSE;
X
X}
X
Xint
Xdo_listen(stab, arglast)
XSTAB *stab;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[1];
X    register STIO *stio;
X    int backlog;
X
X    if (!stab)
X	goto nuts;
X
X    stio = stab_io(stab);
X    if (!stio || !stio->ifp)
X	goto nuts;
X
X    backlog = (int)str_gnum(st[++sp]);
X    return listen(fileno(stio->ifp), backlog) >= 0;
X
Xnuts:
X    if (dowarn)
X	warn("listen() on closed fd");
X    return FALSE;
X}
X
Xvoid
Xdo_accept(str, nstab, gstab)
XSTR *str;
XSTAB *nstab;
XSTAB *gstab;
X{
X    register STIO *nstio;
X    register STIO *gstio;
X    int len = sizeof buf;
X    int fd;
X
X    if (!nstab)
X	goto badexit;
X    if (!gstab)
X	goto nuts;
X
X    gstio = stab_io(gstab);
X    nstio = stab_io(nstab);
X
X    if (!gstio || !gstio->ifp)
X	goto nuts;
X    if (!nstio)
X	nstio = stab_io(nstab) = stio_new();
X    else if (nstio->ifp)
X	do_close(nstab,FALSE);
X
X    fd = accept(fileno(gstio->ifp),buf,&len);
X    if (fd < 0)
X	goto badexit;
X    nstio->ifp = fdopen(fd, "r");
X    nstio->ofp = fdopen(fd, "w");
X    nstio->type = 's';
X    if (!nstio->ifp || !nstio->ofp) {
X	if (nstio->ifp) fclose(nstio->ifp);
X	if (nstio->ofp) fclose(nstio->ofp);
X	if (!nstio->ifp && !nstio->ofp) close(fd);
X	goto badexit;
X    }
X
X    str_nset(str, buf, len);
X    return;
X
Xnuts:
X    if (dowarn)
X	warn("accept() on closed fd");
Xbadexit:
X    str_sset(str,&str_undef);
X    return;
X}
X
Xint
Xdo_shutdown(stab, arglast)
XSTAB *stab;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[1];
X    register STIO *stio;
X    int how;
X
X    if (!stab)
X	goto nuts;
X
X    stio = stab_io(stab);
X    if (!stio || !stio->ifp)
X	goto nuts;
X
X    how = (int)str_gnum(st[++sp]);
X    return shutdown(fileno(stio->ifp), how) >= 0;
X
Xnuts:
X    if (dowarn)
X	warn("shutdown() on closed fd");
X    return FALSE;
X
X}
X
Xint
Xdo_sopt(optype, stab, arglast)
Xint optype;
XSTAB *stab;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[1];
X    register STIO *stio;
X    int fd;
X    int lvl;
X    int optname;
X
X    if (!stab)
X	goto nuts;
X
X    stio = stab_io(stab);
X    if (!stio || !stio->ifp)
X	goto nuts;
X
X    fd = fileno(stio->ifp);
X    lvl = (int)str_gnum(st[sp+1]);
X    optname = (int)str_gnum(st[sp+2]);
X    switch (optype) {
X    case O_GSOCKOPT:
X	st[sp] = str_2mortal(str_new(257));
X	st[sp]->str_cur = 256;
X	st[sp]->str_pok = 1;
X	if (getsockopt(fd, lvl, optname, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
X	    goto nuts;
X	break;
X    case O_SSOCKOPT:
X	st[sp] = st[sp+3];
X	if (setsockopt(fd, lvl, optname, st[sp]->str_ptr, st[sp]->str_cur) < 0)
X	    goto nuts;
X	st[sp] = &str_yes;
X	break;
X    }
X    
X    return sp;
X
Xnuts:
X    if (dowarn)
X	warn("[gs]etsockopt() on closed fd");
X    st[sp] = &str_undef;
X    return sp;
X
X}
X
Xint
Xdo_getsockname(optype, stab, arglast)
Xint optype;
XSTAB *stab;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[1];
X    register STIO *stio;
X    int fd;
X
X    if (!stab)
X	goto nuts;
X
X    stio = stab_io(stab);
X    if (!stio || !stio->ifp)
X	goto nuts;
X
X    st[sp] = str_2mortal(str_new(257));
X    st[sp]->str_cur = 256;
X    st[sp]->str_pok = 1;
X    fd = fileno(stio->ifp);
X    switch (optype) {
X    case O_GETSOCKNAME:
X	if (getsockname(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
X	    goto nuts2;
X	break;
X    case O_GETPEERNAME:
X	if (getpeername(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
X	    goto nuts2;
X	break;
X    }
X    
X    return sp;
X
Xnuts:
X    if (dowarn)
X	warn("get{sock,peer}name() on closed fd");
Xnuts2:
X    st[sp] = &str_undef;
X    return sp;
X
X}
X
Xint
Xdo_ghent(which,gimme,arglast)
Xint which;
Xint gimme;
Xint *arglast;
X{
X    register ARRAY *ary = stack;
X    register int sp = arglast[0];
X    register char **elem;
X    register STR *str;
X    struct hostent *gethostbyname();
X    struct hostent *gethostbyaddr();
X#ifdef HAS_GETHOSTENT
X    struct hostent *gethostent();
X#endif
X    struct hostent *hent;
X    unsigned long len;
X
X    if (gimme != G_ARRAY) {
X	astore(ary, ++sp, str_mortal(&str_undef));
X	return sp;
X    }
X
X    if (which == O_GHBYNAME) {
X	char *name = str_get(ary->ary_array[sp+1]);
X
X	hent = gethostbyname(name);
X    }
X    else if (which == O_GHBYADDR) {
X	STR *addrstr = ary->ary_array[sp+1];
X	int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
X	char *addr = str_get(addrstr);
X
X	hent = gethostbyaddr(addr,addrstr->str_cur,addrtype);
X    }
X    else
X#ifdef HAS_GETHOSTENT
X	hent = gethostent();
X#else
X	fatal("gethostent not implemented");
X#endif
X    if (hent) {
X#ifndef lint
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, hent->h_name);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	for (elem = hent->h_aliases; *elem; elem++) {
X	    str_cat(str, *elem);
X	    if (elem[1])
X		str_ncat(str," ",1);
X	}
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_numset(str, (double)hent->h_addrtype);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	len = hent->h_length;
X	str_numset(str, (double)len);
X#ifdef h_addr
X	for (elem = hent->h_addr_list; *elem; elem++) {
X	    (void)astore(ary, ++sp, str = str_mortal(&str_no));
X	    str_nset(str, *elem, len);
X	}
X#else
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_nset(str, hent->h_addr, len);
X#endif /* h_addr */
X#else /* lint */
X	elem = Nullch;
X	elem = elem;
X	(void)astore(ary, ++sp, str_mortal(&str_no));
X#endif /* lint */
X    }
X
X    return sp;
X}
X
Xint
Xdo_gnent(which,gimme,arglast)
Xint which;
Xint gimme;
Xint *arglast;
X{
X    register ARRAY *ary = stack;
X    register int sp = arglast[0];
X    register char **elem;
X    register STR *str;
X    struct netent *getnetbyname();
X    struct netent *getnetbyaddr();
X    struct netent *getnetent();
X    struct netent *nent;
X
X    if (gimme != G_ARRAY) {
X	astore(ary, ++sp, str_mortal(&str_undef));
X	return sp;
X    }
X
X    if (which == O_GNBYNAME) {
X	char *name = str_get(ary->ary_array[sp+1]);
X
X	nent = getnetbyname(name);
X    }
X    else if (which == O_GNBYADDR) {
X	unsigned long addr = U_L(str_gnum(ary->ary_array[sp+1]));
X	int addrtype = (int)str_gnum(ary->ary_array[sp+2]);
X
X	nent = getnetbyaddr((long)addr,addrtype);
X    }
X    else
X	nent = getnetent();
X
X    if (nent) {
X#ifndef lint
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, nent->n_name);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	for (elem = nent->n_aliases; *elem; elem++) {
X	    str_cat(str, *elem);
X	    if (elem[1])
X		str_ncat(str," ",1);
X	}
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_numset(str, (double)nent->n_addrtype);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_numset(str, (double)nent->n_net);
X#else /* lint */
X	elem = Nullch;
X	elem = elem;
X	(void)astore(ary, ++sp, str_mortal(&str_no));
X#endif /* lint */
X    }
X
X    return sp;
X}
X
Xint
Xdo_gpent(which,gimme,arglast)
Xint which;
Xint gimme;
Xint *arglast;
X{
X    register ARRAY *ary = stack;
X    register int sp = arglast[0];
X    register char **elem;
X    register STR *str;
X    struct protoent *getprotobyname();
X    struct protoent *getprotobynumber();
X    struct protoent *getprotoent();
X    struct protoent *pent;
X
X    if (gimme != G_ARRAY) {
X	astore(ary, ++sp, str_mortal(&str_undef));
X	return sp;
X    }
X
X    if (which == O_GPBYNAME) {
X	char *name = str_get(ary->ary_array[sp+1]);
X
X	pent = getprotobyname(name);
X    }
X    else if (which == O_GPBYNUMBER) {
X	int proto = (int)str_gnum(ary->ary_array[sp+1]);
X
X	pent = getprotobynumber(proto);
X    }
X    else
X	pent = getprotoent();
X
X    if (pent) {
X#ifndef lint
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, pent->p_name);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	for (elem = pent->p_aliases; *elem; elem++) {
X	    str_cat(str, *elem);
X	    if (elem[1])
X		str_ncat(str," ",1);
X	}
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_numset(str, (double)pent->p_proto);
X#else /* lint */
X	elem = Nullch;
X	elem = elem;
X	(void)astore(ary, ++sp, str_mortal(&str_no));
X#endif /* lint */
X    }
X
X    return sp;
X}
X
Xint
Xdo_gsent(which,gimme,arglast)
Xint which;
Xint gimme;
Xint *arglast;
X{
X    register ARRAY *ary = stack;
X    register int sp = arglast[0];
X    register char **elem;
X    register STR *str;
X    struct servent *getservbyname();
X    struct servent *getservbynumber();
X    struct servent *getservent();
X    struct servent *sent;
X
X    if (gimme != G_ARRAY) {
X	astore(ary, ++sp, str_mortal(&str_undef));
X	return sp;
X    }
X
X    if (which == O_GSBYNAME) {
X	char *name = str_get(ary->ary_array[sp+1]);
X	char *proto = str_get(ary->ary_array[sp+2]);
X
X	if (proto && !*proto)
X	    proto = Nullch;
X
X	sent = getservbyname(name,proto);
X    }
X    else if (which == O_GSBYPORT) {
X	int port = (int)str_gnum(ary->ary_array[sp+1]);
X	char *proto = str_get(ary->ary_array[sp+2]);
X
X	sent = getservbyport(port,proto);
X    }
X    else
X	sent = getservent();
X    if (sent) {
X#ifndef lint
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, sent->s_name);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	for (elem = sent->s_aliases; *elem; elem++) {
X	    str_cat(str, *elem);
X	    if (elem[1])
X		str_ncat(str," ",1);
X	}
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X#ifdef HAS_NTOHS
X	str_numset(str, (double)ntohs(sent->s_port));
X#else
X	str_numset(str, (double)(sent->s_port));
X#endif
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, sent->s_proto);
X#else /* lint */
X	elem = Nullch;
X	elem = elem;
X	(void)astore(ary, ++sp, str_mortal(&str_no));
X#endif /* lint */
X    }
X
X    return sp;
X}
X
X#endif /* HAS_SOCKET */
X
X#ifdef HAS_SELECT
Xint
Xdo_select(gimme,arglast)
Xint gimme;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[0];
X    register int i;
X    register int j;
X    register char *s;
X    register STR *str;
X    double value;
X    int maxlen = 0;
X    int nfound;
X    struct timeval timebuf;
X    struct timeval *tbuf = &timebuf;
X    int growsize;
X#if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
X    int masksize;
X    int offset;
X    char *fd_sets[4];
X    int k;
X
X#if BYTEORDER & 0xf0000
X#define ORDERBYTE (0x88888888 - BYTEORDER)
X#else
X#define ORDERBYTE (0x4444 - BYTEORDER)
X#endif
X
X#endif
X
X    for (i = 1; i <= 3; i++) {
X	j = st[sp+i]->str_cur;
X	if (maxlen < j)
X	    maxlen = j;
X    }
X
X#if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
X    growsize = maxlen;		/* little endians can use vecs directly */
X#else
X#ifdef NFDBITS
X
X#ifndef NBBY
X#define NBBY 8
X#endif
X
X    masksize = NFDBITS / NBBY;
X#else
X    masksize = sizeof(long);	/* documented int, everyone seems to use long */
X#endif
X    growsize = maxlen + (masksize - (maxlen % masksize));
X    Zero(&fd_sets[0], 4, char*);
X#endif
X
X    for (i = 1; i <= 3; i++) {
X	str = st[sp+i];
X	j = str->str_len;
X	if (j < growsize) {
X	    if (str->str_pok) {
X		Str_Grow(str,growsize);
X		s = str_get(str) + j;
X		while (++j <= growsize) {
X		    *s++ = '\0';
X		}
X	    }
X	    else if (str->str_ptr) {
X		Safefree(str->str_ptr);
X		str->str_ptr = Nullch;
X	    }
X	}
X#if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
X	s = str->str_ptr;
X	if (s) {
X	    New(403, fd_sets[i], growsize, char);
X	    for (offset = 0; offset < growsize; offset += masksize) {
X		for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
X		    fd_sets[i][j+offset] = s[(k % masksize) + offset];
X	    }
X	}
X#endif
X    }
X    str = st[sp+4];
X    if (str->str_nok || str->str_pok) {
X	value = str_gnum(str);
X	if (value < 0.0)
X	    value = 0.0;
X	timebuf.tv_sec = (long)value;
X	value -= (double)timebuf.tv_sec;
X	timebuf.tv_usec = (long)(value * 1000000.0);
X    }
X    else
X	tbuf = Null(struct timeval*);
X
X#if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
X    nfound = select(
X	maxlen * 8,
X	st[sp+1]->str_ptr,
X	st[sp+2]->str_ptr,
X	st[sp+3]->str_ptr,
X	tbuf);
X#else
X    nfound = select(
X	maxlen * 8,
X	fd_sets[1],
X	fd_sets[2],
X	fd_sets[3],
X	tbuf);
X    for (i = 1; i <= 3; i++) {
X	if (fd_sets[i]) {
X	    str = st[sp+i];
X	    s = str->str_ptr;
X	    for (offset = 0; offset < growsize; offset += masksize) {
X		for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
X		    s[(k % masksize) + offset] = fd_sets[i][j+offset];
X	    }
X	}
X    }
X#endif
X
X    st[++sp] = str_mortal(&str_no);
X    str_numset(st[sp], (double)nfound);
X    if (gimme == G_ARRAY && tbuf) {
X	value = (double)(timebuf.tv_sec) +
X		(double)(timebuf.tv_usec) / 1000000.0;
X	st[++sp] = str_mortal(&str_no);
X	str_numset(st[sp], value);
X    }
X    return sp;
X}
X#endif /* SELECT */
X
X#ifdef HAS_SOCKET
Xint
Xdo_spair(stab1, stab2, arglast)
XSTAB *stab1;
XSTAB *stab2;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[2];
X    register STIO *stio1;
X    register STIO *stio2;
X    int domain, type, protocol, fd[2];
X
X    if (!stab1 || !stab2)
X	return FALSE;
X
X    stio1 = stab_io(stab1);
X    stio2 = stab_io(stab2);
X    if (!stio1)
X	stio1 = stab_io(stab1) = stio_new();
X    else if (stio1->ifp)
X	do_close(stab1,FALSE);
X    if (!stio2)
X	stio2 = stab_io(stab2) = stio_new();
X    else if (stio2->ifp)
X	do_close(stab2,FALSE);
X
X    domain = (int)str_gnum(st[++sp]);
X    type = (int)str_gnum(st[++sp]);
X    protocol = (int)str_gnum(st[++sp]);
X#ifdef TAINT
X    taintproper("Insecure dependency in socketpair");
X#endif
X#ifdef HAS_SOCKETPAIR
X    if (socketpair(domain,type,protocol,fd) < 0)
X	return FALSE;
X#else
X    fatal("Socketpair unimplemented");
X#endif
X    stio1->ifp = fdopen(fd[0], "r");
X    stio1->ofp = fdopen(fd[0], "w");
X    stio1->type = 's';
X    stio2->ifp = fdopen(fd[1], "r");
X    stio2->ofp = fdopen(fd[1], "w");
X    stio2->type = 's';
X    if (!stio1->ifp || !stio1->ofp || !stio2->ifp || !stio2->ofp) {
X	if (stio1->ifp) fclose(stio1->ifp);
X	if (stio1->ofp) fclose(stio1->ofp);
X	if (!stio1->ifp && !stio1->ofp) close(fd[0]);
X	if (stio2->ifp) fclose(stio2->ifp);
X	if (stio2->ofp) fclose(stio2->ofp);
X	if (!stio2->ifp && !stio2->ofp) close(fd[1]);
X	return FALSE;
X    }
X
X    return TRUE;
X}
X
X#endif /* HAS_SOCKET */
X
Xint
Xdo_gpwent(which,gimme,arglast)
Xint which;
Xint gimme;
Xint *arglast;
X{
X#ifdef I_PWD
X    register ARRAY *ary = stack;
X    register int sp = arglast[0];
X    register STR *str;
X    struct passwd *getpwnam();
X    struct passwd *getpwuid();
X    struct passwd *getpwent();
X    struct passwd *pwent;
X
X    if (gimme != G_ARRAY) {
X	astore(ary, ++sp, str_mortal(&str_undef));
X	return sp;
X    }
X
X    if (which == O_GPWNAM) {
X	char *name = str_get(ary->ary_array[sp+1]);
X
X	pwent = getpwnam(name);
X    }
X    else if (which == O_GPWUID) {
X	int uid = (int)str_gnum(ary->ary_array[sp+1]);
X
X	pwent = getpwuid(uid);
X    }
X    else
X	pwent = getpwent();
X
X    if (pwent) {
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, pwent->pw_name);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, pwent->pw_passwd);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_numset(str, (double)pwent->pw_uid);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_numset(str, (double)pwent->pw_gid);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X#ifdef PWCHANGE
X	str_numset(str, (double)pwent->pw_change);
X#else
X#ifdef PWQUOTA
X	str_numset(str, (double)pwent->pw_quota);
X#else
X#ifdef PWAGE
X	str_set(str, pwent->pw_age);
X#endif
X#endif
X#endif
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X#ifdef PWCLASS
X	str_set(str,pwent->pw_class);
X#else
X#ifdef PWCOMMENT
X	str_set(str, pwent->pw_comment);
X#endif
X#endif
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, pwent->pw_gecos);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, pwent->pw_dir);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, pwent->pw_shell);
X#ifdef PWEXPIRE
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_numset(str, (double)pwent->pw_expire);
X#endif
X    }
X
X    return sp;
X#else
X    fatal("password routines not implemented");
X#endif
X}
X
Xint
Xdo_ggrent(which,gimme,arglast)
Xint which;
Xint gimme;
Xint *arglast;
X{
X#ifdef I_GRP
X    register ARRAY *ary = stack;
X    register int sp = arglast[0];
X    register char **elem;
X    register STR *str;
X    struct group *getgrnam();
X    struct group *getgrgid();
X    struct group *getgrent();
X    struct group *grent;
X
X    if (gimme != G_ARRAY) {
X	astore(ary, ++sp, str_mortal(&str_undef));
X	return sp;
X    }
X
X    if (which == O_GGRNAM) {
X	char *name = str_get(ary->ary_array[sp+1]);
X
X	grent = getgrnam(name);
X    }
X    else if (which == O_GGRGID) {
X	int gid = (int)str_gnum(ary->ary_array[sp+1]);
X
X	grent = getgrgid(gid);
X    }
X    else
X	grent = getgrent();
X
X    if (grent) {
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, grent->gr_name);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_set(str, grent->gr_passwd);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	str_numset(str, (double)grent->gr_gid);
X	(void)astore(ary, ++sp, str = str_mortal(&str_no));
X	for (elem = grent->gr_mem; *elem; elem++) {
X	    str_cat(str, *elem);
X	    if (elem[1])
X		str_ncat(str," ",1);
X	}
X    }
X
X    return sp;
X#else
X    fatal("group routines not implemented");
X#endif
X}
X
Xint
Xdo_dirop(optype,stab,gimme,arglast)
Xint optype;
XSTAB *stab;
Xint gimme;
Xint *arglast;
X{
X#if defined(DIRENT) && defined(HAS_READDIR)
X    register ARRAY *ary = stack;
X    register STR **st = ary->ary_array;
X    register int sp = arglast[1];
X    register STIO *stio;
X    long along;
X#ifndef telldir
X    long telldir();
X#endif
X    struct DIRENT *readdir();
X    register struct DIRENT *dp;
X
X    if (!stab)
X	goto nope;
X    if (!(stio = stab_io(stab)))
X	stio = stab_io(stab) = stio_new();
X    if (!stio->dirp && optype != O_OPENDIR)
X	goto nope;
X    st[sp] = &str_yes;
X    switch (optype) {
X    case O_OPENDIR:
X	if (stio->dirp)
X	    closedir(stio->dirp);
X	if (!(stio->dirp = opendir(str_get(st[sp+1]))))
X	    goto nope;
X	break;
X    case O_READDIR:
X	if (gimme == G_ARRAY) {
X	    --sp;
X	    while (dp = readdir(stio->dirp)) {
X#ifdef DIRNAMLEN
X		(void)astore(ary,++sp,
X		  str_2mortal(str_make(dp->d_name,dp->d_namlen)));
X#else
X		(void)astore(ary,++sp,
X		  str_2mortal(str_make(dp->d_name,0)));
X#endif
X	    }
X	}
X	else {
X	    if (!(dp = readdir(stio->dirp)))
X		goto nope;
X	    st[sp] = str_mortal(&str_undef);
X#ifdef DIRNAMLEN
X	    str_nset(st[sp], dp->d_name, dp->d_namlen);
X#else
X	    str_set(st[sp], dp->d_name);
X#endif
X	}
X	break;
X#if MACH
X    case O_TELLDIR:
X    case O_SEEKDIR:
X        goto nope;
X#else
X    case O_TELLDIR:
X	st[sp] = str_mortal(&str_undef);
X	str_numset(st[sp], (double)telldir(stio->dirp));
X	break;
X    case O_SEEKDIR:
X	st[sp] = str_mortal(&str_undef);
X	along = (long)str_gnum(st[sp+1]);
X	(void)seekdir(stio->dirp,along);
X	break;
X#endif
X    case O_REWINDDIR:
X	st[sp] = str_mortal(&str_undef);
X	(void)rewinddir(stio->dirp);
X	break;
X    case O_CLOSEDIR:
X	st[sp] = str_mortal(&str_undef);
X	(void)closedir(stio->dirp);
X	stio->dirp = 0;
X	break;
X    }
X    return sp;
X
Xnope:
X    st[sp] = &str_undef;
X    return sp;
X
X#else
X    fatal("Unimplemented directory operation");
X#endif
X}
X
Xapply(type,arglast)
Xint type;
Xint *arglast;
X{
X    register STR **st = stack->ary_array;
X    register int sp = arglast[1];
X    register int items = arglast[2] - sp;
X    register int val;
X    register int val2;
X    register int tot = 0;
X    char *s;
X
X#ifdef TAINT
X    for (st += ++sp; items--; st++)
X	tainted |= (*st)->str_tainted;
X    st = stack->ary_array;
X    sp = arglast[1];
X    items = arglast[2] - sp;
X#endif
X    switch (type) {
X    case O_CHMOD:
X#ifdef TAINT
X	taintproper("Insecure dependency in chmod");
X#endif
X	if (--items > 0) {
X	    tot = items;
X	    val = (int)str_gnum(st[++sp]);
X	    while (items--) {
X		if (chmod(str_get(st[++sp]),val))
X		    tot--;
X	    }
X	}
X	break;
X#ifdef HAS_CHOWN
X    case O_CHOWN:
X#ifdef TAINT
X	taintproper("Insecure dependency in chown");
X#endif
X	if (items > 2) {
X	    items -= 2;
X	    tot = items;
X	    val = (int)str_gnum(st[++sp]);
X	    val2 = (int)str_gnum(st[++sp]);
X	    while (items--) {
X		if (chown(str_get(st[++sp]),val,val2))
X		    tot--;
X	    }
X	}
X	break;
X#endif
X#ifdef HAS_KILL
X    case O_KILL:
X#ifdef TAINT
X	taintproper("Insecure dependency in kill");
X#endif
X	if (--items > 0) {
X	    tot = items;
X	    s = str_get(st[++sp]);
X	    if (isupper(*s)) {
X		if (*s == 'S' && s[1] == 'I' && s[2] == 'G')
X		    s += 3;
X		if (!(val = whichsig(s)))
X		    fatal("Unrecognized signal name \"%s\"",s);
X	    }
X	    else
X		val = (int)str_gnum(st[sp]);
X	    if (val < 0) {
X		val = -val;
X		while (items--) {
X		    int proc = (int)str_gnum(st[++sp]);
X#ifdef HAS_KILLPG
X		    if (killpg(proc,val))	/* BSD */
X#else
X		    if (kill(-proc,val))	/* SYSV */
X#endif
X			tot--;
X		}
!STUFFY!FUNK!
echo " "
echo "End of kit 3 (of 36)"
cat /dev/null >kit3isdone
run=''
config=''
for iskit in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36; do
    if test -f kit${iskit}isdone; then
	run="$run $iskit"
    else
	todo="$todo $iskit"
    fi
done
case $todo in
    '')
	echo "You have run all your kits.  Please read README and then type Configure."
	for combo in *:AA; do
	    if test -f "$combo"; then
		realfile=`basename $combo :AA`
		cat $realfile:[A-Z][A-Z] >$realfile
		rm -rf $realfile:[A-Z][A-Z]
	    fi
	done
	rm -rf kit*isdone
	chmod 755 Configure
	;;
    *)  echo "You have run$run."
	echo "You still need to run$todo."
	;;
esac
: Someone might mail this, so...
exit

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.