DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦edf8a7d97⟧ TextFile

    Length: 11238 (0x2be6)
    Types: TextFile
    Notes: UNIX file
    Names: »ed2.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦f4b8d8c84⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »cmd/ed/ed2.c« 

TextFile

/*
 * An editor.
 * Commands.
 */
#include <stdio.h>
#include <ctype.h>
#include "ed.h"

/*
 * Edit a file.  The filename is stored in `file'.
 */
edit()
{
	register int ret, i;

	if (doladd > 0)
		delete(1, doladd);
	tmpseek = CLSIZE;
	rcurbno = -1;
	wcurbno = -1;
	if ((fp=xfopen(file, "r")) == NULL) {
		derror("Cannot open file");
		return (0);
	}
#if RSX
	if ((i=fp->v_efbk+1-tmp->v_hibk) > 0) {
		if (grow(i) == 0) {
			terror("Temp file error");
			return (0);
		}
	}
#endif
	ret = 1;
	if (append(0, readfil) == 0)
		ret = 0;
	else if (ferror(fp)) {
		derror("Read error");
		ret = 0;
	}
	fclose(fp);
	for (i=0; i<MKSIZE; i++)
		marklin[i] = 0;
	saved = 1;
	if (cflag != 0) {
		printl(stdout, !oflag ? cct : lct);
		printc(stdout, '\n');
	}
	return (ret);
}

/*
 * Make sure that the previous command is terminated either
 * immediately by a newline or has a 'p' or a 'l' which is
 * then terminated by a newline.  The variable `vcom' is set
 * to the verify command.  A zero is returned if there were
 * bad characters before the newline, otherwise a one.
 */
verify(flag)
{
	register int c;

	vcom = ' ';
	if (flag==0 && mflag!=0)
		return (1);
	if ((c=getx()) == '\n') {
		ungetx(c);
		return (1);
	}
	if (c=='l' || c=='p') {
		if (getx() == '\n') {
			ungetx('\n');
			vcom = c;
			return (1);
		}
	}
	derror("Bad command");
	return (0);
}

/*
 * Get a filename of the form required for the r command.
 * which is returned in `name'.  If no name is specified,
 * the one stored in `file' is copied.  If a file name is
 * specified and none exists in `file', it is copied to
 * `file'.  If an illegal name is given, an error is derrord.
 */
getfile(name)
char name[FNSIZE+1];
{
	register int c;
	register char *p1, *p2;

	switch (c=getx()) {
	case '\n':
		p1 = name;
		p2 = file;
		while (*p1++ = *p2++)
			;
		break;
	case ' ':
		p1 = name;
		p2 = &name[FNSIZE];
		while ((c=getx()) != '\n') {
			if (p1 >= p2) {
				derror("File name too long");
				name[0] = '\0';
				return (0);
			}
			*p1++ = c;
		}
		*p1 = '\0';
		if (file[0] == '\0') {
			p1 = file;
			p2 = name;
			while (*p1++ = *p2++)
				;
		}
		break;
	default:
		while (getx() != '\n')
			;
		derror("Bad command");
		return (0);
	}
	if (name[0] == '\0') {
		derror("Null file name");
		return (0);
	}
	return (1);
}

/*
 * Read the rest of the input line into `tempbuf'.
 */
rest()
{
	register int c;
	register char *cp;

	cp = tempbuf;
	while ((c=getx())!=EOF && c!='\n') {
		if (cp >= &tempbuf[TBSIZE-1]) {
			derror("Line too long");
			return (0);
		}
		*cp++ = c;
	}
	*cp = '\0';
	return (1);
}

/*
 * Append text after the given address.  A line of text is gotten
 * by calling the given function until it returns NULL.
 */
append(a, f)
int (*f)();
{
	int seek;
	register int n;

	cct = 0;
	lct = 0;
	if (a<0 || a>doladd) {
		derror("Address out of range");
		return (0);
	}
	dotadd = a;
	while ((n=(*f)()) != 0) {
		if (intflag)
			return (1);
		seek = linead();
		if (putline(linebuf, n) == 0)
			return (0);
		saved = 0;
		cct += n;
		lct++;
		if (expand(dotadd) == 0)
			return (0);
		line[++dotadd] = seek;
	}
	return (1);
}

/*
 * Expand the line table and leave a hole at the given address.
 */
expand(a)
{
	register LINE *lp1;
	register LINE *lp2;
	register int n;

	if (doladd+3 >= lnsize) {
		lp1 = (LINE *)realloc(line, (n=lnsize*2)*sizeof(LINE));
		if (lp1 == NULL) {
			derror("Line table overflow");
			return (0);
		}
		line = lp1;
		lnsize = n;
	}
	lp1 = &line[doladd+2];
	lp2 = &line[doladd+1];
	n = doladd++ - a;
	while (n--)
		*--lp1 = *--lp2;
	return (1);
}

/*
 * Get a line of text from the terminal.  The number of characters
 * including the null terminator at the end of the string is returned.
 * If end of file or a line containing only a single dot is found,
 * 0 is returned.
 */
