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 /*
31 * Copyright (c) 1981 Regents of the University of California
32 */
33
34 #include "ex.h"
35 #include "ex_tty.h"
36 #include "ex_vis.h"
37 #include <regexpr.h>
38 #ifndef PRESUNEUC
39 #include <wctype.h>
40 /* Undef putchar/getchar if they're defined. */
41 #ifdef putchar
42 #undef putchar
43 #endif
44 #ifdef getchar
45 #undef getchar
46 #endif
47 #endif /* PRESUNEUC */
48
49 #ifdef PRESUNEUC
50 #define blank() isspace(wcursor[0])
51 #endif /* PRESUNEUC */
52 #define forbid(a) if (a) goto errlab;
53
54 unsigned char vscandir[2] = { '/', 0 };
55
56 static int get_addr();
57
58 /*
59 * Decode an operator/operand type command.
60 * Eventually we switch to an operator subroutine in ex_vops.c.
61 * The work here is setting up a function variable to point
62 * to the routine we want, and manipulation of the variables
63 * wcursor and wdot, which mark the other end of the affected
64 * area. If wdot is zero, then the current line is the other end,
65 * and if wcursor is zero, then the first non-blank location of the
66 * other line is implied.
67 */
68 void
operate(int c,int cnt)69 operate(int c, int cnt)
70 {
71 wchar_t i;
72 int (*moveop)(), (*deleteop)();
73 int (*opf)();
74 bool subop = 0;
75 unsigned char *oglobp, *ocurs;
76 line *addr;
77 line *odot;
78 int oc;
79 static unsigned char lastFKND;
80 static wchar_t lastFCHR;
81 short d;
82 /* #ifdef PTR_ADDRESSES */
83 int mouse_x;
84 int mouse_y;
85 int oline;
86 /* #endif PTR_ADDRESSES */
87
88 moveop = vmove, deleteop = (int (*)())vdelete;
89 wcursor = cursor;
90 wdot = NOLINE;
91 notecnt = 0;
92 dir = 1;
93 switch (c) {
94
95 /*
96 * d delete operator.
97 */
98 case 'd':
99 moveop = (int (*)())vdelete;
100 deleteop = beep;
101 break;
102
103 /*
104 * s substitute characters, like c\040, i.e. change space.
105 */
106 case 's':
107 ungetkey(' ');
108 subop++;
109 /* fall into ... */
110
111 /*
112 * c Change operator.
113 */
114 case 'c':
115 if (c == 'c' && workcmd[0] == 'C' || workcmd[0] == 'S')
116 subop++;
117 moveop = (int (*)())vchange;
118 deleteop = beep;
119 break;
120
121 /*
122 * ! Filter through a UNIX command.
123 */
124 case '!':
125 moveop = vfilter;
126 deleteop = beep;
127 break;
128
129 /*
130 * y Yank operator. Place specified text so that it
131 * can be put back with p/P. Also yanks to named buffers.
132 */
133 case 'y':
134 moveop = vyankit;
135 deleteop = beep;
136 break;
137
138 /*
139 * = Reformat operator (for LISP).
140 */
141 case '=':
142 forbid(!value(vi_LISP));
143 /* fall into ... */
144
145 /*
146 * > Right shift operator.
147 * < Left shift operator.
148 */
149 case '<':
150 case '>':
151 moveop = vshftop;
152 deleteop = beep;
153 break;
154
155 /*
156 * r Replace character under cursor with single following
157 * character.
158 */
159 case 'r':
160 vmacchng(1);
161 vrep(cnt);
162 return;
163
164 default:
165 goto nocount;
166 }
167 vmacchng(1);
168 /*
169 * Had an operator, so accept another count.
170 * Multiply counts together.
171 */
172 if (isdigit(peekkey()) && peekkey() != '0') {
173 cnt *= vgetcnt();
174 Xcnt = cnt;
175 forbid(cnt <= 0);
176 }
177
178 /*
179 * Get next character, mapping it and saving as
180 * part of command for repeat.
181 */
182 c = map(getesc(), arrows, 0);
183 if (c == 0)
184 return;
185 if (!subop)
186 *lastcp++ = c;
187 nocount:
188 opf = moveop;
189 switch (c) {
190
191 /* #ifdef PTR_ADDRESSES */
192 /*
193 * ^X^_ Netty Mouse positioning hack
194 * ^X^]
195 */
196 case CTRL('X'):
197 /*
198 * Read in mouse stuff
199 */
200 c = getkey(); /* ^_ or ^] */
201 if ((c != CTRL('_')) && (c != (CTRL(']'))))
202 break;
203 getkey(); /* mouse button */
204 mouse_x = get_addr() + 1;
205 mouse_y = get_addr() + 1;
206 if (mouse_y < WTOP)
207 break;
208 if (Pline == numbline)
209 mouse_x -= 8;
210 if (mouse_x < 0)
211 mouse_x = 0;
212 if (mouse_x > WCOLS)
213 break;
214 /*
215 * Find the line on the screen
216 */
217 for (i = 0; i <= WECHO; i++) {
218 if (vlinfo[i].vliny >= mouse_y)
219 break;
220 }
221 if (i > WECHO)
222 break;
223 /*
224 * Look for lines longer than one line - note odd case at zero
225 */
226 if (i) {
227 if (vlinfo[i - 1].vdepth > 1) {
228 mouse_x += WCOLS * (mouse_y -
229 (vlinfo[i].vliny -
230 (vlinfo[i - 1].vdepth - 1)));
231 }
232 }
233 else
234 {
235 mouse_x += WCOLS * (mouse_y - 1);
236 }
237 /*
238 * Set the line
239 */
240 vsave();
241 ocurs = cursor;
242 odot = dot;
243 oline = vcline;
244 operate('H', i);
245 /*
246 * Set the column
247 */
248 getDOT();
249 if (Pline == numbline)
250 mouse_x += 8;
251 vmovcol = mouse_x;
252 vmoving = 1;
253 wcursor = vfindcol(mouse_x);
254 /*
255 * Reset everything so that stuff like delete and change work
256 */
257 wdot = (odot - oline) + i - 1;
258 cursor = ocurs;
259 vcline = oline;
260 dot = odot;
261 getDOT();
262 break;
263 /* #endif PTR_ADDRESSES */
264
265 /*
266 * b Back up a word.
267 * B Back up a word, liberal definition.
268 */
269 case 'b':
270 case 'B':
271 dir = -1;
272 /* fall into ... */
273
274 /*
275 * w Forward a word.
276 * W Forward a word, liberal definition.
277 */
278 case 'W':
279 case 'w':
280 wdkind = c & ' ';
281 forbid(lfind(2, cnt, opf, (line *)0) < 0);
282 vmoving = 0;
283 break;
284
285 /*
286 * E to end of following blank/nonblank word
287 */
288 case 'E':
289 wdkind = 0;
290 goto ein;
291
292 /*
293 * e To end of following word.
294 */
295 case 'e':
296 wdkind = 1;
297 ein:
298 forbid(lfind(3, cnt - 1, opf, (line *)0) < 0);
299 vmoving = 0;
300 break;
301
302 /*
303 * ( Back an s-expression.
304 */
305 case '(':
306 dir = -1;
307 /* fall into... */
308
309 /*
310 * ) Forward an s-expression.
311 */
312 case ')':
313 forbid(lfind(0, cnt, opf, (line *) 0) < 0);
314 markDOT();
315 break;
316
317 /*
318 * { Back an s-expression, but don't stop on atoms.
319 * In text mode, a paragraph. For C, a balanced set
320 * of {}'s.
321 */
322 case '{':
323 dir = -1;
324 /* fall into... */
325
326 /*
327 * } Forward an s-expression, but don't stop on atoms.
328 * In text mode, back paragraph. For C, back a balanced
329 * set of {}'s.
330 */
331 case '}':
332 forbid(lfind(1, cnt, opf, (line *) 0) < 0);
333 markDOT();
334 break;
335
336 /*
337 * % To matching () or {}. If not at ( or { scan for
338 * first such after cursor on this line.
339 */
340 case '%':
341 vsave();
342 ocurs = cursor;
343 odot = wdot = dot;
344 oglobp = globp;
345 CATCH
346 i = lmatchp((line *) 0);
347 ONERR
348 globp = oglobp;
349 dot = wdot = odot;
350 cursor = ocurs;
351 splitw = 0;
352 vclean();
353 vjumpto(dot, ocurs, 0);
354 return;
355 ENDCATCH
356 #ifdef TRACE
357 if (trace)
358 fprintf(trace, "after lmatchp in %, dot=%d, wdot=%d, "
359 "dol=%d\n", lineno(dot), lineno(wdot), lineno(dol));
360 #endif
361 getDOT();
362 forbid(!i);
363 if (opf != vmove)
364 if (dir > 0)
365 wcursor++;
366 else
367 cursor++;
368 else
369 markDOT();
370 vmoving = 0;
371 break;
372
373 /*
374 * [ Back to beginning of defun, i.e. an ( in column 1.
375 * For text, back to a section macro.
376 * For C, back to a { in column 1 (~~ beg of function.)
377 */
378 case '[':
379 dir = -1;
380 /* fall into ... */
381
382 /*
383 * ] Forward to next defun, i.e. a ( in column 1.
384 * For text, forward section.
385 * For C, forward to a } in column 1 (if delete or such)
386 * or if a move to a { in column 1.
387 */
388 case ']':
389 if (!vglobp)
390 forbid(getkey() != c);
391 #ifndef XPG4
392 forbid(Xhadcnt);
393 #endif
394 vsave();
395 #ifdef XPG4
396 if (cnt > 1) {
397 while (cnt-- > 1) {
398 i = lbrack(c, opf);
399 getDOT();
400 forbid(!i);
401 markDOT();
402 if (ospeed > B300)
403 hold |= HOLDWIG;
404 (*opf)(c);
405 }
406 }
407 #endif /* XPG4 */
408 i = lbrack(c, opf);
409 getDOT();
410 forbid(!i);
411 markDOT();
412 if (ospeed > B300)
413 hold |= HOLDWIG;
414 break;
415
416 /*
417 * , Invert last find with f F t or T, like inverse
418 * of ;.
419 */
420 case ',':
421 forbid(lastFKND == 0);
422 c = isupper(lastFKND) ? tolower(lastFKND) : toupper(lastFKND);
423 i = lastFCHR;
424 if (vglobp == 0)
425 vglobp = (unsigned char *)"";
426 subop++;
427 goto nocount;
428
429 /*
430 * 0 To beginning of real line.
431 */
432 case '0':
433 wcursor = linebuf;
434 vmoving = 0;
435 break;
436
437 /*
438 * ; Repeat last find with f F t or T.
439 */
440 case ';':
441 forbid(lastFKND == 0);
442 c = lastFKND;
443 i = lastFCHR;
444 subop++;
445 goto nocount;
446
447 /*
448 * F Find single character before cursor in current line.
449 * T Like F, but stops before character.
450 */
451 case 'F': /* inverted find */
452 case 'T':
453 dir = -1;
454 /* fall into ... */
455
456 /*
457 * f Find single character following cursor in current line.
458 * t Like f, but stope before character.
459 */
460 case 'f': /* find */
461 case 't':
462 if (!subop) {
463 int length;
464 wchar_t wchar;
465 length = _mbftowc(lastcp, &wchar, getesc, &Peekkey);
466 if (length <= 0 || wchar == 0) {
467 (void) beep();
468 return;
469 }
470 i = wchar;
471 lastcp += length;
472 }
473 if (vglobp == 0)
474 lastFKND = c, lastFCHR = i;
475 for (; cnt > 0; cnt--)
476 forbid(find(i) == 0);
477 vmoving = 0;
478 switch (c) {
479
480 case 'T':
481 wcursor = nextchr(wcursor);
482 break;
483
484 case 't':
485 wcursor = lastchr(linebuf, wcursor);
486 case 'f':
487 fixup:
488 if (moveop != vmove)
489 wcursor = nextchr(wcursor);
490 break;
491 }
492 break;
493
494 /*
495 * | Find specified print column in current line.
496 */
497 case '|':
498 if (Pline == numbline)
499 cnt += 8;
500 vmovcol = cnt;
501 vmoving = 1;
502 wcursor = vfindcol(cnt);
503 break;
504
505 /*
506 * ^ To beginning of non-white space on line.
507 */
508 case '^':
509 wcursor = vskipwh(linebuf);
510 vmoving = 0;
511 break;
512
513 /*
514 * $ To end of line.
515 */
516 case '$':
517 if (opf == vmove) {
518 vmoving = 1;
519 vmovcol = 20000;
520 } else
521 vmoving = 0;
522 if (cnt > 1) {
523 if (opf == vmove) {
524 wcursor = 0;
525 cnt--;
526 } else
527 wcursor = linebuf;
528 /* This is wrong at EOF */
529 wdot = dot + cnt;
530 break;
531 }
532 if (linebuf[0]) {
533 wcursor = strend(linebuf);
534 wcursor = lastchr(linebuf, wcursor);
535 goto fixup;
536 }
537 wcursor = linebuf;
538 break;
539
540 /*
541 * h Back a character.
542 * ^H Back a character.
543 */
544 case 'h':
545 case CTRL('h'):
546 dir = -1;
547 /* fall into ... */
548
549 /*
550 * space Forward a character.
551 */
552 case 'l':
553 case ' ':
554 forbid(margin() || opf == vmove && edge());
555 while (cnt > 0 && !margin()) {
556 if (dir == 1)
557 wcursor = nextchr(wcursor);
558 else
559 wcursor = lastchr(linebuf, wcursor);
560 cnt--;
561 }
562 if (margin() && opf == vmove || wcursor < linebuf) {
563 if (dir == 1)
564 wcursor = lastchr(linebuf, wcursor);
565 else
566 wcursor = linebuf;
567 }
568 vmoving = 0;
569 break;
570
571 /*
572 * D Delete to end of line, short for d$.
573 */
574 case 'D':
575 cnt = INF;
576 goto deleteit;
577
578 /*
579 * X Delete character before cursor.
580 */
581 case 'X':
582 dir = -1;
583 /* fall into ... */
584 deleteit:
585 /*
586 * x Delete character at cursor, leaving cursor where it is.
587 */
588 case 'x':
589 if (margin())
590 goto errlab;
591 vmacchng(1);
592 while (cnt > 0 && !margin()) {
593 if (dir == 1)
594 wcursor = nextchr(wcursor);
595 else
596 wcursor = lastchr(linebuf, wcursor);
597 cnt--;
598 }
599 opf = deleteop;
600 vmoving = 0;
601 break;
602
603 default:
604 /*
605 * Stuttered operators are equivalent to the operator on
606 * a line, thus turn dd into d_.
607 */
608 if (opf == vmove || c != workcmd[0]) {
609 errlab:
610 (void) beep();
611 vmacp = 0;
612 return;
613 }
614 /* fall into ... */
615
616 /*
617 * _ Target for a line or group of lines.
618 * Stuttering is more convenient; this is mostly
619 * for aesthetics.
620 */
621 case '_':
622 wdot = dot + cnt - 1;
623 vmoving = 0;
624 wcursor = 0;
625 break;
626
627 /*
628 * H To first, home line on screen.
629 * Count is for count'th line rather than first.
630 */
631 case 'H':
632 wdot = (dot - vcline) + cnt - 1;
633 if (opf == vmove)
634 markit(wdot);
635 vmoving = 0;
636 wcursor = 0;
637 break;
638
639 /*
640 * - Backwards lines, to first non-white character.
641 */
642 case '-':
643 wdot = dot - cnt;
644 vmoving = 0;
645 wcursor = 0;
646 break;
647
648 /*
649 * ^P To previous line same column. Ridiculous on the
650 * console of the VAX since it puts console in LSI mode.
651 */
652 case 'k':
653 case CTRL('p'):
654 wdot = dot - cnt;
655 if (vmoving == 0)
656 vmoving = 1, vmovcol = column(cursor);
657 wcursor = 0;
658 break;
659
660 /*
661 * L To last line on screen, or count'th line from the
662 * bottom.
663 */
664 case 'L':
665 wdot = dot + vcnt - vcline - cnt;
666 if (opf == vmove)
667 markit(wdot);
668 vmoving = 0;
669 wcursor = 0;
670 break;
671
672 /*
673 * M To the middle of the screen.
674 */
675 case 'M':
676 wdot = dot + ((vcnt + 1) / 2) - vcline - 1;
677 if (opf == vmove)
678 markit(wdot);
679 vmoving = 0;
680 wcursor = 0;
681 break;
682
683 /*
684 * + Forward line, to first non-white.
685 *
686 * CR Convenient synonym for +.
687 */
688 case '+':
689 case CR:
690 wdot = dot + cnt;
691 vmoving = 0;
692 wcursor = 0;
693 break;
694
695 /*
696 * ^N To next line, same column if possible.
697 *
698 * LF Linefeed is a convenient synonym for ^N.
699 */
700 case CTRL('n'):
701 case 'j':
702 case NL:
703 wdot = dot + cnt;
704 if (vmoving == 0)
705 vmoving = 1, vmovcol = column(cursor);
706 wcursor = 0;
707 break;
708
709 /*
710 * n Search to next match of current pattern.
711 */
712 case 'n':
713 vglobp = vscandir;
714 c = *vglobp++;
715 goto nocount;
716
717 /*
718 * N Like n but in reverse direction.
719 */
720 case 'N':
721 vglobp = vscandir[0] == '/' ? (unsigned char *)"?" :
722 (unsigned char *)"/";
723 c = *vglobp++;
724 goto nocount;
725
726 /*
727 * ' Return to line specified by following mark,
728 * first white position on line.
729 *
730 * ` Return to marked line at remembered column.
731 */
732 case '\'':
733 case '`':
734 d = c;
735 c = getesc();
736 if (c == 0)
737 return;
738 c = markreg(c);
739 forbid(c == 0);
740 wdot = getmark(c);
741 forbid(wdot == NOLINE);
742 forbid(Xhadcnt);
743 vmoving = 0;
744 wcursor = d == '`' ? ncols[c - 'a'] : 0;
745 if (opf == vmove && (wdot != dot ||
746 (d == '`' && wcursor != cursor)))
747 markDOT();
748 if (wcursor) {
749 vsave();
750 getaline(*wdot);
751 if (wcursor > strend(linebuf))
752 wcursor = 0;
753 else {
754 cnt = wcursor - linebuf;
755 /*CSTYLED*/
756 for (wcursor = linebuf; wcursor - linebuf < cnt; )
757 wcursor = nextchr(wcursor);
758 if (wcursor - linebuf > cnt)
759 wcursor = lastchr(linebuf, wcursor);
760 }
761 getDOT();
762 }
763 if (ospeed > B300)
764 hold |= HOLDWIG;
765 break;
766
767 /*
768 * G Goto count'th line, or last line if no count
769 * given.
770 */
771 case 'G':
772 if (!Xhadcnt)
773 cnt = lineDOL();
774 wdot = zero + cnt;
775 forbid(wdot < one || wdot > dol);
776 if (opf == vmove)
777 markit(wdot);
778 vmoving = 0;
779 wcursor = 0;
780 break;
781
782 /*
783 * / Scan forward for following re.
784 * ? Scan backward for following re.
785 */
786 case '/':
787 case '?':
788 forbid(Xhadcnt);
789 vsave();
790 oc = c;
791 ocurs = cursor;
792 odot = dot;
793 wcursor = 0;
794 if (readecho(c))
795 return;
796 if (!vglobp)
797 vscandir[0] = genbuf[0];
798 oglobp = globp; CP(vutmp, genbuf); globp = vutmp;
799 d = peekc;
800 fromsemi:
801 ungetchar(0);
802 fixech();
803 CATCH
804 #ifndef CBREAK
805 /*
806 * Lose typeahead (ick).
807 */
808 vcook();
809 #endif
810 addr = address(cursor);
811 #ifndef CBREAK
812 vraw();
813 #endif
814 ONERR
815 #ifndef CBREAK
816 vraw();
817 #endif
818 slerr:
819 globp = oglobp;
820 dot = odot;
821 cursor = ocurs;
822 ungetchar(d);
823 splitw = 0;
824 vclean();
825 vjumpto(dot, ocurs, 0);
826 return;
827 ENDCATCH
828 if (globp == 0)
829 globp = (unsigned char *)"";
830 else if (peekc)
831 --globp;
832 if (*globp == ';') {
833 /* /foo/;/bar/ */
834 globp++;
835 dot = addr;
836 cursor = (unsigned char *)loc1;
837 goto fromsemi;
838 }
839 dot = odot;
840 ungetchar(d);
841 c = 0;
842 if (*globp == 'z')
843 globp++, c = '\n';
844 if (any(*globp, "^+-."))
845 c = *globp++;
846 i = 0;
847 while (isdigit(*globp))
848 i = i * 10 + *globp++ - '0';
849 if (any(*globp, "^+-."))
850 c = *globp++;
851 if (*globp) {
852 /* random junk after the pattern */
853 (void) beep();
854 goto slerr;
855 }
856 globp = oglobp;
857 splitw = 0;
858 vmoving = 0;
859 wcursor = (unsigned char *)loc1;
860 if (i != 0)
861 vsetsiz(i);
862 if (opf == vmove) {
863 if (state == ONEOPEN || state == HARDOPEN)
864 outline = destline = WBOT;
865 if (addr != dot || (unsigned char *)loc1 != cursor)
866 markDOT();
867 if (loc1 > (char *)linebuf && *loc1 == 0)
868 loc1 = (char *)lastchr(linebuf, loc1);
869 if (c)
870 vjumpto(addr, (unsigned char *)loc1, c);
871 else {
872 vmoving = 0;
873 if (loc1) {
874 vmoving++;
875 vmovcol = column(loc1);
876 }
877 getDOT();
878 if (state == CRTOPEN && addr != dot)
879 vup1();
880 vupdown(addr - dot, NOSTR);
881 }
882 if (oc == '/') { /* forward search */
883 if (dot < odot ||
884 (dot == odot && cursor <= ocurs))
885 warnf(value(vi_TERSE) ?
886 gettext("Search wrapped BOTTOM") :
887 gettext("Search wrapped around BOTTOM of buffer"));
888 } else { /* backward search */
889 if (dot > odot ||
890 (dot == odot && cursor >= ocurs))
891 warnf(value(vi_TERSE) ?
892 gettext("Search wrapped TOP") :
893 gettext("Search wrapped around TOP of buffer"));
894 }
895 return;
896 }
897 lastcp[-1] = 'n';
898 getDOT();
899 wdot = addr;
900 break;
901 }
902 /*
903 * Apply.
904 */
905 if (vreg && wdot == 0)
906 wdot = dot;
907 (*opf)(c);
908 wdot = NOLINE;
909 }
910
911 static void
lfixol()912 lfixol()
913 {
914 unsigned char *savevglobp;
915 int savesplit;
916
917 if (Outchar == vputchar)
918 return;
919
920 /* Show messages */
921 putnl();
922 if (inopen > 0 && clr_eol)
923 vclreol();
924 if (enter_standout_mode && exit_bold)
925 putpad((unsigned char *)enter_standout_mode);
926 lprintf(gettext("[Hit return to continue] "), 0);
927 if (enter_standout_mode && exit_bold)
928 putpad((unsigned char *)exit_bold);
929
930 /* Get key input for confirmation */
931 savevglobp = vglobp;
932 vglobp = 0; /* force typed input */
933 getkey();
934 vglobp = savevglobp;
935
936 /* reset output function */
937 Outchar = vputchar;
938
939 /* Clean up screen */
940 savesplit = splitw;
941 splitw = 0;
942 vclear();
943 vdirty(0, WLINES);
944 vredraw(WTOP);
945 splitw = savesplit;
946 }
947
948 void
warnf(char * str,char * cp)949 warnf(char *str, char *cp)
950 {
951 int saveline, savecol, savesplit;
952
953 saveline = outline;
954 savecol = outcol;
955 savesplit = splitw;
956 splitw = 1;
957 vgoto(WECHO, 0);
958 if (!enter_standout_mode || !exit_bold)
959 dingdong();
960 if (clr_eol)
961 vclreol();
962 if (enter_standout_mode && exit_bold)
963 putpad((unsigned char *)enter_standout_mode);
964 lprintf(str, cp);
965 if (enter_standout_mode && exit_bold)
966 putpad((unsigned char *)exit_bold);
967 lfixol();
968 vgoto(saveline, savecol);
969 splitw = savesplit;
970 }
971
972 /* #ifdef PTR_ADDRESSES */
973 /*
974 * read in a row or column address
975 *
976 */
977 static int
get_addr()978 get_addr()
979 {
980 short c;
981 short next;
982
983 c = getkey();
984 next = 0;
985 switch (c) {
986 case CTRL('A'):
987 next = 96;
988 c = getkey();
989 break;
990
991 case CTRL('B'):
992 next = 192;
993 c = getkey();
994 break;
995 }
996 if (c < ' ')
997 return (-1);
998 return (next + c - ' ');
999 }
1000 /* #endif PTR_ADDRESSES */
1001
1002 /*
1003 * Find single character c, in direction dir from cursor.
1004 */
1005 int
find(wchar_t c)1006 find(wchar_t c)
1007 {
1008
1009 wchar_t wchar;
1010 int length;
1011 for (;;) {
1012 if (edge())
1013 return (0);
1014 if (dir == 1)
1015 wcursor = nextchr(wcursor);
1016 else
1017 wcursor = lastchr(linebuf, wcursor);
1018 if ((length = mbtowc(&wchar, (char *)wcursor,
1019 MULTI_BYTE_MAX)) > 0 && wchar == c)
1020 return (1);
1021 }
1022 }
1023
1024 /*
1025 * Do a word motion with operator op, and cnt more words
1026 * to go after this.
1027 */
1028 int
word(int (* op)(),int cnt)1029 word(int (*op)(), int cnt)
1030 {
1031 int which;
1032 unsigned char *iwc;
1033 line *iwdot = wdot;
1034 wchar_t wchar;
1035 int length;
1036
1037 if (dir == 1) {
1038 iwc = wcursor;
1039 which = wordch(wcursor);
1040 while (wordof(which, wcursor)) {
1041 length = mbtowc(&wchar, (char *)wcursor,
1042 MULTI_BYTE_MAX);
1043 if (length <= 0)
1044 length = 1;
1045 if (cnt == 1 && op != vmove && wcursor[length] == 0) {
1046 wcursor += length;
1047 break;
1048 }
1049 if (!lnext())
1050 return (0);
1051 if (wcursor == linebuf)
1052 break;
1053 }
1054 /* Unless last segment of a change skip blanks */
1055 if (op != (int (*)())vchange || cnt > 1)
1056 while (!margin() && blank()) {
1057 if (!lnext())
1058 return (0);
1059 }
1060 else
1061 if (wcursor == iwc && iwdot == wdot && *iwc)
1062 wcursor = nextchr(wcursor);
1063 if (op == vmove && margin()) {
1064 wcursor = lastchr(linebuf, wcursor);
1065 #ifdef XPG4
1066 if (wcursor < linebuf) {
1067 wcursor = linebuf;
1068 }
1069 #endif /* XPG4 */
1070 }
1071 } else {
1072 if (!lnext())
1073 return (0);
1074 while (blank())
1075 if (!lnext())
1076 return (0);
1077 if (!margin()) {
1078 which = wordch(wcursor);
1079 while (!margin() && wordof(which, wcursor))
1080 wcursor = lastchr(linebuf, wcursor);
1081 }
1082 #ifdef PRESUNEUC
1083 if (wcursor < linebuf || !wordof(which, wcursor))
1084 wcursor = nextchr(wcursor);
1085 #else
1086 if (wcursor < linebuf)
1087 wcursor++;
1088 else if (!wordof(which, wcursor))
1089 wcursor = nextchr(wcursor);
1090 #endif /* PRESUNEUC */
1091 }
1092 return (1);
1093 }
1094
1095 /*
1096 * To end of word, with operator op and cnt more motions
1097 * remaining after this.
1098 */
1099 int
eend(int (* op)())1100 eend(int (*op)())
1101 {
1102 int which;
1103
1104 if (!lnext())
1105 return (0);
1106 while (blank())
1107 if (!lnext())
1108 return (0);
1109 which = wordch(wcursor);
1110 while (wordof(which, wcursor)) {
1111 if (wcursor[1] == 0) {
1112 wcursor = nextchr(wcursor);
1113 break;
1114 }
1115 if (!lnext())
1116 return (0);
1117 }
1118 if (op == vyankit)
1119 wcursor = lastchr(linebuf, wcursor) + 1;
1120 else if (op != (int (*)())vchange && op != (int (*)())vdelete &&
1121 wcursor > linebuf)
1122 wcursor = lastchr(linebuf, wcursor);
1123 return (1);
1124 }
1125
1126 /*
1127 * Wordof tells whether the character at *wc is in a word of
1128 * kind which (blank/nonblank words are 0, conservative words 1).
1129 */
1130 int
wordof(unsigned char which,unsigned char * wc)1131 wordof(unsigned char which, unsigned char *wc)
1132 {
1133 #ifdef PRESUNEUC
1134
1135 if (isspace(*wc))
1136 #else
1137 wchar_t z;
1138
1139 (void) mbtowc(&z, (char *)wc, MB_LEN_MAX);
1140 if (iswspace(z))
1141 #endif /* PRESUNEUC */
1142 return (0);
1143 return (!wdkind || wordch(wc) == which);
1144 }
1145
1146 /*
1147 * Wordch tells whether character at *wc is a word character
1148 * i.e. an alfa, digit, or underscore.
1149 */
1150 #ifdef PRESUNEUC
1151 #define SS2 0216
1152 #define SS3 0217
1153 #endif /* PRESUNEUC */
1154
1155 int
wordch(unsigned char * wc)1156 wordch(unsigned char *wc)
1157 {
1158 int length;
1159 wchar_t c;
1160
1161 length = mbtowc(&c, (char *)wc, MULTI_BYTE_MAX);
1162 if (length <= 0)
1163 return (0);
1164 if (length > 1)
1165 #ifndef PRESUNEUC
1166 if (wdwc)
1167 return (*wdwc)(c);
1168 else
1169 #endif /* PRESUNEUC */
1170 return (length);
1171 #ifndef PRESUNEUC
1172 return (isalpha(*wc) || isdigit(*wc) || *wc == '_');
1173 #else
1174 return (isalpha(c) || isdigit(c) || c == '_');
1175 #endif /* PRESUNEUC */
1176 }
1177
1178 /*
1179 * Edge tells when we hit the last character in the current line.
1180 */
1181 int
edge(void)1182 edge(void)
1183 {
1184
1185 if (linebuf[0] == 0)
1186 return (1);
1187 if (dir == 1)
1188 return (*(nextchr(wcursor)) == 0);
1189 else
1190 return (wcursor == linebuf);
1191 }
1192
1193 /*
1194 * Margin tells us when we have fallen off the end of the line.
1195 */
1196 int
margin(void)1197 margin(void)
1198 {
1199
1200 return (wcursor < linebuf || wcursor[0] == 0);
1201 }
1202 #ifndef PRESUNEUC
1203
1204 /*
1205 * Blank tells if the cursor is currently on a TAB, RETURN,
1206 * NEWLINE, FORMFEED, bertical tab, or SPACE character from EUC
1207 * primary and supplementary codesets.
1208 */
1209 int
blank(void)1210 blank(void)
1211 {
1212 wchar_t z;
1213
1214 (void) mbtowc(&z, (char *)wcursor, MB_CUR_MAX);
1215 return (iswspace((int)z));
1216 }
1217 #endif /* PRESUNEUC */
1218