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