4.3BSD/usr/contrib/icon/functions/open.c
#include "../h/rt.h"
/*
* open(s1,s2) - open file s1 with specification s2.
*/
Xopen(nargs, arg2, arg1, arg0)
int nargs;
struct descrip arg2, arg1, arg0;
{
register int slen, i;
register char *s;
int status;
char sbuf1[MAXSTRING], sbuf2[MAXSTRING], mode[3];
FILE *f;
extern struct b_file *alcfile();
extern char *alcstr();
extern FILE *fopen(), *popen();
/*
* s1 must be a string and a C string copy of it is also needed.
* Make it a string if it isn't one; make a C string if s1 is
* a string.
*/
switch (cvstr(&arg1, sbuf1)) {
case 1:
sneed(STRLEN(arg1));
STRLOC(arg1) = alcstr(STRLOC(arg1), STRLEN(arg1));
break;
case 2:
qtos(&arg1, sbuf1);
break;
default:
runerr(103, &arg1);
}
/*
* s2 defaults to "r".
*/
defstr(&arg2, sbuf2, &letr);
hneed(sizeof(struct b_file));
status = 0;
/*
* Scan s2, setting appropriate bits in status. Produce a runerr
* if an unknown character is encountered.
*/
s = STRLOC(arg2);
slen = STRLEN(arg2);
for (i = 0; i < slen; i++) {
switch (*s++) {
case 'a': case 'A':
status |= FS_WRITE|FS_APPEND;
continue;
case 'b': case 'B':
status |= FS_READ|FS_WRITE;
continue;
case 'c': case 'C':
status |= FS_CREATE|FS_WRITE;
continue;
case 'p': case 'P':
status |= FS_PIPE;
continue;
case 'r': case 'R':
status |= FS_READ;
continue;
case 'w': case 'W':
status |= FS_WRITE;
continue;
default:
runerr(209, &arg2);
}
}
/*
* Construct a mode field for fopen/popen.
*/
mode[0] = '\0';
mode[1] = '\0';
mode[2] = '\0';
if ((status & (FS_READ|FS_WRITE)) == 0) /* default: read only */
status |= FS_READ;
if (status & FS_CREATE)
mode[0] = 'w';
else if (status & FS_APPEND)
mode[0] = 'a';
else if (status & FS_READ)
mode[0] = 'r';
else
mode[0] = 'w';
if ((status & (FS_READ|FS_WRITE)) == (FS_READ|FS_WRITE))
mode[1] = '+';
/*
* Open the file with fopen or popen.
*/
if (status & FS_PIPE) {
if (status != (FS_READ|FS_PIPE) && status != (FS_WRITE|FS_PIPE))
runerr(209, &arg2);
f = popen(sbuf1, mode);
}
else
f = fopen(sbuf1, mode);
/*
* Fail if the file can't be opened.
*/
if (f == NULL)
fail();
/*
* If the file isn't a terminal and a buffer is available, assign
* it to the file.
*/
if (!isatty(fileno(f))) {
for (i = 0; i < numbufs; i++)
if (bufused[i] == NULL)
break;
if (i < numbufs) { /* Use buffer if any free. */
setbuf(f, bufs[i]);
bufused[i] = f;
}
else
setbuf(f, NULL);
}
else
setbuf(f, NULL);
/*
* Return the resulting file value.
*/
arg0.type = D_FILE;
BLKLOC(arg0) = (union block *) alcfile(f, status, &arg1);
}
Procblock(open,2)