1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.98 2010/05/08 00:37:39 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.98 2010/05/08 00:37:39 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_ALNUM 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() and c_next_word() 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 (Isdigit(ch) || Isalpha(ch) || ch == '_')
309 return C_CLASS_ALNUM;
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 (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 while ((p < high) && Isspace(*p))
832 p++;
833
834 if (isword(*p))
835 while ((p < high) && isword(*p))
836 p++;
837 else
838 while ((p < high) && !(Isspace(*p) || isword(*p)))
839 p++;
840 }
841
842 p--;
843 return(p);
844 }
845
846 /* Set the max length of the kill ring */
847 void
SetKillRing(int max)848 SetKillRing(int max)
849 {
850 CStr *new;
851 int count, i, j;
852
853 if (max < 1)
854 max = 1; /* no ring, but always one buffer */
855 if (max == KillRingMax)
856 return;
857 new = xcalloc(max, sizeof(CStr));
858 if (KillRing != NULL) {
859 if (KillRingLen != 0) {
860 if (max >= KillRingLen) {
861 count = KillRingLen;
862 j = KillPos;
863 } else {
864 count = max;
865 j = (KillPos - count + KillRingLen) % KillRingLen;
866 }
867 for (i = 0; i < KillRingLen; i++) {
868 if (i < count) /* copy latest */
869 new[i] = KillRing[j];
870 else /* free the others */
871 xfree(KillRing[j].buf);
872 j = (j + 1) % KillRingLen;
873 }
874 KillRingLen = count;
875 KillPos = count % max;
876 YankPos = count - 1;
877 }
878 xfree(KillRing);
879 }
880 KillRing = new;
881 KillRingMax = max;
882 }
883
884 /* Push string from start upto (but not including) end onto kill ring */
885 static void
c_push_kill(Char * start,Char * end)886 c_push_kill(Char *start, Char *end)
887 {
888 CStr save, *pos;
889 Char *dp, *cp, *kp;
890 int len = end - start, i, j, k;
891
892 /* Check for duplicates? */
893 if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) {
894 YankPos = (KillPos - 1 + KillRingLen) % KillRingLen;
895 if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */
896 j = YankPos;
897 for (i = 0; i < KillRingLen; i++) {
898 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
899 KillRing[j].buf[len] == '\0') {
900 save = KillRing[j];
901 for ( ; i > 0; i--) {
902 k = j;
903 j = (j + 1) % KillRingLen;
904 KillRing[k] = KillRing[j];
905 }
906 KillRing[j] = save;
907 return;
908 }
909 j = (j - 1 + KillRingLen) % KillRingLen;
910 }
911 } else if (eq(dp, STRall)) { /* skip if any earlier */
912 for (i = 0; i < KillRingLen; i++)
913 if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 &&
914 KillRing[i].buf[len] == '\0')
915 return;
916 } else if (eq(dp, STRprev)) { /* skip if immediately previous */
917 j = YankPos;
918 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 &&
919 KillRing[j].buf[len] == '\0')
920 return;
921 }
922 }
923
924 /* No duplicate, go ahead and push */
925 len++; /* need space for '\0' */
926 YankPos = KillPos;
927 if (KillRingLen < KillRingMax)
928 KillRingLen++;
929 pos = &KillRing[KillPos];
930 KillPos = (KillPos + 1) % KillRingMax;
931 if (pos->len < len) {
932 pos->buf = xrealloc(pos->buf, len * sizeof(Char));
933 pos->len = len;
934 }
935 cp = start;
936 kp = pos->buf;
937 while (cp < end)
938 *kp++ = *cp++;
939 *kp = '\0';
940 }
941
942 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
943 static void
c_save_inputbuf()944 c_save_inputbuf()
945 {
946 SavedBuf.len = 0;
947 Strbuf_append(&SavedBuf, InputBuf);
948 Strbuf_terminate(&SavedBuf);
949 LastSaved = LastChar - InputBuf;
950 CursSaved = Cursor - InputBuf;
951 HistSaved = Hist_num;
952 RestoreSaved = 1;
953 }
954
955 CCRETVAL
GetHistLine()956 GetHistLine()
957 {
958 struct Hist *hp;
959 int h;
960
961 if (Hist_num == 0) { /* if really the current line */
962 if (HistBuf.s != NULL)
963 copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/
964 else
965 *InputBuf = '\0';
966 LastChar = InputBuf + HistBuf.len;
967
968 #ifdef KSHVI
969 if (VImode)
970 Cursor = InputBuf;
971 else
972 #endif /* KSHVI */
973 Cursor = LastChar;
974
975 return(CC_REFRESH);
976 }
977
978 hp = Histlist.Hnext;
979 if (hp == NULL)
980 return(CC_ERROR);
981
982 for (h = 1; h < Hist_num; h++) {
983 if ((hp->Hnext) == NULL) {
984 Hist_num = h;
985 return(CC_ERROR);
986 }
987 hp = hp->Hnext;
988 }
989
990 if (HistLit && hp->histline) {
991 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
992 CurrentHistLit = 1;
993 }
994 else {
995 Char *p;
996
997 p = sprlex(&hp->Hlex);
998 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
999 xfree(p);
1000 CurrentHistLit = 0;
1001 }
1002 LastChar = Strend(InputBuf);
1003
1004 if (LastChar > InputBuf) {
1005 if (LastChar[-1] == '\n')
1006 LastChar--;
1007 #if 0
1008 if (LastChar[-1] == ' ')
1009 LastChar--;
1010 #endif
1011 if (LastChar < InputBuf)
1012 LastChar = InputBuf;
1013 }
1014
1015 #ifdef KSHVI
1016 if (VImode)
1017 Cursor = InputBuf;
1018 else
1019 #endif /* KSHVI */
1020 Cursor = LastChar;
1021
1022 return(CC_REFRESH);
1023 }
1024
1025 static CCRETVAL
c_search_line(Char * pattern,int dir)1026 c_search_line(Char *pattern, int dir)
1027 {
1028 Char *cp;
1029 size_t len;
1030
1031 len = Strlen(pattern);
1032
1033 if (dir == F_UP_SEARCH_HIST) {
1034 for (cp = Cursor; cp >= InputBuf; cp--)
1035 if (Strncmp(cp, pattern, len) == 0 ||
1036 Gmatch(cp, pattern)) {
1037 Cursor = cp;
1038 return(CC_NORM);
1039 }
1040 return(CC_ERROR);
1041 } else {
1042 for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++)
1043 if (Strncmp(cp, pattern, len) == 0 ||
1044 Gmatch(cp, pattern)) {
1045 Cursor = cp;
1046 return(CC_NORM);
1047 }
1048 return(CC_ERROR);
1049 }
1050 }
1051
1052 static CCRETVAL
e_inc_search(int dir)1053 e_inc_search(int dir)
1054 {
1055 static const Char STRfwd[] = { 'f', 'w', 'd', '\0' },
1056 STRbck[] = { 'b', 'c', 'k', '\0' };
1057 static Char pchar = ':'; /* ':' = normal, '?' = failed */
1058 static Char endcmd[2];
1059 const Char *cp;
1060 Char ch,
1061 *oldCursor = Cursor,
1062 oldpchar = pchar;
1063 CCRETVAL ret = CC_NORM;
1064 int oldHist_num = Hist_num,
1065 oldpatlen = patbuf.len,
1066 newdir = dir,
1067 done, redo;
1068
1069 if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim)
1070 return(CC_ERROR);
1071
1072 for (;;) {
1073
1074 if (patbuf.len == 0) { /* first round */
1075 pchar = ':';
1076 Strbuf_append1(&patbuf, '*');
1077 }
1078 done = redo = 0;
1079 *LastChar++ = '\n';
1080 for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd;
1081 *cp; *LastChar++ = *cp++)
1082 continue;
1083 *LastChar++ = pchar;
1084 for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len];
1085 *LastChar++ = *cp++)
1086 continue;
1087 *LastChar = '\0';
1088 if (adrof(STRhighlight) && pchar == ':') {
1089 /* if the no-glob-search patch is applied, remove the - 1 below */
1090 IncMatchLen = patbuf.len - 1;
1091 ClearLines();
1092 ClearDisp();
1093 }
1094 Refresh();
1095
1096 if (GetNextChar(&ch) != 1)
1097 return(e_send_eof(0));
1098
1099 switch (ch > NT_NUM_KEYS
1100 ? F_INSERT : CurrentKeyMap[(unsigned char) ch]) {
1101 case F_INSERT:
1102 case F_DIGIT:
1103 case F_MAGIC_SPACE:
1104 if (LastChar + 1 >= InputLim) /*FIXBUF*/
1105 SoundBeep();
1106 else {
1107 Strbuf_append1(&patbuf, ch);
1108 *LastChar++ = ch;
1109 *LastChar = '\0';
1110 Refresh();
1111 }
1112 break;
1113
1114 case F_INC_FWD:
1115 newdir = F_DOWN_SEARCH_HIST;
1116 redo++;
1117 break;
1118
1119 case F_INC_BACK:
1120 newdir = F_UP_SEARCH_HIST;
1121 redo++;
1122 break;
1123
1124 case F_DELPREV:
1125 if (patbuf.len > 1)
1126 done++;
1127 else
1128 SoundBeep();
1129 break;
1130
1131 default:
1132 switch (ASC(ch)) {
1133 case 0007: /* ^G: Abort */
1134 ret = CC_ERROR;
1135 done++;
1136 break;
1137
1138 case 0027: /* ^W: Append word */
1139 /* No can do if globbing characters in pattern */
1140 for (cp = &patbuf.s[1]; ; cp++)
1141 if (cp >= &patbuf.s[patbuf.len]) {
1142 Cursor += patbuf.len - 1;
1143 cp = c_next_word(Cursor, LastChar, 1);
1144 while (Cursor < cp && *Cursor != '\n') {
1145 if (LastChar + 1 >= InputLim) {/*FIXBUF*/
1146 SoundBeep();
1147 break;
1148 }
1149 Strbuf_append1(&patbuf, *Cursor);
1150 *LastChar++ = *Cursor++;
1151 }
1152 Cursor = oldCursor;
1153 *LastChar = '\0';
1154 Refresh();
1155 break;
1156 } else if (isglob(*cp)) {
1157 SoundBeep();
1158 break;
1159 }
1160 break;
1161
1162 default: /* Terminate and execute cmd */
1163 endcmd[0] = ch;
1164 PushMacro(endcmd);
1165 /*FALLTHROUGH*/
1166
1167 case 0033: /* ESC: Terminate */
1168 ret = CC_REFRESH;
1169 done++;
1170 break;
1171 }
1172 break;
1173 }
1174
1175 while (LastChar > InputBuf && *LastChar != '\n')
1176 *LastChar-- = '\0';
1177 *LastChar = '\0';
1178
1179 if (!done) {
1180
1181 /* Can't search if unmatched '[' */
1182 for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--)
1183 if (*cp == '[' || *cp == ']') {
1184 ch = *cp;
1185 break;
1186 }
1187
1188 if (patbuf.len > 1 && ch != '[') {
1189 if (redo && newdir == dir) {
1190 if (pchar == '?') { /* wrap around */
1191 Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX;
1192 if (GetHistLine() == CC_ERROR)
1193 /* Hist_num was fixed by first call */
1194 (void) GetHistLine();
1195 Cursor = newdir == F_UP_SEARCH_HIST ?
1196 LastChar : InputBuf;
1197 } else
1198 Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1;
1199 }
1200 Strbuf_append1(&patbuf, '*');
1201 Strbuf_terminate(&patbuf);
1202 if (Cursor < InputBuf || Cursor > LastChar ||
1203 (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) {
1204 LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */
1205 ret = newdir == F_UP_SEARCH_HIST ?
1206 e_up_search_hist(0) : e_down_search_hist(0);
1207 if (ret != CC_ERROR) {
1208 Cursor = newdir == F_UP_SEARCH_HIST ?
1209 LastChar : InputBuf;
1210 (void) c_search_line(&patbuf.s[1], newdir);
1211 }
1212 }
1213 patbuf.s[--patbuf.len] = '\0';
1214 if (ret == CC_ERROR) {
1215 SoundBeep();
1216 if (Hist_num != oldHist_num) {
1217 Hist_num = oldHist_num;
1218 if (GetHistLine() == CC_ERROR)
1219 return(CC_ERROR);
1220 }
1221 Cursor = oldCursor;
1222 pchar = '?';
1223 } else {
1224 pchar = ':';
1225 }
1226 }
1227
1228 ret = e_inc_search(newdir);
1229
1230 if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') {
1231 /* break abort of failed search at last non-failed */
1232 ret = CC_NORM;
1233 }
1234
1235 }
1236
1237 if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) {
1238 /* restore on normal return or error exit */
1239 pchar = oldpchar;
1240 patbuf.len = oldpatlen;
1241 if (Hist_num != oldHist_num) {
1242 Hist_num = oldHist_num;
1243 if (GetHistLine() == CC_ERROR)
1244 return(CC_ERROR);
1245 }
1246 Cursor = oldCursor;
1247 if (ret == CC_ERROR)
1248 Refresh();
1249 }
1250 if (done || ret != CC_NORM)
1251 return(ret);
1252
1253 }
1254
1255 }
1256
1257 static CCRETVAL
v_search(int dir)1258 v_search(int dir)
1259 {
1260 struct Strbuf tmpbuf = Strbuf_INIT;
1261 Char ch;
1262 Char *oldbuf;
1263 Char *oldlc, *oldc;
1264
1265 cleanup_push(&tmpbuf, Strbuf_cleanup);
1266 oldbuf = Strsave(InputBuf);
1267 cleanup_push(oldbuf, xfree);
1268 oldlc = LastChar;
1269 oldc = Cursor;
1270 Strbuf_append1(&tmpbuf, '*');
1271
1272 InputBuf[0] = '\0';
1273 LastChar = InputBuf;
1274 Cursor = InputBuf;
1275 searchdir = dir;
1276
1277 c_insert(2); /* prompt + '\n' */
1278 *Cursor++ = '\n';
1279 *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/';
1280 Refresh();
1281 for (ch = 0;ch == 0;) {
1282 if (GetNextChar(&ch) != 1) {
1283 cleanup_until(&tmpbuf);
1284 return(e_send_eof(0));
1285 }
1286 switch (ASC(ch)) {
1287 case 0010: /* Delete and backspace */
1288 case 0177:
1289 if (tmpbuf.len > 1) {
1290 *Cursor-- = '\0';
1291 LastChar = Cursor;
1292 tmpbuf.len--;
1293 }
1294 else {
1295 copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/
1296 LastChar = oldlc;
1297 Cursor = oldc;
1298 cleanup_until(&tmpbuf);
1299 return(CC_REFRESH);
1300 }
1301 Refresh();
1302 ch = 0;
1303 break;
1304
1305 case 0033: /* ESC */
1306 #ifdef IS_ASCII
1307 case '\r': /* Newline */
1308 case '\n':
1309 #else
1310 case '\012': /* ASCII Line feed */
1311 case '\015': /* ASCII (or EBCDIC) Return */
1312 #endif
1313 break;
1314
1315 default:
1316 Strbuf_append1(&tmpbuf, ch);
1317 *Cursor++ = ch;
1318 LastChar = Cursor;
1319 Refresh();
1320 ch = 0;
1321 break;
1322 }
1323 }
1324 cleanup_until(oldbuf);
1325
1326 if (tmpbuf.len == 1) {
1327 /*
1328 * Use the old pattern, but wild-card it.
1329 */
1330 if (patbuf.len == 0) {
1331 InputBuf[0] = '\0';
1332 LastChar = InputBuf;
1333 Cursor = InputBuf;
1334 Refresh();
1335 cleanup_until(&tmpbuf);
1336 return(CC_ERROR);
1337 }
1338 if (patbuf.s[0] != '*') {
1339 oldbuf = Strsave(patbuf.s);
1340 patbuf.len = 0;
1341 Strbuf_append1(&patbuf, '*');
1342 Strbuf_append(&patbuf, oldbuf);
1343 xfree(oldbuf);
1344 Strbuf_append1(&patbuf, '*');
1345 Strbuf_terminate(&patbuf);
1346 }
1347 }
1348 else {
1349 Strbuf_append1(&tmpbuf, '*');
1350 Strbuf_terminate(&tmpbuf);
1351 patbuf.len = 0;
1352 Strbuf_append(&patbuf, tmpbuf.s);
1353 Strbuf_terminate(&patbuf);
1354 }
1355 cleanup_until(&tmpbuf);
1356 LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */
1357 Cursor = LastChar = InputBuf;
1358 if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) :
1359 e_down_search_hist(0)) == CC_ERROR) {
1360 Refresh();
1361 return(CC_ERROR);
1362 }
1363 else {
1364 if (ASC(ch) == 0033) {
1365 Refresh();
1366 *LastChar++ = '\n';
1367 *LastChar = '\0';
1368 PastBottom();
1369 return(CC_NEWLINE);
1370 }
1371 else
1372 return(CC_REFRESH);
1373 }
1374 }
1375
1376 /*
1377 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1378 * entry point, called from the CcKeyMap indirected into the
1379 * CcFuncTbl array.
1380 */
1381
1382 /*ARGSUSED*/
1383 CCRETVAL
v_cmd_mode(Char c)1384 v_cmd_mode(Char c)
1385 {
1386 USE(c);
1387 InsertPos = 0;
1388 ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */
1389 ActionPos = 0;
1390 DoingArg = 0;
1391 if (UndoPtr > Cursor)
1392 UndoSize = (int)(UndoPtr - Cursor);
1393 else
1394 UndoSize = (int)(Cursor - UndoPtr);
1395
1396 inputmode = MODE_INSERT;
1397 c_alternativ_key_map(1);
1398 #ifdef notdef
1399 /*
1400 * We don't want to move the cursor, because all the editing
1401 * commands don't include the character under the cursor.
1402 */
1403 if (Cursor > InputBuf)
1404 Cursor--;
1405 #endif
1406 RefCursor();
1407 return(CC_NORM);
1408 }
1409
1410 /*ARGSUSED*/
1411 CCRETVAL
e_unassigned(Char c)1412 e_unassigned(Char c)
1413 { /* bound to keys that arn't really assigned */
1414 USE(c);
1415 SoundBeep();
1416 flush();
1417 return(CC_NORM);
1418 }
1419
1420 #ifdef notyet
1421 static CCRETVAL
e_insert_str(Char * c)1422 e_insert_str(Char *c)
1423 {
1424 int i, n;
1425
1426 n = Strlen(c);
1427 if (LastChar + Argument * n >= InputLim)
1428 return(CC_ERROR); /* end of buffer space */
1429 if (inputmode != MODE_INSERT) {
1430 c_delafter(Argument * Strlen(c));
1431 }
1432 c_insert(Argument * n);
1433 while (Argument--) {
1434 for (i = 0; i < n; i++)
1435 *Cursor++ = c[i];
1436 }
1437 Refresh();
1438 return(CC_NORM);
1439 }
1440 #endif
1441
1442 CCRETVAL
e_insert(Char c)1443 e_insert(Char c)
1444 {
1445 #ifndef SHORT_STRINGS
1446 c &= ASCII; /* no meta chars ever */
1447 #endif
1448
1449 if (!c)
1450 return(CC_ERROR); /* no NULs in the input ever!! */
1451
1452 if (LastChar + Argument >= InputLim)
1453 return(CC_ERROR); /* end of buffer space */
1454
1455 if (Argument == 1) { /* How was this optimized ???? */
1456
1457 if (inputmode != MODE_INSERT) {
1458 UndoBuf[UndoSize++] = *Cursor;
1459 UndoBuf[UndoSize] = '\0';
1460 c_delafter(1); /* Do NOT use the saving ONE */
1461 }
1462
1463 c_insert(1);
1464 *Cursor++ = (Char) c;
1465 DoingArg = 0; /* just in case */
1466 RefPlusOne(1); /* fast refresh for one char. */
1467 }
1468 else {
1469 if (inputmode != MODE_INSERT) {
1470 int i;
1471 for(i = 0; i < Argument; i++)
1472 UndoBuf[UndoSize++] = *(Cursor + i);
1473
1474 UndoBuf[UndoSize] = '\0';
1475 c_delafter(Argument); /* Do NOT use the saving ONE */
1476 }
1477
1478 c_insert(Argument);
1479
1480 while (Argument--)
1481 *Cursor++ = (Char) c;
1482 Refresh();
1483 }
1484
1485 if (inputmode == MODE_REPLACE_1)
1486 (void) v_cmd_mode(0);
1487
1488 return(CC_NORM);
1489 }
1490
1491 int
InsertStr(Char * s)1492 InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */
1493 {
1494 int len;
1495
1496 if ((len = (int) Strlen(s)) <= 0)
1497 return -1;
1498 if (LastChar + len >= InputLim)
1499 return -1; /* end of buffer space */
1500
1501 c_insert(len);
1502 while (len--)
1503 *Cursor++ = *s++;
1504 return 0;
1505 }
1506
1507 void
DeleteBack(int n)1508 DeleteBack(int n) /* delete the n characters before . */
1509 {
1510 if (n <= 0)
1511 return;
1512 if (Cursor >= &InputBuf[n]) {
1513 c_delbefore(n); /* delete before dot */
1514 }
1515 }
1516
1517 CCRETVAL
e_digit(Char c)1518 e_digit(Char c) /* gray magic here */
1519 {
1520 if (!Isdigit(c))
1521 return(CC_ERROR); /* no NULs in the input ever!! */
1522
1523 if (DoingArg) { /* if doing an arg, add this in... */
1524 if (LastCmd == F_ARGFOUR) /* if last command was ^U */
1525 Argument = c - '0';
1526 else {
1527 if (Argument > 1000000)
1528 return CC_ERROR;
1529 Argument = (Argument * 10) + (c - '0');
1530 }
1531 return(CC_ARGHACK);
1532 }
1533 else {
1534 if (LastChar + 1 >= InputLim)
1535 return CC_ERROR; /* end of buffer space */
1536
1537 if (inputmode != MODE_INSERT) {
1538 UndoBuf[UndoSize++] = *Cursor;
1539 UndoBuf[UndoSize] = '\0';
1540 c_delafter(1); /* Do NOT use the saving ONE */
1541 }
1542 c_insert(1);
1543 *Cursor++ = (Char) c;
1544 DoingArg = 0; /* just in case */
1545 RefPlusOne(1); /* fast refresh for one char. */
1546 }
1547 return(CC_NORM);
1548 }
1549
1550 CCRETVAL
e_argdigit(Char c)1551 e_argdigit(Char c) /* for ESC-n */
1552 {
1553 #ifdef IS_ASCII
1554 c &= ASCII;
1555 #else
1556 c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */
1557 #endif
1558
1559 if (!Isdigit(c))
1560 return(CC_ERROR); /* no NULs in the input ever!! */
1561
1562 if (DoingArg) { /* if doing an arg, add this in... */
1563 if (Argument > 1000000)
1564 return CC_ERROR;
1565 Argument = (Argument * 10) + (c - '0');
1566 }
1567 else { /* else starting an argument */
1568 Argument = c - '0';
1569 DoingArg = 1;
1570 }
1571 return(CC_ARGHACK);
1572 }
1573
1574 CCRETVAL
v_zero(Char c)1575 v_zero(Char c) /* command mode 0 for vi */
1576 {
1577 if (DoingArg) { /* if doing an arg, add this in... */
1578 if (Argument > 1000000)
1579 return CC_ERROR;
1580 Argument = (Argument * 10) + (c - '0');
1581 return(CC_ARGHACK);
1582 }
1583 else { /* else starting an argument */
1584 Cursor = InputBuf;
1585 if (ActionFlag & TCSHOP_DELETE) {
1586 c_delfini();
1587 return(CC_REFRESH);
1588 }
1589 RefCursor(); /* move the cursor */
1590 return(CC_NORM);
1591 }
1592 }
1593
1594 /*ARGSUSED*/
1595 CCRETVAL
e_newline(Char c)1596 e_newline(Char c)
1597 { /* always ignore argument */
1598 USE(c);
1599 if (adrof(STRhighlight) && MarkIsSet) {
1600 MarkIsSet = 0;
1601 ClearLines();
1602 ClearDisp();
1603 Refresh();
1604 }
1605 MarkIsSet = 0;
1606
1607 /* PastBottom(); NOW done in ed.inputl.c */
1608 *LastChar++ = '\n'; /* for the benefit of CSH */
1609 *LastChar = '\0'; /* just in case */
1610 if (VImode)
1611 InsertPos = InputBuf; /* Reset editing position */
1612 return(CC_NEWLINE);
1613 }
1614
1615 /*ARGSUSED*/
1616 CCRETVAL
e_newline_hold(Char c)1617 e_newline_hold(Char c)
1618 {
1619 USE(c);
1620 c_save_inputbuf();
1621 HistSaved = 0;
1622 *LastChar++ = '\n'; /* for the benefit of CSH */
1623 *LastChar = '\0'; /* just in case */
1624 return(CC_NEWLINE);
1625 }
1626
1627 /*ARGSUSED*/
1628 CCRETVAL
e_newline_down_hist(Char c)1629 e_newline_down_hist(Char c)
1630 {
1631 USE(c);
1632 if (Hist_num > 1) {
1633 HistSaved = Hist_num;
1634 }
1635 *LastChar++ = '\n'; /* for the benefit of CSH */
1636 *LastChar = '\0'; /* just in case */
1637 return(CC_NEWLINE);
1638 }
1639
1640 /*ARGSUSED*/
1641 CCRETVAL
e_send_eof(Char c)1642 e_send_eof(Char c)
1643 { /* for when ^D is ONLY send-eof */
1644 USE(c);
1645 PastBottom();
1646 *LastChar = '\0'; /* just in case */
1647 return(CC_EOF);
1648 }
1649
1650 /*ARGSUSED*/
1651 CCRETVAL
e_complete(Char c)1652 e_complete(Char c)
1653 {
1654 USE(c);
1655 *LastChar = '\0'; /* just in case */
1656 return(CC_COMPLETE);
1657 }
1658
1659 /*ARGSUSED*/
1660 CCRETVAL
e_complete_back(Char c)1661 e_complete_back(Char c)
1662 {
1663 USE(c);
1664 *LastChar = '\0'; /* just in case */
1665 return(CC_COMPLETE_BACK);
1666 }
1667
1668 /*ARGSUSED*/
1669 CCRETVAL
e_complete_fwd(Char c)1670 e_complete_fwd(Char c)
1671 {
1672 USE(c);
1673 *LastChar = '\0'; /* just in case */
1674 return(CC_COMPLETE_FWD);
1675 }
1676
1677 /*ARGSUSED*/
1678 CCRETVAL
e_complete_all(Char c)1679 e_complete_all(Char c)
1680 {
1681 USE(c);
1682 *LastChar = '\0'; /* just in case */
1683 return(CC_COMPLETE_ALL);
1684 }
1685
1686 /*ARGSUSED*/
1687 CCRETVAL
v_cm_complete(Char c)1688 v_cm_complete(Char c)
1689 {
1690 USE(c);
1691 if (Cursor < LastChar)
1692 Cursor++;
1693 *LastChar = '\0'; /* just in case */
1694 return(CC_COMPLETE);
1695 }
1696
1697 /*ARGSUSED*/
1698 CCRETVAL
e_toggle_hist(Char c)1699 e_toggle_hist(Char c)
1700 {
1701 struct Hist *hp;
1702 int h;
1703
1704 USE(c);
1705 *LastChar = '\0'; /* just in case */
1706
1707 if (Hist_num <= 0) {
1708 return CC_ERROR;
1709 }
1710
1711 hp = Histlist.Hnext;
1712 if (hp == NULL) { /* this is only if no history */
1713 return(CC_ERROR);
1714 }
1715
1716 for (h = 1; h < Hist_num; h++)
1717 hp = hp->Hnext;
1718
1719 if (!CurrentHistLit) {
1720 if (hp->histline) {
1721 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/
1722 CurrentHistLit = 1;
1723 }
1724 else {
1725 return CC_ERROR;
1726 }
1727 }
1728 else {
1729 Char *p;
1730
1731 p = sprlex(&hp->Hlex);
1732 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/
1733 xfree(p);
1734 CurrentHistLit = 0;
1735 }
1736
1737 LastChar = Strend(InputBuf);
1738 if (LastChar > InputBuf) {
1739 if (LastChar[-1] == '\n')
1740 LastChar--;
1741 if (LastChar[-1] == ' ')
1742 LastChar--;
1743 if (LastChar < InputBuf)
1744 LastChar = InputBuf;
1745 }
1746
1747 #ifdef KSHVI
1748 if (VImode)
1749 Cursor = InputBuf;
1750 else
1751 #endif /* KSHVI */
1752 Cursor = LastChar;
1753
1754 return(CC_REFRESH);
1755 }
1756
1757 /*ARGSUSED*/
1758 CCRETVAL
e_up_hist(Char c)1759 e_up_hist(Char c)
1760 {
1761 Char beep = 0;
1762
1763 USE(c);
1764 UndoAction = TCSHOP_NOP;
1765 *LastChar = '\0'; /* just in case */
1766
1767 if (Hist_num == 0) { /* save the current buffer away */
1768 HistBuf.len = 0;
1769 Strbuf_append(&HistBuf, InputBuf);
1770 Strbuf_terminate(&HistBuf);
1771 }
1772
1773 Hist_num += Argument;
1774
1775 if (GetHistLine() == CC_ERROR) {
1776 beep = 1;
1777 (void) GetHistLine(); /* Hist_num was fixed by first call */
1778 }
1779
1780 Refresh();
1781 if (beep)
1782 return(CC_ERROR);
1783 else
1784 return(CC_NORM); /* was CC_UP_HIST */
1785 }
1786
1787 /*ARGSUSED*/
1788 CCRETVAL
e_down_hist(Char c)1789 e_down_hist(Char c)
1790 {
1791 USE(c);
1792 UndoAction = TCSHOP_NOP;
1793 *LastChar = '\0'; /* just in case */
1794
1795 Hist_num -= Argument;
1796
1797 if (Hist_num < 0) {
1798 Hist_num = 0;
1799 return(CC_ERROR); /* make it beep */
1800 }
1801
1802 return(GetHistLine());
1803 }
1804
1805
1806
1807 /*
1808 * c_hmatch() return True if the pattern matches the prefix
1809 */
1810 static int
c_hmatch(Char * str)1811 c_hmatch(Char *str)
1812 {
1813 if (Strncmp(patbuf.s, str, patbuf.len) == 0)
1814 return 1;
1815 return Gmatch(str, patbuf.s);
1816 }
1817
1818 /*
1819 * c_hsetpat(): Set the history seatch pattern
1820 */
1821 static void
c_hsetpat(void)1822 c_hsetpat(void)
1823 {
1824 if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) {
1825 patbuf.len = 0;
1826 Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf);
1827 Strbuf_terminate(&patbuf);
1828 }
1829 #ifdef SDEBUG
1830 xprintf("\nHist_num = %d\n", Hist_num);
1831 xprintf("patlen = %d\n", (int)patbuf.len);
1832 xprintf("patbuf = \"%S\"\n", patbuf.s);
1833 xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf);
1834 #endif
1835 }
1836
1837 /*ARGSUSED*/
1838 CCRETVAL
e_up_search_hist(Char c)1839 e_up_search_hist(Char c)
1840 {
1841 struct Hist *hp;
1842 int h;
1843 int found = 0;
1844
1845 USE(c);
1846 ActionFlag = TCSHOP_NOP;
1847 UndoAction = TCSHOP_NOP;
1848 *LastChar = '\0'; /* just in case */
1849 if (Hist_num < 0) {
1850 #ifdef DEBUG_EDIT
1851 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname);
1852 #endif
1853 Hist_num = 0;
1854 return(CC_ERROR);
1855 }
1856
1857 if (Hist_num == 0) {
1858 HistBuf.len = 0;
1859 Strbuf_append(&HistBuf, InputBuf);
1860 Strbuf_terminate(&HistBuf);
1861 }
1862
1863
1864 hp = Histlist.Hnext;
1865 if (hp == NULL)
1866 return(CC_ERROR);
1867
1868 c_hsetpat(); /* Set search pattern !! */
1869
1870 for (h = 1; h <= Hist_num; h++)
1871 hp = hp->Hnext;
1872
1873 while (hp != NULL) {
1874 Char *hl;
1875 int matched;
1876
1877 if (hp->histline == NULL)
1878 hp->histline = sprlex(&hp->Hlex);
1879 if (HistLit)
1880 hl = hp->histline;
1881 else {
1882 hl = sprlex(&hp->Hlex);
1883 cleanup_push(hl, xfree);
1884 }
1885 #ifdef SDEBUG
1886 xprintf("Comparing with \"%S\"\n", hl);
1887 #endif
1888 matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1889 hl[LastChar-InputBuf]) && c_hmatch(hl);
1890 if (!HistLit)
1891 cleanup_until(hl);
1892 if (matched) {
1893 found++;
1894 break;
1895 }
1896 h++;
1897 hp = hp->Hnext;
1898 }
1899
1900 if (!found) {
1901 #ifdef SDEBUG
1902 xprintf("not found\n");
1903 #endif
1904 return(CC_ERROR);
1905 }
1906
1907 Hist_num = h;
1908
1909 return(GetHistLine());
1910 }
1911
1912 /*ARGSUSED*/
1913 CCRETVAL
e_down_search_hist(Char c)1914 e_down_search_hist(Char c)
1915 {
1916 struct Hist *hp;
1917 int h;
1918 int found = 0;
1919
1920 USE(c);
1921 ActionFlag = TCSHOP_NOP;
1922 UndoAction = TCSHOP_NOP;
1923 *LastChar = '\0'; /* just in case */
1924
1925 if (Hist_num == 0)
1926 return(CC_ERROR);
1927
1928 hp = Histlist.Hnext;
1929 if (hp == 0)
1930 return(CC_ERROR);
1931
1932 c_hsetpat(); /* Set search pattern !! */
1933
1934 for (h = 1; h < Hist_num && hp; h++) {
1935 Char *hl;
1936 if (hp->histline == NULL)
1937 hp->histline = sprlex(&hp->Hlex);
1938 if (HistLit)
1939 hl = hp->histline;
1940 else {
1941 hl = sprlex(&hp->Hlex);
1942 cleanup_push(hl, xfree);
1943 }
1944 #ifdef SDEBUG
1945 xprintf("Comparing with \"%S\"\n", hl);
1946 #endif
1947 if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) ||
1948 hl[LastChar-InputBuf]) && c_hmatch(hl))
1949 found = h;
1950 if (!HistLit)
1951 cleanup_until(hl);
1952 hp = hp->Hnext;
1953 }
1954
1955 if (!found) { /* is it the current history number? */
1956 if (!c_hmatch(HistBuf.s)) {
1957 #ifdef SDEBUG
1958 xprintf("not found\n");
1959 #endif
1960 return(CC_ERROR);
1961 }
1962 }
1963
1964 Hist_num = found;
1965
1966 return(GetHistLine());
1967 }
1968
1969 /*ARGSUSED*/
1970 CCRETVAL
e_helpme(Char c)1971 e_helpme(Char c)
1972 {
1973 USE(c);
1974 PastBottom();
1975 *LastChar = '\0'; /* just in case */
1976 return(CC_HELPME);
1977 }
1978
1979 /*ARGSUSED*/
1980 CCRETVAL
e_correct(Char c)1981 e_correct(Char c)
1982 {
1983 USE(c);
1984 *LastChar = '\0'; /* just in case */
1985 return(CC_CORRECT);
1986 }
1987
1988 /*ARGSUSED*/
1989 CCRETVAL
e_correctl(Char c)1990 e_correctl(Char c)
1991 {
1992 USE(c);
1993 *LastChar = '\0'; /* just in case */
1994 return(CC_CORRECT_L);
1995 }
1996
1997 /*ARGSUSED*/
1998 CCRETVAL
e_run_fg_editor(Char c)1999 e_run_fg_editor(Char c)
2000 {
2001 struct process *pp;
2002
2003 USE(c);
2004 if ((pp = find_stop_ed()) != NULL) {
2005 /* save our editor state so we can restore it */
2006 c_save_inputbuf();
2007 Hist_num = 0; /* for the history commands */
2008
2009 /* put the tty in a sane mode */
2010 PastBottom();
2011 (void) Cookedmode(); /* make sure the tty is set up correctly */
2012
2013 /* do it! */
2014 fg_proc_entry(pp);
2015
2016 (void) Rawmode(); /* go on */
2017 Refresh();
2018 RestoreSaved = 0;
2019 HistSaved = 0;
2020 }
2021 return(CC_NORM);
2022 }
2023
2024 /*ARGSUSED*/
2025 CCRETVAL
e_list_choices(Char c)2026 e_list_choices(Char c)
2027 {
2028 USE(c);
2029 PastBottom();
2030 *LastChar = '\0'; /* just in case */
2031 return(CC_LIST_CHOICES);
2032 }
2033
2034 /*ARGSUSED*/
2035 CCRETVAL
e_list_all(Char c)2036 e_list_all(Char c)
2037 {
2038 USE(c);
2039 PastBottom();
2040 *LastChar = '\0'; /* just in case */
2041 return(CC_LIST_ALL);
2042 }
2043
2044 /*ARGSUSED*/
2045 CCRETVAL
e_list_glob(Char c)2046 e_list_glob(Char c)
2047 {
2048 USE(c);
2049 PastBottom();
2050 *LastChar = '\0'; /* just in case */
2051 return(CC_LIST_GLOB);
2052 }
2053
2054 /*ARGSUSED*/
2055 CCRETVAL
e_expand_glob(Char c)2056 e_expand_glob(Char c)
2057 {
2058 USE(c);
2059 *LastChar = '\0'; /* just in case */
2060 return(CC_EXPAND_GLOB);
2061 }
2062
2063 /*ARGSUSED*/
2064 CCRETVAL
e_normalize_path(Char c)2065 e_normalize_path(Char c)
2066 {
2067 USE(c);
2068 *LastChar = '\0'; /* just in case */
2069 return(CC_NORMALIZE_PATH);
2070 }
2071
2072 /*ARGSUSED*/
2073 CCRETVAL
e_normalize_command(Char c)2074 e_normalize_command(Char c)
2075 {
2076 USE(c);
2077 *LastChar = '\0'; /* just in case */
2078 return(CC_NORMALIZE_COMMAND);
2079 }
2080
2081 /*ARGSUSED*/
2082 CCRETVAL
e_expand_vars(Char c)2083 e_expand_vars(Char c)
2084 {
2085 USE(c);
2086 *LastChar = '\0'; /* just in case */
2087 return(CC_EXPAND_VARS);
2088 }
2089
2090 /*ARGSUSED*/
2091 CCRETVAL
e_which(Char c)2092 e_which(Char c)
2093 { /* do a fast command line which(1) */
2094 USE(c);
2095 c_save_inputbuf();
2096 Hist_num = 0; /* for the history commands */
2097 PastBottom();
2098 *LastChar = '\0'; /* just in case */
2099 return(CC_WHICH);
2100 }
2101
2102 /*ARGSUSED*/
2103 CCRETVAL
e_last_item(Char c)2104 e_last_item(Char c)
2105 { /* insert the last element of the prev. cmd */
2106 struct Hist *hp;
2107 struct wordent *wp, *firstp;
2108 int i;
2109 Char *expanded;
2110
2111 USE(c);
2112 if (Argument <= 0)
2113 return(CC_ERROR);
2114
2115 hp = Histlist.Hnext;
2116 if (hp == NULL) { /* this is only if no history */
2117 return(CC_ERROR);
2118 }
2119
2120 wp = (hp->Hlex).prev;
2121
2122 if (wp->prev == (struct wordent *) NULL)
2123 return(CC_ERROR); /* an empty history entry */
2124
2125 firstp = (hp->Hlex).next;
2126
2127 /* back up arg words in lex */
2128 for (i = 0; i < Argument && wp != firstp; i++) {
2129 wp = wp->prev;
2130 }
2131
2132 expanded = expand_lex(wp->prev, 0, i - 1);
2133 if (InsertStr(expanded)) {
2134 xfree(expanded);
2135 return(CC_ERROR);
2136 }
2137
2138 xfree(expanded);
2139 return(CC_REFRESH);
2140 }
2141
2142 /*ARGSUSED*/
2143 CCRETVAL
e_dabbrev_expand(Char c)2144 e_dabbrev_expand(Char c)
2145 { /* expand to preceding word matching prefix */
2146 Char *cp, *ncp, *bp;
2147 struct Hist *hp;
2148 int arg = 0, i;
2149 size_t len = 0;
2150 int found = 0;
2151 Char *hbuf;
2152 static int oldevent, hist, word;
2153 static Char *start, *oldcursor;
2154
2155 USE(c);
2156 if (Argument <= 0)
2157 return(CC_ERROR);
2158
2159 cp = c_preword(Cursor, InputBuf, 1, STRshwordsep);
2160 if (cp == Cursor || Isspace(*cp))
2161 return(CC_ERROR);
2162
2163 hbuf = NULL;
2164 hp = Histlist.Hnext;
2165 bp = InputBuf;
2166 if (Argument == 1 && eventno == oldevent && cp == start &&
2167 Cursor == oldcursor && patbuf.len > 0
2168 && Strncmp(patbuf.s, cp, patbuf.len) == 0){
2169 /* continue previous search - go to last match (hist/word) */
2170 if (hist != 0) { /* need to move up history */
2171 for (i = 1; i < hist && hp != NULL; i++)
2172 hp = hp->Hnext;
2173 if (hp == NULL) /* "can't happen" */
2174 goto err_hbuf;
2175 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2176 cp = Strend(hbuf);
2177 bp = hbuf;
2178 hp = hp->Hnext;
2179 }
2180 cp = c_preword(cp, bp, word, STRshwordsep);
2181 } else { /* starting new search */
2182 oldevent = eventno;
2183 start = cp;
2184 patbuf.len = 0;
2185 Strbuf_appendn(&patbuf, cp, Cursor - cp);
2186 hist = 0;
2187 word = 0;
2188 }
2189
2190 while (!found) {
2191 ncp = c_preword(cp, bp, 1, STRshwordsep);
2192 if (ncp == cp || Isspace(*ncp)) { /* beginning of line */
2193 hist++;
2194 word = 0;
2195 if (hp == NULL)
2196 goto err_hbuf;
2197 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX);
2198 cp = Strend(hbuf);
2199 bp = hbuf;
2200 hp = hp->Hnext;
2201 continue;
2202 } else {
2203 word++;
2204 len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1;
2205 cp = ncp;
2206 }
2207 if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) {
2208 /* We don't fully check distinct matches as Gnuemacs does: */
2209 if (Argument > 1) { /* just count matches */
2210 if (++arg >= Argument)
2211 found++;
2212 } else { /* match if distinct from previous */
2213 if (len != (size_t)(Cursor - start)
2214 || Strncmp(cp, start, len) != 0)
2215 found++;
2216 }
2217 }
2218 }
2219
2220 if (LastChar + len - (Cursor - start) >= InputLim)
2221 goto err_hbuf; /* no room */
2222 DeleteBack(Cursor - start);
2223 c_insert(len);
2224 while (len--)
2225 *Cursor++ = *cp++;
2226 oldcursor = Cursor;
2227 xfree(hbuf);
2228 return(CC_REFRESH);
2229
2230 err_hbuf:
2231 xfree(hbuf);
2232 return CC_ERROR;
2233 }
2234
2235 /*ARGSUSED*/
2236 CCRETVAL
e_yank_kill(Char c)2237 e_yank_kill(Char c)
2238 { /* almost like GnuEmacs */
2239 int len;
2240 Char *kp, *cp;
2241
2242 USE(c);
2243 if (KillRingLen == 0) /* nothing killed */
2244 return(CC_ERROR);
2245 len = Strlen(KillRing[YankPos].buf);
2246 if (LastChar + len >= InputLim)
2247 return(CC_ERROR); /* end of buffer space */
2248
2249 /* else */
2250 cp = Cursor; /* for speed */
2251
2252 c_insert(len); /* open the space, */
2253 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2254 *cp++ = *kp;
2255
2256 if (Argument == 1) { /* if no arg */
2257 Mark = Cursor; /* mark at beginning, cursor at end */
2258 Cursor = cp;
2259 } else {
2260 Mark = cp; /* else cursor at beginning, mark at end */
2261 }
2262
2263 if (adrof(STRhighlight) && MarkIsSet) {
2264 ClearLines();
2265 ClearDisp();
2266 }
2267 MarkIsSet = 0;
2268 return(CC_REFRESH);
2269 }
2270
2271 /*ARGSUSED*/
2272 CCRETVAL
e_yank_pop(Char c)2273 e_yank_pop(Char c)
2274 { /* almost like GnuEmacs */
2275 int m_bef_c, del_len, ins_len;
2276 Char *kp, *cp;
2277
2278 USE(c);
2279
2280 #if 0
2281 /* XXX This "should" be here, but doesn't work, since LastCmd
2282 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2283 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2284 second one will "succeed" even if the first one wasn't preceded
2285 by a yank, and giving an argument is impossible. Now we "succeed"
2286 regardless of previous command, which is wrong too of course. */
2287 if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP)
2288 return(CC_ERROR);
2289 #endif
2290
2291 if (KillRingLen == 0) /* nothing killed */
2292 return(CC_ERROR);
2293 YankPos -= Argument;
2294 while (YankPos < 0)
2295 YankPos += KillRingLen;
2296 YankPos %= KillRingLen;
2297
2298 if (Cursor > Mark) {
2299 del_len = Cursor - Mark;
2300 m_bef_c = 1;
2301 } else {
2302 del_len = Mark - Cursor;
2303 m_bef_c = 0;
2304 }
2305 ins_len = Strlen(KillRing[YankPos].buf);
2306 if (LastChar + ins_len - del_len >= InputLim)
2307 return(CC_ERROR); /* end of buffer space */
2308
2309 if (m_bef_c) {
2310 c_delbefore(del_len);
2311 } else {
2312 c_delafter(del_len);
2313 }
2314 cp = Cursor; /* for speed */
2315
2316 c_insert(ins_len); /* open the space, */
2317 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */
2318 *cp++ = *kp;
2319
2320 if (m_bef_c) {
2321 Mark = Cursor; /* mark at beginning, cursor at end */
2322 Cursor = cp;
2323 } else {
2324 Mark = cp; /* else cursor at beginning, mark at end */
2325 }
2326
2327 if (adrof(STRhighlight) && MarkIsSet) {
2328 ClearLines();
2329 ClearDisp();
2330 }
2331 MarkIsSet = 0;
2332 return(CC_REFRESH);
2333 }
2334
2335 /*ARGSUSED*/
2336 CCRETVAL
v_delprev(Char c)2337 v_delprev(Char c) /* Backspace key in insert mode */
2338 {
2339 int rc;
2340
2341 USE(c);
2342 rc = CC_ERROR;
2343
2344 if (InsertPos != 0) {
2345 if (Argument <= Cursor - InsertPos) {
2346 c_delbefore(Argument); /* delete before */
2347 rc = CC_REFRESH;
2348 }
2349 }
2350 return(rc);
2351 } /* v_delprev */
2352
2353 /*ARGSUSED*/
2354 CCRETVAL
e_delprev(Char c)2355 e_delprev(Char c)
2356 {
2357 USE(c);
2358 if (Cursor > InputBuf) {
2359 c_delbefore(Argument); /* delete before dot */
2360 return(CC_REFRESH);
2361 }
2362 else {
2363 return(CC_ERROR);
2364 }
2365 }
2366
2367 /*ARGSUSED*/
2368 CCRETVAL
e_delwordprev(Char c)2369 e_delwordprev(Char c)
2370 {
2371 Char *cp;
2372
2373 USE(c);
2374 if (Cursor == InputBuf)
2375 return(CC_ERROR);
2376 /* else */
2377
2378 cp = c_prev_word(Cursor, InputBuf, Argument);
2379
2380 c_push_kill(cp, Cursor); /* save the text */
2381
2382 c_delbefore((int)(Cursor - cp)); /* delete before dot */
2383 return(CC_REFRESH);
2384 }
2385
2386 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2387 *
2388 * Changed the names of some of the ^D family of editor functions to
2389 * correspond to what they actually do and created new e_delnext_list
2390 * for completeness.
2391 *
2392 * Old names: New names:
2393 *
2394 * delete-char delete-char-or-eof
2395 * F_DELNEXT F_DELNEXT_EOF
2396 * e_delnext e_delnext_eof
2397 * edelnxt edelnxteof
2398 * delete-char-or-eof delete-char
2399 * F_DELNEXT_EOF F_DELNEXT
2400 * e_delnext_eof e_delnext
2401 * edelnxteof edelnxt
2402 * delete-char-or-list delete-char-or-list-or-eof
2403 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
2404 * e_list_delnext e_delnext_list_eof
2405 * edellsteof
2406 * (no old equivalent) delete-char-or-list
2407 * F_DELNEXT_LIST
2408 * e_delnext_list
2409 * e_delnxtlst
2410 */
2411
2412 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2413 /* rename e_delnext() -> e_delnext_eof() */
2414 /*ARGSUSED*/
2415 CCRETVAL
e_delnext(Char c)2416 e_delnext(Char c)
2417 {
2418 USE(c);
2419 if (Cursor == LastChar) {/* if I'm at the end */
2420 if (!VImode) {
2421 return(CC_ERROR);
2422 }
2423 else {
2424 if (Cursor != InputBuf)
2425 Cursor--;
2426 else
2427 return(CC_ERROR);
2428 }
2429 }
2430 c_delafter(Argument); /* delete after dot */
2431 if (Cursor > LastChar)
2432 Cursor = LastChar; /* bounds check */
2433 return(CC_REFRESH);
2434 }
2435
2436
2437 /*ARGSUSED*/
2438 CCRETVAL
e_delnext_eof(Char c)2439 e_delnext_eof(Char c)
2440 {
2441 USE(c);
2442 if (Cursor == LastChar) {/* if I'm at the end */
2443 if (!VImode) {
2444 if (Cursor == InputBuf) {
2445 /* if I'm also at the beginning */
2446 so_write(STReof, 4);/* then do a EOF */
2447 flush();
2448 return(CC_EOF);
2449 }
2450 else
2451 return(CC_ERROR);
2452 }
2453 else {
2454 if (Cursor != InputBuf)
2455 Cursor--;
2456 else
2457 return(CC_ERROR);
2458 }
2459 }
2460 c_delafter(Argument); /* delete after dot */
2461 if (Cursor > LastChar)
2462 Cursor = LastChar; /* bounds check */
2463 return(CC_REFRESH);
2464 }
2465
2466 /*ARGSUSED*/
2467 CCRETVAL
e_delnext_list(Char c)2468 e_delnext_list(Char c)
2469 {
2470 USE(c);
2471 if (Cursor == LastChar) { /* if I'm at the end */
2472 PastBottom();
2473 *LastChar = '\0'; /* just in case */
2474 return(CC_LIST_CHOICES);
2475 }
2476 else {
2477 c_delafter(Argument); /* delete after dot */
2478 if (Cursor > LastChar)
2479 Cursor = LastChar; /* bounds check */
2480 return(CC_REFRESH);
2481 }
2482 }
2483
2484 /*ARGSUSED*/
2485 CCRETVAL
e_delnext_list_eof(Char c)2486 e_delnext_list_eof(Char c)
2487 {
2488 USE(c);
2489 if (Cursor == LastChar) { /* if I'm at the end */
2490 if (Cursor == InputBuf) { /* if I'm also at the beginning */
2491 so_write(STReof, 4);/* then do a EOF */
2492 flush();
2493 return(CC_EOF);
2494 }
2495 else {
2496 PastBottom();
2497 *LastChar = '\0'; /* just in case */
2498 return(CC_LIST_CHOICES);
2499 }
2500 }
2501 else {
2502 c_delafter(Argument); /* delete after dot */
2503 if (Cursor > LastChar)
2504 Cursor = LastChar; /* bounds check */
2505 return(CC_REFRESH);
2506 }
2507 }
2508
2509 /*ARGSUSED*/
2510 CCRETVAL
e_list_eof(Char c)2511 e_list_eof(Char c)
2512 {
2513 CCRETVAL rv;
2514
2515 USE(c);
2516 if (Cursor == LastChar && Cursor == InputBuf) {
2517 so_write(STReof, 4); /* then do a EOF */
2518 flush();
2519 rv = CC_EOF;
2520 }
2521 else {
2522 PastBottom();
2523 *LastChar = '\0'; /* just in case */
2524 rv = CC_LIST_CHOICES;
2525 }
2526 return rv;
2527 }
2528
2529 /*ARGSUSED*/
2530 CCRETVAL
e_delwordnext(Char c)2531 e_delwordnext(Char c)
2532 {
2533 Char *cp;
2534
2535 USE(c);
2536 if (Cursor == LastChar)
2537 return(CC_ERROR);
2538 /* else */
2539
2540 cp = c_next_word(Cursor, LastChar, Argument);
2541
2542 c_push_kill(Cursor, cp); /* save the text */
2543
2544 c_delafter((int)(cp - Cursor)); /* delete after dot */
2545 if (Cursor > LastChar)
2546 Cursor = LastChar; /* bounds check */
2547 return(CC_REFRESH);
2548 }
2549
2550 /*ARGSUSED*/
2551 CCRETVAL
e_toend(Char c)2552 e_toend(Char c)
2553 {
2554 USE(c);
2555 Cursor = LastChar;
2556 if (VImode)
2557 if (ActionFlag & TCSHOP_DELETE) {
2558 c_delfini();
2559 return(CC_REFRESH);
2560 }
2561 RefCursor(); /* move the cursor */
2562 return(CC_NORM);
2563 }
2564
2565 /*ARGSUSED*/
2566 CCRETVAL
e_tobeg(Char c)2567 e_tobeg(Char c)
2568 {
2569 USE(c);
2570 Cursor = InputBuf;
2571
2572 if (VImode) {
2573 while (Isspace(*Cursor)) /* We want FIRST non space character */
2574 Cursor++;
2575 if (ActionFlag & TCSHOP_DELETE) {
2576 c_delfini();
2577 return(CC_REFRESH);
2578 }
2579 }
2580
2581 RefCursor(); /* move the cursor */
2582 return(CC_NORM);
2583 }
2584
2585 /*ARGSUSED*/
2586 CCRETVAL
e_killend(Char c)2587 e_killend(Char c)
2588 {
2589 USE(c);
2590 c_push_kill(Cursor, LastChar); /* copy it */
2591 LastChar = Cursor; /* zap! -- delete to end */
2592 if (Mark > Cursor)
2593 Mark = Cursor;
2594 MarkIsSet = 0;
2595 return(CC_REFRESH);
2596 }
2597
2598
2599 /*ARGSUSED*/
2600 CCRETVAL
e_killbeg(Char c)2601 e_killbeg(Char c)
2602 {
2603 USE(c);
2604 c_push_kill(InputBuf, Cursor); /* copy it */
2605 c_delbefore((int)(Cursor - InputBuf));
2606 if (Mark && Mark > Cursor)
2607 Mark -= Cursor-InputBuf;
2608 return(CC_REFRESH);
2609 }
2610
2611 /*ARGSUSED*/
2612 CCRETVAL
e_killall(Char c)2613 e_killall(Char c)
2614 {
2615 USE(c);
2616 c_push_kill(InputBuf, LastChar); /* copy it */
2617 Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */
2618 MarkIsSet = 0;
2619 return(CC_REFRESH);
2620 }
2621
2622 /*ARGSUSED*/
2623 CCRETVAL
e_killregion(Char c)2624 e_killregion(Char c)
2625 {
2626 USE(c);
2627 if (!Mark)
2628 return(CC_ERROR);
2629
2630 if (Mark > Cursor) {
2631 c_push_kill(Cursor, Mark); /* copy it */
2632 c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */
2633 Mark = Cursor;
2634 }
2635 else { /* mark is before cursor */
2636 c_push_kill(Mark, Cursor); /* copy it */
2637 c_delbefore((int)(Cursor - Mark));
2638 }
2639 if (adrof(STRhighlight) && MarkIsSet) {
2640 ClearLines();
2641 ClearDisp();
2642 }
2643 MarkIsSet = 0;
2644 return(CC_REFRESH);
2645 }
2646
2647 /*ARGSUSED*/
2648 CCRETVAL
e_copyregion(Char c)2649 e_copyregion(Char c)
2650 {
2651 USE(c);
2652 if (!Mark)
2653 return(CC_ERROR);
2654
2655 if (Mark > Cursor) {
2656 c_push_kill(Cursor, Mark); /* copy it */
2657 }
2658 else { /* mark is before cursor */
2659 c_push_kill(Mark, Cursor); /* copy it */
2660 }
2661 return(CC_NORM); /* don't even need to Refresh() */
2662 }
2663
2664 /*ARGSUSED*/
2665 CCRETVAL
e_charswitch(Char cc)2666 e_charswitch(Char cc)
2667 {
2668 Char c;
2669
2670 USE(cc);
2671
2672 /* do nothing if we are at beginning of line or have only one char */
2673 if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) {
2674 return(CC_ERROR);
2675 }
2676
2677 if (Cursor < LastChar) {
2678 Cursor++;
2679 }
2680 c = Cursor[-2];
2681 Cursor[-2] = Cursor[-1];
2682 Cursor[-1] = c;
2683 return(CC_REFRESH);
2684 }
2685
2686 /*ARGSUSED*/
2687 CCRETVAL
e_gcharswitch(Char cc)2688 e_gcharswitch(Char cc)
2689 { /* gosmacs style ^T */
2690 Char c;
2691
2692 USE(cc);
2693 if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */
2694 c = Cursor[-2];
2695 Cursor[-2] = Cursor[-1];
2696 Cursor[-1] = c;
2697 return(CC_REFRESH);
2698 }
2699 else {
2700 return(CC_ERROR);
2701 }
2702 }
2703
2704 /*ARGSUSED*/
2705 CCRETVAL
e_charback(Char c)2706 e_charback(Char c)
2707 {
2708 USE(c);
2709 if (Cursor > InputBuf) {
2710 if (Argument > Cursor - InputBuf)
2711 Cursor = InputBuf;
2712 else
2713 Cursor -= Argument;
2714
2715 if (VImode)
2716 if (ActionFlag & TCSHOP_DELETE) {
2717 c_delfini();
2718 return(CC_REFRESH);
2719 }
2720
2721 RefCursor();
2722 return(CC_NORM);
2723 }
2724 else {
2725 return(CC_ERROR);
2726 }
2727 }
2728
2729 /*ARGSUSED*/
2730 CCRETVAL
v_wordback(Char c)2731 v_wordback(Char c)
2732 {
2733 USE(c);
2734 if (Cursor == InputBuf)
2735 return(CC_ERROR);
2736 /* else */
2737
2738 Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */
2739
2740 if (ActionFlag & TCSHOP_DELETE) {
2741 c_delfini();
2742 return(CC_REFRESH);
2743 }
2744
2745 RefCursor();
2746 return(CC_NORM);
2747 }
2748
2749 /*ARGSUSED*/
2750 CCRETVAL
e_wordback(Char c)2751 e_wordback(Char c)
2752 {
2753 USE(c);
2754 if (Cursor == InputBuf)
2755 return(CC_ERROR);
2756 /* else */
2757
2758 Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */
2759
2760 if (VImode)
2761 if (ActionFlag & TCSHOP_DELETE) {
2762 c_delfini();
2763 return(CC_REFRESH);
2764 }
2765
2766 RefCursor();
2767 return(CC_NORM);
2768 }
2769
2770 /*ARGSUSED*/
2771 CCRETVAL
e_charfwd(Char c)2772 e_charfwd(Char c)
2773 {
2774 USE(c);
2775 if (Cursor < LastChar) {
2776 Cursor += Argument;
2777 if (Cursor > LastChar)
2778 Cursor = LastChar;
2779
2780 if (VImode)
2781 if (ActionFlag & TCSHOP_DELETE) {
2782 c_delfini();
2783 return(CC_REFRESH);
2784 }
2785
2786 RefCursor();
2787 return(CC_NORM);
2788 }
2789 else {
2790 return(CC_ERROR);
2791 }
2792 }
2793
2794 /*ARGSUSED*/
2795 CCRETVAL
e_wordfwd(Char c)2796 e_wordfwd(Char c)
2797 {
2798 USE(c);
2799 if (Cursor == LastChar)
2800 return(CC_ERROR);
2801 /* else */
2802
2803 Cursor = c_next_word(Cursor, LastChar, Argument);
2804
2805 if (VImode)
2806 if (ActionFlag & TCSHOP_DELETE) {
2807 c_delfini();
2808 return(CC_REFRESH);
2809 }
2810
2811 RefCursor();
2812 return(CC_NORM);
2813 }
2814
2815 /*ARGSUSED*/
2816 CCRETVAL
v_wordfwd(Char c)2817 v_wordfwd(Char c)
2818 {
2819 USE(c);
2820 if (Cursor == LastChar)
2821 return(CC_ERROR);
2822 /* else */
2823
2824 Cursor = c_nexword(Cursor, LastChar, Argument);
2825
2826 if (VImode)
2827 if (ActionFlag & TCSHOP_DELETE) {
2828 c_delfini();
2829 return(CC_REFRESH);
2830 }
2831
2832 RefCursor();
2833 return(CC_NORM);
2834 }
2835
2836 /*ARGSUSED*/
2837 CCRETVAL
v_wordbegnext(Char c)2838 v_wordbegnext(Char c)
2839 {
2840 USE(c);
2841 if (Cursor == LastChar)
2842 return(CC_ERROR);
2843 /* else */
2844
2845 Cursor = c_next_word(Cursor, LastChar, Argument);
2846 if (Cursor < LastChar)
2847 Cursor++;
2848
2849 if (VImode)
2850 if (ActionFlag & TCSHOP_DELETE) {
2851 c_delfini();
2852 return(CC_REFRESH);
2853 }
2854
2855 RefCursor();
2856 return(CC_NORM);
2857 }
2858
2859 /*ARGSUSED*/
2860 static CCRETVAL
v_repeat_srch(int c)2861 v_repeat_srch(int c)
2862 {
2863 CCRETVAL rv = CC_ERROR;
2864 #ifdef SDEBUG
2865 xprintf("dir %d patlen %d patbuf %S\n",
2866 c, (int)patbuf.len, patbuf.s);
2867 #endif
2868
2869 LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */
2870 LastChar = InputBuf;
2871 switch (c) {
2872 case F_DOWN_SEARCH_HIST:
2873 rv = e_down_search_hist(0);
2874 break;
2875 case F_UP_SEARCH_HIST:
2876 rv = e_up_search_hist(0);
2877 break;
2878 default:
2879 break;
2880 }
2881 return rv;
2882 }
2883
2884 static CCRETVAL
v_csearch_back(Char ch,int count,int tflag)2885 v_csearch_back(Char ch, int count, int tflag)
2886 {
2887 Char *cp;
2888
2889 cp = Cursor;
2890 while (count--) {
2891 if (*cp == ch)
2892 cp--;
2893 while (cp > InputBuf && *cp != ch)
2894 cp--;
2895 }
2896
2897 if (cp < InputBuf || (cp == InputBuf && *cp != ch))
2898 return(CC_ERROR);
2899
2900 if (*cp == ch && tflag)
2901 cp++;
2902
2903 Cursor = cp;
2904
2905 if (ActionFlag & TCSHOP_DELETE) {
2906 Cursor++;
2907 c_delfini();
2908 return(CC_REFRESH);
2909 }
2910
2911 RefCursor();
2912 return(CC_NORM);
2913 }
2914
2915 static CCRETVAL
v_csearch_fwd(Char ch,int count,int tflag)2916 v_csearch_fwd(Char ch, int count, int tflag)
2917 {
2918 Char *cp;
2919
2920 cp = Cursor;
2921 while (count--) {
2922 if(*cp == ch)
2923 cp++;
2924 while (cp < LastChar && *cp != ch)
2925 cp++;
2926 }
2927
2928 if (cp >= LastChar)
2929 return(CC_ERROR);
2930
2931 if (*cp == ch && tflag)
2932 cp--;
2933
2934 Cursor = cp;
2935
2936 if (ActionFlag & TCSHOP_DELETE) {
2937 Cursor++;
2938 c_delfini();
2939 return(CC_REFRESH);
2940 }
2941 RefCursor();
2942 return(CC_NORM);
2943 }
2944
2945 /*ARGSUSED*/
2946 static CCRETVAL
v_action(int c)2947 v_action(int c)
2948 {
2949 Char *cp, *kp;
2950
2951 if (ActionFlag == TCSHOP_DELETE) {
2952 ActionFlag = TCSHOP_NOP;
2953 ActionPos = 0;
2954
2955 UndoSize = 0;
2956 kp = UndoBuf;
2957 for (cp = InputBuf; cp < LastChar; cp++) {
2958 *kp++ = *cp;
2959 UndoSize++;
2960 }
2961
2962 UndoAction = TCSHOP_INSERT;
2963 UndoPtr = InputBuf;
2964 LastChar = InputBuf;
2965 Cursor = InputBuf;
2966 if (c & TCSHOP_INSERT)
2967 c_alternativ_key_map(0);
2968
2969 return(CC_REFRESH);
2970 }
2971 #ifdef notdef
2972 else if (ActionFlag == TCSHOP_NOP) {
2973 #endif
2974 ActionPos = Cursor;
2975 ActionFlag = c;
2976 return(CC_ARGHACK); /* Do NOT clear out argument */
2977 #ifdef notdef
2978 }
2979 else {
2980 ActionFlag = 0;
2981 ActionPos = 0;
2982 return(CC_ERROR);
2983 }
2984 #endif
2985 }
2986
2987 #ifdef COMMENT
2988 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2989 static void
c_get_word(Char ** begin,Char ** end)2990 c_get_word(Char **begin, Char **end)
2991 {
2992 Char *cp;
2993
2994 cp = &Cursor[0];
2995 while (Argument--) {
2996 while ((cp <= LastChar) && (isword(*cp)))
2997 cp++;
2998 *end = --cp;
2999 while ((cp >= InputBuf) && (isword(*cp)))
3000 cp--;
3001 *begin = ++cp;
3002 }
3003 }
3004 #endif /* COMMENT */
3005
3006 /*ARGSUSED*/
3007 CCRETVAL
e_uppercase(Char c)3008 e_uppercase(Char c)
3009 {
3010 Char *cp, *end;
3011
3012 USE(c);
3013 end = c_next_word(Cursor, LastChar, Argument);
3014
3015 for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */
3016 if (Islower(*cp))
3017 *cp = Toupper(*cp);
3018
3019 Cursor = end;
3020 if (Cursor > LastChar)
3021 Cursor = LastChar;
3022 return(CC_REFRESH);
3023 }
3024
3025
3026 /*ARGSUSED*/
3027 CCRETVAL
e_capitolcase(Char c)3028 e_capitolcase(Char c)
3029 {
3030 Char *cp, *end;
3031
3032 USE(c);
3033 end = c_next_word(Cursor, LastChar, Argument);
3034
3035 cp = Cursor;
3036 for (; cp < end; cp++) {
3037 if (Isalpha(*cp)) {
3038 if (Islower(*cp))
3039 *cp = Toupper(*cp);
3040 cp++;
3041 break;
3042 }
3043 }
3044 for (; cp < end; cp++)
3045 if (Isupper(*cp))
3046 *cp = Tolower(*cp);
3047
3048 Cursor = end;
3049 if (Cursor > LastChar)
3050 Cursor = LastChar;
3051 return(CC_REFRESH);
3052 }
3053
3054 /*ARGSUSED*/
3055 CCRETVAL
e_lowercase(Char c)3056 e_lowercase(Char c)
3057 {
3058 Char *cp, *end;
3059
3060 USE(c);
3061 end = c_next_word(Cursor, LastChar, Argument);
3062
3063 for (cp = Cursor; cp < end; cp++)
3064 if (Isupper(*cp))
3065 *cp = Tolower(*cp);
3066
3067 Cursor = end;
3068 if (Cursor > LastChar)
3069 Cursor = LastChar;
3070 return(CC_REFRESH);
3071 }
3072
3073
3074 /*ARGSUSED*/
3075 CCRETVAL
e_set_mark(Char c)3076 e_set_mark(Char c)
3077 {
3078 USE(c);
3079 if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) {
3080 ClearLines();
3081 ClearDisp();
3082 Refresh();
3083 }
3084 Mark = Cursor;
3085 MarkIsSet = 1;
3086 return(CC_NORM);
3087 }
3088
3089 /*ARGSUSED*/
3090 CCRETVAL
e_exchange_mark(Char c)3091 e_exchange_mark(Char c)
3092 {
3093 Char *cp;
3094
3095 USE(c);
3096 cp = Cursor;
3097 Cursor = Mark;
3098 Mark = cp;
3099 RefCursor();
3100 return(CC_NORM);
3101 }
3102
3103 /*ARGSUSED*/
3104 CCRETVAL
e_argfour(Char c)3105 e_argfour(Char c)
3106 { /* multiply current argument by 4 */
3107 USE(c);
3108 if (Argument > 1000000)
3109 return CC_ERROR;
3110 DoingArg = 1;
3111 Argument *= 4;
3112 return(CC_ARGHACK);
3113 }
3114
3115 static void
quote_mode_cleanup(void * unused)3116 quote_mode_cleanup(void *unused)
3117 {
3118 USE(unused);
3119 QuoteModeOff();
3120 }
3121
3122 /*ARGSUSED*/
3123 CCRETVAL
e_quote(Char c)3124 e_quote(Char c)
3125 {
3126 Char ch;
3127 int num;
3128
3129 USE(c);
3130 QuoteModeOn();
3131 cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */
3132 num = GetNextChar(&ch);
3133 cleanup_until(&c);
3134 if (num == 1)
3135 return e_insert(ch);
3136 else
3137 return e_send_eof(0);
3138 }
3139
3140 /*ARGSUSED*/
3141 CCRETVAL
e_metanext(Char c)3142 e_metanext(Char c)
3143 {
3144 USE(c);
3145 MetaNext = 1;
3146 return(CC_ARGHACK); /* preserve argument */
3147 }
3148
3149 #ifdef notdef
3150 /*ARGSUSED*/
3151 CCRETVAL
e_extendnext(Char c)3152 e_extendnext(Char c)
3153 {
3154 CurrentKeyMap = CcAltMap;
3155 return(CC_ARGHACK); /* preserve argument */
3156 }
3157
3158 #endif
3159
3160 /*ARGSUSED*/
3161 CCRETVAL
v_insbeg(Char c)3162 v_insbeg(Char c)
3163 { /* move to beginning of line and start vi
3164 * insert mode */
3165 USE(c);
3166 Cursor = InputBuf;
3167 InsertPos = Cursor;
3168
3169 UndoPtr = Cursor;
3170 UndoAction = TCSHOP_DELETE;
3171
3172 RefCursor(); /* move the cursor */
3173 c_alternativ_key_map(0);
3174 return(CC_NORM);
3175 }
3176
3177 /*ARGSUSED*/
3178 CCRETVAL
v_replone(Char c)3179 v_replone(Char c)
3180 { /* vi mode overwrite one character */
3181 USE(c);
3182 c_alternativ_key_map(0);
3183 inputmode = MODE_REPLACE_1;
3184 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3185 UndoPtr = Cursor;
3186 UndoSize = 0;
3187 return(CC_NORM);
3188 }
3189
3190 /*ARGSUSED*/
3191 CCRETVAL
v_replmode(Char c)3192 v_replmode(Char c)
3193 { /* vi mode start overwriting */
3194 USE(c);
3195 c_alternativ_key_map(0);
3196 inputmode = MODE_REPLACE;
3197 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */
3198 UndoPtr = Cursor;
3199 UndoSize = 0;
3200 return(CC_NORM);
3201 }
3202
3203 /*ARGSUSED*/
3204 CCRETVAL
v_substchar(Char c)3205 v_substchar(Char c)
3206 { /* vi mode substitute for one char */
3207 USE(c);
3208 c_delafter(Argument);
3209 c_alternativ_key_map(0);
3210 return(CC_REFRESH);
3211 }
3212
3213 /*ARGSUSED*/
3214 CCRETVAL
v_substline(Char c)3215 v_substline(Char c)
3216 { /* vi mode replace whole line */
3217 USE(c);
3218 (void) e_killall(0);
3219 c_alternativ_key_map(0);
3220 return(CC_REFRESH);
3221 }
3222
3223 /*ARGSUSED*/
3224 CCRETVAL
v_chgtoend(Char c)3225 v_chgtoend(Char c)
3226 { /* vi mode change to end of line */
3227 USE(c);
3228 (void) e_killend(0);
3229 c_alternativ_key_map(0);
3230 return(CC_REFRESH);
3231 }
3232
3233 /*ARGSUSED*/
3234 CCRETVAL
v_insert(Char c)3235 v_insert(Char c)
3236 { /* vi mode start inserting */
3237 USE(c);
3238 c_alternativ_key_map(0);
3239
3240 InsertPos = Cursor;
3241 UndoPtr = Cursor;
3242 UndoAction = TCSHOP_DELETE;
3243
3244 return(CC_NORM);
3245 }
3246
3247 /*ARGSUSED*/
3248 CCRETVAL
v_add(Char c)3249 v_add(Char c)
3250 { /* vi mode start adding */
3251 USE(c);
3252 c_alternativ_key_map(0);
3253 if (Cursor < LastChar)
3254 {
3255 Cursor++;
3256 if (Cursor > LastChar)
3257 Cursor = LastChar;
3258 RefCursor();
3259 }
3260
3261 InsertPos = Cursor;
3262 UndoPtr = Cursor;
3263 UndoAction = TCSHOP_DELETE;
3264
3265 return(CC_NORM);
3266 }
3267
3268 /*ARGSUSED*/
3269 CCRETVAL
v_addend(Char c)3270 v_addend(Char c)
3271 { /* vi mode to add at end of line */
3272 USE(c);
3273 c_alternativ_key_map(0);
3274 Cursor = LastChar;
3275
3276 InsertPos = LastChar; /* Mark where insertion begins */
3277 UndoPtr = LastChar;
3278 UndoAction = TCSHOP_DELETE;
3279
3280 RefCursor();
3281 return(CC_NORM);
3282 }
3283
3284 /*ARGSUSED*/
3285 CCRETVAL
v_change_case(Char cc)3286 v_change_case(Char cc)
3287 {
3288 Char c;
3289
3290 USE(cc);
3291 if (Cursor < LastChar) {
3292 #ifndef WINNT_NATIVE
3293 c = *Cursor;
3294 #else
3295 c = CHAR & *Cursor;
3296 #endif /* WINNT_NATIVE */
3297 if (Isupper(c))
3298 *Cursor++ = Tolower(c);
3299 else if (Islower(c))
3300 *Cursor++ = Toupper(c);
3301 else
3302 Cursor++;
3303 RefPlusOne(1); /* fast refresh for one char */
3304 return(CC_NORM);
3305 }
3306 return(CC_ERROR);
3307 }
3308
3309 /*ARGSUSED*/
3310 CCRETVAL
e_expand(Char c)3311 e_expand(Char c)
3312 {
3313 Char *p;
3314
3315 USE(c);
3316 for (p = InputBuf; Isspace(*p); p++)
3317 continue;
3318 if (p == LastChar)
3319 return(CC_ERROR);
3320
3321 justpr++;
3322 Expand++;
3323 return(e_newline(0));
3324 }
3325
3326 /*ARGSUSED*/
3327 CCRETVAL
e_startover(Char c)3328 e_startover(Char c)
3329 { /* erase all of current line, start again */
3330 USE(c);
3331 ResetInLine(0); /* reset the input pointers */
3332 return(CC_REFRESH);
3333 }
3334
3335 /*ARGSUSED*/
3336 CCRETVAL
e_redisp(Char c)3337 e_redisp(Char c)
3338 {
3339 USE(c);
3340 ClearLines();
3341 ClearDisp();
3342 return(CC_REFRESH);
3343 }
3344
3345 /*ARGSUSED*/
3346 CCRETVAL
e_cleardisp(Char c)3347 e_cleardisp(Char c)
3348 {
3349 USE(c);
3350 ClearScreen(); /* clear the whole real screen */
3351 ClearDisp(); /* reset everything */
3352 return(CC_REFRESH);
3353 }
3354
3355 /*ARGSUSED*/
3356 CCRETVAL
e_tty_int(Char c)3357 e_tty_int(Char c)
3358 {
3359 USE(c);
3360 #if defined(_MINIX) || defined(WINNT_NATIVE)
3361 /* SAK PATCH: erase all of current line, start again */
3362 ResetInLine(0); /* reset the input pointers */
3363 xputchar('\n');
3364 ClearDisp();
3365 return (CC_REFRESH);
3366 #else /* !_MINIX && !WINNT_NATIVE */
3367 /* do no editing */
3368 return (CC_NORM);
3369 #endif /* _MINIX || WINNT_NATIVE */
3370 }
3371
3372 /*
3373 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3374 * Function to send a character back to the input stream in cooked
3375 * mode. Only works if we have TIOCSTI
3376 */
3377 /*ARGSUSED*/
3378 CCRETVAL
e_stuff_char(Char c)3379 e_stuff_char(Char c)
3380 {
3381 #ifdef TIOCSTI
3382 int was_raw = Tty_raw_mode;
3383 char buf[MB_LEN_MAX];
3384 size_t i, len;
3385
3386 if (was_raw)
3387 (void) Cookedmode();
3388
3389 (void) xwrite(SHIN, "\n", 1);
3390 len = one_wctomb(buf, c & CHAR);
3391 for (i = 0; i < len; i++)
3392 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]);
3393
3394 if (was_raw)
3395 (void) Rawmode();
3396 return(e_redisp(c));
3397 #else /* !TIOCSTI */
3398 return(CC_ERROR);
3399 #endif /* !TIOCSTI */
3400 }
3401
3402 /*ARGSUSED*/
3403 CCRETVAL
e_insovr(Char c)3404 e_insovr(Char c)
3405 {
3406 USE(c);
3407 inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT);
3408 return(CC_NORM);
3409 }
3410
3411 /*ARGSUSED*/
3412 CCRETVAL
e_tty_dsusp(Char c)3413 e_tty_dsusp(Char c)
3414 {
3415 USE(c);
3416 /* do no editing */
3417 return(CC_NORM);
3418 }
3419
3420 /*ARGSUSED*/
3421 CCRETVAL
e_tty_flusho(Char c)3422 e_tty_flusho(Char c)
3423 {
3424 USE(c);
3425 /* do no editing */
3426 return(CC_NORM);
3427 }
3428
3429 /*ARGSUSED*/
3430 CCRETVAL
e_tty_quit(Char c)3431 e_tty_quit(Char c)
3432 {
3433 USE(c);
3434 /* do no editing */
3435 return(CC_NORM);
3436 }
3437
3438 /*ARGSUSED*/
3439 CCRETVAL
e_tty_tsusp(Char c)3440 e_tty_tsusp(Char c)
3441 {
3442 USE(c);
3443 /* do no editing */
3444 return(CC_NORM);
3445 }
3446
3447 /*ARGSUSED*/
3448 CCRETVAL
e_tty_stopo(Char c)3449 e_tty_stopo(Char c)
3450 {
3451 USE(c);
3452 /* do no editing */
3453 return(CC_NORM);
3454 }
3455
3456 /* returns the number of (attempted) expansions */
3457 int
ExpandHistory(void)3458 ExpandHistory(void)
3459 {
3460 *LastChar = '\0'; /* just in case */
3461 return c_substitute();
3462 }
3463
3464 /*ARGSUSED*/
3465 CCRETVAL
e_expand_history(Char c)3466 e_expand_history(Char c)
3467 {
3468 USE(c);
3469 (void)ExpandHistory();
3470 return(CC_NORM);
3471 }
3472
3473 /*ARGSUSED*/
3474 CCRETVAL
e_magic_space(Char c)3475 e_magic_space(Char c)
3476 {
3477 USE(c);
3478 *LastChar = '\0'; /* just in case */
3479 (void)c_substitute();
3480 return(e_insert(' '));
3481 }
3482
3483 /*ARGSUSED*/
3484 CCRETVAL
e_inc_fwd(Char c)3485 e_inc_fwd(Char c)
3486 {
3487 CCRETVAL ret;
3488
3489 USE(c);
3490 patbuf.len = 0;
3491 MarkIsSet = 0;
3492 ret = e_inc_search(F_DOWN_SEARCH_HIST);
3493 if (adrof(STRhighlight) && IncMatchLen) {
3494 IncMatchLen = 0;
3495 ClearLines();
3496 ClearDisp();
3497 Refresh();
3498 }
3499 IncMatchLen = 0;
3500 return ret;
3501 }
3502
3503
3504 /*ARGSUSED*/
3505 CCRETVAL
e_inc_back(Char c)3506 e_inc_back(Char c)
3507 {
3508 CCRETVAL ret;
3509
3510 USE(c);
3511 patbuf.len = 0;
3512 MarkIsSet = 0;
3513 ret = e_inc_search(F_UP_SEARCH_HIST);
3514 if (adrof(STRhighlight) && IncMatchLen) {
3515 IncMatchLen = 0;
3516 ClearLines();
3517 ClearDisp();
3518 Refresh();
3519 }
3520 IncMatchLen = 0;
3521 return ret;
3522 }
3523
3524 /*ARGSUSED*/
3525 CCRETVAL
e_copyprev(Char c)3526 e_copyprev(Char c)
3527 {
3528 Char *cp, *oldc, *dp;
3529
3530 USE(c);
3531 if (Cursor == InputBuf)
3532 return(CC_ERROR);
3533 /* else */
3534
3535 oldc = Cursor;
3536 /* does a bounds check */
3537 cp = c_prev_word(Cursor, InputBuf, Argument);
3538
3539 c_insert((int)(oldc - cp));
3540 for (dp = oldc; cp < oldc && dp < LastChar; cp++)
3541 *dp++ = *cp;
3542
3543 Cursor = dp; /* put cursor at end */
3544
3545 return(CC_REFRESH);
3546 }
3547
3548 /*ARGSUSED*/
3549 CCRETVAL
e_tty_starto(Char c)3550 e_tty_starto(Char c)
3551 {
3552 USE(c);
3553 /* do no editing */
3554 return(CC_NORM);
3555 }
3556
3557 /*ARGSUSED*/
3558 CCRETVAL
e_load_average(Char c)3559 e_load_average(Char c)
3560 {
3561 USE(c);
3562 PastBottom();
3563 #ifdef TIOCSTAT
3564 /*
3565 * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3566 * there even if they don't use it. (lukem@netbsd.org)
3567 */
3568 if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0)
3569 #endif
3570 xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
3571 return(CC_REFRESH);
3572 }
3573
3574 /*ARGSUSED*/
3575 CCRETVAL
v_chgmeta(Char c)3576 v_chgmeta(Char c)
3577 {
3578 USE(c);
3579 /*
3580 * Delete with insert == change: first we delete and then we leave in
3581 * insert mode.
3582 */
3583 return(v_action(TCSHOP_DELETE|TCSHOP_INSERT));
3584 }
3585
3586 /*ARGSUSED*/
3587 CCRETVAL
v_delmeta(Char c)3588 v_delmeta(Char c)
3589 {
3590 USE(c);
3591 return(v_action(TCSHOP_DELETE));
3592 }
3593
3594
3595 /*ARGSUSED*/
3596 CCRETVAL
v_endword(Char c)3597 v_endword(Char c)
3598 {
3599 USE(c);
3600 if (Cursor == LastChar)
3601 return(CC_ERROR);
3602 /* else */
3603
3604 Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace);
3605
3606 if (ActionFlag & TCSHOP_DELETE)
3607 {
3608 Cursor++;
3609 c_delfini();
3610 return(CC_REFRESH);
3611 }
3612
3613 RefCursor();
3614 return(CC_NORM);
3615 }
3616
3617 /*ARGSUSED*/
3618 CCRETVAL
v_eword(Char c)3619 v_eword(Char c)
3620 {
3621 USE(c);
3622 if (Cursor == LastChar)
3623 return(CC_ERROR);
3624 /* else */
3625
3626 Cursor = c_eword(Cursor, LastChar, Argument);
3627
3628 if (ActionFlag & TCSHOP_DELETE) {
3629 Cursor++;
3630 c_delfini();
3631 return(CC_REFRESH);
3632 }
3633
3634 RefCursor();
3635 return(CC_NORM);
3636 }
3637
3638 /*ARGSUSED*/
3639 CCRETVAL
v_char_fwd(Char c)3640 v_char_fwd(Char c)
3641 {
3642 Char ch;
3643
3644 USE(c);
3645 if (GetNextChar(&ch) != 1)
3646 return e_send_eof(0);
3647
3648 srch_dir = CHAR_FWD;
3649 srch_char = ch;
3650
3651 return v_csearch_fwd(ch, Argument, 0);
3652
3653 }
3654
3655 /*ARGSUSED*/
3656 CCRETVAL
v_char_back(Char c)3657 v_char_back(Char c)
3658 {
3659 Char ch;
3660
3661 USE(c);
3662 if (GetNextChar(&ch) != 1)
3663 return e_send_eof(0);
3664
3665 srch_dir = CHAR_BACK;
3666 srch_char = ch;
3667
3668 return v_csearch_back(ch, Argument, 0);
3669 }
3670
3671 /*ARGSUSED*/
3672 CCRETVAL
v_charto_fwd(Char c)3673 v_charto_fwd(Char c)
3674 {
3675 Char ch;
3676
3677 USE(c);
3678 if (GetNextChar(&ch) != 1)
3679 return e_send_eof(0);
3680
3681 return v_csearch_fwd(ch, Argument, 1);
3682
3683 }
3684
3685 /*ARGSUSED*/
3686 CCRETVAL
v_charto_back(Char c)3687 v_charto_back(Char c)
3688 {
3689 Char ch;
3690
3691 USE(c);
3692 if (GetNextChar(&ch) != 1)
3693 return e_send_eof(0);
3694
3695 return v_csearch_back(ch, Argument, 1);
3696 }
3697
3698 /*ARGSUSED*/
3699 CCRETVAL
v_rchar_fwd(Char c)3700 v_rchar_fwd(Char c)
3701 {
3702 USE(c);
3703 if (srch_char == 0)
3704 return CC_ERROR;
3705
3706 return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) :
3707 v_csearch_back(srch_char, Argument, 0);
3708 }
3709
3710 /*ARGSUSED*/
3711 CCRETVAL
v_rchar_back(Char c)3712 v_rchar_back(Char c)
3713 {
3714 USE(c);
3715 if (srch_char == 0)
3716 return CC_ERROR;
3717
3718 return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) :
3719 v_csearch_back(srch_char, Argument, 0);
3720 }
3721
3722 /*ARGSUSED*/
3723 CCRETVAL
v_undo(Char c)3724 v_undo(Char c)
3725 {
3726 int loop;
3727 Char *kp, *cp;
3728 Char temp;
3729 int size;
3730
3731 USE(c);
3732 switch (UndoAction) {
3733 case TCSHOP_DELETE|TCSHOP_INSERT:
3734 case TCSHOP_DELETE:
3735 if (UndoSize == 0) return(CC_NORM);
3736 cp = UndoPtr;
3737 kp = UndoBuf;
3738 for (loop=0; loop < UndoSize; loop++) /* copy the chars */
3739 *kp++ = *cp++; /* into UndoBuf */
3740
3741 for (cp = UndoPtr; cp <= LastChar; cp++)
3742 *cp = cp[UndoSize];
3743
3744 LastChar -= UndoSize;
3745 Cursor = UndoPtr;
3746
3747 UndoAction = TCSHOP_INSERT;
3748 break;
3749
3750 case TCSHOP_INSERT:
3751 if (UndoSize == 0) return(CC_NORM);
3752 cp = UndoPtr;
3753 Cursor = UndoPtr;
3754 kp = UndoBuf;
3755 c_insert(UndoSize); /* open the space, */
3756 for (loop = 0; loop < UndoSize; loop++) /* copy the chars */
3757 *cp++ = *kp++;
3758
3759 UndoAction = TCSHOP_DELETE;
3760 break;
3761
3762 case TCSHOP_CHANGE:
3763 if (UndoSize == 0) return(CC_NORM);
3764 cp = UndoPtr;
3765 Cursor = UndoPtr;
3766 kp = UndoBuf;
3767 size = (int)(Cursor-LastChar); /* NOT NSL independant */
3768 if (size < UndoSize)
3769 size = UndoSize;
3770 for(loop = 0; loop < size; loop++) {
3771 temp = *kp;
3772 *kp++ = *cp;
3773 *cp++ = temp;
3774 }
3775 break;
3776
3777 default:
3778 return(CC_ERROR);
3779 }
3780
3781 return(CC_REFRESH);
3782 }
3783
3784 /*ARGSUSED*/
3785 CCRETVAL
v_ush_meta(Char c)3786 v_ush_meta(Char c)
3787 {
3788 USE(c);
3789 return v_search(F_UP_SEARCH_HIST);
3790 }
3791
3792 /*ARGSUSED*/
3793 CCRETVAL
v_dsh_meta(Char c)3794 v_dsh_meta(Char c)
3795 {
3796 USE(c);
3797 return v_search(F_DOWN_SEARCH_HIST);
3798 }
3799
3800 /*ARGSUSED*/
3801 CCRETVAL
v_rsrch_fwd(Char c)3802 v_rsrch_fwd(Char c)
3803 {
3804 USE(c);
3805 if (patbuf.len == 0) return(CC_ERROR);
3806 return(v_repeat_srch(searchdir));
3807 }
3808
3809 /*ARGSUSED*/
3810 CCRETVAL
v_rsrch_back(Char c)3811 v_rsrch_back(Char c)
3812 {
3813 USE(c);
3814 if (patbuf.len == 0) return(CC_ERROR);
3815 return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ?
3816 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST));
3817 }
3818
3819 #ifndef WINNT_NATIVE
3820 /* Since ed.defns.h is generated from ed.defns.c, these empty
3821 functions will keep the F_NUM_FNS consistent
3822 */
3823 CCRETVAL
e_copy_to_clipboard(Char c)3824 e_copy_to_clipboard(Char c)
3825 {
3826 USE(c);
3827 return CC_ERROR;
3828 }
3829
3830 CCRETVAL
e_paste_from_clipboard(Char c)3831 e_paste_from_clipboard(Char c)
3832 {
3833 USE(c);
3834 return (CC_ERROR);
3835 }
3836
3837 CCRETVAL
e_dosify_next(Char c)3838 e_dosify_next(Char c)
3839 {
3840 USE(c);
3841 return (CC_ERROR);
3842 }
3843 CCRETVAL
e_dosify_prev(Char c)3844 e_dosify_prev(Char c)
3845 {
3846 USE(c);
3847 return (CC_ERROR);
3848 }
3849 CCRETVAL
e_page_up(Char c)3850 e_page_up(Char c)
3851 {
3852 USE(c);
3853 return (CC_ERROR);
3854 }
3855 CCRETVAL
e_page_down(Char c)3856 e_page_down(Char c)
3857 {
3858 USE(c);
3859 return (CC_ERROR);
3860 }
3861 #endif /* !WINNT_NATIVE */
3862
3863 #ifdef notdef
3864 void
MoveCursor(int n)3865 MoveCursor(int n) /* move cursor + right - left char */
3866 {
3867 Cursor = Cursor + n;
3868 if (Cursor < InputBuf)
3869 Cursor = InputBuf;
3870 if (Cursor > LastChar)
3871 Cursor = LastChar;
3872 return;
3873 }
3874
3875 Char *
GetCursor(void)3876 GetCursor(void)
3877 {
3878 return(Cursor);
3879 }
3880
3881 int
PutCursor(Char * p)3882 PutCursor(Char *p)
3883 {
3884 if (p < InputBuf || p > LastChar)
3885 return 1; /* Error */
3886 Cursor = p;
3887 return 0;
3888 }
3889 #endif
3890