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