1 /* $NetBSD: edit.c,v 1.22 2009/04/25 05:11:37 lukem Exp $ */
4 * Command line editing - common code
10 __RCSID("$NetBSD: edit.c,v 1.22 2009/04/25 05:11:37 lukem Exp $");
22 #ifdef OS_SCO /* SCO Unix 3.2v4.1 */
23 # include <sys/stream.h> /* needed for <sys/ptem.h> */
24 # include <sys/ptem.h> /* needed for struct winsize */
26 #include <sys/ioctl.h>
31 #if defined(TIOCGWINSZ)
32 static RETSIGTYPE x_sigwinch
ARGS((int sig
));
33 static int got_sigwinch
;
34 static void check_sigwinch
ARGS((void));
35 #endif /* TIOCGWINSZ */
37 static int x_file_glob
ARGS((int flags
, const char *str
, int slen
,
39 static int x_command_glob
ARGS((int flags
, const char *str
, int slen
,
41 static int x_locate_word
ARGS((const char *buf
, int buflen
, int pos
,
42 int *startp
, int *is_command
));
44 static char vdisable_c
;
47 /* Called from main */
51 /* set to -2 to force initial binding */
52 edchars
.erase
= edchars
.kill
= edchars
.intr
= edchars
.quit
54 /* default value for deficient systems */
55 edchars
.werase
= 027; /* ^W */
59 if (setsig(&sigtraps
[SIGWINCH
], x_sigwinch
, SS_RESTORE_ORIG
|SS_SHTRAP
))
60 sigtraps
[SIGWINCH
].flags
|= TF_SHELL_USES
;
61 # endif /* SIGWINCH */
62 got_sigwinch
= 1; /* force initial check */
64 #endif /* TIOCGWINSZ */
70 /* Bizarreness to figure out how to disable
71 * a struct termios.c_cc[] char
73 #ifdef _POSIX_VDISABLE
74 if (_POSIX_VDISABLE
>= 0)
75 vdisable_c
= (char) _POSIX_VDISABLE
;
77 /* `feature not available' */
78 vdisable_c
= (char) 0377;
80 # if defined(HAVE_PATHCONF) && defined(_PC_VDISABLE)
81 vdisable_c
= fpathconf(tty_fd
, _PC_VDISABLE
);
83 vdisable_c
= (char) 0377; /* default to old BSD value */
85 #endif /* _POSIX_VDISABLE */
88 #if defined(TIOCGWINSZ)
98 check_sigwinch
ARGS((void))
104 if (procpid
== kshpid
&& ioctl(tty_fd
, TIOCGWINSZ
, &ws
) >= 0) {
107 /* Do NOT export COLUMNS/LINES. Many applications
108 * check COLUMNS/LINES before checking ws.ws_col/row,
109 * so if the app is started with C/L in the environ
110 * and the window is then resized, the app won't
111 * see the change cause the environ doesn't change.
114 x_cols
= ws
.ws_col
< MIN_COLS
? MIN_COLS
117 if ((vp
= typeset("COLUMNS", 0, 0, 0, 0)))
118 setint(vp
, (long) ws
.ws_col
);
121 && (vp
= typeset("LINES", 0, 0, 0, 0)))
122 setint(vp
, (long) ws
.ws_row
);
126 #endif /* TIOCGWINSZ */
129 * read an edited command line
140 if (Flag(FEMACS
) || Flag(FGMACS
))
141 i
= x_emacs(buf
, len
);
149 i
= -1; /* internal error */
151 #if defined(TIOCGWINSZ)
154 #endif /* TIOCGWINSZ */
165 unsigned char c
= _read_kbd(0, 1, 0);
166 return c
== 0 ? 0xE0 : c
;
171 while ((n
= blocking_read(0, &c
, 1)) < 0 && errno
== EINTR
)
179 return (int) (unsigned char) c
;
193 shf_putc(c
, shl_out
);
201 shf_putc(*s
++, shl_out
);
208 static bool_t x_cur_mode
;
211 if (x_cur_mode
== onoff
)
223 #if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H)
224 edchars
.erase
= cb
.c_cc
[VERASE
];
225 edchars
.kill
= cb
.c_cc
[VKILL
];
226 edchars
.intr
= cb
.c_cc
[VINTR
];
227 edchars
.quit
= cb
.c_cc
[VQUIT
];
228 edchars
.eof
= cb
.c_cc
[VEOF
];
230 edchars
.werase
= cb
.c_cc
[VWERASE
];
232 # ifdef _CRAY2 /* brain-damaged terminal handler */
233 cb
.c_lflag
&= ~(ICANON
|ECHO
);
234 /* rely on print routine to map '\n' to CR,LF */
236 cb
.c_iflag
&= ~(INLCR
|ICRNL
);
237 # ifdef _BSD_SYSV /* need to force CBREAK instead of RAW (need CRMOD on output) */
238 cb
.c_lflag
&= ~(ICANON
|ECHO
);
240 # ifdef SWTCH /* need CBREAK to handle swtch char */
241 cb
.c_lflag
&= ~(ICANON
|ECHO
);
243 cb
.c_cc
[VINTR
] = vdisable_c
;
244 cb
.c_cc
[VQUIT
] = vdisable_c
;
246 cb
.c_lflag
&= ~(ISIG
|ICANON
|ECHO
);
250 /* osf/1 processes lnext when ~icanon */
251 cb
.c_cc
[VLNEXT
] = vdisable_c
;
254 /* sunos 4.1.x & osf/1 processes discard(flush) when ~icanon */
255 cb
.c_cc
[VDISCARD
] = vdisable_c
;
256 # endif /* VDISCARD */
261 /* Assume BSD tty stuff. */
262 edchars
.erase
= cb
.sgttyb
.sg_erase
;
263 edchars
.kill
= cb
.sgttyb
.sg_kill
;
264 cb
.sgttyb
.sg_flags
&= ~ECHO
;
265 cb
.sgttyb
.sg_flags
|= CBREAK
;
267 edchars
.intr
= cb
.lchars
.tc_intrc
;
268 edchars
.quit
= cb
.lchars
.tc_quitc
;
269 edchars
.eof
= cb
.lchars
.tc_eofc
;
270 edchars
.werase
= cb
.lchars
.tc_werasc
;
271 cb
.lchars
.tc_suspc
= -1;
272 cb
.lchars
.tc_dsuspc
= -1;
273 cb
.lchars
.tc_lnextc
= -1;
274 cb
.lchars
.tc_statc
= -1;
275 cb
.lchars
.tc_intrc
= -1;
276 cb
.lchars
.tc_quitc
= -1;
277 cb
.lchars
.tc_rprntc
= -1;
279 edchars
.intr
= cb
.tchars
.t_intrc
;
280 edchars
.quit
= cb
.tchars
.t_quitc
;
281 edchars
.eof
= cb
.tchars
.t_eofc
;
282 cb
.tchars
.t_intrc
= -1;
283 cb
.tchars
.t_quitc
= -1;
285 edchars
.werase
= cb
.ltchars
.t_werasc
;
286 cb
.ltchars
.t_suspc
= -1;
287 cb
.ltchars
.t_dsuspc
= -1;
288 cb
.ltchars
.t_lnextc
= -1;
289 cb
.ltchars
.t_rprntc
= -1;
291 # endif /* TIOCGATC */
292 #endif /* HAVE_TERMIOS_H || HAVE_TERMIO_H */
294 set_tty(tty_fd
, &cb
, TF_WAIT
);
297 if (edchars
.eof
== '\0')
299 #endif /* __CYGWIN__ */
301 /* Convert unset values to internal `unset' value */
302 if (edchars
.erase
== vdisable_c
)
304 if (edchars
.kill
== vdisable_c
)
306 if (edchars
.intr
== vdisable_c
)
308 if (edchars
.quit
== vdisable_c
)
310 if (edchars
.eof
== vdisable_c
)
312 if (edchars
.werase
== vdisable_c
)
314 if (memcmp(&edchars
, &oldchars
, sizeof(edchars
)) != 0) {
316 x_emacs_keys(&edchars
);
320 /* TF_WAIT doesn't seem to be necessary when leaving xmode */
321 set_tty(tty_fd
, &tty_state
, TF_NONE
);
328 * promptlen - calculate the length of PS1 etc.
331 * This function is based on a fix from guy@demon.co.uk
332 * It fixes a bug in that if PS1 contains '!', the length
333 * given by strlen() is probably wrong.
348 /* Undocumented AT&T ksh feature:
349 * If the second char in the prompt string is \r then the first char
350 * is taken to be a non-printing delimiter and any chars between two
351 * instances of the delimiter are not considered to be part of the
354 if (*cp
&& cp
[1] == '\r') {
360 if (indelimit
&& *cp
!= delimiter
)
362 else if (*cp
== '\n' || *cp
== '\r') {
365 } else if (*cp
== '\t') {
366 count
= (count
| 7) + 1;
367 } else if (*cp
== '\b') {
370 } else if (*cp
== delimiter
)
371 indelimit
= !indelimit
;
384 static const enum sh_flag edit_flags
[] = {
395 if ((rcp
= ksh_strrchr_dirsep(ed
)))
397 for (i
= 0; i
< NELEM(edit_flags
); i
++)
398 if (strstr(ed
, goptions
[(int) edit_flags
[i
]].name
)) {
399 change_flag(edit_flags
[i
], OF_SPECIAL
, 1);
404 /* ------------------------------------------------------------------------- */
405 /* Misc common code for vi/emacs */
407 /* Handle the commenting/uncommenting of a line.
409 * 1 if a carriage return is indicated (comment added)
410 * 0 if no return (comment removed)
411 * -1 if there is an error (not enough room for comment chars)
412 * If successful, *lenp contains the new length. Note: cursor should be
413 * moved to the start of the line after (un)commenting.
416 x_do_comment(buf
, bsize
, lenp
)
425 return 1; /* somewhat arbitrary - it's what at&t ksh does */
427 /* Already commented? */
431 for (j
= 0, i
= 1; i
< len
; i
++) {
432 if (!saw_nl
|| buf
[i
] != '#')
434 saw_nl
= buf
[i
] == '\n';
441 /* See if there's room for the #'s - 1 per \n */
442 for (i
= 0; i
< len
; i
++)
445 if (len
+ n
>= bsize
)
447 /* Now add them... */
448 for (i
= len
, j
= len
+ n
; --i
>= 0; ) {
459 /* ------------------------------------------------------------------------- */
460 /* Common file/command completion code for vi/emacs */
463 static char *add_glob
ARGS((const char *, int));
464 static void glob_table
ARGS((const char *, XPtrV
*, struct table
*));
465 static void glob_path
ARGS((int, const char *, XPtrV
*, const char *));
467 #if 0 /* not used... */
468 int x_complete_word
ARGS((const char *, int, int, int *, char **));
470 x_complete_word(str
, slen
, is_command
, nwordsp
, ret
)
481 nwords
= (is_command
? x_command_glob
: x_file_glob
)(XCF_FULLPATH
,
489 prefix_len
= x_longest_prefix(nwords
, words
);
490 *ret
= str_nsave(words
[0], prefix_len
, ATEMP
);
491 x_free_words(nwords
, words
);
497 x_print_expansions(nwords
, words
, is_command
)
508 /* Check if all matches are in the same directory (in this
509 * case, we want to omit the directory name)
512 && (prefix_len
= x_longest_prefix(nwords
, words
)) > 0)
516 /* Special case for 1 match (prefix is whole word) */
518 prefix_len
= x_basename(words
[0], (char *) 0);
519 /* Any (non-trailing) slashes in non-common word suffixes? */
520 for (i
= 0; i
< nwords
; i
++)
521 if (x_basename(words
[i
] + prefix_len
, (char *) 0)
524 /* All in same directory? */
526 while (prefix_len
> 0
527 && !ISDIRSEP(words
[0][prefix_len
- 1]))
530 XPinit(l
, nwords
+ 1);
531 for (i
= 0; i
< nwords
; i
++)
532 XPput(l
, words
[i
] + prefix_len
);
533 XPput(l
, (char *) 0);
538 * Enumerate expansions
542 pr_list(use_copy
? (char **) XPptrv(l
) : words
);
545 XPfree(l
); /* not x_free_words() */
550 * - appends * to (copy of) str if no globbing chars found
551 * - does expansion, checks for no match, etc.
552 * - sets *wordsp to array of matching strings
553 * - returns number of matching strings
556 x_file_glob(flags
, str
, slen
, wordsp
)
564 int nwords
, i
, idx
, escaping
;
566 struct source
*s
, *sold
;
571 toglob
= add_glob(str
, slen
);
573 /* remove all escaping backward slashes */
575 for(i
= 0, idx
= 0; toglob
[i
]; i
++) {
576 if (toglob
[i
] == '\\' && !escaping
) {
581 toglob
[idx
] = toglob
[i
];
583 if (escaping
) escaping
= 0;
588 * Convert "foo*" (toglob) to an array of strings (words)
591 s
= pushs(SWSTR
, ATEMP
);
592 s
->start
= s
->str
= toglob
;
594 if (yylex(ONEWORD
) != LWORD
) {
596 internal_errorf(0, "fileglob: substitute error");
601 expand(yylval
.cp
, &w
, DOGLOB
|DOTILDE
|DOMARKDIRS
);
603 words
= (char **) XPclose(w
);
605 for (nwords
= 0; words
[nwords
]; nwords
++)
610 /* Check if globbing failed (returned glob pattern),
611 * but be careful (E.g. toglob == "ab*" when the file
612 * "ab*" exists is not an error).
613 * Also, check for empty result - happens if we tried
614 * to glob something which evaluated to an empty
615 * string (e.g., "$FOO" when there is no FOO, etc).
617 if ((strcmp(words
[0], toglob
) == 0
618 && stat(words
[0], &statb
) < 0)
619 || words
[0][0] == '\0')
621 x_free_words(nwords
, words
);
626 afree(toglob
, ATEMP
);
631 x_free_words(nwords
, words
);
637 /* Data structure used in x_command_glob() */
638 struct path_order_info
{
644 static int path_order_cmp(const void *aa
, const void *bb
);
646 /* Compare routine used in x_command_glob() */
648 path_order_cmp(aa
, bb
)
652 const struct path_order_info
*a
= (const struct path_order_info
*) aa
;
653 const struct path_order_info
*b
= (const struct path_order_info
*) bb
;
656 t
= FILECMP(a
->word
+ a
->base
, b
->word
+ b
->base
);
657 return t
? t
: a
->path_order
- b
->path_order
;
661 x_command_glob(flags
, str
, slen
, wordsp
)
677 toglob
= add_glob(str
, slen
);
679 /* Convert "foo*" (toglob) to a pattern for future use */
680 pat
= evalstr(toglob
, DOPAT
|DOTILDE
);
681 afree(toglob
, ATEMP
);
685 glob_table(pat
, &w
, &keywords
);
686 glob_table(pat
, &w
, &aliases
);
687 glob_table(pat
, &w
, &builtins
);
688 for (l
= e
->loc
; l
; l
= l
->next
)
689 glob_table(pat
, &w
, &l
->funs
);
691 glob_path(flags
, pat
, &w
, path
);
692 if ((fpath
= str_val(global("FPATH"))) != null
)
693 glob_path(flags
, pat
, &w
, fpath
);
698 *wordsp
= (char **) 0;
704 if (flags
& XCF_FULLPATH
) {
705 /* Sort by basename, then path order */
706 struct path_order_info
*info
;
707 struct path_order_info
*last_info
= 0;
708 char **words
= (char **) XPptrv(w
);
712 info
= (struct path_order_info
*)
713 alloc(sizeof(struct path_order_info
) * nwords
, ATEMP
);
714 for (i
= 0; i
< nwords
; i
++) {
715 info
[i
].word
= words
[i
];
716 info
[i
].base
= x_basename(words
[i
], (char *) 0);
717 if (!last_info
|| info
[i
].base
!= last_info
->base
718 || FILENCMP(words
[i
],
719 last_info
->word
, info
[i
].base
) != 0)
721 last_info
= &info
[i
];
724 info
[i
].path_order
= path_order
;
726 qsort(info
, nwords
, sizeof(struct path_order_info
),
728 for (i
= 0; i
< nwords
; i
++)
729 words
[i
] = info
[i
].word
;
730 afree((void *) info
, ATEMP
);
732 /* Sort and remove duplicate entries */
733 char **words
= (char **) XPptrv(w
);
736 qsortp(XPptrv(w
), (size_t) nwords
, xstrcmp
);
738 for (i
= j
= 0; i
< nwords
- 1; i
++) {
739 if (strcmp(words
[i
], words
[i
+ 1]))
740 words
[j
++] = words
[i
];
742 afree(words
[i
], ATEMP
);
744 words
[j
++] = words
[i
];
746 w
.cur
= (void **) &words
[j
];
750 *wordsp
= (char **) XPclose(w
);
755 #define IS_WORDC(c) !( ctype(c, C_LEX1) || (c) == '\'' || (c) == '"' \
756 || (c) == '`' || (c) == '=' || (c) == ':' )
759 x_locate_word(buf
, buflen
, pos
, startp
, is_commandp
)
769 /* Bad call? Probably should report error */
770 if (pos
< 0 || pos
> buflen
) {
775 /* The case where pos == buflen happens to take care of itself... */
778 /* Keep going backwards to start of word (has effect of allowing
779 * one blank after the end of a word)
781 for (; (start
> 0 && IS_WORDC(buf
[start
- 1]))
782 || (start
> 1 && buf
[start
-2] == '\\'); start
--)
784 /* Go forwards to end of word */
785 for (end
= start
; end
< buflen
&& IS_WORDC(buf
[end
]); end
++) {
786 if (buf
[end
] == '\\' && (end
+1) < buflen
)
793 /* Figure out if this is a command */
794 for (p
= start
- 1; p
>= 0 && isspace((unsigned char)buf
[p
]); p
--)
796 iscmd
= p
< 0 || strchr(";|&()`", buf
[p
]);
798 /* If command has a /, path, etc. is not searched;
799 * only current directory is searched, which is just
800 * like file globbing.
802 for (p
= start
; p
< end
; p
++)
803 if (ISDIRSEP(buf
[p
]))
807 *is_commandp
= iscmd
;
816 x_cf_glob(flags
, buf
, buflen
, pos
, startp
, endp
, wordsp
, is_commandp
)
831 len
= x_locate_word(buf
, buflen
, pos
, startp
, &is_command
);
832 if (!(flags
& XCF_COMMAND
))
834 /* Don't do command globing on zero length strings - it takes too
835 * long and isn't very useful. File globs are more likely to be
836 * useful, so allow these.
838 if (len
== 0 && is_command
)
841 nwords
= (is_command
? x_command_glob
: x_file_glob
)(flags
,
842 buf
+ *startp
, len
, &words
);
844 *wordsp
= (char **) 0;
849 *is_commandp
= is_command
;
851 *endp
= *startp
+ len
;
856 /* Given a string, copy it and possibly add a '*' to the end. The
857 * new string is returned.
866 bool_t saw_slash
= FALSE
;
871 toglob
= str_nsave(str
, slen
+ 1, ATEMP
); /* + 1 for "*" */
875 * If the pathname contains a wildcard (an unquoted '*',
876 * '?', or '[') or parameter expansion ('$'), or a ~username
877 * with no trailing slash, then it is globbed based on that
878 * value (i.e., without the appended '*').
880 for (s
= toglob
; *s
; s
++) {
881 if (*s
== '\\' && s
[1])
883 else if (*s
== '*' || *s
== '[' || *s
== '?' || *s
== '$'
884 || (s
[1] == '(' /*)*/ && strchr("*+?@!", *s
)))
886 else if (ISDIRSEP(*s
))
889 if (!*s
&& (*toglob
!= '~' || saw_slash
)) {
891 toglob
[slen
+ 1] = '\0';
898 * Find longest common prefix
901 x_longest_prefix(nwords
, words
)
912 prefix_len
= strlen(words
[0]);
913 for (i
= 1; i
< nwords
; i
++)
914 for (j
= 0, p
= words
[i
]; j
< prefix_len
; j
++)
915 if (FILECHCONV((unsigned char)p
[j
])
916 != FILECHCONV((unsigned char)words
[0][j
])) {
924 x_free_words(nwords
, words
)
930 for (i
= 0; i
< nwords
; i
++)
932 afree(words
[i
], ATEMP
);
936 /* Return the offset of the basename of string s (which ends at se - need not
937 * be null terminated). Trailing slashes are ignored. If s is just a slash,
938 * then the offset is 0 (actually, length - 1).
955 if (se
== (char *) 0)
960 /* Skip trailing slashes */
961 for (p
= se
- 1; p
> s
&& ISDIRSEP(*p
); p
--)
963 for (; p
> s
&& !ISDIRSEP(*p
); p
--)
965 if (ISDIRSEP(*p
) && p
+ 1 < se
)
972 * Apply pattern matching to a table: all table entries that match a pattern
976 glob_table(pat
, wp
, tp
)
984 for (twalk(&ts
, tp
); (te
= tnext(&ts
)); ) {
985 if (gmatch(te
->name
, pat
, FALSE
))
986 XPput(*wp
, str_save(te
->name
, ATEMP
));
991 glob_path(flags
, pat
, wp
, xpath
)
1002 int oldsize
, newsize
, i
, j
;
1006 patlen
= strlen(pat
) + 1;
1008 Xinit(xs
, xp
, patlen
+ 128, ATEMP
);
1010 xp
= Xstring(xs
, xp
);
1011 if (!(p
= strchr(sp
, PATHSEP
)))
1012 p
= sp
+ strlen(sp
);
1015 /* Copy sp into xp, stuffing any MAGIC characters
1020 XcheckN(xs
, xp
, pathlen
* 2);
1030 XcheckN(xs
, xp
, patlen
);
1031 memcpy(xp
, pat
, patlen
);
1033 oldsize
= XPsize(*wp
);
1034 glob_str(Xstring(xs
, xp
), wp
, 1); /* mark dirs */
1035 newsize
= XPsize(*wp
);
1037 /* Check that each match is executable... */
1038 words
= (char **) XPptrv(*wp
);
1039 for (i
= j
= oldsize
; i
< newsize
; i
++) {
1041 if ((search_access(words
[i
], X_OK
, &staterr
) >= 0)
1042 || (staterr
== EISDIR
)) {
1043 words
[j
] = words
[i
];
1044 if (!(flags
& XCF_FULLPATH
))
1045 memmove(words
[j
], words
[j
] + pathlen
,
1046 strlen(words
[j
] + pathlen
) + 1);
1049 afree(words
[i
], ATEMP
);
1051 wp
->cur
= (void **) &words
[j
];
1060 * if argument string contains any special characters, they will
1061 * be escaped and the result will be put into edit buffer by
1062 * keybinding-specific function
1065 x_escape(s
, len
, putbuf_func
)
1068 int putbuf_func
ARGS((const char *s
, size_t len
));
1071 const char *ifs
= str_val(local("IFS", 0));
1074 for (add
= 0, wlen
= len
; wlen
- add
> 0; add
++) {
1075 if (strchr("\\$(){}[]?*&;#|<>\"'`", s
[add
]) || strchr(ifs
, s
[add
])) {
1076 if (putbuf_func(s
, add
) != 0) {
1081 putbuf_func("\\", 1);
1082 putbuf_func(&s
[add
], 1);
1087 add
= -1; /* after the increment it will go to 0 */
1090 if (wlen
> 0 && rval
== 0)
1091 rval
= putbuf_func(s
, wlen
);