commit bash-20040301 snapshot

This commit is contained in:
Chet Ramey
2011-12-03 12:55:02 -05:00
parent fb65be05d0
commit 5565fb1a35
20 changed files with 4881 additions and 186 deletions
+24
View File
@@ -9202,3 +9202,27 @@ bashline.c
- fix conditional binding of emacs-mode M-~ -- there is a default
binding for it (rl_tilde_expand), so a straight call to
rl_bind_key_if_unbound_in_map doesn't do the right thing
2/27
----
[bash-3.0-beta1 released]
2/29
----
subst.c
- fixed expansion so referencing $a, when a is an array variable
without an element assigned to index 0, exits the shell when
`-u' is enabled
expr.c
- make the exponentiation operator (**) associative, so things like
2**3**4 work right (change `if' to `while')
3/2
---
lib/sh/strftime.c
- SCO Unix 3.2, like Solaris, requires that the system's `timezone'
variable be declared as long
lib/readline/{bind,histfile,input,parens}.c
- changes for Tandem (including `floss.h' (?))
+77 -4
View File
@@ -9144,9 +9144,82 @@ lib/glob/strmatch.c
strmatch()
subst.c
- old match_pattern is now internal_match_pattern
- match_pattern now either calls internal_match_pattern or converts
mbstrings to wide chars and calls internal_match_wpattern
- internal_match_pattern reverted to old non-multibyte code
- old match_pattern is now match_upattern
- match_pattern now either calls match_upattern or converts
mbstrings to wide chars and calls match_wpattern
- match_upattern reverted to old non-multibyte code
- new function: match_pattern_wchar, wide character version of
match_pattern_char
2/1
---
subst.c
- old remove_pattern is now remove_upattern
- remove_upattern reverted to old non-multibyte code (pre-Waugh patch)
- new multibyte version of remove_pattern: remove_wpattern
- remove_pattern now calls either remove_upattern or converts a
multibyte string to a wide character string and calls
remove_wpattern
- new function, wcsdup, wide-character version of strdup(3)
2/4
---
print_cmd.c
- temporarily translate a >&filename redirection from
r_duplicating_output_word to r_err_and_out (as the expansion code
in redir.c does) so it prints without a leading `1' (file
descriptor)
2/5
---
aclocal.m4
- add a check for wcsdup to BASH_CHECK_MULTIBYTE
config.h.in
- add HAVE_WCSDUP define
2/9
---
builtins/shift.def
- fix a call to sh_erange that possibly dereferences a NULL pointer
2/12
----
general.c
- start at a general set of file property checking functions:
file_isdir(), file_iswdir() (is writable directory)
general.h
- extern declarations for new functions
lib/sh/tmpfile.c
- use file_iswdir() to make sure the temporary directory used for
here documents and other temp files is writable in get_sys_tmpdir()
2/17
----
bashline.c
- fix conditional binding of emacs-mode M-~ -- there is a default
binding for it (rl_tilde_expand), so a straight call to
rl_bind_key_if_unbound_in_map doesn't do the right thing
2/27
----
[bash-3.0-beta1 released]
2/29
----
subst.c
- fixed expansion so referencing $a, when a is an array variable
without an element assigned to index 0, exits the shell when
`-u' is enabled
expr.c
- make the exponentiation operator (**) associative, so things like
2**3**4 work right (change `if' to `while')
3/2
---
lib/sh/strftime.c
- SCO Unix 3.2, like Solaris, requires that the system's `timezone'
variable be declared as long
+6 -1
View File
@@ -283,7 +283,12 @@ does not provide the necessary support.
builtins and functions to be timed.
`--enable-cond-command'
Include support for the `[[' conditional command (*note
Include support for the `[[' conditional command. (*note
Conditional Constructs::).
`--enable-cond-regexp'
Include support for matching POSIX regular expressions using the
`=~' binary operator in the `[[' conditional command. (*note
Conditional Constructs::).
`--enable-directory-stack'
+9
View File
@@ -128,6 +128,15 @@ ll. The error message printed when bash cannot open a shell script supplied
as argument 1 now includes the name of the shell, to better identify
the error as coming from bash.
mm. A bug that caused here documents to not work if the directory the shell
used for the temporary files was not writable has been fixed.
nn. The parameter pattern removal and substitution expansions are now much
faster and more efficient when using multibyte characters.
oo. Fixed a bug in the `shift' builtin that could cause core dumps when
reporting an out-of-range argument.
2. New Features in Readline
a. History expansion has a new `a' modifier equivalent to the `g' modifier
+1 -1
View File
@@ -286,4 +286,4 @@ rbash: bashref.texi
cmp -s RBASH ../RBASH || mv RBASH ../RBASH
$(RM) RBASH
xdist: inst posix rbash
xdist: pdf inst posix rbash
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+2 -1
View File
@@ -42,6 +42,7 @@
"||"
"expr ? expr : expr"
"=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", "&=", "^=", "|="
, [comma]
(Note that most of these operators have special meaning to bash, and an
entire expression should be quoted, e.g. "a=$a+1" or "a=a+1" to ensure
@@ -765,7 +766,7 @@ exppower ()
register intmax_t val1, val2, c;
val1 = exp1 ();
if (curtok == POWER)
while (curtok == POWER)
{
readtok ();
val2 = exp1 ();
+5
View File
@@ -19,8 +19,13 @@
is generally kept in a file called COPYING or LICENSE. If you do not
have a copy of the license, write to the Free Software Foundation,
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#define READLINE_LIBRARY
#if defined (__TANDEM)
# include <floss.h>
#endif
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
+2223
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -23,8 +23,13 @@
/* The goal is to make the implementation transparent, so that you
don't have to know what data types are used, just what functions
you can call. I think I have done that. */
#define READLINE_LIBRARY
#if defined (__TANDEM)
# include <floss.h>
#endif
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
+542
View File
@@ -0,0 +1,542 @@
/* histfile.c - functions to manipulate the history file. */
/* Copyright (C) 1989-2003 Free Software Foundation, Inc.
This file contains the GNU History Library (the Library), a set of
routines for managing the text of previously typed lines.
The Library is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
The Library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
The GNU General Public License is often shipped with GNU software, and
is generally kept in a file called COPYING or LICENSE. If you do not
have a copy of the license, write to the Free Software Foundation,
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
/* The goal is to make the implementation transparent, so that you
don't have to know what data types are used, just what functions
you can call. I think I have done that. */
#if defined (__TANDEM)
# include <floss.h>
#endif
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#include "posixstat.h"
#include <fcntl.h>
#if defined (HAVE_STDLIB_H)
# include <stdlib.h>
#else
# include "ansi_stdlib.h"
#endif /* HAVE_STDLIB_H */
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined (__EMX__) || defined (__CYGWIN__)
# undef HAVE_MMAP
#endif
#ifdef HISTORY_USE_MMAP
# include <sys/mman.h>
# ifdef MAP_FILE
# define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE)
# define MAP_WFLAGS (MAP_FILE|MAP_SHARED)
# else
# define MAP_RFLAGS MAP_PRIVATE
# define MAP_WFLAGS MAP_SHARED
# endif
# ifndef MAP_FAILED
# define MAP_FAILED ((void *)-1)
# endif
#endif /* HISTORY_USE_MMAP */
/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
on win 95/98/nt), we want to open files with O_BINARY mode so that there
is no \n -> \r\n conversion performed. On other systems, we don't want to
mess around with O_BINARY at all, so we ensure that it's defined to 0. */
#if defined (__EMX__) || defined (__CYGWIN__)
# ifndef O_BINARY
# define O_BINARY 0
# endif
#else /* !__EMX__ && !__CYGWIN__ */
# undef O_BINARY
# define O_BINARY 0
#endif /* !__EMX__ && !__CYGWIN__ */
#include <errno.h>
#if !defined (errno)
extern int errno;
#endif /* !errno */
#include "history.h"
#include "histlib.h"
#include "rlshell.h"
#include "xmalloc.h"
/* If non-zero, we write timestamps to the history file in history_do_write() */
int history_write_timestamps = 0;
/* Does S look like the beginning of a history timestamp entry? Placeholder
for more extensive tests. */
#define HIST_TIMESTAMP_START(s) (*(s) == history_comment_char)
/* Return the string that should be used in the place of this
filename. This only matters when you don't specify the
filename to read_history (), or write_history (). */
static char *
history_filename (filename)
const char *filename;
{
char *return_val;
const char *home;
int home_len;
return_val = filename ? savestring (filename) : (char *)NULL;
if (return_val)
return (return_val);
home = sh_get_env_value ("HOME");
if (home == 0)
{
home = ".";
home_len = 1;
}
else
home_len = strlen (home);
return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
strcpy (return_val, home);
return_val[home_len] = '/';
#if defined (__MSDOS__)
strcpy (return_val + home_len + 1, "_history");
#else
strcpy (return_val + home_len + 1, ".history");
#endif
return (return_val);
}
/* Add the contents of FILENAME to the history list, a line at a time.
If FILENAME is NULL, then read from ~/.history. Returns 0 if
successful, or errno if not. */
int
read_history (filename)
const char *filename;
{
return (read_history_range (filename, 0, -1));
}
/* Read a range of lines from FILENAME, adding them to the history list.
Start reading at the FROM'th line and end at the TO'th. If FROM
is zero, start at the beginning. If TO is less than FROM, read
until the end of the file. If FILENAME is NULL, then read from
~/.history. Returns 0 if successful, or errno if not. */
int
read_history_range (filename, from, to)
const char *filename;
int from, to;
{
register char *line_start, *line_end, *p;
char *input, *buffer, *bufend, *last_ts;
int file, current_line, chars_read;
struct stat finfo;
size_t file_size;
#if defined (EFBIG)
int overflow_errno = EFBIG;
#elif defined (EOVERFLOW)
int overflow_errno = EOVERFLOW;
#else
int overflow_errno = EIO;
#endif
buffer = last_ts = (char *)NULL;
input = history_filename (filename);
file = open (input, O_RDONLY|O_BINARY, 0666);
if ((file < 0) || (fstat (file, &finfo) == -1))
goto error_and_exit;
file_size = (size_t)finfo.st_size;
/* check for overflow on very large files */
if (file_size != finfo.st_size || file_size + 1 < file_size)
{
errno = overflow_errno;
goto error_and_exit;
}
#ifdef HISTORY_USE_MMAP
/* We map read/write and private so we can change newlines to NULs without
affecting the underlying object. */
buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
if ((void *)buffer == MAP_FAILED)
{
errno = overflow_errno;
goto error_and_exit;
}
chars_read = file_size;
#else
buffer = (char *)malloc (file_size + 1);
if (buffer == 0)
{
errno = overflow_errno;
goto error_and_exit;
}
chars_read = read (file, buffer, file_size);
#endif
if (chars_read < 0)
{
error_and_exit:
if (errno != 0)
chars_read = errno;
else
chars_read = EIO;
if (file >= 0)
close (file);
FREE (input);
#ifndef HISTORY_USE_MMAP
FREE (buffer);
#endif
return (chars_read);
}
close (file);
/* Set TO to larger than end of file if negative. */
if (to < 0)
to = chars_read;
/* Start at beginning of file, work to end. */
bufend = buffer + chars_read;
current_line = 0;
/* Skip lines until we are at FROM. */
for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
if (*line_end == '\n')
{
p = line_end + 1;
/* If we see something we think is a timestamp, continue with this
line. We should check more extensively here... */
if (HIST_TIMESTAMP_START(p) == 0)
current_line++;
line_start = p;
}
/* If there are lines left to gobble, then gobble them now. */
for (line_end = line_start; line_end < bufend; line_end++)
if (*line_end == '\n')
{
*line_end = '\0';
if (*line_start)
{
if (HIST_TIMESTAMP_START(line_start) == 0)
{
add_history (line_start);
if (last_ts)
{
add_history_time (last_ts);
last_ts = NULL;
}
}
else
{
last_ts = line_start;
current_line--;
}
}
current_line++;
if (current_line >= to)
break;
line_start = line_end + 1;
}
FREE (input);
#ifndef HISTORY_USE_MMAP
FREE (buffer);
#else
munmap (buffer, file_size);
#endif
return (0);
}
/* Truncate the history file FNAME, leaving only LINES trailing lines.
If FNAME is NULL, then use ~/.history. Returns 0 on success, errno
on failure. */
int
history_truncate_file (fname, lines)
const char *fname;
int lines;
{
char *buffer, *filename, *bp, *bp1; /* bp1 == bp+1 */
int file, chars_read, rv;
struct stat finfo;
size_t file_size;
buffer = (char *)NULL;
filename = history_filename (fname);
file = open (filename, O_RDONLY|O_BINARY, 0666);
rv = 0;
/* Don't try to truncate non-regular files. */
if (file == -1 || fstat (file, &finfo) == -1)
{
rv = errno;
if (file != -1)
close (file);
goto truncate_exit;
}
if (S_ISREG (finfo.st_mode) == 0)
{
close (file);
#ifdef EFTYPE
rv = EFTYPE;
#else
rv = EINVAL;
#endif
goto truncate_exit;
}
file_size = (size_t)finfo.st_size;
/* check for overflow on very large files */
if (file_size != finfo.st_size || file_size + 1 < file_size)
{
close (file);
#if defined (EFBIG)
rv = errno = EFBIG;
#elif defined (EOVERFLOW)
rv = errno = EOVERFLOW;
#else
rv = errno = EINVAL;
#endif
goto truncate_exit;
}
buffer = (char *)malloc (file_size + 1);
if (buffer == 0)
{
close (file);
goto truncate_exit;
}
chars_read = read (file, buffer, file_size);
close (file);
if (chars_read <= 0)
{
rv = (chars_read < 0) ? errno : 0;
goto truncate_exit;
}
/* Count backwards from the end of buffer until we have passed
LINES lines. bp1 is set funny initially. But since bp[1] can't
be a comment character (since it's off the end) and *bp can't be
both a newline and the history comment character, it should be OK. */
for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
{
if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
lines--;
bp1 = bp;
}
/* If this is the first line, then the file contains exactly the
number of lines we want to truncate to, so we don't need to do
anything. It's the first line if we don't find a newline between
the current value of i and 0. Otherwise, write from the start of
this line until the end of the buffer. */
for ( ; bp > buffer; bp--)
{
if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
{
bp++;
break;
}
bp1 = bp;
}
/* Write only if there are more lines in the file than we want to
truncate to. */
if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
{
write (file, bp, chars_read - (bp - buffer));
#if defined (__BEOS__)
/* BeOS ignores O_TRUNC. */
ftruncate (file, chars_read - (bp - buffer));
#endif
close (file);
}
truncate_exit:
FREE (buffer);
free (filename);
return rv;
}
/* Workhorse function for writing history. Writes NELEMENT entries
from the history list to FILENAME. OVERWRITE is non-zero if you
wish to replace FILENAME with the entries. */
static int
history_do_write (filename, nelements, overwrite)
const char *filename;
int nelements, overwrite;
{
register int i;
char *output;
int file, mode, rv;
#ifdef HISTORY_USE_MMAP
size_t cursize;
mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
#else
mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
#endif
output = history_filename (filename);
rv = 0;
if ((file = open (output, mode, 0600)) == -1)
{
FREE (output);
return (errno);
}
#ifdef HISTORY_USE_MMAP
cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
#endif
if (nelements > history_length)
nelements = history_length;
/* Build a buffer of all the lines to write, and write them in one syscall.
Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
{
HIST_ENTRY **the_history; /* local */
register int j;
int buffer_size;
char *buffer;
the_history = history_list ();
/* Calculate the total number of bytes to write. */
for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
#if 0
buffer_size += 2 + HISTENT_BYTES (the_history[i]);
#else
{
if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
buffer_size += strlen (the_history[i]->timestamp) + 1;
buffer_size += strlen (the_history[i]->line) + 1;
}
#endif
/* Allocate the buffer, and fill it. */
#ifdef HISTORY_USE_MMAP
if (ftruncate (file, buffer_size+cursize) == -1)
goto mmap_error;
buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
if ((void *)buffer == MAP_FAILED)
{
mmap_error:
rv = errno;
FREE (output);
close (file);
return rv;
}
#else
buffer = (char *)malloc (buffer_size);
if (buffer == 0)
{
rv = errno;
FREE (output);
close (file);
return rv;
}
#endif
for (j = 0, i = history_length - nelements; i < history_length; i++)
{
if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
{
strcpy (buffer + j, the_history[i]->timestamp);
j += strlen (the_history[i]->timestamp);
buffer[j++] = '\n';
}
strcpy (buffer + j, the_history[i]->line);
j += strlen (the_history[i]->line);
buffer[j++] = '\n';
}
#ifdef HISTORY_USE_MMAP
if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
rv = errno;
#else
if (write (file, buffer, buffer_size) < 0)
rv = errno;
free (buffer);
#endif
}
close (file);
FREE (output);
return (rv);
}
/* Append NELEMENT entries to FILENAME. The entries appended are from
the end of the list minus NELEMENTs up to the end of the list. */
int
append_history (nelements, filename)
int nelements;
const char *filename;
{
return (history_do_write (filename, nelements, HISTORY_APPEND));
}
/* Overwrite FILENAME with the current history. If FILENAME is NULL,
then write the history list to ~/.history. Values returned
are as in read_history ().*/
int
write_history (filename)
const char *filename;
{
return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
}
+4
View File
@@ -21,6 +21,10 @@
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#define READLINE_LIBRARY
#if defined (__TANDEM)
# include <floss.h>
#endif
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
+551
View File
@@ -0,0 +1,551 @@
/* input.c -- character input functions for readline. */
/* Copyright (C) 1994 Free Software Foundation, Inc.
This file is part of the GNU Readline Library, a library for
reading lines of text with interactive input and history editing.
The GNU Readline Library is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2, or
(at your option) any later version.
The GNU Readline Library is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
The GNU General Public License is often shipped with GNU software, and
is generally kept in a file called COPYING or LICENSE. If you do not
have a copy of the license, write to the Free Software Foundation,
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
#include <sys/types.h>
#include <fcntl.h>
#if defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif /* HAVE_SYS_FILE_H */
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif /* HAVE_UNISTD_H */
#if defined (HAVE_STDLIB_H)
# include <stdlib.h>
#else
# include "ansi_stdlib.h"
#endif /* HAVE_STDLIB_H */
#if defined (HAVE_SELECT)
# if !defined (HAVE_SYS_SELECT_H) || !defined (M_UNIX)
# include <sys/time.h>
# endif
#endif /* HAVE_SELECT */
#if defined (HAVE_SYS_SELECT_H)
# include <sys/select.h>
#endif
#if defined (FIONREAD_IN_SYS_IOCTL)
# include <sys/ioctl.h>
#endif
#include <stdio.h>
#include <errno.h>
#if !defined (errno)
extern int errno;
#endif /* !errno */
/* System-specific feature definitions and include files. */
#include "rldefs.h"
#include "rlmbutil.h"
/* Some standard library routines. */
#include "readline.h"
#include "rlprivate.h"
#include "rlshell.h"
#include "xmalloc.h"
/* What kind of non-blocking I/O do we have? */
#if !defined (O_NDELAY) && defined (O_NONBLOCK)
# define O_NDELAY O_NONBLOCK /* Posix style */
#endif
/* Non-null means it is a pointer to a function to run while waiting for
character input. */
rl_hook_func_t *rl_event_hook = (rl_hook_func_t *)NULL;
rl_getc_func_t *rl_getc_function = rl_getc;
static int _keyboard_input_timeout = 100000; /* 0.1 seconds; it's in usec */
static int ibuffer_space PARAMS((void));
static int rl_get_char PARAMS((int *));
static int rl_gather_tyi PARAMS((void));
/* **************************************************************** */
/* */
/* Character Input Buffering */
/* */
/* **************************************************************** */
static int pop_index, push_index;
static unsigned char ibuffer[512];
static int ibuffer_len = sizeof (ibuffer) - 1;
#define any_typein (push_index != pop_index)
int
_rl_any_typein ()
{
return any_typein;
}
/* Return the amount of space available in the buffer for stuffing
characters. */
static int
ibuffer_space ()
{
if (pop_index > push_index)
return (pop_index - push_index - 1);
else
return (ibuffer_len - (push_index - pop_index));
}
/* Get a key from the buffer of characters to be read.
Return the key in KEY.
Result is KEY if there was a key, or 0 if there wasn't. */
static int
rl_get_char (key)
int *key;
{
if (push_index == pop_index)
return (0);
*key = ibuffer[pop_index++];
if (pop_index >= ibuffer_len)
pop_index = 0;
return (1);
}
/* Stuff KEY into the *front* of the input buffer.
Returns non-zero if successful, zero if there is
no space left in the buffer. */
int
_rl_unget_char (key)
int key;
{
if (ibuffer_space ())
{
pop_index--;
if (pop_index < 0)
pop_index = ibuffer_len - 1;
ibuffer[pop_index] = key;
return (1);
}
return (0);
}
int
_rl_pushed_input_available ()
{
return (push_index != pop_index);
}
/* If a character is available to be read, then read it and stuff it into
IBUFFER. Otherwise, just return. Returns number of characters read
(0 if none available) and -1 on error (EIO). */
static int
rl_gather_tyi ()
{
int tty;
register int tem, result;
int chars_avail, k;
char input;
#if defined(HAVE_SELECT)
fd_set readfds, exceptfds;
struct timeval timeout;
#endif
tty = fileno (rl_instream);
#if defined (HAVE_SELECT)
FD_ZERO (&readfds);
FD_ZERO (&exceptfds);
FD_SET (tty, &readfds);
FD_SET (tty, &exceptfds);
timeout.tv_sec = 0;
timeout.tv_usec = _keyboard_input_timeout;
result = select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout);
if (result <= 0)
return 0; /* Nothing to read. */
#endif
result = -1;
#if defined (FIONREAD)
errno = 0;
result = ioctl (tty, FIONREAD, &chars_avail);
if (result == -1 && errno == EIO)
return -1;
#endif
#if defined (O_NDELAY)
if (result == -1)
{
tem = fcntl (tty, F_GETFL, 0);
fcntl (tty, F_SETFL, (tem | O_NDELAY));
chars_avail = read (tty, &input, 1);
fcntl (tty, F_SETFL, tem);
if (chars_avail == -1 && errno == EAGAIN)
return 0;
}
#endif /* O_NDELAY */
/* If there's nothing available, don't waste time trying to read
something. */
if (chars_avail <= 0)
return 0;
tem = ibuffer_space ();
if (chars_avail > tem)
chars_avail = tem;
/* One cannot read all of the available input. I can only read a single
character at a time, or else programs which require input can be
thwarted. If the buffer is larger than one character, I lose.
Damn! */
if (tem < ibuffer_len)
chars_avail = 0;
if (result != -1)
{
while (chars_avail--)
{
k = (*rl_getc_function) (rl_instream);
rl_stuff_char (k);
if (k == NEWLINE || k == RETURN)
break;
}
}
else
{
if (chars_avail)
rl_stuff_char (input);
}
return 1;
}
int
rl_set_keyboard_input_timeout (u)
int u;
{
int o;
o = _keyboard_input_timeout;
if (u > 0)
_keyboard_input_timeout = u;
return (o);
}
/* Is there input available to be read on the readline input file
descriptor? Only works if the system has select(2) or FIONREAD.
Uses the value of _keyboard_input_timeout as the timeout; if another
readline function wants to specify a timeout and not leave it up to
the user, it should use _rl_input_queued(timeout_value_in_microseconds)
instead. */
int
_rl_input_available ()
{
#if defined(HAVE_SELECT)
fd_set readfds, exceptfds;
struct timeval timeout;
#endif
#if !defined (HAVE_SELECT) && defined(FIONREAD)
int chars_avail;
#endif
int tty;
tty = fileno (rl_instream);
#if defined (HAVE_SELECT)
FD_ZERO (&readfds);
FD_ZERO (&exceptfds);
FD_SET (tty, &readfds);
FD_SET (tty, &exceptfds);
timeout.tv_sec = 0;
timeout.tv_usec = _keyboard_input_timeout;
return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 0);
#else
#if defined (FIONREAD)
if (ioctl (tty, FIONREAD, &chars_avail) == 0)
return (chars_avail);
#endif
#endif
return 0;
}
int
_rl_input_queued (t)
int t;
{
int old_timeout, r;
old_timeout = rl_set_keyboard_input_timeout (t);
r = _rl_input_available ();
rl_set_keyboard_input_timeout (old_timeout);
return r;
}
void
_rl_insert_typein (c)
int c;
{
int key, t, i;
char *string;
i = key = 0;
string = (char *)xmalloc (ibuffer_len + 1);
string[i++] = (char) c;
while ((t = rl_get_char (&key)) &&
_rl_keymap[key].type == ISFUNC &&
_rl_keymap[key].function == rl_insert)
string[i++] = key;
if (t)
_rl_unget_char (key);
string[i] = '\0';
rl_insert_text (string);
free (string);
}
/* Add KEY to the buffer of characters to be read. Returns 1 if the
character was stuffed correctly; 0 otherwise. */
int
rl_stuff_char (key)
int key;
{
if (ibuffer_space () == 0)
return 0;
if (key == EOF)
{
key = NEWLINE;
rl_pending_input = EOF;
RL_SETSTATE (RL_STATE_INPUTPENDING);
}
ibuffer[push_index++] = key;
if (push_index >= ibuffer_len)
push_index = 0;
return 1;
}
/* Make C be the next command to be executed. */
int
rl_execute_next (c)
int c;
{
rl_pending_input = c;
RL_SETSTATE (RL_STATE_INPUTPENDING);
return 0;
}
/* Clear any pending input pushed with rl_execute_next() */
int
rl_clear_pending_input ()
{
rl_pending_input = 0;
RL_UNSETSTATE (RL_STATE_INPUTPENDING);
return 0;
}
/* **************************************************************** */
/* */
/* Character Input */
/* */
/* **************************************************************** */
/* Read a key, including pending input. */
int
rl_read_key ()
{
int c;
rl_key_sequence_length++;
if (rl_pending_input)
{
c = rl_pending_input;
rl_clear_pending_input ();
}
else
{
/* If input is coming from a macro, then use that. */
if (c = _rl_next_macro_key ())
return (c);
/* If the user has an event function, then call it periodically. */
if (rl_event_hook)
{
while (rl_event_hook && rl_get_char (&c) == 0)
{
(*rl_event_hook) ();
if (rl_done) /* XXX - experimental */
return ('\n');
if (rl_gather_tyi () < 0) /* XXX - EIO */
{
rl_done = 1;
return ('\n');
}
}
}
else
{
if (rl_get_char (&c) == 0)
c = (*rl_getc_function) (rl_instream);
}
}
return (c);
}
int
rl_getc (stream)
FILE *stream;
{
int result;
unsigned char c;
while (1)
{
result = read (fileno (stream), &c, sizeof (unsigned char));
if (result == sizeof (unsigned char))
return (c);
/* If zero characters are returned, then the file that we are
reading from is empty! Return EOF in that case. */
if (result == 0)
return (EOF);
#if defined (__BEOS__)
if (errno == EINTR)
continue;
#endif
#if defined (EWOULDBLOCK)
# define X_EWOULDBLOCK EWOULDBLOCK
#else
# define X_EWOULDBLOCK -99
#endif
#if defined (EAGAIN)
# define X_EAGAIN EAGAIN
#else
# define X_EAGAIN -99
#endif
if (errno == X_EWOULDBLOCK || errno == X_EAGAIN)
{
if (sh_unset_nodelay_mode (fileno (stream)) < 0)
return (EOF);
continue;
}
#undef X_EWOULDBLOCK
#undef X_EAGAIN
/* If the error that we received was SIGINT, then try again,
this is simply an interrupted system call to read ().
Otherwise, some error ocurred, also signifying EOF. */
if (errno != EINTR)
return (EOF);
}
}
#if defined (HANDLE_MULTIBYTE)
/* read multibyte char */
int
_rl_read_mbchar (mbchar, size)
char *mbchar;
int size;
{
int mb_len = 0;
size_t mbchar_bytes_length;
wchar_t wc;
mbstate_t ps, ps_back;
memset(&ps, 0, sizeof (mbstate_t));
memset(&ps_back, 0, sizeof (mbstate_t));
while (mb_len < size)
{
RL_SETSTATE(RL_STATE_MOREINPUT);
mbchar[mb_len++] = rl_read_key ();
RL_UNSETSTATE(RL_STATE_MOREINPUT);
mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps);
if (mbchar_bytes_length == (size_t)(-1))
break; /* invalid byte sequence for the current locale */
else if (mbchar_bytes_length == (size_t)(-2))
{
/* shorted bytes */
ps = ps_back;
continue;
}
else if (mbchar_bytes_length > (size_t)(0))
break;
}
return mb_len;
}
/* Read a multibyte-character string whose first character is FIRST into
the buffer MB of length MBLEN. Returns the last character read, which
may be FIRST. Used by the search functions, among others. Very similar
to _rl_read_mbchar. */
int
_rl_read_mbstring (first, mb, mblen)
int first;
char *mb;
int mblen;
{
int i, c;
mbstate_t ps;
c = first;
memset (mb, 0, mblen);
for (i = 0; i < mblen; i++)
{
mb[i] = (char)c;
memset (&ps, 0, sizeof (mbstate_t));
if (_rl_get_char_len (mb, &ps) == -2)
{
/* Read more for multibyte character */
RL_SETSTATE (RL_STATE_MOREINPUT);
c = rl_read_key ();
RL_UNSETSTATE (RL_STATE_MOREINPUT);
}
else
break;
}
return c;
}
#endif /* HANDLE_MULTIBYTE */
+4
View File
@@ -21,6 +21,10 @@
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#define READLINE_LIBRARY
#if defined (__TANDEM)
# include <floss.h>
#endif
#include "rlconf.h"
#if defined (HAVE_CONFIG_H)
+179
View File
@@ -0,0 +1,179 @@
/* parens.c -- Implementation of matching parentheses feature. */
/* Copyright (C) 1987, 1989, 1992 Free Software Foundation, Inc.
This file is part of the GNU Readline Library, a library for
reading lines of text with interactive input and history editing.
The GNU Readline Library is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2, or
(at your option) any later version.
The GNU Readline Library is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
The GNU General Public License is often shipped with GNU software, and
is generally kept in a file called COPYING or LICENSE. If you do not
have a copy of the license, write to the Free Software Foundation,
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#define READLINE_LIBRARY
#include "rlconf.h"
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined (FD_SET) && !defined (HAVE_SELECT)
# define HAVE_SELECT
#endif
#if defined (HAVE_SELECT)
# include <sys/time.h>
#endif /* HAVE_SELECT */
#if defined (HAVE_SYS_SELECT_H)
# include <sys/select.h>
#endif
#if defined (HAVE_STRING_H)
# include <string.h>
#else /* !HAVE_STRING_H */
# include <strings.h>
#endif /* !HAVE_STRING_H */
#if !defined (strchr) && !defined (__STDC__)
extern char *strchr (), *strrchr ();
#endif /* !strchr && !__STDC__ */
#include "readline.h"
#include "rlprivate.h"
static int find_matching_open PARAMS((char *, int, int));
/* Non-zero means try to blink the matching open parenthesis when the
close parenthesis is inserted. */
#if defined (HAVE_SELECT)
int rl_blink_matching_paren = 1;
#else /* !HAVE_SELECT */
int rl_blink_matching_paren = 0;
#endif /* !HAVE_SELECT */
static int _paren_blink_usec = 500000;
/* Change emacs_standard_keymap to have bindings for paren matching when
ON_OR_OFF is 1, change them back to self_insert when ON_OR_OFF == 0. */
void
_rl_enable_paren_matching (on_or_off)
int on_or_off;
{
if (on_or_off)
{ /* ([{ */
rl_bind_key_in_map (')', rl_insert_close, emacs_standard_keymap);
rl_bind_key_in_map (']', rl_insert_close, emacs_standard_keymap);
rl_bind_key_in_map ('}', rl_insert_close, emacs_standard_keymap);
}
else
{ /* ([{ */
rl_bind_key_in_map (')', rl_insert, emacs_standard_keymap);
rl_bind_key_in_map (']', rl_insert, emacs_standard_keymap);
rl_bind_key_in_map ('}', rl_insert, emacs_standard_keymap);
}
}
int
rl_set_paren_blink_timeout (u)
int u;
{
int o;
o = _paren_blink_usec;
if (u > 0)
_paren_blink_usec = u;
return (o);
}
int
rl_insert_close (count, invoking_key)
int count, invoking_key;
{
if (rl_explicit_arg || !rl_blink_matching_paren)
_rl_insert_char (count, invoking_key);
else
{
#if defined (HAVE_SELECT)
int orig_point, match_point, ready;
struct timeval timer;
fd_set readfds;
_rl_insert_char (1, invoking_key);
(*rl_redisplay_function) ();
match_point =
find_matching_open (rl_line_buffer, rl_point - 2, invoking_key);
/* Emacs might message or ring the bell here, but I don't. */
if (match_point < 0)
return -1;
FD_ZERO (&readfds);
FD_SET (fileno (rl_instream), &readfds);
timer.tv_sec = 0;
timer.tv_usec = _paren_blink_usec;
orig_point = rl_point;
rl_point = match_point;
(*rl_redisplay_function) ();
ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer);
rl_point = orig_point;
#else /* !HAVE_SELECT */
_rl_insert_char (count, invoking_key);
#endif /* !HAVE_SELECT */
}
return 0;
}
static int
find_matching_open (string, from, closer)
char *string;
int from, closer;
{
register int i;
int opener, level, delimiter;
switch (closer)
{
case ']': opener = '['; break;
case '}': opener = '{'; break;
case ')': opener = '('; break;
default:
return (-1);
}
level = 1; /* The closer passed in counts as 1. */
delimiter = 0; /* Delimited state unknown. */
for (i = from; i > -1; i--)
{
if (delimiter && (string[i] == delimiter))
delimiter = 0;
else if (rl_basic_quote_characters && strchr (rl_basic_quote_characters, string[i]))
delimiter = string[i];
else if (!delimiter && (string[i] == closer))
level++;
else if (!delimiter && (string[i] == opener))
level--;
if (!level)
break;
}
return (i);
}
+1 -1
View File
@@ -95,7 +95,7 @@ static int iso8601wknum(const struct tm *timeptr);
#if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME)
extern char *tzname[2];
extern int daylight;
#if defined(SOLARIS) || defined(mips)
#if defined(SOLARIS) || defined(mips) || defined (M_UNIX)
extern long int timezone, altzone;
#else
extern int timezone, altzone;
+859
View File
@@ -0,0 +1,859 @@
/*
* Modified slightly by Chet Ramey for inclusion in Bash
*/
/*
* strftime.c
*
* Public-domain implementation of ISO C library routine.
*
* If you can't do prototypes, get GCC.
*
* The C99 standard now specifies just about all of the formats
* that were additional in the earlier versions of this file.
*
* For extensions from SunOS, add SUNOS_EXT.
* For extensions from HP/UX, add HPUX_EXT.
* For VMS dates, add VMS_EXT.
* For complete POSIX semantics, add POSIX_SEMANTICS.
*
* The code for %c, %x, and %X follows the C99 specification for
* the "C" locale.
*
* This version ignores LOCALE information.
* It also doesn't worry about multi-byte characters.
* So there.
*
* This file is also shipped with GAWK (GNU Awk), gawk specific bits of
* code are included if GAWK is defined.
*
* Arnold Robbins
* January, February, March, 1991
* Updated March, April 1992
* Updated April, 1993
* Updated February, 1994
* Updated May, 1994
* Updated January, 1995
* Updated September, 1995
* Updated January, 1996
* Updated July, 1997
* Updated October, 1999
* Updated September, 2000
*
* Fixes from ado@elsie.nci.nih.gov,
* February 1991, May 1992
* Fixes from Tor Lillqvist tml@tik.vtt.fi,
* May 1993
* Further fixes from ado@elsie.nci.nih.gov,
* February 1994
* %z code from chip@chinacat.unicom.com,
* Applied September 1995
* %V code fixed (again) and %G, %g added,
* January 1996
* %v code fixed, better configuration,
* July 1997
* Moved to C99 specification.
* September 2000
*/
#include <config.h>
#ifndef GAWK
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#endif
#if defined(TM_IN_SYS_TIME)
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <stdlib.h>
#include <string.h>
/* defaults: season to taste */
#define SUNOS_EXT 1 /* stuff in SunOS strftime routine */
#define VMS_EXT 1 /* include %v for VMS date format */
#define HPUX_EXT 1 /* non-conflicting stuff in HP-UX date */
#ifndef GAWK
#define POSIX_SEMANTICS 1 /* call tzset() if TZ changes */
#endif
#undef strchr /* avoid AIX weirdness */
extern void tzset(void);
static int weeknumber(const struct tm *timeptr, int firstweekday);
static int iso8601wknum(const struct tm *timeptr);
#ifdef __GNUC__
#define inline __inline__
#else
#define inline /**/
#endif
#define range(low, item, hi) max(low, min(item, hi))
#if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME)
extern char *tzname[2];
extern int daylight;
#if defined(SOLARIS) || defined(mips)
extern long int timezone, altzone;
#else
extern int timezone, altzone;
#endif
#endif
#undef min /* just in case */
/* min --- return minimum of two numbers */
static inline int
min(int a, int b)
{
return (a < b ? a : b);
}
#undef max /* also, just in case */
/* max --- return maximum of two numbers */
static inline int
max(int a, int b)
{
return (a > b ? a : b);
}
/* strftime --- produce formatted time */
size_t
strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr)
{
char *endp = s + maxsize;
char *start = s;
auto char tbuf[100];
long off;
int i, w, y;
static short first = 1;
#ifdef POSIX_SEMANTICS
static char *savetz = NULL;
static int savetzlen = 0;
char *tz;
#endif /* POSIX_SEMANTICS */
#ifndef HAVE_TM_ZONE
#ifndef HAVE_TM_NAME
#ifndef HAVE_TZNAME
extern char *timezone();
struct timeval tv;
struct timezone zone;
#endif /* HAVE_TZNAME */
#endif /* HAVE_TM_NAME */
#endif /* HAVE_TM_ZONE */
/* various tables, useful in North America */
static const char *days_a[] = {
"Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat",
};
static const char *days_l[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday",
};
static const char *months_a[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
static const char *months_l[] = {
"January", "February", "March", "April",
"May", "June", "July", "August", "September",
"October", "November", "December",
};
static const char *ampm[] = { "AM", "PM", };
if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0)
return 0;
/* quick check if we even need to bother */
if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize)
return 0;
#ifndef POSIX_SEMANTICS
if (first) {
tzset();
first = 0;
}
#else /* POSIX_SEMANTICS */
#if defined (SHELL)
tz = get_string_value ("TZ");
#else
tz = getenv("TZ");
#endif
if (first) {
if (tz != NULL) {
int tzlen = strlen(tz);
savetz = (char *) malloc(tzlen + 1);
if (savetz != NULL) {
savetzlen = tzlen + 1;
strcpy(savetz, tz);
}
}
tzset();
first = 0;
}
/* if we have a saved TZ, and it is different, recapture and reset */
if (tz && savetz && (tz[0] != savetz[0] || strcmp(tz, savetz) != 0)) {
i = strlen(tz) + 1;
if (i > savetzlen) {
savetz = (char *) realloc(savetz, i);
if (savetz) {
savetzlen = i;
strcpy(savetz, tz);
}
} else
strcpy(savetz, tz);
tzset();
}
#endif /* POSIX_SEMANTICS */
for (; *format && s < endp - 1; format++) {
tbuf[0] = '\0';
if (*format != '%') {
*s++ = *format;
continue;
}
again:
switch (*++format) {
case '\0':
*s++ = '%';
goto out;
case '%':
*s++ = '%';
continue;
case 'a': /* abbreviated weekday name */
if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
strcpy(tbuf, "?");
else
strcpy(tbuf, days_a[timeptr->tm_wday]);
break;
case 'A': /* full weekday name */
if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
strcpy(tbuf, "?");
else
strcpy(tbuf, days_l[timeptr->tm_wday]);
break;
case 'b': /* abbreviated month name */
short_month:
if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)
strcpy(tbuf, "?");
else
strcpy(tbuf, months_a[timeptr->tm_mon]);
break;
case 'B': /* full month name */
if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)
strcpy(tbuf, "?");
else
strcpy(tbuf, months_l[timeptr->tm_mon]);
break;
case 'c': /* appropriate date and time representation */
/*
* This used to be:
*
* strftime(tbuf, sizeof tbuf, "%a %b %e %H:%M:%S %Y", timeptr);
*
* Now, per the ISO 1999 C standard, it this:
*/
strftime(tbuf, sizeof tbuf, "%A %B %d %T %Y", timeptr);
break;
case 'C':
century:
sprintf(tbuf, "%02d", (timeptr->tm_year + 1900) / 100);
break;
case 'd': /* day of the month, 01 - 31 */
i = range(1, timeptr->tm_mday, 31);
sprintf(tbuf, "%02d", i);
break;
case 'D': /* date as %m/%d/%y */
strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr);
break;
case 'e': /* day of month, blank padded */
sprintf(tbuf, "%2d", range(1, timeptr->tm_mday, 31));
break;
case 'E':
/* POSIX (now C99) locale extensions, ignored for now */
goto again;
case 'F': /* ISO 8601 date representation */
strftime(tbuf, sizeof tbuf, "%Y-%m-%d", timeptr);
break;
case 'g':
case 'G':
/*
* Year of ISO week.
*
* If it's December but the ISO week number is one,
* that week is in next year.
* If it's January but the ISO week number is 52 or
* 53, that week is in last year.
* Otherwise, it's this year.
*/
w = iso8601wknum(timeptr);
if (timeptr->tm_mon == 11 && w == 1)
y = 1900 + timeptr->tm_year + 1;
else if (timeptr->tm_mon == 0 && w >= 52)
y = 1900 + timeptr->tm_year - 1;
else
y = 1900 + timeptr->tm_year;
if (*format == 'G')
sprintf(tbuf, "%d", y);
else
sprintf(tbuf, "%02d", y % 100);
break;
case 'h': /* abbreviated month name */
goto short_month;
case 'H': /* hour, 24-hour clock, 00 - 23 */
i = range(0, timeptr->tm_hour, 23);
sprintf(tbuf, "%02d", i);
break;
case 'I': /* hour, 12-hour clock, 01 - 12 */
i = range(0, timeptr->tm_hour, 23);
if (i == 0)
i = 12;
else if (i > 12)
i -= 12;
sprintf(tbuf, "%02d", i);
break;
case 'j': /* day of the year, 001 - 366 */
sprintf(tbuf, "%03d", timeptr->tm_yday + 1);
break;
case 'm': /* month, 01 - 12 */
i = range(0, timeptr->tm_mon, 11);
sprintf(tbuf, "%02d", i + 1);
break;
case 'M': /* minute, 00 - 59 */
i = range(0, timeptr->tm_min, 59);
sprintf(tbuf, "%02d", i);
break;
case 'n': /* same as \n */
tbuf[0] = '\n';
tbuf[1] = '\0';
break;
case 'O':
/* POSIX (now C99) locale extensions, ignored for now */
goto again;
case 'p': /* am or pm based on 12-hour clock */
i = range(0, timeptr->tm_hour, 23);
if (i < 12)
strcpy(tbuf, ampm[0]);
else
strcpy(tbuf, ampm[1]);
break;
case 'r': /* time as %I:%M:%S %p */
strftime(tbuf, sizeof tbuf, "%I:%M:%S %p", timeptr);
break;
case 'R': /* time as %H:%M */
strftime(tbuf, sizeof tbuf, "%H:%M", timeptr);
break;
#if defined(HAVE_MKTIME) || defined(GAWK)
case 's': /* time as seconds since the Epoch */
{
struct tm non_const_timeptr;
non_const_timeptr = *timeptr;
sprintf(tbuf, "%ld", mktime(& non_const_timeptr));
break;
}
#endif /* defined(HAVE_MKTIME) || defined(GAWK) */
case 'S': /* second, 00 - 60 */
i = range(0, timeptr->tm_sec, 60);
sprintf(tbuf, "%02d", i);
break;
case 't': /* same as \t */
tbuf[0] = '\t';
tbuf[1] = '\0';
break;
case 'T': /* time as %H:%M:%S */
the_time:
strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr);
break;
case 'u':
/* ISO 8601: Weekday as a decimal number [1 (Monday) - 7] */
sprintf(tbuf, "%d", timeptr->tm_wday == 0 ? 7 :
timeptr->tm_wday);
break;
case 'U': /* week of year, Sunday is first day of week */
sprintf(tbuf, "%02d", weeknumber(timeptr, 0));
break;
case 'V': /* week of year according ISO 8601 */
sprintf(tbuf, "%02d", iso8601wknum(timeptr));
break;
case 'w': /* weekday, Sunday == 0, 0 - 6 */
i = range(0, timeptr->tm_wday, 6);
sprintf(tbuf, "%d", i);
break;
case 'W': /* week of year, Monday is first day of week */
sprintf(tbuf, "%02d", weeknumber(timeptr, 1));
break;
case 'x': /* appropriate date representation */
strftime(tbuf, sizeof tbuf, "%A %B %d %Y", timeptr);
break;
case 'X': /* appropriate time representation */
goto the_time;
break;
case 'y': /* year without a century, 00 - 99 */
year:
i = timeptr->tm_year % 100;
sprintf(tbuf, "%02d", i);
break;
case 'Y': /* year with century */
fullyear:
sprintf(tbuf, "%d", 1900 + timeptr->tm_year);
break;
/*
* From: Chip Rosenthal <chip@chinacat.unicom.com>
* Date: Sun, 19 Mar 1995 00:33:29 -0600 (CST)
*
* Warning: the %z [code] is implemented by inspecting the
* timezone name conditional compile settings, and
* inferring a method to get timezone offsets. I've tried
* this code on a couple of machines, but I don't doubt
* there is some system out there that won't like it.
* Maybe the easiest thing to do would be to bracket this
* with an #ifdef that can turn it off. The %z feature
* would be an admittedly obscure one that most folks can
* live without, but it would be a great help to those of
* us that muck around with various message processors.
*/
case 'z': /* time zone offset east of GMT e.g. -0600 */
#ifdef HAVE_TM_NAME
/*
* Systems with tm_name probably have tm_tzadj as
* secs west of GMT. Convert to mins east of GMT.
*/
off = -timeptr->tm_tzadj / 60;
#else /* !HAVE_TM_NAME */
#ifdef HAVE_TM_ZONE
/*
* Systems with tm_zone probably have tm_gmtoff as
* secs east of GMT. Convert to mins east of GMT.
*/
off = timeptr->tm_gmtoff / 60;
#else /* !HAVE_TM_ZONE */
#if HAVE_TZNAME
/*
* Systems with tzname[] probably have timezone as
* secs west of GMT. Convert to mins east of GMT.
*/
off = -(daylight ? timezone : altzone) / 60;
#else /* !HAVE_TZNAME */
off = -zone.tz_minuteswest;
#endif /* !HAVE_TZNAME */
#endif /* !HAVE_TM_ZONE */
#endif /* !HAVE_TM_NAME */
if (off < 0) {
tbuf[0] = '-';
off = -off;
} else {
tbuf[0] = '+';
}
sprintf(tbuf+1, "%02d%02d", off/60, off%60);
break;
case 'Z': /* time zone name or abbrevation */
#ifdef HAVE_TZNAME
i = (daylight && timeptr->tm_isdst > 0); /* 0 or 1 */
strcpy(tbuf, tzname[i]);
#else
#ifdef HAVE_TM_ZONE
strcpy(tbuf, timeptr->tm_zone);
#else
#ifdef HAVE_TM_NAME
strcpy(tbuf, timeptr->tm_name);
#else
gettimeofday(& tv, & zone);
strcpy(tbuf, timezone(zone.tz_minuteswest,
timeptr->tm_isdst > 0));
#endif /* HAVE_TM_NAME */
#endif /* HAVE_TM_ZONE */
#endif /* HAVE_TZNAME */
break;
#ifdef SUNOS_EXT
case 'k': /* hour, 24-hour clock, blank pad */
sprintf(tbuf, "%2d", range(0, timeptr->tm_hour, 23));
break;
case 'l': /* hour, 12-hour clock, 1 - 12, blank pad */
i = range(0, timeptr->tm_hour, 23);
if (i == 0)
i = 12;
else if (i > 12)
i -= 12;
sprintf(tbuf, "%2d", i);
break;
#endif
#ifdef HPUX_EXT
case 'N': /* Emperor/Era name */
/* this is essentially the same as the century */
goto century; /* %C */
case 'o': /* Emperor/Era year */
goto year; /* %y */
#endif /* HPUX_EXT */
#ifdef VMS_EXT
case 'v': /* date as dd-bbb-YYYY */
sprintf(tbuf, "%2d-%3.3s-%4d",
range(1, timeptr->tm_mday, 31),
months_a[range(0, timeptr->tm_mon, 11)],
timeptr->tm_year + 1900);
for (i = 3; i < 6; i++)
if (islower(tbuf[i]))
tbuf[i] = toupper(tbuf[i]);
break;
#endif
default:
tbuf[0] = '%';
tbuf[1] = *format;
tbuf[2] = '\0';
break;
}
i = strlen(tbuf);
if (i) {
if (s + i < endp - 1) {
strcpy(s, tbuf);
s += i;
} else
return 0;
}
}
out:
if (s < endp && *format == '\0') {
*s = '\0';
return (s - start);
} else
return 0;
}
/* isleap --- is a year a leap year? */
static int
isleap(int year)
{
return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
}
/* iso8601wknum --- compute week number according to ISO 8601 */
static int
iso8601wknum(const struct tm *timeptr)
{
/*
* From 1003.2:
* If the week (Monday to Sunday) containing January 1
* has four or more days in the new year, then it is week 1;
* otherwise it is the highest numbered week of the previous
* year (52 or 53), and the next week is week 1.
*
* ADR: This means if Jan 1 was Monday through Thursday,
* it was week 1, otherwise week 52 or 53.
*
* XPG4 erroneously included POSIX.2 rationale text in the
* main body of the standard. Thus it requires week 53.
*/
int weeknum, jan1day, diff;
/* get week number, Monday as first day of the week */
weeknum = weeknumber(timeptr, 1);
/*
* With thanks and tip of the hatlo to tml@tik.vtt.fi
*
* What day of the week does January 1 fall on?
* We know that
* (timeptr->tm_yday - jan1.tm_yday) MOD 7 ==
* (timeptr->tm_wday - jan1.tm_wday) MOD 7
* and that
* jan1.tm_yday == 0
* and that
* timeptr->tm_wday MOD 7 == timeptr->tm_wday
* from which it follows that. . .
*/
jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7);
if (jan1day < 0)
jan1day += 7;
/*
* If Jan 1 was a Monday through Thursday, it was in
* week 1. Otherwise it was last year's highest week, which is
* this year's week 0.
*
* What does that mean?
* If Jan 1 was Monday, the week number is exactly right, it can
* never be 0.
* If it was Tuesday through Thursday, the weeknumber is one
* less than it should be, so we add one.
* Otherwise, Friday, Saturday or Sunday, the week number is
* OK, but if it is 0, it needs to be 52 or 53.
*/
switch (jan1day) {
case 1: /* Monday */
break;
case 2: /* Tuesday */
case 3: /* Wednesday */
case 4: /* Thursday */
weeknum++;
break;
case 5: /* Friday */
case 6: /* Saturday */
case 0: /* Sunday */
if (weeknum == 0) {
#ifdef USE_BROKEN_XPG4
/* XPG4 (as of March 1994) says 53 unconditionally */
weeknum = 53;
#else
/* get week number of last week of last year */
struct tm dec31ly; /* 12/31 last year */
dec31ly = *timeptr;
dec31ly.tm_year--;
dec31ly.tm_mon = 11;
dec31ly.tm_mday = 31;
dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1;
dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900);
weeknum = iso8601wknum(& dec31ly);
#endif
}
break;
}
if (timeptr->tm_mon == 11) {
/*
* The last week of the year
* can be in week 1 of next year.
* Sigh.
*
* This can only happen if
* M T W
* 29 30 31
* 30 31
* 31
*/
int wday, mday;
wday = timeptr->tm_wday;
mday = timeptr->tm_mday;
if ( (wday == 1 && (mday >= 29 && mday <= 31))
|| (wday == 2 && (mday == 30 || mday == 31))
|| (wday == 3 && mday == 31))
weeknum = 1;
}
return weeknum;
}
/* weeknumber --- figure how many weeks into the year */
/* With thanks and tip of the hatlo to ado@elsie.nci.nih.gov */
static int
weeknumber(const struct tm *timeptr, int firstweekday)
{
int wday = timeptr->tm_wday;
int ret;
if (firstweekday == 1) {
if (wday == 0) /* sunday */
wday = 6;
else
wday--;
}
ret = ((timeptr->tm_yday + 7 - wday) / 7);
if (ret < 0)
ret = 0;
return ret;
}
#if 0
/* ADR --- I'm loathe to mess with ado's code ... */
Date: Wed, 24 Apr 91 20:54:08 MDT
From: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK>
To: arnold@audiofax.com
Hi Arnold,
in a process of fixing of strftime() in libraries on Atari ST I grabbed
some pieces of code from your own strftime. When doing that it came
to mind that your weeknumber() function compiles a little bit nicer
in the following form:
/*
* firstweekday is 0 if starting in Sunday, non-zero if in Monday
*/
{
return (timeptr->tm_yday - timeptr->tm_wday +
(firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7;
}
How nicer it depends on a compiler, of course, but always a tiny bit.
Cheers,
Michal
ntomczak@vm.ucs.ualberta.ca
#endif
#ifdef TEST_STRFTIME
/*
* NAME:
* tst
*
* SYNOPSIS:
* tst
*
* DESCRIPTION:
* "tst" is a test driver for the function "strftime".
*
* OPTIONS:
* None.
*
* AUTHOR:
* Karl Vogel
* Control Data Systems, Inc.
* vogelke@c-17igp.wpafb.af.mil
*
* BUGS:
* None noticed yet.
*
* COMPILE:
* cc -o tst -DTEST_STRFTIME strftime.c
*/
/* ADR: I reformatted this to my liking, and deleted some unneeded code. */
#ifndef NULL
#include <stdio.h>
#endif
#include <sys/time.h>
#include <string.h>
#define MAXTIME 132
/*
* Array of time formats.
*/
static char *array[] =
{
"(%%A) full weekday name, var length (Sunday..Saturday) %A",
"(%%B) full month name, var length (January..December) %B",
"(%%C) Century %C",
"(%%D) date (%%m/%%d/%%y) %D",
"(%%E) Locale extensions (ignored) %E",
"(%%F) full month name, var length (January..December) %F",
"(%%H) hour (24-hour clock, 00..23) %H",
"(%%I) hour (12-hour clock, 01..12) %I",
"(%%M) minute (00..59) %M",
"(%%N) Emporer/Era Name %N",
"(%%O) Locale extensions (ignored) %O",
"(%%R) time, 24-hour (%%H:%%M) %R",
"(%%S) second (00..60) %S",
"(%%T) time, 24-hour (%%H:%%M:%%S) %T",
"(%%U) week of year, Sunday as first day of week (00..53) %U",
"(%%V) week of year according to ISO 8601 %V",
"(%%W) week of year, Monday as first day of week (00..53) %W",
"(%%X) appropriate locale time representation (%H:%M:%S) %X",
"(%%Y) year with century (1970...) %Y",
"(%%Z) timezone (EDT), or blank if timezone not determinable %Z",
"(%%a) locale's abbreviated weekday name (Sun..Sat) %a",
"(%%b) locale's abbreviated month name (Jan..Dec) %b",
"(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c",
"(%%d) day of the month (01..31) %d",
"(%%e) day of the month, blank-padded ( 1..31) %e",
"(%%h) should be same as (%%b) %h",
"(%%j) day of the year (001..366) %j",
"(%%k) hour, 24-hour clock, blank pad ( 0..23) %k",
"(%%l) hour, 12-hour clock, blank pad ( 0..12) %l",
"(%%m) month (01..12) %m",
"(%%o) Emporer/Era Year %o",
"(%%p) locale's AM or PM based on 12-hour clock %p",
"(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r",
"(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u",
"(%%v) VMS date (dd-bbb-YYYY) %v",
"(%%w) day of week (0..6, Sunday == 0) %w",
"(%%x) appropriate locale date representation %x",
"(%%y) last two digits of year (00..99) %y",
"(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z",
(char *) NULL
};
/* main routine. */
int
main(argc, argv)
int argc;
char **argv;
{
long time();
char *next;
char string[MAXTIME];
int k;
int length;
struct tm *tm;
long clock;
/* Call the function. */
clock = time((long *) 0);
tm = localtime(&clock);
for (k = 0; next = array[k]; k++) {
length = strftime(string, MAXTIME, next, tm);
printf("%s\n", string);
}
exit(0);
}
#endif /* TEST_STRFTIME */
+10
View File
@@ -5827,10 +5827,17 @@ param_expand (string, sindex, quoted, expanded_something,
string might need it (consider "\"$@\""), but we need some
way to signal that the final split on the first character
of $IFS should be done, even though QUOTED is 1. */
#if 0
if (list && list->next)
{
#endif
if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
*quoted_dollar_at_p = 1;
if (contains_dollar_at)
*contains_dollar_at = 1;
#if 0
}
#endif
/* We want to separate the positional parameters with the first
character of $IFS in case $IFS is something other than a space.
@@ -5974,6 +5981,8 @@ comsub:
temp = array_reference (array_cell (var), 0);
if (temp)
temp = quote_escapes (temp);
else if (unbound_vars_is_error)
goto unbound_variable;
}
else
#endif
@@ -5985,6 +5994,7 @@ comsub:
temp = (char *)NULL;
unbound_variable:
if (unbound_vars_is_error)
err_unboundvar (temp1);
else
+379 -178
View File
@@ -212,8 +212,21 @@ static char *pos_params __P((char *, int, int, int));
static unsigned char *mb_getcharlens __P((char *, int));
static char *remove_upattern __P((char *, char *, int));
#if defined (HANDLE_MULTIBYTE)
# if !defined (HAVE_WCSDUP)
static wchar_t *wcsdup __P((wchar_t *));
# endif
static wchar_t *remove_wpattern __P((wchar_t *, size_t, wchar_t *, int));
#endif
static char *remove_pattern __P((char *, char *, int));
static int match_pattern_char __P((char *, char *));
static int match_upattern __P((char *, char *, int, char **, char **));
#if defined (HANDLE_MULTIBYTE)
static int match_pattern_wchar __P((wchar_t *, wchar_t *));
static int match_wpattern __P((wchar_t *, char **, size_t, wchar_t *, int, char **, char **));
#endif
static int match_pattern __P((char *, char *, int, char **, char **));
static int getpatspec __P((int, char *));
static char *getpattern __P((char *, int, int));
@@ -1171,9 +1184,9 @@ de_backslash (string)
prev_i = i;
ADVANCE_CHAR (string, slen, i);
if (j < prev_i)
do string[j++] = string[prev_i++]; while (prev_i < i);
do string[j++] = string[prev_i++]; while (prev_i < i);
else
j = i;
j = i;
}
string[j] = '\0';
@@ -1565,6 +1578,10 @@ string_list_internal (list, sep)
if (list == 0)
return ((char *)NULL);
/* Short-circuit quickly if we don't need to separate anything. */
if (list->next == 0)
return (savestring (list->word->word));
/* This is nearly always called with either sep[0] == 0 or sep[1] == 0. */
sep_len = STRLEN (sep);
result_size = 0;
@@ -2795,17 +2812,17 @@ remove_quoted_nulls (string)
while (i < slen)
{
if (string[i] == CTLESC)
{
{
/* Old code had j++, but we cannot assume that i == j at this
point -- what if a CTLNUL has already been removed from the
string? We don't want to drop the CTLESC or recopy characters
that we've already copied down. */
i++; string[j++] = CTLESC;
if (i == slen)
break;
}
if (i == slen)
break;
}
else if (string[i] == CTLNUL)
i++;
i++;
prev_i = i;
ADVANCE_CHAR (string, slen, i);
@@ -2840,13 +2857,14 @@ word_list_remove_quoted_nulls (list)
/* **************************************************************** */
#if defined (HANDLE_MULTIBYTE)
#if 0 /* Currently unused */
static unsigned char *
mb_getcharlens (string, len)
char *string;
int len;
{
int i, offset;
unsigned char last, *ret;
int i, offset, last;
unsigned char *ret;
char *p;
DECLARE_MBSTATE;
@@ -2863,6 +2881,7 @@ mb_getcharlens (string, len)
return ret;
}
#endif
#endif
/* Remove the portion of PARAM matched by PATTERN according to OP, where OP
can have one of 4 values:
@@ -2878,130 +2897,208 @@ mb_getcharlens (string, len)
#define RP_SHORT_RIGHT 4
static char *
remove_pattern (param, pattern, op)
remove_upattern (param, pattern, op)
char *param, *pattern;
int op;
{
register int len;
register char *end;
register char *p, *ret, c;
int offset;
unsigned char *mblen;
DECLARE_MBSTATE;
len = STRLEN (param);
end = param + len;
switch (op)
{
case RP_LONG_LEFT: /* remove longest match at start */
for (p = end; p >= param; p--)
{
c = *p; *p = '\0';
if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
*p = c;
return (savestring (p));
}
*p = c;
}
break;
case RP_SHORT_LEFT: /* remove shortest match at start */
for (p = param; p <= end; p++)
{
c = *p; *p = '\0';
if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
*p = c;
return (savestring (p));
}
*p = c;
}
break;
case RP_LONG_RIGHT: /* remove longest match at end */
for (p = param; p <= end; p++)
{
if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
c = *p; *p = '\0';
ret = savestring (param);
*p = c;
return (ret);
}
}
break;
case RP_SHORT_RIGHT: /* remove shortest match at end */
for (p = end; p >= param; p--)
{
if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
c = *p; *p = '\0';
ret = savestring (param);
*p = c;
return (ret);
}
}
break;
}
return (savestring (param)); /* no match, return original string */
}
#if defined (HANDLE_MULTIBYTE)
#if !defined (HAVE_WCSDUP)
static wchar_t *
wcsdup (ws)
wchar_t *ws;
{
wchar_t *ret;
size_t len;
len = wcslen (ws);
ret = xmalloc ((len + 1) * sizeof (wchar_t));
if (ret == 0)
return ret;
return (wcscpy (ret, ws));
}
#endif /* !HAVE_WCSDUP */
static wchar_t *
remove_wpattern (wparam, wstrlen, wpattern, op)
wchar_t *wparam;
size_t wstrlen;
wchar_t *wpattern;
int op;
{
wchar_t wc;
int n, n1;
wchar_t *ret;
switch (op)
{
case RP_LONG_LEFT: /* remove longest match at start */
for (n = wstrlen; n >= 0; n--)
{
wc = wparam[n]; wparam[n] = L'\0';
if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
wparam[n] = wc;
return (wcsdup (wparam + n));
}
wparam[n] = wc;
}
break;
case RP_SHORT_LEFT: /* remove shortest match at start */
for (n = 0; n <= wstrlen; n++)
{
wc = wparam[n]; wparam[n] = L'\0';
if (wcsmatch (wpattern, wparam, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
wparam[n] = wc;
return (wcsdup (wparam + n));
}
wparam[n] = wc;
}
break;
case RP_LONG_RIGHT: /* remove longest match at end */
for (n = 0; n <= wstrlen; n++)
{
if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
wc = wparam[n]; wparam[n] = L'\0';
ret = wcsdup (wparam);
wparam[n] = wc;
return (ret);
}
}
break;
case RP_SHORT_RIGHT: /* remove shortest match at end */
for (n = wstrlen; n >= 0; n--)
{
if (wcsmatch (wpattern, wparam + n, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
wc = wparam[n]; wparam[n] = L'\0';
ret = wcsdup (wparam);
wparam[n] = wc;
return (ret);
}
}
break;
}
return (wcsdup (wparam)); /* no match, return original string */
}
#endif /* HANDLE_MULTIBYTE */
static char *
remove_pattern (param, pattern, op)
char *param, *pattern;
int op;
{
if (param == NULL)
return (param);
if (*param == '\0' || pattern == NULL || *pattern == '\0') /* minor optimization */
return (savestring (param));
len = STRLEN (param);
end = param + len;
mblen = (unsigned char *)0;
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && (op == RP_LONG_LEFT || op == RP_SHORT_RIGHT))
mblen = mb_getcharlens (param, len);
#endif
switch (op)
if (MB_CUR_MAX > 1)
{
case RP_LONG_LEFT: /* remove longest match at start */
p = end;
while (p >= param)
{
c = *p; *p = '\0';
if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
*p = c;
FREE (mblen);
return (savestring (p));
}
*p = c;
wchar_t *ret, *oret;
size_t n;
wchar_t *wparam, *wpattern;
mbstate_t ps;
char *xret;
if (MB_CUR_MAX > 1)
{
while (p >= param)
if (mblen[--p - param])
break;
}
else
p--;
}
break;
n = xdupmbstowcs (&wpattern, NULL, pattern);
if (n == (size_t)-1)
return (remove_upattern (param, pattern, op));
n = xdupmbstowcs (&wparam, NULL, param);
if (n == (size_t)-1)
{
free (wpattern);
return (remove_upattern (param, pattern, op));
}
oret = ret = remove_wpattern (wparam, n, wpattern, op);
case RP_SHORT_LEFT: /* remove shortest match at start */
p = param;
offset = 0;
while (p <= end)
{
c = *p; *p = '\0';
if (strmatch (pattern, param, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
*p = c;
return (savestring (p));
}
*p = c;
free (wparam);
free (wpattern);
if (MB_CUR_MAX > 1)
{
ADVANCE_CHAR (param, len, offset);
p = param + offset;
}
else
p++;
}
break;
case RP_LONG_RIGHT: /* remove longest match at end */
p = param;
offset = 0;
while (p <= end)
{
if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
c = *p; *p = '\0';
ret = savestring (param);
*p = c;
return (ret);
}
if (MB_CUR_MAX > 1)
{
ADVANCE_CHAR (param, len, offset);
p = param + offset;
}
else
p++;
}
break;
case RP_SHORT_RIGHT: /* remove shortest match at end */
p = end;
while (p >= param)
{
if (strmatch (pattern, p, FNMATCH_EXTFLAG) != FNM_NOMATCH)
{
c = *p; *p = '\0';
ret = savestring (param);
*p = c;
FREE (mblen);
return (ret);
}
if (MB_CUR_MAX > 1)
{
while (p >= param)
if (mblen[--p - param])
break;
}
else
p--;
}
break;
n = strlen (param);
xret = xmalloc (n + 1);
memset (&ps, '\0', sizeof (mbstate_t));
n = wcsrtombs (xret, (const wchar_t **)&ret, n, &ps);
xret[n] = '\0'; /* just to make sure */
free (oret);
return xret;
}
FREE (mblen);
return (savestring (param)); /* no match, return original string */
else
#endif
return (remove_upattern (param, pattern, op));
}
/* Return 1 of the first character of STRING could match the first
@@ -3041,7 +3138,7 @@ match_pattern_char (pat, string)
MATCH_BEG and MATCH_END anchor the match at the beginning and end
of the string, respectively. The longest match is returned. */
static int
match_pattern (string, pat, mtype, sp, ep)
match_upattern (string, pat, mtype, sp, ep)
char *string, *pat;
int mtype;
char **sp, **ep;
@@ -3049,33 +3146,18 @@ match_pattern (string, pat, mtype, sp, ep)
int c, len;
register char *p, *p1;
char *end;
int offset;
unsigned char *mblen;
DECLARE_MBSTATE;
if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
return (0);
len = STRLEN (string);
end = string + len;
mblen = (unsigned char *)0;
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1 && (mtype == MATCH_ANY || mtype == MATCH_BEG))
mblen = mb_getcharlens (string, len);
#endif
switch (mtype)
{
case MATCH_ANY:
p = string;
offset = 0;
while (p <= end)
for (p = string; p <= end; p++)
{
if (match_pattern_char (pat, p))
{
p1 = end;
while (p1 >= p)
for (p1 = end; p1 >= p; p1--)
{
c = *p1; *p1 = '\0';
if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
@@ -3083,40 +3165,20 @@ match_pattern (string, pat, mtype, sp, ep)
*p1 = c;
*sp = p;
*ep = p1;
FREE (mblen);
return 1;
}
*p1 = c;
if (MB_CUR_MAX > 1)
{
while (p1 >= p)
if (mblen[--p1 - string])
break;
}
else
p1--;
}
}
if (MB_CUR_MAX > 1)
{
ADVANCE_CHAR (string, len, offset);
p = string + offset;
}
else
p++;
}
FREE (mblen);
return (0);
case MATCH_BEG:
if (match_pattern_char (pat, string) == 0)
return (0);
p = end;
while (p >= string)
for (p = end; p >= string; p--)
{
c = *p; *p = '\0';
if (strmatch (pat, string, FNMATCH_EXTFLAG) == 0)
@@ -3124,28 +3186,15 @@ match_pattern (string, pat, mtype, sp, ep)
*p = c;
*sp = string;
*ep = p;
FREE (mblen);
return 1;
}
*p = c;
if (MB_CUR_MAX > 1)
{
while (p >= string)
if (mblen[--p - string])
break;
}
else
p--;
}
FREE (mblen);
return (0);
case MATCH_END:
p = string;
offset = 0;
while (p <= end)
for (p = string; p <= end; p++)
{
if (strmatch (pat, p, FNMATCH_EXTFLAG) == 0)
{
@@ -3154,21 +3203,167 @@ match_pattern (string, pat, mtype, sp, ep)
return 1;
}
if (MB_CUR_MAX > 1)
{
ADVANCE_CHAR (string, len, offset);
p = string + offset;
}
else
p++;
}
return (0);
}
FREE (mblen);
return (0);
}
#if defined (HANDLE_MULTIBYTE)
/* Return 1 of the first character of WSTRING could match the first
character of pattern WPAT. Wide character version. */
static 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 == LPAREN ? 1 : (*wstring != L'\0'));
case L'*':
return (1);
case L'+':
case L'!':
case L'@':
return (*wpat == LPAREN ? 1 : (*wstring == wc));
case L'[':
return (*wstring != L'\0');
}
}
/* Match WPAT anywhere in WSTRING and return the match boundaries.
This returns 1 in case of a successful match, 0 otherwise. Wide
character version. */
static int
match_wpattern (wstring, indices, wstrlen, wpat, mtype, sp, ep)
wchar_t *wstring;
char **indices;
size_t wstrlen;
wchar_t *wpat;
int mtype;
char **sp, **ep;
{
wchar_t wc;
int len;
#if 0
size_t n, n1; /* Apple's gcc seems to miscompile this badly */
#else
int n, n1;
#endif
switch (mtype)
{
case MATCH_ANY:
for (n = 0; n <= wstrlen; n++)
{
if (match_pattern_wchar (wpat, wstring + n))
{
for (n1 = wstrlen; n1 >= n; n1--)
{
wc = wstring[n1]; wstring[n1] = L'\0';
if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
{
wstring[n1] = wc;
*sp = indices[n];
*ep = indices[n1];
return 1;
}
wstring[n1] = wc;
}
}
}
return (0);
case MATCH_BEG:
if (match_pattern_wchar (wpat, wstring) == 0)
return (0);
for (n = wstrlen; n >= 0; n--)
{
wc = wstring[n]; wstring[n] = L'\0';
if (wcsmatch (wpat, wstring, FNMATCH_EXTFLAG) == 0)
{
wstring[n] = wc;
*sp = indices[0];
*ep = indices[n];
return 1;
}
wstring[n] = wc;
}
return (0);
case MATCH_END:
for (n = 0; n <= wstrlen; n++)
{
if (wcsmatch (wpat, wstring + n, FNMATCH_EXTFLAG) == 0)
{
*sp = indices[n];
*ep = indices[wstrlen];
return 1;
}
}
return (0);
}
return (0);
}
#endif /* HANDLE_MULTIBYTE */
static int
match_pattern (string, pat, mtype, sp, ep)
char *string, *pat;
int mtype;
char **sp, **ep;
{
#if defined (HANDLE_MULTIBYTE)
int ret;
size_t n;
wchar_t *wstring, *wpat;
char **indices;
#endif
if (string == 0 || *string == 0 || pat == 0 || *pat == 0)
return (0);
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1)
{
n = xdupmbstowcs (&wpat, NULL, pat);
if (n == (size_t)-1)
return (match_upattern (string, pat, mtype, sp, ep));
n = xdupmbstowcs (&wstring, &indices, string);
if (n == (size_t)-1)
{
free (wpat);
return (match_upattern (string, pat, mtype, sp, ep));
}
ret = match_wpattern (wstring, indices, n, wpat, mtype, sp, ep);
free (wpat);
free (wstring);
free (indices);
return (ret);
}
else
#endif
return (match_upattern (string, pat, mtype, sp, ep));
}
static int
getpatspec (c, value)
int c;
@@ -4850,8 +5045,8 @@ parameter_brace_substring (varname, value, substr, quoted)
#if defined (ARRAY_VARS)
case VT_ARRAYVAR:
/* We want E2 to be the number of elements desired (arrays can be sparse,
so verify_substring_values just returns the numbers specified and we
rely on array_subrange to understand how to deal with them). */
so verify_substring_values just returns the numbers specified and we
rely on array_subrange to understand how to deal with them). */
tt = array_subrange (array_cell (v), e1, e2, starsub, quoted);
if ((quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) == 0)
{
@@ -5632,10 +5827,13 @@ param_expand (string, sindex, quoted, expanded_something,
string might need it (consider "\"$@\""), but we need some
way to signal that the final split on the first character
of $IFS should be done, even though QUOTED is 1. */
if (list && list->next)
{
if (quoted_dollar_at_p && (quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)))
*quoted_dollar_at_p = 1;
if (contains_dollar_at)
*contains_dollar_at = 1;
}
/* We want to separate the positional parameters with the first
character of $IFS in case $IFS is something other than a space.
@@ -5779,6 +5977,8 @@ comsub:
temp = array_reference (array_cell (var), 0);
if (temp)
temp = quote_escapes (temp);
else if (unbound_vars_is_error)
goto unbound_variable;
}
else
#endif
@@ -5790,6 +5990,7 @@ comsub:
temp = (char *)NULL;
unbound_variable:
if (unbound_vars_is_error)
err_unboundvar (temp1);
else