|
|
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: 15465 (0x3c69)
Types: TextFile
Notes: UNIX file
Names: »ed1.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/ed/ed1.c«
/*
* An editor.
* Main, command parser and general routines.
*/
#include <stdio.h>
#if COHERENT
#include <signal.h>
#endif
#include <ctype.h>
#include "ed.h"
main(argc, argv)
register char *argv[];
{
extern int sigintr(), sighang();
#if COHERENT
register char *cp;
#endif
initialise();
#if COHERENT
if ((cp=getenv("ED")) != NULL)
setoptf(cp);
signal(SIGHUP, sighang);
signal(SIGINT, sigintr);
signal(SIGQUIT, sigintr);
#endif
setup(argc, argv);
for (;;) {
if (intflag) {
/*
finit(stdout);
clearerr(stdin);
clearerr(stdout);
clearerr(stderr);
*/
savechr = '\0';
intflag = 0;
derror("Interrupt");
}
command();
}
}
/*
* Initialisation.
*/
initialise()
{
register int i;
register char *bp;
#if COHERENT
extern char *mktemp();
register char *np;
#endif
if ((bp=malloc(BUFSIZ)) != NULL)
setbuf(stdout, bp);
#if RSX
if ((tmp=fopen("edtmp", "r+w")) == NULL) {
#else
np = mktemp("/tmp/edxxxxxx");
tfn = np;
if ((tmp=fopen(np, "w")) == NULL) {
terror("Cannot create temp file");
return;
}
if ((tmp=freopen(np, "r+w", tmp)) == NULL) {
#endif
terror("Cannot open temp file");
return;
}
#if COHERENT
chmod(tfn, 0);
#endif
#if RSX
fmkdl(tmp);
qio(001400, stdin->v_lun, 1, NULL, NULL);
wtse(1);
#endif
mflag = 0;
oflag = 0;
pflag = 0;
sflag = 0;
tflag = 0;
vflag = 0;
cflag = 1;
intflag = 0;
tmpseek = CLSIZE;
rcurbno = -1;
wcurbno = -1;
lnsize = LNSIZE;
if ((line=(LINE *)malloc(lnsize * sizeof(LINE))) == NULL) {
prints(stderr, "Cannot allocate line number table\n");
exit(1);
}
savechr = '\0';
lastchr = '\n';
gcp = NULL;
codebuf[0] = CSNUL;
file[0] = '\0';
for (i=0; i<MKSIZE; i++)
marklin[i] = 0;
dotadd = 0;
doladd = 0;
saved = 1;
subseek = 0;
keyp = NULL;
}
/*
* Process command line arguments.
*/
setup(argc, argv)
char *argv[];
{
register char *cp;
register int i;
register int f;
f = 0;
for (i=1; i<argc; i++) {
cp = argv[i];
switch (*cp++) {
case '-':
switch (*cp++) {
case '\0':
cflag = 0;
continue;
case 't':
tflag = 1;
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
continue;
case 'u':
setbuf(stdout, NULL);
continue;
case 'x':
setkey();
continue;
default:
usage();
}
case '+':
setoptf(argv[i]);
continue;
default:
if (f++ != 0)
usage();
if (strlen(argv[i]) > FNSIZE)
derror("File name too long");
else {
strcpy(file, argv[i]);
edit();
}
}
}
}
/*
* Print out a usage message.
*/
usage()
{
prints(stderr, "Usage: ed [-[x]] [+cmopsv] [file]\n");
exit(1);
}
#if COHERENT
/*
* Set a flag indicating that interrupt has been hit.
* Used for SIGQUIT and SIGINT.
*/
sigintr(s)
{
intflag++;
signal(s, sigintr);
}
/*
* If we get a hangup signal, write the file onto the file
* `ed.hup' and leave.
*/
sighang()
{
if (doladd != 0)
wfile(1, doladd, "ed.hup", "w", 1);
leave();
}
#endif
/*
* Leave the editor.
*/
leave()
{
unlink(tfn);
exit(0);
}
/*
* Process a command.
*/
command()
{
extern int sigintr();
int c1, n, a3;
char name[FNSIZE+1];
register int a1, a2, c;
for (;;) {
addspec = 0;
a1 = a2 = getaddr();
if (intflag)
return (0);
if (adderrr)
goto err;
c = getx();
if (addspec != 0) {
while (c==',' || c==';') {
a1 = a2;
if (c == ';')
dotadd = a1;
a2 = getaddr();
if (adderrr)
goto err;
if (addspec == 0) {
derror("Missing address");
goto err;
}
c = getx();
}
}
if (c == '*') {
if (addspec++ == 0) {
a1 = 1;
addspec++;
}
a2 = doladd;
c = getx();
}
switch (c) {
case EOF:
if (intflag == 0) {
if (saved != 0)
leave();
saved = 1;
derror("File not saved");
}
return;
case '\n':
if (addques) {
if (errstr) {
prints(stdout, errstr);
printc(stdout, '\n');
}
return (0);
}
if (addpage) {
a1 = a2;
a2 = a1 + PGSIZE;
if (a2 > doladd)
a2 = doladd;
if (print(a1, a2) == 0)
return (0);
return (1);
}
if (addspec == 0)
a2 = dotadd+1;
if (print(a2, a2) == 0)
return (0);
return (1);
case '!':
if (rest() == 0)
goto err;
n = system(tempbuf);
if (n < 0) {
derror("Call failed");
return (0);
} else {
prints(stdout, "!\n");
return (1);
}
case '=':
if (verify(0) == 0)
goto err;
if (addspec == 0)
a2 = doladd;
printd(stdout, a2);
printc(stdout, '\n');
break;
case 'a':
if (verify(1) == 0)
goto err;
getx();
if (append(a2, readtty) == 0)
return (0);
ungetx('\n');
break;
case 'c':
if (verify(1) == 0)
goto err;
getx();
if (delete(a1, a2) == 0)
return (0);
if (append(a1-1, readtty) == 0)
return (0);
ungetx('\n');
break;
case 'd':
if (verify(0) == 0)
goto err;
if (delete(a1, a2) == 0)
goto err;
break;
case 'e':
n = saved;
if (getfile(n?file:name) == 0)
return (0);
if (n == 0) {
saved = 1;
derror("File not saved");
return (0);
}
return (edit());
case 'E':
if (getfile(file) == 0)
return (0);
return (edit());
case 'f':
if ((c=getx()) == ' ') {
ungetx(' ');
getfile(file);
c = '\n';
}
if (c != '\n') {
derror("Bad command");
goto err;
}
if (file[0] != '\0') {
prints(stdout, file);
printc(stdout, '\n');
}
return (1);
case 'g':
if (addspec == 0) {
a1 = 1;
a2 = doladd;
}
if (global(a1, a2, 0) == 0)
goto err;
if (verify(1) == 0)
goto err;
break;
case 'i':
if (verify(1) == 0)
goto err;
getx();
if (doladd==0 && a2==0)
a2 = 1;
if (append(a2-1, readtty) == 0)
return (0);
ungetx('\n');
break;
case 'j':
if (addspec < 2)
a2 = a1+1;
if (verify(0) == 0)
goto err;
if (join(a1, a2) == 0)
goto err;
break;
case 'k':
if ((c=getx()) == '\n') {
derror("No mark name specified");
return (0);
}
if (verify(0) == 0)
goto err;
if (a2<1 || a2>doladd) {
derror("Illegal address range");
goto err;
}
if (!isascii(c) || !islower(c)) {
derror("Bad mark name");
goto err;
}
marklin[c-'a'] = line[a2]|1;
break;
case 'l':
if (verify(0) == 0)
goto err;
if (list(a1, a2) == 0)
goto err;
break;
case 'm':
a3 = getaddr();
if (adderrr)
goto err;
if (verify(0) == 0)
goto err;
if (move(a1, a2, a3) == 0)
goto err;
break;
case 'o':
if (rest() == 0)
goto err;
if (tempbuf[0] == '\0')
disoptf();
else
setoptf(tempbuf);
return (1);
case 'p':
case 'P':
if (verify(0) == 0)
goto err;
if (print(a1, a2) == 0)
goto err;
break;
case 'q':
if (verify(1) == 0)
goto err;
if (addspec != 0) {
derror("Cannot specify address");
goto err;
}
if (saved == 0) {
saved = 1;
derror("File not saved");
goto err;
}
leave();
case 'Q':
if (verify(1) == 0)
goto err;
leave();
case 'r':
if (getfile(name) == 0)
return (0);
if (addspec == 0)
a2 = doladd;
if ((fp=xfopen(name, "r")) == NULL) {
derror("Cannot open file");
return (0);
}
n = 1;
if (append(a2, readfil) == 0)
n = 0;
else if (ferror(fp)) {
derror("Read error");
n = 0;
}
fclose(fp);
if (cflag != 0) {
printl(stdout, !oflag ? cct : lct);
printc(stdout, '\n');
}
return (n);
case 's':
if (subs1(a1, a2) == 0)
goto err;
if (verify(0) == 0)
goto err;
if (subs2(a1, a2) == 0)
goto err;
break;
case 't':
a3 = getaddr();
if (adderrr)
goto err;
if (verify(0) == 0)
goto err;
if (copy(a1, a2, a3) == 0)
goto err;
break;
case 'u':
if (verify(0) == 0)
goto err;
if (a2<1 || a2>doladd) {
derror("Illegal address range");
goto err;
}
if ((line[a2]|1) != subseek) {
derror("Cannot undo substitute");
goto err;
}
line[a2] = suborig;
subseek = 0;
break;
case 'v':
if (addspec == 0) {
a1 = 1;
a2 = doladd;
}
if (global(a1, a2, 1) == 0)
goto err;
if (verify(1) == 0)
goto err;
break;
case 'w':
case 'W':
if ((c1=getx()) != 'q')
ungetx(c1);
if (getfile(name) == 0)
return (0);
if (addspec == 0) {
a1 = 1;
a2 = doladd;
}
if (c=='W' && keyp!=NULL) {
derror("Cannot append in encryption mode");
goto err;
}
if (wfile(a1, a2, name, c=='w'?"w":"a", 0) && c1=='q')
leave();
return (1);
case 'x':
if (verify(1) == 0)
goto err;
if (setkey() == 0)
goto err;
break;
default:
derror("Bad command");
err:
while ((c=getx())!=EOF && c!='\n')
;
return (0);
}
if (intflag)
return (0);
switch (vcom) {
case 'l':
list(dotadd, dotadd);
break;
case 'p':
print(dotadd, dotadd);
break;
}
if ((c=getx()) == '\n')
return (1);
if (mflag == 0) {
derror("Internal error");
goto err;
}
ungetx(c);
}
}
/*
* Get an address.
*/
getaddr()
{
LINE seek;
int absolute, abs, sign;
register int a, c, n;
adderrr = 0;
addpage = 0;
addques = 0;
absolute = 0;
abs = 1;
sign = 0;
a = dotadd;
for (;;) {
switch (c=getx()) {
case '.':
n = dotadd;
abs = 1;
break;
case '$':
n = doladd;
abs = 1;
break;
case '&':
if (sign == 0) {
addpage++;
continue;
}
n = PGSIZE;
abs = 0;
break;
case '\'':
if (!isascii(c=getx()) || !islower(c)) {
derror("Bad mark name");
adderrr++;
return (0);
}
seek = marklin[c-'a'];
for (n=1; n<=doladd; n++) {
if ((line[n]|1) == seek) {
abs = 0;
goto number;
}
}
derror("Mark value not initialised");
adderrr++;
return (0);
case '+':
sign++;
continue;
case '^':
case '-':
--sign;
continue;
case '?':
c = getx();
ungetx(c);
if (c == '\n') {
addques++;
return (0);
}
c = '?';
case '/':
if (compile(c) == 0) {
adderrr++;
return (0);
}
if (a<1 || a>doladd) {
derror("Bad initial address");
adderrr++;
return (0);
}
n = a;
abs = 1;
do {
if (intflag)
return;
if (c == '?') {
if (--n < 1)
n = doladd;
} else {
if (++n > doladd)
n = 1;
}
if (n == a) {
if (execute(n))
break;
derror("Search failed");
adderrr++;
return (0);
}
} while (execute(n) == 0);
break;
default:
if (isascii(c) && isdigit(c)) {
n = 0;
do
n = n*10 + c-'0';
while (isascii(c=getx()) && isdigit(c));
ungetx(c);
abs = 0;
break;
}
ungetx(c);
if (sign) {
a += sign;
addspec++;
}
return (a);
}
number:
if (sign == 0) {
a = n;
absolute = abs;
} else {
if ((absolute+=abs) > 1) {
derror("Relocation address error");
adderrr++;
return (0);
}
a += sign>0 ? n : -n;
sign = 0;
}
addspec++;
}
}
/*
* Get a character.
*/
getx()
{
register int c;
if (intflag != 0)
return (EOF);
if (savechr != '\0') {
c = savechr;
savechr = '\0';
return (c);
}
if (gcp == NULL) {
if (lastchr=='\n' && appflag==0) {
if (pflag != 0) {
printc(stderr, '*');
fflush(stderr);
}
if (tflag != 0) {
printc(stdout, '\000');
printc(stdout, '\027');
fflush(stdout);
}
}
return (lastchr=getchar());
}
if ((c=*gcp++) != '\0')
return (c);
--gcp;
return (EOF);
}
/*
* Put back a character.
*/
ungetx(c)
{
savechr = c;
}
/*
* Given a line number, `a', get a line from the temp file
* and store in the buffer `buffer'. The number of characters read
* including the null is returned.
*/
getline(a, buffer)
char *buffer;
{
LINE l;
int bno, off;
register char *bp, *dp, *cp;
l = line[a];
bno = blockn(l);
off = offset(l);
bp = buffer;
for (;;) {
if ((cp=getdisk(bno++)) == NULL)
return (0);
dp = &cp[off];
cp += DBSIZE;
while (dp < cp) {
if ((*bp++=*dp++) == '\0')
return (bp-buffer);
}
off = 0;
}
}
/*
* Given a buffer, `bp', containing a line and a number of
* characters, `n', in the buffer, add the line onto the end of
* the temp file.
*/
putline(bp, n)
register char *bp;
register int n;
{
int bno, off, inc;
register char *dp;
inc = (n+CLSIZE-1) & ~(CLSIZE-1);
if (tmpseek+inc > (ULARGE/2)*CLSIZE) {
derror("Temp file overflow");
return (0);
}
bno = tmpseek / DBSIZE;
off = tmpseek % DBSIZE;
for (;;) {
if (wcurbno>=0 && bno!=wcurbno)
if (putdisk() == 0)
return (0);
wcurbno = bno;
dp = &wdbcbuf[off];
while (dp < &wdbcbuf[DBSIZE]) {
*dp++ = *bp++;
if (--n == 0) {
tmpseek += inc;
return (1);
}
}
bno++;
off = 0;
}
}
/*
* Given a block number, bring it into a disk buffer. A pointer
* to the buffer is returned.
*/
char *
getdisk(bno)
{
if (bno == wcurbno)
return (wdbcbuf);
if (bno == rcurbno)
return (rdbcbuf);
#if RSX
/* IO.RVB = 0010400 */
qio(010400, flun(tmp), 1, tmp->v_iosb, NULL,
rdbcbuf, sizeof(rdbcbuf), 0, 0, bno+1, 0);
wtse(1);
if ((tmp->v_iosb[0]&0377) != 1)
return (NULL);
#else
lseek(fileno(tmp), (long) bno * DBSIZE, 0);
if (read(fileno(tmp), rdbcbuf, sizeof(rdbcbuf)) != sizeof(rdbcbuf)) {
terror("Read error");
return (NULL);
}
#endif
rcurbno = bno;
return (rdbcbuf);
}
/*
* Write out the current disk buffer.
*/
putdisk()
{
#if RSX
if (wcurbno >= tmp->v_hibk)
if (grow(1) == 0)
return (0);
/* IO.WVB = 0011000 */
qio(011000, flun(tmp), 1, tmp->v_iosb, NULL,
wdbcbuf, sizeof(wdbcbuf), 0, 0, wcurbno+1, 0);
wtse(1);
if ((tmp->v_iosb[0]&0377) != 1)
return (0);
#else
lseek(fileno(tmp), (long) wcurbno * DBSIZE, 0);
if (write(fileno(tmp), wdbcbuf, sizeof(wdbcbuf)) != sizeof(wdbcbuf)) {
terror("Write error");
return (0);
}
#endif
return (1);
}
#if RSX
/*
* Grow the temp file.
*/
grow(n)
{
/* IO.EXT = 0011400 */
qio(011400, flun(tmp), 1, tmp->v_iosb, NULL,
0, 0, 0100000, n, 0, 0);
wtse(1);
if ((tmp->v_iosb[0]&0377) != 1)
return (0);
tmp->v_hibk += n;
return (1);
}
#endif
/*
* A diagnostic error.
*/
derror(str)
char *str;
{
errstr = str;
if (tflag != 0) {
printc(stdout, '\000');
printc(stdout, '\025');
fflush(stdout);
} else {
printc(stderr, '?');
if (vflag != 0)
prints(stderr, str);
printc(stderr, '\n');
}
}
/*
* A temp file error.
*/
terror(str)
char *str;
{
errstr = str;
if (tflag != 0) {
printc(stdout, '\000');
printc(stdout, '\025');
fflush(stdout);
} else {
printc(stderr, '?');
if (vflag == 0)
prints(stderr, "TMP");
else
prints(stderr, str);
printc(stderr, '\n');
}
}
/*
* Print out a decimal number.
*/
printd(fp, n)
FILE *fp;
register int n;
{
register int c;
if (n < 0) {
printc(fp, '-');
if ((n=-n) < 0)
n = 0;
}
c = n%10 + '0';
n /= 10;
if (n != 0)
printd(fp, n);
printc(fp, c);
}
/*
* Print out a long integer.
*/
printl(fp, n)
FILE *fp;
register long n;
{
register int c;
if (n < 0) {
printc(fp, '-');
if ((n=-n) < 0)
n = 0;
}
c = n%10 + '0';
n /= 10;
if (n != 0)
printl(fp, n);
printc(fp, c);
}
/*
* Print out an octal number.
*/
printo(fp, n)
FILE *fp;
{
printc(fp, '0'+((n>>6)&03));
printc(fp, '0'+((n>>3)&07));
printc(fp, '0'+(n&07));
}
/*
* Print out a string.
*/
prints(fp, cp)
register FILE *fp;
register char *cp;
{
while (*cp)
printc(fp, *cp++);
}
/*
* Print out a character.
*/
printc(fp, c)
register FILE *fp;
{
putc(c, fp);
if (tflag==0 && c=='\n' && fp==stdout)
fflush(fp);
}