readtty()
{
	register int c;
	register char *lp;

	appflag++;
	lp = linebuf;
	while ((c=getx())!=EOF && c!='\n') {
		if (lp < &linebuf[LBSIZE-1])
			*lp++ = c;
	}
	--appflag;
	if (c==EOF && lp==linebuf) {
		lastchr = '\n';
		if (gcp == NULL)
			clearerr(stdin);
		return (0);
	}
	if (linebuf[0]=='.' && lp==linebuf+1)
		return (0);
	*lp++ = '\0';
	return (lp-linebuf);
}

/*
 * Get a line of text from the file open on file pointer `fp'.
 * Return the number of characters in the line including the
 * null terminator at the end.  On end of file, 0 is returned.
 */
readfil()
{
	register int c, n;
	register char *lp;

	if ((c=getc(fp)) == EOF)
		return (0);
	lp = linebuf;
	n = LBSIZE-1;
	while (c!=EOF && c!='\n') {
		*lp++ = c;
		if (--n == 0)
			break;
		c = getc(fp);
	}
	*lp++ = '\0';
	return (lp-linebuf);
}

/*
 * Delete the given line range.
 */
delete(a1, a2)
{
	register LINE *p1, *p2;
	register int n;

	if (a1>a2 || a1<1 || a2>doladd) {
		derror("Address out of range");
		return (0);
	}
	p1 = &line[a1];
	p2 = &line[a2+1];
	n = doladd - a2;
	while (n--)
		*p1++ = *p2++;
	doladd -= (a2+1) - a1;
	if ((dotadd=a1) > doladd)
		--dotadd;
	saved = doladd==0;
	return (1);
}

/*
 * Concatenate the lines in the given range to form
 * a single line.
 */
join(a1, a2)
{
	long seek;
	int bn, a;
	register int n;
	register char *lp, *tp;

	if (a1>a2 || a1<1 || a2>doladd) {
		derror("Address out of range");
		return (0);
	}
	bn = 0;
	lp = linebuf;
	for (a=a1; a<=a2; a++) {
		if ((n=getline(a, tempbuf)) == 0)
			return (0);
		if ((bn+=--n) >= LBSIZE-1) {
			derror("Temporary buffer overflow");
			return (0);
		}
		tp = tempbuf;
		while (n--)
			*lp++ = *tp++;
	}
	*lp++ = '\0';
	seek = linead();
	if (putline(linebuf, ++bn) == 0)
		return (0);
	line[a1] = seek;
	a = doladd - a2;
	for (n=0; n<a; n++)
		line[a1+1+n] = line[a2+1+n];
	dotadd = a1;
	doladd -= a2 - a1;
	return (1);
}

/*
 * List the given line range.  All non-printing characters are
 * escaped.
 */
list(a1, a2)
{
	int a;
	register int n;
	register char *p;

	if (a1>a2 || a1<1 || a2>doladd) {
		derror("Address out of range");
		return (0);
	}
	for (a=a1; a<=a2; a++) {
		if (intflag)
			return (1);
		if (getline(a, linebuf) == 0)
			break;
		n = 0;
		for (p=linebuf; *p; p++) {
			if (n++ >= 72) {
				n = 0;
				prints(stdout, "\\\n");
			}
			switch (*p) {
			case '\b':
				prints(stdout, "-\b<");
				continue;
			case '\t':
				prints(stdout, "-\b>");
				continue;
			case '\\':
				prints(stdout, "\\\\");
				continue;
			default:
				if (isascii(*p) && !iscntrl(*p)) {
					printc(stdout, *p);
					continue;
				}
				printc(stdout, '\\');
				printo(stdout, *p);
				n += 3;
			}
		}
		prints(stdout, "\\n");
		printc(stdout, '\n');
		dotadd = a;
	}
	return (1);
}

/*
 * Take the text that is between lines `a1' and `a2' and
 * place it after line `a3'.
 */
move(a1, a2, a3)
int a1, a2, a3;
{
	LINE l;
	register int a, n, x;

	if (a1>a2 || a1<1 || a2>doladd || a3<0 || a3>doladd) {
		derror("Address out of range");
		return (0);
	}
	if (a3>=a1-1 && a3<=a2) {
		dotadd = a2;
		return (1);
	}
	if (a3 < a1) {
		for (a=a1, x=a3+1; a<=a2; a++, x++) {
			l = line[a];
			for (n=a; n>x; --n)
				line[n] = line[n-1];
			line[x] = l;
		}
		dotadd = a3 + a2+1 - a1;
	} else {
		for (a=a2, x=a3; a>=a1; --a, --x) {
			l = line[a];
			for (n=a; n<x; n++)
				line[n] = line[n+1];
			line[x] = l;
		}
		dotadd = a3;
	}
	saved = 0;
	return (1);
}

/*
 * Given a string describing a set of options, set them.
 */
setoptf(sp)
register char *sp;
{
	register int t;

	t = 1;
	while (*sp != '\0') {
		switch (*sp++) {
		case '+':
			t = 1;
			continue;
		case '-':
			t = 0;
			continue;
		case 'c':
			cflag = t;
			continue;
		case 'm':
			mflag = t;
			continue;
		case 'o':
			oflag = t;
			continue;
		case 'p':
			pflag = t;
			continue;
		case 's':
			sflag = t;
			continue;
		case 'v':
			vflag = t;
			continue;
		default:
			derror("Bad option");
			return;
		}
	}
}

