Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_FS_1_19910112 - c/old/lib/urt.c
There are 9 other files named urt.c in the archive. Click here to see a list.
/* 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:
    **	    - ch[fd] contains a JFN
    **	    - ch[0] contains .PRIIN,  ch[1] .PRIOU,  ch[2] .CTTRM
    **	    - 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 */

#define	NULL	   0

/* Externals supported by this module: */
entry _runtm;		/* For calling via KCC startup */
entry exit;		/* UNIX misc syscall */
entry _sexit;		/* stdio.c - random crock */

#include "urtio.h"	/* Include Unix I/O support stuff */

int (*_sexit)() = NULL;		/* Routine to clean up stdio */

char *sbrk();
/* ---------------------------- */
/*      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 = 3; 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 = 0;		/* 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 = 1;		/* 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 (!fork()) {		/*   make new program: */
/* _fname has no business here.  Moved to KCC.  --KLH */
/*		    _fname(fname, out);	/*       find name of program */
		    dup2(pipes[0], 0);	/*       redirect input from pipe */
		    execl(out, out, p, 0); /*  run piped program */
		    abortmsg("?Couldn't get next program in pipe");
		}
		_uioch[pipes[0]] = UIO_UNASS; /*  mother fork, don't close here */
		done = 1;		/*   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 = 1;		/* 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 = 1;		/* 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 = 0;		/* 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 = 0;	/* 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;

    if (_sexit != NULL) (*_sexit)();	/* clean up stdio */
#if SYS_T20+SYS_10X
    resettty();
#endif
    for (i=0; 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 (1) 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 1;
    return 0;
}

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	GJOLD	0100000000000		/* get JFN for existing file */
#define	GJFOU	0400000000000		/* get JFN for output file */
#define	GJIFG	0000100000000

#define	OFAP	0020000			/* open file with append access */
#define OFWR	0100000			/* open file with write access */
#define	OFRD	0200000			/* open file with read access */

#define _PRIIN	0000100			/* (redirected) primary input */
#define	_PRIOU	0000101			/* (redirected) primary output */
#define CTTRM	0777777			/* controlling terminal */

#define PRAST   0000002			/* set PRARG arguments */
#define _FHSLF   0400000			/* .FHSLF */
#define HALTF   0000170			/* HALTF jsys */
#define PRARG   0000545			/* PRARG jsys */

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

static
mangle(p)
char *p;
{
    while(1) {				/* 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 0;			/* no close or second open, redirect */
	case '>':
	    return 1;			/* found an angle, matched */
	}
    }
}
/* ---------------------- */
/*      set up files      */
/* ---------------------- */

static setup(in,out)
char *in, *out;
{
    _uioch[0] = _PRIIN;			/*   primary input (stdin) */
    _uioch[1] = _PRIOU;			/*   primary output (stdout) */
    _uioch[2] = CTTRM;			/*   controlling tty (stderr) */
    setfil(in, 0);			/*   redirect stdin */
    setfil(out, 1);			/*   and stdout */
    settty();				/*   set the ccoc stuff */
}

static setfil(nam, chan)		/*   subroutine for setup */
char *nam;
{
    int fil;

    if (nam != NULL) {			/*   if redirected */
	if (chan) fil = creat(nam, 0);	/*     open output file */
	else fil = open(nam, 0);	/*     or input file */
	if (fil >= 0) dup2(fil, 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 

static int ccoc[2];

static
settty()
{
    int ablock[5];

    ablock[1] = _uioch[2];		/* stderr */
    if (jsys(RFCOC, ablock) == 0)
	return -1;
    ccoc[0] = ablock[2];
    ccoc[1] = ablock[3];	/* save ccoc words */
    ablock[2] = ablock[3] = 0525252525252;
    if (jsys(SFCOC, ablock) == 0)
	return -1;
}

static
resettty()
{
    int ablock[5];

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

static abortmsg(s)
char *s;
{
    _uioch[0] = CTTRM;		/* Crock */
    write(0, s, 0);		/* string terminated by null */
    write(0, "\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);
    if (channel < 0) return -1;		/* make sure got one */
    return channel;
}
/* ------------------------------- */
/*	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) > 0 ? 1 : 0);
}
/* ----------------------------- */
/*      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)
	  {	c = *cp;
		if(c == '\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
#asm

.RSCAN:	MOVEI 1,.RSINI
	RSCAN%
	 ERJMP $RETZ		; No chars avail
	RET
#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;
    char *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[0]);		/* 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[0] = (in  != NULL) ? _uioch[open(in,0)] : 0;	    /* stdin */
    _uioch[1] = (out != NULL) ? _uioch[creat(out,0)] : 1;   /* stdout */
    _uioch[2] = 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;
}
#asm
.RSCAN:	RESCAN 1	; Rescan command line, get # chars avail in 1.
	RET
#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());
}
#asm
; char *_rjcl();	; Return BP to JCL

.RJCL:	.SUSET [.ROPTIO,,1]
	TLNN 1,%OPCMD		; Has our superior said it has a cmd?
	 JRST $RETZ		; No.
	PUSH P,[4]
	PUSH P,[100]		; Get big block to start with
.RJCL1:	PUSHJ P,CALLOC		; Get zeroed memory
	JUMPE 1,[ADJSP P,-2	; Not enough mem!
		JRST $RETZ]
	MOVE 2,(P)
	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 P,1
		PUSHJ P,FREE	; Sigh, must free it.
		POP P,1
		MOVEI 1,100	; Get more words
		ADDM 1,(P)	; Add to arg requested
		JRST .RJCL1]
	ADJSP P,-2		; Got it all!  Flush stack stuff
	HRLI 1,350700		; Return char pointer to ASCIZ
	POPJ P,

.VALRET:
	%CHRBP 1,%ARG1(P)	; We just hope it starts on wd boundary.
	.VALUE (1)
	RET
#endasm

#endif /* ITS */