17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
523a1cceaSRoger A. Faulkner * Common Development and Distribution License (the "License").
623a1cceaSRoger A. Faulkner * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
2123a1cceaSRoger A. Faulkner
22f6db9f27Scf /*
2323a1cceaSRoger A. Faulkner * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
2448bbca81SDaniel Hoffman * Copyright (c) 2016 by Delphix. All rights reserved.
25f6db9f27Scf */
26f6db9f27Scf
277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
287c478bd9Sstevel@tonic-gate /* All Rights Reserved */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate /* Copyright (c) 1981 Regents of the University of California */
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate #include "ex.h"
347c478bd9Sstevel@tonic-gate #include "ex_argv.h"
357c478bd9Sstevel@tonic-gate #include "ex_temp.h"
367c478bd9Sstevel@tonic-gate #include "ex_tty.h"
377c478bd9Sstevel@tonic-gate #include "ex_vis.h"
387c478bd9Sstevel@tonic-gate #ifdef STDIO
397c478bd9Sstevel@tonic-gate #include <stdio.h>
407c478bd9Sstevel@tonic-gate #undef getchar
417c478bd9Sstevel@tonic-gate #undef putchar
427c478bd9Sstevel@tonic-gate #endif
436a3e8e86SRichard Lowe
446a3e8e86SRichard Lowe
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate * Command mode subroutines implementing
477c478bd9Sstevel@tonic-gate * append, args, copy, delete, join, move, put,
487c478bd9Sstevel@tonic-gate * shift, tag, yank, z and undo
497c478bd9Sstevel@tonic-gate */
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate bool endline = 1;
527c478bd9Sstevel@tonic-gate line *tad1;
53f6db9f27Scf static int jnoop(void);
54f6db9f27Scf static void splitit(void);
55f6db9f27Scf int putchar(), getchar();
567c478bd9Sstevel@tonic-gate int tags_flag;
577c478bd9Sstevel@tonic-gate
587c478bd9Sstevel@tonic-gate /*
597c478bd9Sstevel@tonic-gate * Append after line a lines returned by function f.
607c478bd9Sstevel@tonic-gate * Be careful about intermediate states to avoid scramble
617c478bd9Sstevel@tonic-gate * if an interrupt comes in.
627c478bd9Sstevel@tonic-gate */
63f6db9f27Scf int
append(int (* f)(),line * a)64f6db9f27Scf append(int (*f)(), line *a)
657c478bd9Sstevel@tonic-gate {
66f6db9f27Scf line *a1, *a2, *rdot;
677c478bd9Sstevel@tonic-gate int nline;
687c478bd9Sstevel@tonic-gate
697c478bd9Sstevel@tonic-gate nline = 0;
707c478bd9Sstevel@tonic-gate dot = a;
717c478bd9Sstevel@tonic-gate if(FIXUNDO && !inopen && f!=getsub) {
727c478bd9Sstevel@tonic-gate undap1 = undap2 = dot + 1;
737c478bd9Sstevel@tonic-gate undkind = UNDCHANGE;
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate while ((*f)() == 0) {
767c478bd9Sstevel@tonic-gate if (truedol >= endcore) {
777c478bd9Sstevel@tonic-gate if (morelines() < 0) {
787c478bd9Sstevel@tonic-gate if (FIXUNDO && f == getsub) {
797c478bd9Sstevel@tonic-gate undap1 = addr1;
807c478bd9Sstevel@tonic-gate undap2 = addr2 + 1;
817c478bd9Sstevel@tonic-gate }
827c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Out of memory") :
837c478bd9Sstevel@tonic-gate gettext("Out of memory- too many lines in file"));
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate nline++;
877c478bd9Sstevel@tonic-gate a1 = truedol + 1;
887c478bd9Sstevel@tonic-gate a2 = a1 + 1;
897c478bd9Sstevel@tonic-gate dot++;
907c478bd9Sstevel@tonic-gate undap2++;
917c478bd9Sstevel@tonic-gate dol++;
927c478bd9Sstevel@tonic-gate unddol++;
937c478bd9Sstevel@tonic-gate truedol++;
947c478bd9Sstevel@tonic-gate for (rdot = dot; a1 > rdot;)
957c478bd9Sstevel@tonic-gate *--a2 = *--a1;
967c478bd9Sstevel@tonic-gate *rdot = 0;
977c478bd9Sstevel@tonic-gate putmark(rdot);
987c478bd9Sstevel@tonic-gate if (f == gettty) {
997c478bd9Sstevel@tonic-gate dirtcnt++;
1007c478bd9Sstevel@tonic-gate TSYNC();
1017c478bd9Sstevel@tonic-gate }
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate return (nline);
1047c478bd9Sstevel@tonic-gate }
1057c478bd9Sstevel@tonic-gate
106f6db9f27Scf void
appendnone(void)107f6db9f27Scf appendnone(void)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate if(FIXUNDO) {
1117c478bd9Sstevel@tonic-gate undkind = UNDCHANGE;
1127c478bd9Sstevel@tonic-gate undap1 = undap2 = addr1;
1137c478bd9Sstevel@tonic-gate }
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate /*
1177c478bd9Sstevel@tonic-gate * Print out the argument list, with []'s around the current name.
1187c478bd9Sstevel@tonic-gate */
119f6db9f27Scf void
pargs(void)120f6db9f27Scf pargs(void)
1217c478bd9Sstevel@tonic-gate {
122f6db9f27Scf unsigned char **av = argv0, *as = args0;
123f6db9f27Scf int ac;
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate for (ac = 0; ac < argc0; ac++) {
1267c478bd9Sstevel@tonic-gate if (ac != 0)
1277c478bd9Sstevel@tonic-gate putchar(' ');
1287c478bd9Sstevel@tonic-gate if (ac + argc == argc0 - 1)
129f6db9f27Scf viprintf("[");
1307c478bd9Sstevel@tonic-gate lprintf("%s", as);
1317c478bd9Sstevel@tonic-gate if (ac + argc == argc0 - 1)
132f6db9f27Scf viprintf("]");
1337c478bd9Sstevel@tonic-gate as = av ? *++av : strend(as) + 1;
1347c478bd9Sstevel@tonic-gate }
1357c478bd9Sstevel@tonic-gate noonl();
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate * Delete lines; two cases are if we are really deleting,
1407c478bd9Sstevel@tonic-gate * more commonly we are just moving lines to the undo save area.
1417c478bd9Sstevel@tonic-gate */
142f6db9f27Scf int
delete(bool hush)143f6db9f27Scf delete(bool hush)
1447c478bd9Sstevel@tonic-gate {
145f6db9f27Scf line *a1, *a2;
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate nonzero();
1487c478bd9Sstevel@tonic-gate if(FIXUNDO) {
1497c478bd9Sstevel@tonic-gate void (*dsavint)();
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
1527c478bd9Sstevel@tonic-gate if (trace)
1537c478bd9Sstevel@tonic-gate vudump("before delete");
1547c478bd9Sstevel@tonic-gate #endif
1557c478bd9Sstevel@tonic-gate change();
1567c478bd9Sstevel@tonic-gate dsavint = signal(SIGINT, SIG_IGN);
1577c478bd9Sstevel@tonic-gate undkind = UNDCHANGE;
1587c478bd9Sstevel@tonic-gate a1 = addr1;
1597c478bd9Sstevel@tonic-gate squish();
1607c478bd9Sstevel@tonic-gate a2 = addr2;
1617c478bd9Sstevel@tonic-gate if (a2++ != dol) {
1627c478bd9Sstevel@tonic-gate reverse(a1, a2);
1637c478bd9Sstevel@tonic-gate reverse(a2, dol + 1);
1647c478bd9Sstevel@tonic-gate reverse(a1, dol + 1);
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate dol -= a2 - a1;
1677c478bd9Sstevel@tonic-gate unddel = a1 - 1;
1687c478bd9Sstevel@tonic-gate if (a1 > dol)
1697c478bd9Sstevel@tonic-gate a1 = dol;
1707c478bd9Sstevel@tonic-gate dot = a1;
1717c478bd9Sstevel@tonic-gate pkill[0] = pkill[1] = 0;
1727c478bd9Sstevel@tonic-gate signal(SIGINT, dsavint);
1737c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
1747c478bd9Sstevel@tonic-gate if (trace)
1757c478bd9Sstevel@tonic-gate vudump("after delete");
1767c478bd9Sstevel@tonic-gate #endif
1777c478bd9Sstevel@tonic-gate } else {
178f6db9f27Scf line *a3;
179f6db9f27Scf int i;
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate change();
1827c478bd9Sstevel@tonic-gate a1 = addr1;
1837c478bd9Sstevel@tonic-gate a2 = addr2 + 1;
1847c478bd9Sstevel@tonic-gate a3 = truedol;
1857c478bd9Sstevel@tonic-gate i = a2 - a1;
1867c478bd9Sstevel@tonic-gate unddol -= i;
1877c478bd9Sstevel@tonic-gate undap2 -= i;
1887c478bd9Sstevel@tonic-gate dol -= i;
1897c478bd9Sstevel@tonic-gate truedol -= i;
1907c478bd9Sstevel@tonic-gate do
1917c478bd9Sstevel@tonic-gate *a1++ = *a2++;
1927c478bd9Sstevel@tonic-gate while (a2 <= a3);
1937c478bd9Sstevel@tonic-gate a1 = addr1;
1947c478bd9Sstevel@tonic-gate if (a1 > dol)
1957c478bd9Sstevel@tonic-gate a1 = dol;
1967c478bd9Sstevel@tonic-gate dot = a1;
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate if (!hush)
1997c478bd9Sstevel@tonic-gate killed();
200f6db9f27Scf return (0);
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate
203f6db9f27Scf void
deletenone(void)204f6db9f27Scf deletenone(void)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate if(FIXUNDO) {
2087c478bd9Sstevel@tonic-gate undkind = UNDCHANGE;
2097c478bd9Sstevel@tonic-gate squish();
2107c478bd9Sstevel@tonic-gate unddel = addr1;
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate * Crush out the undo save area, moving the open/visual
2167c478bd9Sstevel@tonic-gate * save area down in its place.
2177c478bd9Sstevel@tonic-gate */
218f6db9f27Scf void
squish(void)219f6db9f27Scf squish(void)
2207c478bd9Sstevel@tonic-gate {
221f6db9f27Scf line *a1 = dol + 1, *a2 = unddol + 1, *a3 = truedol + 1;
2227c478bd9Sstevel@tonic-gate
2237c478bd9Sstevel@tonic-gate if(FIXUNDO) {
2247c478bd9Sstevel@tonic-gate if (inopen == -1)
2257c478bd9Sstevel@tonic-gate return;
2267c478bd9Sstevel@tonic-gate if (a1 < a2 && a2 < a3)
2277c478bd9Sstevel@tonic-gate do
2287c478bd9Sstevel@tonic-gate *a1++ = *a2++;
2297c478bd9Sstevel@tonic-gate while (a2 < a3);
2307c478bd9Sstevel@tonic-gate truedol -= unddol - dol;
2317c478bd9Sstevel@tonic-gate unddol = dol;
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate /*
2367c478bd9Sstevel@tonic-gate * Join lines. Special hacks put in spaces, two spaces if
2377c478bd9Sstevel@tonic-gate * preceding line ends with '.', or no spaces if next line starts with ).
2387c478bd9Sstevel@tonic-gate */
239f6db9f27Scf static int jcount;
2407c478bd9Sstevel@tonic-gate
241f6db9f27Scf int
join(int c)242f6db9f27Scf join(int c)
2437c478bd9Sstevel@tonic-gate {
244f6db9f27Scf line *a1;
245f6db9f27Scf unsigned char *cp, *cp1;
2467c478bd9Sstevel@tonic-gate #ifndef PRESUNEUC
247f6db9f27Scf unsigned char *pcp;
248f6db9f27Scf wchar_t *delim;
2497c478bd9Sstevel@tonic-gate wchar_t wc1, wc2;
2507c478bd9Sstevel@tonic-gate int n;
2517c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
2527c478bd9Sstevel@tonic-gate
2537c478bd9Sstevel@tonic-gate cp = genbuf;
2547c478bd9Sstevel@tonic-gate *cp = 0;
2557c478bd9Sstevel@tonic-gate for (a1 = addr1; a1 <= addr2; a1++) {
25623a1cceaSRoger A. Faulkner getaline(*a1);
2577c478bd9Sstevel@tonic-gate cp1 = linebuf;
2587c478bd9Sstevel@tonic-gate if (a1 != addr1 && c == 0) {
2597c478bd9Sstevel@tonic-gate while (*cp1 == ' ' || *cp1 == '\t')
2607c478bd9Sstevel@tonic-gate cp1++;
2617c478bd9Sstevel@tonic-gate if (*cp1 && cp > genbuf && cp[-1] != ' ' && cp[-1] != '\t') {
2627c478bd9Sstevel@tonic-gate #ifndef PRESUNEUC
2637c478bd9Sstevel@tonic-gate /*
2647c478bd9Sstevel@tonic-gate * insert locale-specific word delimiter if
2657c478bd9Sstevel@tonic-gate * either of end-of-former-line or
2667c478bd9Sstevel@tonic-gate * top-of-latter-line is non-ASCII.
2677c478bd9Sstevel@tonic-gate */
2687c478bd9Sstevel@tonic-gate if (wddlm && *cp1 != ')' && cp[-1] != '.') {
2697c478bd9Sstevel@tonic-gate if ((pcp = cp - MB_CUR_MAX) < genbuf)
2707c478bd9Sstevel@tonic-gate pcp = genbuf;;
2717c478bd9Sstevel@tonic-gate for ( ; pcp <= cp-1; pcp++) {
2727c478bd9Sstevel@tonic-gate if ((n = mbtowc(&wc1,
2737c478bd9Sstevel@tonic-gate (char *)pcp, cp - pcp)) ==
2747c478bd9Sstevel@tonic-gate cp - pcp)
2757c478bd9Sstevel@tonic-gate goto gotprev;
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate goto mberror;
2787c478bd9Sstevel@tonic-gate gotprev:
2797c478bd9Sstevel@tonic-gate if (!isascii(wc2 = *cp1)) {
2807c478bd9Sstevel@tonic-gate if (mbtowc(&wc2, (char *) cp1,
2817c478bd9Sstevel@tonic-gate MB_CUR_MAX) <= 0)
2827c478bd9Sstevel@tonic-gate goto mberror;
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate delim = (*wddlm)(wc1,wc2,2);
2857c478bd9Sstevel@tonic-gate while (*delim)
2867c478bd9Sstevel@tonic-gate cp += wctomb((char *)cp,
2877c478bd9Sstevel@tonic-gate *delim++);
2887c478bd9Sstevel@tonic-gate *cp = 0;
2897c478bd9Sstevel@tonic-gate } else
2907c478bd9Sstevel@tonic-gate mberror:
2917c478bd9Sstevel@tonic-gate #endif /* PRESUNEUC */
2927c478bd9Sstevel@tonic-gate if (*cp1 != ')') {
2937c478bd9Sstevel@tonic-gate *cp++ = ' ';
2947c478bd9Sstevel@tonic-gate if (cp[-2] == '.')
2957c478bd9Sstevel@tonic-gate *cp++ = ' ';
2967c478bd9Sstevel@tonic-gate }
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate while (*cp++ = *cp1++)
3007c478bd9Sstevel@tonic-gate if (cp > &genbuf[LBSIZE-2])
3017c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Line overflow") :
3027c478bd9Sstevel@tonic-gate gettext("Result line of join would be too long"));
3037c478bd9Sstevel@tonic-gate cp--;
3047c478bd9Sstevel@tonic-gate }
3057c478bd9Sstevel@tonic-gate strcLIN(genbuf);
306f6db9f27Scf (void) delete(0);
3077c478bd9Sstevel@tonic-gate jcount = 1;
3087c478bd9Sstevel@tonic-gate if (FIXUNDO)
3097c478bd9Sstevel@tonic-gate undap1 = undap2 = addr1;
3107c478bd9Sstevel@tonic-gate (void)append(jnoop, --addr1);
3117c478bd9Sstevel@tonic-gate if (FIXUNDO)
3127c478bd9Sstevel@tonic-gate vundkind = VMANY;
313f6db9f27Scf return (0);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate
316f6db9f27Scf static int
jnoop(void)317f6db9f27Scf jnoop(void)
3187c478bd9Sstevel@tonic-gate {
3197c478bd9Sstevel@tonic-gate
3207c478bd9Sstevel@tonic-gate return(--jcount);
3217c478bd9Sstevel@tonic-gate }
3227c478bd9Sstevel@tonic-gate
3237c478bd9Sstevel@tonic-gate /*
3247c478bd9Sstevel@tonic-gate * Move and copy lines. Hard work is done by move1 which
3257c478bd9Sstevel@tonic-gate * is also called by undo.
3267c478bd9Sstevel@tonic-gate */
3277c478bd9Sstevel@tonic-gate int getcopy();
3287c478bd9Sstevel@tonic-gate
329f6db9f27Scf void
vi_move(void)330f6db9f27Scf vi_move(void)
3317c478bd9Sstevel@tonic-gate {
332f6db9f27Scf line *adt;
3337c478bd9Sstevel@tonic-gate bool iscopy = 0;
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate if (Command[0] == 'm') {
3367c478bd9Sstevel@tonic-gate setdot1();
3377c478bd9Sstevel@tonic-gate markpr(addr2 == dot ? addr1 - 1 : addr2 + 1);
3387c478bd9Sstevel@tonic-gate } else {
3397c478bd9Sstevel@tonic-gate iscopy++;
3407c478bd9Sstevel@tonic-gate setdot();
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate nonzero();
3437c478bd9Sstevel@tonic-gate adt = address((char*)0);
3447c478bd9Sstevel@tonic-gate if (adt == 0)
345f6db9f27Scf serror(value(vi_TERSE) ?
346f6db9f27Scf (unsigned char *)gettext("%s where?") :
347f6db9f27Scf (unsigned char *)gettext("%s requires a trailing address"),
348f6db9f27Scf Command);
3497c478bd9Sstevel@tonic-gate donewline();
3507c478bd9Sstevel@tonic-gate move1(iscopy, adt);
3517c478bd9Sstevel@tonic-gate killed();
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate
354f6db9f27Scf void
move1(int cflag,line * addrt)355f6db9f27Scf move1(int cflag, line *addrt)
3567c478bd9Sstevel@tonic-gate {
357f6db9f27Scf line *adt, *ad1, *ad2;
3587c478bd9Sstevel@tonic-gate int nlines;
3597c478bd9Sstevel@tonic-gate
3607c478bd9Sstevel@tonic-gate adt = addrt;
3617c478bd9Sstevel@tonic-gate nlines = (addr2 - addr1) + 1;
3627c478bd9Sstevel@tonic-gate if (cflag) {
3637c478bd9Sstevel@tonic-gate tad1 = addr1;
3647c478bd9Sstevel@tonic-gate ad1 = dol;
3657c478bd9Sstevel@tonic-gate (void)append(getcopy, ad1++);
3667c478bd9Sstevel@tonic-gate ad2 = dol;
3677c478bd9Sstevel@tonic-gate } else {
3687c478bd9Sstevel@tonic-gate ad2 = addr2;
3697c478bd9Sstevel@tonic-gate for (ad1 = addr1; ad1 <= ad2;)
3707c478bd9Sstevel@tonic-gate *ad1++ &= ~01;
3717c478bd9Sstevel@tonic-gate ad1 = addr1;
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate ad2++;
3747c478bd9Sstevel@tonic-gate if (adt < ad1) {
3757c478bd9Sstevel@tonic-gate if (adt + 1 == ad1 && !cflag && !inglobal)
3767c478bd9Sstevel@tonic-gate error(gettext("That move would do nothing!"));
3777c478bd9Sstevel@tonic-gate dot = adt + (ad2 - ad1);
3787c478bd9Sstevel@tonic-gate if (++adt != ad1) {
3797c478bd9Sstevel@tonic-gate reverse(adt, ad1);
3807c478bd9Sstevel@tonic-gate reverse(ad1, ad2);
3817c478bd9Sstevel@tonic-gate reverse(adt, ad2);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate } else if (adt >= ad2) {
3847c478bd9Sstevel@tonic-gate dot = adt++;
3857c478bd9Sstevel@tonic-gate reverse(ad1, ad2);
3867c478bd9Sstevel@tonic-gate reverse(ad2, adt);
3877c478bd9Sstevel@tonic-gate reverse(ad1, adt);
3887c478bd9Sstevel@tonic-gate } else
3897c478bd9Sstevel@tonic-gate error(gettext("Move to a moved line"));
3907c478bd9Sstevel@tonic-gate change();
3917c478bd9Sstevel@tonic-gate if (!inglobal)
3927c478bd9Sstevel@tonic-gate if(FIXUNDO) {
3937c478bd9Sstevel@tonic-gate if (cflag) {
3947c478bd9Sstevel@tonic-gate undap1 = addrt + 1;
3957c478bd9Sstevel@tonic-gate undap2 = undap1 + nlines;
3967c478bd9Sstevel@tonic-gate deletenone();
3977c478bd9Sstevel@tonic-gate } else {
3987c478bd9Sstevel@tonic-gate undkind = UNDMOVE;
3997c478bd9Sstevel@tonic-gate undap1 = addr1;
4007c478bd9Sstevel@tonic-gate undap2 = addr2;
4017c478bd9Sstevel@tonic-gate unddel = addrt;
4027c478bd9Sstevel@tonic-gate squish();
4037c478bd9Sstevel@tonic-gate }
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate
407f6db9f27Scf int
getcopy(void)408f6db9f27Scf getcopy(void)
4097c478bd9Sstevel@tonic-gate {
4107c478bd9Sstevel@tonic-gate
4117c478bd9Sstevel@tonic-gate if (tad1 > addr2)
4127c478bd9Sstevel@tonic-gate return (EOF);
41323a1cceaSRoger A. Faulkner getaline(*tad1++);
4147c478bd9Sstevel@tonic-gate return (0);
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate /*
4187c478bd9Sstevel@tonic-gate * Put lines in the buffer from the undo save area.
4197c478bd9Sstevel@tonic-gate */
420f6db9f27Scf int
getput(void)421f6db9f27Scf getput(void)
4227c478bd9Sstevel@tonic-gate {
4237c478bd9Sstevel@tonic-gate
4247c478bd9Sstevel@tonic-gate if (tad1 > unddol)
4257c478bd9Sstevel@tonic-gate return (EOF);
42623a1cceaSRoger A. Faulkner getaline(*tad1++);
4277c478bd9Sstevel@tonic-gate tad1++;
4287c478bd9Sstevel@tonic-gate return (0);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate
431f6db9f27Scf int
put(void)432f6db9f27Scf put(void)
4337c478bd9Sstevel@tonic-gate {
434f6db9f27Scf int cnt;
4357c478bd9Sstevel@tonic-gate
4367c478bd9Sstevel@tonic-gate if (!FIXUNDO)
4377c478bd9Sstevel@tonic-gate error(gettext("Cannot put inside global/macro"));
4387c478bd9Sstevel@tonic-gate cnt = unddol - dol;
4397c478bd9Sstevel@tonic-gate if (cnt && inopen && pkill[0] && pkill[1]) {
4407c478bd9Sstevel@tonic-gate pragged(1);
441f6db9f27Scf return (0);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate tad1 = dol + 1;
4447c478bd9Sstevel@tonic-gate (void)append(getput, addr2);
4457c478bd9Sstevel@tonic-gate undkind = UNDPUT;
4467c478bd9Sstevel@tonic-gate notecnt = cnt;
4477c478bd9Sstevel@tonic-gate netchange(cnt);
448f6db9f27Scf return (0);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate
4517c478bd9Sstevel@tonic-gate /*
4527c478bd9Sstevel@tonic-gate * A tricky put, of a group of lines in the middle
4537c478bd9Sstevel@tonic-gate * of an existing line. Only from open/visual.
4547c478bd9Sstevel@tonic-gate * Argument says pkills have meaning, e.g. called from
4557c478bd9Sstevel@tonic-gate * put; it is 0 on calls from putreg.
4567c478bd9Sstevel@tonic-gate */
457f6db9f27Scf void
pragged(bool kill)458f6db9f27Scf pragged(bool kill)
4597c478bd9Sstevel@tonic-gate {
4607c478bd9Sstevel@tonic-gate extern unsigned char *cursor;
4617c478bd9Sstevel@tonic-gate #ifdef XPG4
4627c478bd9Sstevel@tonic-gate extern int P_cursor_offset;
4637c478bd9Sstevel@tonic-gate #endif
464f6db9f27Scf unsigned char *gp = &genbuf[cursor - linebuf];
4657c478bd9Sstevel@tonic-gate
4667c478bd9Sstevel@tonic-gate /*
4677c478bd9Sstevel@tonic-gate * Assume the editor has:
4687c478bd9Sstevel@tonic-gate *
4697c478bd9Sstevel@tonic-gate * cursor is on 'c'
4707c478bd9Sstevel@tonic-gate *
4717c478bd9Sstevel@tonic-gate * file is: 1) abcd
4727c478bd9Sstevel@tonic-gate * 2) efgh
4737c478bd9Sstevel@tonic-gate *
4747c478bd9Sstevel@tonic-gate * undo area: 3) 1
4757c478bd9Sstevel@tonic-gate * 4) 2
4767c478bd9Sstevel@tonic-gate * 5) 3
4777c478bd9Sstevel@tonic-gate */
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate if (!kill)
4807c478bd9Sstevel@tonic-gate getDOT();
48148bbca81SDaniel Hoffman
4827c478bd9Sstevel@tonic-gate /*
4837c478bd9Sstevel@tonic-gate * Copy "abcd" into genbuf.
4847c478bd9Sstevel@tonic-gate * Note that gp points to 'c'.
4857c478bd9Sstevel@tonic-gate */
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate strcpy(genbuf, linebuf);
48848bbca81SDaniel Hoffman
4897c478bd9Sstevel@tonic-gate /*
4907c478bd9Sstevel@tonic-gate * Get last line of undo area ("3") into linebuf.
4917c478bd9Sstevel@tonic-gate */
4927c478bd9Sstevel@tonic-gate
49323a1cceaSRoger A. Faulkner getaline(*unddol);
4947c478bd9Sstevel@tonic-gate if (kill)
4957c478bd9Sstevel@tonic-gate *pkill[1] = 0;
49648bbca81SDaniel Hoffman
4977c478bd9Sstevel@tonic-gate
4987c478bd9Sstevel@tonic-gate /*
4997c478bd9Sstevel@tonic-gate * Concatenate trailing end of current line
5007c478bd9Sstevel@tonic-gate * into the last line of undo area:
5017c478bd9Sstevel@tonic-gate * linebuf = "3cd"
5027c478bd9Sstevel@tonic-gate */
5037c478bd9Sstevel@tonic-gate
5047c478bd9Sstevel@tonic-gate strcat(linebuf, gp);
5057c478bd9Sstevel@tonic-gate #ifdef XPG4
5067c478bd9Sstevel@tonic-gate P_cursor_offset = strlen(linebuf) - strlen(gp) - 1;
5077c478bd9Sstevel@tonic-gate #endif
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate /*
5107c478bd9Sstevel@tonic-gate * Replace the last line with what is now in linebuf.
5117c478bd9Sstevel@tonic-gate * So unddol = "3cd"
5127c478bd9Sstevel@tonic-gate */
5137c478bd9Sstevel@tonic-gate
5147c478bd9Sstevel@tonic-gate putmark(unddol);
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate /*
5177c478bd9Sstevel@tonic-gate * Get the first line of the undo save area into linebuf.
5187c478bd9Sstevel@tonic-gate * So linebuf = "1"
5197c478bd9Sstevel@tonic-gate */
5207c478bd9Sstevel@tonic-gate
52123a1cceaSRoger A. Faulkner getaline(dol[1]);
5227c478bd9Sstevel@tonic-gate if (kill)
5237c478bd9Sstevel@tonic-gate strcLIN(pkill[0]);
52448bbca81SDaniel Hoffman
5257c478bd9Sstevel@tonic-gate /*
5267c478bd9Sstevel@tonic-gate * Copy the first line of the undo save area
5277c478bd9Sstevel@tonic-gate * over what is pointed to by sp.
5287c478bd9Sstevel@tonic-gate * genbuf = "ab1"
5297c478bd9Sstevel@tonic-gate */
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate strcpy(gp, linebuf);
53248bbca81SDaniel Hoffman
5337c478bd9Sstevel@tonic-gate /*
5347c478bd9Sstevel@tonic-gate * Now copy genbuf back into linebuf.
5357c478bd9Sstevel@tonic-gate * linebuf = "ab1"
5367c478bd9Sstevel@tonic-gate */
5377c478bd9Sstevel@tonic-gate
5387c478bd9Sstevel@tonic-gate strcLIN(genbuf);
5397c478bd9Sstevel@tonic-gate
5407c478bd9Sstevel@tonic-gate /*
5417c478bd9Sstevel@tonic-gate * Now put linebuf back into the first line
5427c478bd9Sstevel@tonic-gate * of the undo save area.
5437c478bd9Sstevel@tonic-gate */
5447c478bd9Sstevel@tonic-gate
5457c478bd9Sstevel@tonic-gate putmark(dol+1);
5467c478bd9Sstevel@tonic-gate
5477c478bd9Sstevel@tonic-gate /*
5487c478bd9Sstevel@tonic-gate * Prepare to perform an undo which will actually
5497c478bd9Sstevel@tonic-gate * do a put of multiple lines in the middle of
5507c478bd9Sstevel@tonic-gate * the current line.
5517c478bd9Sstevel@tonic-gate */
5527c478bd9Sstevel@tonic-gate
5537c478bd9Sstevel@tonic-gate undkind = UNDCHANGE;
5547c478bd9Sstevel@tonic-gate undap1 = dot;
5557c478bd9Sstevel@tonic-gate undap2 = dot + 1;
5567c478bd9Sstevel@tonic-gate unddel = dot - 1;
5577c478bd9Sstevel@tonic-gate undo(1);
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate
5607c478bd9Sstevel@tonic-gate /*
5617c478bd9Sstevel@tonic-gate * Shift lines, based on c.
5627c478bd9Sstevel@tonic-gate * If c is neither < nor >, then this is a lisp aligning =.
5637c478bd9Sstevel@tonic-gate */
564f6db9f27Scf void
shift(int c,int cnt)565f6db9f27Scf shift(int c, int cnt)
5667c478bd9Sstevel@tonic-gate {
567f6db9f27Scf line *addr;
568f6db9f27Scf unsigned char *cp;
5697c478bd9Sstevel@tonic-gate unsigned char *dp;
570f6db9f27Scf int i;
5717c478bd9Sstevel@tonic-gate
5727c478bd9Sstevel@tonic-gate if(FIXUNDO)
5737c478bd9Sstevel@tonic-gate save12(), undkind = UNDCHANGE;
5747c478bd9Sstevel@tonic-gate cnt *= value(vi_SHIFTWIDTH);
5757c478bd9Sstevel@tonic-gate for (addr = addr1; addr <= addr2; addr++) {
5767c478bd9Sstevel@tonic-gate dot = addr;
5777c478bd9Sstevel@tonic-gate if (c == '=' && addr == addr1 && addr != addr2)
5787c478bd9Sstevel@tonic-gate continue;
5797c478bd9Sstevel@tonic-gate getDOT();
5807c478bd9Sstevel@tonic-gate i = whitecnt(linebuf);
5817c478bd9Sstevel@tonic-gate switch (c) {
5827c478bd9Sstevel@tonic-gate
5837c478bd9Sstevel@tonic-gate case '>':
5847c478bd9Sstevel@tonic-gate if (linebuf[0] == 0)
5857c478bd9Sstevel@tonic-gate continue;
5867c478bd9Sstevel@tonic-gate cp = genindent(i + cnt);
5877c478bd9Sstevel@tonic-gate break;
5887c478bd9Sstevel@tonic-gate
5897c478bd9Sstevel@tonic-gate case '<':
5907c478bd9Sstevel@tonic-gate if (i == 0)
5917c478bd9Sstevel@tonic-gate continue;
5927c478bd9Sstevel@tonic-gate i -= cnt;
5937c478bd9Sstevel@tonic-gate cp = i > 0 ? genindent(i) : genbuf;
5947c478bd9Sstevel@tonic-gate break;
5957c478bd9Sstevel@tonic-gate
5967c478bd9Sstevel@tonic-gate default:
5977c478bd9Sstevel@tonic-gate i = lindent(addr);
5987c478bd9Sstevel@tonic-gate getDOT();
5997c478bd9Sstevel@tonic-gate cp = genindent(i);
6007c478bd9Sstevel@tonic-gate break;
6017c478bd9Sstevel@tonic-gate }
6027c478bd9Sstevel@tonic-gate if (cp + strlen(dp = vpastwh(linebuf)) >= &genbuf[LBSIZE - 2])
6037c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Line too long") :
6047c478bd9Sstevel@tonic-gate gettext("Result line after shift would be too long"));
6057c478bd9Sstevel@tonic-gate CP(cp, dp);
6067c478bd9Sstevel@tonic-gate strcLIN(genbuf);
6077c478bd9Sstevel@tonic-gate putmark(addr);
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate killed();
6107c478bd9Sstevel@tonic-gate }
6117c478bd9Sstevel@tonic-gate
6127c478bd9Sstevel@tonic-gate /*
6137c478bd9Sstevel@tonic-gate * Find a tag in the tags file.
6147c478bd9Sstevel@tonic-gate * Most work here is in parsing the tags file itself.
6157c478bd9Sstevel@tonic-gate */
616f6db9f27Scf void
tagfind(quick)6177c478bd9Sstevel@tonic-gate tagfind(quick)
6187c478bd9Sstevel@tonic-gate bool quick;
6197c478bd9Sstevel@tonic-gate {
6207c478bd9Sstevel@tonic-gate unsigned char cmdbuf[BUFSIZE];
6217c478bd9Sstevel@tonic-gate unsigned char filebuf[FNSIZE];
6227c478bd9Sstevel@tonic-gate unsigned char tagfbuf[BUFSIZE];
623f6db9f27Scf int c, d;
6247c478bd9Sstevel@tonic-gate bool samef = 1;
6257c478bd9Sstevel@tonic-gate int tfcount = 0;
6267c478bd9Sstevel@tonic-gate int omagic, tl;
6277c478bd9Sstevel@tonic-gate unsigned char *fn, *fne;
6287c478bd9Sstevel@tonic-gate #ifdef STDIO /* was VMUNIX */
6297c478bd9Sstevel@tonic-gate /*
6307c478bd9Sstevel@tonic-gate * We have lots of room so we bring in stdio and do
6317c478bd9Sstevel@tonic-gate * a binary search on the tags file.
6327c478bd9Sstevel@tonic-gate */
6337c478bd9Sstevel@tonic-gate FILE *iof;
6347c478bd9Sstevel@tonic-gate unsigned char iofbuf[BUFSIZE];
6357c478bd9Sstevel@tonic-gate off64_t mid; /* assumed byte offset */
6367c478bd9Sstevel@tonic-gate off64_t top, bot; /* length of tag file */
6377c478bd9Sstevel@tonic-gate struct stat64 sbuf;
6387c478bd9Sstevel@tonic-gate #endif
6397c478bd9Sstevel@tonic-gate
6407c478bd9Sstevel@tonic-gate omagic = value(vi_MAGIC);
6417c478bd9Sstevel@tonic-gate tl = value(vi_TAGLENGTH);
6427c478bd9Sstevel@tonic-gate if (!skipend()) {
643f6db9f27Scf unsigned char *lp = lasttag;
6447c478bd9Sstevel@tonic-gate
6457c478bd9Sstevel@tonic-gate while (!iswhite(peekchar()) && !endcmd(peekchar()))
6467c478bd9Sstevel@tonic-gate if (lp < &lasttag[sizeof lasttag - 2])
6477c478bd9Sstevel@tonic-gate *lp++ = getchar();
6487c478bd9Sstevel@tonic-gate else
6497c478bd9Sstevel@tonic-gate ignchar();
6507c478bd9Sstevel@tonic-gate *lp++ = 0;
6517c478bd9Sstevel@tonic-gate if (!endcmd(peekchar()))
6527c478bd9Sstevel@tonic-gate badtag:
6537c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Bad tag") :
6547c478bd9Sstevel@tonic-gate gettext("Give one tag per line"));
6557c478bd9Sstevel@tonic-gate } else if (lasttag[0] == 0)
6567c478bd9Sstevel@tonic-gate error(gettext("No previous tag"));
6577c478bd9Sstevel@tonic-gate c = getchar();
6587c478bd9Sstevel@tonic-gate if (!endcmd(c))
6597c478bd9Sstevel@tonic-gate goto badtag;
6607c478bd9Sstevel@tonic-gate if (c == EOF)
6617c478bd9Sstevel@tonic-gate ungetchar(c);
6627c478bd9Sstevel@tonic-gate clrstats();
6637c478bd9Sstevel@tonic-gate
6647c478bd9Sstevel@tonic-gate /*
6657c478bd9Sstevel@tonic-gate * Loop once for each file in tags "path".
66648bbca81SDaniel Hoffman *
66748bbca81SDaniel Hoffman * System tags array limits to 4k (tags[ONMSZ]) long,
6687c478bd9Sstevel@tonic-gate * therefore, tagfbuf should be able to hold all tags.
6697c478bd9Sstevel@tonic-gate */
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate CP(tagfbuf, svalue(vi_TAGS));
6727c478bd9Sstevel@tonic-gate fne = tagfbuf - 1;
6737c478bd9Sstevel@tonic-gate while (fne) {
6747c478bd9Sstevel@tonic-gate fn = ++fne;
6757c478bd9Sstevel@tonic-gate while (*fne && *fne != ' ')
6767c478bd9Sstevel@tonic-gate fne++;
6777c478bd9Sstevel@tonic-gate if (*fne == 0)
6787c478bd9Sstevel@tonic-gate fne = 0; /* done, quit after this time */
6797c478bd9Sstevel@tonic-gate else
6807c478bd9Sstevel@tonic-gate *fne = 0; /* null terminate filename */
6817c478bd9Sstevel@tonic-gate #ifdef STDIO /* was VMUNIX */
6827c478bd9Sstevel@tonic-gate iof = fopen((char *)fn, "r");
6837c478bd9Sstevel@tonic-gate if (iof == NULL)
6847c478bd9Sstevel@tonic-gate continue;
6857c478bd9Sstevel@tonic-gate tfcount++;
6867c478bd9Sstevel@tonic-gate setbuf(iof, (char *)iofbuf);
6877c478bd9Sstevel@tonic-gate fstat64(fileno(iof), &sbuf);
6887c478bd9Sstevel@tonic-gate top = sbuf.st_size;
6897c478bd9Sstevel@tonic-gate if (top == 0L || iof == NULL)
6907c478bd9Sstevel@tonic-gate top = -1L;
6917c478bd9Sstevel@tonic-gate bot = 0L;
6927c478bd9Sstevel@tonic-gate while (top >= bot) {
6937c478bd9Sstevel@tonic-gate /* loop for each tags file entry */
694f6db9f27Scf unsigned char *cp = linebuf;
695f6db9f27Scf unsigned char *lp = lasttag;
6967c478bd9Sstevel@tonic-gate unsigned char *oglobp;
6977c478bd9Sstevel@tonic-gate
6987c478bd9Sstevel@tonic-gate mid = (top + bot) / 2;
6997c478bd9Sstevel@tonic-gate fseeko64(iof, mid, 0);
7007c478bd9Sstevel@tonic-gate if (mid > 0) /* to get first tag in file to work */
7017c478bd9Sstevel@tonic-gate /* scan to next \n */
7027c478bd9Sstevel@tonic-gate if(fgets((char *)linebuf, sizeof linebuf, iof)==NULL)
7037c478bd9Sstevel@tonic-gate goto goleft;
7047c478bd9Sstevel@tonic-gate /* get the line itself */
7057c478bd9Sstevel@tonic-gate if(fgets((char *)linebuf, sizeof linebuf, iof)==NULL)
7067c478bd9Sstevel@tonic-gate goto goleft;
7077c478bd9Sstevel@tonic-gate linebuf[strlen(linebuf)-1] = 0; /* was '\n' */
7087c478bd9Sstevel@tonic-gate while (*cp && *lp == *cp)
7097c478bd9Sstevel@tonic-gate cp++, lp++;
7107c478bd9Sstevel@tonic-gate /*
7117c478bd9Sstevel@tonic-gate * This if decides whether there is a tag match.
7127c478bd9Sstevel@tonic-gate * A positive taglength means that a
7137c478bd9Sstevel@tonic-gate * match is found if the tag given matches at least
7147c478bd9Sstevel@tonic-gate * taglength chars of the tag found.
7157c478bd9Sstevel@tonic-gate * A taglength of greater than 511 means that a
7167c478bd9Sstevel@tonic-gate * match is found even if the tag given is a proper
7177c478bd9Sstevel@tonic-gate * prefix of the tag found. i.e. "ab" matches "abcd"
7187c478bd9Sstevel@tonic-gate */
7197c478bd9Sstevel@tonic-gate if ( *lp == 0 && (iswhite(*cp) || tl > 511 || tl > 0 && lp-lasttag >= tl) ) {
7207c478bd9Sstevel@tonic-gate /*
7217c478bd9Sstevel@tonic-gate * Found a match. Force selection to be
7227c478bd9Sstevel@tonic-gate * the first possible.
7237c478bd9Sstevel@tonic-gate */
7247c478bd9Sstevel@tonic-gate if ( mid == bot && mid == top ) {
7257c478bd9Sstevel@tonic-gate ; /* found first possible match */
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate else {
7287c478bd9Sstevel@tonic-gate /* postpone final decision. */
7297c478bd9Sstevel@tonic-gate top = mid;
7307c478bd9Sstevel@tonic-gate continue;
7317c478bd9Sstevel@tonic-gate }
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate else {
7347c478bd9Sstevel@tonic-gate if ((int)*lp > (int)*cp)
7357c478bd9Sstevel@tonic-gate bot = mid + 1;
7367c478bd9Sstevel@tonic-gate else
7377c478bd9Sstevel@tonic-gate goleft:
7387c478bd9Sstevel@tonic-gate top = mid - 1;
7397c478bd9Sstevel@tonic-gate continue;
7407c478bd9Sstevel@tonic-gate }
7417c478bd9Sstevel@tonic-gate /*
7427c478bd9Sstevel@tonic-gate * We found the tag. Decode the line in the file.
7437c478bd9Sstevel@tonic-gate */
7447c478bd9Sstevel@tonic-gate fclose(iof);
7457c478bd9Sstevel@tonic-gate
7467c478bd9Sstevel@tonic-gate /* Rest of tag if abbreviated */
7477c478bd9Sstevel@tonic-gate while (!iswhite(*cp))
7487c478bd9Sstevel@tonic-gate cp++;
7497c478bd9Sstevel@tonic-gate
7507c478bd9Sstevel@tonic-gate /* name of file */
7517c478bd9Sstevel@tonic-gate while (*cp && iswhite(*cp))
7527c478bd9Sstevel@tonic-gate cp++;
7537c478bd9Sstevel@tonic-gate if (!*cp)
7547c478bd9Sstevel@tonic-gate badtags:
755f6db9f27Scf serror((unsigned char *)
756f6db9f27Scf gettext("%s: Bad tags file entry"),
757f6db9f27Scf lasttag);
7587c478bd9Sstevel@tonic-gate lp = filebuf;
7597c478bd9Sstevel@tonic-gate while (*cp && *cp != ' ' && *cp != '\t') {
7607c478bd9Sstevel@tonic-gate if (lp < &filebuf[sizeof filebuf - 2])
7617c478bd9Sstevel@tonic-gate *lp++ = *cp;
7627c478bd9Sstevel@tonic-gate cp++;
7637c478bd9Sstevel@tonic-gate }
7647c478bd9Sstevel@tonic-gate *lp++ = 0;
7657c478bd9Sstevel@tonic-gate
7667c478bd9Sstevel@tonic-gate if (*cp == 0)
7677c478bd9Sstevel@tonic-gate goto badtags;
7687c478bd9Sstevel@tonic-gate if (dol != zero) {
7697c478bd9Sstevel@tonic-gate /*
7707c478bd9Sstevel@tonic-gate * Save current position in 't for ^^ in visual.
7717c478bd9Sstevel@tonic-gate */
7727c478bd9Sstevel@tonic-gate names['t'-'a'] = *dot &~ 01;
7737c478bd9Sstevel@tonic-gate if (inopen) {
7747c478bd9Sstevel@tonic-gate extern unsigned char *ncols['z'-'a'+2];
7757c478bd9Sstevel@tonic-gate extern unsigned char *cursor;
7767c478bd9Sstevel@tonic-gate
7777c478bd9Sstevel@tonic-gate ncols['t'-'a'] = cursor;
7787c478bd9Sstevel@tonic-gate }
7797c478bd9Sstevel@tonic-gate }
7807c478bd9Sstevel@tonic-gate #ifdef TAG_STACK
7817c478bd9Sstevel@tonic-gate if (*savedfile) {
782f6db9f27Scf savetag((char *)savedfile);
7837c478bd9Sstevel@tonic-gate }
78448bbca81SDaniel Hoffman #endif
7857c478bd9Sstevel@tonic-gate strcpy(cmdbuf, cp);
7867c478bd9Sstevel@tonic-gate if (strcmp(filebuf, savedfile) || !edited) {
7877c478bd9Sstevel@tonic-gate unsigned char cmdbuf2[sizeof filebuf + 10];
7887c478bd9Sstevel@tonic-gate
7897c478bd9Sstevel@tonic-gate /* Different file. Do autowrite & get it. */
7907c478bd9Sstevel@tonic-gate if (!quick) {
7917c478bd9Sstevel@tonic-gate ckaw();
7927c478bd9Sstevel@tonic-gate if (chng && dol > zero) {
7937c478bd9Sstevel@tonic-gate #ifdef TAG_STACK
7947c478bd9Sstevel@tonic-gate unsavetag();
7957c478bd9Sstevel@tonic-gate #endif
7967c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ?
7977c478bd9Sstevel@tonic-gate gettext("No write") : gettext("No write since last change (:tag! overrides)"));
7987c478bd9Sstevel@tonic-gate }
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate oglobp = globp;
8017c478bd9Sstevel@tonic-gate strcpy(cmdbuf2, "e! ");
8027c478bd9Sstevel@tonic-gate strcat(cmdbuf2, filebuf);
8037c478bd9Sstevel@tonic-gate globp = cmdbuf2;
8047c478bd9Sstevel@tonic-gate d = peekc; ungetchar(0);
8057c478bd9Sstevel@tonic-gate commands(1, 1);
8067c478bd9Sstevel@tonic-gate peekc = d;
8077c478bd9Sstevel@tonic-gate globp = oglobp;
8087c478bd9Sstevel@tonic-gate value(vi_MAGIC) = omagic;
8097c478bd9Sstevel@tonic-gate samef = 0;
8107c478bd9Sstevel@tonic-gate }
8117c478bd9Sstevel@tonic-gate
8127c478bd9Sstevel@tonic-gate /*
8137c478bd9Sstevel@tonic-gate * Look for pattern in the current file.
8147c478bd9Sstevel@tonic-gate */
8157c478bd9Sstevel@tonic-gate oglobp = globp;
8167c478bd9Sstevel@tonic-gate globp = cmdbuf;
8177c478bd9Sstevel@tonic-gate d = peekc; ungetchar(0);
8187c478bd9Sstevel@tonic-gate if (samef)
8197c478bd9Sstevel@tonic-gate markpr(dot);
8207c478bd9Sstevel@tonic-gate /*
8217c478bd9Sstevel@tonic-gate * BUG: if it isn't found (user edited header
8227c478bd9Sstevel@tonic-gate * line) we get left in nomagic mode.
8237c478bd9Sstevel@tonic-gate */
8247c478bd9Sstevel@tonic-gate value(vi_MAGIC) = 0;
8257c478bd9Sstevel@tonic-gate commands(1, 1);
8267c478bd9Sstevel@tonic-gate peekc = d;
8277c478bd9Sstevel@tonic-gate globp = oglobp;
8287c478bd9Sstevel@tonic-gate value(vi_MAGIC) = omagic;
8297c478bd9Sstevel@tonic-gate return;
8307c478bd9Sstevel@tonic-gate } /* end of "for each tag in file" */
8317c478bd9Sstevel@tonic-gate #endif /* STDIO */
8327c478bd9Sstevel@tonic-gate /*
8337c478bd9Sstevel@tonic-gate * Binary search failed, so try linear search if -S is on.
8347c478bd9Sstevel@tonic-gate * -S is needed for tags files that are not sorted.
8357c478bd9Sstevel@tonic-gate */
8367c478bd9Sstevel@tonic-gate
8377c478bd9Sstevel@tonic-gate /*
8387c478bd9Sstevel@tonic-gate * Avoid stdio and scan tag file linearly.
8397c478bd9Sstevel@tonic-gate */
8407c478bd9Sstevel@tonic-gate if (tags_flag == 0)
8417c478bd9Sstevel@tonic-gate continue;
8427c478bd9Sstevel@tonic-gate io = open(fn, 0);
8437c478bd9Sstevel@tonic-gate if (io < 0)
8447c478bd9Sstevel@tonic-gate continue;
8457c478bd9Sstevel@tonic-gate /* tfcount++; */
8467c478bd9Sstevel@tonic-gate while (getfile() == 0) {
8477c478bd9Sstevel@tonic-gate /* loop for each tags file entry */
848f6db9f27Scf unsigned char *cp = linebuf;
849f6db9f27Scf unsigned char *lp = lasttag;
8507c478bd9Sstevel@tonic-gate unsigned char *oglobp;
8517c478bd9Sstevel@tonic-gate
8527c478bd9Sstevel@tonic-gate while (*cp && *lp == *cp)
8537c478bd9Sstevel@tonic-gate cp++, lp++;
8547c478bd9Sstevel@tonic-gate /*
8557c478bd9Sstevel@tonic-gate * This if decides whether there is a tag match.
8567c478bd9Sstevel@tonic-gate * A positive taglength means that a
8577c478bd9Sstevel@tonic-gate * match is found if the tag given matches at least
8587c478bd9Sstevel@tonic-gate * taglength chars of the tag found.
8597c478bd9Sstevel@tonic-gate * A taglength of greater than 511 means that a
8607c478bd9Sstevel@tonic-gate * match is found even if the tag given is a proper
8617c478bd9Sstevel@tonic-gate * prefix of the tag found. i.e. "ab" matches "abcd"
8627c478bd9Sstevel@tonic-gate */
8637c478bd9Sstevel@tonic-gate if ( *lp == 0 && (iswhite(*cp) || tl > 511 || tl > 0 && lp-lasttag >= tl) ) {
8647c478bd9Sstevel@tonic-gate ; /* Found it. */
8657c478bd9Sstevel@tonic-gate }
8667c478bd9Sstevel@tonic-gate else {
8677c478bd9Sstevel@tonic-gate /* Not this tag. Try the next */
8687c478bd9Sstevel@tonic-gate continue;
8697c478bd9Sstevel@tonic-gate }
8707c478bd9Sstevel@tonic-gate /*
8717c478bd9Sstevel@tonic-gate * We found the tag. Decode the line in the file.
8727c478bd9Sstevel@tonic-gate */
8737c478bd9Sstevel@tonic-gate close(io);
8747c478bd9Sstevel@tonic-gate /* Rest of tag if abbreviated */
8757c478bd9Sstevel@tonic-gate while (!iswhite(*cp))
8767c478bd9Sstevel@tonic-gate cp++;
8777c478bd9Sstevel@tonic-gate
8787c478bd9Sstevel@tonic-gate /* name of file */
8797c478bd9Sstevel@tonic-gate while (*cp && iswhite(*cp))
8807c478bd9Sstevel@tonic-gate cp++;
8817c478bd9Sstevel@tonic-gate if (!*cp)
8827c478bd9Sstevel@tonic-gate badtags2:
883f6db9f27Scf serror((unsigned char *)
884f6db9f27Scf gettext("%s: Bad tags file entry"),
885f6db9f27Scf lasttag);
8867c478bd9Sstevel@tonic-gate lp = filebuf;
8877c478bd9Sstevel@tonic-gate while (*cp && *cp != ' ' && *cp != '\t') {
8887c478bd9Sstevel@tonic-gate if (lp < &filebuf[sizeof filebuf - 2])
8897c478bd9Sstevel@tonic-gate *lp++ = *cp;
8907c478bd9Sstevel@tonic-gate cp++;
8917c478bd9Sstevel@tonic-gate }
8927c478bd9Sstevel@tonic-gate *lp++ = 0;
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate if (*cp == 0)
8957c478bd9Sstevel@tonic-gate goto badtags2;
8967c478bd9Sstevel@tonic-gate if (dol != zero) {
8977c478bd9Sstevel@tonic-gate /*
8987c478bd9Sstevel@tonic-gate * Save current position in 't for ^^ in visual.
8997c478bd9Sstevel@tonic-gate */
9007c478bd9Sstevel@tonic-gate names['t'-'a'] = *dot &~ 01;
9017c478bd9Sstevel@tonic-gate if (inopen) {
9027c478bd9Sstevel@tonic-gate extern unsigned char *ncols['z'-'a'+2];
9037c478bd9Sstevel@tonic-gate extern unsigned char *cursor;
9047c478bd9Sstevel@tonic-gate
9057c478bd9Sstevel@tonic-gate ncols['t'-'a'] = cursor;
9067c478bd9Sstevel@tonic-gate }
9077c478bd9Sstevel@tonic-gate }
9087c478bd9Sstevel@tonic-gate #ifdef TAG_STACK
9097c478bd9Sstevel@tonic-gate if (*savedfile) {
910f6db9f27Scf savetag((char *)savedfile);
9117c478bd9Sstevel@tonic-gate }
91248bbca81SDaniel Hoffman #endif
9137c478bd9Sstevel@tonic-gate strcpy(cmdbuf, cp);
9147c478bd9Sstevel@tonic-gate if (strcmp(filebuf, savedfile) || !edited) {
9157c478bd9Sstevel@tonic-gate unsigned char cmdbuf2[sizeof filebuf + 10];
9167c478bd9Sstevel@tonic-gate
9177c478bd9Sstevel@tonic-gate /* Different file. Do autowrite & get it. */
9187c478bd9Sstevel@tonic-gate if (!quick) {
9197c478bd9Sstevel@tonic-gate ckaw();
9207c478bd9Sstevel@tonic-gate if (chng && dol > zero) {
9217c478bd9Sstevel@tonic-gate #ifdef TAG_STACK
9227c478bd9Sstevel@tonic-gate unsavetag();
9237c478bd9Sstevel@tonic-gate #endif
9247c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ?
9257c478bd9Sstevel@tonic-gate gettext("No write") : gettext("No write since last change (:tag! overrides)"));
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate oglobp = globp;
9297c478bd9Sstevel@tonic-gate strcpy(cmdbuf2, "e! ");
9307c478bd9Sstevel@tonic-gate strcat(cmdbuf2, filebuf);
9317c478bd9Sstevel@tonic-gate globp = cmdbuf2;
9327c478bd9Sstevel@tonic-gate d = peekc; ungetchar(0);
9337c478bd9Sstevel@tonic-gate commands(1, 1);
9347c478bd9Sstevel@tonic-gate peekc = d;
9357c478bd9Sstevel@tonic-gate globp = oglobp;
9367c478bd9Sstevel@tonic-gate value(vi_MAGIC) = omagic;
9377c478bd9Sstevel@tonic-gate samef = 0;
9387c478bd9Sstevel@tonic-gate }
9397c478bd9Sstevel@tonic-gate
9407c478bd9Sstevel@tonic-gate /*
9417c478bd9Sstevel@tonic-gate * Look for pattern in the current file.
9427c478bd9Sstevel@tonic-gate */
9437c478bd9Sstevel@tonic-gate oglobp = globp;
9447c478bd9Sstevel@tonic-gate globp = cmdbuf;
9457c478bd9Sstevel@tonic-gate d = peekc; ungetchar(0);
9467c478bd9Sstevel@tonic-gate if (samef)
9477c478bd9Sstevel@tonic-gate markpr(dot);
9487c478bd9Sstevel@tonic-gate /*
9497c478bd9Sstevel@tonic-gate * BUG: if it isn't found (user edited header
9507c478bd9Sstevel@tonic-gate * line) we get left in nomagic mode.
9517c478bd9Sstevel@tonic-gate */
9527c478bd9Sstevel@tonic-gate value(vi_MAGIC) = 0;
9537c478bd9Sstevel@tonic-gate commands(1, 1);
9547c478bd9Sstevel@tonic-gate peekc = d;
9557c478bd9Sstevel@tonic-gate globp = oglobp;
9567c478bd9Sstevel@tonic-gate value(vi_MAGIC) = omagic;
9577c478bd9Sstevel@tonic-gate return;
9587c478bd9Sstevel@tonic-gate } /* end of "for each tag in file" */
9597c478bd9Sstevel@tonic-gate
9607c478bd9Sstevel@tonic-gate /*
9617c478bd9Sstevel@tonic-gate * No such tag in this file. Close it and try the next.
9627c478bd9Sstevel@tonic-gate */
9637c478bd9Sstevel@tonic-gate #ifdef STDIO /* was VMUNIX */
9647c478bd9Sstevel@tonic-gate fclose(iof);
9657c478bd9Sstevel@tonic-gate #else
9667c478bd9Sstevel@tonic-gate close(io);
9677c478bd9Sstevel@tonic-gate #endif
9687c478bd9Sstevel@tonic-gate } /* end of "for each file in path" */
9697c478bd9Sstevel@tonic-gate if (tfcount <= 0)
9707c478bd9Sstevel@tonic-gate error(gettext("No tags file"));
9717c478bd9Sstevel@tonic-gate else
972f6db9f27Scf serror(value(vi_TERSE) ?
973f6db9f27Scf (unsigned char *)gettext("%s: No such tag") :
974f6db9f27Scf (unsigned char *)gettext("%s: No such tag in tags file"),
975f6db9f27Scf lasttag);
9767c478bd9Sstevel@tonic-gate }
9777c478bd9Sstevel@tonic-gate
9787c478bd9Sstevel@tonic-gate /*
9797c478bd9Sstevel@tonic-gate * Save lines from addr1 thru addr2 as though
9807c478bd9Sstevel@tonic-gate * they had been deleted.
9817c478bd9Sstevel@tonic-gate */
982f6db9f27Scf int
yank(void)983f6db9f27Scf yank(void)
9847c478bd9Sstevel@tonic-gate {
9857c478bd9Sstevel@tonic-gate
9867c478bd9Sstevel@tonic-gate if (!FIXUNDO)
9877c478bd9Sstevel@tonic-gate error(gettext("Can't yank inside global/macro"));
9887c478bd9Sstevel@tonic-gate save12();
9897c478bd9Sstevel@tonic-gate undkind = UNDNONE;
9907c478bd9Sstevel@tonic-gate killcnt(addr2 - addr1 + 1);
991f6db9f27Scf return (0);
9927c478bd9Sstevel@tonic-gate }
9937c478bd9Sstevel@tonic-gate
9947c478bd9Sstevel@tonic-gate /*
9957c478bd9Sstevel@tonic-gate * z command; print windows of text in the file.
9967c478bd9Sstevel@tonic-gate *
9977c478bd9Sstevel@tonic-gate * If this seems unreasonably arcane, the reasons
9987c478bd9Sstevel@tonic-gate * are historical. This is one of the first commands
9997c478bd9Sstevel@tonic-gate * added to the first ex (then called en) and the
10007c478bd9Sstevel@tonic-gate * number of facilities here were the major advantage
10017c478bd9Sstevel@tonic-gate * of en over ed since they allowed more use to be
10027c478bd9Sstevel@tonic-gate * made of fast terminals w/o typing .,.22p all the time.
10037c478bd9Sstevel@tonic-gate */
10047c478bd9Sstevel@tonic-gate bool zhadpr;
10057c478bd9Sstevel@tonic-gate bool znoclear;
10067c478bd9Sstevel@tonic-gate short zweight;
10077c478bd9Sstevel@tonic-gate
1008f6db9f27Scf void
zop(int hadpr)1009f6db9f27Scf zop(int hadpr)
10107c478bd9Sstevel@tonic-gate {
1011f6db9f27Scf int c, nlines, op;
10127c478bd9Sstevel@tonic-gate bool excl;
10137c478bd9Sstevel@tonic-gate
10147c478bd9Sstevel@tonic-gate zhadpr = hadpr;
10157c478bd9Sstevel@tonic-gate notempty();
10167c478bd9Sstevel@tonic-gate znoclear = 0;
10177c478bd9Sstevel@tonic-gate zweight = 0;
10187c478bd9Sstevel@tonic-gate excl = exclam();
10197c478bd9Sstevel@tonic-gate switch (c = op = getchar()) {
10207c478bd9Sstevel@tonic-gate
10217c478bd9Sstevel@tonic-gate case '^':
10227c478bd9Sstevel@tonic-gate zweight = 1;
1023*9097ca5cSToomas Soome /* FALLTHROUGH */
10247c478bd9Sstevel@tonic-gate case '-':
10257c478bd9Sstevel@tonic-gate case '+':
10267c478bd9Sstevel@tonic-gate while (peekchar() == op) {
10277c478bd9Sstevel@tonic-gate ignchar();
10287c478bd9Sstevel@tonic-gate zweight++;
10297c478bd9Sstevel@tonic-gate }
1030*9097ca5cSToomas Soome /* FALLTHROUGH */
10317c478bd9Sstevel@tonic-gate case '=':
10327c478bd9Sstevel@tonic-gate case '.':
10337c478bd9Sstevel@tonic-gate c = getchar();
10347c478bd9Sstevel@tonic-gate break;
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate case EOF:
10377c478bd9Sstevel@tonic-gate znoclear++;
10387c478bd9Sstevel@tonic-gate break;
10397c478bd9Sstevel@tonic-gate
10407c478bd9Sstevel@tonic-gate default:
10417c478bd9Sstevel@tonic-gate op = 0;
10427c478bd9Sstevel@tonic-gate break;
10437c478bd9Sstevel@tonic-gate }
10447c478bd9Sstevel@tonic-gate if (isdigit(c)) {
10457c478bd9Sstevel@tonic-gate nlines = c - '0';
10467c478bd9Sstevel@tonic-gate for(;;) {
10477c478bd9Sstevel@tonic-gate c = getchar();
10487c478bd9Sstevel@tonic-gate if (!isdigit(c))
10497c478bd9Sstevel@tonic-gate break;
10507c478bd9Sstevel@tonic-gate nlines *= 10;
10517c478bd9Sstevel@tonic-gate nlines += c - '0';
10527c478bd9Sstevel@tonic-gate }
10537c478bd9Sstevel@tonic-gate if (nlines < lines)
10547c478bd9Sstevel@tonic-gate znoclear++;
10557c478bd9Sstevel@tonic-gate value(vi_WINDOW) = nlines;
10567c478bd9Sstevel@tonic-gate if (op == '=')
10577c478bd9Sstevel@tonic-gate nlines += 2;
10587c478bd9Sstevel@tonic-gate }
10597c478bd9Sstevel@tonic-gate else {
10607c478bd9Sstevel@tonic-gate nlines = op == EOF ? value(vi_SCROLL) :
10617c478bd9Sstevel@tonic-gate excl ? lines - 1 : value(vi_WINDOW);
10627c478bd9Sstevel@tonic-gate }
10637c478bd9Sstevel@tonic-gate if (inopen || c != EOF) {
10647c478bd9Sstevel@tonic-gate ungetchar(c);
10657c478bd9Sstevel@tonic-gate donewline();
10667c478bd9Sstevel@tonic-gate }
10677c478bd9Sstevel@tonic-gate addr1 = addr2;
10687c478bd9Sstevel@tonic-gate if (addr2 == 0 && dot < dol && op == 0)
10697c478bd9Sstevel@tonic-gate addr1 = addr2 = dot+1;
10707c478bd9Sstevel@tonic-gate setdot();
10717c478bd9Sstevel@tonic-gate zop2(nlines, op);
10727c478bd9Sstevel@tonic-gate }
10737c478bd9Sstevel@tonic-gate
1074f6db9f27Scf void
zop2(int nlines,int op)1075f6db9f27Scf zop2(int nlines, int op)
10767c478bd9Sstevel@tonic-gate {
1077f6db9f27Scf line *split;
10787c478bd9Sstevel@tonic-gate
10797c478bd9Sstevel@tonic-gate split = NULL;
10807c478bd9Sstevel@tonic-gate switch (op) {
10817c478bd9Sstevel@tonic-gate
10827c478bd9Sstevel@tonic-gate case EOF:
10837c478bd9Sstevel@tonic-gate if (addr2 == dol)
10847c478bd9Sstevel@tonic-gate error(gettext("\nAt EOF"));
1085*9097ca5cSToomas Soome /* FALLTHROUGH */
10867c478bd9Sstevel@tonic-gate case '+':
10877c478bd9Sstevel@tonic-gate if (addr2 == dol)
10887c478bd9Sstevel@tonic-gate error(gettext("At EOF"));
10897c478bd9Sstevel@tonic-gate addr2 += nlines * zweight;
10907c478bd9Sstevel@tonic-gate if (addr2 > dol)
10917c478bd9Sstevel@tonic-gate error(gettext("Hit BOTTOM"));
10927c478bd9Sstevel@tonic-gate addr2++;
1093*9097ca5cSToomas Soome /* FALLTHROUGH */
10947c478bd9Sstevel@tonic-gate default:
10957c478bd9Sstevel@tonic-gate addr1 = addr2;
10967c478bd9Sstevel@tonic-gate addr2 += nlines-1;
10977c478bd9Sstevel@tonic-gate dot = addr2;
10987c478bd9Sstevel@tonic-gate break;
10997c478bd9Sstevel@tonic-gate
11007c478bd9Sstevel@tonic-gate case '=':
11017c478bd9Sstevel@tonic-gate case '.':
11027c478bd9Sstevel@tonic-gate znoclear = 0;
11037c478bd9Sstevel@tonic-gate nlines--;
11047c478bd9Sstevel@tonic-gate nlines >>= 1;
11057c478bd9Sstevel@tonic-gate if (op == '=')
11067c478bd9Sstevel@tonic-gate nlines--;
11077c478bd9Sstevel@tonic-gate addr1 = addr2 - nlines;
11087c478bd9Sstevel@tonic-gate if (op == '=')
11097c478bd9Sstevel@tonic-gate dot = split = addr2;
11107c478bd9Sstevel@tonic-gate addr2 += nlines;
11117c478bd9Sstevel@tonic-gate if (op == '.') {
11127c478bd9Sstevel@tonic-gate markDOT();
11137c478bd9Sstevel@tonic-gate dot = addr2;
11147c478bd9Sstevel@tonic-gate }
11157c478bd9Sstevel@tonic-gate break;
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate case '^':
11187c478bd9Sstevel@tonic-gate case '-':
11197c478bd9Sstevel@tonic-gate addr2 -= nlines * zweight;
11207c478bd9Sstevel@tonic-gate if (addr2 < one)
11217c478bd9Sstevel@tonic-gate error(gettext("Hit TOP"));
11227c478bd9Sstevel@tonic-gate nlines--;
11237c478bd9Sstevel@tonic-gate addr1 = addr2 - nlines;
11247c478bd9Sstevel@tonic-gate dot = addr2;
11257c478bd9Sstevel@tonic-gate break;
11267c478bd9Sstevel@tonic-gate }
11277c478bd9Sstevel@tonic-gate if (addr1 <= zero)
11287c478bd9Sstevel@tonic-gate addr1 = one;
11297c478bd9Sstevel@tonic-gate if (addr2 > dol)
11307c478bd9Sstevel@tonic-gate addr2 = dol;
11317c478bd9Sstevel@tonic-gate if (dot > dol)
11327c478bd9Sstevel@tonic-gate dot = dol;
11337c478bd9Sstevel@tonic-gate if (addr1 > addr2)
11347c478bd9Sstevel@tonic-gate return;
11357c478bd9Sstevel@tonic-gate if (op == EOF && zhadpr) {
113623a1cceaSRoger A. Faulkner getaline(*addr1);
11377c478bd9Sstevel@tonic-gate putchar((int)('\r' | QUOTE));
11387c478bd9Sstevel@tonic-gate shudclob = 1;
11397c478bd9Sstevel@tonic-gate } else if (znoclear == 0 && clear_screen != NOSTR && !inopen) {
11407c478bd9Sstevel@tonic-gate flush1();
11417c478bd9Sstevel@tonic-gate vclear();
11427c478bd9Sstevel@tonic-gate }
11437c478bd9Sstevel@tonic-gate if (addr2 - addr1 > 1)
11447c478bd9Sstevel@tonic-gate pstart();
11457c478bd9Sstevel@tonic-gate if (split) {
11467c478bd9Sstevel@tonic-gate plines(addr1, split - 1, 0);
11477c478bd9Sstevel@tonic-gate splitit();
11487c478bd9Sstevel@tonic-gate plines(split, split, 0);
11497c478bd9Sstevel@tonic-gate splitit();
11507c478bd9Sstevel@tonic-gate addr1 = split + 1;
11517c478bd9Sstevel@tonic-gate }
11527c478bd9Sstevel@tonic-gate plines(addr1, addr2, 0);
11537c478bd9Sstevel@tonic-gate }
11547c478bd9Sstevel@tonic-gate
1155f6db9f27Scf static void
splitit(void)1156f6db9f27Scf splitit(void)
11577c478bd9Sstevel@tonic-gate {
1158f6db9f27Scf int l;
11597c478bd9Sstevel@tonic-gate
11607c478bd9Sstevel@tonic-gate for (l = columns > 80 ? 40 : columns / 2; l > 0; l--)
11617c478bd9Sstevel@tonic-gate putchar('-');
11627c478bd9Sstevel@tonic-gate putnl();
11637c478bd9Sstevel@tonic-gate }
11647c478bd9Sstevel@tonic-gate
1165f6db9f27Scf void
plines(line * adr1,line * adr2,bool movedot)1166f6db9f27Scf plines(line *adr1, line *adr2, bool movedot)
11677c478bd9Sstevel@tonic-gate {
1168f6db9f27Scf line *addr;
11697c478bd9Sstevel@tonic-gate
11707c478bd9Sstevel@tonic-gate pofix();
11717c478bd9Sstevel@tonic-gate for (addr = adr1; addr <= adr2; addr++) {
117223a1cceaSRoger A. Faulkner getaline(*addr);
11737c478bd9Sstevel@tonic-gate pline(lineno(addr));
11747c478bd9Sstevel@tonic-gate if (inopen)
11757c478bd9Sstevel@tonic-gate putchar((int)('\n' | QUOTE));
11767c478bd9Sstevel@tonic-gate if (movedot)
11777c478bd9Sstevel@tonic-gate dot = addr;
11787c478bd9Sstevel@tonic-gate }
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate
1181f6db9f27Scf void
pofix(void)1182f6db9f27Scf pofix(void)
11837c478bd9Sstevel@tonic-gate {
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate if (inopen && Outchar != termchar) {
11867c478bd9Sstevel@tonic-gate vnfl();
11877c478bd9Sstevel@tonic-gate setoutt();
11887c478bd9Sstevel@tonic-gate }
11897c478bd9Sstevel@tonic-gate }
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate /*
11927c478bd9Sstevel@tonic-gate * Command level undo works easily because
11937c478bd9Sstevel@tonic-gate * the editor has a unique temporary file
11947c478bd9Sstevel@tonic-gate * index for every line which ever existed.
11957c478bd9Sstevel@tonic-gate * We don't have to save large blocks of text,
11967c478bd9Sstevel@tonic-gate * only the indices which are small. We do this
11977c478bd9Sstevel@tonic-gate * by moving them to after the last line in the
11987c478bd9Sstevel@tonic-gate * line buffer array, and marking down info
11997c478bd9Sstevel@tonic-gate * about whence they came.
12007c478bd9Sstevel@tonic-gate *
12017c478bd9Sstevel@tonic-gate * Undo is its own inverse.
12027c478bd9Sstevel@tonic-gate */
1203f6db9f27Scf void
undo(bool c)1204f6db9f27Scf undo(bool c)
12057c478bd9Sstevel@tonic-gate {
1206f6db9f27Scf int i, k;
1207f6db9f27Scf line *jp, *kp, *j;
12087c478bd9Sstevel@tonic-gate line *dolp1, *newdol, *newadot;
12097c478bd9Sstevel@tonic-gate
12107c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
12117c478bd9Sstevel@tonic-gate if (trace)
12127c478bd9Sstevel@tonic-gate vudump("before undo");
12137c478bd9Sstevel@tonic-gate #endif
12147c478bd9Sstevel@tonic-gate if (inglobal && inopen <= 0)
12157c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Can't undo in global") :
12167c478bd9Sstevel@tonic-gate gettext("Can't undo in global commands"));
121748bbca81SDaniel Hoffman
12187c478bd9Sstevel@tonic-gate /*
12197c478bd9Sstevel@tonic-gate * Unless flag indicates a forced undo, make sure
12207c478bd9Sstevel@tonic-gate * there really was a change before trying to undo it.
12217c478bd9Sstevel@tonic-gate */
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate if (!c)
12247c478bd9Sstevel@tonic-gate somechange();
122548bbca81SDaniel Hoffman
12267c478bd9Sstevel@tonic-gate /*
12277c478bd9Sstevel@tonic-gate * Update change flags.
12287c478bd9Sstevel@tonic-gate */
12297c478bd9Sstevel@tonic-gate
12307c478bd9Sstevel@tonic-gate pkill[0] = pkill[1] = 0;
12317c478bd9Sstevel@tonic-gate change();
12327c478bd9Sstevel@tonic-gate if (undkind == UNDMOVE) {
12337c478bd9Sstevel@tonic-gate /*
12347c478bd9Sstevel@tonic-gate * Command to be undone is a move command.
12357c478bd9Sstevel@tonic-gate * This is handled as a special case by noting that
12367c478bd9Sstevel@tonic-gate * a move "a,b m c" can be inverted by another move.
12377c478bd9Sstevel@tonic-gate */
12387c478bd9Sstevel@tonic-gate if ((i = (jp = unddel) - undap2) > 0) {
12397c478bd9Sstevel@tonic-gate /*
12407c478bd9Sstevel@tonic-gate * when c > b inverse is a+(c-b),c m a-1
12417c478bd9Sstevel@tonic-gate */
12427c478bd9Sstevel@tonic-gate addr2 = jp;
12437c478bd9Sstevel@tonic-gate addr1 = (jp = undap1) + i;
12447c478bd9Sstevel@tonic-gate unddel = jp-1;
12457c478bd9Sstevel@tonic-gate } else {
12467c478bd9Sstevel@tonic-gate /*
12477c478bd9Sstevel@tonic-gate * when b > c inverse is c+1,c+1+(b-a) m b
12487c478bd9Sstevel@tonic-gate */
12497c478bd9Sstevel@tonic-gate addr1 = ++jp;
12507c478bd9Sstevel@tonic-gate addr2 = jp + ((unddel = undap2) - undap1);
12517c478bd9Sstevel@tonic-gate }
12527c478bd9Sstevel@tonic-gate kp = undap1;
12537c478bd9Sstevel@tonic-gate move1(0, unddel);
12547c478bd9Sstevel@tonic-gate dot = kp;
12557c478bd9Sstevel@tonic-gate Command = (unsigned char *)"move";
12567c478bd9Sstevel@tonic-gate killed();
12577c478bd9Sstevel@tonic-gate } else {
12587c478bd9Sstevel@tonic-gate int cnt;
12597c478bd9Sstevel@tonic-gate
12607c478bd9Sstevel@tonic-gate newadot = dot;
12617c478bd9Sstevel@tonic-gate cnt = lineDOL();
12627c478bd9Sstevel@tonic-gate newdol = dol;
12637c478bd9Sstevel@tonic-gate dolp1 = dol + 1;
12647c478bd9Sstevel@tonic-gate /*
12657c478bd9Sstevel@tonic-gate * Command to be undone is a non-move.
12667c478bd9Sstevel@tonic-gate * All such commands are treated as a combination of
12677c478bd9Sstevel@tonic-gate * a delete command and a append command.
12687c478bd9Sstevel@tonic-gate * We first move the lines appended by the last command
12697c478bd9Sstevel@tonic-gate * from undap1 to undap2-1 so that they are just before the
12707c478bd9Sstevel@tonic-gate * saved deleted lines.
12717c478bd9Sstevel@tonic-gate *
12727c478bd9Sstevel@tonic-gate * Assume the editor has:
12737c478bd9Sstevel@tonic-gate *
12747c478bd9Sstevel@tonic-gate * cursor is on 'c'
12757c478bd9Sstevel@tonic-gate *
12767c478bd9Sstevel@tonic-gate * (just change lines 5-8)
12777c478bd9Sstevel@tonic-gate *
12787c478bd9Sstevel@tonic-gate * file is: 1) ab
12797c478bd9Sstevel@tonic-gate * 2) cd
12807c478bd9Sstevel@tonic-gate * 3) ef
12817c478bd9Sstevel@tonic-gate * 4) gh
12827c478bd9Sstevel@tonic-gate * undap1: 5) 12
12837c478bd9Sstevel@tonic-gate * 6) 34
12847c478bd9Sstevel@tonic-gate * 7) 56
12857c478bd9Sstevel@tonic-gate * 8) 78
12867c478bd9Sstevel@tonic-gate * undap2: 9) qr
12877c478bd9Sstevel@tonic-gate * 10) st
12887c478bd9Sstevel@tonic-gate * 11) uv
12897c478bd9Sstevel@tonic-gate * 12) wx
12907c478bd9Sstevel@tonic-gate * dol: 13) yz
12917c478bd9Sstevel@tonic-gate *
12927c478bd9Sstevel@tonic-gate * UNDO AREA:
12937c478bd9Sstevel@tonic-gate * dol+1: 5) ij
12947c478bd9Sstevel@tonic-gate * 6) kl
12957c478bd9Sstevel@tonic-gate * 7) mn
12967c478bd9Sstevel@tonic-gate * unddol: 8) op
12977c478bd9Sstevel@tonic-gate */
12987c478bd9Sstevel@tonic-gate
12997c478bd9Sstevel@tonic-gate /*
13007c478bd9Sstevel@tonic-gate * If this is a change (not a delete/put),
13017c478bd9Sstevel@tonic-gate * then we must move the text between undap1 and undap2
13027c478bd9Sstevel@tonic-gate * and it must not be at the bottom of the file
13037c478bd9Sstevel@tonic-gate */
130448bbca81SDaniel Hoffman
13057c478bd9Sstevel@tonic-gate if ((i = (kp = undap2) - (jp = undap1)) > 0) {
13067c478bd9Sstevel@tonic-gate if (kp != dolp1) {
13077c478bd9Sstevel@tonic-gate
13087c478bd9Sstevel@tonic-gate /*
13097c478bd9Sstevel@tonic-gate * FILE: LINE INITIAL REV1 REV2 REV3
13107c478bd9Sstevel@tonic-gate *
13117c478bd9Sstevel@tonic-gate * 1) ab ab ab ab
13127c478bd9Sstevel@tonic-gate * 2) cd cd cd cd
13137c478bd9Sstevel@tonic-gate * 3) ef ef ef ef
13147c478bd9Sstevel@tonic-gate * unddel: 4) gh gh gh gh
13157c478bd9Sstevel@tonic-gate * undap1: 5) 12 78 78 qr
13167c478bd9Sstevel@tonic-gate * 6) 34 56 56 st
13177c478bd9Sstevel@tonic-gate * 7) 56 34 34 uv
13187c478bd9Sstevel@tonic-gate * 8) 78 12 12 wx
13197c478bd9Sstevel@tonic-gate * undap2: 9) qr qr yz yz
13207c478bd9Sstevel@tonic-gate * 10) st st wx 12
13217c478bd9Sstevel@tonic-gate * 11) uv uv uv 34
13227c478bd9Sstevel@tonic-gate * 12) wx wx st 56
13237c478bd9Sstevel@tonic-gate * dol: 13) yz yz qr 78
13247c478bd9Sstevel@tonic-gate *
13257c478bd9Sstevel@tonic-gate * UNDO AREA:
13267c478bd9Sstevel@tonic-gate * dol+1: 5) ij ij ij ij
13277c478bd9Sstevel@tonic-gate * 6) kl kl kl kl
13287c478bd9Sstevel@tonic-gate * 7) mn mn mn mn
13297c478bd9Sstevel@tonic-gate * unddol: 8) op op op op
13307c478bd9Sstevel@tonic-gate */
13317c478bd9Sstevel@tonic-gate
13327c478bd9Sstevel@tonic-gate reverse(jp, kp);
13337c478bd9Sstevel@tonic-gate reverse(kp, dolp1);
13347c478bd9Sstevel@tonic-gate reverse(jp, dolp1);
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate /*
13377c478bd9Sstevel@tonic-gate * Unddel, the line just before the spot where this
133848bbca81SDaniel Hoffman * test was deleted, may have moved. Account for
13397c478bd9Sstevel@tonic-gate * this in restoration of saved deleted lines.
13407c478bd9Sstevel@tonic-gate */
13417c478bd9Sstevel@tonic-gate if (unddel >= jp)
13427c478bd9Sstevel@tonic-gate unddel -= i;
134348bbca81SDaniel Hoffman
13447c478bd9Sstevel@tonic-gate /*
13457c478bd9Sstevel@tonic-gate * The last line (dol) may have changed,
13467c478bd9Sstevel@tonic-gate * account for this.
13477c478bd9Sstevel@tonic-gate */
13487c478bd9Sstevel@tonic-gate newdol -= i;
134948bbca81SDaniel Hoffman
13507c478bd9Sstevel@tonic-gate /*
13517c478bd9Sstevel@tonic-gate * For the case where no lines are restored, dot
13527c478bd9Sstevel@tonic-gate * is the line before the first line deleted.
13537c478bd9Sstevel@tonic-gate */
13547c478bd9Sstevel@tonic-gate dot = jp-1;
13557c478bd9Sstevel@tonic-gate }
13567c478bd9Sstevel@tonic-gate /*
13577c478bd9Sstevel@tonic-gate * Now put the deleted lines, if any, back where they were.
13587c478bd9Sstevel@tonic-gate * Basic operation is: dol+1,unddol m unddel
13597c478bd9Sstevel@tonic-gate */
13607c478bd9Sstevel@tonic-gate if (undkind == UNDPUT) {
13617c478bd9Sstevel@tonic-gate unddel = undap1 - 1;
13627c478bd9Sstevel@tonic-gate squish();
13637c478bd9Sstevel@tonic-gate }
136448bbca81SDaniel Hoffman
13657c478bd9Sstevel@tonic-gate /*
13667c478bd9Sstevel@tonic-gate * Set jp to the line where deleted text is to be added.
13677c478bd9Sstevel@tonic-gate */
13687c478bd9Sstevel@tonic-gate jp = unddel + 1;
136948bbca81SDaniel Hoffman
13707c478bd9Sstevel@tonic-gate /*
13717c478bd9Sstevel@tonic-gate * Set kp to end of undo save area.
13727c478bd9Sstevel@tonic-gate *
13737c478bd9Sstevel@tonic-gate * If there is any deleted text to be added, do reverses.
13747c478bd9Sstevel@tonic-gate */
137548bbca81SDaniel Hoffman
13767c478bd9Sstevel@tonic-gate if ((i = (kp = unddol) - dol) > 0) {
137748bbca81SDaniel Hoffman
13787c478bd9Sstevel@tonic-gate /*
13797c478bd9Sstevel@tonic-gate * If deleted lines are not to be appended
13807c478bd9Sstevel@tonic-gate * to the bottom of the file...
13817c478bd9Sstevel@tonic-gate */
138248bbca81SDaniel Hoffman
13837c478bd9Sstevel@tonic-gate if (jp != dolp1) {
13847c478bd9Sstevel@tonic-gate /*
13857c478bd9Sstevel@tonic-gate * FILE: LINE START REV1 REV2 REV3
13867c478bd9Sstevel@tonic-gate * 1) ab ab ab ab
13877c478bd9Sstevel@tonic-gate * 2) cd cd cd cd
13887c478bd9Sstevel@tonic-gate * 3) ef ef ef ef
13897c478bd9Sstevel@tonic-gate * unddel: 4) gh gh gh gh
13907c478bd9Sstevel@tonic-gate * undap1: 5) qr 78 78 ij
13917c478bd9Sstevel@tonic-gate * 6) st 56 56 kl
13927c478bd9Sstevel@tonic-gate * 7) uv 34 34 mn
13937c478bd9Sstevel@tonic-gate * 8) wx 12 12 op
13947c478bd9Sstevel@tonic-gate * undap2: 9) yz yz yz qr
13957c478bd9Sstevel@tonic-gate * 10) 12 wx wx st
13967c478bd9Sstevel@tonic-gate * 11) 34 uv uv uv
13977c478bd9Sstevel@tonic-gate * 12) 56 st st wx
13987c478bd9Sstevel@tonic-gate * dol: 13) 78 qr qr yz
13997c478bd9Sstevel@tonic-gate *
14007c478bd9Sstevel@tonic-gate * UNDO AREA:
14017c478bd9Sstevel@tonic-gate * dol+1: 5) ij ij op 12
14027c478bd9Sstevel@tonic-gate * 6) kl kl mn 34
14037c478bd9Sstevel@tonic-gate * 7) mn mn kl 56
14047c478bd9Sstevel@tonic-gate * unddol: 8) op op ij 78
14057c478bd9Sstevel@tonic-gate */
140648bbca81SDaniel Hoffman
14077c478bd9Sstevel@tonic-gate reverse(jp, dolp1);
14087c478bd9Sstevel@tonic-gate reverse(dolp1, ++kp);
14097c478bd9Sstevel@tonic-gate reverse(jp, kp);
14107c478bd9Sstevel@tonic-gate }
14117c478bd9Sstevel@tonic-gate /*
14127c478bd9Sstevel@tonic-gate * Account for possible forward motion of the target
14137c478bd9Sstevel@tonic-gate * (where the deleted lines were restored) for after
14147c478bd9Sstevel@tonic-gate * restoration of the deleted lines.
14157c478bd9Sstevel@tonic-gate */
14167c478bd9Sstevel@tonic-gate if (undap1 >= jp)
14177c478bd9Sstevel@tonic-gate undap1 += i;
14187c478bd9Sstevel@tonic-gate /*
14197c478bd9Sstevel@tonic-gate * Dot is the first resurrected line.
14207c478bd9Sstevel@tonic-gate */
14217c478bd9Sstevel@tonic-gate dot = jp;
142248bbca81SDaniel Hoffman
14237c478bd9Sstevel@tonic-gate /*
14247c478bd9Sstevel@tonic-gate * Account for a shift in the last line (dol).
14257c478bd9Sstevel@tonic-gate */
142648bbca81SDaniel Hoffman
14277c478bd9Sstevel@tonic-gate newdol += i;
14287c478bd9Sstevel@tonic-gate }
14297c478bd9Sstevel@tonic-gate /*
14307c478bd9Sstevel@tonic-gate * Clean up so we are invertible
14317c478bd9Sstevel@tonic-gate */
14327c478bd9Sstevel@tonic-gate unddel = undap1 - 1;
14337c478bd9Sstevel@tonic-gate undap1 = jp;
14347c478bd9Sstevel@tonic-gate undap2 = jp + i;
14357c478bd9Sstevel@tonic-gate dol = newdol;
14367c478bd9Sstevel@tonic-gate netchHAD(cnt);
14377c478bd9Sstevel@tonic-gate if (undkind == UNDALL) {
14387c478bd9Sstevel@tonic-gate dot = undadot;
14397c478bd9Sstevel@tonic-gate undadot = newadot;
14407c478bd9Sstevel@tonic-gate } else
14417c478bd9Sstevel@tonic-gate undkind = UNDCHANGE;
144248bbca81SDaniel Hoffman /*
144348bbca81SDaniel Hoffman * Now relocate all marks for lines that were modified,
144448bbca81SDaniel Hoffman * since the marks point to lines whose address has
144548bbca81SDaniel Hoffman * been modified from the save area to the current
144648bbca81SDaniel Hoffman * area
144748bbca81SDaniel Hoffman */
144848bbca81SDaniel Hoffman
144948bbca81SDaniel Hoffman for (j=unddol; j> dol; j--)
145048bbca81SDaniel Hoffman for (k=0; k<=25; k++)
145148bbca81SDaniel Hoffman if (names[k] == *(j))
145248bbca81SDaniel Hoffman names[k]= *((undap1+(j-dolp1)) );
14537c478bd9Sstevel@tonic-gate }
14547c478bd9Sstevel@tonic-gate /*
14557c478bd9Sstevel@tonic-gate * Defensive programming - after a munged undadot.
14567c478bd9Sstevel@tonic-gate * Also handle empty buffer case.
14577c478bd9Sstevel@tonic-gate */
14587c478bd9Sstevel@tonic-gate if ((dot <= zero || dot > dol) && dot != dol)
14597c478bd9Sstevel@tonic-gate dot = one;
14607c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
14617c478bd9Sstevel@tonic-gate if (trace)
14627c478bd9Sstevel@tonic-gate vudump("after undo");
14637c478bd9Sstevel@tonic-gate #endif
14647c478bd9Sstevel@tonic-gate }
14657c478bd9Sstevel@tonic-gate
14667c478bd9Sstevel@tonic-gate /*
14677c478bd9Sstevel@tonic-gate * Be (almost completely) sure there really
14687c478bd9Sstevel@tonic-gate * was a change, before claiming to undo.
14697c478bd9Sstevel@tonic-gate */
1470f6db9f27Scf void
somechange(void)1471f6db9f27Scf somechange(void)
14727c478bd9Sstevel@tonic-gate {
1473f6db9f27Scf line *ip, *jp;
14747c478bd9Sstevel@tonic-gate
14757c478bd9Sstevel@tonic-gate switch (undkind) {
14767c478bd9Sstevel@tonic-gate
14777c478bd9Sstevel@tonic-gate case UNDMOVE:
14787c478bd9Sstevel@tonic-gate return;
14797c478bd9Sstevel@tonic-gate
14807c478bd9Sstevel@tonic-gate case UNDCHANGE:
14817c478bd9Sstevel@tonic-gate if (undap1 == undap2 && dol == unddol)
14827c478bd9Sstevel@tonic-gate break;
14837c478bd9Sstevel@tonic-gate return;
14847c478bd9Sstevel@tonic-gate
14857c478bd9Sstevel@tonic-gate case UNDPUT:
14867c478bd9Sstevel@tonic-gate if (undap1 != undap2)
14877c478bd9Sstevel@tonic-gate return;
14887c478bd9Sstevel@tonic-gate break;
14897c478bd9Sstevel@tonic-gate
14907c478bd9Sstevel@tonic-gate case UNDALL:
14917c478bd9Sstevel@tonic-gate if (unddol - dol != lineDOL())
14927c478bd9Sstevel@tonic-gate return;
14937c478bd9Sstevel@tonic-gate for (ip = one, jp = dol + 1; ip <= dol; ip++, jp++)
14947c478bd9Sstevel@tonic-gate if ((*ip &~ 01) != (*jp &~ 01))
14957c478bd9Sstevel@tonic-gate return;
14967c478bd9Sstevel@tonic-gate break;
14977c478bd9Sstevel@tonic-gate
14987c478bd9Sstevel@tonic-gate case UNDNONE:
14997c478bd9Sstevel@tonic-gate error(gettext("Nothing to undo"));
15007c478bd9Sstevel@tonic-gate }
15017c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Nothing changed") :
15027c478bd9Sstevel@tonic-gate gettext("Last undoable command didn't change anything"));
15037c478bd9Sstevel@tonic-gate }
15047c478bd9Sstevel@tonic-gate
15057c478bd9Sstevel@tonic-gate /*
15067c478bd9Sstevel@tonic-gate * Map command:
15077c478bd9Sstevel@tonic-gate * map src dest
1508f6db9f27Scf *
1509f6db9f27Scf * un is true if this is unmap command
1510f6db9f27Scf * ab is true if this is abbr command
15117c478bd9Sstevel@tonic-gate */
1512f6db9f27Scf void
mapcmd(int un,int ab)1513f6db9f27Scf mapcmd(int un, int ab)
15147c478bd9Sstevel@tonic-gate {
15157c478bd9Sstevel@tonic-gate unsigned char lhs[100], rhs[100]; /* max sizes resp. */
1516f6db9f27Scf unsigned char *p;
1517f6db9f27Scf int c; /* char --> int */
15187c478bd9Sstevel@tonic-gate unsigned char *dname;
15197c478bd9Sstevel@tonic-gate struct maps *mp; /* the map structure we are working on */
15207c478bd9Sstevel@tonic-gate
15217c478bd9Sstevel@tonic-gate mp = ab ? abbrevs : exclam() ? immacs : arrows;
15227c478bd9Sstevel@tonic-gate if (skipend()) {
15237c478bd9Sstevel@tonic-gate int i;
15247c478bd9Sstevel@tonic-gate
15257c478bd9Sstevel@tonic-gate /* print current mapping values */
15267c478bd9Sstevel@tonic-gate if (peekchar() != EOF)
15277c478bd9Sstevel@tonic-gate ignchar();
15287c478bd9Sstevel@tonic-gate if (un)
15297c478bd9Sstevel@tonic-gate error(gettext("Missing lhs"));
15307c478bd9Sstevel@tonic-gate if (inopen)
15317c478bd9Sstevel@tonic-gate pofix();
15327c478bd9Sstevel@tonic-gate for (i=0; i< MAXNOMACS && mp[i].mapto; i++)
15337c478bd9Sstevel@tonic-gate if (mp[i].cap) {
15347c478bd9Sstevel@tonic-gate lprintf("%s", mp[i].descr);
15357c478bd9Sstevel@tonic-gate putchar('\t');
15367c478bd9Sstevel@tonic-gate lprintf("%s", mp[i].cap);
15377c478bd9Sstevel@tonic-gate putchar('\t');
15387c478bd9Sstevel@tonic-gate lprintf("%s", mp[i].mapto);
15397c478bd9Sstevel@tonic-gate putNFL();
15407c478bd9Sstevel@tonic-gate }
15417c478bd9Sstevel@tonic-gate return;
15427c478bd9Sstevel@tonic-gate }
15437c478bd9Sstevel@tonic-gate
15447c478bd9Sstevel@tonic-gate (void)skipwh();
15457c478bd9Sstevel@tonic-gate for (p=lhs; ; ) {
15467c478bd9Sstevel@tonic-gate c = getchar();
15477c478bd9Sstevel@tonic-gate if (c == CTRL('v')) {
15487c478bd9Sstevel@tonic-gate c = getchar();
15497c478bd9Sstevel@tonic-gate } else if (!un && any(c, " \t")) {
15507c478bd9Sstevel@tonic-gate /* End of lhs */
15517c478bd9Sstevel@tonic-gate break;
15527c478bd9Sstevel@tonic-gate } else if (endcmd(c) && c!='"') {
15537c478bd9Sstevel@tonic-gate ungetchar(c);
15547c478bd9Sstevel@tonic-gate if (un) {
15557c478bd9Sstevel@tonic-gate donewline();
15567c478bd9Sstevel@tonic-gate *p = 0;
1557f6db9f27Scf addmac(lhs, (unsigned char *)NOSTR,
1558f6db9f27Scf (unsigned char *)NOSTR, mp);
15597c478bd9Sstevel@tonic-gate return;
15607c478bd9Sstevel@tonic-gate } else
15617c478bd9Sstevel@tonic-gate error(gettext("Missing rhs"));
15627c478bd9Sstevel@tonic-gate }
15637c478bd9Sstevel@tonic-gate *p++ = c;
15647c478bd9Sstevel@tonic-gate }
15657c478bd9Sstevel@tonic-gate *p = 0;
15667c478bd9Sstevel@tonic-gate
15677c478bd9Sstevel@tonic-gate if (skipend())
15687c478bd9Sstevel@tonic-gate error(gettext("Missing rhs"));
15697c478bd9Sstevel@tonic-gate for (p=rhs; ; ) {
15707c478bd9Sstevel@tonic-gate c = getchar();
15717c478bd9Sstevel@tonic-gate if (c == CTRL('v')) {
15727c478bd9Sstevel@tonic-gate c = getchar();
15737c478bd9Sstevel@tonic-gate } else if (endcmd(c) && c!='"') {
15747c478bd9Sstevel@tonic-gate ungetchar(c);
15757c478bd9Sstevel@tonic-gate break;
15767c478bd9Sstevel@tonic-gate }
15777c478bd9Sstevel@tonic-gate *p++ = c;
15787c478bd9Sstevel@tonic-gate }
15797c478bd9Sstevel@tonic-gate *p = 0;
15807c478bd9Sstevel@tonic-gate donewline();
15817c478bd9Sstevel@tonic-gate /*
15827c478bd9Sstevel@tonic-gate * Special hack for function keys: #1 means key f1, etc.
15837c478bd9Sstevel@tonic-gate * If the terminal doesn't have function keys, we just use #1.
15847c478bd9Sstevel@tonic-gate */
15857c478bd9Sstevel@tonic-gate if (lhs[0] == '#') {
15867c478bd9Sstevel@tonic-gate unsigned char *fnkey;
15877c478bd9Sstevel@tonic-gate unsigned char *fkey();
15887c478bd9Sstevel@tonic-gate unsigned char funkey[3];
15897c478bd9Sstevel@tonic-gate
15907c478bd9Sstevel@tonic-gate fnkey = fkey(lhs[1] - '0');
15917c478bd9Sstevel@tonic-gate funkey[0] = 'f'; funkey[1] = lhs[1]; funkey[2] = 0;
15927c478bd9Sstevel@tonic-gate if (fnkey)
15937c478bd9Sstevel@tonic-gate strcpy(lhs, fnkey);
15947c478bd9Sstevel@tonic-gate dname = funkey;
15957c478bd9Sstevel@tonic-gate } else {
15967c478bd9Sstevel@tonic-gate dname = lhs;
15977c478bd9Sstevel@tonic-gate }
15987c478bd9Sstevel@tonic-gate addmac(lhs,rhs,dname,mp);
15997c478bd9Sstevel@tonic-gate }
16007c478bd9Sstevel@tonic-gate
16017c478bd9Sstevel@tonic-gate /*
16027c478bd9Sstevel@tonic-gate * Add a macro definition to those that already exist. The sequence of
16037c478bd9Sstevel@tonic-gate * chars "src" is mapped into "dest". If src is already mapped into something
16047c478bd9Sstevel@tonic-gate * this overrides the mapping. There is no recursion. Unmap is done by
16057c478bd9Sstevel@tonic-gate * using NOSTR for dest. Dname is what to show in listings. mp is
16067c478bd9Sstevel@tonic-gate * the structure to affect (arrows, etc).
16077c478bd9Sstevel@tonic-gate */
1608f6db9f27Scf void
addmac(unsigned char * src,unsigned char * dest,unsigned char * dname,struct maps * mp)1609f6db9f27Scf addmac(unsigned char *src, unsigned char *dest, unsigned char *dname,
1610f6db9f27Scf struct maps *mp)
16117c478bd9Sstevel@tonic-gate {
1612f6db9f27Scf int slot, zer;
16137c478bd9Sstevel@tonic-gate
16147c478bd9Sstevel@tonic-gate #ifdef UNDOTRACE
16157c478bd9Sstevel@tonic-gate if (trace)
16167c478bd9Sstevel@tonic-gate fprintf(trace, "addmac(src='%s', dest='%s', dname='%s', mp=%x\n", src, dest, dname, mp);
16177c478bd9Sstevel@tonic-gate #endif
16187c478bd9Sstevel@tonic-gate if (dest && mp==arrows) {
16197c478bd9Sstevel@tonic-gate /*
16207c478bd9Sstevel@tonic-gate * Prevent tail recursion. We really should be
16217c478bd9Sstevel@tonic-gate * checking to see if src is a suffix of dest
16227c478bd9Sstevel@tonic-gate * but this makes mapping involving escapes that
16237c478bd9Sstevel@tonic-gate * is reasonable mess up.
16247c478bd9Sstevel@tonic-gate */
16257c478bd9Sstevel@tonic-gate if (src[1] == 0 && src[0] == dest[strlen(dest)-1])
16267c478bd9Sstevel@tonic-gate error(gettext("No tail recursion"));
16277c478bd9Sstevel@tonic-gate /*
1628a141dbd6SAlison C * We don't let the user rob themself of ":", and making
16297c478bd9Sstevel@tonic-gate * multi char words is a bad idea so we don't allow it.
16307c478bd9Sstevel@tonic-gate * Note that if user sets mapinput and maps all of return,
163148bbca81SDaniel Hoffman * linefeed, and escape, they can hurt themself. This is
16327c478bd9Sstevel@tonic-gate * so weird I don't bother to check for it.
16337c478bd9Sstevel@tonic-gate */
16347c478bd9Sstevel@tonic-gate if (isalpha(src[0]) && isascii(src[0]) && src[1] || any(src[0],":"))
16357c478bd9Sstevel@tonic-gate error(gettext("Too dangerous to map that"));
16367c478bd9Sstevel@tonic-gate }
16377c478bd9Sstevel@tonic-gate else if (dest) {
16387c478bd9Sstevel@tonic-gate /* check for tail recursion in input mode: fussier */
16397c478bd9Sstevel@tonic-gate if (eq(src, dest+strlen(dest)-strlen(src)))
16407c478bd9Sstevel@tonic-gate error(gettext("No tail recursion"));
16417c478bd9Sstevel@tonic-gate }
16427c478bd9Sstevel@tonic-gate /*
16437c478bd9Sstevel@tonic-gate * If the src were null it would cause the dest to
16447c478bd9Sstevel@tonic-gate * be mapped always forever. This is not good.
16457c478bd9Sstevel@tonic-gate */
16467c478bd9Sstevel@tonic-gate if (src == (unsigned char *)NOSTR || src[0] == 0)
16477c478bd9Sstevel@tonic-gate error(gettext("Missing lhs"));
16487c478bd9Sstevel@tonic-gate
16497c478bd9Sstevel@tonic-gate /* see if we already have a def for src */
16507c478bd9Sstevel@tonic-gate zer = -1;
16517c478bd9Sstevel@tonic-gate for (slot=0; slot < MAXNOMACS && mp[slot].mapto; slot++) {
16527c478bd9Sstevel@tonic-gate if (mp[slot].cap) {
16537c478bd9Sstevel@tonic-gate if (eq(src, mp[slot].cap) || eq(src, mp[slot].mapto))
16547c478bd9Sstevel@tonic-gate break; /* if so, reuse slot */
16557c478bd9Sstevel@tonic-gate } else {
16567c478bd9Sstevel@tonic-gate zer = slot; /* remember an empty slot */
16577c478bd9Sstevel@tonic-gate }
16587c478bd9Sstevel@tonic-gate }
165948bbca81SDaniel Hoffman
16607c478bd9Sstevel@tonic-gate if (slot >= MAXNOMACS)
16617c478bd9Sstevel@tonic-gate error(gettext("Too many macros"));
16627c478bd9Sstevel@tonic-gate
16637c478bd9Sstevel@tonic-gate if (dest == (unsigned char *)NOSTR) {
16647c478bd9Sstevel@tonic-gate /* unmap */
16657c478bd9Sstevel@tonic-gate if (mp[slot].cap) {
16667c478bd9Sstevel@tonic-gate mp[slot].cap = (unsigned char *)NOSTR;
16677c478bd9Sstevel@tonic-gate mp[slot].descr = (unsigned char *)NOSTR;
16687c478bd9Sstevel@tonic-gate } else {
16697c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ? gettext("Not mapped") :
16707c478bd9Sstevel@tonic-gate gettext("That macro wasn't mapped"));
16717c478bd9Sstevel@tonic-gate }
16727c478bd9Sstevel@tonic-gate return;
16737c478bd9Sstevel@tonic-gate }
16747c478bd9Sstevel@tonic-gate
16757c478bd9Sstevel@tonic-gate /* reuse empty slot, if we found one and src isn't already defined */
16767c478bd9Sstevel@tonic-gate if (zer >= 0 && mp[slot].mapto == 0)
16777c478bd9Sstevel@tonic-gate slot = zer;
16787c478bd9Sstevel@tonic-gate
16797c478bd9Sstevel@tonic-gate /* if not, append to end */
16807c478bd9Sstevel@tonic-gate if (msnext == 0) /* first time */
16817c478bd9Sstevel@tonic-gate msnext = mapspace;
16827c478bd9Sstevel@tonic-gate /* Check is a bit conservative, we charge for dname even if reusing src */
16837c478bd9Sstevel@tonic-gate if (msnext - mapspace + strlen(dest) + strlen(src) + strlen(dname) + 3 > MAXCHARMACS)
16847c478bd9Sstevel@tonic-gate error(gettext("Too much macro text"));
16857c478bd9Sstevel@tonic-gate CP(msnext, src);
16867c478bd9Sstevel@tonic-gate mp[slot].cap = msnext;
16877c478bd9Sstevel@tonic-gate msnext += strlen(src) + 1; /* plus 1 for null on the end */
16887c478bd9Sstevel@tonic-gate CP(msnext, dest);
16897c478bd9Sstevel@tonic-gate mp[slot].mapto = msnext;
16907c478bd9Sstevel@tonic-gate msnext += strlen(dest) + 1;
16917c478bd9Sstevel@tonic-gate if (dname) {
16927c478bd9Sstevel@tonic-gate CP(msnext, dname);
16937c478bd9Sstevel@tonic-gate mp[slot].descr = msnext;
16947c478bd9Sstevel@tonic-gate msnext += strlen(dname) + 1;
16957c478bd9Sstevel@tonic-gate } else {
16967c478bd9Sstevel@tonic-gate /* default descr to string user enters */
16977c478bd9Sstevel@tonic-gate mp[slot].descr = src;
16987c478bd9Sstevel@tonic-gate }
16997c478bd9Sstevel@tonic-gate }
17007c478bd9Sstevel@tonic-gate
17017c478bd9Sstevel@tonic-gate /*
17027c478bd9Sstevel@tonic-gate * Implements macros from command mode. c is the buffer to
17037c478bd9Sstevel@tonic-gate * get the macro from.
17047c478bd9Sstevel@tonic-gate */
1705f6db9f27Scf void
cmdmac(c)17067c478bd9Sstevel@tonic-gate cmdmac(c)
17077c478bd9Sstevel@tonic-gate unsigned char c;
17087c478bd9Sstevel@tonic-gate {
17097c478bd9Sstevel@tonic-gate unsigned char macbuf[BUFSIZE];
17107c478bd9Sstevel@tonic-gate line *ad, *a1, *a2;
17117c478bd9Sstevel@tonic-gate unsigned char *oglobp;
17127c478bd9Sstevel@tonic-gate short pk;
17137c478bd9Sstevel@tonic-gate bool oinglobal;
17147c478bd9Sstevel@tonic-gate
17157c478bd9Sstevel@tonic-gate lastmac = c;
17167c478bd9Sstevel@tonic-gate oglobp = globp;
17177c478bd9Sstevel@tonic-gate oinglobal = inglobal;
17187c478bd9Sstevel@tonic-gate pk = peekc; peekc = 0;
17197c478bd9Sstevel@tonic-gate if (inglobal < 2)
17207c478bd9Sstevel@tonic-gate inglobal = 1;
17217c478bd9Sstevel@tonic-gate regbuf(c, macbuf, sizeof(macbuf));
17227c478bd9Sstevel@tonic-gate a1 = addr1; a2 = addr2;
17237c478bd9Sstevel@tonic-gate for (ad=a1; ad<=a2; ad++) {
17247c478bd9Sstevel@tonic-gate globp = macbuf;
17257c478bd9Sstevel@tonic-gate dot = ad;
17267c478bd9Sstevel@tonic-gate commands(1,1);
17277c478bd9Sstevel@tonic-gate }
17287c478bd9Sstevel@tonic-gate globp = oglobp;
17297c478bd9Sstevel@tonic-gate inglobal = oinglobal;
17307c478bd9Sstevel@tonic-gate peekc = pk;
17317c478bd9Sstevel@tonic-gate }
17327c478bd9Sstevel@tonic-gate
17337c478bd9Sstevel@tonic-gate unsigned char *
vgetpass(prompt)17347c478bd9Sstevel@tonic-gate vgetpass(prompt)
17356a3e8e86SRichard Lowe char *prompt;
17367c478bd9Sstevel@tonic-gate {
1737f6db9f27Scf unsigned char *p;
1738f6db9f27Scf int c;
17397c478bd9Sstevel@tonic-gate static unsigned char pbuf[9];
17407c478bd9Sstevel@tonic-gate
17417c478bd9Sstevel@tonic-gate /* In ex mode, let the system hassle with setting no echo */
17427c478bd9Sstevel@tonic-gate if (!inopen)
17437c478bd9Sstevel@tonic-gate return (unsigned char *)getpass(prompt);
1744f6db9f27Scf viprintf("%s", prompt); flush();
17457c478bd9Sstevel@tonic-gate for (p=pbuf; (c = getkey())!='\n' && c!=EOF && c!='\r';) {
17467c478bd9Sstevel@tonic-gate if (p < &pbuf[8])
17477c478bd9Sstevel@tonic-gate *p++ = c;
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate *p = '\0';
17507c478bd9Sstevel@tonic-gate return(pbuf);
17517c478bd9Sstevel@tonic-gate }
17527c478bd9Sstevel@tonic-gate
17537c478bd9Sstevel@tonic-gate
17547c478bd9Sstevel@tonic-gate #ifdef TAG_STACK
17557c478bd9Sstevel@tonic-gate #define TSTACKSIZE 20
17567c478bd9Sstevel@tonic-gate struct tagstack {
17577c478bd9Sstevel@tonic-gate line *tag_line;
17587c478bd9Sstevel@tonic-gate char *tag_file;
17597c478bd9Sstevel@tonic-gate } tagstack[TSTACKSIZE];
17607c478bd9Sstevel@tonic-gate static int tag_depth = 0;
17617c478bd9Sstevel@tonic-gate
17627c478bd9Sstevel@tonic-gate static char tag_buf[ 1024 ];
17637c478bd9Sstevel@tonic-gate static char *tag_end = tag_buf;
17647c478bd9Sstevel@tonic-gate
1765f6db9f27Scf void
savetag(char * name)1766f6db9f27Scf savetag(char *name) /* saves location where we are */
17677c478bd9Sstevel@tonic-gate {
17687c478bd9Sstevel@tonic-gate if( !value(vi_TAGSTACK) )
17697c478bd9Sstevel@tonic-gate return;
17707c478bd9Sstevel@tonic-gate if(tag_depth >= TSTACKSIZE) {
17717c478bd9Sstevel@tonic-gate error(gettext("Tagstack too deep."));
17727c478bd9Sstevel@tonic-gate }
17737c478bd9Sstevel@tonic-gate if( strlen( name ) + 1 + tag_end >= &tag_buf[1024]) {
17747c478bd9Sstevel@tonic-gate error(gettext("Too many tags."));
17757c478bd9Sstevel@tonic-gate }
17767c478bd9Sstevel@tonic-gate tagstack[tag_depth].tag_line = dot;
17777c478bd9Sstevel@tonic-gate tagstack[tag_depth++].tag_file = tag_end;
17787c478bd9Sstevel@tonic-gate while(*tag_end++ = *name++)
17797c478bd9Sstevel@tonic-gate ;
17807c478bd9Sstevel@tonic-gate }
17817c478bd9Sstevel@tonic-gate
17827c478bd9Sstevel@tonic-gate /*
17837c478bd9Sstevel@tonic-gate * Undo a "savetag".
17847c478bd9Sstevel@tonic-gate */
1785f6db9f27Scf void
unsavetag(void)1786f6db9f27Scf unsavetag(void)
17877c478bd9Sstevel@tonic-gate {
17887c478bd9Sstevel@tonic-gate if (!value(vi_TAGSTACK))
17897c478bd9Sstevel@tonic-gate return;
17907c478bd9Sstevel@tonic-gate if (tag_depth > 0)
17917c478bd9Sstevel@tonic-gate tag_end = tagstack[--tag_depth].tag_file;
17927c478bd9Sstevel@tonic-gate }
17937c478bd9Sstevel@tonic-gate
1794f6db9f27Scf void
poptag(quick)17957c478bd9Sstevel@tonic-gate poptag(quick) /* puts us back where we came from */
17967c478bd9Sstevel@tonic-gate bool quick;
17977c478bd9Sstevel@tonic-gate {
17987c478bd9Sstevel@tonic-gate unsigned char cmdbuf[100];
17997c478bd9Sstevel@tonic-gate unsigned char *oglobp;
18007c478bd9Sstevel@tonic-gate int d;
18017c478bd9Sstevel@tonic-gate
18027c478bd9Sstevel@tonic-gate if (!value(vi_TAGSTACK)) { /* reset the stack */
18037c478bd9Sstevel@tonic-gate tag_end = tag_buf;
18047c478bd9Sstevel@tonic-gate d = tag_depth;
18057c478bd9Sstevel@tonic-gate tag_depth = 0;
18067c478bd9Sstevel@tonic-gate if (d == 0)
18077c478bd9Sstevel@tonic-gate error(gettext("Tagstack not enabled."));
18087c478bd9Sstevel@tonic-gate else
18097c478bd9Sstevel@tonic-gate return;
18107c478bd9Sstevel@tonic-gate }
18117c478bd9Sstevel@tonic-gate if (!tag_depth)
18127c478bd9Sstevel@tonic-gate error(gettext("Tagstack empty."));
181348bbca81SDaniel Hoffman
18147c478bd9Sstevel@tonic-gate /* change to old file */
18157c478bd9Sstevel@tonic-gate if (strcmp(tagstack[tag_depth-1].tag_file, savedfile) ) {
18167c478bd9Sstevel@tonic-gate if (!quick) {
18177c478bd9Sstevel@tonic-gate ckaw();
18187c478bd9Sstevel@tonic-gate if (chng && dol > zero)
18197c478bd9Sstevel@tonic-gate error(value(vi_TERSE) ?
18207c478bd9Sstevel@tonic-gate gettext("No write") : gettext("No write since last change (:pop! overrides)"));
18217c478bd9Sstevel@tonic-gate }
18227c478bd9Sstevel@tonic-gate oglobp = globp;
18237c478bd9Sstevel@tonic-gate strcpy(cmdbuf, "e! ");
18247c478bd9Sstevel@tonic-gate strcat(cmdbuf, tagstack[tag_depth-1].tag_file);
18257c478bd9Sstevel@tonic-gate globp = cmdbuf;
18267c478bd9Sstevel@tonic-gate d = peekc; ungetchar(0);
18277c478bd9Sstevel@tonic-gate commands(1, 1);
18287c478bd9Sstevel@tonic-gate peekc = d;
18297c478bd9Sstevel@tonic-gate globp = oglobp;
18307c478bd9Sstevel@tonic-gate }
18317c478bd9Sstevel@tonic-gate markpr(dot);
18327c478bd9Sstevel@tonic-gate /* set line number */
18337c478bd9Sstevel@tonic-gate dot = tagstack[--tag_depth].tag_line;
18347c478bd9Sstevel@tonic-gate tag_end = tagstack[tag_depth].tag_file;
18357c478bd9Sstevel@tonic-gate }
18367c478bd9Sstevel@tonic-gate #endif
1837