|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T e
Length: 17969 (0x4631)
Types: TextFile
Names: »extend.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦this⟧ »EUUGD11/euug-87hel/sec1/jove/extend.c«
/************************************************************************
* This program is Copyright (C) 1986 by Jonathan Payne. JOVE is *
* provided to you without charge, and with no warranty. You may give *
* away copies of JOVE, including sources, provided that this notice is *
* included in all the files. *
************************************************************************/
#include "jove.h"
#include "io.h"
#include "termcap.h"
#include "ctype.h"
#ifdef JOB_CONTROL
# include <signal.h>
#endif
#include <varargs.h>
int InJoverc = 0;
extern int getch(),
getchar();
/* Auto execute code */
#define NEXECS 20
private struct {
char *a_pattern;
data_obj *a_cmd;
} AutoExecs[NEXECS] = {0};
private int ExecIndex = 0;
/* Command auto-execute. */
CAutoExec()
{
DefAutoExec(findcom);
}
/* Macro auto-execute. */
MAutoExec()
{
DefAutoExec(findmac);
}
/* VARARGS0 */
DefAutoExec(proc)
data_obj *(*proc)();
{
data_obj *d;
char *pattern;
int i;
if (ExecIndex >= NEXECS)
complain("Too many auto-executes, max %d.", NEXECS);
if ((d = (*proc)(ProcFmt)) == 0)
return;
pattern = ask((char *) 0, ": %f %s ", d->Name);
for (i = 0; i < ExecIndex; i++)
if ((AutoExecs[i].a_cmd == d) &&
(strcmp(pattern, AutoExecs[i].a_pattern) == 0))
return; /* Eliminate duplicates. */
AutoExecs[ExecIndex].a_pattern = copystr(pattern);
AutoExecs[ExecIndex].a_cmd = d;
ExecIndex++;
}
/* DoAutoExec: NEW and OLD are file names, and if NEW and OLD aren't the
same kind of file (i.e., match the same pattern) or OLD is 0 and it
matches, we execute the command associated with that kind of file. */
DoAutoExec(new, old)
register char *new,
*old;
{
register int i;
exp_p = YES;
exp = 1; /* So minor modes don't toggle. We always want
them on. */
if (new == 0)
return;
for (i = 0; i < ExecIndex; i++)
if ((LookingAt(AutoExecs[i].a_pattern, new, 0)) &&
(old == 0 || !LookingAt(AutoExecs[i].a_pattern, old, 0)))
ExecCmd(AutoExecs[i].a_cmd);
}
BindAKey()
{
BindSomething(findcom);
}
BindMac()
{
BindSomething(findmac);
}
extern int EscPrefix(),
CtlxPrefix(),
MiscPrefix();
data_obj **
IsPrefix(cp)
data_obj *cp;
{
int (*proc)();
if (cp == 0 || (cp->Type & TYPEMASK) != FUNCTION)
return 0;
proc = ((struct cmd *) cp)->c_proc;
if (proc == EscPrefix)
return pref1map;
if (proc == CtlxPrefix)
return pref2map;
if (proc == MiscPrefix)
return miscmap;
return 0;
}
unbind_aux(c)
{
if (c == CR || c == LF)
return FALSE; /* tells do_ask to return */
Insert(c);
return !FALSE;
}
UnbindC()
{
char *keys;
data_obj **map = mainmap;
keys = do_ask("\r\n\01\02\03\04\05\06\010\011\013\014\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037", unbind_aux, (char *) 0, ProcFmt);
if (keys == 0)
return;
for (;;) {
if (keys[1] == '\0')
break;
if ((map = IsPrefix(map[*keys])) == 0)
break;
keys++;
}
if (keys[1] != 0)
complain("That's not a legitimate key sequence.");
map[keys[0]] = 0;
}
addgetc()
{
int c;
if (!InJoverc)
Asking = strlen(mesgbuf);
c = getch();
if (InJoverc) {
if (c == '\n')
return EOF; /* this isn't part of the sequence */
else if (c == '\\') {
if ((c = getch()) == LF)
complain("[Premature end of line]");
} else if (c == '^') {
if ((c = getch()) == '?')
c = RUBOUT;
else if (isalpha(c) || index("[\\]^_", c))
c = c - '@';
else
complain("[Unknown control character]");
}
}
Asking = 0;
add_mess("%p ", c);
return c;
}
BindWMap(map, lastkey, cmd)
data_obj **map,
*cmd;
{
data_obj **nextmap;
int c;
c = addgetc();
if (c == EOF) {
if (lastkey == EOF)
complain("[Empty key sequence]");
complain("[Premature end of key sequence]");
} else {
if (nextmap = IsPrefix(map[c]))
BindWMap(nextmap, c, cmd);
else
map[c] = cmd;
}
}
/* VARARGS0 */
BindSomething(proc)
data_obj *(*proc)();
{
data_obj *d;
if ((d = (*proc)(ProcFmt)) == 0)
return;
s_mess(": %f %s ", d->Name);
BindWMap(mainmap, EOF, d);
}
/* Describe key */
DescWMap(map, key)
data_obj **map;
{
data_obj *cp = map[key],
**prefp;
if (cp == 0)
add_mess("is unbound.");
else if (prefp = IsPrefix(cp))
DescWMap(prefp, addgetc());
else
add_mess("is bound to %s.", cp->Name);
}
KeyDesc()
{
s_mess(ProcFmt);
DescWMap(mainmap, addgetc());
}
DescCom()
{
data_obj *dp;
char pattern[100],
doc_type[40],
*file = CmdDb;
File *fp;
if (!strcmp(LastCmd->Name, "describe-variable"))
dp = (data_obj *) findvar(ProcFmt);
else
dp = (data_obj *) findcom(ProcFmt);
if (dp == 0)
return;
fp = open_file(file, iobuff, F_READ, COMPLAIN, QUIET);
Placur(ILI, 0);
flusho();
sprintf(pattern, "^:entry \"%s\" \"\\([^\"]*\\)\"", dp->Name);
TOstart("Help", TRUE);
for (;;) {
if (f_gets(fp, genbuf, LBSIZE) == EOF) {
Typeout("There is no documentation for \"%s\".", dp->Name);
goto outahere;
}
if ((strncmp(genbuf, ":entry", 6) == 0) && LookingAt(pattern, genbuf, 0))
break;
}
/* found it ... let's print it */
putmatch(1, doc_type, sizeof doc_type);
if (strcmp("Variable", doc_type) == 0)
Typeout(dp->Name);
else if (strcmp("Command", doc_type) == 0) {
char binding[128];
find_binds(dp, binding);
if (blnkp(binding))
Typeout("To invoke %s, type \"ESC X %s<cr>\".",
dp->Name,
dp->Name);
else
Typeout("Type \"%s\" to invoke %s.", binding, dp->Name);
}
Typeout("");
while (f_gets(fp, genbuf, LBSIZE) != EOF)
if (strncmp(genbuf, ":entry", 6) == 0)
goto outahere;
else
Typeout("%s", genbuf);
outahere:
f_close(fp);
TOstop();
}
DescBindings()
{
extern int Typeout();
TOstart("Key Bindings", TRUE);
DescMap(mainmap, NullStr);
TOstop();
}
DescMap(map, pref)
data_obj **map;
char *pref;
{
int c1,
c2 = 0,
numbetween;
char keydescbuf[40];
data_obj **prefp;
for (c1 = 0; c1 < 0200 && c2 < 0200; c1 = c2 + 1) {
c2 = c1;
if (map[c1] == 0)
continue;
while (++c2 < 0200 && map[c1] == map[c2])
;
c2--;
numbetween = c2 - c1;
if (numbetween == 1)
sprintf(keydescbuf, "%s {%p,%p}", pref, c1, c2);
else if (numbetween == 0)
sprintf(keydescbuf, "%s %p", pref, c1);
else
sprintf(keydescbuf, "%s [%p-%p]", pref, c1, c2);
if (prefp = IsPrefix(map[c1]))
DescMap(prefp, keydescbuf);
else
Typeout("%-14s%s", keydescbuf, map[c1]->Name);
}
}
private
find_binds(dp, buf)
data_obj *dp;
char *buf;
{
char *endp;
buf[0] = '\0';
fb_aux(dp, mainmap, (char *) 0, buf);
endp = buf + strlen(buf) - 2;
if ((endp > buf) && (strcmp(endp, ", ") == 0))
*endp = '\0';
}
private
fb_aux(cp, map, prefix, buf)
register data_obj *cp,
**map;
char *buf,
*prefix;
{
int c1,
c2;
char *bufp = buf + strlen(buf),
prefbuf[20];
data_obj **prefp;
for (c1 = c2 = 0; c1 < 0200 && c2 < 0200; c1 = c2 + 1) {
c2 = c1;
if (map[c1] == cp) {
while (++c2 < 0200 && map[c1] == map[c2])
;
c2--;
if (prefix)
sprintf(bufp, "%s ", prefix);
bufp += strlen(bufp);
switch (c2 - c1) {
case 0:
sprintf(bufp, "%p, ", c1);
break;
case 1:
sprintf(bufp, "{%p,%p}, ", c1, c2);
break;
default:
sprintf(bufp, "[%p-%p], ", c1, c2);
break;
}
}
if (prefp = IsPrefix(map[c1])) {
sprintf(prefbuf, "%p", c1);
fb_aux(cp, prefp, prefbuf, bufp);
}
bufp += strlen(bufp);
}
}
Apropos()
{
register struct cmd *cp;
register struct macro *m;
register struct variable *v;
char *ans;
int anyfs = 0,
anyvs = 0,
anyms = 0;
char buf[256];
ans = ask((char *) 0, ": %f (keyword) ");
TOstart("Help", TRUE);
for (cp = commands; cp->Name != 0; cp++)
if (sindex(ans, cp->Name)) {
if (anyfs == 0) {
Typeout("Commands");
Typeout("--------");
}
find_binds((data_obj *) cp, buf);
if (buf[0])
Typeout(": %-35s(%s)", cp->Name, buf);
else
Typeout(": %s", cp->Name);
anyfs++;
}
if (anyfs)
Typeout(NullStr);
for (v = variables; v->Name != 0; v++)
if (sindex(ans, v->Name)) {
if (anyvs == 0) {
Typeout("Variables");
Typeout("---------");
}
anyvs++;
vpr_aux(v, buf);
Typeout(": set %-26s%s", v->Name, buf);
}
if (anyvs)
Typeout(NullStr);
for (m = macros; m != 0; m = m->m_nextm)
if (sindex(ans, m->Name)) {
if (anyms == 0) {
Typeout("Macros");
Typeout("------");
}
anyms++;
find_binds((data_obj *) m, buf);
if (buf[0])
Typeout(": %-35s(%s)", m->Name, buf);
else
Typeout(": %-35s%s", "execute-macro", m->Name);
}
TOstop();
}
Extend()
{
data_obj *d;
if (d = findcom(": "))
ExecCmd(d);
}
/* Read a positive integer from CP. It must be in base BASE, and
complains if it isn't. If allints is nonzero, all the characters
in the string must be integers or we return -1; otherwise we stop
reading at the first nondigit. */
chr_to_int(cp, base, allints)
register char *cp;
{
register int c;
int value = 0;
while (c = *cp++) {
if (!isdigit(c)) {
if (allints)
return -1;
break;
}
c = c - '0';
if (c >= base)
complain("You must specify in base %d.", base);
value = value * base + c;
}
return value;
}
ask_int(prompt, base)
char *prompt;
int base;
{
char *val = ask((char *) 0, prompt);
int value = chr_to_int(val, base, 1);
if (value < 0)
complain("That's not a number!");
return value;
}
private
vpr_aux(vp, buf)
register struct variable *vp;
char *buf;
{
switch (vp->v_flags & V_TYPEMASK) {
case V_BASE10:
sprintf(buf, "%d", *(vp->v_value));
break;
case V_BASE8:
sprintf(buf, "%o", *(vp->v_value));
break;
case V_BOOL:
sprintf(buf, (*(vp->v_value)) ? "on" : "off");
break;
case V_STRING:
case V_FILENAME:
sprintf(buf, "%s", (char *) vp->v_value);
break;
case V_CHAR:
sprintf(buf, "%p", *(vp->v_value));
break;
}
}
PrVar()
{
struct variable *vp;
char prbuf[256];
if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
return;
vpr_aux(vp, prbuf);
s_mess(": %f %s => %s", vp->Name, prbuf);
}
SetVar()
{
struct variable *vp;
char *prompt;
if ((vp = (struct variable *) findvar(ProcFmt)) == 0)
return;
prompt = sprint(": %f %s ", vp->Name);
switch (vp->v_flags & V_TYPEMASK) {
case V_BASE10:
case V_BASE8:
{
int value;
value = ask_int(prompt, ((vp->v_flags & V_TYPEMASK) == V_BASE10)
? 10 : 8);
*(vp->v_value) = value;
break;
}
case V_BOOL:
{
char *def = *(vp->v_value) ? "off" : "on",
*on_off;
int value;
on_off = ask(def, prompt);
if (casecmp(on_off, "on") == 0)
value = ON;
else if (casecmp(on_off, "off") == 0)
value = OFF;
else
complain("Boolean variables must be ON or OFF.");
*(vp->v_value) = value;
s_mess("%s%s", prompt, value ? "on" : "off");
break;
}
case V_FILENAME:
{
char fbuf[FILESIZE];
sprintf(&prompt[strlen(prompt)], "(default %s) ", vp->v_value);
(void) ask_file(prompt, (char *) vp->v_value, fbuf);
strcpy((char *) vp->v_value, fbuf);
break;
}
case V_STRING:
{
char *str;
/* Do_ask() so you can set string to "" if you so desire. */
str = do_ask("\r\n", (int (*)()) 0, (char *) vp->v_value, prompt);
if (str == 0)
str = NullStr;
strcpy((char *) vp->v_value, str);
/* ... and hope there is enough room. */
break;
}
case V_CHAR:
f_mess(prompt);
*(vp->v_value) = addgetc();
break;
}
if (vp->v_flags & V_MODELINE)
UpdModLine++;
if (vp->v_flags & V_CLRSCREEN)
ClAndRedraw();
if (vp->v_flags & V_TTY_RESET)
tty_reset();
}
/* Command completion - possible is an array of strings, prompt is
the prompt to use, and flags are ... well read jove.h.
If flags are RET_STATE, and the user hits <return> what they typed
so far is in the Minibuf string. */
private char **Possible;
private int comp_value,
comp_flags;
aux_complete(c)
{
int command,
length,
i;
if (comp_flags & CASEIND) {
char *lp;
for (lp = linebuf; *lp != '\0'; lp++)
if (isupper(*lp))
*lp = tolower(*lp);
}
switch (c) {
case EOF:
comp_value = -1;
return 0;
case '\r':
case '\n':
command = match(Possible, linebuf);
if (command >= 0) {
comp_value = command;
return 0; /* tells ask to stop */
}
if (eolp() && bolp()) {
comp_value = NULLSTRING;
return 0;
}
if (comp_flags & RET_STATE) switch (command) {
case UNIQUE:
case ORIGINAL:
case NULLSTRING:
comp_value = command;
return 0;
default:
break;
}
if (InJoverc)
complain("[\"%s\" unknown]", linebuf);
rbell();
break;
case '\t':
case ' ':
{
int minmatch = 1000,
maxmatch = 0,
numfound = 0,
lastmatch = -1,
length = strlen(linebuf);
for (i = 0; Possible[i] != 0; i++) {
int this_len;
this_len = numcomp(Possible[i], linebuf);
maxmatch = max(maxmatch, this_len);
if (this_len >= length) {
if (numfound)
minmatch = min(minmatch, numcomp(Possible[lastmatch], Possible[i]));
else
minmatch = strlen(Possible[i]);
numfound++;
lastmatch = i;
if (strcmp(linebuf, Possible[i]) == 0)
break;
}
}
if (numfound == 0) {
rbell();
if (InJoverc)
complain("[\"%s\" unknown]", linebuf);
/* If we're not in the .joverc then
let's do something helpful for the
user. */
if (maxmatch < length) {
char *cp;
cp = linebuf + maxmatch;
*cp = 0;
Eol();
}
break;
}
if (c != '\t' && numfound == 1) {
comp_value = lastmatch;
return 0;
}
null_ncpy(linebuf, Possible[lastmatch], minmatch);
Eol();
if (minmatch == length) /* No difference */
rbell();
break;
}
case '?':
if (InJoverc)
complain((char *) 0);
/* kludge: in case we're using UseBuffers, in which case
linebuf gets written all over */
strcpy(Minibuf, linebuf);
length = strlen(Minibuf);
TOstart("Completion", TRUE); /* for now ... */
for (i = 0; Possible[i]; i++)
if (numcomp(Possible[i], Minibuf) >= length) {
Typeout(Possible[i]);
if (TOabort != 0)
break;
}
TOstop();
break;
}
return !FALSE;
}
complete(possible, prompt, flags)
register char *possible[];
char *prompt;
{
Possible = possible;
comp_flags = flags;
(void) do_ask("\r\n \t?", aux_complete, NullStr, prompt);
return comp_value;
}
match(choices, what)
register char **choices,
*what;
{
register int len;
int i,
found = 0,
save,
exactmatch = -1;
len = strlen(what);
if (len == 0)
return NULLSTRING;
for (i = 0; choices[i]; i++) {
if (strncmp(what, choices[i], len) == 0) {
if (strcmp(what, choices[i]) == 0)
exactmatch = i;
save = i;
found++; /* Found one. */
}
}
if (found == 0)
save = ORIGINAL;
else if (found > 1) {
if (exactmatch != -1)
save = exactmatch;
else
save = AMBIGUOUS;
}
return save;
}
Source()
{
char *com,
buf[FILESIZE];
sprintf(buf, "%s/.joverc", getenv("HOME"));
com = ask_file((char *) 0, buf, buf);
if (joverc(buf) == NIL)
complain(IOerr("read", com));
}
BufPos()
{
register Line *lp = curbuf->b_first;
register int i,
dotline;
long dotchar,
nchars;
for (i = nchars = 0; lp != 0; i++, lp = lp->l_next) {
if (lp == curline) {
dotchar = nchars + curchar;
dotline = i + 1;
}
nchars += length(lp) + (lp->l_next != 0); /* include the NL */
}
s_mess("[\"%s\" line %d of %d, char %D of %D (%d%%)]",
filename(curbuf),
dotline,
i,
dotchar,
nchars,
(int) (((long) dotchar * 100) / nchars));
}
#define IF_UNBOUND -1
#define IF_TRUE 1
#define IF_FALSE !IF_TRUE
do_if(cmd)
char *cmd;
{
int pid,
status;
switch (pid = fork()) {
case -1:
complain("[Fork failed: if]");
case 0:
{
char *args[12],
*cp = cmd,
**ap = args;
*ap++ = cmd;
for (;;) {
if ((cp = index(cp, ' ')) == 0)
break;
*cp++ = '\0';
*ap++ = cp;
}
*ap = 0;
close(0); /* we want reads to fail */
/* close(1); but not writes or ioctl's
close(2); */
(void) execvp(args[0], args);
_exit(-10); /* signals exec error (see below) */
}
}
#ifdef IPROCS
sighold(SIGCHLD);
#endif
dowait(pid, &status);
#ifdef IPROCS
sigrelse(SIGCHLD);
#endif
if (status == -10)
complain("[Exec failed]");
if (status < 0)
complain("[Exit %d]", status);
return (status == 0); /* 0 means successful */
}
joverc(file)
char *file;
{
char buf[LBSIZE],
lbuf[128];
int lnum = 0,
eof = FALSE;
jmp_buf savejmp;
int IfStatus = IF_UNBOUND;
File *fp;
fp = open_file(file, buf, F_READ, !COMPLAIN, QUIET);
if (fp == NIL)
return NIL;
/* Catch any errors, here, and do the right thing with them,
and then restore the error handle to whoever did a setjmp
last. */
push_env(savejmp);
if (setjmp(mainjmp)) {
Buffer *savebuf = curbuf;
SetBuf(do_select((Window *) 0, "RC errors"));
ins_str(sprint("%s:%d:%s\t%s\n", pr_name(file), lnum, lbuf, mesgbuf), NO);
unmodify();
SetBuf(savebuf);
Asking = 0;
}
InJoverc = 1;
if (!eof) do {
eof = (f_gets(fp, lbuf, sizeof lbuf) == EOF);
lnum++;
if (casencmp(lbuf, "if", 2) == 0) {
char cmd[128];
if (IfStatus != IF_UNBOUND)
complain("[Cannot have nested if's]");
if (LookingAt("if[ \t]*\\(.*\\)$", lbuf, 0) == 0)
complain("[If syntax error]");
putmatch(1, cmd, sizeof cmd);
IfStatus = do_if(cmd) ? IF_TRUE : IF_FALSE;
continue;
} else if (casencmp(lbuf, "else", 4) == 0) {
if (IfStatus == IF_UNBOUND)
complain("[Unexpected `else']");
IfStatus = !IfStatus;
continue;
} else if (casencmp(lbuf, "endif", 5) == 0) {
if (IfStatus == IF_UNBOUND)
complain("[Unexpected `endif']");
IfStatus = IF_UNBOUND;
continue;
}
if (IfStatus == IF_FALSE)
continue;
(void) strcat(lbuf, "\n");
Inputp = lbuf;
while (*Inputp == ' ' || *Inputp == '\t')
Inputp++; /* skip white space */
Extend();
} while (!eof);
f_close(fp);
pop_env(savejmp);
Inputp = 0;
Asking = 0;
InJoverc = 0;
if (IfStatus != IF_UNBOUND)
complain("[Missing endif]");
return !NIL;
}