1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29
30 /* Copyright (c) 1981 Regents of the University of California */
31
32 #include "ex.h"
33 #include "ex_tty.h"
34 #include "ex_vis.h"
35
36 void fixundo(void);
37
38 /*
39 * This file defines the operation sequences which interface the
40 * logical changes to the file buffer with the internal and external
41 * display representations.
42 */
43
44 /*
45 * Undo.
46 *
47 * Undo is accomplished in two ways. We often for small changes in the
48 * current line know how (in terms of a change operator) how the change
49 * occurred. Thus on an intelligent terminal we can undo the operation
50 * by another such operation, using insert and delete character
51 * stuff. The pointers vU[AD][12] index the buffer vutmp when this
52 * is possible and provide the necessary information.
53 *
54 * The other case is that the change involved multiple lines or that
55 * we have moved away from the line or forgotten how the change was
56 * accomplished. In this case we do a redisplay and hope that the
57 * low level optimization routines (which don't look for winning
58 * via insert/delete character) will not lose too badly.
59 */
60 unsigned char *vUA1, *vUA2;
61 unsigned char *vUD1, *vUD2;
62
63 void
vUndo(void)64 vUndo(void)
65 {
66
67 /*
68 * Avoid UU which clobbers ability to do u.
69 */
70 if (vundkind == VNONE || vundkind == VCAPU || vUNDdot != dot) {
71 (void) beep();
72 return;
73 }
74 CP(vutmp, linebuf);
75 vUD1 = linebuf; vUD2 = strend(linebuf);
76 putmk1(dot, vUNDsav);
77 getDOT();
78 vUA1 = linebuf; vUA2 = strend(linebuf);
79 vundkind = VCAPU;
80 if (state == ONEOPEN || state == HARDOPEN) {
81 vjumpto(dot, vUNDcurs, 0);
82 return;
83 }
84 vdirty(vcline, 1);
85 if(MB_CUR_MAX > 1)
86 rewrite = _ON;
87 vsyncCL();
88 if(MB_CUR_MAX > 1)
89 rewrite = _OFF;
90 cursor = linebuf;
91 vfixcurs();
92 }
93
94 void
vundo(show)95 vundo(show)
96 bool show; /* if true update the screen */
97 {
98 int cnt;
99 line *addr;
100 unsigned char *cp;
101 unsigned char temp[LBSIZE];
102 bool savenote;
103 int (*OO)();
104 short oldhold = hold;
105 unsigned multic[MULTI_BYTE_MAX];
106 int length;
107 wchar_t wchar;
108
109 switch (vundkind) {
110
111 case VMANYINS:
112 wcursor = 0;
113 addr1 = undap1;
114 addr2 = undap2 - 1;
115 vsave();
116 (void) YANKreg('1');
117 notecnt = 0;
118 /* fall into ... */
119
120 case VMANY:
121 case VMCHNG:
122 vsave();
123 addr = dot - vcline;
124 notecnt = 1;
125 if (undkind == UNDPUT && undap1 == undap2) {
126 (void) beep();
127 break;
128 }
129 /*
130 * Undo() call below basically replaces undap1 to undap2-1
131 * with dol through unddol-1. Hack screen image to
132 * reflect this replacement.
133 */
134 if (show)
135 if (undkind == UNDMOVE)
136 vdirty(0, lines);
137 else
138 vreplace(undap1 - addr, undap2 - undap1,
139 undkind == UNDPUT ? 0 : unddol - dol);
140 savenote = notecnt;
141 undo(1);
142 if (show && (vundkind != VMCHNG || addr != dot))
143 killU();
144 vundkind = VMANY;
145 cnt = dot - addr;
146 if (cnt < 0 || cnt > vcnt || state != VISUAL) {
147 if (show)
148 vjumpto(dot, (unsigned char *)NOSTR, '.');
149 break;
150 }
151 if (!savenote)
152 notecnt = 0;
153 if (show) {
154 vcline = cnt;
155 if(MB_CUR_MAX > 1)
156 rewrite = _ON;
157 vrepaint(vmcurs);
158 if(MB_CUR_MAX > 1)
159 rewrite = _OFF;
160 }
161 vmcurs = 0;
162 break;
163
164 case VCHNG:
165 case VCAPU:
166 vundkind = VCHNG;
167 strcpy(temp, vutmp);
168 strcpy(vutmp, linebuf);
169 doomed = lcolumn(vUA2) - lcolumn(vUA1);
170 strcLIN(temp);
171 cp = vUA1; vUA1 = vUD1; vUD1 = cp;
172 cp = vUA2; vUA2 = vUD2; vUD2 = cp;
173 if (!show)
174 break;
175 cursor = vUD1;
176 if (state == HARDOPEN) {
177 doomed = 0;
178 vsave();
179 vopen(dot, WBOT);
180 vnline(cursor);
181 break;
182 }
183 /*
184 * Pseudo insert command.
185 */
186 vcursat(cursor);
187 OO = Outchar; Outchar = vinschar; hold |= HOLDQIK;
188 vprepins();
189 temp[vUA2 - linebuf] = 0;
190 for (cp = &temp[vUA1 - linebuf]; *cp;) {
191 length = mbtowc(&wchar, (char *)cp, MULTI_BYTE_MAX);
192 if(length < 0) {
193 putoctal = 1;
194 putchar(*cp++);
195 putoctal = 0;
196 } else {
197 putchar(wchar);
198 cp += length;
199 }
200 }
201 Outchar = OO; hold = oldhold;
202 endim();
203 physdc(cindent(), cindent() + doomed);
204 doomed = 0;
205 vdirty(vcline, 1);
206 if(MB_CUR_MAX > 1)
207 rewrite = _ON;
208 vsyncCL();
209 if(MB_CUR_MAX > 1)
210 rewrite = _OFF;
211 if (cursor > linebuf && cursor >= strend(linebuf))
212 cursor = lastchr(linebuf, cursor);
213 vfixcurs();
214 break;
215
216 case VNONE:
217 (void) beep();
218 break;
219 }
220 }
221
222 /*
223 * Routine to handle a change inside a macro.
224 * Fromvis is true if we were called from a visual command (as
225 * opposed to an ex command). This has nothing to do with being
226 * in open/visual mode as :s/foo/bar is not fromvis.
227 */
228 void
vmacchng(fromvis)229 vmacchng(fromvis)
230 bool fromvis;
231 {
232 line *savedot, *savedol;
233 unsigned char *savecursor;
234 unsigned char savelb[LBSIZE];
235 int nlines, more;
236 line *a1, *a2;
237 unsigned char ch; /* DEBUG */
238 int copyw(), copywR();
239
240 if (!inopen)
241 return;
242 if (!vmacp)
243 vch_mac = VC_NOTINMAC;
244 #ifdef UNDOTRACE
245 if (trace)
246 fprintf(trace, "vmacchng, vch_mac=%d, linebuf='%s', *dot=%o\n", vch_mac, linebuf, *dot);
247 #endif
248 if (vmacp && fromvis)
249 vsave();
250 #ifdef UNDOTRACE
251 if (trace)
252 fprintf(trace, "after vsave, linebuf='%s', *dot=%o\n", linebuf, *dot);
253 #endif
254 switch(vch_mac) {
255 case VC_NOCHANGE:
256 vch_mac = VC_ONECHANGE;
257 break;
258 case VC_ONECHANGE:
259 /* Save current state somewhere */
260 #ifdef UNDOTRACE
261 vudump("before vmacchng hairy case");
262 #endif
263 savedot = dot; savedol = dol; savecursor = cursor;
264 CP(savelb, linebuf);
265 nlines = dol - zero;
266 while ((line *) endcore - truedol < nlines)
267 if (morelines() < 0)
268 return; /* or could be fatal error */
269 copyw(truedol+1, zero+1, nlines);
270 truedol += nlines;
271
272 #ifdef UNDOTRACE
273 visdump("before vundo");
274 #endif
275 /* Restore state as it was at beginning of macro */
276 vundo(0);
277 #ifdef UNDOTRACE
278 visdump("after vundo");
279 vudump("after vundo");
280 #endif
281
282 /* Do the saveall we should have done then */
283 saveall();
284 #ifdef UNDOTRACE
285 vudump("after saveall");
286 #endif
287
288 /* Restore current state from where saved */
289 more = savedol - dol; /* amount we shift everything by */
290 if (more)
291 (*(more>0 ? copywR : copyw))(savedol+1, dol+1, truedol-dol);
292 unddol += more; truedol += more; undap2 += more;
293
294 truedol -= nlines;
295 copyw(zero+1, truedol+1, nlines);
296 dot = savedot; dol = savedol ; cursor = savecursor;
297 CP(linebuf, savelb);
298 vch_mac = VC_MANYCHANGE;
299
300 /* Arrange that no further undo saving happens within macro */
301 otchng = tchng; /* Copied this line blindly - bug? */
302 inopen = -1; /* no need to save since it had to be 1 or -1 before */
303 vundkind = VMANY;
304 #ifdef UNDOTRACE
305 vudump("after vmacchng");
306 #endif
307 break;
308 case VC_NOTINMAC:
309 case VC_MANYCHANGE:
310 /* Nothing to do for various reasons. */
311 break;
312 }
313 }
314
315 /*
316 * Initialize undo information before an append.
317 */
318 void
vnoapp(void)319 vnoapp(void)
320 {
321 vUD1 = vUD2 = cursor;
322 /*
323 * XPG6 assertion 273: Set vmcurs so that undo positions the
324 * cursor column correctly when we've moved off the initial
325 * line that was changed with the A, a, i, and R commands,
326 * eg: when G has moved us off the line, or when a
327 * multi-line change was done.
328 */
329 if (lastcmd[0] == 'A' || lastcmd[0] == 'a' || lastcmd[0] == 'i' ||
330 lastcmd[0] == 'R') {
331 vmcurs = cursor;
332 }
333 }
334
335 /*
336 * All the rest of the motion sequences have one or more
337 * cases to deal with. In the case wdot == 0, operation
338 * is totally within current line, from cursor to wcursor.
339 * If wdot is given, but wcursor is 0, then operation affects
340 * the inclusive line range. The hardest case is when both wdot
341 * and wcursor are given, then operation affects from line dot at
342 * cursor to line wdot at wcursor.
343 */
344
345 /*
346 * Move is simple, except for moving onto new lines in hardcopy open mode.
347 */
348 int
vmove(void)349 vmove(void)
350 {
351 int cnt;
352
353 if (wdot) {
354 if (wdot < one || wdot > dol) {
355 (void) beep();
356 return (0);
357 }
358 cnt = wdot - dot;
359 wdot = NOLINE;
360 if (cnt)
361 killU();
362 vupdown(cnt, wcursor);
363 return (0);
364 }
365
366 /*
367 * When we move onto a new line, save information for U undo.
368 */
369 if (vUNDdot != dot) {
370 vUNDsav = *dot;
371 vUNDcurs = wcursor;
372 vUNDdot = dot;
373 }
374
375 /*
376 * In hardcopy open, type characters to left of cursor
377 * on new line, or back cursor up if its to left of where we are.
378 * In any case if the current line is ``rubbled'' i.e. has trashy
379 * looking overstrikes on it or \'s from deletes, we reprint
380 * so it is more comprehensible (and also because we can't work
381 * if we let it get more out of sync since column() won't work right.
382 */
383 if (state == HARDOPEN) {
384 unsigned char *cp;
385 if (rubble) {
386 int c;
387 int oldhold = hold;
388
389 sethard();
390 cp = wcursor;
391 c = *cp;
392 *cp = 0;
393 hold |= HOLDDOL;
394 (void) vreopen(WTOP, lineDOT(), vcline);
395 hold = oldhold;
396 *cp = c;
397 } else if (wcursor > cursor) {
398 int length;
399 char multic[MULTI_BYTE_MAX];
400 wchar_t wchar;
401 vfixcurs();
402 for (cp = cursor; *cp && cp < wcursor;) {
403 length = mbtowc(&wchar, (char *)cp, MULTI_BYTE_MAX);
404 if(length == 0)
405 putchar(' ');
406 else if(length < 0) {
407 putoctal = 1;
408 putchar(*cp++);
409 putoctal = 0;
410 } else {
411 cp += length;
412 putchar(wchar);
413 }
414 }
415 }
416 }
417 vsetcurs(wcursor);
418 return (0);
419 }
420
421 /*
422 * Delete operator.
423 *
424 * Hard case of deleting a range where both wcursor and wdot
425 * are specified is treated as a special case of change and handled
426 * by vchange (although vchange may pass it back if it degenerates
427 * to a full line range delete.)
428 */
429 int
vdelete(unsigned char c)430 vdelete(unsigned char c)
431 {
432 unsigned char *cp;
433 int i;
434
435 if (wdot) {
436 if (wcursor) {
437 (void) vchange('d');
438 return (0);
439 }
440 if ((i = xdw()) < 0)
441 return (0);
442 if (state != VISUAL) {
443 vgoto(LINE(0), 0);
444 (void) vputchar('@');
445 }
446 wdot = dot;
447 vremote(i, delete, 0);
448 notenam = (unsigned char *)"delete";
449 DEL[0] = 0;
450 killU();
451 vreplace(vcline, i, 0);
452 if (wdot > dol)
453 vcline--;
454 vrepaint(NOSTR);
455 return (0);
456 }
457 if (wcursor < linebuf)
458 wcursor = linebuf;
459 if (cursor == wcursor) {
460 (void) beep();
461 return (0);
462 }
463 i = vdcMID();
464 cp = cursor;
465 setDEL();
466 CP(cp, wcursor);
467 if (cp > linebuf && (cp[0] == 0 || c == '#'))
468 cp = lastchr(linebuf, cp);
469 if (state == HARDOPEN) {
470 bleep(i, cp);
471 cursor = cp;
472 return (0);
473 }
474 physdc(lcolumn(cursor), i);
475 DEPTH(vcline) = 0;
476 if(MB_CUR_MAX > 1)
477 rewrite = _ON;
478 (void) vreopen(LINE(vcline), lineDOT(), vcline);
479 if(MB_CUR_MAX > 1)
480 rewrite = _OFF;
481 vsyncCL();
482 vsetcurs(cp);
483 return (0);
484 }
485
486 /*
487 * Change operator.
488 *
489 * In a single line we mark the end of the changed area with '$'.
490 * On multiple whole lines, we clear the lines first.
491 * Across lines with both wcursor and wdot given, we delete
492 * and sync then append (but one operation for undo).
493 */
494 int
vchange(unsigned char c)495 vchange(unsigned char c)
496 {
497 unsigned char *cp;
498 int i, ind, cnt;
499 line *addr;
500
501 if (wdot) {
502 /*
503 * Change/delete of lines or across line boundaries.
504 */
505 if ((cnt = xdw()) < 0)
506 return (0);
507 getDOT();
508 if (wcursor && cnt == 1) {
509 /*
510 * Not really.
511 */
512 wdot = 0;
513 if (c == 'd') {
514 (void) vdelete(c);
515 return (0);
516 }
517 goto smallchange;
518 }
519 if (cursor && wcursor) {
520 /*
521 * Across line boundaries, but not
522 * necessarily whole lines.
523 * Construct what will be left.
524 */
525 *cursor = 0;
526 strcpy(genbuf, linebuf);
527 getaline(*wdot);
528 if (strlen(genbuf) + strlen(wcursor) > LBSIZE - 2) {
529 getDOT();
530 (void) beep();
531 return (0);
532 }
533 strcat(genbuf, wcursor);
534 if (c == 'd' && *vpastwh(genbuf) == 0) {
535 /*
536 * Although this is a delete
537 * spanning line boundaries, what
538 * would be left is all white space,
539 * so take it all away.
540 */
541 wcursor = 0;
542 getDOT();
543 op = 0;
544 notpart(lastreg);
545 notpart('1');
546 (void) vdelete(c);
547 return (0);
548 }
549 ind = -1;
550 } else if (c == 'd' && wcursor == 0) {
551 (void) vdelete(c);
552 return (0);
553 } else
554 /*
555 * We are just substituting text for whole lines,
556 * so determine the first autoindent.
557 */
558 if (value(vi_LISP) && value(vi_AUTOINDENT))
559 ind = lindent(dot);
560 else
561 ind = whitecnt(linebuf);
562 i = vcline >= 0 ? LINE(vcline) : WTOP;
563
564 /*
565 * Delete the lines from the buffer,
566 * and remember how the partial stuff came about in
567 * case we are told to put.
568 */
569 addr = dot;
570 vremote(cnt, delete, 0);
571 setpk();
572 notenam = (unsigned char *)"delete";
573 if (c != 'd')
574 notenam = (unsigned char *)"change";
575 /*
576 * If DEL[0] were nonzero, put would put it back
577 * rather than the deleted lines.
578 */
579 DEL[0] = 0;
580 if (cnt > 1)
581 killU();
582
583 /*
584 * Now hack the screen image coordination.
585 */
586 vreplace(vcline, cnt, 0);
587 wdot = NOLINE;
588 noteit(0);
589 vcline--;
590 if (addr <= dol)
591 dot--;
592
593 /*
594 * If this is a across line delete/change,
595 * cursor stays where it is; just splice together the pieces
596 * of the new line. Otherwise generate a autoindent
597 * after a S command.
598 */
599 if (ind >= 0) {
600 /*
601 * XPG6 assertion 273: Set vmcurs so that cursor
602 * column will be set by undo.
603 */
604 fixundo();
605 *genindent(ind) = 0;
606 vdoappend(genbuf);
607 } else {
608 vmcurs = cursor;
609 strcLIN(genbuf);
610 vdoappend(linebuf);
611 }
612
613 /*
614 * Indicate a change on hardcopies by
615 * erasing the current line.
616 */
617 if (c != 'd' && state != VISUAL && state != HARDOPEN) {
618 int oldhold = hold;
619
620 hold |= HOLDAT, vclrlin(i, dot), hold = oldhold;
621 }
622
623 /*
624 * Open the line (logically) on the screen, and
625 * update the screen tail. Unless we are really a delete
626 * go off and gather up inserted characters.
627 */
628 vcline++;
629 if (vcline < 0)
630 vcline = 0;
631 vopen(dot, i);
632 vsyncCL();
633 noteit(1);
634 if (c != 'd') {
635 if (ind >= 0) {
636 cursor = linebuf;
637 /*
638 * XPG6 assertion 273: Set vmcurs so that
639 * cursor column will be set by undo. When
640 * undo is preceded by 'S' or 'O' command,
641 * white space isn't skipped in vnline(vmcurs).
642 */
643 fixundo();
644 linebuf[0] = 0;
645 vfixcurs();
646 } else {
647 ind = 0;
648 /*
649 * XPG6 assertion 273: Set vmcurs so that
650 * cursor column will be set by undo.
651 */
652 fixundo();
653 vcursat(cursor);
654 }
655 vappend('x', 1, ind);
656 return (0);
657 }
658 if (*cursor == 0 && cursor > linebuf)
659 cursor = lastchr(linebuf, cursor);
660 vrepaint(cursor);
661 return (0);
662 }
663
664 smallchange:
665 /*
666 * The rest of this is just low level hacking on changes
667 * of small numbers of characters.
668 */
669 if (wcursor < linebuf)
670 wcursor = linebuf;
671 if (cursor == wcursor) {
672 (void) beep();
673 return (0);
674 }
675 i = vdcMID();
676 cp = cursor;
677 if (state != HARDOPEN)
678 vfixcurs();
679
680 /*
681 * Put out the \\'s indicating changed text in hardcopy,
682 * or mark the end of the change with $ if not hardcopy.
683 */
684 if (state == HARDOPEN)
685 bleep(i, cp);
686 else {
687 vcursbef(wcursor);
688 putchar('$');
689 i = cindent();
690 }
691
692 /*
693 * Remember the deleted text for possible put,
694 * and then prepare and execute the input portion of the change.
695 */
696 cursor = cp;
697 setDEL();
698 CP(cursor, wcursor);
699 /*
700 * XPG6 assertion 273: Set vmcurs so that cursor column will be
701 * set by undo.
702 */
703 fixundo();
704 if (state != HARDOPEN) {
705 /* place cursor at beginning of changing text */
706 vgotoCL(lcolumn(cp));
707 doomed = i - cindent();
708 } else {
709 /*
710 sethard();
711 wcursor = cursor;
712 cursor = linebuf;
713 vgoto(outline, value(vi_NUMBER) << 3);
714 vmove();
715 */
716 doomed = 0;
717 }
718 prepapp();
719 vappend('c', 1, 0);
720 return (0);
721 }
722
723 /*
724 * Open new lines.
725 */
726 void
voOpen(int c,int cnt)727 voOpen(int c, int cnt)
728 {
729 int ind = 0, i;
730 short oldhold = hold;
731
732 vsave();
733 setLAST();
734 if (value(vi_AUTOINDENT))
735 ind = whitecnt(linebuf);
736 if (c == 'O') {
737 vcline--;
738 dot--;
739 if (dot > zero)
740 getDOT();
741 }
742 if (value(vi_AUTOINDENT)) {
743 if (value(vi_LISP))
744 ind = lindent(dot + 1);
745 }
746 killU();
747 prepapp();
748 if (FIXUNDO)
749 vundkind = VMANY;
750 if (state != VISUAL)
751 c = WBOT + 1;
752 else {
753 c = vcline < 0 ? WTOP - cnt : LINE(vcline) + DEPTH(vcline);
754 if (c < ZERO)
755 c = ZERO;
756 i = LINE(vcline + 1) - c;
757 if (i < cnt && c <= WBOT && (!insert_line || !delete_line))
758 vinslin(c, cnt - i, vcline);
759 }
760 *genindent(ind) = 0;
761 vdoappend(genbuf);
762 vcline++;
763 oldhold = hold;
764 hold |= HOLDROL;
765 vopen(dot, c);
766 hold = oldhold;
767 if (value(vi_SLOWOPEN))
768 /*
769 * Oh, so lazy!
770 */
771 vscrap();
772 else
773 vsync1(LINE(vcline));
774 cursor = linebuf;
775 /*
776 * XPG6 assertion 273: Set vmcurs so that cursor column will be
777 * set by undo. For undo preceded by 'o' command, white space
778 * isn't skipped in vnline(vmcurs).
779 */
780 fixundo();
781 linebuf[0] = 0;
782 vappend('o', cnt, ind);
783 }
784
785 /*
786 * > < and = shift operators.
787 *
788 * Note that =, which aligns lisp, is just a ragged sort of shift,
789 * since it never distributes text between lines.
790 */
791 unsigned char vshnam[2] = { 'x', 0 };
792
793 int
vshftop(void)794 vshftop(void)
795 {
796 line *addr;
797 int cnt;
798
799 if ((cnt = xdw()) < 0)
800 return (0);
801 addr = dot;
802 vremote(cnt, vshift, 0);
803 vshnam[0] = op;
804 notenam = vshnam;
805 dot = addr;
806 vreplace(vcline, cnt, cnt);
807 if (state == HARDOPEN)
808 vcnt = 0;
809 vrepaint(NOSTR);
810 return (0);
811 }
812
813 /*
814 * !.
815 *
816 * Filter portions of the buffer through unix commands.
817 */
818 int
vfilter(void)819 vfilter(void)
820 {
821 line *addr;
822 int cnt;
823 unsigned char *oglobp;
824 short d;
825
826 if ((cnt = xdw()) < 0)
827 return (0);
828 if (vglobp)
829 vglobp = (unsigned char *)uxb;
830 if (readecho('!'))
831 return (0);
832 oglobp = globp; globp = genbuf + 1;
833 d = peekc; ungetchar(0);
834 CATCH
835 fixech();
836 unix0(0, 0);
837 ONERR
838 splitw = 0;
839 ungetchar(d);
840 vrepaint(cursor);
841 globp = oglobp;
842 return (0);
843 ENDCATCH
844 ungetchar(d); globp = oglobp;
845 addr = dot;
846 CATCH
847 vgoto(WECHO, 0); flusho();
848 vremote(cnt, vi_filter, 2);
849 ONERR
850 vdirty(0, lines);
851 ENDCATCH
852 if (dot == zero && dol > zero)
853 dot = one;
854 splitw = 0;
855 notenam = (unsigned char *)"";
856 /*
857 * BUG: we shouldn't be depending on what undap2 and undap1 are,
858 * since we may be inside a macro. What's really wanted is the
859 * number of lines we read from the filter. However, the mistake
860 * will be an overestimate so it only results in extra work,
861 * it shouldn't cause any real mess-ups.
862 */
863 vreplace(vcline, cnt, undap2 - undap1);
864 dot = addr;
865 if (dot > dol) {
866 dot--;
867 vcline--;
868 }
869 vrepaint(NOSTR);
870 return (0);
871 }
872
873 /*
874 * Xdw exchanges dot and wdot if appropriate and also checks
875 * that wdot is reasonable. Its name comes from
876 * xchange dotand wdot
877 */
878 int
xdw(void)879 xdw(void)
880 {
881 unsigned char *cp;
882 int cnt;
883 /*
884 register int notp = 0;
885 */
886
887 if (wdot == NOLINE || wdot < one || wdot > dol) {
888 (void) beep();
889 return (-1);
890 }
891 vsave();
892 setLAST();
893 if (dot > wdot || (dot == wdot && wcursor != 0 && cursor > wcursor)) {
894 line *addr;
895
896 vcline -= dot - wdot;
897 addr = dot; dot = wdot; wdot = addr;
898 cp = cursor; cursor = wcursor; wcursor = cp;
899 }
900 /*
901 * If a region is specified but wcursor is at the beginning
902 * of the last line, then we move it to be the end of the
903 * previous line (actually off the end).
904 */
905 if (cursor && wcursor == linebuf && wdot > dot) {
906 wdot--;
907 getDOT();
908 if (vpastwh(linebuf) >= cursor)
909 wcursor = 0;
910 else {
911 getaline(*wdot);
912 wcursor = strend(linebuf);
913 getDOT();
914 }
915 /*
916 * Should prepare in caller for possible dot == wdot.
917 */
918 }
919 cnt = wdot - dot + 1;
920 if (vreg) {
921 vremote(cnt, YANKreg, vreg);
922 /*
923 if (notp)
924 notpart(vreg);
925 */
926 }
927
928 /*
929 * Kill buffer code. If delete operator is c or d, then save
930 * the region in numbered buffers.
931 *
932 * BUG: This may be somewhat inefficient due
933 * to the way named buffer are implemented,
934 * necessitating some optimization.
935 */
936 vreg = 0;
937 /* XPG6 assertion 194 and 264: use numeric buffers for 'C' and 'S' */
938 if (any(op, (unsigned char *)"cdCS")) {
939 vremote(cnt, YANKreg, '1');
940 /*
941 if (notp)
942 notpart('1');
943 */
944 }
945 return (cnt);
946 }
947
948 /*
949 * Routine for vremote to call to implement shifts.
950 */
951 int
vshift(void)952 vshift(void)
953 {
954
955 shift(op, 1);
956 return (0);
957 }
958
959 /*
960 * Replace a single character with the next input character.
961 * A funny kind of insert.
962 */
963 void
vrep(int cnt)964 vrep(int cnt)
965 {
966 int i, c;
967 unsigned char *endcurs;
968 endcurs = cursor;
969 /* point endcurs to last char entered */
970 for(i = 1; i <= cnt; i++) {
971 if(!*endcurs) {
972 (void) beep();
973 return;
974 }
975 endcurs = nextchr(endcurs);
976 }
977 i = lcolumn(endcurs);
978 vcursat(cursor);
979 doomed = i - cindent();
980 /*
981 * TRANSLATION_NOTE
982 * "r" is a terse mode message that corresponds to
983 * "REPLACE 1 CHAR".
984 * Translated message of "r" must be 1 character (not byte).
985 * Or, just leave it.
986 */
987 if(value(vi_TERSE))
988 vshowmode(gettext("r"));
989 else
990 vshowmode(gettext("REPLACE 1 CHAR"));
991 if (!vglobp) {
992 /* get a key using getkey() */
993 c = getesc();
994 if (c == 0) {
995 vshowmode("");
996 vfixcurs();
997 return;
998 }
999 ungetkey(c);
1000 }
1001 CP(vutmp, linebuf);
1002 if (FIXUNDO)
1003 vundkind = VCHNG;
1004 wcursor = endcurs;
1005 vUD1 = cursor; vUD2 = wcursor;
1006 CP(cursor, wcursor);
1007 /* before appending lines, set addr1 and undo information */
1008 prepapp();
1009 vappend('r', cnt, 0);
1010 *lastcp++ = INS[0];
1011 setLAST();
1012 }
1013
1014 /*
1015 * Yank.
1016 *
1017 * Yanking to string registers occurs for free (essentially)
1018 * in the routine xdw().
1019 */
1020 int
vyankit(void)1021 vyankit(void)
1022 {
1023 int cnt;
1024
1025 if (wdot) {
1026 if ((cnt = xdw()) < 0)
1027 return (0);
1028 vremote(cnt, yank, 0);
1029 setpk();
1030 notenam = (unsigned char *)"yank";
1031 if (FIXUNDO)
1032 vundkind = VNONE;
1033 DEL[0] = 0;
1034 wdot = NOLINE;
1035 if (notecnt <= vcnt - vcline && notecnt < value(vi_REPORT))
1036 notecnt = 0;
1037 vrepaint(cursor);
1038 return (0);
1039 } else {
1040 /*
1041 * For one line y<motion> commands, eg. 2yw, save the
1042 * command for a subsequent [count].
1043 */
1044 setLAST();
1045 }
1046 takeout(DEL);
1047 return (0);
1048
1049 }
1050
1051 /*
1052 * Set pkill variables so a put can
1053 * know how to put back partial text.
1054 * This is necessary because undo needs the complete
1055 * line images to be saved, while a put wants to trim
1056 * the first and last lines. The compromise
1057 * is for put to be more clever.
1058 */
1059 void
setpk(void)1060 setpk(void)
1061 {
1062
1063 if (wcursor) {
1064 pkill[0] = cursor;
1065 pkill[1] = wcursor;
1066 }
1067 }
1068
1069 /*
1070 * XPG6 assertion 273 : If the command is C, c, o, R, S, or s, set vmcurs
1071 * so that the cursor column will be set by undo.
1072 */
1073 void
fixundo(void)1074 fixundo(void)
1075 {
1076 if (lastcmd[0] == 'C' || lastcmd[0] == 'c' || lastcmd[0] == 'o' ||
1077 lastcmd[0] == 'R' || lastcmd[0] == 'S' || lastcmd[0] == 's') {
1078 vmcurs = cursor;
1079 }
1080 }
1081