mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-27 15:43:18 +02:00
bash-20131025 remove leftover and stray files
This commit is contained in:
-5341
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
Starting bash with the `--posix' command-line option or executing
|
||||
`set -o posix' while bash is running will cause bash to conform more
|
||||
closely to the Posix.2 standard by changing the behavior to match that
|
||||
specified by Posix.2 in areas where the bash default differs.
|
||||
|
||||
The following list is what's changed when `posix mode' is in effect:
|
||||
|
||||
1. When a command in the hash table no longer exists, bash will re-search
|
||||
$PATH to find the new location. This is also available with
|
||||
`shopt -s checkhash'.
|
||||
|
||||
2. The >& redirection does not redirect stdout and stderr.
|
||||
|
||||
3. The message printed by the job control code and builtins when a job
|
||||
exits with a non-zero status is `Done(status)'.
|
||||
|
||||
4. Reserved words may not be aliased.
|
||||
|
||||
5. The Posix.2 PS1 and PS2 expansions of `!' -> history number and
|
||||
`!!' -> `!' are enabled, and parameter expansion is performed on
|
||||
the value regardless of the setting of the `promptvars' option.
|
||||
|
||||
6. Interactive comments are enabled by default. (Note that bash has
|
||||
them on by default anyway.)
|
||||
|
||||
7. The Posix.2 startup files are executed ($ENV) rather than the normal
|
||||
bash files.
|
||||
|
||||
8. Tilde expansion is only performed on assignments preceding a command
|
||||
name, rather than on all assignment statements on the line.
|
||||
|
||||
9. The default history file is ~/.sh_history (default value of $HISTFILE).
|
||||
|
||||
10. The output of `kill -l' prints all the signal names on a single line,
|
||||
separated by spaces.
|
||||
|
||||
11. Non-interactive shells exit if `file' in `. file' is not found.
|
||||
|
||||
12. Redirection operators do not perform pathname expansion on the word
|
||||
in the redirection unless the shell is interactive
|
||||
|
||||
13. Function names must be valid shell identifiers. That is, they may not
|
||||
contain characters other than letters, digits, and underscores, and
|
||||
may not start with a digit. Declaring a function with an illegal name
|
||||
causes a fatal syntax error in non-interactive shells.
|
||||
|
||||
14. Posix.2 `special' builtins are found before shell functions during command
|
||||
lookup.
|
||||
|
||||
15. If a Posix.2 special builtin returns an error status, a non-interactive
|
||||
shell exits. The fatal errors are those listed in the POSIX.2 standard,
|
||||
and include things like passing incorrect options, redirection errors,
|
||||
variable assignment errors for assignments preceding the command name,
|
||||
and so on.
|
||||
|
||||
16. The environment passed to executed commands is not sorted. Neither is
|
||||
the output of `set'. This is not strictly Posix.2 behavior, but sh
|
||||
does it this way. Ksh does not. It's not necessary to sort the
|
||||
environment; no program should rely on it being sorted.
|
||||
|
||||
17. If the `cd' builtin finds a directory to change to using $CDPATH, the
|
||||
value it assigns to $PWD does not contain any symbolic links, as if
|
||||
`cd -P' had been executed.
|
||||
|
||||
18. A non-interactive shell exits with an error status if a variable
|
||||
assignment error occurs when no command name follows the assignment
|
||||
statements. A variable assignment error occurs, for example, when
|
||||
trying to assign a value to a read-only variable.
|
||||
|
||||
19. A non-interactive shell exits with an error status if the iteration
|
||||
variable in a for statement or the selection variable in a select
|
||||
statement is a read-only variable.
|
||||
|
||||
20. Process substitution is not available.
|
||||
|
||||
21. Assignment statements preceding POSIX.2 `special' builtins persist in
|
||||
the shell environment after the builtin completes.
|
||||
|
||||
There is other Posix.2 behavior that bash does not implement. Specifically:
|
||||
|
||||
1. Assignment statements affect the execution environment of all builtins,
|
||||
not just special ones.
|
||||
@@ -1,544 +0,0 @@
|
||||
This file is set.def, from which is created set.c.
|
||||
It implements the "set" and "unset" builtins in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 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 1, 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, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES set.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../shell.h"
|
||||
#include "../flags.h"
|
||||
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int interactive;
|
||||
extern int noclobber, posixly_correct;
|
||||
#if defined (READLINE)
|
||||
extern int rl_editing_mode, no_line_editing;
|
||||
#endif /* READLINE */
|
||||
|
||||
$BUILTIN set
|
||||
$FUNCTION set_builtin
|
||||
$SHORT_DOC set [--abefhkmnptuvxldBCHP] [-o option] [arg ...]
|
||||
-a Mark variables which are modified or created for export.
|
||||
-b Notify of job termination immediately.
|
||||
-e Exit immediately if a command exits with a non-zero status.
|
||||
-f Disable file name generation (globbing).
|
||||
-h Locate and remember function commands as functions are
|
||||
defined. Function commands are normally looked up when
|
||||
the function is executed.
|
||||
-i Force the shell to be an "interactive" one. Interactive shells
|
||||
always read `~/.bashrc' on startup.
|
||||
-k All keyword arguments are placed in the environment for a
|
||||
command, not just those that precede the command name.
|
||||
-m Job control is enabled.
|
||||
-n Read commands but do not execute them.
|
||||
-o option-name
|
||||
Set the variable corresponding to option-name:
|
||||
allexport same as -a
|
||||
braceexpand same as -B
|
||||
#if defined (READLINE)
|
||||
emacs use an emacs-style line editing interface
|
||||
#endif /* READLINE */
|
||||
errexit same as -e
|
||||
histexpand same as -H
|
||||
ignoreeof the shell will not exit upon reading EOF
|
||||
interactive-comments
|
||||
allow comments to appear in interactive commands
|
||||
monitor same as -m
|
||||
noclobber disallow redirection to existing files
|
||||
noexec same as -n
|
||||
noglob same as -f
|
||||
nohash same as -d
|
||||
notify save as -b
|
||||
nounset same as -u
|
||||
physical same as -P
|
||||
posix change the behavior of bash where the default
|
||||
operation differs from the 1003.2 standard to
|
||||
match the standard
|
||||
privileged same as -p
|
||||
verbose same as -v
|
||||
#if defined (READLINE)
|
||||
vi use a vi-style line editing interface
|
||||
#endif /* READLINE */
|
||||
xtrace same as -x
|
||||
-p Turned on whenever the real and effective user ids do not match.
|
||||
Disables processing of the $ENV file and importing of shell
|
||||
functions. Turning this option off causes the effective uid and
|
||||
gid to be set to the real uid and gid.
|
||||
-t Exit after reading and executing one command.
|
||||
-u Treat unset variables as an error when substituting.
|
||||
-v Print shell input lines as they are read.
|
||||
-x Print commands and their arguments as they are executed.
|
||||
-l Save and restore the binding of the NAME in a FOR command.
|
||||
-d Disable the hashing of commands that are looked up for execution.
|
||||
Normally, commands are remembered in a hash table, and once
|
||||
found, do not have to be looked up again.
|
||||
#if defined (BRACE_EXPANSION)
|
||||
-B the shell will perform brace expansion
|
||||
#endif /* BRACE_EXPANSION */
|
||||
#if defined (BANG_HISTORY)
|
||||
-H Enable ! style history substitution. This flag is on
|
||||
by default.
|
||||
#endif /* BANG_HISTORY */
|
||||
-C If set, disallow existing regular files to be overwritten
|
||||
by redirection of output.
|
||||
-P If set, do not follow symbolic links when executing commands
|
||||
such as cd which change the current directory.
|
||||
|
||||
Using + rather than - causes these flags to be turned off. The
|
||||
flags can also be used upon invocation of the shell. The current
|
||||
set of flags may be found in $-. The remaining n ARGs are positional
|
||||
parameters and are assigned, in order, to $1, $2, .. $n. If no
|
||||
ARGs are given, all shell variables are printed.
|
||||
$END
|
||||
|
||||
/* An a-list used to match long options for set -o to the corresponding
|
||||
option letter. */
|
||||
struct {
|
||||
char *name;
|
||||
int letter;
|
||||
} o_options[] = {
|
||||
{ "allexport", 'a' },
|
||||
#if defined (BRACE_EXPANSION)
|
||||
{ "braceexpand",'B' },
|
||||
#endif
|
||||
{ "errexit", 'e' },
|
||||
{ "histexpand", 'H' },
|
||||
{ "monitor", 'm' },
|
||||
{ "noexec", 'n' },
|
||||
{ "noglob", 'f' },
|
||||
{ "nohash", 'd' },
|
||||
#if defined (JOB_CONTROL)
|
||||
{ "notify", 'b' },
|
||||
#endif /* JOB_CONTROL */
|
||||
{"nounset", 'u' },
|
||||
{"physical", 'P' },
|
||||
{"privileged", 'p' },
|
||||
{"verbose", 'v' },
|
||||
{"xtrace", 'x' },
|
||||
{(char *)NULL, 0},
|
||||
};
|
||||
|
||||
#define MINUS_O_FORMAT "%-15s\t%s\n"
|
||||
|
||||
void
|
||||
list_minus_o_opts ()
|
||||
{
|
||||
register int i;
|
||||
char *on = "on", *off = "off";
|
||||
|
||||
printf (MINUS_O_FORMAT, "noclobber", (noclobber == 1) ? on : off);
|
||||
|
||||
if (find_variable ("ignoreeof") || find_variable ("IGNOREEOF"))
|
||||
printf (MINUS_O_FORMAT, "ignoreeof", on);
|
||||
else
|
||||
printf (MINUS_O_FORMAT, "ignoreeof", off);
|
||||
|
||||
printf (MINUS_O_FORMAT, "interactive-comments",
|
||||
interactive_comments ? on : off);
|
||||
|
||||
printf (MINUS_O_FORMAT, "posix", posixly_correct ? on : off);
|
||||
|
||||
#if defined (READLINE)
|
||||
if (no_line_editing)
|
||||
{
|
||||
printf (MINUS_O_FORMAT, "emacs", off);
|
||||
printf (MINUS_O_FORMAT, "vi", off);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Magic. This code `knows' how readline handles rl_editing_mode. */
|
||||
printf (MINUS_O_FORMAT, "emacs", (rl_editing_mode == 1) ? on : off);
|
||||
printf (MINUS_O_FORMAT, "vi", (rl_editing_mode == 0) ? on : off);
|
||||
}
|
||||
#endif /* READLINE */
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
int *on_or_off, zero = 0;
|
||||
|
||||
on_or_off = find_flag (o_options[i].letter);
|
||||
if (on_or_off == FLAG_UNKNOWN)
|
||||
on_or_off = &zero;
|
||||
printf (MINUS_O_FORMAT, o_options[i].name, (*on_or_off == 1) ? on : off);
|
||||
}
|
||||
}
|
||||
|
||||
set_minus_o_option (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
int option_char = -1;
|
||||
|
||||
if (STREQ (option_name, "noclobber"))
|
||||
{
|
||||
if (on_or_off == FLAG_ON)
|
||||
bind_variable ("noclobber", "");
|
||||
else
|
||||
unbind_variable ("noclobber");
|
||||
stupidly_hack_special_variables ("noclobber");
|
||||
}
|
||||
else if (STREQ (option_name, "ignoreeof"))
|
||||
{
|
||||
unbind_variable ("ignoreeof");
|
||||
unbind_variable ("IGNOREEOF");
|
||||
if (on_or_off == FLAG_ON)
|
||||
bind_variable ("IGNOREEOF", "10");
|
||||
stupidly_hack_special_variables ("IGNOREEOF");
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
else if ((STREQ (option_name, "emacs")) || (STREQ (option_name, "vi")))
|
||||
{
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
rl_variable_bind ("editing-mode", option_name);
|
||||
|
||||
if (interactive)
|
||||
with_input_from_stdin ();
|
||||
no_line_editing = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int isemacs = (rl_editing_mode == 1);
|
||||
if ((isemacs && STREQ (option_name, "emacs")) ||
|
||||
(!isemacs && STREQ (option_name, "vi")))
|
||||
{
|
||||
if (interactive)
|
||||
with_input_from_stream (stdin, "stdin");
|
||||
no_line_editing = 1;
|
||||
}
|
||||
else
|
||||
builtin_error ("not in %s editing mode", option_name);
|
||||
}
|
||||
}
|
||||
#endif /* READLINE */
|
||||
else if (STREQ (option_name, "interactive-comments"))
|
||||
interactive_comments = (on_or_off == FLAG_ON);
|
||||
else if (STREQ (option_name, "posix"))
|
||||
{
|
||||
posixly_correct = (on_or_off == FLAG_ON);
|
||||
unbind_variable ("POSIXLY_CORRECT");
|
||||
unbind_variable ("POSIX_PEDANTIC");
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
bind_variable ("POSIXLY_CORRECT", "");
|
||||
stupidly_hack_special_variables ("POSIXLY_CORRECT");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
register int i;
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (STREQ (option_name, o_options[i].name))
|
||||
{
|
||||
option_char = o_options[i].letter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (option_char == -1)
|
||||
{
|
||||
builtin_error ("%s: unknown option name", option_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (change_flag (option_char, on_or_off) == FLAG_ERROR)
|
||||
{
|
||||
bad_option (option_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Set some flags from the word values in the input list. If LIST is empty,
|
||||
then print out the values of the variables instead. If LIST contains
|
||||
non-flags, then set $1 - $9 to the successive words of LIST. */
|
||||
set_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int on_or_off, flag_name, force_assignment = 0;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
SHELL_VAR **vars;
|
||||
|
||||
vars = all_shell_variables ();
|
||||
if (vars)
|
||||
{
|
||||
print_var_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
|
||||
vars = all_shell_functions ();
|
||||
if (vars)
|
||||
{
|
||||
print_var_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Check validity of flag arguments. */
|
||||
if (*list->word->word == '-' || *list->word->word == '+')
|
||||
{
|
||||
register char *arg;
|
||||
WORD_LIST *save_list = list;
|
||||
|
||||
while (list && (arg = list->word->word))
|
||||
{
|
||||
char c;
|
||||
|
||||
if (arg[0] != '-' && arg[0] != '+')
|
||||
break;
|
||||
|
||||
/* `-' or `--' signifies end of flag arguments. */
|
||||
if (arg[0] == '-' &&
|
||||
(!arg[1] || (arg[1] == '-' && !arg[2])))
|
||||
break;
|
||||
|
||||
while (c = *++arg)
|
||||
{
|
||||
if (find_flag (c) == FLAG_UNKNOWN && c != 'o')
|
||||
{
|
||||
char s[2];
|
||||
s[0] = c; s[1] = '\0';
|
||||
bad_option (s);
|
||||
if (c == '?')
|
||||
builtin_usage ();
|
||||
return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
list = save_list;
|
||||
}
|
||||
|
||||
/* Do the set command. While the list consists of words starting with
|
||||
'-' or '+' treat them as flags, otherwise, start assigning them to
|
||||
$1 ... $n. */
|
||||
while (list)
|
||||
{
|
||||
char *string = list->word->word;
|
||||
|
||||
/* If the argument is `--' or `-' then signal the end of the list
|
||||
and remember the remaining arguments. */
|
||||
if (string[0] == '-' && (!string[1] || (string[1] == '-' && !string[2])))
|
||||
{
|
||||
list = list->next;
|
||||
|
||||
/* `set --' unsets the positional parameters. */
|
||||
if (string[1] == '-')
|
||||
force_assignment = 1;
|
||||
|
||||
/* Until told differently, the old shell behaviour of
|
||||
`set - [arg ...]' being equivalent to `set +xv [arg ...]'
|
||||
stands. Posix.2 says the behaviour is marked as obsolescent. */
|
||||
else
|
||||
{
|
||||
change_flag ('x', '+');
|
||||
change_flag ('v', '+');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((on_or_off = *string) &&
|
||||
(on_or_off == '-' || on_or_off == '+'))
|
||||
{
|
||||
int i = 1;
|
||||
while (flag_name = string[i++])
|
||||
{
|
||||
if (flag_name == '?')
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else if (flag_name == 'o') /* -+o option-name */
|
||||
{
|
||||
char *option_name;
|
||||
WORD_LIST *opt;
|
||||
|
||||
opt = list->next;
|
||||
|
||||
if (!opt)
|
||||
{
|
||||
list_minus_o_opts ();
|
||||
continue;
|
||||
}
|
||||
|
||||
option_name = opt->word->word;
|
||||
|
||||
if (!option_name || !*option_name || (*option_name == '-'))
|
||||
{
|
||||
list_minus_o_opts ();
|
||||
continue;
|
||||
}
|
||||
list = list->next; /* Skip over option name. */
|
||||
|
||||
if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
|
||||
{
|
||||
char opt[3];
|
||||
opt[0] = on_or_off;
|
||||
opt[1] = flag_name;
|
||||
opt[2] = '\0';
|
||||
bad_option (opt);
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* Assigning $1 ... $n */
|
||||
if (list || force_assignment)
|
||||
remember_args (list, 1);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
$BUILTIN unset
|
||||
$FUNCTION unset_builtin
|
||||
$SHORT_DOC unset [-f] [-v] [name ...]
|
||||
For each NAME, remove the corresponding variable or function. Given
|
||||
the `-v', unset will only act on variables. Given the `-f' flag,
|
||||
unset will only act on functions. With neither flag, unset first
|
||||
tries to unset a variable, and if that fails, then tries to unset a
|
||||
function. Some variables (such as PATH and IFS) cannot be unset; also
|
||||
see readonly.
|
||||
$END
|
||||
|
||||
#define NEXT_VARIABLE() any_failed++; list = list->next; continue;
|
||||
|
||||
unset_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int unset_function, unset_variable, unset_array, opt, any_failed;
|
||||
char *name;
|
||||
|
||||
unset_function = unset_variable = unset_array = any_failed = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "fv")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
unset_function = 1;
|
||||
break;
|
||||
case 'v':
|
||||
unset_variable = 1;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (unset_function && unset_variable)
|
||||
{
|
||||
builtin_error ("cannot simultaneously unset a function and a variable");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
int tem;
|
||||
#if defined (ARRAY_VARS)
|
||||
char *t;
|
||||
#endif
|
||||
|
||||
name = list->word->word;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (!unset_function && valid_array_reference (name))
|
||||
{
|
||||
t = strchr (name, '[');
|
||||
*t++ = '\0';
|
||||
unset_array++;
|
||||
}
|
||||
#endif
|
||||
|
||||
var = unset_function ? find_function (name) : find_variable (name);
|
||||
|
||||
if (var && !unset_function && non_unsettable_p (var))
|
||||
{
|
||||
builtin_error ("%s: cannot unset", name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Posix.2 says that unsetting readonly variables is an error. */
|
||||
if (var && readonly_p (var))
|
||||
{
|
||||
builtin_error ("%s: cannot unset: readonly %s",
|
||||
name, unset_function ? "function" : "variable");
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Unless the -f option is supplied, the name refers to a variable. */
|
||||
#if defined (ARRAY_VARS)
|
||||
if (var && unset_array)
|
||||
{
|
||||
if (array_p (var) == 0)
|
||||
{
|
||||
builtin_error ("%s: not an array variable", name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
else
|
||||
tem = unbind_array_element (var, t);
|
||||
}
|
||||
else
|
||||
#endif /* ARRAY_VARS */
|
||||
tem = makunbound (name, unset_function ? shell_functions : shell_variables);
|
||||
|
||||
/* This is what Posix.2 draft 11+ says. ``If neither -f nor -v
|
||||
is specified, the name refers to a variable; if a variable by
|
||||
that name does not exist, a function by that name, if any,
|
||||
shall be unset.'' */
|
||||
if ((tem == -1) && !unset_function && !unset_variable)
|
||||
tem = makunbound (name, shell_functions);
|
||||
|
||||
if (tem == -1)
|
||||
any_failed++;
|
||||
else if (!unset_function)
|
||||
stupidly_hack_special_variables (name);
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (any_failed)
|
||||
return (EXECUTION_FAILURE);
|
||||
else
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
/* unwind_prot.h - Macros and functions for hacking unwind protection. */
|
||||
|
||||
/* Copyright (C) 1993 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, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#if !defined (_UNWIND_PROT_H)
|
||||
#define _UNWIND_PROT_H
|
||||
|
||||
/* Run a function without interrupts. */
|
||||
extern void begin_unwind_frame ();
|
||||
extern void discard_unwind_frame ();
|
||||
extern void run_unwind_frame ();
|
||||
extern void add_unwind_protect ();
|
||||
extern void remove_unwind_protect ();
|
||||
extern void run_unwind_protects ();
|
||||
extern void unwind_protect_var ();
|
||||
|
||||
/* Define for people who like their code to look a certain way. */
|
||||
#define end_unwind_frame()
|
||||
|
||||
/* How to protect an integer. */
|
||||
#define unwind_protect_int(X) unwind_protect_var (&(X), (char *)(X), sizeof (int))
|
||||
|
||||
/* How to protect a pointer to a string. */
|
||||
#define unwind_protect_string(X) \
|
||||
unwind_protect_var ((int *)&(X), (X), sizeof (char *))
|
||||
|
||||
/* How to protect any old pointer. */
|
||||
#define unwind_protect_pointer(X) unwind_protect_string (X)
|
||||
|
||||
/* How to protect the contents of a jmp_buf. */
|
||||
#define unwind_protect_jmp_buf(X) \
|
||||
unwind_protect_var ((int *)(X), (char *)(X), sizeof (procenv_t))
|
||||
|
||||
#endif /* _UNWIND_PROT_H */
|
||||
Vendored
-4195
File diff suppressed because it is too large
Load Diff
-4199
File diff suppressed because it is too large
Load Diff
@@ -1,805 +0,0 @@
|
||||
/* braces.c -- code for doing word expansion in curly braces. */
|
||||
|
||||
/* Copyright (C) 1987-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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Stuff in curly braces gets expanded before all other shell expansions. */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (BRACE_EXPANSION)
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#if defined (SHELL)
|
||||
# include "shell.h"
|
||||
#endif /* SHELL */
|
||||
|
||||
#include "typemax.h" /* INTMAX_MIN, INTMAX_MAX */
|
||||
#include "general.h"
|
||||
#include "shmbutil.h"
|
||||
#include "chartypes.h"
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define brace_whitespace(c) (!(c) || (c) == ' ' || (c) == '\t' || (c) == '\n')
|
||||
|
||||
#define BRACE_SEQ_SPECIFIER ".."
|
||||
|
||||
extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
|
||||
|
||||
extern int last_command_exit_value;
|
||||
|
||||
/* Basic idea:
|
||||
|
||||
Segregate the text into 3 sections: preamble (stuff before an open brace),
|
||||
postamble (stuff after the matching close brace) and amble (stuff after
|
||||
preamble, and before postamble). Expand amble, and then tack on the
|
||||
expansions to preamble. Expand postamble, and tack on the expansions to
|
||||
the result so far.
|
||||
*/
|
||||
|
||||
/* The character which is used to separate arguments. */
|
||||
static const int brace_arg_separator = ',';
|
||||
|
||||
#if defined (__P)
|
||||
static int brace_gobbler __P((char *, size_t, int *, int));
|
||||
static char **expand_amble __P((char *, size_t, int));
|
||||
static char **expand_seqterm __P((char *, size_t));
|
||||
static char **mkseq __P((intmax_t, intmax_t, intmax_t, int, int));
|
||||
static char **array_concat __P((char **, char **));
|
||||
#else
|
||||
static int brace_gobbler ();
|
||||
static char **expand_amble ();
|
||||
static char **expand_seqterm ();
|
||||
static char **mkseq();
|
||||
static char **array_concat ();
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static void
|
||||
dump_result (a)
|
||||
char **a;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; a[i]; i++)
|
||||
printf ("dump_result: a[%d] = -%s-\n", i, a[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return an array of strings; the brace expansion of TEXT. */
|
||||
char **
|
||||
brace_expand (text)
|
||||
char *text;
|
||||
{
|
||||
register int start;
|
||||
size_t tlen;
|
||||
char *preamble, *postamble, *amble;
|
||||
size_t alen;
|
||||
char **tack, **result;
|
||||
int i, j, c, c1;
|
||||
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
/* Find the text of the preamble. */
|
||||
tlen = strlen (text);
|
||||
i = 0;
|
||||
#if defined (CSH_BRACE_COMPAT)
|
||||
c = brace_gobbler (text, tlen, &i, '{'); /* } */
|
||||
#else
|
||||
/* Make sure that when we exit this loop, c == 0 or text[i] begins a
|
||||
valid brace expansion sequence. */
|
||||
do
|
||||
{
|
||||
c = brace_gobbler (text, tlen, &i, '{'); /* } */
|
||||
c1 = c;
|
||||
/* Verify that c begins a valid brace expansion word. If it doesn't, we
|
||||
go on. Loop stops when there are no more open braces in the word. */
|
||||
if (c)
|
||||
{
|
||||
start = j = i + 1; /* { */
|
||||
c = brace_gobbler (text, tlen, &j, '}');
|
||||
if (c == 0) /* it's not */
|
||||
{
|
||||
i++;
|
||||
c = c1;
|
||||
continue;
|
||||
}
|
||||
else /* it is */
|
||||
{
|
||||
c = c1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
while (c);
|
||||
#endif /* !CSH_BRACE_COMPAT */
|
||||
|
||||
preamble = (char *)xmalloc (i + 1);
|
||||
if (i > 0)
|
||||
strncpy (preamble, text, i);
|
||||
preamble[i] = '\0';
|
||||
|
||||
result = (char **)xmalloc (2 * sizeof (char *));
|
||||
result[0] = preamble;
|
||||
result[1] = (char *)NULL;
|
||||
|
||||
/* Special case. If we never found an exciting character, then
|
||||
the preamble is all of the text, so just return that. */
|
||||
if (c != '{')
|
||||
return (result);
|
||||
|
||||
/* Find the amble. This is the stuff inside this set of braces. */
|
||||
start = ++i;
|
||||
c = brace_gobbler (text, tlen, &i, '}');
|
||||
|
||||
/* What if there isn't a matching close brace? */
|
||||
if (c == 0)
|
||||
{
|
||||
#if defined (NOTDEF)
|
||||
/* Well, if we found an unquoted BRACE_ARG_SEPARATOR between START
|
||||
and I, then this should be an error. Otherwise, it isn't. */
|
||||
j = start;
|
||||
while (j < i)
|
||||
{
|
||||
if (text[j] == '\\')
|
||||
{
|
||||
j++;
|
||||
ADVANCE_CHAR (text, tlen, j);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (text[j] == brace_arg_separator)
|
||||
{ /* { */
|
||||
strvec_dispose (result);
|
||||
last_command_exit_value = 1;
|
||||
report_error ("no closing `%c' in %s", '}', text);
|
||||
throw_to_top_level ();
|
||||
}
|
||||
ADVANCE_CHAR (text, tlen, j);
|
||||
}
|
||||
#endif
|
||||
free (preamble); /* Same as result[0]; see initialization. */
|
||||
result[0] = savestring (text);
|
||||
return (result);
|
||||
}
|
||||
|
||||
#if defined (SHELL)
|
||||
amble = substring (text, start, i);
|
||||
alen = i - start;
|
||||
#else
|
||||
amble = (char *)xmalloc (1 + (i - start));
|
||||
strncpy (amble, &text[start], (i - start));
|
||||
alen = i - start;
|
||||
amble[alen] = '\0';
|
||||
#endif
|
||||
|
||||
#if defined (SHELL)
|
||||
INITIALIZE_MBSTATE;
|
||||
|
||||
/* If the amble does not contain an unquoted BRACE_ARG_SEPARATOR, then
|
||||
just return without doing any expansion. */
|
||||
j = 0;
|
||||
while (amble[j])
|
||||
{
|
||||
if (amble[j] == '\\')
|
||||
{
|
||||
j++;
|
||||
ADVANCE_CHAR (amble, alen, j);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (amble[j] == brace_arg_separator)
|
||||
break;
|
||||
|
||||
ADVANCE_CHAR (amble, alen, j);
|
||||
}
|
||||
|
||||
if (amble[j] == 0)
|
||||
{
|
||||
tack = expand_seqterm (amble, alen);
|
||||
if (tack)
|
||||
goto add_tack;
|
||||
else if (text[i + 1])
|
||||
{
|
||||
/* If the sequence expansion fails (e.g., because the integers
|
||||
overflow), but there is more in the string, try and process
|
||||
the rest of the string, which may contain additional brace
|
||||
expansions. Treat the unexpanded sequence term as a simple
|
||||
string (including the braces). */
|
||||
tack = strvec_create (2);
|
||||
tack[0] = savestring (text+start-1);
|
||||
tack[0][i-start+2] = '\0';
|
||||
tack[1] = (char *)0;
|
||||
goto add_tack;
|
||||
}
|
||||
else
|
||||
{
|
||||
free (amble);
|
||||
free (preamble);
|
||||
result[0] = savestring (text);
|
||||
return (result);
|
||||
}
|
||||
}
|
||||
#endif /* SHELL */
|
||||
|
||||
tack = expand_amble (amble, alen, 0);
|
||||
add_tack:
|
||||
result = array_concat (result, tack);
|
||||
free (amble);
|
||||
if (tack != result)
|
||||
strvec_dispose (tack);
|
||||
|
||||
postamble = text + i + 1;
|
||||
|
||||
if (postamble && *postamble)
|
||||
{
|
||||
tack = brace_expand (postamble);
|
||||
result = array_concat (result, tack);
|
||||
if (tack != result)
|
||||
strvec_dispose (tack);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Expand the text found inside of braces. We simply try to split the
|
||||
text at BRACE_ARG_SEPARATORs into separate strings. We then brace
|
||||
expand each slot which needs it, until there are no more slots which
|
||||
need it. */
|
||||
static char **
|
||||
expand_amble (text, tlen, flags)
|
||||
char *text;
|
||||
size_t tlen;
|
||||
int flags;
|
||||
{
|
||||
char **result, **partial;
|
||||
char *tem;
|
||||
int start, i, c;
|
||||
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
result = (char **)NULL;
|
||||
|
||||
start = i = 0;
|
||||
c = 1;
|
||||
while (c)
|
||||
{
|
||||
c = brace_gobbler (text, tlen, &i, brace_arg_separator);
|
||||
#if defined (SHELL)
|
||||
tem = substring (text, start, i);
|
||||
#else
|
||||
tem = (char *)xmalloc (1 + (i - start));
|
||||
strncpy (tem, &text[start], (i - start));
|
||||
tem[i- start] = '\0';
|
||||
#endif
|
||||
|
||||
partial = brace_expand (tem);
|
||||
|
||||
if (!result)
|
||||
result = partial;
|
||||
else
|
||||
{
|
||||
register int lr, lp, j;
|
||||
|
||||
lr = strvec_len (result);
|
||||
lp = strvec_len (partial);
|
||||
|
||||
result = strvec_resize (result, lp + lr + 1);
|
||||
|
||||
for (j = 0; j < lp; j++)
|
||||
result[lr + j] = partial[j];
|
||||
|
||||
result[lr + j] = (char *)NULL;
|
||||
free (partial);
|
||||
}
|
||||
free (tem);
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
start = i;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
#define ST_BAD 0
|
||||
#define ST_INT 1
|
||||
#define ST_CHAR 2
|
||||
#define ST_ZINT 3
|
||||
|
||||
#ifndef sh_imaxabs
|
||||
# define sh_imaxabs(x) (((x) >= 0) ? (x) : -(x))
|
||||
#endif
|
||||
|
||||
/* Handle signed arithmetic overflow and underflow. Have to do it this way
|
||||
to avoid compilers optimizing out simpler overflow checks. */
|
||||
|
||||
/* Make sure that a+b does not exceed MAXV or is smaller than MINV (if b < 0).
|
||||
Assumes that b > 0 if a > 0 and b < 0 if a < 0 */
|
||||
#define ADDOVERFLOW(a,b,minv,maxv) \
|
||||
((((a) > 0) && ((b) > ((maxv) - (a)))) || \
|
||||
(((a) < 0) && ((b) < ((minv) - (a)))))
|
||||
|
||||
/* Make sure that a-b is not smaller than MINV or exceeds MAXV (if b < 0).
|
||||
Assumes that b > 0 if a > 0 and b < 0 if a < 0 */
|
||||
#define SUBOVERFLOW(a,b,minv,maxv) \
|
||||
((((b) > 0) && ((a) < ((minv) + (b)))) || \
|
||||
(((b) < 0) && ((a) > ((maxv) + (b)))))
|
||||
|
||||
static char **
|
||||
mkseq (start, end, incr, type, width)
|
||||
intmax_t start, end, incr;
|
||||
int type, width;
|
||||
{
|
||||
intmax_t n, prevn;
|
||||
int i, nelem;
|
||||
char **result, *t;
|
||||
|
||||
if (incr == 0)
|
||||
incr = 1;
|
||||
|
||||
if (start > end && incr > 0)
|
||||
incr = -incr;
|
||||
else if (start < end && incr < 0)
|
||||
{
|
||||
if (incr == INTMAX_MIN) /* Don't use -INTMAX_MIN */
|
||||
return ((char **)NULL);
|
||||
incr = -incr;
|
||||
}
|
||||
|
||||
/* Check that end-start will not overflow INTMAX_MIN, INTMAX_MAX. The +3
|
||||
and -2, not strictly necessary, are there because of the way the number
|
||||
of elements and value passed to strvec_create() are calculated below. */
|
||||
if (SUBOVERFLOW (end, start, INTMAX_MIN+3, INTMAX_MAX-2))
|
||||
return ((char **)NULL);
|
||||
|
||||
prevn = sh_imaxabs (end - start);
|
||||
/* Need to check this way in case INT_MAX == INTMAX_MAX */
|
||||
if (INT_MAX == INTMAX_MAX && (ADDOVERFLOW (prevn, 2, INT_MIN, INT_MAX)))
|
||||
return ((char **)NULL);
|
||||
/* Make sure the assignment to nelem below doesn't end up <= 0 due to
|
||||
intmax_t overflow */
|
||||
else if (ADDOVERFLOW ((prevn/sh_imaxabs(incr)), 1, INTMAX_MIN, INTMAX_MAX))
|
||||
return ((char **)NULL);
|
||||
|
||||
/* XXX - TOFIX: potentially allocating a lot of extra memory if
|
||||
imaxabs(incr) != 1 */
|
||||
/* Instead of a simple nelem = prevn + 1, something like:
|
||||
nelem = (prevn / imaxabs(incr)) + 1;
|
||||
would work */
|
||||
nelem = (prevn / sh_imaxabs(incr)) + 1;
|
||||
if (nelem > INT_MAX - 2) /* Don't overflow int */
|
||||
return ((char **)NULL);
|
||||
result = strvec_create (nelem + 1);
|
||||
|
||||
/* Make sure we go through the loop at least once, so {3..3} prints `3' */
|
||||
i = 0;
|
||||
n = start;
|
||||
do
|
||||
{
|
||||
#if defined (SHELL)
|
||||
QUIT; /* XXX - memory leak here */
|
||||
#endif
|
||||
if (type == ST_INT)
|
||||
result[i++] = itos (n);
|
||||
else if (type == ST_ZINT)
|
||||
{
|
||||
int len, arg;
|
||||
arg = n;
|
||||
len = asprintf (&t, "%0*d", width, arg);
|
||||
result[i++] = t;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (char *)xmalloc (2);
|
||||
t[0] = n;
|
||||
t[1] = '\0';
|
||||
result[i++] = t;
|
||||
}
|
||||
|
||||
/* Handle overflow and underflow of n+incr */
|
||||
if (ADDOVERFLOW (n, incr, INTMAX_MIN, INTMAX_MAX))
|
||||
break;
|
||||
|
||||
n += incr;
|
||||
|
||||
if ((incr < 0 && n < end) || (incr > 0 && n > end))
|
||||
break;
|
||||
}
|
||||
while (1);
|
||||
|
||||
result[i] = (char *)0;
|
||||
return (result);
|
||||
}
|
||||
|
||||
static char **
|
||||
expand_seqterm (text, tlen)
|
||||
char *text;
|
||||
size_t tlen;
|
||||
{
|
||||
char *t, *lhs, *rhs;
|
||||
int i, lhs_t, rhs_t, lhs_l, rhs_l, width;
|
||||
intmax_t lhs_v, rhs_v, incr;
|
||||
intmax_t tl, tr;
|
||||
char **result, *ep, *oep;
|
||||
|
||||
t = strstr (text, BRACE_SEQ_SPECIFIER);
|
||||
if (t == 0)
|
||||
return ((char **)NULL);
|
||||
|
||||
lhs_l = t - text; /* index of start of BRACE_SEQ_SPECIFIER */
|
||||
lhs = substring (text, 0, lhs_l);
|
||||
rhs = substring (text, lhs_l + sizeof(BRACE_SEQ_SPECIFIER) - 1, tlen);
|
||||
|
||||
if (lhs[0] == 0 || rhs[0] == 0)
|
||||
{
|
||||
free (lhs);
|
||||
free (rhs);
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
||||
/* Now figure out whether LHS and RHS are integers or letters. Both
|
||||
sides have to match. */
|
||||
lhs_t = (legal_number (lhs, &tl)) ? ST_INT :
|
||||
((ISALPHA (lhs[0]) && lhs[1] == 0) ? ST_CHAR : ST_BAD);
|
||||
|
||||
/* Decide on rhs and whether or not it looks like the user specified
|
||||
an increment */
|
||||
ep = 0;
|
||||
if (ISDIGIT (rhs[0]) || ((rhs[0] == '+' || rhs[0] == '-') && ISDIGIT (rhs[1])))
|
||||
{
|
||||
rhs_t = ST_INT;
|
||||
errno == 0;
|
||||
tr = strtoimax (rhs, &ep, 10);
|
||||
if (errno == ERANGE || (ep && *ep != 0 && *ep != '.'))
|
||||
rhs_t = ST_BAD; /* invalid */
|
||||
}
|
||||
else if (ISALPHA (rhs[0]) && (rhs[1] == 0 || rhs[1] == '.'))
|
||||
{
|
||||
rhs_t = ST_CHAR;
|
||||
ep = rhs + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
rhs_t = ST_BAD;
|
||||
ep = 0;
|
||||
}
|
||||
|
||||
incr = 1;
|
||||
if (rhs_t != ST_BAD)
|
||||
{
|
||||
oep = ep;
|
||||
errno = 0;
|
||||
if (ep && *ep == '.' && ep[1] == '.' && ep[2])
|
||||
incr = strtoimax (ep + 2, &ep, 10);
|
||||
if (*ep != 0 || errno == ERANGE)
|
||||
rhs_t = ST_BAD; /* invalid incr or overflow */
|
||||
tlen -= ep - oep;
|
||||
}
|
||||
|
||||
if (lhs_t != rhs_t || lhs_t == ST_BAD || rhs_t == ST_BAD)
|
||||
{
|
||||
free (lhs);
|
||||
free (rhs);
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
||||
/* OK, we have something. It's either a sequence of integers, ascending
|
||||
or descending, or a sequence or letters, ditto. Generate the sequence,
|
||||
put it into a string vector, and return it. */
|
||||
|
||||
if (lhs_t == ST_CHAR)
|
||||
{
|
||||
lhs_v = (unsigned char)lhs[0];
|
||||
rhs_v = (unsigned char)rhs[0];
|
||||
width = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lhs_v = tl; /* integer truncation */
|
||||
rhs_v = tr;
|
||||
|
||||
/* Decide whether or not the terms need zero-padding */
|
||||
rhs_l = tlen - lhs_l - sizeof (BRACE_SEQ_SPECIFIER) + 1;
|
||||
width = 0;
|
||||
if (lhs_l > 1 && lhs[0] == '0')
|
||||
width = lhs_l, lhs_t = ST_ZINT;
|
||||
if (lhs_l > 2 && lhs[0] == '-' && lhs[1] == '0')
|
||||
width = lhs_l, lhs_t = ST_ZINT;
|
||||
if (rhs_l > 1 && rhs[0] == '0' && width < rhs_l)
|
||||
width = rhs_l, lhs_t = ST_ZINT;
|
||||
if (rhs_l > 2 && rhs[0] == '-' && rhs[1] == '0' && width < rhs_l)
|
||||
width = rhs_l, lhs_t = ST_ZINT;
|
||||
|
||||
if (width < lhs_l && lhs_t == ST_ZINT)
|
||||
width = lhs_l;
|
||||
if (width < rhs_l && lhs_t == ST_ZINT)
|
||||
width = rhs_l;
|
||||
}
|
||||
|
||||
result = mkseq (lhs_v, rhs_v, incr, lhs_t, width);
|
||||
|
||||
free (lhs);
|
||||
free (rhs);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Start at INDEX, and skip characters in TEXT. Set INDEX to the
|
||||
index of the character matching SATISFY. This understands about
|
||||
quoting. Return the character that caused us to stop searching;
|
||||
this is either the same as SATISFY, or 0. */
|
||||
/* If SATISFY is `}', we are looking for a brace expression, so we
|
||||
should enforce the rules that govern valid brace expansions:
|
||||
1) to count as an arg separator, a comma or `..' has to be outside
|
||||
an inner set of braces.
|
||||
*/
|
||||
static int
|
||||
brace_gobbler (text, tlen, indx, satisfy)
|
||||
char *text;
|
||||
size_t tlen;
|
||||
int *indx;
|
||||
int satisfy;
|
||||
{
|
||||
register int i, c, quoted, level, commas, pass_next;
|
||||
#if defined (SHELL)
|
||||
int si;
|
||||
char *t;
|
||||
#endif
|
||||
DECLARE_MBSTATE;
|
||||
|
||||
level = quoted = pass_next = 0;
|
||||
#if defined (CSH_BRACE_COMPAT)
|
||||
commas = 1;
|
||||
#else
|
||||
commas = (satisfy == '}') ? 0 : 1;
|
||||
#endif
|
||||
|
||||
i = *indx;
|
||||
while (c = text[i])
|
||||
{
|
||||
if (pass_next)
|
||||
{
|
||||
pass_next = 0;
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* A backslash escapes the next character. This allows backslash to
|
||||
escape the quote character in a double-quoted string. */
|
||||
if (c == '\\' && (quoted == 0 || quoted == '"' || quoted == '`'))
|
||||
{
|
||||
pass_next = 1;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined (SHELL)
|
||||
/* If compiling for the shell, treat ${...} like \{...} */
|
||||
if (c == '$' && text[i+1] == '{' && quoted != '\'') /* } */
|
||||
{
|
||||
pass_next = 1;
|
||||
i++;
|
||||
if (quoted == 0)
|
||||
level++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (quoted)
|
||||
{
|
||||
if (c == quoted)
|
||||
quoted = 0;
|
||||
#if defined (SHELL)
|
||||
/* The shell allows quoted command substitutions */
|
||||
if (quoted == '"' && c == '$' && text[i+1] == '(') /*)*/
|
||||
goto comsub;
|
||||
#endif
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '"' || c == '\'' || c == '`')
|
||||
{
|
||||
quoted = c;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined (SHELL)
|
||||
/* Pass new-style command and process substitutions through unchanged. */
|
||||
if ((c == '$' || c == '<' || c == '>') && text[i+1] == '(') /* ) */
|
||||
{
|
||||
comsub:
|
||||
si = i + 2;
|
||||
t = extract_command_subst (text, &si, 0);
|
||||
i = si;
|
||||
free (t);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (c == satisfy && level == 0 && quoted == 0 && commas > 0)
|
||||
{
|
||||
/* We ignore an open brace surrounded by whitespace, and also
|
||||
an open brace followed immediately by a close brace preceded
|
||||
by whitespace. */
|
||||
if (c == '{' &&
|
||||
((!i || brace_whitespace (text[i - 1])) &&
|
||||
(brace_whitespace (text[i + 1]) || text[i + 1] == '}')))
|
||||
{
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == '{')
|
||||
level++;
|
||||
else if (c == '}' && level)
|
||||
level--;
|
||||
#if !defined (CSH_BRACE_COMPAT)
|
||||
else if (satisfy == '}' && c == brace_arg_separator && level == 0)
|
||||
commas++;
|
||||
else if (satisfy == '}' && STREQN (text+i, BRACE_SEQ_SPECIFIER, 2) &&
|
||||
text[i+2] != satisfy && level == 0)
|
||||
commas++;
|
||||
#endif
|
||||
|
||||
ADVANCE_CHAR (text, tlen, i);
|
||||
}
|
||||
|
||||
*indx = i;
|
||||
return (c);
|
||||
}
|
||||
|
||||
/* Return 1 if ARR has any non-empty-string members. Used to short-circuit
|
||||
in array_concat() below. */
|
||||
static int
|
||||
degenerate_array (arr)
|
||||
char **arr;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; arr[i]; i++)
|
||||
if (arr[i][0] != '\0')
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Return a new array of strings which is the result of appending each
|
||||
string in ARR2 to each string in ARR1. The resultant array is
|
||||
len (arr1) * len (arr2) long. For convenience, ARR1 (and its contents)
|
||||
are free ()'ed. ARR1 can be NULL, in that case, a new version of ARR2
|
||||
is returned. */
|
||||
static char **
|
||||
array_concat (arr1, arr2)
|
||||
char **arr1, **arr2;
|
||||
{
|
||||
register int i, j, len, len1, len2;
|
||||
register char **result;
|
||||
|
||||
if (arr1 == 0)
|
||||
return (arr2); /* XXX - see if we can get away without copying? */
|
||||
|
||||
if (arr2 == 0)
|
||||
return (arr1); /* XXX - caller expects us to free arr1 */
|
||||
|
||||
/* We can only short-circuit if the array consists of a single null element;
|
||||
otherwise we need to replicate the contents of the other array and
|
||||
prefix (or append, below) an empty element to each one. */
|
||||
if (arr1[0] && arr1[0][0] == 0 && arr1[1] == 0)
|
||||
{
|
||||
strvec_dispose (arr1);
|
||||
return (arr2); /* XXX - use flags to see if we can avoid copying here */
|
||||
}
|
||||
|
||||
if (arr2[0] && arr2[0][0] == 0 && arr2[1] == 0)
|
||||
return (arr1); /* XXX - rather than copying and freeing it */
|
||||
|
||||
len1 = strvec_len (arr1);
|
||||
len2 = strvec_len (arr2);
|
||||
|
||||
result = (char **)xmalloc ((1 + (len1 * len2)) * sizeof (char *));
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < len1; i++)
|
||||
{
|
||||
int strlen_1 = strlen (arr1[i]);
|
||||
|
||||
for (j = 0; j < len2; j++)
|
||||
{
|
||||
result[len] = (char *)xmalloc (1 + strlen_1 + strlen (arr2[j]));
|
||||
strcpy (result[len], arr1[i]);
|
||||
strcpy (result[len] + strlen_1, arr2[j]);
|
||||
len++;
|
||||
}
|
||||
free (arr1[i]);
|
||||
}
|
||||
free (arr1);
|
||||
|
||||
result[len] = (char *)NULL;
|
||||
return (result);
|
||||
}
|
||||
|
||||
#if defined (TEST)
|
||||
#include <stdio.h>
|
||||
|
||||
fatal_error (format, arg1, arg2)
|
||||
char *format, *arg1, *arg2;
|
||||
{
|
||||
report_error (format, arg1, arg2);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
report_error (format, arg1, arg2)
|
||||
char *format, *arg1, *arg2;
|
||||
{
|
||||
fprintf (stderr, format, arg1, arg2);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
main ()
|
||||
{
|
||||
char example[256];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
char **result;
|
||||
int i;
|
||||
|
||||
fprintf (stderr, "brace_expand> ");
|
||||
|
||||
if ((!fgets (example, 256, stdin)) ||
|
||||
(strncmp (example, "quit", 4) == 0))
|
||||
break;
|
||||
|
||||
if (strlen (example))
|
||||
example[strlen (example) - 1] = '\0';
|
||||
|
||||
result = brace_expand (example);
|
||||
|
||||
for (i = 0; result[i]; i++)
|
||||
printf ("%s\n", result[i]);
|
||||
|
||||
free_array (result);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* compile-command: "gcc -g -Bstatic -DTEST -o brace_expand braces.c general.o"
|
||||
* end:
|
||||
*/
|
||||
|
||||
#endif /* TEST */
|
||||
#endif /* BRACE_EXPANSION */
|
||||
@@ -1,651 +0,0 @@
|
||||
This file is cd.def, from which is created cd.c. It implements the
|
||||
builtins "cd" and "pwd" in Bash.
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
$PRODUCES cd.c
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#include "posixdir.h"
|
||||
#include "posixstat.h"
|
||||
#if defined (HAVE_SYS_PARAM_H)
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <tilde/tilde.h>
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../flags.h"
|
||||
#include "maxpath.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern int posixly_correct;
|
||||
extern int array_needs_making;
|
||||
extern const char * const bash_getcwd_errstr;
|
||||
|
||||
static int bindpwd __P((int));
|
||||
static int setpwd __P((char *));
|
||||
static char *resetpwd __P((char *));
|
||||
static int change_to_directory __P((char *, int, int));
|
||||
|
||||
static int cdxattr __P((char *, char **));
|
||||
static void resetxattr __P((void));
|
||||
|
||||
/* Change this to 1 to get cd spelling correction by default. */
|
||||
int cdspelling = 0;
|
||||
|
||||
int cdable_vars;
|
||||
|
||||
static int eflag; /* file scope so bindpwd() can see it */
|
||||
static int xattrflag; /* O_XATTR support for openat */
|
||||
static int xattrfd = -1;
|
||||
|
||||
$BUILTIN cd
|
||||
$FUNCTION cd_builtin
|
||||
$SHORT_DOC cd [-L|[-P [-e]] [-@]] [dir]
|
||||
Change the shell working directory.
|
||||
|
||||
Change the current directory to DIR. The default DIR is the value of the
|
||||
HOME shell variable.
|
||||
|
||||
The variable CDPATH defines the search path for the directory containing
|
||||
DIR. Alternative directory names in CDPATH are separated by a colon (:).
|
||||
A null directory name is the same as the current directory. If DIR begins
|
||||
with a slash (/), then CDPATH is not used.
|
||||
|
||||
If the directory is not found, and the shell option `cdable_vars' is set,
|
||||
the word is assumed to be a variable name. If that variable has a value,
|
||||
its value is used for DIR.
|
||||
|
||||
Options:
|
||||
-L force symbolic links to be followed: resolve symbolic links in
|
||||
DIR after processing instances of `..'
|
||||
-P use the physical directory structure without following symbolic
|
||||
links: resolve symbolic links in DIR before processing instances
|
||||
of `..'
|
||||
-e if the -P option is supplied, and the current working directory
|
||||
cannot be determined successfully, exit with a non-zero status
|
||||
#if defined (O_XATTR)
|
||||
-@ on systems that support it, treat a file with extended attributes
|
||||
as a directory containing the file attributes
|
||||
#endif
|
||||
|
||||
The default is to follow symbolic links, as if `-L' were specified.
|
||||
`..' is processed by removing the immediately previous pathname component
|
||||
back to a slash or the beginning of DIR.
|
||||
|
||||
Exit Status:
|
||||
Returns 0 if the directory is changed, and if $PWD is set successfully when
|
||||
-P is used; non-zero otherwise.
|
||||
$END
|
||||
|
||||
/* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
|
||||
static int
|
||||
setpwd (dirname)
|
||||
char *dirname;
|
||||
{
|
||||
int old_anm;
|
||||
SHELL_VAR *tvar;
|
||||
|
||||
old_anm = array_needs_making;
|
||||
tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
|
||||
if (tvar && readonly_p (tvar))
|
||||
return EXECUTION_FAILURE;
|
||||
if (tvar && old_anm == 0 && array_needs_making && exported_p (tvar))
|
||||
{
|
||||
update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
|
||||
array_needs_making = 0;
|
||||
}
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
|
||||
static int
|
||||
bindpwd (no_symlinks)
|
||||
int no_symlinks;
|
||||
{
|
||||
char *dirname, *pwdvar;
|
||||
int old_anm, r;
|
||||
SHELL_VAR *tvar;
|
||||
|
||||
r = sh_chkwrite (EXECUTION_SUCCESS);
|
||||
|
||||
#define tcwd the_current_working_directory
|
||||
dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
|
||||
: get_working_directory ("cd");
|
||||
#undef tcwd
|
||||
|
||||
old_anm = array_needs_making;
|
||||
pwdvar = get_string_value ("PWD");
|
||||
|
||||
tvar = bind_variable ("OLDPWD", pwdvar, 0);
|
||||
if (tvar && readonly_p (tvar))
|
||||
r = EXECUTION_FAILURE;
|
||||
|
||||
if (old_anm == 0 && array_needs_making && exported_p (tvar))
|
||||
{
|
||||
update_export_env_inplace ("OLDPWD=", 7, pwdvar);
|
||||
array_needs_making = 0;
|
||||
}
|
||||
|
||||
if (setpwd (dirname) == EXECUTION_FAILURE)
|
||||
r = EXECUTION_FAILURE;
|
||||
if (dirname == 0 && eflag)
|
||||
r = EXECUTION_FAILURE;
|
||||
|
||||
if (dirname && dirname != the_current_working_directory)
|
||||
free (dirname);
|
||||
|
||||
return (r);
|
||||
}
|
||||
|
||||
/* Call get_working_directory to reset the value of
|
||||
the_current_working_directory () */
|
||||
static char *
|
||||
resetpwd (caller)
|
||||
char *caller;
|
||||
{
|
||||
char *tdir;
|
||||
|
||||
FREE (the_current_working_directory);
|
||||
the_current_working_directory = (char *)NULL;
|
||||
tdir = get_working_directory (caller);
|
||||
return (tdir);
|
||||
}
|
||||
|
||||
static int
|
||||
cdxattr (dir, ndirp)
|
||||
char *dir; /* don't assume we can always free DIR */
|
||||
char **ndirp; /* return new constructed directory name */
|
||||
{
|
||||
#if defined (O_XATTR)
|
||||
int apfd, fd, r, e;
|
||||
char buf[11+40+40]; /* construct new `fake' path for pwd */
|
||||
|
||||
apfd = openat (AT_FDCWD, dir, O_RDONLY|O_NONBLOCK);
|
||||
if (apfd < 0)
|
||||
return -1;
|
||||
fd = openat (apfd, ".", O_XATTR);
|
||||
e = errno;
|
||||
close (apfd); /* ignore close error for now */
|
||||
errno = e;
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
r = fchdir (fd); /* assume fchdir exists everywhere with O_XATTR */
|
||||
if (r < 0)
|
||||
{
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
/* NFSv4 and ZFS extended attribute directories do not have names which are
|
||||
visible in the standard Unix directory tree structure. To ensure we have
|
||||
a valid name for $PWD, we synthesize one under /proc, but to keep that
|
||||
path valid, we need to keep the file descriptor open as long as we are in
|
||||
this directory. This imposes a certain structure on /proc. */
|
||||
sprintf (buff, "/proc/%d/fd/%d", getpid(), fd);
|
||||
if (ndirp)
|
||||
*ndirp = savestring (buff);
|
||||
|
||||
if (xattrfd >= 0)
|
||||
close (xattrfd);
|
||||
xattrfd = fd;
|
||||
|
||||
return r;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Clean up the O_XATTR baggage. Currently only closes xattrfd */
|
||||
static void
|
||||
resetxattr ()
|
||||
{
|
||||
#if defined (O_XATTR)
|
||||
if (xattrfd >= 0)
|
||||
{
|
||||
close (xattrfd);
|
||||
xattrfd = -1;
|
||||
}
|
||||
#else
|
||||
xattrfd = -1; /* not strictly necessary */
|
||||
#endif
|
||||
}
|
||||
|
||||
#define LCD_DOVARS 0x001
|
||||
#define LCD_DOSPELL 0x002
|
||||
#define LCD_PRINTPATH 0x004
|
||||
#define LCD_FREEDIRNAME 0x008
|
||||
|
||||
/* This builtin is ultimately the way that all user-visible commands should
|
||||
change the current working directory. It is called by cd_to_string (),
|
||||
so the programming interface is simple, and it handles errors and
|
||||
restrictions properly. */
|
||||
int
|
||||
cd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *dirname, *cdpath, *path, *temp;
|
||||
int path_index, no_symlinks, opt, lflag;
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted)
|
||||
{
|
||||
sh_restricted ((char *)NULL);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif /* RESTRICTED_SHELL */
|
||||
|
||||
eflag = 0;
|
||||
no_symlinks = no_symbolic_links;
|
||||
reset_internal_getopt ();
|
||||
#if defined (O_XATTR)
|
||||
while ((opt = internal_getopt (list, "eLP@")) != -1)
|
||||
#else
|
||||
while ((opt = internal_getopt (list, "eLP")) != -1)
|
||||
#endif
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'P':
|
||||
no_symlinks = 1;
|
||||
break;
|
||||
case 'L':
|
||||
no_symlinks = 0;
|
||||
break;
|
||||
case 'e':
|
||||
eflag = 1;
|
||||
break;
|
||||
#if defined (O_XATTR)
|
||||
case '@':
|
||||
xattrflag = 1;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
lflag = (cdable_vars ? LCD_DOVARS : 0) |
|
||||
((interactive && cdspelling) ? LCD_DOSPELL : 0);
|
||||
if (eflag && no_symlinks == 0)
|
||||
eflag = 0;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
/* `cd' without arguments is equivalent to `cd $HOME' */
|
||||
dirname = get_string_value ("HOME");
|
||||
|
||||
if (dirname == 0)
|
||||
{
|
||||
builtin_error (_("HOME not set"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
lflag = 0;
|
||||
}
|
||||
#if defined (CD_COMPLAINS)
|
||||
else if (list->next)
|
||||
{
|
||||
builtin_error (_("too many arguments"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
|
||||
{
|
||||
/* This is `cd -', equivalent to `cd $OLDPWD' */
|
||||
dirname = get_string_value ("OLDPWD");
|
||||
|
||||
if (dirname == 0)
|
||||
{
|
||||
builtin_error (_("OLDPWD not set"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#if 0
|
||||
lflag = interactive ? LCD_PRINTPATH : 0;
|
||||
#else
|
||||
lflag = LCD_PRINTPATH; /* According to SUSv3 */
|
||||
#endif
|
||||
}
|
||||
else if (absolute_pathname (list->word->word))
|
||||
dirname = list->word->word;
|
||||
else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH")))
|
||||
{
|
||||
dirname = list->word->word;
|
||||
|
||||
/* Find directory in $CDPATH. */
|
||||
path_index = 0;
|
||||
while (path = extract_colon_unit (cdpath, &path_index))
|
||||
{
|
||||
/* OPT is 1 if the path element is non-empty */
|
||||
opt = path[0] != '\0';
|
||||
temp = sh_makepath (path, dirname, MP_DOTILDE);
|
||||
free (path);
|
||||
|
||||
if (change_to_directory (temp, no_symlinks, xattrflag))
|
||||
{
|
||||
/* POSIX.2 says that if a nonempty directory from CDPATH
|
||||
is used to find the directory to change to, the new
|
||||
directory name is echoed to stdout, whether or not
|
||||
the shell is interactive. */
|
||||
if (opt && (path = no_symlinks ? temp : the_current_working_directory))
|
||||
printf ("%s\n", path);
|
||||
|
||||
free (temp);
|
||||
#if 0
|
||||
/* Posix.2 says that after using CDPATH, the resultant
|
||||
value of $PWD will not contain `.' or `..'. */
|
||||
return (bindpwd (posixly_correct || no_symlinks));
|
||||
#else
|
||||
return (bindpwd (no_symlinks));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
free (temp);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* changed for bash-4.2 Posix cd description steps 5-6 */
|
||||
/* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
|
||||
try the current directory, so we just punt now with an error
|
||||
message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
|
||||
is so we don't mistakenly treat a CDPATH value of "" as not
|
||||
specifying the current directory. */
|
||||
if (posixly_correct && cdpath[0])
|
||||
{
|
||||
builtin_error ("%s: %s", dirname, strerror (ENOENT));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
dirname = list->word->word;
|
||||
|
||||
/* When we get here, DIRNAME is the directory to change to. If we
|
||||
chdir successfully, just return. */
|
||||
if (change_to_directory (dirname, no_symlinks, xattrflag))
|
||||
{
|
||||
if (lflag & LCD_PRINTPATH)
|
||||
printf ("%s\n", dirname);
|
||||
return (bindpwd (no_symlinks));
|
||||
}
|
||||
|
||||
/* If the user requests it, then perhaps this is the name of
|
||||
a shell variable, whose value contains the directory to
|
||||
change to. */
|
||||
if (lflag & LCD_DOVARS)
|
||||
{
|
||||
temp = get_string_value (dirname);
|
||||
if (temp && change_to_directory (temp, no_symlinks, xattrflag))
|
||||
{
|
||||
printf ("%s\n", temp);
|
||||
return (bindpwd (no_symlinks));
|
||||
}
|
||||
}
|
||||
|
||||
/* If the user requests it, try to find a directory name similar in
|
||||
spelling to the one requested, in case the user made a simple
|
||||
typo. This is similar to the UNIX 8th and 9th Edition shells. */
|
||||
if (lflag & LCD_DOSPELL)
|
||||
{
|
||||
temp = dirspell (dirname);
|
||||
if (temp && change_to_directory (temp, no_symlinks, xattrflag))
|
||||
{
|
||||
printf ("%s\n", temp);
|
||||
free (temp);
|
||||
return (bindpwd (no_symlinks));
|
||||
}
|
||||
else
|
||||
FREE (temp);
|
||||
}
|
||||
|
||||
builtin_error ("%s: %s", dirname, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
$BUILTIN pwd
|
||||
$FUNCTION pwd_builtin
|
||||
$SHORT_DOC pwd [-LP]
|
||||
Print the name of the current working directory.
|
||||
|
||||
Options:
|
||||
-L print the value of $PWD if it names the current working
|
||||
directory
|
||||
-P print the physical directory, without any symbolic links
|
||||
|
||||
By default, `pwd' behaves as if `-L' were specified.
|
||||
|
||||
Exit Status:
|
||||
Returns 0 unless an invalid option is given or the current directory
|
||||
cannot be read.
|
||||
$END
|
||||
|
||||
/* Non-zero means that pwd always prints the physical directory, without
|
||||
symbolic links. */
|
||||
static int verbatim_pwd;
|
||||
|
||||
/* Print the name of the current working directory. */
|
||||
int
|
||||
pwd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *directory;
|
||||
int opt, pflag;
|
||||
|
||||
verbatim_pwd = no_symbolic_links;
|
||||
pflag = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "LP")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'P':
|
||||
verbatim_pwd = pflag = 1;
|
||||
break;
|
||||
case 'L':
|
||||
verbatim_pwd = 0;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
#define tcwd the_current_working_directory
|
||||
|
||||
directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
|
||||
: get_working_directory ("pwd");
|
||||
|
||||
/* Try again using getcwd() if canonicalization fails (for instance, if
|
||||
the file system has changed state underneath bash). */
|
||||
if ((tcwd && directory == 0) ||
|
||||
(posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
|
||||
{
|
||||
if (directory && directory != tcwd)
|
||||
free (directory);
|
||||
directory = resetpwd ("pwd");
|
||||
}
|
||||
|
||||
#undef tcwd
|
||||
|
||||
if (directory)
|
||||
{
|
||||
opt = EXECUTION_SUCCESS;
|
||||
printf ("%s\n", directory);
|
||||
/* This is dumb but posix-mandated. */
|
||||
if (posixly_correct && pflag)
|
||||
opt = setpwd (directory);
|
||||
if (directory != the_current_working_directory)
|
||||
free (directory);
|
||||
return (sh_chkwrite (opt));
|
||||
}
|
||||
else
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Do the work of changing to the directory NEWDIR. Handle symbolic
|
||||
link following, etc. This function *must* return with
|
||||
the_current_working_directory either set to NULL (in which case
|
||||
getcwd() will eventually be called), or set to a string corresponding
|
||||
to the working directory. Return 1 on success, 0 on failure. */
|
||||
|
||||
static int
|
||||
change_to_directory (newdir, nolinks, xattr)
|
||||
char *newdir;
|
||||
int nolinks, xattr;
|
||||
{
|
||||
char *t, *tdir, *ndir;
|
||||
int err, canon_failed, r, ndlen, dlen;
|
||||
|
||||
tdir = (char *)NULL;
|
||||
|
||||
if (the_current_working_directory == 0)
|
||||
{
|
||||
t = get_working_directory ("chdir");
|
||||
FREE (t);
|
||||
}
|
||||
|
||||
t = make_absolute (newdir, the_current_working_directory);
|
||||
|
||||
/* TDIR is either the canonicalized absolute pathname of NEWDIR
|
||||
(nolinks == 0) or the absolute physical pathname of NEWDIR
|
||||
(nolinks != 0). */
|
||||
tdir = nolinks ? sh_physpath (t, 0)
|
||||
: sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
|
||||
|
||||
ndlen = strlen (newdir);
|
||||
dlen = strlen (t);
|
||||
|
||||
/* Use the canonicalized version of NEWDIR, or, if canonicalization
|
||||
failed, use the non-canonical form. */
|
||||
canon_failed = 0;
|
||||
if (tdir && *tdir)
|
||||
free (t);
|
||||
else
|
||||
{
|
||||
FREE (tdir);
|
||||
tdir = t;
|
||||
canon_failed = 1;
|
||||
}
|
||||
|
||||
/* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
|
||||
returns NULL (because it checks the path, it will return NULL if the
|
||||
resolved path doesn't exist), fail immediately. */
|
||||
if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
|
||||
{
|
||||
#if defined ENAMETOOLONG
|
||||
if (errno != ENOENT && errno != ENAMETOOLONG)
|
||||
#else
|
||||
if (errno != ENOENT)
|
||||
#endif
|
||||
errno = ENOTDIR;
|
||||
free (tdir);
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined (O_XATTR)
|
||||
if (xattrflag)
|
||||
{
|
||||
r = cdxattr (nolinks ? newdir : tdir, &ndir);
|
||||
if (r >= 0)
|
||||
{
|
||||
canon_failed = 0;
|
||||
free (tdir);
|
||||
tdir = ndir;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
r = chdir (nolinks ? newdir : tdir);
|
||||
if (r >= 0)
|
||||
resetxattr ();
|
||||
}
|
||||
|
||||
/* If the chdir succeeds, update the_current_working_directory. */
|
||||
if (r == 0)
|
||||
{
|
||||
/* If canonicalization failed, but the chdir succeeded, reset the
|
||||
shell's idea of the_current_working_directory. */
|
||||
if (canon_failed)
|
||||
{
|
||||
t = resetpwd ("cd");
|
||||
if (t == 0)
|
||||
set_working_directory (tdir);
|
||||
else
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
set_working_directory (tdir);
|
||||
|
||||
free (tdir);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* We failed to change to the appropriate directory name. If we tried
|
||||
what the user passed (nolinks != 0), punt now. */
|
||||
if (nolinks)
|
||||
{
|
||||
free (tdir);
|
||||
return (0);
|
||||
}
|
||||
|
||||
err = errno;
|
||||
|
||||
/* We're not in physical mode (nolinks == 0), but we failed to change to
|
||||
the canonicalized directory name (TDIR). Try what the user passed
|
||||
verbatim. If we succeed, reinitialize the_current_working_directory. */
|
||||
if (chdir (newdir) == 0)
|
||||
{
|
||||
t = resetpwd ("cd");
|
||||
if (t == 0)
|
||||
set_working_directory (tdir);
|
||||
else
|
||||
free (t);
|
||||
|
||||
r = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = err;
|
||||
r = 0;
|
||||
}
|
||||
|
||||
free (tdir);
|
||||
return r;
|
||||
}
|
||||
@@ -1,779 +0,0 @@
|
||||
This file is ulimit.def, from which is created ulimit.c.
|
||||
It implements the builtin "ulimit" in Bash.
|
||||
|
||||
Copyright (C) 1987-2010 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
$PRODUCES ulimit.c
|
||||
|
||||
$BUILTIN ulimit
|
||||
$FUNCTION ulimit_builtin
|
||||
$DEPENDS_ON !_MINIX
|
||||
$SHORT_DOC ulimit [-SHabcdefilmnpqrstuvxT] [limit]
|
||||
Modify shell resource limits.
|
||||
|
||||
Provides control over the resources available to the shell and processes
|
||||
it creates, on systems that allow such control.
|
||||
|
||||
Options:
|
||||
-S use the `soft' resource limit
|
||||
-H use the `hard' resource limit
|
||||
-a all current limits are reported
|
||||
-b the socket buffer size
|
||||
-c the maximum size of core files created
|
||||
-d the maximum size of a process's data segment
|
||||
-e the maximum scheduling priority (`nice')
|
||||
-f the maximum size of files written by the shell and its children
|
||||
-i the maximum number of pending signals
|
||||
-l the maximum size a process may lock into memory
|
||||
-m the maximum resident set size
|
||||
-n the maximum number of open file descriptors
|
||||
-p the pipe buffer size
|
||||
-q the maximum number of bytes in POSIX message queues
|
||||
-r the maximum real-time scheduling priority
|
||||
-s the maximum stack size
|
||||
-t the maximum amount of cpu time in seconds
|
||||
-u the maximum number of user processes
|
||||
-v the size of virtual memory
|
||||
-x the maximum number of file locks
|
||||
-T the maximum number of threads
|
||||
|
||||
Not all options are available on all platforms.
|
||||
|
||||
If LIMIT is given, it is the new value of the specified resource; the
|
||||
special LIMIT values `soft', `hard', and `unlimited' stand for the
|
||||
current soft limit, the current hard limit, and no limit, respectively.
|
||||
Otherwise, the current value of the specified resource is printed. If
|
||||
no option is given, then -f is assumed.
|
||||
|
||||
Values are in 1024-byte increments, except for -t, which is in seconds,
|
||||
-p, which is in increments of 512 bytes, and -u, which is an unscaled
|
||||
number of processes.
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is supplied or an error occurs.
|
||||
$END
|
||||
|
||||
#if !defined (_MINIX)
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#if defined (HAVE_SYS_PARAM_H)
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "pipesize.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
/* For some reason, HPUX chose to make these definitions visible only if
|
||||
_KERNEL is defined, so we define _KERNEL before including <sys/resource.h>
|
||||
and #undef it afterward. */
|
||||
#if defined (HAVE_RESOURCE)
|
||||
# include <sys/time.h>
|
||||
# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
|
||||
# define _KERNEL
|
||||
# endif
|
||||
# include <sys/resource.h>
|
||||
# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
|
||||
# undef _KERNEL
|
||||
# endif
|
||||
#elif defined (HAVE_SYS_TIMES_H)
|
||||
# include <sys/times.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LIMITS_H)
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
/* Check for the most basic symbols. If they aren't present, this
|
||||
system's <sys/resource.h> isn't very useful to us. */
|
||||
#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT)
|
||||
# undef HAVE_RESOURCE
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_RESOURCE) && defined (HAVE_ULIMIT_H)
|
||||
# include <ulimit.h>
|
||||
#endif
|
||||
|
||||
#if !defined (RLIMTYPE)
|
||||
# define RLIMTYPE long
|
||||
# define string_to_rlimtype(s) strtol(s, (char **)NULL, 10)
|
||||
# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
|
||||
#endif
|
||||
|
||||
/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
|
||||
#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
|
||||
# define RLIMIT_NOFILE RLIMIT_OFILE
|
||||
#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
|
||||
|
||||
/* Some systems have these, some do not. */
|
||||
#ifdef RLIMIT_FSIZE
|
||||
# define RLIMIT_FILESIZE RLIMIT_FSIZE
|
||||
#else
|
||||
# define RLIMIT_FILESIZE 256
|
||||
#endif
|
||||
|
||||
#define RLIMIT_PIPESIZE 257
|
||||
|
||||
#ifdef RLIMIT_NOFILE
|
||||
# define RLIMIT_OPENFILES RLIMIT_NOFILE
|
||||
#else
|
||||
# define RLIMIT_OPENFILES 258
|
||||
#endif
|
||||
|
||||
#ifdef RLIMIT_VMEM
|
||||
# define RLIMIT_VIRTMEM RLIMIT_VMEM
|
||||
# define RLIMIT_VMBLKSZ 1024
|
||||
#else
|
||||
# ifdef RLIMIT_AS
|
||||
# define RLIMIT_VIRTMEM RLIMIT_AS
|
||||
# define RLIMIT_VMBLKSZ 1024
|
||||
# else
|
||||
# define RLIMIT_VIRTMEM 259
|
||||
# define RLIMIT_VMBLKSZ 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef RLIMIT_NPROC
|
||||
# define RLIMIT_MAXUPROC RLIMIT_NPROC
|
||||
#else
|
||||
# define RLIMIT_MAXUPROC 260
|
||||
#endif
|
||||
|
||||
#if !defined (RLIM_INFINITY)
|
||||
# define RLIM_INFINITY 0x7fffffff
|
||||
#endif
|
||||
|
||||
#if !defined (RLIM_SAVED_CUR)
|
||||
# define RLIM_SAVED_CUR RLIM_INFINITY
|
||||
#endif
|
||||
|
||||
#if !defined (RLIM_SAVED_MAX)
|
||||
# define RLIM_SAVED_MAX RLIM_INFINITY
|
||||
#endif
|
||||
|
||||
#define LIMIT_HARD 0x01
|
||||
#define LIMIT_SOFT 0x02
|
||||
|
||||
/* "Blocks" are defined as 512 bytes when in Posix mode and 1024 bytes
|
||||
otherwise. */
|
||||
#define POSIXBLK -2
|
||||
|
||||
#define BLOCKSIZE(x) (((x) == POSIXBLK) ? (posixly_correct ? 512 : 1024) : (x))
|
||||
|
||||
extern int posixly_correct;
|
||||
|
||||
static int _findlim __P((int));
|
||||
|
||||
static int ulimit_internal __P((int, char *, int, int));
|
||||
|
||||
static int get_limit __P((int, RLIMTYPE *, RLIMTYPE *));
|
||||
static int set_limit __P((int, RLIMTYPE, int));
|
||||
|
||||
static void printone __P((int, RLIMTYPE, int));
|
||||
static void print_all_limits __P((int));
|
||||
|
||||
static int set_all_limits __P((int, RLIMTYPE));
|
||||
|
||||
static int filesize __P((RLIMTYPE *));
|
||||
static int pipesize __P((RLIMTYPE *));
|
||||
static int getmaxuprc __P((RLIMTYPE *));
|
||||
static int getmaxvm __P((RLIMTYPE *, RLIMTYPE *));
|
||||
|
||||
typedef struct {
|
||||
int option; /* The ulimit option for this limit. */
|
||||
int parameter; /* Parameter to pass to get_limit (). */
|
||||
int block_factor; /* Blocking factor for specific limit. */
|
||||
const char * const description; /* Descriptive string to output. */
|
||||
const char * const units; /* scale */
|
||||
} RESOURCE_LIMITS;
|
||||
|
||||
static RESOURCE_LIMITS limits[] = {
|
||||
#ifdef RLIMIT_PTHREAD
|
||||
{ 'T', RLIMIT_PTHREAD, 1, "number of threads", (char *)NULL },
|
||||
#endif
|
||||
#ifdef RLIMIT_SBSIZE
|
||||
{ 'b', RLIMIT_SBSIZE, 1, "socket buffer size", "bytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_CORE
|
||||
{ 'c', RLIMIT_CORE, POSIXBLK, "core file size", "blocks" },
|
||||
#endif
|
||||
#ifdef RLIMIT_DATA
|
||||
{ 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_NICE
|
||||
{ 'e', RLIMIT_NICE, 1, "scheduling priority", (char *)NULL },
|
||||
#endif
|
||||
{ 'f', RLIMIT_FILESIZE, POSIXBLK, "file size", "blocks" },
|
||||
#ifdef RLIMIT_SIGPENDING
|
||||
{ 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL },
|
||||
#endif
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
{ 'l', RLIMIT_MEMLOCK, 1024, "max locked memory", "kbytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_RSS
|
||||
{ 'm', RLIMIT_RSS, 1024, "max memory size", "kbytes" },
|
||||
#endif /* RLIMIT_RSS */
|
||||
{ 'n', RLIMIT_OPENFILES, 1, "open files", (char *)NULL},
|
||||
{ 'p', RLIMIT_PIPESIZE, 512, "pipe size", "512 bytes" },
|
||||
#ifdef RLIMIT_MSGQUEUE
|
||||
{ 'q', RLIMIT_MSGQUEUE, 1, "POSIX message queues", "bytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_RTPRIO
|
||||
{ 'r', RLIMIT_RTPRIO, 1, "real-time priority", (char *)NULL },
|
||||
#endif
|
||||
#ifdef RLIMIT_STACK
|
||||
{ 's', RLIMIT_STACK, 1024, "stack size", "kbytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_CPU
|
||||
{ 't', RLIMIT_CPU, 1, "cpu time", "seconds" },
|
||||
#endif /* RLIMIT_CPU */
|
||||
{ 'u', RLIMIT_MAXUPROC, 1, "max user processes", (char *)NULL },
|
||||
#if defined (HAVE_RESOURCE)
|
||||
{ 'v', RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory", "kbytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_SWAP
|
||||
{ 'w', RLIMIT_SWAP, 1024, "swap size", "kbytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_LOCKS
|
||||
{ 'x', RLIMIT_LOCKS, 1, "file locks", (char *)NULL },
|
||||
#endif
|
||||
{ -1, -1, -1, (char *)NULL, (char *)NULL }
|
||||
};
|
||||
#define NCMDS (sizeof(limits) / sizeof(limits[0]))
|
||||
|
||||
typedef struct _cmd {
|
||||
int cmd;
|
||||
char *arg;
|
||||
} ULCMD;
|
||||
|
||||
static ULCMD *cmdlist;
|
||||
static int ncmd;
|
||||
static int cmdlistsz;
|
||||
|
||||
#if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT)
|
||||
long
|
||||
ulimit (cmd, newlim)
|
||||
int cmd;
|
||||
long newlim;
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */
|
||||
|
||||
static int
|
||||
_findlim (opt)
|
||||
int opt;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; limits[i].option > 0; i++)
|
||||
if (limits[i].option == opt)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char optstring[4 + 2 * NCMDS];
|
||||
|
||||
/* Report or set limits associated with certain per-process resources.
|
||||
See the help documentation in builtins.c for a full description. */
|
||||
int
|
||||
ulimit_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
register char *s;
|
||||
int c, limind, mode, opt, all_limits;
|
||||
|
||||
mode = 0;
|
||||
|
||||
all_limits = 0;
|
||||
|
||||
/* Idea stolen from pdksh -- build option string the first time called. */
|
||||
if (optstring[0] == 0)
|
||||
{
|
||||
s = optstring;
|
||||
*s++ = 'a'; *s++ = 'S'; *s++ = 'H';
|
||||
for (c = 0; limits[c].option > 0; c++)
|
||||
{
|
||||
*s++ = limits[c].option;
|
||||
*s++ = ';';
|
||||
}
|
||||
*s = '\0';
|
||||
}
|
||||
|
||||
/* Initialize the command list. */
|
||||
if (cmdlistsz == 0)
|
||||
cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
|
||||
ncmd = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, optstring)) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
all_limits++;
|
||||
break;
|
||||
|
||||
/* -S and -H are modifiers, not real options. */
|
||||
case 'S':
|
||||
mode |= LIMIT_SOFT;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
mode |= LIMIT_HARD;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
|
||||
default:
|
||||
if (ncmd >= cmdlistsz)
|
||||
cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
|
||||
cmdlist[ncmd].cmd = opt;
|
||||
cmdlist[ncmd++].arg = list_optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (all_limits)
|
||||
{
|
||||
#ifdef NOTYET
|
||||
if (list) /* setting */
|
||||
{
|
||||
if (STREQ (list->word->word, "unlimited") == 0)
|
||||
{
|
||||
builtin_error (_("%s: invalid limit argument"), list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
return (set_all_limits (mode == 0 ? LIMIT_SOFT|LIMIT_HARD : mode, RLIM_INFINITY));
|
||||
}
|
||||
#endif
|
||||
print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
/* default is `ulimit -f' */
|
||||
if (ncmd == 0)
|
||||
{
|
||||
cmdlist[ncmd].cmd = 'f';
|
||||
/* `ulimit something' is same as `ulimit -f something' */
|
||||
cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
|
||||
if (list)
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* verify each command in the list. */
|
||||
for (c = 0; c < ncmd; c++)
|
||||
{
|
||||
limind = _findlim (cmdlist[c].cmd);
|
||||
if (limind == -1)
|
||||
{
|
||||
builtin_error (_("`%c': bad command"), cmdlist[c].cmd);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
for (c = 0; c < ncmd; c++)
|
||||
if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
ulimit_internal (cmd, cmdarg, mode, multiple)
|
||||
int cmd;
|
||||
char *cmdarg;
|
||||
int mode, multiple;
|
||||
{
|
||||
int opt, limind, setting;
|
||||
int block_factor;
|
||||
RLIMTYPE soft_limit, hard_limit, real_limit, limit;
|
||||
|
||||
setting = cmdarg != 0;
|
||||
limind = _findlim (cmd);
|
||||
if (mode == 0)
|
||||
mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
|
||||
opt = get_limit (limind, &soft_limit, &hard_limit);
|
||||
if (opt < 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot get limit: %s"), limits[limind].description,
|
||||
strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (setting == 0) /* print the value of the specified limit */
|
||||
{
|
||||
printone (limind, (mode & LIMIT_SOFT) ? soft_limit : hard_limit, multiple);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Setting the limit. */
|
||||
if (STREQ (cmdarg, "hard"))
|
||||
real_limit = hard_limit;
|
||||
else if (STREQ (cmdarg, "soft"))
|
||||
real_limit = soft_limit;
|
||||
else if (STREQ (cmdarg, "unlimited"))
|
||||
real_limit = RLIM_INFINITY;
|
||||
else if (all_digits (cmdarg))
|
||||
{
|
||||
limit = string_to_rlimtype (cmdarg);
|
||||
block_factor = BLOCKSIZE(limits[limind].block_factor);
|
||||
real_limit = limit * block_factor;
|
||||
|
||||
if ((real_limit / block_factor) != limit)
|
||||
{
|
||||
sh_erange (cmdarg, _("limit"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidnum (cmdarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (set_limit (limind, real_limit, mode) < 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot modify limit: %s"), limits[limind].description,
|
||||
strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
get_limit (ind, softlim, hardlim)
|
||||
int ind;
|
||||
RLIMTYPE *softlim, *hardlim;
|
||||
{
|
||||
RLIMTYPE value;
|
||||
#if defined (HAVE_RESOURCE)
|
||||
struct rlimit limit;
|
||||
#endif
|
||||
|
||||
if (limits[ind].parameter >= 256)
|
||||
{
|
||||
switch (limits[ind].parameter)
|
||||
{
|
||||
case RLIMIT_FILESIZE:
|
||||
if (filesize (&value) < 0)
|
||||
return -1;
|
||||
break;
|
||||
case RLIMIT_PIPESIZE:
|
||||
if (pipesize (&value) < 0)
|
||||
return -1;
|
||||
break;
|
||||
case RLIMIT_OPENFILES:
|
||||
value = (RLIMTYPE)getdtablesize ();
|
||||
break;
|
||||
case RLIMIT_VIRTMEM:
|
||||
return (getmaxvm (softlim, hardlim));
|
||||
case RLIMIT_MAXUPROC:
|
||||
if (getmaxuprc (&value) < 0)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
*softlim = *hardlim = value;
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (HAVE_RESOURCE)
|
||||
if (getrlimit (limits[ind].parameter, &limit) < 0)
|
||||
return -1;
|
||||
*softlim = limit.rlim_cur;
|
||||
*hardlim = limit.rlim_max;
|
||||
# if defined (HPUX9)
|
||||
if (limits[ind].parameter == RLIMIT_FILESIZE)
|
||||
{
|
||||
*softlim *= 512;
|
||||
*hardlim *= 512; /* Ugh. */
|
||||
}
|
||||
else
|
||||
# endif /* HPUX9 */
|
||||
return 0;
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
set_limit (ind, newlim, mode)
|
||||
int ind;
|
||||
RLIMTYPE newlim;
|
||||
int mode;
|
||||
{
|
||||
#if defined (HAVE_RESOURCE)
|
||||
struct rlimit limit;
|
||||
RLIMTYPE val;
|
||||
#endif
|
||||
|
||||
if (limits[ind].parameter >= 256)
|
||||
switch (limits[ind].parameter)
|
||||
{
|
||||
case RLIMIT_FILESIZE:
|
||||
#if !defined (HAVE_RESOURCE)
|
||||
return (ulimit (2, newlim / 512L));
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
case RLIMIT_OPENFILES:
|
||||
#if defined (HAVE_SETDTABLESIZE)
|
||||
# if defined (__CYGWIN__)
|
||||
/* Grrr... Cygwin declares setdtablesize as void. */
|
||||
setdtablesize (newlim);
|
||||
return 0;
|
||||
# else
|
||||
return (setdtablesize (newlim));
|
||||
# endif
|
||||
#endif
|
||||
case RLIMIT_PIPESIZE:
|
||||
case RLIMIT_VIRTMEM:
|
||||
case RLIMIT_MAXUPROC:
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (HAVE_RESOURCE)
|
||||
if (getrlimit (limits[ind].parameter, &limit) < 0)
|
||||
return -1;
|
||||
# if defined (HPUX9)
|
||||
if (limits[ind].parameter == RLIMIT_FILESIZE)
|
||||
newlim /= 512; /* Ugh. */
|
||||
# endif /* HPUX9 */
|
||||
val = (current_user.euid != 0 && newlim == RLIM_INFINITY &&
|
||||
(mode & LIMIT_HARD) == 0 && /* XXX -- test */
|
||||
(limit.rlim_cur <= limit.rlim_max))
|
||||
? limit.rlim_max : newlim;
|
||||
if (mode & LIMIT_SOFT)
|
||||
limit.rlim_cur = val;
|
||||
if (mode & LIMIT_HARD)
|
||||
limit.rlim_max = val;
|
||||
|
||||
return (setrlimit (limits[ind].parameter, &limit));
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
getmaxvm (softlim, hardlim)
|
||||
RLIMTYPE *softlim, *hardlim;
|
||||
{
|
||||
#if defined (HAVE_RESOURCE)
|
||||
struct rlimit datalim, stacklim;
|
||||
|
||||
if (getrlimit (RLIMIT_DATA, &datalim) < 0)
|
||||
return -1;
|
||||
|
||||
if (getrlimit (RLIMIT_STACK, &stacklim) < 0)
|
||||
return -1;
|
||||
|
||||
/* Protect against overflow. */
|
||||
*softlim = (datalim.rlim_cur / 1024L) + (stacklim.rlim_cur / 1024L);
|
||||
*hardlim = (datalim.rlim_max / 1024L) + (stacklim.rlim_max / 1024L);
|
||||
return 0;
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif /* HAVE_RESOURCE */
|
||||
}
|
||||
|
||||
static int
|
||||
filesize(valuep)
|
||||
RLIMTYPE *valuep;
|
||||
{
|
||||
#if !defined (HAVE_RESOURCE)
|
||||
long result;
|
||||
if ((result = ulimit (1, 0L)) < 0)
|
||||
return -1;
|
||||
else
|
||||
*valuep = (RLIMTYPE) result * 512;
|
||||
return 0;
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
pipesize (valuep)
|
||||
RLIMTYPE *valuep;
|
||||
{
|
||||
#if defined (PIPE_BUF)
|
||||
/* This is defined on Posix systems. */
|
||||
*valuep = (RLIMTYPE) PIPE_BUF;
|
||||
return 0;
|
||||
#else
|
||||
# if defined (_POSIX_PIPE_BUF)
|
||||
*valuep = (RLIMTYPE) _POSIX_PIPE_BUF;
|
||||
return 0;
|
||||
# else
|
||||
# if defined (PIPESIZE)
|
||||
/* This is defined by running a program from the Makefile. */
|
||||
*valuep = (RLIMTYPE) PIPESIZE;
|
||||
return 0;
|
||||
# else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
# endif /* PIPESIZE */
|
||||
# endif /* _POSIX_PIPE_BUF */
|
||||
#endif /* PIPE_BUF */
|
||||
}
|
||||
|
||||
static int
|
||||
getmaxuprc (valuep)
|
||||
RLIMTYPE *valuep;
|
||||
{
|
||||
long maxchild;
|
||||
|
||||
maxchild = getmaxchild ();
|
||||
if (maxchild < 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
*valuep = (RLIMTYPE) maxchild;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
print_all_limits (mode)
|
||||
int mode;
|
||||
{
|
||||
register int i;
|
||||
RLIMTYPE softlim, hardlim;
|
||||
|
||||
if (mode == 0)
|
||||
mode |= LIMIT_SOFT;
|
||||
|
||||
for (i = 0; limits[i].option > 0; i++)
|
||||
{
|
||||
if (get_limit (i, &softlim, &hardlim) == 0)
|
||||
printone (i, (mode & LIMIT_SOFT) ? softlim : hardlim, 1);
|
||||
else if (errno != EINVAL)
|
||||
builtin_error ("%s: cannot get limit: %s", limits[i].description,
|
||||
strerror (errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
printone (limind, curlim, pdesc)
|
||||
int limind;
|
||||
RLIMTYPE curlim;
|
||||
int pdesc;
|
||||
{
|
||||
char unitstr[64];
|
||||
int factor;
|
||||
|
||||
factor = BLOCKSIZE(limits[limind].block_factor);
|
||||
if (pdesc)
|
||||
{
|
||||
if (limits[limind].units)
|
||||
sprintf (unitstr, "(%s, -%c) ", limits[limind].units, limits[limind].option);
|
||||
else
|
||||
sprintf (unitstr, "(-%c) ", limits[limind].option);
|
||||
|
||||
printf ("%-20s %16s", limits[limind].description, unitstr);
|
||||
}
|
||||
if (curlim == RLIM_INFINITY)
|
||||
puts ("unlimited");
|
||||
else if (curlim == RLIM_SAVED_MAX)
|
||||
puts ("hard");
|
||||
else if (curlim == RLIM_SAVED_CUR)
|
||||
puts ("soft");
|
||||
else
|
||||
print_rlimtype ((curlim / factor), 1);
|
||||
}
|
||||
|
||||
/* Set all limits to NEWLIM. NEWLIM currently must be RLIM_INFINITY, which
|
||||
causes all limits to be set as high as possible depending on mode (like
|
||||
csh `unlimit'). Returns -1 if NEWLIM is invalid, 0 if all limits
|
||||
were set successfully, and 1 if at least one limit could not be set.
|
||||
|
||||
To raise all soft limits to their corresponding hard limits, use
|
||||
ulimit -S -a unlimited
|
||||
To attempt to raise all hard limits to infinity (superuser-only), use
|
||||
ulimit -H -a unlimited
|
||||
To attempt to raise all soft and hard limits to infinity, use
|
||||
ulimit -a unlimited
|
||||
*/
|
||||
|
||||
static int
|
||||
set_all_limits (mode, newlim)
|
||||
int mode;
|
||||
RLIMTYPE newlim;
|
||||
{
|
||||
register int i;
|
||||
int retval = 0;
|
||||
|
||||
if (newlim != RLIM_INFINITY)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mode == 0)
|
||||
mode = LIMIT_SOFT|LIMIT_HARD;
|
||||
|
||||
for (retval = i = 0; limits[i].option > 0; i++)
|
||||
if (set_limit (i, newlim, mode) < 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot modify limit: %s"), limits[i].description,
|
||||
strerror (errno));
|
||||
retval = 1;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif /* !_MINIX */
|
||||
@@ -1,316 +0,0 @@
|
||||
This file is umask.def, from which is created umask.c.
|
||||
It implements the builtin "umask" in Bash.
|
||||
|
||||
Copyright (C) 1987-2009 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
$PRODUCES umask.c
|
||||
|
||||
$BUILTIN umask
|
||||
$FUNCTION umask_builtin
|
||||
$SHORT_DOC umask [-p] [-S] [mode]
|
||||
Display or set file mode mask.
|
||||
|
||||
Sets the user file-creation mask to MODE. If MODE is omitted, prints
|
||||
the current value of the mask.
|
||||
|
||||
If MODE begins with a digit, it is interpreted as an octal number;
|
||||
otherwise it is a symbolic mode string like that accepted by chmod(1).
|
||||
|
||||
Options:
|
||||
-p if MODE is omitted, output in a form that may be reused as input
|
||||
-S makes the output symbolic; otherwise an octal number is output
|
||||
|
||||
Exit Status:
|
||||
Returns success unless MODE is invalid or an invalid option is given.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#include "filecntl.h"
|
||||
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <chartypes.h>
|
||||
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "posixstat.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#ifdef __LCC__
|
||||
#define mode_t int
|
||||
#endif
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* UMASK Builtin and Helpers */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
static void print_symbolic_umask __P((mode_t));
|
||||
static int symbolic_umask __P((WORD_LIST *));
|
||||
|
||||
/* Set or display the mask used by the system when creating files. Flag
|
||||
of -S means display the umask in a symbolic mode. */
|
||||
int
|
||||
umask_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int print_symbolically, opt, umask_value, pflag;
|
||||
mode_t umask_arg;
|
||||
|
||||
print_symbolically = pflag = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "Sp")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'S':
|
||||
print_symbolically++;
|
||||
break;
|
||||
case 'p':
|
||||
pflag++;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (list)
|
||||
{
|
||||
if (DIGIT (*list->word->word))
|
||||
{
|
||||
umask_value = read_octal (list->word->word);
|
||||
|
||||
/* Note that other shells just let you set the umask to zero
|
||||
by specifying a number out of range. This is a problem
|
||||
with those shells. We don't change the umask if the input
|
||||
is lousy. */
|
||||
if (umask_value == -1)
|
||||
{
|
||||
sh_erange (list->word->word, _("octal number"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
umask_value = symbolic_umask (list);
|
||||
if (umask_value == -1)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
umask_arg = (mode_t)umask_value;
|
||||
umask (umask_arg);
|
||||
if (print_symbolically)
|
||||
print_symbolic_umask (umask_arg);
|
||||
}
|
||||
else /* Display the UMASK for this user. */
|
||||
{
|
||||
umask_arg = umask (022);
|
||||
umask (umask_arg);
|
||||
|
||||
if (pflag)
|
||||
printf ("umask%s ", (print_symbolically ? " -S" : ""));
|
||||
if (print_symbolically)
|
||||
print_symbolic_umask (umask_arg);
|
||||
else
|
||||
printf ("%04lo\n", (unsigned long)umask_arg);
|
||||
}
|
||||
|
||||
return (sh_chkwrite (EXECUTION_SUCCESS));
|
||||
}
|
||||
|
||||
/* Print the umask in a symbolic form. In the output, a letter is
|
||||
printed if the corresponding bit is clear in the umask. */
|
||||
static void
|
||||
print_symbolic_umask (um)
|
||||
mode_t um;
|
||||
{
|
||||
char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
if ((um & S_IRUSR) == 0)
|
||||
ubits[i++] = 'r';
|
||||
if ((um & S_IWUSR) == 0)
|
||||
ubits[i++] = 'w';
|
||||
if ((um & S_IXUSR) == 0)
|
||||
ubits[i++] = 'x';
|
||||
ubits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if ((um & S_IRGRP) == 0)
|
||||
gbits[i++] = 'r';
|
||||
if ((um & S_IWGRP) == 0)
|
||||
gbits[i++] = 'w';
|
||||
if ((um & S_IXGRP) == 0)
|
||||
gbits[i++] = 'x';
|
||||
gbits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if ((um & S_IROTH) == 0)
|
||||
obits[i++] = 'r';
|
||||
if ((um & S_IWOTH) == 0)
|
||||
obits[i++] = 'w';
|
||||
if ((um & S_IXOTH) == 0)
|
||||
obits[i++] = 'x';
|
||||
obits[i] = '\0';
|
||||
|
||||
printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits);
|
||||
}
|
||||
|
||||
int
|
||||
parse_symbolic_mode (mode, initial_bits)
|
||||
char *mode;
|
||||
int initial_bits;
|
||||
{
|
||||
int who, op, perm, bits, c;
|
||||
char *s;
|
||||
|
||||
for (s = mode, bits = initial_bits;;)
|
||||
{
|
||||
who = op = perm = 0;
|
||||
|
||||
/* Parse the `who' portion of the symbolic mode clause. */
|
||||
while (member (*s, "agou"))
|
||||
{
|
||||
switch (c = *s++)
|
||||
{
|
||||
case 'u':
|
||||
who |= S_IRWXU;
|
||||
continue;
|
||||
case 'g':
|
||||
who |= S_IRWXG;
|
||||
continue;
|
||||
case 'o':
|
||||
who |= S_IRWXO;
|
||||
continue;
|
||||
case 'a':
|
||||
who |= S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The operation is now sitting in *s. */
|
||||
op = *s++;
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
case '-':
|
||||
case '=':
|
||||
break;
|
||||
default:
|
||||
builtin_error (_("`%c': invalid symbolic mode operator"), op);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Parse out the `perm' section of the symbolic mode clause. */
|
||||
while (member (*s, "rwx"))
|
||||
{
|
||||
c = *s++;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'r':
|
||||
perm |= S_IRUGO;
|
||||
break;
|
||||
case 'w':
|
||||
perm |= S_IWUGO;
|
||||
break;
|
||||
case 'x':
|
||||
perm |= S_IXUGO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now perform the operation or return an error for a
|
||||
bad permission string. */
|
||||
if (!*s || *s == ',')
|
||||
{
|
||||
if (who)
|
||||
perm &= who;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
bits |= perm;
|
||||
break;
|
||||
case '-':
|
||||
bits &= ~perm;
|
||||
break;
|
||||
case '=':
|
||||
if (who == 0)
|
||||
who = S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
bits &= ~who;
|
||||
bits |= perm;
|
||||
break;
|
||||
|
||||
/* No other values are possible. */
|
||||
}
|
||||
|
||||
if (*s == '\0')
|
||||
break;
|
||||
else
|
||||
s++; /* skip past ',' */
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin_error (_("`%c': invalid symbolic mode character"), *s);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
return (bits);
|
||||
}
|
||||
|
||||
/* Set the umask from a symbolic mode string similar to that accepted
|
||||
by chmod. If the -S argument is given, then print the umask in a
|
||||
symbolic form. */
|
||||
static int
|
||||
symbolic_umask (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int um, bits;
|
||||
|
||||
/* Get the initial umask. Don't change it yet. */
|
||||
um = umask (022);
|
||||
umask (um);
|
||||
|
||||
/* All work is done with the complement of the umask -- it's
|
||||
more intuitive and easier to deal with. It is complemented
|
||||
again before being returned. */
|
||||
bits = parse_symbolic_mode (list->word->word, ~um & 0777);
|
||||
if (bits == -1)
|
||||
return (-1);
|
||||
|
||||
um = ~bits & 0777;
|
||||
return (um);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
# This file is a shell script that caches the results of configure
|
||||
# tests for CYGWIN32 so they don't need to be done when cross-compiling.
|
||||
|
||||
# AC_FUNC_GETPGRP should also define GETPGRP_VOID
|
||||
ac_cv_func_getpgrp_void=${ac_cv_func_getpgrp_void='yes'}
|
||||
# AC_FUNC_SETVBUF_REVERSED should not define anything else
|
||||
ac_cv_func_setvbuf_reversed=${ac_cv_func_setvbuf_reversed='no'}
|
||||
# on CYGWIN32, system calls do not restart
|
||||
ac_cv_sys_restartable_syscalls=${ac_cv_sys_restartable_syscalls='no'}
|
||||
bash_cv_sys_restartable_syscalls=${bash_cv_sys_restartable_syscalls='no'}
|
||||
|
||||
# these may be necessary, but they are currently commented out
|
||||
#ac_cv_c_bigendian=${ac_cv_c_bigendian='no'}
|
||||
ac_cv_sizeof_char_p=${ac_cv_sizeof_char_p='4'}
|
||||
ac_cv_sizeof_int=${ac_cv_sizeof_int='4'}
|
||||
ac_cv_sizeof_long=${ac_cv_sizeof_long='4'}
|
||||
ac_cv_sizeof_double=${ac_cv_sizeof_double='8'}
|
||||
|
||||
bash_cv_dup2_broken=${bash_cv_dup2_broken='no'}
|
||||
bash_cv_pgrp_pipe=${bash_cv_pgrp_pipe='no'}
|
||||
bash_cv_type_rlimit=${bash_cv_type_rlimit='long'}
|
||||
bash_cv_decl_under_sys_siglist=${bash_cv_decl_under_sys_siglist='no'}
|
||||
bash_cv_under_sys_siglist=${bash_cv_under_sys_siglist='no'}
|
||||
bash_cv_sys_siglist=${bash_cv_sys_siglist='no'}
|
||||
bash_cv_opendir_not_robust=${bash_cv_opendir_not_robust='no'}
|
||||
bash_cv_getenv_redef=${bash_cv_getenv_redef='yes'}
|
||||
bash_cv_printf_declared=${bash_cv_printf_declared='yes'}
|
||||
bash_cv_ulimit_maxfds=${bash_cv_ulimit_maxfds='no'}
|
||||
bash_cv_getcwd_calls_popen=${bash_cv_getcwd_calls_popen='no'}
|
||||
bash_cv_must_reinstall_sighandlers=${bash_cv_must_reinstall_sighandlers='no'}
|
||||
bash_cv_job_control_missing=${bash_cv_job_control_missing='present'}
|
||||
bash_cv_sys_named_pipes=${bash_cv_sys_named_pipes='missing'}
|
||||
bash_cv_func_sigsetjmp=${bash_cv_func_sigsetjmp='missing'}
|
||||
bash_cv_mail_dir=${bash_cv_mail_dir='unknown'}
|
||||
bash_cv_func_strcoll_broken=${bash_cv_func_strcoll_broken='no'}
|
||||
|
||||
bash_cv_type_int32_t=${bash_cv_type_int32_t='int'}
|
||||
bash_cv_type_u_int32_t=${bash_cv_type_u_int32_t='int'}
|
||||
|
||||
ac_cv_type_bits64_t=${ac_cv_type_bits64_t='no'}
|
||||
|
||||
# end of cross-build/cygwin32.cache
|
||||
-1745
File diff suppressed because it is too large
Load Diff
@@ -1,314 +0,0 @@
|
||||
# This Makefile is for the Bash/documentation directory -*- text -*-.
|
||||
#
|
||||
# Copyright (C) 2003-2013 Free Software Foundation, Inc.
|
||||
|
||||
# This program 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.
|
||||
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
PACKAGE = @PACKAGE_NAME@
|
||||
VERSION = @PACKAGE_VERSION@
|
||||
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
|
||||
#
|
||||
SHELL = @MAKE_SHELL@
|
||||
RM = rm -f
|
||||
|
||||
topdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = .:@srcdir@
|
||||
|
||||
prefix = @prefix@
|
||||
exec_prefix = @exec_prefix@
|
||||
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
infodir = @infodir@
|
||||
|
||||
docdir = @docdir@
|
||||
|
||||
# set this to a directory name to have the HTML files installed
|
||||
htmldir = @htmldir@
|
||||
|
||||
# Support an alternate destination root directory for package building
|
||||
DESTDIR =
|
||||
|
||||
mandir = @mandir@
|
||||
manpfx = man
|
||||
|
||||
man1ext = .1
|
||||
man1dir = $(mandir)/$(manpfx)1
|
||||
man3ext = .3
|
||||
man3dir = $(mandir)/$(manpfx)3
|
||||
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
BUILD_DIR = @BUILD_DIR@
|
||||
|
||||
SUPPORT_SRCDIR = $(topdir)/support
|
||||
|
||||
# bad style
|
||||
RL_LIBDIR = $(topdir)/lib/readline
|
||||
|
||||
# unused
|
||||
TEXINDEX = texindex
|
||||
TEX = tex
|
||||
|
||||
MAKEINFO = makeinfo
|
||||
TEXI2DVI = ${SUPPORT_SRCDIR}/texi2dvi
|
||||
TEXI2HTML = ${SUPPORT_SRCDIR}/texi2html
|
||||
MAN2HTML = ${BUILD_DIR}/support/man2html
|
||||
HTMLPOST = ${srcdir}/htmlpost.sh
|
||||
INFOPOST = ${srcdir}/infopost.sh
|
||||
QUIETPS = #set this to -q to shut up dvips
|
||||
PAPERSIZE = letter # change to a4 for A4-size paper
|
||||
PSDPI = 600 # could be 300 if you like
|
||||
DVIPS = dvips -D ${PSDPI} $(QUIETPS) -t ${PAPERSIZE} -o $@ # tricky
|
||||
|
||||
TEXINPUTDIR = $(RL_LIBDIR)/doc
|
||||
SET_TEXINPUTS = TEXINPUTS=.:$(TEXINPUTDIR):$$TEXINPUTS
|
||||
|
||||
# These tools might not be available; they're not required
|
||||
DVIPDF = dvipdfm -o $@ -p ${PAPERSIZE}
|
||||
PSPDF = gs -sPAPERSIZE=${PAPERSIZE} -sDEVICE=pdfwrite -dNOPAUSE -dBATCH -sOutputFile=$@
|
||||
|
||||
MKDIRS = ${SUPPORT_SRCDIR}/mkdirs
|
||||
|
||||
# This should be a program that converts troff to an ascii-readable format
|
||||
NROFF = groff -Tascii
|
||||
|
||||
# This should be a program that converts troff to postscript
|
||||
GROFF = groff
|
||||
|
||||
HSUSER = $(RL_LIBDIR)/doc/hsuser.texi
|
||||
RLUSER = $(RL_LIBDIR)/doc/rluser.texi
|
||||
|
||||
BASHREF_FILES = $(srcdir)/bashref.texi $(srcdir)/fdl.texi $(srcdir)/version.texi
|
||||
|
||||
.SUFFIXES: .0 .1 .3 .ms .ps .txt .dvi .html .pdf
|
||||
|
||||
.1.ps:
|
||||
$(RM) $@
|
||||
-${GROFF} -man $< > $@
|
||||
|
||||
.1.0:
|
||||
$(RM) $@
|
||||
-${NROFF} -man $< > $@
|
||||
|
||||
.1.html:
|
||||
$(RM) $@
|
||||
-${MAN2HTML} $< | ${HTMLPOST} > $@
|
||||
|
||||
.ms.ps:
|
||||
$(RM) $@
|
||||
-${GROFF} -ms $< > $@
|
||||
|
||||
.ms.txt:
|
||||
$(RM) $@
|
||||
-${NROFF} -ms $< > $@
|
||||
|
||||
.3.ps:
|
||||
$(RM) $@
|
||||
-${GROFF} -man $< > $@
|
||||
|
||||
.3.0:
|
||||
$(RM) $@
|
||||
-${NROFF} -man $< > $@
|
||||
|
||||
.3.html:
|
||||
$(RM) $@
|
||||
-${MAN2HTML} $< > $@
|
||||
|
||||
.ps.pdf:
|
||||
$(RM) $@
|
||||
-${PSPDF} $<
|
||||
|
||||
.dvi.pdf:
|
||||
$(RM) $@
|
||||
-${DVIPDF} $<
|
||||
|
||||
.dvi.ps:
|
||||
${RM} $@
|
||||
-${DVIPS} $<
|
||||
|
||||
all: ps info dvi text html
|
||||
nodvi: ps info text html
|
||||
everything: all pdf
|
||||
|
||||
PSFILES = bash.ps bashbug.ps article.ps builtins.ps rbash.ps
|
||||
DVIFILES = bashref.dvi bashref.ps
|
||||
INFOFILES = bashref.info
|
||||
MAN0FILES = bash.0 bashbug.0 builtins.0 rbash.0
|
||||
HTMLFILES = bashref.html bash.html
|
||||
PDFFILES = bash.pdf bashref.pdf article.pdf rose94.pdf
|
||||
|
||||
ps: ${PSFILES}
|
||||
dvi: ${DVIFILES}
|
||||
info: ${INFOFILES}
|
||||
text: ${MAN0FILES}
|
||||
html: ${HTMLFILES}
|
||||
pdf: ${PDFFILES}
|
||||
|
||||
bashref.dvi: $(BASHREF_FILES) $(HSUSER) $(RLUSER)
|
||||
${SET_TEXINPUTS} $(TEXI2DVI) $(srcdir)/bashref.texi || { ${RM} $@ ; exit 1; }
|
||||
|
||||
bashref.info: $(BASHREF_FILES) $(HSUSER) $(RLUSER)
|
||||
$(MAKEINFO) --no-split -I$(TEXINPUTDIR) $(srcdir)/bashref.texi
|
||||
|
||||
bashref.html: $(BASHREF_FILES) $(HSUSER) $(RLUSER)
|
||||
$(TEXI2HTML) -menu -monolithic -I $(TEXINPUTDIR) $(srcdir)/bashref.texi
|
||||
|
||||
bash.info: bashref.info
|
||||
${SHELL} ${INFOPOST} < $(srcdir)/bashref.info > $@ ; \
|
||||
|
||||
bash.txt: bash.1
|
||||
bash.ps: bash.1
|
||||
bash.html: bash.1 $(MAN2HTML)
|
||||
bashbug.ps: bashbug.1
|
||||
builtins.ps: builtins.1 bash.1
|
||||
rbash.ps: rbash.1 bash.1
|
||||
bash.0: bash.1
|
||||
bashbug.0: bashbug.1
|
||||
builtins.0: builtins.1 bash.1
|
||||
rbash.0: rbash.1 bash.1
|
||||
article.ps: article.ms
|
||||
|
||||
bashref.ps: bashref.dvi
|
||||
|
||||
article.pdf: article.ps
|
||||
bashref.pdf: bashref.dvi
|
||||
bash.pdf: bash.ps
|
||||
rose94.pdf: rose94.ps
|
||||
|
||||
OTHER_DOCS = $(srcdir)/FAQ $(srcdir)/INTRO
|
||||
OTHER_INSTALLED_DOCS = FAQ INTRO
|
||||
|
||||
$(MAN2HTML): ${topdir}/support/man2html.c
|
||||
-( cd ${BUILD_DIR}/support ; ${MAKE} ${MFLAGS} man2html)
|
||||
|
||||
clean:
|
||||
$(RM) *.aux *.bak *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps \
|
||||
*.pgs *.bt *.bts *.rw *.rws *.fns *.kys *.tps *.vrs *.o
|
||||
${RM} core *.core
|
||||
|
||||
mostlyclean: clean
|
||||
$(RM) Makefile
|
||||
|
||||
distclean: clean maybe-clean
|
||||
$(RM) Makefile
|
||||
|
||||
maintainer-clean: clean
|
||||
${RM} ${PSFILES} ${DVIFILES} ${INFOFILES} ${MAN0FILES} ${HTMLFILES}
|
||||
${RM} ${CREATED_FAQ}
|
||||
$(RM) Makefile
|
||||
|
||||
maybe-clean:
|
||||
-if test "X$(topdir)" != "X$(BUILD_DIR)"; then \
|
||||
$(RM) ${PSFILES} ${DVIFILES} ${INFOFILES} ${MAN0FILES} ${HTMLFILES}; \
|
||||
fi
|
||||
|
||||
installdirs:
|
||||
-$(SHELL) $(SUPPORT_SRCDIR)/mkinstalldirs $(DESTDIR)$(man1dir)
|
||||
-$(SHELL) $(SUPPORT_SRCDIR)/mkinstalldirs $(DESTDIR)$(infodir)
|
||||
-$(SHELL) $(SUPPORT_SRCDIR)/mkinstalldirs $(DESTDIR)$(docdir)
|
||||
-if test -n "$(htmldir)" ; then \
|
||||
$(SHELL) $(SUPPORT_SRCDIR)/mkinstalldirs $(DESTDIR)$(htmldir) ; \
|
||||
fi
|
||||
|
||||
install: info installdirs bash.info
|
||||
-$(INSTALL_DATA) $(srcdir)/bash.1 $(DESTDIR)$(man1dir)/bash${man1ext}
|
||||
-$(INSTALL_DATA) $(srcdir)/bashbug.1 $(DESTDIR)$(man1dir)/bashbug${man1ext}
|
||||
-$(INSTALL_DATA) $(OTHER_DOCS) $(DESTDIR)$(docdir)
|
||||
# uncomment the next lines to install the builtins man page
|
||||
# sed 's:bash\.1:man1/&:' $(srcdir)/builtins.1 > $${TMPDIR:-/var/tmp}/builtins.1
|
||||
# -$(INSTALL_DATA) $${TMPDIR:-/var/tmp}/builtins.1 $(DESTDIR)$(man1dir)/bash_builtins${man1ext}
|
||||
# -$(RM) $${TMPDIR:-/var/tmp}/builtins.1
|
||||
-if test -f bash.info; then d=.; else d=$(srcdir); fi; \
|
||||
$(INSTALL_DATA) $$d/bash.info $(DESTDIR)$(infodir)/bash.info
|
||||
# run install-info if it is present to update the info directory
|
||||
if $(SHELL) -c 'install-info --version' >/dev/null 2>&1; then \
|
||||
install-info --dir-file=$(DESTDIR)$(infodir)/dir $(DESTDIR)$(infodir)/bash.info; \
|
||||
else true; fi
|
||||
# if htmldir is set, install the html files into that directory
|
||||
-if test -n "${htmldir}" ; then \
|
||||
$(INSTALL_DATA) $(srcdir)/bash.html $(DESTDIR)$(htmldir) ; \
|
||||
$(INSTALL_DATA) $(srcdir)/bashref.html $(DESTDIR)$(htmldir) ; \
|
||||
fi
|
||||
|
||||
install_builtins: installdirs
|
||||
sed 's:bash\.1:man1/&:' $(srcdir)/builtins.1 > $${TMPDIR:-/var/tmp}/builtins.1
|
||||
-$(INSTALL_DATA) $${TMPDIR:-/var/tmp}/builtins.1 $(DESTDIR)$(man1dir)/bash_builtins${man1ext}
|
||||
-$(RM) $${TMPDIR:-/var/tmp}/builtins.1
|
||||
|
||||
install_everything: install install_builtins
|
||||
|
||||
uninstall:
|
||||
-$(RM) $(DESTDIR)$(man1dir)/bash${man1ext} $(DESTDIR)$(man1dir)/bashbug${man1ext}
|
||||
-$(RM) $(DESTDIR)$(man1dir)/bash_builtins${man1ext}
|
||||
$(RM) $(DESTDIR)$(infodir)/bash.info
|
||||
-( cd $(DESTDIR)$(docdir) && $(RM) $(OTHER_INSTALLED_DOCS) )
|
||||
-if test -n "$(htmldir)" ; then \
|
||||
$(RM) $(DESTDIR)$(htmldir)/bash.html ; \
|
||||
$(RM) $(DESTDIR)$(htmldir)/bashref.html ; \
|
||||
fi
|
||||
|
||||
# for use by chet
|
||||
CREATED_FAQ = faq.news faq.news2 faq.mail faq.version
|
||||
|
||||
faq: ${CREATED_FAQ}
|
||||
|
||||
faq.version: FAQ.version FAQ
|
||||
sh mkfaqvers FAQ.version > $@
|
||||
|
||||
faq.headers.mail: FAQ.headers.mail FAQ
|
||||
sh mkfaqvers FAQ.headers.mail > $@
|
||||
|
||||
faq.headers.news: FAQ.headers.news FAQ
|
||||
sh mkfaqvers FAQ.headers.news > $@
|
||||
|
||||
faq.headers.news2: FAQ.headers.news2 FAQ
|
||||
sh mkfaqvers FAQ.headers.news2 > $@
|
||||
|
||||
faq.news: FAQ faq.headers.news faq.version
|
||||
$(RM) $@
|
||||
cat faq.headers.news faq.version FAQ > $@
|
||||
|
||||
faq.news2: FAQ faq.headers.news2 faq.version
|
||||
$(RM) $@
|
||||
cat faq.headers.news2 faq.version FAQ > $@
|
||||
|
||||
faq.mail: FAQ faq.headers.mail faq.version
|
||||
$(RM) $@
|
||||
cat faq.headers.mail faq.version FAQ > $@
|
||||
|
||||
inst: bashref.texi
|
||||
$(SHELL) ./mkinstall
|
||||
cmp -s INSTALL ../INSTALL || mv INSTALL ../INSTALL
|
||||
$(RM) INSTALL
|
||||
|
||||
posix: bashref.texi
|
||||
$(SHELL) ./mkposix
|
||||
cmp -s POSIX ../POSIX || mv POSIX ../POSIX
|
||||
$(RM) POSIX
|
||||
|
||||
rbash: bashref.texi
|
||||
$(SH) ./mkrbash
|
||||
cmp -s RBASH ../RBASH || mv RBASH ../RBASH
|
||||
$(RM) RBASH
|
||||
|
||||
xdist: pdf inst posix rbash
|
||||
-10315
File diff suppressed because it is too large
Load Diff
-8727
File diff suppressed because it is too large
Load Diff
@@ -1,10 +0,0 @@
|
||||
@ignore
|
||||
Copyright (C) 1988-2013 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set LASTCHANGE Mon Oct 14 11:51:31 EDT 2013
|
||||
|
||||
@set EDITION 4.3
|
||||
@set VERSION 4.3
|
||||
@set UPDATED 14 October 2013
|
||||
@set UPDATED-MONTH October 2013
|
||||
@@ -1,238 +0,0 @@
|
||||
#
|
||||
# Simple makefile for the sample loadable builtins
|
||||
#
|
||||
# Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
|
||||
# This program 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.
|
||||
|
||||
# This program 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 this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
# Include some boilerplate Gnu makefile definitions.
|
||||
prefix = @prefix@
|
||||
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
infodir = @infodir@
|
||||
includedir = @includedir@
|
||||
|
||||
topdir = @top_srcdir@
|
||||
BUILD_DIR = @BUILD_DIR@
|
||||
srcdir = @srcdir@
|
||||
VPATH = .:@srcdir@
|
||||
|
||||
@SET_MAKE@
|
||||
CC = @CC@
|
||||
RM = rm -f
|
||||
|
||||
SHELL = @MAKE_SHELL@
|
||||
|
||||
host_os = @host_os@
|
||||
host_cpu = @host_cpu@
|
||||
host_vendor = @host_vendor@
|
||||
|
||||
CFLAGS = @CFLAGS@
|
||||
LOCAL_CFLAGS = @LOCAL_CFLAGS@
|
||||
DEFS = @DEFS@
|
||||
LOCAL_DEFS = @LOCAL_DEFS@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
|
||||
BASHINCDIR = ${topdir}/include
|
||||
|
||||
LIBBUILD = ${BUILD_DIR}/lib
|
||||
|
||||
INTL_LIBSRC = ${topdir}/lib/intl
|
||||
INTL_BUILDDIR = ${LIBBUILD}/intl
|
||||
INTL_INC = @INTL_INC@
|
||||
LIBINTL_H = @LIBINTL_H@
|
||||
|
||||
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) $(CFLAGS)
|
||||
|
||||
#
|
||||
# These values are generated for configure by ${topdir}/support/shobj-conf.
|
||||
# If your system is not supported by that script, but includes facilities for
|
||||
# dynamic loading of shared objects, please update the script and send the
|
||||
# changes to bash-maintainers@gnu.org.
|
||||
#
|
||||
SHOBJ_CC = @SHOBJ_CC@
|
||||
SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
|
||||
SHOBJ_LD = @SHOBJ_LD@
|
||||
SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@
|
||||
SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
|
||||
SHOBJ_LIBS = @SHOBJ_LIBS@
|
||||
SHOBJ_STATUS = @SHOBJ_STATUS@
|
||||
|
||||
INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \
|
||||
-I$(BASHINCDIR) -I$(BUILD_DIR) -I$(LIBBUILD) \
|
||||
-I$(BUILD_DIR)/builtins $(INTL_INC)
|
||||
|
||||
.c.o:
|
||||
$(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CCFLAGS) $(INC) -c -o $@ $<
|
||||
|
||||
|
||||
ALLPROG = print truefalse sleep pushd finfo logname basename dirname \
|
||||
tty pathchk tee head mkdir rmdir printenv id whoami \
|
||||
uname sync push ln unlink cut realpath getconf strftime
|
||||
OTHERPROG = necho hello cat
|
||||
|
||||
all: $(SHOBJ_STATUS)
|
||||
|
||||
supported: $(ALLPROG)
|
||||
others: $(OTHERPROG)
|
||||
|
||||
unsupported:
|
||||
@echo "Your system (${host_os}) is not supported by the"
|
||||
@echo "${topdir}/support/shobj-conf script."
|
||||
@echo "If your operating system provides facilities for dynamic"
|
||||
@echo "loading of shared objects using the dlopen(3) interface,"
|
||||
@echo "please update the script and re-run configure.
|
||||
@echo "Please send the changes you made to bash-maintainers@gnu.org"
|
||||
@echo "for inclusion in future bash releases."
|
||||
|
||||
everything: supported others
|
||||
|
||||
print: print.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS)
|
||||
|
||||
necho: necho.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS)
|
||||
|
||||
getconf: getconf.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS)
|
||||
|
||||
hello: hello.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS)
|
||||
|
||||
truefalse: truefalse.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS)
|
||||
|
||||
sleep: sleep.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS)
|
||||
|
||||
finfo: finfo.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS)
|
||||
|
||||
cat: cat.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS)
|
||||
|
||||
logname: logname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS)
|
||||
|
||||
basename: basename.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS)
|
||||
|
||||
dirname: dirname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS)
|
||||
|
||||
tty: tty.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS)
|
||||
|
||||
pathchk: pathchk.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS)
|
||||
|
||||
tee: tee.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS)
|
||||
|
||||
mkdir: mkdir.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS)
|
||||
|
||||
rmdir: rmdir.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS)
|
||||
|
||||
head: head.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS)
|
||||
|
||||
printenv: printenv.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS)
|
||||
|
||||
id: id.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS)
|
||||
|
||||
whoami: whoami.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS)
|
||||
|
||||
uname: uname.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS)
|
||||
|
||||
sync: sync.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS)
|
||||
|
||||
push: push.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS)
|
||||
|
||||
ln: ln.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS)
|
||||
|
||||
unlink: unlink.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS)
|
||||
|
||||
cut: cut.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cut.o $(SHOBJ_LIBS)
|
||||
|
||||
realpath: realpath.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ realpath.o $(SHOBJ_LIBS)
|
||||
|
||||
strftime: strftime.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ strftime.o $(SHOBJ_LIBS)
|
||||
|
||||
# pushd is a special case. We use the same source that the builtin version
|
||||
# uses, with special compilation options.
|
||||
#
|
||||
pushd.c: ${topdir}/builtins/pushd.def
|
||||
$(RM) $@
|
||||
${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def
|
||||
|
||||
pushd.o: pushd.c
|
||||
$(RM) $@
|
||||
$(SHOBJ_CC) -DHAVE_CONFIG_H -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(CPPFLAGS) $(INC) -c -o $@ $<
|
||||
|
||||
pushd: pushd.o
|
||||
$(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS)
|
||||
|
||||
clean:
|
||||
$(RM) $(ALLPROG) $(OTHERPROG) *.o
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
mostlyclean: clean
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
distclean maintainer-clean: clean
|
||||
$(RM) Makefile pushd.c
|
||||
-( cd perl && ${MAKE} ${MFLAGS} $@ )
|
||||
|
||||
print.o: print.c
|
||||
truefalse.o: truefalse.c
|
||||
sleep.o: sleep.c
|
||||
finfo.o: finfo.c
|
||||
logname.o: logname.c
|
||||
basename.o: basename.c
|
||||
dirname.o: dirname.c
|
||||
tty.o: tty.c
|
||||
pathchk.o: pathchk.c
|
||||
tee.o: tee.c
|
||||
head.o: head.c
|
||||
rmdir.o: rmdir.c
|
||||
necho.o: necho.c
|
||||
getconf.o: getconf.c
|
||||
hello.o: hello.c
|
||||
cat.o: cat.c
|
||||
printenv.o: printenv.c
|
||||
id.o: id.c
|
||||
whoami.o: whoami.c
|
||||
uname.o: uname.c
|
||||
sync.o: sync.c
|
||||
push.o: push.c
|
||||
mkdir.o: mkdir.c
|
||||
realpath.o: realpath.c
|
||||
strftime.o: strftime.c
|
||||
-5413
File diff suppressed because it is too large
Load Diff
@@ -1,663 +0,0 @@
|
||||
/* input.c -- functions to perform buffered input with synchronization. */
|
||||
|
||||
/* Copyright (C) 1992-2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
#include "filecntl.h"
|
||||
#include "posixstat.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "command.h"
|
||||
#include "general.h"
|
||||
#include "input.h"
|
||||
#include "error.h"
|
||||
#include "externs.h"
|
||||
#include "quit.h"
|
||||
#include "trap.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
#if defined (EAGAIN)
|
||||
# define X_EAGAIN EAGAIN
|
||||
#else
|
||||
# define X_EAGAIN -99
|
||||
#endif
|
||||
|
||||
#if defined (EWOULDBLOCK)
|
||||
# define X_EWOULDBLOCK EWOULDBLOCK
|
||||
#else
|
||||
# define X_EWOULDBLOCK -99
|
||||
#endif
|
||||
|
||||
extern void termsig_handler __P((int));
|
||||
|
||||
/* Functions to handle reading input on systems that don't restart read(2)
|
||||
if a signal is received. */
|
||||
|
||||
static char localbuf[128];
|
||||
static int local_index = 0, local_bufused = 0;
|
||||
|
||||
/* Posix and USG systems do not guarantee to restart read () if it is
|
||||
interrupted by a signal. We do the read ourselves, and restart it
|
||||
if it returns EINTR. */
|
||||
int
|
||||
getc_with_restart (stream)
|
||||
FILE *stream;
|
||||
{
|
||||
unsigned char uc;
|
||||
|
||||
CHECK_TERMSIG;
|
||||
|
||||
/* Try local buffering to reduce the number of read(2) calls. */
|
||||
if (local_index == local_bufused || local_bufused == 0)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
QUIT;
|
||||
run_pending_traps ();
|
||||
|
||||
local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
|
||||
if (local_bufused > 0)
|
||||
break;
|
||||
else if (local_bufused == 0)
|
||||
{
|
||||
local_index = 0;
|
||||
return EOF;
|
||||
}
|
||||
else if (errno == X_EAGAIN || errno == X_EWOULDBLOCK)
|
||||
{
|
||||
if (sh_unset_nodelay_mode (fileno (stream)) < 0)
|
||||
{
|
||||
sys_error (_("cannot reset nodelay mode for fd %d"), fileno (stream));
|
||||
return EOF;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (errno != EINTR)
|
||||
{
|
||||
local_index = 0;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
local_index = 0;
|
||||
}
|
||||
uc = localbuf[local_index++];
|
||||
return uc;
|
||||
}
|
||||
|
||||
int
|
||||
ungetc_with_restart (c, stream)
|
||||
int c;
|
||||
FILE *stream;
|
||||
{
|
||||
if (local_index == 0 || c == EOF)
|
||||
return EOF;
|
||||
localbuf[--local_index] = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
|
||||
/* A facility similar to stdio, but input-only. */
|
||||
|
||||
#if defined (USING_BASH_MALLOC)
|
||||
# define MAX_INPUT_BUFFER_SIZE 8176
|
||||
#else
|
||||
# define MAX_INPUT_BUFFER_SIZE 8192
|
||||
#endif
|
||||
|
||||
#if !defined (SEEK_CUR)
|
||||
# define SEEK_CUR 1
|
||||
#endif /* !SEEK_CUR */
|
||||
|
||||
#ifdef max
|
||||
# undef max
|
||||
#endif
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#ifdef min
|
||||
# undef min
|
||||
#endif
|
||||
#define min(a, b) ((a) > (b) ? (b) : (a))
|
||||
|
||||
extern int interactive_shell;
|
||||
|
||||
int bash_input_fd_changed;
|
||||
|
||||
/* This provides a way to map from a file descriptor to the buffer
|
||||
associated with that file descriptor, rather than just the other
|
||||
way around. This is needed so that buffers are managed properly
|
||||
in constructs like 3<&4. buffers[x]->b_fd == x -- that is how the
|
||||
correspondence is maintained. */
|
||||
static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
|
||||
static int nbuffers;
|
||||
|
||||
#define ALLOCATE_BUFFERS(n) \
|
||||
do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
|
||||
|
||||
/* Make sure `buffers' has at least N elements. */
|
||||
static void
|
||||
allocate_buffers (n)
|
||||
int n;
|
||||
{
|
||||
register int i, orig_nbuffers;
|
||||
|
||||
orig_nbuffers = nbuffers;
|
||||
nbuffers = n + 20;
|
||||
buffers = (BUFFERED_STREAM **)xrealloc
|
||||
(buffers, nbuffers * sizeof (BUFFERED_STREAM *));
|
||||
|
||||
/* Zero out the new buffers. */
|
||||
for (i = orig_nbuffers; i < nbuffers; i++)
|
||||
buffers[i] = (BUFFERED_STREAM *)NULL;
|
||||
}
|
||||
|
||||
/* Construct and return a BUFFERED_STREAM corresponding to file descriptor
|
||||
FD, using BUFFER. */
|
||||
static BUFFERED_STREAM *
|
||||
make_buffered_stream (fd, buffer, bufsize)
|
||||
int fd;
|
||||
char *buffer;
|
||||
size_t bufsize;
|
||||
{
|
||||
BUFFERED_STREAM *bp;
|
||||
|
||||
bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
|
||||
ALLOCATE_BUFFERS (fd);
|
||||
buffers[fd] = bp;
|
||||
bp->b_fd = fd;
|
||||
bp->b_buffer = buffer;
|
||||
bp->b_size = bufsize;
|
||||
bp->b_used = bp->b_inputp = bp->b_flag = 0;
|
||||
if (bufsize == 1)
|
||||
bp->b_flag |= B_UNBUFF;
|
||||
if (O_TEXT && (fcntl (fd, F_GETFL) & O_TEXT) != 0)
|
||||
bp->b_flag |= O_TEXT;
|
||||
return (bp);
|
||||
}
|
||||
|
||||
/* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
|
||||
static BUFFERED_STREAM *
|
||||
copy_buffered_stream (bp)
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
BUFFERED_STREAM *nbp;
|
||||
|
||||
if (!bp)
|
||||
return ((BUFFERED_STREAM *)NULL);
|
||||
|
||||
nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
|
||||
xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM));
|
||||
return (nbp);
|
||||
}
|
||||
|
||||
int
|
||||
set_bash_input_fd (fd)
|
||||
int fd;
|
||||
{
|
||||
if (bash_input.type == st_bstream)
|
||||
bash_input.location.buffered_fd = fd;
|
||||
else if (interactive_shell == 0)
|
||||
default_buffered_input = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fd_is_bash_input (fd)
|
||||
int fd;
|
||||
{
|
||||
if (bash_input.type == st_bstream && bash_input.location.buffered_fd == fd)
|
||||
return 1;
|
||||
else if (interactive_shell == 0 && default_buffered_input == fd)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the buffered stream corresponding to file descriptor FD (which bash
|
||||
is using to read input) to a buffered stream associated with NEW_FD. If
|
||||
NEW_FD is -1, a new file descriptor is allocated with fcntl. The new
|
||||
file descriptor is returned on success, -1 on error. */
|
||||
int
|
||||
save_bash_input (fd, new_fd)
|
||||
int fd, new_fd;
|
||||
{
|
||||
int nfd;
|
||||
|
||||
/* Sync the stream so we can re-read from the new file descriptor. We
|
||||
might be able to avoid this by copying the buffered stream verbatim
|
||||
to the new file descriptor. */
|
||||
if (buffers[fd])
|
||||
sync_buffered_stream (fd);
|
||||
|
||||
/* Now take care of duplicating the file descriptor that bash is
|
||||
using for input, so we can reinitialize it later. */
|
||||
nfd = (new_fd == -1) ? fcntl (fd, F_DUPFD, 10) : new_fd;
|
||||
if (nfd == -1)
|
||||
{
|
||||
if (fcntl (fd, F_GETFD, 0) == 0)
|
||||
sys_error (_("cannot allocate new file descriptor for bash input from fd %d"), fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffers[nfd])
|
||||
{
|
||||
/* What's this? A stray buffer without an associated open file
|
||||
descriptor? Free up the buffer and report the error. */
|
||||
internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
|
||||
free_buffered_stream (buffers[nfd]);
|
||||
}
|
||||
|
||||
/* Reinitialize bash_input.location. */
|
||||
if (bash_input.type == st_bstream)
|
||||
{
|
||||
bash_input.location.buffered_fd = nfd;
|
||||
fd_to_buffered_stream (nfd);
|
||||
close_buffered_fd (fd); /* XXX */
|
||||
}
|
||||
else
|
||||
/* If the current input type is not a buffered stream, but the shell
|
||||
is not interactive and therefore using a buffered stream to read
|
||||
input (e.g. with an `eval exec 3>output' inside a script), note
|
||||
that the input fd has been changed. pop_stream() looks at this
|
||||
value and adjusts the input fd to the new value of
|
||||
default_buffered_input accordingly. */
|
||||
bash_input_fd_changed++;
|
||||
|
||||
if (default_buffered_input == fd)
|
||||
default_buffered_input = nfd;
|
||||
|
||||
SET_CLOSE_ON_EXEC (nfd);
|
||||
return nfd;
|
||||
}
|
||||
|
||||
/* Check that file descriptor FD is not the one that bash is currently
|
||||
using to read input from a script. FD is about to be duplicated onto,
|
||||
which means that the kernel will close it for us. If FD is the bash
|
||||
input file descriptor, we need to seek backwards in the script (if
|
||||
possible and necessary -- scripts read from stdin are still unbuffered),
|
||||
allocate a new file descriptor to use for bash input, and re-initialize
|
||||
the buffered stream. Make sure the file descriptor used to save bash
|
||||
input is set close-on-exec. Returns 0 on success, -1 on failure. This
|
||||
works only if fd is > 0 -- if fd == 0 and bash is reading input from
|
||||
fd 0, sync_buffered_stream is used instead, to cooperate with input
|
||||
redirection (look at redir.c:add_undo_redirect()). */
|
||||
int
|
||||
check_bash_input (fd)
|
||||
int fd;
|
||||
{
|
||||
if (fd_is_bash_input (fd))
|
||||
{
|
||||
if (fd > 0)
|
||||
return ((save_bash_input (fd, -1) == -1) ? -1 : 0);
|
||||
else if (fd == 0)
|
||||
return ((sync_buffered_stream (fd) == -1) ? -1 : 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is the buffered stream analogue of dup2(fd1, fd2). The
|
||||
BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists.
|
||||
BUFFERS[fd1] is copied to BUFFERS[fd2]. This is called by the
|
||||
redirect code for constructs like 4<&0 and 3</etc/rc.local. */
|
||||
int
|
||||
duplicate_buffered_stream (fd1, fd2)
|
||||
int fd1, fd2;
|
||||
{
|
||||
int is_bash_input, m;
|
||||
|
||||
if (fd1 == fd2)
|
||||
return 0;
|
||||
|
||||
m = max (fd1, fd2);
|
||||
ALLOCATE_BUFFERS (m);
|
||||
|
||||
/* If FD2 is the file descriptor bash is currently using for shell input,
|
||||
we need to do some extra work to make sure that the buffered stream
|
||||
actually exists (it might not if fd1 was not active, and the copy
|
||||
didn't actually do anything). */
|
||||
is_bash_input = (bash_input.type == st_bstream) &&
|
||||
(bash_input.location.buffered_fd == fd2);
|
||||
|
||||
if (buffers[fd2])
|
||||
{
|
||||
/* If the two objects share the same b_buffer, don't free it. */
|
||||
if (buffers[fd1] && buffers[fd1]->b_buffer && buffers[fd1]->b_buffer == buffers[fd2]->b_buffer)
|
||||
buffers[fd2] = (BUFFERED_STREAM *)NULL;
|
||||
else
|
||||
free_buffered_stream (buffers[fd2]);
|
||||
}
|
||||
buffers[fd2] = copy_buffered_stream (buffers[fd1]);
|
||||
if (buffers[fd2])
|
||||
buffers[fd2]->b_fd = fd2;
|
||||
|
||||
if (is_bash_input)
|
||||
{
|
||||
if (!buffers[fd2])
|
||||
fd_to_buffered_stream (fd2);
|
||||
buffers[fd2]->b_flag |= B_WASBASHINPUT;
|
||||
}
|
||||
|
||||
return (fd2);
|
||||
}
|
||||
|
||||
/* Return 1 if a seek on FD will succeed. */
|
||||
#define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
|
||||
|
||||
/* Take FD, a file descriptor, and create and return a buffered stream
|
||||
corresponding to it. If something is wrong and the file descriptor
|
||||
is invalid, return a NULL stream. */
|
||||
BUFFERED_STREAM *
|
||||
fd_to_buffered_stream (fd)
|
||||
int fd;
|
||||
{
|
||||
char *buffer;
|
||||
size_t size;
|
||||
struct stat sb;
|
||||
|
||||
if (fstat (fd, &sb) < 0)
|
||||
{
|
||||
close (fd);
|
||||
return ((BUFFERED_STREAM *)NULL);
|
||||
}
|
||||
|
||||
size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1;
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
buffer = (char *)xmalloc (size);
|
||||
|
||||
return (make_buffered_stream (fd, buffer, size));
|
||||
}
|
||||
|
||||
/* Return a buffered stream corresponding to FILE, a file name. */
|
||||
BUFFERED_STREAM *
|
||||
open_buffered_stream (file)
|
||||
char *file;
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open (file, O_RDONLY);
|
||||
return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
|
||||
}
|
||||
|
||||
/* Deallocate a buffered stream and free up its resources. Make sure we
|
||||
zero out the slot in BUFFERS that points to BP. */
|
||||
void
|
||||
free_buffered_stream (bp)
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!bp)
|
||||
return;
|
||||
|
||||
n = bp->b_fd;
|
||||
if (bp->b_buffer)
|
||||
free (bp->b_buffer);
|
||||
free (bp);
|
||||
buffers[n] = (BUFFERED_STREAM *)NULL;
|
||||
}
|
||||
|
||||
/* Close the file descriptor associated with BP, a buffered stream, and free
|
||||
up the stream. Return the status of closing BP's file descriptor. */
|
||||
int
|
||||
close_buffered_stream (bp)
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (!bp)
|
||||
return (0);
|
||||
fd = bp->b_fd;
|
||||
free_buffered_stream (bp);
|
||||
return (close (fd));
|
||||
}
|
||||
|
||||
/* Deallocate the buffered stream associated with file descriptor FD, and
|
||||
close FD. Return the status of the close on FD. */
|
||||
int
|
||||
close_buffered_fd (fd)
|
||||
int fd;
|
||||
{
|
||||
if (fd < 0)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
if (fd >= nbuffers || !buffers || !buffers[fd])
|
||||
return (close (fd));
|
||||
return (close_buffered_stream (buffers[fd]));
|
||||
}
|
||||
|
||||
/* Make the BUFFERED_STREAM associated with buffers[FD] be BP, and return
|
||||
the old BUFFERED_STREAM. */
|
||||
BUFFERED_STREAM *
|
||||
set_buffered_stream (fd, bp)
|
||||
int fd;
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
BUFFERED_STREAM *ret;
|
||||
|
||||
ret = buffers[fd];
|
||||
buffers[fd] = bp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read a buffer full of characters from BP, a buffered stream. */
|
||||
static int
|
||||
b_fill_buffer (bp)
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
ssize_t nr;
|
||||
off_t o;
|
||||
|
||||
CHECK_TERMSIG;
|
||||
/* In an environment where text and binary files are treated differently,
|
||||
compensate for lseek() on text files returning an offset different from
|
||||
the count of characters read() returns. Text-mode streams have to be
|
||||
treated as unbuffered. */
|
||||
if ((bp->b_flag & (B_TEXT | B_UNBUFF)) == B_TEXT)
|
||||
{
|
||||
o = lseek (bp->b_fd, 0, SEEK_CUR);
|
||||
nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
|
||||
if (nr > 0 && nr < lseek (bp->b_fd, 0, SEEK_CUR) - o)
|
||||
{
|
||||
lseek (bp->b_fd, o, SEEK_SET);
|
||||
bp->b_flag |= B_UNBUFF;
|
||||
bp->b_size = 1;
|
||||
nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
|
||||
if (nr <= 0)
|
||||
{
|
||||
bp->b_used = 0;
|
||||
bp->b_buffer[0] = 0;
|
||||
if (nr == 0)
|
||||
bp->b_flag |= B_EOF;
|
||||
else
|
||||
bp->b_flag |= B_ERROR;
|
||||
return (EOF);
|
||||
}
|
||||
|
||||
bp->b_used = nr;
|
||||
bp->b_inputp = 0;
|
||||
return (bp->b_buffer[bp->b_inputp++] & 0xFF);
|
||||
}
|
||||
|
||||
/* Get a character from buffered stream BP. */
|
||||
#define bufstream_getc(bp) \
|
||||
(bp->b_inputp == bp->b_used || !bp->b_used) \
|
||||
? b_fill_buffer (bp) \
|
||||
: bp->b_buffer[bp->b_inputp++] & 0xFF
|
||||
|
||||
/* Push C back onto buffered stream BP. */
|
||||
static int
|
||||
bufstream_ungetc(c, bp)
|
||||
int c;
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
if (c == EOF || bp->b_inputp == 0)
|
||||
return (EOF);
|
||||
|
||||
bp->b_buffer[--bp->b_inputp] = c;
|
||||
return (c);
|
||||
}
|
||||
|
||||
/* Seek backwards on file BFD to synchronize what we've read so far
|
||||
with the underlying file pointer. */
|
||||
int
|
||||
sync_buffered_stream (bfd)
|
||||
int bfd;
|
||||
{
|
||||
BUFFERED_STREAM *bp;
|
||||
off_t chars_left;
|
||||
|
||||
if (buffers == 0 || (bp = buffers[bfd]) == 0)
|
||||
return (-1);
|
||||
|
||||
chars_left = bp->b_used - bp->b_inputp;
|
||||
if (chars_left)
|
||||
lseek (bp->b_fd, -chars_left, SEEK_CUR);
|
||||
bp->b_used = bp->b_inputp = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
buffered_getchar ()
|
||||
{
|
||||
CHECK_TERMSIG;
|
||||
|
||||
#if !defined (DJGPP)
|
||||
return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
|
||||
#else
|
||||
/* On DJGPP, ignore \r. */
|
||||
int ch;
|
||||
while ((ch = bufstream_getc (buffers[bash_input.location.buffered_fd])) == '\r')
|
||||
;
|
||||
return ch;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
buffered_ungetchar (c)
|
||||
int c;
|
||||
{
|
||||
return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
|
||||
}
|
||||
|
||||
/* Make input come from file descriptor BFD through a buffered stream. */
|
||||
void
|
||||
with_input_from_buffered_stream (bfd, name)
|
||||
int bfd;
|
||||
char *name;
|
||||
{
|
||||
INPUT_STREAM location;
|
||||
BUFFERED_STREAM *bp;
|
||||
|
||||
location.buffered_fd = bfd;
|
||||
/* Make sure the buffered stream exists. */
|
||||
bp = fd_to_buffered_stream (bfd);
|
||||
init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
|
||||
buffered_ungetchar, st_bstream, name, location);
|
||||
}
|
||||
|
||||
#if defined (TEST)
|
||||
void *
|
||||
xmalloc(s)
|
||||
int s;
|
||||
{
|
||||
return (malloc (s));
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc(s, size)
|
||||
char *s;
|
||||
int size;
|
||||
{
|
||||
if (!s)
|
||||
return(malloc (size));
|
||||
else
|
||||
return(realloc (s, size));
|
||||
}
|
||||
|
||||
void
|
||||
init_yy_io ()
|
||||
{
|
||||
}
|
||||
|
||||
process(bp)
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = bufstream_getc(bp)) != EOF)
|
||||
putchar(c);
|
||||
}
|
||||
|
||||
BASH_INPUT bash_input;
|
||||
|
||||
struct stat dsb; /* can be used from gdb */
|
||||
|
||||
/* imitate /bin/cat */
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
register int i;
|
||||
BUFFERED_STREAM *bp;
|
||||
|
||||
if (argc == 1) {
|
||||
bp = fd_to_buffered_stream (0);
|
||||
process(bp);
|
||||
exit(0);
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-' && argv[i][1] == '\0') {
|
||||
bp = fd_to_buffered_stream (0);
|
||||
if (!bp)
|
||||
continue;
|
||||
process(bp);
|
||||
free_buffered_stream (bp);
|
||||
} else {
|
||||
bp = open_buffered_stream (argv[i]);
|
||||
if (!bp)
|
||||
continue;
|
||||
process(bp);
|
||||
close_buffered_stream (bp);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
#endif /* TEST */
|
||||
#endif /* BUFFERED_INPUT */
|
||||
-1358
File diff suppressed because it is too large
Load Diff
@@ -1,42 +0,0 @@
|
||||
/* File-name wildcard pattern matching for GNU.
|
||||
Copyright (C) 1985, 1988, 1989, 2008,2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _GLOB_H_
|
||||
#define _GLOB_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
#define GX_MARKDIRS 0x001 /* mark directory names with trailing `/' */
|
||||
#define GX_NOCASE 0x002 /* ignore case */
|
||||
#define GX_MATCHDOT 0x004 /* match `.' literally */
|
||||
#define GX_MATCHDIRS 0x008 /* match only directory names */
|
||||
#define GX_ALLDIRS 0x010 /* match all directory names, no others */
|
||||
#define GX_NULLDIR 0x100 /* internal -- no directory preceding pattern */
|
||||
#define GX_ADDCURDIR 0x200 /* internal -- add passed directory name */
|
||||
#define GX_GLOBSTAR 0x400 /* turn on special handling of ** */
|
||||
|
||||
extern int glob_pattern_p __P((const char *));
|
||||
extern char **glob_vector __P((char *, char *, int));
|
||||
extern char **glob_filename __P((char *, int));
|
||||
|
||||
extern char *glob_error_return;
|
||||
extern int noglob_dot_filenames;
|
||||
extern int glob_ignore_case;
|
||||
|
||||
#endif /* _GLOB_H_ */
|
||||
@@ -1,376 +0,0 @@
|
||||
/* gmisc.c -- miscellaneous pattern matching utility functions for Bash.
|
||||
|
||||
Copyright (C) 2010 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shmbutil.h"
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
#ifndef LPAREN
|
||||
# define LPAREN '('
|
||||
#endif
|
||||
#ifndef RPAREN
|
||||
# define RPAREN ')'
|
||||
#endif
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
#define WLPAREN L'('
|
||||
#define WRPAREN L')'
|
||||
|
||||
/* Return 1 of the first character of WSTRING could match the first
|
||||
character of pattern WPAT. Wide character version. */
|
||||
int
|
||||
match_pattern_wchar (wpat, wstring)
|
||||
wchar_t *wpat, *wstring;
|
||||
{
|
||||
wchar_t wc;
|
||||
|
||||
if (*wstring == 0)
|
||||
return (0);
|
||||
|
||||
switch (wc = *wpat++)
|
||||
{
|
||||
default:
|
||||
return (*wstring == wc);
|
||||
case L'\\':
|
||||
return (*wstring == *wpat);
|
||||
case L'?':
|
||||
return (*wpat == WLPAREN ? 1 : (*wstring != L'\0'));
|
||||
case L'*':
|
||||
return (1);
|
||||
case L'+':
|
||||
case L'!':
|
||||
case L'@':
|
||||
return (*wpat == WLPAREN ? 1 : (*wstring == wc));
|
||||
case L'[':
|
||||
return (*wstring != L'\0');
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
wmatchlen (wpat, wmax)
|
||||
wchar_t *wpat;
|
||||
size_t wmax;
|
||||
{
|
||||
wchar_t wc;
|
||||
int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
|
||||
|
||||
if (*wpat == 0)
|
||||
return (0);
|
||||
|
||||
matlen = in_cclass = in_collsym = in_equiv = 0;
|
||||
while (wc = *wpat++)
|
||||
{
|
||||
switch (wc)
|
||||
{
|
||||
default:
|
||||
matlen++;
|
||||
break;
|
||||
case L'\\':
|
||||
if (*wpat == 0)
|
||||
return ++matlen;
|
||||
else
|
||||
{
|
||||
matlen++;
|
||||
wpat++;
|
||||
}
|
||||
break;
|
||||
case L'?':
|
||||
if (*wpat == WLPAREN)
|
||||
return (matlen = -1); /* XXX for now */
|
||||
else
|
||||
matlen++;
|
||||
break;
|
||||
case L'*':
|
||||
return (matlen = -1);
|
||||
case L'+':
|
||||
case L'!':
|
||||
case L'@':
|
||||
if (*wpat == WLPAREN)
|
||||
return (matlen = -1); /* XXX for now */
|
||||
else
|
||||
matlen++;
|
||||
break;
|
||||
case L'[':
|
||||
/* scan for ending `]', skipping over embedded [:...:] */
|
||||
bracklen = 1;
|
||||
wc = *wpat++;
|
||||
do
|
||||
{
|
||||
if (wc == 0)
|
||||
{
|
||||
wpat--; /* back up to NUL */
|
||||
matlen += bracklen;
|
||||
goto bad_bracket;
|
||||
}
|
||||
else if (wc == L'\\')
|
||||
{
|
||||
/* *wpat == backslash-escaped character */
|
||||
bracklen++;
|
||||
/* If the backslash or backslash-escape ends the string,
|
||||
bail. The ++wpat skips over the backslash escape */
|
||||
if (*wpat == 0 || *++wpat == 0)
|
||||
{
|
||||
matlen += bracklen;
|
||||
goto bad_bracket;
|
||||
}
|
||||
}
|
||||
else if (wc == L'[' && *wpat == L':') /* character class */
|
||||
{
|
||||
wpat++;
|
||||
bracklen++;
|
||||
in_cclass = 1;
|
||||
}
|
||||
else if (in_cclass && wc == L':' && *wpat == L']')
|
||||
{
|
||||
wpat++;
|
||||
bracklen++;
|
||||
in_cclass = 0;
|
||||
}
|
||||
else if (wc == L'[' && *wpat == L'.') /* collating symbol */
|
||||
{
|
||||
wpat++;
|
||||
bracklen++;
|
||||
if (*wpat == L']') /* right bracket can appear as collating symbol */
|
||||
{
|
||||
wpat++;
|
||||
bracklen++;
|
||||
}
|
||||
in_collsym = 1;
|
||||
}
|
||||
else if (in_collsym && wc == L'.' && *wpat == L']')
|
||||
{
|
||||
wpat++;
|
||||
bracklen++;
|
||||
in_collsym = 0;
|
||||
}
|
||||
else if (wc == L'[' && *wpat == L'=') /* equivalence class */
|
||||
{
|
||||
wpat++;
|
||||
bracklen++;
|
||||
if (*wpat == L']') /* right bracket can appear as equivalence class */
|
||||
{
|
||||
wpat++;
|
||||
bracklen++;
|
||||
}
|
||||
in_equiv = 1;
|
||||
}
|
||||
else if (in_equiv && wc == L'=' && *wpat == L']')
|
||||
{
|
||||
wpat++;
|
||||
bracklen++;
|
||||
in_equiv = 0;
|
||||
}
|
||||
else
|
||||
bracklen++;
|
||||
}
|
||||
while ((wc = *wpat++) != L']');
|
||||
matlen++; /* bracket expression can only match one char */
|
||||
bad_bracket:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return matlen;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
extglob_pattern (pat)
|
||||
char *pat;
|
||||
{
|
||||
switch (pat[0])
|
||||
{
|
||||
case '*':
|
||||
case '+':
|
||||
case '!':
|
||||
case '@':
|
||||
return (pat[1] == LPAREN);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return 1 of the first character of STRING could match the first
|
||||
character of pattern PAT. Used to avoid n2 calls to strmatch(). */
|
||||
int
|
||||
match_pattern_char (pat, string)
|
||||
char *pat, *string;
|
||||
{
|
||||
char c;
|
||||
|
||||
if (*string == 0)
|
||||
return (0);
|
||||
|
||||
switch (c = *pat++)
|
||||
{
|
||||
default:
|
||||
return (*string == c);
|
||||
case '\\':
|
||||
return (*string == *pat);
|
||||
case '?':
|
||||
return (*pat == LPAREN ? 1 : (*string != '\0'));
|
||||
case '*':
|
||||
return (1);
|
||||
case '+':
|
||||
case '!':
|
||||
case '@':
|
||||
return (*pat == LPAREN ? 1 : (*string == c));
|
||||
case '[':
|
||||
return (*string != '\0');
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
umatchlen (pat, max)
|
||||
char *pat;
|
||||
size_t max;
|
||||
{
|
||||
char c;
|
||||
int matlen, bracklen, t, in_cclass, in_collsym, in_equiv;
|
||||
|
||||
if (*pat == 0)
|
||||
return (0);
|
||||
|
||||
matlen = in_cclass = in_collsym = in_equiv = 0;
|
||||
while (c = *pat++)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
default:
|
||||
matlen++;
|
||||
break;
|
||||
case '\\':
|
||||
if (*pat == 0)
|
||||
return ++matlen;
|
||||
else
|
||||
{
|
||||
matlen++;
|
||||
pat++;
|
||||
}
|
||||
break;
|
||||
case '?':
|
||||
if (*pat == LPAREN)
|
||||
return (matlen = -1); /* XXX for now */
|
||||
else
|
||||
matlen++;
|
||||
break;
|
||||
case '*':
|
||||
return (matlen = -1);
|
||||
case '+':
|
||||
case '!':
|
||||
case '@':
|
||||
if (*pat == LPAREN)
|
||||
return (matlen = -1); /* XXX for now */
|
||||
else
|
||||
matlen++;
|
||||
break;
|
||||
case '[':
|
||||
/* scan for ending `]', skipping over embedded [:...:] */
|
||||
bracklen = 1;
|
||||
c = *pat++;
|
||||
do
|
||||
{
|
||||
if (c == 0)
|
||||
{
|
||||
pat--; /* back up to NUL */
|
||||
matlen += bracklen;
|
||||
goto bad_bracket;
|
||||
}
|
||||
else if (c == '\\')
|
||||
{
|
||||
/* *pat == backslash-escaped character */
|
||||
bracklen++;
|
||||
/* If the backslash or backslash-escape ends the string,
|
||||
bail. The ++pat skips over the backslash escape */
|
||||
if (*pat == 0 || *++pat == 0)
|
||||
{
|
||||
matlen += bracklen;
|
||||
goto bad_bracket;
|
||||
}
|
||||
}
|
||||
else if (c == '[' && *pat == ':') /* character class */
|
||||
{
|
||||
pat++;
|
||||
bracklen++;
|
||||
in_cclass = 1;
|
||||
}
|
||||
else if (in_cclass && c == ':' && *pat == ']')
|
||||
{
|
||||
pat++;
|
||||
bracklen++;
|
||||
in_cclass = 0;
|
||||
}
|
||||
else if (c == '[' && *pat == '.') /* collating symbol */
|
||||
{
|
||||
pat++;
|
||||
bracklen++;
|
||||
if (*pat == ']') /* right bracket can appear as collating symbol */
|
||||
{
|
||||
pat++;
|
||||
bracklen++;
|
||||
}
|
||||
in_collsym = 1;
|
||||
}
|
||||
else if (in_collsym && c == '.' && *pat == ']')
|
||||
{
|
||||
pat++;
|
||||
bracklen++;
|
||||
in_collsym = 0;
|
||||
}
|
||||
else if (c == '[' && *pat == '=') /* equivalence class */
|
||||
{
|
||||
pat++;
|
||||
bracklen++;
|
||||
if (*pat == ']') /* right bracket can appear as equivalence class */
|
||||
{
|
||||
pat++;
|
||||
bracklen++;
|
||||
}
|
||||
in_equiv = 1;
|
||||
}
|
||||
else if (in_equiv && c == '=' && *pat == ']')
|
||||
{
|
||||
pat++;
|
||||
bracklen++;
|
||||
in_equiv = 0;
|
||||
}
|
||||
else
|
||||
bracklen++;
|
||||
}
|
||||
while ((c = *pat++) != ']');
|
||||
matlen++; /* bracket expression can only match one char */
|
||||
bad_bracket:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return matlen;
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
# Derived by hand from the generated readline-src/doc/Makefile
|
||||
# This makefile for Readline library documentation is in -*- text -*- mode.
|
||||
# Emacs likes it that way.
|
||||
|
||||
# Copyright (C) 1996-2002 Free Software Foundation, Inc.
|
||||
|
||||
# This program 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.
|
||||
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
topdir = .
|
||||
srcdir = .
|
||||
VPATH = .
|
||||
|
||||
prefix = /usr/local
|
||||
infodir = ${prefix}/info
|
||||
|
||||
mandir = ${prefix}/man
|
||||
manpfx = man
|
||||
|
||||
man1ext = 1
|
||||
man1dir = $(mandir)/$(manpfx)$(man1ext)
|
||||
man3ext = 3
|
||||
man3dir = $(mandir)/$(manpfx)$(man3ext)
|
||||
|
||||
SHELL = /bin/sh
|
||||
RM = rm -f
|
||||
|
||||
INSTALL = /usr/bin/install -c
|
||||
INSTALL_DATA = ${INSTALL} -m 644
|
||||
|
||||
BUILD_DIR = .
|
||||
TEXINPUTDIR = $(srcdir)
|
||||
|
||||
MAKEINFO = LANGUAGE= makeinfo
|
||||
TEXI2DVI = $(srcdir)/texi2dvi
|
||||
TEXI2HTML = $(srcdir)/texi2html
|
||||
QUIETPS = #set this to -q to shut up dvips
|
||||
PSDPI = 600
|
||||
DVIPS = dvips -D ${PSDPI} $(QUIETPS) -o $@ # tricky
|
||||
DVIPDF = dvipdfm -o $@ -p ${PAPERSIZE}
|
||||
PSPDF = gs -sPAPERSIZE=${PAPERSIZE} -sDEVICE=pdfwrite -dNOPAUSE -dBATCH -sOutputFile=$@
|
||||
|
||||
RLSRC = $(srcdir)/rlman.texi $(srcdir)/rluser.texi \
|
||||
$(srcdir)/rltech.texi $(srcdir)/version.texi \
|
||||
$(srcdir)/rluserman.texi
|
||||
HISTSRC = $(srcdir)/history.texi $(srcdir)/hsuser.texi \
|
||||
$(srcdir)/hstech.texi $(srcdir)/version.texi
|
||||
|
||||
# This should be a program that converts troff to an ascii-readable format
|
||||
NROFF = groff -Tascii
|
||||
|
||||
# This should be a program that converts troff to postscript
|
||||
GROFF = groff
|
||||
|
||||
DVIOBJ = readline.dvi history.dvi rluserman.dvi
|
||||
INFOOBJ = readline.info history.info rluserman.info
|
||||
PSOBJ = readline.ps history.ps rluserman.ps
|
||||
HTMLOBJ = readline.html history.html rluserman.html
|
||||
PDFOBJ = readline.pdf history.pdf rluserman.pdf
|
||||
|
||||
INTERMEDIATE_OBJ = rlman.dvi
|
||||
|
||||
CREATED_DOCS = $(DVIOBJ) $(INFOOBJ) $(PSOBJ) $(HTMLOBJ) $(PDFOBJ)
|
||||
|
||||
.SUFFIXES: .ps .txt .dvi .html .pdf
|
||||
|
||||
.ps.pdf:
|
||||
$(RM) $@
|
||||
-${PSPDF} $<
|
||||
|
||||
.dvi.pdf:
|
||||
$(RM) $@
|
||||
-${DVIPDF} $<
|
||||
|
||||
all: info dvi html ps
|
||||
nodvi: info html
|
||||
pdf: $(PDFOBJ)
|
||||
|
||||
readline.dvi: $(RLSRC)
|
||||
TEXINPUTS=.:$(TEXINPUTDIR):$$TEXINPUTS $(TEXI2DVI) $(srcdir)/rlman.texi
|
||||
mv rlman.dvi readline.dvi
|
||||
|
||||
readline.info: $(RLSRC)
|
||||
$(MAKEINFO) --no-split -I $(TEXINPUTDIR) -o $@ $(srcdir)/rlman.texi
|
||||
|
||||
rluserman.dvi: $(RLSRC)
|
||||
TEXINPUTS=.:$(TEXINPUTDIR):$$TEXINPUTS $(TEXI2DVI) $(srcdir)/rluserman.texi
|
||||
|
||||
rluserman.info: $(RLSRC)
|
||||
$(MAKEINFO) --no-split -I $(TEXINPUTDIR) -o $@ $(srcdir)/rluserman.texi
|
||||
|
||||
history.dvi: ${HISTSRC}
|
||||
TEXINPUTS=.:$(TEXINPUTDIR):$$TEXINPUTS $(TEXI2DVI) $(srcdir)/history.texi
|
||||
|
||||
history.info: ${HISTSRC}
|
||||
$(MAKEINFO) --no-split -I $(TEXINPUTDIR) -o $@ $(srcdir)/history.texi
|
||||
|
||||
readline.ps: readline.dvi
|
||||
$(RM) $@
|
||||
$(DVIPS) readline.dvi
|
||||
|
||||
rluserman.ps: rluserman.dvi
|
||||
$(RM) $@
|
||||
$(DVIPS) rluserman.dvi
|
||||
|
||||
history.ps: history.dvi
|
||||
$(RM) $@
|
||||
$(DVIPS) history.dvi
|
||||
|
||||
readline.html: ${RLSRC}
|
||||
$(TEXI2HTML) -menu -monolithic -I $(TEXINPUTDIR) $(srcdir)/rlman.texi
|
||||
sed -e 's:rlman.html:readline.html:' rlman.html > readline.html
|
||||
$(RM) rlman.html
|
||||
|
||||
rluserman.html: ${RLSRC}
|
||||
$(TEXI2HTML) -menu -monolithic -I $(TEXINPUTDIR) $(srcdir)/rluserman.texi
|
||||
|
||||
history.html: ${HISTSRC}
|
||||
$(TEXI2HTML) -menu -monolithic -I $(TEXINPUTDIR) $(srcdir)/history.texi
|
||||
|
||||
info: $(INFOOBJ)
|
||||
dvi: $(DVIOBJ)
|
||||
ps: $(PSOBJ)
|
||||
html: $(HTMLOBJ)
|
||||
|
||||
readline.pdf: readline.dvi
|
||||
history.pdf: history.dvi
|
||||
rluserman.pdf: rluserman.dvi
|
||||
|
||||
clean:
|
||||
$(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \
|
||||
*.fns *.kys *.tps *.vrs *.bt *.bts *.o core *.core
|
||||
|
||||
distclean: clean
|
||||
$(RM) $(CREATED_DOCS)
|
||||
$(RM) $(INTERMEDIATE_OBJ)
|
||||
$(RM) Makefile
|
||||
|
||||
mostlyclean: clean
|
||||
|
||||
maintainer-clean: clean
|
||||
$(RM) $(CREATED_DOCS)
|
||||
$(RM) $(INTERMEDIATE_OBJ)
|
||||
$(RM) Makefile
|
||||
|
||||
install:
|
||||
@echo "This documentation should not be installed."
|
||||
|
||||
uninstall:
|
||||
@@ -1,76 +0,0 @@
|
||||
# This makefile for Readline library documentation is in -*- text -*- mode.
|
||||
# Emacs likes it that way.
|
||||
RM = rm -f
|
||||
|
||||
MAKEINFO = makeinfo
|
||||
TEXI2DVI = texi2dvi
|
||||
TEXI2HTML = texi2html
|
||||
QUIETPS = #set this to -q to shut up dvips
|
||||
DVIPS = dvips -D 300 $(QUIETPS) -o $@ # tricky
|
||||
|
||||
INSTALL_DATA = cp
|
||||
infodir = /usr/local/info
|
||||
|
||||
RLSRC = rlman.texinfo rluser.texinfo rltech.texinfo
|
||||
HISTSRC = hist.texinfo hsuser.texinfo hstech.texinfo
|
||||
|
||||
DVIOBJ = readline.dvi history.dvi
|
||||
INFOOBJ = readline.info history.info
|
||||
PSOBJ = readline.ps history.ps
|
||||
HTMLOBJ = readline.html history.html
|
||||
|
||||
all: info dvi html ps
|
||||
nodvi: info html
|
||||
|
||||
readline.dvi: $(RLSRC)
|
||||
$(TEXI2DVI) rlman.texinfo
|
||||
mv rlman.dvi readline.dvi
|
||||
|
||||
readline.info: $(RLSRC)
|
||||
$(MAKEINFO) --no-split -o $@ rlman.texinfo
|
||||
|
||||
history.dvi: ${HISTSRC}
|
||||
$(TEXI2DVI) hist.texinfo
|
||||
mv hist.dvi history.dvi
|
||||
|
||||
history.info: ${HISTSRC}
|
||||
$(MAKEINFO) --no-split -o $@ hist.texinfo
|
||||
|
||||
readline.ps: readline.dvi
|
||||
$(RM) $@
|
||||
$(DVIPS) readline.dvi
|
||||
|
||||
history.ps: history.dvi
|
||||
$(RM) $@
|
||||
$(DVIPS) history.dvi
|
||||
|
||||
readline.html: ${RLSRC}
|
||||
$(TEXI2HTML) rlman.texinfo
|
||||
sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman.html > readline.html
|
||||
sed -e 's:rlman.html:readline.html:' -e 's:rlman_toc.html:readline_toc.html:' rlman_toc.html > readline_toc.html
|
||||
$(RM) rlman.html rlman_toc.html
|
||||
|
||||
history.html: ${HISTSRC}
|
||||
$(TEXI2HTML) hist.texinfo
|
||||
sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist.html > history.html
|
||||
sed -e 's:hist.html:history.html:' -e 's:hist_toc.html:history_toc.html:' hist_toc.html > history_toc.html
|
||||
$(RM) hist.html hist_toc.html
|
||||
|
||||
info: $(INFOOBJ)
|
||||
dvi: $(DVIOBJ)
|
||||
ps: $(PSOBJ)
|
||||
html: $(HTMLOBJ)
|
||||
|
||||
clean:
|
||||
$(RM) *.aux *.cp *.fn *.ky *.log *.pg *.toc *.tp *.vr *.cps *.pgs \
|
||||
*.fns *.kys *.tps *.vrs *.o core
|
||||
|
||||
distclean: clean
|
||||
mostlyclean: clean
|
||||
|
||||
maintainer-clean: clean
|
||||
$(RM) *.dvi *.info *.info-* *.ps *.html
|
||||
|
||||
install: info
|
||||
${INSTALL_DATA} readline.info $(infodir)/readline.info
|
||||
${INSTALL_DATA} history.info $(infodir)/history.info
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,630 +0,0 @@
|
||||
/* search.c - code for non-incremental searching in emacs and vi modes. */
|
||||
|
||||
/* Copyright (C) 1992-2009 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define READLINE_LIBRARY
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# include "ansi_stdlib.h"
|
||||
#endif
|
||||
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
#include "readline.h"
|
||||
#include "history.h"
|
||||
#include "histlib.h"
|
||||
|
||||
#include "rlprivate.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#ifdef abs
|
||||
# undef abs
|
||||
#endif
|
||||
#define abs(x) (((x) >= 0) ? (x) : -(x))
|
||||
|
||||
_rl_search_cxt *_rl_nscxt = 0;
|
||||
|
||||
extern HIST_ENTRY *_rl_saved_line_for_history;
|
||||
|
||||
/* Functions imported from the rest of the library. */
|
||||
extern int _rl_free_history_entry PARAMS((HIST_ENTRY *));
|
||||
|
||||
static char *noninc_search_string = (char *) NULL;
|
||||
static int noninc_history_pos;
|
||||
|
||||
static char *prev_line_found = (char *) NULL;
|
||||
|
||||
static int rl_history_search_len;
|
||||
static int rl_history_search_pos;
|
||||
static int rl_history_search_flags;
|
||||
|
||||
static char *history_search_string;
|
||||
static int history_string_size;
|
||||
|
||||
static void make_history_line_current PARAMS((HIST_ENTRY *));
|
||||
static int noninc_search_from_pos PARAMS((char *, int, int));
|
||||
static int noninc_dosearch PARAMS((char *, int));
|
||||
static int noninc_search PARAMS((int, int));
|
||||
static int rl_history_search_internal PARAMS((int, int));
|
||||
static void rl_history_search_reinit PARAMS((int));
|
||||
|
||||
static _rl_search_cxt *_rl_nsearch_init PARAMS((int, int));
|
||||
static int _rl_nsearch_cleanup PARAMS((_rl_search_cxt *, int));
|
||||
static void _rl_nsearch_abort PARAMS((_rl_search_cxt *));
|
||||
static int _rl_nsearch_dispatch PARAMS((_rl_search_cxt *, int));
|
||||
|
||||
/* Make the data from the history entry ENTRY be the contents of the
|
||||
current line. This doesn't do anything with rl_point; the caller
|
||||
must set it. */
|
||||
static void
|
||||
make_history_line_current (entry)
|
||||
HIST_ENTRY *entry;
|
||||
{
|
||||
_rl_replace_text (entry->line, 0, rl_end);
|
||||
_rl_fix_point (1);
|
||||
#if defined (VI_MODE)
|
||||
if (rl_editing_mode == vi_mode)
|
||||
/* POSIX.2 says that the `U' command doesn't affect the copy of any
|
||||
command lines to the edit line. We're going to implement that by
|
||||
making the undo list start after the matching line is copied to the
|
||||
current editing buffer. */
|
||||
rl_free_undo_list ();
|
||||
#endif
|
||||
|
||||
if (_rl_saved_line_for_history)
|
||||
_rl_free_history_entry (_rl_saved_line_for_history);
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
}
|
||||
|
||||
/* Search the history list for STRING starting at absolute history position
|
||||
POS. If STRING begins with `^', the search must match STRING at the
|
||||
beginning of a history line, otherwise a full substring match is performed
|
||||
for STRING. DIR < 0 means to search backwards through the history list,
|
||||
DIR >= 0 means to search forward. */
|
||||
static int
|
||||
noninc_search_from_pos (string, pos, dir)
|
||||
char *string;
|
||||
int pos, dir;
|
||||
{
|
||||
int ret, old;
|
||||
|
||||
if (pos < 0)
|
||||
return -1;
|
||||
|
||||
old = where_history ();
|
||||
if (history_set_pos (pos) == 0)
|
||||
return -1;
|
||||
|
||||
RL_SETSTATE(RL_STATE_SEARCH);
|
||||
if (*string == '^')
|
||||
ret = history_search_prefix (string + 1, dir);
|
||||
else
|
||||
ret = history_search (string, dir);
|
||||
RL_UNSETSTATE(RL_STATE_SEARCH);
|
||||
|
||||
if (ret != -1)
|
||||
ret = where_history ();
|
||||
|
||||
history_set_pos (old);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Search for a line in the history containing STRING. If DIR is < 0, the
|
||||
search is backwards through previous entries, else through subsequent
|
||||
entries. Returns 1 if the search was successful, 0 otherwise. */
|
||||
static int
|
||||
noninc_dosearch (string, dir)
|
||||
char *string;
|
||||
int dir;
|
||||
{
|
||||
int oldpos, pos;
|
||||
HIST_ENTRY *entry;
|
||||
|
||||
if (string == 0 || *string == '\0' || noninc_history_pos < 0)
|
||||
{
|
||||
rl_ding ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
|
||||
if (pos == -1)
|
||||
{
|
||||
/* Search failed, current history position unchanged. */
|
||||
rl_maybe_unsave_line ();
|
||||
rl_clear_message ();
|
||||
rl_point = 0;
|
||||
rl_ding ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
noninc_history_pos = pos;
|
||||
|
||||
oldpos = where_history ();
|
||||
history_set_pos (noninc_history_pos);
|
||||
entry = current_history ();
|
||||
#if defined (VI_MODE)
|
||||
if (rl_editing_mode != vi_mode)
|
||||
#endif
|
||||
history_set_pos (oldpos);
|
||||
|
||||
make_history_line_current (entry);
|
||||
|
||||
rl_point = 0;
|
||||
rl_mark = rl_end;
|
||||
|
||||
rl_clear_message ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
static _rl_search_cxt *
|
||||
_rl_nsearch_init (dir, pchar)
|
||||
int dir, pchar;
|
||||
{
|
||||
_rl_search_cxt *cxt;
|
||||
char *p;
|
||||
|
||||
cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0);
|
||||
if (dir < 0)
|
||||
cxt->sflags |= SF_REVERSE; /* not strictly needed */
|
||||
|
||||
cxt->direction = dir;
|
||||
cxt->history_pos = cxt->save_line;
|
||||
|
||||
rl_maybe_save_line ();
|
||||
|
||||
/* Clear the undo list, since reading the search string should create its
|
||||
own undo list, and the whole list will end up being freed when we
|
||||
finish reading the search string. */
|
||||
rl_undo_list = 0;
|
||||
|
||||
/* Use the line buffer to read the search string. */
|
||||
rl_line_buffer[0] = 0;
|
||||
rl_end = rl_point = 0;
|
||||
|
||||
p = _rl_make_prompt_for_search (pchar ? pchar : ':');
|
||||
rl_message ("%s", p);
|
||||
xfree (p);
|
||||
|
||||
RL_SETSTATE(RL_STATE_NSEARCH);
|
||||
|
||||
_rl_nscxt = cxt;
|
||||
|
||||
return cxt;
|
||||
}
|
||||
|
||||
static int
|
||||
_rl_nsearch_cleanup (cxt, r)
|
||||
_rl_search_cxt *cxt;
|
||||
int r;
|
||||
{
|
||||
_rl_scxt_dispose (cxt, 0);
|
||||
_rl_nscxt = 0;
|
||||
|
||||
RL_UNSETSTATE(RL_STATE_NSEARCH);
|
||||
|
||||
return (r != 1);
|
||||
}
|
||||
|
||||
static void
|
||||
_rl_nsearch_abort (cxt)
|
||||
_rl_search_cxt *cxt;
|
||||
{
|
||||
rl_maybe_unsave_line ();
|
||||
rl_clear_message ();
|
||||
rl_point = cxt->save_point;
|
||||
rl_mark = cxt->save_mark;
|
||||
rl_restore_prompt ();
|
||||
|
||||
RL_UNSETSTATE (RL_STATE_NSEARCH);
|
||||
}
|
||||
|
||||
/* Process just-read character C according to search context CXT. Return -1
|
||||
if the caller should abort the search, 0 if we should break out of the
|
||||
loop, and 1 if we should continue to read characters. */
|
||||
static int
|
||||
_rl_nsearch_dispatch (cxt, c)
|
||||
_rl_search_cxt *cxt;
|
||||
int c;
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case CTRL('W'):
|
||||
rl_unix_word_rubout (1, c);
|
||||
break;
|
||||
|
||||
case CTRL('U'):
|
||||
rl_unix_line_discard (1, c);
|
||||
break;
|
||||
|
||||
case RETURN:
|
||||
case NEWLINE:
|
||||
return 0;
|
||||
|
||||
case CTRL('H'):
|
||||
case RUBOUT:
|
||||
if (rl_point == 0)
|
||||
{
|
||||
_rl_nsearch_abort (cxt);
|
||||
return -1;
|
||||
}
|
||||
_rl_rubout_char (1, c);
|
||||
break;
|
||||
|
||||
case CTRL('C'):
|
||||
case CTRL('G'):
|
||||
rl_ding ();
|
||||
_rl_nsearch_abort (cxt);
|
||||
return -1;
|
||||
|
||||
default:
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
rl_insert_text (cxt->mb);
|
||||
else
|
||||
#endif
|
||||
_rl_insert_char (1, c);
|
||||
break;
|
||||
}
|
||||
|
||||
(*rl_redisplay_function) ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Perform one search according to CXT, using NONINC_SEARCH_STRING. Return
|
||||
-1 if the search should be aborted, any other value means to clean up
|
||||
using _rl_nsearch_cleanup (). Returns 1 if the search was successful,
|
||||
0 otherwise. */
|
||||
static int
|
||||
_rl_nsearch_dosearch (cxt)
|
||||
_rl_search_cxt *cxt;
|
||||
{
|
||||
rl_mark = cxt->save_mark;
|
||||
|
||||
/* If rl_point == 0, we want to re-use the previous search string and
|
||||
start from the saved history position. If there's no previous search
|
||||
string, punt. */
|
||||
if (rl_point == 0)
|
||||
{
|
||||
if (noninc_search_string == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
rl_restore_prompt ();
|
||||
RL_UNSETSTATE (RL_STATE_NSEARCH);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We want to start the search from the current history position. */
|
||||
noninc_history_pos = cxt->save_line;
|
||||
FREE (noninc_search_string);
|
||||
noninc_search_string = savestring (rl_line_buffer);
|
||||
|
||||
/* If we don't want the subsequent undo list generated by the search
|
||||
matching a history line to include the contents of the search string,
|
||||
we need to clear rl_line_buffer here. For now, we just clear the
|
||||
undo list generated by reading the search string. (If the search
|
||||
fails, the old undo list will be restored by rl_maybe_unsave_line.) */
|
||||
rl_free_undo_list ();
|
||||
}
|
||||
|
||||
rl_restore_prompt ();
|
||||
return (noninc_dosearch (noninc_search_string, cxt->direction));
|
||||
}
|
||||
|
||||
/* Search non-interactively through the history list. DIR < 0 means to
|
||||
search backwards through the history of previous commands; otherwise
|
||||
the search is for commands subsequent to the current position in the
|
||||
history list. PCHAR is the character to use for prompting when reading
|
||||
the search string; if not specified (0), it defaults to `:'. */
|
||||
static int
|
||||
noninc_search (dir, pchar)
|
||||
int dir;
|
||||
int pchar;
|
||||
{
|
||||
_rl_search_cxt *cxt;
|
||||
int c, r;
|
||||
|
||||
cxt = _rl_nsearch_init (dir, pchar);
|
||||
|
||||
if (RL_ISSTATE (RL_STATE_CALLBACK))
|
||||
return (0);
|
||||
|
||||
/* Read the search string. */
|
||||
r = 0;
|
||||
while (1)
|
||||
{
|
||||
c = _rl_search_getchar (cxt);
|
||||
|
||||
if (c == 0)
|
||||
break;
|
||||
|
||||
r = _rl_nsearch_dispatch (cxt, c);
|
||||
if (r < 0)
|
||||
return 1;
|
||||
else if (r == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
r = _rl_nsearch_dosearch (cxt);
|
||||
return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
|
||||
}
|
||||
|
||||
/* Search forward through the history list for a string. If the vi-mode
|
||||
code calls this, KEY will be `?'. */
|
||||
int
|
||||
rl_noninc_forward_search (count, key)
|
||||
int count, key;
|
||||
{
|
||||
return noninc_search (1, (key == '?') ? '?' : 0);
|
||||
}
|
||||
|
||||
/* Reverse search the history list for a string. If the vi-mode code
|
||||
calls this, KEY will be `/'. */
|
||||
int
|
||||
rl_noninc_reverse_search (count, key)
|
||||
int count, key;
|
||||
{
|
||||
return noninc_search (-1, (key == '/') ? '/' : 0);
|
||||
}
|
||||
|
||||
/* Search forward through the history list for the last string searched
|
||||
for. If there is no saved search string, abort. */
|
||||
int
|
||||
rl_noninc_forward_search_again (count, key)
|
||||
int count, key;
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!noninc_search_string)
|
||||
{
|
||||
rl_ding ();
|
||||
return (-1);
|
||||
}
|
||||
r = noninc_dosearch (noninc_search_string, 1);
|
||||
return (r != 1);
|
||||
}
|
||||
|
||||
/* Reverse search in the history list for the last string searched
|
||||
for. If there is no saved search string, abort. */
|
||||
int
|
||||
rl_noninc_reverse_search_again (count, key)
|
||||
int count, key;
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!noninc_search_string)
|
||||
{
|
||||
rl_ding ();
|
||||
return (-1);
|
||||
}
|
||||
r = noninc_dosearch (noninc_search_string, -1);
|
||||
return (r != 1);
|
||||
}
|
||||
|
||||
#if defined (READLINE_CALLBACKS)
|
||||
int
|
||||
_rl_nsearch_callback (cxt)
|
||||
_rl_search_cxt *cxt;
|
||||
{
|
||||
int c, r;
|
||||
|
||||
c = _rl_search_getchar (cxt);
|
||||
r = _rl_nsearch_dispatch (cxt, c);
|
||||
if (r != 0)
|
||||
return 1;
|
||||
|
||||
r = _rl_nsearch_dosearch (cxt);
|
||||
return ((r >= 0) ? _rl_nsearch_cleanup (cxt, r) : (r != 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
rl_history_search_internal (count, dir)
|
||||
int count, dir;
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
int ret, oldpos;
|
||||
char *t;
|
||||
|
||||
rl_maybe_save_line ();
|
||||
temp = (HIST_ENTRY *)NULL;
|
||||
|
||||
/* Search COUNT times through the history for a line matching
|
||||
history_search_string. If history_search_string[0] == '^', the
|
||||
line must match from the start; otherwise any substring can match.
|
||||
When this loop finishes, TEMP, if non-null, is the history line to
|
||||
copy into the line buffer. */
|
||||
while (count)
|
||||
{
|
||||
RL_CHECK_SIGNALS ();
|
||||
ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
|
||||
if (ret == -1)
|
||||
break;
|
||||
|
||||
/* Get the history entry we found. */
|
||||
rl_history_search_pos = ret;
|
||||
oldpos = where_history ();
|
||||
history_set_pos (rl_history_search_pos);
|
||||
temp = current_history ();
|
||||
history_set_pos (oldpos);
|
||||
|
||||
/* Don't find multiple instances of the same line. */
|
||||
if (prev_line_found && STREQ (prev_line_found, temp->line))
|
||||
continue;
|
||||
prev_line_found = temp->line;
|
||||
count--;
|
||||
}
|
||||
|
||||
/* If we didn't find anything at all, return. */
|
||||
if (temp == 0)
|
||||
{
|
||||
rl_maybe_unsave_line ();
|
||||
rl_ding ();
|
||||
/* If you don't want the saved history line (last match) to show up
|
||||
in the line buffer after the search fails, change the #if 0 to
|
||||
#if 1 */
|
||||
#if 0
|
||||
if (rl_point > rl_history_search_len)
|
||||
{
|
||||
rl_point = rl_end = rl_history_search_len;
|
||||
rl_line_buffer[rl_end] = '\0';
|
||||
rl_mark = 0;
|
||||
}
|
||||
#else
|
||||
rl_point = rl_history_search_len; /* rl_maybe_unsave_line changes it */
|
||||
rl_mark = rl_end;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Copy the line we found into the current line buffer. */
|
||||
make_history_line_current (temp);
|
||||
|
||||
if (rl_history_search_flags & ANCHORED_SEARCH)
|
||||
rl_point = rl_history_search_len; /* easy case */
|
||||
else
|
||||
{
|
||||
t = strstr (rl_line_buffer, history_search_string);
|
||||
rl_point = t ? (int)(t - rl_line_buffer) + rl_history_search_len : rl_end;
|
||||
}
|
||||
rl_mark = rl_end;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rl_history_search_reinit (flags)
|
||||
int flags;
|
||||
{
|
||||
int sind;
|
||||
|
||||
rl_history_search_pos = where_history ();
|
||||
rl_history_search_len = rl_point;
|
||||
rl_history_search_flags = flags;
|
||||
|
||||
prev_line_found = (char *)NULL;
|
||||
if (rl_point)
|
||||
{
|
||||
/* Allocate enough space for anchored and non-anchored searches */
|
||||
if (rl_history_search_len >= history_string_size - 2)
|
||||
{
|
||||
history_string_size = rl_history_search_len + 2;
|
||||
history_search_string = (char *)xrealloc (history_search_string, history_string_size);
|
||||
}
|
||||
sind = 0;
|
||||
if (flags & ANCHORED_SEARCH)
|
||||
history_search_string[sind++] = '^';
|
||||
strncpy (history_search_string + sind, rl_line_buffer, rl_point);
|
||||
history_search_string[rl_point + sind] = '\0';
|
||||
}
|
||||
_rl_free_saved_history_line ();
|
||||
}
|
||||
|
||||
/* Search forward in the history for the string of characters
|
||||
from the start of the line to rl_point. This is a non-incremental
|
||||
search. The search is anchored to the beginning of the history line. */
|
||||
int
|
||||
rl_history_search_forward (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
if (count == 0)
|
||||
return (0);
|
||||
|
||||
if (rl_last_func != rl_history_search_forward &&
|
||||
rl_last_func != rl_history_search_backward)
|
||||
rl_history_search_reinit (ANCHORED_SEARCH);
|
||||
|
||||
if (rl_history_search_len == 0)
|
||||
return (rl_get_next_history (count, ignore));
|
||||
return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
|
||||
}
|
||||
|
||||
/* Search backward through the history for the string of characters
|
||||
from the start of the line to rl_point. This is a non-incremental
|
||||
search. */
|
||||
int
|
||||
rl_history_search_backward (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
if (count == 0)
|
||||
return (0);
|
||||
|
||||
if (rl_last_func != rl_history_search_forward &&
|
||||
rl_last_func != rl_history_search_backward)
|
||||
rl_history_search_reinit (ANCHORED_SEARCH);
|
||||
|
||||
if (rl_history_search_len == 0)
|
||||
return (rl_get_previous_history (count, ignore));
|
||||
return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
|
||||
}
|
||||
|
||||
/* Search forward in the history for the string of characters
|
||||
from the start of the line to rl_point. This is a non-incremental
|
||||
search. The search succeeds if the search string is present anywhere
|
||||
in the history line. */
|
||||
int
|
||||
rl_history_substr_search_forward (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
if (count == 0)
|
||||
return (0);
|
||||
|
||||
if (rl_last_func != rl_history_substr_search_forward &&
|
||||
rl_last_func != rl_history_substr_search_backward)
|
||||
rl_history_search_reinit (NON_ANCHORED_SEARCH);
|
||||
|
||||
if (rl_history_search_len == 0)
|
||||
return (rl_get_next_history (count, ignore));
|
||||
return (rl_history_search_internal (abs (count), (count > 0) ? 1 : -1));
|
||||
}
|
||||
|
||||
/* Search backward through the history for the string of characters
|
||||
from the start of the line to rl_point. This is a non-incremental
|
||||
search. */
|
||||
int
|
||||
rl_history_substr_search_backward (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
if (count == 0)
|
||||
return (0);
|
||||
|
||||
if (rl_last_func != rl_history_substr_search_forward &&
|
||||
rl_last_func != rl_history_substr_search_backward)
|
||||
rl_history_search_reinit (NON_ANCHORED_SEARCH);
|
||||
|
||||
if (rl_history_search_len == 0)
|
||||
return (rl_get_previous_history (count, ignore));
|
||||
return (rl_history_search_internal (abs (count), (count > 0) ? -1 : 1));
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
/* makepath.c - glue PATH and DIR together into a full pathname. */
|
||||
|
||||
/* Copyright (C) 1987, 1989, 1991 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <bashansi.h>
|
||||
#include "shell.h"
|
||||
|
||||
#include <tilde/tilde.h>
|
||||
|
||||
#ifndef NULL
|
||||
# define NULL 0
|
||||
#endif
|
||||
|
||||
/* MAKE SURE THESE AGREE WITH ../../externs.h. */
|
||||
|
||||
#ifndef MP_DOTILDE
|
||||
# define MP_DOTILDE 0x01
|
||||
# define MP_DOCWD 0x02
|
||||
# define MP_RMDOT 0x04
|
||||
# define MP_IGNDOT 0x08
|
||||
#endif
|
||||
|
||||
extern char *get_working_directory __P((char *));
|
||||
|
||||
static char *nullpath = "";
|
||||
|
||||
/* Take PATH, an element from, e.g., $CDPATH, and DIR, a directory name,
|
||||
and paste them together into PATH/DIR. Tilde expansion is performed on
|
||||
PATH if (flags & MP_DOTILDE) is non-zero. If PATH is NULL or the empty
|
||||
string, it is converted to the current directory. A full pathname is
|
||||
used if (flags & MP_DOCWD) is non-zero, otherwise `./' is used. If
|
||||
(flags & MP_RMDOT) is non-zero, any `./' is removed from the beginning
|
||||
of DIR. If (flags & MP_IGNDOT) is non-zero, a PATH that is "." or "./"
|
||||
is ignored. */
|
||||
|
||||
#define MAKEDOT() \
|
||||
do { \
|
||||
xpath = (char *)xmalloc (2); \
|
||||
xpath[0] = '.'; \
|
||||
xpath[1] = '\0'; \
|
||||
pathlen = 1; \
|
||||
} while (0)
|
||||
|
||||
char *
|
||||
sh_makepath (path, dir, flags)
|
||||
const char *path, *dir;
|
||||
int flags;
|
||||
{
|
||||
int dirlen, pathlen;
|
||||
char *ret, *xpath, *xdir, *r, *s;
|
||||
|
||||
if (path == 0 || *path == '\0')
|
||||
{
|
||||
if (flags & MP_DOCWD)
|
||||
{
|
||||
xpath = get_working_directory ("sh_makepath");
|
||||
if (xpath == 0)
|
||||
{
|
||||
ret = get_string_value ("PWD");
|
||||
if (ret)
|
||||
xpath = savestring (ret);
|
||||
}
|
||||
if (xpath == 0)
|
||||
MAKEDOT();
|
||||
else
|
||||
pathlen = strlen (xpath);
|
||||
}
|
||||
else
|
||||
MAKEDOT();
|
||||
}
|
||||
else if ((flags & MP_IGNDOT) && path[0] == '.' && (path[1] == '\0' ||
|
||||
path[1] == '/' && path[2] == '\0'))
|
||||
{
|
||||
xpath = nullpath;
|
||||
pathlen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xpath = ((flags & MP_DOTILDE) && *path == '~') ? bash_tilde_expand (path, 0) : (char *)path;
|
||||
pathlen = strlen (xpath);
|
||||
}
|
||||
|
||||
xdir = (char *)dir;
|
||||
dirlen = strlen (xdir);
|
||||
if ((flags & MP_RMDOT) && dir[0] == '.' && dir[1] == '/')
|
||||
{
|
||||
xdir += 2;
|
||||
dirlen -= 2;
|
||||
}
|
||||
|
||||
r = ret = (char *)xmalloc (2 + dirlen + pathlen);
|
||||
s = xpath;
|
||||
while (*s)
|
||||
*r++ = *s++;
|
||||
if (s > xpath && s[-1] != '/')
|
||||
*r++ = '/';
|
||||
s = xdir;
|
||||
while (*r++ = *s++)
|
||||
;
|
||||
if (xpath != path && xpath != nullpath)
|
||||
free (xpath);
|
||||
return (ret);
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
:; ./shx
|
||||
|
||||
sh:
|
||||
<&$fd ok
|
||||
nlbq Mon Aug 3 02:45:00 EDT 1992
|
||||
bang geoff
|
||||
quote 712824302
|
||||
setbq defmsgid=<1992Aug3.024502.6176@host>
|
||||
bgwait sleep done... wait 6187
|
||||
|
||||
|
||||
bash:
|
||||
<&$fd ok
|
||||
nlbq Mon Aug 3 02:45:09 EDT 1992
|
||||
bang geoff
|
||||
quote 712824311
|
||||
setbq defmsgid=<1992Aug3.024512.6212@host>
|
||||
bgwait sleep done... wait 6223
|
||||
|
||||
|
||||
ash:
|
||||
<&$fd shx1: 4: Syntax error: Bad fd number
|
||||
nlbq Mon Aug 3 02:45:19 EDT 1992
|
||||
bang geoff
|
||||
quote getdate: `"now"' not a valid date
|
||||
|
||||
setbq defmsgid=<1992Aug3.` echo 024521
|
||||
bgwait sleep done... wait 6241
|
||||
|
||||
|
||||
ksh:
|
||||
<&$fd ok
|
||||
nlbq ./shx: 6248 Memory fault - core dumped
|
||||
bang geoff
|
||||
quote getdate: `"now"' not a valid date
|
||||
|
||||
setbq defmsgid=<1992Aug3.024530.6257@host>
|
||||
bgwait no such job: 6265
|
||||
wait 6265
|
||||
sleep done...
|
||||
|
||||
zsh:
|
||||
<&$fd ok
|
||||
nlbq Mon Aug 3 02:45:36 EDT 1992
|
||||
bang shx3: event not found: /s/ [4]
|
||||
quote 712824337
|
||||
setbq defmsgid=<..6290@host>
|
||||
bgwait shx7: unmatched " [9]
|
||||
sleep done...
|
||||
:;
|
||||
@@ -1,10 +0,0 @@
|
||||
#! /bin/sh
|
||||
for cmd in sh bash ash ksh zsh
|
||||
do
|
||||
echo
|
||||
echo $cmd:
|
||||
for demo in shx?
|
||||
do
|
||||
$cmd $demo
|
||||
done
|
||||
done
|
||||
Reference in New Issue
Block a user