-/* Copyright (c) 1979 Regents of the University of California */
+/* Copyright (c) 1980 Regents of the University of California */
+static char *sccsid = "@(#)ex_cmdsub.c 6.1 %G%";
#include "ex.h"
#include "ex_argv.h"
#include "ex_temp.h"
#include "ex_tty.h"
+#include "ex_vis.h"
/*
* Command mode subroutines implementing
bool endline = 1;
line *tad1;
+static jnoop();
/*
* Append after line a lines returned by function f.
nline = 0;
dot = a;
- /*
- * This is probably a bug, since it's different than the other tests
- * in appendnone, delete, and deletenone. It is known to fail for
- * the command :g/foo/r xxx (where there is one foo and the file
- * xxx exists) and you try to undo it. I'm leaving it in for now
- * because I'm afraid if I change it I'll break something.
- */
- if (!inglobal && !inopen && f != getsub) {
+ if(FIXUNDO && !inopen && f!=getsub) {
undap1 = undap2 = dot + 1;
undkind = UNDCHANGE;
}
while ((*f)() == 0) {
if (truedol >= endcore) {
if (morelines() < 0) {
- if (!inglobal && f == getsub) {
+ if (FIXUNDO && f == getsub) {
undap1 = addr1;
undap2 = addr2 + 1;
}
appendnone()
{
- if (inopen >= 0 && (inopen || !inglobal)) {
+ if(FIXUNDO) {
undkind = UNDCHANGE;
undap1 = undap2 = addr1;
}
register line *a1, *a2;
nonzero();
- if (inopen >= 0 && (inopen || !inglobal)) {
+ if(FIXUNDO) {
register int (*dsavint)();
+#ifdef TRACE
+ if (trace)
+ vudump("before delete");
+#endif
change();
dsavint = signal(SIGINT, SIG_IGN);
undkind = UNDCHANGE;
dot = a1;
pkill[0] = pkill[1] = 0;
signal(SIGINT, dsavint);
+#ifdef TRACE
+ if (trace)
+ vudump("after delete");
+#endif
} else {
register line *a3;
register int i;
deletenone()
{
- if (inopen >= 0 && (inopen || !inglobal)) {
+ if(FIXUNDO) {
undkind = UNDCHANGE;
squish();
unddel = addr1;
{
register line *a1 = dol + 1, *a2 = unddol + 1, *a3 = truedol + 1;
- if (inopen == -1)
- return;
- if (a1 < a2 && a2 < a3)
- do
- *a1++ = *a2++;
- while (a2 < a3);
- truedol -= unddol - dol;
- unddol = dol;
+ if(FIXUNDO) {
+ if (inopen == -1)
+ return;
+ if (a1 < a2 && a2 < a3)
+ do
+ *a1++ = *a2++;
+ while (a2 < a3);
+ truedol -= unddol - dol;
+ unddol = dol;
+ }
}
/*
strcLIN(genbuf);
delete(0);
jcount = 1;
+ if (FIXUNDO)
+ undap1 = undap2 = addr1;
ignore(append(jnoop, --addr1));
+ if (FIXUNDO)
+ vundkind = VMANY;
}
static
error("Move to a moved line");
change();
if (!inglobal)
- if (cflag) {
- undap1 = addrt + 1;
- undap2 = undap1 + lines;
- deletenone();
- } else {
- undkind = UNDMOVE;
- undap1 = addr1;
- undap2 = addr2;
- unddel = addrt;
- squish();
+ if(FIXUNDO) {
+ if (cflag) {
+ undap1 = addrt + 1;
+ undap2 = undap1 + lines;
+ deletenone();
+ } else {
+ undkind = UNDMOVE;
+ undap1 = addr1;
+ undap2 = addr2;
+ unddel = addrt;
+ squish();
+ }
}
}
{
register int cnt;
+ if (!FIXUNDO)
+ error("Cannot put inside global/macro");
cnt = unddol - dol;
if (cnt && inopen && pkill[0] && pkill[1]) {
pragged(1);
char *dp;
register int i;
- if (!inglobal)
+ if(FIXUNDO)
save12(), undkind = UNDCHANGE;
cnt *= value(SHIFTWIDTH);
for (addr = addr1; addr <= addr2; addr++) {
{
char cmdbuf[BUFSIZ];
char filebuf[FNSIZE];
+ char tagfbuf[128];
register int c, d;
bool samef = 1;
- bool notagsfile = 0;
- short master = -1;
- short omagic;
+ int tfcount = 0;
+ int omagic;
+ char *fn, *fne;
+#ifdef VMUNIX
+ /*
+ * We have lots of room so we bring in stdio and do
+ * a binary search on the tags file.
+ */
+# undef EOF
+# include <stdio.h>
+# undef getchar
+# undef putchar
+ FILE *iof;
+ char iofbuf[BUFSIZ];
+ long mid; /* assumed byte offset */
+ long top, bot; /* length of tag file */
+ struct stat sbuf;
+#endif
omagic = value(MAGIC);
- value(MAGIC) = 0; /* force nomagic mode for tags */
if (!skipend()) {
register char *lp = lasttag;
if (c == EOF)
ungetchar(c);
clrstats();
- do {
- io = open(master ? "tags" : MASTERTAGS, 0);
- if (master && io < 0)
- notagsfile = 1;
+
+ /*
+ * Loop once for each file in tags "path".
+ */
+ CP(tagfbuf, svalue(TAGS));
+ fne = tagfbuf - 1;
+ while (fne) {
+ fn = ++fne;
+ while (*fne && *fne != ' ')
+ fne++;
+ if (*fne == 0)
+ fne = 0; /* done, quit after this time */
+ else
+ *fne = 0; /* null terminate filename */
+#ifdef VMUNIX
+ iof = fopen(fn, "r");
+ if (iof == NULL)
+ continue;
+ tfcount++;
+ setbuf(iof, iofbuf);
+ fstat(fileno(iof), &sbuf);
+ top = sbuf.st_size;
+ if (top == 0L || iof == NULL)
+ top = -1L;
+ bot = 0L;
+ while (top >= bot) {
+#else
+ /*
+ * Avoid stdio and scan tag file linearly.
+ */
+ io = open(fn, 0);
+ if (io<0)
+ continue;
+ tfcount++;
while (getfile() == 0) {
+#endif
+ /* loop for each tags file entry */
register char *cp = linebuf;
register char *lp = lasttag;
char *oglobp;
+#ifdef VMUNIX
+ mid = (top + bot) / 2;
+ fseek(iof, mid, 0);
+ if (mid > 0) /* to get first tag in file to work */
+ /* scan to next \n */
+ if(fgets(linebuf, sizeof linebuf, iof)==NULL)
+ goto goleft;
+ /* get the line itself */
+ if(fgets(linebuf, sizeof linebuf, iof)==NULL)
+ goto goleft;
+ linebuf[strlen(linebuf)-1] = 0; /* was '\n' */
+#endif
while (*cp && *lp == *cp)
cp++, lp++;
- if (*lp || !iswhite(*cp))
+ if ((*lp || !iswhite(*cp)) && (value(TAGLENGTH)==0 || lp-lasttag < value(TAGLENGTH))) {
+#ifdef VMUNIX
+ if (*lp > *cp)
+ bot = mid + 1;
+ else
+goleft:
+ top = mid - 1;
+#endif
+ /* Not this tag. Try the next */
continue;
+ }
+
+ /*
+ * We found the tag. Decode the line in the file.
+ */
+#ifdef VMUNIX
+ fclose(iof);
+#else
close(io);
+#endif
+ /* Rest of tag if abbreviated */
+ while (!iswhite(*cp))
+ cp++;
+
+ /* name of file */
while (*cp && iswhite(*cp))
cp++;
if (!*cp)
cp++;
}
*lp++ = 0;
+
if (*cp == 0)
goto badtags;
if (dol != zero) {
*/
names['t'-'a'] = *dot &~ 01;
if (inopen) {
- extern char *ncols['z'-'a'+1];
+ extern char *ncols['z'-'a'+2];
extern char *cursor;
ncols['t'-'a'] = cursor;
if (strcmp(filebuf, savedfile) || !edited) {
char cmdbuf2[sizeof filebuf + 10];
+ /* Different file. Do autowrite & get it. */
if (!quick) {
ckaw();
if (chng && dol > zero)
commands(1, 1);
peekc = d;
globp = oglobp;
+ value(MAGIC) = omagic;
samef = 0;
}
+
+ /*
+ * Look for pattern in the current file.
+ */
oglobp = globp;
globp = cmdbuf;
d = peekc; ungetchar(0);
if (samef)
markpr(dot);
+ /*
+ * BUG: if it isn't found (user edited header
+ * line) we get left in nomagic mode.
+ */
+ value(MAGIC) = 0;
commands(1, 1);
peekc = d;
globp = oglobp;
value(MAGIC) = omagic;
return;
- }
- } while (++master == 0);
- if (notagsfile)
+ } /* end of "for each tag in file" */
+
+ /*
+ * No such tag in this file. Close it and try the next.
+ */
+#ifdef VMUNIX
+ fclose(iof);
+#else
+ close(io);
+#endif
+ } /* end of "for each file in path" */
+ if (tfcount <= 0)
error("No tags file");
- serror("%s: No such tag@in tags file", lasttag);
+ else
+ serror("%s: No such tag@in tags file", lasttag);
}
/*
yank()
{
+ if (!FIXUNDO)
+ error("Can't yank inside global/macro");
save12();
undkind = UNDNONE;
killcnt(addr2 - addr1 + 1);
register line *jp, *kp;
line *dolp1, *newdol, *newadot;
+#ifdef TRACE
+ if (trace)
+ vudump("before undo");
+#endif
if (inglobal && inopen <= 0)
error("Can't undo in global@commands");
if (!c)
if (undkind == UNDALL) {
dot = undadot;
undadot = newadot;
- }
- undkind = UNDCHANGE;
+ } else
+ undkind = UNDCHANGE;
}
- if (dot == zero && dot != dol)
+ /*
+ * Defensive programming - after a munged undadot.
+ * Also handle empty buffer case.
+ */
+ if ((dot <= zero || dot > dol) && dot != dol)
dot = one;
+#ifdef TRACE
+ if (trace)
+ vudump("after undo");
+#endif
}
/*
* Map command:
* map src dest
*/
-mapcmd(un)
+mapcmd(un, ab)
int un; /* true if this is unmap command */
+ int ab; /* true if this is abbr command */
{
- char lhs[10], rhs[100]; /* max sizes resp. */
+ char lhs[100], rhs[100]; /* max sizes resp. */
register char *p;
register char c;
char *dname;
+ struct maps *mp; /* the map structure we are working on */
+ mp = ab ? abbrevs : exclam() ? immacs : arrows;
if (skipend()) {
int i;
/* print current mapping values */
if (peekchar() != EOF)
ignchar();
+ if (un)
+ error("Missing lhs");
if (inopen)
pofix();
- for (i=0; arrows[i].mapto; i++)
- if (arrows[i].cap) {
- lprintf("%s", arrows[i].descr);
+ for (i=0; mp[i].mapto; i++)
+ if (mp[i].cap) {
+ lprintf("%s", mp[i].descr);
putchar('\t');
- lprintf("%s", arrows[i].cap);
+ lprintf("%s", mp[i].cap);
putchar('\t');
- lprintf("%s", arrows[i].mapto);
+ lprintf("%s", mp[i].mapto);
putNFL();
}
return;
c = getchar();
if (c == CTRL(v)) {
c = getchar();
- } else if (any(c, " \t")) {
- if (un)
- eol(); /* will usually cause an error */
- else
- break;
- } else if (endcmd(c)) {
+ } else if (!un && any(c, " \t")) {
+ /* End of lhs */
+ break;
+ } else if (endcmd(c) && c!='"') {
ungetchar(c);
if (un) {
newline();
- addmac(lhs, NOSTR, NOSTR);
+ *p = 0;
+ addmac(lhs, NOSTR, NOSTR, mp);
return;
} else
error("Missing rhs");
c = getchar();
if (c == CTRL(v)) {
c = getchar();
- } else if (endcmd(c)) {
+ } else if (endcmd(c) && c!='"') {
ungetchar(c);
break;
}
} else {
dname = lhs;
}
- addmac(lhs,rhs,dname);
+ addmac(lhs,rhs,dname,mp);
}
/*
* Add a macro definition to those that already exist. The sequence of
* chars "src" is mapped into "dest". If src is already mapped into something
* this overrides the mapping. There is no recursion. Unmap is done by
- * using NOSTR for dest.
+ * using NOSTR for dest. Dname is what to show in listings. mp is
+ * the structure to affect (arrows, etc).
*/
-addmac(src,dest,dname)
+addmac(src,dest,dname,mp)
register char *src, *dest, *dname;
+ register struct maps *mp;
{
register int slot, zer;
- if (dest) {
+#ifdef TRACE
+ if (trace)
+ fprintf(trace, "addmac(src='%s', dest='%s', dname='%s', mp=%x\n", src, dest, dname, mp);
+#endif
+ if (dest && mp==arrows) {
/* Make sure user doesn't screw himself */
/*
- * Prevent head and tail recursion. We really should be
- * checking to see if src is a prefix or suffix of dest
- * but we are too lazy here, so we don't bother unless
- * src is only 1 char long.
+ * Prevent tail recursion. We really should be
+ * checking to see if src is a suffix of dest
+ * but this makes mapping involving escapes that
+ * is reasonable mess up.
*/
- if (src[1] == 0 && (src[0] == dest[0] || src[0] == dest[strlen(dest)-1]))
- error("No recursion");
+ if (src[1] == 0 && src[0] == dest[strlen(dest)-1])
+ error("No tail recursion");
/*
* We don't let the user rob himself of ":", and making
* multi char words is a bad idea so we don't allow it.
*/
if (isalpha(src[0]) && src[1] || any(src[0],":"))
error("Too dangerous to map that");
- /*
- * If the src were null it would cause the dest to
- * be mapped always forever. This is not good.
- */
- if (src[0] == 0)
- error("Null lhs");
}
+ else if (dest) {
+ /* check for tail recursion in input mode: fussier */
+ if (eq(src, dest+strlen(dest)-strlen(src)))
+ error("No tail recursion");
+ }
+ /*
+ * If the src were null it would cause the dest to
+ * be mapped always forever. This is not good.
+ */
+ if (src == NOSTR || src[0] == 0)
+ error("Missing lhs");
/* see if we already have a def for src */
zer = -1;
- for (slot=0; arrows[slot].mapto; slot++) {
- if (arrows[slot].cap) {
- if (eq(src, arrows[slot].cap))
+ for (slot=0; mp[slot].mapto; slot++) {
+ if (mp[slot].cap) {
+ if (eq(src, mp[slot].cap) || eq(src, mp[slot].mapto))
break; /* if so, reuse slot */
} else {
zer = slot; /* remember an empty slot */
if (dest == NOSTR) {
/* unmap */
- if (arrows[slot].cap) {
- arrows[slot].cap = NOSTR;
- arrows[slot].descr = NOSTR;
+ if (mp[slot].cap) {
+ mp[slot].cap = NOSTR;
+ mp[slot].descr = NOSTR;
} else {
error("Not mapped|That macro wasn't mapped");
}
}
/* reuse empty slot, if we found one and src isn't already defined */
- if (zer >= 0 && arrows[slot].mapto == 0)
+ if (zer >= 0 && mp[slot].mapto == 0)
slot = zer;
/* if not, append to end */
if (msnext - mapspace + strlen(dest) + strlen(src) + strlen(dname) + 3 > MAXCHARMACS)
error("Too much macro text");
CP(msnext, src);
- arrows[slot].cap = msnext;
+ mp[slot].cap = msnext;
msnext += strlen(src) + 1; /* plus 1 for null on the end */
CP(msnext, dest);
- arrows[slot].mapto = msnext;
+ mp[slot].mapto = msnext;
msnext += strlen(dest) + 1;
if (dname) {
CP(msnext, dname);
- arrows[slot].descr = msnext;
+ mp[slot].descr = msnext;
msnext += strlen(dname) + 1;
} else {
/* default descr to string user enters */
- arrows[slot].descr = src;
+ mp[slot].descr = src;
}
}