/*
 * Display options.
 */
disoptf()
{
	if (cflag)
		printc(stdout, 'c');
	if (mflag)
		printc(stdout, 'm');
	if (oflag)
		printc(stdout, 'o');
	if (pflag)
		printc(stdout, 'p');
	if (sflag)
		printc(stdout, 's');
	if (vflag)
		printc(stdout, 'v');
	if (keyp != NULL)
		printc(stdout, 'x');
	printc(stdout, '\n');
}

/*
 * Print the given line range.
 */
print(a1, a2)
{
	register int a;
	register char *p;

	if (a1>a2 || a1<1 || a2>doladd) {
		derror("Address out of range");
		return (0);
	}
	for (a=a1; a<=a2; a++) {
		if (intflag)
			return (1);
		if (getline(a, linebuf) == 0)
			break;
		p = linebuf;
		while (*p)
			printc(stdout, *p++);
		printc(stdout, '\n');
		dotadd = a;
	}
	return (1);
}

/*
 * Make a copy of the text between lines `a1' and `a2'
 * and place them after `a3'.
 */
copy(a1, a2, a3)
{
	register int i, j, n;

	if (a1>a2 || a1<1 || a2>doladd || a3<0 || a3>doladd) {
		derror("Address out of range");
		return (0);
	}
	n = (a2+1) - a1;
	if (doladd+n+2 > lnsize) {
		derror("Line table overflow");
		return (0);
	}
	for (i=doladd; i>a3; --i)
		line[i+n] = line[i];
	for (i=0; i<n; i++) {
		if ((j=i+a1) > a3)
			j += n;
		if ((j=getline(j, linebuf)) == 0)
			goto err;
		line[a3+1+i] = linead();
		if (putline(linebuf, j) == 0)
			goto err;
	}
	dotadd = a3+n;
	doladd += n;
	saved = 0;
	return (1);

err:
	for (i=a3+1; i<=doladd; i++)
		line[i] = line[i+n];
	return (0);
}

/*
 * Write the given line range onto the file whose name is
 * stored in `file'.  `perm' is the permission string we
 * want the file opened with.
 */
wfile(a1, a2, name, perm, sflag)
char *name, *perm;
{
	register int a;
	register char *cp;

	if (doladd!=0 || addspec!=0) {
		if (a1>a2 || a1<1 || a2>doladd) {
			derror("Address out of range");
			return (0);
		}
	}
	if ((fp=xfopen(name, perm)) == NULL) {
		derror("Cannot open file");
		return (0);
	}
	cct = 0;
	lct = 0;
	for (a=a1; a<=a2; a++) {
		if (getline(a, linebuf) == 0)
			break;
		cp = linebuf;
		while (*cp) {
			printc(fp, *cp++);
			cct++;
		}
		printc(fp, '\n');
		if (ferror(fp))
			break;
		cct++;
		lct++;
	}
	if (sflag==0 && cflag!=0) {
		printl(stdout, !oflag ? cct : lct);
		printc(stdout, '\n');
	}
	if ((a=ferror(fp)) == 0)
		saved = 1;
	else {
		if (sflag == 0)
			derror("Write error");
	}
	fclose(fp);
#if COHERENT
	sync();
#endif
	return (!a);
}

/*
 * Open a file.  If we are in encryption mode, the open unit is really a
 * file descriptor piped to the crypt command.
 */
FILE *
xfopen(fn, mode)
char *fn;
char *mode;
{
	register FILE *fp;
	register int f;
	register int u;
	register int a;
	register int b;
	int pv[2];

	if (keyp == NULL)
		fp = fopen(fn, mode);
	else {
		switch (mode[0]) {
		case 'a':
			return (NULL);
		case 'r':
			a = 0;
			b = 1;
			break;
		case 'w':
			a = 1;
			b = 0;
			break;
		}
		if (pipe(pv) < 0)
			return (NULL);
		if ((f=fork()) < 0) {
			close(pv[0]);
			close(pv[1]);
			return (NULL);
		}
		if (f == 0) {
			if ((u=(a==0)?open(fn, 0):creat(fn, 0644)) < 0)
				exit(1);
			dup2(u, a);
			dup2(pv[b], b);
			close(u);
			close(pv[0]);
			close(pv[1]);
			execl("/bin/crypt", "crypt", keyp, NULL);
			exit(1);
		}
		close(pv[b]);
		fp = fdopen(pv[a], mode);
	}
	return (fp);
}

/*
 * Read a key from the standard input.
 */
setkey()
{
#if RSX
	derror("Cannot set key");
	return (0);
#else
	register int n;

	keyp = getpass("key? ");
	if ((n=strlen(keyp)) > CKSIZE) {
		derror("Key too long");
		keyp = NULL;
		return (0);
	}
	if (n == 0)
		keyp = NULL;
	return (1);
#endif
}