Trailing-Edge
-
PDP-10 Archives
-
SRI_NIC_PERM_FS_1_19910112
-
kcc-4/lib/usys/urt.c
There are 9 other files named urt.c in the archive. Click here to see a list.
/* URT - USYS Run Time support and startup
**
** Copyright (c) 1987 by Ken Harrenstien & Ian Macky, SRI International
** applies to edits made since name changed to URT.C.
**
** This code is invoked by the CRT (C Run Time) startup and does
** various things (such as parsing any JCL) before invoking the user's
** "main" function.
*/
/* The following edit history is for the most part old, outdated, and
** made irrelevant by sweeping changes. It is kept in case any credits
** are still applicable.
*/
/*
[SRI-NIC]SS:<C.LIB.URT.NEW>URT.C.9, 18-Apr-86 11:25:04, Edit by IAN
more cleanup, adaptation to new urt/stdio
[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 "stdlib.h" /* standard library definitions */
#include "urtsud.h" /* URT StartUp Definition structure */
#include "stdio.h"
#include "errno.h"
#include "frkxec.h" /* New KCC forkexec() call */
#include "sys/usysio.h"
#include "sys/usytty.h" /* Internal TTY defs */
#include "sys/usysig.h"
#include "sys/file.h"
#include "ctype.h"
#include "string.h" /* For str- and mem- defs */
#if SYS_T20+SYS_10X
#include "jsys.h"
#endif
/* Exported functions (defined here) */
void _runtm(); /* URT startup entry point */
/* Imported (external) functions */
extern main(); /* From user program */
extern char *sbrk(); /* See the WALIGN_sbrk macro below */
extern void exit(), _exit();
/* Internal functions */
static char *getstr();
static int caseall();
#if SYS_T20+SYS_10X
static int _openw(), _nextw();
static char *_namew();
#endif
/* Global URT data. Only "errno" is intended to be user-visible. */
int errno = 0; /* Error # from last failing UN*X syscall */
int _vfrkf = 0; /* Non-zero if memory shared as result of vfork() */
int _nfork = 0; /* Count of inferiors created by this process.
** Only used to determine whether a fork or vfork
** was ever done, i.e. if exit() should wait().
*/
/* Define macro so that sbrk()'s idea of the break is always word-aligned
** upon entry to the user program.
*/
#define WS (sizeof(int)) /* Word size */
#define WALIGN_sbrk(n) sbrk((((n)+WS-1)/WS)*WS) /* Word-aligned sbrk() */
/* ---------------------------- */
/* start up C program */
/* ---------------------------- */
#define IN 0
#define OUT 1
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#define MAX_ARG 32
static int argc; /* argument count */
static char **argv; /* pointer to argv vector */
static int argv_size; /* current max size of argv */
static void arg_set(); /* use this to set args in argv */
void _runtm()
{
int (*parser)(); /* parser function to call */
static int shell_parse(), exec_parse();
char *p, *arg_vector[MAX_ARG], *_getjcl();
init_uio(); /* initialize uio layer */
argc = 0; /* no args on command line yet */
argv = arg_vector; /* start off using this array */
argv_size = MAX_ARG; /* size of argv array */
if (_urtsud.su_parser_type != _URTSUD_NO_PARSE && (p = _getjcl(NULL))) {
switch (_urtsud.su_parser_type) {
case _URTSUD_SHELL_PARSE: parser = shell_parse; break;
case _URTSUD_EXEC_PARSE: parser = exec_parse; break;
}
(*parser)(p); /* invoke the parser */
}
tty_set(); /* Set up TTY stuff if any. If so, it must */
/* register a cleanup rtn with onexit()! */
onexit(_cleanup); /* Register STDIO cleanup rtn for exit() */
exit(main(argc, argv)); /* Call user program, return value! */
}
/*
* parser for EXEC-style command lines. takes a string of the form
* "<command>[<space><text>]<CRLF>" and breaks it into one or two
* parts. if argc=1, then there's just a command. if argc=2, then
* there a command plus an arg. argv[0] points to the start of the
* command, argv[1] points to the start of the arg (maybe). both
* skip initial whitespace and null-terminate their parts in place
* in the string buffer.
*
* also, that CRLF might just be a CR, or maube just an LF. be
* sure and handle all cases.
*/
static int exec_parse(p)
char *p;
{
int c;
char *original_p;
while ((c = *p) == ' ' || c == '\t')
p++; /* skip leading whitespace */
original_p = p; /* save this to see if it changes */
while (c && c != ' ' && c != '\t' && c != '\r' && c != '\n')
c = *++p; /* skip text of command, if any */
if (p == original_p) return; /* oops, nothing really there. */
*p = '\0'; /* tie off command. */
arg_set(original_p); /* save start of command */
if (c != ' ' && c != '\t') return 1;/* if not a space, no arg. */
while ((c = *++p) == ' ' || c == '\t')
; /* else, skip whitespace b4 arg. */
if (c == '\r' || c == '\n') /* if lots of blankspace but no */
return; /* real arg, then so be it. */
arg_set(p); /* else save start of arg */
while ((c = *++p) && c != '\r' && c != '\n') ;
if (c) *p = '\0'; /* skip to EOL, clobber CR or LF. */
return;
}
/*
* unix-style shell parser.
*/
static int shell_parse(p)
char *p;
{
int pipes[2], i, done, wild, n, tmpf, append;
char *argbuf, *in, *out;
pipes[IN] = pipes[OUT] = 0; /* no redirection to program */
in = out = NULL; /* no redirection to file */
append = 0; /* no append for stdout redirect */
/*
* 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.
*/
done = wild = FALSE; /* not done yet */
while (!done) switch (*p) { /* while not done... */
/*
* these characters are totally ignored
*/
case ' ':
case '\t': /* space or tab */
#if SYS_WAITS /* or semicolon for WAITS */
case ';':
#endif
p++; /* are merely ignored */
break;
/*
* these characters end the command line
*/
case '\0':
case '\r':
case '\n': /* null, return, and linefeed */
#if SYS_T20+SYS_10X /* and comment chars on TOPS-20 */
case ';':
#endif
done = TRUE; /* end of line, stop making args */
break;
/*
* on T20, a special imbedded comment is like ! ... !, everything
* from the first ! to the second is skipped over.
*/
#if SYS_T20+SYS_10X /* and comment chars on TOPS-20 */
case '!':
while (*++p != '!' && *p) ;
if (!*p) done = TRUE;
break;
#endif
/*
* vertical bar is piping. output goes to the program which comes
* next on the command line.
*/
case '|': /* vertical bracket (pipe fitting)? */
#if SYS_T20
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 1 /* New method using forkexec */
{
struct frkxec f;
char *av[3]; /* Temporary argv array */
av[0] = out; /* Arg 0 is prog name */
av[1] = p; /* Rest is remaining JCL */
av[2] = NULL;
f.fx_flags = FX_PGMSRCH | FX_FDMAP;
f.fx_name = out; /* Program name to run */
f.fx_argv = &av[0];
f.fx_envp = NULL;
f.fx_fdin = pipes[IN]; /* Map fork's input to this */
f.fx_fdout = -1; /* Leave output alone */
if (forkexec(&f) < 0)
abortmsg("?Couldn't get next program in pipe");
/*
* Special hack: forget about pipe's input UFX so we don't accidentally
* close it; there is no mechanism for sharing FD-use count
* between forks! Sigh. If there was, we could just
* dispense with the following two statements.
*/
_uionopen[_uioufx[pipes[IN]]] = 0; /* Can re-use UFX */
_uioufx[pipes[IN]] = 0; /* Quietly forget pipe-input UFX */
}
#else /* Old method using vfork, execlp */
/*
* The vfork call is tricky, because the page map is shared.
* For T20 the call doesn't return to parent fork until
* an exec() is done, and we depend on this to avoid clobbering
* various stuff in the child (like the UIO tables!) before
* it maps in a different program.
*/
tmpf = dup(STDIN_CH); /* Save copy of std input for parent*/
dup2(pipes[IN], STDIN_CH); /* Make stdin input be from pipe */
close(pipes[IN]); /* Then flush old pipe FD slot */
if (!vfork()) { /* make new program: */
execlp(out, out, p, 0); /* run piped program, this will
** take std input from pipe!
*/
abortmsg("?Couldn't get next program in pipe");
}
/*
* Special hack: forget about pipe's input UFX so we don't accidentally
* close it; there is no mechanism for sharing FD-use count
* between forks! Sigh. If there was, we could just
* dispense with the following two statements.
*/
_uionopen[_uioufx[STDIN_CH]] = 0; /* Can re-use UFX */
_uioufx[STDIN_CH] = 0; /* Quietly forget pipe-input UFX */
dup2(tmpf, STDIN_CH); /* Restore original setting of STDIN */
close(tmpf); /* and flush temporary FD slot */
#endif /* End of old method */
done = TRUE; /* remaining JCL went to daughter */
#else
abortmsg("?Pipes not supported on this system");
#endif
break;
/*
* greater-than redirects output to a file
*/
case '>': /* output redirection? */
p++; /* skip close bracket */
if (*p == '>') { /* another one, for append? */
++append; /* Yep, set flag */
++p; /* and skip over the 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
/*
* an ampersand means run in the background. this is implemented
* with the usual EXEC PRARG% hack, which if you don't have, you
* should. it always allows a fork to request being reset, or to
* kept.
*/
case '&':
if (procamper() == -1) /* tell exec we need '&' action */
abortmsg("Couldn't continue ourselves in background");
done = TRUE; /* we shouldn't have anything after this */
break; /* return running in background */
#endif /* TOPS20 */
/*
* less-than meant take redirect the following file to primary input.
* take care not to confuse "foo <dir>name" with a redirection request!
*/
case '<':
#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)) */
/*
* other characters. check for special quoting. Note:
* Can DROP THROUGH to default processing!
*/
default: /* not special char, normal arg */
if (*p == '"' || *p == '\'') {
arg_set(p + 1); /* copy pointer to it past quote */
wild = TRUE; /* nonzero means no check for wild */
} else
arg_set(p); /* copy pointer to it */
p = getstr(p); /* skip over it in args */
/*
* watch out for EXEC stupidness! make sure we don't have
* EXEC key at JCL start
*/
#if SYS_ITS==0
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 (strrchr(argv[argc-1],'*') || strrchr(argv[argc-1],'%')) {
argc--; /* backup to prev. arg. */
if ((wild = _openw(argv[argc])) < 0) /* open wild */
abortmsg("?No match");
do
arg_set(_namew(wild)); /* get new name */
while (_nextw(wild));
wild = FALSE; /* reset in case another wild */
}
#endif /* T20+10X */
} /* end while () switch () */
if (pipes[OUT]) { /* If we are piping output, */
dup2(pipes[OUT], STDOUT_CH); /* redirect output to pipe. */
close(pipes[OUT]); /* And flush this FD now */
out = NULL; /* And don't try sending to file. */
}
if (in) /* If desired, */
setfil(in, STDIN_CH, 0); /* redirect stdin to file */
if (out) /* and ditto for stdout */
setfil(out, STDOUT_CH, append);
}
/*
* add an arg to the argv array, bumping argc. if argv becomes
* full, then expand it.
*/
static char *lastsbrk = 0; /* Last return value from sbrk */
static void arg_set(p)
char *p;
{
int i, new_size; /* new size, if need to expand */
char **newv; /* New array pointer, if ditto */
if (argc >= argv_size) { /* need to expand? */
new_size = argv_size + MAX_ARG; /* increase by this much each time */
if (lastsbrk == sbrk(0)) { /* Can we just expand it? */
WALIGN_sbrk(MAX_ARG * sizeof(char *)); /* Yes, do so */
}
else { /* No, must get new array, and copy old into it. */
newv = (char **)WALIGN_sbrk(new_size * sizeof(char *));
memcpy((char *)newv, (char *)argv, argv_size*sizeof(char *));
argv = newv;
}
argv_size = new_size; /* new max # of args */
lastsbrk = sbrk(0); /* New value of last break */
}
argv[argc++] = p; /* set this arg. */
}
/* ------------------------------- */
/* get a string from JCL */
/* ------------------------------- */
static char *getstr(p)
char *p;
{
int 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 (toupper(*s) == *t++)
if (!*s++) return TRUE;
return FALSE;
}
/****************** System-Dependent Routines ****************************/
#if 0
The system-dependent portion of URT should provide the
following routines:
init_uio() - Initialize I/O at startup
_getjcl(buf) - Read JCL to program
setfil(str, fd, appf) - Redirect FD to given file (append if appf set)
tty_set() - Init TTY at startup; register reset rtn for exit.
abortmsg() - Print message and halt
#endif
#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
*/
/* ------------------------------------------------------------------- */
/* 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 */
}
}
}
/* INIT_UIO - initialize UIO data structures.
** For now we always set FD 2 (std err) to .CTTRM, and
** and check .PRIIN and .PRIOU to set up FDs 0 and 1.
** Later we may inherit a data page from previous process.
*/
static init_uio()
{
int ifx, ofx, efx;
union {
int acs[5];
struct { int junk[2];
unsigned pin : 18; /* LH of AC 2 */
unsigned pout : 18; /* RH of AC 2 */
} res;
} a;
/* Initialize FD 2 (error output) as that is always constant */
efx = _uiofx(); /* Get a free UFX */
_uioch[efx] = _CTTRM; /* Use this JFN */
_uioflgs[efx] = _UIO_CONVERTED; /* With this extra flag */
_openufx(efx, O_RDWR);
_uioufx[STDERR_CH] = efx; /* FD 2 now open for business! */
/* See what our primary JFNs really are */
a.acs[1] = _FHSLF;
jsys(GPJFN, a.acs);
if (a.res.pin == _uioch[efx]) { /* If stdin same as stderr, */
_uioufx[STDIN_CH] = efx; /* just point there. */
_uionopen[efx]++;
} else {
ifx = _uiofx();
_uioch[ifx] = a.res.pin; /* Must set up with this JFN */
_uioflgs[ifx] = _UIO_CONVERTED; /* With this extra flag */
_openufx(ifx, O_RDONLY); /* Take care of rest of vars */
_uioufx[STDIN_CH] = ifx; /* Then make FD 0 open for business */
}
if (a.res.pout == _uioch[efx]) { /* If stdout same as stderr, */
_uioufx[STDOUT_CH] = efx; /* just point there. */
_uionopen[efx]++;
} else {
ofx = _uiofx();
_uioch[ofx] = a.res.pout; /* Must set up with this JFN */
_uioflgs[ofx] = _UIO_CONVERTED; /* With this extra flag */
_openufx(ofx, O_WRONLY); /* Take care of rest of vars */
_uioufx[STDOUT_CH] = ofx; /* Then make FD 1 open for business */
}
}
/* SETFIL - redirect a standard in/out/err file descriptor.
** Note that the STDIO streams must also be changed; a fd and a stream
** are not the same thing. For now we punt on trying to
** change the buffering or stdio flags.
*/
static setfil(name, fd, append)
char *name;
int fd, append;
{
FILE *fp;
int tmpf, flags;
if (!name) return; /* nothing to do. */
switch (fd) {
case STDIN_CH:
fp = stdin;
flags = O_RDONLY;
break;
case STDOUT_CH:
fp = stdout;
flags = (O_WRONLY | O_CREAT | O_TRUNC | (append ? O_APPEND : 0));
break;
case STDERR_CH:
fp = stderr;
flags = (O_WRONLY | O_CREAT | O_TRUNC | (append ? O_APPEND : 0));
break;
default:
abortmsg("?Bad redirection file fd");
}
if ((tmpf = open(name, flags, 0644)) < 0)
abortmsg("?Couldn't open redirection file");
dup2(tmpf, fd); /* Make temp FD be a STDxx FD */
close(tmpf); /* Then flush the temp fd */
if (flags & O_APPEND) /* If appending, */
fseek(fp, 0L, SEEK_END); /* ensure STDIO knows about it */
if (fp == stderr)
setbuf(stderr, (char *)NULL); /* No buffering for stderr */
else if (fp == stdout /* If stdout to non-TTY, */
&& _uiotype[_uioufx[fd]] != _DVTTY)
setvbuf(fp, (char *)NULL, _IOFBF, 0); /* then use full buffering */
}
/* ---------------------------------------- */
/* set terminal mode word */
/* ---------------------------------------- */
#define CCOC_MAGIC 0525252525252
static int ccoc[2];
static void tty_reset();
static tty_set()
{
int ablock[5];
ablock[1] = _CTTRM;
if (!jsys(RFCOC, ablock)) return FALSE;
ccoc[0] = ablock[2];
ccoc[1] = ablock[3]; /* save ccoc words */
if (ccoc[0] != CCOC_MAGIC
|| ccoc[1] != CCOC_MAGIC) {
ablock[2] = ablock[3] = CCOC_MAGIC;
if (!jsys(SFCOC, ablock)) return FALSE;
}
onexit(tty_reset); /* Won, register reset rtn for exit */
}
static void /* Called to reset TTY upon normal exit() */
tty_reset()
{
int ablock[5];
ablock[1] = _CTTRM;
ablock[2] = ccoc[0];
ablock[3] = ccoc[1];
jsys(SFCOC, ablock);
}
/* --------------------------------------- */
/* output error message and exit */
/* --------------------------------------- */
static abortmsg(s)
char *s;
{
char tmpbuf[1000];
int ac[5];
tty_reset();
strcat(strcpy(tmpbuf, s), "\r\n"); /* Terminate error string with CRLF */
ac[1] = (int) tmpbuf;
jsys(ESOUT, ac); /* Use ESOUT% to output it */
_exit(1); /* Then stop program with prejudice */
}
/* ------------------------------- */
/* open wild card filename */
/* ------------------------------- */
static int _openw(name)
char *name;
{
int channel;
channel = _gtjfn(name, O_RDONLY | O_T20_WILD);
return (channel == 0) ? -1 : channel; /* make sure got one */
}
/* ------------------------------- */
/* return wild card filename */
/* ------------------------------- */
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] = 0111110000001; /* DEV+DIR+NAME+TYPE+VERS, punctuate */
if (!jsys(JFNS, ablock))
return NULL; /* something bad happened */
fp = WALIGN_sbrk(strlen(fname) + 1);
strcpy(fp, fname); /* copy the file name here */
return fp;
}
/* ------------------------------- */
/* next wild card filename */
/* ------------------------------- */
static _nextw(jfn)
int jfn;
{
int ablock[5];
ablock[1] = jfn; /* save jfn and flags */
return jsys(GNJFN, ablock);
}
/* ----------------------------- */
/* return command line */
/* ----------------------------- */
static char *
_getjcl(buf)
char *buf;
{
char *cp;
int c, n;
#if SYS_10X
char tmpbuf[1000];
#endif /* SYS_10X */
#if SYS_T20
int acs[5];
if (!(n = _rscan())) return NULL; /* Rescan command line */
if (!buf) buf = WALIGN_sbrk(n + 1); /* make room for chars and null */
/* Have to gobble the RSCAN line directly since only way to access
** the rscan buffer is by using a JFN equivalent to the controlling TTY.
** If our .PRIIN has been redirected, a normal SIN or read() will not
** get the rscan stuff at all.
** TENEX is probably out of luck in this respect.
*/
acs[1] = _CTTRM;
acs[2] = (int) (buf-1);
acs[3] = -n;
jsys(SIN, acs); /* Read the stuff */
buf[n] = 0; /* null-terminate */
#endif /* SYS_T20 */
#if SYS_10X
for (cp = tmpbuf; read(STDIN_CH, cp, 1) == 1; ++cp)
if ((c = *cp) == '\037' || c == '\r' || c == '\n') {
*cp++ = '\n';
break;
}
*cp = 0;
n = strlen(tmpbuf);
buf = WALIGN_sbrk(n + 1);
strcpy(buf, tmpbuf);
#endif /* SYS_10X */
return buf;
}
#if SYS_T20
static int _rscan()
{
int arg_block[5];
arg_block[1] = _RSINI;
return (jsys(RSCAN, arg_block)) ? arg_block[1] : 0;
}
#endif /* SYS_T20 */
/*
* 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
*/
static int procamper()
{
int arg_block[5], temp_arg;
arg_block[1] = (_PRAST << 18) + _FHSLF;
temp_arg = PRA_BACK << 18;
arg_block[2] = (int) &temp_arg;
arg_block[3] = 1;
if (!jsys(PRARG, arg_block)) return -1; /* some lossage */
jsys(HALTF, arg_block); /* stop and let exec continue us */
return 0; /* return to caller in background */
}
#endif /* SYS_T20+SYS_10X */
#if SYS_WAITS
/*
** WAITS specific portions of higher-level runtimes
*/
/* ---------------------- */
/* set up files */
/* ---------------------- */
static setup(in,out)
char *in, *out;
{
_uioch[STDIN_CH] = (in != NULL) ? _uioch[open(in,0)] : STDIN_CH;
_uioch[STDOUT_CH] = (out != NULL) ? _uioch[creat(out,0)] : STDOUT_CH;
_uioch[STDERR_CH] = STDERR_CH;
_uioeof[STDIN_CH] = 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(1); /* in either case, stop program */
}
/* ----------------------------- */
/* return command line */
/* ----------------------------- */
static char *
_getjcl()
{
char *argbuf, *p;
int n;
n = _rscan(); /* Rescan command line */
argbuf = WALIGN_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 int
_rscan()
{
asm(" RESCAN 1\n"); /* Rescan cmd line, get # chars avail in 1 */
}
#endif /* SYS_WAITS */
#if SYS_ITS
/*
* Runtime stuff for ITS
*/
#include "sysits.h"
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(1);
}
static char *
_getjcl()
{
char *_rjcl();
return _rjcl();
}
/* _RJCL() - Return a char pointer to JCL */
static int jclsiz = 100; /* Start with buffer of this many wds */
static char *_rjcl()
{
#asm
.SUSET [.ROPTIO,,1]
TLNN 1,%OPCMD ; Has our superior said it has a cmd?
JRST $RETZ ; No.
PUSH 17,[0] ; Find out current break
PUSHJ 17,sbrk ; by calling low-level sbrk()
MOVEM 1,(17) ; Save result on stack
MOVE 1,jclsiz ; Start off with this many words!
.RJCL1: LSH 1,2 ; Multiply by 4 to get # bytes
PUSH 17,1 ; Get this many bytes
PUSHJ 17,sbrk ; From low-level sbrk() call.
ADJSP 17,-1 ; Remove stack arg.
CAMN 1,[-1] ; If not enough memory,
JRST [ POP 17,1 ; just return a null pointer!
JRST $RETZ]
HRRZ 2,(17) ; Get word address of block start
HRLZI 3,(2) ; Put it in LH of 3
HRRI 3,1(2) ; and addr+1 in RH
ADD 2,jclsiz ; Now in 2 get 1st addr past end
SETZM -1(3) ; Clear 1st word
BLT 3,-2(2) ; Zap all remaining words but one
SETOM -1(2) ; Set up non-zero fence at last word.
HRRZ 3,(17) ; Now get start of block again.
HRLI 3,5 ; 5 = Read JCL from superior
.BREAK 12,3 ; Try to read command string.
SKIPE -2(2) ; See if clobbered last zero word.
JRST [ MOVEI 1,100 ; Add this many more words
ADDB 1,jclsiz
JRST .RJCL1] ; and go try again!
POP 17,1 ; Won! Get ptr to beg of block.
HRLI 1,350700 ; Return 7-bit char pointer to ASCIZ.
#endasm
}
/* _VALRET() - Pass a word-aligned string to DDT.
** We have to just hope the string starts on a word boundary.
*/
static _valret(str)
char *str;
{
#asm
XMOVEI 1,@-1(17) ; We just hope it starts on wd boundary.
.VALUE (1)
#endasm
}
#endif /* ITS */