2 * ed.chared.c: Character editing functions.
5 * Copyright (c) 1980, 1991 The Regents of the University of California.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 Bjorn Knutsson @ Thu Jun 24 19:02:17 1999
35 e_dabbrev_expand() did not do proper completion if quoted spaces were present
36 in the string being completed. Exemple:
40 # echo h<press key bound to dabbrev-expande>
44 # echo h<press key bound to dabbrev-expande>
45 # echo hello\ world<cursor>
47 The same problem occurred if spaces were present in a string withing
48 quotation marks. Example:
52 # echo "h<press key bound to dabbrev-expande>
55 The former problem could be solved with minor modifications of c_preword()
56 and c_endword(). The latter, however, required a significant rewrite of
57 c_preword(), since quoted strings must be parsed from start to end to
58 determine if a given character is inside or outside the quotation marks.
60 Compare the following two strings:
62 # echo \"" 'foo \' bar\"
64 # echo '\"" 'foo \' bar\"
67 The only difference between the two echo lines is in the first character
68 after the echo command. The result is either one or three arguments.
79 #define TCSHOP_NOP 0x00
80 #define TCSHOP_DELETE 0x01
81 #define TCSHOP_INSERT 0x02
82 #define TCSHOP_CHANGE 0x04
89 * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com>
91 #define C_CLASS_WHITE 1
92 #define C_CLASS_WORD 2
93 #define C_CLASS_OTHER 3
95 static Char
*InsertPos
= InputBuf
; /* Where insertion starts */
96 static Char
*ActionPos
= 0; /* Where action begins */
97 static int ActionFlag
= TCSHOP_NOP
; /* What delayed action to take */
101 static int searchdir
= F_UP_SEARCH_HIST
; /* Direction of last search */
102 static struct Strbuf patbuf
; /* = Strbuf_INIT; Search target */
106 static int srch_dir
= CHAR_FWD
; /* Direction of last search */
107 static Char srch_char
= 0; /* Search target */
109 /* all routines that start with c_ are private to this set of routines */
110 static void c_alternativ_key_map (int);
112 void c_delafter (int);
113 void c_delbefore (int);
114 static int c_to_class (Char
);
115 static Char
*c_prev_word (Char
*, Char
*, int);
116 static Char
*c_next_word (Char
*, Char
*, int);
117 static Char
*c_number (Char
*, int *, int);
118 static Char
*c_expand (Char
*);
119 static int c_excl (Char
*);
120 static int c_substitute (void);
121 static void c_delfini (void);
122 static int c_hmatch (Char
*);
123 static void c_hsetpat (void);
125 static void c_get_word (Char
**, Char
**);
127 static Char
*c_preword (Char
*, Char
*, int, Char
*);
128 static Char
*c_nexword (Char
*, Char
*, int);
129 static Char
*c_endword (Char
*, Char
*, Char
*, int, Char
*);
130 static Char
*c_eword (Char
*, Char
*, int);
131 static void c_push_kill (Char
*, Char
*);
132 static void c_save_inputbuf (void);
133 static CCRETVAL
c_search_line (Char
*, int);
134 static CCRETVAL
v_repeat_srch (int);
135 static CCRETVAL
e_inc_search (int);
137 static CCRETVAL
e_insert_str (Char
*);
139 static CCRETVAL
v_search (int);
140 static CCRETVAL
v_csearch_fwd (Char
, int, int);
141 static CCRETVAL
v_action (int);
142 static CCRETVAL
v_csearch_back (Char
, int, int);
145 c_alternativ_key_map(int state
)
149 CurrentKeyMap
= CcKeyMap
;
152 CurrentKeyMap
= CcAltMap
;
158 AltKeyMap
= (Char
) state
;
166 if (LastChar
+ num
>= InputLim
)
167 return; /* can't go past end of buffer */
169 if (Cursor
< LastChar
) { /* if I must move chars */
170 for (cp
= LastChar
; cp
>= Cursor
; cp
--)
172 if (Mark
&& Mark
> Cursor
)
181 Char
*cp
, *kp
= NULL
;
183 if (num
> LastChar
- Cursor
)
184 num
= (int) (LastChar
- Cursor
); /* bounds check */
186 if (num
> 0) { /* if I can delete anything */
188 kp
= UndoBuf
; /* Set Up for VI undo command */
189 UndoAction
= TCSHOP_INSERT
;
192 for (cp
= Cursor
; cp
<= LastChar
; cp
++) {
193 *kp
++ = *cp
; /* Save deleted chars into undobuf */
198 for (cp
= Cursor
; cp
+ num
<= LastChar
; cp
++)
201 /* Mark was within the range of the deleted word? */
202 if (Mark
&& Mark
> Cursor
&& Mark
<= Cursor
+num
)
204 /* Mark after the deleted word? */
205 else if (Mark
&& Mark
> Cursor
)
211 * XXX: We don't want to do that. In emacs mode overwrite should be
212 * sticky. I am not sure how that affects vi mode
214 inputmode
= MODE_INSERT
;
220 c_delbefore(int num
) /* delete before dot, with bounds checking */
222 Char
*cp
, *kp
= NULL
;
224 if (num
> Cursor
- InputBuf
)
225 num
= (int) (Cursor
- InputBuf
); /* bounds check */
227 if (num
> 0) { /* if I can delete anything */
229 kp
= UndoBuf
; /* Set Up for VI undo command */
230 UndoAction
= TCSHOP_INSERT
;
232 UndoPtr
= Cursor
- num
;
233 for (cp
= Cursor
- num
; cp
<= LastChar
; cp
++) {
239 for (cp
= Cursor
- num
; cp
+ num
<= LastChar
; cp
++)
243 /* Mark was within the range of the deleted word? */
244 if (Mark
&& Mark
> Cursor
&& Mark
<= Cursor
+num
)
246 /* Mark after the deleted word? */
247 else if (Mark
&& Mark
> Cursor
)
253 c_preword(Char
*p
, Char
*low
, int n
, Char
*delim
)
259 while (prev
< p
) { /* Skip initial non-word chars */
260 if (!Strchr(delim
, *prev
) || (prev
> low
&& prev
[-1] == (Char
)'\\'))
269 new = c_endword(prev
-1, low
, p
, 1, delim
); /* Skip to next non-word char */
270 new++; /* Step away from end of word */
271 while (new <= p
) { /* Skip trailing non-word chars */
272 if (!Strchr(delim
, *new) || (new > prev
&& new[-1] == (Char
)'\\'))
278 p
= prev
; /* Set to previous word start */
287 * c_to_class() returns the class of the given character.
289 * This is used to make the c_prev_word(), c_next_word() and c_eword() functions
290 * work like vi's, which classify characters. A word is a sequence of
291 * characters belonging to the same class, classes being defined as
295 * 2/ alphanumeric chars, + underscore
302 return C_CLASS_WHITE
;
307 return C_CLASS_OTHER
;
311 c_prev_word(Char
*p
, Char
*low
, int n
)
317 while ((p
>= low
) && !isword(*p
))
319 while ((p
>= low
) && isword(*p
))
323 /* cp now points to one character before the word */
327 /* cp now points where we want it */
337 /* scan until beginning of current word (may be all whitespace!) */
338 c_class
= c_to_class(*p
);
339 while ((p
>= low
) && c_class
== c_to_class(*p
))
342 /* if this was a non_whitespace word, we're ready */
343 if (c_class
!= C_CLASS_WHITE
)
346 /* otherwise, move back to beginning of the word just found */
347 c_class
= c_to_class(*p
);
348 while ((p
>= low
) && c_class
== c_to_class(*p
))
352 p
++; /* correct overshoot */
358 c_next_word(Char
*p
, Char
*high
, int n
)
362 while ((p
< high
) && !isword(*p
))
364 while ((p
< high
) && isword(*p
))
369 /* p now points where we want it */
379 /* scan until end of current word (may be all whitespace!) */
380 c_class
= c_to_class(*p
);
381 while ((p
< high
) && c_class
== c_to_class(*p
))
384 /* if this was all whitespace, we're ready */
385 if (c_class
== C_CLASS_WHITE
)
388 /* if we've found white-space at the end of the word, skip it */
389 while ((p
< high
) && c_to_class(*p
) == C_CLASS_WHITE
)
393 p
--; /* correct overshoot */
399 c_nexword(Char
*p
, Char
*high
, int n
)
402 while ((p
< high
) && !Isspace(*p
))
404 while ((p
< high
) && Isspace(*p
))
410 /* p now points where we want it */
415 * Expand-History (originally "Magic-Space") code added by
416 * Ray Moody <ray@gibbs.physics.purdue.edu>
417 * this is a neat, but odd, addition.
421 * c_number: Ignore character p points to, return number appearing after that.
422 * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
423 * Return p pointing to last char used.
427 * dval is the number to subtract from for things like $-3
431 c_number(Char
*p
, int *num
, int dval
)
442 *num
= INT_MAX
; /* Handle $ */
445 sign
= -1; /* Handle $- */
448 for (i
= 0; *p
>= '0' && *p
<= '9'; i
= 10 * i
+ *p
++ - '0')
450 *num
= (sign
< 0 ? dval
- i
: i
);
455 * excl_expand: There is an excl to be expanded to p -- do the right thing
456 * with it and return a version of p advanced over the expanded stuff. Also,
457 * update tsh_cur and related things as appropriate...
464 struct Hist
*h
= Histlist
.Hnext
;
466 int i
, from
, to
, dval
;
478 switch (*(q
= p
+ 1)) {
481 buf
= expand_lex(&h
->Hlex
, 1, 1);
485 if ((l
= (h
->Hlex
).prev
) != 0)
486 buf
= expand_lex(l
->prev
->prev
, 0, 0);
490 buf
= expand_lex(&h
->Hlex
, 1, INT_MAX
);
494 if (been_once
) { /* unknown argument */
495 /* assume it's a modifier, e.g. !foo:h, and get whole cmd */
496 buf
= expand_lex(&h
->Hlex
, 0, INT_MAX
);
502 if (*q
== ':') /* short form: !:arg */
505 if (HIST
!= '\0' && *q
!= HIST
) {
507 * Search for a space, tab, or colon. See if we have a number (as
508 * in !1234:xyz). Remember the number.
510 for (i
= 0, all_dig
= 1;
511 *q
!= ' ' && *q
!= '\t' && *q
!= ':' && q
< Cursor
; q
++) {
513 * PWP: !-4 is a valid history argument too, therefore the test
514 * is if not a digit, or not a - as the first character.
516 if ((*q
< '0' || *q
> '9') && (*q
!= '-' || q
!= p
+ 1))
519 all_dig
= 2;/* we are sneeky about this */
521 i
= 10 * i
+ *q
- '0';
526 * If we have a number, search for event i. Otherwise, search for
527 * a named event (as in !foo). (In this case, I is the length of
532 i
= -i
; /* make it negitive */
533 if (i
< 0) /* if !-4 (for example) */
534 i
= eventno
+ 1 + i
; /* remember: i is < 0 */
535 for (; h
; h
= h
->Hnext
) {
541 for (i
= (int) (q
- p
); h
; h
= h
->Hnext
) {
542 if ((l
= &h
->Hlex
) != 0) {
543 if (!Strncmp(p
+ 1, l
->next
->word
, (size_t) i
))
551 if (q
[1] == ':' || q
[1] == '-' || q
[1] == '*' ||
552 q
[1] == '$' || q
[1] == '^') { /* get some args */
553 p
= q
[1] == ':' ? ++q
: q
;
557 if ((q
[1] < '0' || q
[1] > '9') &&
558 q
[1] != '-' && q
[1] != '$' && q
[1] != '^')
563 if (q
[1] == '$' && (q
[2] != '-' || q
[3] < '0' || q
[3] > '9'))
566 * Count up the number of words in this event. Store it in dval.
567 * Dval will be fed to number.
570 if ((l
= h
->Hlex
.prev
) != 0) {
571 for (l
= l
->prev
; l
!= h
->Hlex
.next
; l
= l
->prev
, dval
++)
579 q
= c_number(q
, &from
, dval
);
582 if ((q
[1] < '0' || q
[1] > '9') && q
[1] != '$')
585 q
= c_number(q
, &to
, dval
);
587 else if (q
[1] == '*') {
594 if (from
< 0 || to
< from
)
596 buf
= expand_lex(&h
->Hlex
, from
, to
);
598 else /* get whole cmd */
599 buf
= expand_lex(&h
->Hlex
, 0, INT_MAX
);
606 * Apply modifiers, if any.
610 while (q
[1] == ':' && modbuf
!= NULL
) {
620 if ((modbuf
= domod(buf
, (int) q
[2])) != NULL
) {
629 /* Not implemented; this needs to be done before expanding
630 * lex. We don't have the words available to us anymore.
652 buf_len
= Strlen(buf
);
654 * Now replace the text from op to q inclusive with the text from buf.
659 * Now replace text non-inclusively like a real CS major!
661 if (LastChar
+ buf_len
- (q
- op
) >= InputLim
)
663 (void) memmove(op
+ buf_len
, q
, (LastChar
- q
) * sizeof(Char
));
664 LastChar
+= buf_len
- (q
- op
);
665 Cursor
+= buf_len
- (q
- op
);
666 (void) memcpy(op
, buf
, buf_len
* sizeof(Char
));
677 * c_excl: An excl has been found at point p -- back up and find some white
678 * space (or the beginning of the buffer) and properly expand all the excl's
679 * from there up to the current cursor position. We also avoid (trying to)
681 * Returns number of expansions attempted (doesn't matter whether they succeeded
693 * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
694 * back p up to just before the current word.
696 if ((p
[1] == ' ' || p
[1] == '\t') &&
697 (p
[-1] == ' ' || p
[-1] == '\t' || p
[-1] == '>')) {
698 for (q
= p
- 1; q
> InputBuf
&& (*q
== ' ' || *q
== '\t'); --q
)
704 while (*p
!= ' ' && *p
!= '\t' && p
> InputBuf
)
709 * Forever: Look for history char. (Stop looking when we find the cursor.)
710 * Count backslashes. If odd, skip history char. Expand if even number of
716 while (*p
!= HIST
&& p
< Cursor
)
718 for (i
= 1; (p
- i
) >= InputBuf
&& p
[-i
] == '\\'; i
++)
722 if (p
>= Cursor
) /* all done */
739 * Start p out one character before the cursor. Move it backwards looking
740 * for white space, the beginning of the line, or a history character.
743 p
> InputBuf
&& *p
!= ' ' && *p
!= '\t' && *p
&& *p
!= HIST
; --p
)
747 * If we found a history character, go expand it.
749 if (p
>= InputBuf
&& HIST
!= '\0' && *p
== HIST
)
759 c_delfini(void) /* Finish up delete action */
763 if (ActionFlag
& TCSHOP_INSERT
)
764 c_alternativ_key_map(0);
766 ActionFlag
= TCSHOP_NOP
;
771 UndoAction
= TCSHOP_INSERT
;
773 if (Cursor
> ActionPos
) {
774 Size
= (int) (Cursor
-ActionPos
);
778 else if (Cursor
< ActionPos
) {
779 Size
= (int)(ActionPos
-Cursor
);
791 c_endword(Char
*p
, Char
*low
, Char
*high
, int n
, Char
*delim
)
797 while (p
< high
) { /* Skip non-word chars */
798 if (!Strchr(delim
, *p
) || p
[-1] == (Char
)'\\')
802 while (p
< high
) { /* Skip string */
803 if ((*p
== (Char
)'\'' || *p
== (Char
)'"')) { /* Quotation marks? */
804 /* Should it be honored? */
805 if (inquote
|| (p
> low
&& p
[-1] != (Char
)'\\')) {
806 if (inquote
== 0) inquote
= *p
;
807 else if (inquote
== *p
) inquote
= 0;
810 /* Break if unquoted non-word char */
811 if (!inquote
&& Strchr(delim
, *p
) && p
> low
&& p
[-1] != (Char
)'\\')
823 c_eword(Char
*p
, Char
*high
, int n
)
833 /* scan until end of current word (may be all whitespace!) */
834 c_class
= c_to_class(*p
);
835 while ((p
< high
) && c_class
== c_to_class(*p
))
838 /* if this was a non_whitespace word, we're ready */
839 if (c_class
!= C_CLASS_WHITE
)
842 /* otherwise, move to the end of the word just found */
843 c_class
= c_to_class(*p
);
844 while ((p
< high
) && c_class
== c_to_class(*p
))
852 /* Set the max length of the kill ring */
860 max
= 1; /* no ring, but always one buffer */
861 if (max
== KillRingMax
)
863 new = xcalloc(max
, sizeof(CStr
));
864 if (KillRing
!= NULL
) {
865 if (KillRingLen
!= 0) {
866 if (max
>= KillRingLen
) {
871 j
= (KillPos
- count
+ KillRingLen
) % KillRingLen
;
873 for (i
= 0; i
< KillRingLen
; i
++) {
874 if (i
< count
) /* copy latest */
875 new[i
] = KillRing
[j
];
876 else /* free the others */
877 xfree(KillRing
[j
].buf
);
878 j
= (j
+ 1) % KillRingLen
;
881 KillPos
= count
% max
;
890 /* Push string from start upto (but not including) end onto kill ring */
892 c_push_kill(Char
*start
, Char
*end
)
896 int len
= end
- start
, i
, j
, k
;
898 /* Check for duplicates? */
899 if (KillRingLen
> 0 && (dp
= varval(STRkilldup
)) != STRNULL
) {
900 YankPos
= (KillPos
- 1 + KillRingLen
) % KillRingLen
;
901 if (eq(dp
, STRerase
)) { /* erase earlier one (actually move up) */
903 for (i
= 0; i
< KillRingLen
; i
++) {
904 if (Strncmp(KillRing
[j
].buf
, start
, (size_t) len
) == 0 &&
905 KillRing
[j
].buf
[len
] == '\0') {
907 for ( ; i
> 0; i
--) {
909 j
= (j
+ 1) % KillRingLen
;
910 KillRing
[k
] = KillRing
[j
];
915 j
= (j
- 1 + KillRingLen
) % KillRingLen
;
917 } else if (eq(dp
, STRall
)) { /* skip if any earlier */
918 for (i
= 0; i
< KillRingLen
; i
++)
919 if (Strncmp(KillRing
[i
].buf
, start
, (size_t) len
) == 0 &&
920 KillRing
[i
].buf
[len
] == '\0')
922 } else if (eq(dp
, STRprev
)) { /* skip if immediately previous */
924 if (Strncmp(KillRing
[j
].buf
, start
, (size_t) len
) == 0 &&
925 KillRing
[j
].buf
[len
] == '\0')
930 /* No duplicate, go ahead and push */
931 len
++; /* need space for '\0' */
933 if (KillRingLen
< KillRingMax
)
935 pos
= &KillRing
[KillPos
];
936 KillPos
= (KillPos
+ 1) % KillRingMax
;
937 if (pos
->len
< len
) {
938 pos
->buf
= xrealloc(pos
->buf
, len
* sizeof(Char
));
948 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
950 c_save_inputbuf(void)
953 Strbuf_append(&SavedBuf
, InputBuf
);
954 Strbuf_terminate(&SavedBuf
);
955 LastSaved
= LastChar
- InputBuf
;
956 CursSaved
= Cursor
- InputBuf
;
957 HistSaved
= Hist_num
;
967 if (Hist_num
== 0) { /* if really the current line */
968 if (HistBuf
.s
!= NULL
)
969 copyn(InputBuf
, HistBuf
.s
, INBUFSIZE
);/*FIXBUF*/
972 LastChar
= InputBuf
+ HistBuf
.len
;
988 for (h
= 1; h
< Hist_num
; h
++) {
989 if ((hp
->Hnext
) == NULL
) {
996 if (HistLit
&& hp
->histline
) {
997 copyn(InputBuf
, hp
->histline
, INBUFSIZE
);/*FIXBUF*/
1003 p
= sprlex(&hp
->Hlex
);
1004 copyn(InputBuf
, p
, sizeof(InputBuf
) / sizeof(Char
));/*FIXBUF*/
1008 LastChar
= Strend(InputBuf
);
1010 if (LastChar
> InputBuf
) {
1011 if (LastChar
[-1] == '\n')
1014 if (LastChar
[-1] == ' ')
1017 if (LastChar
< InputBuf
)
1018 LastChar
= InputBuf
;
1032 c_search_line(Char
*pattern
, int dir
)
1037 len
= Strlen(pattern
);
1039 if (dir
== F_UP_SEARCH_HIST
) {
1040 for (cp
= Cursor
; cp
>= InputBuf
; cp
--)
1041 if (Strncmp(cp
, pattern
, len
) == 0 ||
1042 Gmatch(cp
, pattern
)) {
1048 for (cp
= Cursor
; *cp
!= '\0' && cp
< InputLim
; cp
++)
1049 if (Strncmp(cp
, pattern
, len
) == 0 ||
1050 Gmatch(cp
, pattern
)) {
1059 e_inc_search(int dir
)
1061 static const Char STRfwd
[] = { 'f', 'w', 'd', '\0' },
1062 STRbck
[] = { 'b', 'c', 'k', '\0' };
1063 static Char pchar
= ':'; /* ':' = normal, '?' = failed */
1064 static Char endcmd
[2];
1067 *oldCursor
= Cursor
,
1069 CCRETVAL ret
= CC_NORM
;
1070 int oldHist_num
= Hist_num
,
1071 oldpatlen
= patbuf
.len
,
1075 if (LastChar
+ sizeof(STRfwd
)/sizeof(Char
) + 2 + patbuf
.len
>= InputLim
)
1080 if (patbuf
.len
== 0) { /* first round */
1082 Strbuf_append1(&patbuf
, '*');
1086 for (cp
= newdir
== F_UP_SEARCH_HIST
? STRbck
: STRfwd
;
1087 *cp
; *LastChar
++ = *cp
++)
1089 *LastChar
++ = pchar
;
1090 for (cp
= &patbuf
.s
[1]; cp
< &patbuf
.s
[patbuf
.len
];
1091 *LastChar
++ = *cp
++)
1094 if (adrof(STRhighlight
) && pchar
== ':') {
1095 /* if the no-glob-search patch is applied, remove the - 1 below */
1096 IncMatchLen
= patbuf
.len
- 1;
1102 if (GetNextChar(&ch
) != 1)
1103 return(e_send_eof(0));
1105 switch (GetCmdChar(ch
)) {
1109 if (LastChar
+ 1 >= InputLim
) /*FIXBUF*/
1112 Strbuf_append1(&patbuf
, ch
);
1120 newdir
= F_DOWN_SEARCH_HIST
;
1125 newdir
= F_UP_SEARCH_HIST
;
1138 case 0007: /* ^G: Abort */
1143 case 0027: /* ^W: Append word */
1144 /* No can do if globbing characters in pattern */
1145 for (cp
= &patbuf
.s
[1]; ; cp
++)
1146 if (cp
>= &patbuf
.s
[patbuf
.len
]) {
1147 Cursor
+= patbuf
.len
- 1;
1148 cp
= c_next_word(Cursor
, LastChar
, 1);
1149 while (Cursor
< cp
&& *Cursor
!= '\n') {
1150 if (LastChar
+ 1 >= InputLim
) {/*FIXBUF*/
1154 Strbuf_append1(&patbuf
, *Cursor
);
1155 *LastChar
++ = *Cursor
++;
1161 } else if (isglob(*cp
)) {
1167 default: /* Terminate and execute cmd */
1172 case 0033: /* ESC: Terminate */
1180 while (LastChar
> InputBuf
&& *LastChar
!= '\n')
1186 /* Can't search if unmatched '[' */
1187 for (cp
= &patbuf
.s
[patbuf
.len
- 1], ch
= ']'; cp
> patbuf
.s
; cp
--)
1188 if (*cp
== '[' || *cp
== ']') {
1193 if (patbuf
.len
> 1 && ch
!= '[') {
1194 if (redo
&& newdir
== dir
) {
1195 if (pchar
== '?') { /* wrap around */
1196 Hist_num
= newdir
== F_UP_SEARCH_HIST
? 0 : INT_MAX
;
1197 if (GetHistLine() == CC_ERROR
)
1198 /* Hist_num was fixed by first call */
1199 (void) GetHistLine();
1200 Cursor
= newdir
== F_UP_SEARCH_HIST
?
1201 LastChar
: InputBuf
;
1203 Cursor
+= newdir
== F_UP_SEARCH_HIST
? -1 : 1;
1205 Strbuf_append1(&patbuf
, '*');
1206 Strbuf_terminate(&patbuf
);
1207 if (Cursor
< InputBuf
|| Cursor
> LastChar
||
1208 (ret
= c_search_line(&patbuf
.s
[1], newdir
)) == CC_ERROR
) {
1209 LastCmd
= (KEYCMD
) newdir
; /* avoid c_hsetpat */
1210 ret
= newdir
== F_UP_SEARCH_HIST
?
1211 e_up_search_hist(0) : e_down_search_hist(0);
1212 if (ret
!= CC_ERROR
) {
1213 Cursor
= newdir
== F_UP_SEARCH_HIST
?
1214 LastChar
: InputBuf
;
1215 (void) c_search_line(&patbuf
.s
[1], newdir
);
1218 patbuf
.s
[--patbuf
.len
] = '\0';
1219 if (ret
== CC_ERROR
) {
1221 if (Hist_num
!= oldHist_num
) {
1222 Hist_num
= oldHist_num
;
1223 if (GetHistLine() == CC_ERROR
)
1233 ret
= e_inc_search(newdir
);
1235 if (ret
== CC_ERROR
&& pchar
== '?' && oldpchar
== ':') {
1236 /* break abort of failed search at last non-failed */
1242 if (ret
== CC_NORM
|| (ret
== CC_ERROR
&& oldpatlen
== 0)) {
1243 /* restore on normal return or error exit */
1245 patbuf
.len
= oldpatlen
;
1246 if (Hist_num
!= oldHist_num
) {
1247 Hist_num
= oldHist_num
;
1248 if (GetHistLine() == CC_ERROR
)
1252 if (ret
== CC_ERROR
)
1255 if (done
|| ret
!= CC_NORM
)
1265 struct Strbuf tmpbuf
= Strbuf_INIT
;
1270 cleanup_push(&tmpbuf
, Strbuf_cleanup
);
1271 oldbuf
= Strsave(InputBuf
);
1272 cleanup_push(oldbuf
, xfree
);
1275 Strbuf_append1(&tmpbuf
, '*');
1278 LastChar
= InputBuf
;
1282 c_insert(2); /* prompt + '\n' */
1284 *Cursor
++ = dir
== F_UP_SEARCH_HIST
? '?' : '/';
1286 for (ch
= 0;ch
== 0;) {
1287 if (GetNextChar(&ch
) != 1) {
1288 cleanup_until(&tmpbuf
);
1289 return(e_send_eof(0));
1292 case 0010: /* Delete and backspace */
1294 if (tmpbuf
.len
> 1) {
1300 copyn(InputBuf
, oldbuf
, INBUFSIZE
);/*FIXBUF*/
1303 cleanup_until(&tmpbuf
);
1310 case 0033: /* ESC */
1312 case '\r': /* Newline */
1315 case '\012': /* ASCII Line feed */
1316 case '\015': /* ASCII (or EBCDIC) Return */
1321 Strbuf_append1(&tmpbuf
, ch
);
1329 cleanup_until(oldbuf
);
1331 if (tmpbuf
.len
== 1) {
1333 * Use the old pattern, but wild-card it.
1335 if (patbuf
.len
== 0) {
1337 LastChar
= InputBuf
;
1340 cleanup_until(&tmpbuf
);
1343 if (patbuf
.s
[0] != '*') {
1344 oldbuf
= Strsave(patbuf
.s
);
1346 Strbuf_append1(&patbuf
, '*');
1347 Strbuf_append(&patbuf
, oldbuf
);
1349 Strbuf_append1(&patbuf
, '*');
1350 Strbuf_terminate(&patbuf
);
1354 Strbuf_append1(&tmpbuf
, '*');
1355 Strbuf_terminate(&tmpbuf
);
1357 Strbuf_append(&patbuf
, tmpbuf
.s
);
1358 Strbuf_terminate(&patbuf
);
1360 cleanup_until(&tmpbuf
);
1361 LastCmd
= (KEYCMD
) dir
; /* avoid c_hsetpat */
1362 Cursor
= LastChar
= InputBuf
;
1363 if ((dir
== F_UP_SEARCH_HIST
? e_up_search_hist(0) :
1364 e_down_search_hist(0)) == CC_ERROR
) {
1369 if (ASC(ch
) == 0033) {
1382 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1383 * entry point, called from the CcKeyMap indirected into the
1393 ActionFlag
= TCSHOP_NOP
; /* [Esc] cancels pending action */
1396 if (UndoPtr
> Cursor
)
1397 UndoSize
= (int)(UndoPtr
- Cursor
);
1399 UndoSize
= (int)(Cursor
- UndoPtr
);
1401 inputmode
= MODE_INSERT
;
1402 c_alternativ_key_map(1);
1405 * We don't want to move the cursor, because all the editing
1406 * commands don't include the character under the cursor.
1408 if (Cursor
> InputBuf
)
1417 e_unassigned(Char c
)
1418 { /* bound to keys that arn't really assigned */
1427 e_insert_str(Char
*c
)
1432 if (LastChar
+ Argument
* n
>= InputLim
)
1433 return(CC_ERROR
); /* end of buffer space */
1434 if (inputmode
!= MODE_INSERT
) {
1435 c_delafter(Argument
* Strlen(c
));
1437 c_insert(Argument
* n
);
1438 while (Argument
--) {
1439 for (i
= 0; i
< n
; i
++)
1450 #ifndef SHORT_STRINGS
1451 c
&= ASCII
; /* no meta chars ever */
1455 return(CC_ERROR
); /* no NULs in the input ever!! */
1457 if (LastChar
+ Argument
>= InputLim
)
1458 return(CC_ERROR
); /* end of buffer space */
1460 if (Argument
== 1) { /* How was this optimized ???? */
1462 if (inputmode
!= MODE_INSERT
) {
1463 UndoBuf
[UndoSize
++] = *Cursor
;
1464 UndoBuf
[UndoSize
] = '\0';
1465 c_delafter(1); /* Do NOT use the saving ONE */
1469 *Cursor
++ = (Char
) c
;
1470 DoingArg
= 0; /* just in case */
1471 RefPlusOne(1); /* fast refresh for one char. */
1474 if (inputmode
!= MODE_INSERT
) {
1476 for (i
= 0; i
< Argument
; i
++)
1477 UndoBuf
[UndoSize
++] = Cursor
[i
];
1479 UndoBuf
[UndoSize
] = '\0';
1480 c_delafter(Argument
); /* Do NOT use the saving ONE */
1486 *Cursor
++ = (Char
) c
;
1490 if (inputmode
== MODE_REPLACE_1
)
1491 (void) v_cmd_mode(0);
1497 InsertStr(Char
*s
) /* insert ASCIZ s at cursor (for complete) */
1501 if ((len
= (int) Strlen(s
)) <= 0)
1503 if (LastChar
+ len
>= InputLim
)
1504 return -1; /* end of buffer space */
1513 DeleteBack(int n
) /* delete the n characters before . */
1517 if (Cursor
>= &InputBuf
[n
]) {
1518 c_delbefore(n
); /* delete before dot */
1523 e_digit(Char c
) /* gray magic here */
1526 return(CC_ERROR
); /* no NULs in the input ever!! */
1528 if (DoingArg
) { /* if doing an arg, add this in... */
1529 if (LastCmd
== F_ARGFOUR
) /* if last command was ^U */
1532 if (Argument
> 1000000)
1534 Argument
= (Argument
* 10) + (c
- '0');
1539 if (LastChar
+ 1 >= InputLim
)
1540 return CC_ERROR
; /* end of buffer space */
1542 if (inputmode
!= MODE_INSERT
) {
1543 UndoBuf
[UndoSize
++] = *Cursor
;
1544 UndoBuf
[UndoSize
] = '\0';
1545 c_delafter(1); /* Do NOT use the saving ONE */
1548 *Cursor
++ = (Char
) c
;
1549 DoingArg
= 0; /* just in case */
1550 RefPlusOne(1); /* fast refresh for one char. */
1556 e_argdigit(Char c
) /* for ESC-n */
1561 c
= CTL_ESC(ASC(c
) & ASCII
); /* stripping for EBCDIC done the ASCII way */
1565 return(CC_ERROR
); /* no NULs in the input ever!! */
1567 if (DoingArg
) { /* if doing an arg, add this in... */
1568 if (Argument
> 1000000)
1570 Argument
= (Argument
* 10) + (c
- '0');
1572 else { /* else starting an argument */
1580 v_zero(Char c
) /* command mode 0 for vi */
1582 if (DoingArg
) { /* if doing an arg, add this in... */
1583 if (Argument
> 1000000)
1585 Argument
= (Argument
* 10) + (c
- '0');
1588 else { /* else starting an argument */
1590 if (ActionFlag
& TCSHOP_DELETE
) {
1594 RefCursor(); /* move the cursor */
1602 { /* always ignore argument */
1604 if (adrof(STRhighlight
) && MarkIsSet
) {
1612 /* PastBottom(); NOW done in ed.inputl.c */
1613 *LastChar
++ = '\n'; /* for the benefit of CSH */
1614 *LastChar
= '\0'; /* just in case */
1616 InsertPos
= InputBuf
; /* Reset editing position */
1622 e_newline_hold(Char c
)
1627 *LastChar
++ = '\n'; /* for the benefit of CSH */
1628 *LastChar
= '\0'; /* just in case */
1634 e_newline_down_hist(Char c
)
1638 HistSaved
= Hist_num
;
1640 *LastChar
++ = '\n'; /* for the benefit of CSH */
1641 *LastChar
= '\0'; /* just in case */
1648 { /* for when ^D is ONLY send-eof */
1651 *LastChar
= '\0'; /* just in case */
1660 *LastChar
= '\0'; /* just in case */
1661 return(CC_COMPLETE
);
1666 e_complete_back(Char c
)
1669 *LastChar
= '\0'; /* just in case */
1670 return(CC_COMPLETE_BACK
);
1675 e_complete_fwd(Char c
)
1678 *LastChar
= '\0'; /* just in case */
1679 return(CC_COMPLETE_FWD
);
1684 e_complete_all(Char c
)
1687 *LastChar
= '\0'; /* just in case */
1688 return(CC_COMPLETE_ALL
);
1693 v_cm_complete(Char c
)
1696 if (Cursor
< LastChar
)
1698 *LastChar
= '\0'; /* just in case */
1699 return(CC_COMPLETE
);
1704 e_toggle_hist(Char c
)
1710 *LastChar
= '\0'; /* just in case */
1712 if (Hist_num
<= 0) {
1716 hp
= Histlist
.Hnext
;
1717 if (hp
== NULL
) { /* this is only if no history */
1721 for (h
= 1; h
< Hist_num
; h
++)
1724 if (!CurrentHistLit
) {
1726 copyn(InputBuf
, hp
->histline
, INBUFSIZE
);/*FIXBUF*/
1736 p
= sprlex(&hp
->Hlex
);
1737 copyn(InputBuf
, p
, sizeof(InputBuf
) / sizeof(Char
));/*FIXBUF*/
1742 LastChar
= Strend(InputBuf
);
1743 if (LastChar
> InputBuf
) {
1744 if (LastChar
[-1] == '\n')
1746 if (LastChar
[-1] == ' ')
1748 if (LastChar
< InputBuf
)
1749 LastChar
= InputBuf
;
1769 UndoAction
= TCSHOP_NOP
;
1770 *LastChar
= '\0'; /* just in case */
1772 if (Hist_num
== 0) { /* save the current buffer away */
1774 Strbuf_append(&HistBuf
, InputBuf
);
1775 Strbuf_terminate(&HistBuf
);
1778 Hist_num
+= Argument
;
1780 if (GetHistLine() == CC_ERROR
) {
1782 (void) GetHistLine(); /* Hist_num was fixed by first call */
1789 return(CC_NORM
); /* was CC_UP_HIST */
1797 UndoAction
= TCSHOP_NOP
;
1798 *LastChar
= '\0'; /* just in case */
1800 Hist_num
-= Argument
;
1804 return(CC_ERROR
); /* make it beep */
1807 return(GetHistLine());
1813 * c_hmatch() return True if the pattern matches the prefix
1818 if (Strncmp(patbuf
.s
, str
, patbuf
.len
) == 0)
1820 return Gmatch(str
, patbuf
.s
);
1824 * c_hsetpat(): Set the history seatch pattern
1829 if (LastCmd
!= F_UP_SEARCH_HIST
&& LastCmd
!= F_DOWN_SEARCH_HIST
) {
1831 Strbuf_appendn(&patbuf
, InputBuf
, Cursor
- InputBuf
);
1832 Strbuf_terminate(&patbuf
);
1835 xprintf("\nHist_num = %d\n", Hist_num
);
1836 xprintf("patlen = %d\n", (int)patbuf
.len
);
1837 xprintf("patbuf = \"%S\"\n", patbuf
.s
);
1838 xprintf("Cursor %d LastChar %d\n", Cursor
- InputBuf
, LastChar
- InputBuf
);
1844 e_up_search_hist(Char c
)
1851 ActionFlag
= TCSHOP_NOP
;
1852 UndoAction
= TCSHOP_NOP
;
1853 *LastChar
= '\0'; /* just in case */
1856 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname
);
1862 if (Hist_num
== 0) {
1864 Strbuf_append(&HistBuf
, InputBuf
);
1865 Strbuf_terminate(&HistBuf
);
1869 hp
= Histlist
.Hnext
;
1873 c_hsetpat(); /* Set search pattern !! */
1875 for (h
= 1; h
<= Hist_num
; h
++)
1878 while (hp
!= NULL
) {
1882 if (hp
->histline
== NULL
)
1883 hp
->histline
= sprlex(&hp
->Hlex
);
1887 hl
= sprlex(&hp
->Hlex
);
1888 cleanup_push(hl
, xfree
);
1891 xprintf("Comparing with \"%S\"\n", hl
);
1893 matched
= (Strncmp(hl
, InputBuf
, (size_t) (LastChar
- InputBuf
)) ||
1894 hl
[LastChar
-InputBuf
]) && c_hmatch(hl
);
1907 xprintf("not found\n");
1914 return(GetHistLine());
1919 e_down_search_hist(Char c
)
1926 ActionFlag
= TCSHOP_NOP
;
1927 UndoAction
= TCSHOP_NOP
;
1928 *LastChar
= '\0'; /* just in case */
1933 hp
= Histlist
.Hnext
;
1937 c_hsetpat(); /* Set search pattern !! */
1939 for (h
= 1; h
< Hist_num
&& hp
; h
++) {
1941 if (hp
->histline
== NULL
)
1942 hp
->histline
= sprlex(&hp
->Hlex
);
1946 hl
= sprlex(&hp
->Hlex
);
1947 cleanup_push(hl
, xfree
);
1950 xprintf("Comparing with \"%S\"\n", hl
);
1952 if ((Strncmp(hl
, InputBuf
, (size_t) (LastChar
- InputBuf
)) ||
1953 hl
[LastChar
-InputBuf
]) && c_hmatch(hl
))
1960 if (!found
) { /* is it the current history number? */
1961 if (!c_hmatch(HistBuf
.s
)) {
1963 xprintf("not found\n");
1971 return(GetHistLine());
1980 *LastChar
= '\0'; /* just in case */
1989 *LastChar
= '\0'; /* just in case */
1998 *LastChar
= '\0'; /* just in case */
1999 return(CC_CORRECT_L
);
2004 e_run_fg_editor(Char c
)
2009 if ((pp
= find_stop_ed()) != NULL
) {
2010 /* save our editor state so we can restore it */
2012 Hist_num
= 0; /* for the history commands */
2014 /* put the tty in a sane mode */
2016 (void) Cookedmode(); /* make sure the tty is set up correctly */
2021 (void) Rawmode(); /* go on */
2031 e_list_choices(Char c
)
2035 *LastChar
= '\0'; /* just in case */
2036 return(CC_LIST_CHOICES
);
2045 *LastChar
= '\0'; /* just in case */
2046 return(CC_LIST_ALL
);
2055 *LastChar
= '\0'; /* just in case */
2056 return(CC_LIST_GLOB
);
2061 e_expand_glob(Char c
)
2064 *LastChar
= '\0'; /* just in case */
2065 return(CC_EXPAND_GLOB
);
2070 e_normalize_path(Char c
)
2073 *LastChar
= '\0'; /* just in case */
2074 return(CC_NORMALIZE_PATH
);
2079 e_normalize_command(Char c
)
2082 *LastChar
= '\0'; /* just in case */
2083 return(CC_NORMALIZE_COMMAND
);
2088 e_expand_vars(Char c
)
2091 *LastChar
= '\0'; /* just in case */
2092 return(CC_EXPAND_VARS
);
2098 { /* do a fast command line which(1) */
2101 Hist_num
= 0; /* for the history commands */
2103 *LastChar
= '\0'; /* just in case */
2110 { /* insert the last element of the prev. cmd */
2112 struct wordent
*wp
, *firstp
;
2120 hp
= Histlist
.Hnext
;
2121 if (hp
== NULL
) { /* this is only if no history */
2125 wp
= (hp
->Hlex
).prev
;
2127 if (wp
->prev
== (struct wordent
*) NULL
)
2128 return(CC_ERROR
); /* an empty history entry */
2130 firstp
= (hp
->Hlex
).next
;
2132 /* back up arg words in lex */
2133 for (i
= 0; i
< Argument
&& wp
!= firstp
; i
++) {
2137 expanded
= expand_lex(wp
->prev
, 0, i
- 1);
2138 if (InsertStr(expanded
)) {
2149 e_dabbrev_expand(Char c
)
2150 { /* expand to preceding word matching prefix */
2151 Char
*cp
, *ncp
, *bp
;
2157 static int oldevent
, hist
, word
;
2158 static Char
*start
, *oldcursor
;
2164 cp
= c_preword(Cursor
, InputBuf
, 1, STRshwordsep
);
2165 if (cp
== Cursor
|| Isspace(*cp
))
2169 hp
= Histlist
.Hnext
;
2171 if (Argument
== 1 && eventno
== oldevent
&& cp
== start
&&
2172 Cursor
== oldcursor
&& patbuf
.len
> 0
2173 && Strncmp(patbuf
.s
, cp
, patbuf
.len
) == 0){
2174 /* continue previous search - go to last match (hist/word) */
2175 if (hist
!= 0) { /* need to move up history */
2176 for (i
= 1; i
< hist
&& hp
!= NULL
; i
++)
2178 if (hp
== NULL
) /* "can't happen" */
2180 hbuf
= expand_lex(&hp
->Hlex
, 0, INT_MAX
);
2185 cp
= c_preword(cp
, bp
, word
, STRshwordsep
);
2186 } else { /* starting new search */
2190 Strbuf_appendn(&patbuf
, cp
, Cursor
- cp
);
2196 ncp
= c_preword(cp
, bp
, 1, STRshwordsep
);
2197 if (ncp
== cp
|| Isspace(*ncp
)) { /* beginning of line */
2202 hbuf
= expand_lex(&hp
->Hlex
, 0, INT_MAX
);
2209 len
= c_endword(ncp
-1, InputBuf
, cp
, 1, STRshwordsep
) - ncp
+ 1;
2212 if (len
> patbuf
.len
&& Strncmp(cp
, patbuf
.s
, patbuf
.len
) == 0) {
2213 /* We don't fully check distinct matches as Gnuemacs does: */
2214 if (Argument
> 1) { /* just count matches */
2215 if (++arg
>= Argument
)
2217 } else { /* match if distinct from previous */
2218 if (len
!= (size_t)(Cursor
- start
)
2219 || Strncmp(cp
, start
, len
) != 0)
2225 if (LastChar
+ len
- (Cursor
- start
) >= InputLim
)
2226 goto err_hbuf
; /* no room */
2227 DeleteBack(Cursor
- start
);
2243 { /* almost like GnuEmacs */
2248 if (KillRingLen
== 0) /* nothing killed */
2250 len
= Strlen(KillRing
[YankPos
].buf
);
2251 if (LastChar
+ len
>= InputLim
)
2252 return(CC_ERROR
); /* end of buffer space */
2255 cp
= Cursor
; /* for speed */
2257 c_insert(len
); /* open the space, */
2258 for (kp
= KillRing
[YankPos
].buf
; *kp
; kp
++) /* copy the chars */
2261 if (Argument
== 1) { /* if no arg */
2262 Mark
= Cursor
; /* mark at beginning, cursor at end */
2265 Mark
= cp
; /* else cursor at beginning, mark at end */
2268 if (adrof(STRhighlight
) && MarkIsSet
) {
2279 { /* almost like GnuEmacs */
2280 int m_bef_c
, del_len
, ins_len
;
2286 /* XXX This "should" be here, but doesn't work, since LastCmd
2287 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2288 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2289 second one will "succeed" even if the first one wasn't preceded
2290 by a yank, and giving an argument is impossible. Now we "succeed"
2291 regardless of previous command, which is wrong too of course. */
2292 if (LastCmd
!= F_YANK_KILL
&& LastCmd
!= F_YANK_POP
)
2296 if (KillRingLen
== 0) /* nothing killed */
2298 YankPos
-= Argument
;
2300 YankPos
+= KillRingLen
;
2301 YankPos
%= KillRingLen
;
2303 if (Cursor
> Mark
) {
2304 del_len
= Cursor
- Mark
;
2307 del_len
= Mark
- Cursor
;
2310 ins_len
= Strlen(KillRing
[YankPos
].buf
);
2311 if (LastChar
+ ins_len
- del_len
>= InputLim
)
2312 return(CC_ERROR
); /* end of buffer space */
2315 c_delbefore(del_len
);
2317 c_delafter(del_len
);
2319 cp
= Cursor
; /* for speed */
2321 c_insert(ins_len
); /* open the space, */
2322 for (kp
= KillRing
[YankPos
].buf
; *kp
; kp
++) /* copy the chars */
2326 Mark
= Cursor
; /* mark at beginning, cursor at end */
2329 Mark
= cp
; /* else cursor at beginning, mark at end */
2332 if (adrof(STRhighlight
) && MarkIsSet
) {
2342 v_delprev(Char c
) /* Backspace key in insert mode */
2349 if (InsertPos
!= 0) {
2350 if (Argument
<= Cursor
- InsertPos
) {
2351 c_delbefore(Argument
); /* delete before */
2363 if (Cursor
> InputBuf
) {
2364 c_delbefore(Argument
); /* delete before dot */
2374 e_delwordprev(Char c
)
2379 if (Cursor
== InputBuf
)
2383 cp
= c_prev_word(Cursor
, InputBuf
, Argument
);
2385 c_push_kill(cp
, Cursor
); /* save the text */
2387 c_delbefore((int)(Cursor
- cp
)); /* delete before dot */
2391 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2393 * Changed the names of some of the ^D family of editor functions to
2394 * correspond to what they actually do and created new e_delnext_list
2397 * Old names: New names:
2399 * delete-char delete-char-or-eof
2400 * F_DELNEXT F_DELNEXT_EOF
2401 * e_delnext e_delnext_eof
2402 * edelnxt edelnxteof
2403 * delete-char-or-eof delete-char
2404 * F_DELNEXT_EOF F_DELNEXT
2405 * e_delnext_eof e_delnext
2406 * edelnxteof edelnxt
2407 * delete-char-or-list delete-char-or-list-or-eof
2408 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
2409 * e_list_delnext e_delnext_list_eof
2411 * (no old equivalent) delete-char-or-list
2417 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2418 /* rename e_delnext() -> e_delnext_eof() */
2424 if (Cursor
== LastChar
) {/* if I'm at the end */
2429 if (Cursor
!= InputBuf
)
2435 c_delafter(Argument
); /* delete after dot */
2436 if (Cursor
> LastChar
)
2437 Cursor
= LastChar
; /* bounds check */
2444 e_delnext_eof(Char c
)
2447 if (Cursor
== LastChar
) {/* if I'm at the end */
2449 if (Cursor
== InputBuf
) {
2450 /* if I'm also at the beginning */
2451 so_write(STReof
, 4);/* then do a EOF */
2459 if (Cursor
!= InputBuf
)
2465 c_delafter(Argument
); /* delete after dot */
2466 if (Cursor
> LastChar
)
2467 Cursor
= LastChar
; /* bounds check */
2473 e_delnext_list(Char c
)
2476 if (Cursor
== LastChar
) { /* if I'm at the end */
2478 *LastChar
= '\0'; /* just in case */
2479 return(CC_LIST_CHOICES
);
2482 c_delafter(Argument
); /* delete after dot */
2483 if (Cursor
> LastChar
)
2484 Cursor
= LastChar
; /* bounds check */
2491 e_delnext_list_eof(Char c
)
2494 if (Cursor
== LastChar
) { /* if I'm at the end */
2495 if (Cursor
== InputBuf
) { /* if I'm also at the beginning */
2496 so_write(STReof
, 4);/* then do a EOF */
2502 *LastChar
= '\0'; /* just in case */
2503 return(CC_LIST_CHOICES
);
2507 c_delafter(Argument
); /* delete after dot */
2508 if (Cursor
> LastChar
)
2509 Cursor
= LastChar
; /* bounds check */
2521 if (Cursor
== LastChar
&& Cursor
== InputBuf
) {
2522 so_write(STReof
, 4); /* then do a EOF */
2528 *LastChar
= '\0'; /* just in case */
2529 rv
= CC_LIST_CHOICES
;
2536 e_delwordnext(Char c
)
2541 if (Cursor
== LastChar
)
2545 cp
= c_next_word(Cursor
, LastChar
, Argument
);
2547 c_push_kill(Cursor
, cp
); /* save the text */
2549 c_delafter((int)(cp
- Cursor
)); /* delete after dot */
2550 if (Cursor
> LastChar
)
2551 Cursor
= LastChar
; /* bounds check */
2562 if (ActionFlag
& TCSHOP_DELETE
) {
2566 RefCursor(); /* move the cursor */
2578 while (Isspace(*Cursor
)) /* We want FIRST non space character */
2580 if (ActionFlag
& TCSHOP_DELETE
) {
2586 RefCursor(); /* move the cursor */
2595 c_push_kill(Cursor
, LastChar
); /* copy it */
2596 LastChar
= Cursor
; /* zap! -- delete to end */
2609 c_push_kill(InputBuf
, Cursor
); /* copy it */
2610 c_delbefore((int)(Cursor
- InputBuf
));
2611 if (Mark
&& Mark
> Cursor
)
2612 Mark
-= Cursor
-InputBuf
;
2621 c_push_kill(InputBuf
, LastChar
); /* copy it */
2622 Cursor
= Mark
= LastChar
= InputBuf
; /* zap! -- delete all of it */
2629 e_killregion(Char c
)
2635 if (Mark
> Cursor
) {
2636 c_push_kill(Cursor
, Mark
); /* copy it */
2637 c_delafter((int)(Mark
- Cursor
)); /* delete it - UNUSED BY VI mode */
2640 else { /* mark is before cursor */
2641 c_push_kill(Mark
, Cursor
); /* copy it */
2642 c_delbefore((int)(Cursor
- Mark
));
2644 if (adrof(STRhighlight
) && MarkIsSet
) {
2654 e_copyregion(Char c
)
2660 if (Mark
> Cursor
) {
2661 c_push_kill(Cursor
, Mark
); /* copy it */
2663 else { /* mark is before cursor */
2664 c_push_kill(Mark
, Cursor
); /* copy it */
2666 return(CC_NORM
); /* don't even need to Refresh() */
2671 e_charswitch(Char cc
)
2677 /* do nothing if we are at beginning of line or have only one char */
2678 if (Cursor
== &InputBuf
[0] || LastChar
== &InputBuf
[1]) {
2682 if (Cursor
< LastChar
) {
2686 Cursor
[-2] = Cursor
[-1];
2693 e_gcharswitch(Char cc
)
2694 { /* gosmacs style ^T */
2698 if (Cursor
> &InputBuf
[1]) {/* must have at least two chars entered */
2700 Cursor
[-2] = Cursor
[-1];
2714 if (Cursor
> InputBuf
) {
2715 if (Argument
> Cursor
- InputBuf
)
2721 if (ActionFlag
& TCSHOP_DELETE
) {
2739 if (Cursor
== InputBuf
)
2743 Cursor
= c_preword(Cursor
, InputBuf
, Argument
, STRshwspace
); /* bounds check */
2745 if (ActionFlag
& TCSHOP_DELETE
) {
2759 if (Cursor
== InputBuf
)
2763 Cursor
= c_prev_word(Cursor
, InputBuf
, Argument
); /* bounds check */
2766 if (ActionFlag
& TCSHOP_DELETE
) {
2780 if (Cursor
< LastChar
) {
2782 if (Cursor
> LastChar
)
2786 if (ActionFlag
& TCSHOP_DELETE
) {
2804 if (Cursor
== LastChar
)
2808 Cursor
= c_next_word(Cursor
, LastChar
, Argument
);
2811 if (ActionFlag
& TCSHOP_DELETE
) {
2825 if (Cursor
== LastChar
)
2829 Cursor
= c_nexword(Cursor
, LastChar
, Argument
);
2832 if (ActionFlag
& TCSHOP_DELETE
) {
2843 v_wordbegnext(Char c
)
2846 if (Cursor
== LastChar
)
2850 Cursor
= c_next_word(Cursor
, LastChar
, Argument
);
2851 if (Cursor
< LastChar
)
2855 if (ActionFlag
& TCSHOP_DELETE
) {
2866 v_repeat_srch(int c
)
2868 CCRETVAL rv
= CC_ERROR
;
2870 xprintf("dir %d patlen %d patbuf %S\n",
2871 c
, (int)patbuf
.len
, patbuf
.s
);
2874 LastCmd
= (KEYCMD
) c
; /* Hack to stop c_hsetpat */
2875 LastChar
= InputBuf
;
2877 case F_DOWN_SEARCH_HIST
:
2878 rv
= e_down_search_hist(0);
2880 case F_UP_SEARCH_HIST
:
2881 rv
= e_up_search_hist(0);
2890 v_csearch_back(Char ch
, int count
, int tflag
)
2898 while (cp
> InputBuf
&& *cp
!= ch
)
2902 if (cp
< InputBuf
|| (cp
== InputBuf
&& *cp
!= ch
))
2905 if (*cp
== ch
&& tflag
)
2910 if (ActionFlag
& TCSHOP_DELETE
) {
2921 v_csearch_fwd(Char ch
, int count
, int tflag
)
2929 while (cp
< LastChar
&& *cp
!= ch
)
2936 if (*cp
== ch
&& tflag
)
2941 if (ActionFlag
& TCSHOP_DELETE
) {
2956 if (ActionFlag
== TCSHOP_DELETE
) {
2957 ActionFlag
= TCSHOP_NOP
;
2962 for (cp
= InputBuf
; cp
< LastChar
; cp
++) {
2967 UndoAction
= TCSHOP_INSERT
;
2969 LastChar
= InputBuf
;
2971 if (c
& TCSHOP_INSERT
)
2972 c_alternativ_key_map(0);
2977 else if (ActionFlag
== TCSHOP_NOP
) {
2981 return(CC_ARGHACK
); /* Do NOT clear out argument */
2993 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2995 c_get_word(Char
**begin
, Char
**end
)
3000 while (Argument
--) {
3001 while ((cp
<= LastChar
) && (isword(*cp
)))
3004 while ((cp
>= InputBuf
) && (isword(*cp
)))
3009 #endif /* COMMENT */
3018 end
= c_next_word(Cursor
, LastChar
, Argument
);
3020 for (cp
= Cursor
; cp
< end
; cp
++) /* PWP: was cp=begin */
3025 if (Cursor
> LastChar
)
3033 e_capitalcase(Char c
)
3038 end
= c_next_word(Cursor
, LastChar
, Argument
);
3041 for (; cp
< end
; cp
++) {
3049 for (; cp
< end
; cp
++)
3054 if (Cursor
> LastChar
)
3066 end
= c_next_word(Cursor
, LastChar
, Argument
);
3068 for (cp
= Cursor
; cp
< end
; cp
++)
3073 if (Cursor
> LastChar
)
3084 if (adrof(STRhighlight
) && MarkIsSet
&& Mark
!= Cursor
) {
3096 e_exchange_mark(Char c
)
3111 { /* multiply current argument by 4 */
3113 if (Argument
> 1000000)
3121 quote_mode_cleanup(void *unused
)
3136 cleanup_push(&c
, quote_mode_cleanup
); /* Using &c just as a mark */
3137 num
= GetNextChar(&ch
);
3140 return e_insert(ch
);
3142 return e_send_eof(0);
3151 return(CC_ARGHACK
); /* preserve argument */
3157 e_extendnext(Char c
)
3159 CurrentKeyMap
= CcAltMap
;
3160 return(CC_ARGHACK
); /* preserve argument */
3168 { /* move to beginning of line and start vi
3175 UndoAction
= TCSHOP_DELETE
;
3177 RefCursor(); /* move the cursor */
3178 c_alternativ_key_map(0);
3185 { /* vi mode overwrite one character */
3187 c_alternativ_key_map(0);
3188 inputmode
= MODE_REPLACE_1
;
3189 UndoAction
= TCSHOP_CHANGE
; /* Set Up for VI undo command */
3198 { /* vi mode start overwriting */
3200 c_alternativ_key_map(0);
3201 inputmode
= MODE_REPLACE
;
3202 UndoAction
= TCSHOP_CHANGE
; /* Set Up for VI undo command */
3211 { /* vi mode substitute for one char */
3213 c_delafter(Argument
);
3214 c_alternativ_key_map(0);
3221 { /* vi mode replace whole line */
3223 (void) e_killall(0);
3224 c_alternativ_key_map(0);
3231 { /* vi mode change to end of line */
3233 (void) e_killend(0);
3234 c_alternativ_key_map(0);
3241 { /* vi mode start inserting */
3243 c_alternativ_key_map(0);
3247 UndoAction
= TCSHOP_DELETE
;
3255 { /* vi mode start adding */
3257 c_alternativ_key_map(0);
3258 if (Cursor
< LastChar
)
3261 if (Cursor
> LastChar
)
3268 UndoAction
= TCSHOP_DELETE
;
3276 { /* vi mode to add at end of line */
3278 c_alternativ_key_map(0);
3281 InsertPos
= LastChar
; /* Mark where insertion begins */
3283 UndoAction
= TCSHOP_DELETE
;
3291 v_change_case(Char cc
)
3296 if (Cursor
< LastChar
) {
3297 #ifndef WINNT_NATIVE
3301 #endif /* WINNT_NATIVE */
3303 *Cursor
++ = Tolower(c
);
3304 else if (Islower(c
))
3305 *Cursor
++ = Toupper(c
);
3308 RefPlusOne(1); /* fast refresh for one char */
3321 for (p
= InputBuf
; Isspace(*p
); p
++)
3328 return(e_newline(0));
3334 { /* erase all of current line, start again */
3336 ResetInLine(0); /* reset the input pointers */
3355 ClearScreen(); /* clear the whole real screen */
3356 ClearDisp(); /* reset everything */
3365 #if defined(_MINIX) || defined(WINNT_NATIVE)
3366 /* SAK PATCH: erase all of current line, start again */
3367 ResetInLine(0); /* reset the input pointers */
3370 return (CC_REFRESH
);
3371 #else /* !_MINIX && !WINNT_NATIVE */
3374 #endif /* _MINIX || WINNT_NATIVE */
3378 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3379 * Function to send a character back to the input stream in cooked
3380 * mode. Only works if we have TIOCSTI
3384 e_stuff_char(Char c
)
3387 int was_raw
= Tty_raw_mode
;
3388 char buf
[MB_LEN_MAX
];
3392 (void) Cookedmode();
3394 (void) xwrite(SHIN
, "\n", 1);
3395 len
= one_wctomb(buf
, c
);
3396 for (i
= 0; i
< len
; i
++)
3397 (void) ioctl(SHIN
, TIOCSTI
, (ioctl_t
) &buf
[i
]);
3401 return(e_redisp(c
));
3402 #else /* !TIOCSTI */
3404 #endif /* !TIOCSTI */
3412 inputmode
= (inputmode
== MODE_INSERT
? MODE_REPLACE
: MODE_INSERT
);
3427 e_tty_flusho(Char c
)
3461 /* returns the number of (attempted) expansions */
3465 *LastChar
= '\0'; /* just in case */
3466 return c_substitute();
3471 e_expand_history(Char c
)
3474 (void)ExpandHistory();
3480 e_magic_space(Char c
)
3483 *LastChar
= '\0'; /* just in case */
3484 (void)c_substitute();
3485 return(e_insert(' '));
3497 ret
= e_inc_search(F_DOWN_SEARCH_HIST
);
3498 if (adrof(STRhighlight
) && IncMatchLen
) {
3518 ret
= e_inc_search(F_UP_SEARCH_HIST
);
3519 if (adrof(STRhighlight
) && IncMatchLen
) {
3533 Char
*cp
, *oldc
, *dp
;
3536 if (Cursor
== InputBuf
)
3541 /* does a bounds check */
3542 cp
= c_prev_word(Cursor
, InputBuf
, Argument
);
3544 c_insert((int)(oldc
- cp
));
3545 for (dp
= oldc
; cp
< oldc
&& dp
< LastChar
; cp
++)
3548 Cursor
= dp
; /* put cursor at end */
3555 e_tty_starto(Char c
)
3564 e_load_average(Char c
)
3570 * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3571 * there even if they don't use it. (lukem@netbsd.org)
3573 if (ioctl(SHIN
, TIOCSTAT
, (ioctl_t
) &c
) < 0)
3575 xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
3585 * Delete with insert == change: first we delete and then we leave in
3588 return(v_action(TCSHOP_DELETE
|TCSHOP_INSERT
));
3596 return(v_action(TCSHOP_DELETE
));
3605 if (Cursor
== LastChar
)
3609 Cursor
= c_endword(Cursor
, InputBuf
, LastChar
, Argument
, STRshwspace
);
3611 if (ActionFlag
& TCSHOP_DELETE
)
3627 if (Cursor
== LastChar
)
3631 Cursor
= c_eword(Cursor
, LastChar
, Argument
);
3633 if (ActionFlag
& TCSHOP_DELETE
) {
3650 if (GetNextChar(&ch
) != 1)
3651 return e_send_eof(0);
3653 srch_dir
= CHAR_FWD
;
3656 return v_csearch_fwd(ch
, Argument
, 0);
3667 if (GetNextChar(&ch
) != 1)
3668 return e_send_eof(0);
3670 srch_dir
= CHAR_BACK
;
3673 return v_csearch_back(ch
, Argument
, 0);
3678 v_charto_fwd(Char c
)
3683 if (GetNextChar(&ch
) != 1)
3684 return e_send_eof(0);
3686 return v_csearch_fwd(ch
, Argument
, 1);
3692 v_charto_back(Char c
)
3697 if (GetNextChar(&ch
) != 1)
3698 return e_send_eof(0);
3700 return v_csearch_back(ch
, Argument
, 1);
3711 return srch_dir
== CHAR_FWD
? v_csearch_fwd(srch_char
, Argument
, 0) :
3712 v_csearch_back(srch_char
, Argument
, 0);
3717 v_rchar_back(Char c
)
3723 return srch_dir
== CHAR_BACK
? v_csearch_fwd(srch_char
, Argument
, 0) :
3724 v_csearch_back(srch_char
, Argument
, 0);
3737 switch (UndoAction
) {
3738 case TCSHOP_DELETE
|TCSHOP_INSERT
:
3740 if (UndoSize
== 0) return(CC_NORM
);
3743 for (loop
=0; loop
< UndoSize
; loop
++) /* copy the chars */
3744 *kp
++ = *cp
++; /* into UndoBuf */
3746 for (cp
= UndoPtr
; cp
<= LastChar
; cp
++)
3749 LastChar
-= UndoSize
;
3752 UndoAction
= TCSHOP_INSERT
;
3756 if (UndoSize
== 0) return(CC_NORM
);
3760 c_insert(UndoSize
); /* open the space, */
3761 for (loop
= 0; loop
< UndoSize
; loop
++) /* copy the chars */
3764 UndoAction
= TCSHOP_DELETE
;
3768 if (UndoSize
== 0) return(CC_NORM
);
3772 size
= (int)(Cursor
-LastChar
); /* NOT NSL independant */
3773 if (size
< UndoSize
)
3775 for (loop
= 0; loop
< size
; loop
++) {
3794 return v_search(F_UP_SEARCH_HIST
);
3802 return v_search(F_DOWN_SEARCH_HIST
);
3810 if (patbuf
.len
== 0) return(CC_ERROR
);
3811 return(v_repeat_srch(searchdir
));
3816 v_rsrch_back(Char c
)
3819 if (patbuf
.len
== 0) return(CC_ERROR
);
3820 return(v_repeat_srch(searchdir
== F_UP_SEARCH_HIST
?
3821 F_DOWN_SEARCH_HIST
: F_UP_SEARCH_HIST
));
3824 #ifndef WINNT_NATIVE
3825 /* Since ed.defns.h is generated from ed.defns.c, these empty
3826 functions will keep the F_NUM_FNS consistent
3829 e_copy_to_clipboard(Char c
)
3836 e_paste_from_clipboard(Char c
)
3843 e_dosify_next(Char c
)
3849 e_dosify_prev(Char c
)
3866 #endif /* !WINNT_NATIVE */
3870 MoveCursor(int n
) /* move cursor + right - left char */
3872 Cursor
= Cursor
+ n
;
3873 if (Cursor
< InputBuf
)
3875 if (Cursor
> LastChar
)
3889 if (p
< InputBuf
|| p
> LastChar
)
3890 return 1; /* Error */