Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_FS_1_19910112 - c/lib5/usys/old-urt.save
There are no other files named old-urt.save in the archive.
/*
   [SRI-NIC]SS:<C.KCC.LIB.URT>URT.C.23, 28-Feb-86 14:08:21, Edit by IAN
   cleanup
   Name changed to URT.C for consistency (UN*X Run Time) --KLH
   <KCC.LIB>RUNTM.C.80, 19-Mar-85 20:26:30, Edit by WHP4
    add & code for TOPS20
   <KCC.LIB>RUNTM.C.79, 19-Mar-85 12:48:23, Edit by SATZ
   Add wildcard code
   <KCC.LIB>RUNTM.C.72,  1-Mar-85 17:04:28, Edit by SATZ
   Make sure arg. parsing code understands quotes
   <KCC.LIB>RUNTM.C.68, 17-Jan-85 17:23:53, Edit by WHP4
    add iwrite to complement iread (TOPS-20)
   SCORE:<KCC.LIB>RUNTM.C.43, 18-Jul-84 14:12:26, Edit by KRONJ
    split out TOPS-20 and WAITS specific code
   SCORE:<KCC.LIB>RUNTM.C.35, 18-Jul-84 10:59:59, Edit by KRONJ
    TOPS20 conditional occasionally misspelled as TOPS-20
   SCORE:<KCC.LIB>RUNTM.C.30, 18-Jul-84 00:12:53, Edit by KRONJ
    clean up, use sbrk() to make space for JCL
   SCORE:<KCC.LIB>RUNTM.C.28, 17-Jul-84 17:52:44, Edit by KRONJ
    fix _abort()
   SCORE:<KCC.LIB>RUNTM.C.27, 17-Jul-84 17:44:35, Edit by KRONJ
    complain about losing redirection rather than just ignoring it
   SCORE:<KCC.LIB>RUNTM.C.4, 16-May-84 21:26:05, Edit by KRONJ
    exit() calls wait() to flush subforks
   SCORE:<KCC.LIB>RUNTM.C.3, 15-May-84 19:59:34, Edit by KRONJ
    runtm() is now _runtm() to avoid conflict w/RUNTM jsys
    "foo <user>bar" hands filename to user rather than silly redirect
    ignore spaces after "<" or ">"
*/

/*
 *	High-level Runtime Support for C (TOPS-20 & WAITS)
 *
 *	k. chen  Aug, 1981
 *
 *	TOPS-20:
 *
 *	. _uioch[fd] contains a JFN
 *	. _uioch[0] contains .PRIIN,  _uioch[1] .PRIOU,  _uioch[2] .CTTRM
 *	. _sios[] is an array a standard FILE pointers, stdin, stdout,
 *	  and stderr; the FDs are 0, 1, and 2 respectively.
 *	. command line is of the form
 *	. @FOO.EXE arg1 arg2 arg3 ...
 *	. redirection to/from files is supported
 *	. pipes are supported
 *
 *	WAITS:
 *
 *	. ch[fd] contains a channel number (usually fd)
 *	. channel 0 is unredirected TTY input, channel 1 output
 *	. command line is of the form
 *	. .RUN FOO ; arg1 arg2 arg3 ...
 *	. redirection to/from files is supported
 */

#include <c-env.h>	/* Include environment/config defs */
#include <stdio.h>
#include <urtio.h>	/* Include Unix I/O support stuff */

#ifndef NULL
#define	NULL		0
#endif

#ifndef TRUE
#define TRUE		1
#define FALSE		0
#endif

char *sbrk(), *malloc();
/* ---------------------------- */
/*      start up C program      */
/* ---------------------------- */

