1 /* $Header: /p/tcsh/cvsroot/tcsh/ed.chared.c,v 3.99 2014/03/09 00:20:26 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.99 2014/03/09 00:20:26 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 int c_excl (Char
*);
124 static int c_substitute (void);
125 static void c_delfini (void);
126 static int c_hmatch (Char
*);
127 static void c_hsetpat (void);
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 */
509 if (HIST
!= '\0' && *q
!= HIST
) {
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)
685 * Returns number of expansions attempted (doesn't matter whether they succeeded
697 * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
698 * back p up to just before the current word.
700 if ((p
[1] == ' ' || p
[1] == '\t') &&
701 (p
[-1] == ' ' || p
[-1] == '\t' || p
[-1] == '>')) {
702 for (q
= p
- 1; q
> InputBuf
&& (*q
== ' ' || *q
== '\t'); --q
)
708 while (*p
!= ' ' && *p
!= '\t' && p
> InputBuf
)
713 * Forever: Look for history char. (Stop looking when we find the cursor.)
714 * Count backslashes. If odd, skip history char. Expand if even number of
720 while (*p
!= HIST
&& p
< Cursor
)
722 for (i
= 1; (p
- i
) >= InputBuf
&& p
[-i
] == '\\'; i
++)
726 if (p
>= Cursor
) /* all done */
743 * Start p out one character before the cursor. Move it backwards looking
744 * for white space, the beginning of the line, or a history character.
747 p
> InputBuf
&& *p
!= ' ' && *p
!= '\t' && *p
&& *p
!= HIST
; --p
)
751 * If we found a history character, go expand it.
753 if (HIST
!= '\0' && *p
== HIST
)
763 c_delfini(void) /* Finish up delete action */
767 if (ActionFlag
& TCSHOP_INSERT
)
768 c_alternativ_key_map(0);
770 ActionFlag
= TCSHOP_NOP
;
775 UndoAction
= TCSHOP_INSERT
;
777 if (Cursor
> ActionPos
) {
778 Size
= (int) (Cursor
-ActionPos
);
782 else if (Cursor
< ActionPos
) {
783 Size
= (int)(ActionPos
-Cursor
);
795 c_endword(Char
*p
, Char
*high
, int n
, Char
*delim
)
801 while (p
< high
) { /* Skip non-word chars */
802 if (!Strchr(delim
, *p
) || *(p
-1) == (Char
)'\\')
806 while (p
< high
) { /* Skip string */
807 if ((*p
== (Char
)'\'' || *p
== (Char
)'"')) { /* Quotation marks? */
808 if (inquote
|| *(p
-1) != (Char
)'\\') { /* Should it be honored? */
809 if (inquote
== 0) inquote
= *p
;
810 else if (inquote
== *p
) inquote
= 0;
813 /* Break if unquoted non-word char */
814 if (!inquote
&& Strchr(delim
, *p
) && *(p
-1) != (Char
)'\\')
826 c_eword(Char
*p
, Char
*high
, int n
)
831 while ((p
< high
) && Isspace(*p
))
835 while ((p
< high
) && isword(*p
))
838 while ((p
< high
) && !(Isspace(*p
) || isword(*p
)))
846 /* Set the max length of the kill ring */
854 max
= 1; /* no ring, but always one buffer */
855 if (max
== KillRingMax
)
857 new = xcalloc(max
, sizeof(CStr
));
858 if (KillRing
!= NULL
) {
859 if (KillRingLen
!= 0) {
860 if (max
>= KillRingLen
) {
865 j
= (KillPos
- count
+ KillRingLen
) % KillRingLen
;
867 for (i
= 0; i
< KillRingLen
; i
++) {
868 if (i
< count
) /* copy latest */
869 new[i
] = KillRing
[j
];
870 else /* free the others */
871 xfree(KillRing
[j
].buf
);
872 j
= (j
+ 1) % KillRingLen
;
875 KillPos
= count
% max
;
884 /* Push string from start upto (but not including) end onto kill ring */
886 c_push_kill(Char
*start
, Char
*end
)
890 int len
= end
- start
, i
, j
, k
;
892 /* Check for duplicates? */
893 if (KillRingLen
> 0 && (dp
= varval(STRkilldup
)) != STRNULL
) {
894 YankPos
= (KillPos
- 1 + KillRingLen
) % KillRingLen
;
895 if (eq(dp
, STRerase
)) { /* erase earlier one (actually move up) */
897 for (i
= 0; i
< KillRingLen
; i
++) {
898 if (Strncmp(KillRing
[j
].buf
, start
, (size_t) len
) == 0 &&
899 KillRing
[j
].buf
[len
] == '\0') {
901 for ( ; i
> 0; i
--) {
903 j
= (j
+ 1) % KillRingLen
;
904 KillRing
[k
] = KillRing
[j
];
909 j
= (j
- 1 + KillRingLen
) % KillRingLen
;
911 } else if (eq(dp
, STRall
)) { /* skip if any earlier */
912 for (i
= 0; i
< KillRingLen
; i
++)
913 if (Strncmp(KillRing
[i
].buf
, start
, (size_t) len
) == 0 &&
914 KillRing
[i
].buf
[len
] == '\0')
916 } else if (eq(dp
, STRprev
)) { /* skip if immediately previous */
918 if (Strncmp(KillRing
[j
].buf
, start
, (size_t) len
) == 0 &&
919 KillRing
[j
].buf
[len
] == '\0')
924 /* No duplicate, go ahead and push */
925 len
++; /* need space for '\0' */
927 if (KillRingLen
< KillRingMax
)
929 pos
= &KillRing
[KillPos
];
930 KillPos
= (KillPos
+ 1) % KillRingMax
;
931 if (pos
->len
< len
) {
932 pos
->buf
= xrealloc(pos
->buf
, len
* sizeof(Char
));
942 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */
944 c_save_inputbuf(void)
947 Strbuf_append(&SavedBuf
, InputBuf
);
948 Strbuf_terminate(&SavedBuf
);
949 LastSaved
= LastChar
- InputBuf
;
950 CursSaved
= Cursor
- InputBuf
;
951 HistSaved
= Hist_num
;
961 if (Hist_num
== 0) { /* if really the current line */
962 if (HistBuf
.s
!= NULL
)
963 copyn(InputBuf
, HistBuf
.s
, INBUFSIZE
);/*FIXBUF*/
966 LastChar
= InputBuf
+ HistBuf
.len
;
982 for (h
= 1; h
< Hist_num
; h
++) {
983 if ((hp
->Hnext
) == NULL
) {
990 if (HistLit
&& hp
->histline
) {
991 copyn(InputBuf
, hp
->histline
, INBUFSIZE
);/*FIXBUF*/
997 p
= sprlex(&hp
->Hlex
);
998 copyn(InputBuf
, p
, sizeof(InputBuf
) / sizeof(Char
));/*FIXBUF*/
1002 LastChar
= Strend(InputBuf
);
1004 if (LastChar
> InputBuf
) {
1005 if (LastChar
[-1] == '\n')
1008 if (LastChar
[-1] == ' ')
1011 if (LastChar
< InputBuf
)
1012 LastChar
= InputBuf
;
1026 c_search_line(Char
*pattern
, int dir
)
1031 len
= Strlen(pattern
);
1033 if (dir
== F_UP_SEARCH_HIST
) {
1034 for (cp
= Cursor
; cp
>= InputBuf
; cp
--)
1035 if (Strncmp(cp
, pattern
, len
) == 0 ||
1036 Gmatch(cp
, pattern
)) {
1042 for (cp
= Cursor
; *cp
!= '\0' && cp
< InputLim
; cp
++)
1043 if (Strncmp(cp
, pattern
, len
) == 0 ||
1044 Gmatch(cp
, pattern
)) {
1053 e_inc_search(int dir
)
1055 static const Char STRfwd
[] = { 'f', 'w', 'd', '\0' },
1056 STRbck
[] = { 'b', 'c', 'k', '\0' };
1057 static Char pchar
= ':'; /* ':' = normal, '?' = failed */
1058 static Char endcmd
[2];
1061 *oldCursor
= Cursor
,
1063 CCRETVAL ret
= CC_NORM
;
1064 int oldHist_num
= Hist_num
,
1065 oldpatlen
= patbuf
.len
,
1069 if (LastChar
+ sizeof(STRfwd
)/sizeof(Char
) + 2 + patbuf
.len
>= InputLim
)
1074 if (patbuf
.len
== 0) { /* first round */
1076 Strbuf_append1(&patbuf
, '*');
1080 for (cp
= newdir
== F_UP_SEARCH_HIST
? STRbck
: STRfwd
;
1081 *cp
; *LastChar
++ = *cp
++)
1083 *LastChar
++ = pchar
;
1084 for (cp
= &patbuf
.s
[1]; cp
< &patbuf
.s
[patbuf
.len
];
1085 *LastChar
++ = *cp
++)
1088 if (adrof(STRhighlight
) && pchar
== ':') {
1089 /* if the no-glob-search patch is applied, remove the - 1 below */
1090 IncMatchLen
= patbuf
.len
- 1;
1096 if (GetNextChar(&ch
) != 1)
1097 return(e_send_eof(0));
1099 switch (ch
> NT_NUM_KEYS
1100 ? F_INSERT
: CurrentKeyMap
[(unsigned char) ch
]) {
1104 if (LastChar
+ 1 >= InputLim
) /*FIXBUF*/
1107 Strbuf_append1(&patbuf
, ch
);
1115 newdir
= F_DOWN_SEARCH_HIST
;
1120 newdir
= F_UP_SEARCH_HIST
;
1133 case 0007: /* ^G: Abort */
1138 case 0027: /* ^W: Append word */
1139 /* No can do if globbing characters in pattern */
1140 for (cp
= &patbuf
.s
[1]; ; cp
++)
1141 if (cp
>= &patbuf
.s
[patbuf
.len
]) {
1142 Cursor
+= patbuf
.len
- 1;
1143 cp
= c_next_word(Cursor
, LastChar
, 1);
1144 while (Cursor
< cp
&& *Cursor
!= '\n') {
1145 if (LastChar
+ 1 >= InputLim
) {/*FIXBUF*/
1149 Strbuf_append1(&patbuf
, *Cursor
);
1150 *LastChar
++ = *Cursor
++;
1156 } else if (isglob(*cp
)) {
1162 default: /* Terminate and execute cmd */
1167 case 0033: /* ESC: Terminate */
1175 while (LastChar
> InputBuf
&& *LastChar
!= '\n')
1181 /* Can't search if unmatched '[' */
1182 for (cp
= &patbuf
.s
[patbuf
.len
- 1], ch
= ']'; cp
> patbuf
.s
; cp
--)
1183 if (*cp
== '[' || *cp
== ']') {
1188 if (patbuf
.len
> 1 && ch
!= '[') {
1189 if (redo
&& newdir
== dir
) {
1190 if (pchar
== '?') { /* wrap around */
1191 Hist_num
= newdir
== F_UP_SEARCH_HIST
? 0 : INT_MAX
;
1192 if (GetHistLine() == CC_ERROR
)
1193 /* Hist_num was fixed by first call */
1194 (void) GetHistLine();
1195 Cursor
= newdir
== F_UP_SEARCH_HIST
?
1196 LastChar
: InputBuf
;
1198 Cursor
+= newdir
== F_UP_SEARCH_HIST
? -1 : 1;
1200 Strbuf_append1(&patbuf
, '*');
1201 Strbuf_terminate(&patbuf
);
1202 if (Cursor
< InputBuf
|| Cursor
> LastChar
||
1203 (ret
= c_search_line(&patbuf
.s
[1], newdir
)) == CC_ERROR
) {
1204 LastCmd
= (KEYCMD
) newdir
; /* avoid c_hsetpat */
1205 ret
= newdir
== F_UP_SEARCH_HIST
?
1206 e_up_search_hist(0) : e_down_search_hist(0);
1207 if (ret
!= CC_ERROR
) {
1208 Cursor
= newdir
== F_UP_SEARCH_HIST
?
1209 LastChar
: InputBuf
;
1210 (void) c_search_line(&patbuf
.s
[1], newdir
);
1213 patbuf
.s
[--patbuf
.len
] = '\0';
1214 if (ret
== CC_ERROR
) {
1216 if (Hist_num
!= oldHist_num
) {
1217 Hist_num
= oldHist_num
;
1218 if (GetHistLine() == CC_ERROR
)
1228 ret
= e_inc_search(newdir
);
1230 if (ret
== CC_ERROR
&& pchar
== '?' && oldpchar
== ':') {
1231 /* break abort of failed search at last non-failed */
1237 if (ret
== CC_NORM
|| (ret
== CC_ERROR
&& oldpatlen
== 0)) {
1238 /* restore on normal return or error exit */
1240 patbuf
.len
= oldpatlen
;
1241 if (Hist_num
!= oldHist_num
) {
1242 Hist_num
= oldHist_num
;
1243 if (GetHistLine() == CC_ERROR
)
1247 if (ret
== CC_ERROR
)
1250 if (done
|| ret
!= CC_NORM
)
1260 struct Strbuf tmpbuf
= Strbuf_INIT
;
1265 cleanup_push(&tmpbuf
, Strbuf_cleanup
);
1266 oldbuf
= Strsave(InputBuf
);
1267 cleanup_push(oldbuf
, xfree
);
1270 Strbuf_append1(&tmpbuf
, '*');
1273 LastChar
= InputBuf
;
1277 c_insert(2); /* prompt + '\n' */
1279 *Cursor
++ = dir
== F_UP_SEARCH_HIST
? '?' : '/';
1281 for (ch
= 0;ch
== 0;) {
1282 if (GetNextChar(&ch
) != 1) {
1283 cleanup_until(&tmpbuf
);
1284 return(e_send_eof(0));
1287 case 0010: /* Delete and backspace */
1289 if (tmpbuf
.len
> 1) {
1295 copyn(InputBuf
, oldbuf
, INBUFSIZE
);/*FIXBUF*/
1298 cleanup_until(&tmpbuf
);
1305 case 0033: /* ESC */
1307 case '\r': /* Newline */
1310 case '\012': /* ASCII Line feed */
1311 case '\015': /* ASCII (or EBCDIC) Return */
1316 Strbuf_append1(&tmpbuf
, ch
);
1324 cleanup_until(oldbuf
);
1326 if (tmpbuf
.len
== 1) {
1328 * Use the old pattern, but wild-card it.
1330 if (patbuf
.len
== 0) {
1332 LastChar
= InputBuf
;
1335 cleanup_until(&tmpbuf
);
1338 if (patbuf
.s
[0] != '*') {
1339 oldbuf
= Strsave(patbuf
.s
);
1341 Strbuf_append1(&patbuf
, '*');
1342 Strbuf_append(&patbuf
, oldbuf
);
1344 Strbuf_append1(&patbuf
, '*');
1345 Strbuf_terminate(&patbuf
);
1349 Strbuf_append1(&tmpbuf
, '*');
1350 Strbuf_terminate(&tmpbuf
);
1352 Strbuf_append(&patbuf
, tmpbuf
.s
);
1353 Strbuf_terminate(&patbuf
);
1355 cleanup_until(&tmpbuf
);
1356 LastCmd
= (KEYCMD
) dir
; /* avoid c_hsetpat */
1357 Cursor
= LastChar
= InputBuf
;
1358 if ((dir
== F_UP_SEARCH_HIST
? e_up_search_hist(0) :
1359 e_down_search_hist(0)) == CC_ERROR
) {
1364 if (ASC(ch
) == 0033) {
1377 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1378 * entry point, called from the CcKeyMap indirected into the
1388 ActionFlag
= TCSHOP_NOP
; /* [Esc] cancels pending action */
1391 if (UndoPtr
> Cursor
)
1392 UndoSize
= (int)(UndoPtr
- Cursor
);
1394 UndoSize
= (int)(Cursor
- UndoPtr
);
1396 inputmode
= MODE_INSERT
;
1397 c_alternativ_key_map(1);
1400 * We don't want to move the cursor, because all the editing
1401 * commands don't include the character under the cursor.
1403 if (Cursor
> InputBuf
)
1412 e_unassigned(Char c
)
1413 { /* bound to keys that arn't really assigned */
1422 e_insert_str(Char
*c
)
1427 if (LastChar
+ Argument
* n
>= InputLim
)
1428 return(CC_ERROR
); /* end of buffer space */
1429 if (inputmode
!= MODE_INSERT
) {
1430 c_delafter(Argument
* Strlen(c
));
1432 c_insert(Argument
* n
);
1433 while (Argument
--) {
1434 for (i
= 0; i
< n
; i
++)
1445 #ifndef SHORT_STRINGS
1446 c
&= ASCII
; /* no meta chars ever */
1450 return(CC_ERROR
); /* no NULs in the input ever!! */
1452 if (LastChar
+ Argument
>= InputLim
)
1453 return(CC_ERROR
); /* end of buffer space */
1455 if (Argument
== 1) { /* How was this optimized ???? */
1457 if (inputmode
!= MODE_INSERT
) {
1458 UndoBuf
[UndoSize
++] = *Cursor
;
1459 UndoBuf
[UndoSize
] = '\0';
1460 c_delafter(1); /* Do NOT use the saving ONE */
1464 *Cursor
++ = (Char
) c
;
1465 DoingArg
= 0; /* just in case */
1466 RefPlusOne(1); /* fast refresh for one char. */
1469 if (inputmode
!= MODE_INSERT
) {
1471 for(i
= 0; i
< Argument
; i
++)
1472 UndoBuf
[UndoSize
++] = *(Cursor
+ i
);
1474 UndoBuf
[UndoSize
] = '\0';
1475 c_delafter(Argument
); /* Do NOT use the saving ONE */
1481 *Cursor
++ = (Char
) c
;
1485 if (inputmode
== MODE_REPLACE_1
)
1486 (void) v_cmd_mode(0);
1492 InsertStr(Char
*s
) /* insert ASCIZ s at cursor (for complete) */
1496 if ((len
= (int) Strlen(s
)) <= 0)
1498 if (LastChar
+ len
>= InputLim
)
1499 return -1; /* end of buffer space */
1508 DeleteBack(int n
) /* delete the n characters before . */
1512 if (Cursor
>= &InputBuf
[n
]) {
1513 c_delbefore(n
); /* delete before dot */
1518 e_digit(Char c
) /* gray magic here */
1521 return(CC_ERROR
); /* no NULs in the input ever!! */
1523 if (DoingArg
) { /* if doing an arg, add this in... */
1524 if (LastCmd
== F_ARGFOUR
) /* if last command was ^U */
1527 if (Argument
> 1000000)
1529 Argument
= (Argument
* 10) + (c
- '0');
1534 if (LastChar
+ 1 >= InputLim
)
1535 return CC_ERROR
; /* end of buffer space */
1537 if (inputmode
!= MODE_INSERT
) {
1538 UndoBuf
[UndoSize
++] = *Cursor
;
1539 UndoBuf
[UndoSize
] = '\0';
1540 c_delafter(1); /* Do NOT use the saving ONE */
1543 *Cursor
++ = (Char
) c
;
1544 DoingArg
= 0; /* just in case */
1545 RefPlusOne(1); /* fast refresh for one char. */
1551 e_argdigit(Char c
) /* for ESC-n */
1556 c
= CTL_ESC(ASC(c
) & ASCII
); /* stripping for EBCDIC done the ASCII way */
1560 return(CC_ERROR
); /* no NULs in the input ever!! */
1562 if (DoingArg
) { /* if doing an arg, add this in... */
1563 if (Argument
> 1000000)
1565 Argument
= (Argument
* 10) + (c
- '0');
1567 else { /* else starting an argument */
1575 v_zero(Char c
) /* command mode 0 for vi */
1577 if (DoingArg
) { /* if doing an arg, add this in... */
1578 if (Argument
> 1000000)
1580 Argument
= (Argument
* 10) + (c
- '0');
1583 else { /* else starting an argument */
1585 if (ActionFlag
& TCSHOP_DELETE
) {
1589 RefCursor(); /* move the cursor */
1597 { /* always ignore argument */
1599 if (adrof(STRhighlight
) && MarkIsSet
) {
1607 /* PastBottom(); NOW done in ed.inputl.c */
1608 *LastChar
++ = '\n'; /* for the benefit of CSH */
1609 *LastChar
= '\0'; /* just in case */
1611 InsertPos
= InputBuf
; /* Reset editing position */
1617 e_newline_hold(Char c
)
1622 *LastChar
++ = '\n'; /* for the benefit of CSH */
1623 *LastChar
= '\0'; /* just in case */
1629 e_newline_down_hist(Char c
)
1633 HistSaved
= Hist_num
;
1635 *LastChar
++ = '\n'; /* for the benefit of CSH */
1636 *LastChar
= '\0'; /* just in case */
1643 { /* for when ^D is ONLY send-eof */
1646 *LastChar
= '\0'; /* just in case */
1655 *LastChar
= '\0'; /* just in case */
1656 return(CC_COMPLETE
);
1661 e_complete_back(Char c
)
1664 *LastChar
= '\0'; /* just in case */
1665 return(CC_COMPLETE_BACK
);
1670 e_complete_fwd(Char c
)
1673 *LastChar
= '\0'; /* just in case */
1674 return(CC_COMPLETE_FWD
);
1679 e_complete_all(Char c
)
1682 *LastChar
= '\0'; /* just in case */
1683 return(CC_COMPLETE_ALL
);
1688 v_cm_complete(Char c
)
1691 if (Cursor
< LastChar
)
1693 *LastChar
= '\0'; /* just in case */
1694 return(CC_COMPLETE
);
1699 e_toggle_hist(Char c
)
1705 *LastChar
= '\0'; /* just in case */
1707 if (Hist_num
<= 0) {
1711 hp
= Histlist
.Hnext
;
1712 if (hp
== NULL
) { /* this is only if no history */
1716 for (h
= 1; h
< Hist_num
; h
++)
1719 if (!CurrentHistLit
) {
1721 copyn(InputBuf
, hp
->histline
, INBUFSIZE
);/*FIXBUF*/
1731 p
= sprlex(&hp
->Hlex
);
1732 copyn(InputBuf
, p
, sizeof(InputBuf
) / sizeof(Char
));/*FIXBUF*/
1737 LastChar
= Strend(InputBuf
);
1738 if (LastChar
> InputBuf
) {
1739 if (LastChar
[-1] == '\n')
1741 if (LastChar
[-1] == ' ')
1743 if (LastChar
< InputBuf
)
1744 LastChar
= InputBuf
;
1764 UndoAction
= TCSHOP_NOP
;
1765 *LastChar
= '\0'; /* just in case */
1767 if (Hist_num
== 0) { /* save the current buffer away */
1769 Strbuf_append(&HistBuf
, InputBuf
);
1770 Strbuf_terminate(&HistBuf
);
1773 Hist_num
+= Argument
;
1775 if (GetHistLine() == CC_ERROR
) {
1777 (void) GetHistLine(); /* Hist_num was fixed by first call */
1784 return(CC_NORM
); /* was CC_UP_HIST */
1792 UndoAction
= TCSHOP_NOP
;
1793 *LastChar
= '\0'; /* just in case */
1795 Hist_num
-= Argument
;
1799 return(CC_ERROR
); /* make it beep */
1802 return(GetHistLine());
1808 * c_hmatch() return True if the pattern matches the prefix
1813 if (Strncmp(patbuf
.s
, str
, patbuf
.len
) == 0)
1815 return Gmatch(str
, patbuf
.s
);
1819 * c_hsetpat(): Set the history seatch pattern
1824 if (LastCmd
!= F_UP_SEARCH_HIST
&& LastCmd
!= F_DOWN_SEARCH_HIST
) {
1826 Strbuf_appendn(&patbuf
, InputBuf
, Cursor
- InputBuf
);
1827 Strbuf_terminate(&patbuf
);
1830 xprintf("\nHist_num = %d\n", Hist_num
);
1831 xprintf("patlen = %d\n", (int)patbuf
.len
);
1832 xprintf("patbuf = \"%S\"\n", patbuf
.s
);
1833 xprintf("Cursor %d LastChar %d\n", Cursor
- InputBuf
, LastChar
- InputBuf
);
1839 e_up_search_hist(Char c
)
1846 ActionFlag
= TCSHOP_NOP
;
1847 UndoAction
= TCSHOP_NOP
;
1848 *LastChar
= '\0'; /* just in case */
1851 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname
);
1857 if (Hist_num
== 0) {
1859 Strbuf_append(&HistBuf
, InputBuf
);
1860 Strbuf_terminate(&HistBuf
);
1864 hp
= Histlist
.Hnext
;
1868 c_hsetpat(); /* Set search pattern !! */
1870 for (h
= 1; h
<= Hist_num
; h
++)
1873 while (hp
!= NULL
) {
1877 if (hp
->histline
== NULL
)
1878 hp
->histline
= sprlex(&hp
->Hlex
);
1882 hl
= sprlex(&hp
->Hlex
);
1883 cleanup_push(hl
, xfree
);
1886 xprintf("Comparing with \"%S\"\n", hl
);
1888 matched
= (Strncmp(hl
, InputBuf
, (size_t) (LastChar
- InputBuf
)) ||
1889 hl
[LastChar
-InputBuf
]) && c_hmatch(hl
);
1902 xprintf("not found\n");
1909 return(GetHistLine());
1914 e_down_search_hist(Char c
)
1921 ActionFlag
= TCSHOP_NOP
;
1922 UndoAction
= TCSHOP_NOP
;
1923 *LastChar
= '\0'; /* just in case */
1928 hp
= Histlist
.Hnext
;
1932 c_hsetpat(); /* Set search pattern !! */
1934 for (h
= 1; h
< Hist_num
&& hp
; h
++) {
1936 if (hp
->histline
== NULL
)
1937 hp
->histline
= sprlex(&hp
->Hlex
);
1941 hl
= sprlex(&hp
->Hlex
);
1942 cleanup_push(hl
, xfree
);
1945 xprintf("Comparing with \"%S\"\n", hl
);
1947 if ((Strncmp(hl
, InputBuf
, (size_t) (LastChar
- InputBuf
)) ||
1948 hl
[LastChar
-InputBuf
]) && c_hmatch(hl
))
1955 if (!found
) { /* is it the current history number? */
1956 if (!c_hmatch(HistBuf
.s
)) {
1958 xprintf("not found\n");
1966 return(GetHistLine());
1975 *LastChar
= '\0'; /* just in case */
1984 *LastChar
= '\0'; /* just in case */
1993 *LastChar
= '\0'; /* just in case */
1994 return(CC_CORRECT_L
);
1999 e_run_fg_editor(Char c
)
2004 if ((pp
= find_stop_ed()) != NULL
) {
2005 /* save our editor state so we can restore it */
2007 Hist_num
= 0; /* for the history commands */
2009 /* put the tty in a sane mode */
2011 (void) Cookedmode(); /* make sure the tty is set up correctly */
2016 (void) Rawmode(); /* go on */
2026 e_list_choices(Char c
)
2030 *LastChar
= '\0'; /* just in case */
2031 return(CC_LIST_CHOICES
);
2040 *LastChar
= '\0'; /* just in case */
2041 return(CC_LIST_ALL
);
2050 *LastChar
= '\0'; /* just in case */
2051 return(CC_LIST_GLOB
);
2056 e_expand_glob(Char c
)
2059 *LastChar
= '\0'; /* just in case */
2060 return(CC_EXPAND_GLOB
);
2065 e_normalize_path(Char c
)
2068 *LastChar
= '\0'; /* just in case */
2069 return(CC_NORMALIZE_PATH
);
2074 e_normalize_command(Char c
)
2077 *LastChar
= '\0'; /* just in case */
2078 return(CC_NORMALIZE_COMMAND
);
2083 e_expand_vars(Char c
)
2086 *LastChar
= '\0'; /* just in case */
2087 return(CC_EXPAND_VARS
);
2093 { /* do a fast command line which(1) */
2096 Hist_num
= 0; /* for the history commands */
2098 *LastChar
= '\0'; /* just in case */
2105 { /* insert the last element of the prev. cmd */
2107 struct wordent
*wp
, *firstp
;
2115 hp
= Histlist
.Hnext
;
2116 if (hp
== NULL
) { /* this is only if no history */
2120 wp
= (hp
->Hlex
).prev
;
2122 if (wp
->prev
== (struct wordent
*) NULL
)
2123 return(CC_ERROR
); /* an empty history entry */
2125 firstp
= (hp
->Hlex
).next
;
2127 /* back up arg words in lex */
2128 for (i
= 0; i
< Argument
&& wp
!= firstp
; i
++) {
2132 expanded
= expand_lex(wp
->prev
, 0, i
- 1);
2133 if (InsertStr(expanded
)) {
2144 e_dabbrev_expand(Char c
)
2145 { /* expand to preceding word matching prefix */
2146 Char
*cp
, *ncp
, *bp
;
2152 static int oldevent
, hist
, word
;
2153 static Char
*start
, *oldcursor
;
2159 cp
= c_preword(Cursor
, InputBuf
, 1, STRshwordsep
);
2160 if (cp
== Cursor
|| Isspace(*cp
))
2164 hp
= Histlist
.Hnext
;
2166 if (Argument
== 1 && eventno
== oldevent
&& cp
== start
&&
2167 Cursor
== oldcursor
&& patbuf
.len
> 0
2168 && Strncmp(patbuf
.s
, cp
, patbuf
.len
) == 0){
2169 /* continue previous search - go to last match (hist/word) */
2170 if (hist
!= 0) { /* need to move up history */
2171 for (i
= 1; i
< hist
&& hp
!= NULL
; i
++)
2173 if (hp
== NULL
) /* "can't happen" */
2175 hbuf
= expand_lex(&hp
->Hlex
, 0, INT_MAX
);
2180 cp
= c_preword(cp
, bp
, word
, STRshwordsep
);
2181 } else { /* starting new search */
2185 Strbuf_appendn(&patbuf
, cp
, Cursor
- cp
);
2191 ncp
= c_preword(cp
, bp
, 1, STRshwordsep
);
2192 if (ncp
== cp
|| Isspace(*ncp
)) { /* beginning of line */
2197 hbuf
= expand_lex(&hp
->Hlex
, 0, INT_MAX
);
2204 len
= c_endword(ncp
-1, cp
, 1, STRshwordsep
) - ncp
+ 1;
2207 if (len
> patbuf
.len
&& Strncmp(cp
, patbuf
.s
, patbuf
.len
) == 0) {
2208 /* We don't fully check distinct matches as Gnuemacs does: */
2209 if (Argument
> 1) { /* just count matches */
2210 if (++arg
>= Argument
)
2212 } else { /* match if distinct from previous */
2213 if (len
!= (size_t)(Cursor
- start
)
2214 || Strncmp(cp
, start
, len
) != 0)
2220 if (LastChar
+ len
- (Cursor
- start
) >= InputLim
)
2221 goto err_hbuf
; /* no room */
2222 DeleteBack(Cursor
- start
);
2238 { /* almost like GnuEmacs */
2243 if (KillRingLen
== 0) /* nothing killed */
2245 len
= Strlen(KillRing
[YankPos
].buf
);
2246 if (LastChar
+ len
>= InputLim
)
2247 return(CC_ERROR
); /* end of buffer space */
2250 cp
= Cursor
; /* for speed */
2252 c_insert(len
); /* open the space, */
2253 for (kp
= KillRing
[YankPos
].buf
; *kp
; kp
++) /* copy the chars */
2256 if (Argument
== 1) { /* if no arg */
2257 Mark
= Cursor
; /* mark at beginning, cursor at end */
2260 Mark
= cp
; /* else cursor at beginning, mark at end */
2263 if (adrof(STRhighlight
) && MarkIsSet
) {
2274 { /* almost like GnuEmacs */
2275 int m_bef_c
, del_len
, ins_len
;
2281 /* XXX This "should" be here, but doesn't work, since LastCmd
2282 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2283 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2284 second one will "succeed" even if the first one wasn't preceded
2285 by a yank, and giving an argument is impossible. Now we "succeed"
2286 regardless of previous command, which is wrong too of course. */
2287 if (LastCmd
!= F_YANK_KILL
&& LastCmd
!= F_YANK_POP
)
2291 if (KillRingLen
== 0) /* nothing killed */
2293 YankPos
-= Argument
;
2295 YankPos
+= KillRingLen
;
2296 YankPos
%= KillRingLen
;
2298 if (Cursor
> Mark
) {
2299 del_len
= Cursor
- Mark
;
2302 del_len
= Mark
- Cursor
;
2305 ins_len
= Strlen(KillRing
[YankPos
].buf
);
2306 if (LastChar
+ ins_len
- del_len
>= InputLim
)
2307 return(CC_ERROR
); /* end of buffer space */
2310 c_delbefore(del_len
);
2312 c_delafter(del_len
);
2314 cp
= Cursor
; /* for speed */
2316 c_insert(ins_len
); /* open the space, */
2317 for (kp
= KillRing
[YankPos
].buf
; *kp
; kp
++) /* copy the chars */
2321 Mark
= Cursor
; /* mark at beginning, cursor at end */
2324 Mark
= cp
; /* else cursor at beginning, mark at end */
2327 if (adrof(STRhighlight
) && MarkIsSet
) {
2337 v_delprev(Char c
) /* Backspace key in insert mode */
2344 if (InsertPos
!= 0) {
2345 if (Argument
<= Cursor
- InsertPos
) {
2346 c_delbefore(Argument
); /* delete before */
2358 if (Cursor
> InputBuf
) {
2359 c_delbefore(Argument
); /* delete before dot */
2369 e_delwordprev(Char c
)
2374 if (Cursor
== InputBuf
)
2378 cp
= c_prev_word(Cursor
, InputBuf
, Argument
);
2380 c_push_kill(cp
, Cursor
); /* save the text */
2382 c_delbefore((int)(Cursor
- cp
)); /* delete before dot */
2386 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2388 * Changed the names of some of the ^D family of editor functions to
2389 * correspond to what they actually do and created new e_delnext_list
2392 * Old names: New names:
2394 * delete-char delete-char-or-eof
2395 * F_DELNEXT F_DELNEXT_EOF
2396 * e_delnext e_delnext_eof
2397 * edelnxt edelnxteof
2398 * delete-char-or-eof delete-char
2399 * F_DELNEXT_EOF F_DELNEXT
2400 * e_delnext_eof e_delnext
2401 * edelnxteof edelnxt
2402 * delete-char-or-list delete-char-or-list-or-eof
2403 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
2404 * e_list_delnext e_delnext_list_eof
2406 * (no old equivalent) delete-char-or-list
2412 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2413 /* rename e_delnext() -> e_delnext_eof() */
2419 if (Cursor
== LastChar
) {/* if I'm at the end */
2424 if (Cursor
!= InputBuf
)
2430 c_delafter(Argument
); /* delete after dot */
2431 if (Cursor
> LastChar
)
2432 Cursor
= LastChar
; /* bounds check */
2439 e_delnext_eof(Char c
)
2442 if (Cursor
== LastChar
) {/* if I'm at the end */
2444 if (Cursor
== InputBuf
) {
2445 /* if I'm also at the beginning */
2446 so_write(STReof
, 4);/* then do a EOF */
2454 if (Cursor
!= InputBuf
)
2460 c_delafter(Argument
); /* delete after dot */
2461 if (Cursor
> LastChar
)
2462 Cursor
= LastChar
; /* bounds check */
2468 e_delnext_list(Char c
)
2471 if (Cursor
== LastChar
) { /* if I'm at the end */
2473 *LastChar
= '\0'; /* just in case */
2474 return(CC_LIST_CHOICES
);
2477 c_delafter(Argument
); /* delete after dot */
2478 if (Cursor
> LastChar
)
2479 Cursor
= LastChar
; /* bounds check */
2486 e_delnext_list_eof(Char c
)
2489 if (Cursor
== LastChar
) { /* if I'm at the end */
2490 if (Cursor
== InputBuf
) { /* if I'm also at the beginning */
2491 so_write(STReof
, 4);/* then do a EOF */
2497 *LastChar
= '\0'; /* just in case */
2498 return(CC_LIST_CHOICES
);
2502 c_delafter(Argument
); /* delete after dot */
2503 if (Cursor
> LastChar
)
2504 Cursor
= LastChar
; /* bounds check */
2516 if (Cursor
== LastChar
&& Cursor
== InputBuf
) {
2517 so_write(STReof
, 4); /* then do a EOF */
2523 *LastChar
= '\0'; /* just in case */
2524 rv
= CC_LIST_CHOICES
;
2531 e_delwordnext(Char c
)
2536 if (Cursor
== LastChar
)
2540 cp
= c_next_word(Cursor
, LastChar
, Argument
);
2542 c_push_kill(Cursor
, cp
); /* save the text */
2544 c_delafter((int)(cp
- Cursor
)); /* delete after dot */
2545 if (Cursor
> LastChar
)
2546 Cursor
= LastChar
; /* bounds check */
2557 if (ActionFlag
& TCSHOP_DELETE
) {
2561 RefCursor(); /* move the cursor */
2573 while (Isspace(*Cursor
)) /* We want FIRST non space character */
2575 if (ActionFlag
& TCSHOP_DELETE
) {
2581 RefCursor(); /* move the cursor */
2590 c_push_kill(Cursor
, LastChar
); /* copy it */
2591 LastChar
= Cursor
; /* zap! -- delete to end */
2604 c_push_kill(InputBuf
, Cursor
); /* copy it */
2605 c_delbefore((int)(Cursor
- InputBuf
));
2606 if (Mark
&& Mark
> Cursor
)
2607 Mark
-= Cursor
-InputBuf
;
2616 c_push_kill(InputBuf
, LastChar
); /* copy it */
2617 Cursor
= Mark
= LastChar
= InputBuf
; /* zap! -- delete all of it */
2624 e_killregion(Char c
)
2630 if (Mark
> Cursor
) {
2631 c_push_kill(Cursor
, Mark
); /* copy it */
2632 c_delafter((int)(Mark
- Cursor
)); /* delete it - UNUSED BY VI mode */
2635 else { /* mark is before cursor */
2636 c_push_kill(Mark
, Cursor
); /* copy it */
2637 c_delbefore((int)(Cursor
- Mark
));
2639 if (adrof(STRhighlight
) && MarkIsSet
) {
2649 e_copyregion(Char c
)
2655 if (Mark
> Cursor
) {
2656 c_push_kill(Cursor
, Mark
); /* copy it */
2658 else { /* mark is before cursor */
2659 c_push_kill(Mark
, Cursor
); /* copy it */
2661 return(CC_NORM
); /* don't even need to Refresh() */
2666 e_charswitch(Char cc
)
2672 /* do nothing if we are at beginning of line or have only one char */
2673 if (Cursor
== &InputBuf
[0] || LastChar
== &InputBuf
[1]) {
2677 if (Cursor
< LastChar
) {
2681 Cursor
[-2] = Cursor
[-1];
2688 e_gcharswitch(Char cc
)
2689 { /* gosmacs style ^T */
2693 if (Cursor
> &InputBuf
[1]) {/* must have at least two chars entered */
2695 Cursor
[-2] = Cursor
[-1];
2709 if (Cursor
> InputBuf
) {
2710 if (Argument
> Cursor
- InputBuf
)
2716 if (ActionFlag
& TCSHOP_DELETE
) {
2734 if (Cursor
== InputBuf
)
2738 Cursor
= c_preword(Cursor
, InputBuf
, Argument
, STRshwspace
); /* bounds check */
2740 if (ActionFlag
& TCSHOP_DELETE
) {
2754 if (Cursor
== InputBuf
)
2758 Cursor
= c_prev_word(Cursor
, InputBuf
, Argument
); /* bounds check */
2761 if (ActionFlag
& TCSHOP_DELETE
) {
2775 if (Cursor
< LastChar
) {
2777 if (Cursor
> LastChar
)
2781 if (ActionFlag
& TCSHOP_DELETE
) {
2799 if (Cursor
== LastChar
)
2803 Cursor
= c_next_word(Cursor
, LastChar
, Argument
);
2806 if (ActionFlag
& TCSHOP_DELETE
) {
2820 if (Cursor
== LastChar
)
2824 Cursor
= c_nexword(Cursor
, LastChar
, Argument
);
2827 if (ActionFlag
& TCSHOP_DELETE
) {
2838 v_wordbegnext(Char c
)
2841 if (Cursor
== LastChar
)
2845 Cursor
= c_next_word(Cursor
, LastChar
, Argument
);
2846 if (Cursor
< LastChar
)
2850 if (ActionFlag
& TCSHOP_DELETE
) {
2861 v_repeat_srch(int c
)
2863 CCRETVAL rv
= CC_ERROR
;
2865 xprintf("dir %d patlen %d patbuf %S\n",
2866 c
, (int)patbuf
.len
, patbuf
.s
);
2869 LastCmd
= (KEYCMD
) c
; /* Hack to stop c_hsetpat */
2870 LastChar
= InputBuf
;
2872 case F_DOWN_SEARCH_HIST
:
2873 rv
= e_down_search_hist(0);
2875 case F_UP_SEARCH_HIST
:
2876 rv
= e_up_search_hist(0);
2885 v_csearch_back(Char ch
, int count
, int tflag
)
2893 while (cp
> InputBuf
&& *cp
!= ch
)
2897 if (cp
< InputBuf
|| (cp
== InputBuf
&& *cp
!= ch
))
2900 if (*cp
== ch
&& tflag
)
2905 if (ActionFlag
& TCSHOP_DELETE
) {
2916 v_csearch_fwd(Char ch
, int count
, int tflag
)
2924 while (cp
< LastChar
&& *cp
!= ch
)
2931 if (*cp
== ch
&& tflag
)
2936 if (ActionFlag
& TCSHOP_DELETE
) {
2951 if (ActionFlag
== TCSHOP_DELETE
) {
2952 ActionFlag
= TCSHOP_NOP
;
2957 for (cp
= InputBuf
; cp
< LastChar
; cp
++) {
2962 UndoAction
= TCSHOP_INSERT
;
2964 LastChar
= InputBuf
;
2966 if (c
& TCSHOP_INSERT
)
2967 c_alternativ_key_map(0);
2972 else if (ActionFlag
== TCSHOP_NOP
) {
2976 return(CC_ARGHACK
); /* Do NOT clear out argument */
2988 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
2990 c_get_word(Char
**begin
, Char
**end
)
2995 while (Argument
--) {
2996 while ((cp
<= LastChar
) && (isword(*cp
)))
2999 while ((cp
>= InputBuf
) && (isword(*cp
)))
3004 #endif /* COMMENT */
3013 end
= c_next_word(Cursor
, LastChar
, Argument
);
3015 for (cp
= Cursor
; cp
< end
; cp
++) /* PWP: was cp=begin */
3020 if (Cursor
> LastChar
)
3028 e_capitolcase(Char c
)
3033 end
= c_next_word(Cursor
, LastChar
, Argument
);
3036 for (; cp
< end
; cp
++) {
3044 for (; cp
< end
; cp
++)
3049 if (Cursor
> LastChar
)
3061 end
= c_next_word(Cursor
, LastChar
, Argument
);
3063 for (cp
= Cursor
; cp
< end
; cp
++)
3068 if (Cursor
> LastChar
)
3079 if (adrof(STRhighlight
) && MarkIsSet
&& Mark
!= Cursor
) {
3091 e_exchange_mark(Char c
)
3106 { /* multiply current argument by 4 */
3108 if (Argument
> 1000000)
3116 quote_mode_cleanup(void *unused
)
3131 cleanup_push(&c
, quote_mode_cleanup
); /* Using &c just as a mark */
3132 num
= GetNextChar(&ch
);
3135 return e_insert(ch
);
3137 return e_send_eof(0);
3146 return(CC_ARGHACK
); /* preserve argument */
3152 e_extendnext(Char c
)
3154 CurrentKeyMap
= CcAltMap
;
3155 return(CC_ARGHACK
); /* preserve argument */
3163 { /* move to beginning of line and start vi
3170 UndoAction
= TCSHOP_DELETE
;
3172 RefCursor(); /* move the cursor */
3173 c_alternativ_key_map(0);
3180 { /* vi mode overwrite one character */
3182 c_alternativ_key_map(0);
3183 inputmode
= MODE_REPLACE_1
;
3184 UndoAction
= TCSHOP_CHANGE
; /* Set Up for VI undo command */
3193 { /* vi mode start overwriting */
3195 c_alternativ_key_map(0);
3196 inputmode
= MODE_REPLACE
;
3197 UndoAction
= TCSHOP_CHANGE
; /* Set Up for VI undo command */
3206 { /* vi mode substitute for one char */
3208 c_delafter(Argument
);
3209 c_alternativ_key_map(0);
3216 { /* vi mode replace whole line */
3218 (void) e_killall(0);
3219 c_alternativ_key_map(0);
3226 { /* vi mode change to end of line */
3228 (void) e_killend(0);
3229 c_alternativ_key_map(0);
3236 { /* vi mode start inserting */
3238 c_alternativ_key_map(0);
3242 UndoAction
= TCSHOP_DELETE
;
3250 { /* vi mode start adding */
3252 c_alternativ_key_map(0);
3253 if (Cursor
< LastChar
)
3256 if (Cursor
> LastChar
)
3263 UndoAction
= TCSHOP_DELETE
;
3271 { /* vi mode to add at end of line */
3273 c_alternativ_key_map(0);
3276 InsertPos
= LastChar
; /* Mark where insertion begins */
3278 UndoAction
= TCSHOP_DELETE
;
3286 v_change_case(Char cc
)
3291 if (Cursor
< LastChar
) {
3292 #ifndef WINNT_NATIVE
3296 #endif /* WINNT_NATIVE */
3298 *Cursor
++ = Tolower(c
);
3299 else if (Islower(c
))
3300 *Cursor
++ = Toupper(c
);
3303 RefPlusOne(1); /* fast refresh for one char */
3316 for (p
= InputBuf
; Isspace(*p
); p
++)
3323 return(e_newline(0));
3329 { /* erase all of current line, start again */
3331 ResetInLine(0); /* reset the input pointers */
3350 ClearScreen(); /* clear the whole real screen */
3351 ClearDisp(); /* reset everything */
3360 #if defined(_MINIX) || defined(WINNT_NATIVE)
3361 /* SAK PATCH: erase all of current line, start again */
3362 ResetInLine(0); /* reset the input pointers */
3365 return (CC_REFRESH
);
3366 #else /* !_MINIX && !WINNT_NATIVE */
3369 #endif /* _MINIX || WINNT_NATIVE */
3373 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3374 * Function to send a character back to the input stream in cooked
3375 * mode. Only works if we have TIOCSTI
3379 e_stuff_char(Char c
)
3382 int was_raw
= Tty_raw_mode
;
3383 char buf
[MB_LEN_MAX
];
3387 (void) Cookedmode();
3389 (void) xwrite(SHIN
, "\n", 1);
3390 len
= one_wctomb(buf
, c
& CHAR
);
3391 for (i
= 0; i
< len
; i
++)
3392 (void) ioctl(SHIN
, TIOCSTI
, (ioctl_t
) &buf
[i
]);
3396 return(e_redisp(c
));
3397 #else /* !TIOCSTI */
3399 #endif /* !TIOCSTI */
3407 inputmode
= (inputmode
== MODE_INSERT
? MODE_REPLACE
: MODE_INSERT
);
3422 e_tty_flusho(Char c
)
3456 /* returns the number of (attempted) expansions */
3460 *LastChar
= '\0'; /* just in case */
3461 return c_substitute();
3466 e_expand_history(Char c
)
3469 (void)ExpandHistory();
3475 e_magic_space(Char c
)
3478 *LastChar
= '\0'; /* just in case */
3479 (void)c_substitute();
3480 return(e_insert(' '));
3492 ret
= e_inc_search(F_DOWN_SEARCH_HIST
);
3493 if (adrof(STRhighlight
) && IncMatchLen
) {
3513 ret
= e_inc_search(F_UP_SEARCH_HIST
);
3514 if (adrof(STRhighlight
) && IncMatchLen
) {
3528 Char
*cp
, *oldc
, *dp
;
3531 if (Cursor
== InputBuf
)
3536 /* does a bounds check */
3537 cp
= c_prev_word(Cursor
, InputBuf
, Argument
);
3539 c_insert((int)(oldc
- cp
));
3540 for (dp
= oldc
; cp
< oldc
&& dp
< LastChar
; cp
++)
3543 Cursor
= dp
; /* put cursor at end */
3550 e_tty_starto(Char c
)
3559 e_load_average(Char c
)
3565 * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3566 * there even if they don't use it. (lukem@netbsd.org)
3568 if (ioctl(SHIN
, TIOCSTAT
, (ioctl_t
) &c
) < 0)
3570 xprintf("%s", CGETS(5, 1, "Load average unavailable\n"));
3580 * Delete with insert == change: first we delete and then we leave in
3583 return(v_action(TCSHOP_DELETE
|TCSHOP_INSERT
));
3591 return(v_action(TCSHOP_DELETE
));
3600 if (Cursor
== LastChar
)
3604 Cursor
= c_endword(Cursor
, LastChar
, Argument
, STRshwspace
);
3606 if (ActionFlag
& TCSHOP_DELETE
)
3622 if (Cursor
== LastChar
)
3626 Cursor
= c_eword(Cursor
, LastChar
, Argument
);
3628 if (ActionFlag
& TCSHOP_DELETE
) {
3645 if (GetNextChar(&ch
) != 1)
3646 return e_send_eof(0);
3648 srch_dir
= CHAR_FWD
;
3651 return v_csearch_fwd(ch
, Argument
, 0);
3662 if (GetNextChar(&ch
) != 1)
3663 return e_send_eof(0);
3665 srch_dir
= CHAR_BACK
;
3668 return v_csearch_back(ch
, Argument
, 0);
3673 v_charto_fwd(Char c
)
3678 if (GetNextChar(&ch
) != 1)
3679 return e_send_eof(0);
3681 return v_csearch_fwd(ch
, Argument
, 1);
3687 v_charto_back(Char c
)
3692 if (GetNextChar(&ch
) != 1)
3693 return e_send_eof(0);
3695 return v_csearch_back(ch
, Argument
, 1);
3706 return srch_dir
== CHAR_FWD
? v_csearch_fwd(srch_char
, Argument
, 0) :
3707 v_csearch_back(srch_char
, Argument
, 0);
3712 v_rchar_back(Char c
)
3718 return srch_dir
== CHAR_BACK
? v_csearch_fwd(srch_char
, Argument
, 0) :
3719 v_csearch_back(srch_char
, Argument
, 0);
3732 switch (UndoAction
) {
3733 case TCSHOP_DELETE
|TCSHOP_INSERT
:
3735 if (UndoSize
== 0) return(CC_NORM
);
3738 for (loop
=0; loop
< UndoSize
; loop
++) /* copy the chars */
3739 *kp
++ = *cp
++; /* into UndoBuf */
3741 for (cp
= UndoPtr
; cp
<= LastChar
; cp
++)
3744 LastChar
-= UndoSize
;
3747 UndoAction
= TCSHOP_INSERT
;
3751 if (UndoSize
== 0) return(CC_NORM
);
3755 c_insert(UndoSize
); /* open the space, */
3756 for (loop
= 0; loop
< UndoSize
; loop
++) /* copy the chars */
3759 UndoAction
= TCSHOP_DELETE
;
3763 if (UndoSize
== 0) return(CC_NORM
);
3767 size
= (int)(Cursor
-LastChar
); /* NOT NSL independant */
3768 if (size
< UndoSize
)
3770 for(loop
= 0; loop
< size
; loop
++) {
3789 return v_search(F_UP_SEARCH_HIST
);
3797 return v_search(F_DOWN_SEARCH_HIST
);
3805 if (patbuf
.len
== 0) return(CC_ERROR
);
3806 return(v_repeat_srch(searchdir
));
3811 v_rsrch_back(Char c
)
3814 if (patbuf
.len
== 0) return(CC_ERROR
);
3815 return(v_repeat_srch(searchdir
== F_UP_SEARCH_HIST
?
3816 F_DOWN_SEARCH_HIST
: F_UP_SEARCH_HIST
));
3819 #ifndef WINNT_NATIVE
3820 /* Since ed.defns.h is generated from ed.defns.c, these empty
3821 functions will keep the F_NUM_FNS consistent
3824 e_copy_to_clipboard(Char c
)
3831 e_paste_from_clipboard(Char c
)
3838 e_dosify_next(Char c
)
3844 e_dosify_prev(Char c
)
3861 #endif /* !WINNT_NATIVE */
3865 MoveCursor(int n
) /* move cursor + right - left char */
3867 Cursor
= Cursor
+ n
;
3868 if (Cursor
< InputBuf
)
3870 if (Cursor
> LastChar
)
3884 if (p
< InputBuf
|| p
> LastChar
)
3885 return 1; /* Error */