|
|
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: 11238 (0x2be6)
Types: TextFile
Notes: UNIX file
Names: »ed2.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/ed/ed2.c«
/*
* 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
}