_runtm()
{
    int argc, pipes[2], i, done, wild, n;
    char *argbuf, *p, *in, *out, *argv[32], fname[128];
    char *getjcl(), *getstr(), *_namew();

    for (i = UIO_FIRST_CH; i < UIO_MAXFILE; i++)
	_uioch[i] = UIO_UNASS;		/* now so pipe() works */

    argc = 0;				/* no args seen */
    pipes[0] = pipes[1] = 0;		/* no redirection to program */
    in = out = NULL;			/* no redirection to file */

/*
 *	Read command line into a string.  We later drop some nulls into
 *	it to separate it into arguments, to save space.  We allocate
 *	space using sbrk() for the string; if there are no wildcard
 *	arguments this will be all we need to store arguments.
 */

    p = argbuf = getjcl();		/* read JCL into buffer */
    if (p && ((n = strlen(p)) > 0)) {
	done = wild = FALSE;		/* not done yet */
	while (!done) {			/* until we hit a comment or eol */
	    switch (*p) {		/* now depending on what it is: */
	    case ' ':
	    case '\t':			/* space or tab */
#if SYS_WAITS				/* or semicolon for WAITS */
	    case ';':
#endif
		p++;			/* are merely ignored */
		break;

	    case '\0':
	    case '\r':
	    case '\n':			/* null, return, and linefeed */
#if SYS_T20+SYS_10X			/* and comment chars on TOPS-20 */
	    case ';':
	    case '!':
#endif
		done = TRUE;		/* end of line, stop making args */
		break;

	    case '|':			/* vertical bracket (pipe fitting)? */
		if (out != NULL) abortmsg("?Multiple redirection of output");
		*p++ = '\0';		/*   null-term in case delimited arg */
		while (*p == ' ' || *p == '\t') p++;
		out = p;		/*   copy string, save as out file */
		if (pipe(pipes) == -1) abortmsg("?Couldn't make pipe");
		p = getstr(p);		/*   skip over program name */
		if (!vfork()) {		/*   make new program: */
		    dup2(pipes[0], 0);	/*       redirect input from pipe */
		    execlp(out, out, p, 0); /*  run piped program */
		    abortmsg("?Couldn't get next program in pipe");
		}
		_uioch[pipes[0]] = UIO_UNASS; /* mom fork, don't close here */
		done = TRUE;		/*   remaining JCL went to daughter */
		break;

	    case '>':			/* output redirection? */
		p++;			/*   skip close bracket */
		if (out != NULL) abortmsg("?Multiple redirection of output");
		while (*p == ' ' || *p == '\t') p++;
		out = p;		/*   copy pointer to file name */
		p = getstr(p);		/*   skip over it in args */
		break;

#if SYS_T20
	    case '&':
		/* we want to tell exec to continue us in background */
		/* requires a simple modification to the EXEC */
		
					/* tell exec we need '&' action */
		if (procamper() == -1)	/* or die trying */
		    abortmsg("Couldn't continue ourselves in background");

		done = TRUE;		/* we shouldn't have anything */
					/* after this */
		break;			/* return running in background */
#endif					/* TOPS20 */
	    case '<':
/*
 *	We want "prog <foo" to be redirected from file FOO, but
 *	"prog <user>bar" should get "<user>bar" as an argument.
 *	luckily the syntax is fairly unambiguous...
 */
#if SYS_T20+SYS_10X
		if (!mangle(p))		/* unmatched brackets? */
#endif
		  {	p++;		/* yes, skip open bracket */
			if (in != NULL)
				abortmsg("?Multiple redirection of input");
			while (*p == ' ' || *p == '\t') p++;
			in = p;		/* copy pointer to file name */
			p = getstr(p);	/* skip over it in args */
			break;
		  }			/* end if (!mangle(p)) */
	/* Note: Can DROP THROUGH to default processing! */

	  default:			/* not special char, normal arg */
	       if (*p == '"' || *p == '\'') {
		   argv[argc++] = p+1;	/* copy pointer to it past quote */
		   wild = TRUE;		/* nonzero means no check for wild */
	       } else
		   argv[argc++] = p;	/* copy pointer to it */
	       p = getstr(p);		/* skip over it in args */

#if SYS_ITS==0
	       /* make sure we don't have EXEC key at JCL start */
	       if (argc == 1 && (caseall(argv[argc-1],"RUN") ||
				 caseall(argv[argc-1],"RU") ||
				 caseall(argv[argc-1],"R") ||
				 caseall(argv[argc-1],"START") ||
				 caseall(argv[argc-1],"ST") ||
				 caseall(argv[argc-1],"S")))
	           argc--;
#endif /* not ITS */
#if SYS_T20+SYS_10X
		if (argc <= 1 || wild)
		    wild = FALSE;	/* don't check for wild card */
		else if (rindex(argv[argc-1],'*') || rindex(argv[argc-1],'%')){
		    argc--;		/* backup to prev. arg. */
		    if ((wild = _openw(argv[argc])) < 0)	/* open wild */
			abortmsg("?No match");
		    do
			argv[argc++] = _namew(wild);	/* get new name */
		    while (_nextw(wild));
		    wild = FALSE;	/* reset in case another wild */
	       }
#endif /* T20+10X */
	    }				/* end switch (*p) */
	}				/* end while (!done) */
    }					/* end if (n) */

    if (pipes[1]) {			/*   if we are piping output */
	dup2(pipes[1], 1);		/*   redirect output to pipe */
	out = NULL;			/*   don't try sending to file */
    }

    setup(in,out);			/* initialize I/O */
    main(argc,argv);			/* call user program */
    exit(0);				/* terminate successfully */
}
/* -------------------------------------------- */
/*	close all files and exit to monitor     */
/* -------------------------------------------- */

