From: Chet Ramey Date: Thu, 12 Sep 2013 12:58:27 +0000 (-0400) Subject: commit bash-20130823 snapshot X-Git-Tag: bash-4.4-alpha~131 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=912dc4e98781ca060470933f974b546245581b65;p=thirdparty%2Fbash.git commit bash-20130823 snapshot --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index aee5efcc5..ae8f84c09 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -5174,3 +5174,46 @@ builtins/fc.def use it if -0 is specified as the beginning or end of the history range to list. Doesn't work for fc -e or fc -s by design. Feature requested by Mike Fied + + 8/16 + ---- +trap.c + - _run_trap_internal: use {save,restore}_parser_state instead of + {save,restore}_token_state. It's more comprehensive + + 8/23 + ---- +doc/bash.1 + - disown: remove repeated text. Report and fix from Thomas Hood + + + 8/25 + ---- +lib/readline/rltty.c + - set_special_char: fix prototype (last arg is rl_command_func_t *) + +sig.c + - set_signal_handler: return oact.sa_handler only if sigaction + succeeds; if it doesn't, return SIG_DFL (reasonable default). From + https://bugzilla.redhat.com/show_bug.cgi?id=911404 + +bashline.c + - attempt_shell_completion: fix to skip assignment statements preceding + command name even if there are no programmable completions defined. + From https://bugzilla.redhat.com/show_bug.cgi?id=994659 + - attempt_shell_completion: if still completing command word following + assignment statements, do command completion even if programmable + completion defined for partial command name entered so far + + 8/26 + ---- +pcomplete.c + - pcomp_filename_completion_function: make sure rl_filename_dequoting_function + is non-NULL before trying to call it. Bug and fix from + Andreas Schwab + +bashline.c + - bash_command_name_stat_hook: if *name is not something we're going + to look up in $PATH (absolute_program(*name) != 0), just call the + usual bash_filename_stat_hook and return those results. This makes + completions like $PWD/exam[TAB] add a trailing slash diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ index 15bfd2ac7..8a48b2713 100644 --- a/CWRU/CWRU.chlog~ +++ b/CWRU/CWRU.chlog~ @@ -5130,4 +5130,84 @@ arrayfunc.c - assign_array_element_internal: before using array_max_index() when processing a negative subscript, make sure the variable is an array. if it's not, use 0 as array_max_index assuming it's a string. - Bug report from Geir Hauge + Fixes bug report from Geir Hauge + + 8/3 + --- +Makefile.in + - pcomplete.o: add dependency on $(DEFDIR)/builtext.h. Suggested by + Curtis Doty + + 8/5 + --- +lib/glob/sm_loop.c + - strcompare: short-circuit and return FNM_NOMATCH if the lengths of the + pattern and string (pe - p and se - s, respectively) are not equal + - strcompare: don't bother trying to set *pe or *se to '\0' if that's + what they already are. Fixes bug reported by Geir Hauge + + + 8/6 + --- +doc/{bash.1,bashref.texi},builtins/hash.def,lib/readline/doc/rluser.texi + - minor typo changes from Geir Hauge + +bultins/help.def + - show_longdoc: avoid trying to translate the empty string because it + often translates to some boilerplate about the project and + translation. Report and fix from Geir Hauge + + 8/8 + --- +builtins/help.def + - help_builtin: try two passes through the list of help topics for each + argument: one doing exact string matching and one, if the first pass + fails to find a match, doing string prefix matching like previous + versions. This prevents `help read' from matching both `read' and + `readonly', but allows `help r' to match everything beginning with + `r'. Inspired by report from Geir Hauge + + 8/13 + ---- +builtins/fc.def + - fc_builtin,fc_gethnum: calculate `real' end of the history list and + use it if -0 is specified as the beginning or end of the history + range to list. Doesn't work for fc -e or fc -s by design. Feature + requested by Mike Fied + + 8/16 + ---- +trap.c + - _run_trap_internal: use {save,restore}_parser_state instead of + {save,restore}_token_state. It's more comprehensive + + 8/23 + ---- +doc/bash.1 + - disown: remove repeated text. Report and fix from Thomas Hood + + + 8/25 + ---- +lib/readline/rltty.c + - set_special_char: fix prototype (last arg is rl_command_func_t *) + +sig.c + - set_signal_handler: return oact.sa_handler only if sigaction + succeeds; if it doesn't, return SIG_DFL (reasonable default). From + https://bugzilla.redhat.com/show_bug.cgi?id=911404 + +bashline.c + - attempt_shell_completion: fix to skip assignment statements preceding + command name even if there are no programmable completions defined. + From https://bugzilla.redhat.com/show_bug.cgi?id=994659 + - attempt_shell_completion: if still completing command word following + assignment statements, do command completion even if programmable + completion defined for partial command name entered so far + + 8/26 + ---- +pcomplete.c + - pcomp_filename_completion_function: make sure rl_filename_dequoting_function + is non-NULL before trying to call it. Bug and fix from + Andreas Schwab diff --git a/bashline.c b/bashline.c index c9c19de6d..ef7219a2e 100644 --- a/bashline.c +++ b/bashline.c @@ -1374,6 +1374,9 @@ attempt_shell_completion (text, start, end) { int in_command_position, ti, saveti, qc, dflags; char **matches, *command_separator_chars; +#if defined (PROGRAMMABLE_COMPLETION) + int have_progcomps, was_assignment; +#endif command_separator_chars = COMMAND_SEPARATORS; matches = (char **)NULL; @@ -1448,8 +1451,8 @@ attempt_shell_completion (text, start, end) #if defined (PROGRAMMABLE_COMPLETION) /* Attempt programmable completion. */ + have_progcomps = prog_completion_enabled && (progcomp_size () > 0); if (matches == 0 && (in_command_position == 0 || text[0] == '\0') && - prog_completion_enabled && (progcomp_size () > 0) && current_prompt_string == ps1_prompt) { int s, e, s1, e1, os, foundcs; @@ -1474,23 +1477,42 @@ attempt_shell_completion (text, start, end) n = find_cmd_name (s, &s1, &e1); s = e1 + 1; } - while (assignment (n, 0)); + while (was_assignment = assignment (n, 0)); s = s1; /* reset to index where name begins */ + /* s == index of where command name begins (reset above) + e == end of current command, may be end of line + s1 = index of where command name begins + e1 == index of where command name ends + start == index of where word to be completed begins + end == index of where word to be completed ends + if (s == start) we are doing command word completion for sure + if (e1 == end) we are at the end of the command name and completing it */ if (start == 0 && end == 0 && e != 0 && text[0] == '\0') /* beginning of non-empty line */ foundcs = 0; else if (start == end && start == s1 && e != 0 && e1 > end) /* beginning of command name, leading whitespace */ foundcs = 0; - else if (e == 0 && e == s && text[0] == '\0') /* beginning of empty line */ + else if (e == 0 && e == s && text[0] == '\0' && have_progcomps) /* beginning of empty line */ prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs); else if (start == end && text[0] == '\0' && s1 > start && whitespace (rl_line_buffer[start])) foundcs = 0; /* whitespace before command name */ - else if (e > s && assignment (n, 0) == 0) - prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); + else if (e > s && was_assignment == 0 && e1 == end && rl_line_buffer[e] == 0 && whitespace (rl_line_buffer[e-1]) == 0) + { + /* not assignment statement, but still want to perform command + completion if we are composing command word. */ + foundcs = 0; + in_command_position = s == start && STREQ (n, text); /* XXX */ + } + else if (e > s && was_assignment == 0 && have_progcomps) + { + prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); + /* command completion if programmable completion fails */ + in_command_position = s == start && STREQ (n, text); /* XXX */ + } else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0) { foundcs = 0; /* empty command name following assignments */ - in_command_position = 1; + in_command_position = was_assignment; } else if (s == start && e == end && STREQ (n, text) && start > 0) { @@ -1650,6 +1672,11 @@ bash_command_name_stat_hook (name) { char *cname, *result; + /* If it's not something we're going to look up in $PATH, just call the + normal filename stat hook. */ + if (absolute_program (*name)) + return (bash_filename_stat_hook (name)); + cname = *name; /* XXX - we could do something here with converting aliases, builtins, and functions into something that came out as executable, but we don't. */ diff --git a/bashline.c.orig b/bashline.c.orig new file mode 100644 index 000000000..c9c19de6d --- /dev/null +++ b/bashline.c.orig @@ -0,0 +1,4156 @@ +/* bashline.c -- Bash's interface to the readline library. */ + +/* Copyright (C) 1987-2013 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bash. If not, see . +*/ + +#include "config.h" + +#if defined (READLINE) + +#include "bashtypes.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_GRP_H) +# include +#endif + +#if defined (HAVE_NETDB_H) +# include +#endif + +#include + +#include +#include "chartypes.h" +#include "bashansi.h" +#include "bashintl.h" + +#include "shell.h" +#include "input.h" +#include "builtins.h" +#include "bashhist.h" +#include "bashline.h" +#include "execute_cmd.h" +#include "findcmd.h" +#include "pathexp.h" +#include "shmbutil.h" + +#include "builtins/common.h" + +#include +#include +#include + +#include + +#if defined (ALIAS) +# include "alias.h" +#endif + +#if defined (PROGRAMMABLE_COMPLETION) +# include "pcomplete.h" +#endif + +/* These should agree with the defines for emacs_mode and vi_mode in + rldefs.h, even though that's not a public readline header file. */ +#ifndef EMACS_EDITING_MODE +# define NO_EDITING_MODE -1 +# define EMACS_EDITING_MODE 1 +# define VI_EDITING_MODE 0 +#endif + +#define RL_BOOLEAN_VARIABLE_VALUE(s) ((s)[0] == 'o' && (s)[1] == 'n' && (s)[2] == '\0') + +#if defined (BRACE_COMPLETION) +extern int bash_brace_completion __P((int, int)); +#endif /* BRACE_COMPLETION */ + +/* To avoid including curses.h/term.h/termcap.h and that whole mess. */ +#ifdef _MINIX +extern int tputs __P((const char *string, int nlines, void (*outx)(int))); +#else +extern int tputs __P((const char *string, int nlines, int (*outx)(int))); +#endif + +/* Forward declarations */ + +/* Functions bound to keys in Readline for Bash users. */ +static int shell_expand_line __P((int, int)); +static int display_shell_version __P((int, int)); +static int operate_and_get_next __P((int, int)); + +static int bash_ignore_filenames __P((char **)); +static int bash_ignore_everything __P((char **)); + +#if defined (BANG_HISTORY) +static char *history_expand_line_internal __P((char *)); +static int history_expand_line __P((int, int)); +static int tcsh_magic_space __P((int, int)); +#endif /* BANG_HISTORY */ +#ifdef ALIAS +static int alias_expand_line __P((int, int)); +#endif +#if defined (BANG_HISTORY) && defined (ALIAS) +static int history_and_alias_expand_line __P((int, int)); +#endif + +static int bash_forward_shellword __P((int, int)); +static int bash_backward_shellword __P((int, int)); +static int bash_kill_shellword __P((int, int)); +static int bash_backward_kill_shellword __P((int, int)); + +/* Helper functions for Readline. */ +static char *restore_tilde __P((char *, char *)); + +static char *bash_filename_rewrite_hook __P((char *, int)); + +static void bash_directory_expansion __P((char **)); +static int bash_filename_stat_hook __P((char **)); +static int bash_command_name_stat_hook __P((char **)); +static int bash_directory_completion_hook __P((char **)); +static int filename_completion_ignore __P((char **)); +static int bash_push_line __P((void)); + +static int executable_completion __P((const char *, int)); + +static rl_icppfunc_t *save_directory_hook __P((void)); +static void restore_directory_hook __P((rl_icppfunc_t)); + +static void cleanup_expansion_error __P((void)); +static void maybe_make_readline_line __P((char *)); +static void set_up_new_line __P((char *)); + +static int check_redir __P((int)); +static char **attempt_shell_completion __P((const char *, int, int)); +static char *variable_completion_function __P((const char *, int)); +static char *hostname_completion_function __P((const char *, int)); +static char *command_subst_completion_function __P((const char *, int)); + +static void build_history_completion_array __P((void)); +static char *history_completion_generator __P((const char *, int)); +static int dynamic_complete_history __P((int, int)); +static int bash_dabbrev_expand __P((int, int)); + +static void initialize_hostname_list __P((void)); +static void add_host_name __P((char *)); +static void snarf_hosts_from_file __P((char *)); +static char **hostnames_matching __P((char *)); + +static void _ignore_completion_names __P((char **, sh_ignore_func_t *)); +static int name_is_acceptable __P((const char *)); +static int test_for_directory __P((const char *)); +static int return_zero __P((const char *)); + +static char *bash_dequote_filename __P((char *, int)); +static char *quote_word_break_chars __P((char *)); +static void set_filename_bstab __P((const char *)); +static char *bash_quote_filename __P((char *, int, char *)); + +#ifdef _MINIX +static void putx __P((int)); +#else +static int putx __P((int)); +#endif +static int bash_execute_unix_command __P((int, int)); +static void init_unix_command_map __P((void)); +static int isolate_sequence __P((char *, int, int, int *)); + +static int set_saved_history __P((void)); + +#if defined (ALIAS) +static int posix_edit_macros __P((int, int)); +#endif + +static int bash_event_hook __P((void)); + +#if defined (PROGRAMMABLE_COMPLETION) +static int find_cmd_start __P((int)); +static int find_cmd_end __P((int)); +static char *find_cmd_name __P((int, int *, int *)); +static char *prog_complete_return __P((const char *, int)); + +static char **prog_complete_matches; +#endif + +/* Variables used here but defined in other files. */ +#if defined (BANG_HISTORY) +extern int hist_verify; +#endif + +extern int current_command_line_count, saved_command_line_count; +extern int last_command_exit_value; +extern int array_needs_making; +extern int posixly_correct, no_symbolic_links; +extern char *current_prompt_string, *ps1_prompt; +extern STRING_INT_ALIST word_token_alist[]; +extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin; + +/* SPECIFIC_COMPLETION_FUNCTIONS specifies that we have individual + completion functions which indicate what type of completion should be + done (at or before point) that can be bound to key sequences with + the readline library. */ +#define SPECIFIC_COMPLETION_FUNCTIONS + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) +static int bash_specific_completion __P((int, rl_compentry_func_t *)); + +static int bash_complete_filename_internal __P((int)); +static int bash_complete_username_internal __P((int)); +static int bash_complete_hostname_internal __P((int)); +static int bash_complete_variable_internal __P((int)); +static int bash_complete_command_internal __P((int)); + +static int bash_complete_filename __P((int, int)); +static int bash_possible_filename_completions __P((int, int)); +static int bash_complete_username __P((int, int)); +static int bash_possible_username_completions __P((int, int)); +static int bash_complete_hostname __P((int, int)); +static int bash_possible_hostname_completions __P((int, int)); +static int bash_complete_variable __P((int, int)); +static int bash_possible_variable_completions __P((int, int)); +static int bash_complete_command __P((int, int)); +static int bash_possible_command_completions __P((int, int)); + +static char *glob_complete_word __P((const char *, int)); +static int bash_glob_completion_internal __P((int)); +static int bash_glob_complete_word __P((int, int)); +static int bash_glob_expand_word __P((int, int)); +static int bash_glob_list_expansions __P((int, int)); + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + +static int edit_and_execute_command __P((int, int, int, char *)); +#if defined (VI_MODE) +static int vi_edit_and_execute_command __P((int, int)); +static int bash_vi_complete __P((int, int)); +#endif +static int emacs_edit_and_execute_command __P((int, int)); + +/* Non-zero once initalize_readline () has been called. */ +int bash_readline_initialized = 0; + +/* If non-zero, we do hostname completion, breaking words at `@' and + trying to complete the stuff after the `@' from our own internal + host list. */ +int perform_hostname_completion = 1; + +/* If non-zero, we don't do command completion on an empty line. */ +int no_empty_command_completion; + +/* Set FORCE_FIGNORE if you want to honor FIGNORE even if it ignores the + only possible matches. Set to 0 if you want to match filenames if they + are the only possible matches, even if FIGNORE says to. */ +int force_fignore = 1; + +/* Perform spelling correction on directory names during word completion */ +int dircomplete_spelling = 0; + +/* Expand directory names during word/filename completion. */ +#if DIRCOMPLETE_EXPAND_DEFAULT +int dircomplete_expand = 1; +int dircomplete_expand_relpath = 1; +#else +int dircomplete_expand = 0; +int dircomplete_expand_relpath = 0; +#endif + +/* When non-zero, perform `normal' shell quoting on completed filenames + even when the completed name contains a directory name with a shell + variable referene, so dollar signs in a filename get quoted appropriately. + Set to zero to remove dollar sign (and braces or parens as needed) from + the set of characters that will be quoted. */ +int complete_fullquote = 1; + +static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:"; +static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:"; +/* )) */ + +static const char *default_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{~"; /*}*/ +static char *custom_filename_quote_characters = 0; +static char filename_bstab[256]; + +static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL; + +static int dot_in_path = 0; + +/* Set to non-zero when dabbrev-expand is running */ +static int dabbrev_expand_active = 0; + +/* What kind of quoting is performed by bash_quote_filename: + COMPLETE_DQUOTE = double-quoting the filename + COMPLETE_SQUOTE = single_quoting the filename + COMPLETE_BSQUOTE = backslash-quoting special chars in the filename +*/ +#define COMPLETE_DQUOTE 1 +#define COMPLETE_SQUOTE 2 +#define COMPLETE_BSQUOTE 3 +static int completion_quoting_style = COMPLETE_BSQUOTE; + +/* Flag values for the final argument to bash_default_completion */ +#define DEFCOMP_CMDPOS 1 + +/* Change the readline VI-mode keymaps into or out of Posix.2 compliance. + Called when the shell is put into or out of `posix' mode. */ +void +posix_readline_initialize (on_or_off) + int on_or_off; +{ + if (on_or_off) + rl_variable_bind ("comment-begin", "#"); +#if defined (VI_MODE) + rl_bind_key_in_map (CTRL ('I'), on_or_off ? rl_insert : rl_complete, vi_insertion_keymap); +#endif +} + +void +reset_completer_word_break_chars () +{ + rl_completer_word_break_characters = perform_hostname_completion ? savestring (bash_completer_word_break_characters) : savestring (bash_nohostname_word_break_characters); +} + +/* When this function returns, rl_completer_word_break_characters points to + dynamically allocated memory. */ +int +enable_hostname_completion (on_or_off) + int on_or_off; +{ + int old_value; + char *at, *nv, *nval; + + old_value = perform_hostname_completion; + + if (on_or_off) + { + perform_hostname_completion = 1; + rl_special_prefixes = "$@"; + } + else + { + perform_hostname_completion = 0; + rl_special_prefixes = "$"; + } + + /* Now we need to figure out how to appropriately modify and assign + rl_completer_word_break_characters depending on whether we want + hostname completion on or off. */ + + /* If this is the first time this has been called + (bash_readline_initialized == 0), use the sames values as before, but + allocate new memory for rl_completer_word_break_characters. */ + + if (bash_readline_initialized == 0 && + (rl_completer_word_break_characters == 0 || + rl_completer_word_break_characters == rl_basic_word_break_characters)) + { + if (on_or_off) + rl_completer_word_break_characters = savestring (bash_completer_word_break_characters); + else + rl_completer_word_break_characters = savestring (bash_nohostname_word_break_characters); + } + else + { + /* See if we have anything to do. */ + at = strchr (rl_completer_word_break_characters, '@'); + if ((at == 0 && on_or_off == 0) || (at != 0 && on_or_off != 0)) + return old_value; + + /* We have something to do. Do it. */ + nval = (char *)xmalloc (strlen (rl_completer_word_break_characters) + 1 + on_or_off); + + if (on_or_off == 0) + { + /* Turn it off -- just remove `@' from word break chars. We want + to remove all occurrences of `@' from the char list, so we loop + rather than just copy the rest of the list over AT. */ + for (nv = nval, at = rl_completer_word_break_characters; *at; ) + if (*at != '@') + *nv++ = *at++; + else + at++; + *nv = '\0'; + } + else + { + nval[0] = '@'; + strcpy (nval + 1, rl_completer_word_break_characters); + } + + free (rl_completer_word_break_characters); + rl_completer_word_break_characters = nval; + } + + return (old_value); +} + +/* Called once from parse.y if we are going to use readline. */ +void +initialize_readline () +{ + rl_command_func_t *func; + char kseq[2]; + + if (bash_readline_initialized) + return; + + rl_terminal_name = get_string_value ("TERM"); + rl_instream = stdin; + rl_outstream = stderr; + + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "Bash"; + + /* Add bindable names before calling rl_initialize so they may be + referenced in the various inputrc files. */ + rl_add_defun ("shell-expand-line", shell_expand_line, -1); +#ifdef BANG_HISTORY + rl_add_defun ("history-expand-line", history_expand_line, -1); + rl_add_defun ("magic-space", tcsh_magic_space, -1); +#endif + + rl_add_defun ("shell-forward-word", bash_forward_shellword, -1); + rl_add_defun ("shell-backward-word", bash_backward_shellword, -1); + rl_add_defun ("shell-kill-word", bash_kill_shellword, -1); + rl_add_defun ("shell-backward-kill-word", bash_backward_kill_shellword, -1); + +#ifdef ALIAS + rl_add_defun ("alias-expand-line", alias_expand_line, -1); +# ifdef BANG_HISTORY + rl_add_defun ("history-and-alias-expand-line", history_and_alias_expand_line, -1); +# endif +#endif + + /* Backwards compatibility. */ + rl_add_defun ("insert-last-argument", rl_yank_last_arg, -1); + + rl_add_defun ("operate-and-get-next", operate_and_get_next, -1); + rl_add_defun ("display-shell-version", display_shell_version, -1); + rl_add_defun ("edit-and-execute-command", emacs_edit_and_execute_command, -1); + +#if defined (BRACE_COMPLETION) + rl_add_defun ("complete-into-braces", bash_brace_completion, -1); +#endif + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + rl_add_defun ("complete-filename", bash_complete_filename, -1); + rl_add_defun ("possible-filename-completions", bash_possible_filename_completions, -1); + rl_add_defun ("complete-username", bash_complete_username, -1); + rl_add_defun ("possible-username-completions", bash_possible_username_completions, -1); + rl_add_defun ("complete-hostname", bash_complete_hostname, -1); + rl_add_defun ("possible-hostname-completions", bash_possible_hostname_completions, -1); + rl_add_defun ("complete-variable", bash_complete_variable, -1); + rl_add_defun ("possible-variable-completions", bash_possible_variable_completions, -1); + rl_add_defun ("complete-command", bash_complete_command, -1); + rl_add_defun ("possible-command-completions", bash_possible_command_completions, -1); + rl_add_defun ("glob-complete-word", bash_glob_complete_word, -1); + rl_add_defun ("glob-expand-word", bash_glob_expand_word, -1); + rl_add_defun ("glob-list-expansions", bash_glob_list_expansions, -1); +#endif + + rl_add_defun ("dynamic-complete-history", dynamic_complete_history, -1); + rl_add_defun ("dabbrev-expand", bash_dabbrev_expand, -1); + + /* Bind defaults before binding our custom shell keybindings. */ + if (RL_ISSTATE(RL_STATE_INITIALIZED) == 0) + rl_initialize (); + + /* Bind up our special shell functions. */ + rl_bind_key_if_unbound_in_map (CTRL('E'), shell_expand_line, emacs_meta_keymap); + +#ifdef BANG_HISTORY + rl_bind_key_if_unbound_in_map ('^', history_expand_line, emacs_meta_keymap); +#endif + + rl_bind_key_if_unbound_in_map (CTRL ('O'), operate_and_get_next, emacs_standard_keymap); + rl_bind_key_if_unbound_in_map (CTRL ('V'), display_shell_version, emacs_ctlx_keymap); + + /* In Bash, the user can switch editing modes with "set -o [vi emacs]", + so it is not necessary to allow C-M-j for context switching. Turn + off this occasionally confusing behaviour. */ + kseq[0] = CTRL('J'); + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == rl_vi_editing_mode) + rl_unbind_key_in_map (CTRL('J'), emacs_meta_keymap); + kseq[0] = CTRL('M'); + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == rl_vi_editing_mode) + rl_unbind_key_in_map (CTRL('M'), emacs_meta_keymap); +#if defined (VI_MODE) + rl_unbind_key_in_map (CTRL('E'), vi_movement_keymap); +#endif + +#if defined (BRACE_COMPLETION) + rl_bind_key_if_unbound_in_map ('{', bash_brace_completion, emacs_meta_keymap); /*}*/ +#endif /* BRACE_COMPLETION */ + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + rl_bind_key_if_unbound_in_map ('/', bash_complete_filename, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('/', bash_possible_filename_completions, emacs_ctlx_keymap); + + /* Have to jump through hoops here because there is a default binding for + M-~ (rl_tilde_expand) */ + kseq[0] = '~'; + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == 0 || func == rl_tilde_expand) + rl_bind_keyseq_in_map (kseq, bash_complete_username, emacs_meta_keymap); + + rl_bind_key_if_unbound_in_map ('~', bash_possible_username_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('@', bash_complete_hostname, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('@', bash_possible_hostname_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('$', bash_complete_variable, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('$', bash_possible_variable_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('!', bash_complete_command, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('!', bash_possible_command_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('g', bash_glob_complete_word, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('*', bash_glob_expand_word, emacs_ctlx_keymap); + rl_bind_key_if_unbound_in_map ('g', bash_glob_list_expansions, emacs_ctlx_keymap); + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + + kseq[0] = TAB; + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == 0 || func == rl_tab_insert) + rl_bind_key_in_map (TAB, dynamic_complete_history, emacs_meta_keymap); + + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = attempt_shell_completion; + + /* Tell the completer that we might want to follow symbolic links or + do other expansion on directory names. */ + set_directory_hook (); + + rl_filename_rewrite_hook = bash_filename_rewrite_hook; + + rl_filename_stat_hook = bash_filename_stat_hook; + + /* Tell the filename completer we want a chance to ignore some names. */ + rl_ignore_some_completions_function = filename_completion_ignore; + + /* Bind C-xC-e to invoke emacs and run result as commands. */ + rl_bind_key_if_unbound_in_map (CTRL ('E'), emacs_edit_and_execute_command, emacs_ctlx_keymap); +#if defined (VI_MODE) + rl_bind_key_if_unbound_in_map ('v', vi_edit_and_execute_command, vi_movement_keymap); +# if defined (ALIAS) + rl_bind_key_if_unbound_in_map ('@', posix_edit_macros, vi_movement_keymap); +# endif + + rl_bind_key_in_map ('\\', bash_vi_complete, vi_movement_keymap); + rl_bind_key_in_map ('*', bash_vi_complete, vi_movement_keymap); + rl_bind_key_in_map ('=', bash_vi_complete, vi_movement_keymap); +#endif + + rl_completer_quote_characters = "'\""; + + /* This sets rl_completer_word_break_characters and rl_special_prefixes + to the appropriate values, depending on whether or not hostname + completion is enabled. */ + enable_hostname_completion (perform_hostname_completion); + + /* characters that need to be quoted when appearing in filenames. */ + rl_filename_quote_characters = default_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + + rl_filename_quoting_function = bash_quote_filename; + rl_filename_dequoting_function = bash_dequote_filename; + rl_char_is_quoted_p = char_is_quoted; + +#if 0 + /* This is superfluous and makes it impossible to use tab completion in + vi mode even when explicitly binding it in ~/.inputrc. sv_strict_posix() + should already have called posix_readline_initialize() when + posixly_correct was set. */ + if (posixly_correct) + posix_readline_initialize (1); +#endif + + bash_readline_initialized = 1; +} + +void +bashline_reinitialize () +{ + bash_readline_initialized = 0; +} + +void +bashline_set_event_hook () +{ + rl_signal_event_hook = bash_event_hook; +} + +void +bashline_reset_event_hook () +{ + rl_signal_event_hook = 0; +} + +/* On Sun systems at least, rl_attempted_completion_function can end up + getting set to NULL, and rl_completion_entry_function set to do command + word completion if Bash is interrupted while trying to complete a command + word. This just resets all the completion functions to the right thing. + It's called from throw_to_top_level(). */ +void +bashline_reset () +{ + tilde_initialize (); + rl_attempted_completion_function = attempt_shell_completion; + rl_completion_entry_function = NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + rl_filename_quote_characters = default_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + + set_directory_hook (); + rl_filename_stat_hook = bash_filename_stat_hook; + + bashline_reset_event_hook (); +} + +/* Contains the line to push into readline. */ +static char *push_to_readline = (char *)NULL; + +/* Push the contents of push_to_readline into the + readline buffer. */ +static int +bash_push_line () +{ + if (push_to_readline) + { + rl_insert_text (push_to_readline); + free (push_to_readline); + push_to_readline = (char *)NULL; + rl_startup_hook = old_rl_startup_hook; + } + return 0; +} + +/* Call this to set the initial text for the next line to read + from readline. */ +int +bash_re_edit (line) + char *line; +{ + FREE (push_to_readline); + + push_to_readline = savestring (line); + old_rl_startup_hook = rl_startup_hook; + rl_startup_hook = bash_push_line; + + return (0); +} + +static int +display_shell_version (count, c) + int count, c; +{ + rl_crlf (); + show_shell_version (0); + putc ('\r', rl_outstream); + fflush (rl_outstream); + rl_on_new_line (); + rl_redisplay (); + return 0; +} + +/* **************************************************************** */ +/* */ +/* Readline Stuff */ +/* */ +/* **************************************************************** */ + +/* If the user requests hostname completion, then simply build a list + of hosts, and complete from that forever more, or at least until + HOSTFILE is unset. */ + +/* THIS SHOULD BE A STRINGLIST. */ +/* The kept list of hostnames. */ +static char **hostname_list = (char **)NULL; + +/* The physical size of the above list. */ +static int hostname_list_size; + +/* The number of hostnames in the above list. */ +static int hostname_list_length; + +/* Whether or not HOSTNAME_LIST has been initialized. */ +int hostname_list_initialized = 0; + +/* Initialize the hostname completion table. */ +static void +initialize_hostname_list () +{ + char *temp; + + temp = get_string_value ("HOSTFILE"); + if (temp == 0) + temp = get_string_value ("hostname_completion_file"); + if (temp == 0) + temp = DEFAULT_HOSTS_FILE; + + snarf_hosts_from_file (temp); + + if (hostname_list) + hostname_list_initialized++; +} + +/* Add NAME to the list of hosts. */ +static void +add_host_name (name) + char *name; +{ + if (hostname_list_length + 2 > hostname_list_size) + { + hostname_list_size = (hostname_list_size + 32) - (hostname_list_size % 32); + hostname_list = strvec_resize (hostname_list, hostname_list_size); + } + + hostname_list[hostname_list_length++] = savestring (name); + hostname_list[hostname_list_length] = (char *)NULL; +} + +#define cr_whitespace(c) ((c) == '\r' || (c) == '\n' || whitespace(c)) + +static void +snarf_hosts_from_file (filename) + char *filename; +{ + FILE *file; + char *temp, buffer[256], name[256]; + register int i, start; + + file = fopen (filename, "r"); + if (file == 0) + return; + + while (temp = fgets (buffer, 255, file)) + { + /* Skip to first character. */ + for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++) + ; + + /* If comment or blank line, ignore. */ + if (buffer[i] == '\0' || buffer[i] == '#') + continue; + + /* If `preprocessor' directive, do the include. */ + if (strncmp (buffer + i, "$include ", 9) == 0) + { + char *incfile, *t; + + /* Find start of filename. */ + for (incfile = buffer + i + 9; *incfile && whitespace (*incfile); incfile++) + ; + + /* Find end of filename. */ + for (t = incfile; *t && cr_whitespace (*t) == 0; t++) + ; + + *t = '\0'; + + snarf_hosts_from_file (incfile); + continue; + } + + /* Skip internet address if present. */ + if (DIGIT (buffer[i])) + for (; buffer[i] && cr_whitespace (buffer[i]) == 0; i++); + + /* Gobble up names. Each name is separated with whitespace. */ + while (buffer[i]) + { + for (; cr_whitespace (buffer[i]); i++) + ; + if (buffer[i] == '\0' || buffer[i] == '#') + break; + + /* Isolate the current word. */ + for (start = i; buffer[i] && cr_whitespace (buffer[i]) == 0; i++) + ; + if (i == start) + continue; + strncpy (name, buffer + start, i - start); + name[i - start] = '\0'; + add_host_name (name); + } + } + fclose (file); +} + +/* Return the hostname list. */ +char ** +get_hostname_list () +{ + if (hostname_list_initialized == 0) + initialize_hostname_list (); + return (hostname_list); +} + +void +clear_hostname_list () +{ + register int i; + + if (hostname_list_initialized == 0) + return; + for (i = 0; i < hostname_list_length; i++) + free (hostname_list[i]); + hostname_list_length = hostname_list_initialized = 0; +} + +/* Return a NULL terminated list of hostnames which begin with TEXT. + Initialize the hostname list the first time if neccessary. + The array is malloc ()'ed, but not the individual strings. */ +static char ** +hostnames_matching (text) + char *text; +{ + register int i, len, nmatch, rsize; + char **result; + + if (hostname_list_initialized == 0) + initialize_hostname_list (); + + if (hostname_list_initialized == 0) + return ((char **)NULL); + + /* Special case. If TEXT consists of nothing, then the whole list is + what is desired. */ + if (*text == '\0') + { + result = strvec_create (1 + hostname_list_length); + for (i = 0; i < hostname_list_length; i++) + result[i] = hostname_list[i]; + result[i] = (char *)NULL; + return (result); + } + + /* Scan until found, or failure. */ + len = strlen (text); + result = (char **)NULL; + for (i = nmatch = rsize = 0; i < hostname_list_length; i++) + { + if (STREQN (text, hostname_list[i], len) == 0) + continue; + + /* OK, it matches. Add it to the list. */ + if (nmatch >= (rsize - 1)) + { + rsize = (rsize + 16) - (rsize % 16); + result = strvec_resize (result, rsize); + } + + result[nmatch++] = hostname_list[i]; + } + if (nmatch) + result[nmatch] = (char *)NULL; + return (result); +} + +/* The equivalent of the Korn shell C-o operate-and-get-next-history-line + editing command. */ +static int saved_history_line_to_use = -1; +static int last_saved_history_line = -1; + +#define HISTORY_FULL() (history_is_stifled () && history_length >= history_max_entries) + +static int +set_saved_history () +{ + /* XXX - compensate for assumption that history was `shuffled' if it was + actually not. */ + if (HISTORY_FULL () && + hist_last_line_added == 0 && + saved_history_line_to_use < history_length - 1) + saved_history_line_to_use++; + + if (saved_history_line_to_use >= 0) + { + rl_get_previous_history (history_length - saved_history_line_to_use, 0); + last_saved_history_line = saved_history_line_to_use; + } + saved_history_line_to_use = -1; + rl_startup_hook = old_rl_startup_hook; + return (0); +} + +static int +operate_and_get_next (count, c) + int count, c; +{ + int where; + + /* Accept the current line. */ + rl_newline (1, c); + + /* Find the current line, and find the next line to use. */ + where = where_history (); + + if (HISTORY_FULL () || (where >= history_length - 1)) + saved_history_line_to_use = where; + else + saved_history_line_to_use = where + 1; + + old_rl_startup_hook = rl_startup_hook; + rl_startup_hook = set_saved_history; + + return 0; +} + +/* This vi mode command causes VI_EDIT_COMMAND to be run on the current + command being entered (if no explicit argument is given), otherwise on + a command from the history file. */ + +#define VI_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-vi}}\"" +#define EMACS_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-emacs}}\"" +#define POSIX_VI_EDIT_COMMAND "fc -e vi" + +static int +edit_and_execute_command (count, c, editing_mode, edit_command) + int count, c, editing_mode; + char *edit_command; +{ + char *command, *metaval; + int r, rrs, metaflag; + sh_parser_state_t ps; + + rrs = rl_readline_state; + saved_command_line_count = current_command_line_count; + + /* Accept the current line. */ + rl_newline (1, c); + + if (rl_explicit_arg) + { + command = (char *)xmalloc (strlen (edit_command) + 8); + sprintf (command, "%s %d", edit_command, count); + } + else + { + /* Take the command we were just editing, add it to the history file, + then call fc to operate on it. We have to add a dummy command to + the end of the history because fc ignores the last command (assumes + it's supposed to deal with the command before the `fc'). */ + /* This breaks down when using command-oriented history and are not + finished with the command, so we should not ignore the last command */ + using_history (); + current_command_line_count++; /* for rl_newline above */ + bash_add_history (rl_line_buffer); + current_command_line_count = 0; /* for dummy history entry */ + bash_add_history (""); + history_lines_this_session++; + using_history (); + command = savestring (edit_command); + } + + metaval = rl_variable_value ("input-meta"); + metaflag = RL_BOOLEAN_VARIABLE_VALUE (metaval); + + /* Now, POSIX.1-2001 and SUSv3 say that the commands executed from the + temporary file should be placed into the history. We don't do that + yet. */ + if (rl_deprep_term_function) + (*rl_deprep_term_function) (); + save_parser_state (&ps); + r = parse_and_execute (command, (editing_mode == VI_EDITING_MODE) ? "v" : "C-xC-e", SEVAL_NOHIST); + restore_parser_state (&ps); + if (rl_prep_term_function) + (*rl_prep_term_function) (metaflag); + + current_command_line_count = saved_command_line_count; + + /* Now erase the contents of the current line and undo the effects of the + rl_accept_line() above. We don't even want to make the text we just + executed available for undoing. */ + rl_line_buffer[0] = '\0'; /* XXX */ + rl_point = rl_end = 0; + rl_done = 0; + rl_readline_state = rrs; + + rl_forced_update_display (); + + return r; +} + +#if defined (VI_MODE) +static int +vi_edit_and_execute_command (count, c) + int count, c; +{ + if (posixly_correct) + return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); + else + return (edit_and_execute_command (count, c, VI_EDITING_MODE, VI_EDIT_COMMAND)); +} +#endif /* VI_MODE */ + +static int +emacs_edit_and_execute_command (count, c) + int count, c; +{ + return (edit_and_execute_command (count, c, EMACS_EDITING_MODE, EMACS_EDIT_COMMAND)); +} + +#if defined (ALIAS) +static int +posix_edit_macros (count, key) + int count, key; +{ + int c; + char alias_name[3], *alias_value, *macro; + + c = rl_read_key (); + alias_name[0] = '_'; + alias_name[1] = c; + alias_name[2] = '\0'; + + alias_value = get_alias_value (alias_name); + if (alias_value && *alias_value) + { + macro = savestring (alias_value); + rl_push_macro_input (macro); + } + return 0; +} +#endif + +/* Bindable commands that move `shell-words': that is, sequences of + non-unquoted-metacharacters. */ + +#define WORDDELIM(c) (shellmeta(c) || shellblank(c)) + +static int +bash_forward_shellword (count, key) + int count, key; +{ + size_t slen; + int sindex, c, p; + DECLARE_MBSTATE; + + if (count < 0) + return (bash_backward_shellword (-count, key)); + + /* The tricky part of this is deciding whether or not the first character + we're on is an unquoted metacharacter. Not completely handled yet. */ + /* XXX - need to test this stuff with backslash-escaped shell + metacharacters and unclosed single- and double-quoted strings. */ + + p = rl_point; + slen = rl_end; + + while (count) + { + if (p == rl_end) + { + rl_point = rl_end; + return 0; + } + + /* Are we in a quoted string? If we are, move to the end of the quoted + string and continue the outer loop. We only want quoted strings, not + backslash-escaped characters, but char_is_quoted doesn't + differentiate. */ + if (char_is_quoted (rl_line_buffer, p) && p > 0 && rl_line_buffer[p-1] != '\\') + { + do + ADVANCE_CHAR (rl_line_buffer, slen, p); + while (p < rl_end && char_is_quoted (rl_line_buffer, p)); + count--; + continue; + } + + /* Rest of code assumes we are not in a quoted string. */ + /* Move forward until we hit a non-metacharacter. */ + while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c)) + { + switch (c) + { + default: + ADVANCE_CHAR (rl_line_buffer, slen, p); + continue; /* straight back to loop, don't increment p */ + case '\\': + if (p < rl_end && rl_line_buffer[p]) + ADVANCE_CHAR (rl_line_buffer, slen, p); + break; + case '\'': + p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP); + break; + case '"': + p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP); + break; + } + + if (p < rl_end) + p++; + } + + if (rl_line_buffer[p] == 0 || p == rl_end) + { + rl_point = rl_end; + rl_ding (); + return 0; + } + + /* Now move forward until we hit a non-quoted metacharacter or EOL */ + while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c) == 0) + { + switch (c) + { + default: + ADVANCE_CHAR (rl_line_buffer, slen, p); + continue; /* straight back to loop, don't increment p */ + case '\\': + if (p < rl_end && rl_line_buffer[p]) + ADVANCE_CHAR (rl_line_buffer, slen, p); + break; + case '\'': + p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP); + break; + case '"': + p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP); + break; + } + + if (p < rl_end) + p++; + } + + if (p == rl_end || rl_line_buffer[p] == 0) + { + rl_point = rl_end; + return (0); + } + + count--; + } + + rl_point = p; + return (0); +} + +static int +bash_backward_shellword (count, key) + int count, key; +{ + size_t slen; + int sindex, c, p; + DECLARE_MBSTATE; + + if (count < 0) + return (bash_forward_shellword (-count, key)); + + p = rl_point; + slen = rl_end; + + while (count) + { + if (p == 0) + { + rl_point = 0; + return 0; + } + + /* Move backward until we hit a non-metacharacter. */ + while (p > 0) + { + c = rl_line_buffer[p]; + if (WORDDELIM (c) && char_is_quoted (rl_line_buffer, p) == 0) + BACKUP_CHAR (rl_line_buffer, slen, p); + break; + } + + if (p == 0) + { + rl_point = 0; + return 0; + } + + /* Now move backward until we hit a metacharacter or BOL. */ + while (p > 0) + { + c = rl_line_buffer[p]; + if (WORDDELIM (c) && char_is_quoted (rl_line_buffer, p) == 0) + break; + BACKUP_CHAR (rl_line_buffer, slen, p); + } + + count--; + } + + rl_point = p; + return 0; +} + +static int +bash_kill_shellword (count, key) + int count, key; +{ + int p; + + if (count < 0) + return (bash_backward_kill_shellword (-count, key)); + + p = rl_point; + bash_forward_shellword (count, key); + + if (rl_point != p) + rl_kill_text (p, rl_point); + + rl_point = p; + if (rl_editing_mode == 1) /* 1 == emacs_mode */ + rl_mark = rl_point; + + return 0; +} + +static int +bash_backward_kill_shellword (count, key) + int count, key; +{ + int p; + + if (count < 0) + return (bash_kill_shellword (-count, key)); + + p = rl_point; + bash_backward_shellword (count, key); + + if (rl_point != p) + rl_kill_text (p, rl_point); + + if (rl_editing_mode == 1) /* 1 == emacs_mode */ + rl_mark = rl_point; + + return 0; +} + + +/* **************************************************************** */ +/* */ +/* How To Do Shell Completion */ +/* */ +/* **************************************************************** */ + +#define COMMAND_SEPARATORS ";|&{(`" +/* )} */ +#define COMMAND_SEPARATORS_PLUS_WS ";|&{(` \t" +/* )} */ + +/* check for redirections and other character combinations that are not + command separators */ +static int +check_redir (ti) + int ti; +{ + register int this_char, prev_char; + + /* Handle the two character tokens `>&', `<&', and `>|'. + We are not in a command position after one of these. */ + this_char = rl_line_buffer[ti]; + prev_char = rl_line_buffer[ti - 1]; + + if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) || + (this_char == '|' && prev_char == '>')) + return (1); + else if (this_char == '{' && prev_char == '$') /*}*/ + return (1); +#if 0 /* Not yet */ + else if (this_char == '(' && prev_char == '$') /*)*/ + return (1); + else if (this_char == '(' && prev_char == '<') /*)*/ + return (1); +#if defined (EXTENDED_GLOB) + else if (extended_glob && this_char == '(' && prev_char == '!') /*)*/ + return (1); +#endif +#endif + else if (char_is_quoted (rl_line_buffer, ti)) + return (1); + return (0); +} + +#if defined (PROGRAMMABLE_COMPLETION) +/* + * XXX - because of the <= start test, and setting os = s+1, this can + * potentially return os > start. This is probably not what we want to + * happen, but fix later after 2.05a-release. + */ +static int +find_cmd_start (start) + int start; +{ + register int s, os; + + os = 0; + /* Flags == SD_NOJMP only because we want to skip over command substitutions + in assignment statements. Have to test whether this affects `standalone' + command substitutions as individual words. */ + while (((s = skip_to_delim (rl_line_buffer, os, COMMAND_SEPARATORS, SD_NOJMP/*|SD_NOSKIPCMD*/)) <= start) && + rl_line_buffer[s]) + os = s+1; + return os; +} + +static int +find_cmd_end (end) + int end; +{ + register int e; + + e = skip_to_delim (rl_line_buffer, end, COMMAND_SEPARATORS, SD_NOJMP); + return e; +} + +static char * +find_cmd_name (start, sp, ep) + int start; + int *sp, *ep; +{ + char *name; + register int s, e; + + for (s = start; whitespace (rl_line_buffer[s]); s++) + ; + + /* skip until a shell break character */ + e = skip_to_delim (rl_line_buffer, s, "()<>;&| \t\n", SD_NOJMP); + + name = substring (rl_line_buffer, s, e); + + if (sp) + *sp = s; + if (ep) + *ep = e; + + return (name); +} + +static char * +prog_complete_return (text, matchnum) + const char *text; + int matchnum; +{ + static int ind; + + if (matchnum == 0) + ind = 0; + + if (prog_complete_matches == 0 || prog_complete_matches[ind] == 0) + return (char *)NULL; + return (prog_complete_matches[ind++]); +} + +#endif /* PROGRAMMABLE_COMPLETION */ + +/* Do some completion on TEXT. The indices of TEXT in RL_LINE_BUFFER are + at START and END. Return an array of matches, or NULL if none. */ +static char ** +attempt_shell_completion (text, start, end) + const char *text; + int start, end; +{ + int in_command_position, ti, saveti, qc, dflags; + char **matches, *command_separator_chars; + + command_separator_chars = COMMAND_SEPARATORS; + matches = (char **)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + + rl_filename_quote_characters = default_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + set_directory_hook (); + rl_filename_stat_hook = bash_filename_stat_hook; + + /* Determine if this could be a command word. It is if it appears at + the start of the line (ignoring preceding whitespace), or if it + appears after a character that separates commands. It cannot be a + command word if we aren't at the top-level prompt. */ + ti = start - 1; + saveti = qc = -1; + + while ((ti > -1) && (whitespace (rl_line_buffer[ti]))) + ti--; + +#if 1 + /* If this is an open quote, maybe we're trying to complete a quoted + command name. */ + if (ti >= 0 && (rl_line_buffer[ti] == '"' || rl_line_buffer[ti] == '\'')) + { + qc = rl_line_buffer[ti]; + saveti = ti--; + while (ti > -1 && (whitespace (rl_line_buffer[ti]))) + ti--; + } +#endif + + in_command_position = 0; + if (ti < 0) + { + /* Only do command completion at the start of a line when we + are prompting at the top level. */ + if (current_prompt_string == ps1_prompt) + in_command_position++; + else if (parser_in_command_position ()) + in_command_position++; + } + else if (member (rl_line_buffer[ti], command_separator_chars)) + { + in_command_position++; + + if (check_redir (ti) == 1) + in_command_position = 0; + } + else + { + /* This still could be in command position. It is possible + that all of the previous words on the line are variable + assignments. */ + } + + /* Check that we haven't incorrectly flagged a closed command substitution + as indicating we're in a command position. */ + if (in_command_position && ti >= 0 && rl_line_buffer[ti] == '`' && + *text != '`' && unclosed_pair (rl_line_buffer, end, "`") == 0) + in_command_position = 0; + + /* Special handling for command substitution. If *TEXT is a backquote, + it can be the start or end of an old-style command substitution, or + unmatched. If it's unmatched, both calls to unclosed_pair will + succeed. Don't bother if readline found a single quote and we are + completing on the substring. */ + if (*text == '`' && rl_completion_quote_character != '\'' && + (in_command_position || (unclosed_pair (rl_line_buffer, start, "`") && + unclosed_pair (rl_line_buffer, end, "`")))) + matches = rl_completion_matches (text, command_subst_completion_function); + +#if defined (PROGRAMMABLE_COMPLETION) + /* Attempt programmable completion. */ + if (matches == 0 && (in_command_position == 0 || text[0] == '\0') && + prog_completion_enabled && (progcomp_size () > 0) && + current_prompt_string == ps1_prompt) + { + int s, e, s1, e1, os, foundcs; + char *n; + + /* XXX - don't free the members */ + if (prog_complete_matches) + free (prog_complete_matches); + prog_complete_matches = (char **)NULL; + + os = start; + n = 0; + s = find_cmd_start (os); + e = find_cmd_end (end); + do + { + /* Skip over assignment statements preceding a command name. If we + don't find a command name at all, we can perform command name + completion. If we find a partial command name, we should perform + command name completion on it. */ + FREE (n); + n = find_cmd_name (s, &s1, &e1); + s = e1 + 1; + } + while (assignment (n, 0)); + s = s1; /* reset to index where name begins */ + + if (start == 0 && end == 0 && e != 0 && text[0] == '\0') /* beginning of non-empty line */ + foundcs = 0; + else if (start == end && start == s1 && e != 0 && e1 > end) /* beginning of command name, leading whitespace */ + foundcs = 0; + else if (e == 0 && e == s && text[0] == '\0') /* beginning of empty line */ + prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs); + else if (start == end && text[0] == '\0' && s1 > start && whitespace (rl_line_buffer[start])) + foundcs = 0; /* whitespace before command name */ + else if (e > s && assignment (n, 0) == 0) + prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); + else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0) + { + foundcs = 0; /* empty command name following assignments */ + in_command_position = 1; + } + else if (s == start && e == end && STREQ (n, text) && start > 0) + { + foundcs = 0; /* partial command name following assignments */ + in_command_position = 1; + } + else + foundcs = 0; + FREE (n); + /* XXX - if we found a COMPSPEC for the command, just return whatever + the programmable completion code returns, and disable the default + filename completion that readline will do unless the COPT_DEFAULT + option has been set with the `-o default' option to complete or + compopt. */ + if (foundcs) + { + pcomp_set_readline_variables (foundcs, 1); + /* Turn what the programmable completion code returns into what + readline wants. I should have made compute_lcd_of_matches + external... */ + matches = rl_completion_matches (text, prog_complete_return); + if ((foundcs & COPT_DEFAULT) == 0) + rl_attempted_completion_over = 1; /* no default */ + if (matches || ((foundcs & COPT_BASHDEFAULT) == 0)) + return (matches); + } + } +#endif + + if (matches == 0) + { + dflags = 0; + if (in_command_position) + dflags |= DEFCOMP_CMDPOS; + matches = bash_default_completion (text, start, end, qc, dflags); + } + + return matches; +} + +char ** +bash_default_completion (text, start, end, qc, compflags) + const char *text; + int start, end, qc, compflags; +{ + char **matches, *t; + + matches = (char **)NULL; + + /* New posix-style command substitution or variable name? */ + if (!matches && *text == '$') + { + if (qc != '\'' && text[1] == '(') /* ) */ + matches = rl_completion_matches (text, command_subst_completion_function); + else + { + matches = rl_completion_matches (text, variable_completion_function); + if (matches && matches[0] && matches[1] == 0) + { + t = savestring (matches[0]); + bash_filename_stat_hook (&t); + /* doesn't use test_for_directory because that performs tilde + expansion */ + if (file_isdir (t)) + rl_completion_append_character = '/'; + free (t); + } + } + } + + /* If the word starts in `~', and there is no slash in the word, then + try completing this word as a username. */ + if (matches == 0 && *text == '~' && mbschr (text, '/') == 0) + matches = rl_completion_matches (text, rl_username_completion_function); + + /* Another one. Why not? If the word starts in '@', then look through + the world of known hostnames for completion first. */ + if (matches == 0 && perform_hostname_completion && *text == '@') + matches = rl_completion_matches (text, hostname_completion_function); + + /* And last, (but not least) if this word is in a command position, then + complete over possible command names, including aliases, functions, + and command names. */ + if (matches == 0 && (compflags & DEFCOMP_CMDPOS)) + { + /* If END == START and text[0] == 0, we are trying to complete an empty + command word. */ + if (no_empty_command_completion && end == start && text[0] == '\0') + { + matches = (char **)NULL; + rl_ignore_some_completions_function = bash_ignore_everything; + } + else + { +#define CMD_IS_DIR(x) (absolute_pathname(x) == 0 && absolute_program(x) == 0 && *(x) != '~' && test_for_directory (x)) + + dot_in_path = 0; + matches = rl_completion_matches (text, command_word_completion_function); + + /* If we are attempting command completion and nothing matches, we + do not want readline to perform filename completion for us. We + still want to be able to complete partial pathnames, so set the + completion ignore function to something which will remove + filenames and leave directories in the match list. */ + if (matches == (char **)NULL) + rl_ignore_some_completions_function = bash_ignore_filenames; + else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) + /* If we found a single match, without looking in the current + directory (because it's not in $PATH), but the found name is + also a command in the current directory, suppress appending any + terminating character, since it's ambiguous. */ + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } + else if (matches[0] && matches[1] && STREQ (matches[0], matches[1]) && CMD_IS_DIR (matches[0])) + /* There are multiple instances of the same match (duplicate + completions haven't yet been removed). In this case, all of + the matches will be the same, and the duplicate removal code + will distill them all down to one. We turn on + rl_completion_suppress_append for the same reason as above. + Remember: we only care if there's eventually a single unique + completion. If there are multiple completions this won't + make a difference and the problem won't occur. */ + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } + } + } + + /* This could be a globbing pattern, so try to expand it using pathname + expansion. */ + if (!matches && glob_pattern_p (text)) + { + matches = rl_completion_matches (text, glob_complete_word); + /* A glob expression that matches more than one filename is problematic. + If we match more than one filename, punt. */ + if (matches && matches[1] && rl_completion_type == TAB) + { + strvec_dispose (matches); + matches = (char **)0; + } + else if (matches && matches[1] && rl_completion_type == '!') + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } + } + + return (matches); +} + +static int +bash_command_name_stat_hook (name) + char **name; +{ + char *cname, *result; + + cname = *name; + /* XXX - we could do something here with converting aliases, builtins, + and functions into something that came out as executable, but we don't. */ + result = search_for_command (cname, 0); + if (result) + { + *name = result; + return 1; + } + return 0; +} + +static int +executable_completion (filename, searching_path) + const char *filename; + int searching_path; +{ + char *f; + int r; + + f = savestring (filename); + bash_directory_completion_hook (&f); + + r = searching_path ? executable_file (f) : executable_or_directory (f); + free (f); + return r; +} + +/* This is the function to call when the word to complete is in a position + where a command word can be found. It grovels $PATH, looking for commands + that match. It also scans aliases, function names, and the shell_builtin + table. */ +char * +command_word_completion_function (hint_text, state) + const char *hint_text; + int state; +{ + static char *hint = (char *)NULL; + static char *path = (char *)NULL; + static char *val = (char *)NULL; + static char *filename_hint = (char *)NULL; + static char *dequoted_hint = (char *)NULL; + static char *directory_part = (char *)NULL; + static char **glob_matches = (char **)NULL; + static int path_index, hint_len, dequoted_len, istate, igncase; + static int mapping_over, local_index, searching_path, hint_is_dir; + static int old_glob_ignore_case, globpat; + static SHELL_VAR **varlist = (SHELL_VAR **)NULL; +#if defined (ALIAS) + static alias_t **alias_list = (alias_t **)NULL; +#endif /* ALIAS */ + char *temp, *cval; + + /* We have to map over the possibilities for command words. If we have + no state, then make one just for that purpose. */ + if (state == 0) + { + rl_filename_stat_hook = bash_command_name_stat_hook; + + if (dequoted_hint && dequoted_hint != hint) + free (dequoted_hint); + if (hint) + free (hint); + + mapping_over = searching_path = 0; + hint_is_dir = CMD_IS_DIR (hint_text); + val = (char *)NULL; + + temp = rl_variable_value ("completion-ignore-case"); + igncase = RL_BOOLEAN_VARIABLE_VALUE (temp); + + if (glob_matches) + { + free (glob_matches); + glob_matches = (char **)NULL; + } + + globpat = glob_pattern_p (hint_text); + + /* If this is an absolute program name, do not check it against + aliases, reserved words, functions or builtins. We must check + whether or not it is unique, and, if so, whether that filename + is executable. */ + if (globpat || absolute_program (hint_text)) + { + /* Perform tilde expansion on what's passed, so we don't end up + passing filenames with tildes directly to stat(). */ + if (*hint_text == '~') + { + hint = bash_tilde_expand (hint_text, 0); + directory_part = savestring (hint_text); + temp = strchr (directory_part, '/'); + if (temp) + *temp = 0; + else + { + free (directory_part); + directory_part = (char *)NULL; + } + } + else + hint = savestring (hint_text); + + dequoted_hint = hint; + /* If readline's completer found a quote character somewhere, but + didn't set the quote character, there must have been a quote + character embedded in the filename. It can't be at the start of + the filename, so we need to dequote the filename before we look + in the file system for it. */ + if (rl_completion_found_quote && rl_completion_quote_character == 0) + { + dequoted_hint = bash_dequote_filename (hint, 0); + free (hint); + hint = dequoted_hint; + } + dequoted_len = hint_len = strlen (hint); + + if (filename_hint) + free (filename_hint); + + filename_hint = savestring (hint); + + istate = 0; + + if (globpat) + { + mapping_over = 5; + goto globword; + } + else + { + if (dircomplete_expand && path_dot_or_dotdot (filename_hint)) + { + dircomplete_expand = 0; + set_directory_hook (); + dircomplete_expand = 1; + } + mapping_over = 4; + goto inner; + } + } + + dequoted_hint = hint = savestring (hint_text); + dequoted_len = hint_len = strlen (hint); + + if (rl_completion_found_quote && rl_completion_quote_character == 0) + { + dequoted_hint = bash_dequote_filename (hint, 0); + dequoted_len = strlen (dequoted_hint); + } + + path = get_string_value ("PATH"); + path_index = dot_in_path = 0; + + /* Initialize the variables for each type of command word. */ + local_index = 0; + + if (varlist) + free (varlist); + + varlist = all_visible_functions (); + +#if defined (ALIAS) + if (alias_list) + free (alias_list); + + alias_list = all_aliases (); +#endif /* ALIAS */ + } + + /* mapping_over says what we are currently hacking. Note that every case + in this list must fall through when there are no more possibilities. */ + + switch (mapping_over) + { + case 0: /* Aliases come first. */ +#if defined (ALIAS) + while (alias_list && alias_list[local_index]) + { + register char *alias; + + alias = alias_list[local_index++]->name; + + if (STREQN (alias, hint, hint_len)) + return (savestring (alias)); + } +#endif /* ALIAS */ + local_index = 0; + mapping_over++; + + case 1: /* Then shell reserved words. */ + { + while (word_token_alist[local_index].word) + { + register char *reserved_word; + + reserved_word = word_token_alist[local_index++].word; + + if (STREQN (reserved_word, hint, hint_len)) + return (savestring (reserved_word)); + } + local_index = 0; + mapping_over++; + } + + case 2: /* Then function names. */ + while (varlist && varlist[local_index]) + { + register char *varname; + + varname = varlist[local_index++]->name; + + if (STREQN (varname, hint, hint_len)) + return (savestring (varname)); + } + local_index = 0; + mapping_over++; + + case 3: /* Then shell builtins. */ + for (; local_index < num_shell_builtins; local_index++) + { + /* Ignore it if it doesn't have a function pointer or if it + is not currently enabled. */ + if (!shell_builtins[local_index].function || + (shell_builtins[local_index].flags & BUILTIN_ENABLED) == 0) + continue; + + if (STREQN (shell_builtins[local_index].name, hint, hint_len)) + { + int i = local_index++; + + return (savestring (shell_builtins[i].name)); + } + } + local_index = 0; + mapping_over++; + } + +globword: + /* Limited support for completing command words with globbing chars. Only + a single match (multiple matches that end up reducing the number of + characters in the common prefix are bad) will ever be returned on + regular completion. */ + if (globpat) + { + if (state == 0) + { + glob_ignore_case = igncase; + glob_matches = shell_glob_filename (hint); + glob_ignore_case = old_glob_ignore_case; + + if (GLOB_FAILED (glob_matches) || glob_matches == 0) + { + glob_matches = (char **)NULL; + return ((char *)NULL); + } + + local_index = 0; + + if (glob_matches[1] && rl_completion_type == TAB) /* multiple matches are bad */ + return ((char *)NULL); + } + + while (val = glob_matches[local_index++]) + { + if (executable_or_directory (val)) + { + if (*hint_text == '~' && directory_part) + { + temp = restore_tilde (val, directory_part); + free (val); + val = temp; + } + return (val); + } + free (val); + } + + glob_ignore_case = old_glob_ignore_case; + return ((char *)NULL); + } + + /* If the text passed is a directory in the current directory, return it + as a possible match. Executables in directories in the current + directory can be specified using relative pathnames and successfully + executed even when `.' is not in $PATH. */ + if (hint_is_dir) + { + hint_is_dir = 0; /* only return the hint text once */ + return (savestring (hint_text)); + } + + /* Repeatedly call filename_completion_function while we have + members of PATH left. Question: should we stat each file? + Answer: we call executable_file () on each file. */ + outer: + + istate = (val != (char *)NULL); + + if (istate == 0) + { + char *current_path; + + /* Get the next directory from the path. If there is none, then we + are all done. */ + if (path == 0 || path[path_index] == 0 || + (current_path = extract_colon_unit (path, &path_index)) == 0) + return ((char *)NULL); + + searching_path = 1; + if (*current_path == 0) + { + free (current_path); + current_path = savestring ("."); + } + + if (*current_path == '~') + { + char *t; + + t = bash_tilde_expand (current_path, 0); + free (current_path); + current_path = t; + } + + if (current_path[0] == '.' && current_path[1] == '\0') + dot_in_path = 1; + + if (filename_hint) + free (filename_hint); + + filename_hint = sh_makepath (current_path, hint, 0); + free (current_path); /* XXX */ + } + + inner: + val = rl_filename_completion_function (filename_hint, istate); + if (mapping_over == 4 && dircomplete_expand) + set_directory_hook (); + + istate = 1; + + if (val == 0) + { + /* If the hint text is an absolute program, then don't bother + searching through PATH. */ + if (absolute_program (hint)) + return ((char *)NULL); + + goto outer; + } + else + { + int match, freetemp; + + if (absolute_program (hint)) + { + if (igncase == 0) + match = strncmp (val, hint, hint_len) == 0; + else + match = strncasecmp (val, hint, hint_len) == 0; + + /* If we performed tilde expansion, restore the original + filename. */ + if (*hint_text == '~') + temp = restore_tilde (val, directory_part); + else + temp = savestring (val); + freetemp = 1; + } + else + { + temp = strrchr (val, '/'); + + if (temp) + { + temp++; + if (igncase == 0) + freetemp = match = strncmp (temp, hint, hint_len) == 0; + else + freetemp = match = strncasecmp (temp, hint, hint_len) == 0; + if (match) + temp = savestring (temp); + } + else + freetemp = match = 0; + } + + /* If we have found a match, and it is an executable file, return it. + We don't return directory names when searching $PATH, since the + bash execution code won't find executables in directories which + appear in directories in $PATH when they're specified using + relative pathnames. */ +#if 0 + /* If we're not searching $PATH and we have a relative pathname, we + need to re-canonicalize it before testing whether or not it's an + executable or a directory so the shell treats .. relative to $PWD + according to the physical/logical option. The shell already + canonicalizes the directory name in order to tell readline where + to look, so not doing it here will be inconsistent. */ + /* XXX -- currently not used -- will introduce more inconsistency, + since shell does not canonicalize ../foo before passing it to + shell_execve(). */ + if (match && searching_path == 0 && *val == '.') + { + char *t, *t1; + + t = get_working_directory ("command-word-completion"); + t1 = make_absolute (val, t); + free (t); + cval = sh_canonpath (t1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + } + else +#endif + cval = val; + + if (match && executable_completion ((searching_path ? val : cval), searching_path)) + { + if (cval != val) + free (cval); + free (val); + val = ""; /* So it won't be NULL. */ + return (temp); + } + else + { + if (freetemp) + free (temp); + if (cval != val) + free (cval); + free (val); + goto inner; + } + } +} + +/* Completion inside an unterminated command substitution. */ +static char * +command_subst_completion_function (text, state) + const char *text; + int state; +{ + static char **matches = (char **)NULL; + static const char *orig_start; + static char *filename_text = (char *)NULL; + static int cmd_index, start_len; + char *value; + + if (state == 0) + { + if (filename_text) + free (filename_text); + orig_start = text; + if (*text == '`') + text++; + else if (*text == '$' && text[1] == '(') /* ) */ + text += 2; + /* If the text was quoted, suppress any quote character that the + readline completion code would insert. */ + rl_completion_suppress_quote = 1; + start_len = text - orig_start; + filename_text = savestring (text); + if (matches) + free (matches); + + /* + * At this point we can entertain the idea of re-parsing + * `filename_text' into a (possibly incomplete) command name and + * arguments, and doing completion based on that. This is + * currently very rudimentary, but it is a small improvement. + */ + for (value = filename_text + strlen (filename_text) - 1; value > filename_text; value--) + if (whitespace (*value) || member (*value, COMMAND_SEPARATORS)) + break; + if (value <= filename_text) + matches = rl_completion_matches (filename_text, command_word_completion_function); + else + { + value++; + start_len += value - filename_text; + if (whitespace (value[-1])) + matches = rl_completion_matches (value, rl_filename_completion_function); + else + matches = rl_completion_matches (value, command_word_completion_function); + } + + /* If there is more than one match, rl_completion_matches has already + put the lcd in matches[0]. Skip over it. */ + cmd_index = matches && matches[0] && matches[1]; + + /* If there's a single match and it's a directory, set the append char + to the expected `/'. Otherwise, don't append anything. */ + if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) + rl_completion_append_character = '/'; + else + rl_completion_suppress_append = 1; + } + + if (matches == 0 || matches[cmd_index] == 0) + { + rl_filename_quoting_desired = 0; /* disable quoting */ + return ((char *)NULL); + } + else + { + value = (char *)xmalloc (1 + start_len + strlen (matches[cmd_index])); + + if (start_len == 1) + value[0] = *orig_start; + else + strncpy (value, orig_start, start_len); + + strcpy (value + start_len, matches[cmd_index]); + + cmd_index++; + return (value); + } +} + +/* Okay, now we write the entry_function for variable completion. */ +static char * +variable_completion_function (text, state) + const char *text; + int state; +{ + static char **varlist = (char **)NULL; + static int varlist_index; + static char *varname = (char *)NULL; + static int namelen; + static int first_char, first_char_loc; + + if (!state) + { + if (varname) + free (varname); + + first_char_loc = 0; + first_char = text[0]; + + if (first_char == '$') + first_char_loc++; + + if (text[first_char_loc] == '{') + first_char_loc++; + + varname = savestring (text + first_char_loc); + + namelen = strlen (varname); + if (varlist) + strvec_dispose (varlist); + + varlist = all_variables_matching_prefix (varname); + varlist_index = 0; + } + + if (!varlist || !varlist[varlist_index]) + { + return ((char *)NULL); + } + else + { + char *value; + + value = (char *)xmalloc (4 + strlen (varlist[varlist_index])); + + if (first_char_loc) + { + value[0] = first_char; + if (first_char_loc == 2) + value[1] = '{'; + } + + strcpy (value + first_char_loc, varlist[varlist_index]); + if (first_char_loc == 2) + strcat (value, "}"); + + varlist_index++; + return (value); + } +} + +/* How about a completion function for hostnames? */ +static char * +hostname_completion_function (text, state) + const char *text; + int state; +{ + static char **list = (char **)NULL; + static int list_index = 0; + static int first_char, first_char_loc; + + /* If we don't have any state, make some. */ + if (state == 0) + { + FREE (list); + + list = (char **)NULL; + + first_char_loc = 0; + first_char = *text; + + if (first_char == '@') + first_char_loc++; + + list = hostnames_matching ((char *)text+first_char_loc); + list_index = 0; + } + + if (list && list[list_index]) + { + char *t; + + t = (char *)xmalloc (2 + strlen (list[list_index])); + *t = first_char; + strcpy (t + first_char_loc, list[list_index]); + list_index++; + return (t); + } + + return ((char *)NULL); +} + +/* + * A completion function for service names from /etc/services (or wherever). + */ +char * +bash_servicename_completion_function (text, state) + const char *text; + int state; +{ +#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GETSERVENT) + return ((char *)NULL); +#else + static char *sname = (char *)NULL; + static struct servent *srvent; + static int snamelen, firstc; + char *value; + char **alist, *aentry; + int afound; + + if (state == 0) + { + FREE (sname); + firstc = *text; + + sname = savestring (text); + snamelen = strlen (sname); + setservent (0); + } + + while (srvent = getservent ()) + { + afound = 0; + if (snamelen == 0 || (STREQN (sname, srvent->s_name, snamelen))) + break; + /* Not primary, check aliases */ + for (alist = srvent->s_aliases; *alist; alist++) + { + aentry = *alist; + if (STREQN (sname, aentry, snamelen)) + { + afound = 1; + break; + } + } + + if (afound) + break; + } + + if (srvent == 0) + { + endservent (); + return ((char *)NULL); + } + + value = afound ? savestring (aentry) : savestring (srvent->s_name); + return value; +#endif +} + +/* + * A completion function for group names from /etc/group (or wherever). + */ +char * +bash_groupname_completion_function (text, state) + const char *text; + int state; +{ +#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GRP_H) + return ((char *)NULL); +#else + static char *gname = (char *)NULL; + static struct group *grent; + static int gnamelen; + char *value; + + if (state == 0) + { + FREE (gname); + gname = savestring (text); + gnamelen = strlen (gname); + + setgrent (); + } + + while (grent = getgrent ()) + { + if (gnamelen == 0 || (STREQN (gname, grent->gr_name, gnamelen))) + break; + } + + if (grent == 0) + { + endgrent (); + return ((char *)NULL); + } + + value = savestring (grent->gr_name); + return (value); +#endif +} + +/* Functions to perform history and alias expansions on the current line. */ + +#if defined (BANG_HISTORY) +/* Perform history expansion on the current line. If no history expansion + is done, pre_process_line() returns what it was passed, so we need to + allocate a new line here. */ +static char * +history_expand_line_internal (line) + char *line; +{ + char *new_line; + int old_verify; + + old_verify = hist_verify; + hist_verify = 0; + new_line = pre_process_line (line, 0, 0); + hist_verify = old_verify; + + return (new_line == line) ? savestring (line) : new_line; +} +#endif + +/* There was an error in expansion. Let the preprocessor print + the error here. */ +static void +cleanup_expansion_error () +{ + char *to_free; +#if defined (BANG_HISTORY) + int old_verify; + + old_verify = hist_verify; + hist_verify = 0; +#endif + + fprintf (rl_outstream, "\r\n"); + to_free = pre_process_line (rl_line_buffer, 1, 0); +#if defined (BANG_HISTORY) + hist_verify = old_verify; +#endif + if (to_free != rl_line_buffer) + FREE (to_free); + putc ('\r', rl_outstream); + rl_forced_update_display (); +} + +/* If NEW_LINE differs from what is in the readline line buffer, add an + undo record to get from the readline line buffer contents to the new + line and make NEW_LINE the current readline line. */ +static void +maybe_make_readline_line (new_line) + char *new_line; +{ + if (strcmp (new_line, rl_line_buffer) != 0) + { + rl_point = rl_end; + + rl_add_undo (UNDO_BEGIN, 0, 0, 0); + rl_delete_text (0, rl_point); + rl_point = rl_end = rl_mark = 0; + rl_insert_text (new_line); + rl_add_undo (UNDO_END, 0, 0, 0); + } +} + +/* Make NEW_LINE be the current readline line. This frees NEW_LINE. */ +static void +set_up_new_line (new_line) + char *new_line; +{ + int old_point, at_end; + + old_point = rl_point; + at_end = rl_point == rl_end; + + /* If the line was history and alias expanded, then make that + be one thing to undo. */ + maybe_make_readline_line (new_line); + free (new_line); + + /* Place rl_point where we think it should go. */ + if (at_end) + rl_point = rl_end; + else if (old_point < rl_end) + { + rl_point = old_point; + if (!whitespace (rl_line_buffer[rl_point])) + rl_forward_word (1, 0); + } +} + +#if defined (ALIAS) +/* Expand aliases in the current readline line. */ +static int +alias_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = alias_expand (rl_line_buffer); + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} +#endif + +#if defined (BANG_HISTORY) +/* History expand the line. */ +static int +history_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = history_expand_line_internal (rl_line_buffer); + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} + +/* Expand history substitutions in the current line and then insert a + space (hopefully close to where we were before). */ +static int +tcsh_magic_space (count, ignore) + int count, ignore; +{ + int dist_from_end, old_point; + + old_point = rl_point; + dist_from_end = rl_end - rl_point; + if (history_expand_line (count, ignore) == 0) + { + /* Try a simple heuristic from Stephen Gildea . + This works if all expansions were before rl_point or if no expansions + were performed. */ + rl_point = (old_point == 0) ? old_point : rl_end - dist_from_end; + rl_insert (1, ' '); + return (0); + } + else + return (1); +} +#endif /* BANG_HISTORY */ + +/* History and alias expand the line. */ +static int +history_and_alias_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = 0; +#if defined (BANG_HISTORY) + new_line = history_expand_line_internal (rl_line_buffer); +#endif + +#if defined (ALIAS) + if (new_line) + { + char *alias_line; + + alias_line = alias_expand (new_line); + free (new_line); + new_line = alias_line; + } +#endif /* ALIAS */ + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} + +/* History and alias expand the line, then perform the shell word + expansions by calling expand_string. This can't use set_up_new_line() + because we want the variable expansions as a separate undo'able + set of operations. */ +static int +shell_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + WORD_LIST *expanded_string; + + new_line = 0; +#if defined (BANG_HISTORY) + new_line = history_expand_line_internal (rl_line_buffer); +#endif + +#if defined (ALIAS) + if (new_line) + { + char *alias_line; + + alias_line = alias_expand (new_line); + free (new_line); + new_line = alias_line; + } +#endif /* ALIAS */ + + if (new_line) + { + int old_point = rl_point; + int at_end = rl_point == rl_end; + + /* If the line was history and alias expanded, then make that + be one thing to undo. */ + maybe_make_readline_line (new_line); + free (new_line); + + /* If there is variable expansion to perform, do that as a separate + operation to be undone. */ + new_line = savestring (rl_line_buffer); + expanded_string = expand_string (new_line, 0); + FREE (new_line); + if (expanded_string == 0) + { + new_line = (char *)xmalloc (1); + new_line[0] = '\0'; + } + else + { + new_line = string_list (expanded_string); + dispose_words (expanded_string); + } + + maybe_make_readline_line (new_line); + free (new_line); + + /* Place rl_point where we think it should go. */ + if (at_end) + rl_point = rl_end; + else if (old_point < rl_end) + { + rl_point = old_point; + if (!whitespace (rl_line_buffer[rl_point])) + rl_forward_word (1, 0); + } + return 0; + } + else + { + cleanup_expansion_error (); + return 1; + } +} + +/* If FIGNORE is set, then don't match files with the given suffixes when + completing filenames. If only one of the possibilities has an acceptable + suffix, delete the others, else just return and let the completer + signal an error. It is called by the completer when real + completions are done on filenames by the completer's internal + function, not for completion lists (M-?) and not on "other" + completion types, such as hostnames or commands. */ + +static struct ignorevar fignore = +{ + "FIGNORE", + (struct ign *)0, + 0, + (char *)0, + (sh_iv_item_func_t *) 0, +}; + +static void +_ignore_completion_names (names, name_func) + char **names; + sh_ignore_func_t *name_func; +{ + char **newnames; + int idx, nidx; + char **oldnames; + int oidx; + + /* If there is only one completion, see if it is acceptable. If it is + not, free it up. In any case, short-circuit and return. This is a + special case because names[0] is not the prefix of the list of names + if there is only one completion; it is the completion itself. */ + if (names[1] == (char *)0) + { + if (force_fignore) + if ((*name_func) (names[0]) == 0) + { + free (names[0]); + names[0] = (char *)NULL; + } + + return; + } + + /* Allocate space for array to hold list of pointers to matching + filenames. The pointers are copied back to NAMES when done. */ + for (nidx = 1; names[nidx]; nidx++) + ; + newnames = strvec_create (nidx + 1); + + if (force_fignore == 0) + { + oldnames = strvec_create (nidx - 1); + oidx = 0; + } + + newnames[0] = names[0]; + for (idx = nidx = 1; names[idx]; idx++) + { + if ((*name_func) (names[idx])) + newnames[nidx++] = names[idx]; + else if (force_fignore == 0) + oldnames[oidx++] = names[idx]; + else + free (names[idx]); + } + + newnames[nidx] = (char *)NULL; + + /* If none are acceptable then let the completer handle it. */ + if (nidx == 1) + { + if (force_fignore) + { + free (names[0]); + names[0] = (char *)NULL; + } + else + free (oldnames); + + free (newnames); + return; + } + + if (force_fignore == 0) + { + while (oidx) + free (oldnames[--oidx]); + free (oldnames); + } + + /* If only one is acceptable, copy it to names[0] and return. */ + if (nidx == 2) + { + free (names[0]); + names[0] = newnames[1]; + names[1] = (char *)NULL; + free (newnames); + return; + } + + /* Copy the acceptable names back to NAMES, set the new array end, + and return. */ + for (nidx = 1; newnames[nidx]; nidx++) + names[nidx] = newnames[nidx]; + names[nidx] = (char *)NULL; + free (newnames); +} + +static int +name_is_acceptable (name) + const char *name; +{ + struct ign *p; + int nlen; + + for (nlen = strlen (name), p = fignore.ignores; p->val; p++) + { + if (nlen > p->len && p->len > 0 && STREQ (p->val, &name[nlen - p->len])) + return (0); + } + + return (1); +} + +#if 0 +static int +ignore_dot_names (name) + char *name; +{ + return (name[0] != '.'); +} +#endif + +static int +filename_completion_ignore (names) + char **names; +{ +#if 0 + if (glob_dot_filenames == 0) + _ignore_completion_names (names, ignore_dot_names); +#endif + + setup_ignore_patterns (&fignore); + + if (fignore.num_ignores == 0) + return 0; + + _ignore_completion_names (names, name_is_acceptable); + + return 0; +} + +/* Return 1 if NAME is a directory. NAME undergoes tilde expansion. */ +static int +test_for_directory (name) + const char *name; +{ + char *fn; + int r; + + fn = bash_tilde_expand (name, 0); + r = file_isdir (fn); + free (fn); + + return (r); +} + +/* Remove files from NAMES, leaving directories. */ +static int +bash_ignore_filenames (names) + char **names; +{ + _ignore_completion_names (names, test_for_directory); + return 0; +} + +static int +return_zero (name) + const char *name; +{ + return 0; +} + +static int +bash_ignore_everything (names) + char **names; +{ + _ignore_completion_names (names, return_zero); + return 0; +} + +/* Replace a tilde-prefix in VAL with a `~', assuming the user typed it. VAL + is an expanded filename. DIRECTORY_PART is the tilde-prefix portion + of the un-tilde-expanded version of VAL (what the user typed). */ +static char * +restore_tilde (val, directory_part) + char *val, *directory_part; +{ + int l, vl, dl2, xl; + char *dh2, *expdir, *ret; + + vl = strlen (val); + + /* We need to duplicate the expansions readline performs on the directory + portion before passing it to our completion function. */ + dh2 = directory_part ? bash_dequote_filename (directory_part, 0) : 0; + bash_directory_expansion (&dh2); + dl2 = strlen (dh2); + + expdir = bash_tilde_expand (directory_part, 0); + xl = strlen (expdir); + free (expdir); + + /* + dh2 = unexpanded but dequoted tilde-prefix + dl2 = length of tilde-prefix + expdir = tilde-expanded tilde-prefix + xl = length of expanded tilde-prefix + l = length of remainder after tilde-prefix + */ + l = (vl - xl) + 1; + + ret = (char *)xmalloc (dl2 + 2 + l); + strcpy (ret, dh2); + strcpy (ret + dl2, val + xl); + + free (dh2); + return (ret); +} + +/* Simulate the expansions that will be performed by + rl_filename_completion_function. This must be called with the address of + a pointer to malloc'd memory. */ +static void +bash_directory_expansion (dirname) + char **dirname; +{ + char *d, *nd; + + d = savestring (*dirname); + + if ((rl_directory_rewrite_hook) && (*rl_directory_rewrite_hook) (&d)) + { + free (*dirname); + *dirname = d; + } + else if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) + { + free (*dirname); + *dirname = d; + } + else if (rl_completion_found_quote) + { + nd = bash_dequote_filename (d, rl_completion_quote_character); + free (*dirname); + free (d); + *dirname = nd; + } +} + +/* If necessary, rewrite directory entry */ +static char * +bash_filename_rewrite_hook (fname, fnlen) + char *fname; + int fnlen; +{ + char *conv; + + conv = fnx_fromfs (fname, fnlen); + if (conv != fname) + conv = savestring (conv); + return conv; +} + +/* Functions to save and restore the appropriate directory hook */ +/* This is not static so the shopt code can call it */ +void +set_directory_hook () +{ + if (dircomplete_expand) + { + rl_directory_completion_hook = bash_directory_completion_hook; + rl_directory_rewrite_hook = (rl_icppfunc_t *)0; + } + else + { + rl_directory_rewrite_hook = bash_directory_completion_hook; + rl_directory_completion_hook = (rl_icppfunc_t *)0; + } +} + +static rl_icppfunc_t * +save_directory_hook () +{ + rl_icppfunc_t *ret; + + if (dircomplete_expand) + { + ret = rl_directory_completion_hook; + rl_directory_completion_hook = (rl_icppfunc_t *)NULL; + } + else + { + ret = rl_directory_rewrite_hook; + rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL; + } + + return ret; +} + +static void +restore_directory_hook (hookf) + rl_icppfunc_t *hookf; +{ + if (dircomplete_expand) + rl_directory_completion_hook = hookf; + else + rl_directory_rewrite_hook = hookf; +} + +/* Expand a filename before the readline completion code passes it to stat(2). + The filename will already have had tilde expansion performed. */ +static int +bash_filename_stat_hook (dirname) + char **dirname; +{ + char *local_dirname, *new_dirname, *t; + int should_expand_dirname, return_value; + WORD_LIST *wl; + struct stat sb; + + local_dirname = *dirname; + should_expand_dirname = return_value = 0; + if (t = mbschr (local_dirname, '$')) + should_expand_dirname = '$'; + else if (t = mbschr (local_dirname, '`')) /* XXX */ + should_expand_dirname = '`'; + +#if defined (HAVE_LSTAT) + if (should_expand_dirname && lstat (local_dirname, &sb) == 0) +#else + if (should_expand_dirname && stat (local_dirname, &sb) == 0) +#endif + should_expand_dirname = 0; + + if (should_expand_dirname) + { + new_dirname = savestring (local_dirname); + wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* does the right thing */ + if (wl) + { + free (new_dirname); + new_dirname = string_list (wl); + /* Tell the completer we actually expanded something and change + *dirname only if we expanded to something non-null -- stat + behaves unpredictably when passed null or empty strings */ + if (new_dirname && *new_dirname) + { + free (local_dirname); /* XXX */ + local_dirname = *dirname = new_dirname; + return_value = STREQ (local_dirname, *dirname) == 0; + } + else + free (new_dirname); + dispose_words (wl); + } + else + free (new_dirname); + } + + /* This is very similar to the code in bash_directory_completion_hook below, + but without spelling correction and not worrying about whether or not + we change relative pathnames. */ + if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1])) + { + char *temp1, *temp2; + + t = get_working_directory ("symlink-hook"); + temp1 = make_absolute (local_dirname, t); + free (t); + temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + + /* If we can't canonicalize, bail. */ + if (temp2 == 0) + { + free (temp1); + return return_value; + } + + free (local_dirname); + *dirname = temp2; + free (temp1); + } + + return (return_value); +} + +/* Handle symbolic link references and other directory name + expansions while hacking completion. This should return 1 if it modifies + the DIRNAME argument, 0 otherwise. It should make sure not to modify + DIRNAME if it returns 0. */ +static int +bash_directory_completion_hook (dirname) + char **dirname; +{ + char *local_dirname, *new_dirname, *t; + int return_value, should_expand_dirname, nextch, closer; + WORD_LIST *wl; + struct stat sb; + + return_value = should_expand_dirname = nextch = closer = 0; + local_dirname = *dirname; + + if (t = mbschr (local_dirname, '$')) + { + should_expand_dirname = '$'; + nextch = t[1]; + /* Deliberately does not handle the deprecated $[...] arithmetic + expansion syntax */ + if (nextch == '(') + closer = ')'; + else if (nextch == '{') + closer = '}'; + else + nextch = 0; + } + else if (local_dirname[0] == '~') + should_expand_dirname = '~'; + else + { + t = mbschr (local_dirname, '`'); + if (t && unclosed_pair (local_dirname, strlen (local_dirname), "`") == 0) + should_expand_dirname = '`'; + } + +#if defined (HAVE_LSTAT) + if (should_expand_dirname && lstat (local_dirname, &sb) == 0) +#else + if (should_expand_dirname && stat (local_dirname, &sb) == 0) +#endif + should_expand_dirname = 0; + + if (should_expand_dirname) + { + new_dirname = savestring (local_dirname); + wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* does the right thing */ + if (wl) + { + *dirname = string_list (wl); + /* Tell the completer to replace the directory name only if we + actually expanded something. */ + return_value = STREQ (local_dirname, *dirname) == 0; + free (local_dirname); + free (new_dirname); + dispose_words (wl); + local_dirname = *dirname; + /* XXX - change rl_filename_quote_characters here based on + should_expand_dirname/nextch/closer. This is the only place + custom_filename_quote_characters is modified. */ + if (rl_filename_quote_characters && *rl_filename_quote_characters) + { + int i, j, c; + i = strlen (default_filename_quote_characters); + custom_filename_quote_characters = xrealloc (custom_filename_quote_characters, i+1); + for (i = j = 0; c = default_filename_quote_characters[i]; i++) + { + if (c == should_expand_dirname || c == nextch || c == closer) + continue; + custom_filename_quote_characters[j++] = c; + } + custom_filename_quote_characters[j] = '\0'; + rl_filename_quote_characters = custom_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + } + } + else + { + free (new_dirname); + free (local_dirname); + *dirname = (char *)xmalloc (1); + **dirname = '\0'; + return 1; + } + } + else + { + /* Dequote the filename even if we don't expand it. */ + new_dirname = bash_dequote_filename (local_dirname, rl_completion_quote_character); + return_value = STREQ (local_dirname, new_dirname) == 0; + free (local_dirname); + local_dirname = *dirname = new_dirname; + } + + /* no_symbolic_links == 0 -> use (default) logical view of the file system. + local_dirname[0] == '.' && local_dirname[1] == '/' means files in the + current directory (./). + local_dirname[0] == '.' && local_dirname[1] == 0 means relative pathnames + in the current directory (e.g., lib/sh). + XXX - should we do spelling correction on these? */ + + /* This is test as it was in bash-4.2: skip relative pathnames in current + directory. Change test to + (local_dirname[0] != '.' || (local_dirname[1] && local_dirname[1] != '/')) + if we want to skip paths beginning with ./ also. */ + if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1])) + { + char *temp1, *temp2; + int len1, len2; + + /* If we have a relative path + (local_dirname[0] != '/' && local_dirname[0] != '.') + that is canonical after appending it to the current directory, then + temp1 = temp2+'/' + That is, + strcmp (temp1, temp2) == 0 + after adding a slash to temp2 below. It should be safe to not + change those. + */ + t = get_working_directory ("symlink-hook"); + temp1 = make_absolute (local_dirname, t); + free (t); + temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + + /* Try spelling correction if initial canonicalization fails. Make + sure we are set to replace the directory name with the results so + subsequent directory checks don't fail. */ + if (temp2 == 0 && dircomplete_spelling && dircomplete_expand) + { + temp2 = dirspell (temp1); + if (temp2) + { + free (temp1); + temp1 = temp2; + temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + return_value |= temp2 != 0; + } + } + /* If we can't canonicalize, bail. */ + if (temp2 == 0) + { + free (temp1); + return return_value; + } + len1 = strlen (temp1); + if (temp1[len1 - 1] == '/') + { + len2 = strlen (temp2); + if (len2 > 2) /* don't append `/' to `/' or `//' */ + { + temp2 = (char *)xrealloc (temp2, len2 + 2); + temp2[len2] = '/'; + temp2[len2 + 1] = '\0'; + } + } + + /* dircomplete_expand_relpath == 0 means we want to leave relative + pathnames that are unchanged by canonicalization alone. + *local_dirname != '/' && *local_dirname != '.' == relative pathname + (consistent with general.c:absolute_pathname()) + temp1 == temp2 (after appending a slash to temp2) means the pathname + is not changed by canonicalization as described above. */ + if (dircomplete_expand_relpath || ((local_dirname[0] != '/' && local_dirname[0] != '.') && STREQ (temp1, temp2) == 0)) + return_value |= STREQ (local_dirname, temp2) == 0; + free (local_dirname); + *dirname = temp2; + free (temp1); + } + + return (return_value); +} + +static char **history_completion_array = (char **)NULL; +static int harry_size; +static int harry_len; + +static void +build_history_completion_array () +{ + register int i, j; + HIST_ENTRY **hlist; + char **tokens; + + /* First, clear out the current dynamic history completion list. */ + if (harry_size) + { + strvec_dispose (history_completion_array); + history_completion_array = (char **)NULL; + harry_size = 0; + harry_len = 0; + } + + /* Next, grovel each line of history, making each shell-sized token + a separate entry in the history_completion_array. */ + hlist = history_list (); + + if (hlist) + { + for (i = 0; hlist[i]; i++) + ; + for ( --i; i >= 0; i--) + { + /* Separate each token, and place into an array. */ + tokens = history_tokenize (hlist[i]->line); + + for (j = 0; tokens && tokens[j]; j++) + { + if (harry_len + 2 > harry_size) + history_completion_array = strvec_resize (history_completion_array, harry_size += 10); + + history_completion_array[harry_len++] = tokens[j]; + history_completion_array[harry_len] = (char *)NULL; + } + free (tokens); + } + + /* Sort the complete list of tokens. */ + if (dabbrev_expand_active == 0) + qsort (history_completion_array, harry_len, sizeof (char *), (QSFUNC *)strvec_strcmp); + } +} + +static char * +history_completion_generator (hint_text, state) + const char *hint_text; + int state; +{ + static int local_index, len; + static const char *text; + + /* If this is the first call to the generator, then initialize the + list of strings to complete over. */ + if (state == 0) + { + if (dabbrev_expand_active) /* This is kind of messy */ + rl_completion_suppress_append = 1; + local_index = 0; + build_history_completion_array (); + text = hint_text; + len = strlen (text); + } + + while (history_completion_array && history_completion_array[local_index]) + { + if (strncmp (text, history_completion_array[local_index++], len) == 0) + return (savestring (history_completion_array[local_index - 1])); + } + return ((char *)NULL); +} + +static int +dynamic_complete_history (count, key) + int count, key; +{ + int r; + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_compignore_func_t *orig_ignore_func; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + + rl_completion_entry_function = history_completion_generator; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + + /* XXX - use rl_completion_mode here? */ + if (rl_last_func == dynamic_complete_history) + r = rl_complete_internal ('?'); + else + r = rl_complete_internal (TAB); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + + return r; +} + +static int +bash_dabbrev_expand (count, key) + int count, key; +{ + int r, orig_suppress, orig_sort; + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_compignore_func_t *orig_ignore_func; + + orig_func = rl_menu_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + orig_suppress = rl_completion_suppress_append; + orig_sort = rl_sort_completion_matches; + + rl_menu_completion_entry_function = history_completion_generator; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + rl_filename_completion_desired = 0; + rl_completion_suppress_append = 1; + rl_sort_completion_matches = 0; + + /* XXX - use rl_completion_mode here? */ + dabbrev_expand_active = 1; + if (rl_last_func == bash_dabbrev_expand) + rl_last_func = rl_menu_complete; + r = rl_menu_complete (count, key); + dabbrev_expand_active = 0; + + rl_last_func = bash_dabbrev_expand; + rl_menu_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + rl_completion_suppress_append = orig_suppress; + rl_sort_completion_matches = orig_sort; + + return r; +} + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) +static int +bash_complete_username (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_username_internal (rl_completion_mode (bash_complete_username)); +} + +static int +bash_possible_username_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_username_internal ('?'); +} + +static int +bash_complete_username_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, rl_username_completion_function); +} + +static int +bash_complete_filename (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_filename_internal (rl_completion_mode (bash_complete_filename)); +} + +static int +bash_possible_filename_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_filename_internal ('?'); +} + +static int +bash_complete_filename_internal (what_to_do) + int what_to_do; +{ + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_icppfunc_t *orig_dir_func; + rl_compignore_func_t *orig_ignore_func; + /*const*/ char *orig_rl_completer_word_break_characters; + int r; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + orig_rl_completer_word_break_characters = rl_completer_word_break_characters; + + orig_dir_func = save_directory_hook (); + + rl_completion_entry_function = rl_filename_completion_function; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + rl_completer_word_break_characters = " \t\n\"\'"; + + r = rl_complete_internal (what_to_do); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + rl_completer_word_break_characters = orig_rl_completer_word_break_characters; + + restore_directory_hook (orig_dir_func); + + return r; +} + +static int +bash_complete_hostname (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_hostname_internal (rl_completion_mode (bash_complete_hostname)); +} + +static int +bash_possible_hostname_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_hostname_internal ('?'); +} + +static int +bash_complete_variable (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_variable_internal (rl_completion_mode (bash_complete_variable)); +} + +static int +bash_possible_variable_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_variable_internal ('?'); +} + +static int +bash_complete_command (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_command_internal (rl_completion_mode (bash_complete_command)); +} + +static int +bash_possible_command_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_command_internal ('?'); +} + +static int +bash_complete_hostname_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, hostname_completion_function); +} + +static int +bash_complete_variable_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, variable_completion_function); +} + +static int +bash_complete_command_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, command_word_completion_function); +} + +static char *globtext; +static char *globorig; + +static char * +glob_complete_word (text, state) + const char *text; + int state; +{ + static char **matches = (char **)NULL; + static int ind; + int glen; + char *ret, *ttext; + + if (state == 0) + { + rl_filename_completion_desired = 1; + FREE (matches); + if (globorig != globtext) + FREE (globorig); + FREE (globtext); + + ttext = bash_tilde_expand (text, 0); + + if (rl_explicit_arg) + { + globorig = savestring (ttext); + glen = strlen (ttext); + globtext = (char *)xmalloc (glen + 2); + strcpy (globtext, ttext); + globtext[glen] = '*'; + globtext[glen+1] = '\0'; + } + else + globtext = globorig = savestring (ttext); + + if (ttext != text) + free (ttext); + + matches = shell_glob_filename (globtext); + if (GLOB_FAILED (matches)) + matches = (char **)NULL; + ind = 0; + } + + ret = matches ? matches[ind] : (char *)NULL; + ind++; + return ret; +} + +static int +bash_glob_completion_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, glob_complete_word); +} + +/* A special quoting function so we don't end up quoting globbing characters + in the word if there are no matches or multiple matches. */ +static char * +bash_glob_quote_filename (s, rtype, qcp) + char *s; + int rtype; + char *qcp; +{ + if (globorig && qcp && *qcp == '\0' && STREQ (s, globorig)) + return (savestring (s)); + else + return (bash_quote_filename (s, rtype, qcp)); +} + +static int +bash_glob_complete_word (count, key) + int count, key; +{ + int r; + rl_quote_func_t *orig_quoting_function; + + if (rl_editing_mode == EMACS_EDITING_MODE) + rl_explicit_arg = 1; /* force `*' append */ + orig_quoting_function = rl_filename_quoting_function; + rl_filename_quoting_function = bash_glob_quote_filename; + + r = bash_glob_completion_internal (rl_completion_mode (bash_glob_complete_word)); + + rl_filename_quoting_function = orig_quoting_function; + return r; +} + +static int +bash_glob_expand_word (count, key) + int count, key; +{ + return bash_glob_completion_internal ('*'); +} + +static int +bash_glob_list_expansions (count, key) + int count, key; +{ + return bash_glob_completion_internal ('?'); +} + +static int +bash_specific_completion (what_to_do, generator) + int what_to_do; + rl_compentry_func_t *generator; +{ + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_compignore_func_t *orig_ignore_func; + int r; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + rl_completion_entry_function = generator; + rl_attempted_completion_function = NULL; + rl_ignore_some_completions_function = orig_ignore_func; + + r = rl_complete_internal (what_to_do); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + + return r; +} + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + +#if defined (VI_MODE) +/* Completion, from vi mode's point of view. This is a modified version of + rl_vi_complete which uses the bash globbing code to implement what POSIX + specifies, which is to append a `*' and attempt filename generation (which + has the side effect of expanding any globbing characters in the word). */ +static int +bash_vi_complete (count, key) + int count, key; +{ +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + int p, r; + char *t; + + if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) + { + if (!whitespace (rl_line_buffer[rl_point + 1])) + rl_vi_end_word (1, 'E'); + rl_point++; + } + + /* Find boundaries of current word, according to vi definition of a + `bigword'. */ + t = 0; + if (rl_point > 0) + { + p = rl_point; + rl_vi_bWord (1, 'B'); + r = rl_point; + rl_point = p; + p = r; + + t = substring (rl_line_buffer, p, rl_point); + } + + if (t && glob_pattern_p (t) == 0) + rl_explicit_arg = 1; /* XXX - force glob_complete_word to append `*' */ + FREE (t); + + if (key == '*') /* Expansion and replacement. */ + r = bash_glob_expand_word (count, key); + else if (key == '=') /* List possible completions. */ + r = bash_glob_list_expansions (count, key); + else if (key == '\\') /* Standard completion */ + r = bash_glob_complete_word (count, key); + else + r = rl_complete (0, key); + + if (key == '*' || key == '\\') + rl_vi_start_inserting (key, 1, 1); + + return (r); +#else + return rl_vi_complete (count, key); +#endif /* !SPECIFIC_COMPLETION_FUNCTIONS */ +} +#endif /* VI_MODE */ + +/* Filename quoting for completion. */ +/* A function to strip unquoted quote characters (single quotes, double + quotes, and backslashes). It allows single quotes to appear + within double quotes, and vice versa. It should be smarter. */ +static char * +bash_dequote_filename (text, quote_char) + char *text; + int quote_char; +{ + char *ret, *p, *r; + int l, quoted; + + l = strlen (text); + ret = (char *)xmalloc (l + 1); + for (quoted = quote_char, p = text, r = ret; p && *p; p++) + { + /* Allow backslash-escaped characters to pass through unscathed. */ + if (*p == '\\') + { + /* Backslashes are preserved within single quotes. */ + if (quoted == '\'') + *r++ = *p; + /* Backslashes are preserved within double quotes unless the + character is one that is defined to be escaped */ + else if (quoted == '"' && ((sh_syntaxtab[p[1]] & CBSDQUOTE) == 0)) + *r++ = *p; + + *r++ = *++p; + if (*p == '\0') + return ret; /* XXX - was break; */ + continue; + } + /* Close quote. */ + if (quoted && *p == quoted) + { + quoted = 0; + continue; + } + /* Open quote. */ + if (quoted == 0 && (*p == '\'' || *p == '"')) + { + quoted = *p; + continue; + } + *r++ = *p; + } + *r = '\0'; + return ret; +} + +/* Quote characters that the readline completion code would treat as + word break characters with backslashes. Pass backslash-quoted + characters through without examination. */ +static char * +quote_word_break_chars (text) + char *text; +{ + char *ret, *r, *s; + int l; + + l = strlen (text); + ret = (char *)xmalloc ((2 * l) + 1); + for (s = text, r = ret; *s; s++) + { + /* Pass backslash-quoted characters through, including the backslash. */ + if (*s == '\\') + { + *r++ = '\\'; + *r++ = *++s; + if (*s == '\0') + break; + continue; + } + /* OK, we have an unquoted character. Check its presence in + rl_completer_word_break_characters. */ + if (mbschr (rl_completer_word_break_characters, *s)) + *r++ = '\\'; + /* XXX -- check for standalone tildes here and backslash-quote them */ + if (s == text && *s == '~' && file_exists (text)) + *r++ = '\\'; + *r++ = *s; + } + *r = '\0'; + return ret; +} + +/* Use characters in STRING to populate the table of characters that should + be backslash-quoted. The table will be used for sh_backslash_quote from + this file. */ +static void +set_filename_bstab (string) + const char *string; +{ + const char *s; + + memset (filename_bstab, 0, sizeof (filename_bstab)); + for (s = string; s && *s; s++) + filename_bstab[*s] = 1; +} + +/* Quote a filename using double quotes, single quotes, or backslashes + depending on the value of completion_quoting_style. If we're + completing using backslashes, we need to quote some additional + characters (those that readline treats as word breaks), so we call + quote_word_break_chars on the result. This returns newly-allocated + memory. */ +static char * +bash_quote_filename (s, rtype, qcp) + char *s; + int rtype; + char *qcp; +{ + char *rtext, *mtext, *ret; + int rlen, cs; + + rtext = (char *)NULL; + + /* If RTYPE == MULT_MATCH, it means that there is + more than one match. In this case, we do not add + the closing quote or attempt to perform tilde + expansion. If RTYPE == SINGLE_MATCH, we try + to perform tilde expansion, because single and double + quotes inhibit tilde expansion by the shell. */ + + cs = completion_quoting_style; + /* Might need to modify the default completion style based on *qcp, + since it's set to any user-provided opening quote. We also change + to single-quoting if there is no user-provided opening quote and + the word being completed contains newlines, since those are not + quoted correctly using backslashes (a backslash-newline pair is + special to the shell parser). */ + if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && mbschr (s, '\n')) + cs = COMPLETE_SQUOTE; + else if (*qcp == '"') + cs = COMPLETE_DQUOTE; + else if (*qcp == '\'') + cs = COMPLETE_SQUOTE; +#if defined (BANG_HISTORY) + else if (*qcp == '\0' && history_expansion && cs == COMPLETE_DQUOTE && + history_expansion_inhibited == 0 && mbschr (s, '!')) + cs = COMPLETE_BSQUOTE; + + if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && + history_expansion_inhibited == 0 && mbschr (s, '!')) + { + cs = COMPLETE_BSQUOTE; + *qcp = '\0'; + } +#endif + + /* Don't tilde-expand backslash-quoted filenames, since only single and + double quotes inhibit tilde expansion. */ + mtext = s; + if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) + mtext = bash_tilde_expand (s, 0); + + switch (cs) + { + case COMPLETE_DQUOTE: + rtext = sh_double_quote (mtext); + break; + case COMPLETE_SQUOTE: + rtext = sh_single_quote (mtext); + break; + case COMPLETE_BSQUOTE: + rtext = sh_backslash_quote (mtext, complete_fullquote ? 0 : filename_bstab, 0); + break; + } + + if (mtext != s) + free (mtext); + + /* We may need to quote additional characters: those that readline treats + as word breaks that are not quoted by backslash_quote. */ + if (rtext && cs == COMPLETE_BSQUOTE) + { + mtext = quote_word_break_chars (rtext); + free (rtext); + rtext = mtext; + } + + /* Leave the opening quote intact. The readline completion code takes + care of avoiding doubled opening quotes. */ + if (rtext) + { + rlen = strlen (rtext); + ret = (char *)xmalloc (rlen + 1); + strcpy (ret, rtext); + } + else + { + ret = (char *)xmalloc (rlen = 1); + ret[0] = '\0'; + } + + /* If there are multiple matches, cut off the closing quote. */ + if (rtype == MULT_MATCH && cs != COMPLETE_BSQUOTE) + ret[rlen - 1] = '\0'; + free (rtext); + return ret; +} + +/* Support for binding readline key sequences to Unix commands. */ +static Keymap cmd_xmap; + +#ifdef _MINIX +static void +#else +static int +#endif +putx(c) + int c; +{ + int x; + x = putc (c, rl_outstream); +#ifndef _MINIX + return x; +#endif +} + +static int +bash_execute_unix_command (count, key) + int count; /* ignored */ + int key; +{ + Keymap ckmap; /* current keymap */ + Keymap xkmap; /* unix command executing keymap */ + rl_command_func_t *func; + int type; + register int i, r; + intmax_t mi; + sh_parser_state_t ps; + char *cmd, *value, *l, *l1, *ce; + SHELL_VAR *v; + char ibuf[INT_STRLEN_BOUND(int) + 1]; + + /* First, we need to find the right command to execute. This is tricky, + because we might have already indirected into another keymap, so we + have to walk cmd_xmap using the entire key sequence. */ + cmd = (char *)rl_function_of_keyseq (rl_executing_keyseq, cmd_xmap, &type); + + if (cmd == 0 || type != ISMACR) + { + rl_crlf (); + internal_error (_("bash_execute_unix_command: cannot find keymap for command")); + rl_forced_update_display (); + return 1; + } + + ce = rl_get_termcap ("ce"); + if (ce) /* clear current line */ + { + fprintf (rl_outstream, "\r"); + tputs (ce, 1, putx); + fflush (rl_outstream); + } + else + rl_crlf (); /* move to a new line */ + + v = bind_variable ("READLINE_LINE", rl_line_buffer, 0); + if (v) + VSETATTR (v, att_exported); + l = v ? value_cell (v) : 0; + value = inttostr (rl_point, ibuf, sizeof (ibuf)); + v = bind_int_variable ("READLINE_POINT", value); + if (v) + VSETATTR (v, att_exported); + array_needs_making = 1; + + save_parser_state (&ps); + r = parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE); + restore_parser_state (&ps); + + v = find_variable ("READLINE_LINE"); + l1 = v ? value_cell (v) : 0; + if (l1 != l) + maybe_make_readline_line (value_cell (v)); + v = find_variable ("READLINE_POINT"); + if (v && legal_number (value_cell (v), &mi)) + { + i = mi; + if (i != rl_point) + { + rl_point = i; + if (rl_point > rl_end) + rl_point = rl_end; + else if (rl_point < 0) + rl_point = 0; + } + } + + unbind_variable ("READLINE_LINE"); + unbind_variable ("READLINE_POINT"); + array_needs_making = 1; + + /* and restore the readline buffer and display after command execution. */ + rl_forced_update_display (); + return 0; +} + +int +print_unix_command_map () +{ + Keymap save; + + save = rl_get_keymap (); + rl_set_keymap (cmd_xmap); + rl_macro_dumper (1); + rl_set_keymap (save); + return 0; +} + +static void +init_unix_command_map () +{ + cmd_xmap = rl_make_bare_keymap (); +} + +static int +isolate_sequence (string, ind, need_dquote, startp) + char *string; + int ind, need_dquote, *startp; +{ + register int i; + int c, passc, delim; + + for (i = ind; string[i] && whitespace (string[i]); i++) + ; + /* NEED_DQUOTE means that the first non-white character *must* be `"'. */ + if (need_dquote && string[i] != '"') + { + builtin_error (_("%s: first non-whitespace character is not `\"'"), string); + return -1; + } + + /* We can have delimited strings even if NEED_DQUOTE == 0, like the command + string to bind the key sequence to. */ + delim = (string[i] == '"' || string[i] == '\'') ? string[i] : 0; + + if (startp) + *startp = delim ? ++i : i; + + for (passc = 0; c = string[i]; i++) + { + if (passc) + { + passc = 0; + continue; + } + if (c == '\\') + { + passc++; + continue; + } + if (c == delim) + break; + } + + if (delim && string[i] != delim) + { + builtin_error (_("no closing `%c' in %s"), delim, string); + return -1; + } + + return i; +} + +int +bind_keyseq_to_unix_command (line) + char *line; +{ + Keymap kmap; + char *kseq, *value; + int i, kstart; + + if (cmd_xmap == 0) + init_unix_command_map (); + + kmap = rl_get_keymap (); + + /* We duplicate some of the work done by rl_parse_and_bind here, but + this code only has to handle `"keyseq": ["]command["]' and can + generate an error for anything else. */ + i = isolate_sequence (line, 0, 1, &kstart); + if (i < 0) + return -1; + + /* Create the key sequence string to pass to rl_generic_bind */ + kseq = substring (line, kstart, i); + + for ( ; line[i] && line[i] != ':'; i++) + ; + if (line[i] != ':') + { + builtin_error (_("%s: missing colon separator"), line); + FREE (kseq); + return -1; + } + + i = isolate_sequence (line, i + 1, 0, &kstart); + if (i < 0) + { + FREE (kseq); + return -1; + } + + /* Create the value string containing the command to execute. */ + value = substring (line, kstart, i); + + /* Save the command to execute and the key sequence in the CMD_XMAP */ + rl_generic_bind (ISMACR, kseq, value, cmd_xmap); + + /* and bind the key sequence in the current keymap to a function that + understands how to execute from CMD_XMAP */ + rl_bind_keyseq_in_map (kseq, bash_execute_unix_command, kmap); + + free (kseq); + return 0; +} + +/* Used by the programmable completion code. Complete TEXT as a filename, + but return only directories as matches. Dequotes the filename before + attempting to find matches. */ +char ** +bash_directory_completion_matches (text) + const char *text; +{ + char **m1; + char *dfn; + int qc; + + qc = rl_dispatching ? rl_completion_quote_character : 0; + dfn = bash_dequote_filename ((char *)text, qc); + m1 = rl_completion_matches (dfn, rl_filename_completion_function); + free (dfn); + + if (m1 == 0 || m1[0] == 0) + return m1; + /* We don't bother recomputing the lcd of the matches, because it will just + get thrown away by the programmable completion code and recomputed + later. */ + (void)bash_ignore_filenames (m1); + return m1; +} + +char * +bash_dequote_text (text) + const char *text; +{ + char *dtxt; + int qc; + + qc = (text[0] == '"' || text[0] == '\'') ? text[0] : 0; + dtxt = bash_dequote_filename ((char *)text, qc); + return (dtxt); +} + +/* This event hook is designed to be called after readline receives a signal + that interrupts read(2). It gives reasonable responsiveness to interrupts + and fatal signals without executing too much code in a signal handler + context. */ +static int +bash_event_hook () +{ + /* If we're going to longjmp to top_level, make sure we clean up readline */ + if (interrupt_state && signal_is_trapped (SIGINT) == 0) + rl_cleanup_after_signal (); + + bashline_reset_event_hook (); + check_signals_and_traps (); /* XXX */ +} + +#endif /* READLINE */ diff --git a/bashline.c~ b/bashline.c~ new file mode 100644 index 000000000..8dd15e1a6 --- /dev/null +++ b/bashline.c~ @@ -0,0 +1,4181 @@ +/* bashline.c -- Bash's interface to the readline library. */ + +/* Copyright (C) 1987-2013 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bash. If not, see . +*/ + +#include "config.h" + +#if defined (READLINE) + +#include "bashtypes.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#if defined (HAVE_GRP_H) +# include +#endif + +#if defined (HAVE_NETDB_H) +# include +#endif + +#include + +#include +#include "chartypes.h" +#include "bashansi.h" +#include "bashintl.h" + +#include "shell.h" +#include "input.h" +#include "builtins.h" +#include "bashhist.h" +#include "bashline.h" +#include "execute_cmd.h" +#include "findcmd.h" +#include "pathexp.h" +#include "shmbutil.h" + +#include "builtins/common.h" + +#include +#include +#include + +#include + +#if defined (ALIAS) +# include "alias.h" +#endif + +#if defined (PROGRAMMABLE_COMPLETION) +# include "pcomplete.h" +#endif + +/* These should agree with the defines for emacs_mode and vi_mode in + rldefs.h, even though that's not a public readline header file. */ +#ifndef EMACS_EDITING_MODE +# define NO_EDITING_MODE -1 +# define EMACS_EDITING_MODE 1 +# define VI_EDITING_MODE 0 +#endif + +#define RL_BOOLEAN_VARIABLE_VALUE(s) ((s)[0] == 'o' && (s)[1] == 'n' && (s)[2] == '\0') + +#if defined (BRACE_COMPLETION) +extern int bash_brace_completion __P((int, int)); +#endif /* BRACE_COMPLETION */ + +/* To avoid including curses.h/term.h/termcap.h and that whole mess. */ +#ifdef _MINIX +extern int tputs __P((const char *string, int nlines, void (*outx)(int))); +#else +extern int tputs __P((const char *string, int nlines, int (*outx)(int))); +#endif + +/* Forward declarations */ + +/* Functions bound to keys in Readline for Bash users. */ +static int shell_expand_line __P((int, int)); +static int display_shell_version __P((int, int)); +static int operate_and_get_next __P((int, int)); + +static int bash_ignore_filenames __P((char **)); +static int bash_ignore_everything __P((char **)); + +#if defined (BANG_HISTORY) +static char *history_expand_line_internal __P((char *)); +static int history_expand_line __P((int, int)); +static int tcsh_magic_space __P((int, int)); +#endif /* BANG_HISTORY */ +#ifdef ALIAS +static int alias_expand_line __P((int, int)); +#endif +#if defined (BANG_HISTORY) && defined (ALIAS) +static int history_and_alias_expand_line __P((int, int)); +#endif + +static int bash_forward_shellword __P((int, int)); +static int bash_backward_shellword __P((int, int)); +static int bash_kill_shellword __P((int, int)); +static int bash_backward_kill_shellword __P((int, int)); + +/* Helper functions for Readline. */ +static char *restore_tilde __P((char *, char *)); + +static char *bash_filename_rewrite_hook __P((char *, int)); + +static void bash_directory_expansion __P((char **)); +static int bash_filename_stat_hook __P((char **)); +static int bash_command_name_stat_hook __P((char **)); +static int bash_directory_completion_hook __P((char **)); +static int filename_completion_ignore __P((char **)); +static int bash_push_line __P((void)); + +static int executable_completion __P((const char *, int)); + +static rl_icppfunc_t *save_directory_hook __P((void)); +static void restore_directory_hook __P((rl_icppfunc_t)); + +static void cleanup_expansion_error __P((void)); +static void maybe_make_readline_line __P((char *)); +static void set_up_new_line __P((char *)); + +static int check_redir __P((int)); +static char **attempt_shell_completion __P((const char *, int, int)); +static char *variable_completion_function __P((const char *, int)); +static char *hostname_completion_function __P((const char *, int)); +static char *command_subst_completion_function __P((const char *, int)); + +static void build_history_completion_array __P((void)); +static char *history_completion_generator __P((const char *, int)); +static int dynamic_complete_history __P((int, int)); +static int bash_dabbrev_expand __P((int, int)); + +static void initialize_hostname_list __P((void)); +static void add_host_name __P((char *)); +static void snarf_hosts_from_file __P((char *)); +static char **hostnames_matching __P((char *)); + +static void _ignore_completion_names __P((char **, sh_ignore_func_t *)); +static int name_is_acceptable __P((const char *)); +static int test_for_directory __P((const char *)); +static int return_zero __P((const char *)); + +static char *bash_dequote_filename __P((char *, int)); +static char *quote_word_break_chars __P((char *)); +static void set_filename_bstab __P((const char *)); +static char *bash_quote_filename __P((char *, int, char *)); + +#ifdef _MINIX +static void putx __P((int)); +#else +static int putx __P((int)); +#endif +static int bash_execute_unix_command __P((int, int)); +static void init_unix_command_map __P((void)); +static int isolate_sequence __P((char *, int, int, int *)); + +static int set_saved_history __P((void)); + +#if defined (ALIAS) +static int posix_edit_macros __P((int, int)); +#endif + +static int bash_event_hook __P((void)); + +#if defined (PROGRAMMABLE_COMPLETION) +static int find_cmd_start __P((int)); +static int find_cmd_end __P((int)); +static char *find_cmd_name __P((int, int *, int *)); +static char *prog_complete_return __P((const char *, int)); + +static char **prog_complete_matches; +#endif + +/* Variables used here but defined in other files. */ +#if defined (BANG_HISTORY) +extern int hist_verify; +#endif + +extern int current_command_line_count, saved_command_line_count; +extern int last_command_exit_value; +extern int array_needs_making; +extern int posixly_correct, no_symbolic_links; +extern char *current_prompt_string, *ps1_prompt; +extern STRING_INT_ALIST word_token_alist[]; +extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin; + +/* SPECIFIC_COMPLETION_FUNCTIONS specifies that we have individual + completion functions which indicate what type of completion should be + done (at or before point) that can be bound to key sequences with + the readline library. */ +#define SPECIFIC_COMPLETION_FUNCTIONS + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) +static int bash_specific_completion __P((int, rl_compentry_func_t *)); + +static int bash_complete_filename_internal __P((int)); +static int bash_complete_username_internal __P((int)); +static int bash_complete_hostname_internal __P((int)); +static int bash_complete_variable_internal __P((int)); +static int bash_complete_command_internal __P((int)); + +static int bash_complete_filename __P((int, int)); +static int bash_possible_filename_completions __P((int, int)); +static int bash_complete_username __P((int, int)); +static int bash_possible_username_completions __P((int, int)); +static int bash_complete_hostname __P((int, int)); +static int bash_possible_hostname_completions __P((int, int)); +static int bash_complete_variable __P((int, int)); +static int bash_possible_variable_completions __P((int, int)); +static int bash_complete_command __P((int, int)); +static int bash_possible_command_completions __P((int, int)); + +static char *glob_complete_word __P((const char *, int)); +static int bash_glob_completion_internal __P((int)); +static int bash_glob_complete_word __P((int, int)); +static int bash_glob_expand_word __P((int, int)); +static int bash_glob_list_expansions __P((int, int)); + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + +static int edit_and_execute_command __P((int, int, int, char *)); +#if defined (VI_MODE) +static int vi_edit_and_execute_command __P((int, int)); +static int bash_vi_complete __P((int, int)); +#endif +static int emacs_edit_and_execute_command __P((int, int)); + +/* Non-zero once initalize_readline () has been called. */ +int bash_readline_initialized = 0; + +/* If non-zero, we do hostname completion, breaking words at `@' and + trying to complete the stuff after the `@' from our own internal + host list. */ +int perform_hostname_completion = 1; + +/* If non-zero, we don't do command completion on an empty line. */ +int no_empty_command_completion; + +/* Set FORCE_FIGNORE if you want to honor FIGNORE even if it ignores the + only possible matches. Set to 0 if you want to match filenames if they + are the only possible matches, even if FIGNORE says to. */ +int force_fignore = 1; + +/* Perform spelling correction on directory names during word completion */ +int dircomplete_spelling = 0; + +/* Expand directory names during word/filename completion. */ +#if DIRCOMPLETE_EXPAND_DEFAULT +int dircomplete_expand = 1; +int dircomplete_expand_relpath = 1; +#else +int dircomplete_expand = 0; +int dircomplete_expand_relpath = 0; +#endif + +/* When non-zero, perform `normal' shell quoting on completed filenames + even when the completed name contains a directory name with a shell + variable referene, so dollar signs in a filename get quoted appropriately. + Set to zero to remove dollar sign (and braces or parens as needed) from + the set of characters that will be quoted. */ +int complete_fullquote = 1; + +static char *bash_completer_word_break_characters = " \t\n\"'@><=;|&(:"; +static char *bash_nohostname_word_break_characters = " \t\n\"'><=;|&(:"; +/* )) */ + +static const char *default_filename_quote_characters = " \t\n\\\"'@<>=;|&()#$`?*[!:{~"; /*}*/ +static char *custom_filename_quote_characters = 0; +static char filename_bstab[256]; + +static rl_hook_func_t *old_rl_startup_hook = (rl_hook_func_t *)NULL; + +static int dot_in_path = 0; + +/* Set to non-zero when dabbrev-expand is running */ +static int dabbrev_expand_active = 0; + +/* What kind of quoting is performed by bash_quote_filename: + COMPLETE_DQUOTE = double-quoting the filename + COMPLETE_SQUOTE = single_quoting the filename + COMPLETE_BSQUOTE = backslash-quoting special chars in the filename +*/ +#define COMPLETE_DQUOTE 1 +#define COMPLETE_SQUOTE 2 +#define COMPLETE_BSQUOTE 3 +static int completion_quoting_style = COMPLETE_BSQUOTE; + +/* Flag values for the final argument to bash_default_completion */ +#define DEFCOMP_CMDPOS 1 + +/* Change the readline VI-mode keymaps into or out of Posix.2 compliance. + Called when the shell is put into or out of `posix' mode. */ +void +posix_readline_initialize (on_or_off) + int on_or_off; +{ + if (on_or_off) + rl_variable_bind ("comment-begin", "#"); +#if defined (VI_MODE) + rl_bind_key_in_map (CTRL ('I'), on_or_off ? rl_insert : rl_complete, vi_insertion_keymap); +#endif +} + +void +reset_completer_word_break_chars () +{ + rl_completer_word_break_characters = perform_hostname_completion ? savestring (bash_completer_word_break_characters) : savestring (bash_nohostname_word_break_characters); +} + +/* When this function returns, rl_completer_word_break_characters points to + dynamically allocated memory. */ +int +enable_hostname_completion (on_or_off) + int on_or_off; +{ + int old_value; + char *at, *nv, *nval; + + old_value = perform_hostname_completion; + + if (on_or_off) + { + perform_hostname_completion = 1; + rl_special_prefixes = "$@"; + } + else + { + perform_hostname_completion = 0; + rl_special_prefixes = "$"; + } + + /* Now we need to figure out how to appropriately modify and assign + rl_completer_word_break_characters depending on whether we want + hostname completion on or off. */ + + /* If this is the first time this has been called + (bash_readline_initialized == 0), use the sames values as before, but + allocate new memory for rl_completer_word_break_characters. */ + + if (bash_readline_initialized == 0 && + (rl_completer_word_break_characters == 0 || + rl_completer_word_break_characters == rl_basic_word_break_characters)) + { + if (on_or_off) + rl_completer_word_break_characters = savestring (bash_completer_word_break_characters); + else + rl_completer_word_break_characters = savestring (bash_nohostname_word_break_characters); + } + else + { + /* See if we have anything to do. */ + at = strchr (rl_completer_word_break_characters, '@'); + if ((at == 0 && on_or_off == 0) || (at != 0 && on_or_off != 0)) + return old_value; + + /* We have something to do. Do it. */ + nval = (char *)xmalloc (strlen (rl_completer_word_break_characters) + 1 + on_or_off); + + if (on_or_off == 0) + { + /* Turn it off -- just remove `@' from word break chars. We want + to remove all occurrences of `@' from the char list, so we loop + rather than just copy the rest of the list over AT. */ + for (nv = nval, at = rl_completer_word_break_characters; *at; ) + if (*at != '@') + *nv++ = *at++; + else + at++; + *nv = '\0'; + } + else + { + nval[0] = '@'; + strcpy (nval + 1, rl_completer_word_break_characters); + } + + free (rl_completer_word_break_characters); + rl_completer_word_break_characters = nval; + } + + return (old_value); +} + +/* Called once from parse.y if we are going to use readline. */ +void +initialize_readline () +{ + rl_command_func_t *func; + char kseq[2]; + + if (bash_readline_initialized) + return; + + rl_terminal_name = get_string_value ("TERM"); + rl_instream = stdin; + rl_outstream = stderr; + + /* Allow conditional parsing of the ~/.inputrc file. */ + rl_readline_name = "Bash"; + + /* Add bindable names before calling rl_initialize so they may be + referenced in the various inputrc files. */ + rl_add_defun ("shell-expand-line", shell_expand_line, -1); +#ifdef BANG_HISTORY + rl_add_defun ("history-expand-line", history_expand_line, -1); + rl_add_defun ("magic-space", tcsh_magic_space, -1); +#endif + + rl_add_defun ("shell-forward-word", bash_forward_shellword, -1); + rl_add_defun ("shell-backward-word", bash_backward_shellword, -1); + rl_add_defun ("shell-kill-word", bash_kill_shellword, -1); + rl_add_defun ("shell-backward-kill-word", bash_backward_kill_shellword, -1); + +#ifdef ALIAS + rl_add_defun ("alias-expand-line", alias_expand_line, -1); +# ifdef BANG_HISTORY + rl_add_defun ("history-and-alias-expand-line", history_and_alias_expand_line, -1); +# endif +#endif + + /* Backwards compatibility. */ + rl_add_defun ("insert-last-argument", rl_yank_last_arg, -1); + + rl_add_defun ("operate-and-get-next", operate_and_get_next, -1); + rl_add_defun ("display-shell-version", display_shell_version, -1); + rl_add_defun ("edit-and-execute-command", emacs_edit_and_execute_command, -1); + +#if defined (BRACE_COMPLETION) + rl_add_defun ("complete-into-braces", bash_brace_completion, -1); +#endif + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + rl_add_defun ("complete-filename", bash_complete_filename, -1); + rl_add_defun ("possible-filename-completions", bash_possible_filename_completions, -1); + rl_add_defun ("complete-username", bash_complete_username, -1); + rl_add_defun ("possible-username-completions", bash_possible_username_completions, -1); + rl_add_defun ("complete-hostname", bash_complete_hostname, -1); + rl_add_defun ("possible-hostname-completions", bash_possible_hostname_completions, -1); + rl_add_defun ("complete-variable", bash_complete_variable, -1); + rl_add_defun ("possible-variable-completions", bash_possible_variable_completions, -1); + rl_add_defun ("complete-command", bash_complete_command, -1); + rl_add_defun ("possible-command-completions", bash_possible_command_completions, -1); + rl_add_defun ("glob-complete-word", bash_glob_complete_word, -1); + rl_add_defun ("glob-expand-word", bash_glob_expand_word, -1); + rl_add_defun ("glob-list-expansions", bash_glob_list_expansions, -1); +#endif + + rl_add_defun ("dynamic-complete-history", dynamic_complete_history, -1); + rl_add_defun ("dabbrev-expand", bash_dabbrev_expand, -1); + + /* Bind defaults before binding our custom shell keybindings. */ + if (RL_ISSTATE(RL_STATE_INITIALIZED) == 0) + rl_initialize (); + + /* Bind up our special shell functions. */ + rl_bind_key_if_unbound_in_map (CTRL('E'), shell_expand_line, emacs_meta_keymap); + +#ifdef BANG_HISTORY + rl_bind_key_if_unbound_in_map ('^', history_expand_line, emacs_meta_keymap); +#endif + + rl_bind_key_if_unbound_in_map (CTRL ('O'), operate_and_get_next, emacs_standard_keymap); + rl_bind_key_if_unbound_in_map (CTRL ('V'), display_shell_version, emacs_ctlx_keymap); + + /* In Bash, the user can switch editing modes with "set -o [vi emacs]", + so it is not necessary to allow C-M-j for context switching. Turn + off this occasionally confusing behaviour. */ + kseq[0] = CTRL('J'); + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == rl_vi_editing_mode) + rl_unbind_key_in_map (CTRL('J'), emacs_meta_keymap); + kseq[0] = CTRL('M'); + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == rl_vi_editing_mode) + rl_unbind_key_in_map (CTRL('M'), emacs_meta_keymap); +#if defined (VI_MODE) + rl_unbind_key_in_map (CTRL('E'), vi_movement_keymap); +#endif + +#if defined (BRACE_COMPLETION) + rl_bind_key_if_unbound_in_map ('{', bash_brace_completion, emacs_meta_keymap); /*}*/ +#endif /* BRACE_COMPLETION */ + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + rl_bind_key_if_unbound_in_map ('/', bash_complete_filename, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('/', bash_possible_filename_completions, emacs_ctlx_keymap); + + /* Have to jump through hoops here because there is a default binding for + M-~ (rl_tilde_expand) */ + kseq[0] = '~'; + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == 0 || func == rl_tilde_expand) + rl_bind_keyseq_in_map (kseq, bash_complete_username, emacs_meta_keymap); + + rl_bind_key_if_unbound_in_map ('~', bash_possible_username_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('@', bash_complete_hostname, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('@', bash_possible_hostname_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('$', bash_complete_variable, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('$', bash_possible_variable_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('!', bash_complete_command, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('!', bash_possible_command_completions, emacs_ctlx_keymap); + + rl_bind_key_if_unbound_in_map ('g', bash_glob_complete_word, emacs_meta_keymap); + rl_bind_key_if_unbound_in_map ('*', bash_glob_expand_word, emacs_ctlx_keymap); + rl_bind_key_if_unbound_in_map ('g', bash_glob_list_expansions, emacs_ctlx_keymap); + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + + kseq[0] = TAB; + kseq[1] = '\0'; + func = rl_function_of_keyseq (kseq, emacs_meta_keymap, (int *)NULL); + if (func == 0 || func == rl_tab_insert) + rl_bind_key_in_map (TAB, dynamic_complete_history, emacs_meta_keymap); + + /* Tell the completer that we want a crack first. */ + rl_attempted_completion_function = attempt_shell_completion; + + /* Tell the completer that we might want to follow symbolic links or + do other expansion on directory names. */ + set_directory_hook (); + + rl_filename_rewrite_hook = bash_filename_rewrite_hook; + + rl_filename_stat_hook = bash_filename_stat_hook; + + /* Tell the filename completer we want a chance to ignore some names. */ + rl_ignore_some_completions_function = filename_completion_ignore; + + /* Bind C-xC-e to invoke emacs and run result as commands. */ + rl_bind_key_if_unbound_in_map (CTRL ('E'), emacs_edit_and_execute_command, emacs_ctlx_keymap); +#if defined (VI_MODE) + rl_bind_key_if_unbound_in_map ('v', vi_edit_and_execute_command, vi_movement_keymap); +# if defined (ALIAS) + rl_bind_key_if_unbound_in_map ('@', posix_edit_macros, vi_movement_keymap); +# endif + + rl_bind_key_in_map ('\\', bash_vi_complete, vi_movement_keymap); + rl_bind_key_in_map ('*', bash_vi_complete, vi_movement_keymap); + rl_bind_key_in_map ('=', bash_vi_complete, vi_movement_keymap); +#endif + + rl_completer_quote_characters = "'\""; + + /* This sets rl_completer_word_break_characters and rl_special_prefixes + to the appropriate values, depending on whether or not hostname + completion is enabled. */ + enable_hostname_completion (perform_hostname_completion); + + /* characters that need to be quoted when appearing in filenames. */ + rl_filename_quote_characters = default_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + + rl_filename_quoting_function = bash_quote_filename; + rl_filename_dequoting_function = bash_dequote_filename; + rl_char_is_quoted_p = char_is_quoted; + +#if 0 + /* This is superfluous and makes it impossible to use tab completion in + vi mode even when explicitly binding it in ~/.inputrc. sv_strict_posix() + should already have called posix_readline_initialize() when + posixly_correct was set. */ + if (posixly_correct) + posix_readline_initialize (1); +#endif + + bash_readline_initialized = 1; +} + +void +bashline_reinitialize () +{ + bash_readline_initialized = 0; +} + +void +bashline_set_event_hook () +{ + rl_signal_event_hook = bash_event_hook; +} + +void +bashline_reset_event_hook () +{ + rl_signal_event_hook = 0; +} + +/* On Sun systems at least, rl_attempted_completion_function can end up + getting set to NULL, and rl_completion_entry_function set to do command + word completion if Bash is interrupted while trying to complete a command + word. This just resets all the completion functions to the right thing. + It's called from throw_to_top_level(). */ +void +bashline_reset () +{ + tilde_initialize (); + rl_attempted_completion_function = attempt_shell_completion; + rl_completion_entry_function = NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + rl_filename_quote_characters = default_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + + set_directory_hook (); + rl_filename_stat_hook = bash_filename_stat_hook; + + bashline_reset_event_hook (); +} + +/* Contains the line to push into readline. */ +static char *push_to_readline = (char *)NULL; + +/* Push the contents of push_to_readline into the + readline buffer. */ +static int +bash_push_line () +{ + if (push_to_readline) + { + rl_insert_text (push_to_readline); + free (push_to_readline); + push_to_readline = (char *)NULL; + rl_startup_hook = old_rl_startup_hook; + } + return 0; +} + +/* Call this to set the initial text for the next line to read + from readline. */ +int +bash_re_edit (line) + char *line; +{ + FREE (push_to_readline); + + push_to_readline = savestring (line); + old_rl_startup_hook = rl_startup_hook; + rl_startup_hook = bash_push_line; + + return (0); +} + +static int +display_shell_version (count, c) + int count, c; +{ + rl_crlf (); + show_shell_version (0); + putc ('\r', rl_outstream); + fflush (rl_outstream); + rl_on_new_line (); + rl_redisplay (); + return 0; +} + +/* **************************************************************** */ +/* */ +/* Readline Stuff */ +/* */ +/* **************************************************************** */ + +/* If the user requests hostname completion, then simply build a list + of hosts, and complete from that forever more, or at least until + HOSTFILE is unset. */ + +/* THIS SHOULD BE A STRINGLIST. */ +/* The kept list of hostnames. */ +static char **hostname_list = (char **)NULL; + +/* The physical size of the above list. */ +static int hostname_list_size; + +/* The number of hostnames in the above list. */ +static int hostname_list_length; + +/* Whether or not HOSTNAME_LIST has been initialized. */ +int hostname_list_initialized = 0; + +/* Initialize the hostname completion table. */ +static void +initialize_hostname_list () +{ + char *temp; + + temp = get_string_value ("HOSTFILE"); + if (temp == 0) + temp = get_string_value ("hostname_completion_file"); + if (temp == 0) + temp = DEFAULT_HOSTS_FILE; + + snarf_hosts_from_file (temp); + + if (hostname_list) + hostname_list_initialized++; +} + +/* Add NAME to the list of hosts. */ +static void +add_host_name (name) + char *name; +{ + if (hostname_list_length + 2 > hostname_list_size) + { + hostname_list_size = (hostname_list_size + 32) - (hostname_list_size % 32); + hostname_list = strvec_resize (hostname_list, hostname_list_size); + } + + hostname_list[hostname_list_length++] = savestring (name); + hostname_list[hostname_list_length] = (char *)NULL; +} + +#define cr_whitespace(c) ((c) == '\r' || (c) == '\n' || whitespace(c)) + +static void +snarf_hosts_from_file (filename) + char *filename; +{ + FILE *file; + char *temp, buffer[256], name[256]; + register int i, start; + + file = fopen (filename, "r"); + if (file == 0) + return; + + while (temp = fgets (buffer, 255, file)) + { + /* Skip to first character. */ + for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++) + ; + + /* If comment or blank line, ignore. */ + if (buffer[i] == '\0' || buffer[i] == '#') + continue; + + /* If `preprocessor' directive, do the include. */ + if (strncmp (buffer + i, "$include ", 9) == 0) + { + char *incfile, *t; + + /* Find start of filename. */ + for (incfile = buffer + i + 9; *incfile && whitespace (*incfile); incfile++) + ; + + /* Find end of filename. */ + for (t = incfile; *t && cr_whitespace (*t) == 0; t++) + ; + + *t = '\0'; + + snarf_hosts_from_file (incfile); + continue; + } + + /* Skip internet address if present. */ + if (DIGIT (buffer[i])) + for (; buffer[i] && cr_whitespace (buffer[i]) == 0; i++); + + /* Gobble up names. Each name is separated with whitespace. */ + while (buffer[i]) + { + for (; cr_whitespace (buffer[i]); i++) + ; + if (buffer[i] == '\0' || buffer[i] == '#') + break; + + /* Isolate the current word. */ + for (start = i; buffer[i] && cr_whitespace (buffer[i]) == 0; i++) + ; + if (i == start) + continue; + strncpy (name, buffer + start, i - start); + name[i - start] = '\0'; + add_host_name (name); + } + } + fclose (file); +} + +/* Return the hostname list. */ +char ** +get_hostname_list () +{ + if (hostname_list_initialized == 0) + initialize_hostname_list (); + return (hostname_list); +} + +void +clear_hostname_list () +{ + register int i; + + if (hostname_list_initialized == 0) + return; + for (i = 0; i < hostname_list_length; i++) + free (hostname_list[i]); + hostname_list_length = hostname_list_initialized = 0; +} + +/* Return a NULL terminated list of hostnames which begin with TEXT. + Initialize the hostname list the first time if neccessary. + The array is malloc ()'ed, but not the individual strings. */ +static char ** +hostnames_matching (text) + char *text; +{ + register int i, len, nmatch, rsize; + char **result; + + if (hostname_list_initialized == 0) + initialize_hostname_list (); + + if (hostname_list_initialized == 0) + return ((char **)NULL); + + /* Special case. If TEXT consists of nothing, then the whole list is + what is desired. */ + if (*text == '\0') + { + result = strvec_create (1 + hostname_list_length); + for (i = 0; i < hostname_list_length; i++) + result[i] = hostname_list[i]; + result[i] = (char *)NULL; + return (result); + } + + /* Scan until found, or failure. */ + len = strlen (text); + result = (char **)NULL; + for (i = nmatch = rsize = 0; i < hostname_list_length; i++) + { + if (STREQN (text, hostname_list[i], len) == 0) + continue; + + /* OK, it matches. Add it to the list. */ + if (nmatch >= (rsize - 1)) + { + rsize = (rsize + 16) - (rsize % 16); + result = strvec_resize (result, rsize); + } + + result[nmatch++] = hostname_list[i]; + } + if (nmatch) + result[nmatch] = (char *)NULL; + return (result); +} + +/* The equivalent of the Korn shell C-o operate-and-get-next-history-line + editing command. */ +static int saved_history_line_to_use = -1; +static int last_saved_history_line = -1; + +#define HISTORY_FULL() (history_is_stifled () && history_length >= history_max_entries) + +static int +set_saved_history () +{ + /* XXX - compensate for assumption that history was `shuffled' if it was + actually not. */ + if (HISTORY_FULL () && + hist_last_line_added == 0 && + saved_history_line_to_use < history_length - 1) + saved_history_line_to_use++; + + if (saved_history_line_to_use >= 0) + { + rl_get_previous_history (history_length - saved_history_line_to_use, 0); + last_saved_history_line = saved_history_line_to_use; + } + saved_history_line_to_use = -1; + rl_startup_hook = old_rl_startup_hook; + return (0); +} + +static int +operate_and_get_next (count, c) + int count, c; +{ + int where; + + /* Accept the current line. */ + rl_newline (1, c); + + /* Find the current line, and find the next line to use. */ + where = where_history (); + + if (HISTORY_FULL () || (where >= history_length - 1)) + saved_history_line_to_use = where; + else + saved_history_line_to_use = where + 1; + + old_rl_startup_hook = rl_startup_hook; + rl_startup_hook = set_saved_history; + + return 0; +} + +/* This vi mode command causes VI_EDIT_COMMAND to be run on the current + command being entered (if no explicit argument is given), otherwise on + a command from the history file. */ + +#define VI_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-vi}}\"" +#define EMACS_EDIT_COMMAND "fc -e \"${VISUAL:-${EDITOR:-emacs}}\"" +#define POSIX_VI_EDIT_COMMAND "fc -e vi" + +static int +edit_and_execute_command (count, c, editing_mode, edit_command) + int count, c, editing_mode; + char *edit_command; +{ + char *command, *metaval; + int r, rrs, metaflag; + sh_parser_state_t ps; + + rrs = rl_readline_state; + saved_command_line_count = current_command_line_count; + + /* Accept the current line. */ + rl_newline (1, c); + + if (rl_explicit_arg) + { + command = (char *)xmalloc (strlen (edit_command) + 8); + sprintf (command, "%s %d", edit_command, count); + } + else + { + /* Take the command we were just editing, add it to the history file, + then call fc to operate on it. We have to add a dummy command to + the end of the history because fc ignores the last command (assumes + it's supposed to deal with the command before the `fc'). */ + /* This breaks down when using command-oriented history and are not + finished with the command, so we should not ignore the last command */ + using_history (); + current_command_line_count++; /* for rl_newline above */ + bash_add_history (rl_line_buffer); + current_command_line_count = 0; /* for dummy history entry */ + bash_add_history (""); + history_lines_this_session++; + using_history (); + command = savestring (edit_command); + } + + metaval = rl_variable_value ("input-meta"); + metaflag = RL_BOOLEAN_VARIABLE_VALUE (metaval); + + /* Now, POSIX.1-2001 and SUSv3 say that the commands executed from the + temporary file should be placed into the history. We don't do that + yet. */ + if (rl_deprep_term_function) + (*rl_deprep_term_function) (); + save_parser_state (&ps); + r = parse_and_execute (command, (editing_mode == VI_EDITING_MODE) ? "v" : "C-xC-e", SEVAL_NOHIST); + restore_parser_state (&ps); + if (rl_prep_term_function) + (*rl_prep_term_function) (metaflag); + + current_command_line_count = saved_command_line_count; + + /* Now erase the contents of the current line and undo the effects of the + rl_accept_line() above. We don't even want to make the text we just + executed available for undoing. */ + rl_line_buffer[0] = '\0'; /* XXX */ + rl_point = rl_end = 0; + rl_done = 0; + rl_readline_state = rrs; + + rl_forced_update_display (); + + return r; +} + +#if defined (VI_MODE) +static int +vi_edit_and_execute_command (count, c) + int count, c; +{ + if (posixly_correct) + return (edit_and_execute_command (count, c, VI_EDITING_MODE, POSIX_VI_EDIT_COMMAND)); + else + return (edit_and_execute_command (count, c, VI_EDITING_MODE, VI_EDIT_COMMAND)); +} +#endif /* VI_MODE */ + +static int +emacs_edit_and_execute_command (count, c) + int count, c; +{ + return (edit_and_execute_command (count, c, EMACS_EDITING_MODE, EMACS_EDIT_COMMAND)); +} + +#if defined (ALIAS) +static int +posix_edit_macros (count, key) + int count, key; +{ + int c; + char alias_name[3], *alias_value, *macro; + + c = rl_read_key (); + alias_name[0] = '_'; + alias_name[1] = c; + alias_name[2] = '\0'; + + alias_value = get_alias_value (alias_name); + if (alias_value && *alias_value) + { + macro = savestring (alias_value); + rl_push_macro_input (macro); + } + return 0; +} +#endif + +/* Bindable commands that move `shell-words': that is, sequences of + non-unquoted-metacharacters. */ + +#define WORDDELIM(c) (shellmeta(c) || shellblank(c)) + +static int +bash_forward_shellword (count, key) + int count, key; +{ + size_t slen; + int sindex, c, p; + DECLARE_MBSTATE; + + if (count < 0) + return (bash_backward_shellword (-count, key)); + + /* The tricky part of this is deciding whether or not the first character + we're on is an unquoted metacharacter. Not completely handled yet. */ + /* XXX - need to test this stuff with backslash-escaped shell + metacharacters and unclosed single- and double-quoted strings. */ + + p = rl_point; + slen = rl_end; + + while (count) + { + if (p == rl_end) + { + rl_point = rl_end; + return 0; + } + + /* Are we in a quoted string? If we are, move to the end of the quoted + string and continue the outer loop. We only want quoted strings, not + backslash-escaped characters, but char_is_quoted doesn't + differentiate. */ + if (char_is_quoted (rl_line_buffer, p) && p > 0 && rl_line_buffer[p-1] != '\\') + { + do + ADVANCE_CHAR (rl_line_buffer, slen, p); + while (p < rl_end && char_is_quoted (rl_line_buffer, p)); + count--; + continue; + } + + /* Rest of code assumes we are not in a quoted string. */ + /* Move forward until we hit a non-metacharacter. */ + while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c)) + { + switch (c) + { + default: + ADVANCE_CHAR (rl_line_buffer, slen, p); + continue; /* straight back to loop, don't increment p */ + case '\\': + if (p < rl_end && rl_line_buffer[p]) + ADVANCE_CHAR (rl_line_buffer, slen, p); + break; + case '\'': + p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP); + break; + case '"': + p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP); + break; + } + + if (p < rl_end) + p++; + } + + if (rl_line_buffer[p] == 0 || p == rl_end) + { + rl_point = rl_end; + rl_ding (); + return 0; + } + + /* Now move forward until we hit a non-quoted metacharacter or EOL */ + while (p < rl_end && (c = rl_line_buffer[p]) && WORDDELIM (c) == 0) + { + switch (c) + { + default: + ADVANCE_CHAR (rl_line_buffer, slen, p); + continue; /* straight back to loop, don't increment p */ + case '\\': + if (p < rl_end && rl_line_buffer[p]) + ADVANCE_CHAR (rl_line_buffer, slen, p); + break; + case '\'': + p = skip_to_delim (rl_line_buffer, ++p, "'", SD_NOJMP); + break; + case '"': + p = skip_to_delim (rl_line_buffer, ++p, "\"", SD_NOJMP); + break; + } + + if (p < rl_end) + p++; + } + + if (p == rl_end || rl_line_buffer[p] == 0) + { + rl_point = rl_end; + return (0); + } + + count--; + } + + rl_point = p; + return (0); +} + +static int +bash_backward_shellword (count, key) + int count, key; +{ + size_t slen; + int sindex, c, p; + DECLARE_MBSTATE; + + if (count < 0) + return (bash_forward_shellword (-count, key)); + + p = rl_point; + slen = rl_end; + + while (count) + { + if (p == 0) + { + rl_point = 0; + return 0; + } + + /* Move backward until we hit a non-metacharacter. */ + while (p > 0) + { + c = rl_line_buffer[p]; + if (WORDDELIM (c) && char_is_quoted (rl_line_buffer, p) == 0) + BACKUP_CHAR (rl_line_buffer, slen, p); + break; + } + + if (p == 0) + { + rl_point = 0; + return 0; + } + + /* Now move backward until we hit a metacharacter or BOL. */ + while (p > 0) + { + c = rl_line_buffer[p]; + if (WORDDELIM (c) && char_is_quoted (rl_line_buffer, p) == 0) + break; + BACKUP_CHAR (rl_line_buffer, slen, p); + } + + count--; + } + + rl_point = p; + return 0; +} + +static int +bash_kill_shellword (count, key) + int count, key; +{ + int p; + + if (count < 0) + return (bash_backward_kill_shellword (-count, key)); + + p = rl_point; + bash_forward_shellword (count, key); + + if (rl_point != p) + rl_kill_text (p, rl_point); + + rl_point = p; + if (rl_editing_mode == 1) /* 1 == emacs_mode */ + rl_mark = rl_point; + + return 0; +} + +static int +bash_backward_kill_shellword (count, key) + int count, key; +{ + int p; + + if (count < 0) + return (bash_kill_shellword (-count, key)); + + p = rl_point; + bash_backward_shellword (count, key); + + if (rl_point != p) + rl_kill_text (p, rl_point); + + if (rl_editing_mode == 1) /* 1 == emacs_mode */ + rl_mark = rl_point; + + return 0; +} + + +/* **************************************************************** */ +/* */ +/* How To Do Shell Completion */ +/* */ +/* **************************************************************** */ + +#define COMMAND_SEPARATORS ";|&{(`" +/* )} */ +#define COMMAND_SEPARATORS_PLUS_WS ";|&{(` \t" +/* )} */ + +/* check for redirections and other character combinations that are not + command separators */ +static int +check_redir (ti) + int ti; +{ + register int this_char, prev_char; + + /* Handle the two character tokens `>&', `<&', and `>|'. + We are not in a command position after one of these. */ + this_char = rl_line_buffer[ti]; + prev_char = rl_line_buffer[ti - 1]; + + if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) || + (this_char == '|' && prev_char == '>')) + return (1); + else if (this_char == '{' && prev_char == '$') /*}*/ + return (1); +#if 0 /* Not yet */ + else if (this_char == '(' && prev_char == '$') /*)*/ + return (1); + else if (this_char == '(' && prev_char == '<') /*)*/ + return (1); +#if defined (EXTENDED_GLOB) + else if (extended_glob && this_char == '(' && prev_char == '!') /*)*/ + return (1); +#endif +#endif + else if (char_is_quoted (rl_line_buffer, ti)) + return (1); + return (0); +} + +#if defined (PROGRAMMABLE_COMPLETION) +/* + * XXX - because of the <= start test, and setting os = s+1, this can + * potentially return os > start. This is probably not what we want to + * happen, but fix later after 2.05a-release. + */ +static int +find_cmd_start (start) + int start; +{ + register int s, os; + + os = 0; + /* Flags == SD_NOJMP only because we want to skip over command substitutions + in assignment statements. Have to test whether this affects `standalone' + command substitutions as individual words. */ + while (((s = skip_to_delim (rl_line_buffer, os, COMMAND_SEPARATORS, SD_NOJMP/*|SD_NOSKIPCMD*/)) <= start) && + rl_line_buffer[s]) + os = s+1; + return os; +} + +static int +find_cmd_end (end) + int end; +{ + register int e; + + e = skip_to_delim (rl_line_buffer, end, COMMAND_SEPARATORS, SD_NOJMP); + return e; +} + +static char * +find_cmd_name (start, sp, ep) + int start; + int *sp, *ep; +{ + char *name; + register int s, e; + + for (s = start; whitespace (rl_line_buffer[s]); s++) + ; + + /* skip until a shell break character */ + e = skip_to_delim (rl_line_buffer, s, "()<>;&| \t\n", SD_NOJMP); + + name = substring (rl_line_buffer, s, e); + + if (sp) + *sp = s; + if (ep) + *ep = e; + + return (name); +} + +static char * +prog_complete_return (text, matchnum) + const char *text; + int matchnum; +{ + static int ind; + + if (matchnum == 0) + ind = 0; + + if (prog_complete_matches == 0 || prog_complete_matches[ind] == 0) + return (char *)NULL; + return (prog_complete_matches[ind++]); +} + +#endif /* PROGRAMMABLE_COMPLETION */ + +/* Do some completion on TEXT. The indices of TEXT in RL_LINE_BUFFER are + at START and END. Return an array of matches, or NULL if none. */ +static char ** +attempt_shell_completion (text, start, end) + const char *text; + int start, end; +{ + int in_command_position, ti, saveti, qc, dflags; + char **matches, *command_separator_chars; +#if defined (PROGRAMMABLE_COMPLETION) + int have_progcomps, was_assignment; +#endif + + command_separator_chars = COMMAND_SEPARATORS; + matches = (char **)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + + rl_filename_quote_characters = default_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + set_directory_hook (); + rl_filename_stat_hook = bash_filename_stat_hook; + + /* Determine if this could be a command word. It is if it appears at + the start of the line (ignoring preceding whitespace), or if it + appears after a character that separates commands. It cannot be a + command word if we aren't at the top-level prompt. */ + ti = start - 1; + saveti = qc = -1; + + while ((ti > -1) && (whitespace (rl_line_buffer[ti]))) + ti--; + +#if 1 + /* If this is an open quote, maybe we're trying to complete a quoted + command name. */ + if (ti >= 0 && (rl_line_buffer[ti] == '"' || rl_line_buffer[ti] == '\'')) + { + qc = rl_line_buffer[ti]; + saveti = ti--; + while (ti > -1 && (whitespace (rl_line_buffer[ti]))) + ti--; + } +#endif + + in_command_position = 0; + if (ti < 0) + { + /* Only do command completion at the start of a line when we + are prompting at the top level. */ + if (current_prompt_string == ps1_prompt) + in_command_position++; + else if (parser_in_command_position ()) + in_command_position++; + } + else if (member (rl_line_buffer[ti], command_separator_chars)) + { + in_command_position++; + + if (check_redir (ti) == 1) + in_command_position = 0; + } + else + { + /* This still could be in command position. It is possible + that all of the previous words on the line are variable + assignments. */ + } + + /* Check that we haven't incorrectly flagged a closed command substitution + as indicating we're in a command position. */ + if (in_command_position && ti >= 0 && rl_line_buffer[ti] == '`' && + *text != '`' && unclosed_pair (rl_line_buffer, end, "`") == 0) + in_command_position = 0; + + /* Special handling for command substitution. If *TEXT is a backquote, + it can be the start or end of an old-style command substitution, or + unmatched. If it's unmatched, both calls to unclosed_pair will + succeed. Don't bother if readline found a single quote and we are + completing on the substring. */ + if (*text == '`' && rl_completion_quote_character != '\'' && + (in_command_position || (unclosed_pair (rl_line_buffer, start, "`") && + unclosed_pair (rl_line_buffer, end, "`")))) + matches = rl_completion_matches (text, command_subst_completion_function); + +#if defined (PROGRAMMABLE_COMPLETION) + /* Attempt programmable completion. */ + have_progcomps = prog_completion_enabled && (progcomp_size () > 0); + if (matches == 0 && (in_command_position == 0 || text[0] == '\0') && + current_prompt_string == ps1_prompt) + { + int s, e, s1, e1, os, foundcs; + char *n; + + /* XXX - don't free the members */ + if (prog_complete_matches) + free (prog_complete_matches); + prog_complete_matches = (char **)NULL; + + os = start; + n = 0; + s = find_cmd_start (os); + e = find_cmd_end (end); + do + { + /* Skip over assignment statements preceding a command name. If we + don't find a command name at all, we can perform command name + completion. If we find a partial command name, we should perform + command name completion on it. */ + FREE (n); + n = find_cmd_name (s, &s1, &e1); + s = e1 + 1; + } + while (was_assignment = assignment (n, 0)); + s = s1; /* reset to index where name begins */ + + /* s == index of where command name begins (reset above) + e == end of current command, may be end of line + s1 = index of where command name begins + e1 == index of where command name ends + start == index of where word to be completed begins + end == index of where word to be completed ends + if (s == start) we are doing command word completion for sure + if (e1 == end) we are at the end of the command name and completing it */ + if (start == 0 && end == 0 && e != 0 && text[0] == '\0') /* beginning of non-empty line */ + foundcs = 0; + else if (start == end && start == s1 && e != 0 && e1 > end) /* beginning of command name, leading whitespace */ + foundcs = 0; + else if (e == 0 && e == s && text[0] == '\0' && have_progcomps) /* beginning of empty line */ + prog_complete_matches = programmable_completions ("_EmptycmD_", text, s, e, &foundcs); + else if (start == end && text[0] == '\0' && s1 > start && whitespace (rl_line_buffer[start])) + foundcs = 0; /* whitespace before command name */ + else if (e > s && was_assignment == 0 && e1 == end && rl_line_buffer[e] == 0 && whitespace (rl_line_buffer[e-1]) == 0) + { + /* not assignment statement, but still want to perform command + completion if we are composing command word. */ + foundcs = 0; + in_command_position = s == start && STREQ (n, text); /* XXX */ + } + else if (e > s && was_assignment == 0 && have_progcomps) + { + prog_complete_matches = programmable_completions (n, text, s, e, &foundcs); + /* command completion if programmable completion fails */ + in_command_position = s == start && STREQ (n, text); /* XXX */ + } + else if (s >= e && n[0] == '\0' && text[0] == '\0' && start > 0) + { + foundcs = 0; /* empty command name following assignments */ + in_command_position = was_assignment; + } + else if (s == start && e == end && STREQ (n, text) && start > 0) + { + foundcs = 0; /* partial command name following assignments */ + in_command_position = 1; + } + else + foundcs = 0; + FREE (n); + /* XXX - if we found a COMPSPEC for the command, just return whatever + the programmable completion code returns, and disable the default + filename completion that readline will do unless the COPT_DEFAULT + option has been set with the `-o default' option to complete or + compopt. */ + if (foundcs) + { + pcomp_set_readline_variables (foundcs, 1); + /* Turn what the programmable completion code returns into what + readline wants. I should have made compute_lcd_of_matches + external... */ + matches = rl_completion_matches (text, prog_complete_return); + if ((foundcs & COPT_DEFAULT) == 0) + rl_attempted_completion_over = 1; /* no default */ + if (matches || ((foundcs & COPT_BASHDEFAULT) == 0)) + return (matches); + } + } +#endif + + if (matches == 0) + { + dflags = 0; + if (in_command_position) + dflags |= DEFCOMP_CMDPOS; + matches = bash_default_completion (text, start, end, qc, dflags); + } + + return matches; +} + +char ** +bash_default_completion (text, start, end, qc, compflags) + const char *text; + int start, end, qc, compflags; +{ + char **matches, *t; + + matches = (char **)NULL; + + /* New posix-style command substitution or variable name? */ + if (!matches && *text == '$') + { + if (qc != '\'' && text[1] == '(') /* ) */ + matches = rl_completion_matches (text, command_subst_completion_function); + else + { + matches = rl_completion_matches (text, variable_completion_function); + if (matches && matches[0] && matches[1] == 0) + { + t = savestring (matches[0]); + bash_filename_stat_hook (&t); + /* doesn't use test_for_directory because that performs tilde + expansion */ + if (file_isdir (t)) + rl_completion_append_character = '/'; + free (t); + } + } + } + + /* If the word starts in `~', and there is no slash in the word, then + try completing this word as a username. */ + if (matches == 0 && *text == '~' && mbschr (text, '/') == 0) + matches = rl_completion_matches (text, rl_username_completion_function); + + /* Another one. Why not? If the word starts in '@', then look through + the world of known hostnames for completion first. */ + if (matches == 0 && perform_hostname_completion && *text == '@') + matches = rl_completion_matches (text, hostname_completion_function); + + /* And last, (but not least) if this word is in a command position, then + complete over possible command names, including aliases, functions, + and command names. */ + if (matches == 0 && (compflags & DEFCOMP_CMDPOS)) + { + /* If END == START and text[0] == 0, we are trying to complete an empty + command word. */ + if (no_empty_command_completion && end == start && text[0] == '\0') + { + matches = (char **)NULL; + rl_ignore_some_completions_function = bash_ignore_everything; + } + else + { +#define CMD_IS_DIR(x) (absolute_pathname(x) == 0 && absolute_program(x) == 0 && *(x) != '~' && test_for_directory (x)) + + dot_in_path = 0; + matches = rl_completion_matches (text, command_word_completion_function); + + /* If we are attempting command completion and nothing matches, we + do not want readline to perform filename completion for us. We + still want to be able to complete partial pathnames, so set the + completion ignore function to something which will remove + filenames and leave directories in the match list. */ + if (matches == (char **)NULL) + rl_ignore_some_completions_function = bash_ignore_filenames; + else if (matches[1] == 0 && CMD_IS_DIR(matches[0]) && dot_in_path == 0) + /* If we found a single match, without looking in the current + directory (because it's not in $PATH), but the found name is + also a command in the current directory, suppress appending any + terminating character, since it's ambiguous. */ + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } + else if (matches[0] && matches[1] && STREQ (matches[0], matches[1]) && CMD_IS_DIR (matches[0])) + /* There are multiple instances of the same match (duplicate + completions haven't yet been removed). In this case, all of + the matches will be the same, and the duplicate removal code + will distill them all down to one. We turn on + rl_completion_suppress_append for the same reason as above. + Remember: we only care if there's eventually a single unique + completion. If there are multiple completions this won't + make a difference and the problem won't occur. */ + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } + } + } + + /* This could be a globbing pattern, so try to expand it using pathname + expansion. */ + if (!matches && glob_pattern_p (text)) + { + matches = rl_completion_matches (text, glob_complete_word); + /* A glob expression that matches more than one filename is problematic. + If we match more than one filename, punt. */ + if (matches && matches[1] && rl_completion_type == TAB) + { + strvec_dispose (matches); + matches = (char **)0; + } + else if (matches && matches[1] && rl_completion_type == '!') + { + rl_completion_suppress_append = 1; + rl_filename_completion_desired = 0; + } + } + + return (matches); +} + +static int +bash_command_name_stat_hook (name) + char **name; +{ + char *cname, *result; + + if (absolute_program (*name)) + return (bash_filename_stat_hook (name)); + + cname = *name; + /* XXX - we could do something here with converting aliases, builtins, + and functions into something that came out as executable, but we don't. */ + result = search_for_command (cname, 0); + if (result) + { + *name = result; + return 1; + } + return 0; +} + +static int +executable_completion (filename, searching_path) + const char *filename; + int searching_path; +{ + char *f; + int r; + + f = savestring (filename); + bash_directory_completion_hook (&f); + + r = searching_path ? executable_file (f) : executable_or_directory (f); + free (f); + return r; +} + +/* This is the function to call when the word to complete is in a position + where a command word can be found. It grovels $PATH, looking for commands + that match. It also scans aliases, function names, and the shell_builtin + table. */ +char * +command_word_completion_function (hint_text, state) + const char *hint_text; + int state; +{ + static char *hint = (char *)NULL; + static char *path = (char *)NULL; + static char *val = (char *)NULL; + static char *filename_hint = (char *)NULL; + static char *dequoted_hint = (char *)NULL; + static char *directory_part = (char *)NULL; + static char **glob_matches = (char **)NULL; + static int path_index, hint_len, dequoted_len, istate, igncase; + static int mapping_over, local_index, searching_path, hint_is_dir; + static int old_glob_ignore_case, globpat; + static SHELL_VAR **varlist = (SHELL_VAR **)NULL; +#if defined (ALIAS) + static alias_t **alias_list = (alias_t **)NULL; +#endif /* ALIAS */ + char *temp, *cval; + + /* We have to map over the possibilities for command words. If we have + no state, then make one just for that purpose. */ + if (state == 0) + { + rl_filename_stat_hook = bash_command_name_stat_hook; + + if (dequoted_hint && dequoted_hint != hint) + free (dequoted_hint); + if (hint) + free (hint); + + mapping_over = searching_path = 0; + hint_is_dir = CMD_IS_DIR (hint_text); + val = (char *)NULL; + + temp = rl_variable_value ("completion-ignore-case"); + igncase = RL_BOOLEAN_VARIABLE_VALUE (temp); + + if (glob_matches) + { + free (glob_matches); + glob_matches = (char **)NULL; + } + + globpat = glob_pattern_p (hint_text); + + /* If this is an absolute program name, do not check it against + aliases, reserved words, functions or builtins. We must check + whether or not it is unique, and, if so, whether that filename + is executable. */ + if (globpat || absolute_program (hint_text)) + { + /* Perform tilde expansion on what's passed, so we don't end up + passing filenames with tildes directly to stat(). */ + if (*hint_text == '~') + { + hint = bash_tilde_expand (hint_text, 0); + directory_part = savestring (hint_text); + temp = strchr (directory_part, '/'); + if (temp) + *temp = 0; + else + { + free (directory_part); + directory_part = (char *)NULL; + } + } + else + hint = savestring (hint_text); + + dequoted_hint = hint; + /* If readline's completer found a quote character somewhere, but + didn't set the quote character, there must have been a quote + character embedded in the filename. It can't be at the start of + the filename, so we need to dequote the filename before we look + in the file system for it. */ + if (rl_completion_found_quote && rl_completion_quote_character == 0) + { + dequoted_hint = bash_dequote_filename (hint, 0); + free (hint); + hint = dequoted_hint; + } + dequoted_len = hint_len = strlen (hint); + + if (filename_hint) + free (filename_hint); + + filename_hint = savestring (hint); + + istate = 0; + + if (globpat) + { + mapping_over = 5; + goto globword; + } + else + { + if (dircomplete_expand && path_dot_or_dotdot (filename_hint)) + { + dircomplete_expand = 0; + set_directory_hook (); + dircomplete_expand = 1; + } + mapping_over = 4; + goto inner; + } + } + + dequoted_hint = hint = savestring (hint_text); + dequoted_len = hint_len = strlen (hint); + + if (rl_completion_found_quote && rl_completion_quote_character == 0) + { + dequoted_hint = bash_dequote_filename (hint, 0); + dequoted_len = strlen (dequoted_hint); + } + + path = get_string_value ("PATH"); + path_index = dot_in_path = 0; + + /* Initialize the variables for each type of command word. */ + local_index = 0; + + if (varlist) + free (varlist); + + varlist = all_visible_functions (); + +#if defined (ALIAS) + if (alias_list) + free (alias_list); + + alias_list = all_aliases (); +#endif /* ALIAS */ + } + + /* mapping_over says what we are currently hacking. Note that every case + in this list must fall through when there are no more possibilities. */ + + switch (mapping_over) + { + case 0: /* Aliases come first. */ +#if defined (ALIAS) + while (alias_list && alias_list[local_index]) + { + register char *alias; + + alias = alias_list[local_index++]->name; + + if (STREQN (alias, hint, hint_len)) + return (savestring (alias)); + } +#endif /* ALIAS */ + local_index = 0; + mapping_over++; + + case 1: /* Then shell reserved words. */ + { + while (word_token_alist[local_index].word) + { + register char *reserved_word; + + reserved_word = word_token_alist[local_index++].word; + + if (STREQN (reserved_word, hint, hint_len)) + return (savestring (reserved_word)); + } + local_index = 0; + mapping_over++; + } + + case 2: /* Then function names. */ + while (varlist && varlist[local_index]) + { + register char *varname; + + varname = varlist[local_index++]->name; + + if (STREQN (varname, hint, hint_len)) + return (savestring (varname)); + } + local_index = 0; + mapping_over++; + + case 3: /* Then shell builtins. */ + for (; local_index < num_shell_builtins; local_index++) + { + /* Ignore it if it doesn't have a function pointer or if it + is not currently enabled. */ + if (!shell_builtins[local_index].function || + (shell_builtins[local_index].flags & BUILTIN_ENABLED) == 0) + continue; + + if (STREQN (shell_builtins[local_index].name, hint, hint_len)) + { + int i = local_index++; + + return (savestring (shell_builtins[i].name)); + } + } + local_index = 0; + mapping_over++; + } + +globword: + /* Limited support for completing command words with globbing chars. Only + a single match (multiple matches that end up reducing the number of + characters in the common prefix are bad) will ever be returned on + regular completion. */ + if (globpat) + { + if (state == 0) + { + glob_ignore_case = igncase; + glob_matches = shell_glob_filename (hint); + glob_ignore_case = old_glob_ignore_case; + + if (GLOB_FAILED (glob_matches) || glob_matches == 0) + { + glob_matches = (char **)NULL; + return ((char *)NULL); + } + + local_index = 0; + + if (glob_matches[1] && rl_completion_type == TAB) /* multiple matches are bad */ + return ((char *)NULL); + } + + while (val = glob_matches[local_index++]) + { + if (executable_or_directory (val)) + { + if (*hint_text == '~' && directory_part) + { + temp = restore_tilde (val, directory_part); + free (val); + val = temp; + } + return (val); + } + free (val); + } + + glob_ignore_case = old_glob_ignore_case; + return ((char *)NULL); + } + + /* If the text passed is a directory in the current directory, return it + as a possible match. Executables in directories in the current + directory can be specified using relative pathnames and successfully + executed even when `.' is not in $PATH. */ + if (hint_is_dir) + { + hint_is_dir = 0; /* only return the hint text once */ + return (savestring (hint_text)); + } + + /* Repeatedly call filename_completion_function while we have + members of PATH left. Question: should we stat each file? + Answer: we call executable_file () on each file. */ + outer: + + istate = (val != (char *)NULL); + + if (istate == 0) + { + char *current_path; + + /* Get the next directory from the path. If there is none, then we + are all done. */ + if (path == 0 || path[path_index] == 0 || + (current_path = extract_colon_unit (path, &path_index)) == 0) + return ((char *)NULL); + + searching_path = 1; + if (*current_path == 0) + { + free (current_path); + current_path = savestring ("."); + } + + if (*current_path == '~') + { + char *t; + + t = bash_tilde_expand (current_path, 0); + free (current_path); + current_path = t; + } + + if (current_path[0] == '.' && current_path[1] == '\0') + dot_in_path = 1; + + if (filename_hint) + free (filename_hint); + + filename_hint = sh_makepath (current_path, hint, 0); + free (current_path); /* XXX */ + } + + inner: + val = rl_filename_completion_function (filename_hint, istate); + if (mapping_over == 4 && dircomplete_expand) + set_directory_hook (); + + istate = 1; + + if (val == 0) + { + /* If the hint text is an absolute program, then don't bother + searching through PATH. */ + if (absolute_program (hint)) + return ((char *)NULL); + + goto outer; + } + else + { + int match, freetemp; + + if (absolute_program (hint)) + { + if (igncase == 0) + match = strncmp (val, hint, hint_len) == 0; + else + match = strncasecmp (val, hint, hint_len) == 0; + + /* If we performed tilde expansion, restore the original + filename. */ + if (*hint_text == '~') + temp = restore_tilde (val, directory_part); + else + temp = savestring (val); + freetemp = 1; + } + else + { + temp = strrchr (val, '/'); + + if (temp) + { + temp++; + if (igncase == 0) + freetemp = match = strncmp (temp, hint, hint_len) == 0; + else + freetemp = match = strncasecmp (temp, hint, hint_len) == 0; + if (match) + temp = savestring (temp); + } + else + freetemp = match = 0; + } + + /* If we have found a match, and it is an executable file, return it. + We don't return directory names when searching $PATH, since the + bash execution code won't find executables in directories which + appear in directories in $PATH when they're specified using + relative pathnames. */ +#if 0 + /* If we're not searching $PATH and we have a relative pathname, we + need to re-canonicalize it before testing whether or not it's an + executable or a directory so the shell treats .. relative to $PWD + according to the physical/logical option. The shell already + canonicalizes the directory name in order to tell readline where + to look, so not doing it here will be inconsistent. */ + /* XXX -- currently not used -- will introduce more inconsistency, + since shell does not canonicalize ../foo before passing it to + shell_execve(). */ + if (match && searching_path == 0 && *val == '.') + { + char *t, *t1; + + t = get_working_directory ("command-word-completion"); + t1 = make_absolute (val, t); + free (t); + cval = sh_canonpath (t1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + } + else +#endif + cval = val; + + if (match && executable_completion ((searching_path ? val : cval), searching_path)) + { + if (cval != val) + free (cval); + free (val); + val = ""; /* So it won't be NULL. */ + return (temp); + } + else + { + if (freetemp) + free (temp); + if (cval != val) + free (cval); + free (val); + goto inner; + } + } +} + +/* Completion inside an unterminated command substitution. */ +static char * +command_subst_completion_function (text, state) + const char *text; + int state; +{ + static char **matches = (char **)NULL; + static const char *orig_start; + static char *filename_text = (char *)NULL; + static int cmd_index, start_len; + char *value; + + if (state == 0) + { + if (filename_text) + free (filename_text); + orig_start = text; + if (*text == '`') + text++; + else if (*text == '$' && text[1] == '(') /* ) */ + text += 2; + /* If the text was quoted, suppress any quote character that the + readline completion code would insert. */ + rl_completion_suppress_quote = 1; + start_len = text - orig_start; + filename_text = savestring (text); + if (matches) + free (matches); + + /* + * At this point we can entertain the idea of re-parsing + * `filename_text' into a (possibly incomplete) command name and + * arguments, and doing completion based on that. This is + * currently very rudimentary, but it is a small improvement. + */ + for (value = filename_text + strlen (filename_text) - 1; value > filename_text; value--) + if (whitespace (*value) || member (*value, COMMAND_SEPARATORS)) + break; + if (value <= filename_text) + matches = rl_completion_matches (filename_text, command_word_completion_function); + else + { + value++; + start_len += value - filename_text; + if (whitespace (value[-1])) + matches = rl_completion_matches (value, rl_filename_completion_function); + else + matches = rl_completion_matches (value, command_word_completion_function); + } + + /* If there is more than one match, rl_completion_matches has already + put the lcd in matches[0]. Skip over it. */ + cmd_index = matches && matches[0] && matches[1]; + + /* If there's a single match and it's a directory, set the append char + to the expected `/'. Otherwise, don't append anything. */ + if (matches && matches[0] && matches[1] == 0 && test_for_directory (matches[0])) + rl_completion_append_character = '/'; + else + rl_completion_suppress_append = 1; + } + + if (matches == 0 || matches[cmd_index] == 0) + { + rl_filename_quoting_desired = 0; /* disable quoting */ + return ((char *)NULL); + } + else + { + value = (char *)xmalloc (1 + start_len + strlen (matches[cmd_index])); + + if (start_len == 1) + value[0] = *orig_start; + else + strncpy (value, orig_start, start_len); + + strcpy (value + start_len, matches[cmd_index]); + + cmd_index++; + return (value); + } +} + +/* Okay, now we write the entry_function for variable completion. */ +static char * +variable_completion_function (text, state) + const char *text; + int state; +{ + static char **varlist = (char **)NULL; + static int varlist_index; + static char *varname = (char *)NULL; + static int namelen; + static int first_char, first_char_loc; + + if (!state) + { + if (varname) + free (varname); + + first_char_loc = 0; + first_char = text[0]; + + if (first_char == '$') + first_char_loc++; + + if (text[first_char_loc] == '{') + first_char_loc++; + + varname = savestring (text + first_char_loc); + + namelen = strlen (varname); + if (varlist) + strvec_dispose (varlist); + + varlist = all_variables_matching_prefix (varname); + varlist_index = 0; + } + + if (!varlist || !varlist[varlist_index]) + { + return ((char *)NULL); + } + else + { + char *value; + + value = (char *)xmalloc (4 + strlen (varlist[varlist_index])); + + if (first_char_loc) + { + value[0] = first_char; + if (first_char_loc == 2) + value[1] = '{'; + } + + strcpy (value + first_char_loc, varlist[varlist_index]); + if (first_char_loc == 2) + strcat (value, "}"); + + varlist_index++; + return (value); + } +} + +/* How about a completion function for hostnames? */ +static char * +hostname_completion_function (text, state) + const char *text; + int state; +{ + static char **list = (char **)NULL; + static int list_index = 0; + static int first_char, first_char_loc; + + /* If we don't have any state, make some. */ + if (state == 0) + { + FREE (list); + + list = (char **)NULL; + + first_char_loc = 0; + first_char = *text; + + if (first_char == '@') + first_char_loc++; + + list = hostnames_matching ((char *)text+first_char_loc); + list_index = 0; + } + + if (list && list[list_index]) + { + char *t; + + t = (char *)xmalloc (2 + strlen (list[list_index])); + *t = first_char; + strcpy (t + first_char_loc, list[list_index]); + list_index++; + return (t); + } + + return ((char *)NULL); +} + +/* + * A completion function for service names from /etc/services (or wherever). + */ +char * +bash_servicename_completion_function (text, state) + const char *text; + int state; +{ +#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GETSERVENT) + return ((char *)NULL); +#else + static char *sname = (char *)NULL; + static struct servent *srvent; + static int snamelen, firstc; + char *value; + char **alist, *aentry; + int afound; + + if (state == 0) + { + FREE (sname); + firstc = *text; + + sname = savestring (text); + snamelen = strlen (sname); + setservent (0); + } + + while (srvent = getservent ()) + { + afound = 0; + if (snamelen == 0 || (STREQN (sname, srvent->s_name, snamelen))) + break; + /* Not primary, check aliases */ + for (alist = srvent->s_aliases; *alist; alist++) + { + aentry = *alist; + if (STREQN (sname, aentry, snamelen)) + { + afound = 1; + break; + } + } + + if (afound) + break; + } + + if (srvent == 0) + { + endservent (); + return ((char *)NULL); + } + + value = afound ? savestring (aentry) : savestring (srvent->s_name); + return value; +#endif +} + +/* + * A completion function for group names from /etc/group (or wherever). + */ +char * +bash_groupname_completion_function (text, state) + const char *text; + int state; +{ +#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GRP_H) + return ((char *)NULL); +#else + static char *gname = (char *)NULL; + static struct group *grent; + static int gnamelen; + char *value; + + if (state == 0) + { + FREE (gname); + gname = savestring (text); + gnamelen = strlen (gname); + + setgrent (); + } + + while (grent = getgrent ()) + { + if (gnamelen == 0 || (STREQN (gname, grent->gr_name, gnamelen))) + break; + } + + if (grent == 0) + { + endgrent (); + return ((char *)NULL); + } + + value = savestring (grent->gr_name); + return (value); +#endif +} + +/* Functions to perform history and alias expansions on the current line. */ + +#if defined (BANG_HISTORY) +/* Perform history expansion on the current line. If no history expansion + is done, pre_process_line() returns what it was passed, so we need to + allocate a new line here. */ +static char * +history_expand_line_internal (line) + char *line; +{ + char *new_line; + int old_verify; + + old_verify = hist_verify; + hist_verify = 0; + new_line = pre_process_line (line, 0, 0); + hist_verify = old_verify; + + return (new_line == line) ? savestring (line) : new_line; +} +#endif + +/* There was an error in expansion. Let the preprocessor print + the error here. */ +static void +cleanup_expansion_error () +{ + char *to_free; +#if defined (BANG_HISTORY) + int old_verify; + + old_verify = hist_verify; + hist_verify = 0; +#endif + + fprintf (rl_outstream, "\r\n"); + to_free = pre_process_line (rl_line_buffer, 1, 0); +#if defined (BANG_HISTORY) + hist_verify = old_verify; +#endif + if (to_free != rl_line_buffer) + FREE (to_free); + putc ('\r', rl_outstream); + rl_forced_update_display (); +} + +/* If NEW_LINE differs from what is in the readline line buffer, add an + undo record to get from the readline line buffer contents to the new + line and make NEW_LINE the current readline line. */ +static void +maybe_make_readline_line (new_line) + char *new_line; +{ + if (strcmp (new_line, rl_line_buffer) != 0) + { + rl_point = rl_end; + + rl_add_undo (UNDO_BEGIN, 0, 0, 0); + rl_delete_text (0, rl_point); + rl_point = rl_end = rl_mark = 0; + rl_insert_text (new_line); + rl_add_undo (UNDO_END, 0, 0, 0); + } +} + +/* Make NEW_LINE be the current readline line. This frees NEW_LINE. */ +static void +set_up_new_line (new_line) + char *new_line; +{ + int old_point, at_end; + + old_point = rl_point; + at_end = rl_point == rl_end; + + /* If the line was history and alias expanded, then make that + be one thing to undo. */ + maybe_make_readline_line (new_line); + free (new_line); + + /* Place rl_point where we think it should go. */ + if (at_end) + rl_point = rl_end; + else if (old_point < rl_end) + { + rl_point = old_point; + if (!whitespace (rl_line_buffer[rl_point])) + rl_forward_word (1, 0); + } +} + +#if defined (ALIAS) +/* Expand aliases in the current readline line. */ +static int +alias_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = alias_expand (rl_line_buffer); + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} +#endif + +#if defined (BANG_HISTORY) +/* History expand the line. */ +static int +history_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = history_expand_line_internal (rl_line_buffer); + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} + +/* Expand history substitutions in the current line and then insert a + space (hopefully close to where we were before). */ +static int +tcsh_magic_space (count, ignore) + int count, ignore; +{ + int dist_from_end, old_point; + + old_point = rl_point; + dist_from_end = rl_end - rl_point; + if (history_expand_line (count, ignore) == 0) + { + /* Try a simple heuristic from Stephen Gildea . + This works if all expansions were before rl_point or if no expansions + were performed. */ + rl_point = (old_point == 0) ? old_point : rl_end - dist_from_end; + rl_insert (1, ' '); + return (0); + } + else + return (1); +} +#endif /* BANG_HISTORY */ + +/* History and alias expand the line. */ +static int +history_and_alias_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + + new_line = 0; +#if defined (BANG_HISTORY) + new_line = history_expand_line_internal (rl_line_buffer); +#endif + +#if defined (ALIAS) + if (new_line) + { + char *alias_line; + + alias_line = alias_expand (new_line); + free (new_line); + new_line = alias_line; + } +#endif /* ALIAS */ + + if (new_line) + { + set_up_new_line (new_line); + return (0); + } + else + { + cleanup_expansion_error (); + return (1); + } +} + +/* History and alias expand the line, then perform the shell word + expansions by calling expand_string. This can't use set_up_new_line() + because we want the variable expansions as a separate undo'able + set of operations. */ +static int +shell_expand_line (count, ignore) + int count, ignore; +{ + char *new_line; + WORD_LIST *expanded_string; + + new_line = 0; +#if defined (BANG_HISTORY) + new_line = history_expand_line_internal (rl_line_buffer); +#endif + +#if defined (ALIAS) + if (new_line) + { + char *alias_line; + + alias_line = alias_expand (new_line); + free (new_line); + new_line = alias_line; + } +#endif /* ALIAS */ + + if (new_line) + { + int old_point = rl_point; + int at_end = rl_point == rl_end; + + /* If the line was history and alias expanded, then make that + be one thing to undo. */ + maybe_make_readline_line (new_line); + free (new_line); + + /* If there is variable expansion to perform, do that as a separate + operation to be undone. */ + new_line = savestring (rl_line_buffer); + expanded_string = expand_string (new_line, 0); + FREE (new_line); + if (expanded_string == 0) + { + new_line = (char *)xmalloc (1); + new_line[0] = '\0'; + } + else + { + new_line = string_list (expanded_string); + dispose_words (expanded_string); + } + + maybe_make_readline_line (new_line); + free (new_line); + + /* Place rl_point where we think it should go. */ + if (at_end) + rl_point = rl_end; + else if (old_point < rl_end) + { + rl_point = old_point; + if (!whitespace (rl_line_buffer[rl_point])) + rl_forward_word (1, 0); + } + return 0; + } + else + { + cleanup_expansion_error (); + return 1; + } +} + +/* If FIGNORE is set, then don't match files with the given suffixes when + completing filenames. If only one of the possibilities has an acceptable + suffix, delete the others, else just return and let the completer + signal an error. It is called by the completer when real + completions are done on filenames by the completer's internal + function, not for completion lists (M-?) and not on "other" + completion types, such as hostnames or commands. */ + +static struct ignorevar fignore = +{ + "FIGNORE", + (struct ign *)0, + 0, + (char *)0, + (sh_iv_item_func_t *) 0, +}; + +static void +_ignore_completion_names (names, name_func) + char **names; + sh_ignore_func_t *name_func; +{ + char **newnames; + int idx, nidx; + char **oldnames; + int oidx; + + /* If there is only one completion, see if it is acceptable. If it is + not, free it up. In any case, short-circuit and return. This is a + special case because names[0] is not the prefix of the list of names + if there is only one completion; it is the completion itself. */ + if (names[1] == (char *)0) + { + if (force_fignore) + if ((*name_func) (names[0]) == 0) + { + free (names[0]); + names[0] = (char *)NULL; + } + + return; + } + + /* Allocate space for array to hold list of pointers to matching + filenames. The pointers are copied back to NAMES when done. */ + for (nidx = 1; names[nidx]; nidx++) + ; + newnames = strvec_create (nidx + 1); + + if (force_fignore == 0) + { + oldnames = strvec_create (nidx - 1); + oidx = 0; + } + + newnames[0] = names[0]; + for (idx = nidx = 1; names[idx]; idx++) + { + if ((*name_func) (names[idx])) + newnames[nidx++] = names[idx]; + else if (force_fignore == 0) + oldnames[oidx++] = names[idx]; + else + free (names[idx]); + } + + newnames[nidx] = (char *)NULL; + + /* If none are acceptable then let the completer handle it. */ + if (nidx == 1) + { + if (force_fignore) + { + free (names[0]); + names[0] = (char *)NULL; + } + else + free (oldnames); + + free (newnames); + return; + } + + if (force_fignore == 0) + { + while (oidx) + free (oldnames[--oidx]); + free (oldnames); + } + + /* If only one is acceptable, copy it to names[0] and return. */ + if (nidx == 2) + { + free (names[0]); + names[0] = newnames[1]; + names[1] = (char *)NULL; + free (newnames); + return; + } + + /* Copy the acceptable names back to NAMES, set the new array end, + and return. */ + for (nidx = 1; newnames[nidx]; nidx++) + names[nidx] = newnames[nidx]; + names[nidx] = (char *)NULL; + free (newnames); +} + +static int +name_is_acceptable (name) + const char *name; +{ + struct ign *p; + int nlen; + + for (nlen = strlen (name), p = fignore.ignores; p->val; p++) + { + if (nlen > p->len && p->len > 0 && STREQ (p->val, &name[nlen - p->len])) + return (0); + } + + return (1); +} + +#if 0 +static int +ignore_dot_names (name) + char *name; +{ + return (name[0] != '.'); +} +#endif + +static int +filename_completion_ignore (names) + char **names; +{ +#if 0 + if (glob_dot_filenames == 0) + _ignore_completion_names (names, ignore_dot_names); +#endif + + setup_ignore_patterns (&fignore); + + if (fignore.num_ignores == 0) + return 0; + + _ignore_completion_names (names, name_is_acceptable); + + return 0; +} + +/* Return 1 if NAME is a directory. NAME undergoes tilde expansion. */ +static int +test_for_directory (name) + const char *name; +{ + char *fn; + int r; + + fn = bash_tilde_expand (name, 0); + r = file_isdir (fn); + free (fn); + + return (r); +} + +/* Remove files from NAMES, leaving directories. */ +static int +bash_ignore_filenames (names) + char **names; +{ + _ignore_completion_names (names, test_for_directory); + return 0; +} + +static int +return_zero (name) + const char *name; +{ + return 0; +} + +static int +bash_ignore_everything (names) + char **names; +{ + _ignore_completion_names (names, return_zero); + return 0; +} + +/* Replace a tilde-prefix in VAL with a `~', assuming the user typed it. VAL + is an expanded filename. DIRECTORY_PART is the tilde-prefix portion + of the un-tilde-expanded version of VAL (what the user typed). */ +static char * +restore_tilde (val, directory_part) + char *val, *directory_part; +{ + int l, vl, dl2, xl; + char *dh2, *expdir, *ret; + + vl = strlen (val); + + /* We need to duplicate the expansions readline performs on the directory + portion before passing it to our completion function. */ + dh2 = directory_part ? bash_dequote_filename (directory_part, 0) : 0; + bash_directory_expansion (&dh2); + dl2 = strlen (dh2); + + expdir = bash_tilde_expand (directory_part, 0); + xl = strlen (expdir); + free (expdir); + + /* + dh2 = unexpanded but dequoted tilde-prefix + dl2 = length of tilde-prefix + expdir = tilde-expanded tilde-prefix + xl = length of expanded tilde-prefix + l = length of remainder after tilde-prefix + */ + l = (vl - xl) + 1; + + ret = (char *)xmalloc (dl2 + 2 + l); + strcpy (ret, dh2); + strcpy (ret + dl2, val + xl); + + free (dh2); + return (ret); +} + +/* Simulate the expansions that will be performed by + rl_filename_completion_function. This must be called with the address of + a pointer to malloc'd memory. */ +static void +bash_directory_expansion (dirname) + char **dirname; +{ + char *d, *nd; + + d = savestring (*dirname); + + if ((rl_directory_rewrite_hook) && (*rl_directory_rewrite_hook) (&d)) + { + free (*dirname); + *dirname = d; + } + else if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&d)) + { + free (*dirname); + *dirname = d; + } + else if (rl_completion_found_quote) + { + nd = bash_dequote_filename (d, rl_completion_quote_character); + free (*dirname); + free (d); + *dirname = nd; + } +} + +/* If necessary, rewrite directory entry */ +static char * +bash_filename_rewrite_hook (fname, fnlen) + char *fname; + int fnlen; +{ + char *conv; + + conv = fnx_fromfs (fname, fnlen); + if (conv != fname) + conv = savestring (conv); + return conv; +} + +/* Functions to save and restore the appropriate directory hook */ +/* This is not static so the shopt code can call it */ +void +set_directory_hook () +{ + if (dircomplete_expand) + { + rl_directory_completion_hook = bash_directory_completion_hook; + rl_directory_rewrite_hook = (rl_icppfunc_t *)0; + } + else + { + rl_directory_rewrite_hook = bash_directory_completion_hook; + rl_directory_completion_hook = (rl_icppfunc_t *)0; + } +} + +static rl_icppfunc_t * +save_directory_hook () +{ + rl_icppfunc_t *ret; + + if (dircomplete_expand) + { + ret = rl_directory_completion_hook; + rl_directory_completion_hook = (rl_icppfunc_t *)NULL; + } + else + { + ret = rl_directory_rewrite_hook; + rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL; + } + + return ret; +} + +static void +restore_directory_hook (hookf) + rl_icppfunc_t *hookf; +{ + if (dircomplete_expand) + rl_directory_completion_hook = hookf; + else + rl_directory_rewrite_hook = hookf; +} + +/* Expand a filename before the readline completion code passes it to stat(2). + The filename will already have had tilde expansion performed. */ +static int +bash_filename_stat_hook (dirname) + char **dirname; +{ + char *local_dirname, *new_dirname, *t; + int should_expand_dirname, return_value; + WORD_LIST *wl; + struct stat sb; + + local_dirname = *dirname; + should_expand_dirname = return_value = 0; + if (t = mbschr (local_dirname, '$')) + should_expand_dirname = '$'; + else if (t = mbschr (local_dirname, '`')) /* XXX */ + should_expand_dirname = '`'; + +#if defined (HAVE_LSTAT) + if (should_expand_dirname && lstat (local_dirname, &sb) == 0) +#else + if (should_expand_dirname && stat (local_dirname, &sb) == 0) +#endif + should_expand_dirname = 0; + + if (should_expand_dirname) + { + new_dirname = savestring (local_dirname); + wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* does the right thing */ + if (wl) + { + free (new_dirname); + new_dirname = string_list (wl); + /* Tell the completer we actually expanded something and change + *dirname only if we expanded to something non-null -- stat + behaves unpredictably when passed null or empty strings */ + if (new_dirname && *new_dirname) + { + free (local_dirname); /* XXX */ + local_dirname = *dirname = new_dirname; + return_value = STREQ (local_dirname, *dirname) == 0; + } + else + free (new_dirname); + dispose_words (wl); + } + else + free (new_dirname); + } + + /* This is very similar to the code in bash_directory_completion_hook below, + but without spelling correction and not worrying about whether or not + we change relative pathnames. */ + if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1])) + { + char *temp1, *temp2; + + t = get_working_directory ("symlink-hook"); + temp1 = make_absolute (local_dirname, t); + free (t); + temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + + /* If we can't canonicalize, bail. */ + if (temp2 == 0) + { + free (temp1); + return return_value; + } + + free (local_dirname); + *dirname = temp2; + free (temp1); + } + + return (return_value); +} + +/* Handle symbolic link references and other directory name + expansions while hacking completion. This should return 1 if it modifies + the DIRNAME argument, 0 otherwise. It should make sure not to modify + DIRNAME if it returns 0. */ +static int +bash_directory_completion_hook (dirname) + char **dirname; +{ + char *local_dirname, *new_dirname, *t; + int return_value, should_expand_dirname, nextch, closer; + WORD_LIST *wl; + struct stat sb; + + return_value = should_expand_dirname = nextch = closer = 0; + local_dirname = *dirname; + + if (t = mbschr (local_dirname, '$')) + { + should_expand_dirname = '$'; + nextch = t[1]; + /* Deliberately does not handle the deprecated $[...] arithmetic + expansion syntax */ + if (nextch == '(') + closer = ')'; + else if (nextch == '{') + closer = '}'; + else + nextch = 0; + } + else if (local_dirname[0] == '~') + should_expand_dirname = '~'; + else + { + t = mbschr (local_dirname, '`'); + if (t && unclosed_pair (local_dirname, strlen (local_dirname), "`") == 0) + should_expand_dirname = '`'; + } + +#if defined (HAVE_LSTAT) + if (should_expand_dirname && lstat (local_dirname, &sb) == 0) +#else + if (should_expand_dirname && stat (local_dirname, &sb) == 0) +#endif + should_expand_dirname = 0; + + if (should_expand_dirname) + { + new_dirname = savestring (local_dirname); + wl = expand_prompt_string (new_dirname, 0, W_NOCOMSUB); /* does the right thing */ + if (wl) + { + *dirname = string_list (wl); + /* Tell the completer to replace the directory name only if we + actually expanded something. */ + return_value = STREQ (local_dirname, *dirname) == 0; + free (local_dirname); + free (new_dirname); + dispose_words (wl); + local_dirname = *dirname; + /* XXX - change rl_filename_quote_characters here based on + should_expand_dirname/nextch/closer. This is the only place + custom_filename_quote_characters is modified. */ + if (rl_filename_quote_characters && *rl_filename_quote_characters) + { + int i, j, c; + i = strlen (default_filename_quote_characters); + custom_filename_quote_characters = xrealloc (custom_filename_quote_characters, i+1); + for (i = j = 0; c = default_filename_quote_characters[i]; i++) + { + if (c == should_expand_dirname || c == nextch || c == closer) + continue; + custom_filename_quote_characters[j++] = c; + } + custom_filename_quote_characters[j] = '\0'; + rl_filename_quote_characters = custom_filename_quote_characters; + set_filename_bstab (rl_filename_quote_characters); + } + } + else + { + free (new_dirname); + free (local_dirname); + *dirname = (char *)xmalloc (1); + **dirname = '\0'; + return 1; + } + } + else + { + /* Dequote the filename even if we don't expand it. */ + new_dirname = bash_dequote_filename (local_dirname, rl_completion_quote_character); + return_value = STREQ (local_dirname, new_dirname) == 0; + free (local_dirname); + local_dirname = *dirname = new_dirname; + } + + /* no_symbolic_links == 0 -> use (default) logical view of the file system. + local_dirname[0] == '.' && local_dirname[1] == '/' means files in the + current directory (./). + local_dirname[0] == '.' && local_dirname[1] == 0 means relative pathnames + in the current directory (e.g., lib/sh). + XXX - should we do spelling correction on these? */ + + /* This is test as it was in bash-4.2: skip relative pathnames in current + directory. Change test to + (local_dirname[0] != '.' || (local_dirname[1] && local_dirname[1] != '/')) + if we want to skip paths beginning with ./ also. */ + if (no_symbolic_links == 0 && (local_dirname[0] != '.' || local_dirname[1])) + { + char *temp1, *temp2; + int len1, len2; + + /* If we have a relative path + (local_dirname[0] != '/' && local_dirname[0] != '.') + that is canonical after appending it to the current directory, then + temp1 = temp2+'/' + That is, + strcmp (temp1, temp2) == 0 + after adding a slash to temp2 below. It should be safe to not + change those. + */ + t = get_working_directory ("symlink-hook"); + temp1 = make_absolute (local_dirname, t); + free (t); + temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + + /* Try spelling correction if initial canonicalization fails. Make + sure we are set to replace the directory name with the results so + subsequent directory checks don't fail. */ + if (temp2 == 0 && dircomplete_spelling && dircomplete_expand) + { + temp2 = dirspell (temp1); + if (temp2) + { + free (temp1); + temp1 = temp2; + temp2 = sh_canonpath (temp1, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + return_value |= temp2 != 0; + } + } + /* If we can't canonicalize, bail. */ + if (temp2 == 0) + { + free (temp1); + return return_value; + } + len1 = strlen (temp1); + if (temp1[len1 - 1] == '/') + { + len2 = strlen (temp2); + if (len2 > 2) /* don't append `/' to `/' or `//' */ + { + temp2 = (char *)xrealloc (temp2, len2 + 2); + temp2[len2] = '/'; + temp2[len2 + 1] = '\0'; + } + } + + /* dircomplete_expand_relpath == 0 means we want to leave relative + pathnames that are unchanged by canonicalization alone. + *local_dirname != '/' && *local_dirname != '.' == relative pathname + (consistent with general.c:absolute_pathname()) + temp1 == temp2 (after appending a slash to temp2) means the pathname + is not changed by canonicalization as described above. */ + if (dircomplete_expand_relpath || ((local_dirname[0] != '/' && local_dirname[0] != '.') && STREQ (temp1, temp2) == 0)) + return_value |= STREQ (local_dirname, temp2) == 0; + free (local_dirname); + *dirname = temp2; + free (temp1); + } + + return (return_value); +} + +static char **history_completion_array = (char **)NULL; +static int harry_size; +static int harry_len; + +static void +build_history_completion_array () +{ + register int i, j; + HIST_ENTRY **hlist; + char **tokens; + + /* First, clear out the current dynamic history completion list. */ + if (harry_size) + { + strvec_dispose (history_completion_array); + history_completion_array = (char **)NULL; + harry_size = 0; + harry_len = 0; + } + + /* Next, grovel each line of history, making each shell-sized token + a separate entry in the history_completion_array. */ + hlist = history_list (); + + if (hlist) + { + for (i = 0; hlist[i]; i++) + ; + for ( --i; i >= 0; i--) + { + /* Separate each token, and place into an array. */ + tokens = history_tokenize (hlist[i]->line); + + for (j = 0; tokens && tokens[j]; j++) + { + if (harry_len + 2 > harry_size) + history_completion_array = strvec_resize (history_completion_array, harry_size += 10); + + history_completion_array[harry_len++] = tokens[j]; + history_completion_array[harry_len] = (char *)NULL; + } + free (tokens); + } + + /* Sort the complete list of tokens. */ + if (dabbrev_expand_active == 0) + qsort (history_completion_array, harry_len, sizeof (char *), (QSFUNC *)strvec_strcmp); + } +} + +static char * +history_completion_generator (hint_text, state) + const char *hint_text; + int state; +{ + static int local_index, len; + static const char *text; + + /* If this is the first call to the generator, then initialize the + list of strings to complete over. */ + if (state == 0) + { + if (dabbrev_expand_active) /* This is kind of messy */ + rl_completion_suppress_append = 1; + local_index = 0; + build_history_completion_array (); + text = hint_text; + len = strlen (text); + } + + while (history_completion_array && history_completion_array[local_index]) + { + if (strncmp (text, history_completion_array[local_index++], len) == 0) + return (savestring (history_completion_array[local_index - 1])); + } + return ((char *)NULL); +} + +static int +dynamic_complete_history (count, key) + int count, key; +{ + int r; + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_compignore_func_t *orig_ignore_func; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + + rl_completion_entry_function = history_completion_generator; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + + /* XXX - use rl_completion_mode here? */ + if (rl_last_func == dynamic_complete_history) + r = rl_complete_internal ('?'); + else + r = rl_complete_internal (TAB); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + + return r; +} + +static int +bash_dabbrev_expand (count, key) + int count, key; +{ + int r, orig_suppress, orig_sort; + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_compignore_func_t *orig_ignore_func; + + orig_func = rl_menu_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + orig_suppress = rl_completion_suppress_append; + orig_sort = rl_sort_completion_matches; + + rl_menu_completion_entry_function = history_completion_generator; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + rl_filename_completion_desired = 0; + rl_completion_suppress_append = 1; + rl_sort_completion_matches = 0; + + /* XXX - use rl_completion_mode here? */ + dabbrev_expand_active = 1; + if (rl_last_func == bash_dabbrev_expand) + rl_last_func = rl_menu_complete; + r = rl_menu_complete (count, key); + dabbrev_expand_active = 0; + + rl_last_func = bash_dabbrev_expand; + rl_menu_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + rl_completion_suppress_append = orig_suppress; + rl_sort_completion_matches = orig_sort; + + return r; +} + +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) +static int +bash_complete_username (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_username_internal (rl_completion_mode (bash_complete_username)); +} + +static int +bash_possible_username_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_username_internal ('?'); +} + +static int +bash_complete_username_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, rl_username_completion_function); +} + +static int +bash_complete_filename (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_filename_internal (rl_completion_mode (bash_complete_filename)); +} + +static int +bash_possible_filename_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_filename_internal ('?'); +} + +static int +bash_complete_filename_internal (what_to_do) + int what_to_do; +{ + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_icppfunc_t *orig_dir_func; + rl_compignore_func_t *orig_ignore_func; + /*const*/ char *orig_rl_completer_word_break_characters; + int r; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + orig_rl_completer_word_break_characters = rl_completer_word_break_characters; + + orig_dir_func = save_directory_hook (); + + rl_completion_entry_function = rl_filename_completion_function; + rl_attempted_completion_function = (rl_completion_func_t *)NULL; + rl_ignore_some_completions_function = filename_completion_ignore; + rl_completer_word_break_characters = " \t\n\"\'"; + + r = rl_complete_internal (what_to_do); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + rl_completer_word_break_characters = orig_rl_completer_word_break_characters; + + restore_directory_hook (orig_dir_func); + + return r; +} + +static int +bash_complete_hostname (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_hostname_internal (rl_completion_mode (bash_complete_hostname)); +} + +static int +bash_possible_hostname_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_hostname_internal ('?'); +} + +static int +bash_complete_variable (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_variable_internal (rl_completion_mode (bash_complete_variable)); +} + +static int +bash_possible_variable_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_variable_internal ('?'); +} + +static int +bash_complete_command (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_command_internal (rl_completion_mode (bash_complete_command)); +} + +static int +bash_possible_command_completions (ignore, ignore2) + int ignore, ignore2; +{ + return bash_complete_command_internal ('?'); +} + +static int +bash_complete_hostname_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, hostname_completion_function); +} + +static int +bash_complete_variable_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, variable_completion_function); +} + +static int +bash_complete_command_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, command_word_completion_function); +} + +static char *globtext; +static char *globorig; + +static char * +glob_complete_word (text, state) + const char *text; + int state; +{ + static char **matches = (char **)NULL; + static int ind; + int glen; + char *ret, *ttext; + + if (state == 0) + { + rl_filename_completion_desired = 1; + FREE (matches); + if (globorig != globtext) + FREE (globorig); + FREE (globtext); + + ttext = bash_tilde_expand (text, 0); + + if (rl_explicit_arg) + { + globorig = savestring (ttext); + glen = strlen (ttext); + globtext = (char *)xmalloc (glen + 2); + strcpy (globtext, ttext); + globtext[glen] = '*'; + globtext[glen+1] = '\0'; + } + else + globtext = globorig = savestring (ttext); + + if (ttext != text) + free (ttext); + + matches = shell_glob_filename (globtext); + if (GLOB_FAILED (matches)) + matches = (char **)NULL; + ind = 0; + } + + ret = matches ? matches[ind] : (char *)NULL; + ind++; + return ret; +} + +static int +bash_glob_completion_internal (what_to_do) + int what_to_do; +{ + return bash_specific_completion (what_to_do, glob_complete_word); +} + +/* A special quoting function so we don't end up quoting globbing characters + in the word if there are no matches or multiple matches. */ +static char * +bash_glob_quote_filename (s, rtype, qcp) + char *s; + int rtype; + char *qcp; +{ + if (globorig && qcp && *qcp == '\0' && STREQ (s, globorig)) + return (savestring (s)); + else + return (bash_quote_filename (s, rtype, qcp)); +} + +static int +bash_glob_complete_word (count, key) + int count, key; +{ + int r; + rl_quote_func_t *orig_quoting_function; + + if (rl_editing_mode == EMACS_EDITING_MODE) + rl_explicit_arg = 1; /* force `*' append */ + orig_quoting_function = rl_filename_quoting_function; + rl_filename_quoting_function = bash_glob_quote_filename; + + r = bash_glob_completion_internal (rl_completion_mode (bash_glob_complete_word)); + + rl_filename_quoting_function = orig_quoting_function; + return r; +} + +static int +bash_glob_expand_word (count, key) + int count, key; +{ + return bash_glob_completion_internal ('*'); +} + +static int +bash_glob_list_expansions (count, key) + int count, key; +{ + return bash_glob_completion_internal ('?'); +} + +static int +bash_specific_completion (what_to_do, generator) + int what_to_do; + rl_compentry_func_t *generator; +{ + rl_compentry_func_t *orig_func; + rl_completion_func_t *orig_attempt_func; + rl_compignore_func_t *orig_ignore_func; + int r; + + orig_func = rl_completion_entry_function; + orig_attempt_func = rl_attempted_completion_function; + orig_ignore_func = rl_ignore_some_completions_function; + rl_completion_entry_function = generator; + rl_attempted_completion_function = NULL; + rl_ignore_some_completions_function = orig_ignore_func; + + r = rl_complete_internal (what_to_do); + + rl_completion_entry_function = orig_func; + rl_attempted_completion_function = orig_attempt_func; + rl_ignore_some_completions_function = orig_ignore_func; + + return r; +} + +#endif /* SPECIFIC_COMPLETION_FUNCTIONS */ + +#if defined (VI_MODE) +/* Completion, from vi mode's point of view. This is a modified version of + rl_vi_complete which uses the bash globbing code to implement what POSIX + specifies, which is to append a `*' and attempt filename generation (which + has the side effect of expanding any globbing characters in the word). */ +static int +bash_vi_complete (count, key) + int count, key; +{ +#if defined (SPECIFIC_COMPLETION_FUNCTIONS) + int p, r; + char *t; + + if ((rl_point < rl_end) && (!whitespace (rl_line_buffer[rl_point]))) + { + if (!whitespace (rl_line_buffer[rl_point + 1])) + rl_vi_end_word (1, 'E'); + rl_point++; + } + + /* Find boundaries of current word, according to vi definition of a + `bigword'. */ + t = 0; + if (rl_point > 0) + { + p = rl_point; + rl_vi_bWord (1, 'B'); + r = rl_point; + rl_point = p; + p = r; + + t = substring (rl_line_buffer, p, rl_point); + } + + if (t && glob_pattern_p (t) == 0) + rl_explicit_arg = 1; /* XXX - force glob_complete_word to append `*' */ + FREE (t); + + if (key == '*') /* Expansion and replacement. */ + r = bash_glob_expand_word (count, key); + else if (key == '=') /* List possible completions. */ + r = bash_glob_list_expansions (count, key); + else if (key == '\\') /* Standard completion */ + r = bash_glob_complete_word (count, key); + else + r = rl_complete (0, key); + + if (key == '*' || key == '\\') + rl_vi_start_inserting (key, 1, 1); + + return (r); +#else + return rl_vi_complete (count, key); +#endif /* !SPECIFIC_COMPLETION_FUNCTIONS */ +} +#endif /* VI_MODE */ + +/* Filename quoting for completion. */ +/* A function to strip unquoted quote characters (single quotes, double + quotes, and backslashes). It allows single quotes to appear + within double quotes, and vice versa. It should be smarter. */ +static char * +bash_dequote_filename (text, quote_char) + char *text; + int quote_char; +{ + char *ret, *p, *r; + int l, quoted; + + l = strlen (text); + ret = (char *)xmalloc (l + 1); + for (quoted = quote_char, p = text, r = ret; p && *p; p++) + { + /* Allow backslash-escaped characters to pass through unscathed. */ + if (*p == '\\') + { + /* Backslashes are preserved within single quotes. */ + if (quoted == '\'') + *r++ = *p; + /* Backslashes are preserved within double quotes unless the + character is one that is defined to be escaped */ + else if (quoted == '"' && ((sh_syntaxtab[p[1]] & CBSDQUOTE) == 0)) + *r++ = *p; + + *r++ = *++p; + if (*p == '\0') + return ret; /* XXX - was break; */ + continue; + } + /* Close quote. */ + if (quoted && *p == quoted) + { + quoted = 0; + continue; + } + /* Open quote. */ + if (quoted == 0 && (*p == '\'' || *p == '"')) + { + quoted = *p; + continue; + } + *r++ = *p; + } + *r = '\0'; + return ret; +} + +/* Quote characters that the readline completion code would treat as + word break characters with backslashes. Pass backslash-quoted + characters through without examination. */ +static char * +quote_word_break_chars (text) + char *text; +{ + char *ret, *r, *s; + int l; + + l = strlen (text); + ret = (char *)xmalloc ((2 * l) + 1); + for (s = text, r = ret; *s; s++) + { + /* Pass backslash-quoted characters through, including the backslash. */ + if (*s == '\\') + { + *r++ = '\\'; + *r++ = *++s; + if (*s == '\0') + break; + continue; + } + /* OK, we have an unquoted character. Check its presence in + rl_completer_word_break_characters. */ + if (mbschr (rl_completer_word_break_characters, *s)) + *r++ = '\\'; + /* XXX -- check for standalone tildes here and backslash-quote them */ + if (s == text && *s == '~' && file_exists (text)) + *r++ = '\\'; + *r++ = *s; + } + *r = '\0'; + return ret; +} + +/* Use characters in STRING to populate the table of characters that should + be backslash-quoted. The table will be used for sh_backslash_quote from + this file. */ +static void +set_filename_bstab (string) + const char *string; +{ + const char *s; + + memset (filename_bstab, 0, sizeof (filename_bstab)); + for (s = string; s && *s; s++) + filename_bstab[*s] = 1; +} + +/* Quote a filename using double quotes, single quotes, or backslashes + depending on the value of completion_quoting_style. If we're + completing using backslashes, we need to quote some additional + characters (those that readline treats as word breaks), so we call + quote_word_break_chars on the result. This returns newly-allocated + memory. */ +static char * +bash_quote_filename (s, rtype, qcp) + char *s; + int rtype; + char *qcp; +{ + char *rtext, *mtext, *ret; + int rlen, cs; + + rtext = (char *)NULL; + + /* If RTYPE == MULT_MATCH, it means that there is + more than one match. In this case, we do not add + the closing quote or attempt to perform tilde + expansion. If RTYPE == SINGLE_MATCH, we try + to perform tilde expansion, because single and double + quotes inhibit tilde expansion by the shell. */ + + cs = completion_quoting_style; + /* Might need to modify the default completion style based on *qcp, + since it's set to any user-provided opening quote. We also change + to single-quoting if there is no user-provided opening quote and + the word being completed contains newlines, since those are not + quoted correctly using backslashes (a backslash-newline pair is + special to the shell parser). */ + if (*qcp == '\0' && cs == COMPLETE_BSQUOTE && mbschr (s, '\n')) + cs = COMPLETE_SQUOTE; + else if (*qcp == '"') + cs = COMPLETE_DQUOTE; + else if (*qcp == '\'') + cs = COMPLETE_SQUOTE; +#if defined (BANG_HISTORY) + else if (*qcp == '\0' && history_expansion && cs == COMPLETE_DQUOTE && + history_expansion_inhibited == 0 && mbschr (s, '!')) + cs = COMPLETE_BSQUOTE; + + if (*qcp == '"' && history_expansion && cs == COMPLETE_DQUOTE && + history_expansion_inhibited == 0 && mbschr (s, '!')) + { + cs = COMPLETE_BSQUOTE; + *qcp = '\0'; + } +#endif + + /* Don't tilde-expand backslash-quoted filenames, since only single and + double quotes inhibit tilde expansion. */ + mtext = s; + if (mtext[0] == '~' && rtype == SINGLE_MATCH && cs != COMPLETE_BSQUOTE) + mtext = bash_tilde_expand (s, 0); + + switch (cs) + { + case COMPLETE_DQUOTE: + rtext = sh_double_quote (mtext); + break; + case COMPLETE_SQUOTE: + rtext = sh_single_quote (mtext); + break; + case COMPLETE_BSQUOTE: + rtext = sh_backslash_quote (mtext, complete_fullquote ? 0 : filename_bstab, 0); + break; + } + + if (mtext != s) + free (mtext); + + /* We may need to quote additional characters: those that readline treats + as word breaks that are not quoted by backslash_quote. */ + if (rtext && cs == COMPLETE_BSQUOTE) + { + mtext = quote_word_break_chars (rtext); + free (rtext); + rtext = mtext; + } + + /* Leave the opening quote intact. The readline completion code takes + care of avoiding doubled opening quotes. */ + if (rtext) + { + rlen = strlen (rtext); + ret = (char *)xmalloc (rlen + 1); + strcpy (ret, rtext); + } + else + { + ret = (char *)xmalloc (rlen = 1); + ret[0] = '\0'; + } + + /* If there are multiple matches, cut off the closing quote. */ + if (rtype == MULT_MATCH && cs != COMPLETE_BSQUOTE) + ret[rlen - 1] = '\0'; + free (rtext); + return ret; +} + +/* Support for binding readline key sequences to Unix commands. */ +static Keymap cmd_xmap; + +#ifdef _MINIX +static void +#else +static int +#endif +putx(c) + int c; +{ + int x; + x = putc (c, rl_outstream); +#ifndef _MINIX + return x; +#endif +} + +static int +bash_execute_unix_command (count, key) + int count; /* ignored */ + int key; +{ + Keymap ckmap; /* current keymap */ + Keymap xkmap; /* unix command executing keymap */ + rl_command_func_t *func; + int type; + register int i, r; + intmax_t mi; + sh_parser_state_t ps; + char *cmd, *value, *l, *l1, *ce; + SHELL_VAR *v; + char ibuf[INT_STRLEN_BOUND(int) + 1]; + + /* First, we need to find the right command to execute. This is tricky, + because we might have already indirected into another keymap, so we + have to walk cmd_xmap using the entire key sequence. */ + cmd = (char *)rl_function_of_keyseq (rl_executing_keyseq, cmd_xmap, &type); + + if (cmd == 0 || type != ISMACR) + { + rl_crlf (); + internal_error (_("bash_execute_unix_command: cannot find keymap for command")); + rl_forced_update_display (); + return 1; + } + + ce = rl_get_termcap ("ce"); + if (ce) /* clear current line */ + { + fprintf (rl_outstream, "\r"); + tputs (ce, 1, putx); + fflush (rl_outstream); + } + else + rl_crlf (); /* move to a new line */ + + v = bind_variable ("READLINE_LINE", rl_line_buffer, 0); + if (v) + VSETATTR (v, att_exported); + l = v ? value_cell (v) : 0; + value = inttostr (rl_point, ibuf, sizeof (ibuf)); + v = bind_int_variable ("READLINE_POINT", value); + if (v) + VSETATTR (v, att_exported); + array_needs_making = 1; + + save_parser_state (&ps); + r = parse_and_execute (cmd, "bash_execute_unix_command", SEVAL_NOHIST|SEVAL_NOFREE); + restore_parser_state (&ps); + + v = find_variable ("READLINE_LINE"); + l1 = v ? value_cell (v) : 0; + if (l1 != l) + maybe_make_readline_line (value_cell (v)); + v = find_variable ("READLINE_POINT"); + if (v && legal_number (value_cell (v), &mi)) + { + i = mi; + if (i != rl_point) + { + rl_point = i; + if (rl_point > rl_end) + rl_point = rl_end; + else if (rl_point < 0) + rl_point = 0; + } + } + + unbind_variable ("READLINE_LINE"); + unbind_variable ("READLINE_POINT"); + array_needs_making = 1; + + /* and restore the readline buffer and display after command execution. */ + rl_forced_update_display (); + return 0; +} + +int +print_unix_command_map () +{ + Keymap save; + + save = rl_get_keymap (); + rl_set_keymap (cmd_xmap); + rl_macro_dumper (1); + rl_set_keymap (save); + return 0; +} + +static void +init_unix_command_map () +{ + cmd_xmap = rl_make_bare_keymap (); +} + +static int +isolate_sequence (string, ind, need_dquote, startp) + char *string; + int ind, need_dquote, *startp; +{ + register int i; + int c, passc, delim; + + for (i = ind; string[i] && whitespace (string[i]); i++) + ; + /* NEED_DQUOTE means that the first non-white character *must* be `"'. */ + if (need_dquote && string[i] != '"') + { + builtin_error (_("%s: first non-whitespace character is not `\"'"), string); + return -1; + } + + /* We can have delimited strings even if NEED_DQUOTE == 0, like the command + string to bind the key sequence to. */ + delim = (string[i] == '"' || string[i] == '\'') ? string[i] : 0; + + if (startp) + *startp = delim ? ++i : i; + + for (passc = 0; c = string[i]; i++) + { + if (passc) + { + passc = 0; + continue; + } + if (c == '\\') + { + passc++; + continue; + } + if (c == delim) + break; + } + + if (delim && string[i] != delim) + { + builtin_error (_("no closing `%c' in %s"), delim, string); + return -1; + } + + return i; +} + +int +bind_keyseq_to_unix_command (line) + char *line; +{ + Keymap kmap; + char *kseq, *value; + int i, kstart; + + if (cmd_xmap == 0) + init_unix_command_map (); + + kmap = rl_get_keymap (); + + /* We duplicate some of the work done by rl_parse_and_bind here, but + this code only has to handle `"keyseq": ["]command["]' and can + generate an error for anything else. */ + i = isolate_sequence (line, 0, 1, &kstart); + if (i < 0) + return -1; + + /* Create the key sequence string to pass to rl_generic_bind */ + kseq = substring (line, kstart, i); + + for ( ; line[i] && line[i] != ':'; i++) + ; + if (line[i] != ':') + { + builtin_error (_("%s: missing colon separator"), line); + FREE (kseq); + return -1; + } + + i = isolate_sequence (line, i + 1, 0, &kstart); + if (i < 0) + { + FREE (kseq); + return -1; + } + + /* Create the value string containing the command to execute. */ + value = substring (line, kstart, i); + + /* Save the command to execute and the key sequence in the CMD_XMAP */ + rl_generic_bind (ISMACR, kseq, value, cmd_xmap); + + /* and bind the key sequence in the current keymap to a function that + understands how to execute from CMD_XMAP */ + rl_bind_keyseq_in_map (kseq, bash_execute_unix_command, kmap); + + free (kseq); + return 0; +} + +/* Used by the programmable completion code. Complete TEXT as a filename, + but return only directories as matches. Dequotes the filename before + attempting to find matches. */ +char ** +bash_directory_completion_matches (text) + const char *text; +{ + char **m1; + char *dfn; + int qc; + + qc = rl_dispatching ? rl_completion_quote_character : 0; + dfn = bash_dequote_filename ((char *)text, qc); + m1 = rl_completion_matches (dfn, rl_filename_completion_function); + free (dfn); + + if (m1 == 0 || m1[0] == 0) + return m1; + /* We don't bother recomputing the lcd of the matches, because it will just + get thrown away by the programmable completion code and recomputed + later. */ + (void)bash_ignore_filenames (m1); + return m1; +} + +char * +bash_dequote_text (text) + const char *text; +{ + char *dtxt; + int qc; + + qc = (text[0] == '"' || text[0] == '\'') ? text[0] : 0; + dtxt = bash_dequote_filename ((char *)text, qc); + return (dtxt); +} + +/* This event hook is designed to be called after readline receives a signal + that interrupts read(2). It gives reasonable responsiveness to interrupts + and fatal signals without executing too much code in a signal handler + context. */ +static int +bash_event_hook () +{ + /* If we're going to longjmp to top_level, make sure we clean up readline */ + if (interrupt_state && signal_is_trapped (SIGINT) == 0) + rl_cleanup_after_signal (); + + bashline_reset_event_hook (); + check_signals_and_traps (); /* XXX */ +} + +#endif /* READLINE */ diff --git a/doc/bash.1 b/doc/bash.1 index 72568fecb..64475cf63 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -7569,8 +7569,8 @@ Without options, remove each from the table of active jobs. If .I jobspec -is not present, and neither \fB\-a\fP nor \fB\-r\fP is supplied, -the shell's notion of the \fIcurrent job\fP is used. +is not present, and neither the \fB\-a\fP nor the \fB\-r\fP option +is supplied, the \fIcurrent job\fP is used. If the \fB\-h\fP option is given, each .I jobspec is not removed from the table, but is marked so that @@ -7581,13 +7581,6 @@ is not sent to the job if the shell receives a .BR SIGHUP . If no .I jobspec -is present, and neither the -.B \-a -nor the -.B \-r -option is supplied, the \fIcurrent job\fP is used. -If no -.I jobspec is supplied, the .B \-a option means to remove or mark all jobs; the diff --git a/doc/bashref.bt b/doc/bashref.bt index 34c29d187..8d104c82b 100644 --- a/doc/bashref.bt +++ b/doc/bashref.bt @@ -25,7 +25,7 @@ \entry{caller}{48}{\code {caller}} \entry{command}{49}{\code {command}} \entry{declare}{49}{\code {declare}} -\entry{echo}{50}{\code {echo}} +\entry{echo}{51}{\code {echo}} \entry{enable}{51}{\code {enable}} \entry{help}{52}{\code {help}} \entry{let}{52}{\code {let}} @@ -44,7 +44,7 @@ \entry{shopt}{61}{\code {shopt}} \entry{dirs}{90}{\code {dirs}} \entry{popd}{90}{\code {popd}} -\entry{pushd}{90}{\code {pushd}} +\entry{pushd}{91}{\code {pushd}} \entry{bg}{98}{\code {bg}} \entry{fg}{98}{\code {fg}} \entry{jobs}{98}{\code {jobs}} diff --git a/doc/bashref.bts b/doc/bashref.bts index 5f7d68504..df37f7aa6 100644 --- a/doc/bashref.bts +++ b/doc/bashref.bts @@ -24,7 +24,7 @@ \entry {\code {dirs}}{90} \entry {\code {disown}}{99} \initial {E} -\entry {\code {echo}}{50} +\entry {\code {echo}}{51} \entry {\code {enable}}{51} \entry {\code {eval}}{41} \entry {\code {exec}}{41} @@ -52,7 +52,7 @@ \initial {P} \entry {\code {popd}}{90} \entry {\code {printf}}{53} -\entry {\code {pushd}}{90} +\entry {\code {pushd}}{91} \entry {\code {pwd}}{43} \initial {R} \entry {\code {read}}{54} diff --git a/doc/bashref.dvi b/doc/bashref.dvi index 456f53c55..9287c8c69 100644 Binary files a/doc/bashref.dvi and b/doc/bashref.dvi differ diff --git a/doc/bashref.log b/doc/bashref.log index 2bd489a39..36af3326c 100644 --- a/doc/bashref.log +++ b/doc/bashref.log @@ -1,4 +1,4 @@ -This is TeX, Version 3.1415926 (TeX Live 2011/Fink) (format=tex 2012.4.18) 8 MAR 2013 15:57 +This is TeX, Version 3.1415926 (TeX Live 2011/Fink) (format=tex 2012.4.18) 19 AUG 2013 15:43 **/usr/homes/chet/src/bash/src/doc/bashref.texi (/usr/homes/chet/src/bash/src/doc/bashref.texi (./texinfo.tex Loading texinfo [version 2009-01-18.17]: @@ -232,7 +232,7 @@ arallel -k traceroute[] [16] [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30] [31] [32] [33] [34] [35] [36] [37] [38] Chapter 4 [39] [40] [41] [42] [43] [44] [45] [46] -Underfull \hbox (badness 5231) in paragraph at lines 3760--3773 +Underfull \hbox (badness 5231) in paragraph at lines 3762--3775 @texttt emacs-meta[]@textrm , @texttt emacs-ctlx[]@textrm , @texttt vi[]@textr m , @texttt vi-move[]@textrm , @texttt vi-command[]@textrm , and @@ -245,21 +245,9 @@ m , @texttt vi-move[]@textrm , @texttt vi-command[]@textrm , and .etc. [47] [48] [49] [50] [51] [52] [53] [54] [55] [56] [57] [58] [59] [60] [61] -[62] [63] [64] -Underfull \hbox (badness 5460) in paragraph at lines 5047--5053 - []@textrm If set, range ex-pres-sions used in pat-tern match-ing (see - -@hbox(8.2125+2.73749)x433.62, glue set 3.79674 -.@glue(@leftskip) 115.63242 -.@hbox(0.0+0.0)x0.0 -.@textrm I -.@textrm f -.@glue 3.65 plus 1.825 minus 1.21666 -.etc. - -[65] [66] Chapter 5 [67] [68] [69] [70] [71] [72] [73] [74] [75] [76] [77] -Chapter 6 [78] -Overfull \hbox (51.96864pt too wide) in paragraph at lines 5972--5972 +[62] [63] [64] [65] [66] Chapter 5 [67] [68] [69] [70] [71] [72] [73] [74] +[75] [76] [77] Chapter 6 [78] +Overfull \hbox (51.96864pt too wide) in paragraph at lines 5979--5979 []@texttt bash [long-opt] [-ir] [-abefhkmnptuvxdBCDHP] [-o @textttsl op-tion@t exttt ] [-O @textttsl shopt_option@texttt ] [@textttsl ar- @@ -272,7 +260,7 @@ exttt ] [-O @textttsl shopt_option@texttt ] [@textttsl ar- .etc. -Overfull \hbox (76.23077pt too wide) in paragraph at lines 5973--5973 +Overfull \hbox (76.23077pt too wide) in paragraph at lines 5980--5980 []@texttt bash [long-opt] [-abefhkmnptuvxdBCDHP] [-o @textttsl op-tion@texttt ] [-O @textttsl shopt_option@texttt ] -c @textttsl string @texttt [@textttsl ar - @@ -286,7 +274,7 @@ Overfull \hbox (76.23077pt too wide) in paragraph at lines 5973--5973 .etc. -Overfull \hbox (34.72258pt too wide) in paragraph at lines 5974--5974 +Overfull \hbox (34.72258pt too wide) in paragraph at lines 5981--5981 []@texttt bash [long-opt] -s [-abefhkmnptuvxdBCDHP] [-o @textttsl op-tion@text tt ] [-O @textttsl shopt_option@texttt ] [@textttsl ar- @@ -299,7 +287,7 @@ tt ] [-O @textttsl shopt_option@texttt ] [@textttsl ar- .etc. [79] [80] -Underfull \hbox (badness 2245) in paragraph at lines 6146--6148 +Underfull \hbox (badness 2245) in paragraph at lines 6153--6155 []@textrm When a lo-gin shell ex-its, Bash reads and ex-e-cutes com-mands from the file @@ -311,8 +299,8 @@ the file .@textrm n .etc. -[81] [82] [83] [84] [85] [86] [87] [88] [89] [90] [91] [92] [93] [94] -Underfull \hbox (badness 2521) in paragraph at lines 7358--7361 +[81] [82] [83] [84] [85] [86] [87] [88] [89] [90] [91] [92] [93] [94] [95] +Underfull \hbox (badness 2521) in paragraph at lines 7371--7374 @textrm `@texttt --enable-strict-posix-default[]@textrm '[] to @texttt configur e[] @textrm when build-ing (see Sec-tion 10.8 @@ -324,7 +312,7 @@ e[] @textrm when build-ing (see Sec-tion 10.8 .@texttt n .etc. -Chapter 7 [95] [96] [97] [98] [99] +Chapter 7 [96] [97] [98] [99] (/usr/homes/chet/src/bash/src/lib/readline/doc/rluser.texi Chapter 8 [100] [101] [102] [103] [104] [105] [106] Underfull \hbox (badness 5231) in paragraph at lines 565--581 @@ -393,7 +381,7 @@ athname[] [131]) (/usr/homes/chet/src/bash/src/lib/readline/doc/hsuser.texi Chapter 9 [132] [133] [134] [135] [136]) Chapter 10 [137] [138] [139] [140] -Underfull \hbox (badness 2772) in paragraph at lines 7966--7970 +Underfull \hbox (badness 2772) in paragraph at lines 7979--7983 []@textrm Enable sup-port for large files (@texttt http://www.sas.com/standard s/large_ @@ -412,10 +400,10 @@ Appendix D [159] (./bashref.bts) [160] (./bashref.rws) (./bashref.vrs [161] Here is how much of TeX's memory you used: 2085 strings out of 497974 28645 string characters out of 3220833 - 66392 words of memory out of 3000000 + 66401 words of memory out of 3000000 2901 multiletter control sequences out of 15000+200000 32127 words of font info for 112 fonts, out of 3000000 for 9000 51 hyphenation exceptions out of 8191 16i,6n,14p,319b,705s stack positions out of 5000i,500n,10000p,200000b,50000s -Output written on bashref.dvi (172 pages, 717824 bytes). +Output written on bashref.dvi (172 pages, 719444 bytes). diff --git a/doc/bashref.pdf b/doc/bashref.pdf index 8873bf872..30e36596e 100644 Binary files a/doc/bashref.pdf and b/doc/bashref.pdf differ diff --git a/doc/bashref.texi b/doc/bashref.texi index d92d3056c..48c58c5ca 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -7611,8 +7611,8 @@ active jobs. If the @option{-h} option is given, the job is not removed from the table, but is marked so that @code{SIGHUP} is not sent to the job if the shell receives a @code{SIGHUP}. -If @var{jobspec} is not present, and neither the @option{-a} nor @option{-r} -option is supplied, the current job is used. +If @var{jobspec} is not present, and neither the @option{-a} nor the +@option{-r} option is supplied, the current job is used. If no @var{jobspec} is supplied, the @option{-a} option means to remove or mark all jobs; the @option{-r} option without a @var{jobspec} argument restricts operation to running jobs. diff --git a/lib/readline/rltty.c b/lib/readline/rltty.c index bd2c0eaa8..908bae18c 100644 --- a/lib/readline/rltty.c +++ b/lib/readline/rltty.c @@ -121,7 +121,7 @@ static int set_tty_settings PARAMS((int, TIOTYPE *)); static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); -static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); +static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t *)); static void save_tty_chars (tiop) @@ -341,7 +341,7 @@ static int set_tty_settings PARAMS((int, TIOTYPE *)); static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); -static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); +static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t *)); static void _rl_bind_tty_special_chars PARAMS((Keymap, TIOTYPE)); #if defined (FLUSHO) diff --git a/lib/readline/rltty.c~ b/lib/readline/rltty.c~ new file mode 100644 index 000000000..bd2c0eaa8 --- /dev/null +++ b/lib/readline/rltty.c~ @@ -0,0 +1,975 @@ +/* rltty.c -- functions to prepare and restore the terminal for readline's + use. */ + +/* Copyright (C) 1992-2005 Free Software Foundation, Inc. + + This file is part of the GNU Readline Library (Readline), a library + for reading lines of text with interactive input and history editing. + + Readline is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Readline is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Readline. If not, see . +*/ + +#define READLINE_LIBRARY + +#if defined (HAVE_CONFIG_H) +# include +#endif + +#include +#include +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif /* HAVE_UNISTD_H */ + +#include "rldefs.h" + +#if defined (GWINSZ_IN_SYS_IOCTL) +# include +#endif /* GWINSZ_IN_SYS_IOCTL */ + +#include "rltty.h" +#include "readline.h" +#include "rlprivate.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +rl_vintfunc_t *rl_prep_term_function = rl_prep_terminal; +rl_voidfunc_t *rl_deprep_term_function = rl_deprep_terminal; + +static void set_winsize PARAMS((int)); + +/* **************************************************************** */ +/* */ +/* Saving and Restoring the TTY */ +/* */ +/* **************************************************************** */ + +/* Non-zero means that the terminal is in a prepped state. */ +static int terminal_prepped; + +static _RL_TTY_CHARS _rl_tty_chars, _rl_last_tty_chars; + +/* If non-zero, means that this process has called tcflow(fd, TCOOFF) + and output is suspended. */ +#if defined (__ksr1__) +static int ksrflow; +#endif + +/* Dummy call to force a backgrounded readline to stop before it tries + to get the tty settings. */ +static void +set_winsize (tty) + int tty; +{ +#if defined (TIOCGWINSZ) + struct winsize w; + + if (ioctl (tty, TIOCGWINSZ, &w) == 0) + (void) ioctl (tty, TIOCSWINSZ, &w); +#endif /* TIOCGWINSZ */ +} + +#if defined (NO_TTY_DRIVER) +/* Nothing */ +#elif defined (NEW_TTY_DRIVER) + +/* Values for the `flags' field of a struct bsdtty. This tells which + elements of the struct bsdtty have been fetched from the system and + are valid. */ +#define SGTTY_SET 0x01 +#define LFLAG_SET 0x02 +#define TCHARS_SET 0x04 +#define LTCHARS_SET 0x08 + +struct bsdtty { + struct sgttyb sgttyb; /* Basic BSD tty driver information. */ + int lflag; /* Local mode flags, like LPASS8. */ +#if defined (TIOCGETC) + struct tchars tchars; /* Terminal special characters, including ^S and ^Q. */ +#endif +#if defined (TIOCGLTC) + struct ltchars ltchars; /* 4.2 BSD editing characters */ +#endif + int flags; /* Bitmap saying which parts of the struct are valid. */ +}; + +#define TIOTYPE struct bsdtty + +static TIOTYPE otio; + +static void save_tty_chars PARAMS((TIOTYPE *)); +static int _get_tty_settings PARAMS((int, TIOTYPE *)); +static int get_tty_settings PARAMS((int, TIOTYPE *)); +static int _set_tty_settings PARAMS((int, TIOTYPE *)); +static int set_tty_settings PARAMS((int, TIOTYPE *)); + +static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); + +static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); + +static void +save_tty_chars (tiop) + TIOTYPE *tiop; +{ + _rl_last_tty_chars = _rl_tty_chars; + + if (tiop->flags & SGTTY_SET) + { + _rl_tty_chars.t_erase = tiop->sgttyb.sg_erase; + _rl_tty_chars.t_kill = tiop->sgttyb.sg_kill; + } + + if (tiop->flags & TCHARS_SET) + { + _rl_intr_char = _rl_tty_chars.t_intr = tiop->tchars.t_intrc; + _rl_quit_char = _rl_tty_chars.t_quit = tiop->tchars.t_quitc; + + _rl_tty_chars.t_start = tiop->tchars.t_startc; + _rl_tty_chars.t_stop = tiop->tchars.t_stopc; + _rl_tty_chars.t_eof = tiop->tchars.t_eofc; + _rl_tty_chars.t_eol = '\n'; + _rl_tty_chars.t_eol2 = tiop->tchars.t_brkc; + } + + if (tiop->flags & LTCHARS_SET) + { + _rl_susp_char = _rl_tty_chars.t_susp = tiop->ltchars.t_suspc; + + _rl_tty_chars.t_dsusp = tiop->ltchars.t_dsuspc; + _rl_tty_chars.t_reprint = tiop->ltchars.t_rprntc; + _rl_tty_chars.t_flush = tiop->ltchars.t_flushc; + _rl_tty_chars.t_werase = tiop->ltchars.t_werasc; + _rl_tty_chars.t_lnext = tiop->ltchars.t_lnextc; + } + + _rl_tty_chars.t_status = -1; +} + +static int +get_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + set_winsize (tty); + + tiop->flags = tiop->lflag = 0; + + errno = 0; + if (ioctl (tty, TIOCGETP, &(tiop->sgttyb)) < 0) + return -1; + tiop->flags |= SGTTY_SET; + +#if defined (TIOCLGET) + if (ioctl (tty, TIOCLGET, &(tiop->lflag)) == 0) + tiop->flags |= LFLAG_SET; +#endif + +#if defined (TIOCGETC) + if (ioctl (tty, TIOCGETC, &(tiop->tchars)) == 0) + tiop->flags |= TCHARS_SET; +#endif + +#if defined (TIOCGLTC) + if (ioctl (tty, TIOCGLTC, &(tiop->ltchars)) == 0) + tiop->flags |= LTCHARS_SET; +#endif + + return 0; +} + +static int +set_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + if (tiop->flags & SGTTY_SET) + { + ioctl (tty, TIOCSETN, &(tiop->sgttyb)); + tiop->flags &= ~SGTTY_SET; + } + _rl_echoing_p = 1; + +#if defined (TIOCLSET) + if (tiop->flags & LFLAG_SET) + { + ioctl (tty, TIOCLSET, &(tiop->lflag)); + tiop->flags &= ~LFLAG_SET; + } +#endif + +#if defined (TIOCSETC) + if (tiop->flags & TCHARS_SET) + { + ioctl (tty, TIOCSETC, &(tiop->tchars)); + tiop->flags &= ~TCHARS_SET; + } +#endif + +#if defined (TIOCSLTC) + if (tiop->flags & LTCHARS_SET) + { + ioctl (tty, TIOCSLTC, &(tiop->ltchars)); + tiop->flags &= ~LTCHARS_SET; + } +#endif + + return 0; +} + +static void +prepare_terminal_settings (meta_flag, oldtio, tiop) + int meta_flag; + TIOTYPE oldtio, *tiop; +{ + _rl_echoing_p = (oldtio.sgttyb.sg_flags & ECHO); + _rl_echoctl = (oldtio.sgttyb.sg_flags & ECHOCTL); + + /* Copy the original settings to the structure we're going to use for + our settings. */ + tiop->sgttyb = oldtio.sgttyb; + tiop->lflag = oldtio.lflag; +#if defined (TIOCGETC) + tiop->tchars = oldtio.tchars; +#endif +#if defined (TIOCGLTC) + tiop->ltchars = oldtio.ltchars; +#endif + tiop->flags = oldtio.flags; + + /* First, the basic settings to put us into character-at-a-time, no-echo + input mode. */ + tiop->sgttyb.sg_flags &= ~(ECHO | CRMOD); + tiop->sgttyb.sg_flags |= CBREAK; + + /* If this terminal doesn't care how the 8th bit is used, then we can + use it for the meta-key. If only one of even or odd parity is + specified, then the terminal is using parity, and we cannot. */ +#if !defined (ANYP) +# define ANYP (EVENP | ODDP) +#endif + if (((oldtio.sgttyb.sg_flags & ANYP) == ANYP) || + ((oldtio.sgttyb.sg_flags & ANYP) == 0)) + { + tiop->sgttyb.sg_flags |= ANYP; + + /* Hack on local mode flags if we can. */ +#if defined (TIOCLGET) +# if defined (LPASS8) + tiop->lflag |= LPASS8; +# endif /* LPASS8 */ +#endif /* TIOCLGET */ + } + +#if defined (TIOCGETC) +# if defined (USE_XON_XOFF) + /* Get rid of terminal output start and stop characters. */ + tiop->tchars.t_stopc = -1; /* C-s */ + tiop->tchars.t_startc = -1; /* C-q */ + + /* If there is an XON character, bind it to restart the output. */ + if (oldtio.tchars.t_startc != -1) + rl_bind_key (oldtio.tchars.t_startc, rl_restart_output); +# endif /* USE_XON_XOFF */ + + /* If there is an EOF char, bind _rl_eof_char to it. */ + if (oldtio.tchars.t_eofc != -1) + _rl_eof_char = oldtio.tchars.t_eofc; + +# if defined (NO_KILL_INTR) + /* Get rid of terminal-generated SIGQUIT and SIGINT. */ + tiop->tchars.t_quitc = -1; /* C-\ */ + tiop->tchars.t_intrc = -1; /* C-c */ +# endif /* NO_KILL_INTR */ +#endif /* TIOCGETC */ + +#if defined (TIOCGLTC) + /* Make the interrupt keys go away. Just enough to make people happy. */ + tiop->ltchars.t_dsuspc = -1; /* C-y */ + tiop->ltchars.t_lnextc = -1; /* C-v */ +#endif /* TIOCGLTC */ +} + +#else /* !defined (NEW_TTY_DRIVER) */ + +#if !defined (VMIN) +# define VMIN VEOF +#endif + +#if !defined (VTIME) +# define VTIME VEOL +#endif + +#if defined (TERMIOS_TTY_DRIVER) +# define TIOTYPE struct termios +# define DRAIN_OUTPUT(fd) tcdrain (fd) +# define GETATTR(tty, tiop) (tcgetattr (tty, tiop)) +# ifdef M_UNIX +# define SETATTR(tty, tiop) (tcsetattr (tty, TCSANOW, tiop)) +# else +# define SETATTR(tty, tiop) (tcsetattr (tty, TCSADRAIN, tiop)) +# endif /* !M_UNIX */ +#else +# define TIOTYPE struct termio +# define DRAIN_OUTPUT(fd) +# define GETATTR(tty, tiop) (ioctl (tty, TCGETA, tiop)) +# define SETATTR(tty, tiop) (ioctl (tty, TCSETAW, tiop)) +#endif /* !TERMIOS_TTY_DRIVER */ + +static TIOTYPE otio; + +static void save_tty_chars PARAMS((TIOTYPE *)); +static int _get_tty_settings PARAMS((int, TIOTYPE *)); +static int get_tty_settings PARAMS((int, TIOTYPE *)); +static int _set_tty_settings PARAMS((int, TIOTYPE *)); +static int set_tty_settings PARAMS((int, TIOTYPE *)); + +static void prepare_terminal_settings PARAMS((int, TIOTYPE, TIOTYPE *)); + +static void set_special_char PARAMS((Keymap, TIOTYPE *, int, rl_command_func_t)); +static void _rl_bind_tty_special_chars PARAMS((Keymap, TIOTYPE)); + +#if defined (FLUSHO) +# define OUTPUT_BEING_FLUSHED(tp) (tp->c_lflag & FLUSHO) +#else +# define OUTPUT_BEING_FLUSHED(tp) 0 +#endif + +static void +save_tty_chars (tiop) + TIOTYPE *tiop; +{ + _rl_last_tty_chars = _rl_tty_chars; + + _rl_tty_chars.t_eof = tiop->c_cc[VEOF]; + _rl_tty_chars.t_eol = tiop->c_cc[VEOL]; +#ifdef VEOL2 + _rl_tty_chars.t_eol2 = tiop->c_cc[VEOL2]; +#endif + _rl_tty_chars.t_erase = tiop->c_cc[VERASE]; +#ifdef VWERASE + _rl_tty_chars.t_werase = tiop->c_cc[VWERASE]; +#endif + _rl_tty_chars.t_kill = tiop->c_cc[VKILL]; +#ifdef VREPRINT + _rl_tty_chars.t_reprint = tiop->c_cc[VREPRINT]; +#endif + _rl_intr_char = _rl_tty_chars.t_intr = tiop->c_cc[VINTR]; + _rl_quit_char = _rl_tty_chars.t_quit = tiop->c_cc[VQUIT]; +#ifdef VSUSP + _rl_susp_char = _rl_tty_chars.t_susp = tiop->c_cc[VSUSP]; +#endif +#ifdef VDSUSP + _rl_tty_chars.t_dsusp = tiop->c_cc[VDSUSP]; +#endif +#ifdef VSTART + _rl_tty_chars.t_start = tiop->c_cc[VSTART]; +#endif +#ifdef VSTOP + _rl_tty_chars.t_stop = tiop->c_cc[VSTOP]; +#endif +#ifdef VLNEXT + _rl_tty_chars.t_lnext = tiop->c_cc[VLNEXT]; +#endif +#ifdef VDISCARD + _rl_tty_chars.t_flush = tiop->c_cc[VDISCARD]; +#endif +#ifdef VSTATUS + _rl_tty_chars.t_status = tiop->c_cc[VSTATUS]; +#endif +} + +#if defined (_AIX) || defined (_AIX41) +/* Currently this is only used on AIX */ +static void +rltty_warning (msg) + char *msg; +{ + _rl_errmsg ("warning: %s", msg); +} +#endif + +#if defined (_AIX) +void +setopost(tp) +TIOTYPE *tp; +{ + if ((tp->c_oflag & OPOST) == 0) + { + _rl_errmsg ("warning: turning on OPOST for terminal\r"); + tp->c_oflag |= OPOST|ONLCR; + } +} +#endif + +static int +_get_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + int ioctl_ret; + + while (1) + { + ioctl_ret = GETATTR (tty, tiop); + if (ioctl_ret < 0) + { + if (errno != EINTR) + return -1; + else + continue; + } + if (OUTPUT_BEING_FLUSHED (tiop)) + { +#if defined (FLUSHO) + _rl_errmsg ("warning: turning off output flushing"); + tiop->c_lflag &= ~FLUSHO; + break; +#else + continue; +#endif + } + break; + } + + return 0; +} + +static int +get_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + set_winsize (tty); + + errno = 0; + if (_get_tty_settings (tty, tiop) < 0) + return -1; + +#if defined (_AIX) + setopost(tiop); +#endif + + return 0; +} + +static int +_set_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + while (SETATTR (tty, tiop) < 0) + { + if (errno != EINTR) + return -1; + errno = 0; + } + return 0; +} + +static int +set_tty_settings (tty, tiop) + int tty; + TIOTYPE *tiop; +{ + if (_set_tty_settings (tty, tiop) < 0) + return -1; + +#if 0 + +#if defined (TERMIOS_TTY_DRIVER) +# if defined (__ksr1__) + if (ksrflow) + { + ksrflow = 0; + tcflow (tty, TCOON); + } +# else /* !ksr1 */ + tcflow (tty, TCOON); /* Simulate a ^Q. */ +# endif /* !ksr1 */ +#else + ioctl (tty, TCXONC, 1); /* Simulate a ^Q. */ +#endif /* !TERMIOS_TTY_DRIVER */ + +#endif /* 0 */ + + return 0; +} + +static void +prepare_terminal_settings (meta_flag, oldtio, tiop) + int meta_flag; + TIOTYPE oldtio, *tiop; +{ + _rl_echoing_p = (oldtio.c_lflag & ECHO); +#if defined (ECHOCTL) + _rl_echoctl = (oldtio.c_lflag & ECHOCTL); +#endif + + tiop->c_lflag &= ~(ICANON | ECHO); + + if ((unsigned char) oldtio.c_cc[VEOF] != (unsigned char) _POSIX_VDISABLE) + _rl_eof_char = oldtio.c_cc[VEOF]; + +#if defined (USE_XON_XOFF) +#if defined (IXANY) + tiop->c_iflag &= ~(IXON | IXANY); +#else + /* `strict' Posix systems do not define IXANY. */ + tiop->c_iflag &= ~IXON; +#endif /* IXANY */ +#endif /* USE_XON_XOFF */ + + /* Only turn this off if we are using all 8 bits. */ + if (((tiop->c_cflag & CSIZE) == CS8) || meta_flag) + tiop->c_iflag &= ~(ISTRIP | INPCK); + + /* Make sure we differentiate between CR and NL on input. */ + tiop->c_iflag &= ~(ICRNL | INLCR); + +#if !defined (HANDLE_SIGNALS) + tiop->c_lflag &= ~ISIG; +#else + tiop->c_lflag |= ISIG; +#endif + + tiop->c_cc[VMIN] = 1; + tiop->c_cc[VTIME] = 0; + +#if defined (FLUSHO) + if (OUTPUT_BEING_FLUSHED (tiop)) + { + tiop->c_lflag &= ~FLUSHO; + oldtio.c_lflag &= ~FLUSHO; + } +#endif + + /* Turn off characters that we need on Posix systems with job control, + just to be sure. This includes ^Y and ^V. This should not really + be necessary. */ +#if defined (TERMIOS_TTY_DRIVER) && defined (_POSIX_VDISABLE) + +#if defined (VLNEXT) + tiop->c_cc[VLNEXT] = _POSIX_VDISABLE; +#endif + +#if defined (VDSUSP) + tiop->c_cc[VDSUSP] = _POSIX_VDISABLE; +#endif + +#endif /* TERMIOS_TTY_DRIVER && _POSIX_VDISABLE */ +} +#endif /* !NEW_TTY_DRIVER */ + +/* Put the terminal in CBREAK mode so that we can detect key presses. */ +#if defined (NO_TTY_DRIVER) +void +rl_prep_terminal (meta_flag) + int meta_flag; +{ + _rl_echoing_p = 1; +} + +void +rl_deprep_terminal () +{ +} + +#else /* ! NO_TTY_DRIVER */ +void +rl_prep_terminal (meta_flag) + int meta_flag; +{ + int tty; + TIOTYPE tio; + + if (terminal_prepped) + return; + + /* Try to keep this function from being INTerrupted. */ + _rl_block_sigint (); + + tty = rl_instream ? fileno (rl_instream) : fileno (stdin); + + if (get_tty_settings (tty, &tio) < 0) + { +#if defined (ENOTSUP) + /* MacOS X and Linux, at least, lie about the value of errno if + tcgetattr fails. */ + if (errno == ENOTTY || errno == EINVAL || errno == ENOTSUP) +#else + if (errno == ENOTTY || errno == EINVAL) +#endif + _rl_echoing_p = 1; /* XXX */ + + _rl_release_sigint (); + return; + } + + otio = tio; + + if (_rl_bind_stty_chars) + { +#if defined (VI_MODE) + /* If editing in vi mode, make sure we restore the bindings in the + insertion keymap no matter what keymap we ended up in. */ + if (rl_editing_mode == vi_mode) + rl_tty_unset_default_bindings (vi_insertion_keymap); + else +#endif + rl_tty_unset_default_bindings (_rl_keymap); + } + save_tty_chars (&otio); + RL_SETSTATE(RL_STATE_TTYCSAVED); + if (_rl_bind_stty_chars) + { +#if defined (VI_MODE) + /* If editing in vi mode, make sure we set the bindings in the + insertion keymap no matter what keymap we ended up in. */ + if (rl_editing_mode == vi_mode) + _rl_bind_tty_special_chars (vi_insertion_keymap, tio); + else +#endif + _rl_bind_tty_special_chars (_rl_keymap, tio); + } + + prepare_terminal_settings (meta_flag, otio, &tio); + + if (set_tty_settings (tty, &tio) < 0) + { + _rl_release_sigint (); + return; + } + + if (_rl_enable_keypad) + _rl_control_keypad (1); + + fflush (rl_outstream); + terminal_prepped = 1; + RL_SETSTATE(RL_STATE_TERMPREPPED); + + _rl_release_sigint (); +} + +/* Restore the terminal's normal settings and modes. */ +void +rl_deprep_terminal () +{ + int tty; + + if (!terminal_prepped) + return; + + /* Try to keep this function from being interrupted. */ + _rl_block_sigint (); + + tty = rl_instream ? fileno (rl_instream) : fileno (stdin); + + if (_rl_enable_keypad) + _rl_control_keypad (0); + + fflush (rl_outstream); + + if (set_tty_settings (tty, &otio) < 0) + { + _rl_release_sigint (); + return; + } + + terminal_prepped = 0; + RL_UNSETSTATE(RL_STATE_TERMPREPPED); + + _rl_release_sigint (); +} +#endif /* !NO_TTY_DRIVER */ + +/* **************************************************************** */ +/* */ +/* Bogus Flow Control */ +/* */ +/* **************************************************************** */ + +int +rl_restart_output (count, key) + int count, key; +{ +#if defined (__MINGW32__) + return 0; +#else /* !__MING32__ */ + + int fildes = fileno (rl_outstream); +#if defined (TIOCSTART) +#if defined (apollo) + ioctl (&fildes, TIOCSTART, 0); +#else + ioctl (fildes, TIOCSTART, 0); +#endif /* apollo */ + +#else /* !TIOCSTART */ +# if defined (TERMIOS_TTY_DRIVER) +# if defined (__ksr1__) + if (ksrflow) + { + ksrflow = 0; + tcflow (fildes, TCOON); + } +# else /* !ksr1 */ + tcflow (fildes, TCOON); /* Simulate a ^Q. */ +# endif /* !ksr1 */ +# else /* !TERMIOS_TTY_DRIVER */ +# if defined (TCXONC) + ioctl (fildes, TCXONC, TCOON); +# endif /* TCXONC */ +# endif /* !TERMIOS_TTY_DRIVER */ +#endif /* !TIOCSTART */ + + return 0; +#endif /* !__MINGW32__ */ +} + +int +rl_stop_output (count, key) + int count, key; +{ +#if defined (__MINGW32__) + return 0; +#else + + int fildes = fileno (rl_instream); + +#if defined (TIOCSTOP) +# if defined (apollo) + ioctl (&fildes, TIOCSTOP, 0); +# else + ioctl (fildes, TIOCSTOP, 0); +# endif /* apollo */ +#else /* !TIOCSTOP */ +# if defined (TERMIOS_TTY_DRIVER) +# if defined (__ksr1__) + ksrflow = 1; +# endif /* ksr1 */ + tcflow (fildes, TCOOFF); +# else +# if defined (TCXONC) + ioctl (fildes, TCXONC, TCOON); +# endif /* TCXONC */ +# endif /* !TERMIOS_TTY_DRIVER */ +#endif /* !TIOCSTOP */ + + return 0; +#endif /* !__MINGW32__ */ +} + +/* **************************************************************** */ +/* */ +/* Default Key Bindings */ +/* */ +/* **************************************************************** */ + +#if !defined (NO_TTY_DRIVER) +#define SET_SPECIAL(sc, func) set_special_char(kmap, &ttybuff, sc, func) +#endif + +#if defined (NO_TTY_DRIVER) + +#define SET_SPECIAL(sc, func) +#define RESET_SPECIAL(c) + +#elif defined (NEW_TTY_DRIVER) +static void +set_special_char (kmap, tiop, sc, func) + Keymap kmap; + TIOTYPE *tiop; + int sc; + rl_command_func_t *func; +{ + if (sc != -1 && kmap[(unsigned char)sc].type == ISFUNC) + kmap[(unsigned char)sc].function = func; +} + +#define RESET_SPECIAL(c) \ + if (c != -1 && kmap[(unsigned char)c].type == ISFUNC) \ + kmap[(unsigned char)c].function = rl_insert; + +static void +_rl_bind_tty_special_chars (kmap, ttybuff) + Keymap kmap; + TIOTYPE ttybuff; +{ + if (ttybuff.flags & SGTTY_SET) + { + SET_SPECIAL (ttybuff.sgttyb.sg_erase, rl_rubout); + SET_SPECIAL (ttybuff.sgttyb.sg_kill, rl_unix_line_discard); + } + +# if defined (TIOCGLTC) + if (ttybuff.flags & LTCHARS_SET) + { + SET_SPECIAL (ttybuff.ltchars.t_werasc, rl_unix_word_rubout); + SET_SPECIAL (ttybuff.ltchars.t_lnextc, rl_quoted_insert); + } +# endif /* TIOCGLTC */ +} + +#else /* !NEW_TTY_DRIVER */ +static void +set_special_char (kmap, tiop, sc, func) + Keymap kmap; + TIOTYPE *tiop; + int sc; + rl_command_func_t *func; +{ + unsigned char uc; + + uc = tiop->c_cc[sc]; + if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) + kmap[uc].function = func; +} + +/* used later */ +#define RESET_SPECIAL(uc) \ + if (uc != (unsigned char)_POSIX_VDISABLE && kmap[uc].type == ISFUNC) \ + kmap[uc].function = rl_insert; + +static void +_rl_bind_tty_special_chars (kmap, ttybuff) + Keymap kmap; + TIOTYPE ttybuff; +{ + SET_SPECIAL (VERASE, rl_rubout); + SET_SPECIAL (VKILL, rl_unix_line_discard); + +# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) + SET_SPECIAL (VLNEXT, rl_quoted_insert); +# endif /* VLNEXT && TERMIOS_TTY_DRIVER */ + +# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) + SET_SPECIAL (VWERASE, rl_unix_word_rubout); +# endif /* VWERASE && TERMIOS_TTY_DRIVER */ +} + +#endif /* !NEW_TTY_DRIVER */ + +/* Set the system's default editing characters to their readline equivalents + in KMAP. Should be static, now that we have rl_tty_set_default_bindings. */ +void +rltty_set_default_bindings (kmap) + Keymap kmap; +{ +#if !defined (NO_TTY_DRIVER) + TIOTYPE ttybuff; + int tty; + + tty = fileno (rl_instream); + + if (get_tty_settings (tty, &ttybuff) == 0) + _rl_bind_tty_special_chars (kmap, ttybuff); +#endif +} + +/* New public way to set the system default editing chars to their readline + equivalents. */ +void +rl_tty_set_default_bindings (kmap) + Keymap kmap; +{ + rltty_set_default_bindings (kmap); +} + +/* Rebind all of the tty special chars that readline worries about back + to self-insert. Call this before saving the current terminal special + chars with save_tty_chars(). This only works on POSIX termios or termio + systems. */ +void +rl_tty_unset_default_bindings (kmap) + Keymap kmap; +{ + /* Don't bother before we've saved the tty special chars at least once. */ + if (RL_ISSTATE(RL_STATE_TTYCSAVED) == 0) + return; + + RESET_SPECIAL (_rl_tty_chars.t_erase); + RESET_SPECIAL (_rl_tty_chars.t_kill); + +# if defined (VLNEXT) && defined (TERMIOS_TTY_DRIVER) + RESET_SPECIAL (_rl_tty_chars.t_lnext); +# endif /* VLNEXT && TERMIOS_TTY_DRIVER */ + +# if defined (VWERASE) && defined (TERMIOS_TTY_DRIVER) + RESET_SPECIAL (_rl_tty_chars.t_werase); +# endif /* VWERASE && TERMIOS_TTY_DRIVER */ +} + +#if defined (HANDLE_SIGNALS) + +#if defined (NEW_TTY_DRIVER) || defined (NO_TTY_DRIVER) +int +_rl_disable_tty_signals () +{ + return 0; +} + +int +_rl_restore_tty_signals () +{ + return 0; +} +#else + +static TIOTYPE sigstty, nosigstty; +static int tty_sigs_disabled = 0; + +int +_rl_disable_tty_signals () +{ + if (tty_sigs_disabled) + return 0; + + if (_get_tty_settings (fileno (rl_instream), &sigstty) < 0) + return -1; + + nosigstty = sigstty; + + nosigstty.c_lflag &= ~ISIG; + nosigstty.c_iflag &= ~IXON; + + if (_set_tty_settings (fileno (rl_instream), &nosigstty) < 0) + return (_set_tty_settings (fileno (rl_instream), &sigstty)); + + tty_sigs_disabled = 1; + return 0; +} + +int +_rl_restore_tty_signals () +{ + int r; + + if (tty_sigs_disabled == 0) + return 0; + + r = _set_tty_settings (fileno (rl_instream), &sigstty); + + if (r == 0) + tty_sigs_disabled = 0; + + return r; +} +#endif /* !NEW_TTY_DRIVER */ + +#endif /* HANDLE_SIGNALS */ diff --git a/pcomplete.c b/pcomplete.c index 6b4e03323..a3327ed53 100644 --- a/pcomplete.c +++ b/pcomplete.c @@ -744,7 +744,8 @@ pcomp_filename_completion_function (text, state) (rl_completion_found_quote == 0). */ iscompgen = this_shell_builtin == compgen_builtin; iscompleting = RL_ISSTATE (RL_STATE_COMPLETING); - if (iscompgen && iscompleting == 0 && rl_completion_found_quote == 0) + if (iscompgen && iscompleting == 0 && rl_completion_found_quote == 0 + && rl_filename_dequoting_function) { /* Use rl_completion_quote_character because any single or double quotes have been removed by the time TEXT makes it diff --git a/pcomplete.c~ b/pcomplete.c~ new file mode 100644 index 000000000..6b4e03323 --- /dev/null +++ b/pcomplete.c~ @@ -0,0 +1,1631 @@ +/* pcomplete.c - functions to generate lists of matches for programmable completion. */ + +/* Copyright (C) 1999-2012 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bash. If not, see . +*/ + +#include + +#if defined (PROGRAMMABLE_COMPLETION) + +#include "bashtypes.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include + +#if defined (PREFER_STDARG) +# include +#else +# include +#endif + +#include + +#include +#include "bashansi.h" +#include "bashintl.h" + +#include "shell.h" +#include "pcomplete.h" +#include "alias.h" +#include "bashline.h" +#include "execute_cmd.h" +#include "pathexp.h" + +#if defined (JOB_CONTROL) +# include "jobs.h" +#endif + +#if !defined (NSIG) +# include "trap.h" +#endif + +#include "shmbutil.h" + +#include "builtins.h" +#include "builtins/common.h" +#include "builtins/builtext.h" + +#include +#include + +#include +#include +#include + +#define PCOMP_RETRYFAIL 256 + +#ifdef STRDUP +# undef STRDUP +#endif +#define STRDUP(x) ((x) ? savestring (x) : (char *)NULL) + +typedef SHELL_VAR **SVFUNC (); + +#ifndef HAVE_STRPBRK +extern char *strpbrk __P((char *, char *)); +#endif + +extern int array_needs_making; +extern STRING_INT_ALIST word_token_alist[]; +extern char *signal_names[]; +extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin; + +#if defined (DEBUG) +#if defined (PREFER_STDARG) +static void debug_printf (const char *, ...) __attribute__((__format__ (printf, 1, 2))); +#endif +#endif /* DEBUG */ + +static int it_init_joblist __P((ITEMLIST *, int)); + +static int it_init_aliases __P((ITEMLIST *)); +static int it_init_arrayvars __P((ITEMLIST *)); +static int it_init_bindings __P((ITEMLIST *)); +static int it_init_builtins __P((ITEMLIST *)); +static int it_init_disabled __P((ITEMLIST *)); +static int it_init_enabled __P((ITEMLIST *)); +static int it_init_exported __P((ITEMLIST *)); +static int it_init_functions __P((ITEMLIST *)); +static int it_init_helptopics __P((ITEMLIST *)); +static int it_init_hostnames __P((ITEMLIST *)); +static int it_init_jobs __P((ITEMLIST *)); +static int it_init_running __P((ITEMLIST *)); +static int it_init_stopped __P((ITEMLIST *)); +static int it_init_keywords __P((ITEMLIST *)); +static int it_init_signals __P((ITEMLIST *)); +static int it_init_variables __P((ITEMLIST *)); +static int it_init_setopts __P((ITEMLIST *)); +static int it_init_shopts __P((ITEMLIST *)); + +static int shouldexp_filterpat __P((char *)); +static char *preproc_filterpat __P((char *, char *)); + +static void init_itemlist_from_varlist __P((ITEMLIST *, SVFUNC *)); + +static STRINGLIST *gen_matches_from_itemlist __P((ITEMLIST *, const char *)); +static STRINGLIST *gen_action_completions __P((COMPSPEC *, const char *)); +static STRINGLIST *gen_globpat_matches __P((COMPSPEC *, const char *)); +static STRINGLIST *gen_wordlist_matches __P((COMPSPEC *, const char *)); +static STRINGLIST *gen_shell_function_matches __P((COMPSPEC *, const char *, + const char *, + char *, int, WORD_LIST *, + int, int, int *)); +static STRINGLIST *gen_command_matches __P((COMPSPEC *, const char *, + const char *, + char *, int, WORD_LIST *, + int, int)); + +static STRINGLIST *gen_progcomp_completions __P((const char *, const char *, + const char *, + int, int, int *, int *, + COMPSPEC **)); + +static char *pcomp_filename_completion_function __P((const char *, int)); + +#if defined (ARRAY_VARS) +static SHELL_VAR *bind_comp_words __P((WORD_LIST *)); +#endif +static void bind_compfunc_variables __P((char *, int, WORD_LIST *, int, int)); +static void unbind_compfunc_variables __P((int)); +static WORD_LIST *build_arg_list __P((char *, const char *, const char *, WORD_LIST *, int)); +static WORD_LIST *command_line_to_word_list __P((char *, int, int, int *, int *)); + +#ifdef DEBUG +static int progcomp_debug = 0; +#endif + +int prog_completion_enabled = 1; + +/* These are used to manage the arrays of strings for possible completions. */ +ITEMLIST it_aliases = { 0, it_init_aliases, (STRINGLIST *)0 }; +ITEMLIST it_arrayvars = { LIST_DYNAMIC, it_init_arrayvars, (STRINGLIST *)0 }; +ITEMLIST it_bindings = { 0, it_init_bindings, (STRINGLIST *)0 }; +ITEMLIST it_builtins = { 0, it_init_builtins, (STRINGLIST *)0 }; +ITEMLIST it_commands = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_directories = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_disabled = { 0, it_init_disabled, (STRINGLIST *)0 }; +ITEMLIST it_enabled = { 0, it_init_enabled, (STRINGLIST *)0 }; +ITEMLIST it_exports = { LIST_DYNAMIC, it_init_exported, (STRINGLIST *)0 }; +ITEMLIST it_files = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_functions = { 0, it_init_functions, (STRINGLIST *)0 }; +ITEMLIST it_helptopics = { 0, it_init_helptopics, (STRINGLIST *)0 }; +ITEMLIST it_hostnames = { LIST_DYNAMIC, it_init_hostnames, (STRINGLIST *)0 }; +ITEMLIST it_groups = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_jobs = { LIST_DYNAMIC, it_init_jobs, (STRINGLIST *)0 }; +ITEMLIST it_keywords = { 0, it_init_keywords, (STRINGLIST *)0 }; +ITEMLIST it_running = { LIST_DYNAMIC, it_init_running, (STRINGLIST *)0 }; +ITEMLIST it_services = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_setopts = { 0, it_init_setopts, (STRINGLIST *)0 }; +ITEMLIST it_shopts = { 0, it_init_shopts, (STRINGLIST *)0 }; +ITEMLIST it_signals = { 0, it_init_signals, (STRINGLIST *)0 }; +ITEMLIST it_stopped = { LIST_DYNAMIC, it_init_stopped, (STRINGLIST *)0 }; +ITEMLIST it_users = { LIST_DYNAMIC }; /* unused */ +ITEMLIST it_variables = { LIST_DYNAMIC, it_init_variables, (STRINGLIST *)0 }; + +COMPSPEC *pcomp_curcs; +const char *pcomp_curcmd; + +#ifdef DEBUG +/* Debugging code */ +static void +#if defined (PREFER_STDARG) +debug_printf (const char *format, ...) +#else +debug_printf (format, va_alist) + const char *format; + va_dcl +#endif +{ + va_list args; + + if (progcomp_debug == 0) + return; + + SH_VA_START (args, format); + + fprintf (stdout, "DEBUG: "); + vfprintf (stdout, format, args); + fprintf (stdout, "\n"); + + rl_on_new_line (); + + va_end (args); +} +#endif + +/* Functions to manage the item lists */ + +void +set_itemlist_dirty (it) + ITEMLIST *it; +{ + it->flags |= LIST_DIRTY; +} + +void +initialize_itemlist (itp) + ITEMLIST *itp; +{ + (*itp->list_getter) (itp); + itp->flags |= LIST_INITIALIZED; + itp->flags &= ~LIST_DIRTY; +} + +void +clean_itemlist (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + + sl = itp->slist; + if (sl) + { + if ((itp->flags & (LIST_DONTFREEMEMBERS|LIST_DONTFREE)) == 0) + strvec_flush (sl->list); + if ((itp->flags & LIST_DONTFREE) == 0) + free (sl->list); + free (sl); + } + itp->slist = (STRINGLIST *)NULL; + itp->flags &= ~(LIST_DONTFREE|LIST_DONTFREEMEMBERS|LIST_INITIALIZED|LIST_DIRTY); +} + + +static int +shouldexp_filterpat (s) + char *s; +{ + register char *p; + + for (p = s; p && *p; p++) + { + if (*p == '\\') + p++; + else if (*p == '&') + return 1; + } + return 0; +} + +/* Replace any instance of `&' in PAT with TEXT. Backslash may be used to + quote a `&' and inhibit substitution. Returns a new string. This just + calls stringlib.c:strcreplace(). */ +static char * +preproc_filterpat (pat, text) + char *pat; + char *text; +{ + char *ret; + + ret = strcreplace (pat, '&', text, 1); + return ret; +} + +/* Remove any match of FILTERPAT from SL. A `&' in FILTERPAT is replaced by + TEXT. A leading `!' in FILTERPAT negates the pattern; in this case + any member of SL->list that does *not* match will be removed. This returns + a new STRINGLIST with the matching members of SL *copied*. Any + non-matching members of SL->list are *freed*. */ +STRINGLIST * +filter_stringlist (sl, filterpat, text) + STRINGLIST *sl; + char *filterpat, *text; +{ + int i, m, not; + STRINGLIST *ret; + char *npat, *t; + + if (sl == 0 || sl->list == 0 || sl->list_len == 0) + return sl; + + npat = shouldexp_filterpat (filterpat) ? preproc_filterpat (filterpat, text) : filterpat; + + not = (npat[0] == '!'); + t = not ? npat + 1 : npat; + + ret = strlist_create (sl->list_size); + for (i = 0; i < sl->list_len; i++) + { + m = strmatch (t, sl->list[i], FNMATCH_EXTFLAG); + if ((not && m == FNM_NOMATCH) || (not == 0 && m != FNM_NOMATCH)) + free (sl->list[i]); + else + ret->list[ret->list_len++] = sl->list[i]; + } + + ret->list[ret->list_len] = (char *)NULL; + if (npat != filterpat) + free (npat); + + return ret; +} + +/* Turn an array of strings returned by rl_completion_matches into a STRINGLIST. + This understands how rl_completion_matches sets matches[0] (the lcd of the + strings in the list, unless it's the only match). */ +STRINGLIST * +completions_to_stringlist (matches) + char **matches; +{ + STRINGLIST *sl; + int mlen, i, n; + + mlen = (matches == 0) ? 0 : strvec_len (matches); + sl = strlist_create (mlen + 1); + + if (matches == 0 || matches[0] == 0) + return sl; + + if (matches[1] == 0) + { + sl->list[0] = STRDUP (matches[0]); + sl->list[sl->list_len = 1] = (char *)NULL; + return sl; + } + + for (i = 1, n = 0; i < mlen; i++, n++) + sl->list[n] = STRDUP (matches[i]); + sl->list_len = n; + sl->list[n] = (char *)NULL; + + return sl; +} + +/* Functions to manage the various ITEMLISTs that we populate internally. + The caller is responsible for setting ITP->flags correctly. */ + +static int +it_init_aliases (itp) + ITEMLIST *itp; +{ +#ifdef ALIAS + alias_t **alias_list; + register int i, n; + STRINGLIST *sl; + + alias_list = all_aliases (); + if (alias_list == 0) + { + itp->slist = (STRINGLIST *)NULL; + return 0; + } + for (n = 0; alias_list[n]; n++) + ; + sl = strlist_create (n+1); + for (i = 0; i < n; i++) + sl->list[i] = STRDUP (alias_list[i]->name); + sl->list[n] = (char *)NULL; + sl->list_size = sl->list_len = n; + itp->slist = sl; +#else + itp->slist = (STRINGLIST *)NULL; +#endif + free (alias_list); + return 1; +} + +static void +init_itemlist_from_varlist (itp, svfunc) + ITEMLIST *itp; + SVFUNC *svfunc; +{ + SHELL_VAR **vlist; + STRINGLIST *sl; + register int i, n; + + vlist = (*svfunc) (); + if (vlist == 0) + { + itp->slist = (STRINGLIST *)NULL; + return; + } + for (n = 0; vlist[n]; n++) + ; + sl = strlist_create (n+1); + for (i = 0; i < n; i++) + sl->list[i] = savestring (vlist[i]->name); + sl->list[sl->list_len = n] = (char *)NULL; + itp->slist = sl; +} + +static int +it_init_arrayvars (itp) + ITEMLIST *itp; +{ +#if defined (ARRAY_VARS) + init_itemlist_from_varlist (itp, all_array_variables); + return 1; +#else + return 0; +#endif +} + +static int +it_init_bindings (itp) + ITEMLIST *itp; +{ + char **blist; + STRINGLIST *sl; + + /* rl_funmap_names allocates blist, but not its members */ + blist = (char **)rl_funmap_names (); /* XXX fix const later */ + sl = strlist_create (0); + sl->list = blist; + sl->list_size = 0; + sl->list_len = strvec_len (sl->list); + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + + return 0; +} + +static int +it_init_builtins (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + register int i, n; + + sl = strlist_create (num_shell_builtins); + for (i = n = 0; i < num_shell_builtins; i++) + if (shell_builtins[i].function) + sl->list[n++] = shell_builtins[i].name; + sl->list[sl->list_len = n] = (char *)NULL; + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + return 0; +} + +static int +it_init_enabled (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + register int i, n; + + sl = strlist_create (num_shell_builtins); + for (i = n = 0; i < num_shell_builtins; i++) + { + if (shell_builtins[i].function && (shell_builtins[i].flags & BUILTIN_ENABLED)) + sl->list[n++] = shell_builtins[i].name; + } + sl->list[sl->list_len = n] = (char *)NULL; + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + return 0; +} + +static int +it_init_disabled (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + register int i, n; + + sl = strlist_create (num_shell_builtins); + for (i = n = 0; i < num_shell_builtins; i++) + { + if (shell_builtins[i].function && ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0)) + sl->list[n++] = shell_builtins[i].name; + } + sl->list[sl->list_len = n] = (char *)NULL; + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + return 0; +} + +static int +it_init_exported (itp) + ITEMLIST *itp; +{ + init_itemlist_from_varlist (itp, all_exported_variables); + return 0; +} + +static int +it_init_functions (itp) + ITEMLIST *itp; +{ + init_itemlist_from_varlist (itp, all_visible_functions); + return 0; +} + +/* Like it_init_builtins, but includes everything the help builtin looks at, + not just builtins with an active implementing function. */ +static int +it_init_helptopics (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + register int i, n; + + sl = strlist_create (num_shell_builtins); + for (i = n = 0; i < num_shell_builtins; i++) + sl->list[n++] = shell_builtins[i].name; + sl->list[sl->list_len = n] = (char *)NULL; + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + return 0; +} + +static int +it_init_hostnames (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + + sl = strlist_create (0); + sl->list = get_hostname_list (); + sl->list_len = sl->list ? strvec_len (sl->list) : 0; + sl->list_size = sl->list_len; + itp->slist = sl; + itp->flags |= LIST_DONTFREEMEMBERS|LIST_DONTFREE; + return 0; +} + +static int +it_init_joblist (itp, jstate) + ITEMLIST *itp; + int jstate; +{ +#if defined (JOB_CONTROL) + STRINGLIST *sl; + register int i; + register PROCESS *p; + char *s, *t; + JOB *j; + JOB_STATE ws; /* wanted state */ + + ws = JNONE; + if (jstate == 0) + ws = JRUNNING; + else if (jstate == 1) + ws = JSTOPPED; + + sl = strlist_create (js.j_jobslots); + for (i = js.j_jobslots - 1; i >= 0; i--) + { + j = get_job_by_jid (i); + if (j == 0) + continue; + p = j->pipe; + if (jstate == -1 || JOBSTATE(i) == ws) + { + s = savestring (p->command); + t = strpbrk (s, " \t\n"); + if (t) + *t = '\0'; + sl->list[sl->list_len++] = s; + } + } + itp->slist = sl; +#else + itp->slist = (STRINGLIST *)NULL; +#endif + return 0; +} + +static int +it_init_jobs (itp) + ITEMLIST *itp; +{ + return (it_init_joblist (itp, -1)); +} + +static int +it_init_running (itp) + ITEMLIST *itp; +{ + return (it_init_joblist (itp, 0)); +} + +static int +it_init_stopped (itp) + ITEMLIST *itp; +{ + return (it_init_joblist (itp, 1)); +} + +static int +it_init_keywords (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + register int i, n; + + for (n = 0; word_token_alist[n].word; n++) + ; + sl = strlist_create (n); + for (i = 0; i < n; i++) + sl->list[i] = word_token_alist[i].word; + sl->list[sl->list_len = i] = (char *)NULL; + itp->flags |= LIST_DONTFREEMEMBERS; + itp->slist = sl; + return 0; +} + +static int +it_init_signals (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + + sl = strlist_create (0); + sl->list = signal_names; + sl->list_len = strvec_len (sl->list); + itp->flags |= LIST_DONTFREE; + itp->slist = sl; + return 0; +} + +static int +it_init_variables (itp) + ITEMLIST *itp; +{ + init_itemlist_from_varlist (itp, all_visible_variables); + return 0; +} + +static int +it_init_setopts (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + + sl = strlist_create (0); + sl->list = get_minus_o_opts (); + sl->list_len = strvec_len (sl->list); + itp->slist = sl; + itp->flags |= LIST_DONTFREEMEMBERS; + return 0; +} + +static int +it_init_shopts (itp) + ITEMLIST *itp; +{ + STRINGLIST *sl; + + sl = strlist_create (0); + sl->list = get_shopt_options (); + sl->list_len = strvec_len (sl->list); + itp->slist = sl; + itp->flags |= LIST_DONTFREEMEMBERS; + return 0; +} + +/* Generate a list of all matches for TEXT using the STRINGLIST in itp->slist + as the list of possibilities. If the itemlist has been marked dirty or + it should be regenerated every time, destroy the old STRINGLIST and make a + new one before trying the match. TEXT is dequoted before attempting a + match. */ +static STRINGLIST * +gen_matches_from_itemlist (itp, text) + ITEMLIST *itp; + const char *text; +{ + STRINGLIST *ret, *sl; + int tlen, i, n; + char *ntxt; + + if ((itp->flags & (LIST_DIRTY|LIST_DYNAMIC)) || + (itp->flags & LIST_INITIALIZED) == 0) + { + if (itp->flags & (LIST_DIRTY|LIST_DYNAMIC)) + clean_itemlist (itp); + if ((itp->flags & LIST_INITIALIZED) == 0) + initialize_itemlist (itp); + } + if (itp->slist == 0) + return ((STRINGLIST *)NULL); + ret = strlist_create (itp->slist->list_len+1); + sl = itp->slist; + + ntxt = bash_dequote_text (text); + tlen = STRLEN (ntxt); + + for (i = n = 0; i < sl->list_len; i++) + { + if (tlen == 0 || STREQN (sl->list[i], ntxt, tlen)) + ret->list[n++] = STRDUP (sl->list[i]); + } + ret->list[ret->list_len = n] = (char *)NULL; + + FREE (ntxt); + return ret; +} + +/* A wrapper for rl_filename_completion_function that dequotes the filename + before attempting completions. */ +static char * +pcomp_filename_completion_function (text, state) + const char *text; + int state; +{ + static char *dfn; /* dequoted filename */ + int qc; + int iscompgen, iscompleting; + + if (state == 0) + { + FREE (dfn); + /* remove backslashes quoting special characters in filenames. */ + /* There are roughly three paths we can follow to get here: + 1. complete -f + 2. compgen -f "$word" from a completion function + 3. compgen -f "$word" from the command line + They all need to be handled. + + In the first two cases, readline will run the filename dequoting + function in rl_filename_completion_function if it found a filename + quoting character in the word to be completed + (rl_completion_found_quote). We run the dequoting function here + if we're running compgen, we're not completing, and the + rl_filename_completion_function won't dequote the filename + (rl_completion_found_quote == 0). */ + iscompgen = this_shell_builtin == compgen_builtin; + iscompleting = RL_ISSTATE (RL_STATE_COMPLETING); + if (iscompgen && iscompleting == 0 && rl_completion_found_quote == 0) + { + /* Use rl_completion_quote_character because any single or + double quotes have been removed by the time TEXT makes it + here, and we don't want to remove backslashes inside + quoted strings. */ + dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character); + } + else + dfn = savestring (text); + } + + return (rl_filename_completion_function (dfn, state)); +} + +#define GEN_COMPS(bmap, flag, it, text, glist, tlist) \ + do { \ + if (bmap & flag) \ + { \ + tlist = gen_matches_from_itemlist (it, text); \ + if (tlist) \ + { \ + glist = strlist_append (glist, tlist); \ + strlist_dispose (tlist); \ + } \ + } \ + } while (0) + +#define GEN_XCOMPS(bmap, flag, text, func, cmatches, glist, tlist) \ + do { \ + if (bmap & flag) \ + { \ + cmatches = rl_completion_matches (text, func); \ + tlist = completions_to_stringlist (cmatches); \ + glist = strlist_append (glist, tlist); \ + strvec_dispose (cmatches); \ + strlist_dispose (tlist); \ + } \ + } while (0) + +/* Functions to generate lists of matches from the actions member of CS. */ + +static STRINGLIST * +gen_action_completions (cs, text) + COMPSPEC *cs; + const char *text; +{ + STRINGLIST *ret, *tmatches; + char **cmatches; /* from rl_completion_matches ... */ + unsigned long flags; + int t; + + ret = tmatches = (STRINGLIST *)NULL; + flags = cs->actions; + + GEN_COMPS (flags, CA_ALIAS, &it_aliases, text, ret, tmatches); + GEN_COMPS (flags, CA_ARRAYVAR, &it_arrayvars, text, ret, tmatches); + GEN_COMPS (flags, CA_BINDING, &it_bindings, text, ret, tmatches); + GEN_COMPS (flags, CA_BUILTIN, &it_builtins, text, ret, tmatches); + GEN_COMPS (flags, CA_DISABLED, &it_disabled, text, ret, tmatches); + GEN_COMPS (flags, CA_ENABLED, &it_enabled, text, ret, tmatches); + GEN_COMPS (flags, CA_EXPORT, &it_exports, text, ret, tmatches); + GEN_COMPS (flags, CA_FUNCTION, &it_functions, text, ret, tmatches); + GEN_COMPS (flags, CA_HELPTOPIC, &it_helptopics, text, ret, tmatches); + GEN_COMPS (flags, CA_HOSTNAME, &it_hostnames, text, ret, tmatches); + GEN_COMPS (flags, CA_JOB, &it_jobs, text, ret, tmatches); + GEN_COMPS (flags, CA_KEYWORD, &it_keywords, text, ret, tmatches); + GEN_COMPS (flags, CA_RUNNING, &it_running, text, ret, tmatches); + GEN_COMPS (flags, CA_SETOPT, &it_setopts, text, ret, tmatches); + GEN_COMPS (flags, CA_SHOPT, &it_shopts, text, ret, tmatches); + GEN_COMPS (flags, CA_SIGNAL, &it_signals, text, ret, tmatches); + GEN_COMPS (flags, CA_STOPPED, &it_stopped, text, ret, tmatches); + GEN_COMPS (flags, CA_VARIABLE, &it_variables, text, ret, tmatches); + + GEN_XCOMPS(flags, CA_COMMAND, text, command_word_completion_function, cmatches, ret, tmatches); + GEN_XCOMPS(flags, CA_FILE, text, pcomp_filename_completion_function, cmatches, ret, tmatches); + GEN_XCOMPS(flags, CA_USER, text, rl_username_completion_function, cmatches, ret, tmatches); + GEN_XCOMPS(flags, CA_GROUP, text, bash_groupname_completion_function, cmatches, ret, tmatches); + GEN_XCOMPS(flags, CA_SERVICE, text, bash_servicename_completion_function, cmatches, ret, tmatches); + + /* And lastly, the special case for directories */ + if (flags & CA_DIRECTORY) + { + t = rl_filename_completion_desired; + rl_completion_mark_symlink_dirs = 1; /* override user preference */ + cmatches = bash_directory_completion_matches (text); + /* If we did not want filename completion before this, and there are + no matches, turn off rl_filename_completion_desired so whatever + matches we get are not treated as filenames (it gets turned on by + rl_filename_completion_function unconditionally). */ + if (t == 0 && cmatches == 0 && rl_filename_completion_desired == 1) + rl_filename_completion_desired = 0; + tmatches = completions_to_stringlist (cmatches); + ret = strlist_append (ret, tmatches); + strvec_dispose (cmatches); + strlist_dispose (tmatches); + } + + return ret; +} + +/* Generate a list of matches for CS->globpat. Unresolved: should this use + TEXT as a match prefix, or just go without? Currently, the code does not + use TEXT, just globs CS->globpat and returns the results. If we do decide + to use TEXT, we should call quote_string_for_globbing before the call to + glob_filename. */ +static STRINGLIST * +gen_globpat_matches (cs, text) + COMPSPEC *cs; + const char *text; +{ + STRINGLIST *sl; + + sl = strlist_create (0); + sl->list = glob_filename (cs->globpat, 0); + if (GLOB_FAILED (sl->list)) + sl->list = (char **)NULL; + if (sl->list) + sl->list_len = sl->list_size = strvec_len (sl->list); + return sl; +} + +/* Perform the shell word expansions on CS->words and return the results. + Again, this ignores TEXT. */ +static STRINGLIST * +gen_wordlist_matches (cs, text) + COMPSPEC *cs; + const char *text; +{ + WORD_LIST *l, *l2; + STRINGLIST *sl; + int nw, tlen; + char *ntxt; /* dequoted TEXT to use in comparisons */ + + if (cs->words == 0 || cs->words[0] == '\0') + return ((STRINGLIST *)NULL); + + /* This used to be a simple expand_string(cs->words, 0), but that won't + do -- there's no way to split a simple list into individual words + that way, since the shell semantics say that word splitting is done + only on the results of expansion. split_at_delims also handles embedded + quoted strings and preserves the quotes for the expand_words_shellexp + function call that follows. */ + /* XXX - this is where this function spends most of its time */ + l = split_at_delims (cs->words, strlen (cs->words), (char *)NULL, -1, 0, (int *)NULL, (int *)NULL); + if (l == 0) + return ((STRINGLIST *)NULL); + /* This will jump back to the top level if the expansion fails... */ + l2 = expand_words_shellexp (l); + dispose_words (l); + + nw = list_length (l2); + sl = strlist_create (nw + 1); + + ntxt = bash_dequote_text (text); + tlen = STRLEN (ntxt); + + for (nw = 0, l = l2; l; l = l->next) + { + if (tlen == 0 || STREQN (l->word->word, ntxt, tlen)) + sl->list[nw++] = STRDUP (l->word->word); + } + sl->list[sl->list_len = nw] = (char *)NULL; + + dispose_words (l2); + FREE (ntxt); + return sl; +} + +#ifdef ARRAY_VARS + +static SHELL_VAR * +bind_comp_words (lwords) + WORD_LIST *lwords; +{ + SHELL_VAR *v; + + v = find_variable ("COMP_WORDS"); + if (v == 0) + v = make_new_array_variable ("COMP_WORDS"); + if (readonly_p (v)) + VUNSETATTR (v, att_readonly); + if (array_p (v) == 0) + v = convert_var_to_array (v); + v = assign_array_var_from_word_list (v, lwords, 0); + + VUNSETATTR (v, att_invisible); + return v; +} +#endif /* ARRAY_VARS */ + +static void +bind_compfunc_variables (line, ind, lwords, cw, exported) + char *line; + int ind; + WORD_LIST *lwords; + int cw, exported; +{ + char ibuf[INT_STRLEN_BOUND(int) + 1]; + char *value; + SHELL_VAR *v; + size_t llen; + int c; + + /* Set the variables that the function expects while it executes. Maybe + these should be in the function environment (temporary_env). */ + v = bind_variable ("COMP_LINE", line, 0); + if (v && exported) + VSETATTR(v, att_exported); + + /* Post bash-4.2: COMP_POINT is characters instead of bytes. */ + c = line[ind]; + line[ind] = '\0'; + llen = MB_STRLEN (line); + line[ind] = c; + value = inttostr (llen, ibuf, sizeof(ibuf)); + v = bind_int_variable ("COMP_POINT", value); + if (v && exported) + VSETATTR(v, att_exported); + + value = inttostr (rl_completion_type, ibuf, sizeof (ibuf)); + v = bind_int_variable ("COMP_TYPE", value); + if (v && exported) + VSETATTR(v, att_exported); + + value = inttostr (rl_completion_invoking_key, ibuf, sizeof (ibuf)); + v = bind_int_variable ("COMP_KEY", value); + if (v && exported) + VSETATTR(v, att_exported); + + /* Since array variables can't be exported, we don't bother making the + array of words. */ + if (exported == 0) + { +#ifdef ARRAY_VARS + v = bind_comp_words (lwords); + value = inttostr (cw, ibuf, sizeof(ibuf)); + bind_int_variable ("COMP_CWORD", value); +#endif + } + else + array_needs_making = 1; +} + +static void +unbind_compfunc_variables (exported) + int exported; +{ + unbind_variable ("COMP_LINE"); + unbind_variable ("COMP_POINT"); + unbind_variable ("COMP_TYPE"); + unbind_variable ("COMP_KEY"); +#ifdef ARRAY_VARS + unbind_variable ("COMP_WORDS"); + unbind_variable ("COMP_CWORD"); +#endif + if (exported) + array_needs_making = 1; +} + +/* Build the list of words to pass to a function or external command + as arguments. When the function or command is invoked, + + $0 == function or command being invoked + $1 == command name + $2 == word to be completed (possibly null) + $3 == previous word + + Functions can access all of the words in the current command line + with the COMP_WORDS array. External commands cannot; they have to + make do with the COMP_LINE and COMP_POINT variables. */ + +static WORD_LIST * +build_arg_list (cmd, cname, text, lwords, ind) + char *cmd; + const char *cname; + const char *text; + WORD_LIST *lwords; + int ind; +{ + WORD_LIST *ret, *cl, *l; + WORD_DESC *w; + int i; + + ret = (WORD_LIST *)NULL; + w = make_word (cmd); + ret = make_word_list (w, (WORD_LIST *)NULL); /* $0 */ + + w = make_word (cname); /* $1 */ + cl = ret->next = make_word_list (w, (WORD_LIST *)NULL); + + w = make_word (text); + cl->next = make_word_list (w, (WORD_LIST *)NULL); /* $2 */ + cl = cl->next; + + /* Search lwords for current word */ + for (l = lwords, i = 1; l && i < ind-1; l = l->next, i++) + ; + w = (l && l->word) ? copy_word (l->word) : make_word (""); + cl->next = make_word_list (w, (WORD_LIST *)NULL); + + return ret; +} + +/* Build a command string with + $0 == cs->funcname (function to execute for completion list) + $1 == command name (command being completed) + $2 = word to be completed (possibly null) + $3 = previous word + and run in the current shell. The function should put its completion + list into the array variable COMPREPLY. We build a STRINGLIST + from the results and return it. + + Since the shell function should return its list of matches in an array + variable, this does nothing if arrays are not compiled into the shell. */ + +static STRINGLIST * +gen_shell_function_matches (cs, cmd, text, line, ind, lwords, nw, cw, foundp) + COMPSPEC *cs; + const char *cmd; + const char *text; + char *line; + int ind; + WORD_LIST *lwords; + int nw, cw; + int *foundp; +{ + char *funcname; + STRINGLIST *sl; + SHELL_VAR *f, *v; + WORD_LIST *cmdlist; + int fval, found; + sh_parser_state_t ps; + sh_parser_state_t * restrict pps; +#if defined (ARRAY_VARS) + ARRAY *a; +#endif + + found = 0; + if (foundp) + *foundp = found; + + funcname = cs->funcname; + f = find_function (funcname); + if (f == 0) + { + internal_error (_("completion: function `%s' not found"), funcname); + rl_ding (); + rl_on_new_line (); + return ((STRINGLIST *)NULL); + } + +#if !defined (ARRAY_VARS) + return ((STRINGLIST *)NULL); +#else + + /* We pass cw - 1 because command_line_to_word_list returns indices that are + 1-based, while bash arrays are 0-based. */ + bind_compfunc_variables (line, ind, lwords, cw - 1, 0); + + cmdlist = build_arg_list (funcname, cmd, text, lwords, cw); + + pps = &ps; + save_parser_state (pps); + begin_unwind_frame ("gen-shell-function-matches"); + add_unwind_protect (restore_parser_state, (char *)pps); + add_unwind_protect (dispose_words, (char *)cmdlist); + add_unwind_protect (unbind_compfunc_variables, (char *)0); + + fval = execute_shell_function (f, cmdlist); + + discard_unwind_frame ("gen-shell-function-matches"); + restore_parser_state (pps); + + found = fval != EX_NOTFOUND; + if (fval == EX_RETRYFAIL) + found |= PCOMP_RETRYFAIL; + if (foundp) + *foundp = found; + + /* Now clean up and destroy everything. */ + dispose_words (cmdlist); + unbind_compfunc_variables (0); + + /* The list of completions is returned in the array variable COMPREPLY. */ + v = find_variable ("COMPREPLY"); + if (v == 0) + return ((STRINGLIST *)NULL); + if (array_p (v) == 0) + v = convert_var_to_array (v); + + VUNSETATTR (v, att_invisible); + + a = array_cell (v); + if (found == 0 || (found & PCOMP_RETRYFAIL) || a == 0 || array_empty (a)) + sl = (STRINGLIST *)NULL; + else + { + /* XXX - should we filter the list of completions so only those matching + TEXT are returned? Right now, we do not. */ + sl = strlist_create (0); + sl->list = array_to_argv (a); + sl->list_len = sl->list_size = array_num_elements (a); + } + + /* XXX - should we unbind COMPREPLY here? */ + unbind_variable ("COMPREPLY"); + + return (sl); +#endif +} + +/* Build a command string with + $0 == cs->command (command to execute for completion list) + $1 == command name (command being completed) + $2 = word to be completed (possibly null) + $3 = previous word + and run in with command substitution. Parse the results, one word + per line, with backslashes allowed to escape newlines. Build a + STRINGLIST from the results and return it. */ + +static STRINGLIST * +gen_command_matches (cs, cmd, text, line, ind, lwords, nw, cw) + COMPSPEC *cs; + const char *cmd; + const char *text; + char *line; + int ind; + WORD_LIST *lwords; + int nw, cw; +{ + char *csbuf, *cscmd, *t; + int cmdlen, cmdsize, n, ws, we; + WORD_LIST *cmdlist, *cl; + WORD_DESC *tw; + STRINGLIST *sl; + + bind_compfunc_variables (line, ind, lwords, cw, 1); + cmdlist = build_arg_list (cs->command, cmd, text, lwords, cw); + + /* Estimate the size needed for the buffer. */ + n = strlen (cs->command); + cmdsize = n + 1; + for (cl = cmdlist->next; cl; cl = cl->next) + cmdsize += STRLEN (cl->word->word) + 3; + cmdsize += 2; + + /* allocate the string for the command and fill it in. */ + cscmd = (char *)xmalloc (cmdsize + 1); + + strcpy (cscmd, cs->command); /* $0 */ + cmdlen = n; + cscmd[cmdlen++] = ' '; + for (cl = cmdlist->next; cl; cl = cl->next) /* $1, $2, $3, ... */ + { + t = sh_single_quote (cl->word->word ? cl->word->word : ""); + n = strlen (t); + RESIZE_MALLOCED_BUFFER (cscmd, cmdlen, n + 2, cmdsize, 64); + strcpy (cscmd + cmdlen, t); + cmdlen += n; + if (cl->next) + cscmd[cmdlen++] = ' '; + free (t); + } + cscmd[cmdlen] = '\0'; + + tw = command_substitute (cscmd, 0); + csbuf = tw ? tw->word : (char *)NULL; + if (tw) + dispose_word_desc (tw); + + /* Now clean up and destroy everything. */ + dispose_words (cmdlist); + free (cscmd); + unbind_compfunc_variables (1); + + if (csbuf == 0 || *csbuf == '\0') + { + FREE (csbuf); + return ((STRINGLIST *)NULL); + } + + /* Now break CSBUF up at newlines, with backslash allowed to escape a + newline, and put the individual words into a STRINGLIST. */ + sl = strlist_create (16); + for (ws = 0; csbuf[ws]; ) + { + we = ws; + while (csbuf[we] && csbuf[we] != '\n') + { + if (csbuf[we] == '\\' && csbuf[we+1] == '\n') + we++; + we++; + } + t = substring (csbuf, ws, we); + if (sl->list_len >= sl->list_size - 1) + strlist_resize (sl, sl->list_size + 16); + sl->list[sl->list_len++] = t; + while (csbuf[we] == '\n') we++; + ws = we; + } + sl->list[sl->list_len] = (char *)NULL; + + free (csbuf); + return (sl); +} + +static WORD_LIST * +command_line_to_word_list (line, llen, sentinel, nwp, cwp) + char *line; + int llen, sentinel, *nwp, *cwp; +{ + WORD_LIST *ret; + char *delims; + +#if 0 + delims = "()<>;&| \t\n"; /* shell metacharacters break words */ +#else + delims = rl_completer_word_break_characters; +#endif + ret = split_at_delims (line, llen, delims, sentinel, SD_NOQUOTEDELIM, nwp, cwp); + return (ret); +} + +/* Evaluate COMPSPEC *cs and return all matches for WORD. */ + +STRINGLIST * +gen_compspec_completions (cs, cmd, word, start, end, foundp) + COMPSPEC *cs; + const char *cmd; + const char *word; + int start, end; + int *foundp; +{ + STRINGLIST *ret, *tmatches; + char *line; + int llen, nw, cw, found, foundf; + WORD_LIST *lwords; + WORD_DESC *lw; + COMPSPEC *tcs; + + found = 1; + +#ifdef DEBUG + debug_printf ("gen_compspec_completions (%s, %s, %d, %d)", cmd, word, start, end); + debug_printf ("gen_compspec_completions: %s -> %p", cmd, cs); +#endif + ret = gen_action_completions (cs, word); +#ifdef DEBUG + if (ret && progcomp_debug) + { + debug_printf ("gen_action_completions (%p, %s) -->", cs, word); + strlist_print (ret, "\t"); + rl_on_new_line (); + } +#endif + + /* Now we start generating completions based on the other members of CS. */ + if (cs->globpat) + { + tmatches = gen_globpat_matches (cs, word); + if (tmatches) + { +#ifdef DEBUG + if (progcomp_debug) + { + debug_printf ("gen_globpat_matches (%p, %s) -->", cs, word); + strlist_print (tmatches, "\t"); + rl_on_new_line (); + } +#endif + ret = strlist_append (ret, tmatches); + strlist_dispose (tmatches); + rl_filename_completion_desired = 1; + } + } + + if (cs->words) + { + tmatches = gen_wordlist_matches (cs, word); + if (tmatches) + { +#ifdef DEBUG + if (progcomp_debug) + { + debug_printf ("gen_wordlist_matches (%p, %s) -->", cs, word); + strlist_print (tmatches, "\t"); + rl_on_new_line (); + } +#endif + ret = strlist_append (ret, tmatches); + strlist_dispose (tmatches); + } + } + + lwords = (WORD_LIST *)NULL; + line = (char *)NULL; + if (cs->command || cs->funcname) + { + /* If we have a command or function to execute, we need to first break + the command line into individual words, find the number of words, + and find the word in the list containing the word to be completed. */ + line = substring (rl_line_buffer, start, end); + llen = end - start; + +#ifdef DEBUG + debug_printf ("command_line_to_word_list (%s, %d, %d, %p, %p)", + line, llen, rl_point - start, &nw, &cw); +#endif + lwords = command_line_to_word_list (line, llen, rl_point - start, &nw, &cw); + /* If we skipped a NULL word at the beginning of the line, add it back */ + if (lwords && lwords->word && cmd[0] == 0 && lwords->word->word[0] != 0) + { + lw = make_bare_word (cmd); + lwords = make_word_list (lw, lwords); + nw++; + cw++; + } +#ifdef DEBUG + if (lwords == 0 && llen > 0) + debug_printf ("ERROR: command_line_to_word_list returns NULL"); + else if (progcomp_debug) + { + debug_printf ("command_line_to_word_list -->"); + printf ("\t"); + print_word_list (lwords, "!"); + printf ("\n"); + fflush(stdout); + rl_on_new_line (); + } +#endif + } + + if (cs->funcname) + { + foundf = 0; + tmatches = gen_shell_function_matches (cs, cmd, word, line, rl_point - start, lwords, nw, cw, &foundf); + if (foundf != 0) + found = foundf; + if (tmatches) + { +#ifdef DEBUG + if (progcomp_debug) + { + debug_printf ("gen_shell_function_matches (%p, %s, %s, %p, %d, %d) -->", cs, cmd, word, lwords, nw, cw); + strlist_print (tmatches, "\t"); + rl_on_new_line (); + } +#endif + ret = strlist_append (ret, tmatches); + strlist_dispose (tmatches); + } + } + + if (cs->command) + { + tmatches = gen_command_matches (cs, cmd, word, line, rl_point - start, lwords, nw, cw); + if (tmatches) + { +#ifdef DEBUG + if (progcomp_debug) + { + debug_printf ("gen_command_matches (%p, %s, %s, %p, %d, %d) -->", cs, cmd, word, lwords, nw, cw); + strlist_print (tmatches, "\t"); + rl_on_new_line (); + } +#endif + ret = strlist_append (ret, tmatches); + strlist_dispose (tmatches); + } + } + + if (cs->command || cs->funcname) + { + if (lwords) + dispose_words (lwords); + FREE (line); + } + + if (foundp) + *foundp = found; + + if (found == 0 || (found & PCOMP_RETRYFAIL)) + { + strlist_dispose (ret); + return NULL; + } + + if (cs->filterpat) + { + tmatches = filter_stringlist (ret, cs->filterpat, word); +#ifdef DEBUG + if (progcomp_debug) + { + debug_printf ("filter_stringlist (%p, %s, %s) -->", ret, cs->filterpat, word); + strlist_print (tmatches, "\t"); + rl_on_new_line (); + } +#endif + if (ret && ret != tmatches) + { + FREE (ret->list); + free (ret); + } + ret = tmatches; + } + + if (cs->prefix || cs->suffix) + ret = strlist_prefix_suffix (ret, cs->prefix, cs->suffix); + + /* If no matches have been generated and the user has specified that + directory completion should be done as a default, call + gen_action_completions again to generate a list of matching directory + names. */ + if ((ret == 0 || ret->list_len == 0) && (cs->options & COPT_DIRNAMES)) + { + tcs = compspec_create (); + tcs->actions = CA_DIRECTORY; + FREE (ret); + ret = gen_action_completions (tcs, word); + compspec_dispose (tcs); + } + else if (cs->options & COPT_PLUSDIRS) + { + tcs = compspec_create (); + tcs->actions = CA_DIRECTORY; + tmatches = gen_action_completions (tcs, word); + ret = strlist_append (ret, tmatches); + strlist_dispose (tmatches); + compspec_dispose (tcs); + } + + return (ret); +} + +void +pcomp_set_readline_variables (flags, nval) + int flags, nval; +{ + /* If the user specified that the compspec returns filenames, make + sure that readline knows it. */ + if (flags & COPT_FILENAMES) + rl_filename_completion_desired = nval; + /* If the user doesn't want a space appended, tell readline. */ + if (flags & COPT_NOSPACE) + rl_completion_suppress_append = nval; + /* The value here is inverted, since the default is on and the `noquote' + option is supposed to turn it off */ + if (flags & COPT_NOQUOTE) + rl_filename_quoting_desired = 1 - nval; +} + +/* Set or unset FLAGS in the options word of the current compspec. + SET_OR_UNSET is 1 for setting, 0 for unsetting. */ +void +pcomp_set_compspec_options (cs, flags, set_or_unset) + COMPSPEC *cs; + int flags, set_or_unset; +{ + if (cs == 0 && ((cs = pcomp_curcs) == 0)) + return; + if (set_or_unset) + cs->options |= flags; + else + cs->options &= ~flags; +} + +static STRINGLIST * +gen_progcomp_completions (ocmd, cmd, word, start, end, foundp, retryp, lastcs) + const char *ocmd; + const char *cmd; + const char *word; + int start, end; + int *foundp, *retryp; + COMPSPEC **lastcs; +{ + COMPSPEC *cs, *oldcs; + const char *oldcmd; + STRINGLIST *ret; + + cs = progcomp_search (ocmd); + + if (cs == 0 || cs == *lastcs) + { +#if 0 + if (foundp) + *foundp = 0; +#endif + return (NULL); + } + + if (*lastcs) + compspec_dispose (*lastcs); + cs->refcount++; /* XXX */ + *lastcs = cs; + + cs = compspec_copy (cs); + + oldcs = pcomp_curcs; + oldcmd = pcomp_curcmd; + + pcomp_curcs = cs; + pcomp_curcmd = cmd; + + ret = gen_compspec_completions (cs, cmd, word, start, end, foundp); + + pcomp_curcs = oldcs; + pcomp_curcmd = oldcmd; + + /* We need to conditionally handle setting *retryp here */ + if (retryp) + *retryp = foundp && (*foundp & PCOMP_RETRYFAIL); + + if (foundp) + { + *foundp &= ~PCOMP_RETRYFAIL; + *foundp |= cs->options; + } + + compspec_dispose (cs); + return ret; +} + +/* The driver function for the programmable completion code. Returns a list + of matches for WORD, which is an argument to command CMD. START and END + bound the command currently being completed in rl_line_buffer. */ +char ** +programmable_completions (cmd, word, start, end, foundp) + const char *cmd; + const char *word; + int start, end, *foundp; +{ + COMPSPEC *cs, *lastcs; + STRINGLIST *ret; + char **rmatches, *t; + int found, retry, count; + + lastcs = 0; + found = count = 0; + + do + { + retry = 0; + + /* We look at the basename of CMD if the full command does not have + an associated COMPSPEC. */ + ret = gen_progcomp_completions (cmd, cmd, word, start, end, &found, &retry, &lastcs); + if (found == 0) + { + t = strrchr (cmd, '/'); + if (t && *(++t)) + ret = gen_progcomp_completions (t, cmd, word, start, end, &found, &retry, &lastcs); + } + + if (found == 0) + ret = gen_progcomp_completions (DEFAULTCMD, cmd, word, start, end, &found, &retry, &lastcs); + + count++; + + if (count > 32) + { + internal_warning ("programmable_completion: %s: possible retry loop", cmd); + break; + } + } + while (retry); + + if (ret) + { + rmatches = ret->list; + free (ret); + } + else + rmatches = (char **)NULL; + + if (foundp) + *foundp = found; + + if (lastcs) /* XXX - should be while? */ + compspec_dispose (lastcs); + + return (rmatches); +} + +#endif /* PROGRAMMABLE_COMPLETION */ diff --git a/po/de.po b/po/de.po index d5d39e277..43e061100 100644 --- a/po/de.po +++ b/po/de.po @@ -1,13 +1,13 @@ -# German language file for GNU Bash 4.2 +# German language file for GNU Bash 4.3 # Copyright (C) 2011 Free Software Foundation, Inc. # This file is distributed under the same license as the bash package. -# Nils Naumann , 1996-2011. +# Nils Naumann , 1996-2013. msgid "" msgstr "" -"Project-Id-Version: bash 4.2\n" +"Project-Id-Version: bash 4.3-pre2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-08-14 11:14-0400\n" -"PO-Revision-Date: 2012-09-24 19:12+0200\n" +"POT-Creation-Date: 2013-03-08 16:00-0500\n" +"PO-Revision-Date: 2013-08-26 21:04+0200\n" "Last-Translator: Nils Naumann \n" "Language-Team: German \n" "Language: de\n" @@ -20,7 +20,7 @@ msgstr "" msgid "bad array subscript" msgstr "Falscher Feldbezeichner." -#: arrayfunc.c:356 builtins/declare.def:585 +#: arrayfunc.c:356 builtins/declare.def:578 #, c-format msgid "%s: cannot convert indexed to associative array" msgstr "%s: Kann nicht das indizierte in ein assoziatives Array umwandeln." @@ -38,32 +38,28 @@ msgstr "%s: Kann nicht auf einen nicht-numerischen Index zuweisen." #: arrayfunc.c:586 #, c-format msgid "%s: %s: must use subscript when assigning associative array" -msgstr "" -"%s: %s: Ein Feldbezeicher wird zum Zuweisen eines assoziativen Arrays " -"benötigt." +msgstr "%s: %s: Ein Feldbezeicher wird zum Zuweisen eines assoziativen Arrays benötigt." #: bashhist.c:388 #, c-format msgid "%s: cannot create: %s" msgstr "%s: Kann die Datei %s nicht erzeugen." -#: bashline.c:3928 +#: bashline.c:3923 msgid "bash_execute_unix_command: cannot find keymap for command" -msgstr "" -"bash_execute_unix_command: Kann nicht die Tastenzuordnung fĂƒÂŒr das Kommando " -"finden." +msgstr "bash_execute_unix_command: Kann nicht die Tastenzuordnung fĂƒÂŒr das Kommando finden." -#: bashline.c:4015 +#: bashline.c:4010 #, c-format msgid "%s: first non-whitespace character is not `\"'" msgstr " %s: Das erste Zeichen ist nicht `\\'." -#: bashline.c:4044 +#: bashline.c:4039 #, c-format msgid "no closing `%c' in %s" msgstr "fehlende schließende `%c' in %s." -#: bashline.c:4078 +#: bashline.c:4073 #, c-format msgid "%s: missing colon separator" msgstr "%s: Fehlender Doppelpunkt." @@ -189,7 +185,7 @@ msgstr "UngĂƒÂŒltige Oktalzahl." msgid "invalid hex number" msgstr "UngĂƒÂŒltige hexadezimale Zahl." -#: builtins/common.c:242 expr.c:1461 +#: builtins/common.c:242 expr.c:1451 msgid "invalid number" msgstr "UngĂƒÂŒltige Zahl." @@ -302,35 +298,34 @@ msgstr "GegenwÀrtig wird keine Komplettierungsfunktion ausgefĂƒÂŒhrt." msgid "can only be used in a function" msgstr "kann nur innerhalb einer Funktion benutzt werden." -#: builtins/declare.def:315 builtins/declare.def:533 +#: builtins/declare.def:311 builtins/declare.def:526 #, c-format msgid "%s: reference variable cannot be an array" msgstr "" -#: builtins/declare.def:324 +#: builtins/declare.def:317 #, c-format msgid "%s: nameref variable self references not allowed" msgstr "" -#: builtins/declare.def:422 +#: builtins/declare.def:415 msgid "cannot use `-f' to make functions" msgstr "Mit `-f' können keine Funktionen erzeugt werden." -#: builtins/declare.def:434 execute_cmd.c:5328 +#: builtins/declare.def:427 execute_cmd.c:5315 #, c-format msgid "%s: readonly function" msgstr "%s: SchreibgeschĂƒÂŒtzte Funktion." -#: builtins/declare.def:572 +#: builtins/declare.def:565 #, c-format msgid "%s: cannot destroy array variables in this way" msgstr "%s: Kann Feldvariablen nicht auf diese Art löschen." -#: builtins/declare.def:579 builtins/read.def:733 +#: builtins/declare.def:572 builtins/read.def:721 #, c-format msgid "%s: cannot convert associative to indexed array" -msgstr "" -"%s: Konvertieren von assoziativen in indizierte Arrays ist nicht möglich." +msgstr "%s: Konvertieren von assoziativen in indizierte Arrays ist nicht möglich." #: builtins/enable.def:137 builtins/enable.def:145 msgid "dynamic loading not available" @@ -356,7 +351,7 @@ msgstr "%s: Ist nicht dynamisch geladen." msgid "%s: cannot delete: %s" msgstr "%s: Kann nicht löschen: %s" -#: builtins/evalfile.c:140 builtins/hash.def:171 execute_cmd.c:5175 +#: builtins/evalfile.c:140 builtins/hash.def:171 execute_cmd.c:5162 #: shell.c:1481 #, c-format msgid "%s: is a directory" @@ -405,11 +400,11 @@ msgstr "Es gibt noch laufende Prozesse.\n" msgid "no command found" msgstr "Kein Kommando gefunden." -#: builtins/fc.def:320 builtins/fc.def:369 +#: builtins/fc.def:312 builtins/fc.def:359 msgid "history specification" msgstr "" -#: builtins/fc.def:390 +#: builtins/fc.def:380 #, c-format msgid "%s: cannot open temp file: %s" msgstr "%s: Kann die temprÀre Datei nicht öffnen: %s" @@ -454,20 +449,17 @@ msgid_plural "Shell commands matching keywords `" msgstr[0] "Shell Kommandos auf die das SchlĂƒÂŒsselwort zutrifft `" msgstr[1] "Shell Kommandos auf die die SchlĂƒÂŒsselwörter zutreffen `" -#: builtins/help.def:182 +#: builtins/help.def:168 #, c-format -msgid "" -"no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'." -msgstr "" -"Auf `%s' trifft kein Hilfethema zu. Probieren Sie `help help', `man -k %s' " -"oder `info %s'." +msgid "no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'." +msgstr "Auf `%s' trifft kein Hilfethema zu. Probieren Sie `help help', `man -k %s' oder `info %s'." -#: builtins/help.def:199 +#: builtins/help.def:185 #, c-format msgid "%s: cannot open: %s" msgstr "%s: Kann die Datei nicht öffnen: %s" -#: builtins/help.def:485 +#: builtins/help.def:471 #, c-format msgid "" "These shell commands are defined internally. Type `help' to see this list.\n" @@ -518,7 +510,7 @@ msgstr "%s: Die Argumente mĂƒÂŒssen Prozess- oder Jobbezeichnungen sein." msgid "Unknown error" msgstr "Unbekannter Fehler." -#: builtins/let.def:95 builtins/let.def:120 expr.c:583 expr.c:598 +#: builtins/let.def:95 builtins/let.def:120 expr.c:586 expr.c:601 msgid "expression expected" msgstr "Ausdruck erwartet." @@ -594,9 +586,9 @@ msgid "no other directory" msgstr "kein anderes Verzeichnis" #: builtins/pushd.def:354 -#, fuzzy, c-format +#, c-format msgid "%s: invalid argument" -msgstr "%s: UngĂƒÂŒltiges Grenzwertargument." +msgstr "%s: UngĂƒÂŒltiges Argument." #: builtins/pushd.def:468 msgid "" @@ -625,12 +617,10 @@ msgid "" " \twith its position in the stack\n" " \n" " Arguments:\n" -" +N\tDisplays the Nth entry counting from the left of the list shown " -"by\n" +" +N\tDisplays the Nth entry counting from the left of the list shown by\n" " \tdirs when invoked without options, starting with zero.\n" " \n" -" -N\tDisplays the Nth entry counting from the right of the list shown " -"by\n" +" -N\tDisplays the Nth entry counting from the right of the list shown by\n" "\tdirs when invoked without options, starting with zero." msgstr "" "Zeigt die Liste der gegenwÀrtig gespeicherten Verzeichnisse an. Durch\n" @@ -744,21 +734,18 @@ msgstr "" msgid "%s: invalid timeout specification" msgstr "%s: UngĂƒÂŒltige Wartezeitangebe." -#: builtins/read.def:678 +#: builtins/read.def:666 #, c-format msgid "read error: %d: %s" msgstr "Lesefehler: %d: %s" #: builtins/return.def:75 msgid "can only `return' from a function or sourced script" -msgstr "" -"»Return« ist nur aus einer Funktion oder einem mit »source« ausgefĂƒÂŒhten " -"Skript möglich." +msgstr "»Return« ist nur aus einer Funktion oder einem mit »source« ausgefĂƒÂŒhten Skript möglich." #: builtins/set.def:782 msgid "cannot simultaneously unset a function and a variable" -msgstr "" -"Gleichzeitiges `unset' einer Funktion und einer Variable ist nicht möglich." +msgstr "Gleichzeitiges `unset' einer Funktion und einer Variable ist nicht möglich." #: builtins/set.def:826 #, c-format @@ -925,118 +912,117 @@ msgstr "\aZu lange keine Eingabe: Automatisch ausgeloggt.\n" msgid "cannot redirect standard input from /dev/null: %s" msgstr "Kann nicht die Standardeingabe von /dev/null umleiten: %s" -#: execute_cmd.c:1230 +#: execute_cmd.c:1228 #, c-format msgid "TIMEFORMAT: `%c': invalid format character" msgstr "TIMEFORMAT: `%c': UngĂƒÂŒltiges Formatzeichen." -#: execute_cmd.c:2284 +#: execute_cmd.c:2282 msgid "pipe error" msgstr "Pipe-Fehler" -#: execute_cmd.c:4358 +#: execute_cmd.c:4347 #, c-format msgid "%s: maximum function nesting level exceeded (%d)" msgstr "" -#: execute_cmd.c:4851 +#: execute_cmd.c:4840 #, c-format msgid "%s: restricted: cannot specify `/' in command names" msgstr "%s: Verboten: `/' ist in Kommandonamen unzulÀssig." -#: execute_cmd.c:4940 +#: execute_cmd.c:4929 #, c-format msgid "%s: command not found" msgstr "%s: Kommando nicht gefunden." -#: execute_cmd.c:5173 +#: execute_cmd.c:5160 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: execute_cmd.c:5210 +#: execute_cmd.c:5197 #, c-format msgid "%s: %s: bad interpreter" msgstr "%s: %s: Defekter Interpreter" -#: execute_cmd.c:5247 -#, fuzzy, c-format +#: execute_cmd.c:5234 +#, c-format msgid "%s: cannot execute binary file: %s" -msgstr "%s: Kann die Datei nicht ausfĂƒÂŒhren." +msgstr "%s: Kann die BinÀrdatei nicht ausfĂƒÂŒhren: %s" -#: execute_cmd.c:5319 -#, fuzzy, c-format +#: execute_cmd.c:5306 +#, c-format msgid "`%s': is a special builtin" -msgstr "%s ist eine von der Shell mitgelieferte Funktion.\n" +msgstr "`%s' ist eine spezielle eingebaute Funktion." -#: execute_cmd.c:5371 +#: execute_cmd.c:5358 #, c-format msgid "cannot duplicate fd %d to fd %d" msgstr "Kann fd %d nicht auf fd %d verdoppeln." -#: expr.c:259 +#: expr.c:262 msgid "expression recursion level exceeded" msgstr "Zu viele Rekursionen in Ausdruck." -#: expr.c:283 +#: expr.c:286 msgid "recursion stack underflow" msgstr "Rekursionsstapel leer." -#: expr.c:431 +#: expr.c:434 msgid "syntax error in expression" msgstr "Syntaxfehler im Ausdruck." -#: expr.c:475 +#: expr.c:478 msgid "attempted assignment to non-variable" msgstr "Versuchte Zuweisung zu keiner Variablen." -#: expr.c:495 expr.c:851 +#: expr.c:498 expr.c:847 msgid "division by 0" msgstr "Division durch 0." -#: expr.c:542 +#: expr.c:545 msgid "bug: bad expassign token" msgstr "Fehler: Falscher Zuweisungsoperator." -#: expr.c:595 +#: expr.c:598 msgid "`:' expected for conditional expression" msgstr "`:' fĂƒÂŒr ein bedingten Ausdruck erwaret." -#: expr.c:910 +#: expr.c:904 msgid "exponent less than 0" msgstr "Der Exponent ist kleiner als 0." -#: expr.c:967 +#: expr.c:957 msgid "identifier expected after pre-increment or pre-decrement" -msgstr "" -"Nach einem PrÀinkrement oder PrÀdekrement wird ein Bezeichner erwartet." +msgstr "Nach einem PrÀinkrement oder PrÀdekrement wird ein Bezeichner erwartet." -#: expr.c:993 +#: expr.c:983 msgid "missing `)'" msgstr "Fehlende `)'" -#: expr.c:1044 expr.c:1381 +#: expr.c:1034 expr.c:1371 msgid "syntax error: operand expected" msgstr "Syntax Fehler: Operator erwartet." -#: expr.c:1383 +#: expr.c:1373 msgid "syntax error: invalid arithmetic operator" msgstr "Syntaxfehler: UngĂƒÂŒltiger arithmetischer Operator." -#: expr.c:1407 +#: expr.c:1397 #, c-format msgid "%s%s%s: %s (error token is \"%s\")" msgstr "%s%s%s: %s (Fehlerverursachendes Zeichen ist \\\"%s\\\")." -#: expr.c:1465 +#: expr.c:1455 msgid "invalid arithmetic base" msgstr "UngĂƒÂŒltige Basis." -#: expr.c:1485 +#: expr.c:1475 msgid "value too great for base" msgstr "Der Wert ist fĂƒÂŒr die aktuelle Basis zu groß." -#: expr.c:1534 +#: expr.c:1524 #, c-format msgid "%s: expression error\n" msgstr "%s: Fehler im Ausdruck.\n" @@ -1045,7 +1031,7 @@ msgstr "%s: Fehler im Ausdruck.\n" msgid "getcwd: cannot access parent directories" msgstr "getwd: Kann auf das ĂƒÂŒbergeordnete Verzeichnis nicht zugreifen." -#: input.c:101 subst.c:5129 +#: input.c:101 subst.c:5067 #, c-format msgid "cannot reset nodelay mode for fd %d" msgstr "Konnte den No-Delay Modus fĂƒÂŒr fd %d nicht wieder herstellen." @@ -1153,62 +1139,62 @@ msgstr "wait: Prozeß %ld wurde nicht von dieser Shell gestartet." msgid "wait_for: No record of process %ld" msgstr "" -#: jobs.c:2692 +#: jobs.c:2689 #, c-format msgid "wait_for_job: job %d is stopped" msgstr "" -#: jobs.c:2984 +#: jobs.c:2981 #, c-format msgid "%s: job has terminated" msgstr "%s: Programm ist beendet." -#: jobs.c:2993 +#: jobs.c:2990 #, c-format msgid "%s: job %d already in background" msgstr "" -#: jobs.c:3218 +#: jobs.c:3215 msgid "waitchld: turning on WNOHANG to avoid indefinite block" msgstr "" # Debug Ausgabe -#: jobs.c:3709 +#: jobs.c:3699 #, c-format msgid "%s: line %d: " msgstr "%s: Zeile %d: " -#: jobs.c:3723 nojobs.c:843 +#: jobs.c:3713 nojobs.c:843 #, c-format msgid " (core dumped)" msgstr " (Speicherabzug geschrieben)" -#: jobs.c:3735 jobs.c:3748 +#: jobs.c:3725 jobs.c:3738 #, c-format msgid "(wd now: %s)\n" msgstr "(gegenwÀrtiges Arbeitsverzeichnis ist: %s)\n" # interner Fehler -#: jobs.c:3780 +#: jobs.c:3770 msgid "initialize_job_control: getpgrp failed" msgstr "initialize_jobs: getpgrp war nicht erfolgreich." # interner Fehler -#: jobs.c:3841 +#: jobs.c:3831 msgid "initialize_job_control: line discipline" msgstr "initialize_job_control: line discipline" # interner Fehler -#: jobs.c:3851 +#: jobs.c:3841 msgid "initialize_job_control: setpgid" msgstr "initialize_job_control: setpgid" -#: jobs.c:3872 jobs.c:3881 +#: jobs.c:3862 jobs.c:3871 #, c-format msgid "cannot set terminal process group (%d)" msgstr "Kann die Prozessgruppe des Terminals nicht setzen (%d)." -#: jobs.c:3886 +#: jobs.c:3876 msgid "no job control in this shell" msgstr "Keine Job Steuerung in dieser Shell." @@ -1232,8 +1218,7 @@ msgstr "Unbekannt" #: lib/malloc/malloc.c:801 msgid "malloc: block on free list clobbered" -msgstr "" -"Malloc: Ein frei gekennzeichneter Speicherbereich wurde ĂƒÂŒberschrieben." +msgstr "Malloc: Ein frei gekennzeichneter Speicherbereich wurde ĂƒÂŒberschrieben." #: lib/malloc/malloc.c:878 msgid "free: called with already freed block argument" @@ -1257,8 +1242,7 @@ msgstr "realloc: Mit nicht zugewiesenen Argument aufgerufen." #: lib/malloc/malloc.c:1020 msgid "realloc: underflow detected; mh_nbytes out of range" -msgstr "" -"realloc: Underflow erkannt; mh_nbytes außerhalb des GĂƒÂŒltigkeitsbereichs." +msgstr "realloc: Underflow erkannt; mh_nbytes außerhalb des GĂƒÂŒltigkeitsbereichs." #: lib/malloc/malloc.c:1026 msgid "realloc: start and end chunk sizes differ" @@ -1267,22 +1251,17 @@ msgstr "realloc: Beginn und Ende SegmentgrĂƒÂ¶ĂƒÂŸen sind unterschiedlich.<" #: lib/malloc/table.c:194 #, c-format msgid "register_alloc: alloc table is full with FIND_ALLOC?\n" -msgstr "" -"register_alloc: Speicherzuordnungstabelle ist mit FIND_ALLOC gefĂƒÂŒllt?\n" +msgstr "register_alloc: Speicherzuordnungstabelle ist mit FIND_ALLOC gefĂƒÂŒllt?\n" #: lib/malloc/table.c:203 #, c-format msgid "register_alloc: %p already in table as allocated?\n" -msgstr "" -"register_alloc: %p ist bereits in der Speicherzuordnungstabelle als belegt " -"gekennzeichnet?\n" +msgstr "register_alloc: %p ist bereits in der Speicherzuordnungstabelle als belegt gekennzeichnet?\n" #: lib/malloc/table.c:256 #, c-format msgid "register_free: %p already in table as free?\n" -msgstr "" -"register_free: %p ist bereits in der Speicherzuordnungstabelle als frei " -"gekennzeichnet?\n" +msgstr "register_free: %p ist bereits in der Speicherzuordnungstabelle als frei gekennzeichnet?\n" #: lib/sh/fmtulong.c:102 msgid "invalid base" @@ -1363,109 +1342,107 @@ msgstr "make_here_document: Falscher Befehlstyp %d." #: make_cmd.c:662 #, c-format msgid "here-document at line %d delimited by end-of-file (wanted `%s')" -msgstr "" -"Das in der Zeile %d beginnende Here-Dokument geht bis zum Dateiende " -"(erwartet wird `%s')." +msgstr "Das in der Zeile %d beginnende Here-Dokument geht bis zum Dateiende (erwartet wird `%s')." #: make_cmd.c:759 #, c-format msgid "make_redirection: redirection instruction `%d' out of range" msgstr "" -#: parse.y:3210 parse.y:3493 +#: parse.y:3209 parse.y:3480 #, c-format msgid "unexpected EOF while looking for matching `%c'" msgstr "Dateiende beim Suchen nach `%c' erreicht." -#: parse.y:4099 +#: parse.y:4086 msgid "unexpected EOF while looking for `]]'" msgstr "Dateiende beim Suchen nach `]]' erreicht." -#: parse.y:4104 +#: parse.y:4091 #, c-format msgid "syntax error in conditional expression: unexpected token `%s'" msgstr "Syntaxfehler im bedingten Ausdruck: Unerwartetes Zeichen `%s'." -#: parse.y:4108 +#: parse.y:4095 msgid "syntax error in conditional expression" msgstr "Syntaxfehler im bedingen Ausdruck." -#: parse.y:4186 +#: parse.y:4173 #, c-format msgid "unexpected token `%s', expected `)'" msgstr "Unerwartetes Zeichen: `%s' anstatt von `)'" -#: parse.y:4190 +#: parse.y:4177 msgid "expected `)'" msgstr "`)' erwartet." -#: parse.y:4218 +#: parse.y:4205 #, c-format msgid "unexpected argument `%s' to conditional unary operator" msgstr "" -#: parse.y:4222 +#: parse.y:4209 msgid "unexpected argument to conditional unary operator" msgstr "" -#: parse.y:4268 +#: parse.y:4255 #, c-format msgid "unexpected token `%s', conditional binary operator expected" msgstr "" -#: parse.y:4272 +#: parse.y:4259 msgid "conditional binary operator expected" msgstr "" -#: parse.y:4294 +#: parse.y:4281 #, c-format msgid "unexpected argument `%s' to conditional binary operator" msgstr "" -#: parse.y:4298 +#: parse.y:4285 msgid "unexpected argument to conditional binary operator" msgstr "" -#: parse.y:4309 +#: parse.y:4296 #, c-format msgid "unexpected token `%c' in conditional command" msgstr "" -#: parse.y:4312 +#: parse.y:4299 #, c-format msgid "unexpected token `%s' in conditional command" msgstr "" -#: parse.y:4316 +#: parse.y:4303 #, c-format msgid "unexpected token %d in conditional command" msgstr "" -#: parse.y:5666 +#: parse.y:5649 #, c-format msgid "syntax error near unexpected token `%s'" msgstr "Syntaxfehler beim unerwarteten Wort `%s'" -#: parse.y:5684 +#: parse.y:5667 #, c-format msgid "syntax error near `%s'" msgstr "Syntaxfehler beim unerwarteten Wort `%s'" -#: parse.y:5694 +#: parse.y:5677 msgid "syntax error: unexpected end of file" msgstr "Syntax Fehler: Unerwartetes Dateiende." -#: parse.y:5694 +#: parse.y:5677 msgid "syntax error" msgstr "Syntax Fehler" # Du oder Sie? -#: parse.y:5756 +#: parse.y:5739 #, c-format msgid "Use \"%s\" to leave the shell.\n" msgstr "Benutze \"%s\" um die Shell zu verlassen.\n" -#: parse.y:5918 +#: parse.y:5901 msgid "unexpected EOF while looking for matching `)'" msgstr "Dateiende beim Suchen nach passender `)' erreicht." @@ -1536,7 +1513,7 @@ msgstr "%s: Kann fd keiner Variable zuweisen." msgid "/dev/(tcp|udp)/host/port not supported without networking" msgstr "/dev/(tcp|udp)/host/port Wird ohne Netzwerk nicht unterstĂƒÂŒtzt" -#: redir.c:861 redir.c:973 redir.c:1034 redir.c:1199 +#: redir.c:861 redir.c:971 redir.c:1032 redir.c:1194 msgid "redirection error: cannot duplicate fd" msgstr "" @@ -1580,9 +1557,8 @@ msgid "Shell options:\n" msgstr "Shell-Optionen:\n" #: shell.c:1835 -#, fuzzy msgid "\t-ilrsD or -c command or -O shopt_option\t\t(invocation only)\n" -msgstr "\t-irsD oder -c Kommando\t\t(Nur Aufruf)\n" +msgstr "\t-ilrsD oder -c Kommando\toder -O shopt_option (Nur Aufruf)\n" #: shell.c:1850 #, c-format @@ -1778,92 +1754,88 @@ msgstr "Unbekannte Signalnummer." msgid "Unknown Signal #%d" msgstr "Unbekanntes Signal Nr.: %d." -#: subst.c:1358 subst.c:1516 +#: subst.c:1352 subst.c:1510 #, c-format msgid "bad substitution: no closing `%s' in %s" msgstr "Falsche Ersetzung: Keine schließende `%s' in `%s' enthalten." -#: subst.c:2829 +#: subst.c:2823 #, c-format msgid "%s: cannot assign list to array member" msgstr "%s: Kann einem Feldelement keine Liste zuweisen." -#: subst.c:5026 subst.c:5042 +#: subst.c:4964 subst.c:4980 msgid "cannot make pipe for process substitution" msgstr "Kann keine Pipe fĂƒÂŒr die Prozeßersetzung erzeugen." -#: subst.c:5074 +#: subst.c:5012 msgid "cannot make child for process substitution" msgstr "Kann den Kindsprozess fĂƒÂŒr die Prozeßersetzung nicht erzeugen." -#: subst.c:5119 +#: subst.c:5057 #, c-format msgid "cannot open named pipe %s for reading" msgstr "Kann nicht die benannte Pipe %s zum lesen öffnen." -#: subst.c:5121 +#: subst.c:5059 #, c-format msgid "cannot open named pipe %s for writing" msgstr "Kann nicht die benannte Pipe %s zum schreiben öffnen." -#: subst.c:5139 +#: subst.c:5077 #, c-format msgid "cannot duplicate named pipe %s as fd %d" msgstr "Kann die benannte Pipe %s nicht auf fd %d." -#: subst.c:5337 +#: subst.c:5273 msgid "cannot make pipe for command substitution" msgstr "Kann keine Pipes fĂƒÂŒr Kommandoersetzung erzeugen." -#: subst.c:5375 +#: subst.c:5311 msgid "cannot make child for command substitution" msgstr "Kann keinen Unterprozess fĂƒÂŒr die Kommandoersetzung erzeugen." # interner Fehler -#: subst.c:5394 +#: subst.c:5330 msgid "command_substitute: cannot duplicate pipe as fd 1" msgstr "Kommandoersetzung: Kann Pipe nicht als fd 1 duplizieren." -#: subst.c:5798 subst.c:8001 +#: subst.c:5733 subst.c:7900 #, c-format msgid "%s: invalid variable name for name reference" msgstr "" -#: subst.c:6009 +#: subst.c:5926 #, c-format msgid "%s: parameter null or not set" msgstr "%s: Parameter ist Null oder nicht gesetzt." # interner Fehler -#: subst.c:6281 subst.c:6296 +#: subst.c:6198 subst.c:6213 #, c-format msgid "%s: substring expression < 0" msgstr "%s: Teilstring-Ausdruck < 0." -#: subst.c:7457 +#: subst.c:7356 #, c-format msgid "%s: bad substitution" msgstr "%s: Falsche Variablenersetzung." -#: subst.c:7534 +#: subst.c:7433 #, c-format msgid "$%s: cannot assign in this way" msgstr "$%s: Kann so nicht zuweisen." -#: subst.c:7868 -msgid "" -"future versions of the shell will force evaluation as an arithmetic " -"substitution" -msgstr "" -"ZukĂƒÂŒnftige Versionen dieser Shell werden das Auswerten arithmetischer " -"Ersetzungen erzwingen." +#: subst.c:7767 +msgid "future versions of the shell will force evaluation as an arithmetic substitution" +msgstr "ZukĂƒÂŒnftige Versionen dieser Shell werden das Auswerten arithmetischer Ersetzungen erzwingen." -#: subst.c:8372 +#: subst.c:8271 #, c-format msgid "bad substitution: no closing \"`\" in %s" msgstr "Falsche Ersetzung: Keine schließende \"`\" in %s." -#: subst.c:9273 +#: subst.c:9172 #, c-format msgid "no match: %s" msgstr "Keine Entsprechung: %s" @@ -1904,105 +1876,94 @@ msgstr "Fehlende `]'" msgid "invalid signal number" msgstr "UngĂƒÂŒltige Signalnummer." -#: trap.c:354 +#: trap.c:348 #, c-format msgid "run_pending_traps: bad value in trap_list[%d]: %p" msgstr "" -#: trap.c:358 +#: trap.c:352 #, c-format -msgid "" -"run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself" +msgid "run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself" msgstr "" # Programmierfehler -#: trap.c:413 +#: trap.c:398 #, c-format msgid "trap_handler: bad signal %d" msgstr "trap_handler: Falsches Signal %d." -#: variables.c:382 +#: variables.c:380 #, c-format msgid "error importing function definition for `%s'" msgstr "Fehler beim Importieren der Funktionsdefinition fĂƒÂŒr `%s'." -#: variables.c:780 +#: variables.c:778 #, c-format msgid "shell level (%d) too high, resetting to 1" msgstr "" -#: variables.c:1865 -#, c-format -msgid "%s: circular name reference" -msgstr "" - -#: variables.c:2228 +#: variables.c:2198 msgid "make_local_variable: no function context at current scope" msgstr "" -#: variables.c:2247 -#, fuzzy, c-format +#: variables.c:2217 +#, c-format msgid "%s: variable may not be assigned value" -msgstr "%s: Kann fd keiner Variable zuweisen." +msgstr "%s: Der Variable könnte kein Wert zugewiesen sein." -#: variables.c:3600 +#: variables.c:3554 msgid "all_local_variables: no function context at current scope" msgstr "" -#: variables.c:3845 +#: variables.c:3799 #, c-format msgid "%s has null exportstr" msgstr "" -#: variables.c:3850 variables.c:3859 +#: variables.c:3804 variables.c:3813 #, c-format msgid "invalid character %d in exportstr for %s" msgstr "" -#: variables.c:3865 +#: variables.c:3819 #, c-format msgid "no `=' in exportstr for %s" msgstr "" -#: variables.c:4298 +#: variables.c:4252 msgid "pop_var_context: head of shell_variables not a function context" msgstr "" -#: variables.c:4311 +#: variables.c:4265 msgid "pop_var_context: no global_variables context" msgstr "" -#: variables.c:4385 +#: variables.c:4339 msgid "pop_scope: head of shell_variables not a temporary environment scope" msgstr "" -#: variables.c:5211 +#: variables.c:5165 #, c-format msgid "%s: %s: cannot open as FILE" msgstr "%s: %s: Kann nicht als Datei geöffnet werden." -#: variables.c:5216 +#: variables.c:5170 #, c-format msgid "%s: %s: invalid value for trace file descriptor" msgstr "" -#: variables.c:5261 -#, fuzzy, c-format +#: variables.c:5215 +#, c-format msgid "%s: %s: compatibility value out of range" -msgstr "%s: %s ist außerhalb des GĂƒÂŒltigkeitsbereiches." +msgstr "%s: %s: KompatibilitÀtswert außerhalb des GĂƒÂŒltigkeitsbereiches." -#: version.c:46 -#, fuzzy -msgid "Copyright (C) 2013 Free Software Foundation, Inc." -msgstr "Copyright (C) 2011 Free Software Foundation, Inc." +#: version.c:46 version2.c:46 +msgid "Copyright (C) 2012 Free Software Foundation, Inc." +msgstr "Copyright (C) 2012 Free Software Foundation, Inc." #: version.c:47 version2.c:47 -msgid "" -"License GPLv3+: GNU GPL version 3 or later \n" -msgstr "" -"Lizenz GPLv3+: GNU GPL Version 3 oder jĂƒÂŒnger \n" +msgid "License GPLv3+: GNU GPL version 3 or later \n" +msgstr "Lizenz GPLv3+: GNU GPL Version 3 oder jĂƒÂŒnger \n" #: version.c:86 version2.c:86 #, c-format @@ -2010,19 +1971,12 @@ msgid "GNU bash, version %s (%s)\n" msgstr "GNU bash, Version %s (%s)\n" #: version.c:91 version2.c:91 -#, fuzzy msgid "This is free software; you are free to change and redistribute it." -msgstr "Dies ist freie Software. Sie darf verÀndert und verteilt werden.\n" +msgstr "Dies ist freie Software. Sie darf verÀndert und verteilt werden." #: version.c:92 version2.c:92 -#, fuzzy msgid "There is NO WARRANTY, to the extent permitted by law." -msgstr "FĂƒÂŒr dieses Programm besteht keinerlei Garantie.\n" - -#: version2.c:46 -#, fuzzy -msgid "Copyright (C) 2012 Free Software Foundation, Inc." -msgstr "Copyright (C) 2011 Free Software Foundation, Inc." +msgstr "FĂƒÂŒr den grĂƒÂ¶ĂƒÂŸtmöglichen gesetzlich zulÀssigen Umfang wird jede Haftung ausgeschlossen." #: xmalloc.c:91 #, c-format @@ -2053,13 +2007,10 @@ msgid "unalias [-a] name [name ...]" msgstr "unalias [-a] Name [Name ...]" #: builtins.c:51 -#, fuzzy -msgid "" -"bind [-lpsvPSVX] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-" -"x keyseq:shell-command] [keyseq:readline-function or readline-command]" +msgid "bind [-lpsvPSVX] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command]" msgstr "" -"bind [-lpvsPVS] [-m Tastaturtabelle] [-f Dateiname] [-q Name] [-u Name] [-r " -"Tastenfolge:Shell Kommando] [Tastenfolge:readline Funktion oder Kommando]" +"bind [-lpsvPSVX] [-m Tastaturtabelle] [-f Dateiname] [-q Name] [-u\n" +"Name] [-r Tastenfolge] [-x Tastenfolge:Shell Kommando] [Tastenfolge:readline Funktion oder Kommando]" #: builtins.c:54 msgid "break [n]" @@ -2102,9 +2053,8 @@ msgid "command [-pVv] command [arg ...]" msgstr "command [-pVv] Kommando [Argument ...]" #: builtins.c:76 -#, fuzzy msgid "declare [-aAfFgilnrtux] [-p] [name[=value] ...]" -msgstr "declare [-aAfFgilrtux] [-p] Name[=Wert] ..." +msgstr "declare [-aAfFgilrntux] [-p] Name[=Wert] ..." # #: builtins.c:78 @@ -2149,9 +2099,7 @@ msgstr "logout [n]" #: builtins.c:103 msgid "fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]" -msgstr "" -"fc [-e Editor] [-lnr] [Anfang] [Ende] oder fc -s [Muster=Ersetzung] " -"[Kommando]" +msgstr "fc [-e Editor] [-lnr] [Anfang] [Ende] oder fc -s [Muster=Ersetzung] [Kommando]" #: builtins.c:107 msgid "fg [job_spec]" @@ -2170,12 +2118,8 @@ msgid "help [-dms] [pattern ...]" msgstr "help [-dms] [Muster ...]" #: builtins.c:121 -msgid "" -"history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg " -"[arg...]" -msgstr "" -"history [-c] [-d Offset] [n] oder history -anrw [Dateiname] oder history -ps " -"Argument [Argument...]" +msgid "history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...]" +msgstr "history [-c] [-d Offset] [n] oder history -anrw [Dateiname] oder history -ps Argument [Argument...]" #: builtins.c:125 msgid "jobs [-lnprs] [jobspec ...] or jobs -x command [args]" @@ -2186,24 +2130,16 @@ msgid "disown [-h] [-ar] [jobspec ...]" msgstr "disown [-h] [-ar] [Jobbezeichnung ...]" #: builtins.c:132 -msgid "" -"kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l " -"[sigspec]" -msgstr "" -"kill [-s Signalname | -n Signalnummer | -Signalname] [pid | job] ... oder " -"kill -l [Signalname]" +msgid "kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]" +msgstr "kill [-s Signalname | -n Signalnummer | -Signalname] [pid | job] ... oder kill -l [Signalname]" #: builtins.c:134 msgid "let arg [arg ...]" msgstr "let Argument [Argument ...]" #: builtins.c:136 -msgid "" -"read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p " -"prompt] [-t timeout] [-u fd] [name ...]" -msgstr "" -"read [-ers] [-a Feld] [-d Begrenzer] [-i Text] [-n Zeichenanzahl] [-N " -"Zeichenanzahl] [-p Prompt] [-t Zeitlimit] [-u fd] [Name ...]" +msgid "read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]" +msgstr "read [-ers] [-a Feld] [-d Begrenzer] [-i Text] [-n Zeichenanzahl] [-N Zeichenanzahl] [-p Prompt] [-t Zeitlimit] [-u fd] [Name ...]" #: builtins.c:138 msgid "return [n]" @@ -2214,9 +2150,8 @@ msgid "set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]" msgstr "set [-abefhkmnptuvxBCHP] [-o Option] [--] [Argument ...]" #: builtins.c:142 -#, fuzzy msgid "unset [-f] [-v] [-n] [name ...]" -msgstr "unset [-f] [-v] [NAME ...]" +msgstr "unset [-f] [-v] [-n] [NAME ...]" #: builtins.c:144 msgid "export [-fn] [name[=value] ...] or export -p" @@ -2263,23 +2198,20 @@ msgid "type [-afptP] name [name ...]" msgstr "type [-afptP] Name [Name ...]" #: builtins.c:169 -#, fuzzy msgid "ulimit [-SHabcdefilmnpqrstuvxT] [limit]" -msgstr "ulimit [-SHacdefilmnpqrstuvx] [Grenzwert]" +msgstr "ulimit [-SHabcdefilmnpqrstuvxT] [Grenzwert]" #: builtins.c:172 msgid "umask [-p] [-S] [mode]" msgstr "umask [-p] [-S] [Modus]" #: builtins.c:175 -#, fuzzy msgid "wait [-n] [id ...]" -msgstr "wait [id]" +msgstr "wait [-n] [id ...]" #: builtins.c:179 -#, fuzzy msgid "wait [pid ...]" -msgstr "wait [pid]" +msgstr "wait [pid ...]" #: builtins.c:182 msgid "for NAME [in WORDS ... ] ; do COMMANDS; done" @@ -2302,12 +2234,8 @@ msgid "case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac" msgstr "case Wort in [Muster [| Muster]...) Kommandos ;;]... esac" #: builtins.c:192 -msgid "" -"if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else " -"COMMANDS; ] fi" -msgstr "" -"if Kommandos; then Kommandos; [ elif Kommandos; then Kommandos; ]... [ else " -"Kommandos; ] fi" +msgid "if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi" +msgstr "if Kommandos; then Kommandos; [ elif Kommandos; then Kommandos; ]... [ else Kommandos; ] fi" #: builtins.c:194 msgid "while COMMANDS; do COMMANDS; done" @@ -2366,47 +2294,27 @@ msgid "printf [-v var] format [arguments]" msgstr "printf [-v var] Format [Argumente]" #: builtins.c:229 -msgid "" -"complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-" -"W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S " -"suffix] [name ...]" -msgstr "" -"complete [-abcdefgjksuv] [-pr] [-DE] [-o Option] [-A Aktion] [-G Suchmuster] " -"[-W Wortliste] [-F Funktion] [-C Kommando] [-X Filtermuster] [-P Prefix] [-" -"S Suffix] [Name ...]" +msgid "complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]" +msgstr "complete [-abcdefgjksuv] [-pr] [-DE] [-o Option] [-A Aktion] [-G Suchmuster] [-W Wortliste] [-F Funktion] [-C Kommando] [-X Filtermuster] [-P Prefix] [-S Suffix] [Name ...]" #: builtins.c:233 -msgid "" -"compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] " -"[-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]" -msgstr "" -"compgen [-abcdefgjksuv] [-o Option] [-A Aktion] [-G Suchmuster] [-W " -"Wortliste] [-F Funktion] [-C Kommando] [-X Filtermuster] [-P Prefix] [-S " -"Suffix] [Wort]" +msgid "compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]" +msgstr "compgen [-abcdefgjksuv] [-o Option] [-A Aktion] [-G Suchmuster] [-W Wortliste] [-F Funktion] [-C Kommando] [-X Filtermuster] [-P Prefix] [-S Suffix] [Wort]" #: builtins.c:237 msgid "compopt [-o|+o option] [-DE] [name ...]" msgstr "compopt [-o|+o Option] [-DE] [Name ...]" #: builtins.c:240 -msgid "" -"mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c " -"quantum] [array]" -msgstr "" -"mapfile [-n Anzahl] [-O Quelle] [-s Anzahl] [-t] [-u fd] [-C Callback] [-c " -"Menge] [Feldvariable]" +msgid "mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]" +msgstr "mapfile [-n Anzahl] [-O Quelle] [-s Anzahl] [-t] [-u fd] [-C Callback] [-c Menge] [Feldvariable]" #: builtins.c:242 -msgid "" -"readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c " -"quantum] [array]" -msgstr "" -"readarray [-n Anzahl] [-O Quelle] [-s Anzahl] [-t] [-u fd] [-C Callback] [-c " -"Menge] [Feldvariable]" +msgid "readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]" +msgstr "readarray [-n Anzahl] [-O Quelle] [-s Anzahl] [-t] [-u fd] [-C Callback] [-c Menge] [Feldvariable]" # alias #: builtins.c:254 -#, fuzzy msgid "" "Define or display aliases.\n" " \n" @@ -2421,25 +2329,23 @@ msgid "" " -p\tPrint all defined aliases in a reusable format\n" " \n" " Exit Status:\n" -" alias returns true unless a NAME is supplied for which no alias has " -"been\n" +" alias returns true unless a NAME is supplied for which no alias has been\n" " defined." msgstr "" "Definiert Aliase oder zeigt sie an.\n" " \n" -" Ohne Argumente wird die Liste der Aliase (Synonyme) in der Form \n" -" `alias Name=Wert' auf die Standardausgabe gedruckt.\n" +" Ohne Argumente wird die Liste der Aliase (Synonyme) in der Form\n" +" `alias Name=Wert' auf die Standardausgabe ausgegeben.\n" "\n" -" Sonst wird ein Alias fĂƒÂŒr jeden angegebenen Namen definiert, fĂƒÂŒr den ein\n" -" Wert angegeben wurde. \n" -" A trailing space in VALUE causes the next word to be checked for\n" -" alias substitution when the alias is expanded.\n" -" \n" -" Options:\n" -" -p\tPrint all defined aliases in a reusable format\n" +" Sonst wird ein Alias fĂƒÂŒr jeden angegebenen Namen definiert, fĂƒÂŒr\n" +" den ein Wert angegeben wurde. Wenn `Wert' mit einem Leerzeichen\n" +" abschließt, dann wird auch das folgende Wort auf Aliase ĂƒÂŒberprĂƒÂŒft.\n" +"\n" +" Optionen:\n" +" -p\tGibt alle definierten Aliase aus.\n" " \n" " RĂƒÂŒckgabewert:\n" -" Meldet Erfolg, außer wenn NAME nicht existiert." +" Meldet Erfolg, außer wenn `Name' nicht existiert." # unalias #: builtins.c:276 @@ -2460,7 +2366,6 @@ msgstr "" # bind #: builtins.c:289 -#, fuzzy msgid "" "Set Readline key bindings and variables.\n" " \n" @@ -2472,24 +2377,20 @@ msgid "" " Options:\n" " -m keymap Use KEYMAP as the keymap for the duration of this\n" " command. Acceptable keymap names are emacs,\n" -" emacs-standard, emacs-meta, emacs-ctlx, vi, vi-" -"move,\n" +" emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move,\n" " vi-command, and vi-insert.\n" " -l List names of functions.\n" " -P List function names and bindings.\n" " -p List functions and bindings in a form that can be\n" " reused as input.\n" -" -S List key sequences that invoke macros and their " -"values\n" -" -s List key sequences that invoke macros and their " -"values\n" +" -S List key sequences that invoke macros and their values\n" +" -s List key sequences that invoke macros and their values\n" " in a form that can be reused as input.\n" " -V List variable names and values\n" " -v List variable names and values in a form that can\n" " be reused as input.\n" " -q function-name Query about which keys invoke the named function.\n" -" -u function-name Unbind all keys which are bound to the named " -"function.\n" +" -u function-name Unbind all keys which are bound to the named function.\n" " -r keyseq Remove the binding for KEYSEQ.\n" " -f filename Read key bindings from FILENAME.\n" " -x keyseq:shell-command\tCause SHELL-COMMAND to be executed when\n" @@ -2503,48 +2404,40 @@ msgstr "" "Konfiguriert Readline Tastenzuordnungen und Variablen.\n" " \n" " Weist eine Tastensequenz einer Readline Funktion oder einem Makro\n" -" zu oder setzt eine Readline Variable. Der non-option Argument\n" -" syntax ist zu den EintrÀgen in ~/.inputrc Àquivalent, aber sie\n" -" mĂƒÂŒssen als einzelnes Argument ĂƒÂŒbergeben werden. Z.B: bind\n" -" '\"\\C-x\\C-r\": re-read-init-file'.\n" +" zu oder setzt eine Readline Variable. Der Argument syntax ist zu\n" +" den EintrÀgen in ~/.inputrc Àquivalent, aber sie mĂƒÂŒssen als\n" +" einzelnes Argument ĂƒÂŒbergeben werden. Z.B: bind '\"\\C-x\\C-r\":\n" +" re-read-init-file'.\n" " \n" " Optionen:\n" -" -m Keymap Benutzt KEYMAP as Tastaturbelegung fĂƒÂŒr die " -"Laufzeit\n" -" dieses Kommandos. GĂƒÂŒltige Keymap Namen sind: " -"emacs,\n" -" emacs-standard, emacs-meta, emacs-ctlx, vi, vi-" -"move,\n" +" -m Keymap Benutzt KEYMAP as Tastaturbelegung fĂƒÂŒr die Laufzeit\n" +" dieses Kommandos. GĂƒÂŒltige Keymap Namen sind: emacs,\n" +" emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move,\n" " vi-command und vi-insert.\n" " -l Listet Funktionsnamen auf.\n" " -P Listet Funktionsnamen und Tastenzuordnungen auf.\n" -" -p Listet Funktionsnamen und Tastenzuordnungen so " -"auf,\n" -" dass sie direkt als Eingabe verwendet werden " -"können.\n" -" -S Listet Tastenfolgen und deren Werte auf, die " -"Makros \n" +" -p Listet Funktionsnamen und Tastenzuordnungen so auf,\n" +" dass sie direkt als Eingabe verwendet werden können.\n" +" -S Listet Tastenfolgen und deren Werte auf, die Makros \n" " aufrufen.\n" -" -s Listet Tastenfolgen und deren Werte auf, die " -"Makros \n" -" aufrufen, dass sie als Eingabe wiederverwendet " -"werden\n" +" -s Listet Tastenfolgen und deren Werte auf, die Makros \n" +" aufrufen, dass sie als Eingabe wiederverwendet werden\n" " können.\n" " -V Listet Variablennamen und Werte auf.\n" -" -v Listet Variablennamen und Werte so auf, dass sie " -"als\n" +" -v Listet Variablennamen und Werte so auf, dass sie als\n" " Eingabe verwendet werden können.\n" -" -q Funktionsname Sucht die Tastenfolgen, welche die angegebene " -"Funktion aufrufen.\n" -" -u Funktionsname Entfernt alle der Funktion zugeordneten " -"Tastenfolgen.\n" -" -r Tastenfolge Entfernt die Zuweisungen der angegebeben " -"Tastenfolge.\n" -" -f Dateiname Liest die Tastenzuordnungen aus der angegebenen " -"Datei.\n" -" -x Tastenfolge:Shellkommando\tWeist der Tastenfolge das " -"Shellkommando\n" +" -q Funktionsname Sucht die Tastenfolgen, welche die angegebene\n" +" Funktion aufrufen.\n" +" -u Funktionsname Entfernt alle der Funktion zugeordneten Tastenfolgen.\n" +" -r Tastenfolge Entfernt die Zuweisungen der angegebeben Tastenfolge.\n" +" -f Dateiname Liest die Tastenzuordnungen aus der angegebenen Datei.\n" +" -x Tastenfolge:Shellkommando\tWeist der Tastenfolge das Shellkommando\n" " \t\t\t\t\tzu.\n" +" -X Listet mit -x erzeugte\n" +" Tastenfolgen und deren Werte\n" +" auf, die Makros aufrufen, dass\n" +" sie als Eingabe wiederverwendet werden\n" +" können.\n" " \n" " RĂƒÂŒckgabewert: \n" " Bind gibt 0 zurĂƒÂŒck, wenn keine unerkannte Option angegeben wurde\n" @@ -2597,8 +2490,7 @@ msgid "" " \n" " Execute SHELL-BUILTIN with arguments ARGs without performing command\n" " lookup. This is useful when you wish to reimplement a shell builtin\n" -" as a shell function, but need to execute the builtin within the " -"function.\n" +" as a shell function, but need to execute the builtin within the function.\n" " \n" " Exit Status:\n" " Returns the exit status of SHELL-BUILTIN, or false if SHELL-BUILTIN is\n" @@ -2634,26 +2526,19 @@ msgstr "" # cd #: builtins.c:385 -#, fuzzy msgid "" "Change the shell working directory.\n" " \n" -" Change the current directory to DIR. The default DIR is the value of " -"the\n" +" Change the current directory to DIR. The default DIR is the value of the\n" " HOME shell variable.\n" " \n" -" The variable CDPATH defines the search path for the directory " -"containing\n" -" DIR. Alternative directory names in CDPATH are separated by a colon " -"(:).\n" -" A null directory name is the same as the current directory. If DIR " -"begins\n" +" The variable CDPATH defines the search path for the directory containing\n" +" DIR. Alternative directory names in CDPATH are separated by a colon (:).\n" +" A null directory name is the same as the current directory. If DIR begins\n" " with a slash (/), then CDPATH is not used.\n" " \n" -" If the directory is not found, and the shell option `cdable_vars' is " -"set,\n" -" the word is assumed to be a variable name. If that variable has a " -"value,\n" +" If the directory is not found, and the shell option `cdable_vars' is set,\n" +" the word is assumed to be a variable name. If that variable has a value,\n" " its value is used for DIR.\n" " \n" " Options:\n" @@ -2666,13 +2551,11 @@ msgid "" " \tcannot be determined successfully, exit with a non-zero status\n" " \n" " The default is to follow symbolic links, as if `-L' were specified.\n" -" `..' is processed by removing the immediately previous pathname " -"component\n" +" `..' is processed by removing the immediately previous pathname component\n" " back to a slash or the beginning of DIR.\n" " \n" " Exit Status:\n" -" Returns 0 if the directory is changed, and if $PWD is set successfully " -"when\n" +" Returns 0 if the directory is changed, and if $PWD is set successfully when\n" " -P is used; non-zero otherwise." msgstr "" "Wechselt das Arbeitsverzeichnis.\n" @@ -2692,14 +2575,20 @@ msgstr "" " Wert besitzt, wird dieser als Inhalt von DIR verwendet.\n" " \n" " Optionen:\n" -" -L\tErzwingt das Folgen symbolischer Verweise.\n" -" -P\tSymbolische Verweise werden ignoriert.\n" -" -e\tZusammen mit der »-P« Option wird der RĂƒÂŒckgabewert ungleich 0, \n" -"\t\twenn das aktuelle Arbeitsverzeichns nach einem\n" -"\t\terfolgreichn Verzeichniswechsel nicht ermittelt werden\n" -"\t\tkonnte.\n" -" \n" -" StandardmĂƒÂ€ĂƒÂŸig wird symbolischen Verweisen gefolgt.\n" +" -L\tErzwingt das symbolischen Verweisen gefolgt wird.\n" +" Symbolische Links im aktuellen Verzeichnis werden nach\n" +" dem ĂƒÂŒbergeordneten Verzeichnis aufgelöst.\n" +" -P\tSymbolische Verweise werden ignoriert. Symbolische\n" +" Links im aktuellen Verzeichnis werden vor dem\n" +" ĂƒÂŒbergeordneten Verzeichnis aufgelöst.\n" +" -e\tWenn mit der »-P« das aktuelle Arbeitsverzeichns nicht\n" +" ermittelt werden kann, wird ein RĂƒÂŒckgabwert ungleich 0\n" +" geliefert.\n" +" \n" +" StandardmĂƒÂ€ĂƒÂŸig wird symbolischen Verweisen gefolgt (Option -L).\n" +" Das ĂƒÂŒbergeordnete Verzeichnis wird ermittelt, indem der\n" +" Dateiname am letzten SchrÀgstrich gekĂƒÂŒrzt wird oder es wird der\n" +" Anfang von DIR verwendet.\n" " \n" " RĂƒÂŒckgabewert: \n" " Der RĂƒÂŒckgabewert ist 0, wenn das Verzeichnis gewechselt wurde,\n" @@ -2784,8 +2673,7 @@ msgid "" "Execute a simple command or display information about commands.\n" " \n" " Runs COMMAND with ARGS suppressing shell function lookup, or display\n" -" information about the specified COMMANDs. Can be used to invoke " -"commands\n" +" information about the specified COMMANDs. Can be used to invoke commands\n" " on disk when a function with the same name exists.\n" " \n" " Options:\n" @@ -2829,8 +2717,7 @@ msgid "" " Variables with the integer attribute have arithmetic evaluation (see\n" " the `let' command) performed when the variable is assigned a value.\n" " \n" -" When used in a function, `declare' makes NAMEs local, as with the " -"`local'\n" +" When used in a function, `declare' makes NAMEs local, as with the `local'\n" " command. The `-g' option suppresses this behavior.\n" " \n" " Exit Status:\n" @@ -2849,7 +2736,6 @@ msgstr "" " Veraltet. Siehe `help declare'." #: builtins.c:533 -#, fuzzy msgid "" "Define local variables.\n" " \n" @@ -2865,25 +2751,23 @@ msgid "" msgstr "" "Definiert lokale Variablen.\n" " \n" -" Erzeugt eine Lokale Variable NAME und weist ihr den Wert VALUE zu. " -"OPTION\n" -" kann eine beliebige von `declare' akzeptierte Option sein.\n" +" Erzeugt eine Lokale Variable NAME und weist ihr den Wert VALUE zu.\n" +" OPTION kann eine beliebige von `declare' akzeptierte Option sein.\n" "\n" -" Lokale Variablen können nur innerhalb einer Funktion benutzt werden. " -"Sie\n" -" sind nur in der sie erzeugenden Funktion und ihren Kindern " -"sichtbar. \n" +" Lokale Variablen können nur innerhalb einer Funktion benutzt\n" +" werden. Sie sind nur in der sie erzeugenden Funktion und ihren\n" +" Kindern sichtbar.\n" " \n" -" RĂƒÂŒckgabewert:\n" -" Liefert \"Erfolg\" außer bei einer ungĂƒÂŒltigen Option, einem Fehler oder\n" -" die Shell fĂƒÂŒhrt keine Funktion aus." +" RĂƒÂŒckgabewert: \n" +" Liefert 0 außer bei Angabe einer ungĂƒÂŒltigen Option, einer\n" +" fehlerhaften Variablenzuweisung oder dem Aufruf außerhalb einer\n" +" Funktion." #: builtins.c:550 msgid "" "Write arguments to the standard output.\n" " \n" -" Display the ARGs, separated by a single space character and followed by " -"a\n" +" Display the ARGs, separated by a single space character and followed by a\n" " newline, on the standard output.\n" " \n" " Options:\n" @@ -2956,8 +2840,7 @@ msgstr "" msgid "" "Execute arguments as a shell command.\n" " \n" -" Combine ARGs into a single string, use the result as input to the " -"shell,\n" +" Combine ARGs into a single string, use the result as input to the shell,\n" " and execute the resulting commands.\n" " \n" " Exit Status:\n" @@ -3018,8 +2901,7 @@ msgid "" "Replace the shell with the given command.\n" " \n" " Execute COMMAND, replacing this shell with the specified program.\n" -" ARGUMENTS become the arguments to COMMAND. If COMMAND is not " -"specified,\n" +" ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified,\n" " any redirections take effect in the current shell.\n" " \n" " Options:\n" @@ -3027,13 +2909,11 @@ msgid "" " -c\t\texecute COMMAND with an empty environment\n" " -l\t\tplace a dash in the zeroth argument to COMMAND\n" " \n" -" If the command cannot be executed, a non-interactive shell exits, " -"unless\n" +" If the command cannot be executed, a non-interactive shell exits, unless\n" " the shell option `execfail' is set.\n" " \n" " Exit Status:\n" -" Returns success unless COMMAND is not found or a redirection error " -"occurs." +" Returns success unless COMMAND is not found or a redirection error occurs." msgstr "" # exit @@ -3046,16 +2926,14 @@ msgid "" msgstr "" "Beendet die aktuelle Shell.\n" "\n" -" Beendt die die aktuelle Shell mit dem RĂƒÂŒckgabewert N. Wenn N nicht " -"angegeben ist,\n" +" Beendt die die aktuelle Shell mit dem RĂƒÂŒckgabewert N. Wenn N nicht angegeben ist,\n" " wird der RĂƒÂŒckgabewert des letzten ausgefĂƒÂŒhrten Kommandos ĂƒÂŒbernommen." #: builtins.c:713 msgid "" "Exit a login shell.\n" " \n" -" Exits a login shell with exit status N. Returns an error if not " -"executed\n" +" Exits a login shell with exit status N. Returns an error if not executed\n" " in a login shell." msgstr "" @@ -3064,15 +2942,13 @@ msgstr "" msgid "" "Display or execute commands from the history list.\n" " \n" -" fc is used to list or edit and re-execute commands from the history " -"list.\n" +" fc is used to list or edit and re-execute commands from the history list.\n" " FIRST and LAST can be numbers specifying the range, or FIRST can be a\n" " string, which means the most recent command beginning with that\n" " string.\n" " \n" " Options:\n" -" -e ENAME\tselect which editor to use. Default is FCEDIT, then " -"EDITOR,\n" +" -e ENAME\tselect which editor to use. Default is FCEDIT, then EDITOR,\n" " \t\tthen vi\n" " -l \tlist lines instead of editing\n" " -n\tomit line numbers when listing\n" @@ -3086,8 +2962,7 @@ msgid "" " the last command.\n" " \n" " Exit Status:\n" -" Returns success or status of executed command; non-zero if an error " -"occurs." +" Returns success or status of executed command; non-zero if an error occurs." msgstr "" #: builtins.c:753 @@ -3114,10 +2989,8 @@ msgstr "" msgid "" "Move jobs to the background.\n" " \n" -" Place the jobs identified by each JOB_SPEC in the background, as if " -"they\n" -" had been started with `&'. If JOB_SPEC is not present, the shell's " -"notion\n" +" Place the jobs identified by each JOB_SPEC in the background, as if they\n" +" had been started with `&'. If JOB_SPEC is not present, the shell's notion\n" " of the current job is used.\n" " \n" " Exit Status:\n" @@ -3137,13 +3010,12 @@ msgid "" "Remember or display program locations.\n" " \n" " Determine and remember the full pathname of each command NAME. If\n" -" no arguments are given, information about remembered commands is " -"displayed.\n" +" no arguments are given, information about remembered commands is displayed.\n" " \n" " Options:\n" " -d\t\tforget the remembered location of each NAME\n" " -l\t\tdisplay in a format that may be reused as input\n" -" -p pathname\tuse PATHNAME as the full pathname of NAME\n" +" -p pathname\tuse PATHNAME is the full pathname of NAME\n" " -r\t\tforget all remembered locations\n" " -t\t\tprint the remembered location of each NAME, preceding\n" " \t\teach location with the corresponding NAME if multiple\n" @@ -3174,8 +3046,7 @@ msgid "" " PATTERN\tPattern specifiying a help topic\n" " \n" " Exit Status:\n" -" Returns success unless PATTERN is not found or an invalid option is " -"given." +" Returns success unless PATTERN is not found or an invalid option is given." msgstr "" #: builtins.c:831 @@ -3205,8 +3076,7 @@ msgid "" " \n" " If the $HISTTIMEFORMAT variable is set and not null, its value is used\n" " as a format string for strftime(3) to print the time stamp associated\n" -" with each displayed history entry. No time stamps are printed " -"otherwise.\n" +" with each displayed history entry. No time stamps are printed otherwise.\n" " \n" " Exit Status:\n" " Returns success unless an invalid option is given or an error occurs." @@ -3282,8 +3152,7 @@ msgid "" " Evaluate each ARG as an arithmetic expression. Evaluation is done in\n" " fixed-width integers with no check for overflow, though division by 0\n" " is trapped and flagged as an error. The following list of operators is\n" -" grouped into levels of equal-precedence operators. The levels are " -"listed\n" +" grouped into levels of equal-precedence operators. The levels are listed\n" " in order of decreasing precedence.\n" " \n" " \tid++, id--\tvariable post-increment, post-decrement\n" @@ -3325,16 +3194,13 @@ msgid "" "Read a line from the standard input and split it into fields.\n" " \n" " Reads a single line from the standard input, or from file descriptor FD\n" -" if the -u option is supplied. The line is split into fields as with " -"word\n" +" if the -u option is supplied. The line is split into fields as with word\n" " splitting, and the first word is assigned to the first NAME, the second\n" " word to the second NAME, and so on, with any leftover words assigned to\n" -" the last NAME. Only the characters found in $IFS are recognized as " -"word\n" +" the last NAME. Only the characters found in $IFS are recognized as word\n" " delimiters.\n" " \n" -" If no NAMEs are supplied, the line read is stored in the REPLY " -"variable.\n" +" If no NAMEs are supplied, the line read is stored in the REPLY variable.\n" " \n" " Options:\n" " -a array\tassign the words read to sequential indices of the array\n" @@ -3346,15 +3212,13 @@ msgid "" " -n nchars\treturn after reading NCHARS characters rather than waiting\n" " \t\tfor a newline, but honor a delimiter if fewer than NCHARS\n" " \t\tcharacters are read before the delimiter\n" -" -N nchars\treturn only after reading exactly NCHARS characters, " -"unless\n" +" -N nchars\treturn only after reading exactly NCHARS characters, unless\n" " \t\tEOF is encountered or read times out, ignoring any delimiter\n" " -p prompt\toutput the string PROMPT without a trailing newline before\n" " \t\tattempting to read\n" " -r\t\tdo not allow backslashes to escape any characters\n" " -s\t\tdo not echo input coming from a terminal\n" -" -t timeout\ttime out and return failure if a complete line of input " -"is\n" +" -t timeout\ttime out and return failure if a complete line of input is\n" " \t\tnot read within TIMEOUT seconds. The value of the TMOUT\n" " \t\tvariable is the default timeout. TIMEOUT may be a\n" " \t\tfractional number. If TIMEOUT is 0, read returns immediately,\n" @@ -3364,10 +3228,8 @@ msgid "" " -u fd\t\tread from file descriptor FD instead of the standard input\n" " \n" " Exit Status:\n" -" The return code is zero, unless end-of-file is encountered, read times " -"out\n" -" (in which case it's greater than 128), a variable assignment error " -"occurs,\n" +" The return code is zero, unless end-of-file is encountered, read times out\n" +" (in which case it's greater than 128), a variable assignment error occurs,\n" " or an invalid file descriptor is supplied as the argument to -u." msgstr "" @@ -3426,8 +3288,7 @@ msgid "" " physical same as -P\n" " pipefail the return value of a pipeline is the status of\n" " the last command to exit with a non-zero status,\n" -" or zero if no command exited with a non-zero " -"status\n" +" or zero if no command exited with a non-zero status\n" " posix change the behavior of bash where the default\n" " operation differs from the Posix standard to\n" " match the standard\n" @@ -3480,8 +3341,7 @@ msgid "" " -n\ttreat each NAME as a name reference and unset the variable itself\n" " \trather than the variable it references\n" " \n" -" Without options, unset first tries to unset a variable, and if that " -"fails,\n" +" Without options, unset first tries to unset a variable, and if that fails,\n" " tries to unset a function.\n" " \n" " Some variables cannot be unset; also see `readonly'.\n" @@ -3495,8 +3355,7 @@ msgid "" "Set export attribute for shell variables.\n" " \n" " Marks each NAME for automatic export to the environment of subsequently\n" -" executed commands. If VALUE is supplied, assign VALUE before " -"exporting.\n" +" executed commands. If VALUE is supplied, assign VALUE before exporting.\n" " \n" " Options:\n" " -f\trefer to shell functions\n" @@ -3521,9 +3380,7 @@ msgid "" " -a\trefer to indexed array variables\n" " -A\trefer to associative array variables\n" " -f\trefer to shell functions\n" -" -p\tdisplay a list of all readonly variables or functions, depending " -"on\n" -" whether or not the -f option is given\n" +" -p\tdisplay a list of all readonly variables and functions\n" " \n" " An argument of `--' disables further option processing.\n" " \n" @@ -3531,7 +3388,7 @@ msgid "" " Returns success unless an invalid option is given or NAME is invalid." msgstr "" -#: builtins.c:1187 +#: builtins.c:1186 msgid "" "Shift positional parameters.\n" " \n" @@ -3542,7 +3399,7 @@ msgid "" " Returns success unless N is negative or greater than $#." msgstr "" -#: builtins.c:1199 builtins.c:1214 +#: builtins.c:1198 builtins.c:1213 msgid "" "Execute commands from a file in the current shell.\n" " \n" @@ -3556,7 +3413,7 @@ msgid "" " FILENAME cannot be read." msgstr "" -#: builtins.c:1230 +#: builtins.c:1229 msgid "" "Suspend shell execution.\n" " \n" @@ -3570,7 +3427,7 @@ msgid "" " Returns success unless job control is not enabled or an error occurs." msgstr "" -#: builtins.c:1246 +#: builtins.c:1245 msgid "" "Evaluate conditional expression.\n" " \n" @@ -3604,8 +3461,7 @@ msgid "" " -x FILE True if the file is executable by you.\n" " -O FILE True if the file is effectively owned by you.\n" " -G FILE True if the file is effectively owned by your group.\n" -" -N FILE True if the file has been modified since it was last " -"read.\n" +" -N FILE True if the file has been modified since it was last read.\n" " \n" " FILE1 -nt FILE2 True if file1 is newer than file2 (according to\n" " modification date).\n" @@ -3626,8 +3482,7 @@ msgid "" " STRING1 != STRING2\n" " True if the strings are not equal.\n" " STRING1 < STRING2\n" -" True if STRING1 sorts before STRING2 " -"lexicographically.\n" +" True if STRING1 sorts before STRING2 lexicographically.\n" " STRING1 > STRING2\n" " True if STRING1 sorts after STRING2 lexicographically.\n" " \n" @@ -3635,8 +3490,7 @@ msgid "" " \n" " -o OPTION True if the shell option OPTION is enabled.\n" " -v VAR\t True if the shell variable VAR is set\n" -" -R VAR\t True if the shell variable VAR is set and is a name " -"reference.\n" +" -R VAR\t True if the shell variable VAR is set and is a name reference.\n" " ! EXPR True if expr is false.\n" " EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.\n" " EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.\n" @@ -3654,7 +3508,7 @@ msgid "" msgstr "" # [ -#: builtins.c:1327 +#: builtins.c:1326 msgid "" "Evaluate conditional expression.\n" " \n" @@ -3668,12 +3522,11 @@ msgstr "" " schließt." # times -#: builtins.c:1336 +#: builtins.c:1335 msgid "" "Display process times.\n" " \n" -" Prints the accumulated user and system times for the shell and all of " -"its\n" +" Prints the accumulated user and system times for the shell and all of its\n" " child processes.\n" " \n" " Exit Status:\n" @@ -3687,12 +3540,11 @@ msgstr "" " RĂƒÂŒckgabewert:\n" " Immer 0." -#: builtins.c:1348 +#: builtins.c:1347 msgid "" "Trap signals and other events.\n" " \n" -" Defines and activates handlers to be run when the shell receives " -"signals\n" +" Defines and activates handlers to be run when the shell receives signals\n" " or other conditions.\n" " \n" " ARG is a command to be read and executed when the shell receives the\n" @@ -3701,37 +3553,29 @@ msgid "" " value. If ARG is the null string each SIGNAL_SPEC is ignored by the\n" " shell and by the commands it invokes.\n" " \n" -" If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell. " -"If\n" -" a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command. " -"If\n" -" a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or " -"a\n" -" script run by the . or source builtins finishes executing. A " -"SIGNAL_SPEC\n" -" of ERR means to execute ARG each time a command's failure would cause " -"the\n" +" If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell. If\n" +" a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command. If\n" +" a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a\n" +" script run by the . or source builtins finishes executing. A SIGNAL_SPEC\n" +" of ERR means to execute ARG each time a command's failure would cause the\n" " shell to exit when the -e option is enabled.\n" " \n" -" If no arguments are supplied, trap prints the list of commands " -"associated\n" +" If no arguments are supplied, trap prints the list of commands associated\n" " with each signal.\n" " \n" " Options:\n" " -l\tprint a list of signal names and their corresponding numbers\n" " -p\tdisplay the trap commands associated with each SIGNAL_SPEC\n" " \n" -" Each SIGNAL_SPEC is either a signal name in or a signal " -"number.\n" +" Each SIGNAL_SPEC is either a signal name in or a signal number.\n" " Signal names are case insensitive and the SIG prefix is optional. A\n" " signal may be sent to the shell with \"kill -signal $$\".\n" " \n" " Exit Status:\n" -" Returns success unless a SIGSPEC is invalid or an invalid option is " -"given." +" Returns success unless a SIGSPEC is invalid or an invalid option is given." msgstr "" -#: builtins.c:1384 +#: builtins.c:1383 msgid "" "Display information about command type.\n" " \n" @@ -3757,16 +3601,14 @@ msgid "" " NAME\tCommand name to be interpreted.\n" " \n" " Exit Status:\n" -" Returns success if all of the NAMEs are found; fails if any are not " -"found." +" Returns success if all of the NAMEs are found; fails if any are not found." msgstr "" -#: builtins.c:1415 +#: builtins.c:1414 msgid "" "Modify shell resource limits.\n" " \n" -" Provides control over the resources available to the shell and " -"processes\n" +" Provides control over the resources available to the shell and processes\n" " it creates, on systems that allow such control.\n" " \n" " Options:\n" @@ -3808,7 +3650,7 @@ msgid "" " Returns success unless an invalid option is supplied or an error occurs." msgstr "" -#: builtins.c:1463 +#: builtins.c:1462 msgid "" "Display or set file mode mask.\n" " \n" @@ -3826,16 +3668,14 @@ msgid "" " Returns success unless MODE is invalid or an invalid option is given." msgstr "" -#: builtins.c:1483 +#: builtins.c:1482 msgid "" "Wait for job completion and return exit status.\n" " \n" -" Waits for each process identified by an ID, which may be a process ID or " -"a\n" +" Waits for each process identified by an ID, which may be a process ID or a\n" " job specification, and reports its termination status. If ID is not\n" " given, waits for all currently active child processes, and the return\n" -" status is zero. If ID is a a job specification, waits for all " -"processes\n" +" status is zero. If ID is a a job specification, waits for all processes\n" " in that job's pipeline.\n" " \n" " If the -n option is supplied, waits for the next job to terminate and\n" @@ -3846,22 +3686,20 @@ msgid "" " option is given." msgstr "" -#: builtins.c:1504 +#: builtins.c:1503 msgid "" "Wait for process completion and return exit status.\n" " \n" -" Waits for each process specified by a PID and reports its termination " -"status.\n" +" Waits for each process specified by a PID and reports its termination status.\n" " If PID is not given, waits for all currently active child processes,\n" " and the return status is zero. PID must be a process ID.\n" " \n" " Exit Status:\n" -" Returns the status of the last PID; fails if PID is invalid or an " -"invalid\n" +" Returns the status of the last PID; fails if PID is invalid or an invalid\n" " option is given." msgstr "" -#: builtins.c:1519 +#: builtins.c:1518 msgid "" "Execute commands for each member in a list.\n" " \n" @@ -3874,7 +3712,7 @@ msgid "" " Returns the status of the last command executed." msgstr "" -#: builtins.c:1533 +#: builtins.c:1532 msgid "" "Arithmetic for loop.\n" " \n" @@ -3891,7 +3729,7 @@ msgid "" " Returns the status of the last command executed." msgstr "" -#: builtins.c:1551 +#: builtins.c:1550 msgid "" "Select words from a list and execute commands.\n" " \n" @@ -3911,7 +3749,7 @@ msgid "" " Returns the status of the last command executed." msgstr "" -#: builtins.c:1572 +#: builtins.c:1571 msgid "" "Report time consumed by pipeline's execution.\n" " \n" @@ -3927,7 +3765,7 @@ msgid "" " The return status is the return status of PIPELINE." msgstr "" -#: builtins.c:1589 +#: builtins.c:1588 msgid "" "Execute commands based on pattern matching.\n" " \n" @@ -3938,28 +3776,23 @@ msgid "" " Returns the status of the last command executed." msgstr "" -#: builtins.c:1601 +#: builtins.c:1600 msgid "" "Execute commands based on conditional.\n" " \n" -" The `if COMMANDS' list is executed. If its exit status is zero, then " -"the\n" -" `then COMMANDS' list is executed. Otherwise, each `elif COMMANDS' list " -"is\n" +" The `if COMMANDS' list is executed. If its exit status is zero, then the\n" +" `then COMMANDS' list is executed. Otherwise, each `elif COMMANDS' list is\n" " executed in turn, and if its exit status is zero, the corresponding\n" -" `then COMMANDS' list is executed and the if command completes. " -"Otherwise,\n" -" the `else COMMANDS' list is executed, if present. The exit status of " -"the\n" -" entire construct is the exit status of the last command executed, or " -"zero\n" +" `then COMMANDS' list is executed and the if command completes. Otherwise,\n" +" the `else COMMANDS' list is executed, if present. The exit status of the\n" +" entire construct is the exit status of the last command executed, or zero\n" " if no condition tested true.\n" " \n" " Exit Status:\n" " Returns the status of the last command executed." msgstr "" -#: builtins.c:1618 +#: builtins.c:1617 msgid "" "Execute commands as long as a test succeeds.\n" " \n" @@ -3970,7 +3803,7 @@ msgid "" " Returns the status of the last command executed." msgstr "" -#: builtins.c:1630 +#: builtins.c:1629 msgid "" "Execute commands as long as a test does not succeed.\n" " \n" @@ -3981,7 +3814,7 @@ msgid "" " Returns the status of the last command executed." msgstr "" -#: builtins.c:1642 +#: builtins.c:1641 msgid "" "Create a coprocess named NAME.\n" " \n" @@ -3994,13 +3827,12 @@ msgid "" " Returns the exit status of COMMAND." msgstr "" -#: builtins.c:1656 +#: builtins.c:1655 msgid "" "Define shell function.\n" " \n" " Create a shell function named NAME. When invoked as a simple command,\n" -" NAME runs COMMANDs in the calling shell's context. When NAME is " -"invoked,\n" +" NAME runs COMMANDs in the calling shell's context. When NAME is invoked,\n" " the arguments are passed to the function as $1...$n, and the function's\n" " name is in $FUNCNAME.\n" " \n" @@ -4008,7 +3840,7 @@ msgid "" " Returns success unless NAME is readonly." msgstr "" -#: builtins.c:1670 +#: builtins.c:1669 msgid "" "Group commands as a unit.\n" " \n" @@ -4019,7 +3851,7 @@ msgid "" " Returns the status of the last command executed." msgstr "" -#: builtins.c:1682 +#: builtins.c:1681 msgid "" "Resume job in foreground.\n" " \n" @@ -4033,7 +3865,7 @@ msgid "" " Returns the status of the resumed job." msgstr "" -#: builtins.c:1697 +#: builtins.c:1696 msgid "" "Evaluate arithmetic expression.\n" " \n" @@ -4044,16 +3876,13 @@ msgid "" " Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise." msgstr "" -#: builtins.c:1709 +#: builtins.c:1708 msgid "" "Execute conditional command.\n" " \n" -" Returns a status of 0 or 1 depending on the evaluation of the " -"conditional\n" -" expression EXPRESSION. Expressions are composed of the same primaries " -"used\n" -" by the `test' builtin, and may be combined using the following " -"operators:\n" +" Returns a status of 0 or 1 depending on the evaluation of the conditional\n" +" expression EXPRESSION. Expressions are composed of the same primaries used\n" +" by the `test' builtin, and may be combined using the following operators:\n" " \n" " ( EXPRESSION )\tReturns the value of EXPRESSION\n" " ! EXPRESSION\t\tTrue if EXPRESSION is false; else false\n" @@ -4073,8 +3902,7 @@ msgid "" msgstr "" # variable_help -#: builtins.c:1735 -#, fuzzy +#: builtins.c:1734 msgid "" "Common shell variable names and usage.\n" " \n" @@ -4128,63 +3956,64 @@ msgid "" " \t\tcommands should be saved on the history list.\n" msgstr "" " BASH_VERSION\tVersionsnummer der Bash.\n" -" CDPATH\tEine durch Doppelpunkt getrennte Liste von\n" -" Verzeichnissen, die\t\tdurchsucht werden, wenn das Argument\n" -" von `cd' nicht im\t\taktuellen Verzeichnis gefunden wird.\n" +" CDPATH\tEine durch Doppelpunkte getrennte Liste von\n" +" Verzeichnissen, die durchsucht werden, wenn das\n" +" Argument von `cd' nicht im aktuellen Verzeichnis\n" +" gefunden wird.\n" +" GLOBIGNORE Eine durch Doppelpunkte getrennte Liste von\n" +" Dateinamenmustern, die fĂƒÂŒr die DateinamensergÀnzung\n" +" ignoriert werden.\n" " HISTFILE\tDatei, die den Kommandozeilenspeicher enthÀlt.\n" -" HISTFILESIZE\tMaximale Zeilenanzahl, die diese Datei\n" -" enthalten darf.\n" +" HISTFILESIZE\tMaximale Zeilenanzahl, dieser Datei.\n" " HISTSIZE\tMaximale Anzahl von Zeilen, auf die der\n" -" Historymechanismus\t\tder Shell zurĂƒÂŒckgreifen kann.\n" +" Historymechanismus der Shell zurĂƒÂŒckgreifen kann.\n" " HOME\tHeimatverzeichnis des aktuellen Benutzers.\n" -" HOSTTYPE\tCPU-Typ des Rechners, auf dem die Bash gegenwÀrtig\n" -" lÀuft.\n" +" HOSTNAME Der aktuelle Rechnername.\n" +" HOSTTYPE\tCPU-Typ des aktuellen Rechners.\n" " IGNOREEOF\tLegt die Reaktion der Shell auf ein EOF-Zeichen fest.\n" -" Wenn die Variable eine ganze Zahl enthÀlt, wird diese Anzahl\n" -" EOF Zeichen (Ctrl-D) abgewartet, bis die Shell verlassen wird.\n" -" Der Vorgabewert ist 10. Ist IGNOREEOF nicht gesetzt,\n" -" signalisiert EOF das Ende der Eingabe.\n" -" MAILCHECK\tZeitintervall [s], in dem nach angekommener Post\n" -" gesucht wird.\n" -" MAILPATH\tEine durch Doppelpunkt getrennte Liste von Dateien,\n" -" die nach\t\tneu angekommener Post durchsucht werden.\n" -" OSTYPE\tBetriebssystemversion, auf der die Bash gegenwÀrtig\n" -" lÀuft.\n" +" Wenn die Variable eine ganze Zahl enthÀlt, wird diese\n" +" Anzahl EOF Zeichen (Ctrl-D) abgewartet, bis die Shell\n" +" verlassen wird. Der Vorgabewert ist 10. Ist IGNOREEOF\n" +" nicht gesetzt, signalisiert EOF das Ende der Eingabe.\n" +" MACHTYPE Eine Zeichenkette die das aktuell laufende System beschreibt.\n" +" MAILCHECK\tZeit in s, nach der nach E-Mail gesehen wird.\n" +" MAILPATH\tEine durch Doppelpunkt getrennte Liste von Dateinamen,\n" +" die nach E-Mail durchsucht werden.\n" +" OSTYPE\tUnix Version, auf der die Bash gegenwÀrtig lÀuft.\n" " PATH\tDurch Doppelpunkt getrennte Liste von Verzeichnissen,\n" -" die nach Kommandos durchsucht werden.\n" +" die nach Kommandos durchsucht werden.\n" " PROMPT_COMMAND\tKommando, das vor der Anzeige einer primÀren\n" -" Eingabeaufforderung (PS1) ausgefĂƒÂŒhrt wird.\n" -" PS1\tZeichenkette, die die primÀre Eingabeaufforderung enthÀlt.\n" -" PS2\tZeichenkette, die die sekundÀre Eingabeaufforderung enthÀlt.\n" +" Eingabeaufforderung (PS1) ausgefĂƒÂŒhrt wird.\n" +" PS1 Zeichenkette, die die primÀre\n" +" Eingabeaufforderung enthÀlt.\n" +" PS2 Zeichenkette, die die sekundÀre\n" +" Eingabeaufforderung enthÀlt.\n" +" PWD Der vollstÀndige aktuelle Verzeichnisname.\n" +" SHELLOPTS Durch Doppelpunkt getrennte Liste der aktiven\n" +" Shell Optionen.\n" " TERM\tName des aktuellen Terminaltyps.\n" -" auto_resume\tEin Wert ungleich Null bewirkt, daß ein einzelnes\n" -" Kommando auf einer Zeile zunÀchst in der Liste\n" -" gegenwÀrtig gestoppter Jobs\tgesucht und dieser in den\n" -" Vordergrund geholt wird. `exact' bewirkt, daß das\n" -" Kommando genau dem Kommando in der Liste der gestoppten\n" -" Jobs entsprechen muß. Wenn die Variable den Wert\n" -" `substring' enthÀlt, muß das Kommando einem Substring\n" -" der Jobbezeichnung entsprechen. Bei einem anderen Wert mĂƒÂŒssen\n" -" die ersten Zeichen ĂƒÂŒbereinstimmen.\n" -" command_oriented_history\tMehrzeilige Kommandos werden im\n" -" Kommandozeilenspeicher in einer\tZeile abgelegt, wenn die\n" -" Variable ungleich Null gesetzt ist.\n" -" histchars Zeichen, die die Befehlswiederholung und die\n" -" Schnellersetzung steuern. An erster Stelle steht das\n" -" Befehlswiederholungszeichen (normalerweise `!'); an zweiter das\n" -" `Schnell-Ersetzen-Zeichen' (normalerweise `^'). Das dritte Zeichen\n" -" ist das\t`Kommentarzeichen' (normalerweise `#').\n" -" HISTCONTROL Gesetzt auf `ignorespace' werden keine mit einem\n" -" \tLeerzeichen oder Tabulator beginnenden Zeilen im\n" -" \tKommandospeicher abgelegt. Der Wert `ignoredups' verhindert\n" -" \tdas Speichern aufeinanderfolgender identischer\n" -" \tZeilen. `ignoreboth' kombiniert beide Einstellungen. Wenn die\n" -" \tVariable nicht oder auf einen anderen Wert gesetzt ist, werden\n" -" \talle eingegebenen Zeilen im Kommandospeicher abgelegt." +" auto_resume Ein Wert ungleich Null bewirkt, daß ein einzelnes\n" +" Kommando auf einer Zeile zunÀchst in der Liste\n" +" gegenwÀrtig gestoppter Jobs gesucht und dieser in den\n" +" Vordergrund geholt wird. `exact' bewirkt, daß das\n" +" Kommando genau dem Kommando in der Liste der\n" +" gestoppten Jobs entsprechen muß. Wenn die Variable den\n" +" Wert `substring' enthÀlt, muß das Kommando einem\n" +" Substring der Jobbezeichnung entsprechen. Bei einem\n" +" anderen Wert mĂƒÂŒssen die ersten Zeichen ĂƒÂŒbereinstimmen.\n" +" histchars Zeichen, die die Befehlswiederholung und die\n" +" Schnellersetzung steuern. An erster Stelle steht\n" +" das Befehlswiederholungszeichen (normalerweise\n" +" `!'); an zweiter das `Schnell-Ersetzen-Zeichen'\n" +" (normalerweise `^'). Das dritte Zeichen ist das\n" +" `Kommentarzeichen' (normalerweise `#').\n" +" HISTIGNORE Eine durch Doppelpunkt getrennte Liste von\n" +" Mustern, welche die in der\n" +" Befehlswiederholungsliste zu speichernden\n" +" Kommandos angibt.\n" # pushd -#: builtins.c:1792 -#, fuzzy +#: builtins.c:1791 msgid "" "Add directories to stack.\n" " \n" @@ -4218,8 +4047,8 @@ msgstr "" "\n" " Legt ein Verzeichnisnamen auf den Verzeichnisstapel oder rotiert\n" " diesen so,daß das Arbeitsverzeichnis auf der Spitze des Stapels\n" -" liegt. OhneArgumente werden die obersten zwei Verzeichnisse auf\n" -" dem Stapel vertauscht.\n" +" liegt. Ohne angegebene Argumente werden die obersten zwei\n" +" Verzeichnisse auf dem Stapel getauscht.\n" "\n" " Optionen:\n" " -n\tunterdrĂƒÂŒckt das Wechseln in das Verzeichnis beim HinzufĂƒÂŒgen\n" @@ -4235,13 +4064,17 @@ msgstr "" " -befindet.\n" " \n" "\n" -" DIR\tLegt DIR auf die Spitze des Verzeichnisstapels und wechselt " -"dorthin.\n" +" DIR\tLegt DIR auf die Spitze des Verzeichnisstapels und wechselt dorthin.\n" +"\n" +" Der Verzeichnisstapel kann mit dem Kommando `dirs' angezeigt\n" +" werden.\n" "\n" -" Der Verzeichnisstapel kann mit dem Kommando `dirs' angezeigt werden." +" RĂƒÂŒckgabewert: \n" +" Gibt Erfolg zurĂƒÂŒck, außer wenn ein ungĂƒÂŒltiges Argument angegeben\n" +" wurde oder der Verzeichniswechsel nicht erfolgreich war." # popd -#: builtins.c:1826 +#: builtins.c:1825 msgid "" "Remove directories from stack.\n" " \n" @@ -4295,7 +4128,7 @@ msgstr "" " wurde oder der Verzeichniswechsel nicht erfolgreich war." # dirs -#: builtins.c:1856 +#: builtins.c:1855 msgid "" "Display directory stack.\n" " \n" @@ -4312,25 +4145,47 @@ msgid "" " \twith its position in the stack\n" " \n" " Arguments:\n" -" +N\tDisplays the Nth entry counting from the left of the list shown " -"by\n" +" +N\tDisplays the Nth entry counting from the left of the list shown by\n" " \tdirs when invoked without options, starting with zero.\n" " \n" -" -N\tDisplays the Nth entry counting from the right of the list shown " -"by\n" +" -N\tDisplays the Nth entry counting from the right of the list shown by\n" " \tdirs when invoked without options, starting with zero.\n" " \n" " Exit Status:\n" " Returns success unless an invalid option is supplied or an error occurs." msgstr "" +"Zeigt den Verzeichnisstapel an.\n" +"\n" +" Zeigt die Liste der gegenwÀrtig gespeicherten Verzeichnisse.\n" +" Diese werden mit dem `pushd' Kommando eingetragen und mit dem\n" +" `popd' Kommando ausgelesen.\n" +"\n" +" Optionen:\n" +" -c Löscht den Verzeichnisstapel.\n" +" -l Keine AbkĂƒÂŒrzung fĂƒÂŒr das Heimatverzeichnis durch die\n" +" Tilde (~).\n" +" -p Ausgabe von einem Eintrag pro Zeile.\n" +" -v Ausgabe von einem Eintrag pro Zeile mit Angabe der\n" +" Position im Stapel<\n" +"\n" +" Argumente:\n" +" +N Gibt das N'te Element von links der Liste aus, die\n" +" ohne Argumente ausgegeben wird. Die ZÀhlung beginnt\n" +" bei 0.\n" +" -N Gibt das N'te Element von rechts der Liste aus, die\n" +" ohne Argumente ausgegeben wird. Die ZÀhlung beginnt\n" +" bei 0.\n" +"\n" +" RĂƒÂŒckgabewert:\n" +" Gibt Erfolg zurĂƒÂŒck, außer bei einer ungĂƒÂŒltigen Option oder wenn\n" +" ein Fehler auftritt." -#: builtins.c:1885 +#: builtins.c:1884 msgid "" "Set and unset shell options.\n" " \n" " Change the setting of each shell option OPTNAME. Without any option\n" -" arguments, list all shell options with an indication of whether or not " -"each\n" +" arguments, list all shell options with an indication of whether or not each\n" " is set.\n" " \n" " Options:\n" @@ -4344,8 +4199,26 @@ msgid "" " Returns success if OPTNAME is enabled; fails if an invalid option is\n" " given or OPTNAME is disabled." msgstr "" +"Setzt oder löscht Shell Optionen.\n" +"\n" +" Ändert die in `Optionsname' genannten Shell Optionen. Ohne\n" +" Argumente wird eine Liste der Shell Optionen un deren Stati\n" +" ausgegeben.\n" +"\n" +" Optionen:\n" +" -o BeschrÀnkt die Optionsmanen auf die, welche mit \n" +" `set -o' definiert werden mĂƒÂŒssen.\n" +" -p Gibt alle Shelloptionen und deren Stati aus.\n" +" -q UnterdrĂƒÂŒckt Ausgaben.\n" +" -s Setzt jede Option in `Optionsname.'\n" +" -u Deaktiviert jede Option in `Optionsname'.\n" +"\n" +" RĂƒÂŒckgabewert:\n" +" Gibt Erfolg zurĂƒÂŒck, wenn eine Option gesetzt worden ist. Wenn\n" +" eine ungĂƒÂŒltige Option angegeben wurde oder eine Option deaktiviert\n" +" worden ist, wird Fehler zurĂƒÂŒckgegeben." -#: builtins.c:1906 +#: builtins.c:1905 msgid "" "Formats and prints ARGUMENTS under control of the FORMAT.\n" " \n" @@ -4353,45 +4226,36 @@ msgid "" " -v var\tassign the output to shell variable VAR rather than\n" " \t\tdisplay it on the standard output\n" " \n" -" FORMAT is a character string which contains three types of objects: " -"plain\n" -" characters, which are simply copied to standard output; character " -"escape\n" +" FORMAT is a character string which contains three types of objects: plain\n" +" characters, which are simply copied to standard output; character escape\n" " sequences, which are converted and copied to the standard output; and\n" -" format specifications, each of which causes printing of the next " -"successive\n" +" format specifications, each of which causes printing of the next successive\n" " argument.\n" " \n" -" In addition to the standard format specifications described in " -"printf(1),\n" +" In addition to the standard format specifications described in printf(1),\n" " printf interprets:\n" " \n" " %b\texpand backslash escape sequences in the corresponding argument\n" " %q\tquote the argument in a way that can be reused as shell input\n" -" %(fmt)T output the date-time string resulting from using FMT as a " -"format\n" +" %(fmt)T output the date-time string resulting from using FMT as a format\n" " string for strftime(3)\n" " \n" " The format is re-used as necessary to consume all of the arguments. If\n" " there are fewer arguments than the format requires, extra format\n" -" specifications behave as if a zero value or null string, as " -"appropriate,\n" +" specifications behave as if a zero value or null string, as appropriate,\n" " had been supplied.\n" " \n" " Exit Status:\n" -" Returns success unless an invalid option is given or a write or " -"assignment\n" +" Returns success unless an invalid option is given or a write or assignment\n" " error occurs." msgstr "" -#: builtins.c:1940 +#: builtins.c:1939 msgid "" "Specify how arguments are to be completed by Readline.\n" " \n" -" For each NAME, specify how arguments are to be completed. If no " -"options\n" -" are supplied, existing completion specifications are printed in a way " -"that\n" +" For each NAME, specify how arguments are to be completed. If no options\n" +" are supplied, existing completion specifications are printed in a way that\n" " allows them to be reused as input.\n" " \n" " Options:\n" @@ -4411,29 +4275,25 @@ msgid "" " Returns success unless an invalid option is supplied or an error occurs." msgstr "" -#: builtins.c:1968 +#: builtins.c:1967 msgid "" "Display possible completions depending on the options.\n" " \n" " Intended to be used from within a shell function generating possible\n" -" completions. If the optional WORD argument is supplied, matches " -"against\n" +" completions. If the optional WORD argument is supplied, matches against\n" " WORD are generated.\n" " \n" " Exit Status:\n" " Returns success unless an invalid option is supplied or an error occurs." msgstr "" -#: builtins.c:1983 +#: builtins.c:1982 msgid "" "Modify or display completion options.\n" " \n" -" Modify the completion options for each NAME, or, if no NAMEs are " -"supplied,\n" -" the completion currently being executed. If no OPTIONs are given, " -"print\n" -" the completion options for each NAME or the current completion " -"specification.\n" +" Modify the completion options for each NAME, or, if no NAMEs are supplied,\n" +" the completion currently being executed. If no OPTIONs are given, print\n" +" the completion options for each NAME or the current completion specification.\n" " \n" " Options:\n" " \t-o option\tSet completion option OPTION for each NAME\n" @@ -4455,28 +4315,22 @@ msgid "" " have a completion specification defined." msgstr "" -#: builtins.c:2013 +#: builtins.c:2012 msgid "" "Read lines from the standard input into an indexed array variable.\n" " \n" -" Read lines from the standard input into the indexed array variable " -"ARRAY, or\n" -" from file descriptor FD if the -u option is supplied. The variable " -"MAPFILE\n" +" Read lines from the standard input into the indexed array variable ARRAY, or\n" +" from file descriptor FD if the -u option is supplied. The variable MAPFILE\n" " is the default ARRAY.\n" " \n" " Options:\n" -" -n count\tCopy at most COUNT lines. If COUNT is 0, all lines are " -"copied.\n" -" -O origin\tBegin assigning to ARRAY at index ORIGIN. The default " -"index is 0.\n" +" -n count\tCopy at most COUNT lines. If COUNT is 0, all lines are copied.\n" +" -O origin\tBegin assigning to ARRAY at index ORIGIN. The default index is 0.\n" " -s count \tDiscard the first COUNT lines read.\n" " -t\t\tRemove a trailing newline from each line read.\n" -" -u fd\t\tRead lines from file descriptor FD instead of the standard " -"input.\n" +" -u fd\t\tRead lines from file descriptor FD instead of the standard input.\n" " -C callback\tEvaluate CALLBACK each time QUANTUM lines are read.\n" -" -c quantum\tSpecify the number of lines read between each call to " -"CALLBACK.\n" +" -c quantum\tSpecify the number of lines read between each call to CALLBACK.\n" " \n" " Arguments:\n" " ARRAY\t\tArray variable name to use for file data.\n" @@ -4486,17 +4340,15 @@ msgid "" " element to be assigned and the line to be assigned to that element\n" " as additional arguments.\n" " \n" -" If not supplied with an explicit origin, mapfile will clear ARRAY " -"before\n" +" If not supplied with an explicit origin, mapfile will clear ARRAY before\n" " assigning to it.\n" " \n" " Exit Status:\n" -" Returns success unless an invalid option is given or ARRAY is readonly " -"or\n" +" Returns success unless an invalid option is given or ARRAY is readonly or\n" " not an indexed array." msgstr "" -#: builtins.c:2047 +#: builtins.c:2046 msgid "" "Read lines from a file into an array variable.\n" " \n" @@ -4505,13 +4357,3 @@ msgstr "" "Liest Zeilen einer Datei in eine Array Variable.\n" "\n" " Ist ein Synonym fĂƒÂŒr `mapfile'." - -#~ msgid "Copyright (C) 2009 Free Software Foundation, Inc.\n" -#~ msgstr "Copyright (C) 2009 Free Software Foundation, Inc.\n" - -#~ msgid "" -#~ "License GPLv2+: GNU GPL version 2 or later \n" -#~ msgstr "" -#~ "Lizenz GPLv2+: GNU GPL Version 2 oder jĂƒÂŒnger \n" diff --git a/po/eo.po b/po/eo.po index 75a647c0c..24a3d5dec 100644 --- a/po/eo.po +++ b/po/eo.po @@ -20,6 +20,7 @@ # here-document tuj-dokumento (info "(bash)Redirections") # indexed array entjerindica tabelo (info "(bash)Arrays") # positional parameter numerparametro ($1 ...) (info "(bash)Positional Parameters") +# resolve (symbolic links) elnodigi # special builtin speciala komando (info "(coreutils)Special built-in utilities") # substitution anstataÅ­igo (info "(bash)Shell Expansions") # unset malvalorizi (variablon); malaktivigi, malŝalti (opcion, nomon) @@ -28,7 +29,7 @@ msgstr "" "Project-Id-Version: GNU bash 4.3-pre2\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-03-08 16:00-0500\n" -"PO-Revision-Date: 2013-08-18 15:10+0700\n" +"PO-Revision-Date: 2013-08-24 14:35+0700\n" "Last-Translator: Sergio Pokrovskij \n" "Language-Team: Esperanto \n" "Language: eo\n" @@ -324,12 +325,12 @@ msgstr "Uzeblas nur ene de funkcio" #: builtins/declare.def:311 builtins/declare.def:526 #, c-format msgid "%s: reference variable cannot be an array" -msgstr "%s: referenca variablo ne povas esti tabelo" +msgstr "%s: Referenca variablo ne povas esti tabelo" #: builtins/declare.def:317 #, c-format msgid "%s: nameref variable self references not allowed" -msgstr "%s: nomreferenca variablo ne referencu sin mem" +msgstr "%s: Nomreferenca variablo ne referencu sin mem" #: builtins/declare.def:415 msgid "cannot use `-f' to make functions" @@ -343,7 +344,7 @@ msgstr "%s: Nurlega funkcio" #: builtins/declare.def:565 #, c-format msgid "%s: cannot destroy array variables in this way" -msgstr "$%s: ĉi tiel ne eblas neniigi variablojn" +msgstr "%s: Ĉi tiel ne eblas neniigi tabelvariablojn" #: builtins/declare.def:572 builtins/read.def:721 #, c-format @@ -952,7 +953,7 @@ msgstr "Eraro en dukto" #: execute_cmd.c:4347 #, c-format msgid "%s: maximum function nesting level exceeded (%d)" -msgstr "%s: la ingado de funkcioj superis sian maksimumon (%d)" +msgstr "%s: La ingado de funkcioj superis sian maksimumon (%d)" #: execute_cmd.c:4840 #, c-format @@ -2479,6 +2480,7 @@ msgstr "" " alinome." # unalias [-a] name [name ...] +# unalias [-a] NOMO [NOMO ...] #: builtins.c:276 msgid "" "Remove each NAME from the list of defined aliases.\n" @@ -2488,7 +2490,7 @@ msgid "" " \n" " Return success unless a NAME is not an existing alias." msgstr "" -"Forigu la nomojn name ... el la listo de difinitaj alinomoj.\n" +"Forigu la NOMOjn el la listo de difinitaj alinomoj.\n" "\n" " Opcioj:\n" " -a\tSe enestas la opcio ñ€ž-añ€Ÿ, ĉiujn alinomojn forigu.\n" @@ -2662,7 +2664,6 @@ msgstr "" " estas valida." # cd: -# "resolve symbolic links" -- interpreti? ekstrakti? (-L, -P)?? #: builtins.c:385 msgid "" "Change the shell working directory.\n" @@ -2698,7 +2699,7 @@ msgid "" msgstr "" "Ŝanĝu la kurantan laboran dosierujon de la ŝelo.\n" "\n" -" La kuranta dosierujo iĝu DOSIERUJO aÅ­, se DOSIERUJO malestas,\n" +" La kuranta dosierujo iĝu DOSIERUJO -- aÅ­, se DOSIERUJO malestas,\n" " la valoro de la variablo $HOME.\n" "\n" " La variablo $CDPATH difinas la serĉvojon por la dosierujo\n" @@ -2711,16 +2712,15 @@ msgstr "" " variablo havas valoron, tiu valoro estas uzata kiel DOSIERUJO.\n" "\n" " Opcioj:\n" -" -L\tsimbolaj ligiloj estu sekvataj: interpretu simbolajn ligilojn\n" -" en DOSIERUJO post prilaboro de la aperoj de ñ€ž..ñ€œ.\n" -" -P\tuzu la fizikan strukturon de dosierujoj sen iri laÅ­ simbolaj\n" -" ligiloj: interpretu simbolajn ligilojn de DOSIERUJO antaÅ­ ol\n" -" prilabori la aperojn de ñ€ž..ñ€œ.\n" +" -L\tlaÅ­u simbolajn Ligilojn: en DOSIERUJO, traktu la aperojn de\n" +" ñ€ž..ñ€œ antaÅ­ ol elnodigi la simbolajn ligilojn.\n" +" -P\tuzu la Fizikan strukturon de dosierujoj, elnodiginte simbolajn\n" +" ligilojn de DOSIERUJO antaÅ­ ol trakti la aperojn de ñ€ž..ñ€œ.\n" " -e eliru kun nenula elirstato se ñ€ž-Pñ€Ÿ ĉeestas kaj la\n" " kuranta dosierujo ne estas determinebla.\n" "\n" -" DefaÅ­lte la simbolaj ligiloj estas sekvataj, kvazaÅ­ ñ€ž-Lñ€Ÿ ĉeestus.\n" -" La prilaboro de ñ€ž..ñ€œ konsistas en forigo de la Ĕus-antaÅ­a vojnoma\n" +" DefaÅ­lte la simbolaj ligiloj estas laÅ­ataj, kvazaÅ­ ñ€ž-Lñ€Ÿ ĉeestus.\n" +" La traktado de ñ€ž..ñ€œ konsistas en forigo de la Ĕus-antaÅ­a vojnoma\n" " ero retrodirekte ĝis la oblikvo ñ€ž/ñ€œ aÅ­ la komenco de DOSIERUJO.\n" "\n" " Elirstato:\n" @@ -3473,19 +3473,19 @@ msgid "" " Exit Status:\n" " Returns success unless an invalid option is given or an error occurs." msgstr "" -"Eligu aÅ­ redaktu la historiliston\n" +"Eligu aÅ­ redaktu la historiliston.\n" "\n" " Eligu la liston de enigitaj komandoj kun lininumeroj. La ŝanĝitajn\n" " liniojn marku per ñ€ž*ñ€Ÿ. Kun argumento n, eligu nur la Ĕusajn\n" " n liniojn.\n" "\n" " Opcioj:\n" -" -c\tforviŝu la tutan historion (forigu ĉiujn eroj el la listo)\n" +" -c forviŝu la tutan historion (forigu ĉiujn erojn el la listo)\n" " -d forviŝu la linion kies numero estas DEŜOVO\n" "\n" -" -a\taldonu la historiliniojn de la kuranta seanco al la\n" +" -a aldonu la historiliniojn de la kuranta seanco al la\n" " historidosiero\n" -" -n\tlegu ĉiujn ankoraÅ­ ne legitajn liniojn el la historidosiero\n" +" -n legu ĉiujn ankoraÅ­ ne legitajn liniojn el la historidosiero\n" " kaj aldonu ilin en la historiliston\n" " -r legu la dosieron kaj aldonu ĝian enhavon al la kuranta\n" " historilisto\n" @@ -3985,14 +3985,15 @@ msgstr "" "\tfunkcioj\n" " -H\tEbligu atingi la historion !-stile. DefaÅ­lte la opcio estas\n" "\taktiva en la dialogaj ŝeloj.\n" -" -P\tNe interpretu simbolajn ligilojn plenumante komandojn kiuj\n" -" ŝanĝas la kurantan dosierujon (ñ€žcdñ€Ÿ ktp)\n" +" -P\tLa simbolaj ligiloj estu travideblaj ĉe plenumo de komandoj\n" +"\tkiuj ŝanĝas la kurantan dosierujon (ñ€žcdñ€Ÿ ktp uzu «fizikan»\n" +"\tinterpreton de vojnomo).\n" " -T\tSe aktiva, la DEBUG-kaptilon (DEBUG trap) heredas la ŝelaj\n" "\tfunkcioj\n" " --\tLa restantajn argumentojn uzu por valorizi la numerparametrojn.\n" -" Se tiaj argumentoj mankas, malvalorizu la numerparametrojn.\n" +"\tSe tiaj argumentoj mankas, malvalorizu la numerparametrojn.\n" " -\tLa restantajn argumentojn uzu por valorizi la numerparametrojn.\n" -" La opcioj -x kaj -v malaktiviĝas.\n" +"\tLa opcioj -x kaj -v malaktiviĝas.\n" "\n" " Uzante la signon + anstataÅ­ - vi povas malŝalti la opcion. La\n" " opciojn ankaÅ­ eblas uzi ĉe la voko de la ŝelo. La kuranta aro da\n" @@ -4541,32 +4542,32 @@ msgid "" " Exit Status:\n" " Returns success unless an invalid option is supplied or an error occurs." msgstr "" -"Ŝanĝu risurcolimaĔojn de la ŝelo\n" +"Ŝanĝu risurcolimaĔojn de la ŝelo.\n" "\n" " La komando ñ€žulimitñ€Ÿ ebligas mastrumi la risurcojn disponeblajn al\n" " la procezoj lanĉataj el la ŝelo (se la operaciumo ebligas tion).\n" "\n" " Opcioj:\n" -" -S\tŝanĝebla (ñ€žsoftñ€Ÿ) limo\n" -" -H\tfirma (ñ€žhardñ€Ÿ) limo\n" -" -a\teligu ĉiujn kurantajn risurcolimaĔojn\n" +" -S ŝanĝebla (ñ€žsoftñ€Ÿ) limo\n" +" -H firma (ñ€žhardñ€Ÿ) limo\n" +" -a eligu ĉiujn kurantajn risurcolimaĔojn\n" " -b la kontaktoskatola bufrolongo\n" -" -c\tmaksimuma longo de nekropsia dosiero (ñ€žcoreñ€Ÿ)\n" -" -d\tmaksimuma longo de datumsegmento de procezo\n" -" -e\tmaksimuma viciga prioritato (ñ€žniceñ€Ÿ)\n" +" -c maksimuma longo de nekropsia dosiero (ñ€žcoreñ€Ÿ)\n" +" -d maksimuma longo de datumsegmento de procezo\n" +" -e maksimuma viciga prioritato (ñ€žniceñ€Ÿ)\n" " -i maksimuma longo de pendaj signaloj\n" -" -f\tmaksimuma longo de dosieroj skribataj de la ŝelo kaj ĝiaj idoj\n" -" -l\tmaksimuma longo de ŝlosebla procezmemoro (mlock)\n" -" -m\tmaksimuma longo de rezida procezmemoro\n" -" -n\tmaksimuma nombro de malfermitaj dosiernumeroj\n" -" -p\tlongo de dukta bufro (pipe)\n" -" -q\tmaksimuma nombro da bajtoj en atendovicoj de Poziksaj mesaĝoj\n" -" -r\tmaksimuma prioritato realtempa\n" -" -s\tmaksimuma longo de stako\n" -" -t\tmaksimuma tempo ĉefprocesora (en sekundoj)\n" -" -u\tmaksimuma nombro de procezoj de la uzanto\n" -" -v\tlongo de la virtuala memoro\n" -" -x\tmaksimuma nombro de dosierŝlosoj\n" +" -f maksimuma longo de dosieroj skribataj de la ŝelo kaj ĝiaj idoj\n" +" -l maksimuma longo de ŝlosebla procezmemoro (mlock)\n" +" -m maksimuma longo de rezida procezmemoro\n" +" -n maksimuma nombro de malfermitaj dosiernumeroj\n" +" -p longo de dukta bufro (pipe)\n" +" -q maksimuma nombro da bajtoj en atendovicoj de Poziksaj mesaĝoj\n" +" -r maksimuma prioritato realtempa\n" +" -s maksimuma longo de stako\n" +" -t maksimuma tempo ĉefprocesora (en sekundoj)\n" +" -u maksimuma nombro de procezoj de la uzanto\n" +" -v longo de la virtuala memoro\n" +" -x maksimuma nombro de dosierŝlosoj\n" " -T maksimuma nombro de fadenoj\n" "\n" " Ne ĉiuj opcioj disponeblas sur ĉiuj komputilaj platformoj.\n" @@ -5389,7 +5390,7 @@ msgid "" " Returns success unless an invalid option is given or a write or assignment\n" " error occurs." msgstr "" -"Aranĝu kaj eligu argumentojn argumentojn laÅ­ formato\n" +"Aranĝu kaj eligu ARGUMENTOJn laÅ­ FORMATO.\n" "\n" " Opcio:\n" " -v VAR eligu en ŝelvariablon VAR anstataÅ­ en la ĉefeligujon\n" @@ -5442,14 +5443,14 @@ msgid "" " Exit Status:\n" " Returns success unless an invalid option is supplied or an error occurs." msgstr "" -"Difinu, kiel Readline kompletigu argumentojn\n" +"Difinu, kiel Readline kompletigu argumentojn.\n" "\n" " Por ĉiu NOMO difinu, kiel la argumentoj estu kompletigotaj. Se\n" " nenia opcio estas donita, eligu la aktualajn \n" " kompletigoregulojn en formo reuzebla por enigo en la ŝelon.\n" "\n" " Opcioj:\n" -" -p\tkompletigoregulojn en formo reuzebla por enigo en la ŝelon\n" +" -p\teligu kompletigoregulojn en formo uzebla por enigo en la ŝelon\n" " -r\tforigu la kompletigoregulon por ĉiu NOMO, aÅ­, se nenia NOMO\n" "\testas donita, ĉiujn kompletigoregulojn\n" " -D apliku la indikitajn kompletigojn kaj agojn DefaÅ­lte por la\n" diff --git a/po/sv.po b/po/sv.po index b2172364f..f63bcc98f 100644 --- a/po/sv.po +++ b/po/sv.po @@ -1,15 +1,15 @@ # Swedish translation of bash -# Copyright © 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +# Copyright © 2008, 2009, 2010, 2011, 2013 Free Software Foundation, Inc. # This file is distributed under the same license as the bash package. -# Göran Uddeborg , 2008, 2009, 2010, 2011. +# Göran Uddeborg , 2008, 2009, 2010, 2011, 2013. # -# $Revision: 1.11 $ +# $Revision: 1.13 $ msgid "" msgstr "" -"Project-Id-Version: bash 4.2\n" +"Project-Id-Version: bash 4.3-pre2\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-08-14 11:14-0400\n" -"PO-Revision-Date: 2011-02-16 23:42+0100\n" +"POT-Creation-Date: 2013-03-08 16:00-0500\n" +"PO-Revision-Date: 2013-08-25 20:00+0200\n" "Last-Translator: Göran Uddeborg \n" "Language-Team: Swedish \n" "Language: sv\n" @@ -22,7 +22,7 @@ msgstr "" msgid "bad array subscript" msgstr "felaktigt vektorindex" -#: arrayfunc.c:356 builtins/declare.def:585 +#: arrayfunc.c:356 builtins/declare.def:578 #, c-format msgid "%s: cannot convert indexed to associative array" msgstr "%s: det gÄr inte att konvertera en indexerad vektor till associativ" @@ -47,23 +47,21 @@ msgstr "%s: %s: mÄste anvÀnda index vid tilldelning av associativ vektor" msgid "%s: cannot create: %s" msgstr "%s: det gÄr inte att skapa: %s" -#: bashline.c:3928 +#: bashline.c:3923 msgid "bash_execute_unix_command: cannot find keymap for command" -msgstr "" -"bash_execute_unix_command: det gÄr inte att hitta en tangentbindning för " -"kommandot" +msgstr "bash_execute_unix_command: det gÄr inte att hitta en tangentbindning för kommandot" -#: bashline.c:4015 +#: bashline.c:4010 #, c-format msgid "%s: first non-whitespace character is not `\"'" msgstr "%s: första ickeblanka tecknet Àr inte '\"'" -#: bashline.c:4044 +#: bashline.c:4039 #, c-format msgid "no closing `%c' in %s" msgstr "ingen avslutande \"%c\" i %s" -#: bashline.c:4078 +#: bashline.c:4073 #, c-format msgid "%s: missing colon separator" msgstr "%s: kolonseparator saknas" @@ -190,7 +188,7 @@ msgstr "ogiltigt oktalt tal" msgid "invalid hex number" msgstr "ogiltigt hexadecimalt tal" -#: builtins/common.c:242 expr.c:1461 +#: builtins/common.c:242 expr.c:1451 msgid "invalid number" msgstr "ogiltigt tal" @@ -303,31 +301,31 @@ msgstr "kör inte en kompletteringsfunktion" msgid "can only be used in a function" msgstr "kan endast anvÀndas i en funktion" -#: builtins/declare.def:315 builtins/declare.def:533 +#: builtins/declare.def:311 builtins/declare.def:526 #, c-format msgid "%s: reference variable cannot be an array" -msgstr "" +msgstr "%s: en referensvariabel kan inte vara en vektor" -#: builtins/declare.def:324 +#: builtins/declare.def:317 #, c-format msgid "%s: nameref variable self references not allowed" -msgstr "" +msgstr "%s: att en namnreferensvariabel sjÀlvrefererar Àr inte tillÄtet" -#: builtins/declare.def:422 +#: builtins/declare.def:415 msgid "cannot use `-f' to make functions" msgstr "det gÄr inte att anvÀnda \"-f\" för att göra funktioner" -#: builtins/declare.def:434 execute_cmd.c:5328 +#: builtins/declare.def:427 execute_cmd.c:5315 #, c-format msgid "%s: readonly function" msgstr "%s: endast lÀsbar funktion" -#: builtins/declare.def:572 +#: builtins/declare.def:565 #, c-format msgid "%s: cannot destroy array variables in this way" msgstr "%s: det gÄr inte att förstöra vektorvariabler pÄ detta sÀtt" -#: builtins/declare.def:579 builtins/read.def:733 +#: builtins/declare.def:572 builtins/read.def:721 #, c-format msgid "%s: cannot convert associative to indexed array" msgstr "%s: det gÄr inte att konvertera en associativ vektor till indexerad" @@ -356,7 +354,7 @@ msgstr "%s: inte dynamiskt laddad" msgid "%s: cannot delete: %s" msgstr "%s: kan inte ta bort: %s" -#: builtins/evalfile.c:140 builtins/hash.def:171 execute_cmd.c:5175 +#: builtins/evalfile.c:140 builtins/hash.def:171 execute_cmd.c:5162 #: shell.c:1481 #, c-format msgid "%s: is a directory" @@ -405,11 +403,11 @@ msgstr "Det finns körande jobb.\n" msgid "no command found" msgstr "hittar inget kommando" -#: builtins/fc.def:320 builtins/fc.def:369 +#: builtins/fc.def:312 builtins/fc.def:359 msgid "history specification" msgstr "historiespecifikation" -#: builtins/fc.def:390 +#: builtins/fc.def:380 #, c-format msgid "%s: cannot open temp file: %s" msgstr "%s: det gÄr inte att öppna temporÀrfil: %s" @@ -454,20 +452,17 @@ msgid_plural "Shell commands matching keywords `" msgstr[0] "Skalkommandon som matchar nyckelordet '" msgstr[1] "Skalkommandon som matchar nyckelorden '" -#: builtins/help.def:182 +#: builtins/help.def:168 #, c-format -msgid "" -"no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'." -msgstr "" -"inget hjÀlpÀmne matchar \"%s\". Prova \"help help\" eller \"man -k %s\" " -"eller \"info %s\"." +msgid "no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'." +msgstr "inget hjÀlpÀmne matchar \"%s\". Prova \"help help\" eller \"man -k %s\" eller \"info %s\"." -#: builtins/help.def:199 +#: builtins/help.def:185 #, c-format msgid "%s: cannot open: %s" msgstr "%s: det gÄr inte att öppna: %s" -#: builtins/help.def:485 +#: builtins/help.def:471 #, c-format msgid "" "These shell commands are defined internally. Type `help' to see this list.\n" @@ -518,7 +513,7 @@ msgstr "%s: argument mÄste vara processer eller job-id:n" msgid "Unknown error" msgstr "OkÀnt fel" -#: builtins/let.def:95 builtins/let.def:120 expr.c:583 expr.c:598 +#: builtins/let.def:95 builtins/let.def:120 expr.c:586 expr.c:601 msgid "expression expected" msgstr "uttryck förvÀntades" @@ -594,9 +589,9 @@ msgid "no other directory" msgstr "ingen annan katalog" #: builtins/pushd.def:354 -#, fuzzy, c-format +#, c-format msgid "%s: invalid argument" -msgstr "%s: ogiltigt grÀnsargument" +msgstr "%s: ogiltigt argument" #: builtins/pushd.def:468 msgid "" @@ -625,12 +620,10 @@ msgid "" " \twith its position in the stack\n" " \n" " Arguments:\n" -" +N\tDisplays the Nth entry counting from the left of the list shown " -"by\n" +" +N\tDisplays the Nth entry counting from the left of the list shown by\n" " \tdirs when invoked without options, starting with zero.\n" " \n" -" -N\tDisplays the Nth entry counting from the right of the list shown " -"by\n" +" -N\tDisplays the Nth entry counting from the right of the list shown by\n" "\tdirs when invoked without options, starting with zero." msgstr "" "Visa listan av kataloger i minnet just nu. Kataloger hamnar i listan\n" @@ -741,15 +734,14 @@ msgstr "" msgid "%s: invalid timeout specification" msgstr "%s: ogiltig tidsgrÀnsspecifikation" -#: builtins/read.def:678 +#: builtins/read.def:666 #, c-format msgid "read error: %d: %s" msgstr "lÀsfel: %d: %s" #: builtins/return.def:75 msgid "can only `return' from a function or sourced script" -msgstr "" -"det gÄr bara att göra \"return\" frÄn en funktion eller kÀllinlÀst skript" +msgstr "det gÄr bara att göra \"return\" frÄn en funktion eller kÀllinlÀst skript" #: builtins/set.def:782 msgid "cannot simultaneously unset a function and a variable" @@ -918,117 +910,117 @@ msgstr "\atiden gick ut i vÀntan pÄ indata: automatisk utloggning\n" msgid "cannot redirect standard input from /dev/null: %s" msgstr "det gÄr inte att omdiregera standard in frÄn /dev/null: %s" -#: execute_cmd.c:1230 +#: execute_cmd.c:1228 #, c-format msgid "TIMEFORMAT: `%c': invalid format character" msgstr "TIMEFORMAT: \"%c\": ogiltigt formateringstecken" -#: execute_cmd.c:2284 +#: execute_cmd.c:2282 msgid "pipe error" msgstr "rörfel" -#: execute_cmd.c:4358 +#: execute_cmd.c:4347 #, c-format msgid "%s: maximum function nesting level exceeded (%d)" -msgstr "" +msgstr "%s: maximal nÀstning av funktioner överskriden (%d)" -#: execute_cmd.c:4851 +#: execute_cmd.c:4840 #, c-format msgid "%s: restricted: cannot specify `/' in command names" msgstr "%s: begrÀnsat: det gÄr inte att ange \"/\" i kommandonamn" -#: execute_cmd.c:4940 +#: execute_cmd.c:4929 #, c-format msgid "%s: command not found" msgstr "%s: kommandot finns inte" -#: execute_cmd.c:5173 +#: execute_cmd.c:5160 #, c-format msgid "%s: %s" msgstr "%s: %s" -#: execute_cmd.c:5210 +#: execute_cmd.c:5197 #, c-format msgid "%s: %s: bad interpreter" msgstr "%s: %s: felaktig tolk" -#: execute_cmd.c:5247 -#, fuzzy, c-format +#: execute_cmd.c:5234 +#, c-format msgid "%s: cannot execute binary file: %s" -msgstr "%s: det gÄr inte att köra binÀr fil" +msgstr "%s: det gÄr inte att köra binÀr fil: %s" -#: execute_cmd.c:5319 -#, fuzzy, c-format +#: execute_cmd.c:5306 +#, c-format msgid "`%s': is a special builtin" -msgstr "%s Àr inbyggt i skalet\n" +msgstr "ñ€%sñ€: Àr en speciell inbyggd" -#: execute_cmd.c:5371 +#: execute_cmd.c:5358 #, c-format msgid "cannot duplicate fd %d to fd %d" msgstr "det gÄr inte att duplicera fb %d till fb %d" -#: expr.c:259 +#: expr.c:262 msgid "expression recursion level exceeded" msgstr "rekursionsnivÄ i uttryck överskriden" -#: expr.c:283 +#: expr.c:286 msgid "recursion stack underflow" msgstr "underspill i rekursionsstacken" -#: expr.c:431 +#: expr.c:434 msgid "syntax error in expression" msgstr "syntaxfel i uttrycket" -#: expr.c:475 +#: expr.c:478 msgid "attempted assignment to non-variable" msgstr "försök att tilldela till en icke-variabel" -#: expr.c:495 expr.c:851 +#: expr.c:498 expr.c:847 msgid "division by 0" msgstr "division med 0" -#: expr.c:542 +#: expr.c:545 msgid "bug: bad expassign token" msgstr "bug: felaktig expassign-token" -#: expr.c:595 +#: expr.c:598 msgid "`:' expected for conditional expression" msgstr "\":\" förvÀntades i villkorligt uttryck" -#: expr.c:910 +#: expr.c:904 msgid "exponent less than 0" msgstr "exponenten Àr mindre Àn 0" -#: expr.c:967 +#: expr.c:957 msgid "identifier expected after pre-increment or pre-decrement" msgstr "en identifierare förvÀntades efter pre-ökning eller pre-minskning" -#: expr.c:993 +#: expr.c:983 msgid "missing `)'" msgstr "\")\" saknas" -#: expr.c:1044 expr.c:1381 +#: expr.c:1034 expr.c:1371 msgid "syntax error: operand expected" msgstr "syntaxfel: en operand förvÀntades" -#: expr.c:1383 +#: expr.c:1373 msgid "syntax error: invalid arithmetic operator" msgstr "syntaxfel: ogiltig aritmetisk operator" -#: expr.c:1407 +#: expr.c:1397 #, c-format msgid "%s%s%s: %s (error token is \"%s\")" msgstr "%s%s%s: %s (felsymbol Àr \"%s\")" -#: expr.c:1465 +#: expr.c:1455 msgid "invalid arithmetic base" msgstr "ogiltig aritmetisk bas" -#: expr.c:1485 +#: expr.c:1475 msgid "value too great for base" msgstr "vÀrdet Àr för stort för basen" -#: expr.c:1534 +#: expr.c:1524 #, c-format msgid "%s: expression error\n" msgstr "%s: uttrycksfel\n" @@ -1037,7 +1029,7 @@ msgstr "%s: uttrycksfel\n" msgid "getcwd: cannot access parent directories" msgstr "getcwd: det gÄr inte att komma Ät förÀldrakatalogen" -#: input.c:101 subst.c:5129 +#: input.c:101 subst.c:5067 #, c-format msgid "cannot reset nodelay mode for fd %d" msgstr "det gÄr inte att ÄterstÀlla fördröjningsfritt lÀge för fb %d" @@ -1045,8 +1037,7 @@ msgstr "det gÄr inte att ÄterstÀlla fördröjningsfritt lÀge för fb %d" #: input.c:267 #, c-format msgid "cannot allocate new file descriptor for bash input from fd %d" -msgstr "" -"det gÄr inte att allokera en ny filbeskrivare för bashindata frÄn fb %d" +msgstr "det gÄr inte att allokera en ny filbeskrivare för bashindata frÄn fb %d" #: input.c:275 #, c-format @@ -1143,58 +1134,58 @@ msgstr "wait: pid %ld Àr inte ett barn till detta skal" msgid "wait_for: No record of process %ld" msgstr "wait_for: Ingen uppgift om process %ld" -#: jobs.c:2692 +#: jobs.c:2689 #, c-format msgid "wait_for_job: job %d is stopped" msgstr "wait_for_job: jobb %d Àr stoppat" -#: jobs.c:2984 +#: jobs.c:2981 #, c-format msgid "%s: job has terminated" msgstr "%s: jobbet har avslutat" -#: jobs.c:2993 +#: jobs.c:2990 #, c-format msgid "%s: job %d already in background" msgstr "%s: jobb %d Àr redan i bakgrunden" -#: jobs.c:3218 +#: jobs.c:3215 msgid "waitchld: turning on WNOHANG to avoid indefinite block" msgstr "waitchld: slÄr pÄ WNOHANG för att undvika oÀndlig blockering" -#: jobs.c:3709 +#: jobs.c:3699 #, c-format msgid "%s: line %d: " msgstr "%s: rad %d: " -#: jobs.c:3723 nojobs.c:843 +#: jobs.c:3713 nojobs.c:843 #, c-format msgid " (core dumped)" msgstr " (minnesutskrift skapad)" -#: jobs.c:3735 jobs.c:3748 +#: jobs.c:3725 jobs.c:3738 #, c-format msgid "(wd now: %s)\n" msgstr "(ak nu: %s)\n" -#: jobs.c:3780 +#: jobs.c:3770 msgid "initialize_job_control: getpgrp failed" msgstr "initialize_job_control: getpgrp misslyckades" -#: jobs.c:3841 +#: jobs.c:3831 msgid "initialize_job_control: line discipline" msgstr "initialize_job_control: linjedisciplin" -#: jobs.c:3851 +#: jobs.c:3841 msgid "initialize_job_control: setpgid" msgstr "initialize_job_control: setpgid" -#: jobs.c:3872 jobs.c:3881 +#: jobs.c:3862 jobs.c:3871 #, c-format msgid "cannot set terminal process group (%d)" msgstr "det gÄr inte att sÀtta terminalprocessgrupp (%d)" -#: jobs.c:3886 +#: jobs.c:3876 msgid "no job control in this shell" msgstr "ingen jobbstyrning i detta skal" @@ -1345,102 +1336,101 @@ msgstr "hÀr-dokument pÄ rad %d avgrÀnsas av filslut (ville ha \"%s\")" #: make_cmd.c:759 #, c-format msgid "make_redirection: redirection instruction `%d' out of range" -msgstr "" -"make_redirection: omdirigeringsinstruktion \"%d\" utanför giltigt intervall" +msgstr "make_redirection: omdirigeringsinstruktion \"%d\" utanför giltigt intervall" -#: parse.y:3210 parse.y:3493 +#: parse.y:3209 parse.y:3480 #, c-format msgid "unexpected EOF while looking for matching `%c'" msgstr "ovÀntat filslut vid sökning efter matchande \"%c\"" -#: parse.y:4099 +#: parse.y:4086 msgid "unexpected EOF while looking for `]]'" msgstr "ovÀntat filslut vid sökning efter \"]]\"" -#: parse.y:4104 +#: parse.y:4091 #, c-format msgid "syntax error in conditional expression: unexpected token `%s'" msgstr "syntaxfel i villkorligt uttryck: ovÀntad symbol \"%s\"" -#: parse.y:4108 +#: parse.y:4095 msgid "syntax error in conditional expression" msgstr "syntaxfel i villkorligt uttryck" -#: parse.y:4186 +#: parse.y:4173 #, c-format msgid "unexpected token `%s', expected `)'" msgstr "ovÀntad symbol \"%s\", \")\" förvÀntades" -#: parse.y:4190 +#: parse.y:4177 msgid "expected `)'" msgstr "\")\" förvÀntades" -#: parse.y:4218 +#: parse.y:4205 #, c-format msgid "unexpected argument `%s' to conditional unary operator" msgstr "ovÀntat argument \"%s\" till villkorlig unÀr operator" -#: parse.y:4222 +#: parse.y:4209 msgid "unexpected argument to conditional unary operator" msgstr "ovÀntat argument till villkorlig unÀr operator" -#: parse.y:4268 +#: parse.y:4255 #, c-format msgid "unexpected token `%s', conditional binary operator expected" msgstr "ovÀntad symbol \"%s\", villkorlig binÀr operator förvÀntades" -#: parse.y:4272 +#: parse.y:4259 msgid "conditional binary operator expected" msgstr "villkorlig binÀr operato förvÀntades" -#: parse.y:4294 +#: parse.y:4281 #, c-format msgid "unexpected argument `%s' to conditional binary operator" msgstr "ovÀntat argument \"%s\" till villkorlig binÀr operator" -#: parse.y:4298 +#: parse.y:4285 msgid "unexpected argument to conditional binary operator" msgstr "ovÀntat argument till villkorlig binÀr operator" -#: parse.y:4309 +#: parse.y:4296 #, c-format msgid "unexpected token `%c' in conditional command" msgstr "ovÀntad symbol \"%c\" i villkorligt kommando" -#: parse.y:4312 +#: parse.y:4299 #, c-format msgid "unexpected token `%s' in conditional command" msgstr "ovÀntad symbol \"%s\" i villkorligt kommando" -#: parse.y:4316 +#: parse.y:4303 #, c-format msgid "unexpected token %d in conditional command" msgstr "ovÀntad symbol %d i villkorligt kommando" -#: parse.y:5666 +#: parse.y:5649 #, c-format msgid "syntax error near unexpected token `%s'" msgstr "syntaxfel nÀra den ovÀntade symbolen \"%s\"" -#: parse.y:5684 +#: parse.y:5667 #, c-format msgid "syntax error near `%s'" msgstr "syntaxfel nÀra \"%s\"" -#: parse.y:5694 +#: parse.y:5677 msgid "syntax error: unexpected end of file" msgstr "syntaxfel: ovÀntat filslut" -#: parse.y:5694 +#: parse.y:5677 msgid "syntax error" msgstr "syntaxfel" -#: parse.y:5756 +#: parse.y:5739 #, c-format msgid "Use \"%s\" to leave the shell.\n" msgstr "AnvÀnd \"%s\" fÀr att lÀmna skalet.\n" -#: parse.y:5918 +#: parse.y:5901 msgid "unexpected EOF while looking for matching `)'" msgstr "ovÀntat filslut nÀr matchande \")\" söktes" @@ -1511,7 +1501,7 @@ msgstr "%s: det gÄr inte att tilldela fb till variabel" msgid "/dev/(tcp|udp)/host/port not supported without networking" msgstr "/dev/(tcp|udp)/host/port stöds inte utan nÀtverksfunktion" -#: redir.c:861 redir.c:973 redir.c:1034 redir.c:1199 +#: redir.c:861 redir.c:971 redir.c:1032 redir.c:1194 msgid "redirection error: cannot duplicate fd" msgstr "omdirigeringsfel: det gÄr inte att duplicera fb" @@ -1555,9 +1545,8 @@ msgid "Shell options:\n" msgstr "Skalflaggor:\n" #: shell.c:1835 -#, fuzzy msgid "\t-ilrsD or -c command or -O shopt_option\t\t(invocation only)\n" -msgstr "\t-irsD eller -c kommando eller -O shopt_flagga\t\t(bara uppstart)\n" +msgstr "\t-ilrsD eller -c kommando eller -O shopt_flagga\t\t(bara uppstart)\n" #: shell.c:1850 #, c-format @@ -1755,90 +1744,86 @@ msgstr "OkÀnd signal nr " msgid "Unknown Signal #%d" msgstr "OkÀnd signal nr %d" -#: subst.c:1358 subst.c:1516 +#: subst.c:1352 subst.c:1510 #, c-format msgid "bad substitution: no closing `%s' in %s" msgstr "felaktig substitution: ingen avslutande \"%s\" i %s" -#: subst.c:2829 +#: subst.c:2823 #, c-format msgid "%s: cannot assign list to array member" msgstr "%s: det gÄr inte att tilldela listor till vektormedlemmar" -#: subst.c:5026 subst.c:5042 +#: subst.c:4964 subst.c:4980 msgid "cannot make pipe for process substitution" msgstr "det gÄr inte att skapa rör för processubstitution" -#: subst.c:5074 +#: subst.c:5012 msgid "cannot make child for process substitution" msgstr "det gÄr inte att skapa barn för processubstitution" -#: subst.c:5119 +#: subst.c:5057 #, c-format msgid "cannot open named pipe %s for reading" msgstr "det gÄr inte att öppna namngivet rör %s för lÀsning" -#: subst.c:5121 +#: subst.c:5059 #, c-format msgid "cannot open named pipe %s for writing" msgstr "det gÄr inte att öppna namngivet rör %s för skrivning" -#: subst.c:5139 +#: subst.c:5077 #, c-format msgid "cannot duplicate named pipe %s as fd %d" msgstr "det gÄr inte att duplicera namngivet rör %s som fb %d" -#: subst.c:5337 +#: subst.c:5273 msgid "cannot make pipe for command substitution" msgstr "det gÄr inte att skapa rör för kommandosubstitution" -#: subst.c:5375 +#: subst.c:5311 msgid "cannot make child for command substitution" msgstr "det gÄr inte att skapa barn för kommandosubstitution" -#: subst.c:5394 +#: subst.c:5330 msgid "command_substitute: cannot duplicate pipe as fd 1" msgstr "command_substitute: det gÄr inte att duplicera rör som fb 1" -#: subst.c:5798 subst.c:8001 -#, fuzzy, c-format +#: subst.c:5733 subst.c:7900 +#, c-format msgid "%s: invalid variable name for name reference" -msgstr "%s: %s: ogiltigt vÀrde för spÄrningsfilbeskrivare" +msgstr "%s: ogiltigt variabelnamn för referens" -#: subst.c:6009 +#: subst.c:5926 #, c-format msgid "%s: parameter null or not set" msgstr "%s: parametern tom eller inte satt" -#: subst.c:6281 subst.c:6296 +#: subst.c:6198 subst.c:6213 #, c-format msgid "%s: substring expression < 0" msgstr "%s: delstrÀnguttryck < 0" -#: subst.c:7457 +#: subst.c:7356 #, c-format msgid "%s: bad substitution" msgstr "%s: felaktig substitution" -#: subst.c:7534 +#: subst.c:7433 #, c-format msgid "$%s: cannot assign in this way" msgstr "$%s: det gÄr inte att tilldela pÄ detta sÀtt" -#: subst.c:7868 -msgid "" -"future versions of the shell will force evaluation as an arithmetic " -"substitution" -msgstr "" -"framtida versioner av skalet kommer att framtvinga evaluering som en " -"aritmetisk substition" +#: subst.c:7767 +msgid "future versions of the shell will force evaluation as an arithmetic substitution" +msgstr "framtida versioner av skalet kommer att framtvinga evaluering som en aritmetisk substition" -#: subst.c:8372 +#: subst.c:8271 #, c-format msgid "bad substitution: no closing \"`\" in %s" msgstr "felaktig ersÀttning: ingen avslutande \"`\" i %s" -#: subst.c:9273 +#: subst.c:9172 #, c-format msgid "no match: %s" msgstr "ingen match: %s" @@ -1879,108 +1864,93 @@ msgstr "\"]\" saknas" msgid "invalid signal number" msgstr "ogiltigt signalnummer" -#: trap.c:354 +#: trap.c:348 #, c-format msgid "run_pending_traps: bad value in trap_list[%d]: %p" msgstr "run_pending_traps: felaktigt vÀrde i trap_list[%d]: %p" -#: trap.c:358 +#: trap.c:352 #, c-format -msgid "" -"run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself" -msgstr "" -"run_pending_traps: signalhanterare Àr SIG_DFL, skickar om %d (%s) till mig " -"sjÀlv" +msgid "run_pending_traps: signal handler is SIG_DFL, resending %d (%s) to myself" +msgstr "run_pending_traps: signalhanterare Àr SIG_DFL, skickar om %d (%s) till mig sjÀlv" -#: trap.c:413 +#: trap.c:398 #, c-format msgid "trap_handler: bad signal %d" msgstr "trap_handler: felaktig signal %d" -#: variables.c:382 +#: variables.c:380 #, c-format msgid "error importing function definition for `%s'" msgstr "fel vid import av funktionsdefinition för \"%s\"" -#: variables.c:780 +#: variables.c:778 #, c-format msgid "shell level (%d) too high, resetting to 1" msgstr "skalnivÄ (%d) för hög, ÄterstÀller till 1" -#: variables.c:1865 -#, fuzzy, c-format -msgid "%s: circular name reference" -msgstr "%s: %s: ogiltigt vÀrde för spÄrningsfilbeskrivare" - -#: variables.c:2228 +#: variables.c:2198 msgid "make_local_variable: no function context at current scope" msgstr "make_local_variable: ingen funktionskontext i aktuellt sammanhang" -#: variables.c:2247 -#, fuzzy, c-format +#: variables.c:2217 +#, c-format msgid "%s: variable may not be assigned value" -msgstr "%s: det gÄr inte att tilldela fb till variabel" +msgstr "%s: variabeln fÄr inte tilldelas ett vÀrde" -#: variables.c:3600 +#: variables.c:3554 msgid "all_local_variables: no function context at current scope" msgstr "all_local_variables: ingen funktionskontext i aktuellt sammanhang" -#: variables.c:3845 +#: variables.c:3799 #, c-format msgid "%s has null exportstr" msgstr "%s har tom exportstr" -#: variables.c:3850 variables.c:3859 +#: variables.c:3804 variables.c:3813 #, c-format msgid "invalid character %d in exportstr for %s" msgstr "ogiltigt tecken %d i exportstr för %s" -#: variables.c:3865 +#: variables.c:3819 #, c-format msgid "no `=' in exportstr for %s" msgstr "inget \"=\" i exportstr för %s" -#: variables.c:4298 +#: variables.c:4252 msgid "pop_var_context: head of shell_variables not a function context" -msgstr "" -"pop_var_context: huvudet pÄ shell_variables Àr inte en funktionskontext" +msgstr "pop_var_context: huvudet pÄ shell_variables Àr inte en funktionskontext" -#: variables.c:4311 +#: variables.c:4265 msgid "pop_var_context: no global_variables context" msgstr "pop_var_context: ingen kontext global_variables" -#: variables.c:4385 +#: variables.c:4339 msgid "pop_scope: head of shell_variables not a temporary environment scope" -msgstr "" -"pop_scope: huvudet pÄ shell_variables Àr inte en temporÀr omgivningsrÀckvidd" +msgstr "pop_scope: huvudet pÄ shell_variables Àr inte en temporÀr omgivningsrÀckvidd" -#: variables.c:5211 +#: variables.c:5165 #, c-format msgid "%s: %s: cannot open as FILE" msgstr "%s: %s: gÄr inte att öppna som FILE" -#: variables.c:5216 +#: variables.c:5170 #, c-format msgid "%s: %s: invalid value for trace file descriptor" msgstr "%s: %s: ogiltigt vÀrde för spÄrningsfilbeskrivare" -#: variables.c:5261 -#, fuzzy, c-format +#: variables.c:5215 +#, c-format msgid "%s: %s: compatibility value out of range" -msgstr "%s: %s utanför giltigt intervall" +msgstr "%s: %s: kompatibilitetsvÀrde utanför giltigt intervall" -#: version.c:46 -#, fuzzy -msgid "Copyright (C) 2013 Free Software Foundation, Inc." -msgstr "Copyright © 2011 Free Software Foundation, Inc." +#: version.c:46 version2.c:46 +msgid "Copyright (C) 2012 Free Software Foundation, Inc." +msgstr "Copyright © 2012 Free Software Foundation, Inc." #: version.c:47 version2.c:47 -msgid "" -"License GPLv3+: GNU GPL version 3 or later \n" -msgstr "" -"Licens GPLv3+: GNU GPL version 3 eller senare \n" +msgid "License GPLv3+: GNU GPL version 3 or later \n" +msgstr "Licens GPLv3+: GNU GPL version 3 eller senare \n" #: version.c:86 version2.c:86 #, c-format @@ -1988,20 +1958,12 @@ msgid "GNU bash, version %s (%s)\n" msgstr "GNU bash, version %s (%s)\n" #: version.c:91 version2.c:91 -#, fuzzy msgid "This is free software; you are free to change and redistribute it." -msgstr "" -"Detta Àr fri programvara, det fÄr fritt Àndra och vidaredistribuera den.\n" +msgstr "Detta Àr fri programvara, det fÄr fritt Àndra och vidaredistribuera den." #: version.c:92 version2.c:92 -#, fuzzy msgid "There is NO WARRANTY, to the extent permitted by law." -msgstr "Det finns INGEN GARANTI, sÄ lÄngt lagen tillÄter.\n" - -#: version2.c:46 -#, fuzzy -msgid "Copyright (C) 2012 Free Software Foundation, Inc." -msgstr "Copyright © 2011 Free Software Foundation, Inc." +msgstr "Det finns INGEN GARANTI, sÄ lÄngt lagen tillÄter." #: xmalloc.c:91 #, c-format @@ -2032,14 +1994,8 @@ msgid "unalias [-a] name [name ...]" msgstr "unalias [-a] namn [namn ...]" #: builtins.c:51 -#, fuzzy -msgid "" -"bind [-lpsvPSVX] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-" -"x keyseq:shell-command] [keyseq:readline-function or readline-command]" -msgstr "" -"bind [-lpvsPVS] [-m tangentkarta] [-f filenamn] [-q namn] [-u namn] [-r " -"tangentsekv] [-x tangentsekv:skalkommando] [tangentsekv:readline-funktion " -"eller readline-kommando]" +msgid "bind [-lpsvPSVX] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command]" +msgstr "bind [-lpvsPVSX] [-m tangentkarta] [-f filenamn] [-q namn] [-u namn] [-r tangentsekv] [-x tangentsekv:skalkommando] [tangentsekv:readline-funktion eller readline-kommando]" #: builtins.c:54 msgid "break [n]" @@ -2082,9 +2038,8 @@ msgid "command [-pVv] command [arg ...]" msgstr "command [-pVv] kommando [arg ...]" #: builtins.c:76 -#, fuzzy msgid "declare [-aAfFgilnrtux] [-p] [name[=value] ...]" -msgstr "declare [-aAfFgilrtux] [-p] [namn[=vÀrde] ...]" +msgstr "declare [-aAfFgilnrtux] [-p] [namn[=vÀrde] ñ€©]" #: builtins.c:78 msgid "typeset [-aAfFgilrtux] [-p] name[=value] ..." @@ -2128,8 +2083,7 @@ msgstr "logout [n]" #: builtins.c:103 msgid "fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]" -msgstr "" -"fc [-e rnamn] [-lnr] [första] [sista] eller fc -s [mnst=ers] [kommando]" +msgstr "fc [-e rnamn] [-lnr] [första] [sista] eller fc -s [mnst=ers] [kommando]" #: builtins.c:107 msgid "fg [job_spec]" @@ -2148,12 +2102,8 @@ msgid "help [-dms] [pattern ...]" msgstr "help [-dms] [mönster ...]" #: builtins.c:121 -msgid "" -"history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg " -"[arg...]" -msgstr "" -"history [-c] [-d avstÄnd] [n] eller history -anrw [filnamn] eller history -" -"ps arg [arg...]" +msgid "history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...]" +msgstr "history [-c] [-d avstÄnd] [n] eller history -anrw [filnamn] eller history -ps arg [arg...]" #: builtins.c:125 msgid "jobs [-lnprs] [jobspec ...] or jobs -x command [args]" @@ -2164,24 +2114,16 @@ msgid "disown [-h] [-ar] [jobspec ...]" msgstr "disown [-h] [-ar] [jobbspec ...]" #: builtins.c:132 -msgid "" -"kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l " -"[sigspec]" -msgstr "" -"kill [-s sigspec | -n signum | -sigspec] pid | jobbspec ... eller kill -l " -"[sigspec]" +msgid "kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]" +msgstr "kill [-s sigspec | -n signum | -sigspec] pid | jobbspec ... eller kill -l [sigspec]" #: builtins.c:134 msgid "let arg [arg ...]" msgstr "let arg [arg ...]" #: builtins.c:136 -msgid "" -"read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p " -"prompt] [-t timeout] [-u fd] [name ...]" -msgstr "" -"read [-ers] [-a vektor] [-d avgr] [-i text] [-n ntkn] [-N ntkn] [-p prompt] " -"[-t tidgrÀns] [-u fb] [namn ...]" +msgid "read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]" +msgstr "read [-ers] [-a vektor] [-d avgr] [-i text] [-n ntkn] [-N ntkn] [-p prompt] [-t tidgrÀns] [-u fb] [namn ...]" #: builtins.c:138 msgid "return [n]" @@ -2192,9 +2134,8 @@ msgid "set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]" msgstr "set [-abefhkmnptuvxBCHP] [-o flaggnamn] [--] [arg ...]" #: builtins.c:142 -#, fuzzy msgid "unset [-f] [-v] [-n] [name ...]" -msgstr "unset [-f] [-v] [namn ...]" +msgstr "unset [-f] [-v] [-n] [namn ñ€©]" #: builtins.c:144 msgid "export [-fn] [name[=value] ...] or export -p" @@ -2241,23 +2182,20 @@ msgid "type [-afptP] name [name ...]" msgstr "type [-afptP] namn [namn ...]" #: builtins.c:169 -#, fuzzy msgid "ulimit [-SHabcdefilmnpqrstuvxT] [limit]" -msgstr "ulimit [-SHacdefilmnpqrstuvx] [grÀns]" +msgstr "ulimit [-SHabcdefilmnpqrstuvxT] [grÀns]" #: builtins.c:172 msgid "umask [-p] [-S] [mode]" msgstr "umask [-p] [-S] [rÀttigheter]" #: builtins.c:175 -#, fuzzy msgid "wait [-n] [id ...]" -msgstr "wait [id]" +msgstr "wait [-n] [id ñ€©]" #: builtins.c:179 -#, fuzzy msgid "wait [pid ...]" -msgstr "wait [id]" +msgstr "wait [pid ñ€©]" #: builtins.c:182 msgid "for NAME [in WORDS ... ] ; do COMMANDS; done" @@ -2280,12 +2218,8 @@ msgid "case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac" msgstr "case ORD in [MÖNSTER [| MÖNSTER]...) KOMMANDON ;;]... esac" #: builtins.c:192 -msgid "" -"if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else " -"COMMANDS; ] fi" -msgstr "" -"if KOMMANDON; then KOMMANDON; [ elif KOMMANDON; then KOMMANDON; ]... [ else " -"KOMMANDON; ] fi" +msgid "if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi" +msgstr "if KOMMANDON; then KOMMANDON; [ elif KOMMANDON; then KOMMANDON; ]... [ else KOMMANDON; ] fi" #: builtins.c:194 msgid "while COMMANDS; do COMMANDS; done" @@ -2344,43 +2278,24 @@ msgid "printf [-v var] format [arguments]" msgstr "printf [-v var] format [argument]" #: builtins.c:229 -msgid "" -"complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-" -"W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S " -"suffix] [name ...]" -msgstr "" -"complete [-abcdefgjksuv] [-pr] [-DE] [-o flagga] [-A ÄtgÀrd] [-G globmnst] [-" -"W ordlista] [-F funktion] [-C kommando] [-X filtermnst] [-P prefix] [-S " -"suffix] [namn ...]" +msgid "complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]" +msgstr "complete [-abcdefgjksuv] [-pr] [-DE] [-o flagga] [-A ÄtgÀrd] [-G globmnst] [-W ordlista] [-F funktion] [-C kommando] [-X filtermnst] [-P prefix] [-S suffix] [namn ...]" #: builtins.c:233 -msgid "" -"compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] " -"[-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]" -msgstr "" -"compgen [-abcdefgjksuv] [-o flagga] [-A ÄtgÀrd] [-G globmnst] [-W " -"ordlista] [-F funktion] [-C kommando] [-X filtermnst] [-P prefix] [-S " -"suffix] [ord]" +msgid "compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]" +msgstr "compgen [-abcdefgjksuv] [-o flagga] [-A ÄtgÀrd] [-G globmnst] [-W ordlista] [-F funktion] [-C kommando] [-X filtermnst] [-P prefix] [-S suffix] [ord]" #: builtins.c:237 msgid "compopt [-o|+o option] [-DE] [name ...]" msgstr "compopt [-o|+o flagga] [-DE] [namn ...]" #: builtins.c:240 -msgid "" -"mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c " -"quantum] [array]" -msgstr "" -"mapfile [-n antal] [-O start] [-s antal] [-t] [-u fb] [-C Äteranrop] [-c " -"kvanta] [vektor]" +msgid "mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]" +msgstr "mapfile [-n antal] [-O start] [-s antal] [-t] [-u fb] [-C Äteranrop] [-c kvanta] [vektor]" #: builtins.c:242 -msgid "" -"readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c " -"quantum] [array]" -msgstr "" -"readarray [-n antal] [-O start] [-s antal] [-t] [-u fb] [-C Äteranrop] [-c " -"kvanta] [vektor]" +msgid "readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]" +msgstr "readarray [-n antal] [-O start] [-s antal] [-t] [-u fb] [-C Äteranrop] [-c kvanta] [vektor]" #: builtins.c:254 msgid "" @@ -2397,14 +2312,12 @@ msgid "" " -p\tPrint all defined aliases in a reusable format\n" " \n" " Exit Status:\n" -" alias returns true unless a NAME is supplied for which no alias has " -"been\n" +" alias returns true unless a NAME is supplied for which no alias has been\n" " defined." msgstr "" "Definiera eller visa alias.\n" " \n" -" Utan argumen skriver \"alias\" listan pÄ alias pÄ den ÄteranvÀndbara " -"formen\n" +" Utan argumen skriver \"alias\" listan pÄ alias pÄ den ÄteranvÀndbara formen\n" " \"alias NAMN=VÄRDE\" pÄ standard ut.\n" " \n" " Annars Àr ett alias definierat för varje NAMN vars VÄRDE Àr angivet.\n" @@ -2435,7 +2348,6 @@ msgstr "" " Returnerar framgÄng om inte ett NAMN inte Àr ett existerande alias." #: builtins.c:289 -#, fuzzy msgid "" "Set Readline key bindings and variables.\n" " \n" @@ -2447,24 +2359,20 @@ msgid "" " Options:\n" " -m keymap Use KEYMAP as the keymap for the duration of this\n" " command. Acceptable keymap names are emacs,\n" -" emacs-standard, emacs-meta, emacs-ctlx, vi, vi-" -"move,\n" +" emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move,\n" " vi-command, and vi-insert.\n" " -l List names of functions.\n" " -P List function names and bindings.\n" " -p List functions and bindings in a form that can be\n" " reused as input.\n" -" -S List key sequences that invoke macros and their " -"values\n" -" -s List key sequences that invoke macros and their " -"values\n" +" -S List key sequences that invoke macros and their values\n" +" -s List key sequences that invoke macros and their values\n" " in a form that can be reused as input.\n" " -V List variable names and values\n" " -v List variable names and values in a form that can\n" " be reused as input.\n" " -q function-name Query about which keys invoke the named function.\n" -" -u function-name Unbind all keys which are bound to the named " -"function.\n" +" -u function-name Unbind all keys which are bound to the named function.\n" " -r keyseq Remove the binding for KEYSEQ.\n" " -f filename Read key bindings from FILENAME.\n" " -x keyseq:shell-command\tCause SHELL-COMMAND to be executed when\n" @@ -2477,42 +2385,38 @@ msgid "" msgstr "" "SÀtt Readline-tangentbindningar och -variabler.\n" " \n" -" Bind en tangentsekvens till en Readline-funktion eller -makro, eller " -"sÀtt\n" +" Bind en tangentsekvens till en Readline-funktion eller -makro, eller sÀtt\n" " en Readline-variabel. Syntaxen för argument vid sidan om flaggor Àr\n" -" densamma som den i ~/.inputrc, men mÄste skickas som ett ensamt " -"argument:\n" +" densamma som den i ~/.inputrc, men mÄste skickas som ett ensamt argument:\n" " t.ex., bind '\"\\C-x\\C-r\": re-read-init-file'.\n" " \n" " Flaggor:\n" " -m tangentkarta AnvÀnt TANGENTKARTA som tangentkarta under detta\n" " kommando. Acceptabla tangentkartenamn Àr emacs,\n" -" emacs-standard, emacs-meta, emacs-ctlx, vi, vi-" -"move,\n" +" emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move,\n" " vi-command och vi-insert.\n" " -l Lista namnen pÄ funktioner.\n" " -P List funktionsnamn och bindningar.\n" " -p List funktioner och bindningar pÄ ett sÀtt som kan\n" " ÄteranvÀndas som indata.\n" -" -S Lista tangentsekvenser som anropar makron och " -"deras\n" +" -S Lista tangentsekvenser som anropar makron och deras\n" " vÀrden.\n" -" -s Lista tangentskevenser som anropar makron och " -"deras\n" -" vÀrden pÄ ett sÀtt som kan ÄteranvÀndas som " -"indata.\n" +" -s Lista tangentskevenser som anropar makron och deras\n" +" vÀrden pÄ ett sÀtt som kan ÄteranvÀndas som indata.\n" " -V Lista variabelnamn och vÀrden\n" " -v Lista variabelnamn och vÀrden pÄ ett sÀtt som kan\n" " ÄteranvÀndas som indata.\n" -" -q funktionsnamn FrÄga efter vilka tangenter som anroper den " -"namngivna\n" +" -q funktionsnamn FrÄga efter vilka tangenter som anroper den namngivna\n" " funktionen\n" " -u funktionsnamn Tag bort alla tangenter som Àr bundna till den\n" " namngivna funktionen.\n" " -r tangentsekv Ta bort bindningen för TANGENTSEKV.\n" " -f filnamn LÀs tangentbindningar frÄn FILNAMN.\n" -" -x tangentsekv:skalkommando Görs sÄ att SKALKOMMANDO körs nÀr\n" +" -x tangentsekv:skalkommando Gör sÄ att SKALKOMMANDO körs nÀr\n" " \t\t\t\t TANGENTSEKV skrivs.\n" +" -X\t\t Lista tangentsekvenser bundna med -x och tillhörande\n" +" kommandon pÄ ett format som kan ÄteranvÀndas som\n" +" indata.\n" " \n" " Slutstatus:\n" " bind returnerar 0 om inte en okÀnd flagga ges eller ett fel intrÀffar." @@ -2547,8 +2451,7 @@ msgid "" msgstr "" "Återuppta for-, while eller until-slinga.\n" " \n" -" Återuppta nÀsta iteration i den omslutande FOR-, WHILE- eller UNTIL-" -"slingan.\n" +" Återuppta nÀsta iteration i den omslutande FOR-, WHILE- eller UNTIL-slingan.\n" " Om N anges, Äteruppta den N:e omslutande slingan.\n" " \n" " Slutstatus:\n" @@ -2560,8 +2463,7 @@ msgid "" " \n" " Execute SHELL-BUILTIN with arguments ARGs without performing command\n" " lookup. This is useful when you wish to reimplement a shell builtin\n" -" as a shell function, but need to execute the builtin within the " -"function.\n" +" as a shell function, but need to execute the builtin within the function.\n" " \n" " Exit Status:\n" " Returns the exit status of SHELL-BUILTIN, or false if SHELL-BUILTIN is\n" @@ -2569,15 +2471,13 @@ msgid "" msgstr "" "Exekvera en i skalet inbyggd funktion.\n" " \n" -" Exekvera SKALINBYGGD med argument ARG utan att utföra " -"kommandouppslagning.\n" +" Exekvera SKALINBYGGD med argument ARG utan att utföra kommandouppslagning.\n" " Detta Àr anvÀndbart nÀr du vill implementera om en inbyggd funktion i\n" " skalet som en skalfunktion, men behöver köra den inbyggda funktionen i\n" " skalfunktionen.\n" " \n" " Slutstatus:\n" -" Returnerar slutstatus frÄn SKALINBYGGD, eller falkst om SKALINBYGGD " -"inte\n" +" Returnerar slutstatus frÄn SKALINBYGGD, eller falkst om SKALINBYGGD inte\n" " Àr inbyggd i skalet." #: builtins.c:367 @@ -2609,26 +2509,19 @@ msgstr "" " ogiltigt." #: builtins.c:385 -#, fuzzy msgid "" "Change the shell working directory.\n" " \n" -" Change the current directory to DIR. The default DIR is the value of " -"the\n" +" Change the current directory to DIR. The default DIR is the value of the\n" " HOME shell variable.\n" " \n" -" The variable CDPATH defines the search path for the directory " -"containing\n" -" DIR. Alternative directory names in CDPATH are separated by a colon " -"(:).\n" -" A null directory name is the same as the current directory. If DIR " -"begins\n" +" The variable CDPATH defines the search path for the directory containing\n" +" DIR. Alternative directory names in CDPATH are separated by a colon (:).\n" +" A null directory name is the same as the current directory. If DIR begins\n" " with a slash (/), then CDPATH is not used.\n" " \n" -" If the directory is not found, and the shell option `cdable_vars' is " -"set,\n" -" the word is assumed to be a variable name. If that variable has a " -"value,\n" +" If the directory is not found, and the shell option `cdable_vars' is set,\n" +" the word is assumed to be a variable name. If that variable has a value,\n" " its value is used for DIR.\n" " \n" " Options:\n" @@ -2641,13 +2534,11 @@ msgid "" " \tcannot be determined successfully, exit with a non-zero status\n" " \n" " The default is to follow symbolic links, as if `-L' were specified.\n" -" `..' is processed by removing the immediately previous pathname " -"component\n" +" `..' is processed by removing the immediately previous pathname component\n" " back to a slash or the beginning of DIR.\n" " \n" " Exit Status:\n" -" Returns 0 if the directory is changed, and if $PWD is set successfully " -"when\n" +" Returns 0 if the directory is changed, and if $PWD is set successfully when\n" " -P is used; non-zero otherwise." msgstr "" "Ändra skalets arbetskatalog.\n" @@ -2660,20 +2551,22 @@ msgstr "" " katalognamn Àr detsamma som aktuell katalog. Om KAT börjar med ett\n" " snedstreck (/) anvÀnds inte CDPATH.\n" " \n" -" Om katalogen inte kan hittas, och skalvariabeln \"cdable_vars\" Àr " -"satt,\n" +" Om katalogen inte kan hittas, och skalvariabeln ñ€cdable_varsñ€ Àr satt,\n" " antas ordet vara ett variabelnamn. Om den variabeln har ett vÀrde\n" " anvÀnds dess vÀrde för KAT.\n" " \n" " Flaggor:\n" -" -L\tframtvinga att symboliska lÀnkar följs\n" +" -L\tframtvinga att symboliska lÀnkar följs: lös upp symboliska\n" +" \tKAT efter behandling av instanser av ñ€..ñ€\n" " -P\tanvÀnd den fysiska katalogstrukturen utan att följa\n" -" \tsymboliska lÀnkar\n" +" \tsymboliska lÀnkar: lös upp symboliska lÀnkar i KAT före behandling av\n" +" \tñ€..ñ€\n" " -e\tom flaggan -P ges, och det inte gÄr att avgöra den aktuella\n" " \tkatalogen, returnera dÄ med status skild frÄn noll\n" " \n" -" StandardvÀrde Àr att följa symboliska lÀngar, som om \"-L\" vore " -"angivet.\n" +" StandardvÀrde Àr att följa symboliska lÀngar, som om ñ€-Lñ€ vore angivet.\n" +" ñ€..ñ€ behandlas genom att ta bort den omedelbart föregÄende\n" +" sökvÀgskomponenten tillbaka till ett snedstreck eller början av KAT\n" " \n" " Slutstatus:\n" " Returnerar 0 om katalogen Àr Àndrad, och om $PWD satts korrekt om -P\n" @@ -2704,8 +2597,7 @@ msgstr "" " Som standard beter sig \"pwd\" som om \"-L\" vore angivet.\n" " \n" " Slutstatus:\n" -" Returnerar 0 om inte en ogiltig flagga anges eller den aktuella " -"katalogen\n" +" Returnerar 0 om inte en ogiltig flagga anges eller den aktuella katalogen\n" " inte kan lÀsas." #: builtins.c:437 @@ -2753,8 +2645,7 @@ msgid "" "Execute a simple command or display information about commands.\n" " \n" " Runs COMMAND with ARGS suppressing shell function lookup, or display\n" -" information about the specified COMMANDs. Can be used to invoke " -"commands\n" +" information about the specified COMMANDs. Can be used to invoke commands\n" " on disk when a function with the same name exists.\n" " \n" " Options:\n" @@ -2779,12 +2670,10 @@ msgstr "" " -V\tskriv en mer utförlig beskrivning om varje KOMMANDO\n" " \n" " Slutstatus:\n" -" Returnerar slutstatus frÄn KOMMANDO, eller misslyckande om KOMMANDO " -"inte\n" +" Returnerar slutstatus frÄn KOMMANDO, eller misslyckande om KOMMANDO inte\n" " finns." #: builtins.c:485 -#, fuzzy msgid "" "Set variable values and attributes.\n" " \n" @@ -2815,8 +2704,7 @@ msgid "" " Variables with the integer attribute have arithmetic evaluation (see\n" " the `let' command) performed when the variable is assigned a value.\n" " \n" -" When used in a function, `declare' makes NAMEs local, as with the " -"`local'\n" +" When used in a function, `declare' makes NAMEs local, as with the `local'\n" " command. The `-g' option suppresses this behavior.\n" " \n" " Exit Status:\n" @@ -2841,6 +2729,7 @@ msgstr "" " -A\tför att göra NAMN till associativa vektorer (om det stöds)\n" " -i\tför att ge NAMN attributet \"heltal\"\n" " -l\tför att konvertera NAMN till gemena vid tilldelning\n" +" -n\tgör NAMN till en referens till variablen som namnges som vÀrde\n" " -r\tför att göra NAMN endast lÀsbart\n" " -t\tför att ge NAMN attributet \"spÄra\"\n" " -u\tför att konvertera NAMN till versaler vid tilldelning\n" @@ -2851,13 +2740,12 @@ msgstr "" " För variabler med attributet heltal utförs atitmetisk berÀkning (se\n" " kommandot \"let\") nÀr variabeln tilldelas ett vÀrde.\n" " \n" -" Vid anvÀndning i en funktion gör \"declare\" NAMN lokala, som med " -"kommandot\n" +" Vid anvÀndning i en funktion gör \"declare\" NAMN lokala, som med kommandot\n" " \"local\". Flaggan \"-g\" ÄsidosÀtter detta beteende.\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel " -"intrÀffar." +" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel vid\n" +" variabeltilldelning intrÀffar." #: builtins.c:525 msgid "" @@ -2870,7 +2758,6 @@ msgstr "" " FörÄldrat. Se \"help declare\"." #: builtins.c:533 -#, fuzzy msgid "" "Define local variables.\n" " \n" @@ -2887,23 +2774,20 @@ msgstr "" "Definiera lokala variabler.\n" " \n" " Skapa en lokal variabel kallad NAMN, och ge den VÄRDE. FLAGGA kan\n" -" vara alla flaggor som accepteras av \"declare\".\n" +" vara alla flaggor som accepteras av ñ€declareñ€.\n" " \n" -" Lokala variabler kan endast anvÀndas i en funktion; de Àr synliga " -"endast\n" +" Lokala variabler kan endast anvÀndas i en funktion; de Àr synliga endast\n" " för funktionen de definieras i och dess barn.\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte en ogiltig flagga ges, ett fel intrÀffar\n" -" eller skalet inte exekverar en funktion." +" Returnerar framgÄng om inte en ogiltig flagga ges, ett fel vid\n" +" variabeltilldelning intrÀffar eller skalet inte exekverar en funktion." #: builtins.c:550 -#, fuzzy msgid "" "Write arguments to the standard output.\n" " \n" -" Display the ARGs, separated by a single space character and followed by " -"a\n" +" Display the ARGs, separated by a single space character and followed by a\n" " newline, on the standard output.\n" " \n" " Options:\n" @@ -2933,18 +2817,20 @@ msgid "" msgstr "" "Skriv argument pÄ standard ut.\n" " \n" -" Visa ARGumenten pÄ standard ut följt av en nyrad.\n" +" Visa ARGumenten, separerade av ensamma blanktecken och följda av en\n" +" nyrad, pÄ standard ut.\n" " \n" " Flaggor:\n" " -n\tlÀgg inte till en nyrad\n" " -e\taktivera tolkning av nedanstÄende specialsekvenser\n" " -E\tundertryck uttryckligen tolkning av specialsekvenser\n" " \n" -" \"echo\" tolkar följande bakstrecksekvenser:\n" +" ñ€echoñ€ tolkar följande bakstrecksekvenser:\n" " \\a\talarm (klocka)\n" " \\b\tbacksteg\n" " \\c\tundertryck följande utdata\n" " \\e\tescape-tecknet\n" +" \\E\tescape-tecknet\n" " \\f\tsidmatning\n" " \\n\tnyrad\n" " \\r\tvagnretur\n" @@ -3039,8 +2925,7 @@ msgstr "" msgid "" "Execute arguments as a shell command.\n" " \n" -" Combine ARGs into a single string, use the result as input to the " -"shell,\n" +" Combine ARGs into a single string, use the result as input to the shell,\n" " and execute the resulting commands.\n" " \n" " Exit Status:\n" @@ -3048,8 +2933,7 @@ msgid "" msgstr "" "Exekvera argument som ett skalkommando.\n" " \n" -" Kombinera ARGument till en enda strÀng, och anvÀnd resultatet som " -"indata\n" +" Kombinera ARGument till en enda strÀng, och anvÀnd resultatet som indata\n" " till skalet och exekvera de resulterande kommandona.\n" " \n" " Slutstatus:\n" @@ -3137,8 +3021,7 @@ msgid "" "Replace the shell with the given command.\n" " \n" " Execute COMMAND, replacing this shell with the specified program.\n" -" ARGUMENTS become the arguments to COMMAND. If COMMAND is not " -"specified,\n" +" ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified,\n" " any redirections take effect in the current shell.\n" " \n" " Options:\n" @@ -3146,18 +3029,15 @@ msgid "" " -c\t\texecute COMMAND with an empty environment\n" " -l\t\tplace a dash in the zeroth argument to COMMAND\n" " \n" -" If the command cannot be executed, a non-interactive shell exits, " -"unless\n" +" If the command cannot be executed, a non-interactive shell exits, unless\n" " the shell option `execfail' is set.\n" " \n" " Exit Status:\n" -" Returns success unless COMMAND is not found or a redirection error " -"occurs." +" Returns success unless COMMAND is not found or a redirection error occurs." msgstr "" "ErsÀtt skalet med det givna kommandot.\n" " \n" -" Exekvera KOMMANDO genom att ersÀtta detta skal med det angivna " -"programmet.\n" +" Exekvera KOMMANDO genom att ersÀtta detta skal med det angivna programmet.\n" " ARGUMENT blir argument till KOMMANDO. Om KOMMANDO inte anges kommer\n" " eventuella omdirigeringar att gÀlla för det aktuella skalet.\n" " \n" @@ -3189,8 +3069,7 @@ msgstr "" msgid "" "Exit a login shell.\n" " \n" -" Exits a login shell with exit status N. Returns an error if not " -"executed\n" +" Exits a login shell with exit status N. Returns an error if not executed\n" " in a login shell." msgstr "" "Avsluta ett inloggningsskal.\n" @@ -3202,15 +3081,13 @@ msgstr "" msgid "" "Display or execute commands from the history list.\n" " \n" -" fc is used to list or edit and re-execute commands from the history " -"list.\n" +" fc is used to list or edit and re-execute commands from the history list.\n" " FIRST and LAST can be numbers specifying the range, or FIRST can be a\n" " string, which means the most recent command beginning with that\n" " string.\n" " \n" " Options:\n" -" -e ENAME\tselect which editor to use. Default is FCEDIT, then " -"EDITOR,\n" +" -e ENAME\tselect which editor to use. Default is FCEDIT, then EDITOR,\n" " \t\tthen vi\n" " -l \tlist lines instead of editing\n" " -n\tomit line numbers when listing\n" @@ -3224,8 +3101,7 @@ msgid "" " the last command.\n" " \n" " Exit Status:\n" -" Returns success or status of executed command; non-zero if an error " -"occurs." +" Returns success or status of executed command; non-zero if an error occurs." msgstr "" "Visa eller kör kommandon frÄn historielistan.\n" " \n" @@ -3244,10 +3120,8 @@ msgstr "" " Med formatet \"fc -s [mnst=ers ...] [kommando]\" körs KOMMANDO om efter\n" " att substitutionen GAMMALT=NYTT har utförts.\n" " \n" -" Ett anvÀndbart alias att anvÀnda med detta Àr r=\"fc -s\", sÄ att " -"skriva\n" -" \"r cc\" kör senaste kommandot som börjar med \"cc\" och att skriva \"r" -"\" kör\n" +" Ett anvÀndbart alias att anvÀnda med detta Àr r=\"fc -s\", sÄ att skriva\n" +" \"r cc\" kör senaste kommandot som börjar med \"cc\" och att skriva \"r\" kör\n" " om senaste kommandot.\n" " \n" " Slutstatus:\n" @@ -3279,10 +3153,8 @@ msgstr "" msgid "" "Move jobs to the background.\n" " \n" -" Place the jobs identified by each JOB_SPEC in the background, as if " -"they\n" -" had been started with `&'. If JOB_SPEC is not present, the shell's " -"notion\n" +" Place the jobs identified by each JOB_SPEC in the background, as if they\n" +" had been started with `&'. If JOB_SPEC is not present, the shell's notion\n" " of the current job is used.\n" " \n" " Exit Status:\n" @@ -3290,30 +3162,25 @@ msgid "" msgstr "" "Flytta jobb till bakgrunden.\n" " \n" -" Placera jobben som idintifieras av varje JOBBSPEC i bakgrunden som om " -"de\n" -" hade startats med \"&\". Om ingen JOBBSPEC finns anvÀnds skalets " -"begrepp\n" +" Placera jobben som idintifieras av varje JOBBSPEC i bakgrunden som om de\n" +" hade startats med \"&\". Om ingen JOBBSPEC finns anvÀnds skalets begrepp\n" " om det aktuella jobbet.\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte jobbstyrning inte Àr aktiverat eller ett " -"fel\n" +" Returnerar framgÄng om inte jobbstyrning inte Àr aktiverat eller ett fel\n" " intrÀffar." #: builtins.c:782 -#, fuzzy msgid "" "Remember or display program locations.\n" " \n" " Determine and remember the full pathname of each command NAME. If\n" -" no arguments are given, information about remembered commands is " -"displayed.\n" +" no arguments are given, information about remembered commands is displayed.\n" " \n" " Options:\n" " -d\t\tforget the remembered location of each NAME\n" " -l\t\tdisplay in a format that may be reused as input\n" -" -p pathname\tuse PATHNAME as the full pathname of NAME\n" +" -p pathname\tuse PATHNAME is the full pathname of NAME\n" " -r\t\tforget all remembered locations\n" " -t\t\tprint the remembered location of each NAME, preceding\n" " \t\teach location with the corresponding NAME if multiple\n" @@ -3328,8 +3195,7 @@ msgstr "" "Kom ihÄg eller visa programlÀgen.\n" " \n" " BestÀm och kom ihÄg den fullstÀndiga sökvÀgen till varje kommando NAMN.\n" -" Om inget argument ges visas information om kommandon som finns i " -"minnet.\n" +" Om inget argument ges visas information om kommandon som finns i minnet.\n" " \n" " Flaggor:\n" " -d\t\tglöm platsen i minnet för varje NAMN\n" @@ -3363,14 +3229,12 @@ msgid "" " PATTERN\tPattern specifiying a help topic\n" " \n" " Exit Status:\n" -" Returns success unless PATTERN is not found or an invalid option is " -"given." +" Returns success unless PATTERN is not found or an invalid option is given." msgstr "" "Visa information om inbyggda kommandon.\n" " \n" " Visar korta sammanfattningar om inbyggda kommandon. Om MÖNSTER anges\n" -" ges detaljerad hjÀlp om alla kommandon som matchar MÖNSTER, annars " -"skrivs\n" +" ges detaljerad hjÀlp om alla kommandon som matchar MÖNSTER, annars skrivs\n" " listan med hjÀlpÀmnen.\n" " \n" " Flaggor:\n" @@ -3383,8 +3247,7 @@ msgstr "" " MÖNSTER\tMönster som anger hjÀlpÀmnen\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte MÖNSTER inte finns eller en ogiltig flagga " -"ges." +" Returnerar framgÄng om inte MÖNSTER inte finns eller en ogiltig flagga ges." #: builtins.c:831 msgid "" @@ -3413,8 +3276,7 @@ msgid "" " \n" " If the $HISTTIMEFORMAT variable is set and not null, its value is used\n" " as a format string for strftime(3) to print the time stamp associated\n" -" with each displayed history entry. No time stamps are printed " -"otherwise.\n" +" with each displayed history entry. No time stamps are printed otherwise.\n" " \n" " Exit Status:\n" " Returns success unless an invalid option is given or an error occurs." @@ -3438,19 +3300,15 @@ msgstr "" " \tatt lagra det i historielistan\n" " -s\tlÀgg till ARG till historielistan som en ensam post\n" " \n" -" Om FILENAMN anges anvÀnds det som historiefil. Annars, om $HISTFILE " -"har\n" +" Om FILENAMN anges anvÀnds det som historiefil. Annars, om $HISTFILE har\n" " ett vÀrde anvÀnds det, annars ~/.bash_history.\n" " \n" -" Om variabeln $HISTTIMEFORMAT Àr satt och inte tom anvÀnds dess vÀrde " -"som\n" -" en formatstrÀng till strftime(3) för att skriva tidsstÀmplar " -"tillhörande\n" +" Om variabeln $HISTTIMEFORMAT Àr satt och inte tom anvÀnds dess vÀrde som\n" +" en formatstrÀng till strftime(3) för att skriva tidsstÀmplar tillhörande\n" " varje visad historiepost. Inga tidsstÀmplar skrivs annars.\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel " -"intrÀffar." +" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel intrÀffar." #: builtins.c:867 msgid "" @@ -3492,8 +3350,7 @@ msgstr "" " i ARG har ersatts med process-id:t för det jobbets processgruppledare.\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel " -"intrÀffar.\n" +" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel intrÀffar.\n" " Om -x anvÀnds returneras slutstatus frÄn KOMMANDO." #: builtins.c:894 @@ -3549,8 +3406,7 @@ msgid "" msgstr "" "Skicka en signal till ett jobb.\n" " \n" -" Skicka processerna som identifieras av PID eller JOBBSPEC signalerna " -"som\n" +" Skicka processerna som identifieras av PID eller JOBBSPEC signalerna som\n" " namnges av SIGSPEC eller SIGNUM. Om varken SIGSPEC eller SIGNUM Àr\n" " angivna antas SIGTERM.\n" " \n" @@ -3560,10 +3416,8 @@ msgstr "" " -l\tlista signalnamnen. Om argument följer \"-l\" antas de vara\n" " \tsignalnummer som namn skall listas för\n" " \n" -" Kill Àr inbyggt i skalet av tvÄ skÀl: det tillÄter att jobb-id:n " -"anvÀnds\n" -" istÀllet för process-id:n, och det tillÄter processer att dödas om " -"grÀnsen\n" +" Kill Àr inbyggt i skalet av tvÄ skÀl: det tillÄter att jobb-id:n anvÀnds\n" +" istÀllet för process-id:n, och det tillÄter processer att dödas om grÀnsen\n" " för hur mÄnga processer du fÄr skapa har nÄtts.\n" " \n" " Slutstatus:\n" @@ -3577,8 +3431,7 @@ msgid "" " Evaluate each ARG as an arithmetic expression. Evaluation is done in\n" " fixed-width integers with no check for overflow, though division by 0\n" " is trapped and flagged as an error. The following list of operators is\n" -" grouped into levels of equal-precedence operators. The levels are " -"listed\n" +" grouped into levels of equal-precedence operators. The levels are listed\n" " in order of decreasing precedence.\n" " \n" " \tid++, id--\tvariable post-increment, post-decrement\n" @@ -3616,12 +3469,10 @@ msgid "" msgstr "" "Evaluera aritmetiska uttryck.\n" " \n" -" Evaluera varje ARG som ett aritmetiskt uttryck. Evaluering görs i " -"heltal\n" +" Evaluera varje ARG som ett aritmetiskt uttryck. Evaluering görs i heltal\n" " med fix bredd utan kontroll av spill, fast division med 0 fÄngas och\n" " flaggas som ett fel. Följande lista över operatorer Àr grupperad i\n" -" nivÄer av operatorer med samma precedens. NivÄerna Àr listade i " -"ordning\n" +" nivÄer av operatorer med samma precedens. NivÄerna Àr listade i ordning\n" " med sjunkande precedens.\n" " \n" " \tid++, id--\tpostinkrementering av variabel, postdekrementering\n" @@ -3650,30 +3501,24 @@ msgstr "" " uttryck. Variablerna behöver inte ha sina heltalsattribut pÄslagna för\n" " att anvÀndas i ett uttryck.\n" " \n" -" Operatorer berÀknas i precedensordning. Delutryck i parenteser " -"berÀknas\n" +" Operatorer berÀknas i precedensordning. Delutryck i parenteser berÀknas\n" " först och kan ÄsidosÀtta precedensreglerna ovan.\n" " \n" " Slutstatus:\n" -" Om det sista ARG berÀknas till 0, returnerar let 1; let returnerar 0 " -"annars." +" Om det sista ARG berÀknas till 0, returnerar let 1; let returnerar 0 annars." #: builtins.c:981 -#, fuzzy msgid "" "Read a line from the standard input and split it into fields.\n" " \n" " Reads a single line from the standard input, or from file descriptor FD\n" -" if the -u option is supplied. The line is split into fields as with " -"word\n" +" if the -u option is supplied. The line is split into fields as with word\n" " splitting, and the first word is assigned to the first NAME, the second\n" " word to the second NAME, and so on, with any leftover words assigned to\n" -" the last NAME. Only the characters found in $IFS are recognized as " -"word\n" +" the last NAME. Only the characters found in $IFS are recognized as word\n" " delimiters.\n" " \n" -" If no NAMEs are supplied, the line read is stored in the REPLY " -"variable.\n" +" If no NAMEs are supplied, the line read is stored in the REPLY variable.\n" " \n" " Options:\n" " -a array\tassign the words read to sequential indices of the array\n" @@ -3685,15 +3530,13 @@ msgid "" " -n nchars\treturn after reading NCHARS characters rather than waiting\n" " \t\tfor a newline, but honor a delimiter if fewer than NCHARS\n" " \t\tcharacters are read before the delimiter\n" -" -N nchars\treturn only after reading exactly NCHARS characters, " -"unless\n" +" -N nchars\treturn only after reading exactly NCHARS characters, unless\n" " \t\tEOF is encountered or read times out, ignoring any delimiter\n" " -p prompt\toutput the string PROMPT without a trailing newline before\n" " \t\tattempting to read\n" " -r\t\tdo not allow backslashes to escape any characters\n" " -s\t\tdo not echo input coming from a terminal\n" -" -t timeout\ttime out and return failure if a complete line of input " -"is\n" +" -t timeout\ttime out and return failure if a complete line of input is\n" " \t\tnot read within TIMEOUT seconds. The value of the TMOUT\n" " \t\tvariable is the default timeout. TIMEOUT may be a\n" " \t\tfractional number. If TIMEOUT is 0, read returns immediately,\n" @@ -3703,27 +3546,22 @@ msgid "" " -u fd\t\tread from file descriptor FD instead of the standard input\n" " \n" " Exit Status:\n" -" The return code is zero, unless end-of-file is encountered, read times " -"out\n" -" (in which case it's greater than 128), a variable assignment error " -"occurs,\n" +" The return code is zero, unless end-of-file is encountered, read times out\n" +" (in which case it's greater than 128), a variable assignment error occurs,\n" " or an invalid file descriptor is supplied as the argument to -u." msgstr "" "LÀs en rad frÄn standard in och dela upp den i fÀlt.\n" " \n" " LÀser en ensam rad frÄn standard in, eller frÄn filbeskrivare FB om\n" -" flaggan -u ges. Raden delas upp i fÀlt som vid orduppdelning, och " -"första\n" -" ordet tilldelas det första NAMNet, andra ordet till det andra NAMNet, " -"och\n" +" flaggan -u ges. Raden delas upp i fÀlt som vid orduppdelning, och första\n" +" ordet tilldelas det första NAMNet, andra ordet till det andra NAMNet, och\n" " sÄ vidare, med eventuella ÄterstÄende ord tilldelade till det sista\n" " NAMNet. Endast tecknen som finns i $IFS anvÀnds som ordavgrÀnsare.\n" " \n" " Om inga NAMN anges, lagras den inlÀsta raden i variabeln REPLY.\n" " \n" " Flaggor:\n" -" -a vektor\ttilldela de inlÀsta orden till sekvensiella index i " -"vektor-\n" +" -a vektor\ttilldela de inlÀsta orden till sekvensiella index i vektor-\n" " \t\tvariabeln VEKTOR, med start frÄn noll\n" " -d avgr\tfortsÀtt tills det första tecknet i AVGR lÀsts, istÀllet för\n" " \t\tnyrad\n" @@ -3733,8 +3571,7 @@ msgstr "" " -n ntkn\treturnera efter att ha lÀst NTKN tecken istÀllet för att\n" " \t\tvÀnta pÄ en nyrad, men ta hÀnsyn till en avgrÀnsare om fÀrre\n" " \t\tÀn NTKN tecken lÀsts före avgrÀnsaren\n" -" -N ntkn\treturnera endast efter att ha lÀst exakt NTKN tecken, om " -"inte\n" +" -N ntkn\treturnera endast efter att ha lÀst exakt NTKN tecken, om inte\n" " \t\tfilslut pÄtrÀffades eller tidsgrÀnsen överskreds, ignorera\n" " \t\talla avgrÀnsare\n" " -p prompt\tskriv ut strÀngen PROMPT utan en avslutande nyrad före\n" @@ -3744,14 +3581,16 @@ msgstr "" " -t tidgrÀns\tsluta vÀnta och returnera misslyckande om inte en\n" " \t\tkomplett rad lÀsts inom TIDSGRÄNS sekunder. VÀrdet pÄ variabeln\n" " \t\tTMOUT Àr standardvÀrdet pÄ tidsgrÀnsen. TIDSGRÄNS kan vara ett\n" -" \t\tbrÄktal. Om TIDSGRÄNS Àr 0 returnerar read lyckad status bara\n" +" \t\tdecimaltal. Om TIDSGRÄNS Àr 0 returnerar read direkt, utan\n" +" att försöka lÀsa nÄgra data, och returnerar lyckad status bara\n" "\t\tom det finns indata tillgÀngligt pÄ den angivna filbeskrivaren.\n" " Slutstatus Àr större Àn 128 om tidsgrÀnsen överskrids\n" " -u fb\t\tlÀs frÄn filbeskrivare FB istÀllet för standard in\n" " \n" " Slutstatus:\n" " Returkoden Àr noll om inte filslut nÄs, lÀsningens tidsgrÀns överskrids\n" -" eller en ogiltig filbeskrivare ges som argument till -u." +" (dÄ den Àr större Àn 128), ett fel vid variabeltilldelning intrÀffar eller\n" +" en ogiltig filbeskrivare ges som argument till -u." #: builtins.c:1026 msgid "" @@ -3775,7 +3614,6 @@ msgstr "" " skript." #: builtins.c:1039 -#, fuzzy msgid "" "Set or unset values of shell options and positional parameters.\n" " \n" @@ -3818,8 +3656,7 @@ msgid "" " physical same as -P\n" " pipefail the return value of a pipeline is the status of\n" " the last command to exit with a non-zero status,\n" -" or zero if no command exited with a non-zero " -"status\n" +" or zero if no command exited with a non-zero status\n" " posix change the behavior of bash where the default\n" " operation differs from the Posix standard to\n" " match the standard\n" @@ -3870,8 +3707,7 @@ msgstr "" " -e Avsluta omedelbart om ett kommando avslutar med nollskild status.\n" " -f Avaktivera filnamnsgenerering (globbing).\n" " -h Kom ihÄg platsen för kommandon nÀr de slÄs upp.\n" -" -k Alla tilldelningsargument placeras i miljön för ett kommando, " -"inte\n" +" -k Alla tilldelningsargument placeras i miljön för ett kommando, inte\n" " bara de som föregÄr kommandonamnet.\n" " -m Jobbstyrning Àr aktiverat.\n" " -n LÀs kommandon men exekvera dem inte.\n" @@ -3886,8 +3722,7 @@ msgstr "" " hashall samma som -h\n" " histexpand samma som -H\n" " history aktivera kommandohistoria\n" -" ignoreeof skalet kommer inte avsluta vid lÀsning av " -"filslut\n" +" ignoreeof skalet kommer inte avsluta vid lÀsning av filslut\n" " interactive-comments\n" " tillÄt kommentarer att förekomma i interaktiva\n" " kommandon\n" @@ -3914,8 +3749,7 @@ msgstr "" " xtrace samma som -x\n" " -p SlÄs pÄ nÀr den verkliga och effektiva anvÀndar-id:n inte stÀmmer\n" " överens. Avaktiverar bearbetning av $ENV-filen och import av\n" -" skalfunktioner. Att slÄ av denna flagga fÄr den effektiva uid " -"och\n" +" skalfunktioner. Att slÄ av denna flagga fÄr den effektiva uid och\n" " gid att sÀttas till den verkliga uid och gid.\n" " -t Avsluta efter att ha lÀst och exekverat ett kommando.\n" " -u Behandla osatta variabler som fel vid substitution.\n" @@ -3927,19 +3761,16 @@ msgstr "" " -E Om satt Àrvs ERR-fÀllan av skalfunktioner.\n" " -H Aktivera historiesubstituion i !-stil. Denna flagga Àr pÄ som\n" " standard nÀr skalet Àr interaktivt.\n" -" -P Om satt följs inte symboliska lÀnkar nÀr kommandon sÄsom cd körs\n" -" som Àndrar aktuell katalog.\n" +" -P Om satt löses inte symboliska lÀnkar upp nÀr kommandon sÄsom cd\n" +" körs som Àndrar aktuell katalog.\n" " -T Om satt Àrvs DEBUG-fÀllan av skalfunktioner.\n" -" -- Tilldela eventuella ÄterstÄende argument till " -"positionsparametrar.\n" +" -- Tilldela eventuella ÄterstÄende argument till positionsparametrar.\n" " Om det inte finns nÄgra ÄterstÄende argument nollstÀlls\n" " positionsparametrarna.\n" -" - Tilldela eventuella ÄterstÄende argument till " -"positionsparametrar.\n" +" - Tilldela eventuella ÄterstÄende argument till positionsparametrar.\n" " Flaggorna -x och -v slÄs av.\n" " \n" -" AnvÀndning av + istÀllet för - fÄr dessa flaggor att slÄs av. " -"Flaggorna\n" +" AnvÀndning av + istÀllet för - fÄr dessa flaggor att slÄs av. Flaggorna\n" " kan Àven anvÀndas vid uppstart av skalet. Den aktuella uppsÀttningen\n" " flaggor finns i $-. De ÄterstÄende n ARGumenten Àr positionsparametrar\n" " och tilldelas, i ordning, till $1, $2, .. $n. Om inga ARGument ges\n" @@ -3949,7 +3780,6 @@ msgstr "" " Returnerar framgÄng om inte en ogiltig flagga ges." #: builtins.c:1124 -#, fuzzy msgid "" "Unset values and attributes of shell variables and functions.\n" " \n" @@ -3961,8 +3791,7 @@ msgid "" " -n\ttreat each NAME as a name reference and unset the variable itself\n" " \trather than the variable it references\n" " \n" -" Without options, unset first tries to unset a variable, and if that " -"fails,\n" +" Without options, unset first tries to unset a variable, and if that fails,\n" " tries to unset a function.\n" " \n" " Some variables cannot be unset; also see `readonly'.\n" @@ -3977,11 +3806,13 @@ msgstr "" " Flaggor:\n" " -f\tbehandla varje NAMN som en skalfunktion\n" " -v\tbehandla varje NAMN som en skalvariabel\n" +" -n\tbehandla varje NAMN som en namnreferens tar bort vÀrdet pÄ\n" +" \tvariabeln sjÀlv istÀllet för variabeln den refererar\n" " \n" " Utan flaggor försöker unset först att ta bort en variabel, och, om det\n" " misslyckas, försöker den ta bort en funktion.\n" " \n" -" NÄgra variabler kan inte tas bort, se Àven \"readonly\".\n" +" NÄgra variabler kan inte tas bort, se Àven ñ€readonlyñ€.\n" " \n" " Slutstatus:\n" " Returnerar framgÄng om inte en ogiltig flagga ges eller NAMN endast Àr\n" @@ -3992,8 +3823,7 @@ msgid "" "Set export attribute for shell variables.\n" " \n" " Marks each NAME for automatic export to the environment of subsequently\n" -" executed commands. If VALUE is supplied, assign VALUE before " -"exporting.\n" +" executed commands. If VALUE is supplied, assign VALUE before exporting.\n" " \n" " Options:\n" " -f\trefer to shell functions\n" @@ -4021,7 +3851,6 @@ msgstr "" " Returnerar framgÄng om inte en ogiltig flagga ges eller NAMN Àr ogiltigt." #: builtins.c:1165 -#, fuzzy msgid "" "Mark shell variables as unchangeable.\n" " \n" @@ -4033,9 +3862,7 @@ msgid "" " -a\trefer to indexed array variables\n" " -A\trefer to associative array variables\n" " -f\trefer to shell functions\n" -" -p\tdisplay a list of all readonly variables or functions, depending " -"on\n" -" whether or not the -f option is given\n" +" -p\tdisplay a list of all readonly variables and functions\n" " \n" " An argument of `--' disables further option processing.\n" " \n" @@ -4059,7 +3886,7 @@ msgstr "" " Slutstatus:\n" " Returnerar framgÄng om inte en ogiltig flagga ges eller NAMN Àr ogiltigt." -#: builtins.c:1187 +#: builtins.c:1186 msgid "" "Shift positional parameters.\n" " \n" @@ -4071,14 +3898,13 @@ msgid "" msgstr "" "Skifta positionsparametrar.\n" " \n" -" Byt namn pÄ positionsparametrarna $N+1,$N+2 ... till $1,$2 ... Om N " -"inte\n" +" Byt namn pÄ positionsparametrarna $N+1,$N+2 ... till $1,$2 ... Om N inte\n" " anges antas det vara 1.\n" " \n" " Slutstatus:\n" " Returnerar framgÄng om inte N Àr negativt eller större Àn $#." -#: builtins.c:1199 builtins.c:1214 +#: builtins.c:1198 builtins.c:1213 msgid "" "Execute commands from a file in the current shell.\n" " \n" @@ -4093,8 +3919,7 @@ msgid "" msgstr "" "Exekvera kommandon frÄn en fil i det aktuella skalet.\n" " \n" -" LÀs och exekvera kommandon frÄn FILNAMN i det aktuella skalet. " -"Posterna\n" +" LÀs och exekvera kommandon frÄn FILNAMN i det aktuella skalet. Posterna\n" " i $PATH anvÀnds för att hitta katalogen som innehÄller FILNAMN. Om\n" " nÄgot ARGUMENT ges blir de positionsparametrar nÀr FILNAMN körs.\n" " \n" @@ -4102,7 +3927,7 @@ msgstr "" " Returnerar status pÄ det sista kommandot som körs i FILNAMN, misslyckas\n" " om FILNAMN inte kan lÀsas." -#: builtins.c:1230 +#: builtins.c:1229 msgid "" "Suspend shell execution.\n" " \n" @@ -4124,12 +3949,10 @@ msgstr "" " -f\tframtvinga suspendering, Àven om skalet Àr ett inloggningsskal\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte jobbstyrning inte Àr aktiverat eller ett " -"fel\n" +" Returnerar framgÄng om inte jobbstyrning inte Àr aktiverat eller ett fel\n" " intrÀffar." -#: builtins.c:1246 -#, fuzzy +#: builtins.c:1245 msgid "" "Evaluate conditional expression.\n" " \n" @@ -4163,8 +3986,7 @@ msgid "" " -x FILE True if the file is executable by you.\n" " -O FILE True if the file is effectively owned by you.\n" " -G FILE True if the file is effectively owned by your group.\n" -" -N FILE True if the file has been modified since it was last " -"read.\n" +" -N FILE True if the file has been modified since it was last read.\n" " \n" " FILE1 -nt FILE2 True if file1 is newer than file2 (according to\n" " modification date).\n" @@ -4185,8 +4007,7 @@ msgid "" " STRING1 != STRING2\n" " True if the strings are not equal.\n" " STRING1 < STRING2\n" -" True if STRING1 sorts before STRING2 " -"lexicographically.\n" +" True if STRING1 sorts before STRING2 lexicographically.\n" " STRING1 > STRING2\n" " True if STRING1 sorts after STRING2 lexicographically.\n" " \n" @@ -4194,8 +4015,7 @@ msgid "" " \n" " -o OPTION True if the shell option OPTION is enabled.\n" " -v VAR\t True if the shell variable VAR is set\n" -" -R VAR\t True if the shell variable VAR is set and is a name " -"reference.\n" +" -R VAR\t True if the shell variable VAR is set and is a name reference.\n" " ! EXPR True if expr is false.\n" " EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.\n" " EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.\n" @@ -4232,7 +4052,7 @@ msgstr "" " -g FIL Sant om filen Àr sÀtt-gruppid.\n" " -h FIL Sant om filen Àr en symbolisk lÀnk.\n" " -L FIL Sant om filen Àr en symbolisk lÀnk.\n" -" -k FIL Sant om filen har \"fastbiten\" satt.\n" +" -k FIL Sant om filen har ñ€fastbitenñ€ satt.\n" " -p FIL Sant om filen Àr ett namngivet rör.\n" " -r FIL Sant om filen kan lÀsas av dig.\n" " -s FIL Sant om filen finns och inte Àr tom.\n" @@ -4272,6 +4092,7 @@ msgstr "" " \n" " -o FLAGGA Sant om skalflaggan FLAGGA Àr aktiv.\n" " -v VAR Sant om skalvariabeln VAR Àr satt.\n" +" -R VAR Sant om skalvariabeln VAR Àr satt och Àr en namnreferens.\n" " ! UTTR Sant om uttr Àr falskt.\n" " UTTR1 -a UTTR2 Sant om bÄde uttr1 OCH uttr2 Àr sanna.\n" " UTTR1 -o UTTR2 Sant om antingen uttr1 ELLER uttr2 Àr sanna.\n" @@ -4287,7 +4108,7 @@ msgstr "" " Returnerar framgÄng om UTTR berÀknas till sant. Misslyckas ifall UTTR\n" " berÀknas till falskt eller ett ogiltigt argument ges." -#: builtins.c:1327 +#: builtins.c:1326 msgid "" "Evaluate conditional expression.\n" " \n" @@ -4296,16 +4117,14 @@ msgid "" msgstr "" "BerÀkna villkorligt uttryck.\n" " \n" -" Detta Àr en synonym till det inbyggda \"test\", men det sista " -"argumentet\n" +" Detta Àr en synonym till det inbyggda \"test\", men det sista argumentet\n" " mÄste vara en bokstavlig \"]\", för att matcha den inledande \"[\"." -#: builtins.c:1336 +#: builtins.c:1335 msgid "" "Display process times.\n" " \n" -" Prints the accumulated user and system times for the shell and all of " -"its\n" +" Prints the accumulated user and system times for the shell and all of its\n" " child processes.\n" " \n" " Exit Status:\n" @@ -4313,19 +4132,17 @@ msgid "" msgstr "" "Visa processtider.\n" " \n" -" Skriver ut den sammanlagda anvÀndar- och systemtiden för skalet och " -"alla\n" +" Skriver ut den sammanlagda anvÀndar- och systemtiden för skalet och alla\n" " dess barnprocesser.\n" " \n" " Slutstatus:\n" " Lyckas alltid." -#: builtins.c:1348 +#: builtins.c:1347 msgid "" "Trap signals and other events.\n" " \n" -" Defines and activates handlers to be run when the shell receives " -"signals\n" +" Defines and activates handlers to be run when the shell receives signals\n" " or other conditions.\n" " \n" " ARG is a command to be read and executed when the shell receives the\n" @@ -4334,34 +4151,26 @@ msgid "" " value. If ARG is the null string each SIGNAL_SPEC is ignored by the\n" " shell and by the commands it invokes.\n" " \n" -" If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell. " -"If\n" -" a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command. " -"If\n" -" a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or " -"a\n" -" script run by the . or source builtins finishes executing. A " -"SIGNAL_SPEC\n" -" of ERR means to execute ARG each time a command's failure would cause " -"the\n" +" If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell. If\n" +" a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command. If\n" +" a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a\n" +" script run by the . or source builtins finishes executing. A SIGNAL_SPEC\n" +" of ERR means to execute ARG each time a command's failure would cause the\n" " shell to exit when the -e option is enabled.\n" " \n" -" If no arguments are supplied, trap prints the list of commands " -"associated\n" +" If no arguments are supplied, trap prints the list of commands associated\n" " with each signal.\n" " \n" " Options:\n" " -l\tprint a list of signal names and their corresponding numbers\n" " -p\tdisplay the trap commands associated with each SIGNAL_SPEC\n" " \n" -" Each SIGNAL_SPEC is either a signal name in or a signal " -"number.\n" +" Each SIGNAL_SPEC is either a signal name in or a signal number.\n" " Signal names are case insensitive and the SIG prefix is optional. A\n" " signal may be sent to the shell with \"kill -signal $$\".\n" " \n" " Exit Status:\n" -" Returns success unless a SIGSPEC is invalid or an invalid option is " -"given." +" Returns success unless a SIGSPEC is invalid or an invalid option is given." msgstr "" "FÄnga signaler och andra hÀndelser.\n" " \n" @@ -4381,8 +4190,7 @@ msgstr "" " SIGNALSPEC ERR betyder att köra ARG varje gÄng ett kommandos felstatus\n" " skulle fÄtt skalet att avsluta om flaggan -e ovre satt.\n" " \n" -" Om inga argument ges skriver trap listan av kommandon som hör till " -"varje\n" +" Om inga argument ges skriver trap listan av kommandon som hör till varje\n" " signal.\n" " \n" " Flaggor:\n" @@ -4394,11 +4202,10 @@ msgstr "" " frivilligt. En signal kan skickas till skalet med \"kill -signal $$\".\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte en SIGSPEC Àr ogiltig eller en ogiltig " -"flagga\n" +" Returnerar framgÄng om inte en SIGSPEC Àr ogiltig eller en ogiltig flagga\n" " ges." -#: builtins.c:1384 +#: builtins.c:1383 msgid "" "Display information about command type.\n" " \n" @@ -4424,8 +4231,7 @@ msgid "" " NAME\tCommand name to be interpreted.\n" " \n" " Exit Status:\n" -" Returns success if all of the NAMEs are found; fails if any are not " -"found." +" Returns success if all of the NAMEs are found; fails if any are not found." msgstr "" "Visa information om kommandotyper.\n" " \n" @@ -4443,10 +4249,8 @@ msgstr "" " -p\treturnerar antingen namnet pÄ diskfilen som skulle exekverats,\n" " \teller ingenting om \"type -t NAMN\" inte skulle returnerat \"file\".\n" " -t\tskriv ut ett ensamt ord som Àr ett av \"alias\", \"keyword\",\n" -" \t\"function\", \"builtin\", \"file\" eller \"\", om NAMN Àr ett alias, " -"ett\n" -" \treserverat ord i skalet, en skalfunktion, inbyggt i skalet, en " -"diskfil\n" +" \t\"function\", \"builtin\", \"file\" eller \"\", om NAMN Àr ett alias, ett\n" +" \treserverat ord i skalet, en skalfunktion, inbyggt i skalet, en diskfil\n" " \trespektive inte finns\n" " \n" " Argument:\n" @@ -4455,13 +4259,11 @@ msgstr "" " Slutstatus:\n" " Returnerar framgÄng om alla NAMNen finns, misslyckas om nÄgot inte finns." -#: builtins.c:1415 -#, fuzzy +#: builtins.c:1414 msgid "" "Modify shell resource limits.\n" " \n" -" Provides control over the resources available to the shell and " -"processes\n" +" Provides control over the resources available to the shell and processes\n" " it creates, on systems that allow such control.\n" " \n" " Options:\n" @@ -4504,18 +4306,17 @@ msgid "" msgstr "" "Modifiera skalresursgrÀnser.\n" " \n" -" Ger kontroll över resurserna som Àr tillgÀngliga till skalet och " -"processer\n" +" Ger kontroll över resurserna som Àr tillgÀngliga till skalet och processer\n" " det skapar, pÄ system som möjliggör sÄdan styrning.\n" " \n" " Flaggor:\n" -" -S\tanvÀnd den \"mjuka\" resursgrÀnsen\n" -" -H\tanvÀnd den \"hÄrda\" resursgrÀnsen\n" +" -S\tanvÀnd den ñ€mjukañ€ resursgrÀnsen\n" +" -H\tanvÀnd den ñ€hÄrdañ€ resursgrÀnsen\n" " -a\talla aktuella grÀnser rapporteras\n" " -b\tstorleken pÄ uttagsbuffertar\n" " -c\tden maximala storleken pÄ minnesutskrifter som skapas\n" " -d\tden maximala storleken pÄ en process datasegmen\n" -" -e\tden maximala schemalÀggningsprioriteten (\"nice\")\n" +" -e\tden maximala schemalÀggningsprioriteten (ñ€niceñ€)\n" " -f\tden maximala storleken pÄ filer som skrivs av skalet och dess\n" " \tbarn\n" " -i\tdet maximala antalet vÀntande signaler\n" @@ -4530,24 +4331,23 @@ msgstr "" " -u\tdet maximala antalet anvÀndarprocesser\n" " -v\tstorleken pÄ det virtuella minnet\n" " -x\tdet maximala antalet fillÄs\n" +" -T det maximala antalet trÄdar\n" +" \n" +" Alla flaggor Àr inte tillgÀngliga pÄ alla plattformar.\n" " \n" " Om GRÄNS anges Àr det ett nytt vÀrde för den specificerade resursen; de\n" -" speciella GRÄNS-vÀrdena \"soft\", \"hard\" och \"unlimited\" stÄr för " -"den\n" -" aktuella mjuka grÀnsen, den aktuella hÄrda grÄnsen respektive inge " -"grÀns.\n" +" speciella GRÄNS-vÀrdena ñ€softñ€, ñ€hardñ€ och ñ€unlimitedñ€ stÄr för den\n" +" aktuella mjuka grÀnsen, den aktuella hÄrda grÄnsen respektive inge grÀns.\n" " Annars skrivs det aktuella vÀrdet pÄ den specificerade resursen. Om\n" " ingen flagga ges antas -f.\n" " \n" -" VÀrden Àr i 1024-bytesteg, utom för -t som Àr i sekunder, -p som Àr i " -"steg\n" +" VÀrden Àr i 1024-bytesteg, utom för -t som Àr i sekunder, -p som Àr i steg\n" " pÄ 512 byte och -u som Àr ett antal processer utan nÄgon skalning.\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte en ogiltig flagga anges eller ett fel " -"intrÀffar." +" Returnerar framgÄng om inte en ogiltig flagga anges eller ett fel intrÀffar." -#: builtins.c:1463 +#: builtins.c:1462 msgid "" "Display or set file mode mask.\n" " \n" @@ -4569,8 +4369,7 @@ msgstr "" " SÀtter anvÀndarens filskapningsmask till RÄTTIGHETER. Om RÄTTIGHETER\n" " utelÀmnas skrivs det aktuella vÀrdet pÄ masken.\n" " \n" -" Om RÄTTIGHETER börjar med en siffra tolkas det som ett oktalt tal, " -"annars\n" +" Om RÄTTIGHETER börjar med en siffra tolkas det som ett oktalt tal, annars\n" " Àr det en symbolisk rÀttighetsstrÀng som den som tas av chmod(1).\n" " \n" " Flaggor:\n" @@ -4579,21 +4378,17 @@ msgstr "" " -S\tgör utmatningen symbolisk, annars anvÀnds oktala tal\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte RÄTTIGHETER Àr ogiltig eller en ogiltig " -"flagga\n" +" Returnerar framgÄng om inte RÄTTIGHETER Àr ogiltig eller en ogiltig flagga\n" " ges." -#: builtins.c:1483 -#, fuzzy +#: builtins.c:1482 msgid "" "Wait for job completion and return exit status.\n" " \n" -" Waits for each process identified by an ID, which may be a process ID or " -"a\n" +" Waits for each process identified by an ID, which may be a process ID or a\n" " job specification, and reports its termination status. If ID is not\n" " given, waits for all currently active child processes, and the return\n" -" status is zero. If ID is a a job specification, waits for all " -"processes\n" +" status is zero. If ID is a a job specification, waits for all processes\n" " in that job's pipeline.\n" " \n" " If the -n option is supplied, waits for the next job to terminate and\n" @@ -4603,48 +4398,44 @@ msgid "" " Returns the status of the last ID; fails if ID is invalid or an invalid\n" " option is given." msgstr "" -"VÀnta pÄ att jobb blir fÀrdiga och returnerar slutstatus.\n" +"VÀnta pÄ att jobb blir fÀrdiga och returnera slutstatus.\n" " \n" -" VÀntar pÄ processen som identifieras av ID, som kan vara en process-id\n" -" eller en jobbspecifikation, och rapportera dess avslutningsstatus. Om\n" -" ID inte ges, vÀnta pÄ alla nu körande barnprocesser, och returstatus Àr\n" -" noll. Om ID Àr en jobbspecifikation, vÀnta pÄ alla processer i det\n" -" jobbets rör.\n" +" VÀntar pÄ varje process som identifieras av ett ID, som kan vara en\n" +" process-id eller en jobbspecifikation, och rapportera dess\n" +" avslutningsstatus. Om ID inte ges, vÀnta pÄ alla nu körande\n" +" barnprocesser, och returstatus Àr noll. Om ID Àr en jobbspecifikation, \n" +" vÀnta pÄ alla processer i det jobbets rör.\n" +" \n" +" Om flaggan -n ges vÀntar pÄ nÀsta jobb att avsluta och retunera dess\n" +" slutstatus.\n" " \n" " Slutstatus:\n" -" Returnerar status pÄ ID, misslyckas ifall ID Àr ogiltig eller en " -"ogiltig\n" -" flagga ges." +" Returnerar status pÄ den sista ID, misslyckas ifall ID Àr ogiltig\n" +" eller en ogiltig flagga ges." -#: builtins.c:1504 -#, fuzzy +#: builtins.c:1503 msgid "" "Wait for process completion and return exit status.\n" " \n" -" Waits for each process specified by a PID and reports its termination " -"status.\n" +" Waits for each process specified by a PID and reports its termination status.\n" " If PID is not given, waits for all currently active child processes,\n" " and the return status is zero. PID must be a process ID.\n" " \n" " Exit Status:\n" -" Returns the status of the last PID; fails if PID is invalid or an " -"invalid\n" +" Returns the status of the last PID; fails if PID is invalid or an invalid\n" " option is given." msgstr "" "VÀnta pÄ att en process blir fÀrdig och returnerar slutstatus.\n" " \n" -" VÀntar pÄ den angivna processen och rapportera dess avslutningsstatus. " -"Om\n" -" PID inte ges, vÀnta pÄ alla nu körande barnprocesser, och returstatus " -"Àr\n" -" noll. PID mÄste vara en process-id.\n" +" VÀntar pÄ varje process som identifieras av en PID rapporterar dess\n" +" slutstatus. Om PID inte ges, vÀntar pÄ alla nu körande barnprocesser,\n" +" och returstatus Àr noll. PID mÄste vara en process-id.\n" " \n" " Slutstatus:\n" -" Returnerar status pÄ ID, misslyckas ifall ID Àr ogiltig eller en " -"ogiltig\n" -" flagga ges." +" Returnerar status pÄ den sista PID, misslyckas ifall PID Àr ogiltig\n" +" eller en ogiltig flagga ges." -#: builtins.c:1519 +#: builtins.c:1518 msgid "" "Execute commands for each member in a list.\n" " \n" @@ -4659,15 +4450,14 @@ msgstr "" "Exekvera kommandon för varje medlem i en lista.\n" " \n" " \"for\"-slingan exekverar en sekvens av kommandon för varje medlem i en\n" -" lista av element. Om \"in ORD ...;\" inte Àr med antas 'in \"$@\"'. " -"För\n" +" lista av element. Om \"in ORD ...;\" inte Àr med antas 'in \"$@\"'. För\n" " varje element i ORD sÀtts NAMN till det elementet, och KOMMANDON\n" " exekveras.\n" " \n" " Slutstatus:\n" " Returnerar status för det sist exekverade kommandot." -#: builtins.c:1533 +#: builtins.c:1532 msgid "" "Arithmetic for loop.\n" " \n" @@ -4697,7 +4487,7 @@ msgstr "" " Slutstatus:\n" " Returnerar statusen frÄn det sist exekverade kommandot." -#: builtins.c:1551 +#: builtins.c:1550 msgid "" "Select words from a list and execute commands.\n" " \n" @@ -4732,7 +4522,7 @@ msgstr "" " Sluttatus:\n" " Returnerar statusen frÄn det sist exekverade kommandot." -#: builtins.c:1572 +#: builtins.c:1571 msgid "" "Report time consumed by pipeline's execution.\n" " \n" @@ -4761,7 +4551,7 @@ msgstr "" " Slutstatus:\n" " Returstatusen Àr returstatusen frÄn RÖR." -#: builtins.c:1589 +#: builtins.c:1588 msgid "" "Execute commands based on pattern matching.\n" " \n" @@ -4779,21 +4569,16 @@ msgstr "" " Slutstatus:\n" " Returnerar statusen frÄn det sist exekverade kommandot." -#: builtins.c:1601 +#: builtins.c:1600 msgid "" "Execute commands based on conditional.\n" " \n" -" The `if COMMANDS' list is executed. If its exit status is zero, then " -"the\n" -" `then COMMANDS' list is executed. Otherwise, each `elif COMMANDS' list " -"is\n" +" The `if COMMANDS' list is executed. If its exit status is zero, then the\n" +" `then COMMANDS' list is executed. Otherwise, each `elif COMMANDS' list is\n" " executed in turn, and if its exit status is zero, the corresponding\n" -" `then COMMANDS' list is executed and the if command completes. " -"Otherwise,\n" -" the `else COMMANDS' list is executed, if present. The exit status of " -"the\n" -" entire construct is the exit status of the last command executed, or " -"zero\n" +" `then COMMANDS' list is executed and the if command completes. Otherwise,\n" +" the `else COMMANDS' list is executed, if present. The exit status of the\n" +" entire construct is the exit status of the last command executed, or zero\n" " if no condition tested true.\n" " \n" " Exit Status:\n" @@ -4801,13 +4586,10 @@ msgid "" msgstr "" "Exekvera kommndon baserat pÄ ett villkor.\n" " \n" -" Listan \"if KOMMANDON\" exekveras. Om des slutstatus Àr noll sÄ " -"exekveras\n" -" listan \"then COMMANDS\". Annars exekveras varje lista \"elif KOMMANDON" -"\"\n" +" Listan \"if KOMMANDON\" exekveras. Om des slutstatus Àr noll sÄ exekveras\n" +" listan \"then COMMANDS\". Annars exekveras varje lista \"elif KOMMANDON\"\n" " i tur och ordning, och om dess slutstatus Àr noll exekveras motsvarande\n" -" lista \"then COMMANDS\" och if-kommandot avslutar. Annars exekveras " -"listan\n" +" lista \"then COMMANDS\" och if-kommandot avslutar. Annars exekveras listan\n" " \"else COMMANDS\" om den finns. Slutstatus av hela konstruktionen Àr\n" " slutstatusen pÄ det sist exekverade kommandot, eller noll om inget\n" " villkor returnerade sant.\n" @@ -4815,7 +4597,7 @@ msgstr "" " Slutstatus:\n" " Returnerar status frÄn det sist exekverade kommandot." -#: builtins.c:1618 +#: builtins.c:1617 msgid "" "Execute commands as long as a test succeeds.\n" " \n" @@ -4833,7 +4615,7 @@ msgstr "" " Slutstatus:\n" " Returnerar statusen frÄn det sist exekverade kommandot." -#: builtins.c:1630 +#: builtins.c:1629 msgid "" "Execute commands as long as a test does not succeed.\n" " \n" @@ -4851,7 +4633,7 @@ msgstr "" " Slutstatus:\n" " Returnerar statusen frÄn det sist exekverade kommandot." -#: builtins.c:1642 +#: builtins.c:1641 msgid "" "Create a coprocess named NAME.\n" " \n" @@ -4873,13 +4655,12 @@ msgstr "" " Slutstatus:\n" " Returnerar statusen frÄn KOMMANDO." -#: builtins.c:1656 +#: builtins.c:1655 msgid "" "Define shell function.\n" " \n" " Create a shell function named NAME. When invoked as a simple command,\n" -" NAME runs COMMANDs in the calling shell's context. When NAME is " -"invoked,\n" +" NAME runs COMMANDs in the calling shell's context. When NAME is invoked,\n" " the arguments are passed to the function as $1...$n, and the function's\n" " name is in $FUNCNAME.\n" " \n" @@ -4896,7 +4677,7 @@ msgstr "" " Slutstatus:\n" " Returnerar framgÄng om inte NAMN endast Àr lÀsbart." -#: builtins.c:1670 +#: builtins.c:1669 msgid "" "Group commands as a unit.\n" " \n" @@ -4914,7 +4695,7 @@ msgstr "" " Slutstatus:\n" " Returnerar stutusen frÄn det sist exekverade kommandot." -#: builtins.c:1682 +#: builtins.c:1681 msgid "" "Resume job in foreground.\n" " \n" @@ -4938,7 +4719,7 @@ msgstr "" " Slutstatus:\n" " Returnerar statusen pÄ det Äterupptagna jobbet." -#: builtins.c:1697 +#: builtins.c:1696 msgid "" "Evaluate arithmetic expression.\n" " \n" @@ -4956,16 +4737,13 @@ msgstr "" " Slutstatus:\n" " Returnerar 1 om UTTRYCK berÀknas till 0, returnerar 0 annars." -#: builtins.c:1709 +#: builtins.c:1708 msgid "" "Execute conditional command.\n" " \n" -" Returns a status of 0 or 1 depending on the evaluation of the " -"conditional\n" -" expression EXPRESSION. Expressions are composed of the same primaries " -"used\n" -" by the `test' builtin, and may be combined using the following " -"operators:\n" +" Returns a status of 0 or 1 depending on the evaluation of the conditional\n" +" expression EXPRESSION. Expressions are composed of the same primaries used\n" +" by the `test' builtin, and may be combined using the following operators:\n" " \n" " ( EXPRESSION )\tReturns the value of EXPRESSION\n" " ! EXPRESSION\t\tTrue if EXPRESSION is false; else false\n" @@ -4986,8 +4764,7 @@ msgstr "" "Kör ett villkorligt kommando.\n" " \n" " Returnerar en status av 0 eller 1 beroende pÄ evalueringen av det\n" -" villkorliga uttrycket UTTRYCK. Uttryck Àr sammansatta av samma " -"primitiver\n" +" villkorliga uttrycket UTTRYCK. Uttryck Àr sammansatta av samma primitiver\n" " som anvÀnds av det inbyggda \"test\", och kan kombineras med följande\n" " operatorer:\n" " \n" @@ -4997,10 +4774,8 @@ msgstr "" " UTTR1 || UTTR2\tSant om antingen UTTR1 eller UTTR2 Àr sant, annars\n" " falskt\n" " \n" -" NÀr operatorerna \"==\" och \"!=\" anvÀnds anvÀnds strÀngen till höger " -"om\n" -" som ett mönster och mönstermatchning utförs. NÀr operatorn \"=~\" " -"anvÀnds\n" +" NÀr operatorerna \"==\" och \"!=\" anvÀnds anvÀnds strÀngen till höger om\n" +" som ett mönster och mönstermatchning utförs. NÀr operatorn \"=~\" anvÀnds\n" " matchas strÀngen till höger om operatorn som ett reguljÀrt uttryck.\n" " \n" " Operatorerna && och || berÀknar inte UTTR2 om UTTR1 Àr tillrÀckligt för\n" @@ -5009,7 +4784,7 @@ msgstr "" " Slutstatus:\n" " 0 eller 1 beroende pÄ vÀrdet av UTTRYCK." -#: builtins.c:1735 +#: builtins.c:1734 msgid "" "Common shell variable names and usage.\n" " \n" @@ -5114,7 +4889,7 @@ msgstr "" " HISTIGNORE\tEn kolonseparerad lista av mönster som anvÀnds för att\n" " \t\tbestÀmma vilka kommandon som skall sparas i historielistan.\n" -#: builtins.c:1792 +#: builtins.c:1791 msgid "" "Add directories to stack.\n" " \n" @@ -5172,7 +4947,7 @@ msgstr "" " Returnerar framgÄng om inte ett ogiltigt argument ges eller bytet av\n" " katalog misslyckas." -#: builtins.c:1826 +#: builtins.c:1825 msgid "" "Remove directories from stack.\n" " \n" @@ -5222,7 +4997,7 @@ msgstr "" " Returnerar framgÄng om inte ett ogiltigt argument ges eller bytet av\n" " katalog misslyckas." -#: builtins.c:1856 +#: builtins.c:1855 msgid "" "Display directory stack.\n" " \n" @@ -5239,12 +5014,10 @@ msgid "" " \twith its position in the stack\n" " \n" " Arguments:\n" -" +N\tDisplays the Nth entry counting from the left of the list shown " -"by\n" +" +N\tDisplays the Nth entry counting from the left of the list shown by\n" " \tdirs when invoked without options, starting with zero.\n" " \n" -" -N\tDisplays the Nth entry counting from the right of the list shown " -"by\n" +" -N\tDisplays the Nth entry counting from the right of the list shown by\n" " \tdirs when invoked without options, starting with zero.\n" " \n" " Exit Status:\n" @@ -5272,16 +5045,14 @@ msgstr "" " \tav dirs nÀr det anropas utan flÀggor, med början frÄn noll.\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel " -"intrÀffar." +" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel intrÀffar." -#: builtins.c:1885 +#: builtins.c:1884 msgid "" "Set and unset shell options.\n" " \n" " Change the setting of each shell option OPTNAME. Without any option\n" -" arguments, list all shell options with an indication of whether or not " -"each\n" +" arguments, list all shell options with an indication of whether or not each\n" " is set.\n" " \n" " Options:\n" @@ -5311,8 +5082,7 @@ msgstr "" " Returnerar framgÄng om FLGNAMN Àr aktiverat, misslyckas om en ogiltig\n" " flagga ges eller FLGNAMN Àr avaktiverat." -#: builtins.c:1906 -#, fuzzy +#: builtins.c:1905 msgid "" "Formats and prints ARGUMENTS under control of the FORMAT.\n" " \n" @@ -5320,34 +5090,27 @@ msgid "" " -v var\tassign the output to shell variable VAR rather than\n" " \t\tdisplay it on the standard output\n" " \n" -" FORMAT is a character string which contains three types of objects: " -"plain\n" -" characters, which are simply copied to standard output; character " -"escape\n" +" FORMAT is a character string which contains three types of objects: plain\n" +" characters, which are simply copied to standard output; character escape\n" " sequences, which are converted and copied to the standard output; and\n" -" format specifications, each of which causes printing of the next " -"successive\n" +" format specifications, each of which causes printing of the next successive\n" " argument.\n" " \n" -" In addition to the standard format specifications described in " -"printf(1),\n" +" In addition to the standard format specifications described in printf(1),\n" " printf interprets:\n" " \n" " %b\texpand backslash escape sequences in the corresponding argument\n" " %q\tquote the argument in a way that can be reused as shell input\n" -" %(fmt)T output the date-time string resulting from using FMT as a " -"format\n" +" %(fmt)T output the date-time string resulting from using FMT as a format\n" " string for strftime(3)\n" " \n" " The format is re-used as necessary to consume all of the arguments. If\n" " there are fewer arguments than the format requires, extra format\n" -" specifications behave as if a zero value or null string, as " -"appropriate,\n" +" specifications behave as if a zero value or null string, as appropriate,\n" " had been supplied.\n" " \n" " Exit Status:\n" -" Returns success unless an invalid option is given or a write or " -"assignment\n" +" Returns success unless an invalid option is given or a write or assignment\n" " error occurs." msgstr "" "Formatera och skriv ARGUMENT styrda av FORMAT.\n" @@ -5358,13 +5121,12 @@ msgstr "" " \n" " FORMAT Àr en teckenstrÀng som innehÄller tre sortes objekt: vanliga\n" " tecken, som helt enkelt kopieras till standard ut, teckenstyrsekvenser\n" -" som konverteras och kopieras till standard ut och " -"formatspecifikationer,\n" +" som konverteras och kopieras till standard ut och formatspecifikationer,\n" " dÀr var och en medför utskrift av det nÀstföljande argumentet.\n" " argument.\n" " \n" -" Förutom de standardformatspecifikationer som beskrivs a printf(1) och\n" -" printf(3) tolkar printf:\n" +" Förutom de standardformatspecifikationer som beskrivs a printf(1),\n" +" tolkar printf:\n" " \n" " %b\texpandera bakstrecksstyrsekvenser i motsvarande argument\n" " %q\tcitera argumentet pÄ ett sÀtt som kan ÄteranvÀndas som\n" @@ -5372,18 +5134,21 @@ msgstr "" " %(fmt)T skriv ut datum-/tidstrÀngen som blir resultatet av att\n" " anvÀnda FMT som en formatstrÀng till strftime(3)\n" " \n" +" Formatet ÄteranvÀnds vid behov för att konsumera alla argument. Om\n" +" det finns fÀrre argument Àn formatet behöver beter sig överskjutande\n" +" formatspecifikationer som om vÀrdet noll eller den tomma strÀngen,\n" +" det som passar, hade angivits.\n" +" \n" " Slutstatus:\n" " Returnerar framgÄng om inte en ogiltig flagga ges eller ett skriv-\n" " eller tilldelningsfel intrÀffar." -#: builtins.c:1940 +#: builtins.c:1939 msgid "" "Specify how arguments are to be completed by Readline.\n" " \n" -" For each NAME, specify how arguments are to be completed. If no " -"options\n" -" are supplied, existing completion specifications are printed in a way " -"that\n" +" For each NAME, specify how arguments are to be completed. If no options\n" +" are supplied, existing completion specifications are printed in a way that\n" " allows them to be reused as input.\n" " \n" " Options:\n" @@ -5423,16 +5188,14 @@ msgstr "" " -E.\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel " -"intrÀffar." +" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel intrÀffar." -#: builtins.c:1968 +#: builtins.c:1967 msgid "" "Display possible completions depending on the options.\n" " \n" " Intended to be used from within a shell function generating possible\n" -" completions. If the optional WORD argument is supplied, matches " -"against\n" +" completions. If the optional WORD argument is supplied, matches against\n" " WORD are generated.\n" " \n" " Exit Status:\n" @@ -5445,19 +5208,15 @@ msgstr "" " matchningar av ORD.\n" " \n" " Slutstatus:\n" -" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel " -"intrÀffar." +" Returnerar framgÄng om inte en ogiltig flagga ges eller ett fel intrÀffar." -#: builtins.c:1983 +#: builtins.c:1982 msgid "" "Modify or display completion options.\n" " \n" -" Modify the completion options for each NAME, or, if no NAMEs are " -"supplied,\n" -" the completion currently being executed. If no OPTIONs are given, " -"print\n" -" the completion options for each NAME or the current completion " -"specification.\n" +" Modify the completion options for each NAME, or, if no NAMEs are supplied,\n" +" the completion currently being executed. If no OPTIONs are given, print\n" +" the completion options for each NAME or the current completion specification.\n" " \n" " Options:\n" " \t-o option\tSet completion option OPTION for each NAME\n" @@ -5480,8 +5239,7 @@ msgid "" msgstr "" "Modifiera eller visa kompletteringsflaggor.\n" " \n" -" Modifiera kompletteringsflaggorna för varje NAMN, eller, om inga NAMN " -"Àr\n" +" Modifiera kompletteringsflaggorna för varje NAMN, eller, om inga NAMN Àr\n" " givna, den komplettering som för nÀrvarande körs. Om ingen FLAGGA Àr\n" " given skrivs kompletteringsflaggorna för varje NAMN eller den aktuella\n" " kompletteringsspecifikationen.\n" @@ -5491,14 +5249,12 @@ msgstr "" " \t-D\t Ändra flaggorna för standardkommandokompletteringen\n" " \t-E\t\tÄndra flaggorna för komplettering av ett tomt kommando\n" " \n" -" Genom att anvÀnda \"+o\" istÀllet för \"-o\" slÄs den angivna flaggan " -"av.\n" +" Genom att anvÀnda \"+o\" istÀllet för \"-o\" slÄs den angivna flaggan av.\n" " \n" " Argument:\n" " \n" " Varje NAMN refererar till ett kommando för vilket en kompletterings-\n" -" specifikation mÄste ha definierats tidigare med det inbyggda \"complete" -"\".\n" +" specifikation mÄste ha definierats tidigare med det inbyggda \"complete\".\n" " Om inget NAMN ges mÄste compopt anropas av en funktion som just nu\n" " genererar kompletteringar, och flaggorna för den just nu exekverande\n" " kompletteringsgeneratorn modifieras.\n" @@ -5507,28 +5263,22 @@ msgstr "" " Returnerar framgÄng om inte en ogiltig flagga ges eller NAMN inte har\n" " nÄgon kompletteringsspecifikaation definierad." -#: builtins.c:2013 +#: builtins.c:2012 msgid "" "Read lines from the standard input into an indexed array variable.\n" " \n" -" Read lines from the standard input into the indexed array variable " -"ARRAY, or\n" -" from file descriptor FD if the -u option is supplied. The variable " -"MAPFILE\n" +" Read lines from the standard input into the indexed array variable ARRAY, or\n" +" from file descriptor FD if the -u option is supplied. The variable MAPFILE\n" " is the default ARRAY.\n" " \n" " Options:\n" -" -n count\tCopy at most COUNT lines. If COUNT is 0, all lines are " -"copied.\n" -" -O origin\tBegin assigning to ARRAY at index ORIGIN. The default " -"index is 0.\n" +" -n count\tCopy at most COUNT lines. If COUNT is 0, all lines are copied.\n" +" -O origin\tBegin assigning to ARRAY at index ORIGIN. The default index is 0.\n" " -s count \tDiscard the first COUNT lines read.\n" " -t\t\tRemove a trailing newline from each line read.\n" -" -u fd\t\tRead lines from file descriptor FD instead of the standard " -"input.\n" +" -u fd\t\tRead lines from file descriptor FD instead of the standard input.\n" " -C callback\tEvaluate CALLBACK each time QUANTUM lines are read.\n" -" -c quantum\tSpecify the number of lines read between each call to " -"CALLBACK.\n" +" -c quantum\tSpecify the number of lines read between each call to CALLBACK.\n" " \n" " Arguments:\n" " ARRAY\t\tArray variable name to use for file data.\n" @@ -5538,13 +5288,11 @@ msgid "" " element to be assigned and the line to be assigned to that element\n" " as additional arguments.\n" " \n" -" If not supplied with an explicit origin, mapfile will clear ARRAY " -"before\n" +" If not supplied with an explicit origin, mapfile will clear ARRAY before\n" " assigning to it.\n" " \n" " Exit Status:\n" -" Returns success unless an invalid option is given or ARRAY is readonly " -"or\n" +" Returns success unless an invalid option is given or ARRAY is readonly or\n" " not an indexed array." msgstr "" "LÀs rader frÄn standard in till en indexerad vektorvariabel.\n" @@ -5554,10 +5302,8 @@ msgstr "" " standard för VEKTOR.\n" " \n" " Flaggor:\n" -" -n antal\tKopiera högs ANTAL rader. Om ANTAL Àr 0 kopieras alla " -"rader.\n" -" -O start\tBörja tilldela till VEKTOR vid index START. Standardindex " -"Àr 0.\n" +" -n antal\tKopiera högs ANTAL rader. Om ANTAL Àr 0 kopieras alla rader.\n" +" -O start\tBörja tilldela till VEKTOR vid index START. Standardindex Àr 0.\n" " -s antal \tSlÀng de första ANTAL inlÀsta raderna.\n" " -t\t\tTa bort en avslutande nyrad frÄn varje inlÀst rad.\n" " -u fb\t\tLÀs rader frÄn filbeskrivare FB istÀllet för standard in.\n" @@ -5569,19 +5315,17 @@ msgstr "" " VEKTOR\t\tNamn pÄ vektorvariabel att anvÀnda för fildata.\n" " \n" " Om -C ges utan -c Àr standardkvanta 5000. NÀr ÅTERANROP evalueras fÄr\n" -" den indexet pÄ nÀsta vektorelement att tilldelas och raden att " -"tilldelas\n" +" den indexet pÄ nÀsta vektorelement att tilldelas och raden att tilldelas\n" " till det elementet som extra argument.\n" " \n" -" Om det inte ges nÄgon specificerad start kommer mapfile nollstÀlla " -"VEKTOR\n" +" Om det inte ges nÄgon specificerad start kommer mapfile nollstÀlla VEKTOR\n" " före tilldelning till den.\n" " \n" " Slutstatus:\n" " Returnerar framgÄng om inte en ogiltig flagga ges eller VEKTOR Àr\n" " oförÀnderlig eller inte en indexerad vektor." -#: builtins.c:2047 +#: builtins.c:2046 msgid "" "Read lines from a file into an array variable.\n" " \n" @@ -5590,16 +5334,3 @@ msgstr "" "LÀs rader frÄn en fil till en vektorvariabel.\n" " \n" " En synonym till \"mapfile\"." - -#~ msgid "Copyright (C) 2009 Free Software Foundation, Inc.\n" -#~ msgstr "Copyright © 2009 Free Software Foundation, Inc.\n" - -#~ msgid "" -#~ "License GPLv2+: GNU GPL version 2 or later \n" -#~ msgstr "" -#~ "Licens GPLv2+: GNU GPL version 2 eller senare \n" - -#~ msgid "wait [pid]" -#~ msgstr "wait [pid]" diff --git a/sig.c b/sig.c index ee78fa33f..83e40fb1d 100644 --- a/sig.c +++ b/sig.c @@ -717,7 +717,9 @@ set_signal_handler (sig, handler) sigemptyset (&act.sa_mask); sigemptyset (&oact.sa_mask); - sigaction (sig, &act, &oact); - return (oact.sa_handler); + if (sigaction (sig, &act, &oact) == 0) + return (oact.sa_handler); + else + return (SIG_DFL); } #endif /* HAVE_POSIX_SIGNALS */ diff --git a/sig.c~ b/sig.c~ new file mode 100644 index 000000000..ee78fa33f --- /dev/null +++ b/sig.c~ @@ -0,0 +1,723 @@ +/* sig.c - interface for shell signal handlers and signal initialization. */ + +/* Copyright (C) 1994-2013 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Bash is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Bash. If not, see . +*/ + +#include "config.h" + +#include "bashtypes.h" + +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#endif + +#include +#include + +#include "bashintl.h" + +#include "shell.h" +#if defined (JOB_CONTROL) +#include "jobs.h" +#endif /* JOB_CONTROL */ +#include "siglist.h" +#include "sig.h" +#include "trap.h" + +#include "builtins/common.h" + +#if defined (READLINE) +# include "bashline.h" +# include +#endif + +#if defined (HISTORY) +# include "bashhist.h" +#endif + +extern int last_command_exit_value; +extern int last_command_exit_signal; +extern int return_catch_flag; +extern int loop_level, continuing, breaking, funcnest; +extern int executing_list; +extern int comsub_ignore_return; +extern int parse_and_execute_level, shell_initialized; +#if defined (HISTORY) +extern int history_lines_this_session; +#endif +extern int no_line_editing; + +extern void initialize_siglist (); + +/* Non-zero after SIGINT. */ +volatile sig_atomic_t interrupt_state = 0; + +/* Non-zero after SIGWINCH */ +volatile sig_atomic_t sigwinch_received = 0; + +/* Non-zero after SIGTERM */ +volatile sig_atomic_t sigterm_received = 0; + +/* Set to the value of any terminating signal received. */ +volatile sig_atomic_t terminating_signal = 0; + +/* The environment at the top-level R-E loop. We use this in + the case of error return. */ +procenv_t top_level; + +#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) +/* The signal masks that this shell runs with. */ +sigset_t top_level_mask; +#endif /* JOB_CONTROL */ + +/* When non-zero, we throw_to_top_level (). */ +int interrupt_immediately = 0; + +/* When non-zero, we call the terminating signal handler immediately. */ +int terminate_immediately = 0; + +#if defined (SIGWINCH) +static SigHandler *old_winch = (SigHandler *)SIG_DFL; +#endif + +static void initialize_shell_signals __P((void)); + +void +initialize_signals (reinit) + int reinit; +{ + initialize_shell_signals (); + initialize_job_signals (); +#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL) + if (reinit == 0) + initialize_siglist (); +#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */ +} + +/* A structure describing a signal that terminates the shell if not + caught. The orig_handler member is present so children can reset + these signals back to their original handlers. */ +struct termsig { + int signum; + SigHandler *orig_handler; + int orig_flags; +}; + +#define NULL_HANDLER (SigHandler *)SIG_DFL + +/* The list of signals that would terminate the shell if not caught. + We catch them, but just so that we can write the history file, + and so forth. */ +static struct termsig terminating_signals[] = { +#ifdef SIGHUP +{ SIGHUP, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGINT +{ SIGINT, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGILL +{ SIGILL, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGTRAP +{ SIGTRAP, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGIOT +{ SIGIOT, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGDANGER +{ SIGDANGER, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGEMT +{ SIGEMT, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGFPE +{ SIGFPE, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGBUS +{ SIGBUS, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGSEGV +{ SIGSEGV, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGSYS +{ SIGSYS, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGPIPE +{ SIGPIPE, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGALRM +{ SIGALRM, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGTERM +{ SIGTERM, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGXCPU +{ SIGXCPU, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGXFSZ +{ SIGXFSZ, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGVTALRM +{ SIGVTALRM, NULL_HANDLER, 0 }, +#endif + +#if 0 +#ifdef SIGPROF +{ SIGPROF, NULL_HANDLER, 0 }, +#endif +#endif + +#ifdef SIGLOST +{ SIGLOST, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGUSR1 +{ SIGUSR1, NULL_HANDLER, 0 }, +#endif + +#ifdef SIGUSR2 +{ SIGUSR2, NULL_HANDLER, 0 }, +#endif +}; + +#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig)) + +#define XSIG(x) (terminating_signals[x].signum) +#define XHANDLER(x) (terminating_signals[x].orig_handler) +#define XSAFLAGS(x) (terminating_signals[x].orig_flags) + +static int termsigs_initialized = 0; + +/* Initialize signals that will terminate the shell to do some + unwind protection. For non-interactive shells, we only call + this when a trap is defined for EXIT (0) or when trap is run + to display signal dispositions. */ +void +initialize_terminating_signals () +{ + register int i; +#if defined (HAVE_POSIX_SIGNALS) + struct sigaction act, oact; +#endif + + if (termsigs_initialized) + return; + + /* The following code is to avoid an expensive call to + set_signal_handler () for each terminating_signals. Fortunately, + this is possible in Posix. Unfortunately, we have to call signal () + on non-Posix systems for each signal in terminating_signals. */ +#if defined (HAVE_POSIX_SIGNALS) + act.sa_handler = termsig_sighandler; + act.sa_flags = 0; + sigemptyset (&act.sa_mask); + sigemptyset (&oact.sa_mask); + for (i = 0; i < TERMSIGS_LENGTH; i++) + sigaddset (&act.sa_mask, XSIG (i)); + for (i = 0; i < TERMSIGS_LENGTH; i++) + { + /* If we've already trapped it, don't do anything. */ + if (signal_is_trapped (XSIG (i))) + continue; + + sigaction (XSIG (i), &act, &oact); + XHANDLER(i) = oact.sa_handler; + XSAFLAGS(i) = oact.sa_flags; + /* Don't do anything with signals that are ignored at shell entry + if the shell is not interactive. */ + /* XXX - should we do this for interactive shells, too? */ + if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN) + { + sigaction (XSIG (i), &oact, &act); + set_signal_ignored (XSIG (i)); + } +#if defined (SIGPROF) && !defined (_MINIX) + if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) + sigaction (XSIG (i), &oact, (struct sigaction *)NULL); +#endif /* SIGPROF && !_MINIX */ + } + +#else /* !HAVE_POSIX_SIGNALS */ + + for (i = 0; i < TERMSIGS_LENGTH; i++) + { + /* If we've already trapped it, don't do anything. */ + if (signal_is_trapped (XSIG (i))) + continue; + + XHANDLER(i) = signal (XSIG (i), termsig_sighandler); + XSAFLAGS(i) = 0; + /* Don't do anything with signals that are ignored at shell entry + if the shell is not interactive. */ + /* XXX - should we do this for interactive shells, too? */ + if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN) + { + signal (XSIG (i), SIG_IGN); + set_signal_ignored (XSIG (i)); + } +#ifdef SIGPROF + if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN) + signal (XSIG (i), XHANDLER (i)); +#endif + } + +#endif /* !HAVE_POSIX_SIGNALS */ + + termsigs_initialized = 1; +} + +static void +initialize_shell_signals () +{ + if (interactive) + initialize_terminating_signals (); + +#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) + /* All shells use the signal mask they inherit, and pass it along + to child processes. Children will never block SIGCHLD, though. */ + sigemptyset (&top_level_mask); + sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask); +# if defined (SIGCHLD) + sigdelset (&top_level_mask, SIGCHLD); +# endif +#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */ + + /* And, some signals that are specifically ignored by the shell. */ + set_signal_handler (SIGQUIT, SIG_IGN); + + if (interactive) + { + set_signal_handler (SIGINT, sigint_sighandler); + get_original_signal (SIGTERM); + if (signal_is_hard_ignored (SIGTERM) == 0) + set_signal_handler (SIGTERM, sigterm_sighandler); + set_sigwinch_handler (); + } +} + +void +reset_terminating_signals () +{ + register int i; +#if defined (HAVE_POSIX_SIGNALS) + struct sigaction act; +#endif + + if (termsigs_initialized == 0) + return; + +#if defined (HAVE_POSIX_SIGNALS) + act.sa_flags = 0; + sigemptyset (&act.sa_mask); + for (i = 0; i < TERMSIGS_LENGTH; i++) + { + /* Skip a signal if it's trapped or handled specially, because the + trap code will restore the correct value. */ + if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) + continue; + + act.sa_handler = XHANDLER (i); + act.sa_flags = XSAFLAGS (i); + sigaction (XSIG (i), &act, (struct sigaction *) NULL); + } +#else /* !HAVE_POSIX_SIGNALS */ + for (i = 0; i < TERMSIGS_LENGTH; i++) + { + if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) + continue; + + signal (XSIG (i), XHANDLER (i)); + } +#endif /* !HAVE_POSIX_SIGNALS */ + + termsigs_initialized = 0; +} +#undef XSIG +#undef XHANDLER + +/* Run some of the cleanups that should be performed when we run + jump_to_top_level from a builtin command context. XXX - might want to + also call reset_parser here. */ +void +top_level_cleanup () +{ + /* Clean up string parser environment. */ + while (parse_and_execute_level) + parse_and_execute_cleanup (); + +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif /* PROCESS_SUBSTITUTION */ + + run_unwind_protects (); + loop_level = continuing = breaking = funcnest = 0; + executing_list = comsub_ignore_return = return_catch_flag = 0; +} + +/* What to do when we've been interrupted, and it is safe to handle it. */ +void +throw_to_top_level () +{ + int print_newline = 0; + + if (interrupt_state) + { + if (last_command_exit_value < 128) + last_command_exit_value = 128 + SIGINT; + print_newline = 1; + DELINTERRUPT; + } + + if (interrupt_state) + return; + + last_command_exit_signal = (last_command_exit_value > 128) ? + (last_command_exit_value - 128) : 0; + last_command_exit_value |= 128; + + /* Run any traps set on SIGINT. */ + run_interrupt_trap (); + + /* Clean up string parser environment. */ + while (parse_and_execute_level) + parse_and_execute_cleanup (); + +#if defined (JOB_CONTROL) + give_terminal_to (shell_pgrp, 0); +#endif /* JOB_CONTROL */ + +#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS) + /* This needs to stay because jobs.c:make_child() uses it without resetting + the signal mask. */ + sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); +#endif + + reset_parser (); + +#if defined (READLINE) + if (interactive) + bashline_reset (); +#endif /* READLINE */ + +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif /* PROCESS_SUBSTITUTION */ + + run_unwind_protects (); + loop_level = continuing = breaking = funcnest = 0; + executing_list = comsub_ignore_return = return_catch_flag = 0; + + if (interactive && print_newline) + { + fflush (stdout); + fprintf (stderr, "\n"); + fflush (stderr); + } + + /* An interrupted `wait' command in a script does not exit the script. */ + if (interactive || (interactive_shell && !shell_initialized) || + (print_newline && signal_is_trapped (SIGINT))) + jump_to_top_level (DISCARD); + else + jump_to_top_level (EXITPROG); +} + +/* This is just here to isolate the longjmp calls. */ +void +jump_to_top_level (value) + int value; +{ + longjmp (top_level, value); +} + +sighandler +termsig_sighandler (sig) + int sig; +{ + /* If we get called twice with the same signal before handling it, + terminate right away. */ + if ( +#ifdef SIGHUP + sig != SIGHUP && +#endif +#ifdef SIGINT + sig != SIGINT && +#endif +#ifdef SIGDANGER + sig != SIGDANGER && +#endif +#ifdef SIGPIPE + sig != SIGPIPE && +#endif +#ifdef SIGALRM + sig != SIGALRM && +#endif +#ifdef SIGTERM + sig != SIGTERM && +#endif +#ifdef SIGXCPU + sig != SIGXCPU && +#endif +#ifdef SIGXFSZ + sig != SIGXFSZ && +#endif +#ifdef SIGVTALRM + sig != SIGVTALRM && +#endif +#ifdef SIGLOST + sig != SIGLOST && +#endif +#ifdef SIGUSR1 + sig != SIGUSR1 && +#endif +#ifdef SIGUSR2 + sig != SIGUSR2 && +#endif + sig == terminating_signal) + terminate_immediately = 1; + + terminating_signal = sig; + + /* XXX - should this also trigger when interrupt_immediately is set? */ + if (terminate_immediately) + { +#if defined (HISTORY) + /* XXX - will inhibit history file being written */ +# if defined (READLINE) + if (interactive_shell == 0 || interactive == 0 || (sig != SIGHUP && sig != SIGTERM) || no_line_editing || (RL_ISSTATE (RL_STATE_READCMD) == 0)) +# endif + history_lines_this_session = 0; +#endif + terminate_immediately = 0; + termsig_handler (sig); + } + +#if defined (READLINE) + /* Set the event hook so readline will call it after the signal handlers + finish executing, so if this interrupted character input we can get + quick response. */ + if (interactive_shell && interactive && no_line_editing == 0) + bashline_set_event_hook (); +#endif + + SIGRETURN (0); +} + +void +termsig_handler (sig) + int sig; +{ + static int handling_termsig = 0; + + /* Simple semaphore to keep this function from being executed multiple + times. Since we no longer are running as a signal handler, we don't + block multiple occurrences of the terminating signals while running. */ + if (handling_termsig) + return; + handling_termsig = 1; + terminating_signal = 0; /* keep macro from re-testing true. */ + + /* I don't believe this condition ever tests true. */ + if (sig == SIGINT && signal_is_trapped (SIGINT)) + run_interrupt_trap (); + +#if defined (HISTORY) + /* If we don't do something like this, the history will not be saved when + an interactive shell is running in a terminal window that gets closed + with the `close' button. We can't test for RL_STATE_READCMD because + readline no longer handles SIGTERM synchronously. */ + if (interactive_shell && interactive && (sig == SIGHUP || sig == SIGTERM) && remember_on_history) + maybe_save_shell_history (); +#endif /* HISTORY */ + +#if defined (JOB_CONTROL) + if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB)))) + hangup_all_jobs (); + end_job_control (); +#endif /* JOB_CONTROL */ + +#if defined (PROCESS_SUBSTITUTION) + unlink_fifo_list (); +#endif /* PROCESS_SUBSTITUTION */ + + /* Reset execution context */ + loop_level = continuing = breaking = funcnest = 0; + executing_list = comsub_ignore_return = return_catch_flag = 0; + + run_exit_trap (); /* XXX - run exit trap possibly in signal context? */ + set_signal_handler (sig, SIG_DFL); + kill (getpid (), sig); +} + +/* What we really do when SIGINT occurs. */ +sighandler +sigint_sighandler (sig) + int sig; +{ +#if defined (MUST_REINSTALL_SIGHANDLERS) + signal (sig, sigint_sighandler); +#endif + + /* interrupt_state needs to be set for the stack of interrupts to work + right. Should it be set unconditionally? */ + if (interrupt_state == 0) + ADDINTERRUPT; + + if (interrupt_immediately) + { + interrupt_immediately = 0; + last_command_exit_value = 128 + sig; + throw_to_top_level (); + } +#if defined (READLINE) + /* Set the event hook so readline will call it after the signal handlers + finish executing, so if this interrupted character input we can get + quick response. */ + else if (RL_ISSTATE (RL_STATE_SIGHANDLER)) + bashline_set_event_hook (); +#endif + + SIGRETURN (0); +} + +#if defined (SIGWINCH) +sighandler +sigwinch_sighandler (sig) + int sig; +{ +#if defined (MUST_REINSTALL_SIGHANDLERS) + set_signal_handler (SIGWINCH, sigwinch_sighandler); +#endif /* MUST_REINSTALL_SIGHANDLERS */ + sigwinch_received = 1; + SIGRETURN (0); +} +#endif /* SIGWINCH */ + +void +set_sigwinch_handler () +{ +#if defined (SIGWINCH) + old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); +#endif +} + +void +unset_sigwinch_handler () +{ +#if defined (SIGWINCH) + set_signal_handler (SIGWINCH, old_winch); +#endif +} + +sighandler +sigterm_sighandler (sig) + int sig; +{ + sigterm_received = 1; /* XXX - counter? */ + SIGRETURN (0); +} + +/* Signal functions used by the rest of the code. */ +#if !defined (HAVE_POSIX_SIGNALS) + +/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */ +sigprocmask (operation, newset, oldset) + int operation, *newset, *oldset; +{ + int old, new; + + if (newset) + new = *newset; + else + new = 0; + + switch (operation) + { + case SIG_BLOCK: + old = sigblock (new); + break; + + case SIG_SETMASK: + old = sigsetmask (new); + break; + + default: + internal_error (_("sigprocmask: %d: invalid operation"), operation); + } + + if (oldset) + *oldset = old; +} + +#else + +#if !defined (SA_INTERRUPT) +# define SA_INTERRUPT 0 +#endif + +#if !defined (SA_RESTART) +# define SA_RESTART 0 +#endif + +SigHandler * +set_signal_handler (sig, handler) + int sig; + SigHandler *handler; +{ + struct sigaction act, oact; + + act.sa_handler = handler; + act.sa_flags = 0; + + /* XXX - bash-4.2 */ + /* We don't want a child death to interrupt interruptible system calls, even + if we take the time to reap children */ +#if defined (SIGCHLD) + if (sig == SIGCHLD) + act.sa_flags |= SA_RESTART; /* XXX */ +#endif + /* If we're installing a SIGTERM handler for interactive shells, we want + it to be as close to SIG_IGN as possible. */ + if (sig == SIGTERM && handler == sigterm_sighandler) + act.sa_flags |= SA_RESTART; /* XXX */ + + sigemptyset (&act.sa_mask); + sigemptyset (&oact.sa_mask); + sigaction (sig, &act, &oact); + return (oact.sa_handler); +} +#endif /* HAVE_POSIX_SIGNALS */