1 /*
2 * ed.chared.c: Character editing functions.
3 */
4 /*-
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32 /*
33 Bjorn Knutsson @ Thu Jun 24 19:02:17 1999
34
35 e_dabbrev_expand() did not do proper completion if quoted spaces were present
36 in the string being completed. Exemple:
37
38 # echo hello\ world
39 hello world
40 # echo h<press key bound to dabbrev-expande>
41 # echo hello\<cursor>
42
43 Correct behavior is:
44 # echo h<press key bound to dabbrev-expande>
45 # echo hello\ world<cursor>
46
47 The same problem occured if spaces were present in a string withing quotation
48 marks. Example:
49
50 # echo "hello world"
51 hello world
52 # echo "h<press key bound to dabbrev-expande>
53 # echo "hello<cursor>
54
55 The former problem could be solved with minor modifications of c_preword()
56 and c_endword(). The latter, however, required a significant rewrite of
57 c_preword(), since quoted strings must be parsed from start to end to
58 determine if a given character is inside or outside the quotation marks.
59
60 Compare the following two strings:
61
62 # echo \"" 'foo \' bar\"
63 " 'foo \' bar\
64 # echo '\"" 'foo \' bar\"
65 \"" foo ' bar"
66
67 The only difference between the two echo lines is in the first character
68 after the echo command. The result is either one or three arguments.
69
70 */
71
72 #include "sh.h"
73 #include "ed.h"
74 #include "tw.h"
75 #include "ed.defns.h"
76
77 /* #define SDEBUG */
78
79 #define TCSHOP_NOP 0x00
80 #define TCSHOP_DELETE 0x01
81 #define TCSHOP_INSERT 0x02
82 #define TCSHOP_CHANGE 0x04
83
84 #define CHAR_FWD 0
85 #define CHAR_BACK 1
86
87 /*
88 * vi word treatment
89 * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com>
90 */
91 #define C_CLASS_WHITE 1
92 #define C_CLASS_WORD 2
93 #define C_CLASS_OTHER 3
94
95 static Char *InsertPos = InputBuf; /* Where insertion starts */
96 static Char *ActionPos = 0; /* Where action begins */
97 static int ActionFlag = TCSHOP_NOP; /* What delayed action to take */
98 /*
99 * Word search state
100 */
101 static int searchdir = F_UP_SEARCH_HIST; /* Direction of last search */
102 static struct Strbuf patbuf; /* = Strbuf_INIT; Search target */
103 /*
104 * Char search state
105 */
106 static int srch_dir = CHAR_FWD; /* Direction of last search */
107 static Char srch_char = 0; /* Search target */
108
109 /* all routines that start with c_ are private to this set of routines */
110 static void c_alternativ_key_map (int);
111 void c_insert (int);
112 void c_delafter (int);
113 void c_delbefore (int);
114 static int c_to_class (Char);
115 static Char *c_prev_word (Char *, Char *, int);
116 static Char *c_next_word (Char *, Char *, int);
117 static Char *c_number (Char *, int *, int);
118 static Char *c_expand (Char *);
119 static int c_excl (Char *);
120 static int c_substitute (void);
121 static void c_delfini (void);
122 static int c_hmatch (Char *);
123 static void c_hsetpat (void);
124 #ifdef COMMENT
125 static void c_get_word (Char **, Char **);
126 #endif
127 static Char *c_preword (Char *, Char *, int, Char *);
128 static Char *c_nexword (Char *, Char *, int);
129 static Char *c_endword (Char *, Char *, int, Char *);
130 static Char *c_eword (Char *, Char *, int);
131 static void c_push_kill (Char *, Char *);
132 static void c_save_inputbuf (void);
133 static CCRETVAL c_search_line (Char *, int);
134 static CCRETVAL v_repeat_srch (int);
135 static CCRETVAL e_inc_search (int);
136 #ifdef notyet
137 static CCRETVAL e_insert_str (Char *);
138 #endif
139 static CCRETVAL v_search (int);
140 static CCRETVAL v_csearch_fwd (Char, int, int);
141 static CCRETVAL v_action (int);
142 static CCRETVAL v_csearch_back (Char, int, int);
143
144 static void
c_alternativ_key_map(int state)145 c_alternativ_key_map(int state)
146 {
147 switch (state) {
148 case 0:
149 CurrentKeyMap = CcKeyMap;
150 break;
151 case 1:
152 CurrentKeyMap = CcAltMap;
153 break;
154 default:
155 return;
156 }
157
158 AltKeyMap = (Char) state;
159 }
160
161 void
c_insert(int num)162 c_insert(int num)
163 {
164 Char *cp;
165
166 if (LastChar + num >= InputLim)
167 return; /* can't go past end of buffer */
168
169 if (Cursor < LastChar) { /* if I must move chars */
170 for (cp = LastChar; cp >= Cursor; cp--)
171 cp[num] = *cp;
172 if (Mark && Mark > Cursor)
173 Mark += num;
174 }
175 LastChar += num;
176 }
177
178 void
c_delafter(int num)179 c_delafter(int num)
180 {
181 Char *cp, *kp = NULL;
182
183 if (num > LastChar - Cursor)
184 num = (int) (LastChar - Cursor); /* bounds check */
185
186 if (num > 0) { /* if I can delete anything */
187 if (VImode) {
188 kp = UndoBuf; /* Set Up for VI undo command */
189 UndoAction = TCSHOP_INSERT;
190 UndoSize = num;
191 UndoPtr = Cursor;
192 for (cp = Cursor; cp <= LastChar; cp++) {
193 *kp++ = *cp; /* Save deleted chars into undobuf */
194 *cp = cp[num];
195 }
196 }
197 else
198 for (cp = Cursor; cp + num <= LastChar; cp++)
199 *cp = cp[num];
200 LastChar -= num;
201 /* Mark was within the range of the deleted word? */
202 if (Mark && Mark > Cursor && Mark <= Cursor+num)
203 Mark = Cursor;
204 /* Mark after the deleted word? */
205 else if (Mark && Mark > Cursor)
206 Mark -= num;
207 }
208 #ifdef notdef
209 else {
210 /*
211 * XXX: We don't want to do that. In emacs mode overwrite should be
212 * sticky. I am not sure how that affects vi mode
213 */
214 inputmode = MODE_INSERT;
215 }
216 #endif /* notdef */
217 }
218
219 void
c_delbefore(int num)220 c_delbefore(int num) /* delete before dot, with bounds checking */
221 {
222 Char *cp, *kp = NULL;
223
224 if (num > Cursor - InputBuf)
225 num = (int) (Cursor - InputBuf); /* bounds check */
226
227 if (num > 0) { /* if I can delete anything */
228 if (VImode) {
229 kp = UndoBuf; /* Set Up for VI undo command */
230 UndoAction = TCSHOP_INSERT;
231 UndoSize = num;
232 UndoPtr = Cursor - num;
233 for (cp = Cursor - num; cp <= LastChar; cp++) {
234 *kp++ = *cp;
235 *cp = cp[num];
236 }
237 }
238 else
239 for (cp = Cursor - num; cp + num <= LastChar; cp++)
240 *cp = cp[num];
241 LastChar -= num;
242 Cursor -= num;
243 /* Mark was within the range of the deleted word? */
244 if (Mark && Mark > Cursor && Mark <= Cursor+num)
245 Mark = Cursor;
246 /* Mark after the deleted word? */
247 else if (Mark && Mark > Cursor)
248 Mark -= num;
249 }
250 }
251
252 static Char *
c_preword(Char * p,Char * low,int n,Char * delim)253 c_preword(Char *p, Char *low, int n, Char *delim)
254 {
255 while (n--) {
256 Char *prev = low;
257 Char *new;
258
259 while (prev < p) { /* Skip initial non-word chars */
260 if (!Strchr(delim, *prev) || (prev > low && prev[-1] == (Char)'\\'))
261 break;
262 prev++;
263 }
264
265 new = prev;
266
267 while (new < p) {
268 prev = new;
269 new = c_endword(prev-1, p, 1, delim); /* Skip to next non-word char */
270 new++; /* Step away from end of word */
271 while (new <= p) { /* Skip trailing non-word chars */
272 if (!Strchr(delim, *new) || (new > prev && new[-1] == (Char)'\\'))
273 break;
274 new++;
275 }
276 }
277
278 p = prev; /* Set to previous word start */
279
280 }
281 if (p < low)
282 p = low;
283 return (p);
284 }
285
286 /*
287 * c_to_class() returns the class of the given character.
288 *
289 * This is used to make the c_prev_word(), c_next_word() and c_eword() functions
290 * work like vi's, which classify characters. A word is a sequence of
291 * characters belonging to the same class, classes being defined as
292 * follows:
293 *
294 * 1/ whitespace
295 * 2/ alphanumeric chars, + underscore
296 * 3/ others
297 */
298 static int
c_to_class(Char ch)299 c_to_class(Char ch)
300 {
301 if (Isspace(ch))
302 return C_CLASS_WHITE;
303
304 if (isword(ch))
305 return C_CLASS_WORD;
306
307 return C_CLASS_OTHER;
308 }
309
310 static Char *
c_prev_word(Char * p,Char * low,int n)311 c_prev_word(Char *p, Char *low, int n)
312 {
313 p--;
314
315 if (!VImode) {
316 while (n--) {
317 while ((p >= low) && !isword(*p))
318 p--;
319 while ((p >= low) && isword(*p))
320 p--;
321 }
322
323 /* cp now points to one character before the word */
324 p++;
325 if (p < low)
326 p = low;
327 /* cp now points where we want it */
328 return(p);
329 }
330
331 while (n--) {
332 int c_class;
333
334 if (p < low)
335 break;
336
337 /* scan until beginning of current word (may be all whitespace!) */
338 c_class = c_to_class(*p);
339 while ((p >= low) && c_class == c_to_class(*p))
340 p--;
341
342 /* if this was a non_whitespace word, we're ready */
343 if (c_class != C_CLASS_WHITE)
344 continue;
345
346 /* otherwise, move back to beginning of the word just found */
347 c_class = c_to_class(*p);
348 while ((p >= low) && c_class == c_to_class(*p))
349 p--;
350 }
351
352 p++; /* correct overshoot */
353
354 return (p);
355 }
356
357 static Char *
c_next_word(Char * p,Char * high,int n)358 c_next_word(Char *p, Char *high, int n)
359 {
360 if (!VImode) {
361 while (n--) {
362 while ((p < high) && !isword(*p))
363 p++;
364 while ((p < high) && isword(*p))
365 p++;
366 }
367 if (p > high)
368 p = high;
369 /* p now points where we want it */
370 return(p);
371 }
372
373 while (n--) {
374 int c_class;
375
376 if (p >= high)
377 break;
378
379 /* scan until end of current word (may be all whitespace!) */
380 c_class = c_to_class(*p);
381 while ((p < high) && c_class == c_to_class(*p))
382 p++;
383
384 /* if this was all whitespace, we're ready */
385 if (c_class == C_CLASS_WHITE)
386 continue;
387
388 /* if we've found white-space at the end of the word, skip it */
389 while ((p < high) && c_to_class(*p) == C_CLASS_WHITE)
390 p++;
391 }
392
393 p--; /* correct overshoot */
394
395 return (p);
396 }
397
398 static Char *
c_nexword(Char * p,Char * high,int n)399 c_nexword(Char *p, Char *high, int n)
400 {
401 while (n--) {
402 while ((p < high) && !Isspace(*p))
403 p++;
404 while ((p < high) && Isspace(*p))
405 p++;
406 }
407
408 if (p > high)
409 p = high;
410 /* p now points where we want it */
411 return(p);
412 }
413
414 /*
415 * Expand-History (originally "Magic-Space") code added by
416 * Ray Moody <ray@gibbs.physics.purdue.edu>
417 * this is a neat, but odd, addition.
418 */
419
420 /*
421 * c_number: Ignore character p points to, return number appearing after that.
422 * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
423 * Return p pointing to last char used.
424 */
425
426 /*
427 * dval is the number to subtract from for things like $-3
428 */
429
430 static Char *
c_number(Char * p,int * num,int dval)431 c_number(Char *p, int *num, int dval)
432 {
433 int i;
434 int sign = 1;
435
436 if (*++p == '^') {
437 *num = 1;
438 return(p);
439 }
440 if (*p == '$') {
441 if (*++p != '-') {
442 *num = INT_MAX; /* Handle $ */
443 return(--p);
444 }
445 sign = -1; /* Handle $- */
446 ++p;
447 }
448 for (i = 0; *p >= '0' && *p <= '9'; i = 10 * i + *p++ - '0')
449 continue;
450 *num = (sign < 0 ? dval - i : i);
451 return(--p);
452 }
453
454 /*
455 * excl_expand: There is an excl to be expanded to p -- do the right thing
456 * with it and return a version of p advanced over the expanded stuff. Also,
457 * update tsh_cur and related things as appropriate...
458 */
459
460 static Char *
c_expand(Char * p)461 c_expand(Char *p)
462 {
463 Char *q;
464 struct Hist *h = Histlist.Hnext;
465 struct wordent *l;
466 int i, from, to, dval;
467 int all_dig;
468 int been_once = 0;
469 Char *op = p;
470 Char *buf;
471 size_t buf_len;
472 Char *modbuf;
473
474 buf = NULL;
475 if (!h)
476 goto excl_err;
477 excl_sw:
478 switch (*(q = p + 1)) {
479
480 case '^':
481 buf = expand_lex(&h->Hlex, 1, 1);
482 break;
483
484 case '$':
485 if ((l = (h->Hlex).prev) != 0)
486 buf = expand_lex(l->prev->prev, 0, 0);
487 break;
488
489 case '*':
490 buf = expand_lex(&h->Hlex, 1, INT_MAX);
491 break;
492
493 default:
494 if (been_once) { /* unknown argument */
495 /* assume it's a modifier, e.g. !foo:h, and get whole cmd */
496 buf = expand_lex(&h->Hlex, 0, INT_MAX);
497 q -= 2;
498 break;
499 }
500 been_once = 1;
501
502 if (*q == ':') /* short form: !:arg */
503 --q;
504
505 if (HIST != '\0' && *q != HIST) {
506 /*
507 * Search for a space, tab, or colon. See if we have a number (as
508 * in !1234:xyz). Remember the number.
509 */
510 for (i = 0, all_dig = 1;
511 *q != ' ' && *q != '\t' && *q != ':' && q < Cursor; q++) {
512 /*
513 * PWP: !-4 is a valid history argument too, therefore the test
514 * is if not a digit, or not a - as the first character.
515 */
516 if ((*q < '0' || *q > '9') && (*q != '-' || q != p + 1))
517 all_dig = 0;
518 else if (*q == '-')
519 all_dig = 2;/* we are sneeky about this */
520 else
521 i = 10 * i + *q - '0';
522 }
523 --q;
524
525 /*
526 * If we have a number, search for event i. Otherwise, search for
527 * a named event (as in !foo). (In this case, I is the length of
528 * the named event).
529 */
530 if (all_dig) {
531 if (all_dig == 2)
532 i = -i; /* make it negitive */
533 if (i < 0) /* if !-4 (for example) */
534 i = eventno + 1 + i; /* remember: i is < 0 */
535 for (; h; h = h->Hnext) {
536 if (h->Hnum == i)
537 break;
538 }
539 }
540 else {
541 for (i = (int) (q - p); h; h = h->Hnext) {
542 if ((l = &h->Hlex) != 0) {
543 if (!Strncmp(p + 1, l->next->word, (size_t) i))
544 break;
545 }
546 }
547 }
548 }
549 if (!h)
550 goto excl_err;
551 if (q[1] == ':' || q[1] == '-' || q[1] == '*' ||
552 q[1] == '$' || q[1] == '^') { /* get some args */
553 p = q[1] == ':' ? ++q : q;
554 /*
555 * Go handle !foo:*
556 */
557 if ((q[1] < '0' || q[1] > '9') &&
558 q[1] != '-' && q[1] != '$' && q[1] != '^')
559 goto excl_sw;
560 /*
561 * Go handle !foo:$
562 */
563 if (q[1] == '$' && (q[2] != '-' || q[3] < '0' || q[3] > '9'))
564 goto excl_sw;
565 /*
566 * Count up the number of words in this event. Store it in dval.
567 * Dval will be fed to number.
568 */
569 dval = 0;
570 if ((l = h->Hlex.prev) != 0) {
571 for (l = l->prev; l != h->Hlex.next; l = l->prev, dval++)
572 continue;
573 }
574 if (!dval)
575 goto excl_err;
576 if (q[1] == '-')
577 from = 0;
578 else
579 q = c_number(q, &from, dval);
580 if (q[1] == '-') {
581 ++q;
582 if ((q[1] < '0' || q[1] > '9') && q[1] != '$')
583 to = dval - 1;
584 else
585 q = c_number(q, &to, dval);
586 }
587 else if (q[1] == '*') {
588 ++q;
589 to = INT_MAX;
590 }
591 else {
592 to = from;
593 }
594 if (from < 0 || to < from)
595 goto excl_err;
596 buf = expand_lex(&h->Hlex, from, to);
597 }
598 else /* get whole cmd */
599 buf = expand_lex(&h->Hlex, 0, INT_MAX);
600 break;
601 }
602 if (buf == NULL)
603 buf = SAVE("");
604
605 /*
606 * Apply modifiers, if any.
607 */
608 if (q[1] == ':') {
609 modbuf = buf;
610 while (q[1] == ':' && modbuf != NULL) {
611 switch (q[2]) {
612 case 'r':
613 case 'e':
614 case 'h':
615 case 't':
616 case 'q':
617 case 'x':
618 case 'u':
619 case 'l':
620 if ((modbuf = domod(buf, (int) q[2])) != NULL) {
621 xfree(buf);
622 buf = modbuf;
623 }
624 ++q;
625 break;
626
627 case 'a':
628 case 'g':
629 /* Not implemented; this needs to be done before expanding
630 * lex. We don't have the words available to us anymore.
631 */
632 ++q;
633 break;
634
635 case 'p':
636 /* Ok */
637 ++q;
638 break;
639
640 case '\0':
641 break;
642
643 default:
644 ++q;
645 break;
646 }
647 if (q[1])
648 ++q;
649 }
650 }
651
652 buf_len = Strlen(buf);
653 /*
654 * Now replace the text from op to q inclusive with the text from buf.
655 */
656 q++;
657
658 /*
659 * Now replace text non-inclusively like a real CS major!
660 */
661 if (LastChar + buf_len - (q - op) >= InputLim)
662 goto excl_err;
663 (void) memmove(op + buf_len, q, (LastChar - q) * sizeof(Char));
664 LastChar += buf_len - (q - op);
665 Cursor += buf_len - (q - op);
666 (void) memcpy(op, buf, buf_len * sizeof(Char));
667 *LastChar = '\0';
668 xfree(buf);
669 return op + buf_len;
670 excl_err:
671 xfree(buf);
672 SoundBeep();
673 return(op + 1);
674 }
675
676 /*
677 * c_excl: An excl has been found at point p -- back up and find some white
678 * space (or the beginning of the buffer) and properly expand all the excl's
679 * from there up to the current cursor position. We also avoid (trying to)
680 * expanding '>!'
681 * Returns number of expansions attempted (doesn't matter whether they succeeded
682 * or not).
683 */
684
685 static int
c_excl(Char * p)686 c_excl(Char *p)
687 {
688 int i;
689 Char *q;
690 int nr_exp;
691
692 /*
693 * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
694 * back p up to just before the current word.
695 */
696 if ((p[1] == ' ' || p[1] == '\t') &&
697 (p[-1] == ' ' || p[-1] == '\t' || p[-1] == '>')) {
698 for (q = p - 1; q > InputBuf && (*q == ' ' || *q == '\t'); --q)
699 continue;
700 if (*q == '>')
701 ++p;
702 }
703 else {
704 while (*p != ' ' && *p != '\t' && p > InputBuf)
705 --p;
706 }
707
708 /*
709 * Forever: Look for history char. (Stop looking when we find the cursor.)
710 * Count backslashes. If odd, skip history char. Expand if even number of
711 * backslashes.
712 */
713 nr_exp = 0;
714 for (;;) {
715 if (HIST != '\0')
716 while (*p != HIST && p < Cursor)
717 ++p;
718 for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++)
719 continue;
720 if (i % 2 == 0)
721 ++p;
722 if (p >= Cursor) /* all done */
723 return nr_exp;
724 if (i % 2 == 1) {
725 p = c_expand(p);
726 ++nr_exp;
727 }
728 }
729 }
730
731
732 static int
c_substitute(void)733 c_substitute(void)
734 {
735 Char *p;
736 int nr_exp;
737
738 /*
739 * Start p out one character before the cursor. Move it backwards looking
740 * for white space, the beginning of the line, or a history character.
741 */
742 for (p = Cursor - 1;
743 p > InputBuf && *p != ' ' && *p != '\t' && *p && *p != HIST; --p)
744 continue;
745
746 /*
747 * If we found a history character, go expand it.
748 */
749 if (p >= InputBuf && HIST != '\0' && *p == HIST)
750 nr_exp = c_excl(p);
751 else
752 nr_exp = 0;
753 Refresh();
754
755 return nr_exp;
756 }
757
758 static void
c_delfini(void)759 c_delfini(void) /* Finish up delete action */
760 {
761 int Size;
762
763 if (ActionFlag & TCSHOP_INSERT)
764 c_alternativ_key_map(0);
765
766 ActionFlag = TCSHOP_NOP;
767
768 if (ActionPos == 0)
769 return;
770
771 UndoAction = TCSHOP_INSERT;
772
773 if (Cursor > ActionPos) {
774 Size = (int) (Cursor-ActionPos);
775 c_delbefore(Size);
776 RefCursor();
777 }
778 else if (Cursor < ActionPos) {
779 Size = (int)(ActionPos-Cursor);
780 c_delafter(Size);
781 }
782 else {
783 Size = 1;
784 c_delafter(Size);
785 }
786 UndoPtr = Cursor;
787 UndoSize = Size;
788 }
789
790 static Char *
c_endword(Char * p,Char * high,int n,Char * delim)791 c_endword(Char *p, Char *high, int n, Char *delim)
792 {
793 Char inquote = 0;
794 p++;
795
796 while (n--) {
797 while (p < high) { /* Skip non-word chars */
798 if (!Strchr(delim, *p) || p[-1] == (Char)'\\')
799 break;
800 p++;
801 }
802 while (p < high) { /* Skip string */
803 if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */
804 if (inquote || p[-1] != (Char)'\\') { /* Should it be honored? */
805 if (inquote == 0) inquote = *p;
806 else if (inquote == *p) inquote = 0;
807 }
808 }
809 /* Break if unquoted non-word char */
810 if (!inquote && Strchr(delim, *p) && p[-1] != (Char)'\\')
811 break;
812 p++;
813 }
814 }
815
816 p--;
817 return(p);
818 }
819
820
821 static Char *
c_eword(Char * p,Char * high,int n)822 c_eword(Char *p, Char *high, int n)
823 {
824 p++;
825
826 while (n--) {
827 int c_class;
828
829 if (p >= high)
830 break;
831
832 /* scan until end of current word (may be all whitespace!) */
833 c_class = c_to_class(*p);
834 while ((p < high) && c_class == c_to_class(*p))
835 p++;
836
837 /* if this was a non_whitespace word, we're ready */
838 if (c_class != C_CLASS_WHITE)
839 continue;
840
841 /* otherwise, move to the end of the word just found */
842 c_class = c_to_class(*p);
843 while ((p < high) && c_class == c_to_class(*p))
844 p++;
845 }
846
847 p--;
848 return(p);
849 }
850
851 /* Set the max length of the kill ring */
852 void
SetKillRing(int max)853 SetKillRing(int max)
854 {
855 CStr *new;
856 int count, i, j;
857
858 if (max < 1)
859 max = 1; /* no ring, but always one buffer */
860 if (max == KillRingMax)
861 return;
862 new = xcalloc(max, sizeof(CStr));
863 if (KillRing != NULL) {
864 if (KillRingLen != 0) {
865 if (max >= KillRingLen) {
866 count = KillRingLen;
867 j = KillPos;
868 } else {
869 count = max;
870 j = (KillPos - count + KillRingLen) % KillRingLen;
871 }
872 for (i = 0; i < KillRingLen; i++) {
873 if (i < count) /* copy latest */
874 new[i] = KillRing[j];
875 else /* free the others */
876 xfree(KillRing[j].buf);
877 j = (j + 1) % KillRingLen;
878 }
879 KillRingLen = count;
880 KillPos = count % max;
881 YankPos = count - 1;
882 }
883 xfree(KillRing);
884 }
885 KillRing = new;
886 KillRingMax = max;
887 }
888
889 /* Push string from start upto (but not including) end onto kill ring */
890 static void
c_push_kill(Char * start,Char * end)891 c_push_kill(Char *start, Char *end)
892 {
893 CStr save, *pos;
894 Char *dp, *cp, *kp;
895 int len = end - start, i, j, k;
896
897 /* Check for duplicates? */
898 if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
899 YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
900 if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */
901 j = YankPos;
902 for (i = 0; i < KillRingLen; i++) {
903 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
904 KillRing[j].buf[len] == '\0') {
905 save = KillRing[j];
906 for ( ; i > 0; i--) {
907 k = j;
908 j = (j + 1) % KillRingLen;
909 KillRing[k] = KillRing[j];
910 }
911 KillRing[j] = save;
912 return;
913 }
914 j = (j - 1 + KillRingLen) % KillRingLen;
915 }
916 } else if (eq(dp, STRall)) { /* skip if any earlier */
917 for (i = 0; i < KillRingLen; i++)
918 if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
919 KillRing[i].buf[len] == '\0')
920 return;
921 } else if (eq(dp, STRprev)) { /* skip if immediately previous */
922 j = YankPos;
923 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
924 KillRing[j].buf[len] == '\0')
925 return;
926 }
927 }
928
929 /* No duplicate, go ahead and push */
930 len++; /* need space for '\0' */
931 YankPos = KillPos;
932 if (KillRingLen < KillRingMax)
933 KillRingLen++;
934 pos = &KillRing[KillPos];
935 KillPos = (KillPos + 1) % KillRingMax;
936 if (pos->len < len) {
937 pos->buf = xrealloc(pos->buf, len * sizeof(Char));
938 pos->len = len;
939 }
940 cp = start;
941 kp = pos->buf;
942 while (cp < end)
943 *kp++ = *cp++;
944 *kp = '\0';
945 }
946
947 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
948 static void
c_save_inputbuf(void)949 c_save_inputbuf(void)
950 {
951 SavedBuf.len = 0;
952 Strbuf_append(&SavedBuf, InputBuf);
953 Strbuf_terminate(&SavedBuf);
954 LastSaved = LastChar - InputBuf;
955 CursSaved = Cursor - InputBuf;
956 HistSaved = Hist_num;
957 RestoreSaved = 1;
958 }
959
960 CCRETVAL
GetHistLine(void)961 GetHistLine(void)
962 {
963 struct Hist *hp;
964 int h;
965
966 if (Hist_num == 0) { /* if really the current line */
967 if (HistBuf.s != NULL)
968 copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
969 else
970 *InputBuf = '\0';
971 LastChar = InputBuf + HistBuf.len;
972
973 #ifdef KSHVI
974 if (VImode)
975 Cursor = InputBuf;
976 else
977 #endif /* KSHVI */
978 Cursor = LastChar;
979
980 return(CC_REFRESH);
981 }
982
983 hp = Histlist.Hnext;
984 if (hp == NULL)
985 return(CC_ERROR);
986
987 for (h = 1; h < Hist_num; h++) {
988 if ((hp->Hnext) == NULL) {
989 Hist_num = h;
990 return(CC_ERROR);
991 }
992 hp = hp->Hnext;
993 }
994
995 if (HistLit && hp->histline) {
996 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
997 CurrentHistLit = 1;
998 }
999 else {
1000 Char *p;
1001
1002 p = sprlex(&hp->Hlex);
1003 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1004 xfree(p);
1005 CurrentHistLit = 0;
1006 }
1007 LastChar = Strend(InputBuf);
1008
1009 if (LastChar > InputBuf) {
1010 if (LastChar[-1] == '\n')
1011 LastChar--;
1012 #if 0
1013 if (LastChar[-1] == ' ')
1014 LastChar--;
1015 #endif
1016 if (LastChar < InputBuf)
1017 LastChar = InputBuf;
1018 }
1019
1020 #ifdef KSHVI
1021 if (VImode)
1022 Cursor = InputBuf;
1023 else
1024 #endif /* KSHVI */
1025 Cursor = LastChar;
1026
1027 return(CC_REFRESH);
1028 }
1029
1030 static CCRETVAL
c_search_line(Char * pattern,int dir)1031 c_search_line(Char *pattern, int dir)
1032 {
1033 Char *cp;
1034 size_t len;
1035
1036 len = Strlen(pattern);
1037
1038 if (dir == F_UP_SEARCH_HIST) {
1039 for (cp = Cursor; cp >= InputBuf; cp--)
1040 if (Strncmp(cp, pattern, len) == 0 ||
1041 Gmatch(cp, pattern)) {
1042 Cursor = cp;
1043 return(CC_NORM);
1044 }
1045 return(CC_ERROR);
1046 } else {
1047 for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1048 if (Strncmp(cp, pattern, len) == 0 ||
1049 Gmatch(cp, pattern)) {
1050 Cursor = cp;
1051 return(CC_NORM);
1052 }
1053 return(CC_ERROR);
1054 }
1055 }
1056
1057 static CCRETVAL
e_inc_search(int dir)1058 e_inc_search(int dir)
1059 {
1060 static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1061 STRbck[] = { 'b', 'c', 'k', '\0' };
1062 static Char pchar = ':'; /* ':' = normal, '?' = failed */
1063 static Char endcmd[2];
1064 const Char *cp;
1065 Char ch,
1066 *oldCursor = Cursor,
1067 oldpchar = pchar;
1068 CCRETVAL ret = CC_NORM;
1069 int oldHist_num = Hist_num,
1070 oldpatlen = patbuf.len,
1071 newdir = dir,
1072 done, redo;
1073
1074 if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
1075 return(CC_ERROR);
1076
1077 for (;;) {
1078
1079 if (patbuf.len == 0) { /* first round */
1080 pchar = ':';
1081 Strbuf_append1(&patbuf, '*');
1082 }
1083 done = redo = 0;
1084 *LastChar++ = '\n';
1085 for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
1086 *cp; *LastChar++ = *cp++)
1087 continue;
1088 *LastChar++ = pchar;
1089 for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1090 *LastChar++ = *cp++)
1091 continue;
1092 *LastChar = '\0';
1093 if (adrof(STRhighlight) && pchar == ':') {
1094 /* if the no-glob-search patch is applied, remove the - 1 below */
1095 IncMatchLen = patbuf.len - 1;
1096 ClearLines();
1097 ClearDisp();
1098 }
1099 Refresh();
1100
1101 if (GetNextChar(&ch) != 1)
1102 return(e_send_eof(0));
1103
1104 switch (GetCmdChar(ch)) {
1105 case F_INSERT:
1106 case F_DIGIT:
1107 case F_MAGIC_SPACE:
1108 if (LastChar + 1 >= InputLim) /*FIXBUF*/
1109 SoundBeep();
1110 else {
1111 Strbuf_append1(&patbuf, ch);
1112 *LastChar++ = ch;
1113 *LastChar = '\0';
1114 Refresh();
1115 }
1116 break;
1117
1118 case F_INC_FWD:
1119 newdir = F_DOWN_SEARCH_HIST;
1120 redo++;
1121 break;
1122
1123 case F_INC_BACK:
1124 newdir = F_UP_SEARCH_HIST;
1125 redo++;
1126 break;
1127
1128 case F_DELPREV:
1129 if (patbuf.len > 1)
1130 done++;
1131 else
1132 SoundBeep();
1133 break;
1134
1135 default:
1136 switch (ASC(ch)) {
1137 case 0007: /* ^G: Abort */
1138 ret = CC_ERROR;
1139 done++;
1140 break;
1141
1142 case 0027: /* ^W: Append word */
1143 /* No can do if globbing characters in pattern */
1144 for (cp = &patbuf.s[1]; ; cp++)
1145 if (cp >= &patbuf.s[patbuf.len]) {
1146 Cursor += patbuf.len - 1;
1147 cp = c_next_word(Cursor, LastChar, 1);
1148 while (Cursor < cp && *Cursor != '\n') {
1149 if (LastChar + 1 >= InputLim) {/*FIXBUF*/
1150 SoundBeep();
1151 break;
1152 }
1153 Strbuf_append1(&patbuf, *Cursor);
1154 *LastChar++ = *Cursor++;
1155 }
1156 Cursor = oldCursor;
1157 *LastChar = '\0';
1158 Refresh();
1159 break;
1160 } else if (isglob(*cp)) {
1161 SoundBeep();
1162 break;
1163 }
1164 break;
1165
1166 default: /* Terminate and execute cmd */
1167 endcmd[0] = ch;
1168 PushMacro(endcmd);
1169 /*FALLTHROUGH*/
1170
1171 case 0033: /* ESC: Terminate */
1172 ret = CC_REFRESH;
1173 done++;
1174 break;
1175 }
1176 break;
1177 }
1178
1179 while (LastChar > InputBuf && *LastChar != '\n')
1180 *LastChar-- = '\0';
1181 *LastChar = '\0';
1182
1183 if (!done) {
1184
1185 /* Can't search if unmatched '[' */
1186 for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
1187 if (*cp == '[' || *cp == ']') {
1188 ch = *cp;
1189 break;
1190 }
1191
1192 if (patbuf.len > 1 && ch != '[') {
1193 if (redo && newdir == dir) {
1194 if (pchar == '?') { /* wrap around */
1195 Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1196 if (GetHistLine() == CC_ERROR)
1197 /* Hist_num was fixed by first call */
1198 (void) GetHistLine();
1199 Cursor = newdir == F_UP_SEARCH_HIST ?
1200 LastChar : InputBuf;
1201 } else
1202 Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
1203 }
1204 Strbuf_append1(&patbuf, '*');
1205 Strbuf_terminate(&patbuf);
1206 if (Cursor < InputBuf || Cursor > LastChar ||
1207 (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
1208 LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
1209 ret = newdir == F_UP_SEARCH_HIST ?
1210 e_up_search_hist(0) : e_down_search_hist(0);
1211 if (ret != CC_ERROR) {
1212 Cursor = newdir == F_UP_SEARCH_HIST ?
1213 LastChar : InputBuf;
1214 (void) c_search_line(&patbuf.s[1], newdir);
1215 }
1216 }
1217 patbuf.s[--patbuf.len] = '\0';
1218 if (ret == CC_ERROR) {
1219 SoundBeep();
1220 if (Hist_num != oldHist_num) {
1221 Hist_num = oldHist_num;
1222 if (GetHistLine() == CC_ERROR)
1223 return(CC_ERROR);
1224 }
1225 Cursor = oldCursor;
1226 pchar = '?';
1227 } else {
1228 pchar = ':';
1229 }
1230 }
1231
1232 ret = e_inc_search(newdir);
1233
1234 if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
1235 /* break abort of failed search at last non-failed */
1236 ret = CC_NORM;
1237 }
1238
1239 }
1240
1241 if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
1242 /* restore on normal return or error exit */
1243 pchar = oldpchar;
1244 patbuf.len = oldpatlen;
1245 if (Hist_num != oldHist_num) {
1246 Hist_num = oldHist_num;
1247 if (GetHistLine() == CC_ERROR)
1248 return(CC_ERROR);
1249 }
1250 Cursor = oldCursor;
1251 if (ret == CC_ERROR)
1252 Refresh();
1253 }
1254 if (done || ret != CC_NORM)
1255 return(ret);
1256
1257 }
1258
1259 }
1260
1261 static CCRETVAL
v_search(int dir)1262 v_search(int dir)
1263 {
1264 struct Strbuf tmpbuf = Strbuf_INIT;
1265 Char ch;
1266 Char *oldbuf;
1267 Char *oldlc, *oldc;
1268
1269 cleanup_push(&tmpbuf, Strbuf_cleanup);
1270 oldbuf = Strsave(InputBuf);
1271 cleanup_push(oldbuf, xfree);
1272 oldlc = LastChar;
1273 oldc = Cursor;
1274 Strbuf_append1(&tmpbuf, '*');
1275
1276 InputBuf[0] = '\0';
1277 LastChar = InputBuf;
1278 Cursor = InputBuf;
1279 searchdir = dir;
1280
1281 c_insert(2); /* prompt + '\n' */
1282 *Cursor++ = '\n';
1283 *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
1284 Refresh();
1285 for (ch = 0;ch == 0;) {
1286 if (GetNextChar(&ch) != 1) {
1287 cleanup_until(&tmpbuf);
1288 return(e_send_eof(0));
1289 }
1290 switch (ASC(ch)) {
1291 case 0010: /* Delete and backspace */
1292 case 0177:
1293 if (tmpbuf.len > 1) {
1294 *Cursor-- = '\0';
1295 LastChar = Cursor;
1296 tmpbuf.len--;
1297 }
1298 else {
1299 copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
1300 LastChar = oldlc;
1301 Cursor = oldc;
1302 cleanup_until(&tmpbuf);
1303 return(CC_REFRESH);
1304 }
1305 Refresh();
1306 ch = 0;
1307 break;
1308
1309 case 0033: /* ESC */
1310 #ifdef IS_ASCII
1311 case '\r': /* Newline */
1312 case '\n':
1313 #else
1314 case '\012': /* ASCII Line feed */
1315 case '\015': /* ASCII (or EBCDIC) Return */
1316 #endif
1317 break;
1318
1319 default:
1320 Strbuf_append1(&tmpbuf, ch);
1321 *Cursor++ = ch;
1322 LastChar = Cursor;
1323 Refresh();
1324 ch = 0;
1325 break;
1326 }
1327 }
1328 cleanup_until(oldbuf);
1329
1330 if (tmpbuf.len == 1) {
1331 /*
1332 * Use the old pattern, but wild-card it.
1333 */
1334 if (patbuf.len == 0) {
1335 InputBuf[0] = '\0';
1336 LastChar = InputBuf;
1337 Cursor = InputBuf;
1338 Refresh();
1339 cleanup_until(&tmpbuf);
1340 return(CC_ERROR);
1341 }
1342 if (patbuf.s[0] != '*') {
1343 oldbuf = Strsave(patbuf.s);
1344 patbuf.len = 0;
1345 Strbuf_append1(&patbuf, '*');
1346 Strbuf_append(&patbuf, oldbuf);
1347 xfree(oldbuf);
1348 Strbuf_append1(&patbuf, '*');
1349 Strbuf_terminate(&patbuf);
1350 }
1351 }
1352 else {
1353 Strbuf_append1(&tmpbuf, '*');
1354 Strbuf_terminate(&tmpbuf);
1355 patbuf.len = 0;
1356 Strbuf_append(&patbuf, tmpbuf.s);
1357 Strbuf_terminate(&patbuf);
1358 }
1359 cleanup_until(&tmpbuf);
1360 LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
1361 Cursor = LastChar = InputBuf;
1362 if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
1363 e_down_search_hist(0)) == CC_ERROR) {
1364 Refresh();
1365 return(CC_ERROR);
1366 }
1367 else {
1368 if (ASC(ch) == 0033) {
1369 Refresh();
1370 *LastChar++ = '\n';
1371 *LastChar = '\0';
1372 PastBottom();
1373 return(CC_NEWLINE);
1374 }
1375 else
1376 return(CC_REFRESH);
1377 }
1378 }
1379
1380 /*
1381 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1382 * entry point, called from the CcKeyMap indirected into the
1383 * CcFuncTbl array.
1384 */
1385
1386 /*ARGSUSED*/
1387 CCRETVAL
v_cmd_mode(Char c)1388 v_cmd_mode(Char c)
1389 {
1390 USE(c);
1391 InsertPos = 0;
1392 ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */
1393 ActionPos = 0;
1394 DoingArg = 0;
1395 if (UndoPtr > Cursor)
1396 UndoSize = (int)(UndoPtr - Cursor);
1397 else
1398 UndoSize = (int)(Cursor - UndoPtr);
1399
1400 inputmode = MODE_INSERT;
1401 c_alternativ_key_map(1);
1402 #ifdef notdef
1403 /*
1404 * We don't want to move the cursor, because all the editing
1405 * commands don't include the character under the cursor.
1406 */
1407 if (Cursor > InputBuf)
1408 Cursor--;
1409 #endif
1410 RefCursor();
1411 return(CC_NORM);
1412 }
1413
1414 /*ARGSUSED*/
1415 CCRETVAL
e_unassigned(Char c)1416 e_unassigned(Char c)
1417 { /* bound to keys that arn't really assigned */
1418 USE(c);
1419 SoundBeep();
1420 flush();
1421 return(CC_NORM);
1422 }
1423
1424 #ifdef notyet
1425 static CCRETVAL
e_insert_str(Char * c)1426 e_insert_str(Char *c)
1427 {
1428 int i, n;
1429
1430 n = Strlen(c);
1431 if (LastChar + Argument * n >= InputLim)
1432 return(CC_ERROR); /* end of buffer space */
1433 if (inputmode != MODE_INSERT) {
1434 c_delafter(Argument * Strlen(c));
1435 }
1436 c_insert(Argument * n);
1437 while (Argument--) {
1438 for (i = 0; i < n; i++)
1439 *Cursor++ = c[i];
1440 }
1441 Refresh();
1442 return(CC_NORM);
1443 }
1444 #endif
1445
1446 CCRETVAL
e_insert(Char c)1447 e_insert(Char c)
1448 {
1449 #ifndef SHORT_STRINGS
1450 c &= ASCII; /* no meta chars ever */
1451 #endif
1452
1453 if (!c)
1454 return(CC_ERROR); /* no NULs in the input ever!! */
1455
1456 if (LastChar + Argument >= InputLim)
1457 return(CC_ERROR); /* end of buffer space */
1458
1459 if (Argument == 1) { /* How was this optimized ???? */
1460
1461 if (inputmode != MODE_INSERT) {
1462 UndoBuf[UndoSize++] = *Cursor;
1463 UndoBuf[UndoSize] = '\0';
1464 c_delafter(1); /* Do NOT use the saving ONE */
1465 }
1466
1467 c_insert(1);
1468 *Cursor++ = (Char) c;
1469 DoingArg = 0; /* just in case */
1470 RefPlusOne(1); /* fast refresh for one char. */
1471 }
1472 else {
1473 if (inputmode != MODE_INSERT) {
1474 int i;
1475 for (i = 0; i < Argument; i++)
1476 UndoBuf[UndoSize++] = Cursor[i];
1477
1478 UndoBuf[UndoSize] = '\0';
1479 c_delafter(Argument); /* Do NOT use the saving ONE */
1480 }
1481
1482 c_insert(Argument);
1483
1484 while (Argument--)
1485 *Cursor++ = (Char) c;
1486 Refresh();
1487 }
1488
1489 if (inputmode == MODE_REPLACE_1)
1490 (void) v_cmd_mode(0);
1491
1492 return(CC_NORM);
1493 }
1494
1495 int
InsertStr(Char * s)1496 InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */
1497 {
1498 int len;
1499
1500 if ((len = (int) Strlen(s)) <= 0)
1501 return -1;
1502 if (LastChar + len >= InputLim)
1503 return -1; /* end of buffer space */
1504
1505 c_insert(len);
1506 while (len--)
1507 *Cursor++ = *s++;
1508 return 0;
1509 }
1510
1511 void
DeleteBack(int n)1512 DeleteBack(int n) /* delete the n characters before . */
1513 {
1514 if (n <= 0)
1515 return;
1516 if (Cursor >= &InputBuf[n]) {
1517 c_delbefore(n); /* delete before dot */
1518 }
1519 }
1520
1521 CCRETVAL
e_digit(Char c)1522 e_digit(Char c) /* gray magic here */
1523 {
1524 if (!Isdigit(c))
1525 return(CC_ERROR); /* no NULs in the input ever!! */
1526
1527 if (DoingArg) { /* if doing an arg, add this in... */
1528 if (LastCmd == F_ARGFOUR) /* if last command was ^U */
1529 Argument = c - '0';
1530 else {
1531 if (Argument > 1000000)
1532 return CC_ERROR;
1533 Argument = (Argument * 10) + (c - '0');
1534 }
1535 return(CC_ARGHACK);
1536 }
1537 else {
1538 if (LastChar + 1 >= InputLim)
1539 return CC_ERROR; /* end of buffer space */
1540
1541 if (inputmode != MODE_INSERT) {
1542 UndoBuf[UndoSize++] = *Cursor;
1543 UndoBuf[UndoSize] = '\0';
1544 c_delafter(1); /* Do NOT use the saving ONE */
1545 }
1546 c_insert(1);
1547 *Cursor++ = (Char) c;
1548 DoingArg = 0; /* just in case */
1549 RefPlusOne(1); /* fast refresh for one char. */
1550 }
1551 return(CC_NORM);
1552 }
1553
1554 CCRETVAL
e_argdigit(Char c)1555 e_argdigit(Char c) /* for ESC-n */
1556 {
1557 #ifdef IS_ASCII
1558 c &= ASCII;
1559 #else
1560 c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1561 #endif
1562
1563 if (!Isdigit(c))
1564 return(CC_ERROR); /* no NULs in the input ever!! */
1565
1566 if (DoingArg) { /* if doing an arg, add this in... */
1567 if (Argument > 1000000)
1568 return CC_ERROR;
1569 Argument = (Argument * 10) + (c - '0');
1570 }
1571 else { /* else starting an argument */
1572 Argument = c - '0';
1573 DoingArg = 1;
1574 }
1575 return(CC_ARGHACK);
1576 }
1577
1578 CCRETVAL
v_zero(Char c)1579 v_zero(Char c) /* command mode 0 for vi */
1580 {
1581 if (DoingArg) { /* if doing an arg, add this in... */
1582 if (Argument > 1000000)
1583 return CC_ERROR;
1584 Argument = (Argument * 10) + (c - '0');
1585 return(CC_ARGHACK);
1586 }
1587 else { /* else starting an argument */
1588 Cursor = InputBuf;
1589 if (ActionFlag & TCSHOP_DELETE) {
1590 c_delfini();
1591 return(CC_REFRESH);
1592 }
1593 RefCursor(); /* move the cursor */
1594 return(CC_NORM);
1595 }
1596 }
1597
1598 /*ARGSUSED*/
1599 CCRETVAL
e_newline(Char c)1600 e_newline(Char c)
1601 { /* always ignore argument */
1602 USE(c);
1603 if (adrof(STRhighlight) && MarkIsSet) {
1604 MarkIsSet = 0;
1605 ClearLines();
1606 ClearDisp();
1607 Refresh();
1608 }
1609 MarkIsSet = 0;
1610
1611 /* PastBottom(); NOW done in ed.inputl.c */
1612 *LastChar++ = '\n'; /* for the benefit of CSH */
1613 *LastChar = '\0'; /* just in case */
1614 if (VImode)
1615 InsertPos = InputBuf; /* Reset editing position */
1616 return(CC_NEWLINE);
1617 }
1618
1619 /*ARGSUSED*/
1620 CCRETVAL
e_newline_hold(Char c)1621 e_newline_hold(Char c)
1622 {
1623 USE(c);
1624 c_save_inputbuf();
1625 HistSaved = 0;
1626 *LastChar++ = '\n'; /* for the benefit of CSH */
1627 *LastChar = '\0'; /* just in case */
1628 return(CC_NEWLINE);
1629 }
1630
1631 /*ARGSUSED*/
1632 CCRETVAL
e_newline_down_hist(Char c)1633 e_newline_down_hist(Char c)
1634 {
1635 USE(c);
1636 if (Hist_num > 1) {
1637 HistSaved = Hist_num;
1638 }
1639 *LastChar++ = '\n'; /* for the benefit of CSH */
1640 *LastChar = '\0'; /* just in case */
1641 return(CC_NEWLINE);
1642 }
1643
1644 /*ARGSUSED*/
1645 CCRETVAL
e_send_eof(Char c)1646 e_send_eof(Char c)
1647 { /* for when ^D is ONLY send-eof */
1648 USE(c);
1649 PastBottom();
1650 *LastChar = '\0'; /* just in case */
1651 return(CC_EOF);
1652 }
1653
1654 /*ARGSUSED*/
1655 CCRETVAL
e_complete(Char c)1656 e_complete(Char c)
1657 {
1658 USE(c);
1659 *LastChar = '\0'; /* just in case */
1660 return(CC_COMPLETE);
1661 }
1662
1663 /*ARGSUSED*/
1664 CCRETVAL
e_complete_back(Char c)1665 e_complete_back(Char c)
1666 {
1667 USE(c);
1668 *LastChar = '\0'; /* just in case */
1669 return(CC_COMPLETE_BACK);
1670 }
1671
1672 /*ARGSUSED*/
1673 CCRETVAL
e_complete_fwd(Char c)1674 e_complete_fwd(Char c)
1675 {
1676 USE(c);
1677 *LastChar = '\0'; /* just in case */
1678 return(CC_COMPLETE_FWD);
1679 }
1680
1681 /*ARGSUSED*/
1682 CCRETVAL
e_complete_all(Char c)1683 e_complete_all(Char c)
1684 {
1685 USE(c);
1686 *LastChar = '\0'; /* just in case */
1687 return(CC_COMPLETE_ALL);
1688 }
1689
1690 /*ARGSUSED*/
1691 CCRETVAL
v_cm_complete(Char c)1692 v_cm_complete(Char c)
1693 {
1694 USE(c);
1695 if (Cursor < LastChar)
1696 Cursor++;
1697 *LastChar = '\0'; /* just in case */
1698 return(CC_COMPLETE);
1699 }
1700
1701 /*ARGSUSED*/
1702 CCRETVAL
e_toggle_hist(Char c)1703 e_toggle_hist(Char c)
1704 {
1705 struct Hist *hp;
1706 int h;
1707
1708 USE(c);
1709 *LastChar = '\0'; /* just in case */
1710
1711 if (Hist_num <= 0) {
1712 return CC_ERROR;
1713 }
1714
1715 hp = Histlist.Hnext;
1716 if (hp == NULL) { /* this is only if no history */
1717 return(CC_ERROR);
1718 }
1719
1720 for (h = 1; h < Hist_num; h++)
1721 hp = hp->Hnext;
1722
1723 if (!CurrentHistLit) {
1724 if (hp->histline) {
1725 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1726 CurrentHistLit = 1;
1727 }
1728 else {
1729 return CC_ERROR;
1730 }
1731 }
1732 else {
1733 Char *p;
1734
1735 p = sprlex(&hp->Hlex);
1736 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1737 xfree(p);
1738 CurrentHistLit = 0;
1739 }
1740
1741 LastChar = Strend(InputBuf);
1742 if (LastChar > InputBuf) {
1743 if (LastChar[-1] == '\n')
1744 LastChar--;
1745 if (LastChar[-1] == ' ')
1746 LastChar--;
1747 if (LastChar < InputBuf)
1748 LastChar = InputBuf;
1749 }
1750
1751 #ifdef KSHVI
1752 if (VImode)
1753 Cursor = InputBuf;
1754 else
1755 #endif /* KSHVI */
1756 Cursor = LastChar;
1757
1758 return(CC_REFRESH);
1759 }
1760
1761 /*ARGSUSED*/
1762 CCRETVAL
e_up_hist(Char c)1763 e_up_hist(Char c)
1764 {
1765 Char beep = 0;
1766
1767 USE(c);
1768 UndoAction = TCSHOP_NOP;
1769 *LastChar = '\0'; /* just in case */
1770
1771 if (Hist_num == 0) { /* save the current buffer away */
1772 HistBuf.len = 0;
1773 Strbuf_append(&HistBuf, InputBuf);
1774 Strbuf_terminate(&HistBuf);
1775 }
1776
1777 Hist_num += Argument;
1778
1779 if (GetHistLine() == CC_ERROR) {
1780 beep = 1;
1781 (void) GetHistLine(); /* Hist_num was fixed by first call */
1782 }
1783
1784 Refresh();
1785 if (beep)
1786 return(CC_ERROR);
1787 else
1788 return(CC_NORM); /* was CC_UP_HIST */
1789 }
1790
1791 /*ARGSUSED*/
1792 CCRETVAL
e_down_hist(Char c)1793 e_down_hist(Char c)
1794 {
1795 USE(c);
1796 UndoAction = TCSHOP_NOP;
1797 *LastChar = '\0'; /* just in case */
1798
1799 Hist_num -= Argument;
1800
1801 if (Hist_num < 0) {
1802 Hist_num = 0;
1803 return(CC_ERROR); /* make it beep */
1804 }
1805
1806 return(GetHistLine());
1807 }
1808
1809
1810
1811 /*
1812 * c_hmatch() return True if the pattern matches the prefix
1813 */
1814 static int
c_hmatch(Char * str)1815 c_hmatch(Char *str)
1816 {
1817 if (Strncmp(patbuf.s, str, patbuf.len) == 0)
1818 return 1;
1819 return Gmatch(str, patbuf.s);
1820 }
1821
1822 /*
1823 * c_hsetpat(): Set the history seatch pattern
1824 */
1825 static void
c_hsetpat(void)1826 c_hsetpat(void)
1827 {
1828 if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1829 patbuf.len = 0;
1830 Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1831 Strbuf_terminate(&patbuf);
1832 }
1833 #ifdef SDEBUG
1834 xprintf("\nHist_num = %d\n", Hist_num);
1835 xprintf("patlen = %d\n", (int)patbuf.len);
1836 xprintf("patbuf = \"%S\"\n", patbuf.s);
1837 xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
1838 #endif
1839 }
1840
1841 /*ARGSUSED*/
1842 CCRETVAL
e_up_search_hist(Char c)1843 e_up_search_hist(Char c)
1844 {
1845 struct Hist *hp;
1846 int h;
1847 int found = 0;
1848
1849 USE(c);
1850 ActionFlag = TCSHOP_NOP;
1851 UndoAction = TCSHOP_NOP;
1852 *LastChar = '\0'; /* just in case */
1853 if (Hist_num < 0) {
1854 #ifdef DEBUG_EDIT
1855 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
1856 #endif
1857 Hist_num = 0;
1858 return(CC_ERROR);
1859 }
1860
1861 if (Hist_num == 0) {
1862 HistBuf.len = 0;
1863 Strbuf_append(&HistBuf, InputBuf);
1864 Strbuf_terminate(&HistBuf);
1865 }
1866
1867
1868 hp = Histlist.Hnext;
1869 if (hp == NULL)
1870 return(CC_ERROR);
1871
1872 c_hsetpat(); /* Set search pattern !! */
1873
1874 for (h = 1; h <= Hist_num; h++)
1875 hp = hp->Hnext;
1876
1877 while (hp != NULL) {
1878 Char *hl;
1879 int matched;
1880
1881 if (hp->histline == NULL)
1882 hp->histline = sprlex(&hp->Hlex);
1883 if (HistLit)
1884 hl = hp->histline;
1885 else {
1886 hl = sprlex(&hp->Hlex);
1887 cleanup_push(hl, xfree);
1888 }
1889 #ifdef SDEBUG
1890 xprintf("Comparing with \"%S\"\n", hl);
1891 #endif
1892 matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1893 hl[LastChar-InputBuf]) && c_hmatch(hl);
1894 if (!HistLit)
1895 cleanup_until(hl);
1896 if (matched) {
1897 found++;
1898 break;
1899 }
1900 h++;
1901 hp = hp->Hnext;
1902 }
1903
1904 if (!found) {
1905 #ifdef SDEBUG
1906 xprintf("not found\n");
1907 #endif
1908 return(CC_ERROR);
1909 }
1910
1911 Hist_num = h;
1912
1913 return(GetHistLine());
1914 }
1915
1916 /*ARGSUSED*/
1917 CCRETVAL
e_down_search_hist(Char c)1918 e_down_search_hist(Char c)
1919 {
1920 struct Hist *hp;
1921 int h;
1922 int found = 0;
1923
1924 USE(c);
1925 ActionFlag = TCSHOP_NOP;
1926 UndoAction = TCSHOP_NOP;
1927 *LastChar = '\0'; /* just in case */
1928
1929 if (Hist_num == 0)
1930 return(CC_ERROR);
1931
1932 hp = Histlist.Hnext;
1933 if (hp == 0)
1934 return(CC_ERROR);
1935
1936 c_hsetpat(); /* Set search pattern !! */
1937
1938 for (h = 1; h < Hist_num && hp; h++) {
1939 Char *hl;
1940 if (hp->histline == NULL)
1941 hp->histline = sprlex(&hp->Hlex);
1942 if (HistLit)
1943 hl = hp->histline;
1944 else {
1945 hl = sprlex(&hp->Hlex);
1946 cleanup_push(hl, xfree);
1947 }
1948 #ifdef SDEBUG
1949 xprintf("Comparing with \"%S\"\n", hl);
1950 #endif
1951 if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1952 hl[LastChar-InputBuf]) && c_hmatch(hl))
1953 found = h;
1954 if (!HistLit)
1955 cleanup_until(hl);
1956 hp = hp->Hnext;
1957 }
1958
1959 if (!found) { /* is it the current history number? */
1960 if (!c_hmatch(HistBuf.s)) {
1961 #ifdef SDEBUG
1962 xprintf("not found\n");
1963 #endif
1964 return(CC_ERROR);
1965 }
1966 }
1967
1968 Hist_num = found;
1969
1970 return(GetHistLine());
1971 }
1972
1973 /*ARGSUSED*/
1974 CCRETVAL
e_helpme(Char c)1975 e_helpme(Char c)
1976 {
1977 USE(c);
1978 PastBottom();
1979 *LastChar = '\0'; /* just in case */
1980 return(CC_HELPME);
1981 }
1982
1983 /*ARGSUSED*/
1984 CCRETVAL
e_correct(Char c)1985 e_correct(Char c)
1986 {
1987 USE(c);
1988 *LastChar = '\0'; /* just in case */
1989 return(CC_CORRECT);
1990 }
1991
1992 /*ARGSUSED*/
1993 CCRETVAL
e_correctl(Char c)1994 e_correctl(Char c)
1995 {
1996 USE(c);
1997 *LastChar = '\0'; /* just in case */
1998 return(CC_CORRECT_L);
1999 }
2000
2001 /*ARGSUSED*/
2002 CCRETVAL
e_run_fg_editor(Char c)2003 e_run_fg_editor(Char c)
2004 {
2005 struct process *pp;
2006
2007 USE(c);
2008 if ((pp = find_stop_ed()) != NULL) {
2009 /* save our editor state so we can restore it */
2010 c_save_inputbuf();
2011 Hist_num = 0; /* for the history commands */
2012
2013 /* put the tty in a sane mode */
2014 PastBottom();
2015 (void) Cookedmode(); /* make sure the tty is set up correctly */
2016
2017 /* do it! */
2018 fg_proc_entry(pp);
2019
2020 (void) Rawmode(); /* go on */
2021 Refresh();
2022 RestoreSaved = 0;
2023 HistSaved = 0;
2024 }
2025 return(CC_NORM);
2026 }
2027
2028 /*ARGSUSED*/
2029 CCRETVAL
e_list_choices(Char c)2030 e_list_choices(Char c)
2031 {
2032 USE(c);
2033 PastBottom();
2034 *LastChar = '\0'; /* just in case */
2035 return(CC_LIST_CHOICES);
2036 }
2037
2038 /*ARGSUSED*/
2039 CCRETVAL
e_list_all(Char c)2040 e_list_all(Char c)
2041 {
2042 USE(c);
2043 PastBottom();
2044 *LastChar = '\0'; /* just in case */
2045 return(CC_LIST_ALL);
2046 }
2047
2048 /*ARGSUSED*/
2049 CCRETVAL
e_list_glob(Char c)2050 e_list_glob(Char c)
2051 {
2052 USE(c);
2053 PastBottom();
2054 *LastChar = '\0'; /* just in case */
2055 return(CC_LIST_GLOB);
2056 }
2057
2058 /*ARGSUSED*/
2059 CCRETVAL
e_expand_glob(Char c)2060 e_expand_glob(Char c)
2061 {
2062 USE(c);
2063 *LastChar = '\0'; /* just in case */
2064 return(CC_EXPAND_GLOB);
2065 }
2066
2067 /*ARGSUSED*/
2068 CCRETVAL
e_normalize_path(Char c)2069 e_normalize_path(Char c)
2070 {
2071 USE(c);
2072 *LastChar = '\0'; /* just in case */
2073 return(CC_NORMALIZE_PATH);
2074 }
2075
2076 /*ARGSUSED*/
2077 CCRETVAL
e_normalize_command(Char c)2078 e_normalize_command(Char c)
2079 {
2080 USE(c);
2081 *LastChar = '\0'; /* just in case */
2082 return(CC_NORMALIZE_COMMAND);
2083 }
2084
2085 /*ARGSUSED*/
2086 CCRETVAL
e_expand_vars(Char c)2087 e_expand_vars(Char c)
2088 {
2089 USE(c);
2090 *LastChar = '\0'; /* just in case */
2091 return(CC_EXPAND_VARS);
2092 }
2093
2094 /*ARGSUSED*/
2095 CCRETVAL
e_which(Char c)2096 e_which(Char c)
2097 { /* do a fast command line which(1) */
2098 USE(c);
2099 c_save_inputbuf();
2100 Hist_num = 0; /* for the history commands */
2101 PastBottom();
2102 *LastChar = '\0'; /* just in case */
2103 return(CC_WHICH);
2104 }
2105
2106 /*ARGSUSED*/
2107 CCRETVAL
e_last_item(Char c)2108 e_last_item(Char c)
2109 { /* insert the last element of the prev. cmd */
2110 struct Hist *hp;
2111 struct wordent *wp, *firstp;
2112 int i;
2113 Char *expanded;
2114
2115 USE(c);
2116 if (Argument <= 0)
2117 return(CC_ERROR);
2118
2119 hp = Histlist.Hnext;
2120 if (hp == NULL) { /* this is only if no history */
2121 return(CC_ERROR);
2122 }
2123
2124 wp = (hp->Hlex).prev;
2125
2126 if (wp->prev == (struct wordent *) NULL)
2127 return(CC_ERROR); /* an empty history entry */
2128
2129 firstp = (hp->Hlex).next;
2130
2131 /* back up arg words in lex */
2132 for (i = 0; i < Argument && wp != firstp; i++) {
2133 wp = wp->prev;
2134 }
2135
2136 expanded = expand_lex(wp->prev, 0, i - 1);
2137 if (InsertStr(expanded)) {
2138 xfree(expanded);
2139 return(CC_ERROR);
2140 }
2141
2142 xfree(expanded);
2143 return(CC_REFRESH);
2144 }
2145
2146 /*ARGSUSED*/
2147 CCRETVAL
e_dabbrev_expand(Char c)2148 e_dabbrev_expand(Char c)
2149 { /* expand to preceding word matching prefix */
2150 Char *cp, *ncp, *bp;
2151 struct Hist *hp;
2152 int arg = 0, i;
2153 size_t len = 0;
2154 int found = 0;
2155 Char *hbuf;
2156 static int oldevent, hist, word;
2157 static Char *start, *oldcursor;
2158
2159 USE(c);
2160 if (Argument <= 0)
2161 return(CC_ERROR);
2162
2163 cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
2164 if (cp == Cursor || Isspace(*cp))
2165 return(CC_ERROR);
2166
2167 hbuf = NULL;
2168 hp = Histlist.Hnext;
2169 bp = InputBuf;
2170 if (Argument == 1 && eventno == oldevent && cp == start &&
2171 Cursor == oldcursor && patbuf.len > 0
2172 && Strncmp(patbuf.s, cp, patbuf.len) == 0){
2173 /* continue previous search - go to last match (hist/word) */
2174 if (hist != 0) { /* need to move up history */
2175 for (i = 1; i < hist && hp != NULL; i++)
2176 hp = hp->Hnext;
2177 if (hp == NULL) /* "can't happen" */
2178 goto err_hbuf;
2179 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2180 cp = Strend(hbuf);
2181 bp = hbuf;
2182 hp = hp->Hnext;
2183 }
2184 cp = c_preword(cp, bp, word, STRshwordsep);
2185 } else { /* starting new search */
2186 oldevent = eventno;
2187 start = cp;
2188 patbuf.len = 0;
2189 Strbuf_appendn(&patbuf, cp, Cursor - cp);
2190 hist = 0;
2191 word = 0;
2192 }
2193
2194 while (!found) {
2195 ncp = c_preword(cp, bp, 1, STRshwordsep);
2196 if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2197 hist++;
2198 word = 0;
2199 if (hp == NULL)
2200 goto err_hbuf;
2201 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2202 cp = Strend(hbuf);
2203 bp = hbuf;
2204 hp = hp->Hnext;
2205 continue;
2206 } else {
2207 word++;
2208 len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
2209 cp = ncp;
2210 }
2211 if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
2212 /* We don't fully check distinct matches as Gnuemacs does: */
2213 if (Argument > 1) { /* just count matches */
2214 if (++arg >= Argument)
2215 found++;
2216 } else { /* match if distinct from previous */
2217 if (len != (size_t)(Cursor - start)
2218 || Strncmp(cp, start, len) != 0)
2219 found++;
2220 }
2221 }
2222 }
2223
2224 if (LastChar + len - (Cursor - start) >= InputLim)
2225 goto err_hbuf; /* no room */
2226 DeleteBack(Cursor - start);
2227 c_insert(len);
2228 while (len--)
2229 *Cursor++ = *cp++;
2230 oldcursor = Cursor;
2231 xfree(hbuf);
2232 return(CC_REFRESH);
2233
2234 err_hbuf:
2235 xfree(hbuf);
2236 return CC_ERROR;
2237 }
2238
2239 /*ARGSUSED*/
2240 CCRETVAL
e_yank_kill(Char c)2241 e_yank_kill(Char c)
2242 { /* almost like GnuEmacs */
2243 int len;
2244 Char *kp, *cp;
2245
2246 USE(c);
2247 if (KillRingLen == 0) /* nothing killed */
2248 return(CC_ERROR);
2249 len = Strlen(KillRing[YankPos].buf);
2250 if (LastChar + len >= InputLim)
2251 return(CC_ERROR); /* end of buffer space */
2252
2253 /* else */
2254 cp = Cursor; /* for speed */
2255
2256 c_insert(len); /* open the space, */
2257 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2258 *cp++ = *kp;
2259
2260 if (Argument == 1) { /* if no arg */
2261 Mark = Cursor; /* mark at beginning, cursor at end */
2262 Cursor = cp;
2263 } else {
2264 Mark = cp; /* else cursor at beginning, mark at end */
2265 }
2266
2267 if (adrof(STRhighlight) && MarkIsSet) {
2268 ClearLines();
2269 ClearDisp();
2270 }
2271 MarkIsSet = 0;
2272 return(CC_REFRESH);
2273 }
2274
2275 /*ARGSUSED*/
2276 CCRETVAL
e_yank_pop(Char c)2277 e_yank_pop(Char c)
2278 { /* almost like GnuEmacs */
2279 int m_bef_c, del_len, ins_len;
2280 Char *kp, *cp;
2281
2282 USE(c);
2283
2284 #if 0
2285 /* XXX This "should" be here, but doesn't work, since LastCmd
2286 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2287 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2288 second one will "succeed" even if the first one wasn't preceded
2289 by a yank, and giving an argument is impossible. Now we "succeed"
2290 regardless of previous command, which is wrong too of course. */
2291 if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
2292 return(CC_ERROR);
2293 #endif
2294
2295 if (KillRingLen == 0) /* nothing killed */
2296 return(CC_ERROR);
2297 YankPos -= Argument;
2298 while (YankPos < 0)
2299 YankPos += KillRingLen;
2300 YankPos %= KillRingLen;
2301
2302 if (Cursor > Mark) {
2303 del_len = Cursor - Mark;
2304 m_bef_c = 1;
2305 } else {
2306 del_len = Mark - Cursor;
2307 m_bef_c = 0;
2308 }
2309 ins_len = Strlen(KillRing[YankPos].buf);
2310 if (LastChar + ins_len - del_len >= InputLim)
2311 return(CC_ERROR); /* end of buffer space */
2312
2313 if (m_bef_c) {
2314 c_delbefore(del_len);
2315 } else {
2316 c_delafter(del_len);
2317 }
2318 cp = Cursor; /* for speed */
2319
2320 c_insert(ins_len); /* open the space, */
2321 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2322 *cp++ = *kp;
2323
2324 if (m_bef_c) {
2325 Mark = Cursor; /* mark at beginning, cursor at end */
2326 Cursor = cp;
2327 } else {
2328 Mark = cp; /* else cursor at beginning, mark at end */
2329 }
2330
2331 if (adrof(STRhighlight) && MarkIsSet) {
2332 ClearLines();
2333 ClearDisp();
2334 }
2335 MarkIsSet = 0;
2336 return(CC_REFRESH);
2337 }
2338
2339 /*ARGSUSED*/
2340 CCRETVAL
v_delprev(Char c)2341 v_delprev(Char c) /* Backspace key in insert mode */
2342 {
2343 int rc;
2344
2345 USE(c);
2346 rc = CC_ERROR;
2347
2348 if (InsertPos != 0) {
2349 if (Argument <= Cursor - InsertPos) {
2350 c_delbefore(Argument); /* delete before */
2351 rc = CC_REFRESH;
2352 }
2353 }
2354 return(rc);
2355 } /* v_delprev */
2356
2357 /*ARGSUSED*/
2358 CCRETVAL
e_delprev(Char c)2359 e_delprev(Char c)
2360 {
2361 USE(c);
2362 if (Cursor > InputBuf) {
2363 c_delbefore(Argument); /* delete before dot */
2364 return(CC_REFRESH);
2365 }
2366 else {
2367 return(CC_ERROR);
2368 }
2369 }
2370
2371 /*ARGSUSED*/
2372 CCRETVAL
e_delwordprev(Char c)2373 e_delwordprev(Char c)
2374 {
2375 Char *cp;
2376
2377 USE(c);
2378 if (Cursor == InputBuf)
2379 return(CC_ERROR);
2380 /* else */
2381
2382 cp = c_prev_word(Cursor, InputBuf, Argument);
2383
2384 c_push_kill(cp, Cursor); /* save the text */
2385
2386 c_delbefore((int)(Cursor - cp)); /* delete before dot */
2387 return(CC_REFRESH);
2388 }
2389
2390 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2391 *
2392 * Changed the names of some of the ^D family of editor functions to
2393 * correspond to what they actually do and created new e_delnext_list
2394 * for completeness.
2395 *
2396 * Old names: New names:
2397 *
2398 * delete-char delete-char-or-eof
2399 * F_DELNEXT F_DELNEXT_EOF
2400 * e_delnext e_delnext_eof
2401 * edelnxt edelnxteof
2402 * delete-char-or-eof delete-char
2403 * F_DELNEXT_EOF F_DELNEXT
2404 * e_delnext_eof e_delnext
2405 * edelnxteof edelnxt
2406 * delete-char-or-list delete-char-or-list-or-eof
2407 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
2408 * e_list_delnext e_delnext_list_eof
2409 * edellsteof
2410 * (no old equivalent) delete-char-or-list
2411 * F_DELNEXT_LIST
2412 * e_delnext_list
2413 * e_delnxtlst
2414 */
2415
2416 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2417 /* rename e_delnext() -> e_delnext_eof() */
2418 /*ARGSUSED*/
2419 CCRETVAL
e_delnext(Char c)2420 e_delnext(Char c)
2421 {
2422 USE(c);
2423 if (Cursor == LastChar) {/* if I'm at the end */
2424 if (!VImode) {
2425 return(CC_ERROR);
2426 }
2427 else {
2428 if (Cursor != InputBuf)
2429 Cursor--;
2430 else
2431 return(CC_ERROR);
2432 }
2433 }
2434 c_delafter(Argument); /* delete after dot */
2435 if (Cursor > LastChar)
2436 Cursor = LastChar; /* bounds check */
2437 return(CC_REFRESH);
2438 }
2439
2440
2441 /*ARGSUSED*/
2442 CCRETVAL
e_delnext_eof(Char c)2443 e_delnext_eof(Char c)
2444 {
2445 USE(c);
2446 if (Cursor == LastChar) {/* if I'm at the end */
2447 if (!VImode) {
2448 if (Cursor == InputBuf) {
2449 /* if I'm also at the beginning */
2450 so_write(STReof, 4);/* then do a EOF */
2451 flush();
2452 return(CC_EOF);
2453 }
2454 else
2455 return(CC_ERROR);
2456 }
2457 else {
2458 if (Cursor != InputBuf)
2459 Cursor--;
2460 else
2461 return(CC_ERROR);
2462 }
2463 }
2464 c_delafter(Argument); /* delete after dot */
2465 if (Cursor > LastChar)
2466 Cursor = LastChar; /* bounds check */
2467 return(CC_REFRESH);
2468 }
2469
2470 /*ARGSUSED*/
2471 CCRETVAL
e_delnext_list(Char c)2472 e_delnext_list(Char c)
2473 {
2474 USE(c);
2475 if (Cursor == LastChar) { /* if I'm at the end */
2476 PastBottom();
2477 *LastChar = '\0'; /* just in case */
2478 return(CC_LIST_CHOICES);
2479 }
2480 else {
2481 c_delafter(Argument); /* delete after dot */
2482 if (Cursor > LastChar)
2483 Cursor = LastChar; /* bounds check */
2484 return(CC_REFRESH);
2485 }
2486 }
2487
2488 /*ARGSUSED*/
2489 CCRETVAL
e_delnext_list_eof(Char c)2490 e_delnext_list_eof(Char c)
2491 {
2492 USE(c);
2493 if (Cursor == LastChar) { /* if I'm at the end */
2494 if (Cursor == InputBuf) { /* if I'm also at the beginning */
2495 so_write(STReof, 4);/* then do a EOF */
2496 flush();
2497 return(CC_EOF);
2498 }
2499 else {
2500 PastBottom();
2501 *LastChar = '\0'; /* just in case */
2502 return(CC_LIST_CHOICES);
2503 }
2504 }
2505 else {
2506 c_delafter(Argument); /* delete after dot */
2507 if (Cursor > LastChar)
2508 Cursor = LastChar; /* bounds check */
2509 return(CC_REFRESH);
2510 }
2511 }
2512
2513 /*ARGSUSED*/
2514 CCRETVAL
e_list_eof(Char c)2515 e_list_eof(Char c)
2516 {
2517 CCRETVAL rv;
2518
2519 USE(c);
2520 if (Cursor == LastChar && Cursor == InputBuf) {
2521 so_write(STReof, 4); /* then do a EOF */
2522 flush();
2523 rv = CC_EOF;
2524 }
2525 else {
2526 PastBottom();
2527 *LastChar = '\0'; /* just in case */
2528 rv = CC_LIST_CHOICES;
2529 }
2530 return rv;
2531 }
2532
2533 /*ARGSUSED*/
2534 CCRETVAL
e_delwordnext(Char c)2535 e_delwordnext(Char c)
2536 {
2537 Char *cp;
2538
2539 USE(c);
2540 if (Cursor == LastChar)
2541 return(CC_ERROR);
2542 /* else */
2543
2544 cp = c_next_word(Cursor, LastChar, Argument);
2545
2546 c_push_kill(Cursor, cp); /* save the text */
2547
2548 c_delafter((int)(cp - Cursor)); /* delete after dot */
2549 if (Cursor > LastChar)
2550 Cursor = LastChar; /* bounds check */
2551 return(CC_REFRESH);
2552 }
2553
2554 /*ARGSUSED*/
2555 CCRETVAL
e_toend(Char c)2556 e_toend(Char c)
2557 {
2558 USE(c);
2559 Cursor = LastChar;
2560 if (VImode)
2561 if (ActionFlag & TCSHOP_DELETE) {
2562 c_delfini();
2563 return(CC_REFRESH);
2564 }
2565 RefCursor(); /* move the cursor */
2566 return(CC_NORM);
2567 }
2568
2569 /*ARGSUSED*/
2570 CCRETVAL
e_tobeg(Char c)2571 e_tobeg(Char c)
2572 {
2573 USE(c);
2574 Cursor = InputBuf;
2575
2576 if (VImode) {
2577 while (Isspace(*Cursor)) /* We want FIRST non space character */
2578 Cursor++;
2579 if (ActionFlag & TCSHOP_DELETE) {
2580 c_delfini();
2581 return(CC_REFRESH);
2582 }
2583 }
2584
2585 RefCursor(); /* move the cursor */
2586 return(CC_NORM);
2587 }
2588
2589 /*ARGSUSED*/
2590 CCRETVAL
e_killend(Char c)2591 e_killend(Char c)
2592 {
2593 USE(c);
2594 c_push_kill(Cursor, LastChar); /* copy it */
2595 LastChar = Cursor; /* zap! -- delete to end */
2596 if (Mark > Cursor)
2597 Mark = Cursor;
2598 MarkIsSet = 0;
2599 return(CC_REFRESH);
2600 }
2601
2602
2603 /*ARGSUSED*/
2604 CCRETVAL
e_killbeg(Char c)2605 e_killbeg(Char c)
2606 {
2607 USE(c);
2608 c_push_kill(InputBuf, Cursor); /* copy it */
2609 c_delbefore((int)(Cursor - InputBuf));
2610 if (Mark && Mark > Cursor)
2611 Mark -= Cursor-InputBuf;
2612 return(CC_REFRESH);
2613 }
2614
2615 /*ARGSUSED*/
2616 CCRETVAL
e_killall(Char c)2617 e_killall(Char c)
2618 {
2619 USE(c);
2620 c_push_kill(InputBuf, LastChar); /* copy it */
2621 Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */
2622 MarkIsSet = 0;
2623 return(CC_REFRESH);
2624 }
2625
2626 /*ARGSUSED*/
2627 CCRETVAL
e_killregion(Char c)2628 e_killregion(Char c)
2629 {
2630 USE(c);
2631 if (!Mark)
2632 return(CC_ERROR);
2633
2634 if (Mark > Cursor) {
2635 c_push_kill(Cursor, Mark); /* copy it */
2636 c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
2637 Mark = Cursor;
2638 }
2639 else { /* mark is before cursor */
2640 c_push_kill(Mark, Cursor); /* copy it */
2641 c_delbefore((int)(Cursor - Mark));
2642 }
2643 if (adrof(STRhighlight) && MarkIsSet) {
2644 ClearLines();
2645 ClearDisp();
2646 }
2647 MarkIsSet = 0;
2648 return(CC_REFRESH);
2649 }
2650
2651 /*ARGSUSED*/
2652 CCRETVAL
e_copyregion(Char c)2653 e_copyregion(Char c)
2654 {
2655 USE(c);
2656 if (!Mark)
2657 return(CC_ERROR);
2658
2659 if (Mark > Cursor) {
2660 c_push_kill(Cursor, Mark); /* copy it */
2661 }
2662 else { /* mark is before cursor */
2663 c_push_kill(Mark, Cursor); /* copy it */
2664 }
2665 return(CC_NORM); /* don't even need to Refresh() */
2666 }
2667
2668 /*ARGSUSED*/
2669 CCRETVAL
e_charswitch(Char cc)2670 e_charswitch(Char cc)
2671 {
2672 Char c;
2673
2674 USE(cc);
2675
2676 /* do nothing if we are at beginning of line or have only one char */
2677 if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
2678 return(CC_ERROR);
2679 }
2680
2681 if (Cursor < LastChar) {
2682 Cursor++;
2683 }
2684 c = Cursor[-2];
2685 Cursor[-2] = Cursor[-1];
2686 Cursor[-1] = c;
2687 return(CC_REFRESH);
2688 }
2689
2690 /*ARGSUSED*/
2691 CCRETVAL
e_gcharswitch(Char cc)2692 e_gcharswitch(Char cc)
2693 { /* gosmacs style ^T */
2694 Char c;
2695
2696 USE(cc);
2697 if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
2698 c = Cursor[-2];
2699 Cursor[-2] = Cursor[-1];
2700 Cursor[-1] = c;
2701 return(CC_REFRESH);
2702 }
2703 else {
2704 return(CC_ERROR);
2705 }
2706 }
2707
2708 /*ARGSUSED*/
2709 CCRETVAL
e_charback(Char c)2710 e_charback(Char c)
2711 {
2712 USE(c);
2713 if (Cursor > InputBuf) {
2714 if (Argument > Cursor - InputBuf)
2715 Cursor = InputBuf;
2716 else
2717 Cursor -= Argument;
2718
2719 if (VImode)
2720 if (ActionFlag & TCSHOP_DELETE) {
2721 c_delfini();
2722 return(CC_REFRESH);
2723 }
2724
2725 RefCursor();
2726 return(CC_NORM);
2727 }
2728 else {
2729 return(CC_ERROR);
2730 }
2731 }
2732
2733 /*ARGSUSED*/
2734 CCRETVAL
v_wordback(Char c)2735 v_wordback(Char c)
2736 {
2737 USE(c);
2738 if (Cursor == InputBuf)
2739 return(CC_ERROR);
2740 /* else */
2741
2742 Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
2743
2744 if (ActionFlag & TCSHOP_DELETE) {
2745 c_delfini();
2746 return(CC_REFRESH);
2747 }
2748
2749 RefCursor();
2750 return(CC_NORM);
2751 }
2752
2753 /*ARGSUSED*/
2754 CCRETVAL
e_wordback(Char c)2755 e_wordback(Char c)
2756 {
2757 USE(c);
2758 if (Cursor == InputBuf)
2759 return(CC_ERROR);
2760 /* else */
2761
2762 Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
2763
2764 if (VImode)
2765 if (ActionFlag & TCSHOP_DELETE) {
2766 c_delfini();
2767 return(CC_REFRESH);
2768 }
2769
2770 RefCursor();
2771 return(CC_NORM);
2772 }
2773
2774 /*ARGSUSED*/
2775 CCRETVAL
e_charfwd(Char c)2776 e_charfwd(Char c)
2777 {
2778 USE(c);
2779 if (Cursor < LastChar) {
2780 Cursor += Argument;
2781 if (Cursor > LastChar)
2782 Cursor = LastChar;
2783
2784 if (VImode)
2785 if (ActionFlag & TCSHOP_DELETE) {
2786 c_delfini();
2787 return(CC_REFRESH);
2788 }
2789
2790 RefCursor();
2791 return(CC_NORM);
2792 }
2793 else {
2794 return(CC_ERROR);
2795 }
2796 }
2797
2798 /*ARGSUSED*/
2799 CCRETVAL
e_wordfwd(Char c)2800 e_wordfwd(Char c)
2801 {
2802 USE(c);
2803 if (Cursor == LastChar)
2804 return(CC_ERROR);
2805 /* else */
2806
2807 Cursor = c_next_word(Cursor, LastChar, Argument);
2808
2809 if (VImode)
2810 if (ActionFlag & TCSHOP_DELETE) {
2811 c_delfini();
2812 return(CC_REFRESH);
2813 }
2814
2815 RefCursor();
2816 return(CC_NORM);
2817 }
2818
2819 /*ARGSUSED*/
2820 CCRETVAL
v_wordfwd(Char c)2821 v_wordfwd(Char c)
2822 {
2823 USE(c);
2824 if (Cursor == LastChar)
2825 return(CC_ERROR);
2826 /* else */
2827
2828 Cursor = c_nexword(Cursor, LastChar, Argument);
2829
2830 if (VImode)
2831 if (ActionFlag & TCSHOP_DELETE) {
2832 c_delfini();
2833 return(CC_REFRESH);
2834 }
2835
2836 RefCursor();
2837 return(CC_NORM);
2838 }
2839
2840 /*ARGSUSED*/
2841 CCRETVAL
v_wordbegnext(Char c)2842 v_wordbegnext(Char c)
2843 {
2844 USE(c);
2845 if (Cursor == LastChar)
2846 return(CC_ERROR);
2847 /* else */
2848
2849 Cursor = c_next_word(Cursor, LastChar, Argument);
2850 if (Cursor < LastChar)
2851 Cursor++;
2852
2853 if (VImode)
2854 if (ActionFlag & TCSHOP_DELETE) {
2855 c_delfini();
2856 return(CC_REFRESH);
2857 }
2858
2859 RefCursor();
2860 return(CC_NORM);
2861 }
2862
2863 /*ARGSUSED*/
2864 static CCRETVAL
v_repeat_srch(int c)2865 v_repeat_srch(int c)
2866 {
2867 CCRETVAL rv = CC_ERROR;
2868 #ifdef SDEBUG
2869 xprintf("dir %d patlen %d patbuf %S\n",
2870 c, (int)patbuf.len, patbuf.s);
2871 #endif
2872
2873 LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */
2874 LastChar = InputBuf;
2875 switch (c) {
2876 case F_DOWN_SEARCH_HIST:
2877 rv = e_down_search_hist(0);
2878 break;
2879 case F_UP_SEARCH_HIST:
2880 rv = e_up_search_hist(0);
2881 break;
2882 default:
2883 break;
2884 }
2885 return rv;
2886 }
2887
2888 static CCRETVAL
v_csearch_back(Char ch,int count,int tflag)2889 v_csearch_back(Char ch, int count, int tflag)
2890 {
2891 Char *cp;
2892
2893 cp = Cursor;
2894 while (count--) {
2895 if (*cp == ch)
2896 cp--;
2897 while (cp > InputBuf && *cp != ch)
2898 cp--;
2899 }
2900
2901 if (cp < InputBuf || (cp == InputBuf && *cp != ch))
2902 return(CC_ERROR);
2903
2904 if (*cp == ch && tflag)
2905 cp++;
2906
2907 Cursor = cp;
2908
2909 if (ActionFlag & TCSHOP_DELETE) {
2910 Cursor++;
2911 c_delfini();
2912 return(CC_REFRESH);
2913 }
2914
2915 RefCursor();
2916 return(CC_NORM);
2917 }
2918
2919 static CCRETVAL
v_csearch_fwd(Char ch,int count,int tflag)2920 v_csearch_fwd(Char ch, int count, int tflag)
2921 {
2922 Char *cp;
2923
2924 cp = Cursor;
2925 while (count--) {
2926 if (*cp == ch)
2927 cp++;
2928 while (cp < LastChar && *cp != ch)
2929 cp++;
2930 }
2931
2932 if (cp >= LastChar)
2933 return(CC_ERROR);
2934
2935 if (*cp == ch && tflag)
2936 cp--;
2937
2938 Cursor = cp;
2939
2940 if (ActionFlag & TCSHOP_DELETE) {
2941 Cursor++;
2942 c_delfini();
2943 return(CC_REFRESH);
2944 }
2945 RefCursor();
2946 return(CC_NORM);
2947 }
2948
2949 /*ARGSUSED*/
2950 static CCRETVAL
v_action(int c)2951 v_action(int c)
2952 {
2953 Char *cp, *kp;
2954
2955 if (ActionFlag == TCSHOP_DELETE) {
2956 ActionFlag = TCSHOP_NOP;
2957 ActionPos = 0;
2958
2959 UndoSize = 0;
2960 kp = UndoBuf;
2961 for (cp = InputBuf; cp < LastChar; cp++) {
2962 *kp++ = *cp;
2963 UndoSize++;
2964 }
2965
2966 UndoAction = TCSHOP_INSERT;
2967 UndoPtr = InputBuf;
2968 LastChar = InputBuf;
2969 Cursor = InputBuf;
2970 if (c & TCSHOP_INSERT)
2971 c_alternativ_key_map(0);
2972
2973 return(CC_REFRESH);
2974 }
2975 #ifdef notdef
2976 else if (ActionFlag == TCSHOP_NOP) {
2977 #endif
2978 ActionPos = Cursor;
2979 ActionFlag = c;
2980 return(CC_ARGHACK); /* Do NOT clear out argument */
2981 #ifdef notdef
2982 }
2983 else {
2984 ActionFlag = 0;
2985 ActionPos = 0;
2986 return(CC_ERROR);
2987 }
2988 #endif
2989 }
2990
2991 #ifdef COMMENT
2992 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2993 static void
c_get_word(Char ** begin,Char ** end)2994 c_get_word(Char **begin, Char **end)
2995 {
2996 Char *cp;
2997
2998 cp = &Cursor[0];
2999 while (Argument--) {
3000 while ((cp <= LastChar) && (isword(*cp)))
3001 cp++;
3002 *end = --cp;
3003 while ((cp >= InputBuf) && (isword(*cp)))
3004 cp--;
3005 *begin = ++cp;
3006 }
3007 }
3008 #endif /* COMMENT */
3009
3010 /*ARGSUSED*/
3011 CCRETVAL
e_uppercase(Char c)3012 e_uppercase(Char c)
3013 {
3014 Char *cp, *end;
3015
3016 USE(c);
3017 end = c_next_word(Cursor, LastChar, Argument);
3018
3019 for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */
3020 if (Islower(*cp))
3021 *cp = Toupper(*cp);
3022
3023 Cursor = end;
3024 if (Cursor > LastChar)
3025 Cursor = LastChar;
3026 return(CC_REFRESH);
3027 }
3028
3029
3030 /*ARGSUSED*/
3031 CCRETVAL
e_capitalcase(Char c)3032 e_capitalcase(Char c)
3033 {
3034 Char *cp, *end;
3035
3036 USE(c);
3037 end = c_next_word(Cursor, LastChar, Argument);
3038
3039 cp = Cursor;
3040 for (; cp < end; cp++) {
3041 if (Isalpha(*cp)) {
3042 if (Islower(*cp))
3043 *cp = Toupper(*cp);
3044 cp++;
3045 break;
3046 }
3047 }
3048 for (; cp < end; cp++)
3049 if (Isupper(*cp))
3050 *cp = Tolower(*cp);
3051
3052 Cursor = end;
3053 if (Cursor > LastChar)
3054 Cursor = LastChar;
3055 return(CC_REFRESH);
3056 }
3057
3058 /*ARGSUSED*/
3059 CCRETVAL
e_lowercase(Char c)3060 e_lowercase(Char c)
3061 {
3062 Char *cp, *end;
3063
3064 USE(c);
3065 end = c_next_word(Cursor, LastChar, Argument);
3066
3067 for (cp = Cursor; cp < end; cp++)
3068 if (Isupper(*cp))
3069 *cp = Tolower(*cp);
3070
3071 Cursor = end;
3072 if (Cursor > LastChar)
3073 Cursor = LastChar;
3074 return(CC_REFRESH);
3075 }
3076
3077
3078 /*ARGSUSED*/
3079 CCRETVAL
e_set_mark(Char c)3080 e_set_mark(Char c)
3081 {
3082 USE(c);
3083 if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
3084 ClearLines();
3085 ClearDisp();
3086 Refresh();
3087 }
3088 Mark = Cursor;
3089 MarkIsSet = 1;
3090 return(CC_NORM);
3091 }
3092
3093 /*ARGSUSED*/
3094 CCRETVAL
e_exchange_mark(Char c)3095 e_exchange_mark(Char c)
3096 {
3097 Char *cp;
3098
3099 USE(c);
3100 cp = Cursor;
3101 Cursor = Mark;
3102 Mark = cp;
3103 RefCursor();
3104 return(CC_NORM);
3105 }
3106
3107 /*ARGSUSED*/
3108 CCRETVAL
e_argfour(Char c)3109 e_argfour(Char c)
3110 { /* multiply current argument by 4 */
3111 USE(c);
3112 if (Argument > 1000000)
3113 return CC_ERROR;
3114 DoingArg = 1;
3115 Argument *= 4;
3116 return(CC_ARGHACK);
3117 }
3118
3119 static void
quote_mode_cleanup(void * unused)3120 quote_mode_cleanup(void *unused)
3121 {
3122 USE(unused);
3123 QuoteModeOff();
3124 }
3125
3126 /*ARGSUSED*/
3127 CCRETVAL
e_quote(Char c)3128 e_quote(Char c)
3129 {
3130 Char ch;
3131 int num;
3132
3133 USE(c);
3134 QuoteModeOn();
3135 cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
3136 num = GetNextChar(&ch);
3137 cleanup_until(&c);
3138 if (num == 1)
3139 return e_insert(ch);
3140 else
3141 return e_send_eof(0);
3142 }
3143
3144 /*ARGSUSED*/
3145 CCRETVAL
e_metanext(Char c)3146 e_metanext(Char c)
3147 {
3148 USE(c);
3149 MetaNext = 1;
3150 return(CC_ARGHACK); /* preserve argument */
3151 }
3152
3153 #ifdef notdef
3154 /*ARGSUSED*/
3155 CCRETVAL
e_extendnext(Char c)3156 e_extendnext(Char c)
3157 {
3158 CurrentKeyMap = CcAltMap;
3159 return(CC_ARGHACK); /* preserve argument */
3160 }
3161
3162 #endif
3163
3164 /*ARGSUSED*/
3165 CCRETVAL
v_insbeg(Char c)3166 v_insbeg(Char c)
3167 { /* move to beginning of line and start vi
3168 * insert mode */
3169 USE(c);
3170 Cursor = InputBuf;
3171 InsertPos = Cursor;
3172
3173 UndoPtr = Cursor;
3174 UndoAction = TCSHOP_DELETE;
3175
3176 RefCursor(); /* move the cursor */
3177 c_alternativ_key_map(0);
3178 return(CC_NORM);
3179 }
3180
3181 /*ARGSUSED*/
3182 CCRETVAL
v_replone(Char c)3183 v_replone(Char c)
3184 { /* vi mode overwrite one character */
3185 USE(c);
3186 c_alternativ_key_map(0);
3187 inputmode = MODE_REPLACE_1;
3188 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3189 UndoPtr = Cursor;
3190 UndoSize = 0;
3191 return(CC_NORM);
3192 }
3193
3194 /*ARGSUSED*/
3195 CCRETVAL
v_replmode(Char c)3196 v_replmode(Char c)
3197 { /* vi mode start overwriting */
3198 USE(c);
3199 c_alternativ_key_map(0);
3200 inputmode = MODE_REPLACE;
3201 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3202 UndoPtr = Cursor;
3203 UndoSize = 0;
3204 return(CC_NORM);
3205 }
3206
3207 /*ARGSUSED*/
3208 CCRETVAL
v_substchar(Char c)3209 v_substchar(Char c)
3210 { /* vi mode substitute for one char */
3211 USE(c);
3212 c_delafter(Argument);
3213 c_alternativ_key_map(0);
3214 return(CC_REFRESH);
3215 }
3216
3217 /*ARGSUSED*/
3218 CCRETVAL
v_substline(Char c)3219 v_substline(Char c)
3220 { /* vi mode replace whole line */
3221 USE(c);
3222 (void) e_killall(0);
3223 c_alternativ_key_map(0);
3224 return(CC_REFRESH);
3225 }
3226
3227 /*ARGSUSED*/
3228 CCRETVAL
v_chgtoend(Char c)3229 v_chgtoend(Char c)
3230 { /* vi mode change to end of line */
3231 USE(c);
3232 (void) e_killend(0);
3233 c_alternativ_key_map(0);
3234 return(CC_REFRESH);
3235 }
3236
3237 /*ARGSUSED*/
3238 CCRETVAL
v_insert(Char c)3239 v_insert(Char c)
3240 { /* vi mode start inserting */
3241 USE(c);
3242 c_alternativ_key_map(0);
3243
3244 InsertPos = Cursor;
3245 UndoPtr = Cursor;
3246 UndoAction = TCSHOP_DELETE;
3247
3248 return(CC_NORM);
3249 }
3250
3251 /*ARGSUSED*/
3252 CCRETVAL
v_add(Char c)3253 v_add(Char c)
3254 { /* vi mode start adding */
3255 USE(c);
3256 c_alternativ_key_map(0);
3257 if (Cursor < LastChar)
3258 {
3259 Cursor++;
3260 if (Cursor > LastChar)
3261 Cursor = LastChar;
3262 RefCursor();
3263 }
3264
3265 InsertPos = Cursor;
3266 UndoPtr = Cursor;
3267 UndoAction = TCSHOP_DELETE;
3268
3269 return(CC_NORM);
3270 }
3271
3272 /*ARGSUSED*/
3273 CCRETVAL
v_addend(Char c)3274 v_addend(Char c)
3275 { /* vi mode to add at end of line */
3276 USE(c);
3277 c_alternativ_key_map(0);
3278 Cursor = LastChar;
3279
3280 InsertPos = LastChar; /* Mark where insertion begins */
3281 UndoPtr = LastChar;
3282 UndoAction = TCSHOP_DELETE;
3283
3284 RefCursor();
3285 return(CC_NORM);
3286 }
3287
3288 /*ARGSUSED*/
3289 CCRETVAL
v_change_case(Char cc)3290 v_change_case(Char cc)
3291 {
3292 Char c;
3293
3294 USE(cc);
3295 if (Cursor < LastChar) {
3296 #ifndef WINNT_NATIVE
3297 c = *Cursor;
3298 #else
3299 c = CHAR & *Cursor;
3300 #endif /* WINNT_NATIVE */
3301 if (Isupper(c))
3302 *Cursor++ = Tolower(c);
3303 else if (Islower(c))
3304 *Cursor++ = Toupper(c);
3305 else
3306 Cursor++;
3307 RefPlusOne(1); /* fast refresh for one char */
3308 return(CC_NORM);
3309 }
3310 return(CC_ERROR);
3311 }
3312
3313 /*ARGSUSED*/
3314 CCRETVAL
e_expand(Char c)3315 e_expand(Char c)
3316 {
3317 Char *p;
3318
3319 USE(c);
3320 for (p = InputBuf; Isspace(*p); p++)
3321 continue;
3322 if (p == LastChar)
3323 return(CC_ERROR);
3324
3325 justpr++;
3326 Expand++;
3327 return(e_newline(0));
3328 }
3329
3330 /*ARGSUSED*/
3331 CCRETVAL
e_startover(Char c)3332 e_startover(Char c)
3333 { /* erase all of current line, start again */
3334 USE(c);
3335 ResetInLine(0); /* reset the input pointers */
3336 return(CC_REFRESH);
3337 }
3338
3339 /*ARGSUSED*/
3340 CCRETVAL
e_redisp(Char c)3341 e_redisp(Char c)
3342 {
3343 USE(c);
3344 ClearLines();
3345 ClearDisp();
3346 return(CC_REFRESH);
3347 }
3348
3349 /*ARGSUSED*/
3350 CCRETVAL
e_cleardisp(Char c)3351 e_cleardisp(Char c)
3352 {
3353 USE(c);
3354 ClearScreen(); /* clear the whole real screen */
3355 ClearDisp(); /* reset everything */
3356 return(CC_REFRESH);
3357 }
3358
3359 /*ARGSUSED*/
3360 CCRETVAL
e_tty_int(Char c)3361 e_tty_int(Char c)
3362 {
3363 USE(c);
3364 #if defined(_MINIX) || defined(WINNT_NATIVE)
3365 /* SAK PATCH: erase all of current line, start again */
3366 ResetInLine(0); /* reset the input pointers */
3367 xputchar('\n');
3368 ClearDisp();
3369 return (CC_REFRESH);
3370 #else /* !_MINIX && !WINNT_NATIVE */
3371 /* do no editing */
3372 return (CC_NORM);
3373 #endif /* _MINIX || WINNT_NATIVE */
3374 }
3375
3376 /*
3377 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3378 * Function to send a character back to the input stream in cooked
3379 * mode. Only works if we have TIOCSTI
3380 */
3381 /*ARGSUSED*/
3382 CCRETVAL
e_stuff_char(Char c)3383 e_stuff_char(Char c)
3384 {
3385 #ifdef TIOCSTI
3386 int was_raw = Tty_raw_mode;
3387 char buf[MB_LEN_MAX];
3388 size_t i, len;
3389
3390 if (was_raw)
3391 (void) Cookedmode();
3392
3393 (void) xwrite(SHIN, "\n", 1);
3394 len = one_wctomb(buf, c);
3395 for (i = 0; i < len; i++)
3396 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
3397
3398 if (was_raw)
3399 (void) Rawmode();
3400 return(e_redisp(c));
3401 #else /* !TIOCSTI */
3402 return(CC_ERROR);
3403 #endif /* !TIOCSTI */
3404 }
3405
3406 /*ARGSUSED*/
3407 CCRETVAL
e_insovr(Char c)3408 e_insovr(Char c)
3409 {
3410 USE(c);
3411 inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
3412 return(CC_NORM);
3413 }
3414
3415 /*ARGSUSED*/
3416 CCRETVAL
e_tty_dsusp(Char c)3417 e_tty_dsusp(Char c)
3418 {
3419 USE(c);
3420 /* do no editing */
3421 return(CC_NORM);
3422 }
3423
3424 /*ARGSUSED*/
3425 CCRETVAL
e_tty_flusho(Char c)3426 e_tty_flusho(Char c)
3427 {
3428 USE(c);
3429 /* do no editing */
3430 return(CC_NORM);
3431 }
3432
3433 /*ARGSUSED*/
3434 CCRETVAL
e_tty_quit(Char c)3435 e_tty_quit(Char c)
3436 {
3437 USE(c);
3438 /* do no editing */
3439 return(CC_NORM);
3440 }
3441
3442 /*ARGSUSED*/
3443 CCRETVAL
e_tty_tsusp(Char c)3444 e_tty_tsusp(Char c)
3445 {
3446 USE(c);
3447 /* do no editing */
3448 return(CC_NORM);
3449 }
3450
3451 /*ARGSUSED*/
3452 CCRETVAL
e_tty_stopo(Char c)3453 e_tty_stopo(Char c)
3454 {
3455 USE(c);
3456 /* do no editing */
3457 return(CC_NORM);
3458 }
3459
3460 /* returns the number of (attempted) expansions */
3461 int
ExpandHistory(void)3462 ExpandHistory(void)
3463 {
3464 *LastChar = '\0'; /* just in case */
3465 return c_substitute();
3466 }
3467
3468 /*ARGSUSED*/
3469 CCRETVAL
e_expand_history(Char c)3470 e_expand_history(Char c)
3471 {
3472 USE(c);
3473 (void)ExpandHistory();
3474 return(CC_NORM);
3475 }
3476
3477 /*ARGSUSED*/
3478 CCRETVAL
e_magic_space(Char c)3479 e_magic_space(Char c)
3480 {
3481 USE(c);
3482 *LastChar = '\0'; /* just in case */
3483 (void)c_substitute();
3484 return(e_insert(' '));
3485 }
3486
3487 /*ARGSUSED*/
3488 CCRETVAL
e_inc_fwd(Char c)3489 e_inc_fwd(Char c)
3490 {
3491 CCRETVAL ret;
3492
3493 USE(c);
3494 patbuf.len = 0;
3495 MarkIsSet = 0;
3496 ret = e_inc_search(F_DOWN_SEARCH_HIST);
3497 if (adrof(STRhighlight) && IncMatchLen) {
3498 IncMatchLen = 0;
3499 ClearLines();
3500 ClearDisp();
3501 Refresh();
3502 }
3503 IncMatchLen = 0;
3504 return ret;
3505 }
3506
3507
3508 /*ARGSUSED*/
3509 CCRETVAL
e_inc_back(Char c)3510 e_inc_back(Char c)
3511 {
3512 CCRETVAL ret;
3513
3514 USE(c);
3515 patbuf.len = 0;
3516 MarkIsSet = 0;
3517 ret = e_inc_search(F_UP_SEARCH_HIST);
3518 if (adrof(STRhighlight) && IncMatchLen) {
3519 IncMatchLen = 0;
3520 ClearLines();
3521 ClearDisp();
3522 Refresh();
3523 }
3524 IncMatchLen = 0;
3525 return ret;
3526 }
3527
3528 /*ARGSUSED*/
3529 CCRETVAL
e_copyprev(Char c)3530 e_copyprev(Char c)
3531 {
3532 Char *cp, *oldc, *dp;
3533
3534 USE(c);
3535 if (Cursor == InputBuf)
3536 return(CC_ERROR);
3537 /* else */
3538
3539 oldc = Cursor;
3540 /* does a bounds check */
3541 cp = c_prev_word(Cursor, InputBuf, Argument);
3542
3543 c_insert((int)(oldc - cp));
3544 for (dp = oldc; cp < oldc && dp < LastChar; cp++)
3545 *dp++ = *cp;
3546
3547 Cursor = dp; /* put cursor at end */
3548
3549 return(CC_REFRESH);
3550 }
3551
3552 /*ARGSUSED*/
3553 CCRETVAL
e_tty_starto(Char c)3554 e_tty_starto(Char c)
3555 {
3556 USE(c);
3557 /* do no editing */
3558 return(CC_NORM);
3559 }
3560
3561 /*ARGSUSED*/
3562 CCRETVAL
e_load_average(Char c)3563 e_load_average(Char c)
3564 {
3565 USE(c);
3566 PastBottom();
3567 #ifdef TIOCSTAT
3568 /*
3569 * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3570 * there even if they don't use it. (lukem@netbsd.org)
3571 */
3572 if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
3573 #endif
3574 xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
3575 return(CC_REFRESH);
3576 }
3577
3578 /*ARGSUSED*/
3579 CCRETVAL
v_chgmeta(Char c)3580 v_chgmeta(Char c)
3581 {
3582 USE(c);
3583 /*
3584 * Delete with insert == change: first we delete and then we leave in
3585 * insert mode.
3586 */
3587 return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
3588 }
3589
3590 /*ARGSUSED*/
3591 CCRETVAL
v_delmeta(Char c)3592 v_delmeta(Char c)
3593 {
3594 USE(c);
3595 return(v_action(TCSHOP_DELETE));
3596 }
3597
3598
3599 /*ARGSUSED*/
3600 CCRETVAL
v_endword(Char c)3601 v_endword(Char c)
3602 {
3603 USE(c);
3604 if (Cursor == LastChar)
3605 return(CC_ERROR);
3606 /* else */
3607
3608 Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace);
3609
3610 if (ActionFlag & TCSHOP_DELETE)
3611 {
3612 Cursor++;
3613 c_delfini();
3614 return(CC_REFRESH);
3615 }
3616
3617 RefCursor();
3618 return(CC_NORM);
3619 }
3620
3621 /*ARGSUSED*/
3622 CCRETVAL
v_eword(Char c)3623 v_eword(Char c)
3624 {
3625 USE(c);
3626 if (Cursor == LastChar)
3627 return(CC_ERROR);
3628 /* else */
3629
3630 Cursor = c_eword(Cursor, LastChar, Argument);
3631
3632 if (ActionFlag & TCSHOP_DELETE) {
3633 Cursor++;
3634 c_delfini();
3635 return(CC_REFRESH);
3636 }
3637
3638 RefCursor();
3639 return(CC_NORM);
3640 }
3641
3642 /*ARGSUSED*/
3643 CCRETVAL
v_char_fwd(Char c)3644 v_char_fwd(Char c)
3645 {
3646 Char ch;
3647
3648 USE(c);
3649 if (GetNextChar(&ch) != 1)
3650 return e_send_eof(0);
3651
3652 srch_dir = CHAR_FWD;
3653 srch_char = ch;
3654
3655 return v_csearch_fwd(ch, Argument, 0);
3656
3657 }
3658
3659 /*ARGSUSED*/
3660 CCRETVAL
v_char_back(Char c)3661 v_char_back(Char c)
3662 {
3663 Char ch;
3664
3665 USE(c);
3666 if (GetNextChar(&ch) != 1)
3667 return e_send_eof(0);
3668
3669 srch_dir = CHAR_BACK;
3670 srch_char = ch;
3671
3672 return v_csearch_back(ch, Argument, 0);
3673 }
3674
3675 /*ARGSUSED*/
3676 CCRETVAL
v_charto_fwd(Char c)3677 v_charto_fwd(Char c)
3678 {
3679 Char ch;
3680
3681 USE(c);
3682 if (GetNextChar(&ch) != 1)
3683 return e_send_eof(0);
3684
3685 return v_csearch_fwd(ch, Argument, 1);
3686
3687 }
3688
3689 /*ARGSUSED*/
3690 CCRETVAL
v_charto_back(Char c)3691 v_charto_back(Char c)
3692 {
3693 Char ch;
3694
3695 USE(c);
3696 if (GetNextChar(&ch) != 1)
3697 return e_send_eof(0);
3698
3699 return v_csearch_back(ch, Argument, 1);
3700 }
3701
3702 /*ARGSUSED*/
3703 CCRETVAL
v_rchar_fwd(Char c)3704 v_rchar_fwd(Char c)
3705 {
3706 USE(c);
3707 if (srch_char == 0)
3708 return CC_ERROR;
3709
3710 return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
3711 v_csearch_back(srch_char, Argument, 0);
3712 }
3713
3714 /*ARGSUSED*/
3715 CCRETVAL
v_rchar_back(Char c)3716 v_rchar_back(Char c)
3717 {
3718 USE(c);
3719 if (srch_char == 0)
3720 return CC_ERROR;
3721
3722 return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
3723 v_csearch_back(srch_char, Argument, 0);
3724 }
3725
3726 /*ARGSUSED*/
3727 CCRETVAL
v_undo(Char c)3728 v_undo(Char c)
3729 {
3730 int loop;
3731 Char *kp, *cp;
3732 Char temp;
3733 int size;
3734
3735 USE(c);
3736 switch (UndoAction) {
3737 case TCSHOP_DELETE|TCSHOP_INSERT:
3738 case TCSHOP_DELETE:
3739 if (UndoSize == 0) return(CC_NORM);
3740 cp = UndoPtr;
3741 kp = UndoBuf;
3742 for (loop=0; loop < UndoSize; loop++) /* copy the chars */
3743 *kp++ = *cp++; /* into UndoBuf */
3744
3745 for (cp = UndoPtr; cp <= LastChar; cp++)
3746 *cp = cp[UndoSize];
3747
3748 LastChar -= UndoSize;
3749 Cursor = UndoPtr;
3750
3751 UndoAction = TCSHOP_INSERT;
3752 break;
3753
3754 case TCSHOP_INSERT:
3755 if (UndoSize == 0) return(CC_NORM);
3756 cp = UndoPtr;
3757 Cursor = UndoPtr;
3758 kp = UndoBuf;
3759 c_insert(UndoSize); /* open the space, */
3760 for (loop = 0; loop < UndoSize; loop++) /* copy the chars */
3761 *cp++ = *kp++;
3762
3763 UndoAction = TCSHOP_DELETE;
3764 break;
3765
3766 case TCSHOP_CHANGE:
3767 if (UndoSize == 0) return(CC_NORM);
3768 cp = UndoPtr;
3769 Cursor = UndoPtr;
3770 kp = UndoBuf;
3771 size = (int)(Cursor-LastChar); /* NOT NSL independant */
3772 if (size < UndoSize)
3773 size = UndoSize;
3774 for (loop = 0; loop < size; loop++) {
3775 temp = *kp;
3776 *kp++ = *cp;
3777 *cp++ = temp;
3778 }
3779 break;
3780
3781 default:
3782 return(CC_ERROR);
3783 }
3784
3785 return(CC_REFRESH);
3786 }
3787
3788 /*ARGSUSED*/
3789 CCRETVAL
v_ush_meta(Char c)3790 v_ush_meta(Char c)
3791 {
3792 USE(c);
3793 return v_search(F_UP_SEARCH_HIST);
3794 }
3795
3796 /*ARGSUSED*/
3797 CCRETVAL
v_dsh_meta(Char c)3798 v_dsh_meta(Char c)
3799 {
3800 USE(c);
3801 return v_search(F_DOWN_SEARCH_HIST);
3802 }
3803
3804 /*ARGSUSED*/
3805 CCRETVAL
v_rsrch_fwd(Char c)3806 v_rsrch_fwd(Char c)
3807 {
3808 USE(c);
3809 if (patbuf.len == 0) return(CC_ERROR);
3810 return(v_repeat_srch(searchdir));
3811 }
3812
3813 /*ARGSUSED*/
3814 CCRETVAL
v_rsrch_back(Char c)3815 v_rsrch_back(Char c)
3816 {
3817 USE(c);
3818 if (patbuf.len == 0) return(CC_ERROR);
3819 return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
3820 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
3821 }
3822
3823 #ifndef WINNT_NATIVE
3824 /* Since ed.defns.h is generated from ed.defns.c, these empty
3825 functions will keep the F_NUM_FNS consistent
3826 */
3827 CCRETVAL
e_copy_to_clipboard(Char c)3828 e_copy_to_clipboard(Char c)
3829 {
3830 USE(c);
3831 return CC_ERROR;
3832 }
3833
3834 CCRETVAL
e_paste_from_clipboard(Char c)3835 e_paste_from_clipboard(Char c)
3836 {
3837 USE(c);
3838 return (CC_ERROR);
3839 }
3840
3841 CCRETVAL
e_dosify_next(Char c)3842 e_dosify_next(Char c)
3843 {
3844 USE(c);
3845 return (CC_ERROR);
3846 }
3847 CCRETVAL
e_dosify_prev(Char c)3848 e_dosify_prev(Char c)
3849 {
3850 USE(c);
3851 return (CC_ERROR);
3852 }
3853 CCRETVAL
e_page_up(Char c)3854 e_page_up(Char c)
3855 {
3856 USE(c);
3857 return (CC_ERROR);
3858 }
3859 CCRETVAL
e_page_down(Char c)3860 e_page_down(Char c)
3861 {
3862 USE(c);
3863 return (CC_ERROR);
3864 }
3865 #endif /* !WINNT_NATIVE */
3866
3867 #ifdef notdef
3868 void
MoveCursor(int n)3869 MoveCursor(int n) /* move cursor + right - left char */
3870 {
3871 Cursor = Cursor + n;
3872 if (Cursor < InputBuf)
3873 Cursor = InputBuf;
3874 if (Cursor > LastChar)
3875 Cursor = LastChar;
3876 return;
3877 }
3878
3879 Char *
GetCursor(void)3880 GetCursor(void)
3881 {
3882 return(Cursor);
3883 }
3884
3885 int
PutCursor(Char * p)3886 PutCursor(Char *p)
3887 {
3888 if (p < InputBuf || p > LastChar)
3889 return 1; /* Error */
3890 Cursor = p;
3891 return 0;
3892 }
3893 #endif
3894