exit(n)
{
    int i;

    _sexit();				/* clean up stdio */
#if SYS_T20+SYS_10X
    resettty();
#endif
    for (i = UIO_FIRST_CH; i < UIO_MAXFILE; i++)
	if (_uioch[i] != UIO_UNASS)
	    close(i);
    while (wait(&i) != -1);		/* flush all daughter forks */
    _exit(n);				/* go do low level exit */
}
/* ------------------------------- */
/*	get a string from JCL      */
/* ------------------------------- */

static char *getstr(p)
char *p;
{
    char s;

    while (TRUE) switch (*p) {
#if SYS_T20+SYS_10X			/* TOPS-20: */
    case ';':				/*   semicolon */
    case '!':				/*   and excl are other line ends */
#endif
    case '\n':
    case '\r':
	*p = '\0';			/* end of line, null out */
	return p;			/* but don't incr before return */

    case ' ':
    case '\t':
#if	SYS_WAITS				/* WAITS: */
    case ';':				/*   semicolon is like a space */
#endif
	*p++ = '\0';			/* null terminate, go on */

    case '\0':				/* null is already null */
    case '|':				/* pipe delim gets nulled later */
	return p;			/* so just return the end ptr */

    case '"':				/* get end of strings */
    case '\'':
	s = *p;				/* remember which quote */
	while (*++p && *p != s)		/* while not null and not quote */
	    if (*p =='\\')		/* check for quoted characters */
		p++;			/* always skip it */
	*p = ' ';			/* get rid of it */
	break;

    case '\026':
    case '\\':				/* check for special characters */
	p++;				/* skip it and next character */
    default:
	p++;				/* not special, just go past it */
    }
}
/* ---------------------------------------------- */
/*	compare string with uppercase string      */
/* ---------------------------------------------- */

static caseall(s,t)
char *s,*t;
{
    while (up(*s) == *t++)
	if (!*s++) return TRUE;
    return FALSE;
}

static up(c)
{
    if (c >= 'a' && c <= 'z') return c - 'a' + 'A';
    return c;
}
/* ----------------------------------- */
/*      System-dependent routines      */
/* ----------------------------------- */

#if SYS_T20+SYS_10X			/* TOPS-20 and TENEX: */
/* Name changed to URTT20 for consistency --KLH */
/* <KCC.LIB>RUNTM.T.55, 19-Mar-85 21:11:03, Edit by WHP4 */
/*  finally get it right (the logic, that is) */
/* <KCC.LIB>RUNTM.T.51, 19-Mar-85 20:41:48, Edit by WHP4 */
/*  keep compiler happy about implicit coercions */
/* <KCC.LIB>RUNTM.T.50, 19-Mar-85 20:26:50, Edit by WHP4 */
/*  add & code for TOPS20 */
/* <KCC.LIB>RUNTM.T.47,  2-Mar-85 13:28:49, Edit by SATZ */
/* Add wildcard code */
/* <KCC.LIB>RUNTM.T.42, 17-Jan-85 17:18:58, Edit by WHP4 */
/*  add iwrite to complement iread */

/*
** TOPS-20/TENEX specific portions of higher-level runtimes
**
*/

