doc/{bash.1,bashref.texi}
- clarifed `trap' description to make it clear that trapped signals
that are not set to SIG_IGN are reset when a subshell is created
+
+ 5/18
+ ----
+locale.c
+ - change reset_locale_vars to call setlocale (LC_ALL, "") if LANG
+ is unset or NULL
+ - if LANG is unset or NULL, reset the export environment before
+ calling setlocale in reset_locale_vars, and trust that it will
+ change the environment setlocale() inspects
+
+ 5/21
+ ----
+lib/readline/history.c
+ - new function, HIST_ENTRY *alloc_history_entry (char *string, char *ts);
+ creates a new history entry with text STRING and timestamp TS (both
+ of which may be NULL)
+ - new function, HIST_ENTRY *copy_history_entry (HIST_ENTRY *hist),
+ which copies the line and timestamp entries to new memory but just
+ copies the data member, since that's an opaque pointer
+ - new function, void replace_history_data (int which, histdata_t *old, histdata_t *new)
+ which replaces the `data' member of specified history entries with
+ NEW, as long as it is OLD. WHICH says which history entries to
+ modify
+ - add calls to replace_history_data in rl_free_undo_list and
+ rl_do_undo
+
+lib/readline/undo.c
+ - new function, alloc_undo_entry (enum undo_code what, int start, int end, char *text)
+ takes care of allocating and populating a struct for an individual
+ undo list entry
+ - new function: _rl_copy_undo_entry(UNDO_LIST *entry)
+ - new function: _rl_copy_undo_list(UNDO_LIST *head)
+
+lib/readline/rlprivate.h
+ - new extern declarations for _rl_copy_undo_{entry,list}
arrayfunc.h
- new extern declarations for expand_compound_array_assignment and
assign_compound_array_list
+
+subst.c
+ - in do_compound_assignment, call expand_compound_array_assignment
+ before creating the local variable so a previous inherited
+ value can be used when expanding the rhs of the compound assignment
+ statement
+
+ 5/11
+ ----
+doc/{bash.1,bashref.texi}
+ - clarifed `trap' description to make it clear that trapped signals
+ that are not set to SIG_IGN are reset when a subshell is created
+
+ 5/18
+ ----
+locale.c
+ - change reset_locale_vars to call setlocale (LC_ALL, "") if LANG
+ is unset or NULL
+ - if LANG is unset or NULL, reset the export environment before
+ calling setlocale in reset_locale_vars, and trust that it will
+ change the environment setlocale() inspects
+
+ 5/21
+ ----
+lib/readline/history.c
+ - new function, HIST_ENTRY *alloc_history_entry (char *string, char *ts);
+ creates a new history entry with text STRING and timestamp TS (both
+ of which may be NULL)
+ - new function, HIST_ENTRY *copy_history_entry (HIST_ENTRY *hist),
+ which copies the line and timestamp entries to new memory but just
+ copies the data member, since that's an opaque pointer
+ - new function, void replace_history_data (int which, histdata_t *old, histdata_t *new)
+ which replaces the `data' member of specified history entries with
+ NEW, as long as it is OLD. WHICH says which history entries to
+ modify
+ - add calls to replace_history_data in rl_free_undo_list and
+ rl_do_undo
+
+lib/readline/undo.c
+ - new function, alloc_undo_entry (enum undo_code what, int start, int end, char *text)
+ takes care of allocating and populating a struct for an individual
+ undo list entry
+
+
+
}
else if (cond->type == COND_BINARY)
{
+ rmatch = 0;
patmatch = ((cond->op->word[1] == '=') && (cond->op->word[2] == '\0') &&
(cond->op->word[0] == '!' || cond->op->word[0] == '=') ||
(cond->op->word[0] == '=' && cond->op->word[1] == '\0'));
arg1 = cond_expand_word (cond->left->op, 0);
if (arg1 == 0)
arg1 = nullstr;
- arg2 = cond_expand_word (cond->right->op, patmatch);
+ arg2 = cond_expand_word (cond->right->op, patmatch||rmatch);
if (arg2 == 0)
arg2 = nullstr;
report the correct line number. Kind of a hack. */
static int showing_function_line;
+static int line_number_for_err_trap;
+
/* For catching RETURN in a function. */
int return_catch_flag;
int return_catch_value;
if (command->flags & CMD_STDIN_REDIR)
command->value.Simple->flags |= CMD_STDIN_REDIR;
- line_number = command->value.Simple->line;
+ line_number_for_err_trap = line_number = command->value.Simple->line;
exec_result =
execute_simple_command (command->value.Simple, pipe_in, pipe_out,
asynchronous, fds_to_close);
: the_history[local_index];
}
+HIST_ENTRY *
+alloc_history_entry (string, ts)
+ char *string;
+ char *ts;
+{
+ HIST_ENTRY *temp;
+
+ temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+
+ temp->line = string ? savestring (string) : string;
+ temp->data = (char *)NULL;
+ temp->timestamp = ts;
+
+ return temp;
+}
+
time_t
history_get_time (hist)
HIST_ENTRY *hist;
}
}
- temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
- temp->line = savestring (string);
- temp->data = (char *)NULL;
-
- temp->timestamp = hist_inittime ();
+ temp = alloc_history_entry (string, hist_inittime ());
the_history[history_length] = (HIST_ENTRY *)NULL;
the_history[history_length - 1] = temp;
free (hist);
return (x);
}
+
+HIST_ENTRY *
+copy_history_entry (hist)
+ HIST_ENTRY *hist;
+{
+ HIST_ENTRY *ret;
+ char *ts;
+
+ if (hist == 0)
+ return hist;
+
+ ret = alloc_history_entry (hist->line, (char *)NULL);
+
+ ts = hist->timestamp ? savestring (hist->timestamp) : hist->timestamp;
+ ret->timestamp = ts;
+
+ ret->data = hist->data;
+
+ return ret;
+}
/* Make the history entry at WHICH have LINE and DATA. This returns
the old entry so you can dispose of the data. In the case of an
return (old_value);
}
+/* Replace the DATA in the specified history entries, replacing OLD with
+ NEW. WHICH says which one(s) to replace: WHICH == -1 means to replace
+ all of the history entries where entry->data == OLD; WHICH == -2 means
+ to replace the `newest' history entry where entry->data == OLD; and
+ WHICH >= 0 means to replace that particular history entry's data, as
+ long as it matches OLD. */
+void
+replace_history_data (which,old, new)
+ int which;
+ histdata_t *old, *new;
+{
+ HIST_ENTRY *entry;
+ register int i, last;
+
+ if (which < -2 || which >= history_length || history_length == 0 || the_history == 0)
+ return;
+
+ if (which >= 0)
+ {
+ entry = the_history[which];
+ if (entry && entry->data == old)
+ entry->data = new;
+ return;
+ }
+
+ last = -1;
+ for (i = 0; i < history_length; i++)
+ {
+ entry = the_history[i];
+ if (entry == 0)
+ continue;
+ if (entry->data == old)
+ {
+ last = i;
+ if (which == -1)
+ entry->data = new;
+ }
+ }
+ if (which == -2 && last >= 0)
+ {
+ entry = the_history[last];
+ entry->data = new; /* XXX - we don't check entry->old */
+ }
+}
+
/* Remove history element WHICH from the history. The removed
element is returned to you so you can free the line, data,
and containing structure. */
--- /dev/null
+/* history.c -- standalone history library */
+
+/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
+
+ This file contains the GNU History Library (the Library), a set of
+ routines for managing the text of previously typed lines.
+
+ The Library 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 2, or (at your option)
+ any later version.
+
+ The Library 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+/* The goal is to make the implementation transparent, so that you
+ don't have to know what data types are used, just what functions
+ you can call. I think I have done that. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "history.h"
+#include "histlib.h"
+
+#include "xmalloc.h"
+
+/* The number of slots to increase the_history by. */
+#define DEFAULT_HISTORY_GROW_SIZE 50
+
+static char *hist_inittime PARAMS((void));
+
+/* **************************************************************** */
+/* */
+/* History Functions */
+/* */
+/* **************************************************************** */
+
+/* An array of HIST_ENTRY. This is where we store the history. */
+static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
+
+/* Non-zero means that we have enforced a limit on the amount of
+ history that we save. */
+static int history_stifled;
+
+/* The current number of slots allocated to the input_history. */
+static int history_size;
+
+/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
+ entries to remember. */
+int history_max_entries;
+int max_input_history; /* backwards compatibility */
+
+/* The current location of the interactive history pointer. Just makes
+ life easier for outside callers. */
+int history_offset;
+
+/* The number of strings currently stored in the history list. */
+int history_length;
+
+/* The logical `base' of the history array. It defaults to 1. */
+int history_base = 1;
+
+/* Return the current HISTORY_STATE of the history. */
+HISTORY_STATE *
+history_get_history_state ()
+{
+ HISTORY_STATE *state;
+
+ state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));
+ state->entries = the_history;
+ state->offset = history_offset;
+ state->length = history_length;
+ state->size = history_size;
+ state->flags = 0;
+ if (history_stifled)
+ state->flags |= HS_STIFLED;
+
+ return (state);
+}
+
+/* Set the state of the current history array to STATE. */
+void
+history_set_history_state (state)
+ HISTORY_STATE *state;
+{
+ the_history = state->entries;
+ history_offset = state->offset;
+ history_length = state->length;
+ history_size = state->size;
+ if (state->flags & HS_STIFLED)
+ history_stifled = 1;
+}
+
+/* Begin a session in which the history functions might be used. This
+ initializes interactive variables. */
+void
+using_history ()
+{
+ history_offset = history_length;
+}
+
+/* Return the number of bytes that the primary history entries are using.
+ This just adds up the lengths of the_history->lines and the associated
+ timestamps. */
+int
+history_total_bytes ()
+{
+ register int i, result;
+
+ for (i = result = 0; the_history && the_history[i]; i++)
+ result += HISTENT_BYTES (the_history[i]);
+
+ return (result);
+}
+
+/* Returns the magic number which says what history element we are
+ looking at now. In this implementation, it returns history_offset. */
+int
+where_history ()
+{
+ return (history_offset);
+}
+
+/* Make the current history item be the one at POS, an absolute index.
+ Returns zero if POS is out of range, else non-zero. */
+int
+history_set_pos (pos)
+ int pos;
+{
+ if (pos > history_length || pos < 0 || !the_history)
+ return (0);
+ history_offset = pos;
+ return (1);
+}
+
+/* Return the current history array. The caller has to be carefull, since this
+ is the actual array of data, and could be bashed or made corrupt easily.
+ The array is terminated with a NULL pointer. */
+HIST_ENTRY **
+history_list ()
+{
+ return (the_history);
+}
+
+/* Return the history entry at the current position, as determined by
+ history_offset. If there is no entry there, return a NULL pointer. */
+HIST_ENTRY *
+current_history ()
+{
+ return ((history_offset == history_length) || the_history == 0)
+ ? (HIST_ENTRY *)NULL
+ : the_history[history_offset];
+}
+
+/* Back up history_offset to the previous history entry, and return
+ a pointer to that entry. If there is no previous entry then return
+ a NULL pointer. */
+HIST_ENTRY *
+previous_history ()
+{
+ return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL;
+}
+
+/* Move history_offset forward to the next history entry, and return
+ a pointer to that entry. If there is no next entry then return a
+ NULL pointer. */
+HIST_ENTRY *
+next_history ()
+{
+ return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset];
+}
+
+/* Return the history entry which is logically at OFFSET in the history array.
+ OFFSET is relative to history_base. */
+HIST_ENTRY *
+history_get (offset)
+ int offset;
+{
+ int local_index;
+
+ local_index = offset - history_base;
+ return (local_index >= history_length || local_index < 0 || the_history == 0)
+ ? (HIST_ENTRY *)NULL
+ : the_history[local_index];
+}
+
+time_t
+history_get_time (hist)
+ HIST_ENTRY *hist;
+{
+ char *ts;
+ time_t t;
+
+ if (hist == 0 || hist->timestamp == 0)
+ return 0;
+ ts = hist->timestamp;
+ if (ts[0] != history_comment_char)
+ return 0;
+ t = (time_t) atol (ts + 1); /* XXX - should use strtol() here */
+ return t;
+}
+
+static char *
+hist_inittime ()
+{
+ time_t t;
+ char ts[64], *ret;
+
+ t = (time_t) time ((time_t *)0);
+#if defined (HAVE_VSNPRINTF) /* assume snprintf if vsnprintf exists */
+ snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t);
+#else
+ sprintf (ts, "X%lu", (unsigned long) t);
+#endif
+ ret = savestring (ts);
+ ret[0] = history_comment_char;
+
+ return ret;
+}
+
+/* Place STRING at the end of the history list. The data field
+ is set to NULL. */
+void
+add_history (string)
+ const char *string;
+{
+ HIST_ENTRY *temp;
+
+ if (history_stifled && (history_length == history_max_entries))
+ {
+ register int i;
+
+ /* If the history is stifled, and history_length is zero,
+ and it equals history_max_entries, we don't save items. */
+ if (history_length == 0)
+ return;
+
+ /* If there is something in the slot, then remove it. */
+ if (the_history[0])
+ (void) free_history_entry (the_history[0]);
+
+ /* Copy the rest of the entries, moving down one slot. */
+ for (i = 0; i < history_length; i++)
+ the_history[i] = the_history[i + 1];
+
+ history_base++;
+ }
+ else
+ {
+ if (history_size == 0)
+ {
+ history_size = DEFAULT_HISTORY_GROW_SIZE;
+ the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
+ history_length = 1;
+ }
+ else
+ {
+ if (history_length == (history_size - 1))
+ {
+ history_size += DEFAULT_HISTORY_GROW_SIZE;
+ the_history = (HIST_ENTRY **)
+ xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
+ }
+ history_length++;
+ }
+ }
+
+ temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+ temp->line = savestring (string);
+ temp->data = (char *)NULL;
+
+ temp->timestamp = hist_inittime ();
+
+ the_history[history_length] = (HIST_ENTRY *)NULL;
+ the_history[history_length - 1] = temp;
+}
+
+/* Change the time stamp of the most recent history entry to STRING. */
+void
+add_history_time (string)
+ const char *string;
+{
+ HIST_ENTRY *hs;
+
+ hs = the_history[history_length - 1];
+ FREE (hs->timestamp);
+ hs->timestamp = savestring (string);
+}
+
+/* Free HIST and return the data so the calling application can free it
+ if necessary and desired. */
+histdata_t
+free_history_entry (hist)
+ HIST_ENTRY *hist;
+{
+ histdata_t x;
+
+ if (hist == 0)
+ return ((histdata_t) 0);
+ FREE (hist->line);
+ FREE (hist->timestamp);
+ x = hist->data;
+ free (hist);
+ return (x);
+}
+
+/* Make the history entry at WHICH have LINE and DATA. This returns
+ the old entry so you can dispose of the data. In the case of an
+ invalid WHICH, a NULL pointer is returned. */
+HIST_ENTRY *
+replace_history_entry (which, line, data)
+ int which;
+ const char *line;
+ histdata_t data;
+{
+ HIST_ENTRY *temp, *old_value;
+
+ if (which < 0 || which >= history_length)
+ return ((HIST_ENTRY *)NULL);
+
+ temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
+ old_value = the_history[which];
+
+ temp->line = savestring (line);
+ temp->data = data;
+ temp->timestamp = savestring (old_value->timestamp);
+ the_history[which] = temp;
+
+ return (old_value);
+}
+
+/* Replace the DATA in the specified history entries, replacing OLD with
+ NEW. WHICH says which one(s) to replace: WHICH == -1 means to replace
+ all of the history entries where entry->data == OLD; WHICH == -2 means
+ to replace the `newest' history entry where entry->data == OLD; and
+ WHICH >= 0 means to replace that particular history entry's data, as
+ long as it matches OLD. */
+void
+replace_history_data (which,old, new)
+ int which;
+ histdata_t *old, *new;
+{
+ HIST_ENTRY *entry;
+ register int i, last;
+
+ if (which < -2 || which >= history_length || history_length == 0 || the_history == 0)
+ return;
+
+ if (which >= 0)
+ {
+ entry = the_history[which];
+ if (entry && entry->data == old)
+ entry->data = new;
+ return;
+ }
+
+ last = -1;
+ for (i = 0; i < history_length; i++)
+ {
+ entry = the_history[i];
+ if (entry == 0)
+ continue;
+ if (entry->data == old)
+ {
+ last = i;
+ if (which == -1)
+ entry->data = new;
+ }
+ }
+ if (which == -2 && last >= 0)
+ {
+ entry = the_history[last];
+ entry->data = new; /* XXX - we don't check entry->old */
+ }
+}
+
+/* Remove history element WHICH from the history. The removed
+ element is returned to you so you can free the line, data,
+ and containing structure. */
+HIST_ENTRY *
+remove_history (which)
+ int which;
+{
+ HIST_ENTRY *return_value;
+ register int i;
+
+ if (which < 0 || which >= history_length || history_length == 0 || the_history == 0)
+ return ((HIST_ENTRY *)NULL);
+
+ return_value = the_history[which];
+
+ for (i = which; i < history_length; i++)
+ the_history[i] = the_history[i + 1];
+
+ history_length--;
+
+ return (return_value);
+}
+
+/* Stifle the history list, remembering only MAX number of lines. */
+void
+stifle_history (max)
+ int max;
+{
+ register int i, j;
+
+ if (max < 0)
+ max = 0;
+
+ if (history_length > max)
+ {
+ /* This loses because we cannot free the data. */
+ for (i = 0, j = history_length - max; i < j; i++)
+ free_history_entry (the_history[i]);
+
+ history_base = i;
+ for (j = 0, i = history_length - max; j < max; i++, j++)
+ the_history[j] = the_history[i];
+ the_history[j] = (HIST_ENTRY *)NULL;
+ history_length = j;
+ }
+
+ history_stifled = 1;
+ max_input_history = history_max_entries = max;
+}
+
+/* Stop stifling the history. This returns the previous maximum
+ number of history entries. The value is positive if the history
+ was stifled, negative if it wasn't. */
+int
+unstifle_history ()
+{
+ if (history_stifled)
+ {
+ history_stifled = 0;
+ return (history_max_entries);
+ }
+ else
+ return (-history_max_entries);
+}
+
+int
+history_is_stifled ()
+{
+ return (history_stifled);
+}
+
+void
+clear_history ()
+{
+ register int i;
+
+ /* This loses because we cannot free the data. */
+ for (i = 0; i < history_length; i++)
+ {
+ free_history_entry (the_history[i]);
+ the_history[i] = (HIST_ENTRY *)NULL;
+ }
+
+ history_offset = history_length = 0;
+}
#endif
extern int _rl_set_mark_at_pos PARAMS((int));
+/* undo.c */
+extern UNDO_LIST *_rl_copy_undo_entry PARAMS((UNDO_LIST *));
+extern UNDO_LIST *_rl_copy_undo_list PARAMS((UNDO_LIST *));
+
/* util.c */
extern int _rl_abort_internal PARAMS((void));
extern char *_rl_strindex PARAMS((const char *, const char *));
--- /dev/null
+/* rlprivate.h -- functions and variables global to the readline library,
+ but not intended for use by applications. */
+
+/* Copyright (C) 1999-2005 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library 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 2, or
+ (at your option) any later version.
+
+ The GNU Readline Library 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#if !defined (_RL_PRIVATE_H_)
+#define _RL_PRIVATE_H_
+
+#include "rlconf.h" /* for VISIBLE_STATS */
+#include "rlstdc.h"
+#include "posixjmp.h" /* defines procenv_t */
+
+/*************************************************************************
+ * *
+ * Global structs undocumented in texinfo manual and not in readline.h *
+ * *
+ *************************************************************************/
+/* search types */
+#define RL_SEARCH_ISEARCH 0x01 /* incremental search */
+#define RL_SEARCH_NSEARCH 0x02 /* non-incremental search */
+#define RL_SEARCH_CSEARCH 0x04 /* intra-line char search */
+
+/* search flags */
+#define SF_REVERSE 0x01
+#define SF_FOUND 0x02
+#define SF_FAILED 0x04
+
+typedef struct __rl_search_context
+{
+ int type;
+ int sflags;
+
+ char *search_string;
+ int search_string_index;
+ int search_string_size;
+
+ char **lines;
+ char *allocated_line;
+ int hlen;
+ int hindex;
+
+ int save_point;
+ int save_mark;
+ int save_line;
+ int last_found_line;
+ char *prev_line_found;
+
+ UNDO_LIST *save_undo_list;
+
+ int history_pos;
+ int direction;
+
+ int lastc;
+#if defined (HANDLE_MULTIBYTE)
+ char mb[MB_LEN_MAX];
+#endif
+
+ char *sline;
+ int sline_len;
+ int sline_index;
+
+ char *search_terminators;
+} _rl_search_cxt;
+
+/* Callback data for reading numeric arguments */
+#define NUM_SAWMINUS 0x01
+#define NUM_SAWDIGITS 0x02
+#define NUM_READONE 0x04
+
+typedef int _rl_arg_cxt;
+
+/* A context for reading key sequences longer than a single character when
+ using the callback interface. */
+#define KSEQ_DISPATCHED 0x01
+#define KSEQ_SUBSEQ 0x02
+#define KSEQ_RECURSIVE 0x04
+
+typedef struct __rl_keyseq_context
+{
+ int flags;
+ int subseq_arg;
+ int subseq_retval; /* XXX */
+ Keymap dmap;
+
+ Keymap oldmap;
+ int okey;
+ struct __rl_keyseq_context *ocxt;
+ int childval;
+} _rl_keyseq_cxt;
+
+ /* fill in more as needed */
+/* `Generic' callback data and functions */
+typedef struct __rl_callback_generic_arg
+{
+ int count;
+ int i1, i2;
+ /* add here as needed */
+} _rl_callback_generic_arg;
+
+typedef int _rl_callback_func_t PARAMS((_rl_callback_generic_arg *));
+
+/*************************************************************************
+ * *
+ * Global functions undocumented in texinfo manual and not in readline.h *
+ * *
+ *************************************************************************/
+
+/*************************************************************************
+ * *
+ * Global variables undocumented in texinfo manual and not in readline.h *
+ * *
+ *************************************************************************/
+
+/* complete.c */
+extern int rl_complete_with_tilde_expansion;
+#if defined (VISIBLE_STATS)
+extern int rl_visible_stats;
+#endif /* VISIBLE_STATS */
+
+/* readline.c */
+extern int rl_line_buffer_len;
+extern int rl_arg_sign;
+extern int rl_visible_prompt_length;
+extern int readline_echoing_p;
+extern int rl_key_sequence_length;
+extern int rl_byte_oriented;
+
+extern _rl_keyseq_cxt *_rl_kscxt;
+
+/* display.c */
+extern int rl_display_fixed;
+
+/* parens.c */
+extern int rl_blink_matching_paren;
+
+/*************************************************************************
+ * *
+ * Global functions and variables unsed and undocumented *
+ * *
+ *************************************************************************/
+
+/* kill.c */
+extern int rl_set_retained_kills PARAMS((int));
+
+/* terminal.c */
+extern void _rl_set_screen_size PARAMS((int, int));
+
+/* undo.c */
+extern int _rl_fix_last_undo_of_type PARAMS((int, int, int));
+
+/* util.c */
+extern char *_rl_savestring PARAMS((const char *));
+
+/*************************************************************************
+ * *
+ * Functions and variables private to the readline library *
+ * *
+ *************************************************************************/
+
+/* NOTE: Functions and variables prefixed with `_rl_' are
+ pseudo-global: they are global so they can be shared
+ between files in the readline library, but are not intended
+ to be visible to readline callers. */
+
+/*************************************************************************
+ * Undocumented private functions *
+ *************************************************************************/
+
+#if defined(READLINE_CALLBACKS)
+
+/* readline.c */
+extern void readline_internal_setup PARAMS((void));
+extern char *readline_internal_teardown PARAMS((int));
+extern int readline_internal_char PARAMS((void));
+
+extern _rl_keyseq_cxt *_rl_keyseq_cxt_alloc PARAMS((void));
+extern void _rl_keyseq_cxt_dispose PARAMS((_rl_keyseq_cxt *));
+extern void _rl_keyseq_chain_dispose PARAMS((void));
+
+extern int _rl_dispatch_callback PARAMS((_rl_keyseq_cxt *));
+
+/* callback.c */
+extern _rl_callback_generic_arg *_rl_callback_data_alloc PARAMS((int));
+extern void _rl_callback_data_dispose PARAMS((_rl_callback_generic_arg *));
+
+#endif /* READLINE_CALLBACKS */
+
+/* bind.c */
+
+/* complete.c */
+extern char _rl_find_completion_word PARAMS((int *, int *));
+extern void _rl_free_match_list PARAMS((char **));
+
+/* display.c */
+extern char *_rl_strip_prompt PARAMS((char *));
+extern void _rl_move_cursor_relative PARAMS((int, const char *));
+extern void _rl_move_vert PARAMS((int));
+extern void _rl_save_prompt PARAMS((void));
+extern void _rl_restore_prompt PARAMS((void));
+extern char *_rl_make_prompt_for_search PARAMS((int));
+extern void _rl_erase_at_end_of_line PARAMS((int));
+extern void _rl_clear_to_eol PARAMS((int));
+extern void _rl_clear_screen PARAMS((void));
+extern void _rl_update_final PARAMS((void));
+extern void _rl_redisplay_after_sigwinch PARAMS((void));
+extern void _rl_clean_up_for_exit PARAMS((void));
+extern void _rl_erase_entire_line PARAMS((void));
+extern int _rl_current_display_line PARAMS((void));
+
+/* input.c */
+extern int _rl_any_typein PARAMS((void));
+extern int _rl_input_available PARAMS((void));
+extern int _rl_input_queued PARAMS((int));
+extern void _rl_insert_typein PARAMS((int));
+extern int _rl_unget_char PARAMS((int));
+extern int _rl_pushed_input_available PARAMS((void));
+
+/* isearch.c */
+extern _rl_search_cxt *_rl_scxt_alloc PARAMS((int, int));
+extern void _rl_scxt_dispose PARAMS((_rl_search_cxt *, int));
+
+extern int _rl_isearch_dispatch PARAMS((_rl_search_cxt *, int));
+extern int _rl_isearch_callback PARAMS((_rl_search_cxt *));
+
+extern int _rl_search_getchar PARAMS((_rl_search_cxt *));
+
+/* macro.c */
+extern void _rl_with_macro_input PARAMS((char *));
+extern int _rl_next_macro_key PARAMS((void));
+extern void _rl_push_executing_macro PARAMS((void));
+extern void _rl_pop_executing_macro PARAMS((void));
+extern void _rl_add_macro_char PARAMS((int));
+extern void _rl_kill_kbd_macro PARAMS((void));
+
+/* misc.c */
+extern int _rl_arg_overflow PARAMS((void));
+extern void _rl_arg_init PARAMS((void));
+extern int _rl_arg_getchar PARAMS((void));
+extern int _rl_arg_callback PARAMS((_rl_arg_cxt));
+extern void _rl_reset_argument PARAMS((void));
+
+extern void _rl_start_using_history PARAMS((void));
+extern int _rl_free_saved_history_line PARAMS((void));
+extern void _rl_set_insert_mode PARAMS((int, int));
+
+/* nls.c */
+extern int _rl_init_eightbit PARAMS((void));
+
+/* parens.c */
+extern void _rl_enable_paren_matching PARAMS((int));
+
+/* readline.c */
+extern void _rl_init_line_state PARAMS((void));
+extern void _rl_set_the_line PARAMS((void));
+extern int _rl_dispatch PARAMS((int, Keymap));
+extern int _rl_dispatch_subseq PARAMS((int, Keymap, int));
+extern void _rl_internal_char_cleanup PARAMS((void));
+
+/* rltty.c */
+extern int _rl_disable_tty_signals PARAMS((void));
+extern int _rl_restore_tty_signals PARAMS((void));
+
+/* search.c */
+extern int _rl_nsearch_callback PARAMS((_rl_search_cxt *));
+
+/* terminal.c */
+extern void _rl_get_screen_size PARAMS((int, int));
+extern int _rl_init_terminal_io PARAMS((const char *));
+#ifdef _MINIX
+extern void _rl_output_character_function PARAMS((int));
+#else
+extern int _rl_output_character_function PARAMS((int));
+#endif
+extern void _rl_output_some_chars PARAMS((const char *, int));
+extern int _rl_backspace PARAMS((int));
+extern void _rl_enable_meta_key PARAMS((void));
+extern void _rl_control_keypad PARAMS((int));
+extern void _rl_set_cursor PARAMS((int, int));
+
+/* text.c */
+extern void _rl_fix_point PARAMS((int));
+extern int _rl_replace_text PARAMS((const char *, int, int));
+extern int _rl_insert_char PARAMS((int, int));
+extern int _rl_overwrite_char PARAMS((int, int));
+extern int _rl_overwrite_rubout PARAMS((int, int));
+extern int _rl_rubout_char PARAMS((int, int));
+#if defined (HANDLE_MULTIBYTE)
+extern int _rl_char_search_internal PARAMS((int, int, char *, int));
+#else
+extern int _rl_char_search_internal PARAMS((int, int, int));
+#endif
+extern int _rl_set_mark_at_pos PARAMS((int));
+
+/* util.c */
+extern int _rl_abort_internal PARAMS((void));
+extern char *_rl_strindex PARAMS((const char *, const char *));
+extern int _rl_qsort_string_compare PARAMS((char **, char **));
+extern int (_rl_uppercase_p) PARAMS((int));
+extern int (_rl_lowercase_p) PARAMS((int));
+extern int (_rl_pure_alphabetic) PARAMS((int));
+extern int (_rl_digit_p) PARAMS((int));
+extern int (_rl_to_lower) PARAMS((int));
+extern int (_rl_to_upper) PARAMS((int));
+extern int (_rl_digit_value) PARAMS((int));
+
+/* vi_mode.c */
+extern void _rl_vi_initialize_line PARAMS((void));
+extern void _rl_vi_reset_last PARAMS((void));
+extern void _rl_vi_set_last PARAMS((int, int, int));
+extern int _rl_vi_textmod_command PARAMS((int));
+extern void _rl_vi_done_inserting PARAMS((void));
+
+/*************************************************************************
+ * Undocumented private variables *
+ *************************************************************************/
+
+/* bind.c */
+extern const char *_rl_possible_control_prefixes[];
+extern const char *_rl_possible_meta_prefixes[];
+
+/* callback.c */
+extern _rl_callback_func_t *_rl_callback_func;
+extern _rl_callback_generic_arg *_rl_callback_data;
+
+/* complete.c */
+extern int _rl_complete_show_all;
+extern int _rl_complete_show_unmodified;
+extern int _rl_complete_mark_directories;
+extern int _rl_complete_mark_symlink_dirs;
+extern int _rl_print_completions_horizontally;
+extern int _rl_completion_case_fold;
+extern int _rl_match_hidden_files;
+extern int _rl_page_completions;
+
+/* display.c */
+extern int _rl_vis_botlin;
+extern int _rl_last_c_pos;
+extern int _rl_suppress_redisplay;
+extern int _rl_want_redisplay;
+extern char *rl_display_prompt;
+
+/* isearch.c */
+extern char *_rl_isearch_terminators;
+
+extern _rl_search_cxt *_rl_iscxt;
+
+/* macro.c */
+extern char *_rl_executing_macro;
+
+/* misc.c */
+extern int _rl_history_preserve_point;
+extern int _rl_history_saved_point;
+
+extern _rl_arg_cxt _rl_argcxt;
+
+/* readline.c */
+extern int _rl_horizontal_scroll_mode;
+extern int _rl_mark_modified_lines;
+extern int _rl_bell_preference;
+extern int _rl_meta_flag;
+extern int _rl_convert_meta_chars_to_ascii;
+extern int _rl_output_meta_chars;
+extern int _rl_bind_stty_chars;
+extern char *_rl_comment_begin;
+extern unsigned char _rl_parsing_conditionalized_out;
+extern Keymap _rl_keymap;
+extern FILE *_rl_in_stream;
+extern FILE *_rl_out_stream;
+extern int _rl_last_command_was_kill;
+extern int _rl_eof_char;
+extern procenv_t readline_top_level;
+
+/* search.c */
+extern _rl_search_cxt *_rl_nscxt;
+
+/* terminal.c */
+extern int _rl_enable_keypad;
+extern int _rl_enable_meta;
+extern char *_rl_term_clreol;
+extern char *_rl_term_clrpag;
+extern char *_rl_term_im;
+extern char *_rl_term_ic;
+extern char *_rl_term_ei;
+extern char *_rl_term_DC;
+extern char *_rl_term_up;
+extern char *_rl_term_dc;
+extern char *_rl_term_cr;
+extern char *_rl_term_IC;
+extern int _rl_screenheight;
+extern int _rl_screenwidth;
+extern int _rl_screenchars;
+extern int _rl_terminal_can_insert;
+extern int _rl_term_autowrap;
+
+/* undo.c */
+extern int _rl_doing_an_undo;
+extern int _rl_undo_group_level;
+
+/* vi_mode.c */
+extern int _rl_vi_last_command;
+
+#endif /* _RL_PRIVATE_H_ */
/* readline.c -- a general facility for reading lines of input
with emacs style editing and completion. */
-/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
+/* Copyright (C) 1987, 1989, 1992, 2006 Free Software Foundation, Inc.
This file is part of the GNU Readline Library, a library for
reading lines of text with interactive input and history editing.
#include "rlprivate.h"
#include "xmalloc.h"
+extern void replace_history_data PARAMS((int, histdata_t *, histdata_t *));
+
/* Non-zero tells rl_delete_text and rl_insert_text to not add to
the undo list. */
int _rl_doing_an_undo = 0;
/* */
/* **************************************************************** */
-/* Remember how to undo something. Concatenate some undos if that
- seems right. */
-void
-rl_add_undo (what, start, end, text)
+static UNDO_LIST *
+alloc_undo_entry (what, start, end, text)
enum undo_code what;
int start, end;
char *text;
{
- UNDO_LIST *temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
+ UNDO_LIST *temp;
+
+ temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
temp->what = what;
temp->start = start;
temp->end = end;
temp->text = text;
+
+ temp->next = (UNDO_LIST *)NULL;
+ return temp;
+}
+
+/* Remember how to undo something. Concatenate some undos if that
+ seems right. */
+void
+rl_add_undo (what, start, end, text)
+ enum undo_code what;
+ int start, end;
+ char *text;
+{
+ UNDO_LIST *temp;
+
+ temp = alloc_undo_entry (what, start, end, text);
temp->next = rl_undo_list;
rl_undo_list = temp;
}
void
rl_free_undo_list ()
{
+ UNDO_LIST *release, *orig_list;
+
+ orig_list = rl_undo_list;
while (rl_undo_list)
{
- UNDO_LIST *release = rl_undo_list;
+ release = rl_undo_list;
rl_undo_list = rl_undo_list->next;
if (release->what == UNDO_DELETE)
free (release);
}
rl_undo_list = (UNDO_LIST *)NULL;
+ replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
+}
+
+UNDO_LIST *
+_rl_copy_undo_entry (entry)
+ UNDO_LIST *entry;
+{
+ UNDO_LIST *new;
+
+ new = alloc_undo_entry (entry->what, entry->start, entry->end, (char *)NULL);
+ new->text = entry->text ? savestring (entry->text) : 0;
+ return new;
+}
+
+UNDO_LIST *
+_rl_copy_undo_list (head)
+ UNDO_LIST *head;
+{
+ UNDO_LIST *list, *new, *roving, *c;
+
+ list = head;
+ new = 0;
+ while (list)
+ {
+ c = _rl_copy_undo_entry (list);
+ if (new == 0)
+ roving = new = c;
+ else
+ {
+ roving->next = c;
+ roving = roving->next;
+ }
+ list = list->next;
+ }
+
+ roving->next = 0;
+ return new;
}
/* Undo the next thing in the list. Return 0 if there
release = rl_undo_list;
rl_undo_list = rl_undo_list->next;
+ replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
+
free (release);
}
while (waiting_for_begin);
--- /dev/null
+/* readline.c -- a general facility for reading lines of input
+ with emacs style editing and completion. */
+
+/* Copyright (C) 1987, 1989, 1992, 2006 Free Software Foundation, Inc.
+
+ This file is part of the GNU Readline Library, a library for
+ reading lines of text with interactive input and history editing.
+
+ The GNU Readline Library 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 2, or
+ (at your option) any later version.
+
+ The GNU Readline Library 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.
+
+ The GNU General Public License is often shipped with GNU software, and
+ is generally kept in a file called COPYING or LICENSE. If you do not
+ have a copy of the license, write to the Free Software Foundation,
+ 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+#define READLINE_LIBRARY
+
+#if defined (HAVE_CONFIG_H)
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h> /* for _POSIX_VERSION */
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STDLIB_H)
+# include <stdlib.h>
+#else
+# include "ansi_stdlib.h"
+#endif /* HAVE_STDLIB_H */
+
+#include <stdio.h>
+
+/* System-specific feature definitions and include files. */
+#include "rldefs.h"
+
+/* Some standard library routines. */
+#include "readline.h"
+#include "history.h"
+
+#include "rlprivate.h"
+#include "xmalloc.h"
+
+extern void replace_history_data PARAMS((int, histdata_t *, histdata_t *));
+
+/* Non-zero tells rl_delete_text and rl_insert_text to not add to
+ the undo list. */
+int _rl_doing_an_undo = 0;
+
+/* How many unclosed undo groups we currently have. */
+int _rl_undo_group_level = 0;
+
+/* The current undo list for THE_LINE. */
+UNDO_LIST *rl_undo_list = (UNDO_LIST *)NULL;
+
+/* **************************************************************** */
+/* */
+/* Undo, and Undoing */
+/* */
+/* **************************************************************** */
+
+static UNDO_LIST *
+alloc_undo_entry (what, start, end, text)
+ enum undo_code what;
+ int start, end;
+ char *text;
+{
+ UNDO_LIST *temp;
+
+ temp = (UNDO_LIST *)xmalloc (sizeof (UNDO_LIST));
+ temp->what = what;
+ temp->start = start;
+ temp->end = end;
+ temp->text = text;
+
+ temp->next = (UNDO_LIST *)NULL;
+ return temp;
+}
+
+/* Remember how to undo something. Concatenate some undos if that
+ seems right. */
+void
+rl_add_undo (what, start, end, text)
+ enum undo_code what;
+ int start, end;
+ char *text;
+{
+ UNDO_LIST *temp;
+
+ temp = alloc_undo_entry (what, start, end, text);
+ temp->next = rl_undo_list;
+ rl_undo_list = temp;
+}
+
+/* Free the existing undo list. */
+void
+rl_free_undo_list ()
+{
+ UNDO_LIST *release, *orig_list;
+
+ orig_list = rl_undo_list;
+ while (rl_undo_list)
+ {
+ release = rl_undo_list;
+ rl_undo_list = rl_undo_list->next;
+
+ if (release->what == UNDO_DELETE)
+ free (release->text);
+
+ free (release);
+ }
+ rl_undo_list = (UNDO_LIST *)NULL;
+ replace_history_data (-1, (histdata_t *)orig_list, (histdata_t *)NULL);
+}
+
+/* Undo the next thing in the list. Return 0 if there
+ is nothing to undo, or non-zero if there was. */
+int
+rl_do_undo ()
+{
+ UNDO_LIST *release;
+ int waiting_for_begin, start, end;
+
+#define TRANS(i) ((i) == -1 ? rl_point : ((i) == -2 ? rl_end : (i)))
+
+ start = end = waiting_for_begin = 0;
+ do
+ {
+ if (!rl_undo_list)
+ return (0);
+
+ _rl_doing_an_undo = 1;
+ RL_SETSTATE(RL_STATE_UNDOING);
+
+ /* To better support vi-mode, a start or end value of -1 means
+ rl_point, and a value of -2 means rl_end. */
+ if (rl_undo_list->what == UNDO_DELETE || rl_undo_list->what == UNDO_INSERT)
+ {
+ start = TRANS (rl_undo_list->start);
+ end = TRANS (rl_undo_list->end);
+ }
+
+ switch (rl_undo_list->what)
+ {
+ /* Undoing deletes means inserting some text. */
+ case UNDO_DELETE:
+ rl_point = start;
+ rl_insert_text (rl_undo_list->text);
+ free (rl_undo_list->text);
+ break;
+
+ /* Undoing inserts means deleting some text. */
+ case UNDO_INSERT:
+ rl_delete_text (start, end);
+ rl_point = start;
+ break;
+
+ /* Undoing an END means undoing everything 'til we get to a BEGIN. */
+ case UNDO_END:
+ waiting_for_begin++;
+ break;
+
+ /* Undoing a BEGIN means that we are done with this group. */
+ case UNDO_BEGIN:
+ if (waiting_for_begin)
+ waiting_for_begin--;
+ else
+ rl_ding ();
+ break;
+ }
+
+ _rl_doing_an_undo = 0;
+ RL_UNSETSTATE(RL_STATE_UNDOING);
+
+ release = rl_undo_list;
+ rl_undo_list = rl_undo_list->next;
+ replace_history_data (-1, (histdata_t *)release, (histdata_t *)rl_undo_list);
+
+ free (release);
+ }
+ while (waiting_for_begin);
+
+ return (1);
+}
+#undef TRANS
+
+int
+_rl_fix_last_undo_of_type (type, start, end)
+ int type, start, end;
+{
+ UNDO_LIST *rl;
+
+ for (rl = rl_undo_list; rl; rl = rl->next)
+ {
+ if (rl->what == type)
+ {
+ rl->start = start;
+ rl->end = end;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Begin a group. Subsequent undos are undone as an atomic operation. */
+int
+rl_begin_undo_group ()
+{
+ rl_add_undo (UNDO_BEGIN, 0, 0, 0);
+ _rl_undo_group_level++;
+ return 0;
+}
+
+/* End an undo group started with rl_begin_undo_group (). */
+int
+rl_end_undo_group ()
+{
+ rl_add_undo (UNDO_END, 0, 0, 0);
+ _rl_undo_group_level--;
+ return 0;
+}
+
+/* Save an undo entry for the text from START to END. */
+int
+rl_modifying (start, end)
+ int start, end;
+{
+ if (start > end)
+ {
+ SWAP (start, end);
+ }
+
+ if (start != end)
+ {
+ char *temp = rl_copy_text (start, end);
+ rl_begin_undo_group ();
+ rl_add_undo (UNDO_DELETE, start, end, temp);
+ rl_add_undo (UNDO_INSERT, start, end, (char *)NULL);
+ rl_end_undo_group ();
+ }
+ return 0;
+}
+
+/* Revert the current line to its previous state. */
+int
+rl_revert_line (count, key)
+ int count, key;
+{
+ if (!rl_undo_list)
+ rl_ding ();
+ else
+ {
+ while (rl_undo_list)
+ rl_do_undo ();
+#if defined (VI_MODE)
+ if (rl_editing_mode == vi_mode)
+ rl_point = rl_mark = 0; /* rl_end should be set correctly */
+#endif
+ }
+
+ return 0;
+}
+
+/* Do some undoing of things that were done. */
+int
+rl_undo_command (count, key)
+ int count, key;
+{
+ if (count < 0)
+ return 0; /* Nothing to do. */
+
+ while (count)
+ {
+ if (rl_do_undo ())
+ count--;
+ else
+ {
+ rl_ding ();
+ break;
+ }
+ }
+ return 0;
+}
return ((lc_all == 0 || *lc_all == 0) ? reset_locale_vars () : 0);
}
+/* Set default values for LANG and LC_ALL. Default values for all other
+ locale-related variables depend on these. */
+void
+set_default_lang ()
+{
+ char *v;
+
+ v = get_string_value ("LC_ALL");
+ set_locale_var ("LC_ALL", v);
+
+ v = get_string_value ("LANG");
+ set_lang ("LANG", v);
+}
+
/* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE).
The precedence is as POSIX.2 specifies: LC_ALL has precedence over
the specific locale variables, and LANG, if set, is used as the default. */
if (locale == 0 || *locale == 0)
locale = lang;
if (locale == 0 || *locale == 0)
- locale = default_locale; /* system-dependent; not really portable */
+ locale = default_locale; /* system-dependent; not really portable. should it be "C"? */
return (locale);
}
reset_locale_vars ()
{
#if defined (HAVE_SETLOCALE)
- char *locale;
-
- locale = lang;
- if (locale == 0 || *locale == '\0')
- locale = default_locale;
- if (setlocale (LC_ALL, locale) == 0)
+ if (lang == 0 || *lang == '\0')
+ maybe_make_export_env (); /* trust that this will change environment for setlocale */
+ if (setlocale (LC_ALL, lang ? lang : "") == 0)
return 0;
# if defined (LC_CTYPE)
--- /dev/null
+/* locale.c - Miscellaneous internationalization functions. */
+
+/* Copyright (C) 1996-2004 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 2, 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; see the file COPYING. If not, write to the Free Software
+ Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#include "config.h"
+
+#include "bashtypes.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "bashintl.h"
+#include "bashansi.h"
+#include <stdio.h>
+#include "chartypes.h"
+
+#include "shell.h"
+#include "input.h" /* For bash_input */
+
+extern int dump_translatable_strings, dump_po_strings;
+
+/* The current locale when the program begins */
+static char *default_locale;
+
+/* The current domain for textdomain(3). */
+static char *default_domain;
+static char *default_dir;
+
+/* tracks the value of LC_ALL; used to override values for other locale
+ categories */
+static char *lc_all;
+
+/* tracks the value of LC_ALL; used to provide defaults for locale
+ categories */
+static char *lang;
+
+/* Called to reset all of the locale variables to their appropriate values
+ if (and only if) LC_ALL has not been assigned a value. */
+static int reset_locale_vars __P((void));
+
+static void locale_setblanks __P((void));
+
+/* Set the value of default_locale and make the current locale the
+ system default locale. This should be called very early in main(). */
+void
+set_default_locale ()
+{
+#if defined (HAVE_SETLOCALE)
+ default_locale = setlocale (LC_ALL, "");
+ if (default_locale)
+ default_locale = savestring (default_locale);
+itrace("default locale = %s", default_locale ? default_locale : "NULL");
+#endif /* HAVE_SETLOCALE */
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+}
+
+/* Set default values for LC_CTYPE, LC_COLLATE, LC_MESSAGES, LC_NUMERIC and
+ LC_TIME if they are not specified in the environment, but LC_ALL is. This
+ should be called from main() after parsing the environment. */
+void
+set_default_locale_vars ()
+{
+ char *val;
+ int r;
+
+#if defined (HAVE_SETLOCALE)
+
+# if defined (LC_CTYPE)
+ val = get_string_value ("LC_CTYPE");
+ if (val == 0 && lc_all && *lc_all)
+ {
+ setlocale (LC_CTYPE, lc_all);
+ locale_setblanks ();
+ }
+# endif
+
+# if defined (LC_COLLATE)
+ val = get_string_value ("LC_COLLATE");
+ if (val == 0 && lc_all && *lc_all)
+ setlocale (LC_COLLATE, lc_all);
+# endif /* LC_COLLATE */
+
+# if defined (LC_MESSAGES)
+ val = get_string_value ("LC_MESSAGES");
+ if (val == 0 && lc_all && *lc_all)
+ setlocale (LC_MESSAGES, lc_all);
+# endif /* LC_MESSAGES */
+
+# if defined (LC_NUMERIC)
+ val = get_string_value ("LC_NUMERIC");
+ if (val == 0 && lc_all && *lc_all)
+ setlocale (LC_NUMERIC, lc_all);
+# endif /* LC_NUMERIC */
+
+# if defined (LC_TIME)
+ val = get_string_value ("LC_TIME");
+ if (val == 0 && lc_all && *lc_all)
+ setlocale (LC_TIME, lc_all);
+# endif /* LC_TIME */
+
+#endif /* HAVE_SETLOCALE */
+
+ val = get_string_value ("TEXTDOMAIN");
+ if (val && *val)
+ {
+ FREE (default_domain);
+ default_domain = savestring (val);
+#if 0
+ /* Don't want to override the shell's textdomain as the default */
+ textdomain (default_domain);
+#endif
+ }
+
+ val = get_string_value ("TEXTDOMAINDIR");
+ if (val && *val)
+ {
+ FREE (default_dir);
+ default_dir = savestring (val);
+ if (default_domain && *default_domain)
+ bindtextdomain (default_domain, default_dir);
+ }
+}
+
+/* Set one of the locale categories (specified by VAR) to VALUE. Returns 1
+ if successful, 0 otherwise. */
+int
+set_locale_var (var, value)
+ char *var, *value;
+{
+ int r;
+
+ if (var[0] == 'T' && var[10] == 0) /* TEXTDOMAIN */
+ {
+ FREE (default_domain);
+ default_domain = value ? savestring (value) : (char *)NULL;
+#if 0
+ /* Don't want to override the shell's textdomain as the default */
+ textdomain (default_domain);
+#endif
+ return (1);
+ }
+ else if (var[0] == 'T') /* TEXTDOMAINDIR */
+ {
+ FREE (default_dir);
+ default_dir = value ? savestring (value) : (char *)NULL;
+ if (default_domain && *default_domain)
+ bindtextdomain (default_domain, default_dir);
+ return (1);
+ }
+
+ /* var[0] == 'L' && var[1] == 'C' && var[2] == '_' */
+
+ else if (var[3] == 'A') /* LC_ALL */
+ {
+ FREE (lc_all);
+ if (value)
+ lc_all = savestring (value);
+ else
+ {
+ lc_all = (char *)xmalloc (1);
+ lc_all[0] = '\0';
+ }
+#if defined (HAVE_SETLOCALE)
+ r = *lc_all ? (setlocale (LC_ALL, lc_all) != 0) : reset_locale_vars ();
+ locale_setblanks ();
+ return r;
+#else
+ return (1);
+#endif
+ }
+
+#if defined (HAVE_SETLOCALE)
+ else if (var[3] == 'C' && var[4] == 'T') /* LC_CTYPE */
+ {
+# if defined (LC_CTYPE)
+ if (lc_all == 0 || *lc_all == '\0')
+ {
+ r = (setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE")) != 0);
+ locale_setblanks ();
+ return r;
+ }
+# endif
+ }
+ else if (var[3] == 'C' && var[4] == 'O') /* LC_COLLATE */
+ {
+# if defined (LC_COLLATE)
+ if (lc_all == 0 || *lc_all == '\0')
+ return (setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE")) != 0);
+# endif /* LC_COLLATE */
+ }
+ else if (var[3] == 'M' && var[4] == 'E') /* LC_MESSAGES */
+ {
+# if defined (LC_MESSAGES)
+ if (lc_all == 0 || *lc_all == '\0')
+ return (setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES")) != 0);
+# endif /* LC_MESSAGES */
+ }
+ else if (var[3] == 'N' && var[4] == 'U') /* LC_NUMERIC */
+ {
+# if defined (LC_NUMERIC)
+ if (lc_all == 0 || *lc_all == '\0')
+ return (setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC")) != 0);
+# endif /* LC_NUMERIC */
+ }
+ else if (var[3] == 'T' && var[4] == 'I') /* LC_TIME */
+ {
+# if defined (LC_TIME)
+ if (lc_all == 0 || *lc_all == '\0')
+ return (setlocale (LC_TIME, get_locale_var ("LC_TIME")) != 0);
+# endif /* LC_TIME */
+ }
+#endif /* HAVE_SETLOCALE */
+
+
+ return (0);
+}
+
+/* Called when LANG is assigned a value. Tracks value in `lang'. Calls
+ reset_locale_vars() to reset any default values if LC_ALL is unset or
+ null. */
+int
+set_lang (var, value)
+ char *var, *value;
+{
+ FREE (lang);
+ if (value)
+ lang = savestring (value);
+ else
+ {
+ lang = (char *)xmalloc (1);
+ lang[0] = '\0';
+ }
+
+ return ((lc_all == 0 || *lc_all == 0) ? reset_locale_vars () : 0);
+}
+
+/* Set default values for LANG and LC_ALL. Default values for all other
+ locale-related variables depend on these. */
+void
+set_default_lang ()
+{
+ char *v;
+
+ v = get_string_value ("LC_ALL");
+ set_locale_var ("LC_ALL", v);
+
+ v = get_string_value ("LANG");
+ set_lang ("LANG", v);
+}
+
+/* Get the value of one of the locale variables (LC_MESSAGES, LC_CTYPE).
+ The precedence is as POSIX.2 specifies: LC_ALL has precedence over
+ the specific locale variables, and LANG, if set, is used as the default. */
+char *
+get_locale_var (var)
+ char *var;
+{
+ char *locale;
+
+ locale = lc_all;
+
+ if (locale == 0 || *locale == 0)
+ locale = get_string_value (var);
+ if (locale == 0 || *locale == 0)
+ locale = lang;
+ if (locale == 0 || *locale == 0)
+ locale = default_locale; /* system-dependent; not really portable. should it be "C"? */
+
+ return (locale);
+}
+
+/* Called to reset all of the locale variables to their appropriate values
+ if (and only if) LC_ALL has not been assigned a value. DO NOT CALL THIS
+ IF LC_ALL HAS BEEN ASSIGNED A VALUE. */
+static int
+reset_locale_vars ()
+{
+#if defined (HAVE_SETLOCALE)
+ char *locale;
+
+ if (lang == 0 || *lang == '\0')
+ maybe_make_export_env (); /* trust that this will change environment for setlocale */
+ if (setlocale (LC_ALL, lang ? lang : "") == 0)
+ return 0;
+
+itrace("setlocale(LC_ALL, \"%s\")", lang ? lang : "");
+locale = setlocale(LC_ALL, (char *)NULL);
+itrace("current locale = %s", locale ? locale : "NULL");
+
+# if defined (LC_CTYPE)
+ setlocale (LC_CTYPE, get_locale_var ("LC_CTYPE"));
+# endif
+# if defined (LC_COLLATE)
+ setlocale (LC_COLLATE, get_locale_var ("LC_COLLATE"));
+# endif
+# if defined (LC_MESSAGES)
+ setlocale (LC_MESSAGES, get_locale_var ("LC_MESSAGES"));
+# endif
+# if defined (LC_NUMERIC)
+ setlocale (LC_NUMERIC, get_locale_var ("LC_NUMERIC"));
+# endif
+# if defined (LC_TIME)
+ setlocale (LC_TIME, get_locale_var ("LC_TIME"));
+# endif
+
+ locale_setblanks ();
+
+#endif
+ return 1;
+}
+
+/* Translate the contents of STRING, a $"..." quoted string, according
+ to the current locale. In the `C' or `POSIX' locale, or if gettext()
+ is not available, the passed string is returned unchanged. The
+ length of the translated string is returned in LENP, if non-null. */
+char *
+localetrans (string, len, lenp)
+ char *string;
+ int len, *lenp;
+{
+ char *locale, *t;
+ char *translated;
+ int tlen;
+
+ /* Don't try to translate null strings. */
+ if (string == 0 || *string == 0)
+ {
+ if (lenp)
+ *lenp = 0;
+ return ((char *)NULL);
+ }
+
+ locale = get_locale_var ("LC_MESSAGES");
+
+ /* If we don't have setlocale() or the current locale is `C' or `POSIX',
+ just return the string. If we don't have gettext(), there's no use
+ doing anything else. */
+ if (locale == 0 || locale[0] == '\0' ||
+ (locale[0] == 'C' && locale[1] == '\0') || STREQ (locale, "POSIX"))
+ {
+ t = (char *)xmalloc (len + 1);
+ strcpy (t, string);
+ if (lenp)
+ *lenp = len;
+ return (t);
+ }
+
+ /* Now try to translate it. */
+ if (default_domain && *default_domain)
+ translated = dgettext (default_domain, string);
+ else
+ translated = string;
+
+ if (translated == string) /* gettext returns its argument if untranslatable */
+ {
+ t = (char *)xmalloc (len + 1);
+ strcpy (t, string);
+ if (lenp)
+ *lenp = len;
+ }
+ else
+ {
+ tlen = strlen (translated);
+ t = (char *)xmalloc (tlen + 1);
+ strcpy (t, translated);
+ if (lenp)
+ *lenp = tlen;
+ }
+ return (t);
+}
+
+/* Change a bash string into a string suitable for inclusion in a `po' file.
+ This backslash-escapes `"' and `\' and changes newlines into \\\n"\n". */
+char *
+mk_msgstr (string, foundnlp)
+ char *string;
+ int *foundnlp;
+{
+ register int c, len;
+ char *result, *r, *s;
+
+ for (len = 0, s = string; s && *s; s++)
+ {
+ len++;
+ if (*s == '"' || *s == '\\')
+ len++;
+ else if (*s == '\n')
+ len += 5;
+ }
+
+ r = result = (char *)xmalloc (len + 3);
+ *r++ = '"';
+
+ for (s = string; s && (c = *s); s++)
+ {
+ if (c == '\n') /* <NL> -> \n"<NL>" */
+ {
+ *r++ = '\\';
+ *r++ = 'n';
+ *r++ = '"';
+ *r++ = '\n';
+ *r++ = '"';
+ if (foundnlp)
+ *foundnlp = 1;
+ continue;
+ }
+ if (c == '"' || c == '\\')
+ *r++ = '\\';
+ *r++ = c;
+ }
+
+ *r++ = '"';
+ *r++ = '\0';
+
+ return result;
+}
+
+/* $"..." -- Translate the portion of STRING between START and END
+ according to current locale using gettext (if available) and return
+ the result. The caller will take care of leaving the quotes intact.
+ The string will be left without the leading `$' by the caller.
+ If translation is performed, the translated string will be double-quoted
+ by the caller. The length of the translated string is returned in LENP,
+ if non-null. */
+char *
+localeexpand (string, start, end, lineno, lenp)
+ char *string;
+ int start, end, lineno, *lenp;
+{
+ int len, tlen, foundnl;
+ char *temp, *t, *t2;
+
+ temp = (char *)xmalloc (end - start + 1);
+ for (tlen = 0, len = start; len < end; )
+ temp[tlen++] = string[len++];
+ temp[tlen] = '\0';
+
+ /* If we're just dumping translatable strings, don't do anything with the
+ string itself, but if we're dumping in `po' file format, convert it into
+ a form more palatable to gettext(3) and friends by quoting `"' and `\'
+ with backslashes and converting <NL> into `\n"<NL>"'. If we find a
+ newline in TEMP, we first output a `msgid ""' line and then the
+ translated string; otherwise we output the `msgid' and translated
+ string all on one line. */
+ if (dump_translatable_strings)
+ {
+ if (dump_po_strings)
+ {
+ foundnl = 0;
+ t = mk_msgstr (temp, &foundnl);
+ t2 = foundnl ? "\"\"\n" : "";
+
+ printf ("#: %s:%d\nmsgid %s%s\nmsgstr \"\"\n",
+ yy_input_name (), lineno, t2, t);
+ free (t);
+ }
+ else
+ printf ("\"%s\"\n", temp);
+
+ if (lenp)
+ *lenp = tlen;
+ return (temp);
+ }
+ else if (*temp)
+ {
+ t = localetrans (temp, tlen, &len);
+ free (temp);
+ if (lenp)
+ *lenp = len;
+ return (t);
+ }
+ else
+ {
+ if (lenp)
+ *lenp = 0;
+ return (temp);
+ }
+}
+
+/* Set every character in the <blank> character class to be a shell break
+ character for the lexical analyzer when the locale changes. */
+static void
+locale_setblanks ()
+{
+ int x;
+
+ for (x = 0; x < sh_syntabsiz; x++)
+ {
+ if (isblank (x))
+ sh_syntaxtab[x] |= CSHBRK;
+ else if (member (x, shell_break_chars))
+ sh_syntaxtab[x] |= CSHBRK;
+ else
+ sh_syntaxtab[x] &= ~CSHBRK;
+ }
+}
Variables from the environment are expected to be set, etc. */
shell_initialize ();
+ set_default_lang ();
set_default_locale_vars ();
if (interactive_shell)
else
{
temp_var = bind_variable (name, string, 0);
+if (strcmp(name,"LANG") == 0)
+ itrace("bound LANG to %s", string);
VSETATTR (temp_var, (att_exported | att_imported));
array_needs_making = 1;
}
bind_variable ("OPTERR", "1", 0);
sh_opterr = 1;
- if (login_shell == 1)
+ if (login_shell == 1 && posixly_correct == 0)
set_home_var ();
/* Get the full pathname to THIS shell, and set the BASH variable
ARRAY *a;
WORD_LIST *l;
- l = get_directory_stack ();
+ l = get_directory_stack (0);
a = array_from_word_list (l);
array_dispose (array_cell (self));
dispose_words (l);