|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 12272 (0x2ff0)
Types: TextFile
Notes: UNIX file
Names: »sed2.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/sed/sed2.c«
/*
* A stream editor.
* Compiler.
*/
#include <stdio.h>
#include <ctype.h>
#include "sed.h"
FIL *codefil();
char *codetrn();
LAB *codelab();
char *duplstr();
SUB *codesub();
/*
* Compile a file of commands.
*/
compfil(name)
char *name;
{
register FILE *fp;
register int c;
register char *cp;
if ((fp=fopen(name, "r")) == NULL) {
fprintf(stderr, "Cannot open %s\n", name);
exit(1);
}
cp = linebuf;
while ((c=getc(fp)) != EOF) {
if (cp >= &linebuf[LHPSIZE-2]) {
printc("Line too long");
cp = linebuf;
while ((c=getc(fp))!='\n' && c!=EOF)
;
if (c == EOF)
break;
}
if (c == '\n') {
*cp = '\0';
ncp = linebuf;
compcom();
cp = linebuf;
continue;
}
if (c == '\\') {
if ((c=getc(fp))!='\n' && c!='\\') {
ungetc(c, fp);
c = '\\';
}
}
*cp++ = c;
}
if (cp != linebuf) {
*cp++ = '\0';
ncp = linebuf;
compcom();
}
}
/*
* Compile a string.
*/
compstr(cp)
register char *cp;
{
register int c;
register char *lp;
do {
lp = linebuf;
while ((c=*cp++)!='\0' && c!='\n')
*lp++ = c;
*lp = '\0';
ncp = linebuf;
compcom();
} while (c != '\0');
}
/*
* Compile a command and return a pointer to the compiled
* structure.
*/
compcom()
{
QCL *qp;
int nadd;
register COM *cp;
register LAB *lp;
register int c;
lno++;
while (isascii(c=getn()) && isspace(c))
;
if (c == '\0')
return;
ungetn(c);
cp = (COM *)salloc(sizeof (COM));
if (getaddr(&cp->c_a[0]) == 0)
goto err;
nadd = addnone ? 0 : 1;
if ((c=getn()) == ',') {
if (addnone!=0 || getaddr(&cp->c_a[1])==0 || addnone!=0)
goto err;
c = getn();
nadd++;
}
while (isascii(c) && isspace(c))
c = getn();
if (c == '!') {
cp->c_notf = 1;
c = getn();
} else
cp->c_notf = 0;
cp->c_name = c;
cp->c_nadd = nadd;
switch (c) {
case '{':
qp = (QCL *)salloc(sizeof (QCL));
qp->q_next = qcbp;
qcbp = qp;
qp->q_comp = cp;
if ((c=getn()) != '\0') {
*compp = cp;
compp = &cp->c_next;
ungetn(c);
compcom();
return;
}
break;
case '}':
if ((qp=qcbp) == NULL) {
printc("Too many `}'");
goto err;
}
qcbp = qcbp->q_next;
if (codenwl() == 0)
goto err;
qp->q_comp->c_p.p_com = qp->q_comp->c_next;
qp->q_comp->c_next = cp;
free(qp);
break;
case '=':
if (codenwl() == 0)
goto err;
break;
case ':':
if ((lp=codelab()) == NULL)
goto err;
if (lp->l_comp != NULL) {
printc("Label %s multiply defined", pattbuf);
goto err;
}
lp->l_comp = cp;
break;
case 'a':
if (nadd > 1)
goto adr;
if (getn() != '\n')
goto syn;
if (codelin() == 0)
goto err;
cp->c_p.p_buf = duplstr(pattbuf);
if (cp->c_a[0].a_lno == 0+1) {
cp->c_name = 'i';
cp->c_a[0].a_lno = 1+1;
}
break;
case 'b':
if ((lp=codelab()) == NULL)
goto err;
cp->c_p.p_lab = lp;
lp->l_refc++;
break;
case 'c':
if (getn() != '\n')
goto syn;
if (codelin() == 0)
goto err;
cp->c_p.p_buf = duplstr(pattbuf);
break;
case 'd':
case 'D':
case 'g':
case 'G':
case 'h':
case 'H':
if (codenwl() == 0)
goto err;
break;
case 'i':
if (nadd > 1)
goto adr;
if (getn() != '\n')
goto syn;
if (codelin() == 0)
goto err;
cp->c_p.p_buf = duplstr(pattbuf);
break;
case 'l':
case 'n':
case 'N':
case 'p':
case 'P':
if (codenwl() == 0)
goto err;
break;
case 'q':
if (nadd > 1)
goto adr;
if (codenwl() == 0)
goto err;
break;
case 'r':
if (nadd > 1)
goto adr;
if (codelin() == 0)
goto err;
if (pattbuf[0] != ' ')
goto err;
cp->c_p.p_buf = duplstr(&pattbuf[1]);
break;
case 's':
if ((cp->c_p.p_sub=codesub()) == NULL)
goto err;
break;
case 't':
if ((lp=codelab()) == NULL)
goto err;
cp->c_p.p_lab = lp;
lp->l_refc++;
break;
case 'w':
if ((cp->c_p.p_fil=codefil()) == NULL)
goto err;
break;
case 'x':
if (codenwl() == 0)
goto err;
break;
case 'y':
if ((cp->c_p.p_buf=codetrn()) == NULL)
goto err;
break;
default:
printc("Bad command");
goto err;
}
*compp = cp;
compp = &cp->c_next;
return;
syn:
printc("Syntax error");
free(cp);
return;
adr:
printc("Bad address");
err:
free(cp);
}
/*
* Read a line address and compile it into the given address
* pointer.
*/
getaddr(ap)
register ADD *ap;
{
register int c, n;
addnone = 0;
if ((c=getn()) == '/') {
if (compile('/') == 0)
return (0);
ap->a_lno = 0;
ap->a_pat = duplstr(pattbuf);
return (1);
}
if (c == '$') {
ap->a_lno = HUGE;
return (1);
}
if (isascii(c) && isdigit(c)) {
n = 0;
do {
n = n*10 + c-'0';
} while (isascii(c=getn()) && isdigit(c));
ungetn(c);
ap->a_lno = n+1;
return (1);
}
ungetn(c);
addnone = 1;
return (1);
}
/*
* There shouldn't be any more input left.
*/
codenwl()
{
if (getn() != '\0') {
printc("Syntax error");
return (0);
}
return (1);
}
/*
* Parse a label, put it into the label table and return
* a pointer to the entry.
*/
LAB *
codelab()
{
char name[LNMSIZE];
register LAB *lp;
register int c;
register char *np;
while (isascii(c=getn()) && isspace(c))
;
np = name;
while (c != '\0') {
if (np < &name[LNMSIZE-1])
*np++ = c;
c = getn();
}
*np = '\0';
for (lp=labp; lp; lp=lp->l_next) {
if (strcmp(lp->l_name, name) == 0)
return (lp);
}
lp = (LAB *)salloc(sizeof (LAB));
lp->l_next = labp;
labp = lp;
strcpy(lp->l_name, name);
lp->l_comp = NULL;
lp->l_refc = 0;
return (lp);
}
/*
* Parse a file name that will be used to write on and set it
* up in our write table.
*/
FIL *
codefil()
{
char name[FNMSIZE];
register FIL *fp;
register int c;
register char *np;
while (isascii(c=getn()) && isspace(c))
;
np = name;
while (c != '\0') {
if (np >= &name[FNMSIZE-1]) {
printc("Line buffer overflow");
return (NULL);
}
*np++ = c;
c = getn();
}
*np = '\0';
for (fp=filp; fp; fp=fp->f_next) {
if (strcmp(fp->f_name, name) == 0)
return (fp);
}
fp = (FIL *)salloc(sizeof (FIL));
fp->f_next = filp;
filp = fp;
strcpy(fp->f_name, name);
fp->f_filp = NULL;
return (fp);
}
/*
* Get a line of text for commands such as the append.
*/
codelin()
{
register int c;
register char *pp;
pp = pattbuf;
while ((c=getn()) != '\0') {
if (pp >= &pattbuf[LHPSIZE-1]) {
printc("Line buffer overflow");
return (0);
}
*pp++ = c;
}
*pp = '\0';
return (1);
}
/*
* Compile the substitute command.
*/
SUB *
codesub()
{
int nth, ec;
register SUB *sp;
register int c;
register char *pp;
nth = 1;
if (isascii(c=getn()) && isdigit(c)) {
nth = 0;
while (isascii(c) && isdigit(c)) {
nth = nth*10 + c-'0';
c = getn();
}
}
if ((ec=c) == '\n') {
ungetn(c);
printc("Syntax error");
return (NULL);
}
if (compile(ec) == 0)
return (NULL);
pp = holdbuf;
while ((c=getn()) != ec) {
if (pp >= &holdbuf[LHPSIZE-4]) {
printc("Pattern buffer overflow");
return (NULL);
}
switch (c) {
case '\0':
ungetn(c);
printc("Syntax error");
return (NULL);
case '&':
*pp++ = '\\';
*pp++ = '0';
continue;
case '\\':
if ((c=getn()) == '\\') {
*pp++ = '\\';
*pp++ = '\\';
continue;
}
if (c >= '1' && c <= '9') {
*pp++ = '\\';
*pp++ = c;
continue;
}
default:
*pp++ = c;
continue;
}
}
*pp++ = '\0';
sp = (SUB *)salloc(sizeof (SUB));
sp->s_pat = duplstr(pattbuf);
sp->s_rep = duplstr(holdbuf);
sp->s_nth = nth;
sp->s_cop = 0;
sp->s_fil = NULL;
while ((c=getn()) != '\0') {
switch (c) {
case 'g':
sp->s_nth = 0;
continue;
case 'p':
sp->s_cop = 1;
continue;
case 'w':
sp->s_fil = codefil();
continue;
default:
printc("Bad flag in substitute");
free(sp->s_pat);
free(sp->s_rep);
free(sp);
return (NULL);
}
}
return (sp);
}
/*
* Compile a regular expression. `ec' is the character upon which
* the regular expression ends. If an error is encountered, the
* pattern is cleared and input characters are thrown away until
* a new line is found.
*/
compile(ec)
{
int bstack[NBRC], bcount, blevel, n;
register int c;
register char *pp, *lpp;
bcount = 1;
blevel = 0;
pp = &pattbuf[0];
if ((c=getn()) == ec) {
if (*pp == CSNUL) {
printc("No saved pattern");
goto err;
}
return (1);
}
if (c == '^') {
*pp++ = CSSOL;
c = getn();
}
while (c != ec) {
if (pp > &pattbuf[LHPSIZE-4])
goto ovf;
switch (c) {
case '\0':
case '.':
if ((c=getn()) != '*') {
*pp++ = CSDOT;
continue;
}
*pp++ = CMDOT;
c = getn();
continue;
case '$':
if ((c=getn()) != ec) {
ungetn(c);
c = '$';
goto character;
}
*pp++ = CSEOL;
continue;
case '[':
lpp = pp;
if ((c=getn()) == '^')
*pp++ = CSNCL;
else {
ungetn(c);
*pp++ = CSCCL;
}
*pp++ = 0;
if ((c=getn()) == ']')
*pp++ = c;
else
ungetn(c);
while ((c=getn()) != ']') {
if (c == '\n')
goto nwl;
if (c!='-' || pp==lpp+2) {
if (pp >= &pattbuf[LHPSIZE-4])
goto ovf;
*pp++ = c;
if (sflag && isascii(c) && isallet(c))
*pp++ = toother(c);
continue;
}
if ((c=getn()) == '\n')
goto nwl;
if (c == ']') {
*pp++ = '-';
ungetn(c);
continue;
}
if ((n=pp[-1]) > c)
goto syn;
while (++n <= c) {
if (pp >= &pattbuf[LHPSIZE-4])
goto ovf;
*pp++ = n;
if (sflag && isascii(c) && isallet(c))
*pp++ = toother(c);
}
}
if ((c=getn()) == '*') {
(*lpp)++;
c = getn();
}
if ((n=pp-(lpp+2)) > 255) {
printc("Character class too large");
goto err;
}
*++lpp = n;
continue;
case '\\':
switch (c=getn()) {
case '\n':
goto nwl;
case '(':
if (bcount > NBRC) {
printc("Too many \\(");
goto err;
}
*pp++ = CSOPR;
*pp++ = bstack[blevel++] = bcount++;
c = getn();
continue;
case ')':
if (blevel == 0)
goto syn;
*pp++ = CSCPR;
*pp++ = bstack[--blevel];
c = getn();
continue;
case 'n':
c = '\n';
goto character;
default:
if (isascii(c) && isdigit(c)) {
*pp++ = CSBRN;
*pp++ = c-'0';
c = getn();
continue;
}
}
case '*':
default:
character:
if (sflag && isascii(c) && isallet(c)) {
*pp++ = CSSCC;
if (isupper(c))
c = tolower(c);
} else
*pp++ = CSCHR;
*pp++ = c;
if ((c=getn()) == '*') {
pp[-2]++;
c = getn();
}
}
}
*pp++ = CSNUL;
return (1);
ovf:
printc("Pattern buffer overflow");
pattbuf[0] = CSNUL;
return (0);
nwl:
ungetn(c);
syn:
printc("Syntax error");
err:
pattbuf[0] = CSNUL;
return (0);
}
/*
* Compile the translate command.
*/
char *
codetrn()
{
int ec;
char *trnp;
register int c, n;
register char *bp;
trnp = salloc(256);
bp = trnp;
for (n=0; n<256; n++)
*bp++ = n;
if ((ec=getn()) == '\0') {
printc("Syntax error");
return (NULL);
}
bp = pattbuf;
while ((c=getn()) != ec) {
if (c == '\0') {
printc("Syntax error");
return (NULL);
}
if (bp >= &pattbuf[LHPSIZE-1]) {
printc("Code buffer overflow");
return (NULL);
}
*bp++ = c&0377;
}
bp = pattbuf;
while ((c=getn()) != ec) {
if (c == '\0') {
printc("Syntax error");
return (NULL);
}
if (*bp == '\0') {
printc("Right part of translate too long");
return (NULL);
}
trnp[*bp++] = c;
}
return (trnp);
}
/*
* Given a string, return a pointer to a copy of it.
*/
char *
duplstr(sp0)
register char *sp0;
{
register char *sp1, *sp2;
sp1 = sp0;
while (*sp1++)
;
sp2 = salloc(sp1-sp0);
sp1 = sp2;
while (*sp1++=*sp0++)
;
return (sp2);
}
/*
* Get a character.
*/
getn()
{
register int c;
if ((c=*ncp++) == '\0')
--ncp;
return (c);
}
/*
* Unget a character.
*/
ungetn(c)
{
if (*ncp!='\0' || c!='\0')
*--ncp = c;
}
/*
* Go through the command list fixing up labels and files.
*/
load()
{
register LAB *lp;
register FIL *fp;
*compp = NULL;
if (qcbp != NULL)
printc("Missing `}'");
for (lp=labp; lp; lp=lp->l_next) {
if (lp->l_comp == NULL)
printc("Undefined label %s", lp->l_name);
}
for (fp=filp; fp; fp=fp->f_next) {
if (fp->f_filp == NULL)
if ((fp->f_filp=fopen(fp->f_name, "w")) == NULL)
printc("Cannot open %s", fp->f_name);
}
}
/*
* Print out a compile error message.
*/
printc(s)
{
nerr++;
fprintf(stderr, "%d: %r", lno, &s);
putc('\n', stderr);
}