1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.93 2006/08/23 15:03:13 christos Exp $ */
3 * ed.chared.c: Character editing functions.
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
34 Bjorn Knutsson @ Thu Jun 24 19:02:17 1999
36 e_dabbrev_expand() did not do proper completion if quoted spaces were present
37 in the string being completed. Exemple:
41 # echo h<press key bound to dabbrev-expande>
45 # echo h<press key bound to dabbrev-expande>
46 # echo hello\ world<cursor>
48 The same problem occured if spaces were present in a string withing quotation
53 # echo "h<press key bound to dabbrev-expande>
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.
61 Compare the following two strings:
63 # echo \"" 'foo \' bar\"
65 # echo '\"" 'foo \' bar\"
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.
75 RCSID("$tcsh: ed.chared.c,v 3.93 2006/08/23 15:03:13 christos Exp $")
83 #define TCSHOP_NOP 0x00
84 #define TCSHOP_DELETE 0x01
85 #define TCSHOP_INSERT 0x02
86 #define TCSHOP_CHANGE 0x04
93 * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com>
95 #define C_CLASS_WHITE 1
96 #define C_CLASS_ALNUM 2
97 #define C_CLASS_OTHER 3
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 */
105 static int searchdir
= F_UP_SEARCH_HIST
; /* Direction of last search */
106 static struct Strbuf patbuf
; /* = Strbuf_INIT; Search target */
110 static int srch_dir
= CHAR_FWD
; /* Direction of last search */
111 static Char srch_char
= 0; /* Search target */
113 /* all routines that start with c_ are private to this set of routines */
114 static void c_alternativ_key_map (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 void c_excl (Char
*);
124 static void c_substitute (void);
125 static void c_delfini (void);
126 static int c_hmatch (Char
*);
127 static void c_hsetpat (void);
129 static void c_get_word (Char
**, Char
**);
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);
141 static CCRETVAL
e_insert_str (Char
*);
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);
149 c_alternativ_key_map(int state
)
153 CurrentKeyMap
= CcKeyMap
;
156 CurrentKeyMap
= CcAltMap
;
162 AltKeyMap
= (Char
) state
;
170 if (LastChar
+ num
>= InputLim
)
171 return; /* can't go past end of buffer */
173 if (Cursor
< LastChar
) { /* if I must move chars */
174 for (cp
= LastChar
; cp
>= Cursor
; cp
--)
176 if (Mark
&& Mark
> Cursor
)
185 Char
*cp
, *kp
= NULL
;
187 if (num
> LastChar
- Cursor
)
188 num
= (int) (LastChar
- Cursor
); /* bounds check */
190 if (num
> 0) { /* if I can delete anything */
192 kp
= UndoBuf
; /* Set Up for VI undo command */
193 UndoAction
= TCSHOP_INSERT
;
196 for (cp
= Cursor
; cp
<= LastChar
; cp
++) {
197 *kp
++ = *cp
; /* Save deleted chars into undobuf */
202 for (cp
= Cursor
; cp
+ num
<= LastChar
; cp
++)
205 /* Mark was within the range of the deleted word? */
206 if (Mark
&& Mark
> Cursor
&& Mark
<= Cursor
+num
)
208 /* Mark after the deleted word? */
209 else if (Mark
&& Mark
> Cursor
)
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
218 inputmode
= MODE_INSERT
;
224 c_delbefore(int num
) /* delete before dot, with bounds checking */
226 Char
*cp
, *kp
= NULL
;
228 if (num
> Cursor
- InputBuf
)
229 num
= (int) (Cursor
- InputBuf
); /* bounds check */
231 if (num
> 0) { /* if I can delete anything */
233 kp
= UndoBuf
; /* Set Up for VI undo command */
234 UndoAction
= TCSHOP_INSERT
;
236 UndoPtr
= Cursor
- num
;
237 for (cp
= Cursor
- num
; cp
<= LastChar
; cp
++) {
243 for (cp
= Cursor
- num
; cp
+ num
<= LastChar
; cp
++)
247 /* Mark was within the range of the deleted word? */
248 if (Mark
&& Mark
> Cursor
&& Mark
<= Cursor
+num
)
250 /* Mark after the deleted word? */
251 else if (Mark
&& Mark
> Cursor
)
257 c_preword(Char
*p
, Char
*low
, int n
, Char
*delim
)
263 while (prev
< p
) { /* Skip initial non-word chars */
264 if (!Strchr(delim
, *prev
) || *(prev
-1) == (Char
)'\\')
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
)'\\')
282 p
= prev
; /* Set to previous word start */
291 * c_to_class() returns the class of the given character.
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
299 * 2/ alphanumeric chars, + underscore
306 return C_CLASS_WHITE
;
308 if (Isdigit(ch
) || Isalpha(ch
) || ch
== '_')
309 return C_CLASS_ALNUM
;
311 return C_CLASS_OTHER
;
315 c_prev_word(Char
*p
, Char
*low
, int n
)
321 while ((p
>= low
) && !isword(*p
))
323 while ((p
>= low
) && isword(*p
))
327 /* cp now points to one character before the word */
331 /* cp now points where we want it */
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
))
346 /* if this was a non_whitespace word, we're ready */
347 if (c_class
!= C_CLASS_WHITE
)
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
))
356 p
++; /* correct overshoot */
362 c_next_word(Char
*p
, Char
*high
, int n
)
366 while ((p
< high
) && !isword(*p
))
368 while ((p
< high
) && isword(*p
))
373 /* p now points where we want it */
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
))
388 /* if this was all whitespace, we're ready */
389 if (c_class
== C_CLASS_WHITE
)
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
)
397 p
--; /* correct overshoot */
403 c_nexword(Char
*p
, Char
*high
, int n
)
406 while ((p
< high
) && !Isspace(*p
))
408 while ((p
< high
) && Isspace(*p
))
414 /* p now points where we want it */
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.
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.
431 * dval is the number to subtract from for things like $-3
435 c_number(Char
*p
, int *num
, int dval
)
446 *num
= INT_MAX
; /* Handle $ */
449 sign
= -1; /* Handle $- */
452 for (i
= 0; *p
>= '0' && *p
<= '9'; i
= 10 * i
+ *p
++ - '0')
454 *num
= (sign
< 0 ? dval
- i
: i
);
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...
468 struct Hist
*h
= Histlist
.Hnext
;
470 int i
, from
, to
, dval
;
482 switch (*(q
= p
+ 1)) {
485 buf
= expand_lex(&h
->Hlex
, 1, 1);
489 if ((l
= (h
->Hlex
).prev
) != 0)
490 buf
= expand_lex(l
->prev
->prev
, 0, 0);
494 buf
= expand_lex(&h
->Hlex
, 1, INT_MAX
);
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
);
506 if (*q
== ':') /* short form: !:arg */
511 * Search for a space, tab, or colon. See if we have a number (as
512 * in !1234:xyz). Remember the number.
514 for (i
= 0, all_dig
= 1;
515 *q
!= ' ' && *q
!= '\t' && *q
!= ':' && q
< Cursor
; q
++) {
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.
520 if ((*q
< '0' || *q
> '9') && (*q
!= '-' || q
!= p
+ 1))
523 all_dig
= 2;/* we are sneeky about this */
525 i
= 10 * i
+ *q
- '0';
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
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
) {
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
))
555 if (q
[1] == ':' || q
[1] == '-' || q
[1] == '*' ||
556 q
[1] == '$' || q
[1] == '^') { /* get some args */
557 p
= q
[1] == ':' ? ++q
: q
;
561 if ((q
[1] < '0' || q
[1] > '9') &&
562 q
[1] != '-' && q
[1] != '$' && q
[1] != '^')
567 if (q
[1] == '$' && (q
[2] != '-' || q
[3] < '0' || q
[3] > '9'))
570 * Count up the number of words in this event. Store it in dval.
571 * Dval will be fed to number.
574 if ((l
= h
->Hlex
.prev
) != 0) {
575 for (l
= l
->prev
; l
!= h
->Hlex
.next
; l
= l
->prev
, dval
++)
583 q
= c_number(q
, &from
, dval
);
586 if ((q
[1] < '0' || q
[1] > '9') && q
[1] != '$')
589 q
= c_number(q
, &to
, dval
);
591 else if (q
[1] == '*') {
598 if (from
< 0 || to
< from
)
600 buf
= expand_lex(&h
->Hlex
, from
, to
);
602 else /* get whole cmd */
603 buf
= expand_lex(&h
->Hlex
, 0, INT_MAX
);
610 * Apply modifiers, if any.
614 while (q
[1] == ':' && modbuf
!= NULL
) {
624 if ((modbuf
= domod(buf
, (int) q
[2])) != NULL
) {
633 /* Not implemented; this needs to be done before expanding
634 * lex. We don't have the words available to us anymore.
656 buf_len
= Strlen(buf
);
658 * Now replace the text from op to q inclusive with the text from buf.
663 * Now replace text non-inclusively like a real CS major!
665 if (LastChar
+ buf_len
- (q
- op
) >= InputLim
)
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
));
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)
694 * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
695 * back p up to just before the current word.
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
)
705 while (*p
!= ' ' && *p
!= '\t' && p
> InputBuf
)
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.
715 while (*p
!= HIST
&& p
< Cursor
)
717 for (i
= 1; (p
- i
) >= InputBuf
&& p
[-i
] == '\\'; i
++)
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.
739 p
> InputBuf
&& *p
!= ' ' && *p
!= '\t' && *p
!= HIST
; --p
)
743 * If we found a history character, go expand it.
751 c_delfini(void) /* Finish up delete action */
755 if (ActionFlag
& TCSHOP_INSERT
)
756 c_alternativ_key_map(0);
758 ActionFlag
= TCSHOP_NOP
;
763 UndoAction
= TCSHOP_INSERT
;
765 if (Cursor
> ActionPos
) {
766 Size
= (int) (Cursor
-ActionPos
);
770 else if (Cursor
< ActionPos
) {
771 Size
= (int)(ActionPos
-Cursor
);
783 c_endword(Char
*p
, Char
*high
, int n
, Char
*delim
)
789 while (p
< high
) { /* Skip non-word chars */
790 if (!Strchr(delim
, *p
) || *(p
-1) == (Char
)'\\')
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;
801 /* Break if unquoted non-word char */
802 if (!inquote
&& Strchr(delim
, *p
) && *(p
-1) != (Char
)'\\')
814 c_eword(Char
*p
, Char
*high
, int n
)
819 while ((p
< high
) && Isspace(*p
))
823 while ((p
< high
) && Isalnum(*p
))
826 while ((p
< high
) && !(Isspace(*p
) || Isalnum(*p
)))
834 /* Set the max length of the kill ring */
842 max
= 1; /* no ring, but always one buffer */
843 if (max
== KillRingMax
)
845 new = xcalloc(max
, sizeof(CStr
));
846 if (KillRing
!= NULL
) {
847 if (KillRingLen
!= 0) {
848 if (max
>= KillRingLen
) {
853 j
= (KillPos
- count
+ KillRingLen
) % KillRingLen
;
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
;
863 KillPos
= count
% max
;
872 /* Push string from start upto (but not including) end onto kill ring */
874 c_push_kill(Char
*start
, Char
*end
)
878 int len
= end
- start
, i
, j
, k
;
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) */
885 for (i
= 0; i
< KillRingLen
; i
++) {
886 if (Strncmp(KillRing
[j
].buf
, start
, (size_t) len
) == 0 &&
887 KillRing
[j
].buf
[len
] == '\0') {
889 for ( ; i
> 0; i
--) {
891 j
= (j
+ 1) % KillRingLen
;
892 KillRing
[k
] = KillRing
[j
];
897 j
= (j
- 1 + KillRingLen
) % KillRingLen
;
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')
904 } else if (eq(dp
, STRprev
)) { /* skip if immediately previous */
906 if (Strncmp(KillRing
[j
].buf
, start
, (size_t) len
) == 0 &&
907 KillRing
[j
].buf
[len
] == '\0')
912 /* No duplicate, go ahead and push */
913 len
++; /* need space for '\0' */
915 if (KillRingLen
< KillRingMax
)
917 pos
= &KillRing
[KillPos
];
918 KillPos
= (KillPos
+ 1) % KillRingMax
;
919 if (pos
->len
< len
) {
920 pos
->buf
= xrealloc(pos
->buf
, len
* sizeof(Char
));
930 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
935 Strbuf_append(&SavedBuf
, InputBuf
);
936 Strbuf_terminate(&SavedBuf
);
937 LastSaved
= LastChar
- InputBuf
;
938 CursSaved
= Cursor
- InputBuf
;
939 HistSaved
= Hist_num
;
949 if (Hist_num
== 0) { /* if really the current line */
950 if (HistBuf
.s
!= NULL
)
951 copyn(InputBuf
, HistBuf
.s
, INBUFSIZE
);/*FIXBUF*/
954 LastChar
= InputBuf
+ HistBuf
.len
;
970 for (h
= 1; h
< Hist_num
; h
++) {
971 if ((hp
->Hnext
) == NULL
) {
978 if (HistLit
&& hp
->histline
) {
979 copyn(InputBuf
, hp
->histline
, INBUFSIZE
);/*FIXBUF*/
985 p
= sprlex(&hp
->Hlex
);
986 copyn(InputBuf
, p
, sizeof(InputBuf
) / sizeof(Char
));/*FIXBUF*/
990 LastChar
= Strend(InputBuf
);
992 if (LastChar
> InputBuf
) {
993 if (LastChar
[-1] == '\n')
996 if (LastChar
[-1] == ' ')
999 if (LastChar
< InputBuf
)
1000 LastChar
= InputBuf
;
1014 c_search_line(Char
*pattern
, int dir
)
1019 len
= Strlen(pattern
);
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
)) {
1030 for (cp
= Cursor
; *cp
!= '\0' && cp
< InputLim
; cp
++)
1031 if (Strncmp(cp
, pattern
, len
) == 0 ||
1032 Gmatch(cp
, pattern
)) {
1041 e_inc_search(int dir
)
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];
1049 *oldCursor
= Cursor
,
1051 CCRETVAL ret
= CC_NORM
;
1052 int oldHist_num
= Hist_num
,
1053 oldpatlen
= patbuf
.len
,
1057 if (LastChar
+ sizeof(STRfwd
)/sizeof(Char
) + 2 + patbuf
.len
>= InputLim
)
1062 if (patbuf
.len
== 0) { /* first round */
1064 Strbuf_append1(&patbuf
, '*');
1068 for (cp
= newdir
== F_UP_SEARCH_HIST
? STRbck
: STRfwd
;
1069 *cp
; *LastChar
++ = *cp
++)
1071 *LastChar
++ = pchar
;
1072 for (cp
= &patbuf
.s
[1]; cp
< &patbuf
.s
[patbuf
.len
];
1073 *LastChar
++ = *cp
++)
1076 if (adrof(STRhighlight
) && pchar
== ':') {
1077 /* if the no-glob-search patch is applied, remove the - 1 below */
1078 IncMatchLen
= patbuf
.len
- 1;
1084 if (GetNextChar(&ch
) != 1)
1085 return(e_send_eof(0));
1087 switch (ch
> NT_NUM_KEYS
1088 ? F_INSERT
: CurrentKeyMap
[(unsigned char) ch
]) {
1092 if (LastChar
+ 1 >= InputLim
) /*FIXBUF*/
1095 Strbuf_append1(&patbuf
, ch
);
1103 newdir
= F_DOWN_SEARCH_HIST
;
1108 newdir
= F_UP_SEARCH_HIST
;
1121 case 0007: /* ^G: Abort */
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*/
1137 Strbuf_append1(&patbuf
, *Cursor
);
1138 *LastChar
++ = *Cursor
++;
1144 } else if (isglob(*cp
)) {
1150 default: /* Terminate and execute cmd */
1155 case 0033: /* ESC: Terminate */
1163 while (LastChar
> InputBuf
&& *LastChar
!= '\n')
1169 /* Can't search if unmatched '[' */
1170 for (cp
= &patbuf
.s
[patbuf
.len
- 1], ch
= ']'; cp
> patbuf
.s
; cp
--)
1171 if (*cp
== '[' || *cp
== ']') {
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
;
1186 Cursor
+= newdir
== F_UP_SEARCH_HIST
? -1 : 1;
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
);
1201 patbuf
.s
[--patbuf
.len
] = '\0';
1202 if (ret
== CC_ERROR
) {
1204 if (Hist_num
!= oldHist_num
) {
1205 Hist_num
= oldHist_num
;
1206 if (GetHistLine() == CC_ERROR
)
1216 ret
= e_inc_search(newdir
);
1218 if (ret
== CC_ERROR
&& pchar
== '?' && oldpchar
== ':') {
1219 /* break abort of failed search at last non-failed */
1225 if (ret
== CC_NORM
|| (ret
== CC_ERROR
&& oldpatlen
== 0)) {
1226 /* restore on normal return or error exit */
1228 patbuf
.len
= oldpatlen
;
1229 if (Hist_num
!= oldHist_num
) {
1230 Hist_num
= oldHist_num
;
1231 if (GetHistLine() == CC_ERROR
)
1235 if (ret
== CC_ERROR
)
1238 if (done
|| ret
!= CC_NORM
)
1248 struct Strbuf tmpbuf
= Strbuf_INIT
;
1253 cleanup_push(&tmpbuf
, Strbuf_cleanup
);
1254 oldbuf
= Strsave(InputBuf
);
1255 cleanup_push(oldbuf
, xfree
);
1258 Strbuf_append1(&tmpbuf
, '*');
1261 LastChar
= InputBuf
;
1265 c_insert(2); /* prompt + '\n' */
1267 *Cursor
++ = dir
== F_UP_SEARCH_HIST
? '?' : '/';
1269 for (ch
= 0;ch
== 0;) {
1270 if (GetNextChar(&ch
) != 1) {
1271 cleanup_until(&tmpbuf
);
1272 return(e_send_eof(0));
1275 case 0010: /* Delete and backspace */
1277 if (tmpbuf
.len
> 1) {
1283 copyn(InputBuf
, oldbuf
, INBUFSIZE
);/*FIXBUF*/
1286 cleanup_until(&tmpbuf
);
1293 case 0033: /* ESC */
1295 case '\r': /* Newline */
1298 case '\012': /* ASCII Line feed */
1299 case '\015': /* ASCII (or EBCDIC) Return */
1304 Strbuf_append1(&tmpbuf
, ch
);
1312 cleanup_until(oldbuf
);
1314 if (tmpbuf
.len
== 1) {
1316 * Use the old pattern, but wild-card it.
1318 if (patbuf
.len
== 0) {
1320 LastChar
= InputBuf
;
1323 cleanup_until(&tmpbuf
);
1326 if (patbuf
.s
[0] != '*') {
1327 oldbuf
= Strsave(patbuf
.s
);
1329 Strbuf_append1(&patbuf
, '*');
1330 Strbuf_append(&patbuf
, oldbuf
);
1332 Strbuf_append1(&patbuf
, '*');
1333 Strbuf_terminate(&patbuf
);
1337 Strbuf_append1(&tmpbuf
, '*');
1338 Strbuf_terminate(&tmpbuf
);
1340 Strbuf_append(&patbuf
, tmpbuf
.s
);
1341 Strbuf_terminate(&patbuf
);
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
) {
1352 if (ASC(ch
) == 0033) {
1365 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1366 * entry point, called from the CcKeyMap indirected into the
1376 ActionFlag
= TCSHOP_NOP
; /* [Esc] cancels pending action */
1379 if (UndoPtr
> Cursor
)
1380 UndoSize
= (int)(UndoPtr
- Cursor
);
1382 UndoSize
= (int)(Cursor
- UndoPtr
);
1384 inputmode
= MODE_INSERT
;
1385 c_alternativ_key_map(1);
1388 * We don't want to move the cursor, because all the editing
1389 * commands don't include the character under the cursor.
1391 if (Cursor
> InputBuf
)
1400 e_unassigned(Char c
)
1401 { /* bound to keys that arn't really assigned */
1410 e_insert_str(Char
*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
));
1420 c_insert(Argument
* n
);
1421 while (Argument
--) {
1422 for (i
= 0; i
< n
; i
++)
1433 #ifndef SHORT_STRINGS
1434 c
&= ASCII
; /* no meta chars ever */
1438 return(CC_ERROR
); /* no NULs in the input ever!! */
1440 if (LastChar
+ Argument
>= InputLim
)
1441 return(CC_ERROR
); /* end of buffer space */
1443 if (Argument
== 1) { /* How was this optimized ???? */
1445 if (inputmode
!= MODE_INSERT
) {
1446 UndoBuf
[UndoSize
++] = *Cursor
;
1447 UndoBuf
[UndoSize
] = '\0';
1448 c_delafter(1); /* Do NOT use the saving ONE */
1452 *Cursor
++ = (Char
) c
;
1453 DoingArg
= 0; /* just in case */
1454 RefPlusOne(1); /* fast refresh for one char. */
1457 if (inputmode
!= MODE_INSERT
) {
1459 for(i
= 0; i
< Argument
; i
++)
1460 UndoBuf
[UndoSize
++] = *(Cursor
+ i
);
1462 UndoBuf
[UndoSize
] = '\0';
1463 c_delafter(Argument
); /* Do NOT use the saving ONE */
1469 *Cursor
++ = (Char
) c
;
1473 if (inputmode
== MODE_REPLACE_1
)
1474 (void) v_cmd_mode(0);
1480 InsertStr(Char
*s
) /* insert ASCIZ s at cursor (for complete) */
1484 if ((len
= (int) Strlen(s
)) <= 0)
1486 if (LastChar
+ len
>= InputLim
)
1487 return -1; /* end of buffer space */
1496 DeleteBack(int n
) /* delete the n characters before . */
1500 if (Cursor
>= &InputBuf
[n
]) {
1501 c_delbefore(n
); /* delete before dot */
1506 e_digit(Char c
) /* gray magic here */
1509 return(CC_ERROR
); /* no NULs in the input ever!! */
1511 if (DoingArg
) { /* if doing an arg, add this in... */
1512 if (LastCmd
== F_ARGFOUR
) /* if last command was ^U */
1515 if (Argument
> 1000000)
1517 Argument
= (Argument
* 10) + (c
- '0');
1522 if (LastChar
+ 1 >= InputLim
)
1523 return CC_ERROR
; /* end of buffer space */
1525 if (inputmode
!= MODE_INSERT
) {
1526 UndoBuf
[UndoSize
++] = *Cursor
;
1527 UndoBuf
[UndoSize
] = '\0';
1528 c_delafter(1); /* Do NOT use the saving ONE */
1531 *Cursor
++ = (Char
) c
;
1532 DoingArg
= 0; /* just in case */
1533 RefPlusOne(1); /* fast refresh for one char. */
1539 e_argdigit(Char c
) /* for ESC-n */
1544 c
= CTL_ESC(ASC(c
) & ASCII
); /* stripping for EBCDIC done the ASCII way */
1548 return(CC_ERROR
); /* no NULs in the input ever!! */
1550 if (DoingArg
) { /* if doing an arg, add this in... */
1551 if (Argument
> 1000000)
1553 Argument
= (Argument
* 10) + (c
- '0');
1555 else { /* else starting an argument */
1563 v_zero(Char c
) /* command mode 0 for vi */
1565 if (DoingArg
) { /* if doing an arg, add this in... */
1566 if (Argument
> 1000000)
1568 Argument
= (Argument
* 10) + (c
- '0');
1571 else { /* else starting an argument */
1573 if (ActionFlag
& TCSHOP_DELETE
) {
1577 RefCursor(); /* move the cursor */
1585 { /* always ignore argument */
1587 if (adrof(STRhighlight
) && MarkIsSet
) {
1595 /* PastBottom(); NOW done in ed.inputl.c */
1596 *LastChar
++ = '\n'; /* for the benefit of CSH */
1597 *LastChar
= '\0'; /* just in case */
1599 InsertPos
= InputBuf
; /* Reset editing position */
1605 e_newline_hold(Char c
)
1610 *LastChar
++ = '\n'; /* for the benefit of CSH */
1611 *LastChar
= '\0'; /* just in case */
1617 e_newline_down_hist(Char c
)
1621 HistSaved
= Hist_num
;
1623 *LastChar
++ = '\n'; /* for the benefit of CSH */
1624 *LastChar
= '\0'; /* just in case */
1631 { /* for when ^D is ONLY send-eof */
1634 *LastChar
= '\0'; /* just in case */
1643 *LastChar
= '\0'; /* just in case */
1644 return(CC_COMPLETE
);
1649 e_complete_back(Char c
)
1652 *LastChar
= '\0'; /* just in case */
1653 return(CC_COMPLETE_BACK
);
1658 e_complete_fwd(Char c
)
1661 *LastChar
= '\0'; /* just in case */
1662 return(CC_COMPLETE_FWD
);
1667 e_complete_all(Char c
)
1670 *LastChar
= '\0'; /* just in case */
1671 return(CC_COMPLETE_ALL
);
1676 v_cm_complete(Char c
)
1679 if (Cursor
< LastChar
)
1681 *LastChar
= '\0'; /* just in case */
1682 return(CC_COMPLETE
);
1687 e_toggle_hist(Char c
)
1693 *LastChar
= '\0'; /* just in case */
1695 if (Hist_num
<= 0) {
1699 hp
= Histlist
.Hnext
;
1700 if (hp
== NULL
) { /* this is only if no history */
1704 for (h
= 1; h
< Hist_num
; h
++)
1707 if (!CurrentHistLit
) {
1709 copyn(InputBuf
, hp
->histline
, INBUFSIZE
);/*FIXBUF*/
1719 p
= sprlex(&hp
->Hlex
);
1720 copyn(InputBuf
, p
, sizeof(InputBuf
) / sizeof(Char
));/*FIXBUF*/
1725 LastChar
= Strend(InputBuf
);
1726 if (LastChar
> InputBuf
) {
1727 if (LastChar
[-1] == '\n')
1729 if (LastChar
[-1] == ' ')
1731 if (LastChar
< InputBuf
)
1732 LastChar
= InputBuf
;
1752 UndoAction
= TCSHOP_NOP
;
1753 *LastChar
= '\0'; /* just in case */
1755 if (Hist_num
== 0) { /* save the current buffer away */
1757 Strbuf_append(&HistBuf
, InputBuf
);
1758 Strbuf_terminate(&HistBuf
);
1761 Hist_num
+= Argument
;
1763 if (GetHistLine() == CC_ERROR
) {
1765 (void) GetHistLine(); /* Hist_num was fixed by first call */
1772 return(CC_NORM
); /* was CC_UP_HIST */
1780 UndoAction
= TCSHOP_NOP
;
1781 *LastChar
= '\0'; /* just in case */
1783 Hist_num
-= Argument
;
1787 return(CC_ERROR
); /* make it beep */
1790 return(GetHistLine());
1796 * c_hmatch() return True if the pattern matches the prefix
1801 if (Strncmp(patbuf
.s
, str
, patbuf
.len
) == 0)
1803 return Gmatch(str
, patbuf
.s
);
1807 * c_hsetpat(): Set the history seatch pattern
1812 if (LastCmd
!= F_UP_SEARCH_HIST
&& LastCmd
!= F_DOWN_SEARCH_HIST
) {
1814 Strbuf_appendn(&patbuf
, InputBuf
, Cursor
- InputBuf
);
1815 Strbuf_terminate(&patbuf
);
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
);
1827 e_up_search_hist(Char c
)
1834 ActionFlag
= TCSHOP_NOP
;
1835 UndoAction
= TCSHOP_NOP
;
1836 *LastChar
= '\0'; /* just in case */
1839 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname
);
1845 if (Hist_num
== 0) {
1847 Strbuf_append(&HistBuf
, InputBuf
);
1848 Strbuf_terminate(&HistBuf
);
1852 hp
= Histlist
.Hnext
;
1856 c_hsetpat(); /* Set search pattern !! */
1858 for (h
= 1; h
<= Hist_num
; h
++)
1861 while (hp
!= NULL
) {
1865 if (hp
->histline
== NULL
)
1866 hp
->histline
= sprlex(&hp
->Hlex
);
1870 hl
= sprlex(&hp
->Hlex
);
1871 cleanup_push(hl
, xfree
);
1874 xprintf("Comparing with \"%S\"\n", hl
);
1876 matched
= (Strncmp(hl
, InputBuf
, (size_t) (LastChar
- InputBuf
)) ||
1877 hl
[LastChar
-InputBuf
]) && c_hmatch(hl
);
1890 xprintf("not found\n");
1897 return(GetHistLine());
1902 e_down_search_hist(Char c
)
1909 ActionFlag
= TCSHOP_NOP
;
1910 UndoAction
= TCSHOP_NOP
;
1911 *LastChar
= '\0'; /* just in case */
1916 hp
= Histlist
.Hnext
;
1920 c_hsetpat(); /* Set search pattern !! */
1922 for (h
= 1; h
< Hist_num
&& hp
; h
++) {
1924 if (hp
->histline
== NULL
)
1925 hp
->histline
= sprlex(&hp
->Hlex
);
1929 hl
= sprlex(&hp
->Hlex
);
1930 cleanup_push(hl
, xfree
);
1933 xprintf("Comparing with \"%S\"\n", hl
);
1935 if ((Strncmp(hl
, InputBuf
, (size_t) (LastChar
- InputBuf
)) ||
1936 hl
[LastChar
-InputBuf
]) && c_hmatch(hl
))
1943 if (!found
) { /* is it the current history number? */
1944 if (!c_hmatch(HistBuf
.s
)) {
1946 xprintf("not found\n");
1954 return(GetHistLine());
1963 *LastChar
= '\0'; /* just in case */
1972 *LastChar
= '\0'; /* just in case */
1981 *LastChar
= '\0'; /* just in case */
1982 return(CC_CORRECT_L
);
1987 e_run_fg_editor(Char c
)
1992 if ((pp
= find_stop_ed()) != NULL
) {
1993 /* save our editor state so we can restore it */
1995 Hist_num
= 0; /* for the history commands */
1997 /* put the tty in a sane mode */
1999 (void) Cookedmode(); /* make sure the tty is set up correctly */
2004 (void) Rawmode(); /* go on */
2014 e_list_choices(Char c
)
2018 *LastChar
= '\0'; /* just in case */
2019 return(CC_LIST_CHOICES
);
2028 *LastChar
= '\0'; /* just in case */
2029 return(CC_LIST_ALL
);
2038 *LastChar
= '\0'; /* just in case */
2039 return(CC_LIST_GLOB
);
2044 e_expand_glob(Char c
)
2047 *LastChar
= '\0'; /* just in case */
2048 return(CC_EXPAND_GLOB
);
2053 e_normalize_path(Char c
)
2056 *LastChar
= '\0'; /* just in case */
2057 return(CC_NORMALIZE_PATH
);
2062 e_normalize_command(Char c
)
2065 *LastChar
= '\0'; /* just in case */
2066 return(CC_NORMALIZE_COMMAND
);
2071 e_expand_vars(Char c
)
2074 *LastChar
= '\0'; /* just in case */
2075 return(CC_EXPAND_VARS
);
2081 { /* do a fast command line which(1) */
2084 Hist_num
= 0; /* for the history commands */
2086 *LastChar
= '\0'; /* just in case */
2093 { /* insert the last element of the prev. cmd */
2095 struct wordent
*wp
, *firstp
;
2103 hp
= Histlist
.Hnext
;
2104 if (hp
== NULL
) { /* this is only if no history */
2108 wp
= (hp
->Hlex
).prev
;
2110 if (wp
->prev
== (struct wordent
*) NULL
)
2111 return(CC_ERROR
); /* an empty history entry */
2113 firstp
= (hp
->Hlex
).next
;
2115 /* back up arg words in lex */
2116 for (i
= 0; i
< Argument
&& wp
!= firstp
; i
++) {
2120 expanded
= expand_lex(wp
->prev
, 0, i
- 1);
2121 if (InsertStr(expanded
)) {
2132 e_dabbrev_expand(Char c
)
2133 { /* expand to preceding word matching prefix */
2134 Char
*cp
, *ncp
, *bp
;
2140 static int oldevent
, hist
, word
;
2141 static Char
*start
, *oldcursor
;
2147 cp
= c_preword(Cursor
, InputBuf
, 1, STRshwordsep
);
2148 if (cp
== Cursor
|| Isspace(*cp
))
2152 hp
= Histlist
.Hnext
;
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
++)
2161 if (hp
== NULL
) /* "can't happen" */
2163 hbuf
= expand_lex(&hp
->Hlex
, 0, INT_MAX
);
2168 cp
= c_preword(cp
, bp
, word
, STRshwordsep
);
2169 } else { /* starting new search */
2173 Strbuf_appendn(&patbuf
, cp
, Cursor
- cp
);
2179 ncp
= c_preword(cp
, bp
, 1, STRshwordsep
);
2180 if (ncp
== cp
|| Isspace(*ncp
)) { /* beginning of line */
2185 hbuf
= expand_lex(&hp
->Hlex
, 0, INT_MAX
);
2192 len
= c_endword(ncp
-1, cp
, 1, STRshwordsep
) - ncp
+ 1;
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
)
2200 } else { /* match if distinct from previous */
2201 if (len
!= (size_t)(Cursor
- start
)
2202 || Strncmp(cp
, start
, len
) != 0)
2208 if (LastChar
+ len
- (Cursor
- start
) >= InputLim
)
2209 goto err_hbuf
; /* no room */
2210 DeleteBack(Cursor
- start
);
2226 { /* almost like GnuEmacs */
2231 if (KillRingLen
== 0) /* nothing killed */
2233 len
= Strlen(KillRing
[YankPos
].buf
);
2234 if (LastChar
+ len
>= InputLim
)
2235 return(CC_ERROR
); /* end of buffer space */
2238 cp
= Cursor
; /* for speed */
2240 c_insert(len
); /* open the space, */
2241 for (kp
= KillRing
[YankPos
].buf
; *kp
; kp
++) /* copy the chars */
2244 if (Argument
== 1) { /* if no arg */
2245 Mark
= Cursor
; /* mark at beginning, cursor at end */
2248 Mark
= cp
; /* else cursor at beginning, mark at end */
2251 if (adrof(STRhighlight
) && MarkIsSet
) {
2262 { /* almost like GnuEmacs */
2263 int m_bef_c
, del_len
, ins_len
;
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
)
2279 if (KillRingLen
== 0) /* nothing killed */
2281 YankPos
-= Argument
;
2283 YankPos
+= KillRingLen
;
2284 YankPos
%= KillRingLen
;
2286 if (Cursor
> Mark
) {
2287 del_len
= Cursor
- Mark
;
2290 del_len
= Mark
- Cursor
;
2293 ins_len
= Strlen(KillRing
[YankPos
].buf
);
2294 if (LastChar
+ ins_len
- del_len
>= InputLim
)
2295 return(CC_ERROR
); /* end of buffer space */
2298 c_delbefore(del_len
);
2300 c_delafter(del_len
);
2302 cp
= Cursor
; /* for speed */
2304 c_insert(ins_len
); /* open the space, */
2305 for (kp
= KillRing
[YankPos
].buf
; *kp
; kp
++) /* copy the chars */
2309 Mark
= Cursor
; /* mark at beginning, cursor at end */
2312 Mark
= cp
; /* else cursor at beginning, mark at end */
2315 if (adrof(STRhighlight
) && MarkIsSet
) {
2325 v_delprev(Char c
) /* Backspace key in insert mode */
2332 if (InsertPos
!= 0) {
2333 if (Argument
<= Cursor
- InsertPos
) {
2334 c_delbefore(Argument
); /* delete before */
2346 if (Cursor
> InputBuf
) {
2347 c_delbefore(Argument
); /* delete before dot */
2357 e_delwordprev(Char c
)
2362 if (Cursor
== InputBuf
)
2366 cp
= c_prev_word(Cursor
, InputBuf
, Argument
);
2368 c_push_kill(cp
, Cursor
); /* save the text */
2370 c_delbefore((int)(Cursor
- cp
)); /* delete before dot */
2374 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
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
2380 * Old names: New names:
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
2394 * (no old equivalent) delete-char-or-list
2400 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2401 /* rename e_delnext() -> e_delnext_eof() */
2407 if (Cursor
== LastChar
) {/* if I'm at the end */
2412 if (Cursor
!= InputBuf
)
2418 c_delafter(Argument
); /* delete after dot */
2419 if (Cursor
> LastChar
)
2420 Cursor
= LastChar
; /* bounds check */
2427 e_delnext_eof(Char c
)
2430 if (Cursor
== LastChar
) {/* if I'm at the end */
2432 if (Cursor
== InputBuf
) {
2433 /* if I'm also at the beginning */
2434 so_write(STReof
, 4);/* then do a EOF */
2442 if (Cursor
!= InputBuf
)
2448 c_delafter(Argument
); /* delete after dot */
2449 if (Cursor
> LastChar
)
2450 Cursor
= LastChar
; /* bounds check */
2456 e_delnext_list(Char c
)
2459 if (Cursor
== LastChar
) { /* if I'm at the end */
2461 *LastChar
= '\0'; /* just in case */
2462 return(CC_LIST_CHOICES
);
2465 c_delafter(Argument
); /* delete after dot */
2466 if (Cursor
> LastChar
)
2467 Cursor
= LastChar
; /* bounds check */
2474 e_delnext_list_eof(Char 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 */
2485 *LastChar
= '\0'; /* just in case */
2486 return(CC_LIST_CHOICES
);
2490 c_delafter(Argument
); /* delete after dot */
2491 if (Cursor
> LastChar
)
2492 Cursor
= LastChar
; /* bounds check */
2504 if (Cursor
== LastChar
&& Cursor
== InputBuf
) {
2505 so_write(STReof
, 4); /* then do a EOF */
2511 *LastChar
= '\0'; /* just in case */
2512 rv
= CC_LIST_CHOICES
;
2519 e_delwordnext(Char c
)
2524 if (Cursor
== LastChar
)
2528 cp
= c_next_word(Cursor
, LastChar
, Argument
);
2530 c_push_kill(Cursor
, cp
); /* save the text */
2532 c_delafter((int)(cp
- Cursor
)); /* delete after dot */
2533 if (Cursor
> LastChar
)
2534 Cursor
= LastChar
; /* bounds check */
2545 if (ActionFlag
& TCSHOP_DELETE
) {
2549 RefCursor(); /* move the cursor */
2561 while (Isspace(*Cursor
)) /* We want FIRST non space character */
2563 if (ActionFlag
& TCSHOP_DELETE
) {
2569 RefCursor(); /* move the cursor */
2578 c_push_kill(Cursor
, LastChar
); /* copy it */
2579 LastChar
= Cursor
; /* zap! -- delete to end */
2592 c_push_kill(InputBuf
, Cursor
); /* copy it */
2593 c_delbefore((int)(Cursor
- InputBuf
));
2594 if (Mark
&& Mark
> Cursor
)
2595 Mark
-= Cursor
-InputBuf
;
2604 c_push_kill(InputBuf
, LastChar
); /* copy it */
2605 Cursor
= Mark
= LastChar
= InputBuf
; /* zap! -- delete all of it */
2612 e_killregion(Char c
)
2618 if (Mark
> Cursor
) {
2619 c_push_kill(Cursor
, Mark
); /* copy it */
2620 c_delafter((int)(Mark
- Cursor
)); /* delete it - UNUSED BY VI mode */
2623 else { /* mark is before cursor */
2624 c_push_kill(Mark
, Cursor
); /* copy it */
2625 c_delbefore((int)(Cursor
- Mark
));
2627 if (adrof(STRhighlight
) && MarkIsSet
) {
2637 e_copyregion(Char c
)
2643 if (Mark
> Cursor
) {
2644 c_push_kill(Cursor
, Mark
); /* copy it */
2646 else { /* mark is before cursor */
2647 c_push_kill(Mark
, Cursor
); /* copy it */
2649 return(CC_NORM
); /* don't even need to Refresh() */
2654 e_charswitch(Char cc
)
2660 /* do nothing if we are at beginning of line or have only one char */
2661 if (Cursor
== &InputBuf
[0] || LastChar
== &InputBuf
[1]) {
2665 if (Cursor
< LastChar
) {
2669 Cursor
[-2] = Cursor
[-1];
2676 e_gcharswitch(Char cc
)
2677 { /* gosmacs style ^T */
2681 if (Cursor
> &InputBuf
[1]) {/* must have at least two chars entered */
2683 Cursor
[-2] = Cursor
[-1];
2697 if (Cursor
> InputBuf
) {
2698 if (Argument
> Cursor
- InputBuf
)
2704 if (ActionFlag
& TCSHOP_DELETE
) {
2722 if (Cursor
== InputBuf
)
2726 Cursor
= c_preword(Cursor
, InputBuf
, Argument
, STRshwspace
); /* bounds check */
2728 if (ActionFlag
& TCSHOP_DELETE
) {
2742 if (Cursor
== InputBuf
)
2746 Cursor
= c_prev_word(Cursor
, InputBuf
, Argument
); /* bounds check */
2749 if (ActionFlag
& TCSHOP_DELETE
) {
2763 if (Cursor
< LastChar
) {
2765 if (Cursor
> LastChar
)
2769 if (ActionFlag
& TCSHOP_DELETE
) {
2787 if (Cursor
== LastChar
)
2791 Cursor
= c_next_word(Cursor
, LastChar
, Argument
);
2794 if (ActionFlag
& TCSHOP_DELETE
) {
2808 if (Cursor
== LastChar
)
2812 Cursor
= c_nexword(Cursor
, LastChar
, Argument
);
2815 if (ActionFlag
& TCSHOP_DELETE
) {
2826 v_wordbegnext(Char c
)
2829 if (Cursor
== LastChar
)
2833 Cursor
= c_next_word(Cursor
, LastChar
, Argument
);
2834 if (Cursor
< LastChar
)
2838 if (ActionFlag
& TCSHOP_DELETE
) {
2849 v_repeat_srch(int c
)
2851 CCRETVAL rv
= CC_ERROR
;
2853 xprintf("dir %d patlen %d patbuf %S\n",
2854 c
, (int)patbuf
.len
, patbuf
.s
);
2857 LastCmd
= (KEYCMD
) c
; /* Hack to stop c_hsetpat */
2858 LastChar
= InputBuf
;
2860 case F_DOWN_SEARCH_HIST
:
2861 rv
= e_down_search_hist(0);
2863 case F_UP_SEARCH_HIST
:
2864 rv
= e_up_search_hist(0);
2873 v_csearch_back(Char ch
, int count
, int tflag
)
2881 while (cp
> InputBuf
&& *cp
!= ch
)
2885 if (cp
< InputBuf
|| (cp
== InputBuf
&& *cp
!= ch
))
2888 if (*cp
== ch
&& tflag
)
2893 if (ActionFlag
& TCSHOP_DELETE
) {
2904 v_csearch_fwd(Char ch
, int count
, int tflag
)
2912 while (cp
< LastChar
&& *cp
!= ch
)
2919 if (*cp
== ch
&& tflag
)
2924 if (ActionFlag
& TCSHOP_DELETE
) {
2939 if (ActionFlag
== TCSHOP_DELETE
) {
2940 ActionFlag
= TCSHOP_NOP
;
2945 for (cp
= InputBuf
; cp
< LastChar
; cp
++) {
2950 UndoAction
= TCSHOP_INSERT
;
2952 LastChar
= InputBuf
;
2954 if (c
& TCSHOP_INSERT
)
2955 c_alternativ_key_map(0);
2960 else if (ActionFlag
== TCSHOP_NOP
) {
2964 return(CC_ARGHACK
); /* Do NOT clear out argument */
2976 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2978 c_get_word(Char
**begin
, Char
**end
)
2983 while (Argument
--) {
2984 while ((cp
<= LastChar
) && (isword(*cp
)))
2987 while ((cp
>= InputBuf
) && (isword(*cp
)))
2992 #endif /* COMMENT */
3001 end
= c_next_word(Cursor
, LastChar
, Argument
);
3003 for (cp
= Cursor
; cp
< end
; cp
++) /* PWP: was cp=begin */
3008 if (Cursor
> LastChar
)
3016 e_capitolcase(Char c
)
3021 end
= c_next_word(Cursor
, LastChar
, Argument
);
3024 for (; cp
< end
; cp
++) {
3032 for (; cp
< end
; cp
++)
3037 if (Cursor
> LastChar
)
3049 end
= c_next_word(Cursor
, LastChar
, Argument
);
3051 for (cp
= Cursor
; cp
< end
; cp
++)
3056 if (Cursor
> LastChar
)
3067 if (adrof(STRhighlight
) && MarkIsSet
&& Mark
!= Cursor
) {
3079 e_exchange_mark(Char c
)
3094 { /* multiply current argument by 4 */
3096 if (Argument
> 1000000)
3104 quote_mode_cleanup(void *unused
)
3119 cleanup_push(&c
, quote_mode_cleanup
); /* Using &c just as a mark */
3120 num
= GetNextChar(&ch
);
3123 return e_insert(ch
);
3125 return e_send_eof(0);
3134 return(CC_ARGHACK
); /* preserve argument */
3140 e_extendnext(Char c
)
3142 CurrentKeyMap
= CcAltMap
;
3143 return(CC_ARGHACK
); /* preserve argument */
3151 { /* move to beginning of line and start vi
3158 UndoAction
= TCSHOP_DELETE
;
3160 RefCursor(); /* move the cursor */
3161 c_alternativ_key_map(0);
3168 { /* vi mode overwrite one character */
3170 c_alternativ_key_map(0);
3171 inputmode
= MODE_REPLACE_1
;
3172 UndoAction
= TCSHOP_CHANGE
; /* Set Up for VI undo command */
3181 { /* vi mode start overwriting */
3183 c_alternativ_key_map(0);
3184 inputmode
= MODE_REPLACE
;
3185 UndoAction
= TCSHOP_CHANGE
; /* Set Up for VI undo command */
3194 { /* vi mode substitute for one char */
3196 c_delafter(Argument
);
3197 c_alternativ_key_map(0);
3204 { /* vi mode replace whole line */
3206 (void) e_killall(0);
3207 c_alternativ_key_map(0);
3214 { /* vi mode change to end of line */
3216 (void) e_killend(0);
3217 c_alternativ_key_map(0);
3224 { /* vi mode start inserting */
3226 c_alternativ_key_map(0);
3230 UndoAction
= TCSHOP_DELETE
;
3238 { /* vi mode start adding */
3240 c_alternativ_key_map(0);
3241 if (Cursor
< LastChar
)
3244 if (Cursor
> LastChar
)
3251 UndoAction
= TCSHOP_DELETE
;
3259 { /* vi mode to add at end of line */
3261 c_alternativ_key_map(0);
3264 InsertPos
= LastChar
; /* Mark where insertion begins */
3266 UndoAction
= TCSHOP_DELETE
;
3274 v_change_case(Char cc
)
3279 if (Cursor
< LastChar
) {
3280 #ifndef WINNT_NATIVE
3284 #endif /* WINNT_NATIVE */
3286 *Cursor
++ = Tolower(c
);
3287 else if (Islower(c
))
3288 *Cursor
++ = Toupper(c
);
3291 RefPlusOne(1); /* fast refresh for one char */
3304 for (p
= InputBuf
; Isspace(*p
); p
++)
3311 return(e_newline(0));
3317 { /* erase all of current line, start again */
3319 ResetInLine(0); /* reset the input pointers */
3338 ClearScreen(); /* clear the whole real screen */
3339 ClearDisp(); /* reset everything */
3348 #if defined(_MINIX) || defined(WINNT_NATIVE)
3349 /* SAK PATCH: erase all of current line, start again */
3350 ResetInLine(0); /* reset the input pointers */
3353 return (CC_REFRESH
);
3354 #else /* !_MINIX && !WINNT_NATIVE */
3357 #endif /* _MINIX || WINNT_NATIVE */
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
3367 e_stuff_char(Char c
)
3370 int was_raw
= Tty_raw_mode
;
3371 char buf
[MB_LEN_MAX
];
3375 (void) Cookedmode();
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
]);
3384 return(e_redisp(c
));
3385 #else /* !TIOCSTI */
3387 #endif /* !TIOCSTI */
3395 inputmode
= (inputmode
== MODE_INSERT
? MODE_REPLACE
: MODE_INSERT
);
3410 e_tty_flusho(Char c
)
3446 e_expand_history(Char c
)
3449 *LastChar
= '\0'; /* just in case */
3456 e_magic_space(Char c
)
3459 *LastChar
= '\0'; /* just in case */
3461 return(e_insert(' '));
3473 ret
= e_inc_search(F_DOWN_SEARCH_HIST
);
3474 if (adrof(STRhighlight
) && IncMatchLen
) {
3494 ret
= e_inc_search(F_UP_SEARCH_HIST
);
3495 if (adrof(STRhighlight
) && IncMatchLen
) {
3509 Char
*cp
, *oldc
, *dp
;
3512 if (Cursor
== InputBuf
)
3517 /* does a bounds check */
3518 cp
= c_prev_word(Cursor
, InputBuf
, Argument
);
3520 c_insert((int)(oldc
- cp
));
3521 for (dp
= oldc
; cp
< oldc
&& dp
< LastChar
; cp
++)
3524 Cursor
= dp
; /* put cursor at end */
3531 e_tty_starto(Char c
)
3540 e_load_average(Char c
)
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)
3549 if (ioctl(SHIN
, TIOCSTAT
, (ioctl_t
) &c
) < 0)
3551 xprintf(CGETS(5, 1, "Load average unavailable\n"));
3561 * Delete with insert == change: first we delete and then we leave in
3564 return(v_action(TCSHOP_DELETE
|TCSHOP_INSERT
));
3572 return(v_action(TCSHOP_DELETE
));
3581 if (Cursor
== LastChar
)
3585 Cursor
= c_endword(Cursor
, LastChar
, Argument
, STRshwspace
);
3587 if (ActionFlag
& TCSHOP_DELETE
)
3603 if (Cursor
== LastChar
)
3607 Cursor
= c_eword(Cursor
, LastChar
, Argument
);
3609 if (ActionFlag
& TCSHOP_DELETE
) {
3626 if (GetNextChar(&ch
) != 1)
3627 return e_send_eof(0);
3629 srch_dir
= CHAR_FWD
;
3632 return v_csearch_fwd(ch
, Argument
, 0);
3643 if (GetNextChar(&ch
) != 1)
3644 return e_send_eof(0);
3646 srch_dir
= CHAR_BACK
;
3649 return v_csearch_back(ch
, Argument
, 0);
3654 v_charto_fwd(Char c
)
3659 if (GetNextChar(&ch
) != 1)
3660 return e_send_eof(0);
3662 return v_csearch_fwd(ch
, Argument
, 1);
3668 v_charto_back(Char c
)
3673 if (GetNextChar(&ch
) != 1)
3674 return e_send_eof(0);
3676 return v_csearch_back(ch
, Argument
, 1);
3687 return srch_dir
== CHAR_FWD
? v_csearch_fwd(srch_char
, Argument
, 0) :
3688 v_csearch_back(srch_char
, Argument
, 0);
3693 v_rchar_back(Char c
)
3699 return srch_dir
== CHAR_BACK
? v_csearch_fwd(srch_char
, Argument
, 0) :
3700 v_csearch_back(srch_char
, Argument
, 0);
3713 switch (UndoAction
) {
3714 case TCSHOP_DELETE
|TCSHOP_INSERT
:
3716 if (UndoSize
== 0) return(CC_NORM
);
3719 for (loop
=0; loop
< UndoSize
; loop
++) /* copy the chars */
3720 *kp
++ = *cp
++; /* into UndoBuf */
3722 for (cp
= UndoPtr
; cp
<= LastChar
; cp
++)
3725 LastChar
-= UndoSize
;
3728 UndoAction
= TCSHOP_INSERT
;
3732 if (UndoSize
== 0) return(CC_NORM
);
3736 c_insert(UndoSize
); /* open the space, */
3737 for (loop
= 0; loop
< UndoSize
; loop
++) /* copy the chars */
3740 UndoAction
= TCSHOP_DELETE
;
3744 if (UndoSize
== 0) return(CC_NORM
);
3748 size
= (int)(Cursor
-LastChar
); /* NOT NSL independant */
3749 if (size
< UndoSize
)
3751 for(loop
= 0; loop
< size
; loop
++) {
3770 return v_search(F_UP_SEARCH_HIST
);
3778 return v_search(F_DOWN_SEARCH_HIST
);
3786 if (patbuf
.len
== 0) return(CC_ERROR
);
3787 return(v_repeat_srch(searchdir
));
3792 v_rsrch_back(Char 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
));
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
3805 e_copy_to_clipboard(Char c
)
3812 e_paste_from_clipboard(Char c
)
3819 e_dosify_next(Char c
)
3825 e_dosify_prev(Char c
)
3842 #endif /* !WINNT_NATIVE */
3846 MoveCursor(int n
) /* move cursor + right - left char */
3848 Cursor
= Cursor
+ n
;
3849 if (Cursor
< InputBuf
)
3851 if (Cursor
> LastChar
)
3865 if (p
< InputBuf
|| p
> LastChar
)
3866 return 1; /* Error */