Imported from ../bash-2.05b.tar.gz.
This commit is contained in:
parent
f73dda092b
commit
7117c2d221
362 changed files with 34387 additions and 15063 deletions
|
|
@ -39,6 +39,8 @@ MV = mv
|
|||
|
||||
SHELL = @MAKE_SHELL@
|
||||
|
||||
PROFILE_FLAGS = @PROFILE_FLAGS@
|
||||
|
||||
CFLAGS = @CFLAGS@
|
||||
LOCAL_CFLAGS = @LOCAL_CFLAGS@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
|
|
@ -51,7 +53,8 @@ BASHINCDIR = ${topdir}/include
|
|||
|
||||
INCLUDES = -I. -I../.. -I$(topdir) -I$(BASHINCDIR) -I$(topdir)/lib
|
||||
|
||||
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(CPPFLAGS) ${INCLUDES} $(LOCAL_CFLAGS) $(CFLAGS)
|
||||
CCFLAGS = $(PROFILE_FLAGS) $(DEFS) $(LOCAL_DEFS) $(CPPFLAGS) ${INCLUDES} \
|
||||
$(LOCAL_CFLAGS) $(CFLAGS)
|
||||
|
||||
# Here is a rule for making .o files from .c files that doesn't force
|
||||
# the type of the machine (like -sun3) into the flags.
|
||||
|
|
@ -62,12 +65,13 @@ CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(CPPFLAGS) ${INCLUDES} $(LOCAL_CFLAGS) $(CFLAGS
|
|||
LIBRARY_NAME = libglob.a
|
||||
|
||||
# The C code source files for this library.
|
||||
CSOURCES = $(srcdir)/glob.c $(srcdir)/strmatch.c
|
||||
CSOURCES = $(srcdir)/glob.c $(srcdir)/strmatch.c $(srcdir)/smatch.c \
|
||||
$(srcdir)/xmbsrtowcs.c
|
||||
|
||||
# The header files for this library.
|
||||
HSOURCES = $(srcdir)/strmatch.h
|
||||
|
||||
OBJECTS = glob.o strmatch.o
|
||||
OBJECTS = glob.o strmatch.o smatch.o xmbsrtowcs.o
|
||||
|
||||
# The texinfo files which document this library.
|
||||
DOCSOURCE = doc/glob.texi
|
||||
|
|
@ -121,15 +125,34 @@ mostlyclean: clean
|
|||
# #
|
||||
######################################################################
|
||||
|
||||
smatch.o: strmatch.h
|
||||
smatch.o: $(BUILD_DIR)/config.h
|
||||
smatch.o: $(BASHINCDIR)/chartypes.h
|
||||
smatch.o: $(BASHINCDIR)/ansi_stdlib.h $(topdir)/bashansi.h
|
||||
smatch.o: $(BASHINCDIR)/shmbutil.h
|
||||
smatch.o: $(topdir)/xmalloc.h
|
||||
|
||||
strmatch.o: strmatch.h
|
||||
strmatch.o: $(BUILD_DIR)/config.h
|
||||
strmatch.o: $(BASHINCDIR)/chartypes.h
|
||||
strmatch.o: $(BASHINCDIR)/stdc.h
|
||||
|
||||
glob.o: $(BUILD_DIR)/config.h
|
||||
glob.o: $(topdir)/bashtypes.h $(BASHINCDIR)/ansi_stdlib.h $(topdir)/bashansi.h
|
||||
glob.o: $(BASHINCDIR)/posixstat.h $(BASHINCDIR)/memalloc.h
|
||||
glob.o: strmatch.h
|
||||
glob.o: strmatch.h glob.h
|
||||
glob.o: $(BASHINCDIR)/shmbutil.h
|
||||
glob.o: $(topdir)/xmalloc.h
|
||||
|
||||
xmbsrtowcs.o: ${BUILD_DIR}/config.h
|
||||
xmbsrtowcs.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
xmbsrtowcs.o: ${BASHINCDIR}/shmbutil.h
|
||||
|
||||
# Rules for deficient makes, like SunOS and Solaris
|
||||
strmatch.o: strmatch.c
|
||||
glob.o: glob.c
|
||||
strmatch.o: strmatch.c
|
||||
smatch.o: smatch.c
|
||||
xmbsrtowcs.o: xmbsrtowcs.c
|
||||
|
||||
# dependencies for C files that include other C files
|
||||
glob.o: glob_loop.c
|
||||
smatch.o: sm_loop.c
|
||||
|
|
|
|||
|
|
@ -1,141 +1,140 @@
|
|||
/* collsyms.h -- collating symbol names and their corresponding characters
|
||||
(in ascii) as given by POSIX.2 in table 2.8. */
|
||||
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1997-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#ifndef _COLLSYMS_H_
|
||||
# define _COLLSYSMS_H_
|
||||
|
||||
/* The upper-case letters, lower-case letters, and digits are omitted from
|
||||
this table. The digits are not included in the table in the POSIX.2
|
||||
spec. The upper and lower case letters are translated by the code
|
||||
in fnmatch.c:collsym(). */
|
||||
in smatch.c:collsym(). */
|
||||
|
||||
typedef struct _collsym {
|
||||
char *name;
|
||||
char code;
|
||||
} COLLSYM;
|
||||
typedef struct _COLLSYM {
|
||||
XCHAR *name;
|
||||
CHAR code;
|
||||
} __COLLSYM;
|
||||
|
||||
static COLLSYM posix_collsyms[] =
|
||||
static __COLLSYM POSIXCOLL [] =
|
||||
{
|
||||
{ "NUL", '\0' },
|
||||
{ "SOH", '\001' },
|
||||
{ "STX", '\002' },
|
||||
{ "ETX", '\003' },
|
||||
{ "EOT", '\004' },
|
||||
{ "ENQ", '\005' },
|
||||
{ "ACK", '\006' },
|
||||
{ L("NUL"), L('\0') },
|
||||
{ L("SOH"), L('\001') },
|
||||
{ L("STX"), L('\002') },
|
||||
{ L("ETX"), L('\003') },
|
||||
{ L("EOT"), L('\004') },
|
||||
{ L("ENQ"), L('\005') },
|
||||
{ L("ACK"), L('\006') },
|
||||
#ifdef __STDC__
|
||||
{ "alert", '\a' },
|
||||
{ L("alert"), L('\a') },
|
||||
#else
|
||||
{ "alert", '\007' },
|
||||
{ L("alert"), L('\007') },
|
||||
#endif
|
||||
{ "BS", '\010' },
|
||||
{ "backspace", '\b' },
|
||||
{ "HT", '\011' },
|
||||
{ "tab", '\t' },
|
||||
{ "LF", '\012' },
|
||||
{ "newline", '\n' },
|
||||
{ "VT", '\013' },
|
||||
{ "vertical-tab", '\v' },
|
||||
{ "FF", '\014' },
|
||||
{ "form-feed", '\f' },
|
||||
{ "CR", '\015' },
|
||||
{ "carriage-return", '\r' },
|
||||
{ "SO", '\016' },
|
||||
{ "SI", '\017' },
|
||||
{ "DLE", '\020' },
|
||||
{ "DC1", '\021' },
|
||||
{ "DC2", '\022' },
|
||||
{ "DC3", '\023' },
|
||||
{ "DC4", '\024' },
|
||||
{ "NAK", '\025' },
|
||||
{ "SYN", '\026' },
|
||||
{ "ETB", '\027' },
|
||||
{ "CAN", '\030' },
|
||||
{ "EM", '\031' },
|
||||
{ "SUB", '\032' },
|
||||
{ "ESC", '\033' },
|
||||
{ "IS4", '\034' },
|
||||
{ "FS", '\034' },
|
||||
{ "IS3", '\035' },
|
||||
{ "GS", '\035' },
|
||||
{ "IS2", '\036' },
|
||||
{ "RS", '\036' },
|
||||
{ "IS1", '\037' },
|
||||
{ "US", '\037' },
|
||||
{ "space", ' ' },
|
||||
{ "exclamation-mark", '!' },
|
||||
{ "quotation-mark", '"' },
|
||||
{ "number-sign", '#' },
|
||||
{ "dollar-sign", '$' },
|
||||
{ "percent-sign", '%' },
|
||||
{ "ampersand", '&' },
|
||||
{ "apostrophe", '\'' },
|
||||
{ "left-parenthesis", '(' },
|
||||
{ "right-parenthesis", ')' },
|
||||
{ "asterisk", '*' },
|
||||
{ "plus-sign", '+' },
|
||||
{ "comma", ',' },
|
||||
{ "hyphen", '-' },
|
||||
{ "hyphen-minus", '-' },
|
||||
{ "minus", '-' }, /* extension from POSIX.2 */
|
||||
{ "dash", '-' }, /* extension from POSIX.2 */
|
||||
{ "period", '.' },
|
||||
{ "full-stop", '.' },
|
||||
{ "slash", '/' },
|
||||
{ "solidus", '/' }, /* extension from POSIX.2 */
|
||||
{ "zero", '0' },
|
||||
{ "one", '1' },
|
||||
{ "two", '2' },
|
||||
{ "three", '3' },
|
||||
{ "four", '4' },
|
||||
{ "five", '5' },
|
||||
{ "six", '6' },
|
||||
{ "seven", '7' },
|
||||
{ "eight", '8' },
|
||||
{ "nine", '9' },
|
||||
{ "colon", ':' },
|
||||
{ "semicolon", ';' },
|
||||
{ "less-than-sign", '<' },
|
||||
{ "equals-sign", '=' },
|
||||
{ "greater-than-sign", '>' },
|
||||
{ "question-mark", '?' },
|
||||
{ "commercial-at", '@' },
|
||||
{ L("BS"), L('\010') },
|
||||
{ L("backspace"), L('\b') },
|
||||
{ L("HT"), L('\011') },
|
||||
{ L("tab"), L('\t') },
|
||||
{ L("LF"), L('\012') },
|
||||
{ L("newline"), L('\n') },
|
||||
{ L("VT"), L('\013') },
|
||||
{ L("vertical-tab"), L('\v') },
|
||||
{ L("FF"), L('\014') },
|
||||
{ L("form-feed"), L('\f') },
|
||||
{ L("CR"), L('\015') },
|
||||
{ L("carriage-return"), L('\r') },
|
||||
{ L("SO"), L('\016') },
|
||||
{ L("SI"), L('\017') },
|
||||
{ L("DLE"), L('\020') },
|
||||
{ L("DC1"), L('\021') },
|
||||
{ L("DC2"), L('\022') },
|
||||
{ L("DC3"), L('\023') },
|
||||
{ L("DC4"), L('\024') },
|
||||
{ L("NAK"), L('\025') },
|
||||
{ L("SYN"), L('\026') },
|
||||
{ L("ETB"), L('\027') },
|
||||
{ L("CAN"), L('\030') },
|
||||
{ L("EM"), L('\031') },
|
||||
{ L("SUB"), L('\032') },
|
||||
{ L("ESC"), L('\033') },
|
||||
{ L("IS4"), L('\034') },
|
||||
{ L("FS"), L('\034') },
|
||||
{ L("IS3"), L('\035') },
|
||||
{ L("GS"), L('\035') },
|
||||
{ L("IS2"), L('\036') },
|
||||
{ L("RS"), L('\036') },
|
||||
{ L("IS1"), L('\037') },
|
||||
{ L("US"), L('\037') },
|
||||
{ L("space"), L(' ') },
|
||||
{ L("exclamation-mark"), L('!') },
|
||||
{ L("quotation-mark"), L('"') },
|
||||
{ L("number-sign"), L('#') },
|
||||
{ L("dollar-sign"), L('$') },
|
||||
{ L("percent-sign"), L('%') },
|
||||
{ L("ampersand"), L('&') },
|
||||
{ L("apostrophe"), L('\'') },
|
||||
{ L("left-parenthesis"), L('(') },
|
||||
{ L("right-parenthesis"), L(')') },
|
||||
{ L("asterisk"), L('*') },
|
||||
{ L("plus-sign"), L('+') },
|
||||
{ L("comma"), L(',') },
|
||||
{ L("hyphen"), L('-') },
|
||||
{ L("hyphen-minus"), L('-') },
|
||||
{ L("minus"), L('-') }, /* extension from POSIX.2 */
|
||||
{ L("dash"), L('-') }, /* extension from POSIX.2 */
|
||||
{ L("period"), L('.') },
|
||||
{ L("full-stop"), L('.') },
|
||||
{ L("slash"), L('/') },
|
||||
{ L("solidus"), L('/') }, /* extension from POSIX.2 */
|
||||
{ L("zero"), L('0') },
|
||||
{ L("one"), L('1') },
|
||||
{ L("two"), L('2') },
|
||||
{ L("three"), L('3') },
|
||||
{ L("four"), L('4') },
|
||||
{ L("five"), L('5') },
|
||||
{ L("six"), L('6') },
|
||||
{ L("seven"), L('7') },
|
||||
{ L("eight"), L('8') },
|
||||
{ L("nine"), L('9') },
|
||||
{ L("colon"), L(':') },
|
||||
{ L("semicolon"), L(';') },
|
||||
{ L("less-than-sign"), L('<') },
|
||||
{ L("equals-sign"), L('=') },
|
||||
{ L("greater-than-sign"), L('>') },
|
||||
{ L("question-mark"), L('?') },
|
||||
{ L("commercial-at"), L('@') },
|
||||
/* upper-case letters omitted */
|
||||
{ "left-square-bracket",'[' },
|
||||
{ "backslash", '\\' },
|
||||
{ "reverse-solidus", '\\' },
|
||||
{ "right-square-bracket",']' },
|
||||
{ "circumflex", '^' },
|
||||
{ "circumflex-accent", '^' }, /* extension from POSIX.2 */
|
||||
{ "underscore", '_' },
|
||||
{ "grave-accent", '`' },
|
||||
{ L("left-square-bracket"), L('[') },
|
||||
{ L("backslash"), L('\\') },
|
||||
{ L("reverse-solidus"), L('\\') },
|
||||
{ L("right-square-bracket"), L(']') },
|
||||
{ L("circumflex"), L('^') },
|
||||
{ L("circumflex-accent"), L('^') }, /* extension from POSIX.2 */
|
||||
{ L("underscore"), L('_') },
|
||||
{ L("grave-accent"), L('`') },
|
||||
/* lower-case letters omitted */
|
||||
{ "left-brace", '{' }, /* extension from POSIX.2 */
|
||||
{ "left-curly-bracket",'{' },
|
||||
{ "vertical-line", '|' },
|
||||
{ "right-brace", '}' }, /* extension from POSIX.2 */
|
||||
{ "right-curly-bracket",'}' },
|
||||
{ "tilde", '~' },
|
||||
{ "DEL", '\177' },
|
||||
{ L("left-brace"), L('{') }, /* extension from POSIX.2 */
|
||||
{ L("left-curly-bracket"), L('{') },
|
||||
{ L("vertical-line"), L('|') },
|
||||
{ L("right-brace"), L('}') }, /* extension from POSIX.2 */
|
||||
{ L("right-curly-bracket"), L('}') },
|
||||
{ L("tilde"), L('~') },
|
||||
{ L("DEL"), L('\177') },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
#endif
|
||||
#undef _COLLSYM
|
||||
#undef __COLLSYM
|
||||
#undef POSIXCOLL
|
||||
|
|
|
|||
433
lib/glob/glob.c
433
lib/glob/glob.c
|
|
@ -1,5 +1,6 @@
|
|||
/* File-name wildcard pattern matching for GNU.
|
||||
Copyright (C) 1985, 1988, 1989 Free Software Foundation, Inc.
|
||||
/* glob.c -- file-name wildcard pattern matching for Bash.
|
||||
|
||||
Copyright (C) 1985-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
|
||||
|
|
@ -25,81 +26,33 @@
|
|||
#pragma alloca
|
||||
#endif /* _AIX && RISC6000 && !__GNUC__ */
|
||||
|
||||
#if defined (SHELL)
|
||||
# include "bashtypes.h"
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (SHELL)
|
||||
# include "bashansi.h"
|
||||
#else
|
||||
# if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
# if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
# else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
# endif /* !HAVE_STRING_H */
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_DIRENT_H)
|
||||
# include <dirent.h>
|
||||
# define D_NAMLEN(d) strlen ((d)->d_name)
|
||||
#else /* !HAVE_DIRENT_H */
|
||||
# define D_NAMLEN(d) ((d)->d_namlen)
|
||||
# if defined (HAVE_SYS_NDIR_H)
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# if defined (HAVE_SYS_DIR_H)
|
||||
# include <sys/dir.h>
|
||||
# endif /* HAVE_SYS_DIR_H */
|
||||
# if defined (HAVE_NDIR_H)
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
# if !defined (dirent)
|
||||
# define dirent direct
|
||||
# endif
|
||||
#endif /* !HAVE_DIRENT_H */
|
||||
|
||||
#if defined (_POSIX_SOURCE) && !defined (STRUCT_DIRENT_HAS_D_INO) || defined (BROKEN_DIRENT_D_INO)
|
||||
/* Posix does not require that the d_ino field be present, and some
|
||||
systems do not provide it. */
|
||||
# define REAL_DIR_ENTRY(dp) 1
|
||||
#else
|
||||
# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
|
||||
#endif /* _POSIX_SOURCE */
|
||||
|
||||
#if !defined (HAVE_BCOPY) && !defined (bcopy)
|
||||
# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n)))
|
||||
#endif /* !HAVE_BCOPY && !bcopy */
|
||||
|
||||
#if defined (SHELL)
|
||||
# include "posixstat.h"
|
||||
#else /* !SHELL */
|
||||
# include <sys/stat.h>
|
||||
#endif /* !SHELL */
|
||||
#include "bashansi.h"
|
||||
#include "posixdir.h"
|
||||
#include "posixstat.h"
|
||||
#include "shmbutil.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#include "filecntl.h"
|
||||
#if !defined (F_OK)
|
||||
# define F_OK 0
|
||||
#endif
|
||||
|
||||
#if defined (SHELL)
|
||||
# include "memalloc.h"
|
||||
#endif
|
||||
#include "stdc.h"
|
||||
#include "memalloc.h"
|
||||
#include "quit.h"
|
||||
|
||||
#include "glob.h"
|
||||
#include "strmatch.h"
|
||||
|
||||
#if !defined (HAVE_STDLIB_H) && !defined (SHELL)
|
||||
extern char *malloc (), *realloc ();
|
||||
extern void free ();
|
||||
#endif /* !HAVE_STDLIB_H */
|
||||
#if !defined (HAVE_BCOPY) && !defined (bcopy)
|
||||
# define bcopy(s, d, n) ((void) memcpy ((d), (s), (n)))
|
||||
#endif /* !HAVE_BCOPY && !bcopy */
|
||||
|
||||
#if !defined (NULL)
|
||||
# if defined (__STDC__)
|
||||
|
|
@ -109,13 +62,10 @@ extern void free ();
|
|||
# endif /* __STDC__ */
|
||||
#endif /* !NULL */
|
||||
|
||||
#if defined (SHELL)
|
||||
extern void throw_to_top_level ();
|
||||
extern int test_eaccess ();
|
||||
extern void throw_to_top_level __P((void));
|
||||
extern int test_eaccess __P((char *, int));
|
||||
|
||||
extern int interrupt_state;
|
||||
extern int extended_glob;
|
||||
#endif /* SHELL */
|
||||
|
||||
/* Global variable which controls whether or not * matches .*.
|
||||
Non-zero means don't match .*. */
|
||||
|
|
@ -128,51 +78,152 @@ int glob_ignore_case = 0;
|
|||
/* Global variable to return to signify an error in globbing. */
|
||||
char *glob_error_return;
|
||||
|
||||
/* Return nonzero if PATTERN has any special globbing chars in it. */
|
||||
/* Some forward declarations. */
|
||||
static int skipname __P((char *, char *));
|
||||
#if HANDLE_MULTIBYTE
|
||||
static int mbskipname __P((char *, char *));
|
||||
#endif
|
||||
#if HANDLE_MULTIBYTE
|
||||
static void udequote_pathname __P((char *));
|
||||
static void wdequote_pathname __P((char *));
|
||||
#else
|
||||
# define dequote_pathname udequote_pathname
|
||||
#endif
|
||||
static void dequote_pathname __P((char *));
|
||||
static int glob_testdir __P((char *));
|
||||
static char **glob_dir_to_array __P((char *, char **, int));
|
||||
|
||||
/* Compile `glob_loop.c' for single-byte characters. */
|
||||
#define CHAR unsigned char
|
||||
#define INT int
|
||||
#define L(CS) CS
|
||||
#define INTERNAL_GLOB_PATTERN_P internal_glob_pattern_p
|
||||
#include "glob_loop.c"
|
||||
|
||||
/* Compile `glob_loop.c' again for multibyte characters. */
|
||||
#if HANDLE_MULTIBYTE
|
||||
|
||||
#define CHAR wchar_t
|
||||
#define INT wint_t
|
||||
#define L(CS) L##CS
|
||||
#define INTERNAL_GLOB_PATTERN_P internal_glob_wpattern_p
|
||||
#include "glob_loop.c"
|
||||
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
||||
/* And now a function that calls either the single-byte or multibyte version
|
||||
of internal_glob_pattern_p. */
|
||||
int
|
||||
glob_pattern_p (pattern)
|
||||
const char *pattern;
|
||||
{
|
||||
register const char *p;
|
||||
register char c;
|
||||
int bopen;
|
||||
#if HANDLE_MULTIBYTE
|
||||
mbstate_t ps;
|
||||
size_t n;
|
||||
wchar_t *wpattern;
|
||||
int r;
|
||||
|
||||
p = pattern;
|
||||
bopen = 0;
|
||||
if (MB_CUR_MAX == 1)
|
||||
return (internal_glob_pattern_p (pattern));
|
||||
|
||||
while ((c = *p++) != '\0')
|
||||
switch (c)
|
||||
{
|
||||
case '?':
|
||||
case '*':
|
||||
return (1);
|
||||
|
||||
case '[': /* Only accept an open brace if there is a close */
|
||||
bopen++; /* brace to match it. Bracket expressions must be */
|
||||
continue; /* complete, according to Posix.2 */
|
||||
case ']':
|
||||
if (bopen)
|
||||
return (1);
|
||||
continue;
|
||||
|
||||
case '+': /* extended matching operators */
|
||||
case '@':
|
||||
case '!':
|
||||
if (*p == '(') /*) */
|
||||
return (1);
|
||||
continue;
|
||||
|
||||
case '\\':
|
||||
if (*p++ == '\0')
|
||||
return (0);
|
||||
}
|
||||
|
||||
return (0);
|
||||
/* Convert strings to wide chars, and call the multibyte version. */
|
||||
memset (&ps, '\0', sizeof (ps));
|
||||
n = xmbsrtowcs (NULL, (const char **)&pattern, 0, &ps);
|
||||
if (n == (size_t)-1)
|
||||
/* Oops. Invalid multibyte sequence. Try it as single-byte sequence. */
|
||||
return (internal_glob_pattern_p (pattern));
|
||||
wpattern = (wchar_t *)xmalloc ((n + 1) * sizeof (wchar_t));
|
||||
(void) xmbsrtowcs (wpattern, (const char **)&pattern, n + 1, &ps);
|
||||
r = internal_glob_wpattern_p (wpattern);
|
||||
free (wpattern);
|
||||
return r;
|
||||
#else
|
||||
return (internal_glob_pattern_p (pattern));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return 1 if DNAME should be skipped according to PAT. Mostly concerned
|
||||
with matching leading `.'. */
|
||||
|
||||
static int
|
||||
skipname (pat, dname)
|
||||
char *pat;
|
||||
char *dname;
|
||||
{
|
||||
/* If a leading dot need not be explicitly matched, and the pattern
|
||||
doesn't start with a `.', don't match `.' or `..' */
|
||||
if (noglob_dot_filenames == 0 && pat[0] != '.' &&
|
||||
(pat[0] != '\\' || pat[1] != '.') &&
|
||||
(dname[0] == '.' &&
|
||||
(dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0'))))
|
||||
return 1;
|
||||
|
||||
/* If a dot must be explicity matched, check to see if they do. */
|
||||
else if (noglob_dot_filenames && dname[0] == '.' && pat[0] != '.' &&
|
||||
(pat[0] != '\\' || pat[1] != '.'))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HANDLE_MULTIBYTE
|
||||
/* Return 1 if DNAME should be skipped according to PAT. Handles multibyte
|
||||
characters in PAT and DNAME. Mostly concerned with matching leading `.'. */
|
||||
|
||||
static int
|
||||
mbskipname (pat, dname)
|
||||
char *pat, *dname;
|
||||
{
|
||||
char *pat_bak, *dn_bak;
|
||||
wchar_t *pat_wc, *dn_wc;
|
||||
mbstate_t pat_ps, dn_ps;
|
||||
size_t pat_n, dn_n, n;
|
||||
|
||||
n = strlen(pat);
|
||||
pat_bak = (char *) alloca (n + 1);
|
||||
memcpy (pat_bak, pat, n + 1);
|
||||
|
||||
n = strlen(dname);
|
||||
dn_bak = (char *) alloca (n + 1);
|
||||
memcpy (dn_bak, dname, n + 1);
|
||||
|
||||
memset(&pat_ps, '\0', sizeof(mbstate_t));
|
||||
memset(&dn_ps, '\0', sizeof(mbstate_t));
|
||||
|
||||
pat_n = xmbsrtowcs (NULL, (const char **)&pat_bak, 0, &pat_ps);
|
||||
dn_n = xmbsrtowcs (NULL, (const char **)&dn_bak, 0, &dn_ps);
|
||||
|
||||
if (pat_n != (size_t)-1 && dn_n !=(size_t)-1)
|
||||
{
|
||||
pat_wc = (wchar_t *) alloca ((pat_n + 1) * sizeof(wchar_t));
|
||||
dn_wc = (wchar_t *) alloca ((dn_n + 1) * sizeof(wchar_t));
|
||||
|
||||
(void) xmbsrtowcs (pat_wc, (const char **)&pat_bak, pat_n + 1, &pat_ps);
|
||||
(void) xmbsrtowcs (dn_wc, (const char **)&dn_bak, dn_n + 1, &dn_ps);
|
||||
|
||||
/* If a leading dot need not be explicitly matched, and the
|
||||
pattern doesn't start with a `.', don't match `.' or `..' */
|
||||
if (noglob_dot_filenames == 0 && pat_wc[0] != L'.' &&
|
||||
(pat_wc[0] != L'\\' || pat_wc[1] != L'.') &&
|
||||
(dn_wc[0] == L'.' &&
|
||||
(dn_wc[1] == L'\0' || (dn_wc[1] == L'.' && dn_wc[2] == L'\0'))))
|
||||
return 1;
|
||||
|
||||
/* If a leading dot must be explicity matched, check to see if the
|
||||
pattern and dirname both have one. */
|
||||
else if (noglob_dot_filenames && dn_wc[0] == L'.' &&
|
||||
pat_wc[0] != L'.' &&
|
||||
(pat_wc[0] != L'\\' || pat_wc[1] != L'.'))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
||||
/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */
|
||||
static void
|
||||
dequote_pathname (pathname)
|
||||
udequote_pathname (pathname)
|
||||
char *pathname;
|
||||
{
|
||||
register int i, j;
|
||||
|
|
@ -190,18 +241,71 @@ dequote_pathname (pathname)
|
|||
pathname[j] = '\0';
|
||||
}
|
||||
|
||||
|
||||
#if HANDLE_MULTIBYTE
|
||||
/* Remove backslashes quoting characters in PATHNAME by modifying PATHNAME. */
|
||||
static void
|
||||
wdequote_pathname (pathname)
|
||||
char *pathname;
|
||||
{
|
||||
mbstate_t ps;
|
||||
size_t len, n;
|
||||
wchar_t *wpathname;
|
||||
char *pathname_bak;
|
||||
int i, j;
|
||||
|
||||
len = strlen (pathname);
|
||||
pathname_bak = (char *) alloca (len + 1);
|
||||
memcpy (pathname_bak, pathname , len + 1);
|
||||
|
||||
/* Convert the strings into wide characters. */
|
||||
memset (&ps, '\0', sizeof (ps));
|
||||
n = xmbsrtowcs (NULL, (const char **)&pathname_bak, 0, &ps);
|
||||
if (n == (size_t) -1)
|
||||
/* Something wrong. */
|
||||
return;
|
||||
|
||||
wpathname = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
|
||||
(void) xmbsrtowcs (wpathname, (const char **)&pathname_bak, n + 1, &ps);
|
||||
|
||||
for (i = j = 0; wpathname && wpathname[i]; )
|
||||
{
|
||||
if (wpathname[i] == L'\\')
|
||||
i++;
|
||||
|
||||
wpathname[j++] = wpathname[i++];
|
||||
|
||||
if (!wpathname[i - 1])
|
||||
break;
|
||||
}
|
||||
wpathname[j] = L'\0';
|
||||
|
||||
/* Convert the wide character string into unibyte character set. */
|
||||
memset (&ps, '\0', sizeof(mbstate_t));
|
||||
n = wcsrtombs(pathname, (const wchar_t **)&wpathname, len, &ps);
|
||||
pathname[len] = '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
dequote_pathname (pathname)
|
||||
char *pathname;
|
||||
{
|
||||
if (MB_CUR_MAX > 1)
|
||||
wdequote_pathname (pathname);
|
||||
else
|
||||
udequote_pathname (pathname);
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
||||
/* Test whether NAME exists. */
|
||||
|
||||
#if defined (HAVE_LSTAT)
|
||||
# define GLOB_TESTNAME(name) (lstat (name, &finfo))
|
||||
#else /* !HAVE_LSTAT */
|
||||
# if defined (SHELL) && !defined (AFS)
|
||||
# if !defined (AFS)
|
||||
# define GLOB_TESTNAME(name) (test_eaccess (nextname, F_OK))
|
||||
# else /* !SHELL || AFS */
|
||||
# else /* AFS */
|
||||
# define GLOB_TESTNAME(name) (access (nextname, F_OK))
|
||||
# endif /* !SHELL || AFS */
|
||||
# endif /* AFS */
|
||||
#endif /* !HAVE_LSTAT */
|
||||
|
||||
/* Return 0 if DIR is a directory, -1 otherwise. */
|
||||
|
|
@ -237,9 +341,10 @@ glob_testdir (dir)
|
|||
Look in errno for more information. */
|
||||
|
||||
char **
|
||||
glob_vector (pat, dir)
|
||||
glob_vector (pat, dir, flags)
|
||||
char *pat;
|
||||
char *dir;
|
||||
int flags;
|
||||
{
|
||||
struct globval
|
||||
{
|
||||
|
|
@ -256,7 +361,7 @@ glob_vector (pat, dir)
|
|||
int lose, skip;
|
||||
register char **name_vector;
|
||||
register unsigned int i;
|
||||
int flags; /* Flags passed to strmatch (). */
|
||||
int mflags; /* Flags passed to strmatch (). */
|
||||
|
||||
lastlink = 0;
|
||||
count = lose = skip = 0;
|
||||
|
|
@ -344,17 +449,15 @@ glob_vector (pat, dir)
|
|||
|
||||
/* Compute the flags that will be passed to strmatch(). We don't
|
||||
need to do this every time through the loop. */
|
||||
flags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME;
|
||||
mflags = (noglob_dot_filenames ? FNM_PERIOD : 0) | FNM_PATHNAME;
|
||||
|
||||
#ifdef FNM_CASEFOLD
|
||||
if (glob_ignore_case)
|
||||
flags |= FNM_CASEFOLD;
|
||||
mflags |= FNM_CASEFOLD;
|
||||
#endif
|
||||
|
||||
#ifdef SHELL
|
||||
if (extended_glob)
|
||||
flags |= FNM_EXTMATCH;
|
||||
#endif
|
||||
mflags |= FNM_EXTMATCH;
|
||||
|
||||
/* Scan the directory, finding all names that match.
|
||||
For each name that matches, allocate a struct globval
|
||||
|
|
@ -362,14 +465,12 @@ glob_vector (pat, dir)
|
|||
Chain those structs together; lastlink is the front of the chain. */
|
||||
while (1)
|
||||
{
|
||||
#if defined (SHELL)
|
||||
/* Make globbing interruptible in the shell. */
|
||||
if (interrupt_state)
|
||||
{
|
||||
lose = 1;
|
||||
break;
|
||||
}
|
||||
#endif /* SHELL */
|
||||
|
||||
dp = readdir (d);
|
||||
if (dp == NULL)
|
||||
|
|
@ -379,22 +480,15 @@ glob_vector (pat, dir)
|
|||
if (REAL_DIR_ENTRY (dp) == 0)
|
||||
continue;
|
||||
|
||||
/* If a leading dot need not be explicitly matched, and the pattern
|
||||
doesn't start with a `.', don't match `.' or `..' */
|
||||
#define dname dp->d_name
|
||||
if (noglob_dot_filenames == 0 && pat[0] != '.' &&
|
||||
(pat[0] != '\\' || pat[1] != '.') &&
|
||||
(dname[0] == '.' &&
|
||||
(dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0'))))
|
||||
#undef dname
|
||||
#if HANDLE_MULTIBYTE
|
||||
if (MB_CUR_MAX > 1 && mbskipname (pat, dp->d_name))
|
||||
continue;
|
||||
else
|
||||
#endif
|
||||
if (skipname (pat, dp->d_name))
|
||||
continue;
|
||||
|
||||
/* If a dot must be explicity matched, check to see if they do. */
|
||||
if (noglob_dot_filenames && dp->d_name[0] == '.' && pat[0] != '.' &&
|
||||
(pat[0] != '\\' || pat[1] != '.'))
|
||||
continue;
|
||||
|
||||
if (strmatch (pat, dp->d_name, flags) != FNM_NOMATCH)
|
||||
if (strmatch (pat, dp->d_name, mflags) != FNM_NOMATCH)
|
||||
{
|
||||
nextlink = (struct globval *) alloca (sizeof (struct globval));
|
||||
nextlink->next = lastlink;
|
||||
|
|
@ -429,10 +523,8 @@ glob_vector (pat, dir)
|
|||
free (lastlink->name);
|
||||
lastlink = lastlink->next;
|
||||
}
|
||||
#if defined (SHELL)
|
||||
if (interrupt_state)
|
||||
throw_to_top_level ();
|
||||
#endif /* SHELL */
|
||||
|
||||
QUIT;
|
||||
|
||||
return ((char **)NULL);
|
||||
}
|
||||
|
|
@ -447,22 +539,40 @@ glob_vector (pat, dir)
|
|||
name_vector[count] = NULL;
|
||||
return (name_vector);
|
||||
}
|
||||
|
||||
|
||||
/* Return a new array which is the concatenation of each string in ARRAY
|
||||
to DIR. This function expects you to pass in an allocated ARRAY, and
|
||||
it takes care of free()ing that array. Thus, you might think of this
|
||||
function as side-effecting ARRAY. */
|
||||
function as side-effecting ARRAY. This should handle GX_MARKDIRS. */
|
||||
static char **
|
||||
glob_dir_to_array (dir, array)
|
||||
glob_dir_to_array (dir, array, flags)
|
||||
char *dir, **array;
|
||||
int flags;
|
||||
{
|
||||
register unsigned int i, l;
|
||||
int add_slash;
|
||||
char **result;
|
||||
char **result, *new;
|
||||
struct stat sb;
|
||||
|
||||
l = strlen (dir);
|
||||
if (l == 0)
|
||||
return (array);
|
||||
{
|
||||
if (flags & GX_MARKDIRS)
|
||||
for (i = 0; array[i]; i++)
|
||||
{
|
||||
if ((stat (array[i], &sb) == 0) && S_ISDIR (sb.st_mode))
|
||||
{
|
||||
l = strlen (array[i]);
|
||||
new = (char *)realloc (array[i], l + 2);
|
||||
if (new == 0)
|
||||
return NULL;
|
||||
new[l] = '/';
|
||||
new[l+1] = '\0';
|
||||
array[i] = new;
|
||||
}
|
||||
}
|
||||
return (array);
|
||||
}
|
||||
|
||||
add_slash = dir[l - 1] != '/';
|
||||
|
||||
|
|
@ -476,8 +586,9 @@ glob_dir_to_array (dir, array)
|
|||
|
||||
for (i = 0; array[i] != NULL; i++)
|
||||
{
|
||||
result[i] = (char *) malloc (l + (add_slash ? 1 : 0)
|
||||
+ strlen (array[i]) + 1);
|
||||
/* 3 == 1 for NUL, 1 for slash at end of DIR, 1 for GX_MARKDIRS */
|
||||
result[i] = (char *) malloc (l + strlen (array[i]) + 3);
|
||||
|
||||
if (result[i] == NULL)
|
||||
return (NULL);
|
||||
|
||||
|
|
@ -485,6 +596,16 @@ glob_dir_to_array (dir, array)
|
|||
if (add_slash)
|
||||
result[i][l] = '/';
|
||||
strcpy (result[i] + l + add_slash, array[i]);
|
||||
if (flags & GX_MARKDIRS)
|
||||
{
|
||||
if ((stat (result[i], &sb) == 0) && S_ISDIR (sb.st_mode))
|
||||
{
|
||||
size_t rlen;
|
||||
rlen = strlen (result[i]);
|
||||
result[i][rlen] = '/';
|
||||
result[i][rlen+1] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
result[i] = NULL;
|
||||
|
||||
|
|
@ -495,15 +616,16 @@ glob_dir_to_array (dir, array)
|
|||
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
||||
/* Do globbing on PATHNAME. Return an array of pathnames that match,
|
||||
marking the end of the array with a null-pointer as an element.
|
||||
If no pathnames match, then the array is empty (first element is null).
|
||||
If there isn't enough memory, then return NULL.
|
||||
If a file system error occurs, return -1; `errno' has the error code. */
|
||||
char **
|
||||
glob_filename (pathname)
|
||||
glob_filename (pathname, flags)
|
||||
char *pathname;
|
||||
int flags;
|
||||
{
|
||||
char **result;
|
||||
unsigned int result_size;
|
||||
|
|
@ -545,7 +667,7 @@ glob_filename (pathname)
|
|||
if (directory_name[directory_len - 1] == '/')
|
||||
directory_name[directory_len - 1] = '\0';
|
||||
|
||||
directories = glob_filename (directory_name);
|
||||
directories = glob_filename (directory_name, flags & ~GX_MARKDIRS);
|
||||
|
||||
if (directories == NULL)
|
||||
goto memory_error;
|
||||
|
|
@ -571,7 +693,7 @@ glob_filename (pathname)
|
|||
/* Scan directory even on a NULL pathname. That way, `*h/'
|
||||
returns only directories ending in `h', instead of all
|
||||
files ending in `h' with a `/' appended. */
|
||||
temp_results = glob_vector (filename, directories[i]);
|
||||
temp_results = glob_vector (filename, directories[i], flags & ~GX_MARKDIRS);
|
||||
|
||||
/* Handle error cases. */
|
||||
if (temp_results == NULL)
|
||||
|
|
@ -584,7 +706,7 @@ glob_filename (pathname)
|
|||
char **array;
|
||||
register unsigned int l;
|
||||
|
||||
array = glob_dir_to_array (directories[i], temp_results);
|
||||
array = glob_dir_to_array (directories[i], temp_results, flags);
|
||||
l = 0;
|
||||
while (array[l] != NULL)
|
||||
++l;
|
||||
|
|
@ -619,6 +741,7 @@ glob_filename (pathname)
|
|||
result = (char **) realloc ((char *) result, 2 * sizeof (char *));
|
||||
if (result == NULL)
|
||||
return (NULL);
|
||||
/* Handle GX_MARKDIRS here. */
|
||||
result[0] = (char *) malloc (directory_len + 1);
|
||||
if (result[0] == NULL)
|
||||
goto memory_error;
|
||||
|
|
@ -642,13 +765,14 @@ glob_filename (pathname)
|
|||
|
||||
/* Just return what glob_vector () returns appended to the
|
||||
directory name. */
|
||||
temp_results =
|
||||
glob_vector (filename, (directory_len == 0 ? "." : directory_name));
|
||||
temp_results = glob_vector (filename,
|
||||
(directory_len == 0 ? "." : directory_name),
|
||||
flags & ~GX_MARKDIRS);
|
||||
|
||||
if (temp_results == NULL || temp_results == (char **)&glob_error_return)
|
||||
return (temp_results);
|
||||
|
||||
return (glob_dir_to_array (directory_name, temp_results));
|
||||
return (glob_dir_to_array (directory_name, temp_results, flags));
|
||||
}
|
||||
|
||||
/* We get to memory_error if the program has run out of memory, or
|
||||
|
|
@ -661,13 +785,12 @@ glob_filename (pathname)
|
|||
free (result[i]);
|
||||
free ((char *) result);
|
||||
}
|
||||
#if defined (SHELL)
|
||||
if (interrupt_state)
|
||||
throw_to_top_level ();
|
||||
#endif /* SHELL */
|
||||
|
||||
QUIT;
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
|
||||
#if defined (TEST)
|
||||
|
||||
main (argc, argv)
|
||||
|
|
@ -678,7 +801,7 @@ main (argc, argv)
|
|||
|
||||
for (i = 1; i < argc; ++i)
|
||||
{
|
||||
char **value = glob_filename (argv[i]);
|
||||
char **value = glob_filename (argv[i], 0);
|
||||
if (value == NULL)
|
||||
puts ("Out of memory.");
|
||||
else if (value == &glob_error_return)
|
||||
|
|
|
|||
|
|
@ -20,9 +20,13 @@
|
|||
|
||||
#include "stdc.h"
|
||||
|
||||
#define GX_MARKDIRS 0x01 /* mark directory names with trailing `/' */
|
||||
#define GX_NOCASE 0x02 /* ignore case */
|
||||
#define GX_MATCHDOT 0x04 /* match `.' literally */
|
||||
|
||||
extern int glob_pattern_p __P((const char *));
|
||||
extern char **glob_vector __P((char *, char *));
|
||||
extern char **glob_filename __P((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;
|
||||
|
|
|
|||
67
lib/glob/glob_loop.c
Normal file
67
lib/glob/glob_loop.c
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/* Copyright (C) 1991-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
static int INTERNAL_GLOB_PATTERN_P __P((const CHAR *));
|
||||
|
||||
/* Return nonzero if PATTERN has any special globbing chars in it.
|
||||
Compiled twice, once each for single-byte and multibyte characters. */
|
||||
static int
|
||||
INTERNAL_GLOB_PATTERN_P (pattern)
|
||||
const CHAR *pattern;
|
||||
{
|
||||
register const CHAR *p;
|
||||
register CHAR c;
|
||||
int bopen;
|
||||
|
||||
p = pattern;
|
||||
bopen = 0;
|
||||
|
||||
while ((c = *p++) != L('\0'))
|
||||
switch (c)
|
||||
{
|
||||
case L('?'):
|
||||
case L('*'):
|
||||
return 1;
|
||||
|
||||
case L('['): /* Only accept an open brace if there is a close */
|
||||
bopen++; /* brace to match it. Bracket expressions must be */
|
||||
continue; /* complete, according to Posix.2 */
|
||||
case L(']'):
|
||||
if (bopen)
|
||||
return 1;
|
||||
continue;
|
||||
|
||||
case L('+'): /* extended matching operators */
|
||||
case L('@'):
|
||||
case L('!'):
|
||||
if (*p == L('(')) /*) */
|
||||
return 1;
|
||||
continue;
|
||||
|
||||
case L('\\'):
|
||||
if (*p++ == L('\0'))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef INTERNAL_GLOB_PATTERN_P
|
||||
#undef L
|
||||
#undef INT
|
||||
#undef CHAR
|
||||
737
lib/glob/sm_loop.c
Normal file
737
lib/glob/sm_loop.c
Normal file
|
|
@ -0,0 +1,737 @@
|
|||
/* Copyright (C) 1991-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
static int FCT __P((CHAR *, CHAR *, int));
|
||||
static int GMATCH __P((CHAR *, CHAR *, CHAR *, CHAR *, int));
|
||||
static CHAR *PARSE_COLLSYM __P((CHAR *, INT *));
|
||||
static CHAR *BRACKMATCH __P((CHAR *, U_CHAR, int));
|
||||
static int EXTMATCH __P((INT, CHAR *, CHAR *, CHAR *, CHAR *, int));
|
||||
static CHAR *PATSCAN __P((CHAR *, CHAR *, INT));
|
||||
|
||||
static int
|
||||
FCT (pattern, string, flags)
|
||||
CHAR *pattern;
|
||||
CHAR *string;
|
||||
int flags;
|
||||
{
|
||||
CHAR *se, *pe;
|
||||
|
||||
if (string == 0 || pattern == 0)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
se = string + STRLEN ((XCHAR *)string);
|
||||
pe = pattern + STRLEN ((XCHAR *)pattern);
|
||||
|
||||
return (GMATCH (string, se, pattern, pe, flags));
|
||||
}
|
||||
|
||||
/* Match STRING against the filename pattern PATTERN, returning zero if
|
||||
it matches, FNM_NOMATCH if not. */
|
||||
static int
|
||||
GMATCH (string, se, pattern, pe, flags)
|
||||
CHAR *string, *se;
|
||||
CHAR *pattern, *pe;
|
||||
int flags;
|
||||
{
|
||||
CHAR *p, *n; /* pattern, string */
|
||||
INT c; /* current pattern character - XXX U_CHAR? */
|
||||
INT sc; /* current string character - XXX U_CHAR? */
|
||||
|
||||
p = pattern;
|
||||
n = string;
|
||||
|
||||
if (string == 0 || pattern == 0)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
#if DEBUG_MATCHING
|
||||
fprintf(stderr, "gmatch: string = %s; se = %s\n", string, se);
|
||||
fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
|
||||
#endif
|
||||
|
||||
while (p < pe)
|
||||
{
|
||||
c = *p++;
|
||||
c = FOLD (c);
|
||||
|
||||
sc = n < se ? *n : '\0';
|
||||
|
||||
#ifdef EXTENDED_GLOB
|
||||
/* EXTMATCH () will handle recursively calling GMATCH, so we can
|
||||
just return what EXTMATCH() returns. */
|
||||
if ((flags & FNM_EXTMATCH) && *p == L('(') &&
|
||||
(c == L('+') || c == L('*') || c == L('?') || c == L('@') || c == L('!'))) /* ) */
|
||||
{
|
||||
int lflags;
|
||||
/* If we're not matching the start of the string, we're not
|
||||
concerned about the special cases for matching `.' */
|
||||
lflags = (n == string) ? flags : (flags & ~FNM_PERIOD);
|
||||
return (EXTMATCH (c, n, se, p, pe, lflags));
|
||||
}
|
||||
#endif /* EXTENDED_GLOB */
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case L('?'): /* Match single character */
|
||||
if (sc == '\0')
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_PATHNAME) && sc == L('/'))
|
||||
/* If we are matching a pathname, `?' can never match a `/'. */
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_PERIOD) && sc == L('.') &&
|
||||
(n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
|
||||
/* `?' cannot match a `.' if it is the first character of the
|
||||
string or if it is the first character following a slash and
|
||||
we are matching a pathname. */
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
case L('\\'): /* backslash escape removes special meaning */
|
||||
if (p == pe)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
if ((flags & FNM_NOESCAPE) == 0)
|
||||
{
|
||||
c = *p++;
|
||||
/* A trailing `\' cannot match. */
|
||||
if (p > pe)
|
||||
return FNM_NOMATCH;
|
||||
c = FOLD (c);
|
||||
}
|
||||
if (FOLD (sc) != (U_CHAR)c)
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
case '*': /* Match zero or more characters */
|
||||
if (p == pe)
|
||||
return 0;
|
||||
|
||||
if ((flags & FNM_PERIOD) && sc == L('.') &&
|
||||
(n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
|
||||
/* `*' cannot match a `.' if it is the first character of the
|
||||
string or if it is the first character following a slash and
|
||||
we are matching a pathname. */
|
||||
return FNM_NOMATCH;
|
||||
|
||||
/* Collapse multiple consecutive `*' and `?', but make sure that
|
||||
one character of the string is consumed for each `?'. */
|
||||
for (c = *p++; (c == L('?') || c == L('*')); c = *p++)
|
||||
{
|
||||
if ((flags & FNM_PATHNAME) && sc == L('/'))
|
||||
/* A slash does not match a wildcard under FNM_PATHNAME. */
|
||||
return FNM_NOMATCH;
|
||||
else if (c == L('?'))
|
||||
{
|
||||
if (sc == L('\0'))
|
||||
return FNM_NOMATCH;
|
||||
/* One character of the string is consumed in matching
|
||||
this ? wildcard, so *??? won't match if there are
|
||||
fewer than three characters. */
|
||||
n++;
|
||||
sc = n < se ? *n : '\0';
|
||||
}
|
||||
|
||||
#ifdef EXTENDED_GLOB
|
||||
/* Handle ******(patlist) */
|
||||
if ((flags & FNM_EXTMATCH) && c == L('*') && *p == L('(')) /*)*/
|
||||
{
|
||||
CHAR *newn;
|
||||
/* We need to check whether or not the extended glob
|
||||
pattern matches the remainder of the string.
|
||||
If it does, we match the entire pattern. */
|
||||
for (newn = n; newn < se; ++newn)
|
||||
{
|
||||
if (EXTMATCH (c, newn, se, p, pe, flags) == 0)
|
||||
return (0);
|
||||
}
|
||||
/* We didn't match the extended glob pattern, but
|
||||
that's OK, since we can match 0 or more occurrences.
|
||||
We need to skip the glob pattern and see if we
|
||||
match the rest of the string. */
|
||||
newn = PATSCAN (p + 1, pe, 0);
|
||||
/* If NEWN is 0, we have an ill-formed pattern. */
|
||||
p = newn ? newn : pe;
|
||||
}
|
||||
#endif
|
||||
if (p == pe)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we've hit the end of the pattern and the last character of
|
||||
the pattern was handled by the loop above, we've succeeded.
|
||||
Otherwise, we need to match that last character. */
|
||||
if (p == pe && (c == L('?') || c == L('*')))
|
||||
return (0);
|
||||
|
||||
/* General case, use recursion. */
|
||||
{
|
||||
U_CHAR c1;
|
||||
|
||||
c1 = ((flags & FNM_NOESCAPE) == 0 && c == L('\\')) ? *p : c;
|
||||
c1 = FOLD (c1);
|
||||
for (--p; n < se; ++n)
|
||||
{
|
||||
/* Only call strmatch if the first character indicates a
|
||||
possible match. We can check the first character if
|
||||
we're not doing an extended glob match. */
|
||||
if ((flags & FNM_EXTMATCH) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/
|
||||
continue;
|
||||
|
||||
/* If we're doing an extended glob match and the pattern is not
|
||||
one of the extended glob patterns, we can check the first
|
||||
character. */
|
||||
if ((flags & FNM_EXTMATCH) && p[1] != L('(') && /*)*/
|
||||
STRCHR (L("?*+@!"), *p) == 0 && c != L('[') && FOLD (*n) != c1) /*]*/
|
||||
continue;
|
||||
|
||||
/* Otherwise, we just recurse. */
|
||||
if (GMATCH (n, se, p, pe, flags & ~FNM_PERIOD) == 0)
|
||||
return (0);
|
||||
}
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
case L('['):
|
||||
{
|
||||
if (sc == L('\0') || n == se)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
/* A character class cannot match a `.' if it is the first
|
||||
character of the string or if it is the first character
|
||||
following a slash and we are matching a pathname. */
|
||||
if ((flags & FNM_PERIOD) && sc == L('.') &&
|
||||
(n == string || ((flags & FNM_PATHNAME) && n[-1] == L('/'))))
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
p = BRACKMATCH (p, sc, flags);
|
||||
if (p == 0)
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((U_CHAR)c != FOLD (sc))
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
++n;
|
||||
}
|
||||
|
||||
if (n == se)
|
||||
return (0);
|
||||
|
||||
if ((flags & FNM_LEADING_DIR) && *n == L('/'))
|
||||
/* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
|
||||
return 0;
|
||||
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
/* Parse a bracket expression collating symbol ([.sym.]) starting at P, find
|
||||
the value of the symbol, and move P past the collating symbol expression.
|
||||
The value is returned in *VP, if VP is not null. */
|
||||
static CHAR *
|
||||
PARSE_COLLSYM (p, vp)
|
||||
CHAR *p;
|
||||
INT *vp;
|
||||
{
|
||||
register int pc;
|
||||
INT val;
|
||||
|
||||
p++; /* move past the `.' */
|
||||
|
||||
for (pc = 0; p[pc]; pc++)
|
||||
if (p[pc] == L('.') && p[pc+1] == L(']'))
|
||||
break;
|
||||
val = COLLSYM (p, pc);
|
||||
if (vp)
|
||||
*vp = val;
|
||||
return (p + pc + 2);
|
||||
}
|
||||
|
||||
/* Use prototype definition here because of type promotion. */
|
||||
static CHAR *
|
||||
#if defined (PROTOTYPES)
|
||||
BRACKMATCH (CHAR *p, U_CHAR test, int flags)
|
||||
#else
|
||||
BRACKMATCH (p, test, flags)
|
||||
CHAR *p;
|
||||
U_CHAR test;
|
||||
int flags;
|
||||
#endif
|
||||
{
|
||||
register CHAR cstart, cend, c;
|
||||
register int not; /* Nonzero if the sense of the character class is inverted. */
|
||||
int brcnt;
|
||||
INT pc;
|
||||
CHAR *savep;
|
||||
|
||||
test = FOLD (test);
|
||||
|
||||
savep = p;
|
||||
|
||||
/* POSIX.2 3.13.1 says that an exclamation mark (`!') shall replace the
|
||||
circumflex (`^') in its role in a `nonmatching list'. A bracket
|
||||
expression starting with an unquoted circumflex character produces
|
||||
unspecified results. This implementation treats the two identically. */
|
||||
if (not = (*p == L('!') || *p == L('^')))
|
||||
++p;
|
||||
|
||||
c = *p++;
|
||||
for (;;)
|
||||
{
|
||||
/* Initialize cstart and cend in case `-' is the last
|
||||
character of the pattern. */
|
||||
cstart = cend = c;
|
||||
|
||||
/* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find
|
||||
the end of the equivalence class, move the pattern pointer past
|
||||
it, and check for equivalence. XXX - this handles only
|
||||
single-character equivalence classes, which is wrong, or at
|
||||
least incomplete. */
|
||||
if (c == L('[') && *p == L('=') && p[2] == L('=') && p[3] == L(']'))
|
||||
{
|
||||
pc = FOLD (p[1]);
|
||||
p += 4;
|
||||
if (COLLEQUIV (test, pc))
|
||||
{
|
||||
/*[*/ /* Move past the closing `]', since the first thing we do at
|
||||
the `matched:' label is back p up one. */
|
||||
p++;
|
||||
goto matched;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = *p++;
|
||||
if (c == L('\0'))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0); /*]*/
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* POSIX.2 character class expression. See POSIX.2 2.8.3.2. */
|
||||
if (c == L('[') && *p == L(':'))
|
||||
{
|
||||
CHAR *close, *ccname;
|
||||
|
||||
pc = 0; /* make sure invalid char classes don't match. */
|
||||
/* Find end of character class name */
|
||||
for (close = p + 1; *close != '\0'; close++)
|
||||
if (*close == L(':') && *(close+1) == L(']'))
|
||||
break;
|
||||
|
||||
if (*close != L('\0'))
|
||||
{
|
||||
ccname = (CHAR *)malloc ((close - p) * sizeof (CHAR));
|
||||
if (ccname == 0)
|
||||
pc = 0;
|
||||
else
|
||||
{
|
||||
bcopy (p + 1, ccname, (close - p - 1) * sizeof (CHAR));
|
||||
*(ccname + (close - p - 1)) = L('\0');
|
||||
pc = IS_CCLASS (test, ccname);
|
||||
}
|
||||
if (pc == -1)
|
||||
pc = 0;
|
||||
else
|
||||
p = close + 2;
|
||||
|
||||
free (ccname);
|
||||
}
|
||||
|
||||
if (pc)
|
||||
{
|
||||
/*[*/ /* Move past the closing `]', since the first thing we do at
|
||||
the `matched:' label is back p up one. */
|
||||
p++;
|
||||
goto matched;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* continue the loop here, since this expression can't be
|
||||
the first part of a range expression. */
|
||||
c = *p++;
|
||||
if (c == L('\0'))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
else if (c == L(']'))
|
||||
break;
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* POSIX.2 collating symbols. See POSIX.2 2.8.3.2. Find the end of
|
||||
the symbol name, make sure it is terminated by `.]', translate
|
||||
the name to a character using the external table, and do the
|
||||
comparison. */
|
||||
if (c == L('[') && *p == L('.'))
|
||||
{
|
||||
p = PARSE_COLLSYM (p, &pc);
|
||||
/* An invalid collating symbol cannot be the first point of a
|
||||
range. If it is, we set cstart to one greater than `test',
|
||||
so any comparisons later will fail. */
|
||||
cstart = (pc == INVALID) ? test + 1 : pc;
|
||||
}
|
||||
|
||||
if (!(flags & FNM_NOESCAPE) && c == L('\\'))
|
||||
{
|
||||
if (*p == '\0')
|
||||
return (CHAR *)0;
|
||||
cstart = cend = *p++;
|
||||
}
|
||||
|
||||
cstart = cend = FOLD (cstart);
|
||||
|
||||
/* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that
|
||||
is not preceded by a backslash and is not part of a bracket
|
||||
expression produces undefined results.' This implementation
|
||||
treats the `[' as just a character to be matched if there is
|
||||
not a closing `]'. */
|
||||
if (c == L('\0'))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
|
||||
c = *p++;
|
||||
c = FOLD (c);
|
||||
|
||||
if ((flags & FNM_PATHNAME) && c == L('/'))
|
||||
/* [/] can never match when matching a pathname. */
|
||||
return (CHAR *)0;
|
||||
|
||||
/* This introduces a range, unless the `-' is the last
|
||||
character of the class. Find the end of the range
|
||||
and move past it. */
|
||||
if (c == L('-') && *p != L(']'))
|
||||
{
|
||||
cend = *p++;
|
||||
if (!(flags & FNM_NOESCAPE) && cend == L('\\'))
|
||||
cend = *p++;
|
||||
if (cend == L('\0'))
|
||||
return (CHAR *)0;
|
||||
if (cend == L('[') && *p == L('.'))
|
||||
{
|
||||
p = PARSE_COLLSYM (p, &pc);
|
||||
/* An invalid collating symbol cannot be the second part of a
|
||||
range expression. If we get one, we set cend to one fewer
|
||||
than the test character to make sure the range test fails. */
|
||||
cend = (pc == INVALID) ? test - 1 : pc;
|
||||
}
|
||||
cend = FOLD (cend);
|
||||
|
||||
c = *p++;
|
||||
|
||||
/* POSIX.2 2.8.3.2: ``The ending range point shall collate
|
||||
equal to or higher than the starting range point; otherwise
|
||||
the expression shall be treated as invalid.'' Note that this
|
||||
applies to only the range expression; the rest of the bracket
|
||||
expression is still checked for matches. */
|
||||
if (RANGECMP (cstart, cend) > 0)
|
||||
{
|
||||
if (c == L(']'))
|
||||
break;
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (RANGECMP (test, cstart) >= 0 && RANGECMP (test, cend) <= 0)
|
||||
goto matched;
|
||||
|
||||
if (c == L(']'))
|
||||
break;
|
||||
}
|
||||
/* No match. */
|
||||
return (!not ? (CHAR *)0 : p);
|
||||
|
||||
matched:
|
||||
/* Skip the rest of the [...] that already matched. */
|
||||
c = *--p;
|
||||
brcnt = 1;
|
||||
while (brcnt > 0)
|
||||
{
|
||||
/* A `[' without a matching `]' is just another character to match. */
|
||||
if (c == L('\0'))
|
||||
return ((test == L('[')) ? savep : (CHAR *)0);
|
||||
|
||||
c = *p++;
|
||||
if (c == L('[') && (*p == L('=') || *p == L(':') || *p == L('.')))
|
||||
brcnt++;
|
||||
else if (c == L(']'))
|
||||
brcnt--;
|
||||
else if (!(flags & FNM_NOESCAPE) && c == L('\\'))
|
||||
{
|
||||
if (*p == '\0')
|
||||
return (CHAR *)0;
|
||||
/* XXX 1003.2d11 is unclear if this is right. */
|
||||
++p;
|
||||
}
|
||||
}
|
||||
return (not ? (CHAR *)0 : p);
|
||||
}
|
||||
|
||||
#if defined (EXTENDED_GLOB)
|
||||
/* ksh-like extended pattern matching:
|
||||
|
||||
[?*+@!](pat-list)
|
||||
|
||||
where pat-list is a list of one or patterns separated by `|'. Operation
|
||||
is as follows:
|
||||
|
||||
?(patlist) match zero or one of the given patterns
|
||||
*(patlist) match zero or more of the given patterns
|
||||
+(patlist) match one or more of the given patterns
|
||||
@(patlist) match exactly one of the given patterns
|
||||
!(patlist) match anything except one of the given patterns
|
||||
*/
|
||||
|
||||
/* Scan a pattern starting at STRING and ending at END, keeping track of
|
||||
embedded () and []. If DELIM is 0, we scan until a matching `)'
|
||||
because we're scanning a `patlist'. Otherwise, we scan until we see
|
||||
DELIM. In all cases, we never scan past END. The return value is the
|
||||
first character after the matching DELIM. */
|
||||
static CHAR *
|
||||
PATSCAN (string, end, delim)
|
||||
CHAR *string, *end;
|
||||
INT delim;
|
||||
{
|
||||
int pnest, bnest;
|
||||
INT cchar;
|
||||
CHAR *s, c, *bfirst;
|
||||
|
||||
pnest = bnest = 0;
|
||||
cchar = 0;
|
||||
bfirst = NULL;
|
||||
|
||||
for (s = string; c = *s; s++)
|
||||
{
|
||||
if (s >= end)
|
||||
return (s);
|
||||
switch (c)
|
||||
{
|
||||
case L('\0'):
|
||||
return ((CHAR *)NULL);
|
||||
|
||||
/* `[' is not special inside a bracket expression, but it may
|
||||
introduce one of the special POSIX bracket expressions
|
||||
([.SYM.], [=c=], [: ... :]) that needs special handling. */
|
||||
case L('['):
|
||||
if (bnest == 0)
|
||||
{
|
||||
bfirst = s + 1;
|
||||
if (*bfirst == L('!') || *bfirst == L('^'))
|
||||
bfirst++;
|
||||
bnest++;
|
||||
}
|
||||
else if (s[1] == L(':') || s[1] == L('.') || s[1] == L('='))
|
||||
cchar = s[1];
|
||||
break;
|
||||
|
||||
/* `]' is not special if it's the first char (after a leading `!'
|
||||
or `^') in a bracket expression or if it's part of one of the
|
||||
special POSIX bracket expressions ([.SYM.], [=c=], [: ... :]) */
|
||||
case L(']'):
|
||||
if (bnest)
|
||||
{
|
||||
if (cchar && s[-1] == cchar)
|
||||
cchar = 0;
|
||||
else if (s != bfirst)
|
||||
{
|
||||
bnest--;
|
||||
bfirst = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case L('('):
|
||||
if (bnest == 0)
|
||||
pnest++;
|
||||
break;
|
||||
|
||||
case L(')'):
|
||||
if (bnest == 0 && pnest-- <= 0)
|
||||
return ++s;
|
||||
break;
|
||||
|
||||
case L('|'):
|
||||
if (bnest == 0 && pnest == 0 && delim == L('|'))
|
||||
return ++s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Return 0 if dequoted pattern matches S in the current locale. */
|
||||
static int
|
||||
STRCOMPARE (p, pe, s, se)
|
||||
CHAR *p, *pe, *s, *se;
|
||||
{
|
||||
int ret;
|
||||
CHAR c1, c2;
|
||||
|
||||
c1 = *pe;
|
||||
c2 = *se;
|
||||
|
||||
*pe = *se = '\0';
|
||||
#if HAVE_MULTIBYTE || defined (HAVE_STRCOLL)
|
||||
ret = STRCOLL ((XCHAR *)p, (XCHAR *)s);
|
||||
#else
|
||||
ret = STRCMP ((XCHAR *)p, (XCHAR *)s);
|
||||
#endif
|
||||
|
||||
*pe = c1;
|
||||
*se = c2;
|
||||
|
||||
return (ret == 0 ? ret : FNM_NOMATCH);
|
||||
}
|
||||
|
||||
/* Match a ksh extended pattern specifier. Return FNM_NOMATCH on failure or
|
||||
0 on success. This is handed the entire rest of the pattern and string
|
||||
the first time an extended pattern specifier is encountered, so it calls
|
||||
gmatch recursively. */
|
||||
static int
|
||||
EXTMATCH (xc, s, se, p, pe, flags)
|
||||
INT xc; /* select which operation */
|
||||
CHAR *s, *se;
|
||||
CHAR *p, *pe;
|
||||
int flags;
|
||||
{
|
||||
CHAR *prest; /* pointer to rest of pattern */
|
||||
CHAR *psub; /* pointer to sub-pattern */
|
||||
CHAR *pnext; /* pointer to next sub-pattern */
|
||||
CHAR *srest; /* pointer to rest of string */
|
||||
int m1, m2;
|
||||
|
||||
#if DEBUG_MATCHING
|
||||
fprintf(stderr, "extmatch: xc = %c\n", xc);
|
||||
fprintf(stderr, "extmatch: s = %s; se = %s\n", s, se);
|
||||
fprintf(stderr, "extmatch: p = %s; pe = %s\n", p, pe);
|
||||
#endif
|
||||
|
||||
prest = PATSCAN (p + (*p == L('(')), pe, 0); /* ) */
|
||||
if (prest == 0)
|
||||
/* If PREST is 0, we failed to scan a valid pattern. In this
|
||||
case, we just want to compare the two as strings. */
|
||||
return (STRCOMPARE (p - 1, pe, s, se));
|
||||
|
||||
switch (xc)
|
||||
{
|
||||
case L('+'): /* match one or more occurrences */
|
||||
case L('*'): /* match zero or more occurrences */
|
||||
/* If we can get away with no matches, don't even bother. Just
|
||||
call GMATCH on the rest of the pattern and return success if
|
||||
it succeeds. */
|
||||
if (xc == L('*') && (GMATCH (s, se, prest, pe, flags) == 0))
|
||||
return 0;
|
||||
|
||||
/* OK, we have to do this the hard way. First, we make sure one of
|
||||
the subpatterns matches, then we try to match the rest of the
|
||||
string. */
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = PATSCAN (psub, pe, L('|'));
|
||||
for (srest = s; srest <= se; srest++)
|
||||
{
|
||||
/* Match this substring (S -> SREST) against this
|
||||
subpattern (psub -> pnext - 1) */
|
||||
m1 = GMATCH (s, srest, psub, pnext - 1, flags) == 0;
|
||||
/* OK, we matched a subpattern, so make sure the rest of the
|
||||
string matches the rest of the pattern. Also handle
|
||||
multiple matches of the pattern. */
|
||||
if (m1)
|
||||
m2 = (GMATCH (srest, se, prest, pe, flags) == 0) ||
|
||||
(s != srest && GMATCH (srest, se, p - 1, pe, flags) == 0);
|
||||
if (m1 && m2)
|
||||
return (0);
|
||||
}
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
case L('?'): /* match zero or one of the patterns */
|
||||
case L('@'): /* match exactly one of the patterns */
|
||||
/* If we can get away with no matches, don't even bother. Just
|
||||
call gmatch on the rest of the pattern and return success if
|
||||
it succeeds. */
|
||||
if (xc == L('?') && (GMATCH (s, se, prest, pe, flags) == 0))
|
||||
return 0;
|
||||
|
||||
/* OK, we have to do this the hard way. First, we see if one of
|
||||
the subpatterns matches, then, if it does, we try to match the
|
||||
rest of the string. */
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = PATSCAN (psub, pe, L('|'));
|
||||
srest = (prest == pe) ? se : s;
|
||||
for ( ; srest <= se; srest++)
|
||||
{
|
||||
if (GMATCH (s, srest, psub, pnext - 1, flags) == 0 &&
|
||||
GMATCH (srest, se, prest, pe, flags) == 0)
|
||||
return (0);
|
||||
}
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
case '!': /* match anything *except* one of the patterns */
|
||||
for (srest = s; srest <= se; srest++)
|
||||
{
|
||||
m1 = 0;
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = PATSCAN (psub, pe, L('|'));
|
||||
/* If one of the patterns matches, just bail immediately. */
|
||||
if (m1 = (GMATCH (s, srest, psub, pnext - 1, flags) == 0))
|
||||
break;
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
if (m1 == 0 && GMATCH (srest, se, prest, pe, flags) == 0)
|
||||
return (0);
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
#endif /* EXTENDED_GLOB */
|
||||
|
||||
#undef IS_CCLASS
|
||||
#undef FOLD
|
||||
#undef CHAR
|
||||
#undef U_CHAR
|
||||
#undef XCHAR
|
||||
#undef INT
|
||||
#undef INVALID
|
||||
#undef FCT
|
||||
#undef GMATCH
|
||||
#undef COLLSYM
|
||||
#undef PARSE_COLLSYM
|
||||
#undef PATSCAN
|
||||
#undef STRCOMPARE
|
||||
#undef EXTMATCH
|
||||
#undef BRACKMATCH
|
||||
#undef STRCHR
|
||||
#undef STRCOLL
|
||||
#undef STRLEN
|
||||
#undef STRCMP
|
||||
#undef COLLEQUIV
|
||||
#undef RANGECMP
|
||||
#undef L
|
||||
410
lib/glob/smatch.c
Normal file
410
lib/glob/smatch.c
Normal file
|
|
@ -0,0 +1,410 @@
|
|||
/* strmatch.c -- ksh-like extended pattern matching for the shell and filename
|
||||
globbing. */
|
||||
|
||||
/* Copyright (C) 1991-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h> /* for debugging */
|
||||
|
||||
#include "strmatch.h"
|
||||
#include <chartypes.h>
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shmbutil.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* First, compile `sm_loop.c' for single-byte characters. */
|
||||
#define CHAR unsigned char
|
||||
#define U_CHAR unsigned char
|
||||
#define XCHAR char
|
||||
#define INT int
|
||||
#define L(CS) CS
|
||||
#define INVALID -1
|
||||
|
||||
#undef STREQ
|
||||
#undef STREQN
|
||||
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
|
||||
#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)
|
||||
|
||||
/* We use strcoll(3) for range comparisons in bracket expressions,
|
||||
even though it can have unwanted side effects in locales
|
||||
other than POSIX or US. For instance, in the de locale, [A-Z] matches
|
||||
all characters. */
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
/* Helper function for collating symbol equivalence. */
|
||||
static int rangecmp (c1, c2)
|
||||
int c1, c2;
|
||||
{
|
||||
static char s1[2] = { ' ', '\0' };
|
||||
static char s2[2] = { ' ', '\0' };
|
||||
int ret;
|
||||
|
||||
/* Eight bits only. Period. */
|
||||
c1 &= 0xFF;
|
||||
c2 &= 0xFF;
|
||||
|
||||
if (c1 == c2)
|
||||
return (0);
|
||||
|
||||
s1[0] = c1;
|
||||
s2[0] = c2;
|
||||
|
||||
if ((ret = strcoll (s1, s2)) != 0)
|
||||
return ret;
|
||||
return (c1 - c2);
|
||||
}
|
||||
#else /* !HAVE_STRCOLL */
|
||||
# define rangecmp(c1, c2) ((int)(c1) - (int)(c2))
|
||||
#endif /* !HAVE_STRCOLL */
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
static int
|
||||
collequiv (c1, c2)
|
||||
int c1, c2;
|
||||
{
|
||||
return (rangecmp (c1, c2) == 0);
|
||||
}
|
||||
#else
|
||||
# define collequiv(c1, c2) ((c1) == (c2))
|
||||
#endif
|
||||
|
||||
#define _COLLSYM _collsym
|
||||
#define __COLLSYM __collsym
|
||||
#define POSIXCOLL posix_collsyms
|
||||
#include "collsyms.h"
|
||||
|
||||
static int
|
||||
collsym (s, len)
|
||||
char *s;
|
||||
int len;
|
||||
{
|
||||
register struct _collsym *csp;
|
||||
|
||||
for (csp = posix_collsyms; csp->name; csp++)
|
||||
{
|
||||
if (STREQN(csp->name, s, len) && csp->name[len] == '\0')
|
||||
return (csp->code);
|
||||
}
|
||||
if (len == 1)
|
||||
return s[0];
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
/* unibyte character classification */
|
||||
#if !defined (isascii) && !defined (HAVE_ISASCII)
|
||||
# define isascii(c) ((unsigned int)(c) <= 0177)
|
||||
#endif
|
||||
|
||||
enum char_class
|
||||
{
|
||||
CC_NO_CLASS = 0,
|
||||
CC_ASCII, CC_ALNUM, CC_ALPHA, CC_BLANK, CC_CNTRL, CC_DIGIT, CC_GRAPH,
|
||||
CC_LOWER, CC_PRINT, CC_PUNCT, CC_SPACE, CC_UPPER, CC_WORD, CC_XDIGIT
|
||||
};
|
||||
|
||||
static char const *const cclass_name[] =
|
||||
{
|
||||
"",
|
||||
"ascii", "alnum", "alpha", "blank", "cntrl", "digit", "graph",
|
||||
"lower", "print", "punct", "space", "upper", "word", "xdigit"
|
||||
};
|
||||
|
||||
#define N_CHAR_CLASS (sizeof(cclass_name) / sizeof (cclass_name[0]))
|
||||
|
||||
static int
|
||||
is_cclass (c, name)
|
||||
int c;
|
||||
const char *name;
|
||||
{
|
||||
enum char_class char_class = CC_NO_CLASS;
|
||||
int i, result;
|
||||
|
||||
for (i = 1; i < N_CHAR_CLASS; i++)
|
||||
{
|
||||
if (STREQ (name, cclass_name[i]))
|
||||
{
|
||||
char_class = (enum char_class)i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (char_class == 0)
|
||||
return -1;
|
||||
|
||||
switch (char_class)
|
||||
{
|
||||
case CC_ASCII:
|
||||
result = isascii (c);
|
||||
break;
|
||||
case CC_ALNUM:
|
||||
result = ISALNUM (c);
|
||||
break;
|
||||
case CC_ALPHA:
|
||||
result = ISALPHA (c);
|
||||
break;
|
||||
case CC_BLANK:
|
||||
result = ISBLANK (c);
|
||||
break;
|
||||
case CC_CNTRL:
|
||||
result = ISCNTRL (c);
|
||||
break;
|
||||
case CC_DIGIT:
|
||||
result = ISDIGIT (c);
|
||||
break;
|
||||
case CC_GRAPH:
|
||||
result = ISGRAPH (c);
|
||||
break;
|
||||
case CC_LOWER:
|
||||
result = ISLOWER (c);
|
||||
break;
|
||||
case CC_PRINT:
|
||||
result = ISPRINT (c);
|
||||
break;
|
||||
case CC_PUNCT:
|
||||
result = ISPUNCT (c);
|
||||
break;
|
||||
case CC_SPACE:
|
||||
result = ISSPACE (c);
|
||||
break;
|
||||
case CC_UPPER:
|
||||
result = ISUPPER (c);
|
||||
break;
|
||||
case CC_WORD:
|
||||
result = (ISALNUM (c) || c == '_');
|
||||
break;
|
||||
case CC_XDIGIT:
|
||||
result = ISXDIGIT (c);
|
||||
break;
|
||||
default:
|
||||
result = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Now include `sm_loop.c' for single-byte characters. */
|
||||
/* The result of FOLD is an `unsigned char' */
|
||||
# define FOLD(c) ((flags & FNM_CASEFOLD) \
|
||||
? TOLOWER ((unsigned char)c) \
|
||||
: ((unsigned char)c))
|
||||
|
||||
#define FCT internal_strmatch
|
||||
#define GMATCH gmatch
|
||||
#define COLLSYM collsym
|
||||
#define PARSE_COLLSYM parse_collsym
|
||||
#define BRACKMATCH brackmatch
|
||||
#define PATSCAN patscan
|
||||
#define STRCOMPARE strcompare
|
||||
#define EXTMATCH extmatch
|
||||
#define STRCHR(S, C) strchr((S), (C))
|
||||
#define STRCOLL(S1, S2) strcoll((S1), (S2))
|
||||
#define STRLEN(S) strlen(S)
|
||||
#define STRCMP(S1, S2) strcmp((S1), (S2))
|
||||
#define RANGECMP(C1, C2) rangecmp((C1), (C2))
|
||||
#define COLLEQUIV(C1, C2) collequiv((C1), (C2))
|
||||
#define CTYPE_T enum char_class
|
||||
#define IS_CCLASS(C, S) is_cclass((C), (S))
|
||||
#include "sm_loop.c"
|
||||
|
||||
#if HANDLE_MULTIBYTE
|
||||
|
||||
# define CHAR wchar_t
|
||||
# define U_CHAR wint_t
|
||||
# define XCHAR wchar_t
|
||||
# define INT wint_t
|
||||
# define L(CS) L##CS
|
||||
# define INVALID WEOF
|
||||
|
||||
# undef STREQ
|
||||
# undef STREQN
|
||||
# define STREQ(s1, s2) ((wcscmp (s1, s2) == 0))
|
||||
# define STREQN(a, b, n) ((a)[0] == (b)[0] && wcsncmp(a, b, n) == 0)
|
||||
|
||||
static int
|
||||
rangecmp_wc (c1, c2)
|
||||
wint_t c1, c2;
|
||||
{
|
||||
static wchar_t s1[2] = { L' ', L'\0' };
|
||||
static wchar_t s2[2] = { L' ', L'\0' };
|
||||
int ret;
|
||||
|
||||
if (c1 == c2)
|
||||
return 0;
|
||||
|
||||
s1[0] = c1;
|
||||
s2[0] = c2;
|
||||
|
||||
return (wcscoll (s1, s2));
|
||||
}
|
||||
|
||||
static int
|
||||
collequiv_wc (c, equiv)
|
||||
wint_t c, equiv;
|
||||
{
|
||||
return (!(c - equiv));
|
||||
}
|
||||
|
||||
/* Helper function for collating symbol. */
|
||||
# define _COLLSYM _collwcsym
|
||||
# define __COLLSYM __collwcsym
|
||||
# define POSIXCOLL posix_collwcsyms
|
||||
# include "collsyms.h"
|
||||
|
||||
static wint_t
|
||||
collwcsym (s, len)
|
||||
wchar_t *s;
|
||||
int len;
|
||||
{
|
||||
register struct _collwcsym *csp;
|
||||
|
||||
for (csp = posix_collwcsyms; csp->name; csp++)
|
||||
{
|
||||
if (STREQN(csp->name, s, len) && csp->name[len] == L'\0')
|
||||
return (csp->code);
|
||||
}
|
||||
if (len == 1)
|
||||
return s[0];
|
||||
return INVALID;
|
||||
}
|
||||
|
||||
static int
|
||||
is_wcclass (wc, name)
|
||||
wint_t wc;
|
||||
wchar_t *name;
|
||||
{
|
||||
char *mbs;
|
||||
mbstate_t state;
|
||||
size_t mbslength;
|
||||
wctype_t desc;
|
||||
int want_word;
|
||||
|
||||
if ((wctype ("ascii") == (wctype_t)0) && (wcscmp (name, L"ascii") == 0))
|
||||
{
|
||||
int c;
|
||||
|
||||
if ((c = wctob (wc)) == EOF)
|
||||
return 0;
|
||||
else
|
||||
return (c <= 0x7F);
|
||||
}
|
||||
|
||||
want_word = (wcscmp (name, L"word") == 0);
|
||||
if (want_word)
|
||||
name = L"alnum";
|
||||
|
||||
memset (&state, '\0', sizeof (mbstate_t));
|
||||
mbs = (char *) malloc (wcslen(name) * MB_CUR_MAX + 1);
|
||||
mbslength = wcsrtombs(mbs, (const wchar_t **)&name, (wcslen(name) * MB_CUR_MAX + 1), &state);
|
||||
|
||||
if (mbslength == (size_t)-1 || mbslength == (size_t)-2)
|
||||
{
|
||||
free (mbs);
|
||||
return -1;
|
||||
}
|
||||
desc = wctype (mbs);
|
||||
free (mbs);
|
||||
|
||||
if (desc == (wctype_t)0)
|
||||
return -1;
|
||||
|
||||
if (want_word)
|
||||
return (iswctype (wc, desc) || wc == L'_');
|
||||
else
|
||||
return (iswctype (wc, desc));
|
||||
}
|
||||
|
||||
/* Now include `sm_loop.c' for multibyte characters. */
|
||||
#define FOLD(c) ((flags & FNM_CASEFOLD) && iswupper (c) ? towlower (c) : (c))
|
||||
#define FCT internal_wstrmatch
|
||||
#define GMATCH gmatch_wc
|
||||
#define COLLSYM collwcsym
|
||||
#define PARSE_COLLSYM parse_collwcsym
|
||||
#define BRACKMATCH brackmatch_wc
|
||||
#define PATSCAN patscan_wc
|
||||
#define STRCOMPARE wscompare
|
||||
#define EXTMATCH extmatch_wc
|
||||
#define STRCHR(S, C) wcschr((S), (C))
|
||||
#define STRCOLL(S1, S2) wcscoll((S1), (S2))
|
||||
#define STRLEN(S) wcslen(S)
|
||||
#define STRCMP(S1, S2) wcscmp((S1), (S2))
|
||||
#define RANGECMP(C1, C2) rangecmp_wc((C1), (C2))
|
||||
#define COLLEQUIV(C1, C2) collequiv_wc((C1), (C2))
|
||||
#define CTYPE_T enum char_class
|
||||
#define IS_CCLASS(C, S) is_wcclass((C), (S))
|
||||
#include "sm_loop.c"
|
||||
|
||||
#endif /* HAVE_MULTIBYTE */
|
||||
|
||||
int
|
||||
xstrmatch (pattern, string, flags)
|
||||
char *pattern;
|
||||
char *string;
|
||||
int flags;
|
||||
{
|
||||
#if HANDLE_MULTIBYTE
|
||||
int ret;
|
||||
mbstate_t ps;
|
||||
size_t n;
|
||||
char *pattern_bak;
|
||||
wchar_t *wpattern, *wstring;
|
||||
|
||||
if (MB_CUR_MAX == 1)
|
||||
return (internal_strmatch (pattern, string, flags));
|
||||
|
||||
pattern_bak = (char *)xmalloc (strlen (pattern) + 1);
|
||||
strcpy (pattern_bak, pattern);
|
||||
|
||||
memset (&ps, '\0', sizeof (mbstate_t));
|
||||
n = xmbsrtowcs (NULL, (const char **)&pattern, 0, &ps);
|
||||
if (n == (size_t)-1 || n == (size_t)-2)
|
||||
{
|
||||
free (pattern_bak);
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
}
|
||||
|
||||
wpattern = (wchar_t *)xmalloc ((n + 1) * sizeof (wchar_t));
|
||||
(void) xmbsrtowcs (wpattern, (const char **)&pattern, n + 1, &ps);
|
||||
|
||||
memset (&ps, '\0', sizeof (mbstate_t));
|
||||
n = xmbsrtowcs (NULL, (const char **)&string, 0, &ps);
|
||||
if (n == (size_t)-1 || n == (size_t)-2)
|
||||
{
|
||||
free (wpattern);
|
||||
ret = internal_strmatch (pattern_bak, string, flags);
|
||||
free (pattern_bak);
|
||||
return ret;
|
||||
}
|
||||
|
||||
wstring = (wchar_t *)xmalloc ((n + 1) * sizeof (wchar_t));
|
||||
(void) xmbsrtowcs (wstring, (const char **)&string, n + 1, &ps);
|
||||
|
||||
ret = internal_wstrmatch (wpattern, wstring, flags);
|
||||
|
||||
free (pattern_bak);
|
||||
free (wpattern);
|
||||
free (wstring);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
return (internal_strmatch ((unsigned char *)pattern, (unsigned char *)string, flags));
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
/* strmatch.c -- ksh-like extended pattern matching for the shell and filename
|
||||
globbing. */
|
||||
|
||||
/* Copyright (C) 1991, 1997 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1991-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
|
@ -21,805 +21,29 @@
|
|||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h> /* for debugging */
|
||||
|
||||
#include "stdc.h"
|
||||
#include "strmatch.h"
|
||||
#include "collsyms.h"
|
||||
#include <chartypes.h>
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
/* Structured this way so that if HAVE_LIBC_FNM_EXTMATCH is defined, the
|
||||
matching portion of the library (smatch.c) is not linked into the shell. */
|
||||
|
||||
#ifndef HAVE_LIBC_FNM_EXTMATCH
|
||||
extern int xstrmatch __P((char *, char *, int));
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif /* HAVE_STRING_H */
|
||||
|
||||
static int gmatch ();
|
||||
static char *brackmatch ();
|
||||
#ifdef EXTENDED_GLOB
|
||||
static int extmatch ();
|
||||
static char *patscan ();
|
||||
#endif
|
||||
|
||||
#if !defined (isascii) && !defined (HAVE_ISASCII)
|
||||
# define isascii(c) ((unsigned int)(c) <= 0177)
|
||||
# define xstrmatch fnmatch
|
||||
#endif
|
||||
|
||||
/* The result of FOLD is an `unsigned char' */
|
||||
# define FOLD(c) ((flags & FNM_CASEFOLD) \
|
||||
? TOLOWER ((unsigned char)c) \
|
||||
: ((unsigned char)c))
|
||||
|
||||
#ifndef STREQ
|
||||
#define STREQ(a, b) ((a)[0] == (b)[0] && strcmp(a, b) == 0)
|
||||
#define STREQN(a, b, n) ((a)[0] == (b)[0] && strncmp(a, b, n) == 0)
|
||||
#endif
|
||||
|
||||
/* We use strcoll(3) for range comparisons in bracket expressions,
|
||||
even though it can have unwanted side effects in locales
|
||||
other than POSIX or US. For instance, in the de locale, [A-Z] matches
|
||||
all characters. */
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
/* Helper function for collating symbol equivalence. */
|
||||
static int rangecmp (c1, c2)
|
||||
int c1, c2;
|
||||
{
|
||||
static char s1[2] = { ' ', '\0' };
|
||||
static char s2[2] = { ' ', '\0' };
|
||||
int ret;
|
||||
|
||||
/* Eight bits only. Period. */
|
||||
c1 &= 0xFF;
|
||||
c2 &= 0xFF;
|
||||
|
||||
if (c1 == c2)
|
||||
return (0);
|
||||
|
||||
s1[0] = c1;
|
||||
s2[0] = c2;
|
||||
|
||||
if ((ret = strcoll (s1, s2)) != 0)
|
||||
return ret;
|
||||
return (c1 - c2);
|
||||
}
|
||||
#else /* !HAVE_STRCOLL */
|
||||
# define rangecmp(c1, c2) ((int)(c1) - (int)(c2))
|
||||
#endif /* !HAVE_STRCOLL */
|
||||
|
||||
#if defined (HAVE_STRCOLL)
|
||||
static int collequiv (c1, c2)
|
||||
int c1, c2;
|
||||
{
|
||||
return (rangecmp (c1, c2) == 0);
|
||||
}
|
||||
#else
|
||||
# define collequiv(c1, c2) ((c1) == (c2))
|
||||
#endif
|
||||
|
||||
static int
|
||||
collsym (s, len)
|
||||
char *s;
|
||||
int len;
|
||||
{
|
||||
register struct _collsym *csp;
|
||||
|
||||
for (csp = posix_collsyms; csp->name; csp++)
|
||||
{
|
||||
if (STREQN(csp->name, s, len) && csp->name[len] == '\0')
|
||||
return (csp->code);
|
||||
}
|
||||
if (len == 1)
|
||||
return s[0];
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LIBC_FNM_EXTMATCH
|
||||
int
|
||||
strmatch (pattern, string, flags)
|
||||
char *pattern;
|
||||
char *string;
|
||||
int flags;
|
||||
{
|
||||
char *se, *pe;
|
||||
|
||||
if (string == 0 || pattern == 0)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
return (fnmatch (pattern, string, flags));
|
||||
return (xstrmatch (pattern, string, flags));
|
||||
}
|
||||
#else /* !HAVE_LIBC_FNM_EXTMATCH */
|
||||
int
|
||||
strmatch (pattern, string, flags)
|
||||
char *pattern;
|
||||
char *string;
|
||||
int flags;
|
||||
{
|
||||
char *se, *pe;
|
||||
|
||||
if (string == 0 || pattern == 0)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
se = string + strlen (string);
|
||||
pe = pattern + strlen (pattern);
|
||||
|
||||
return (gmatch (string, se, pattern, pe, flags));
|
||||
}
|
||||
#endif /* !HAVE_LIBC_FNM_EXTMATCH */
|
||||
|
||||
/* Match STRING against the filename pattern PATTERN, returning zero if
|
||||
it matches, FNM_NOMATCH if not. */
|
||||
static int
|
||||
gmatch (string, se, pattern, pe, flags)
|
||||
char *string, *se;
|
||||
char *pattern, *pe;
|
||||
int flags;
|
||||
{
|
||||
register char *p, *n; /* pattern, string */
|
||||
register char c; /* current pattern character */
|
||||
register char sc; /* current string character */
|
||||
|
||||
p = pattern;
|
||||
n = string;
|
||||
|
||||
if (string == 0 || pattern == 0)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
#if DEBUG_MATCHING
|
||||
fprintf(stderr, "gmatch: string = %s; se = %s\n", string, se);
|
||||
fprintf(stderr, "gmatch: pattern = %s; pe = %s\n", pattern, pe);
|
||||
#endif
|
||||
|
||||
while (p < pe)
|
||||
{
|
||||
c = *p++;
|
||||
c = FOLD (c);
|
||||
|
||||
sc = n < se ? *n : '\0';
|
||||
|
||||
#ifdef EXTENDED_GLOB
|
||||
/* extmatch () will handle recursively calling gmatch, so we can
|
||||
just return what extmatch() returns. */
|
||||
if ((flags & FNM_EXTMATCH) && *p == '(' &&
|
||||
(c == '+' || c == '*' || c == '?' || c == '@' || c == '!')) /* ) */
|
||||
{
|
||||
int lflags;
|
||||
/* If we're not matching the start of the string, we're not
|
||||
concerned about the special cases for matching `.' */
|
||||
lflags = (n == string) ? flags : (flags & ~FNM_PERIOD);
|
||||
return (extmatch (c, n, se, p, pe, lflags));
|
||||
}
|
||||
#endif
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '?': /* Match single character */
|
||||
if (sc == '\0')
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_PATHNAME) && sc == '/')
|
||||
/* If we are matching a pathname, `?' can never match a `/'. */
|
||||
return FNM_NOMATCH;
|
||||
else if ((flags & FNM_PERIOD) && sc == '.' &&
|
||||
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
|
||||
/* `?' cannot match a `.' if it is the first character of the
|
||||
string or if it is the first character following a slash and
|
||||
we are matching a pathname. */
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
case '\\': /* backslash escape removes special meaning */
|
||||
if (p == pe)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
if ((flags & FNM_NOESCAPE) == 0)
|
||||
{
|
||||
c = *p++;
|
||||
/* A trailing `\' cannot match. */
|
||||
if (p > pe)
|
||||
return FNM_NOMATCH;
|
||||
c = FOLD (c);
|
||||
}
|
||||
if (FOLD (sc) != (unsigned char)c)
|
||||
return FNM_NOMATCH;
|
||||
break;
|
||||
|
||||
case '*': /* Match zero or more characters */
|
||||
if (p == pe)
|
||||
return 0;
|
||||
|
||||
if ((flags & FNM_PERIOD) && sc == '.' &&
|
||||
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
|
||||
/* `*' cannot match a `.' if it is the first character of the
|
||||
string or if it is the first character following a slash and
|
||||
we are matching a pathname. */
|
||||
return FNM_NOMATCH;
|
||||
|
||||
/* Collapse multiple consecutive `*' and `?', but make sure that
|
||||
one character of the string is consumed for each `?'. */
|
||||
for (c = *p++; (c == '?' || c == '*'); c = *p++)
|
||||
{
|
||||
if ((flags & FNM_PATHNAME) && sc == '/')
|
||||
/* A slash does not match a wildcard under FNM_PATHNAME. */
|
||||
return FNM_NOMATCH;
|
||||
else if (c == '?')
|
||||
{
|
||||
if (sc == '\0')
|
||||
return FNM_NOMATCH;
|
||||
/* One character of the string is consumed in matching
|
||||
this ? wildcard, so *??? won't match if there are
|
||||
fewer than three characters. */
|
||||
n++;
|
||||
sc = n < se ? *n : '\0';
|
||||
}
|
||||
|
||||
#ifdef EXTENDED_GLOB
|
||||
/* Handle ******(patlist) */
|
||||
if ((flags & FNM_EXTMATCH) && c == '*' && *p == '(') /*)*/
|
||||
{
|
||||
char *newn;
|
||||
/* We need to check whether or not the extended glob
|
||||
pattern matches the remainder of the string.
|
||||
If it does, we match the entire pattern. */
|
||||
for (newn = n; newn < se; ++newn)
|
||||
{
|
||||
if (extmatch (c, newn, se, p, pe, flags) == 0)
|
||||
return (0);
|
||||
}
|
||||
/* We didn't match the extended glob pattern, but
|
||||
that's OK, since we can match 0 or more occurrences.
|
||||
We need to skip the glob pattern and see if we
|
||||
match the rest of the string. */
|
||||
newn = patscan (p + 1, pe, 0);
|
||||
/* If NEWN is 0, we have an ill-formed pattern. */
|
||||
p = newn ? newn : pe;
|
||||
}
|
||||
#endif
|
||||
if (p == pe)
|
||||
break;
|
||||
}
|
||||
|
||||
/* If we've hit the end of the pattern and the last character of
|
||||
the pattern was handled by the loop above, we've succeeded.
|
||||
Otherwise, we need to match that last character. */
|
||||
if (p == pe && (c == '?' || c == '*'))
|
||||
return (0);
|
||||
|
||||
/* General case, use recursion. */
|
||||
{
|
||||
unsigned char c1;
|
||||
|
||||
c1 = (unsigned char)((flags & FNM_NOESCAPE) == 0 && c == '\\') ? *p : c;
|
||||
c1 = FOLD (c1);
|
||||
for (--p; n < se; ++n)
|
||||
{
|
||||
/* Only call strmatch if the first character indicates a
|
||||
possible match. We can check the first character if
|
||||
we're not doing an extended glob match. */
|
||||
if ((flags & FNM_EXTMATCH) == 0 && c != '[' && FOLD (*n) != c1) /*]*/
|
||||
continue;
|
||||
|
||||
/* If we're doing an extended glob match and the pattern is not
|
||||
one of the extended glob patterns, we can check the first
|
||||
character. */
|
||||
if ((flags & FNM_EXTMATCH) && p[1] != '(' && /*)*/
|
||||
strchr ("?*+@!", *p) == 0 && c != '[' && FOLD (*n) != c1) /*]*/
|
||||
continue;
|
||||
|
||||
/* Otherwise, we just recurse. */
|
||||
if (gmatch (n, se, p, pe, flags & ~FNM_PERIOD) == 0)
|
||||
return (0);
|
||||
}
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
|
||||
case '[':
|
||||
{
|
||||
if (sc == '\0' || n == se)
|
||||
return FNM_NOMATCH;
|
||||
|
||||
/* A character class cannot match a `.' if it is the first
|
||||
character of the string or if it is the first character
|
||||
following a slash and we are matching a pathname. */
|
||||
if ((flags & FNM_PERIOD) && sc == '.' &&
|
||||
(n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
p = brackmatch (p, sc, flags);
|
||||
if (p == 0)
|
||||
return FNM_NOMATCH;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((unsigned char)c != FOLD (sc))
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
++n;
|
||||
}
|
||||
|
||||
if (n == se)
|
||||
return (0);
|
||||
|
||||
if ((flags & FNM_LEADING_DIR) && *n == '/')
|
||||
/* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
|
||||
return 0;
|
||||
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
/* Parse a bracket expression collating symbol ([.sym.]) starting at P, find
|
||||
the value of the symbol, and move P past the collating symbol expression.
|
||||
The value is returned in *VP, if VP is not null. */
|
||||
static char *
|
||||
parse_collsym (p, vp)
|
||||
char *p;
|
||||
int *vp;
|
||||
{
|
||||
register int pc;
|
||||
int val;
|
||||
|
||||
p++; /* move past the `.' */
|
||||
|
||||
for (pc = 0; p[pc]; pc++)
|
||||
if (p[pc] == '.' && p[pc+1] == ']')
|
||||
break;
|
||||
val = collsym (p, pc);
|
||||
if (vp)
|
||||
*vp = val;
|
||||
return (p + pc + 2);
|
||||
}
|
||||
|
||||
static char *
|
||||
brackmatch (p, test, flags)
|
||||
char *p;
|
||||
unsigned char test;
|
||||
int flags;
|
||||
{
|
||||
register char cstart, cend, c;
|
||||
register int not; /* Nonzero if the sense of the character class is inverted. */
|
||||
int pc, brcnt;
|
||||
char *savep;
|
||||
|
||||
test = FOLD (test);
|
||||
|
||||
savep = p;
|
||||
|
||||
/* POSIX.2 3.13.1 says that an exclamation mark (`!') shall replace the
|
||||
circumflex (`^') in its role in a `nonmatching list'. A bracket
|
||||
expression starting with an unquoted circumflex character produces
|
||||
unspecified results. This implementation treats the two identically. */
|
||||
if (not = (*p == '!' || *p == '^'))
|
||||
++p;
|
||||
|
||||
c = *p++;
|
||||
for (;;)
|
||||
{
|
||||
/* Initialize cstart and cend in case `-' is the last
|
||||
character of the pattern. */
|
||||
cstart = cend = c;
|
||||
|
||||
/* POSIX.2 equivalence class: [=c=]. See POSIX.2 2.8.3.2. Find
|
||||
the end of the equivalence class, move the pattern pointer past
|
||||
it, and check for equivalence. XXX - this handles only
|
||||
single-character equivalence classes, which is wrong, or at
|
||||
least incomplete. */
|
||||
if (c == '[' && *p == '=' && p[2] == '=' && p[3] == ']')
|
||||
{
|
||||
pc = FOLD (p[1]);
|
||||
p += 4;
|
||||
if (collequiv (test, pc))
|
||||
{
|
||||
/*[*/ /* Move past the closing `]', since the first thing we do at
|
||||
the `matched:' label is back p up one. */
|
||||
p++;
|
||||
goto matched;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = *p++;
|
||||
if (c == '\0')
|
||||
return ((test == '[') ? savep : (char *)0); /*]*/
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* POSIX.2 character class expression. See POSIX.2 2.8.3.2. */
|
||||
if (c == '[' && *p == ':') /*]*/
|
||||
{
|
||||
pc = 0; /* make sure invalid char classes don't match. */
|
||||
if (STREQN (p+1, "alnum:]", 7))
|
||||
{ pc = ISALNUM (test); p += 8; }
|
||||
else if (STREQN (p+1, "alpha:]", 7))
|
||||
{ pc = ISALPHA (test); p += 8; }
|
||||
else if (STREQN (p+1, "blank:]", 7))
|
||||
{ pc = ISBLANK (test); p += 8; }
|
||||
else if (STREQN (p+1, "cntrl:]", 7))
|
||||
{ pc = ISCNTRL (test); p += 8; }
|
||||
else if (STREQN (p+1, "digit:]", 7))
|
||||
{ pc = ISDIGIT (test); p += 8; }
|
||||
else if (STREQN (p+1, "graph:]", 7))
|
||||
{ pc = ISGRAPH (test); p += 8; }
|
||||
else if (STREQN (p+1, "lower:]", 7))
|
||||
{ pc = ISLOWER (test); p += 8; }
|
||||
else if (STREQN (p+1, "print:]", 7))
|
||||
{ pc = ISPRINT (test); p += 8; }
|
||||
else if (STREQN (p+1, "punct:]", 7))
|
||||
{ pc = ISPUNCT (test); p += 8; }
|
||||
else if (STREQN (p+1, "space:]", 7))
|
||||
{ pc = ISSPACE (test); p += 8; }
|
||||
else if (STREQN (p+1, "upper:]", 7))
|
||||
{ pc = ISUPPER (test); p += 8; }
|
||||
else if (STREQN (p+1, "xdigit:]", 8))
|
||||
{ pc = ISXDIGIT (test); p += 9; }
|
||||
else if (STREQN (p+1, "ascii:]", 7))
|
||||
{ pc = isascii (test); p += 8; }
|
||||
if (pc)
|
||||
{
|
||||
/*[*/ /* Move past the closing `]', since the first thing we do at
|
||||
the `matched:' label is back p up one. */
|
||||
p++;
|
||||
goto matched;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* continue the loop here, since this expression can't be
|
||||
the first part of a range expression. */
|
||||
c = *p++;
|
||||
if (c == '\0')
|
||||
return ((test == '[') ? savep : (char *)0);
|
||||
else if (c == ']')
|
||||
break;
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* POSIX.2 collating symbols. See POSIX.2 2.8.3.2. Find the end of
|
||||
the symbol name, make sure it is terminated by `.]', translate
|
||||
the name to a character using the external table, and do the
|
||||
comparison. */
|
||||
if (c == '[' && *p == '.')
|
||||
{
|
||||
p = parse_collsym (p, &pc);
|
||||
/* An invalid collating symbol cannot be the first point of a
|
||||
range. If it is, we set cstart to one greater than `test',
|
||||
so any comparisons later will fail. */
|
||||
cstart = (pc == -1) ? test + 1 : pc;
|
||||
}
|
||||
|
||||
if (!(flags & FNM_NOESCAPE) && c == '\\')
|
||||
{
|
||||
if (*p == '\0')
|
||||
return (char *)0;
|
||||
cstart = cend = *p++;
|
||||
}
|
||||
|
||||
cstart = cend = FOLD (cstart);
|
||||
|
||||
/* POSIX.2 2.8.3.1.2 says: `An expression containing a `[' that
|
||||
is not preceded by a backslash and is not part of a bracket
|
||||
expression produces undefined results.' This implementation
|
||||
treats the `[' as just a character to be matched if there is
|
||||
not a closing `]'. */
|
||||
if (c == '\0')
|
||||
return ((test == '[') ? savep : (char *)0);
|
||||
|
||||
c = *p++;
|
||||
c = FOLD (c);
|
||||
|
||||
if ((flags & FNM_PATHNAME) && c == '/')
|
||||
/* [/] can never match when matching a pathname. */
|
||||
return (char *)0;
|
||||
|
||||
/* This introduces a range, unless the `-' is the last
|
||||
character of the class. Find the end of the range
|
||||
and move past it. */
|
||||
if (c == '-' && *p != ']')
|
||||
{
|
||||
cend = *p++;
|
||||
if (!(flags & FNM_NOESCAPE) && cend == '\\')
|
||||
cend = *p++;
|
||||
if (cend == '\0')
|
||||
return (char *)0;
|
||||
if (cend == '[' && *p == '.')
|
||||
{
|
||||
p = parse_collsym (p, &pc);
|
||||
/* An invalid collating symbol cannot be the second part of a
|
||||
range expression. If we get one, we set cend to one fewer
|
||||
than the test character to make sure the range test fails. */
|
||||
cend = (pc == -1) ? test - 1 : pc;
|
||||
}
|
||||
cend = FOLD (cend);
|
||||
|
||||
c = *p++;
|
||||
|
||||
/* POSIX.2 2.8.3.2: ``The ending range point shall collate
|
||||
equal to or higher than the starting range point; otherwise
|
||||
the expression shall be treated as invalid.'' Note that this
|
||||
applies to only the range expression; the rest of the bracket
|
||||
expression is still checked for matches. */
|
||||
if (rangecmp (cstart, cend) > 0)
|
||||
{
|
||||
if (c == ']')
|
||||
break;
|
||||
c = FOLD (c);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (rangecmp (test, cstart) >= 0 && rangecmp (test, cend) <= 0)
|
||||
goto matched;
|
||||
|
||||
if (c == ']')
|
||||
break;
|
||||
}
|
||||
/* No match. */
|
||||
return (!not ? (char *)0 : p);
|
||||
|
||||
matched:
|
||||
/* Skip the rest of the [...] that already matched. */
|
||||
#if 0
|
||||
brcnt = (c != ']') + (c == '[' && (*p == '=' || *p == ':' || *p == '.'));
|
||||
#else
|
||||
c = *--p;
|
||||
brcnt = 1;
|
||||
#endif
|
||||
while (brcnt > 0)
|
||||
{
|
||||
/* A `[' without a matching `]' is just another character to match. */
|
||||
if (c == '\0')
|
||||
return ((test == '[') ? savep : (char *)0);
|
||||
|
||||
c = *p++;
|
||||
if (c == '[' && (*p == '=' || *p == ':' || *p == '.'))
|
||||
brcnt++;
|
||||
else if (c == ']')
|
||||
brcnt--;
|
||||
else if (!(flags & FNM_NOESCAPE) && c == '\\')
|
||||
{
|
||||
if (*p == '\0')
|
||||
return (char *)0;
|
||||
/* XXX 1003.2d11 is unclear if this is right. */
|
||||
++p;
|
||||
}
|
||||
}
|
||||
return (not ? (char *)0 : p);
|
||||
}
|
||||
|
||||
#if defined (EXTENDED_GLOB)
|
||||
/* ksh-like extended pattern matching:
|
||||
|
||||
[?*+@!](pat-list)
|
||||
|
||||
where pat-list is a list of one or patterns separated by `|'. Operation
|
||||
is as follows:
|
||||
|
||||
?(patlist) match zero or one of the given patterns
|
||||
*(patlist) match zero or more of the given patterns
|
||||
+(patlist) match one or more of the given patterns
|
||||
@(patlist) match exactly one of the given patterns
|
||||
!(patlist) match anything except one of the given patterns
|
||||
*/
|
||||
|
||||
/* Scan a pattern starting at STRING and ending at END, keeping track of
|
||||
embedded () and []. If DELIM is 0, we scan until a matching `)'
|
||||
because we're scanning a `patlist'. Otherwise, we scan until we see
|
||||
DELIM. In all cases, we never scan past END. The return value is the
|
||||
first character after the matching DELIM. */
|
||||
static char *
|
||||
patscan (string, end, delim)
|
||||
char *string, *end;
|
||||
int delim;
|
||||
{
|
||||
int pnest, bnest, cchar;
|
||||
char *s, c, *bfirst;
|
||||
|
||||
pnest = bnest = cchar = 0;
|
||||
bfirst = 0;
|
||||
for (s = string; c = *s; s++)
|
||||
{
|
||||
if (s >= end)
|
||||
return (s);
|
||||
switch (c)
|
||||
{
|
||||
case '\0':
|
||||
return ((char *)0);
|
||||
|
||||
/* `[' is not special inside a bracket expression, but it may
|
||||
introduce one of the special POSIX bracket expressions
|
||||
([.SYM.], [=c=], [: ... :]) that needs special handling. */
|
||||
case '[':
|
||||
if (bnest == 0)
|
||||
{
|
||||
bfirst = s + 1;
|
||||
if (*bfirst == '!' || *bfirst == '^')
|
||||
bfirst++;
|
||||
bnest++;
|
||||
}
|
||||
else if (s[1] == ':' || s[1] == '.' || s[1] == '=')
|
||||
cchar = s[1];
|
||||
break;
|
||||
|
||||
/* `]' is not special if it's the first char (after a leading `!'
|
||||
or `^') in a bracket expression or if it's part of one of the
|
||||
special POSIX bracket expressions ([.SYM.], [=c=], [: ... :]) */
|
||||
case ']':
|
||||
if (bnest)
|
||||
{
|
||||
if (cchar && s[-1] == cchar)
|
||||
cchar = 0;
|
||||
else if (s != bfirst)
|
||||
{
|
||||
bnest--;
|
||||
bfirst = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case '(':
|
||||
if (bnest == 0)
|
||||
pnest++;
|
||||
break;
|
||||
|
||||
case ')':
|
||||
#if 0
|
||||
if (bnest == 0)
|
||||
pnest--;
|
||||
if (pnest <= 0)
|
||||
return ++s;
|
||||
#else
|
||||
if (bnest == 0 && pnest-- <= 0)
|
||||
return ++s;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case '|':
|
||||
if (bnest == 0 && pnest == 0 && delim == '|')
|
||||
return ++s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (char *)0;
|
||||
}
|
||||
|
||||
/* Return 0 if dequoted pattern matches S in the current locale. */
|
||||
static int
|
||||
strcompare (p, pe, s, se)
|
||||
char *p, *pe, *s, *se;
|
||||
{
|
||||
int ret;
|
||||
char c1, c2;
|
||||
|
||||
c1 = *pe;
|
||||
c2 = *se;
|
||||
|
||||
*pe = *se = '\0';
|
||||
#if defined (HAVE_STRCOLL)
|
||||
ret = strcoll (p, s);
|
||||
#else
|
||||
ret = strcmp (p, s);
|
||||
#endif
|
||||
|
||||
*pe = c1;
|
||||
*se = c2;
|
||||
|
||||
return (ret == 0 ? ret : FNM_NOMATCH);
|
||||
}
|
||||
|
||||
/* Match a ksh extended pattern specifier. Return FNM_NOMATCH on failure or
|
||||
0 on success. This is handed the entire rest of the pattern and string
|
||||
the first time an extended pattern specifier is encountered, so it calls
|
||||
gmatch recursively. */
|
||||
static int
|
||||
extmatch (xc, s, se, p, pe, flags)
|
||||
int xc; /* select which operation */
|
||||
char *s, *se;
|
||||
char *p, *pe;
|
||||
int flags;
|
||||
{
|
||||
char *prest; /* pointer to rest of pattern */
|
||||
char *psub; /* pointer to sub-pattern */
|
||||
char *pnext; /* pointer to next sub-pattern */
|
||||
char *srest; /* pointer to rest of string */
|
||||
int m1, m2;
|
||||
|
||||
#if DEBUG_MATCHING
|
||||
fprintf(stderr, "extmatch: xc = %c\n", xc);
|
||||
fprintf(stderr, "extmatch: s = %s; se = %s\n", s, se);
|
||||
fprintf(stderr, "extmatch: p = %s; pe = %s\n", p, pe);
|
||||
#endif
|
||||
|
||||
prest = patscan (p + (*p == '('), pe, 0); /* ) */
|
||||
if (prest == 0)
|
||||
/* If PREST is 0, we failed to scan a valid pattern. In this
|
||||
case, we just want to compare the two as strings. */
|
||||
return (strcompare (p - 1, pe, s, se));
|
||||
|
||||
switch (xc)
|
||||
{
|
||||
case '+': /* match one or more occurrences */
|
||||
case '*': /* match zero or more occurrences */
|
||||
/* If we can get away with no matches, don't even bother. Just
|
||||
call gmatch on the rest of the pattern and return success if
|
||||
it succeeds. */
|
||||
if (xc == '*' && (gmatch (s, se, prest, pe, flags) == 0))
|
||||
return 0;
|
||||
|
||||
/* OK, we have to do this the hard way. First, we make sure one of
|
||||
the subpatterns matches, then we try to match the rest of the
|
||||
string. */
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = patscan (psub, pe, '|');
|
||||
for (srest = s; srest <= se; srest++)
|
||||
{
|
||||
/* Match this substring (S -> SREST) against this
|
||||
subpattern (psub -> pnext - 1) */
|
||||
m1 = gmatch (s, srest, psub, pnext - 1, flags) == 0;
|
||||
/* OK, we matched a subpattern, so make sure the rest of the
|
||||
string matches the rest of the pattern. Also handle
|
||||
multiple matches of the pattern. */
|
||||
if (m1)
|
||||
m2 = (gmatch (srest, se, prest, pe, flags) == 0) ||
|
||||
(s != srest && gmatch (srest, se, p - 1, pe, flags) == 0);
|
||||
if (m1 && m2)
|
||||
return (0);
|
||||
}
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
case '?': /* match zero or one of the patterns */
|
||||
case '@': /* match exactly one of the patterns */
|
||||
/* If we can get away with no matches, don't even bother. Just
|
||||
call gmatch on the rest of the pattern and return success if
|
||||
it succeeds. */
|
||||
if (xc == '?' && (gmatch (s, se, prest, pe, flags) == 0))
|
||||
return 0;
|
||||
|
||||
/* OK, we have to do this the hard way. First, we see if one of
|
||||
the subpatterns matches, then, if it does, we try to match the
|
||||
rest of the string. */
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = patscan (psub, pe, '|');
|
||||
srest = (prest == pe) ? se : s;
|
||||
for ( ; srest <= se; srest++)
|
||||
{
|
||||
if (gmatch (s, srest, psub, pnext - 1, flags) == 0 &&
|
||||
gmatch (srest, se, prest, pe, flags) == 0)
|
||||
return (0);
|
||||
}
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
case '!': /* match anything *except* one of the patterns */
|
||||
for (srest = s; srest <= se; srest++)
|
||||
{
|
||||
m1 = 0;
|
||||
for (psub = p + 1; ; psub = pnext)
|
||||
{
|
||||
pnext = patscan (psub, pe, '|');
|
||||
/* If one of the patterns matches, just bail immediately. */
|
||||
if (m1 = (gmatch (s, srest, psub, pnext - 1, flags) == 0))
|
||||
break;
|
||||
if (pnext == prest)
|
||||
break;
|
||||
}
|
||||
if (m1 == 0 && gmatch (srest, se, prest, pe, flags) == 0)
|
||||
return (0);
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
#endif /* EXTENDED_GLOB */
|
||||
|
||||
#ifdef TEST
|
||||
main (c, v)
|
||||
|
|
|
|||
116
lib/glob/xmbsrtowcs.c
Normal file
116
lib/glob/xmbsrtowcs.c
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/* xmbsrtowcs.c -- replacement function for mbsrtowcs */
|
||||
|
||||
/* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
#include <config.h>
|
||||
|
||||
#include <bashansi.h>
|
||||
|
||||
/* <wchar.h>, <wctype.h> and <stdlib.h> are included in "shmbutil.h".
|
||||
If <wchar.h>, <wctype.h>, mbsrtowcs(), exist, HANDLE_MULTIBYTE
|
||||
is defined as 1. */
|
||||
#include <shmbutil.h>
|
||||
|
||||
#if HANDLE_MULTIBYTE
|
||||
/* On some locales (ex. ja_JP.sjis), mbsrtowc doesn't convert 0x5c to U<0x5c>.
|
||||
So, this function is made for converting 0x5c to U<0x5c>. */
|
||||
|
||||
static mbstate_t local_state;
|
||||
static int local_state_use = 0;
|
||||
|
||||
size_t
|
||||
xmbsrtowcs (dest, src, len, pstate)
|
||||
wchar_t *dest;
|
||||
const char **src;
|
||||
size_t len;
|
||||
mbstate_t *pstate;
|
||||
{
|
||||
mbstate_t *ps;
|
||||
size_t mblength, wclength, n;
|
||||
|
||||
ps = pstate;
|
||||
if (pstate == NULL)
|
||||
{
|
||||
if (!local_state_use)
|
||||
{
|
||||
memset (&local_state, '\0', sizeof(mbstate_t));
|
||||
local_state_use = 1;
|
||||
}
|
||||
ps = &local_state;
|
||||
}
|
||||
|
||||
n = strlen(*src) + 1;
|
||||
|
||||
if (dest == NULL)
|
||||
{
|
||||
wchar_t *wsbuf;
|
||||
char *mbsbuf, *mbsbuf_top;
|
||||
mbstate_t psbuf;
|
||||
|
||||
wsbuf = (wchar_t *) malloc ((n + 1) * sizeof(wchar_t));
|
||||
mbsbuf_top = mbsbuf = (char *) malloc (n + 1);
|
||||
memcpy(mbsbuf, *src, n + 1);
|
||||
psbuf = *ps;
|
||||
|
||||
wclength = mbsrtowcs (wsbuf, (const char **)&mbsbuf, n, &psbuf);
|
||||
|
||||
free (wsbuf);
|
||||
free (mbsbuf_top);
|
||||
return wclength;
|
||||
}
|
||||
|
||||
for(wclength = 0; wclength < len; wclength++, dest++)
|
||||
{
|
||||
if(mbsinit(ps))
|
||||
{
|
||||
if (**src == '\0')
|
||||
{
|
||||
*dest = L'\0';
|
||||
*src = NULL;
|
||||
return (wclength);
|
||||
}
|
||||
else if (**src == '\\')
|
||||
{
|
||||
*dest = L'\\';
|
||||
mblength = 1;
|
||||
}
|
||||
else
|
||||
mblength = mbrtowc(dest, *src, n, ps);
|
||||
}
|
||||
else
|
||||
mblength = mbrtowc(dest, *src, n, ps);
|
||||
|
||||
/* Cannot convert multibyte character to wide character. */
|
||||
if (mblength == (size_t)-1 || mblength == (size_t)-2)
|
||||
return (size_t)-1;
|
||||
|
||||
*src += mblength;
|
||||
n -= mblength;
|
||||
|
||||
/* The multibyte string has been completely converted,
|
||||
including the terminating '\0'. */
|
||||
if (*dest == L'\0')
|
||||
{
|
||||
*src = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (wclength);
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
|
@ -36,7 +36,7 @@ MV = mv
|
|||
|
||||
SHELL = @MAKE_SHELL@
|
||||
|
||||
PROFILE_FLAGS =
|
||||
PROFILE_FLAGS = @PROFILE_FLAGS@
|
||||
|
||||
CFLAGS = @CFLAGS@
|
||||
LOCAL_CFLAGS = @LOCAL_CFLAGS@
|
||||
|
|
@ -69,7 +69,7 @@ MALLOC_SRC = @MALLOC_SRC@
|
|||
MALLOC = @MALLOC@
|
||||
ALLOCA = @ALLOCA@
|
||||
|
||||
MALLOC_OBJS = malloc.o $(ALLOCA) trace.o stats.o table.o
|
||||
MALLOC_OBJS = malloc.o $(ALLOCA) trace.o stats.o table.o watch.o
|
||||
STUB_OBJS = $(ALLOCA) stub.o
|
||||
|
||||
.PHONY: malloc stubmalloc
|
||||
|
|
@ -110,9 +110,11 @@ trace.o: ${BUILD_DIR}/config.h
|
|||
table.o: ${BUILD_DIR}/config.h
|
||||
|
||||
malloc.o: ${srcdir}/imalloc.h ${srcdir}/mstats.h
|
||||
malloc.o: ${srcdir}/table.h ${srcdir}/watch.h
|
||||
stats.o: ${srcdir}/imalloc.h ${srcdir}/mstats.h
|
||||
trace.o: ${srcdir}/imalloc.h
|
||||
table.o: ${srcdir}/imalloc.h ${srcdir}/table.h
|
||||
watch.o: ${srcdir}/imalloc.h ${srcdir}/watch.h
|
||||
|
||||
# Rules for deficient makes, like SunOS and Solaris
|
||||
stub.o: stub.c
|
||||
|
|
@ -120,3 +122,4 @@ malloc.o: malloc.c
|
|||
table.o: table.c
|
||||
trace.o: trace.c
|
||||
stats.o: stats.c
|
||||
watch.o: watch.c
|
||||
|
|
|
|||
|
|
@ -20,15 +20,18 @@
|
|||
|
||||
/* Must be included *after* config.h */
|
||||
|
||||
#ifndef _IMALLOC_H_
|
||||
#ifndef _IMALLOC_H
|
||||
#define _IMALLOC_H
|
||||
|
||||
#ifdef MALLOC_DEBUG
|
||||
#define MALLOC_STATS
|
||||
#define MALLOC_TRACE
|
||||
#define MALLOC_REGISTER
|
||||
#define MALLOC_WATCH
|
||||
#endif
|
||||
|
||||
#define MALLOC_WRAPFUNCS
|
||||
|
||||
/* Generic pointer type. */
|
||||
#ifndef PTR_T
|
||||
# if defined (__STDC__)
|
||||
|
|
@ -64,4 +67,96 @@
|
|||
# endif /* HAVE_BCOPY */
|
||||
#endif /* !__GNUC__ */
|
||||
|
||||
#if !defined (__P)
|
||||
# if defined (__STDC__) || defined (__GNUC__) || defined (__cplusplus) || defined (PROTOTYPES)
|
||||
# define __P(protos) protos
|
||||
# else
|
||||
# define __P(protos) ()
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Use Duff's device for good zeroing/copying performance. DO NOT call the
|
||||
Duff's device macros with NBYTES == 0. */
|
||||
|
||||
#define MALLOC_BZERO(charp, nbytes) \
|
||||
do { \
|
||||
if ((nbytes) <= 32) { \
|
||||
size_t * mzp = (size_t *)(charp); \
|
||||
unsigned long mctmp = (nbytes)/sizeof(size_t); \
|
||||
long mcn; \
|
||||
if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp &= 7; } \
|
||||
switch (mctmp) { \
|
||||
case 0: for(;;) { *mzp++ = 0; \
|
||||
case 7: *mzp++ = 0; \
|
||||
case 6: *mzp++ = 0; \
|
||||
case 5: *mzp++ = 0; \
|
||||
case 4: *mzp++ = 0; \
|
||||
case 3: *mzp++ = 0; \
|
||||
case 2: *mzp++ = 0; \
|
||||
case 1: *mzp++ = 0; if(mcn <= 0) break; mcn--; } \
|
||||
} \
|
||||
else \
|
||||
memset ((charp), 0, (nbytes)); \
|
||||
} while(0)
|
||||
|
||||
#define MALLOC_ZERO(charp, nbytes) \
|
||||
do { \
|
||||
size_t mzsz = (nbytes); \
|
||||
if (mzsz <= 9 * sizeof(mzsz) { \
|
||||
size_t *mz = (size_t *)(charp); \
|
||||
if(mzsz >= 5*sizeof(mzsz)) { *mz++ = 0; \
|
||||
*mz++ = 0; \
|
||||
if(mzsz >= 7*sizeof(mzsz)) { *mz++ = 0; \
|
||||
*mz++ = 0; \
|
||||
if(mzsz >= 9*sizeof(mzsz)) { *mz++ = 0; \
|
||||
*mz++ = 0; }}} \
|
||||
*mz++ = 0; \
|
||||
*mz++ = 0; \
|
||||
*mz = 0; \
|
||||
} else \
|
||||
memset ((charp), 0, mzsz); \
|
||||
} while (0)
|
||||
|
||||
#define MALLOC_MEMSET(charp, xch, nbytes) \
|
||||
do { \
|
||||
if ((nbytes) <= 32) { \
|
||||
register char * mzp = (charp); \
|
||||
unsigned long mctmp = (nbytes); \
|
||||
register long mcn; \
|
||||
if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp &= 7; } \
|
||||
switch (mctmp) { \
|
||||
case 0: for(;;) { *mzp++ = xch; \
|
||||
case 7: *mzp++ = xch; \
|
||||
case 6: *mzp++ = xch; \
|
||||
case 5: *mzp++ = xch; \
|
||||
case 4: *mzp++ = xch; \
|
||||
case 3: *mzp++ = xch; \
|
||||
case 2: *mzp++ = xch; \
|
||||
case 1: *mzp++ = xch; if(mcn <= 0) break; mcn--; } \
|
||||
} \
|
||||
} else \
|
||||
memset ((charp), (xch), (nbytes)); \
|
||||
} while(0)
|
||||
|
||||
#define MALLOC_MEMCPY(dest,src,nbytes) \
|
||||
do { \
|
||||
if ((nbytes) <= 32) { \
|
||||
size_t* mcsrc = (size_t*) src; \
|
||||
size_t* mcdst = (size_t*) dest; \
|
||||
unsigned long mctmp = (nbytes)/sizeof(size_t); \
|
||||
long mcn; \
|
||||
if (mctmp < 8) mcn = 0; else { mcn = (mctmp-1)/8; mctmp &= 7; } \
|
||||
switch (mctmp) { \
|
||||
case 0: for(;;) { *mcdst++ = *mcsrc++; \
|
||||
case 7: *mcdst++ = *mcsrc++; \
|
||||
case 6: *mcdst++ = *mcsrc++; \
|
||||
case 5: *mcdst++ = *mcsrc++; \
|
||||
case 4: *mcdst++ = *mcsrc++; \
|
||||
case 3: *mcdst++ = *mcsrc++; \
|
||||
case 2: *mcdst++ = *mcsrc++; \
|
||||
case 1: *mcdst++ = *mcsrc++; if(mcn <= 0) break; mcn--; } \
|
||||
} else \
|
||||
memcpy ((dest), (src), (nbytes)) \
|
||||
} while(0)
|
||||
|
||||
#endif /* _IMALLOC_H */
|
||||
|
|
|
|||
|
|
@ -53,12 +53,12 @@ what you give them. Help stamp out software-hoarding! */
|
|||
* to the second.
|
||||
*/
|
||||
|
||||
/* Define this to have free() write 0xcf into memory as it's freed, to
|
||||
uncover callers that refer to freed memory. */
|
||||
/* SCO 3.2v4 getcwd and possibly other libc routines fail with MEMSCRAMBLE */
|
||||
#if !defined (NO_MEMSCRAMBLE)
|
||||
# define MEMSCRAMBLE
|
||||
#endif
|
||||
/* Define MEMSCRAMBLE to have free() write 0xcf into memory as it's freed, to
|
||||
uncover callers that refer to freed memory, and to have malloc() write 0xdf
|
||||
into memory as it's allocated to avoid referring to previous contents. */
|
||||
|
||||
/* SCO 3.2v4 getcwd and possibly other libc routines fail with MEMSCRAMBLE;
|
||||
handled by configure. */
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
|
|
@ -69,15 +69,6 @@ what you give them. Help stamp out software-hoarding! */
|
|||
# include "stdc.h"
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
|
||||
# ifndef __P
|
||||
# if defined (__STDC__) || defined (__GNUC__) || defined (__cplusplus)
|
||||
# define __P(protos) protos
|
||||
# else
|
||||
# define __P(protos) ()
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
|
|
@ -107,6 +98,9 @@ what you give them. Help stamp out software-hoarding! */
|
|||
#ifdef MALLOC_REGISTER
|
||||
# include "table.h"
|
||||
#endif
|
||||
#ifdef MALLOC_WATCH
|
||||
# include "watch.h"
|
||||
#endif
|
||||
|
||||
/* System-specific omissions. */
|
||||
#ifdef HPUX
|
||||
|
|
@ -145,6 +139,14 @@ union mhead {
|
|||
#define mh_nbytes minfo.mi_nbytes
|
||||
#define mh_magic2 minfo.mi_magic2
|
||||
|
||||
#define MOVERHEAD sizeof(union mhead)
|
||||
#define MALIGN_MASK 7 /* one less than desired alignment */
|
||||
|
||||
typedef union _malloc_guard {
|
||||
char s[4];
|
||||
u_bits32_t i;
|
||||
} mguard_t;
|
||||
|
||||
/* Access free-list pointer of a block.
|
||||
It is stored at block + sizeof (char *).
|
||||
This is not a field in the minfo structure member of union mhead
|
||||
|
|
@ -159,16 +161,15 @@ union mhead {
|
|||
and end of each allocated block, and make sure they are undisturbed
|
||||
whenever a free or a realloc occurs. */
|
||||
|
||||
/* Written in each of the 4 bytes following the block's real space */
|
||||
#define MAGIC1 0x55
|
||||
/* Written in the 2 bytes before the block's real space (-4 bytes) */
|
||||
#define MAGIC2 0x5555
|
||||
#define MSLOP 4 /* 4 bytes extra for MAGIC1s */
|
||||
#define MSLOP 4 /* 4 bytes extra for u_bits32_t size */
|
||||
|
||||
/* How many bytes are actually allocated for a request of size N --
|
||||
rounded up to nearest multiple of 8 after accounting for malloc
|
||||
overhead. */
|
||||
#define ALLOCATED_BYTES(n) (((n) + sizeof (union mhead) + MSLOP + 7) & ~7)
|
||||
#define ALLOCATED_BYTES(n) \
|
||||
(((n) + MOVERHEAD + MSLOP + MALIGN_MASK) & ~MALIGN_MASK)
|
||||
|
||||
#define ASSERT(p) \
|
||||
do \
|
||||
|
|
@ -179,15 +180,18 @@ union mhead {
|
|||
|
||||
/* Minimum and maximum bucket indices for block splitting (and to bound
|
||||
the search for a block to split). */
|
||||
#define SPLIT_MIN 3
|
||||
#define SPLIT_MID 11 /* XXX - was 9 */
|
||||
#define SPLIT_MAX 14 /* XXX - was 12 */
|
||||
#define SPLIT_MIN 2 /* XXX - was 3 */
|
||||
#define SPLIT_MID 11
|
||||
#define SPLIT_MAX 14
|
||||
|
||||
/* Minimum and maximum bucket indices for block coalescing. */
|
||||
#define COMBINE_MIN 6
|
||||
#define COMBINE_MAX (pagebucket - 1)
|
||||
#define COMBINE_MIN 2
|
||||
#define COMBINE_MAX (pagebucket - 1) /* XXX */
|
||||
|
||||
#define MIN_COMBINE_FREE 4
|
||||
#define LESSCORE_MIN 10
|
||||
#define LESSCORE_FRC 13
|
||||
|
||||
#define STARTBUCK 1
|
||||
|
||||
/* Flags for the internal functions. */
|
||||
#define MALLOC_WRAPPER 0x01 /* wrapper function */
|
||||
|
|
@ -202,9 +206,16 @@ union mhead {
|
|||
#define ERR_ASSERT_FAILED 0x08
|
||||
|
||||
/* Evaluates to true if NB is appropriate for bucket NU. NB is adjusted
|
||||
appropriately by the caller to account for malloc overhead. */
|
||||
#define IN_BUCKET(nb, nu) \
|
||||
((nb) > (4 << (nu)) && ((nb) <= (8 << (nu))))
|
||||
appropriately by the caller to account for malloc overhead. This only
|
||||
checks that the recorded size is not too big for the bucket. We
|
||||
can't check whether or not it's in between NU and NU-1 because we
|
||||
might have encountered a busy bucket when allocating and moved up to
|
||||
the next size. */
|
||||
#define IN_BUCKET(nb, nu) ((nb) <= binsizes[(nu)])
|
||||
|
||||
/* Use this when we want to be sure that NB is in bucket NU. */
|
||||
#define RIGHT_BUCKET(nb, nu) \
|
||||
(((nb) > binsizes[(nu)-1]) && ((nb) <= binsizes[(nu)]))
|
||||
|
||||
/* nextf[i] is free list of blocks of size 2**(i + 3) */
|
||||
|
||||
|
|
@ -218,6 +229,19 @@ static int pagesz; /* system page size. */
|
|||
static int pagebucket; /* bucket for requests a page in size */
|
||||
static int maxbuck; /* highest bucket receiving allocation request. */
|
||||
|
||||
static char *memtop; /* top of heap */
|
||||
|
||||
static unsigned long binsizes[NBUCKETS] = {
|
||||
8UL, 16UL, 32UL, 64UL, 128UL, 256UL, 512UL, 1024UL, 2048UL, 4096UL,
|
||||
8192UL, 16384UL, 32768UL, 65536UL, 131072UL, 262144UL, 524288UL,
|
||||
1048576UL, 2097152UL, 4194304UL, 8388608UL, 16777216UL, 33554432UL,
|
||||
67108864UL, 134217728UL, 268435456UL, 536870912UL, 1073741824UL,
|
||||
2147483648UL, 4294967296UL-1
|
||||
};
|
||||
|
||||
/* binsizes[x] == (1 << ((x) + 3)) */
|
||||
#define binsize(x) binsizes[(x)]
|
||||
|
||||
/* Declarations for internal functions */
|
||||
static PTR_T internal_malloc __P((size_t, const char *, int, int));
|
||||
static PTR_T internal_realloc __P((PTR_T, size_t, const char *, int, int));
|
||||
|
|
@ -238,10 +262,6 @@ static void botch __P((const char *, const char *, int));
|
|||
#endif
|
||||
static void xbotch __P((PTR_T, int, const char *, const char *, int));
|
||||
|
||||
#ifdef MALLOC_STATS
|
||||
extern struct _malstats _mstats;
|
||||
#endif /* MALLOC_STATS */
|
||||
|
||||
#if !HAVE_DECL_SBRK
|
||||
extern char *sbrk ();
|
||||
#endif /* !HAVE_DECL_SBRK */
|
||||
|
|
@ -251,11 +271,23 @@ extern int interrupt_immediately;
|
|||
extern int signal_is_trapped __P((int));
|
||||
#endif
|
||||
|
||||
#ifdef MALLOC_STATS
|
||||
struct _malstats _mstats;
|
||||
#endif /* MALLOC_STATS */
|
||||
|
||||
/* Debugging variables available to applications. */
|
||||
int malloc_flags = 0; /* future use */
|
||||
int malloc_trace = 0; /* trace allocations and frees to stderr */
|
||||
int malloc_register = 0; /* future use */
|
||||
|
||||
#ifdef MALLOC_TRACE
|
||||
char _malloc_trace_buckets[NBUCKETS];
|
||||
|
||||
/* These should really go into a header file. */
|
||||
extern void mtrace_alloc __P((const char *, PTR_T, size_t, const char *, int));
|
||||
extern void mtrace_free __P((PTR_T, int, const char *, int));
|
||||
#endif
|
||||
|
||||
#if !defined (botch)
|
||||
static void
|
||||
botch (s, file, line)
|
||||
|
|
@ -286,53 +318,54 @@ xbotch (mem, e, s, file, line)
|
|||
botch(s, file, line);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Coalesce two adjacent free blocks off the free list for size NU - 1,
|
||||
as long as there are at least MIN_COMBINE_FREE free blocks and we
|
||||
can find two adjacent free blocks. nextf[NU -1] is assumed to not
|
||||
be busy; the caller (morecore()) checks for this. */
|
||||
as long as we can find two adjacent free blocks. nextf[NU -1] is
|
||||
assumed to not be busy; the caller (morecore()) checks for this. */
|
||||
static void
|
||||
bcoalesce (nu)
|
||||
register int nu;
|
||||
{
|
||||
register union mhead *mp, *mp1, *mp2;
|
||||
register int nfree, nbuck;
|
||||
register int nbuck;
|
||||
unsigned long siz;
|
||||
|
||||
nbuck = nu - 1;
|
||||
if (nextf[nbuck] == 0)
|
||||
return;
|
||||
|
||||
nfree = 1;
|
||||
mp1 = nextf[nbuck];
|
||||
siz = binsize (nbuck);
|
||||
|
||||
mp2 = mp1 = nextf[nbuck];
|
||||
mp = CHAIN (mp1);
|
||||
mp2 = (union mhead *)0;
|
||||
while (CHAIN (mp))
|
||||
while (mp && mp != (union mhead *)((char *)mp1 + siz))
|
||||
{
|
||||
mp2 = mp1;
|
||||
mp1 = mp;
|
||||
mp = CHAIN (mp);
|
||||
nfree++;
|
||||
/* We may not want to run all the way through the free list here;
|
||||
if we do not, we need to check a threshold value here and break
|
||||
if nfree exceeds it. */
|
||||
}
|
||||
if (nfree < MIN_COMBINE_FREE)
|
||||
if (mp == 0)
|
||||
return;
|
||||
|
||||
/* OK, now we have mp1 pointing to the block we want to add to nextf[NU].
|
||||
CHAIN(mp2) must equal mp1. Check that mp1 and mp are adjacent. */
|
||||
if (CHAIN(mp2) != mp1)
|
||||
if (mp2 != mp1 && CHAIN(mp2) != mp1)
|
||||
xbotch ((PTR_T)0, 0, "bcoalesce: CHAIN(mp2) != mp1", (char *)NULL, 0);
|
||||
siz = 1 << (nbuck + 3);
|
||||
|
||||
#ifdef MALLOC_DEBUG
|
||||
if (CHAIN (mp1) != (union mhead *)((char *)mp1 + siz))
|
||||
return; /* not adjacent */
|
||||
#endif
|
||||
|
||||
#ifdef MALLOC_STATS
|
||||
_mstats.tbcoalesce++;
|
||||
_mstats.ncoalesce[nbuck]++;
|
||||
#endif
|
||||
|
||||
/* Since they are adjacent, remove them from the free list */
|
||||
CHAIN (mp2) = CHAIN (mp);
|
||||
if (mp1 == nextf[nbuck])
|
||||
nextf[nbuck] = CHAIN (mp);
|
||||
else
|
||||
CHAIN (mp2) = CHAIN (mp);
|
||||
|
||||
/* And add the combined two blocks to nextf[NU]. */
|
||||
mp1->mh_alloc = ISFREE;
|
||||
|
|
@ -340,7 +373,6 @@ bcoalesce (nu)
|
|||
CHAIN (mp1) = nextf[nu];
|
||||
nextf[nu] = mp1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Split a block at index > NU (but less than SPLIT_MAX) into a set of
|
||||
blocks of the correct size, and attach them to nextf[NU]. nextf[NU]
|
||||
|
|
@ -387,8 +419,8 @@ bsplit (nu)
|
|||
#endif
|
||||
|
||||
/* Figure out how many blocks we'll get. */
|
||||
siz = (1 << (nu + 3));
|
||||
nblks = (1 << (nbuck + 3)) / siz;
|
||||
siz = binsize (nu);
|
||||
nblks = binsize (nbuck) / siz;
|
||||
|
||||
/* Remove the block from the chain of larger blocks. */
|
||||
mp = nextf[nbuck];
|
||||
|
|
@ -434,6 +466,27 @@ unblock_signals (setp, osetp)
|
|||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return some memory to the system by reducing the break. This is only
|
||||
called with NU > pagebucket, so we're always assured of giving back
|
||||
more than one page of memory. */
|
||||
static void
|
||||
lesscore (nu) /* give system back some memory */
|
||||
register int nu; /* size index we're discarding */
|
||||
{
|
||||
long siz;
|
||||
|
||||
siz = binsize (nu);
|
||||
/* Should check for errors here, I guess. */
|
||||
sbrk (-siz);
|
||||
memtop -= siz;
|
||||
|
||||
#ifdef MALLOC_STATS
|
||||
_mstats.nsbrk++;
|
||||
_mstats.tsbrk -= siz;
|
||||
_mstats.nlesscore[nu]++;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
morecore (nu) /* ask system for more memory */
|
||||
|
|
@ -456,7 +509,7 @@ morecore (nu) /* ask system for more memory */
|
|||
blocked_sigs = 1;
|
||||
}
|
||||
|
||||
siz = 1 << (nu + 3); /* size of desired block for nextf[nu] */
|
||||
siz = binsize (nu); /* size of desired block for nextf[nu] */
|
||||
|
||||
if (siz < 0)
|
||||
goto morecore_done; /* oops */
|
||||
|
|
@ -474,7 +527,6 @@ morecore (nu) /* ask system for more memory */
|
|||
goto morecore_done;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Try to coalesce two adjacent blocks from the free list on nextf[nu - 1],
|
||||
if we can, and we're withing the range of the block coalescing limits. */
|
||||
if (nu >= COMBINE_MIN && nu < COMBINE_MAX && busy[nu - 1] == 0 && nextf[nu - 1])
|
||||
|
|
@ -483,7 +535,6 @@ morecore (nu) /* ask system for more memory */
|
|||
if (nextf[nu] != 0)
|
||||
goto morecore_done;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Take at least a page, and figure out how many blocks of the requested
|
||||
size we're getting. */
|
||||
|
|
@ -499,7 +550,7 @@ morecore (nu) /* ask system for more memory */
|
|||
an amount. If it is, we can just request it. If not, we want
|
||||
the smallest integral multiple of pagesize that is larger than
|
||||
`siz' and will satisfy the request. */
|
||||
sbrk_amt = siz % pagesz;
|
||||
sbrk_amt = siz & (pagesz - 1);
|
||||
if (sbrk_amt == 0)
|
||||
sbrk_amt = siz;
|
||||
else
|
||||
|
|
@ -518,10 +569,12 @@ morecore (nu) /* ask system for more memory */
|
|||
if ((long)mp == -1)
|
||||
goto morecore_done;
|
||||
|
||||
memtop += sbrk_amt;
|
||||
|
||||
/* shouldn't happen, but just in case -- require 8-byte alignment */
|
||||
if ((long)mp & 7)
|
||||
if ((long)mp & MALIGN_MASK)
|
||||
{
|
||||
mp = (union mhead *) (((long)mp + 7) & ~7);
|
||||
mp = (union mhead *) (((long)mp + MALIGN_MASK) & ~MALIGN_MASK);
|
||||
nblks--;
|
||||
}
|
||||
|
||||
|
|
@ -542,28 +595,82 @@ morecore_done:
|
|||
unblock_signals (&set, &oset);
|
||||
}
|
||||
|
||||
#if defined (MEMSCRAMBLE) || !defined (NO_CALLOC)
|
||||
static char *
|
||||
zmemset (s, c, n)
|
||||
char *s;
|
||||
int c;
|
||||
register int n;
|
||||
{
|
||||
register char *sp;
|
||||
|
||||
sp = s;
|
||||
while (--n >= 0)
|
||||
*sp++ = c;
|
||||
return (s);
|
||||
}
|
||||
#endif /* MEMSCRAMBLE || !NO_CALLOC */
|
||||
|
||||
static void
|
||||
malloc_debug_dummy ()
|
||||
{
|
||||
write (1, "malloc_debug_dummy\n", 19);
|
||||
}
|
||||
|
||||
#define PREPOP_BIN 2
|
||||
#define PREPOP_SIZE 32
|
||||
|
||||
static int
|
||||
pagealign ()
|
||||
{
|
||||
register int nunits;
|
||||
register union mhead *mp;
|
||||
long sbrk_needed;
|
||||
char *curbrk;
|
||||
|
||||
pagesz = getpagesize ();
|
||||
if (pagesz < 1024)
|
||||
pagesz = 1024;
|
||||
|
||||
/* OK, how much do we need to allocate to make things page-aligned?
|
||||
Some of this partial page will be wasted space, but we'll use as
|
||||
much as we can. Once we figure out how much to advance the break
|
||||
pointer, go ahead and do it. */
|
||||
memtop = curbrk = sbrk (0);
|
||||
sbrk_needed = pagesz - ((long)curbrk & (pagesz - 1)); /* sbrk(0) % pagesz */
|
||||
if (sbrk_needed < 0)
|
||||
sbrk_needed += pagesz;
|
||||
|
||||
/* Now allocate the wasted space. */
|
||||
if (sbrk_needed)
|
||||
{
|
||||
#ifdef MALLOC_STATS
|
||||
_mstats.nsbrk++;
|
||||
_mstats.tsbrk += sbrk_needed;
|
||||
#endif
|
||||
curbrk = sbrk (sbrk_needed);
|
||||
if ((long)curbrk == -1)
|
||||
return -1;
|
||||
memtop += sbrk_needed;
|
||||
|
||||
/* Take the memory which would otherwise be wasted and populate the most
|
||||
popular bin (2 == 32 bytes) with it. Add whatever we need to curbrk
|
||||
to make things 32-byte aligned, compute how many 32-byte chunks we're
|
||||
going to get, and set up the bin. */
|
||||
curbrk += sbrk_needed & (PREPOP_SIZE - 1);
|
||||
sbrk_needed -= sbrk_needed & (PREPOP_SIZE - 1);
|
||||
nunits = sbrk_needed / PREPOP_SIZE;
|
||||
|
||||
if (nunits > 0)
|
||||
{
|
||||
mp = (union mhead *)curbrk;
|
||||
|
||||
nextf[PREPOP_BIN] = mp;
|
||||
while (1)
|
||||
{
|
||||
mp->mh_alloc = ISFREE;
|
||||
mp->mh_index = PREPOP_BIN;
|
||||
if (--nunits <= 0) break;
|
||||
CHAIN(mp) = (union mhead *)((char *)mp + PREPOP_SIZE);
|
||||
mp = (union mhead *)((char *)mp + PREPOP_SIZE);
|
||||
}
|
||||
CHAIN(mp) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* compute which bin corresponds to the page size. */
|
||||
for (nunits = 7; nunits < NBUCKETS; nunits++)
|
||||
if (pagesz <= binsize(nunits))
|
||||
break;
|
||||
pagebucket = nunits;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PTR_T
|
||||
internal_malloc (n, file, line, flags) /* get a block */
|
||||
size_t n;
|
||||
|
|
@ -571,71 +678,27 @@ internal_malloc (n, file, line, flags) /* get a block */
|
|||
int line, flags;
|
||||
{
|
||||
register union mhead *p;
|
||||
register long nbytes;
|
||||
register int nunits;
|
||||
register char *m, *z;
|
||||
long nbytes;
|
||||
mguard_t mg;
|
||||
|
||||
/* Get the system page size and align break pointer so everything will
|
||||
/* Get the system page size and align break pointer so future sbrks will
|
||||
be page-aligned. The page size must be at least 1K -- anything
|
||||
smaller is increased. */
|
||||
if (pagesz == 0)
|
||||
{
|
||||
register long sbrk_needed;
|
||||
|
||||
pagesz = getpagesize ();
|
||||
if (pagesz < 1024)
|
||||
pagesz = 1024;
|
||||
/* OK, how much do we need to allocate to make things page-aligned?
|
||||
This partial page is wasted space. Once we figure out how much
|
||||
to advance the break pointer, go ahead and do it. */
|
||||
sbrk_needed = pagesz - ((long)sbrk (0) & (pagesz - 1)); /* sbrk(0) % pagesz */
|
||||
if (sbrk_needed < 0)
|
||||
sbrk_needed += pagesz;
|
||||
/* Now allocate the wasted space. */
|
||||
if (sbrk_needed)
|
||||
{
|
||||
#ifdef MALLOC_STATS
|
||||
_mstats.nsbrk++;
|
||||
_mstats.tsbrk += sbrk_needed;
|
||||
#endif
|
||||
if ((long)sbrk (sbrk_needed) == -1)
|
||||
return (NULL);
|
||||
}
|
||||
nunits = 0;
|
||||
nbytes = 8;
|
||||
while (pagesz > nbytes)
|
||||
{
|
||||
nbytes <<= 1;
|
||||
nunits++;
|
||||
}
|
||||
pagebucket = nunits;
|
||||
}
|
||||
if (pagealign () < 0)
|
||||
return ((PTR_T)NULL);
|
||||
|
||||
/* Figure out how many bytes are required, rounding up to the nearest
|
||||
multiple of 8, then figure out which nextf[] area to use. Try to
|
||||
be smart about where to start searching -- if the number of bytes
|
||||
needed is greater than the page size, we can start at pagebucket. */
|
||||
nbytes = ALLOCATED_BYTES(n);
|
||||
nunits = 0;
|
||||
if (nbytes <= (pagesz >> 1))
|
||||
{
|
||||
register unsigned int shiftr;
|
||||
|
||||
shiftr = (nbytes - 1) >> 2; /* == (nbytes - 1) / 4 */
|
||||
while (shiftr >>= 1) /* == (nbytes - 1) / {8,16,32,...} */
|
||||
nunits++;
|
||||
}
|
||||
else
|
||||
{
|
||||
register u_bits32_t amt;
|
||||
|
||||
nunits = pagebucket;
|
||||
amt = pagesz;
|
||||
while (nbytes > amt)
|
||||
{
|
||||
amt <<= 1;
|
||||
nunits++;
|
||||
}
|
||||
}
|
||||
nunits = (nbytes <= (pagesz >> 1)) ? STARTBUCK : pagebucket;
|
||||
for ( ; nunits < NBUCKETS; nunits++)
|
||||
if (nbytes <= binsize(nunits))
|
||||
break;
|
||||
|
||||
/* Silently reject too-large requests. */
|
||||
if (nunits >= NBUCKETS)
|
||||
|
|
@ -671,30 +734,35 @@ internal_malloc (n, file, line, flags) /* get a block */
|
|||
/* If not for this check, we would gobble a clobbered free chain ptr
|
||||
and bomb out on the NEXT allocate of this size block */
|
||||
if (p->mh_alloc != ISFREE || p->mh_index != nunits)
|
||||
xbotch ((PTR_T)0, 0, "malloc: block on free list clobbered", file, line);
|
||||
xbotch ((PTR_T)(p+1), 0, "malloc: block on free list clobbered", file, line);
|
||||
|
||||
/* Fill in the info, and set up the magic numbers for range checking. */
|
||||
p->mh_alloc = ISALLOC;
|
||||
p->mh_magic2 = MAGIC2;
|
||||
p->mh_nbytes = n;
|
||||
{
|
||||
register char *m = (char *) (p + 1) + n;
|
||||
|
||||
*m++ = MAGIC1, *m++ = MAGIC1, *m++ = MAGIC1, *m = MAGIC1;
|
||||
}
|
||||
/* End guard */
|
||||
mg.i = n;
|
||||
z = mg.s;
|
||||
m = (char *) (p + 1) + n;
|
||||
*m++ = *z++, *m++ = *z++, *m++ = *z++, *m++ = *z++;
|
||||
|
||||
#ifdef MEMSCRAMBLE
|
||||
zmemset ((char *)(p + 1), 0xdf, n); /* scramble previous contents */
|
||||
if (n)
|
||||
MALLOC_MEMSET ((char *)(p + 1), 0xdf, n); /* scramble previous contents */
|
||||
#endif
|
||||
#ifdef MALLOC_STATS
|
||||
_mstats.nmalloc[nunits]++;
|
||||
_mstats.tmalloc[nunits]++;
|
||||
_mstats.nmal++;
|
||||
_mstats.bytesreq += n;
|
||||
#endif /* MALLOC_STATS */
|
||||
|
||||
#ifdef MALLOC_TRACE
|
||||
if (malloc_trace && (flags & MALLOC_NOTRACE) == 0)
|
||||
mtrace_alloc ("malloc", p + 1, n, file, line);
|
||||
else if (_malloc_trace_buckets[nunits])
|
||||
mtrace_alloc ("malloc", p + 1, n, file, line);
|
||||
#endif
|
||||
|
||||
#ifdef MALLOC_REGISTER
|
||||
|
|
@ -702,7 +770,12 @@ internal_malloc (n, file, line, flags) /* get a block */
|
|||
mregister_alloc ("malloc", p + 1, n, file, line);
|
||||
#endif
|
||||
|
||||
return (char *) (p + 1); /* XXX - should be cast to PTR_T? */
|
||||
#ifdef MALLOC_WATCH
|
||||
if (_malloc_nwatch > 0)
|
||||
_malloc_ckwatch (p + 1, file, line, W_ALLOC, n);
|
||||
#endif
|
||||
|
||||
return (PTR_T) (p + 1);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -712,10 +785,11 @@ internal_free (mem, file, line, flags)
|
|||
int line, flags;
|
||||
{
|
||||
register union mhead *p;
|
||||
register char *ap;
|
||||
register char *ap, *z;
|
||||
register int nunits;
|
||||
register unsigned int nbytes;
|
||||
int ubytes; /* caller-requested size */
|
||||
mguard_t mg;
|
||||
|
||||
if ((ap = (char *)mem) == 0)
|
||||
return;
|
||||
|
|
@ -753,18 +827,42 @@ internal_free (mem, file, line, flags)
|
|||
We sanity-check the value of mh_nbytes against the size of the blocks
|
||||
in the appropriate bucket before we use it. This can still cause problems
|
||||
and obscure errors if mh_nbytes is wrong but still within range; the
|
||||
checks against MAGIC1 will probably fail then. Using MALLOC_REGISTER
|
||||
will help here, since it saves the original number of bytes requested. */
|
||||
checks against the size recorded at the end of the chunk will probably
|
||||
fail then. Using MALLOC_REGISTER will help here, since it saves the
|
||||
original number of bytes requested. */
|
||||
|
||||
if (IN_BUCKET(nbytes, nunits) == 0)
|
||||
xbotch (mem, ERR_UNDERFLOW,
|
||||
"free: underflow detected; mh_nbytes out of range", file, line);
|
||||
|
||||
ap += p->mh_nbytes;
|
||||
ASSERT (*ap++ == MAGIC1); ASSERT (*ap++ == MAGIC1);
|
||||
ASSERT (*ap++ == MAGIC1); ASSERT (*ap == MAGIC1);
|
||||
z = mg.s;
|
||||
*z++ = *ap++, *z++ = *ap++, *z++ = *ap++, *z++ = *ap++;
|
||||
if (mg.i != p->mh_nbytes)
|
||||
xbotch (mem, ERR_ASSERT_FAILED, "free: start and end chunk sizes differ", file, line);
|
||||
|
||||
#if 1
|
||||
if (nunits >= LESSCORE_MIN && ((char *)p + binsize(nunits) == memtop))
|
||||
#else
|
||||
if (((char *)p + binsize(nunits) == memtop) && nunits >= LESSCORE_MIN)
|
||||
#endif
|
||||
{
|
||||
/* If above LESSCORE_FRC, give back unconditionally. This should be set
|
||||
high enough to be infrequently encountered. If between LESSCORE_MIN
|
||||
and LESSCORE_FRC, call lesscore if the bucket is marked as busy (in
|
||||
which case we would punt below and leak memory) or if there's already
|
||||
a block on the free list. */
|
||||
if ((nunits >= LESSCORE_FRC) || busy[nunits] || nextf[nunits] != 0)
|
||||
{
|
||||
lesscore (nunits);
|
||||
/* keeps the tracing and registering code in one place */
|
||||
goto free_return;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MEMSCRAMBLE
|
||||
zmemset (mem, 0xcf, p->mh_nbytes);
|
||||
if (p->mh_nbytes)
|
||||
MALLOC_MEMSET (mem, 0xcf, p->mh_nbytes);
|
||||
#endif
|
||||
|
||||
ASSERT (nunits < NBUCKETS);
|
||||
|
|
@ -780,6 +878,8 @@ internal_free (mem, file, line, flags)
|
|||
nextf[nunits] = p;
|
||||
busy[nunits] = 0;
|
||||
|
||||
free_return:
|
||||
|
||||
#ifdef MALLOC_STATS
|
||||
_mstats.nmalloc[nunits]--;
|
||||
_mstats.nfre++;
|
||||
|
|
@ -788,12 +888,19 @@ internal_free (mem, file, line, flags)
|
|||
#ifdef MALLOC_TRACE
|
||||
if (malloc_trace && (flags & MALLOC_NOTRACE) == 0)
|
||||
mtrace_free (mem, ubytes, file, line);
|
||||
else if (_malloc_trace_buckets[nunits])
|
||||
mtrace_free (mem, ubytes, file, line);
|
||||
#endif
|
||||
|
||||
#ifdef MALLOC_REGISTER
|
||||
if (malloc_register && (flags & MALLOC_NOREG) == 0)
|
||||
mregister_free (mem, ubytes, file, line);
|
||||
#endif
|
||||
|
||||
#ifdef MALLOC_WATCH
|
||||
if (_malloc_nwatch > 0)
|
||||
_malloc_ckwatch (mem, file, line, W_FREE, ubytes);
|
||||
#endif
|
||||
}
|
||||
|
||||
static PTR_T
|
||||
|
|
@ -807,7 +914,8 @@ internal_realloc (mem, n, file, line, flags)
|
|||
register u_bits32_t tocopy;
|
||||
register unsigned int nbytes;
|
||||
register int nunits;
|
||||
register char *m;
|
||||
register char *m, *z;
|
||||
mguard_t mg;
|
||||
|
||||
#ifdef MALLOC_STATS
|
||||
_mstats.nrealloc++;
|
||||
|
|
@ -837,37 +945,56 @@ internal_realloc (mem, n, file, line, flags)
|
|||
We sanity-check the value of mh_nbytes against the size of the blocks
|
||||
in the appropriate bucket before we use it. This can still cause problems
|
||||
and obscure errors if mh_nbytes is wrong but still within range; the
|
||||
checks against MAGIC1 will probably fail then. Using MALLOC_REGISTER
|
||||
will help here, since it saves the original number of bytes requested. */
|
||||
checks against the size recorded at the end of the chunk will probably
|
||||
fail then. Using MALLOC_REGISTER will help here, since it saves the
|
||||
original number of bytes requested. */
|
||||
if (IN_BUCKET(nbytes, nunits) == 0)
|
||||
xbotch (mem, ERR_UNDERFLOW,
|
||||
"realloc: underflow detected; mh_nbytes out of range", file, line);
|
||||
|
||||
m = (char *)mem + (tocopy = p->mh_nbytes);
|
||||
ASSERT (*m++ == MAGIC1); ASSERT (*m++ == MAGIC1);
|
||||
ASSERT (*m++ == MAGIC1); ASSERT (*m == MAGIC1);
|
||||
z = mg.s;
|
||||
*z++ = *m++, *z++ = *m++, *z++ = *m++, *z++ = *m++;
|
||||
if (mg.i != p->mh_nbytes)
|
||||
xbotch (mem, ERR_ASSERT_FAILED, "realloc: start and end chunk sizes differ", file, line);
|
||||
|
||||
#ifdef MALLOC_WATCH
|
||||
if (_malloc_nwatch > 0)
|
||||
_malloc_ckwatch (p + 1, file, line, W_REALLOC, n);
|
||||
#endif
|
||||
#ifdef MALLOC_STATS
|
||||
_mstats.bytesreq += (n < tocopy) ? 0 : n - tocopy;
|
||||
#endif
|
||||
|
||||
/* See if desired size rounds to same power of 2 as actual size. */
|
||||
nbytes = ALLOCATED_BYTES(n);
|
||||
|
||||
/* If ok, use the same block, just marking its size as changed. */
|
||||
if (IN_BUCKET(nbytes, nunits))
|
||||
if (RIGHT_BUCKET(nbytes, nunits))
|
||||
{
|
||||
m = (char *)mem + tocopy;
|
||||
#if 0
|
||||
m = (char *)mem + p->mh_nbytes;
|
||||
#else
|
||||
/* Compensate for increment above. */
|
||||
m -= 4;
|
||||
#endif
|
||||
*m++ = 0; *m++ = 0; *m++ = 0; *m++ = 0;
|
||||
p->mh_nbytes = n;
|
||||
m = (char *)mem + n;
|
||||
*m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1; *m++ = MAGIC1;
|
||||
m = (char *)mem + (p->mh_nbytes = n);
|
||||
|
||||
mg.i = n;
|
||||
z = mg.s;
|
||||
*m++ = *z++, *m++ = *z++, *m++ = *z++, *m++ = *z++;
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
if (n < tocopy)
|
||||
tocopy = n;
|
||||
|
||||
#ifdef MALLOC_STATS
|
||||
_mstats.nrcopy++;
|
||||
#endif
|
||||
|
||||
if (n < tocopy)
|
||||
tocopy = n;
|
||||
|
||||
if ((m = internal_malloc (n, file, line, MALLOC_INTERNAL|MALLOC_NOTRACE|MALLOC_NOREG)) == 0)
|
||||
return 0;
|
||||
FASTCOPY (mem, m, tocopy);
|
||||
|
|
@ -876,6 +1003,8 @@ internal_realloc (mem, n, file, line, flags)
|
|||
#ifdef MALLOC_TRACE
|
||||
if (malloc_trace && (flags & MALLOC_NOTRACE) == 0)
|
||||
mtrace_alloc ("realloc", m, n, file, line);
|
||||
else if (_malloc_trace_buckets[nunits])
|
||||
mtrace_alloc ("realloc", m, n, file, line);
|
||||
#endif
|
||||
|
||||
#ifdef MALLOC_REGISTER
|
||||
|
|
@ -883,6 +1012,11 @@ internal_realloc (mem, n, file, line, flags)
|
|||
mregister_alloc ("realloc", m, n, file, line);
|
||||
#endif
|
||||
|
||||
#ifdef MALLOC_WATCH
|
||||
if (_malloc_nwatch > 0)
|
||||
_malloc_ckwatch (m, file, line, W_RESIZED, n);
|
||||
#endif
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
|
|
@ -946,7 +1080,7 @@ internal_calloc (n, s, file, line, flags)
|
|||
total = n * s;
|
||||
result = internal_malloc (total, file, line, flags|MALLOC_INTERNAL);
|
||||
if (result)
|
||||
zmemset (result, 0, total);
|
||||
memset (result, 0, total);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -961,7 +1095,6 @@ internal_cfree (p, file, line, flags)
|
|||
#endif /* !NO_CALLOC */
|
||||
|
||||
#ifdef MALLOC_STATS
|
||||
|
||||
int
|
||||
malloc_free_blocks (size)
|
||||
int size;
|
||||
|
|
@ -977,7 +1110,7 @@ malloc_free_blocks (size)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined (SHELL)
|
||||
#if defined (MALLOC_WRAPFUNCS)
|
||||
PTR_T
|
||||
sh_malloc (bytes, file, line)
|
||||
size_t bytes;
|
||||
|
|
@ -1045,9 +1178,9 @@ sh_valloc (size, file, line)
|
|||
{
|
||||
return internal_valloc (size, file, line, MALLOC_WRAPPER);
|
||||
}
|
||||
#endif
|
||||
#endif /* !NO_VALLOC */
|
||||
|
||||
#endif
|
||||
#endif /* MALLOC_WRAPFUNCS */
|
||||
|
||||
/* Externally-available functions that call their internal counterparts. */
|
||||
|
||||
|
|
|
|||
|
|
@ -31,18 +31,28 @@
|
|||
* NMALLOC[i] is the difference between the number of mallocs and frees
|
||||
* for a given block size. TMALLOC[i] is the total number of mallocs for
|
||||
* a given block size. NMORECORE[i] is the total number of calls to
|
||||
* morecore(i). NMAL and NFRE are counts of the number of calls to malloc()
|
||||
* and free(), respectively. NREALLOC is the total number of calls to
|
||||
* realloc(); NRCOPY is the number of times realloc() had to allocate new
|
||||
* memory and copy to it. NRECURSE is a count of the number of recursive
|
||||
* calls to malloc() for the same bucket size, which can be caused by calls
|
||||
* to malloc() from a signal handler. NSBRK is the number of calls to sbrk()
|
||||
* (whether by morecore() or for alignment); TSBRK is the total number of
|
||||
* bytes requested from the kernel with sbrk(). BYTESUSED is the total
|
||||
* number of bytes consumed by blocks currently in use; BYTESFREE is the
|
||||
* total number of bytes currently on all of the free lists. TBSPLIT is
|
||||
* the number of times a larger block was split to satisfy a smaller request.
|
||||
* NSPLIT[i] is the number of times a block of size I was split.
|
||||
* morecore(i). NLESSCORE[i] is the total number of calls to lesscore(i).
|
||||
*
|
||||
* NMAL and NFRE are counts of the number of calls to malloc() and free(),
|
||||
* respectively. NREALLOC is the total number of calls to realloc();
|
||||
* NRCOPY is the number of times realloc() had to allocate new memory and
|
||||
* copy to it. NRECURSE is a count of the number of recursive calls to
|
||||
* malloc() for the same bucket size, which can be caused by calls to
|
||||
* malloc() from a signal handler.
|
||||
*
|
||||
* NSBRK is the number of calls to sbrk() (whether by morecore() or for
|
||||
* alignment); TSBRK is the total number of bytes requested from the kernel
|
||||
* with sbrk().
|
||||
*
|
||||
* BYTESUSED is the total number of bytes consumed by blocks currently in
|
||||
* use; BYTESFREE is the total number of bytes currently on all of the free
|
||||
* lists. BYTESREQ is the total number of bytes requested by the caller
|
||||
* via calls to malloc() and realloc().
|
||||
*
|
||||
* TBSPLIT is the number of times a larger block was split to satisfy a
|
||||
* smaller request. NSPLIT[i] is the number of times a block of size I was
|
||||
* split.
|
||||
*
|
||||
* TBCOALESCE is the number of times two adjacent smaller blocks off the free
|
||||
* list were combined to satisfy a larger request.
|
||||
*/
|
||||
|
|
@ -50,6 +60,7 @@ struct _malstats {
|
|||
int nmalloc[NBUCKETS];
|
||||
int tmalloc[NBUCKETS];
|
||||
int nmorecore[NBUCKETS];
|
||||
int nlesscore[NBUCKETS];
|
||||
int nmal;
|
||||
int nfre;
|
||||
int nrealloc;
|
||||
|
|
@ -59,31 +70,38 @@ struct _malstats {
|
|||
bits32_t tsbrk;
|
||||
bits32_t bytesused;
|
||||
bits32_t bytesfree;
|
||||
u_bits32_t bytesreq;
|
||||
int tbsplit;
|
||||
int nsplit[NBUCKETS];
|
||||
int tbcoalesce;
|
||||
int ncoalesce[NBUCKETS];
|
||||
};
|
||||
|
||||
/* Return statistics describing allocation of blocks of size BLOCKSIZE.
|
||||
NFREE is the number of free blocks for this allocation size. NUSED
|
||||
is the number of blocks in use. NMAL is the number of requests for
|
||||
blocks of size BLOCKSIZE. NMORECORE is the number of times we had
|
||||
to call MORECORE to repopulate the free list for this bucket. NSPLIT
|
||||
is the number of times a block of this size was split to satisfy a
|
||||
smaller request. */
|
||||
to call MORECORE to repopulate the free list for this bucket.
|
||||
NLESSCORE is the number of times we gave memory back to the system
|
||||
from this bucket. NSPLIT is the number of times a block of this size
|
||||
was split to satisfy a smaller request. NCOALESCE is the number of
|
||||
times two blocks of this size were combined to satisfy a larger
|
||||
request. */
|
||||
struct bucket_stats {
|
||||
u_bits32_t blocksize;
|
||||
int nfree;
|
||||
int nused;
|
||||
int nmal;
|
||||
int nmorecore;
|
||||
int nlesscore;
|
||||
int nsplit;
|
||||
int ncoalesce;
|
||||
};
|
||||
|
||||
extern struct bucket_stats malloc_bucket_stats ();
|
||||
extern struct _malstats malloc_stats ();
|
||||
extern void print_malloc_stats ();
|
||||
extern void trace_malloc_stats ();
|
||||
extern struct bucket_stats malloc_bucket_stats __P((int));
|
||||
extern struct _malstats malloc_stats __P((void));
|
||||
extern void print_malloc_stats __P((char *));
|
||||
extern void trace_malloc_stats __P((char *, char *));
|
||||
|
||||
#endif /* MALLOC_STATS */
|
||||
|
||||
|
|
|
|||
|
|
@ -62,6 +62,6 @@ extern int malloc_set_register __P((int));
|
|||
/* stats.c */
|
||||
extern void print_malloc_stats __P((char *));
|
||||
extern void fprint_malloc_stats (); /* full prototype requires stdio.h */
|
||||
extern void trace_malloc_stats __P((char *));
|
||||
extern void trace_malloc_stats __P((char *, char *));
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,9 +25,15 @@
|
|||
#ifdef MALLOC_STATS
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "mstats.h"
|
||||
|
||||
struct _malstats _mstats;
|
||||
extern int malloc_free_blocks __P((int));
|
||||
|
||||
extern struct _malstats _mstats;
|
||||
|
||||
struct bucket_stats
|
||||
malloc_bucket_stats (size)
|
||||
|
|
@ -40,7 +46,7 @@ malloc_bucket_stats (size)
|
|||
if (size < 0 || size >= NBUCKETS)
|
||||
{
|
||||
v.blocksize = 0;
|
||||
v.nused = v.nmal = v.nmorecore = v.nsplit = 0;
|
||||
v.nused = v.nmal = v.nmorecore = v.nlesscore = v.nsplit = 0;
|
||||
return v;
|
||||
}
|
||||
|
||||
|
|
@ -48,7 +54,9 @@ malloc_bucket_stats (size)
|
|||
v.nused = _mstats.nmalloc[size];
|
||||
v.nmal = _mstats.tmalloc[size];
|
||||
v.nmorecore = _mstats.nmorecore[size];
|
||||
v.nlesscore = _mstats.nlesscore[size];
|
||||
v.nsplit = _mstats.nsplit[size];
|
||||
v.ncoalesce = _mstats.ncoalesce[size];
|
||||
|
||||
v.nfree = malloc_free_blocks (size); /* call back to malloc.c */
|
||||
|
||||
|
|
@ -86,16 +94,18 @@ _print_malloc_stats (s, fp)
|
|||
unsigned long totused, totfree;
|
||||
struct bucket_stats v;
|
||||
|
||||
fprintf (fp, "Memory allocation statistics: %s\n\tsize\tfree\tin use\ttotal\tmorecore\tsplit\n", s ? s : "");
|
||||
fprintf (fp, "Memory allocation statistics: %s\n size\tfree\tin use\ttotal\tmorecore lesscore split\tcoalesce\n", s ? s : "");
|
||||
for (i = totused = totfree = 0; i < NBUCKETS; i++)
|
||||
{
|
||||
v = malloc_bucket_stats (i);
|
||||
fprintf (fp, "%12lu\t%4d\t%6d\t%5d\t%8d\t%5d\n", (unsigned long)v.blocksize, v.nfree, v.nused, v.nmal, v.nmorecore, v.nsplit);
|
||||
if (v.nmal > 0)
|
||||
fprintf (fp, "%8lu\t%4d\t%6d\t%5d\t%8d\t%d %5d %8d\n", (unsigned long)v.blocksize, v.nfree, v.nused, v.nmal, v.nmorecore, v.nlesscore, v.nsplit, v.ncoalesce);
|
||||
totfree += v.nfree * v.blocksize;
|
||||
totused += v.nused * v.blocksize;
|
||||
}
|
||||
fprintf (fp, "\nTotal bytes in use: %lu, total bytes free: %lu\n",
|
||||
totused, totfree);
|
||||
fprintf (fp, "\nTotal bytes requested by application: %lu\n", _mstats.bytesreq);
|
||||
fprintf (fp, "Total mallocs: %d, total frees: %d, total reallocs: %d (%d copies)\n",
|
||||
_mstats.nmal, _mstats.nfre, _mstats.nrealloc, _mstats.nrcopy);
|
||||
fprintf (fp, "Total sbrks: %d, total bytes via sbrk: %d\n",
|
||||
|
|
@ -120,24 +130,51 @@ fprint_malloc_stats (s, fp)
|
|||
}
|
||||
|
||||
#define TRACEROOT "/var/tmp/maltrace/trace."
|
||||
extern char *inttostr ();
|
||||
static char mallbuf[1024];
|
||||
|
||||
void
|
||||
trace_malloc_stats (s)
|
||||
char *s;
|
||||
trace_malloc_stats (s, fn)
|
||||
char *s, *fn;
|
||||
{
|
||||
char ibuf[32], *ip;
|
||||
char fname[64];
|
||||
long p;
|
||||
char defname[sizeof (TRACEROOT) + 64];
|
||||
char fname[1024];
|
||||
long l;
|
||||
FILE *fp;
|
||||
|
||||
p = getpid();
|
||||
ip = inttostr(p, ibuf, sizeof(ibuf));
|
||||
strcpy (fname, TRACEROOT);
|
||||
strcat (fname, ip);
|
||||
fp = fopen(fname, "w");
|
||||
l = (long)getpid ();
|
||||
if (fn == 0)
|
||||
{
|
||||
sprintf (defname, "%s%ld", TRACEROOT, l);
|
||||
fp = fopen(defname, "w");
|
||||
}
|
||||
else
|
||||
{
|
||||
char *p, *q, *r;
|
||||
char pidbuf[32];
|
||||
int sp;
|
||||
|
||||
sprintf (pidbuf, "%ld", l);
|
||||
if ((strlen (pidbuf) + strlen (fn) + 2) >= sizeof (fname))
|
||||
return;
|
||||
for (sp = 0, p = fname, q = fn; *q; )
|
||||
{
|
||||
if (sp == 0 && *q == '%' && q[1] == 'p')
|
||||
{
|
||||
sp = 1;
|
||||
for (r = pidbuf; *r; )
|
||||
*p++ = *r++;
|
||||
q += 2;
|
||||
}
|
||||
else
|
||||
*p++ = *q++;
|
||||
}
|
||||
*p = '\0';
|
||||
fp = fopen (fname, "w");
|
||||
}
|
||||
|
||||
if (fp)
|
||||
{
|
||||
setvbuf (fp, mallbuf, _IOFBF, sizeof (mallbuf));
|
||||
_print_malloc_stats (s, fp);
|
||||
fflush(fp);
|
||||
fclose(fp);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,21 @@
|
|||
/* Copyright (C) 1993-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
void
|
||||
bash_malloc_stub()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@ extern int malloc_register;
|
|||
#define FIND_EXIST 0x02 /* find existing entry */
|
||||
|
||||
static int table_count = 0;
|
||||
static int table_allocated = 0;
|
||||
static mr_table_t mem_table[REG_TABLE_SIZE];
|
||||
static mr_table_t mem_overflow;
|
||||
|
||||
/*
|
||||
* NOTE: taken from dmalloc (http://dmalloc.com) and modified.
|
||||
|
|
@ -43,7 +45,7 @@ static unsigned int
|
|||
mt_hash (key)
|
||||
const PTR_T key;
|
||||
{
|
||||
unsigned int a, b, c, len;
|
||||
unsigned int a, b, c;
|
||||
unsigned long x;
|
||||
|
||||
/* set up the internal state */
|
||||
|
|
@ -61,10 +63,10 @@ static unsigned int
|
|||
which_bucket (mem)
|
||||
PTR_T mem;
|
||||
{
|
||||
return (mt_hash ((unsigned char *)mem) % REG_TABLE_SIZE);
|
||||
return (mt_hash ((unsigned char *)mem) & (REG_TABLE_SIZE-1));
|
||||
}
|
||||
#else
|
||||
#define which_bucket(mem) (mt_hash ((unsigned char *)(mem)) % REG_TABLE_SIZE);
|
||||
#define which_bucket(mem) (mt_hash ((unsigned char *)(mem)) & (REG_TABLE_SIZE-1));
|
||||
#endif
|
||||
|
||||
static mr_table_t *
|
||||
|
|
@ -76,6 +78,9 @@ find_entry (mem, flags)
|
|||
register mr_table_t *tp;
|
||||
mr_table_t *endp, *lastp;
|
||||
|
||||
if (mem_overflow.mem == mem)
|
||||
return (&mem_overflow);
|
||||
|
||||
bucket = which_bucket (mem); /* get initial hash */
|
||||
tp = endp = mem_table + bucket;
|
||||
lastp = mem_table + REG_TABLE_SIZE;
|
||||
|
|
@ -105,17 +110,26 @@ find_entry (mem, flags)
|
|||
/* oops. table is full. replace an existing free entry. */
|
||||
do
|
||||
{
|
||||
/* If there are no free entries, punt right away without searching. */
|
||||
if (table_allocated == REG_TABLE_SIZE)
|
||||
break;
|
||||
|
||||
if (tp->flags & MT_FREE)
|
||||
{
|
||||
memset(tp, 0, sizeof (mr_table_t));
|
||||
return (tp);
|
||||
}
|
||||
tp++;
|
||||
|
||||
if (tp == lastp)
|
||||
tp = mem_table;
|
||||
}
|
||||
while (tp != endp);
|
||||
|
||||
/* wow. entirely full. return NULL. */
|
||||
return ((mr_table_t *)NULL);
|
||||
/* wow. entirely full. return mem_overflow dummy entry. */
|
||||
tp = &mem_overflow;
|
||||
memset (tp, 0, sizeof (mr_table_t));
|
||||
return tp;
|
||||
}
|
||||
|
||||
mr_table_t *
|
||||
|
|
@ -158,7 +172,7 @@ mregister_alloc (tag, mem, size, file, line)
|
|||
if (tentry == 0)
|
||||
{
|
||||
/* oops. table is full. punt. */
|
||||
fprintf (stderr, "register_alloc: alloc table is full?\n");
|
||||
fprintf (stderr, "register_alloc: alloc table is full with FIND_ALLOC?\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -175,6 +189,9 @@ mregister_alloc (tag, mem, size, file, line)
|
|||
tentry->file = file;
|
||||
tentry->line = line;
|
||||
tentry->nalloc++;
|
||||
|
||||
if (tentry != &mem_overflow)
|
||||
table_allocated++;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -190,7 +207,9 @@ mregister_free (mem, size, file, line)
|
|||
if (tentry == 0)
|
||||
{
|
||||
/* oops. not found. */
|
||||
#if 0
|
||||
fprintf (stderr, "register_free: %p not in allocation table?\n", mem);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (tentry->flags & MT_FREE)
|
||||
|
|
@ -204,6 +223,9 @@ mregister_free (mem, size, file, line)
|
|||
tentry->file = file;
|
||||
tentry->line = line;
|
||||
tentry->nfree++;
|
||||
|
||||
if (tentry != &mem_overflow)
|
||||
table_allocated--;
|
||||
}
|
||||
|
||||
/* If we ever add more flags, this will require changes. */
|
||||
|
|
@ -250,6 +272,7 @@ void
|
|||
mregister_table_init ()
|
||||
{
|
||||
memset (mem_table, 0, sizeof(mr_table_t) * REG_TABLE_SIZE);
|
||||
memset (&mem_overflow, 0, sizeof (mr_table_t));
|
||||
table_count = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,12 +55,12 @@ typedef struct mr_table {
|
|||
|
||||
#define REG_TABLE_SIZE 8192
|
||||
|
||||
extern mr_table_t *mr_table_entry ();
|
||||
extern void mregister_alloc ();
|
||||
extern void mregister_free ();
|
||||
extern mr_table_t *mr_table_entry __P((PTR_T));
|
||||
extern void mregister_alloc __P((const char *, PTR_T, size_t, const char *, int));
|
||||
extern void mregister_free __P((PTR_T, int, const char *, int));
|
||||
extern void mregister_describe_mem ();
|
||||
extern void mregister_dump_table ();
|
||||
extern void mregister_table_init ();
|
||||
extern void mregister_dump_table __P((void));
|
||||
extern void mregister_table_init __P((void));
|
||||
|
||||
/* NOTE: HASH_MIX taken from dmalloc (http://dmalloc.com) */
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ static int _mtrace_verbose = 0;
|
|||
#ifdef MALLOC_TRACE
|
||||
|
||||
FILE *_mtrace_fp = NULL;
|
||||
extern char _malloc_trace_buckets[];
|
||||
|
||||
void
|
||||
mtrace_alloc (tag, mem, size, file, line)
|
||||
|
|
@ -72,7 +73,7 @@ mtrace_free (mem, size, file, line)
|
|||
#endif /* MALLOC_TRACE */
|
||||
|
||||
int
|
||||
malloc_set_trace(n)
|
||||
malloc_set_trace (n)
|
||||
int n;
|
||||
{
|
||||
int old;
|
||||
|
|
@ -84,10 +85,19 @@ malloc_set_trace(n)
|
|||
}
|
||||
|
||||
void
|
||||
malloc_set_tracefp(fp)
|
||||
malloc_set_tracefp (fp)
|
||||
FILE *fp;
|
||||
{
|
||||
#ifdef MALLOC_TRACE
|
||||
_mtrace_fp = fp ? fp : stderr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
malloc_trace_bin (n)
|
||||
int n;
|
||||
{
|
||||
#ifdef MALLOC_TRACE
|
||||
_malloc_trace_buckets[n] = 1;
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
150
lib/malloc/watch.c
Normal file
150
lib/malloc/watch.c
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/* watch.c - watchpoint functions for malloc */
|
||||
|
||||
/* Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "imalloc.h"
|
||||
|
||||
#ifdef MALLOC_WATCH
|
||||
#include "watch.h"
|
||||
|
||||
#define WATCH_MAX 32
|
||||
|
||||
int _malloc_nwatch;
|
||||
static PTR_T _malloc_watch_list[WATCH_MAX];
|
||||
|
||||
static void
|
||||
watch_warn (addr, file, line, type, data)
|
||||
PTR_T addr;
|
||||
const char *file;
|
||||
int line, type;
|
||||
unsigned long data;
|
||||
{
|
||||
char *tag;
|
||||
|
||||
if (type == W_ALLOC)
|
||||
tag = "allocated";
|
||||
else if (type == W_FREE)
|
||||
tag = "freed";
|
||||
else if (type == W_REALLOC)
|
||||
tag = "requesting resize";
|
||||
else if (type == W_RESIZED)
|
||||
tag = "just resized";
|
||||
else
|
||||
tag = "bug: unknown operation";
|
||||
|
||||
fprintf (stderr, "malloc: watch alert: %p %s ", addr, tag);
|
||||
if (data != (unsigned long)-1)
|
||||
fprintf (stderr, "(size %lu) ", data);
|
||||
fprintf (stderr, "from '%s:%d'\n", file ? file : "unknown", line);
|
||||
}
|
||||
|
||||
void
|
||||
_malloc_ckwatch (addr, file, line, type, data)
|
||||
PTR_T addr;
|
||||
const char *file;
|
||||
int line, type;
|
||||
unsigned long data;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = _malloc_nwatch - 1; i >= 0; i--)
|
||||
{
|
||||
if (_malloc_watch_list[i] == addr)
|
||||
{
|
||||
watch_warn (addr, file, line, type, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* MALLOC_WATCH */
|
||||
|
||||
PTR_T
|
||||
malloc_watch (addr)
|
||||
PTR_T addr;
|
||||
{
|
||||
register int i;
|
||||
PTR_T ret;
|
||||
|
||||
if (addr == 0)
|
||||
return addr;
|
||||
ret = (PTR_T)0;
|
||||
|
||||
#ifdef MALLOC_WATCH
|
||||
for (i = _malloc_nwatch - 1; i >= 0; i--)
|
||||
{
|
||||
if (_malloc_watch_list[i] == addr)
|
||||
break;
|
||||
}
|
||||
if (i < 0)
|
||||
{
|
||||
if (_malloc_nwatch == WATCH_MAX) /* full, take out first */
|
||||
{
|
||||
ret = _malloc_watch_list[0];
|
||||
_malloc_nwatch--;
|
||||
for (i = 0; i < _malloc_nwatch; i++)
|
||||
_malloc_watch_list[i] = _malloc_watch_list[i+1];
|
||||
}
|
||||
_malloc_watch_list[_malloc_nwatch++] = addr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Remove a watchpoint set on ADDR. If ADDR is NULL, remove all
|
||||
watchpoints. Returns ADDR if everything went OK, NULL if ADDR was
|
||||
not being watched. */
|
||||
PTR_T
|
||||
malloc_unwatch (addr)
|
||||
PTR_T addr;
|
||||
{
|
||||
#ifdef MALLOC_WATCH
|
||||
register int i;
|
||||
|
||||
if (addr == 0)
|
||||
{
|
||||
for (i = 0; i < _malloc_nwatch; i++)
|
||||
_malloc_watch_list[i] = (PTR_T)0;
|
||||
_malloc_nwatch = 0;
|
||||
return ((PTR_T)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < _malloc_nwatch; i++)
|
||||
{
|
||||
if (_malloc_watch_list[i] == addr)
|
||||
break;
|
||||
}
|
||||
if (i == _malloc_nwatch)
|
||||
return ((PTR_T)0); /* not found */
|
||||
/* shuffle everything from i+1 to end down 1 */
|
||||
_malloc_nwatch--;
|
||||
for ( ; i < _malloc_nwatch; i++)
|
||||
_malloc_watch_list[i] = _malloc_watch_list[i+1];
|
||||
return addr;
|
||||
}
|
||||
#else
|
||||
return ((PTR_T)0);
|
||||
#endif
|
||||
}
|
||||
39
lib/malloc/watch.h
Normal file
39
lib/malloc/watch.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* watch.h - definitions for tables for keeping track of allocated memory */
|
||||
|
||||
/* Copyright (C) 2001 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. */
|
||||
|
||||
#ifndef _MWATCH_H
|
||||
#define _MWATCH_H
|
||||
|
||||
#include "imalloc.h"
|
||||
|
||||
#ifdef MALLOC_WATCH
|
||||
|
||||
/* `Events' for watchpoints */
|
||||
|
||||
#define W_ALLOC 0x01
|
||||
#define W_FREE 0x02
|
||||
#define W_REALLOC 0x04
|
||||
#define W_RESIZED 0x08
|
||||
|
||||
extern int _malloc_nwatch;
|
||||
|
||||
extern void _malloc_ckwatch __P((PTR_T, const char *, int, int, unsigned long));
|
||||
|
||||
#endif /* MALLOC_WATCH */
|
||||
|
||||
#endif /* _MWATCH_H */
|
||||
|
|
@ -73,20 +73,22 @@ CSOURCES = $(srcdir)/readline.c $(srcdir)/funmap.c $(srcdir)/keymaps.c \
|
|||
$(srcdir)/history.c $(srcdir)/histsearch.c $(srcdir)/histexpand.c \
|
||||
$(srcdir)/histfile.c $(srcdir)/nls.c $(srcdir)/search.c \
|
||||
$(srcdir)/shell.c $(srcdir)/tilde.c $(srcdir)/savestring.c \
|
||||
$(srcdir)/compat.c
|
||||
$(srcdir)/text.c $(srcdir)/misc.c $(srcdir)/compat.c \
|
||||
$(srcdir)/mbutil.c
|
||||
|
||||
# The header files for this library.
|
||||
HSOURCES = readline.h rldefs.h chardefs.h keymaps.h history.h histlib.h \
|
||||
posixstat.h posixdir.h posixjmp.h tilde.h rlconf.h rltty.h \
|
||||
ansi_stdlib.h rlstdc.h tcap.h xmalloc.h rlprivate.h rlshell.h \
|
||||
rltypedefs.h
|
||||
rltypedefs.h rlmbutil.h
|
||||
|
||||
HISTOBJ = history.o histexpand.o histfile.o histsearch.o shell.o savestring.o
|
||||
HISTOBJ = history.o histexpand.o histfile.o histsearch.o shell.o savestring.o \
|
||||
mbutil.o
|
||||
TILDEOBJ = tilde.o
|
||||
OBJECTS = readline.o vi_mode.o funmap.o keymaps.o parens.o search.o \
|
||||
rltty.o complete.o bind.o isearch.o display.o signals.o \
|
||||
util.o kill.o undo.o macro.o input.o callback.o terminal.o \
|
||||
nls.o $(HISTOBJ) $(TILDEOBJ) xmalloc.o compat.o
|
||||
text.o nls.o misc.o $(HISTOBJ) $(TILDEOBJ) xmalloc.o compat.o
|
||||
|
||||
# The texinfo files which document this library.
|
||||
DOCSOURCE = doc/rlman.texinfo doc/rltech.texinfo doc/rluser.texinfo
|
||||
|
|
@ -203,6 +205,11 @@ macro.o: ansi_stdlib.h
|
|||
macro.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
|
||||
macro.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
|
||||
macro.o: history.h rlstdc.h
|
||||
mbutil.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h rlmbutil.h
|
||||
mbutil.o: readline.h keymaps.h rltypedefs.h chardefs.h rlstdc.h
|
||||
misc.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
|
||||
misc.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
|
||||
misc.o: history.h rlstdc.h ansi_stdlib.h
|
||||
nls.o: ansi_stdlib.h
|
||||
nls.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
|
||||
nls.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
|
||||
|
|
@ -228,6 +235,10 @@ terminal.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
|
|||
terminal.o: tcap.h
|
||||
terminal.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
|
||||
terminal.o: history.h rlstdc.h
|
||||
text.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
|
||||
text.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
|
||||
text.o: history.h rlstdc.h ansi_stdlib.h
|
||||
rltty.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
|
||||
tilde.o: ansi_stdlib.h
|
||||
tilde.o: ${BUILD_DIR}/config.h
|
||||
tilde.o: tilde.h
|
||||
|
|
@ -259,6 +270,8 @@ input.o: rlprivate.h
|
|||
isearch.o: rlprivate.h
|
||||
kill.o: rlprivate.h
|
||||
macro.o: rlprivate.h
|
||||
mbutil.o: rlprivate.h
|
||||
misc.o: rlprivate.h
|
||||
nls.o: rlprivate.h
|
||||
parens.o: rlprivate.h
|
||||
readline.o: rlprivate.h
|
||||
|
|
@ -266,6 +279,7 @@ rltty.o: rlprivate.h
|
|||
search.o: rlprivate.h
|
||||
signals.o: rlprivate.h
|
||||
terminal.o: rlprivate.h
|
||||
text.o: rlprivate.h
|
||||
undo.o: rlprivate.h
|
||||
util.o: rlprivate.h
|
||||
vi_mode.o: rlprivate.h
|
||||
|
|
@ -282,14 +296,31 @@ isearch.o: xmalloc.h
|
|||
keymaps.o: xmalloc.h
|
||||
kill.o: xmalloc.h
|
||||
macro.o: xmalloc.h
|
||||
mbutil.o: xmalloc.h
|
||||
misc.o: xmalloc.h
|
||||
readline.o: xmalloc.h
|
||||
savestring.o: xmalloc.h
|
||||
search.o: xmalloc.h
|
||||
shell.o: xmalloc.h
|
||||
tilde.o: xmalloc.h
|
||||
terminal.o: xmalloc.h
|
||||
text.o: xmalloc.h
|
||||
tilde.o: xmalloc.h
|
||||
undo.o: xmalloc.h
|
||||
util.o: xmalloc.h
|
||||
vi_mode.o: xmalloc.h
|
||||
xmalloc.o: xmalloc.h
|
||||
|
||||
complete.o: rlmbutil.h
|
||||
display.o: rlmbutil.h
|
||||
histexpand.o: rlmbutil.h
|
||||
input.o: rlmbutil.h
|
||||
isearch.o: rlmbutil.h
|
||||
mbutil.o: rlmbutil.h
|
||||
misc.o: rlmbutil.h
|
||||
readline.o: rlmbutil.h
|
||||
search.o: rlmbutil.h
|
||||
text.o: rlmbutil.h
|
||||
vi_mode.o: rlmbutil.h
|
||||
|
||||
# Rules for deficient makes, like SunOS and Solaris
|
||||
bind.o: bind.c
|
||||
|
|
@ -298,15 +329,13 @@ compat.o: compat.c
|
|||
complete.o: complete.c
|
||||
display.o: display.c
|
||||
funmap.o: funmap.c
|
||||
histexpand.o: histexpand.c
|
||||
histfile.o: histfile.c
|
||||
history.o: history.c
|
||||
histsearch.o: histsearch.c
|
||||
input.o: input.c
|
||||
isearch.o: isearch.c
|
||||
keymaps.o: keymaps.c emacs_keymap.c vi_keymap.c
|
||||
kill.o: kill.c
|
||||
macro.o: macro.c
|
||||
mbutil.o: mbutil.c
|
||||
misc.o: misc.c
|
||||
nls.o: nls.c
|
||||
parens.o: parens.c
|
||||
readline.o: readline.c
|
||||
|
|
@ -316,8 +345,14 @@ search.o: search.c
|
|||
shell.o: shell.c
|
||||
signals.o: signals.c
|
||||
terminal.o: terminal.c
|
||||
text.o: terminal.c
|
||||
tilde.o: tilde.c
|
||||
undo.o: undo.c
|
||||
util.o: util.c
|
||||
vi_mode.o: vi_mode.c
|
||||
xmalloc.o: xmalloc.c
|
||||
|
||||
histexpand.o: histexpand.c
|
||||
histfile.o: histfile.c
|
||||
history.o: history.c
|
||||
histsearch.o: histsearch.c
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ extern char *strchr (), *strrchr ();
|
|||
/* Variables exported by this file. */
|
||||
Keymap rl_binding_keymap;
|
||||
|
||||
static char *_rl_read_file PARAMS((char *, size_t *));
|
||||
static void _rl_init_file_error PARAMS((const char *));
|
||||
static int _rl_read_init_file PARAMS((const char *, int));
|
||||
static int glean_key_from_name PARAMS((char *));
|
||||
static int substring_member_of_array PARAMS((char *, const char **));
|
||||
|
|
@ -246,6 +248,9 @@ rl_generic_bind (type, keyseq, data, map)
|
|||
char *keys;
|
||||
int keys_len;
|
||||
register int i;
|
||||
KEYMAP_ENTRY k;
|
||||
|
||||
k.function = 0;
|
||||
|
||||
/* If no keys to bind to, exit right away. */
|
||||
if (!keyseq || !*keyseq)
|
||||
|
|
@ -269,7 +274,12 @@ rl_generic_bind (type, keyseq, data, map)
|
|||
/* Bind keys, making new keymaps as necessary. */
|
||||
for (i = 0; i < keys_len; i++)
|
||||
{
|
||||
unsigned char ic = keys[i];
|
||||
unsigned char uc = keys[i];
|
||||
int ic;
|
||||
|
||||
ic = uc;
|
||||
if (ic < 0 || ic >= KEYMAP_SIZE)
|
||||
return -1;
|
||||
|
||||
if (_rl_convert_meta_chars_to_ascii && META_CHAR (ic))
|
||||
{
|
||||
|
|
@ -282,18 +292,40 @@ rl_generic_bind (type, keyseq, data, map)
|
|||
{
|
||||
if (map[ic].type != ISKMAP)
|
||||
{
|
||||
if (map[ic].type == ISMACR)
|
||||
free ((char *)map[ic].function);
|
||||
/* We allow subsequences of keys. If a keymap is being
|
||||
created that will `shadow' an existing function or macro
|
||||
key binding, we save that keybinding into the ANYOTHERKEY
|
||||
index in the new map. The dispatch code will look there
|
||||
to find the function to execute if the subsequence is not
|
||||
matched. ANYOTHERKEY was chosen to be greater than
|
||||
UCHAR_MAX. */
|
||||
k = map[ic];
|
||||
|
||||
map[ic].type = ISKMAP;
|
||||
map[ic].function = KEYMAP_TO_FUNCTION (rl_make_bare_keymap());
|
||||
}
|
||||
map = FUNCTION_TO_KEYMAP (map, ic);
|
||||
/* The dispatch code will return this function if no matching
|
||||
key sequence is found in the keymap. This (with a little
|
||||
help from the dispatch code in readline.c) allows `a' to be
|
||||
mapped to something, `abc' to be mapped to something else,
|
||||
and the function bound to `a' to be executed when the user
|
||||
types `abx', leaving `bx' in the input queue. */
|
||||
if (k.function /* && k.type == ISFUNC */)
|
||||
{
|
||||
map[ANYOTHERKEY] = k;
|
||||
k.function = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (map[ic].type == ISMACR)
|
||||
free ((char *)map[ic].function);
|
||||
else if (map[ic].type == ISKMAP)
|
||||
{
|
||||
map = FUNCTION_TO_KEYMAP (map, ic);
|
||||
ic = ANYOTHERKEY;
|
||||
}
|
||||
|
||||
map[ic].function = KEYMAP_TO_FUNCTION (data);
|
||||
map[ic].type = type;
|
||||
|
|
@ -331,7 +363,7 @@ rl_translate_keyseq (seq, array, len)
|
|||
/* Handle special case of backwards define. */
|
||||
if (strncmp (&seq[i], "C-\\M-", 5) == 0)
|
||||
{
|
||||
array[l++] = ESC;
|
||||
array[l++] = ESC; /* ESC is meta-prefix */
|
||||
i += 5;
|
||||
array[l++] = CTRL (_rl_to_upper (seq[i]));
|
||||
if (seq[i] == '\0')
|
||||
|
|
@ -340,7 +372,7 @@ rl_translate_keyseq (seq, array, len)
|
|||
else if (c == 'M')
|
||||
{
|
||||
i++;
|
||||
array[l++] = ESC; /* XXX */
|
||||
array[l++] = ESC; /* ESC is meta-prefix */
|
||||
}
|
||||
else if (c == 'C')
|
||||
{
|
||||
|
|
@ -632,25 +664,15 @@ _rl_read_file (filename, sizep)
|
|||
i = read (file, buffer, file_size);
|
||||
close (file);
|
||||
|
||||
#if 0
|
||||
if (i < file_size)
|
||||
#else
|
||||
if (i < 0)
|
||||
#endif
|
||||
{
|
||||
free (buffer);
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
#if 0
|
||||
buffer[file_size] = '\0';
|
||||
if (sizep)
|
||||
*sizep = file_size;
|
||||
#else
|
||||
buffer[i] = '\0';
|
||||
if (sizep)
|
||||
*sizep = i;
|
||||
#endif
|
||||
|
||||
return (buffer);
|
||||
}
|
||||
|
|
@ -767,7 +789,7 @@ _rl_read_init_file (filename, include_level)
|
|||
|
||||
static void
|
||||
_rl_init_file_error (msg)
|
||||
char *msg;
|
||||
const char *msg;
|
||||
{
|
||||
if (currently_reading_init_file)
|
||||
fprintf (stderr, "readline: %s: line %d: %s\n", current_readline_init_file,
|
||||
|
|
@ -1075,7 +1097,7 @@ rl_parse_and_bind (string)
|
|||
/* Make VAR point to start of variable name. */
|
||||
while (*var && whitespace (*var)) var++;
|
||||
|
||||
/* Make value point to start of value string. */
|
||||
/* Make VALUE point to start of value string. */
|
||||
value = var;
|
||||
while (*value && !whitespace (*value)) value++;
|
||||
if (*value)
|
||||
|
|
@ -1240,6 +1262,7 @@ static struct {
|
|||
int flags;
|
||||
} boolean_varlist [] = {
|
||||
{ "blink-matching-paren", &rl_blink_matching_paren, V_SPECIAL },
|
||||
{ "byte-oriented", &rl_byte_oriented, 0 },
|
||||
{ "completion-ignore-case", &_rl_completion_case_fold, 0 },
|
||||
{ "convert-meta", &_rl_convert_meta_chars_to_ascii, 0 },
|
||||
{ "disable-completion", &rl_inhibit_completion, 0 },
|
||||
|
|
@ -1250,9 +1273,11 @@ static struct {
|
|||
{ "input-meta", &_rl_meta_flag, 0 },
|
||||
{ "mark-directories", &_rl_complete_mark_directories, 0 },
|
||||
{ "mark-modified-lines", &_rl_mark_modified_lines, 0 },
|
||||
{ "mark-symlinked-directories", &_rl_complete_mark_symlink_dirs, 0 },
|
||||
{ "match-hidden-files", &_rl_match_hidden_files, 0 },
|
||||
{ "meta-flag", &_rl_meta_flag, 0 },
|
||||
{ "output-meta", &_rl_output_meta_chars, 0 },
|
||||
{ "page-completions", &_rl_page_completions, 0 },
|
||||
{ "prefer-visible-bell", &_rl_prefer_visible_bell, V_SPECIAL },
|
||||
{ "print-completions-horizontally", &_rl_print_completions_horizontally, 0 },
|
||||
{ "show-all-if-ambiguous", &_rl_complete_show_all, 0 },
|
||||
|
|
@ -1264,7 +1289,7 @@ static struct {
|
|||
|
||||
static int
|
||||
find_boolean_var (name)
|
||||
char *name;
|
||||
const char *name;
|
||||
{
|
||||
register int i;
|
||||
|
||||
|
|
@ -1333,7 +1358,7 @@ static struct {
|
|||
|
||||
static int
|
||||
find_string_var (name)
|
||||
char *name;
|
||||
const char *name;
|
||||
{
|
||||
register int i;
|
||||
|
||||
|
|
@ -1659,17 +1684,18 @@ _rl_get_keyname (key)
|
|||
pairs for possible inclusion in an inputrc file, we don't want to
|
||||
do any special meta processing on KEY. */
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
/* XXX - Experimental */
|
||||
/* We might want to do this, but the old version of the code did not. */
|
||||
|
||||
/* If this is an escape character, we don't want to do any more processing.
|
||||
Just add the special ESC key sequence and return. */
|
||||
if (c == ESC)
|
||||
{
|
||||
keyseq[0] = '\\';
|
||||
keyseq[1] = 'e';
|
||||
keyseq[2] = '\0';
|
||||
return keyseq;
|
||||
keyname[0] = '\\';
|
||||
keyname[1] = 'e';
|
||||
keyname[2] = '\0';
|
||||
return keyname;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -1780,7 +1806,12 @@ rl_invoking_keyseqs_in_map (function, map)
|
|||
char *keyname = (char *)xmalloc (6 + strlen (seqs[i]));
|
||||
|
||||
if (key == ESC)
|
||||
#if 0
|
||||
sprintf (keyname, "\\e");
|
||||
#else
|
||||
/* XXX - experimental */
|
||||
sprintf (keyname, "\\M-");
|
||||
#endif
|
||||
else if (CTRL_CHAR (key))
|
||||
sprintf (keyname, "\\C-%c", _rl_to_lower (UNCTRL (key)));
|
||||
else if (key == RUBOUT)
|
||||
|
|
@ -1927,11 +1958,8 @@ _rl_macro_dumper_internal (print_readably, map, prefix)
|
|||
{
|
||||
case ISMACR:
|
||||
keyname = _rl_get_keyname (key);
|
||||
#if 0
|
||||
out = (char *)map[key].function;
|
||||
#else
|
||||
out = _rl_untranslate_macro_value ((char *)map[key].function);
|
||||
#endif
|
||||
|
||||
if (print_readably)
|
||||
fprintf (rl_outstream, "\"%s%s\": \"%s\"\n", prefix ? prefix : "",
|
||||
keyname,
|
||||
|
|
@ -1941,9 +1969,7 @@ _rl_macro_dumper_internal (print_readably, map, prefix)
|
|||
keyname,
|
||||
out ? out : "");
|
||||
free (keyname);
|
||||
#if 1
|
||||
free (out);
|
||||
#endif
|
||||
break;
|
||||
case ISFUNC:
|
||||
break;
|
||||
|
|
@ -2033,7 +2059,7 @@ rl_variable_dumper (print_readably)
|
|||
if (print_readably)
|
||||
fprintf (rl_outstream, "set comment-begin %s\n", _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT);
|
||||
else
|
||||
fprintf (rl_outstream, "comment-begin is set to `%s'\n", _rl_comment_begin ? _rl_comment_begin : "");
|
||||
fprintf (rl_outstream, "comment-begin is set to `%s'\n", _rl_comment_begin ? _rl_comment_begin : RL_COMMENT_BEGIN_DEFAULT);
|
||||
|
||||
/* completion-query-items */
|
||||
if (print_readably)
|
||||
|
|
@ -2047,15 +2073,6 @@ rl_variable_dumper (print_readably)
|
|||
else
|
||||
fprintf (rl_outstream, "editing-mode is set to `%s'\n", (rl_editing_mode == emacs_mode) ? "emacs" : "vi");
|
||||
|
||||
/* keymap */
|
||||
kname = rl_get_keymap_name (_rl_keymap);
|
||||
if (kname == 0)
|
||||
kname = rl_get_keymap_name_from_edit_mode ();
|
||||
if (print_readably)
|
||||
fprintf (rl_outstream, "set keymap %s\n", kname ? kname : "none");
|
||||
else
|
||||
fprintf (rl_outstream, "keymap is set to `%s'\n", kname ? kname : "none");
|
||||
|
||||
/* isearch-terminators */
|
||||
if (_rl_isearch_terminators)
|
||||
{
|
||||
|
|
@ -2070,6 +2087,15 @@ rl_variable_dumper (print_readably)
|
|||
|
||||
free (disp);
|
||||
}
|
||||
|
||||
/* keymap */
|
||||
kname = rl_get_keymap_name (_rl_keymap);
|
||||
if (kname == 0)
|
||||
kname = rl_get_keymap_name_from_edit_mode ();
|
||||
if (print_readably)
|
||||
fprintf (rl_outstream, "set keymap %s\n", kname ? kname : "none");
|
||||
else
|
||||
fprintf (rl_outstream, "keymap is set to `%s'\n", kname ? kname : "none");
|
||||
}
|
||||
|
||||
/* Print all of the current variables and their values to
|
||||
|
|
@ -2086,7 +2112,9 @@ rl_dump_variables (count, key)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. */
|
||||
/* Bind key sequence KEYSEQ to DEFAULT_FUNC if KEYSEQ is unbound. Right
|
||||
now, this is always used to attempt to bind the arrow keys, hence the
|
||||
check for rl_vi_movement_mode. */
|
||||
void
|
||||
_rl_bind_if_unbound (keyseq, default_func)
|
||||
const char *keyseq;
|
||||
|
|
@ -2097,7 +2125,11 @@ _rl_bind_if_unbound (keyseq, default_func)
|
|||
if (keyseq)
|
||||
{
|
||||
func = rl_function_of_keyseq (keyseq, _rl_keymap, (int *)NULL);
|
||||
#if defined (VI_MODE)
|
||||
if (!func || func == rl_do_lowercase_version || func == rl_vi_movement_mode)
|
||||
#else
|
||||
if (!func || func == rl_do_lowercase_version)
|
||||
#endif
|
||||
rl_set_key (keyseq, default_func, _rl_keymap);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,10 @@
|
|||
#endif
|
||||
|
||||
#ifdef CTRL
|
||||
#undef CTRL
|
||||
# undef CTRL
|
||||
#endif
|
||||
#ifdef UNCTRL
|
||||
# undef UNCTRL
|
||||
#endif
|
||||
|
||||
/* Some character stuff. */
|
||||
|
|
@ -76,6 +79,9 @@
|
|||
|
||||
#define NON_NEGATIVE(c) ((unsigned char)(c) == (c))
|
||||
|
||||
/* Some systems define these; we want our definitions. */
|
||||
#undef ISPRINT
|
||||
|
||||
#define ISALNUM(c) (IN_CTYPE_DOMAIN (c) && isalnum (c))
|
||||
#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
|
||||
#define ISDIGIT(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ extern int errno;
|
|||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
|
|
@ -100,10 +101,11 @@ static int stat_char PARAMS((char *));
|
|||
|
||||
static char *rl_quote_filename PARAMS((char *, int, char *));
|
||||
|
||||
static int get_y_or_n PARAMS((void));
|
||||
static void set_completion_defaults PARAMS((int));
|
||||
static int get_y_or_n PARAMS((int));
|
||||
static int _rl_internal_pager PARAMS((int));
|
||||
static char *printable_part PARAMS((char *));
|
||||
static int print_filename PARAMS((char *, char *));
|
||||
static char find_completion_word PARAMS((int *, int *));
|
||||
|
||||
static char **gen_completion_matches PARAMS((char *, int, int, rl_compentry_func_t *, int, int));
|
||||
|
||||
|
|
@ -116,7 +118,6 @@ static int compute_lcd_of_matches PARAMS((char **, int, const char *));
|
|||
static int postprocess_matches PARAMS((char ***, int));
|
||||
|
||||
static char *make_quoted_replacement PARAMS((char *, int, char *));
|
||||
static void free_match_list PARAMS((char **));
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
|
|
@ -132,6 +133,12 @@ int _rl_complete_show_all = 0;
|
|||
/* If non-zero, completed directory names have a slash appended. */
|
||||
int _rl_complete_mark_directories = 1;
|
||||
|
||||
/* If non-zero, the symlinked directory completion behavior introduced in
|
||||
readline-4.2a is disabled, and symlinks that point to directories have
|
||||
a slash appended (subject to the value of _rl_complete_mark_directories).
|
||||
This is user-settable via the mark-symlinked-directories variable. */
|
||||
int _rl_complete_mark_symlink_dirs = 0;
|
||||
|
||||
/* If non-zero, completions are printed horizontally in alphabetical order,
|
||||
like `ls -x'. */
|
||||
int _rl_print_completions_horizontally;
|
||||
|
|
@ -194,10 +201,12 @@ int rl_completion_type = 0;
|
|||
she is sure she wants to see them all. */
|
||||
int rl_completion_query_items = 100;
|
||||
|
||||
int _rl_page_completions = 1;
|
||||
|
||||
/* The basic list of characters that signal a break between words for the
|
||||
completer routine. The contents of this variable is what breaks words
|
||||
in the shell, i.e. " \t\n\"\\'`@$><=" */
|
||||
const char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{(";
|
||||
const char *rl_basic_word_break_characters = " \t\n\"\\'`@$><=;|&{("; /* }) */
|
||||
|
||||
/* List of basic quoting characters. */
|
||||
const char *rl_basic_quote_characters = "\"'";
|
||||
|
|
@ -264,10 +273,26 @@ rl_dequote_func_t *rl_filename_dequoting_function = (rl_dequote_func_t *)NULL;
|
|||
completer. */
|
||||
rl_linebuf_func_t *rl_char_is_quoted_p = (rl_linebuf_func_t *)NULL;
|
||||
|
||||
/* If non-zero, the completion functions don't append anything except a
|
||||
possible closing quote. This is set to 0 by rl_complete_internal and
|
||||
may be changed by an application-specific completion function. */
|
||||
int rl_completion_suppress_append = 0;
|
||||
|
||||
/* Character appended to completed words when at the end of the line. The
|
||||
default is a space. */
|
||||
int rl_completion_append_character = ' ';
|
||||
|
||||
/* If non-zero, a slash will be appended to completed filenames that are
|
||||
symbolic links to directory names, subject to the value of the
|
||||
mark-directories variable (which is user-settable). This exists so
|
||||
that application completion functions can override the user's preference
|
||||
(set via the mark-symlinked-directories variable) if appropriate.
|
||||
It's set to the value of _rl_complete_mark_symlink_dirs in
|
||||
rl_complete_internal before any application-specific completion
|
||||
function is called, so without that function doing anything, the user's
|
||||
preferences are honored. */
|
||||
int rl_completion_mark_symlink_dirs;
|
||||
|
||||
/* If non-zero, inhibit completion (temporarily). */
|
||||
int rl_inhibit_completion;
|
||||
|
||||
|
|
@ -290,7 +315,7 @@ rl_complete (ignore, invoking_key)
|
|||
int ignore, invoking_key;
|
||||
{
|
||||
if (rl_inhibit_completion)
|
||||
return (rl_insert (ignore, invoking_key));
|
||||
return (_rl_insert_char (ignore, invoking_key));
|
||||
else if (rl_last_func == rl_complete && !completion_changed_buffer)
|
||||
return (rl_complete_internal ('?'));
|
||||
else if (_rl_complete_show_all)
|
||||
|
|
@ -314,15 +339,49 @@ rl_insert_completions (ignore, invoking_key)
|
|||
return (rl_complete_internal ('*'));
|
||||
}
|
||||
|
||||
/* Return the correct value to pass to rl_complete_internal performing
|
||||
the same tests as rl_complete. This allows consecutive calls to an
|
||||
application's completion function to list possible completions and for
|
||||
an application-specific completion function to honor the
|
||||
show-all-if-ambiguous readline variable. */
|
||||
int
|
||||
rl_completion_mode (cfunc)
|
||||
rl_command_func_t *cfunc;
|
||||
{
|
||||
if (rl_last_func == cfunc && !completion_changed_buffer)
|
||||
return '?';
|
||||
else if (_rl_complete_show_all)
|
||||
return '!';
|
||||
else
|
||||
return TAB;
|
||||
}
|
||||
|
||||
/************************************/
|
||||
/* */
|
||||
/* Completion utility functions */
|
||||
/* */
|
||||
/************************************/
|
||||
|
||||
/* Set default values for readline word completion. These are the variables
|
||||
that application completion functions can change or inspect. */
|
||||
static void
|
||||
set_completion_defaults (what_to_do)
|
||||
int what_to_do;
|
||||
{
|
||||
/* Only the completion entry function can change these. */
|
||||
rl_filename_completion_desired = 0;
|
||||
rl_filename_quoting_desired = 1;
|
||||
rl_completion_type = what_to_do;
|
||||
rl_completion_suppress_append = 0;
|
||||
|
||||
/* The completion entry function may optionally change this. */
|
||||
rl_completion_mark_symlink_dirs = _rl_complete_mark_symlink_dirs;
|
||||
}
|
||||
|
||||
/* The user must press "y" or "n". Non-zero return means "y" pressed. */
|
||||
static int
|
||||
get_y_or_n ()
|
||||
get_y_or_n (for_pager)
|
||||
int for_pager;
|
||||
{
|
||||
int c;
|
||||
|
||||
|
|
@ -338,10 +397,32 @@ get_y_or_n ()
|
|||
return (0);
|
||||
if (c == ABORT_CHAR)
|
||||
_rl_abort_internal ();
|
||||
if (for_pager && (c == NEWLINE || c == RETURN))
|
||||
return (2);
|
||||
if (for_pager && (c == 'q' || c == 'Q'))
|
||||
return (0);
|
||||
rl_ding ();
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_rl_internal_pager (lines)
|
||||
int lines;
|
||||
{
|
||||
int i;
|
||||
|
||||
fprintf (rl_outstream, "--More--");
|
||||
fflush (rl_outstream);
|
||||
i = get_y_or_n (1);
|
||||
_rl_erase_entire_line ();
|
||||
if (i == 0)
|
||||
return -1;
|
||||
else if (i == 2)
|
||||
return (lines - 1);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined (VISIBLE_STATS)
|
||||
/* Return the character which best describes FILENAME.
|
||||
`@' for symbolic links
|
||||
|
|
@ -402,19 +483,41 @@ stat_char (filename)
|
|||
/* Return the portion of PATHNAME that should be output when listing
|
||||
possible completions. If we are hacking filename completion, we
|
||||
are only interested in the basename, the portion following the
|
||||
final slash. Otherwise, we return what we were passed. */
|
||||
final slash. Otherwise, we return what we were passed. Since
|
||||
printing empty strings is not very informative, if we're doing
|
||||
filename completion, and the basename is the empty string, we look
|
||||
for the previous slash and return the portion following that. If
|
||||
there's no previous slash, we just return what we were passed. */
|
||||
static char *
|
||||
printable_part (pathname)
|
||||
char *pathname;
|
||||
{
|
||||
char *temp;
|
||||
char *temp, *x;
|
||||
|
||||
temp = rl_filename_completion_desired ? strrchr (pathname, '/') : (char *)NULL;
|
||||
if (rl_filename_completion_desired == 0) /* don't need to do anything */
|
||||
return (pathname);
|
||||
|
||||
temp = strrchr (pathname, '/');
|
||||
#if defined (__MSDOS__)
|
||||
if (rl_filename_completion_desired && temp == 0 && ISALPHA ((unsigned char)pathname[0]) && pathname[1] == ':')
|
||||
if (temp == 0 && ISALPHA ((unsigned char)pathname[0]) && pathname[1] == ':')
|
||||
temp = pathname + 1;
|
||||
#endif
|
||||
return (temp ? ++temp : pathname);
|
||||
|
||||
if (temp == 0 || *temp == '\0')
|
||||
return (pathname);
|
||||
/* If the basename is NULL, we might have a pathname like '/usr/src/'.
|
||||
Look for a previous slash and, if one is found, return the portion
|
||||
following that slash. If there's no previous slash, just return the
|
||||
pathname we were passed. */
|
||||
else if (temp[1] == '\0')
|
||||
{
|
||||
for (x = temp - 1; x > pathname; x--)
|
||||
if (*x == '/')
|
||||
break;
|
||||
return ((*x == '/') ? x + 1 : pathname);
|
||||
}
|
||||
else
|
||||
return ++temp;
|
||||
}
|
||||
|
||||
/* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we
|
||||
|
|
@ -543,8 +646,8 @@ rl_quote_filename (s, rtype, qcp)
|
|||
quote, or backslash) anywhere in the string. DP, if non-null, is set to
|
||||
the value of the delimiter character that caused a word break. */
|
||||
|
||||
static char
|
||||
find_completion_word (fp, dp)
|
||||
char
|
||||
_rl_find_completion_word (fp, dp)
|
||||
int *fp, *dp;
|
||||
{
|
||||
int scan, end, found_quote, delimiter, pass_next, isbrk;
|
||||
|
|
@ -599,6 +702,8 @@ find_completion_word (fp, dp)
|
|||
found_quote |= RL_QF_SINGLE_QUOTE;
|
||||
else if (quote_char == '"')
|
||||
found_quote |= RL_QF_DOUBLE_QUOTE;
|
||||
else
|
||||
found_quote |= RL_QF_OTHER_QUOTE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -608,7 +713,11 @@ find_completion_word (fp, dp)
|
|||
/* We didn't find an unclosed quoted substring upon which to do
|
||||
completion, so use the word break characters to find the
|
||||
substring on which to complete. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
while (rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_ANY))
|
||||
#else
|
||||
while (--rl_point)
|
||||
#endif
|
||||
{
|
||||
scan = rl_line_buffer[rl_point];
|
||||
|
||||
|
|
@ -780,6 +889,11 @@ compute_lcd_of_matches (match_list, matches, text)
|
|||
{
|
||||
register int i, c1, c2, si;
|
||||
int low; /* Count of max-matched characters. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
int v;
|
||||
mbstate_t ps1, ps2;
|
||||
wchar_t wc1, wc2;
|
||||
#endif
|
||||
|
||||
/* If only one match, just use that. Otherwise, compare each
|
||||
member of the list with the next, finding out where they
|
||||
|
|
@ -793,12 +907,33 @@ compute_lcd_of_matches (match_list, matches, text)
|
|||
|
||||
for (i = 1, low = 100000; i < matches; i++)
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
memset (&ps1, 0, sizeof (mbstate_t));
|
||||
memset (&ps2, 0, sizeof (mbstate_t));
|
||||
}
|
||||
#endif
|
||||
if (_rl_completion_case_fold)
|
||||
{
|
||||
for (si = 0;
|
||||
(c1 = _rl_to_lower(match_list[i][si])) &&
|
||||
(c2 = _rl_to_lower(match_list[i + 1][si]));
|
||||
si++)
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
v = mbrtowc (&wc1, match_list[i]+si, strlen (match_list[i]+si), &ps1);
|
||||
mbrtowc (&wc2, match_list[i+1]+si, strlen (match_list[i+1]+si), &ps2);
|
||||
wc1 = towlower (wc1);
|
||||
wc2 = towlower (wc2);
|
||||
if (wc1 != wc2)
|
||||
break;
|
||||
else if (v > 1)
|
||||
si += v - 1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (c1 != c2)
|
||||
break;
|
||||
}
|
||||
|
|
@ -808,6 +943,17 @@ compute_lcd_of_matches (match_list, matches, text)
|
|||
(c1 = match_list[i][si]) &&
|
||||
(c2 = match_list[i + 1][si]);
|
||||
si++)
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
mbstate_t ps_back = ps1;
|
||||
if (!_rl_compare_chars (match_list[i], si, &ps1, match_list[i+1], si, &ps2))
|
||||
break;
|
||||
else if ((v = _rl_get_char_len (&match_list[i][si], &ps_back)) > 1)
|
||||
si += v - 1;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (c1 != c2)
|
||||
break;
|
||||
}
|
||||
|
|
@ -828,6 +974,8 @@ compute_lcd_of_matches (match_list, matches, text)
|
|||
{
|
||||
match_list[0] = (char *)xmalloc (low + 1);
|
||||
|
||||
/* XXX - this might need changes in the presence of multibyte chars */
|
||||
|
||||
/* If we are ignoring case, try to preserve the case of the string
|
||||
the user typed in the face of multiple matches differing in case. */
|
||||
if (_rl_completion_case_fold)
|
||||
|
|
@ -871,6 +1019,9 @@ postprocess_matches (matchesp, matching_filenames)
|
|||
|
||||
matches = *matchesp;
|
||||
|
||||
if (matches == 0)
|
||||
return 0;
|
||||
|
||||
/* It seems to me that in all the cases we handle we would like
|
||||
to ignore duplicate possiblilities. Scan for the text to
|
||||
insert being identical to the other completions. */
|
||||
|
|
@ -923,7 +1074,7 @@ rl_display_match_list (matches, len, max)
|
|||
char **matches;
|
||||
int len, max;
|
||||
{
|
||||
int count, limit, printed_len;
|
||||
int count, limit, printed_len, lines;
|
||||
int i, j, k, l;
|
||||
char *temp;
|
||||
|
||||
|
|
@ -951,6 +1102,7 @@ rl_display_match_list (matches, len, max)
|
|||
|
||||
rl_crlf ();
|
||||
|
||||
lines = 0;
|
||||
if (_rl_print_completions_horizontally == 0)
|
||||
{
|
||||
/* Print the sorted items, up-and-down alphabetically, like ls. */
|
||||
|
|
@ -972,6 +1124,13 @@ rl_display_match_list (matches, len, max)
|
|||
l += count;
|
||||
}
|
||||
rl_crlf ();
|
||||
lines++;
|
||||
if (_rl_page_completions && lines >= (_rl_screenheight - 1) && i < count)
|
||||
{
|
||||
lines = _rl_internal_pager (lines);
|
||||
if (lines < 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -985,7 +1144,16 @@ rl_display_match_list (matches, len, max)
|
|||
if (matches[i+1])
|
||||
{
|
||||
if (i && (limit > 1) && (i % limit) == 0)
|
||||
rl_crlf ();
|
||||
{
|
||||
rl_crlf ();
|
||||
lines++;
|
||||
if (_rl_page_completions && lines >= _rl_screenheight - 1)
|
||||
{
|
||||
lines = _rl_internal_pager (lines);
|
||||
if (lines < 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
for (k = 0; k < max - printed_len; k++)
|
||||
putc (' ', rl_outstream);
|
||||
|
|
@ -1057,7 +1225,7 @@ display_matches (matches)
|
|||
rl_crlf ();
|
||||
fprintf (rl_outstream, "Display all %d possibilities? (y or n)", len);
|
||||
fflush (rl_outstream);
|
||||
if (get_y_or_n () == 0)
|
||||
if (get_y_or_n (0) == 0)
|
||||
{
|
||||
rl_crlf ();
|
||||
|
||||
|
|
@ -1155,7 +1323,11 @@ insert_match (match, start, mtype, qc)
|
|||
default trailing character is a space. Returns the number of characters
|
||||
appended. If NONTRIVIAL_MATCH is set, we test for a symlink (if the OS
|
||||
has them) and don't add a suffix for a symlink to a directory. A
|
||||
nontrivial match is one that actually adds to the word being completed. */
|
||||
nontrivial match is one that actually adds to the word being completed.
|
||||
The variable rl_completion_mark_symlink_dirs controls this behavior
|
||||
(it's initially set to the what the user has chosen, indicated by the
|
||||
value of _rl_complete_mark_symlink_dirs, but may be modified by an
|
||||
application's completion function). */
|
||||
static int
|
||||
append_to_match (text, delimiter, quote_char, nontrivial_match)
|
||||
char *text;
|
||||
|
|
@ -1171,7 +1343,7 @@ append_to_match (text, delimiter, quote_char, nontrivial_match)
|
|||
|
||||
if (delimiter)
|
||||
temp_string[temp_string_index++] = delimiter;
|
||||
else if (rl_completion_append_character)
|
||||
else if (rl_completion_suppress_append == 0 && rl_completion_append_character)
|
||||
temp_string[temp_string_index++] = rl_completion_append_character;
|
||||
|
||||
temp_string[temp_string_index++] = '\0';
|
||||
|
|
@ -1179,11 +1351,21 @@ append_to_match (text, delimiter, quote_char, nontrivial_match)
|
|||
if (rl_filename_completion_desired)
|
||||
{
|
||||
filename = tilde_expand (text);
|
||||
s = nontrivial_match ? LSTAT (filename, &finfo) : stat (filename, &finfo);
|
||||
s = (nontrivial_match && rl_completion_mark_symlink_dirs == 0)
|
||||
? LSTAT (filename, &finfo)
|
||||
: stat (filename, &finfo);
|
||||
if (s == 0 && S_ISDIR (finfo.st_mode))
|
||||
{
|
||||
if (_rl_complete_mark_directories && rl_line_buffer[rl_point] != '/')
|
||||
rl_insert_text ("/");
|
||||
if (_rl_complete_mark_directories)
|
||||
{
|
||||
/* This is clumsy. Avoid putting in a double slash if point
|
||||
is at the end of the line and the previous character is a
|
||||
slash. */
|
||||
if (rl_point && rl_line_buffer[rl_point] == '\0' && rl_line_buffer[rl_point - 1] == '/')
|
||||
;
|
||||
else if (rl_line_buffer[rl_point] != '/')
|
||||
rl_insert_text ("/");
|
||||
}
|
||||
}
|
||||
#ifdef S_ISLNK
|
||||
/* Don't add anything if the filename is a symlink and resolves to a
|
||||
|
|
@ -1194,14 +1376,14 @@ append_to_match (text, delimiter, quote_char, nontrivial_match)
|
|||
#endif
|
||||
else
|
||||
{
|
||||
if (rl_point == rl_end)
|
||||
if (rl_point == rl_end && temp_string_index)
|
||||
rl_insert_text (temp_string);
|
||||
}
|
||||
free (filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rl_point == rl_end)
|
||||
if (rl_point == rl_end && temp_string_index)
|
||||
rl_insert_text (temp_string);
|
||||
}
|
||||
|
||||
|
|
@ -1247,12 +1429,15 @@ insert_all_matches (matches, point, qc)
|
|||
rl_end_undo_group ();
|
||||
}
|
||||
|
||||
static void
|
||||
free_match_list (matches)
|
||||
void
|
||||
_rl_free_match_list (matches)
|
||||
char **matches;
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (matches == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; matches[i]; i++)
|
||||
free (matches[i]);
|
||||
free (matches);
|
||||
|
|
@ -1276,10 +1461,8 @@ rl_complete_internal (what_to_do)
|
|||
char quote_char;
|
||||
|
||||
RL_SETSTATE(RL_STATE_COMPLETING);
|
||||
/* Only the completion entry function can change these. */
|
||||
rl_filename_completion_desired = 0;
|
||||
rl_filename_quoting_desired = 1;
|
||||
rl_completion_type = what_to_do;
|
||||
|
||||
set_completion_defaults (what_to_do);
|
||||
|
||||
saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL;
|
||||
our_func = rl_completion_entry_function
|
||||
|
|
@ -1294,7 +1477,7 @@ rl_complete_internal (what_to_do)
|
|||
if (rl_point)
|
||||
/* This (possibly) changes rl_point. If it returns a non-zero char,
|
||||
we know we have an open quote. */
|
||||
quote_char = find_completion_word (&found_quote, &delimiter);
|
||||
quote_char = _rl_find_completion_word (&found_quote, &delimiter);
|
||||
|
||||
start = rl_point;
|
||||
rl_point = end;
|
||||
|
|
@ -1310,6 +1493,7 @@ rl_complete_internal (what_to_do)
|
|||
{
|
||||
rl_ding ();
|
||||
FREE (saved_line_buffer);
|
||||
completion_changed_buffer = 0;
|
||||
RL_UNSETSTATE(RL_STATE_COMPLETING);
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -1375,7 +1559,7 @@ rl_complete_internal (what_to_do)
|
|||
return 1;
|
||||
}
|
||||
|
||||
free_match_list (matches);
|
||||
_rl_free_match_list (matches);
|
||||
|
||||
/* Check to see if the line has changed through all of this manipulation. */
|
||||
if (saved_line_buffer)
|
||||
|
|
@ -1735,15 +1919,13 @@ rl_menu_complete (count, ignore)
|
|||
/* Clean up from previous call, if any. */
|
||||
FREE (orig_text);
|
||||
if (matches)
|
||||
free_match_list (matches);
|
||||
_rl_free_match_list (matches);
|
||||
|
||||
match_list_index = match_list_size = 0;
|
||||
matches = (char **)NULL;
|
||||
|
||||
/* Only the completion entry function can change these. */
|
||||
rl_filename_completion_desired = 0;
|
||||
rl_filename_quoting_desired = 1;
|
||||
rl_completion_type = '%';
|
||||
set_completion_defaults ('%');
|
||||
|
||||
our_func = rl_completion_entry_function
|
||||
? rl_completion_entry_function
|
||||
|
|
@ -1757,7 +1939,7 @@ rl_menu_complete (count, ignore)
|
|||
if (rl_point)
|
||||
/* This (possibly) changes rl_point. If it returns a non-zero char,
|
||||
we know we have an open quote. */
|
||||
quote_char = find_completion_word (&found_quote, &delimiter);
|
||||
quote_char = _rl_find_completion_word (&found_quote, &delimiter);
|
||||
|
||||
orig_start = rl_point;
|
||||
rl_point = orig_end;
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
/* Termcap library stuff. */
|
||||
#include "tcap.h"
|
||||
|
|
@ -65,9 +66,16 @@ extern char *_rl_term_forward_char;
|
|||
static void update_line PARAMS((char *, char *, int, int, int, int));
|
||||
static void space_to_eol PARAMS((int));
|
||||
static void delete_chars PARAMS((int));
|
||||
static void insert_some_chars PARAMS((char *, int));
|
||||
static void insert_some_chars PARAMS((char *, int, int));
|
||||
static void cr PARAMS((void));
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
static int _rl_col_width PARAMS((char *, int, int));
|
||||
static int *_rl_wrapped_line;
|
||||
#else
|
||||
# define _rl_col_width(l, s, e) (((e) <= (s)) ? 0 : (e) - (s))
|
||||
#endif
|
||||
|
||||
static int *inv_lbreaks, *vis_lbreaks;
|
||||
static int inv_lbsize, vis_lbsize;
|
||||
|
||||
|
|
@ -359,6 +367,9 @@ init_line_structures (minsize)
|
|||
inv_lbsize = vis_lbsize = 256;
|
||||
inv_lbreaks = (int *)xmalloc (inv_lbsize * sizeof (int));
|
||||
vis_lbreaks = (int *)xmalloc (vis_lbsize * sizeof (int));
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
_rl_wrapped_line = (int *)xmalloc (vis_lbsize * sizeof (int));
|
||||
#endif
|
||||
inv_lbreaks[0] = vis_lbreaks[0] = 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -372,6 +383,13 @@ rl_redisplay ()
|
|||
int c_pos, inv_botlin, lb_botlin, lb_linenum;
|
||||
int newlines, lpos, temp;
|
||||
char *prompt_this_line;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
wchar_t wc;
|
||||
size_t wc_bytes;
|
||||
int wc_width;
|
||||
mbstate_t ps;
|
||||
int _rl_wrapped_multicolumn = 0;
|
||||
#endif
|
||||
|
||||
if (!readline_echoing_p)
|
||||
return;
|
||||
|
|
@ -472,7 +490,25 @@ rl_redisplay ()
|
|||
inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
#define CHECK_LPOS() \
|
||||
do { \
|
||||
lpos++; \
|
||||
if (lpos >= _rl_screenwidth) \
|
||||
{ \
|
||||
if (newlines >= (inv_lbsize - 2)) \
|
||||
{ \
|
||||
inv_lbsize *= 2; \
|
||||
inv_lbreaks = (int *)xrealloc (inv_lbreaks, inv_lbsize * sizeof (int)); \
|
||||
_rl_wrapped_line = (int *)xrealloc (_rl_wrapped_line, inv_lbsize * sizeof (int)); \
|
||||
} \
|
||||
inv_lbreaks[++newlines] = out; \
|
||||
_rl_wrapped_line[newlines] = _rl_wrapped_multicolumn; \
|
||||
lpos = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define CHECK_LPOS() \
|
||||
do { \
|
||||
lpos++; \
|
||||
|
|
@ -487,10 +523,14 @@ rl_redisplay ()
|
|||
lpos = 0; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
/* inv_lbreaks[i] is where line i starts in the buffer. */
|
||||
inv_lbreaks[newlines = 0] = 0;
|
||||
lpos = out - wrap_offset;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
memset (_rl_wrapped_line, 0, vis_lbsize);
|
||||
#endif
|
||||
|
||||
/* prompt_invis_chars_first_line is the number of invisible characters in
|
||||
the first physical line of the prompt.
|
||||
|
|
@ -508,7 +548,11 @@ rl_redisplay ()
|
|||
probably too much work for the benefit gained. How many people have
|
||||
prompts that exceed two physical lines? */
|
||||
temp = ((newlines + 1) * _rl_screenwidth) +
|
||||
#if 0
|
||||
((newlines == 0) ? prompt_invis_chars_first_line : 0) +
|
||||
#else
|
||||
((newlines == 0 && local_prompt_prefix == 0) ? prompt_invis_chars_first_line : 0) +
|
||||
#endif
|
||||
((newlines == 1) ? wrap_offset : 0);
|
||||
|
||||
inv_lbreaks[++newlines] = temp;
|
||||
|
|
@ -523,10 +567,44 @@ rl_redisplay ()
|
|||
It maintains an array of line breaks for display (inv_lbreaks).
|
||||
This handles expanding tabs for display and displaying meta characters. */
|
||||
lb_linenum = 0;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
in = 0;
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
wc_bytes = mbrtowc (&wc, rl_line_buffer, rl_end, &ps);
|
||||
}
|
||||
else
|
||||
wc_bytes = 1;
|
||||
while (in < rl_end)
|
||||
#else
|
||||
for (in = 0; in < rl_end; in++)
|
||||
#endif
|
||||
{
|
||||
c = (unsigned char)rl_line_buffer[in];
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
if (wc_bytes == (size_t)-1 || wc_bytes == (size_t)-2)
|
||||
{
|
||||
/* Byte sequence is invalid or shortened. Assume that the
|
||||
first byte represents a character. */
|
||||
wc_bytes = 1;
|
||||
/* Assume that a character occupies a single column. */
|
||||
wc_width = 1;
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
}
|
||||
else if (wc_bytes == (size_t)0)
|
||||
break; /* Found '\0' */
|
||||
else
|
||||
{
|
||||
temp = wcwidth (wc);
|
||||
wc_width = (temp < 0) ? 1 : temp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (out + 8 >= line_size) /* XXX - 8 for \t */
|
||||
{
|
||||
line_size *= 2;
|
||||
|
|
@ -541,7 +619,11 @@ rl_redisplay ()
|
|||
lb_linenum = newlines;
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (META_CHAR (c) && _rl_output_meta_chars == 0) /* XXX - clean up */
|
||||
#else
|
||||
if (META_CHAR (c))
|
||||
#endif
|
||||
{
|
||||
if (_rl_output_meta_chars == 0)
|
||||
{
|
||||
|
|
@ -610,9 +692,52 @@ rl_redisplay ()
|
|||
}
|
||||
else
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
register int i;
|
||||
|
||||
_rl_wrapped_multicolumn = 0;
|
||||
|
||||
if (_rl_screenwidth < lpos + wc_width)
|
||||
for (i = lpos; i < _rl_screenwidth; i++)
|
||||
{
|
||||
/* The space will be removed in update_line() */
|
||||
line[out++] = ' ';
|
||||
_rl_wrapped_multicolumn++;
|
||||
CHECK_LPOS();
|
||||
}
|
||||
if (in == rl_point)
|
||||
{
|
||||
c_pos = out;
|
||||
lb_linenum = newlines;
|
||||
}
|
||||
for (i = in; i < in+wc_bytes; i++)
|
||||
line[out++] = rl_line_buffer[i];
|
||||
for (i = 0; i < wc_width; i++)
|
||||
CHECK_LPOS();
|
||||
}
|
||||
else
|
||||
{
|
||||
line[out++] = c;
|
||||
CHECK_LPOS();
|
||||
}
|
||||
#else
|
||||
line[out++] = c;
|
||||
CHECK_LPOS();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
in += wc_bytes;
|
||||
wc_bytes = mbrtowc (&wc, rl_line_buffer + in, rl_end - in, &ps);
|
||||
}
|
||||
else
|
||||
in++;
|
||||
#endif
|
||||
|
||||
}
|
||||
line[out] = '\0';
|
||||
if (c_pos < 0)
|
||||
|
|
@ -650,7 +775,12 @@ rl_redisplay ()
|
|||
only display a screenful. We should display the last screen,
|
||||
not the first. */
|
||||
if (out >= _rl_screenchars)
|
||||
out = _rl_screenchars - 1;
|
||||
{
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
out = _rl_find_prev_mbchar (line, _rl_screenchars, MB_FIND_ANY);
|
||||
else
|
||||
out = _rl_screenchars - 1;
|
||||
}
|
||||
|
||||
/* The first line is at character position 0 in the buffer. The
|
||||
second and subsequent lines start at inv_lbreaks[N], offset by
|
||||
|
|
@ -736,7 +866,10 @@ rl_redisplay ()
|
|||
tputs (_rl_term_cr, 1, _rl_output_character_function);
|
||||
#endif
|
||||
_rl_output_some_chars (local_prompt, nleft);
|
||||
_rl_last_c_pos = nleft;
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
_rl_last_c_pos = _rl_col_width(local_prompt, 0, nleft);
|
||||
else
|
||||
_rl_last_c_pos = nleft;
|
||||
}
|
||||
|
||||
/* Where on that line? And where does that line start
|
||||
|
|
@ -752,10 +885,15 @@ rl_redisplay ()
|
|||
if (wrap_offset && cursor_linenum == 0 && nleft < _rl_last_c_pos)
|
||||
{
|
||||
_rl_backspace (_rl_last_c_pos - nleft);
|
||||
_rl_last_c_pos = nleft;
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
_rl_last_c_pos = _rl_col_width (&visible_line[pos], 0, nleft);
|
||||
else
|
||||
_rl_last_c_pos = nleft;
|
||||
}
|
||||
|
||||
if (nleft != _rl_last_c_pos)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
_rl_move_cursor_relative (nleft, &invisible_line[pos]);
|
||||
else if (nleft != _rl_last_c_pos)
|
||||
_rl_move_cursor_relative (nleft, &invisible_line[pos]);
|
||||
}
|
||||
}
|
||||
|
|
@ -900,6 +1038,11 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
|
|||
register char *ofd, *ols, *oe, *nfd, *nls, *ne;
|
||||
int temp, lendiff, wsatend, od, nd;
|
||||
int current_invis_chars;
|
||||
int col_lendiff, col_temp;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
mbstate_t ps_new, ps_old;
|
||||
int new_offset, old_offset, tmp;
|
||||
#endif
|
||||
|
||||
/* If we're at the right edge of a terminal that supports xn, we're
|
||||
ready to wrap around, so do so. This fixes problems with knowing
|
||||
|
|
@ -908,19 +1051,97 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
|
|||
position of the cursor. */
|
||||
temp = _rl_last_c_pos - W_OFFSET(_rl_last_v_pos, visible_wrap_offset);
|
||||
if (temp == _rl_screenwidth && _rl_term_autowrap && !_rl_horizontal_scroll_mode
|
||||
&& _rl_last_v_pos == current_line - 1)
|
||||
&& _rl_last_v_pos == current_line - 1)
|
||||
{
|
||||
if (new[0])
|
||||
putc (new[0], rl_outstream);
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
wchar_t wc;
|
||||
mbstate_t ps;
|
||||
int tempwidth, bytes;
|
||||
size_t ret;
|
||||
|
||||
/* This fixes only double-column characters, but if the wrapped
|
||||
character comsumes more than three columns, spaces will be
|
||||
inserted in the string buffer. */
|
||||
if (_rl_wrapped_line[current_line] > 0)
|
||||
_rl_clear_to_eol (_rl_wrapped_line[current_line]);
|
||||
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
ret = mbrtowc (&wc, new, MB_CUR_MAX, &ps);
|
||||
if (ret == (size_t)-1 || ret == (size_t)-2)
|
||||
{
|
||||
tempwidth = 1;
|
||||
ret = 1;
|
||||
}
|
||||
else if (ret == 0)
|
||||
tempwidth = 0;
|
||||
else
|
||||
tempwidth = wcwidth (wc);
|
||||
|
||||
if (tempwidth > 0)
|
||||
{
|
||||
int count;
|
||||
bytes = ret;
|
||||
for (count = 0; count < bytes; count++)
|
||||
putc (new[count], rl_outstream);
|
||||
_rl_last_c_pos = tempwidth;
|
||||
_rl_last_v_pos++;
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
ret = mbrtowc (&wc, old, MB_CUR_MAX, &ps);
|
||||
if (ret != 0 && bytes != 0)
|
||||
{
|
||||
if (ret == (size_t)-1 || ret == (size_t)-2)
|
||||
memmove (old+bytes, old+1, strlen (old+1));
|
||||
else
|
||||
memmove (old+bytes, old+ret, strlen (old+ret));
|
||||
memcpy (old, new, bytes);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
putc (' ', rl_outstream);
|
||||
_rl_last_c_pos = 1;
|
||||
_rl_last_v_pos++;
|
||||
if (old[0] && new[0])
|
||||
old[0] = new[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
putc (' ', rl_outstream);
|
||||
_rl_last_c_pos = 1; /* XXX */
|
||||
_rl_last_v_pos++;
|
||||
if (old[0] && new[0])
|
||||
old[0] = new[0];
|
||||
#endif
|
||||
{
|
||||
if (new[0])
|
||||
putc (new[0], rl_outstream);
|
||||
else
|
||||
putc (' ', rl_outstream);
|
||||
_rl_last_c_pos = 1; /* XXX */
|
||||
_rl_last_v_pos++;
|
||||
if (old[0] && new[0])
|
||||
old[0] = new[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Find first difference. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
memset (&ps_new, 0, sizeof(mbstate_t));
|
||||
memset (&ps_old, 0, sizeof(mbstate_t));
|
||||
|
||||
new_offset = old_offset = 0;
|
||||
for (ofd = old, nfd = new;
|
||||
(ofd - old < omax) && *ofd &&
|
||||
_rl_compare_chars(old, old_offset, &ps_old, new, new_offset, &ps_new); )
|
||||
{
|
||||
old_offset = _rl_find_next_mbchar (old, old_offset, 1, MB_FIND_ANY);
|
||||
new_offset = _rl_find_next_mbchar (new, new_offset, 1, MB_FIND_ANY);
|
||||
ofd = old + old_offset;
|
||||
nfd = new + new_offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
for (ofd = old, nfd = new;
|
||||
(ofd - old < omax) && *ofd && (*ofd == *nfd);
|
||||
ofd++, nfd++)
|
||||
|
|
@ -937,6 +1158,33 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
|
|||
return;
|
||||
|
||||
wsatend = 1; /* flag for trailing whitespace */
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
ols = old + _rl_find_prev_mbchar (old, oe - old, MB_FIND_ANY);
|
||||
nls = new + _rl_find_prev_mbchar (new, ne - new, MB_FIND_ANY);
|
||||
while ((ols > ofd) && (nls > nfd))
|
||||
{
|
||||
memset (&ps_old, 0, sizeof (mbstate_t));
|
||||
memset (&ps_new, 0, sizeof (mbstate_t));
|
||||
|
||||
_rl_adjust_point (old, ols - old, &ps_old);
|
||||
_rl_adjust_point (new, nls - new, &ps_new);
|
||||
|
||||
if (_rl_compare_chars (old, ols - old, &ps_old, new, nls - new, &ps_new) == 0)
|
||||
break;
|
||||
|
||||
if (*ols == ' ')
|
||||
wsatend = 0;
|
||||
|
||||
ols = old + _rl_find_prev_mbchar (old, ols - old, MB_FIND_ANY);
|
||||
nls = new + _rl_find_prev_mbchar (new, nls - new, MB_FIND_ANY);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
ols = oe - 1; /* find last same */
|
||||
nls = ne - 1;
|
||||
while ((ols > ofd) && (nls > nfd) && (*ols == *nls))
|
||||
|
|
@ -946,18 +1194,38 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
|
|||
ols--;
|
||||
nls--;
|
||||
}
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (wsatend)
|
||||
{
|
||||
ols = oe;
|
||||
nls = ne;
|
||||
}
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
/* This may not work for stateful encoding, but who cares? To handle
|
||||
stateful encoding properly, we have to scan each string from the
|
||||
beginning and compare. */
|
||||
else if (_rl_compare_chars (ols, 0, NULL, nls, 0, NULL) == 0)
|
||||
#else
|
||||
else if (*ols != *nls)
|
||||
#endif
|
||||
{
|
||||
if (*ols) /* don't step past the NUL */
|
||||
ols++;
|
||||
{
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
ols = old + _rl_find_next_mbchar (old, ols - old, 1, MB_FIND_ANY);
|
||||
else
|
||||
ols++;
|
||||
}
|
||||
if (*nls)
|
||||
nls++;
|
||||
{
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
nls = new + _rl_find_next_mbchar (new, nls - new, 1, MB_FIND_ANY);
|
||||
else
|
||||
nls++;
|
||||
}
|
||||
}
|
||||
|
||||
/* count of invisible characters in the current invisible line. */
|
||||
|
|
@ -993,24 +1261,50 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
|
|||
tputs (_rl_term_cr, 1, _rl_output_character_function);
|
||||
#endif
|
||||
_rl_output_some_chars (local_prompt, lendiff);
|
||||
_rl_last_c_pos = lendiff;
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
_rl_last_c_pos = _rl_col_width (local_prompt, 0, lendiff);
|
||||
else
|
||||
_rl_last_c_pos = lendiff;
|
||||
}
|
||||
|
||||
_rl_move_cursor_relative (od, old);
|
||||
|
||||
/* if (len (new) > len (old)) */
|
||||
/* if (len (new) > len (old))
|
||||
lendiff == difference in buffer
|
||||
col_lendiff == difference on screen
|
||||
When not using multibyte characters, these are equal */
|
||||
lendiff = (nls - nfd) - (ols - ofd);
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
col_lendiff = _rl_col_width (new, nfd - new, nls - new) - _rl_col_width (old, ofd - old, ols - old);
|
||||
else
|
||||
col_lendiff = lendiff;
|
||||
|
||||
/* If we are changing the number of invisible characters in a line, and
|
||||
the spot of first difference is before the end of the invisible chars,
|
||||
lendiff needs to be adjusted. */
|
||||
if (current_line == 0 && !_rl_horizontal_scroll_mode &&
|
||||
current_invis_chars != visible_wrap_offset)
|
||||
lendiff += visible_wrap_offset - current_invis_chars;
|
||||
{
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
lendiff += visible_wrap_offset - current_invis_chars;
|
||||
col_lendiff += visible_wrap_offset - current_invis_chars;
|
||||
}
|
||||
else
|
||||
{
|
||||
lendiff += visible_wrap_offset - current_invis_chars;
|
||||
col_lendiff = lendiff;
|
||||
}
|
||||
}
|
||||
|
||||
/* Insert (diff (len (old), len (new)) ch. */
|
||||
temp = ne - nfd;
|
||||
if (lendiff > 0)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
col_temp = _rl_col_width (new, nfd - new, ne - new);
|
||||
else
|
||||
col_temp = temp;
|
||||
|
||||
if (col_lendiff > 0) /* XXX - was lendiff */
|
||||
{
|
||||
/* Non-zero if we're increasing the number of lines. */
|
||||
int gl = current_line >= _rl_vis_botlin && inv_botlin > _rl_vis_botlin;
|
||||
|
|
@ -1018,7 +1312,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
|
|||
use the terminal's capabilities. If we're growing the number
|
||||
of lines, make sure we actually cause the new line to wrap
|
||||
around on auto-wrapping terminals. */
|
||||
if (_rl_terminal_can_insert && ((2 * temp) >= lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl))
|
||||
if (_rl_terminal_can_insert && ((2 * col_temp) >= col_lendiff || _rl_term_IC) && (!_rl_term_autowrap || !gl))
|
||||
{
|
||||
/* If lendiff > prompt_visible_length and _rl_last_c_pos == 0 and
|
||||
_rl_horizontal_scroll_mode == 1, inserting the characters with
|
||||
|
|
@ -1027,8 +1321,8 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
|
|||
if (*ols && (!_rl_horizontal_scroll_mode || _rl_last_c_pos > 0 ||
|
||||
lendiff <= prompt_visible_length || !current_invis_chars))
|
||||
{
|
||||
insert_some_chars (nfd, lendiff);
|
||||
_rl_last_c_pos += lendiff;
|
||||
insert_some_chars (nfd, lendiff, col_lendiff);
|
||||
_rl_last_c_pos += col_lendiff;
|
||||
}
|
||||
else if (*ols == 0)
|
||||
{
|
||||
|
|
@ -1037,7 +1331,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
|
|||
/* However, this screws up the rest of this block, which
|
||||
assumes you've done the insert because you can. */
|
||||
_rl_output_some_chars (nfd, lendiff);
|
||||
_rl_last_c_pos += lendiff;
|
||||
_rl_last_c_pos += col_lendiff;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -1045,7 +1339,7 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
|
|||
the end. We have invisible characters in this line. This
|
||||
is a dumb update. */
|
||||
_rl_output_some_chars (nfd, temp);
|
||||
_rl_last_c_pos += temp;
|
||||
_rl_last_c_pos += col_temp;
|
||||
return;
|
||||
}
|
||||
/* Copy (new) chars to screen from first diff to last match. */
|
||||
|
|
@ -1053,37 +1347,41 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
|
|||
if ((temp - lendiff) > 0)
|
||||
{
|
||||
_rl_output_some_chars (nfd + lendiff, temp - lendiff);
|
||||
_rl_last_c_pos += temp - lendiff;
|
||||
#if 0
|
||||
_rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-lendiff) - col_lendiff;
|
||||
#else
|
||||
_rl_last_c_pos += _rl_col_width (nfd+lendiff, 0, temp-col_lendiff);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* cannot insert chars, write to EOL */
|
||||
_rl_output_some_chars (nfd, temp);
|
||||
_rl_last_c_pos += temp;
|
||||
_rl_last_c_pos += col_temp;
|
||||
}
|
||||
}
|
||||
else /* Delete characters from line. */
|
||||
{
|
||||
/* If possible and inexpensive to use terminal deletion, then do so. */
|
||||
if (_rl_term_dc && (2 * temp) >= -lendiff)
|
||||
if (_rl_term_dc && (2 * col_temp) >= -col_lendiff)
|
||||
{
|
||||
/* If all we're doing is erasing the invisible characters in the
|
||||
prompt string, don't bother. It screws up the assumptions
|
||||
about what's on the screen. */
|
||||
if (_rl_horizontal_scroll_mode && _rl_last_c_pos == 0 &&
|
||||
-lendiff == visible_wrap_offset)
|
||||
lendiff = 0;
|
||||
col_lendiff = 0;
|
||||
|
||||
if (lendiff)
|
||||
delete_chars (-lendiff); /* delete (diff) characters */
|
||||
if (col_lendiff)
|
||||
delete_chars (-col_lendiff); /* delete (diff) characters */
|
||||
|
||||
/* Copy (new) chars to screen from first diff to last match */
|
||||
temp = nls - nfd;
|
||||
if (temp > 0)
|
||||
{
|
||||
_rl_output_some_chars (nfd, temp);
|
||||
_rl_last_c_pos += temp;
|
||||
_rl_last_c_pos += _rl_col_width (nfd, 0, temp);;
|
||||
}
|
||||
}
|
||||
/* Otherwise, print over the existing material. */
|
||||
|
|
@ -1092,15 +1390,20 @@ update_line (old, new, current_line, omax, nmax, inv_botlin)
|
|||
if (temp > 0)
|
||||
{
|
||||
_rl_output_some_chars (nfd, temp);
|
||||
_rl_last_c_pos += temp;
|
||||
_rl_last_c_pos += col_temp;
|
||||
}
|
||||
lendiff = (oe - old) - (ne - new);
|
||||
if (lendiff)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
col_lendiff = _rl_col_width (old, 0, oe - old) - _rl_col_width (new, 0, ne - new);
|
||||
else
|
||||
col_lendiff = lendiff;
|
||||
|
||||
if (col_lendiff)
|
||||
{
|
||||
if (_rl_term_autowrap && current_line < inv_botlin)
|
||||
space_to_eol (lendiff);
|
||||
space_to_eol (col_lendiff);
|
||||
else
|
||||
_rl_clear_to_eol (lendiff);
|
||||
_rl_clear_to_eol (col_lendiff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1146,7 +1449,10 @@ rl_on_new_line_with_prompt ()
|
|||
prompt_last_line = rl_prompt;
|
||||
|
||||
l = strlen (prompt_last_line);
|
||||
_rl_last_c_pos = l;
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
_rl_last_c_pos = _rl_col_width (prompt_last_line, 0, l);
|
||||
else
|
||||
_rl_last_c_pos = l;
|
||||
|
||||
/* Dissect prompt_last_line into screen lines. Note that here we have
|
||||
to use the real screenwidth. Readline's notion of screenwidth might be
|
||||
|
|
@ -1201,7 +1507,14 @@ _rl_move_cursor_relative (new, data)
|
|||
register int i;
|
||||
|
||||
/* If we don't have to do anything, then return. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
/* If we have multibyte characters, NEW is indexed by the buffer point in
|
||||
a multibyte string, but _rl_last_c_pos is the display position. In
|
||||
this case, NEW's display position is not obvious. */
|
||||
if ((MB_CUR_MAX == 1 || rl_byte_oriented ) && _rl_last_c_pos == new) return;
|
||||
#else
|
||||
if (_rl_last_c_pos == new) return;
|
||||
#endif
|
||||
|
||||
/* It may be faster to output a CR, and then move forwards instead
|
||||
of moving backwards. */
|
||||
|
|
@ -1231,19 +1544,69 @@ _rl_move_cursor_relative (new, data)
|
|||
data is underneath the cursor. */
|
||||
#if defined (HACK_TERMCAP_MOTION)
|
||||
if (_rl_term_forward_char)
|
||||
for (i = _rl_last_c_pos; i < new; i++)
|
||||
tputs (_rl_term_forward_char, 1, _rl_output_character_function);
|
||||
{
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
int width;
|
||||
width = _rl_col_width (data, _rl_last_c_pos, new);
|
||||
for (i = 0; i < width; i++)
|
||||
tputs (_rl_term_forward_char, 1, _rl_output_character_function);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = _rl_last_c_pos; i < new; i++)
|
||||
tputs (_rl_term_forward_char, 1, _rl_output_character_function);
|
||||
}
|
||||
}
|
||||
else if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
tputs (_rl_term_cr, 1, _rl_output_character_function);
|
||||
for (i = 0; i < new; i++)
|
||||
putc (data[i], rl_outstream);
|
||||
}
|
||||
else
|
||||
for (i = _rl_last_c_pos; i < new; i++)
|
||||
putc (data[i], rl_outstream);
|
||||
#else
|
||||
for (i = _rl_last_c_pos; i < new; i++)
|
||||
putc (data[i], rl_outstream);
|
||||
#endif /* HACK_TERMCAP_MOTION */
|
||||
|
||||
#else /* !HACK_TERMCAP_MOTION */
|
||||
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
tputs (_rl_term_cr, 1, _rl_output_character_function);
|
||||
for (i = 0; i < new; i++)
|
||||
putc (data[i], rl_outstream);
|
||||
}
|
||||
else
|
||||
for (i = _rl_last_c_pos; i < new; i++)
|
||||
putc (data[i], rl_outstream);
|
||||
|
||||
#endif /* !HACK_TERMCAP_MOTION */
|
||||
|
||||
}
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
/* NEW points to the buffer point, but _rl_last_c_pos is the display point.
|
||||
The byte length of the string is probably bigger than the column width
|
||||
of the string, which means that if NEW == _rl_last_c_pos, then NEW's
|
||||
display point is less than _rl_last_c_pos. */
|
||||
else if (_rl_last_c_pos >= new)
|
||||
#else
|
||||
else if (_rl_last_c_pos > new)
|
||||
_rl_backspace (_rl_last_c_pos - new);
|
||||
_rl_last_c_pos = new;
|
||||
#endif
|
||||
{
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
tputs (_rl_term_cr, 1, _rl_output_character_function);
|
||||
for (i = 0; i < new; i++)
|
||||
putc (data[i], rl_outstream);
|
||||
}
|
||||
else
|
||||
_rl_backspace (_rl_last_c_pos - new);
|
||||
}
|
||||
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
_rl_last_c_pos = _rl_col_width (data, 0, new);
|
||||
else
|
||||
_rl_last_c_pos = new;
|
||||
}
|
||||
|
||||
/* PWP: move the cursor up or down. */
|
||||
|
|
@ -1514,17 +1877,23 @@ _rl_clear_screen ()
|
|||
rl_crlf ();
|
||||
}
|
||||
|
||||
/* Insert COUNT characters from STRING to the output stream. */
|
||||
/* Insert COUNT characters from STRING to the output stream at column COL. */
|
||||
static void
|
||||
insert_some_chars (string, count)
|
||||
insert_some_chars (string, count, col)
|
||||
char *string;
|
||||
int count;
|
||||
int count, col;
|
||||
{
|
||||
/* DEBUGGING */
|
||||
if (MB_CUR_MAX == 1 || rl_byte_oriented)
|
||||
if (count != col)
|
||||
fprintf(stderr, "readline: debug: insert_some_chars: count (%d) != col (%d)\n", count, col);
|
||||
|
||||
/* If IC is defined, then we do not have to "enter" insert mode. */
|
||||
if (_rl_term_IC)
|
||||
{
|
||||
char *buffer;
|
||||
buffer = tgoto (_rl_term_IC, 0, count);
|
||||
|
||||
buffer = tgoto (_rl_term_IC, 0, col);
|
||||
tputs (buffer, 1, _rl_output_character_function);
|
||||
_rl_output_some_chars (string, count);
|
||||
}
|
||||
|
|
@ -1540,7 +1909,7 @@ insert_some_chars (string, count)
|
|||
use that first to open up the space. */
|
||||
if (_rl_term_ic && *_rl_term_ic)
|
||||
{
|
||||
for (i = count; i--; )
|
||||
for (i = col; i--; )
|
||||
tputs (_rl_term_ic, 1, _rl_output_character_function);
|
||||
}
|
||||
|
||||
|
|
@ -1595,11 +1964,8 @@ _rl_update_final ()
|
|||
if (full_lines && _rl_term_autowrap && (VIS_LLEN(_rl_vis_botlin) == _rl_screenwidth))
|
||||
{
|
||||
char *last_line;
|
||||
#if 0
|
||||
last_line = &visible_line[inv_lbreaks[_rl_vis_botlin]];
|
||||
#else
|
||||
|
||||
last_line = &visible_line[vis_lbreaks[_rl_vis_botlin]];
|
||||
#endif
|
||||
_rl_move_cursor_relative (_rl_screenwidth - 1, last_line);
|
||||
_rl_clear_to_eol (0);
|
||||
putc (last_line[_rl_screenwidth - 1], rl_outstream);
|
||||
|
|
@ -1744,3 +2110,87 @@ _rl_current_display_line ()
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
/* Calculate the number of screen columns occupied by STR from START to END.
|
||||
In the case of multibyte characters with stateful encoding, we have to
|
||||
scan from the beginning of the string to take the state into account. */
|
||||
static int
|
||||
_rl_col_width (str, start, end)
|
||||
char *str;
|
||||
int start, end;
|
||||
{
|
||||
wchar_t wc;
|
||||
mbstate_t ps = {0};
|
||||
int tmp, point, width, max;
|
||||
|
||||
if (end <= start)
|
||||
return 0;
|
||||
|
||||
point = 0;
|
||||
max = end;
|
||||
|
||||
while (point < start)
|
||||
{
|
||||
tmp = mbrlen (str + point, max, &ps);
|
||||
if ((size_t)tmp == (size_t)-1 || (size_t)tmp == (size_t)-2)
|
||||
{
|
||||
/* In this case, the bytes are invalid or too short to compose a
|
||||
multibyte character, so we assume that the first byte represents
|
||||
a single character. */
|
||||
point++;
|
||||
max--;
|
||||
|
||||
/* Clear the state of the byte sequence, because in this case the
|
||||
effect of mbstate is undefined. */
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
}
|
||||
else if (tmp == 0)
|
||||
break; /* Found '\0' */
|
||||
else
|
||||
{
|
||||
point += tmp;
|
||||
max -= tmp;
|
||||
}
|
||||
}
|
||||
|
||||
/* If START is not a byte that starts a character, then POINT will be
|
||||
greater than START. In this case, assume that (POINT - START) gives
|
||||
a byte count that is the number of columns of difference. */
|
||||
width = point - start;
|
||||
|
||||
while (point < end)
|
||||
{
|
||||
tmp = mbrtowc (&wc, str + point, max, &ps);
|
||||
if ((size_t)tmp == (size_t)-1 || (size_t)tmp == (size_t)-2)
|
||||
{
|
||||
/* In this case, the bytes are invalid or too short to compose a
|
||||
multibyte character, so we assume that the first byte represents
|
||||
a single character. */
|
||||
point++;
|
||||
max--;
|
||||
|
||||
/* and assume that the byte occupies a single column. */
|
||||
width++;
|
||||
|
||||
/* Clear the state of the byte sequence, because in this case the
|
||||
effect of mbstate is undefined. */
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
}
|
||||
else if (tmp == 0)
|
||||
break; /* Found '\0' */
|
||||
else
|
||||
{
|
||||
point += tmp;
|
||||
max -= tmp;
|
||||
tmp = wcwidth(wc);
|
||||
width += (tmp >= 0) ? tmp : 1;
|
||||
}
|
||||
}
|
||||
|
||||
width += point - end;
|
||||
|
||||
return width;
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,23 @@
|
|||
# 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 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.
|
||||
|
||||
topdir = .
|
||||
srcdir = .
|
||||
VPATH = .
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ This document describes the GNU History library, a programming tool that
|
|||
provides a consistent user interface for recalling lines of previously
|
||||
typed input.
|
||||
|
||||
Copyright (C) 1988-2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-2002 Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to make and distribute verbatim copies of
|
||||
this manual provided the copyright notice and this permission notice
|
||||
|
|
@ -73,7 +73,7 @@ except that this permission notice may be stated in a translation approved
|
|||
by the Free Software Foundation.
|
||||
|
||||
@vskip 0pt plus 1filll
|
||||
Copyright @copyright{} 1988-2001 Free Software Foundation, Inc.
|
||||
Copyright @copyright{} 1988-2002 Free Software Foundation, Inc.
|
||||
@end titlepage
|
||||
|
||||
@ifinfo
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
@ignore
|
||||
This file documents the user interface to the GNU History library.
|
||||
|
||||
Copyright (C) 1988-2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-2002 Free Software Foundation, Inc.
|
||||
Authored by Brian Fox and Chet Ramey.
|
||||
|
||||
Permission is granted to make and distribute verbatim copies of this manual
|
||||
|
|
@ -188,8 +188,9 @@ Stifle the history list, remembering only the last @var{max} entries.
|
|||
@end deftypefun
|
||||
|
||||
@deftypefun int unstifle_history (void)
|
||||
Stop stifling the history. This returns the previous amount the
|
||||
history was stifled. The value is positive if the history was
|
||||
Stop stifling the history. This returns the previously-set
|
||||
maximum number of history entries (as set by @code{stifle_history()}).
|
||||
The value is positive if the history was
|
||||
stifled, negative if it wasn't.
|
||||
@end deftypefun
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
@ignore
|
||||
This file documents the user interface to the GNU History library.
|
||||
|
||||
Copyright (C) 1988-1999 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-2002 Free Software Foundation, Inc.
|
||||
Authored by Brian Fox and Chet Ramey.
|
||||
|
||||
Permission is granted to make and distribute verbatim copies of this manual
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
@set EDITION 4.2a
|
||||
@set VERSION 4.2a
|
||||
@set UPDATED 2001 October 9
|
||||
@set UPDATE-MONTH October 2001
|
||||
@ignore
|
||||
Copyright (C) 1988-2002 Free Software Foundation, Inc.
|
||||
@end ignore
|
||||
|
||||
@set LASTCHANGE Tue Oct 9 15:03:34 EDT 2001
|
||||
@set EDITION 4.3
|
||||
@set VERSION 4.3
|
||||
@set UPDATED 2002 March 4
|
||||
@set UPDATE-MONTH March 2002
|
||||
|
||||
@set LASTCHANGE Mon Mar 4 12:00:16 EST 2002
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ This document describes the GNU Readline Library, a utility which aids
|
|||
in the consistency of user interface across discrete programs that need
|
||||
to provide a command line interface.
|
||||
|
||||
Copyright (C) 1988-2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-2002 Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to make and distribute verbatim copies of
|
||||
this manual provided the copyright notice and this permission notice
|
||||
|
|
@ -73,7 +73,7 @@ except that this permission notice may be stated in a translation approved
|
|||
by the Free Software Foundation.
|
||||
|
||||
@vskip 0pt plus 1filll
|
||||
Copyright @copyright{} 1988-2001 Free Software Foundation, Inc.
|
||||
Copyright @copyright{} 1988-2002 Free Software Foundation, Inc.
|
||||
@end titlepage
|
||||
|
||||
@ifinfo
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ This document describes the GNU Readline Library, a utility for aiding
|
|||
in the consitency of user interface across discrete programs that need
|
||||
to provide a command line interface.
|
||||
|
||||
Copyright (C) 1988-2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-2002 Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to make and distribute verbatim copies of
|
||||
this manual provided the copyright notice and this permission notice
|
||||
|
|
@ -111,12 +111,13 @@ function, and has the advantage of no static buffer to overflow:
|
|||
/* A static variable for holding the line. */
|
||||
static char *line_read = (char *)NULL;
|
||||
|
||||
/* Read a string, and return a pointer to it. Returns NULL on EOF. */
|
||||
/* Read a string, and return a pointer to it.
|
||||
Returns NULL on EOF. */
|
||||
char *
|
||||
rl_gets ()
|
||||
@{
|
||||
/* If the buffer has already been allocated, return the memory
|
||||
to the free pool. */
|
||||
/* If the buffer has already been allocated,
|
||||
return the memory to the free pool. */
|
||||
if (line_read)
|
||||
@{
|
||||
free (line_read);
|
||||
|
|
@ -126,7 +127,8 @@ rl_gets ()
|
|||
/* Get a line from the user. */
|
||||
line_read = readline ("");
|
||||
|
||||
/* If the line has any text in it, save it on the history. */
|
||||
/* If the line has any text in it,
|
||||
save it on the history. */
|
||||
if (line_read && *line_read)
|
||||
add_history (line_read);
|
||||
|
||||
|
|
@ -263,7 +265,7 @@ variables that describe the current state of the line read so far.
|
|||
The calling sequence for a command @code{foo} looks like
|
||||
|
||||
@example
|
||||
@code{foo (int count, int key)}
|
||||
@code{int foo (int count, int key)}
|
||||
@end example
|
||||
|
||||
@noindent
|
||||
|
|
@ -280,6 +282,9 @@ to do something useful with both negative and positive arguments.
|
|||
At the very least, it should be aware that it can be passed a
|
||||
negative argument.
|
||||
|
||||
A command function should return 0 if its action completes successfully,
|
||||
and a non-zero value if some error occurs.
|
||||
|
||||
@node Readline Variables
|
||||
@section Readline Variables
|
||||
|
||||
|
|
@ -385,10 +390,12 @@ The value allows conditional parsing of the inputrc file
|
|||
|
||||
@deftypevar {FILE *} rl_instream
|
||||
The stdio stream from which Readline reads input.
|
||||
If @code{NULL}, Readline defaults to @var{stdin}.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar {FILE *} rl_outstream
|
||||
The stdio stream to which Readline performs output.
|
||||
If @code{NULL}, Readline defaults to @var{stdout}.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar {rl_command_func_t *} rl_last_func
|
||||
|
|
@ -766,9 +773,9 @@ This is done with @code{rl_begin_undo_group()} and
|
|||
|
||||
The types of events that can be undone are:
|
||||
|
||||
@example
|
||||
@smallexample
|
||||
enum undo_code @{ UNDO_DELETE, UNDO_INSERT, UNDO_BEGIN, UNDO_END @};
|
||||
@end example
|
||||
@end smallexample
|
||||
|
||||
Notice that @code{UNDO_DELETE} means to insert some text, and
|
||||
@code{UNDO_INSERT} means to delete some text. That is, the undo code
|
||||
|
|
@ -901,10 +908,12 @@ to the result.
|
|||
|
||||
@deftypefun int rl_insert_text (const char *text)
|
||||
Insert @var{text} into the line at the current cursor position.
|
||||
Returns the number of characters inserted.
|
||||
@end deftypefun
|
||||
|
||||
@deftypefun int rl_delete_text (int start, int end)
|
||||
Delete the text between @var{start} and @var{end} in the current line.
|
||||
Returns the number of characters deleted.
|
||||
@end deftypefun
|
||||
|
||||
@deftypefun {char *} rl_copy_text (int start, int end)
|
||||
|
|
@ -947,7 +956,9 @@ be the keyboard.
|
|||
@deftypefun int rl_stuff_char (int c)
|
||||
Insert @var{c} into the Readline input stream. It will be "read"
|
||||
before Readline attempts to read characters from the terminal with
|
||||
@code{rl_read_key()}.
|
||||
@code{rl_read_key()}. Up to 512 characters may be pushed back.
|
||||
@code{rl_stuff_char} returns 1 if the character was successfully inserted;
|
||||
0 otherwise.
|
||||
@end deftypefun
|
||||
|
||||
@deftypefun int rl_execute_next (int c)
|
||||
|
|
@ -1000,6 +1011,13 @@ environment variable is used.
|
|||
@node Utility Functions
|
||||
@subsection Utility Functions
|
||||
|
||||
@deftypefun void rl_replace_line (const char *text, int clear_undo)
|
||||
Replace the contents of @code{rl_line_buffer} with @var{text}.
|
||||
The point and mark are preserved, if possible.
|
||||
If @var{clear_undo} is non-zero, the undo list associated with the
|
||||
current line is cleared.
|
||||
@end deftypefun
|
||||
|
||||
@deftypefun int rl_extend_line_buffer (int len)
|
||||
Ensure that @code{rl_line_buffer} has enough space to hold @var{len}
|
||||
characters, possibly reallocating it if necessary.
|
||||
|
|
@ -1123,16 +1141,26 @@ The function takes the text of the line as an argument.
|
|||
@deftypefun void rl_callback_read_char (void)
|
||||
Whenever an application determines that keyboard input is available, it
|
||||
should call @code{rl_callback_read_char()}, which will read the next
|
||||
character from the current input source. If that character completes the
|
||||
line, @code{rl_callback_read_char} will invoke the @var{lhandler}
|
||||
function saved by @code{rl_callback_handler_install} to process the
|
||||
line. @code{EOF} is indicated by calling @var{lhandler} with a
|
||||
character from the current input source.
|
||||
If that character completes the line, @code{rl_callback_read_char} will
|
||||
invoke the @var{lhandler} function saved by @code{rl_callback_handler_install}
|
||||
to process the line.
|
||||
Before calling the @var{lhandler} function, the terminal settings are
|
||||
reset to the values they had before calling
|
||||
@code{rl_callback_handler_install}.
|
||||
If the @var{lhandler} function returns,
|
||||
the terminal settings are modified for Readline's use again.
|
||||
@code{EOF} is indicated by calling @var{lhandler} with a
|
||||
@code{NULL} line.
|
||||
@end deftypefun
|
||||
|
||||
@deftypefun void rl_callback_handler_remove (void)
|
||||
Restore the terminal to its initial state and remove the line handler.
|
||||
This may be called from within a callback as well as independently.
|
||||
If the @var{lhandler} installed by @code{rl_callback_handler_install}
|
||||
does not exit the program, either this function or the function referred
|
||||
to by the value of @code{rl_deprep_term_function} should be called before
|
||||
the program exits to reset the terminal settings.
|
||||
@end deftypefun
|
||||
|
||||
@node A Readline Example
|
||||
|
|
@ -1185,8 +1213,8 @@ invert_case_line (count, key)
|
|||
end = temp;
|
||||
@}
|
||||
|
||||
/* Tell readline that we are modifying the line, so it will save
|
||||
the undo information. */
|
||||
/* Tell readline that we are modifying the line,
|
||||
so it will save the undo information. */
|
||||
rl_modifying (start, end);
|
||||
|
||||
for (i = start; i != end; i++)
|
||||
|
|
@ -1442,6 +1470,14 @@ partially-completed word. See description of @code{rl_complete()}.
|
|||
This calls @code{rl_complete_internal()} with an argument of @samp{*}.
|
||||
@end deftypefun
|
||||
|
||||
@deftypefun int rl_completion_mode (rl_command_func_t *cfunc)
|
||||
Returns the apppriate value to pass to @code{rl_complete_internal()}
|
||||
depending on whether @var{cfunc} was called twice in succession and
|
||||
the value of the @code{show-all-if-ambiguous} variable.
|
||||
Application-specific completion functions may use this function to present
|
||||
the same interface as @code{rl_complete()}.
|
||||
@end deftypefun
|
||||
|
||||
@deftypefun {char **} rl_completion_matches (const char *text, rl_compentry_func_t *entry_func)
|
||||
Returns an array of strings which is a list of completions for
|
||||
@var{text}. If there are no completions, returns @code{NULL}.
|
||||
|
|
@ -1528,10 +1564,41 @@ character found in @code{rl_completer_word_break_characters} should be
|
|||
used to break words for the completer.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar int rl_completion_query_items
|
||||
Up to this many items will be displayed in response to a
|
||||
possible-completions call. After that, we ask the user if she is sure
|
||||
she wants to see them all. The default value is 100.
|
||||
@deftypevar {rl_compignore_func_t *} rl_ignore_some_completions_function
|
||||
This function, if defined, is called by the completer when real filename
|
||||
completion is done, after all the matching names have been generated.
|
||||
It is passed a @code{NULL} terminated array of matches.
|
||||
The first element (@code{matches[0]}) is the
|
||||
maximal substring common to all matches. This function can
|
||||
re-arrange the list of matches as required, but each element deleted
|
||||
from the array must be freed.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar {rl_icppfunc_t *} rl_directory_completion_hook
|
||||
This function, if defined, is allowed to modify the directory portion
|
||||
of filenames Readline completes. It is called with the address of a
|
||||
string (the current directory name) as an argument, and may modify that string.
|
||||
If the string is replaced with a new string, the old value should be freed.
|
||||
Any modified directory name should have a trailing slash.
|
||||
The modified value will be displayed as part of the completion, replacing
|
||||
the directory portion of the pathname the user typed.
|
||||
It returns an integer that should be non-zero if the function modifies
|
||||
its directory argument.
|
||||
It could be used to expand symbolic links or shell variables in pathnames.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar {rl_compdisp_func_t *} rl_completion_display_matches_hook
|
||||
If non-zero, then this is the address of a function to call when
|
||||
completing a word would normally display the list of possible matches.
|
||||
This function is called in lieu of Readline displaying the list.
|
||||
It takes three arguments:
|
||||
(@code{char **}@var{matches}, @code{int} @var{num_matches}, @code{int} @var{max_length})
|
||||
where @var{matches} is the array of matching strings,
|
||||
@var{num_matches} is the number of strings in that array, and
|
||||
@var{max_length} is the length of the longest string in that array.
|
||||
Readline provides a convenience function, @code{rl_display_match_list},
|
||||
that takes care of doing the display to Readline's output stream. That
|
||||
function may be called from this hook.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar {const char *} rl_basic_word_break_characters
|
||||
|
|
@ -1571,6 +1638,12 @@ For instance, Bash sets this variable to "$@@" so that it can complete
|
|||
shell variables and hostnames.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar int rl_completion_query_items
|
||||
Up to this many items will be displayed in response to a
|
||||
possible-completions call. After that, we ask the user if she is sure
|
||||
she wants to see them all. The default value is 100.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar {int} rl_completion_append_character
|
||||
When a single completion alternative matches at the end of the command
|
||||
line, this character is appended to the inserted completion text. The
|
||||
|
|
@ -1581,6 +1654,24 @@ provide the ``most sensible word separator character'' according to
|
|||
an application-specific command line syntax specification.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar int rl_completion_suppress_append
|
||||
If non-zero, @var{rl_completion_append_character} is not appended to
|
||||
matches at the end of the command line, as described above. It is
|
||||
set to 0 before any application-specific completion function is called.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar int rl_completion_mark_symlink_dirs
|
||||
If non-zero, a slash will be appended to completed filenames that are
|
||||
symbolic links to directory names, subject to the value of the
|
||||
user-settable @var{mark-directories} variable.
|
||||
This variable exists so that application completion functions can
|
||||
override the user's global preference (set via the
|
||||
@var{mark-symlinked-directories} Readline variable) if appropriate.
|
||||
This variable is set to the user's preference before any
|
||||
application completion function is called, so unless that function
|
||||
modifies the value, the user's preferences are honored.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar int rl_ignore_completion_duplicates
|
||||
If non-zero, then duplicates in the matches are removed.
|
||||
The default is 1.
|
||||
|
|
@ -1625,43 +1716,6 @@ If this variable is non-zero, completion is inhibited. The completion
|
|||
character will be inserted as any other bound to @code{self-insert}.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar {rl_compignore_func_t *} rl_ignore_some_completions_function
|
||||
This function, if defined, is called by the completer when real filename
|
||||
completion is done, after all the matching names have been generated.
|
||||
It is passed a @code{NULL} terminated array of matches.
|
||||
The first element (@code{matches[0]}) is the
|
||||
maximal substring common to all matches. This function can
|
||||
re-arrange the list of matches as required, but each element deleted
|
||||
from the array must be freed.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar {rl_icppfunc_t *} rl_directory_completion_hook
|
||||
This function, if defined, is allowed to modify the directory portion
|
||||
of filenames Readline completes. It is called with the address of a
|
||||
string (the current directory name) as an argument, and may modify that string.
|
||||
If the string is replaced with a new string, the old value should be freed.
|
||||
Any modified directory name should have a trailing slash.
|
||||
The modified value will be displayed as part of the completion, replacing
|
||||
the directory portion of the pathname the user typed.
|
||||
It returns an integer that should be non-zero if the function modifies
|
||||
its directory argument.
|
||||
It could be used to expand symbolic links or shell variables in pathnames.
|
||||
@end deftypevar
|
||||
|
||||
@deftypevar {rl_compdisp_func_t *} rl_completion_display_matches_hook
|
||||
If non-zero, then this is the address of a function to call when
|
||||
completing a word would normally display the list of possible matches.
|
||||
This function is called in lieu of Readline displaying the list.
|
||||
It takes three arguments:
|
||||
(@code{char **}@var{matches}, @code{int} @var{num_matches}, @code{int} @var{max_length})
|
||||
where @var{matches} is the array of matching strings,
|
||||
@var{num_matches} is the number of strings in that array, and
|
||||
@var{max_length} is the length of the longest string in that array.
|
||||
Readline provides a convenience function, @code{rl_display_match_list},
|
||||
that takes care of doing the display to Readline's output stream. That
|
||||
function may be called from this hook.
|
||||
@end deftypevar
|
||||
|
||||
@node A Short Completion Example
|
||||
@subsection A Short Completion Example
|
||||
|
||||
|
|
@ -2089,12 +2143,13 @@ too_dangerous (caller)
|
|||
char *caller;
|
||||
@{
|
||||
fprintf (stderr,
|
||||
"%s: Too dangerous for me to distribute. Write it yourself.\n",
|
||||
"%s: Too dangerous for me to distribute.\n"
|
||||
caller);
|
||||
fprintf (stderr, "Write it yourself.\n");
|
||||
@}
|
||||
|
||||
/* Return non-zero if ARG is a valid argument for CALLER, else print
|
||||
an error message and return zero. */
|
||||
/* Return non-zero if ARG is a valid argument for CALLER,
|
||||
else print an error message and return zero. */
|
||||
int
|
||||
valid_argument (caller, arg)
|
||||
char *caller, *arg;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use these features. There is a document entitled "readline.texinfo"
|
|||
which contains both end-user and programmer documentation for the
|
||||
GNU Readline Library.
|
||||
|
||||
Copyright (C) 1988-2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-2002 Free Software Foundation, Inc.
|
||||
|
||||
Authored by Brian Fox and Chet Ramey.
|
||||
|
||||
|
|
@ -512,6 +512,13 @@ This variable, when set to @samp{on}, causes Readline to display an
|
|||
asterisk (@samp{*}) at the start of history lines which have been modified.
|
||||
This variable is @samp{off} by default.
|
||||
|
||||
@item mark-symlinked-directories
|
||||
@vindex mark-symlinked-directories
|
||||
If set to @samp{on}, completed names which are symbolic links
|
||||
to directories have a slash appended (subject to the value of
|
||||
@code{mark-directories}).
|
||||
The default is @samp{off}.
|
||||
|
||||
@item match-hidden-files
|
||||
@vindex match-hidden-files
|
||||
This variable, when set to @samp{on}, causes Readline to match files whose
|
||||
|
|
@ -526,6 +533,12 @@ If set to @samp{on}, Readline will display characters with the
|
|||
eighth bit set directly rather than as a meta-prefixed escape
|
||||
sequence. The default is @samp{off}.
|
||||
|
||||
@item page-completions
|
||||
@vindex page-completions
|
||||
If set to @samp{on}, Readline uses an internal @code{more}-like pager
|
||||
to display a screenful of possible completions at a time.
|
||||
This variable is @samp{on} by default.
|
||||
|
||||
@item print-completions-horizontally
|
||||
If set to @samp{on}, Readline will display completions with matches
|
||||
sorted horizontally in alphabetical order, rather than down the screen.
|
||||
|
|
@ -757,14 +770,14 @@ binding, variable assignment, and conditional syntax.
|
|||
@example
|
||||
@page
|
||||
# This file controls the behaviour of line input editing for
|
||||
# programs that use the Gnu Readline library. Existing programs
|
||||
# include FTP, Bash, and Gdb.
|
||||
# programs that use the GNU Readline library. Existing
|
||||
# programs include FTP, Bash, and GDB.
|
||||
#
|
||||
# You can re-read the inputrc file with C-x C-r.
|
||||
# Lines beginning with '#' are comments.
|
||||
#
|
||||
# First, include any systemwide bindings and variable assignments from
|
||||
# /etc/Inputrc
|
||||
# First, include any systemwide bindings and variable
|
||||
# assignments from /etc/Inputrc
|
||||
$include /etc/Inputrc
|
||||
|
||||
#
|
||||
|
|
@ -816,10 +829,12 @@ TAB: complete
|
|||
$if Bash
|
||||
# edit the path
|
||||
"\C-xp": "PATH=$@{PATH@}\e\C-e\C-a\ef\C-f"
|
||||
# prepare to type a quoted word -- insert open and close double quotes
|
||||
# prepare to type a quoted word --
|
||||
# insert open and close double quotes
|
||||
# and move to just after the open quote
|
||||
"\C-x\"": "\"\"\C-b"
|
||||
# insert a backslash (testing backslash escapes in sequences and macros)
|
||||
# insert a backslash (testing backslash escapes
|
||||
# in sequences and macros)
|
||||
"\C-x\\": "\\"
|
||||
# Quote the current or previous word
|
||||
"\C-xq": "\eb\"\ef\""
|
||||
|
|
@ -835,16 +850,16 @@ set bell-style visible
|
|||
# don't strip characters to 7 bits when reading
|
||||
set input-meta on
|
||||
|
||||
# allow iso-latin1 characters to be inserted rather than converted to
|
||||
# prefix-meta sequences
|
||||
# allow iso-latin1 characters to be inserted rather
|
||||
# than converted to prefix-meta sequences
|
||||
set convert-meta off
|
||||
|
||||
# display characters with the eighth bit set directly rather than
|
||||
# as meta-prefixed characters
|
||||
# display characters with the eighth bit set directly
|
||||
# rather than as meta-prefixed characters
|
||||
set output-meta on
|
||||
|
||||
# if there are more than 150 possible completions for a word, ask the
|
||||
# user if he wants to see all of them
|
||||
# if there are more than 150 possible completions for
|
||||
# a word, ask the user if he wants to see all of them
|
||||
set completion-query-items 150
|
||||
|
||||
# For FTP
|
||||
|
|
@ -1053,6 +1068,20 @@ lowercase the previous word, but do not move the cursor.
|
|||
Capitalize the current (or following) word. With a negative argument,
|
||||
capitalize the previous word, but do not move the cursor.
|
||||
|
||||
@item overwrite-mode ()
|
||||
Toggle overwrite mode. With an explicit positive numeric argument,
|
||||
switches to overwrite mode. With an explicit non-positive numeric
|
||||
argument, switches to insert mode. This command affects only
|
||||
@code{emacs} mode; @code{vi} mode does overwrite differently.
|
||||
Each call to @code{readline()} starts in insert mode.
|
||||
|
||||
In overwrite mode, characters bound to @code{self-insert} replace
|
||||
the text at point rather than pushing the text to the right.
|
||||
Characters bound to @code{backward-delete-char} replace the character
|
||||
before point with a space.
|
||||
|
||||
By default, this command is unbound.
|
||||
|
||||
@end ftable
|
||||
|
||||
@node Commands For Killing
|
||||
|
|
@ -1312,12 +1341,19 @@ of that character. A negative count searches for subsequent
|
|||
occurrences.
|
||||
|
||||
@item insert-comment (M-#)
|
||||
The value of the @code{comment-begin}
|
||||
variable is inserted at the beginning of the current line,
|
||||
and the line is accepted as if a newline had been typed.
|
||||
Without a numeric argument, the value of the @code{comment-begin}
|
||||
variable is inserted at the beginning of the current line.
|
||||
If a numeric argument is supplied, this command acts as a toggle: if
|
||||
the characters at the beginning of the line do not match the value
|
||||
of @code{comment-begin}, the value is inserted, otherwise
|
||||
the characters in @code{comment-begin} are deleted from the beginning of
|
||||
the line.
|
||||
In either case, the line is accepted as if a newline had been typed.
|
||||
@ifset BashFeatures
|
||||
The default value of @code{comment-begin} causes this command
|
||||
to make the current line a shell comment.
|
||||
If a numeric argument causes the comment character to be removed, the line
|
||||
will be executed by the shell.
|
||||
@end ifset
|
||||
|
||||
@item dump-functions ()
|
||||
|
|
@ -1339,13 +1375,22 @@ the output is formatted in such a way that it can be made part
|
|||
of an @var{inputrc} file. This command is unbound by default.
|
||||
|
||||
@ifset BashFeatures
|
||||
@item glob-complete-word (M-g)
|
||||
The word before point is treated as a pattern for pathname expansion,
|
||||
with an asterisk implicitly appended. This pattern is used to
|
||||
generate a list of matching file names for possible completions.
|
||||
|
||||
@item glob-expand-word (C-x *)
|
||||
The word before point is treated as a pattern for pathname expansion,
|
||||
and the list of matching file names is inserted, replacing the word.
|
||||
If a numeric argument is supplied, a @samp{*} is appended before
|
||||
pathname expansion.
|
||||
|
||||
@item glob-list-expansions (C-x g)
|
||||
The list of expansions that would have been generated by
|
||||
@code{glob-expand-word} is displayed, and the line is redrawn.
|
||||
If a numeric argument is supplied, a @samp{*} is appended before
|
||||
pathname expansion.
|
||||
|
||||
@item display-shell-version (C-x C-v)
|
||||
Display version information about the current instance of Bash.
|
||||
|
|
@ -1376,13 +1421,26 @@ Accept the current line for execution and fetch the next line
|
|||
relative to the current line from the history for editing. Any
|
||||
argument is ignored.
|
||||
|
||||
@item emacs-editing-mode (C-e)
|
||||
When in @code{vi} editing mode, this causes a switch back to
|
||||
@code{emacs} editing mode, as if the command @samp{set -o emacs} had
|
||||
been executed.
|
||||
@item edit-and-execute-command (C-xC-e)
|
||||
Invoke an editor on the current command line, and execute the result as shell
|
||||
commands.
|
||||
Bash attempts to invoke
|
||||
@code{$FCEDIT}, @code{$EDITOR}, and @code{emacs}
|
||||
as the editor, in that order.
|
||||
|
||||
@end ifset
|
||||
|
||||
@ifclear BashFeatures
|
||||
@item emacs-editing-mode (C-e)
|
||||
When in @code{vi} command mode, this causes a switch to @code{emacs}
|
||||
editing mode.
|
||||
|
||||
@item vi-editing-mode (M-C-j)
|
||||
When in @code{emacs} editing mode, this causes a switch to @code{vi}
|
||||
editing mode.
|
||||
|
||||
@end ifclear
|
||||
|
||||
@end ftable
|
||||
|
||||
@node Readline vi Mode
|
||||
|
|
@ -1518,6 +1576,12 @@ If the @option{-o default} option was supplied to @code{complete} when the
|
|||
compspec was defined, Readline's default completion will be performed
|
||||
if the compspec generates no matches.
|
||||
|
||||
When a compspec indicates that directory name completion is desired,
|
||||
the programmable completion functions force Readline to append a slash
|
||||
to completed names which are symbolic links to directories, subject to
|
||||
the value of the @var{mark-directories} Readline variable, regardless
|
||||
of the setting of the @var{mark-symlinked-directories} Readline variable.
|
||||
|
||||
@node Programmable Completion Builtins
|
||||
@section Programmable Completion Builtins
|
||||
@cindex completion builtins
|
||||
|
|
@ -1553,7 +1617,7 @@ matches were generated.
|
|||
@item complete
|
||||
@btindex complete
|
||||
@example
|
||||
@code{complete [-abcdefgjkvu] [-o @var{comp-option}] [-A @var{action}] [-G @var{globpat}] [-W @var{wordlist}]
|
||||
@code{complete [-abcdefgjksuv] [-o @var{comp-option}] [-A @var{action}] [-G @var{globpat}] [-W @var{wordlist}]
|
||||
[-P @var{prefix}] [-S @var{suffix}] [-X @var{filterpat}] [-F @var{function}]
|
||||
[-C @var{command}] @var{name} [@var{name} @dots{}]}
|
||||
@code{complete -pr [@var{name} @dots{}]}
|
||||
|
|
@ -1586,7 +1650,8 @@ beyond the simple generation of completions.
|
|||
@table @code
|
||||
|
||||
@item default
|
||||
Use readline's default completion if the compspec generates no matches.
|
||||
Use Readline's default filename completion if the compspec generates
|
||||
no matches.
|
||||
|
||||
@item dirnames
|
||||
Perform directory name completion if the compspec generates no matches.
|
||||
|
|
@ -1596,6 +1661,10 @@ Tell Readline that the compspec generates filenames, so it can perform any
|
|||
filename\-specific processing (like adding a slash to directory names or
|
||||
suppressing trailing spaces). This option is intended to be used with
|
||||
shell functions specified with @option{-F}.
|
||||
|
||||
@item nospace
|
||||
Tell Readline not to append a space (the default) to words completed at
|
||||
the end of the line.
|
||||
@end table
|
||||
|
||||
@item -A @var{action}
|
||||
|
|
@ -1655,6 +1724,9 @@ Shell reserved words. May also be specified as @option{-k}.
|
|||
@item running
|
||||
Names of running jobs, if job control is active.
|
||||
|
||||
@item service
|
||||
Service names. May also be specified as @option{-s}.
|
||||
|
||||
@item setopt
|
||||
Valid arguments for the @option{-o} option to the @code{set} builtin
|
||||
(@pxref{The Set Builtin}).
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ This document describes the end user interface of the GNU Readline Library,
|
|||
a utility which aids in the consistency of user interface across discrete
|
||||
programs that need to provide a command line interface.
|
||||
|
||||
Copyright (C) 1988-2001 Free Software Foundation, Inc.
|
||||
Copyright (C) 1988-2002 Free Software Foundation, Inc.
|
||||
|
||||
Permission is granted to make and distribute verbatim copies of
|
||||
this manual provided the copyright notice and this permission notice
|
||||
|
|
@ -72,7 +72,7 @@ except that this permission notice may be stated in a translation approved
|
|||
by the Free Software Foundation.
|
||||
|
||||
@vskip 0pt plus 1filll
|
||||
Copyright @copyright{} 1988-2001 Free Software Foundation, Inc.
|
||||
Copyright @copyright{} 1988-2002 Free Software Foundation, Inc.
|
||||
@end titlepage
|
||||
|
||||
@ifinfo
|
||||
|
|
|
|||
|
|
@ -35,11 +35,11 @@ KEYMAP_ENTRY_ARRAY emacs_standard_keymap = {
|
|||
/* Control keys. */
|
||||
{ ISFUNC, rl_set_mark }, /* Control-@ */
|
||||
{ ISFUNC, rl_beg_of_line }, /* Control-a */
|
||||
{ ISFUNC, rl_backward }, /* Control-b */
|
||||
{ ISFUNC, rl_backward_char }, /* Control-b */
|
||||
{ ISFUNC, (rl_command_func_t *)0x0 }, /* Control-c */
|
||||
{ ISFUNC, rl_delete }, /* Control-d */
|
||||
{ ISFUNC, rl_end_of_line }, /* Control-e */
|
||||
{ ISFUNC, rl_forward }, /* Control-f */
|
||||
{ ISFUNC, rl_forward_char }, /* Control-f */
|
||||
{ ISFUNC, rl_abort }, /* Control-g */
|
||||
{ ISFUNC, rl_rubout }, /* Control-h */
|
||||
{ ISFUNC, rl_complete }, /* Control-i */
|
||||
|
|
|
|||
|
|
@ -4,6 +4,22 @@
|
|||
# on which program is running, or what terminal is active.
|
||||
#
|
||||
|
||||
# Copyright (C) 1989-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 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.
|
||||
|
||||
# In all programs, all terminals, make sure this is bound.
|
||||
"\C-x\C-r": re-read-init-file
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ fileman: fileman.o
|
|||
rltest: rltest.o
|
||||
$(CC) $(LDFLAGS) -o $@ rltest.o -lreadline -ltermcap
|
||||
|
||||
rlcat: rlcat.o
|
||||
$(CC) $(LDFLAGS) -o $@ rlcat.o -lreadline -ltermcap
|
||||
|
||||
fileman.o: fileman.c
|
||||
rltest.o: rltest.c
|
||||
rl.o: rl.c
|
||||
rlcat.o: rlcat.c
|
||||
|
|
|
|||
|
|
@ -1,3 +1,23 @@
|
|||
/* Copyright (C) 1987-2002 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. */
|
||||
|
||||
/* fileman.c -- A tiny application which demonstrates how to use the
|
||||
GNU Readline library. This application interactively allows users
|
||||
to manipulate files and their modes. */
|
||||
|
|
|
|||
|
|
@ -1,3 +1,23 @@
|
|||
/* Copyright (C) 1987-2002 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. */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef READLINE_LIBRARY
|
||||
|
|
|
|||
|
|
@ -1,5 +1,25 @@
|
|||
/* manexamp.c -- The examples which appear in the documentation are here. */
|
||||
|
||||
/* Copyright (C) 1987-2002 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. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <readline/readline.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,26 @@
|
|||
* usage: rl [-p prompt] [-u unit] [-d default] [-n nchars]
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library, a library for
|
||||
reading lines of text with interactive input and history editing.
|
||||
|
||||
The GNU Readline Library is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2, or
|
||||
(at your option) any later version.
|
||||
|
||||
The GNU Readline Library is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
The GNU General Public License is often shipped with GNU software, and
|
||||
is generally kept in a file called COPYING or LICENSE. If you do not
|
||||
have a copy of the license, write to the Free Software Foundation,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
|
|
|||
174
lib/readline/examples/rlcat.c
Normal file
174
lib/readline/examples/rlcat.c
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* rlcat - cat(1) using readline
|
||||
*
|
||||
* usage: rlcat
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library, a library for
|
||||
reading lines of text with interactive input and history editing.
|
||||
|
||||
The GNU Readline Library is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2, or
|
||||
(at your option) any later version.
|
||||
|
||||
The GNU Readline Library is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
The GNU General Public License is often shipped with GNU software, and
|
||||
is generally kept in a file called COPYING or LICENSE. If you do not
|
||||
have a copy of the license, write to the Free Software Foundation,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "posixstat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if defined (READLINE_LIBRARY)
|
||||
# include "readline.h"
|
||||
# include "history.h"
|
||||
#else
|
||||
# include <readline/readline.h>
|
||||
# include <readline/history.h>
|
||||
#endif
|
||||
|
||||
extern int optind;
|
||||
extern char *optarg;
|
||||
|
||||
static int stdcat();
|
||||
|
||||
static char *progname;
|
||||
static int vflag;
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
fprintf (stderr, "%s: usage: %s [-vEVN] [filename]\n", progname, progname);
|
||||
}
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char *temp;
|
||||
int opt, Vflag, Nflag;
|
||||
|
||||
progname = strrchr(argv[0], '/');
|
||||
if (progname == 0)
|
||||
progname = argv[0];
|
||||
else
|
||||
progname++;
|
||||
|
||||
vflag = Vflag = Nflag = 0;
|
||||
while ((opt = getopt(argc, argv, "vEVN")) != EOF)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
break;
|
||||
case 'V':
|
||||
Vflag = 1;
|
||||
break;
|
||||
case 'E':
|
||||
Vflag = 0;
|
||||
break;
|
||||
case 'N':
|
||||
Nflag = 1;
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
exit (2);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (isatty(0) == 0 || argc || Nflag)
|
||||
return stdcat(argc, argv);
|
||||
|
||||
rl_variable_bind ("editing-mode", Vflag ? "vi" : "emacs");
|
||||
while (temp = readline (""))
|
||||
{
|
||||
if (*temp)
|
||||
add_history (temp);
|
||||
printf ("%s\n", temp);
|
||||
}
|
||||
|
||||
return (ferror (stdout));
|
||||
}
|
||||
|
||||
static int
|
||||
fcopy(fp)
|
||||
FILE *fp;
|
||||
{
|
||||
int c;
|
||||
char *x;
|
||||
|
||||
while ((c = getc(fp)) != EOF)
|
||||
{
|
||||
if (vflag && isascii ((unsigned char)c) && isprint((unsigned char)c) == 0)
|
||||
{
|
||||
x = rl_untranslate_keyseq (c);
|
||||
if (fputs (x, stdout) != 0)
|
||||
return 1;
|
||||
}
|
||||
else if (putchar (c) == EOF)
|
||||
return 1;
|
||||
}
|
||||
return (ferror (stdout));
|
||||
}
|
||||
|
||||
int
|
||||
stdcat (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int i, fd, r;
|
||||
char *s;
|
||||
FILE *fp;
|
||||
|
||||
if (argc == 0)
|
||||
return (fcopy(stdin));
|
||||
|
||||
for (i = 0, r = 1; i < argc; i++)
|
||||
{
|
||||
if (*argv[i] == '-' && argv[i][1] == 0)
|
||||
fp = stdin;
|
||||
else
|
||||
{
|
||||
fp = fopen (argv[i], "r");
|
||||
if (fp == 0)
|
||||
{
|
||||
fprintf (stderr, "%s: %s: cannot open: %s\n", progname, argv[i], strerror(errno));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
r = fcopy (fp);
|
||||
if (fp != stdin)
|
||||
fclose(fp);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
|
@ -4,6 +4,26 @@
|
|||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library, a library for
|
||||
reading lines of text with interactive input and history editing.
|
||||
|
||||
The GNU Readline Library is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2, or
|
||||
(at your option) any later version.
|
||||
|
||||
The GNU Readline Library is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
The GNU General Public License is often shipped with GNU software, and
|
||||
is generally kept in a file called COPYING or LICENSE. If you do not
|
||||
have a copy of the license, write to the Free Software Foundation,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -60,7 +60,8 @@ static FUNMAP default_funmap[] = {
|
|||
{ "abort", rl_abort },
|
||||
{ "accept-line", rl_newline },
|
||||
{ "arrow-key-prefix", rl_arrow_keys },
|
||||
{ "backward-char", rl_backward },
|
||||
{ "backward-byte", rl_backward_byte },
|
||||
{ "backward-char", rl_backward_char },
|
||||
{ "backward-delete-char", rl_rubout },
|
||||
{ "backward-kill-line", rl_backward_kill_line },
|
||||
{ "backward-kill-word", rl_backward_kill_word },
|
||||
|
|
@ -91,7 +92,8 @@ static FUNMAP default_funmap[] = {
|
|||
{ "end-of-line", rl_end_of_line },
|
||||
{ "exchange-point-and-mark", rl_exchange_point_and_mark },
|
||||
{ "forward-backward-delete-char", rl_rubout_or_delete },
|
||||
{ "forward-char", rl_forward },
|
||||
{ "forward-byte", rl_forward_byte },
|
||||
{ "forward-char", rl_forward_char },
|
||||
{ "forward-search-history", rl_forward_search_history },
|
||||
{ "forward-word", rl_forward_word },
|
||||
{ "history-search-backward", rl_history_search_backward },
|
||||
|
|
@ -108,6 +110,7 @@ static FUNMAP default_funmap[] = {
|
|||
{ "non-incremental-reverse-search-history", rl_noninc_reverse_search },
|
||||
{ "non-incremental-forward-search-history-again", rl_noninc_forward_search_again },
|
||||
{ "non-incremental-reverse-search-history-again", rl_noninc_reverse_search_again },
|
||||
{ "overwrite-mode", rl_overwrite_mode },
|
||||
#ifdef __CYGWIN__
|
||||
{ "paste-from-clipboard", rl_paste_from_clipboard },
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -41,11 +41,7 @@
|
|||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
#include "rlmbutil.h"
|
||||
|
||||
#include "history.h"
|
||||
#include "histlib.h"
|
||||
|
|
@ -58,6 +54,8 @@
|
|||
|
||||
typedef int _hist_search_func_t PARAMS((const char *, int));
|
||||
|
||||
extern int rl_byte_oriented; /* declared in mbutil.c */
|
||||
|
||||
static char error_pointer;
|
||||
|
||||
static char *subst_lhs;
|
||||
|
|
@ -204,12 +202,30 @@ get_history_event (string, caller_index, delimiting_quote)
|
|||
|
||||
/* Only a closing `?' or a newline delimit a substring search string. */
|
||||
for (local_index = i; c = string[i]; i++)
|
||||
if ((!substring_okay && (whitespace (c) || c == ':' ||
|
||||
(history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
|
||||
string[i] == delimiting_quote)) ||
|
||||
string[i] == '\n' ||
|
||||
(substring_okay && string[i] == '?'))
|
||||
break;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
int v;
|
||||
mbstate_t ps;
|
||||
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
/* These produce warnings because we're passing a const string to a
|
||||
function that takes a non-const string. */
|
||||
_rl_adjust_point (string, i, &ps);
|
||||
if ((v = _rl_get_char_len (string + i, &ps)) > 1)
|
||||
{
|
||||
i += v - 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
if ((!substring_okay && (whitespace (c) || c == ':' ||
|
||||
(history_search_delimiter_chars && member (c, history_search_delimiter_chars)) ||
|
||||
string[i] == delimiting_quote)) ||
|
||||
string[i] == '\n' ||
|
||||
(substring_okay && string[i] == '?'))
|
||||
break;
|
||||
|
||||
which = i - local_index;
|
||||
temp = (char *)xmalloc (1 + which);
|
||||
|
|
@ -405,13 +421,33 @@ get_subst_pattern (str, iptr, delimiter, is_rhs, lenptr)
|
|||
int *iptr, delimiter, is_rhs, *lenptr;
|
||||
{
|
||||
register int si, i, j, k;
|
||||
char *s = (char *) NULL;
|
||||
char *s;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
mbstate_t ps;
|
||||
#endif
|
||||
|
||||
s = (char *)NULL;
|
||||
i = *iptr;
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
_rl_adjust_point (str, i, &ps);
|
||||
#endif
|
||||
|
||||
for (si = i; str[si] && str[si] != delimiter; si++)
|
||||
if (str[si] == '\\' && str[si + 1] == delimiter)
|
||||
si++;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
int v;
|
||||
if ((v = _rl_get_char_len (str + si, &ps)) > 1)
|
||||
si += v - 1;
|
||||
else if (str[si] == '\\' && str[si + 1] == delimiter)
|
||||
si++;
|
||||
}
|
||||
else
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
if (str[si] == '\\' && str[si + 1] == delimiter)
|
||||
si++;
|
||||
|
||||
if (si > i || is_rhs)
|
||||
{
|
||||
|
|
@ -484,6 +520,11 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
|
|||
int substitute_globally, want_quotes, print_only;
|
||||
char *event, *temp, *result, *tstr, *t, c, *word_spec;
|
||||
int result_len;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
mbstate_t ps;
|
||||
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
#endif
|
||||
|
||||
result = (char *)xmalloc (result_len = 128);
|
||||
|
||||
|
|
@ -514,8 +555,21 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
|
|||
quote, then this expansion takes place inside of the
|
||||
quoted string. If we have to search for some text ("!foo"),
|
||||
allow the delimiter to end the search string. */
|
||||
if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
|
||||
quoted_search_delimiter = string[i - 1];
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
int c, l;
|
||||
l = _rl_find_prev_mbchar (string, i, MB_FIND_ANY);
|
||||
c = string[l];
|
||||
/* XXX - original patch had i - 1 ??? If i == 0 it would fail. */
|
||||
if (i && (c == '\'' || c == '"'))
|
||||
quoted_search_delimiter = c;
|
||||
}
|
||||
else
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
if (i && (string[i - 1] == '\'' || string[i - 1] == '"'))
|
||||
quoted_search_delimiter = string[i - 1];
|
||||
|
||||
event = get_history_event (string, &i, quoted_search_delimiter);
|
||||
}
|
||||
|
||||
|
|
@ -634,7 +688,20 @@ history_expand_internal (string, start, end_index_ptr, ret_string, current_line)
|
|||
if (c == 's')
|
||||
{
|
||||
if (i + 2 < (int)strlen (string))
|
||||
delimiter = string[i + 2];
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
_rl_adjust_point (string, i + 2, &ps);
|
||||
if (_rl_get_char_len (string + i + 2, &ps) > 1)
|
||||
delimiter = 0;
|
||||
else
|
||||
delimiter = string[i + 2];
|
||||
}
|
||||
else
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
delimiter = string[i + 2];
|
||||
}
|
||||
else
|
||||
break; /* no search delimiter */
|
||||
|
||||
|
|
@ -819,6 +886,11 @@ history_expand (hstring, output)
|
|||
int result_len;
|
||||
char *result;
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
char mb[MB_LEN_MAX];
|
||||
mbstate_t ps;
|
||||
#endif
|
||||
|
||||
/* Used when adding the string. */
|
||||
char *temp;
|
||||
|
||||
|
|
@ -861,6 +933,10 @@ history_expand (hstring, output)
|
|||
}
|
||||
else
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
#endif
|
||||
|
||||
string = hstring;
|
||||
/* If not quick substitution, still maybe have to do expansion. */
|
||||
|
||||
|
|
@ -868,8 +944,21 @@ history_expand (hstring, output)
|
|||
is NOT an expansion. */
|
||||
for (i = 0; string[i]; i++)
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
int v;
|
||||
v = _rl_get_char_len (string + i, &ps);
|
||||
if (v > 1)
|
||||
{
|
||||
i += v - 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
||||
cc = string[i + 1];
|
||||
/* The history_comment_char, if set, appearing that the beginning
|
||||
/* The history_comment_char, if set, appearing at the beginning
|
||||
of a word signifies that the rest of the line should not have
|
||||
history expansion performed on it.
|
||||
Skip the rest of the line and break out of the loop. */
|
||||
|
|
@ -932,6 +1021,30 @@ history_expand (hstring, output)
|
|||
continue;
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
int k, c;
|
||||
|
||||
c = tchar;
|
||||
memset (mb, 0, sizeof (mb));
|
||||
for (k = 0; k < MB_LEN_MAX; k++)
|
||||
{
|
||||
mb[k] = (char)c;
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
if (_rl_get_char_len (mb, &ps) == -2)
|
||||
c = string[++i];
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (strlen (mb) > 1)
|
||||
{
|
||||
ADD_STRING (mb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
||||
if (tchar == history_expansion_char)
|
||||
tchar = -3;
|
||||
else if (tchar == history_comment_char)
|
||||
|
|
|
|||
|
|
@ -48,12 +48,26 @@
|
|||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
#if defined (__EMX__) || defined (__CYGWIN__)
|
||||
# undef HAVE_MMAP
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_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 /* HAVE_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
|
||||
|
|
@ -137,8 +151,8 @@ read_history_range (filename, from, to)
|
|||
const char *filename;
|
||||
int from, to;
|
||||
{
|
||||
register int line_start, line_end;
|
||||
char *input, *buffer;
|
||||
register char *line_start, *line_end;
|
||||
char *input, *buffer, *bufend;
|
||||
int file, current_line, chars_read;
|
||||
struct stat finfo;
|
||||
size_t file_size;
|
||||
|
|
@ -157,23 +171,39 @@ read_history_range (filename, from, to)
|
|||
{
|
||||
#if defined (EFBIG)
|
||||
errno = EFBIG;
|
||||
#elif defined (EOVERFLOW)
|
||||
errno = EOVERFLOW;
|
||||
#endif
|
||||
goto error_and_exit;
|
||||
}
|
||||
|
||||
buffer = (char *)xmalloc (file_size + 1);
|
||||
#ifdef HAVE_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)
|
||||
goto error_and_exit;
|
||||
chars_read = file_size;
|
||||
#else
|
||||
buffer = (char *)malloc (file_size + 1);
|
||||
if (buffer == 0)
|
||||
goto error_and_exit;
|
||||
|
||||
chars_read = read (file, buffer, file_size);
|
||||
#endif
|
||||
if (chars_read < 0)
|
||||
{
|
||||
error_and_exit:
|
||||
chars_read = errno;
|
||||
if (file >= 0)
|
||||
close (file);
|
||||
|
||||
FREE (input);
|
||||
#ifndef HAVE_MMAP
|
||||
FREE (buffer);
|
||||
#endif
|
||||
|
||||
return (errno);
|
||||
return (chars_read);
|
||||
}
|
||||
|
||||
close (file);
|
||||
|
|
@ -183,29 +213,25 @@ read_history_range (filename, from, to)
|
|||
to = chars_read;
|
||||
|
||||
/* Start at beginning of file, work to end. */
|
||||
line_start = line_end = current_line = 0;
|
||||
bufend = buffer + chars_read;
|
||||
current_line = 0;
|
||||
|
||||
/* Skip lines until we are at FROM. */
|
||||
while (line_start < chars_read && current_line < from)
|
||||
{
|
||||
for (line_end = line_start; line_end < chars_read; line_end++)
|
||||
if (buffer[line_end] == '\n')
|
||||
{
|
||||
current_line++;
|
||||
line_start = line_end + 1;
|
||||
if (current_line == from)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
|
||||
if (*line_end == '\n')
|
||||
{
|
||||
current_line++;
|
||||
line_start = line_end + 1;
|
||||
}
|
||||
|
||||
/* If there are lines left to gobble, then gobble them now. */
|
||||
for (line_end = line_start; line_end < chars_read; line_end++)
|
||||
if (buffer[line_end] == '\n')
|
||||
for (line_end = line_start; line_end < bufend; line_end++)
|
||||
if (*line_end == '\n')
|
||||
{
|
||||
buffer[line_end] = '\0';
|
||||
*line_end = '\0';
|
||||
|
||||
if (buffer[line_start])
|
||||
add_history (buffer + line_start);
|
||||
if (*line_start)
|
||||
add_history (line_start);
|
||||
|
||||
current_line++;
|
||||
|
||||
|
|
@ -216,7 +242,11 @@ read_history_range (filename, from, to)
|
|||
}
|
||||
|
||||
FREE (input);
|
||||
#ifndef HAVE_MMAP
|
||||
FREE (buffer);
|
||||
#else
|
||||
munmap (buffer, file_size);
|
||||
#endif
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -229,9 +259,8 @@ history_truncate_file (fname, lines)
|
|||
const char *fname;
|
||||
int lines;
|
||||
{
|
||||
register int i;
|
||||
char *buffer, *filename, *bp;
|
||||
int file, chars_read, rv;
|
||||
char *buffer, *filename;
|
||||
struct stat finfo;
|
||||
size_t file_size;
|
||||
|
||||
|
|
@ -276,7 +305,13 @@ history_truncate_file (fname, lines)
|
|||
goto truncate_exit;
|
||||
}
|
||||
|
||||
buffer = (char *)xmalloc (file_size + 1);
|
||||
buffer = (char *)malloc (file_size + 1);
|
||||
if (buffer == 0)
|
||||
{
|
||||
close (file);
|
||||
goto truncate_exit;
|
||||
}
|
||||
|
||||
chars_read = read (file, buffer, file_size);
|
||||
close (file);
|
||||
|
||||
|
|
@ -288,9 +323,9 @@ history_truncate_file (fname, lines)
|
|||
|
||||
/* Count backwards from the end of buffer until we have passed
|
||||
LINES lines. */
|
||||
for (i = chars_read - 1; lines && i; i--)
|
||||
for (bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
|
||||
{
|
||||
if (buffer[i] == '\n')
|
||||
if (*bp == '\n')
|
||||
lines--;
|
||||
}
|
||||
|
||||
|
|
@ -299,22 +334,22 @@ history_truncate_file (fname, lines)
|
|||
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 ( ; i; i--)
|
||||
if (buffer[i] == '\n')
|
||||
for ( ; bp > buffer; bp--)
|
||||
if (*bp == '\n')
|
||||
{
|
||||
i++;
|
||||
bp++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Write only if there are more lines in the file than we want to
|
||||
truncate to. */
|
||||
if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
|
||||
if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
|
||||
{
|
||||
write (file, buffer + i, chars_read - i);
|
||||
write (file, bp, chars_read - (bp - buffer));
|
||||
|
||||
#if defined (__BEOS__)
|
||||
/* BeOS ignores O_TRUNC. */
|
||||
ftruncate (file, chars_read - i);
|
||||
ftruncate (file, chars_read - (bp - buffer));
|
||||
#endif
|
||||
|
||||
close (file);
|
||||
|
|
@ -339,8 +374,13 @@ history_do_write (filename, nelements, overwrite)
|
|||
register int i;
|
||||
char *output;
|
||||
int file, mode, rv;
|
||||
size_t cursize;
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
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;
|
||||
|
||||
|
|
@ -350,6 +390,10 @@ history_do_write (filename, nelements, overwrite)
|
|||
return (errno);
|
||||
}
|
||||
|
||||
#ifdef HAVE_MMAP
|
||||
cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
|
||||
#endif
|
||||
|
||||
if (nelements > history_length)
|
||||
nelements = history_length;
|
||||
|
||||
|
|
@ -367,7 +411,28 @@ history_do_write (filename, nelements, overwrite)
|
|||
buffer_size += 1 + strlen (the_history[i]->line);
|
||||
|
||||
/* Allocate the buffer, and fill it. */
|
||||
buffer = (char *)xmalloc (buffer_size);
|
||||
#ifdef HAVE_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++)
|
||||
{
|
||||
|
|
@ -376,9 +441,14 @@ history_do_write (filename, nelements, overwrite)
|
|||
buffer[j++] = '\n';
|
||||
}
|
||||
|
||||
#ifdef HAVE_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);
|
||||
|
|
|
|||
|
|
@ -22,6 +22,12 @@
|
|||
#if !defined (_HISTLIB_H_)
|
||||
#define _HISTLIB_H_
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#if !defined (STREQ)
|
||||
#define STREQ(a, b) (((a)[0] == (b)[0]) && (strcmp ((a), (b)) == 0))
|
||||
#define STREQN(a, b, n) (((n) == 0) ? (1) \
|
||||
|
|
@ -29,9 +35,6 @@
|
|||
#endif
|
||||
|
||||
#ifndef savestring
|
||||
# ifndef strcpy
|
||||
extern char *strcpy ();
|
||||
# endif
|
||||
#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -44,12 +44,6 @@
|
|||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include "history.h"
|
||||
#include "histlib.h"
|
||||
|
||||
|
|
@ -349,19 +343,19 @@ stifle_history (max)
|
|||
max_input_history = history_max_entries = max;
|
||||
}
|
||||
|
||||
/* Stop stifling the history. This returns the previous amount the
|
||||
history was stifled by. The value is positive if the history was
|
||||
stifled, negative if it wasn't. */
|
||||
/* Stop stifling the history. This returns the previous maximum
|
||||
number of history entries. The value is positive if the history
|
||||
was stifled, negative if it wasn't. */
|
||||
int
|
||||
unstifle_history ()
|
||||
{
|
||||
if (history_stifled)
|
||||
{
|
||||
history_stifled = 0;
|
||||
return (-history_max_entries);
|
||||
return (history_max_entries);
|
||||
}
|
||||
|
||||
return (history_max_entries);
|
||||
else
|
||||
return (-history_max_entries);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -32,17 +32,13 @@
|
|||
#else
|
||||
# include "ansi_stdlib.h"
|
||||
#endif /* HAVE_STDLIB_H */
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include "history.h"
|
||||
#include "histlib.h"
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ extern int errno;
|
|||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
|
|
@ -86,8 +87,7 @@ 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_unget_char PARAMS((int));
|
||||
static void rl_gather_tyi PARAMS((void));
|
||||
static int rl_gather_tyi PARAMS((void));
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
|
|
@ -139,8 +139,8 @@ rl_get_char (key)
|
|||
/* Stuff KEY into the *front* of the input buffer.
|
||||
Returns non-zero if successful, zero if there is
|
||||
no space left in the buffer. */
|
||||
static int
|
||||
rl_unget_char (key)
|
||||
int
|
||||
_rl_unget_char (key)
|
||||
int key;
|
||||
{
|
||||
if (ibuffer_space ())
|
||||
|
|
@ -154,9 +154,10 @@ rl_unget_char (key)
|
|||
return (0);
|
||||
}
|
||||
|
||||
/* If a character is available to be read, then read it
|
||||
and stuff it into IBUFFER. Otherwise, just return. */
|
||||
static void
|
||||
/* 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;
|
||||
|
|
@ -177,13 +178,17 @@ rl_gather_tyi ()
|
|||
FD_SET (tty, &exceptfds);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = _keyboard_input_timeout;
|
||||
if (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) <= 0)
|
||||
return; /* Nothing to read. */
|
||||
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)
|
||||
|
|
@ -196,14 +201,14 @@ rl_gather_tyi ()
|
|||
|
||||
fcntl (tty, F_SETFL, tem);
|
||||
if (chars_avail == -1 && errno == EAGAIN)
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
#endif /* O_NDELAY */
|
||||
|
||||
/* If there's nothing available, don't waste time trying to read
|
||||
something. */
|
||||
if (chars_avail <= 0)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
tem = ibuffer_space ();
|
||||
|
||||
|
|
@ -227,6 +232,8 @@ rl_gather_tyi ()
|
|||
if (chars_avail)
|
||||
rl_stuff_char (input);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -242,7 +249,11 @@ rl_set_keyboard_input_timeout (u)
|
|||
}
|
||||
|
||||
/* Is there input available to be read on the readline input file
|
||||
descriptor? Only works if the system has select(2) or FIONREAD. */
|
||||
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 ()
|
||||
{
|
||||
|
|
@ -277,6 +288,18 @@ _rl_input_available ()
|
|||
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;
|
||||
|
|
@ -294,7 +317,7 @@ _rl_insert_typein (c)
|
|||
string[i++] = key;
|
||||
|
||||
if (t)
|
||||
rl_unget_char (key);
|
||||
_rl_unget_char (key);
|
||||
|
||||
string[i] = '\0';
|
||||
rl_insert_text (string);
|
||||
|
|
@ -375,7 +398,11 @@ rl_read_key ()
|
|||
(*rl_event_hook) ();
|
||||
if (rl_done) /* XXX - experimental */
|
||||
return ('\n');
|
||||
rl_gather_tyi ();
|
||||
if (rl_gather_tyi () < 0) /* XXX - EIO */
|
||||
{
|
||||
rl_done = 1;
|
||||
return ('\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -441,3 +468,73 @@ rl_getc (stream)
|
|||
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,7 +4,7 @@
|
|||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Copyright (C) 1987,1989 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file contains the Readline Library (the Library), a set of
|
||||
routines for providing Emacs style line input to programs that ask
|
||||
|
|
@ -45,6 +45,8 @@
|
|||
#endif
|
||||
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
#include "readline.h"
|
||||
#include "history.h"
|
||||
|
||||
|
|
@ -165,8 +167,12 @@ rl_search_history (direction, invoking_key)
|
|||
HIST_ENTRY **hlist;
|
||||
|
||||
register int i;
|
||||
int orig_point, orig_line, last_found_line;
|
||||
int orig_point, orig_mark, orig_line, last_found_line;
|
||||
int c, found, failed, sline_len;
|
||||
int n, wstart, wlen;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
char mb[MB_LEN_MAX];
|
||||
#endif
|
||||
|
||||
/* The line currently being searched. */
|
||||
char *sline;
|
||||
|
|
@ -184,6 +190,7 @@ rl_search_history (direction, invoking_key)
|
|||
|
||||
RL_SETSTATE(RL_STATE_ISEARCH);
|
||||
orig_point = rl_point;
|
||||
orig_mark = rl_mark;
|
||||
last_found_line = orig_line = where_history ();
|
||||
reverse = direction < 0;
|
||||
hlist = history_list ();
|
||||
|
|
@ -246,6 +253,12 @@ rl_search_history (direction, invoking_key)
|
|||
c = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
c = _rl_read_mbstring (c, mb, MB_LEN_MAX);
|
||||
#endif
|
||||
|
||||
/* Translate the keys we do something with to opcodes. */
|
||||
if (c >= 0 && _rl_keymap[c].type == ISFUNC)
|
||||
{
|
||||
f = _rl_keymap[c].function;
|
||||
|
|
@ -254,33 +267,53 @@ rl_search_history (direction, invoking_key)
|
|||
c = reverse ? -1 : -2;
|
||||
else if (f == rl_forward_search_history)
|
||||
c = !reverse ? -1 : -2;
|
||||
else if (f == rl_rubout)
|
||||
c = -3;
|
||||
else if (c == CTRL ('G'))
|
||||
c = -4;
|
||||
else if (c == CTRL ('W')) /* XXX */
|
||||
c = -5;
|
||||
else if (c == CTRL ('Y')) /* XXX */
|
||||
c = -6;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Let NEWLINE (^J) terminate the search for people who don't like
|
||||
using ESC. ^M can still be used to terminate the search and
|
||||
immediately execute the command. */
|
||||
if (c == ESC || c == NEWLINE)
|
||||
#else
|
||||
/* The characters in isearch_terminators (set from the user-settable
|
||||
variable isearch-terminators) are used to terminate the search but
|
||||
not subsequently execute the character as a command. The default
|
||||
value is "\033\012" (ESC and C-J). */
|
||||
if (strchr (isearch_terminators, c))
|
||||
#endif
|
||||
{
|
||||
/* ESC still terminates the search, but if there is pending
|
||||
input or if input arrives within 0.1 seconds (on systems
|
||||
with select(2)) it is used as a prefix character
|
||||
with rl_execute_next. WATCH OUT FOR THIS! This is intended
|
||||
to allow the arrow keys to be used like ^F and ^B are used
|
||||
to terminate the search and execute the movement command. */
|
||||
if (c == ESC && _rl_input_available ()) /* XXX */
|
||||
to terminate the search and execute the movement command.
|
||||
XXX - since _rl_input_available depends on the application-
|
||||
settable keyboard timeout value, this could alternatively
|
||||
use _rl_input_queued(100000) */
|
||||
if (c == ESC && _rl_input_available ())
|
||||
rl_execute_next (ESC);
|
||||
break;
|
||||
}
|
||||
|
||||
if (c >= 0 && (CTRL_CHAR (c) || META_CHAR (c) || c == RUBOUT) && c != CTRL ('G'))
|
||||
#define ENDSRCH_CHAR(c) \
|
||||
((CTRL_CHAR (c) || META_CHAR (c) || (c) == RUBOUT) && ((c) != CTRL ('G')))
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
if (c >= 0 && strlen (mb) == 1 && ENDSRCH_CHAR (c))
|
||||
{
|
||||
/* This sets rl_pending_input to c; it will be picked up the next
|
||||
time rl_read_key is called. */
|
||||
rl_execute_next (c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (c >= 0 && ENDSRCH_CHAR (c))
|
||||
{
|
||||
/* This sets rl_pending_input to c; it will be picked up the next
|
||||
time rl_read_key is called. */
|
||||
|
|
@ -318,10 +351,23 @@ rl_search_history (direction, invoking_key)
|
|||
reverse = direction < 0;
|
||||
break;
|
||||
|
||||
case CTRL ('G'):
|
||||
strcpy (rl_line_buffer, lines[orig_line]);
|
||||
/* delete character from search string. */
|
||||
case -3: /* C-H, DEL */
|
||||
/* This is tricky. To do this right, we need to keep a
|
||||
stack of search positions for the current search, with
|
||||
sentinels marking the beginning and end. But this will
|
||||
do until we have a real isearch-undo. */
|
||||
if (search_string_index == 0)
|
||||
rl_ding ();
|
||||
else
|
||||
search_string[--search_string_index] = '\0';
|
||||
|
||||
break;
|
||||
|
||||
case -4: /* C-G */
|
||||
rl_replace_line (lines[orig_line], 0);
|
||||
rl_point = orig_point;
|
||||
rl_end = strlen (rl_line_buffer);
|
||||
rl_mark = orig_mark;
|
||||
rl_restore_prompt();
|
||||
rl_clear_message ();
|
||||
if (allocated_line)
|
||||
|
|
@ -330,20 +376,53 @@ rl_search_history (direction, invoking_key)
|
|||
RL_UNSETSTATE(RL_STATE_ISEARCH);
|
||||
return 0;
|
||||
|
||||
#if 0
|
||||
/* delete character from search string. */
|
||||
case -3:
|
||||
if (search_string_index == 0)
|
||||
rl_ding ();
|
||||
else
|
||||
case -5: /* C-W */
|
||||
/* skip over portion of line we already matched */
|
||||
wstart = rl_point + search_string_index;
|
||||
if (wstart >= rl_end)
|
||||
{
|
||||
search_string[--search_string_index] = '\0';
|
||||
/* This is tricky. To do this right, we need to keep a
|
||||
stack of search positions for the current search, with
|
||||
sentinels marking the beginning and end. */
|
||||
rl_ding ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* if not in a word, move to one. */
|
||||
if (rl_alphabetic(rl_line_buffer[wstart]) == 0)
|
||||
{
|
||||
rl_ding ();
|
||||
break;
|
||||
}
|
||||
n = wstart;
|
||||
while (n < rl_end && rl_alphabetic(rl_line_buffer[n]))
|
||||
n++;
|
||||
wlen = n - wstart + 1;
|
||||
if (search_string_index + wlen + 1 >= search_string_size)
|
||||
{
|
||||
search_string_size += wlen + 1;
|
||||
search_string = (char *)xrealloc (search_string, search_string_size);
|
||||
}
|
||||
for (; wstart < n; wstart++)
|
||||
search_string[search_string_index++] = rl_line_buffer[wstart];
|
||||
search_string[search_string_index] = '\0';
|
||||
break;
|
||||
|
||||
case -6: /* C-Y */
|
||||
/* skip over portion of line we already matched */
|
||||
wstart = rl_point + search_string_index;
|
||||
if (wstart >= rl_end)
|
||||
{
|
||||
rl_ding ();
|
||||
break;
|
||||
}
|
||||
n = rl_end - wstart + 1;
|
||||
if (search_string_index + n + 1 >= search_string_size)
|
||||
{
|
||||
search_string_size += n + 1;
|
||||
search_string = (char *)xrealloc (search_string, search_string_size);
|
||||
}
|
||||
for (n = wstart; n < rl_end; n++)
|
||||
search_string[search_string_index++] = rl_line_buffer[n];
|
||||
search_string[search_string_index] = '\0';
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
/* Add character to search string and continue search. */
|
||||
|
|
@ -352,7 +431,16 @@ rl_search_history (direction, invoking_key)
|
|||
search_string_size += 128;
|
||||
search_string = (char *)xrealloc (search_string, search_string_size);
|
||||
}
|
||||
search_string[search_string_index++] = c;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
int j, l;
|
||||
for (j = 0, l = strlen (mb); j < l; )
|
||||
search_string[search_string_index++] = mb[j++];
|
||||
}
|
||||
else
|
||||
#endif
|
||||
search_string[search_string_index++] = c;
|
||||
search_string[search_string_index] = '\0';
|
||||
break;
|
||||
}
|
||||
|
|
@ -417,17 +505,9 @@ rl_search_history (direction, invoking_key)
|
|||
the location. */
|
||||
if (found)
|
||||
{
|
||||
int line_len;
|
||||
|
||||
prev_line_found = lines[i];
|
||||
line_len = strlen (lines[i]);
|
||||
|
||||
if (line_len >= rl_line_buffer_len)
|
||||
rl_extend_line_buffer (line_len);
|
||||
|
||||
strcpy (rl_line_buffer, lines[i]);
|
||||
rl_replace_line (lines[i], 0);
|
||||
rl_point = line_index;
|
||||
rl_end = line_len;
|
||||
last_found_line = i;
|
||||
rl_display_search (search_string, reverse, (i == orig_line) ? -1 : i);
|
||||
}
|
||||
|
|
@ -443,25 +523,32 @@ rl_search_history (direction, invoking_key)
|
|||
|
||||
rl_restore_prompt ();
|
||||
|
||||
#if 1
|
||||
/* Save the search string for possible later use. */
|
||||
FREE (last_isearch_string);
|
||||
last_isearch_string = search_string;
|
||||
last_isearch_string_len = search_string_index;
|
||||
#else
|
||||
/* Free the search string. */
|
||||
free (search_string);
|
||||
#endif
|
||||
|
||||
if (last_found_line < orig_line)
|
||||
rl_get_previous_history (orig_line - last_found_line, 0);
|
||||
else
|
||||
rl_get_next_history (last_found_line - orig_line, 0);
|
||||
|
||||
/* If the string was not found, put point at the end of the line. */
|
||||
/* If the string was not found, put point at the end of the last matching
|
||||
line. If last_found_line == orig_line, we didn't find any matching
|
||||
history lines at all, so put point back in its original position. */
|
||||
if (line_index < 0)
|
||||
line_index = strlen (rl_line_buffer);
|
||||
{
|
||||
if (last_found_line == orig_line)
|
||||
line_index = orig_point;
|
||||
else
|
||||
line_index = strlen (rl_line_buffer);
|
||||
rl_mark = orig_mark;
|
||||
}
|
||||
|
||||
rl_point = line_index;
|
||||
/* Don't worry about where to put the mark here; rl_get_previous_history
|
||||
and rl_get_next_history take care of it. */
|
||||
|
||||
rl_clear_message ();
|
||||
|
||||
FREE (allocated_line);
|
||||
|
|
|
|||
|
|
@ -49,8 +49,9 @@ typedef struct _keymap_entry {
|
|||
|
||||
/* This must be large enough to hold bindings for all of the characters
|
||||
in a desired character set (e.g, 128 for ASCII, 256 for ISO Latin-x,
|
||||
and so on). */
|
||||
#define KEYMAP_SIZE 256
|
||||
and so on) plus one for subsequence matching. */
|
||||
#define KEYMAP_SIZE 257
|
||||
#define ANYOTHERKEY KEYMAP_SIZE-1
|
||||
|
||||
/* I wanted to make the above structure contain a union of:
|
||||
union { rl_command_func_t *function; struct _keymap_entry *keymap; } value;
|
||||
|
|
|
|||
|
|
@ -201,18 +201,21 @@ int
|
|||
rl_kill_word (count, key)
|
||||
int count, key;
|
||||
{
|
||||
int orig_point = rl_point;
|
||||
int orig_point;
|
||||
|
||||
if (count < 0)
|
||||
return (rl_backward_kill_word (-count, key));
|
||||
else
|
||||
{
|
||||
orig_point = rl_point;
|
||||
rl_forward_word (count, key);
|
||||
|
||||
if (rl_point != orig_point)
|
||||
rl_kill_text (orig_point, rl_point);
|
||||
|
||||
rl_point = orig_point;
|
||||
if (rl_editing_mode == emacs_mode)
|
||||
rl_mark = rl_point;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -222,16 +225,20 @@ int
|
|||
rl_backward_kill_word (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
int orig_point = rl_point;
|
||||
int orig_point;
|
||||
|
||||
if (count < 0)
|
||||
return (rl_kill_word (-count, ignore));
|
||||
else
|
||||
{
|
||||
orig_point = rl_point;
|
||||
rl_backward_word (count, ignore);
|
||||
|
||||
if (rl_point != orig_point)
|
||||
rl_kill_text (orig_point, rl_point);
|
||||
|
||||
if (rl_editing_mode == emacs_mode)
|
||||
rl_mark = rl_point;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -242,16 +249,19 @@ int
|
|||
rl_kill_line (direction, ignore)
|
||||
int direction, ignore;
|
||||
{
|
||||
int orig_point = rl_point;
|
||||
int orig_point;
|
||||
|
||||
if (direction < 0)
|
||||
return (rl_backward_kill_line (1, ignore));
|
||||
else
|
||||
{
|
||||
orig_point = rl_point;
|
||||
rl_end_of_line (1, ignore);
|
||||
if (orig_point != rl_point)
|
||||
rl_kill_text (orig_point, rl_point);
|
||||
rl_point = orig_point;
|
||||
if (rl_editing_mode == emacs_mode)
|
||||
rl_mark = rl_point;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -262,7 +272,7 @@ int
|
|||
rl_backward_kill_line (direction, ignore)
|
||||
int direction, ignore;
|
||||
{
|
||||
int orig_point = rl_point;
|
||||
int orig_point;
|
||||
|
||||
if (direction < 0)
|
||||
return (rl_kill_line (1, ignore));
|
||||
|
|
@ -272,8 +282,12 @@ rl_backward_kill_line (direction, ignore)
|
|||
rl_ding ();
|
||||
else
|
||||
{
|
||||
orig_point = rl_point;
|
||||
rl_beg_of_line (1, ignore);
|
||||
rl_kill_text (orig_point, rl_point);
|
||||
if (rl_point != orig_point)
|
||||
rl_kill_text (orig_point, rl_point);
|
||||
if (rl_editing_mode == emacs_mode)
|
||||
rl_mark = rl_point;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -287,6 +301,7 @@ rl_kill_full_line (count, ignore)
|
|||
rl_begin_undo_group ();
|
||||
rl_point = 0;
|
||||
rl_kill_text (rl_point, rl_end);
|
||||
rl_mark = 0;
|
||||
rl_end_undo_group ();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -321,6 +336,8 @@ rl_unix_word_rubout (count, key)
|
|||
}
|
||||
|
||||
rl_kill_text (orig_point, rl_point);
|
||||
if (rl_editing_mode == emacs_mode)
|
||||
rl_mark = rl_point;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -341,6 +358,8 @@ rl_unix_line_discard (count, key)
|
|||
{
|
||||
rl_kill_text (rl_point, 0);
|
||||
rl_point = 0;
|
||||
if (rl_editing_mode == emacs_mode)
|
||||
rl_mark = rl_point;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -353,17 +372,14 @@ region_kill_internal (delete)
|
|||
{
|
||||
char *text;
|
||||
|
||||
if (rl_mark == rl_point)
|
||||
if (rl_mark != rl_point)
|
||||
{
|
||||
_rl_last_command_was_kill++;
|
||||
return 0;
|
||||
text = rl_copy_text (rl_point, rl_mark);
|
||||
if (delete)
|
||||
rl_delete_text (rl_point, rl_mark);
|
||||
_rl_copy_to_kill_ring (text, rl_point < rl_mark);
|
||||
}
|
||||
|
||||
text = rl_copy_text (rl_point, rl_mark);
|
||||
if (delete)
|
||||
rl_delete_text (rl_point, rl_mark);
|
||||
_rl_copy_to_kill_ring (text, rl_point < rl_mark);
|
||||
|
||||
_rl_last_command_was_kill++;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -530,6 +546,8 @@ rl_yank_nth_arg_internal (count, ignore, history_skip)
|
|||
|
||||
rl_begin_undo_group ();
|
||||
|
||||
_rl_set_mark_at_pos (rl_point);
|
||||
|
||||
#if defined (VI_MODE)
|
||||
/* Vi mode always inserts a space before yanking the argument, and it
|
||||
inserts it right *after* rl_point. */
|
||||
|
|
@ -623,6 +641,7 @@ rl_paste_from_clipboard (count, key)
|
|||
}
|
||||
else
|
||||
ptr = data;
|
||||
_rl_set_mark_at_pos (rl_point);
|
||||
rl_insert_text (ptr);
|
||||
if (ptr != data)
|
||||
free (ptr);
|
||||
|
|
|
|||
|
|
@ -49,8 +49,6 @@
|
|||
#include "rlprivate.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0)
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Hacking Keyboard Macros */
|
||||
|
|
@ -61,9 +59,6 @@
|
|||
then it is a malloc ()'ed string where input is coming from. */
|
||||
char *rl_executing_macro = (char *)NULL;
|
||||
|
||||
/* Non-zero means to save keys that we dispatch on in a kbd macro. */
|
||||
int _rl_defining_kbd_macro = 0;
|
||||
|
||||
/* The offset in the above string to the next character to be read. */
|
||||
static int executing_macro_index;
|
||||
|
||||
|
|
@ -186,7 +181,6 @@ _rl_kill_kbd_macro ()
|
|||
rl_executing_macro = (char *) NULL;
|
||||
executing_macro_index = 0;
|
||||
|
||||
_rl_defining_kbd_macro = 0;
|
||||
RL_UNSETSTATE(RL_STATE_MACRODEF);
|
||||
}
|
||||
|
||||
|
|
@ -200,7 +194,7 @@ int
|
|||
rl_start_kbd_macro (ignore1, ignore2)
|
||||
int ignore1, ignore2;
|
||||
{
|
||||
if (_rl_defining_kbd_macro)
|
||||
if (RL_ISSTATE (RL_STATE_MACRODEF))
|
||||
{
|
||||
_rl_abort_internal ();
|
||||
return -1;
|
||||
|
|
@ -214,7 +208,6 @@ rl_start_kbd_macro (ignore1, ignore2)
|
|||
else
|
||||
current_macro_index = 0;
|
||||
|
||||
_rl_defining_kbd_macro = 1;
|
||||
RL_SETSTATE(RL_STATE_MACRODEF);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -226,7 +219,7 @@ int
|
|||
rl_end_kbd_macro (count, ignore)
|
||||
int count, ignore;
|
||||
{
|
||||
if (_rl_defining_kbd_macro == 0)
|
||||
if (RL_ISSTATE (RL_STATE_MACRODEF) == 0)
|
||||
{
|
||||
_rl_abort_internal ();
|
||||
return -1;
|
||||
|
|
@ -235,7 +228,6 @@ rl_end_kbd_macro (count, ignore)
|
|||
current_macro_index -= rl_key_sequence_length - 1;
|
||||
current_macro[current_macro_index] = '\0';
|
||||
|
||||
_rl_defining_kbd_macro = 0;
|
||||
RL_UNSETSTATE(RL_STATE_MACRODEF);
|
||||
|
||||
return (rl_call_last_kbd_macro (--count, 0));
|
||||
|
|
@ -250,7 +242,7 @@ rl_call_last_kbd_macro (count, ignore)
|
|||
if (current_macro == 0)
|
||||
_rl_abort_internal ();
|
||||
|
||||
if (_rl_defining_kbd_macro)
|
||||
if (RL_ISSTATE (RL_STATE_MACRODEF))
|
||||
{
|
||||
rl_ding (); /* no recursive macros */
|
||||
current_macro[--current_macro_index] = '\0'; /* erase this char */
|
||||
|
|
|
|||
337
lib/readline/mbutil.c
Normal file
337
lib/readline/mbutil.c
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
/* mbutil.c -- readline multibyte character utility functions */
|
||||
|
||||
/* Copyright (C) 2001 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>
|
||||
#include "posixjmp.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h> /* for _POSIX_VERSION */
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# include "ansi_stdlib.h"
|
||||
#endif /* HAVE_STDLIB_H */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
#if defined (TIOCSTAT_IN_SYS_IOCTL)
|
||||
# include <sys/ioctl.h>
|
||||
#endif /* TIOCSTAT_IN_SYS_IOCTL */
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
|
||||
#include "rlprivate.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* Declared here so it can be shared between the readline and history
|
||||
libraries. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
int rl_byte_oriented = 0;
|
||||
#else
|
||||
int rl_byte_oriented = 1;
|
||||
#endif
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Multibyte Character Utility Functions */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
#if defined(HANDLE_MULTIBYTE)
|
||||
|
||||
static int
|
||||
_rl_find_next_mbchar_internal (string, seed, count, find_non_zero)
|
||||
char *string;
|
||||
int seed, count, find_non_zero;
|
||||
{
|
||||
size_t tmp = 0;
|
||||
mbstate_t ps;
|
||||
int point = 0;
|
||||
wchar_t wc;
|
||||
|
||||
memset(&ps, 0, sizeof (mbstate_t));
|
||||
if (seed < 0)
|
||||
seed = 0;
|
||||
if (count <= 0)
|
||||
return seed;
|
||||
|
||||
point = seed + _rl_adjust_point(string, seed, &ps);
|
||||
/* if this is true, means that seed was not pointed character
|
||||
started byte. So correct the point and consume count */
|
||||
if (seed < point)
|
||||
count --;
|
||||
|
||||
while (count > 0)
|
||||
{
|
||||
tmp = mbrtowc (&wc, string+point, strlen(string + point), &ps);
|
||||
if ((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2)
|
||||
{
|
||||
/* invalid bytes. asume a byte represents a character */
|
||||
point++;
|
||||
count--;
|
||||
/* reset states. */
|
||||
memset(&ps, 0, sizeof(mbstate_t));
|
||||
}
|
||||
else if (tmp == (size_t)0)
|
||||
/* found '\0' char */
|
||||
break;
|
||||
else
|
||||
{
|
||||
/* valid bytes */
|
||||
point += tmp;
|
||||
if (find_non_zero)
|
||||
{
|
||||
if (wcwidth (wc) == 0)
|
||||
continue;
|
||||
else
|
||||
count--;
|
||||
}
|
||||
else
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
if (find_non_zero)
|
||||
{
|
||||
tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
|
||||
while (wcwidth (wc) == 0)
|
||||
{
|
||||
point += tmp;
|
||||
tmp = mbrtowc (&wc, string + point, strlen (string + point), &ps);
|
||||
if (tmp == (size_t)(0) || tmp == (size_t)(-1) || tmp == (size_t)(-2))
|
||||
break;
|
||||
}
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
static int
|
||||
_rl_find_prev_mbchar_internal (string, seed, find_non_zero)
|
||||
char *string;
|
||||
int seed, find_non_zero;
|
||||
{
|
||||
mbstate_t ps;
|
||||
int prev, non_zero_prev, point, length;
|
||||
size_t tmp;
|
||||
wchar_t wc;
|
||||
|
||||
memset(&ps, 0, sizeof(mbstate_t));
|
||||
length = strlen(string);
|
||||
|
||||
if (seed < 0)
|
||||
return 0;
|
||||
else if (length < seed)
|
||||
return length;
|
||||
|
||||
prev = non_zero_prev = point = 0;
|
||||
while (point < seed)
|
||||
{
|
||||
tmp = mbrtowc (&wc, string + point, length - point, &ps);
|
||||
if ((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2)
|
||||
{
|
||||
/* in this case, bytes are invalid or shorted to compose
|
||||
multibyte char, so assume that the first byte represents
|
||||
a single character anyway. */
|
||||
tmp = 1;
|
||||
/* clear the state of the byte sequence, because
|
||||
in this case effect of mbstate is undefined */
|
||||
memset(&ps, 0, sizeof (mbstate_t));
|
||||
}
|
||||
else if (tmp == 0)
|
||||
break; /* Found '\0' char. Can this happen? */
|
||||
else
|
||||
{
|
||||
if (find_non_zero)
|
||||
{
|
||||
if (wcwidth (wc) != 0)
|
||||
prev = point;
|
||||
}
|
||||
else
|
||||
prev = point;
|
||||
}
|
||||
|
||||
point += tmp;
|
||||
}
|
||||
|
||||
return prev;
|
||||
}
|
||||
|
||||
/* return the number of bytes parsed from the multibyte sequence starting
|
||||
at src, if a non-L'\0' wide character was recognized. It returns 0,
|
||||
if a L'\0' wide character was recognized. It returns (size_t)(-1),
|
||||
if an invalid multibyte sequence was encountered. It returns (size_t)(-2)
|
||||
if it couldn't parse a complete multibyte character. */
|
||||
int
|
||||
_rl_get_char_len (src, ps)
|
||||
char *src;
|
||||
mbstate_t *ps;
|
||||
{
|
||||
size_t tmp;
|
||||
|
||||
tmp = mbrlen((const char *)src, (size_t)strlen (src), ps);
|
||||
if (tmp == (size_t)(-2))
|
||||
{
|
||||
/* shorted to compose multibyte char */
|
||||
memset (ps, 0, sizeof(mbstate_t));
|
||||
return -2;
|
||||
}
|
||||
else if (tmp == (size_t)(-1))
|
||||
{
|
||||
/* invalid to compose multibyte char */
|
||||
/* initialize the conversion state */
|
||||
memset (ps, 0, sizeof(mbstate_t));
|
||||
return -1;
|
||||
}
|
||||
else if (tmp == (size_t)0)
|
||||
return 0;
|
||||
else
|
||||
return (int)tmp;
|
||||
}
|
||||
|
||||
/* compare the specified two characters. If the characters matched,
|
||||
return 1. Otherwise return 0. */
|
||||
int
|
||||
_rl_compare_chars (buf1, pos1, ps1, buf2, pos2, ps2)
|
||||
char *buf1, *buf2;
|
||||
mbstate_t *ps1, *ps2;
|
||||
int pos1, pos2;
|
||||
{
|
||||
int i, w1, w2;
|
||||
|
||||
if ((w1 = _rl_get_char_len (&buf1[pos1], ps1)) <= 0 ||
|
||||
(w2 = _rl_get_char_len (&buf2[pos2], ps2)) <= 0 ||
|
||||
(w1 != w2) ||
|
||||
(buf1[pos1] != buf2[pos2]))
|
||||
return 0;
|
||||
|
||||
for (i = 1; i < w1; i++)
|
||||
if (buf1[pos1+i] != buf2[pos2+i])
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* adjust pointed byte and find mbstate of the point of string.
|
||||
adjusted point will be point <= adjusted_point, and returns
|
||||
differences of the byte(adjusted_point - point).
|
||||
if point is invalied (point < 0 || more than string length),
|
||||
it returns -1 */
|
||||
int
|
||||
_rl_adjust_point(string, point, ps)
|
||||
char *string;
|
||||
int point;
|
||||
mbstate_t *ps;
|
||||
{
|
||||
size_t tmp = 0;
|
||||
int length;
|
||||
int pos = 0;
|
||||
|
||||
length = strlen(string);
|
||||
if (point < 0)
|
||||
return -1;
|
||||
if (length < point)
|
||||
return -1;
|
||||
|
||||
while (pos < point)
|
||||
{
|
||||
tmp = mbrlen (string + pos, length - pos, ps);
|
||||
if((size_t)(tmp) == (size_t)-1 || (size_t)(tmp) == (size_t)-2)
|
||||
{
|
||||
/* in this case, bytes are invalid or shorted to compose
|
||||
multibyte char, so assume that the first byte represents
|
||||
a single character anyway. */
|
||||
pos++;
|
||||
/* clear the state of the byte sequence, because
|
||||
in this case effect of mbstate is undefined */
|
||||
memset (ps, 0, sizeof (mbstate_t));
|
||||
}
|
||||
else
|
||||
pos += tmp;
|
||||
}
|
||||
|
||||
return (pos - point);
|
||||
}
|
||||
|
||||
int
|
||||
_rl_is_mbchar_matched (string, seed, end, mbchar, length)
|
||||
char *string;
|
||||
int seed, end;
|
||||
char *mbchar;
|
||||
int length;
|
||||
{
|
||||
int i;
|
||||
|
||||
if ((end - seed) < length)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
if (string[seed + i] != mbchar[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
||||
/* Find next `count' characters started byte point of the specified seed.
|
||||
If flags is MB_FIND_NONZERO, we look for non-zero-width multibyte
|
||||
characters. */
|
||||
#undef _rl_find_next_mbchar
|
||||
int
|
||||
_rl_find_next_mbchar (string, seed, count, flags)
|
||||
char *string;
|
||||
int seed, count, flags;
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
return _rl_find_next_mbchar_internal (string, seed, count, flags);
|
||||
#else
|
||||
return (seed + count);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Find previous character started byte point of the specified seed.
|
||||
Returned point will be point <= seed. If flags is MB_FIND_NONZERO,
|
||||
we look for non-zero-width multibyte characters. */
|
||||
#undef _rl_find_prev_mbchar
|
||||
int
|
||||
_rl_find_prev_mbchar (string, seed, flags)
|
||||
char *string;
|
||||
int seed, flags;
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
return _rl_find_prev_mbchar_internal (string, seed, flags);
|
||||
#else
|
||||
return ((seed == 0) ? seed : seed - 1);
|
||||
#endif
|
||||
}
|
||||
496
lib/readline/misc.c
Normal file
496
lib/readline/misc.c
Normal file
|
|
@ -0,0 +1,496 @@
|
|||
/* misc.c -- miscellaneous bindable readline functions. */
|
||||
|
||||
/* Copyright (C) 1987-2002 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
|
||||
|
||||
#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_LOCALE_H)
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
#include "history.h"
|
||||
|
||||
#include "rlprivate.h"
|
||||
#include "rlshell.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
static int rl_digit_loop PARAMS((void));
|
||||
static void _rl_history_set_point PARAMS((void));
|
||||
|
||||
/* Forward declarations used in this file */
|
||||
void _rl_free_history_entry PARAMS((HIST_ENTRY *));
|
||||
|
||||
/* If non-zero, rl_get_previous_history and rl_get_next_history attempt
|
||||
to preserve the value of rl_point from line to line. */
|
||||
int _rl_history_preserve_point = 0;
|
||||
|
||||
/* Saved target point for when _rl_history_preserve_point is set. Special
|
||||
value of -1 means that point is at the end of the line. */
|
||||
int _rl_history_saved_point = -1;
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Numeric Arguments */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Handle C-u style numeric args, as well as M--, and M-digits. */
|
||||
static int
|
||||
rl_digit_loop ()
|
||||
{
|
||||
int key, c, sawminus, sawdigits;
|
||||
|
||||
rl_save_prompt ();
|
||||
|
||||
RL_SETSTATE(RL_STATE_NUMERICARG);
|
||||
sawminus = sawdigits = 0;
|
||||
while (1)
|
||||
{
|
||||
if (rl_numeric_arg > 1000000)
|
||||
{
|
||||
sawdigits = rl_explicit_arg = rl_numeric_arg = 0;
|
||||
rl_ding ();
|
||||
rl_restore_prompt ();
|
||||
rl_clear_message ();
|
||||
RL_UNSETSTATE(RL_STATE_NUMERICARG);
|
||||
return 1;
|
||||
}
|
||||
rl_message ("(arg: %d) ", rl_arg_sign * rl_numeric_arg);
|
||||
RL_SETSTATE(RL_STATE_MOREINPUT);
|
||||
key = c = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
|
||||
if (c < 0)
|
||||
{
|
||||
_rl_abort_internal ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* If we see a key bound to `universal-argument' after seeing digits,
|
||||
it ends the argument but is otherwise ignored. */
|
||||
if (_rl_keymap[c].type == ISFUNC &&
|
||||
_rl_keymap[c].function == rl_universal_argument)
|
||||
{
|
||||
if (sawdigits == 0)
|
||||
{
|
||||
rl_numeric_arg *= 4;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
RL_SETSTATE(RL_STATE_MOREINPUT);
|
||||
key = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
rl_restore_prompt ();
|
||||
rl_clear_message ();
|
||||
RL_UNSETSTATE(RL_STATE_NUMERICARG);
|
||||
return (_rl_dispatch (key, _rl_keymap));
|
||||
}
|
||||
}
|
||||
|
||||
c = UNMETA (c);
|
||||
|
||||
if (_rl_digit_p (c))
|
||||
{
|
||||
rl_numeric_arg = rl_explicit_arg ? (rl_numeric_arg * 10) + c - '0' : c - '0';
|
||||
sawdigits = rl_explicit_arg = 1;
|
||||
}
|
||||
else if (c == '-' && rl_explicit_arg == 0)
|
||||
{
|
||||
rl_numeric_arg = sawminus = 1;
|
||||
rl_arg_sign = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Make M-- command equivalent to M--1 command. */
|
||||
if (sawminus && rl_numeric_arg == 1 && rl_explicit_arg == 0)
|
||||
rl_explicit_arg = 1;
|
||||
rl_restore_prompt ();
|
||||
rl_clear_message ();
|
||||
RL_UNSETSTATE(RL_STATE_NUMERICARG);
|
||||
return (_rl_dispatch (key, _rl_keymap));
|
||||
}
|
||||
}
|
||||
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
/* Add the current digit to the argument in progress. */
|
||||
int
|
||||
rl_digit_argument (ignore, key)
|
||||
int ignore, key;
|
||||
{
|
||||
rl_execute_next (key);
|
||||
return (rl_digit_loop ());
|
||||
}
|
||||
|
||||
/* What to do when you abort reading an argument. */
|
||||
int
|
||||
rl_discard_argument ()
|
||||
{
|
||||
rl_ding ();
|
||||
rl_clear_message ();
|
||||
_rl_init_argument ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Create a default argument. */
|
||||
int
|
||||
_rl_init_argument ()
|
||||
{
|
||||
rl_numeric_arg = rl_arg_sign = 1;
|
||||
rl_explicit_arg = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* C-u, universal argument. Multiply the current argument by 4.
|
||||
Read a key. If the key has nothing to do with arguments, then
|
||||
dispatch on it. If the key is the abort character then abort. */
|
||||
int
|
||||
rl_universal_argument (count, key)
|
||||
int count, key;
|
||||
{
|
||||
rl_numeric_arg *= 4;
|
||||
return (rl_digit_loop ());
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* History Utilities */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* We already have a history library, and that is what we use to control
|
||||
the history features of readline. This is our local interface to
|
||||
the history mechanism. */
|
||||
|
||||
/* While we are editing the history, this is the saved
|
||||
version of the original line. */
|
||||
HIST_ENTRY *_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
|
||||
/* Set the history pointer back to the last entry in the history. */
|
||||
void
|
||||
_rl_start_using_history ()
|
||||
{
|
||||
using_history ();
|
||||
if (_rl_saved_line_for_history)
|
||||
_rl_free_history_entry (_rl_saved_line_for_history);
|
||||
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
}
|
||||
|
||||
/* Free the contents (and containing structure) of a HIST_ENTRY. */
|
||||
void
|
||||
_rl_free_history_entry (entry)
|
||||
HIST_ENTRY *entry;
|
||||
{
|
||||
if (entry == 0)
|
||||
return;
|
||||
if (entry->line)
|
||||
free (entry->line);
|
||||
free (entry);
|
||||
}
|
||||
|
||||
/* Perhaps put back the current line if it has changed. */
|
||||
int
|
||||
rl_maybe_replace_line ()
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
|
||||
temp = current_history ();
|
||||
/* If the current line has changed, save the changes. */
|
||||
if (temp && ((UNDO_LIST *)(temp->data) != rl_undo_list))
|
||||
{
|
||||
temp = replace_history_entry (where_history (), rl_line_buffer, (histdata_t)rl_undo_list);
|
||||
free (temp->line);
|
||||
free (temp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Restore the _rl_saved_line_for_history if there is one. */
|
||||
int
|
||||
rl_maybe_unsave_line ()
|
||||
{
|
||||
if (_rl_saved_line_for_history)
|
||||
{
|
||||
rl_replace_line (_rl_saved_line_for_history->line, 0);
|
||||
rl_undo_list = (UNDO_LIST *)_rl_saved_line_for_history->data;
|
||||
_rl_free_history_entry (_rl_saved_line_for_history);
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
rl_point = rl_end; /* rl_replace_line sets rl_end */
|
||||
}
|
||||
else
|
||||
rl_ding ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the current line in _rl_saved_line_for_history. */
|
||||
int
|
||||
rl_maybe_save_line ()
|
||||
{
|
||||
if (_rl_saved_line_for_history == 0)
|
||||
{
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
|
||||
_rl_saved_line_for_history->line = savestring (rl_line_buffer);
|
||||
_rl_saved_line_for_history->data = (char *)rl_undo_list;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_rl_free_saved_history_line ()
|
||||
{
|
||||
if (_rl_saved_line_for_history)
|
||||
{
|
||||
_rl_free_history_entry (_rl_saved_line_for_history);
|
||||
_rl_saved_line_for_history = (HIST_ENTRY *)NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_rl_history_set_point ()
|
||||
{
|
||||
rl_point = (_rl_history_preserve_point && _rl_history_saved_point != -1)
|
||||
? _rl_history_saved_point
|
||||
: rl_end;
|
||||
if (rl_point > rl_end)
|
||||
rl_point = rl_end;
|
||||
|
||||
#if defined (VI_MODE)
|
||||
if (rl_editing_mode == vi_mode)
|
||||
rl_point = 0;
|
||||
#endif /* VI_MODE */
|
||||
|
||||
if (rl_editing_mode == emacs_mode)
|
||||
rl_mark = (rl_point == rl_end ? 0 : rl_end);
|
||||
}
|
||||
|
||||
void
|
||||
rl_replace_from_history (entry, flags)
|
||||
HIST_ENTRY *entry;
|
||||
int flags; /* currently unused */
|
||||
{
|
||||
rl_replace_line (entry->line, 0);
|
||||
rl_undo_list = (UNDO_LIST *)entry->data;
|
||||
rl_point = rl_end;
|
||||
rl_mark = 0;
|
||||
|
||||
#if defined (VI_MODE)
|
||||
if (rl_editing_mode == vi_mode)
|
||||
{
|
||||
rl_point = 0;
|
||||
rl_mark = rl_end;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* History Commands */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Meta-< goes to the start of the history. */
|
||||
int
|
||||
rl_beginning_of_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
return (rl_get_previous_history (1 + where_history (), key));
|
||||
}
|
||||
|
||||
/* Meta-> goes to the end of the history. (The current line). */
|
||||
int
|
||||
rl_end_of_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
rl_maybe_replace_line ();
|
||||
using_history ();
|
||||
rl_maybe_unsave_line ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Move down to the next history line. */
|
||||
int
|
||||
rl_get_next_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
|
||||
if (count < 0)
|
||||
return (rl_get_previous_history (-count, key));
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
rl_maybe_replace_line ();
|
||||
|
||||
/* either not saved by rl_newline or at end of line, so set appropriately. */
|
||||
if (_rl_history_saved_point == -1 && (rl_point || rl_end))
|
||||
_rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
|
||||
|
||||
temp = (HIST_ENTRY *)NULL;
|
||||
while (count)
|
||||
{
|
||||
temp = next_history ();
|
||||
if (!temp)
|
||||
break;
|
||||
--count;
|
||||
}
|
||||
|
||||
if (temp == 0)
|
||||
rl_maybe_unsave_line ();
|
||||
else
|
||||
{
|
||||
rl_replace_from_history (temp, 0);
|
||||
_rl_history_set_point ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the previous item out of our interactive history, making it the current
|
||||
line. If there is no previous history, just ding. */
|
||||
int
|
||||
rl_get_previous_history (count, key)
|
||||
int count, key;
|
||||
{
|
||||
HIST_ENTRY *old_temp, *temp;
|
||||
|
||||
if (count < 0)
|
||||
return (rl_get_next_history (-count, key));
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
/* either not saved by rl_newline or at end of line, so set appropriately. */
|
||||
if (_rl_history_saved_point == -1 && (rl_point || rl_end))
|
||||
_rl_history_saved_point = (rl_point == rl_end) ? -1 : rl_point;
|
||||
|
||||
/* If we don't have a line saved, then save this one. */
|
||||
rl_maybe_save_line ();
|
||||
|
||||
/* If the current line has changed, save the changes. */
|
||||
rl_maybe_replace_line ();
|
||||
|
||||
temp = old_temp = (HIST_ENTRY *)NULL;
|
||||
while (count)
|
||||
{
|
||||
temp = previous_history ();
|
||||
if (temp == 0)
|
||||
break;
|
||||
|
||||
old_temp = temp;
|
||||
--count;
|
||||
}
|
||||
|
||||
/* If there was a large argument, and we moved back to the start of the
|
||||
history, that is not an error. So use the last value found. */
|
||||
if (!temp && old_temp)
|
||||
temp = old_temp;
|
||||
|
||||
if (temp == 0)
|
||||
rl_ding ();
|
||||
else
|
||||
{
|
||||
rl_replace_from_history (temp, 0);
|
||||
_rl_history_set_point ();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Editing Modes */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
/* How to toggle back and forth between editing modes. */
|
||||
int
|
||||
rl_vi_editing_mode (count, key)
|
||||
int count, key;
|
||||
{
|
||||
#if defined (VI_MODE)
|
||||
_rl_set_insert_mode (RL_IM_INSERT, 1); /* vi mode ignores insert mode */
|
||||
rl_editing_mode = vi_mode;
|
||||
rl_vi_insertion_mode (1, key);
|
||||
#endif /* VI_MODE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rl_emacs_editing_mode (count, key)
|
||||
int count, key;
|
||||
{
|
||||
rl_editing_mode = emacs_mode;
|
||||
_rl_set_insert_mode (RL_IM_INSERT, 1); /* emacs mode default is insert mode */
|
||||
_rl_keymap = emacs_standard_keymap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Function for the rest of the library to use to set insert/overwrite mode. */
|
||||
void
|
||||
_rl_set_insert_mode (im, force)
|
||||
int im, force;
|
||||
{
|
||||
#ifdef CURSOR_MODE
|
||||
_rl_set_cursor (im, force);
|
||||
#endif
|
||||
|
||||
rl_insert_mode = im;
|
||||
}
|
||||
|
||||
/* Toggle overwrite mode. A positive explicit argument selects overwrite
|
||||
mode. A negative or zero explicit argument selects insert mode. */
|
||||
int
|
||||
rl_overwrite_mode (count, key)
|
||||
int count, key;
|
||||
{
|
||||
if (rl_explicit_arg == 0)
|
||||
_rl_set_insert_mode (rl_insert_mode ^ 1, 0);
|
||||
else if (count > 0)
|
||||
_rl_set_insert_mode (RL_IM_OVERWRITE, 0);
|
||||
else
|
||||
_rl_set_insert_mode (RL_IM_INSERT, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -30,6 +30,10 @@
|
|||
#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
|
||||
|
|
@ -103,7 +107,7 @@ rl_insert_close (count, invoking_key)
|
|||
int count, invoking_key;
|
||||
{
|
||||
if (rl_explicit_arg || !rl_blink_matching_paren)
|
||||
rl_insert (count, invoking_key);
|
||||
_rl_insert_char (count, invoking_key);
|
||||
else
|
||||
{
|
||||
#if defined (HAVE_SELECT)
|
||||
|
|
@ -111,7 +115,7 @@ rl_insert_close (count, invoking_key)
|
|||
struct timeval timer;
|
||||
fd_set readfds;
|
||||
|
||||
rl_insert (1, invoking_key);
|
||||
_rl_insert_char (1, invoking_key);
|
||||
(*rl_redisplay_function) ();
|
||||
match_point =
|
||||
find_matching_open (rl_line_buffer, rl_point - 2, invoking_key);
|
||||
|
|
@ -131,7 +135,7 @@ rl_insert_close (count, invoking_key)
|
|||
ready = select (1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer);
|
||||
rl_point = orig_point;
|
||||
#else /* !HAVE_SELECT */
|
||||
rl_insert (count, invoking_key);
|
||||
_rl_insert_char (count, invoking_key);
|
||||
#endif /* !HAVE_SELECT */
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -46,4 +46,12 @@
|
|||
# define d_fileno d_ino
|
||||
#endif
|
||||
|
||||
#if defined (_POSIX_SOURCE) && (!defined (STRUCT_DIRENT_HAS_D_INO) || defined (BROKEN_DIRENT_D_INO))
|
||||
/* Posix does not require that the d_ino field be present, and some
|
||||
systems do not provide it. */
|
||||
# define REAL_DIR_ENTRY(dp) 1
|
||||
#else
|
||||
# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
|
||||
#endif /* _POSIX_SOURCE */
|
||||
|
||||
#endif /* !_POSIXDIR_H_ */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -29,18 +29,20 @@ extern "C" {
|
|||
|
||||
#if defined (READLINE_LIBRARY)
|
||||
# include "rlstdc.h"
|
||||
# include "rltypedefs.h"
|
||||
# include "keymaps.h"
|
||||
# include "tilde.h"
|
||||
#else
|
||||
# include <readline/rlstdc.h>
|
||||
# include <readline/rltypedefs.h>
|
||||
# include <readline/keymaps.h>
|
||||
# include <readline/tilde.h>
|
||||
#endif
|
||||
|
||||
/* Hex-encoded Readline version number. */
|
||||
#define RL_READLINE_VERSION 0x0402 /* Readline 4.2 */
|
||||
#define RL_READLINE_VERSION 0x0403 /* Readline 4.3 */
|
||||
#define RL_VERSION_MAJOR 4
|
||||
#define RL_VERSION_MINOR 2
|
||||
#define RL_VERSION_MINOR 3
|
||||
|
||||
/* Readline data structures. */
|
||||
|
||||
|
|
@ -82,7 +84,11 @@ extern int rl_digit_argument PARAMS((int, int));
|
|||
extern int rl_universal_argument PARAMS((int, int));
|
||||
|
||||
/* Bindable commands for moving the cursor. */
|
||||
extern int rl_forward_byte PARAMS((int, int));
|
||||
extern int rl_forward_char PARAMS((int, int));
|
||||
extern int rl_forward PARAMS((int, int));
|
||||
extern int rl_backward_byte PARAMS((int, int));
|
||||
extern int rl_backward_char PARAMS((int, int));
|
||||
extern int rl_backward PARAMS((int, int));
|
||||
extern int rl_beg_of_line PARAMS((int, int));
|
||||
extern int rl_end_of_line PARAMS((int, int));
|
||||
|
|
@ -132,6 +138,9 @@ extern int rl_exchange_point_and_mark PARAMS((int, int));
|
|||
extern int rl_vi_editing_mode PARAMS((int, int));
|
||||
extern int rl_emacs_editing_mode PARAMS((int, int));
|
||||
|
||||
/* Bindable commands to change the insert mode (insert or overwrite) */
|
||||
extern int rl_overwrite_mode PARAMS((int, int));
|
||||
|
||||
/* Bindable commands for managing key bindings. */
|
||||
extern int rl_re_read_init_file PARAMS((int, int));
|
||||
extern int rl_dump_functions PARAMS((int, int));
|
||||
|
|
@ -365,6 +374,7 @@ extern void rl_save_prompt PARAMS((void));
|
|||
extern void rl_restore_prompt PARAMS((void));
|
||||
|
||||
/* Modifying text. */
|
||||
extern void rl_replace_line PARAMS((const char *, int));
|
||||
extern int rl_insert_text PARAMS((const char *));
|
||||
extern int rl_delete_text PARAMS((int, int));
|
||||
extern int rl_kill_text PARAMS((int, int));
|
||||
|
|
@ -417,6 +427,8 @@ extern char **rl_completion_matches PARAMS((const char *, rl_compentry_func_t *)
|
|||
extern char *rl_username_completion_function PARAMS((const char *, int));
|
||||
extern char *rl_filename_completion_function PARAMS((const char *, int));
|
||||
|
||||
extern int rl_completion_mode PARAMS((rl_command_func_t *));
|
||||
|
||||
#if 0
|
||||
/* Backwards compatibility (compat.c). These will go away sometime. */
|
||||
extern void free_undo_list PARAMS((void));
|
||||
|
|
@ -453,6 +465,10 @@ extern int rl_readline_state;
|
|||
0 means vi mode. */
|
||||
extern int rl_editing_mode;
|
||||
|
||||
/* Insert or overwrite mode for emacs mode. 1 means insert mode; 0 means
|
||||
overwrite mode. Reset to insert mode on each input line. */
|
||||
extern int rl_insert_mode;
|
||||
|
||||
/* The name of the calling program. You should initialize this to
|
||||
whatever was in argv[0]. It is used when parsing conditionals. */
|
||||
extern const char *rl_readline_name;
|
||||
|
|
@ -675,18 +691,33 @@ extern int rl_completion_type;
|
|||
default is a space. Nothing is added if this is '\0'. */
|
||||
extern int rl_completion_append_character;
|
||||
|
||||
/* If set to non-zero by an application completion function,
|
||||
rl_completion_append_character will not be appended. */
|
||||
extern int rl_completion_suppress_append;
|
||||
|
||||
/* Up to this many items will be displayed in response to a
|
||||
possible-completions call. After that, we ask the user if she
|
||||
is sure she wants to see them all. The default value is 100. */
|
||||
extern int rl_completion_query_items;
|
||||
|
||||
/* If non-zero, a slash will be appended to completed filenames that are
|
||||
symbolic links to directory names, subject to the value of the
|
||||
mark-directories variable (which is user-settable). This exists so
|
||||
that application completion functions can override the user's preference
|
||||
(set via the mark-symlinked-directories variable) if appropriate.
|
||||
It's set to the value of _rl_complete_mark_symlink_dirs in
|
||||
rl_complete_internal before any application-specific completion
|
||||
function is called, so without that function doing anything, the user's
|
||||
preferences are honored. */
|
||||
extern int rl_completion_mark_symlink_dirs;
|
||||
|
||||
/* If non-zero, then disallow duplicates in the matches. */
|
||||
extern int rl_ignore_completion_duplicates;
|
||||
|
||||
/* If this is non-zero, completion is (temporarily) inhibited, and the
|
||||
completion character will be inserted as any other. */
|
||||
extern int rl_inhibit_completion;
|
||||
|
||||
|
||||
/* Definitions available for use by readline clients. */
|
||||
#define RL_PROMPT_START_IGNORE '\001'
|
||||
#define RL_PROMPT_END_IGNORE '\002'
|
||||
|
|
@ -725,6 +756,42 @@ extern int rl_inhibit_completion;
|
|||
#define RL_UNSETSTATE(x) (rl_readline_state &= ~(x))
|
||||
#define RL_ISSTATE(x) (rl_readline_state & (x))
|
||||
|
||||
struct readline_state {
|
||||
/* line state */
|
||||
int point;
|
||||
int end;
|
||||
int mark;
|
||||
char *buffer;
|
||||
int buflen;
|
||||
UNDO_LIST *ul;
|
||||
char *prompt;
|
||||
|
||||
/* global state */
|
||||
int rlstate;
|
||||
int done;
|
||||
Keymap kmap;
|
||||
|
||||
/* input state */
|
||||
rl_command_func_t *lastfunc;
|
||||
int insmode;
|
||||
int edmode;
|
||||
int kseqlen;
|
||||
FILE *inf;
|
||||
FILE *outf;
|
||||
int pendingin;
|
||||
char *macro;
|
||||
|
||||
/* signal state */
|
||||
int catchsigs;
|
||||
int catchsigwinch;
|
||||
|
||||
/* reserved for future expansion, so the struct size doesn't change */
|
||||
char reserved[64];
|
||||
};
|
||||
|
||||
extern int rl_save_state PARAMS((struct readline_state *));
|
||||
extern int rl_restore_state PARAMS((struct readline_state *));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -54,4 +54,7 @@
|
|||
X `callback' style. */
|
||||
#define READLINE_CALLBACKS
|
||||
|
||||
/* Define this if you want the cursor to indicate insert or overwrite mode. */
|
||||
/* #define CURSOR_MODE */
|
||||
|
||||
#endif /* _RLCONF_H_ */
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ extern char *strchr (), *strrchr ();
|
|||
#define _rl_strnicmp strncasecmp
|
||||
#else
|
||||
extern int _rl_stricmp PARAMS((char *, char *));
|
||||
extern int _rl_strnicmp PARAMS((char *, char *));
|
||||
extern int _rl_strnicmp PARAMS((char *, char *, int));
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_STRPBRK)
|
||||
|
|
@ -89,6 +89,13 @@ extern char *_rl_strpbrk PARAMS((const char *, const char *));
|
|||
# define emacs_mode 1
|
||||
#endif
|
||||
|
||||
#if !defined (RL_IM_INSERT)
|
||||
# define RL_IM_INSERT 1
|
||||
# define RL_IM_OVERWRITE 0
|
||||
#
|
||||
# define RL_IM_DEFAULT RL_IM_INSERT
|
||||
#endif
|
||||
|
||||
/* If you cast map[key].function to type (Keymap) on a Cray,
|
||||
the compiler takes the value of map[key].function and
|
||||
divides it by 4 to convert between pointer types (pointers
|
||||
|
|
@ -121,9 +128,10 @@ extern char *_rl_strpbrk PARAMS((const char *, const char *));
|
|||
/* Possible values for the found_quote flags word used by the completion
|
||||
functions. It says what kind of (shell-like) quoting we found anywhere
|
||||
in the line. */
|
||||
#define RL_QF_SINGLE_QUOTE 0x1
|
||||
#define RL_QF_DOUBLE_QUOTE 0x2
|
||||
#define RL_QF_BACKSLASH 0x4
|
||||
#define RL_QF_SINGLE_QUOTE 0x01
|
||||
#define RL_QF_DOUBLE_QUOTE 0x02
|
||||
#define RL_QF_BACKSLASH 0x04
|
||||
#define RL_QF_OTHER_QUOTE 0x08
|
||||
|
||||
/* Default readline line buffer length. */
|
||||
#define DEFAULT_BUFFER_SIZE 256
|
||||
|
|
@ -138,6 +146,10 @@ extern char *_rl_strpbrk PARAMS((const char *, const char *));
|
|||
# define FREE(x) if (x) free (x)
|
||||
#endif
|
||||
|
||||
#if !defined (SWAP)
|
||||
# define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0)
|
||||
#endif
|
||||
|
||||
/* CONFIGURATION SECTION */
|
||||
#include "rlconf.h"
|
||||
|
||||
|
|
|
|||
108
lib/readline/rlmbutil.h
Normal file
108
lib/readline/rlmbutil.h
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/* rlmbutil.h -- utility functions for multibyte characters. */
|
||||
|
||||
/* Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library, a library for
|
||||
reading lines of text with interactive input and history editing.
|
||||
|
||||
The GNU Readline Library is free software; you can redistribute it
|
||||
and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2, or
|
||||
(at your option) any later version.
|
||||
|
||||
The GNU Readline Library is distributed in the hope that it will be
|
||||
useful, but WITHOUT ANY WARRANTY; without even the implied warranty
|
||||
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
The GNU General Public License is often shipped with GNU software, and
|
||||
is generally kept in a file called COPYING or LICENSE. If you do not
|
||||
have a copy of the license, write to the Free Software Foundation,
|
||||
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#if !defined (_RL_MBUTIL_H_)
|
||||
#define _RL_MBUTIL_H_
|
||||
|
||||
#include "rlstdc.h"
|
||||
|
||||
/************************************************/
|
||||
/* check multibyte capability for I18N code */
|
||||
/************************************************/
|
||||
|
||||
/* For platforms which support the ISO C amendement 1 functionality we
|
||||
support user defined character classes. */
|
||||
/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */
|
||||
#if defined (HAVE_WCTYPE_H) && defined (HAVE_WCHAR_H)
|
||||
# include <wchar.h>
|
||||
# include <wctype.h>
|
||||
# if defined (HAVE_MBSRTOWCS) /* system is supposed to support XPG5 */
|
||||
# define HANDLE_MULTIBYTE 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Some systems, like BeOS, have multibyte encodings but lack mbstate_t. */
|
||||
#if HANDLE_MULTIBYTE && !defined (HAVE_MBSTATE_T)
|
||||
# define wcsrtombs(dest, src, len, ps) (wcsrtombs) (dest, src, len, 0)
|
||||
# define mbsrtowcs(dest, src, len, ps) (mbsrtowcs) (dest, src, len, 0)
|
||||
# define wcrtomb(s, wc, ps) (wcrtomb) (s, wc, 0)
|
||||
# define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
|
||||
# define mbrlen(s, n, ps) (mbrlen) (s, n, 0)
|
||||
# define mbstate_t int
|
||||
#endif
|
||||
|
||||
/* Make sure MB_LEN_MAX is at least 16 on systems that claim to be able to
|
||||
handle multibyte chars (some systems define MB_LEN_MAX as 1) */
|
||||
#ifdef HANDLE_MULTIBYTE
|
||||
# include <limits.h>
|
||||
# if defined(MB_LEN_MAX) && (MB_LEN_MAX < 16)
|
||||
# undef MB_LEN_MAX
|
||||
# endif
|
||||
# if !defined (MB_LEN_MAX)
|
||||
# define MB_LEN_MAX 16
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/************************************************/
|
||||
/* end of multibyte capability checks for I18N */
|
||||
/************************************************/
|
||||
|
||||
/*
|
||||
* Flags for _rl_find_prev_mbchar and _rl_find_next_mbchar:
|
||||
*
|
||||
* MB_FIND_ANY find any multibyte character
|
||||
* MB_FIND_NONZERO find a non-zero-width multibyte character
|
||||
*/
|
||||
|
||||
#define MB_FIND_ANY 0x00
|
||||
#define MB_FIND_NONZERO 0x01
|
||||
|
||||
extern int _rl_find_prev_mbchar PARAMS((char *, int, int));
|
||||
extern int _rl_find_next_mbchar PARAMS((char *, int, int, int));
|
||||
|
||||
#ifdef HANDLE_MULTIBYTE
|
||||
|
||||
extern int _rl_compare_chars PARAMS((char *, int, mbstate_t *, char *, int, mbstate_t *));
|
||||
extern int _rl_get_char_len PARAMS((char *, mbstate_t *));
|
||||
extern int _rl_adjust_point PARAMS((char *, int, mbstate_t *));
|
||||
|
||||
extern int _rl_read_mbchar PARAMS((char *, int));
|
||||
extern int _rl_read_mbstring PARAMS((int, char *, int));
|
||||
|
||||
extern int _rl_is_mbchar_matched PARAMS((char *, int, int, char *, int));
|
||||
|
||||
#else /* !HANDLE_MULTIBYTE */
|
||||
|
||||
#undef MB_LEN_MAX
|
||||
#undef MB_CUR_MAX
|
||||
|
||||
#define MB_LEN_MAX 1
|
||||
#define MB_CUR_MAX 1
|
||||
|
||||
#define _rl_find_prev_mbchar(b, i, f) (((i) == 0) ? (i) : ((i) - 1))
|
||||
#define _rl_find_next_mbchar(b, i1, i2, f) ((i1) + (i2))
|
||||
|
||||
#endif /* !HANDLE_MULTIBYTE */
|
||||
|
||||
extern int rl_byte_oriented;
|
||||
|
||||
#endif /* _RL_MBUTIL_H_ */
|
||||
|
|
@ -52,6 +52,7 @@ extern int rl_arg_sign;
|
|||
extern int rl_visible_prompt_length;
|
||||
extern int readline_echoing_p;
|
||||
extern int rl_key_sequence_length;
|
||||
extern int rl_byte_oriented;
|
||||
|
||||
/* display.c */
|
||||
extern int rl_display_fixed;
|
||||
|
|
@ -65,18 +66,9 @@ extern int rl_blink_matching_paren;
|
|||
* *
|
||||
*************************************************************************/
|
||||
|
||||
/* bind.c */
|
||||
extern char *rl_untranslate_keyseq PARAMS((int));
|
||||
|
||||
/* kill.c */
|
||||
extern int rl_set_retained_kills PARAMS((int));
|
||||
|
||||
/* readline.c */
|
||||
extern int rl_discard_argument PARAMS((void));
|
||||
|
||||
/* rltty.c */
|
||||
extern int rl_stop_output PARAMS((int, int));
|
||||
|
||||
/* terminal.c */
|
||||
extern void _rl_set_screen_size PARAMS((int, int));
|
||||
|
||||
|
|
@ -113,6 +105,10 @@ extern int readline_internal_char PARAMS((void));
|
|||
/* bind.c */
|
||||
extern void _rl_bind_if_unbound PARAMS((const char *, rl_command_func_t *));
|
||||
|
||||
/* complete.c */
|
||||
extern char _rl_find_completion_word PARAMS((int *, int *));
|
||||
extern void _rl_free_match_list PARAMS((char **));
|
||||
|
||||
/* display.c */
|
||||
extern char *_rl_strip_prompt PARAMS((char *));
|
||||
extern void _rl_move_cursor_relative PARAMS((int, const char *));
|
||||
|
|
@ -132,7 +128,9 @@ extern int _rl_current_display_line PARAMS((void));
|
|||
/* input.c */
|
||||
extern int _rl_any_typein PARAMS((void));
|
||||
extern int _rl_input_available PARAMS((void));
|
||||
extern int _rl_input_queued PARAMS((int));
|
||||
extern void _rl_insert_typein PARAMS((int));
|
||||
extern int _rl_unget_char PARAMS((int));
|
||||
|
||||
/* macro.c */
|
||||
extern void _rl_with_macro_input PARAMS((char *));
|
||||
|
|
@ -142,6 +140,12 @@ extern void _rl_pop_executing_macro PARAMS((void));
|
|||
extern void _rl_add_macro_char PARAMS((int));
|
||||
extern void _rl_kill_kbd_macro PARAMS((void));
|
||||
|
||||
/* misc.c */
|
||||
extern int _rl_init_argument PARAMS((void));
|
||||
extern void _rl_start_using_history PARAMS((void));
|
||||
extern int _rl_free_saved_history_line PARAMS((void));
|
||||
extern void _rl_set_insert_mode PARAMS((int, int));
|
||||
|
||||
/* nls.c */
|
||||
extern int _rl_init_eightbit PARAMS((void));
|
||||
|
||||
|
|
@ -152,12 +156,7 @@ extern void _rl_enable_paren_matching PARAMS((int));
|
|||
extern void _rl_init_line_state PARAMS((void));
|
||||
extern void _rl_set_the_line PARAMS((void));
|
||||
extern int _rl_dispatch PARAMS((int, Keymap));
|
||||
extern int _rl_init_argument PARAMS((void));
|
||||
extern void _rl_fix_point PARAMS((int));
|
||||
extern void _rl_replace_text PARAMS((const char *, int, int));
|
||||
extern int _rl_char_search_internal PARAMS((int, int, int));
|
||||
extern int _rl_set_mark_at_pos PARAMS((int));
|
||||
extern int _rl_free_saved_history_line PARAMS((void));
|
||||
extern int _rl_dispatch_subseq PARAMS((int, Keymap, int));
|
||||
|
||||
/* rltty.c */
|
||||
extern int _rl_disable_tty_signals PARAMS((void));
|
||||
|
|
@ -175,9 +174,23 @@ extern void _rl_output_some_chars PARAMS((const char *, int));
|
|||
extern int _rl_backspace PARAMS((int));
|
||||
extern void _rl_enable_meta_key PARAMS((void));
|
||||
extern void _rl_control_keypad PARAMS((int));
|
||||
extern void _rl_set_cursor PARAMS((int, int));
|
||||
|
||||
/* text.c */
|
||||
extern void _rl_fix_point PARAMS((int));
|
||||
extern int _rl_replace_text PARAMS((const char *, int, int));
|
||||
extern int _rl_insert_char PARAMS((int, int));
|
||||
extern int _rl_overwrite_char PARAMS((int, int));
|
||||
extern int _rl_overwrite_rubout PARAMS((int, int));
|
||||
extern int _rl_rubout_char PARAMS((int, int));
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
extern int _rl_char_search_internal PARAMS((int, int, char *, int));
|
||||
#else
|
||||
extern int _rl_char_search_internal PARAMS((int, int, int));
|
||||
#endif
|
||||
extern int _rl_set_mark_at_pos PARAMS((int));
|
||||
|
||||
/* util.c */
|
||||
extern int rl_alphabetic PARAMS((int));
|
||||
extern int _rl_abort_internal PARAMS((void));
|
||||
extern char *_rl_strindex PARAMS((const char *, const char *));
|
||||
extern int _rl_qsort_string_compare PARAMS((char **, char **));
|
||||
|
|
@ -207,9 +220,11 @@ extern const char *_rl_possible_meta_prefixes[];
|
|||
/* complete.c */
|
||||
extern int _rl_complete_show_all;
|
||||
extern int _rl_complete_mark_directories;
|
||||
extern int _rl_complete_mark_symlink_dirs;
|
||||
extern int _rl_print_completions_horizontally;
|
||||
extern int _rl_completion_case_fold;
|
||||
extern int _rl_match_hidden_files;
|
||||
extern int _rl_page_completions;
|
||||
|
||||
/* display.c */
|
||||
extern int _rl_vis_botlin;
|
||||
|
|
@ -221,9 +236,12 @@ extern char *rl_display_prompt;
|
|||
extern char *_rl_isearch_terminators;
|
||||
|
||||
/* macro.c */
|
||||
extern int _rl_defining_kbd_macro;
|
||||
extern char *_rl_executing_macro;
|
||||
|
||||
/* misc.c */
|
||||
extern int _rl_history_preserve_point;
|
||||
extern int _rl_history_saved_point;
|
||||
|
||||
/* readline.c */
|
||||
extern int _rl_horizontal_scroll_mode;
|
||||
extern int _rl_mark_modified_lines;
|
||||
|
|
@ -231,7 +249,6 @@ extern int _rl_bell_preference;
|
|||
extern int _rl_meta_flag;
|
||||
extern int _rl_convert_meta_chars_to_ascii;
|
||||
extern int _rl_output_meta_chars;
|
||||
extern int _rl_history_preserve_point;
|
||||
extern char *_rl_comment_begin;
|
||||
extern unsigned char _rl_parsing_conditionalized_out;
|
||||
extern Keymap _rl_keymap;
|
||||
|
|
|
|||
|
|
@ -647,7 +647,6 @@ rl_prep_terminal (meta_flag)
|
|||
if (get_tty_settings (tty, &tio) < 0)
|
||||
{
|
||||
release_sigint ();
|
||||
fprintf(stderr, "readline: warning: rl_prep_terminal: cannot get terminal settings");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@
|
|||
#endif
|
||||
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
#include "readline.h"
|
||||
#include "history.h"
|
||||
|
||||
|
|
@ -80,15 +82,8 @@ static void
|
|||
make_history_line_current (entry)
|
||||
HIST_ENTRY *entry;
|
||||
{
|
||||
int line_len;
|
||||
|
||||
line_len = strlen (entry->line);
|
||||
if (line_len >= rl_line_buffer_len)
|
||||
rl_extend_line_buffer (line_len);
|
||||
strcpy (rl_line_buffer, entry->line);
|
||||
|
||||
rl_replace_line (entry->line, 0);
|
||||
rl_undo_list = (UNDO_LIST *)entry->data;
|
||||
rl_end = line_len;
|
||||
|
||||
if (_rl_saved_line_for_history)
|
||||
_rl_free_history_entry (_rl_saved_line_for_history);
|
||||
|
|
@ -169,6 +164,8 @@ noninc_dosearch (string, dir)
|
|||
make_history_line_current (entry);
|
||||
|
||||
rl_point = 0;
|
||||
rl_mark = rl_end;
|
||||
|
||||
rl_clear_message ();
|
||||
}
|
||||
|
||||
|
|
@ -182,11 +179,15 @@ noninc_search (dir, pchar)
|
|||
int dir;
|
||||
int pchar;
|
||||
{
|
||||
int saved_point, c;
|
||||
int saved_point, saved_mark, c;
|
||||
char *p;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
char mb[MB_LEN_MAX];
|
||||
#endif
|
||||
|
||||
rl_maybe_save_line ();
|
||||
saved_point = rl_point;
|
||||
saved_mark = rl_mark;
|
||||
|
||||
/* Use the line buffer to read the search string. */
|
||||
rl_line_buffer[0] = 0;
|
||||
|
|
@ -206,6 +207,11 @@ noninc_search (dir, pchar)
|
|||
c = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
c = _rl_read_mbstring (c, mb, MB_LEN_MAX);
|
||||
#endif
|
||||
|
||||
if (c == 0)
|
||||
break;
|
||||
|
||||
|
|
@ -218,9 +224,10 @@ noninc_search (dir, pchar)
|
|||
rl_maybe_unsave_line ();
|
||||
rl_clear_message ();
|
||||
rl_point = saved_point;
|
||||
rl_mark = saved_mark;
|
||||
SEARCH_RETURN;
|
||||
}
|
||||
rl_rubout (1, c);
|
||||
_rl_rubout_char (1, c);
|
||||
break;
|
||||
|
||||
case CTRL('W'):
|
||||
|
|
@ -242,17 +249,25 @@ noninc_search (dir, pchar)
|
|||
rl_maybe_unsave_line ();
|
||||
rl_clear_message ();
|
||||
rl_point = saved_point;
|
||||
rl_mark = saved_mark;
|
||||
rl_ding ();
|
||||
SEARCH_RETURN;
|
||||
|
||||
default:
|
||||
rl_insert (1, c);
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
rl_insert_text (mb);
|
||||
else
|
||||
#endif
|
||||
_rl_insert_char (1, c);
|
||||
break;
|
||||
}
|
||||
(*rl_redisplay_function) ();
|
||||
}
|
||||
|
||||
dosearch:
|
||||
rl_mark = saved_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. */
|
||||
|
|
@ -373,9 +388,11 @@ rl_history_search_internal (count, dir)
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
|
@ -384,6 +401,8 @@ rl_history_search_internal (count, dir)
|
|||
make_history_line_current (temp);
|
||||
|
||||
rl_point = rl_history_search_len;
|
||||
rl_mark = rl_end;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt
|
|||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *));
|
||||
static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *));
|
||||
|
||||
/* Exported variables for use by applications. */
|
||||
|
||||
|
|
@ -232,7 +233,7 @@ rl_set_sighandler (sig, handler, ohandler)
|
|||
struct sigaction act;
|
||||
|
||||
act.sa_handler = handler;
|
||||
act.sa_flags = 0;
|
||||
act.sa_flags = 0; /* XXX - should we set SA_RESTART for SIGWINCH? */
|
||||
sigemptyset (&act.sa_mask);
|
||||
sigemptyset (&ohandler->sa_mask);
|
||||
sigaction (sig, &act, &old_handler);
|
||||
|
|
|
|||
|
|
@ -66,6 +66,9 @@
|
|||
#include "rlshell.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay)
|
||||
#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc)
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Terminal and Termcap */
|
||||
|
|
@ -140,6 +143,16 @@ static char *_rl_term_ke;
|
|||
/* The key sequences sent by the Home and End keys, if any. */
|
||||
static char *_rl_term_kh;
|
||||
static char *_rl_term_kH;
|
||||
static char *_rl_term_at7; /* @7 */
|
||||
|
||||
/* Insert key */
|
||||
static char *_rl_term_kI;
|
||||
|
||||
/* Cursor control */
|
||||
static char *_rl_term_vs; /* very visible */
|
||||
static char *_rl_term_ve; /* normal */
|
||||
|
||||
static void bind_termcap_arrow_keys PARAMS((Keymap));
|
||||
|
||||
/* Variables that hold the screen dimensions, used by the display code. */
|
||||
int _rl_screenwidth, _rl_screenheight, _rl_screenchars;
|
||||
|
|
@ -274,7 +287,10 @@ rl_resize_terminal ()
|
|||
if (readline_echoing_p)
|
||||
{
|
||||
_rl_get_screen_size (fileno (rl_instream), 1);
|
||||
_rl_redisplay_after_sigwinch ();
|
||||
if (CUSTOM_REDISPLAY_FUNC ())
|
||||
rl_forced_update_display ();
|
||||
else
|
||||
_rl_redisplay_after_sigwinch ();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -287,6 +303,7 @@ struct _tc_string {
|
|||
search algorithm to something smarter. */
|
||||
static struct _tc_string tc_strings[] =
|
||||
{
|
||||
{ "@7", &_rl_term_at7 },
|
||||
{ "DC", &_rl_term_DC },
|
||||
{ "IC", &_rl_term_IC },
|
||||
{ "ce", &_rl_term_clreol },
|
||||
|
|
@ -296,14 +313,15 @@ static struct _tc_string tc_strings[] =
|
|||
{ "ei", &_rl_term_ei },
|
||||
{ "ic", &_rl_term_ic },
|
||||
{ "im", &_rl_term_im },
|
||||
{ "kH", &_rl_term_kH }, /* home down ?? */
|
||||
{ "kI", &_rl_term_kI }, /* insert */
|
||||
{ "kd", &_rl_term_kd },
|
||||
{ "ke", &_rl_term_ke }, /* end keypad mode */
|
||||
{ "kh", &_rl_term_kh }, /* home */
|
||||
{ "kH", &_rl_term_kH }, /* end */
|
||||
{ "kl", &_rl_term_kl },
|
||||
{ "kr", &_rl_term_kr },
|
||||
{ "ks", &_rl_term_ks }, /* start keypad mode */
|
||||
{ "ku", &_rl_term_ku },
|
||||
{ "ks", &_rl_term_ks },
|
||||
{ "ke", &_rl_term_ke },
|
||||
{ "le", &_rl_term_backspace },
|
||||
{ "mm", &_rl_term_mm },
|
||||
{ "mo", &_rl_term_mo },
|
||||
|
|
@ -313,6 +331,8 @@ static struct _tc_string tc_strings[] =
|
|||
{ "pc", &_rl_term_pc },
|
||||
{ "up", &_rl_term_up },
|
||||
{ "vb", &_rl_visible_bell },
|
||||
{ "vs", &_rl_term_vs },
|
||||
{ "ve", &_rl_term_ve },
|
||||
};
|
||||
|
||||
#define NUM_TC_STRINGS (sizeof (tc_strings) / sizeof (struct _tc_string))
|
||||
|
|
@ -336,9 +356,6 @@ get_term_capabilities (bp)
|
|||
tcap_initialized = 1;
|
||||
}
|
||||
|
||||
#define CUSTOM_REDISPLAY_FUNC() (rl_redisplay_function != rl_redisplay)
|
||||
#define CUSTOM_INPUT_FUNC() (rl_getc_function != rl_getc)
|
||||
|
||||
int
|
||||
_rl_init_terminal_io (terminal_name)
|
||||
const char *terminal_name;
|
||||
|
|
@ -346,7 +363,6 @@ _rl_init_terminal_io (terminal_name)
|
|||
const char *term;
|
||||
char *buffer;
|
||||
int tty, tgetent_ret;
|
||||
Keymap xkeymap;
|
||||
|
||||
term = terminal_name ? terminal_name : sh_get_env_value ("TERM");
|
||||
_rl_term_clrpag = _rl_term_cr = _rl_term_clreol = (char *)NULL;
|
||||
|
|
@ -404,7 +420,10 @@ _rl_init_terminal_io (terminal_name)
|
|||
_rl_term_im = _rl_term_ei = _rl_term_ic = _rl_term_IC = (char *)NULL;
|
||||
_rl_term_up = _rl_term_dc = _rl_term_DC = _rl_visible_bell = (char *)NULL;
|
||||
_rl_term_ku = _rl_term_kd = _rl_term_kl = _rl_term_kr = (char *)NULL;
|
||||
_rl_term_kh = _rl_term_kH = _rl_term_kI = (char *)NULL;
|
||||
_rl_term_ks = _rl_term_ke = _rl_term_at7 = (char *)NULL;
|
||||
_rl_term_mm = _rl_term_mo = (char *)NULL;
|
||||
_rl_term_ve = _rl_term_vs = (char *)NULL;
|
||||
#if defined (HACK_TERMCAP_MOTION)
|
||||
term_forward_char = (char *)NULL;
|
||||
#endif
|
||||
|
|
@ -449,31 +468,36 @@ _rl_init_terminal_io (terminal_name)
|
|||
|
||||
/* Attempt to find and bind the arrow keys. Do not override already
|
||||
bound keys in an overzealous attempt, however. */
|
||||
xkeymap = _rl_keymap;
|
||||
|
||||
_rl_keymap = emacs_standard_keymap;
|
||||
_rl_bind_if_unbound (_rl_term_ku, rl_get_previous_history);
|
||||
_rl_bind_if_unbound (_rl_term_kd, rl_get_next_history);
|
||||
_rl_bind_if_unbound (_rl_term_kr, rl_forward);
|
||||
_rl_bind_if_unbound (_rl_term_kl, rl_backward);
|
||||
|
||||
_rl_bind_if_unbound (_rl_term_kh, rl_beg_of_line); /* Home */
|
||||
_rl_bind_if_unbound (_rl_term_kH, rl_end_of_line); /* End */
|
||||
bind_termcap_arrow_keys (emacs_standard_keymap);
|
||||
|
||||
#if defined (VI_MODE)
|
||||
_rl_keymap = vi_movement_keymap;
|
||||
bind_termcap_arrow_keys (vi_movement_keymap);
|
||||
bind_termcap_arrow_keys (vi_insertion_keymap);
|
||||
#endif /* VI_MODE */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Bind the arrow key sequences from the termcap description in MAP. */
|
||||
static void
|
||||
bind_termcap_arrow_keys (map)
|
||||
Keymap map;
|
||||
{
|
||||
Keymap xkeymap;
|
||||
|
||||
xkeymap = _rl_keymap;
|
||||
_rl_keymap = map;
|
||||
|
||||
_rl_bind_if_unbound (_rl_term_ku, rl_get_previous_history);
|
||||
_rl_bind_if_unbound (_rl_term_kd, rl_get_next_history);
|
||||
_rl_bind_if_unbound (_rl_term_kr, rl_forward);
|
||||
_rl_bind_if_unbound (_rl_term_kl, rl_backward);
|
||||
|
||||
_rl_bind_if_unbound (_rl_term_kh, rl_beg_of_line); /* Home */
|
||||
_rl_bind_if_unbound (_rl_term_kH, rl_end_of_line); /* End */
|
||||
#endif /* VI_MODE */
|
||||
_rl_bind_if_unbound (_rl_term_at7, rl_end_of_line); /* End */
|
||||
|
||||
_rl_keymap = xkeymap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
|
|
@ -610,3 +634,29 @@ _rl_control_keypad (on)
|
|||
tputs (_rl_term_ke, 1, _rl_output_character_function);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Controlling the Cursor */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Set the cursor appropriately depending on IM, which is one of the
|
||||
insert modes (insert or overwrite). Insert mode gets the normal
|
||||
cursor. Overwrite mode gets a very visible cursor. Only does
|
||||
anything if we have both capabilities. */
|
||||
void
|
||||
_rl_set_cursor (im, force)
|
||||
int im, force;
|
||||
{
|
||||
if (_rl_term_ve && _rl_term_vs)
|
||||
{
|
||||
if (force || im != rl_insert_mode)
|
||||
{
|
||||
if (im == RL_IM_OVERWRITE)
|
||||
tputs (_rl_term_vs, 1, _rl_output_character_function);
|
||||
else
|
||||
tputs (_rl_term_ve, 1, _rl_output_character_function);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
1540
lib/readline/text.c
Normal file
1540
lib/readline/text.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -59,9 +59,6 @@ extern struct passwd *getpwnam PARAMS((const char *));
|
|||
#endif /* !HAVE_GETPW_DECLS */
|
||||
|
||||
#if !defined (savestring)
|
||||
# ifndef strcpy
|
||||
extern char *strcpy ();
|
||||
# endif
|
||||
#define savestring(x) strcpy ((char *)xmalloc (1 + strlen (x)), (x))
|
||||
#endif /* !savestring */
|
||||
|
||||
|
|
|
|||
|
|
@ -24,10 +24,6 @@
|
|||
#if !defined (_TILDE_H_)
|
||||
# define _TILDE_H_
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -50,8 +50,6 @@
|
|||
#include "rlprivate.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0)
|
||||
|
||||
/* Non-zero tells rl_delete_text and rl_insert_text to not add to
|
||||
the undo list. */
|
||||
int _rl_doing_an_undo = 0;
|
||||
|
|
|
|||
|
|
@ -55,8 +55,6 @@
|
|||
#include "rlprivate.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
#define SWAP(s, e) do { int t; t = s; s = e; e = t; } while (0)
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Utility Functions */
|
||||
|
|
@ -89,7 +87,7 @@ _rl_abort_internal ()
|
|||
_rl_init_argument ();
|
||||
rl_clear_pending_input ();
|
||||
|
||||
_rl_defining_kbd_macro = 0;
|
||||
RL_UNSETSTATE (RL_STATE_MACRODEF);
|
||||
while (rl_executing_macro)
|
||||
_rl_pop_executing_macro ();
|
||||
|
||||
|
|
@ -233,6 +231,12 @@ _rl_strpbrk (string1, string2)
|
|||
const char *string1, *string2;
|
||||
{
|
||||
register const char *scan;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
mbstate_t ps;
|
||||
register int i, v;
|
||||
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
#endif
|
||||
|
||||
for (; *string1; string1++)
|
||||
{
|
||||
|
|
@ -241,6 +245,14 @@ _rl_strpbrk (string1, string2)
|
|||
if (*string1 == *scan)
|
||||
return ((char *)string1);
|
||||
}
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
v = _rl_get_char_len (string1, &ps);
|
||||
if (v > 1)
|
||||
string += v - 1; /* -1 to account for auto-increment in loop */
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = {
|
|||
{ ISFUNC, rl_emacs_editing_mode }, /* Control-e */
|
||||
{ ISFUNC, (rl_command_func_t *)0x0 }, /* Control-f */
|
||||
{ ISFUNC, rl_abort }, /* Control-g */
|
||||
{ ISFUNC, rl_backward }, /* Control-h */
|
||||
{ ISFUNC, rl_backward_char }, /* Control-h */
|
||||
{ ISFUNC, (rl_command_func_t *)0x0 }, /* Control-i */
|
||||
{ ISFUNC, rl_newline }, /* Control-j */
|
||||
{ ISFUNC, rl_kill_line }, /* Control-k */
|
||||
|
|
@ -68,7 +68,7 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = {
|
|||
{ ISFUNC, rl_vi_undo }, /* Control-_ */
|
||||
|
||||
/* The start of printing characters. */
|
||||
{ ISFUNC, rl_forward }, /* SPACE */
|
||||
{ ISFUNC, rl_forward_char }, /* SPACE */
|
||||
{ ISFUNC, (rl_command_func_t *)0x0 }, /* ! */
|
||||
{ ISFUNC, (rl_command_func_t *)0x0 }, /* " */
|
||||
{ ISFUNC, rl_insert_comment }, /* # */
|
||||
|
|
@ -150,11 +150,11 @@ KEYMAP_ENTRY_ARRAY vi_movement_keymap = {
|
|||
{ ISFUNC, rl_vi_end_word }, /* e */
|
||||
{ ISFUNC, rl_vi_char_search }, /* f */
|
||||
{ ISFUNC, (rl_command_func_t *)0x0 }, /* g */
|
||||
{ ISFUNC, rl_backward }, /* h */
|
||||
{ ISFUNC, rl_backward_char }, /* h */
|
||||
{ ISFUNC, rl_vi_insertion_mode }, /* i */
|
||||
{ ISFUNC, rl_get_next_history }, /* j */
|
||||
{ ISFUNC, rl_get_previous_history }, /* k */
|
||||
{ ISFUNC, rl_forward }, /* l */
|
||||
{ ISFUNC, rl_forward_char }, /* l */
|
||||
{ ISFUNC, rl_vi_set_mark }, /* m */
|
||||
{ ISFUNC, rl_vi_search_again }, /* n */
|
||||
{ ISFUNC, (rl_command_func_t *)0x0 }, /* o */
|
||||
|
|
|
|||
|
|
@ -51,6 +51,8 @@
|
|||
|
||||
/* Some standard library routines. */
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
#include "readline.h"
|
||||
#include "history.h"
|
||||
|
||||
|
|
@ -61,10 +63,6 @@
|
|||
#define member(c, s) ((c) ? (char *)strchr ((s), (c)) != (char *)NULL : 0)
|
||||
#endif
|
||||
|
||||
#ifndef exchange
|
||||
#define exchange(x, y) do {int temp = x; x = y; y = temp;} while (0)
|
||||
#endif
|
||||
|
||||
/* Non-zero means enter insertion mode. */
|
||||
static int _rl_vi_doing_insert;
|
||||
|
||||
|
|
@ -89,7 +87,11 @@ static int _rl_vi_last_command = 'i'; /* default `.' puts you in insert mode */
|
|||
static int _rl_vi_last_repeat = 1;
|
||||
static int _rl_vi_last_arg_sign = 1;
|
||||
static int _rl_vi_last_motion;
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
static char _rl_vi_last_search_mbchar[MB_LEN_MAX];
|
||||
#else
|
||||
static int _rl_vi_last_search_char;
|
||||
#endif
|
||||
static int _rl_vi_last_replacement;
|
||||
|
||||
static int _rl_vi_last_key_before_insert;
|
||||
|
|
@ -158,12 +160,15 @@ int
|
|||
rl_vi_redo (count, c)
|
||||
int count, c;
|
||||
{
|
||||
int r;
|
||||
|
||||
if (!rl_explicit_arg)
|
||||
{
|
||||
rl_numeric_arg = _rl_vi_last_repeat;
|
||||
rl_arg_sign = _rl_vi_last_arg_sign;
|
||||
}
|
||||
|
||||
r = 0;
|
||||
vi_redoing = 1;
|
||||
/* If we're redoing an insert with `i', stuff in the inserted text
|
||||
and do not go into insertion mode. */
|
||||
|
|
@ -175,10 +180,10 @@ rl_vi_redo (count, c)
|
|||
rl_point--;
|
||||
}
|
||||
else
|
||||
_rl_dispatch (_rl_vi_last_command, _rl_keymap);
|
||||
r = _rl_dispatch (_rl_vi_last_command, _rl_keymap);
|
||||
vi_redoing = 0;
|
||||
|
||||
return (0);
|
||||
return (r);
|
||||
}
|
||||
|
||||
/* A placeholder for further expansion. */
|
||||
|
|
@ -547,7 +552,17 @@ rl_vi_append_mode (count, key)
|
|||
int count, key;
|
||||
{
|
||||
if (rl_point < rl_end)
|
||||
rl_point++;
|
||||
{
|
||||
if (MB_CUR_MAX == 1 || rl_byte_oriented)
|
||||
rl_point++;
|
||||
else
|
||||
{
|
||||
int point = rl_point;
|
||||
rl_forward_char (1, key);
|
||||
if (point == rl_point)
|
||||
rl_point = rl_end;
|
||||
}
|
||||
}
|
||||
rl_vi_insertion_mode (1, key);
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -612,6 +627,7 @@ _rl_vi_done_inserting ()
|
|||
{
|
||||
if (_rl_vi_doing_insert)
|
||||
{
|
||||
/* The `C', `s', and `S' commands set this. */
|
||||
rl_end_undo_group ();
|
||||
/* Now, the text between rl_undo_list->next->start and
|
||||
rl_undo_list->next->end is what was inserted while in insert
|
||||
|
|
@ -640,7 +656,7 @@ rl_vi_movement_mode (count, key)
|
|||
int count, key;
|
||||
{
|
||||
if (rl_point > 0)
|
||||
rl_backward (1, key);
|
||||
rl_backward_char (1, key);
|
||||
|
||||
_rl_keymap = vi_movement_keymap;
|
||||
_rl_vi_done_inserting ();
|
||||
|
|
@ -657,6 +673,51 @@ rl_vi_arg_digit (count, c)
|
|||
return (rl_digit_argument (count, c));
|
||||
}
|
||||
|
||||
/* Change the case of the next COUNT characters. */
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
static int
|
||||
_rl_vi_change_mbchar_case (count)
|
||||
int count;
|
||||
{
|
||||
wchar_t wc;
|
||||
char mb[MB_LEN_MAX];
|
||||
mbstate_t ps;
|
||||
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
if (_rl_adjust_point (rl_line_buffer, rl_point, &ps) > 0)
|
||||
count--;
|
||||
while (count-- && rl_point < rl_end)
|
||||
{
|
||||
mbrtowc (&wc, rl_line_buffer + rl_point, rl_end - rl_point, &ps);
|
||||
if (iswupper (wc))
|
||||
wc = towlower (wc);
|
||||
else if (iswlower (wc))
|
||||
wc = towupper (wc);
|
||||
else
|
||||
{
|
||||
/* Just skip over chars neither upper nor lower case */
|
||||
rl_forward_char (1, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Vi is kind of strange here. */
|
||||
if (wc)
|
||||
{
|
||||
wctomb (mb, wc);
|
||||
rl_begin_undo_group ();
|
||||
rl_delete (1, 0);
|
||||
rl_insert_text (mb);
|
||||
rl_end_undo_group ();
|
||||
rl_vi_check ();
|
||||
}
|
||||
else
|
||||
rl_forward_char (1, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
rl_vi_change_case (count, ignore)
|
||||
int count, ignore;
|
||||
|
|
@ -667,6 +728,11 @@ rl_vi_change_case (count, ignore)
|
|||
if (rl_point >= rl_end)
|
||||
return (0);
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
return (_rl_vi_change_mbchar_case (count));
|
||||
#endif
|
||||
|
||||
while (count-- && rl_point < rl_end)
|
||||
{
|
||||
if (_rl_uppercase_p (rl_line_buffer[rl_point]))
|
||||
|
|
@ -676,7 +742,7 @@ rl_vi_change_case (count, ignore)
|
|||
else
|
||||
{
|
||||
/* Just skip over characters neither upper nor lower case. */
|
||||
rl_forward (1, c);
|
||||
rl_forward_char (1, c);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -685,12 +751,12 @@ rl_vi_change_case (count, ignore)
|
|||
{
|
||||
rl_begin_undo_group ();
|
||||
rl_delete (1, c);
|
||||
rl_insert (1, c);
|
||||
_rl_insert_char (1, c);
|
||||
rl_end_undo_group ();
|
||||
rl_vi_check ();
|
||||
}
|
||||
else
|
||||
rl_forward (1, c);
|
||||
rl_forward_char (1, c);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -700,10 +766,10 @@ rl_vi_put (count, key)
|
|||
int count, key;
|
||||
{
|
||||
if (!_rl_uppercase_p (key) && (rl_point + 1 <= rl_end))
|
||||
rl_point++;
|
||||
rl_point = _rl_find_next_mbchar (rl_line_buffer, rl_point, 1, MB_FIND_NONZERO);
|
||||
|
||||
rl_yank (1, key);
|
||||
rl_backward (1, key);
|
||||
rl_backward_char (1, key);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -711,7 +777,12 @@ int
|
|||
rl_vi_check ()
|
||||
{
|
||||
if (rl_point && rl_point == rl_end)
|
||||
rl_point--;
|
||||
{
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
rl_point = _rl_find_prev_mbchar (rl_line_buffer, rl_point, MB_FIND_NONZERO);
|
||||
else
|
||||
rl_point--;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -813,7 +884,7 @@ rl_vi_domove (key, nextkey)
|
|||
}
|
||||
|
||||
if (rl_mark < rl_point)
|
||||
exchange (rl_point, rl_mark);
|
||||
SWAP (rl_point, rl_mark);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
|
@ -991,7 +1062,10 @@ rl_vi_delete (count, key)
|
|||
return -1;
|
||||
}
|
||||
|
||||
end = rl_point + count;
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
end = _rl_find_next_mbchar (rl_line_buffer, rl_point, count, MB_FIND_NONZERO);
|
||||
else
|
||||
end = rl_point + count;
|
||||
|
||||
if (end >= rl_end)
|
||||
end = rl_end;
|
||||
|
|
@ -999,7 +1073,7 @@ rl_vi_delete (count, key)
|
|||
rl_kill_text (rl_point, end);
|
||||
|
||||
if (rl_point > 0 && rl_point == rl_end)
|
||||
rl_backward (1, key);
|
||||
rl_backward_char (1, key);
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -1024,7 +1098,12 @@ int
|
|||
rl_vi_char_search (count, key)
|
||||
int count, key;
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
static char *target;
|
||||
static int mb_len;
|
||||
#else
|
||||
static char target;
|
||||
#endif
|
||||
static int orig_dir, dir;
|
||||
|
||||
if (key == ';' || key == ',')
|
||||
|
|
@ -1032,12 +1111,21 @@ rl_vi_char_search (count, key)
|
|||
else
|
||||
{
|
||||
if (vi_redoing)
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
target = _rl_vi_last_search_mbchar;
|
||||
#else
|
||||
target = _rl_vi_last_search_char;
|
||||
#endif
|
||||
else
|
||||
{
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
mb_len = _rl_read_mbchar (_rl_vi_last_search_mbchar, MB_LEN_MAX);
|
||||
target = _rl_vi_last_search_mbchar;
|
||||
#else
|
||||
RL_SETSTATE(RL_STATE_MOREINPUT);
|
||||
_rl_vi_last_search_char = target = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
switch (key)
|
||||
|
|
@ -1060,7 +1148,11 @@ rl_vi_char_search (count, key)
|
|||
}
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
return (_rl_char_search_internal (count, dir, target, mb_len));
|
||||
#else
|
||||
return (_rl_char_search_internal (count, dir, target));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Match brackets */
|
||||
|
|
@ -1068,14 +1160,25 @@ int
|
|||
rl_vi_match (ignore, key)
|
||||
int ignore, key;
|
||||
{
|
||||
int count = 1, brack, pos;
|
||||
int count = 1, brack, pos, tmp, pre;
|
||||
|
||||
pos = rl_point;
|
||||
if ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
|
||||
{
|
||||
while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
|
||||
rl_point < rl_end - 1)
|
||||
rl_forward (1, key);
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
{
|
||||
while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0)
|
||||
{
|
||||
pre = rl_point;
|
||||
rl_forward_char (1, key);
|
||||
if (pre == rl_point)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
while ((brack = rl_vi_bracktype (rl_line_buffer[rl_point])) == 0 &&
|
||||
rl_point < rl_end - 1)
|
||||
rl_forward_char (1, key);
|
||||
|
||||
if (brack <= 0)
|
||||
{
|
||||
|
|
@ -1091,7 +1194,16 @@ rl_vi_match (ignore, key)
|
|||
{
|
||||
while (count)
|
||||
{
|
||||
if (--pos >= 0)
|
||||
tmp = pos;
|
||||
if (MB_CUR_MAX == 1 || rl_byte_oriented)
|
||||
pos--;
|
||||
else
|
||||
{
|
||||
pos = _rl_find_prev_mbchar (rl_line_buffer, pos, MB_FIND_ANY);
|
||||
if (tmp == pos)
|
||||
pos--;
|
||||
}
|
||||
if (pos >= 0)
|
||||
{
|
||||
int b = rl_vi_bracktype (rl_line_buffer[pos]);
|
||||
if (b == -brack)
|
||||
|
|
@ -1110,7 +1222,12 @@ rl_vi_match (ignore, key)
|
|||
{ /* brack > 0 */
|
||||
while (count)
|
||||
{
|
||||
if (++pos < rl_end)
|
||||
if (MB_CUR_MAX == 1 || rl_byte_oriented)
|
||||
pos++;
|
||||
else
|
||||
pos = _rl_find_next_mbchar (rl_line_buffer, pos, 1, MB_FIND_ANY);
|
||||
|
||||
if (pos < rl_end)
|
||||
{
|
||||
int b = rl_vi_bracktype (rl_line_buffer[pos]);
|
||||
if (b == -brack)
|
||||
|
|
@ -1145,6 +1262,11 @@ rl_vi_bracktype (c)
|
|||
}
|
||||
}
|
||||
|
||||
/* XXX - think about reading an entire mbchar with _rl_read_mbchar and
|
||||
inserting it in one bunch instead of the loop below (like in
|
||||
rl_vi_char_search or _rl_vi_change_mbchar_case. Set c to mbchar[0]
|
||||
for test against 033 or ^C. Make sure that _rl_read_mbchar does
|
||||
this right. */
|
||||
int
|
||||
rl_vi_change_char (count, key)
|
||||
int count, key;
|
||||
|
|
@ -1168,9 +1290,19 @@ rl_vi_change_char (count, key)
|
|||
rl_begin_undo_group ();
|
||||
|
||||
rl_delete (1, c);
|
||||
rl_insert (1, c);
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (MB_CUR_MAX > 1 && rl_byte_oriented == 0)
|
||||
while (_rl_insert_char (1, c))
|
||||
{
|
||||
RL_SETSTATE (RL_STATE_MOREINPUT);
|
||||
c = rl_read_key ();
|
||||
RL_UNSETSTATE (RL_STATE_MOREINPUT);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
_rl_insert_char (1, c);
|
||||
if (count == 0)
|
||||
rl_backward (1, c);
|
||||
rl_backward_char (1, c);
|
||||
|
||||
rl_end_undo_group ();
|
||||
}
|
||||
|
|
@ -1181,66 +1313,29 @@ int
|
|||
rl_vi_subst (count, key)
|
||||
int count, key;
|
||||
{
|
||||
rl_begin_undo_group ();
|
||||
/* If we are redoing, rl_vi_change_to will stuff the last motion char */
|
||||
if (vi_redoing == 0)
|
||||
rl_stuff_char ((key == 'S') ? 'c' : ' '); /* `S' == `cc', `s' == `c ' */
|
||||
|
||||
if (_rl_uppercase_p (key))
|
||||
{
|
||||
rl_beg_of_line (1, key);
|
||||
rl_kill_line (1, key);
|
||||
}
|
||||
else
|
||||
rl_delete_text (rl_point, rl_point+count);
|
||||
|
||||
rl_end_undo_group ();
|
||||
|
||||
_rl_vi_set_last (key, count, rl_arg_sign);
|
||||
|
||||
if (vi_redoing)
|
||||
{
|
||||
int o = _rl_doing_an_undo;
|
||||
|
||||
_rl_doing_an_undo = 1;
|
||||
if (vi_insert_buffer && *vi_insert_buffer)
|
||||
rl_insert_text (vi_insert_buffer);
|
||||
_rl_doing_an_undo = o;
|
||||
}
|
||||
else
|
||||
{
|
||||
rl_begin_undo_group ();
|
||||
_rl_vi_doing_insert = 1;
|
||||
rl_vi_insertion_mode (1, key);
|
||||
}
|
||||
|
||||
return (0);
|
||||
return (rl_vi_change_to (count, 'c'));
|
||||
}
|
||||
|
||||
int
|
||||
rl_vi_overstrike (count, key)
|
||||
int count, key;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (_rl_vi_doing_insert == 0)
|
||||
{
|
||||
_rl_vi_doing_insert = 1;
|
||||
rl_begin_undo_group ();
|
||||
}
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
if (count > 0)
|
||||
{
|
||||
vi_replace_count++;
|
||||
rl_begin_undo_group ();
|
||||
|
||||
if (rl_point < rl_end)
|
||||
{
|
||||
rl_delete (1, key);
|
||||
rl_insert (1, key);
|
||||
}
|
||||
else
|
||||
rl_insert (1, key);
|
||||
|
||||
rl_end_undo_group ();
|
||||
_rl_overwrite_char (count, key);
|
||||
vi_replace_count += count;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
|
@ -1263,7 +1358,7 @@ rl_vi_overstrike_delete (count, key)
|
|||
vi_replace_count--;
|
||||
|
||||
if (rl_point == s)
|
||||
rl_backward (1, key);
|
||||
rl_backward_char (1, key);
|
||||
}
|
||||
|
||||
if (vi_replace_count == 0 && _rl_vi_doing_insert)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
# Makefile for the Bash library
|
||||
#
|
||||
#
|
||||
# Copyright (C) 1998 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1998-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
|
||||
|
|
@ -68,10 +68,12 @@ LIBRARY_NAME = libsh.a
|
|||
CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \
|
||||
strcasecmp.c strerror.c strtod.c strtol.c strtoul.c \
|
||||
vprint.c itos.c rename.c zread.c zwrite.c shtty.c \
|
||||
inet_aton.c netopen.c strpbrk.c timeval.c makepath.c pathcanon.c \
|
||||
pathphys.c tmpfile.c stringlist.c stringvec.c spell.c \
|
||||
shquote.c strtrans.c strindex.c snprintf.c mailstat.c fmtulong.c \
|
||||
fmtullong.c strtoll.c strtoull.c strtoimax.c strtoumax.c
|
||||
inet_aton.c netconn.c netopen.c strpbrk.c timeval.c makepath.c \
|
||||
pathcanon.c pathphys.c tmpfile.c stringlist.c stringvec.c spell.c \
|
||||
shquote.c strtrans.c strindex.c snprintf.c mailstat.c \
|
||||
fmtulong.c fmtullong.c fmtumax.c \
|
||||
strtoll.c strtoull.c strtoimax.c strtoumax.c memset.c \
|
||||
mktime.c strftime.c xstrchr.c zcatfd.c
|
||||
|
||||
# The header files for this library.
|
||||
HSOURCES =
|
||||
|
|
@ -80,10 +82,10 @@ HSOURCES =
|
|||
LIBOBJS = @LIBOBJS@
|
||||
OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o \
|
||||
itos.o zread.o zwrite.o shtty.o \
|
||||
netopen.o timeval.o makepath.o pathcanon.o \
|
||||
netconn.o netopen.o timeval.o makepath.o pathcanon.o \
|
||||
pathphys.o tmpfile.o stringlist.o stringvec.o spell.o shquote.o \
|
||||
strtrans.o strindex.o snprintf.o mailstat.o fmtulong.o \
|
||||
fmtullong.o ${LIBOBJS}
|
||||
fmtullong.o fmtumax.o xstrchr.o zcatfd.o ${LIBOBJS}
|
||||
|
||||
SUPPORT = Makefile
|
||||
|
||||
|
|
@ -116,12 +118,16 @@ clktck.o: clktck.c
|
|||
clock.o: clock.c
|
||||
fmtullong.o: fmtullong.c
|
||||
fmtulong.o: fmtulong.c
|
||||
fmtumax.o: fmtumax.c
|
||||
getcwd.o: getcwd.c
|
||||
getenv.o: getenv.c
|
||||
inet_aton.o: inet_aton.c
|
||||
itos.o: itos.c
|
||||
mailstat.o: mailstat.c
|
||||
makepath.o: makepath.c
|
||||
memset.o: memset.c
|
||||
mktime.o: mktime.c
|
||||
netconn.o: netconn.c
|
||||
netopen.o: netopen.c
|
||||
oslib.o: oslib.c
|
||||
pathcanon.o: pathcanon.c
|
||||
|
|
@ -134,6 +140,7 @@ snprintf.o: snprintf.c
|
|||
spell.o: spell.c
|
||||
strcasecmp.o: strcasecmp.c
|
||||
strerror.o: strerror.c
|
||||
strftime.o: strftime.c
|
||||
strindex.o: strindex.c
|
||||
stringlist.o: stringlist.c
|
||||
stringvec.o: stringvec.c
|
||||
|
|
@ -150,11 +157,14 @@ times.o: times.c
|
|||
timeval.o: timeval.c
|
||||
tmpfile.o: tmpfile.c
|
||||
vprint.o: vprint.c
|
||||
xstrchr.o: xstrchr.c
|
||||
zcatfd.o: zcatfd.c
|
||||
zread.o: zread.c
|
||||
zwrite.o: zwrite.c
|
||||
|
||||
# dependencies for c files that include other c files
|
||||
fmtullong.o: fmtulong.c
|
||||
fmtumax.o: fmtulong.c
|
||||
strtoll.o: strtol.c
|
||||
strtoul.o: strtol.c
|
||||
strtoull.o: strtol.c
|
||||
|
|
@ -164,12 +174,16 @@ clktck.o: ${BUILD_DIR}/config.h
|
|||
clock.o: ${BUILD_DIR}/config.h
|
||||
fmtullong.o: ${BUILD_DIR}/config.h
|
||||
fmtulong.o: ${BUILD_DIR}/config.h
|
||||
fmtumax.o: ${BUILD_DIR}/config.h
|
||||
getcwd.o: ${BUILD_DIR}/config.h
|
||||
getenv.o: ${BUILD_DIR}/config.h
|
||||
inet_aton.o: ${BUILD_DIR}/config.h
|
||||
itos.o: ${BUILD_DIR}/config.h
|
||||
mailstat.o: ${BUILD_DIR}/config.h
|
||||
makepath.o: ${BUILD_DIR}/config.h
|
||||
memset.o: ${BUILD_DIR}/config.h
|
||||
mktime.o: ${BUILD_DIR}/config.h
|
||||
netconn.o: ${BUILD_DIR}/config.h
|
||||
netopen.o: ${BUILD_DIR}/config.h
|
||||
oslib.o: ${BUILD_DIR}/config.h
|
||||
pathcanon.o: ${BUILD_DIR}/config.h
|
||||
|
|
@ -182,6 +196,7 @@ snprintf.o: ${BUILD_DIR}/config.h
|
|||
spell.o: ${BUILD_DIR}/config.h
|
||||
strcasecmp.o: ${BUILD_DIR}/config.h
|
||||
strerror.o: ${BUILD_DIR}/config.h
|
||||
strftime.o: ${BUILD_DIR}/config.h
|
||||
strindex.o: ${BUILD_DIR}/config.h
|
||||
stringlist.o: ${BUILD_DIR}/config.h
|
||||
stringvec.o: ${BUILD_DIR}/config.h
|
||||
|
|
@ -198,6 +213,8 @@ times.o: ${BUILD_DIR}/config.h
|
|||
timeval.o: ${BUILD_DIR}/config.h
|
||||
tmpfile.o: ${BUILD_DIR}/config.h
|
||||
vprint.o: ${BUILD_DIR}/config.h
|
||||
xstrchr.o: ${BUILD_DIR}/config.h
|
||||
zcatfd.o: ${BUILD_DIR}/config.h
|
||||
zread.o: ${BUILD_DIR}/config.h
|
||||
zwrite.o: ${BUILD_DIR}/config.h
|
||||
|
||||
|
|
@ -237,6 +254,9 @@ makepath.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h
|
|||
makepath.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h
|
||||
makepath.o: ${topdir}/pathnames.h ${topdir}/externs.h
|
||||
|
||||
netconn.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h
|
||||
netconn.o: ${topdir}/bashtypes.h
|
||||
|
||||
netopen.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${topdir}/xmalloc.h
|
||||
netopen.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
|
||||
netopen.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
|
||||
|
|
@ -280,6 +300,7 @@ pathphys.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h
|
|||
pathphys.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h
|
||||
|
||||
rename.o: ${topdir}/bashtypes.h ${BASHINCDIR}/stdc.h
|
||||
rename.o: ${BASHINCDIR}/posixstat.h
|
||||
|
||||
setlinebuf.o: ${topdir}/xmalloc.h ${topdir}/bashansi.h
|
||||
setlinebuf.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/stdc.h
|
||||
|
|
@ -395,3 +416,13 @@ fmtullong.o: ${BASHINCDIR}/ansi_stdlib.h
|
|||
fmtullong.o: ${BASHINCDIR}/chartypes.h
|
||||
fmtullong.o: ${BASHINCDIR}/stdc.h
|
||||
fmtullong.o: ${BASHINCDIR}/typemax.h
|
||||
|
||||
fmtumax.o: ${topdir}/bashansi.h
|
||||
fmtumax.o: ${BASHINCDIR}/ansi_stdlib.h
|
||||
fmtumax.o: ${BASHINCDIR}/chartypes.h
|
||||
fmtumax.o: ${BASHINCDIR}/stdc.h
|
||||
fmtumax.o: ${BASHINCDIR}/typemax.h
|
||||
|
||||
xstrchr.o: ${topdir}/bashansi.h
|
||||
xstrchr.o: ${BASHINCDIR}/ansi_stdlib.h
|
||||
xstrchr.o: ${BASHINCDIR}/shmbutil.h
|
||||
|
|
|
|||
|
|
@ -27,6 +27,10 @@
|
|||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LIMITS_H)
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#if !defined (HAVE_SYSCONF) || !defined (_SC_CLK_TCK)
|
||||
# if !defined (CLK_TCK)
|
||||
# if defined (HZ)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
/* Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
/* fmtullong.c - convert `long long int' to string */
|
||||
|
||||
/* Copyright (C) 2001-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
|
||||
|
|
@ -18,7 +20,10 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|||
|
||||
#ifdef HAVE_LONG_LONG
|
||||
|
||||
#define QUAD 1
|
||||
#define LONG long long
|
||||
#define UNSIGNED_LONG unsigned long long
|
||||
#define fmtulong fmtullong
|
||||
|
||||
#include "fmtulong.c"
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* fmtulong.c -- Convert unsigned long int to string. */
|
||||
|
||||
/* Copyright (C) 1998, Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1998-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
|
@ -67,20 +67,9 @@ extern int errno;
|
|||
# define FL_UNSIGNED 0x08 /* don't add any sign */
|
||||
#endif
|
||||
|
||||
#ifdef QUAD
|
||||
/* fmtullong */
|
||||
# define LONG long long
|
||||
# define FMTUL_LONG_MAX LLONG_MAX
|
||||
# define FMTUL_ULONG_MAX ULLONG_MAX
|
||||
#else
|
||||
#ifndef LONG
|
||||
# define LONG long
|
||||
# define FMTUL_LONG_MAX LONG_MAX
|
||||
# define FMTUL_ULONG_MAX ULONG_MAX
|
||||
#endif
|
||||
|
||||
/* Set the name */
|
||||
#ifdef QUAD
|
||||
# define fmtulong fmtullong
|
||||
# define UNSIGNED_LONG unsigned long
|
||||
#endif
|
||||
|
||||
/* `unsigned long' (or unsigned long long) to string conversion for a given
|
||||
|
|
@ -88,7 +77,7 @@ extern int errno;
|
|||
check for buffer underflow, but currently does not. */
|
||||
char *
|
||||
fmtulong (ui, base, buf, len, flags)
|
||||
unsigned LONG ui;
|
||||
UNSIGNED_LONG ui;
|
||||
int base;
|
||||
char *buf;
|
||||
size_t len;
|
||||
|
|
@ -134,7 +123,7 @@ fmtulong (ui, base, buf, len, flags)
|
|||
}
|
||||
/* Favor signed arithmetic over unsigned arithmetic; it is faster on
|
||||
many machines. */
|
||||
if (ui > FMTUL_LONG_MAX)
|
||||
if ((LONG)ui < 0)
|
||||
{
|
||||
*p-- = TOCHAR (ui % 10);
|
||||
si = ui / 10;
|
||||
|
|
|
|||
25
lib/sh/fmtumax.c
Normal file
25
lib/sh/fmtumax.c
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* fmtumax.c -- Convert uintmax_t to string. */
|
||||
|
||||
/* Copyright (C) 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 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-1307, USA. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#define LONG intmax_t
|
||||
#define UNSIGNED_LONG uintmax_t
|
||||
#define fmtulong fmtumax
|
||||
|
||||
#include "fmtulong.c"
|
||||
154
lib/sh/getenv.c
154
lib/sh/getenv.c
|
|
@ -1,7 +1,7 @@
|
|||
/* getenv.c - get environment variable value from the shell's variable
|
||||
list. */
|
||||
|
||||
/* Copyright (C) 1997 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1997-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
|
@ -28,8 +28,13 @@
|
|||
#endif
|
||||
|
||||
#include <bashansi.h>
|
||||
#include <errno.h>
|
||||
#include <shell.h>
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern char **environ;
|
||||
|
||||
/* We supply our own version of getenv () because we want library
|
||||
|
|
@ -43,21 +48,19 @@ static char *last_tempenv_value = (char *)NULL;
|
|||
|
||||
char *
|
||||
getenv (name)
|
||||
#if defined (__linux__) || defined (__bsdi__) || defined (convex)
|
||||
const char *name;
|
||||
#else
|
||||
char const *name;
|
||||
#endif /* !__linux__ && !__bsdi__ && !convex */
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
if (name == 0 || *name == '\0')
|
||||
return ((char *)NULL);
|
||||
|
||||
var = find_tempenv_variable ((char *)name);
|
||||
if (var)
|
||||
{
|
||||
FREE (last_tempenv_value);
|
||||
|
||||
last_tempenv_value = value_cell (var) ? savestring (value_cell (var)) : (char *)NULL;
|
||||
dispose_variable (var);
|
||||
return (last_tempenv_value);
|
||||
}
|
||||
else if (shell_variables)
|
||||
|
|
@ -88,12 +91,143 @@ getenv (name)
|
|||
/* Some versions of Unix use _getenv instead. */
|
||||
char *
|
||||
_getenv (name)
|
||||
#if defined (__linux__) || defined (__bsdi__) || defined (convex)
|
||||
const char *name;
|
||||
#else
|
||||
char const *name;
|
||||
#endif /* !__linux__ && !__bsdi__ && !convex */
|
||||
{
|
||||
return (getenv (name));
|
||||
}
|
||||
|
||||
/* SUSv3 says argument is a `char *'; BSD implementations disagree */
|
||||
int
|
||||
putenv (str)
|
||||
#ifndef HAVE_STD_PUTENV
|
||||
const char *str;
|
||||
#else
|
||||
char *str;
|
||||
#endif
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
char *name, *value;
|
||||
int offset;
|
||||
|
||||
if (str == 0 || *str == '\0')
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
offset = assignment (str);
|
||||
if (str[offset] != '=')
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
name = savestring (str);
|
||||
name[offset] = 0;
|
||||
|
||||
value = name + offset + 1;
|
||||
|
||||
/* XXX - should we worry about readonly here? */
|
||||
var = bind_variable (name, value);
|
||||
if (var == 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
VUNSETATTR (var, att_invisible);
|
||||
VSETATTR (var, att_exported);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
_putenv (name)
|
||||
#ifndef HAVE_STD_PUTENV
|
||||
const char *name;
|
||||
#else
|
||||
char *name;
|
||||
#endif
|
||||
{
|
||||
return putenv (name);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
setenv (name, value, rewrite)
|
||||
const char *name;
|
||||
const char *value;
|
||||
int rewrite;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
char *v;
|
||||
|
||||
if (name == 0 || *name == '\0' || strchr (name, '=') != 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
var = 0;
|
||||
v = value;
|
||||
/* XXX - should we worry about readonly here? */
|
||||
if (rewrite == 0)
|
||||
var = find_variable (name);
|
||||
|
||||
if (var == 0)
|
||||
var = bind_variable (name, v);
|
||||
|
||||
if (var == 0)
|
||||
return -1;
|
||||
|
||||
VUNSETATTR (var, att_invisible);
|
||||
VSETATTR (var, att_exported);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
_setenv (name, value, rewrite)
|
||||
const char *name;
|
||||
const char *value;
|
||||
int rewrite;
|
||||
{
|
||||
return setenv (name, value, rewrite);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* SUSv3 says unsetenv returns int; existing implementations (BSD) disagree. */
|
||||
|
||||
#ifdef HAVE_STD_UNSETENV
|
||||
#define UNSETENV_RETURN(N) return(N)
|
||||
#define UNSETENV_RETTYPE int
|
||||
#else
|
||||
#define UNSETENV_RETURN(N) return
|
||||
#define UNSETENV_RETTYPE void
|
||||
#endif
|
||||
|
||||
UNSETENV_RETTYPE
|
||||
unsetenv (name)
|
||||
const char *name;
|
||||
{
|
||||
if (name == 0 || *name == '\0' || strchr (name, '=') != 0)
|
||||
{
|
||||
errno = EINVAL;
|
||||
UNSETENV_RETURN(-1);
|
||||
}
|
||||
|
||||
/* XXX - should we just remove the export attribute here? */
|
||||
#if 1
|
||||
unbind_variable (name);
|
||||
#else
|
||||
SHELL_VAR *v;
|
||||
|
||||
v = find_variable (name);
|
||||
if (v)
|
||||
VUNSETATTR (v, att_exported);
|
||||
#endif
|
||||
|
||||
UNSETENV_RETURN(0);
|
||||
}
|
||||
#endif /* CAN_REDEFINE_GETENV */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* itos.c -- Convert integer to string. */
|
||||
|
||||
/* Copyright (C) 1998, Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1998-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
|
@ -27,47 +27,46 @@
|
|||
#endif
|
||||
|
||||
#include <bashansi.h>
|
||||
#include <chartypes.h>
|
||||
#include "shell.h"
|
||||
|
||||
char *
|
||||
inttostr (i, buf, len)
|
||||
long i;
|
||||
intmax_t i;
|
||||
char *buf;
|
||||
size_t len;
|
||||
{
|
||||
return (fmtulong (i, 10, buf, len, 0));
|
||||
return (fmtumax (i, 10, buf, len, 0));
|
||||
}
|
||||
|
||||
/* Integer to string conversion. This conses the string; the
|
||||
caller should free it. */
|
||||
char *
|
||||
itos (i)
|
||||
long i;
|
||||
intmax_t i;
|
||||
{
|
||||
char *p, lbuf[INT_STRLEN_BOUND(long) + 1];
|
||||
char *p, lbuf[INT_STRLEN_BOUND(intmax_t) + 1];
|
||||
|
||||
p = fmtulong (i, 10, lbuf, sizeof(lbuf), 0);
|
||||
p = fmtumax (i, 10, lbuf, sizeof(lbuf), 0);
|
||||
return (savestring (p));
|
||||
}
|
||||
|
||||
char *
|
||||
uinttostr (i, buf, len)
|
||||
unsigned long i;
|
||||
uintmax_t i;
|
||||
char *buf;
|
||||
size_t len;
|
||||
{
|
||||
return (fmtulong (i, 10, buf, len, FL_UNSIGNED));
|
||||
return (fmtumax (i, 10, buf, len, FL_UNSIGNED));
|
||||
}
|
||||
|
||||
/* Integer to string conversion. This conses the string; the
|
||||
caller should free it. */
|
||||
char *
|
||||
uitos (i)
|
||||
unsigned long i;
|
||||
uintmax_t i;
|
||||
{
|
||||
char *p, lbuf[INT_STRLEN_BOUND(long) + 1];
|
||||
char *p, lbuf[INT_STRLEN_BOUND(uintmax_t) + 1];
|
||||
|
||||
p = fmtulong (i, 10, lbuf, sizeof(lbuf), FL_UNSIGNED);
|
||||
p = fmtumax (i, 10, lbuf, sizeof(lbuf), FL_UNSIGNED);
|
||||
return (savestring (p));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ sh_makepath (path, dir, flags)
|
|||
}
|
||||
else
|
||||
{
|
||||
xpath = ((flags & MP_DOTILDE) && *path == '~') ? bash_tilde_expand (path) : (char *)path;
|
||||
xpath = ((flags & MP_DOTILDE) && *path == '~') ? bash_tilde_expand (path, 0) : (char *)path;
|
||||
pathlen = strlen (xpath);
|
||||
}
|
||||
|
||||
|
|
|
|||
26
lib/sh/memset.c
Normal file
26
lib/sh/memset.c
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* memset.c -- set an area of memory to a given value
|
||||
Copyright (C) 1991-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 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-1307, USA. */
|
||||
|
||||
char *
|
||||
memset (char *str, int c, unsigned int len)
|
||||
{
|
||||
register char *st = str;
|
||||
|
||||
while (len-- > 0)
|
||||
*st++ = c;
|
||||
return str;
|
||||
}
|
||||
425
lib/sh/mktime.c
Normal file
425
lib/sh/mktime.c
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/* Copyright (C) 1993-2002 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Paul Eggert (eggert@twinsun.com).
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* Define this to have a standalone program to test this implementation of
|
||||
mktime. */
|
||||
/* #define DEBUG 1 */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#ifdef _LIBC
|
||||
# define HAVE_LIMITS_H 1
|
||||
# define HAVE_LOCALTIME_R 1
|
||||
# define STDC_HEADERS 1
|
||||
#endif
|
||||
|
||||
/* Assume that leap seconds are possible, unless told otherwise.
|
||||
If the host has a `zic' command with a `-L leapsecondfilename' option,
|
||||
then it supports leap seconds; otherwise it probably doesn't. */
|
||||
#ifndef LEAP_SECONDS_POSSIBLE
|
||||
#define LEAP_SECONDS_POSSIBLE 1
|
||||
#endif
|
||||
|
||||
#ifndef VMS
|
||||
#include <sys/types.h> /* Some systems define `time_t' here. */
|
||||
#else
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
|
||||
#if HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
#include <stdio.h>
|
||||
#if STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
/* Make it work even if the system's libc has its own mktime routine. */
|
||||
#define mktime my_mktime
|
||||
#endif /* DEBUG */
|
||||
|
||||
#ifndef __P
|
||||
#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
|
||||
#define __P(args) args
|
||||
#else
|
||||
#define __P(args) ()
|
||||
#endif /* GCC. */
|
||||
#endif /* Not __P. */
|
||||
|
||||
#ifndef CHAR_BIT
|
||||
#define CHAR_BIT 8
|
||||
#endif
|
||||
|
||||
#ifndef INT_MIN
|
||||
#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
|
||||
#endif
|
||||
#ifndef INT_MAX
|
||||
#define INT_MAX (~0 - INT_MIN)
|
||||
#endif
|
||||
|
||||
#ifndef TIME_T_MIN
|
||||
#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
|
||||
: ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
|
||||
#endif
|
||||
#ifndef TIME_T_MAX
|
||||
#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
|
||||
#endif
|
||||
|
||||
#define TM_YEAR_BASE 1900
|
||||
#define EPOCH_YEAR 1970
|
||||
|
||||
#ifndef __isleap
|
||||
/* Nonzero if YEAR is a leap year (every 4 years,
|
||||
except every 100th isn't, and every 400th is). */
|
||||
#define __isleap(year) \
|
||||
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
|
||||
#endif
|
||||
|
||||
/* How many days come before each month (0-12). */
|
||||
const unsigned short int __mon_yday[2][13] =
|
||||
{
|
||||
/* Normal years. */
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||
/* Leap years. */
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
|
||||
static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
|
||||
time_t __mktime_internal __P ((struct tm *,
|
||||
struct tm *(*) (const time_t *, struct tm *),
|
||||
time_t *));
|
||||
|
||||
|
||||
static struct tm *my_localtime_r __P ((const time_t *, struct tm *));
|
||||
static struct tm *
|
||||
my_localtime_r (t, tp)
|
||||
const time_t *t;
|
||||
struct tm *tp;
|
||||
{
|
||||
struct tm *l = localtime (t);
|
||||
if (! l)
|
||||
return 0;
|
||||
*tp = *l;
|
||||
return tp;
|
||||
}
|
||||
|
||||
|
||||
/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
|
||||
measured in seconds, ignoring leap seconds.
|
||||
YEAR uses the same numbering as TM->tm_year.
|
||||
All values are in range, except possibly YEAR.
|
||||
If overflow occurs, yield the low order bits of the correct answer. */
|
||||
static time_t
|
||||
ydhms_tm_diff (year, yday, hour, min, sec, tp)
|
||||
int year, yday, hour, min, sec;
|
||||
const struct tm *tp;
|
||||
{
|
||||
/* Compute intervening leap days correctly even if year is negative.
|
||||
Take care to avoid int overflow. time_t overflow is OK, since
|
||||
only the low order bits of the correct time_t answer are needed.
|
||||
Don't convert to time_t until after all divisions are done, since
|
||||
time_t might be unsigned. */
|
||||
int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
|
||||
int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
|
||||
int a100 = a4 / 25 - (a4 % 25 < 0);
|
||||
int b100 = b4 / 25 - (b4 % 25 < 0);
|
||||
int a400 = a100 >> 2;
|
||||
int b400 = b100 >> 2;
|
||||
int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
|
||||
time_t years = year - (time_t) tp->tm_year;
|
||||
time_t days = (365 * years + intervening_leap_days
|
||||
+ (yday - tp->tm_yday));
|
||||
return (60 * (60 * (24 * days + (hour - tp->tm_hour))
|
||||
+ (min - tp->tm_min))
|
||||
+ (sec - tp->tm_sec));
|
||||
}
|
||||
|
||||
|
||||
static time_t localtime_offset;
|
||||
|
||||
/* Convert *TP to a time_t value. */
|
||||
time_t
|
||||
mktime (tp)
|
||||
struct tm *tp;
|
||||
{
|
||||
#ifdef _LIBC
|
||||
/* POSIX.1 8.1.1 requires that whenever mktime() is called, the
|
||||
time zone names contained in the external variable `tzname' shall
|
||||
be set as if the tzset() function had been called. */
|
||||
__tzset ();
|
||||
#endif
|
||||
|
||||
return __mktime_internal (tp, my_localtime_r, &localtime_offset);
|
||||
}
|
||||
|
||||
/* Convert *TP to a time_t value, inverting
|
||||
the monotonic and mostly-unit-linear conversion function CONVERT.
|
||||
Use *OFFSET to keep track of a guess at the offset of the result,
|
||||
compared to what the result would be for UTC without leap seconds.
|
||||
If *OFFSET's guess is correct, only one CONVERT call is needed. */
|
||||
time_t
|
||||
__mktime_internal (tp, convert, offset)
|
||||
struct tm *tp;
|
||||
struct tm *(*convert) __P ((const time_t *, struct tm *));
|
||||
time_t *offset;
|
||||
{
|
||||
time_t t, dt, t0;
|
||||
struct tm tm;
|
||||
|
||||
/* The maximum number of probes (calls to CONVERT) should be enough
|
||||
to handle any combinations of time zone rule changes, solar time,
|
||||
and leap seconds. Posix.1 prohibits leap seconds, but some hosts
|
||||
have them anyway. */
|
||||
int remaining_probes = 4;
|
||||
|
||||
/* Time requested. Copy it in case CONVERT modifies *TP; this can
|
||||
occur if TP is localtime's returned value and CONVERT is localtime. */
|
||||
int sec = tp->tm_sec;
|
||||
int min = tp->tm_min;
|
||||
int hour = tp->tm_hour;
|
||||
int mday = tp->tm_mday;
|
||||
int mon = tp->tm_mon;
|
||||
int year_requested = tp->tm_year;
|
||||
int isdst = tp->tm_isdst;
|
||||
|
||||
/* Ensure that mon is in range, and set year accordingly. */
|
||||
int mon_remainder = mon % 12;
|
||||
int negative_mon_remainder = mon_remainder < 0;
|
||||
int mon_years = mon / 12 - negative_mon_remainder;
|
||||
int year = year_requested + mon_years;
|
||||
|
||||
/* The other values need not be in range:
|
||||
the remaining code handles minor overflows correctly,
|
||||
assuming int and time_t arithmetic wraps around.
|
||||
Major overflows are caught at the end. */
|
||||
|
||||
/* Calculate day of year from year, month, and day of month.
|
||||
The result need not be in range. */
|
||||
int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
|
||||
[mon_remainder + 12 * negative_mon_remainder])
|
||||
+ mday - 1);
|
||||
|
||||
#if LEAP_SECONDS_POSSIBLE
|
||||
/* Handle out-of-range seconds specially,
|
||||
since ydhms_tm_diff assumes every minute has 60 seconds. */
|
||||
int sec_requested = sec;
|
||||
if (sec < 0)
|
||||
sec = 0;
|
||||
if (59 < sec)
|
||||
sec = 59;
|
||||
#endif
|
||||
|
||||
/* Invert CONVERT by probing. First assume the same offset as last time.
|
||||
Then repeatedly use the error to improve the guess. */
|
||||
|
||||
tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
|
||||
tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
|
||||
t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
|
||||
|
||||
for (t = t0 + *offset;
|
||||
(dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
|
||||
t += dt)
|
||||
if (--remaining_probes == 0)
|
||||
return -1;
|
||||
|
||||
/* Check whether tm.tm_isdst has the requested value, if any. */
|
||||
if (0 <= isdst && 0 <= tm.tm_isdst)
|
||||
{
|
||||
int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
|
||||
if (dst_diff)
|
||||
{
|
||||
/* Move two hours in the direction indicated by the disagreement,
|
||||
probe some more, and switch to a new time if found.
|
||||
The largest known fallback due to daylight savings is two hours:
|
||||
once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
|
||||
time_t ot = t - 2 * 60 * 60 * dst_diff;
|
||||
while (--remaining_probes != 0)
|
||||
{
|
||||
struct tm otm;
|
||||
if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
|
||||
(*convert) (&ot, &otm))))
|
||||
{
|
||||
t = ot;
|
||||
tm = otm;
|
||||
break;
|
||||
}
|
||||
if ((ot += dt) == t)
|
||||
break; /* Avoid a redundant probe. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*offset = t - t0;
|
||||
|
||||
#if LEAP_SECONDS_POSSIBLE
|
||||
if (sec_requested != tm.tm_sec)
|
||||
{
|
||||
/* Adjust time to reflect the tm_sec requested, not the normalized value.
|
||||
Also, repair any damage from a false match due to a leap second. */
|
||||
t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
|
||||
(*convert) (&t, &tm);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
|
||||
{
|
||||
/* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
|
||||
so check for major overflows. A gross check suffices,
|
||||
since if t has overflowed, it is off by a multiple of
|
||||
TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
|
||||
the difference that is bounded by a small value. */
|
||||
|
||||
double dyear = (double) year_requested + mon_years - tm.tm_year;
|
||||
double dday = 366 * dyear + mday;
|
||||
double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
|
||||
|
||||
if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
|
||||
return -1;
|
||||
}
|
||||
|
||||
*tp = tm;
|
||||
return t;
|
||||
}
|
||||
|
||||
#ifdef weak_alias
|
||||
weak_alias (mktime, timelocal)
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
|
||||
static int
|
||||
not_equal_tm (a, b)
|
||||
struct tm *a;
|
||||
struct tm *b;
|
||||
{
|
||||
return ((a->tm_sec ^ b->tm_sec)
|
||||
| (a->tm_min ^ b->tm_min)
|
||||
| (a->tm_hour ^ b->tm_hour)
|
||||
| (a->tm_mday ^ b->tm_mday)
|
||||
| (a->tm_mon ^ b->tm_mon)
|
||||
| (a->tm_year ^ b->tm_year)
|
||||
| (a->tm_mday ^ b->tm_mday)
|
||||
| (a->tm_yday ^ b->tm_yday)
|
||||
| (a->tm_isdst ^ b->tm_isdst));
|
||||
}
|
||||
|
||||
static void
|
||||
print_tm (tp)
|
||||
struct tm *tp;
|
||||
{
|
||||
printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
|
||||
tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
|
||||
tp->tm_hour, tp->tm_min, tp->tm_sec,
|
||||
tp->tm_yday, tp->tm_wday, tp->tm_isdst);
|
||||
}
|
||||
|
||||
static int
|
||||
check_result (tk, tmk, tl, tml)
|
||||
time_t tk;
|
||||
struct tm tmk;
|
||||
time_t tl;
|
||||
struct tm tml;
|
||||
{
|
||||
if (tk != tl || not_equal_tm (&tmk, &tml))
|
||||
{
|
||||
printf ("mktime (");
|
||||
print_tm (&tmk);
|
||||
printf (")\nyields (");
|
||||
print_tm (&tml);
|
||||
printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int status = 0;
|
||||
struct tm tm, tmk, tml;
|
||||
time_t tk, tl;
|
||||
char trailer;
|
||||
|
||||
if ((argc == 3 || argc == 4)
|
||||
&& (sscanf (argv[1], "%d-%d-%d%c",
|
||||
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
|
||||
== 3)
|
||||
&& (sscanf (argv[2], "%d:%d:%d%c",
|
||||
&tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
|
||||
== 3))
|
||||
{
|
||||
tm.tm_year -= TM_YEAR_BASE;
|
||||
tm.tm_mon--;
|
||||
tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
|
||||
tmk = tm;
|
||||
tl = mktime (&tmk);
|
||||
tml = *localtime (&tl);
|
||||
printf ("mktime returns %ld == ", (long) tl);
|
||||
print_tm (&tmk);
|
||||
printf ("\n");
|
||||
status = check_result (tl, tmk, tl, tml);
|
||||
}
|
||||
else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
|
||||
{
|
||||
time_t from = atol (argv[1]);
|
||||
time_t by = atol (argv[2]);
|
||||
time_t to = atol (argv[3]);
|
||||
|
||||
if (argc == 4)
|
||||
for (tl = from; tl <= to; tl += by)
|
||||
{
|
||||
tml = *localtime (&tl);
|
||||
tmk = tml;
|
||||
tk = mktime (&tmk);
|
||||
status |= check_result (tk, tmk, tl, tml);
|
||||
}
|
||||
else
|
||||
for (tl = from; tl <= to; tl += by)
|
||||
{
|
||||
/* Null benchmark. */
|
||||
tml = *localtime (&tl);
|
||||
tmk = tml;
|
||||
tk = tl;
|
||||
status |= check_result (tk, tmk, tl, tml);
|
||||
}
|
||||
}
|
||||
else
|
||||
printf ("Usage:\
|
||||
\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
|
||||
\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
|
||||
\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
|
||||
argv[0], argv[0], argv[0]);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"
|
||||
End:
|
||||
*/
|
||||
83
lib/sh/netconn.c
Normal file
83
lib/sh/netconn.c
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
/* netconn.c -- is a particular file descriptor a network connection?. */
|
||||
|
||||
/* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <bashtypes.h>
|
||||
#ifndef _MINIX
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
#include <posixstat.h>
|
||||
#include <filecntl.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* The second and subsequent conditions must match those used to decide
|
||||
whether or not to call getpeername() in isnetconn(). */
|
||||
#if defined (HAVE_SYS_SOCKET_H) && defined (HAVE_GETPEERNAME) && !defined (SVR4_2)
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
/* Is FD a socket or network connection? */
|
||||
int
|
||||
isnetconn (fd)
|
||||
int fd;
|
||||
{
|
||||
#if defined (HAVE_GETPEERNAME) && !defined (SVR4_2) && !defined (__BEOS__)
|
||||
int rv;
|
||||
socklen_t l;
|
||||
struct sockaddr sa;
|
||||
|
||||
l = sizeof(sa);
|
||||
rv = getpeername(fd, &sa, &l);
|
||||
/* Solaris 2.5 getpeername() returns EINVAL if the fd is not a socket. */
|
||||
return ((rv < 0 && (errno == ENOTSOCK || errno == EINVAL)) ? 0 : 1);
|
||||
#else /* !HAVE_GETPEERNAME || SVR4_2 || __BEOS__ */
|
||||
# if defined (SVR4) || defined (SVR4_2)
|
||||
/* Sockets on SVR4 and SVR4.2 are character special (streams) devices. */
|
||||
struct stat sb;
|
||||
|
||||
if (isatty (fd))
|
||||
return (0);
|
||||
if (fstat (fd, &sb) < 0)
|
||||
return (0);
|
||||
# if defined (S_ISFIFO)
|
||||
if (S_ISFIFO (sb.st_mode))
|
||||
return (0);
|
||||
# endif /* S_ISFIFO */
|
||||
return (S_ISCHR (sb.st_mode));
|
||||
# else /* !SVR4 && !SVR4_2 */
|
||||
# if defined (S_ISSOCK) && !defined (__BEOS__)
|
||||
struct stat sb;
|
||||
|
||||
if (fstat (fd, &sb) < 0)
|
||||
return (0);
|
||||
return (S_ISSOCK (sb.st_mode));
|
||||
# else /* !S_ISSOCK || __BEOS__ */
|
||||
return (0);
|
||||
# endif /* !S_ISSOCK || __BEOS__ */
|
||||
# endif /* !SVR4 && !SVR4_2 */
|
||||
#endif /* !HAVE_GETPEERNAME || SVR4_2 || __BEOS__ */
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
* chet@ins.CWRU.Edu
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1987,1991 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
|
@ -107,7 +107,7 @@ _getserv (serv, proto, pp)
|
|||
int proto;
|
||||
unsigned short *pp;
|
||||
{
|
||||
long l;
|
||||
intmax_t l;
|
||||
unsigned short s;
|
||||
|
||||
if (legal_number (serv, &l))
|
||||
|
|
@ -165,7 +165,7 @@ _netopen4(host, serv, typ)
|
|||
return -1;
|
||||
}
|
||||
|
||||
bzero ((char *)&sin, sizeof(sin));
|
||||
memset ((char *)&sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
sin.sin_port = p;
|
||||
sin.sin_addr = ina;
|
||||
|
|
@ -205,7 +205,7 @@ _netopen6 (host, serv, typ)
|
|||
struct addrinfo hints, *res, *res0;
|
||||
int gerr;
|
||||
|
||||
bzero ((char *)&hints, sizeof (hints));
|
||||
memset ((char *)&hints, 0, sizeof (hints));
|
||||
/* XXX -- if problems with IPv6, set to PF_INET for IPv4 only */
|
||||
#ifdef DEBUG /* PF_INET is the one that works for me */
|
||||
hints.ai_family = PF_INET;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,10 @@
|
|||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LIMITS_H)
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
#include <posixstat.h>
|
||||
#include <filecntl.h>
|
||||
#include <bashansi.h>
|
||||
|
|
@ -237,3 +241,56 @@ mkfifo (path, mode)
|
|||
#endif /* !S_IFIFO */
|
||||
}
|
||||
#endif /* !HAVE_MKFIFO && PROCESS_SUBSTITUTION */
|
||||
|
||||
#define DEFAULT_MAXGROUPS 64
|
||||
|
||||
int
|
||||
getmaxgroups ()
|
||||
{
|
||||
static int maxgroups = -1;
|
||||
|
||||
if (maxgroups > 0)
|
||||
return maxgroups;
|
||||
|
||||
#if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
|
||||
maxgroups = sysconf (_SC_NGROUPS_MAX);
|
||||
#else
|
||||
# if defined (NGROUPS_MAX)
|
||||
maxgroups = NGROUPS_MAX;
|
||||
# else /* !NGROUPS_MAX */
|
||||
# if defined (NGROUPS)
|
||||
maxgroups = NGROUPS;
|
||||
# else /* !NGROUPS */
|
||||
maxgroups = DEFAULT_MAXGROUPS;
|
||||
# endif /* !NGROUPS */
|
||||
# endif /* !NGROUPS_MAX */
|
||||
#endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */
|
||||
|
||||
if (maxgroups <= 0)
|
||||
maxgroups = DEFAULT_MAXGROUPS;
|
||||
|
||||
return maxgroups;
|
||||
}
|
||||
|
||||
long
|
||||
getmaxchild ()
|
||||
{
|
||||
static long maxchild = -1L;
|
||||
|
||||
if (maxchild > 0)
|
||||
return maxchild;
|
||||
|
||||
#if defined (HAVE_SYSCONF) && defined (_SC_CHILD_MAX)
|
||||
maxchild = sysconf (_SC_CHILD_MAX);
|
||||
#else
|
||||
# if defined (CHILD_MAX)
|
||||
maxchild = CHILD_MAX;
|
||||
# else
|
||||
# if defined (MAXUPRC)
|
||||
maxchild = MAXUPRC;
|
||||
# endif /* MAXUPRC */
|
||||
# endif /* CHILD_MAX */
|
||||
#endif /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
|
||||
|
||||
return (maxchild);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,34 @@
|
|||
|
||||
#include "shell.h"
|
||||
|
||||
#if defined (__CYGWIN__)
|
||||
#include <sys/cygwin.h>
|
||||
|
||||
static int
|
||||
_is_cygdrive (path)
|
||||
char *path;
|
||||
{
|
||||
static char user[MAXPATHLEN];
|
||||
static char system[MAXPATHLEN];
|
||||
static int first_time = 1;
|
||||
|
||||
/* If the path is the first part of a network path, treat it as
|
||||
existing. */
|
||||
if (path[0] == '/' && path[1] == '/' && !strchr (path + 2, '/'))
|
||||
return 1;
|
||||
/* Otherwise check for /cygdrive prefix. */
|
||||
if (first_time)
|
||||
{
|
||||
char user_flags[MAXPATHLEN];
|
||||
char system_flags[MAXPATHLEN];
|
||||
/* Get the cygdrive info */
|
||||
cygwin_internal (CW_GET_CYGDRIVE_INFO, user, system, user_flags, system_flags);
|
||||
first_time = 0;
|
||||
}
|
||||
return !strcasecmp (path, user) || !strcasecmp (path, system);
|
||||
}
|
||||
#endif /* __CYGWIN__ */
|
||||
|
||||
/* Return 1 if PATH corresponds to a directory. A function for debugging. */
|
||||
static int
|
||||
_path_isdir (path)
|
||||
|
|
@ -46,6 +74,10 @@ _path_isdir (path)
|
|||
struct stat sb;
|
||||
|
||||
l = stat (path, &sb) == 0 && S_ISDIR (sb.st_mode);
|
||||
#if defined (__CYGWIN__)
|
||||
if (l == 0)
|
||||
l = _is_cygdrive (path);
|
||||
#endif
|
||||
return l;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,21 +25,52 @@
|
|||
#if !defined (HAVE_RENAME)
|
||||
|
||||
#include <bashtypes.h>
|
||||
#include <posixstat.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include <stdc.h>
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
int
|
||||
rename (from, to)
|
||||
const char *from, *to;
|
||||
{
|
||||
unlink (to);
|
||||
struct stat fb, tb;
|
||||
|
||||
if (stat (from, &fb) < 0)
|
||||
return -1;
|
||||
|
||||
if (stat (to, &tb) < 0)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fb.st_dev == tb.st_dev && fb.st_ino == tb.st_ino)
|
||||
return 0; /* same file */
|
||||
if (unlink (to) < 0 && errno != ENOENT)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (link (from, to) < 0)
|
||||
return (-1);
|
||||
unlink (from);
|
||||
|
||||
if (unlink (from) < 0 && errno != ENOENT)
|
||||
{
|
||||
int e = errno;
|
||||
unlink (to);
|
||||
errno = e;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif /* !HAVE_RENAME */
|
||||
|
|
|
|||
|
|
@ -147,6 +147,7 @@ sh_backslash_quote (string)
|
|||
case '*': case '[': case '?': case ']': /* globbing chars */
|
||||
case '^':
|
||||
case '$': case '`': /* expansion chars */
|
||||
case ',': /* brace expansion */
|
||||
*r++ = '\\';
|
||||
*r++ = c;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -47,9 +47,7 @@
|
|||
* Currently doesn't handle (and bash/readline doesn't use):
|
||||
* *M$ width, precision specifications
|
||||
* %N$ numbered argument conversions
|
||||
* inf, nan floating values (could use isinf(), isnan())
|
||||
* `,', `'' flags
|
||||
* `C', `S' conversions
|
||||
* inf, nan floating values imperfect (if isinf(), isnan() not in libc)
|
||||
* support for `F' is imperfect, since underlying printf may not handle it
|
||||
*/
|
||||
|
||||
|
|
@ -65,10 +63,12 @@
|
|||
#ifdef __linux__
|
||||
#define HAVE_PRINTF_A_FORMAT
|
||||
#endif
|
||||
#define HAVE_ISINF_IN_LIBC
|
||||
#define PREFER_STDARG
|
||||
#define HAVE_STRINGIZE
|
||||
#define HAVE_LIMITS_H
|
||||
#define HAVE_STDDEF_H
|
||||
#define HAVE_LOCALE_H
|
||||
#define intmax_t long
|
||||
#endif
|
||||
|
||||
|
|
@ -96,12 +96,18 @@
|
|||
#endif
|
||||
|
||||
#ifdef FLOATING_POINT
|
||||
# include <float.h> /* for manifest constants */
|
||||
# include <stdio.h> /* for sprintf */
|
||||
#endif
|
||||
|
||||
#include <typemax.h>
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
#endif
|
||||
|
||||
#include "stdc.h"
|
||||
#include <shmbutil.h>
|
||||
|
||||
#ifndef DRIVER
|
||||
# include "shell.h"
|
||||
|
|
@ -114,6 +120,10 @@ extern char *fmtulong __P((unsigned long int, int, char *, size_t, int));
|
|||
extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));
|
||||
#endif
|
||||
|
||||
#ifndef FREE
|
||||
# define FREE(x) if (x) free (x)
|
||||
#endif
|
||||
|
||||
/* Bound on length of the string representing an integer value of type T.
|
||||
Subtract one for the sign bit if T is signed;
|
||||
302 / 1000 is log10 (2) rounded up;
|
||||
|
|
@ -130,7 +140,7 @@ extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));
|
|||
#define PF_ZEROPAD 0x00008 /* 0 */
|
||||
#define PF_PLUS 0x00010 /* + */
|
||||
#define PF_SPACE 0x00020 /* ' ' */
|
||||
#define PF_COMMA 0x00040 /* , */
|
||||
#define PF_THOUSANDS 0x00040 /* ' */
|
||||
|
||||
#define PF_DOT 0x00080 /* `.precision' */
|
||||
#define PF_STAR_P 0x00100 /* `*' after precision */
|
||||
|
|
@ -158,6 +168,10 @@ extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));
|
|||
|
||||
static char intbuf[INT_STRLEN_BOUND(unsigned long) + 1];
|
||||
|
||||
static int decpoint;
|
||||
static int thoussep;
|
||||
static char *grouping;
|
||||
|
||||
/*
|
||||
* For the FLOATING POINT FORMAT :
|
||||
* the challenge was finding a way to
|
||||
|
|
@ -196,25 +210,27 @@ static char intbuf[INT_STRLEN_BOUND(unsigned long) + 1];
|
|||
|
||||
#define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}
|
||||
|
||||
#define GETARG(type) (va_arg(args, type))
|
||||
|
||||
/* Macros that do proper sign extension and handle length modifiers. Used
|
||||
for the integer conversion specifiers. */
|
||||
#define GETSIGNED(p) \
|
||||
(((p)->flags & PF_LONGINT) \
|
||||
? va_arg(args, long) \
|
||||
: (((p)->flags & PF_SHORTINT) ? (long)(short)va_arg(args, int) \
|
||||
: (long)va_arg(args, int)))
|
||||
? GETARG (long) \
|
||||
: (((p)->flags & PF_SHORTINT) ? (long)(short)GETARG (int) \
|
||||
: (long)GETARG (int)))
|
||||
|
||||
#define GETUNSIGNED(p) \
|
||||
(((p)->flags & PF_LONGINT) \
|
||||
? va_arg(args, unsigned long) \
|
||||
: (((p)->flags & PF_SHORTINT) ? (unsigned long)(unsigned short)va_arg(args, int) \
|
||||
: (unsigned long)va_arg(args, unsigned int)))
|
||||
? GETARG (unsigned long) \
|
||||
: (((p)->flags & PF_SHORTINT) ? (unsigned long)(unsigned short)GETARG (int) \
|
||||
: (unsigned long)GETARG (unsigned int)))
|
||||
|
||||
|
||||
#ifdef HAVE_LONG_DOUBLE
|
||||
#define GETLDOUBLE(p) va_arg(args, long double)
|
||||
#define GETLDOUBLE(p) GETARG (long double)
|
||||
#endif
|
||||
#define GETDOUBLE(p) va_arg(args, double)
|
||||
#define GETDOUBLE(p) GETARG (double)
|
||||
|
||||
#define SET_SIZE_FLAGS(p, type) \
|
||||
if (sizeof (type) > sizeof (int)) \
|
||||
|
|
@ -271,6 +287,8 @@ static void ldfallback __P((struct DATA *, const char *, const char *, long doub
|
|||
static void dfallback __P((struct DATA *, const char *, const char *, double));
|
||||
#endif
|
||||
|
||||
static char *groupnum __P((char *));
|
||||
|
||||
#ifdef DRIVER
|
||||
static void memory_error_and_abort ();
|
||||
static void *xmalloc __P((size_t));
|
||||
|
|
@ -317,6 +335,20 @@ static void xfree __P((void *));
|
|||
} \
|
||||
while (0)
|
||||
|
||||
/* Output a string. P->WIDTH has already been adjusted for padding. */
|
||||
#define PUT_STRING(string, len, p) \
|
||||
do \
|
||||
{ \
|
||||
PAD_RIGHT (p); \
|
||||
while ((len)-- > 0) \
|
||||
{ \
|
||||
PUT_CHAR (*(string), (p)); \
|
||||
(string)++; \
|
||||
} \
|
||||
PAD_LEFT (p); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define PUT_PLUS(d, p, zero) \
|
||||
if ((d) > zero && (p)->justify == RIGHT) \
|
||||
PUT_CHAR('+', p)
|
||||
|
|
@ -340,9 +372,34 @@ static void xfree __P((void *));
|
|||
/* if width and prec. in the args */
|
||||
#define STAR_ARGS(p) \
|
||||
if ((p)->flags & PF_STAR_W) \
|
||||
(p)->width = va_arg(args, int); \
|
||||
(p)->width = GETARG (int); \
|
||||
if ((p)->flags & PF_STAR_P) \
|
||||
(p)->precision = va_arg(args, int)
|
||||
(p)->precision = GETARG (int)
|
||||
|
||||
#if defined (HAVE_LOCALE_H)
|
||||
# define GETLOCALEDATA(d, t, g) \
|
||||
do \
|
||||
{ \
|
||||
struct lconv *lv; \
|
||||
if ((d) == 0) { \
|
||||
(d) = '.'; (t) = -1; (g) = 0; /* defaults */ \
|
||||
lv = localeconv(); \
|
||||
if (lv) \
|
||||
{ \
|
||||
if (lv->decimal_point && lv->decimal_point[0]) \
|
||||
(d) = lv->decimal_point[0]; \
|
||||
if (lv->thousands_sep && lv->thousands_sep[0]) \
|
||||
(t) = lv->thousands_sep[0]; \
|
||||
(g) = lv->grouping ? lv->grouping : ""; \
|
||||
if (*(g) == '\0' || *(g) == CHAR_MAX || (t) == -1) (g) = 0; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
while (0);
|
||||
#else
|
||||
# define GETLOCALEDATA(d, t, g) \
|
||||
( (d) = '.', (t) = ',', g = "\003" )
|
||||
#endif
|
||||
|
||||
#ifdef FLOATING_POINT
|
||||
/*
|
||||
|
|
@ -496,6 +553,8 @@ numtoa(number, base, precision, fract)
|
|||
integral_part[1] = '\0';
|
||||
fraction_part[0] = '0';
|
||||
fraction_part[1] = '\0';
|
||||
if (fract)
|
||||
*fract = fraction_part;
|
||||
return integral_part;
|
||||
}
|
||||
|
||||
|
|
@ -570,7 +629,7 @@ number(p, d, base)
|
|||
unsigned long d;
|
||||
int base;
|
||||
{
|
||||
char *tmp;
|
||||
char *tmp, *t;
|
||||
long sd;
|
||||
int flags;
|
||||
|
||||
|
|
@ -580,6 +639,14 @@ number(p, d, base)
|
|||
flags |= FL_HEXUPPER;
|
||||
|
||||
tmp = fmtulong (d, base, intbuf, sizeof(intbuf), flags);
|
||||
t = 0;
|
||||
if ((p->flags & PF_THOUSANDS))
|
||||
{
|
||||
GETLOCALEDATA(decpoint, thoussep, grouping);
|
||||
if (grouping && (t = groupnum (tmp)))
|
||||
tmp = t;
|
||||
}
|
||||
|
||||
p->width -= strlen(tmp);
|
||||
PAD_RIGHT(p);
|
||||
|
||||
|
|
@ -609,6 +676,7 @@ number(p, d, base)
|
|||
}
|
||||
|
||||
PAD_LEFT(p);
|
||||
FREE (t);
|
||||
}
|
||||
|
||||
#ifdef HAVE_LONG_LONG
|
||||
|
|
@ -621,7 +689,7 @@ lnumber(p, d, base)
|
|||
unsigned long long d;
|
||||
int base;
|
||||
{
|
||||
char *tmp;
|
||||
char *tmp, *t;
|
||||
long long sd;
|
||||
int flags;
|
||||
|
||||
|
|
@ -631,6 +699,14 @@ lnumber(p, d, base)
|
|||
flags |= FL_HEXUPPER;
|
||||
|
||||
tmp = fmtullong (d, base, intbuf, sizeof(intbuf), flags);
|
||||
t = 0;
|
||||
if ((p->flags & PF_THOUSANDS))
|
||||
{
|
||||
GETLOCALEDATA(decpoint, thoussep, grouping);
|
||||
if (grouping && (t = groupnum (tmp)))
|
||||
tmp = t;
|
||||
}
|
||||
|
||||
p->width -= strlen(tmp);
|
||||
PAD_RIGHT(p);
|
||||
|
||||
|
|
@ -660,6 +736,7 @@ lnumber(p, d, base)
|
|||
}
|
||||
|
||||
PAD_LEFT(p);
|
||||
FREE (t);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -692,34 +769,162 @@ strings(p, tmp)
|
|||
struct DATA *p;
|
||||
char *tmp;
|
||||
{
|
||||
int i;
|
||||
size_t len;
|
||||
|
||||
i = strlen(tmp);
|
||||
len = strlen(tmp);
|
||||
if (p->precision != NOT_FOUND) /* the smallest number */
|
||||
i = (i < p->precision ? i : p->precision);
|
||||
p->width -= i;
|
||||
PAD_RIGHT(p);
|
||||
while (i-- > 0)
|
||||
{ /* put the sting */
|
||||
PUT_CHAR(*tmp, p);
|
||||
tmp++;
|
||||
}
|
||||
PAD_LEFT(p);
|
||||
len = (len < p->precision ? len : p->precision);
|
||||
p->width -= len;
|
||||
|
||||
PUT_STRING (tmp, len, p);
|
||||
}
|
||||
|
||||
#if HANDLE_MULTIBYTE
|
||||
/* %ls wide-character strings */
|
||||
static void
|
||||
wstrings(p, tmp)
|
||||
struct DATA *p;
|
||||
wchar_t *tmp;
|
||||
{
|
||||
size_t len;
|
||||
mbstate_t mbs;
|
||||
char *os;
|
||||
const wchar_t *ws;
|
||||
|
||||
memset (&mbs, '\0', sizeof (mbstate_t));
|
||||
ws = (const wchar_t *)tmp;
|
||||
|
||||
os = (char *)NULL;
|
||||
if (p->precision != NOT_FOUND)
|
||||
{
|
||||
os = (char *)xmalloc (p->precision + 1);
|
||||
len = wcsrtombs (os, &ws, p->precision, &mbs);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = wcsrtombs (NULL, &ws, 0, &mbs);
|
||||
if (len != (size_t)-1)
|
||||
{
|
||||
memset (&mbs, '\0', sizeof (mbstate_t));
|
||||
os = (char *)xmalloc (len + 1);
|
||||
(void)wcsrtombs (os, &ws, len + 1, &mbs);
|
||||
}
|
||||
}
|
||||
if (len == (size_t)-1)
|
||||
{
|
||||
/* invalid multibyte sequence; bail now. */
|
||||
FREE (os);
|
||||
return;
|
||||
}
|
||||
|
||||
p->width -= len;
|
||||
PUT_STRING (os, len, p);
|
||||
free (os);
|
||||
}
|
||||
|
||||
static void
|
||||
wchars (p, wc)
|
||||
struct DATA *p;
|
||||
wint_t wc;
|
||||
{
|
||||
char *lbuf, *l;
|
||||
mbstate_t mbs;
|
||||
size_t len;
|
||||
|
||||
lbuf = (char *)malloc (MB_CUR_MAX+1);
|
||||
if (lbuf == 0)
|
||||
return;
|
||||
memset (&mbs, '\0', sizeof (mbstate_t));
|
||||
len = wcrtomb (lbuf, wc, &mbs);
|
||||
if (len == (size_t)-1)
|
||||
/* conversion failed; bail now. */
|
||||
return;
|
||||
p->width -= len;
|
||||
l = lbuf;
|
||||
PUT_STRING (l, len, p);
|
||||
free (lbuf);
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
|
||||
#ifdef FLOATING_POINT
|
||||
|
||||
#ifndef HAVE_ISINF_IN_LIBC
|
||||
/* Half-assed versions, since we don't want to link with libm. */
|
||||
static int
|
||||
isinf(d)
|
||||
double d;
|
||||
{
|
||||
#ifdef DBL_MAX
|
||||
if (d < DBL_MIN)
|
||||
return -1;
|
||||
else if (d > DBL_MAX)
|
||||
return 1;
|
||||
else
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
isnan(d)
|
||||
double d;
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check for [+-]infinity and NaN. If MODE == 1, we check for Infinity, else
|
||||
(mode == 2) we check for NaN. This does the necessary printing. Returns
|
||||
1 if Inf or Nan, 0 if not. */
|
||||
static int
|
||||
chkinfnan(p, d, mode)
|
||||
struct DATA *p;
|
||||
double d;
|
||||
int mode; /* == 1 for inf, == 2 for nan */
|
||||
{
|
||||
int i;
|
||||
char *tmp;
|
||||
char *big, *small;
|
||||
|
||||
i = (mode == 1) ? isinf(d) : isnan(d);
|
||||
if (i == 0)
|
||||
return 0;
|
||||
big = (mode == 1) ? "INF" : "NAN";
|
||||
small = (mode == 1) ? "inf" : "nan";
|
||||
|
||||
tmp = (*p->pf == 'F' || *p->pf == 'G' || *p->pf == 'E') ? big : small;
|
||||
|
||||
if (i < 0)
|
||||
PUT_CHAR('-', p);
|
||||
|
||||
while (*tmp)
|
||||
{
|
||||
PUT_CHAR (*tmp, p);
|
||||
tmp++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* %f %F %g %G floating point representation */
|
||||
static void
|
||||
floating(p, d)
|
||||
struct DATA *p;
|
||||
double d;
|
||||
{
|
||||
char *tmp, *tmp2;
|
||||
char *tmp, *tmp2, *t;
|
||||
int i;
|
||||
|
||||
if (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))
|
||||
return; /* already printed nan or inf */
|
||||
|
||||
GETLOCALEDATA(decpoint, thoussep, grouping);
|
||||
DEF_PREC(p);
|
||||
d = ROUND(d, p);
|
||||
tmp = dtoa(d, p->precision, &tmp2);
|
||||
t = 0;
|
||||
if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp)))
|
||||
tmp = t;
|
||||
|
||||
/* calculate the padding. 1 for the dot */
|
||||
p->width = p->width -
|
||||
((d > 0. && p->justify == RIGHT) ? 1:0) -
|
||||
|
|
@ -728,17 +933,22 @@ floating(p, d)
|
|||
PAD_RIGHT(p);
|
||||
PUT_PLUS(d, p, 0.);
|
||||
PUT_SPACE(d, p, 0.);
|
||||
|
||||
while (*tmp)
|
||||
{ /* the integral */
|
||||
PUT_CHAR(*tmp, p);
|
||||
tmp++;
|
||||
}
|
||||
FREE (t);
|
||||
|
||||
if (p->precision != 0 || (p->flags & PF_ALTFORM))
|
||||
PUT_CHAR('.', p); /* put the '.' */
|
||||
PUT_CHAR(decpoint, p); /* put the '.' */
|
||||
|
||||
if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
|
||||
/* smash the trailing zeros unless altform */
|
||||
for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
|
||||
tmp2[i] = '\0';
|
||||
tmp2[i] = '\0';
|
||||
|
||||
for (; *tmp2; tmp2++)
|
||||
PUT_CHAR(*tmp2, p); /* the fraction */
|
||||
|
||||
|
|
@ -752,69 +962,55 @@ exponent(p, d)
|
|||
double d;
|
||||
{
|
||||
char *tmp, *tmp2;
|
||||
int j, i, nsig, ndig;
|
||||
int j, i;
|
||||
|
||||
if (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))
|
||||
return; /* already printed nan or inf */
|
||||
|
||||
GETLOCALEDATA(decpoint, thoussep, grouping);
|
||||
DEF_PREC(p);
|
||||
j = log_10(d);
|
||||
d = d / pow_10(j); /* get the Mantissa */
|
||||
d = ROUND(d, p);
|
||||
tmp = dtoa(d, p->precision, &tmp2);
|
||||
|
||||
/* 1 for unit, 1 for the '.', 1 for 'e|E',
|
||||
* 1 for '+|-', 2 for 'exp' */
|
||||
/* calculate how much padding need */
|
||||
p->width = p->width -
|
||||
((d > 0. && p->justify == RIGHT) ? 1:0) -
|
||||
((p->flags & PF_SPACE) ? 1:0) - p->precision - 6;
|
||||
|
||||
PAD_RIGHT(p);
|
||||
PUT_PLUS(d, p, 0.);
|
||||
PUT_SPACE(d, p, 0.);
|
||||
/*
|
||||
* When supplied %g or %G, an optional precision is the number of
|
||||
* significant digits to print.
|
||||
*
|
||||
* nsig = number of significant digits we've printed (leading zeros are
|
||||
* never significant)
|
||||
* ndig = if non-zero, max number of significant digits to print (only
|
||||
* applicable to %g/%G)
|
||||
*/
|
||||
nsig = ndig = 0;
|
||||
if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_DOT))
|
||||
ndig = (p->precision == 0) ? 1 : p->precision;
|
||||
|
||||
while (*tmp)
|
||||
{
|
||||
PUT_CHAR(*tmp, p);
|
||||
tmp++;
|
||||
if (ndig && (++nsig >= ndig))
|
||||
break;
|
||||
}
|
||||
|
||||
if ((p->precision != 0 || (p->flags & PF_ALTFORM)) && (ndig == 0 || nsig < ndig))
|
||||
PUT_CHAR('.', p); /* the '.' */
|
||||
if (p->precision != 0 || (p->flags & PF_ALTFORM))
|
||||
PUT_CHAR(decpoint, p); /* the '.' */
|
||||
|
||||
if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
|
||||
/* smash the trailing zeros unless altform */
|
||||
for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
|
||||
tmp2[i] = '\0';
|
||||
tmp2[i] = '\0';
|
||||
|
||||
for (; *tmp2; tmp2++)
|
||||
{
|
||||
if (ndig && (nsig++ >= ndig))
|
||||
break;
|
||||
PUT_CHAR(*tmp2, p); /* the fraction */
|
||||
}
|
||||
PUT_CHAR(*tmp2, p); /* the fraction */
|
||||
|
||||
/* the exponent put the 'e|E' */
|
||||
if (*p->pf == 'g' || *p->pf == 'e')
|
||||
{
|
||||
PUT_CHAR('e', p);
|
||||
}
|
||||
PUT_CHAR('e', p);
|
||||
else
|
||||
PUT_CHAR('E', p);
|
||||
PUT_CHAR('E', p);
|
||||
|
||||
/* the sign of the exp */
|
||||
if (j > 0)
|
||||
{
|
||||
PUT_CHAR('+', p);
|
||||
}
|
||||
PUT_CHAR('+', p);
|
||||
else
|
||||
{
|
||||
PUT_CHAR('-', p);
|
||||
|
|
@ -825,9 +1021,7 @@ exponent(p, d)
|
|||
/* pad out to at least two spaces. pad with `0' if the exponent is a
|
||||
single digit. */
|
||||
if (j <= 9)
|
||||
{
|
||||
PUT_CHAR('0', p);
|
||||
}
|
||||
PUT_CHAR('0', p);
|
||||
|
||||
/* the exponent */
|
||||
while (*tmp)
|
||||
|
|
@ -839,6 +1033,69 @@ exponent(p, d)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Return a new string with the digits in S grouped according to the locale's
|
||||
grouping info and thousands separator. If no grouping should be performed,
|
||||
this returns NULL; the caller needs to check for it. */
|
||||
static char *
|
||||
groupnum (s)
|
||||
char *s;
|
||||
{
|
||||
char *se, *ret, *re, *g;
|
||||
int len, slen;
|
||||
|
||||
if (grouping == 0 || *grouping <= 0 || *grouping == CHAR_MAX)
|
||||
return ((char *)NULL);
|
||||
|
||||
/* find min grouping to size returned string */
|
||||
for (len = *grouping, g = grouping; *g; g++)
|
||||
if (*g > 0 && *g < len)
|
||||
len = *g;
|
||||
|
||||
slen = strlen (s);
|
||||
len = slen / len + 1;
|
||||
ret = (char *)xmalloc (slen + len + 1);
|
||||
re = ret + slen + len;
|
||||
*re = '\0';
|
||||
|
||||
g = grouping;
|
||||
se = s + slen;
|
||||
len = *g;
|
||||
|
||||
while (se > s)
|
||||
{
|
||||
*--re = *--se;
|
||||
|
||||
/* handle `-' inserted by numtoa() and the fmtu* family here. */
|
||||
if (se > s && se[-1] == '-')
|
||||
continue;
|
||||
|
||||
/* begin new group. */
|
||||
if (--len == 0 && se > s)
|
||||
{
|
||||
*--re = thoussep;
|
||||
len = *++g; /* was g++, but that uses first char twice (glibc bug, too) */
|
||||
if (*g == '\0')
|
||||
len = *--g; /* use previous grouping */
|
||||
else if (*g == CHAR_MAX)
|
||||
{
|
||||
do
|
||||
*--re = *--se;
|
||||
while (se > s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (re > ret)
|
||||
#ifdef HAVE_MEMMOVE
|
||||
memmove (ret, re, strlen (re) + 1);
|
||||
#else
|
||||
strcpy (ret, re);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* initialize the conversion specifiers */
|
||||
static void
|
||||
init_conv_flag (p)
|
||||
|
|
@ -887,18 +1144,26 @@ vsnprintf_internal(data, string, length, format, args)
|
|||
#endif
|
||||
int state, i, c, n;
|
||||
char *s;
|
||||
#if HANDLE_MULTIBYTE
|
||||
wchar_t *ws;
|
||||
wint_t wc;
|
||||
#endif
|
||||
const char *convstart;
|
||||
|
||||
/* Sanity check, the string must be > 1. C99 actually says that LENGTH
|
||||
can be zero here, in the case of snprintf/vsnprintf (it's never 0 in
|
||||
the case of asprintf/vasprintf), and the return value is the number
|
||||
/* Sanity check, the string length must be >= 0. C99 actually says that
|
||||
LENGTH can be zero here, in the case of snprintf/vsnprintf (it's never
|
||||
0 in the case of asprintf/vasprintf), and the return value is the number
|
||||
of characters that would have been written. */
|
||||
if (length < 1)
|
||||
if (length < 0)
|
||||
return -1;
|
||||
|
||||
if (format == 0)
|
||||
return 0;
|
||||
|
||||
/* Reset these for each call because the locale might have changed. */
|
||||
decpoint = thoussep = 0;
|
||||
grouping = 0;
|
||||
|
||||
for (; c = *(data->pf); data->pf++)
|
||||
{
|
||||
if (c != '%')
|
||||
|
|
@ -966,8 +1231,8 @@ vsnprintf_internal(data, string, length, format, args)
|
|||
data->flags |= PF_PLUS;
|
||||
data->justify = RIGHT;
|
||||
continue;
|
||||
case ',':
|
||||
data->flags |= PF_COMMA; /* not implemented yet */
|
||||
case '\'':
|
||||
data->flags |= PF_THOUSANDS;
|
||||
continue;
|
||||
|
||||
case '1': case '2': case '3':
|
||||
|
|
@ -1043,9 +1308,18 @@ conv_break:
|
|||
* else use %e|%E
|
||||
*/
|
||||
if (-4 < i && i < data->precision)
|
||||
floating(data, d);
|
||||
{
|
||||
/* reset precision */
|
||||
data->precision -= i + 1;
|
||||
floating(data, d);
|
||||
}
|
||||
else
|
||||
exponent(data, d);
|
||||
{
|
||||
/* reduce precision by 1 because of leading digit before
|
||||
decimal point in e format. */
|
||||
data->precision--;
|
||||
exponent(data, d);
|
||||
}
|
||||
state = 0;
|
||||
break;
|
||||
case 'e':
|
||||
|
|
@ -1073,7 +1347,7 @@ conv_break:
|
|||
#ifdef HAVE_LONG_LONG
|
||||
if (data->flags & PF_LONGLONG)
|
||||
{
|
||||
ull = va_arg(args, unsigned long long);
|
||||
ull = GETARG (unsigned long long);
|
||||
lnumber(data, ull, 10);
|
||||
}
|
||||
else
|
||||
|
|
@ -1093,7 +1367,7 @@ conv_break:
|
|||
#ifdef HAVE_LONG_LONG
|
||||
if (data->flags & PF_LONGLONG)
|
||||
{
|
||||
ull = va_arg(args, long long);
|
||||
ull = GETARG (long long);
|
||||
lnumber(data, ull, 10);
|
||||
}
|
||||
else
|
||||
|
|
@ -1109,7 +1383,7 @@ conv_break:
|
|||
#ifdef HAVE_LONG_LONG
|
||||
if (data->flags & PF_LONGLONG)
|
||||
{
|
||||
ull = va_arg(args, unsigned long long);
|
||||
ull = GETARG (unsigned long long);
|
||||
lnumber(data, ull, 8);
|
||||
}
|
||||
else
|
||||
|
|
@ -1126,7 +1400,7 @@ conv_break:
|
|||
#ifdef HAVE_LONG_LONG
|
||||
if (data->flags & PF_LONGLONG)
|
||||
{
|
||||
ull = va_arg(args, unsigned long long);
|
||||
ull = GETARG (unsigned long long);
|
||||
lnumber(data, ull, 16);
|
||||
}
|
||||
else
|
||||
|
|
@ -1139,33 +1413,64 @@ conv_break:
|
|||
break;
|
||||
case 'p':
|
||||
STAR_ARGS(data);
|
||||
ul = (unsigned long)va_arg(args, void *);
|
||||
ul = (unsigned long)GETARG (void *);
|
||||
pointer(data, ul);
|
||||
state = 0;
|
||||
break;
|
||||
#if HANDLE_MULTIBYTE
|
||||
case 'C':
|
||||
data->flags |= PF_LONGINT;
|
||||
/* FALLTHROUGH */
|
||||
#endif
|
||||
case 'c': /* character */
|
||||
ul = va_arg(args, int);
|
||||
PUT_CHAR(ul, data);
|
||||
STAR_ARGS(data);
|
||||
#if HANDLE_MULTIBYTE
|
||||
if (data->flags & PF_LONGINT)
|
||||
{
|
||||
wc = GETARG (wint_t);
|
||||
wchars (data, wc);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ul = GETARG (int);
|
||||
PUT_CHAR(ul, data);
|
||||
}
|
||||
state = 0;
|
||||
break;
|
||||
#if HANDLE_MULTIBYTE
|
||||
case 'S':
|
||||
data->flags |= PF_LONGINT;
|
||||
/* FALLTHROUGH */
|
||||
#endif
|
||||
case 's': /* string */
|
||||
STAR_ARGS(data);
|
||||
s = va_arg(args, char *);
|
||||
strings(data, s);
|
||||
#if HANDLE_MULTIBYTE
|
||||
if (data->flags & PF_LONGINT)
|
||||
{
|
||||
ws = GETARG (wchar_t *);
|
||||
wstrings (data, ws);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
s = GETARG (char *);
|
||||
strings(data, s);
|
||||
}
|
||||
state = 0;
|
||||
break;
|
||||
case 'n':
|
||||
#ifdef HAVE_LONG_LONG
|
||||
if (data->flags & PF_LONGLONG)
|
||||
*(va_arg(args, long long *)) = data->counter;
|
||||
*(GETARG (long long *)) = data->counter;
|
||||
else
|
||||
#endif
|
||||
if (data->flags & PF_LONGINT)
|
||||
*(va_arg(args, long *)) = data->counter;
|
||||
*(GETARG (long *)) = data->counter;
|
||||
else if (data->flags & PF_SHORTINT)
|
||||
*(va_arg(args, short *)) = data->counter;
|
||||
*(GETARG (short *)) = data->counter;
|
||||
else
|
||||
*(va_arg(args, int *)) = data->counter;
|
||||
*(GETARG (int *)) = data->counter;
|
||||
state = 0;
|
||||
break;
|
||||
case '%': /* nothing just % */
|
||||
|
|
@ -1201,7 +1506,7 @@ ldfallback (data, fs, fe, ld)
|
|||
char fmtbuf[FALLBACK_FMTSIZE], *obuf;
|
||||
int fl;
|
||||
|
||||
obuf = xmalloc(LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2);
|
||||
obuf = (char *)xmalloc(LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2);
|
||||
fl = fe - fs + 1;
|
||||
strncpy (fmtbuf, fs, fl);
|
||||
fmtbuf[fl] = '\0';
|
||||
|
|
@ -1248,6 +1553,8 @@ vsnprintf(string, length, format, args)
|
|||
{
|
||||
struct DATA data;
|
||||
|
||||
if (string == 0 && length != 0)
|
||||
return 0;
|
||||
init_data (&data, string, length, format, PFM_SN);
|
||||
return (vsnprintf_internal(&data, string, length, format, args));
|
||||
}
|
||||
|
|
@ -1267,12 +1574,10 @@ snprintf(string, length, format, va_alist)
|
|||
int rval;
|
||||
va_list args;
|
||||
|
||||
#if defined(PREFER_STDARG)
|
||||
va_start(args, format);
|
||||
#else
|
||||
va_start(args);
|
||||
#endif
|
||||
SH_VA_START(args, format);
|
||||
|
||||
if (string == 0 && length != 0)
|
||||
return 0;
|
||||
init_data (&data, string, length, format, PFM_SN);
|
||||
rval = vsnprintf_internal (&data, string, length, format, args);
|
||||
|
||||
|
|
@ -1319,11 +1624,7 @@ asprintf(stringp, format, va_alist)
|
|||
int rval;
|
||||
va_list args;
|
||||
|
||||
#if defined(PREFER_STDARG)
|
||||
va_start(args, format);
|
||||
#else
|
||||
va_start(args);
|
||||
#endif
|
||||
SH_VA_START(args, format);
|
||||
|
||||
rval = vasprintf (stringp, format, args);
|
||||
|
||||
|
|
@ -1378,10 +1679,6 @@ xfree(x)
|
|||
free (x);
|
||||
}
|
||||
|
||||
#ifdef FLOATING_POINT
|
||||
# include <float.h>
|
||||
#endif
|
||||
|
||||
/* set of small tests for snprintf() */
|
||||
main()
|
||||
{
|
||||
|
|
@ -1389,6 +1686,18 @@ main()
|
|||
char *h;
|
||||
int i, si, ai;
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
setlocale(LC_ALL, "");
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
si = snprintf((char *)NULL, 0, "abcde\n");
|
||||
printf("snprintf returns %d with NULL first argument and size of 0\n", si);
|
||||
si = snprintf(holder, 0, "abcde\n");
|
||||
printf("snprintf returns %d with non-NULL first argument and size of 0\n", si);
|
||||
si = snprintf((char *)NULL, 16, "abcde\n");
|
||||
printf("snprintf returns %d with NULL first argument and non-zero size\n", si);
|
||||
|
||||
/*
|
||||
printf("Suite of test for snprintf:\n");
|
||||
printf("a_format\n");
|
||||
|
|
@ -1660,6 +1969,92 @@ main()
|
|||
printf ("<%d> <%s>\n", si, holder);
|
||||
printf ("<%d> <%s>\n\n", ai, h);
|
||||
|
||||
/* huh? */
|
||||
printf("/%%g/, 421.2345\n");
|
||||
snprintf(holder, sizeof holder, "/%g/\n", 421.2345);
|
||||
asprintf(&h, "/%g/\n", 421.2345);
|
||||
printf("/%g/\n", 421.2345);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
|
||||
printf("/%%g/, 4214.2345\n");
|
||||
snprintf(holder, sizeof holder, "/%g/\n", 4214.2345);
|
||||
asprintf(&h, "/%g/\n", 4214.2345);
|
||||
printf("/%g/\n", 4214.2345);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
|
||||
printf("/%%.5g/, 4214.2345\n");
|
||||
snprintf(holder, sizeof holder, "/%.5g/\n", 4214.2345);
|
||||
asprintf(&h, "/%.5g/\n", 4214.2345);
|
||||
printf("/%.5g/\n", 4214.2345);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
|
||||
printf("/%%.4g/, 4214.2345\n");
|
||||
snprintf(holder, sizeof holder, "/%.4g/\n", 4214.2345);
|
||||
asprintf(&h, "/%.4g/\n", 4214.2345);
|
||||
printf("/%.4g/\n", 4214.2345);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
|
||||
printf("/%%'ld %%'ld/, 12345, 1234567\n");
|
||||
snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 12345, 1234567);
|
||||
asprintf(&h, "/%'ld %'ld/\n", 12345, 1234567);
|
||||
printf("/%'ld %'ld/\n", 12345, 1234567);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
|
||||
printf("/%%'ld %%'ld/, 336, 3336\n");
|
||||
snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 336, 3336);
|
||||
asprintf(&h, "/%'ld %'ld/\n", 336, 3336);
|
||||
printf("/%'ld %'ld/\n", 336, 3336);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
|
||||
printf("/%%'ld %%'ld/, -42786, -142786\n");
|
||||
snprintf(holder, sizeof holder, "/%'ld %'ld/\n", -42786, -142786);
|
||||
asprintf(&h, "/%'ld %'ld/\n", -42786, -142786);
|
||||
printf("/%'ld %'ld/\n", -42786, -142786);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
|
||||
printf("/%%'f %%'f/, 421.2345, 421234.56789\n");
|
||||
snprintf(holder, sizeof holder, "/%'f %'f/\n", 421.2345, 421234.56789);
|
||||
asprintf(&h, "/%'f %'f/\n", 421.2345, 421234.56789);
|
||||
printf("/%'f %'f/\n", 421.2345, 421234.56789);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
|
||||
printf("/%%'f %%'f/, -421.2345, -421234.56789\n");
|
||||
snprintf(holder, sizeof holder, "/%'f %'f/\n", -421.2345, -421234.56789);
|
||||
asprintf(&h, "/%'f %'f/\n", -421.2345, -421234.56789);
|
||||
printf("/%'f %'f/\n", -421.2345, -421234.56789);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
|
||||
printf("/%%'g %%'g/, 421.2345, 421234.56789\n");
|
||||
snprintf(holder, sizeof holder, "/%'g %'g/\n", 421.2345, 421234.56789);
|
||||
asprintf(&h, "/%'g %'g/\n", 421.2345, 421234.56789);
|
||||
printf("/%'g %'g/\n", 421.2345, 421234.56789);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
|
||||
printf("/%%'g %%'g/, -421.2345, -421234.56789\n");
|
||||
snprintf(holder, sizeof holder, "/%'g %'g/\n", -421.2345, -421234.56789);
|
||||
asprintf(&h, "/%'g %'g/\n", -421.2345, -421234.56789);
|
||||
printf("/%'g %'g/\n", -421.2345, -421234.56789);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
#endif
|
||||
|
||||
printf("/%%'g/, 4213455.8392\n");
|
||||
snprintf(holder, sizeof holder, "/%'g/\n", 4213455.8392);
|
||||
asprintf(&h, "/%'g/\n", 4213455.8392);
|
||||
printf("/%'g/\n", 4213455.8392);
|
||||
printf("%s", holder);
|
||||
printf("%s\n", h);
|
||||
|
||||
exit (0);
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -38,8 +38,10 @@ Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
|||
|
||||
#include <bashansi.h>
|
||||
#include <maxpath.h>
|
||||
#include <stdc.h>
|
||||
|
||||
static int mindist (), spdist ();
|
||||
static int mindist __P((char *, char *, char *));
|
||||
static int spdist __P((char *, char *));
|
||||
|
||||
/*
|
||||
* `spname' and its helpers are inspired by the code in "The UNIX
|
||||
|
|
|
|||
859
lib/sh/strftime.c
Normal file
859
lib/sh/strftime.c
Normal 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 */
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/* stringlist.c - functions to handle a generic `list of strings' structure */
|
||||
|
||||
/* Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2000-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
/* Allocate a new STRINGLIST, with room for N strings. */
|
||||
|
||||
STRINGLIST *
|
||||
alloc_stringlist (n)
|
||||
strlist_create (n)
|
||||
int n;
|
||||
{
|
||||
STRINGLIST *ret;
|
||||
|
|
@ -46,7 +46,7 @@ alloc_stringlist (n)
|
|||
ret = (STRINGLIST *)xmalloc (sizeof (STRINGLIST));
|
||||
if (n)
|
||||
{
|
||||
ret->list = alloc_array (n+1);
|
||||
ret->list = strvec_create (n+1);
|
||||
ret->list_size = n;
|
||||
for (i = 0; i < n; i++)
|
||||
ret->list[i] = (char *)NULL;
|
||||
|
|
@ -61,38 +61,64 @@ alloc_stringlist (n)
|
|||
}
|
||||
|
||||
STRINGLIST *
|
||||
realloc_stringlist (sl, n)
|
||||
strlist_resize (sl, n)
|
||||
STRINGLIST *sl;
|
||||
int n;
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (sl == 0)
|
||||
return (sl = alloc_stringlist(n));
|
||||
return (sl = strlist_create (n));
|
||||
|
||||
if (n > sl->list_size)
|
||||
{
|
||||
sl->list = (char **)xrealloc (sl->list, (n+1) * sizeof (char *));
|
||||
sl->list = strvec_resize (sl->list, n + 1);
|
||||
for (i = sl->list_size; i <= n; i++)
|
||||
sl->list[i] = (char *)NULL;
|
||||
sl->list_size = n;
|
||||
}
|
||||
return sl;
|
||||
}
|
||||
|
||||
void
|
||||
strlist_flush (sl)
|
||||
STRINGLIST *sl;
|
||||
{
|
||||
if (sl == 0 || sl->list == 0)
|
||||
return;
|
||||
strvec_flush (sl->list);
|
||||
sl->list_len = 0;
|
||||
}
|
||||
|
||||
void
|
||||
free_stringlist (sl)
|
||||
strlist_dispose (sl)
|
||||
STRINGLIST *sl;
|
||||
{
|
||||
if (sl == 0)
|
||||
return;
|
||||
if (sl->list)
|
||||
free_array (sl->list);
|
||||
strvec_dispose (sl->list);
|
||||
free (sl);
|
||||
}
|
||||
|
||||
int
|
||||
strlist_remove (sl, s)
|
||||
STRINGLIST *sl;
|
||||
char *s;
|
||||
{
|
||||
int r;
|
||||
|
||||
if (sl == 0 || sl->list == 0 || sl->list_len == 0)
|
||||
return 0;
|
||||
|
||||
r = strvec_remove (sl->list, s);
|
||||
if (r)
|
||||
sl->list_len--;
|
||||
return r;
|
||||
}
|
||||
|
||||
STRINGLIST *
|
||||
copy_stringlist (sl)
|
||||
strlist_copy (sl)
|
||||
STRINGLIST *sl;
|
||||
{
|
||||
STRINGLIST *new;
|
||||
|
|
@ -100,8 +126,8 @@ copy_stringlist (sl)
|
|||
|
||||
if (sl == 0)
|
||||
return ((STRINGLIST *)0);
|
||||
new = alloc_stringlist (sl->list_size);
|
||||
/* I'd like to use copy_array, but that doesn't copy everything. */
|
||||
new = strlist_create (sl->list_size);
|
||||
/* I'd like to use strvec_copy, but that doesn't copy everything. */
|
||||
if (sl->list)
|
||||
{
|
||||
for (i = 0; i < sl->list_size; i++)
|
||||
|
|
@ -118,7 +144,7 @@ copy_stringlist (sl)
|
|||
/* Return a new STRINGLIST with everything from M1 and M2. */
|
||||
|
||||
STRINGLIST *
|
||||
merge_stringlists (m1, m2)
|
||||
strlist_merge (m1, m2)
|
||||
STRINGLIST *m1, *m2;
|
||||
{
|
||||
STRINGLIST *sl;
|
||||
|
|
@ -127,7 +153,7 @@ merge_stringlists (m1, m2)
|
|||
l1 = m1 ? m1->list_len : 0;
|
||||
l2 = m2 ? m2->list_len : 0;
|
||||
|
||||
sl = alloc_stringlist (l1 + l2 + 1);
|
||||
sl = strlist_create (l1 + l2 + 1);
|
||||
for (i = n = 0; i < l1; i++, n++)
|
||||
sl->list[n] = STRDUP (m1->list[i]);
|
||||
for (i = 0; i < l2; i++, n++)
|
||||
|
|
@ -139,20 +165,20 @@ merge_stringlists (m1, m2)
|
|||
|
||||
/* Make STRINGLIST M1 contain everything in M1 and M2. */
|
||||
STRINGLIST *
|
||||
append_stringlist (m1, m2)
|
||||
strlist_append (m1, m2)
|
||||
STRINGLIST *m1, *m2;
|
||||
{
|
||||
register int i, n, len1, len2;
|
||||
|
||||
if (m1 == 0)
|
||||
return (m2 ? copy_stringlist (m2) : (STRINGLIST *)0);
|
||||
return (m2 ? strlist_copy (m2) : (STRINGLIST *)0);
|
||||
|
||||
len1 = m1->list_len;
|
||||
len2 = m2 ? m2->list_len : 0;
|
||||
|
||||
if (len2)
|
||||
{
|
||||
m1 = realloc_stringlist (m1, len1 + len2 + 1);
|
||||
m1 = strlist_resize (m1, len1 + len2 + 1);
|
||||
for (i = 0, n = len1; i < len2; i++, n++)
|
||||
m1->list[n] = STRDUP (m2->list[i]);
|
||||
m1->list[n] = (char *)NULL;
|
||||
|
|
@ -163,7 +189,7 @@ append_stringlist (m1, m2)
|
|||
}
|
||||
|
||||
STRINGLIST *
|
||||
prefix_suffix_stringlist (sl, prefix, suffix)
|
||||
strlist_prefix_suffix (sl, prefix, suffix)
|
||||
STRINGLIST *sl;
|
||||
char *prefix, *suffix;
|
||||
{
|
||||
|
|
@ -197,7 +223,7 @@ prefix_suffix_stringlist (sl, prefix, suffix)
|
|||
}
|
||||
|
||||
void
|
||||
print_stringlist (sl, prefix)
|
||||
strlist_print (sl, prefix)
|
||||
STRINGLIST *sl;
|
||||
char *prefix;
|
||||
{
|
||||
|
|
@ -210,18 +236,32 @@ print_stringlist (sl, prefix)
|
|||
}
|
||||
|
||||
void
|
||||
sort_stringlist (sl)
|
||||
strlist_walk (sl, func)
|
||||
STRINGLIST *sl;
|
||||
sh_strlist_map_func_t *func;
|
||||
{
|
||||
register int i;
|
||||
|
||||
if (sl == 0)
|
||||
return;
|
||||
for (i = 0; i < sl->list_len; i++)
|
||||
if ((*func)(sl->list[i]) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
void
|
||||
strlist_sort (sl)
|
||||
STRINGLIST *sl;
|
||||
{
|
||||
if (sl == 0 || sl->list_len == 0 || sl->list == 0)
|
||||
return;
|
||||
sort_char_array (sl->list);
|
||||
strvec_sort (sl->list);
|
||||
}
|
||||
|
||||
STRINGLIST *
|
||||
word_list_to_stringlist (list, copy, starting_index, ip)
|
||||
strlist_from_word_list (list, alloc, starting_index, ip)
|
||||
WORD_LIST *list;
|
||||
int copy, starting_index, *ip;
|
||||
int alloc, starting_index, *ip;
|
||||
{
|
||||
STRINGLIST *ret;
|
||||
int slen, len;
|
||||
|
|
@ -234,7 +274,7 @@ word_list_to_stringlist (list, copy, starting_index, ip)
|
|||
}
|
||||
slen = list_length (list);
|
||||
ret = (STRINGLIST *)xmalloc (sizeof (STRINGLIST));
|
||||
ret->list = word_list_to_argv (list, copy, starting_index, &len);
|
||||
ret->list = strvec_from_word_list (list, alloc, starting_index, &len);
|
||||
ret->list_size = slen + starting_index;
|
||||
ret->list_len = len;
|
||||
if (ip)
|
||||
|
|
@ -243,15 +283,15 @@ word_list_to_stringlist (list, copy, starting_index, ip)
|
|||
}
|
||||
|
||||
WORD_LIST *
|
||||
stringlist_to_word_list (sl, copy, starting_index)
|
||||
strlist_to_word_list (sl, alloc, starting_index)
|
||||
STRINGLIST *sl;
|
||||
int copy, starting_index;
|
||||
int alloc, starting_index;
|
||||
{
|
||||
WORD_LIST *list;
|
||||
|
||||
if (sl == 0 || sl->list == 0)
|
||||
return ((WORD_LIST *)NULL);
|
||||
|
||||
list = argv_to_word_list (sl->list, copy, starting_index);
|
||||
list = strvec_to_word_list (sl->list, alloc, starting_index);
|
||||
return list;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* stringvec.c - function for managing arrays of strings. */
|
||||
/* stringvec.c - functions for managing arrays of strings. */
|
||||
|
||||
/* Copyright (C) 2000 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2000-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
|
|
@ -32,34 +32,25 @@
|
|||
|
||||
#include "shell.h"
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Find NAME in ARRAY. Return the index of NAME, or -1 if not present.
|
||||
ARRAY should be NULL terminated. */
|
||||
int
|
||||
find_name_in_array (name, array)
|
||||
char *name, **array;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; array[i]; i++)
|
||||
if (STREQ (name, array[i]))
|
||||
return (i);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Allocate an array of strings with room for N members. */
|
||||
char **
|
||||
alloc_array (n)
|
||||
strvec_create (n)
|
||||
int n;
|
||||
{
|
||||
return ((char **)xmalloc ((n) * sizeof (char *)));
|
||||
}
|
||||
|
||||
char **
|
||||
strvec_resize (array, nsize)
|
||||
char **array;
|
||||
int nsize;
|
||||
{
|
||||
return ((char **)xrealloc (array, nsize * sizeof (char *)));
|
||||
}
|
||||
|
||||
/* Return the length of ARRAY, a NULL terminated array of char *. */
|
||||
int
|
||||
array_len (array)
|
||||
strvec_len (array)
|
||||
char **array;
|
||||
{
|
||||
register int i;
|
||||
|
|
@ -70,7 +61,7 @@ array_len (array)
|
|||
|
||||
/* Free the contents of ARRAY, a NULL terminated array of char *. */
|
||||
void
|
||||
free_array_members (array)
|
||||
strvec_flush (array)
|
||||
char **array;
|
||||
{
|
||||
register int i;
|
||||
|
|
@ -83,26 +74,65 @@ free_array_members (array)
|
|||
}
|
||||
|
||||
void
|
||||
free_array (array)
|
||||
strvec_dispose (array)
|
||||
char **array;
|
||||
{
|
||||
if (array == 0)
|
||||
return;
|
||||
|
||||
free_array_members (array);
|
||||
strvec_flush (array);
|
||||
free (array);
|
||||
}
|
||||
|
||||
int
|
||||
strvec_remove (array, name)
|
||||
char **array, *name;
|
||||
{
|
||||
register int i, j;
|
||||
char *x;
|
||||
|
||||
if (array == 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; array[i]; i++)
|
||||
if (STREQ (name, array[i]))
|
||||
{
|
||||
x = array[i];
|
||||
for (j = i; array[j]; j++)
|
||||
array[j] = array[j + 1];
|
||||
free (x);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Find NAME in ARRAY. Return the index of NAME, or -1 if not present.
|
||||
ARRAY should be NULL terminated. */
|
||||
int
|
||||
strvec_search (array, name)
|
||||
char **array, *name;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; array[i]; i++)
|
||||
if (STREQ (name, array[i]))
|
||||
return (i);
|
||||
|
||||
return (-1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Allocate and return a new copy of ARRAY and its contents. */
|
||||
char **
|
||||
copy_array (array)
|
||||
strvec_copy (array)
|
||||
char **array;
|
||||
{
|
||||
register int i;
|
||||
int len;
|
||||
char **ret;
|
||||
|
||||
len = array_len (array);
|
||||
len = strvec_len (array);
|
||||
|
||||
ret = (char **)xmalloc ((len + 1) * sizeof (char *));
|
||||
for (i = 0; array[i]; i++)
|
||||
|
|
@ -115,7 +145,7 @@ copy_array (array)
|
|||
/* Comparison routine for use with qsort() on arrays of strings. Uses
|
||||
strcoll(3) if available, otherwise it uses strcmp(3). */
|
||||
int
|
||||
qsort_string_compare (s1, s2)
|
||||
strvec_strcmp (s1, s2)
|
||||
register char **s1, **s2;
|
||||
{
|
||||
#if defined (HAVE_STRCOLL)
|
||||
|
|
@ -132,8 +162,71 @@ qsort_string_compare (s1, s2)
|
|||
|
||||
/* Sort ARRAY, a null terminated array of pointers to strings. */
|
||||
void
|
||||
sort_char_array (array)
|
||||
strvec_sort (array)
|
||||
char **array;
|
||||
{
|
||||
qsort (array, array_len (array), sizeof (char *), (QSFUNC *)qsort_string_compare);
|
||||
qsort (array, strvec_len (array), sizeof (char *), (QSFUNC *)strvec_strcmp);
|
||||
}
|
||||
|
||||
/* Cons up a new array of words. The words are taken from LIST,
|
||||
which is a WORD_LIST *. If ALLOC is true, everything is malloc'ed,
|
||||
so you should free everything in this array when you are done.
|
||||
The array is NULL terminated. If IP is non-null, it gets the
|
||||
number of words in the returned array. STARTING_INDEX says where
|
||||
to start filling in the returned array; it can be used to reserve
|
||||
space at the beginning of the array. */
|
||||
|
||||
char **
|
||||
strvec_from_word_list (list, alloc, starting_index, ip)
|
||||
WORD_LIST *list;
|
||||
int alloc, starting_index, *ip;
|
||||
{
|
||||
int count;
|
||||
char **array;
|
||||
|
||||
count = list_length (list);
|
||||
array = (char **)xmalloc ((1 + count + starting_index) * sizeof (char *));
|
||||
|
||||
for (count = 0; count < starting_index; count++)
|
||||
array[count] = (char *)NULL;
|
||||
for (count = starting_index; list; count++, list = list->next)
|
||||
array[count] = alloc ? savestring (list->word->word) : list->word->word;
|
||||
array[count] = (char *)NULL;
|
||||
|
||||
if (ip)
|
||||
*ip = count;
|
||||
return (array);
|
||||
}
|
||||
|
||||
/* Convert an array of strings into the form used internally by the shell.
|
||||
ALLOC means to allocate new storage for each WORD_DESC in the returned
|
||||
list rather than copy the values in ARRAY. STARTING_INDEX says where
|
||||
in ARRAY to begin. */
|
||||
|
||||
WORD_LIST *
|
||||
strvec_to_word_list (array, alloc, starting_index)
|
||||
char **array;
|
||||
int alloc, starting_index;
|
||||
{
|
||||
WORD_LIST *list;
|
||||
WORD_DESC *w;
|
||||
int i, count;
|
||||
|
||||
if (array == 0 || array[0] == 0)
|
||||
return (WORD_LIST *)NULL;
|
||||
|
||||
for (count = 0; array[count]; count++)
|
||||
;
|
||||
|
||||
for (i = starting_index, list = (WORD_LIST *)NULL; i < count; i++)
|
||||
{
|
||||
w = make_bare_word (alloc ? array[i] : "");
|
||||
if (alloc == 0)
|
||||
{
|
||||
free (w->word);
|
||||
w->word = array[i];
|
||||
}
|
||||
list = make_word_list (w, list);
|
||||
}
|
||||
return (REVERSE_LIST (list, WORD_LIST *));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,14 +40,15 @@
|
|||
/* Convert STRING by expanding the escape sequences specified by the
|
||||
ANSI C standard. If SAWC is non-null, recognize `\c' and use that
|
||||
as a string terminator. If we see \c, set *SAWC to 1 before
|
||||
returning. LEN is the length of STRING. FOR_ECHO is a flag that
|
||||
means, if non-zero, that we're translating a string for `echo -e',
|
||||
and therefore should not treat a single quote as a character that
|
||||
may be escaped with a backslash. */
|
||||
returning. LEN is the length of STRING. If (FLAGS&1) is non-zero,
|
||||
that we're translating a string for `echo -e', and therefore should not
|
||||
treat a single quote as a character that may be escaped with a backslash.
|
||||
If (FLAGS&2) is non-zero, we're expanding for the parser and want to
|
||||
quote CTLESC and CTLNUL with CTLESC */
|
||||
char *
|
||||
ansicstr (string, len, for_echo, sawc, rlen)
|
||||
ansicstr (string, len, flags, sawc, rlen)
|
||||
char *string;
|
||||
int len, for_echo, *sawc, *rlen;
|
||||
int len, flags, *sawc, *rlen;
|
||||
{
|
||||
int c, temp;
|
||||
char *ret, *r, *s;
|
||||
|
|
@ -55,7 +56,7 @@ ansicstr (string, len, for_echo, sawc, rlen)
|
|||
if (string == 0 || *string == '\0')
|
||||
return ((char *)NULL);
|
||||
|
||||
ret = (char *)xmalloc (len + 1);
|
||||
ret = (char *)xmalloc (2*len + 1); /* 2*len for possible CTLESC */
|
||||
for (r = ret, s = string; s && *s; )
|
||||
{
|
||||
c = *s++;
|
||||
|
|
@ -81,7 +82,12 @@ ansicstr (string, len, for_echo, sawc, rlen)
|
|||
case 't': c = '\t'; break;
|
||||
case '0': case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
for (temp = 2, c -= '0'; ISOCTAL (*s) && temp--; s++)
|
||||
/* If (FLAGS & 1), we're translating a string for echo -e (or
|
||||
the equivalent xpg_echo option), so we obey the SUSv3/
|
||||
POSIX-2001 requirement and accept 0-3 octal digits after
|
||||
a leading `0'. */
|
||||
temp = 2 + ((flags & 1) && (c == '0'));
|
||||
for (c -= '0'; ISOCTAL (*s) && temp--; s++)
|
||||
c = (c * 8) + OCTVALUE (*s);
|
||||
c &= 0xFF;
|
||||
break;
|
||||
|
|
@ -99,7 +105,7 @@ ansicstr (string, len, for_echo, sawc, rlen)
|
|||
case '\\':
|
||||
break;
|
||||
case '\'':
|
||||
if (for_echo)
|
||||
if (flags & 1)
|
||||
*r++ = '\\';
|
||||
break;
|
||||
case 'c':
|
||||
|
|
@ -111,8 +117,17 @@ ansicstr (string, len, for_echo, sawc, rlen)
|
|||
*rlen = r - ret;
|
||||
return ret;
|
||||
}
|
||||
else if ((flags & 1) == 0 && (c = *s))
|
||||
{
|
||||
s++;
|
||||
c = TOCTRL(c);
|
||||
break;
|
||||
}
|
||||
/*FALLTHROUGH*/
|
||||
default: *r++ = '\\'; break;
|
||||
}
|
||||
if ((flags & 2) && (c == CTLESC || c == CTLNUL))
|
||||
*r++ = CTLESC;
|
||||
*r++ = c;
|
||||
}
|
||||
}
|
||||
|
|
@ -129,7 +144,7 @@ ansic_quote (str, flags, rlen)
|
|||
char *str;
|
||||
int flags, *rlen;
|
||||
{
|
||||
char *r, *ret, *s, obuf[8];
|
||||
char *r, *ret, *s;
|
||||
int l, rsize, t;
|
||||
unsigned char c;
|
||||
|
||||
|
|
@ -137,7 +152,7 @@ ansic_quote (str, flags, rlen)
|
|||
return ((char *)0);
|
||||
|
||||
l = strlen (str);
|
||||
rsize = 2 * l + 4;
|
||||
rsize = 4 * l + 4;
|
||||
r = ret = (char *)xmalloc (rsize);
|
||||
|
||||
*r++ = '$';
|
||||
|
|
@ -169,12 +184,10 @@ ansic_quote (str, flags, rlen)
|
|||
default:
|
||||
if (ISPRINT (c) == 0)
|
||||
{
|
||||
sprintf (obuf, "\\%.3o", c);
|
||||
t = r - ret;
|
||||
RESIZE_MALLOCED_BUFFER (ret, t, 5, rsize, 16);
|
||||
r = ret + t; /* in case reallocated */
|
||||
for (t = 0; t < 4; t++)
|
||||
*r++ = obuf[t];
|
||||
*r++ = '\\';
|
||||
*r++ = TOCHAR ((c >> 6) & 07);
|
||||
*r++ = TOCHAR ((c >> 3) & 07);
|
||||
*r++ = TOCHAR (c & 07);
|
||||
continue;
|
||||
}
|
||||
l = 0;
|
||||
|
|
@ -193,6 +206,7 @@ ansic_quote (str, flags, rlen)
|
|||
}
|
||||
|
||||
/* return 1 if we need to quote with $'...' because of non-printing chars. */
|
||||
int
|
||||
ansic_shouldquote (string)
|
||||
const char *string;
|
||||
{
|
||||
|
|
@ -208,3 +222,32 @@ ansic_shouldquote (string)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* $'...' ANSI-C expand the portion of STRING between START and END and
|
||||
return the result. The result cannot be longer than the input string. */
|
||||
char *
|
||||
ansiexpand (string, start, end, lenp)
|
||||
char *string;
|
||||
int start, end, *lenp;
|
||||
{
|
||||
char *temp, *t;
|
||||
int len, tlen;
|
||||
|
||||
temp = (char *)xmalloc (end - start + 1);
|
||||
for (tlen = 0, len = start; len < end; )
|
||||
temp[tlen++] = string[len++];
|
||||
temp[tlen] = '\0';
|
||||
|
||||
if (*temp)
|
||||
{
|
||||
t = ansicstr (temp, tlen, 2, (int *)NULL, lenp);
|
||||
free (temp);
|
||||
return (t);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lenp)
|
||||
*lenp = 0;
|
||||
return (temp);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <bashtypes.h>
|
||||
#include <posixstat.h>
|
||||
#include <posixtime.h>
|
||||
#include <filecntl.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
|
|
|
|||
78
lib/sh/xstrchr.c
Normal file
78
lib/sh/xstrchr.c
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/* xstrchr.c - strchr(3) that handles multibyte characters. */
|
||||
|
||||
/* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "shmbutil.h"
|
||||
|
||||
#undef xstrchr
|
||||
|
||||
/* In some locales, the non-first byte of some multibyte characters have
|
||||
the same value as some ascii character. Faced with these strings, a
|
||||
legacy strchr() might return the wrong value. */
|
||||
|
||||
char *
|
||||
#if defined (PROTOTYPES)
|
||||
xstrchr (const char *s, int c)
|
||||
#else
|
||||
xstrchr (s, c)
|
||||
const char *s;
|
||||
int c;
|
||||
#endif
|
||||
{
|
||||
#if HANDLE_MULTIBYTE
|
||||
char *pos;
|
||||
mbstate_t state;
|
||||
size_t strlength, mblength;
|
||||
|
||||
/* The locale encodings with said weird property are BIG5, BIG5-HKSCS,
|
||||
GBK, GB18030, SHIFT_JIS, and JOHAB. They exhibit the problem only
|
||||
when c >= 0x30. We can therefore use the faster bytewise search if
|
||||
c <= 0x30. */
|
||||
if ((unsigned char)c >= '0' && MB_CUR_MAX > 1)
|
||||
{
|
||||
pos = (char *)s;
|
||||
memset (&state, '\0', sizeof(mbstate_t));
|
||||
strlength = strlen (s);
|
||||
|
||||
while (strlength > 0)
|
||||
{
|
||||
mblength = mbrlen (pos, strlength, &state);
|
||||
if (mblength == (size_t)-2 || mblength == (size_t)-1 || mblength == (size_t)0)
|
||||
mblength = 1;
|
||||
|
||||
if (c == (unsigned char)*pos)
|
||||
return pos;
|
||||
|
||||
strlength -= mblength;
|
||||
pos += mblength;
|
||||
}
|
||||
|
||||
return ((char *)NULL);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
return (strchr (s, c));
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue