|
|
BSD 4.3
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1984. */
static char rcsid[] = "$Header: /var/lib/cvsd/repos/CSRG/43BSD/contrib/B/src/bed/edit.c,v 1.1.1.1 2018/04/24 16:12:54 root Exp $";
/*
* B editor -- Read unit from file.
*/
#include <ctype.h>
#include "b.h"
#include "feat.h"
#include "erro.h"
#include "bobj.h"
#include "node.h"
#include "tabl.h"
#include "gram.h"
#include "supr.h"
#include "queu.h"
string unixerror();
/*
* TABSIZE sets the number of spaces equivalent to a tab character
* read from the input; INDENT sets the number of spaces for one indentation
* level.
* The definitions here are unrelated to the definition of TABS
* in eval.h (used by show.c and eval.c). The definition here only
* defines how many spaces must be equivalenced to a tab stop when read
* from a file; tab stops must be caused by editing a unit with another
* editor (vi, ed, ex, emacs), since "save.c" always writes spaces,
* not tabs. The value '4' is best suited for people at the CWI who
* may have workspaces with units edited with the previous version of
* the B editor, which emitted a tab for each indentation level (and
* assumed 4 spaces for a tab stop on input).
*
* The variables 'spacesused' and 'tabsused' are kept to see if mixed use
* of spaces and tabs was made; this can cause indentation errors.
*/
#ifdef CWI
#define TABSIZE 4
#else
#define TABSIZE 8
#endif
#define INDENT 4
Hidden bool spacesused;
Hidden bool tabsused;
/*
* Read (edit) parse tree from file into the focus.
* Rather ad hoc, we use ins_string for each line
* and do some magic tricks to get the indentation right
* (most of the time).
* If line > 0, position the focus at that line, if possible;
* otherwise the focus is left at the end of the inserted text.
*/
Visible bool
edit(ep, filename, line)
register environ *ep;
string filename;
int line;
{
int lines = 0;
register FILE *fp = fopen(filename, "r");
register int c;
char buf[BUFSIZ];
auto string cp;
auto queue q = Qnil;
if (!fp) {
error("%s", unixerror(filename));
return No;
}
spacesused = tabsused = No;
do {
do {
for (cp = buf; cp < buf + sizeof buf - 1; ++cp) {
c = getc(fp);
if (c == EOF || c == '\n')
break;
if (c < ' ' || c >= 0177)
c = ' ';
*cp = c;
}
if (cp > buf) {
*cp = 0;
if (!ins_string(ep, buf, &q, 0) || !emptyqueue(q)) {
qrelease(q);
error(EDIT_BAD);
fclose(fp);
return No;
}
qrelease(q);
}
} while (c != EOF && c != '\n');
++lines;
if (c != EOF && !editindentation(ep, fp)) {
fclose(fp);
return No;
}
} while (c != EOF);
fclose(fp);
if (ep->mode == FHOLE || ep->mode == VHOLE && (ep->s1&1)) {
cp = "";
soften(ep, &cp, 0);
}
if (lines > 1 && line > 0) {
gotoyx(ep, line-1, 0);
oneline(ep);
}
if (spacesused && tabsused)
error(EDIT_TABS);
return Yes;
}
/*
* Do all the footwork required to get the indentation proper.
*/
Hidden Procedure
editindentation(ep, fp)
register environ *ep;
register FILE *fp;
{
register int tabs = 0;
auto int level;
register int c;
while ((c = getc(fp)) == ' ' || c == '\t') {
if (c == ' ') {
spacesused = Yes;
++tabs;
}
else {
tabsused = Yes;
tabs = (tabs/TABSIZE + 1)*TABSIZE;
}
}
ungetc(c, fp);
if (c == EOF || c == '\n')
return Yes;
tabs = (tabs+(INDENT/2))/INDENT; /* Transform to tab stops */
if (!ins_newline(ep)) {
#ifndef NDEBUG
debug("[Burp! Can't insert a newline.]");
#endif NDEBUG
return No;
}
level = Level(ep->focus);
for (; tabs < level; --level) {
if (!ins_newline(ep)) {
#ifndef NDEBUG
debug("[Burp, burp! Can't decrease indentation.]");
#endif NDEBUG
return No;
}
}
fixit(ep);
return Yes;
}
/* ------------------------------------------------------------ */
#ifdef SAVEBUF
/*
* Read the next non-space character.
*/
Hidden int
skipsp(fp)
register FILE *fp;
{
register int c;
do {
c = getc(fp);
} while (c == ' ');
return c;
}
/*
* Read a text in standard B format when the initial quote has already
* been read.
*/
Hidden value
readtext(fp, quote)
register FILE *fp;
register char quote;
{
auto value v = Vnil;
char buf[BUFSIZ];
register string cp = buf;
register int c;
auto int i;
for (; ; ++cp) {
c = getc(fp);
if (!isascii(c) || c != ' ' && !isprint(c)) {
if (c == EOF)
debug("readtext: EOF");
else
debug("readtext: bad char (0%02o)", c);
release(v);
return Vnil; /* Bad character or EOF */
}
if (c == quote) {
c = getc(fp);
if (c != quote) {
ungetc(c, fp);
break;
}
}
else if (c == '`') {
c = skipsp(fp);
if (c == '$') {
i = 0;
if (fscanf(fp, "%d", &i) != 1
|| i == 0 || !isascii(i)) {
debug("readtext: error in conversion");
release(v);
return Vnil;
}
c = skipsp(fp);
}
else
i = '`';
if (c != '`') {
if (c == EOF)
debug("readtext: EOF in conversion");
else
debug("readtext: bad char in conversion (0%o)", c);
release(v);
return Vnil;
}
c = i;
}
if (cp >= &buf[sizeof buf - 1]) {
*cp = 0;
if (v)
concato(&v, buf);
else
v = mk_text(buf);
cp = buf;
}
*cp = c;
}
*cp = 0;
if (!v)
return mk_text(buf);
concato(&v, buf);
return v;
}
Hidden int
readsym(fp)
register FILE *fp;
{
register int c;
char buf[100];
register string bufp;
for (bufp = buf; ; ++bufp) {
c = getc(fp);
if (c == EOF)
return -1;
if (!isascii(c) || !isalnum(c) && c != '_') {
if (ungetc(c, fp) == EOF)
syserr("readsym: ungetc failed");
break;
}
*bufp = c;
}
*bufp = 0;
if (isdigit(buf[0]))
return atoi(buf);
if (strcmp(buf, "Required") == 0) /***** Compatibility hack *****/
return Hole;
return nametosym(buf);
}
/*
* Read a node in internal format (recursively).
* Return nil pointer if EOF or error.
*/
Hidden node
readnode(fp)
FILE *fp;
{
int c;
int nch;
node ch[MAXCHILD];
node n;
int sym;
c = skipsp(fp);
switch (c) {
case EOF:
return Nnil; /* EOF hit */
case '(':
sym = readsym(fp);
if (sym < 0) {
debug("readnode: missing symbol");
return Nnil; /* No number as first item */
}
if (sym < 0 || sym > Hole) {
debug("readnode: bad symbol (%d)", sym);
return Nnil;
}
nch = 0;
while ((c = skipsp(fp)) == ',' && nch < MAXCHILD) {
n = readnode(fp);
if (!n) {
for (; nch > 0; --nch)
noderelease(ch[nch-1]);
return Nnil; /* Error encountered in child */
}
ch[nch] = n;
++nch;
}
if (c != ')') {
if (c == ',')
debug("readnode: node too long (sym=%d)", sym);
else
debug("readnode: no ')' where expected (sym=%d)", sym);
for (; nch > 0; --nch)
noderelease(ch[nch-1]);
return Nnil; /* Not terminated with ')' or too many children */
}
if (nch == 0)
return gram(sym); /* Saves space for Optional/Hole nodes */
return newnode(nch, sym, ch);
case '\'':
case '"':
return (node) readtext(fp, c);
default:
debug("readnode: bad initial character");
return Nnil; /* Bad initial character */
}
}
/*
* Read a node written in a more or less internal format.
*/
Visible value
editqueue(filename)
string filename;
{
register FILE *fp = fopen(filename, "r");
auto queue q = Qnil;
register node n;
if (!fp)
return Vnil;
do {
n = readnode(fp);
if (!n)
break; /* EOF or error */
addtoqueue(&q, n);
noderelease(n);
} while (skipsp(fp) == '\n');
fclose(fp);
return (value)q;
}
#endif SAVEBUF
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.