1 /* $Header: /src/pub/tcsh/ed.chared.c,v 3.71 2002/03/08 17:36:45 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("$Id: ed.chared.c,v 3.71 2002/03/08 17:36:45 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 Char patbuf
[INBUFSIZE
]; /* Search target */
107 static int patlen
= 0;
111 static int srch_dir
= CHAR_FWD
; /* Direction of last search */
112 static Char srch_char
= 0; /* Search target */
114 /* all routines that start with c_ are private to this set of routines */
115 static void c_alternativ_key_map
__P((int));
116 void c_insert
__P((int));
117 void c_delafter
__P((int));
118 void c_delbefore
__P((int));
119 static int c_to_class
__P((int));
120 static Char
*c_prev_word
__P((Char
*, Char
*, int));
121 static Char
*c_next_word
__P((Char
*, Char
*, int));
122 static Char
*c_number
__P((Char
*, int *, int));
123 static Char
*c_expand
__P((Char
*));
124 static void c_excl
__P((Char
*));
125 static void c_substitute
__P((void));
126 static void c_delfini
__P((void));
127 static int c_hmatch
__P((Char
*));
128 static void c_hsetpat
__P((void));
130 static void c_get_word
__P((Char
**, Char
**));
132 static Char
*c_preword
__P((Char
*, Char
*, int, Char
*));
133 static Char
*c_nexword
__P((Char
*, Char
*, int));
134 static Char
*c_endword
__P((Char
*, Char
*, int, Char
*));
135 static Char
*c_eword
__P((Char
*, Char
*, int));
136 static void c_push_kill
__P((Char
*, Char
*));
137 static CCRETVAL c_get_histline
__P((void));
138 static CCRETVAL c_search_line
__P((Char
*, int));
139 static CCRETVAL v_repeat_srch
__P((int));
140 static CCRETVAL e_inc_search
__P((int));
141 static CCRETVAL v_search
__P((int));
142 static CCRETVAL v_csearch_fwd
__P((int, int, int));
143 static CCRETVAL v_action
__P((int));
144 static CCRETVAL v_csearch_back
__P((int, int, int));
146 #if defined(DSPMBYTE)
147 static void e_charfwd_mbyte
__P((int));
148 static void e_charback_mbyte
__P((int));
150 static int extins
= 0;
154 c_alternativ_key_map(state
)
159 CurrentKeyMap
= CcKeyMap
;
162 CurrentKeyMap
= CcAltMap
;
168 AltKeyMap
= (Char
) state
;
177 if (LastChar
+ num
>= InputLim
)
178 return; /* can't go past end of buffer */
180 if (Cursor
< LastChar
) { /* if I must move chars */
181 for (cp
= LastChar
; cp
>= Cursor
; cp
--)
191 Char
*cp
, *kp
= NULL
;
193 #if defined(DSPMBYTE)
199 if (num
> LastChar
- Cursor
)
200 num
= (int) (LastChar
- Cursor
); /* bounds check */
202 if (num
> 0) { /* if I can delete anything */
203 #if defined(DSPMBYTE)
204 /* check for code of deleted character */
205 if (_enable_mbdisp
) {
206 for (wkcp
= Cursor
; wkcp
< Cursor
+ num
; wkcp
++) {
208 extdel
= Ismbyte1(*wkcp
); /* check to 1st. byte */
210 extdel
= 0; /* if 2nd. byte, force set to 0 */
215 kp
= UndoBuf
; /* Set Up for VI undo command */
216 UndoAction
= TCSHOP_INSERT
;
219 for (cp
= Cursor
; cp
<= LastChar
; cp
++) {
220 *kp
++ = *cp
; /* Save deleted chars into undobuf */
225 for (cp
= Cursor
; cp
<= LastChar
; cp
++)
228 #if defined(DSPMBYTE)
229 if (_enable_mbdisp
&& extdel
&& Ismbyte2(*Cursor
)) {
232 *kp
++ = *Cursor
; /* Save deleted chars into undobuf */
234 for (cp
= Cursor
; cp
<= LastChar
; cp
++)
246 * XXX: We don't want to do that. In emacs mode overwrite should be
247 * sticky. I am not sure how that affects vi mode
249 inputmode
= MODE_INSERT
;
255 c_delbefore(num
) /* delete before dot, with bounds checking */
258 Char
*cp
, *kp
= NULL
;
260 #if defined(DSPMBYTE)
267 if (num
> Cursor
- InputBuf
)
268 num
= (int) (Cursor
- InputBuf
); /* bounds check */
270 if (num
> 0) { /* if I can delete anything */
271 #if defined(DSPMBYTE)
272 nowcur
= Cursor
- num
;
276 kp
= UndoBuf
; /* Set Up for VI undo command */
277 UndoAction
= TCSHOP_INSERT
;
279 UndoPtr
= Cursor
- num
;
280 for (cp
= Cursor
- num
; cp
<= LastChar
; cp
++) {
286 for (cp
= Cursor
- num
; cp
<= LastChar
; cp
++)
289 #if defined(DSPMBYTE)
290 if (_enable_mbdisp
) {
291 for (wkcp
= InputBuf
; wkcp
< nowcur
; wkcp
++) {
293 extdel
= Ismbyte1(*wkcp
); /* check to 1st. byte */
295 extdel
= 0; /* if 2nd. byte, force set to 0 */
297 if (extdel
&& Ismbyte2(delc
)) {
302 /* Save deleted chars into undobuf */
304 for (cp
= nowcur
- 1; cp
<= LastChar
; cp
++)
316 c_preword(p
, low
, n
, delim
)
317 Char
*p
, *low
, *delim
;
324 while (prev
< p
) { /* Skip initial non-word chars */
325 if (!Strchr(delim
, *prev
) || *(prev
-1) == (Char
)'\\')
334 new = c_endword(prev
-1, p
, 1, delim
); /* Skip to next non-word char */
335 new++; /* Step away from end of word */
336 while (new <= p
) { /* Skip trailing non-word chars */
337 if (!Strchr(delim
, *new) || *(new-1) == (Char
)'\\')
343 p
= prev
; /* Set to previous word start */
352 * c_to_class() returns the class of the given character.
354 * This is used to make the c_prev_word() and c_next_word() functions
355 * work like vi's, which classify characters. A word is a sequence of
356 * characters belonging to the same class, classes being defined as
360 * 2/ alphanumeric chars, + underscore
368 return C_CLASS_WHITE
;
370 if (Isdigit(ch
) || Isalpha(ch
) || ch
== '_')
371 return C_CLASS_ALNUM
;
373 return C_CLASS_OTHER
;
377 c_prev_word(p
, low
, n
)
385 while ((p
>= low
) && !isword(*p
))
387 while ((p
>= low
) && isword(*p
))
391 /* cp now points to one character before the word */
395 /* cp now points where we want it */
405 /* scan until beginning of current word (may be all whitespace!) */
406 c_class
= c_to_class(*p
);
407 while ((p
>= low
) && c_class
== c_to_class(*p
))
410 /* if this was a non_whitespace word, we're ready */
411 if (c_class
!= C_CLASS_WHITE
)
414 /* otherwise, move back to beginning of the word just found */
415 c_class
= c_to_class(*p
);
416 while ((p
>= low
) && c_class
== c_to_class(*p
))
420 p
++; /* correct overshoot */
426 c_next_word(p
, high
, n
)
432 while ((p
< high
) && !isword(*p
))
434 while ((p
< high
) && isword(*p
))
439 /* p now points where we want it */
449 /* scan until end of current word (may be all whitespace!) */
450 c_class
= c_to_class(*p
);
451 while ((p
< high
) && c_class
== c_to_class(*p
))
454 /* if this was all whitespace, we're ready */
455 if (c_class
== C_CLASS_WHITE
)
458 /* if we've found white-space at the end of the word, skip it */
459 while ((p
< high
) && c_to_class(*p
) == C_CLASS_WHITE
)
463 p
--; /* correct overshoot */
469 c_nexword(p
, high
, n
)
474 while ((p
< high
) && !Isspace(*p
))
476 while ((p
< high
) && Isspace(*p
))
482 /* p now points where we want it */
487 * Expand-History (originally "Magic-Space") code added by
488 * Ray Moody <ray@gibbs.physics.purdue.edu>
489 * this is a neat, but odd, addition.
493 * c_number: Ignore character p points to, return number appearing after that.
494 * A '$' by itself means a big number; "$-" is for negative; '^' means 1.
495 * Return p pointing to last char used.
499 * dval is the number to subtract from for things like $-3
503 c_number(p
, num
, dval
)
517 *num
= NCARGS
; /* Handle $ */
520 sign
= -1; /* Handle $- */
523 for (i
= 0; *p
>= '0' && *p
<= '9'; i
= 10 * i
+ *p
++ - '0')
525 *num
= (sign
< 0 ? dval
- i
: i
);
530 * excl_expand: There is an excl to be expanded to p -- do the right thing
531 * with it and return a version of p advanced over the expanded stuff. Also,
532 * update tsh_cur and related things as appropriate...
540 struct Hist
*h
= Histlist
.Hnext
;
542 int i
, from
, to
, dval
;
548 Char
*modbuf
, *omodbuf
;
553 switch (*(q
= p
+ 1)) {
556 bend
= expand_lex(buf
, INBUFSIZE
, &h
->Hlex
, 1, 1);
560 if ((l
= (h
->Hlex
).prev
) != 0)
561 bend
= expand_lex(buf
, INBUFSIZE
, l
->prev
->prev
, 0, 0);
565 bend
= expand_lex(buf
, INBUFSIZE
, &h
->Hlex
, 1, NCARGS
);
569 if (been_once
) { /* unknown argument */
570 /* assume it's a modifier, e.g. !foo:h, and get whole cmd */
571 bend
= expand_lex(buf
, INBUFSIZE
, &h
->Hlex
, 0, NCARGS
);
577 if (*q
== ':') /* short form: !:arg */
582 * Search for a space, tab, or colon. See if we have a number (as
583 * in !1234:xyz). Remember the number.
585 for (i
= 0, all_dig
= 1;
586 *q
!= ' ' && *q
!= '\t' && *q
!= ':' && q
< Cursor
; q
++) {
588 * PWP: !-4 is a valid history argument too, therefore the test
589 * is if not a digit, or not a - as the first character.
591 if ((*q
< '0' || *q
> '9') && (*q
!= '-' || q
!= p
+ 1))
594 all_dig
= 2;/* we are sneeky about this */
596 i
= 10 * i
+ *q
- '0';
601 * If we have a number, search for event i. Otherwise, search for
602 * a named event (as in !foo). (In this case, I is the length of
607 i
= -i
; /* make it negitive */
608 if (i
< 0) /* if !-4 (for example) */
609 i
= eventno
+ 1 + i
; /* remember: i is < 0 */
610 for (; h
; h
= h
->Hnext
) {
616 for (i
= (int) (q
- p
); h
; h
= h
->Hnext
) {
617 if ((l
= &h
->Hlex
) != 0) {
618 if (!Strncmp(p
+ 1, l
->next
->word
, (size_t) i
))
626 if (q
[1] == ':' || q
[1] == '-' || q
[1] == '*' ||
627 q
[1] == '$' || q
[1] == '^') { /* get some args */
628 p
= q
[1] == ':' ? ++q
: q
;
632 if ((q
[1] < '0' || q
[1] > '9') &&
633 q
[1] != '-' && q
[1] != '$' && q
[1] != '^')
638 if (q
[1] == '$' && (q
[2] != '-' || q
[3] < '0' || q
[3] > '9'))
641 * Count up the number of words in this event. Store it in dval.
642 * Dval will be fed to number.
645 if ((l
= h
->Hlex
.prev
) != 0) {
646 for (l
= l
->prev
; l
!= h
->Hlex
.next
; l
= l
->prev
, dval
++)
654 q
= c_number(q
, &from
, dval
);
657 if ((q
[1] < '0' || q
[1] > '9') && q
[1] != '$')
660 q
= c_number(q
, &to
, dval
);
662 else if (q
[1] == '*') {
669 if (from
< 0 || to
< from
)
671 bend
= expand_lex(buf
, INBUFSIZE
, &h
->Hlex
, from
, to
);
673 else { /* get whole cmd */
674 bend
= expand_lex(buf
, INBUFSIZE
, &h
->Hlex
, 0, NCARGS
);
680 * Apply modifiers, if any.
684 modbuf
= omodbuf
= buf
;
685 while (q
[1] == ':' && modbuf
!= NULL
) {
695 if ((modbuf
= domod(omodbuf
, (int) q
[2])) != NULL
) {
697 xfree((ptr_t
) omodbuf
);
705 /* Not implemented; this needs to be done before expanding
706 * lex. We don't have the words available to us anymore.
726 if (omodbuf
!= buf
) {
727 (void) Strcpy(buf
, omodbuf
);
728 xfree((ptr_t
) omodbuf
);
734 * Now replace the text from op to q inclusive with the text from buf to
740 * Now replace text non-inclusively like a real CS major!
742 if (LastChar
+ (bend
- buf
) - (q
- op
) >= InputLim
)
744 (void) memmove((ptr_t
) (q
+ (bend
- buf
) - (q
- op
)), (ptr_t
) q
,
745 (size_t) ((LastChar
- q
) * sizeof(Char
)));
746 LastChar
+= (bend
- buf
) - (q
- op
);
747 Cursor
+= (bend
- buf
) - (q
- op
);
748 (void) memmove((ptr_t
) op
, (ptr_t
) buf
,
749 (size_t) ((bend
- buf
) * sizeof(Char
)));
751 return(op
+ (bend
- buf
));
758 * c_excl: An excl has been found at point p -- back up and find some white
759 * space (or the beginning of the buffer) and properly expand all the excl's
760 * from there up to the current cursor position. We also avoid (trying to)
772 * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise,
773 * back p up to just before the current word.
775 if ((p
[1] == ' ' || p
[1] == '\t') &&
776 (p
[-1] == ' ' || p
[-1] == '\t' || p
[-1] == '>')) {
777 for (q
= p
- 1; q
> InputBuf
&& (*q
== ' ' || *q
== '\t'); --q
)
783 while (*p
!= ' ' && *p
!= '\t' && p
> InputBuf
)
788 * Forever: Look for history char. (Stop looking when we find the cursor.)
789 * Count backslashes. Of odd, skip history char. Return if all done.
790 * Expand if even number of backslashes.
793 while (*p
!= HIST
&& p
< Cursor
)
795 for (i
= 1; (p
- i
) >= InputBuf
&& p
[-i
] == '\\'; i
++)
813 * Start p out one character before the cursor. Move it backwards looking
814 * for white space, the beginning of the line, or a history character.
817 p
> InputBuf
&& *p
!= ' ' && *p
!= '\t' && *p
!= HIST
; --p
)
821 * If we found a history character, go expand it.
829 c_delfini() /* Finish up delete action */
833 if (ActionFlag
& TCSHOP_INSERT
)
834 c_alternativ_key_map(0);
836 ActionFlag
= TCSHOP_NOP
;
841 UndoAction
= TCSHOP_INSERT
;
843 if (Cursor
> ActionPos
) {
844 Size
= (int) (Cursor
-ActionPos
);
847 #if defined(DSPMBYTE)
848 if (_enable_mbdisp
&& extdel
) {
855 else if (Cursor
< ActionPos
) {
856 Size
= (int)(ActionPos
-Cursor
);
868 c_endword(p
, high
, n
, delim
)
869 Char
*p
, *high
, *delim
;
876 while (p
< high
) { /* Skip non-word chars */
877 if (!Strchr(delim
, *p
) || *(p
-1) == (Char
)'\\')
881 while (p
< high
) { /* Skip string */
882 if ((*p
== (Char
)'\'' || *p
== (Char
)'"')) { /* Quotation marks? */
883 if (inquote
|| *(p
-1) != (Char
)'\\') { /* Should it be honored? */
884 if (inquote
== 0) inquote
= *p
;
885 else if (inquote
== *p
) inquote
= 0;
888 /* Break if unquoted non-word char */
889 if (!inquote
&& Strchr(delim
, *p
) && *(p
-1) != (Char
)'\\')
908 while ((p
< high
) && Isspace(*p
))
912 while ((p
< high
) && Isalnum(*p
))
915 while ((p
< high
) && !(Isspace(*p
) || Isalnum(*p
)))
923 /* Set the max length of the kill ring */
932 max
= 1; /* no ring, but always one buffer */
933 if (max
== KillRingMax
)
935 new = (CStr
*)xcalloc((size_t) max
, sizeof(CStr
));
936 if (KillRing
!= NULL
) {
937 if (KillRingLen
!= 0) {
938 if (max
>= KillRingLen
) {
943 j
= (KillPos
- count
+ KillRingLen
) % KillRingLen
;
945 for (i
= 0; i
< KillRingLen
; i
++) {
946 if (i
< count
) /* copy latest */
947 new[i
] = KillRing
[j
];
948 else /* free the others */
949 xfree(KillRing
[j
].buf
);
950 j
= (j
+ 1) % KillRingLen
;
953 KillPos
= count
% max
;
962 /* Push string from start upto (but not including) end onto kill ring */
964 c_push_kill(start
, end
)
969 int len
= end
- start
, i
, j
, k
;
971 /* Check for duplicates? */
972 if (KillRingLen
> 0 && (dp
= varval(STRkilldup
)) != STRNULL
) {
973 YankPos
= (KillPos
- 1 + KillRingLen
) % KillRingLen
;
974 if (eq(dp
, STRerase
)) { /* erase earlier one (actually move up) */
976 for (i
= 0; i
< KillRingLen
; i
++) {
977 if (Strncmp(KillRing
[j
].buf
, start
, (size_t) len
) == 0 &&
978 KillRing
[j
].buf
[len
] == '\0') {
980 for ( ; i
> 0; i
--) {
982 j
= (j
+ 1) % KillRingLen
;
983 KillRing
[k
] = KillRing
[j
];
988 j
= (j
- 1 + KillRingLen
) % KillRingLen
;
990 } else if (eq(dp
, STRall
)) { /* skip if any earlier */
991 for (i
= 0; i
< KillRingLen
; i
++)
992 if (Strncmp(KillRing
[i
].buf
, start
, (size_t) len
) == 0 &&
993 KillRing
[i
].buf
[len
] == '\0')
995 } else if (eq(dp
, STRprev
)) { /* skip if immediately previous */
997 if (Strncmp(KillRing
[j
].buf
, start
, (size_t) len
) == 0 &&
998 KillRing
[j
].buf
[len
] == '\0')
1003 /* No duplicate, go ahead and push */
1004 len
++; /* need space for '\0' */
1006 if (KillRingLen
< KillRingMax
)
1008 pos
= &KillRing
[KillPos
];
1009 KillPos
= (KillPos
+ 1) % KillRingMax
;
1010 if (pos
->len
< len
) {
1011 if (pos
->buf
== NULL
)
1012 pos
->buf
= (Char
*) xmalloc(len
* sizeof(Char
));
1014 pos
->buf
= (Char
*) xrealloc((ptr_t
) pos
->buf
, len
* sizeof(Char
));
1030 if (Hist_num
== 0) { /* if really the current line */
1031 copyn(InputBuf
, HistBuf
, INBUFSIZE
);
1032 LastChar
= InputBuf
+ (LastHist
- HistBuf
);
1044 hp
= Histlist
.Hnext
;
1048 for (h
= 1; h
< Hist_num
; h
++) {
1049 if ((hp
->Hnext
) == NULL
) {
1056 if (HistLit
&& hp
->histline
) {
1057 copyn(InputBuf
, hp
->histline
, INBUFSIZE
);
1061 (void) sprlex(InputBuf
, sizeof(InputBuf
) / sizeof(Char
), &hp
->Hlex
);
1064 LastChar
= InputBuf
+ Strlen(InputBuf
);
1066 if (LastChar
> InputBuf
) {
1067 if (LastChar
[-1] == '\n')
1070 if (LastChar
[-1] == ' ')
1073 if (LastChar
< InputBuf
)
1074 LastChar
= InputBuf
;
1088 c_search_line(pattern
, dir
)
1095 len
= (int) Strlen(pattern
);
1097 if (dir
== F_UP_SEARCH_HIST
) {
1098 for (cp
= Cursor
; cp
>= InputBuf
; cp
--)
1099 if (Strncmp(cp
, pattern
, (size_t) len
) == 0 ||
1100 Gmatch(cp
, pattern
)) {
1106 for (cp
= Cursor
; *cp
!= '\0' && cp
< InputLim
; cp
++)
1107 if (Strncmp(cp
, pattern
, (size_t) len
) == 0 ||
1108 Gmatch(cp
, pattern
)) {
1120 static Char STRfwd
[] = { 'f', 'w', 'd', '\0' },
1121 STRbck
[] = { 'b', 'c', 'k', '\0' };
1122 static Char pchar
= ':'; /* ':' = normal, '?' = failed */
1123 static Char endcmd
[2];
1125 *oldCursor
= Cursor
,
1127 CCRETVAL ret
= CC_NORM
;
1128 int oldHist_num
= Hist_num
,
1133 if (LastChar
+ sizeof(STRfwd
)/sizeof(Char
) + 2 + patlen
>= InputLim
)
1138 if (patlen
== 0) { /* first round */
1140 patbuf
[patlen
++] = '*';
1144 for (cp
= newdir
== F_UP_SEARCH_HIST
? STRbck
: STRfwd
;
1145 *cp
; *LastChar
++ = *cp
++)
1147 *LastChar
++ = pchar
;
1148 for (cp
= &patbuf
[1]; cp
< &patbuf
[patlen
]; *LastChar
++ = *cp
++)
1153 if (GetNextChar(&ch
) != 1)
1154 return(e_send_eof(0));
1156 switch (CurrentKeyMap
[(unsigned char) ch
]) {
1160 if (patlen
> INBUFSIZE
- 3)
1163 patbuf
[patlen
++] = ch
;
1171 newdir
= F_DOWN_SEARCH_HIST
;
1176 newdir
= F_UP_SEARCH_HIST
;
1189 case 0007: /* ^G: Abort */
1194 case 0027: /* ^W: Append word */
1195 /* No can do if globbing characters in pattern */
1196 for (cp
= &patbuf
[1]; ; cp
++)
1197 if (cp
>= &patbuf
[patlen
]) {
1198 Cursor
+= patlen
- 1;
1199 cp
= c_next_word(Cursor
, LastChar
, 1);
1200 while (Cursor
< cp
&& *Cursor
!= '\n') {
1201 if (patlen
> INBUFSIZE
- 3) {
1205 patbuf
[patlen
++] = *Cursor
;
1206 *LastChar
++ = *Cursor
++;
1212 } else if (isglob(*cp
)) {
1218 default: /* Terminate and execute cmd */
1223 case 0033: /* ESC: Terminate */
1231 while (LastChar
> InputBuf
&& *LastChar
!= '\n')
1237 /* Can't search if unmatched '[' */
1238 for (cp
= &patbuf
[patlen
- 1], ch
= ']'; cp
> patbuf
; cp
--)
1239 if (*cp
== '[' || *cp
== ']') {
1244 if (patlen
> 1 && ch
!= '[') {
1245 if (redo
&& newdir
== dir
) {
1246 if (pchar
== '?') { /* wrap around */
1247 Hist_num
= newdir
== F_UP_SEARCH_HIST
? 0 : 0x7fffffff;
1248 if (c_get_histline() == CC_ERROR
)
1249 /* Hist_num was fixed by first call */
1250 (void) c_get_histline();
1251 Cursor
= newdir
== F_UP_SEARCH_HIST
?
1252 LastChar
: InputBuf
;
1254 Cursor
+= newdir
== F_UP_SEARCH_HIST
? -1 : 1;
1256 patbuf
[patlen
++] = '*';
1257 patbuf
[patlen
] = '\0';
1258 if (Cursor
< InputBuf
|| Cursor
> LastChar
||
1259 (ret
= c_search_line(&patbuf
[1], newdir
)) == CC_ERROR
) {
1260 LastCmd
= (KEYCMD
) newdir
; /* avoid c_hsetpat */
1261 ret
= newdir
== F_UP_SEARCH_HIST
?
1262 e_up_search_hist(0) : e_down_search_hist(0);
1263 if (ret
!= CC_ERROR
) {
1264 Cursor
= newdir
== F_UP_SEARCH_HIST
?
1265 LastChar
: InputBuf
;
1266 (void) c_search_line(&patbuf
[1], newdir
);
1269 patbuf
[--patlen
] = '\0';
1270 if (ret
== CC_ERROR
) {
1272 if (Hist_num
!= oldHist_num
) {
1273 Hist_num
= oldHist_num
;
1274 if (c_get_histline() == CC_ERROR
)
1284 ret
= e_inc_search(newdir
);
1286 if (ret
== CC_ERROR
&& pchar
== '?' && oldpchar
== ':') {
1287 /* break abort of failed search at last non-failed */
1293 if (ret
== CC_NORM
|| (ret
== CC_ERROR
&& oldpatlen
== 0)) {
1294 /* restore on normal return or error exit */
1297 if (Hist_num
!= oldHist_num
) {
1298 Hist_num
= oldHist_num
;
1299 if (c_get_histline() == CC_ERROR
)
1303 if (ret
== CC_ERROR
)
1306 if (done
|| ret
!= CC_NORM
)
1318 Char tmpbuf
[INBUFSIZE
];
1319 Char oldbuf
[INBUFSIZE
];
1323 copyn(oldbuf
, InputBuf
, INBUFSIZE
);
1327 tmpbuf
[tmplen
++] = '*';
1330 LastChar
= InputBuf
;
1334 c_insert(2); /* prompt + '\n' */
1336 *Cursor
++ = dir
== F_UP_SEARCH_HIST
? '?' : '/';
1338 for (ch
= 0;ch
== 0;) {
1339 if (GetNextChar(&ch
) != 1)
1340 return(e_send_eof(0));
1342 case 0010: /* Delete and backspace */
1347 tmpbuf
[tmplen
--] = '\0';
1350 copyn(InputBuf
, oldbuf
, INBUFSIZE
);
1359 case 0033: /* ESC */
1361 case '\r': /* Newline */
1364 case '\012': /* ASCII Line feed */
1365 case '\015': /* ASCII (or EBCDIC) Return */
1370 if (tmplen
>= INBUFSIZE
)
1373 tmpbuf
[tmplen
++] = ch
;
1385 * Use the old pattern, but wild-card it.
1389 LastChar
= InputBuf
;
1394 if (patbuf
[0] != '*') {
1395 (void) Strcpy(tmpbuf
, patbuf
);
1397 (void) Strcpy(&patbuf
[1], tmpbuf
);
1399 patbuf
[patlen
++] = '*';
1400 patbuf
[patlen
] = '\0';
1404 tmpbuf
[tmplen
++] = '*';
1405 tmpbuf
[tmplen
] = '\0';
1406 (void) Strcpy(patbuf
, tmpbuf
);
1409 LastCmd
= (KEYCMD
) dir
; /* avoid c_hsetpat */
1410 Cursor
= LastChar
= InputBuf
;
1411 if ((dir
== F_UP_SEARCH_HIST
? e_up_search_hist(0) :
1412 e_down_search_hist(0)) == CC_ERROR
) {
1430 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an
1431 * entry point, called from the CcKeyMap indirected into the
1442 ActionFlag
= TCSHOP_NOP
; /* [Esc] cancels pending action */
1445 if (UndoPtr
> Cursor
)
1446 UndoSize
= (int)(UndoPtr
- Cursor
);
1448 UndoSize
= (int)(Cursor
- UndoPtr
);
1450 inputmode
= MODE_INSERT
;
1451 c_alternativ_key_map(1);
1454 * We don't want to move the cursor, because all the editing
1455 * commands don't include the character under the cursor.
1457 if (Cursor
> InputBuf
)
1468 { /* bound to keys that arn't really assigned */
1480 #if defined(DSPMBYTE)
1483 static int exterr
= 0;
1485 #ifndef SHORT_STRINGS
1486 c
&= ASCII
; /* no meta chars ever */
1488 #if defined(DSPMBYTE)
1489 ret
= (CCRETVAL
) CC_NORM
;
1493 return(CC_ERROR
); /* no NULs in the input ever!! */
1495 if (LastChar
+ Argument
>= InputLim
)
1496 return(CC_ERROR
); /* end of buffer space */
1498 if (Argument
== 1) { /* How was this optimized ???? */
1500 #if defined(DSPMBYTE)
1501 if(_enable_mbdisp
&& extins
&& exterr
&& Ismbyte2(c
)) {
1507 if (inputmode
!= MODE_INSERT
) {
1508 UndoBuf
[UndoSize
++] = *Cursor
;
1509 UndoBuf
[UndoSize
] = '\0';
1510 c_delafter(1); /* Do NOT use the saving ONE */
1515 #if defined(DSPMBYTE)
1516 /* 1st. byte is store to special buffer, and replace space */
1517 if(_enable_mbdisp
&& extins
== 0 && Ismbyte1(c
)) {
1520 *Cursor
++ = (Char
) ' ';
1522 else if (_enable_mbdisp
&& extins
&& Ismbyte2(c
)) {
1523 *(Cursor
-1) = savec
;
1524 *Cursor
++ = (Char
) c
;
1531 *Cursor
++ = (Char
) c
;
1532 DoingArg
= 0; /* just in case */
1533 if (ret
!= CC_REFRESH
)
1534 RefPlusOne(); /* fast refresh for one char. */
1536 *Cursor
++ = (Char
) c
;
1537 DoingArg
= 0; /* just in case */
1538 RefPlusOne(); /* fast refresh for one char. */
1542 #if defined(DSPMBYTE)
1543 /* Cannot use ESC-(number) for multi-byte */
1544 if (_enable_mbdisp
&& extins
== 0 && Ismbyte1(c
)) {
1549 else if (_enable_mbdisp
&& extins
&& exterr
&& Ismbyte2(c
))
1556 if (inputmode
!= MODE_INSERT
) {
1558 for(i
=0;i
<Argument
;i
++)
1559 UndoBuf
[UndoSize
++] = *(Cursor
+i
);
1561 UndoBuf
[UndoSize
] = '\0';
1562 c_delafter(Argument
); /* Do NOT use the saving ONE */
1568 *Cursor
++ = (Char
) c
;
1572 if (inputmode
== MODE_REPLACE_1
)
1573 (void) v_cmd_mode(0);
1575 #if defined(DSPMBYTE)
1583 InsertStr(s
) /* insert ASCIZ s at cursor (for complete) */
1588 if ((len
= (int) Strlen(s
)) <= 0)
1590 if (LastChar
+ len
>= InputLim
)
1591 return -1; /* end of buffer space */
1600 DeleteBack(n
) /* delete the n characters before . */
1605 if (Cursor
>= &InputBuf
[n
]) {
1606 c_delbefore(n
); /* delete before dot */
1607 if (n
> Cursor
- InputBuf
)
1608 Cursor
= InputBuf
; /* bounds check */
1611 #if defined(DSPMBYTE)
1612 if(_enable_mbdisp
&& extdel
&& Cursor
> InputBuf
) {
1621 e_digit(c
) /* gray magic here */
1625 return(CC_ERROR
); /* no NULs in the input ever!! */
1627 if (DoingArg
) { /* if doing an arg, add this in... */
1628 if (LastCmd
== F_ARGFOUR
) /* if last command was ^U */
1631 if (Argument
> 1000000)
1633 Argument
= (Argument
* 10) + (c
- '0');
1638 if (LastChar
+ 1 >= InputLim
)
1639 return CC_ERROR
; /* end of buffer space */
1641 if (inputmode
!= MODE_INSERT
) {
1642 UndoBuf
[UndoSize
++] = *Cursor
;
1643 UndoBuf
[UndoSize
] = '\0';
1644 c_delafter(1); /* Do NOT use the saving ONE */
1647 *Cursor
++ = (Char
) c
;
1648 DoingArg
= 0; /* just in case */
1649 RefPlusOne(); /* fast refresh for one char. */
1655 e_argdigit(c
) /* for ESC-n */
1661 return(CC_ERROR
); /* no NULs in the input ever!! */
1663 if (DoingArg
) { /* if doing an arg, add this in... */
1664 if (Argument
> 1000000)
1666 Argument
= (Argument
* 10) + (c
- '0');
1668 else { /* else starting an argument */
1676 v_zero(c
) /* command mode 0 for vi */
1679 if (DoingArg
) { /* if doing an arg, add this in... */
1680 if (Argument
> 1000000)
1682 Argument
= (Argument
* 10) + (c
- '0');
1685 else { /* else starting an argument */
1687 if (ActionFlag
& TCSHOP_DELETE
) {
1691 RefCursor(); /* move the cursor */
1700 { /* always ignore argument */
1702 /* PastBottom(); NOW done in ed.inputl.c */
1703 *LastChar
++ = '\n'; /* for the benefit of CSH */
1704 *LastChar
= '\0'; /* just in case */
1706 InsertPos
= InputBuf
; /* Reset editing position */
1714 { /* for when ^D is ONLY send-eof */
1717 *LastChar
= '\0'; /* just in case */
1727 *LastChar
= '\0'; /* just in case */
1728 return(CC_COMPLETE
);
1737 *LastChar
= '\0'; /* just in case */
1738 return(CC_COMPLETE_BACK
);
1747 *LastChar
= '\0'; /* just in case */
1748 return(CC_COMPLETE_FWD
);
1757 *LastChar
= '\0'; /* just in case */
1758 return(CC_COMPLETE_ALL
);
1767 if (Cursor
< LastChar
)
1769 *LastChar
= '\0'; /* just in case */
1770 return(CC_COMPLETE
);
1782 *LastChar
= '\0'; /* just in case */
1784 if (Hist_num
<= 0) {
1788 hp
= Histlist
.Hnext
;
1789 if (hp
== NULL
) { /* this is only if no history */
1793 for (h
= 1; h
< Hist_num
; h
++)
1796 if (!CurrentHistLit
) {
1798 copyn(InputBuf
, hp
->histline
, INBUFSIZE
);
1806 (void) sprlex(InputBuf
, sizeof(InputBuf
) / sizeof(Char
), &hp
->Hlex
);
1810 LastChar
= InputBuf
+ Strlen(InputBuf
);
1811 if (LastChar
> InputBuf
) {
1812 if (LastChar
[-1] == '\n')
1814 if (LastChar
[-1] == ' ')
1816 if (LastChar
< InputBuf
)
1817 LastChar
= InputBuf
;
1838 UndoAction
= TCSHOP_NOP
;
1839 *LastChar
= '\0'; /* just in case */
1841 if (Hist_num
== 0) { /* save the current buffer away */
1842 copyn(HistBuf
, InputBuf
, INBUFSIZE
);
1843 LastHist
= HistBuf
+ (LastChar
- InputBuf
);
1846 Hist_num
+= Argument
;
1848 if (c_get_histline() == CC_ERROR
) {
1850 (void) c_get_histline(); /* Hist_num was fixed by first call */
1857 return(CC_NORM
); /* was CC_UP_HIST */
1866 UndoAction
= TCSHOP_NOP
;
1867 *LastChar
= '\0'; /* just in case */
1869 Hist_num
-= Argument
;
1873 return(CC_ERROR
); /* make it beep */
1876 return(c_get_histline());
1882 * c_hmatch() return True if the pattern matches the prefix
1888 if (Strncmp(patbuf
, str
, (size_t) patlen
) == 0)
1890 return Gmatch(str
, patbuf
);
1894 * c_hsetpat(): Set the history seatch pattern
1899 if (LastCmd
!= F_UP_SEARCH_HIST
&& LastCmd
!= F_DOWN_SEARCH_HIST
) {
1900 patlen
= (int) (Cursor
- InputBuf
);
1901 if (patlen
>= INBUFSIZE
) patlen
= INBUFSIZE
-1;
1903 (void) Strncpy(patbuf
, InputBuf
, (size_t) patlen
);
1904 patbuf
[patlen
] = '\0';
1907 patlen
= (int) Strlen(patbuf
);
1910 xprintf("\nHist_num = %d\n", Hist_num
);
1911 xprintf("patlen = %d\n", patlen
);
1912 xprintf("patbuf = \"%S\"\n", patbuf
);
1913 xprintf("Cursor %d LastChar %d\n", Cursor
- InputBuf
, LastChar
- InputBuf
);
1927 ActionFlag
= TCSHOP_NOP
;
1928 UndoAction
= TCSHOP_NOP
;
1929 *LastChar
= '\0'; /* just in case */
1932 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname
);
1940 copyn(HistBuf
, InputBuf
, INBUFSIZE
);
1941 LastHist
= HistBuf
+ (LastChar
- InputBuf
);
1945 hp
= Histlist
.Hnext
;
1949 c_hsetpat(); /* Set search pattern !! */
1951 for (h
= 1; h
<= Hist_num
; h
++)
1954 while (hp
!= NULL
) {
1955 Char sbuf
[INBUFSIZE
], *hl
;
1956 if (hp
->histline
== NULL
) {
1957 hp
->histline
= Strsave(sprlex(sbuf
, sizeof(sbuf
) / sizeof(Char
),
1960 hl
= HistLit
? hp
->histline
: sprlex(sbuf
, sizeof(sbuf
) / sizeof(Char
),
1963 xprintf("Comparing with \"%S\"\n", hl
);
1965 if ((Strncmp(hl
, InputBuf
, (size_t) (LastChar
- InputBuf
)) ||
1966 hl
[LastChar
-InputBuf
]) && c_hmatch(hl
)) {
1976 xprintf("not found\n");
1983 return(c_get_histline());
1988 e_down_search_hist(c
)
1996 ActionFlag
= TCSHOP_NOP
;
1997 UndoAction
= TCSHOP_NOP
;
1998 *LastChar
= '\0'; /* just in case */
2003 hp
= Histlist
.Hnext
;
2007 c_hsetpat(); /* Set search pattern !! */
2009 for (h
= 1; h
< Hist_num
&& hp
; h
++) {
2010 Char sbuf
[INBUFSIZE
], *hl
;
2011 if (hp
->histline
== NULL
) {
2012 hp
->histline
= Strsave(sprlex(sbuf
, sizeof(sbuf
) / sizeof(Char
),
2015 hl
= HistLit
? hp
->histline
: sprlex(sbuf
, sizeof(sbuf
) / sizeof(Char
),
2018 xprintf("Comparing with \"%S\"\n", hl
);
2020 if ((Strncmp(hl
, InputBuf
, (size_t) (LastChar
- InputBuf
)) ||
2021 hl
[LastChar
-InputBuf
]) && c_hmatch(hl
))
2026 if (!found
) { /* is it the current history number? */
2027 if (!c_hmatch(HistBuf
)) {
2029 xprintf("not found\n");
2037 return(c_get_histline());
2047 *LastChar
= '\0'; /* just in case */
2057 *LastChar
= '\0'; /* just in case */
2067 *LastChar
= '\0'; /* just in case */
2068 return(CC_CORRECT_L
);
2077 extern bool tellwhat
;
2080 if ((pp
= find_stop_ed()) != NULL
) {
2081 /* save our editor state so we can restore it */
2083 copyn(WhichBuf
, InputBuf
, INBUFSIZE
);
2084 LastWhich
= WhichBuf
+ (LastChar
- InputBuf
);
2085 CursWhich
= WhichBuf
+ (Cursor
- InputBuf
);
2086 HistWhich
= Hist_num
;
2087 Hist_num
= 0; /* for the history commands */
2089 /* put the tty in a sane mode */
2091 (void) Cookedmode(); /* make sure the tty is set up correctly */
2096 (void) Rawmode(); /* go on */
2110 *LastChar
= '\0'; /* just in case */
2111 return(CC_LIST_CHOICES
);
2121 *LastChar
= '\0'; /* just in case */
2122 return(CC_LIST_ALL
);
2132 *LastChar
= '\0'; /* just in case */
2133 return(CC_LIST_GLOB
);
2142 *LastChar
= '\0'; /* just in case */
2143 return(CC_EXPAND_GLOB
);
2152 *LastChar
= '\0'; /* just in case */
2153 return(CC_NORMALIZE_PATH
);
2158 e_normalize_command(c
)
2162 *LastChar
= '\0'; /* just in case */
2163 return(CC_NORMALIZE_COMMAND
);
2172 *LastChar
= '\0'; /* just in case */
2173 return(CC_EXPAND_VARS
);
2180 { /* do a fast command line which(1) */
2183 *LastChar
= '\0'; /* just in case */
2191 { /* insert the last element of the prev. cmd */
2194 struct wordent
*wp
, *firstp
;
2196 Char buf
[INBUFSIZE
];
2202 hp
= Histlist
.Hnext
;
2203 if (hp
== NULL
) { /* this is only if no history */
2207 wp
= (hp
->Hlex
).prev
;
2209 if (wp
->prev
== (struct wordent
*) NULL
)
2210 return(CC_ERROR
); /* an empty history entry */
2212 firstp
= (hp
->Hlex
).next
;
2214 /* back up arg words in lex */
2215 for (i
= 0; i
< Argument
&& wp
!= firstp
; i
++) {
2219 cp
= expand_lex(buf
, INBUFSIZE
, wp
->prev
, 0, i
- 1);
2231 { /* expand to preceding word matching prefix */
2232 Char
*cp
, *ncp
, *bp
;
2234 int arg
= 0, len
= 0, i
; /* len = 0 to shut up gcc -Wall */
2236 Char hbuf
[INBUFSIZE
];
2237 static int oldevent
, hist
, word
;
2238 static Char
*start
, *oldcursor
;
2244 cp
= c_preword(Cursor
, InputBuf
, 1, STRshwordsep
);
2245 if (cp
== Cursor
|| Isspace(*cp
))
2248 hp
= Histlist
.Hnext
;
2250 if (Argument
== 1 && eventno
== oldevent
&& cp
== start
&&
2251 Cursor
== oldcursor
&& patlen
> 0 && Strncmp(patbuf
, cp
, patlen
) == 0){
2252 /* continue previous search - go to last match (hist/word) */
2253 if (hist
!= 0) { /* need to move up history */
2254 for (i
= 1; i
< hist
&& hp
!= NULL
; i
++)
2256 if (hp
== NULL
) /* "can't happen" */
2258 cp
= expand_lex(hbuf
, INBUFSIZE
, &hp
->Hlex
, 0, NCARGS
);
2263 cp
= c_preword(cp
, bp
, word
, STRshwordsep
);
2264 } else { /* starting new search */
2267 patlen
= (int) (Cursor
- cp
);
2268 (void) Strncpy(patbuf
, cp
, patlen
);
2274 ncp
= c_preword(cp
, bp
, 1, STRshwordsep
);
2275 if (ncp
== cp
|| Isspace(*ncp
)) { /* beginning of line */
2280 cp
= expand_lex(hbuf
, INBUFSIZE
, &hp
->Hlex
, 0, NCARGS
);
2287 len
= (int) (c_endword(ncp
-1, cp
, 1, STRshwordsep
) - ncp
+ 1);
2290 if (len
> patlen
&& Strncmp(cp
, patbuf
, patlen
) == 0) {
2291 /* We don't fully check distinct matches as Gnuemacs does: */
2292 if (Argument
> 1) { /* just count matches */
2293 if (++arg
>= Argument
)
2295 } else { /* match if distinct from previous */
2296 if (len
!= Cursor
- start
|| Strncmp(cp
, start
, len
) != 0)
2302 if (LastChar
+ len
- (Cursor
- start
) >= InputLim
)
2303 return(CC_ERROR
); /* no room */
2304 DeleteBack(Cursor
- start
);
2316 { /* almost like GnuEmacs */
2321 if (KillRingLen
== 0) /* nothing killed */
2323 len
= Strlen(KillRing
[YankPos
].buf
);
2324 if (LastChar
+ len
>= InputLim
)
2325 return(CC_ERROR
); /* end of buffer space */
2328 cp
= Cursor
; /* for speed */
2330 c_insert(len
); /* open the space, */
2331 for (kp
= KillRing
[YankPos
].buf
; *kp
; kp
++) /* copy the chars */
2334 if (Argument
== 1) { /* if no arg */
2335 Mark
= Cursor
; /* mark at beginning, cursor at end */
2338 Mark
= cp
; /* else cursor at beginning, mark at end */
2348 { /* almost like GnuEmacs */
2349 int m_bef_c
, del_len
, ins_len
;
2355 /* XXX This "should" be here, but doesn't work, since LastCmd
2356 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?).
2357 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the
2358 second one will "succeed" even if the first one wasn't preceded
2359 by a yank, and giving an argument is impossible. Now we "succeed"
2360 regardless of previous command, which is wrong too of course. */
2361 if (LastCmd
!= F_YANK_KILL
&& LastCmd
!= F_YANK_POP
)
2365 if (KillRingLen
== 0) /* nothing killed */
2367 YankPos
-= Argument
;
2369 YankPos
+= KillRingLen
;
2370 YankPos
%= KillRingLen
;
2372 if (Cursor
> Mark
) {
2373 del_len
= Cursor
- Mark
;
2376 del_len
= Mark
- Cursor
;
2379 ins_len
= Strlen(KillRing
[YankPos
].buf
);
2380 if (LastChar
+ ins_len
- del_len
>= InputLim
)
2381 return(CC_ERROR
); /* end of buffer space */
2384 c_delbefore(del_len
);
2387 c_delafter(del_len
);
2389 cp
= Cursor
; /* for speed */
2391 c_insert(ins_len
); /* open the space, */
2392 for (kp
= KillRing
[YankPos
].buf
; *kp
; kp
++) /* copy the chars */
2396 Mark
= Cursor
; /* mark at beginning, cursor at end */
2399 Mark
= cp
; /* else cursor at beginning, mark at end */
2407 v_delprev(c
) /* Backspace key in insert mode */
2415 if (InsertPos
!= 0) {
2416 if (Argument
<= Cursor
- InsertPos
) {
2417 c_delbefore(Argument
); /* delete before */
2419 #if defined(DSPMBYTE)
2420 if (_enable_mbdisp
&& extdel
) {
2437 if (Cursor
> InputBuf
) {
2438 c_delbefore(Argument
); /* delete before dot */
2439 if (Argument
> Cursor
- InputBuf
)
2440 Cursor
= InputBuf
; /* bounds check */
2443 #if defined(DSPMBYTE)
2444 if (_enable_mbdisp
&& extdel
&& Cursor
> InputBuf
) {
2464 if (Cursor
== InputBuf
)
2468 cp
= c_prev_word(Cursor
, InputBuf
, Argument
);
2470 c_push_kill(cp
, Cursor
); /* save the text */
2472 c_delbefore((int)(Cursor
- cp
)); /* delete before dot */
2474 if (Cursor
< InputBuf
)
2475 Cursor
= InputBuf
; /* bounds check */
2479 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93
2481 * Changed the names of some of the ^D family of editor functions to
2482 * correspond to what they actually do and created new e_delnext_list
2485 * Old names: New names:
2487 * delete-char delete-char-or-eof
2488 * F_DELNEXT F_DELNEXT_EOF
2489 * e_delnext e_delnext_eof
2490 * edelnxt edelnxteof
2491 * delete-char-or-eof delete-char
2492 * F_DELNEXT_EOF F_DELNEXT
2493 * e_delnext_eof e_delnext
2494 * edelnxteof edelnxt
2495 * delete-char-or-list delete-char-or-list-or-eof
2496 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF
2497 * e_list_delnext e_delnext_list_eof
2499 * (no old equivalent) delete-char-or-list
2505 /* added by mtk@ari.ncl.omron.co.jp (920818) */
2506 /* rename e_delnext() -> e_delnext_eof() */
2513 if (Cursor
== LastChar
) {/* if I'm at the end */
2518 if (Cursor
!= InputBuf
)
2524 c_delafter(Argument
); /* delete after dot */
2525 if (Cursor
> LastChar
)
2526 Cursor
= LastChar
; /* bounds check */
2537 if (Cursor
== LastChar
) {/* if I'm at the end */
2539 if (Cursor
== InputBuf
) {
2540 /* if I'm also at the beginning */
2541 so_write(STReof
, 4);/* then do a EOF */
2549 if (Cursor
!= InputBuf
)
2555 c_delafter(Argument
); /* delete after dot */
2556 if (Cursor
> LastChar
)
2557 Cursor
= LastChar
; /* bounds check */
2567 if (Cursor
== LastChar
) { /* if I'm at the end */
2569 *LastChar
= '\0'; /* just in case */
2570 return(CC_LIST_CHOICES
);
2573 c_delafter(Argument
); /* delete after dot */
2574 if (Cursor
> LastChar
)
2575 Cursor
= LastChar
; /* bounds check */
2582 e_delnext_list_eof(c
)
2586 if (Cursor
== LastChar
) { /* if I'm at the end */
2587 if (Cursor
== InputBuf
) { /* if I'm also at the beginning */
2588 so_write(STReof
, 4);/* then do a EOF */
2594 *LastChar
= '\0'; /* just in case */
2595 return(CC_LIST_CHOICES
);
2599 c_delafter(Argument
); /* delete after dot */
2600 if (Cursor
> LastChar
)
2601 Cursor
= LastChar
; /* bounds check */
2614 if (Cursor
== LastChar
&& Cursor
== InputBuf
) {
2615 so_write(STReof
, 4); /* then do a EOF */
2621 *LastChar
= '\0'; /* just in case */
2622 rv
= CC_LIST_CHOICES
;
2635 if (Cursor
== LastChar
)
2639 cp
= c_next_word(Cursor
, LastChar
, Argument
);
2641 c_push_kill(Cursor
, cp
); /* save the text */
2643 c_delafter((int)(cp
- Cursor
)); /* delete after dot */
2644 if (Cursor
> LastChar
)
2645 Cursor
= LastChar
; /* bounds check */
2657 if (ActionFlag
& TCSHOP_DELETE
) {
2661 RefCursor(); /* move the cursor */
2674 while (Isspace(*Cursor
)) /* We want FIRST non space character */
2676 if (ActionFlag
& TCSHOP_DELETE
) {
2682 RefCursor(); /* move the cursor */
2692 c_push_kill(Cursor
, LastChar
); /* copy it */
2693 LastChar
= Cursor
; /* zap! -- delete to end */
2704 c_push_kill(InputBuf
, Cursor
); /* copy it */
2705 c_delbefore((int)(Cursor
- InputBuf
));
2706 Cursor
= InputBuf
; /* zap! */
2716 c_push_kill(InputBuf
, LastChar
); /* copy it */
2717 LastChar
= InputBuf
; /* zap! -- delete all of it */
2731 if (Mark
> Cursor
) {
2732 c_push_kill(Cursor
, Mark
); /* copy it */
2733 c_delafter((int)(Mark
- Cursor
)); /* delete it - UNUSED BY VI mode */
2736 else { /* mark is before cursor */
2737 c_push_kill(Mark
, Cursor
); /* copy it */
2738 c_delbefore((int)(Cursor
- Mark
));
2753 if (Mark
> Cursor
) {
2754 c_push_kill(Cursor
, Mark
); /* copy it */
2756 else { /* mark is before cursor */
2757 c_push_kill(Mark
, Cursor
); /* copy it */
2759 return(CC_NORM
); /* don't even need to Refresh() */
2771 /* do nothing if we are at beginning of line or have only one char */
2772 if (Cursor
== &InputBuf
[0] || LastChar
== &InputBuf
[1]) {
2776 if (Cursor
< LastChar
) {
2780 Cursor
[-2] = Cursor
[-1];
2789 { /* gosmacs style ^T */
2793 if (Cursor
> &InputBuf
[1]) {/* must have at least two chars entered */
2795 Cursor
[-2] = Cursor
[-1];
2804 #if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */
2807 e_charback_mbyte(argument
)
2810 if (!_enable_mbdisp
) {
2811 if (Argument
> Cursor
- InputBuf
)
2817 while (0 < argument
&& Cursor
> InputBuf
) {
2818 if (Cursor
- 1 != InputBuf
&&
2819 Ismbyte1(*(Cursor
- 2)) && Ismbyte2(*(Cursor
- 1))) {
2835 if (Cursor
> InputBuf
) {
2836 #if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */
2837 e_charback_mbyte(Argument
);
2839 if (Argument
> Cursor
- InputBuf
)
2846 if (ActionFlag
& TCSHOP_DELETE
) {
2865 if (Cursor
== InputBuf
)
2869 Cursor
= c_preword(Cursor
, InputBuf
, Argument
, STRshwspace
); /* bounds check */
2871 if (ActionFlag
& TCSHOP_DELETE
) {
2886 if (Cursor
== InputBuf
)
2890 Cursor
= c_prev_word(Cursor
, InputBuf
, Argument
); /* bounds check */
2893 if (ActionFlag
& TCSHOP_DELETE
) {
2902 #if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */
2905 e_charfwd_mbyte(argument
)
2908 if (!_enable_mbdisp
)
2911 while (0 < argument
&& Cursor
< LastChar
) {
2912 if (Cursor
+ 1 != LastChar
&&
2913 Ismbyte1(*Cursor
) && Ismbyte2(*(Cursor
+ 1))) {
2928 if (Cursor
< LastChar
) {
2929 #if defined(DSPMBYTE) /* BY TAGA Nayuta VERY THANKS */
2930 e_charfwd_mbyte(Argument
);
2934 if (Cursor
> LastChar
)
2938 if (ActionFlag
& TCSHOP_DELETE
) {
2957 if (Cursor
== LastChar
)
2961 Cursor
= c_next_word(Cursor
, LastChar
, Argument
);
2964 if (ActionFlag
& TCSHOP_DELETE
) {
2979 if (Cursor
== LastChar
)
2983 Cursor
= c_nexword(Cursor
, LastChar
, Argument
);
2986 if (ActionFlag
& TCSHOP_DELETE
) {
3001 if (Cursor
== LastChar
)
3005 Cursor
= c_next_word(Cursor
, LastChar
, Argument
);
3006 if (Cursor
< LastChar
)
3010 if (ActionFlag
& TCSHOP_DELETE
) {
3024 CCRETVAL rv
= CC_ERROR
;
3026 xprintf("dir %d patlen %d patbuf %S\n",
3030 LastCmd
= (KEYCMD
) c
; /* Hack to stop c_hsetpat */
3031 LastChar
= InputBuf
;
3033 case F_DOWN_SEARCH_HIST
:
3034 rv
= e_down_search_hist(0);
3036 case F_UP_SEARCH_HIST
:
3037 rv
= e_up_search_hist(0);
3046 v_csearch_back(ch
, count
, tflag
)
3047 int ch
, count
, tflag
;
3055 while (cp
> InputBuf
&& *cp
!= ch
)
3059 if (cp
< InputBuf
|| (cp
== InputBuf
&& *cp
!= ch
))
3062 if (*cp
== ch
&& tflag
)
3067 if (ActionFlag
& TCSHOP_DELETE
) {
3078 v_csearch_fwd(ch
, count
, tflag
)
3079 int ch
, count
, tflag
;
3087 while (cp
< LastChar
&& *cp
!= ch
)
3094 if (*cp
== ch
&& tflag
)
3099 if (ActionFlag
& TCSHOP_DELETE
) {
3115 if (ActionFlag
== TCSHOP_DELETE
) {
3116 ActionFlag
= TCSHOP_NOP
;
3121 for (cp
= InputBuf
; cp
< LastChar
; cp
++) {
3126 UndoAction
= TCSHOP_INSERT
;
3128 LastChar
= InputBuf
;
3130 if (c
& TCSHOP_INSERT
)
3131 c_alternativ_key_map(0);
3136 else if (ActionFlag
== TCSHOP_NOP
) {
3140 return(CC_ARGHACK
); /* Do NOT clear out argument */
3152 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */
3154 c_get_word(begin
, end
)
3161 while (Argument
--) {
3162 while ((cp
<= LastChar
) && (isword(*cp
)))
3165 while ((cp
>= InputBuf
) && (isword(*cp
)))
3170 #endif /* COMMENT */
3180 end
= c_next_word(Cursor
, LastChar
, Argument
);
3182 for (cp
= Cursor
; cp
< end
; cp
++) /* PWP: was cp=begin */
3187 if (Cursor
> LastChar
)
3201 end
= c_next_word(Cursor
, LastChar
, Argument
);
3204 for (; cp
< end
; cp
++) {
3212 for (; cp
< end
; cp
++)
3217 if (Cursor
> LastChar
)
3230 end
= c_next_word(Cursor
, LastChar
, Argument
);
3232 for (cp
= Cursor
; cp
< end
; cp
++)
3237 if (Cursor
> LastChar
)
3272 { /* multiply current argument by 4 */
3274 if (Argument
> 1000000)
3291 num
= GetNextChar(&ch
);
3294 return e_insert(ch
);
3296 return e_send_eof(0);
3306 return(CC_ARGHACK
); /* preserve argument */
3315 CurrentKeyMap
= CcAltMap
;
3316 return(CC_ARGHACK
); /* preserve argument */
3325 { /* move to beginning of line and start vi
3332 UndoAction
= TCSHOP_DELETE
;
3334 RefCursor(); /* move the cursor */
3335 c_alternativ_key_map(0);
3343 { /* vi mode overwrite one character */
3345 c_alternativ_key_map(0);
3346 inputmode
= MODE_REPLACE_1
;
3347 UndoAction
= TCSHOP_CHANGE
; /* Set Up for VI undo command */
3357 { /* vi mode start overwriting */
3359 c_alternativ_key_map(0);
3360 inputmode
= MODE_REPLACE
;
3361 UndoAction
= TCSHOP_CHANGE
; /* Set Up for VI undo command */
3371 { /* vi mode substitute for one char */
3373 c_delafter(Argument
);
3374 c_alternativ_key_map(0);
3382 { /* vi mode replace whole line */
3384 (void) e_killall(0);
3385 c_alternativ_key_map(0);
3393 { /* vi mode change to end of line */
3395 (void) e_killend(0);
3396 c_alternativ_key_map(0);
3404 { /* vi mode start inserting */
3406 c_alternativ_key_map(0);
3410 UndoAction
= TCSHOP_DELETE
;
3419 { /* vi mode start adding */
3421 c_alternativ_key_map(0);
3422 if (Cursor
< LastChar
)
3425 if (Cursor
> LastChar
)
3432 UndoAction
= TCSHOP_DELETE
;
3441 { /* vi mode to add at end of line */
3443 c_alternativ_key_map(0);
3446 InsertPos
= LastChar
; /* Mark where insertion begins */
3448 UndoAction
= TCSHOP_DELETE
;
3462 if (Cursor
< LastChar
) {
3463 #ifndef WINNT_NATIVE
3467 #endif /* WINNT_NATIVE */
3469 *Cursor
++ = Tolower(c
);
3470 else if (Islower(c
))
3471 *Cursor
++ = Toupper(c
);
3474 RefPlusOne(); /* fast refresh for one char */
3489 for (p
= InputBuf
; Isspace(*p
); p
++)
3496 return(e_newline(0));
3503 { /* erase all of current line, start again */
3505 ResetInLine(0); /* reset the input pointers */
3526 ClearScreen(); /* clear the whole real screen */
3527 ClearDisp(); /* reset everything */
3537 #if defined(_MINIX) || defined(WINNT_NATIVE)
3538 /* SAK PATCH: erase all of current line, start again */
3539 ResetInLine(0); /* reset the input pointers */
3542 return (CC_REFRESH
);
3543 #else /* !_MINIX && !WINNT_NATIVE */
3546 #endif /* _MINIX || WINNT_NATIVE */
3550 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi)
3551 * Function to send a character back to the input stream in cooked
3552 * mode. Only works if we have TIOCSTI
3560 extern int Tty_raw_mode
;
3561 int was_raw
= Tty_raw_mode
;
3565 (void) Cookedmode();
3567 (void) write(SHIN
, "\n", 1);
3568 (void) ioctl(SHIN
, TIOCSTI
, (ioctl_t
) &ch
);
3572 return(e_redisp(c
));
3573 #else /* !TIOCSTI */
3575 #endif /* !TIOCSTI */
3584 inputmode
= (inputmode
== MODE_INSERT
? MODE_REPLACE
: MODE_INSERT
);
3644 *LastChar
= '\0'; /* just in case */
3655 *LastChar
= '\0'; /* just in case */
3657 return(e_insert(' '));
3667 return e_inc_search(F_DOWN_SEARCH_HIST
);
3678 return e_inc_search(F_UP_SEARCH_HIST
);
3686 Char
*cp
, *oldc
, *dp
;
3689 if (Cursor
== InputBuf
)
3694 /* does a bounds check */
3695 cp
= c_prev_word(Cursor
, InputBuf
, Argument
);
3697 c_insert((int)(oldc
- cp
));
3698 for (dp
= oldc
; cp
< oldc
&& dp
< LastChar
; cp
++)
3701 Cursor
= dp
; /* put cursor at end */
3725 * Here we pass &c to the ioctl because some os's (NetBSD) expect it
3726 * there even if they don't use it. (lukem@netbsd.org)
3728 if (ioctl(SHIN
, TIOCSTAT
, (ioctl_t
) &c
) < 0)
3730 xprintf(CGETS(5, 1, "Load average unavailable\n"));
3741 * Delete with insert == change: first we delete and then we leave in
3744 return(v_action(TCSHOP_DELETE
|TCSHOP_INSERT
));
3753 return(v_action(TCSHOP_DELETE
));
3763 if (Cursor
== LastChar
)
3767 Cursor
= c_endword(Cursor
, LastChar
, Argument
, STRshwspace
);
3769 if (ActionFlag
& TCSHOP_DELETE
)
3786 if (Cursor
== LastChar
)
3790 Cursor
= c_eword(Cursor
, LastChar
, Argument
);
3792 if (ActionFlag
& TCSHOP_DELETE
) {
3810 if (GetNextChar(&ch
) != 1)
3811 return e_send_eof(0);
3813 srch_dir
= CHAR_FWD
;
3816 return v_csearch_fwd(ch
, Argument
, 0);
3828 if (GetNextChar(&ch
) != 1)
3829 return e_send_eof(0);
3831 srch_dir
= CHAR_BACK
;
3834 return v_csearch_back(ch
, Argument
, 0);
3845 if (GetNextChar(&ch
) != 1)
3846 return e_send_eof(0);
3848 return v_csearch_fwd(ch
, Argument
, 1);
3860 if (GetNextChar(&ch
) != 1)
3861 return e_send_eof(0);
3863 return v_csearch_back(ch
, Argument
, 1);
3875 return srch_dir
== CHAR_FWD
? v_csearch_fwd(srch_char
, Argument
, 0) :
3876 v_csearch_back(srch_char
, Argument
, 0);
3888 return srch_dir
== CHAR_BACK
? v_csearch_fwd(srch_char
, Argument
, 0) :
3889 v_csearch_back(srch_char
, Argument
, 0);
3903 switch (UndoAction
) {
3904 case TCSHOP_DELETE
|TCSHOP_INSERT
:
3906 if (UndoSize
== 0) return(CC_NORM
);
3909 for (loop
=0; loop
< UndoSize
; loop
++) /* copy the chars */
3910 *kp
++ = *cp
++; /* into UndoBuf */
3912 for (cp
= UndoPtr
; cp
<= LastChar
; cp
++)
3915 LastChar
-= UndoSize
;
3918 UndoAction
= TCSHOP_INSERT
;
3922 if (UndoSize
== 0) return(CC_NORM
);
3926 c_insert(UndoSize
); /* open the space, */
3927 for (loop
= 0; loop
< UndoSize
; loop
++) /* copy the chars */
3930 UndoAction
= TCSHOP_DELETE
;
3934 if (UndoSize
== 0) return(CC_NORM
);
3938 size
= (int)(Cursor
-LastChar
); /* NOT NSL independant */
3939 if (size
< UndoSize
)
3941 for(loop
= 0; loop
< size
; loop
++) {
3961 return v_search(F_UP_SEARCH_HIST
);
3970 return v_search(F_DOWN_SEARCH_HIST
);
3979 if (patlen
== 0) return(CC_ERROR
);
3980 return(v_repeat_srch(searchdir
));
3989 if (patlen
== 0) return(CC_ERROR
);
3990 return(v_repeat_srch(searchdir
== F_UP_SEARCH_HIST
?
3991 F_DOWN_SEARCH_HIST
: F_UP_SEARCH_HIST
));
3994 #ifndef WINNT_NATIVE
3995 /* Since ed.defns.h is generated from ed.defns.c, these empty
3996 functions will keep the F_NUM_FNS consistent
3999 e_copy_to_clipboard(c
)
4007 e_paste_from_clipboard(c
)
4042 #endif /* !WINNT_NATIVE */
4046 MoveCursor(n
) /* move cursor + right - left char */
4049 Cursor
= Cursor
+ n
;
4050 if (Cursor
< InputBuf
)
4052 if (Cursor
> LastChar
)
4067 if (p
< InputBuf
|| p
> LastChar
)
4068 return 1; /* Error */