4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2016 by Delphix. All rights reserved.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
31 /* Copyright (c) 1981 Regents of the University of California */
46 * Command mode subroutines implementing
47 * append, args, copy, delete, join, move, put,
48 * shift, tag, yank, z and undo
53 static int jnoop(void);
54 static void splitit(void);
55 int putchar(), getchar();
59 * Append after line a lines returned by function f.
60 * Be careful about intermediate states to avoid scramble
61 * if an interrupt comes in.
64 append(int (*f
)(), line
*a
)
71 if(FIXUNDO
&& !inopen
&& f
!=getsub
) {
72 undap1
= undap2
= dot
+ 1;
76 if (truedol
>= endcore
) {
77 if (morelines() < 0) {
78 if (FIXUNDO
&& f
== getsub
) {
82 error(value(vi_TERSE
) ? gettext("Out of memory") :
83 gettext("Out of memory- too many lines in file"));
94 for (rdot
= dot
; a1
> rdot
;)
112 undap1
= undap2
= addr1
;
117 * Print out the argument list, with []'s around the current name.
122 unsigned char **av
= argv0
, *as
= args0
;
125 for (ac
= 0; ac
< argc0
; ac
++) {
128 if (ac
+ argc
== argc0
- 1)
131 if (ac
+ argc
== argc0
- 1)
133 as
= av
? *++av
: strend(as
) + 1;
139 * Delete lines; two cases are if we are really deleting,
140 * more commonly we are just moving lines to the undo save area.
153 vudump("before delete");
156 dsavint
= signal(SIGINT
, SIG_IGN
);
163 reverse(a2
, dol
+ 1);
164 reverse(a1
, dol
+ 1);
171 pkill
[0] = pkill
[1] = 0;
172 signal(SIGINT
, dsavint
);
175 vudump("after delete");
215 * Crush out the undo save area, moving the open/visual
216 * save area down in its place.
221 line
*a1
= dol
+ 1, *a2
= unddol
+ 1, *a3
= truedol
+ 1;
226 if (a1
< a2
&& a2
< a3
)
230 truedol
-= unddol
- dol
;
236 * Join lines. Special hacks put in spaces, two spaces if
237 * preceding line ends with '.', or no spaces if next line starts with ).
245 unsigned char *cp
, *cp1
;
251 #endif /* PRESUNEUC */
255 for (a1
= addr1
; a1
<= addr2
; a1
++) {
258 if (a1
!= addr1
&& c
== 0) {
259 while (*cp1
== ' ' || *cp1
== '\t')
261 if (*cp1
&& cp
> genbuf
&& cp
[-1] != ' ' && cp
[-1] != '\t') {
264 * insert locale-specific word delimiter if
265 * either of end-of-former-line or
266 * top-of-latter-line is non-ASCII.
268 if (wddlm
&& *cp1
!= ')' && cp
[-1] != '.') {
269 if ((pcp
= cp
- MB_CUR_MAX
) < genbuf
)
271 for ( ; pcp
<= cp
-1; pcp
++) {
272 if ((n
= mbtowc(&wc1
,
273 (char *)pcp
, cp
- pcp
)) ==
279 if (!isascii(wc2
= *cp1
)) {
280 if (mbtowc(&wc2
, (char *) cp1
,
284 delim
= (*wddlm
)(wc1
,wc2
,2);
286 cp
+= wctomb((char *)cp
,
291 #endif /* PRESUNEUC */
299 while (*cp
++ = *cp1
++)
300 if (cp
> &genbuf
[LBSIZE
-2])
301 error(value(vi_TERSE
) ? gettext("Line overflow") :
302 gettext("Result line of join would be too long"));
309 undap1
= undap2
= addr1
;
310 (void)append(jnoop
, --addr1
);
324 * Move and copy lines. Hard work is done by move1 which
325 * is also called by undo.
335 if (Command
[0] == 'm') {
337 markpr(addr2
== dot
? addr1
- 1 : addr2
+ 1);
343 adt
= address((char*)0);
345 serror(value(vi_TERSE
) ?
346 (unsigned char *)gettext("%s where?") :
347 (unsigned char *)gettext("%s requires a trailing address"),
355 move1(int cflag
, line
*addrt
)
357 line
*adt
, *ad1
, *ad2
;
361 nlines
= (addr2
- addr1
) + 1;
365 (void)append(getcopy
, ad1
++);
369 for (ad1
= addr1
; ad1
<= ad2
;)
375 if (adt
+ 1 == ad1
&& !cflag
&& !inglobal
)
376 error(gettext("That move would do nothing!"));
377 dot
= adt
+ (ad2
- ad1
);
383 } else if (adt
>= ad2
) {
389 error(gettext("Move to a moved line"));
395 undap2
= undap1
+ nlines
;
418 * Put lines in the buffer from the undo save area.
437 error(gettext("Cannot put inside global/macro"));
439 if (cnt
&& inopen
&& pkill
[0] && pkill
[1]) {
444 (void)append(getput
, addr2
);
452 * A tricky put, of a group of lines in the middle
453 * of an existing line. Only from open/visual.
454 * Argument says pkills have meaning, e.g. called from
455 * put; it is 0 on calls from putreg.
460 extern unsigned char *cursor
;
462 extern int P_cursor_offset
;
464 unsigned char *gp
= &genbuf
[cursor
- linebuf
];
467 * Assume the editor has:
483 * Copy "abcd" into genbuf.
484 * Note that gp points to 'c'.
487 strcpy(genbuf
, linebuf
);
490 * Get last line of undo area ("3") into linebuf.
499 * Concatenate trailing end of current line
500 * into the last line of undo area:
506 P_cursor_offset
= strlen(linebuf
) - strlen(gp
) - 1;
510 * Replace the last line with what is now in linebuf.
517 * Get the first line of the undo save area into linebuf.
526 * Copy the first line of the undo save area
527 * over what is pointed to by sp.
534 * Now copy genbuf back into linebuf.
541 * Now put linebuf back into the first line
542 * of the undo save area.
548 * Prepare to perform an undo which will actually
549 * do a put of multiple lines in the middle of
561 * Shift lines, based on c.
562 * If c is neither < nor >, then this is a lisp aligning =.
565 shift(int c
, int cnt
)
573 save12(), undkind
= UNDCHANGE
;
574 cnt
*= value(vi_SHIFTWIDTH
);
575 for (addr
= addr1
; addr
<= addr2
; addr
++) {
577 if (c
== '=' && addr
== addr1
&& addr
!= addr2
)
580 i
= whitecnt(linebuf
);
586 cp
= genindent(i
+ cnt
);
593 cp
= i
> 0 ? genindent(i
) : genbuf
;
602 if (cp
+ strlen(dp
= vpastwh(linebuf
)) >= &genbuf
[LBSIZE
- 2])
603 error(value(vi_TERSE
) ? gettext("Line too long") :
604 gettext("Result line after shift would be too long"));
613 * Find a tag in the tags file.
614 * Most work here is in parsing the tags file itself.
620 unsigned char cmdbuf
[BUFSIZE
];
621 unsigned char filebuf
[FNSIZE
];
622 unsigned char tagfbuf
[BUFSIZE
];
627 unsigned char *fn
, *fne
;
628 #ifdef STDIO /* was VMUNIX */
630 * We have lots of room so we bring in stdio and do
631 * a binary search on the tags file.
634 unsigned char iofbuf
[BUFSIZE
];
635 off64_t mid
; /* assumed byte offset */
636 off64_t top
, bot
; /* length of tag file */
640 omagic
= value(vi_MAGIC
);
641 tl
= value(vi_TAGLENGTH
);
643 unsigned char *lp
= lasttag
;
645 while (!iswhite(peekchar()) && !endcmd(peekchar()))
646 if (lp
< &lasttag
[sizeof lasttag
- 2])
651 if (!endcmd(peekchar()))
653 error(value(vi_TERSE
) ? gettext("Bad tag") :
654 gettext("Give one tag per line"));
655 } else if (lasttag
[0] == 0)
656 error(gettext("No previous tag"));
665 * Loop once for each file in tags "path".
667 * System tags array limits to 4k (tags[ONMSZ]) long,
668 * therefore, tagfbuf should be able to hold all tags.
671 CP(tagfbuf
, svalue(vi_TAGS
));
675 while (*fne
&& *fne
!= ' ')
678 fne
= 0; /* done, quit after this time */
680 *fne
= 0; /* null terminate filename */
681 #ifdef STDIO /* was VMUNIX */
682 iof
= fopen((char *)fn
, "r");
686 setbuf(iof
, (char *)iofbuf
);
687 fstat64(fileno(iof
), &sbuf
);
689 if (top
== 0L || iof
== NULL
)
693 /* loop for each tags file entry */
694 unsigned char *cp
= linebuf
;
695 unsigned char *lp
= lasttag
;
696 unsigned char *oglobp
;
698 mid
= (top
+ bot
) / 2;
699 fseeko64(iof
, mid
, 0);
700 if (mid
> 0) /* to get first tag in file to work */
701 /* scan to next \n */
702 if(fgets((char *)linebuf
, sizeof linebuf
, iof
)==NULL
)
704 /* get the line itself */
705 if(fgets((char *)linebuf
, sizeof linebuf
, iof
)==NULL
)
707 linebuf
[strlen(linebuf
)-1] = 0; /* was '\n' */
708 while (*cp
&& *lp
== *cp
)
711 * This if decides whether there is a tag match.
712 * A positive taglength means that a
713 * match is found if the tag given matches at least
714 * taglength chars of the tag found.
715 * A taglength of greater than 511 means that a
716 * match is found even if the tag given is a proper
717 * prefix of the tag found. i.e. "ab" matches "abcd"
719 if ( *lp
== 0 && (iswhite(*cp
) || tl
> 511 || tl
> 0 && lp
-lasttag
>= tl
) ) {
721 * Found a match. Force selection to be
722 * the first possible.
724 if ( mid
== bot
&& mid
== top
) {
725 ; /* found first possible match */
728 /* postpone final decision. */
734 if ((int)*lp
> (int)*cp
)
742 * We found the tag. Decode the line in the file.
746 /* Rest of tag if abbreviated */
747 while (!iswhite(*cp
))
751 while (*cp
&& iswhite(*cp
))
755 serror((unsigned char *)
756 gettext("%s: Bad tags file entry"),
759 while (*cp
&& *cp
!= ' ' && *cp
!= '\t') {
760 if (lp
< &filebuf
[sizeof filebuf
- 2])
770 * Save current position in 't for ^^ in visual.
772 names
['t'-'a'] = *dot
&~ 01;
774 extern unsigned char *ncols
['z'-'a'+2];
775 extern unsigned char *cursor
;
777 ncols
['t'-'a'] = cursor
;
782 savetag((char *)savedfile
);
786 if (strcmp(filebuf
, savedfile
) || !edited
) {
787 unsigned char cmdbuf2
[sizeof filebuf
+ 10];
789 /* Different file. Do autowrite & get it. */
792 if (chng
&& dol
> zero
) {
796 error(value(vi_TERSE
) ?
797 gettext("No write") : gettext("No write since last change (:tag! overrides)"));
801 strcpy(cmdbuf2
, "e! ");
802 strcat(cmdbuf2
, filebuf
);
804 d
= peekc
; ungetchar(0);
808 value(vi_MAGIC
) = omagic
;
813 * Look for pattern in the current file.
817 d
= peekc
; ungetchar(0);
821 * BUG: if it isn't found (user edited header
822 * line) we get left in nomagic mode.
828 value(vi_MAGIC
) = omagic
;
830 } /* end of "for each tag in file" */
833 * Binary search failed, so try linear search if -S is on.
834 * -S is needed for tags files that are not sorted.
838 * Avoid stdio and scan tag file linearly.
846 while (getfile() == 0) {
847 /* loop for each tags file entry */
848 unsigned char *cp
= linebuf
;
849 unsigned char *lp
= lasttag
;
850 unsigned char *oglobp
;
852 while (*cp
&& *lp
== *cp
)
855 * This if decides whether there is a tag match.
856 * A positive taglength means that a
857 * match is found if the tag given matches at least
858 * taglength chars of the tag found.
859 * A taglength of greater than 511 means that a
860 * match is found even if the tag given is a proper
861 * prefix of the tag found. i.e. "ab" matches "abcd"
863 if ( *lp
== 0 && (iswhite(*cp
) || tl
> 511 || tl
> 0 && lp
-lasttag
>= tl
) ) {
867 /* Not this tag. Try the next */
871 * We found the tag. Decode the line in the file.
874 /* Rest of tag if abbreviated */
875 while (!iswhite(*cp
))
879 while (*cp
&& iswhite(*cp
))
883 serror((unsigned char *)
884 gettext("%s: Bad tags file entry"),
887 while (*cp
&& *cp
!= ' ' && *cp
!= '\t') {
888 if (lp
< &filebuf
[sizeof filebuf
- 2])
898 * Save current position in 't for ^^ in visual.
900 names
['t'-'a'] = *dot
&~ 01;
902 extern unsigned char *ncols
['z'-'a'+2];
903 extern unsigned char *cursor
;
905 ncols
['t'-'a'] = cursor
;
910 savetag((char *)savedfile
);
914 if (strcmp(filebuf
, savedfile
) || !edited
) {
915 unsigned char cmdbuf2
[sizeof filebuf
+ 10];
917 /* Different file. Do autowrite & get it. */
920 if (chng
&& dol
> zero
) {
924 error(value(vi_TERSE
) ?
925 gettext("No write") : gettext("No write since last change (:tag! overrides)"));
929 strcpy(cmdbuf2
, "e! ");
930 strcat(cmdbuf2
, filebuf
);
932 d
= peekc
; ungetchar(0);
936 value(vi_MAGIC
) = omagic
;
941 * Look for pattern in the current file.
945 d
= peekc
; ungetchar(0);
949 * BUG: if it isn't found (user edited header
950 * line) we get left in nomagic mode.
956 value(vi_MAGIC
) = omagic
;
958 } /* end of "for each tag in file" */
961 * No such tag in this file. Close it and try the next.
963 #ifdef STDIO /* was VMUNIX */
968 } /* end of "for each file in path" */
970 error(gettext("No tags file"));
972 serror(value(vi_TERSE
) ?
973 (unsigned char *)gettext("%s: No such tag") :
974 (unsigned char *)gettext("%s: No such tag in tags file"),
979 * Save lines from addr1 thru addr2 as though
980 * they had been deleted.
987 error(gettext("Can't yank inside global/macro"));
990 killcnt(addr2
- addr1
+ 1);
995 * z command; print windows of text in the file.
997 * If this seems unreasonably arcane, the reasons
998 * are historical. This is one of the first commands
999 * added to the first ex (then called en) and the
1000 * number of facilities here were the major advantage
1001 * of en over ed since they allowed more use to be
1002 * made of fast terminals w/o typing .,.22p all the time.
1019 switch (c
= op
= getchar()) {
1025 while (peekchar() == op
) {
1053 value(vi_WINDOW
) = nlines
;
1058 nlines
= op
== EOF
? value(vi_SCROLL
) :
1059 excl
? lines
- 1 : value(vi_WINDOW
);
1061 if (inopen
|| c
!= EOF
) {
1066 if (addr2
== 0 && dot
< dol
&& op
== 0)
1067 addr1
= addr2
= dot
+1;
1073 zop2(int nlines
, int op
)
1082 error(gettext("\nAt EOF"));
1085 error(gettext("At EOF"));
1086 addr2
+= nlines
* zweight
;
1088 error(gettext("Hit BOTTOM"));
1103 addr1
= addr2
- nlines
;
1105 dot
= split
= addr2
;
1115 addr2
-= nlines
* zweight
;
1117 error(gettext("Hit TOP"));
1119 addr1
= addr2
- nlines
;
1131 if (op
== EOF
&& zhadpr
) {
1133 putchar((int)('\r' | QUOTE
));
1135 } else if (znoclear
== 0 && clear_screen
!= NOSTR
&& !inopen
) {
1139 if (addr2
- addr1
> 1)
1142 plines(addr1
, split
- 1, 0);
1144 plines(split
, split
, 0);
1148 plines(addr1
, addr2
, 0);
1156 for (l
= columns
> 80 ? 40 : columns
/ 2; l
> 0; l
--)
1162 plines(line
*adr1
, line
*adr2
, bool movedot
)
1167 for (addr
= adr1
; addr
<= adr2
; addr
++) {
1169 pline(lineno(addr
));
1171 putchar((int)('\n' | QUOTE
));
1181 if (inopen
&& Outchar
!= termchar
) {
1188 * Command level undo works easily because
1189 * the editor has a unique temporary file
1190 * index for every line which ever existed.
1191 * We don't have to save large blocks of text,
1192 * only the indices which are small. We do this
1193 * by moving them to after the last line in the
1194 * line buffer array, and marking down info
1195 * about whence they came.
1197 * Undo is its own inverse.
1204 line
*dolp1
, *newdol
, *newadot
;
1208 vudump("before undo");
1210 if (inglobal
&& inopen
<= 0)
1211 error(value(vi_TERSE
) ? gettext("Can't undo in global") :
1212 gettext("Can't undo in global commands"));
1215 * Unless flag indicates a forced undo, make sure
1216 * there really was a change before trying to undo it.
1223 * Update change flags.
1226 pkill
[0] = pkill
[1] = 0;
1228 if (undkind
== UNDMOVE
) {
1230 * Command to be undone is a move command.
1231 * This is handled as a special case by noting that
1232 * a move "a,b m c" can be inverted by another move.
1234 if ((i
= (jp
= unddel
) - undap2
) > 0) {
1236 * when c > b inverse is a+(c-b),c m a-1
1239 addr1
= (jp
= undap1
) + i
;
1243 * when b > c inverse is c+1,c+1+(b-a) m b
1246 addr2
= jp
+ ((unddel
= undap2
) - undap1
);
1251 Command
= (unsigned char *)"move";
1261 * Command to be undone is a non-move.
1262 * All such commands are treated as a combination of
1263 * a delete command and a append command.
1264 * We first move the lines appended by the last command
1265 * from undap1 to undap2-1 so that they are just before the
1266 * saved deleted lines.
1268 * Assume the editor has:
1272 * (just change lines 5-8)
1296 * If this is a change (not a delete/put),
1297 * then we must move the text between undap1 and undap2
1298 * and it must not be at the bottom of the file
1301 if ((i
= (kp
= undap2
) - (jp
= undap1
)) > 0) {
1305 * FILE: LINE INITIAL REV1 REV2 REV3
1310 * unddel: 4) gh gh gh gh
1311 * undap1: 5) 12 78 78 qr
1315 * undap2: 9) qr qr yz yz
1319 * dol: 13) yz yz qr 78
1322 * dol+1: 5) ij ij ij ij
1325 * unddol: 8) op op op op
1333 * Unddel, the line just before the spot where this
1334 * test was deleted, may have moved. Account for
1335 * this in restoration of saved deleted lines.
1341 * The last line (dol) may have changed,
1347 * For the case where no lines are restored, dot
1348 * is the line before the first line deleted.
1353 * Now put the deleted lines, if any, back where they were.
1354 * Basic operation is: dol+1,unddol m unddel
1356 if (undkind
== UNDPUT
) {
1357 unddel
= undap1
- 1;
1362 * Set jp to the line where deleted text is to be added.
1367 * Set kp to end of undo save area.
1369 * If there is any deleted text to be added, do reverses.
1372 if ((i
= (kp
= unddol
) - dol
) > 0) {
1375 * If deleted lines are not to be appended
1376 * to the bottom of the file...
1381 * FILE: LINE START REV1 REV2 REV3
1385 * unddel: 4) gh gh gh gh
1386 * undap1: 5) qr 78 78 ij
1390 * undap2: 9) yz yz yz qr
1394 * dol: 13) 78 qr qr yz
1397 * dol+1: 5) ij ij op 12
1400 * unddol: 8) op op ij 78
1404 reverse(dolp1
, ++kp
);
1408 * Account for possible forward motion of the target
1409 * (where the deleted lines were restored) for after
1410 * restoration of the deleted lines.
1415 * Dot is the first resurrected line.
1420 * Account for a shift in the last line (dol).
1426 * Clean up so we are invertible
1428 unddel
= undap1
- 1;
1433 if (undkind
== UNDALL
) {
1437 undkind
= UNDCHANGE
;
1439 * Now relocate all marks for lines that were modified,
1440 * since the marks point to lines whose address has
1441 * been modified from the save area to the current
1445 for (j
=unddol
; j
> dol
; j
--)
1446 for (k
=0; k
<=25; k
++)
1447 if (names
[k
] == *(j
))
1448 names
[k
]= *((undap1
+(j
-dolp1
)) );
1451 * Defensive programming - after a munged undadot.
1452 * Also handle empty buffer case.
1454 if ((dot
<= zero
|| dot
> dol
) && dot
!= dol
)
1458 vudump("after undo");
1463 * Be (almost completely) sure there really
1464 * was a change, before claiming to undo.
1477 if (undap1
== undap2
&& dol
== unddol
)
1482 if (undap1
!= undap2
)
1487 if (unddol
- dol
!= lineDOL())
1489 for (ip
= one
, jp
= dol
+ 1; ip
<= dol
; ip
++, jp
++)
1490 if ((*ip
&~ 01) != (*jp
&~ 01))
1495 error(gettext("Nothing to undo"));
1497 error(value(vi_TERSE
) ? gettext("Nothing changed") :
1498 gettext("Last undoable command didn't change anything"));
1505 * un is true if this is unmap command
1506 * ab is true if this is abbr command
1509 mapcmd(int un
, int ab
)
1511 unsigned char lhs
[100], rhs
[100]; /* max sizes resp. */
1513 int c
; /* char --> int */
1514 unsigned char *dname
;
1515 struct maps
*mp
; /* the map structure we are working on */
1517 mp
= ab
? abbrevs
: exclam() ? immacs
: arrows
;
1521 /* print current mapping values */
1522 if (peekchar() != EOF
)
1525 error(gettext("Missing lhs"));
1528 for (i
=0; i
< MAXNOMACS
&& mp
[i
].mapto
; i
++)
1530 lprintf("%s", mp
[i
].descr
);
1532 lprintf("%s", mp
[i
].cap
);
1534 lprintf("%s", mp
[i
].mapto
);
1543 if (c
== CTRL('v')) {
1545 } else if (!un
&& any(c
, " \t")) {
1548 } else if (endcmd(c
) && c
!='"') {
1553 addmac(lhs
, (unsigned char *)NOSTR
,
1554 (unsigned char *)NOSTR
, mp
);
1557 error(gettext("Missing rhs"));
1564 error(gettext("Missing rhs"));
1567 if (c
== CTRL('v')) {
1569 } else if (endcmd(c
) && c
!='"') {
1578 * Special hack for function keys: #1 means key f1, etc.
1579 * If the terminal doesn't have function keys, we just use #1.
1581 if (lhs
[0] == '#') {
1582 unsigned char *fnkey
;
1583 unsigned char *fkey();
1584 unsigned char funkey
[3];
1586 fnkey
= fkey(lhs
[1] - '0');
1587 funkey
[0] = 'f'; funkey
[1] = lhs
[1]; funkey
[2] = 0;
1594 addmac(lhs
,rhs
,dname
,mp
);
1598 * Add a macro definition to those that already exist. The sequence of
1599 * chars "src" is mapped into "dest". If src is already mapped into something
1600 * this overrides the mapping. There is no recursion. Unmap is done by
1601 * using NOSTR for dest. Dname is what to show in listings. mp is
1602 * the structure to affect (arrows, etc).
1605 addmac(unsigned char *src
, unsigned char *dest
, unsigned char *dname
,
1612 fprintf(trace
, "addmac(src='%s', dest='%s', dname='%s', mp=%x\n", src
, dest
, dname
, mp
);
1614 if (dest
&& mp
==arrows
) {
1616 * Prevent tail recursion. We really should be
1617 * checking to see if src is a suffix of dest
1618 * but this makes mapping involving escapes that
1619 * is reasonable mess up.
1621 if (src
[1] == 0 && src
[0] == dest
[strlen(dest
)-1])
1622 error(gettext("No tail recursion"));
1624 * We don't let the user rob himself of ":", and making
1625 * multi char words is a bad idea so we don't allow it.
1626 * Note that if user sets mapinput and maps all of return,
1627 * linefeed, and escape, they can hurt themself. This is
1628 * so weird I don't bother to check for it.
1630 if (isalpha(src
[0]) && isascii(src
[0]) && src
[1] || any(src
[0],":"))
1631 error(gettext("Too dangerous to map that"));
1634 /* check for tail recursion in input mode: fussier */
1635 if (eq(src
, dest
+strlen(dest
)-strlen(src
)))
1636 error(gettext("No tail recursion"));
1639 * If the src were null it would cause the dest to
1640 * be mapped always forever. This is not good.
1642 if (src
== (unsigned char *)NOSTR
|| src
[0] == 0)
1643 error(gettext("Missing lhs"));
1645 /* see if we already have a def for src */
1647 for (slot
=0; slot
< MAXNOMACS
&& mp
[slot
].mapto
; slot
++) {
1649 if (eq(src
, mp
[slot
].cap
) || eq(src
, mp
[slot
].mapto
))
1650 break; /* if so, reuse slot */
1652 zer
= slot
; /* remember an empty slot */
1656 if (slot
>= MAXNOMACS
)
1657 error(gettext("Too many macros"));
1659 if (dest
== (unsigned char *)NOSTR
) {
1662 mp
[slot
].cap
= (unsigned char *)NOSTR
;
1663 mp
[slot
].descr
= (unsigned char *)NOSTR
;
1665 error(value(vi_TERSE
) ? gettext("Not mapped") :
1666 gettext("That macro wasn't mapped"));
1671 /* reuse empty slot, if we found one and src isn't already defined */
1672 if (zer
>= 0 && mp
[slot
].mapto
== 0)
1675 /* if not, append to end */
1676 if (msnext
== 0) /* first time */
1678 /* Check is a bit conservative, we charge for dname even if reusing src */
1679 if (msnext
- mapspace
+ strlen(dest
) + strlen(src
) + strlen(dname
) + 3 > MAXCHARMACS
)
1680 error(gettext("Too much macro text"));
1682 mp
[slot
].cap
= msnext
;
1683 msnext
+= strlen(src
) + 1; /* plus 1 for null on the end */
1685 mp
[slot
].mapto
= msnext
;
1686 msnext
+= strlen(dest
) + 1;
1689 mp
[slot
].descr
= msnext
;
1690 msnext
+= strlen(dname
) + 1;
1692 /* default descr to string user enters */
1693 mp
[slot
].descr
= src
;
1698 * Implements macros from command mode. c is the buffer to
1699 * get the macro from.
1705 unsigned char macbuf
[BUFSIZE
];
1707 unsigned char *oglobp
;
1713 oinglobal
= inglobal
;
1714 pk
= peekc
; peekc
= 0;
1717 regbuf(c
, macbuf
, sizeof(macbuf
));
1718 a1
= addr1
; a2
= addr2
;
1719 for (ad
=a1
; ad
<=a2
; ad
++) {
1725 inglobal
= oinglobal
;
1735 static unsigned char pbuf
[9];
1737 /* In ex mode, let the system hassle with setting no echo */
1739 return (unsigned char *)getpass(prompt
);
1740 viprintf("%s", prompt
); flush();
1741 for (p
=pbuf
; (c
= getkey())!='\n' && c
!=EOF
&& c
!='\r';) {
1751 #define TSTACKSIZE 20
1755 } tagstack
[TSTACKSIZE
];
1756 static int tag_depth
= 0;
1758 static char tag_buf
[ 1024 ];
1759 static char *tag_end
= tag_buf
;
1762 savetag(char *name
) /* saves location where we are */
1764 if( !value(vi_TAGSTACK
) )
1766 if(tag_depth
>= TSTACKSIZE
) {
1767 error(gettext("Tagstack too deep."));
1769 if( strlen( name
) + 1 + tag_end
>= &tag_buf
[1024]) {
1770 error(gettext("Too many tags."));
1772 tagstack
[tag_depth
].tag_line
= dot
;
1773 tagstack
[tag_depth
++].tag_file
= tag_end
;
1774 while(*tag_end
++ = *name
++)
1784 if (!value(vi_TAGSTACK
))
1787 tag_end
= tagstack
[--tag_depth
].tag_file
;
1791 poptag(quick
) /* puts us back where we came from */
1794 unsigned char cmdbuf
[100];
1795 unsigned char *oglobp
;
1798 if (!value(vi_TAGSTACK
)) { /* reset the stack */
1803 error(gettext("Tagstack not enabled."));
1808 error(gettext("Tagstack empty."));
1810 /* change to old file */
1811 if (strcmp(tagstack
[tag_depth
-1].tag_file
, savedfile
) ) {
1814 if (chng
&& dol
> zero
)
1815 error(value(vi_TERSE
) ?
1816 gettext("No write") : gettext("No write since last change (:pop! overrides)"));
1819 strcpy(cmdbuf
, "e! ");
1820 strcat(cmdbuf
, tagstack
[tag_depth
-1].tag_file
);
1822 d
= peekc
; ungetchar(0);
1828 /* set line number */
1829 dot
= tagstack
[--tag_depth
].tag_line
;
1830 tag_end
= tagstack
[tag_depth
].tag_file
;