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