#define bit(b)	(1 << (35 - b))

#define	GJFOU	bit(0)			/* get JFN for output file */
#define	GJOLD	bit(2)			/* get JFN for existing file */
#define	GJIFG	bit(11)			/* allow wildcard filename */

#define	OFRD	bit(19)			/* open file with read access */
#define OFWR	bit(20)			/* open file with write access */
#define	OFAP	bit(22)			/* open file with append access */

#define _PRIIN	0100			/* (redirected) primary input */
#define	_PRIOU	0101			/* (redirected) primary output */
#define _CTTRM	0777777			/* controlling terminal */

#define PRAST   2			/* set PRARG arguments */
#define _FHSLF  0400000			/* .FHSLF */
#define HALTF   0170			/* HALTF jsys */
#define PRARG   0545			/* PRARG jsys */

#define _IN_S		0
#define _OUT_S		1
#define _ERR_S		2

FILE _sios[] = {{0, NULL, NULL, 0,
		 _SIOF_READ | _SIOF_BUF | _SIOF_LINEBUF | _SIOF_AUTOBUF,
		 _IN_S, 0L, 0, NULL, 0, ""},

		{0, NULL, NULL, 0,
		 _SIOF_WRITE | _SIOF_BUF | _SIOF_LINEBUF | _SIOF_AUTOBUF,
		 _OUT_S, 0L, 0, NULL, 0, ""},

		{0, NULL, NULL, 0,
		 _SIOF_WRITE,
		 _ERR_S, 0L, 0, NULL, 0, ""}};

#asm
	SEARCH MONSYM
#endasm
/* ------------------------------------------------------------------- */
/*      check for matched angles to see if want to do redirection      */
/* ------------------------------------------------------------------- */

static mangle(p)
char *p;
{
    while (TRUE) {			/* until we find a special char */
	switch (*++p) {			/* check char (ignoring first open) */
	case ' ': case '\t': case '\n': case '\r':
	case ';': case '<':  case ':':  case '\0':
	    return FALSE;		/* no close or second open, redirect */
	case '>':
	    return TRUE;		/* found an angle, matched */
	}
    }
}
/* ---------------------- */
/*      set up files      */
/* ---------------------- */

static setup(in,out)
char *in, *out;
{
    _uioch[_IN_S] = _PRIIN;
    _uioch[_OUT_S] = _PRIOU;
    _uioch[_ERR_S] = _CTTRM;
    setfil(in, _IN_S);			/* redirect stdin */
    setfil(out, _OUT_S);		/* and stdout */
    settty();				/* set the ccoc stuff */
}

static setfil(name, chan)		/*   subroutine for setup */
char *name;
{
    int file;

    if (name != NULL) {				/* if redirected */
	if (chan) file = creat(name, 0);	/* open output file */
	else file = open(name, 0);		/* or input file */
	if (file >= 0) dup2(file, chan);	/* set it as new primary I/O */
	else abortmsg("?Couldn't open redirection file");
    }
}
/* ---------------------------------------- */
/*	set terminal mode word		    */
/* ---------------------------------------- */

#define	RFCOC 		0112
#define	SFCOC 		0113 
#define CCOC_MAGIC	0525252525252

static int ccoc[2];

static settty()
{
    int ablock[5];

    ablock[1] = _uioch[_ERR_S];		/* stderr */
    if (!jsys(RFCOC, ablock)) return FALSE;
    ccoc[0] = ablock[2];
    ccoc[1] = ablock[3];		/* save ccoc words */
    ablock[2] = ablock[3] = CCOC_MAGIC;
    if (!jsys(SFCOC, ablock)) return FALSE;
    else return TRUE;
}

static resettty()
{
    int ablock[5];

    ablock[1] = _uioch[2];		/* stderr */
    ablock[2] = ccoc[0];
    ablock[3] = ccoc[1];
    return (jsys(SFCOC, ablock)) ? TRUE : FALSE;
}
/* --------------------------------------- */
/*      output error message and exit      */
/* --------------------------------------- */

static abortmsg(s)
char *s;
{
    _uioch[_IN_S] = _CTTRM;	/* Crock */
    write(_IN_S, s, 0);		/* string terminated by null */
    write(_IN_S, "\015\012", 0);/* CRLF, again null-terminated */
    _exit(0);			/* in either case, stop program */
}
/* ------------------------------- */
/*	open wild card filename	   */
/* ------------------------------- */

_openw(name)
char *name;
{
    int channel;

    channel = _gtjfn(name, GJOLD | GJIFG);
    return (channel < 0) ? -1 : channel;	/* make sure got one */
}
/* ------------------------------- */
/*	return wild card filename  */
/* ------------------------------- */

#define	_JFNS	030

static char *_namew(jfn)
int jfn;
{
    char *fp, fname[128];
    int ablock[5];

    ablock[1] = (int) (fname - 1);
    ablock[2] = jfn & 0777777;	/* jfn, no flags */
    ablock[3] = 0111100000001;	/* DEV+DIR+NAME+TYPE, punctuate */
    if (!jsys(_JFNS, ablock))
	return NULL;		/* something bad happened */
    fp = sbrk(strlen(fname) + 1);
    strcpy(fp, fname);		/* copy the file name here */
    return fp;
}
/* ------------------------------- */
/*	next wild card filename	   */
/* ------------------------------- */

#define	GNJFN	017

static _nextw(jfn)
int jfn;
{
    int ablock[5];

    ablock[1] = jfn;		/* save jfn and flags */
    return (jsys(GNJFN, ablock)) ? TRUE : FALSE;
}
/* ----------------------------- */
/*      return command line      */
/* ----------------------------- */

static char *getjcl()
{
    char *argbuf, *cp;
    int c, n;
	int ffd;			/* Use a fake FD to avoid _read */
#if SYS_10X
	char tmpbuf[1000];
#endif

	ffd = _uiofd();
	_uioch[ffd] = _CTTRM;		/* Gross crock */
#if SYS_T20
    n = _rscan();			/* Rescan command line */
    argbuf = sbrk(n + 1);		/* make room for chars and null */
    read(ffd,argbuf,n);			/* read from .CTTRM not .PRIOU */
    argbuf[n] = 0;
#endif
#if SYS_10X
    for (cp = tmpbuf; read(ffd, cp, 1) == 1; ++cp)
	if ((c  = *cp) == '\037' || c == '\r' || c == '\n') {
	    *cp++ = '\n';
	    break;
	}
    *cp = 0;
    n = strlen(tmpbuf);
    argbuf = sbrk(n + 1);
    strcpy(argbuf, tmpbuf);
#endif /*SYS_10X*/
    _uioch[ffd] = UIO_UNASS;		/* Reset crock */
    return argbuf;
}
#if SYS_T20

static _rscan();
#asm

.RSCAN:	MOVEI	1,.RSINI
	RSCAN%
	 ERJMP	$RETZ		; No chars avail
	POPJ	17,
#endasm
#endif
static char *bp7 (ip)
int *ip;
{
    int i = ip;
    i |= ((i &~ 0777777) ? 0620000000000 : 0350700000000);
    return (char *) i;
}


/*
 *	Tell EXEC via termination PRARG that we want to be continued in
 *	the background (e.g. we were invoked by foo &) requires slight
 *	EXEC modification
 */

procamper()
{
    int trmprg[30], acs[5];

    char *p, *q = "continue, background\015\012";
    
    trmprg[0] = 1;
    trmprg[1] = 0400740000002;		/* magic number needed by exec */
    p = bp7(&trmprg[2]);		/* (points to this word for string) */
    while (*q) *p++ = *q++;		/* copy command string */
    *p++ = 0;				/* null terminate it */
    acs[1] = PRAST << 18 | _FHSLF;	/* 1/ .PRAST,,.FHSLF */
    acs[2] = (int) (trmprg);		/* 2/ address of trmprg */
    acs[3] = 30;			/* 3/ length of trmprg */
    if (!jsys(PRARG, acs)) return -1;	/* some lossage */
    jsys(HALTF, acs);			/* stop and let exec continue us */
    return;				/* return to caller in background */
}
#endif
#if SYS_WAITS				/* WAITS: */
/*
**  WAITS specific portions of higher-level runtimes
*/
/* ---------------------- */
/*	set up files      */
/* ---------------------- */

static setup(in,out)
char *in, *out;
{
    _uioch[_IN_S] = (in  != NULL) ? _uioch[open(in,0)] : 0;	    /* stdin */
    _uioch[_OUT_S] = (out != NULL) ? _uioch[creat(out,0)] : 1;   /* stdout */
    _uioch[_ERR_S] = 2;					    /* stderr */
    _uioeof = 0;				/*   no eof on terminal yet */
}
/* --------------------------------------- */
/*	output error message and exit      */
/* --------------------------------------- */

static abortmsg(s)
char *s;
{
    while (*s) _putty(*s++);		/*   send it out a bit at a time */
    _putty('\n');			/*   with a CR to make a new line */
    _exit(0);				/* in either case, stop program */
}
/* ----------------------------- */
/*      return command line      */
/* ----------------------------- */

static char *getjcl()
{
    char *argbuf, *p;
    int n;

    n = _rscan();			/* Rescan command line */
    argbuf = sbrk(n + 1);		/* make room for chars and null */
    p = argbuf;				/* point to start of buffer */
    while (--n) *p++ = _getty();	/* read the number of chars */
    _getty();				/* plus one trailer */
    *p = '\0';				/* terminate with a null */
    return argbuf;
}

static _rscan();
#asm
.RSCAN:	RESCAN	1	; Rescan command line, get # chars avail in 1.
	POPJ	17,
#endasm

#endif /* WAITS */
#if SYS_ITS
/*
 *	Runtime stuff for ITS
 */

#include "sysits.h"

extern char *calloc();
extern free();

static
setup(in,out)
{
	setfil(0, in ? in : "TTY:", 0);
	setfil(1, out?out : "TTY:", 1);
	setfil(2, "TTY:", 1);
}

static setfil(fd, name, umode)
char *name;
{
    int fdx;

    if ((fdx = _ofile(name, umode, 7)) >= 0) {
	if (fdx != fd)
	    dup2(fdx, fd);
    } else abortmsg("?Couldn't open redirection file");
}

static abortmsg(msg)
char *msg;
{
    char tmpbuf[1000];

    strcat(strcat(strcpy(tmpbuf,":\033 "),msg)," \033\r\n\033p");
    _valret(tmpbuf);
    _exit(0);
}


static char *getjcl()
{
    char *_rjcl();

    return _rjcl();
}
static char *_rjcl();			/* return BP to JCL */
static _valret();			/* pass word-aligned string to DDT */
#asm

/*
** Whoever wrote this code ought to be shot.
** One is not supposed to depend on arguments to subroutines
** (in this case calloc()) having any useful value after the return.
** But it doesn't affect me and I'm too lazy to fix it.
**	- David Eppstein, 1-Jul-85
*/

.RJCL:	.SUSET [.ROPTIO,,1]
	TLNN 1,%OPCMD		; Has our superior said it has a cmd?
	 JRST $RETZ		; No.
	PUSH 17,[4]
	PUSH 17,[100]		; Get big block to start with
.RJCL1:	PUSHJ 17,calloc		; Get zeroed memory
	JUMPE 1,[ADJSP 17,-2	; Not enough mem!
		JRST $RETZ]
	MOVE 2,0(17)
	ADDI 2,(1)		; Get addr of 1st wd past block
	SETOM -1(2)		; Set up fence at last word.
	MOVEI 3,(1)
	HRLI 3,5		; 5 = Read JCL from superior
	.BREAK 12,3		; Try to read command string.
	SKIPE -2(2)		; See if clobbered last word
	 JRST [	PUSH 17,1
		PUSHJ 17,free	; Sigh, must free it.
		POP 17,1
		MOVEI 1,100	; Get more words
		ADDM 1,(17)	; Add to arg requested
		JRST .RJCL1]
	ADJSP 17,-2		; Got it all!  Flush stack stuff
	HRLI 1,350700		; Return char pointer to ASCIZ
	POPJ 17,

.VALRET:
	XMOVEI 1,@-1(17)	; We just hope it starts on wd boundary.
	.VALUE (1)
	POPJ	17,
#endasm

#endif /* ITS */