/contrib/toolchain/binutils/libiberty/Makefile |
---|
0,0 → 1,44 |
CFLAGS_OPT = -U_Win32 -U_WIN32 -U__MINGW32__ -UWIN32 -U_MSC_VER -O2 |
CFLAGS_OPT+= -fomit-frame-pointer -fno-ident -mno-ms-bitfields |
CFLAGS_OPT+= -W -Wall -Wwrite-strings -Wc++-compat -Wstrict-prototypes |
CFLAGS = -c $(CFLAGS_OPT) |
INCLUDES= -I. -I../include -I$(SDK_DIR)/sources/newlib/libc/include |
DEFINES= -DHAVE_CONFIG_H |
SRCS = \ |
alloca.c argv.c asprintf.c bcmp.c bcopy.c bzero.c \ |
choose-temp.c concat.c cp-demangle.c cp-demint.c \ |
cplus-dem.c crc32.c dwarfnames.c dyn-string.c fdmatch.c \ |
ffs.c fibheap.c filename_cmp.c floatformat.c fnmatch.c \ |
fopen_unlocked.c getopt.c getopt1.c getpwd.c \ |
getruntime.c hashtab.c hex.c index.c insque.c \ |
lbasename.c lrealpath.c make-relative-prefix.c \ |
make-temp-file.c md5.c memmem.c mempcpy.c mkstemps.c \ |
objalloc.c obstack.c partition.c physmem.c random.c \ |
regex.c rindex.c safe-ctype.c setenv.c setproctitle.c \ |
sha1.c sigsetmask.c simple-object.c simple-object-coff.c\ |
simple-object-elf.c simple-object-mach-o.c \ |
simple-object-xcoff.c sort.c spaces.c splay-tree.c \ |
stack-limit.c stpcpy.c stpncpy.c strcasecmp.c strerror.c\ |
strncasecmp.c strndup.c strnlen.c strverscmp.c \ |
timeval-utils.c unlink-if-ordinary.c vasprintf.c \ |
xatexit.c xexit.c xmalloc.c xmemdup.c xstrdup.c \ |
xstrerror.c xstrndup.c |
OBJS = $(patsubst %.cpp, %.o, $(patsubst %.c, %.o, $(SRCS))) |
# targets |
all: libiberty.a |
libiberty.a : $(OBJS) MAkefile |
$(AR) crs libiberty.a $(OBJS) |
# mv -f libiberty.a $(SDK_DIR)/lib |
%.o : %.c Makefile |
$(CC) $(CFLAGS) $(DEFINES) $(INCLUDES) -o $@ $< |
/contrib/toolchain/binutils/libiberty/alloca.c |
---|
0,0 → 1,483 |
/* alloca.c -- allocate automatically reclaimed memory |
(Mostly) portable public-domain implementation -- D A Gwyn |
This implementation of the PWB library alloca function, |
which is used to allocate space off the run-time stack so |
that it is automatically reclaimed upon procedure exit, |
was inspired by discussions with J. Q. Johnson of Cornell. |
J.Otto Tennant <jot@cray.com> contributed the Cray support. |
There are some preprocessor constants that can |
be defined when compiling for your specific system, for |
improved efficiency; however, the defaults should be okay. |
The general concept of this implementation is to keep |
track of all alloca-allocated blocks, and reclaim any |
that are found to be deeper in the stack than the current |
invocation. This heuristic does not reclaim storage as |
soon as it becomes invalid, but it will do so eventually. |
As a special case, alloca(0) reclaims storage without |
allocating any. It is a good idea to use alloca(0) in |
your main control loop, etc. to force garbage collection. */ |
/* |
@deftypefn Replacement void* alloca (size_t @var{size}) |
This function allocates memory which will be automatically reclaimed |
after the procedure exits. The @libib{} implementation does not free |
the memory immediately but will do so eventually during subsequent |
calls to this function. Memory is allocated using @code{xmalloc} under |
normal circumstances. |
The header file @file{alloca-conf.h} can be used in conjunction with the |
GNU Autoconf test @code{AC_FUNC_ALLOCA} to test for and properly make |
available this function. The @code{AC_FUNC_ALLOCA} test requires that |
client code use a block of preprocessor code to be safe (see the Autoconf |
manual for more); this header incorporates that logic and more, including |
the possibility of a GCC built-in function. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include <config.h> |
#endif |
#include <libiberty.h> |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
/* These variables are used by the ASTRDUP implementation that relies |
on C_alloca. */ |
#ifdef __cplusplus |
extern "C" { |
#endif /* __cplusplus */ |
const char *libiberty_optr; |
char *libiberty_nptr; |
unsigned long libiberty_len; |
#ifdef __cplusplus |
} |
#endif /* __cplusplus */ |
/* If your stack is a linked list of frames, you have to |
provide an "address metric" ADDRESS_FUNCTION macro. */ |
#if defined (CRAY) && defined (CRAY_STACKSEG_END) |
static long i00afunc (); |
#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg)) |
#else |
#define ADDRESS_FUNCTION(arg) &(arg) |
#endif |
#ifndef NULL |
#define NULL 0 |
#endif |
/* Define STACK_DIRECTION if you know the direction of stack |
growth for your system; otherwise it will be automatically |
deduced at run-time. |
STACK_DIRECTION > 0 => grows toward higher addresses |
STACK_DIRECTION < 0 => grows toward lower addresses |
STACK_DIRECTION = 0 => direction of growth unknown */ |
#ifndef STACK_DIRECTION |
#define STACK_DIRECTION 0 /* Direction unknown. */ |
#endif |
#if STACK_DIRECTION != 0 |
#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */ |
#else /* STACK_DIRECTION == 0; need run-time code. */ |
static int stack_dir; /* 1 or -1 once known. */ |
#define STACK_DIR stack_dir |
static void |
find_stack_direction (void) |
{ |
static char *addr = NULL; /* Address of first `dummy', once known. */ |
auto char dummy; /* To get stack address. */ |
if (addr == NULL) |
{ /* Initial entry. */ |
addr = ADDRESS_FUNCTION (dummy); |
find_stack_direction (); /* Recurse once. */ |
} |
else |
{ |
/* Second entry. */ |
if (ADDRESS_FUNCTION (dummy) > addr) |
stack_dir = 1; /* Stack grew upward. */ |
else |
stack_dir = -1; /* Stack grew downward. */ |
} |
} |
#endif /* STACK_DIRECTION == 0 */ |
/* An "alloca header" is used to: |
(a) chain together all alloca'ed blocks; |
(b) keep track of stack depth. |
It is very important that sizeof(header) agree with malloc |
alignment chunk size. The following default should work okay. */ |
#ifndef ALIGN_SIZE |
#define ALIGN_SIZE sizeof(double) |
#endif |
typedef union hdr |
{ |
char align[ALIGN_SIZE]; /* To force sizeof(header). */ |
struct |
{ |
union hdr *next; /* For chaining headers. */ |
char *deep; /* For stack depth measure. */ |
} h; |
} header; |
static header *last_alloca_header = NULL; /* -> last alloca header. */ |
/* Return a pointer to at least SIZE bytes of storage, |
which will be automatically reclaimed upon exit from |
the procedure that called alloca. Originally, this space |
was supposed to be taken from the current stack frame of the |
caller, but that method cannot be made to work for some |
implementations of C, for example under Gould's UTX/32. */ |
/* @undocumented C_alloca */ |
PTR |
C_alloca (size_t size) |
{ |
auto char probe; /* Probes stack depth: */ |
register char *depth = ADDRESS_FUNCTION (probe); |
#if STACK_DIRECTION == 0 |
if (STACK_DIR == 0) /* Unknown growth direction. */ |
find_stack_direction (); |
#endif |
/* Reclaim garbage, defined as all alloca'd storage that |
was allocated from deeper in the stack than currently. */ |
{ |
register header *hp; /* Traverses linked list. */ |
for (hp = last_alloca_header; hp != NULL;) |
if ((STACK_DIR > 0 && hp->h.deep > depth) |
|| (STACK_DIR < 0 && hp->h.deep < depth)) |
{ |
register header *np = hp->h.next; |
free ((PTR) hp); /* Collect garbage. */ |
hp = np; /* -> next header. */ |
} |
else |
break; /* Rest are not deeper. */ |
last_alloca_header = hp; /* -> last valid storage. */ |
} |
if (size == 0) |
return NULL; /* No allocation required. */ |
/* Allocate combined header + user data storage. */ |
{ |
register void *new_storage = XNEWVEC (char, sizeof (header) + size); |
/* Address of header. */ |
if (new_storage == 0) |
abort(); |
((header *) new_storage)->h.next = last_alloca_header; |
((header *) new_storage)->h.deep = depth; |
last_alloca_header = (header *) new_storage; |
/* User storage begins just after header. */ |
return (PTR) ((char *) new_storage + sizeof (header)); |
} |
} |
#if defined (CRAY) && defined (CRAY_STACKSEG_END) |
#ifdef DEBUG_I00AFUNC |
#include <stdio.h> |
#endif |
#ifndef CRAY_STACK |
#define CRAY_STACK |
#ifndef CRAY2 |
/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */ |
struct stack_control_header |
{ |
long shgrow:32; /* Number of times stack has grown. */ |
long shaseg:32; /* Size of increments to stack. */ |
long shhwm:32; /* High water mark of stack. */ |
long shsize:32; /* Current size of stack (all segments). */ |
}; |
/* The stack segment linkage control information occurs at |
the high-address end of a stack segment. (The stack |
grows from low addresses to high addresses.) The initial |
part of the stack segment linkage control information is |
0200 (octal) words. This provides for register storage |
for the routine which overflows the stack. */ |
struct stack_segment_linkage |
{ |
long ss[0200]; /* 0200 overflow words. */ |
long sssize:32; /* Number of words in this segment. */ |
long ssbase:32; /* Offset to stack base. */ |
long:32; |
long sspseg:32; /* Offset to linkage control of previous |
segment of stack. */ |
long:32; |
long sstcpt:32; /* Pointer to task common address block. */ |
long sscsnm; /* Private control structure number for |
microtasking. */ |
long ssusr1; /* Reserved for user. */ |
long ssusr2; /* Reserved for user. */ |
long sstpid; /* Process ID for pid based multi-tasking. */ |
long ssgvup; /* Pointer to multitasking thread giveup. */ |
long sscray[7]; /* Reserved for Cray Research. */ |
long ssa0; |
long ssa1; |
long ssa2; |
long ssa3; |
long ssa4; |
long ssa5; |
long ssa6; |
long ssa7; |
long sss0; |
long sss1; |
long sss2; |
long sss3; |
long sss4; |
long sss5; |
long sss6; |
long sss7; |
}; |
#else /* CRAY2 */ |
/* The following structure defines the vector of words |
returned by the STKSTAT library routine. */ |
struct stk_stat |
{ |
long now; /* Current total stack size. */ |
long maxc; /* Amount of contiguous space which would |
be required to satisfy the maximum |
stack demand to date. */ |
long high_water; /* Stack high-water mark. */ |
long overflows; /* Number of stack overflow ($STKOFEN) calls. */ |
long hits; /* Number of internal buffer hits. */ |
long extends; /* Number of block extensions. */ |
long stko_mallocs; /* Block allocations by $STKOFEN. */ |
long underflows; /* Number of stack underflow calls ($STKRETN). */ |
long stko_free; /* Number of deallocations by $STKRETN. */ |
long stkm_free; /* Number of deallocations by $STKMRET. */ |
long segments; /* Current number of stack segments. */ |
long maxs; /* Maximum number of stack segments so far. */ |
long pad_size; /* Stack pad size. */ |
long current_address; /* Current stack segment address. */ |
long current_size; /* Current stack segment size. This |
number is actually corrupted by STKSTAT to |
include the fifteen word trailer area. */ |
long initial_address; /* Address of initial segment. */ |
long initial_size; /* Size of initial segment. */ |
}; |
/* The following structure describes the data structure which trails |
any stack segment. I think that the description in 'asdef' is |
out of date. I only describe the parts that I am sure about. */ |
struct stk_trailer |
{ |
long this_address; /* Address of this block. */ |
long this_size; /* Size of this block (does not include |
this trailer). */ |
long unknown2; |
long unknown3; |
long link; /* Address of trailer block of previous |
segment. */ |
long unknown5; |
long unknown6; |
long unknown7; |
long unknown8; |
long unknown9; |
long unknown10; |
long unknown11; |
long unknown12; |
long unknown13; |
long unknown14; |
}; |
#endif /* CRAY2 */ |
#endif /* not CRAY_STACK */ |
#ifdef CRAY2 |
/* Determine a "stack measure" for an arbitrary ADDRESS. |
I doubt that "lint" will like this much. */ |
static long |
i00afunc (long *address) |
{ |
struct stk_stat status; |
struct stk_trailer *trailer; |
long *block, size; |
long result = 0; |
/* We want to iterate through all of the segments. The first |
step is to get the stack status structure. We could do this |
more quickly and more directly, perhaps, by referencing the |
$LM00 common block, but I know that this works. */ |
STKSTAT (&status); |
/* Set up the iteration. */ |
trailer = (struct stk_trailer *) (status.current_address |
+ status.current_size |
- 15); |
/* There must be at least one stack segment. Therefore it is |
a fatal error if "trailer" is null. */ |
if (trailer == 0) |
abort (); |
/* Discard segments that do not contain our argument address. */ |
while (trailer != 0) |
{ |
block = (long *) trailer->this_address; |
size = trailer->this_size; |
if (block == 0 || size == 0) |
abort (); |
trailer = (struct stk_trailer *) trailer->link; |
if ((block <= address) && (address < (block + size))) |
break; |
} |
/* Set the result to the offset in this segment and add the sizes |
of all predecessor segments. */ |
result = address - block; |
if (trailer == 0) |
{ |
return result; |
} |
do |
{ |
if (trailer->this_size <= 0) |
abort (); |
result += trailer->this_size; |
trailer = (struct stk_trailer *) trailer->link; |
} |
while (trailer != 0); |
/* We are done. Note that if you present a bogus address (one |
not in any segment), you will get a different number back, formed |
from subtracting the address of the first block. This is probably |
not what you want. */ |
return (result); |
} |
#else /* not CRAY2 */ |
/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP. |
Determine the number of the cell within the stack, |
given the address of the cell. The purpose of this |
routine is to linearize, in some sense, stack addresses |
for alloca. */ |
static long |
i00afunc (long address) |
{ |
long stkl = 0; |
long size, pseg, this_segment, stack; |
long result = 0; |
struct stack_segment_linkage *ssptr; |
/* Register B67 contains the address of the end of the |
current stack segment. If you (as a subprogram) store |
your registers on the stack and find that you are past |
the contents of B67, you have overflowed the segment. |
B67 also points to the stack segment linkage control |
area, which is what we are really interested in. */ |
stkl = CRAY_STACKSEG_END (); |
ssptr = (struct stack_segment_linkage *) stkl; |
/* If one subtracts 'size' from the end of the segment, |
one has the address of the first word of the segment. |
If this is not the first segment, 'pseg' will be |
nonzero. */ |
pseg = ssptr->sspseg; |
size = ssptr->sssize; |
this_segment = stkl - size; |
/* It is possible that calling this routine itself caused |
a stack overflow. Discard stack segments which do not |
contain the target address. */ |
while (!(this_segment <= address && address <= stkl)) |
{ |
#ifdef DEBUG_I00AFUNC |
fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl); |
#endif |
if (pseg == 0) |
break; |
stkl = stkl - pseg; |
ssptr = (struct stack_segment_linkage *) stkl; |
size = ssptr->sssize; |
pseg = ssptr->sspseg; |
this_segment = stkl - size; |
} |
result = address - this_segment; |
/* If you subtract pseg from the current end of the stack, |
you get the address of the previous stack segment's end. |
This seems a little convoluted to me, but I'll bet you save |
a cycle somewhere. */ |
while (pseg != 0) |
{ |
#ifdef DEBUG_I00AFUNC |
fprintf (stderr, "%011o %011o\n", pseg, size); |
#endif |
stkl = stkl - pseg; |
ssptr = (struct stack_segment_linkage *) stkl; |
size = ssptr->sssize; |
pseg = ssptr->sspseg; |
result += size; |
} |
return (result); |
} |
#endif /* not CRAY2 */ |
#endif /* CRAY */ |
/contrib/toolchain/binutils/libiberty/argv.c |
---|
0,0 → 1,540 |
/* Create and destroy argument vectors (argv's) |
Copyright (C) 1992, 2001, 2010, 2012 Free Software Foundation, Inc. |
Written by Fred Fish @ Cygnus Support |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* Create and destroy argument vectors. An argument vector is simply an |
array of string pointers, terminated by a NULL pointer. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#include "safe-ctype.h" |
/* Routines imported from standard C runtime libraries. */ |
#include <stddef.h> |
#include <string.h> |
#include <stdlib.h> |
#include <stdio.h> |
#ifndef NULL |
#define NULL 0 |
#endif |
#ifndef EOS |
#define EOS '\0' |
#endif |
#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */ |
/* |
@deftypefn Extension char** dupargv (char **@var{vector}) |
Duplicate an argument vector. Simply scans through @var{vector}, |
duplicating each argument until the terminating @code{NULL} is found. |
Returns a pointer to the argument vector if successful. Returns |
@code{NULL} if there is insufficient memory to complete building the |
argument vector. |
@end deftypefn |
*/ |
char ** |
dupargv (char **argv) |
{ |
int argc; |
char **copy; |
if (argv == NULL) |
return NULL; |
/* the vector */ |
for (argc = 0; argv[argc] != NULL; argc++); |
copy = (char **) xmalloc ((argc + 1) * sizeof (char *)); |
/* the strings */ |
for (argc = 0; argv[argc] != NULL; argc++) |
{ |
int len = strlen (argv[argc]); |
copy[argc] = (char *) xmalloc (len + 1); |
strcpy (copy[argc], argv[argc]); |
} |
copy[argc] = NULL; |
return copy; |
} |
/* |
@deftypefn Extension void freeargv (char **@var{vector}) |
Free an argument vector that was built using @code{buildargv}. Simply |
scans through @var{vector}, freeing the memory for each argument until |
the terminating @code{NULL} is found, and then frees @var{vector} |
itself. |
@end deftypefn |
*/ |
void freeargv (char **vector) |
{ |
register char **scan; |
if (vector != NULL) |
{ |
for (scan = vector; *scan != NULL; scan++) |
{ |
free (*scan); |
} |
free (vector); |
} |
} |
static void |
consume_whitespace (const char **input) |
{ |
while (ISSPACE (**input)) |
{ |
(*input)++; |
} |
} |
static int |
only_whitespace (const char* input) |
{ |
while (*input != EOS && ISSPACE (*input)) |
input++; |
return (*input == EOS); |
} |
/* |
@deftypefn Extension char** buildargv (char *@var{sp}) |
Given a pointer to a string, parse the string extracting fields |
separated by whitespace and optionally enclosed within either single |
or double quotes (which are stripped off), and build a vector of |
pointers to copies of the string for each field. The input string |
remains unchanged. The last element of the vector is followed by a |
@code{NULL} element. |
All of the memory for the pointer array and copies of the string |
is obtained from @code{xmalloc}. All of the memory can be returned to the |
system with the single function call @code{freeargv}, which takes the |
returned result of @code{buildargv}, as it's argument. |
Returns a pointer to the argument vector if successful. Returns |
@code{NULL} if @var{sp} is @code{NULL} or if there is insufficient |
memory to complete building the argument vector. |
If the input is a null string (as opposed to a @code{NULL} pointer), |
then buildarg returns an argument vector that has one arg, a null |
string. |
@end deftypefn |
The memory for the argv array is dynamically expanded as necessary. |
In order to provide a working buffer for extracting arguments into, |
with appropriate stripping of quotes and translation of backslash |
sequences, we allocate a working buffer at least as long as the input |
string. This ensures that we always have enough space in which to |
work, since the extracted arg is never larger than the input string. |
The argument vector is always kept terminated with a @code{NULL} arg |
pointer, so it can be passed to @code{freeargv} at any time, or |
returned, as appropriate. |
*/ |
char **buildargv (const char *input) |
{ |
char *arg; |
char *copybuf; |
int squote = 0; |
int dquote = 0; |
int bsquote = 0; |
int argc = 0; |
int maxargc = 0; |
char **argv = NULL; |
char **nargv; |
if (input != NULL) |
{ |
copybuf = (char *) xmalloc (strlen (input) + 1); |
/* Is a do{}while to always execute the loop once. Always return an |
argv, even for null strings. See NOTES above, test case below. */ |
do |
{ |
/* Pick off argv[argc] */ |
consume_whitespace (&input); |
if ((maxargc == 0) || (argc >= (maxargc - 1))) |
{ |
/* argv needs initialization, or expansion */ |
if (argv == NULL) |
{ |
maxargc = INITIAL_MAXARGC; |
nargv = (char **) xmalloc (maxargc * sizeof (char *)); |
} |
else |
{ |
maxargc *= 2; |
nargv = (char **) xrealloc (argv, maxargc * sizeof (char *)); |
} |
argv = nargv; |
argv[argc] = NULL; |
} |
/* Begin scanning arg */ |
arg = copybuf; |
while (*input != EOS) |
{ |
if (ISSPACE (*input) && !squote && !dquote && !bsquote) |
{ |
break; |
} |
else |
{ |
if (bsquote) |
{ |
bsquote = 0; |
*arg++ = *input; |
} |
else if (*input == '\\') |
{ |
bsquote = 1; |
} |
else if (squote) |
{ |
if (*input == '\'') |
{ |
squote = 0; |
} |
else |
{ |
*arg++ = *input; |
} |
} |
else if (dquote) |
{ |
if (*input == '"') |
{ |
dquote = 0; |
} |
else |
{ |
*arg++ = *input; |
} |
} |
else |
{ |
if (*input == '\'') |
{ |
squote = 1; |
} |
else if (*input == '"') |
{ |
dquote = 1; |
} |
else |
{ |
*arg++ = *input; |
} |
} |
input++; |
} |
} |
*arg = EOS; |
argv[argc] = xstrdup (copybuf); |
argc++; |
argv[argc] = NULL; |
consume_whitespace (&input); |
} |
while (*input != EOS); |
free (copybuf); |
} |
return (argv); |
} |
/* |
@deftypefn Extension int writeargv (const char **@var{argv}, FILE *@var{file}) |
Write each member of ARGV, handling all necessary quoting, to the file |
named by FILE, separated by whitespace. Return 0 on success, non-zero |
if an error occurred while writing to FILE. |
@end deftypefn |
*/ |
int |
writeargv (char **argv, FILE *f) |
{ |
int status = 0; |
if (f == NULL) |
return 1; |
while (*argv != NULL) |
{ |
const char *arg = *argv; |
while (*arg != EOS) |
{ |
char c = *arg; |
if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"') |
if (EOF == fputc ('\\', f)) |
{ |
status = 1; |
goto done; |
} |
if (EOF == fputc (c, f)) |
{ |
status = 1; |
goto done; |
} |
arg++; |
} |
if (EOF == fputc ('\n', f)) |
{ |
status = 1; |
goto done; |
} |
argv++; |
} |
done: |
return status; |
} |
/* |
@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp}) |
The @var{argcp} and @code{argvp} arguments are pointers to the usual |
@code{argc} and @code{argv} arguments to @code{main}. This function |
looks for arguments that begin with the character @samp{@@}. Any such |
arguments are interpreted as ``response files''. The contents of the |
response file are interpreted as additional command line options. In |
particular, the file is separated into whitespace-separated strings; |
each such string is taken as a command-line option. The new options |
are inserted in place of the option naming the response file, and |
@code{*argcp} and @code{*argvp} will be updated. If the value of |
@code{*argvp} is modified by this function, then the new value has |
been dynamically allocated and can be deallocated by the caller with |
@code{freeargv}. However, most callers will simply call |
@code{expandargv} near the beginning of @code{main} and allow the |
operating system to free the memory when the program exits. |
@end deftypefn |
*/ |
void |
expandargv (int *argcp, char ***argvp) |
{ |
/* The argument we are currently processing. */ |
int i = 0; |
/* Non-zero if ***argvp has been dynamically allocated. */ |
int argv_dynamic = 0; |
/* Limit the number of response files that we parse in order |
to prevent infinite recursion. */ |
unsigned int iteration_limit = 2000; |
/* Loop over the arguments, handling response files. We always skip |
ARGVP[0], as that is the name of the program being run. */ |
while (++i < *argcp) |
{ |
/* The name of the response file. */ |
const char *filename; |
/* The response file. */ |
FILE *f; |
/* An upper bound on the number of characters in the response |
file. */ |
long pos; |
/* The number of characters in the response file, when actually |
read. */ |
size_t len; |
/* A dynamically allocated buffer used to hold options read from a |
response file. */ |
char *buffer; |
/* Dynamically allocated storage for the options read from the |
response file. */ |
char **file_argv; |
/* The number of options read from the response file, if any. */ |
size_t file_argc; |
/* We are only interested in options of the form "@file". */ |
filename = (*argvp)[i]; |
if (filename[0] != '@') |
continue; |
/* If we have iterated too many times then stop. */ |
if (-- iteration_limit == 0) |
{ |
fprintf (stderr, "%s: error: too many @-files encountered\n", (*argvp)[0]); |
xexit (1); |
} |
/* Read the contents of the file. */ |
f = fopen (++filename, "r"); |
if (!f) |
continue; |
if (fseek (f, 0L, SEEK_END) == -1) |
goto error; |
pos = ftell (f); |
if (pos == -1) |
goto error; |
if (fseek (f, 0L, SEEK_SET) == -1) |
goto error; |
buffer = (char *) xmalloc (pos * sizeof (char) + 1); |
len = fread (buffer, sizeof (char), pos, f); |
if (len != (size_t) pos |
/* On Windows, fread may return a value smaller than POS, |
due to CR/LF->CR translation when reading text files. |
That does not in-and-of itself indicate failure. */ |
&& ferror (f)) |
goto error; |
/* Add a NUL terminator. */ |
buffer[len] = '\0'; |
/* If the file is empty or contains only whitespace, buildargv would |
return a single empty argument. In this context we want no arguments, |
instead. */ |
if (only_whitespace (buffer)) |
{ |
file_argv = (char **) xmalloc (sizeof (char *)); |
file_argv[0] = NULL; |
} |
else |
/* Parse the string. */ |
file_argv = buildargv (buffer); |
/* If *ARGVP is not already dynamically allocated, copy it. */ |
if (!argv_dynamic) |
*argvp = dupargv (*argvp); |
/* Count the number of arguments. */ |
file_argc = 0; |
while (file_argv[file_argc]) |
++file_argc; |
/* Now, insert FILE_ARGV into ARGV. The "+1" below handles the |
NULL terminator at the end of ARGV. */ |
*argvp = ((char **) |
xrealloc (*argvp, |
(*argcp + file_argc + 1) * sizeof (char *))); |
memmove (*argvp + i + file_argc, *argvp + i + 1, |
(*argcp - i) * sizeof (char *)); |
memcpy (*argvp + i, file_argv, file_argc * sizeof (char *)); |
/* The original option has been replaced by all the new |
options. */ |
*argcp += file_argc - 1; |
/* Free up memory allocated to process the response file. We do |
not use freeargv because the individual options in FILE_ARGV |
are now in the main ARGV. */ |
free (file_argv); |
free (buffer); |
/* Rescan all of the arguments just read to support response |
files that include other response files. */ |
--i; |
error: |
/* We're all done with the file now. */ |
fclose (f); |
} |
} |
/* |
@deftypefn Extension int countargv (char **@var{argv}) |
Return the number of elements in @var{argv}. |
Returns zero if @var{argv} is NULL. |
@end deftypefn |
*/ |
int |
countargv (char **argv) |
{ |
int argc; |
if (argv == NULL) |
return 0; |
for (argc = 0; argv[argc] != NULL; argc++) |
continue; |
return argc; |
} |
#ifdef MAIN |
/* Simple little test driver. */ |
static const char *const tests[] = |
{ |
"a simple command line", |
"arg 'foo' is single quoted", |
"arg \"bar\" is double quoted", |
"arg \"foo bar\" has embedded whitespace", |
"arg 'Jack said \\'hi\\'' has single quotes", |
"arg 'Jack said \\\"hi\\\"' has double quotes", |
"a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9", |
/* This should be expanded into only one argument. */ |
"trailing-whitespace ", |
"", |
NULL |
}; |
int |
main (void) |
{ |
char **argv; |
const char *const *test; |
char **targs; |
for (test = tests; *test != NULL; test++) |
{ |
printf ("buildargv(\"%s\")\n", *test); |
if ((argv = buildargv (*test)) == NULL) |
{ |
printf ("failed!\n\n"); |
} |
else |
{ |
for (targs = argv; *targs != NULL; targs++) |
{ |
printf ("\t\"%s\"\n", *targs); |
} |
printf ("\n"); |
} |
freeargv (argv); |
} |
return 0; |
} |
#endif /* MAIN */ |
/contrib/toolchain/binutils/libiberty/asprintf.c |
---|
0,0 → 1,56 |
/* Like sprintf but provides a pointer to malloc'd storage, which must |
be freed by the caller. |
Copyright (C) 1997, 2003 Free Software Foundation, Inc. |
Contributed by Cygnus Solutions. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#include <stdarg.h> |
/* |
@deftypefn Extension int asprintf (char **@var{resptr}, const char *@var{format}, ...) |
Like @code{sprintf}, but instead of passing a pointer to a buffer, you |
pass a pointer to a pointer. This function will compute the size of |
the buffer needed, allocate memory with @code{malloc}, and store a |
pointer to the allocated memory in @code{*@var{resptr}}. The value |
returned is the same as @code{sprintf} would return. If memory could |
not be allocated, minus one is returned and @code{NULL} is stored in |
@code{*@var{resptr}}. |
@end deftypefn |
*/ |
int |
asprintf (char **buf, const char *fmt, ...) |
{ |
int status; |
VA_OPEN (ap, fmt); |
VA_FIXEDARG (ap, char **, buf); |
VA_FIXEDARG (ap, const char *, fmt); |
status = vasprintf (buf, fmt, ap); |
VA_CLOSE (ap); |
return status; |
} |
/contrib/toolchain/binutils/libiberty/bcmp.c |
---|
0,0 → 1,27 |
/* bcmp |
This function is in the public domain. */ |
/* |
@deftypefn Supplemental int bcmp (char *@var{x}, char *@var{y}, int @var{count}) |
Compares the first @var{count} bytes of two areas of memory. Returns |
zero if they are the same, nonzero otherwise. Returns zero if |
@var{count} is zero. A nonzero result only indicates a difference, |
it does not indicate any sorting order (say, by having a positive |
result mean @var{x} sorts before @var{y}). |
@end deftypefn |
*/ |
#include <stddef.h> |
extern int memcmp(const void *, const void *, size_t); |
int |
bcmp (const void *s1, const void *s2, size_t count) |
{ |
return memcmp (s1, s2, count); |
} |
/contrib/toolchain/binutils/libiberty/bcopy.c |
---|
0,0 → 1,31 |
/* bcopy -- copy memory regions of arbitary length |
@deftypefn Supplemental void bcopy (char *@var{in}, char *@var{out}, int @var{length}) |
Copies @var{length} bytes from memory region @var{in} to region |
@var{out}. The use of @code{bcopy} is deprecated in new programs. |
@end deftypefn |
*/ |
#include <stddef.h> |
void |
bcopy (const void *src, void *dest, size_t len) |
{ |
if (dest < src) |
{ |
const char *firsts = (const char *) src; |
char *firstd = (char *) dest; |
while (len--) |
*firstd++ = *firsts++; |
} |
else |
{ |
const char *lasts = (const char *)src + (len-1); |
char *lastd = (char *)dest + (len-1); |
while (len--) |
*lastd-- = *lasts--; |
} |
} |
/contrib/toolchain/binutils/libiberty/bzero.c |
---|
0,0 → 1,23 |
/* Portable version of bzero for systems without it. |
This function is in the public domain. */ |
/* |
@deftypefn Supplemental void bzero (char *@var{mem}, int @var{count}) |
Zeros @var{count} bytes starting at @var{mem}. Use of this function |
is deprecated in favor of @code{memset}. |
@end deftypefn |
*/ |
#include <stddef.h> |
extern void *memset(void *, int, size_t); |
void |
bzero (void *to, size_t count) |
{ |
memset (to, 0, count); |
} |
/contrib/toolchain/binutils/libiberty/choose-temp.c |
---|
0,0 → 1,75 |
/* Utility to pick a temporary filename prefix. |
Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If not, |
write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <stdio.h> /* May get P_tmpdir. */ |
#include <sys/types.h> |
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#include "libiberty.h" |
extern char *choose_tmpdir (void); |
/* Name of temporary file. |
mktemp requires 6 trailing X's. */ |
#define TEMP_FILE "ccXXXXXX" |
#define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1) |
/* |
@deftypefn Extension char* choose_temp_base (void) |
Return a prefix for temporary file names or @code{NULL} if unable to |
find one. The current directory is chosen if all else fails so the |
program is exited if a temporary directory can't be found (@code{mktemp} |
fails). The buffer for the result is obtained with @code{xmalloc}. |
This function is provided for backwards compatibility only. Its use is |
not recommended. |
@end deftypefn |
*/ |
char * |
choose_temp_base (void) |
{ |
const char *base = choose_tmpdir (); |
char *temp_filename; |
int len; |
len = strlen (base); |
temp_filename = XNEWVEC (char, len + TEMP_FILE_LEN + 1); |
strcpy (temp_filename, base); |
strcpy (temp_filename + len, TEMP_FILE); |
if (mktemp (temp_filename) == 0) |
abort (); |
return temp_filename; |
} |
/contrib/toolchain/binutils/libiberty/concat.c |
---|
0,0 → 1,234 |
/* Concatenate variable number of strings. |
Copyright (C) 1991, 1994, 2001, 2011 Free Software Foundation, Inc. |
Written by Fred Fish @ Cygnus Support |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Extension char* concat (const char *@var{s1}, const char *@var{s2}, @ |
@dots{}, @code{NULL}) |
Concatenate zero or more of strings and return the result in freshly |
@code{xmalloc}ed memory. Returns @code{NULL} if insufficient memory is |
available. The argument list is terminated by the first @code{NULL} |
pointer encountered. Pointers to empty strings are ignored. |
@end deftypefn |
NOTES |
This function uses xmalloc() which is expected to be a front end |
function to malloc() that deals with low memory situations. In |
typical use, if malloc() returns NULL then xmalloc() diverts to an |
error handler routine which never returns, and thus xmalloc will |
never return a NULL pointer. If the client application wishes to |
deal with low memory situations itself, it should supply an xmalloc |
that just directly invokes malloc and blindly returns whatever |
malloc returns. |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#include <sys/types.h> /* size_t */ |
#include <stdarg.h> |
# if HAVE_STRING_H |
# include <string.h> |
# else |
# if HAVE_STRINGS_H |
# include <strings.h> |
# endif |
# endif |
#if HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
static inline unsigned long vconcat_length (const char *, va_list); |
static inline unsigned long |
vconcat_length (const char *first, va_list args) |
{ |
unsigned long length = 0; |
const char *arg; |
for (arg = first; arg ; arg = va_arg (args, const char *)) |
length += strlen (arg); |
return length; |
} |
static inline char * |
vconcat_copy (char *dst, const char *first, va_list args) |
{ |
char *end = dst; |
const char *arg; |
for (arg = first; arg ; arg = va_arg (args, const char *)) |
{ |
unsigned long length = strlen (arg); |
memcpy (end, arg, length); |
end += length; |
} |
*end = '\000'; |
return dst; |
} |
/* @undocumented concat_length */ |
unsigned long |
concat_length (const char *first, ...) |
{ |
unsigned long length; |
VA_OPEN (args, first); |
VA_FIXEDARG (args, const char *, first); |
length = vconcat_length (first, args); |
VA_CLOSE (args); |
return length; |
} |
/* @undocumented concat_copy */ |
char * |
concat_copy (char *dst, const char *first, ...) |
{ |
char *save_dst; |
VA_OPEN (args, first); |
VA_FIXEDARG (args, char *, dst); |
VA_FIXEDARG (args, const char *, first); |
vconcat_copy (dst, first, args); |
save_dst = dst; /* With K&R C, dst goes out of scope here. */ |
VA_CLOSE (args); |
return save_dst; |
} |
#ifdef __cplusplus |
extern "C" { |
#endif /* __cplusplus */ |
char *libiberty_concat_ptr; |
#ifdef __cplusplus |
} |
#endif /* __cplusplus */ |
/* @undocumented concat_copy2 */ |
char * |
concat_copy2 (const char *first, ...) |
{ |
VA_OPEN (args, first); |
VA_FIXEDARG (args, const char *, first); |
vconcat_copy (libiberty_concat_ptr, first, args); |
VA_CLOSE (args); |
return libiberty_concat_ptr; |
} |
char * |
concat (const char *first, ...) |
{ |
char *newstr; |
/* First compute the size of the result and get sufficient memory. */ |
VA_OPEN (args, first); |
VA_FIXEDARG (args, const char *, first); |
newstr = XNEWVEC (char, vconcat_length (first, args) + 1); |
VA_CLOSE (args); |
/* Now copy the individual pieces to the result string. */ |
VA_OPEN (args, first); |
VA_FIXEDARG (args, const char *, first); |
vconcat_copy (newstr, first, args); |
VA_CLOSE (args); |
return newstr; |
} |
/* |
@deftypefn Extension char* reconcat (char *@var{optr}, const char *@var{s1}, @ |
@dots{}, @code{NULL}) |
Same as @code{concat}, except that if @var{optr} is not @code{NULL} it |
is freed after the string is created. This is intended to be useful |
when you're extending an existing string or building up a string in a |
loop: |
@example |
str = reconcat (str, "pre-", str, NULL); |
@end example |
@end deftypefn |
*/ |
char * |
reconcat (char *optr, const char *first, ...) |
{ |
char *newstr; |
/* First compute the size of the result and get sufficient memory. */ |
VA_OPEN (args, first); |
VA_FIXEDARG (args, char *, optr); |
VA_FIXEDARG (args, const char *, first); |
newstr = XNEWVEC (char, vconcat_length (first, args) + 1); |
VA_CLOSE (args); |
/* Now copy the individual pieces to the result string. */ |
VA_OPEN (args, first); |
VA_FIXEDARG (args, char *, optr); |
VA_FIXEDARG (args, const char *, first); |
vconcat_copy (newstr, first, args); |
if (optr) /* Done before VA_CLOSE so optr stays in scope for K&R C. */ |
free (optr); |
VA_CLOSE (args); |
return newstr; |
} |
#ifdef MAIN |
#define NULLP (char *)0 |
/* Simple little test driver. */ |
#include <stdio.h> |
int |
main (void) |
{ |
printf ("\"\" = \"%s\"\n", concat (NULLP)); |
printf ("\"a\" = \"%s\"\n", concat ("a", NULLP)); |
printf ("\"ab\" = \"%s\"\n", concat ("a", "b", NULLP)); |
printf ("\"abc\" = \"%s\"\n", concat ("a", "b", "c", NULLP)); |
printf ("\"abcd\" = \"%s\"\n", concat ("ab", "cd", NULLP)); |
printf ("\"abcde\" = \"%s\"\n", concat ("ab", "c", "de", NULLP)); |
printf ("\"abcdef\" = \"%s\"\n", concat ("", "a", "", "bcd", "ef", NULLP)); |
return 0; |
} |
#endif |
/contrib/toolchain/binutils/libiberty/config.h |
---|
0,0 → 1,500 |
/* config.h. Generated from config.in by configure. */ |
/* config.in. Generated from configure.ac by autoheader. */ |
/* Define if building universal (internal helper macro) */ |
/* #undef AC_APPLE_UNIVERSAL_BUILD */ |
/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. |
This function is required for alloca.c support on those systems. */ |
/* #undef CRAY_STACKSEG_END */ |
/* Define to 1 if you have the <alloca.h> header file. */ |
/* #undef HAVE_ALLOCA_H */ |
/* Define to 1 if you have the `asprintf' function. */ |
/* #undef HAVE_ASPRINTF */ |
/* Define to 1 if you have the `atexit' function. */ |
#define HAVE_ATEXIT 1 |
/* Define to 1 if you have the `basename' function. */ |
#define HAVE_BASENAME 1 |
/* Define to 1 if you have the `bcmp' function. */ |
/* #undef HAVE_BCMP */ |
/* Define to 1 if you have the `bcopy' function. */ |
/* #undef HAVE_BCOPY */ |
/* Define to 1 if you have the `bsearch' function. */ |
#define HAVE_BSEARCH 1 |
/* Define to 1 if you have the `bzero' function. */ |
/* #undef HAVE_BZERO */ |
/* Define to 1 if you have the `calloc' function. */ |
#define HAVE_CALLOC 1 |
/* Define to 1 if you have the `canonicalize_file_name' function. */ |
/* #undef HAVE_CANONICALIZE_FILE_NAME */ |
/* Define to 1 if you have the `clock' function. */ |
#define HAVE_CLOCK 1 |
/* Define to 1 if you have the declaration of `asprintf', and to 0 if you |
don't. */ |
#define HAVE_DECL_ASPRINTF 0 |
/* Define to 1 if you have the declaration of `basename(char *)', and to 0 if |
you don't. */ |
#define HAVE_DECL_BASENAME 0 |
/* Define to 1 if you have the declaration of `calloc', and to 0 if you don't. |
*/ |
#define HAVE_DECL_CALLOC 1 |
/* Define to 1 if you have the declaration of `ffs', and to 0 if you don't. */ |
#define HAVE_DECL_FFS 0 |
/* Define to 1 if you have the declaration of `getenv', and to 0 if you don't. |
*/ |
#define HAVE_DECL_GETENV 1 |
/* Define to 1 if you have the declaration of `getopt', and to 0 if you don't. |
*/ |
#define HAVE_DECL_GETOPT 1 |
/* Define to 1 if you have the declaration of `malloc', and to 0 if you don't. |
*/ |
#define HAVE_DECL_MALLOC 1 |
/* Define to 1 if you have the declaration of `realloc', and to 0 if you |
don't. */ |
#define HAVE_DECL_REALLOC 1 |
/* Define to 1 if you have the declaration of `sbrk', and to 0 if you don't. |
*/ |
#define HAVE_DECL_SBRK 0 |
/* Define to 1 if you have the declaration of `snprintf', and to 0 if you |
don't. */ |
#define HAVE_DECL_SNPRINTF 1 |
/* Define to 1 if you have the declaration of `strverscmp', and to 0 if you |
don't. */ |
#define HAVE_DECL_STRVERSCMP 0 |
/* Define to 1 if you have the declaration of `vasprintf', and to 0 if you |
don't. */ |
#define HAVE_DECL_VASPRINTF 0 |
/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you |
don't. */ |
#define HAVE_DECL_VSNPRINTF 1 |
/* Define to 1 if you have the `dup3' function. */ |
/* #undef HAVE_DUP3 */ |
/* Define to 1 if you have the <fcntl.h> header file. */ |
#define HAVE_FCNTL_H 1 |
/* Define to 1 if you have the `ffs' function. */ |
/* #undef HAVE_FFS */ |
/* Define to 1 if you have the `fork' function. */ |
/* #undef HAVE_FORK */ |
/* Define to 1 if you have the `getcwd' function. */ |
#define HAVE_GETCWD 1 |
/* Define to 1 if you have the `getpagesize' function. */ |
#define HAVE_GETPAGESIZE 1 |
/* Define to 1 if you have the `getrlimit' function. */ |
/* #undef HAVE_GETRLIMIT */ |
/* Define to 1 if you have the `getrusage' function. */ |
/* #undef HAVE_GETRUSAGE */ |
/* Define to 1 if you have the `getsysinfo' function. */ |
/* #undef HAVE_GETSYSINFO */ |
/* Define to 1 if you have the `gettimeofday' function. */ |
#define HAVE_GETTIMEOFDAY 1 |
/* Define to 1 if you have the `index' function. */ |
/* #undef HAVE_INDEX */ |
/* Define to 1 if you have the `insque' function. */ |
/* #undef HAVE_INSQUE */ |
/* Define to 1 if the system has the type `intptr_t'. */ |
#define HAVE_INTPTR_T 1 |
/* Define to 1 if you have the <inttypes.h> header file. */ |
#define HAVE_INTTYPES_H 1 |
/* Define to 1 if you have the <limits.h> header file. */ |
#define HAVE_LIMITS_H 1 |
/* Define to 1 if you have the <machine/hal_sysinfo.h> header file. */ |
/* #undef HAVE_MACHINE_HAL_SYSINFO_H */ |
/* Define to 1 if you have the <malloc.h> header file. */ |
#define HAVE_MALLOC_H 1 |
/* Define to 1 if you have the `memchr' function. */ |
#define HAVE_MEMCHR 1 |
/* Define to 1 if you have the `memcmp' function. */ |
#define HAVE_MEMCMP 1 |
/* Define to 1 if you have the `memcpy' function. */ |
#define HAVE_MEMCPY 1 |
/* Define to 1 if you have the `memmem' function. */ |
/* #undef HAVE_MEMMEM */ |
/* Define to 1 if you have the `memmove' function. */ |
#define HAVE_MEMMOVE 1 |
/* Define to 1 if you have the <memory.h> header file. */ |
#define HAVE_MEMORY_H 1 |
/* Define to 1 if you have the `memset' function. */ |
#define HAVE_MEMSET 1 |
/* Define to 1 if you have the `mkstemps' function. */ |
/* #undef HAVE_MKSTEMPS */ |
/* Define to 1 if you have a working `mmap' system call. */ |
/* #undef HAVE_MMAP */ |
/* Define to 1 if you have the `on_exit' function. */ |
/* #undef HAVE_ON_EXIT */ |
/* Define to 1 if you have the <process.h> header file. */ |
#define HAVE_PROCESS_H 1 |
/* Define to 1 if you have the `psignal' function. */ |
/* #undef HAVE_PSIGNAL */ |
/* Define to 1 if you have the `pstat_getdynamic' function. */ |
/* #undef HAVE_PSTAT_GETDYNAMIC */ |
/* Define to 1 if you have the `pstat_getstatic' function. */ |
/* #undef HAVE_PSTAT_GETSTATIC */ |
/* Define to 1 if you have the `putenv' function. */ |
#define HAVE_PUTENV 1 |
/* Define to 1 if you have the `random' function. */ |
/* #undef HAVE_RANDOM */ |
/* Define to 1 if you have the `realpath' function. */ |
/* #undef HAVE_REALPATH */ |
/* Define to 1 if you have the `rename' function. */ |
#define HAVE_RENAME 1 |
/* Define to 1 if you have the `rindex' function. */ |
/* #undef HAVE_RINDEX */ |
/* Define to 1 if you have the `sbrk' function. */ |
/* #undef HAVE_SBRK */ |
/* Define to 1 if you have the `setenv' function. */ |
/* #undef HAVE_SETENV */ |
/* Define to 1 if you have the `setproctitle' function. */ |
/* #undef HAVE_SETPROCTITLE */ |
/* Define to 1 if you have the `setrlimit' function. */ |
/* #undef HAVE_SETRLIMIT */ |
/* Define to 1 if you have the `sigsetmask' function. */ |
/* #undef HAVE_SIGSETMASK */ |
/* Define to 1 if you have the `snprintf' function. */ |
#define HAVE_SNPRINTF 1 |
/* Define to 1 if you have the `spawnve' function. */ |
#define HAVE_SPAWNVE 1 |
/* Define to 1 if you have the `spawnvpe' function. */ |
#define HAVE_SPAWNVPE 1 |
/* Define to 1 if you have the <stdint.h> header file. */ |
#define HAVE_STDINT_H 1 |
/* Define to 1 if you have the <stdio_ext.h> header file. */ |
/* #undef HAVE_STDIO_EXT_H */ |
/* Define to 1 if you have the <stdlib.h> header file. */ |
#define HAVE_STDLIB_H 1 |
/* Define to 1 if you have the `stpcpy' function. */ |
/* #undef HAVE_STPCPY */ |
/* Define to 1 if you have the `stpncpy' function. */ |
/* #undef HAVE_STPNCPY */ |
/* Define to 1 if you have the `strcasecmp' function. */ |
/* #undef HAVE_STRCASECMP */ |
/* Define to 1 if you have the `strchr' function. */ |
#define HAVE_STRCHR 1 |
/* Define to 1 if you have the `strdup' function. */ |
#define HAVE_STRDUP 1 |
/* Define to 1 if you have the `strerror' function. */ |
#define HAVE_STRERROR 1 |
/* Define to 1 if you have the <strings.h> header file. */ |
#define HAVE_STRINGS_H 1 |
/* Define to 1 if you have the <string.h> header file. */ |
#define HAVE_STRING_H 1 |
/* Define to 1 if you have the `strncasecmp' function. */ |
/* #undef HAVE_STRNCASECMP */ |
/* Define to 1 if you have the `strndup' function. */ |
/* #undef HAVE_STRNDUP */ |
/* Define to 1 if you have the `strnlen' function. */ |
/* #undef HAVE_STRNLEN */ |
/* Define to 1 if you have the `strrchr' function. */ |
#define HAVE_STRRCHR 1 |
/* Define to 1 if you have the `strsignal' function. */ |
/* #undef HAVE_STRSIGNAL */ |
/* Define to 1 if you have the `strstr' function. */ |
#define HAVE_STRSTR 1 |
/* Define to 1 if you have the `strtod' function. */ |
#define HAVE_STRTOD 1 |
/* Define to 1 if you have the `strtol' function. */ |
#define HAVE_STRTOL 1 |
/* Define to 1 if you have the `strtoul' function. */ |
#define HAVE_STRTOUL 1 |
/* Define to 1 if you have the `strverscmp' function. */ |
/* #undef HAVE_STRVERSCMP */ |
/* Define to 1 if you have the `sysconf' function. */ |
/* #undef HAVE_SYSCONF */ |
/* Define to 1 if you have the `sysctl' function. */ |
/* #undef HAVE_SYSCTL */ |
/* Define to 1 if you have the `sysmp' function. */ |
/* #undef HAVE_SYSMP */ |
/* Define if you have the sys_errlist variable. */ |
#define HAVE_SYS_ERRLIST 1 |
/* Define to 1 if you have the <sys/file.h> header file. */ |
#define HAVE_SYS_FILE_H 1 |
/* Define to 1 if you have the <sys/mman.h> header file. */ |
/* #undef HAVE_SYS_MMAN_H */ |
/* Define if you have the sys_nerr variable. */ |
#define HAVE_SYS_NERR 1 |
/* Define to 1 if you have the <sys/param.h> header file. */ |
#define HAVE_SYS_PARAM_H 1 |
/* Define to 1 if you have the <sys/prctl.h> header file. */ |
/* #undef HAVE_SYS_PRCTL_H */ |
/* Define to 1 if you have the <sys/pstat.h> header file. */ |
/* #undef HAVE_SYS_PSTAT_H */ |
/* Define to 1 if you have the <sys/resource.h> header file. */ |
/* #undef HAVE_SYS_RESOURCE_H */ |
/* Define if you have the sys_siglist variable. */ |
/* #undef HAVE_SYS_SIGLIST */ |
/* Define to 1 if you have the <sys/stat.h> header file. */ |
#define HAVE_SYS_STAT_H 1 |
/* Define to 1 if you have the <sys/sysctl.h> header file. */ |
/* #undef HAVE_SYS_SYSCTL_H */ |
/* Define to 1 if you have the <sys/sysinfo.h> header file. */ |
/* #undef HAVE_SYS_SYSINFO_H */ |
/* Define to 1 if you have the <sys/sysmp.h> header file. */ |
/* #undef HAVE_SYS_SYSMP_H */ |
/* Define to 1 if you have the <sys/systemcfg.h> header file. */ |
/* #undef HAVE_SYS_SYSTEMCFG_H */ |
/* Define to 1 if you have the <sys/table.h> header file. */ |
/* #undef HAVE_SYS_TABLE_H */ |
/* Define to 1 if you have the <sys/time.h> header file. */ |
#define HAVE_SYS_TIME_H 1 |
/* Define to 1 if you have the <sys/types.h> header file. */ |
#define HAVE_SYS_TYPES_H 1 |
/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */ |
/* #undef HAVE_SYS_WAIT_H */ |
/* Define to 1 if you have the `table' function. */ |
/* #undef HAVE_TABLE */ |
/* Define to 1 if you have the `times' function. */ |
/* #undef HAVE_TIMES */ |
/* Define to 1 if you have the <time.h> header file. */ |
#define HAVE_TIME_H 1 |
/* Define to 1 if you have the `tmpnam' function. */ |
#define HAVE_TMPNAM 1 |
/* Define if you have the \`uintptr_t' type. */ |
#define HAVE_UINTPTR_T 1 |
/* Define to 1 if you have the <unistd.h> header file. */ |
#define HAVE_UNISTD_H 1 |
/* Define to 1 if you have the `vasprintf' function. */ |
/* #undef HAVE_VASPRINTF */ |
/* Define to 1 if you have the `vfork' function. */ |
/* #undef HAVE_VFORK */ |
/* Define to 1 if you have the <vfork.h> header file. */ |
/* #undef HAVE_VFORK_H */ |
/* Define to 1 if you have the `vfprintf' function. */ |
#define HAVE_VFPRINTF 1 |
/* Define to 1 if you have the `vprintf' function. */ |
#define HAVE_VPRINTF 1 |
/* Define to 1 if you have the `vsprintf' function. */ |
#define HAVE_VSPRINTF 1 |
/* Define to 1 if you have the `wait3' function. */ |
/* #undef HAVE_WAIT3 */ |
/* Define to 1 if you have the `wait4' function. */ |
/* #undef HAVE_WAIT4 */ |
/* Define to 1 if you have the `waitpid' function. */ |
/* #undef HAVE_WAITPID */ |
/* Define to 1 if `fork' works. */ |
/* #undef HAVE_WORKING_FORK */ |
/* Define to 1 if `vfork' works. */ |
/* #undef HAVE_WORKING_VFORK */ |
/* Define to 1 if you have the `_doprnt' function. */ |
/* #undef HAVE__DOPRNT */ |
/* Define if you have the _system_configuration variable. */ |
/* #undef HAVE__SYSTEM_CONFIGURATION */ |
/* Define to 1 if you have the `__fsetlocking' function. */ |
/* #undef HAVE___FSETLOCKING */ |
/* Define if canonicalize_file_name is not declared in system header files. */ |
#define NEED_DECLARATION_CANONICALIZE_FILE_NAME 1 |
/* Define if errno must be declared even when <errno.h> is included. */ |
/* #undef NEED_DECLARATION_ERRNO */ |
/* Define to 1 if your C compiler doesn't accept -c and -o together. */ |
/* #undef NO_MINUS_C_MINUS_O */ |
/* Define to the address where bug reports for this package should be sent. */ |
#define PACKAGE_BUGREPORT "" |
/* Define to the full name of this package. */ |
#define PACKAGE_NAME "" |
/* Define to the full name and version of this package. */ |
#define PACKAGE_STRING "" |
/* Define to the one symbol short name of this package. */ |
#define PACKAGE_TARNAME "" |
/* Define to the home page for this package. */ |
#define PACKAGE_URL "" |
/* Define to the version of this package. */ |
#define PACKAGE_VERSION "" |
/* The size of `int', as computed by sizeof. */ |
#define SIZEOF_INT 4 |
/* Define if you know the direction of stack growth for your system; otherwise |
it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows |
toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses |
STACK_DIRECTION = 0 => direction of growth unknown */ |
#define STACK_DIRECTION -1 |
/* Define to 1 if you have the ANSI C header files. */ |
#define STDC_HEADERS 1 |
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ |
#define TIME_WITH_SYS_TIME 1 |
/* Define to an unsigned 64-bit type available in the compiler. */ |
#define UNSIGNED_64BIT_TYPE uint64_t |
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most |
significant byte first (like Motorola and SPARC, unlike Intel). */ |
#if defined AC_APPLE_UNIVERSAL_BUILD |
# if defined __BIG_ENDIAN__ |
# define WORDS_BIGENDIAN 1 |
# endif |
#else |
# ifndef WORDS_BIGENDIAN |
/* # undef WORDS_BIGENDIAN */ |
# endif |
#endif |
/* Number of bits in a file offset, on hosts where this is settable. */ |
/* #undef _FILE_OFFSET_BITS */ |
/* Define for large files, on AIX-style hosts. */ |
/* #undef _LARGE_FILES */ |
/* Define to empty if `const' does not conform to ANSI C. */ |
/* #undef const */ |
/* Define to `__inline__' or `__inline' if that's what the C compiler |
calls it, or to nothing if 'inline' is not supported under any name. */ |
#ifndef __cplusplus |
/* #undef inline */ |
#endif |
/* Define to the type of a signed integer type wide enough to hold a pointer, |
if such a type exists, and if the system does not define it. */ |
/* #undef intptr_t */ |
/* Define to `int' if <sys/types.h> does not define. */ |
/* #undef pid_t */ |
/* Define to `int' if <sys/types.h> does not define. */ |
/* #undef ssize_t */ |
/* Define to the type of an unsigned integer type wide enough to hold a |
pointer, if such a type exists, and if the system does not define it. */ |
/* #undef uintptr_t */ |
/* Define as `fork' if `vfork' does not work. */ |
#define vfork fork |
/contrib/toolchain/binutils/libiberty/cp-demangle.c |
---|
0,0 → 1,5937 |
/* Demangler for g++ V3 ABI. |
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 |
Free Software Foundation, Inc. |
Written by Ian Lance Taylor <ian@wasabisystems.com>. |
This file is part of the libiberty library, which is part of GCC. |
This file 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 of the License, or |
(at your option) any later version. |
In addition to the permissions in the GNU General Public License, the |
Free Software Foundation gives you unlimited permission to link the |
compiled version of this file into combinations with other programs, |
and to distribute those combinations without any restriction coming |
from the use of this file. (The General Public License restrictions |
do apply in other respects; for example, they cover modification of |
the file, and distribution when not linked into a combined |
executable.) |
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
*/ |
/* This code implements a demangler for the g++ V3 ABI. The ABI is |
described on this web page: |
http://www.codesourcery.com/cxx-abi/abi.html#mangling |
This code was written while looking at the demangler written by |
Alex Samuel <samuel@codesourcery.com>. |
This code first pulls the mangled name apart into a list of |
components, and then walks the list generating the demangled |
name. |
This file will normally define the following functions, q.v.: |
char *cplus_demangle_v3(const char *mangled, int options) |
char *java_demangle_v3(const char *mangled) |
int cplus_demangle_v3_callback(const char *mangled, int options, |
demangle_callbackref callback) |
int java_demangle_v3_callback(const char *mangled, |
demangle_callbackref callback) |
enum gnu_v3_ctor_kinds is_gnu_v3_mangled_ctor (const char *name) |
enum gnu_v3_dtor_kinds is_gnu_v3_mangled_dtor (const char *name) |
Also, the interface to the component list is public, and defined in |
demangle.h. The interface consists of these types, which are |
defined in demangle.h: |
enum demangle_component_type |
struct demangle_component |
demangle_callbackref |
and these functions defined in this file: |
cplus_demangle_fill_name |
cplus_demangle_fill_extended_operator |
cplus_demangle_fill_ctor |
cplus_demangle_fill_dtor |
cplus_demangle_print |
cplus_demangle_print_callback |
and other functions defined in the file cp-demint.c. |
This file also defines some other functions and variables which are |
only to be used by the file cp-demint.c. |
Preprocessor macros you can define while compiling this file: |
IN_LIBGCC2 |
If defined, this file defines the following functions, q.v.: |
char *__cxa_demangle (const char *mangled, char *buf, size_t *len, |
int *status) |
int __gcclibcxx_demangle_callback (const char *, |
void (*) |
(const char *, size_t, void *), |
void *) |
instead of cplus_demangle_v3[_callback]() and |
java_demangle_v3[_callback](). |
IN_GLIBCPP_V3 |
If defined, this file defines only __cxa_demangle() and |
__gcclibcxx_demangle_callback(), and no other publically visible |
functions or variables. |
STANDALONE_DEMANGLER |
If defined, this file defines a main() function which demangles |
any arguments, or, if none, demangles stdin. |
CP_DEMANGLE_DEBUG |
If defined, turns on debugging mode, which prints information on |
stdout about the mangled string. This is not generally useful. |
*/ |
#if defined (_AIX) && !defined (__GNUC__) |
#pragma alloca |
#endif |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <stdio.h> |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifdef HAVE_ALLOCA_H |
# include <alloca.h> |
#else |
# ifndef alloca |
# ifdef __GNUC__ |
# define alloca __builtin_alloca |
# else |
extern char *alloca (); |
# endif /* __GNUC__ */ |
# endif /* alloca */ |
#endif /* HAVE_ALLOCA_H */ |
#include "ansidecl.h" |
#include "libiberty.h" |
#include "demangle.h" |
#include "cp-demangle.h" |
/* If IN_GLIBCPP_V3 is defined, some functions are made static. We |
also rename them via #define to avoid compiler errors when the |
static definition conflicts with the extern declaration in a header |
file. */ |
#ifdef IN_GLIBCPP_V3 |
#define CP_STATIC_IF_GLIBCPP_V3 static |
#define cplus_demangle_fill_name d_fill_name |
static int d_fill_name (struct demangle_component *, const char *, int); |
#define cplus_demangle_fill_extended_operator d_fill_extended_operator |
static int |
d_fill_extended_operator (struct demangle_component *, int, |
struct demangle_component *); |
#define cplus_demangle_fill_ctor d_fill_ctor |
static int |
d_fill_ctor (struct demangle_component *, enum gnu_v3_ctor_kinds, |
struct demangle_component *); |
#define cplus_demangle_fill_dtor d_fill_dtor |
static int |
d_fill_dtor (struct demangle_component *, enum gnu_v3_dtor_kinds, |
struct demangle_component *); |
#define cplus_demangle_mangled_name d_mangled_name |
static struct demangle_component *d_mangled_name (struct d_info *, int); |
#define cplus_demangle_type d_type |
static struct demangle_component *d_type (struct d_info *); |
#define cplus_demangle_print d_print |
static char *d_print (int, const struct demangle_component *, int, size_t *); |
#define cplus_demangle_print_callback d_print_callback |
static int d_print_callback (int, const struct demangle_component *, |
demangle_callbackref, void *); |
#define cplus_demangle_init_info d_init_info |
static void d_init_info (const char *, int, size_t, struct d_info *); |
#else /* ! defined(IN_GLIBCPP_V3) */ |
#define CP_STATIC_IF_GLIBCPP_V3 |
#endif /* ! defined(IN_GLIBCPP_V3) */ |
/* See if the compiler supports dynamic arrays. */ |
#ifdef __GNUC__ |
#define CP_DYNAMIC_ARRAYS |
#else |
#ifdef __STDC__ |
#ifdef __STDC_VERSION__ |
#if __STDC_VERSION__ >= 199901L |
#define CP_DYNAMIC_ARRAYS |
#endif /* __STDC__VERSION >= 199901L */ |
#endif /* defined (__STDC_VERSION__) */ |
#endif /* defined (__STDC__) */ |
#endif /* ! defined (__GNUC__) */ |
/* We avoid pulling in the ctype tables, to prevent pulling in |
additional unresolved symbols when this code is used in a library. |
FIXME: Is this really a valid reason? This comes from the original |
V3 demangler code. |
As of this writing this file has the following undefined references |
when compiled with -DIN_GLIBCPP_V3: realloc, free, memcpy, strcpy, |
strcat, strlen. */ |
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9') |
#define IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z') |
#define IS_LOWER(c) ((c) >= 'a' && (c) <= 'z') |
/* The prefix prepended by GCC to an identifier represnting the |
anonymous namespace. */ |
#define ANONYMOUS_NAMESPACE_PREFIX "_GLOBAL_" |
#define ANONYMOUS_NAMESPACE_PREFIX_LEN \ |
(sizeof (ANONYMOUS_NAMESPACE_PREFIX) - 1) |
/* Information we keep for the standard substitutions. */ |
struct d_standard_sub_info |
{ |
/* The code for this substitution. */ |
char code; |
/* The simple string it expands to. */ |
const char *simple_expansion; |
/* The length of the simple expansion. */ |
int simple_len; |
/* The results of a full, verbose, expansion. This is used when |
qualifying a constructor/destructor, or when in verbose mode. */ |
const char *full_expansion; |
/* The length of the full expansion. */ |
int full_len; |
/* What to set the last_name field of d_info to; NULL if we should |
not set it. This is only relevant when qualifying a |
constructor/destructor. */ |
const char *set_last_name; |
/* The length of set_last_name. */ |
int set_last_name_len; |
}; |
/* Accessors for subtrees of struct demangle_component. */ |
#define d_left(dc) ((dc)->u.s_binary.left) |
#define d_right(dc) ((dc)->u.s_binary.right) |
/* A list of templates. This is used while printing. */ |
struct d_print_template |
{ |
/* Next template on the list. */ |
struct d_print_template *next; |
/* This template. */ |
const struct demangle_component *template_decl; |
}; |
/* A list of type modifiers. This is used while printing. */ |
struct d_print_mod |
{ |
/* Next modifier on the list. These are in the reverse of the order |
in which they appeared in the mangled string. */ |
struct d_print_mod *next; |
/* The modifier. */ |
const struct demangle_component *mod; |
/* Whether this modifier was printed. */ |
int printed; |
/* The list of templates which applies to this modifier. */ |
struct d_print_template *templates; |
}; |
/* We use these structures to hold information during printing. */ |
struct d_growable_string |
{ |
/* Buffer holding the result. */ |
char *buf; |
/* Current length of data in buffer. */ |
size_t len; |
/* Allocated size of buffer. */ |
size_t alc; |
/* Set to 1 if we had a memory allocation failure. */ |
int allocation_failure; |
}; |
enum { D_PRINT_BUFFER_LENGTH = 256 }; |
struct d_print_info |
{ |
/* Fixed-length allocated buffer for demangled data, flushed to the |
callback with a NUL termination once full. */ |
char buf[D_PRINT_BUFFER_LENGTH]; |
/* Current length of data in buffer. */ |
size_t len; |
/* The last character printed, saved individually so that it survives |
any buffer flush. */ |
char last_char; |
/* Callback function to handle demangled buffer flush. */ |
demangle_callbackref callback; |
/* Opaque callback argument. */ |
void *opaque; |
/* The current list of templates, if any. */ |
struct d_print_template *templates; |
/* The current list of modifiers (e.g., pointer, reference, etc.), |
if any. */ |
struct d_print_mod *modifiers; |
/* Set to 1 if we saw a demangling error. */ |
int demangle_failure; |
/* The current index into any template argument packs we are using |
for printing. */ |
int pack_index; |
/* Number of d_print_flush calls so far. */ |
unsigned long int flush_count; |
}; |
#ifdef CP_DEMANGLE_DEBUG |
static void d_dump (struct demangle_component *, int); |
#endif |
static struct demangle_component * |
d_make_empty (struct d_info *); |
static struct demangle_component * |
d_make_comp (struct d_info *, enum demangle_component_type, |
struct demangle_component *, |
struct demangle_component *); |
static struct demangle_component * |
d_make_name (struct d_info *, const char *, int); |
static struct demangle_component * |
d_make_demangle_mangled_name (struct d_info *, const char *); |
static struct demangle_component * |
d_make_builtin_type (struct d_info *, |
const struct demangle_builtin_type_info *); |
static struct demangle_component * |
d_make_operator (struct d_info *, |
const struct demangle_operator_info *); |
static struct demangle_component * |
d_make_extended_operator (struct d_info *, int, |
struct demangle_component *); |
static struct demangle_component * |
d_make_ctor (struct d_info *, enum gnu_v3_ctor_kinds, |
struct demangle_component *); |
static struct demangle_component * |
d_make_dtor (struct d_info *, enum gnu_v3_dtor_kinds, |
struct demangle_component *); |
static struct demangle_component * |
d_make_template_param (struct d_info *, long); |
static struct demangle_component * |
d_make_sub (struct d_info *, const char *, int); |
static int |
has_return_type (struct demangle_component *); |
static int |
is_ctor_dtor_or_conversion (struct demangle_component *); |
static struct demangle_component *d_encoding (struct d_info *, int); |
static struct demangle_component *d_name (struct d_info *); |
static struct demangle_component *d_nested_name (struct d_info *); |
static struct demangle_component *d_prefix (struct d_info *); |
static struct demangle_component *d_unqualified_name (struct d_info *); |
static struct demangle_component *d_source_name (struct d_info *); |
static long d_number (struct d_info *); |
static struct demangle_component *d_identifier (struct d_info *, int); |
static struct demangle_component *d_operator_name (struct d_info *); |
static struct demangle_component *d_special_name (struct d_info *); |
static int d_call_offset (struct d_info *, int); |
static struct demangle_component *d_ctor_dtor_name (struct d_info *); |
static struct demangle_component ** |
d_cv_qualifiers (struct d_info *, struct demangle_component **, int); |
static struct demangle_component * |
d_ref_qualifier (struct d_info *, struct demangle_component *); |
static struct demangle_component * |
d_function_type (struct d_info *); |
static struct demangle_component * |
d_bare_function_type (struct d_info *, int); |
static struct demangle_component * |
d_class_enum_type (struct d_info *); |
static struct demangle_component *d_array_type (struct d_info *); |
static struct demangle_component *d_vector_type (struct d_info *); |
static struct demangle_component * |
d_pointer_to_member_type (struct d_info *); |
static struct demangle_component * |
d_template_param (struct d_info *); |
static struct demangle_component *d_template_args (struct d_info *); |
static struct demangle_component * |
d_template_arg (struct d_info *); |
static struct demangle_component *d_expression (struct d_info *); |
static struct demangle_component *d_expr_primary (struct d_info *); |
static struct demangle_component *d_local_name (struct d_info *); |
static int d_discriminator (struct d_info *); |
static struct demangle_component *d_lambda (struct d_info *); |
static struct demangle_component *d_unnamed_type (struct d_info *); |
static struct demangle_component * |
d_clone_suffix (struct d_info *, struct demangle_component *); |
static int |
d_add_substitution (struct d_info *, struct demangle_component *); |
static struct demangle_component *d_substitution (struct d_info *, int); |
static void d_growable_string_init (struct d_growable_string *, size_t); |
static inline void |
d_growable_string_resize (struct d_growable_string *, size_t); |
static inline void |
d_growable_string_append_buffer (struct d_growable_string *, |
const char *, size_t); |
static void |
d_growable_string_callback_adapter (const char *, size_t, void *); |
static void |
d_print_init (struct d_print_info *, demangle_callbackref, void *); |
static inline void d_print_error (struct d_print_info *); |
static inline int d_print_saw_error (struct d_print_info *); |
static inline void d_print_flush (struct d_print_info *); |
static inline void d_append_char (struct d_print_info *, char); |
static inline void d_append_buffer (struct d_print_info *, |
const char *, size_t); |
static inline void d_append_string (struct d_print_info *, const char *); |
static inline char d_last_char (struct d_print_info *); |
static void |
d_print_comp (struct d_print_info *, int, const struct demangle_component *); |
static void |
d_print_java_identifier (struct d_print_info *, const char *, int); |
static void |
d_print_mod_list (struct d_print_info *, int, struct d_print_mod *, int); |
static void |
d_print_mod (struct d_print_info *, int, const struct demangle_component *); |
static void |
d_print_function_type (struct d_print_info *, int, |
const struct demangle_component *, |
struct d_print_mod *); |
static void |
d_print_array_type (struct d_print_info *, int, |
const struct demangle_component *, |
struct d_print_mod *); |
static void |
d_print_expr_op (struct d_print_info *, int, const struct demangle_component *); |
static void |
d_print_cast (struct d_print_info *, int, const struct demangle_component *); |
static int d_demangle_callback (const char *, int, |
demangle_callbackref, void *); |
static char *d_demangle (const char *, int, size_t *); |
#ifdef CP_DEMANGLE_DEBUG |
static void |
d_dump (struct demangle_component *dc, int indent) |
{ |
int i; |
if (dc == NULL) |
{ |
if (indent == 0) |
printf ("failed demangling\n"); |
return; |
} |
for (i = 0; i < indent; ++i) |
putchar (' '); |
switch (dc->type) |
{ |
case DEMANGLE_COMPONENT_NAME: |
printf ("name '%.*s'\n", dc->u.s_name.len, dc->u.s_name.s); |
return; |
case DEMANGLE_COMPONENT_TAGGED_NAME: |
printf ("tagged name\n"); |
d_dump (dc->u.s_binary.left, indent + 2); |
d_dump (dc->u.s_binary.right, indent + 2); |
return; |
case DEMANGLE_COMPONENT_TEMPLATE_PARAM: |
printf ("template parameter %ld\n", dc->u.s_number.number); |
return; |
case DEMANGLE_COMPONENT_CTOR: |
printf ("constructor %d\n", (int) dc->u.s_ctor.kind); |
d_dump (dc->u.s_ctor.name, indent + 2); |
return; |
case DEMANGLE_COMPONENT_DTOR: |
printf ("destructor %d\n", (int) dc->u.s_dtor.kind); |
d_dump (dc->u.s_dtor.name, indent + 2); |
return; |
case DEMANGLE_COMPONENT_SUB_STD: |
printf ("standard substitution %s\n", dc->u.s_string.string); |
return; |
case DEMANGLE_COMPONENT_BUILTIN_TYPE: |
printf ("builtin type %s\n", dc->u.s_builtin.type->name); |
return; |
case DEMANGLE_COMPONENT_OPERATOR: |
printf ("operator %s\n", dc->u.s_operator.op->name); |
return; |
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: |
printf ("extended operator with %d args\n", |
dc->u.s_extended_operator.args); |
d_dump (dc->u.s_extended_operator.name, indent + 2); |
return; |
case DEMANGLE_COMPONENT_QUAL_NAME: |
printf ("qualified name\n"); |
break; |
case DEMANGLE_COMPONENT_LOCAL_NAME: |
printf ("local name\n"); |
break; |
case DEMANGLE_COMPONENT_TYPED_NAME: |
printf ("typed name\n"); |
break; |
case DEMANGLE_COMPONENT_TEMPLATE: |
printf ("template\n"); |
break; |
case DEMANGLE_COMPONENT_VTABLE: |
printf ("vtable\n"); |
break; |
case DEMANGLE_COMPONENT_VTT: |
printf ("VTT\n"); |
break; |
case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: |
printf ("construction vtable\n"); |
break; |
case DEMANGLE_COMPONENT_TYPEINFO: |
printf ("typeinfo\n"); |
break; |
case DEMANGLE_COMPONENT_TYPEINFO_NAME: |
printf ("typeinfo name\n"); |
break; |
case DEMANGLE_COMPONENT_TYPEINFO_FN: |
printf ("typeinfo function\n"); |
break; |
case DEMANGLE_COMPONENT_THUNK: |
printf ("thunk\n"); |
break; |
case DEMANGLE_COMPONENT_VIRTUAL_THUNK: |
printf ("virtual thunk\n"); |
break; |
case DEMANGLE_COMPONENT_COVARIANT_THUNK: |
printf ("covariant thunk\n"); |
break; |
case DEMANGLE_COMPONENT_JAVA_CLASS: |
printf ("java class\n"); |
break; |
case DEMANGLE_COMPONENT_GUARD: |
printf ("guard\n"); |
break; |
case DEMANGLE_COMPONENT_REFTEMP: |
printf ("reference temporary\n"); |
break; |
case DEMANGLE_COMPONENT_HIDDEN_ALIAS: |
printf ("hidden alias\n"); |
break; |
case DEMANGLE_COMPONENT_TRANSACTION_CLONE: |
printf ("transaction clone\n"); |
break; |
case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE: |
printf ("non-transaction clone\n"); |
break; |
case DEMANGLE_COMPONENT_RESTRICT: |
printf ("restrict\n"); |
break; |
case DEMANGLE_COMPONENT_VOLATILE: |
printf ("volatile\n"); |
break; |
case DEMANGLE_COMPONENT_CONST: |
printf ("const\n"); |
break; |
case DEMANGLE_COMPONENT_RESTRICT_THIS: |
printf ("restrict this\n"); |
break; |
case DEMANGLE_COMPONENT_VOLATILE_THIS: |
printf ("volatile this\n"); |
break; |
case DEMANGLE_COMPONENT_CONST_THIS: |
printf ("const this\n"); |
break; |
case DEMANGLE_COMPONENT_REFERENCE_THIS: |
printf ("reference this\n"); |
break; |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: |
printf ("rvalue reference this\n"); |
break; |
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: |
printf ("vendor type qualifier\n"); |
break; |
case DEMANGLE_COMPONENT_POINTER: |
printf ("pointer\n"); |
break; |
case DEMANGLE_COMPONENT_REFERENCE: |
printf ("reference\n"); |
break; |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE: |
printf ("rvalue reference\n"); |
break; |
case DEMANGLE_COMPONENT_COMPLEX: |
printf ("complex\n"); |
break; |
case DEMANGLE_COMPONENT_IMAGINARY: |
printf ("imaginary\n"); |
break; |
case DEMANGLE_COMPONENT_VENDOR_TYPE: |
printf ("vendor type\n"); |
break; |
case DEMANGLE_COMPONENT_FUNCTION_TYPE: |
printf ("function type\n"); |
break; |
case DEMANGLE_COMPONENT_ARRAY_TYPE: |
printf ("array type\n"); |
break; |
case DEMANGLE_COMPONENT_PTRMEM_TYPE: |
printf ("pointer to member type\n"); |
break; |
case DEMANGLE_COMPONENT_FIXED_TYPE: |
printf ("fixed-point type\n"); |
break; |
case DEMANGLE_COMPONENT_ARGLIST: |
printf ("argument list\n"); |
break; |
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: |
printf ("template argument list\n"); |
break; |
case DEMANGLE_COMPONENT_INITIALIZER_LIST: |
printf ("initializer list\n"); |
break; |
case DEMANGLE_COMPONENT_CAST: |
printf ("cast\n"); |
break; |
case DEMANGLE_COMPONENT_NULLARY: |
printf ("nullary operator\n"); |
break; |
case DEMANGLE_COMPONENT_UNARY: |
printf ("unary operator\n"); |
break; |
case DEMANGLE_COMPONENT_BINARY: |
printf ("binary operator\n"); |
break; |
case DEMANGLE_COMPONENT_BINARY_ARGS: |
printf ("binary operator arguments\n"); |
break; |
case DEMANGLE_COMPONENT_TRINARY: |
printf ("trinary operator\n"); |
break; |
case DEMANGLE_COMPONENT_TRINARY_ARG1: |
printf ("trinary operator arguments 1\n"); |
break; |
case DEMANGLE_COMPONENT_TRINARY_ARG2: |
printf ("trinary operator arguments 1\n"); |
break; |
case DEMANGLE_COMPONENT_LITERAL: |
printf ("literal\n"); |
break; |
case DEMANGLE_COMPONENT_LITERAL_NEG: |
printf ("negative literal\n"); |
break; |
case DEMANGLE_COMPONENT_JAVA_RESOURCE: |
printf ("java resource\n"); |
break; |
case DEMANGLE_COMPONENT_COMPOUND_NAME: |
printf ("compound name\n"); |
break; |
case DEMANGLE_COMPONENT_CHARACTER: |
printf ("character '%c'\n", dc->u.s_character.character); |
return; |
case DEMANGLE_COMPONENT_DECLTYPE: |
printf ("decltype\n"); |
break; |
case DEMANGLE_COMPONENT_PACK_EXPANSION: |
printf ("pack expansion\n"); |
break; |
case DEMANGLE_COMPONENT_TLS_INIT: |
printf ("tls init function\n"); |
break; |
case DEMANGLE_COMPONENT_TLS_WRAPPER: |
printf ("tls wrapper function\n"); |
break; |
case DEMANGLE_COMPONENT_DEFAULT_ARG: |
printf ("default argument %d\n", dc->u.s_unary_num.num); |
d_dump (dc->u.s_unary_num.sub, indent+2); |
return; |
case DEMANGLE_COMPONENT_LAMBDA: |
printf ("lambda %d\n", dc->u.s_unary_num.num); |
d_dump (dc->u.s_unary_num.sub, indent+2); |
return; |
} |
d_dump (d_left (dc), indent + 2); |
d_dump (d_right (dc), indent + 2); |
} |
#endif /* CP_DEMANGLE_DEBUG */ |
/* Fill in a DEMANGLE_COMPONENT_NAME. */ |
CP_STATIC_IF_GLIBCPP_V3 |
int |
cplus_demangle_fill_name (struct demangle_component *p, const char *s, int len) |
{ |
if (p == NULL || s == NULL || len == 0) |
return 0; |
p->type = DEMANGLE_COMPONENT_NAME; |
p->u.s_name.s = s; |
p->u.s_name.len = len; |
return 1; |
} |
/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */ |
CP_STATIC_IF_GLIBCPP_V3 |
int |
cplus_demangle_fill_extended_operator (struct demangle_component *p, int args, |
struct demangle_component *name) |
{ |
if (p == NULL || args < 0 || name == NULL) |
return 0; |
p->type = DEMANGLE_COMPONENT_EXTENDED_OPERATOR; |
p->u.s_extended_operator.args = args; |
p->u.s_extended_operator.name = name; |
return 1; |
} |
/* Fill in a DEMANGLE_COMPONENT_CTOR. */ |
CP_STATIC_IF_GLIBCPP_V3 |
int |
cplus_demangle_fill_ctor (struct demangle_component *p, |
enum gnu_v3_ctor_kinds kind, |
struct demangle_component *name) |
{ |
if (p == NULL |
|| name == NULL |
|| (int) kind < gnu_v3_complete_object_ctor |
|| (int) kind > gnu_v3_object_ctor_group) |
return 0; |
p->type = DEMANGLE_COMPONENT_CTOR; |
p->u.s_ctor.kind = kind; |
p->u.s_ctor.name = name; |
return 1; |
} |
/* Fill in a DEMANGLE_COMPONENT_DTOR. */ |
CP_STATIC_IF_GLIBCPP_V3 |
int |
cplus_demangle_fill_dtor (struct demangle_component *p, |
enum gnu_v3_dtor_kinds kind, |
struct demangle_component *name) |
{ |
if (p == NULL |
|| name == NULL |
|| (int) kind < gnu_v3_deleting_dtor |
|| (int) kind > gnu_v3_object_dtor_group) |
return 0; |
p->type = DEMANGLE_COMPONENT_DTOR; |
p->u.s_dtor.kind = kind; |
p->u.s_dtor.name = name; |
return 1; |
} |
/* Add a new component. */ |
static struct demangle_component * |
d_make_empty (struct d_info *di) |
{ |
struct demangle_component *p; |
if (di->next_comp >= di->num_comps) |
return NULL; |
p = &di->comps[di->next_comp]; |
++di->next_comp; |
return p; |
} |
/* Add a new generic component. */ |
static struct demangle_component * |
d_make_comp (struct d_info *di, enum demangle_component_type type, |
struct demangle_component *left, |
struct demangle_component *right) |
{ |
struct demangle_component *p; |
/* We check for errors here. A typical error would be a NULL return |
from a subroutine. We catch those here, and return NULL |
upward. */ |
switch (type) |
{ |
/* These types require two parameters. */ |
case DEMANGLE_COMPONENT_QUAL_NAME: |
case DEMANGLE_COMPONENT_LOCAL_NAME: |
case DEMANGLE_COMPONENT_TYPED_NAME: |
case DEMANGLE_COMPONENT_TAGGED_NAME: |
case DEMANGLE_COMPONENT_TEMPLATE: |
case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: |
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: |
case DEMANGLE_COMPONENT_PTRMEM_TYPE: |
case DEMANGLE_COMPONENT_UNARY: |
case DEMANGLE_COMPONENT_BINARY: |
case DEMANGLE_COMPONENT_BINARY_ARGS: |
case DEMANGLE_COMPONENT_TRINARY: |
case DEMANGLE_COMPONENT_TRINARY_ARG1: |
case DEMANGLE_COMPONENT_LITERAL: |
case DEMANGLE_COMPONENT_LITERAL_NEG: |
case DEMANGLE_COMPONENT_COMPOUND_NAME: |
case DEMANGLE_COMPONENT_VECTOR_TYPE: |
case DEMANGLE_COMPONENT_CLONE: |
if (left == NULL || right == NULL) |
return NULL; |
break; |
/* These types only require one parameter. */ |
case DEMANGLE_COMPONENT_VTABLE: |
case DEMANGLE_COMPONENT_VTT: |
case DEMANGLE_COMPONENT_TYPEINFO: |
case DEMANGLE_COMPONENT_TYPEINFO_NAME: |
case DEMANGLE_COMPONENT_TYPEINFO_FN: |
case DEMANGLE_COMPONENT_THUNK: |
case DEMANGLE_COMPONENT_VIRTUAL_THUNK: |
case DEMANGLE_COMPONENT_COVARIANT_THUNK: |
case DEMANGLE_COMPONENT_JAVA_CLASS: |
case DEMANGLE_COMPONENT_GUARD: |
case DEMANGLE_COMPONENT_TLS_INIT: |
case DEMANGLE_COMPONENT_TLS_WRAPPER: |
case DEMANGLE_COMPONENT_REFTEMP: |
case DEMANGLE_COMPONENT_HIDDEN_ALIAS: |
case DEMANGLE_COMPONENT_TRANSACTION_CLONE: |
case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE: |
case DEMANGLE_COMPONENT_POINTER: |
case DEMANGLE_COMPONENT_REFERENCE: |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE: |
case DEMANGLE_COMPONENT_COMPLEX: |
case DEMANGLE_COMPONENT_IMAGINARY: |
case DEMANGLE_COMPONENT_VENDOR_TYPE: |
case DEMANGLE_COMPONENT_CAST: |
case DEMANGLE_COMPONENT_JAVA_RESOURCE: |
case DEMANGLE_COMPONENT_DECLTYPE: |
case DEMANGLE_COMPONENT_PACK_EXPANSION: |
case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: |
case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: |
case DEMANGLE_COMPONENT_NULLARY: |
case DEMANGLE_COMPONENT_TRINARY_ARG2: |
if (left == NULL) |
return NULL; |
break; |
/* This needs a right parameter, but the left parameter can be |
empty. */ |
case DEMANGLE_COMPONENT_ARRAY_TYPE: |
case DEMANGLE_COMPONENT_INITIALIZER_LIST: |
if (right == NULL) |
return NULL; |
break; |
/* These are allowed to have no parameters--in some cases they |
will be filled in later. */ |
case DEMANGLE_COMPONENT_FUNCTION_TYPE: |
case DEMANGLE_COMPONENT_RESTRICT: |
case DEMANGLE_COMPONENT_VOLATILE: |
case DEMANGLE_COMPONENT_CONST: |
case DEMANGLE_COMPONENT_RESTRICT_THIS: |
case DEMANGLE_COMPONENT_VOLATILE_THIS: |
case DEMANGLE_COMPONENT_CONST_THIS: |
case DEMANGLE_COMPONENT_REFERENCE_THIS: |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: |
case DEMANGLE_COMPONENT_ARGLIST: |
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: |
break; |
/* Other types should not be seen here. */ |
default: |
return NULL; |
} |
p = d_make_empty (di); |
if (p != NULL) |
{ |
p->type = type; |
p->u.s_binary.left = left; |
p->u.s_binary.right = right; |
} |
return p; |
} |
/* Add a new demangle mangled name component. */ |
static struct demangle_component * |
d_make_demangle_mangled_name (struct d_info *di, const char *s) |
{ |
if (d_peek_char (di) != '_' || d_peek_next_char (di) != 'Z') |
return d_make_name (di, s, strlen (s)); |
d_advance (di, 2); |
return d_encoding (di, 0); |
} |
/* Add a new name component. */ |
static struct demangle_component * |
d_make_name (struct d_info *di, const char *s, int len) |
{ |
struct demangle_component *p; |
p = d_make_empty (di); |
if (! cplus_demangle_fill_name (p, s, len)) |
return NULL; |
return p; |
} |
/* Add a new builtin type component. */ |
static struct demangle_component * |
d_make_builtin_type (struct d_info *di, |
const struct demangle_builtin_type_info *type) |
{ |
struct demangle_component *p; |
if (type == NULL) |
return NULL; |
p = d_make_empty (di); |
if (p != NULL) |
{ |
p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE; |
p->u.s_builtin.type = type; |
} |
return p; |
} |
/* Add a new operator component. */ |
static struct demangle_component * |
d_make_operator (struct d_info *di, const struct demangle_operator_info *op) |
{ |
struct demangle_component *p; |
p = d_make_empty (di); |
if (p != NULL) |
{ |
p->type = DEMANGLE_COMPONENT_OPERATOR; |
p->u.s_operator.op = op; |
} |
return p; |
} |
/* Add a new extended operator component. */ |
static struct demangle_component * |
d_make_extended_operator (struct d_info *di, int args, |
struct demangle_component *name) |
{ |
struct demangle_component *p; |
p = d_make_empty (di); |
if (! cplus_demangle_fill_extended_operator (p, args, name)) |
return NULL; |
return p; |
} |
static struct demangle_component * |
d_make_default_arg (struct d_info *di, int num, |
struct demangle_component *sub) |
{ |
struct demangle_component *p = d_make_empty (di); |
if (p) |
{ |
p->type = DEMANGLE_COMPONENT_DEFAULT_ARG; |
p->u.s_unary_num.num = num; |
p->u.s_unary_num.sub = sub; |
} |
return p; |
} |
/* Add a new constructor component. */ |
static struct demangle_component * |
d_make_ctor (struct d_info *di, enum gnu_v3_ctor_kinds kind, |
struct demangle_component *name) |
{ |
struct demangle_component *p; |
p = d_make_empty (di); |
if (! cplus_demangle_fill_ctor (p, kind, name)) |
return NULL; |
return p; |
} |
/* Add a new destructor component. */ |
static struct demangle_component * |
d_make_dtor (struct d_info *di, enum gnu_v3_dtor_kinds kind, |
struct demangle_component *name) |
{ |
struct demangle_component *p; |
p = d_make_empty (di); |
if (! cplus_demangle_fill_dtor (p, kind, name)) |
return NULL; |
return p; |
} |
/* Add a new template parameter. */ |
static struct demangle_component * |
d_make_template_param (struct d_info *di, long i) |
{ |
struct demangle_component *p; |
p = d_make_empty (di); |
if (p != NULL) |
{ |
p->type = DEMANGLE_COMPONENT_TEMPLATE_PARAM; |
p->u.s_number.number = i; |
} |
return p; |
} |
/* Add a new function parameter. */ |
static struct demangle_component * |
d_make_function_param (struct d_info *di, long i) |
{ |
struct demangle_component *p; |
p = d_make_empty (di); |
if (p != NULL) |
{ |
p->type = DEMANGLE_COMPONENT_FUNCTION_PARAM; |
p->u.s_number.number = i; |
} |
return p; |
} |
/* Add a new standard substitution component. */ |
static struct demangle_component * |
d_make_sub (struct d_info *di, const char *name, int len) |
{ |
struct demangle_component *p; |
p = d_make_empty (di); |
if (p != NULL) |
{ |
p->type = DEMANGLE_COMPONENT_SUB_STD; |
p->u.s_string.string = name; |
p->u.s_string.len = len; |
} |
return p; |
} |
/* <mangled-name> ::= _Z <encoding> [<clone-suffix>]* |
TOP_LEVEL is non-zero when called at the top level. */ |
CP_STATIC_IF_GLIBCPP_V3 |
struct demangle_component * |
cplus_demangle_mangled_name (struct d_info *di, int top_level) |
{ |
struct demangle_component *p; |
if (! d_check_char (di, '_') |
/* Allow missing _ if not at toplevel to work around a |
bug in G++ abi-version=2 mangling; see the comment in |
write_template_arg. */ |
&& top_level) |
return NULL; |
if (! d_check_char (di, 'Z')) |
return NULL; |
p = d_encoding (di, top_level); |
/* If at top level and parsing parameters, check for a clone |
suffix. */ |
if (top_level && (di->options & DMGL_PARAMS) != 0) |
while (d_peek_char (di) == '.' |
&& (IS_LOWER (d_peek_next_char (di)) |
|| d_peek_next_char (di) == '_' |
|| IS_DIGIT (d_peek_next_char (di)))) |
p = d_clone_suffix (di, p); |
return p; |
} |
/* Return whether a function should have a return type. The argument |
is the function name, which may be qualified in various ways. The |
rules are that template functions have return types with some |
exceptions, function types which are not part of a function name |
mangling have return types with some exceptions, and non-template |
function names do not have return types. The exceptions are that |
constructors, destructors, and conversion operators do not have |
return types. */ |
static int |
has_return_type (struct demangle_component *dc) |
{ |
if (dc == NULL) |
return 0; |
switch (dc->type) |
{ |
default: |
return 0; |
case DEMANGLE_COMPONENT_TEMPLATE: |
return ! is_ctor_dtor_or_conversion (d_left (dc)); |
case DEMANGLE_COMPONENT_RESTRICT_THIS: |
case DEMANGLE_COMPONENT_VOLATILE_THIS: |
case DEMANGLE_COMPONENT_CONST_THIS: |
case DEMANGLE_COMPONENT_REFERENCE_THIS: |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: |
return has_return_type (d_left (dc)); |
} |
} |
/* Return whether a name is a constructor, a destructor, or a |
conversion operator. */ |
static int |
is_ctor_dtor_or_conversion (struct demangle_component *dc) |
{ |
if (dc == NULL) |
return 0; |
switch (dc->type) |
{ |
default: |
return 0; |
case DEMANGLE_COMPONENT_QUAL_NAME: |
case DEMANGLE_COMPONENT_LOCAL_NAME: |
return is_ctor_dtor_or_conversion (d_right (dc)); |
case DEMANGLE_COMPONENT_CTOR: |
case DEMANGLE_COMPONENT_DTOR: |
case DEMANGLE_COMPONENT_CAST: |
return 1; |
} |
} |
/* <encoding> ::= <(function) name> <bare-function-type> |
::= <(data) name> |
::= <special-name> |
TOP_LEVEL is non-zero when called at the top level, in which case |
if DMGL_PARAMS is not set we do not demangle the function |
parameters. We only set this at the top level, because otherwise |
we would not correctly demangle names in local scopes. */ |
static struct demangle_component * |
d_encoding (struct d_info *di, int top_level) |
{ |
char peek = d_peek_char (di); |
if (peek == 'G' || peek == 'T') |
return d_special_name (di); |
else |
{ |
struct demangle_component *dc; |
dc = d_name (di); |
if (dc != NULL && top_level && (di->options & DMGL_PARAMS) == 0) |
{ |
/* Strip off any initial CV-qualifiers, as they really apply |
to the `this' parameter, and they were not output by the |
v2 demangler without DMGL_PARAMS. */ |
while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS |
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS |
|| dc->type == DEMANGLE_COMPONENT_CONST_THIS |
|| dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS |
|| dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS) |
dc = d_left (dc); |
/* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then |
there may be CV-qualifiers on its right argument which |
really apply here; this happens when parsing a class |
which is local to a function. */ |
if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME) |
{ |
struct demangle_component *dcr; |
dcr = d_right (dc); |
while (dcr->type == DEMANGLE_COMPONENT_RESTRICT_THIS |
|| dcr->type == DEMANGLE_COMPONENT_VOLATILE_THIS |
|| dcr->type == DEMANGLE_COMPONENT_CONST_THIS |
|| dcr->type == DEMANGLE_COMPONENT_REFERENCE_THIS |
|| dcr->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS) |
dcr = d_left (dcr); |
dc->u.s_binary.right = dcr; |
} |
return dc; |
} |
peek = d_peek_char (di); |
if (dc == NULL || peek == '\0' || peek == 'E') |
return dc; |
return d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, dc, |
d_bare_function_type (di, has_return_type (dc))); |
} |
} |
/* <tagged-name> ::= <name> B <source-name> */ |
static struct demangle_component * |
d_abi_tags (struct d_info *di, struct demangle_component *dc) |
{ |
char peek; |
while (peek = d_peek_char (di), |
peek == 'B') |
{ |
struct demangle_component *tag; |
d_advance (di, 1); |
tag = d_source_name (di); |
dc = d_make_comp (di, DEMANGLE_COMPONENT_TAGGED_NAME, dc, tag); |
} |
return dc; |
} |
/* <name> ::= <nested-name> |
::= <unscoped-name> |
::= <unscoped-template-name> <template-args> |
::= <local-name> |
<unscoped-name> ::= <unqualified-name> |
::= St <unqualified-name> |
<unscoped-template-name> ::= <unscoped-name> |
::= <substitution> |
*/ |
static struct demangle_component * |
d_name (struct d_info *di) |
{ |
char peek = d_peek_char (di); |
struct demangle_component *dc; |
switch (peek) |
{ |
case 'N': |
return d_nested_name (di); |
case 'Z': |
return d_local_name (di); |
case 'L': |
case 'U': |
return d_unqualified_name (di); |
case 'S': |
{ |
int subst; |
if (d_peek_next_char (di) != 't') |
{ |
dc = d_substitution (di, 0); |
subst = 1; |
} |
else |
{ |
d_advance (di, 2); |
dc = d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, |
d_make_name (di, "std", 3), |
d_unqualified_name (di)); |
di->expansion += 3; |
subst = 0; |
} |
if (d_peek_char (di) != 'I') |
{ |
/* The grammar does not permit this case to occur if we |
called d_substitution() above (i.e., subst == 1). We |
don't bother to check. */ |
} |
else |
{ |
/* This is <template-args>, which means that we just saw |
<unscoped-template-name>, which is a substitution |
candidate if we didn't just get it from a |
substitution. */ |
if (! subst) |
{ |
if (! d_add_substitution (di, dc)) |
return NULL; |
} |
dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc, |
d_template_args (di)); |
} |
return dc; |
} |
default: |
dc = d_unqualified_name (di); |
if (d_peek_char (di) == 'I') |
{ |
/* This is <template-args>, which means that we just saw |
<unscoped-template-name>, which is a substitution |
candidate. */ |
if (! d_add_substitution (di, dc)) |
return NULL; |
dc = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, dc, |
d_template_args (di)); |
} |
return dc; |
} |
} |
/* <nested-name> ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E |
::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> <template-args> E |
*/ |
static struct demangle_component * |
d_nested_name (struct d_info *di) |
{ |
struct demangle_component *ret; |
struct demangle_component **pret; |
struct demangle_component *rqual; |
if (! d_check_char (di, 'N')) |
return NULL; |
pret = d_cv_qualifiers (di, &ret, 1); |
if (pret == NULL) |
return NULL; |
/* Parse the ref-qualifier now and then attach it |
once we have something to attach it to. */ |
rqual = d_ref_qualifier (di, NULL); |
*pret = d_prefix (di); |
if (*pret == NULL) |
return NULL; |
if (rqual) |
{ |
d_left (rqual) = ret; |
ret = rqual; |
} |
if (! d_check_char (di, 'E')) |
return NULL; |
return ret; |
} |
/* <prefix> ::= <prefix> <unqualified-name> |
::= <template-prefix> <template-args> |
::= <template-param> |
::= <decltype> |
::= |
::= <substitution> |
<template-prefix> ::= <prefix> <(template) unqualified-name> |
::= <template-param> |
::= <substitution> |
*/ |
static struct demangle_component * |
d_prefix (struct d_info *di) |
{ |
struct demangle_component *ret = NULL; |
while (1) |
{ |
char peek; |
enum demangle_component_type comb_type; |
struct demangle_component *dc; |
peek = d_peek_char (di); |
if (peek == '\0') |
return NULL; |
/* The older code accepts a <local-name> here, but I don't see |
that in the grammar. The older code does not accept a |
<template-param> here. */ |
comb_type = DEMANGLE_COMPONENT_QUAL_NAME; |
if (peek == 'D') |
{ |
char peek2 = d_peek_next_char (di); |
if (peek2 == 'T' || peek2 == 't') |
/* Decltype. */ |
dc = cplus_demangle_type (di); |
else |
/* Destructor name. */ |
dc = d_unqualified_name (di); |
} |
else if (IS_DIGIT (peek) |
|| IS_LOWER (peek) |
|| peek == 'C' |
|| peek == 'U' |
|| peek == 'L') |
dc = d_unqualified_name (di); |
else if (peek == 'S') |
dc = d_substitution (di, 1); |
else if (peek == 'I') |
{ |
if (ret == NULL) |
return NULL; |
comb_type = DEMANGLE_COMPONENT_TEMPLATE; |
dc = d_template_args (di); |
} |
else if (peek == 'T') |
dc = d_template_param (di); |
else if (peek == 'E') |
return ret; |
else if (peek == 'M') |
{ |
/* Initializer scope for a lambda. We don't need to represent |
this; the normal code will just treat the variable as a type |
scope, which gives appropriate output. */ |
if (ret == NULL) |
return NULL; |
d_advance (di, 1); |
continue; |
} |
else |
return NULL; |
if (ret == NULL) |
ret = dc; |
else |
ret = d_make_comp (di, comb_type, ret, dc); |
if (peek != 'S' && d_peek_char (di) != 'E') |
{ |
if (! d_add_substitution (di, ret)) |
return NULL; |
} |
} |
} |
/* <unqualified-name> ::= <operator-name> |
::= <ctor-dtor-name> |
::= <source-name> |
::= <local-source-name> |
<local-source-name> ::= L <source-name> <discriminator> |
*/ |
static struct demangle_component * |
d_unqualified_name (struct d_info *di) |
{ |
struct demangle_component *ret; |
char peek; |
peek = d_peek_char (di); |
if (IS_DIGIT (peek)) |
ret = d_source_name (di); |
else if (IS_LOWER (peek)) |
{ |
ret = d_operator_name (di); |
if (ret != NULL && ret->type == DEMANGLE_COMPONENT_OPERATOR) |
{ |
di->expansion += sizeof "operator" + ret->u.s_operator.op->len - 2; |
if (!strcmp (ret->u.s_operator.op->code, "li")) |
ret = d_make_comp (di, DEMANGLE_COMPONENT_UNARY, ret, |
d_source_name (di)); |
} |
} |
else if (peek == 'C' || peek == 'D') |
ret = d_ctor_dtor_name (di); |
else if (peek == 'L') |
{ |
d_advance (di, 1); |
ret = d_source_name (di); |
if (ret == NULL) |
return NULL; |
if (! d_discriminator (di)) |
return NULL; |
} |
else if (peek == 'U') |
{ |
switch (d_peek_next_char (di)) |
{ |
case 'l': |
ret = d_lambda (di); |
break; |
case 't': |
ret = d_unnamed_type (di); |
break; |
default: |
return NULL; |
} |
} |
else |
return NULL; |
if (d_peek_char (di) == 'B') |
ret = d_abi_tags (di, ret); |
return ret; |
} |
/* <source-name> ::= <(positive length) number> <identifier> */ |
static struct demangle_component * |
d_source_name (struct d_info *di) |
{ |
long len; |
struct demangle_component *ret; |
len = d_number (di); |
if (len <= 0) |
return NULL; |
ret = d_identifier (di, len); |
di->last_name = ret; |
return ret; |
} |
/* number ::= [n] <(non-negative decimal integer)> */ |
static long |
d_number (struct d_info *di) |
{ |
int negative; |
char peek; |
long ret; |
negative = 0; |
peek = d_peek_char (di); |
if (peek == 'n') |
{ |
negative = 1; |
d_advance (di, 1); |
peek = d_peek_char (di); |
} |
ret = 0; |
while (1) |
{ |
if (! IS_DIGIT (peek)) |
{ |
if (negative) |
ret = - ret; |
return ret; |
} |
ret = ret * 10 + peek - '0'; |
d_advance (di, 1); |
peek = d_peek_char (di); |
} |
} |
/* Like d_number, but returns a demangle_component. */ |
static struct demangle_component * |
d_number_component (struct d_info *di) |
{ |
struct demangle_component *ret = d_make_empty (di); |
if (ret) |
{ |
ret->type = DEMANGLE_COMPONENT_NUMBER; |
ret->u.s_number.number = d_number (di); |
} |
return ret; |
} |
/* identifier ::= <(unqualified source code identifier)> */ |
static struct demangle_component * |
d_identifier (struct d_info *di, int len) |
{ |
const char *name; |
name = d_str (di); |
if (di->send - name < len) |
return NULL; |
d_advance (di, len); |
/* A Java mangled name may have a trailing '$' if it is a C++ |
keyword. This '$' is not included in the length count. We just |
ignore the '$'. */ |
if ((di->options & DMGL_JAVA) != 0 |
&& d_peek_char (di) == '$') |
d_advance (di, 1); |
/* Look for something which looks like a gcc encoding of an |
anonymous namespace, and replace it with a more user friendly |
name. */ |
if (len >= (int) ANONYMOUS_NAMESPACE_PREFIX_LEN + 2 |
&& memcmp (name, ANONYMOUS_NAMESPACE_PREFIX, |
ANONYMOUS_NAMESPACE_PREFIX_LEN) == 0) |
{ |
const char *s; |
s = name + ANONYMOUS_NAMESPACE_PREFIX_LEN; |
if ((*s == '.' || *s == '_' || *s == '$') |
&& s[1] == 'N') |
{ |
di->expansion -= len - sizeof "(anonymous namespace)"; |
return d_make_name (di, "(anonymous namespace)", |
sizeof "(anonymous namespace)" - 1); |
} |
} |
return d_make_name (di, name, len); |
} |
/* operator_name ::= many different two character encodings. |
::= cv <type> |
::= v <digit> <source-name> |
This list is sorted for binary search. */ |
#define NL(s) s, (sizeof s) - 1 |
CP_STATIC_IF_GLIBCPP_V3 |
const struct demangle_operator_info cplus_demangle_operators[] = |
{ |
{ "aN", NL ("&="), 2 }, |
{ "aS", NL ("="), 2 }, |
{ "aa", NL ("&&"), 2 }, |
{ "ad", NL ("&"), 1 }, |
{ "an", NL ("&"), 2 }, |
{ "at", NL ("alignof "), 1 }, |
{ "az", NL ("alignof "), 1 }, |
{ "cc", NL ("const_cast"), 2 }, |
{ "cl", NL ("()"), 2 }, |
{ "cm", NL (","), 2 }, |
{ "co", NL ("~"), 1 }, |
{ "dV", NL ("/="), 2 }, |
{ "da", NL ("delete[] "), 1 }, |
{ "dc", NL ("dynamic_cast"), 2 }, |
{ "de", NL ("*"), 1 }, |
{ "dl", NL ("delete "), 1 }, |
{ "ds", NL (".*"), 2 }, |
{ "dt", NL ("."), 2 }, |
{ "dv", NL ("/"), 2 }, |
{ "eO", NL ("^="), 2 }, |
{ "eo", NL ("^"), 2 }, |
{ "eq", NL ("=="), 2 }, |
{ "ge", NL (">="), 2 }, |
{ "gs", NL ("::"), 1 }, |
{ "gt", NL (">"), 2 }, |
{ "ix", NL ("[]"), 2 }, |
{ "lS", NL ("<<="), 2 }, |
{ "le", NL ("<="), 2 }, |
{ "li", NL ("operator\"\" "), 1 }, |
{ "ls", NL ("<<"), 2 }, |
{ "lt", NL ("<"), 2 }, |
{ "mI", NL ("-="), 2 }, |
{ "mL", NL ("*="), 2 }, |
{ "mi", NL ("-"), 2 }, |
{ "ml", NL ("*"), 2 }, |
{ "mm", NL ("--"), 1 }, |
{ "na", NL ("new[]"), 3 }, |
{ "ne", NL ("!="), 2 }, |
{ "ng", NL ("-"), 1 }, |
{ "nt", NL ("!"), 1 }, |
{ "nw", NL ("new"), 3 }, |
{ "oR", NL ("|="), 2 }, |
{ "oo", NL ("||"), 2 }, |
{ "or", NL ("|"), 2 }, |
{ "pL", NL ("+="), 2 }, |
{ "pl", NL ("+"), 2 }, |
{ "pm", NL ("->*"), 2 }, |
{ "pp", NL ("++"), 1 }, |
{ "ps", NL ("+"), 1 }, |
{ "pt", NL ("->"), 2 }, |
{ "qu", NL ("?"), 3 }, |
{ "rM", NL ("%="), 2 }, |
{ "rS", NL (">>="), 2 }, |
{ "rc", NL ("reinterpret_cast"), 2 }, |
{ "rm", NL ("%"), 2 }, |
{ "rs", NL (">>"), 2 }, |
{ "sc", NL ("static_cast"), 2 }, |
{ "st", NL ("sizeof "), 1 }, |
{ "sz", NL ("sizeof "), 1 }, |
{ "tr", NL ("throw"), 0 }, |
{ "tw", NL ("throw "), 1 }, |
{ NULL, NULL, 0, 0 } |
}; |
static struct demangle_component * |
d_operator_name (struct d_info *di) |
{ |
char c1; |
char c2; |
c1 = d_next_char (di); |
c2 = d_next_char (di); |
if (c1 == 'v' && IS_DIGIT (c2)) |
return d_make_extended_operator (di, c2 - '0', d_source_name (di)); |
else if (c1 == 'c' && c2 == 'v') |
return d_make_comp (di, DEMANGLE_COMPONENT_CAST, |
cplus_demangle_type (di), NULL); |
else |
{ |
/* LOW is the inclusive lower bound. */ |
int low = 0; |
/* HIGH is the exclusive upper bound. We subtract one to ignore |
the sentinel at the end of the array. */ |
int high = ((sizeof (cplus_demangle_operators) |
/ sizeof (cplus_demangle_operators[0])) |
- 1); |
while (1) |
{ |
int i; |
const struct demangle_operator_info *p; |
i = low + (high - low) / 2; |
p = cplus_demangle_operators + i; |
if (c1 == p->code[0] && c2 == p->code[1]) |
return d_make_operator (di, p); |
if (c1 < p->code[0] || (c1 == p->code[0] && c2 < p->code[1])) |
high = i; |
else |
low = i + 1; |
if (low == high) |
return NULL; |
} |
} |
} |
static struct demangle_component * |
d_make_character (struct d_info *di, int c) |
{ |
struct demangle_component *p; |
p = d_make_empty (di); |
if (p != NULL) |
{ |
p->type = DEMANGLE_COMPONENT_CHARACTER; |
p->u.s_character.character = c; |
} |
return p; |
} |
static struct demangle_component * |
d_java_resource (struct d_info *di) |
{ |
struct demangle_component *p = NULL; |
struct demangle_component *next = NULL; |
long len, i; |
char c; |
const char *str; |
len = d_number (di); |
if (len <= 1) |
return NULL; |
/* Eat the leading '_'. */ |
if (d_next_char (di) != '_') |
return NULL; |
len--; |
str = d_str (di); |
i = 0; |
while (len > 0) |
{ |
c = str[i]; |
if (!c) |
return NULL; |
/* Each chunk is either a '$' escape... */ |
if (c == '$') |
{ |
i++; |
switch (str[i++]) |
{ |
case 'S': |
c = '/'; |
break; |
case '_': |
c = '.'; |
break; |
case '$': |
c = '$'; |
break; |
default: |
return NULL; |
} |
next = d_make_character (di, c); |
d_advance (di, i); |
str = d_str (di); |
len -= i; |
i = 0; |
if (next == NULL) |
return NULL; |
} |
/* ... or a sequence of characters. */ |
else |
{ |
while (i < len && str[i] && str[i] != '$') |
i++; |
next = d_make_name (di, str, i); |
d_advance (di, i); |
str = d_str (di); |
len -= i; |
i = 0; |
if (next == NULL) |
return NULL; |
} |
if (p == NULL) |
p = next; |
else |
{ |
p = d_make_comp (di, DEMANGLE_COMPONENT_COMPOUND_NAME, p, next); |
if (p == NULL) |
return NULL; |
} |
} |
p = d_make_comp (di, DEMANGLE_COMPONENT_JAVA_RESOURCE, p, NULL); |
return p; |
} |
/* <special-name> ::= TV <type> |
::= TT <type> |
::= TI <type> |
::= TS <type> |
::= GV <(object) name> |
::= T <call-offset> <(base) encoding> |
::= Tc <call-offset> <call-offset> <(base) encoding> |
Also g++ extensions: |
::= TC <type> <(offset) number> _ <(base) type> |
::= TF <type> |
::= TJ <type> |
::= GR <name> |
::= GA <encoding> |
::= Gr <resource name> |
::= GTt <encoding> |
::= GTn <encoding> |
*/ |
static struct demangle_component * |
d_special_name (struct d_info *di) |
{ |
di->expansion += 20; |
if (d_check_char (di, 'T')) |
{ |
switch (d_next_char (di)) |
{ |
case 'V': |
di->expansion -= 5; |
return d_make_comp (di, DEMANGLE_COMPONENT_VTABLE, |
cplus_demangle_type (di), NULL); |
case 'T': |
di->expansion -= 10; |
return d_make_comp (di, DEMANGLE_COMPONENT_VTT, |
cplus_demangle_type (di), NULL); |
case 'I': |
return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO, |
cplus_demangle_type (di), NULL); |
case 'S': |
return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_NAME, |
cplus_demangle_type (di), NULL); |
case 'h': |
if (! d_call_offset (di, 'h')) |
return NULL; |
return d_make_comp (di, DEMANGLE_COMPONENT_THUNK, |
d_encoding (di, 0), NULL); |
case 'v': |
if (! d_call_offset (di, 'v')) |
return NULL; |
return d_make_comp (di, DEMANGLE_COMPONENT_VIRTUAL_THUNK, |
d_encoding (di, 0), NULL); |
case 'c': |
if (! d_call_offset (di, '\0')) |
return NULL; |
if (! d_call_offset (di, '\0')) |
return NULL; |
return d_make_comp (di, DEMANGLE_COMPONENT_COVARIANT_THUNK, |
d_encoding (di, 0), NULL); |
case 'C': |
{ |
struct demangle_component *derived_type; |
long offset; |
struct demangle_component *base_type; |
derived_type = cplus_demangle_type (di); |
offset = d_number (di); |
if (offset < 0) |
return NULL; |
if (! d_check_char (di, '_')) |
return NULL; |
base_type = cplus_demangle_type (di); |
/* We don't display the offset. FIXME: We should display |
it in verbose mode. */ |
di->expansion += 5; |
return d_make_comp (di, DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE, |
base_type, derived_type); |
} |
case 'F': |
return d_make_comp (di, DEMANGLE_COMPONENT_TYPEINFO_FN, |
cplus_demangle_type (di), NULL); |
case 'J': |
return d_make_comp (di, DEMANGLE_COMPONENT_JAVA_CLASS, |
cplus_demangle_type (di), NULL); |
case 'H': |
return d_make_comp (di, DEMANGLE_COMPONENT_TLS_INIT, |
d_name (di), NULL); |
case 'W': |
return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER, |
d_name (di), NULL); |
default: |
return NULL; |
} |
} |
else if (d_check_char (di, 'G')) |
{ |
switch (d_next_char (di)) |
{ |
case 'V': |
return d_make_comp (di, DEMANGLE_COMPONENT_GUARD, d_name (di), NULL); |
case 'R': |
{ |
struct demangle_component *name = d_name (di); |
return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, name, |
d_number_component (di)); |
} |
case 'A': |
return d_make_comp (di, DEMANGLE_COMPONENT_HIDDEN_ALIAS, |
d_encoding (di, 0), NULL); |
case 'T': |
switch (d_next_char (di)) |
{ |
case 'n': |
return d_make_comp (di, DEMANGLE_COMPONENT_NONTRANSACTION_CLONE, |
d_encoding (di, 0), NULL); |
default: |
/* ??? The proposal is that other letters (such as 'h') stand |
for different variants of transaction cloning, such as |
compiling directly for hardware transaction support. But |
they still should all be transactional clones of some sort |
so go ahead and call them that. */ |
case 't': |
return d_make_comp (di, DEMANGLE_COMPONENT_TRANSACTION_CLONE, |
d_encoding (di, 0), NULL); |
} |
case 'r': |
return d_java_resource (di); |
default: |
return NULL; |
} |
} |
else |
return NULL; |
} |
/* <call-offset> ::= h <nv-offset> _ |
::= v <v-offset> _ |
<nv-offset> ::= <(offset) number> |
<v-offset> ::= <(offset) number> _ <(virtual offset) number> |
The C parameter, if not '\0', is a character we just read which is |
the start of the <call-offset>. |
We don't display the offset information anywhere. FIXME: We should |
display it in verbose mode. */ |
static int |
d_call_offset (struct d_info *di, int c) |
{ |
if (c == '\0') |
c = d_next_char (di); |
if (c == 'h') |
d_number (di); |
else if (c == 'v') |
{ |
d_number (di); |
if (! d_check_char (di, '_')) |
return 0; |
d_number (di); |
} |
else |
return 0; |
if (! d_check_char (di, '_')) |
return 0; |
return 1; |
} |
/* <ctor-dtor-name> ::= C1 |
::= C2 |
::= C3 |
::= D0 |
::= D1 |
::= D2 |
*/ |
static struct demangle_component * |
d_ctor_dtor_name (struct d_info *di) |
{ |
if (di->last_name != NULL) |
{ |
if (di->last_name->type == DEMANGLE_COMPONENT_NAME) |
di->expansion += di->last_name->u.s_name.len; |
else if (di->last_name->type == DEMANGLE_COMPONENT_SUB_STD) |
di->expansion += di->last_name->u.s_string.len; |
} |
switch (d_peek_char (di)) |
{ |
case 'C': |
{ |
enum gnu_v3_ctor_kinds kind; |
switch (d_peek_next_char (di)) |
{ |
case '1': |
kind = gnu_v3_complete_object_ctor; |
break; |
case '2': |
kind = gnu_v3_base_object_ctor; |
break; |
case '3': |
kind = gnu_v3_complete_object_allocating_ctor; |
break; |
case '5': |
kind = gnu_v3_object_ctor_group; |
break; |
default: |
return NULL; |
} |
d_advance (di, 2); |
return d_make_ctor (di, kind, di->last_name); |
} |
case 'D': |
{ |
enum gnu_v3_dtor_kinds kind; |
switch (d_peek_next_char (di)) |
{ |
case '0': |
kind = gnu_v3_deleting_dtor; |
break; |
case '1': |
kind = gnu_v3_complete_object_dtor; |
break; |
case '2': |
kind = gnu_v3_base_object_dtor; |
break; |
case '5': |
kind = gnu_v3_object_dtor_group; |
break; |
default: |
return NULL; |
} |
d_advance (di, 2); |
return d_make_dtor (di, kind, di->last_name); |
} |
default: |
return NULL; |
} |
} |
/* <type> ::= <builtin-type> |
::= <function-type> |
::= <class-enum-type> |
::= <array-type> |
::= <pointer-to-member-type> |
::= <template-param> |
::= <template-template-param> <template-args> |
::= <substitution> |
::= <CV-qualifiers> <type> |
::= P <type> |
::= R <type> |
::= O <type> (C++0x) |
::= C <type> |
::= G <type> |
::= U <source-name> <type> |
<builtin-type> ::= various one letter codes |
::= u <source-name> |
*/ |
CP_STATIC_IF_GLIBCPP_V3 |
const struct demangle_builtin_type_info |
cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT] = |
{ |
/* a */ { NL ("signed char"), NL ("signed char"), D_PRINT_DEFAULT }, |
/* b */ { NL ("bool"), NL ("boolean"), D_PRINT_BOOL }, |
/* c */ { NL ("char"), NL ("byte"), D_PRINT_DEFAULT }, |
/* d */ { NL ("double"), NL ("double"), D_PRINT_FLOAT }, |
/* e */ { NL ("long double"), NL ("long double"), D_PRINT_FLOAT }, |
/* f */ { NL ("float"), NL ("float"), D_PRINT_FLOAT }, |
/* g */ { NL ("__float128"), NL ("__float128"), D_PRINT_FLOAT }, |
/* h */ { NL ("unsigned char"), NL ("unsigned char"), D_PRINT_DEFAULT }, |
/* i */ { NL ("int"), NL ("int"), D_PRINT_INT }, |
/* j */ { NL ("unsigned int"), NL ("unsigned"), D_PRINT_UNSIGNED }, |
/* k */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, |
/* l */ { NL ("long"), NL ("long"), D_PRINT_LONG }, |
/* m */ { NL ("unsigned long"), NL ("unsigned long"), D_PRINT_UNSIGNED_LONG }, |
/* n */ { NL ("__int128"), NL ("__int128"), D_PRINT_DEFAULT }, |
/* o */ { NL ("unsigned __int128"), NL ("unsigned __int128"), |
D_PRINT_DEFAULT }, |
/* p */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, |
/* q */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, |
/* r */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, |
/* s */ { NL ("short"), NL ("short"), D_PRINT_DEFAULT }, |
/* t */ { NL ("unsigned short"), NL ("unsigned short"), D_PRINT_DEFAULT }, |
/* u */ { NULL, 0, NULL, 0, D_PRINT_DEFAULT }, |
/* v */ { NL ("void"), NL ("void"), D_PRINT_VOID }, |
/* w */ { NL ("wchar_t"), NL ("char"), D_PRINT_DEFAULT }, |
/* x */ { NL ("long long"), NL ("long"), D_PRINT_LONG_LONG }, |
/* y */ { NL ("unsigned long long"), NL ("unsigned long long"), |
D_PRINT_UNSIGNED_LONG_LONG }, |
/* z */ { NL ("..."), NL ("..."), D_PRINT_DEFAULT }, |
/* 26 */ { NL ("decimal32"), NL ("decimal32"), D_PRINT_DEFAULT }, |
/* 27 */ { NL ("decimal64"), NL ("decimal64"), D_PRINT_DEFAULT }, |
/* 28 */ { NL ("decimal128"), NL ("decimal128"), D_PRINT_DEFAULT }, |
/* 29 */ { NL ("half"), NL ("half"), D_PRINT_FLOAT }, |
/* 30 */ { NL ("char16_t"), NL ("char16_t"), D_PRINT_DEFAULT }, |
/* 31 */ { NL ("char32_t"), NL ("char32_t"), D_PRINT_DEFAULT }, |
/* 32 */ { NL ("decltype(nullptr)"), NL ("decltype(nullptr)"), |
D_PRINT_DEFAULT }, |
}; |
CP_STATIC_IF_GLIBCPP_V3 |
struct demangle_component * |
cplus_demangle_type (struct d_info *di) |
{ |
char peek; |
struct demangle_component *ret; |
int can_subst; |
/* The ABI specifies that when CV-qualifiers are used, the base type |
is substitutable, and the fully qualified type is substitutable, |
but the base type with a strict subset of the CV-qualifiers is |
not substitutable. The natural recursive implementation of the |
CV-qualifiers would cause subsets to be substitutable, so instead |
we pull them all off now. |
FIXME: The ABI says that order-insensitive vendor qualifiers |
should be handled in the same way, but we have no way to tell |
which vendor qualifiers are order-insensitive and which are |
order-sensitive. So we just assume that they are all |
order-sensitive. g++ 3.4 supports only one vendor qualifier, |
__vector, and it treats it as order-sensitive when mangling |
names. */ |
peek = d_peek_char (di); |
if (peek == 'r' || peek == 'V' || peek == 'K') |
{ |
struct demangle_component **pret; |
pret = d_cv_qualifiers (di, &ret, 0); |
if (pret == NULL) |
return NULL; |
if (d_peek_char (di) == 'F') |
{ |
/* cv-qualifiers before a function type apply to 'this', |
so avoid adding the unqualified function type to |
the substitution list. */ |
*pret = d_function_type (di); |
} |
else |
*pret = cplus_demangle_type (di); |
if (!*pret) |
return NULL; |
if ((*pret)->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS |
|| (*pret)->type == DEMANGLE_COMPONENT_REFERENCE_THIS) |
{ |
/* Move the ref-qualifier outside the cv-qualifiers so that |
they are printed in the right order. */ |
struct demangle_component *fn = d_left (*pret); |
d_left (*pret) = ret; |
ret = *pret; |
*pret = fn; |
} |
if (! d_add_substitution (di, ret)) |
return NULL; |
return ret; |
} |
can_subst = 1; |
switch (peek) |
{ |
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': |
case 'h': case 'i': case 'j': case 'l': case 'm': case 'n': |
case 'o': case 's': case 't': |
case 'v': case 'w': case 'x': case 'y': case 'z': |
ret = d_make_builtin_type (di, |
&cplus_demangle_builtin_types[peek - 'a']); |
di->expansion += ret->u.s_builtin.type->len; |
can_subst = 0; |
d_advance (di, 1); |
break; |
case 'u': |
d_advance (di, 1); |
ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE, |
d_source_name (di), NULL); |
break; |
case 'F': |
ret = d_function_type (di); |
break; |
case '0': case '1': case '2': case '3': case '4': |
case '5': case '6': case '7': case '8': case '9': |
case 'N': |
case 'Z': |
ret = d_class_enum_type (di); |
break; |
case 'A': |
ret = d_array_type (di); |
break; |
case 'M': |
ret = d_pointer_to_member_type (di); |
break; |
case 'T': |
ret = d_template_param (di); |
if (d_peek_char (di) == 'I') |
{ |
/* This is <template-template-param> <template-args>. The |
<template-template-param> part is a substitution |
candidate. */ |
if (! d_add_substitution (di, ret)) |
return NULL; |
ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, |
d_template_args (di)); |
} |
break; |
case 'S': |
/* If this is a special substitution, then it is the start of |
<class-enum-type>. */ |
{ |
char peek_next; |
peek_next = d_peek_next_char (di); |
if (IS_DIGIT (peek_next) |
|| peek_next == '_' |
|| IS_UPPER (peek_next)) |
{ |
ret = d_substitution (di, 0); |
/* The substituted name may have been a template name and |
may be followed by tepmlate args. */ |
if (d_peek_char (di) == 'I') |
ret = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, ret, |
d_template_args (di)); |
else |
can_subst = 0; |
} |
else |
{ |
ret = d_class_enum_type (di); |
/* If the substitution was a complete type, then it is not |
a new substitution candidate. However, if the |
substitution was followed by template arguments, then |
the whole thing is a substitution candidate. */ |
if (ret != NULL && ret->type == DEMANGLE_COMPONENT_SUB_STD) |
can_subst = 0; |
} |
} |
break; |
case 'O': |
d_advance (di, 1); |
ret = d_make_comp (di, DEMANGLE_COMPONENT_RVALUE_REFERENCE, |
cplus_demangle_type (di), NULL); |
break; |
case 'P': |
d_advance (di, 1); |
ret = d_make_comp (di, DEMANGLE_COMPONENT_POINTER, |
cplus_demangle_type (di), NULL); |
break; |
case 'R': |
d_advance (di, 1); |
ret = d_make_comp (di, DEMANGLE_COMPONENT_REFERENCE, |
cplus_demangle_type (di), NULL); |
break; |
case 'C': |
d_advance (di, 1); |
ret = d_make_comp (di, DEMANGLE_COMPONENT_COMPLEX, |
cplus_demangle_type (di), NULL); |
break; |
case 'G': |
d_advance (di, 1); |
ret = d_make_comp (di, DEMANGLE_COMPONENT_IMAGINARY, |
cplus_demangle_type (di), NULL); |
break; |
case 'U': |
d_advance (di, 1); |
ret = d_source_name (di); |
ret = d_make_comp (di, DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL, |
cplus_demangle_type (di), ret); |
break; |
case 'D': |
can_subst = 0; |
d_advance (di, 1); |
peek = d_next_char (di); |
switch (peek) |
{ |
case 'T': |
case 't': |
/* decltype (expression) */ |
ret = d_make_comp (di, DEMANGLE_COMPONENT_DECLTYPE, |
d_expression (di), NULL); |
if (ret && d_next_char (di) != 'E') |
ret = NULL; |
can_subst = 1; |
break; |
case 'p': |
/* Pack expansion. */ |
ret = d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION, |
cplus_demangle_type (di), NULL); |
can_subst = 1; |
break; |
case 'a': |
/* auto */ |
ret = d_make_name (di, "auto", 4); |
break; |
case 'f': |
/* 32-bit decimal floating point */ |
ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[26]); |
di->expansion += ret->u.s_builtin.type->len; |
break; |
case 'd': |
/* 64-bit DFP */ |
ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[27]); |
di->expansion += ret->u.s_builtin.type->len; |
break; |
case 'e': |
/* 128-bit DFP */ |
ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[28]); |
di->expansion += ret->u.s_builtin.type->len; |
break; |
case 'h': |
/* 16-bit half-precision FP */ |
ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[29]); |
di->expansion += ret->u.s_builtin.type->len; |
break; |
case 's': |
/* char16_t */ |
ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[30]); |
di->expansion += ret->u.s_builtin.type->len; |
break; |
case 'i': |
/* char32_t */ |
ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[31]); |
di->expansion += ret->u.s_builtin.type->len; |
break; |
case 'F': |
/* Fixed point types. DF<int bits><length><fract bits><sat> */ |
ret = d_make_empty (di); |
ret->type = DEMANGLE_COMPONENT_FIXED_TYPE; |
if ((ret->u.s_fixed.accum = IS_DIGIT (d_peek_char (di)))) |
/* For demangling we don't care about the bits. */ |
d_number (di); |
ret->u.s_fixed.length = cplus_demangle_type (di); |
if (ret->u.s_fixed.length == NULL) |
return NULL; |
d_number (di); |
peek = d_next_char (di); |
ret->u.s_fixed.sat = (peek == 's'); |
break; |
case 'v': |
ret = d_vector_type (di); |
can_subst = 1; |
break; |
case 'n': |
/* decltype(nullptr) */ |
ret = d_make_builtin_type (di, &cplus_demangle_builtin_types[32]); |
di->expansion += ret->u.s_builtin.type->len; |
break; |
default: |
return NULL; |
} |
break; |
default: |
return NULL; |
} |
if (can_subst) |
{ |
if (! d_add_substitution (di, ret)) |
return NULL; |
} |
return ret; |
} |
/* <CV-qualifiers> ::= [r] [V] [K] */ |
static struct demangle_component ** |
d_cv_qualifiers (struct d_info *di, |
struct demangle_component **pret, int member_fn) |
{ |
struct demangle_component **pstart; |
char peek; |
pstart = pret; |
peek = d_peek_char (di); |
while (peek == 'r' || peek == 'V' || peek == 'K') |
{ |
enum demangle_component_type t; |
d_advance (di, 1); |
if (peek == 'r') |
{ |
t = (member_fn |
? DEMANGLE_COMPONENT_RESTRICT_THIS |
: DEMANGLE_COMPONENT_RESTRICT); |
di->expansion += sizeof "restrict"; |
} |
else if (peek == 'V') |
{ |
t = (member_fn |
? DEMANGLE_COMPONENT_VOLATILE_THIS |
: DEMANGLE_COMPONENT_VOLATILE); |
di->expansion += sizeof "volatile"; |
} |
else |
{ |
t = (member_fn |
? DEMANGLE_COMPONENT_CONST_THIS |
: DEMANGLE_COMPONENT_CONST); |
di->expansion += sizeof "const"; |
} |
*pret = d_make_comp (di, t, NULL, NULL); |
if (*pret == NULL) |
return NULL; |
pret = &d_left (*pret); |
peek = d_peek_char (di); |
} |
if (!member_fn && peek == 'F') |
{ |
while (pstart != pret) |
{ |
switch ((*pstart)->type) |
{ |
case DEMANGLE_COMPONENT_RESTRICT: |
(*pstart)->type = DEMANGLE_COMPONENT_RESTRICT_THIS; |
break; |
case DEMANGLE_COMPONENT_VOLATILE: |
(*pstart)->type = DEMANGLE_COMPONENT_VOLATILE_THIS; |
break; |
case DEMANGLE_COMPONENT_CONST: |
(*pstart)->type = DEMANGLE_COMPONENT_CONST_THIS; |
break; |
default: |
break; |
} |
pstart = &d_left (*pstart); |
} |
} |
return pret; |
} |
/* <ref-qualifier> ::= R |
::= O */ |
static struct demangle_component * |
d_ref_qualifier (struct d_info *di, struct demangle_component *sub) |
{ |
struct demangle_component *ret = sub; |
char peek; |
peek = d_peek_char (di); |
if (peek == 'R' || peek == 'O') |
{ |
enum demangle_component_type t; |
if (peek == 'R') |
{ |
t = DEMANGLE_COMPONENT_REFERENCE_THIS; |
di->expansion += sizeof "&"; |
} |
else |
{ |
t = DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS; |
di->expansion += sizeof "&&"; |
} |
d_advance (di, 1); |
ret = d_make_comp (di, t, ret, NULL); |
} |
return ret; |
} |
/* <function-type> ::= F [Y] <bare-function-type> [<ref-qualifier>] E */ |
static struct demangle_component * |
d_function_type (struct d_info *di) |
{ |
struct demangle_component *ret; |
if (! d_check_char (di, 'F')) |
return NULL; |
if (d_peek_char (di) == 'Y') |
{ |
/* Function has C linkage. We don't print this information. |
FIXME: We should print it in verbose mode. */ |
d_advance (di, 1); |
} |
ret = d_bare_function_type (di, 1); |
ret = d_ref_qualifier (di, ret); |
if (! d_check_char (di, 'E')) |
return NULL; |
return ret; |
} |
/* <type>+ */ |
static struct demangle_component * |
d_parmlist (struct d_info *di) |
{ |
struct demangle_component *tl; |
struct demangle_component **ptl; |
tl = NULL; |
ptl = &tl; |
while (1) |
{ |
struct demangle_component *type; |
char peek = d_peek_char (di); |
if (peek == '\0' || peek == 'E' || peek == '.') |
break; |
if ((peek == 'R' || peek == 'O') |
&& d_peek_next_char (di) == 'E') |
/* Function ref-qualifier, not a ref prefix for a parameter type. */ |
break; |
type = cplus_demangle_type (di); |
if (type == NULL) |
return NULL; |
*ptl = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, type, NULL); |
if (*ptl == NULL) |
return NULL; |
ptl = &d_right (*ptl); |
} |
/* There should be at least one parameter type besides the optional |
return type. A function which takes no arguments will have a |
single parameter type void. */ |
if (tl == NULL) |
return NULL; |
/* If we have a single parameter type void, omit it. */ |
if (d_right (tl) == NULL |
&& d_left (tl)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE |
&& d_left (tl)->u.s_builtin.type->print == D_PRINT_VOID) |
{ |
di->expansion -= d_left (tl)->u.s_builtin.type->len; |
d_left (tl) = NULL; |
} |
return tl; |
} |
/* <bare-function-type> ::= [J]<type>+ */ |
static struct demangle_component * |
d_bare_function_type (struct d_info *di, int has_return_type) |
{ |
struct demangle_component *return_type; |
struct demangle_component *tl; |
char peek; |
/* Detect special qualifier indicating that the first argument |
is the return type. */ |
peek = d_peek_char (di); |
if (peek == 'J') |
{ |
d_advance (di, 1); |
has_return_type = 1; |
} |
if (has_return_type) |
{ |
return_type = cplus_demangle_type (di); |
if (return_type == NULL) |
return NULL; |
} |
else |
return_type = NULL; |
tl = d_parmlist (di); |
if (tl == NULL) |
return NULL; |
return d_make_comp (di, DEMANGLE_COMPONENT_FUNCTION_TYPE, |
return_type, tl); |
} |
/* <class-enum-type> ::= <name> */ |
static struct demangle_component * |
d_class_enum_type (struct d_info *di) |
{ |
return d_name (di); |
} |
/* <array-type> ::= A <(positive dimension) number> _ <(element) type> |
::= A [<(dimension) expression>] _ <(element) type> |
*/ |
static struct demangle_component * |
d_array_type (struct d_info *di) |
{ |
char peek; |
struct demangle_component *dim; |
if (! d_check_char (di, 'A')) |
return NULL; |
peek = d_peek_char (di); |
if (peek == '_') |
dim = NULL; |
else if (IS_DIGIT (peek)) |
{ |
const char *s; |
s = d_str (di); |
do |
{ |
d_advance (di, 1); |
peek = d_peek_char (di); |
} |
while (IS_DIGIT (peek)); |
dim = d_make_name (di, s, d_str (di) - s); |
if (dim == NULL) |
return NULL; |
} |
else |
{ |
dim = d_expression (di); |
if (dim == NULL) |
return NULL; |
} |
if (! d_check_char (di, '_')) |
return NULL; |
return d_make_comp (di, DEMANGLE_COMPONENT_ARRAY_TYPE, dim, |
cplus_demangle_type (di)); |
} |
/* <vector-type> ::= Dv <number> _ <type> |
::= Dv _ <expression> _ <type> */ |
static struct demangle_component * |
d_vector_type (struct d_info *di) |
{ |
char peek; |
struct demangle_component *dim; |
peek = d_peek_char (di); |
if (peek == '_') |
{ |
d_advance (di, 1); |
dim = d_expression (di); |
} |
else |
dim = d_number_component (di); |
if (dim == NULL) |
return NULL; |
if (! d_check_char (di, '_')) |
return NULL; |
return d_make_comp (di, DEMANGLE_COMPONENT_VECTOR_TYPE, dim, |
cplus_demangle_type (di)); |
} |
/* <pointer-to-member-type> ::= M <(class) type> <(member) type> */ |
static struct demangle_component * |
d_pointer_to_member_type (struct d_info *di) |
{ |
struct demangle_component *cl; |
struct demangle_component *mem; |
if (! d_check_char (di, 'M')) |
return NULL; |
cl = cplus_demangle_type (di); |
if (cl == NULL) |
return NULL; |
/* The ABI says, "The type of a non-static member function is considered |
to be different, for the purposes of substitution, from the type of a |
namespace-scope or static member function whose type appears |
similar. The types of two non-static member functions are considered |
to be different, for the purposes of substitution, if the functions |
are members of different classes. In other words, for the purposes of |
substitution, the class of which the function is a member is |
considered part of the type of function." |
For a pointer to member function, this call to cplus_demangle_type |
will end up adding a (possibly qualified) non-member function type to |
the substitution table, which is not correct; however, the member |
function type will never be used in a substitution, so putting the |
wrong type in the substitution table is harmless. */ |
mem = cplus_demangle_type (di); |
if (mem == NULL) |
return NULL; |
return d_make_comp (di, DEMANGLE_COMPONENT_PTRMEM_TYPE, cl, mem); |
} |
/* <non-negative number> _ */ |
static long |
d_compact_number (struct d_info *di) |
{ |
long num; |
if (d_peek_char (di) == '_') |
num = 0; |
else if (d_peek_char (di) == 'n') |
return -1; |
else |
num = d_number (di) + 1; |
if (! d_check_char (di, '_')) |
return -1; |
return num; |
} |
/* <template-param> ::= T_ |
::= T <(parameter-2 non-negative) number> _ |
*/ |
static struct demangle_component * |
d_template_param (struct d_info *di) |
{ |
long param; |
if (! d_check_char (di, 'T')) |
return NULL; |
param = d_compact_number (di); |
if (param < 0) |
return NULL; |
++di->did_subs; |
return d_make_template_param (di, param); |
} |
/* <template-args> ::= I <template-arg>+ E */ |
static struct demangle_component * |
d_template_args (struct d_info *di) |
{ |
struct demangle_component *hold_last_name; |
struct demangle_component *al; |
struct demangle_component **pal; |
/* Preserve the last name we saw--don't let the template arguments |
clobber it, as that would give us the wrong name for a subsequent |
constructor or destructor. */ |
hold_last_name = di->last_name; |
if (d_peek_char (di) != 'I' |
&& d_peek_char (di) != 'J') |
return NULL; |
d_advance (di, 1); |
if (d_peek_char (di) == 'E') |
{ |
/* An argument pack can be empty. */ |
d_advance (di, 1); |
return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, NULL, NULL); |
} |
al = NULL; |
pal = &al; |
while (1) |
{ |
struct demangle_component *a; |
a = d_template_arg (di); |
if (a == NULL) |
return NULL; |
*pal = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE_ARGLIST, a, NULL); |
if (*pal == NULL) |
return NULL; |
pal = &d_right (*pal); |
if (d_peek_char (di) == 'E') |
{ |
d_advance (di, 1); |
break; |
} |
} |
di->last_name = hold_last_name; |
return al; |
} |
/* <template-arg> ::= <type> |
::= X <expression> E |
::= <expr-primary> |
*/ |
static struct demangle_component * |
d_template_arg (struct d_info *di) |
{ |
struct demangle_component *ret; |
switch (d_peek_char (di)) |
{ |
case 'X': |
d_advance (di, 1); |
ret = d_expression (di); |
if (! d_check_char (di, 'E')) |
return NULL; |
return ret; |
case 'L': |
return d_expr_primary (di); |
case 'I': |
case 'J': |
/* An argument pack. */ |
return d_template_args (di); |
default: |
return cplus_demangle_type (di); |
} |
} |
/* Parse a sequence of expressions until we hit the terminator |
character. */ |
static struct demangle_component * |
d_exprlist (struct d_info *di, char terminator) |
{ |
struct demangle_component *list = NULL; |
struct demangle_component **p = &list; |
if (d_peek_char (di) == terminator) |
{ |
d_advance (di, 1); |
return d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, NULL, NULL); |
} |
while (1) |
{ |
struct demangle_component *arg = d_expression (di); |
if (arg == NULL) |
return NULL; |
*p = d_make_comp (di, DEMANGLE_COMPONENT_ARGLIST, arg, NULL); |
if (*p == NULL) |
return NULL; |
p = &d_right (*p); |
if (d_peek_char (di) == terminator) |
{ |
d_advance (di, 1); |
break; |
} |
} |
return list; |
} |
/* Returns nonzero iff OP is an operator for a C++ cast: const_cast, |
dynamic_cast, static_cast or reinterpret_cast. */ |
static int |
op_is_new_cast (struct demangle_component *op) |
{ |
const char *code = op->u.s_operator.op->code; |
return (code[1] == 'c' |
&& (code[0] == 's' || code[0] == 'd' |
|| code[0] == 'c' || code[0] == 'r')); |
} |
/* <expression> ::= <(unary) operator-name> <expression> |
::= <(binary) operator-name> <expression> <expression> |
::= <(trinary) operator-name> <expression> <expression> <expression> |
::= cl <expression>+ E |
::= st <type> |
::= <template-param> |
::= sr <type> <unqualified-name> |
::= sr <type> <unqualified-name> <template-args> |
::= <expr-primary> |
*/ |
static struct demangle_component * |
d_expression (struct d_info *di) |
{ |
char peek; |
peek = d_peek_char (di); |
if (peek == 'L') |
return d_expr_primary (di); |
else if (peek == 'T') |
return d_template_param (di); |
else if (peek == 's' && d_peek_next_char (di) == 'r') |
{ |
struct demangle_component *type; |
struct demangle_component *name; |
d_advance (di, 2); |
type = cplus_demangle_type (di); |
name = d_unqualified_name (di); |
if (d_peek_char (di) != 'I') |
return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, name); |
else |
return d_make_comp (di, DEMANGLE_COMPONENT_QUAL_NAME, type, |
d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name, |
d_template_args (di))); |
} |
else if (peek == 's' && d_peek_next_char (di) == 'p') |
{ |
d_advance (di, 2); |
return d_make_comp (di, DEMANGLE_COMPONENT_PACK_EXPANSION, |
d_expression (di), NULL); |
} |
else if (peek == 'f' && d_peek_next_char (di) == 'p') |
{ |
/* Function parameter used in a late-specified return type. */ |
int index; |
d_advance (di, 2); |
if (d_peek_char (di) == 'T') |
{ |
/* 'this' parameter. */ |
d_advance (di, 1); |
index = 0; |
} |
else |
{ |
index = d_compact_number (di) + 1; |
if (index == 0) |
return NULL; |
} |
return d_make_function_param (di, index); |
} |
else if (IS_DIGIT (peek) |
|| (peek == 'o' && d_peek_next_char (di) == 'n')) |
{ |
/* We can get an unqualified name as an expression in the case of |
a dependent function call, i.e. decltype(f(t)). */ |
struct demangle_component *name; |
if (peek == 'o') |
/* operator-function-id, i.e. operator+(t). */ |
d_advance (di, 2); |
name = d_unqualified_name (di); |
if (name == NULL) |
return NULL; |
if (d_peek_char (di) == 'I') |
return d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, name, |
d_template_args (di)); |
else |
return name; |
} |
else if ((peek == 'i' || peek == 't') |
&& d_peek_next_char (di) == 'l') |
{ |
/* Brace-enclosed initializer list, untyped or typed. */ |
struct demangle_component *type = NULL; |
if (peek == 't') |
type = cplus_demangle_type (di); |
d_advance (di, 2); |
return d_make_comp (di, DEMANGLE_COMPONENT_INITIALIZER_LIST, |
type, d_exprlist (di, 'E')); |
} |
else |
{ |
struct demangle_component *op; |
const char *code = NULL; |
int args; |
op = d_operator_name (di); |
if (op == NULL) |
return NULL; |
if (op->type == DEMANGLE_COMPONENT_OPERATOR) |
{ |
code = op->u.s_operator.op->code; |
di->expansion += op->u.s_operator.op->len - 2; |
if (strcmp (code, "st") == 0) |
return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, |
cplus_demangle_type (di)); |
} |
switch (op->type) |
{ |
default: |
return NULL; |
case DEMANGLE_COMPONENT_OPERATOR: |
args = op->u.s_operator.op->args; |
break; |
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: |
args = op->u.s_extended_operator.args; |
break; |
case DEMANGLE_COMPONENT_CAST: |
args = 1; |
break; |
} |
switch (args) |
{ |
case 0: |
return d_make_comp (di, DEMANGLE_COMPONENT_NULLARY, op, NULL); |
case 1: |
{ |
struct demangle_component *operand; |
int suffix = 0; |
if (code && (code[0] == 'p' || code[0] == 'm') |
&& code[1] == code[0]) |
/* pp_ and mm_ are the prefix variants. */ |
suffix = !d_check_char (di, '_'); |
if (op->type == DEMANGLE_COMPONENT_CAST |
&& d_check_char (di, '_')) |
operand = d_exprlist (di, 'E'); |
else |
operand = d_expression (di); |
if (suffix) |
/* Indicate the suffix variant for d_print_comp. */ |
return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, |
d_make_comp (di, |
DEMANGLE_COMPONENT_BINARY_ARGS, |
operand, operand)); |
else |
return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, |
operand); |
} |
case 2: |
{ |
struct demangle_component *left; |
struct demangle_component *right; |
if (op_is_new_cast (op)) |
left = cplus_demangle_type (di); |
else |
left = d_expression (di); |
if (!strcmp (code, "cl")) |
right = d_exprlist (di, 'E'); |
else if (!strcmp (code, "dt") || !strcmp (code, "pt")) |
{ |
right = d_unqualified_name (di); |
if (d_peek_char (di) == 'I') |
right = d_make_comp (di, DEMANGLE_COMPONENT_TEMPLATE, |
right, d_template_args (di)); |
} |
else |
right = d_expression (di); |
return d_make_comp (di, DEMANGLE_COMPONENT_BINARY, op, |
d_make_comp (di, |
DEMANGLE_COMPONENT_BINARY_ARGS, |
left, right)); |
} |
case 3: |
{ |
struct demangle_component *first; |
struct demangle_component *second; |
struct demangle_component *third; |
if (!strcmp (code, "qu")) |
{ |
/* ?: expression. */ |
first = d_expression (di); |
second = d_expression (di); |
third = d_expression (di); |
} |
else if (code[0] == 'n') |
{ |
/* new-expression. */ |
if (code[1] != 'w' && code[1] != 'a') |
return NULL; |
first = d_exprlist (di, '_'); |
second = cplus_demangle_type (di); |
if (d_peek_char (di) == 'E') |
{ |
d_advance (di, 1); |
third = NULL; |
} |
else if (d_peek_char (di) == 'p' |
&& d_peek_next_char (di) == 'i') |
{ |
/* Parenthesized initializer. */ |
d_advance (di, 2); |
third = d_exprlist (di, 'E'); |
} |
else if (d_peek_char (di) == 'i' |
&& d_peek_next_char (di) == 'l') |
/* initializer-list. */ |
third = d_expression (di); |
else |
return NULL; |
} |
else |
return NULL; |
return d_make_comp (di, DEMANGLE_COMPONENT_TRINARY, op, |
d_make_comp (di, |
DEMANGLE_COMPONENT_TRINARY_ARG1, |
first, |
d_make_comp (di, |
DEMANGLE_COMPONENT_TRINARY_ARG2, |
second, third))); |
} |
default: |
return NULL; |
} |
} |
} |
/* <expr-primary> ::= L <type> <(value) number> E |
::= L <type> <(value) float> E |
::= L <mangled-name> E |
*/ |
static struct demangle_component * |
d_expr_primary (struct d_info *di) |
{ |
struct demangle_component *ret; |
if (! d_check_char (di, 'L')) |
return NULL; |
if (d_peek_char (di) == '_' |
/* Workaround for G++ bug; see comment in write_template_arg. */ |
|| d_peek_char (di) == 'Z') |
ret = cplus_demangle_mangled_name (di, 0); |
else |
{ |
struct demangle_component *type; |
enum demangle_component_type t; |
const char *s; |
type = cplus_demangle_type (di); |
if (type == NULL) |
return NULL; |
/* If we have a type we know how to print, we aren't going to |
print the type name itself. */ |
if (type->type == DEMANGLE_COMPONENT_BUILTIN_TYPE |
&& type->u.s_builtin.type->print != D_PRINT_DEFAULT) |
di->expansion -= type->u.s_builtin.type->len; |
/* Rather than try to interpret the literal value, we just |
collect it as a string. Note that it's possible to have a |
floating point literal here. The ABI specifies that the |
format of such literals is machine independent. That's fine, |
but what's not fine is that versions of g++ up to 3.2 with |
-fabi-version=1 used upper case letters in the hex constant, |
and dumped out gcc's internal representation. That makes it |
hard to tell where the constant ends, and hard to dump the |
constant in any readable form anyhow. We don't attempt to |
handle these cases. */ |
t = DEMANGLE_COMPONENT_LITERAL; |
if (d_peek_char (di) == 'n') |
{ |
t = DEMANGLE_COMPONENT_LITERAL_NEG; |
d_advance (di, 1); |
} |
s = d_str (di); |
while (d_peek_char (di) != 'E') |
{ |
if (d_peek_char (di) == '\0') |
return NULL; |
d_advance (di, 1); |
} |
ret = d_make_comp (di, t, type, d_make_name (di, s, d_str (di) - s)); |
} |
if (! d_check_char (di, 'E')) |
return NULL; |
return ret; |
} |
/* <local-name> ::= Z <(function) encoding> E <(entity) name> [<discriminator>] |
::= Z <(function) encoding> E s [<discriminator>] |
::= Z <(function) encoding> E d [<parameter> number>] _ <entity name> |
*/ |
static struct demangle_component * |
d_local_name (struct d_info *di) |
{ |
struct demangle_component *function; |
if (! d_check_char (di, 'Z')) |
return NULL; |
function = d_encoding (di, 0); |
if (! d_check_char (di, 'E')) |
return NULL; |
if (d_peek_char (di) == 's') |
{ |
d_advance (di, 1); |
if (! d_discriminator (di)) |
return NULL; |
return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, |
d_make_name (di, "string literal", |
sizeof "string literal" - 1)); |
} |
else |
{ |
struct demangle_component *name; |
int num = -1; |
if (d_peek_char (di) == 'd') |
{ |
/* Default argument scope: d <number> _. */ |
d_advance (di, 1); |
num = d_compact_number (di); |
if (num < 0) |
return NULL; |
} |
name = d_name (di); |
if (name) |
switch (name->type) |
{ |
/* Lambdas and unnamed types have internal discriminators. */ |
case DEMANGLE_COMPONENT_LAMBDA: |
case DEMANGLE_COMPONENT_UNNAMED_TYPE: |
break; |
default: |
if (! d_discriminator (di)) |
return NULL; |
} |
if (num >= 0) |
name = d_make_default_arg (di, num, name); |
return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name); |
} |
} |
/* <discriminator> ::= _ <(non-negative) number> |
We demangle the discriminator, but we don't print it out. FIXME: |
We should print it out in verbose mode. */ |
static int |
d_discriminator (struct d_info *di) |
{ |
long discrim; |
if (d_peek_char (di) != '_') |
return 1; |
d_advance (di, 1); |
discrim = d_number (di); |
if (discrim < 0) |
return 0; |
return 1; |
} |
/* <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ */ |
static struct demangle_component * |
d_lambda (struct d_info *di) |
{ |
struct demangle_component *tl; |
struct demangle_component *ret; |
int num; |
if (! d_check_char (di, 'U')) |
return NULL; |
if (! d_check_char (di, 'l')) |
return NULL; |
tl = d_parmlist (di); |
if (tl == NULL) |
return NULL; |
if (! d_check_char (di, 'E')) |
return NULL; |
num = d_compact_number (di); |
if (num < 0) |
return NULL; |
ret = d_make_empty (di); |
if (ret) |
{ |
ret->type = DEMANGLE_COMPONENT_LAMBDA; |
ret->u.s_unary_num.sub = tl; |
ret->u.s_unary_num.num = num; |
} |
if (! d_add_substitution (di, ret)) |
return NULL; |
return ret; |
} |
/* <unnamed-type-name> ::= Ut [ <nonnegative number> ] _ */ |
static struct demangle_component * |
d_unnamed_type (struct d_info *di) |
{ |
struct demangle_component *ret; |
long num; |
if (! d_check_char (di, 'U')) |
return NULL; |
if (! d_check_char (di, 't')) |
return NULL; |
num = d_compact_number (di); |
if (num < 0) |
return NULL; |
ret = d_make_empty (di); |
if (ret) |
{ |
ret->type = DEMANGLE_COMPONENT_UNNAMED_TYPE; |
ret->u.s_number.number = num; |
} |
if (! d_add_substitution (di, ret)) |
return NULL; |
return ret; |
} |
/* <clone-suffix> ::= [ . <clone-type-identifier> ] [ . <nonnegative number> ]* |
*/ |
static struct demangle_component * |
d_clone_suffix (struct d_info *di, struct demangle_component *encoding) |
{ |
const char *suffix = d_str (di); |
const char *pend = suffix; |
struct demangle_component *n; |
if (*pend == '.' && (IS_LOWER (pend[1]) || pend[1] == '_')) |
{ |
pend += 2; |
while (IS_LOWER (*pend) || *pend == '_') |
++pend; |
} |
while (*pend == '.' && IS_DIGIT (pend[1])) |
{ |
pend += 2; |
while (IS_DIGIT (*pend)) |
++pend; |
} |
d_advance (di, pend - suffix); |
n = d_make_name (di, suffix, pend - suffix); |
return d_make_comp (di, DEMANGLE_COMPONENT_CLONE, encoding, n); |
} |
/* Add a new substitution. */ |
static int |
d_add_substitution (struct d_info *di, struct demangle_component *dc) |
{ |
if (dc == NULL) |
return 0; |
if (di->next_sub >= di->num_subs) |
return 0; |
di->subs[di->next_sub] = dc; |
++di->next_sub; |
return 1; |
} |
/* <substitution> ::= S <seq-id> _ |
::= S_ |
::= St |
::= Sa |
::= Sb |
::= Ss |
::= Si |
::= So |
::= Sd |
If PREFIX is non-zero, then this type is being used as a prefix in |
a qualified name. In this case, for the standard substitutions, we |
need to check whether we are being used as a prefix for a |
constructor or destructor, and return a full template name. |
Otherwise we will get something like std::iostream::~iostream() |
which does not correspond particularly well to any function which |
actually appears in the source. |
*/ |
static const struct d_standard_sub_info standard_subs[] = |
{ |
{ 't', NL ("std"), |
NL ("std"), |
NULL, 0 }, |
{ 'a', NL ("std::allocator"), |
NL ("std::allocator"), |
NL ("allocator") }, |
{ 'b', NL ("std::basic_string"), |
NL ("std::basic_string"), |
NL ("basic_string") }, |
{ 's', NL ("std::string"), |
NL ("std::basic_string<char, std::char_traits<char>, std::allocator<char> >"), |
NL ("basic_string") }, |
{ 'i', NL ("std::istream"), |
NL ("std::basic_istream<char, std::char_traits<char> >"), |
NL ("basic_istream") }, |
{ 'o', NL ("std::ostream"), |
NL ("std::basic_ostream<char, std::char_traits<char> >"), |
NL ("basic_ostream") }, |
{ 'd', NL ("std::iostream"), |
NL ("std::basic_iostream<char, std::char_traits<char> >"), |
NL ("basic_iostream") } |
}; |
static struct demangle_component * |
d_substitution (struct d_info *di, int prefix) |
{ |
char c; |
if (! d_check_char (di, 'S')) |
return NULL; |
c = d_next_char (di); |
if (c == '_' || IS_DIGIT (c) || IS_UPPER (c)) |
{ |
unsigned int id; |
id = 0; |
if (c != '_') |
{ |
do |
{ |
unsigned int new_id; |
if (IS_DIGIT (c)) |
new_id = id * 36 + c - '0'; |
else if (IS_UPPER (c)) |
new_id = id * 36 + c - 'A' + 10; |
else |
return NULL; |
if (new_id < id) |
return NULL; |
id = new_id; |
c = d_next_char (di); |
} |
while (c != '_'); |
++id; |
} |
if (id >= (unsigned int) di->next_sub) |
return NULL; |
++di->did_subs; |
return di->subs[id]; |
} |
else |
{ |
int verbose; |
const struct d_standard_sub_info *p; |
const struct d_standard_sub_info *pend; |
verbose = (di->options & DMGL_VERBOSE) != 0; |
if (! verbose && prefix) |
{ |
char peek; |
peek = d_peek_char (di); |
if (peek == 'C' || peek == 'D') |
verbose = 1; |
} |
pend = (&standard_subs[0] |
+ sizeof standard_subs / sizeof standard_subs[0]); |
for (p = &standard_subs[0]; p < pend; ++p) |
{ |
if (c == p->code) |
{ |
const char *s; |
int len; |
if (p->set_last_name != NULL) |
di->last_name = d_make_sub (di, p->set_last_name, |
p->set_last_name_len); |
if (verbose) |
{ |
s = p->full_expansion; |
len = p->full_len; |
} |
else |
{ |
s = p->simple_expansion; |
len = p->simple_len; |
} |
di->expansion += len; |
return d_make_sub (di, s, len); |
} |
} |
return NULL; |
} |
} |
/* Initialize a growable string. */ |
static void |
d_growable_string_init (struct d_growable_string *dgs, size_t estimate) |
{ |
dgs->buf = NULL; |
dgs->len = 0; |
dgs->alc = 0; |
dgs->allocation_failure = 0; |
if (estimate > 0) |
d_growable_string_resize (dgs, estimate); |
} |
/* Grow a growable string to a given size. */ |
static inline void |
d_growable_string_resize (struct d_growable_string *dgs, size_t need) |
{ |
size_t newalc; |
char *newbuf; |
if (dgs->allocation_failure) |
return; |
/* Start allocation at two bytes to avoid any possibility of confusion |
with the special value of 1 used as a return in *palc to indicate |
allocation failures. */ |
newalc = dgs->alc > 0 ? dgs->alc : 2; |
while (newalc < need) |
newalc <<= 1; |
newbuf = (char *) realloc (dgs->buf, newalc); |
if (newbuf == NULL) |
{ |
free (dgs->buf); |
dgs->buf = NULL; |
dgs->len = 0; |
dgs->alc = 0; |
dgs->allocation_failure = 1; |
return; |
} |
dgs->buf = newbuf; |
dgs->alc = newalc; |
} |
/* Append a buffer to a growable string. */ |
static inline void |
d_growable_string_append_buffer (struct d_growable_string *dgs, |
const char *s, size_t l) |
{ |
size_t need; |
need = dgs->len + l + 1; |
if (need > dgs->alc) |
d_growable_string_resize (dgs, need); |
if (dgs->allocation_failure) |
return; |
memcpy (dgs->buf + dgs->len, s, l); |
dgs->buf[dgs->len + l] = '\0'; |
dgs->len += l; |
} |
/* Bridge growable strings to the callback mechanism. */ |
static void |
d_growable_string_callback_adapter (const char *s, size_t l, void *opaque) |
{ |
struct d_growable_string *dgs = (struct d_growable_string*) opaque; |
d_growable_string_append_buffer (dgs, s, l); |
} |
/* Initialize a print information structure. */ |
static void |
d_print_init (struct d_print_info *dpi, demangle_callbackref callback, |
void *opaque) |
{ |
dpi->len = 0; |
dpi->last_char = '\0'; |
dpi->templates = NULL; |
dpi->modifiers = NULL; |
dpi->pack_index = 0; |
dpi->flush_count = 0; |
dpi->callback = callback; |
dpi->opaque = opaque; |
dpi->demangle_failure = 0; |
} |
/* Indicate that an error occurred during printing, and test for error. */ |
static inline void |
d_print_error (struct d_print_info *dpi) |
{ |
dpi->demangle_failure = 1; |
} |
static inline int |
d_print_saw_error (struct d_print_info *dpi) |
{ |
return dpi->demangle_failure != 0; |
} |
/* Flush buffered characters to the callback. */ |
static inline void |
d_print_flush (struct d_print_info *dpi) |
{ |
dpi->buf[dpi->len] = '\0'; |
dpi->callback (dpi->buf, dpi->len, dpi->opaque); |
dpi->len = 0; |
dpi->flush_count++; |
} |
/* Append characters and buffers for printing. */ |
static inline void |
d_append_char (struct d_print_info *dpi, char c) |
{ |
if (dpi->len == sizeof (dpi->buf) - 1) |
d_print_flush (dpi); |
dpi->buf[dpi->len++] = c; |
dpi->last_char = c; |
} |
static inline void |
d_append_buffer (struct d_print_info *dpi, const char *s, size_t l) |
{ |
size_t i; |
for (i = 0; i < l; i++) |
d_append_char (dpi, s[i]); |
} |
static inline void |
d_append_string (struct d_print_info *dpi, const char *s) |
{ |
d_append_buffer (dpi, s, strlen (s)); |
} |
static inline void |
d_append_num (struct d_print_info *dpi, long l) |
{ |
char buf[25]; |
sprintf (buf,"%ld", l); |
d_append_string (dpi, buf); |
} |
static inline char |
d_last_char (struct d_print_info *dpi) |
{ |
return dpi->last_char; |
} |
/* Turn components into a human readable string. OPTIONS is the |
options bits passed to the demangler. DC is the tree to print. |
CALLBACK is a function to call to flush demangled string segments |
as they fill the intermediate buffer, and OPAQUE is a generalized |
callback argument. On success, this returns 1. On failure, |
it returns 0, indicating a bad parse. It does not use heap |
memory to build an output string, so cannot encounter memory |
allocation failure. */ |
CP_STATIC_IF_GLIBCPP_V3 |
int |
cplus_demangle_print_callback (int options, |
const struct demangle_component *dc, |
demangle_callbackref callback, void *opaque) |
{ |
struct d_print_info dpi; |
d_print_init (&dpi, callback, opaque); |
d_print_comp (&dpi, options, dc); |
d_print_flush (&dpi); |
return ! d_print_saw_error (&dpi); |
} |
/* Turn components into a human readable string. OPTIONS is the |
options bits passed to the demangler. DC is the tree to print. |
ESTIMATE is a guess at the length of the result. This returns a |
string allocated by malloc, or NULL on error. On success, this |
sets *PALC to the size of the allocated buffer. On failure, this |
sets *PALC to 0 for a bad parse, or to 1 for a memory allocation |
failure. */ |
CP_STATIC_IF_GLIBCPP_V3 |
char * |
cplus_demangle_print (int options, const struct demangle_component *dc, |
int estimate, size_t *palc) |
{ |
struct d_growable_string dgs; |
d_growable_string_init (&dgs, estimate); |
if (! cplus_demangle_print_callback (options, dc, |
d_growable_string_callback_adapter, |
&dgs)) |
{ |
free (dgs.buf); |
*palc = 0; |
return NULL; |
} |
*palc = dgs.allocation_failure ? 1 : dgs.alc; |
return dgs.buf; |
} |
/* Returns the I'th element of the template arglist ARGS, or NULL on |
failure. */ |
static struct demangle_component * |
d_index_template_argument (struct demangle_component *args, int i) |
{ |
struct demangle_component *a; |
for (a = args; |
a != NULL; |
a = d_right (a)) |
{ |
if (a->type != DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) |
return NULL; |
if (i <= 0) |
break; |
--i; |
} |
if (i != 0 || a == NULL) |
return NULL; |
return d_left (a); |
} |
/* Returns the template argument from the current context indicated by DC, |
which is a DEMANGLE_COMPONENT_TEMPLATE_PARAM, or NULL. */ |
static struct demangle_component * |
d_lookup_template_argument (struct d_print_info *dpi, |
const struct demangle_component *dc) |
{ |
if (dpi->templates == NULL) |
{ |
d_print_error (dpi); |
return NULL; |
} |
return d_index_template_argument |
(d_right (dpi->templates->template_decl), |
dc->u.s_number.number); |
} |
/* Returns a template argument pack used in DC (any will do), or NULL. */ |
static struct demangle_component * |
d_find_pack (struct d_print_info *dpi, |
const struct demangle_component *dc) |
{ |
struct demangle_component *a; |
if (dc == NULL) |
return NULL; |
switch (dc->type) |
{ |
case DEMANGLE_COMPONENT_TEMPLATE_PARAM: |
a = d_lookup_template_argument (dpi, dc); |
if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) |
return a; |
return NULL; |
case DEMANGLE_COMPONENT_PACK_EXPANSION: |
return NULL; |
case DEMANGLE_COMPONENT_LAMBDA: |
case DEMANGLE_COMPONENT_NAME: |
case DEMANGLE_COMPONENT_TAGGED_NAME: |
case DEMANGLE_COMPONENT_OPERATOR: |
case DEMANGLE_COMPONENT_BUILTIN_TYPE: |
case DEMANGLE_COMPONENT_SUB_STD: |
case DEMANGLE_COMPONENT_CHARACTER: |
case DEMANGLE_COMPONENT_FUNCTION_PARAM: |
case DEMANGLE_COMPONENT_UNNAMED_TYPE: |
return NULL; |
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: |
return d_find_pack (dpi, dc->u.s_extended_operator.name); |
case DEMANGLE_COMPONENT_CTOR: |
return d_find_pack (dpi, dc->u.s_ctor.name); |
case DEMANGLE_COMPONENT_DTOR: |
return d_find_pack (dpi, dc->u.s_dtor.name); |
default: |
a = d_find_pack (dpi, d_left (dc)); |
if (a) |
return a; |
return d_find_pack (dpi, d_right (dc)); |
} |
} |
/* Returns the length of the template argument pack DC. */ |
static int |
d_pack_length (const struct demangle_component *dc) |
{ |
int count = 0; |
while (dc && dc->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST |
&& d_left (dc) != NULL) |
{ |
++count; |
dc = d_right (dc); |
} |
return count; |
} |
/* DC is a component of a mangled expression. Print it, wrapped in parens |
if needed. */ |
static void |
d_print_subexpr (struct d_print_info *dpi, int options, |
const struct demangle_component *dc) |
{ |
int simple = 0; |
if (dc->type == DEMANGLE_COMPONENT_NAME |
|| dc->type == DEMANGLE_COMPONENT_QUAL_NAME |
|| dc->type == DEMANGLE_COMPONENT_INITIALIZER_LIST |
|| dc->type == DEMANGLE_COMPONENT_FUNCTION_PARAM) |
simple = 1; |
if (!simple) |
d_append_char (dpi, '('); |
d_print_comp (dpi, options, dc); |
if (!simple) |
d_append_char (dpi, ')'); |
} |
/* Subroutine to handle components. */ |
static void |
d_print_comp (struct d_print_info *dpi, int options, |
const struct demangle_component *dc) |
{ |
/* Magic variable to let reference smashing skip over the next modifier |
without needing to modify *dc. */ |
const struct demangle_component *mod_inner = NULL; |
if (dc == NULL) |
{ |
d_print_error (dpi); |
return; |
} |
if (d_print_saw_error (dpi)) |
return; |
switch (dc->type) |
{ |
case DEMANGLE_COMPONENT_NAME: |
if ((options & DMGL_JAVA) == 0) |
d_append_buffer (dpi, dc->u.s_name.s, dc->u.s_name.len); |
else |
d_print_java_identifier (dpi, dc->u.s_name.s, dc->u.s_name.len); |
return; |
case DEMANGLE_COMPONENT_TAGGED_NAME: |
d_print_comp (dpi, options, d_left (dc)); |
d_append_string (dpi, "[abi:"); |
d_print_comp (dpi, options, d_right (dc)); |
d_append_char (dpi, ']'); |
return; |
case DEMANGLE_COMPONENT_QUAL_NAME: |
case DEMANGLE_COMPONENT_LOCAL_NAME: |
d_print_comp (dpi, options, d_left (dc)); |
if ((options & DMGL_JAVA) == 0) |
d_append_string (dpi, "::"); |
else |
d_append_char (dpi, '.'); |
{ |
struct demangle_component *local_name = d_right (dc); |
if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG) |
{ |
d_append_string (dpi, "{default arg#"); |
d_append_num (dpi, local_name->u.s_unary_num.num + 1); |
d_append_string (dpi, "}::"); |
local_name = local_name->u.s_unary_num.sub; |
} |
d_print_comp (dpi, options, local_name); |
} |
return; |
case DEMANGLE_COMPONENT_TYPED_NAME: |
{ |
struct d_print_mod *hold_modifiers; |
struct demangle_component *typed_name; |
struct d_print_mod adpm[4]; |
unsigned int i; |
struct d_print_template dpt; |
/* Pass the name down to the type so that it can be printed in |
the right place for the type. We also have to pass down |
any CV-qualifiers, which apply to the this parameter. */ |
hold_modifiers = dpi->modifiers; |
dpi->modifiers = 0; |
i = 0; |
typed_name = d_left (dc); |
while (typed_name != NULL) |
{ |
if (i >= sizeof adpm / sizeof adpm[0]) |
{ |
d_print_error (dpi); |
return; |
} |
adpm[i].next = dpi->modifiers; |
dpi->modifiers = &adpm[i]; |
adpm[i].mod = typed_name; |
adpm[i].printed = 0; |
adpm[i].templates = dpi->templates; |
++i; |
if (typed_name->type != DEMANGLE_COMPONENT_RESTRICT_THIS |
&& typed_name->type != DEMANGLE_COMPONENT_VOLATILE_THIS |
&& typed_name->type != DEMANGLE_COMPONENT_CONST_THIS |
&& typed_name->type != DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS |
&& typed_name->type != DEMANGLE_COMPONENT_REFERENCE_THIS) |
break; |
typed_name = d_left (typed_name); |
} |
if (typed_name == NULL) |
{ |
d_print_error (dpi); |
return; |
} |
/* If typed_name is a template, then it applies to the |
function type as well. */ |
if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE) |
{ |
dpt.next = dpi->templates; |
dpi->templates = &dpt; |
dpt.template_decl = typed_name; |
} |
/* If typed_name is a DEMANGLE_COMPONENT_LOCAL_NAME, then |
there may be CV-qualifiers on its right argument which |
really apply here; this happens when parsing a class which |
is local to a function. */ |
if (typed_name->type == DEMANGLE_COMPONENT_LOCAL_NAME) |
{ |
struct demangle_component *local_name; |
local_name = d_right (typed_name); |
if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG) |
local_name = local_name->u.s_unary_num.sub; |
while (local_name->type == DEMANGLE_COMPONENT_RESTRICT_THIS |
|| local_name->type == DEMANGLE_COMPONENT_VOLATILE_THIS |
|| local_name->type == DEMANGLE_COMPONENT_CONST_THIS |
|| local_name->type == DEMANGLE_COMPONENT_REFERENCE_THIS |
|| (local_name->type |
== DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)) |
{ |
if (i >= sizeof adpm / sizeof adpm[0]) |
{ |
d_print_error (dpi); |
return; |
} |
adpm[i] = adpm[i - 1]; |
adpm[i].next = &adpm[i - 1]; |
dpi->modifiers = &adpm[i]; |
adpm[i - 1].mod = local_name; |
adpm[i - 1].printed = 0; |
adpm[i - 1].templates = dpi->templates; |
++i; |
local_name = d_left (local_name); |
} |
} |
d_print_comp (dpi, options, d_right (dc)); |
if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE) |
dpi->templates = dpt.next; |
/* If the modifiers didn't get printed by the type, print them |
now. */ |
while (i > 0) |
{ |
--i; |
if (! adpm[i].printed) |
{ |
d_append_char (dpi, ' '); |
d_print_mod (dpi, options, adpm[i].mod); |
} |
} |
dpi->modifiers = hold_modifiers; |
return; |
} |
case DEMANGLE_COMPONENT_TEMPLATE: |
{ |
struct d_print_mod *hold_dpm; |
struct demangle_component *dcl; |
/* Don't push modifiers into a template definition. Doing so |
could give the wrong definition for a template argument. |
Instead, treat the template essentially as a name. */ |
hold_dpm = dpi->modifiers; |
dpi->modifiers = NULL; |
dcl = d_left (dc); |
if ((options & DMGL_JAVA) != 0 |
&& dcl->type == DEMANGLE_COMPONENT_NAME |
&& dcl->u.s_name.len == 6 |
&& strncmp (dcl->u.s_name.s, "JArray", 6) == 0) |
{ |
/* Special-case Java arrays, so that JArray<TYPE> appears |
instead as TYPE[]. */ |
d_print_comp (dpi, options, d_right (dc)); |
d_append_string (dpi, "[]"); |
} |
else |
{ |
d_print_comp (dpi, options, dcl); |
if (d_last_char (dpi) == '<') |
d_append_char (dpi, ' '); |
d_append_char (dpi, '<'); |
d_print_comp (dpi, options, d_right (dc)); |
/* Avoid generating two consecutive '>' characters, to avoid |
the C++ syntactic ambiguity. */ |
if (d_last_char (dpi) == '>') |
d_append_char (dpi, ' '); |
d_append_char (dpi, '>'); |
} |
dpi->modifiers = hold_dpm; |
return; |
} |
case DEMANGLE_COMPONENT_TEMPLATE_PARAM: |
{ |
struct d_print_template *hold_dpt; |
struct demangle_component *a = d_lookup_template_argument (dpi, dc); |
if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) |
a = d_index_template_argument (a, dpi->pack_index); |
if (a == NULL) |
{ |
d_print_error (dpi); |
return; |
} |
/* While processing this parameter, we need to pop the list of |
templates. This is because the template parameter may |
itself be a reference to a parameter of an outer |
template. */ |
hold_dpt = dpi->templates; |
dpi->templates = hold_dpt->next; |
d_print_comp (dpi, options, a); |
dpi->templates = hold_dpt; |
return; |
} |
case DEMANGLE_COMPONENT_CTOR: |
d_print_comp (dpi, options, dc->u.s_ctor.name); |
return; |
case DEMANGLE_COMPONENT_DTOR: |
d_append_char (dpi, '~'); |
d_print_comp (dpi, options, dc->u.s_dtor.name); |
return; |
case DEMANGLE_COMPONENT_VTABLE: |
d_append_string (dpi, "vtable for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_VTT: |
d_append_string (dpi, "VTT for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: |
d_append_string (dpi, "construction vtable for "); |
d_print_comp (dpi, options, d_left (dc)); |
d_append_string (dpi, "-in-"); |
d_print_comp (dpi, options, d_right (dc)); |
return; |
case DEMANGLE_COMPONENT_TYPEINFO: |
d_append_string (dpi, "typeinfo for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_TYPEINFO_NAME: |
d_append_string (dpi, "typeinfo name for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_TYPEINFO_FN: |
d_append_string (dpi, "typeinfo fn for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_THUNK: |
d_append_string (dpi, "non-virtual thunk to "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_VIRTUAL_THUNK: |
d_append_string (dpi, "virtual thunk to "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_COVARIANT_THUNK: |
d_append_string (dpi, "covariant return thunk to "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_JAVA_CLASS: |
d_append_string (dpi, "java Class for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_GUARD: |
d_append_string (dpi, "guard variable for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_TLS_INIT: |
d_append_string (dpi, "TLS init function for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_TLS_WRAPPER: |
d_append_string (dpi, "TLS wrapper function for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_REFTEMP: |
d_append_string (dpi, "reference temporary #"); |
d_print_comp (dpi, options, d_right (dc)); |
d_append_string (dpi, " for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_HIDDEN_ALIAS: |
d_append_string (dpi, "hidden alias for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_TRANSACTION_CLONE: |
d_append_string (dpi, "transaction clone for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_NONTRANSACTION_CLONE: |
d_append_string (dpi, "non-transaction clone for "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_SUB_STD: |
d_append_buffer (dpi, dc->u.s_string.string, dc->u.s_string.len); |
return; |
case DEMANGLE_COMPONENT_RESTRICT: |
case DEMANGLE_COMPONENT_VOLATILE: |
case DEMANGLE_COMPONENT_CONST: |
{ |
struct d_print_mod *pdpm; |
/* When printing arrays, it's possible to have cases where the |
same CV-qualifier gets pushed on the stack multiple times. |
We only need to print it once. */ |
for (pdpm = dpi->modifiers; pdpm != NULL; pdpm = pdpm->next) |
{ |
if (! pdpm->printed) |
{ |
if (pdpm->mod->type != DEMANGLE_COMPONENT_RESTRICT |
&& pdpm->mod->type != DEMANGLE_COMPONENT_VOLATILE |
&& pdpm->mod->type != DEMANGLE_COMPONENT_CONST) |
break; |
if (pdpm->mod->type == dc->type) |
{ |
d_print_comp (dpi, options, d_left (dc)); |
return; |
} |
} |
} |
} |
goto modifier; |
case DEMANGLE_COMPONENT_REFERENCE: |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE: |
{ |
/* Handle reference smashing: & + && = &. */ |
const struct demangle_component *sub = d_left (dc); |
if (sub->type == DEMANGLE_COMPONENT_TEMPLATE_PARAM) |
{ |
struct demangle_component *a = d_lookup_template_argument (dpi, sub); |
if (a && a->type == DEMANGLE_COMPONENT_TEMPLATE_ARGLIST) |
a = d_index_template_argument (a, dpi->pack_index); |
if (a == NULL) |
{ |
d_print_error (dpi); |
return; |
} |
sub = a; |
} |
if (sub->type == DEMANGLE_COMPONENT_REFERENCE |
|| sub->type == dc->type) |
dc = sub; |
else if (sub->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE) |
mod_inner = d_left (sub); |
} |
/* Fall through. */ |
case DEMANGLE_COMPONENT_RESTRICT_THIS: |
case DEMANGLE_COMPONENT_VOLATILE_THIS: |
case DEMANGLE_COMPONENT_CONST_THIS: |
case DEMANGLE_COMPONENT_REFERENCE_THIS: |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: |
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: |
case DEMANGLE_COMPONENT_POINTER: |
case DEMANGLE_COMPONENT_COMPLEX: |
case DEMANGLE_COMPONENT_IMAGINARY: |
modifier: |
{ |
/* We keep a list of modifiers on the stack. */ |
struct d_print_mod dpm; |
dpm.next = dpi->modifiers; |
dpi->modifiers = &dpm; |
dpm.mod = dc; |
dpm.printed = 0; |
dpm.templates = dpi->templates; |
if (!mod_inner) |
mod_inner = d_left (dc); |
d_print_comp (dpi, options, mod_inner); |
/* If the modifier didn't get printed by the type, print it |
now. */ |
if (! dpm.printed) |
d_print_mod (dpi, options, dc); |
dpi->modifiers = dpm.next; |
return; |
} |
case DEMANGLE_COMPONENT_BUILTIN_TYPE: |
if ((options & DMGL_JAVA) == 0) |
d_append_buffer (dpi, dc->u.s_builtin.type->name, |
dc->u.s_builtin.type->len); |
else |
d_append_buffer (dpi, dc->u.s_builtin.type->java_name, |
dc->u.s_builtin.type->java_len); |
return; |
case DEMANGLE_COMPONENT_VENDOR_TYPE: |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_FUNCTION_TYPE: |
{ |
if ((options & DMGL_RET_POSTFIX) != 0) |
d_print_function_type (dpi, |
options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), |
dc, dpi->modifiers); |
/* Print return type if present */ |
if (d_left (dc) != NULL && (options & DMGL_RET_POSTFIX) != 0) |
d_print_comp (dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), |
d_left (dc)); |
else if (d_left (dc) != NULL && (options & DMGL_RET_DROP) == 0) |
{ |
struct d_print_mod dpm; |
/* We must pass this type down as a modifier in order to |
print it in the right location. */ |
dpm.next = dpi->modifiers; |
dpi->modifiers = &dpm; |
dpm.mod = dc; |
dpm.printed = 0; |
dpm.templates = dpi->templates; |
d_print_comp (dpi, options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), |
d_left (dc)); |
dpi->modifiers = dpm.next; |
if (dpm.printed) |
return; |
/* In standard prefix notation, there is a space between the |
return type and the function signature. */ |
if ((options & DMGL_RET_POSTFIX) == 0) |
d_append_char (dpi, ' '); |
} |
if ((options & DMGL_RET_POSTFIX) == 0) |
d_print_function_type (dpi, |
options & ~(DMGL_RET_POSTFIX | DMGL_RET_DROP), |
dc, dpi->modifiers); |
return; |
} |
case DEMANGLE_COMPONENT_ARRAY_TYPE: |
{ |
struct d_print_mod *hold_modifiers; |
struct d_print_mod adpm[4]; |
unsigned int i; |
struct d_print_mod *pdpm; |
/* We must pass this type down as a modifier in order to print |
multi-dimensional arrays correctly. If the array itself is |
CV-qualified, we act as though the element type were |
CV-qualified. We do this by copying the modifiers down |
rather than fiddling pointers, so that we don't wind up |
with a d_print_mod higher on the stack pointing into our |
stack frame after we return. */ |
hold_modifiers = dpi->modifiers; |
adpm[0].next = hold_modifiers; |
dpi->modifiers = &adpm[0]; |
adpm[0].mod = dc; |
adpm[0].printed = 0; |
adpm[0].templates = dpi->templates; |
i = 1; |
pdpm = hold_modifiers; |
while (pdpm != NULL |
&& (pdpm->mod->type == DEMANGLE_COMPONENT_RESTRICT |
|| pdpm->mod->type == DEMANGLE_COMPONENT_VOLATILE |
|| pdpm->mod->type == DEMANGLE_COMPONENT_CONST)) |
{ |
if (! pdpm->printed) |
{ |
if (i >= sizeof adpm / sizeof adpm[0]) |
{ |
d_print_error (dpi); |
return; |
} |
adpm[i] = *pdpm; |
adpm[i].next = dpi->modifiers; |
dpi->modifiers = &adpm[i]; |
pdpm->printed = 1; |
++i; |
} |
pdpm = pdpm->next; |
} |
d_print_comp (dpi, options, d_right (dc)); |
dpi->modifiers = hold_modifiers; |
if (adpm[0].printed) |
return; |
while (i > 1) |
{ |
--i; |
d_print_mod (dpi, options, adpm[i].mod); |
} |
d_print_array_type (dpi, options, dc, dpi->modifiers); |
return; |
} |
case DEMANGLE_COMPONENT_PTRMEM_TYPE: |
case DEMANGLE_COMPONENT_VECTOR_TYPE: |
{ |
struct d_print_mod dpm; |
dpm.next = dpi->modifiers; |
dpi->modifiers = &dpm; |
dpm.mod = dc; |
dpm.printed = 0; |
dpm.templates = dpi->templates; |
d_print_comp (dpi, options, d_right (dc)); |
/* If the modifier didn't get printed by the type, print it |
now. */ |
if (! dpm.printed) |
d_print_mod (dpi, options, dc); |
dpi->modifiers = dpm.next; |
return; |
} |
case DEMANGLE_COMPONENT_FIXED_TYPE: |
if (dc->u.s_fixed.sat) |
d_append_string (dpi, "_Sat "); |
/* Don't print "int _Accum". */ |
if (dc->u.s_fixed.length->u.s_builtin.type |
!= &cplus_demangle_builtin_types['i'-'a']) |
{ |
d_print_comp (dpi, options, dc->u.s_fixed.length); |
d_append_char (dpi, ' '); |
} |
if (dc->u.s_fixed.accum) |
d_append_string (dpi, "_Accum"); |
else |
d_append_string (dpi, "_Fract"); |
return; |
case DEMANGLE_COMPONENT_ARGLIST: |
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: |
if (d_left (dc) != NULL) |
d_print_comp (dpi, options, d_left (dc)); |
if (d_right (dc) != NULL) |
{ |
size_t len; |
unsigned long int flush_count; |
/* Make sure ", " isn't flushed by d_append_string, otherwise |
dpi->len -= 2 wouldn't work. */ |
if (dpi->len >= sizeof (dpi->buf) - 2) |
d_print_flush (dpi); |
d_append_string (dpi, ", "); |
len = dpi->len; |
flush_count = dpi->flush_count; |
d_print_comp (dpi, options, d_right (dc)); |
/* If that didn't print anything (which can happen with empty |
template argument packs), remove the comma and space. */ |
if (dpi->flush_count == flush_count && dpi->len == len) |
dpi->len -= 2; |
} |
return; |
case DEMANGLE_COMPONENT_INITIALIZER_LIST: |
{ |
struct demangle_component *type = d_left (dc); |
struct demangle_component *list = d_right (dc); |
if (type) |
d_print_comp (dpi, options, type); |
d_append_char (dpi, '{'); |
d_print_comp (dpi, options, list); |
d_append_char (dpi, '}'); |
} |
return; |
case DEMANGLE_COMPONENT_OPERATOR: |
{ |
const struct demangle_operator_info *op = dc->u.s_operator.op; |
int len = op->len; |
d_append_string (dpi, "operator"); |
/* Add a space before new/delete. */ |
if (IS_LOWER (op->name[0])) |
d_append_char (dpi, ' '); |
/* Omit a trailing space. */ |
if (op->name[len-1] == ' ') |
--len; |
d_append_buffer (dpi, op->name, len); |
return; |
} |
case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: |
d_append_string (dpi, "operator "); |
d_print_comp (dpi, options, dc->u.s_extended_operator.name); |
return; |
case DEMANGLE_COMPONENT_CAST: |
d_append_string (dpi, "operator "); |
d_print_cast (dpi, options, dc); |
return; |
case DEMANGLE_COMPONENT_NULLARY: |
d_print_expr_op (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_UNARY: |
{ |
struct demangle_component *op = d_left (dc); |
struct demangle_component *operand = d_right (dc); |
const char *code = NULL; |
if (op->type == DEMANGLE_COMPONENT_OPERATOR) |
{ |
code = op->u.s_operator.op->code; |
if (!strcmp (code, "ad")) |
{ |
/* Don't print the argument list for the address of a |
function. */ |
if (operand->type == DEMANGLE_COMPONENT_TYPED_NAME |
&& d_left (operand)->type == DEMANGLE_COMPONENT_QUAL_NAME |
&& d_right (operand)->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) |
operand = d_left (operand); |
} |
if (operand->type == DEMANGLE_COMPONENT_BINARY_ARGS) |
{ |
/* This indicates a suffix operator. */ |
operand = d_left (operand); |
d_print_subexpr (dpi, options, operand); |
d_print_expr_op (dpi, options, op); |
return; |
} |
} |
if (op->type != DEMANGLE_COMPONENT_CAST) |
d_print_expr_op (dpi, options, op); |
else |
{ |
d_append_char (dpi, '('); |
d_print_cast (dpi, options, op); |
d_append_char (dpi, ')'); |
} |
if (code && !strcmp (code, "gs")) |
/* Avoid parens after '::'. */ |
d_print_comp (dpi, options, operand); |
else if (code && !strcmp (code, "st")) |
/* Always print parens for sizeof (type). */ |
{ |
d_append_char (dpi, '('); |
d_print_comp (dpi, options, operand); |
d_append_char (dpi, ')'); |
} |
else |
d_print_subexpr (dpi, options, operand); |
} |
return; |
case DEMANGLE_COMPONENT_BINARY: |
if (d_right (dc)->type != DEMANGLE_COMPONENT_BINARY_ARGS) |
{ |
d_print_error (dpi); |
return; |
} |
if (op_is_new_cast (d_left (dc))) |
{ |
d_print_expr_op (dpi, options, d_left (dc)); |
d_append_char (dpi, '<'); |
d_print_comp (dpi, options, d_left (d_right (dc))); |
d_append_string (dpi, ">("); |
d_print_comp (dpi, options, d_right (d_right (dc))); |
d_append_char (dpi, ')'); |
return; |
} |
/* We wrap an expression which uses the greater-than operator in |
an extra layer of parens so that it does not get confused |
with the '>' which ends the template parameters. */ |
if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR |
&& d_left (dc)->u.s_operator.op->len == 1 |
&& d_left (dc)->u.s_operator.op->name[0] == '>') |
d_append_char (dpi, '('); |
if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") == 0 |
&& d_left (d_right (dc))->type == DEMANGLE_COMPONENT_TYPED_NAME) |
{ |
/* Function call used in an expression should not have printed types |
of the function arguments. Values of the function arguments still |
get printed below. */ |
const struct demangle_component *func = d_left (d_right (dc)); |
if (d_right (func)->type != DEMANGLE_COMPONENT_FUNCTION_TYPE) |
d_print_error (dpi); |
d_print_subexpr (dpi, options, d_left (func)); |
} |
else |
d_print_subexpr (dpi, options, d_left (d_right (dc))); |
if (strcmp (d_left (dc)->u.s_operator.op->code, "ix") == 0) |
{ |
d_append_char (dpi, '['); |
d_print_comp (dpi, options, d_right (d_right (dc))); |
d_append_char (dpi, ']'); |
} |
else |
{ |
if (strcmp (d_left (dc)->u.s_operator.op->code, "cl") != 0) |
d_print_expr_op (dpi, options, d_left (dc)); |
d_print_subexpr (dpi, options, d_right (d_right (dc))); |
} |
if (d_left (dc)->type == DEMANGLE_COMPONENT_OPERATOR |
&& d_left (dc)->u.s_operator.op->len == 1 |
&& d_left (dc)->u.s_operator.op->name[0] == '>') |
d_append_char (dpi, ')'); |
return; |
case DEMANGLE_COMPONENT_BINARY_ARGS: |
/* We should only see this as part of DEMANGLE_COMPONENT_BINARY. */ |
d_print_error (dpi); |
return; |
case DEMANGLE_COMPONENT_TRINARY: |
if (d_right (dc)->type != DEMANGLE_COMPONENT_TRINARY_ARG1 |
|| d_right (d_right (dc))->type != DEMANGLE_COMPONENT_TRINARY_ARG2) |
{ |
d_print_error (dpi); |
return; |
} |
{ |
struct demangle_component *op = d_left (dc); |
struct demangle_component *first = d_left (d_right (dc)); |
struct demangle_component *second = d_left (d_right (d_right (dc))); |
struct demangle_component *third = d_right (d_right (d_right (dc))); |
if (!strcmp (op->u.s_operator.op->code, "qu")) |
{ |
d_print_subexpr (dpi, options, first); |
d_print_expr_op (dpi, options, op); |
d_print_subexpr (dpi, options, second); |
d_append_string (dpi, " : "); |
d_print_subexpr (dpi, options, third); |
} |
else |
{ |
d_append_string (dpi, "new "); |
if (d_left (first) != NULL) |
{ |
d_print_subexpr (dpi, options, first); |
d_append_char (dpi, ' '); |
} |
d_print_comp (dpi, options, second); |
if (third) |
d_print_subexpr (dpi, options, third); |
} |
} |
return; |
case DEMANGLE_COMPONENT_TRINARY_ARG1: |
case DEMANGLE_COMPONENT_TRINARY_ARG2: |
/* We should only see these are part of DEMANGLE_COMPONENT_TRINARY. */ |
d_print_error (dpi); |
return; |
case DEMANGLE_COMPONENT_LITERAL: |
case DEMANGLE_COMPONENT_LITERAL_NEG: |
{ |
enum d_builtin_type_print tp; |
/* For some builtin types, produce simpler output. */ |
tp = D_PRINT_DEFAULT; |
if (d_left (dc)->type == DEMANGLE_COMPONENT_BUILTIN_TYPE) |
{ |
tp = d_left (dc)->u.s_builtin.type->print; |
switch (tp) |
{ |
case D_PRINT_INT: |
case D_PRINT_UNSIGNED: |
case D_PRINT_LONG: |
case D_PRINT_UNSIGNED_LONG: |
case D_PRINT_LONG_LONG: |
case D_PRINT_UNSIGNED_LONG_LONG: |
if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME) |
{ |
if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG) |
d_append_char (dpi, '-'); |
d_print_comp (dpi, options, d_right (dc)); |
switch (tp) |
{ |
default: |
break; |
case D_PRINT_UNSIGNED: |
d_append_char (dpi, 'u'); |
break; |
case D_PRINT_LONG: |
d_append_char (dpi, 'l'); |
break; |
case D_PRINT_UNSIGNED_LONG: |
d_append_string (dpi, "ul"); |
break; |
case D_PRINT_LONG_LONG: |
d_append_string (dpi, "ll"); |
break; |
case D_PRINT_UNSIGNED_LONG_LONG: |
d_append_string (dpi, "ull"); |
break; |
} |
return; |
} |
break; |
case D_PRINT_BOOL: |
if (d_right (dc)->type == DEMANGLE_COMPONENT_NAME |
&& d_right (dc)->u.s_name.len == 1 |
&& dc->type == DEMANGLE_COMPONENT_LITERAL) |
{ |
switch (d_right (dc)->u.s_name.s[0]) |
{ |
case '0': |
d_append_string (dpi, "false"); |
return; |
case '1': |
d_append_string (dpi, "true"); |
return; |
default: |
break; |
} |
} |
break; |
default: |
break; |
} |
} |
d_append_char (dpi, '('); |
d_print_comp (dpi, options, d_left (dc)); |
d_append_char (dpi, ')'); |
if (dc->type == DEMANGLE_COMPONENT_LITERAL_NEG) |
d_append_char (dpi, '-'); |
if (tp == D_PRINT_FLOAT) |
d_append_char (dpi, '['); |
d_print_comp (dpi, options, d_right (dc)); |
if (tp == D_PRINT_FLOAT) |
d_append_char (dpi, ']'); |
} |
return; |
case DEMANGLE_COMPONENT_NUMBER: |
d_append_num (dpi, dc->u.s_number.number); |
return; |
case DEMANGLE_COMPONENT_JAVA_RESOURCE: |
d_append_string (dpi, "java resource "); |
d_print_comp (dpi, options, d_left (dc)); |
return; |
case DEMANGLE_COMPONENT_COMPOUND_NAME: |
d_print_comp (dpi, options, d_left (dc)); |
d_print_comp (dpi, options, d_right (dc)); |
return; |
case DEMANGLE_COMPONENT_CHARACTER: |
d_append_char (dpi, dc->u.s_character.character); |
return; |
case DEMANGLE_COMPONENT_DECLTYPE: |
d_append_string (dpi, "decltype ("); |
d_print_comp (dpi, options, d_left (dc)); |
d_append_char (dpi, ')'); |
return; |
case DEMANGLE_COMPONENT_PACK_EXPANSION: |
{ |
int len; |
int i; |
struct demangle_component *a = d_find_pack (dpi, d_left (dc)); |
if (a == NULL) |
{ |
/* d_find_pack won't find anything if the only packs involved |
in this expansion are function parameter packs; in that |
case, just print the pattern and "...". */ |
d_print_subexpr (dpi, options, d_left (dc)); |
d_append_string (dpi, "..."); |
return; |
} |
len = d_pack_length (a); |
dc = d_left (dc); |
for (i = 0; i < len; ++i) |
{ |
dpi->pack_index = i; |
d_print_comp (dpi, options, dc); |
if (i < len-1) |
d_append_string (dpi, ", "); |
} |
} |
return; |
case DEMANGLE_COMPONENT_FUNCTION_PARAM: |
{ |
long num = dc->u.s_number.number; |
if (num == 0) |
d_append_string (dpi, "this"); |
else |
{ |
d_append_string (dpi, "{parm#"); |
d_append_num (dpi, num); |
d_append_char (dpi, '}'); |
} |
} |
return; |
case DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS: |
d_append_string (dpi, "global constructors keyed to "); |
d_print_comp (dpi, options, dc->u.s_binary.left); |
return; |
case DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS: |
d_append_string (dpi, "global destructors keyed to "); |
d_print_comp (dpi, options, dc->u.s_binary.left); |
return; |
case DEMANGLE_COMPONENT_LAMBDA: |
d_append_string (dpi, "{lambda("); |
d_print_comp (dpi, options, dc->u.s_unary_num.sub); |
d_append_string (dpi, ")#"); |
d_append_num (dpi, dc->u.s_unary_num.num + 1); |
d_append_char (dpi, '}'); |
return; |
case DEMANGLE_COMPONENT_UNNAMED_TYPE: |
d_append_string (dpi, "{unnamed type#"); |
d_append_num (dpi, dc->u.s_number.number + 1); |
d_append_char (dpi, '}'); |
return; |
case DEMANGLE_COMPONENT_CLONE: |
d_print_comp (dpi, options, d_left (dc)); |
d_append_string (dpi, " [clone "); |
d_print_comp (dpi, options, d_right (dc)); |
d_append_char (dpi, ']'); |
return; |
default: |
d_print_error (dpi); |
return; |
} |
} |
/* Print a Java dentifier. For Java we try to handle encoded extended |
Unicode characters. The C++ ABI doesn't mention Unicode encoding, |
so we don't it for C++. Characters are encoded as |
__U<hex-char>+_. */ |
static void |
d_print_java_identifier (struct d_print_info *dpi, const char *name, int len) |
{ |
const char *p; |
const char *end; |
end = name + len; |
for (p = name; p < end; ++p) |
{ |
if (end - p > 3 |
&& p[0] == '_' |
&& p[1] == '_' |
&& p[2] == 'U') |
{ |
unsigned long c; |
const char *q; |
c = 0; |
for (q = p + 3; q < end; ++q) |
{ |
int dig; |
if (IS_DIGIT (*q)) |
dig = *q - '0'; |
else if (*q >= 'A' && *q <= 'F') |
dig = *q - 'A' + 10; |
else if (*q >= 'a' && *q <= 'f') |
dig = *q - 'a' + 10; |
else |
break; |
c = c * 16 + dig; |
} |
/* If the Unicode character is larger than 256, we don't try |
to deal with it here. FIXME. */ |
if (q < end && *q == '_' && c < 256) |
{ |
d_append_char (dpi, c); |
p = q; |
continue; |
} |
} |
d_append_char (dpi, *p); |
} |
} |
/* Print a list of modifiers. SUFFIX is 1 if we are printing |
qualifiers on this after printing a function. */ |
static void |
d_print_mod_list (struct d_print_info *dpi, int options, |
struct d_print_mod *mods, int suffix) |
{ |
struct d_print_template *hold_dpt; |
if (mods == NULL || d_print_saw_error (dpi)) |
return; |
if (mods->printed |
|| (! suffix |
&& (mods->mod->type == DEMANGLE_COMPONENT_RESTRICT_THIS |
|| mods->mod->type == DEMANGLE_COMPONENT_VOLATILE_THIS |
|| mods->mod->type == DEMANGLE_COMPONENT_CONST_THIS |
|| mods->mod->type == DEMANGLE_COMPONENT_REFERENCE_THIS |
|| (mods->mod->type |
== DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)))) |
{ |
d_print_mod_list (dpi, options, mods->next, suffix); |
return; |
} |
mods->printed = 1; |
hold_dpt = dpi->templates; |
dpi->templates = mods->templates; |
if (mods->mod->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) |
{ |
d_print_function_type (dpi, options, mods->mod, mods->next); |
dpi->templates = hold_dpt; |
return; |
} |
else if (mods->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE) |
{ |
d_print_array_type (dpi, options, mods->mod, mods->next); |
dpi->templates = hold_dpt; |
return; |
} |
else if (mods->mod->type == DEMANGLE_COMPONENT_LOCAL_NAME) |
{ |
struct d_print_mod *hold_modifiers; |
struct demangle_component *dc; |
/* When this is on the modifier stack, we have pulled any |
qualifiers off the right argument already. Otherwise, we |
print it as usual, but don't let the left argument see any |
modifiers. */ |
hold_modifiers = dpi->modifiers; |
dpi->modifiers = NULL; |
d_print_comp (dpi, options, d_left (mods->mod)); |
dpi->modifiers = hold_modifiers; |
if ((options & DMGL_JAVA) == 0) |
d_append_string (dpi, "::"); |
else |
d_append_char (dpi, '.'); |
dc = d_right (mods->mod); |
if (dc->type == DEMANGLE_COMPONENT_DEFAULT_ARG) |
{ |
d_append_string (dpi, "{default arg#"); |
d_append_num (dpi, dc->u.s_unary_num.num + 1); |
d_append_string (dpi, "}::"); |
dc = dc->u.s_unary_num.sub; |
} |
while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS |
|| dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS |
|| dc->type == DEMANGLE_COMPONENT_CONST_THIS |
|| dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS |
|| dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS) |
dc = d_left (dc); |
d_print_comp (dpi, options, dc); |
dpi->templates = hold_dpt; |
return; |
} |
d_print_mod (dpi, options, mods->mod); |
dpi->templates = hold_dpt; |
d_print_mod_list (dpi, options, mods->next, suffix); |
} |
/* Print a modifier. */ |
static void |
d_print_mod (struct d_print_info *dpi, int options, |
const struct demangle_component *mod) |
{ |
switch (mod->type) |
{ |
case DEMANGLE_COMPONENT_RESTRICT: |
case DEMANGLE_COMPONENT_RESTRICT_THIS: |
d_append_string (dpi, " restrict"); |
return; |
case DEMANGLE_COMPONENT_VOLATILE: |
case DEMANGLE_COMPONENT_VOLATILE_THIS: |
d_append_string (dpi, " volatile"); |
return; |
case DEMANGLE_COMPONENT_CONST: |
case DEMANGLE_COMPONENT_CONST_THIS: |
d_append_string (dpi, " const"); |
return; |
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: |
d_append_char (dpi, ' '); |
d_print_comp (dpi, options, d_right (mod)); |
return; |
case DEMANGLE_COMPONENT_POINTER: |
/* There is no pointer symbol in Java. */ |
if ((options & DMGL_JAVA) == 0) |
d_append_char (dpi, '*'); |
return; |
case DEMANGLE_COMPONENT_REFERENCE_THIS: |
/* For the ref-qualifier, put a space before the &. */ |
d_append_char (dpi, ' '); |
case DEMANGLE_COMPONENT_REFERENCE: |
d_append_char (dpi, '&'); |
return; |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: |
d_append_char (dpi, ' '); |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE: |
d_append_string (dpi, "&&"); |
return; |
case DEMANGLE_COMPONENT_COMPLEX: |
d_append_string (dpi, "complex "); |
return; |
case DEMANGLE_COMPONENT_IMAGINARY: |
d_append_string (dpi, "imaginary "); |
return; |
case DEMANGLE_COMPONENT_PTRMEM_TYPE: |
if (d_last_char (dpi) != '(') |
d_append_char (dpi, ' '); |
d_print_comp (dpi, options, d_left (mod)); |
d_append_string (dpi, "::*"); |
return; |
case DEMANGLE_COMPONENT_TYPED_NAME: |
d_print_comp (dpi, options, d_left (mod)); |
return; |
case DEMANGLE_COMPONENT_VECTOR_TYPE: |
d_append_string (dpi, " __vector("); |
d_print_comp (dpi, options, d_left (mod)); |
d_append_char (dpi, ')'); |
return; |
default: |
/* Otherwise, we have something that won't go back on the |
modifier stack, so we can just print it. */ |
d_print_comp (dpi, options, mod); |
return; |
} |
} |
/* Print a function type, except for the return type. */ |
static void |
d_print_function_type (struct d_print_info *dpi, int options, |
const struct demangle_component *dc, |
struct d_print_mod *mods) |
{ |
int need_paren; |
int need_space; |
struct d_print_mod *p; |
struct d_print_mod *hold_modifiers; |
need_paren = 0; |
need_space = 0; |
for (p = mods; p != NULL; p = p->next) |
{ |
if (p->printed) |
break; |
switch (p->mod->type) |
{ |
case DEMANGLE_COMPONENT_POINTER: |
case DEMANGLE_COMPONENT_REFERENCE: |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE: |
need_paren = 1; |
break; |
case DEMANGLE_COMPONENT_RESTRICT: |
case DEMANGLE_COMPONENT_VOLATILE: |
case DEMANGLE_COMPONENT_CONST: |
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: |
case DEMANGLE_COMPONENT_COMPLEX: |
case DEMANGLE_COMPONENT_IMAGINARY: |
case DEMANGLE_COMPONENT_PTRMEM_TYPE: |
need_space = 1; |
need_paren = 1; |
break; |
case DEMANGLE_COMPONENT_RESTRICT_THIS: |
case DEMANGLE_COMPONENT_VOLATILE_THIS: |
case DEMANGLE_COMPONENT_CONST_THIS: |
case DEMANGLE_COMPONENT_REFERENCE_THIS: |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: |
break; |
default: |
break; |
} |
if (need_paren) |
break; |
} |
if (need_paren) |
{ |
if (! need_space) |
{ |
if (d_last_char (dpi) != '(' |
&& d_last_char (dpi) != '*') |
need_space = 1; |
} |
if (need_space && d_last_char (dpi) != ' ') |
d_append_char (dpi, ' '); |
d_append_char (dpi, '('); |
} |
hold_modifiers = dpi->modifiers; |
dpi->modifiers = NULL; |
d_print_mod_list (dpi, options, mods, 0); |
if (need_paren) |
d_append_char (dpi, ')'); |
d_append_char (dpi, '('); |
if (d_right (dc) != NULL) |
d_print_comp (dpi, options, d_right (dc)); |
d_append_char (dpi, ')'); |
d_print_mod_list (dpi, options, mods, 1); |
dpi->modifiers = hold_modifiers; |
} |
/* Print an array type, except for the element type. */ |
static void |
d_print_array_type (struct d_print_info *dpi, int options, |
const struct demangle_component *dc, |
struct d_print_mod *mods) |
{ |
int need_space; |
need_space = 1; |
if (mods != NULL) |
{ |
int need_paren; |
struct d_print_mod *p; |
need_paren = 0; |
for (p = mods; p != NULL; p = p->next) |
{ |
if (! p->printed) |
{ |
if (p->mod->type == DEMANGLE_COMPONENT_ARRAY_TYPE) |
{ |
need_space = 0; |
break; |
} |
else |
{ |
need_paren = 1; |
need_space = 1; |
break; |
} |
} |
} |
if (need_paren) |
d_append_string (dpi, " ("); |
d_print_mod_list (dpi, options, mods, 0); |
if (need_paren) |
d_append_char (dpi, ')'); |
} |
if (need_space) |
d_append_char (dpi, ' '); |
d_append_char (dpi, '['); |
if (d_left (dc) != NULL) |
d_print_comp (dpi, options, d_left (dc)); |
d_append_char (dpi, ']'); |
} |
/* Print an operator in an expression. */ |
static void |
d_print_expr_op (struct d_print_info *dpi, int options, |
const struct demangle_component *dc) |
{ |
if (dc->type == DEMANGLE_COMPONENT_OPERATOR) |
d_append_buffer (dpi, dc->u.s_operator.op->name, |
dc->u.s_operator.op->len); |
else |
d_print_comp (dpi, options, dc); |
} |
/* Print a cast. */ |
static void |
d_print_cast (struct d_print_info *dpi, int options, |
const struct demangle_component *dc) |
{ |
if (d_left (dc)->type != DEMANGLE_COMPONENT_TEMPLATE) |
d_print_comp (dpi, options, d_left (dc)); |
else |
{ |
struct d_print_mod *hold_dpm; |
struct d_print_template dpt; |
/* It appears that for a templated cast operator, we need to put |
the template parameters in scope for the operator name, but |
not for the parameters. The effect is that we need to handle |
the template printing here. */ |
hold_dpm = dpi->modifiers; |
dpi->modifiers = NULL; |
dpt.next = dpi->templates; |
dpi->templates = &dpt; |
dpt.template_decl = d_left (dc); |
d_print_comp (dpi, options, d_left (d_left (dc))); |
dpi->templates = dpt.next; |
if (d_last_char (dpi) == '<') |
d_append_char (dpi, ' '); |
d_append_char (dpi, '<'); |
d_print_comp (dpi, options, d_right (d_left (dc))); |
/* Avoid generating two consecutive '>' characters, to avoid |
the C++ syntactic ambiguity. */ |
if (d_last_char (dpi) == '>') |
d_append_char (dpi, ' '); |
d_append_char (dpi, '>'); |
dpi->modifiers = hold_dpm; |
} |
} |
/* Initialize the information structure we use to pass around |
information. */ |
CP_STATIC_IF_GLIBCPP_V3 |
void |
cplus_demangle_init_info (const char *mangled, int options, size_t len, |
struct d_info *di) |
{ |
di->s = mangled; |
di->send = mangled + len; |
di->options = options; |
di->n = mangled; |
/* We can not need more components than twice the number of chars in |
the mangled string. Most components correspond directly to |
chars, but the ARGLIST types are exceptions. */ |
di->num_comps = 2 * len; |
di->next_comp = 0; |
/* Similarly, we can not need more substitutions than there are |
chars in the mangled string. */ |
di->num_subs = len; |
di->next_sub = 0; |
di->did_subs = 0; |
di->last_name = NULL; |
di->expansion = 0; |
} |
/* Internal implementation for the demangler. If MANGLED is a g++ v3 ABI |
mangled name, return strings in repeated callback giving the demangled |
name. OPTIONS is the usual libiberty demangler options. On success, |
this returns 1. On failure, returns 0. */ |
static int |
d_demangle_callback (const char *mangled, int options, |
demangle_callbackref callback, void *opaque) |
{ |
enum |
{ |
DCT_TYPE, |
DCT_MANGLED, |
DCT_GLOBAL_CTORS, |
DCT_GLOBAL_DTORS |
} |
type; |
struct d_info di; |
struct demangle_component *dc; |
int status; |
if (mangled[0] == '_' && mangled[1] == 'Z') |
type = DCT_MANGLED; |
else if (strncmp (mangled, "_GLOBAL_", 8) == 0 |
&& (mangled[8] == '.' || mangled[8] == '_' || mangled[8] == '$') |
&& (mangled[9] == 'D' || mangled[9] == 'I') |
&& mangled[10] == '_') |
type = mangled[9] == 'I' ? DCT_GLOBAL_CTORS : DCT_GLOBAL_DTORS; |
else |
{ |
if ((options & DMGL_TYPES) == 0) |
return 0; |
type = DCT_TYPE; |
} |
cplus_demangle_init_info (mangled, options, strlen (mangled), &di); |
{ |
#ifdef CP_DYNAMIC_ARRAYS |
__extension__ struct demangle_component comps[di.num_comps]; |
__extension__ struct demangle_component *subs[di.num_subs]; |
di.comps = comps; |
di.subs = subs; |
#else |
di.comps = alloca (di.num_comps * sizeof (*di.comps)); |
di.subs = alloca (di.num_subs * sizeof (*di.subs)); |
#endif |
switch (type) |
{ |
case DCT_TYPE: |
dc = cplus_demangle_type (&di); |
break; |
case DCT_MANGLED: |
dc = cplus_demangle_mangled_name (&di, 1); |
break; |
case DCT_GLOBAL_CTORS: |
case DCT_GLOBAL_DTORS: |
d_advance (&di, 11); |
dc = d_make_comp (&di, |
(type == DCT_GLOBAL_CTORS |
? DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS |
: DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS), |
d_make_demangle_mangled_name (&di, d_str (&di)), |
NULL); |
d_advance (&di, strlen (d_str (&di))); |
break; |
} |
/* If DMGL_PARAMS is set, then if we didn't consume the entire |
mangled string, then we didn't successfully demangle it. If |
DMGL_PARAMS is not set, we didn't look at the trailing |
parameters. */ |
if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0') |
dc = NULL; |
#ifdef CP_DEMANGLE_DEBUG |
d_dump (dc, 0); |
#endif |
status = (dc != NULL) |
? cplus_demangle_print_callback (options, dc, callback, opaque) |
: 0; |
} |
return status; |
} |
/* Entry point for the demangler. If MANGLED is a g++ v3 ABI mangled |
name, return a buffer allocated with malloc holding the demangled |
name. OPTIONS is the usual libiberty demangler options. On |
success, this sets *PALC to the allocated size of the returned |
buffer. On failure, this sets *PALC to 0 for a bad name, or 1 for |
a memory allocation failure, and returns NULL. */ |
static char * |
d_demangle (const char *mangled, int options, size_t *palc) |
{ |
struct d_growable_string dgs; |
int status; |
d_growable_string_init (&dgs, 0); |
status = d_demangle_callback (mangled, options, |
d_growable_string_callback_adapter, &dgs); |
if (status == 0) |
{ |
free (dgs.buf); |
*palc = 0; |
return NULL; |
} |
*palc = dgs.allocation_failure ? 1 : dgs.alc; |
return dgs.buf; |
} |
#if defined(IN_LIBGCC2) || defined(IN_GLIBCPP_V3) |
extern char *__cxa_demangle (const char *, char *, size_t *, int *); |
/* ia64 ABI-mandated entry point in the C++ runtime library for |
performing demangling. MANGLED_NAME is a NUL-terminated character |
string containing the name to be demangled. |
OUTPUT_BUFFER is a region of memory, allocated with malloc, of |
*LENGTH bytes, into which the demangled name is stored. If |
OUTPUT_BUFFER is not long enough, it is expanded using realloc. |
OUTPUT_BUFFER may instead be NULL; in that case, the demangled name |
is placed in a region of memory allocated with malloc. |
If LENGTH is non-NULL, the length of the buffer containing the |
demangled name, is placed in *LENGTH. |
The return value is a pointer to the start of the NUL-terminated |
demangled name, or NULL if the demangling fails. The caller is |
responsible for deallocating this memory using free. |
*STATUS is set to one of the following values: |
0: The demangling operation succeeded. |
-1: A memory allocation failure occurred. |
-2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules. |
-3: One of the arguments is invalid. |
The demangling is performed using the C++ ABI mangling rules, with |
GNU extensions. */ |
char * |
__cxa_demangle (const char *mangled_name, char *output_buffer, |
size_t *length, int *status) |
{ |
char *demangled; |
size_t alc; |
if (mangled_name == NULL) |
{ |
if (status != NULL) |
*status = -3; |
return NULL; |
} |
if (output_buffer != NULL && length == NULL) |
{ |
if (status != NULL) |
*status = -3; |
return NULL; |
} |
demangled = d_demangle (mangled_name, DMGL_PARAMS | DMGL_TYPES, &alc); |
if (demangled == NULL) |
{ |
if (status != NULL) |
{ |
if (alc == 1) |
*status = -1; |
else |
*status = -2; |
} |
return NULL; |
} |
if (output_buffer == NULL) |
{ |
if (length != NULL) |
*length = alc; |
} |
else |
{ |
if (strlen (demangled) < *length) |
{ |
strcpy (output_buffer, demangled); |
free (demangled); |
demangled = output_buffer; |
} |
else |
{ |
free (output_buffer); |
*length = alc; |
} |
} |
if (status != NULL) |
*status = 0; |
return demangled; |
} |
extern int __gcclibcxx_demangle_callback (const char *, |
void (*) |
(const char *, size_t, void *), |
void *); |
/* Alternative, allocationless entry point in the C++ runtime library |
for performing demangling. MANGLED_NAME is a NUL-terminated character |
string containing the name to be demangled. |
CALLBACK is a callback function, called with demangled string |
segments as demangling progresses; it is called at least once, |
but may be called more than once. OPAQUE is a generalized pointer |
used as a callback argument. |
The return code is one of the following values, equivalent to |
the STATUS values of __cxa_demangle() (excluding -1, since this |
function performs no memory allocations): |
0: The demangling operation succeeded. |
-2: MANGLED_NAME is not a valid name under the C++ ABI mangling rules. |
-3: One of the arguments is invalid. |
The demangling is performed using the C++ ABI mangling rules, with |
GNU extensions. */ |
int |
__gcclibcxx_demangle_callback (const char *mangled_name, |
void (*callback) (const char *, size_t, void *), |
void *opaque) |
{ |
int status; |
if (mangled_name == NULL || callback == NULL) |
return -3; |
status = d_demangle_callback (mangled_name, DMGL_PARAMS | DMGL_TYPES, |
callback, opaque); |
if (status == 0) |
return -2; |
return 0; |
} |
#else /* ! (IN_LIBGCC2 || IN_GLIBCPP_V3) */ |
/* Entry point for libiberty demangler. If MANGLED is a g++ v3 ABI |
mangled name, return a buffer allocated with malloc holding the |
demangled name. Otherwise, return NULL. */ |
char * |
cplus_demangle_v3 (const char *mangled, int options) |
{ |
size_t alc; |
return d_demangle (mangled, options, &alc); |
} |
int |
cplus_demangle_v3_callback (const char *mangled, int options, |
demangle_callbackref callback, void *opaque) |
{ |
return d_demangle_callback (mangled, options, callback, opaque); |
} |
/* Demangle a Java symbol. Java uses a subset of the V3 ABI C++ mangling |
conventions, but the output formatting is a little different. |
This instructs the C++ demangler not to emit pointer characters ("*"), to |
use Java's namespace separator symbol ("." instead of "::"), and to output |
JArray<TYPE> as TYPE[]. */ |
char * |
java_demangle_v3 (const char *mangled) |
{ |
size_t alc; |
return d_demangle (mangled, DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, &alc); |
} |
int |
java_demangle_v3_callback (const char *mangled, |
demangle_callbackref callback, void *opaque) |
{ |
return d_demangle_callback (mangled, |
DMGL_JAVA | DMGL_PARAMS | DMGL_RET_POSTFIX, |
callback, opaque); |
} |
#endif /* IN_LIBGCC2 || IN_GLIBCPP_V3 */ |
#ifndef IN_GLIBCPP_V3 |
/* Demangle a string in order to find out whether it is a constructor |
or destructor. Return non-zero on success. Set *CTOR_KIND and |
*DTOR_KIND appropriately. */ |
static int |
is_ctor_or_dtor (const char *mangled, |
enum gnu_v3_ctor_kinds *ctor_kind, |
enum gnu_v3_dtor_kinds *dtor_kind) |
{ |
struct d_info di; |
struct demangle_component *dc; |
int ret; |
*ctor_kind = (enum gnu_v3_ctor_kinds) 0; |
*dtor_kind = (enum gnu_v3_dtor_kinds) 0; |
cplus_demangle_init_info (mangled, DMGL_GNU_V3, strlen (mangled), &di); |
{ |
#ifdef CP_DYNAMIC_ARRAYS |
__extension__ struct demangle_component comps[di.num_comps]; |
__extension__ struct demangle_component *subs[di.num_subs]; |
di.comps = comps; |
di.subs = subs; |
#else |
di.comps = alloca (di.num_comps * sizeof (*di.comps)); |
di.subs = alloca (di.num_subs * sizeof (*di.subs)); |
#endif |
dc = cplus_demangle_mangled_name (&di, 1); |
/* Note that because we did not pass DMGL_PARAMS, we don't expect |
to demangle the entire string. */ |
ret = 0; |
while (dc != NULL) |
{ |
switch (dc->type) |
{ |
/* These cannot appear on a constructor or destructor. */ |
case DEMANGLE_COMPONENT_RESTRICT_THIS: |
case DEMANGLE_COMPONENT_VOLATILE_THIS: |
case DEMANGLE_COMPONENT_CONST_THIS: |
case DEMANGLE_COMPONENT_REFERENCE_THIS: |
case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: |
default: |
dc = NULL; |
break; |
case DEMANGLE_COMPONENT_TYPED_NAME: |
case DEMANGLE_COMPONENT_TEMPLATE: |
dc = d_left (dc); |
break; |
case DEMANGLE_COMPONENT_QUAL_NAME: |
case DEMANGLE_COMPONENT_LOCAL_NAME: |
dc = d_right (dc); |
break; |
case DEMANGLE_COMPONENT_CTOR: |
*ctor_kind = dc->u.s_ctor.kind; |
ret = 1; |
dc = NULL; |
break; |
case DEMANGLE_COMPONENT_DTOR: |
*dtor_kind = dc->u.s_dtor.kind; |
ret = 1; |
dc = NULL; |
break; |
} |
} |
} |
return ret; |
} |
/* Return whether NAME is the mangled form of a g++ V3 ABI constructor |
name. A non-zero return indicates the type of constructor. */ |
enum gnu_v3_ctor_kinds |
is_gnu_v3_mangled_ctor (const char *name) |
{ |
enum gnu_v3_ctor_kinds ctor_kind; |
enum gnu_v3_dtor_kinds dtor_kind; |
if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind)) |
return (enum gnu_v3_ctor_kinds) 0; |
return ctor_kind; |
} |
/* Return whether NAME is the mangled form of a g++ V3 ABI destructor |
name. A non-zero return indicates the type of destructor. */ |
enum gnu_v3_dtor_kinds |
is_gnu_v3_mangled_dtor (const char *name) |
{ |
enum gnu_v3_ctor_kinds ctor_kind; |
enum gnu_v3_dtor_kinds dtor_kind; |
if (! is_ctor_or_dtor (name, &ctor_kind, &dtor_kind)) |
return (enum gnu_v3_dtor_kinds) 0; |
return dtor_kind; |
} |
#endif /* IN_GLIBCPP_V3 */ |
#ifdef STANDALONE_DEMANGLER |
#include "getopt.h" |
#include "dyn-string.h" |
static void print_usage (FILE* fp, int exit_value); |
#define IS_ALPHA(CHAR) \ |
(((CHAR) >= 'a' && (CHAR) <= 'z') \ |
|| ((CHAR) >= 'A' && (CHAR) <= 'Z')) |
/* Non-zero if CHAR is a character than can occur in a mangled name. */ |
#define is_mangled_char(CHAR) \ |
(IS_ALPHA (CHAR) || IS_DIGIT (CHAR) \ |
|| (CHAR) == '_' || (CHAR) == '.' || (CHAR) == '$') |
/* The name of this program, as invoked. */ |
const char* program_name; |
/* Prints usage summary to FP and then exits with EXIT_VALUE. */ |
static void |
print_usage (FILE* fp, int exit_value) |
{ |
fprintf (fp, "Usage: %s [options] [names ...]\n", program_name); |
fprintf (fp, "Options:\n"); |
fprintf (fp, " -h,--help Display this message.\n"); |
fprintf (fp, " -p,--no-params Don't display function parameters\n"); |
fprintf (fp, " -v,--verbose Produce verbose demanglings.\n"); |
fprintf (fp, "If names are provided, they are demangled. Otherwise filters standard input.\n"); |
exit (exit_value); |
} |
/* Option specification for getopt_long. */ |
static const struct option long_options[] = |
{ |
{ "help", no_argument, NULL, 'h' }, |
{ "no-params", no_argument, NULL, 'p' }, |
{ "verbose", no_argument, NULL, 'v' }, |
{ NULL, no_argument, NULL, 0 }, |
}; |
/* Main entry for a demangling filter executable. It will demangle |
its command line arguments, if any. If none are provided, it will |
filter stdin to stdout, replacing any recognized mangled C++ names |
with their demangled equivalents. */ |
int |
main (int argc, char *argv[]) |
{ |
int i; |
int opt_char; |
int options = DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES; |
/* Use the program name of this program, as invoked. */ |
program_name = argv[0]; |
/* Parse options. */ |
do |
{ |
opt_char = getopt_long (argc, argv, "hpv", long_options, NULL); |
switch (opt_char) |
{ |
case '?': /* Unrecognized option. */ |
print_usage (stderr, 1); |
break; |
case 'h': |
print_usage (stdout, 0); |
break; |
case 'p': |
options &= ~ DMGL_PARAMS; |
break; |
case 'v': |
options |= DMGL_VERBOSE; |
break; |
} |
} |
while (opt_char != -1); |
if (optind == argc) |
/* No command line arguments were provided. Filter stdin. */ |
{ |
dyn_string_t mangled = dyn_string_new (3); |
char *s; |
/* Read all of input. */ |
while (!feof (stdin)) |
{ |
char c; |
/* Pile characters into mangled until we hit one that can't |
occur in a mangled name. */ |
c = getchar (); |
while (!feof (stdin) && is_mangled_char (c)) |
{ |
dyn_string_append_char (mangled, c); |
if (feof (stdin)) |
break; |
c = getchar (); |
} |
if (dyn_string_length (mangled) > 0) |
{ |
#ifdef IN_GLIBCPP_V3 |
s = __cxa_demangle (dyn_string_buf (mangled), NULL, NULL, NULL); |
#else |
s = cplus_demangle_v3 (dyn_string_buf (mangled), options); |
#endif |
if (s != NULL) |
{ |
fputs (s, stdout); |
free (s); |
} |
else |
{ |
/* It might not have been a mangled name. Print the |
original text. */ |
fputs (dyn_string_buf (mangled), stdout); |
} |
dyn_string_clear (mangled); |
} |
/* If we haven't hit EOF yet, we've read one character that |
can't occur in a mangled name, so print it out. */ |
if (!feof (stdin)) |
putchar (c); |
} |
dyn_string_delete (mangled); |
} |
else |
/* Demangle command line arguments. */ |
{ |
/* Loop over command line arguments. */ |
for (i = optind; i < argc; ++i) |
{ |
char *s; |
#ifdef IN_GLIBCPP_V3 |
int status; |
#endif |
/* Attempt to demangle. */ |
#ifdef IN_GLIBCPP_V3 |
s = __cxa_demangle (argv[i], NULL, NULL, &status); |
#else |
s = cplus_demangle_v3 (argv[i], options); |
#endif |
/* If it worked, print the demangled name. */ |
if (s != NULL) |
{ |
printf ("%s\n", s); |
free (s); |
} |
else |
{ |
#ifdef IN_GLIBCPP_V3 |
fprintf (stderr, "Failed: %s (status %d)\n", argv[i], status); |
#else |
fprintf (stderr, "Failed: %s\n", argv[i]); |
#endif |
} |
} |
} |
return 0; |
} |
#endif /* STANDALONE_DEMANGLER */ |
/contrib/toolchain/binutils/libiberty/cp-demangle.h |
---|
0,0 → 1,169 |
/* Internal demangler interface for g++ V3 ABI. |
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2010 |
Free Software Foundation, Inc. |
Written by Ian Lance Taylor <ian@wasabisystems.com>. |
This file is part of the libiberty library, which is part of GCC. |
This file 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 of the License, or |
(at your option) any later version. |
In addition to the permissions in the GNU General Public License, the |
Free Software Foundation gives you unlimited permission to link the |
compiled version of this file into combinations with other programs, |
and to distribute those combinations without any restriction coming |
from the use of this file. (The General Public License restrictions |
do apply in other respects; for example, they cover modification of |
the file, and distribution when not linked into a combined |
executable.) |
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
*/ |
/* This file provides some definitions shared by cp-demangle.c and |
cp-demint.c. It should not be included by any other files. */ |
/* Information we keep for operators. */ |
struct demangle_operator_info |
{ |
/* Mangled name. */ |
const char *code; |
/* Real name. */ |
const char *name; |
/* Length of real name. */ |
int len; |
/* Number of arguments. */ |
int args; |
}; |
/* How to print the value of a builtin type. */ |
enum d_builtin_type_print |
{ |
/* Print as (type)val. */ |
D_PRINT_DEFAULT, |
/* Print as integer. */ |
D_PRINT_INT, |
/* Print as unsigned integer, with trailing "u". */ |
D_PRINT_UNSIGNED, |
/* Print as long, with trailing "l". */ |
D_PRINT_LONG, |
/* Print as unsigned long, with trailing "ul". */ |
D_PRINT_UNSIGNED_LONG, |
/* Print as long long, with trailing "ll". */ |
D_PRINT_LONG_LONG, |
/* Print as unsigned long long, with trailing "ull". */ |
D_PRINT_UNSIGNED_LONG_LONG, |
/* Print as bool. */ |
D_PRINT_BOOL, |
/* Print as float--put value in square brackets. */ |
D_PRINT_FLOAT, |
/* Print in usual way, but here to detect void. */ |
D_PRINT_VOID |
}; |
/* Information we keep for a builtin type. */ |
struct demangle_builtin_type_info |
{ |
/* Type name. */ |
const char *name; |
/* Length of type name. */ |
int len; |
/* Type name when using Java. */ |
const char *java_name; |
/* Length of java name. */ |
int java_len; |
/* How to print a value of this type. */ |
enum d_builtin_type_print print; |
}; |
/* The information structure we pass around. */ |
struct d_info |
{ |
/* The string we are demangling. */ |
const char *s; |
/* The end of the string we are demangling. */ |
const char *send; |
/* The options passed to the demangler. */ |
int options; |
/* The next character in the string to consider. */ |
const char *n; |
/* The array of components. */ |
struct demangle_component *comps; |
/* The index of the next available component. */ |
int next_comp; |
/* The number of available component structures. */ |
int num_comps; |
/* The array of substitutions. */ |
struct demangle_component **subs; |
/* The index of the next substitution. */ |
int next_sub; |
/* The number of available entries in the subs array. */ |
int num_subs; |
/* The number of substitutions which we actually made from the subs |
array, plus the number of template parameter references we |
saw. */ |
int did_subs; |
/* The last name we saw, for constructors and destructors. */ |
struct demangle_component *last_name; |
/* A running total of the length of large expansions from the |
mangled name to the demangled name, such as standard |
substitutions and builtin types. */ |
int expansion; |
}; |
/* To avoid running past the ending '\0', don't: |
- call d_peek_next_char if d_peek_char returned '\0' |
- call d_advance with an 'i' that is too large |
- call d_check_char(di, '\0') |
Everything else is safe. */ |
#define d_peek_char(di) (*((di)->n)) |
#define d_peek_next_char(di) ((di)->n[1]) |
#define d_advance(di, i) ((di)->n += (i)) |
#define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0) |
#define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++)) |
#define d_str(di) ((di)->n) |
/* Functions and arrays in cp-demangle.c which are referenced by |
functions in cp-demint.c. */ |
#ifdef IN_GLIBCPP_V3 |
#define CP_STATIC_IF_GLIBCPP_V3 static |
#else |
#define CP_STATIC_IF_GLIBCPP_V3 extern |
#endif |
#ifndef IN_GLIBCPP_V3 |
extern const struct demangle_operator_info cplus_demangle_operators[]; |
#endif |
#define D_BUILTIN_TYPE_COUNT (33) |
CP_STATIC_IF_GLIBCPP_V3 |
const struct demangle_builtin_type_info |
cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT]; |
CP_STATIC_IF_GLIBCPP_V3 |
struct demangle_component * |
cplus_demangle_mangled_name (struct d_info *, int); |
CP_STATIC_IF_GLIBCPP_V3 |
struct demangle_component * |
cplus_demangle_type (struct d_info *); |
extern void |
cplus_demangle_init_info (const char *, int, size_t, struct d_info *); |
/* cp-demangle.c needs to define this a little differently */ |
#undef CP_STATIC_IF_GLIBCPP_V3 |
/contrib/toolchain/binutils/libiberty/cp-demint.c |
---|
0,0 → 1,232 |
/* Demangler component interface functions. |
Copyright (C) 2004 Free Software Foundation, Inc. |
Written by Ian Lance Taylor <ian@wasabisystems.com>. |
This file is part of the libiberty library, which is part of GCC. |
This file 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 of the License, or |
(at your option) any later version. |
In addition to the permissions in the GNU General Public License, the |
Free Software Foundation gives you unlimited permission to link the |
compiled version of this file into combinations with other programs, |
and to distribute those combinations without any restriction coming |
from the use of this file. (The General Public License restrictions |
do apply in other respects; for example, they cover modification of |
the file, and distribution when not linked into a combined |
executable.) |
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
*/ |
/* This file implements a few interface functions which are provided |
for use with struct demangle_component trees. These functions are |
declared in demangle.h. These functions are closely tied to the |
demangler code in cp-demangle.c, and other interface functions can |
be found in that file. We put these functions in a separate file |
because they are not needed by the demangler, and so we avoid |
having them pulled in by programs which only need the |
demangler. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#include "demangle.h" |
#include "cp-demangle.h" |
/* Fill in most component types. */ |
int |
cplus_demangle_fill_component (struct demangle_component *p, |
enum demangle_component_type type, |
struct demangle_component *left, |
struct demangle_component *right) |
{ |
if (p == NULL) |
return 0; |
switch (type) |
{ |
case DEMANGLE_COMPONENT_QUAL_NAME: |
case DEMANGLE_COMPONENT_LOCAL_NAME: |
case DEMANGLE_COMPONENT_TYPED_NAME: |
case DEMANGLE_COMPONENT_TEMPLATE: |
case DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE: |
case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: |
case DEMANGLE_COMPONENT_FUNCTION_TYPE: |
case DEMANGLE_COMPONENT_ARRAY_TYPE: |
case DEMANGLE_COMPONENT_PTRMEM_TYPE: |
case DEMANGLE_COMPONENT_ARGLIST: |
case DEMANGLE_COMPONENT_TEMPLATE_ARGLIST: |
case DEMANGLE_COMPONENT_UNARY: |
case DEMANGLE_COMPONENT_BINARY: |
case DEMANGLE_COMPONENT_BINARY_ARGS: |
case DEMANGLE_COMPONENT_TRINARY: |
case DEMANGLE_COMPONENT_TRINARY_ARG1: |
case DEMANGLE_COMPONENT_TRINARY_ARG2: |
case DEMANGLE_COMPONENT_LITERAL: |
case DEMANGLE_COMPONENT_LITERAL_NEG: |
break; |
/* These component types only have one subtree. */ |
case DEMANGLE_COMPONENT_VTABLE: |
case DEMANGLE_COMPONENT_VTT: |
case DEMANGLE_COMPONENT_TYPEINFO: |
case DEMANGLE_COMPONENT_TYPEINFO_NAME: |
case DEMANGLE_COMPONENT_TYPEINFO_FN: |
case DEMANGLE_COMPONENT_THUNK: |
case DEMANGLE_COMPONENT_VIRTUAL_THUNK: |
case DEMANGLE_COMPONENT_COVARIANT_THUNK: |
case DEMANGLE_COMPONENT_JAVA_CLASS: |
case DEMANGLE_COMPONENT_GUARD: |
case DEMANGLE_COMPONENT_REFTEMP: |
case DEMANGLE_COMPONENT_RESTRICT: |
case DEMANGLE_COMPONENT_VOLATILE: |
case DEMANGLE_COMPONENT_CONST: |
case DEMANGLE_COMPONENT_RESTRICT_THIS: |
case DEMANGLE_COMPONENT_VOLATILE_THIS: |
case DEMANGLE_COMPONENT_CONST_THIS: |
case DEMANGLE_COMPONENT_POINTER: |
case DEMANGLE_COMPONENT_REFERENCE: |
case DEMANGLE_COMPONENT_COMPLEX: |
case DEMANGLE_COMPONENT_IMAGINARY: |
case DEMANGLE_COMPONENT_VENDOR_TYPE: |
case DEMANGLE_COMPONENT_CAST: |
if (right != NULL) |
return 0; |
break; |
default: |
/* Other types do not use subtrees. */ |
return 0; |
} |
p->type = type; |
p->u.s_binary.left = left; |
p->u.s_binary.right = right; |
return 1; |
} |
/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE. */ |
int |
cplus_demangle_fill_builtin_type (struct demangle_component *p, |
const char *type_name) |
{ |
int len; |
unsigned int i; |
if (p == NULL || type_name == NULL) |
return 0; |
len = strlen (type_name); |
for (i = 0; i < D_BUILTIN_TYPE_COUNT; ++i) |
{ |
if (len == cplus_demangle_builtin_types[i].len |
&& strcmp (type_name, cplus_demangle_builtin_types[i].name) == 0) |
{ |
p->type = DEMANGLE_COMPONENT_BUILTIN_TYPE; |
p->u.s_builtin.type = &cplus_demangle_builtin_types[i]; |
return 1; |
} |
} |
return 0; |
} |
/* Fill in a DEMANGLE_COMPONENT_OPERATOR. */ |
int |
cplus_demangle_fill_operator (struct demangle_component *p, |
const char *opname, int args) |
{ |
int len; |
unsigned int i; |
if (p == NULL || opname == NULL) |
return 0; |
len = strlen (opname); |
for (i = 0; cplus_demangle_operators[i].name != NULL; ++i) |
{ |
if (len == cplus_demangle_operators[i].len |
&& args == cplus_demangle_operators[i].args |
&& strcmp (opname, cplus_demangle_operators[i].name) == 0) |
{ |
p->type = DEMANGLE_COMPONENT_OPERATOR; |
p->u.s_operator.op = &cplus_demangle_operators[i]; |
return 1; |
} |
} |
return 0; |
} |
/* Translate a mangled name into components. */ |
struct demangle_component * |
cplus_demangle_v3_components (const char *mangled, int options, void **mem) |
{ |
size_t len; |
int type; |
struct d_info di; |
struct demangle_component *dc; |
len = strlen (mangled); |
if (mangled[0] == '_' && mangled[1] == 'Z') |
type = 0; |
else |
{ |
if ((options & DMGL_TYPES) == 0) |
return NULL; |
type = 1; |
} |
cplus_demangle_init_info (mangled, options, len, &di); |
di.comps = ((struct demangle_component *) |
malloc (di.num_comps * sizeof (struct demangle_component))); |
di.subs = ((struct demangle_component **) |
malloc (di.num_subs * sizeof (struct demangle_component *))); |
if (di.comps == NULL || di.subs == NULL) |
{ |
free (di.comps); |
free (di.subs); |
return NULL; |
} |
if (! type) |
dc = cplus_demangle_mangled_name (&di, 1); |
else |
dc = cplus_demangle_type (&di); |
/* If DMGL_PARAMS is set, then if we didn't consume the entire |
mangled string, then we didn't successfully demangle it. */ |
if ((options & DMGL_PARAMS) != 0 && d_peek_char (&di) != '\0') |
dc = NULL; |
free (di.subs); |
if (dc != NULL) |
*mem = di.comps; |
else |
free (di.comps); |
return dc; |
} |
/contrib/toolchain/binutils/libiberty/cplus-dem.c |
---|
0,0 → 1,4862 |
/* Demangler for GNU C++ |
Copyright 1989, 1991, 1994, 1995, 1996, 1997, 1998, 1999, |
2000, 2001, 2002, 2003, 2004, 2010 Free Software Foundation, Inc. |
Written by James Clark (jjc@jclark.uucp) |
Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling |
Modified by Satish Pai (pai@apollo.hp.com) for HP demangling |
This file is part of the libiberty library. |
Libiberty 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. |
In addition to the permissions in the GNU Library General Public |
License, the Free Software Foundation gives you unlimited permission |
to link the compiled version of this file into combinations with other |
programs, and to distribute those combinations without any restriction |
coming from the use of this file. (The Library Public License |
restrictions do apply in other respects; for example, they cover |
modification of the file, and distribution when not linked into a |
combined executable.) |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* This file exports two functions; cplus_mangle_opname and cplus_demangle. |
This file imports xmalloc and xrealloc, which are like malloc and |
realloc except that they generate a fatal error if there is no |
available memory. */ |
/* This file lives in both GCC and libiberty. When making changes, please |
try not to break either. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "safe-ctype.h" |
#include <sys/types.h> |
#include <string.h> |
#include <stdio.h> |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#else |
void * malloc (); |
void * realloc (); |
#endif |
#include <demangle.h> |
#undef CURRENT_DEMANGLING_STYLE |
#define CURRENT_DEMANGLING_STYLE work->options |
#include "libiberty.h" |
#define min(X,Y) (((X) < (Y)) ? (X) : (Y)) |
/* A value at least one greater than the maximum number of characters |
that will be output when using the `%d' format with `printf'. */ |
#define INTBUF_SIZE 32 |
extern void fancy_abort (void) ATTRIBUTE_NORETURN; |
/* In order to allow a single demangler executable to demangle strings |
using various common values of CPLUS_MARKER, as well as any specific |
one set at compile time, we maintain a string containing all the |
commonly used ones, and check to see if the marker we are looking for |
is in that string. CPLUS_MARKER is usually '$' on systems where the |
assembler can deal with that. Where the assembler can't, it's usually |
'.' (but on many systems '.' is used for other things). We put the |
current defined CPLUS_MARKER first (which defaults to '$'), followed |
by the next most common value, followed by an explicit '$' in case |
the value of CPLUS_MARKER is not '$'. |
We could avoid this if we could just get g++ to tell us what the actual |
cplus marker character is as part of the debug information, perhaps by |
ensuring that it is the character that terminates the gcc<n>_compiled |
marker symbol (FIXME). */ |
#if !defined (CPLUS_MARKER) |
#define CPLUS_MARKER '$' |
#endif |
enum demangling_styles current_demangling_style = auto_demangling; |
static char cplus_markers[] = { CPLUS_MARKER, '.', '$', '\0' }; |
static char char_str[2] = { '\000', '\000' }; |
void |
set_cplus_marker_for_demangling (int ch) |
{ |
cplus_markers[0] = ch; |
} |
typedef struct string /* Beware: these aren't required to be */ |
{ /* '\0' terminated. */ |
char *b; /* pointer to start of string */ |
char *p; /* pointer after last character */ |
char *e; /* pointer after end of allocated space */ |
} string; |
/* Stuff that is shared between sub-routines. |
Using a shared structure allows cplus_demangle to be reentrant. */ |
struct work_stuff |
{ |
int options; |
char **typevec; |
char **ktypevec; |
char **btypevec; |
int numk; |
int numb; |
int ksize; |
int bsize; |
int ntypes; |
int typevec_size; |
int constructor; |
int destructor; |
int static_type; /* A static member function */ |
int temp_start; /* index in demangled to start of template args */ |
int type_quals; /* The type qualifiers. */ |
int dllimported; /* Symbol imported from a PE DLL */ |
char **tmpl_argvec; /* Template function arguments. */ |
int ntmpl_args; /* The number of template function arguments. */ |
int forgetting_types; /* Nonzero if we are not remembering the types |
we see. */ |
string* previous_argument; /* The last function argument demangled. */ |
int nrepeats; /* The number of times to repeat the previous |
argument. */ |
}; |
#define PRINT_ANSI_QUALIFIERS (work -> options & DMGL_ANSI) |
#define PRINT_ARG_TYPES (work -> options & DMGL_PARAMS) |
static const struct optable |
{ |
const char *const in; |
const char *const out; |
const int flags; |
} optable[] = { |
{"nw", " new", DMGL_ANSI}, /* new (1.92, ansi) */ |
{"dl", " delete", DMGL_ANSI}, /* new (1.92, ansi) */ |
{"new", " new", 0}, /* old (1.91, and 1.x) */ |
{"delete", " delete", 0}, /* old (1.91, and 1.x) */ |
{"vn", " new []", DMGL_ANSI}, /* GNU, pending ansi */ |
{"vd", " delete []", DMGL_ANSI}, /* GNU, pending ansi */ |
{"as", "=", DMGL_ANSI}, /* ansi */ |
{"ne", "!=", DMGL_ANSI}, /* old, ansi */ |
{"eq", "==", DMGL_ANSI}, /* old, ansi */ |
{"ge", ">=", DMGL_ANSI}, /* old, ansi */ |
{"gt", ">", DMGL_ANSI}, /* old, ansi */ |
{"le", "<=", DMGL_ANSI}, /* old, ansi */ |
{"lt", "<", DMGL_ANSI}, /* old, ansi */ |
{"plus", "+", 0}, /* old */ |
{"pl", "+", DMGL_ANSI}, /* ansi */ |
{"apl", "+=", DMGL_ANSI}, /* ansi */ |
{"minus", "-", 0}, /* old */ |
{"mi", "-", DMGL_ANSI}, /* ansi */ |
{"ami", "-=", DMGL_ANSI}, /* ansi */ |
{"mult", "*", 0}, /* old */ |
{"ml", "*", DMGL_ANSI}, /* ansi */ |
{"amu", "*=", DMGL_ANSI}, /* ansi (ARM/Lucid) */ |
{"aml", "*=", DMGL_ANSI}, /* ansi (GNU/g++) */ |
{"convert", "+", 0}, /* old (unary +) */ |
{"negate", "-", 0}, /* old (unary -) */ |
{"trunc_mod", "%", 0}, /* old */ |
{"md", "%", DMGL_ANSI}, /* ansi */ |
{"amd", "%=", DMGL_ANSI}, /* ansi */ |
{"trunc_div", "/", 0}, /* old */ |
{"dv", "/", DMGL_ANSI}, /* ansi */ |
{"adv", "/=", DMGL_ANSI}, /* ansi */ |
{"truth_andif", "&&", 0}, /* old */ |
{"aa", "&&", DMGL_ANSI}, /* ansi */ |
{"truth_orif", "||", 0}, /* old */ |
{"oo", "||", DMGL_ANSI}, /* ansi */ |
{"truth_not", "!", 0}, /* old */ |
{"nt", "!", DMGL_ANSI}, /* ansi */ |
{"postincrement","++", 0}, /* old */ |
{"pp", "++", DMGL_ANSI}, /* ansi */ |
{"postdecrement","--", 0}, /* old */ |
{"mm", "--", DMGL_ANSI}, /* ansi */ |
{"bit_ior", "|", 0}, /* old */ |
{"or", "|", DMGL_ANSI}, /* ansi */ |
{"aor", "|=", DMGL_ANSI}, /* ansi */ |
{"bit_xor", "^", 0}, /* old */ |
{"er", "^", DMGL_ANSI}, /* ansi */ |
{"aer", "^=", DMGL_ANSI}, /* ansi */ |
{"bit_and", "&", 0}, /* old */ |
{"ad", "&", DMGL_ANSI}, /* ansi */ |
{"aad", "&=", DMGL_ANSI}, /* ansi */ |
{"bit_not", "~", 0}, /* old */ |
{"co", "~", DMGL_ANSI}, /* ansi */ |
{"call", "()", 0}, /* old */ |
{"cl", "()", DMGL_ANSI}, /* ansi */ |
{"alshift", "<<", 0}, /* old */ |
{"ls", "<<", DMGL_ANSI}, /* ansi */ |
{"als", "<<=", DMGL_ANSI}, /* ansi */ |
{"arshift", ">>", 0}, /* old */ |
{"rs", ">>", DMGL_ANSI}, /* ansi */ |
{"ars", ">>=", DMGL_ANSI}, /* ansi */ |
{"component", "->", 0}, /* old */ |
{"pt", "->", DMGL_ANSI}, /* ansi; Lucid C++ form */ |
{"rf", "->", DMGL_ANSI}, /* ansi; ARM/GNU form */ |
{"indirect", "*", 0}, /* old */ |
{"method_call", "->()", 0}, /* old */ |
{"addr", "&", 0}, /* old (unary &) */ |
{"array", "[]", 0}, /* old */ |
{"vc", "[]", DMGL_ANSI}, /* ansi */ |
{"compound", ", ", 0}, /* old */ |
{"cm", ", ", DMGL_ANSI}, /* ansi */ |
{"cond", "?:", 0}, /* old */ |
{"cn", "?:", DMGL_ANSI}, /* pseudo-ansi */ |
{"max", ">?", 0}, /* old */ |
{"mx", ">?", DMGL_ANSI}, /* pseudo-ansi */ |
{"min", "<?", 0}, /* old */ |
{"mn", "<?", DMGL_ANSI}, /* pseudo-ansi */ |
{"nop", "", 0}, /* old (for operator=) */ |
{"rm", "->*", DMGL_ANSI}, /* ansi */ |
{"sz", "sizeof ", DMGL_ANSI} /* pseudo-ansi */ |
}; |
/* These values are used to indicate the various type varieties. |
They are all non-zero so that they can be used as `success' |
values. */ |
typedef enum type_kind_t |
{ |
tk_none, |
tk_pointer, |
tk_reference, |
tk_integral, |
tk_bool, |
tk_char, |
tk_real |
} type_kind_t; |
const struct demangler_engine libiberty_demanglers[] = |
{ |
{ |
NO_DEMANGLING_STYLE_STRING, |
no_demangling, |
"Demangling disabled" |
} |
, |
{ |
AUTO_DEMANGLING_STYLE_STRING, |
auto_demangling, |
"Automatic selection based on executable" |
} |
, |
{ |
GNU_DEMANGLING_STYLE_STRING, |
gnu_demangling, |
"GNU (g++) style demangling" |
} |
, |
{ |
LUCID_DEMANGLING_STYLE_STRING, |
lucid_demangling, |
"Lucid (lcc) style demangling" |
} |
, |
{ |
ARM_DEMANGLING_STYLE_STRING, |
arm_demangling, |
"ARM style demangling" |
} |
, |
{ |
HP_DEMANGLING_STYLE_STRING, |
hp_demangling, |
"HP (aCC) style demangling" |
} |
, |
{ |
EDG_DEMANGLING_STYLE_STRING, |
edg_demangling, |
"EDG style demangling" |
} |
, |
{ |
GNU_V3_DEMANGLING_STYLE_STRING, |
gnu_v3_demangling, |
"GNU (g++) V3 ABI-style demangling" |
} |
, |
{ |
JAVA_DEMANGLING_STYLE_STRING, |
java_demangling, |
"Java style demangling" |
} |
, |
{ |
GNAT_DEMANGLING_STYLE_STRING, |
gnat_demangling, |
"GNAT style demangling" |
} |
, |
{ |
NULL, unknown_demangling, NULL |
} |
}; |
#define STRING_EMPTY(str) ((str) -> b == (str) -> p) |
#define APPEND_BLANK(str) {if (!STRING_EMPTY(str)) \ |
string_append(str, " ");} |
#define LEN_STRING(str) ( (STRING_EMPTY(str))?0:((str)->p - (str)->b)) |
/* The scope separator appropriate for the language being demangled. */ |
#define SCOPE_STRING(work) ((work->options & DMGL_JAVA) ? "." : "::") |
#define ARM_VTABLE_STRING "__vtbl__" /* Lucid/ARM virtual table prefix */ |
#define ARM_VTABLE_STRLEN 8 /* strlen (ARM_VTABLE_STRING) */ |
/* Prototypes for local functions */ |
static void delete_work_stuff (struct work_stuff *); |
static void delete_non_B_K_work_stuff (struct work_stuff *); |
static char *mop_up (struct work_stuff *, string *, int); |
static void squangle_mop_up (struct work_stuff *); |
static void work_stuff_copy_to_from (struct work_stuff *, struct work_stuff *); |
#if 0 |
static int |
demangle_method_args (struct work_stuff *, const char **, string *); |
#endif |
static char * |
internal_cplus_demangle (struct work_stuff *, const char *); |
static int |
demangle_template_template_parm (struct work_stuff *work, |
const char **, string *); |
static int |
demangle_template (struct work_stuff *work, const char **, string *, |
string *, int, int); |
static int |
arm_pt (struct work_stuff *, const char *, int, const char **, |
const char **); |
static int |
demangle_class_name (struct work_stuff *, const char **, string *); |
static int |
demangle_qualified (struct work_stuff *, const char **, string *, |
int, int); |
static int demangle_class (struct work_stuff *, const char **, string *); |
static int demangle_fund_type (struct work_stuff *, const char **, string *); |
static int demangle_signature (struct work_stuff *, const char **, string *); |
static int demangle_prefix (struct work_stuff *, const char **, string *); |
static int gnu_special (struct work_stuff *, const char **, string *); |
static int arm_special (const char **, string *); |
static void string_need (string *, int); |
static void string_delete (string *); |
static void |
string_init (string *); |
static void string_clear (string *); |
#if 0 |
static int string_empty (string *); |
#endif |
static void string_append (string *, const char *); |
static void string_appends (string *, string *); |
static void string_appendn (string *, const char *, int); |
static void string_prepend (string *, const char *); |
static void string_prependn (string *, const char *, int); |
static void string_append_template_idx (string *, int); |
static int get_count (const char **, int *); |
static int consume_count (const char **); |
static int consume_count_with_underscores (const char**); |
static int demangle_args (struct work_stuff *, const char **, string *); |
static int demangle_nested_args (struct work_stuff*, const char**, string*); |
static int do_type (struct work_stuff *, const char **, string *); |
static int do_arg (struct work_stuff *, const char **, string *); |
static int |
demangle_function_name (struct work_stuff *, const char **, string *, |
const char *); |
static int |
iterate_demangle_function (struct work_stuff *, |
const char **, string *, const char *); |
static void remember_type (struct work_stuff *, const char *, int); |
static void remember_Btype (struct work_stuff *, const char *, int, int); |
static int register_Btype (struct work_stuff *); |
static void remember_Ktype (struct work_stuff *, const char *, int); |
static void forget_types (struct work_stuff *); |
static void forget_B_and_K_types (struct work_stuff *); |
static void string_prepends (string *, string *); |
static int |
demangle_template_value_parm (struct work_stuff*, const char**, |
string*, type_kind_t); |
static int |
do_hpacc_template_const_value (struct work_stuff *, const char **, string *); |
static int |
do_hpacc_template_literal (struct work_stuff *, const char **, string *); |
static int snarf_numeric_literal (const char **, string *); |
/* There is a TYPE_QUAL value for each type qualifier. They can be |
combined by bitwise-or to form the complete set of qualifiers for a |
type. */ |
#define TYPE_UNQUALIFIED 0x0 |
#define TYPE_QUAL_CONST 0x1 |
#define TYPE_QUAL_VOLATILE 0x2 |
#define TYPE_QUAL_RESTRICT 0x4 |
static int code_for_qualifier (int); |
static const char* qualifier_string (int); |
static const char* demangle_qualifier (int); |
static int demangle_expression (struct work_stuff *, const char **, string *, |
type_kind_t); |
static int |
demangle_integral_value (struct work_stuff *, const char **, string *); |
static int |
demangle_real_value (struct work_stuff *, const char **, string *); |
static void |
demangle_arm_hp_template (struct work_stuff *, const char **, int, string *); |
static void |
recursively_demangle (struct work_stuff *, const char **, string *, int); |
/* Translate count to integer, consuming tokens in the process. |
Conversion terminates on the first non-digit character. |
Trying to consume something that isn't a count results in no |
consumption of input and a return of -1. |
Overflow consumes the rest of the digits, and returns -1. */ |
static int |
consume_count (const char **type) |
{ |
int count = 0; |
if (! ISDIGIT ((unsigned char)**type)) |
return -1; |
while (ISDIGIT ((unsigned char)**type)) |
{ |
count *= 10; |
/* Check for overflow. |
We assume that count is represented using two's-complement; |
no power of two is divisible by ten, so if an overflow occurs |
when multiplying by ten, the result will not be a multiple of |
ten. */ |
if ((count % 10) != 0) |
{ |
while (ISDIGIT ((unsigned char) **type)) |
(*type)++; |
return -1; |
} |
count += **type - '0'; |
(*type)++; |
} |
if (count < 0) |
count = -1; |
return (count); |
} |
/* Like consume_count, but for counts that are preceded and followed |
by '_' if they are greater than 10. Also, -1 is returned for |
failure, since 0 can be a valid value. */ |
static int |
consume_count_with_underscores (const char **mangled) |
{ |
int idx; |
if (**mangled == '_') |
{ |
(*mangled)++; |
if (!ISDIGIT ((unsigned char)**mangled)) |
return -1; |
idx = consume_count (mangled); |
if (**mangled != '_') |
/* The trailing underscore was missing. */ |
return -1; |
(*mangled)++; |
} |
else |
{ |
if (**mangled < '0' || **mangled > '9') |
return -1; |
idx = **mangled - '0'; |
(*mangled)++; |
} |
return idx; |
} |
/* C is the code for a type-qualifier. Return the TYPE_QUAL |
corresponding to this qualifier. */ |
static int |
code_for_qualifier (int c) |
{ |
switch (c) |
{ |
case 'C': |
return TYPE_QUAL_CONST; |
case 'V': |
return TYPE_QUAL_VOLATILE; |
case 'u': |
return TYPE_QUAL_RESTRICT; |
default: |
break; |
} |
/* C was an invalid qualifier. */ |
abort (); |
} |
/* Return the string corresponding to the qualifiers given by |
TYPE_QUALS. */ |
static const char* |
qualifier_string (int type_quals) |
{ |
switch (type_quals) |
{ |
case TYPE_UNQUALIFIED: |
return ""; |
case TYPE_QUAL_CONST: |
return "const"; |
case TYPE_QUAL_VOLATILE: |
return "volatile"; |
case TYPE_QUAL_RESTRICT: |
return "__restrict"; |
case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE: |
return "const volatile"; |
case TYPE_QUAL_CONST | TYPE_QUAL_RESTRICT: |
return "const __restrict"; |
case TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: |
return "volatile __restrict"; |
case TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE | TYPE_QUAL_RESTRICT: |
return "const volatile __restrict"; |
default: |
break; |
} |
/* TYPE_QUALS was an invalid qualifier set. */ |
abort (); |
} |
/* C is the code for a type-qualifier. Return the string |
corresponding to this qualifier. This function should only be |
called with a valid qualifier code. */ |
static const char* |
demangle_qualifier (int c) |
{ |
return qualifier_string (code_for_qualifier (c)); |
} |
int |
cplus_demangle_opname (const char *opname, char *result, int options) |
{ |
int len, len1, ret; |
string type; |
struct work_stuff work[1]; |
const char *tem; |
len = strlen(opname); |
result[0] = '\0'; |
ret = 0; |
memset ((char *) work, 0, sizeof (work)); |
work->options = options; |
if (opname[0] == '_' && opname[1] == '_' |
&& opname[2] == 'o' && opname[3] == 'p') |
{ |
/* ANSI. */ |
/* type conversion operator. */ |
tem = opname + 4; |
if (do_type (work, &tem, &type)) |
{ |
strcat (result, "operator "); |
strncat (result, type.b, type.p - type.b); |
string_delete (&type); |
ret = 1; |
} |
} |
else if (opname[0] == '_' && opname[1] == '_' |
&& ISLOWER((unsigned char)opname[2]) |
&& ISLOWER((unsigned char)opname[3])) |
{ |
if (opname[4] == '\0') |
{ |
/* Operator. */ |
size_t i; |
for (i = 0; i < ARRAY_SIZE (optable); i++) |
{ |
if (strlen (optable[i].in) == 2 |
&& memcmp (optable[i].in, opname + 2, 2) == 0) |
{ |
strcat (result, "operator"); |
strcat (result, optable[i].out); |
ret = 1; |
break; |
} |
} |
} |
else |
{ |
if (opname[2] == 'a' && opname[5] == '\0') |
{ |
/* Assignment. */ |
size_t i; |
for (i = 0; i < ARRAY_SIZE (optable); i++) |
{ |
if (strlen (optable[i].in) == 3 |
&& memcmp (optable[i].in, opname + 2, 3) == 0) |
{ |
strcat (result, "operator"); |
strcat (result, optable[i].out); |
ret = 1; |
break; |
} |
} |
} |
} |
} |
else if (len >= 3 |
&& opname[0] == 'o' |
&& opname[1] == 'p' |
&& strchr (cplus_markers, opname[2]) != NULL) |
{ |
/* see if it's an assignment expression */ |
if (len >= 10 /* op$assign_ */ |
&& memcmp (opname + 3, "assign_", 7) == 0) |
{ |
size_t i; |
for (i = 0; i < ARRAY_SIZE (optable); i++) |
{ |
len1 = len - 10; |
if ((int) strlen (optable[i].in) == len1 |
&& memcmp (optable[i].in, opname + 10, len1) == 0) |
{ |
strcat (result, "operator"); |
strcat (result, optable[i].out); |
strcat (result, "="); |
ret = 1; |
break; |
} |
} |
} |
else |
{ |
size_t i; |
for (i = 0; i < ARRAY_SIZE (optable); i++) |
{ |
len1 = len - 3; |
if ((int) strlen (optable[i].in) == len1 |
&& memcmp (optable[i].in, opname + 3, len1) == 0) |
{ |
strcat (result, "operator"); |
strcat (result, optable[i].out); |
ret = 1; |
break; |
} |
} |
} |
} |
else if (len >= 5 && memcmp (opname, "type", 4) == 0 |
&& strchr (cplus_markers, opname[4]) != NULL) |
{ |
/* type conversion operator */ |
tem = opname + 5; |
if (do_type (work, &tem, &type)) |
{ |
strcat (result, "operator "); |
strncat (result, type.b, type.p - type.b); |
string_delete (&type); |
ret = 1; |
} |
} |
squangle_mop_up (work); |
return ret; |
} |
/* Takes operator name as e.g. "++" and returns mangled |
operator name (e.g. "postincrement_expr"), or NULL if not found. |
If OPTIONS & DMGL_ANSI == 1, return the ANSI name; |
if OPTIONS & DMGL_ANSI == 0, return the old GNU name. */ |
const char * |
cplus_mangle_opname (const char *opname, int options) |
{ |
size_t i; |
int len; |
len = strlen (opname); |
for (i = 0; i < ARRAY_SIZE (optable); i++) |
{ |
if ((int) strlen (optable[i].out) == len |
&& (options & DMGL_ANSI) == (optable[i].flags & DMGL_ANSI) |
&& memcmp (optable[i].out, opname, len) == 0) |
return optable[i].in; |
} |
return (0); |
} |
/* Add a routine to set the demangling style to be sure it is valid and |
allow for any demangler initialization that maybe necessary. */ |
enum demangling_styles |
cplus_demangle_set_style (enum demangling_styles style) |
{ |
const struct demangler_engine *demangler = libiberty_demanglers; |
for (; demangler->demangling_style != unknown_demangling; ++demangler) |
if (style == demangler->demangling_style) |
{ |
current_demangling_style = style; |
return current_demangling_style; |
} |
return unknown_demangling; |
} |
/* Do string name to style translation */ |
enum demangling_styles |
cplus_demangle_name_to_style (const char *name) |
{ |
const struct demangler_engine *demangler = libiberty_demanglers; |
for (; demangler->demangling_style != unknown_demangling; ++demangler) |
if (strcmp (name, demangler->demangling_style_name) == 0) |
return demangler->demangling_style; |
return unknown_demangling; |
} |
/* char *cplus_demangle (const char *mangled, int options) |
If MANGLED is a mangled function name produced by GNU C++, then |
a pointer to a @code{malloc}ed string giving a C++ representation |
of the name will be returned; otherwise NULL will be returned. |
It is the caller's responsibility to free the string which |
is returned. |
The OPTIONS arg may contain one or more of the following bits: |
DMGL_ANSI ANSI qualifiers such as `const' and `void' are |
included. |
DMGL_PARAMS Function parameters are included. |
For example, |
cplus_demangle ("foo__1Ai", DMGL_PARAMS) => "A::foo(int)" |
cplus_demangle ("foo__1Ai", DMGL_PARAMS | DMGL_ANSI) => "A::foo(int)" |
cplus_demangle ("foo__1Ai", 0) => "A::foo" |
cplus_demangle ("foo__1Afe", DMGL_PARAMS) => "A::foo(float,...)" |
cplus_demangle ("foo__1Afe", DMGL_PARAMS | DMGL_ANSI)=> "A::foo(float,...)" |
cplus_demangle ("foo__1Afe", 0) => "A::foo" |
Note that any leading underscores, or other such characters prepended by |
the compilation system, are presumed to have already been stripped from |
MANGLED. */ |
char * |
cplus_demangle (const char *mangled, int options) |
{ |
char *ret; |
struct work_stuff work[1]; |
if (current_demangling_style == no_demangling) |
return xstrdup (mangled); |
memset ((char *) work, 0, sizeof (work)); |
work->options = options; |
if ((work->options & DMGL_STYLE_MASK) == 0) |
work->options |= (int) current_demangling_style & DMGL_STYLE_MASK; |
/* The V3 ABI demangling is implemented elsewhere. */ |
if (GNU_V3_DEMANGLING || AUTO_DEMANGLING) |
{ |
ret = cplus_demangle_v3 (mangled, work->options); |
if (ret || GNU_V3_DEMANGLING) |
return ret; |
} |
if (JAVA_DEMANGLING) |
{ |
ret = java_demangle_v3 (mangled); |
if (ret) |
return ret; |
} |
if (GNAT_DEMANGLING) |
return ada_demangle (mangled, options); |
ret = internal_cplus_demangle (work, mangled); |
squangle_mop_up (work); |
return (ret); |
} |
/* Demangle ada names. The encoding is documented in gcc/ada/exp_dbug.ads. */ |
char * |
ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED) |
{ |
int len0; |
const char* p; |
char *d; |
char *demangled; |
/* Discard leading _ada_, which is used for library level subprograms. */ |
if (strncmp (mangled, "_ada_", 5) == 0) |
mangled += 5; |
/* All ada unit names are lower-case. */ |
if (!ISLOWER (mangled[0])) |
goto unknown; |
/* Most of the demangling will trivially remove chars. Operator names |
may add one char but because they are always preceeded by '__' which is |
replaced by '.', they eventually never expand the size. |
A few special names such as '___elabs' add a few chars (at most 7), but |
they occur only once. */ |
len0 = strlen (mangled) + 7 + 1; |
demangled = XNEWVEC (char, len0); |
d = demangled; |
p = mangled; |
while (1) |
{ |
/* An entity names is expected. */ |
if (ISLOWER (*p)) |
{ |
/* An identifier, which is always lower case. */ |
do |
*d++ = *p++; |
while (ISLOWER(*p) || ISDIGIT (*p) |
|| (p[0] == '_' && (ISLOWER (p[1]) || ISDIGIT (p[1])))); |
} |
else if (p[0] == 'O') |
{ |
/* An operator name. */ |
static const char * const operators[][2] = |
{{"Oabs", "abs"}, {"Oand", "and"}, {"Omod", "mod"}, |
{"Onot", "not"}, {"Oor", "or"}, {"Orem", "rem"}, |
{"Oxor", "xor"}, {"Oeq", "="}, {"One", "/="}, |
{"Olt", "<"}, {"Ole", "<="}, {"Ogt", ">"}, |
{"Oge", ">="}, {"Oadd", "+"}, {"Osubtract", "-"}, |
{"Oconcat", "&"}, {"Omultiply", "*"}, {"Odivide", "/"}, |
{"Oexpon", "**"}, {NULL, NULL}}; |
int k; |
for (k = 0; operators[k][0] != NULL; k++) |
{ |
size_t slen = strlen (operators[k][0]); |
if (strncmp (p, operators[k][0], slen) == 0) |
{ |
p += slen; |
slen = strlen (operators[k][1]); |
*d++ = '"'; |
memcpy (d, operators[k][1], slen); |
d += slen; |
*d++ = '"'; |
break; |
} |
} |
/* Operator not found. */ |
if (operators[k][0] == NULL) |
goto unknown; |
} |
else |
{ |
/* Not a GNAT encoding. */ |
goto unknown; |
} |
/* The name can be directly followed by some uppercase letters. */ |
if (p[0] == 'T' && p[1] == 'K') |
{ |
/* Task stuff. */ |
if (p[2] == 'B' && p[3] == 0) |
{ |
/* Subprogram for task body. */ |
break; |
} |
else if (p[2] == '_' && p[3] == '_') |
{ |
/* Inner declarations in a task. */ |
p += 4; |
*d++ = '.'; |
continue; |
} |
else |
goto unknown; |
} |
if (p[0] == 'E' && p[1] == 0) |
{ |
/* Exception name. */ |
goto unknown; |
} |
if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0) |
{ |
/* Protected type subprogram. */ |
break; |
} |
if ((*p == 'N' || *p == 'S') && p[1] == 0) |
{ |
/* Enumerated type name table. */ |
goto unknown; |
} |
if (p[0] == 'X') |
{ |
/* Body nested. */ |
p++; |
while (p[0] == 'n' || p[0] == 'b') |
p++; |
} |
if (p[0] == 'S' && p[1] != 0 && (p[2] == '_' || p[2] == 0)) |
{ |
/* Stream operations. */ |
const char *name; |
switch (p[1]) |
{ |
case 'R': |
name = "'Read"; |
break; |
case 'W': |
name = "'Write"; |
break; |
case 'I': |
name = "'Input"; |
break; |
case 'O': |
name = "'Output"; |
break; |
default: |
goto unknown; |
} |
p += 2; |
strcpy (d, name); |
d += strlen (name); |
} |
else if (p[0] == 'D') |
{ |
/* Controlled type operation. */ |
const char *name; |
switch (p[1]) |
{ |
case 'F': |
name = ".Finalize"; |
break; |
case 'A': |
name = ".Adjust"; |
break; |
default: |
goto unknown; |
} |
strcpy (d, name); |
d += strlen (name); |
break; |
} |
if (p[0] == '_') |
{ |
/* Separator. */ |
if (p[1] == '_') |
{ |
/* Standard separator. Handled first. */ |
p += 2; |
if (ISDIGIT (*p)) |
{ |
/* Overloading number. */ |
do |
p++; |
while (ISDIGIT (*p) || (p[0] == '_' && ISDIGIT (p[1]))); |
if (*p == 'X') |
{ |
p++; |
while (p[0] == 'n' || p[0] == 'b') |
p++; |
} |
} |
else if (p[0] == '_' && p[1] != '_') |
{ |
/* Special names. */ |
static const char * const special[][2] = { |
{ "_elabb", "'Elab_Body" }, |
{ "_elabs", "'Elab_Spec" }, |
{ "_size", "'Size" }, |
{ "_alignment", "'Alignment" }, |
{ "_assign", ".\":=\"" }, |
{ NULL, NULL } |
}; |
int k; |
for (k = 0; special[k][0] != NULL; k++) |
{ |
size_t slen = strlen (special[k][0]); |
if (strncmp (p, special[k][0], slen) == 0) |
{ |
p += slen; |
slen = strlen (special[k][1]); |
memcpy (d, special[k][1], slen); |
d += slen; |
break; |
} |
} |
if (special[k][0] != NULL) |
break; |
else |
goto unknown; |
} |
else |
{ |
*d++ = '.'; |
continue; |
} |
} |
else if (p[1] == 'B' || p[1] == 'E') |
{ |
/* Entry Body or barrier Evaluation. */ |
p += 2; |
while (ISDIGIT (*p)) |
p++; |
if (p[0] == 's' && p[1] == 0) |
break; |
else |
goto unknown; |
} |
else |
goto unknown; |
} |
if (p[0] == '.' && ISDIGIT (p[1])) |
{ |
/* Nested subprogram. */ |
p += 2; |
while (ISDIGIT (*p)) |
p++; |
} |
if (*p == 0) |
{ |
/* End of mangled name. */ |
break; |
} |
else |
goto unknown; |
} |
*d = 0; |
return demangled; |
unknown: |
len0 = strlen (mangled); |
demangled = XNEWVEC (char, len0 + 3); |
if (mangled[0] == '<') |
strcpy (demangled, mangled); |
else |
sprintf (demangled, "<%s>", mangled); |
return demangled; |
} |
/* This function performs most of what cplus_demangle use to do, but |
to be able to demangle a name with a B, K or n code, we need to |
have a longer term memory of what types have been seen. The original |
now initializes and cleans up the squangle code info, while internal |
calls go directly to this routine to avoid resetting that info. */ |
static char * |
internal_cplus_demangle (struct work_stuff *work, const char *mangled) |
{ |
string decl; |
int success = 0; |
char *demangled = NULL; |
int s1, s2, s3, s4; |
s1 = work->constructor; |
s2 = work->destructor; |
s3 = work->static_type; |
s4 = work->type_quals; |
work->constructor = work->destructor = 0; |
work->type_quals = TYPE_UNQUALIFIED; |
work->dllimported = 0; |
if ((mangled != NULL) && (*mangled != '\0')) |
{ |
string_init (&decl); |
/* First check to see if gnu style demangling is active and if the |
string to be demangled contains a CPLUS_MARKER. If so, attempt to |
recognize one of the gnu special forms rather than looking for a |
standard prefix. In particular, don't worry about whether there |
is a "__" string in the mangled string. Consider "_$_5__foo" for |
example. */ |
if ((AUTO_DEMANGLING || GNU_DEMANGLING)) |
{ |
success = gnu_special (work, &mangled, &decl); |
} |
if (!success) |
{ |
success = demangle_prefix (work, &mangled, &decl); |
} |
if (success && (*mangled != '\0')) |
{ |
success = demangle_signature (work, &mangled, &decl); |
} |
if (work->constructor == 2) |
{ |
string_prepend (&decl, "global constructors keyed to "); |
work->constructor = 0; |
} |
else if (work->destructor == 2) |
{ |
string_prepend (&decl, "global destructors keyed to "); |
work->destructor = 0; |
} |
else if (work->dllimported == 1) |
{ |
string_prepend (&decl, "import stub for "); |
work->dllimported = 0; |
} |
demangled = mop_up (work, &decl, success); |
} |
work->constructor = s1; |
work->destructor = s2; |
work->static_type = s3; |
work->type_quals = s4; |
return demangled; |
} |
/* Clear out and squangling related storage */ |
static void |
squangle_mop_up (struct work_stuff *work) |
{ |
/* clean up the B and K type mangling types. */ |
forget_B_and_K_types (work); |
if (work -> btypevec != NULL) |
{ |
free ((char *) work -> btypevec); |
} |
if (work -> ktypevec != NULL) |
{ |
free ((char *) work -> ktypevec); |
} |
} |
/* Copy the work state and storage. */ |
static void |
work_stuff_copy_to_from (struct work_stuff *to, struct work_stuff *from) |
{ |
int i; |
delete_work_stuff (to); |
/* Shallow-copy scalars. */ |
memcpy (to, from, sizeof (*to)); |
/* Deep-copy dynamic storage. */ |
if (from->typevec_size) |
to->typevec = XNEWVEC (char *, from->typevec_size); |
for (i = 0; i < from->ntypes; i++) |
{ |
int len = strlen (from->typevec[i]) + 1; |
to->typevec[i] = XNEWVEC (char, len); |
memcpy (to->typevec[i], from->typevec[i], len); |
} |
if (from->ksize) |
to->ktypevec = XNEWVEC (char *, from->ksize); |
for (i = 0; i < from->numk; i++) |
{ |
int len = strlen (from->ktypevec[i]) + 1; |
to->ktypevec[i] = XNEWVEC (char, len); |
memcpy (to->ktypevec[i], from->ktypevec[i], len); |
} |
if (from->bsize) |
to->btypevec = XNEWVEC (char *, from->bsize); |
for (i = 0; i < from->numb; i++) |
{ |
int len = strlen (from->btypevec[i]) + 1; |
to->btypevec[i] = XNEWVEC (char , len); |
memcpy (to->btypevec[i], from->btypevec[i], len); |
} |
if (from->ntmpl_args) |
to->tmpl_argvec = XNEWVEC (char *, from->ntmpl_args); |
for (i = 0; i < from->ntmpl_args; i++) |
{ |
int len = strlen (from->tmpl_argvec[i]) + 1; |
to->tmpl_argvec[i] = XNEWVEC (char, len); |
memcpy (to->tmpl_argvec[i], from->tmpl_argvec[i], len); |
} |
if (from->previous_argument) |
{ |
to->previous_argument = XNEW (string); |
string_init (to->previous_argument); |
string_appends (to->previous_argument, from->previous_argument); |
} |
} |
/* Delete dynamic stuff in work_stuff that is not to be re-used. */ |
static void |
delete_non_B_K_work_stuff (struct work_stuff *work) |
{ |
/* Discard the remembered types, if any. */ |
forget_types (work); |
if (work -> typevec != NULL) |
{ |
free ((char *) work -> typevec); |
work -> typevec = NULL; |
work -> typevec_size = 0; |
} |
if (work->tmpl_argvec) |
{ |
int i; |
for (i = 0; i < work->ntmpl_args; i++) |
free ((char*) work->tmpl_argvec[i]); |
free ((char*) work->tmpl_argvec); |
work->tmpl_argvec = NULL; |
} |
if (work->previous_argument) |
{ |
string_delete (work->previous_argument); |
free ((char*) work->previous_argument); |
work->previous_argument = NULL; |
} |
} |
/* Delete all dynamic storage in work_stuff. */ |
static void |
delete_work_stuff (struct work_stuff *work) |
{ |
delete_non_B_K_work_stuff (work); |
squangle_mop_up (work); |
} |
/* Clear out any mangled storage */ |
static char * |
mop_up (struct work_stuff *work, string *declp, int success) |
{ |
char *demangled = NULL; |
delete_non_B_K_work_stuff (work); |
/* If demangling was successful, ensure that the demangled string is null |
terminated and return it. Otherwise, free the demangling decl. */ |
if (!success) |
{ |
string_delete (declp); |
} |
else |
{ |
string_appendn (declp, "", 1); |
demangled = declp->b; |
} |
return (demangled); |
} |
/* |
LOCAL FUNCTION |
demangle_signature -- demangle the signature part of a mangled name |
SYNOPSIS |
static int |
demangle_signature (struct work_stuff *work, const char **mangled, |
string *declp); |
DESCRIPTION |
Consume and demangle the signature portion of the mangled name. |
DECLP is the string where demangled output is being built. At |
entry it contains the demangled root name from the mangled name |
prefix. I.E. either a demangled operator name or the root function |
name. In some special cases, it may contain nothing. |
*MANGLED points to the current unconsumed location in the mangled |
name. As tokens are consumed and demangling is performed, the |
pointer is updated to continuously point at the next token to |
be consumed. |
Demangling GNU style mangled names is nasty because there is no |
explicit token that marks the start of the outermost function |
argument list. */ |
static int |
demangle_signature (struct work_stuff *work, |
const char **mangled, string *declp) |
{ |
int success = 1; |
int func_done = 0; |
int expect_func = 0; |
int expect_return_type = 0; |
const char *oldmangled = NULL; |
string trawname; |
string tname; |
while (success && (**mangled != '\0')) |
{ |
switch (**mangled) |
{ |
case 'Q': |
oldmangled = *mangled; |
success = demangle_qualified (work, mangled, declp, 1, 0); |
if (success) |
remember_type (work, oldmangled, *mangled - oldmangled); |
if (AUTO_DEMANGLING || GNU_DEMANGLING) |
expect_func = 1; |
oldmangled = NULL; |
break; |
case 'K': |
oldmangled = *mangled; |
success = demangle_qualified (work, mangled, declp, 1, 0); |
if (AUTO_DEMANGLING || GNU_DEMANGLING) |
{ |
expect_func = 1; |
} |
oldmangled = NULL; |
break; |
case 'S': |
/* Static member function */ |
if (oldmangled == NULL) |
{ |
oldmangled = *mangled; |
} |
(*mangled)++; |
work -> static_type = 1; |
break; |
case 'C': |
case 'V': |
case 'u': |
work->type_quals |= code_for_qualifier (**mangled); |
/* a qualified member function */ |
if (oldmangled == NULL) |
oldmangled = *mangled; |
(*mangled)++; |
break; |
case 'L': |
/* Local class name follows after "Lnnn_" */ |
if (HP_DEMANGLING) |
{ |
while (**mangled && (**mangled != '_')) |
(*mangled)++; |
if (!**mangled) |
success = 0; |
else |
(*mangled)++; |
} |
else |
success = 0; |
break; |
case '0': case '1': case '2': case '3': case '4': |
case '5': case '6': case '7': case '8': case '9': |
if (oldmangled == NULL) |
{ |
oldmangled = *mangled; |
} |
work->temp_start = -1; /* uppermost call to demangle_class */ |
success = demangle_class (work, mangled, declp); |
if (success) |
{ |
remember_type (work, oldmangled, *mangled - oldmangled); |
} |
if (AUTO_DEMANGLING || GNU_DEMANGLING || EDG_DEMANGLING) |
{ |
/* EDG and others will have the "F", so we let the loop cycle |
if we are looking at one. */ |
if (**mangled != 'F') |
expect_func = 1; |
} |
oldmangled = NULL; |
break; |
case 'B': |
{ |
string s; |
success = do_type (work, mangled, &s); |
if (success) |
{ |
string_append (&s, SCOPE_STRING (work)); |
string_prepends (declp, &s); |
string_delete (&s); |
} |
oldmangled = NULL; |
expect_func = 1; |
} |
break; |
case 'F': |
/* Function */ |
/* ARM/HP style demangling includes a specific 'F' character after |
the class name. For GNU style, it is just implied. So we can |
safely just consume any 'F' at this point and be compatible |
with either style. */ |
oldmangled = NULL; |
func_done = 1; |
(*mangled)++; |
/* For lucid/ARM/HP style we have to forget any types we might |
have remembered up to this point, since they were not argument |
types. GNU style considers all types seen as available for |
back references. See comment in demangle_args() */ |
if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) |
{ |
forget_types (work); |
} |
success = demangle_args (work, mangled, declp); |
/* After picking off the function args, we expect to either |
find the function return type (preceded by an '_') or the |
end of the string. */ |
if (success && (AUTO_DEMANGLING || EDG_DEMANGLING) && **mangled == '_') |
{ |
++(*mangled); |
/* At this level, we do not care about the return type. */ |
success = do_type (work, mangled, &tname); |
string_delete (&tname); |
} |
break; |
case 't': |
/* G++ Template */ |
string_init(&trawname); |
string_init(&tname); |
if (oldmangled == NULL) |
{ |
oldmangled = *mangled; |
} |
success = demangle_template (work, mangled, &tname, |
&trawname, 1, 1); |
if (success) |
{ |
remember_type (work, oldmangled, *mangled - oldmangled); |
} |
string_append (&tname, SCOPE_STRING (work)); |
string_prepends(declp, &tname); |
if (work -> destructor & 1) |
{ |
string_prepend (&trawname, "~"); |
string_appends (declp, &trawname); |
work->destructor -= 1; |
} |
if ((work->constructor & 1) || (work->destructor & 1)) |
{ |
string_appends (declp, &trawname); |
work->constructor -= 1; |
} |
string_delete(&trawname); |
string_delete(&tname); |
oldmangled = NULL; |
expect_func = 1; |
break; |
case '_': |
if ((AUTO_DEMANGLING || GNU_DEMANGLING) && expect_return_type) |
{ |
/* Read the return type. */ |
string return_type; |
(*mangled)++; |
success = do_type (work, mangled, &return_type); |
APPEND_BLANK (&return_type); |
string_prepends (declp, &return_type); |
string_delete (&return_type); |
break; |
} |
else |
/* At the outermost level, we cannot have a return type specified, |
so if we run into another '_' at this point we are dealing with |
a mangled name that is either bogus, or has been mangled by |
some algorithm we don't know how to deal with. So just |
reject the entire demangling. */ |
/* However, "_nnn" is an expected suffix for alternate entry point |
numbered nnn for a function, with HP aCC, so skip over that |
without reporting failure. pai/1997-09-04 */ |
if (HP_DEMANGLING) |
{ |
(*mangled)++; |
while (**mangled && ISDIGIT ((unsigned char)**mangled)) |
(*mangled)++; |
} |
else |
success = 0; |
break; |
case 'H': |
if (AUTO_DEMANGLING || GNU_DEMANGLING) |
{ |
/* A G++ template function. Read the template arguments. */ |
success = demangle_template (work, mangled, declp, 0, 0, |
0); |
if (!(work->constructor & 1)) |
expect_return_type = 1; |
(*mangled)++; |
break; |
} |
else |
/* fall through */ |
{;} |
default: |
if (AUTO_DEMANGLING || GNU_DEMANGLING) |
{ |
/* Assume we have stumbled onto the first outermost function |
argument token, and start processing args. */ |
func_done = 1; |
success = demangle_args (work, mangled, declp); |
} |
else |
{ |
/* Non-GNU demanglers use a specific token to mark the start |
of the outermost function argument tokens. Typically 'F', |
for ARM/HP-demangling, for example. So if we find something |
we are not prepared for, it must be an error. */ |
success = 0; |
} |
break; |
} |
/* |
if (AUTO_DEMANGLING || GNU_DEMANGLING) |
*/ |
{ |
if (success && expect_func) |
{ |
func_done = 1; |
if (LUCID_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) |
{ |
forget_types (work); |
} |
success = demangle_args (work, mangled, declp); |
/* Since template include the mangling of their return types, |
we must set expect_func to 0 so that we don't try do |
demangle more arguments the next time we get here. */ |
expect_func = 0; |
} |
} |
} |
if (success && !func_done) |
{ |
if (AUTO_DEMANGLING || GNU_DEMANGLING) |
{ |
/* With GNU style demangling, bar__3foo is 'foo::bar(void)', and |
bar__3fooi is 'foo::bar(int)'. We get here when we find the |
first case, and need to ensure that the '(void)' gets added to |
the current declp. Note that with ARM/HP, the first case |
represents the name of a static data member 'foo::bar', |
which is in the current declp, so we leave it alone. */ |
success = demangle_args (work, mangled, declp); |
} |
} |
if (success && PRINT_ARG_TYPES) |
{ |
if (work->static_type) |
string_append (declp, " static"); |
if (work->type_quals != TYPE_UNQUALIFIED) |
{ |
APPEND_BLANK (declp); |
string_append (declp, qualifier_string (work->type_quals)); |
} |
} |
return (success); |
} |
#if 0 |
static int |
demangle_method_args (struct work_stuff *work, const char **mangled, |
string *declp) |
{ |
int success = 0; |
if (work -> static_type) |
{ |
string_append (declp, *mangled + 1); |
*mangled += strlen (*mangled); |
success = 1; |
} |
else |
{ |
success = demangle_args (work, mangled, declp); |
} |
return (success); |
} |
#endif |
static int |
demangle_template_template_parm (struct work_stuff *work, |
const char **mangled, string *tname) |
{ |
int i; |
int r; |
int need_comma = 0; |
int success = 1; |
string temp; |
string_append (tname, "template <"); |
/* get size of template parameter list */ |
if (get_count (mangled, &r)) |
{ |
for (i = 0; i < r; i++) |
{ |
if (need_comma) |
{ |
string_append (tname, ", "); |
} |
/* Z for type parameters */ |
if (**mangled == 'Z') |
{ |
(*mangled)++; |
string_append (tname, "class"); |
} |
/* z for template parameters */ |
else if (**mangled == 'z') |
{ |
(*mangled)++; |
success = |
demangle_template_template_parm (work, mangled, tname); |
if (!success) |
{ |
break; |
} |
} |
else |
{ |
/* temp is initialized in do_type */ |
success = do_type (work, mangled, &temp); |
if (success) |
{ |
string_appends (tname, &temp); |
} |
string_delete(&temp); |
if (!success) |
{ |
break; |
} |
} |
need_comma = 1; |
} |
} |
if (tname->p[-1] == '>') |
string_append (tname, " "); |
string_append (tname, "> class"); |
return (success); |
} |
static int |
demangle_expression (struct work_stuff *work, const char **mangled, |
string *s, type_kind_t tk) |
{ |
int need_operator = 0; |
int success; |
success = 1; |
string_appendn (s, "(", 1); |
(*mangled)++; |
while (success && **mangled != 'W' && **mangled != '\0') |
{ |
if (need_operator) |
{ |
size_t i; |
size_t len; |
success = 0; |
len = strlen (*mangled); |
for (i = 0; i < ARRAY_SIZE (optable); ++i) |
{ |
size_t l = strlen (optable[i].in); |
if (l <= len |
&& memcmp (optable[i].in, *mangled, l) == 0) |
{ |
string_appendn (s, " ", 1); |
string_append (s, optable[i].out); |
string_appendn (s, " ", 1); |
success = 1; |
(*mangled) += l; |
break; |
} |
} |
if (!success) |
break; |
} |
else |
need_operator = 1; |
success = demangle_template_value_parm (work, mangled, s, tk); |
} |
if (**mangled != 'W') |
success = 0; |
else |
{ |
string_appendn (s, ")", 1); |
(*mangled)++; |
} |
return success; |
} |
static int |
demangle_integral_value (struct work_stuff *work, |
const char **mangled, string *s) |
{ |
int success; |
if (**mangled == 'E') |
success = demangle_expression (work, mangled, s, tk_integral); |
else if (**mangled == 'Q' || **mangled == 'K') |
success = demangle_qualified (work, mangled, s, 0, 1); |
else |
{ |
int value; |
/* By default, we let the number decide whether we shall consume an |
underscore. */ |
int multidigit_without_leading_underscore = 0; |
int leave_following_underscore = 0; |
success = 0; |
if (**mangled == '_') |
{ |
if (mangled[0][1] == 'm') |
{ |
/* Since consume_count_with_underscores does not handle the |
`m'-prefix we must do it here, using consume_count and |
adjusting underscores: we have to consume the underscore |
matching the prepended one. */ |
multidigit_without_leading_underscore = 1; |
string_appendn (s, "-", 1); |
(*mangled) += 2; |
} |
else |
{ |
/* Do not consume a following underscore; |
consume_count_with_underscores will consume what |
should be consumed. */ |
leave_following_underscore = 1; |
} |
} |
else |
{ |
/* Negative numbers are indicated with a leading `m'. */ |
if (**mangled == 'm') |
{ |
string_appendn (s, "-", 1); |
(*mangled)++; |
} |
/* Since consume_count_with_underscores does not handle |
multi-digit numbers that do not start with an underscore, |
and this number can be an integer template parameter, |
we have to call consume_count. */ |
multidigit_without_leading_underscore = 1; |
/* These multi-digit numbers never end on an underscore, |
so if there is one then don't eat it. */ |
leave_following_underscore = 1; |
} |
/* We must call consume_count if we expect to remove a trailing |
underscore, since consume_count_with_underscores expects |
the leading underscore (that we consumed) if it is to handle |
multi-digit numbers. */ |
if (multidigit_without_leading_underscore) |
value = consume_count (mangled); |
else |
value = consume_count_with_underscores (mangled); |
if (value != -1) |
{ |
char buf[INTBUF_SIZE]; |
sprintf (buf, "%d", value); |
string_append (s, buf); |
/* Numbers not otherwise delimited, might have an underscore |
appended as a delimeter, which we should skip. |
??? This used to always remove a following underscore, which |
is wrong. If other (arbitrary) cases are followed by an |
underscore, we need to do something more radical. */ |
if ((value > 9 || multidigit_without_leading_underscore) |
&& ! leave_following_underscore |
&& **mangled == '_') |
(*mangled)++; |
/* All is well. */ |
success = 1; |
} |
} |
return success; |
} |
/* Demangle the real value in MANGLED. */ |
static int |
demangle_real_value (struct work_stuff *work, |
const char **mangled, string *s) |
{ |
if (**mangled == 'E') |
return demangle_expression (work, mangled, s, tk_real); |
if (**mangled == 'm') |
{ |
string_appendn (s, "-", 1); |
(*mangled)++; |
} |
while (ISDIGIT ((unsigned char)**mangled)) |
{ |
string_appendn (s, *mangled, 1); |
(*mangled)++; |
} |
if (**mangled == '.') /* fraction */ |
{ |
string_appendn (s, ".", 1); |
(*mangled)++; |
while (ISDIGIT ((unsigned char)**mangled)) |
{ |
string_appendn (s, *mangled, 1); |
(*mangled)++; |
} |
} |
if (**mangled == 'e') /* exponent */ |
{ |
string_appendn (s, "e", 1); |
(*mangled)++; |
while (ISDIGIT ((unsigned char)**mangled)) |
{ |
string_appendn (s, *mangled, 1); |
(*mangled)++; |
} |
} |
return 1; |
} |
static int |
demangle_template_value_parm (struct work_stuff *work, const char **mangled, |
string *s, type_kind_t tk) |
{ |
int success = 1; |
if (**mangled == 'Y') |
{ |
/* The next argument is a template parameter. */ |
int idx; |
(*mangled)++; |
idx = consume_count_with_underscores (mangled); |
if (idx == -1 |
|| (work->tmpl_argvec && idx >= work->ntmpl_args) |
|| consume_count_with_underscores (mangled) == -1) |
return -1; |
if (work->tmpl_argvec) |
string_append (s, work->tmpl_argvec[idx]); |
else |
string_append_template_idx (s, idx); |
} |
else if (tk == tk_integral) |
success = demangle_integral_value (work, mangled, s); |
else if (tk == tk_char) |
{ |
char tmp[2]; |
int val; |
if (**mangled == 'm') |
{ |
string_appendn (s, "-", 1); |
(*mangled)++; |
} |
string_appendn (s, "'", 1); |
val = consume_count(mangled); |
if (val <= 0) |
success = 0; |
else |
{ |
tmp[0] = (char)val; |
tmp[1] = '\0'; |
string_appendn (s, &tmp[0], 1); |
string_appendn (s, "'", 1); |
} |
} |
else if (tk == tk_bool) |
{ |
int val = consume_count (mangled); |
if (val == 0) |
string_appendn (s, "false", 5); |
else if (val == 1) |
string_appendn (s, "true", 4); |
else |
success = 0; |
} |
else if (tk == tk_real) |
success = demangle_real_value (work, mangled, s); |
else if (tk == tk_pointer || tk == tk_reference) |
{ |
if (**mangled == 'Q') |
success = demangle_qualified (work, mangled, s, |
/*isfuncname=*/0, |
/*append=*/1); |
else |
{ |
int symbol_len = consume_count (mangled); |
if (symbol_len == -1) |
return -1; |
if (symbol_len == 0) |
string_appendn (s, "0", 1); |
else |
{ |
char *p = XNEWVEC (char, symbol_len + 1), *q; |
strncpy (p, *mangled, symbol_len); |
p [symbol_len] = '\0'; |
/* We use cplus_demangle here, rather than |
internal_cplus_demangle, because the name of the entity |
mangled here does not make use of any of the squangling |
or type-code information we have built up thus far; it is |
mangled independently. */ |
q = cplus_demangle (p, work->options); |
if (tk == tk_pointer) |
string_appendn (s, "&", 1); |
/* FIXME: Pointer-to-member constants should get a |
qualifying class name here. */ |
if (q) |
{ |
string_append (s, q); |
free (q); |
} |
else |
string_append (s, p); |
free (p); |
} |
*mangled += symbol_len; |
} |
} |
return success; |
} |
/* Demangle the template name in MANGLED. The full name of the |
template (e.g., S<int>) is placed in TNAME. The name without the |
template parameters (e.g. S) is placed in TRAWNAME if TRAWNAME is |
non-NULL. If IS_TYPE is nonzero, this template is a type template, |
not a function template. If both IS_TYPE and REMEMBER are nonzero, |
the template is remembered in the list of back-referenceable |
types. */ |
static int |
demangle_template (struct work_stuff *work, const char **mangled, |
string *tname, string *trawname, |
int is_type, int remember) |
{ |
int i; |
int r; |
int need_comma = 0; |
int success = 0; |
int is_java_array = 0; |
string temp; |
(*mangled)++; |
if (is_type) |
{ |
/* get template name */ |
if (**mangled == 'z') |
{ |
int idx; |
(*mangled)++; |
(*mangled)++; |
idx = consume_count_with_underscores (mangled); |
if (idx == -1 |
|| (work->tmpl_argvec && idx >= work->ntmpl_args) |
|| consume_count_with_underscores (mangled) == -1) |
return (0); |
if (work->tmpl_argvec) |
{ |
string_append (tname, work->tmpl_argvec[idx]); |
if (trawname) |
string_append (trawname, work->tmpl_argvec[idx]); |
} |
else |
{ |
string_append_template_idx (tname, idx); |
if (trawname) |
string_append_template_idx (trawname, idx); |
} |
} |
else |
{ |
if ((r = consume_count (mangled)) <= 0 |
|| (int) strlen (*mangled) < r) |
{ |
return (0); |
} |
is_java_array = (work -> options & DMGL_JAVA) |
&& strncmp (*mangled, "JArray1Z", 8) == 0; |
if (! is_java_array) |
{ |
string_appendn (tname, *mangled, r); |
} |
if (trawname) |
string_appendn (trawname, *mangled, r); |
*mangled += r; |
} |
} |
if (!is_java_array) |
string_append (tname, "<"); |
/* get size of template parameter list */ |
if (!get_count (mangled, &r)) |
{ |
return (0); |
} |
if (!is_type) |
{ |
/* Create an array for saving the template argument values. */ |
work->tmpl_argvec = XNEWVEC (char *, r); |
work->ntmpl_args = r; |
for (i = 0; i < r; i++) |
work->tmpl_argvec[i] = 0; |
} |
for (i = 0; i < r; i++) |
{ |
if (need_comma) |
{ |
string_append (tname, ", "); |
} |
/* Z for type parameters */ |
if (**mangled == 'Z') |
{ |
(*mangled)++; |
/* temp is initialized in do_type */ |
success = do_type (work, mangled, &temp); |
if (success) |
{ |
string_appends (tname, &temp); |
if (!is_type) |
{ |
/* Save the template argument. */ |
int len = temp.p - temp.b; |
work->tmpl_argvec[i] = XNEWVEC (char, len + 1); |
memcpy (work->tmpl_argvec[i], temp.b, len); |
work->tmpl_argvec[i][len] = '\0'; |
} |
} |
string_delete(&temp); |
if (!success) |
{ |
break; |
} |
} |
/* z for template parameters */ |
else if (**mangled == 'z') |
{ |
int r2; |
(*mangled)++; |
success = demangle_template_template_parm (work, mangled, tname); |
if (success |
&& (r2 = consume_count (mangled)) > 0 |
&& (int) strlen (*mangled) >= r2) |
{ |
string_append (tname, " "); |
string_appendn (tname, *mangled, r2); |
if (!is_type) |
{ |
/* Save the template argument. */ |
int len = r2; |
work->tmpl_argvec[i] = XNEWVEC (char, len + 1); |
memcpy (work->tmpl_argvec[i], *mangled, len); |
work->tmpl_argvec[i][len] = '\0'; |
} |
*mangled += r2; |
} |
if (!success) |
{ |
break; |
} |
} |
else |
{ |
string param; |
string* s; |
/* otherwise, value parameter */ |
/* temp is initialized in do_type */ |
success = do_type (work, mangled, &temp); |
string_delete(&temp); |
if (!success) |
break; |
if (!is_type) |
{ |
s = ¶m; |
string_init (s); |
} |
else |
s = tname; |
success = demangle_template_value_parm (work, mangled, s, |
(type_kind_t) success); |
if (!success) |
{ |
if (!is_type) |
string_delete (s); |
success = 0; |
break; |
} |
if (!is_type) |
{ |
int len = s->p - s->b; |
work->tmpl_argvec[i] = XNEWVEC (char, len + 1); |
memcpy (work->tmpl_argvec[i], s->b, len); |
work->tmpl_argvec[i][len] = '\0'; |
string_appends (tname, s); |
string_delete (s); |
} |
} |
need_comma = 1; |
} |
if (is_java_array) |
{ |
string_append (tname, "[]"); |
} |
else |
{ |
if (tname->p[-1] == '>') |
string_append (tname, " "); |
string_append (tname, ">"); |
} |
if (is_type && remember) |
{ |
const int bindex = register_Btype (work); |
remember_Btype (work, tname->b, LEN_STRING (tname), bindex); |
} |
/* |
if (work -> static_type) |
{ |
string_append (declp, *mangled + 1); |
*mangled += strlen (*mangled); |
success = 1; |
} |
else |
{ |
success = demangle_args (work, mangled, declp); |
} |
} |
*/ |
return (success); |
} |
static int |
arm_pt (struct work_stuff *work, const char *mangled, |
int n, const char **anchor, const char **args) |
{ |
/* Check if ARM template with "__pt__" in it ("parameterized type") */ |
/* Allow HP also here, because HP's cfront compiler follows ARM to some extent */ |
if ((ARM_DEMANGLING || HP_DEMANGLING) && (*anchor = strstr (mangled, "__pt__"))) |
{ |
int len; |
*args = *anchor + 6; |
len = consume_count (args); |
if (len == -1) |
return 0; |
if (*args + len == mangled + n && **args == '_') |
{ |
++*args; |
return 1; |
} |
} |
if (AUTO_DEMANGLING || EDG_DEMANGLING) |
{ |
if ((*anchor = strstr (mangled, "__tm__")) |
|| (*anchor = strstr (mangled, "__ps__")) |
|| (*anchor = strstr (mangled, "__pt__"))) |
{ |
int len; |
*args = *anchor + 6; |
len = consume_count (args); |
if (len == -1) |
return 0; |
if (*args + len == mangled + n && **args == '_') |
{ |
++*args; |
return 1; |
} |
} |
else if ((*anchor = strstr (mangled, "__S"))) |
{ |
int len; |
*args = *anchor + 3; |
len = consume_count (args); |
if (len == -1) |
return 0; |
if (*args + len == mangled + n && **args == '_') |
{ |
++*args; |
return 1; |
} |
} |
} |
return 0; |
} |
static void |
demangle_arm_hp_template (struct work_stuff *work, const char **mangled, |
int n, string *declp) |
{ |
const char *p; |
const char *args; |
const char *e = *mangled + n; |
string arg; |
/* Check for HP aCC template spec: classXt1t2 where t1, t2 are |
template args */ |
if (HP_DEMANGLING && ((*mangled)[n] == 'X')) |
{ |
char *start_spec_args = NULL; |
int hold_options; |
/* First check for and omit template specialization pseudo-arguments, |
such as in "Spec<#1,#1.*>" */ |
start_spec_args = strchr (*mangled, '<'); |
if (start_spec_args && (start_spec_args - *mangled < n)) |
string_appendn (declp, *mangled, start_spec_args - *mangled); |
else |
string_appendn (declp, *mangled, n); |
(*mangled) += n + 1; |
string_init (&arg); |
if (work->temp_start == -1) /* non-recursive call */ |
work->temp_start = declp->p - declp->b; |
/* We want to unconditionally demangle parameter types in |
template parameters. */ |
hold_options = work->options; |
work->options |= DMGL_PARAMS; |
string_append (declp, "<"); |
while (1) |
{ |
string_delete (&arg); |
switch (**mangled) |
{ |
case 'T': |
/* 'T' signals a type parameter */ |
(*mangled)++; |
if (!do_type (work, mangled, &arg)) |
goto hpacc_template_args_done; |
break; |
case 'U': |
case 'S': |
/* 'U' or 'S' signals an integral value */ |
if (!do_hpacc_template_const_value (work, mangled, &arg)) |
goto hpacc_template_args_done; |
break; |
case 'A': |
/* 'A' signals a named constant expression (literal) */ |
if (!do_hpacc_template_literal (work, mangled, &arg)) |
goto hpacc_template_args_done; |
break; |
default: |
/* Today, 1997-09-03, we have only the above types |
of template parameters */ |
/* FIXME: maybe this should fail and return null */ |
goto hpacc_template_args_done; |
} |
string_appends (declp, &arg); |
/* Check if we're at the end of template args. |
0 if at end of static member of template class, |
_ if done with template args for a function */ |
if ((**mangled == '\000') || (**mangled == '_')) |
break; |
else |
string_append (declp, ","); |
} |
hpacc_template_args_done: |
string_append (declp, ">"); |
string_delete (&arg); |
if (**mangled == '_') |
(*mangled)++; |
work->options = hold_options; |
return; |
} |
/* ARM template? (Also handles HP cfront extensions) */ |
else if (arm_pt (work, *mangled, n, &p, &args)) |
{ |
int hold_options; |
string type_str; |
string_init (&arg); |
string_appendn (declp, *mangled, p - *mangled); |
if (work->temp_start == -1) /* non-recursive call */ |
work->temp_start = declp->p - declp->b; |
/* We want to unconditionally demangle parameter types in |
template parameters. */ |
hold_options = work->options; |
work->options |= DMGL_PARAMS; |
string_append (declp, "<"); |
/* should do error checking here */ |
while (args < e) { |
string_delete (&arg); |
/* Check for type or literal here */ |
switch (*args) |
{ |
/* HP cfront extensions to ARM for template args */ |
/* spec: Xt1Lv1 where t1 is a type, v1 is a literal value */ |
/* FIXME: We handle only numeric literals for HP cfront */ |
case 'X': |
/* A typed constant value follows */ |
args++; |
if (!do_type (work, &args, &type_str)) |
goto cfront_template_args_done; |
string_append (&arg, "("); |
string_appends (&arg, &type_str); |
string_delete (&type_str); |
string_append (&arg, ")"); |
if (*args != 'L') |
goto cfront_template_args_done; |
args++; |
/* Now snarf a literal value following 'L' */ |
if (!snarf_numeric_literal (&args, &arg)) |
goto cfront_template_args_done; |
break; |
case 'L': |
/* Snarf a literal following 'L' */ |
args++; |
if (!snarf_numeric_literal (&args, &arg)) |
goto cfront_template_args_done; |
break; |
default: |
/* Not handling other HP cfront stuff */ |
{ |
const char* old_args = args; |
if (!do_type (work, &args, &arg)) |
goto cfront_template_args_done; |
/* Fail if we didn't make any progress: prevent infinite loop. */ |
if (args == old_args) |
{ |
work->options = hold_options; |
return; |
} |
} |
} |
string_appends (declp, &arg); |
string_append (declp, ","); |
} |
cfront_template_args_done: |
string_delete (&arg); |
if (args >= e) |
--declp->p; /* remove extra comma */ |
string_append (declp, ">"); |
work->options = hold_options; |
} |
else if (n>10 && strncmp (*mangled, "_GLOBAL_", 8) == 0 |
&& (*mangled)[9] == 'N' |
&& (*mangled)[8] == (*mangled)[10] |
&& strchr (cplus_markers, (*mangled)[8])) |
{ |
/* A member of the anonymous namespace. */ |
string_append (declp, "{anonymous}"); |
} |
else |
{ |
if (work->temp_start == -1) /* non-recursive call only */ |
work->temp_start = 0; /* disable in recursive calls */ |
string_appendn (declp, *mangled, n); |
} |
*mangled += n; |
} |
/* Extract a class name, possibly a template with arguments, from the |
mangled string; qualifiers, local class indicators, etc. have |
already been dealt with */ |
static int |
demangle_class_name (struct work_stuff *work, const char **mangled, |
string *declp) |
{ |
int n; |
int success = 0; |
n = consume_count (mangled); |
if (n == -1) |
return 0; |
if ((int) strlen (*mangled) >= n) |
{ |
demangle_arm_hp_template (work, mangled, n, declp); |
success = 1; |
} |
return (success); |
} |
/* |
LOCAL FUNCTION |
demangle_class -- demangle a mangled class sequence |
SYNOPSIS |
static int |
demangle_class (struct work_stuff *work, const char **mangled, |
strint *declp) |
DESCRIPTION |
DECLP points to the buffer into which demangling is being done. |
*MANGLED points to the current token to be demangled. On input, |
it points to a mangled class (I.E. "3foo", "13verylongclass", etc.) |
On exit, it points to the next token after the mangled class on |
success, or the first unconsumed token on failure. |
If the CONSTRUCTOR or DESTRUCTOR flags are set in WORK, then |
we are demangling a constructor or destructor. In this case |
we prepend "class::class" or "class::~class" to DECLP. |
Otherwise, we prepend "class::" to the current DECLP. |
Reset the constructor/destructor flags once they have been |
"consumed". This allows demangle_class to be called later during |
the same demangling, to do normal class demangling. |
Returns 1 if demangling is successful, 0 otherwise. |
*/ |
static int |
demangle_class (struct work_stuff *work, const char **mangled, string *declp) |
{ |
int success = 0; |
int btype; |
string class_name; |
char *save_class_name_end = 0; |
string_init (&class_name); |
btype = register_Btype (work); |
if (demangle_class_name (work, mangled, &class_name)) |
{ |
save_class_name_end = class_name.p; |
if ((work->constructor & 1) || (work->destructor & 1)) |
{ |
/* adjust so we don't include template args */ |
if (work->temp_start && (work->temp_start != -1)) |
{ |
class_name.p = class_name.b + work->temp_start; |
} |
string_prepends (declp, &class_name); |
if (work -> destructor & 1) |
{ |
string_prepend (declp, "~"); |
work -> destructor -= 1; |
} |
else |
{ |
work -> constructor -= 1; |
} |
} |
class_name.p = save_class_name_end; |
remember_Ktype (work, class_name.b, LEN_STRING(&class_name)); |
remember_Btype (work, class_name.b, LEN_STRING(&class_name), btype); |
string_prepend (declp, SCOPE_STRING (work)); |
string_prepends (declp, &class_name); |
success = 1; |
} |
string_delete (&class_name); |
return (success); |
} |
/* Called when there's a "__" in the mangled name, with `scan' pointing to |
the rightmost guess. |
Find the correct "__"-sequence where the function name ends and the |
signature starts, which is ambiguous with GNU mangling. |
Call demangle_signature here, so we can make sure we found the right |
one; *mangled will be consumed so caller will not make further calls to |
demangle_signature. */ |
static int |
iterate_demangle_function (struct work_stuff *work, const char **mangled, |
string *declp, const char *scan) |
{ |
const char *mangle_init = *mangled; |
int success = 0; |
string decl_init; |
struct work_stuff work_init; |
if (*(scan + 2) == '\0') |
return 0; |
/* Do not iterate for some demangling modes, or if there's only one |
"__"-sequence. This is the normal case. */ |
if (ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING |
|| strstr (scan + 2, "__") == NULL) |
return demangle_function_name (work, mangled, declp, scan); |
/* Save state so we can restart if the guess at the correct "__" was |
wrong. */ |
string_init (&decl_init); |
string_appends (&decl_init, declp); |
memset (&work_init, 0, sizeof work_init); |
work_stuff_copy_to_from (&work_init, work); |
/* Iterate over occurrences of __, allowing names and types to have a |
"__" sequence in them. We must start with the first (not the last) |
occurrence, since "__" most often occur between independent mangled |
parts, hence starting at the last occurence inside a signature |
might get us a "successful" demangling of the signature. */ |
while (scan[2]) |
{ |
if (demangle_function_name (work, mangled, declp, scan)) |
{ |
success = demangle_signature (work, mangled, declp); |
if (success) |
break; |
} |
/* Reset demangle state for the next round. */ |
*mangled = mangle_init; |
string_clear (declp); |
string_appends (declp, &decl_init); |
work_stuff_copy_to_from (work, &work_init); |
/* Leave this underscore-sequence. */ |
scan += 2; |
/* Scan for the next "__" sequence. */ |
while (*scan && (scan[0] != '_' || scan[1] != '_')) |
scan++; |
/* Move to last "__" in this sequence. */ |
while (*scan && *scan == '_') |
scan++; |
scan -= 2; |
} |
/* Delete saved state. */ |
delete_work_stuff (&work_init); |
string_delete (&decl_init); |
return success; |
} |
/* |
LOCAL FUNCTION |
demangle_prefix -- consume the mangled name prefix and find signature |
SYNOPSIS |
static int |
demangle_prefix (struct work_stuff *work, const char **mangled, |
string *declp); |
DESCRIPTION |
Consume and demangle the prefix of the mangled name. |
While processing the function name root, arrange to call |
demangle_signature if the root is ambiguous. |
DECLP points to the string buffer into which demangled output is |
placed. On entry, the buffer is empty. On exit it contains |
the root function name, the demangled operator name, or in some |
special cases either nothing or the completely demangled result. |
MANGLED points to the current pointer into the mangled name. As each |
token of the mangled name is consumed, it is updated. Upon entry |
the current mangled name pointer points to the first character of |
the mangled name. Upon exit, it should point to the first character |
of the signature if demangling was successful, or to the first |
unconsumed character if demangling of the prefix was unsuccessful. |
Returns 1 on success, 0 otherwise. |
*/ |
static int |
demangle_prefix (struct work_stuff *work, const char **mangled, |
string *declp) |
{ |
int success = 1; |
const char *scan; |
int i; |
if (strlen(*mangled) > 6 |
&& (strncmp(*mangled, "_imp__", 6) == 0 |
|| strncmp(*mangled, "__imp_", 6) == 0)) |
{ |
/* it's a symbol imported from a PE dynamic library. Check for both |
new style prefix _imp__ and legacy __imp_ used by older versions |
of dlltool. */ |
(*mangled) += 6; |
work->dllimported = 1; |
} |
else if (strlen(*mangled) >= 11 && strncmp(*mangled, "_GLOBAL_", 8) == 0) |
{ |
char *marker = strchr (cplus_markers, (*mangled)[8]); |
if (marker != NULL && *marker == (*mangled)[10]) |
{ |
if ((*mangled)[9] == 'D') |
{ |
/* it's a GNU global destructor to be executed at program exit */ |
(*mangled) += 11; |
work->destructor = 2; |
if (gnu_special (work, mangled, declp)) |
return success; |
} |
else if ((*mangled)[9] == 'I') |
{ |
/* it's a GNU global constructor to be executed at program init */ |
(*mangled) += 11; |
work->constructor = 2; |
if (gnu_special (work, mangled, declp)) |
return success; |
} |
} |
} |
else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__std__", 7) == 0) |
{ |
/* it's a ARM global destructor to be executed at program exit */ |
(*mangled) += 7; |
work->destructor = 2; |
} |
else if ((ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) && strncmp(*mangled, "__sti__", 7) == 0) |
{ |
/* it's a ARM global constructor to be executed at program initial */ |
(*mangled) += 7; |
work->constructor = 2; |
} |
/* This block of code is a reduction in strength time optimization |
of: |
scan = strstr (*mangled, "__"); */ |
{ |
scan = *mangled; |
do { |
scan = strchr (scan, '_'); |
} while (scan != NULL && *++scan != '_'); |
if (scan != NULL) --scan; |
} |
if (scan != NULL) |
{ |
/* We found a sequence of two or more '_', ensure that we start at |
the last pair in the sequence. */ |
i = strspn (scan, "_"); |
if (i > 2) |
{ |
scan += (i - 2); |
} |
} |
if (scan == NULL) |
{ |
success = 0; |
} |
else if (work -> static_type) |
{ |
if (!ISDIGIT ((unsigned char)scan[0]) && (scan[0] != 't')) |
{ |
success = 0; |
} |
} |
else if ((scan == *mangled) |
&& (ISDIGIT ((unsigned char)scan[2]) || (scan[2] == 'Q') |
|| (scan[2] == 't') || (scan[2] == 'K') || (scan[2] == 'H'))) |
{ |
/* The ARM says nothing about the mangling of local variables. |
But cfront mangles local variables by prepending __<nesting_level> |
to them. As an extension to ARM demangling we handle this case. */ |
if ((LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING) |
&& ISDIGIT ((unsigned char)scan[2])) |
{ |
*mangled = scan + 2; |
consume_count (mangled); |
string_append (declp, *mangled); |
*mangled += strlen (*mangled); |
success = 1; |
} |
else |
{ |
/* A GNU style constructor starts with __[0-9Qt]. But cfront uses |
names like __Q2_3foo3bar for nested type names. So don't accept |
this style of constructor for cfront demangling. A GNU |
style member-template constructor starts with 'H'. */ |
if (!(LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING)) |
work -> constructor += 1; |
*mangled = scan + 2; |
} |
} |
else if (ARM_DEMANGLING && scan[2] == 'p' && scan[3] == 't') |
{ |
/* Cfront-style parameterized type. Handled later as a signature. */ |
success = 1; |
/* ARM template? */ |
demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); |
} |
else if (EDG_DEMANGLING && ((scan[2] == 't' && scan[3] == 'm') |
|| (scan[2] == 'p' && scan[3] == 's') |
|| (scan[2] == 'p' && scan[3] == 't'))) |
{ |
/* EDG-style parameterized type. Handled later as a signature. */ |
success = 1; |
/* EDG template? */ |
demangle_arm_hp_template (work, mangled, strlen (*mangled), declp); |
} |
else if ((scan == *mangled) && !ISDIGIT ((unsigned char)scan[2]) |
&& (scan[2] != 't')) |
{ |
/* Mangled name starts with "__". Skip over any leading '_' characters, |
then find the next "__" that separates the prefix from the signature. |
*/ |
if (!(ARM_DEMANGLING || LUCID_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) |
|| (arm_special (mangled, declp) == 0)) |
{ |
while (*scan == '_') |
{ |
scan++; |
} |
if ((scan = strstr (scan, "__")) == NULL || (*(scan + 2) == '\0')) |
{ |
/* No separator (I.E. "__not_mangled"), or empty signature |
(I.E. "__not_mangled_either__") */ |
success = 0; |
} |
else |
return iterate_demangle_function (work, mangled, declp, scan); |
} |
} |
else if (*(scan + 2) != '\0') |
{ |
/* Mangled name does not start with "__" but does have one somewhere |
in there with non empty stuff after it. Looks like a global |
function name. Iterate over all "__":s until the right |
one is found. */ |
return iterate_demangle_function (work, mangled, declp, scan); |
} |
else |
{ |
/* Doesn't look like a mangled name */ |
success = 0; |
} |
if (!success && (work->constructor == 2 || work->destructor == 2)) |
{ |
string_append (declp, *mangled); |
*mangled += strlen (*mangled); |
success = 1; |
} |
return (success); |
} |
/* |
LOCAL FUNCTION |
gnu_special -- special handling of gnu mangled strings |
SYNOPSIS |
static int |
gnu_special (struct work_stuff *work, const char **mangled, |
string *declp); |
DESCRIPTION |
Process some special GNU style mangling forms that don't fit |
the normal pattern. For example: |
_$_3foo (destructor for class foo) |
_vt$foo (foo virtual table) |
_vt$foo$bar (foo::bar virtual table) |
__vt_foo (foo virtual table, new style with thunks) |
_3foo$varname (static data member) |
_Q22rs2tu$vw (static data member) |
__t6vector1Zii (constructor with template) |
__thunk_4__$_7ostream (virtual function thunk) |
*/ |
static int |
gnu_special (struct work_stuff *work, const char **mangled, string *declp) |
{ |
int n; |
int success = 1; |
const char *p; |
if ((*mangled)[0] == '_' |
&& strchr (cplus_markers, (*mangled)[1]) != NULL |
&& (*mangled)[2] == '_') |
{ |
/* Found a GNU style destructor, get past "_<CPLUS_MARKER>_" */ |
(*mangled) += 3; |
work -> destructor += 1; |
} |
else if ((*mangled)[0] == '_' |
&& (((*mangled)[1] == '_' |
&& (*mangled)[2] == 'v' |
&& (*mangled)[3] == 't' |
&& (*mangled)[4] == '_') |
|| ((*mangled)[1] == 'v' |
&& (*mangled)[2] == 't' |
&& strchr (cplus_markers, (*mangled)[3]) != NULL))) |
{ |
/* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>" |
and create the decl. Note that we consume the entire mangled |
input string, which means that demangle_signature has no work |
to do. */ |
if ((*mangled)[2] == 'v') |
(*mangled) += 5; /* New style, with thunks: "__vt_" */ |
else |
(*mangled) += 4; /* Old style, no thunks: "_vt<CPLUS_MARKER>" */ |
while (**mangled != '\0') |
{ |
switch (**mangled) |
{ |
case 'Q': |
case 'K': |
success = demangle_qualified (work, mangled, declp, 0, 1); |
break; |
case 't': |
success = demangle_template (work, mangled, declp, 0, 1, |
1); |
break; |
default: |
if (ISDIGIT((unsigned char)*mangled[0])) |
{ |
n = consume_count(mangled); |
/* We may be seeing a too-large size, or else a |
".<digits>" indicating a static local symbol. In |
any case, declare victory and move on; *don't* try |
to use n to allocate. */ |
if (n > (int) strlen (*mangled)) |
{ |
success = 1; |
break; |
} |
} |
else |
{ |
n = strcspn (*mangled, cplus_markers); |
} |
string_appendn (declp, *mangled, n); |
(*mangled) += n; |
} |
p = strpbrk (*mangled, cplus_markers); |
if (success && ((p == NULL) || (p == *mangled))) |
{ |
if (p != NULL) |
{ |
string_append (declp, SCOPE_STRING (work)); |
(*mangled)++; |
} |
} |
else |
{ |
success = 0; |
break; |
} |
} |
if (success) |
string_append (declp, " virtual table"); |
} |
else if ((*mangled)[0] == '_' |
&& (strchr("0123456789Qt", (*mangled)[1]) != NULL) |
&& (p = strpbrk (*mangled, cplus_markers)) != NULL) |
{ |
/* static data member, "_3foo$varname" for example */ |
(*mangled)++; |
switch (**mangled) |
{ |
case 'Q': |
case 'K': |
success = demangle_qualified (work, mangled, declp, 0, 1); |
break; |
case 't': |
success = demangle_template (work, mangled, declp, 0, 1, 1); |
break; |
default: |
n = consume_count (mangled); |
if (n < 0 || n > (long) strlen (*mangled)) |
{ |
success = 0; |
break; |
} |
if (n > 10 && strncmp (*mangled, "_GLOBAL_", 8) == 0 |
&& (*mangled)[9] == 'N' |
&& (*mangled)[8] == (*mangled)[10] |
&& strchr (cplus_markers, (*mangled)[8])) |
{ |
/* A member of the anonymous namespace. There's information |
about what identifier or filename it was keyed to, but |
it's just there to make the mangled name unique; we just |
step over it. */ |
string_append (declp, "{anonymous}"); |
(*mangled) += n; |
/* Now p points to the marker before the N, so we need to |
update it to the first marker after what we consumed. */ |
p = strpbrk (*mangled, cplus_markers); |
break; |
} |
string_appendn (declp, *mangled, n); |
(*mangled) += n; |
} |
if (success && (p == *mangled)) |
{ |
/* Consumed everything up to the cplus_marker, append the |
variable name. */ |
(*mangled)++; |
string_append (declp, SCOPE_STRING (work)); |
n = strlen (*mangled); |
string_appendn (declp, *mangled, n); |
(*mangled) += n; |
} |
else |
{ |
success = 0; |
} |
} |
else if (strncmp (*mangled, "__thunk_", 8) == 0) |
{ |
int delta; |
(*mangled) += 8; |
delta = consume_count (mangled); |
if (delta == -1) |
success = 0; |
else |
{ |
char *method = internal_cplus_demangle (work, ++*mangled); |
if (method) |
{ |
char buf[50]; |
sprintf (buf, "virtual function thunk (delta:%d) for ", -delta); |
string_append (declp, buf); |
string_append (declp, method); |
free (method); |
n = strlen (*mangled); |
(*mangled) += n; |
} |
else |
{ |
success = 0; |
} |
} |
} |
else if (strncmp (*mangled, "__t", 3) == 0 |
&& ((*mangled)[3] == 'i' || (*mangled)[3] == 'f')) |
{ |
p = (*mangled)[3] == 'i' ? " type_info node" : " type_info function"; |
(*mangled) += 4; |
switch (**mangled) |
{ |
case 'Q': |
case 'K': |
success = demangle_qualified (work, mangled, declp, 0, 1); |
break; |
case 't': |
success = demangle_template (work, mangled, declp, 0, 1, 1); |
break; |
default: |
success = do_type (work, mangled, declp); |
break; |
} |
if (success && **mangled != '\0') |
success = 0; |
if (success) |
string_append (declp, p); |
} |
else |
{ |
success = 0; |
} |
return (success); |
} |
static void |
recursively_demangle(struct work_stuff *work, const char **mangled, |
string *result, int namelength) |
{ |
char * recurse = (char *)NULL; |
char * recurse_dem = (char *)NULL; |
recurse = XNEWVEC (char, namelength + 1); |
memcpy (recurse, *mangled, namelength); |
recurse[namelength] = '\000'; |
recurse_dem = cplus_demangle (recurse, work->options); |
if (recurse_dem) |
{ |
string_append (result, recurse_dem); |
free (recurse_dem); |
} |
else |
{ |
string_appendn (result, *mangled, namelength); |
} |
free (recurse); |
*mangled += namelength; |
} |
/* |
LOCAL FUNCTION |
arm_special -- special handling of ARM/lucid mangled strings |
SYNOPSIS |
static int |
arm_special (const char **mangled, |
string *declp); |
DESCRIPTION |
Process some special ARM style mangling forms that don't fit |
the normal pattern. For example: |
__vtbl__3foo (foo virtual table) |
__vtbl__3foo__3bar (bar::foo virtual table) |
*/ |
static int |
arm_special (const char **mangled, string *declp) |
{ |
int n; |
int success = 1; |
const char *scan; |
if (strncmp (*mangled, ARM_VTABLE_STRING, ARM_VTABLE_STRLEN) == 0) |
{ |
/* Found a ARM style virtual table, get past ARM_VTABLE_STRING |
and create the decl. Note that we consume the entire mangled |
input string, which means that demangle_signature has no work |
to do. */ |
scan = *mangled + ARM_VTABLE_STRLEN; |
while (*scan != '\0') /* first check it can be demangled */ |
{ |
n = consume_count (&scan); |
if (n == -1) |
{ |
return (0); /* no good */ |
} |
scan += n; |
if (scan[0] == '_' && scan[1] == '_') |
{ |
scan += 2; |
} |
} |
(*mangled) += ARM_VTABLE_STRLEN; |
while (**mangled != '\0') |
{ |
n = consume_count (mangled); |
if (n == -1 |
|| n > (long) strlen (*mangled)) |
return 0; |
string_prependn (declp, *mangled, n); |
(*mangled) += n; |
if ((*mangled)[0] == '_' && (*mangled)[1] == '_') |
{ |
string_prepend (declp, "::"); |
(*mangled) += 2; |
} |
} |
string_append (declp, " virtual table"); |
} |
else |
{ |
success = 0; |
} |
return (success); |
} |
/* |
LOCAL FUNCTION |
demangle_qualified -- demangle 'Q' qualified name strings |
SYNOPSIS |
static int |
demangle_qualified (struct work_stuff *, const char *mangled, |
string *result, int isfuncname, int append); |
DESCRIPTION |
Demangle a qualified name, such as "Q25Outer5Inner" which is |
the mangled form of "Outer::Inner". The demangled output is |
prepended or appended to the result string according to the |
state of the append flag. |
If isfuncname is nonzero, then the qualified name we are building |
is going to be used as a member function name, so if it is a |
constructor or destructor function, append an appropriate |
constructor or destructor name. I.E. for the above example, |
the result for use as a constructor is "Outer::Inner::Inner" |
and the result for use as a destructor is "Outer::Inner::~Inner". |
BUGS |
Numeric conversion is ASCII dependent (FIXME). |
*/ |
static int |
demangle_qualified (struct work_stuff *work, const char **mangled, |
string *result, int isfuncname, int append) |
{ |
int qualifiers = 0; |
int success = 1; |
char num[2]; |
string temp; |
string last_name; |
int bindex = register_Btype (work); |
/* We only make use of ISFUNCNAME if the entity is a constructor or |
destructor. */ |
isfuncname = (isfuncname |
&& ((work->constructor & 1) || (work->destructor & 1))); |
string_init (&temp); |
string_init (&last_name); |
if ((*mangled)[0] == 'K') |
{ |
/* Squangling qualified name reuse */ |
int idx; |
(*mangled)++; |
idx = consume_count_with_underscores (mangled); |
if (idx == -1 || idx >= work -> numk) |
success = 0; |
else |
string_append (&temp, work -> ktypevec[idx]); |
} |
else |
switch ((*mangled)[1]) |
{ |
case '_': |
/* GNU mangled name with more than 9 classes. The count is preceded |
by an underscore (to distinguish it from the <= 9 case) and followed |
by an underscore. */ |
(*mangled)++; |
qualifiers = consume_count_with_underscores (mangled); |
if (qualifiers == -1) |
success = 0; |
break; |
case '1': |
case '2': |
case '3': |
case '4': |
case '5': |
case '6': |
case '7': |
case '8': |
case '9': |
/* The count is in a single digit. */ |
num[0] = (*mangled)[1]; |
num[1] = '\0'; |
qualifiers = atoi (num); |
/* If there is an underscore after the digit, skip it. This is |
said to be for ARM-qualified names, but the ARM makes no |
mention of such an underscore. Perhaps cfront uses one. */ |
if ((*mangled)[2] == '_') |
{ |
(*mangled)++; |
} |
(*mangled) += 2; |
break; |
case '0': |
default: |
success = 0; |
} |
if (!success) |
return success; |
/* Pick off the names and collect them in the temp buffer in the order |
in which they are found, separated by '::'. */ |
while (qualifiers-- > 0) |
{ |
int remember_K = 1; |
string_clear (&last_name); |
if (*mangled[0] == '_') |
(*mangled)++; |
if (*mangled[0] == 't') |
{ |
/* Here we always append to TEMP since we will want to use |
the template name without the template parameters as a |
constructor or destructor name. The appropriate |
(parameter-less) value is returned by demangle_template |
in LAST_NAME. We do not remember the template type here, |
in order to match the G++ mangling algorithm. */ |
success = demangle_template(work, mangled, &temp, |
&last_name, 1, 0); |
if (!success) |
break; |
} |
else if (*mangled[0] == 'K') |
{ |
int idx; |
(*mangled)++; |
idx = consume_count_with_underscores (mangled); |
if (idx == -1 || idx >= work->numk) |
success = 0; |
else |
string_append (&temp, work->ktypevec[idx]); |
remember_K = 0; |
if (!success) break; |
} |
else |
{ |
if (EDG_DEMANGLING) |
{ |
int namelength; |
/* Now recursively demangle the qualifier |
* This is necessary to deal with templates in |
* mangling styles like EDG */ |
namelength = consume_count (mangled); |
if (namelength == -1) |
{ |
success = 0; |
break; |
} |
recursively_demangle(work, mangled, &temp, namelength); |
} |
else |
{ |
string_delete (&last_name); |
success = do_type (work, mangled, &last_name); |
if (!success) |
break; |
string_appends (&temp, &last_name); |
} |
} |
if (remember_K) |
remember_Ktype (work, temp.b, LEN_STRING (&temp)); |
if (qualifiers > 0) |
string_append (&temp, SCOPE_STRING (work)); |
} |
remember_Btype (work, temp.b, LEN_STRING (&temp), bindex); |
/* If we are using the result as a function name, we need to append |
the appropriate '::' separated constructor or destructor name. |
We do this here because this is the most convenient place, where |
we already have a pointer to the name and the length of the name. */ |
if (isfuncname) |
{ |
string_append (&temp, SCOPE_STRING (work)); |
if (work -> destructor & 1) |
string_append (&temp, "~"); |
string_appends (&temp, &last_name); |
} |
/* Now either prepend the temp buffer to the result, or append it, |
depending upon the state of the append flag. */ |
if (append) |
string_appends (result, &temp); |
else |
{ |
if (!STRING_EMPTY (result)) |
string_append (&temp, SCOPE_STRING (work)); |
string_prepends (result, &temp); |
} |
string_delete (&last_name); |
string_delete (&temp); |
return (success); |
} |
/* |
LOCAL FUNCTION |
get_count -- convert an ascii count to integer, consuming tokens |
SYNOPSIS |
static int |
get_count (const char **type, int *count) |
DESCRIPTION |
Assume that *type points at a count in a mangled name; set |
*count to its value, and set *type to the next character after |
the count. There are some weird rules in effect here. |
If *type does not point at a string of digits, return zero. |
If *type points at a string of digits followed by an |
underscore, set *count to their value as an integer, advance |
*type to point *after the underscore, and return 1. |
If *type points at a string of digits not followed by an |
underscore, consume only the first digit. Set *count to its |
value as an integer, leave *type pointing after that digit, |
and return 1. |
The excuse for this odd behavior: in the ARM and HP demangling |
styles, a type can be followed by a repeat count of the form |
`Nxy', where: |
`x' is a single digit specifying how many additional copies |
of the type to append to the argument list, and |
`y' is one or more digits, specifying the zero-based index of |
the first repeated argument in the list. Yes, as you're |
unmangling the name you can figure this out yourself, but |
it's there anyway. |
So, for example, in `bar__3fooFPiN51', the first argument is a |
pointer to an integer (`Pi'), and then the next five arguments |
are the same (`N5'), and the first repeat is the function's |
second argument (`1'). |
*/ |
static int |
get_count (const char **type, int *count) |
{ |
const char *p; |
int n; |
if (!ISDIGIT ((unsigned char)**type)) |
return (0); |
else |
{ |
*count = **type - '0'; |
(*type)++; |
if (ISDIGIT ((unsigned char)**type)) |
{ |
p = *type; |
n = *count; |
do |
{ |
n *= 10; |
n += *p - '0'; |
p++; |
} |
while (ISDIGIT ((unsigned char)*p)); |
if (*p == '_') |
{ |
*type = p + 1; |
*count = n; |
} |
} |
} |
return (1); |
} |
/* RESULT will be initialised here; it will be freed on failure. The |
value returned is really a type_kind_t. */ |
static int |
do_type (struct work_stuff *work, const char **mangled, string *result) |
{ |
int n; |
int done; |
int success; |
string decl; |
const char *remembered_type; |
int type_quals; |
type_kind_t tk = tk_none; |
string_init (&decl); |
string_init (result); |
done = 0; |
success = 1; |
while (success && !done) |
{ |
int member; |
switch (**mangled) |
{ |
/* A pointer type */ |
case 'P': |
case 'p': |
(*mangled)++; |
if (! (work -> options & DMGL_JAVA)) |
string_prepend (&decl, "*"); |
if (tk == tk_none) |
tk = tk_pointer; |
break; |
/* A reference type */ |
case 'R': |
(*mangled)++; |
string_prepend (&decl, "&"); |
if (tk == tk_none) |
tk = tk_reference; |
break; |
/* An array */ |
case 'A': |
{ |
++(*mangled); |
if (!STRING_EMPTY (&decl) |
&& (decl.b[0] == '*' || decl.b[0] == '&')) |
{ |
string_prepend (&decl, "("); |
string_append (&decl, ")"); |
} |
string_append (&decl, "["); |
if (**mangled != '_') |
success = demangle_template_value_parm (work, mangled, &decl, |
tk_integral); |
if (**mangled == '_') |
++(*mangled); |
string_append (&decl, "]"); |
break; |
} |
/* A back reference to a previously seen type */ |
case 'T': |
(*mangled)++; |
if (!get_count (mangled, &n) || n >= work -> ntypes) |
{ |
success = 0; |
} |
else |
{ |
remembered_type = work -> typevec[n]; |
mangled = &remembered_type; |
} |
break; |
/* A function */ |
case 'F': |
(*mangled)++; |
if (!STRING_EMPTY (&decl) |
&& (decl.b[0] == '*' || decl.b[0] == '&')) |
{ |
string_prepend (&decl, "("); |
string_append (&decl, ")"); |
} |
/* After picking off the function args, we expect to either find the |
function return type (preceded by an '_') or the end of the |
string. */ |
if (!demangle_nested_args (work, mangled, &decl) |
|| (**mangled != '_' && **mangled != '\0')) |
{ |
success = 0; |
break; |
} |
if (success && (**mangled == '_')) |
(*mangled)++; |
break; |
case 'M': |
case 'O': |
{ |
type_quals = TYPE_UNQUALIFIED; |
member = **mangled == 'M'; |
(*mangled)++; |
string_append (&decl, ")"); |
/* We don't need to prepend `::' for a qualified name; |
demangle_qualified will do that for us. */ |
if (**mangled != 'Q') |
string_prepend (&decl, SCOPE_STRING (work)); |
if (ISDIGIT ((unsigned char)**mangled)) |
{ |
n = consume_count (mangled); |
if (n == -1 |
|| (int) strlen (*mangled) < n) |
{ |
success = 0; |
break; |
} |
string_prependn (&decl, *mangled, n); |
*mangled += n; |
} |
else if (**mangled == 'X' || **mangled == 'Y') |
{ |
string temp; |
do_type (work, mangled, &temp); |
string_prepends (&decl, &temp); |
string_delete (&temp); |
} |
else if (**mangled == 't') |
{ |
string temp; |
string_init (&temp); |
success = demangle_template (work, mangled, &temp, |
NULL, 1, 1); |
if (success) |
{ |
string_prependn (&decl, temp.b, temp.p - temp.b); |
string_delete (&temp); |
} |
else |
break; |
} |
else if (**mangled == 'Q') |
{ |
success = demangle_qualified (work, mangled, &decl, |
/*isfuncnam=*/0, |
/*append=*/0); |
if (!success) |
break; |
} |
else |
{ |
success = 0; |
break; |
} |
string_prepend (&decl, "("); |
if (member) |
{ |
switch (**mangled) |
{ |
case 'C': |
case 'V': |
case 'u': |
type_quals |= code_for_qualifier (**mangled); |
(*mangled)++; |
break; |
default: |
break; |
} |
if (*(*mangled)++ != 'F') |
{ |
success = 0; |
break; |
} |
} |
if ((member && !demangle_nested_args (work, mangled, &decl)) |
|| **mangled != '_') |
{ |
success = 0; |
break; |
} |
(*mangled)++; |
if (! PRINT_ANSI_QUALIFIERS) |
{ |
break; |
} |
if (type_quals != TYPE_UNQUALIFIED) |
{ |
APPEND_BLANK (&decl); |
string_append (&decl, qualifier_string (type_quals)); |
} |
break; |
} |
case 'G': |
(*mangled)++; |
break; |
case 'C': |
case 'V': |
case 'u': |
if (PRINT_ANSI_QUALIFIERS) |
{ |
if (!STRING_EMPTY (&decl)) |
string_prepend (&decl, " "); |
string_prepend (&decl, demangle_qualifier (**mangled)); |
} |
(*mangled)++; |
break; |
/* |
} |
*/ |
/* fall through */ |
default: |
done = 1; |
break; |
} |
} |
if (success) switch (**mangled) |
{ |
/* A qualified name, such as "Outer::Inner". */ |
case 'Q': |
case 'K': |
{ |
success = demangle_qualified (work, mangled, result, 0, 1); |
break; |
} |
/* A back reference to a previously seen squangled type */ |
case 'B': |
(*mangled)++; |
if (!get_count (mangled, &n) || n >= work -> numb) |
success = 0; |
else |
string_append (result, work->btypevec[n]); |
break; |
case 'X': |
case 'Y': |
/* A template parm. We substitute the corresponding argument. */ |
{ |
int idx; |
(*mangled)++; |
idx = consume_count_with_underscores (mangled); |
if (idx == -1 |
|| (work->tmpl_argvec && idx >= work->ntmpl_args) |
|| consume_count_with_underscores (mangled) == -1) |
{ |
success = 0; |
break; |
} |
if (work->tmpl_argvec) |
string_append (result, work->tmpl_argvec[idx]); |
else |
string_append_template_idx (result, idx); |
success = 1; |
} |
break; |
default: |
success = demangle_fund_type (work, mangled, result); |
if (tk == tk_none) |
tk = (type_kind_t) success; |
break; |
} |
if (success) |
{ |
if (!STRING_EMPTY (&decl)) |
{ |
string_append (result, " "); |
string_appends (result, &decl); |
} |
} |
else |
string_delete (result); |
string_delete (&decl); |
if (success) |
/* Assume an integral type, if we're not sure. */ |
return (int) ((tk == tk_none) ? tk_integral : tk); |
else |
return 0; |
} |
/* Given a pointer to a type string that represents a fundamental type |
argument (int, long, unsigned int, etc) in TYPE, a pointer to the |
string in which the demangled output is being built in RESULT, and |
the WORK structure, decode the types and add them to the result. |
For example: |
"Ci" => "const int" |
"Sl" => "signed long" |
"CUs" => "const unsigned short" |
The value returned is really a type_kind_t. */ |
static int |
demangle_fund_type (struct work_stuff *work, |
const char **mangled, string *result) |
{ |
int done = 0; |
int success = 1; |
char buf[INTBUF_SIZE + 5 /* 'int%u_t' */]; |
unsigned int dec = 0; |
type_kind_t tk = tk_integral; |
/* First pick off any type qualifiers. There can be more than one. */ |
while (!done) |
{ |
switch (**mangled) |
{ |
case 'C': |
case 'V': |
case 'u': |
if (PRINT_ANSI_QUALIFIERS) |
{ |
if (!STRING_EMPTY (result)) |
string_prepend (result, " "); |
string_prepend (result, demangle_qualifier (**mangled)); |
} |
(*mangled)++; |
break; |
case 'U': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "unsigned"); |
break; |
case 'S': /* signed char only */ |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "signed"); |
break; |
case 'J': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "__complex"); |
break; |
default: |
done = 1; |
break; |
} |
} |
/* Now pick off the fundamental type. There can be only one. */ |
switch (**mangled) |
{ |
case '\0': |
case '_': |
break; |
case 'v': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "void"); |
break; |
case 'x': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "long long"); |
break; |
case 'l': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "long"); |
break; |
case 'i': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "int"); |
break; |
case 's': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "short"); |
break; |
case 'b': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "bool"); |
tk = tk_bool; |
break; |
case 'c': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "char"); |
tk = tk_char; |
break; |
case 'w': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "wchar_t"); |
tk = tk_char; |
break; |
case 'r': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "long double"); |
tk = tk_real; |
break; |
case 'd': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "double"); |
tk = tk_real; |
break; |
case 'f': |
(*mangled)++; |
APPEND_BLANK (result); |
string_append (result, "float"); |
tk = tk_real; |
break; |
case 'G': |
(*mangled)++; |
if (!ISDIGIT ((unsigned char)**mangled)) |
{ |
success = 0; |
break; |
} |
case 'I': |
(*mangled)++; |
if (**mangled == '_') |
{ |
int i; |
(*mangled)++; |
for (i = 0; |
i < (long) sizeof (buf) - 1 && **mangled && **mangled != '_'; |
(*mangled)++, i++) |
buf[i] = **mangled; |
if (**mangled != '_') |
{ |
success = 0; |
break; |
} |
buf[i] = '\0'; |
(*mangled)++; |
} |
else |
{ |
strncpy (buf, *mangled, 2); |
buf[2] = '\0'; |
*mangled += min (strlen (*mangled), 2); |
} |
sscanf (buf, "%x", &dec); |
sprintf (buf, "int%u_t", dec); |
APPEND_BLANK (result); |
string_append (result, buf); |
break; |
/* fall through */ |
/* An explicit type, such as "6mytype" or "7integer" */ |
case '0': |
case '1': |
case '2': |
case '3': |
case '4': |
case '5': |
case '6': |
case '7': |
case '8': |
case '9': |
{ |
int bindex = register_Btype (work); |
string btype; |
string_init (&btype); |
if (demangle_class_name (work, mangled, &btype)) { |
remember_Btype (work, btype.b, LEN_STRING (&btype), bindex); |
APPEND_BLANK (result); |
string_appends (result, &btype); |
} |
else |
success = 0; |
string_delete (&btype); |
break; |
} |
case 't': |
{ |
string btype; |
string_init (&btype); |
success = demangle_template (work, mangled, &btype, 0, 1, 1); |
string_appends (result, &btype); |
string_delete (&btype); |
break; |
} |
default: |
success = 0; |
break; |
} |
return success ? ((int) tk) : 0; |
} |
/* Handle a template's value parameter for HP aCC (extension from ARM) |
**mangled points to 'S' or 'U' */ |
static int |
do_hpacc_template_const_value (struct work_stuff *work ATTRIBUTE_UNUSED, |
const char **mangled, string *result) |
{ |
int unsigned_const; |
if (**mangled != 'U' && **mangled != 'S') |
return 0; |
unsigned_const = (**mangled == 'U'); |
(*mangled)++; |
switch (**mangled) |
{ |
case 'N': |
string_append (result, "-"); |
/* fall through */ |
case 'P': |
(*mangled)++; |
break; |
case 'M': |
/* special case for -2^31 */ |
string_append (result, "-2147483648"); |
(*mangled)++; |
return 1; |
default: |
return 0; |
} |
/* We have to be looking at an integer now */ |
if (!(ISDIGIT ((unsigned char)**mangled))) |
return 0; |
/* We only deal with integral values for template |
parameters -- so it's OK to look only for digits */ |
while (ISDIGIT ((unsigned char)**mangled)) |
{ |
char_str[0] = **mangled; |
string_append (result, char_str); |
(*mangled)++; |
} |
if (unsigned_const) |
string_append (result, "U"); |
/* FIXME? Some day we may have 64-bit (or larger :-) ) constants |
with L or LL suffixes. pai/1997-09-03 */ |
return 1; /* success */ |
} |
/* Handle a template's literal parameter for HP aCC (extension from ARM) |
**mangled is pointing to the 'A' */ |
static int |
do_hpacc_template_literal (struct work_stuff *work, const char **mangled, |
string *result) |
{ |
int literal_len = 0; |
char * recurse; |
char * recurse_dem; |
if (**mangled != 'A') |
return 0; |
(*mangled)++; |
literal_len = consume_count (mangled); |
if (literal_len <= 0) |
return 0; |
/* Literal parameters are names of arrays, functions, etc. and the |
canonical representation uses the address operator */ |
string_append (result, "&"); |
/* Now recursively demangle the literal name */ |
recurse = XNEWVEC (char, literal_len + 1); |
memcpy (recurse, *mangled, literal_len); |
recurse[literal_len] = '\000'; |
recurse_dem = cplus_demangle (recurse, work->options); |
if (recurse_dem) |
{ |
string_append (result, recurse_dem); |
free (recurse_dem); |
} |
else |
{ |
string_appendn (result, *mangled, literal_len); |
} |
(*mangled) += literal_len; |
free (recurse); |
return 1; |
} |
static int |
snarf_numeric_literal (const char **args, string *arg) |
{ |
if (**args == '-') |
{ |
char_str[0] = '-'; |
string_append (arg, char_str); |
(*args)++; |
} |
else if (**args == '+') |
(*args)++; |
if (!ISDIGIT ((unsigned char)**args)) |
return 0; |
while (ISDIGIT ((unsigned char)**args)) |
{ |
char_str[0] = **args; |
string_append (arg, char_str); |
(*args)++; |
} |
return 1; |
} |
/* Demangle the next argument, given by MANGLED into RESULT, which |
*should be an uninitialized* string. It will be initialized here, |
and free'd should anything go wrong. */ |
static int |
do_arg (struct work_stuff *work, const char **mangled, string *result) |
{ |
/* Remember where we started so that we can record the type, for |
non-squangling type remembering. */ |
const char *start = *mangled; |
string_init (result); |
if (work->nrepeats > 0) |
{ |
--work->nrepeats; |
if (work->previous_argument == 0) |
return 0; |
/* We want to reissue the previous type in this argument list. */ |
string_appends (result, work->previous_argument); |
return 1; |
} |
if (**mangled == 'n') |
{ |
/* A squangling-style repeat. */ |
(*mangled)++; |
work->nrepeats = consume_count(mangled); |
if (work->nrepeats <= 0) |
/* This was not a repeat count after all. */ |
return 0; |
if (work->nrepeats > 9) |
{ |
if (**mangled != '_') |
/* The repeat count should be followed by an '_' in this |
case. */ |
return 0; |
else |
(*mangled)++; |
} |
/* Now, the repeat is all set up. */ |
return do_arg (work, mangled, result); |
} |
/* Save the result in WORK->previous_argument so that we can find it |
if it's repeated. Note that saving START is not good enough: we |
do not want to add additional types to the back-referenceable |
type vector when processing a repeated type. */ |
if (work->previous_argument) |
string_delete (work->previous_argument); |
else |
work->previous_argument = XNEW (string); |
if (!do_type (work, mangled, work->previous_argument)) |
return 0; |
string_appends (result, work->previous_argument); |
remember_type (work, start, *mangled - start); |
return 1; |
} |
static void |
remember_type (struct work_stuff *work, const char *start, int len) |
{ |
char *tem; |
if (work->forgetting_types) |
return; |
if (work -> ntypes >= work -> typevec_size) |
{ |
if (work -> typevec_size == 0) |
{ |
work -> typevec_size = 3; |
work -> typevec = XNEWVEC (char *, work->typevec_size); |
} |
else |
{ |
work -> typevec_size *= 2; |
work -> typevec |
= XRESIZEVEC (char *, work->typevec, work->typevec_size); |
} |
} |
tem = XNEWVEC (char, len + 1); |
memcpy (tem, start, len); |
tem[len] = '\0'; |
work -> typevec[work -> ntypes++] = tem; |
} |
/* Remember a K type class qualifier. */ |
static void |
remember_Ktype (struct work_stuff *work, const char *start, int len) |
{ |
char *tem; |
if (work -> numk >= work -> ksize) |
{ |
if (work -> ksize == 0) |
{ |
work -> ksize = 5; |
work -> ktypevec = XNEWVEC (char *, work->ksize); |
} |
else |
{ |
work -> ksize *= 2; |
work -> ktypevec |
= XRESIZEVEC (char *, work->ktypevec, work->ksize); |
} |
} |
tem = XNEWVEC (char, len + 1); |
memcpy (tem, start, len); |
tem[len] = '\0'; |
work -> ktypevec[work -> numk++] = tem; |
} |
/* Register a B code, and get an index for it. B codes are registered |
as they are seen, rather than as they are completed, so map<temp<char> > |
registers map<temp<char> > as B0, and temp<char> as B1 */ |
static int |
register_Btype (struct work_stuff *work) |
{ |
int ret; |
if (work -> numb >= work -> bsize) |
{ |
if (work -> bsize == 0) |
{ |
work -> bsize = 5; |
work -> btypevec = XNEWVEC (char *, work->bsize); |
} |
else |
{ |
work -> bsize *= 2; |
work -> btypevec |
= XRESIZEVEC (char *, work->btypevec, work->bsize); |
} |
} |
ret = work -> numb++; |
work -> btypevec[ret] = NULL; |
return(ret); |
} |
/* Store a value into a previously registered B code type. */ |
static void |
remember_Btype (struct work_stuff *work, const char *start, |
int len, int index) |
{ |
char *tem; |
tem = XNEWVEC (char, len + 1); |
memcpy (tem, start, len); |
tem[len] = '\0'; |
work -> btypevec[index] = tem; |
} |
/* Lose all the info related to B and K type codes. */ |
static void |
forget_B_and_K_types (struct work_stuff *work) |
{ |
int i; |
while (work -> numk > 0) |
{ |
i = --(work -> numk); |
if (work -> ktypevec[i] != NULL) |
{ |
free (work -> ktypevec[i]); |
work -> ktypevec[i] = NULL; |
} |
} |
while (work -> numb > 0) |
{ |
i = --(work -> numb); |
if (work -> btypevec[i] != NULL) |
{ |
free (work -> btypevec[i]); |
work -> btypevec[i] = NULL; |
} |
} |
} |
/* Forget the remembered types, but not the type vector itself. */ |
static void |
forget_types (struct work_stuff *work) |
{ |
int i; |
while (work -> ntypes > 0) |
{ |
i = --(work -> ntypes); |
if (work -> typevec[i] != NULL) |
{ |
free (work -> typevec[i]); |
work -> typevec[i] = NULL; |
} |
} |
} |
/* Process the argument list part of the signature, after any class spec |
has been consumed, as well as the first 'F' character (if any). For |
example: |
"__als__3fooRT0" => process "RT0" |
"complexfunc5__FPFPc_PFl_i" => process "PFPc_PFl_i" |
DECLP must be already initialised, usually non-empty. It won't be freed |
on failure. |
Note that g++ differs significantly from ARM and lucid style mangling |
with regards to references to previously seen types. For example, given |
the source fragment: |
class foo { |
public: |
foo::foo (int, foo &ia, int, foo &ib, int, foo &ic); |
}; |
foo::foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } |
void foo (int, foo &ia, int, foo &ib, int, foo &ic) { ia = ib = ic; } |
g++ produces the names: |
__3fooiRT0iT2iT2 |
foo__FiR3fooiT1iT1 |
while lcc (and presumably other ARM style compilers as well) produces: |
foo__FiR3fooT1T2T1T2 |
__ct__3fooFiR3fooT1T2T1T2 |
Note that g++ bases its type numbers starting at zero and counts all |
previously seen types, while lucid/ARM bases its type numbers starting |
at one and only considers types after it has seen the 'F' character |
indicating the start of the function args. For lucid/ARM style, we |
account for this difference by discarding any previously seen types when |
we see the 'F' character, and subtracting one from the type number |
reference. |
*/ |
static int |
demangle_args (struct work_stuff *work, const char **mangled, |
string *declp) |
{ |
string arg; |
int need_comma = 0; |
int r; |
int t; |
const char *tem; |
char temptype; |
if (PRINT_ARG_TYPES) |
{ |
string_append (declp, "("); |
if (**mangled == '\0') |
{ |
string_append (declp, "void"); |
} |
} |
while ((**mangled != '_' && **mangled != '\0' && **mangled != 'e') |
|| work->nrepeats > 0) |
{ |
if ((**mangled == 'N') || (**mangled == 'T')) |
{ |
temptype = *(*mangled)++; |
if (temptype == 'N') |
{ |
if (!get_count (mangled, &r)) |
{ |
return (0); |
} |
} |
else |
{ |
r = 1; |
} |
if ((HP_DEMANGLING || ARM_DEMANGLING || EDG_DEMANGLING) && work -> ntypes >= 10) |
{ |
/* If we have 10 or more types we might have more than a 1 digit |
index so we'll have to consume the whole count here. This |
will lose if the next thing is a type name preceded by a |
count but it's impossible to demangle that case properly |
anyway. Eg if we already have 12 types is T12Pc "(..., type1, |
Pc, ...)" or "(..., type12, char *, ...)" */ |
if ((t = consume_count(mangled)) <= 0) |
{ |
return (0); |
} |
} |
else |
{ |
if (!get_count (mangled, &t)) |
{ |
return (0); |
} |
} |
if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) |
{ |
t--; |
} |
/* Validate the type index. Protect against illegal indices from |
malformed type strings. */ |
if ((t < 0) || (t >= work -> ntypes)) |
{ |
return (0); |
} |
while (work->nrepeats > 0 || --r >= 0) |
{ |
tem = work -> typevec[t]; |
if (need_comma && PRINT_ARG_TYPES) |
{ |
string_append (declp, ", "); |
} |
if (!do_arg (work, &tem, &arg)) |
{ |
return (0); |
} |
if (PRINT_ARG_TYPES) |
{ |
string_appends (declp, &arg); |
} |
string_delete (&arg); |
need_comma = 1; |
} |
} |
else |
{ |
if (need_comma && PRINT_ARG_TYPES) |
string_append (declp, ", "); |
if (!do_arg (work, mangled, &arg)) |
return (0); |
if (PRINT_ARG_TYPES) |
string_appends (declp, &arg); |
string_delete (&arg); |
need_comma = 1; |
} |
} |
if (**mangled == 'e') |
{ |
(*mangled)++; |
if (PRINT_ARG_TYPES) |
{ |
if (need_comma) |
{ |
string_append (declp, ","); |
} |
string_append (declp, "..."); |
} |
} |
if (PRINT_ARG_TYPES) |
{ |
string_append (declp, ")"); |
} |
return (1); |
} |
/* Like demangle_args, but for demangling the argument lists of function |
and method pointers or references, not top-level declarations. */ |
static int |
demangle_nested_args (struct work_stuff *work, const char **mangled, |
string *declp) |
{ |
string* saved_previous_argument; |
int result; |
int saved_nrepeats; |
/* The G++ name-mangling algorithm does not remember types on nested |
argument lists, unless -fsquangling is used, and in that case the |
type vector updated by remember_type is not used. So, we turn |
off remembering of types here. */ |
++work->forgetting_types; |
/* For the repeat codes used with -fsquangling, we must keep track of |
the last argument. */ |
saved_previous_argument = work->previous_argument; |
saved_nrepeats = work->nrepeats; |
work->previous_argument = 0; |
work->nrepeats = 0; |
/* Actually demangle the arguments. */ |
result = demangle_args (work, mangled, declp); |
/* Restore the previous_argument field. */ |
if (work->previous_argument) |
{ |
string_delete (work->previous_argument); |
free ((char *) work->previous_argument); |
} |
work->previous_argument = saved_previous_argument; |
--work->forgetting_types; |
work->nrepeats = saved_nrepeats; |
return result; |
} |
/* Returns 1 if a valid function name was found or 0 otherwise. */ |
static int |
demangle_function_name (struct work_stuff *work, const char **mangled, |
string *declp, const char *scan) |
{ |
size_t i; |
string type; |
const char *tem; |
string_appendn (declp, (*mangled), scan - (*mangled)); |
string_need (declp, 1); |
*(declp -> p) = '\0'; |
/* Consume the function name, including the "__" separating the name |
from the signature. We are guaranteed that SCAN points to the |
separator. */ |
(*mangled) = scan + 2; |
/* We may be looking at an instantiation of a template function: |
foo__Xt1t2_Ft3t4, where t1, t2, ... are template arguments and a |
following _F marks the start of the function arguments. Handle |
the template arguments first. */ |
if (HP_DEMANGLING && (**mangled == 'X')) |
{ |
demangle_arm_hp_template (work, mangled, 0, declp); |
/* This leaves MANGLED pointing to the 'F' marking func args */ |
} |
if (LUCID_DEMANGLING || ARM_DEMANGLING || HP_DEMANGLING || EDG_DEMANGLING) |
{ |
/* See if we have an ARM style constructor or destructor operator. |
If so, then just record it, clear the decl, and return. |
We can't build the actual constructor/destructor decl until later, |
when we recover the class name from the signature. */ |
if (strcmp (declp -> b, "__ct") == 0) |
{ |
work -> constructor += 1; |
string_clear (declp); |
return 1; |
} |
else if (strcmp (declp -> b, "__dt") == 0) |
{ |
work -> destructor += 1; |
string_clear (declp); |
return 1; |
} |
} |
if (declp->p - declp->b >= 3 |
&& declp->b[0] == 'o' |
&& declp->b[1] == 'p' |
&& strchr (cplus_markers, declp->b[2]) != NULL) |
{ |
/* see if it's an assignment expression */ |
if (declp->p - declp->b >= 10 /* op$assign_ */ |
&& memcmp (declp->b + 3, "assign_", 7) == 0) |
{ |
for (i = 0; i < ARRAY_SIZE (optable); i++) |
{ |
int len = declp->p - declp->b - 10; |
if ((int) strlen (optable[i].in) == len |
&& memcmp (optable[i].in, declp->b + 10, len) == 0) |
{ |
string_clear (declp); |
string_append (declp, "operator"); |
string_append (declp, optable[i].out); |
string_append (declp, "="); |
break; |
} |
} |
} |
else |
{ |
for (i = 0; i < ARRAY_SIZE (optable); i++) |
{ |
int len = declp->p - declp->b - 3; |
if ((int) strlen (optable[i].in) == len |
&& memcmp (optable[i].in, declp->b + 3, len) == 0) |
{ |
string_clear (declp); |
string_append (declp, "operator"); |
string_append (declp, optable[i].out); |
break; |
} |
} |
} |
} |
else if (declp->p - declp->b >= 5 && memcmp (declp->b, "type", 4) == 0 |
&& strchr (cplus_markers, declp->b[4]) != NULL) |
{ |
/* type conversion operator */ |
tem = declp->b + 5; |
if (do_type (work, &tem, &type)) |
{ |
string_clear (declp); |
string_append (declp, "operator "); |
string_appends (declp, &type); |
string_delete (&type); |
} |
} |
else if (declp->b[0] == '_' && declp->b[1] == '_' |
&& declp->b[2] == 'o' && declp->b[3] == 'p') |
{ |
/* ANSI. */ |
/* type conversion operator. */ |
tem = declp->b + 4; |
if (do_type (work, &tem, &type)) |
{ |
string_clear (declp); |
string_append (declp, "operator "); |
string_appends (declp, &type); |
string_delete (&type); |
} |
} |
else if (declp->b[0] == '_' && declp->b[1] == '_' |
&& ISLOWER((unsigned char)declp->b[2]) |
&& ISLOWER((unsigned char)declp->b[3])) |
{ |
if (declp->b[4] == '\0') |
{ |
/* Operator. */ |
for (i = 0; i < ARRAY_SIZE (optable); i++) |
{ |
if (strlen (optable[i].in) == 2 |
&& memcmp (optable[i].in, declp->b + 2, 2) == 0) |
{ |
string_clear (declp); |
string_append (declp, "operator"); |
string_append (declp, optable[i].out); |
break; |
} |
} |
} |
else |
{ |
if (declp->b[2] == 'a' && declp->b[5] == '\0') |
{ |
/* Assignment. */ |
for (i = 0; i < ARRAY_SIZE (optable); i++) |
{ |
if (strlen (optable[i].in) == 3 |
&& memcmp (optable[i].in, declp->b + 2, 3) == 0) |
{ |
string_clear (declp); |
string_append (declp, "operator"); |
string_append (declp, optable[i].out); |
break; |
} |
} |
} |
} |
} |
/* If a function name was obtained but it's not valid, we were not |
successful. */ |
if (LEN_STRING (declp) == 1 && declp->b[0] == '.') |
return 0; |
else |
return 1; |
} |
/* a mini string-handling package */ |
static void |
string_need (string *s, int n) |
{ |
int tem; |
if (s->b == NULL) |
{ |
if (n < 32) |
{ |
n = 32; |
} |
s->p = s->b = XNEWVEC (char, n); |
s->e = s->b + n; |
} |
else if (s->e - s->p < n) |
{ |
tem = s->p - s->b; |
n += tem; |
n *= 2; |
s->b = XRESIZEVEC (char, s->b, n); |
s->p = s->b + tem; |
s->e = s->b + n; |
} |
} |
static void |
string_delete (string *s) |
{ |
if (s->b != NULL) |
{ |
free (s->b); |
s->b = s->e = s->p = NULL; |
} |
} |
static void |
string_init (string *s) |
{ |
s->b = s->p = s->e = NULL; |
} |
static void |
string_clear (string *s) |
{ |
s->p = s->b; |
} |
#if 0 |
static int |
string_empty (string *s) |
{ |
return (s->b == s->p); |
} |
#endif |
static void |
string_append (string *p, const char *s) |
{ |
int n; |
if (s == NULL || *s == '\0') |
return; |
n = strlen (s); |
string_need (p, n); |
memcpy (p->p, s, n); |
p->p += n; |
} |
static void |
string_appends (string *p, string *s) |
{ |
int n; |
if (s->b != s->p) |
{ |
n = s->p - s->b; |
string_need (p, n); |
memcpy (p->p, s->b, n); |
p->p += n; |
} |
} |
static void |
string_appendn (string *p, const char *s, int n) |
{ |
if (n != 0) |
{ |
string_need (p, n); |
memcpy (p->p, s, n); |
p->p += n; |
} |
} |
static void |
string_prepend (string *p, const char *s) |
{ |
if (s != NULL && *s != '\0') |
{ |
string_prependn (p, s, strlen (s)); |
} |
} |
static void |
string_prepends (string *p, string *s) |
{ |
if (s->b != s->p) |
{ |
string_prependn (p, s->b, s->p - s->b); |
} |
} |
static void |
string_prependn (string *p, const char *s, int n) |
{ |
char *q; |
if (n != 0) |
{ |
string_need (p, n); |
for (q = p->p - 1; q >= p->b; q--) |
{ |
q[n] = q[0]; |
} |
memcpy (p->b, s, n); |
p->p += n; |
} |
} |
static void |
string_append_template_idx (string *s, int idx) |
{ |
char buf[INTBUF_SIZE + 1 /* 'T' */]; |
sprintf(buf, "T%d", idx); |
string_append (s, buf); |
} |
/contrib/toolchain/binutils/libiberty/crc32.c |
---|
0,0 → 1,181 |
/* crc32.c |
Copyright (C) 2009, 2011 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
This file 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 of the License, or |
(at your option) any later version. |
In addition to the permissions in the GNU General Public License, the |
Free Software Foundation gives you unlimited permission to link the |
compiled version of this file into combinations with other programs, |
and to distribute those combinations without any restriction coming |
from the use of this file. (The General Public License restrictions |
do apply in other respects; for example, they cover modification of |
the file, and distribution when not linked into a combined |
executable.) |
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "libiberty.h" |
/* This table was generated by the following program. This matches |
what gdb does. |
#include <stdio.h> |
int |
main () |
{ |
int i, j; |
unsigned int c; |
int table[256]; |
for (i = 0; i < 256; i++) |
{ |
for (c = i << 24, j = 8; j > 0; --j) |
c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1); |
table[i] = c; |
} |
printf ("static const unsigned int crc32_table[] =\n{\n"); |
for (i = 0; i < 256; i += 4) |
{ |
printf (" 0x%08x, 0x%08x, 0x%08x, 0x%08x", |
table[i + 0], table[i + 1], table[i + 2], table[i + 3]); |
if (i + 4 < 256) |
putchar (','); |
putchar ('\n'); |
} |
printf ("};\n"); |
return 0; |
} |
For more information on CRC, see, e.g., |
http://www.ross.net/crc/download/crc_v3.txt. */ |
static const unsigned int crc32_table[] = |
{ |
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, |
0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, |
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, |
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, |
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, |
0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, |
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, |
0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, |
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, |
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, |
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, |
0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, |
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, |
0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, |
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, |
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, |
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, |
0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, |
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, |
0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, |
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, |
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, |
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, |
0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, |
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, |
0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, |
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, |
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, |
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, |
0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, |
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, |
0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, |
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, |
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, |
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, |
0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, |
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, |
0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, |
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, |
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, |
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, |
0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, |
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, |
0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, |
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, |
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, |
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, |
0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, |
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, |
0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, |
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, |
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, |
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, |
0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, |
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, |
0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, |
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, |
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, |
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, |
0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, |
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, |
0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, |
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, |
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 |
}; |
/* |
@deftypefn Extension {unsigned int} crc32 (const unsigned char *@var{buf}, @ |
int @var{len}, unsigned int @var{init}) |
Compute the 32-bit CRC of @var{buf} which has length @var{len}. The |
starting value is @var{init}; this may be used to compute the CRC of |
data split across multiple buffers by passing the return value of each |
call as the @var{init} parameter of the next. |
This is intended to match the CRC used by the @command{gdb} remote |
protocol for the @samp{qCRC} command. In order to get the same |
results as gdb for a block of data, you must pass the first CRC |
parameter as @code{0xffffffff}. |
This CRC can be specified as: |
Width : 32 |
Poly : 0x04c11db7 |
Init : parameter, typically 0xffffffff |
RefIn : false |
RefOut : false |
XorOut : 0 |
This differs from the "standard" CRC-32 algorithm in that the values |
are not reflected, and there is no final XOR value. These differences |
make it easy to compose the values of multiple blocks. |
@end deftypefn |
*/ |
unsigned int |
xcrc32 (const unsigned char *buf, int len, unsigned int init) |
{ |
unsigned int crc = init; |
while (len--) |
{ |
crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255]; |
buf++; |
} |
return crc; |
} |
/contrib/toolchain/binutils/libiberty/dwarfnames.c |
---|
0,0 → 1,98 |
/* Names of various DWARF tags. |
Copyright (C) 2012 Free Software Foundation, Inc. |
This file is part of GNU CC. |
GNU CC 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. |
In addition to the permissions in the GNU General Public License, the |
Free Software Foundation gives you unlimited permission to link the |
compiled version of this file into combinations with other programs, |
and to distribute those combinations without any restriction coming |
from the use of this file. (The General Public License restrictions |
do apply in other respects; for example, they cover modification of |
the file, and distribution when not linked into a combined |
executable.) |
GNU CC 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 GNU CC; see the file COPYING. If not, write to |
the Free Software Foundation, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#include "dwarf2.h" |
#define DW_FIRST_TAG(name, value) \ |
const char *get_DW_TAG_name (unsigned int tag) \ |
{ switch (tag) { \ |
DW_TAG (name, value) |
#define DW_END_TAG } return 0; } |
#define DW_FIRST_FORM(name, value) \ |
const char *get_DW_FORM_name (unsigned int form) \ |
{ switch (form) { \ |
DW_FORM (name, value) |
#define DW_END_FORM } return 0; } |
#define DW_FIRST_AT(name, value) \ |
const char *get_DW_AT_name (unsigned int attr) { \ |
switch (attr) { \ |
DW_AT (name, value) |
#define DW_END_AT } return 0; } |
#define DW_FIRST_OP(name, value) \ |
const char *get_DW_OP_name (unsigned int op) { \ |
switch (op) { \ |
DW_OP (name, value) |
#define DW_END_OP } return 0; } |
#define DW_FIRST_ATE(name, value) \ |
const char *get_DW_ATE_name (unsigned int enc) { \ |
switch (enc) { \ |
DW_ATE (name, value) |
#define DW_END_ATE } return 0; } |
#define DW_FIRST_CFA(name, value) \ |
const char *get_DW_CFA_name (unsigned int opc) { \ |
switch (opc) { \ |
DW_CFA (name, value) |
#define DW_END_CFA } return 0; } |
#define DW_TAG(name, value) case name: return # name ; |
#define DW_TAG_DUP(name, value) |
#define DW_FORM(name, value) case name: return # name ; |
#define DW_AT(name, value) case name: return # name ; |
#define DW_AT_DUP(name, value) |
#define DW_OP(name, value) case name: return # name ; |
#define DW_OP_DUP(name, value) |
#define DW_ATE(name, value) case name: return # name ; |
#define DW_ATE_DUP(name, value) |
#define DW_CFA(name, value) case name: return # name ; |
#include "dwarf2.def" |
#undef DW_FIRST_TAG |
#undef DW_END_TAG |
#undef DW_FIRST_FORM |
#undef DW_END_FORM |
#undef DW_FIRST_AT |
#undef DW_END_AT |
#undef DW_FIRST_OP |
#undef DW_END_OP |
#undef DW_FIRST_ATE |
#undef DW_END_ATE |
#undef DW_FIRST_CFA |
#undef DW_END_CFA |
#undef DW_TAG |
#undef DW_TAG_DUP |
#undef DW_FORM |
#undef DW_AT |
#undef DW_AT_DUP |
#undef DW_OP |
#undef DW_OP_DUP |
#undef DW_ATE |
#undef DW_ATE_DUP |
#undef DW_CFA |
/contrib/toolchain/binutils/libiberty/dyn-string.c |
---|
0,0 → 1,397 |
/* An abstract string datatype. |
Copyright (C) 1998, 1999, 2000, 2002, 2004 Free Software Foundation, Inc. |
Contributed by Mark Mitchell (mark@markmitchell.com). |
This file is part of GNU CC. |
GNU CC 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. |
In addition to the permissions in the GNU General Public License, the |
Free Software Foundation gives you unlimited permission to link the |
compiled version of this file into combinations with other programs, |
and to distribute those combinations without any restriction coming |
from the use of this file. (The General Public License restrictions |
do apply in other respects; for example, they cover modification of |
the file, and distribution when not linked into a combined |
executable.) |
GNU CC 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 GNU CC; see the file COPYING. If not, write to |
the Free Software Foundation, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <stdio.h> |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#include "libiberty.h" |
#include "dyn-string.h" |
/* Performs in-place initialization of a dyn_string struct. This |
function can be used with a dyn_string struct on the stack or |
embedded in another object. The contents of of the string itself |
are still dynamically allocated. The string initially is capable |
of holding at least SPACE characeters, including the terminating |
NUL. If SPACE is 0, it will silently be increated to 1. |
If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation |
fails, returns 0. Otherwise returns 1. */ |
int |
dyn_string_init (struct dyn_string *ds_struct_ptr, int space) |
{ |
/* We need at least one byte in which to store the terminating NUL. */ |
if (space == 0) |
space = 1; |
#ifdef RETURN_ON_ALLOCATION_FAILURE |
ds_struct_ptr->s = (char *) malloc (space); |
if (ds_struct_ptr->s == NULL) |
return 0; |
#else |
ds_struct_ptr->s = XNEWVEC (char, space); |
#endif |
ds_struct_ptr->allocated = space; |
ds_struct_ptr->length = 0; |
ds_struct_ptr->s[0] = '\0'; |
return 1; |
} |
/* Create a new dynamic string capable of holding at least SPACE |
characters, including the terminating NUL. If SPACE is 0, it will |
be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is |
defined and memory allocation fails, returns NULL. Otherwise |
returns the newly allocated string. */ |
dyn_string_t |
dyn_string_new (int space) |
{ |
dyn_string_t result; |
#ifdef RETURN_ON_ALLOCATION_FAILURE |
result = (dyn_string_t) malloc (sizeof (struct dyn_string)); |
if (result == NULL) |
return NULL; |
if (!dyn_string_init (result, space)) |
{ |
free (result); |
return NULL; |
} |
#else |
result = XNEW (struct dyn_string); |
dyn_string_init (result, space); |
#endif |
return result; |
} |
/* Free the memory used by DS. */ |
void |
dyn_string_delete (dyn_string_t ds) |
{ |
free (ds->s); |
free (ds); |
} |
/* Returns the contents of DS in a buffer allocated with malloc. It |
is the caller's responsibility to deallocate the buffer using free. |
DS is then set to the empty string. Deletes DS itself. */ |
char* |
dyn_string_release (dyn_string_t ds) |
{ |
/* Store the old buffer. */ |
char* result = ds->s; |
/* The buffer is no longer owned by DS. */ |
ds->s = NULL; |
/* Delete DS. */ |
free (ds); |
/* Return the old buffer. */ |
return result; |
} |
/* Increase the capacity of DS so it can hold at least SPACE |
characters, plus the terminating NUL. This function will not (at |
present) reduce the capacity of DS. Returns DS on success. |
If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation |
operation fails, deletes DS and returns NULL. */ |
dyn_string_t |
dyn_string_resize (dyn_string_t ds, int space) |
{ |
int new_allocated = ds->allocated; |
/* Increase SPACE to hold the NUL termination. */ |
++space; |
/* Increase allocation by factors of two. */ |
while (space > new_allocated) |
new_allocated *= 2; |
if (new_allocated != ds->allocated) |
{ |
ds->allocated = new_allocated; |
/* We actually need more space. */ |
#ifdef RETURN_ON_ALLOCATION_FAILURE |
ds->s = (char *) realloc (ds->s, ds->allocated); |
if (ds->s == NULL) |
{ |
free (ds); |
return NULL; |
} |
#else |
ds->s = XRESIZEVEC (char, ds->s, ds->allocated); |
#endif |
} |
return ds; |
} |
/* Sets the contents of DS to the empty string. */ |
void |
dyn_string_clear (dyn_string_t ds) |
{ |
/* A dyn_string always has room for at least the NUL terminator. */ |
ds->s[0] = '\0'; |
ds->length = 0; |
} |
/* Makes the contents of DEST the same as the contents of SRC. DEST |
and SRC must be distinct. Returns 1 on success. On failure, if |
RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ |
int |
dyn_string_copy (dyn_string_t dest, dyn_string_t src) |
{ |
if (dest == src) |
abort (); |
/* Make room in DEST. */ |
if (dyn_string_resize (dest, src->length) == NULL) |
return 0; |
/* Copy DEST into SRC. */ |
strcpy (dest->s, src->s); |
/* Update the size of DEST. */ |
dest->length = src->length; |
return 1; |
} |
/* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on |
success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST |
and returns 0. */ |
int |
dyn_string_copy_cstr (dyn_string_t dest, const char *src) |
{ |
int length = strlen (src); |
/* Make room in DEST. */ |
if (dyn_string_resize (dest, length) == NULL) |
return 0; |
/* Copy DEST into SRC. */ |
strcpy (dest->s, src); |
/* Update the size of DEST. */ |
dest->length = length; |
return 1; |
} |
/* Inserts SRC at the beginning of DEST. DEST is expanded as |
necessary. SRC and DEST must be distinct. Returns 1 on success. |
On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and |
returns 0. */ |
int |
dyn_string_prepend (dyn_string_t dest, dyn_string_t src) |
{ |
return dyn_string_insert (dest, 0, src); |
} |
/* Inserts SRC, a NUL-terminated string, at the beginning of DEST. |
DEST is expanded as necessary. Returns 1 on success. On failure, |
if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ |
int |
dyn_string_prepend_cstr (dyn_string_t dest, const char *src) |
{ |
return dyn_string_insert_cstr (dest, 0, src); |
} |
/* Inserts SRC into DEST starting at position POS. DEST is expanded |
as necessary. SRC and DEST must be distinct. Returns 1 on |
success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST |
and returns 0. */ |
int |
dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src) |
{ |
int i; |
if (src == dest) |
abort (); |
if (dyn_string_resize (dest, dest->length + src->length) == NULL) |
return 0; |
/* Make room for the insertion. Be sure to copy the NUL. */ |
for (i = dest->length; i >= pos; --i) |
dest->s[i + src->length] = dest->s[i]; |
/* Splice in the new stuff. */ |
strncpy (dest->s + pos, src->s, src->length); |
/* Compute the new length. */ |
dest->length += src->length; |
return 1; |
} |
/* Inserts SRC, a NUL-terminated string, into DEST starting at |
position POS. DEST is expanded as necessary. Returns 1 on |
success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST |
and returns 0. */ |
int |
dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src) |
{ |
int i; |
int length = strlen (src); |
if (dyn_string_resize (dest, dest->length + length) == NULL) |
return 0; |
/* Make room for the insertion. Be sure to copy the NUL. */ |
for (i = dest->length; i >= pos; --i) |
dest->s[i + length] = dest->s[i]; |
/* Splice in the new stuff. */ |
strncpy (dest->s + pos, src, length); |
/* Compute the new length. */ |
dest->length += length; |
return 1; |
} |
/* Inserts character C into DEST starting at position POS. DEST is |
expanded as necessary. Returns 1 on success. On failure, |
RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ |
int |
dyn_string_insert_char (dyn_string_t dest, int pos, int c) |
{ |
int i; |
if (dyn_string_resize (dest, dest->length + 1) == NULL) |
return 0; |
/* Make room for the insertion. Be sure to copy the NUL. */ |
for (i = dest->length; i >= pos; --i) |
dest->s[i + 1] = dest->s[i]; |
/* Add the new character. */ |
dest->s[pos] = c; |
/* Compute the new length. */ |
++dest->length; |
return 1; |
} |
/* Append S to DS, resizing DS if necessary. Returns 1 on success. |
On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and |
returns 0. */ |
int |
dyn_string_append (dyn_string_t dest, dyn_string_t s) |
{ |
if (dyn_string_resize (dest, dest->length + s->length) == 0) |
return 0; |
strcpy (dest->s + dest->length, s->s); |
dest->length += s->length; |
return 1; |
} |
/* Append the NUL-terminated string S to DS, resizing DS if necessary. |
Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, |
deletes DEST and returns 0. */ |
int |
dyn_string_append_cstr (dyn_string_t dest, const char *s) |
{ |
int len = strlen (s); |
/* The new length is the old length plus the size of our string, plus |
one for the null at the end. */ |
if (dyn_string_resize (dest, dest->length + len) == NULL) |
return 0; |
strcpy (dest->s + dest->length, s); |
dest->length += len; |
return 1; |
} |
/* Appends C to the end of DEST. Returns 1 on success. On failure, |
if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */ |
int |
dyn_string_append_char (dyn_string_t dest, int c) |
{ |
/* Make room for the extra character. */ |
if (dyn_string_resize (dest, dest->length + 1) == NULL) |
return 0; |
/* Append the character; it will overwrite the old NUL. */ |
dest->s[dest->length] = c; |
/* Add a new NUL at the end. */ |
dest->s[dest->length + 1] = '\0'; |
/* Update the length. */ |
++(dest->length); |
return 1; |
} |
/* Sets the contents of DEST to the substring of SRC starting at START |
and ending before END. START must be less than or equal to END, |
and both must be between zero and the length of SRC, inclusive. |
Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE, |
deletes DEST and returns 0. */ |
int |
dyn_string_substring (dyn_string_t dest, dyn_string_t src, |
int start, int end) |
{ |
int i; |
int length = end - start; |
if (start > end || start > src->length || end > src->length) |
abort (); |
/* Make room for the substring. */ |
if (dyn_string_resize (dest, length) == NULL) |
return 0; |
/* Copy the characters in the substring, */ |
for (i = length; --i >= 0; ) |
dest->s[i] = src->s[start + i]; |
/* NUL-terimate the result. */ |
dest->s[length] = '\0'; |
/* Record the length of the substring. */ |
dest->length = length; |
return 1; |
} |
/* Returns non-zero if DS1 and DS2 have the same contents. */ |
int |
dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2) |
{ |
/* If DS1 and DS2 have different lengths, they must not be the same. */ |
if (ds1->length != ds2->length) |
return 0; |
else |
return !strcmp (ds1->s, ds2->s); |
} |
/contrib/toolchain/binutils/libiberty/fdmatch.c |
---|
0,0 → 1,68 |
/* Compare two open file descriptors to see if they refer to the same file. |
Copyright (C) 1991 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Extension int fdmatch (int @var{fd1}, int @var{fd2}) |
Check to see if two open file descriptors refer to the same file. |
This is useful, for example, when we have an open file descriptor for |
an unnamed file, and the name of a file that we believe to correspond |
to that fd. This can happen when we are exec'd with an already open |
file (@code{stdout} for example) or from the SVR4 @file{/proc} calls |
that return open file descriptors for mapped address spaces. All we |
have to do is open the file by name and check the two file descriptors |
for a match, which is done by comparing major and minor device numbers |
and inode numbers. |
@end deftypefn |
BUGS |
(FIXME: does this work for networks?) |
It works for NFS, which assigns a device number to each mount. |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#include <sys/types.h> |
#include <sys/stat.h> |
int fdmatch (int fd1, int fd2) |
{ |
struct stat sbuf1; |
struct stat sbuf2; |
if ((fstat (fd1, &sbuf1) == 0) && |
(fstat (fd2, &sbuf2) == 0) && |
(sbuf1.st_dev == sbuf2.st_dev) && |
(sbuf1.st_ino == sbuf2.st_ino)) |
{ |
return (1); |
} |
else |
{ |
return (0); |
} |
} |
/contrib/toolchain/binutils/libiberty/ffs.c |
---|
0,0 → 1,26 |
/* ffs -- Find the first bit set in the parameter |
@deftypefn Supplemental int ffs (int @var{valu}) |
Find the first (least significant) bit set in @var{valu}. Bits are |
numbered from right to left, starting with bit 1 (corresponding to the |
value 1). If @var{valu} is zero, zero is returned. |
@end deftypefn |
*/ |
int |
ffs (register int valu) |
{ |
register int bit; |
if (valu == 0) |
return 0; |
for (bit = 1; !(valu & 1); bit++) |
valu >>= 1; |
return bit; |
} |
/contrib/toolchain/binutils/libiberty/fibheap.c |
---|
0,0 → 1,486 |
/* A Fibonacci heap datatype. |
Copyright 1998, 1999, 2000, 2001 Free Software Foundation, Inc. |
Contributed by Daniel Berlin (dan@cgsoftware.com). |
This file is part of GNU CC. |
GNU CC 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. |
GNU CC 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 GNU CC; see the file COPYING. If not, write to |
the Free Software Foundation, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#ifdef HAVE_LIMITS_H |
#include <limits.h> |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#include "libiberty.h" |
#include "fibheap.h" |
#define FIBHEAPKEY_MIN LONG_MIN |
static void fibheap_ins_root (fibheap_t, fibnode_t); |
static void fibheap_rem_root (fibheap_t, fibnode_t); |
static void fibheap_consolidate (fibheap_t); |
static void fibheap_link (fibheap_t, fibnode_t, fibnode_t); |
static void fibheap_cut (fibheap_t, fibnode_t, fibnode_t); |
static void fibheap_cascading_cut (fibheap_t, fibnode_t); |
static fibnode_t fibheap_extr_min_node (fibheap_t); |
static int fibheap_compare (fibheap_t, fibnode_t, fibnode_t); |
static int fibheap_comp_data (fibheap_t, fibheapkey_t, void *, fibnode_t); |
static fibnode_t fibnode_new (void); |
static void fibnode_insert_after (fibnode_t, fibnode_t); |
#define fibnode_insert_before(a, b) fibnode_insert_after (a->left, b) |
static fibnode_t fibnode_remove (fibnode_t); |
/* Create a new fibonacci heap. */ |
fibheap_t |
fibheap_new (void) |
{ |
return (fibheap_t) xcalloc (1, sizeof (struct fibheap)); |
} |
/* Create a new fibonacci heap node. */ |
static fibnode_t |
fibnode_new (void) |
{ |
fibnode_t node; |
node = (fibnode_t) xcalloc (1, sizeof *node); |
node->left = node; |
node->right = node; |
return node; |
} |
static inline int |
fibheap_compare (fibheap_t heap ATTRIBUTE_UNUSED, fibnode_t a, fibnode_t b) |
{ |
if (a->key < b->key) |
return -1; |
if (a->key > b->key) |
return 1; |
return 0; |
} |
static inline int |
fibheap_comp_data (fibheap_t heap, fibheapkey_t key, void *data, fibnode_t b) |
{ |
struct fibnode a; |
a.key = key; |
a.data = data; |
return fibheap_compare (heap, &a, b); |
} |
/* Insert DATA, with priority KEY, into HEAP. */ |
fibnode_t |
fibheap_insert (fibheap_t heap, fibheapkey_t key, void *data) |
{ |
fibnode_t node; |
/* Create the new node. */ |
node = fibnode_new (); |
/* Set the node's data. */ |
node->data = data; |
node->key = key; |
/* Insert it into the root list. */ |
fibheap_ins_root (heap, node); |
/* If their was no minimum, or this key is less than the min, |
it's the new min. */ |
if (heap->min == NULL || node->key < heap->min->key) |
heap->min = node; |
heap->nodes++; |
return node; |
} |
/* Return the data of the minimum node (if we know it). */ |
void * |
fibheap_min (fibheap_t heap) |
{ |
/* If there is no min, we can't easily return it. */ |
if (heap->min == NULL) |
return NULL; |
return heap->min->data; |
} |
/* Return the key of the minimum node (if we know it). */ |
fibheapkey_t |
fibheap_min_key (fibheap_t heap) |
{ |
/* If there is no min, we can't easily return it. */ |
if (heap->min == NULL) |
return 0; |
return heap->min->key; |
} |
/* Union HEAPA and HEAPB into a new heap. */ |
fibheap_t |
fibheap_union (fibheap_t heapa, fibheap_t heapb) |
{ |
fibnode_t a_root, b_root, temp; |
/* If one of the heaps is empty, the union is just the other heap. */ |
if ((a_root = heapa->root) == NULL) |
{ |
free (heapa); |
return heapb; |
} |
if ((b_root = heapb->root) == NULL) |
{ |
free (heapb); |
return heapa; |
} |
/* Merge them to the next nodes on the opposite chain. */ |
a_root->left->right = b_root; |
b_root->left->right = a_root; |
temp = a_root->left; |
a_root->left = b_root->left; |
b_root->left = temp; |
heapa->nodes += heapb->nodes; |
/* And set the new minimum, if it's changed. */ |
if (fibheap_compare (heapa, heapb->min, heapa->min) < 0) |
heapa->min = heapb->min; |
free (heapb); |
return heapa; |
} |
/* Extract the data of the minimum node from HEAP. */ |
void * |
fibheap_extract_min (fibheap_t heap) |
{ |
fibnode_t z; |
void *ret = NULL; |
/* If we don't have a min set, it means we have no nodes. */ |
if (heap->min != NULL) |
{ |
/* Otherwise, extract the min node, free the node, and return the |
node's data. */ |
z = fibheap_extr_min_node (heap); |
ret = z->data; |
free (z); |
} |
return ret; |
} |
/* Replace both the KEY and the DATA associated with NODE. */ |
void * |
fibheap_replace_key_data (fibheap_t heap, fibnode_t node, |
fibheapkey_t key, void *data) |
{ |
void *odata; |
fibheapkey_t okey; |
fibnode_t y; |
/* If we wanted to, we could actually do a real increase by redeleting and |
inserting. However, this would require O (log n) time. So just bail out |
for now. */ |
if (fibheap_comp_data (heap, key, data, node) > 0) |
return NULL; |
odata = node->data; |
okey = node->key; |
node->data = data; |
node->key = key; |
y = node->parent; |
/* Short-circuit if the key is the same, as we then don't have to |
do anything. Except if we're trying to force the new node to |
be the new minimum for delete. */ |
if (okey == key && okey != FIBHEAPKEY_MIN) |
return odata; |
/* These two compares are specifically <= 0 to make sure that in the case |
of equality, a node we replaced the data on, becomes the new min. This |
is needed so that delete's call to extractmin gets the right node. */ |
if (y != NULL && fibheap_compare (heap, node, y) <= 0) |
{ |
fibheap_cut (heap, node, y); |
fibheap_cascading_cut (heap, y); |
} |
if (fibheap_compare (heap, node, heap->min) <= 0) |
heap->min = node; |
return odata; |
} |
/* Replace the DATA associated with NODE. */ |
void * |
fibheap_replace_data (fibheap_t heap, fibnode_t node, void *data) |
{ |
return fibheap_replace_key_data (heap, node, node->key, data); |
} |
/* Replace the KEY associated with NODE. */ |
fibheapkey_t |
fibheap_replace_key (fibheap_t heap, fibnode_t node, fibheapkey_t key) |
{ |
int okey = node->key; |
fibheap_replace_key_data (heap, node, key, node->data); |
return okey; |
} |
/* Delete NODE from HEAP. */ |
void * |
fibheap_delete_node (fibheap_t heap, fibnode_t node) |
{ |
void *ret = node->data; |
/* To perform delete, we just make it the min key, and extract. */ |
fibheap_replace_key (heap, node, FIBHEAPKEY_MIN); |
if (node != heap->min) |
{ |
fprintf (stderr, "Can't force minimum on fibheap.\n"); |
abort (); |
} |
fibheap_extract_min (heap); |
return ret; |
} |
/* Delete HEAP. */ |
void |
fibheap_delete (fibheap_t heap) |
{ |
while (heap->min != NULL) |
free (fibheap_extr_min_node (heap)); |
free (heap); |
} |
/* Determine if HEAP is empty. */ |
int |
fibheap_empty (fibheap_t heap) |
{ |
return heap->nodes == 0; |
} |
/* Extract the minimum node of the heap. */ |
static fibnode_t |
fibheap_extr_min_node (fibheap_t heap) |
{ |
fibnode_t ret = heap->min; |
fibnode_t x, y, orig; |
/* Attach the child list of the minimum node to the root list of the heap. |
If there is no child list, we don't do squat. */ |
for (x = ret->child, orig = NULL; x != orig && x != NULL; x = y) |
{ |
if (orig == NULL) |
orig = x; |
y = x->right; |
x->parent = NULL; |
fibheap_ins_root (heap, x); |
} |
/* Remove the old root. */ |
fibheap_rem_root (heap, ret); |
heap->nodes--; |
/* If we are left with no nodes, then the min is NULL. */ |
if (heap->nodes == 0) |
heap->min = NULL; |
else |
{ |
/* Otherwise, consolidate to find new minimum, as well as do the reorg |
work that needs to be done. */ |
heap->min = ret->right; |
fibheap_consolidate (heap); |
} |
return ret; |
} |
/* Insert NODE into the root list of HEAP. */ |
static void |
fibheap_ins_root (fibheap_t heap, fibnode_t node) |
{ |
/* If the heap is currently empty, the new node becomes the singleton |
circular root list. */ |
if (heap->root == NULL) |
{ |
heap->root = node; |
node->left = node; |
node->right = node; |
return; |
} |
/* Otherwise, insert it in the circular root list between the root |
and it's right node. */ |
fibnode_insert_after (heap->root, node); |
} |
/* Remove NODE from the rootlist of HEAP. */ |
static void |
fibheap_rem_root (fibheap_t heap, fibnode_t node) |
{ |
if (node->left == node) |
heap->root = NULL; |
else |
heap->root = fibnode_remove (node); |
} |
/* Consolidate the heap. */ |
static void |
fibheap_consolidate (fibheap_t heap) |
{ |
fibnode_t a[1 + 8 * sizeof (long)]; |
fibnode_t w; |
fibnode_t y; |
fibnode_t x; |
int i; |
int d; |
int D; |
D = 1 + 8 * sizeof (long); |
memset (a, 0, sizeof (fibnode_t) * D); |
while ((w = heap->root) != NULL) |
{ |
x = w; |
fibheap_rem_root (heap, w); |
d = x->degree; |
while (a[d] != NULL) |
{ |
y = a[d]; |
if (fibheap_compare (heap, x, y) > 0) |
{ |
fibnode_t temp; |
temp = x; |
x = y; |
y = temp; |
} |
fibheap_link (heap, y, x); |
a[d] = NULL; |
d++; |
} |
a[d] = x; |
} |
heap->min = NULL; |
for (i = 0; i < D; i++) |
if (a[i] != NULL) |
{ |
fibheap_ins_root (heap, a[i]); |
if (heap->min == NULL || fibheap_compare (heap, a[i], heap->min) < 0) |
heap->min = a[i]; |
} |
} |
/* Make NODE a child of PARENT. */ |
static void |
fibheap_link (fibheap_t heap ATTRIBUTE_UNUSED, |
fibnode_t node, fibnode_t parent) |
{ |
if (parent->child == NULL) |
parent->child = node; |
else |
fibnode_insert_before (parent->child, node); |
node->parent = parent; |
parent->degree++; |
node->mark = 0; |
} |
/* Remove NODE from PARENT's child list. */ |
static void |
fibheap_cut (fibheap_t heap, fibnode_t node, fibnode_t parent) |
{ |
fibnode_remove (node); |
parent->degree--; |
fibheap_ins_root (heap, node); |
node->parent = NULL; |
node->mark = 0; |
} |
static void |
fibheap_cascading_cut (fibheap_t heap, fibnode_t y) |
{ |
fibnode_t z; |
while ((z = y->parent) != NULL) |
{ |
if (y->mark == 0) |
{ |
y->mark = 1; |
return; |
} |
else |
{ |
fibheap_cut (heap, y, z); |
y = z; |
} |
} |
} |
static void |
fibnode_insert_after (fibnode_t a, fibnode_t b) |
{ |
if (a == a->right) |
{ |
a->right = b; |
a->left = b; |
b->right = a; |
b->left = a; |
} |
else |
{ |
b->right = a->right; |
a->right->left = b; |
a->right = b; |
b->left = a; |
} |
} |
static fibnode_t |
fibnode_remove (fibnode_t node) |
{ |
fibnode_t ret; |
if (node == node->left) |
ret = NULL; |
else |
ret = node->left; |
if (node->parent != NULL && node->parent->child == node) |
node->parent->child = ret; |
node->right->left = node->left; |
node->left->right = node->right; |
node->parent = NULL; |
node->left = node; |
node->right = node; |
return ret; |
} |
/contrib/toolchain/binutils/libiberty/filename_cmp.c |
---|
0,0 → 1,192 |
/* File name comparison routine. |
Copyright (C) 2007 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#include "filenames.h" |
#include "safe-ctype.h" |
/* |
@deftypefn Extension int filename_cmp (const char *@var{s1}, const char *@var{s2}) |
Return zero if the two file names @var{s1} and @var{s2} are equivalent. |
If not equivalent, the returned value is similar to what @code{strcmp} |
would return. In other words, it returns a negative value if @var{s1} |
is less than @var{s2}, or a positive value if @var{s2} is greater than |
@var{s2}. |
This function does not normalize file names. As a result, this function |
will treat filenames that are spelled differently as different even in |
the case when the two filenames point to the same underlying file. |
However, it does handle the fact that on DOS-like file systems, forward |
and backward slashes are equal. |
@end deftypefn |
*/ |
int |
filename_cmp (const char *s1, const char *s2) |
{ |
#if !defined(HAVE_DOS_BASED_FILE_SYSTEM) \ |
&& !defined(HAVE_CASE_INSENSITIVE_FILE_SYSTEM) |
return strcmp(s1, s2); |
#else |
for (;;) |
{ |
int c1 = *s1; |
int c2 = *s2; |
#if defined (HAVE_CASE_INSENSITIVE_FILE_SYSTEM) |
c1 = TOLOWER (c1); |
c2 = TOLOWER (c2); |
#endif |
#if defined (HAVE_DOS_BASED_FILE_SYSTEM) |
/* On DOS-based file systems, the '/' and the '\' are equivalent. */ |
if (c1 == '/') |
c1 = '\\'; |
if (c2 == '/') |
c2 = '\\'; |
#endif |
if (c1 != c2) |
return (c1 - c2); |
if (c1 == '\0') |
return 0; |
s1++; |
s2++; |
} |
#endif |
} |
/* |
@deftypefn Extension int filename_ncmp (const char *@var{s1}, const char *@var{s2}, size_t @var{n}) |
Return zero if the two file names @var{s1} and @var{s2} are equivalent |
in range @var{n}. |
If not equivalent, the returned value is similar to what @code{strncmp} |
would return. In other words, it returns a negative value if @var{s1} |
is less than @var{s2}, or a positive value if @var{s2} is greater than |
@var{s2}. |
This function does not normalize file names. As a result, this function |
will treat filenames that are spelled differently as different even in |
the case when the two filenames point to the same underlying file. |
However, it does handle the fact that on DOS-like file systems, forward |
and backward slashes are equal. |
@end deftypefn |
*/ |
int |
filename_ncmp (const char *s1, const char *s2, size_t n) |
{ |
#if !defined(HAVE_DOS_BASED_FILE_SYSTEM) \ |
&& !defined(HAVE_CASE_INSENSITIVE_FILE_SYSTEM) |
return strncmp(s1, s2, n); |
#else |
if (!n) |
return 0; |
for (; n > 0; --n) |
{ |
int c1 = *s1; |
int c2 = *s2; |
#if defined (HAVE_CASE_INSENSITIVE_FILE_SYSTEM) |
c1 = TOLOWER (c1); |
c2 = TOLOWER (c2); |
#endif |
#if defined (HAVE_DOS_BASED_FILE_SYSTEM) |
/* On DOS-based file systems, the '/' and the '\' are equivalent. */ |
if (c1 == '/') |
c1 = '\\'; |
if (c2 == '/') |
c2 = '\\'; |
#endif |
if (c1 == '\0' || c1 != c2) |
return (c1 - c2); |
s1++; |
s2++; |
} |
return 0; |
#endif |
} |
/* |
@deftypefn Extension hashval_t filename_hash (const void *@var{s}) |
Return the hash value for file name @var{s} that will be compared |
using filename_cmp. |
This function is for use with hashtab.c hash tables. |
@end deftypefn |
*/ |
hashval_t |
filename_hash (const void *s) |
{ |
/* The cast is for -Wc++-compat. */ |
const unsigned char *str = (const unsigned char *) s; |
hashval_t r = 0; |
unsigned char c; |
while ((c = *str++) != 0) |
{ |
if (c == '\\') |
c = '/'; |
c = TOLOWER (c); |
r = r * 67 + c - 113; |
} |
return r; |
} |
/* |
@deftypefn Extension int filename_eq (const void *@var{s1}, const void *@var{s2}) |
Return non-zero if file names @var{s1} and @var{s2} are equivalent. |
This function is for use with hashtab.c hash tables. |
@end deftypefn |
*/ |
int |
filename_eq (const void *s1, const void *s2) |
{ |
/* The casts are for -Wc++-compat. */ |
return filename_cmp ((const char *) s1, (const char *) s2) == 0; |
} |
/contrib/toolchain/binutils/libiberty/floatformat.c |
---|
0,0 → 1,774 |
/* IEEE floating point support routines, for GDB, the GNU Debugger. |
Copyright 1991, 1994, 1999, 2000, 2003, 2005, 2006, 2010, 2012 |
Free Software Foundation, Inc. |
This file is part of GDB. |
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 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ |
/* This is needed to pick up the NAN macro on some systems. */ |
#define _GNU_SOURCE |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <math.h> |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
/* On some platforms, <float.h> provides DBL_QNAN. */ |
#ifdef STDC_HEADERS |
#include <float.h> |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#include "floatformat.h" |
#ifndef INFINITY |
#ifdef HUGE_VAL |
#define INFINITY HUGE_VAL |
#else |
#define INFINITY (1.0 / 0.0) |
#endif |
#endif |
#ifndef NAN |
#ifdef DBL_QNAN |
#define NAN DBL_QNAN |
#else |
#define NAN (0.0 / 0.0) |
#endif |
#endif |
static int mant_bits_set (const struct floatformat *, const unsigned char *); |
static unsigned long get_field (const unsigned char *, |
enum floatformat_byteorders, |
unsigned int, |
unsigned int, |
unsigned int); |
static int floatformat_always_valid (const struct floatformat *fmt, |
const void *from); |
static int |
floatformat_always_valid (const struct floatformat *fmt ATTRIBUTE_UNUSED, |
const void *from ATTRIBUTE_UNUSED) |
{ |
return 1; |
} |
/* The odds that CHAR_BIT will be anything but 8 are low enough that I'm not |
going to bother with trying to muck around with whether it is defined in |
a system header, what we do if not, etc. */ |
#define FLOATFORMAT_CHAR_BIT 8 |
/* floatformats for IEEE half, single and double, big and little endian. */ |
const struct floatformat floatformat_ieee_half_big = |
{ |
floatformat_big, 16, 0, 1, 5, 15, 31, 6, 10, |
floatformat_intbit_no, |
"floatformat_ieee_half_big", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_ieee_half_little = |
{ |
floatformat_little, 16, 0, 1, 5, 15, 31, 6, 10, |
floatformat_intbit_no, |
"floatformat_ieee_half_little", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_ieee_single_big = |
{ |
floatformat_big, 32, 0, 1, 8, 127, 255, 9, 23, |
floatformat_intbit_no, |
"floatformat_ieee_single_big", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_ieee_single_little = |
{ |
floatformat_little, 32, 0, 1, 8, 127, 255, 9, 23, |
floatformat_intbit_no, |
"floatformat_ieee_single_little", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_ieee_double_big = |
{ |
floatformat_big, 64, 0, 1, 11, 1023, 2047, 12, 52, |
floatformat_intbit_no, |
"floatformat_ieee_double_big", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_ieee_double_little = |
{ |
floatformat_little, 64, 0, 1, 11, 1023, 2047, 12, 52, |
floatformat_intbit_no, |
"floatformat_ieee_double_little", |
floatformat_always_valid, |
NULL |
}; |
/* floatformat for IEEE double, little endian byte order, with big endian word |
ordering, as on the ARM. */ |
const struct floatformat floatformat_ieee_double_littlebyte_bigword = |
{ |
floatformat_littlebyte_bigword, 64, 0, 1, 11, 1023, 2047, 12, 52, |
floatformat_intbit_no, |
"floatformat_ieee_double_littlebyte_bigword", |
floatformat_always_valid, |
NULL |
}; |
/* floatformat for VAX. Not quite IEEE, but close enough. */ |
const struct floatformat floatformat_vax_f = |
{ |
floatformat_vax, 32, 0, 1, 8, 129, 0, 9, 23, |
floatformat_intbit_no, |
"floatformat_vax_f", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_vax_d = |
{ |
floatformat_vax, 64, 0, 1, 8, 129, 0, 9, 55, |
floatformat_intbit_no, |
"floatformat_vax_d", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_vax_g = |
{ |
floatformat_vax, 64, 0, 1, 11, 1025, 0, 12, 52, |
floatformat_intbit_no, |
"floatformat_vax_g", |
floatformat_always_valid, |
NULL |
}; |
static int floatformat_i387_ext_is_valid (const struct floatformat *fmt, |
const void *from); |
static int |
floatformat_i387_ext_is_valid (const struct floatformat *fmt, const void *from) |
{ |
/* In the i387 double-extended format, if the exponent is all ones, |
then the integer bit must be set. If the exponent is neither 0 |
nor ~0, the intbit must also be set. Only if the exponent is |
zero can it be zero, and then it must be zero. */ |
unsigned long exponent, int_bit; |
const unsigned char *ufrom = (const unsigned char *) from; |
exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, |
fmt->exp_start, fmt->exp_len); |
int_bit = get_field (ufrom, fmt->byteorder, fmt->totalsize, |
fmt->man_start, 1); |
if ((exponent == 0) != (int_bit == 0)) |
return 0; |
else |
return 1; |
} |
const struct floatformat floatformat_i387_ext = |
{ |
floatformat_little, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, |
floatformat_intbit_yes, |
"floatformat_i387_ext", |
floatformat_i387_ext_is_valid, |
NULL |
}; |
const struct floatformat floatformat_m68881_ext = |
{ |
/* Note that the bits from 16 to 31 are unused. */ |
floatformat_big, 96, 0, 1, 15, 0x3fff, 0x7fff, 32, 64, |
floatformat_intbit_yes, |
"floatformat_m68881_ext", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_i960_ext = |
{ |
/* Note that the bits from 0 to 15 are unused. */ |
floatformat_little, 96, 16, 17, 15, 0x3fff, 0x7fff, 32, 64, |
floatformat_intbit_yes, |
"floatformat_i960_ext", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_m88110_ext = |
{ |
floatformat_big, 80, 0, 1, 15, 0x3fff, 0x7fff, 16, 64, |
floatformat_intbit_yes, |
"floatformat_m88110_ext", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_m88110_harris_ext = |
{ |
/* Harris uses raw format 128 bytes long, but the number is just an ieee |
double, and the last 64 bits are wasted. */ |
floatformat_big,128, 0, 1, 11, 0x3ff, 0x7ff, 12, 52, |
floatformat_intbit_no, |
"floatformat_m88110_ext_harris", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_arm_ext_big = |
{ |
/* Bits 1 to 16 are unused. */ |
floatformat_big, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, |
floatformat_intbit_yes, |
"floatformat_arm_ext_big", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_arm_ext_littlebyte_bigword = |
{ |
/* Bits 1 to 16 are unused. */ |
floatformat_littlebyte_bigword, 96, 0, 17, 15, 0x3fff, 0x7fff, 32, 64, |
floatformat_intbit_yes, |
"floatformat_arm_ext_littlebyte_bigword", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_ia64_spill_big = |
{ |
floatformat_big, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, |
floatformat_intbit_yes, |
"floatformat_ia64_spill_big", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_ia64_spill_little = |
{ |
floatformat_little, 128, 0, 1, 17, 65535, 0x1ffff, 18, 64, |
floatformat_intbit_yes, |
"floatformat_ia64_spill_little", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_ia64_quad_big = |
{ |
floatformat_big, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, |
floatformat_intbit_no, |
"floatformat_ia64_quad_big", |
floatformat_always_valid, |
NULL |
}; |
const struct floatformat floatformat_ia64_quad_little = |
{ |
floatformat_little, 128, 0, 1, 15, 16383, 0x7fff, 16, 112, |
floatformat_intbit_no, |
"floatformat_ia64_quad_little", |
floatformat_always_valid, |
NULL |
}; |
static int |
floatformat_ibm_long_double_is_valid (const struct floatformat *fmt, |
const void *from) |
{ |
const unsigned char *ufrom = (const unsigned char *) from; |
const struct floatformat *hfmt = fmt->split_half; |
long top_exp, bot_exp; |
int top_nan = 0; |
top_exp = get_field (ufrom, hfmt->byteorder, hfmt->totalsize, |
hfmt->exp_start, hfmt->exp_len); |
bot_exp = get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize, |
hfmt->exp_start, hfmt->exp_len); |
if ((unsigned long) top_exp == hfmt->exp_nan) |
top_nan = mant_bits_set (hfmt, ufrom); |
/* A NaN is valid with any low part. */ |
if (top_nan) |
return 1; |
/* An infinity, zero or denormal requires low part 0 (positive or |
negative). */ |
if ((unsigned long) top_exp == hfmt->exp_nan || top_exp == 0) |
{ |
if (bot_exp != 0) |
return 0; |
return !mant_bits_set (hfmt, ufrom + 8); |
} |
/* The top part is now a finite normal value. The long double value |
is the sum of the two parts, and the top part must equal the |
result of rounding the long double value to nearest double. Thus |
the bottom part must be <= 0.5ulp of the top part in absolute |
value, and if it is < 0.5ulp then the long double is definitely |
valid. */ |
if (bot_exp < top_exp - 53) |
return 1; |
if (bot_exp > top_exp - 53 && bot_exp != 0) |
return 0; |
if (bot_exp == 0) |
{ |
/* The bottom part is 0 or denormal. Determine which, and if |
denormal the first two set bits. */ |
int first_bit = -1, second_bit = -1, cur_bit; |
for (cur_bit = 0; (unsigned int) cur_bit < hfmt->man_len; cur_bit++) |
if (get_field (ufrom + 8, hfmt->byteorder, hfmt->totalsize, |
hfmt->man_start + cur_bit, 1)) |
{ |
if (first_bit == -1) |
first_bit = cur_bit; |
else |
{ |
second_bit = cur_bit; |
break; |
} |
} |
/* Bottom part 0 is OK. */ |
if (first_bit == -1) |
return 1; |
/* The real exponent of the bottom part is -first_bit. */ |
if (-first_bit < top_exp - 53) |
return 1; |
if (-first_bit > top_exp - 53) |
return 0; |
/* The bottom part is at least 0.5ulp of the top part. For this |
to be OK, the bottom part must be exactly 0.5ulp (i.e. no |
more bits set) and the top part must have last bit 0. */ |
if (second_bit != -1) |
return 0; |
return !get_field (ufrom, hfmt->byteorder, hfmt->totalsize, |
hfmt->man_start + hfmt->man_len - 1, 1); |
} |
else |
{ |
/* The bottom part is at least 0.5ulp of the top part. For this |
to be OK, it must be exactly 0.5ulp (i.e. no explicit bits |
set) and the top part must have last bit 0. */ |
if (get_field (ufrom, hfmt->byteorder, hfmt->totalsize, |
hfmt->man_start + hfmt->man_len - 1, 1)) |
return 0; |
return !mant_bits_set (hfmt, ufrom + 8); |
} |
} |
const struct floatformat floatformat_ibm_long_double_big = |
{ |
floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52, |
floatformat_intbit_no, |
"floatformat_ibm_long_double_big", |
floatformat_ibm_long_double_is_valid, |
&floatformat_ieee_double_big |
}; |
const struct floatformat floatformat_ibm_long_double_little = |
{ |
floatformat_little, 128, 0, 1, 11, 1023, 2047, 12, 52, |
floatformat_intbit_no, |
"floatformat_ibm_long_double_little", |
floatformat_ibm_long_double_is_valid, |
&floatformat_ieee_double_little |
}; |
#ifndef min |
#define min(a, b) ((a) < (b) ? (a) : (b)) |
#endif |
/* Return 1 if any bits are explicitly set in the mantissa of UFROM, |
format FMT, 0 otherwise. */ |
static int |
mant_bits_set (const struct floatformat *fmt, const unsigned char *ufrom) |
{ |
unsigned int mant_bits, mant_off; |
int mant_bits_left; |
mant_off = fmt->man_start; |
mant_bits_left = fmt->man_len; |
while (mant_bits_left > 0) |
{ |
mant_bits = min (mant_bits_left, 32); |
if (get_field (ufrom, fmt->byteorder, fmt->totalsize, |
mant_off, mant_bits) != 0) |
return 1; |
mant_off += mant_bits; |
mant_bits_left -= mant_bits; |
} |
return 0; |
} |
/* Extract a field which starts at START and is LEN bits long. DATA and |
TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ |
static unsigned long |
get_field (const unsigned char *data, enum floatformat_byteorders order, |
unsigned int total_len, unsigned int start, unsigned int len) |
{ |
unsigned long result = 0; |
unsigned int cur_byte; |
int lo_bit, hi_bit, cur_bitshift = 0; |
int nextbyte = (order == floatformat_little) ? 1 : -1; |
/* Start is in big-endian bit order! Fix that first. */ |
start = total_len - (start + len); |
/* Start at the least significant part of the field. */ |
if (order == floatformat_little) |
cur_byte = start / FLOATFORMAT_CHAR_BIT; |
else |
cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; |
lo_bit = start % FLOATFORMAT_CHAR_BIT; |
hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); |
do |
{ |
unsigned int shifted = *(data + cur_byte) >> lo_bit; |
unsigned int bits = hi_bit - lo_bit; |
unsigned int mask = (1 << bits) - 1; |
result |= (shifted & mask) << cur_bitshift; |
len -= bits; |
cur_bitshift += bits; |
cur_byte += nextbyte; |
lo_bit = 0; |
hi_bit = min (len, FLOATFORMAT_CHAR_BIT); |
} |
while (len != 0); |
return result; |
} |
/* Convert from FMT to a double. |
FROM is the address of the extended float. |
Store the double in *TO. */ |
void |
floatformat_to_double (const struct floatformat *fmt, |
const void *from, double *to) |
{ |
const unsigned char *ufrom = (const unsigned char *) from; |
double dto; |
long exponent; |
unsigned long mant; |
unsigned int mant_bits, mant_off; |
int mant_bits_left; |
/* Split values are not handled specially, since the top half has |
the correctly rounded double value (in the only supported case of |
split values). */ |
exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize, |
fmt->exp_start, fmt->exp_len); |
/* If the exponent indicates a NaN, we don't have information to |
decide what to do. So we handle it like IEEE, except that we |
don't try to preserve the type of NaN. FIXME. */ |
if ((unsigned long) exponent == fmt->exp_nan) |
{ |
int nan = mant_bits_set (fmt, ufrom); |
/* On certain systems (such as GNU/Linux), the use of the |
INFINITY macro below may generate a warning that can not be |
silenced due to a bug in GCC (PR preprocessor/11931). The |
preprocessor fails to recognise the __extension__ keyword in |
conjunction with the GNU/C99 extension for hexadecimal |
floating point constants and will issue a warning when |
compiling with -pedantic. */ |
if (nan) |
dto = NAN; |
else |
dto = INFINITY; |
if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) |
dto = -dto; |
*to = dto; |
return; |
} |
mant_bits_left = fmt->man_len; |
mant_off = fmt->man_start; |
dto = 0.0; |
/* Build the result algebraically. Might go infinite, underflow, etc; |
who cares. */ |
/* For denorms use minimum exponent. */ |
if (exponent == 0) |
exponent = 1 - fmt->exp_bias; |
else |
{ |
exponent -= fmt->exp_bias; |
/* If this format uses a hidden bit, explicitly add it in now. |
Otherwise, increment the exponent by one to account for the |
integer bit. */ |
if (fmt->intbit == floatformat_intbit_no) |
dto = ldexp (1.0, exponent); |
else |
exponent++; |
} |
while (mant_bits_left > 0) |
{ |
mant_bits = min (mant_bits_left, 32); |
mant = get_field (ufrom, fmt->byteorder, fmt->totalsize, |
mant_off, mant_bits); |
dto += ldexp ((double) mant, exponent - mant_bits); |
exponent -= mant_bits; |
mant_off += mant_bits; |
mant_bits_left -= mant_bits; |
} |
/* Negate it if negative. */ |
if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1)) |
dto = -dto; |
*to = dto; |
} |
static void put_field (unsigned char *, enum floatformat_byteorders, |
unsigned int, |
unsigned int, |
unsigned int, |
unsigned long); |
/* Set a field which starts at START and is LEN bits long. DATA and |
TOTAL_LEN are the thing we are extracting it from, in byteorder ORDER. */ |
static void |
put_field (unsigned char *data, enum floatformat_byteorders order, |
unsigned int total_len, unsigned int start, unsigned int len, |
unsigned long stuff_to_put) |
{ |
unsigned int cur_byte; |
int lo_bit, hi_bit; |
int nextbyte = (order == floatformat_little) ? 1 : -1; |
/* Start is in big-endian bit order! Fix that first. */ |
start = total_len - (start + len); |
/* Start at the least significant part of the field. */ |
if (order == floatformat_little) |
cur_byte = start / FLOATFORMAT_CHAR_BIT; |
else |
cur_byte = (total_len - start - 1) / FLOATFORMAT_CHAR_BIT; |
lo_bit = start % FLOATFORMAT_CHAR_BIT; |
hi_bit = min (lo_bit + len, FLOATFORMAT_CHAR_BIT); |
do |
{ |
unsigned char *byte_ptr = data + cur_byte; |
unsigned int bits = hi_bit - lo_bit; |
unsigned int mask = ((1 << bits) - 1) << lo_bit; |
*byte_ptr = (*byte_ptr & ~mask) | ((stuff_to_put << lo_bit) & mask); |
stuff_to_put >>= bits; |
len -= bits; |
cur_byte += nextbyte; |
lo_bit = 0; |
hi_bit = min (len, FLOATFORMAT_CHAR_BIT); |
} |
while (len != 0); |
} |
/* The converse: convert the double *FROM to an extended float |
and store where TO points. Neither FROM nor TO have any alignment |
restrictions. */ |
void |
floatformat_from_double (const struct floatformat *fmt, |
const double *from, void *to) |
{ |
double dfrom; |
int exponent; |
double mant; |
unsigned int mant_bits, mant_off; |
int mant_bits_left; |
unsigned char *uto = (unsigned char *) to; |
dfrom = *from; |
memset (uto, 0, fmt->totalsize / FLOATFORMAT_CHAR_BIT); |
/* Split values are not handled specially, since a bottom half of |
zero is correct for any value representable as double (in the |
only supported case of split values). */ |
/* If negative, set the sign bit. */ |
if (dfrom < 0) |
{ |
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1); |
dfrom = -dfrom; |
} |
if (dfrom == 0) |
{ |
/* 0.0. */ |
return; |
} |
if (dfrom != dfrom) |
{ |
/* NaN. */ |
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, |
fmt->exp_len, fmt->exp_nan); |
/* Be sure it's not infinity, but NaN value is irrelevant. */ |
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start, |
32, 1); |
return; |
} |
if (dfrom + dfrom == dfrom) |
{ |
/* This can only happen for an infinite value (or zero, which we |
already handled above). */ |
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, |
fmt->exp_len, fmt->exp_nan); |
return; |
} |
mant = frexp (dfrom, &exponent); |
if (exponent + fmt->exp_bias - 1 > 0) |
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, |
fmt->exp_len, exponent + fmt->exp_bias - 1); |
else |
{ |
/* Handle a denormalized number. FIXME: What should we do for |
non-IEEE formats? */ |
put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, |
fmt->exp_len, 0); |
mant = ldexp (mant, exponent + fmt->exp_bias - 1); |
} |
mant_bits_left = fmt->man_len; |
mant_off = fmt->man_start; |
while (mant_bits_left > 0) |
{ |
unsigned long mant_long; |
mant_bits = mant_bits_left < 32 ? mant_bits_left : 32; |
mant *= 4294967296.0; |
mant_long = (unsigned long)mant; |
mant -= mant_long; |
/* If the integer bit is implicit, and we are not creating a |
denormalized number, then we need to discard it. */ |
if ((unsigned int) mant_bits_left == fmt->man_len |
&& fmt->intbit == floatformat_intbit_no |
&& exponent + fmt->exp_bias - 1 > 0) |
{ |
mant_long &= 0x7fffffff; |
mant_bits -= 1; |
} |
else if (mant_bits < 32) |
{ |
/* The bits we want are in the most significant MANT_BITS bits of |
mant_long. Move them to the least significant. */ |
mant_long >>= 32 - mant_bits; |
} |
put_field (uto, fmt->byteorder, fmt->totalsize, |
mant_off, mant_bits, mant_long); |
mant_off += mant_bits; |
mant_bits_left -= mant_bits; |
} |
} |
/* Return non-zero iff the data at FROM is a valid number in format FMT. */ |
int |
floatformat_is_valid (const struct floatformat *fmt, const void *from) |
{ |
return fmt->is_valid (fmt, from); |
} |
#ifdef IEEE_DEBUG |
#include <stdio.h> |
/* This is to be run on a host which uses IEEE floating point. */ |
void |
ieee_test (double n) |
{ |
double result; |
floatformat_to_double (&floatformat_ieee_double_little, &n, &result); |
if ((n != result && (! isnan (n) || ! isnan (result))) |
|| (n < 0 && result >= 0) |
|| (n >= 0 && result < 0)) |
printf ("Differ(to): %.20g -> %.20g\n", n, result); |
floatformat_from_double (&floatformat_ieee_double_little, &n, &result); |
if ((n != result && (! isnan (n) || ! isnan (result))) |
|| (n < 0 && result >= 0) |
|| (n >= 0 && result < 0)) |
printf ("Differ(from): %.20g -> %.20g\n", n, result); |
#if 0 |
{ |
char exten[16]; |
floatformat_from_double (&floatformat_m68881_ext, &n, exten); |
floatformat_to_double (&floatformat_m68881_ext, exten, &result); |
if (n != result) |
printf ("Differ(to+from): %.20g -> %.20g\n", n, result); |
} |
#endif |
#if IEEE_DEBUG > 1 |
/* This is to be run on a host which uses 68881 format. */ |
{ |
long double ex = *(long double *)exten; |
if (ex != n) |
printf ("Differ(from vs. extended): %.20g\n", n); |
} |
#endif |
} |
int |
main (void) |
{ |
ieee_test (0.0); |
ieee_test (0.5); |
ieee_test (1.1); |
ieee_test (256.0); |
ieee_test (0.12345); |
ieee_test (234235.78907234); |
ieee_test (-512.0); |
ieee_test (-0.004321); |
ieee_test (1.2E-70); |
ieee_test (1.2E-316); |
ieee_test (4.9406564584124654E-324); |
ieee_test (- 4.9406564584124654E-324); |
ieee_test (- 0.0); |
ieee_test (- INFINITY); |
ieee_test (- NAN); |
ieee_test (INFINITY); |
ieee_test (NAN); |
return 0; |
} |
#endif |
/contrib/toolchain/binutils/libiberty/fnmatch.c |
---|
0,0 → 1,220 |
/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. |
NOTE: This source is derived from an old version taken from the GNU C |
Library (glibc). |
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, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#if defined (CONFIG_BROKETS) |
/* We use <config.h> instead of "config.h" so that a compilation |
using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h |
(which it would do because it found this file in $srcdir). */ |
#include <config.h> |
#else |
#include "config.h" |
#endif |
#endif |
#ifndef _GNU_SOURCE |
#define _GNU_SOURCE |
#endif |
/* This code to undef const added in libiberty. */ |
#ifndef __STDC__ |
/* This is a separate conditional since some stdc systems |
reject `defined (const)'. */ |
#ifndef const |
#define const |
#endif |
#endif |
#include <errno.h> |
#include <fnmatch.h> |
#include <safe-ctype.h> |
/* Comment out all this code if we are using the GNU C Library, and are not |
actually compiling the library itself. This code is part of the GNU C |
Library, but also included in many other GNU distributions. Compiling |
and linking in this code is a waste when using the GNU C library |
(especially if it is a shared library). Rather than having every GNU |
program understand `configure --with-gnu-libc' and omit the object files, |
it is simpler to just do this in the source for each such file. */ |
#if defined (_LIBC) || !defined (__GNU_LIBRARY__) |
#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) |
extern int errno; |
#endif |
/* Match STRING against the filename pattern PATTERN, returning zero if |
it matches, nonzero if not. */ |
int |
fnmatch (const char *pattern, const char *string, int flags) |
{ |
register const char *p = pattern, *n = string; |
register unsigned char c; |
#define FOLD(c) ((flags & FNM_CASEFOLD) ? TOLOWER (c) : (c)) |
while ((c = *p++) != '\0') |
{ |
c = FOLD (c); |
switch (c) |
{ |
case '?': |
if (*n == '\0') |
return FNM_NOMATCH; |
else if ((flags & FNM_FILE_NAME) && *n == '/') |
return FNM_NOMATCH; |
else if ((flags & FNM_PERIOD) && *n == '.' && |
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) |
return FNM_NOMATCH; |
break; |
case '\\': |
if (!(flags & FNM_NOESCAPE)) |
{ |
c = *p++; |
c = FOLD (c); |
} |
if (FOLD ((unsigned char)*n) != c) |
return FNM_NOMATCH; |
break; |
case '*': |
if ((flags & FNM_PERIOD) && *n == '.' && |
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) |
return FNM_NOMATCH; |
for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) |
if (((flags & FNM_FILE_NAME) && *n == '/') || |
(c == '?' && *n == '\0')) |
return FNM_NOMATCH; |
if (c == '\0') |
return 0; |
{ |
unsigned char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; |
c1 = FOLD (c1); |
for (--p; *n != '\0'; ++n) |
if ((c == '[' || FOLD ((unsigned char)*n) == c1) && |
fnmatch (p, n, flags & ~FNM_PERIOD) == 0) |
return 0; |
return FNM_NOMATCH; |
} |
case '[': |
{ |
/* Nonzero if the sense of the character class is inverted. */ |
register int negate; |
if (*n == '\0') |
return FNM_NOMATCH; |
if ((flags & FNM_PERIOD) && *n == '.' && |
(n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) |
return FNM_NOMATCH; |
negate = (*p == '!' || *p == '^'); |
if (negate) |
++p; |
c = *p++; |
for (;;) |
{ |
register unsigned char cstart = c, cend = c; |
if (!(flags & FNM_NOESCAPE) && c == '\\') |
cstart = cend = *p++; |
cstart = cend = FOLD (cstart); |
if (c == '\0') |
/* [ (unterminated) loses. */ |
return FNM_NOMATCH; |
c = *p++; |
c = FOLD (c); |
if ((flags & FNM_FILE_NAME) && c == '/') |
/* [/] can never match. */ |
return FNM_NOMATCH; |
if (c == '-' && *p != ']') |
{ |
cend = *p++; |
if (!(flags & FNM_NOESCAPE) && cend == '\\') |
cend = *p++; |
if (cend == '\0') |
return FNM_NOMATCH; |
cend = FOLD (cend); |
c = *p++; |
} |
if (FOLD ((unsigned char)*n) >= cstart |
&& FOLD ((unsigned char)*n) <= cend) |
goto matched; |
if (c == ']') |
break; |
} |
if (!negate) |
return FNM_NOMATCH; |
break; |
matched:; |
/* Skip the rest of the [...] that already matched. */ |
while (c != ']') |
{ |
if (c == '\0') |
/* [... (unterminated) loses. */ |
return FNM_NOMATCH; |
c = *p++; |
if (!(flags & FNM_NOESCAPE) && c == '\\') |
/* XXX 1003.2d11 is unclear if this is right. */ |
++p; |
} |
if (negate) |
return FNM_NOMATCH; |
} |
break; |
default: |
if (c != FOLD ((unsigned char)*n)) |
return FNM_NOMATCH; |
} |
++n; |
} |
if (*n == '\0') |
return 0; |
if ((flags & FNM_LEADING_DIR) && *n == '/') |
/* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ |
return 0; |
return FNM_NOMATCH; |
} |
#endif /* _LIBC or not __GNU_LIBRARY__. */ |
/contrib/toolchain/binutils/libiberty/fopen_unlocked.c |
---|
0,0 → 1,129 |
/* Implement fopen_unlocked and related functions. |
Copyright (C) 2005, 2011 Free Software Foundation, Inc. |
Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Extension void unlock_stream (FILE * @var{stream}) |
If the OS supports it, ensure that the supplied stream is setup to |
avoid any multi-threaded locking. Otherwise leave the @code{FILE} |
pointer unchanged. If the @var{stream} is @code{NULL} do nothing. |
@end deftypefn |
@deftypefn Extension void unlock_std_streams (void) |
If the OS supports it, ensure that the standard I/O streams, |
@code{stdin}, @code{stdout} and @code{stderr} are setup to avoid any |
multi-threaded locking. Otherwise do nothing. |
@end deftypefn |
@deftypefn Extension {FILE *} fopen_unlocked (const char *@var{path}, @ |
const char * @var{mode}) |
Opens and returns a @code{FILE} pointer via @code{fopen}. If the |
operating system supports it, ensure that the stream is setup to avoid |
any multi-threaded locking. Otherwise return the @code{FILE} pointer |
unchanged. |
@end deftypefn |
@deftypefn Extension {FILE *} fdopen_unlocked (int @var{fildes}, @ |
const char * @var{mode}) |
Opens and returns a @code{FILE} pointer via @code{fdopen}. If the |
operating system supports it, ensure that the stream is setup to avoid |
any multi-threaded locking. Otherwise return the @code{FILE} pointer |
unchanged. |
@end deftypefn |
@deftypefn Extension {FILE *} freopen_unlocked (const char * @var{path}, @ |
const char * @var{mode}, FILE * @var{stream}) |
Opens and returns a @code{FILE} pointer via @code{freopen}. If the |
operating system supports it, ensure that the stream is setup to avoid |
any multi-threaded locking. Otherwise return the @code{FILE} pointer |
unchanged. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <stdio.h> |
#ifdef HAVE_STDIO_EXT_H |
#include <stdio_ext.h> |
#endif |
#include "libiberty.h" |
/* This is an inline helper function to consolidate attempts to unlock |
a stream. */ |
static inline void |
unlock_1 (FILE *const fp ATTRIBUTE_UNUSED) |
{ |
#if defined(HAVE___FSETLOCKING) && defined(FSETLOCKING_BYCALLER) |
if (fp) |
__fsetlocking (fp, FSETLOCKING_BYCALLER); |
#endif |
} |
void |
unlock_stream (FILE *fp) |
{ |
unlock_1 (fp); |
} |
void |
unlock_std_streams (void) |
{ |
unlock_1 (stdin); |
unlock_1 (stdout); |
unlock_1 (stderr); |
} |
FILE * |
fopen_unlocked (const char *path, const char *mode) |
{ |
FILE *const fp = fopen (path, mode); |
unlock_1 (fp); |
return fp; |
} |
FILE * |
fdopen_unlocked (int fildes, const char *mode) |
{ |
FILE *const fp = fdopen (fildes, mode); |
unlock_1 (fp); |
return fp; |
} |
FILE * |
freopen_unlocked (const char *path, const char *mode, FILE *stream) |
{ |
FILE *const fp = freopen (path, mode, stream); |
unlock_1 (fp); |
return fp; |
} |
/contrib/toolchain/binutils/libiberty/getopt.c |
---|
0,0 → 1,1044 |
/* Getopt for GNU. |
NOTE: getopt is now part of the C library, so if you don't know what |
"Keep this file name-space clean" means, talk to drepper@gnu.org |
before changing it! |
Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, |
1996, 1997, 1998, 2005 Free Software Foundation, Inc. |
NOTE: This source is derived from an old version taken from the GNU C |
Library (glibc). |
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, |
USA. */ |
/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. |
Ditto for AIX 3.2 and <stdlib.h>. */ |
#ifndef _NO_PROTO |
# define _NO_PROTO |
#endif |
#ifdef HAVE_CONFIG_H |
# include <config.h> |
#endif |
#if !defined __STDC__ || !__STDC__ |
/* This is a separate conditional since some stdc systems |
reject `defined (const)'. */ |
# ifndef const |
# define const |
# endif |
#endif |
#include "ansidecl.h" |
#include <stdio.h> |
/* Comment out all this code if we are using the GNU C Library, and are not |
actually compiling the library itself. This code is part of the GNU C |
Library, but also included in many other GNU distributions. Compiling |
and linking in this code is a waste when using the GNU C library |
(especially if it is a shared library). Rather than having every GNU |
program understand `configure --with-gnu-libc' and omit the object files, |
it is simpler to just do this in the source for each such file. */ |
#define GETOPT_INTERFACE_VERSION 2 |
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 |
# include <gnu-versions.h> |
# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION |
# define ELIDE_CODE |
# endif |
#endif |
#ifndef ELIDE_CODE |
/* This needs to come after some library #include |
to get __GNU_LIBRARY__ defined. */ |
#ifdef __GNU_LIBRARY__ |
/* Don't include stdlib.h for non-GNU C libraries because some of them |
contain conflicting prototypes for getopt. */ |
# include <stdlib.h> |
# include <unistd.h> |
#endif /* GNU C library. */ |
#ifdef VMS |
# include <unixlib.h> |
# if HAVE_STRING_H - 0 |
# include <string.h> |
# endif |
#endif |
# define _(msgid) (msgid) |
/* This version of `getopt' appears to the caller like standard Unix `getopt' |
but it behaves differently for the user, since it allows the user |
to intersperse the options with the other arguments. |
As `getopt' works, it permutes the elements of ARGV so that, |
when it is done, all the options precede everything else. Thus |
all application programs are extended to handle flexible argument order. |
Setting the environment variable POSIXLY_CORRECT disables permutation. |
Then the behavior is completely standard. |
GNU application programs can use a third alternative mode in which |
they can distinguish the relative order of options and other arguments. */ |
#include "getopt.h" |
/* For communication from `getopt' to the caller. |
When `getopt' finds an option that takes an argument, |
the argument value is returned here. |
Also, when `ordering' is RETURN_IN_ORDER, |
each non-option ARGV-element is returned here. */ |
char *optarg = NULL; |
/* Index in ARGV of the next element to be scanned. |
This is used for communication to and from the caller |
and for communication between successive calls to `getopt'. |
On entry to `getopt', zero means this is the first call; initialize. |
When `getopt' returns -1, this is the index of the first of the |
non-option elements that the caller should itself scan. |
Otherwise, `optind' communicates from one call to the next |
how much of ARGV has been scanned so far. */ |
/* 1003.2 says this must be 1 before any call. */ |
int optind = 1; |
/* Formerly, initialization of getopt depended on optind==0, which |
causes problems with re-calling getopt as programs generally don't |
know that. */ |
int __getopt_initialized = 0; |
/* The next char to be scanned in the option-element |
in which the last option character we returned was found. |
This allows us to pick up the scan where we left off. |
If this is zero, or a null string, it means resume the scan |
by advancing to the next ARGV-element. */ |
static char *nextchar; |
/* Callers store zero here to inhibit the error message |
for unrecognized options. */ |
int opterr = 1; |
/* Set to an option character which was unrecognized. |
This must be initialized on some systems to avoid linking in the |
system's own getopt implementation. */ |
int optopt = '?'; |
/* Describe how to deal with options that follow non-option ARGV-elements. |
If the caller did not specify anything, |
the default is REQUIRE_ORDER if the environment variable |
POSIXLY_CORRECT is defined, PERMUTE otherwise. |
REQUIRE_ORDER means don't recognize them as options; |
stop option processing when the first non-option is seen. |
This is what Unix does. |
This mode of operation is selected by either setting the environment |
variable POSIXLY_CORRECT, or using `+' as the first character |
of the list of option characters. |
PERMUTE is the default. We permute the contents of ARGV as we scan, |
so that eventually all the non-options are at the end. This allows options |
to be given in any order, even with programs that were not written to |
expect this. |
RETURN_IN_ORDER is an option available to programs that were written |
to expect options and other ARGV-elements in any order and that care about |
the ordering of the two. We describe each non-option ARGV-element |
as if it were the argument of an option with character code 1. |
Using `-' as the first character of the list of option characters |
selects this mode of operation. |
The special argument `--' forces an end of option-scanning regardless |
of the value of `ordering'. In the case of RETURN_IN_ORDER, only |
`--' can cause `getopt' to return -1 with `optind' != ARGC. */ |
static enum |
{ |
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER |
} ordering; |
/* Value of POSIXLY_CORRECT environment variable. */ |
static char *posixly_correct; |
#ifdef __GNU_LIBRARY__ |
/* We want to avoid inclusion of string.h with non-GNU libraries |
because there are many ways it can cause trouble. |
On some systems, it contains special magic macros that don't work |
in GCC. */ |
# include <string.h> |
# define my_index strchr |
#else |
# if HAVE_STRING_H |
# include <string.h> |
# else |
# if HAVE_STRINGS_H |
# include <strings.h> |
# endif |
# endif |
/* Avoid depending on library functions or files |
whose names are inconsistent. */ |
#if HAVE_STDLIB_H && HAVE_DECL_GETENV |
# include <stdlib.h> |
#elif !defined(getenv) |
# ifdef __cplusplus |
extern "C" { |
# endif /* __cplusplus */ |
extern char *getenv (const char *); |
# ifdef __cplusplus |
} |
# endif /* __cplusplus */ |
#endif |
static char * |
my_index (const char *str, int chr) |
{ |
while (*str) |
{ |
if (*str == chr) |
return (char *) str; |
str++; |
} |
return 0; |
} |
/* If using GCC, we can safely declare strlen this way. |
If not using GCC, it is ok not to declare it. */ |
#ifdef __GNUC__ |
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. |
That was relevant to code that was here before. */ |
# if (!defined __STDC__ || !__STDC__) && !defined strlen |
/* gcc with -traditional declares the built-in strlen to return int, |
and has done so at least since version 2.4.5. -- rms. */ |
extern int strlen (const char *); |
# endif /* not __STDC__ */ |
#endif /* __GNUC__ */ |
#endif /* not __GNU_LIBRARY__ */ |
/* Handle permutation of arguments. */ |
/* Describe the part of ARGV that contains non-options that have |
been skipped. `first_nonopt' is the index in ARGV of the first of them; |
`last_nonopt' is the index after the last of them. */ |
static int first_nonopt; |
static int last_nonopt; |
#ifdef _LIBC |
/* Bash 2.0 gives us an environment variable containing flags |
indicating ARGV elements that should not be considered arguments. */ |
/* Defined in getopt_init.c */ |
extern char *__getopt_nonoption_flags; |
static int nonoption_flags_max_len; |
static int nonoption_flags_len; |
static int original_argc; |
static char *const *original_argv; |
/* Make sure the environment variable bash 2.0 puts in the environment |
is valid for the getopt call we must make sure that the ARGV passed |
to getopt is that one passed to the process. */ |
static void |
__attribute__ ((unused)) |
store_args_and_env (int argc, char *const *argv) |
{ |
/* XXX This is no good solution. We should rather copy the args so |
that we can compare them later. But we must not use malloc(3). */ |
original_argc = argc; |
original_argv = argv; |
} |
# ifdef text_set_element |
text_set_element (__libc_subinit, store_args_and_env); |
# endif /* text_set_element */ |
# define SWAP_FLAGS(ch1, ch2) \ |
if (nonoption_flags_len > 0) \ |
{ \ |
char __tmp = __getopt_nonoption_flags[ch1]; \ |
__getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \ |
__getopt_nonoption_flags[ch2] = __tmp; \ |
} |
#else /* !_LIBC */ |
# define SWAP_FLAGS(ch1, ch2) |
#endif /* _LIBC */ |
/* Exchange two adjacent subsequences of ARGV. |
One subsequence is elements [first_nonopt,last_nonopt) |
which contains all the non-options that have been skipped so far. |
The other is elements [last_nonopt,optind), which contains all |
the options processed since those non-options were skipped. |
`first_nonopt' and `last_nonopt' are relocated so that they describe |
the new indices of the non-options in ARGV after they are moved. */ |
#if defined __STDC__ && __STDC__ |
static void exchange (char **); |
#endif |
static void |
exchange (char **argv) |
{ |
int bottom = first_nonopt; |
int middle = last_nonopt; |
int top = optind; |
char *tem; |
/* Exchange the shorter segment with the far end of the longer segment. |
That puts the shorter segment into the right place. |
It leaves the longer segment in the right place overall, |
but it consists of two parts that need to be swapped next. */ |
#ifdef _LIBC |
/* First make sure the handling of the `__getopt_nonoption_flags' |
string can work normally. Our top argument must be in the range |
of the string. */ |
if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len) |
{ |
/* We must extend the array. The user plays games with us and |
presents new arguments. */ |
char *new_str = (char *) malloc (top + 1); |
if (new_str == NULL) |
nonoption_flags_len = nonoption_flags_max_len = 0; |
else |
{ |
memset (mempcpy (new_str, __getopt_nonoption_flags, |
nonoption_flags_max_len), |
'\0', top + 1 - nonoption_flags_max_len); |
nonoption_flags_max_len = top + 1; |
__getopt_nonoption_flags = new_str; |
} |
} |
#endif |
while (top > middle && middle > bottom) |
{ |
if (top - middle > middle - bottom) |
{ |
/* Bottom segment is the short one. */ |
int len = middle - bottom; |
register int i; |
/* Swap it with the top part of the top segment. */ |
for (i = 0; i < len; i++) |
{ |
tem = argv[bottom + i]; |
argv[bottom + i] = argv[top - (middle - bottom) + i]; |
argv[top - (middle - bottom) + i] = tem; |
SWAP_FLAGS (bottom + i, top - (middle - bottom) + i); |
} |
/* Exclude the moved bottom segment from further swapping. */ |
top -= len; |
} |
else |
{ |
/* Top segment is the short one. */ |
int len = top - middle; |
register int i; |
/* Swap it with the bottom part of the bottom segment. */ |
for (i = 0; i < len; i++) |
{ |
tem = argv[bottom + i]; |
argv[bottom + i] = argv[middle + i]; |
argv[middle + i] = tem; |
SWAP_FLAGS (bottom + i, middle + i); |
} |
/* Exclude the moved top segment from further swapping. */ |
bottom += len; |
} |
} |
/* Update records for the slots the non-options now occupy. */ |
first_nonopt += (optind - last_nonopt); |
last_nonopt = optind; |
} |
/* Initialize the internal data when the first call is made. */ |
#if defined __STDC__ && __STDC__ |
static const char *_getopt_initialize (int, char *const *, const char *); |
#endif |
static const char * |
_getopt_initialize (int argc ATTRIBUTE_UNUSED, |
char *const *argv ATTRIBUTE_UNUSED, |
const char *optstring) |
{ |
/* Start processing options with ARGV-element 1 (since ARGV-element 0 |
is the program name); the sequence of previously skipped |
non-option ARGV-elements is empty. */ |
first_nonopt = last_nonopt = optind; |
nextchar = NULL; |
posixly_correct = getenv ("POSIXLY_CORRECT"); |
/* Determine how to handle the ordering of options and nonoptions. */ |
if (optstring[0] == '-') |
{ |
ordering = RETURN_IN_ORDER; |
++optstring; |
} |
else if (optstring[0] == '+') |
{ |
ordering = REQUIRE_ORDER; |
++optstring; |
} |
else if (posixly_correct != NULL) |
ordering = REQUIRE_ORDER; |
else |
ordering = PERMUTE; |
#ifdef _LIBC |
if (posixly_correct == NULL |
&& argc == original_argc && argv == original_argv) |
{ |
if (nonoption_flags_max_len == 0) |
{ |
if (__getopt_nonoption_flags == NULL |
|| __getopt_nonoption_flags[0] == '\0') |
nonoption_flags_max_len = -1; |
else |
{ |
const char *orig_str = __getopt_nonoption_flags; |
int len = nonoption_flags_max_len = strlen (orig_str); |
if (nonoption_flags_max_len < argc) |
nonoption_flags_max_len = argc; |
__getopt_nonoption_flags = |
(char *) malloc (nonoption_flags_max_len); |
if (__getopt_nonoption_flags == NULL) |
nonoption_flags_max_len = -1; |
else |
memset (mempcpy (__getopt_nonoption_flags, orig_str, len), |
'\0', nonoption_flags_max_len - len); |
} |
} |
nonoption_flags_len = nonoption_flags_max_len; |
} |
else |
nonoption_flags_len = 0; |
#endif |
return optstring; |
} |
/* Scan elements of ARGV (whose length is ARGC) for option characters |
given in OPTSTRING. |
If an element of ARGV starts with '-', and is not exactly "-" or "--", |
then it is an option element. The characters of this element |
(aside from the initial '-') are option characters. If `getopt' |
is called repeatedly, it returns successively each of the option characters |
from each of the option elements. |
If `getopt' finds another option character, it returns that character, |
updating `optind' and `nextchar' so that the next call to `getopt' can |
resume the scan with the following option character or ARGV-element. |
If there are no more option characters, `getopt' returns -1. |
Then `optind' is the index in ARGV of the first ARGV-element |
that is not an option. (The ARGV-elements have been permuted |
so that those that are not options now come last.) |
OPTSTRING is a string containing the legitimate option characters. |
If an option character is seen that is not listed in OPTSTRING, |
return '?' after printing an error message. If you set `opterr' to |
zero, the error message is suppressed but we still return '?'. |
If a char in OPTSTRING is followed by a colon, that means it wants an arg, |
so the following text in the same ARGV-element, or the text of the following |
ARGV-element, is returned in `optarg'. Two colons mean an option that |
wants an optional arg; if there is text in the current ARGV-element, |
it is returned in `optarg', otherwise `optarg' is set to zero. |
If OPTSTRING starts with `-' or `+', it requests different methods of |
handling the non-option ARGV-elements. |
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above. |
Long-named options begin with `--' instead of `-'. |
Their names may be abbreviated as long as the abbreviation is unique |
or is an exact match for some defined option. If they have an |
argument, it follows the option name in the same ARGV-element, separated |
from the option name by a `=', or else the in next ARGV-element. |
When `getopt' finds a long-named option, it returns 0 if that option's |
`flag' field is nonzero, the value of the option's `val' field |
if the `flag' field is zero. |
The elements of ARGV aren't really const, because we permute them. |
But we pretend they're const in the prototype to be compatible |
with other systems. |
LONGOPTS is a vector of `struct option' terminated by an |
element containing a name which is zero. |
LONGIND returns the index in LONGOPT of the long-named option found. |
It is only valid when a long-named option has been found by the most |
recent call. |
If LONG_ONLY is nonzero, '-' as well as '--' can introduce |
long-named options. */ |
int |
_getopt_internal (int argc, char *const *argv, const char *optstring, |
const struct option *longopts, |
int *longind, int long_only) |
{ |
optarg = NULL; |
if (optind == 0 || !__getopt_initialized) |
{ |
if (optind == 0) |
optind = 1; /* Don't scan ARGV[0], the program name. */ |
optstring = _getopt_initialize (argc, argv, optstring); |
__getopt_initialized = 1; |
} |
/* Test whether ARGV[optind] points to a non-option argument. |
Either it does not have option syntax, or there is an environment flag |
from the shell indicating it is not an option. The later information |
is only used when the used in the GNU libc. */ |
#ifdef _LIBC |
# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \ |
|| (optind < nonoption_flags_len \ |
&& __getopt_nonoption_flags[optind] == '1')) |
#else |
# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0') |
#endif |
if (nextchar == NULL || *nextchar == '\0') |
{ |
/* Advance to the next ARGV-element. */ |
/* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been |
moved back by the user (who may also have changed the arguments). */ |
if (last_nonopt > optind) |
last_nonopt = optind; |
if (first_nonopt > optind) |
first_nonopt = optind; |
if (ordering == PERMUTE) |
{ |
/* If we have just processed some options following some non-options, |
exchange them so that the options come first. */ |
if (first_nonopt != last_nonopt && last_nonopt != optind) |
exchange ((char **) argv); |
else if (last_nonopt != optind) |
first_nonopt = optind; |
/* Skip any additional non-options |
and extend the range of non-options previously skipped. */ |
while (optind < argc && NONOPTION_P) |
optind++; |
last_nonopt = optind; |
} |
/* The special ARGV-element `--' means premature end of options. |
Skip it like a null option, |
then exchange with previous non-options as if it were an option, |
then skip everything else like a non-option. */ |
if (optind != argc && !strcmp (argv[optind], "--")) |
{ |
optind++; |
if (first_nonopt != last_nonopt && last_nonopt != optind) |
exchange ((char **) argv); |
else if (first_nonopt == last_nonopt) |
first_nonopt = optind; |
last_nonopt = argc; |
optind = argc; |
} |
/* If we have done all the ARGV-elements, stop the scan |
and back over any non-options that we skipped and permuted. */ |
if (optind == argc) |
{ |
/* Set the next-arg-index to point at the non-options |
that we previously skipped, so the caller will digest them. */ |
if (first_nonopt != last_nonopt) |
optind = first_nonopt; |
return -1; |
} |
/* If we have come to a non-option and did not permute it, |
either stop the scan or describe it to the caller and pass it by. */ |
if (NONOPTION_P) |
{ |
if (ordering == REQUIRE_ORDER) |
return -1; |
optarg = argv[optind++]; |
return 1; |
} |
/* We have found another option-ARGV-element. |
Skip the initial punctuation. */ |
nextchar = (argv[optind] + 1 |
+ (longopts != NULL && argv[optind][1] == '-')); |
} |
/* Decode the current option-ARGV-element. */ |
/* Check whether the ARGV-element is a long option. |
If long_only and the ARGV-element has the form "-f", where f is |
a valid short option, don't consider it an abbreviated form of |
a long option that starts with f. Otherwise there would be no |
way to give the -f short option. |
On the other hand, if there's a long option "fubar" and |
the ARGV-element is "-fu", do consider that an abbreviation of |
the long option, just like "--fu", and not "-f" with arg "u". |
This distinction seems to be the most useful approach. */ |
if (longopts != NULL |
&& (argv[optind][1] == '-' |
|| (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1]))))) |
{ |
char *nameend; |
const struct option *p; |
const struct option *pfound = NULL; |
int exact = 0; |
int ambig = 0; |
int indfound = -1; |
int option_index; |
for (nameend = nextchar; *nameend && *nameend != '='; nameend++) |
/* Do nothing. */ ; |
/* Test all long options for either exact match |
or abbreviated matches. */ |
for (p = longopts, option_index = 0; p->name; p++, option_index++) |
if (!strncmp (p->name, nextchar, nameend - nextchar)) |
{ |
if ((unsigned int) (nameend - nextchar) |
== (unsigned int) strlen (p->name)) |
{ |
/* Exact match found. */ |
pfound = p; |
indfound = option_index; |
exact = 1; |
break; |
} |
else if (pfound == NULL) |
{ |
/* First nonexact match found. */ |
pfound = p; |
indfound = option_index; |
} |
else |
/* Second or later nonexact match found. */ |
ambig = 1; |
} |
if (ambig && !exact) |
{ |
if (opterr) |
fprintf (stderr, _("%s: option `%s' is ambiguous\n"), |
argv[0], argv[optind]); |
nextchar += strlen (nextchar); |
optind++; |
optopt = 0; |
return '?'; |
} |
if (pfound != NULL) |
{ |
option_index = indfound; |
optind++; |
if (*nameend) |
{ |
/* Don't test has_arg with >, because some C compilers don't |
allow it to be used on enums. */ |
if (pfound->has_arg) |
optarg = nameend + 1; |
else |
{ |
if (opterr) |
{ |
if (argv[optind - 1][1] == '-') |
/* --option */ |
fprintf (stderr, |
_("%s: option `--%s' doesn't allow an argument\n"), |
argv[0], pfound->name); |
else |
/* +option or -option */ |
fprintf (stderr, |
_("%s: option `%c%s' doesn't allow an argument\n"), |
argv[0], argv[optind - 1][0], pfound->name); |
nextchar += strlen (nextchar); |
optopt = pfound->val; |
return '?'; |
} |
} |
} |
else if (pfound->has_arg == 1) |
{ |
if (optind < argc) |
optarg = argv[optind++]; |
else |
{ |
if (opterr) |
fprintf (stderr, |
_("%s: option `%s' requires an argument\n"), |
argv[0], argv[optind - 1]); |
nextchar += strlen (nextchar); |
optopt = pfound->val; |
return optstring[0] == ':' ? ':' : '?'; |
} |
} |
nextchar += strlen (nextchar); |
if (longind != NULL) |
*longind = option_index; |
if (pfound->flag) |
{ |
*(pfound->flag) = pfound->val; |
return 0; |
} |
return pfound->val; |
} |
/* Can't find it as a long option. If this is not getopt_long_only, |
or the option starts with '--' or is not a valid short |
option, then it's an error. |
Otherwise interpret it as a short option. */ |
if (!long_only || argv[optind][1] == '-' |
|| my_index (optstring, *nextchar) == NULL) |
{ |
if (opterr) |
{ |
if (argv[optind][1] == '-') |
/* --option */ |
fprintf (stderr, _("%s: unrecognized option `--%s'\n"), |
argv[0], nextchar); |
else |
/* +option or -option */ |
fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), |
argv[0], argv[optind][0], nextchar); |
} |
nextchar = (char *) ""; |
optind++; |
optopt = 0; |
return '?'; |
} |
} |
/* Look at and handle the next short option-character. */ |
{ |
char c = *nextchar++; |
char *temp = my_index (optstring, c); |
/* Increment `optind' when we start to process its last character. */ |
if (*nextchar == '\0') |
++optind; |
if (temp == NULL || c == ':') |
{ |
if (opterr) |
{ |
if (posixly_correct) |
/* 1003.2 specifies the format of this message. */ |
fprintf (stderr, _("%s: illegal option -- %c\n"), |
argv[0], c); |
else |
fprintf (stderr, _("%s: invalid option -- %c\n"), |
argv[0], c); |
} |
optopt = c; |
return '?'; |
} |
/* Convenience. Treat POSIX -W foo same as long option --foo */ |
if (temp[0] == 'W' && temp[1] == ';') |
{ |
char *nameend; |
const struct option *p; |
const struct option *pfound = NULL; |
int exact = 0; |
int ambig = 0; |
int indfound = 0; |
int option_index; |
/* This is an option that requires an argument. */ |
if (*nextchar != '\0') |
{ |
optarg = nextchar; |
/* If we end this ARGV-element by taking the rest as an arg, |
we must advance to the next element now. */ |
optind++; |
} |
else if (optind == argc) |
{ |
if (opterr) |
{ |
/* 1003.2 specifies the format of this message. */ |
fprintf (stderr, _("%s: option requires an argument -- %c\n"), |
argv[0], c); |
} |
optopt = c; |
if (optstring[0] == ':') |
c = ':'; |
else |
c = '?'; |
return c; |
} |
else |
/* We already incremented `optind' once; |
increment it again when taking next ARGV-elt as argument. */ |
optarg = argv[optind++]; |
/* optarg is now the argument, see if it's in the |
table of longopts. */ |
for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++) |
/* Do nothing. */ ; |
/* Test all long options for either exact match |
or abbreviated matches. */ |
for (p = longopts, option_index = 0; p->name; p++, option_index++) |
if (!strncmp (p->name, nextchar, nameend - nextchar)) |
{ |
if ((unsigned int) (nameend - nextchar) == strlen (p->name)) |
{ |
/* Exact match found. */ |
pfound = p; |
indfound = option_index; |
exact = 1; |
break; |
} |
else if (pfound == NULL) |
{ |
/* First nonexact match found. */ |
pfound = p; |
indfound = option_index; |
} |
else |
/* Second or later nonexact match found. */ |
ambig = 1; |
} |
if (ambig && !exact) |
{ |
if (opterr) |
fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"), |
argv[0], argv[optind]); |
nextchar += strlen (nextchar); |
optind++; |
return '?'; |
} |
if (pfound != NULL) |
{ |
option_index = indfound; |
if (*nameend) |
{ |
/* Don't test has_arg with >, because some C compilers don't |
allow it to be used on enums. */ |
if (pfound->has_arg) |
optarg = nameend + 1; |
else |
{ |
if (opterr) |
fprintf (stderr, _("\ |
%s: option `-W %s' doesn't allow an argument\n"), |
argv[0], pfound->name); |
nextchar += strlen (nextchar); |
return '?'; |
} |
} |
else if (pfound->has_arg == 1) |
{ |
if (optind < argc) |
optarg = argv[optind++]; |
else |
{ |
if (opterr) |
fprintf (stderr, |
_("%s: option `%s' requires an argument\n"), |
argv[0], argv[optind - 1]); |
nextchar += strlen (nextchar); |
return optstring[0] == ':' ? ':' : '?'; |
} |
} |
nextchar += strlen (nextchar); |
if (longind != NULL) |
*longind = option_index; |
if (pfound->flag) |
{ |
*(pfound->flag) = pfound->val; |
return 0; |
} |
return pfound->val; |
} |
nextchar = NULL; |
return 'W'; /* Let the application handle it. */ |
} |
if (temp[1] == ':') |
{ |
if (temp[2] == ':') |
{ |
/* This is an option that accepts an argument optionally. */ |
if (*nextchar != '\0') |
{ |
optarg = nextchar; |
optind++; |
} |
else |
optarg = NULL; |
nextchar = NULL; |
} |
else |
{ |
/* This is an option that requires an argument. */ |
if (*nextchar != '\0') |
{ |
optarg = nextchar; |
/* If we end this ARGV-element by taking the rest as an arg, |
we must advance to the next element now. */ |
optind++; |
} |
else if (optind == argc) |
{ |
if (opterr) |
{ |
/* 1003.2 specifies the format of this message. */ |
fprintf (stderr, |
_("%s: option requires an argument -- %c\n"), |
argv[0], c); |
} |
optopt = c; |
if (optstring[0] == ':') |
c = ':'; |
else |
c = '?'; |
} |
else |
/* We already incremented `optind' once; |
increment it again when taking next ARGV-elt as argument. */ |
optarg = argv[optind++]; |
nextchar = NULL; |
} |
} |
return c; |
} |
} |
int |
getopt (int argc, char *const *argv, const char *optstring) |
{ |
return _getopt_internal (argc, argv, optstring, |
(const struct option *) 0, |
(int *) 0, |
0); |
} |
#endif /* Not ELIDE_CODE. */ |
#ifdef TEST |
/* Compile with -DTEST to make an executable for use in testing |
the above definition of `getopt'. */ |
int |
main (int argc, char **argv) |
{ |
int c; |
int digit_optind = 0; |
while (1) |
{ |
int this_option_optind = optind ? optind : 1; |
c = getopt (argc, argv, "abc:d:0123456789"); |
if (c == -1) |
break; |
switch (c) |
{ |
case '0': |
case '1': |
case '2': |
case '3': |
case '4': |
case '5': |
case '6': |
case '7': |
case '8': |
case '9': |
if (digit_optind != 0 && digit_optind != this_option_optind) |
printf ("digits occur in two different argv-elements.\n"); |
digit_optind = this_option_optind; |
printf ("option %c\n", c); |
break; |
case 'a': |
printf ("option a\n"); |
break; |
case 'b': |
printf ("option b\n"); |
break; |
case 'c': |
printf ("option c with value `%s'\n", optarg); |
break; |
case '?': |
break; |
default: |
printf ("?? getopt returned character code 0%o ??\n", c); |
} |
} |
if (optind < argc) |
{ |
printf ("non-option ARGV-elements: "); |
while (optind < argc) |
printf ("%s ", argv[optind++]); |
printf ("\n"); |
} |
exit (0); |
} |
#endif /* TEST */ |
/contrib/toolchain/binutils/libiberty/getopt1.c |
---|
0,0 → 1,180 |
/* getopt_long and getopt_long_only entry points for GNU getopt. |
Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98,2005 |
Free Software Foundation, Inc. |
NOTE: This source is derived from an old version taken from the GNU C |
Library (glibc). |
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, |
USA. */ |
#ifdef HAVE_CONFIG_H |
#include <config.h> |
#endif |
#if !defined __STDC__ || !__STDC__ |
/* This is a separate conditional since some stdc systems |
reject `defined (const)'. */ |
#ifndef const |
#define const |
#endif |
#endif |
#include <stdio.h> |
#include "getopt.h" |
/* Comment out all this code if we are using the GNU C Library, and are not |
actually compiling the library itself. This code is part of the GNU C |
Library, but also included in many other GNU distributions. Compiling |
and linking in this code is a waste when using the GNU C library |
(especially if it is a shared library). Rather than having every GNU |
program understand `configure --with-gnu-libc' and omit the object files, |
it is simpler to just do this in the source for each such file. */ |
#define GETOPT_INTERFACE_VERSION 2 |
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2 |
#include <gnu-versions.h> |
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION |
#define ELIDE_CODE |
#endif |
#endif |
#ifndef ELIDE_CODE |
/* This needs to come after some library #include |
to get __GNU_LIBRARY__ defined. */ |
#ifdef __GNU_LIBRARY__ |
#include <stdlib.h> |
#endif |
#ifndef NULL |
#define NULL 0 |
#endif |
int |
getopt_long (int argc, char *const *argv, const char *options, |
const struct option *long_options, int *opt_index) |
{ |
return _getopt_internal (argc, argv, options, long_options, opt_index, 0); |
} |
/* Like getopt_long, but '-' as well as '--' can indicate a long option. |
If an option that starts with '-' (not '--') doesn't match a long option, |
but does match a short option, it is parsed as a short option |
instead. */ |
int |
getopt_long_only (int argc, char *const *argv, const char *options, |
const struct option *long_options, int *opt_index) |
{ |
return _getopt_internal (argc, argv, options, long_options, opt_index, 1); |
} |
#endif /* Not ELIDE_CODE. */ |
#ifdef TEST |
#include <stdio.h> |
int |
main (int argc, char **argv) |
{ |
int c; |
int digit_optind = 0; |
while (1) |
{ |
int this_option_optind = optind ? optind : 1; |
int option_index = 0; |
static struct option long_options[] = |
{ |
{"add", 1, 0, 0}, |
{"append", 0, 0, 0}, |
{"delete", 1, 0, 0}, |
{"verbose", 0, 0, 0}, |
{"create", 0, 0, 0}, |
{"file", 1, 0, 0}, |
{0, 0, 0, 0} |
}; |
c = getopt_long (argc, argv, "abc:d:0123456789", |
long_options, &option_index); |
if (c == -1) |
break; |
switch (c) |
{ |
case 0: |
printf ("option %s", long_options[option_index].name); |
if (optarg) |
printf (" with arg %s", optarg); |
printf ("\n"); |
break; |
case '0': |
case '1': |
case '2': |
case '3': |
case '4': |
case '5': |
case '6': |
case '7': |
case '8': |
case '9': |
if (digit_optind != 0 && digit_optind != this_option_optind) |
printf ("digits occur in two different argv-elements.\n"); |
digit_optind = this_option_optind; |
printf ("option %c\n", c); |
break; |
case 'a': |
printf ("option a\n"); |
break; |
case 'b': |
printf ("option b\n"); |
break; |
case 'c': |
printf ("option c with value `%s'\n", optarg); |
break; |
case 'd': |
printf ("option d with value `%s'\n", optarg); |
break; |
case '?': |
break; |
default: |
printf ("?? getopt returned character code 0%o ??\n", c); |
} |
} |
if (optind < argc) |
{ |
printf ("non-option ARGV-elements: "); |
while (optind < argc) |
printf ("%s ", argv[optind++]); |
printf ("\n"); |
} |
exit (0); |
} |
#endif /* TEST */ |
/contrib/toolchain/binutils/libiberty/getpwd.c |
---|
0,0 → 1,128 |
/* getpwd.c - get the working directory */ |
/* |
@deftypefn Supplemental char* getpwd (void) |
Returns the current working directory. This implementation caches the |
result on the assumption that the process will not call @code{chdir} |
between calls to @code{getpwd}. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <sys/types.h> |
#include <errno.h> |
#ifndef errno |
extern int errno; |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
#ifdef HAVE_SYS_PARAM_H |
#include <sys/param.h> |
#endif |
#if HAVE_SYS_STAT_H |
#include <sys/stat.h> |
#endif |
#if HAVE_LIMITS_H |
#include <limits.h> |
#endif |
#include "libiberty.h" |
/* Virtually every UN*X system now in common use (except for pre-4.3-tahoe |
BSD systems) now provides getcwd as called for by POSIX. Allow for |
the few exceptions to the general rule here. */ |
#if !defined(HAVE_GETCWD) && defined(HAVE_GETWD) |
/* Prototype in case the system headers doesn't provide it. */ |
extern char *getwd (); |
#define getcwd(buf,len) getwd(buf) |
#endif |
#ifdef MAXPATHLEN |
#define GUESSPATHLEN (MAXPATHLEN + 1) |
#else |
#define GUESSPATHLEN 100 |
#endif |
#if !(defined (VMS) || (defined(_WIN32) && !defined(__CYGWIN__))) |
/* Get the working directory. Use the PWD environment variable if it's |
set correctly, since this is faster and gives more uniform answers |
to the user. Yield the working directory if successful; otherwise, |
yield 0 and set errno. */ |
char * |
getpwd (void) |
{ |
static char *pwd; |
static int failure_errno; |
char *p = pwd; |
size_t s; |
struct stat dotstat, pwdstat; |
if (!p && !(errno = failure_errno)) |
{ |
if (! ((p = getenv ("PWD")) != 0 |
&& *p == '/' |
&& stat (p, &pwdstat) == 0 |
&& stat (".", &dotstat) == 0 |
&& dotstat.st_ino == pwdstat.st_ino |
&& dotstat.st_dev == pwdstat.st_dev)) |
/* The shortcut didn't work. Try the slow, ``sure'' way. */ |
for (s = GUESSPATHLEN; !getcwd (p = XNEWVEC (char, s), s); s *= 2) |
{ |
int e = errno; |
free (p); |
#ifdef ERANGE |
if (e != ERANGE) |
#endif |
{ |
errno = failure_errno = e; |
p = 0; |
break; |
} |
} |
/* Cache the result. This assumes that the program does |
not invoke chdir between calls to getpwd. */ |
pwd = p; |
} |
return p; |
} |
#else /* VMS || _WIN32 && !__CYGWIN__ */ |
#ifndef MAXPATHLEN |
#define MAXPATHLEN 255 |
#endif |
char * |
getpwd (void) |
{ |
static char *pwd = 0; |
if (!pwd) |
pwd = getcwd (XNEWVEC (char, MAXPATHLEN + 1), MAXPATHLEN + 1 |
#ifdef VMS |
, 0 |
#endif |
); |
return pwd; |
} |
#endif /* VMS || _WIN32 && !__CYGWIN__ */ |
/contrib/toolchain/binutils/libiberty/getruntime.c |
---|
0,0 → 1,116 |
/* Return time used so far, in microseconds. |
Copyright (C) 1994, 1999, 2002 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#include "config.h" |
#include "ansidecl.h" |
#include "libiberty.h" |
/* On some systems (such as WindISS), you must include <sys/types.h> |
to get the definition of "time_t" before you include <time.h>. */ |
#include <sys/types.h> |
/* There are several ways to get elapsed execution time; unfortunately no |
single way is available for all host systems, nor are there reliable |
ways to find out which way is correct for a given host. */ |
#ifdef TIME_WITH_SYS_TIME |
# include <sys/time.h> |
# include <time.h> |
#else |
# if HAVE_SYS_TIME_H |
# include <sys/time.h> |
# else |
# ifdef HAVE_TIME_H |
# include <time.h> |
# endif |
# endif |
#endif |
#if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H) |
#include <sys/resource.h> |
#endif |
#ifdef HAVE_TIMES |
#ifdef HAVE_SYS_PARAM_H |
#include <sys/param.h> |
#endif |
#include <sys/times.h> |
#endif |
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
/* This is a fallback; if wrong, it will likely make obviously wrong |
results. */ |
#ifndef CLOCKS_PER_SEC |
#define CLOCKS_PER_SEC 1 |
#endif |
#ifdef _SC_CLK_TCK |
#define GNU_HZ sysconf(_SC_CLK_TCK) |
#else |
#ifdef HZ |
#define GNU_HZ HZ |
#else |
#ifdef CLOCKS_PER_SEC |
#define GNU_HZ CLOCKS_PER_SEC |
#endif |
#endif |
#endif |
/* |
@deftypefn Replacement long get_run_time (void) |
Returns the time used so far, in microseconds. If possible, this is |
the time used by this process, else it is the elapsed time since the |
process started. |
@end deftypefn |
*/ |
long |
get_run_time (void) |
{ |
#if defined (HAVE_GETRUSAGE) && defined (HAVE_SYS_RESOURCE_H) |
struct rusage rusage; |
getrusage (0, &rusage); |
return (rusage.ru_utime.tv_sec * 1000000 + rusage.ru_utime.tv_usec |
+ rusage.ru_stime.tv_sec * 1000000 + rusage.ru_stime.tv_usec); |
#else /* ! HAVE_GETRUSAGE */ |
#ifdef HAVE_TIMES |
struct tms tms; |
times (&tms); |
return (tms.tms_utime + tms.tms_stime) * (1000000 / GNU_HZ); |
#else /* ! HAVE_TIMES */ |
/* Fall back on clock and hope it's correctly implemented. */ |
const long clocks_per_sec = CLOCKS_PER_SEC; |
if (clocks_per_sec <= 1000000) |
return clock () * (1000000 / clocks_per_sec); |
else |
return clock () / clocks_per_sec; |
#endif /* HAVE_TIMES */ |
#endif /* HAVE_GETRUSAGE */ |
} |
/contrib/toolchain/binutils/libiberty/hashtab.c |
---|
0,0 → 1,998 |
/* An expandable hash tables datatype. |
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2009, 2010 |
Free Software Foundation, Inc. |
Contributed by Vladimir Makarov (vmakarov@cygnus.com). |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* This package implements basic hash table functionality. It is possible |
to search for an entry, create an entry and destroy an entry. |
Elements in the table are generic pointers. |
The size of the table is not fixed; if the occupancy of the table |
grows too high the hash table will be expanded. |
The abstract data implementation is based on generalized Algorithm D |
from Knuth's book "The art of computer programming". Hash table is |
expanded by creation of new hash table and transferring elements from |
the old table to the new table. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <sys/types.h> |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifdef HAVE_MALLOC_H |
#include <malloc.h> |
#endif |
#ifdef HAVE_LIMITS_H |
#include <limits.h> |
#endif |
#ifdef HAVE_INTTYPES_H |
#include <inttypes.h> |
#endif |
#ifdef HAVE_STDINT_H |
#include <stdint.h> |
#endif |
#include <stdio.h> |
#include "libiberty.h" |
#include "ansidecl.h" |
#include "hashtab.h" |
#ifndef CHAR_BIT |
#define CHAR_BIT 8 |
#endif |
static unsigned int higher_prime_index (unsigned long); |
static hashval_t htab_mod_1 (hashval_t, hashval_t, hashval_t, int); |
static hashval_t htab_mod (hashval_t, htab_t); |
static hashval_t htab_mod_m2 (hashval_t, htab_t); |
static hashval_t hash_pointer (const void *); |
static int eq_pointer (const void *, const void *); |
static int htab_expand (htab_t); |
static PTR *find_empty_slot_for_expand (htab_t, hashval_t); |
/* At some point, we could make these be NULL, and modify the |
hash-table routines to handle NULL specially; that would avoid |
function-call overhead for the common case of hashing pointers. */ |
htab_hash htab_hash_pointer = hash_pointer; |
htab_eq htab_eq_pointer = eq_pointer; |
/* Table of primes and multiplicative inverses. |
Note that these are not minimally reduced inverses. Unlike when generating |
code to divide by a constant, we want to be able to use the same algorithm |
all the time. All of these inverses (are implied to) have bit 32 set. |
For the record, here's the function that computed the table; it's a |
vastly simplified version of the function of the same name from gcc. */ |
#if 0 |
unsigned int |
ceil_log2 (unsigned int x) |
{ |
int i; |
for (i = 31; i >= 0 ; --i) |
if (x > (1u << i)) |
return i+1; |
abort (); |
} |
unsigned int |
choose_multiplier (unsigned int d, unsigned int *mlp, unsigned char *shiftp) |
{ |
unsigned long long mhigh; |
double nx; |
int lgup, post_shift; |
int pow, pow2; |
int n = 32, precision = 32; |
lgup = ceil_log2 (d); |
pow = n + lgup; |
pow2 = n + lgup - precision; |
nx = ldexp (1.0, pow) + ldexp (1.0, pow2); |
mhigh = nx / d; |
*shiftp = lgup - 1; |
*mlp = mhigh; |
return mhigh >> 32; |
} |
#endif |
struct prime_ent |
{ |
hashval_t prime; |
hashval_t inv; |
hashval_t inv_m2; /* inverse of prime-2 */ |
hashval_t shift; |
}; |
static struct prime_ent const prime_tab[] = { |
{ 7, 0x24924925, 0x9999999b, 2 }, |
{ 13, 0x3b13b13c, 0x745d1747, 3 }, |
{ 31, 0x08421085, 0x1a7b9612, 4 }, |
{ 61, 0x0c9714fc, 0x15b1e5f8, 5 }, |
{ 127, 0x02040811, 0x0624dd30, 6 }, |
{ 251, 0x05197f7e, 0x073260a5, 7 }, |
{ 509, 0x01824366, 0x02864fc8, 8 }, |
{ 1021, 0x00c0906d, 0x014191f7, 9 }, |
{ 2039, 0x0121456f, 0x0161e69e, 10 }, |
{ 4093, 0x00300902, 0x00501908, 11 }, |
{ 8191, 0x00080041, 0x00180241, 12 }, |
{ 16381, 0x000c0091, 0x00140191, 13 }, |
{ 32749, 0x002605a5, 0x002a06e6, 14 }, |
{ 65521, 0x000f00e2, 0x00110122, 15 }, |
{ 131071, 0x00008001, 0x00018003, 16 }, |
{ 262139, 0x00014002, 0x0001c004, 17 }, |
{ 524287, 0x00002001, 0x00006001, 18 }, |
{ 1048573, 0x00003001, 0x00005001, 19 }, |
{ 2097143, 0x00004801, 0x00005801, 20 }, |
{ 4194301, 0x00000c01, 0x00001401, 21 }, |
{ 8388593, 0x00001e01, 0x00002201, 22 }, |
{ 16777213, 0x00000301, 0x00000501, 23 }, |
{ 33554393, 0x00001381, 0x00001481, 24 }, |
{ 67108859, 0x00000141, 0x000001c1, 25 }, |
{ 134217689, 0x000004e1, 0x00000521, 26 }, |
{ 268435399, 0x00000391, 0x000003b1, 27 }, |
{ 536870909, 0x00000019, 0x00000029, 28 }, |
{ 1073741789, 0x0000008d, 0x00000095, 29 }, |
{ 2147483647, 0x00000003, 0x00000007, 30 }, |
/* Avoid "decimal constant so large it is unsigned" for 4294967291. */ |
{ 0xfffffffb, 0x00000006, 0x00000008, 31 } |
}; |
/* The following function returns an index into the above table of the |
nearest prime number which is greater than N, and near a power of two. */ |
static unsigned int |
higher_prime_index (unsigned long n) |
{ |
unsigned int low = 0; |
unsigned int high = sizeof(prime_tab) / sizeof(prime_tab[0]); |
while (low != high) |
{ |
unsigned int mid = low + (high - low) / 2; |
if (n > prime_tab[mid].prime) |
low = mid + 1; |
else |
high = mid; |
} |
/* If we've run out of primes, abort. */ |
if (n > prime_tab[low].prime) |
{ |
fprintf (stderr, "Cannot find prime bigger than %lu\n", n); |
abort (); |
} |
return low; |
} |
/* Returns non-zero if P1 and P2 are equal. */ |
static int |
eq_pointer (const PTR p1, const PTR p2) |
{ |
return p1 == p2; |
} |
/* The parens around the function names in the next two definitions |
are essential in order to prevent macro expansions of the name. |
The bodies, however, are expanded as expected, so they are not |
recursive definitions. */ |
/* Return the current size of given hash table. */ |
#define htab_size(htab) ((htab)->size) |
size_t |
(htab_size) (htab_t htab) |
{ |
return htab_size (htab); |
} |
/* Return the current number of elements in given hash table. */ |
#define htab_elements(htab) ((htab)->n_elements - (htab)->n_deleted) |
size_t |
(htab_elements) (htab_t htab) |
{ |
return htab_elements (htab); |
} |
/* Return X % Y. */ |
static inline hashval_t |
htab_mod_1 (hashval_t x, hashval_t y, hashval_t inv, int shift) |
{ |
/* The multiplicative inverses computed above are for 32-bit types, and |
requires that we be able to compute a highpart multiply. */ |
#ifdef UNSIGNED_64BIT_TYPE |
__extension__ typedef UNSIGNED_64BIT_TYPE ull; |
if (sizeof (hashval_t) * CHAR_BIT <= 32) |
{ |
hashval_t t1, t2, t3, t4, q, r; |
t1 = ((ull)x * inv) >> 32; |
t2 = x - t1; |
t3 = t2 >> 1; |
t4 = t1 + t3; |
q = t4 >> shift; |
r = x - (q * y); |
return r; |
} |
#endif |
/* Otherwise just use the native division routines. */ |
return x % y; |
} |
/* Compute the primary hash for HASH given HTAB's current size. */ |
static inline hashval_t |
htab_mod (hashval_t hash, htab_t htab) |
{ |
const struct prime_ent *p = &prime_tab[htab->size_prime_index]; |
return htab_mod_1 (hash, p->prime, p->inv, p->shift); |
} |
/* Compute the secondary hash for HASH given HTAB's current size. */ |
static inline hashval_t |
htab_mod_m2 (hashval_t hash, htab_t htab) |
{ |
const struct prime_ent *p = &prime_tab[htab->size_prime_index]; |
return 1 + htab_mod_1 (hash, p->prime - 2, p->inv_m2, p->shift); |
} |
/* This function creates table with length slightly longer than given |
source length. Created hash table is initiated as empty (all the |
hash table entries are HTAB_EMPTY_ENTRY). The function returns the |
created hash table, or NULL if memory allocation fails. */ |
htab_t |
htab_create_alloc (size_t size, htab_hash hash_f, htab_eq eq_f, |
htab_del del_f, htab_alloc alloc_f, htab_free free_f) |
{ |
return htab_create_typed_alloc (size, hash_f, eq_f, del_f, alloc_f, alloc_f, |
free_f); |
} |
/* As above, but uses the variants of ALLOC_F and FREE_F which accept |
an extra argument. */ |
htab_t |
htab_create_alloc_ex (size_t size, htab_hash hash_f, htab_eq eq_f, |
htab_del del_f, void *alloc_arg, |
htab_alloc_with_arg alloc_f, |
htab_free_with_arg free_f) |
{ |
htab_t result; |
unsigned int size_prime_index; |
size_prime_index = higher_prime_index (size); |
size = prime_tab[size_prime_index].prime; |
result = (htab_t) (*alloc_f) (alloc_arg, 1, sizeof (struct htab)); |
if (result == NULL) |
return NULL; |
result->entries = (PTR *) (*alloc_f) (alloc_arg, size, sizeof (PTR)); |
if (result->entries == NULL) |
{ |
if (free_f != NULL) |
(*free_f) (alloc_arg, result); |
return NULL; |
} |
result->size = size; |
result->size_prime_index = size_prime_index; |
result->hash_f = hash_f; |
result->eq_f = eq_f; |
result->del_f = del_f; |
result->alloc_arg = alloc_arg; |
result->alloc_with_arg_f = alloc_f; |
result->free_with_arg_f = free_f; |
return result; |
} |
/* |
@deftypefn Supplemental htab_t htab_create_typed_alloc (size_t @var{size}, @ |
htab_hash @var{hash_f}, htab_eq @var{eq_f}, htab_del @var{del_f}, @ |
htab_alloc @var{alloc_tab_f}, htab_alloc @var{alloc_f}, @ |
htab_free @var{free_f}) |
This function creates a hash table that uses two different allocators |
@var{alloc_tab_f} and @var{alloc_f} to use for allocating the table itself |
and its entries respectively. This is useful when variables of different |
types need to be allocated with different allocators. |
The created hash table is slightly larger than @var{size} and it is |
initially empty (all the hash table entries are @code{HTAB_EMPTY_ENTRY}). |
The function returns the created hash table, or @code{NULL} if memory |
allocation fails. |
@end deftypefn |
*/ |
htab_t |
htab_create_typed_alloc (size_t size, htab_hash hash_f, htab_eq eq_f, |
htab_del del_f, htab_alloc alloc_tab_f, |
htab_alloc alloc_f, htab_free free_f) |
{ |
htab_t result; |
unsigned int size_prime_index; |
size_prime_index = higher_prime_index (size); |
size = prime_tab[size_prime_index].prime; |
result = (htab_t) (*alloc_tab_f) (1, sizeof (struct htab)); |
if (result == NULL) |
return NULL; |
result->entries = (PTR *) (*alloc_f) (size, sizeof (PTR)); |
if (result->entries == NULL) |
{ |
if (free_f != NULL) |
(*free_f) (result); |
return NULL; |
} |
result->size = size; |
result->size_prime_index = size_prime_index; |
result->hash_f = hash_f; |
result->eq_f = eq_f; |
result->del_f = del_f; |
result->alloc_f = alloc_f; |
result->free_f = free_f; |
return result; |
} |
/* Update the function pointers and allocation parameter in the htab_t. */ |
void |
htab_set_functions_ex (htab_t htab, htab_hash hash_f, htab_eq eq_f, |
htab_del del_f, PTR alloc_arg, |
htab_alloc_with_arg alloc_f, htab_free_with_arg free_f) |
{ |
htab->hash_f = hash_f; |
htab->eq_f = eq_f; |
htab->del_f = del_f; |
htab->alloc_arg = alloc_arg; |
htab->alloc_with_arg_f = alloc_f; |
htab->free_with_arg_f = free_f; |
} |
/* These functions exist solely for backward compatibility. */ |
#undef htab_create |
htab_t |
htab_create (size_t size, htab_hash hash_f, htab_eq eq_f, htab_del del_f) |
{ |
return htab_create_alloc (size, hash_f, eq_f, del_f, xcalloc, free); |
} |
htab_t |
htab_try_create (size_t size, htab_hash hash_f, htab_eq eq_f, htab_del del_f) |
{ |
return htab_create_alloc (size, hash_f, eq_f, del_f, calloc, free); |
} |
/* This function frees all memory allocated for given hash table. |
Naturally the hash table must already exist. */ |
void |
htab_delete (htab_t htab) |
{ |
size_t size = htab_size (htab); |
PTR *entries = htab->entries; |
int i; |
if (htab->del_f) |
for (i = size - 1; i >= 0; i--) |
if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY) |
(*htab->del_f) (entries[i]); |
if (htab->free_f != NULL) |
{ |
(*htab->free_f) (entries); |
(*htab->free_f) (htab); |
} |
else if (htab->free_with_arg_f != NULL) |
{ |
(*htab->free_with_arg_f) (htab->alloc_arg, entries); |
(*htab->free_with_arg_f) (htab->alloc_arg, htab); |
} |
} |
/* This function clears all entries in the given hash table. */ |
void |
htab_empty (htab_t htab) |
{ |
size_t size = htab_size (htab); |
PTR *entries = htab->entries; |
int i; |
if (htab->del_f) |
for (i = size - 1; i >= 0; i--) |
if (entries[i] != HTAB_EMPTY_ENTRY && entries[i] != HTAB_DELETED_ENTRY) |
(*htab->del_f) (entries[i]); |
/* Instead of clearing megabyte, downsize the table. */ |
if (size > 1024*1024 / sizeof (PTR)) |
{ |
int nindex = higher_prime_index (1024 / sizeof (PTR)); |
int nsize = prime_tab[nindex].prime; |
if (htab->free_f != NULL) |
(*htab->free_f) (htab->entries); |
else if (htab->free_with_arg_f != NULL) |
(*htab->free_with_arg_f) (htab->alloc_arg, htab->entries); |
if (htab->alloc_with_arg_f != NULL) |
htab->entries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize, |
sizeof (PTR *)); |
else |
htab->entries = (PTR *) (*htab->alloc_f) (nsize, sizeof (PTR *)); |
htab->size = nsize; |
htab->size_prime_index = nindex; |
} |
else |
memset (entries, 0, size * sizeof (PTR)); |
htab->n_deleted = 0; |
htab->n_elements = 0; |
} |
/* Similar to htab_find_slot, but without several unwanted side effects: |
- Does not call htab->eq_f when it finds an existing entry. |
- Does not change the count of elements/searches/collisions in the |
hash table. |
This function also assumes there are no deleted entries in the table. |
HASH is the hash value for the element to be inserted. */ |
static PTR * |
find_empty_slot_for_expand (htab_t htab, hashval_t hash) |
{ |
hashval_t index = htab_mod (hash, htab); |
size_t size = htab_size (htab); |
PTR *slot = htab->entries + index; |
hashval_t hash2; |
if (*slot == HTAB_EMPTY_ENTRY) |
return slot; |
else if (*slot == HTAB_DELETED_ENTRY) |
abort (); |
hash2 = htab_mod_m2 (hash, htab); |
for (;;) |
{ |
index += hash2; |
if (index >= size) |
index -= size; |
slot = htab->entries + index; |
if (*slot == HTAB_EMPTY_ENTRY) |
return slot; |
else if (*slot == HTAB_DELETED_ENTRY) |
abort (); |
} |
} |
/* The following function changes size of memory allocated for the |
entries and repeatedly inserts the table elements. The occupancy |
of the table after the call will be about 50%. Naturally the hash |
table must already exist. Remember also that the place of the |
table entries is changed. If memory allocation failures are allowed, |
this function will return zero, indicating that the table could not be |
expanded. If all goes well, it will return a non-zero value. */ |
static int |
htab_expand (htab_t htab) |
{ |
PTR *oentries; |
PTR *olimit; |
PTR *p; |
PTR *nentries; |
size_t nsize, osize, elts; |
unsigned int oindex, nindex; |
oentries = htab->entries; |
oindex = htab->size_prime_index; |
osize = htab->size; |
olimit = oentries + osize; |
elts = htab_elements (htab); |
/* Resize only when table after removal of unused elements is either |
too full or too empty. */ |
if (elts * 2 > osize || (elts * 8 < osize && osize > 32)) |
{ |
nindex = higher_prime_index (elts * 2); |
nsize = prime_tab[nindex].prime; |
} |
else |
{ |
nindex = oindex; |
nsize = osize; |
} |
if (htab->alloc_with_arg_f != NULL) |
nentries = (PTR *) (*htab->alloc_with_arg_f) (htab->alloc_arg, nsize, |
sizeof (PTR *)); |
else |
nentries = (PTR *) (*htab->alloc_f) (nsize, sizeof (PTR *)); |
if (nentries == NULL) |
return 0; |
htab->entries = nentries; |
htab->size = nsize; |
htab->size_prime_index = nindex; |
htab->n_elements -= htab->n_deleted; |
htab->n_deleted = 0; |
p = oentries; |
do |
{ |
PTR x = *p; |
if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY) |
{ |
PTR *q = find_empty_slot_for_expand (htab, (*htab->hash_f) (x)); |
*q = x; |
} |
p++; |
} |
while (p < olimit); |
if (htab->free_f != NULL) |
(*htab->free_f) (oentries); |
else if (htab->free_with_arg_f != NULL) |
(*htab->free_with_arg_f) (htab->alloc_arg, oentries); |
return 1; |
} |
/* This function searches for a hash table entry equal to the given |
element. It cannot be used to insert or delete an element. */ |
PTR |
htab_find_with_hash (htab_t htab, const PTR element, hashval_t hash) |
{ |
hashval_t index, hash2; |
size_t size; |
PTR entry; |
htab->searches++; |
size = htab_size (htab); |
index = htab_mod (hash, htab); |
entry = htab->entries[index]; |
if (entry == HTAB_EMPTY_ENTRY |
|| (entry != HTAB_DELETED_ENTRY && (*htab->eq_f) (entry, element))) |
return entry; |
hash2 = htab_mod_m2 (hash, htab); |
for (;;) |
{ |
htab->collisions++; |
index += hash2; |
if (index >= size) |
index -= size; |
entry = htab->entries[index]; |
if (entry == HTAB_EMPTY_ENTRY |
|| (entry != HTAB_DELETED_ENTRY && (*htab->eq_f) (entry, element))) |
return entry; |
} |
} |
/* Like htab_find_slot_with_hash, but compute the hash value from the |
element. */ |
PTR |
htab_find (htab_t htab, const PTR element) |
{ |
return htab_find_with_hash (htab, element, (*htab->hash_f) (element)); |
} |
/* This function searches for a hash table slot containing an entry |
equal to the given element. To delete an entry, call this with |
insert=NO_INSERT, then call htab_clear_slot on the slot returned |
(possibly after doing some checks). To insert an entry, call this |
with insert=INSERT, then write the value you want into the returned |
slot. When inserting an entry, NULL may be returned if memory |
allocation fails. */ |
PTR * |
htab_find_slot_with_hash (htab_t htab, const PTR element, |
hashval_t hash, enum insert_option insert) |
{ |
PTR *first_deleted_slot; |
hashval_t index, hash2; |
size_t size; |
PTR entry; |
size = htab_size (htab); |
if (insert == INSERT && size * 3 <= htab->n_elements * 4) |
{ |
if (htab_expand (htab) == 0) |
return NULL; |
size = htab_size (htab); |
} |
index = htab_mod (hash, htab); |
htab->searches++; |
first_deleted_slot = NULL; |
entry = htab->entries[index]; |
if (entry == HTAB_EMPTY_ENTRY) |
goto empty_entry; |
else if (entry == HTAB_DELETED_ENTRY) |
first_deleted_slot = &htab->entries[index]; |
else if ((*htab->eq_f) (entry, element)) |
return &htab->entries[index]; |
hash2 = htab_mod_m2 (hash, htab); |
for (;;) |
{ |
htab->collisions++; |
index += hash2; |
if (index >= size) |
index -= size; |
entry = htab->entries[index]; |
if (entry == HTAB_EMPTY_ENTRY) |
goto empty_entry; |
else if (entry == HTAB_DELETED_ENTRY) |
{ |
if (!first_deleted_slot) |
first_deleted_slot = &htab->entries[index]; |
} |
else if ((*htab->eq_f) (entry, element)) |
return &htab->entries[index]; |
} |
empty_entry: |
if (insert == NO_INSERT) |
return NULL; |
if (first_deleted_slot) |
{ |
htab->n_deleted--; |
*first_deleted_slot = HTAB_EMPTY_ENTRY; |
return first_deleted_slot; |
} |
htab->n_elements++; |
return &htab->entries[index]; |
} |
/* Like htab_find_slot_with_hash, but compute the hash value from the |
element. */ |
PTR * |
htab_find_slot (htab_t htab, const PTR element, enum insert_option insert) |
{ |
return htab_find_slot_with_hash (htab, element, (*htab->hash_f) (element), |
insert); |
} |
/* This function deletes an element with the given value from hash |
table (the hash is computed from the element). If there is no matching |
element in the hash table, this function does nothing. */ |
void |
htab_remove_elt (htab_t htab, PTR element) |
{ |
htab_remove_elt_with_hash (htab, element, (*htab->hash_f) (element)); |
} |
/* This function deletes an element with the given value from hash |
table. If there is no matching element in the hash table, this |
function does nothing. */ |
void |
htab_remove_elt_with_hash (htab_t htab, PTR element, hashval_t hash) |
{ |
PTR *slot; |
slot = htab_find_slot_with_hash (htab, element, hash, NO_INSERT); |
if (*slot == HTAB_EMPTY_ENTRY) |
return; |
if (htab->del_f) |
(*htab->del_f) (*slot); |
*slot = HTAB_DELETED_ENTRY; |
htab->n_deleted++; |
} |
/* This function clears a specified slot in a hash table. It is |
useful when you've already done the lookup and don't want to do it |
again. */ |
void |
htab_clear_slot (htab_t htab, PTR *slot) |
{ |
if (slot < htab->entries || slot >= htab->entries + htab_size (htab) |
|| *slot == HTAB_EMPTY_ENTRY || *slot == HTAB_DELETED_ENTRY) |
abort (); |
if (htab->del_f) |
(*htab->del_f) (*slot); |
*slot = HTAB_DELETED_ENTRY; |
htab->n_deleted++; |
} |
/* This function scans over the entire hash table calling |
CALLBACK for each live entry. If CALLBACK returns false, |
the iteration stops. INFO is passed as CALLBACK's second |
argument. */ |
void |
htab_traverse_noresize (htab_t htab, htab_trav callback, PTR info) |
{ |
PTR *slot; |
PTR *limit; |
slot = htab->entries; |
limit = slot + htab_size (htab); |
do |
{ |
PTR x = *slot; |
if (x != HTAB_EMPTY_ENTRY && x != HTAB_DELETED_ENTRY) |
if (!(*callback) (slot, info)) |
break; |
} |
while (++slot < limit); |
} |
/* Like htab_traverse_noresize, but does resize the table when it is |
too empty to improve effectivity of subsequent calls. */ |
void |
htab_traverse (htab_t htab, htab_trav callback, PTR info) |
{ |
size_t size = htab_size (htab); |
if (htab_elements (htab) * 8 < size && size > 32) |
htab_expand (htab); |
htab_traverse_noresize (htab, callback, info); |
} |
/* Return the fraction of fixed collisions during all work with given |
hash table. */ |
double |
htab_collisions (htab_t htab) |
{ |
if (htab->searches == 0) |
return 0.0; |
return (double) htab->collisions / (double) htab->searches; |
} |
/* Hash P as a null-terminated string. |
Copied from gcc/hashtable.c. Zack had the following to say with respect |
to applicability, though note that unlike hashtable.c, this hash table |
implementation re-hashes rather than chain buckets. |
http://gcc.gnu.org/ml/gcc-patches/2001-08/msg01021.html |
From: Zack Weinberg <zackw@panix.com> |
Date: Fri, 17 Aug 2001 02:15:56 -0400 |
I got it by extracting all the identifiers from all the source code |
I had lying around in mid-1999, and testing many recurrences of |
the form "H_n = H_{n-1} * K + c_n * L + M" where K, L, M were either |
prime numbers or the appropriate identity. This was the best one. |
I don't remember exactly what constituted "best", except I was |
looking at bucket-length distributions mostly. |
So it should be very good at hashing identifiers, but might not be |
as good at arbitrary strings. |
I'll add that it thoroughly trounces the hash functions recommended |
for this use at http://burtleburtle.net/bob/hash/index.html, both |
on speed and bucket distribution. I haven't tried it against the |
function they just started using for Perl's hashes. */ |
hashval_t |
htab_hash_string (const PTR p) |
{ |
const unsigned char *str = (const unsigned char *) p; |
hashval_t r = 0; |
unsigned char c; |
while ((c = *str++) != 0) |
r = r * 67 + c - 113; |
return r; |
} |
/* DERIVED FROM: |
-------------------------------------------------------------------- |
lookup2.c, by Bob Jenkins, December 1996, Public Domain. |
hash(), hash2(), hash3, and mix() are externally useful functions. |
Routines to test the hash are included if SELF_TEST is defined. |
You can use this free for any purpose. It has no warranty. |
-------------------------------------------------------------------- |
*/ |
/* |
-------------------------------------------------------------------- |
mix -- mix 3 32-bit values reversibly. |
For every delta with one or two bit set, and the deltas of all three |
high bits or all three low bits, whether the original value of a,b,c |
is almost all zero or is uniformly distributed, |
* If mix() is run forward or backward, at least 32 bits in a,b,c |
have at least 1/4 probability of changing. |
* If mix() is run forward, every bit of c will change between 1/3 and |
2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) |
mix() was built out of 36 single-cycle latency instructions in a |
structure that could supported 2x parallelism, like so: |
a -= b; |
a -= c; x = (c>>13); |
b -= c; a ^= x; |
b -= a; x = (a<<8); |
c -= a; b ^= x; |
c -= b; x = (b>>13); |
... |
Unfortunately, superscalar Pentiums and Sparcs can't take advantage |
of that parallelism. They've also turned some of those single-cycle |
latency instructions into multi-cycle latency instructions. Still, |
this is the fastest good hash I could find. There were about 2^^68 |
to choose from. I only looked at a billion or so. |
-------------------------------------------------------------------- |
*/ |
/* same, but slower, works on systems that might have 8 byte hashval_t's */ |
#define mix(a,b,c) \ |
{ \ |
a -= b; a -= c; a ^= (c>>13); \ |
b -= c; b -= a; b ^= (a<< 8); \ |
c -= a; c -= b; c ^= ((b&0xffffffff)>>13); \ |
a -= b; a -= c; a ^= ((c&0xffffffff)>>12); \ |
b -= c; b -= a; b = (b ^ (a<<16)) & 0xffffffff; \ |
c -= a; c -= b; c = (c ^ (b>> 5)) & 0xffffffff; \ |
a -= b; a -= c; a = (a ^ (c>> 3)) & 0xffffffff; \ |
b -= c; b -= a; b = (b ^ (a<<10)) & 0xffffffff; \ |
c -= a; c -= b; c = (c ^ (b>>15)) & 0xffffffff; \ |
} |
/* |
-------------------------------------------------------------------- |
hash() -- hash a variable-length key into a 32-bit value |
k : the key (the unaligned variable-length array of bytes) |
len : the length of the key, counting by bytes |
level : can be any 4-byte value |
Returns a 32-bit value. Every bit of the key affects every bit of |
the return value. Every 1-bit and 2-bit delta achieves avalanche. |
About 36+6len instructions. |
The best hash table sizes are powers of 2. There is no need to do |
mod a prime (mod is sooo slow!). If you need less than 32 bits, |
use a bitmask. For example, if you need only 10 bits, do |
h = (h & hashmask(10)); |
In which case, the hash table should have hashsize(10) elements. |
If you are hashing n strings (ub1 **)k, do it like this: |
for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h); |
By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this |
code any way you wish, private, educational, or commercial. It's free. |
See http://burtleburtle.net/bob/hash/evahash.html |
Use for hash table lookup, or anything where one collision in 2^32 is |
acceptable. Do NOT use for cryptographic purposes. |
-------------------------------------------------------------------- |
*/ |
hashval_t |
iterative_hash (const PTR k_in /* the key */, |
register size_t length /* the length of the key */, |
register hashval_t initval /* the previous hash, or |
an arbitrary value */) |
{ |
register const unsigned char *k = (const unsigned char *)k_in; |
register hashval_t a,b,c,len; |
/* Set up the internal state */ |
len = length; |
a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */ |
c = initval; /* the previous hash value */ |
/*---------------------------------------- handle most of the key */ |
#ifndef WORDS_BIGENDIAN |
/* On a little-endian machine, if the data is 4-byte aligned we can hash |
by word for better speed. This gives nondeterministic results on |
big-endian machines. */ |
if (sizeof (hashval_t) == 4 && (((size_t)k)&3) == 0) |
while (len >= 12) /* aligned */ |
{ |
a += *(hashval_t *)(k+0); |
b += *(hashval_t *)(k+4); |
c += *(hashval_t *)(k+8); |
mix(a,b,c); |
k += 12; len -= 12; |
} |
else /* unaligned */ |
#endif |
while (len >= 12) |
{ |
a += (k[0] +((hashval_t)k[1]<<8) +((hashval_t)k[2]<<16) +((hashval_t)k[3]<<24)); |
b += (k[4] +((hashval_t)k[5]<<8) +((hashval_t)k[6]<<16) +((hashval_t)k[7]<<24)); |
c += (k[8] +((hashval_t)k[9]<<8) +((hashval_t)k[10]<<16)+((hashval_t)k[11]<<24)); |
mix(a,b,c); |
k += 12; len -= 12; |
} |
/*------------------------------------- handle the last 11 bytes */ |
c += length; |
switch(len) /* all the case statements fall through */ |
{ |
case 11: c+=((hashval_t)k[10]<<24); |
case 10: c+=((hashval_t)k[9]<<16); |
case 9 : c+=((hashval_t)k[8]<<8); |
/* the first byte of c is reserved for the length */ |
case 8 : b+=((hashval_t)k[7]<<24); |
case 7 : b+=((hashval_t)k[6]<<16); |
case 6 : b+=((hashval_t)k[5]<<8); |
case 5 : b+=k[4]; |
case 4 : a+=((hashval_t)k[3]<<24); |
case 3 : a+=((hashval_t)k[2]<<16); |
case 2 : a+=((hashval_t)k[1]<<8); |
case 1 : a+=k[0]; |
/* case 0: nothing left to add */ |
} |
mix(a,b,c); |
/*-------------------------------------------- report the result */ |
return c; |
} |
/* Returns a hash code for pointer P. Simplified version of evahash */ |
static hashval_t |
hash_pointer (const PTR p) |
{ |
intptr_t v = (intptr_t) p; |
unsigned a, b, c; |
a = b = 0x9e3779b9; |
a += v >> (sizeof (intptr_t) * CHAR_BIT / 2); |
b += v & (((intptr_t) 1 << (sizeof (intptr_t) * CHAR_BIT / 2)) - 1); |
c = 0x42135234; |
mix (a, b, c); |
return c; |
} |
/contrib/toolchain/binutils/libiberty/hex.c |
---|
0,0 → 1,192 |
/* Hex character manipulation support. |
Copyright (C) 1995, 2001 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#include <stdio.h> /* for EOF */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "libiberty.h" |
#include "safe-ctype.h" /* for HOST_CHARSET_ASCII */ |
#if EOF != -1 |
#error "hex.c requires EOF == -1" |
#endif |
/* |
@deftypefn Extension void hex_init (void) |
Initializes the array mapping the current character set to |
corresponding hex values. This function must be called before any |
call to @code{hex_p} or @code{hex_value}. If you fail to call it, a |
default ASCII-based table will normally be used on ASCII systems. |
@end deftypefn |
@deftypefn Extension int hex_p (int @var{c}) |
Evaluates to non-zero if the given character is a valid hex character, |
or zero if it is not. Note that the value you pass will be cast to |
@code{unsigned char} within the macro. |
@end deftypefn |
@deftypefn Extension {unsigned int} hex_value (int @var{c}) |
Returns the numeric equivalent of the given character when interpreted |
as a hexadecimal digit. The result is undefined if you pass an |
invalid hex digit. Note that the value you pass will be cast to |
@code{unsigned char} within the macro. |
The @code{hex_value} macro returns @code{unsigned int}, rather than |
signed @code{int}, to make it easier to use in parsing addresses from |
hex dump files: a signed @code{int} would be sign-extended when |
converted to a wider unsigned type --- like @code{bfd_vma}, on some |
systems. |
@end deftypefn |
@undocumented _hex_array_size |
@undocumented _hex_bad |
@undocumented _hex_value |
*/ |
/* Are we ASCII? */ |
#if HOST_CHARSET == HOST_CHARSET_ASCII |
const unsigned char _hex_value[_hex_array_size] = |
{ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* NUL SOH STX ETX */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* EOT ENQ ACK BEL */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* BS HT LF VT */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* FF CR SO SI */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* DLE DC1 DC2 DC3 */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* DC4 NAK SYN ETB */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* CAN EM SUB ESC */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* FS GS RS US */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* SP ! " # */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* $ % & ' */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* ( ) * + */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* , - . / */ |
0, 1, 2, 3, /* 0 1 2 3 */ |
4, 5, 6, 7, /* 4 5 6 7 */ |
8, 9, _hex_bad, _hex_bad, /* 8 9 : ; */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* < = > ? */ |
_hex_bad, 10, 11, 12, /* @ A B C */ |
13, 14, 15, _hex_bad, /* D E F G */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* H I J K */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* L M N O */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* P Q R S */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* T U V W */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* X Y Z [ */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* \ ] ^ _ */ |
_hex_bad, 10, 11, 12, /* ` a b c */ |
13, 14, 15, _hex_bad, /* d e f g */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* h i j k */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* l m n o */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* p q r s */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* t u v w */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* x y z { */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, /* | } ~ DEL */ |
/* The high half of unsigned char, all values are _hex_bad. */ |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
_hex_bad, _hex_bad, _hex_bad, _hex_bad, |
}; |
#define HEX_TABLE_INITIALIZED |
#else |
unsigned char _hex_value[_hex_array_size]; |
#endif /* not ASCII */ |
void |
hex_init (void) |
{ |
#ifndef HEX_TABLE_INITIALIZED |
int i; |
for (i=0; i<_hex_array_size; i++) |
{ |
switch (i) |
{ |
case '0': _hex_value[i] = 0; break; |
case '1': _hex_value[i] = 1; break; |
case '2': _hex_value[i] = 2; break; |
case '3': _hex_value[i] = 3; break; |
case '4': _hex_value[i] = 4; break; |
case '5': _hex_value[i] = 5; break; |
case '6': _hex_value[i] = 6; break; |
case '7': _hex_value[i] = 7; break; |
case '8': _hex_value[i] = 8; break; |
case '9': _hex_value[i] = 9; break; |
case 'a': case 'A': _hex_value[i] = 10; break; |
case 'b': case 'B': _hex_value[i] = 11; break; |
case 'c': case 'C': _hex_value[i] = 12; break; |
case 'd': case 'D': _hex_value[i] = 13; break; |
case 'e': case 'E': _hex_value[i] = 14; break; |
case 'f': case 'F': _hex_value[i] = 15; break; |
default: |
_hex_value[i] = _hex_bad; |
break; |
} |
} |
#endif |
} |
/contrib/toolchain/binutils/libiberty/index.c |
---|
0,0 → 1,21 |
/* Stub implementation of (obsolete) index(). */ |
/* |
@deftypefn Supplemental char* index (char *@var{s}, int @var{c}) |
Returns a pointer to the first occurrence of the character @var{c} in |
the string @var{s}, or @code{NULL} if not found. The use of @code{index} is |
deprecated in new programs in favor of @code{strchr}. |
@end deftypefn |
*/ |
extern char * strchr(const char *, int); |
char * |
index (const char *s, int c) |
{ |
return strchr (s, c); |
} |
/contrib/toolchain/binutils/libiberty/insque.c |
---|
0,0 → 1,51 |
/* insque(3C) routines |
This file is in the public domain. */ |
/* |
@deftypefn Supplemental void insque (struct qelem *@var{elem}, @ |
struct qelem *@var{pred}) |
@deftypefnx Supplemental void remque (struct qelem *@var{elem}) |
Routines to manipulate queues built from doubly linked lists. The |
@code{insque} routine inserts @var{elem} in the queue immediately |
after @var{pred}. The @code{remque} routine removes @var{elem} from |
its containing queue. These routines expect to be passed pointers to |
structures which have as their first members a forward pointer and a |
back pointer, like this prototype (although no prototype is provided): |
@example |
struct qelem @{ |
struct qelem *q_forw; |
struct qelem *q_back; |
char q_data[]; |
@}; |
@end example |
@end deftypefn |
*/ |
struct qelem { |
struct qelem *q_forw; |
struct qelem *q_back; |
}; |
void |
insque (struct qelem *elem, struct qelem *pred) |
{ |
elem -> q_forw = pred -> q_forw; |
pred -> q_forw -> q_back = elem; |
elem -> q_back = pred; |
pred -> q_forw = elem; |
} |
void |
remque (struct qelem *elem) |
{ |
elem -> q_forw -> q_back = elem -> q_back; |
elem -> q_back -> q_forw = elem -> q_forw; |
} |
/contrib/toolchain/binutils/libiberty/lbasename.c |
---|
0,0 → 1,84 |
/* Libiberty basename. Like basename, but is not overridden by the |
system C library. |
Copyright (C) 2001, 2002, 2010 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Replacement {const char*} lbasename (const char *@var{name}) |
Given a pointer to a string containing a typical pathname |
(@samp{/usr/src/cmd/ls/ls.c} for example), returns a pointer to the |
last component of the pathname (@samp{ls.c} in this case). The |
returned pointer is guaranteed to lie within the original |
string. This latter fact is not true of many vendor C |
libraries, which return special strings or modify the passed |
strings for particular input. |
In particular, the empty string returns the same empty string, |
and a path ending in @code{/} returns the empty string after it. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#include "safe-ctype.h" |
#include "filenames.h" |
const char * |
unix_lbasename (const char *name) |
{ |
const char *base; |
for (base = name; *name; name++) |
if (IS_UNIX_DIR_SEPARATOR (*name)) |
base = name + 1; |
return base; |
} |
const char * |
dos_lbasename (const char *name) |
{ |
const char *base; |
/* Skip over a possible disk name. */ |
if (ISALPHA (name[0]) && name[1] == ':') |
name += 2; |
for (base = name; *name; name++) |
if (IS_DOS_DIR_SEPARATOR (*name)) |
base = name + 1; |
return base; |
} |
const char * |
lbasename (const char *name) |
{ |
#if defined (HAVE_DOS_BASED_FILE_SYSTEM) |
return dos_lbasename (name); |
#else |
return unix_lbasename (name); |
#endif |
} |
/contrib/toolchain/binutils/libiberty/lrealpath.c |
---|
0,0 → 1,157 |
/* Libiberty realpath. Like realpath, but more consistent behavior. |
Based on gdb_realpath from GDB. |
Copyright 2003 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
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 of the License, or |
(at your option) any later version. |
This program is distributed in the hope that it will be useful, |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
You should have received a copy of the GNU General Public License |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Replacement {const char*} lrealpath (const char *@var{name}) |
Given a pointer to a string containing a pathname, returns a canonical |
version of the filename. Symlinks will be resolved, and ``.'' and ``..'' |
components will be simplified. The returned value will be allocated using |
@code{malloc}, or @code{NULL} will be returned on a memory allocation error. |
@end deftypefn |
*/ |
#include "config.h" |
#include "ansidecl.h" |
#include "libiberty.h" |
#ifdef HAVE_LIMITS_H |
#include <limits.h> |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
/* On GNU libc systems the declaration is only visible with _GNU_SOURCE. */ |
#if defined(HAVE_CANONICALIZE_FILE_NAME) \ |
&& defined(NEED_DECLARATION_CANONICALIZE_FILE_NAME) |
extern char *canonicalize_file_name (const char *); |
#endif |
#if defined(HAVE_REALPATH) |
# if defined (PATH_MAX) |
# define REALPATH_LIMIT PATH_MAX |
# else |
# if defined (MAXPATHLEN) |
# define REALPATH_LIMIT MAXPATHLEN |
# endif |
# endif |
#else |
/* cygwin has realpath, so it won't get here. */ |
# if defined (_WIN32) |
# define WIN32_LEAN_AND_MEAN |
# include <windows.h> /* for GetFullPathName */ |
# endif |
#endif |
char * |
lrealpath (const char *filename) |
{ |
/* Method 1: The system has a compile time upper bound on a filename |
path. Use that and realpath() to canonicalize the name. This is |
the most common case. Note that, if there isn't a compile time |
upper bound, you want to avoid realpath() at all costs. */ |
#if defined(REALPATH_LIMIT) |
{ |
char buf[REALPATH_LIMIT]; |
const char *rp = realpath (filename, buf); |
if (rp == NULL) |
rp = filename; |
return strdup (rp); |
} |
#endif /* REALPATH_LIMIT */ |
/* Method 2: The host system (i.e., GNU) has the function |
canonicalize_file_name() which malloc's a chunk of memory and |
returns that, use that. */ |
#if defined(HAVE_CANONICALIZE_FILE_NAME) |
{ |
char *rp = canonicalize_file_name (filename); |
if (rp == NULL) |
return strdup (filename); |
else |
return rp; |
} |
#endif |
/* Method 3: Now we're getting desperate! The system doesn't have a |
compile time buffer size and no alternative function. Query the |
OS, using pathconf(), for the buffer limit. Care is needed |
though, some systems do not limit PATH_MAX (return -1 for |
pathconf()) making it impossible to pass a correctly sized buffer |
to realpath() (it could always overflow). On those systems, we |
skip this. */ |
#if defined (HAVE_REALPATH) && defined (HAVE_UNISTD_H) |
{ |
/* Find out the max path size. */ |
long path_max = pathconf ("/", _PC_PATH_MAX); |
if (path_max > 0) |
{ |
/* PATH_MAX is bounded. */ |
char *buf, *rp, *ret; |
buf = (char *) malloc (path_max); |
if (buf == NULL) |
return NULL; |
rp = realpath (filename, buf); |
ret = strdup (rp ? rp : filename); |
free (buf); |
return ret; |
} |
} |
#endif |
/* The MS Windows method. If we don't have realpath, we assume we |
don't have symlinks and just canonicalize to a Windows absolute |
path. GetFullPath converts ../ and ./ in relative paths to |
absolute paths, filling in current drive if one is not given |
or using the current directory of a specified drive (eg, "E:foo"). |
It also converts all forward slashes to back slashes. */ |
#if defined (_WIN32) |
{ |
char buf[MAX_PATH]; |
char* basename; |
DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename); |
if (len == 0 || len > MAX_PATH - 1) |
return strdup (filename); |
else |
{ |
/* The file system is case-preserving but case-insensitive, |
Canonicalize to lowercase, using the codepage associated |
with the process locale. */ |
CharLowerBuff (buf, len); |
return strdup (buf); |
} |
} |
#endif |
/* This system is a lost cause, just duplicate the filename. */ |
return strdup (filename); |
} |
/contrib/toolchain/binutils/libiberty/make-relative-prefix.c |
---|
0,0 → 1,427 |
/* Relative (relocatable) prefix support. |
Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, |
1999, 2000, 2001, 2002, 2006, 2012 Free Software Foundation, Inc. |
This file is part of libiberty. |
GCC 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. |
GCC 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 GCC; see the file COPYING. If not, write to the Free |
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA |
02110-1301, USA. */ |
/* |
@deftypefn Extension {const char*} make_relative_prefix (const char *@var{progname}, @ |
const char *@var{bin_prefix}, const char *@var{prefix}) |
Given three paths @var{progname}, @var{bin_prefix}, @var{prefix}, |
return the path that is in the same position relative to |
@var{progname}'s directory as @var{prefix} is relative to |
@var{bin_prefix}. That is, a string starting with the directory |
portion of @var{progname}, followed by a relative pathname of the |
difference between @var{bin_prefix} and @var{prefix}. |
If @var{progname} does not contain any directory separators, |
@code{make_relative_prefix} will search @env{PATH} to find a program |
named @var{progname}. Also, if @var{progname} is a symbolic link, |
the symbolic link will be resolved. |
For example, if @var{bin_prefix} is @code{/alpha/beta/gamma/gcc/delta}, |
@var{prefix} is @code{/alpha/beta/gamma/omega/}, and @var{progname} is |
@code{/red/green/blue/gcc}, then this function will return |
@code{/red/green/blue/../../omega/}. |
The return value is normally allocated via @code{malloc}. If no |
relative prefix can be found, return @code{NULL}. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
#ifdef HAVE_SYS_STAT_H |
#include <sys/stat.h> |
#endif |
#include <string.h> |
#include "ansidecl.h" |
#include "libiberty.h" |
#ifndef R_OK |
#define R_OK 4 |
#define W_OK 2 |
#define X_OK 1 |
#endif |
#ifndef DIR_SEPARATOR |
# define DIR_SEPARATOR '/' |
#endif |
#if defined (_WIN32) || defined (__MSDOS__) \ |
|| defined (__DJGPP__) || defined (__OS2__) |
# define HAVE_DOS_BASED_FILE_SYSTEM |
# define HAVE_HOST_EXECUTABLE_SUFFIX |
# define HOST_EXECUTABLE_SUFFIX ".exe" |
# ifndef DIR_SEPARATOR_2 |
# define DIR_SEPARATOR_2 '\\' |
# endif |
# define PATH_SEPARATOR ';' |
#else |
# define PATH_SEPARATOR ':' |
#endif |
#ifndef DIR_SEPARATOR_2 |
# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) |
#else |
# define IS_DIR_SEPARATOR(ch) \ |
(((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) |
#endif |
#define DIR_UP ".." |
static char *save_string (const char *, int); |
static char **split_directories (const char *, int *); |
static void free_split_directories (char **); |
static char * |
save_string (const char *s, int len) |
{ |
char *result = (char *) malloc (len + 1); |
memcpy (result, s, len); |
result[len] = 0; |
return result; |
} |
/* Split a filename into component directories. */ |
static char ** |
split_directories (const char *name, int *ptr_num_dirs) |
{ |
int num_dirs = 0; |
char **dirs; |
const char *p, *q; |
int ch; |
/* Count the number of directories. Special case MSDOS disk names as part |
of the initial directory. */ |
p = name; |
#ifdef HAVE_DOS_BASED_FILE_SYSTEM |
if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) |
{ |
p += 3; |
num_dirs++; |
} |
#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ |
while ((ch = *p++) != '\0') |
{ |
if (IS_DIR_SEPARATOR (ch)) |
{ |
num_dirs++; |
while (IS_DIR_SEPARATOR (*p)) |
p++; |
} |
} |
dirs = (char **) malloc (sizeof (char *) * (num_dirs + 2)); |
if (dirs == NULL) |
return NULL; |
/* Now copy the directory parts. */ |
num_dirs = 0; |
p = name; |
#ifdef HAVE_DOS_BASED_FILE_SYSTEM |
if (name[1] == ':' && IS_DIR_SEPARATOR (name[2])) |
{ |
dirs[num_dirs++] = save_string (p, 3); |
if (dirs[num_dirs - 1] == NULL) |
{ |
free (dirs); |
return NULL; |
} |
p += 3; |
} |
#endif /* HAVE_DOS_BASED_FILE_SYSTEM */ |
q = p; |
while ((ch = *p++) != '\0') |
{ |
if (IS_DIR_SEPARATOR (ch)) |
{ |
while (IS_DIR_SEPARATOR (*p)) |
p++; |
dirs[num_dirs++] = save_string (q, p - q); |
if (dirs[num_dirs - 1] == NULL) |
{ |
dirs[num_dirs] = NULL; |
free_split_directories (dirs); |
return NULL; |
} |
q = p; |
} |
} |
if (p - 1 - q > 0) |
dirs[num_dirs++] = save_string (q, p - 1 - q); |
dirs[num_dirs] = NULL; |
if (dirs[num_dirs - 1] == NULL) |
{ |
free_split_directories (dirs); |
return NULL; |
} |
if (ptr_num_dirs) |
*ptr_num_dirs = num_dirs; |
return dirs; |
} |
/* Release storage held by split directories. */ |
static void |
free_split_directories (char **dirs) |
{ |
int i = 0; |
if (dirs != NULL) |
{ |
while (dirs[i] != NULL) |
free (dirs[i++]); |
free ((char *) dirs); |
} |
} |
/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets |
to PREFIX starting with the directory portion of PROGNAME and a relative |
pathname of the difference between BIN_PREFIX and PREFIX. |
For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is |
/alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this |
function will return /red/green/blue/../../omega/. |
If no relative prefix can be found, return NULL. */ |
static char * |
make_relative_prefix_1 (const char *progname, const char *bin_prefix, |
const char *prefix, const int resolve_links) |
{ |
char **prog_dirs = NULL, **bin_dirs = NULL, **prefix_dirs = NULL; |
int prog_num, bin_num, prefix_num; |
int i, n, common; |
int needed_len; |
char *ret = NULL, *ptr, *full_progname; |
if (progname == NULL || bin_prefix == NULL || prefix == NULL) |
return NULL; |
/* If there is no full pathname, try to find the program by checking in each |
of the directories specified in the PATH environment variable. */ |
if (lbasename (progname) == progname) |
{ |
char *temp; |
temp = getenv ("PATH"); |
if (temp) |
{ |
char *startp, *endp, *nstore; |
size_t prefixlen = strlen (temp) + 1; |
size_t len; |
if (prefixlen < 2) |
prefixlen = 2; |
len = prefixlen + strlen (progname) + 1; |
#ifdef HAVE_HOST_EXECUTABLE_SUFFIX |
len += strlen (HOST_EXECUTABLE_SUFFIX); |
#endif |
nstore = (char *) alloca (len); |
startp = endp = temp; |
while (1) |
{ |
if (*endp == PATH_SEPARATOR || *endp == 0) |
{ |
if (endp == startp) |
{ |
nstore[0] = '.'; |
nstore[1] = DIR_SEPARATOR; |
nstore[2] = '\0'; |
} |
else |
{ |
memcpy (nstore, startp, endp - startp); |
if (! IS_DIR_SEPARATOR (endp[-1])) |
{ |
nstore[endp - startp] = DIR_SEPARATOR; |
nstore[endp - startp + 1] = 0; |
} |
else |
nstore[endp - startp] = 0; |
} |
strcat (nstore, progname); |
if (! access (nstore, X_OK) |
#ifdef HAVE_HOST_EXECUTABLE_SUFFIX |
|| ! access (strcat (nstore, HOST_EXECUTABLE_SUFFIX), X_OK) |
#endif |
) |
{ |
#if defined (HAVE_SYS_STAT_H) && defined (S_ISREG) |
struct stat st; |
if (stat (nstore, &st) >= 0 && S_ISREG (st.st_mode)) |
#endif |
{ |
progname = nstore; |
break; |
} |
} |
if (*endp == 0) |
break; |
endp = startp = endp + 1; |
} |
else |
endp++; |
} |
} |
} |
if (resolve_links) |
full_progname = lrealpath (progname); |
else |
full_progname = strdup (progname); |
if (full_progname == NULL) |
return NULL; |
prog_dirs = split_directories (full_progname, &prog_num); |
free (full_progname); |
if (prog_dirs == NULL) |
return NULL; |
bin_dirs = split_directories (bin_prefix, &bin_num); |
if (bin_dirs == NULL) |
goto bailout; |
/* Remove the program name from comparison of directory names. */ |
prog_num--; |
/* If we are still installed in the standard location, we don't need to |
specify relative directories. Also, if argv[0] still doesn't contain |
any directory specifiers after the search above, then there is not much |
we can do. */ |
if (prog_num == bin_num) |
{ |
for (i = 0; i < bin_num; i++) |
{ |
if (strcmp (prog_dirs[i], bin_dirs[i]) != 0) |
break; |
} |
if (prog_num <= 0 || i == bin_num) |
goto bailout; |
} |
prefix_dirs = split_directories (prefix, &prefix_num); |
if (prefix_dirs == NULL) |
goto bailout; |
/* Find how many directories are in common between bin_prefix & prefix. */ |
n = (prefix_num < bin_num) ? prefix_num : bin_num; |
for (common = 0; common < n; common++) |
{ |
if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0) |
break; |
} |
/* If there are no common directories, there can be no relative prefix. */ |
if (common == 0) |
goto bailout; |
/* Two passes: first figure out the size of the result string, and |
then construct it. */ |
needed_len = 0; |
for (i = 0; i < prog_num; i++) |
needed_len += strlen (prog_dirs[i]); |
needed_len += sizeof (DIR_UP) * (bin_num - common); |
for (i = common; i < prefix_num; i++) |
needed_len += strlen (prefix_dirs[i]); |
needed_len += 1; /* Trailing NUL. */ |
ret = (char *) malloc (needed_len); |
if (ret == NULL) |
goto bailout; |
/* Build up the pathnames in argv[0]. */ |
*ret = '\0'; |
for (i = 0; i < prog_num; i++) |
strcat (ret, prog_dirs[i]); |
/* Now build up the ..'s. */ |
ptr = ret + strlen(ret); |
for (i = common; i < bin_num; i++) |
{ |
strcpy (ptr, DIR_UP); |
ptr += sizeof (DIR_UP) - 1; |
*(ptr++) = DIR_SEPARATOR; |
} |
*ptr = '\0'; |
/* Put in directories to move over to prefix. */ |
for (i = common; i < prefix_num; i++) |
strcat (ret, prefix_dirs[i]); |
bailout: |
free_split_directories (prog_dirs); |
free_split_directories (bin_dirs); |
free_split_directories (prefix_dirs); |
return ret; |
} |
/* Do the full job, including symlink resolution. |
This path will find files installed in the same place as the |
program even when a soft link has been made to the program |
from somwhere else. */ |
char * |
make_relative_prefix (const char *progname, const char *bin_prefix, |
const char *prefix) |
{ |
return make_relative_prefix_1 (progname, bin_prefix, prefix, 1); |
} |
/* Make the relative pathname without attempting to resolve any links. |
'..' etc may also be left in the pathname. |
This will find the files the user meant the program to find if the |
installation is patched together with soft links. */ |
char * |
make_relative_prefix_ignore_links (const char *progname, |
const char *bin_prefix, |
const char *prefix) |
{ |
return make_relative_prefix_1 (progname, bin_prefix, prefix, 0); |
} |
/contrib/toolchain/binutils/libiberty/make-temp-file.c |
---|
0,0 → 1,217 |
/* Utility to pick a temporary filename prefix. |
Copyright (C) 1996, 1997, 1998, 2001, 2009, 2010 |
Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If not, |
write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <stdio.h> /* May get P_tmpdir. */ |
#include <sys/types.h> |
#include <errno.h> |
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifdef HAVE_SYS_FILE_H |
#include <sys/file.h> /* May get R_OK, etc. on some systems. */ |
#endif |
#if defined(_WIN32) && !defined(__CYGWIN__) |
#include <windows.h> |
#endif |
#ifndef R_OK |
#define R_OK 4 |
#define W_OK 2 |
#define X_OK 1 |
#endif |
#include "libiberty.h" |
extern int mkstemps (char *, int); |
/* '/' works just fine on MS-DOS based systems. */ |
#ifndef DIR_SEPARATOR |
#define DIR_SEPARATOR '/' |
#endif |
/* Name of temporary file. |
mktemp requires 6 trailing X's. */ |
#define TEMP_FILE "ccXXXXXX" |
#define TEMP_FILE_LEN (sizeof(TEMP_FILE) - 1) |
#if !defined(_WIN32) || defined(__CYGWIN__) |
/* Subroutine of choose_tmpdir. |
If BASE is non-NULL, return it. |
Otherwise it checks if DIR is a usable directory. |
If success, DIR is returned. |
Otherwise NULL is returned. */ |
static inline const char *try_dir (const char *, const char *); |
static inline const char * |
try_dir (const char *dir, const char *base) |
{ |
if (base != 0) |
return base; |
if (dir != 0 |
&& access (dir, R_OK | W_OK | X_OK) == 0) |
return dir; |
return 0; |
} |
static const char tmp[] = { DIR_SEPARATOR, 't', 'm', 'p', 0 }; |
static const char usrtmp[] = |
{ DIR_SEPARATOR, 'u', 's', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 }; |
static const char vartmp[] = |
{ DIR_SEPARATOR, 'v', 'a', 'r', DIR_SEPARATOR, 't', 'm', 'p', 0 }; |
#endif |
static char *memoized_tmpdir; |
/* |
@deftypefn Replacement char* choose_tmpdir () |
Returns a pointer to a directory path suitable for creating temporary |
files in. |
@end deftypefn |
*/ |
char * |
choose_tmpdir (void) |
{ |
if (!memoized_tmpdir) |
{ |
#if !defined(_WIN32) || defined(__CYGWIN__) |
const char *base = 0; |
char *tmpdir; |
unsigned int len; |
#ifdef VMS |
/* Try VMS standard temp logical. */ |
base = try_dir ("/sys$scratch", base); |
#else |
base = try_dir (getenv ("TMPDIR"), base); |
base = try_dir (getenv ("TMP"), base); |
base = try_dir (getenv ("TEMP"), base); |
#endif |
#ifdef P_tmpdir |
/* We really want a directory name here as if concatenated with say \dir |
we do not end up with a double \\ which defines an UNC path. */ |
if (strcmp (P_tmpdir, "\\") == 0) |
base = try_dir ("\\.", base); |
else |
base = try_dir (P_tmpdir, base); |
#endif |
/* Try /var/tmp, /usr/tmp, then /tmp. */ |
base = try_dir (vartmp, base); |
base = try_dir (usrtmp, base); |
base = try_dir (tmp, base); |
/* If all else fails, use the current directory! */ |
if (base == 0) |
base = "."; |
/* Append DIR_SEPARATOR to the directory we've chosen |
and return it. */ |
len = strlen (base); |
tmpdir = XNEWVEC (char, len + 2); |
strcpy (tmpdir, base); |
tmpdir[len] = DIR_SEPARATOR; |
tmpdir[len+1] = '\0'; |
memoized_tmpdir = tmpdir; |
#else /* defined(_WIN32) && !defined(__CYGWIN__) */ |
DWORD len; |
/* Figure out how much space we need. */ |
len = GetTempPath(0, NULL); |
if (len) |
{ |
memoized_tmpdir = XNEWVEC (char, len); |
if (!GetTempPath(len, memoized_tmpdir)) |
{ |
XDELETEVEC (memoized_tmpdir); |
memoized_tmpdir = NULL; |
} |
} |
if (!memoized_tmpdir) |
/* If all else fails, use the current directory. */ |
memoized_tmpdir = xstrdup (".\\"); |
#endif /* defined(_WIN32) && !defined(__CYGWIN__) */ |
} |
return memoized_tmpdir; |
} |
/* |
@deftypefn Replacement char* make_temp_file (const char *@var{suffix}) |
Return a temporary file name (as a string) or @code{NULL} if unable to |
create one. @var{suffix} is a suffix to append to the file name. The |
string is @code{malloc}ed, and the temporary file has been created. |
@end deftypefn |
*/ |
char * |
make_temp_file (const char *suffix) |
{ |
const char *base = choose_tmpdir (); |
char *temp_filename; |
int base_len, suffix_len; |
int fd; |
if (suffix == 0) |
suffix = ""; |
base_len = strlen (base); |
suffix_len = strlen (suffix); |
temp_filename = XNEWVEC (char, base_len |
+ TEMP_FILE_LEN |
+ suffix_len + 1); |
strcpy (temp_filename, base); |
strcpy (temp_filename + base_len, TEMP_FILE); |
strcpy (temp_filename + base_len + TEMP_FILE_LEN, suffix); |
fd = mkstemps (temp_filename, suffix_len); |
/* Mkstemps failed. It may be EPERM, ENOSPC etc. */ |
if (fd == -1) |
{ |
fprintf (stderr, "Cannot create temporary file in %s: %s\n", |
base, strerror (errno)); |
abort (); |
} |
/* We abort on failed close out of sheer paranoia. */ |
if (close (fd)) |
abort (); |
return temp_filename; |
} |
/contrib/toolchain/binutils/libiberty/md5.c |
---|
0,0 → 1,440 |
/* md5.c - Functions to compute MD5 message digest of files or memory blocks |
according to the definition of MD5 in RFC 1321 from April 1992. |
Copyright (C) 1995, 1996, 2011 Free Software Foundation, Inc. |
NOTE: This source is derived from an old version taken from the GNU C |
Library (glibc). |
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ |
/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. */ |
#ifdef HAVE_CONFIG_H |
# include <config.h> |
#endif |
#include <sys/types.h> |
#if STDC_HEADERS || defined _LIBC |
# include <stdlib.h> |
# include <string.h> |
#else |
# ifndef HAVE_MEMCPY |
# define memcpy(d, s, n) bcopy ((s), (d), (n)) |
# endif |
#endif |
#include "ansidecl.h" |
#include "md5.h" |
#ifdef _LIBC |
# include <endian.h> |
# if __BYTE_ORDER == __BIG_ENDIAN |
# define WORDS_BIGENDIAN 1 |
# endif |
#endif |
#ifdef WORDS_BIGENDIAN |
# define SWAP(n) \ |
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) |
#else |
# define SWAP(n) (n) |
#endif |
/* This array contains the bytes used to pad the buffer to the next |
64-byte boundary. (RFC 1321, 3.1: Step 1) */ |
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; |
/* Initialize structure containing state of computation. |
(RFC 1321, 3.3: Step 3) */ |
void |
md5_init_ctx (struct md5_ctx *ctx) |
{ |
ctx->A = (md5_uint32) 0x67452301; |
ctx->B = (md5_uint32) 0xefcdab89; |
ctx->C = (md5_uint32) 0x98badcfe; |
ctx->D = (md5_uint32) 0x10325476; |
ctx->total[0] = ctx->total[1] = 0; |
ctx->buflen = 0; |
} |
/* Put result from CTX in first 16 bytes following RESBUF. The result |
must be in little endian byte order. |
IMPORTANT: RESBUF may not be aligned as strongly as MD5_UNIT32 so we |
put things in a local (aligned) buffer first, then memcpy into RESBUF. */ |
void * |
md5_read_ctx (const struct md5_ctx *ctx, void *resbuf) |
{ |
md5_uint32 buffer[4]; |
buffer[0] = SWAP (ctx->A); |
buffer[1] = SWAP (ctx->B); |
buffer[2] = SWAP (ctx->C); |
buffer[3] = SWAP (ctx->D); |
memcpy (resbuf, buffer, 16); |
return resbuf; |
} |
/* Process the remaining bytes in the internal buffer and the usual |
prolog according to the standard and write the result to RESBUF. |
IMPORTANT: On some systems it is required that RESBUF is correctly |
aligned for a 32 bits value. */ |
void * |
md5_finish_ctx (struct md5_ctx *ctx, void *resbuf) |
{ |
/* Take yet unprocessed bytes into account. */ |
md5_uint32 bytes = ctx->buflen; |
md5_uint32 swap_bytes; |
size_t pad; |
/* Now count remaining bytes. */ |
ctx->total[0] += bytes; |
if (ctx->total[0] < bytes) |
++ctx->total[1]; |
pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; |
memcpy (&ctx->buffer[bytes], fillbuf, pad); |
/* Put the 64-bit file length in *bits* at the end of the buffer. |
Use memcpy to avoid aliasing problems. On most systems, this |
will be optimized away to the same code. */ |
swap_bytes = SWAP (ctx->total[0] << 3); |
memcpy (&ctx->buffer[bytes + pad], &swap_bytes, sizeof (swap_bytes)); |
swap_bytes = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); |
memcpy (&ctx->buffer[bytes + pad + 4], &swap_bytes, sizeof (swap_bytes)); |
/* Process last bytes. */ |
md5_process_block (ctx->buffer, bytes + pad + 8, ctx); |
return md5_read_ctx (ctx, resbuf); |
} |
/* Compute MD5 message digest for bytes read from STREAM. The |
resulting message digest number will be written into the 16 bytes |
beginning at RESBLOCK. */ |
int |
md5_stream (FILE *stream, void *resblock) |
{ |
/* Important: BLOCKSIZE must be a multiple of 64. */ |
#define BLOCKSIZE 4096 |
struct md5_ctx ctx; |
char buffer[BLOCKSIZE + 72]; |
size_t sum; |
/* Initialize the computation context. */ |
md5_init_ctx (&ctx); |
/* Iterate over full file contents. */ |
while (1) |
{ |
/* We read the file in blocks of BLOCKSIZE bytes. One call of the |
computation function processes the whole buffer so that with the |
next round of the loop another block can be read. */ |
size_t n; |
sum = 0; |
/* Read block. Take care for partial reads. */ |
do |
{ |
n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); |
sum += n; |
} |
while (sum < BLOCKSIZE && n != 0); |
if (n == 0 && ferror (stream)) |
return 1; |
/* If end of file is reached, end the loop. */ |
if (n == 0) |
break; |
/* Process buffer with BLOCKSIZE bytes. Note that |
BLOCKSIZE % 64 == 0 |
*/ |
md5_process_block (buffer, BLOCKSIZE, &ctx); |
} |
/* Add the last bytes if necessary. */ |
if (sum > 0) |
md5_process_bytes (buffer, sum, &ctx); |
/* Construct result in desired memory. */ |
md5_finish_ctx (&ctx, resblock); |
return 0; |
} |
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The |
result is always in little endian byte order, so that a byte-wise |
output yields to the wanted ASCII representation of the message |
digest. */ |
void * |
md5_buffer (const char *buffer, size_t len, void *resblock) |
{ |
struct md5_ctx ctx; |
/* Initialize the computation context. */ |
md5_init_ctx (&ctx); |
/* Process whole buffer but last len % 64 bytes. */ |
md5_process_bytes (buffer, len, &ctx); |
/* Put result in desired memory area. */ |
return md5_finish_ctx (&ctx, resblock); |
} |
void |
md5_process_bytes (const void *buffer, size_t len, struct md5_ctx *ctx) |
{ |
/* When we already have some bits in our internal buffer concatenate |
both inputs first. */ |
if (ctx->buflen != 0) |
{ |
size_t left_over = ctx->buflen; |
size_t add = 128 - left_over > len ? len : 128 - left_over; |
memcpy (&ctx->buffer[left_over], buffer, add); |
ctx->buflen += add; |
if (left_over + add > 64) |
{ |
md5_process_block (ctx->buffer, (left_over + add) & ~63, ctx); |
/* The regions in the following copy operation cannot overlap. */ |
memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], |
(left_over + add) & 63); |
ctx->buflen = (left_over + add) & 63; |
} |
buffer = (const void *) ((const char *) buffer + add); |
len -= add; |
} |
/* Process available complete blocks. */ |
if (len > 64) |
{ |
#if !_STRING_ARCH_unaligned |
/* To check alignment gcc has an appropriate operator. Other |
compilers don't. */ |
# if __GNUC__ >= 2 |
# define UNALIGNED_P(p) (((md5_uintptr) p) % __alignof__ (md5_uint32) != 0) |
# else |
# define UNALIGNED_P(p) (((md5_uintptr) p) % sizeof (md5_uint32) != 0) |
# endif |
if (UNALIGNED_P (buffer)) |
while (len > 64) |
{ |
memcpy (ctx->buffer, buffer, 64); |
md5_process_block (ctx->buffer, 64, ctx); |
buffer = (const char *) buffer + 64; |
len -= 64; |
} |
else |
#endif |
{ |
md5_process_block (buffer, len & ~63, ctx); |
buffer = (const void *) ((const char *) buffer + (len & ~63)); |
len &= 63; |
} |
} |
/* Move remaining bytes in internal buffer. */ |
if (len > 0) |
{ |
memcpy (ctx->buffer, buffer, len); |
ctx->buflen = len; |
} |
} |
/* These are the four functions used in the four steps of the MD5 algorithm |
and defined in the RFC 1321. The first function is a little bit optimized |
(as found in Colin Plumbs public domain implementation). */ |
/* #define FF(b, c, d) ((b & c) | (~b & d)) */ |
#define FF(b, c, d) (d ^ (b & (c ^ d))) |
#define FG(b, c, d) FF (d, b, c) |
#define FH(b, c, d) (b ^ c ^ d) |
#define FI(b, c, d) (c ^ (b | ~d)) |
/* Process LEN bytes of BUFFER, accumulating context into CTX. |
It is assumed that LEN % 64 == 0. */ |
void |
md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) |
{ |
md5_uint32 correct_words[16]; |
const md5_uint32 *words = (const md5_uint32 *) buffer; |
size_t nwords = len / sizeof (md5_uint32); |
const md5_uint32 *endp = words + nwords; |
md5_uint32 A = ctx->A; |
md5_uint32 B = ctx->B; |
md5_uint32 C = ctx->C; |
md5_uint32 D = ctx->D; |
/* First increment the byte count. RFC 1321 specifies the possible |
length of the file up to 2^64 bits. Here we only compute the |
number of bytes. Do a double word increment. */ |
ctx->total[0] += len; |
ctx->total[1] += ((len >> 31) >> 1) + (ctx->total[0] < len); |
/* Process all bytes in the buffer with 64 bytes in each round of |
the loop. */ |
while (words < endp) |
{ |
md5_uint32 *cwp = correct_words; |
md5_uint32 A_save = A; |
md5_uint32 B_save = B; |
md5_uint32 C_save = C; |
md5_uint32 D_save = D; |
/* First round: using the given function, the context and a constant |
the next context is computed. Because the algorithms processing |
unit is a 32-bit word and it is determined to work on words in |
little endian byte order we perhaps have to change the byte order |
before the computation. To reduce the work for the next steps |
we store the swapped words in the array CORRECT_WORDS. */ |
#define OP(a, b, c, d, s, T) \ |
do \ |
{ \ |
a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \ |
++words; \ |
CYCLIC (a, s); \ |
a += b; \ |
} \ |
while (0) |
/* It is unfortunate that C does not provide an operator for |
cyclic rotation. Hope the C compiler is smart enough. */ |
#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s))) |
/* Before we start, one word to the strange constants. |
They are defined in RFC 1321 as |
T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 |
*/ |
/* Round 1. */ |
OP (A, B, C, D, 7, (md5_uint32) 0xd76aa478); |
OP (D, A, B, C, 12, (md5_uint32) 0xe8c7b756); |
OP (C, D, A, B, 17, (md5_uint32) 0x242070db); |
OP (B, C, D, A, 22, (md5_uint32) 0xc1bdceee); |
OP (A, B, C, D, 7, (md5_uint32) 0xf57c0faf); |
OP (D, A, B, C, 12, (md5_uint32) 0x4787c62a); |
OP (C, D, A, B, 17, (md5_uint32) 0xa8304613); |
OP (B, C, D, A, 22, (md5_uint32) 0xfd469501); |
OP (A, B, C, D, 7, (md5_uint32) 0x698098d8); |
OP (D, A, B, C, 12, (md5_uint32) 0x8b44f7af); |
OP (C, D, A, B, 17, (md5_uint32) 0xffff5bb1); |
OP (B, C, D, A, 22, (md5_uint32) 0x895cd7be); |
OP (A, B, C, D, 7, (md5_uint32) 0x6b901122); |
OP (D, A, B, C, 12, (md5_uint32) 0xfd987193); |
OP (C, D, A, B, 17, (md5_uint32) 0xa679438e); |
OP (B, C, D, A, 22, (md5_uint32) 0x49b40821); |
/* For the second to fourth round we have the possibly swapped words |
in CORRECT_WORDS. Redefine the macro to take an additional first |
argument specifying the function to use. */ |
#undef OP |
#define OP(a, b, c, d, k, s, T) \ |
do \ |
{ \ |
a += FX (b, c, d) + correct_words[k] + T; \ |
CYCLIC (a, s); \ |
a += b; \ |
} \ |
while (0) |
#define FX(b, c, d) FG (b, c, d) |
/* Round 2. */ |
OP (A, B, C, D, 1, 5, (md5_uint32) 0xf61e2562); |
OP (D, A, B, C, 6, 9, (md5_uint32) 0xc040b340); |
OP (C, D, A, B, 11, 14, (md5_uint32) 0x265e5a51); |
OP (B, C, D, A, 0, 20, (md5_uint32) 0xe9b6c7aa); |
OP (A, B, C, D, 5, 5, (md5_uint32) 0xd62f105d); |
OP (D, A, B, C, 10, 9, (md5_uint32) 0x02441453); |
OP (C, D, A, B, 15, 14, (md5_uint32) 0xd8a1e681); |
OP (B, C, D, A, 4, 20, (md5_uint32) 0xe7d3fbc8); |
OP (A, B, C, D, 9, 5, (md5_uint32) 0x21e1cde6); |
OP (D, A, B, C, 14, 9, (md5_uint32) 0xc33707d6); |
OP (C, D, A, B, 3, 14, (md5_uint32) 0xf4d50d87); |
OP (B, C, D, A, 8, 20, (md5_uint32) 0x455a14ed); |
OP (A, B, C, D, 13, 5, (md5_uint32) 0xa9e3e905); |
OP (D, A, B, C, 2, 9, (md5_uint32) 0xfcefa3f8); |
OP (C, D, A, B, 7, 14, (md5_uint32) 0x676f02d9); |
OP (B, C, D, A, 12, 20, (md5_uint32) 0x8d2a4c8a); |
#undef FX |
#define FX(b, c, d) FH (b, c, d) |
/* Round 3. */ |
OP (A, B, C, D, 5, 4, (md5_uint32) 0xfffa3942); |
OP (D, A, B, C, 8, 11, (md5_uint32) 0x8771f681); |
OP (C, D, A, B, 11, 16, (md5_uint32) 0x6d9d6122); |
OP (B, C, D, A, 14, 23, (md5_uint32) 0xfde5380c); |
OP (A, B, C, D, 1, 4, (md5_uint32) 0xa4beea44); |
OP (D, A, B, C, 4, 11, (md5_uint32) 0x4bdecfa9); |
OP (C, D, A, B, 7, 16, (md5_uint32) 0xf6bb4b60); |
OP (B, C, D, A, 10, 23, (md5_uint32) 0xbebfbc70); |
OP (A, B, C, D, 13, 4, (md5_uint32) 0x289b7ec6); |
OP (D, A, B, C, 0, 11, (md5_uint32) 0xeaa127fa); |
OP (C, D, A, B, 3, 16, (md5_uint32) 0xd4ef3085); |
OP (B, C, D, A, 6, 23, (md5_uint32) 0x04881d05); |
OP (A, B, C, D, 9, 4, (md5_uint32) 0xd9d4d039); |
OP (D, A, B, C, 12, 11, (md5_uint32) 0xe6db99e5); |
OP (C, D, A, B, 15, 16, (md5_uint32) 0x1fa27cf8); |
OP (B, C, D, A, 2, 23, (md5_uint32) 0xc4ac5665); |
#undef FX |
#define FX(b, c, d) FI (b, c, d) |
/* Round 4. */ |
OP (A, B, C, D, 0, 6, (md5_uint32) 0xf4292244); |
OP (D, A, B, C, 7, 10, (md5_uint32) 0x432aff97); |
OP (C, D, A, B, 14, 15, (md5_uint32) 0xab9423a7); |
OP (B, C, D, A, 5, 21, (md5_uint32) 0xfc93a039); |
OP (A, B, C, D, 12, 6, (md5_uint32) 0x655b59c3); |
OP (D, A, B, C, 3, 10, (md5_uint32) 0x8f0ccc92); |
OP (C, D, A, B, 10, 15, (md5_uint32) 0xffeff47d); |
OP (B, C, D, A, 1, 21, (md5_uint32) 0x85845dd1); |
OP (A, B, C, D, 8, 6, (md5_uint32) 0x6fa87e4f); |
OP (D, A, B, C, 15, 10, (md5_uint32) 0xfe2ce6e0); |
OP (C, D, A, B, 6, 15, (md5_uint32) 0xa3014314); |
OP (B, C, D, A, 13, 21, (md5_uint32) 0x4e0811a1); |
OP (A, B, C, D, 4, 6, (md5_uint32) 0xf7537e82); |
OP (D, A, B, C, 11, 10, (md5_uint32) 0xbd3af235); |
OP (C, D, A, B, 2, 15, (md5_uint32) 0x2ad7d2bb); |
OP (B, C, D, A, 9, 21, (md5_uint32) 0xeb86d391); |
/* Add the starting values of the context. */ |
A += A_save; |
B += B_save; |
C += C_save; |
D += D_save; |
} |
/* Put checksum in context given as argument. */ |
ctx->A = A; |
ctx->B = B; |
ctx->C = C; |
ctx->D = D; |
} |
/contrib/toolchain/binutils/libiberty/memmem.c |
---|
0,0 → 1,71 |
/* Copyright (C) 1991,92,93,94,96,97,98,2000,2004,2007,2011 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Supplemental void* memmem (const void *@var{haystack}, @ |
size_t @var{haystack_len} const void *@var{needle}, size_t @var{needle_len}) |
Returns a pointer to the first occurrence of @var{needle} (length |
@var{needle_len}) in @var{haystack} (length @var{haystack_len}). |
Returns @code{NULL} if not found. |
@end deftypefn |
*/ |
#ifndef _LIBC |
# include <config.h> |
#endif |
#include <stddef.h> |
#include <string.h> |
#ifndef _LIBC |
# define __builtin_expect(expr, val) (expr) |
#endif |
#undef memmem |
/* Return the first occurrence of NEEDLE in HAYSTACK. */ |
void * |
memmem (const void *haystack, size_t haystack_len, const void *needle, |
size_t needle_len) |
{ |
const char *begin; |
const char *const last_possible |
= (const char *) haystack + haystack_len - needle_len; |
if (needle_len == 0) |
/* The first occurrence of the empty string is deemed to occur at |
the beginning of the string. */ |
return (void *) haystack; |
/* Sanity check, otherwise the loop might search through the whole |
memory. */ |
if (__builtin_expect (haystack_len < needle_len, 0)) |
return NULL; |
for (begin = (const char *) haystack; begin <= last_possible; ++begin) |
if (begin[0] == ((const char *) needle)[0] && |
!memcmp ((const void *) &begin[1], |
(const void *) ((const char *) needle + 1), |
needle_len - 1)) |
return (void *) begin; |
return NULL; |
} |
/contrib/toolchain/binutils/libiberty/mempcpy.c |
---|
0,0 → 1,42 |
/* Implement the mempcpy function. |
Copyright (C) 2003, 2004, 2005, 2011 Free Software Foundation, Inc. |
Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Supplemental void* mempcpy (void *@var{out}, const void *@var{in}, @ |
size_t @var{length}) |
Copies @var{length} bytes from memory region @var{in} to region |
@var{out}. Returns a pointer to @var{out} + @var{length}. |
@end deftypefn |
*/ |
#include <ansidecl.h> |
#include <stddef.h> |
extern PTR memcpy (PTR, const PTR, size_t); |
PTR |
mempcpy (PTR dst, const PTR src, size_t len) |
{ |
return (char *) memcpy (dst, src, len) + len; |
} |
/contrib/toolchain/binutils/libiberty/mkstemps.c |
---|
0,0 → 1,147 |
/* Copyright (C) 1991, 1992, 1996, 1998, 2004 Free Software Foundation, Inc. |
This file is derived from mkstemp.c from the GNU C Library. |
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., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <sys/types.h> |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#include <errno.h> |
#include <stdio.h> |
#include <fcntl.h> |
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
#ifdef HAVE_SYS_TIME_H |
#include <sys/time.h> |
#endif |
#include "ansidecl.h" |
/* We need to provide a type for gcc_uint64_t. */ |
#ifdef __GNUC__ |
__extension__ typedef unsigned long long gcc_uint64_t; |
#else |
typedef unsigned long gcc_uint64_t; |
#endif |
#ifndef TMP_MAX |
#define TMP_MAX 16384 |
#endif |
#ifndef O_BINARY |
# define O_BINARY 0 |
#endif |
/* |
@deftypefn Replacement int mkstemps (char *@var{pattern}, int @var{suffix_len}) |
Generate a unique temporary file name from @var{pattern}. |
@var{pattern} has the form: |
@example |
@var{path}/ccXXXXXX@var{suffix} |
@end example |
@var{suffix_len} tells us how long @var{suffix} is (it can be zero |
length). The last six characters of @var{pattern} before @var{suffix} |
must be @samp{XXXXXX}; they are replaced with a string that makes the |
filename unique. Returns a file descriptor open on the file for |
reading and writing. |
@end deftypefn |
*/ |
int |
mkstemps (char *pattern, int suffix_len) |
{ |
static const char letters[] |
= "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; |
static gcc_uint64_t value; |
#ifdef HAVE_GETTIMEOFDAY |
struct timeval tv; |
#endif |
char *XXXXXX; |
size_t len; |
int count; |
len = strlen (pattern); |
if ((int) len < 6 + suffix_len |
|| strncmp (&pattern[len - 6 - suffix_len], "XXXXXX", 6)) |
{ |
return -1; |
} |
XXXXXX = &pattern[len - 6 - suffix_len]; |
#ifdef HAVE_GETTIMEOFDAY |
/* Get some more or less random data. */ |
gettimeofday (&tv, NULL); |
value += ((gcc_uint64_t) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid (); |
#else |
value += getpid (); |
#endif |
for (count = 0; count < TMP_MAX; ++count) |
{ |
gcc_uint64_t v = value; |
int fd; |
/* Fill in the random bits. */ |
XXXXXX[0] = letters[v % 62]; |
v /= 62; |
XXXXXX[1] = letters[v % 62]; |
v /= 62; |
XXXXXX[2] = letters[v % 62]; |
v /= 62; |
XXXXXX[3] = letters[v % 62]; |
v /= 62; |
XXXXXX[4] = letters[v % 62]; |
v /= 62; |
XXXXXX[5] = letters[v % 62]; |
fd = open (pattern, O_BINARY|O_RDWR|O_CREAT|O_EXCL, 0600); |
if (fd >= 0) |
/* The file does not exist. */ |
return fd; |
if (errno != EEXIST |
#ifdef EISDIR |
&& errno != EISDIR |
#endif |
) |
/* Fatal error (EPERM, ENOSPC etc). Doesn't make sense to loop. */ |
break; |
/* This is a random value. It is only necessary that the next |
TMP_MAX values generated by adding 7777 to VALUE are different |
with (module 2^32). */ |
value += 7777; |
} |
/* We return the null string if we can't find a unique file name. */ |
pattern[0] = '\0'; |
return -1; |
} |
/contrib/toolchain/binutils/libiberty/objalloc.c |
---|
0,0 → 1,298 |
/* objalloc.c -- routines to allocate memory for objects |
Copyright 1997-2012 Free Software Foundation, Inc. |
Written by Ian Lance Taylor, Cygnus Solutions. |
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, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#include "config.h" |
#include "ansidecl.h" |
#include "objalloc.h" |
/* Get a definition for NULL. */ |
#include <stdio.h> |
#if VMS |
#include <stdlib.h> |
#include <unixlib.h> |
#else |
/* Get a definition for size_t. */ |
#include <stddef.h> |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#else |
/* For systems with larger pointers than ints, this must be declared. */ |
extern PTR malloc (size_t); |
extern void free (PTR); |
#endif |
#endif |
/* These routines allocate space for an object. Freeing allocated |
space may or may not free all more recently allocated space. |
We handle large and small allocation requests differently. If we |
don't have enough space in the current block, and the allocation |
request is for more than 512 bytes, we simply pass it through to |
malloc. */ |
/* The objalloc structure is defined in objalloc.h. */ |
/* This structure appears at the start of each chunk. */ |
struct objalloc_chunk |
{ |
/* Next chunk. */ |
struct objalloc_chunk *next; |
/* If this chunk contains large objects, this is the value of |
current_ptr when this chunk was allocated. If this chunk |
contains small objects, this is NULL. */ |
char *current_ptr; |
}; |
/* The aligned size of objalloc_chunk. */ |
#define CHUNK_HEADER_SIZE \ |
((sizeof (struct objalloc_chunk) + OBJALLOC_ALIGN - 1) \ |
&~ (OBJALLOC_ALIGN - 1)) |
/* We ask for this much memory each time we create a chunk which is to |
hold small objects. */ |
#define CHUNK_SIZE (4096 - 32) |
/* A request for this amount or more is just passed through to malloc. */ |
#define BIG_REQUEST (512) |
/* Create an objalloc structure. */ |
struct objalloc * |
objalloc_create (void) |
{ |
struct objalloc *ret; |
struct objalloc_chunk *chunk; |
ret = (struct objalloc *) malloc (sizeof *ret); |
if (ret == NULL) |
return NULL; |
ret->chunks = (PTR) malloc (CHUNK_SIZE); |
if (ret->chunks == NULL) |
{ |
free (ret); |
return NULL; |
} |
chunk = (struct objalloc_chunk *) ret->chunks; |
chunk->next = NULL; |
chunk->current_ptr = NULL; |
ret->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE; |
ret->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE; |
return ret; |
} |
/* Allocate space from an objalloc structure. */ |
PTR |
_objalloc_alloc (struct objalloc *o, unsigned long original_len) |
{ |
unsigned long len = original_len; |
/* We avoid confusion from zero sized objects by always allocating |
at least 1 byte. */ |
if (len == 0) |
len = 1; |
len = (len + OBJALLOC_ALIGN - 1) &~ (OBJALLOC_ALIGN - 1); |
/* Check for overflow in the alignment operation above and the |
malloc argument below. */ |
if (len + CHUNK_HEADER_SIZE < original_len) |
return NULL; |
if (len <= o->current_space) |
{ |
o->current_ptr += len; |
o->current_space -= len; |
return (PTR) (o->current_ptr - len); |
} |
if (len >= BIG_REQUEST) |
{ |
char *ret; |
struct objalloc_chunk *chunk; |
ret = (char *) malloc (CHUNK_HEADER_SIZE + len); |
if (ret == NULL) |
return NULL; |
chunk = (struct objalloc_chunk *) ret; |
chunk->next = (struct objalloc_chunk *) o->chunks; |
chunk->current_ptr = o->current_ptr; |
o->chunks = (PTR) chunk; |
return (PTR) (ret + CHUNK_HEADER_SIZE); |
} |
else |
{ |
struct objalloc_chunk *chunk; |
chunk = (struct objalloc_chunk *) malloc (CHUNK_SIZE); |
if (chunk == NULL) |
return NULL; |
chunk->next = (struct objalloc_chunk *) o->chunks; |
chunk->current_ptr = NULL; |
o->current_ptr = (char *) chunk + CHUNK_HEADER_SIZE; |
o->current_space = CHUNK_SIZE - CHUNK_HEADER_SIZE; |
o->chunks = (PTR) chunk; |
return objalloc_alloc (o, len); |
} |
} |
/* Free an entire objalloc structure. */ |
void |
objalloc_free (struct objalloc *o) |
{ |
struct objalloc_chunk *l; |
l = (struct objalloc_chunk *) o->chunks; |
while (l != NULL) |
{ |
struct objalloc_chunk *next; |
next = l->next; |
free (l); |
l = next; |
} |
free (o); |
} |
/* Free a block from an objalloc structure. This also frees all more |
recently allocated blocks. */ |
void |
objalloc_free_block (struct objalloc *o, PTR block) |
{ |
struct objalloc_chunk *p, *small; |
char *b = (char *) block; |
/* First set P to the chunk which contains the block we are freeing, |
and set Q to the last small object chunk we see before P. */ |
small = NULL; |
for (p = (struct objalloc_chunk *) o->chunks; p != NULL; p = p->next) |
{ |
if (p->current_ptr == NULL) |
{ |
if (b > (char *) p && b < (char *) p + CHUNK_SIZE) |
break; |
small = p; |
} |
else |
{ |
if (b == (char *) p + CHUNK_HEADER_SIZE) |
break; |
} |
} |
/* If we can't find the chunk, the caller has made a mistake. */ |
if (p == NULL) |
abort (); |
if (p->current_ptr == NULL) |
{ |
struct objalloc_chunk *q; |
struct objalloc_chunk *first; |
/* The block is in a chunk containing small objects. We can |
free every chunk through SMALL, because they have certainly |
been allocated more recently. After SMALL, we will not see |
any chunks containing small objects; we can free any big |
chunk if the current_ptr is greater than or equal to B. We |
can then reset the new current_ptr to B. */ |
first = NULL; |
q = (struct objalloc_chunk *) o->chunks; |
while (q != p) |
{ |
struct objalloc_chunk *next; |
next = q->next; |
if (small != NULL) |
{ |
if (small == q) |
small = NULL; |
free (q); |
} |
else if (q->current_ptr > b) |
free (q); |
else if (first == NULL) |
first = q; |
q = next; |
} |
if (first == NULL) |
first = p; |
o->chunks = (PTR) first; |
/* Now start allocating from this small block again. */ |
o->current_ptr = b; |
o->current_space = ((char *) p + CHUNK_SIZE) - b; |
} |
else |
{ |
struct objalloc_chunk *q; |
char *current_ptr; |
/* This block is in a large chunk by itself. We can free |
everything on the list up to and including this block. We |
then start allocating from the next chunk containing small |
objects, setting current_ptr from the value stored with the |
large chunk we are freeing. */ |
current_ptr = p->current_ptr; |
p = p->next; |
q = (struct objalloc_chunk *) o->chunks; |
while (q != p) |
{ |
struct objalloc_chunk *next; |
next = q->next; |
free (q); |
q = next; |
} |
o->chunks = (PTR) p; |
while (p->current_ptr != NULL) |
p = p->next; |
o->current_ptr = current_ptr; |
o->current_space = ((char *) p + CHUNK_SIZE) - current_ptr; |
} |
} |
/contrib/toolchain/binutils/libiberty/obstack.c |
---|
0,0 → 1,510 |
/* obstack.c - subroutines used implicitly by object stack macros |
Copyright (C) 1988,89,90,91,92,93,94,96,97 Free Software Foundation, Inc. |
NOTE: This source is derived from an old version taken from the GNU C |
Library (glibc). |
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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, |
USA. */ |
#ifdef HAVE_CONFIG_H |
#include <config.h> |
#endif |
#include "obstack.h" |
/* NOTE BEFORE MODIFYING THIS FILE: This version number must be |
incremented whenever callers compiled using an old obstack.h can no |
longer properly call the functions in this obstack.c. */ |
#define OBSTACK_INTERFACE_VERSION 1 |
/* Comment out all this code if we are using the GNU C Library, and are not |
actually compiling the library itself, and the installed library |
supports the same library interface we do. This code is part of the GNU |
C Library, but also included in many other GNU distributions. Compiling |
and linking in this code is a waste when using the GNU C library |
(especially if it is a shared library). Rather than having every GNU |
program understand `configure --with-gnu-libc' and omit the object |
files, it is simpler to just do this in the source for each such file. */ |
#include <stdio.h> /* Random thing to get __GNU_LIBRARY__. */ |
#if !defined (_LIBC) && defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1 |
#include <gnu-versions.h> |
#if _GNU_OBSTACK_INTERFACE_VERSION == OBSTACK_INTERFACE_VERSION |
#define ELIDE_CODE |
#endif |
#endif |
#ifndef ELIDE_CODE |
#define POINTER void * |
/* Determine default alignment. */ |
struct fooalign {char x; double d;}; |
#define DEFAULT_ALIGNMENT \ |
((PTR_INT_TYPE) ((char *) &((struct fooalign *) 0)->d - (char *) 0)) |
/* If malloc were really smart, it would round addresses to DEFAULT_ALIGNMENT. |
But in fact it might be less smart and round addresses to as much as |
DEFAULT_ROUNDING. So we prepare for it to do that. */ |
union fooround {long x; double d;}; |
#define DEFAULT_ROUNDING (sizeof (union fooround)) |
/* When we copy a long block of data, this is the unit to do it with. |
On some machines, copying successive ints does not work; |
in such a case, redefine COPYING_UNIT to `long' (if that works) |
or `char' as a last resort. */ |
#ifndef COPYING_UNIT |
#define COPYING_UNIT int |
#endif |
/* The functions allocating more room by calling `obstack_chunk_alloc' |
jump to the handler pointed to by `obstack_alloc_failed_handler'. |
This variable by default points to the internal function |
`print_and_abort'. */ |
static void print_and_abort (void); |
void (*obstack_alloc_failed_handler) (void) = print_and_abort; |
/* Exit value used when `print_and_abort' is used. */ |
#if defined __GNU_LIBRARY__ || defined HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifndef EXIT_FAILURE |
#define EXIT_FAILURE 1 |
#endif |
int obstack_exit_failure = EXIT_FAILURE; |
/* The non-GNU-C macros copy the obstack into this global variable |
to avoid multiple evaluation. */ |
struct obstack *_obstack; |
/* Define a macro that either calls functions with the traditional malloc/free |
calling interface, or calls functions with the mmalloc/mfree interface |
(that adds an extra first argument), based on the state of use_extra_arg. |
For free, do not use ?:, since some compilers, like the MIPS compilers, |
do not allow (expr) ? void : void. */ |
#if defined (__STDC__) && __STDC__ |
#define CALL_CHUNKFUN(h, size) \ |
(((h) -> use_extra_arg) \ |
? (*(h)->chunkfun) ((h)->extra_arg, (size)) \ |
: (*(struct _obstack_chunk *(*) (long)) (h)->chunkfun) ((size))) |
#define CALL_FREEFUN(h, old_chunk) \ |
do { \ |
if ((h) -> use_extra_arg) \ |
(*(h)->freefun) ((h)->extra_arg, (old_chunk)); \ |
else \ |
(*(void (*) (void *)) (h)->freefun) ((old_chunk)); \ |
} while (0) |
#else |
#define CALL_CHUNKFUN(h, size) \ |
(((h) -> use_extra_arg) \ |
? (*(h)->chunkfun) ((h)->extra_arg, (size)) \ |
: (*(struct _obstack_chunk *(*) ()) (h)->chunkfun) ((size))) |
#define CALL_FREEFUN(h, old_chunk) \ |
do { \ |
if ((h) -> use_extra_arg) \ |
(*(h)->freefun) ((h)->extra_arg, (old_chunk)); \ |
else \ |
(*(void (*) ()) (h)->freefun) ((old_chunk)); \ |
} while (0) |
#endif |
/* Initialize an obstack H for use. Specify chunk size SIZE (0 means default). |
Objects start on multiples of ALIGNMENT (0 means use default). |
CHUNKFUN is the function to use to allocate chunks, |
and FREEFUN the function to free them. |
Return nonzero if successful, zero if out of memory. |
To recover from an out of memory error, |
free up some memory, then call this again. */ |
int |
_obstack_begin (struct obstack *h, int size, int alignment, |
POINTER (*chunkfun) (long), void (*freefun) (void *)) |
{ |
register struct _obstack_chunk *chunk; /* points to new chunk */ |
if (alignment == 0) |
alignment = (int) DEFAULT_ALIGNMENT; |
if (size == 0) |
/* Default size is what GNU malloc can fit in a 4096-byte block. */ |
{ |
/* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. |
Use the values for range checking, because if range checking is off, |
the extra bytes won't be missed terribly, but if range checking is on |
and we used a larger request, a whole extra 4096 bytes would be |
allocated. |
These number are irrelevant to the new GNU malloc. I suspect it is |
less sensitive to the size of the request. */ |
int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) |
+ 4 + DEFAULT_ROUNDING - 1) |
& ~(DEFAULT_ROUNDING - 1)); |
size = 4096 - extra; |
} |
h->chunkfun = (struct _obstack_chunk * (*)(void *, long)) chunkfun; |
h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun; |
h->chunk_size = size; |
h->alignment_mask = alignment - 1; |
h->use_extra_arg = 0; |
chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); |
if (!chunk) |
(*obstack_alloc_failed_handler) (); |
h->next_free = h->object_base = chunk->contents; |
h->chunk_limit = chunk->limit |
= (char *) chunk + h->chunk_size; |
chunk->prev = 0; |
/* The initial chunk now contains no empty object. */ |
h->maybe_empty_object = 0; |
h->alloc_failed = 0; |
return 1; |
} |
int |
_obstack_begin_1 (struct obstack *h, int size, int alignment, |
POINTER (*chunkfun) (POINTER, long), |
void (*freefun) (POINTER, POINTER), POINTER arg) |
{ |
register struct _obstack_chunk *chunk; /* points to new chunk */ |
if (alignment == 0) |
alignment = (int) DEFAULT_ALIGNMENT; |
if (size == 0) |
/* Default size is what GNU malloc can fit in a 4096-byte block. */ |
{ |
/* 12 is sizeof (mhead) and 4 is EXTRA from GNU malloc. |
Use the values for range checking, because if range checking is off, |
the extra bytes won't be missed terribly, but if range checking is on |
and we used a larger request, a whole extra 4096 bytes would be |
allocated. |
These number are irrelevant to the new GNU malloc. I suspect it is |
less sensitive to the size of the request. */ |
int extra = ((((12 + DEFAULT_ROUNDING - 1) & ~(DEFAULT_ROUNDING - 1)) |
+ 4 + DEFAULT_ROUNDING - 1) |
& ~(DEFAULT_ROUNDING - 1)); |
size = 4096 - extra; |
} |
h->chunkfun = (struct _obstack_chunk * (*)(void *,long)) chunkfun; |
h->freefun = (void (*) (void *, struct _obstack_chunk *)) freefun; |
h->chunk_size = size; |
h->alignment_mask = alignment - 1; |
h->extra_arg = arg; |
h->use_extra_arg = 1; |
chunk = h->chunk = CALL_CHUNKFUN (h, h -> chunk_size); |
if (!chunk) |
(*obstack_alloc_failed_handler) (); |
h->next_free = h->object_base = chunk->contents; |
h->chunk_limit = chunk->limit |
= (char *) chunk + h->chunk_size; |
chunk->prev = 0; |
/* The initial chunk now contains no empty object. */ |
h->maybe_empty_object = 0; |
h->alloc_failed = 0; |
return 1; |
} |
/* Allocate a new current chunk for the obstack *H |
on the assumption that LENGTH bytes need to be added |
to the current object, or a new object of length LENGTH allocated. |
Copies any partial object from the end of the old chunk |
to the beginning of the new one. */ |
void |
_obstack_newchunk (struct obstack *h, int length) |
{ |
register struct _obstack_chunk *old_chunk = h->chunk; |
register struct _obstack_chunk *new_chunk; |
register long new_size; |
register long obj_size = h->next_free - h->object_base; |
register long i; |
long already; |
/* Compute size for new chunk. */ |
new_size = (obj_size + length) + (obj_size >> 3) + 100; |
if (new_size < h->chunk_size) |
new_size = h->chunk_size; |
/* Allocate and initialize the new chunk. */ |
new_chunk = CALL_CHUNKFUN (h, new_size); |
if (!new_chunk) |
(*obstack_alloc_failed_handler) (); |
h->chunk = new_chunk; |
new_chunk->prev = old_chunk; |
new_chunk->limit = h->chunk_limit = (char *) new_chunk + new_size; |
/* Move the existing object to the new chunk. |
Word at a time is fast and is safe if the object |
is sufficiently aligned. */ |
if (h->alignment_mask + 1 >= DEFAULT_ALIGNMENT) |
{ |
for (i = obj_size / sizeof (COPYING_UNIT) - 1; |
i >= 0; i--) |
((COPYING_UNIT *)new_chunk->contents)[i] |
= ((COPYING_UNIT *)h->object_base)[i]; |
/* We used to copy the odd few remaining bytes as one extra COPYING_UNIT, |
but that can cross a page boundary on a machine |
which does not do strict alignment for COPYING_UNITS. */ |
already = obj_size / sizeof (COPYING_UNIT) * sizeof (COPYING_UNIT); |
} |
else |
already = 0; |
/* Copy remaining bytes one by one. */ |
for (i = already; i < obj_size; i++) |
new_chunk->contents[i] = h->object_base[i]; |
/* If the object just copied was the only data in OLD_CHUNK, |
free that chunk and remove it from the chain. |
But not if that chunk might contain an empty object. */ |
if (h->object_base == old_chunk->contents && ! h->maybe_empty_object) |
{ |
new_chunk->prev = old_chunk->prev; |
CALL_FREEFUN (h, old_chunk); |
} |
h->object_base = new_chunk->contents; |
h->next_free = h->object_base + obj_size; |
/* The new chunk certainly contains no empty object yet. */ |
h->maybe_empty_object = 0; |
} |
/* Return nonzero if object OBJ has been allocated from obstack H. |
This is here for debugging. |
If you use it in a program, you are probably losing. */ |
/* Suppress -Wmissing-prototypes warning. We don't want to declare this in |
obstack.h because it is just for debugging. */ |
int _obstack_allocated_p (struct obstack *h, POINTER obj); |
int |
_obstack_allocated_p (struct obstack *h, POINTER obj) |
{ |
register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ |
register struct _obstack_chunk *plp; /* point to previous chunk if any */ |
lp = (h)->chunk; |
/* We use >= rather than > since the object cannot be exactly at |
the beginning of the chunk but might be an empty object exactly |
at the end of an adjacent chunk. */ |
while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj)) |
{ |
plp = lp->prev; |
lp = plp; |
} |
return lp != 0; |
} |
/* Free objects in obstack H, including OBJ and everything allocate |
more recently than OBJ. If OBJ is zero, free everything in H. */ |
#undef obstack_free |
/* This function has two names with identical definitions. |
This is the first one, called from non-ANSI code. */ |
void |
_obstack_free (struct obstack *h, POINTER obj) |
{ |
register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ |
register struct _obstack_chunk *plp; /* point to previous chunk if any */ |
lp = h->chunk; |
/* We use >= because there cannot be an object at the beginning of a chunk. |
But there can be an empty object at that address |
at the end of another chunk. */ |
while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj)) |
{ |
plp = lp->prev; |
CALL_FREEFUN (h, lp); |
lp = plp; |
/* If we switch chunks, we can't tell whether the new current |
chunk contains an empty object, so assume that it may. */ |
h->maybe_empty_object = 1; |
} |
if (lp) |
{ |
h->object_base = h->next_free = (char *) (obj); |
h->chunk_limit = lp->limit; |
h->chunk = lp; |
} |
else if (obj != 0) |
/* obj is not in any of the chunks! */ |
abort (); |
} |
/* This function is used from ANSI code. */ |
void |
obstack_free (struct obstack *h, POINTER obj) |
{ |
register struct _obstack_chunk *lp; /* below addr of any objects in this chunk */ |
register struct _obstack_chunk *plp; /* point to previous chunk if any */ |
lp = h->chunk; |
/* We use >= because there cannot be an object at the beginning of a chunk. |
But there can be an empty object at that address |
at the end of another chunk. */ |
while (lp != 0 && ((POINTER) lp >= obj || (POINTER) (lp)->limit < obj)) |
{ |
plp = lp->prev; |
CALL_FREEFUN (h, lp); |
lp = plp; |
/* If we switch chunks, we can't tell whether the new current |
chunk contains an empty object, so assume that it may. */ |
h->maybe_empty_object = 1; |
} |
if (lp) |
{ |
h->object_base = h->next_free = (char *) (obj); |
h->chunk_limit = lp->limit; |
h->chunk = lp; |
} |
else if (obj != 0) |
/* obj is not in any of the chunks! */ |
abort (); |
} |
int |
_obstack_memory_used (struct obstack *h) |
{ |
register struct _obstack_chunk* lp; |
register int nbytes = 0; |
for (lp = h->chunk; lp != 0; lp = lp->prev) |
{ |
nbytes += lp->limit - (char *) lp; |
} |
return nbytes; |
} |
/* Define the error handler. */ |
#ifndef _ |
# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC |
# include <libintl.h> |
# ifndef _ |
# define _(Str) gettext (Str) |
# endif |
# else |
# define _(Str) (Str) |
# endif |
#endif |
static void |
print_and_abort (void) |
{ |
fputs (_("memory exhausted\n"), stderr); |
exit (obstack_exit_failure); |
} |
#if 0 |
/* These are now turned off because the applications do not use it |
and it uses bcopy via obstack_grow, which causes trouble on sysV. */ |
/* Now define the functional versions of the obstack macros. |
Define them to simply use the corresponding macros to do the job. */ |
/* The function names appear in parentheses in order to prevent |
the macro-definitions of the names from being expanded there. */ |
POINTER (obstack_base) (struct obstack *obstack) |
{ |
return obstack_base (obstack); |
} |
POINTER (obstack_next_free) (struct obstack *obstack) |
{ |
return obstack_next_free (obstack); |
} |
int (obstack_object_size) (struct obstack *obstack) |
{ |
return obstack_object_size (obstack); |
} |
int (obstack_room) (struct obstack *obstack) |
{ |
return obstack_room (obstack); |
} |
int (obstack_make_room) (struct obstack *obstack, int length) |
{ |
return obstack_make_room (obstack, length); |
} |
void (obstack_grow) (struct obstack *obstack, POINTER pointer, int length) |
{ |
obstack_grow (obstack, pointer, length); |
} |
void (obstack_grow0) (struct obstack *obstack, POINTER pointer, int length) |
{ |
obstack_grow0 (obstack, pointer, length); |
} |
void (obstack_1grow) (struct obstack *obstack, int character) |
{ |
obstack_1grow (obstack, character); |
} |
void (obstack_blank) (struct obstack *obstack, int length) |
{ |
obstack_blank (obstack, length); |
} |
void (obstack_1grow_fast) (struct obstack *obstack, int character) |
{ |
obstack_1grow_fast (obstack, character); |
} |
void (obstack_blank_fast) (struct obstack *obstack, int length) |
{ |
obstack_blank_fast (obstack, length); |
} |
POINTER (obstack_finish) (struct obstack *obstack) |
{ |
return obstack_finish (obstack); |
} |
POINTER (obstack_alloc) (struct obstack *obstack, int length) |
{ |
return obstack_alloc (obstack, length); |
} |
POINTER (obstack_copy) (struct obstack *obstack, POINTER pointer, int length) |
{ |
return obstack_copy (obstack, pointer, length); |
} |
POINTER (obstack_copy0) (struct obstack *obstack, POINTER pointer, int length) |
{ |
return obstack_copy0 (obstack, pointer, length); |
} |
#endif /* 0 */ |
#endif /* !ELIDE_CODE */ |
/contrib/toolchain/binutils/libiberty/partition.c |
---|
0,0 → 1,183 |
/* List implementation of a partition of consecutive integers. |
Copyright (C) 2000, 2001 Free Software Foundation, Inc. |
Contributed by CodeSourcery, LLC. |
This file is part of GNU CC. |
GNU CC 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. |
GNU CC 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 GNU CC; see the file COPYING. If not, write to |
the Free Software Foundation, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#include "libiberty.h" |
#include "partition.h" |
static int elem_compare (const void *, const void *); |
/* Creates a partition of NUM_ELEMENTS elements. Initially each |
element is in a class by itself. */ |
partition |
partition_new (int num_elements) |
{ |
int e; |
partition part = (partition) |
xmalloc (sizeof (struct partition_def) + |
(num_elements - 1) * sizeof (struct partition_elem)); |
part->num_elements = num_elements; |
for (e = 0; e < num_elements; ++e) |
{ |
part->elements[e].class_element = e; |
part->elements[e].next = &(part->elements[e]); |
part->elements[e].class_count = 1; |
} |
return part; |
} |
/* Freeds a partition. */ |
void |
partition_delete (partition part) |
{ |
free (part); |
} |
/* Unites the classes containing ELEM1 and ELEM2 into a single class |
of partition PART. If ELEM1 and ELEM2 are already in the same |
class, does nothing. Returns the canonical element of the |
resulting union class. */ |
int |
partition_union (partition part, int elem1, int elem2) |
{ |
struct partition_elem *elements = part->elements; |
struct partition_elem *e1; |
struct partition_elem *e2; |
struct partition_elem *p; |
struct partition_elem *old_next; |
/* The canonical element of the resulting union class. */ |
int class_element = elements[elem1].class_element; |
/* If they're already in the same class, do nothing. */ |
if (class_element == elements[elem2].class_element) |
return class_element; |
/* Make sure ELEM1 is in the larger class of the two. If not, swap |
them. This way we always scan the shorter list. */ |
if (elements[elem1].class_count < elements[elem2].class_count) |
{ |
int temp = elem1; |
elem1 = elem2; |
elem2 = temp; |
class_element = elements[elem1].class_element; |
} |
e1 = &(elements[elem1]); |
e2 = &(elements[elem2]); |
/* Keep a count of the number of elements in the list. */ |
elements[class_element].class_count |
+= elements[e2->class_element].class_count; |
/* Update the class fields in elem2's class list. */ |
e2->class_element = class_element; |
for (p = e2->next; p != e2; p = p->next) |
p->class_element = class_element; |
/* Splice ELEM2's class list into ELEM1's. These are circular |
lists. */ |
old_next = e1->next; |
e1->next = e2->next; |
e2->next = old_next; |
return class_element; |
} |
/* Compare elements ELEM1 and ELEM2 from array of integers, given a |
pointer to each. Used to qsort such an array. */ |
static int |
elem_compare (const void *elem1, const void *elem2) |
{ |
int e1 = * (const int *) elem1; |
int e2 = * (const int *) elem2; |
if (e1 < e2) |
return -1; |
else if (e1 > e2) |
return 1; |
else |
return 0; |
} |
/* Prints PART to the file pointer FP. The elements of each |
class are sorted. */ |
void |
partition_print (partition part, FILE *fp) |
{ |
char *done; |
int num_elements = part->num_elements; |
struct partition_elem *elements = part->elements; |
int *class_elements; |
int e; |
/* Flag the elements we've already printed. */ |
done = (char *) xmalloc (num_elements); |
memset (done, 0, num_elements); |
/* A buffer used to sort elements in a class. */ |
class_elements = (int *) xmalloc (num_elements * sizeof (int)); |
fputc ('[', fp); |
for (e = 0; e < num_elements; ++e) |
/* If we haven't printed this element, print its entire class. */ |
if (! done[e]) |
{ |
int c = e; |
int count = elements[elements[e].class_element].class_count; |
int i; |
/* Collect the elements in this class. */ |
for (i = 0; i < count; ++i) { |
class_elements[i] = c; |
done[c] = 1; |
c = elements[c].next - elements; |
} |
/* Sort them. */ |
qsort ((void *) class_elements, count, sizeof (int), elem_compare); |
/* Print them. */ |
fputc ('(', fp); |
for (i = 0; i < count; ++i) |
fprintf (fp, i == 0 ? "%d" : " %d", class_elements[i]); |
fputc (')', fp); |
} |
fputc (']', fp); |
free (class_elements); |
free (done); |
} |
/contrib/toolchain/binutils/libiberty/pex-common.h |
---|
0,0 → 1,153 |
/* Utilities to execute a program in a subprocess (possibly linked by pipes |
with other subprocesses), and wait for it. Shared logic. |
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004 |
Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If not, |
write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifndef PEX_COMMON_H |
#define PEX_COMMON_H |
#include "config.h" |
#include "libiberty.h" |
#include <stdio.h> |
/* pid_t is may defined by config.h or sys/types.h needs to be |
included. */ |
#if !defined(pid_t) && defined(HAVE_SYS_TYPES_H) |
#include <sys/types.h> |
#endif |
#define install_error_msg "installation problem, cannot exec `%s'" |
/* stdin file number. */ |
#define STDIN_FILE_NO 0 |
/* stdout file number. */ |
#define STDOUT_FILE_NO 1 |
/* stderr file number. */ |
#define STDERR_FILE_NO 2 |
/* value of `pipe': port index for reading. */ |
#define READ_PORT 0 |
/* value of `pipe': port index for writing. */ |
#define WRITE_PORT 1 |
/* The structure used by pex_init and friends. */ |
struct pex_obj |
{ |
/* Flags. */ |
int flags; |
/* Name of calling program, for error messages. */ |
const char *pname; |
/* Base name to use for temporary files. */ |
const char *tempbase; |
/* Pipe to use as stdin for next process. */ |
int next_input; |
/* File name to use as stdin for next process. */ |
char *next_input_name; |
/* Whether next_input_name was allocated using malloc. */ |
int next_input_name_allocated; |
/* If not -1, stderr pipe from the last process. */ |
int stderr_pipe; |
/* Number of child processes. */ |
int count; |
/* PIDs of child processes; array allocated using malloc. */ |
pid_t *children; |
/* Exit statuses of child processes; array allocated using malloc. */ |
int *status; |
/* Time used by child processes; array allocated using malloc. */ |
struct pex_time *time; |
/* Number of children we have already waited for. */ |
int number_waited; |
/* FILE created by pex_input_file. */ |
FILE *input_file; |
/* FILE created by pex_read_output. */ |
FILE *read_output; |
/* FILE created by pex_read_err. */ |
FILE *read_err; |
/* Number of temporary files to remove. */ |
int remove_count; |
/* List of temporary files to remove; array allocated using malloc |
of strings allocated using malloc. */ |
char **remove; |
/* Pointers to system dependent functions. */ |
const struct pex_funcs *funcs; |
/* For use by system dependent code. */ |
void *sysdep; |
}; |
/* Functions passed to pex_run_common. */ |
struct pex_funcs |
{ |
/* Open file NAME for reading. If BINARY is non-zero, open in |
binary mode. Return >= 0 on success, -1 on error. */ |
int (*open_read) (struct pex_obj *, const char */* name */, int /* binary */); |
/* Open file NAME for writing. If BINARY is non-zero, open in |
binary mode. Return >= 0 on success, -1 on error. */ |
int (*open_write) (struct pex_obj *, const char */* name */, |
int /* binary */); |
/* Execute a child process. FLAGS, EXECUTABLE, ARGV, ERR are from |
pex_run. IN, OUT, ERRDES, TOCLOSE are all descriptors, from |
open_read, open_write, or pipe, or they are one of STDIN_FILE_NO, |
STDOUT_FILE_NO or STDERR_FILE_NO; if IN, OUT, and ERRDES are not |
STD*_FILE_NO, they should be closed. If the descriptor TOCLOSE |
is not -1, and the system supports pipes, TOCLOSE should be |
closed in the child process. The function should handle the |
PEX_STDERR_TO_STDOUT flag. Return >= 0 on success, or -1 on |
error and set *ERRMSG and *ERR. */ |
pid_t (*exec_child) (struct pex_obj *, int /* flags */, |
const char */* executable */, char * const * /* argv */, |
char * const * /* env */, |
int /* in */, int /* out */, int /* errdes */, |
int /* toclose */, const char **/* errmsg */, |
int */* err */); |
/* Close a descriptor. Return 0 on success, -1 on error. */ |
int (*close) (struct pex_obj *, int); |
/* Wait for a child to complete, returning exit status in *STATUS |
and time in *TIME (if it is not null). CHILD is from fork. DONE |
is 1 if this is called via pex_free. ERRMSG and ERR are as in |
fork. Return 0 on success, -1 on error. */ |
pid_t (*wait) (struct pex_obj *, pid_t /* child */, int * /* status */, |
struct pex_time * /* time */, int /* done */, |
const char ** /* errmsg */, int * /* err */); |
/* Create a pipe (only called if PEX_USE_PIPES is set) storing two |
descriptors in P[0] and P[1]. If BINARY is non-zero, open in |
binary mode. Return 0 on success, -1 on error. */ |
int (*pipe) (struct pex_obj *, int * /* p */, int /* binary */); |
/* Get a FILE pointer to read from a file descriptor (only called if |
PEX_USE_PIPES is set). If BINARY is non-zero, open in binary |
mode. Return pointer on success, NULL on error. */ |
FILE * (*fdopenr) (struct pex_obj *, int /* fd */, int /* binary */); |
/* Get a FILE pointer to write to the file descriptor FD (only |
called if PEX_USE_PIPES is set). If BINARY is non-zero, open in |
binary mode. Arrange for FD not to be inherited by the child |
processes. Return pointer on success, NULL on error. */ |
FILE * (*fdopenw) (struct pex_obj *, int /* fd */, int /* binary */); |
/* Free any system dependent data associated with OBJ. May be |
NULL if there is nothing to do. */ |
void (*cleanup) (struct pex_obj *); |
}; |
extern struct pex_obj *pex_init_common (int, const char *, const char *, |
const struct pex_funcs *); |
#endif |
/contrib/toolchain/binutils/libiberty/physmem.c |
---|
0,0 → 1,305 |
/* Calculate the size of physical memory. |
Copyright 2000, 2001, 2003, 2004, 2005 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ |
/* Written by Paul Eggert. */ |
#if HAVE_CONFIG_H |
# include <config.h> |
#endif |
#if HAVE_UNISTD_H |
# include <unistd.h> |
#endif |
#if HAVE_SYS_PSTAT_H |
# include <sys/pstat.h> |
#endif |
#if HAVE_SYS_SYSMP_H |
# include <sys/sysmp.h> |
#endif |
#if HAVE_SYS_SYSINFO_H && HAVE_MACHINE_HAL_SYSINFO_H |
# include <sys/sysinfo.h> |
# include <machine/hal_sysinfo.h> |
#endif |
#if HAVE_SYS_TABLE_H |
# include <sys/table.h> |
#endif |
#include <sys/types.h> |
#if HAVE_SYS_PARAM_H |
# include <sys/param.h> |
#endif |
#if HAVE_SYS_SYSCTL_H |
# include <sys/sysctl.h> |
#endif |
#if HAVE_SYS_SYSTEMCFG_H |
# include <sys/systemcfg.h> |
#endif |
#ifdef _WIN32 |
# define WIN32_LEAN_AND_MEAN |
# include <windows.h> |
/* MEMORYSTATUSEX is missing from older windows headers, so define |
a local replacement. */ |
typedef struct |
{ |
DWORD dwLength; |
DWORD dwMemoryLoad; |
DWORDLONG ullTotalPhys; |
DWORDLONG ullAvailPhys; |
DWORDLONG ullTotalPageFile; |
DWORDLONG ullAvailPageFile; |
DWORDLONG ullTotalVirtual; |
DWORDLONG ullAvailVirtual; |
DWORDLONG ullAvailExtendedVirtual; |
} lMEMORYSTATUSEX; |
typedef WINBOOL (WINAPI *PFN_MS_EX) (lMEMORYSTATUSEX*); |
#endif |
#include "libiberty.h" |
/* Return the total amount of physical memory. */ |
double |
physmem_total (void) |
{ |
#if defined _SC_PHYS_PAGES && defined _SC_PAGESIZE |
{ /* This works on linux-gnu, solaris2 and cygwin. */ |
double pages = sysconf (_SC_PHYS_PAGES); |
double pagesize = sysconf (_SC_PAGESIZE); |
if (0 <= pages && 0 <= pagesize) |
return pages * pagesize; |
} |
#endif |
#if HAVE_PSTAT_GETSTATIC |
{ /* This works on hpux11. */ |
struct pst_static pss; |
if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0)) |
{ |
double pages = pss.physical_memory; |
double pagesize = pss.page_size; |
if (0 <= pages && 0 <= pagesize) |
return pages * pagesize; |
} |
} |
#endif |
#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE |
{ /* This works on irix6. */ |
struct rminfo realmem; |
if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) |
{ |
double pagesize = sysconf (_SC_PAGESIZE); |
double pages = realmem.physmem; |
if (0 <= pages && 0 <= pagesize) |
return pages * pagesize; |
} |
} |
#endif |
#if HAVE_GETSYSINFO && defined GSI_PHYSMEM |
{ /* This works on Tru64 UNIX V4/5. */ |
int physmem; |
if (getsysinfo (GSI_PHYSMEM, (caddr_t) &physmem, sizeof (physmem), |
NULL, NULL, NULL) == 1) |
{ |
double kbytes = physmem; |
if (0 <= kbytes) |
return kbytes * 1024.0; |
} |
} |
#endif |
#if HAVE_SYSCTL && defined HW_PHYSMEM |
{ /* This works on *bsd and darwin. */ |
unsigned int physmem; |
size_t len = sizeof physmem; |
static int mib[2] = { CTL_HW, HW_PHYSMEM }; |
if (sysctl (mib, ARRAY_SIZE (mib), &physmem, &len, NULL, 0) == 0 |
&& len == sizeof (physmem)) |
return (double) physmem; |
} |
#endif |
#if HAVE__SYSTEM_CONFIGURATION |
/* This works on AIX 4.3.3+. */ |
return _system_configuration.physmem; |
#endif |
#if defined _WIN32 |
{ /* this works on windows */ |
PFN_MS_EX pfnex; |
HMODULE h = GetModuleHandle ("kernel32.dll"); |
if (!h) |
return 0.0; |
/* Use GlobalMemoryStatusEx if available. */ |
if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) |
{ |
lMEMORYSTATUSEX lms_ex; |
lms_ex.dwLength = sizeof lms_ex; |
if (!pfnex (&lms_ex)) |
return 0.0; |
return (double) lms_ex.ullTotalPhys; |
} |
/* Fall back to GlobalMemoryStatus which is always available. |
but returns wrong results for physical memory > 4GB. */ |
else |
{ |
MEMORYSTATUS ms; |
GlobalMemoryStatus (&ms); |
return (double) ms.dwTotalPhys; |
} |
} |
#endif |
/* Return 0 if we can't determine the value. */ |
return 0; |
} |
/* Return the amount of physical memory available. */ |
double |
physmem_available (void) |
{ |
#if defined _SC_AVPHYS_PAGES && defined _SC_PAGESIZE |
{ /* This works on linux-gnu, solaris2 and cygwin. */ |
double pages = sysconf (_SC_AVPHYS_PAGES); |
double pagesize = sysconf (_SC_PAGESIZE); |
if (0 <= pages && 0 <= pagesize) |
return pages * pagesize; |
} |
#endif |
#if HAVE_PSTAT_GETSTATIC && HAVE_PSTAT_GETDYNAMIC |
{ /* This works on hpux11. */ |
struct pst_static pss; |
struct pst_dynamic psd; |
if (0 <= pstat_getstatic (&pss, sizeof pss, 1, 0) |
&& 0 <= pstat_getdynamic (&psd, sizeof psd, 1, 0)) |
{ |
double pages = psd.psd_free; |
double pagesize = pss.page_size; |
if (0 <= pages && 0 <= pagesize) |
return pages * pagesize; |
} |
} |
#endif |
#if HAVE_SYSMP && defined MP_SAGET && defined MPSA_RMINFO && defined _SC_PAGESIZE |
{ /* This works on irix6. */ |
struct rminfo realmem; |
if (sysmp (MP_SAGET, MPSA_RMINFO, &realmem, sizeof realmem) == 0) |
{ |
double pagesize = sysconf (_SC_PAGESIZE); |
double pages = realmem.availrmem; |
if (0 <= pages && 0 <= pagesize) |
return pages * pagesize; |
} |
} |
#endif |
#if HAVE_TABLE && defined TBL_VMSTATS |
{ /* This works on Tru64 UNIX V4/5. */ |
struct tbl_vmstats vmstats; |
if (table (TBL_VMSTATS, 0, &vmstats, 1, sizeof (vmstats)) == 1) |
{ |
double pages = vmstats.free_count; |
double pagesize = vmstats.pagesize; |
if (0 <= pages && 0 <= pagesize) |
return pages * pagesize; |
} |
} |
#endif |
#if HAVE_SYSCTL && defined HW_USERMEM |
{ /* This works on *bsd and darwin. */ |
unsigned int usermem; |
size_t len = sizeof usermem; |
static int mib[2] = { CTL_HW, HW_USERMEM }; |
if (sysctl (mib, ARRAY_SIZE (mib), &usermem, &len, NULL, 0) == 0 |
&& len == sizeof (usermem)) |
return (double) usermem; |
} |
#endif |
#if defined _WIN32 |
{ /* this works on windows */ |
PFN_MS_EX pfnex; |
HMODULE h = GetModuleHandle ("kernel32.dll"); |
if (!h) |
return 0.0; |
/* Use GlobalMemoryStatusEx if available. */ |
if ((pfnex = (PFN_MS_EX) GetProcAddress (h, "GlobalMemoryStatusEx"))) |
{ |
lMEMORYSTATUSEX lms_ex; |
lms_ex.dwLength = sizeof lms_ex; |
if (!pfnex (&lms_ex)) |
return 0.0; |
return (double) lms_ex.ullAvailPhys; |
} |
/* Fall back to GlobalMemoryStatus which is always available. |
but returns wrong results for physical memory > 4GB */ |
else |
{ |
MEMORYSTATUS ms; |
GlobalMemoryStatus (&ms); |
return (double) ms.dwAvailPhys; |
} |
} |
#endif |
/* Guess 25% of physical memory. */ |
return physmem_total () / 4; |
} |
#if DEBUG |
# include <stdio.h> |
# include <stdlib.h> |
int |
main (void) |
{ |
printf ("%12.f %12.f\n", physmem_total (), physmem_available ()); |
exit (0); |
} |
#endif /* DEBUG */ |
/* |
Local Variables: |
compile-command: "gcc -DDEBUG -DHAVE_CONFIG_H -I.. -g -O -Wall -W physmem.c" |
End: |
*/ |
/contrib/toolchain/binutils/libiberty/random.c |
---|
0,0 → 1,404 |
/* |
* Copyright (c) 1983 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* are met: |
* 1. Redistributions of source code must retain the above copyright |
* notice, this list of conditions and the following disclaimer. |
* 2. Redistributions in binary form must reproduce the above copyright |
* notice, this list of conditions and the following disclaimer in the |
* documentation and/or other materials provided with the distribution. |
* 3. [rescinded 22 July 1999] |
* 4. Neither the name of the University nor the names of its contributors |
* may be used to endorse or promote products derived from this software |
* without specific prior written permission. |
* |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
* SUCH DAMAGE. |
*/ |
/* |
* This is derived from the Berkeley source: |
* @(#)random.c 5.5 (Berkeley) 7/6/88 |
* It was reworked for the GNU C Library by Roland McGrath. |
*/ |
/* |
@deftypefn Supplement {long int} random (void) |
@deftypefnx Supplement void srandom (unsigned int @var{seed}) |
@deftypefnx Supplement void* initstate (unsigned int @var{seed}, @ |
void *@var{arg_state}, unsigned long @var{n}) |
@deftypefnx Supplement void* setstate (void *@var{arg_state}) |
Random number functions. @code{random} returns a random number in the |
range 0 to @code{LONG_MAX}. @code{srandom} initializes the random |
number generator to some starting point determined by @var{seed} |
(else, the values returned by @code{random} are always the same for each |
run of the program). @code{initstate} and @code{setstate} allow fine-grained |
control over the state of the random number generator. |
@end deftypefn |
*/ |
#include <errno.h> |
#if 0 |
#include <ansidecl.h> |
#include <limits.h> |
#include <stddef.h> |
#include <stdlib.h> |
#else |
#define ULONG_MAX ((unsigned long)(~0L)) /* 0xFFFFFFFF for 32-bits */ |
#define LONG_MAX ((long)(ULONG_MAX >> 1)) /* 0x7FFFFFFF for 32-bits*/ |
#ifdef __STDC__ |
# define PTR void * |
# ifndef NULL |
# define NULL (void *) 0 |
# endif |
#else |
# define PTR char * |
# ifndef NULL |
# define NULL (void *) 0 |
# endif |
#endif |
#endif |
long int random (void); |
/* An improved random number generation package. In addition to the standard |
rand()/srand() like interface, this package also has a special state info |
interface. The initstate() routine is called with a seed, an array of |
bytes, and a count of how many bytes are being passed in; this array is |
then initialized to contain information for random number generation with |
that much state information. Good sizes for the amount of state |
information are 32, 64, 128, and 256 bytes. The state can be switched by |
calling the setstate() function with the same array as was initiallized |
with initstate(). By default, the package runs with 128 bytes of state |
information and generates far better random numbers than a linear |
congruential generator. If the amount of state information is less than |
32 bytes, a simple linear congruential R.N.G. is used. Internally, the |
state information is treated as an array of longs; the zeroeth element of |
the array is the type of R.N.G. being used (small integer); the remainder |
of the array is the state information for the R.N.G. Thus, 32 bytes of |
state information will give 7 longs worth of state information, which will |
allow a degree seven polynomial. (Note: The zeroeth word of state |
information also has some other information stored in it; see setstate |
for details). The random number generation technique is a linear feedback |
shift register approach, employing trinomials (since there are fewer terms |
to sum up that way). In this approach, the least significant bit of all |
the numbers in the state table will act as a linear feedback shift register, |
and will have period 2^deg - 1 (where deg is the degree of the polynomial |
being used, assuming that the polynomial is irreducible and primitive). |
The higher order bits will have longer periods, since their values are |
also influenced by pseudo-random carries out of the lower bits. The |
total period of the generator is approximately deg*(2**deg - 1); thus |
doubling the amount of state information has a vast influence on the |
period of the generator. Note: The deg*(2**deg - 1) is an approximation |
only good for large deg, when the period of the shift register is the |
dominant factor. With deg equal to seven, the period is actually much |
longer than the 7*(2**7 - 1) predicted by this formula. */ |
/* For each of the currently supported random number generators, we have a |
break value on the amount of state information (you need at least thi |
bytes of state info to support this random number generator), a degree for |
the polynomial (actually a trinomial) that the R.N.G. is based on, and |
separation between the two lower order coefficients of the trinomial. */ |
/* Linear congruential. */ |
#define TYPE_0 0 |
#define BREAK_0 8 |
#define DEG_0 0 |
#define SEP_0 0 |
/* x**7 + x**3 + 1. */ |
#define TYPE_1 1 |
#define BREAK_1 32 |
#define DEG_1 7 |
#define SEP_1 3 |
/* x**15 + x + 1. */ |
#define TYPE_2 2 |
#define BREAK_2 64 |
#define DEG_2 15 |
#define SEP_2 1 |
/* x**31 + x**3 + 1. */ |
#define TYPE_3 3 |
#define BREAK_3 128 |
#define DEG_3 31 |
#define SEP_3 3 |
/* x**63 + x + 1. */ |
#define TYPE_4 4 |
#define BREAK_4 256 |
#define DEG_4 63 |
#define SEP_4 1 |
/* Array versions of the above information to make code run faster. |
Relies on fact that TYPE_i == i. */ |
#define MAX_TYPES 5 /* Max number of types above. */ |
static int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; |
static int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; |
/* Initially, everything is set up as if from: |
initstate(1, randtbl, 128); |
Note that this initialization takes advantage of the fact that srandom |
advances the front and rear pointers 10*rand_deg times, and hence the |
rear pointer which starts at 0 will also end up at zero; thus the zeroeth |
element of the state information, which contains info about the current |
position of the rear pointer is just |
(MAX_TYPES * (rptr - state)) + TYPE_3 == TYPE_3. */ |
static long int randtbl[DEG_3 + 1] = |
{ TYPE_3, |
0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, |
0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, |
0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, |
0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, |
0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, |
0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, |
0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, |
0xf5ad9d0e, 0x8999220b, 0x27fb47b9 |
}; |
/* FPTR and RPTR are two pointers into the state info, a front and a rear |
pointer. These two pointers are always rand_sep places aparts, as they |
cycle through the state information. (Yes, this does mean we could get |
away with just one pointer, but the code for random is more efficient |
this way). The pointers are left positioned as they would be from the call: |
initstate(1, randtbl, 128); |
(The position of the rear pointer, rptr, is really 0 (as explained above |
in the initialization of randtbl) because the state table pointer is set |
to point to randtbl[1] (as explained below).) */ |
static long int *fptr = &randtbl[SEP_3 + 1]; |
static long int *rptr = &randtbl[1]; |
/* The following things are the pointer to the state information table, |
the type of the current generator, the degree of the current polynomial |
being used, and the separation between the two pointers. |
Note that for efficiency of random, we remember the first location of |
the state information, not the zeroeth. Hence it is valid to access |
state[-1], which is used to store the type of the R.N.G. |
Also, we remember the last location, since this is more efficient than |
indexing every time to find the address of the last element to see if |
the front and rear pointers have wrapped. */ |
static long int *state = &randtbl[1]; |
static int rand_type = TYPE_3; |
static int rand_deg = DEG_3; |
static int rand_sep = SEP_3; |
static long int *end_ptr = &randtbl[sizeof(randtbl) / sizeof(randtbl[0])]; |
/* Initialize the random number generator based on the given seed. If the |
type is the trivial no-state-information type, just remember the seed. |
Otherwise, initializes state[] based on the given "seed" via a linear |
congruential generator. Then, the pointers are set to known locations |
that are exactly rand_sep places apart. Lastly, it cycles the state |
information a given number of times to get rid of any initial dependencies |
introduced by the L.C.R.N.G. Note that the initialization of randtbl[] |
for default usage relies on values produced by this routine. */ |
void |
srandom (unsigned int x) |
{ |
state[0] = x; |
if (rand_type != TYPE_0) |
{ |
register long int i; |
for (i = 1; i < rand_deg; ++i) |
state[i] = (1103515145 * state[i - 1]) + 12345; |
fptr = &state[rand_sep]; |
rptr = &state[0]; |
for (i = 0; i < 10 * rand_deg; ++i) |
random(); |
} |
} |
/* Initialize the state information in the given array of N bytes for |
future random number generation. Based on the number of bytes we |
are given, and the break values for the different R.N.G.'s, we choose |
the best (largest) one we can and set things up for it. srandom is |
then called to initialize the state information. Note that on return |
from srandom, we set state[-1] to be the type multiplexed with the current |
value of the rear pointer; this is so successive calls to initstate won't |
lose this information and will be able to restart with setstate. |
Note: The first thing we do is save the current state, if any, just like |
setstate so that it doesn't matter when initstate is called. |
Returns a pointer to the old state. */ |
PTR |
initstate (unsigned int seed, PTR arg_state, unsigned long n) |
{ |
PTR ostate = (PTR) &state[-1]; |
if (rand_type == TYPE_0) |
state[-1] = rand_type; |
else |
state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; |
if (n < BREAK_1) |
{ |
if (n < BREAK_0) |
{ |
errno = EINVAL; |
return NULL; |
} |
rand_type = TYPE_0; |
rand_deg = DEG_0; |
rand_sep = SEP_0; |
} |
else if (n < BREAK_2) |
{ |
rand_type = TYPE_1; |
rand_deg = DEG_1; |
rand_sep = SEP_1; |
} |
else if (n < BREAK_3) |
{ |
rand_type = TYPE_2; |
rand_deg = DEG_2; |
rand_sep = SEP_2; |
} |
else if (n < BREAK_4) |
{ |
rand_type = TYPE_3; |
rand_deg = DEG_3; |
rand_sep = SEP_3; |
} |
else |
{ |
rand_type = TYPE_4; |
rand_deg = DEG_4; |
rand_sep = SEP_4; |
} |
state = &((long int *) arg_state)[1]; /* First location. */ |
/* Must set END_PTR before srandom. */ |
end_ptr = &state[rand_deg]; |
srandom(seed); |
if (rand_type == TYPE_0) |
state[-1] = rand_type; |
else |
state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; |
return ostate; |
} |
/* Restore the state from the given state array. |
Note: It is important that we also remember the locations of the pointers |
in the current state information, and restore the locations of the pointers |
from the old state information. This is done by multiplexing the pointer |
location into the zeroeth word of the state information. Note that due |
to the order in which things are done, it is OK to call setstate with the |
same state as the current state |
Returns a pointer to the old state information. */ |
PTR |
setstate (PTR arg_state) |
{ |
register long int *new_state = (long int *) arg_state; |
register int type = new_state[0] % MAX_TYPES; |
register int rear = new_state[0] / MAX_TYPES; |
PTR ostate = (PTR) &state[-1]; |
if (rand_type == TYPE_0) |
state[-1] = rand_type; |
else |
state[-1] = (MAX_TYPES * (rptr - state)) + rand_type; |
switch (type) |
{ |
case TYPE_0: |
case TYPE_1: |
case TYPE_2: |
case TYPE_3: |
case TYPE_4: |
rand_type = type; |
rand_deg = degrees[type]; |
rand_sep = seps[type]; |
break; |
default: |
/* State info munged. */ |
errno = EINVAL; |
return NULL; |
} |
state = &new_state[1]; |
if (rand_type != TYPE_0) |
{ |
rptr = &state[rear]; |
fptr = &state[(rear + rand_sep) % rand_deg]; |
} |
/* Set end_ptr too. */ |
end_ptr = &state[rand_deg]; |
return ostate; |
} |
/* If we are using the trivial TYPE_0 R.N.G., just do the old linear |
congruential bit. Otherwise, we do our fancy trinomial stuff, which is the |
same in all ther other cases due to all the global variables that have been |
set up. The basic operation is to add the number at the rear pointer into |
the one at the front pointer. Then both pointers are advanced to the next |
location cyclically in the table. The value returned is the sum generated, |
reduced to 31 bits by throwing away the "least random" low bit. |
Note: The code takes advantage of the fact that both the front and |
rear pointers can't wrap on the same call by not testing the rear |
pointer if the front one has wrapped. Returns a 31-bit random number. */ |
long int |
random (void) |
{ |
if (rand_type == TYPE_0) |
{ |
state[0] = ((state[0] * 1103515245) + 12345) & LONG_MAX; |
return state[0]; |
} |
else |
{ |
long int i; |
*fptr += *rptr; |
/* Chucking least random bit. */ |
i = (*fptr >> 1) & LONG_MAX; |
++fptr; |
if (fptr >= end_ptr) |
{ |
fptr = state; |
++rptr; |
} |
else |
{ |
++rptr; |
if (rptr >= end_ptr) |
rptr = state; |
} |
return i; |
} |
} |
/contrib/toolchain/binutils/libiberty/regex.c |
---|
0,0 → 1,8204 |
/* Extended regular expression matching and search library, |
version 0.12. |
(Implements POSIX draft P1003.2/D11.2, except for some of the |
internationalization features.) |
Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, |
2002, 2005, 2010, 2013 Free Software Foundation, Inc. |
This file is part of the GNU C Library. |
The GNU C Library is free software; you can redistribute it and/or |
modify it under the terms of the GNU Lesser General Public |
License as published by the Free Software Foundation; either |
version 2.1 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 |
Lesser General Public License for more details. |
You should have received a copy of the GNU Lesser General Public |
License along with the GNU C Library; if not, write to the Free |
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
02110-1301 USA. */ |
/* This file has been modified for usage in libiberty. It includes "xregex.h" |
instead of <regex.h>. The "xregex.h" header file renames all external |
routines with an "x" prefix so they do not collide with the native regex |
routines or with other components regex routines. */ |
/* AIX requires this to be the first thing in the file. */ |
#if defined _AIX && !defined __GNUC__ && !defined REGEX_MALLOC |
#pragma alloca |
#endif |
#undef _GNU_SOURCE |
#define _GNU_SOURCE |
#ifndef INSIDE_RECURSION |
# ifdef HAVE_CONFIG_H |
# include <config.h> |
# endif |
#endif |
#include <ansidecl.h> |
#ifndef INSIDE_RECURSION |
# if defined STDC_HEADERS && !defined emacs |
# include <stddef.h> |
# define PTR_INT_TYPE ptrdiff_t |
# else |
/* We need this for `regex.h', and perhaps for the Emacs include files. */ |
# include <sys/types.h> |
# define PTR_INT_TYPE long |
# endif |
# define WIDE_CHAR_SUPPORT (HAVE_WCTYPE_H && HAVE_WCHAR_H && HAVE_BTOWC) |
/* For platform which support the ISO C amendement 1 functionality we |
support user defined character classes. */ |
# if defined _LIBC || WIDE_CHAR_SUPPORT |
/* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ |
# include <wchar.h> |
# include <wctype.h> |
# endif |
# ifdef _LIBC |
/* We have to keep the namespace clean. */ |
# define regfree(preg) __regfree (preg) |
# define regexec(pr, st, nm, pm, ef) __regexec (pr, st, nm, pm, ef) |
# define regcomp(preg, pattern, cflags) __regcomp (preg, pattern, cflags) |
# define regerror(errcode, preg, errbuf, errbuf_size) \ |
__regerror(errcode, preg, errbuf, errbuf_size) |
# define re_set_registers(bu, re, nu, st, en) \ |
__re_set_registers (bu, re, nu, st, en) |
# define re_match_2(bufp, string1, size1, string2, size2, pos, regs, stop) \ |
__re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop) |
# define re_match(bufp, string, size, pos, regs) \ |
__re_match (bufp, string, size, pos, regs) |
# define re_search(bufp, string, size, startpos, range, regs) \ |
__re_search (bufp, string, size, startpos, range, regs) |
# define re_compile_pattern(pattern, length, bufp) \ |
__re_compile_pattern (pattern, length, bufp) |
# define re_set_syntax(syntax) __re_set_syntax (syntax) |
# define re_search_2(bufp, st1, s1, st2, s2, startpos, range, regs, stop) \ |
__re_search_2 (bufp, st1, s1, st2, s2, startpos, range, regs, stop) |
# define re_compile_fastmap(bufp) __re_compile_fastmap (bufp) |
# define btowc __btowc |
/* We are also using some library internals. */ |
# include <locale/localeinfo.h> |
# include <locale/elem-hash.h> |
# include <langinfo.h> |
# include <locale/coll-lookup.h> |
# endif |
/* This is for other GNU distributions with internationalized messages. */ |
# if (HAVE_LIBINTL_H && ENABLE_NLS) || defined _LIBC |
# include <libintl.h> |
# ifdef _LIBC |
# undef gettext |
# define gettext(msgid) __dcgettext ("libc", msgid, LC_MESSAGES) |
# endif |
# else |
# define gettext(msgid) (msgid) |
# endif |
# ifndef gettext_noop |
/* This define is so xgettext can find the internationalizable |
strings. */ |
# define gettext_noop(String) String |
# endif |
/* The `emacs' switch turns on certain matching commands |
that make sense only in Emacs. */ |
# ifdef emacs |
# include "lisp.h" |
# include "buffer.h" |
# include "syntax.h" |
# else /* not emacs */ |
/* If we are not linking with Emacs proper, |
we can't use the relocating allocator |
even if config.h says that we can. */ |
# undef REL_ALLOC |
# if defined STDC_HEADERS || defined _LIBC |
# include <stdlib.h> |
# else |
char *malloc (); |
char *realloc (); |
# endif |
/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow. |
If nothing else has been done, use the method below. */ |
# ifdef INHIBIT_STRING_HEADER |
# if !(defined HAVE_BZERO && defined HAVE_BCOPY) |
# if !defined bzero && !defined bcopy |
# undef INHIBIT_STRING_HEADER |
# endif |
# endif |
# endif |
/* This is the normal way of making sure we have a bcopy and a bzero. |
This is used in most programs--a few other programs avoid this |
by defining INHIBIT_STRING_HEADER. */ |
# ifndef INHIBIT_STRING_HEADER |
# if defined HAVE_STRING_H || defined STDC_HEADERS || defined _LIBC |
# include <string.h> |
# ifndef bzero |
# ifndef _LIBC |
# define bzero(s, n) (memset (s, '\0', n), (s)) |
# else |
# define bzero(s, n) __bzero (s, n) |
# endif |
# endif |
# else |
# include <strings.h> |
# ifndef memcmp |
# define memcmp(s1, s2, n) bcmp (s1, s2, n) |
# endif |
# ifndef memcpy |
# define memcpy(d, s, n) (bcopy (s, d, n), (d)) |
# endif |
# endif |
# endif |
/* Define the syntax stuff for \<, \>, etc. */ |
/* This must be nonzero for the wordchar and notwordchar pattern |
commands in re_match_2. */ |
# ifndef Sword |
# define Sword 1 |
# endif |
# ifdef SWITCH_ENUM_BUG |
# define SWITCH_ENUM_CAST(x) ((int)(x)) |
# else |
# define SWITCH_ENUM_CAST(x) (x) |
# endif |
# endif /* not emacs */ |
# if defined _LIBC || HAVE_LIMITS_H |
# include <limits.h> |
# endif |
# ifndef MB_LEN_MAX |
# define MB_LEN_MAX 1 |
# endif |
/* Get the interface, including the syntax bits. */ |
# include "xregex.h" /* change for libiberty */ |
/* isalpha etc. are used for the character classes. */ |
# include <ctype.h> |
/* Jim Meyering writes: |
"... Some ctype macros are valid only for character codes that |
isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when |
using /bin/cc or gcc but without giving an ansi option). So, all |
ctype uses should be through macros like ISPRINT... If |
STDC_HEADERS is defined, then autoconf has verified that the ctype |
macros don't need to be guarded with references to isascii. ... |
Defining isascii to 1 should let any compiler worth its salt |
eliminate the && through constant folding." |
Solaris defines some of these symbols so we must undefine them first. */ |
# undef ISASCII |
# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) |
# define ISASCII(c) 1 |
# else |
# define ISASCII(c) isascii(c) |
# endif |
# ifdef isblank |
# define ISBLANK(c) (ISASCII (c) && isblank (c)) |
# else |
# define ISBLANK(c) ((c) == ' ' || (c) == '\t') |
# endif |
# ifdef isgraph |
# define ISGRAPH(c) (ISASCII (c) && isgraph (c)) |
# else |
# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) |
# endif |
# undef ISPRINT |
# define ISPRINT(c) (ISASCII (c) && isprint (c)) |
# define ISDIGIT(c) (ISASCII (c) && isdigit (c)) |
# define ISALNUM(c) (ISASCII (c) && isalnum (c)) |
# define ISALPHA(c) (ISASCII (c) && isalpha (c)) |
# define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) |
# define ISLOWER(c) (ISASCII (c) && islower (c)) |
# define ISPUNCT(c) (ISASCII (c) && ispunct (c)) |
# define ISSPACE(c) (ISASCII (c) && isspace (c)) |
# define ISUPPER(c) (ISASCII (c) && isupper (c)) |
# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) |
# ifdef _tolower |
# define TOLOWER(c) _tolower(c) |
# else |
# define TOLOWER(c) tolower(c) |
# endif |
# ifndef NULL |
# define NULL (void *)0 |
# endif |
/* We remove any previous definition of `SIGN_EXTEND_CHAR', |
since ours (we hope) works properly with all combinations of |
machines, compilers, `char' and `unsigned char' argument types. |
(Per Bothner suggested the basic approach.) */ |
# undef SIGN_EXTEND_CHAR |
# if __STDC__ |
# define SIGN_EXTEND_CHAR(c) ((signed char) (c)) |
# else /* not __STDC__ */ |
/* As in Harbison and Steele. */ |
# define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128) |
# endif |
# ifndef emacs |
/* How many characters in the character set. */ |
# define CHAR_SET_SIZE 256 |
# ifdef SYNTAX_TABLE |
extern char *re_syntax_table; |
# else /* not SYNTAX_TABLE */ |
static char re_syntax_table[CHAR_SET_SIZE]; |
static void init_syntax_once (void); |
static void |
init_syntax_once (void) |
{ |
register int c; |
static int done = 0; |
if (done) |
return; |
bzero (re_syntax_table, sizeof re_syntax_table); |
for (c = 0; c < CHAR_SET_SIZE; ++c) |
if (ISALNUM (c)) |
re_syntax_table[c] = Sword; |
re_syntax_table['_'] = Sword; |
done = 1; |
} |
# endif /* not SYNTAX_TABLE */ |
# define SYNTAX(c) re_syntax_table[(unsigned char) (c)] |
# endif /* emacs */ |
/* Integer type for pointers. */ |
# if !defined _LIBC && !defined HAVE_UINTPTR_T |
typedef unsigned long int uintptr_t; |
# endif |
/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we |
use `alloca' instead of `malloc'. This is because using malloc in |
re_search* or re_match* could cause memory leaks when C-g is used in |
Emacs; also, malloc is slower and causes storage fragmentation. On |
the other hand, malloc is more portable, and easier to debug. |
Because we sometimes use alloca, some routines have to be macros, |
not functions -- `alloca'-allocated space disappears at the end of the |
function it is called in. */ |
# ifdef REGEX_MALLOC |
# define REGEX_ALLOCATE malloc |
# define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize) |
# define REGEX_FREE free |
# else /* not REGEX_MALLOC */ |
/* Emacs already defines alloca, sometimes. */ |
# ifndef alloca |
/* Make alloca work the best possible way. */ |
# ifdef __GNUC__ |
# define alloca __builtin_alloca |
# else /* not __GNUC__ */ |
# if HAVE_ALLOCA_H |
# include <alloca.h> |
# endif /* HAVE_ALLOCA_H */ |
# endif /* not __GNUC__ */ |
# endif /* not alloca */ |
# define REGEX_ALLOCATE alloca |
/* Assumes a `char *destination' variable. */ |
# define REGEX_REALLOCATE(source, osize, nsize) \ |
(destination = (char *) alloca (nsize), \ |
memcpy (destination, source, osize)) |
/* No need to do anything to free, after alloca. */ |
# define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */ |
# endif /* not REGEX_MALLOC */ |
/* Define how to allocate the failure stack. */ |
# if defined REL_ALLOC && defined REGEX_MALLOC |
# define REGEX_ALLOCATE_STACK(size) \ |
r_alloc (&failure_stack_ptr, (size)) |
# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ |
r_re_alloc (&failure_stack_ptr, (nsize)) |
# define REGEX_FREE_STACK(ptr) \ |
r_alloc_free (&failure_stack_ptr) |
# else /* not using relocating allocator */ |
# ifdef REGEX_MALLOC |
# define REGEX_ALLOCATE_STACK malloc |
# define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize) |
# define REGEX_FREE_STACK free |
# else /* not REGEX_MALLOC */ |
# define REGEX_ALLOCATE_STACK alloca |
# define REGEX_REALLOCATE_STACK(source, osize, nsize) \ |
REGEX_REALLOCATE (source, osize, nsize) |
/* No need to explicitly free anything. */ |
# define REGEX_FREE_STACK(arg) |
# endif /* not REGEX_MALLOC */ |
# endif /* not using relocating allocator */ |
/* True if `size1' is non-NULL and PTR is pointing anywhere inside |
`string1' or just past its end. This works if PTR is NULL, which is |
a good thing. */ |
# define FIRST_STRING_P(ptr) \ |
(size1 && string1 <= (ptr) && (ptr) <= string1 + size1) |
/* (Re)Allocate N items of type T using malloc, or fail. */ |
# define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t))) |
# define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t))) |
# define RETALLOC_IF(addr, n, t) \ |
if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t) |
# define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t))) |
# define BYTEWIDTH 8 /* In bits. */ |
# define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) |
# undef MAX |
# undef MIN |
# define MAX(a, b) ((a) > (b) ? (a) : (b)) |
# define MIN(a, b) ((a) < (b) ? (a) : (b)) |
typedef char boolean; |
# define false 0 |
# define true 1 |
static reg_errcode_t byte_regex_compile (const char *pattern, size_t size, |
reg_syntax_t syntax, |
struct re_pattern_buffer *bufp); |
static int byte_re_match_2_internal (struct re_pattern_buffer *bufp, |
const char *string1, int size1, |
const char *string2, int size2, |
int pos, |
struct re_registers *regs, |
int stop); |
static int byte_re_search_2 (struct re_pattern_buffer *bufp, |
const char *string1, int size1, |
const char *string2, int size2, |
int startpos, int range, |
struct re_registers *regs, int stop); |
static int byte_re_compile_fastmap (struct re_pattern_buffer *bufp); |
#ifdef MBS_SUPPORT |
static reg_errcode_t wcs_regex_compile (const char *pattern, size_t size, |
reg_syntax_t syntax, |
struct re_pattern_buffer *bufp); |
static int wcs_re_match_2_internal (struct re_pattern_buffer *bufp, |
const char *cstring1, int csize1, |
const char *cstring2, int csize2, |
int pos, |
struct re_registers *regs, |
int stop, |
wchar_t *string1, int size1, |
wchar_t *string2, int size2, |
int *mbs_offset1, int *mbs_offset2); |
static int wcs_re_search_2 (struct re_pattern_buffer *bufp, |
const char *string1, int size1, |
const char *string2, int size2, |
int startpos, int range, |
struct re_registers *regs, int stop); |
static int wcs_re_compile_fastmap (struct re_pattern_buffer *bufp); |
#endif |
/* These are the command codes that appear in compiled regular |
expressions. Some opcodes are followed by argument bytes. A |
command code can specify any interpretation whatsoever for its |
arguments. Zero bytes may appear in the compiled regular expression. */ |
typedef enum |
{ |
no_op = 0, |
/* Succeed right away--no more backtracking. */ |
succeed, |
/* Followed by one byte giving n, then by n literal bytes. */ |
exactn, |
# ifdef MBS_SUPPORT |
/* Same as exactn, but contains binary data. */ |
exactn_bin, |
# endif |
/* Matches any (more or less) character. */ |
anychar, |
/* Matches any one char belonging to specified set. First |
following byte is number of bitmap bytes. Then come bytes |
for a bitmap saying which chars are in. Bits in each byte |
are ordered low-bit-first. A character is in the set if its |
bit is 1. A character too large to have a bit in the map is |
automatically not in the set. */ |
/* ifdef MBS_SUPPORT, following element is length of character |
classes, length of collating symbols, length of equivalence |
classes, length of character ranges, and length of characters. |
Next, character class element, collating symbols elements, |
equivalence class elements, range elements, and character |
elements follow. |
See regex_compile function. */ |
charset, |
/* Same parameters as charset, but match any character that is |
not one of those specified. */ |
charset_not, |
/* Start remembering the text that is matched, for storing in a |
register. Followed by one byte with the register number, in |
the range 0 to one less than the pattern buffer's re_nsub |
field. Then followed by one byte with the number of groups |
inner to this one. (This last has to be part of the |
start_memory only because we need it in the on_failure_jump |
of re_match_2.) */ |
start_memory, |
/* Stop remembering the text that is matched and store it in a |
memory register. Followed by one byte with the register |
number, in the range 0 to one less than `re_nsub' in the |
pattern buffer, and one byte with the number of inner groups, |
just like `start_memory'. (We need the number of inner |
groups here because we don't have any easy way of finding the |
corresponding start_memory when we're at a stop_memory.) */ |
stop_memory, |
/* Match a duplicate of something remembered. Followed by one |
byte containing the register number. */ |
duplicate, |
/* Fail unless at beginning of line. */ |
begline, |
/* Fail unless at end of line. */ |
endline, |
/* Succeeds if at beginning of buffer (if emacs) or at beginning |
of string to be matched (if not). */ |
begbuf, |
/* Analogously, for end of buffer/string. */ |
endbuf, |
/* Followed by two byte relative address to which to jump. */ |
jump, |
/* Same as jump, but marks the end of an alternative. */ |
jump_past_alt, |
/* Followed by two-byte relative address of place to resume at |
in case of failure. */ |
/* ifdef MBS_SUPPORT, the size of address is 1. */ |
on_failure_jump, |
/* Like on_failure_jump, but pushes a placeholder instead of the |
current string position when executed. */ |
on_failure_keep_string_jump, |
/* Throw away latest failure point and then jump to following |
two-byte relative address. */ |
/* ifdef MBS_SUPPORT, the size of address is 1. */ |
pop_failure_jump, |
/* Change to pop_failure_jump if know won't have to backtrack to |
match; otherwise change to jump. This is used to jump |
back to the beginning of a repeat. If what follows this jump |
clearly won't match what the repeat does, such that we can be |
sure that there is no use backtracking out of repetitions |
already matched, then we change it to a pop_failure_jump. |
Followed by two-byte address. */ |
/* ifdef MBS_SUPPORT, the size of address is 1. */ |
maybe_pop_jump, |
/* Jump to following two-byte address, and push a dummy failure |
point. This failure point will be thrown away if an attempt |
is made to use it for a failure. A `+' construct makes this |
before the first repeat. Also used as an intermediary kind |
of jump when compiling an alternative. */ |
/* ifdef MBS_SUPPORT, the size of address is 1. */ |
dummy_failure_jump, |
/* Push a dummy failure point and continue. Used at the end of |
alternatives. */ |
push_dummy_failure, |
/* Followed by two-byte relative address and two-byte number n. |
After matching N times, jump to the address upon failure. */ |
/* ifdef MBS_SUPPORT, the size of address is 1. */ |
succeed_n, |
/* Followed by two-byte relative address, and two-byte number n. |
Jump to the address N times, then fail. */ |
/* ifdef MBS_SUPPORT, the size of address is 1. */ |
jump_n, |
/* Set the following two-byte relative address to the |
subsequent two-byte number. The address *includes* the two |
bytes of number. */ |
/* ifdef MBS_SUPPORT, the size of address is 1. */ |
set_number_at, |
wordchar, /* Matches any word-constituent character. */ |
notwordchar, /* Matches any char that is not a word-constituent. */ |
wordbeg, /* Succeeds if at word beginning. */ |
wordend, /* Succeeds if at word end. */ |
wordbound, /* Succeeds if at a word boundary. */ |
notwordbound /* Succeeds if not at a word boundary. */ |
# ifdef emacs |
,before_dot, /* Succeeds if before point. */ |
at_dot, /* Succeeds if at point. */ |
after_dot, /* Succeeds if after point. */ |
/* Matches any character whose syntax is specified. Followed by |
a byte which contains a syntax code, e.g., Sword. */ |
syntaxspec, |
/* Matches any character whose syntax is not that specified. */ |
notsyntaxspec |
# endif /* emacs */ |
} re_opcode_t; |
#endif /* not INSIDE_RECURSION */ |
#ifdef BYTE |
# define CHAR_T char |
# define UCHAR_T unsigned char |
# define COMPILED_BUFFER_VAR bufp->buffer |
# define OFFSET_ADDRESS_SIZE 2 |
# define PREFIX(name) byte_##name |
# define ARG_PREFIX(name) name |
# define PUT_CHAR(c) putchar (c) |
#else |
# ifdef WCHAR |
# define CHAR_T wchar_t |
# define UCHAR_T wchar_t |
# define COMPILED_BUFFER_VAR wc_buffer |
# define OFFSET_ADDRESS_SIZE 1 /* the size which STORE_NUMBER macro use */ |
# define CHAR_CLASS_SIZE ((__alignof__(wctype_t)+sizeof(wctype_t))/sizeof(CHAR_T)+1) |
# define PREFIX(name) wcs_##name |
# define ARG_PREFIX(name) c##name |
/* Should we use wide stream?? */ |
# define PUT_CHAR(c) printf ("%C", c); |
# define TRUE 1 |
# define FALSE 0 |
# else |
# ifdef MBS_SUPPORT |
# define WCHAR |
# define INSIDE_RECURSION |
# include "regex.c" |
# undef INSIDE_RECURSION |
# endif |
# define BYTE |
# define INSIDE_RECURSION |
# include "regex.c" |
# undef INSIDE_RECURSION |
# endif |
#endif |
#ifdef INSIDE_RECURSION |
/* Common operations on the compiled pattern. */ |
/* Store NUMBER in two contiguous bytes starting at DESTINATION. */ |
/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */ |
# ifdef WCHAR |
# define STORE_NUMBER(destination, number) \ |
do { \ |
*(destination) = (UCHAR_T)(number); \ |
} while (0) |
# else /* BYTE */ |
# define STORE_NUMBER(destination, number) \ |
do { \ |
(destination)[0] = (number) & 0377; \ |
(destination)[1] = (number) >> 8; \ |
} while (0) |
# endif /* WCHAR */ |
/* Same as STORE_NUMBER, except increment DESTINATION to |
the byte after where the number is stored. Therefore, DESTINATION |
must be an lvalue. */ |
/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */ |
# define STORE_NUMBER_AND_INCR(destination, number) \ |
do { \ |
STORE_NUMBER (destination, number); \ |
(destination) += OFFSET_ADDRESS_SIZE; \ |
} while (0) |
/* Put into DESTINATION a number stored in two contiguous bytes starting |
at SOURCE. */ |
/* ifdef MBS_SUPPORT, we store NUMBER in 1 element. */ |
# ifdef WCHAR |
# define EXTRACT_NUMBER(destination, source) \ |
do { \ |
(destination) = *(source); \ |
} while (0) |
# else /* BYTE */ |
# define EXTRACT_NUMBER(destination, source) \ |
do { \ |
(destination) = *(source) & 0377; \ |
(destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \ |
} while (0) |
# endif |
# ifdef DEBUG |
static void PREFIX(extract_number) (int *dest, UCHAR_T *source); |
static void |
PREFIX(extract_number) (int *dest, UCHAR_T *source) |
{ |
# ifdef WCHAR |
*dest = *source; |
# else /* BYTE */ |
int temp = SIGN_EXTEND_CHAR (*(source + 1)); |
*dest = *source & 0377; |
*dest += temp << 8; |
# endif |
} |
# ifndef EXTRACT_MACROS /* To debug the macros. */ |
# undef EXTRACT_NUMBER |
# define EXTRACT_NUMBER(dest, src) PREFIX(extract_number) (&dest, src) |
# endif /* not EXTRACT_MACROS */ |
# endif /* DEBUG */ |
/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number. |
SOURCE must be an lvalue. */ |
# define EXTRACT_NUMBER_AND_INCR(destination, source) \ |
do { \ |
EXTRACT_NUMBER (destination, source); \ |
(source) += OFFSET_ADDRESS_SIZE; \ |
} while (0) |
# ifdef DEBUG |
static void PREFIX(extract_number_and_incr) (int *destination, |
UCHAR_T **source); |
static void |
PREFIX(extract_number_and_incr) (int *destination, UCHAR_T **source) |
{ |
PREFIX(extract_number) (destination, *source); |
*source += OFFSET_ADDRESS_SIZE; |
} |
# ifndef EXTRACT_MACROS |
# undef EXTRACT_NUMBER_AND_INCR |
# define EXTRACT_NUMBER_AND_INCR(dest, src) \ |
PREFIX(extract_number_and_incr) (&dest, &src) |
# endif /* not EXTRACT_MACROS */ |
# endif /* DEBUG */ |
/* If DEBUG is defined, Regex prints many voluminous messages about what |
it is doing (if the variable `debug' is nonzero). If linked with the |
main program in `iregex.c', you can enter patterns and strings |
interactively. And if linked with the main program in `main.c' and |
the other test files, you can run the already-written tests. */ |
# ifdef DEBUG |
# ifndef DEFINED_ONCE |
/* We use standard I/O for debugging. */ |
# include <stdio.h> |
/* It is useful to test things that ``must'' be true when debugging. */ |
# include <assert.h> |
static int debug; |
# define DEBUG_STATEMENT(e) e |
# define DEBUG_PRINT1(x) if (debug) printf (x) |
# define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2) |
# define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3) |
# define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4) |
# endif /* not DEFINED_ONCE */ |
# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \ |
if (debug) PREFIX(print_partial_compiled_pattern) (s, e) |
# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \ |
if (debug) PREFIX(print_double_string) (w, s1, sz1, s2, sz2) |
/* Print the fastmap in human-readable form. */ |
# ifndef DEFINED_ONCE |
void |
print_fastmap (char *fastmap) |
{ |
unsigned was_a_range = 0; |
unsigned i = 0; |
while (i < (1 << BYTEWIDTH)) |
{ |
if (fastmap[i++]) |
{ |
was_a_range = 0; |
putchar (i - 1); |
while (i < (1 << BYTEWIDTH) && fastmap[i]) |
{ |
was_a_range = 1; |
i++; |
} |
if (was_a_range) |
{ |
printf ("-"); |
putchar (i - 1); |
} |
} |
} |
putchar ('\n'); |
} |
# endif /* not DEFINED_ONCE */ |
/* Print a compiled pattern string in human-readable form, starting at |
the START pointer into it and ending just before the pointer END. */ |
void |
PREFIX(print_partial_compiled_pattern) (UCHAR_T *start, UCHAR_T *end) |
{ |
int mcnt, mcnt2; |
UCHAR_T *p1; |
UCHAR_T *p = start; |
UCHAR_T *pend = end; |
if (start == NULL) |
{ |
printf ("(null)\n"); |
return; |
} |
/* Loop over pattern commands. */ |
while (p < pend) |
{ |
# ifdef _LIBC |
printf ("%td:\t", p - start); |
# else |
printf ("%ld:\t", (long int) (p - start)); |
# endif |
switch ((re_opcode_t) *p++) |
{ |
case no_op: |
printf ("/no_op"); |
break; |
case exactn: |
mcnt = *p++; |
printf ("/exactn/%d", mcnt); |
do |
{ |
putchar ('/'); |
PUT_CHAR (*p++); |
} |
while (--mcnt); |
break; |
# ifdef MBS_SUPPORT |
case exactn_bin: |
mcnt = *p++; |
printf ("/exactn_bin/%d", mcnt); |
do |
{ |
printf("/%lx", (long int) *p++); |
} |
while (--mcnt); |
break; |
# endif /* MBS_SUPPORT */ |
case start_memory: |
mcnt = *p++; |
printf ("/start_memory/%d/%ld", mcnt, (long int) *p++); |
break; |
case stop_memory: |
mcnt = *p++; |
printf ("/stop_memory/%d/%ld", mcnt, (long int) *p++); |
break; |
case duplicate: |
printf ("/duplicate/%ld", (long int) *p++); |
break; |
case anychar: |
printf ("/anychar"); |
break; |
case charset: |
case charset_not: |
{ |
# ifdef WCHAR |
int i, length; |
wchar_t *workp = p; |
printf ("/charset [%s", |
(re_opcode_t) *(workp - 1) == charset_not ? "^" : ""); |
p += 5; |
length = *workp++; /* the length of char_classes */ |
for (i=0 ; i<length ; i++) |
printf("[:%lx:]", (long int) *p++); |
length = *workp++; /* the length of collating_symbol */ |
for (i=0 ; i<length ;) |
{ |
printf("[."); |
while(*p != 0) |
PUT_CHAR((i++,*p++)); |
i++,p++; |
printf(".]"); |
} |
length = *workp++; /* the length of equivalence_class */ |
for (i=0 ; i<length ;) |
{ |
printf("[="); |
while(*p != 0) |
PUT_CHAR((i++,*p++)); |
i++,p++; |
printf("=]"); |
} |
length = *workp++; /* the length of char_range */ |
for (i=0 ; i<length ; i++) |
{ |
wchar_t range_start = *p++; |
wchar_t range_end = *p++; |
printf("%C-%C", range_start, range_end); |
} |
length = *workp++; /* the length of char */ |
for (i=0 ; i<length ; i++) |
printf("%C", *p++); |
putchar (']'); |
# else |
register int c, last = -100; |
register int in_range = 0; |
printf ("/charset [%s", |
(re_opcode_t) *(p - 1) == charset_not ? "^" : ""); |
assert (p + *p < pend); |
for (c = 0; c < 256; c++) |
if (c / 8 < *p |
&& (p[1 + (c/8)] & (1 << (c % 8)))) |
{ |
/* Are we starting a range? */ |
if (last + 1 == c && ! in_range) |
{ |
putchar ('-'); |
in_range = 1; |
} |
/* Have we broken a range? */ |
else if (last + 1 != c && in_range) |
{ |
putchar (last); |
in_range = 0; |
} |
if (! in_range) |
putchar (c); |
last = c; |
} |
if (in_range) |
putchar (last); |
putchar (']'); |
p += 1 + *p; |
# endif /* WCHAR */ |
} |
break; |
case begline: |
printf ("/begline"); |
break; |
case endline: |
printf ("/endline"); |
break; |
case on_failure_jump: |
PREFIX(extract_number_and_incr) (&mcnt, &p); |
# ifdef _LIBC |
printf ("/on_failure_jump to %td", p + mcnt - start); |
# else |
printf ("/on_failure_jump to %ld", (long int) (p + mcnt - start)); |
# endif |
break; |
case on_failure_keep_string_jump: |
PREFIX(extract_number_and_incr) (&mcnt, &p); |
# ifdef _LIBC |
printf ("/on_failure_keep_string_jump to %td", p + mcnt - start); |
# else |
printf ("/on_failure_keep_string_jump to %ld", |
(long int) (p + mcnt - start)); |
# endif |
break; |
case dummy_failure_jump: |
PREFIX(extract_number_and_incr) (&mcnt, &p); |
# ifdef _LIBC |
printf ("/dummy_failure_jump to %td", p + mcnt - start); |
# else |
printf ("/dummy_failure_jump to %ld", (long int) (p + mcnt - start)); |
# endif |
break; |
case push_dummy_failure: |
printf ("/push_dummy_failure"); |
break; |
case maybe_pop_jump: |
PREFIX(extract_number_and_incr) (&mcnt, &p); |
# ifdef _LIBC |
printf ("/maybe_pop_jump to %td", p + mcnt - start); |
# else |
printf ("/maybe_pop_jump to %ld", (long int) (p + mcnt - start)); |
# endif |
break; |
case pop_failure_jump: |
PREFIX(extract_number_and_incr) (&mcnt, &p); |
# ifdef _LIBC |
printf ("/pop_failure_jump to %td", p + mcnt - start); |
# else |
printf ("/pop_failure_jump to %ld", (long int) (p + mcnt - start)); |
# endif |
break; |
case jump_past_alt: |
PREFIX(extract_number_and_incr) (&mcnt, &p); |
# ifdef _LIBC |
printf ("/jump_past_alt to %td", p + mcnt - start); |
# else |
printf ("/jump_past_alt to %ld", (long int) (p + mcnt - start)); |
# endif |
break; |
case jump: |
PREFIX(extract_number_and_incr) (&mcnt, &p); |
# ifdef _LIBC |
printf ("/jump to %td", p + mcnt - start); |
# else |
printf ("/jump to %ld", (long int) (p + mcnt - start)); |
# endif |
break; |
case succeed_n: |
PREFIX(extract_number_and_incr) (&mcnt, &p); |
p1 = p + mcnt; |
PREFIX(extract_number_and_incr) (&mcnt2, &p); |
# ifdef _LIBC |
printf ("/succeed_n to %td, %d times", p1 - start, mcnt2); |
# else |
printf ("/succeed_n to %ld, %d times", |
(long int) (p1 - start), mcnt2); |
# endif |
break; |
case jump_n: |
PREFIX(extract_number_and_incr) (&mcnt, &p); |
p1 = p + mcnt; |
PREFIX(extract_number_and_incr) (&mcnt2, &p); |
printf ("/jump_n to %d, %d times", p1 - start, mcnt2); |
break; |
case set_number_at: |
PREFIX(extract_number_and_incr) (&mcnt, &p); |
p1 = p + mcnt; |
PREFIX(extract_number_and_incr) (&mcnt2, &p); |
# ifdef _LIBC |
printf ("/set_number_at location %td to %d", p1 - start, mcnt2); |
# else |
printf ("/set_number_at location %ld to %d", |
(long int) (p1 - start), mcnt2); |
# endif |
break; |
case wordbound: |
printf ("/wordbound"); |
break; |
case notwordbound: |
printf ("/notwordbound"); |
break; |
case wordbeg: |
printf ("/wordbeg"); |
break; |
case wordend: |
printf ("/wordend"); |
break; |
# ifdef emacs |
case before_dot: |
printf ("/before_dot"); |
break; |
case at_dot: |
printf ("/at_dot"); |
break; |
case after_dot: |
printf ("/after_dot"); |
break; |
case syntaxspec: |
printf ("/syntaxspec"); |
mcnt = *p++; |
printf ("/%d", mcnt); |
break; |
case notsyntaxspec: |
printf ("/notsyntaxspec"); |
mcnt = *p++; |
printf ("/%d", mcnt); |
break; |
# endif /* emacs */ |
case wordchar: |
printf ("/wordchar"); |
break; |
case notwordchar: |
printf ("/notwordchar"); |
break; |
case begbuf: |
printf ("/begbuf"); |
break; |
case endbuf: |
printf ("/endbuf"); |
break; |
default: |
printf ("?%ld", (long int) *(p-1)); |
} |
putchar ('\n'); |
} |
# ifdef _LIBC |
printf ("%td:\tend of pattern.\n", p - start); |
# else |
printf ("%ld:\tend of pattern.\n", (long int) (p - start)); |
# endif |
} |
void |
PREFIX(print_compiled_pattern) (struct re_pattern_buffer *bufp) |
{ |
UCHAR_T *buffer = (UCHAR_T*) bufp->buffer; |
PREFIX(print_partial_compiled_pattern) (buffer, buffer |
+ bufp->used / sizeof(UCHAR_T)); |
printf ("%ld bytes used/%ld bytes allocated.\n", |
bufp->used, bufp->allocated); |
if (bufp->fastmap_accurate && bufp->fastmap) |
{ |
printf ("fastmap: "); |
print_fastmap (bufp->fastmap); |
} |
# ifdef _LIBC |
printf ("re_nsub: %Zd\t", bufp->re_nsub); |
# else |
printf ("re_nsub: %ld\t", (long int) bufp->re_nsub); |
# endif |
printf ("regs_alloc: %d\t", bufp->regs_allocated); |
printf ("can_be_null: %d\t", bufp->can_be_null); |
printf ("newline_anchor: %d\n", bufp->newline_anchor); |
printf ("no_sub: %d\t", bufp->no_sub); |
printf ("not_bol: %d\t", bufp->not_bol); |
printf ("not_eol: %d\t", bufp->not_eol); |
printf ("syntax: %lx\n", bufp->syntax); |
/* Perhaps we should print the translate table? */ |
} |
void |
PREFIX(print_double_string) (const CHAR_T *where, const CHAR_T *string1, |
int size1, const CHAR_T *string2, int size2) |
{ |
int this_char; |
if (where == NULL) |
printf ("(null)"); |
else |
{ |
int cnt; |
if (FIRST_STRING_P (where)) |
{ |
for (this_char = where - string1; this_char < size1; this_char++) |
PUT_CHAR (string1[this_char]); |
where = string2; |
} |
cnt = 0; |
for (this_char = where - string2; this_char < size2; this_char++) |
{ |
PUT_CHAR (string2[this_char]); |
if (++cnt > 100) |
{ |
fputs ("...", stdout); |
break; |
} |
} |
} |
} |
# ifndef DEFINED_ONCE |
void |
printchar (int c) |
{ |
putc (c, stderr); |
} |
# endif |
# else /* not DEBUG */ |
# ifndef DEFINED_ONCE |
# undef assert |
# define assert(e) |
# define DEBUG_STATEMENT(e) |
# define DEBUG_PRINT1(x) |
# define DEBUG_PRINT2(x1, x2) |
# define DEBUG_PRINT3(x1, x2, x3) |
# define DEBUG_PRINT4(x1, x2, x3, x4) |
# endif /* not DEFINED_ONCE */ |
# define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) |
# define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) |
# endif /* not DEBUG */ |
# ifdef WCHAR |
/* This convert a multibyte string to a wide character string. |
And write their correspondances to offset_buffer(see below) |
and write whether each wchar_t is binary data to is_binary. |
This assume invalid multibyte sequences as binary data. |
We assume offset_buffer and is_binary is already allocated |
enough space. */ |
static size_t convert_mbs_to_wcs (CHAR_T *dest, const unsigned char* src, |
size_t len, int *offset_buffer, |
char *is_binary); |
static size_t |
convert_mbs_to_wcs (CHAR_T *dest, const unsigned char*src, size_t len, |
int *offset_buffer, char *is_binary) |
/* It hold correspondances between src(char string) and |
dest(wchar_t string) for optimization. |
e.g. src = "xxxyzz" |
dest = {'X', 'Y', 'Z'} |
(each "xxx", "y" and "zz" represent one multibyte character |
corresponding to 'X', 'Y' and 'Z'.) |
offset_buffer = {0, 0+3("xxx"), 0+3+1("y"), 0+3+1+2("zz")} |
= {0, 3, 4, 6} |
*/ |
{ |
wchar_t *pdest = dest; |
const unsigned char *psrc = src; |
size_t wc_count = 0; |
mbstate_t mbs; |
int i, consumed; |
size_t mb_remain = len; |
size_t mb_count = 0; |
/* Initialize the conversion state. */ |
memset (&mbs, 0, sizeof (mbstate_t)); |
offset_buffer[0] = 0; |
for( ; mb_remain > 0 ; ++wc_count, ++pdest, mb_remain -= consumed, |
psrc += consumed) |
{ |
#ifdef _LIBC |
consumed = __mbrtowc (pdest, psrc, mb_remain, &mbs); |
#else |
consumed = mbrtowc (pdest, psrc, mb_remain, &mbs); |
#endif |
if (consumed <= 0) |
/* failed to convert. maybe src contains binary data. |
So we consume 1 byte manualy. */ |
{ |
*pdest = *psrc; |
consumed = 1; |
is_binary[wc_count] = TRUE; |
} |
else |
is_binary[wc_count] = FALSE; |
/* In sjis encoding, we use yen sign as escape character in |
place of reverse solidus. So we convert 0x5c(yen sign in |
sjis) to not 0xa5(yen sign in UCS2) but 0x5c(reverse |
solidus in UCS2). */ |
if (consumed == 1 && (int) *psrc == 0x5c && (int) *pdest == 0xa5) |
*pdest = (wchar_t) *psrc; |
offset_buffer[wc_count + 1] = mb_count += consumed; |
} |
/* Fill remain of the buffer with sentinel. */ |
for (i = wc_count + 1 ; i <= len ; i++) |
offset_buffer[i] = mb_count + 1; |
return wc_count; |
} |
# endif /* WCHAR */ |
#else /* not INSIDE_RECURSION */ |
/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can |
also be assigned to arbitrarily: each pattern buffer stores its own |
syntax, so it can be changed between regex compilations. */ |
/* This has no initializer because initialized variables in Emacs |
become read-only after dumping. */ |
reg_syntax_t re_syntax_options; |
/* Specify the precise syntax of regexps for compilation. This provides |
for compatibility for various utilities which historically have |
different, incompatible syntaxes. |
The argument SYNTAX is a bit mask comprised of the various bits |
defined in regex.h. We return the old syntax. */ |
reg_syntax_t |
re_set_syntax (reg_syntax_t syntax) |
{ |
reg_syntax_t ret = re_syntax_options; |
re_syntax_options = syntax; |
# ifdef DEBUG |
if (syntax & RE_DEBUG) |
debug = 1; |
else if (debug) /* was on but now is not */ |
debug = 0; |
# endif /* DEBUG */ |
return ret; |
} |
# ifdef _LIBC |
weak_alias (__re_set_syntax, re_set_syntax) |
# endif |
/* This table gives an error message for each of the error codes listed |
in regex.h. Obviously the order here has to be same as there. |
POSIX doesn't require that we do anything for REG_NOERROR, |
but why not be nice? */ |
static const char *re_error_msgid[] = |
{ |
gettext_noop ("Success"), /* REG_NOERROR */ |
gettext_noop ("No match"), /* REG_NOMATCH */ |
gettext_noop ("Invalid regular expression"), /* REG_BADPAT */ |
gettext_noop ("Invalid collation character"), /* REG_ECOLLATE */ |
gettext_noop ("Invalid character class name"), /* REG_ECTYPE */ |
gettext_noop ("Trailing backslash"), /* REG_EESCAPE */ |
gettext_noop ("Invalid back reference"), /* REG_ESUBREG */ |
gettext_noop ("Unmatched [ or [^"), /* REG_EBRACK */ |
gettext_noop ("Unmatched ( or \\("), /* REG_EPAREN */ |
gettext_noop ("Unmatched \\{"), /* REG_EBRACE */ |
gettext_noop ("Invalid content of \\{\\}"), /* REG_BADBR */ |
gettext_noop ("Invalid range end"), /* REG_ERANGE */ |
gettext_noop ("Memory exhausted"), /* REG_ESPACE */ |
gettext_noop ("Invalid preceding regular expression"), /* REG_BADRPT */ |
gettext_noop ("Premature end of regular expression"), /* REG_EEND */ |
gettext_noop ("Regular expression too big"), /* REG_ESIZE */ |
gettext_noop ("Unmatched ) or \\)") /* REG_ERPAREN */ |
}; |
#endif /* INSIDE_RECURSION */ |
#ifndef DEFINED_ONCE |
/* Avoiding alloca during matching, to placate r_alloc. */ |
/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the |
searching and matching functions should not call alloca. On some |
systems, alloca is implemented in terms of malloc, and if we're |
using the relocating allocator routines, then malloc could cause a |
relocation, which might (if the strings being searched are in the |
ralloc heap) shift the data out from underneath the regexp |
routines. |
Here's another reason to avoid allocation: Emacs |
processes input from X in a signal handler; processing X input may |
call malloc; if input arrives while a matching routine is calling |
malloc, then we're scrod. But Emacs can't just block input while |
calling matching routines; then we don't notice interrupts when |
they come in. So, Emacs blocks input around all regexp calls |
except the matching calls, which it leaves unprotected, in the |
faith that they will not malloc. */ |
/* Normally, this is fine. */ |
# define MATCH_MAY_ALLOCATE |
/* When using GNU C, we are not REALLY using the C alloca, no matter |
what config.h may say. So don't take precautions for it. */ |
# ifdef __GNUC__ |
# undef C_ALLOCA |
# endif |
/* The match routines may not allocate if (1) they would do it with malloc |
and (2) it's not safe for them to use malloc. |
Note that if REL_ALLOC is defined, matching would not use malloc for the |
failure stack, but we would still use it for the register vectors; |
so REL_ALLOC should not affect this. */ |
# if (defined C_ALLOCA || defined REGEX_MALLOC) && defined emacs |
# undef MATCH_MAY_ALLOCATE |
# endif |
#endif /* not DEFINED_ONCE */ |
#ifdef INSIDE_RECURSION |
/* Failure stack declarations and macros; both re_compile_fastmap and |
re_match_2 use a failure stack. These have to be macros because of |
REGEX_ALLOCATE_STACK. */ |
/* Number of failure points for which to initially allocate space |
when matching. If this number is exceeded, we allocate more |
space, so it is not a hard limit. */ |
# ifndef INIT_FAILURE_ALLOC |
# define INIT_FAILURE_ALLOC 5 |
# endif |
/* Roughly the maximum number of failure points on the stack. Would be |
exactly that if always used MAX_FAILURE_ITEMS items each time we failed. |
This is a variable only so users of regex can assign to it; we never |
change it ourselves. */ |
# ifdef INT_IS_16BIT |
# ifndef DEFINED_ONCE |
# if defined MATCH_MAY_ALLOCATE |
/* 4400 was enough to cause a crash on Alpha OSF/1, |
whose default stack limit is 2mb. */ |
long int re_max_failures = 4000; |
# else |
long int re_max_failures = 2000; |
# endif |
# endif |
union PREFIX(fail_stack_elt) |
{ |
UCHAR_T *pointer; |
long int integer; |
}; |
typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t); |
typedef struct |
{ |
PREFIX(fail_stack_elt_t) *stack; |
unsigned long int size; |
unsigned long int avail; /* Offset of next open position. */ |
} PREFIX(fail_stack_type); |
# else /* not INT_IS_16BIT */ |
# ifndef DEFINED_ONCE |
# if defined MATCH_MAY_ALLOCATE |
/* 4400 was enough to cause a crash on Alpha OSF/1, |
whose default stack limit is 2mb. */ |
int re_max_failures = 4000; |
# else |
int re_max_failures = 2000; |
# endif |
# endif |
union PREFIX(fail_stack_elt) |
{ |
UCHAR_T *pointer; |
int integer; |
}; |
typedef union PREFIX(fail_stack_elt) PREFIX(fail_stack_elt_t); |
typedef struct |
{ |
PREFIX(fail_stack_elt_t) *stack; |
unsigned size; |
unsigned avail; /* Offset of next open position. */ |
} PREFIX(fail_stack_type); |
# endif /* INT_IS_16BIT */ |
# ifndef DEFINED_ONCE |
# define FAIL_STACK_EMPTY() (fail_stack.avail == 0) |
# define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0) |
# define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size) |
# endif |
/* Define macros to initialize and free the failure stack. |
Do `return -2' if the alloc fails. */ |
# ifdef MATCH_MAY_ALLOCATE |
# define INIT_FAIL_STACK() \ |
do { \ |
fail_stack.stack = (PREFIX(fail_stack_elt_t) *) \ |
REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (PREFIX(fail_stack_elt_t))); \ |
\ |
if (fail_stack.stack == NULL) \ |
return -2; \ |
\ |
fail_stack.size = INIT_FAILURE_ALLOC; \ |
fail_stack.avail = 0; \ |
} while (0) |
# define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack) |
# else |
# define INIT_FAIL_STACK() \ |
do { \ |
fail_stack.avail = 0; \ |
} while (0) |
# define RESET_FAIL_STACK() |
# endif |
/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items. |
Return 1 if succeeds, and 0 if either ran out of memory |
allocating space for it or it was already too large. |
REGEX_REALLOCATE_STACK requires `destination' be declared. */ |
# define DOUBLE_FAIL_STACK(fail_stack) \ |
((fail_stack).size > (unsigned) (re_max_failures * MAX_FAILURE_ITEMS) \ |
? 0 \ |
: ((fail_stack).stack = (PREFIX(fail_stack_elt_t) *) \ |
REGEX_REALLOCATE_STACK ((fail_stack).stack, \ |
(fail_stack).size * sizeof (PREFIX(fail_stack_elt_t)), \ |
((fail_stack).size << 1) * sizeof (PREFIX(fail_stack_elt_t))),\ |
\ |
(fail_stack).stack == NULL \ |
? 0 \ |
: ((fail_stack).size <<= 1, \ |
1))) |
/* Push pointer POINTER on FAIL_STACK. |
Return 1 if was able to do so and 0 if ran out of memory allocating |
space to do so. */ |
# define PUSH_PATTERN_OP(POINTER, FAIL_STACK) \ |
((FAIL_STACK_FULL () \ |
&& !DOUBLE_FAIL_STACK (FAIL_STACK)) \ |
? 0 \ |
: ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER, \ |
1)) |
/* Push a pointer value onto the failure stack. |
Assumes the variable `fail_stack'. Probably should only |
be called from within `PUSH_FAILURE_POINT'. */ |
# define PUSH_FAILURE_POINTER(item) \ |
fail_stack.stack[fail_stack.avail++].pointer = (UCHAR_T *) (item) |
/* This pushes an integer-valued item onto the failure stack. |
Assumes the variable `fail_stack'. Probably should only |
be called from within `PUSH_FAILURE_POINT'. */ |
# define PUSH_FAILURE_INT(item) \ |
fail_stack.stack[fail_stack.avail++].integer = (item) |
/* Push a fail_stack_elt_t value onto the failure stack. |
Assumes the variable `fail_stack'. Probably should only |
be called from within `PUSH_FAILURE_POINT'. */ |
# define PUSH_FAILURE_ELT(item) \ |
fail_stack.stack[fail_stack.avail++] = (item) |
/* These three POP... operations complement the three PUSH... operations. |
All assume that `fail_stack' is nonempty. */ |
# define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer |
# define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer |
# define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail] |
/* Used to omit pushing failure point id's when we're not debugging. */ |
# ifdef DEBUG |
# define DEBUG_PUSH PUSH_FAILURE_INT |
# define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT () |
# else |
# define DEBUG_PUSH(item) |
# define DEBUG_POP(item_addr) |
# endif |
/* Push the information about the state we will need |
if we ever fail back to it. |
Requires variables fail_stack, regstart, regend, reg_info, and |
num_regs_pushed be declared. DOUBLE_FAIL_STACK requires `destination' |
be declared. |
Does `return FAILURE_CODE' if runs out of memory. */ |
# define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \ |
do { \ |
char *destination; \ |
/* Must be int, so when we don't save any registers, the arithmetic \ |
of 0 + -1 isn't done as unsigned. */ \ |
/* Can't be int, since there is not a shred of a guarantee that int \ |
is wide enough to hold a value of something to which pointer can \ |
be assigned */ \ |
active_reg_t this_reg; \ |
\ |
DEBUG_STATEMENT (failure_id++); \ |
DEBUG_STATEMENT (nfailure_points_pushed++); \ |
DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \ |
DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\ |
DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\ |
\ |
DEBUG_PRINT2 (" slots needed: %ld\n", NUM_FAILURE_ITEMS); \ |
DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \ |
\ |
/* Ensure we have enough space allocated for what we will push. */ \ |
while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \ |
{ \ |
if (!DOUBLE_FAIL_STACK (fail_stack)) \ |
return failure_code; \ |
\ |
DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \ |
(fail_stack).size); \ |
DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\ |
} \ |
\ |
/* Push the info, starting with the registers. */ \ |
DEBUG_PRINT1 ("\n"); \ |
\ |
if (1) \ |
for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \ |
this_reg++) \ |
{ \ |
DEBUG_PRINT2 (" Pushing reg: %lu\n", this_reg); \ |
DEBUG_STATEMENT (num_regs_pushed++); \ |
\ |
DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ |
PUSH_FAILURE_POINTER (regstart[this_reg]); \ |
\ |
DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ |
PUSH_FAILURE_POINTER (regend[this_reg]); \ |
\ |
DEBUG_PRINT2 (" info: %p\n ", \ |
reg_info[this_reg].word.pointer); \ |
DEBUG_PRINT2 (" match_null=%d", \ |
REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \ |
DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \ |
DEBUG_PRINT2 (" matched_something=%d", \ |
MATCHED_SOMETHING (reg_info[this_reg])); \ |
DEBUG_PRINT2 (" ever_matched=%d", \ |
EVER_MATCHED_SOMETHING (reg_info[this_reg])); \ |
DEBUG_PRINT1 ("\n"); \ |
PUSH_FAILURE_ELT (reg_info[this_reg].word); \ |
} \ |
\ |
DEBUG_PRINT2 (" Pushing low active reg: %ld\n", lowest_active_reg);\ |
PUSH_FAILURE_INT (lowest_active_reg); \ |
\ |
DEBUG_PRINT2 (" Pushing high active reg: %ld\n", highest_active_reg);\ |
PUSH_FAILURE_INT (highest_active_reg); \ |
\ |
DEBUG_PRINT2 (" Pushing pattern %p:\n", pattern_place); \ |
DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \ |
PUSH_FAILURE_POINTER (pattern_place); \ |
\ |
DEBUG_PRINT2 (" Pushing string %p: `", string_place); \ |
DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \ |
size2); \ |
DEBUG_PRINT1 ("'\n"); \ |
PUSH_FAILURE_POINTER (string_place); \ |
\ |
DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \ |
DEBUG_PUSH (failure_id); \ |
} while (0) |
# ifndef DEFINED_ONCE |
/* This is the number of items that are pushed and popped on the stack |
for each register. */ |
# define NUM_REG_ITEMS 3 |
/* Individual items aside from the registers. */ |
# ifdef DEBUG |
# define NUM_NONREG_ITEMS 5 /* Includes failure point id. */ |
# else |
# define NUM_NONREG_ITEMS 4 |
# endif |
/* We push at most this many items on the stack. */ |
/* We used to use (num_regs - 1), which is the number of registers |
this regexp will save; but that was changed to 5 |
to avoid stack overflow for a regexp with lots of parens. */ |
# define MAX_FAILURE_ITEMS (5 * NUM_REG_ITEMS + NUM_NONREG_ITEMS) |
/* We actually push this many items. */ |
# define NUM_FAILURE_ITEMS \ |
(((0 \ |
? 0 : highest_active_reg - lowest_active_reg + 1) \ |
* NUM_REG_ITEMS) \ |
+ NUM_NONREG_ITEMS) |
/* How many items can still be added to the stack without overflowing it. */ |
# define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail) |
# endif /* not DEFINED_ONCE */ |
/* Pops what PUSH_FAIL_STACK pushes. |
We restore into the parameters, all of which should be lvalues: |
STR -- the saved data position. |
PAT -- the saved pattern position. |
LOW_REG, HIGH_REG -- the highest and lowest active registers. |
REGSTART, REGEND -- arrays of string positions. |
REG_INFO -- array of information about each subexpression. |
Also assumes the variables `fail_stack' and (if debugging), `bufp', |
`pend', `string1', `size1', `string2', and `size2'. */ |
# define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\ |
{ \ |
DEBUG_STATEMENT (unsigned failure_id;) \ |
active_reg_t this_reg; \ |
const UCHAR_T *string_temp; \ |
\ |
assert (!FAIL_STACK_EMPTY ()); \ |
\ |
/* Remove failure points and point to how many regs pushed. */ \ |
DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \ |
DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \ |
DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \ |
\ |
assert (fail_stack.avail >= NUM_NONREG_ITEMS); \ |
\ |
DEBUG_POP (&failure_id); \ |
DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \ |
\ |
/* If the saved string location is NULL, it came from an \ |
on_failure_keep_string_jump opcode, and we want to throw away the \ |
saved NULL, thus retaining our current position in the string. */ \ |
string_temp = POP_FAILURE_POINTER (); \ |
if (string_temp != NULL) \ |
str = (const CHAR_T *) string_temp; \ |
\ |
DEBUG_PRINT2 (" Popping string %p: `", str); \ |
DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \ |
DEBUG_PRINT1 ("'\n"); \ |
\ |
pat = (UCHAR_T *) POP_FAILURE_POINTER (); \ |
DEBUG_PRINT2 (" Popping pattern %p:\n", pat); \ |
DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \ |
\ |
/* Restore register info. */ \ |
high_reg = (active_reg_t) POP_FAILURE_INT (); \ |
DEBUG_PRINT2 (" Popping high active reg: %ld\n", high_reg); \ |
\ |
low_reg = (active_reg_t) POP_FAILURE_INT (); \ |
DEBUG_PRINT2 (" Popping low active reg: %ld\n", low_reg); \ |
\ |
if (1) \ |
for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \ |
{ \ |
DEBUG_PRINT2 (" Popping reg: %ld\n", this_reg); \ |
\ |
reg_info[this_reg].word = POP_FAILURE_ELT (); \ |
DEBUG_PRINT2 (" info: %p\n", \ |
reg_info[this_reg].word.pointer); \ |
\ |
regend[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER (); \ |
DEBUG_PRINT2 (" end: %p\n", regend[this_reg]); \ |
\ |
regstart[this_reg] = (const CHAR_T *) POP_FAILURE_POINTER (); \ |
DEBUG_PRINT2 (" start: %p\n", regstart[this_reg]); \ |
} \ |
else \ |
{ \ |
for (this_reg = highest_active_reg; this_reg > high_reg; this_reg--) \ |
{ \ |
reg_info[this_reg].word.integer = 0; \ |
regend[this_reg] = 0; \ |
regstart[this_reg] = 0; \ |
} \ |
highest_active_reg = high_reg; \ |
} \ |
\ |
set_regs_matched_done = 0; \ |
DEBUG_STATEMENT (nfailure_points_popped++); \ |
} /* POP_FAILURE_POINT */ |
/* Structure for per-register (a.k.a. per-group) information. |
Other register information, such as the |
starting and ending positions (which are addresses), and the list of |
inner groups (which is a bits list) are maintained in separate |
variables. |
We are making a (strictly speaking) nonportable assumption here: that |
the compiler will pack our bit fields into something that fits into |
the type of `word', i.e., is something that fits into one item on the |
failure stack. */ |
/* Declarations and macros for re_match_2. */ |
typedef union |
{ |
PREFIX(fail_stack_elt_t) word; |
struct |
{ |
/* This field is one if this group can match the empty string, |
zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */ |
# define MATCH_NULL_UNSET_VALUE 3 |
unsigned match_null_string_p : 2; |
unsigned is_active : 1; |
unsigned matched_something : 1; |
unsigned ever_matched_something : 1; |
} bits; |
} PREFIX(register_info_type); |
# ifndef DEFINED_ONCE |
# define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p) |
# define IS_ACTIVE(R) ((R).bits.is_active) |
# define MATCHED_SOMETHING(R) ((R).bits.matched_something) |
# define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something) |
/* Call this when have matched a real character; it sets `matched' flags |
for the subexpressions which we are currently inside. Also records |
that those subexprs have matched. */ |
# define SET_REGS_MATCHED() \ |
do \ |
{ \ |
if (!set_regs_matched_done) \ |
{ \ |
active_reg_t r; \ |
set_regs_matched_done = 1; \ |
for (r = lowest_active_reg; r <= highest_active_reg; r++) \ |
{ \ |
MATCHED_SOMETHING (reg_info[r]) \ |
= EVER_MATCHED_SOMETHING (reg_info[r]) \ |
= 1; \ |
} \ |
} \ |
} \ |
while (0) |
# endif /* not DEFINED_ONCE */ |
/* Registers are set to a sentinel when they haven't yet matched. */ |
static CHAR_T PREFIX(reg_unset_dummy); |
# define REG_UNSET_VALUE (&PREFIX(reg_unset_dummy)) |
# define REG_UNSET(e) ((e) == REG_UNSET_VALUE) |
/* Subroutine declarations and macros for regex_compile. */ |
static void PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg); |
static void PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc, |
int arg1, int arg2); |
static void PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc, |
int arg, UCHAR_T *end); |
static void PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc, |
int arg1, int arg2, UCHAR_T *end); |
static boolean PREFIX(at_begline_loc_p) (const CHAR_T *pattern, |
const CHAR_T *p, |
reg_syntax_t syntax); |
static boolean PREFIX(at_endline_loc_p) (const CHAR_T *p, |
const CHAR_T *pend, |
reg_syntax_t syntax); |
# ifdef WCHAR |
static reg_errcode_t wcs_compile_range (CHAR_T range_start, |
const CHAR_T **p_ptr, |
const CHAR_T *pend, |
char *translate, |
reg_syntax_t syntax, |
UCHAR_T *b, |
CHAR_T *char_set); |
static void insert_space (int num, CHAR_T *loc, CHAR_T *end); |
# else /* BYTE */ |
static reg_errcode_t byte_compile_range (unsigned int range_start, |
const char **p_ptr, |
const char *pend, |
char *translate, |
reg_syntax_t syntax, |
unsigned char *b); |
# endif /* WCHAR */ |
/* Fetch the next character in the uncompiled pattern---translating it |
if necessary. Also cast from a signed character in the constant |
string passed to us by the user to an unsigned char that we can use |
as an array index (in, e.g., `translate'). */ |
/* ifdef MBS_SUPPORT, we translate only if character <= 0xff, |
because it is impossible to allocate 4GB array for some encodings |
which have 4 byte character_set like UCS4. */ |
# ifndef PATFETCH |
# ifdef WCHAR |
# define PATFETCH(c) \ |
do {if (p == pend) return REG_EEND; \ |
c = (UCHAR_T) *p++; \ |
if (translate && (c <= 0xff)) c = (UCHAR_T) translate[c]; \ |
} while (0) |
# else /* BYTE */ |
# define PATFETCH(c) \ |
do {if (p == pend) return REG_EEND; \ |
c = (unsigned char) *p++; \ |
if (translate) c = (unsigned char) translate[c]; \ |
} while (0) |
# endif /* WCHAR */ |
# endif |
/* Fetch the next character in the uncompiled pattern, with no |
translation. */ |
# define PATFETCH_RAW(c) \ |
do {if (p == pend) return REG_EEND; \ |
c = (UCHAR_T) *p++; \ |
} while (0) |
/* Go backwards one character in the pattern. */ |
# define PATUNFETCH p-- |
/* If `translate' is non-null, return translate[D], else just D. We |
cast the subscript to translate because some data is declared as |
`char *', to avoid warnings when a string constant is passed. But |
when we use a character as a subscript we must make it unsigned. */ |
/* ifdef MBS_SUPPORT, we translate only if character <= 0xff, |
because it is impossible to allocate 4GB array for some encodings |
which have 4 byte character_set like UCS4. */ |
# ifndef TRANSLATE |
# ifdef WCHAR |
# define TRANSLATE(d) \ |
((translate && ((UCHAR_T) (d)) <= 0xff) \ |
? (char) translate[(unsigned char) (d)] : (d)) |
# else /* BYTE */ |
# define TRANSLATE(d) \ |
(translate ? (char) translate[(unsigned char) (d)] : (char) (d)) |
# endif /* WCHAR */ |
# endif |
/* Macros for outputting the compiled pattern into `buffer'. */ |
/* If the buffer isn't allocated when it comes in, use this. */ |
# define INIT_BUF_SIZE (32 * sizeof(UCHAR_T)) |
/* Make sure we have at least N more bytes of space in buffer. */ |
# ifdef WCHAR |
# define GET_BUFFER_SPACE(n) \ |
while (((unsigned long)b - (unsigned long)COMPILED_BUFFER_VAR \ |
+ (n)*sizeof(CHAR_T)) > bufp->allocated) \ |
EXTEND_BUFFER () |
# else /* BYTE */ |
# define GET_BUFFER_SPACE(n) \ |
while ((unsigned long) (b - bufp->buffer + (n)) > bufp->allocated) \ |
EXTEND_BUFFER () |
# endif /* WCHAR */ |
/* Make sure we have one more byte of buffer space and then add C to it. */ |
# define BUF_PUSH(c) \ |
do { \ |
GET_BUFFER_SPACE (1); \ |
*b++ = (UCHAR_T) (c); \ |
} while (0) |
/* Ensure we have two more bytes of buffer space and then append C1 and C2. */ |
# define BUF_PUSH_2(c1, c2) \ |
do { \ |
GET_BUFFER_SPACE (2); \ |
*b++ = (UCHAR_T) (c1); \ |
*b++ = (UCHAR_T) (c2); \ |
} while (0) |
/* As with BUF_PUSH_2, except for three bytes. */ |
# define BUF_PUSH_3(c1, c2, c3) \ |
do { \ |
GET_BUFFER_SPACE (3); \ |
*b++ = (UCHAR_T) (c1); \ |
*b++ = (UCHAR_T) (c2); \ |
*b++ = (UCHAR_T) (c3); \ |
} while (0) |
/* Store a jump with opcode OP at LOC to location TO. We store a |
relative address offset by the three bytes the jump itself occupies. */ |
# define STORE_JUMP(op, loc, to) \ |
PREFIX(store_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE))) |
/* Likewise, for a two-argument jump. */ |
# define STORE_JUMP2(op, loc, to, arg) \ |
PREFIX(store_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), arg) |
/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */ |
# define INSERT_JUMP(op, loc, to) \ |
PREFIX(insert_op1) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)), b) |
/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */ |
# define INSERT_JUMP2(op, loc, to, arg) \ |
PREFIX(insert_op2) (op, loc, (int) ((to) - (loc) - (1 + OFFSET_ADDRESS_SIZE)),\ |
arg, b) |
/* This is not an arbitrary limit: the arguments which represent offsets |
into the pattern are two bytes long. So if 2^16 bytes turns out to |
be too small, many things would have to change. */ |
/* Any other compiler which, like MSC, has allocation limit below 2^16 |
bytes will have to use approach similar to what was done below for |
MSC and drop MAX_BUF_SIZE a bit. Otherwise you may end up |
reallocating to 0 bytes. Such thing is not going to work too well. |
You have been warned!! */ |
# ifndef DEFINED_ONCE |
# if defined _MSC_VER && !defined WIN32 |
/* Microsoft C 16-bit versions limit malloc to approx 65512 bytes. |
The REALLOC define eliminates a flurry of conversion warnings, |
but is not required. */ |
# define MAX_BUF_SIZE 65500L |
# define REALLOC(p,s) realloc ((p), (size_t) (s)) |
# else |
# define MAX_BUF_SIZE (1L << 16) |
# define REALLOC(p,s) realloc ((p), (s)) |
# endif |
/* Extend the buffer by twice its current size via realloc and |
reset the pointers that pointed into the old block to point to the |
correct places in the new one. If extending the buffer results in it |
being larger than MAX_BUF_SIZE, then flag memory exhausted. */ |
# if __BOUNDED_POINTERS__ |
# define SET_HIGH_BOUND(P) (__ptrhigh (P) = __ptrlow (P) + bufp->allocated) |
# define MOVE_BUFFER_POINTER(P) \ |
(__ptrlow (P) += incr, SET_HIGH_BOUND (P), __ptrvalue (P) += incr) |
# define ELSE_EXTEND_BUFFER_HIGH_BOUND \ |
else \ |
{ \ |
SET_HIGH_BOUND (b); \ |
SET_HIGH_BOUND (begalt); \ |
if (fixup_alt_jump) \ |
SET_HIGH_BOUND (fixup_alt_jump); \ |
if (laststart) \ |
SET_HIGH_BOUND (laststart); \ |
if (pending_exact) \ |
SET_HIGH_BOUND (pending_exact); \ |
} |
# else |
# define MOVE_BUFFER_POINTER(P) (P) += incr |
# define ELSE_EXTEND_BUFFER_HIGH_BOUND |
# endif |
# endif /* not DEFINED_ONCE */ |
# ifdef WCHAR |
# define EXTEND_BUFFER() \ |
do { \ |
UCHAR_T *old_buffer = COMPILED_BUFFER_VAR; \ |
int wchar_count; \ |
if (bufp->allocated + sizeof(UCHAR_T) > MAX_BUF_SIZE) \ |
return REG_ESIZE; \ |
bufp->allocated <<= 1; \ |
if (bufp->allocated > MAX_BUF_SIZE) \ |
bufp->allocated = MAX_BUF_SIZE; \ |
/* How many characters the new buffer can have? */ \ |
wchar_count = bufp->allocated / sizeof(UCHAR_T); \ |
if (wchar_count == 0) wchar_count = 1; \ |
/* Truncate the buffer to CHAR_T align. */ \ |
bufp->allocated = wchar_count * sizeof(UCHAR_T); \ |
RETALLOC (COMPILED_BUFFER_VAR, wchar_count, UCHAR_T); \ |
bufp->buffer = (char*)COMPILED_BUFFER_VAR; \ |
if (COMPILED_BUFFER_VAR == NULL) \ |
return REG_ESPACE; \ |
/* If the buffer moved, move all the pointers into it. */ \ |
if (old_buffer != COMPILED_BUFFER_VAR) \ |
{ \ |
PTR_INT_TYPE incr = COMPILED_BUFFER_VAR - old_buffer; \ |
MOVE_BUFFER_POINTER (b); \ |
MOVE_BUFFER_POINTER (begalt); \ |
if (fixup_alt_jump) \ |
MOVE_BUFFER_POINTER (fixup_alt_jump); \ |
if (laststart) \ |
MOVE_BUFFER_POINTER (laststart); \ |
if (pending_exact) \ |
MOVE_BUFFER_POINTER (pending_exact); \ |
} \ |
ELSE_EXTEND_BUFFER_HIGH_BOUND \ |
} while (0) |
# else /* BYTE */ |
# define EXTEND_BUFFER() \ |
do { \ |
UCHAR_T *old_buffer = COMPILED_BUFFER_VAR; \ |
if (bufp->allocated == MAX_BUF_SIZE) \ |
return REG_ESIZE; \ |
bufp->allocated <<= 1; \ |
if (bufp->allocated > MAX_BUF_SIZE) \ |
bufp->allocated = MAX_BUF_SIZE; \ |
bufp->buffer = (UCHAR_T *) REALLOC (COMPILED_BUFFER_VAR, \ |
bufp->allocated); \ |
if (COMPILED_BUFFER_VAR == NULL) \ |
return REG_ESPACE; \ |
/* If the buffer moved, move all the pointers into it. */ \ |
if (old_buffer != COMPILED_BUFFER_VAR) \ |
{ \ |
PTR_INT_TYPE incr = COMPILED_BUFFER_VAR - old_buffer; \ |
MOVE_BUFFER_POINTER (b); \ |
MOVE_BUFFER_POINTER (begalt); \ |
if (fixup_alt_jump) \ |
MOVE_BUFFER_POINTER (fixup_alt_jump); \ |
if (laststart) \ |
MOVE_BUFFER_POINTER (laststart); \ |
if (pending_exact) \ |
MOVE_BUFFER_POINTER (pending_exact); \ |
} \ |
ELSE_EXTEND_BUFFER_HIGH_BOUND \ |
} while (0) |
# endif /* WCHAR */ |
# ifndef DEFINED_ONCE |
/* Since we have one byte reserved for the register number argument to |
{start,stop}_memory, the maximum number of groups we can report |
things about is what fits in that byte. */ |
# define MAX_REGNUM 255 |
/* But patterns can have more than `MAX_REGNUM' registers. We just |
ignore the excess. */ |
typedef unsigned regnum_t; |
/* Macros for the compile stack. */ |
/* Since offsets can go either forwards or backwards, this type needs to |
be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */ |
/* int may be not enough when sizeof(int) == 2. */ |
typedef long pattern_offset_t; |
typedef struct |
{ |
pattern_offset_t begalt_offset; |
pattern_offset_t fixup_alt_jump; |
pattern_offset_t inner_group_offset; |
pattern_offset_t laststart_offset; |
regnum_t regnum; |
} compile_stack_elt_t; |
typedef struct |
{ |
compile_stack_elt_t *stack; |
unsigned size; |
unsigned avail; /* Offset of next open position. */ |
} compile_stack_type; |
# define INIT_COMPILE_STACK_SIZE 32 |
# define COMPILE_STACK_EMPTY (compile_stack.avail == 0) |
# define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size) |
/* The next available element. */ |
# define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail]) |
# endif /* not DEFINED_ONCE */ |
/* Set the bit for character C in a list. */ |
# ifndef DEFINED_ONCE |
# define SET_LIST_BIT(c) \ |
(b[((unsigned char) (c)) / BYTEWIDTH] \ |
|= 1 << (((unsigned char) c) % BYTEWIDTH)) |
# endif /* DEFINED_ONCE */ |
/* Get the next unsigned number in the uncompiled pattern. */ |
# define GET_UNSIGNED_NUMBER(num) \ |
{ \ |
while (p != pend) \ |
{ \ |
PATFETCH (c); \ |
if (c < '0' || c > '9') \ |
break; \ |
if (num <= RE_DUP_MAX) \ |
{ \ |
if (num < 0) \ |
num = 0; \ |
num = num * 10 + c - '0'; \ |
} \ |
} \ |
} |
# ifndef DEFINED_ONCE |
# if defined _LIBC || WIDE_CHAR_SUPPORT |
/* The GNU C library provides support for user-defined character classes |
and the functions from ISO C amendement 1. */ |
# ifdef CHARCLASS_NAME_MAX |
# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX |
# else |
/* This shouldn't happen but some implementation might still have this |
problem. Use a reasonable default value. */ |
# define CHAR_CLASS_MAX_LENGTH 256 |
# endif |
# ifdef _LIBC |
# define IS_CHAR_CLASS(string) __wctype (string) |
# else |
# define IS_CHAR_CLASS(string) wctype (string) |
# endif |
# else |
# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ |
# define IS_CHAR_CLASS(string) \ |
(STREQ (string, "alpha") || STREQ (string, "upper") \ |
|| STREQ (string, "lower") || STREQ (string, "digit") \ |
|| STREQ (string, "alnum") || STREQ (string, "xdigit") \ |
|| STREQ (string, "space") || STREQ (string, "print") \ |
|| STREQ (string, "punct") || STREQ (string, "graph") \ |
|| STREQ (string, "cntrl") || STREQ (string, "blank")) |
# endif |
# endif /* DEFINED_ONCE */ |
# ifndef MATCH_MAY_ALLOCATE |
/* If we cannot allocate large objects within re_match_2_internal, |
we make the fail stack and register vectors global. |
The fail stack, we grow to the maximum size when a regexp |
is compiled. |
The register vectors, we adjust in size each time we |
compile a regexp, according to the number of registers it needs. */ |
static PREFIX(fail_stack_type) fail_stack; |
/* Size with which the following vectors are currently allocated. |
That is so we can make them bigger as needed, |
but never make them smaller. */ |
# ifdef DEFINED_ONCE |
static int regs_allocated_size; |
static const char ** regstart, ** regend; |
static const char ** old_regstart, ** old_regend; |
static const char **best_regstart, **best_regend; |
static const char **reg_dummy; |
# endif /* DEFINED_ONCE */ |
static PREFIX(register_info_type) *PREFIX(reg_info); |
static PREFIX(register_info_type) *PREFIX(reg_info_dummy); |
/* Make the register vectors big enough for NUM_REGS registers, |
but don't make them smaller. */ |
static void |
PREFIX(regex_grow_registers) (int num_regs) |
{ |
if (num_regs > regs_allocated_size) |
{ |
RETALLOC_IF (regstart, num_regs, const char *); |
RETALLOC_IF (regend, num_regs, const char *); |
RETALLOC_IF (old_regstart, num_regs, const char *); |
RETALLOC_IF (old_regend, num_regs, const char *); |
RETALLOC_IF (best_regstart, num_regs, const char *); |
RETALLOC_IF (best_regend, num_regs, const char *); |
RETALLOC_IF (PREFIX(reg_info), num_regs, PREFIX(register_info_type)); |
RETALLOC_IF (reg_dummy, num_regs, const char *); |
RETALLOC_IF (PREFIX(reg_info_dummy), num_regs, PREFIX(register_info_type)); |
regs_allocated_size = num_regs; |
} |
} |
# endif /* not MATCH_MAY_ALLOCATE */ |
# ifndef DEFINED_ONCE |
static boolean group_in_compile_stack (compile_stack_type compile_stack, |
regnum_t regnum); |
# endif /* not DEFINED_ONCE */ |
/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX. |
Returns one of error codes defined in `regex.h', or zero for success. |
Assumes the `allocated' (and perhaps `buffer') and `translate' |
fields are set in BUFP on entry. |
If it succeeds, results are put in BUFP (if it returns an error, the |
contents of BUFP are undefined): |
`buffer' is the compiled pattern; |
`syntax' is set to SYNTAX; |
`used' is set to the length of the compiled pattern; |
`fastmap_accurate' is zero; |
`re_nsub' is the number of subexpressions in PATTERN; |
`not_bol' and `not_eol' are zero; |
The `fastmap' and `newline_anchor' fields are neither |
examined nor set. */ |
/* Return, freeing storage we allocated. */ |
# ifdef WCHAR |
# define FREE_STACK_RETURN(value) \ |
return (free(pattern), free(mbs_offset), free(is_binary), free (compile_stack.stack), value) |
# else |
# define FREE_STACK_RETURN(value) \ |
return (free (compile_stack.stack), value) |
# endif /* WCHAR */ |
static reg_errcode_t |
PREFIX(regex_compile) (const char *ARG_PREFIX(pattern), |
size_t ARG_PREFIX(size), reg_syntax_t syntax, |
struct re_pattern_buffer *bufp) |
{ |
/* We fetch characters from PATTERN here. Even though PATTERN is |
`char *' (i.e., signed), we declare these variables as unsigned, so |
they can be reliably used as array indices. */ |
register UCHAR_T c, c1; |
#ifdef WCHAR |
/* A temporary space to keep wchar_t pattern and compiled pattern. */ |
CHAR_T *pattern, *COMPILED_BUFFER_VAR; |
size_t size; |
/* offset buffer for optimization. See convert_mbs_to_wc. */ |
int *mbs_offset = NULL; |
/* It hold whether each wchar_t is binary data or not. */ |
char *is_binary = NULL; |
/* A flag whether exactn is handling binary data or not. */ |
char is_exactn_bin = FALSE; |
#endif /* WCHAR */ |
/* A random temporary spot in PATTERN. */ |
const CHAR_T *p1; |
/* Points to the end of the buffer, where we should append. */ |
register UCHAR_T *b; |
/* Keeps track of unclosed groups. */ |
compile_stack_type compile_stack; |
/* Points to the current (ending) position in the pattern. */ |
#ifdef WCHAR |
const CHAR_T *p; |
const CHAR_T *pend; |
#else /* BYTE */ |
const CHAR_T *p = pattern; |
const CHAR_T *pend = pattern + size; |
#endif /* WCHAR */ |
/* How to translate the characters in the pattern. */ |
RE_TRANSLATE_TYPE translate = bufp->translate; |
/* Address of the count-byte of the most recently inserted `exactn' |
command. This makes it possible to tell if a new exact-match |
character can be added to that command or if the character requires |
a new `exactn' command. */ |
UCHAR_T *pending_exact = 0; |
/* Address of start of the most recently finished expression. |
This tells, e.g., postfix * where to find the start of its |
operand. Reset at the beginning of groups and alternatives. */ |
UCHAR_T *laststart = 0; |
/* Address of beginning of regexp, or inside of last group. */ |
UCHAR_T *begalt; |
/* Address of the place where a forward jump should go to the end of |
the containing expression. Each alternative of an `or' -- except the |
last -- ends with a forward jump of this sort. */ |
UCHAR_T *fixup_alt_jump = 0; |
/* Counts open-groups as they are encountered. Remembered for the |
matching close-group on the compile stack, so the same register |
number is put in the stop_memory as the start_memory. */ |
regnum_t regnum = 0; |
#ifdef WCHAR |
/* Initialize the wchar_t PATTERN and offset_buffer. */ |
p = pend = pattern = TALLOC(csize + 1, CHAR_T); |
mbs_offset = TALLOC(csize + 1, int); |
is_binary = TALLOC(csize + 1, char); |
if (pattern == NULL || mbs_offset == NULL || is_binary == NULL) |
{ |
free(pattern); |
free(mbs_offset); |
free(is_binary); |
return REG_ESPACE; |
} |
pattern[csize] = L'\0'; /* sentinel */ |
size = convert_mbs_to_wcs(pattern, cpattern, csize, mbs_offset, is_binary); |
pend = p + size; |
if (size < 0) |
{ |
free(pattern); |
free(mbs_offset); |
free(is_binary); |
return REG_BADPAT; |
} |
#endif |
#ifdef DEBUG |
DEBUG_PRINT1 ("\nCompiling pattern: "); |
if (debug) |
{ |
unsigned debug_count; |
for (debug_count = 0; debug_count < size; debug_count++) |
PUT_CHAR (pattern[debug_count]); |
putchar ('\n'); |
} |
#endif /* DEBUG */ |
/* Initialize the compile stack. */ |
compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t); |
if (compile_stack.stack == NULL) |
{ |
#ifdef WCHAR |
free(pattern); |
free(mbs_offset); |
free(is_binary); |
#endif |
return REG_ESPACE; |
} |
compile_stack.size = INIT_COMPILE_STACK_SIZE; |
compile_stack.avail = 0; |
/* Initialize the pattern buffer. */ |
bufp->syntax = syntax; |
bufp->fastmap_accurate = 0; |
bufp->not_bol = bufp->not_eol = 0; |
/* Set `used' to zero, so that if we return an error, the pattern |
printer (for debugging) will think there's no pattern. We reset it |
at the end. */ |
bufp->used = 0; |
/* Always count groups, whether or not bufp->no_sub is set. */ |
bufp->re_nsub = 0; |
#if !defined emacs && !defined SYNTAX_TABLE |
/* Initialize the syntax table. */ |
init_syntax_once (); |
#endif |
if (bufp->allocated == 0) |
{ |
if (bufp->buffer) |
{ /* If zero allocated, but buffer is non-null, try to realloc |
enough space. This loses if buffer's address is bogus, but |
that is the user's responsibility. */ |
#ifdef WCHAR |
/* Free bufp->buffer and allocate an array for wchar_t pattern |
buffer. */ |
free(bufp->buffer); |
COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE/sizeof(UCHAR_T), |
UCHAR_T); |
#else |
RETALLOC (COMPILED_BUFFER_VAR, INIT_BUF_SIZE, UCHAR_T); |
#endif /* WCHAR */ |
} |
else |
{ /* Caller did not allocate a buffer. Do it for them. */ |
COMPILED_BUFFER_VAR = TALLOC (INIT_BUF_SIZE / sizeof(UCHAR_T), |
UCHAR_T); |
} |
if (!COMPILED_BUFFER_VAR) FREE_STACK_RETURN (REG_ESPACE); |
#ifdef WCHAR |
bufp->buffer = (char*)COMPILED_BUFFER_VAR; |
#endif /* WCHAR */ |
bufp->allocated = INIT_BUF_SIZE; |
} |
#ifdef WCHAR |
else |
COMPILED_BUFFER_VAR = (UCHAR_T*) bufp->buffer; |
#endif |
begalt = b = COMPILED_BUFFER_VAR; |
/* Loop through the uncompiled pattern until we're at the end. */ |
while (p != pend) |
{ |
PATFETCH (c); |
switch (c) |
{ |
case '^': |
{ |
if ( /* If at start of pattern, it's an operator. */ |
p == pattern + 1 |
/* If context independent, it's an operator. */ |
|| syntax & RE_CONTEXT_INDEP_ANCHORS |
/* Otherwise, depends on what's come before. */ |
|| PREFIX(at_begline_loc_p) (pattern, p, syntax)) |
BUF_PUSH (begline); |
else |
goto normal_char; |
} |
break; |
case '$': |
{ |
if ( /* If at end of pattern, it's an operator. */ |
p == pend |
/* If context independent, it's an operator. */ |
|| syntax & RE_CONTEXT_INDEP_ANCHORS |
/* Otherwise, depends on what's next. */ |
|| PREFIX(at_endline_loc_p) (p, pend, syntax)) |
BUF_PUSH (endline); |
else |
goto normal_char; |
} |
break; |
case '+': |
case '?': |
if ((syntax & RE_BK_PLUS_QM) |
|| (syntax & RE_LIMITED_OPS)) |
goto normal_char; |
handle_plus: |
case '*': |
/* If there is no previous pattern... */ |
if (!laststart) |
{ |
if (syntax & RE_CONTEXT_INVALID_OPS) |
FREE_STACK_RETURN (REG_BADRPT); |
else if (!(syntax & RE_CONTEXT_INDEP_OPS)) |
goto normal_char; |
} |
{ |
/* Are we optimizing this jump? */ |
boolean keep_string_p = false; |
/* 1 means zero (many) matches is allowed. */ |
char zero_times_ok = 0, many_times_ok = 0; |
/* If there is a sequence of repetition chars, collapse it |
down to just one (the right one). We can't combine |
interval operators with these because of, e.g., `a{2}*', |
which should only match an even number of `a's. */ |
for (;;) |
{ |
zero_times_ok |= c != '+'; |
many_times_ok |= c != '?'; |
if (p == pend) |
break; |
PATFETCH (c); |
if (c == '*' |
|| (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?'))) |
; |
else if (syntax & RE_BK_PLUS_QM && c == '\\') |
{ |
if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); |
PATFETCH (c1); |
if (!(c1 == '+' || c1 == '?')) |
{ |
PATUNFETCH; |
PATUNFETCH; |
break; |
} |
c = c1; |
} |
else |
{ |
PATUNFETCH; |
break; |
} |
/* If we get here, we found another repeat character. */ |
} |
/* Star, etc. applied to an empty pattern is equivalent |
to an empty pattern. */ |
if (!laststart) |
break; |
/* Now we know whether or not zero matches is allowed |
and also whether or not two or more matches is allowed. */ |
if (many_times_ok) |
{ /* More than one repetition is allowed, so put in at the |
end a backward relative jump from `b' to before the next |
jump we're going to put in below (which jumps from |
laststart to after this jump). |
But if we are at the `*' in the exact sequence `.*\n', |
insert an unconditional jump backwards to the ., |
instead of the beginning of the loop. This way we only |
push a failure point once, instead of every time |
through the loop. */ |
assert (p - 1 > pattern); |
/* Allocate the space for the jump. */ |
GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
/* We know we are not at the first character of the pattern, |
because laststart was nonzero. And we've already |
incremented `p', by the way, to be the character after |
the `*'. Do we have to do something analogous here |
for null bytes, because of RE_DOT_NOT_NULL? */ |
if (TRANSLATE (*(p - 2)) == TRANSLATE ('.') |
&& zero_times_ok |
&& p < pend && TRANSLATE (*p) == TRANSLATE ('\n') |
&& !(syntax & RE_DOT_NEWLINE)) |
{ /* We have .*\n. */ |
STORE_JUMP (jump, b, laststart); |
keep_string_p = true; |
} |
else |
/* Anything else. */ |
STORE_JUMP (maybe_pop_jump, b, laststart - |
(1 + OFFSET_ADDRESS_SIZE)); |
/* We've added more stuff to the buffer. */ |
b += 1 + OFFSET_ADDRESS_SIZE; |
} |
/* On failure, jump from laststart to b + 3, which will be the |
end of the buffer after this jump is inserted. */ |
/* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE' instead of |
'b + 3'. */ |
GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump |
: on_failure_jump, |
laststart, b + 1 + OFFSET_ADDRESS_SIZE); |
pending_exact = 0; |
b += 1 + OFFSET_ADDRESS_SIZE; |
if (!zero_times_ok) |
{ |
/* At least one repetition is required, so insert a |
`dummy_failure_jump' before the initial |
`on_failure_jump' instruction of the loop. This |
effects a skip over that instruction the first time |
we hit that loop. */ |
GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
INSERT_JUMP (dummy_failure_jump, laststart, laststart + |
2 + 2 * OFFSET_ADDRESS_SIZE); |
b += 1 + OFFSET_ADDRESS_SIZE; |
} |
} |
break; |
case '.': |
laststart = b; |
BUF_PUSH (anychar); |
break; |
case '[': |
{ |
boolean had_char_class = false; |
#ifdef WCHAR |
CHAR_T range_start = 0xffffffff; |
#else |
unsigned int range_start = 0xffffffff; |
#endif |
if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
#ifdef WCHAR |
/* We assume a charset(_not) structure as a wchar_t array. |
charset[0] = (re_opcode_t) charset(_not) |
charset[1] = l (= length of char_classes) |
charset[2] = m (= length of collating_symbols) |
charset[3] = n (= length of equivalence_classes) |
charset[4] = o (= length of char_ranges) |
charset[5] = p (= length of chars) |
charset[6] = char_class (wctype_t) |
charset[6+CHAR_CLASS_SIZE] = char_class (wctype_t) |
... |
charset[l+5] = char_class (wctype_t) |
charset[l+6] = collating_symbol (wchar_t) |
... |
charset[l+m+5] = collating_symbol (wchar_t) |
ifdef _LIBC we use the index if |
_NL_COLLATE_SYMB_EXTRAMB instead of |
wchar_t string. |
charset[l+m+6] = equivalence_classes (wchar_t) |
... |
charset[l+m+n+5] = equivalence_classes (wchar_t) |
ifdef _LIBC we use the index in |
_NL_COLLATE_WEIGHT instead of |
wchar_t string. |
charset[l+m+n+6] = range_start |
charset[l+m+n+7] = range_end |
... |
charset[l+m+n+2o+4] = range_start |
charset[l+m+n+2o+5] = range_end |
ifdef _LIBC we use the value looked up |
in _NL_COLLATE_COLLSEQ instead of |
wchar_t character. |
charset[l+m+n+2o+6] = char |
... |
charset[l+m+n+2o+p+5] = char |
*/ |
/* We need at least 6 spaces: the opcode, the length of |
char_classes, the length of collating_symbols, the length of |
equivalence_classes, the length of char_ranges, the length of |
chars. */ |
GET_BUFFER_SPACE (6); |
/* Save b as laststart. And We use laststart as the pointer |
to the first element of the charset here. |
In other words, laststart[i] indicates charset[i]. */ |
laststart = b; |
/* We test `*p == '^' twice, instead of using an if |
statement, so we only need one BUF_PUSH. */ |
BUF_PUSH (*p == '^' ? charset_not : charset); |
if (*p == '^') |
p++; |
/* Push the length of char_classes, the length of |
collating_symbols, the length of equivalence_classes, the |
length of char_ranges and the length of chars. */ |
BUF_PUSH_3 (0, 0, 0); |
BUF_PUSH_2 (0, 0); |
/* Remember the first position in the bracket expression. */ |
p1 = p; |
/* charset_not matches newline according to a syntax bit. */ |
if ((re_opcode_t) b[-6] == charset_not |
&& (syntax & RE_HAT_LISTS_NOT_NEWLINE)) |
{ |
BUF_PUSH('\n'); |
laststart[5]++; /* Update the length of characters */ |
} |
/* Read in characters and ranges, setting map bits. */ |
for (;;) |
{ |
if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
PATFETCH (c); |
/* \ might escape characters inside [...] and [^...]. */ |
if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') |
{ |
if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); |
PATFETCH (c1); |
BUF_PUSH(c1); |
laststart[5]++; /* Update the length of chars */ |
range_start = c1; |
continue; |
} |
/* Could be the end of the bracket expression. If it's |
not (i.e., when the bracket expression is `[]' so |
far), the ']' character bit gets set way below. */ |
if (c == ']' && p != p1 + 1) |
break; |
/* Look ahead to see if it's a range when the last thing |
was a character class. */ |
if (had_char_class && c == '-' && *p != ']') |
FREE_STACK_RETURN (REG_ERANGE); |
/* Look ahead to see if it's a range when the last thing |
was a character: if this is a hyphen not at the |
beginning or the end of a list, then it's the range |
operator. */ |
if (c == '-' |
&& !(p - 2 >= pattern && p[-2] == '[') |
&& !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') |
&& *p != ']') |
{ |
reg_errcode_t ret; |
/* Allocate the space for range_start and range_end. */ |
GET_BUFFER_SPACE (2); |
/* Update the pointer to indicate end of buffer. */ |
b += 2; |
ret = wcs_compile_range (range_start, &p, pend, translate, |
syntax, b, laststart); |
if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); |
range_start = 0xffffffff; |
} |
else if (p[0] == '-' && p[1] != ']') |
{ /* This handles ranges made up of characters only. */ |
reg_errcode_t ret; |
/* Move past the `-'. */ |
PATFETCH (c1); |
/* Allocate the space for range_start and range_end. */ |
GET_BUFFER_SPACE (2); |
/* Update the pointer to indicate end of buffer. */ |
b += 2; |
ret = wcs_compile_range (c, &p, pend, translate, syntax, b, |
laststart); |
if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); |
range_start = 0xffffffff; |
} |
/* See if we're at the beginning of a possible character |
class. */ |
else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') |
{ /* Leave room for the null. */ |
char str[CHAR_CLASS_MAX_LENGTH + 1]; |
PATFETCH (c); |
c1 = 0; |
/* If pattern is `[[:'. */ |
if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
for (;;) |
{ |
PATFETCH (c); |
if ((c == ':' && *p == ']') || p == pend) |
break; |
if (c1 < CHAR_CLASS_MAX_LENGTH) |
str[c1++] = c; |
else |
/* This is in any case an invalid class name. */ |
str[0] = '\0'; |
} |
str[c1] = '\0'; |
/* If isn't a word bracketed by `[:' and `:]': |
undo the ending character, the letters, and leave |
the leading `:' and `[' (but store them as character). */ |
if (c == ':' && *p == ']') |
{ |
wctype_t wt; |
uintptr_t alignedp; |
/* Query the character class as wctype_t. */ |
wt = IS_CHAR_CLASS (str); |
if (wt == 0) |
FREE_STACK_RETURN (REG_ECTYPE); |
/* Throw away the ] at the end of the character |
class. */ |
PATFETCH (c); |
if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
/* Allocate the space for character class. */ |
GET_BUFFER_SPACE(CHAR_CLASS_SIZE); |
/* Update the pointer to indicate end of buffer. */ |
b += CHAR_CLASS_SIZE; |
/* Move data which follow character classes |
not to violate the data. */ |
insert_space(CHAR_CLASS_SIZE, |
laststart + 6 + laststart[1], |
b - 1); |
alignedp = ((uintptr_t)(laststart + 6 + laststart[1]) |
+ __alignof__(wctype_t) - 1) |
& ~(uintptr_t)(__alignof__(wctype_t) - 1); |
/* Store the character class. */ |
*((wctype_t*)alignedp) = wt; |
/* Update length of char_classes */ |
laststart[1] += CHAR_CLASS_SIZE; |
had_char_class = true; |
} |
else |
{ |
c1++; |
while (c1--) |
PATUNFETCH; |
BUF_PUSH ('['); |
BUF_PUSH (':'); |
laststart[5] += 2; /* Update the length of characters */ |
range_start = ':'; |
had_char_class = false; |
} |
} |
else if (syntax & RE_CHAR_CLASSES && c == '[' && (*p == '=' |
|| *p == '.')) |
{ |
CHAR_T str[128]; /* Should be large enough. */ |
CHAR_T delim = *p; /* '=' or '.' */ |
# ifdef _LIBC |
uint32_t nrules = |
_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
# endif |
PATFETCH (c); |
c1 = 0; |
/* If pattern is `[[=' or '[[.'. */ |
if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
for (;;) |
{ |
PATFETCH (c); |
if ((c == delim && *p == ']') || p == pend) |
break; |
if (c1 < sizeof (str) - 1) |
str[c1++] = c; |
else |
/* This is in any case an invalid class name. */ |
str[0] = '\0'; |
} |
str[c1] = '\0'; |
if (c == delim && *p == ']' && str[0] != '\0') |
{ |
unsigned int i, offset; |
/* If we have no collation data we use the default |
collation in which each character is in a class |
by itself. It also means that ASCII is the |
character set and therefore we cannot have character |
with more than one byte in the multibyte |
representation. */ |
/* If not defined _LIBC, we push the name and |
`\0' for the sake of matching performance. */ |
int datasize = c1 + 1; |
# ifdef _LIBC |
int32_t idx = 0; |
if (nrules == 0) |
# endif |
{ |
if (c1 != 1) |
FREE_STACK_RETURN (REG_ECOLLATE); |
} |
# ifdef _LIBC |
else |
{ |
const int32_t *table; |
const int32_t *weights; |
const int32_t *extra; |
const int32_t *indirect; |
wint_t *cp; |
/* This #include defines a local function! */ |
# include <locale/weightwc.h> |
if(delim == '=') |
{ |
/* We push the index for equivalence class. */ |
cp = (wint_t*)str; |
table = (const int32_t *) |
_NL_CURRENT (LC_COLLATE, |
_NL_COLLATE_TABLEWC); |
weights = (const int32_t *) |
_NL_CURRENT (LC_COLLATE, |
_NL_COLLATE_WEIGHTWC); |
extra = (const int32_t *) |
_NL_CURRENT (LC_COLLATE, |
_NL_COLLATE_EXTRAWC); |
indirect = (const int32_t *) |
_NL_CURRENT (LC_COLLATE, |
_NL_COLLATE_INDIRECTWC); |
idx = findidx ((const wint_t**)&cp); |
if (idx == 0 || cp < (wint_t*) str + c1) |
/* This is no valid character. */ |
FREE_STACK_RETURN (REG_ECOLLATE); |
str[0] = (wchar_t)idx; |
} |
else /* delim == '.' */ |
{ |
/* We push collation sequence value |
for collating symbol. */ |
int32_t table_size; |
const int32_t *symb_table; |
const unsigned char *extra; |
int32_t idx; |
int32_t elem; |
int32_t second; |
int32_t hash; |
char char_str[c1]; |
/* We have to convert the name to a single-byte |
string. This is possible since the names |
consist of ASCII characters and the internal |
representation is UCS4. */ |
for (i = 0; i < c1; ++i) |
char_str[i] = str[i]; |
table_size = |
_NL_CURRENT_WORD (LC_COLLATE, |
_NL_COLLATE_SYMB_HASH_SIZEMB); |
symb_table = (const int32_t *) |
_NL_CURRENT (LC_COLLATE, |
_NL_COLLATE_SYMB_TABLEMB); |
extra = (const unsigned char *) |
_NL_CURRENT (LC_COLLATE, |
_NL_COLLATE_SYMB_EXTRAMB); |
/* Locate the character in the hashing table. */ |
hash = elem_hash (char_str, c1); |
idx = 0; |
elem = hash % table_size; |
second = hash % (table_size - 2); |
while (symb_table[2 * elem] != 0) |
{ |
/* First compare the hashing value. */ |
if (symb_table[2 * elem] == hash |
&& c1 == extra[symb_table[2 * elem + 1]] |
&& memcmp (char_str, |
&extra[symb_table[2 * elem + 1] |
+ 1], c1) == 0) |
{ |
/* Yep, this is the entry. */ |
idx = symb_table[2 * elem + 1]; |
idx += 1 + extra[idx]; |
break; |
} |
/* Next entry. */ |
elem += second; |
} |
if (symb_table[2 * elem] != 0) |
{ |
/* Compute the index of the byte sequence |
in the table. */ |
idx += 1 + extra[idx]; |
/* Adjust for the alignment. */ |
idx = (idx + 3) & ~3; |
str[0] = (wchar_t) idx + 4; |
} |
else if (symb_table[2 * elem] == 0 && c1 == 1) |
{ |
/* No valid character. Match it as a |
single byte character. */ |
had_char_class = false; |
BUF_PUSH(str[0]); |
/* Update the length of characters */ |
laststart[5]++; |
range_start = str[0]; |
/* Throw away the ] at the end of the |
collating symbol. */ |
PATFETCH (c); |
/* exit from the switch block. */ |
continue; |
} |
else |
FREE_STACK_RETURN (REG_ECOLLATE); |
} |
datasize = 1; |
} |
# endif |
/* Throw away the ] at the end of the equivalence |
class (or collating symbol). */ |
PATFETCH (c); |
/* Allocate the space for the equivalence class |
(or collating symbol) (and '\0' if needed). */ |
GET_BUFFER_SPACE(datasize); |
/* Update the pointer to indicate end of buffer. */ |
b += datasize; |
if (delim == '=') |
{ /* equivalence class */ |
/* Calculate the offset of char_ranges, |
which is next to equivalence_classes. */ |
offset = laststart[1] + laststart[2] |
+ laststart[3] +6; |
/* Insert space. */ |
insert_space(datasize, laststart + offset, b - 1); |
/* Write the equivalence_class and \0. */ |
for (i = 0 ; i < datasize ; i++) |
laststart[offset + i] = str[i]; |
/* Update the length of equivalence_classes. */ |
laststart[3] += datasize; |
had_char_class = true; |
} |
else /* delim == '.' */ |
{ /* collating symbol */ |
/* Calculate the offset of the equivalence_classes, |
which is next to collating_symbols. */ |
offset = laststart[1] + laststart[2] + 6; |
/* Insert space and write the collationg_symbol |
and \0. */ |
insert_space(datasize, laststart + offset, b-1); |
for (i = 0 ; i < datasize ; i++) |
laststart[offset + i] = str[i]; |
/* In re_match_2_internal if range_start < -1, we |
assume -range_start is the offset of the |
collating symbol which is specified as |
the character of the range start. So we assign |
-(laststart[1] + laststart[2] + 6) to |
range_start. */ |
range_start = -(laststart[1] + laststart[2] + 6); |
/* Update the length of collating_symbol. */ |
laststart[2] += datasize; |
had_char_class = false; |
} |
} |
else |
{ |
c1++; |
while (c1--) |
PATUNFETCH; |
BUF_PUSH ('['); |
BUF_PUSH (delim); |
laststart[5] += 2; /* Update the length of characters */ |
range_start = delim; |
had_char_class = false; |
} |
} |
else |
{ |
had_char_class = false; |
BUF_PUSH(c); |
laststart[5]++; /* Update the length of characters */ |
range_start = c; |
} |
} |
#else /* BYTE */ |
/* Ensure that we have enough space to push a charset: the |
opcode, the length count, and the bitset; 34 bytes in all. */ |
GET_BUFFER_SPACE (34); |
laststart = b; |
/* We test `*p == '^' twice, instead of using an if |
statement, so we only need one BUF_PUSH. */ |
BUF_PUSH (*p == '^' ? charset_not : charset); |
if (*p == '^') |
p++; |
/* Remember the first position in the bracket expression. */ |
p1 = p; |
/* Push the number of bytes in the bitmap. */ |
BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH); |
/* Clear the whole map. */ |
bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH); |
/* charset_not matches newline according to a syntax bit. */ |
if ((re_opcode_t) b[-2] == charset_not |
&& (syntax & RE_HAT_LISTS_NOT_NEWLINE)) |
SET_LIST_BIT ('\n'); |
/* Read in characters and ranges, setting map bits. */ |
for (;;) |
{ |
if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
PATFETCH (c); |
/* \ might escape characters inside [...] and [^...]. */ |
if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\') |
{ |
if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); |
PATFETCH (c1); |
SET_LIST_BIT (c1); |
range_start = c1; |
continue; |
} |
/* Could be the end of the bracket expression. If it's |
not (i.e., when the bracket expression is `[]' so |
far), the ']' character bit gets set way below. */ |
if (c == ']' && p != p1 + 1) |
break; |
/* Look ahead to see if it's a range when the last thing |
was a character class. */ |
if (had_char_class && c == '-' && *p != ']') |
FREE_STACK_RETURN (REG_ERANGE); |
/* Look ahead to see if it's a range when the last thing |
was a character: if this is a hyphen not at the |
beginning or the end of a list, then it's the range |
operator. */ |
if (c == '-' |
&& !(p - 2 >= pattern && p[-2] == '[') |
&& !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^') |
&& *p != ']') |
{ |
reg_errcode_t ret |
= byte_compile_range (range_start, &p, pend, translate, |
syntax, b); |
if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); |
range_start = 0xffffffff; |
} |
else if (p[0] == '-' && p[1] != ']') |
{ /* This handles ranges made up of characters only. */ |
reg_errcode_t ret; |
/* Move past the `-'. */ |
PATFETCH (c1); |
ret = byte_compile_range (c, &p, pend, translate, syntax, b); |
if (ret != REG_NOERROR) FREE_STACK_RETURN (ret); |
range_start = 0xffffffff; |
} |
/* See if we're at the beginning of a possible character |
class. */ |
else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':') |
{ /* Leave room for the null. */ |
char str[CHAR_CLASS_MAX_LENGTH + 1]; |
PATFETCH (c); |
c1 = 0; |
/* If pattern is `[[:'. */ |
if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
for (;;) |
{ |
PATFETCH (c); |
if ((c == ':' && *p == ']') || p == pend) |
break; |
if (c1 < CHAR_CLASS_MAX_LENGTH) |
str[c1++] = c; |
else |
/* This is in any case an invalid class name. */ |
str[0] = '\0'; |
} |
str[c1] = '\0'; |
/* If isn't a word bracketed by `[:' and `:]': |
undo the ending character, the letters, and leave |
the leading `:' and `[' (but set bits for them). */ |
if (c == ':' && *p == ']') |
{ |
# if defined _LIBC || WIDE_CHAR_SUPPORT |
boolean is_lower = STREQ (str, "lower"); |
boolean is_upper = STREQ (str, "upper"); |
wctype_t wt; |
int ch; |
wt = IS_CHAR_CLASS (str); |
if (wt == 0) |
FREE_STACK_RETURN (REG_ECTYPE); |
/* Throw away the ] at the end of the character |
class. */ |
PATFETCH (c); |
if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
for (ch = 0; ch < 1 << BYTEWIDTH; ++ch) |
{ |
# ifdef _LIBC |
if (__iswctype (__btowc (ch), wt)) |
SET_LIST_BIT (ch); |
# else |
if (iswctype (btowc (ch), wt)) |
SET_LIST_BIT (ch); |
# endif |
if (translate && (is_upper || is_lower) |
&& (ISUPPER (ch) || ISLOWER (ch))) |
SET_LIST_BIT (ch); |
} |
had_char_class = true; |
# else |
int ch; |
boolean is_alnum = STREQ (str, "alnum"); |
boolean is_alpha = STREQ (str, "alpha"); |
boolean is_blank = STREQ (str, "blank"); |
boolean is_cntrl = STREQ (str, "cntrl"); |
boolean is_digit = STREQ (str, "digit"); |
boolean is_graph = STREQ (str, "graph"); |
boolean is_lower = STREQ (str, "lower"); |
boolean is_print = STREQ (str, "print"); |
boolean is_punct = STREQ (str, "punct"); |
boolean is_space = STREQ (str, "space"); |
boolean is_upper = STREQ (str, "upper"); |
boolean is_xdigit = STREQ (str, "xdigit"); |
if (!IS_CHAR_CLASS (str)) |
FREE_STACK_RETURN (REG_ECTYPE); |
/* Throw away the ] at the end of the character |
class. */ |
PATFETCH (c); |
if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
for (ch = 0; ch < 1 << BYTEWIDTH; ch++) |
{ |
/* This was split into 3 if's to |
avoid an arbitrary limit in some compiler. */ |
if ( (is_alnum && ISALNUM (ch)) |
|| (is_alpha && ISALPHA (ch)) |
|| (is_blank && ISBLANK (ch)) |
|| (is_cntrl && ISCNTRL (ch))) |
SET_LIST_BIT (ch); |
if ( (is_digit && ISDIGIT (ch)) |
|| (is_graph && ISGRAPH (ch)) |
|| (is_lower && ISLOWER (ch)) |
|| (is_print && ISPRINT (ch))) |
SET_LIST_BIT (ch); |
if ( (is_punct && ISPUNCT (ch)) |
|| (is_space && ISSPACE (ch)) |
|| (is_upper && ISUPPER (ch)) |
|| (is_xdigit && ISXDIGIT (ch))) |
SET_LIST_BIT (ch); |
if ( translate && (is_upper || is_lower) |
&& (ISUPPER (ch) || ISLOWER (ch))) |
SET_LIST_BIT (ch); |
} |
had_char_class = true; |
# endif /* libc || wctype.h */ |
} |
else |
{ |
c1++; |
while (c1--) |
PATUNFETCH; |
SET_LIST_BIT ('['); |
SET_LIST_BIT (':'); |
range_start = ':'; |
had_char_class = false; |
} |
} |
else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '=') |
{ |
unsigned char str[MB_LEN_MAX + 1]; |
# ifdef _LIBC |
uint32_t nrules = |
_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
# endif |
PATFETCH (c); |
c1 = 0; |
/* If pattern is `[[='. */ |
if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
for (;;) |
{ |
PATFETCH (c); |
if ((c == '=' && *p == ']') || p == pend) |
break; |
if (c1 < MB_LEN_MAX) |
str[c1++] = c; |
else |
/* This is in any case an invalid class name. */ |
str[0] = '\0'; |
} |
str[c1] = '\0'; |
if (c == '=' && *p == ']' && str[0] != '\0') |
{ |
/* If we have no collation data we use the default |
collation in which each character is in a class |
by itself. It also means that ASCII is the |
character set and therefore we cannot have character |
with more than one byte in the multibyte |
representation. */ |
# ifdef _LIBC |
if (nrules == 0) |
# endif |
{ |
if (c1 != 1) |
FREE_STACK_RETURN (REG_ECOLLATE); |
/* Throw away the ] at the end of the equivalence |
class. */ |
PATFETCH (c); |
/* Set the bit for the character. */ |
SET_LIST_BIT (str[0]); |
} |
# ifdef _LIBC |
else |
{ |
/* Try to match the byte sequence in `str' against |
those known to the collate implementation. |
First find out whether the bytes in `str' are |
actually from exactly one character. */ |
const int32_t *table; |
const unsigned char *weights; |
const unsigned char *extra; |
const int32_t *indirect; |
int32_t idx; |
const unsigned char *cp = str; |
int ch; |
/* This #include defines a local function! */ |
# include <locale/weight.h> |
table = (const int32_t *) |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEMB); |
weights = (const unsigned char *) |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTMB); |
extra = (const unsigned char *) |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAMB); |
indirect = (const int32_t *) |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTMB); |
idx = findidx (&cp); |
if (idx == 0 || cp < str + c1) |
/* This is no valid character. */ |
FREE_STACK_RETURN (REG_ECOLLATE); |
/* Throw away the ] at the end of the equivalence |
class. */ |
PATFETCH (c); |
/* Now we have to go through the whole table |
and find all characters which have the same |
first level weight. |
XXX Note that this is not entirely correct. |
we would have to match multibyte sequences |
but this is not possible with the current |
implementation. */ |
for (ch = 1; ch < 256; ++ch) |
/* XXX This test would have to be changed if we |
would allow matching multibyte sequences. */ |
if (table[ch] > 0) |
{ |
int32_t idx2 = table[ch]; |
size_t len = weights[idx2]; |
/* Test whether the lenghts match. */ |
if (weights[idx] == len) |
{ |
/* They do. New compare the bytes of |
the weight. */ |
size_t cnt = 0; |
while (cnt < len |
&& (weights[idx + 1 + cnt] |
== weights[idx2 + 1 + cnt])) |
++cnt; |
if (cnt == len) |
/* They match. Mark the character as |
acceptable. */ |
SET_LIST_BIT (ch); |
} |
} |
} |
# endif |
had_char_class = true; |
} |
else |
{ |
c1++; |
while (c1--) |
PATUNFETCH; |
SET_LIST_BIT ('['); |
SET_LIST_BIT ('='); |
range_start = '='; |
had_char_class = false; |
} |
} |
else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == '.') |
{ |
unsigned char str[128]; /* Should be large enough. */ |
# ifdef _LIBC |
uint32_t nrules = |
_NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
# endif |
PATFETCH (c); |
c1 = 0; |
/* If pattern is `[[.'. */ |
if (p == pend) FREE_STACK_RETURN (REG_EBRACK); |
for (;;) |
{ |
PATFETCH (c); |
if ((c == '.' && *p == ']') || p == pend) |
break; |
if (c1 < sizeof (str)) |
str[c1++] = c; |
else |
/* This is in any case an invalid class name. */ |
str[0] = '\0'; |
} |
str[c1] = '\0'; |
if (c == '.' && *p == ']' && str[0] != '\0') |
{ |
/* If we have no collation data we use the default |
collation in which each character is the name |
for its own class which contains only the one |
character. It also means that ASCII is the |
character set and therefore we cannot have character |
with more than one byte in the multibyte |
representation. */ |
# ifdef _LIBC |
if (nrules == 0) |
# endif |
{ |
if (c1 != 1) |
FREE_STACK_RETURN (REG_ECOLLATE); |
/* Throw away the ] at the end of the equivalence |
class. */ |
PATFETCH (c); |
/* Set the bit for the character. */ |
SET_LIST_BIT (str[0]); |
range_start = ((const unsigned char *) str)[0]; |
} |
# ifdef _LIBC |
else |
{ |
/* Try to match the byte sequence in `str' against |
those known to the collate implementation. |
First find out whether the bytes in `str' are |
actually from exactly one character. */ |
int32_t table_size; |
const int32_t *symb_table; |
const unsigned char *extra; |
int32_t idx; |
int32_t elem; |
int32_t second; |
int32_t hash; |
table_size = |
_NL_CURRENT_WORD (LC_COLLATE, |
_NL_COLLATE_SYMB_HASH_SIZEMB); |
symb_table = (const int32_t *) |
_NL_CURRENT (LC_COLLATE, |
_NL_COLLATE_SYMB_TABLEMB); |
extra = (const unsigned char *) |
_NL_CURRENT (LC_COLLATE, |
_NL_COLLATE_SYMB_EXTRAMB); |
/* Locate the character in the hashing table. */ |
hash = elem_hash (str, c1); |
idx = 0; |
elem = hash % table_size; |
second = hash % (table_size - 2); |
while (symb_table[2 * elem] != 0) |
{ |
/* First compare the hashing value. */ |
if (symb_table[2 * elem] == hash |
&& c1 == extra[symb_table[2 * elem + 1]] |
&& memcmp (str, |
&extra[symb_table[2 * elem + 1] |
+ 1], |
c1) == 0) |
{ |
/* Yep, this is the entry. */ |
idx = symb_table[2 * elem + 1]; |
idx += 1 + extra[idx]; |
break; |
} |
/* Next entry. */ |
elem += second; |
} |
if (symb_table[2 * elem] == 0) |
/* This is no valid character. */ |
FREE_STACK_RETURN (REG_ECOLLATE); |
/* Throw away the ] at the end of the equivalence |
class. */ |
PATFETCH (c); |
/* Now add the multibyte character(s) we found |
to the accept list. |
XXX Note that this is not entirely correct. |
we would have to match multibyte sequences |
but this is not possible with the current |
implementation. Also, we have to match |
collating symbols, which expand to more than |
one file, as a whole and not allow the |
individual bytes. */ |
c1 = extra[idx++]; |
if (c1 == 1) |
range_start = extra[idx]; |
while (c1-- > 0) |
{ |
SET_LIST_BIT (extra[idx]); |
++idx; |
} |
} |
# endif |
had_char_class = false; |
} |
else |
{ |
c1++; |
while (c1--) |
PATUNFETCH; |
SET_LIST_BIT ('['); |
SET_LIST_BIT ('.'); |
range_start = '.'; |
had_char_class = false; |
} |
} |
else |
{ |
had_char_class = false; |
SET_LIST_BIT (c); |
range_start = c; |
} |
} |
/* Discard any (non)matching list bytes that are all 0 at the |
end of the map. Decrease the map-length byte too. */ |
while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) |
b[-1]--; |
b += b[-1]; |
#endif /* WCHAR */ |
} |
break; |
case '(': |
if (syntax & RE_NO_BK_PARENS) |
goto handle_open; |
else |
goto normal_char; |
case ')': |
if (syntax & RE_NO_BK_PARENS) |
goto handle_close; |
else |
goto normal_char; |
case '\n': |
if (syntax & RE_NEWLINE_ALT) |
goto handle_alt; |
else |
goto normal_char; |
case '|': |
if (syntax & RE_NO_BK_VBAR) |
goto handle_alt; |
else |
goto normal_char; |
case '{': |
if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES) |
goto handle_interval; |
else |
goto normal_char; |
case '\\': |
if (p == pend) FREE_STACK_RETURN (REG_EESCAPE); |
/* Do not translate the character after the \, so that we can |
distinguish, e.g., \B from \b, even if we normally would |
translate, e.g., B to b. */ |
PATFETCH_RAW (c); |
switch (c) |
{ |
case '(': |
if (syntax & RE_NO_BK_PARENS) |
goto normal_backslash; |
handle_open: |
bufp->re_nsub++; |
regnum++; |
if (COMPILE_STACK_FULL) |
{ |
RETALLOC (compile_stack.stack, compile_stack.size << 1, |
compile_stack_elt_t); |
if (compile_stack.stack == NULL) return REG_ESPACE; |
compile_stack.size <<= 1; |
} |
/* These are the values to restore when we hit end of this |
group. They are all relative offsets, so that if the |
whole pattern moves because of realloc, they will still |
be valid. */ |
COMPILE_STACK_TOP.begalt_offset = begalt - COMPILED_BUFFER_VAR; |
COMPILE_STACK_TOP.fixup_alt_jump |
= fixup_alt_jump ? fixup_alt_jump - COMPILED_BUFFER_VAR + 1 : 0; |
COMPILE_STACK_TOP.laststart_offset = b - COMPILED_BUFFER_VAR; |
COMPILE_STACK_TOP.regnum = regnum; |
/* We will eventually replace the 0 with the number of |
groups inner to this one. But do not push a |
start_memory for groups beyond the last one we can |
represent in the compiled pattern. */ |
if (regnum <= MAX_REGNUM) |
{ |
COMPILE_STACK_TOP.inner_group_offset = b |
- COMPILED_BUFFER_VAR + 2; |
BUF_PUSH_3 (start_memory, regnum, 0); |
} |
compile_stack.avail++; |
fixup_alt_jump = 0; |
laststart = 0; |
begalt = b; |
/* If we've reached MAX_REGNUM groups, then this open |
won't actually generate any code, so we'll have to |
clear pending_exact explicitly. */ |
pending_exact = 0; |
break; |
case ')': |
if (syntax & RE_NO_BK_PARENS) goto normal_backslash; |
if (COMPILE_STACK_EMPTY) |
{ |
if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) |
goto normal_backslash; |
else |
FREE_STACK_RETURN (REG_ERPAREN); |
} |
handle_close: |
if (fixup_alt_jump) |
{ /* Push a dummy failure point at the end of the |
alternative for a possible future |
`pop_failure_jump' to pop. See comments at |
`push_dummy_failure' in `re_match_2'. */ |
BUF_PUSH (push_dummy_failure); |
/* We allocated space for this jump when we assigned |
to `fixup_alt_jump', in the `handle_alt' case below. */ |
STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1); |
} |
/* See similar code for backslashed left paren above. */ |
if (COMPILE_STACK_EMPTY) |
{ |
if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD) |
goto normal_char; |
else |
FREE_STACK_RETURN (REG_ERPAREN); |
} |
/* Since we just checked for an empty stack above, this |
``can't happen''. */ |
assert (compile_stack.avail != 0); |
{ |
/* We don't just want to restore into `regnum', because |
later groups should continue to be numbered higher, |
as in `(ab)c(de)' -- the second group is #2. */ |
regnum_t this_group_regnum; |
compile_stack.avail--; |
begalt = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.begalt_offset; |
fixup_alt_jump |
= COMPILE_STACK_TOP.fixup_alt_jump |
? COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.fixup_alt_jump - 1 |
: 0; |
laststart = COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.laststart_offset; |
this_group_regnum = COMPILE_STACK_TOP.regnum; |
/* If we've reached MAX_REGNUM groups, then this open |
won't actually generate any code, so we'll have to |
clear pending_exact explicitly. */ |
pending_exact = 0; |
/* We're at the end of the group, so now we know how many |
groups were inside this one. */ |
if (this_group_regnum <= MAX_REGNUM) |
{ |
UCHAR_T *inner_group_loc |
= COMPILED_BUFFER_VAR + COMPILE_STACK_TOP.inner_group_offset; |
*inner_group_loc = regnum - this_group_regnum; |
BUF_PUSH_3 (stop_memory, this_group_regnum, |
regnum - this_group_regnum); |
} |
} |
break; |
case '|': /* `\|'. */ |
if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR) |
goto normal_backslash; |
handle_alt: |
if (syntax & RE_LIMITED_OPS) |
goto normal_char; |
/* Insert before the previous alternative a jump which |
jumps to this alternative if the former fails. */ |
GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
INSERT_JUMP (on_failure_jump, begalt, |
b + 2 + 2 * OFFSET_ADDRESS_SIZE); |
pending_exact = 0; |
b += 1 + OFFSET_ADDRESS_SIZE; |
/* The alternative before this one has a jump after it |
which gets executed if it gets matched. Adjust that |
jump so it will jump to this alternative's analogous |
jump (put in below, which in turn will jump to the next |
(if any) alternative's such jump, etc.). The last such |
jump jumps to the correct final destination. A picture: |
_____ _____ |
| | | | |
| v | v |
a | b | c |
If we are at `b', then fixup_alt_jump right now points to a |
three-byte space after `a'. We'll put in the jump, set |
fixup_alt_jump to right after `b', and leave behind three |
bytes which we'll fill in when we get to after `c'. */ |
if (fixup_alt_jump) |
STORE_JUMP (jump_past_alt, fixup_alt_jump, b); |
/* Mark and leave space for a jump after this alternative, |
to be filled in later either by next alternative or |
when know we're at the end of a series of alternatives. */ |
fixup_alt_jump = b; |
GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
b += 1 + OFFSET_ADDRESS_SIZE; |
laststart = 0; |
begalt = b; |
break; |
case '{': |
/* If \{ is a literal. */ |
if (!(syntax & RE_INTERVALS) |
/* If we're at `\{' and it's not the open-interval |
operator. */ |
|| (syntax & RE_NO_BK_BRACES)) |
goto normal_backslash; |
handle_interval: |
{ |
/* If got here, then the syntax allows intervals. */ |
/* At least (most) this many matches must be made. */ |
int lower_bound = -1, upper_bound = -1; |
/* Place in the uncompiled pattern (i.e., just after |
the '{') to go back to if the interval is invalid. */ |
const CHAR_T *beg_interval = p; |
if (p == pend) |
goto invalid_interval; |
GET_UNSIGNED_NUMBER (lower_bound); |
if (c == ',') |
{ |
GET_UNSIGNED_NUMBER (upper_bound); |
if (upper_bound < 0) |
upper_bound = RE_DUP_MAX; |
} |
else |
/* Interval such as `{1}' => match exactly once. */ |
upper_bound = lower_bound; |
if (! (0 <= lower_bound && lower_bound <= upper_bound)) |
goto invalid_interval; |
if (!(syntax & RE_NO_BK_BRACES)) |
{ |
if (c != '\\' || p == pend) |
goto invalid_interval; |
PATFETCH (c); |
} |
if (c != '}') |
goto invalid_interval; |
/* If it's invalid to have no preceding re. */ |
if (!laststart) |
{ |
if (syntax & RE_CONTEXT_INVALID_OPS |
&& !(syntax & RE_INVALID_INTERVAL_ORD)) |
FREE_STACK_RETURN (REG_BADRPT); |
else if (syntax & RE_CONTEXT_INDEP_OPS) |
laststart = b; |
else |
goto unfetch_interval; |
} |
/* We just parsed a valid interval. */ |
if (RE_DUP_MAX < upper_bound) |
FREE_STACK_RETURN (REG_BADBR); |
/* If the upper bound is zero, don't want to succeed at |
all; jump from `laststart' to `b + 3', which will be |
the end of the buffer after we insert the jump. */ |
/* ifdef WCHAR, 'b + 1 + OFFSET_ADDRESS_SIZE' |
instead of 'b + 3'. */ |
if (upper_bound == 0) |
{ |
GET_BUFFER_SPACE (1 + OFFSET_ADDRESS_SIZE); |
INSERT_JUMP (jump, laststart, b + 1 |
+ OFFSET_ADDRESS_SIZE); |
b += 1 + OFFSET_ADDRESS_SIZE; |
} |
/* Otherwise, we have a nontrivial interval. When |
we're all done, the pattern will look like: |
set_number_at <jump count> <upper bound> |
set_number_at <succeed_n count> <lower bound> |
succeed_n <after jump addr> <succeed_n count> |
<body of loop> |
jump_n <succeed_n addr> <jump count> |
(The upper bound and `jump_n' are omitted if |
`upper_bound' is 1, though.) */ |
else |
{ /* If the upper bound is > 1, we need to insert |
more at the end of the loop. */ |
unsigned nbytes = 2 + 4 * OFFSET_ADDRESS_SIZE + |
(upper_bound > 1) * (2 + 4 * OFFSET_ADDRESS_SIZE); |
GET_BUFFER_SPACE (nbytes); |
/* Initialize lower bound of the `succeed_n', even |
though it will be set during matching by its |
attendant `set_number_at' (inserted next), |
because `re_compile_fastmap' needs to know. |
Jump to the `jump_n' we might insert below. */ |
INSERT_JUMP2 (succeed_n, laststart, |
b + 1 + 2 * OFFSET_ADDRESS_SIZE |
+ (upper_bound > 1) * (1 + 2 * OFFSET_ADDRESS_SIZE) |
, lower_bound); |
b += 1 + 2 * OFFSET_ADDRESS_SIZE; |
/* Code to initialize the lower bound. Insert |
before the `succeed_n'. The `5' is the last two |
bytes of this `set_number_at', plus 3 bytes of |
the following `succeed_n'. */ |
/* ifdef WCHAR, The '1+2*OFFSET_ADDRESS_SIZE' |
is the 'set_number_at', plus '1+OFFSET_ADDRESS_SIZE' |
of the following `succeed_n'. */ |
PREFIX(insert_op2) (set_number_at, laststart, 1 |
+ 2 * OFFSET_ADDRESS_SIZE, lower_bound, b); |
b += 1 + 2 * OFFSET_ADDRESS_SIZE; |
if (upper_bound > 1) |
{ /* More than one repetition is allowed, so |
append a backward jump to the `succeed_n' |
that starts this interval. |
When we've reached this during matching, |
we'll have matched the interval once, so |
jump back only `upper_bound - 1' times. */ |
STORE_JUMP2 (jump_n, b, laststart |
+ 2 * OFFSET_ADDRESS_SIZE + 1, |
upper_bound - 1); |
b += 1 + 2 * OFFSET_ADDRESS_SIZE; |
/* The location we want to set is the second |
parameter of the `jump_n'; that is `b-2' as |
an absolute address. `laststart' will be |
the `set_number_at' we're about to insert; |
`laststart+3' the number to set, the source |
for the relative address. But we are |
inserting into the middle of the pattern -- |
so everything is getting moved up by 5. |
Conclusion: (b - 2) - (laststart + 3) + 5, |
i.e., b - laststart. |
We insert this at the beginning of the loop |
so that if we fail during matching, we'll |
reinitialize the bounds. */ |
PREFIX(insert_op2) (set_number_at, laststart, |
b - laststart, |
upper_bound - 1, b); |
b += 1 + 2 * OFFSET_ADDRESS_SIZE; |
} |
} |
pending_exact = 0; |
break; |
invalid_interval: |
if (!(syntax & RE_INVALID_INTERVAL_ORD)) |
FREE_STACK_RETURN (p == pend ? REG_EBRACE : REG_BADBR); |
unfetch_interval: |
/* Match the characters as literals. */ |
p = beg_interval; |
c = '{'; |
if (syntax & RE_NO_BK_BRACES) |
goto normal_char; |
else |
goto normal_backslash; |
} |
#ifdef emacs |
/* There is no way to specify the before_dot and after_dot |
operators. rms says this is ok. --karl */ |
case '=': |
BUF_PUSH (at_dot); |
break; |
case 's': |
laststart = b; |
PATFETCH (c); |
BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]); |
break; |
case 'S': |
laststart = b; |
PATFETCH (c); |
BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]); |
break; |
#endif /* emacs */ |
case 'w': |
if (syntax & RE_NO_GNU_OPS) |
goto normal_char; |
laststart = b; |
BUF_PUSH (wordchar); |
break; |
case 'W': |
if (syntax & RE_NO_GNU_OPS) |
goto normal_char; |
laststart = b; |
BUF_PUSH (notwordchar); |
break; |
case '<': |
if (syntax & RE_NO_GNU_OPS) |
goto normal_char; |
BUF_PUSH (wordbeg); |
break; |
case '>': |
if (syntax & RE_NO_GNU_OPS) |
goto normal_char; |
BUF_PUSH (wordend); |
break; |
case 'b': |
if (syntax & RE_NO_GNU_OPS) |
goto normal_char; |
BUF_PUSH (wordbound); |
break; |
case 'B': |
if (syntax & RE_NO_GNU_OPS) |
goto normal_char; |
BUF_PUSH (notwordbound); |
break; |
case '`': |
if (syntax & RE_NO_GNU_OPS) |
goto normal_char; |
BUF_PUSH (begbuf); |
break; |
case '\'': |
if (syntax & RE_NO_GNU_OPS) |
goto normal_char; |
BUF_PUSH (endbuf); |
break; |
case '1': case '2': case '3': case '4': case '5': |
case '6': case '7': case '8': case '9': |
if (syntax & RE_NO_BK_REFS) |
goto normal_char; |
c1 = c - '0'; |
if (c1 > regnum) |
FREE_STACK_RETURN (REG_ESUBREG); |
/* Can't back reference to a subexpression if inside of it. */ |
if (group_in_compile_stack (compile_stack, (regnum_t) c1)) |
goto normal_char; |
laststart = b; |
BUF_PUSH_2 (duplicate, c1); |
break; |
case '+': |
case '?': |
if (syntax & RE_BK_PLUS_QM) |
goto handle_plus; |
else |
goto normal_backslash; |
default: |
normal_backslash: |
/* You might think it would be useful for \ to mean |
not to translate; but if we don't translate it |
it will never match anything. */ |
c = TRANSLATE (c); |
goto normal_char; |
} |
break; |
default: |
/* Expects the character in `c'. */ |
normal_char: |
/* If no exactn currently being built. */ |
if (!pending_exact |
#ifdef WCHAR |
/* If last exactn handle binary(or character) and |
new exactn handle character(or binary). */ |
|| is_exactn_bin != is_binary[p - 1 - pattern] |
#endif /* WCHAR */ |
/* If last exactn not at current position. */ |
|| pending_exact + *pending_exact + 1 != b |
/* We have only one byte following the exactn for the count. */ |
|| *pending_exact == (1 << BYTEWIDTH) - 1 |
/* If followed by a repetition operator. */ |
|| *p == '*' || *p == '^' |
|| ((syntax & RE_BK_PLUS_QM) |
? *p == '\\' && (p[1] == '+' || p[1] == '?') |
: (*p == '+' || *p == '?')) |
|| ((syntax & RE_INTERVALS) |
&& ((syntax & RE_NO_BK_BRACES) |
? *p == '{' |
: (p[0] == '\\' && p[1] == '{')))) |
{ |
/* Start building a new exactn. */ |
laststart = b; |
#ifdef WCHAR |
/* Is this exactn binary data or character? */ |
is_exactn_bin = is_binary[p - 1 - pattern]; |
if (is_exactn_bin) |
BUF_PUSH_2 (exactn_bin, 0); |
else |
BUF_PUSH_2 (exactn, 0); |
#else |
BUF_PUSH_2 (exactn, 0); |
#endif /* WCHAR */ |
pending_exact = b - 1; |
} |
BUF_PUSH (c); |
(*pending_exact)++; |
break; |
} /* switch (c) */ |
} /* while p != pend */ |
/* Through the pattern now. */ |
if (fixup_alt_jump) |
STORE_JUMP (jump_past_alt, fixup_alt_jump, b); |
if (!COMPILE_STACK_EMPTY) |
FREE_STACK_RETURN (REG_EPAREN); |
/* If we don't want backtracking, force success |
the first time we reach the end of the compiled pattern. */ |
if (syntax & RE_NO_POSIX_BACKTRACKING) |
BUF_PUSH (succeed); |
#ifdef WCHAR |
free (pattern); |
free (mbs_offset); |
free (is_binary); |
#endif |
free (compile_stack.stack); |
/* We have succeeded; set the length of the buffer. */ |
#ifdef WCHAR |
bufp->used = (uintptr_t) b - (uintptr_t) COMPILED_BUFFER_VAR; |
#else |
bufp->used = b - bufp->buffer; |
#endif |
#ifdef DEBUG |
if (debug) |
{ |
DEBUG_PRINT1 ("\nCompiled pattern: \n"); |
PREFIX(print_compiled_pattern) (bufp); |
} |
#endif /* DEBUG */ |
#ifndef MATCH_MAY_ALLOCATE |
/* Initialize the failure stack to the largest possible stack. This |
isn't necessary unless we're trying to avoid calling alloca in |
the search and match routines. */ |
{ |
int num_regs = bufp->re_nsub + 1; |
/* Since DOUBLE_FAIL_STACK refuses to double only if the current size |
is strictly greater than re_max_failures, the largest possible stack |
is 2 * re_max_failures failure points. */ |
if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS)) |
{ |
fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS); |
# ifdef emacs |
if (! fail_stack.stack) |
fail_stack.stack |
= (PREFIX(fail_stack_elt_t) *) xmalloc (fail_stack.size |
* sizeof (PREFIX(fail_stack_elt_t))); |
else |
fail_stack.stack |
= (PREFIX(fail_stack_elt_t) *) xrealloc (fail_stack.stack, |
(fail_stack.size |
* sizeof (PREFIX(fail_stack_elt_t)))); |
# else /* not emacs */ |
if (! fail_stack.stack) |
fail_stack.stack |
= (PREFIX(fail_stack_elt_t) *) malloc (fail_stack.size |
* sizeof (PREFIX(fail_stack_elt_t))); |
else |
fail_stack.stack |
= (PREFIX(fail_stack_elt_t) *) realloc (fail_stack.stack, |
(fail_stack.size |
* sizeof (PREFIX(fail_stack_elt_t)))); |
# endif /* not emacs */ |
} |
PREFIX(regex_grow_registers) (num_regs); |
} |
#endif /* not MATCH_MAY_ALLOCATE */ |
return REG_NOERROR; |
} /* regex_compile */ |
/* Subroutines for `regex_compile'. */ |
/* Store OP at LOC followed by two-byte integer parameter ARG. */ |
/* ifdef WCHAR, integer parameter is 1 wchar_t. */ |
static void |
PREFIX(store_op1) (re_opcode_t op, UCHAR_T *loc, int arg) |
{ |
*loc = (UCHAR_T) op; |
STORE_NUMBER (loc + 1, arg); |
} |
/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */ |
/* ifdef WCHAR, integer parameter is 1 wchar_t. */ |
static void |
PREFIX(store_op2) (re_opcode_t op, UCHAR_T *loc, int arg1, int arg2) |
{ |
*loc = (UCHAR_T) op; |
STORE_NUMBER (loc + 1, arg1); |
STORE_NUMBER (loc + 1 + OFFSET_ADDRESS_SIZE, arg2); |
} |
/* Copy the bytes from LOC to END to open up three bytes of space at LOC |
for OP followed by two-byte integer parameter ARG. */ |
/* ifdef WCHAR, integer parameter is 1 wchar_t. */ |
static void |
PREFIX(insert_op1) (re_opcode_t op, UCHAR_T *loc, int arg, UCHAR_T *end) |
{ |
register UCHAR_T *pfrom = end; |
register UCHAR_T *pto = end + 1 + OFFSET_ADDRESS_SIZE; |
while (pfrom != loc) |
*--pto = *--pfrom; |
PREFIX(store_op1) (op, loc, arg); |
} |
/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */ |
/* ifdef WCHAR, integer parameter is 1 wchar_t. */ |
static void |
PREFIX(insert_op2) (re_opcode_t op, UCHAR_T *loc, int arg1, |
int arg2, UCHAR_T *end) |
{ |
register UCHAR_T *pfrom = end; |
register UCHAR_T *pto = end + 1 + 2 * OFFSET_ADDRESS_SIZE; |
while (pfrom != loc) |
*--pto = *--pfrom; |
PREFIX(store_op2) (op, loc, arg1, arg2); |
} |
/* P points to just after a ^ in PATTERN. Return true if that ^ comes |
after an alternative or a begin-subexpression. We assume there is at |
least one character before the ^. */ |
static boolean |
PREFIX(at_begline_loc_p) (const CHAR_T *pattern, const CHAR_T *p, |
reg_syntax_t syntax) |
{ |
const CHAR_T *prev = p - 2; |
boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\'; |
return |
/* After a subexpression? */ |
(*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash)) |
/* After an alternative? */ |
|| (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash)); |
} |
/* The dual of at_begline_loc_p. This one is for $. We assume there is |
at least one character after the $, i.e., `P < PEND'. */ |
static boolean |
PREFIX(at_endline_loc_p) (const CHAR_T *p, const CHAR_T *pend, |
reg_syntax_t syntax) |
{ |
const CHAR_T *next = p; |
boolean next_backslash = *next == '\\'; |
const CHAR_T *next_next = p + 1 < pend ? p + 1 : 0; |
return |
/* Before a subexpression? */ |
(syntax & RE_NO_BK_PARENS ? *next == ')' |
: next_backslash && next_next && *next_next == ')') |
/* Before an alternative? */ |
|| (syntax & RE_NO_BK_VBAR ? *next == '|' |
: next_backslash && next_next && *next_next == '|'); |
} |
#else /* not INSIDE_RECURSION */ |
/* Returns true if REGNUM is in one of COMPILE_STACK's elements and |
false if it's not. */ |
static boolean |
group_in_compile_stack (compile_stack_type compile_stack, regnum_t regnum) |
{ |
int this_element; |
for (this_element = compile_stack.avail - 1; |
this_element >= 0; |
this_element--) |
if (compile_stack.stack[this_element].regnum == regnum) |
return true; |
return false; |
} |
#endif /* not INSIDE_RECURSION */ |
#ifdef INSIDE_RECURSION |
#ifdef WCHAR |
/* This insert space, which size is "num", into the pattern at "loc". |
"end" must point the end of the allocated buffer. */ |
static void |
insert_space (int num, CHAR_T *loc, CHAR_T *end) |
{ |
register CHAR_T *pto = end; |
register CHAR_T *pfrom = end - num; |
while (pfrom >= loc) |
*pto-- = *pfrom--; |
} |
#endif /* WCHAR */ |
#ifdef WCHAR |
static reg_errcode_t |
wcs_compile_range (CHAR_T range_start_char, const CHAR_T **p_ptr, |
const CHAR_T *pend, RE_TRANSLATE_TYPE translate, |
reg_syntax_t syntax, CHAR_T *b, CHAR_T *char_set) |
{ |
const CHAR_T *p = *p_ptr; |
CHAR_T range_start, range_end; |
reg_errcode_t ret; |
# ifdef _LIBC |
uint32_t nrules; |
uint32_t start_val, end_val; |
# endif |
if (p == pend) |
return REG_ERANGE; |
# ifdef _LIBC |
nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
if (nrules != 0) |
{ |
const char *collseq = (const char *) _NL_CURRENT(LC_COLLATE, |
_NL_COLLATE_COLLSEQWC); |
const unsigned char *extra = (const unsigned char *) |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); |
if (range_start_char < -1) |
{ |
/* range_start is a collating symbol. */ |
int32_t *wextra; |
/* Retreive the index and get collation sequence value. */ |
wextra = (int32_t*)(extra + char_set[-range_start_char]); |
start_val = wextra[1 + *wextra]; |
} |
else |
start_val = collseq_table_lookup(collseq, TRANSLATE(range_start_char)); |
end_val = collseq_table_lookup (collseq, TRANSLATE (p[0])); |
/* Report an error if the range is empty and the syntax prohibits |
this. */ |
ret = ((syntax & RE_NO_EMPTY_RANGES) |
&& (start_val > end_val))? REG_ERANGE : REG_NOERROR; |
/* Insert space to the end of the char_ranges. */ |
insert_space(2, b - char_set[5] - 2, b - 1); |
*(b - char_set[5] - 2) = (wchar_t)start_val; |
*(b - char_set[5] - 1) = (wchar_t)end_val; |
char_set[4]++; /* ranges_index */ |
} |
else |
# endif |
{ |
range_start = (range_start_char >= 0)? TRANSLATE (range_start_char): |
range_start_char; |
range_end = TRANSLATE (p[0]); |
/* Report an error if the range is empty and the syntax prohibits |
this. */ |
ret = ((syntax & RE_NO_EMPTY_RANGES) |
&& (range_start > range_end))? REG_ERANGE : REG_NOERROR; |
/* Insert space to the end of the char_ranges. */ |
insert_space(2, b - char_set[5] - 2, b - 1); |
*(b - char_set[5] - 2) = range_start; |
*(b - char_set[5] - 1) = range_end; |
char_set[4]++; /* ranges_index */ |
} |
/* Have to increment the pointer into the pattern string, so the |
caller isn't still at the ending character. */ |
(*p_ptr)++; |
return ret; |
} |
#else /* BYTE */ |
/* Read the ending character of a range (in a bracket expression) from the |
uncompiled pattern *P_PTR (which ends at PEND). We assume the |
starting character is in `P[-2]'. (`P[-1]' is the character `-'.) |
Then we set the translation of all bits between the starting and |
ending characters (inclusive) in the compiled pattern B. |
Return an error code. |
We use these short variable names so we can use the same macros as |
`regex_compile' itself. */ |
static reg_errcode_t |
byte_compile_range (unsigned int range_start_char, const char **p_ptr, |
const char *pend, RE_TRANSLATE_TYPE translate, |
reg_syntax_t syntax, unsigned char *b) |
{ |
unsigned this_char; |
const char *p = *p_ptr; |
reg_errcode_t ret; |
# if _LIBC |
const unsigned char *collseq; |
unsigned int start_colseq; |
unsigned int end_colseq; |
# else |
unsigned end_char; |
# endif |
if (p == pend) |
return REG_ERANGE; |
/* Have to increment the pointer into the pattern string, so the |
caller isn't still at the ending character. */ |
(*p_ptr)++; |
/* Report an error if the range is empty and the syntax prohibits this. */ |
ret = syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR; |
# if _LIBC |
collseq = (const unsigned char *) _NL_CURRENT (LC_COLLATE, |
_NL_COLLATE_COLLSEQMB); |
start_colseq = collseq[(unsigned char) TRANSLATE (range_start_char)]; |
end_colseq = collseq[(unsigned char) TRANSLATE (p[0])]; |
for (this_char = 0; this_char <= (unsigned char) -1; ++this_char) |
{ |
unsigned int this_colseq = collseq[(unsigned char) TRANSLATE (this_char)]; |
if (start_colseq <= this_colseq && this_colseq <= end_colseq) |
{ |
SET_LIST_BIT (TRANSLATE (this_char)); |
ret = REG_NOERROR; |
} |
} |
# else |
/* Here we see why `this_char' has to be larger than an `unsigned |
char' -- we would otherwise go into an infinite loop, since all |
characters <= 0xff. */ |
range_start_char = TRANSLATE (range_start_char); |
/* TRANSLATE(p[0]) is casted to char (not unsigned char) in TRANSLATE, |
and some compilers cast it to int implicitly, so following for_loop |
may fall to (almost) infinite loop. |
e.g. If translate[p[0]] = 0xff, end_char may equals to 0xffffffff. |
To avoid this, we cast p[0] to unsigned int and truncate it. */ |
end_char = ((unsigned)TRANSLATE(p[0]) & ((1 << BYTEWIDTH) - 1)); |
for (this_char = range_start_char; this_char <= end_char; ++this_char) |
{ |
SET_LIST_BIT (TRANSLATE (this_char)); |
ret = REG_NOERROR; |
} |
# endif |
return ret; |
} |
#endif /* WCHAR */ |
/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in |
BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible |
characters can start a string that matches the pattern. This fastmap |
is used by re_search to skip quickly over impossible starting points. |
The caller must supply the address of a (1 << BYTEWIDTH)-byte data |
area as BUFP->fastmap. |
We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in |
the pattern buffer. |
Returns 0 if we succeed, -2 if an internal error. */ |
#ifdef WCHAR |
/* local function for re_compile_fastmap. |
truncate wchar_t character to char. */ |
static unsigned char truncate_wchar (CHAR_T c); |
static unsigned char |
truncate_wchar (CHAR_T c) |
{ |
unsigned char buf[MB_CUR_MAX]; |
mbstate_t state; |
int retval; |
memset (&state, '\0', sizeof (state)); |
# ifdef _LIBC |
retval = __wcrtomb (buf, c, &state); |
# else |
retval = wcrtomb (buf, c, &state); |
# endif |
return retval > 0 ? buf[0] : (unsigned char) c; |
} |
#endif /* WCHAR */ |
static int |
PREFIX(re_compile_fastmap) (struct re_pattern_buffer *bufp) |
{ |
int j, k; |
#ifdef MATCH_MAY_ALLOCATE |
PREFIX(fail_stack_type) fail_stack; |
#endif |
#ifndef REGEX_MALLOC |
char *destination; |
#endif |
register char *fastmap = bufp->fastmap; |
#ifdef WCHAR |
/* We need to cast pattern to (wchar_t*), because we casted this compiled |
pattern to (char*) in regex_compile. */ |
UCHAR_T *pattern = (UCHAR_T*)bufp->buffer; |
register UCHAR_T *pend = (UCHAR_T*) (bufp->buffer + bufp->used); |
#else /* BYTE */ |
UCHAR_T *pattern = bufp->buffer; |
register UCHAR_T *pend = pattern + bufp->used; |
#endif /* WCHAR */ |
UCHAR_T *p = pattern; |
#ifdef REL_ALLOC |
/* This holds the pointer to the failure stack, when |
it is allocated relocatably. */ |
fail_stack_elt_t *failure_stack_ptr; |
#endif |
/* Assume that each path through the pattern can be null until |
proven otherwise. We set this false at the bottom of switch |
statement, to which we get only if a particular path doesn't |
match the empty string. */ |
boolean path_can_be_null = true; |
/* We aren't doing a `succeed_n' to begin with. */ |
boolean succeed_n_p = false; |
assert (fastmap != NULL && p != NULL); |
INIT_FAIL_STACK (); |
bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */ |
bufp->fastmap_accurate = 1; /* It will be when we're done. */ |
bufp->can_be_null = 0; |
while (1) |
{ |
if (p == pend || *p == (UCHAR_T) succeed) |
{ |
/* We have reached the (effective) end of pattern. */ |
if (!FAIL_STACK_EMPTY ()) |
{ |
bufp->can_be_null |= path_can_be_null; |
/* Reset for next path. */ |
path_can_be_null = true; |
p = fail_stack.stack[--fail_stack.avail].pointer; |
continue; |
} |
else |
break; |
} |
/* We should never be about to go beyond the end of the pattern. */ |
assert (p < pend); |
switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) |
{ |
/* I guess the idea here is to simply not bother with a fastmap |
if a backreference is used, since it's too hard to figure out |
the fastmap for the corresponding group. Setting |
`can_be_null' stops `re_search_2' from using the fastmap, so |
that is all we do. */ |
case duplicate: |
bufp->can_be_null = 1; |
goto done; |
/* Following are the cases which match a character. These end |
with `break'. */ |
#ifdef WCHAR |
case exactn: |
fastmap[truncate_wchar(p[1])] = 1; |
break; |
#else /* BYTE */ |
case exactn: |
fastmap[p[1]] = 1; |
break; |
#endif /* WCHAR */ |
#ifdef MBS_SUPPORT |
case exactn_bin: |
fastmap[p[1]] = 1; |
break; |
#endif |
#ifdef WCHAR |
/* It is hard to distinguish fastmap from (multi byte) characters |
which depends on current locale. */ |
case charset: |
case charset_not: |
case wordchar: |
case notwordchar: |
bufp->can_be_null = 1; |
goto done; |
#else /* BYTE */ |
case charset: |
for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) |
if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))) |
fastmap[j] = 1; |
break; |
case charset_not: |
/* Chars beyond end of map must be allowed. */ |
for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++) |
fastmap[j] = 1; |
for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--) |
if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))) |
fastmap[j] = 1; |
break; |
case wordchar: |
for (j = 0; j < (1 << BYTEWIDTH); j++) |
if (SYNTAX (j) == Sword) |
fastmap[j] = 1; |
break; |
case notwordchar: |
for (j = 0; j < (1 << BYTEWIDTH); j++) |
if (SYNTAX (j) != Sword) |
fastmap[j] = 1; |
break; |
#endif /* WCHAR */ |
case anychar: |
{ |
int fastmap_newline = fastmap['\n']; |
/* `.' matches anything ... */ |
for (j = 0; j < (1 << BYTEWIDTH); j++) |
fastmap[j] = 1; |
/* ... except perhaps newline. */ |
if (!(bufp->syntax & RE_DOT_NEWLINE)) |
fastmap['\n'] = fastmap_newline; |
/* Return if we have already set `can_be_null'; if we have, |
then the fastmap is irrelevant. Something's wrong here. */ |
else if (bufp->can_be_null) |
goto done; |
/* Otherwise, have to check alternative paths. */ |
break; |
} |
#ifdef emacs |
case syntaxspec: |
k = *p++; |
for (j = 0; j < (1 << BYTEWIDTH); j++) |
if (SYNTAX (j) == (enum syntaxcode) k) |
fastmap[j] = 1; |
break; |
case notsyntaxspec: |
k = *p++; |
for (j = 0; j < (1 << BYTEWIDTH); j++) |
if (SYNTAX (j) != (enum syntaxcode) k) |
fastmap[j] = 1; |
break; |
/* All cases after this match the empty string. These end with |
`continue'. */ |
case before_dot: |
case at_dot: |
case after_dot: |
continue; |
#endif /* emacs */ |
case no_op: |
case begline: |
case endline: |
case begbuf: |
case endbuf: |
case wordbound: |
case notwordbound: |
case wordbeg: |
case wordend: |
case push_dummy_failure: |
continue; |
case jump_n: |
case pop_failure_jump: |
case maybe_pop_jump: |
case jump: |
case jump_past_alt: |
case dummy_failure_jump: |
EXTRACT_NUMBER_AND_INCR (j, p); |
p += j; |
if (j > 0) |
continue; |
/* Jump backward implies we just went through the body of a |
loop and matched nothing. Opcode jumped to should be |
`on_failure_jump' or `succeed_n'. Just treat it like an |
ordinary jump. For a * loop, it has pushed its failure |
point already; if so, discard that as redundant. */ |
if ((re_opcode_t) *p != on_failure_jump |
&& (re_opcode_t) *p != succeed_n) |
continue; |
p++; |
EXTRACT_NUMBER_AND_INCR (j, p); |
p += j; |
/* If what's on the stack is where we are now, pop it. */ |
if (!FAIL_STACK_EMPTY () |
&& fail_stack.stack[fail_stack.avail - 1].pointer == p) |
fail_stack.avail--; |
continue; |
case on_failure_jump: |
case on_failure_keep_string_jump: |
handle_on_failure_jump: |
EXTRACT_NUMBER_AND_INCR (j, p); |
/* For some patterns, e.g., `(a?)?', `p+j' here points to the |
end of the pattern. We don't want to push such a point, |
since when we restore it above, entering the switch will |
increment `p' past the end of the pattern. We don't need |
to push such a point since we obviously won't find any more |
fastmap entries beyond `pend'. Such a pattern can match |
the null string, though. */ |
if (p + j < pend) |
{ |
if (!PUSH_PATTERN_OP (p + j, fail_stack)) |
{ |
RESET_FAIL_STACK (); |
return -2; |
} |
} |
else |
bufp->can_be_null = 1; |
if (succeed_n_p) |
{ |
EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */ |
succeed_n_p = false; |
} |
continue; |
case succeed_n: |
/* Get to the number of times to succeed. */ |
p += OFFSET_ADDRESS_SIZE; |
/* Increment p past the n for when k != 0. */ |
EXTRACT_NUMBER_AND_INCR (k, p); |
if (k == 0) |
{ |
p -= 2 * OFFSET_ADDRESS_SIZE; |
succeed_n_p = true; /* Spaghetti code alert. */ |
goto handle_on_failure_jump; |
} |
continue; |
case set_number_at: |
p += 2 * OFFSET_ADDRESS_SIZE; |
continue; |
case start_memory: |
case stop_memory: |
p += 2; |
continue; |
default: |
abort (); /* We have listed all the cases. */ |
} /* switch *p++ */ |
/* Getting here means we have found the possible starting |
characters for one path of the pattern -- and that the empty |
string does not match. We need not follow this path further. |
Instead, look at the next alternative (remembered on the |
stack), or quit if no more. The test at the top of the loop |
does these things. */ |
path_can_be_null = false; |
p = pend; |
} /* while p */ |
/* Set `can_be_null' for the last path (also the first path, if the |
pattern is empty). */ |
bufp->can_be_null |= path_can_be_null; |
done: |
RESET_FAIL_STACK (); |
return 0; |
} |
#else /* not INSIDE_RECURSION */ |
int |
re_compile_fastmap (struct re_pattern_buffer *bufp) |
{ |
# ifdef MBS_SUPPORT |
if (MB_CUR_MAX != 1) |
return wcs_re_compile_fastmap(bufp); |
else |
# endif |
return byte_re_compile_fastmap(bufp); |
} /* re_compile_fastmap */ |
#ifdef _LIBC |
weak_alias (__re_compile_fastmap, re_compile_fastmap) |
#endif |
/* Set REGS to hold NUM_REGS registers, storing them in STARTS and |
ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use |
this memory for recording register information. STARTS and ENDS |
must be allocated using the malloc library routine, and must each |
be at least NUM_REGS * sizeof (regoff_t) bytes long. |
If NUM_REGS == 0, then subsequent matches should allocate their own |
register data. |
Unless this function is called, the first search or match using |
PATTERN_BUFFER will allocate its own register data, without |
freeing the old data. */ |
void |
re_set_registers (struct re_pattern_buffer *bufp, |
struct re_registers *regs, unsigned num_regs, |
regoff_t *starts, regoff_t *ends) |
{ |
if (num_regs) |
{ |
bufp->regs_allocated = REGS_REALLOCATE; |
regs->num_regs = num_regs; |
regs->start = starts; |
regs->end = ends; |
} |
else |
{ |
bufp->regs_allocated = REGS_UNALLOCATED; |
regs->num_regs = 0; |
regs->start = regs->end = (regoff_t *) 0; |
} |
} |
#ifdef _LIBC |
weak_alias (__re_set_registers, re_set_registers) |
#endif |
/* Searching routines. */ |
/* Like re_search_2, below, but only one string is specified, and |
doesn't let you say where to stop matching. */ |
int |
re_search (struct re_pattern_buffer *bufp, const char *string, int size, |
int startpos, int range, struct re_registers *regs) |
{ |
return re_search_2 (bufp, NULL, 0, string, size, startpos, range, |
regs, size); |
} |
#ifdef _LIBC |
weak_alias (__re_search, re_search) |
#endif |
/* Using the compiled pattern in BUFP->buffer, first tries to match the |
virtual concatenation of STRING1 and STRING2, starting first at index |
STARTPOS, then at STARTPOS + 1, and so on. |
STRING1 and STRING2 have length SIZE1 and SIZE2, respectively. |
RANGE is how far to scan while trying to match. RANGE = 0 means try |
only at STARTPOS; in general, the last start tried is STARTPOS + |
RANGE. |
In REGS, return the indices of the virtual concatenation of STRING1 |
and STRING2 that matched the entire BUFP->buffer and its contained |
subexpressions. |
Do not consider matching one past the index STOP in the virtual |
concatenation of STRING1 and STRING2. |
We return either the position in the strings at which the match was |
found, -1 if no match, or -2 if error (such as failure |
stack overflow). */ |
int |
re_search_2 (struct re_pattern_buffer *bufp, const char *string1, int size1, |
const char *string2, int size2, int startpos, int range, |
struct re_registers *regs, int stop) |
{ |
# ifdef MBS_SUPPORT |
if (MB_CUR_MAX != 1) |
return wcs_re_search_2 (bufp, string1, size1, string2, size2, startpos, |
range, regs, stop); |
else |
# endif |
return byte_re_search_2 (bufp, string1, size1, string2, size2, startpos, |
range, regs, stop); |
} /* re_search_2 */ |
#ifdef _LIBC |
weak_alias (__re_search_2, re_search_2) |
#endif |
#endif /* not INSIDE_RECURSION */ |
#ifdef INSIDE_RECURSION |
#ifdef MATCH_MAY_ALLOCATE |
# define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL |
#else |
# define FREE_VAR(var) free (var); var = NULL |
#endif |
#ifdef WCHAR |
# define MAX_ALLOCA_SIZE 2000 |
# define FREE_WCS_BUFFERS() \ |
do { \ |
if (size1 > MAX_ALLOCA_SIZE) \ |
{ \ |
free (wcs_string1); \ |
free (mbs_offset1); \ |
} \ |
else \ |
{ \ |
FREE_VAR (wcs_string1); \ |
FREE_VAR (mbs_offset1); \ |
} \ |
if (size2 > MAX_ALLOCA_SIZE) \ |
{ \ |
free (wcs_string2); \ |
free (mbs_offset2); \ |
} \ |
else \ |
{ \ |
FREE_VAR (wcs_string2); \ |
FREE_VAR (mbs_offset2); \ |
} \ |
} while (0) |
#endif |
static int |
PREFIX(re_search_2) (struct re_pattern_buffer *bufp, const char *string1, |
int size1, const char *string2, int size2, |
int startpos, int range, |
struct re_registers *regs, int stop) |
{ |
int val; |
register char *fastmap = bufp->fastmap; |
register RE_TRANSLATE_TYPE translate = bufp->translate; |
int total_size = size1 + size2; |
int endpos = startpos + range; |
#ifdef WCHAR |
/* We need wchar_t* buffers correspond to cstring1, cstring2. */ |
wchar_t *wcs_string1 = NULL, *wcs_string2 = NULL; |
/* We need the size of wchar_t buffers correspond to csize1, csize2. */ |
int wcs_size1 = 0, wcs_size2 = 0; |
/* offset buffer for optimizatoin. See convert_mbs_to_wc. */ |
int *mbs_offset1 = NULL, *mbs_offset2 = NULL; |
/* They hold whether each wchar_t is binary data or not. */ |
char *is_binary = NULL; |
#endif /* WCHAR */ |
/* Check for out-of-range STARTPOS. */ |
if (startpos < 0 || startpos > total_size) |
return -1; |
/* Fix up RANGE if it might eventually take us outside |
the virtual concatenation of STRING1 and STRING2. |
Make sure we won't move STARTPOS below 0 or above TOTAL_SIZE. */ |
if (endpos < 0) |
range = 0 - startpos; |
else if (endpos > total_size) |
range = total_size - startpos; |
/* If the search isn't to be a backwards one, don't waste time in a |
search for a pattern that must be anchored. */ |
if (bufp->used > 0 && range > 0 |
&& ((re_opcode_t) bufp->buffer[0] == begbuf |
/* `begline' is like `begbuf' if it cannot match at newlines. */ |
|| ((re_opcode_t) bufp->buffer[0] == begline |
&& !bufp->newline_anchor))) |
{ |
if (startpos > 0) |
return -1; |
else |
range = 1; |
} |
#ifdef emacs |
/* In a forward search for something that starts with \=. |
don't keep searching past point. */ |
if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == at_dot && range > 0) |
{ |
range = PT - startpos; |
if (range <= 0) |
return -1; |
} |
#endif /* emacs */ |
/* Update the fastmap now if not correct already. */ |
if (fastmap && !bufp->fastmap_accurate) |
if (re_compile_fastmap (bufp) == -2) |
return -2; |
#ifdef WCHAR |
/* Allocate wchar_t array for wcs_string1 and wcs_string2 and |
fill them with converted string. */ |
if (size1 != 0) |
{ |
if (size1 > MAX_ALLOCA_SIZE) |
{ |
wcs_string1 = TALLOC (size1 + 1, CHAR_T); |
mbs_offset1 = TALLOC (size1 + 1, int); |
is_binary = TALLOC (size1 + 1, char); |
} |
else |
{ |
wcs_string1 = REGEX_TALLOC (size1 + 1, CHAR_T); |
mbs_offset1 = REGEX_TALLOC (size1 + 1, int); |
is_binary = REGEX_TALLOC (size1 + 1, char); |
} |
if (!wcs_string1 || !mbs_offset1 || !is_binary) |
{ |
if (size1 > MAX_ALLOCA_SIZE) |
{ |
free (wcs_string1); |
free (mbs_offset1); |
free (is_binary); |
} |
else |
{ |
FREE_VAR (wcs_string1); |
FREE_VAR (mbs_offset1); |
FREE_VAR (is_binary); |
} |
return -2; |
} |
wcs_size1 = convert_mbs_to_wcs(wcs_string1, string1, size1, |
mbs_offset1, is_binary); |
wcs_string1[wcs_size1] = L'\0'; /* for a sentinel */ |
if (size1 > MAX_ALLOCA_SIZE) |
free (is_binary); |
else |
FREE_VAR (is_binary); |
} |
if (size2 != 0) |
{ |
if (size2 > MAX_ALLOCA_SIZE) |
{ |
wcs_string2 = TALLOC (size2 + 1, CHAR_T); |
mbs_offset2 = TALLOC (size2 + 1, int); |
is_binary = TALLOC (size2 + 1, char); |
} |
else |
{ |
wcs_string2 = REGEX_TALLOC (size2 + 1, CHAR_T); |
mbs_offset2 = REGEX_TALLOC (size2 + 1, int); |
is_binary = REGEX_TALLOC (size2 + 1, char); |
} |
if (!wcs_string2 || !mbs_offset2 || !is_binary) |
{ |
FREE_WCS_BUFFERS (); |
if (size2 > MAX_ALLOCA_SIZE) |
free (is_binary); |
else |
FREE_VAR (is_binary); |
return -2; |
} |
wcs_size2 = convert_mbs_to_wcs(wcs_string2, string2, size2, |
mbs_offset2, is_binary); |
wcs_string2[wcs_size2] = L'\0'; /* for a sentinel */ |
if (size2 > MAX_ALLOCA_SIZE) |
free (is_binary); |
else |
FREE_VAR (is_binary); |
} |
#endif /* WCHAR */ |
/* Loop through the string, looking for a place to start matching. */ |
for (;;) |
{ |
/* If a fastmap is supplied, skip quickly over characters that |
cannot be the start of a match. If the pattern can match the |
null string, however, we don't need to skip characters; we want |
the first null string. */ |
if (fastmap && startpos < total_size && !bufp->can_be_null) |
{ |
if (range > 0) /* Searching forwards. */ |
{ |
register const char *d; |
register int lim = 0; |
int irange = range; |
if (startpos < size1 && startpos + range >= size1) |
lim = range - (size1 - startpos); |
d = (startpos >= size1 ? string2 - size1 : string1) + startpos; |
/* Written out as an if-else to avoid testing `translate' |
inside the loop. */ |
if (translate) |
while (range > lim |
&& !fastmap[(unsigned char) |
translate[(unsigned char) *d++]]) |
range--; |
else |
while (range > lim && !fastmap[(unsigned char) *d++]) |
range--; |
startpos += irange - range; |
} |
else /* Searching backwards. */ |
{ |
register CHAR_T c = (size1 == 0 || startpos >= size1 |
? string2[startpos - size1] |
: string1[startpos]); |
if (!fastmap[(unsigned char) TRANSLATE (c)]) |
goto advance; |
} |
} |
/* If can't match the null string, and that's all we have left, fail. */ |
if (range >= 0 && startpos == total_size && fastmap |
&& !bufp->can_be_null) |
{ |
#ifdef WCHAR |
FREE_WCS_BUFFERS (); |
#endif |
return -1; |
} |
#ifdef WCHAR |
val = wcs_re_match_2_internal (bufp, string1, size1, string2, |
size2, startpos, regs, stop, |
wcs_string1, wcs_size1, |
wcs_string2, wcs_size2, |
mbs_offset1, mbs_offset2); |
#else /* BYTE */ |
val = byte_re_match_2_internal (bufp, string1, size1, string2, |
size2, startpos, regs, stop); |
#endif /* BYTE */ |
#ifndef REGEX_MALLOC |
# ifdef C_ALLOCA |
alloca (0); |
# endif |
#endif |
if (val >= 0) |
{ |
#ifdef WCHAR |
FREE_WCS_BUFFERS (); |
#endif |
return startpos; |
} |
if (val == -2) |
{ |
#ifdef WCHAR |
FREE_WCS_BUFFERS (); |
#endif |
return -2; |
} |
advance: |
if (!range) |
break; |
else if (range > 0) |
{ |
range--; |
startpos++; |
} |
else |
{ |
range++; |
startpos--; |
} |
} |
#ifdef WCHAR |
FREE_WCS_BUFFERS (); |
#endif |
return -1; |
} |
#ifdef WCHAR |
/* This converts PTR, a pointer into one of the search wchar_t strings |
`string1' and `string2' into an multibyte string offset from the |
beginning of that string. We use mbs_offset to optimize. |
See convert_mbs_to_wcs. */ |
# define POINTER_TO_OFFSET(ptr) \ |
(FIRST_STRING_P (ptr) \ |
? ((regoff_t)(mbs_offset1 != NULL? mbs_offset1[(ptr)-string1] : 0)) \ |
: ((regoff_t)((mbs_offset2 != NULL? mbs_offset2[(ptr)-string2] : 0) \ |
+ csize1))) |
#else /* BYTE */ |
/* This converts PTR, a pointer into one of the search strings `string1' |
and `string2' into an offset from the beginning of that string. */ |
# define POINTER_TO_OFFSET(ptr) \ |
(FIRST_STRING_P (ptr) \ |
? ((regoff_t) ((ptr) - string1)) \ |
: ((regoff_t) ((ptr) - string2 + size1))) |
#endif /* WCHAR */ |
/* Macros for dealing with the split strings in re_match_2. */ |
#define MATCHING_IN_FIRST_STRING (dend == end_match_1) |
/* Call before fetching a character with *d. This switches over to |
string2 if necessary. */ |
#define PREFETCH() \ |
while (d == dend) \ |
{ \ |
/* End of string2 => fail. */ \ |
if (dend == end_match_2) \ |
goto fail; \ |
/* End of string1 => advance to string2. */ \ |
d = string2; \ |
dend = end_match_2; \ |
} |
/* Test if at very beginning or at very end of the virtual concatenation |
of `string1' and `string2'. If only one string, it's `string2'. */ |
#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2) |
#define AT_STRINGS_END(d) ((d) == end2) |
/* Test if D points to a character which is word-constituent. We have |
two special cases to check for: if past the end of string1, look at |
the first character in string2; and if before the beginning of |
string2, look at the last character in string1. */ |
#ifdef WCHAR |
/* Use internationalized API instead of SYNTAX. */ |
# define WORDCHAR_P(d) \ |
(iswalnum ((wint_t)((d) == end1 ? *string2 \ |
: (d) == string2 - 1 ? *(end1 - 1) : *(d))) != 0 \ |
|| ((d) == end1 ? *string2 \ |
: (d) == string2 - 1 ? *(end1 - 1) : *(d)) == L'_') |
#else /* BYTE */ |
# define WORDCHAR_P(d) \ |
(SYNTAX ((d) == end1 ? *string2 \ |
: (d) == string2 - 1 ? *(end1 - 1) : *(d)) \ |
== Sword) |
#endif /* WCHAR */ |
/* Disabled due to a compiler bug -- see comment at case wordbound */ |
#if 0 |
/* Test if the character before D and the one at D differ with respect |
to being word-constituent. */ |
#define AT_WORD_BOUNDARY(d) \ |
(AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \ |
|| WORDCHAR_P (d - 1) != WORDCHAR_P (d)) |
#endif |
/* Free everything we malloc. */ |
#ifdef MATCH_MAY_ALLOCATE |
# ifdef WCHAR |
# define FREE_VARIABLES() \ |
do { \ |
REGEX_FREE_STACK (fail_stack.stack); \ |
FREE_VAR (regstart); \ |
FREE_VAR (regend); \ |
FREE_VAR (old_regstart); \ |
FREE_VAR (old_regend); \ |
FREE_VAR (best_regstart); \ |
FREE_VAR (best_regend); \ |
FREE_VAR (reg_info); \ |
FREE_VAR (reg_dummy); \ |
FREE_VAR (reg_info_dummy); \ |
if (!cant_free_wcs_buf) \ |
{ \ |
FREE_VAR (string1); \ |
FREE_VAR (string2); \ |
FREE_VAR (mbs_offset1); \ |
FREE_VAR (mbs_offset2); \ |
} \ |
} while (0) |
# else /* BYTE */ |
# define FREE_VARIABLES() \ |
do { \ |
REGEX_FREE_STACK (fail_stack.stack); \ |
FREE_VAR (regstart); \ |
FREE_VAR (regend); \ |
FREE_VAR (old_regstart); \ |
FREE_VAR (old_regend); \ |
FREE_VAR (best_regstart); \ |
FREE_VAR (best_regend); \ |
FREE_VAR (reg_info); \ |
FREE_VAR (reg_dummy); \ |
FREE_VAR (reg_info_dummy); \ |
} while (0) |
# endif /* WCHAR */ |
#else |
# ifdef WCHAR |
# define FREE_VARIABLES() \ |
do { \ |
if (!cant_free_wcs_buf) \ |
{ \ |
FREE_VAR (string1); \ |
FREE_VAR (string2); \ |
FREE_VAR (mbs_offset1); \ |
FREE_VAR (mbs_offset2); \ |
} \ |
} while (0) |
# else /* BYTE */ |
# define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */ |
# endif /* WCHAR */ |
#endif /* not MATCH_MAY_ALLOCATE */ |
/* These values must meet several constraints. They must not be valid |
register values; since we have a limit of 255 registers (because |
we use only one byte in the pattern for the register number), we can |
use numbers larger than 255. They must differ by 1, because of |
NUM_FAILURE_ITEMS above. And the value for the lowest register must |
be larger than the value for the highest register, so we do not try |
to actually save any registers when none are active. */ |
#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH) |
#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1) |
#else /* not INSIDE_RECURSION */ |
/* Matching routines. */ |
#ifndef emacs /* Emacs never uses this. */ |
/* re_match is like re_match_2 except it takes only a single string. */ |
int |
re_match (struct re_pattern_buffer *bufp, const char *string, |
int size, int pos, struct re_registers *regs) |
{ |
int result; |
# ifdef MBS_SUPPORT |
if (MB_CUR_MAX != 1) |
result = wcs_re_match_2_internal (bufp, NULL, 0, string, size, |
pos, regs, size, |
NULL, 0, NULL, 0, NULL, NULL); |
else |
# endif |
result = byte_re_match_2_internal (bufp, NULL, 0, string, size, |
pos, regs, size); |
# ifndef REGEX_MALLOC |
# ifdef C_ALLOCA |
alloca (0); |
# endif |
# endif |
return result; |
} |
# ifdef _LIBC |
weak_alias (__re_match, re_match) |
# endif |
#endif /* not emacs */ |
#endif /* not INSIDE_RECURSION */ |
#ifdef INSIDE_RECURSION |
static boolean PREFIX(group_match_null_string_p) (UCHAR_T **p, |
UCHAR_T *end, |
PREFIX(register_info_type) *reg_info); |
static boolean PREFIX(alt_match_null_string_p) (UCHAR_T *p, |
UCHAR_T *end, |
PREFIX(register_info_type) *reg_info); |
static boolean PREFIX(common_op_match_null_string_p) (UCHAR_T **p, |
UCHAR_T *end, |
PREFIX(register_info_type) *reg_info); |
static int PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2, |
int len, char *translate); |
#else /* not INSIDE_RECURSION */ |
/* re_match_2 matches the compiled pattern in BUFP against the |
the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1 |
and SIZE2, respectively). We start matching at POS, and stop |
matching at STOP. |
If REGS is non-null and the `no_sub' field of BUFP is nonzero, we |
store offsets for the substring each group matched in REGS. See the |
documentation for exactly how many groups we fill. |
We return -1 if no match, -2 if an internal error (such as the |
failure stack overflowing). Otherwise, we return the length of the |
matched substring. */ |
int |
re_match_2 (struct re_pattern_buffer *bufp, const char *string1, int size1, |
const char *string2, int size2, int pos, |
struct re_registers *regs, int stop) |
{ |
int result; |
# ifdef MBS_SUPPORT |
if (MB_CUR_MAX != 1) |
result = wcs_re_match_2_internal (bufp, string1, size1, string2, size2, |
pos, regs, stop, |
NULL, 0, NULL, 0, NULL, NULL); |
else |
# endif |
result = byte_re_match_2_internal (bufp, string1, size1, string2, size2, |
pos, regs, stop); |
#ifndef REGEX_MALLOC |
# ifdef C_ALLOCA |
alloca (0); |
# endif |
#endif |
return result; |
} |
#ifdef _LIBC |
weak_alias (__re_match_2, re_match_2) |
#endif |
#endif /* not INSIDE_RECURSION */ |
#ifdef INSIDE_RECURSION |
#ifdef WCHAR |
static int count_mbs_length (int *, int); |
/* This check the substring (from 0, to length) of the multibyte string, |
to which offset_buffer correspond. And count how many wchar_t_characters |
the substring occupy. We use offset_buffer to optimization. |
See convert_mbs_to_wcs. */ |
static int |
count_mbs_length(int *offset_buffer, int length) |
{ |
int upper, lower; |
/* Check whether the size is valid. */ |
if (length < 0) |
return -1; |
if (offset_buffer == NULL) |
return 0; |
/* If there are no multibyte character, offset_buffer[i] == i. |
Optmize for this case. */ |
if (offset_buffer[length] == length) |
return length; |
/* Set up upper with length. (because for all i, offset_buffer[i] >= i) */ |
upper = length; |
lower = 0; |
while (true) |
{ |
int middle = (lower + upper) / 2; |
if (middle == lower || middle == upper) |
break; |
if (offset_buffer[middle] > length) |
upper = middle; |
else if (offset_buffer[middle] < length) |
lower = middle; |
else |
return middle; |
} |
return -1; |
} |
#endif /* WCHAR */ |
/* This is a separate function so that we can force an alloca cleanup |
afterwards. */ |
#ifdef WCHAR |
static int |
wcs_re_match_2_internal (struct re_pattern_buffer *bufp, |
const char *cstring1, int csize1, |
const char *cstring2, int csize2, |
int pos, |
struct re_registers *regs, |
int stop, |
/* string1 == string2 == NULL means string1/2, size1/2 and |
mbs_offset1/2 need seting up in this function. */ |
/* We need wchar_t* buffers correspond to cstring1, cstring2. */ |
wchar_t *string1, int size1, |
wchar_t *string2, int size2, |
/* offset buffer for optimizatoin. See convert_mbs_to_wc. */ |
int *mbs_offset1, int *mbs_offset2) |
#else /* BYTE */ |
static int |
byte_re_match_2_internal (struct re_pattern_buffer *bufp, |
const char *string1, int size1, |
const char *string2, int size2, |
int pos, |
struct re_registers *regs, int stop) |
#endif /* BYTE */ |
{ |
/* General temporaries. */ |
int mcnt; |
UCHAR_T *p1; |
#ifdef WCHAR |
/* They hold whether each wchar_t is binary data or not. */ |
char *is_binary = NULL; |
/* If true, we can't free string1/2, mbs_offset1/2. */ |
int cant_free_wcs_buf = 1; |
#endif /* WCHAR */ |
/* Just past the end of the corresponding string. */ |
const CHAR_T *end1, *end2; |
/* Pointers into string1 and string2, just past the last characters in |
each to consider matching. */ |
const CHAR_T *end_match_1, *end_match_2; |
/* Where we are in the data, and the end of the current string. */ |
const CHAR_T *d, *dend; |
/* Where we are in the pattern, and the end of the pattern. */ |
#ifdef WCHAR |
UCHAR_T *pattern, *p; |
register UCHAR_T *pend; |
#else /* BYTE */ |
UCHAR_T *p = bufp->buffer; |
register UCHAR_T *pend = p + bufp->used; |
#endif /* WCHAR */ |
/* Mark the opcode just after a start_memory, so we can test for an |
empty subpattern when we get to the stop_memory. */ |
UCHAR_T *just_past_start_mem = 0; |
/* We use this to map every character in the string. */ |
RE_TRANSLATE_TYPE translate = bufp->translate; |
/* Failure point stack. Each place that can handle a failure further |
down the line pushes a failure point on this stack. It consists of |
restart, regend, and reg_info for all registers corresponding to |
the subexpressions we're currently inside, plus the number of such |
registers, and, finally, two char *'s. The first char * is where |
to resume scanning the pattern; the second one is where to resume |
scanning the strings. If the latter is zero, the failure point is |
a ``dummy''; if a failure happens and the failure point is a dummy, |
it gets discarded and the next next one is tried. */ |
#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ |
PREFIX(fail_stack_type) fail_stack; |
#endif |
#ifdef DEBUG |
static unsigned failure_id; |
unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0; |
#endif |
#ifdef REL_ALLOC |
/* This holds the pointer to the failure stack, when |
it is allocated relocatably. */ |
fail_stack_elt_t *failure_stack_ptr; |
#endif |
/* We fill all the registers internally, independent of what we |
return, for use in backreferences. The number here includes |
an element for register zero. */ |
size_t num_regs = bufp->re_nsub + 1; |
/* The currently active registers. */ |
active_reg_t lowest_active_reg = NO_LOWEST_ACTIVE_REG; |
active_reg_t highest_active_reg = NO_HIGHEST_ACTIVE_REG; |
/* Information on the contents of registers. These are pointers into |
the input strings; they record just what was matched (on this |
attempt) by a subexpression part of the pattern, that is, the |
regnum-th regstart pointer points to where in the pattern we began |
matching and the regnum-th regend points to right after where we |
stopped matching the regnum-th subexpression. (The zeroth register |
keeps track of what the whole pattern matches.) */ |
#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ |
const CHAR_T **regstart, **regend; |
#endif |
/* If a group that's operated upon by a repetition operator fails to |
match anything, then the register for its start will need to be |
restored because it will have been set to wherever in the string we |
are when we last see its open-group operator. Similarly for a |
register's end. */ |
#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ |
const CHAR_T **old_regstart, **old_regend; |
#endif |
/* The is_active field of reg_info helps us keep track of which (possibly |
nested) subexpressions we are currently in. The matched_something |
field of reg_info[reg_num] helps us tell whether or not we have |
matched any of the pattern so far this time through the reg_num-th |
subexpression. These two fields get reset each time through any |
loop their register is in. */ |
#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */ |
PREFIX(register_info_type) *reg_info; |
#endif |
/* The following record the register info as found in the above |
variables when we find a match better than any we've seen before. |
This happens as we backtrack through the failure points, which in |
turn happens only if we have not yet matched the entire string. */ |
unsigned best_regs_set = false; |
#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ |
const CHAR_T **best_regstart, **best_regend; |
#endif |
/* Logically, this is `best_regend[0]'. But we don't want to have to |
allocate space for that if we're not allocating space for anything |
else (see below). Also, we never need info about register 0 for |
any of the other register vectors, and it seems rather a kludge to |
treat `best_regend' differently than the rest. So we keep track of |
the end of the best match so far in a separate variable. We |
initialize this to NULL so that when we backtrack the first time |
and need to test it, it's not garbage. */ |
const CHAR_T *match_end = NULL; |
/* This helps SET_REGS_MATCHED avoid doing redundant work. */ |
int set_regs_matched_done = 0; |
/* Used when we pop values we don't care about. */ |
#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */ |
const CHAR_T **reg_dummy; |
PREFIX(register_info_type) *reg_info_dummy; |
#endif |
#ifdef DEBUG |
/* Counts the total number of registers pushed. */ |
unsigned num_regs_pushed = 0; |
#endif |
DEBUG_PRINT1 ("\n\nEntering re_match_2.\n"); |
INIT_FAIL_STACK (); |
#ifdef MATCH_MAY_ALLOCATE |
/* Do not bother to initialize all the register variables if there are |
no groups in the pattern, as it takes a fair amount of time. If |
there are groups, we include space for register 0 (the whole |
pattern), even though we never use it, since it simplifies the |
array indexing. We should fix this. */ |
if (bufp->re_nsub) |
{ |
regstart = REGEX_TALLOC (num_regs, const CHAR_T *); |
regend = REGEX_TALLOC (num_regs, const CHAR_T *); |
old_regstart = REGEX_TALLOC (num_regs, const CHAR_T *); |
old_regend = REGEX_TALLOC (num_regs, const CHAR_T *); |
best_regstart = REGEX_TALLOC (num_regs, const CHAR_T *); |
best_regend = REGEX_TALLOC (num_regs, const CHAR_T *); |
reg_info = REGEX_TALLOC (num_regs, PREFIX(register_info_type)); |
reg_dummy = REGEX_TALLOC (num_regs, const CHAR_T *); |
reg_info_dummy = REGEX_TALLOC (num_regs, PREFIX(register_info_type)); |
if (!(regstart && regend && old_regstart && old_regend && reg_info |
&& best_regstart && best_regend && reg_dummy && reg_info_dummy)) |
{ |
FREE_VARIABLES (); |
return -2; |
} |
} |
else |
{ |
/* We must initialize all our variables to NULL, so that |
`FREE_VARIABLES' doesn't try to free them. */ |
regstart = regend = old_regstart = old_regend = best_regstart |
= best_regend = reg_dummy = NULL; |
reg_info = reg_info_dummy = (PREFIX(register_info_type) *) NULL; |
} |
#endif /* MATCH_MAY_ALLOCATE */ |
/* The starting position is bogus. */ |
#ifdef WCHAR |
if (pos < 0 || pos > csize1 + csize2) |
#else /* BYTE */ |
if (pos < 0 || pos > size1 + size2) |
#endif |
{ |
FREE_VARIABLES (); |
return -1; |
} |
#ifdef WCHAR |
/* Allocate wchar_t array for string1 and string2 and |
fill them with converted string. */ |
if (string1 == NULL && string2 == NULL) |
{ |
/* We need seting up buffers here. */ |
/* We must free wcs buffers in this function. */ |
cant_free_wcs_buf = 0; |
if (csize1 != 0) |
{ |
string1 = REGEX_TALLOC (csize1 + 1, CHAR_T); |
mbs_offset1 = REGEX_TALLOC (csize1 + 1, int); |
is_binary = REGEX_TALLOC (csize1 + 1, char); |
if (!string1 || !mbs_offset1 || !is_binary) |
{ |
FREE_VAR (string1); |
FREE_VAR (mbs_offset1); |
FREE_VAR (is_binary); |
return -2; |
} |
} |
if (csize2 != 0) |
{ |
string2 = REGEX_TALLOC (csize2 + 1, CHAR_T); |
mbs_offset2 = REGEX_TALLOC (csize2 + 1, int); |
is_binary = REGEX_TALLOC (csize2 + 1, char); |
if (!string2 || !mbs_offset2 || !is_binary) |
{ |
FREE_VAR (string1); |
FREE_VAR (mbs_offset1); |
FREE_VAR (string2); |
FREE_VAR (mbs_offset2); |
FREE_VAR (is_binary); |
return -2; |
} |
size2 = convert_mbs_to_wcs(string2, cstring2, csize2, |
mbs_offset2, is_binary); |
string2[size2] = L'\0'; /* for a sentinel */ |
FREE_VAR (is_binary); |
} |
} |
/* We need to cast pattern to (wchar_t*), because we casted this compiled |
pattern to (char*) in regex_compile. */ |
p = pattern = (CHAR_T*)bufp->buffer; |
pend = (CHAR_T*)(bufp->buffer + bufp->used); |
#endif /* WCHAR */ |
/* Initialize subexpression text positions to -1 to mark ones that no |
start_memory/stop_memory has been seen for. Also initialize the |
register information struct. */ |
for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) |
{ |
regstart[mcnt] = regend[mcnt] |
= old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE; |
REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE; |
IS_ACTIVE (reg_info[mcnt]) = 0; |
MATCHED_SOMETHING (reg_info[mcnt]) = 0; |
EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0; |
} |
/* We move `string1' into `string2' if the latter's empty -- but not if |
`string1' is null. */ |
if (size2 == 0 && string1 != NULL) |
{ |
string2 = string1; |
size2 = size1; |
string1 = 0; |
size1 = 0; |
#ifdef WCHAR |
mbs_offset2 = mbs_offset1; |
csize2 = csize1; |
mbs_offset1 = NULL; |
csize1 = 0; |
#endif |
} |
end1 = string1 + size1; |
end2 = string2 + size2; |
/* Compute where to stop matching, within the two strings. */ |
#ifdef WCHAR |
if (stop <= csize1) |
{ |
mcnt = count_mbs_length(mbs_offset1, stop); |
end_match_1 = string1 + mcnt; |
end_match_2 = string2; |
} |
else |
{ |
if (stop > csize1 + csize2) |
stop = csize1 + csize2; |
end_match_1 = end1; |
mcnt = count_mbs_length(mbs_offset2, stop-csize1); |
end_match_2 = string2 + mcnt; |
} |
if (mcnt < 0) |
{ /* count_mbs_length return error. */ |
FREE_VARIABLES (); |
return -1; |
} |
#else |
if (stop <= size1) |
{ |
end_match_1 = string1 + stop; |
end_match_2 = string2; |
} |
else |
{ |
end_match_1 = end1; |
end_match_2 = string2 + stop - size1; |
} |
#endif /* WCHAR */ |
/* `p' scans through the pattern as `d' scans through the data. |
`dend' is the end of the input string that `d' points within. `d' |
is advanced into the following input string whenever necessary, but |
this happens before fetching; therefore, at the beginning of the |
loop, `d' can be pointing at the end of a string, but it cannot |
equal `string2'. */ |
#ifdef WCHAR |
if (size1 > 0 && pos <= csize1) |
{ |
mcnt = count_mbs_length(mbs_offset1, pos); |
d = string1 + mcnt; |
dend = end_match_1; |
} |
else |
{ |
mcnt = count_mbs_length(mbs_offset2, pos-csize1); |
d = string2 + mcnt; |
dend = end_match_2; |
} |
if (mcnt < 0) |
{ /* count_mbs_length return error. */ |
FREE_VARIABLES (); |
return -1; |
} |
#else |
if (size1 > 0 && pos <= size1) |
{ |
d = string1 + pos; |
dend = end_match_1; |
} |
else |
{ |
d = string2 + pos - size1; |
dend = end_match_2; |
} |
#endif /* WCHAR */ |
DEBUG_PRINT1 ("The compiled pattern is:\n"); |
DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend); |
DEBUG_PRINT1 ("The string to match is: `"); |
DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2); |
DEBUG_PRINT1 ("'\n"); |
/* This loops over pattern commands. It exits by returning from the |
function if the match is complete, or it drops through if the match |
fails at this starting point in the input data. */ |
for (;;) |
{ |
#ifdef _LIBC |
DEBUG_PRINT2 ("\n%p: ", p); |
#else |
DEBUG_PRINT2 ("\n0x%x: ", p); |
#endif |
if (p == pend) |
{ /* End of pattern means we might have succeeded. */ |
DEBUG_PRINT1 ("end of pattern ... "); |
/* If we haven't matched the entire string, and we want the |
longest match, try backtracking. */ |
if (d != end_match_2) |
{ |
/* 1 if this match ends in the same string (string1 or string2) |
as the best previous match. */ |
boolean same_str_p; |
/* 1 if this match is the best seen so far. */ |
boolean best_match_p; |
same_str_p = (FIRST_STRING_P (match_end) |
== MATCHING_IN_FIRST_STRING); |
/* AIX compiler got confused when this was combined |
with the previous declaration. */ |
if (same_str_p) |
best_match_p = d > match_end; |
else |
best_match_p = !MATCHING_IN_FIRST_STRING; |
DEBUG_PRINT1 ("backtracking.\n"); |
if (!FAIL_STACK_EMPTY ()) |
{ /* More failure points to try. */ |
/* If exceeds best match so far, save it. */ |
if (!best_regs_set || best_match_p) |
{ |
best_regs_set = true; |
match_end = d; |
DEBUG_PRINT1 ("\nSAVING match as best so far.\n"); |
for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) |
{ |
best_regstart[mcnt] = regstart[mcnt]; |
best_regend[mcnt] = regend[mcnt]; |
} |
} |
goto fail; |
} |
/* If no failure points, don't restore garbage. And if |
last match is real best match, don't restore second |
best one. */ |
else if (best_regs_set && !best_match_p) |
{ |
restore_best_regs: |
/* Restore best match. It may happen that `dend == |
end_match_1' while the restored d is in string2. |
For example, the pattern `x.*y.*z' against the |
strings `x-' and `y-z-', if the two strings are |
not consecutive in memory. */ |
DEBUG_PRINT1 ("Restoring best registers.\n"); |
d = match_end; |
dend = ((d >= string1 && d <= end1) |
? end_match_1 : end_match_2); |
for (mcnt = 1; (unsigned) mcnt < num_regs; mcnt++) |
{ |
regstart[mcnt] = best_regstart[mcnt]; |
regend[mcnt] = best_regend[mcnt]; |
} |
} |
} /* d != end_match_2 */ |
succeed_label: |
DEBUG_PRINT1 ("Accepting match.\n"); |
/* If caller wants register contents data back, do it. */ |
if (regs && !bufp->no_sub) |
{ |
/* Have the register data arrays been allocated? */ |
if (bufp->regs_allocated == REGS_UNALLOCATED) |
{ /* No. So allocate them with malloc. We need one |
extra element beyond `num_regs' for the `-1' marker |
GNU code uses. */ |
regs->num_regs = MAX (RE_NREGS, num_regs + 1); |
regs->start = TALLOC (regs->num_regs, regoff_t); |
regs->end = TALLOC (regs->num_regs, regoff_t); |
if (regs->start == NULL || regs->end == NULL) |
{ |
FREE_VARIABLES (); |
return -2; |
} |
bufp->regs_allocated = REGS_REALLOCATE; |
} |
else if (bufp->regs_allocated == REGS_REALLOCATE) |
{ /* Yes. If we need more elements than were already |
allocated, reallocate them. If we need fewer, just |
leave it alone. */ |
if (regs->num_regs < num_regs + 1) |
{ |
regs->num_regs = num_regs + 1; |
RETALLOC (regs->start, regs->num_regs, regoff_t); |
RETALLOC (regs->end, regs->num_regs, regoff_t); |
if (regs->start == NULL || regs->end == NULL) |
{ |
FREE_VARIABLES (); |
return -2; |
} |
} |
} |
else |
{ |
/* These braces fend off a "empty body in an else-statement" |
warning under GCC when assert expands to nothing. */ |
assert (bufp->regs_allocated == REGS_FIXED); |
} |
/* Convert the pointer data in `regstart' and `regend' to |
indices. Register zero has to be set differently, |
since we haven't kept track of any info for it. */ |
if (regs->num_regs > 0) |
{ |
regs->start[0] = pos; |
#ifdef WCHAR |
if (MATCHING_IN_FIRST_STRING) |
regs->end[0] = mbs_offset1 != NULL ? |
mbs_offset1[d-string1] : 0; |
else |
regs->end[0] = csize1 + (mbs_offset2 != NULL ? |
mbs_offset2[d-string2] : 0); |
#else |
regs->end[0] = (MATCHING_IN_FIRST_STRING |
? ((regoff_t) (d - string1)) |
: ((regoff_t) (d - string2 + size1))); |
#endif /* WCHAR */ |
} |
/* Go through the first `min (num_regs, regs->num_regs)' |
registers, since that is all we initialized. */ |
for (mcnt = 1; (unsigned) mcnt < MIN (num_regs, regs->num_regs); |
mcnt++) |
{ |
if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt])) |
regs->start[mcnt] = regs->end[mcnt] = -1; |
else |
{ |
regs->start[mcnt] |
= (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]); |
regs->end[mcnt] |
= (regoff_t) POINTER_TO_OFFSET (regend[mcnt]); |
} |
} |
/* If the regs structure we return has more elements than |
were in the pattern, set the extra elements to -1. If |
we (re)allocated the registers, this is the case, |
because we always allocate enough to have at least one |
-1 at the end. */ |
for (mcnt = num_regs; (unsigned) mcnt < regs->num_regs; mcnt++) |
regs->start[mcnt] = regs->end[mcnt] = -1; |
} /* regs && !bufp->no_sub */ |
DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n", |
nfailure_points_pushed, nfailure_points_popped, |
nfailure_points_pushed - nfailure_points_popped); |
DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed); |
#ifdef WCHAR |
if (MATCHING_IN_FIRST_STRING) |
mcnt = mbs_offset1 != NULL ? mbs_offset1[d-string1] : 0; |
else |
mcnt = (mbs_offset2 != NULL ? mbs_offset2[d-string2] : 0) + |
csize1; |
mcnt -= pos; |
#else |
mcnt = d - pos - (MATCHING_IN_FIRST_STRING |
? string1 |
: string2 - size1); |
#endif /* WCHAR */ |
DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt); |
FREE_VARIABLES (); |
return mcnt; |
} |
/* Otherwise match next pattern command. */ |
switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++)) |
{ |
/* Ignore these. Used to ignore the n of succeed_n's which |
currently have n == 0. */ |
case no_op: |
DEBUG_PRINT1 ("EXECUTING no_op.\n"); |
break; |
case succeed: |
DEBUG_PRINT1 ("EXECUTING succeed.\n"); |
goto succeed_label; |
/* Match the next n pattern characters exactly. The following |
byte in the pattern defines n, and the n bytes after that |
are the characters to match. */ |
case exactn: |
#ifdef MBS_SUPPORT |
case exactn_bin: |
#endif |
mcnt = *p++; |
DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt); |
/* This is written out as an if-else so we don't waste time |
testing `translate' inside the loop. */ |
if (translate) |
{ |
do |
{ |
PREFETCH (); |
#ifdef WCHAR |
if (*d <= 0xff) |
{ |
if ((UCHAR_T) translate[(unsigned char) *d++] |
!= (UCHAR_T) *p++) |
goto fail; |
} |
else |
{ |
if (*d++ != (CHAR_T) *p++) |
goto fail; |
} |
#else |
if ((UCHAR_T) translate[(unsigned char) *d++] |
!= (UCHAR_T) *p++) |
goto fail; |
#endif /* WCHAR */ |
} |
while (--mcnt); |
} |
else |
{ |
do |
{ |
PREFETCH (); |
if (*d++ != (CHAR_T) *p++) goto fail; |
} |
while (--mcnt); |
} |
SET_REGS_MATCHED (); |
break; |
/* Match any character except possibly a newline or a null. */ |
case anychar: |
DEBUG_PRINT1 ("EXECUTING anychar.\n"); |
PREFETCH (); |
if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n') |
|| (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000')) |
goto fail; |
SET_REGS_MATCHED (); |
DEBUG_PRINT2 (" Matched `%ld'.\n", (long int) *d); |
d++; |
break; |
case charset: |
case charset_not: |
{ |
register UCHAR_T c; |
#ifdef WCHAR |
unsigned int i, char_class_length, coll_symbol_length, |
equiv_class_length, ranges_length, chars_length, length; |
CHAR_T *workp, *workp2, *charset_top; |
#define WORK_BUFFER_SIZE 128 |
CHAR_T str_buf[WORK_BUFFER_SIZE]; |
# ifdef _LIBC |
uint32_t nrules; |
# endif /* _LIBC */ |
#endif /* WCHAR */ |
boolean negate = (re_opcode_t) *(p - 1) == charset_not; |
DEBUG_PRINT2 ("EXECUTING charset%s.\n", negate ? "_not" : ""); |
PREFETCH (); |
c = TRANSLATE (*d); /* The character to match. */ |
#ifdef WCHAR |
# ifdef _LIBC |
nrules = _NL_CURRENT_WORD (LC_COLLATE, _NL_COLLATE_NRULES); |
# endif /* _LIBC */ |
charset_top = p - 1; |
char_class_length = *p++; |
coll_symbol_length = *p++; |
equiv_class_length = *p++; |
ranges_length = *p++; |
chars_length = *p++; |
/* p points charset[6], so the address of the next instruction |
(charset[l+m+n+2o+k+p']) equals p[l+m+n+2*o+p'], |
where l=length of char_classes, m=length of collating_symbol, |
n=equivalence_class, o=length of char_range, |
p'=length of character. */ |
workp = p; |
/* Update p to indicate the next instruction. */ |
p += char_class_length + coll_symbol_length+ equiv_class_length + |
2*ranges_length + chars_length; |
/* match with char_class? */ |
for (i = 0; i < char_class_length ; i += CHAR_CLASS_SIZE) |
{ |
wctype_t wctype; |
uintptr_t alignedp = ((uintptr_t)workp |
+ __alignof__(wctype_t) - 1) |
& ~(uintptr_t)(__alignof__(wctype_t) - 1); |
wctype = *((wctype_t*)alignedp); |
workp += CHAR_CLASS_SIZE; |
# ifdef _LIBC |
if (__iswctype((wint_t)c, wctype)) |
goto char_set_matched; |
# else |
if (iswctype((wint_t)c, wctype)) |
goto char_set_matched; |
# endif |
} |
/* match with collating_symbol? */ |
# ifdef _LIBC |
if (nrules != 0) |
{ |
const unsigned char *extra = (const unsigned char *) |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_SYMB_EXTRAMB); |
for (workp2 = workp + coll_symbol_length ; workp < workp2 ; |
workp++) |
{ |
int32_t *wextra; |
wextra = (int32_t*)(extra + *workp++); |
for (i = 0; i < *wextra; ++i) |
if (TRANSLATE(d[i]) != wextra[1 + i]) |
break; |
if (i == *wextra) |
{ |
/* Update d, however d will be incremented at |
char_set_matched:, we decrement d here. */ |
d += i - 1; |
goto char_set_matched; |
} |
} |
} |
else /* (nrules == 0) */ |
# endif |
/* If we can't look up collation data, we use wcscoll |
instead. */ |
{ |
for (workp2 = workp + coll_symbol_length ; workp < workp2 ;) |
{ |
const CHAR_T *backup_d = d, *backup_dend = dend; |
# ifdef _LIBC |
length = __wcslen (workp); |
# else |
length = wcslen (workp); |
# endif |
/* If wcscoll(the collating symbol, whole string) > 0, |
any substring of the string never match with the |
collating symbol. */ |
# ifdef _LIBC |
if (__wcscoll (workp, d) > 0) |
# else |
if (wcscoll (workp, d) > 0) |
# endif |
{ |
workp += length + 1; |
continue; |
} |
/* First, we compare the collating symbol with |
the first character of the string. |
If it don't match, we add the next character to |
the compare buffer in turn. */ |
for (i = 0 ; i < WORK_BUFFER_SIZE-1 ; i++, d++) |
{ |
int match; |
if (d == dend) |
{ |
if (dend == end_match_2) |
break; |
d = string2; |
dend = end_match_2; |
} |
/* add next character to the compare buffer. */ |
str_buf[i] = TRANSLATE(*d); |
str_buf[i+1] = '\0'; |
# ifdef _LIBC |
match = __wcscoll (workp, str_buf); |
# else |
match = wcscoll (workp, str_buf); |
# endif |
if (match == 0) |
goto char_set_matched; |
if (match < 0) |
/* (str_buf > workp) indicate (str_buf + X > workp), |
because for all X (str_buf + X > str_buf). |
So we don't need continue this loop. */ |
break; |
/* Otherwise(str_buf < workp), |
(str_buf+next_character) may equals (workp). |
So we continue this loop. */ |
} |
/* not matched */ |
d = backup_d; |
dend = backup_dend; |
workp += length + 1; |
} |
} |
/* match with equivalence_class? */ |
# ifdef _LIBC |
if (nrules != 0) |
{ |
const CHAR_T *backup_d = d, *backup_dend = dend; |
/* Try to match the equivalence class against |
those known to the collate implementation. */ |
const int32_t *table; |
const int32_t *weights; |
const int32_t *extra; |
const int32_t *indirect; |
int32_t idx, idx2; |
wint_t *cp; |
size_t len; |
/* This #include defines a local function! */ |
# include <locale/weightwc.h> |
table = (const int32_t *) |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_TABLEWC); |
weights = (const wint_t *) |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_WEIGHTWC); |
extra = (const wint_t *) |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_EXTRAWC); |
indirect = (const int32_t *) |
_NL_CURRENT (LC_COLLATE, _NL_COLLATE_INDIRECTWC); |
/* Write 1 collating element to str_buf, and |
get its index. */ |
idx2 = 0; |
for (i = 0 ; idx2 == 0 && i < WORK_BUFFER_SIZE - 1; i++) |
{ |
cp = (wint_t*)str_buf; |
if (d == dend) |
{ |
if (dend == end_match_2) |
break; |
d = string2; |
dend = end_match_2; |
} |
str_buf[i] = TRANSLATE(*(d+i)); |
str_buf[i+1] = '\0'; /* sentinel */ |
idx2 = findidx ((const wint_t**)&cp); |
} |
/* Update d, however d will be incremented at |
char_set_matched:, we decrement d here. */ |
d = backup_d + ((wchar_t*)cp - (wchar_t*)str_buf - 1); |
if (d >= dend) |
{ |
if (dend == end_match_2) |
d = dend; |
else |
{ |
d = string2; |
dend = end_match_2; |
} |
} |
len = weights[idx2]; |
for (workp2 = workp + equiv_class_length ; workp < workp2 ; |
workp++) |
{ |
idx = (int32_t)*workp; |
/* We already checked idx != 0 in regex_compile. */ |
if (idx2 != 0 && len == weights[idx]) |
{ |
int cnt = 0; |
while (cnt < len && (weights[idx + 1 + cnt] |
== weights[idx2 + 1 + cnt])) |
++cnt; |
if (cnt == len) |
goto char_set_matched; |
} |
} |
/* not matched */ |
d = backup_d; |
dend = backup_dend; |
} |
else /* (nrules == 0) */ |
# endif |
/* If we can't look up collation data, we use wcscoll |
instead. */ |
{ |
for (workp2 = workp + equiv_class_length ; workp < workp2 ;) |
{ |
const CHAR_T *backup_d = d, *backup_dend = dend; |
# ifdef _LIBC |
length = __wcslen (workp); |
# else |
length = wcslen (workp); |
# endif |
/* If wcscoll(the collating symbol, whole string) > 0, |
any substring of the string never match with the |
collating symbol. */ |
# ifdef _LIBC |
if (__wcscoll (workp, d) > 0) |
# else |
if (wcscoll (workp, d) > 0) |
# endif |
{ |
workp += length + 1; |
break; |
} |
/* First, we compare the equivalence class with |
the first character of the string. |
If it don't match, we add the next character to |
the compare buffer in turn. */ |
for (i = 0 ; i < WORK_BUFFER_SIZE - 1 ; i++, d++) |
{ |
int match; |
if (d == dend) |
{ |
if (dend == end_match_2) |
break; |
d = string2; |
dend = end_match_2; |
} |
/* add next character to the compare buffer. */ |
str_buf[i] = TRANSLATE(*d); |
str_buf[i+1] = '\0'; |
# ifdef _LIBC |
match = __wcscoll (workp, str_buf); |
# else |
match = wcscoll (workp, str_buf); |
# endif |
if (match == 0) |
goto char_set_matched; |
if (match < 0) |
/* (str_buf > workp) indicate (str_buf + X > workp), |
because for all X (str_buf + X > str_buf). |
So we don't need continue this loop. */ |
break; |
/* Otherwise(str_buf < workp), |
(str_buf+next_character) may equals (workp). |
So we continue this loop. */ |
} |
/* not matched */ |
d = backup_d; |
dend = backup_dend; |
workp += length + 1; |
} |
} |
/* match with char_range? */ |
# ifdef _LIBC |
if (nrules != 0) |
{ |
uint32_t collseqval; |
const char *collseq = (const char *) |
_NL_CURRENT(LC_COLLATE, _NL_COLLATE_COLLSEQWC); |
collseqval = collseq_table_lookup (collseq, c); |
for (; workp < p - chars_length ;) |
{ |
uint32_t start_val, end_val; |
/* We already compute the collation sequence value |
of the characters (or collating symbols). */ |
start_val = (uint32_t) *workp++; /* range_start */ |
end_val = (uint32_t) *workp++; /* range_end */ |
if (start_val <= collseqval && collseqval <= end_val) |
goto char_set_matched; |
} |
} |
else |
# endif |
{ |
/* We set range_start_char at str_buf[0], range_end_char |
at str_buf[4], and compared char at str_buf[2]. */ |
str_buf[1] = 0; |
str_buf[2] = c; |
str_buf[3] = 0; |
str_buf[5] = 0; |
for (; workp < p - chars_length ;) |
{ |
wchar_t *range_start_char, *range_end_char; |
/* match if (range_start_char <= c <= range_end_char). */ |
/* If range_start(or end) < 0, we assume -range_start(end) |
is the offset of the collating symbol which is specified |
as the character of the range start(end). */ |
/* range_start */ |
if (*workp < 0) |
range_start_char = charset_top - (*workp++); |
else |
{ |
str_buf[0] = *workp++; |
range_start_char = str_buf; |
} |
/* range_end */ |
if (*workp < 0) |
range_end_char = charset_top - (*workp++); |
else |
{ |
str_buf[4] = *workp++; |
range_end_char = str_buf + 4; |
} |
# ifdef _LIBC |
if (__wcscoll (range_start_char, str_buf+2) <= 0 |
&& __wcscoll (str_buf+2, range_end_char) <= 0) |
# else |
if (wcscoll (range_start_char, str_buf+2) <= 0 |
&& wcscoll (str_buf+2, range_end_char) <= 0) |
# endif |
goto char_set_matched; |
} |
} |
/* match with char? */ |
for (; workp < p ; workp++) |
if (c == *workp) |
goto char_set_matched; |
negate = !negate; |
char_set_matched: |
if (negate) goto fail; |
#else |
/* Cast to `unsigned' instead of `unsigned char' in case the |
bit list is a full 32 bytes long. */ |
if (c < (unsigned) (*p * BYTEWIDTH) |
&& p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) |
negate = !negate; |
p += 1 + *p; |
if (!negate) goto fail; |
#undef WORK_BUFFER_SIZE |
#endif /* WCHAR */ |
SET_REGS_MATCHED (); |
d++; |
break; |
} |
/* The beginning of a group is represented by start_memory. |
The arguments are the register number in the next byte, and the |
number of groups inner to this one in the next. The text |
matched within the group is recorded (in the internal |
registers data structure) under the register number. */ |
case start_memory: |
DEBUG_PRINT3 ("EXECUTING start_memory %ld (%ld):\n", |
(long int) *p, (long int) p[1]); |
/* Find out if this group can match the empty string. */ |
p1 = p; /* To send to group_match_null_string_p. */ |
if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE) |
REG_MATCH_NULL_STRING_P (reg_info[*p]) |
= PREFIX(group_match_null_string_p) (&p1, pend, reg_info); |
/* Save the position in the string where we were the last time |
we were at this open-group operator in case the group is |
operated upon by a repetition operator, e.g., with `(a*)*b' |
against `ab'; then we want to ignore where we are now in |
the string in case this attempt to match fails. */ |
old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) |
? REG_UNSET (regstart[*p]) ? d : regstart[*p] |
: regstart[*p]; |
DEBUG_PRINT2 (" old_regstart: %d\n", |
POINTER_TO_OFFSET (old_regstart[*p])); |
regstart[*p] = d; |
DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p])); |
IS_ACTIVE (reg_info[*p]) = 1; |
MATCHED_SOMETHING (reg_info[*p]) = 0; |
/* Clear this whenever we change the register activity status. */ |
set_regs_matched_done = 0; |
/* This is the new highest active register. */ |
highest_active_reg = *p; |
/* If nothing was active before, this is the new lowest active |
register. */ |
if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) |
lowest_active_reg = *p; |
/* Move past the register number and inner group count. */ |
p += 2; |
just_past_start_mem = p; |
break; |
/* The stop_memory opcode represents the end of a group. Its |
arguments are the same as start_memory's: the register |
number, and the number of inner groups. */ |
case stop_memory: |
DEBUG_PRINT3 ("EXECUTING stop_memory %ld (%ld):\n", |
(long int) *p, (long int) p[1]); |
/* We need to save the string position the last time we were at |
this close-group operator in case the group is operated |
upon by a repetition operator, e.g., with `((a*)*(b*)*)*' |
against `aba'; then we want to ignore where we are now in |
the string in case this attempt to match fails. */ |
old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p]) |
? REG_UNSET (regend[*p]) ? d : regend[*p] |
: regend[*p]; |
DEBUG_PRINT2 (" old_regend: %d\n", |
POINTER_TO_OFFSET (old_regend[*p])); |
regend[*p] = d; |
DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p])); |
/* This register isn't active anymore. */ |
IS_ACTIVE (reg_info[*p]) = 0; |
/* Clear this whenever we change the register activity status. */ |
set_regs_matched_done = 0; |
/* If this was the only register active, nothing is active |
anymore. */ |
if (lowest_active_reg == highest_active_reg) |
{ |
lowest_active_reg = NO_LOWEST_ACTIVE_REG; |
highest_active_reg = NO_HIGHEST_ACTIVE_REG; |
} |
else |
{ /* We must scan for the new highest active register, since |
it isn't necessarily one less than now: consider |
(a(b)c(d(e)f)g). When group 3 ends, after the f), the |
new highest active register is 1. */ |
UCHAR_T r = *p - 1; |
while (r > 0 && !IS_ACTIVE (reg_info[r])) |
r--; |
/* If we end up at register zero, that means that we saved |
the registers as the result of an `on_failure_jump', not |
a `start_memory', and we jumped to past the innermost |
`stop_memory'. For example, in ((.)*) we save |
registers 1 and 2 as a result of the *, but when we pop |
back to the second ), we are at the stop_memory 1. |
Thus, nothing is active. */ |
if (r == 0) |
{ |
lowest_active_reg = NO_LOWEST_ACTIVE_REG; |
highest_active_reg = NO_HIGHEST_ACTIVE_REG; |
} |
else |
highest_active_reg = r; |
} |
/* If just failed to match something this time around with a |
group that's operated on by a repetition operator, try to |
force exit from the ``loop'', and restore the register |
information for this group that we had before trying this |
last match. */ |
if ((!MATCHED_SOMETHING (reg_info[*p]) |
|| just_past_start_mem == p - 1) |
&& (p + 2) < pend) |
{ |
boolean is_a_jump_n = false; |
p1 = p + 2; |
mcnt = 0; |
switch ((re_opcode_t) *p1++) |
{ |
case jump_n: |
is_a_jump_n = true; |
case pop_failure_jump: |
case maybe_pop_jump: |
case jump: |
case dummy_failure_jump: |
EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
if (is_a_jump_n) |
p1 += OFFSET_ADDRESS_SIZE; |
break; |
default: |
/* do nothing */ ; |
} |
p1 += mcnt; |
/* If the next operation is a jump backwards in the pattern |
to an on_failure_jump right before the start_memory |
corresponding to this stop_memory, exit from the loop |
by forcing a failure after pushing on the stack the |
on_failure_jump's jump in the pattern, and d. */ |
if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump |
&& (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == start_memory |
&& p1[2+OFFSET_ADDRESS_SIZE] == *p) |
{ |
/* If this group ever matched anything, then restore |
what its registers were before trying this last |
failed match, e.g., with `(a*)*b' against `ab' for |
regstart[1], and, e.g., with `((a*)*(b*)*)*' |
against `aba' for regend[3]. |
Also restore the registers for inner groups for, |
e.g., `((a*)(b*))*' against `aba' (register 3 would |
otherwise get trashed). */ |
if (EVER_MATCHED_SOMETHING (reg_info[*p])) |
{ |
unsigned r; |
EVER_MATCHED_SOMETHING (reg_info[*p]) = 0; |
/* Restore this and inner groups' (if any) registers. */ |
for (r = *p; r < (unsigned) *p + (unsigned) *(p + 1); |
r++) |
{ |
regstart[r] = old_regstart[r]; |
/* xx why this test? */ |
if (old_regend[r] >= regstart[r]) |
regend[r] = old_regend[r]; |
} |
} |
p1++; |
EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
PUSH_FAILURE_POINT (p1 + mcnt, d, -2); |
goto fail; |
} |
} |
/* Move past the register number and the inner group count. */ |
p += 2; |
break; |
/* \<digit> has been turned into a `duplicate' command which is |
followed by the numeric value of <digit> as the register number. */ |
case duplicate: |
{ |
register const CHAR_T *d2, *dend2; |
int regno = *p++; /* Get which register to match against. */ |
DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno); |
/* Can't back reference a group which we've never matched. */ |
if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno])) |
goto fail; |
/* Where in input to try to start matching. */ |
d2 = regstart[regno]; |
/* Where to stop matching; if both the place to start and |
the place to stop matching are in the same string, then |
set to the place to stop, otherwise, for now have to use |
the end of the first string. */ |
dend2 = ((FIRST_STRING_P (regstart[regno]) |
== FIRST_STRING_P (regend[regno])) |
? regend[regno] : end_match_1); |
for (;;) |
{ |
/* If necessary, advance to next segment in register |
contents. */ |
while (d2 == dend2) |
{ |
if (dend2 == end_match_2) break; |
if (dend2 == regend[regno]) break; |
/* End of string1 => advance to string2. */ |
d2 = string2; |
dend2 = regend[regno]; |
} |
/* At end of register contents => success */ |
if (d2 == dend2) break; |
/* If necessary, advance to next segment in data. */ |
PREFETCH (); |
/* How many characters left in this segment to match. */ |
mcnt = dend - d; |
/* Want how many consecutive characters we can match in |
one shot, so, if necessary, adjust the count. */ |
if (mcnt > dend2 - d2) |
mcnt = dend2 - d2; |
/* Compare that many; failure if mismatch, else move |
past them. */ |
if (translate |
? PREFIX(bcmp_translate) (d, d2, mcnt, translate) |
: memcmp (d, d2, mcnt*sizeof(UCHAR_T))) |
goto fail; |
d += mcnt, d2 += mcnt; |
/* Do this because we've match some characters. */ |
SET_REGS_MATCHED (); |
} |
} |
break; |
/* begline matches the empty string at the beginning of the string |
(unless `not_bol' is set in `bufp'), and, if |
`newline_anchor' is set, after newlines. */ |
case begline: |
DEBUG_PRINT1 ("EXECUTING begline.\n"); |
if (AT_STRINGS_BEG (d)) |
{ |
if (!bufp->not_bol) break; |
} |
else if (d[-1] == '\n' && bufp->newline_anchor) |
{ |
break; |
} |
/* In all other cases, we fail. */ |
goto fail; |
/* endline is the dual of begline. */ |
case endline: |
DEBUG_PRINT1 ("EXECUTING endline.\n"); |
if (AT_STRINGS_END (d)) |
{ |
if (!bufp->not_eol) break; |
} |
/* We have to ``prefetch'' the next character. */ |
else if ((d == end1 ? *string2 : *d) == '\n' |
&& bufp->newline_anchor) |
{ |
break; |
} |
goto fail; |
/* Match at the very beginning of the data. */ |
case begbuf: |
DEBUG_PRINT1 ("EXECUTING begbuf.\n"); |
if (AT_STRINGS_BEG (d)) |
break; |
goto fail; |
/* Match at the very end of the data. */ |
case endbuf: |
DEBUG_PRINT1 ("EXECUTING endbuf.\n"); |
if (AT_STRINGS_END (d)) |
break; |
goto fail; |
/* on_failure_keep_string_jump is used to optimize `.*\n'. It |
pushes NULL as the value for the string on the stack. Then |
`pop_failure_point' will keep the current value for the |
string, instead of restoring it. To see why, consider |
matching `foo\nbar' against `.*\n'. The .* matches the foo; |
then the . fails against the \n. But the next thing we want |
to do is match the \n against the \n; if we restored the |
string value, we would be back at the foo. |
Because this is used only in specific cases, we don't need to |
check all the things that `on_failure_jump' does, to make |
sure the right things get saved on the stack. Hence we don't |
share its code. The only reason to push anything on the |
stack at all is that otherwise we would have to change |
`anychar's code to do something besides goto fail in this |
case; that seems worse than this. */ |
case on_failure_keep_string_jump: |
DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump"); |
EXTRACT_NUMBER_AND_INCR (mcnt, p); |
#ifdef _LIBC |
DEBUG_PRINT3 (" %d (to %p):\n", mcnt, p + mcnt); |
#else |
DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt); |
#endif |
PUSH_FAILURE_POINT (p + mcnt, NULL, -2); |
break; |
/* Uses of on_failure_jump: |
Each alternative starts with an on_failure_jump that points |
to the beginning of the next alternative. Each alternative |
except the last ends with a jump that in effect jumps past |
the rest of the alternatives. (They really jump to the |
ending jump of the following alternative, because tensioning |
these jumps is a hassle.) |
Repeats start with an on_failure_jump that points past both |
the repetition text and either the following jump or |
pop_failure_jump back to this on_failure_jump. */ |
case on_failure_jump: |
on_failure: |
DEBUG_PRINT1 ("EXECUTING on_failure_jump"); |
EXTRACT_NUMBER_AND_INCR (mcnt, p); |
#ifdef _LIBC |
DEBUG_PRINT3 (" %d (to %p)", mcnt, p + mcnt); |
#else |
DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt); |
#endif |
/* If this on_failure_jump comes right before a group (i.e., |
the original * applied to a group), save the information |
for that group and all inner ones, so that if we fail back |
to this point, the group's information will be correct. |
For example, in \(a*\)*\1, we need the preceding group, |
and in \(zz\(a*\)b*\)\2, we need the inner group. */ |
/* We can't use `p' to check ahead because we push |
a failure point to `p + mcnt' after we do this. */ |
p1 = p; |
/* We need to skip no_op's before we look for the |
start_memory in case this on_failure_jump is happening as |
the result of a completed succeed_n, as in \(a\)\{1,3\}b\1 |
against aba. */ |
while (p1 < pend && (re_opcode_t) *p1 == no_op) |
p1++; |
if (p1 < pend && (re_opcode_t) *p1 == start_memory) |
{ |
/* We have a new highest active register now. This will |
get reset at the start_memory we are about to get to, |
but we will have saved all the registers relevant to |
this repetition op, as described above. */ |
highest_active_reg = *(p1 + 1) + *(p1 + 2); |
if (lowest_active_reg == NO_LOWEST_ACTIVE_REG) |
lowest_active_reg = *(p1 + 1); |
} |
DEBUG_PRINT1 (":\n"); |
PUSH_FAILURE_POINT (p + mcnt, d, -2); |
break; |
/* A smart repeat ends with `maybe_pop_jump'. |
We change it to either `pop_failure_jump' or `jump'. */ |
case maybe_pop_jump: |
EXTRACT_NUMBER_AND_INCR (mcnt, p); |
DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt); |
{ |
register UCHAR_T *p2 = p; |
/* Compare the beginning of the repeat with what in the |
pattern follows its end. If we can establish that there |
is nothing that they would both match, i.e., that we |
would have to backtrack because of (as in, e.g., `a*a') |
then we can change to pop_failure_jump, because we'll |
never have to backtrack. |
This is not true in the case of alternatives: in |
`(a|ab)*' we do need to backtrack to the `ab' alternative |
(e.g., if the string was `ab'). But instead of trying to |
detect that here, the alternative has put on a dummy |
failure point which is what we will end up popping. */ |
/* Skip over open/close-group commands. |
If what follows this loop is a ...+ construct, |
look at what begins its body, since we will have to |
match at least one of that. */ |
while (1) |
{ |
if (p2 + 2 < pend |
&& ((re_opcode_t) *p2 == stop_memory |
|| (re_opcode_t) *p2 == start_memory)) |
p2 += 3; |
else if (p2 + 2 + 2 * OFFSET_ADDRESS_SIZE < pend |
&& (re_opcode_t) *p2 == dummy_failure_jump) |
p2 += 2 + 2 * OFFSET_ADDRESS_SIZE; |
else |
break; |
} |
p1 = p + mcnt; |
/* p1[0] ... p1[2] are the `on_failure_jump' corresponding |
to the `maybe_finalize_jump' of this case. Examine what |
follows. */ |
/* If we're at the end of the pattern, we can change. */ |
if (p2 == pend) |
{ |
/* Consider what happens when matching ":\(.*\)" |
against ":/". I don't really understand this code |
yet. */ |
p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T) |
pop_failure_jump; |
DEBUG_PRINT1 |
(" End of pattern: change to `pop_failure_jump'.\n"); |
} |
else if ((re_opcode_t) *p2 == exactn |
#ifdef MBS_SUPPORT |
|| (re_opcode_t) *p2 == exactn_bin |
#endif |
|| (bufp->newline_anchor && (re_opcode_t) *p2 == endline)) |
{ |
register UCHAR_T c |
= *p2 == (UCHAR_T) endline ? '\n' : p2[2]; |
if (((re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn |
#ifdef MBS_SUPPORT |
|| (re_opcode_t) p1[1+OFFSET_ADDRESS_SIZE] == exactn_bin |
#endif |
) && p1[3+OFFSET_ADDRESS_SIZE] != c) |
{ |
p[-(1+OFFSET_ADDRESS_SIZE)] = (UCHAR_T) |
pop_failure_jump; |
#ifdef WCHAR |
DEBUG_PRINT3 (" %C != %C => pop_failure_jump.\n", |
(wint_t) c, |
(wint_t) p1[3+OFFSET_ADDRESS_SIZE]); |
#else |
DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n", |
(char) c, |
(char) p1[3+OFFSET_ADDRESS_SIZE]); |
#endif |
} |
#ifndef WCHAR |
else if ((re_opcode_t) p1[3] == charset |
|| (re_opcode_t) p1[3] == charset_not) |
{ |
int negate = (re_opcode_t) p1[3] == charset_not; |
if (c < (unsigned) (p1[4] * BYTEWIDTH) |
&& p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH))) |
negate = !negate; |
/* `negate' is equal to 1 if c would match, which means |
that we can't change to pop_failure_jump. */ |
if (!negate) |
{ |
p[-3] = (unsigned char) pop_failure_jump; |
DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); |
} |
} |
#endif /* not WCHAR */ |
} |
#ifndef WCHAR |
else if ((re_opcode_t) *p2 == charset) |
{ |
/* We win if the first character of the loop is not part |
of the charset. */ |
if ((re_opcode_t) p1[3] == exactn |
&& ! ((int) p2[1] * BYTEWIDTH > (int) p1[5] |
&& (p2[2 + p1[5] / BYTEWIDTH] |
& (1 << (p1[5] % BYTEWIDTH))))) |
{ |
p[-3] = (unsigned char) pop_failure_jump; |
DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); |
} |
else if ((re_opcode_t) p1[3] == charset_not) |
{ |
int idx; |
/* We win if the charset_not inside the loop |
lists every character listed in the charset after. */ |
for (idx = 0; idx < (int) p2[1]; idx++) |
if (! (p2[2 + idx] == 0 |
|| (idx < (int) p1[4] |
&& ((p2[2 + idx] & ~ p1[5 + idx]) == 0)))) |
break; |
if (idx == p2[1]) |
{ |
p[-3] = (unsigned char) pop_failure_jump; |
DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); |
} |
} |
else if ((re_opcode_t) p1[3] == charset) |
{ |
int idx; |
/* We win if the charset inside the loop |
has no overlap with the one after the loop. */ |
for (idx = 0; |
idx < (int) p2[1] && idx < (int) p1[4]; |
idx++) |
if ((p2[2 + idx] & p1[5 + idx]) != 0) |
break; |
if (idx == p2[1] || idx == p1[4]) |
{ |
p[-3] = (unsigned char) pop_failure_jump; |
DEBUG_PRINT1 (" No match => pop_failure_jump.\n"); |
} |
} |
} |
#endif /* not WCHAR */ |
} |
p -= OFFSET_ADDRESS_SIZE; /* Point at relative address again. */ |
if ((re_opcode_t) p[-1] != pop_failure_jump) |
{ |
p[-1] = (UCHAR_T) jump; |
DEBUG_PRINT1 (" Match => jump.\n"); |
goto unconditional_jump; |
} |
/* Note fall through. */ |
/* The end of a simple repeat has a pop_failure_jump back to |
its matching on_failure_jump, where the latter will push a |
failure point. The pop_failure_jump takes off failure |
points put on by this pop_failure_jump's matching |
on_failure_jump; we got through the pattern to here from the |
matching on_failure_jump, so didn't fail. */ |
case pop_failure_jump: |
{ |
/* We need to pass separate storage for the lowest and |
highest registers, even though we don't care about the |
actual values. Otherwise, we will restore only one |
register from the stack, since lowest will == highest in |
`pop_failure_point'. */ |
active_reg_t dummy_low_reg, dummy_high_reg; |
UCHAR_T *pdummy ATTRIBUTE_UNUSED = NULL; |
const CHAR_T *sdummy ATTRIBUTE_UNUSED = NULL; |
DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n"); |
POP_FAILURE_POINT (sdummy, pdummy, |
dummy_low_reg, dummy_high_reg, |
reg_dummy, reg_dummy, reg_info_dummy); |
} |
/* Note fall through. */ |
unconditional_jump: |
#ifdef _LIBC |
DEBUG_PRINT2 ("\n%p: ", p); |
#else |
DEBUG_PRINT2 ("\n0x%x: ", p); |
#endif |
/* Note fall through. */ |
/* Unconditionally jump (without popping any failure points). */ |
case jump: |
EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */ |
DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt); |
p += mcnt; /* Do the jump. */ |
#ifdef _LIBC |
DEBUG_PRINT2 ("(to %p).\n", p); |
#else |
DEBUG_PRINT2 ("(to 0x%x).\n", p); |
#endif |
break; |
/* We need this opcode so we can detect where alternatives end |
in `group_match_null_string_p' et al. */ |
case jump_past_alt: |
DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n"); |
goto unconditional_jump; |
/* Normally, the on_failure_jump pushes a failure point, which |
then gets popped at pop_failure_jump. We will end up at |
pop_failure_jump, also, and with a pattern of, say, `a+', we |
are skipping over the on_failure_jump, so we have to push |
something meaningless for pop_failure_jump to pop. */ |
case dummy_failure_jump: |
DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n"); |
/* It doesn't matter what we push for the string here. What |
the code at `fail' tests is the value for the pattern. */ |
PUSH_FAILURE_POINT (NULL, NULL, -2); |
goto unconditional_jump; |
/* At the end of an alternative, we need to push a dummy failure |
point in case we are followed by a `pop_failure_jump', because |
we don't want the failure point for the alternative to be |
popped. For example, matching `(a|ab)*' against `aab' |
requires that we match the `ab' alternative. */ |
case push_dummy_failure: |
DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n"); |
/* See comments just above at `dummy_failure_jump' about the |
two zeroes. */ |
PUSH_FAILURE_POINT (NULL, NULL, -2); |
break; |
/* Have to succeed matching what follows at least n times. |
After that, handle like `on_failure_jump'. */ |
case succeed_n: |
EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE); |
DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt); |
assert (mcnt >= 0); |
/* Originally, this is how many times we HAVE to succeed. */ |
if (mcnt > 0) |
{ |
mcnt--; |
p += OFFSET_ADDRESS_SIZE; |
STORE_NUMBER_AND_INCR (p, mcnt); |
#ifdef _LIBC |
DEBUG_PRINT3 (" Setting %p to %d.\n", p - OFFSET_ADDRESS_SIZE |
, mcnt); |
#else |
DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p - OFFSET_ADDRESS_SIZE |
, mcnt); |
#endif |
} |
else if (mcnt == 0) |
{ |
#ifdef _LIBC |
DEBUG_PRINT2 (" Setting two bytes from %p to no_op.\n", |
p + OFFSET_ADDRESS_SIZE); |
#else |
DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", |
p + OFFSET_ADDRESS_SIZE); |
#endif /* _LIBC */ |
#ifdef WCHAR |
p[1] = (UCHAR_T) no_op; |
#else |
p[2] = (UCHAR_T) no_op; |
p[3] = (UCHAR_T) no_op; |
#endif /* WCHAR */ |
goto on_failure; |
} |
break; |
case jump_n: |
EXTRACT_NUMBER (mcnt, p + OFFSET_ADDRESS_SIZE); |
DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt); |
/* Originally, this is how many times we CAN jump. */ |
if (mcnt) |
{ |
mcnt--; |
STORE_NUMBER (p + OFFSET_ADDRESS_SIZE, mcnt); |
#ifdef _LIBC |
DEBUG_PRINT3 (" Setting %p to %d.\n", p + OFFSET_ADDRESS_SIZE, |
mcnt); |
#else |
DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p + OFFSET_ADDRESS_SIZE, |
mcnt); |
#endif /* _LIBC */ |
goto unconditional_jump; |
} |
/* If don't have to jump any more, skip over the rest of command. */ |
else |
p += 2 * OFFSET_ADDRESS_SIZE; |
break; |
case set_number_at: |
{ |
DEBUG_PRINT1 ("EXECUTING set_number_at.\n"); |
EXTRACT_NUMBER_AND_INCR (mcnt, p); |
p1 = p + mcnt; |
EXTRACT_NUMBER_AND_INCR (mcnt, p); |
#ifdef _LIBC |
DEBUG_PRINT3 (" Setting %p to %d.\n", p1, mcnt); |
#else |
DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt); |
#endif |
STORE_NUMBER (p1, mcnt); |
break; |
} |
#if 0 |
/* The DEC Alpha C compiler 3.x generates incorrect code for the |
test WORDCHAR_P (d - 1) != WORDCHAR_P (d) in the expansion of |
AT_WORD_BOUNDARY, so this code is disabled. Expanding the |
macro and introducing temporary variables works around the bug. */ |
case wordbound: |
DEBUG_PRINT1 ("EXECUTING wordbound.\n"); |
if (AT_WORD_BOUNDARY (d)) |
break; |
goto fail; |
case notwordbound: |
DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); |
if (AT_WORD_BOUNDARY (d)) |
goto fail; |
break; |
#else |
case wordbound: |
{ |
boolean prevchar, thischar; |
DEBUG_PRINT1 ("EXECUTING wordbound.\n"); |
if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) |
break; |
prevchar = WORDCHAR_P (d - 1); |
thischar = WORDCHAR_P (d); |
if (prevchar != thischar) |
break; |
goto fail; |
} |
case notwordbound: |
{ |
boolean prevchar, thischar; |
DEBUG_PRINT1 ("EXECUTING notwordbound.\n"); |
if (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)) |
goto fail; |
prevchar = WORDCHAR_P (d - 1); |
thischar = WORDCHAR_P (d); |
if (prevchar != thischar) |
goto fail; |
break; |
} |
#endif |
case wordbeg: |
DEBUG_PRINT1 ("EXECUTING wordbeg.\n"); |
if (!AT_STRINGS_END (d) && WORDCHAR_P (d) |
&& (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1))) |
break; |
goto fail; |
case wordend: |
DEBUG_PRINT1 ("EXECUTING wordend.\n"); |
if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1) |
&& (AT_STRINGS_END (d) || !WORDCHAR_P (d))) |
break; |
goto fail; |
#ifdef emacs |
case before_dot: |
DEBUG_PRINT1 ("EXECUTING before_dot.\n"); |
if (PTR_CHAR_POS ((unsigned char *) d) >= point) |
goto fail; |
break; |
case at_dot: |
DEBUG_PRINT1 ("EXECUTING at_dot.\n"); |
if (PTR_CHAR_POS ((unsigned char *) d) != point) |
goto fail; |
break; |
case after_dot: |
DEBUG_PRINT1 ("EXECUTING after_dot.\n"); |
if (PTR_CHAR_POS ((unsigned char *) d) <= point) |
goto fail; |
break; |
case syntaxspec: |
DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt); |
mcnt = *p++; |
goto matchsyntax; |
case wordchar: |
DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n"); |
mcnt = (int) Sword; |
matchsyntax: |
PREFETCH (); |
/* Can't use *d++ here; SYNTAX may be an unsafe macro. */ |
d++; |
if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt) |
goto fail; |
SET_REGS_MATCHED (); |
break; |
case notsyntaxspec: |
DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt); |
mcnt = *p++; |
goto matchnotsyntax; |
case notwordchar: |
DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n"); |
mcnt = (int) Sword; |
matchnotsyntax: |
PREFETCH (); |
/* Can't use *d++ here; SYNTAX may be an unsafe macro. */ |
d++; |
if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt) |
goto fail; |
SET_REGS_MATCHED (); |
break; |
#else /* not emacs */ |
case wordchar: |
DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n"); |
PREFETCH (); |
if (!WORDCHAR_P (d)) |
goto fail; |
SET_REGS_MATCHED (); |
d++; |
break; |
case notwordchar: |
DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n"); |
PREFETCH (); |
if (WORDCHAR_P (d)) |
goto fail; |
SET_REGS_MATCHED (); |
d++; |
break; |
#endif /* not emacs */ |
default: |
abort (); |
} |
continue; /* Successfully executed one pattern command; keep going. */ |
/* We goto here if a matching operation fails. */ |
fail: |
if (!FAIL_STACK_EMPTY ()) |
{ /* A restart point is known. Restore to that state. */ |
DEBUG_PRINT1 ("\nFAIL:\n"); |
POP_FAILURE_POINT (d, p, |
lowest_active_reg, highest_active_reg, |
regstart, regend, reg_info); |
/* If this failure point is a dummy, try the next one. */ |
if (!p) |
goto fail; |
/* If we failed to the end of the pattern, don't examine *p. */ |
assert (p <= pend); |
if (p < pend) |
{ |
boolean is_a_jump_n = false; |
/* If failed to a backwards jump that's part of a repetition |
loop, need to pop this failure point and use the next one. */ |
switch ((re_opcode_t) *p) |
{ |
case jump_n: |
is_a_jump_n = true; |
case maybe_pop_jump: |
case pop_failure_jump: |
case jump: |
p1 = p + 1; |
EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
p1 += mcnt; |
if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n) |
|| (!is_a_jump_n |
&& (re_opcode_t) *p1 == on_failure_jump)) |
goto fail; |
break; |
default: |
/* do nothing */ ; |
} |
} |
if (d >= string1 && d <= end1) |
dend = end_match_1; |
} |
else |
break; /* Matching at this starting point really fails. */ |
} /* for (;;) */ |
if (best_regs_set) |
goto restore_best_regs; |
FREE_VARIABLES (); |
return -1; /* Failure to match. */ |
} /* re_match_2 */ |
/* Subroutine definitions for re_match_2. */ |
/* We are passed P pointing to a register number after a start_memory. |
Return true if the pattern up to the corresponding stop_memory can |
match the empty string, and false otherwise. |
If we find the matching stop_memory, sets P to point to one past its number. |
Otherwise, sets P to an undefined byte less than or equal to END. |
We don't handle duplicates properly (yet). */ |
static boolean |
PREFIX(group_match_null_string_p) (UCHAR_T **p, UCHAR_T *end, |
PREFIX(register_info_type) *reg_info) |
{ |
int mcnt; |
/* Point to after the args to the start_memory. */ |
UCHAR_T *p1 = *p + 2; |
while (p1 < end) |
{ |
/* Skip over opcodes that can match nothing, and return true or |
false, as appropriate, when we get to one that can't, or to the |
matching stop_memory. */ |
switch ((re_opcode_t) *p1) |
{ |
/* Could be either a loop or a series of alternatives. */ |
case on_failure_jump: |
p1++; |
EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
/* If the next operation is not a jump backwards in the |
pattern. */ |
if (mcnt >= 0) |
{ |
/* Go through the on_failure_jumps of the alternatives, |
seeing if any of the alternatives cannot match nothing. |
The last alternative starts with only a jump, |
whereas the rest start with on_failure_jump and end |
with a jump, e.g., here is the pattern for `a|b|c': |
/on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6 |
/on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3 |
/exactn/1/c |
So, we have to first go through the first (n-1) |
alternatives and then deal with the last one separately. */ |
/* Deal with the first (n-1) alternatives, which start |
with an on_failure_jump (see above) that jumps to right |
past a jump_past_alt. */ |
while ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] == |
jump_past_alt) |
{ |
/* `mcnt' holds how many bytes long the alternative |
is, including the ending `jump_past_alt' and |
its number. */ |
if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt - |
(1 + OFFSET_ADDRESS_SIZE), |
reg_info)) |
return false; |
/* Move to right after this alternative, including the |
jump_past_alt. */ |
p1 += mcnt; |
/* Break if it's the beginning of an n-th alternative |
that doesn't begin with an on_failure_jump. */ |
if ((re_opcode_t) *p1 != on_failure_jump) |
break; |
/* Still have to check that it's not an n-th |
alternative that starts with an on_failure_jump. */ |
p1++; |
EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
if ((re_opcode_t) p1[mcnt-(1+OFFSET_ADDRESS_SIZE)] != |
jump_past_alt) |
{ |
/* Get to the beginning of the n-th alternative. */ |
p1 -= 1 + OFFSET_ADDRESS_SIZE; |
break; |
} |
} |
/* Deal with the last alternative: go back and get number |
of the `jump_past_alt' just before it. `mcnt' contains |
the length of the alternative. */ |
EXTRACT_NUMBER (mcnt, p1 - OFFSET_ADDRESS_SIZE); |
if (!PREFIX(alt_match_null_string_p) (p1, p1 + mcnt, reg_info)) |
return false; |
p1 += mcnt; /* Get past the n-th alternative. */ |
} /* if mcnt > 0 */ |
break; |
case stop_memory: |
assert (p1[1] == **p); |
*p = p1 + 2; |
return true; |
default: |
if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info)) |
return false; |
} |
} /* while p1 < end */ |
return false; |
} /* group_match_null_string_p */ |
/* Similar to group_match_null_string_p, but doesn't deal with alternatives: |
It expects P to be the first byte of a single alternative and END one |
byte past the last. The alternative can contain groups. */ |
static boolean |
PREFIX(alt_match_null_string_p) (UCHAR_T *p, UCHAR_T *end, |
PREFIX(register_info_type) *reg_info) |
{ |
int mcnt; |
UCHAR_T *p1 = p; |
while (p1 < end) |
{ |
/* Skip over opcodes that can match nothing, and break when we get |
to one that can't. */ |
switch ((re_opcode_t) *p1) |
{ |
/* It's a loop. */ |
case on_failure_jump: |
p1++; |
EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
p1 += mcnt; |
break; |
default: |
if (!PREFIX(common_op_match_null_string_p) (&p1, end, reg_info)) |
return false; |
} |
} /* while p1 < end */ |
return true; |
} /* alt_match_null_string_p */ |
/* Deals with the ops common to group_match_null_string_p and |
alt_match_null_string_p. |
Sets P to one after the op and its arguments, if any. */ |
static boolean |
PREFIX(common_op_match_null_string_p) (UCHAR_T **p, UCHAR_T *end, |
PREFIX(register_info_type) *reg_info) |
{ |
int mcnt; |
boolean ret; |
int reg_no; |
UCHAR_T *p1 = *p; |
switch ((re_opcode_t) *p1++) |
{ |
case no_op: |
case begline: |
case endline: |
case begbuf: |
case endbuf: |
case wordbeg: |
case wordend: |
case wordbound: |
case notwordbound: |
#ifdef emacs |
case before_dot: |
case at_dot: |
case after_dot: |
#endif |
break; |
case start_memory: |
reg_no = *p1; |
assert (reg_no > 0 && reg_no <= MAX_REGNUM); |
ret = PREFIX(group_match_null_string_p) (&p1, end, reg_info); |
/* Have to set this here in case we're checking a group which |
contains a group and a back reference to it. */ |
if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE) |
REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret; |
if (!ret) |
return false; |
break; |
/* If this is an optimized succeed_n for zero times, make the jump. */ |
case jump: |
EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
if (mcnt >= 0) |
p1 += mcnt; |
else |
return false; |
break; |
case succeed_n: |
/* Get to the number of times to succeed. */ |
p1 += OFFSET_ADDRESS_SIZE; |
EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
if (mcnt == 0) |
{ |
p1 -= 2 * OFFSET_ADDRESS_SIZE; |
EXTRACT_NUMBER_AND_INCR (mcnt, p1); |
p1 += mcnt; |
} |
else |
return false; |
break; |
case duplicate: |
if (!REG_MATCH_NULL_STRING_P (reg_info[*p1])) |
return false; |
break; |
case set_number_at: |
p1 += 2 * OFFSET_ADDRESS_SIZE; |
default: |
/* All other opcodes mean we cannot match the empty string. */ |
return false; |
} |
*p = p1; |
return true; |
} /* common_op_match_null_string_p */ |
/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN |
bytes; nonzero otherwise. */ |
static int |
PREFIX(bcmp_translate) (const CHAR_T *s1, const CHAR_T *s2, register int len, |
RE_TRANSLATE_TYPE translate) |
{ |
register const UCHAR_T *p1 = (const UCHAR_T *) s1; |
register const UCHAR_T *p2 = (const UCHAR_T *) s2; |
while (len) |
{ |
#ifdef WCHAR |
if (((*p1<=0xff)?translate[*p1++]:*p1++) |
!= ((*p2<=0xff)?translate[*p2++]:*p2++)) |
return 1; |
#else /* BYTE */ |
if (translate[*p1++] != translate[*p2++]) return 1; |
#endif /* WCHAR */ |
len--; |
} |
return 0; |
} |
#else /* not INSIDE_RECURSION */ |
/* Entry points for GNU code. */ |
/* re_compile_pattern is the GNU regular expression compiler: it |
compiles PATTERN (of length SIZE) and puts the result in BUFP. |
Returns 0 if the pattern was valid, otherwise an error string. |
Assumes the `allocated' (and perhaps `buffer') and `translate' fields |
are set in BUFP on entry. |
We call regex_compile to do the actual compilation. */ |
const char * |
re_compile_pattern (const char *pattern, size_t length, |
struct re_pattern_buffer *bufp) |
{ |
reg_errcode_t ret; |
/* GNU code is written to assume at least RE_NREGS registers will be set |
(and at least one extra will be -1). */ |
bufp->regs_allocated = REGS_UNALLOCATED; |
/* And GNU code determines whether or not to get register information |
by passing null for the REGS argument to re_match, etc., not by |
setting no_sub. */ |
bufp->no_sub = 0; |
/* Match anchors at newline. */ |
bufp->newline_anchor = 1; |
# ifdef MBS_SUPPORT |
if (MB_CUR_MAX != 1) |
ret = wcs_regex_compile (pattern, length, re_syntax_options, bufp); |
else |
# endif |
ret = byte_regex_compile (pattern, length, re_syntax_options, bufp); |
if (!ret) |
return NULL; |
return gettext (re_error_msgid[(int) ret]); |
} |
#ifdef _LIBC |
weak_alias (__re_compile_pattern, re_compile_pattern) |
#endif |
/* Entry points compatible with 4.2 BSD regex library. We don't define |
them unless specifically requested. */ |
#if defined _REGEX_RE_COMP || defined _LIBC |
/* BSD has one and only one pattern buffer. */ |
static struct re_pattern_buffer re_comp_buf; |
char * |
#ifdef _LIBC |
/* Make these definitions weak in libc, so POSIX programs can redefine |
these names if they don't use our functions, and still use |
regcomp/regexec below without link errors. */ |
weak_function |
#endif |
re_comp (const char *s) |
{ |
reg_errcode_t ret; |
if (!s) |
{ |
if (!re_comp_buf.buffer) |
return (char *) gettext ("No previous regular expression"); |
return 0; |
} |
if (!re_comp_buf.buffer) |
{ |
re_comp_buf.buffer = (unsigned char *) malloc (200); |
if (re_comp_buf.buffer == NULL) |
return (char *) gettext (re_error_msgid[(int) REG_ESPACE]); |
re_comp_buf.allocated = 200; |
re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH); |
if (re_comp_buf.fastmap == NULL) |
return (char *) gettext (re_error_msgid[(int) REG_ESPACE]); |
} |
/* Since `re_exec' always passes NULL for the `regs' argument, we |
don't need to initialize the pattern buffer fields which affect it. */ |
/* Match anchors at newlines. */ |
re_comp_buf.newline_anchor = 1; |
# ifdef MBS_SUPPORT |
if (MB_CUR_MAX != 1) |
ret = wcs_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); |
else |
# endif |
ret = byte_regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf); |
if (!ret) |
return NULL; |
/* Yes, we're discarding `const' here if !HAVE_LIBINTL. */ |
return (char *) gettext (re_error_msgid[(int) ret]); |
} |
int |
#ifdef _LIBC |
weak_function |
#endif |
re_exec (const char *s) |
{ |
const int len = strlen (s); |
return |
0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0); |
} |
#endif /* _REGEX_RE_COMP */ |
/* POSIX.2 functions. Don't define these for Emacs. */ |
#ifndef emacs |
/* regcomp takes a regular expression as a string and compiles it. |
PREG is a regex_t *. We do not expect any fields to be initialized, |
since POSIX says we shouldn't. Thus, we set |
`buffer' to the compiled pattern; |
`used' to the length of the compiled pattern; |
`syntax' to RE_SYNTAX_POSIX_EXTENDED if the |
REG_EXTENDED bit in CFLAGS is set; otherwise, to |
RE_SYNTAX_POSIX_BASIC; |
`newline_anchor' to REG_NEWLINE being set in CFLAGS; |
`fastmap' to an allocated space for the fastmap; |
`fastmap_accurate' to zero; |
`re_nsub' to the number of subexpressions in PATTERN. |
PATTERN is the address of the pattern string. |
CFLAGS is a series of bits which affect compilation. |
If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we |
use POSIX basic syntax. |
If REG_NEWLINE is set, then . and [^...] don't match newline. |
Also, regexec will try a match beginning after every newline. |
If REG_ICASE is set, then we considers upper- and lowercase |
versions of letters to be equivalent when matching. |
If REG_NOSUB is set, then when PREG is passed to regexec, that |
routine will report only success or failure, and nothing about the |
registers. |
It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for |
the return codes and their meanings.) */ |
int |
regcomp (regex_t *preg, const char *pattern, int cflags) |
{ |
reg_errcode_t ret; |
reg_syntax_t syntax |
= (cflags & REG_EXTENDED) ? |
RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC; |
/* regex_compile will allocate the space for the compiled pattern. */ |
preg->buffer = 0; |
preg->allocated = 0; |
preg->used = 0; |
/* Try to allocate space for the fastmap. */ |
preg->fastmap = (char *) malloc (1 << BYTEWIDTH); |
if (cflags & REG_ICASE) |
{ |
int i; |
preg->translate |
= (RE_TRANSLATE_TYPE) malloc (CHAR_SET_SIZE |
* sizeof (*(RE_TRANSLATE_TYPE)0)); |
if (preg->translate == NULL) |
return (int) REG_ESPACE; |
/* Map uppercase characters to corresponding lowercase ones. */ |
for (i = 0; i < CHAR_SET_SIZE; i++) |
preg->translate[i] = ISUPPER (i) ? TOLOWER (i) : i; |
} |
else |
preg->translate = NULL; |
/* If REG_NEWLINE is set, newlines are treated differently. */ |
if (cflags & REG_NEWLINE) |
{ /* REG_NEWLINE implies neither . nor [^...] match newline. */ |
syntax &= ~RE_DOT_NEWLINE; |
syntax |= RE_HAT_LISTS_NOT_NEWLINE; |
/* It also changes the matching behavior. */ |
preg->newline_anchor = 1; |
} |
else |
preg->newline_anchor = 0; |
preg->no_sub = !!(cflags & REG_NOSUB); |
/* POSIX says a null character in the pattern terminates it, so we |
can use strlen here in compiling the pattern. */ |
# ifdef MBS_SUPPORT |
if (MB_CUR_MAX != 1) |
ret = wcs_regex_compile (pattern, strlen (pattern), syntax, preg); |
else |
# endif |
ret = byte_regex_compile (pattern, strlen (pattern), syntax, preg); |
/* POSIX doesn't distinguish between an unmatched open-group and an |
unmatched close-group: both are REG_EPAREN. */ |
if (ret == REG_ERPAREN) ret = REG_EPAREN; |
if (ret == REG_NOERROR && preg->fastmap) |
{ |
/* Compute the fastmap now, since regexec cannot modify the pattern |
buffer. */ |
if (re_compile_fastmap (preg) == -2) |
{ |
/* Some error occurred while computing the fastmap, just forget |
about it. */ |
free (preg->fastmap); |
preg->fastmap = NULL; |
} |
} |
return (int) ret; |
} |
#ifdef _LIBC |
weak_alias (__regcomp, regcomp) |
#endif |
/* regexec searches for a given pattern, specified by PREG, in the |
string STRING. |
If NMATCH is zero or REG_NOSUB was set in the cflags argument to |
`regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at |
least NMATCH elements, and we set them to the offsets of the |
corresponding matched substrings. |
EFLAGS specifies `execution flags' which affect matching: if |
REG_NOTBOL is set, then ^ does not match at the beginning of the |
string; if REG_NOTEOL is set, then $ does not match at the end. |
We return 0 if we find a match and REG_NOMATCH if not. */ |
int |
regexec (const regex_t *preg, const char *string, size_t nmatch, |
regmatch_t pmatch[], int eflags) |
{ |
int ret; |
struct re_registers regs; |
regex_t private_preg; |
int len = strlen (string); |
boolean want_reg_info = !preg->no_sub && nmatch > 0; |
private_preg = *preg; |
private_preg.not_bol = !!(eflags & REG_NOTBOL); |
private_preg.not_eol = !!(eflags & REG_NOTEOL); |
/* The user has told us exactly how many registers to return |
information about, via `nmatch'. We have to pass that on to the |
matching routines. */ |
private_preg.regs_allocated = REGS_FIXED; |
if (want_reg_info) |
{ |
regs.num_regs = nmatch; |
regs.start = TALLOC (nmatch * 2, regoff_t); |
if (regs.start == NULL) |
return (int) REG_NOMATCH; |
regs.end = regs.start + nmatch; |
} |
/* Perform the searching operation. */ |
ret = re_search (&private_preg, string, len, |
/* start: */ 0, /* range: */ len, |
want_reg_info ? ®s : (struct re_registers *) 0); |
/* Copy the register information to the POSIX structure. */ |
if (want_reg_info) |
{ |
if (ret >= 0) |
{ |
unsigned r; |
for (r = 0; r < nmatch; r++) |
{ |
pmatch[r].rm_so = regs.start[r]; |
pmatch[r].rm_eo = regs.end[r]; |
} |
} |
/* If we needed the temporary register info, free the space now. */ |
free (regs.start); |
} |
/* We want zero return to mean success, unlike `re_search'. */ |
return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH; |
} |
#ifdef _LIBC |
weak_alias (__regexec, regexec) |
#endif |
/* Returns a message corresponding to an error code, ERRCODE, returned |
from either regcomp or regexec. We don't use PREG here. */ |
size_t |
regerror (int errcode, const regex_t *preg ATTRIBUTE_UNUSED, |
char *errbuf, size_t errbuf_size) |
{ |
const char *msg; |
size_t msg_size; |
if (errcode < 0 |
|| errcode >= (int) (sizeof (re_error_msgid) |
/ sizeof (re_error_msgid[0]))) |
/* Only error codes returned by the rest of the code should be passed |
to this routine. If we are given anything else, or if other regex |
code generates an invalid error code, then the program has a bug. |
Dump core so we can fix it. */ |
abort (); |
msg = gettext (re_error_msgid[errcode]); |
msg_size = strlen (msg) + 1; /* Includes the null. */ |
if (errbuf_size != 0) |
{ |
if (msg_size > errbuf_size) |
{ |
#if defined HAVE_MEMPCPY || defined _LIBC |
*((char *) mempcpy (errbuf, msg, errbuf_size - 1)) = '\0'; |
#else |
memcpy (errbuf, msg, errbuf_size - 1); |
errbuf[errbuf_size - 1] = 0; |
#endif |
} |
else |
memcpy (errbuf, msg, msg_size); |
} |
return msg_size; |
} |
#ifdef _LIBC |
weak_alias (__regerror, regerror) |
#endif |
/* Free dynamically allocated space used by PREG. */ |
void |
regfree (regex_t *preg) |
{ |
free (preg->buffer); |
preg->buffer = NULL; |
preg->allocated = 0; |
preg->used = 0; |
free (preg->fastmap); |
preg->fastmap = NULL; |
preg->fastmap_accurate = 0; |
free (preg->translate); |
preg->translate = NULL; |
} |
#ifdef _LIBC |
weak_alias (__regfree, regfree) |
#endif |
#endif /* not emacs */ |
#endif /* not INSIDE_RECURSION */ |
#undef STORE_NUMBER |
#undef STORE_NUMBER_AND_INCR |
#undef EXTRACT_NUMBER |
#undef EXTRACT_NUMBER_AND_INCR |
#undef DEBUG_PRINT_COMPILED_PATTERN |
#undef DEBUG_PRINT_DOUBLE_STRING |
#undef INIT_FAIL_STACK |
#undef RESET_FAIL_STACK |
#undef DOUBLE_FAIL_STACK |
#undef PUSH_PATTERN_OP |
#undef PUSH_FAILURE_POINTER |
#undef PUSH_FAILURE_INT |
#undef PUSH_FAILURE_ELT |
#undef POP_FAILURE_POINTER |
#undef POP_FAILURE_INT |
#undef POP_FAILURE_ELT |
#undef DEBUG_PUSH |
#undef DEBUG_POP |
#undef PUSH_FAILURE_POINT |
#undef POP_FAILURE_POINT |
#undef REG_UNSET_VALUE |
#undef REG_UNSET |
#undef PATFETCH |
#undef PATFETCH_RAW |
#undef PATUNFETCH |
#undef TRANSLATE |
#undef INIT_BUF_SIZE |
#undef GET_BUFFER_SPACE |
#undef BUF_PUSH |
#undef BUF_PUSH_2 |
#undef BUF_PUSH_3 |
#undef STORE_JUMP |
#undef STORE_JUMP2 |
#undef INSERT_JUMP |
#undef INSERT_JUMP2 |
#undef EXTEND_BUFFER |
#undef GET_UNSIGNED_NUMBER |
#undef FREE_STACK_RETURN |
# undef POINTER_TO_OFFSET |
# undef MATCHING_IN_FRST_STRING |
# undef PREFETCH |
# undef AT_STRINGS_BEG |
# undef AT_STRINGS_END |
# undef WORDCHAR_P |
# undef FREE_VAR |
# undef FREE_VARIABLES |
# undef NO_HIGHEST_ACTIVE_REG |
# undef NO_LOWEST_ACTIVE_REG |
# undef CHAR_T |
# undef UCHAR_T |
# undef COMPILED_BUFFER_VAR |
# undef OFFSET_ADDRESS_SIZE |
# undef CHAR_CLASS_SIZE |
# undef PREFIX |
# undef ARG_PREFIX |
# undef PUT_CHAR |
# undef BYTE |
# undef WCHAR |
# define DEFINED_ONCE |
/contrib/toolchain/binutils/libiberty/rindex.c |
---|
0,0 → 1,21 |
/* Stub implementation of (obsolete) rindex(). */ |
/* |
@deftypefn Supplemental char* rindex (const char *@var{s}, int @var{c}) |
Returns a pointer to the last occurrence of the character @var{c} in |
the string @var{s}, or @code{NULL} if not found. The use of @code{rindex} is |
deprecated in new programs in favor of @code{strrchr}. |
@end deftypefn |
*/ |
extern char *strrchr (const char *, int); |
char * |
rindex (const char *s, int c) |
{ |
return strrchr (s, c); |
} |
/contrib/toolchain/binutils/libiberty/safe-ctype.c |
---|
0,0 → 1,255 |
/* <ctype.h> replacement macros. |
Copyright (C) 2000, 2001, 2002, 2003, 2004, |
2005 Free Software Foundation, Inc. |
Contributed by Zack Weinberg <zackw@stanford.edu>. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@defvr Extension HOST_CHARSET |
This macro indicates the basic character set and encoding used by the |
host: more precisely, the encoding used for character constants in |
preprocessor @samp{#if} statements (the C "execution character set"). |
It is defined by @file{safe-ctype.h}, and will be an integer constant |
with one of the following values: |
@ftable @code |
@item HOST_CHARSET_UNKNOWN |
The host character set is unknown - that is, not one of the next two |
possibilities. |
@item HOST_CHARSET_ASCII |
The host character set is ASCII. |
@item HOST_CHARSET_EBCDIC |
The host character set is some variant of EBCDIC. (Only one of the |
nineteen EBCDIC varying characters is tested; exercise caution.) |
@end ftable |
@end defvr |
@deffn Extension ISALPHA (@var{c}) |
@deffnx Extension ISALNUM (@var{c}) |
@deffnx Extension ISBLANK (@var{c}) |
@deffnx Extension ISCNTRL (@var{c}) |
@deffnx Extension ISDIGIT (@var{c}) |
@deffnx Extension ISGRAPH (@var{c}) |
@deffnx Extension ISLOWER (@var{c}) |
@deffnx Extension ISPRINT (@var{c}) |
@deffnx Extension ISPUNCT (@var{c}) |
@deffnx Extension ISSPACE (@var{c}) |
@deffnx Extension ISUPPER (@var{c}) |
@deffnx Extension ISXDIGIT (@var{c}) |
These twelve macros are defined by @file{safe-ctype.h}. Each has the |
same meaning as the corresponding macro (with name in lowercase) |
defined by the standard header @file{ctype.h}. For example, |
@code{ISALPHA} returns true for alphabetic characters and false for |
others. However, there are two differences between these macros and |
those provided by @file{ctype.h}: |
@itemize @bullet |
@item These macros are guaranteed to have well-defined behavior for all |
values representable by @code{signed char} and @code{unsigned char}, and |
for @code{EOF}. |
@item These macros ignore the current locale; they are true for these |
fixed sets of characters: |
@multitable {@code{XDIGIT}} {yada yada yada yada yada yada yada yada} |
@item @code{ALPHA} @tab @kbd{A-Za-z} |
@item @code{ALNUM} @tab @kbd{A-Za-z0-9} |
@item @code{BLANK} @tab @kbd{space tab} |
@item @code{CNTRL} @tab @code{!PRINT} |
@item @code{DIGIT} @tab @kbd{0-9} |
@item @code{GRAPH} @tab @code{ALNUM || PUNCT} |
@item @code{LOWER} @tab @kbd{a-z} |
@item @code{PRINT} @tab @code{GRAPH ||} @kbd{space} |
@item @code{PUNCT} @tab @kbd{`~!@@#$%^&*()_-=+[@{]@}\|;:'",<.>/?} |
@item @code{SPACE} @tab @kbd{space tab \n \r \f \v} |
@item @code{UPPER} @tab @kbd{A-Z} |
@item @code{XDIGIT} @tab @kbd{0-9A-Fa-f} |
@end multitable |
Note that, if the host character set is ASCII or a superset thereof, |
all these macros will return false for all values of @code{char} outside |
the range of 7-bit ASCII. In particular, both ISPRINT and ISCNTRL return |
false for characters with numeric values from 128 to 255. |
@end itemize |
@end deffn |
@deffn Extension ISIDNUM (@var{c}) |
@deffnx Extension ISIDST (@var{c}) |
@deffnx Extension IS_VSPACE (@var{c}) |
@deffnx Extension IS_NVSPACE (@var{c}) |
@deffnx Extension IS_SPACE_OR_NUL (@var{c}) |
@deffnx Extension IS_ISOBASIC (@var{c}) |
These six macros are defined by @file{safe-ctype.h} and provide |
additional character classes which are useful when doing lexical |
analysis of C or similar languages. They are true for the following |
sets of characters: |
@multitable {@code{SPACE_OR_NUL}} {yada yada yada yada yada yada yada yada} |
@item @code{IDNUM} @tab @kbd{A-Za-z0-9_} |
@item @code{IDST} @tab @kbd{A-Za-z_} |
@item @code{VSPACE} @tab @kbd{\r \n} |
@item @code{NVSPACE} @tab @kbd{space tab \f \v \0} |
@item @code{SPACE_OR_NUL} @tab @code{VSPACE || NVSPACE} |
@item @code{ISOBASIC} @tab @code{VSPACE || NVSPACE || PRINT} |
@end multitable |
@end deffn |
*/ |
#include "ansidecl.h" |
#include <safe-ctype.h> |
#include <stdio.h> /* for EOF */ |
#if EOF != -1 |
#error "<safe-ctype.h> requires EOF == -1" |
#endif |
/* Shorthand */ |
#define bl _sch_isblank |
#define cn _sch_iscntrl |
#define di _sch_isdigit |
#define is _sch_isidst |
#define lo _sch_islower |
#define nv _sch_isnvsp |
#define pn _sch_ispunct |
#define pr _sch_isprint |
#define sp _sch_isspace |
#define up _sch_isupper |
#define vs _sch_isvsp |
#define xd _sch_isxdigit |
/* Masks. */ |
#define L (const unsigned short) (lo|is |pr) /* lower case letter */ |
#define XL (const unsigned short) (lo|is|xd|pr) /* lowercase hex digit */ |
#define U (const unsigned short) (up|is |pr) /* upper case letter */ |
#define XU (const unsigned short) (up|is|xd|pr) /* uppercase hex digit */ |
#define D (const unsigned short) (di |xd|pr) /* decimal digit */ |
#define P (const unsigned short) (pn |pr) /* punctuation */ |
#define _ (const unsigned short) (pn|is |pr) /* underscore */ |
#define C (const unsigned short) ( cn) /* control character */ |
#define Z (const unsigned short) (nv |cn) /* NUL */ |
#define M (const unsigned short) (nv|sp |cn) /* cursor movement: \f \v */ |
#define V (const unsigned short) (vs|sp |cn) /* vertical space: \r \n */ |
#define T (const unsigned short) (nv|sp|bl|cn) /* tab */ |
#define S (const unsigned short) (nv|sp|bl|pr) /* space */ |
/* Are we ASCII? */ |
#if HOST_CHARSET == HOST_CHARSET_ASCII |
const unsigned short _sch_istable[256] = |
{ |
Z, C, C, C, C, C, C, C, /* NUL SOH STX ETX EOT ENQ ACK BEL */ |
C, T, V, M, M, V, C, C, /* BS HT LF VT FF CR SO SI */ |
C, C, C, C, C, C, C, C, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ |
C, C, C, C, C, C, C, C, /* CAN EM SUB ESC FS GS RS US */ |
S, P, P, P, P, P, P, P, /* SP ! " # $ % & ' */ |
P, P, P, P, P, P, P, P, /* ( ) * + , - . / */ |
D, D, D, D, D, D, D, D, /* 0 1 2 3 4 5 6 7 */ |
D, D, P, P, P, P, P, P, /* 8 9 : ; < = > ? */ |
P, XU, XU, XU, XU, XU, XU, U, /* @ A B C D E F G */ |
U, U, U, U, U, U, U, U, /* H I J K L M N O */ |
U, U, U, U, U, U, U, U, /* P Q R S T U V W */ |
U, U, U, P, P, P, P, _, /* X Y Z [ \ ] ^ _ */ |
P, XL, XL, XL, XL, XL, XL, L, /* ` a b c d e f g */ |
L, L, L, L, L, L, L, L, /* h i j k l m n o */ |
L, L, L, L, L, L, L, L, /* p q r s t u v w */ |
L, L, L, P, P, P, P, C, /* x y z { | } ~ DEL */ |
/* high half of unsigned char is locale-specific, so all tests are |
false in "C" locale */ |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
}; |
const unsigned char _sch_tolower[256] = |
{ |
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, |
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, |
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, |
64, |
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', |
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
91, 92, 93, 94, 95, 96, |
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', |
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
123,124,125,126,127, |
128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, |
144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, |
160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175, |
176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191, |
192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207, |
208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, |
224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, |
240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255, |
}; |
const unsigned char _sch_toupper[256] = |
{ |
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, |
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, |
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, |
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, |
64, |
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', |
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
91, 92, 93, 94, 95, 96, |
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', |
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
123,124,125,126,127, |
128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143, |
144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159, |
160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175, |
176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191, |
192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207, |
208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223, |
224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239, |
240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255, |
}; |
#else |
# if HOST_CHARSET == HOST_CHARSET_EBCDIC |
#error "FIXME: write tables for EBCDIC" |
# else |
#error "Unrecognized host character set" |
# endif |
#endif |
/contrib/toolchain/binutils/libiberty/setenv.c |
---|
0,0 → 1,185 |
/* Copyright (C) 1992, 1995, 1996, 1997, 2002, 2011 Free Software Foundation, |
Inc. |
This file based on setenv.c in the GNU C Library. |
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., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Supplemental int setenv (const char *@var{name}, @ |
const char *@var{value}, int @var{overwrite}) |
@deftypefnx Supplemental void unsetenv (const char *@var{name}) |
@code{setenv} adds @var{name} to the environment with value |
@var{value}. If the name was already present in the environment, |
the new value will be stored only if @var{overwrite} is nonzero. |
The companion @code{unsetenv} function removes @var{name} from the |
environment. This implementation is not safe for multithreaded code. |
@end deftypefn |
*/ |
#if HAVE_CONFIG_H |
# include <config.h> |
#endif |
#define setenv libiberty_setenv |
#define unsetenv libiberty_unsetenv |
#include "ansidecl.h" |
#include <sys/types.h> /* For `size_t' */ |
#include <stdio.h> /* For `NULL' */ |
#include <errno.h> |
#if !defined(errno) && !defined(HAVE_ERRNO_DECL) |
extern int errno; |
#endif |
#define __set_errno(ev) ((errno) = (ev)) |
#if HAVE_STDLIB_H |
# include <stdlib.h> |
#endif |
#if HAVE_STRING_H |
# include <string.h> |
#endif |
#if HAVE_UNISTD_H |
# include <unistd.h> |
#endif |
#define __environ environ |
#ifndef HAVE_ENVIRON_DECL |
extern char **environ; |
#endif |
#undef setenv |
#undef unsetenv |
/* LOCK and UNLOCK are defined as no-ops. This makes the libiberty |
* implementation MT-Unsafe. */ |
#define LOCK |
#define UNLOCK |
/* Below this point, it's verbatim code from the glibc-2.0 implementation */ |
/* If this variable is not a null pointer we allocated the current |
environment. */ |
static char **last_environ; |
int |
setenv (const char *name, const char *value, int replace) |
{ |
register char **ep = 0; |
register size_t size; |
const size_t namelen = strlen (name); |
const size_t vallen = strlen (value) + 1; |
LOCK; |
size = 0; |
if (__environ != NULL) |
{ |
for (ep = __environ; *ep != NULL; ++ep) |
if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') |
break; |
else |
++size; |
} |
if (__environ == NULL || *ep == NULL) |
{ |
char **new_environ; |
if (__environ == last_environ && __environ != NULL) |
/* We allocated this space; we can extend it. */ |
new_environ = (char **) realloc (last_environ, |
(size + 2) * sizeof (char *)); |
else |
new_environ = (char **) malloc ((size + 2) * sizeof (char *)); |
if (new_environ == NULL) |
{ |
UNLOCK; |
return -1; |
} |
new_environ[size] = (char *) malloc (namelen + 1 + vallen); |
if (new_environ[size] == NULL) |
{ |
free ((char *) new_environ); |
__set_errno (ENOMEM); |
UNLOCK; |
return -1; |
} |
if (__environ != last_environ) |
memcpy ((char *) new_environ, (char *) __environ, |
size * sizeof (char *)); |
memcpy (new_environ[size], name, namelen); |
new_environ[size][namelen] = '='; |
memcpy (&new_environ[size][namelen + 1], value, vallen); |
new_environ[size + 1] = NULL; |
last_environ = __environ = new_environ; |
} |
else if (replace) |
{ |
size_t len = strlen (*ep); |
if (len + 1 < namelen + 1 + vallen) |
{ |
/* The existing string is too short; malloc a new one. */ |
char *new_string = (char *) malloc (namelen + 1 + vallen); |
if (new_string == NULL) |
{ |
UNLOCK; |
return -1; |
} |
*ep = new_string; |
} |
memcpy (*ep, name, namelen); |
(*ep)[namelen] = '='; |
memcpy (&(*ep)[namelen + 1], value, vallen); |
} |
UNLOCK; |
return 0; |
} |
void |
unsetenv (const char *name) |
{ |
const size_t len = strlen (name); |
char **ep; |
LOCK; |
for (ep = __environ; *ep; ++ep) |
if (!strncmp (*ep, name, len) && (*ep)[len] == '=') |
{ |
/* Found it. Remove this pointer by moving later ones back. */ |
char **dp = ep; |
do |
dp[0] = dp[1]; |
while (*dp++); |
/* Continue the loop in case NAME appears again. */ |
} |
UNLOCK; |
} |
/contrib/toolchain/binutils/libiberty/setproctitle.c |
---|
0,0 → 1,48 |
/* Set the title of a process. |
Copyright (C) 2010, 2011 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If not, |
write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#ifdef HAVE_SYS_PRCTL_H |
#include <sys/types.h> |
#include <sys/prctl.h> |
#endif |
#include "ansidecl.h" |
/* |
@deftypefn Supplemental void setproctitle (const char *@var{fmt}, ...) |
Set the title of a process to @var{fmt}. va args not supported for now, |
but defined for compatibility with BSD. |
@end deftypefn |
*/ |
void |
setproctitle (const char *name ATTRIBUTE_UNUSED, ...) |
{ |
#ifdef PR_SET_NAME |
/* On GNU/Linux this sets the top visible "comm", but not |
necessarily the name visible in ps. */ |
prctl (PR_SET_NAME, name); |
#endif |
} |
/contrib/toolchain/binutils/libiberty/sha1.c |
---|
0,0 → 1,415 |
/* sha1.c - Functions to compute SHA1 message digest of files or |
memory blocks according to the NIST specification FIPS-180-1. |
Copyright (C) 2000, 2001, 2003, 2004, 2005, 2006, 2008 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ |
/* Written by Scott G. Miller |
Credits: |
Robert Klep <robert@ilse.nl> -- Expansion function fix |
*/ |
#include <config.h> |
#include "sha1.h" |
#include <stddef.h> |
#include <string.h> |
#if USE_UNLOCKED_IO |
# include "unlocked-io.h" |
#endif |
#ifdef WORDS_BIGENDIAN |
# define SWAP(n) (n) |
#else |
# define SWAP(n) \ |
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) |
#endif |
#define BLOCKSIZE 4096 |
#if BLOCKSIZE % 64 != 0 |
# error "invalid BLOCKSIZE" |
#endif |
/* This array contains the bytes used to pad the buffer to the next |
64-byte boundary. (RFC 1321, 3.1: Step 1) */ |
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; |
/* Take a pointer to a 160 bit block of data (five 32 bit ints) and |
initialize it to the start constants of the SHA1 algorithm. This |
must be called before using hash in the call to sha1_hash. */ |
void |
sha1_init_ctx (struct sha1_ctx *ctx) |
{ |
ctx->A = 0x67452301; |
ctx->B = 0xefcdab89; |
ctx->C = 0x98badcfe; |
ctx->D = 0x10325476; |
ctx->E = 0xc3d2e1f0; |
ctx->total[0] = ctx->total[1] = 0; |
ctx->buflen = 0; |
} |
/* Put result from CTX in first 20 bytes following RESBUF. The result |
must be in little endian byte order. |
IMPORTANT: On some systems it is required that RESBUF is correctly |
aligned for a 32-bit value. */ |
void * |
sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf) |
{ |
((sha1_uint32 *) resbuf)[0] = SWAP (ctx->A); |
((sha1_uint32 *) resbuf)[1] = SWAP (ctx->B); |
((sha1_uint32 *) resbuf)[2] = SWAP (ctx->C); |
((sha1_uint32 *) resbuf)[3] = SWAP (ctx->D); |
((sha1_uint32 *) resbuf)[4] = SWAP (ctx->E); |
return resbuf; |
} |
/* Process the remaining bytes in the internal buffer and the usual |
prolog according to the standard and write the result to RESBUF. |
IMPORTANT: On some systems it is required that RESBUF is correctly |
aligned for a 32-bit value. */ |
void * |
sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) |
{ |
/* Take yet unprocessed bytes into account. */ |
sha1_uint32 bytes = ctx->buflen; |
size_t size = (bytes < 56) ? 64 / 4 : 64 * 2 / 4; |
/* Now count remaining bytes. */ |
ctx->total[0] += bytes; |
if (ctx->total[0] < bytes) |
++ctx->total[1]; |
/* Put the 64-bit file length in *bits* at the end of the buffer. */ |
ctx->buffer[size - 2] = SWAP ((ctx->total[1] << 3) | (ctx->total[0] >> 29)); |
ctx->buffer[size - 1] = SWAP (ctx->total[0] << 3); |
memcpy (&((char *) ctx->buffer)[bytes], fillbuf, (size - 2) * 4 - bytes); |
/* Process last bytes. */ |
sha1_process_block (ctx->buffer, size * 4, ctx); |
return sha1_read_ctx (ctx, resbuf); |
} |
/* Compute SHA1 message digest for bytes read from STREAM. The |
resulting message digest number will be written into the 16 bytes |
beginning at RESBLOCK. */ |
int |
sha1_stream (FILE *stream, void *resblock) |
{ |
struct sha1_ctx ctx; |
char buffer[BLOCKSIZE + 72]; |
size_t sum; |
/* Initialize the computation context. */ |
sha1_init_ctx (&ctx); |
/* Iterate over full file contents. */ |
while (1) |
{ |
/* We read the file in blocks of BLOCKSIZE bytes. One call of the |
computation function processes the whole buffer so that with the |
next round of the loop another block can be read. */ |
size_t n; |
sum = 0; |
/* Read block. Take care for partial reads. */ |
while (1) |
{ |
n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); |
sum += n; |
if (sum == BLOCKSIZE) |
break; |
if (n == 0) |
{ |
/* Check for the error flag IFF N == 0, so that we don't |
exit the loop after a partial read due to e.g., EAGAIN |
or EWOULDBLOCK. */ |
if (ferror (stream)) |
return 1; |
goto process_partial_block; |
} |
/* We've read at least one byte, so ignore errors. But always |
check for EOF, since feof may be true even though N > 0. |
Otherwise, we could end up calling fread after EOF. */ |
if (feof (stream)) |
goto process_partial_block; |
} |
/* Process buffer with BLOCKSIZE bytes. Note that |
BLOCKSIZE % 64 == 0 |
*/ |
sha1_process_block (buffer, BLOCKSIZE, &ctx); |
} |
process_partial_block:; |
/* Process any remaining bytes. */ |
if (sum > 0) |
sha1_process_bytes (buffer, sum, &ctx); |
/* Construct result in desired memory. */ |
sha1_finish_ctx (&ctx, resblock); |
return 0; |
} |
/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The |
result is always in little endian byte order, so that a byte-wise |
output yields to the wanted ASCII representation of the message |
digest. */ |
void * |
sha1_buffer (const char *buffer, size_t len, void *resblock) |
{ |
struct sha1_ctx ctx; |
/* Initialize the computation context. */ |
sha1_init_ctx (&ctx); |
/* Process whole buffer but last len % 64 bytes. */ |
sha1_process_bytes (buffer, len, &ctx); |
/* Put result in desired memory area. */ |
return sha1_finish_ctx (&ctx, resblock); |
} |
void |
sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) |
{ |
/* When we already have some bits in our internal buffer concatenate |
both inputs first. */ |
if (ctx->buflen != 0) |
{ |
size_t left_over = ctx->buflen; |
size_t add = 128 - left_over > len ? len : 128 - left_over; |
memcpy (&((char *) ctx->buffer)[left_over], buffer, add); |
ctx->buflen += add; |
if (ctx->buflen > 64) |
{ |
sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx); |
ctx->buflen &= 63; |
/* The regions in the following copy operation cannot overlap. */ |
memcpy (ctx->buffer, |
&((char *) ctx->buffer)[(left_over + add) & ~63], |
ctx->buflen); |
} |
buffer = (const char *) buffer + add; |
len -= add; |
} |
/* Process available complete blocks. */ |
if (len >= 64) |
{ |
#if !_STRING_ARCH_unaligned |
# define alignof(type) offsetof (struct { char c; type x; }, x) |
# define UNALIGNED_P(p) (((size_t) p) % alignof (sha1_uint32) != 0) |
if (UNALIGNED_P (buffer)) |
while (len > 64) |
{ |
sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); |
buffer = (const char *) buffer + 64; |
len -= 64; |
} |
else |
#endif |
{ |
sha1_process_block (buffer, len & ~63, ctx); |
buffer = (const char *) buffer + (len & ~63); |
len &= 63; |
} |
} |
/* Move remaining bytes in internal buffer. */ |
if (len > 0) |
{ |
size_t left_over = ctx->buflen; |
memcpy (&((char *) ctx->buffer)[left_over], buffer, len); |
left_over += len; |
if (left_over >= 64) |
{ |
sha1_process_block (ctx->buffer, 64, ctx); |
left_over -= 64; |
memcpy (ctx->buffer, &ctx->buffer[16], left_over); |
} |
ctx->buflen = left_over; |
} |
} |
/* --- Code below is the primary difference between md5.c and sha1.c --- */ |
/* SHA1 round constants */ |
#define K1 0x5a827999 |
#define K2 0x6ed9eba1 |
#define K3 0x8f1bbcdc |
#define K4 0xca62c1d6 |
/* Round functions. Note that F2 is the same as F4. */ |
#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) ) |
#define F2(B,C,D) (B ^ C ^ D) |
#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) ) |
#define F4(B,C,D) (B ^ C ^ D) |
/* Process LEN bytes of BUFFER, accumulating context into CTX. |
It is assumed that LEN % 64 == 0. |
Most of this code comes from GnuPG's cipher/sha1.c. */ |
void |
sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx) |
{ |
const sha1_uint32 *words = (const sha1_uint32*) buffer; |
size_t nwords = len / sizeof (sha1_uint32); |
const sha1_uint32 *endp = words + nwords; |
sha1_uint32 x[16]; |
sha1_uint32 a = ctx->A; |
sha1_uint32 b = ctx->B; |
sha1_uint32 c = ctx->C; |
sha1_uint32 d = ctx->D; |
sha1_uint32 e = ctx->E; |
/* First increment the byte count. RFC 1321 specifies the possible |
length of the file up to 2^64 bits. Here we only compute the |
number of bytes. Do a double word increment. */ |
ctx->total[0] += len; |
ctx->total[1] += ((len >> 31) >> 1) + (ctx->total[0] < len); |
#define rol(x, n) (((x) << (n)) | ((sha1_uint32) (x) >> (32 - (n)))) |
#define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \ |
^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \ |
, (x[I&0x0f] = rol(tm, 1)) ) |
#define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \ |
+ F( B, C, D ) \ |
+ K \ |
+ M; \ |
B = rol( B, 30 ); \ |
} while(0) |
while (words < endp) |
{ |
sha1_uint32 tm; |
int t; |
for (t = 0; t < 16; t++) |
{ |
x[t] = SWAP (*words); |
words++; |
} |
R( a, b, c, d, e, F1, K1, x[ 0] ); |
R( e, a, b, c, d, F1, K1, x[ 1] ); |
R( d, e, a, b, c, F1, K1, x[ 2] ); |
R( c, d, e, a, b, F1, K1, x[ 3] ); |
R( b, c, d, e, a, F1, K1, x[ 4] ); |
R( a, b, c, d, e, F1, K1, x[ 5] ); |
R( e, a, b, c, d, F1, K1, x[ 6] ); |
R( d, e, a, b, c, F1, K1, x[ 7] ); |
R( c, d, e, a, b, F1, K1, x[ 8] ); |
R( b, c, d, e, a, F1, K1, x[ 9] ); |
R( a, b, c, d, e, F1, K1, x[10] ); |
R( e, a, b, c, d, F1, K1, x[11] ); |
R( d, e, a, b, c, F1, K1, x[12] ); |
R( c, d, e, a, b, F1, K1, x[13] ); |
R( b, c, d, e, a, F1, K1, x[14] ); |
R( a, b, c, d, e, F1, K1, x[15] ); |
R( e, a, b, c, d, F1, K1, M(16) ); |
R( d, e, a, b, c, F1, K1, M(17) ); |
R( c, d, e, a, b, F1, K1, M(18) ); |
R( b, c, d, e, a, F1, K1, M(19) ); |
R( a, b, c, d, e, F2, K2, M(20) ); |
R( e, a, b, c, d, F2, K2, M(21) ); |
R( d, e, a, b, c, F2, K2, M(22) ); |
R( c, d, e, a, b, F2, K2, M(23) ); |
R( b, c, d, e, a, F2, K2, M(24) ); |
R( a, b, c, d, e, F2, K2, M(25) ); |
R( e, a, b, c, d, F2, K2, M(26) ); |
R( d, e, a, b, c, F2, K2, M(27) ); |
R( c, d, e, a, b, F2, K2, M(28) ); |
R( b, c, d, e, a, F2, K2, M(29) ); |
R( a, b, c, d, e, F2, K2, M(30) ); |
R( e, a, b, c, d, F2, K2, M(31) ); |
R( d, e, a, b, c, F2, K2, M(32) ); |
R( c, d, e, a, b, F2, K2, M(33) ); |
R( b, c, d, e, a, F2, K2, M(34) ); |
R( a, b, c, d, e, F2, K2, M(35) ); |
R( e, a, b, c, d, F2, K2, M(36) ); |
R( d, e, a, b, c, F2, K2, M(37) ); |
R( c, d, e, a, b, F2, K2, M(38) ); |
R( b, c, d, e, a, F2, K2, M(39) ); |
R( a, b, c, d, e, F3, K3, M(40) ); |
R( e, a, b, c, d, F3, K3, M(41) ); |
R( d, e, a, b, c, F3, K3, M(42) ); |
R( c, d, e, a, b, F3, K3, M(43) ); |
R( b, c, d, e, a, F3, K3, M(44) ); |
R( a, b, c, d, e, F3, K3, M(45) ); |
R( e, a, b, c, d, F3, K3, M(46) ); |
R( d, e, a, b, c, F3, K3, M(47) ); |
R( c, d, e, a, b, F3, K3, M(48) ); |
R( b, c, d, e, a, F3, K3, M(49) ); |
R( a, b, c, d, e, F3, K3, M(50) ); |
R( e, a, b, c, d, F3, K3, M(51) ); |
R( d, e, a, b, c, F3, K3, M(52) ); |
R( c, d, e, a, b, F3, K3, M(53) ); |
R( b, c, d, e, a, F3, K3, M(54) ); |
R( a, b, c, d, e, F3, K3, M(55) ); |
R( e, a, b, c, d, F3, K3, M(56) ); |
R( d, e, a, b, c, F3, K3, M(57) ); |
R( c, d, e, a, b, F3, K3, M(58) ); |
R( b, c, d, e, a, F3, K3, M(59) ); |
R( a, b, c, d, e, F4, K4, M(60) ); |
R( e, a, b, c, d, F4, K4, M(61) ); |
R( d, e, a, b, c, F4, K4, M(62) ); |
R( c, d, e, a, b, F4, K4, M(63) ); |
R( b, c, d, e, a, F4, K4, M(64) ); |
R( a, b, c, d, e, F4, K4, M(65) ); |
R( e, a, b, c, d, F4, K4, M(66) ); |
R( d, e, a, b, c, F4, K4, M(67) ); |
R( c, d, e, a, b, F4, K4, M(68) ); |
R( b, c, d, e, a, F4, K4, M(69) ); |
R( a, b, c, d, e, F4, K4, M(70) ); |
R( e, a, b, c, d, F4, K4, M(71) ); |
R( d, e, a, b, c, F4, K4, M(72) ); |
R( c, d, e, a, b, F4, K4, M(73) ); |
R( b, c, d, e, a, F4, K4, M(74) ); |
R( a, b, c, d, e, F4, K4, M(75) ); |
R( e, a, b, c, d, F4, K4, M(76) ); |
R( d, e, a, b, c, F4, K4, M(77) ); |
R( c, d, e, a, b, F4, K4, M(78) ); |
R( b, c, d, e, a, F4, K4, M(79) ); |
a = ctx->A += a; |
b = ctx->B += b; |
c = ctx->C += c; |
d = ctx->D += d; |
e = ctx->E += e; |
} |
} |
/contrib/toolchain/binutils/libiberty/sigsetmask.c |
---|
0,0 → 1,40 |
/* Version of sigsetmask.c |
Written by Steve Chamberlain (sac@cygnus.com). |
Contributed by Cygnus Support. |
This file is in the public doamin. */ |
/* |
@deftypefn Supplemental int sigsetmask (int @var{set}) |
Sets the signal mask to the one provided in @var{set} and returns |
the old mask (which, for libiberty's implementation, will always |
be the value @code{1}). |
@end deftypefn |
*/ |
#define _POSIX_SOURCE |
#include <ansidecl.h> |
/* Including <sys/types.h> seems to be needed by ISC. */ |
#include <sys/types.h> |
#include <signal.h> |
extern void abort (void) ATTRIBUTE_NORETURN; |
#ifdef SIG_SETMASK |
int |
sigsetmask (int set) |
{ |
sigset_t new_sig; |
sigset_t old_sig; |
sigemptyset (&new_sig); |
if (set != 0) { |
abort(); /* FIXME, we don't know how to translate old mask to new */ |
} |
sigprocmask(SIG_SETMASK, &new_sig, &old_sig); |
return 1; /* FIXME, we always return 1 as old value. */ |
} |
#endif |
/contrib/toolchain/binutils/libiberty/simple-object-coff.c |
---|
0,0 → 1,804 |
/* simple-object-coff.c -- routines to manipulate COFF object files. |
Copyright 2010 Free Software Foundation, Inc. |
Written by Ian Lance Taylor, Google. |
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, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#include "config.h" |
#include "libiberty.h" |
#include "simple-object.h" |
#include <errno.h> |
#include <stddef.h> |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STDINT_H |
#include <stdint.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifdef HAVE_INTTYPES_H |
#include <inttypes.h> |
#endif |
#include "simple-object-common.h" |
/* COFF structures and constants. */ |
/* COFF file header. */ |
struct external_filehdr |
{ |
unsigned char f_magic[2]; /* magic number */ |
unsigned char f_nscns[2]; /* number of sections */ |
unsigned char f_timdat[4]; /* time & date stamp */ |
unsigned char f_symptr[4]; /* file pointer to symtab */ |
unsigned char f_nsyms[4]; /* number of symtab entries */ |
unsigned char f_opthdr[2]; /* sizeof(optional hdr) */ |
unsigned char f_flags[2]; /* flags */ |
}; |
/* Bits for filehdr f_flags field. */ |
#define F_EXEC (0x0002) |
#define IMAGE_FILE_SYSTEM (0x1000) |
#define IMAGE_FILE_DLL (0x2000) |
/* COFF section header. */ |
struct external_scnhdr |
{ |
unsigned char s_name[8]; /* section name */ |
unsigned char s_paddr[4]; /* physical address, aliased s_nlib */ |
unsigned char s_vaddr[4]; /* virtual address */ |
unsigned char s_size[4]; /* section size */ |
unsigned char s_scnptr[4]; /* file ptr to raw data for section */ |
unsigned char s_relptr[4]; /* file ptr to relocation */ |
unsigned char s_lnnoptr[4]; /* file ptr to line numbers */ |
unsigned char s_nreloc[2]; /* number of relocation entries */ |
unsigned char s_nlnno[2]; /* number of line number entries */ |
unsigned char s_flags[4]; /* flags */ |
}; |
/* The length of the s_name field in struct external_scnhdr. */ |
#define SCNNMLEN (8) |
/* Bits for scnhdr s_flags field. This includes some bits defined |
only for PE. This may need to be moved into coff_magic. */ |
#define STYP_DATA (1 << 6) |
#define IMAGE_SCN_MEM_DISCARDABLE (1 << 25) |
#define IMAGE_SCN_MEM_SHARED (1 << 28) |
#define IMAGE_SCN_MEM_READ (1 << 30) |
#define IMAGE_SCN_ALIGN_POWER_BIT_POS 20 |
#define IMAGE_SCN_ALIGN_POWER_CONST(val) \ |
(((val) + 1) << IMAGE_SCN_ALIGN_POWER_BIT_POS) |
/* COFF symbol table entry. */ |
#define E_SYMNMLEN 8 /* # characters in a symbol name */ |
struct external_syment |
{ |
union |
{ |
unsigned char e_name[E_SYMNMLEN]; |
struct |
{ |
unsigned char e_zeroes[4]; |
unsigned char e_offset[4]; |
} e; |
} e; |
unsigned char e_value[4]; |
unsigned char e_scnum[2]; |
unsigned char e_type[2]; |
unsigned char e_sclass[1]; |
unsigned char e_numaux[1]; |
}; |
/* Length allowed for filename in aux sym format 4. */ |
#define E_FILNMLEN 18 |
/* Omits x_sym and other unused variants. */ |
union external_auxent |
{ |
/* Aux sym format 4: file. */ |
union |
{ |
char x_fname[E_FILNMLEN]; |
struct |
{ |
unsigned char x_zeroes[4]; |
unsigned char x_offset[4]; |
} x_n; |
} x_file; |
/* Aux sym format 5: section. */ |
struct |
{ |
unsigned char x_scnlen[4]; /* section length */ |
unsigned char x_nreloc[2]; /* # relocation entries */ |
unsigned char x_nlinno[2]; /* # line numbers */ |
unsigned char x_checksum[4]; /* section COMDAT checksum */ |
unsigned char x_associated[2]; /* COMDAT assoc section index */ |
unsigned char x_comdat[1]; /* COMDAT selection number */ |
} x_scn; |
}; |
/* Symbol-related constants. */ |
#define IMAGE_SYM_DEBUG (-2) |
#define IMAGE_SYM_TYPE_NULL (0) |
#define IMAGE_SYM_DTYPE_NULL (0) |
#define IMAGE_SYM_CLASS_STATIC (3) |
#define IMAGE_SYM_CLASS_FILE (103) |
#define IMAGE_SYM_TYPE \ |
((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL) |
/* Private data for an simple_object_read. */ |
struct simple_object_coff_read |
{ |
/* Magic number. */ |
unsigned short magic; |
/* Whether the file is big-endian. */ |
unsigned char is_big_endian; |
/* Number of sections. */ |
unsigned short nscns; |
/* File offset of symbol table. */ |
off_t symptr; |
/* Number of symbol table entries. */ |
unsigned int nsyms; |
/* Flags. */ |
unsigned short flags; |
/* Offset of section headers in file. */ |
off_t scnhdr_offset; |
}; |
/* Private data for an simple_object_attributes. */ |
struct simple_object_coff_attributes |
{ |
/* Magic number. */ |
unsigned short magic; |
/* Whether the file is big-endian. */ |
unsigned char is_big_endian; |
/* Flags. */ |
unsigned short flags; |
}; |
/* There is no magic number which indicates a COFF file as opposed to |
any other sort of file. Instead, each COFF file starts with a |
two-byte magic number which also indicates the type of the target. |
This struct holds a magic number as well as characteristics of that |
COFF format. */ |
struct coff_magic_struct |
{ |
/* Magic number. */ |
unsigned short magic; |
/* Whether this magic number is for a big-endian file. */ |
unsigned char is_big_endian; |
/* Flag bits, in the f_flags fields, which indicates that this file |
is not a relocatable object file. There is no flag which |
specifically indicates a relocatable object file, it is only |
implied by the absence of these flags. */ |
unsigned short non_object_flags; |
}; |
/* This is a list of the COFF magic numbers which we recognize, namely |
the ones used on Windows. More can be added as needed. */ |
static const struct coff_magic_struct coff_magic[] = |
{ |
/* i386. */ |
{ 0x14c, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL }, |
/* x86_64. */ |
{ 0x8664, 0, F_EXEC | IMAGE_FILE_SYSTEM | IMAGE_FILE_DLL } |
}; |
/* See if we have a COFF file. */ |
static void * |
simple_object_coff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], |
int descriptor, off_t offset, |
const char *segment_name ATTRIBUTE_UNUSED, |
const char **errmsg, int *err) |
{ |
size_t c; |
unsigned short magic_big; |
unsigned short magic_little; |
unsigned short magic; |
size_t i; |
int is_big_endian; |
unsigned short (*fetch_16) (const unsigned char *); |
unsigned int (*fetch_32) (const unsigned char *); |
unsigned char hdrbuf[sizeof (struct external_filehdr)]; |
unsigned short flags; |
struct simple_object_coff_read *ocr; |
c = sizeof (coff_magic) / sizeof (coff_magic[0]); |
magic_big = simple_object_fetch_big_16 (header); |
magic_little = simple_object_fetch_little_16 (header); |
for (i = 0; i < c; ++i) |
{ |
if (coff_magic[i].is_big_endian |
? coff_magic[i].magic == magic_big |
: coff_magic[i].magic == magic_little) |
break; |
} |
if (i >= c) |
{ |
*errmsg = NULL; |
*err = 0; |
return NULL; |
} |
is_big_endian = coff_magic[i].is_big_endian; |
magic = is_big_endian ? magic_big : magic_little; |
fetch_16 = (is_big_endian |
? simple_object_fetch_big_16 |
: simple_object_fetch_little_16); |
fetch_32 = (is_big_endian |
? simple_object_fetch_big_32 |
: simple_object_fetch_little_32); |
if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf, |
errmsg, err)) |
return NULL; |
flags = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_flags)); |
if ((flags & coff_magic[i].non_object_flags) != 0) |
{ |
*errmsg = "not relocatable object file"; |
*err = 0; |
return NULL; |
} |
ocr = XNEW (struct simple_object_coff_read); |
ocr->magic = magic; |
ocr->is_big_endian = is_big_endian; |
ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns)); |
ocr->symptr = fetch_32 (hdrbuf |
+ offsetof (struct external_filehdr, f_symptr)); |
ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, f_nsyms)); |
ocr->flags = flags; |
ocr->scnhdr_offset = (sizeof (struct external_filehdr) |
+ fetch_16 (hdrbuf + offsetof (struct external_filehdr, |
f_opthdr))); |
return (void *) ocr; |
} |
/* Read the string table in a COFF file. */ |
static char * |
simple_object_coff_read_strtab (simple_object_read *sobj, size_t *strtab_size, |
const char **errmsg, int *err) |
{ |
struct simple_object_coff_read *ocr = |
(struct simple_object_coff_read *) sobj->data; |
off_t strtab_offset; |
unsigned char strsizebuf[4]; |
size_t strsize; |
char *strtab; |
strtab_offset = sobj->offset + ocr->symptr |
+ ocr->nsyms * sizeof (struct external_syment); |
if (!simple_object_internal_read (sobj->descriptor, strtab_offset, |
strsizebuf, 4, errmsg, err)) |
return NULL; |
strsize = (ocr->is_big_endian |
? simple_object_fetch_big_32 (strsizebuf) |
: simple_object_fetch_little_32 (strsizebuf)); |
strtab = XNEWVEC (char, strsize); |
if (!simple_object_internal_read (sobj->descriptor, strtab_offset, |
(unsigned char *) strtab, strsize, errmsg, |
err)) |
{ |
XDELETEVEC (strtab); |
return NULL; |
} |
*strtab_size = strsize; |
return strtab; |
} |
/* Find all sections in a COFF file. */ |
static const char * |
simple_object_coff_find_sections (simple_object_read *sobj, |
int (*pfn) (void *, const char *, |
off_t offset, off_t length), |
void *data, |
int *err) |
{ |
struct simple_object_coff_read *ocr = |
(struct simple_object_coff_read *) sobj->data; |
size_t scnhdr_size; |
unsigned char *scnbuf; |
const char *errmsg; |
unsigned int (*fetch_32) (const unsigned char *); |
unsigned int nscns; |
char *strtab; |
size_t strtab_size; |
unsigned int i; |
scnhdr_size = sizeof (struct external_scnhdr); |
scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns); |
if (!simple_object_internal_read (sobj->descriptor, |
sobj->offset + ocr->scnhdr_offset, |
scnbuf, scnhdr_size * ocr->nscns, &errmsg, |
err)) |
{ |
XDELETEVEC (scnbuf); |
return errmsg; |
} |
fetch_32 = (ocr->is_big_endian |
? simple_object_fetch_big_32 |
: simple_object_fetch_little_32); |
nscns = ocr->nscns; |
strtab = NULL; |
strtab_size = 0; |
for (i = 0; i < nscns; ++i) |
{ |
unsigned char *scnhdr; |
unsigned char *scnname; |
char namebuf[SCNNMLEN + 1]; |
char *name; |
off_t scnptr; |
unsigned int size; |
scnhdr = scnbuf + i * scnhdr_size; |
scnname = scnhdr + offsetof (struct external_scnhdr, s_name); |
memcpy (namebuf, scnname, SCNNMLEN); |
namebuf[SCNNMLEN] = '\0'; |
name = &namebuf[0]; |
if (namebuf[0] == '/') |
{ |
size_t strindex; |
char *end; |
strindex = strtol (namebuf + 1, &end, 10); |
if (*end == '\0') |
{ |
/* The real section name is found in the string |
table. */ |
if (strtab == NULL) |
{ |
strtab = simple_object_coff_read_strtab (sobj, |
&strtab_size, |
&errmsg, err); |
if (strtab == NULL) |
{ |
XDELETEVEC (scnbuf); |
return errmsg; |
} |
} |
if (strindex < 4 || strindex >= strtab_size) |
{ |
XDELETEVEC (strtab); |
XDELETEVEC (scnbuf); |
*err = 0; |
return "section string index out of range"; |
} |
name = strtab + strindex; |
} |
} |
scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_scnptr)); |
size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, s_size)); |
if (!(*pfn) (data, name, scnptr, size)) |
break; |
} |
if (strtab != NULL) |
XDELETEVEC (strtab); |
XDELETEVEC (scnbuf); |
return NULL; |
} |
/* Fetch the attributes for an simple_object_read. */ |
static void * |
simple_object_coff_fetch_attributes (simple_object_read *sobj, |
const char **errmsg ATTRIBUTE_UNUSED, |
int *err ATTRIBUTE_UNUSED) |
{ |
struct simple_object_coff_read *ocr = |
(struct simple_object_coff_read *) sobj->data; |
struct simple_object_coff_attributes *ret; |
ret = XNEW (struct simple_object_coff_attributes); |
ret->magic = ocr->magic; |
ret->is_big_endian = ocr->is_big_endian; |
ret->flags = ocr->flags; |
return ret; |
} |
/* Release the private data for an simple_object_read. */ |
static void |
simple_object_coff_release_read (void *data) |
{ |
XDELETE (data); |
} |
/* Compare two attributes structures. */ |
static const char * |
simple_object_coff_attributes_merge (void *todata, void *fromdata, int *err) |
{ |
struct simple_object_coff_attributes *to = |
(struct simple_object_coff_attributes *) todata; |
struct simple_object_coff_attributes *from = |
(struct simple_object_coff_attributes *) fromdata; |
if (to->magic != from->magic || to->is_big_endian != from->is_big_endian) |
{ |
*err = 0; |
return "COFF object format mismatch"; |
} |
return NULL; |
} |
/* Release the private data for an attributes structure. */ |
static void |
simple_object_coff_release_attributes (void *data) |
{ |
XDELETE (data); |
} |
/* Prepare to write out a file. */ |
static void * |
simple_object_coff_start_write (void *attributes_data, |
const char **errmsg ATTRIBUTE_UNUSED, |
int *err ATTRIBUTE_UNUSED) |
{ |
struct simple_object_coff_attributes *attrs = |
(struct simple_object_coff_attributes *) attributes_data; |
struct simple_object_coff_attributes *ret; |
/* We're just going to record the attributes, but we need to make a |
copy because the user may delete them. */ |
ret = XNEW (struct simple_object_coff_attributes); |
*ret = *attrs; |
return ret; |
} |
/* Write out a COFF filehdr. */ |
static int |
simple_object_coff_write_filehdr (simple_object_write *sobj, int descriptor, |
unsigned int nscns, size_t symtab_offset, |
unsigned int nsyms, const char **errmsg, |
int *err) |
{ |
struct simple_object_coff_attributes *attrs = |
(struct simple_object_coff_attributes *) sobj->data; |
unsigned char hdrbuf[sizeof (struct external_filehdr)]; |
unsigned char *hdr; |
void (*set_16) (unsigned char *, unsigned short); |
void (*set_32) (unsigned char *, unsigned int); |
hdr = &hdrbuf[0]; |
set_16 = (attrs->is_big_endian |
? simple_object_set_big_16 |
: simple_object_set_little_16); |
set_32 = (attrs->is_big_endian |
? simple_object_set_big_32 |
: simple_object_set_little_32); |
memset (hdr, 0, sizeof (struct external_filehdr)); |
set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic); |
set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns); |
/* f_timdat left as zero. */ |
set_32 (hdr + offsetof (struct external_filehdr, f_symptr), symtab_offset); |
set_32 (hdr + offsetof (struct external_filehdr, f_nsyms), nsyms); |
/* f_opthdr left as zero. */ |
set_16 (hdr + offsetof (struct external_filehdr, f_flags), attrs->flags); |
return simple_object_internal_write (descriptor, 0, hdrbuf, |
sizeof (struct external_filehdr), |
errmsg, err); |
} |
/* Write out a COFF section header. */ |
static int |
simple_object_coff_write_scnhdr (simple_object_write *sobj, int descriptor, |
const char *name, size_t *name_offset, |
off_t scnhdr_offset, size_t scnsize, |
off_t offset, unsigned int align, |
const char **errmsg, int *err) |
{ |
struct simple_object_coff_attributes *attrs = |
(struct simple_object_coff_attributes *) sobj->data; |
void (*set_32) (unsigned char *, unsigned int); |
unsigned char hdrbuf[sizeof (struct external_scnhdr)]; |
unsigned char *hdr; |
size_t namelen; |
unsigned int flags; |
set_32 = (attrs->is_big_endian |
? simple_object_set_big_32 |
: simple_object_set_little_32); |
memset (hdrbuf, 0, sizeof hdrbuf); |
hdr = &hdrbuf[0]; |
namelen = strlen (name); |
if (namelen <= SCNNMLEN) |
strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), name, |
SCNNMLEN); |
else |
{ |
snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name), |
SCNNMLEN, "/%lu", (unsigned long) *name_offset); |
*name_offset += namelen + 1; |
} |
/* s_paddr left as zero. */ |
/* s_vaddr left as zero. */ |
set_32 (hdr + offsetof (struct external_scnhdr, s_size), scnsize); |
set_32 (hdr + offsetof (struct external_scnhdr, s_scnptr), offset); |
/* s_relptr left as zero. */ |
/* s_lnnoptr left as zero. */ |
/* s_nreloc left as zero. */ |
/* s_nlnno left as zero. */ |
flags = (STYP_DATA | IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_MEM_SHARED |
| IMAGE_SCN_MEM_READ); |
/* PE can represent alignment up to 13. */ |
if (align > 13) |
align = 13; |
flags |= IMAGE_SCN_ALIGN_POWER_CONST(align); |
set_32 (hdr + offsetof (struct external_scnhdr, s_flags), flags); |
return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf, |
sizeof (struct external_scnhdr), |
errmsg, err); |
} |
/* Write out a complete COFF file. */ |
static const char * |
simple_object_coff_write_to_file (simple_object_write *sobj, int descriptor, |
int *err) |
{ |
struct simple_object_coff_attributes *attrs = |
(struct simple_object_coff_attributes *) sobj->data; |
unsigned int nscns, secnum; |
simple_object_write_section *section; |
off_t scnhdr_offset; |
size_t symtab_offset; |
off_t secsym_offset; |
unsigned int nsyms; |
size_t offset; |
size_t name_offset; |
const char *errmsg; |
unsigned char strsizebuf[4]; |
/* The interface doesn't give us access to the name of the input file |
yet. We want to use its basename for the FILE symbol. This is |
what 'gas' uses when told to assemble from stdin. */ |
const char *source_filename = "fake"; |
size_t sflen; |
union |
{ |
struct external_syment sym; |
union external_auxent aux; |
} syms[2]; |
void (*set_16) (unsigned char *, unsigned short); |
void (*set_32) (unsigned char *, unsigned int); |
set_16 = (attrs->is_big_endian |
? simple_object_set_big_16 |
: simple_object_set_little_16); |
set_32 = (attrs->is_big_endian |
? simple_object_set_big_32 |
: simple_object_set_little_32); |
nscns = 0; |
for (section = sobj->sections; section != NULL; section = section->next) |
++nscns; |
scnhdr_offset = sizeof (struct external_filehdr); |
offset = scnhdr_offset + nscns * sizeof (struct external_scnhdr); |
name_offset = 4; |
for (section = sobj->sections; section != NULL; section = section->next) |
{ |
size_t mask; |
size_t new_offset; |
size_t scnsize; |
struct simple_object_write_section_buffer *buffer; |
mask = (1U << section->align) - 1; |
new_offset = offset & mask; |
new_offset &= ~ mask; |
while (new_offset > offset) |
{ |
unsigned char zeroes[16]; |
size_t write; |
memset (zeroes, 0, sizeof zeroes); |
write = new_offset - offset; |
if (write > sizeof zeroes) |
write = sizeof zeroes; |
if (!simple_object_internal_write (descriptor, offset, zeroes, write, |
&errmsg, err)) |
return errmsg; |
} |
scnsize = 0; |
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) |
{ |
if (!simple_object_internal_write (descriptor, offset + scnsize, |
((const unsigned char *) |
buffer->buffer), |
buffer->size, &errmsg, err)) |
return errmsg; |
scnsize += buffer->size; |
} |
if (!simple_object_coff_write_scnhdr (sobj, descriptor, section->name, |
&name_offset, scnhdr_offset, |
scnsize, offset, section->align, |
&errmsg, err)) |
return errmsg; |
scnhdr_offset += sizeof (struct external_scnhdr); |
offset += scnsize; |
} |
/* Symbol table is always half-word aligned. */ |
offset += (offset & 1); |
/* There is a file symbol and a section symbol per section, |
and each of these has a single auxiliary symbol following. */ |
nsyms = 2 * (nscns + 1); |
symtab_offset = offset; |
/* Advance across space reserved for symbol table to locate |
start of string table. */ |
offset += nsyms * sizeof (struct external_syment); |
/* Write out file symbol. */ |
memset (&syms[0], 0, sizeof (syms)); |
strcpy ((char *)&syms[0].sym.e.e_name[0], ".file"); |
set_16 (&syms[0].sym.e_scnum[0], IMAGE_SYM_DEBUG); |
set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); |
syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_FILE; |
syms[0].sym.e_numaux[0] = 1; |
/* The name need not be nul-terminated if it fits into the x_fname field |
directly, but must be if it has to be placed into the string table. */ |
sflen = strlen (source_filename); |
if (sflen <= E_FILNMLEN) |
memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen); |
else |
{ |
set_32 (&syms[1].aux.x_file.x_n.x_offset[0], name_offset); |
if (!simple_object_internal_write (descriptor, offset + name_offset, |
((const unsigned char *) |
source_filename), |
sflen + 1, &errmsg, err)) |
return errmsg; |
name_offset += strlen (source_filename) + 1; |
} |
if (!simple_object_internal_write (descriptor, symtab_offset, |
(const unsigned char *) &syms[0], |
sizeof (syms), &errmsg, err)) |
return errmsg; |
/* Write the string table length, followed by the strings and section |
symbols in step with each other. */ |
set_32 (strsizebuf, name_offset); |
if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4, |
&errmsg, err)) |
return errmsg; |
name_offset = 4; |
secsym_offset = symtab_offset + sizeof (syms); |
memset (&syms[0], 0, sizeof (syms)); |
set_16 (&syms[0].sym.e_type[0], IMAGE_SYM_TYPE); |
syms[0].sym.e_sclass[0] = IMAGE_SYM_CLASS_STATIC; |
syms[0].sym.e_numaux[0] = 1; |
secnum = 1; |
for (section = sobj->sections; section != NULL; section = section->next) |
{ |
size_t namelen; |
size_t scnsize; |
struct simple_object_write_section_buffer *buffer; |
namelen = strlen (section->name); |
set_16 (&syms[0].sym.e_scnum[0], secnum++); |
scnsize = 0; |
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) |
scnsize += buffer->size; |
set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize); |
if (namelen > SCNNMLEN) |
{ |
set_32 (&syms[0].sym.e.e.e_zeroes[0], 0); |
set_32 (&syms[0].sym.e.e.e_offset[0], name_offset); |
if (!simple_object_internal_write (descriptor, offset + name_offset, |
((const unsigned char *) |
section->name), |
namelen + 1, &errmsg, err)) |
return errmsg; |
name_offset += namelen + 1; |
} |
else |
{ |
memcpy (&syms[0].sym.e.e_name[0], section->name, |
strlen (section->name)); |
memset (&syms[0].sym.e.e_name[strlen (section->name)], 0, |
E_SYMNMLEN - strlen (section->name)); |
} |
if (!simple_object_internal_write (descriptor, secsym_offset, |
(const unsigned char *) &syms[0], |
sizeof (syms), &errmsg, err)) |
return errmsg; |
secsym_offset += sizeof (syms); |
} |
if (!simple_object_coff_write_filehdr (sobj, descriptor, nscns, |
symtab_offset, nsyms, &errmsg, err)) |
return errmsg; |
return NULL; |
} |
/* Release the private data for an simple_object_write structure. */ |
static void |
simple_object_coff_release_write (void *data) |
{ |
XDELETE (data); |
} |
/* The COFF functions. */ |
const struct simple_object_functions simple_object_coff_functions = |
{ |
simple_object_coff_match, |
simple_object_coff_find_sections, |
simple_object_coff_fetch_attributes, |
simple_object_coff_release_read, |
simple_object_coff_attributes_merge, |
simple_object_coff_release_attributes, |
simple_object_coff_start_write, |
simple_object_coff_write_to_file, |
simple_object_coff_release_write |
}; |
/contrib/toolchain/binutils/libiberty/simple-object-common.h |
---|
0,0 → 1,356 |
/* simple-object-common.h -- common structs for object file manipulation. |
Copyright (C) 2010 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If not, |
write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* Forward reference. */ |
struct simple_object_functions; |
/* An object file opened for reading. */ |
struct simple_object_read_struct |
{ |
/* The file descriptor. */ |
int descriptor; |
/* The offset within the file. */ |
off_t offset; |
/* The functions which do the actual work. */ |
const struct simple_object_functions *functions; |
/* Private data for the object file format. */ |
void *data; |
}; |
/* Object file attributes. */ |
struct simple_object_attributes_struct |
{ |
/* The functions which do the actual work. */ |
const struct simple_object_functions *functions; |
/* Private data for the object file format. */ |
void *data; |
}; |
/* An object file being created. */ |
struct simple_object_write_struct |
{ |
/* The functions which do the actual work. */ |
const struct simple_object_functions *functions; |
/* The segment_name argument from the user. */ |
char *segment_name; |
/* The start of the list of sections. */ |
simple_object_write_section *sections; |
/* The last entry in the list of sections. */ |
simple_object_write_section *last_section; |
/* Private data for the object file format. */ |
void *data; |
}; |
/* A section in an object file being created. */ |
struct simple_object_write_section_struct |
{ |
/* Next in the list of sections attached to an |
simple_object_write. */ |
simple_object_write_section *next; |
/* The name of this section. */ |
char *name; |
/* The required alignment. */ |
unsigned int align; |
/* The first data attached to this section. */ |
struct simple_object_write_section_buffer *buffers; |
/* The last data attached to this section. */ |
struct simple_object_write_section_buffer *last_buffer; |
}; |
/* Data attached to a section. */ |
struct simple_object_write_section_buffer |
{ |
/* The next data for this section. */ |
struct simple_object_write_section_buffer *next; |
/* The size of the buffer. */ |
size_t size; |
/* The actual bytes. */ |
const void *buffer; |
/* A buffer to free, or NULL. */ |
void *free_buffer; |
}; |
/* The number of bytes we read from the start of the file to pass to |
the match function. */ |
#define SIMPLE_OBJECT_MATCH_HEADER_LEN (16) |
/* Format-specific object file functions. */ |
struct simple_object_functions |
{ |
/* If this file matches these functions, return a new value for the |
private data for an simple_object_read. HEADER is the first 16 |
bytes of the file. DESCRIPTOR, OFFSET, SEGMENT_NAME, ERRMSG, and |
ERR are as for simple_object_open_read. If this file does not |
match, this function should return NULL with *ERRMSG set to |
NULL. */ |
void *(*match) (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], |
int descriptor, off_t offset, const char *segment_name, |
const char **errmsg, int *err); |
/* Implement simple_object_find_sections. */ |
const char *(*find_sections) (simple_object_read *, |
int (*pfn) (void *, const char *, |
off_t offset, off_t length), |
void *data, |
int *err); |
/* Return the private data for the attributes for SOBJ. */ |
void *(*fetch_attributes) (simple_object_read *sobj, const char **errmsg, |
int *err); |
/* Release the private data for an simple_object_read. */ |
void (*release_read) (void *); |
/* Merge the private data for the attributes of two files. If they |
could be linked together, return NULL. Otherwise return an error |
message. */ |
const char *(*attributes_merge) (void *, void *, int *err); |
/* Release the private data for an simple_object_attributes. */ |
void (*release_attributes) (void *); |
/* Start creating an object file. */ |
void *(*start_write) (void *attributes_data, const char **errmsg, |
int *err); |
/* Write the complete object file. */ |
const char *(*write_to_file) (simple_object_write *sobj, int descriptor, |
int *err); |
/* Release the private data for an simple_object_write. */ |
void (*release_write) (void *); |
}; |
/* The known object file formats. */ |
extern const struct simple_object_functions simple_object_coff_functions; |
extern const struct simple_object_functions simple_object_elf_functions; |
extern const struct simple_object_functions simple_object_mach_o_functions; |
extern const struct simple_object_functions simple_object_xcoff_functions; |
/* Read SIZE bytes from DESCRIPTOR at file offset OFFSET into BUFFER. |
Return non-zero on success. On failure return 0 and set *ERRMSG |
and *ERR. */ |
extern int |
simple_object_internal_read (int descriptor, off_t offset, |
unsigned char *buffer, size_t size, |
const char **errmsg, int *err); |
/* Write SIZE bytes from BUFFER to DESCRIPTOR at file offset OFFSET. |
Return non-zero on success. On failure return 0 and set *ERRMSG |
and *ERR. */ |
extern int |
simple_object_internal_write (int descriptor, off_t offset, |
const unsigned char *buffer, size_t size, |
const char **errmsg, int *err); |
/* Define ulong_type as an unsigned 64-bit type if available. |
Otherwise just make it unsigned long. */ |
#ifdef UNSIGNED_64BIT_TYPE |
__extension__ typedef UNSIGNED_64BIT_TYPE ulong_type; |
#else |
typedef unsigned long ulong_type; |
#endif |
/* Fetch a big-endian 16-bit value. */ |
static inline unsigned short |
simple_object_fetch_big_16 (const unsigned char *buf) |
{ |
return ((unsigned short) buf[0] << 8) | (unsigned short) buf[1]; |
} |
/* Fetch a little-endian 16-bit value. */ |
static inline unsigned short |
simple_object_fetch_little_16 (const unsigned char *buf) |
{ |
return ((unsigned short) buf[1] << 8) | (unsigned short) buf[0]; |
} |
/* Fetch a big-endian 32-bit value. */ |
static inline unsigned int |
simple_object_fetch_big_32 (const unsigned char *buf) |
{ |
return (((unsigned int) buf[0] << 24) |
| ((unsigned int) buf[1] << 16) |
| ((unsigned int) buf[2] << 8) |
| (unsigned int) buf[3]); |
} |
/* Fetch a little-endian 32-bit value. */ |
static inline unsigned int |
simple_object_fetch_little_32 (const unsigned char *buf) |
{ |
return (((unsigned int) buf[3] << 24) |
| ((unsigned int) buf[2] << 16) |
| ((unsigned int) buf[1] << 8) |
| (unsigned int) buf[0]); |
} |
/* Fetch a big-endian 32-bit value as a ulong_type. */ |
static inline ulong_type |
simple_object_fetch_big_32_ulong (const unsigned char *buf) |
{ |
return (ulong_type) simple_object_fetch_big_32 (buf); |
} |
/* Fetch a little-endian 32-bit value as a ulong_type. */ |
static inline ulong_type |
simple_object_fetch_little_32_ulong (const unsigned char *buf) |
{ |
return (ulong_type) simple_object_fetch_little_32 (buf); |
} |
#ifdef UNSIGNED_64BIT_TYPE |
/* Fetch a big-endian 64-bit value. */ |
static inline ulong_type |
simple_object_fetch_big_64 (const unsigned char *buf) |
{ |
return (((ulong_type) buf[0] << 56) |
| ((ulong_type) buf[1] << 48) |
| ((ulong_type) buf[2] << 40) |
| ((ulong_type) buf[3] << 32) |
| ((ulong_type) buf[4] << 24) |
| ((ulong_type) buf[5] << 16) |
| ((ulong_type) buf[6] << 8) |
| (ulong_type) buf[7]); |
} |
/* Fetch a little-endian 64-bit value. */ |
static inline ulong_type |
simple_object_fetch_little_64 (const unsigned char *buf) |
{ |
return (((ulong_type) buf[7] << 56) |
| ((ulong_type) buf[6] << 48) |
| ((ulong_type) buf[5] << 40) |
| ((ulong_type) buf[4] << 32) |
| ((ulong_type) buf[3] << 24) |
| ((ulong_type) buf[2] << 16) |
| ((ulong_type) buf[1] << 8) |
| (ulong_type) buf[0]); |
} |
#endif |
/* Store a big-endian 16-bit value. */ |
static inline void |
simple_object_set_big_16 (unsigned char *buf, unsigned short val) |
{ |
buf[0] = (val >> 8) & 0xff; |
buf[1] = val & 0xff; |
} |
/* Store a little-endian 16-bit value. */ |
static inline void |
simple_object_set_little_16 (unsigned char *buf, unsigned short val) |
{ |
buf[1] = (val >> 8) & 0xff; |
buf[0] = val & 0xff; |
} |
/* Store a big-endian 32-bit value. */ |
static inline void |
simple_object_set_big_32 (unsigned char *buf, unsigned int val) |
{ |
buf[0] = (val >> 24) & 0xff; |
buf[1] = (val >> 16) & 0xff; |
buf[2] = (val >> 8) & 0xff; |
buf[3] = val & 0xff; |
} |
/* Store a little-endian 32-bit value. */ |
static inline void |
simple_object_set_little_32 (unsigned char *buf, unsigned int val) |
{ |
buf[3] = (val >> 24) & 0xff; |
buf[2] = (val >> 16) & 0xff; |
buf[1] = (val >> 8) & 0xff; |
buf[0] = val & 0xff; |
} |
/* Store a big-endian 32-bit value coming in as a ulong_type. */ |
static inline void |
simple_object_set_big_32_ulong (unsigned char *buf, ulong_type val) |
{ |
simple_object_set_big_32 (buf, val); |
} |
/* Store a little-endian 32-bit value coming in as a ulong_type. */ |
static inline void |
simple_object_set_little_32_ulong (unsigned char *buf, ulong_type val) |
{ |
simple_object_set_little_32 (buf, val); |
} |
#ifdef UNSIGNED_64BIT_TYPE |
/* Store a big-endian 64-bit value. */ |
static inline void |
simple_object_set_big_64 (unsigned char *buf, ulong_type val) |
{ |
buf[0] = (val >> 56) & 0xff; |
buf[1] = (val >> 48) & 0xff; |
buf[2] = (val >> 40) & 0xff; |
buf[3] = (val >> 32) & 0xff; |
buf[4] = (val >> 24) & 0xff; |
buf[5] = (val >> 16) & 0xff; |
buf[6] = (val >> 8) & 0xff; |
buf[7] = val & 0xff; |
} |
/* Store a little-endian 64-bit value. */ |
static inline void |
simple_object_set_little_64 (unsigned char *buf, ulong_type val) |
{ |
buf[7] = (val >> 56) & 0xff; |
buf[6] = (val >> 48) & 0xff; |
buf[5] = (val >> 40) & 0xff; |
buf[4] = (val >> 32) & 0xff; |
buf[3] = (val >> 24) & 0xff; |
buf[2] = (val >> 16) & 0xff; |
buf[1] = (val >> 8) & 0xff; |
buf[0] = val & 0xff; |
} |
#endif |
/contrib/toolchain/binutils/libiberty/simple-object-elf.c |
---|
0,0 → 1,953 |
/* simple-object-elf.c -- routines to manipulate ELF object files. |
Copyright 2010 Free Software Foundation, Inc. |
Written by Ian Lance Taylor, Google. |
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, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#include "config.h" |
#include "libiberty.h" |
#include "simple-object.h" |
#include <errno.h> |
#include <stddef.h> |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STDINT_H |
#include <stdint.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifdef HAVE_INTTYPES_H |
#include <inttypes.h> |
#endif |
#include "simple-object-common.h" |
/* ELF structures and constants. */ |
/* 32-bit ELF file header. */ |
typedef struct { |
unsigned char e_ident[16]; /* ELF "magic number" */ |
unsigned char e_type[2]; /* Identifies object file type */ |
unsigned char e_machine[2]; /* Specifies required architecture */ |
unsigned char e_version[4]; /* Identifies object file version */ |
unsigned char e_entry[4]; /* Entry point virtual address */ |
unsigned char e_phoff[4]; /* Program header table file offset */ |
unsigned char e_shoff[4]; /* Section header table file offset */ |
unsigned char e_flags[4]; /* Processor-specific flags */ |
unsigned char e_ehsize[2]; /* ELF header size in bytes */ |
unsigned char e_phentsize[2]; /* Program header table entry size */ |
unsigned char e_phnum[2]; /* Program header table entry count */ |
unsigned char e_shentsize[2]; /* Section header table entry size */ |
unsigned char e_shnum[2]; /* Section header table entry count */ |
unsigned char e_shstrndx[2]; /* Section header string table index */ |
} Elf32_External_Ehdr; |
/* 64-bit ELF file header. */ |
typedef struct { |
unsigned char e_ident[16]; /* ELF "magic number" */ |
unsigned char e_type[2]; /* Identifies object file type */ |
unsigned char e_machine[2]; /* Specifies required architecture */ |
unsigned char e_version[4]; /* Identifies object file version */ |
unsigned char e_entry[8]; /* Entry point virtual address */ |
unsigned char e_phoff[8]; /* Program header table file offset */ |
unsigned char e_shoff[8]; /* Section header table file offset */ |
unsigned char e_flags[4]; /* Processor-specific flags */ |
unsigned char e_ehsize[2]; /* ELF header size in bytes */ |
unsigned char e_phentsize[2]; /* Program header table entry size */ |
unsigned char e_phnum[2]; /* Program header table entry count */ |
unsigned char e_shentsize[2]; /* Section header table entry size */ |
unsigned char e_shnum[2]; /* Section header table entry count */ |
unsigned char e_shstrndx[2]; /* Section header string table index */ |
} Elf64_External_Ehdr; |
/* Indexes and values in e_ident field of Ehdr. */ |
#define EI_MAG0 0 /* File identification byte 0 index */ |
#define ELFMAG0 0x7F /* Magic number byte 0 */ |
#define EI_MAG1 1 /* File identification byte 1 index */ |
#define ELFMAG1 'E' /* Magic number byte 1 */ |
#define EI_MAG2 2 /* File identification byte 2 index */ |
#define ELFMAG2 'L' /* Magic number byte 2 */ |
#define EI_MAG3 3 /* File identification byte 3 index */ |
#define ELFMAG3 'F' /* Magic number byte 3 */ |
#define EI_CLASS 4 /* File class */ |
#define ELFCLASSNONE 0 /* Invalid class */ |
#define ELFCLASS32 1 /* 32-bit objects */ |
#define ELFCLASS64 2 /* 64-bit objects */ |
#define EI_DATA 5 /* Data encoding */ |
#define ELFDATANONE 0 /* Invalid data encoding */ |
#define ELFDATA2LSB 1 /* 2's complement, little endian */ |
#define ELFDATA2MSB 2 /* 2's complement, big endian */ |
#define EI_VERSION 6 /* File version */ |
#define EV_CURRENT 1 /* Current version */ |
#define EI_OSABI 7 /* Operating System/ABI indication */ |
/* Values for e_type field of Ehdr. */ |
#define ET_REL 1 /* Relocatable file */ |
/* Values for e_machine field of Ehdr. */ |
#define EM_SPARC 2 /* SUN SPARC */ |
#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ |
/* Special section index values. */ |
#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ |
#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ |
/* 32-bit ELF program header. */ |
typedef struct { |
unsigned char p_type[4]; /* Identifies program segment type */ |
unsigned char p_offset[4]; /* Segment file offset */ |
unsigned char p_vaddr[4]; /* Segment virtual address */ |
unsigned char p_paddr[4]; /* Segment physical address */ |
unsigned char p_filesz[4]; /* Segment size in file */ |
unsigned char p_memsz[4]; /* Segment size in memory */ |
unsigned char p_flags[4]; /* Segment flags */ |
unsigned char p_align[4]; /* Segment alignment, file & memory */ |
} Elf32_External_Phdr; |
/* 64-bit ELF program header. */ |
typedef struct { |
unsigned char p_type[4]; /* Identifies program segment type */ |
unsigned char p_flags[4]; /* Segment flags */ |
unsigned char p_offset[8]; /* Segment file offset */ |
unsigned char p_vaddr[8]; /* Segment virtual address */ |
unsigned char p_paddr[8]; /* Segment physical address */ |
unsigned char p_filesz[8]; /* Segment size in file */ |
unsigned char p_memsz[8]; /* Segment size in memory */ |
unsigned char p_align[8]; /* Segment alignment, file & memory */ |
} Elf64_External_Phdr; |
/* 32-bit ELF section header */ |
typedef struct { |
unsigned char sh_name[4]; /* Section name, index in string tbl */ |
unsigned char sh_type[4]; /* Type of section */ |
unsigned char sh_flags[4]; /* Miscellaneous section attributes */ |
unsigned char sh_addr[4]; /* Section virtual addr at execution */ |
unsigned char sh_offset[4]; /* Section file offset */ |
unsigned char sh_size[4]; /* Size of section in bytes */ |
unsigned char sh_link[4]; /* Index of another section */ |
unsigned char sh_info[4]; /* Additional section information */ |
unsigned char sh_addralign[4]; /* Section alignment */ |
unsigned char sh_entsize[4]; /* Entry size if section holds table */ |
} Elf32_External_Shdr; |
/* 64-bit ELF section header. */ |
typedef struct { |
unsigned char sh_name[4]; /* Section name, index in string tbl */ |
unsigned char sh_type[4]; /* Type of section */ |
unsigned char sh_flags[8]; /* Miscellaneous section attributes */ |
unsigned char sh_addr[8]; /* Section virtual addr at execution */ |
unsigned char sh_offset[8]; /* Section file offset */ |
unsigned char sh_size[8]; /* Size of section in bytes */ |
unsigned char sh_link[4]; /* Index of another section */ |
unsigned char sh_info[4]; /* Additional section information */ |
unsigned char sh_addralign[8]; /* Section alignment */ |
unsigned char sh_entsize[8]; /* Entry size if section holds table */ |
} Elf64_External_Shdr; |
/* Values for sh_type field. */ |
#define SHT_PROGBITS 1 /* Program data */ |
#define SHT_STRTAB 3 /* A string table */ |
/* Functions to fetch and store different ELF types, depending on the |
endianness and size. */ |
struct elf_type_functions |
{ |
unsigned short (*fetch_Elf_Half) (const unsigned char *); |
unsigned int (*fetch_Elf_Word) (const unsigned char *); |
ulong_type (*fetch_Elf_Addr) (const unsigned char *); |
void (*set_Elf_Half) (unsigned char *, unsigned short); |
void (*set_Elf_Word) (unsigned char *, unsigned int); |
void (*set_Elf_Addr) (unsigned char *, ulong_type); |
}; |
static const struct elf_type_functions elf_big_32_functions = |
{ |
simple_object_fetch_big_16, |
simple_object_fetch_big_32, |
simple_object_fetch_big_32_ulong, |
simple_object_set_big_16, |
simple_object_set_big_32, |
simple_object_set_big_32_ulong |
}; |
static const struct elf_type_functions elf_little_32_functions = |
{ |
simple_object_fetch_little_16, |
simple_object_fetch_little_32, |
simple_object_fetch_little_32_ulong, |
simple_object_set_little_16, |
simple_object_set_little_32, |
simple_object_set_little_32_ulong |
}; |
#ifdef UNSIGNED_64BIT_TYPE |
static const struct elf_type_functions elf_big_64_functions = |
{ |
simple_object_fetch_big_16, |
simple_object_fetch_big_32, |
simple_object_fetch_big_64, |
simple_object_set_big_16, |
simple_object_set_big_32, |
simple_object_set_big_64 |
}; |
static const struct elf_type_functions elf_little_64_functions = |
{ |
simple_object_fetch_little_16, |
simple_object_fetch_little_32, |
simple_object_fetch_little_64, |
simple_object_set_little_16, |
simple_object_set_little_32, |
simple_object_set_little_64 |
}; |
#endif |
/* Hideous macro to fetch the value of a field from an external ELF |
struct of some sort. TYPEFUNCS is the set of type functions. |
BUFFER points to the external data. STRUCTTYPE is the appropriate |
struct type. FIELD is a field within the struct. TYPE is the type |
of the field in the struct: Elf_Half, Elf_Word, or Elf_Addr. */ |
#define ELF_FETCH_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE) \ |
((TYPEFUNCS)->fetch_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD))) |
/* Even more hideous macro to fetch the value of FIELD from BUFFER. |
SIZE is 32 or 64. STRUCTTYPE is the name of the struct from |
elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in |
the struct. TYPE is the type of the field in the struct: Elf_Half, |
Elf_Word, or Elf_Addr. */ |
#define ELF_FETCH_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, \ |
FIELD, TYPE) \ |
ELF_FETCH_STRUCT_FIELD (TYPEFUNCS, \ |
Elf ## SIZE ## _External_ ## STRUCTTYPE, \ |
FIELD, BUFFER, TYPE) |
/* Like ELF_FETCH_SIZED_FIELD but taking an ELFCLASS value. */ |
#define ELF_FETCH_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, \ |
FIELD, TYPE) \ |
((CLASS) == ELFCLASS32 \ |
? ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \ |
TYPE) \ |
: ELF_FETCH_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \ |
TYPE)) |
/* Hideous macro to set the value of a field in an external ELF |
structure to VAL. TYPEFUNCS is the set of type functions. BUFFER |
points to the external data. STRUCTTYPE is the appropriate |
structure type. FIELD is a field within the struct. TYPE is the |
type of the field in the struct: Elf_Half, Elf_Word, or |
Elf_Addr. */ |
#define ELF_SET_STRUCT_FIELD(TYPEFUNCS, STRUCTTYPE, FIELD, BUFFER, TYPE, VAL) \ |
(TYPEFUNCS)->set_ ## TYPE ((BUFFER) + offsetof (STRUCTTYPE, FIELD), (VAL)) |
/* Even more hideous macro to set the value of FIELD in BUFFER to VAL. |
SIZE is 32 or 64. STRUCTTYPE is the name of the struct from |
elf/external.h: Ehdr, Shdr, etc. FIELD is the name of a field in |
the struct. TYPE is the type of the field in the struct: Elf_Half, |
Elf_Word, or Elf_Addr. */ |
#define ELF_SET_SIZED_FIELD(TYPEFUNCS, SIZE, STRUCTTYPE, BUFFER, FIELD, \ |
TYPE, VAL) \ |
ELF_SET_STRUCT_FIELD (TYPEFUNCS, \ |
Elf ## SIZE ## _External_ ## STRUCTTYPE, \ |
FIELD, BUFFER, TYPE, VAL) |
/* Like ELF_SET_SIZED_FIELD but taking an ELFCLASS value. */ |
#define ELF_SET_FIELD(TYPEFUNCS, CLASS, STRUCTTYPE, BUFFER, FIELD, \ |
TYPE, VAL) \ |
((CLASS) == ELFCLASS32 \ |
? ELF_SET_SIZED_FIELD (TYPEFUNCS, 32, STRUCTTYPE, BUFFER, FIELD, \ |
TYPE, VAL) \ |
: ELF_SET_SIZED_FIELD (TYPEFUNCS, 64, STRUCTTYPE, BUFFER, FIELD, \ |
TYPE, VAL)) |
/* Private data for an simple_object_read. */ |
struct simple_object_elf_read |
{ |
/* Type functions. */ |
const struct elf_type_functions* type_functions; |
/* Elf data. */ |
unsigned char ei_data; |
/* Elf class. */ |
unsigned char ei_class; |
/* ELF OS ABI. */ |
unsigned char ei_osabi; |
/* Elf machine number. */ |
unsigned short machine; |
/* Processor specific flags. */ |
unsigned int flags; |
/* File offset of section headers. */ |
ulong_type shoff; |
/* Number of sections. */ |
unsigned int shnum; |
/* Index of string table section header. */ |
unsigned int shstrndx; |
}; |
/* Private data for an simple_object_attributes. */ |
struct simple_object_elf_attributes |
{ |
/* Type functions. */ |
const struct elf_type_functions* type_functions; |
/* Elf data. */ |
unsigned char ei_data; |
/* Elf class. */ |
unsigned char ei_class; |
/* ELF OS ABI. */ |
unsigned char ei_osabi; |
/* Elf machine number. */ |
unsigned short machine; |
/* Processor specific flags. */ |
unsigned int flags; |
}; |
/* See if we have an ELF file. */ |
static void * |
simple_object_elf_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], |
int descriptor, off_t offset, |
const char *segment_name ATTRIBUTE_UNUSED, |
const char **errmsg, int *err) |
{ |
unsigned char ei_data; |
unsigned char ei_class; |
const struct elf_type_functions *type_functions; |
unsigned char ehdr[sizeof (Elf64_External_Ehdr)]; |
struct simple_object_elf_read *eor; |
if (header[EI_MAG0] != ELFMAG0 |
|| header[EI_MAG1] != ELFMAG1 |
|| header[EI_MAG2] != ELFMAG2 |
|| header[EI_MAG3] != ELFMAG3 |
|| header[EI_VERSION] != EV_CURRENT) |
{ |
*errmsg = NULL; |
*err = 0; |
return NULL; |
} |
ei_data = header[EI_DATA]; |
if (ei_data != ELFDATA2LSB && ei_data != ELFDATA2MSB) |
{ |
*errmsg = "unknown ELF endianness"; |
*err = 0; |
return NULL; |
} |
ei_class = header[EI_CLASS]; |
switch (ei_class) |
{ |
case ELFCLASS32: |
type_functions = (ei_data == ELFDATA2LSB |
? &elf_little_32_functions |
: &elf_big_32_functions); |
break; |
case ELFCLASS64: |
#ifndef UNSIGNED_64BIT_TYPE |
*errmsg = "64-bit ELF objects not supported"; |
*err = 0; |
return NULL; |
#else |
type_functions = (ei_data == ELFDATA2LSB |
? &elf_little_64_functions |
: &elf_big_64_functions); |
break; |
#endif |
default: |
*errmsg = "unrecognized ELF size"; |
*err = 0; |
return NULL; |
} |
if (!simple_object_internal_read (descriptor, offset, ehdr, sizeof ehdr, |
errmsg, err)) |
return NULL; |
eor = XNEW (struct simple_object_elf_read); |
eor->type_functions = type_functions; |
eor->ei_data = ei_data; |
eor->ei_class = ei_class; |
eor->ei_osabi = header[EI_OSABI]; |
eor->machine = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, |
e_machine, Elf_Half); |
eor->flags = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, |
e_flags, Elf_Word); |
eor->shoff = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, |
e_shoff, Elf_Addr); |
eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, |
e_shnum, Elf_Half); |
eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Ehdr, ehdr, |
e_shstrndx, Elf_Half); |
if ((eor->shnum == 0 || eor->shstrndx == SHN_XINDEX) |
&& eor->shoff != 0) |
{ |
unsigned char shdr[sizeof (Elf64_External_Shdr)]; |
/* Object file has more than 0xffff sections. */ |
if (!simple_object_internal_read (descriptor, offset + eor->shoff, shdr, |
(ei_class == ELFCLASS32 |
? sizeof (Elf32_External_Shdr) |
: sizeof (Elf64_External_Shdr)), |
errmsg, err)) |
{ |
XDELETE (eor); |
return NULL; |
} |
if (eor->shnum == 0) |
eor->shnum = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
shdr, sh_size, Elf_Addr); |
if (eor->shstrndx == SHN_XINDEX) |
{ |
eor->shstrndx = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
shdr, sh_link, Elf_Word); |
/* Versions of the GNU binutils between 2.12 and 2.18 did |
not handle objects with more than SHN_LORESERVE sections |
correctly. All large section indexes were offset by |
0x100. There is more information at |
http://sourceware.org/bugzilla/show_bug.cgi?id-5900 . |
Fortunately these object files are easy to detect, as the |
GNU binutils always put the section header string table |
near the end of the list of sections. Thus if the |
section header string table index is larger than the |
number of sections, then we know we have to subtract |
0x100 to get the real section index. */ |
if (eor->shstrndx >= eor->shnum |
&& eor->shstrndx >= SHN_LORESERVE + 0x100) |
eor->shstrndx -= 0x100; |
} |
} |
if (eor->shstrndx >= eor->shnum) |
{ |
*errmsg = "invalid ELF shstrndx >= shnum"; |
*err = 0; |
XDELETE (eor); |
return NULL; |
} |
return (void *) eor; |
} |
/* Find all sections in an ELF file. */ |
static const char * |
simple_object_elf_find_sections (simple_object_read *sobj, |
int (*pfn) (void *, const char *, |
off_t offset, off_t length), |
void *data, |
int *err) |
{ |
struct simple_object_elf_read *eor = |
(struct simple_object_elf_read *) sobj->data; |
const struct elf_type_functions *type_functions = eor->type_functions; |
unsigned char ei_class = eor->ei_class; |
size_t shdr_size; |
unsigned int shnum; |
unsigned char *shdrs; |
const char *errmsg; |
unsigned char *shstrhdr; |
size_t name_size; |
off_t shstroff; |
unsigned char *names; |
unsigned int i; |
shdr_size = (ei_class == ELFCLASS32 |
? sizeof (Elf32_External_Shdr) |
: sizeof (Elf64_External_Shdr)); |
/* Read the section headers. We skip section 0, which is not a |
useful section. */ |
shnum = eor->shnum; |
shdrs = XNEWVEC (unsigned char, shdr_size * (shnum - 1)); |
if (!simple_object_internal_read (sobj->descriptor, |
sobj->offset + eor->shoff + shdr_size, |
shdrs, |
shdr_size * (shnum - 1), |
&errmsg, err)) |
{ |
XDELETEVEC (shdrs); |
return errmsg; |
} |
/* Read the section names. */ |
shstrhdr = shdrs + (eor->shstrndx - 1) * shdr_size; |
name_size = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
shstrhdr, sh_size, Elf_Addr); |
shstroff = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
shstrhdr, sh_offset, Elf_Addr); |
names = XNEWVEC (unsigned char, name_size); |
if (!simple_object_internal_read (sobj->descriptor, |
sobj->offset + shstroff, |
names, name_size, &errmsg, err)) |
{ |
XDELETEVEC (names); |
XDELETEVEC (shdrs); |
return errmsg; |
} |
for (i = 1; i < shnum; ++i) |
{ |
unsigned char *shdr; |
unsigned int sh_name; |
const char *name; |
off_t offset; |
off_t length; |
shdr = shdrs + (i - 1) * shdr_size; |
sh_name = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
shdr, sh_name, Elf_Word); |
if (sh_name >= name_size) |
{ |
*err = 0; |
XDELETEVEC (names); |
XDELETEVEC (shdrs); |
return "ELF section name out of range"; |
} |
name = (const char *) names + sh_name; |
offset = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
shdr, sh_offset, Elf_Addr); |
length = ELF_FETCH_FIELD (type_functions, ei_class, Shdr, |
shdr, sh_size, Elf_Addr); |
if (!(*pfn) (data, name, offset, length)) |
break; |
} |
XDELETEVEC (names); |
XDELETEVEC (shdrs); |
return NULL; |
} |
/* Fetch the attributes for an simple_object_read. */ |
static void * |
simple_object_elf_fetch_attributes (simple_object_read *sobj, |
const char **errmsg ATTRIBUTE_UNUSED, |
int *err ATTRIBUTE_UNUSED) |
{ |
struct simple_object_elf_read *eor = |
(struct simple_object_elf_read *) sobj->data; |
struct simple_object_elf_attributes *ret; |
ret = XNEW (struct simple_object_elf_attributes); |
ret->type_functions = eor->type_functions; |
ret->ei_data = eor->ei_data; |
ret->ei_class = eor->ei_class; |
ret->ei_osabi = eor->ei_osabi; |
ret->machine = eor->machine; |
ret->flags = eor->flags; |
return ret; |
} |
/* Release the privata data for an simple_object_read. */ |
static void |
simple_object_elf_release_read (void *data) |
{ |
XDELETE (data); |
} |
/* Compare two attributes structures. */ |
static const char * |
simple_object_elf_attributes_merge (void *todata, void *fromdata, int *err) |
{ |
struct simple_object_elf_attributes *to = |
(struct simple_object_elf_attributes *) todata; |
struct simple_object_elf_attributes *from = |
(struct simple_object_elf_attributes *) fromdata; |
if (to->ei_data != from->ei_data || to->ei_class != from->ei_class) |
{ |
*err = 0; |
return "ELF object format mismatch"; |
} |
if (to->machine != from->machine) |
{ |
int ok; |
/* EM_SPARC and EM_SPARC32PLUS are compatible and force an |
output of EM_SPARC32PLUS. */ |
ok = 0; |
switch (to->machine) |
{ |
case EM_SPARC: |
if (from->machine == EM_SPARC32PLUS) |
{ |
to->machine = from->machine; |
ok = 1; |
} |
break; |
case EM_SPARC32PLUS: |
if (from->machine == EM_SPARC) |
ok = 1; |
break; |
default: |
break; |
} |
if (!ok) |
{ |
*err = 0; |
return "ELF machine number mismatch"; |
} |
} |
return NULL; |
} |
/* Release the private data for an attributes structure. */ |
static void |
simple_object_elf_release_attributes (void *data) |
{ |
XDELETE (data); |
} |
/* Prepare to write out a file. */ |
static void * |
simple_object_elf_start_write (void *attributes_data, |
const char **errmsg ATTRIBUTE_UNUSED, |
int *err ATTRIBUTE_UNUSED) |
{ |
struct simple_object_elf_attributes *attrs = |
(struct simple_object_elf_attributes *) attributes_data; |
struct simple_object_elf_attributes *ret; |
/* We're just going to record the attributes, but we need to make a |
copy because the user may delete them. */ |
ret = XNEW (struct simple_object_elf_attributes); |
*ret = *attrs; |
return ret; |
} |
/* Write out an ELF ehdr. */ |
static int |
simple_object_elf_write_ehdr (simple_object_write *sobj, int descriptor, |
const char **errmsg, int *err) |
{ |
struct simple_object_elf_attributes *attrs = |
(struct simple_object_elf_attributes *) sobj->data; |
const struct elf_type_functions* fns; |
unsigned char cl; |
size_t ehdr_size; |
unsigned char buf[sizeof (Elf64_External_Ehdr)]; |
simple_object_write_section *section; |
unsigned int shnum; |
fns = attrs->type_functions; |
cl = attrs->ei_class; |
shnum = 0; |
for (section = sobj->sections; section != NULL; section = section->next) |
++shnum; |
if (shnum > 0) |
{ |
/* Add a section header for the dummy section and one for |
.shstrtab. */ |
shnum += 2; |
} |
ehdr_size = (cl == ELFCLASS32 |
? sizeof (Elf32_External_Ehdr) |
: sizeof (Elf64_External_Ehdr)); |
memset (buf, 0, sizeof (Elf64_External_Ehdr)); |
buf[EI_MAG0] = ELFMAG0; |
buf[EI_MAG1] = ELFMAG1; |
buf[EI_MAG2] = ELFMAG2; |
buf[EI_MAG3] = ELFMAG3; |
buf[EI_CLASS] = cl; |
buf[EI_DATA] = attrs->ei_data; |
buf[EI_VERSION] = EV_CURRENT; |
buf[EI_OSABI] = attrs->ei_osabi; |
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_type, Elf_Half, ET_REL); |
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_machine, Elf_Half, attrs->machine); |
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_version, Elf_Word, EV_CURRENT); |
/* e_entry left as zero. */ |
/* e_phoff left as zero. */ |
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shoff, Elf_Addr, ehdr_size); |
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_flags, Elf_Word, attrs->flags); |
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_ehsize, Elf_Half, ehdr_size); |
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_phentsize, Elf_Half, |
(cl == ELFCLASS32 |
? sizeof (Elf32_External_Phdr) |
: sizeof (Elf64_External_Phdr))); |
/* e_phnum left as zero. */ |
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shentsize, Elf_Half, |
(cl == ELFCLASS32 |
? sizeof (Elf32_External_Shdr) |
: sizeof (Elf64_External_Shdr))); |
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shnum, Elf_Half, shnum); |
ELF_SET_FIELD (fns, cl, Ehdr, buf, e_shstrndx, Elf_Half, |
shnum == 0 ? 0 : shnum - 1); |
return simple_object_internal_write (descriptor, 0, buf, ehdr_size, |
errmsg, err); |
} |
/* Write out an ELF shdr. */ |
static int |
simple_object_elf_write_shdr (simple_object_write *sobj, int descriptor, |
off_t offset, unsigned int sh_name, |
unsigned int sh_type, unsigned int sh_flags, |
unsigned int sh_offset, unsigned int sh_size, |
unsigned int sh_addralign, const char **errmsg, |
int *err) |
{ |
struct simple_object_elf_attributes *attrs = |
(struct simple_object_elf_attributes *) sobj->data; |
const struct elf_type_functions* fns; |
unsigned char cl; |
size_t shdr_size; |
unsigned char buf[sizeof (Elf64_External_Shdr)]; |
fns = attrs->type_functions; |
cl = attrs->ei_class; |
shdr_size = (cl == ELFCLASS32 |
? sizeof (Elf32_External_Shdr) |
: sizeof (Elf64_External_Shdr)); |
memset (buf, 0, sizeof (Elf64_External_Shdr)); |
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_name, Elf_Word, sh_name); |
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_type, Elf_Word, sh_type); |
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_flags, Elf_Addr, sh_flags); |
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_offset, Elf_Addr, sh_offset); |
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_size, Elf_Addr, sh_size); |
/* sh_link left as zero. */ |
/* sh_info left as zero. */ |
ELF_SET_FIELD (fns, cl, Shdr, buf, sh_addralign, Elf_Addr, sh_addralign); |
/* sh_entsize left as zero. */ |
return simple_object_internal_write (descriptor, offset, buf, shdr_size, |
errmsg, err); |
} |
/* Write out a complete ELF file. |
Ehdr |
initial dummy Shdr |
user-created Shdrs |
.shstrtab Shdr |
user-created section data |
.shstrtab data */ |
static const char * |
simple_object_elf_write_to_file (simple_object_write *sobj, int descriptor, |
int *err) |
{ |
struct simple_object_elf_attributes *attrs = |
(struct simple_object_elf_attributes *) sobj->data; |
unsigned char cl; |
size_t ehdr_size; |
size_t shdr_size; |
const char *errmsg; |
simple_object_write_section *section; |
unsigned int shnum; |
size_t shdr_offset; |
size_t sh_offset; |
size_t sh_name; |
unsigned char zero; |
if (!simple_object_elf_write_ehdr (sobj, descriptor, &errmsg, err)) |
return errmsg; |
cl = attrs->ei_class; |
if (cl == ELFCLASS32) |
{ |
ehdr_size = sizeof (Elf32_External_Ehdr); |
shdr_size = sizeof (Elf32_External_Shdr); |
} |
else |
{ |
ehdr_size = sizeof (Elf64_External_Ehdr); |
shdr_size = sizeof (Elf64_External_Shdr); |
} |
shnum = 0; |
for (section = sobj->sections; section != NULL; section = section->next) |
++shnum; |
if (shnum == 0) |
return NULL; |
/* Add initial dummy Shdr and .shstrtab. */ |
shnum += 2; |
shdr_offset = ehdr_size; |
sh_offset = shdr_offset + shnum * shdr_size; |
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, |
0, 0, 0, 0, 0, 0, &errmsg, err)) |
return errmsg; |
shdr_offset += shdr_size; |
sh_name = 1; |
for (section = sobj->sections; section != NULL; section = section->next) |
{ |
size_t mask; |
size_t new_sh_offset; |
size_t sh_size; |
struct simple_object_write_section_buffer *buffer; |
mask = (1U << section->align) - 1; |
new_sh_offset = sh_offset + mask; |
new_sh_offset &= ~ mask; |
while (new_sh_offset > sh_offset) |
{ |
unsigned char zeroes[16]; |
size_t write; |
memset (zeroes, 0, sizeof zeroes); |
write = new_sh_offset - sh_offset; |
if (write > sizeof zeroes) |
write = sizeof zeroes; |
if (!simple_object_internal_write (descriptor, sh_offset, zeroes, |
write, &errmsg, err)) |
return errmsg; |
sh_offset += write; |
} |
sh_size = 0; |
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) |
{ |
if (!simple_object_internal_write (descriptor, sh_offset + sh_size, |
((const unsigned char *) |
buffer->buffer), |
buffer->size, &errmsg, err)) |
return errmsg; |
sh_size += buffer->size; |
} |
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, |
sh_name, SHT_PROGBITS, 0, sh_offset, |
sh_size, 1U << section->align, |
&errmsg, err)) |
return errmsg; |
shdr_offset += shdr_size; |
sh_name += strlen (section->name) + 1; |
sh_offset += sh_size; |
} |
if (!simple_object_elf_write_shdr (sobj, descriptor, shdr_offset, |
sh_name, SHT_STRTAB, 0, sh_offset, |
sh_name + strlen (".shstrtab") + 1, |
1, &errmsg, err)) |
return errmsg; |
/* .shstrtab has a leading zero byte. */ |
zero = 0; |
if (!simple_object_internal_write (descriptor, sh_offset, &zero, 1, |
&errmsg, err)) |
return errmsg; |
++sh_offset; |
for (section = sobj->sections; section != NULL; section = section->next) |
{ |
size_t len; |
len = strlen (section->name) + 1; |
if (!simple_object_internal_write (descriptor, sh_offset, |
(const unsigned char *) section->name, |
len, &errmsg, err)) |
return errmsg; |
sh_offset += len; |
} |
if (!simple_object_internal_write (descriptor, sh_offset, |
(const unsigned char *) ".shstrtab", |
strlen (".shstrtab") + 1, &errmsg, err)) |
return errmsg; |
return NULL; |
} |
/* Release the private data for an simple_object_write structure. */ |
static void |
simple_object_elf_release_write (void *data) |
{ |
XDELETE (data); |
} |
/* The ELF functions. */ |
const struct simple_object_functions simple_object_elf_functions = |
{ |
simple_object_elf_match, |
simple_object_elf_find_sections, |
simple_object_elf_fetch_attributes, |
simple_object_elf_release_read, |
simple_object_elf_attributes_merge, |
simple_object_elf_release_attributes, |
simple_object_elf_start_write, |
simple_object_elf_write_to_file, |
simple_object_elf_release_write |
}; |
/contrib/toolchain/binutils/libiberty/simple-object-mach-o.c |
---|
0,0 → 1,1378 |
/* simple-object-mach-o.c -- routines to manipulate Mach-O object files. |
Copyright 2010, 2011, 2013 Free Software Foundation, Inc. |
Written by Ian Lance Taylor, Google. |
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, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#include "config.h" |
#include "libiberty.h" |
#include "simple-object.h" |
#include <stddef.h> |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STDINT_H |
#include <stdint.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifdef HAVE_INTTYPES_H |
#include <inttypes.h> |
#endif |
#include "simple-object-common.h" |
/* Mach-O structures and constants. */ |
/* Mach-O header (32-bit version). */ |
struct mach_o_header_32 |
{ |
unsigned char magic[4]; /* Magic number. */ |
unsigned char cputype[4]; /* CPU that this object is for. */ |
unsigned char cpusubtype[4]; /* CPU subtype. */ |
unsigned char filetype[4]; /* Type of file. */ |
unsigned char ncmds[4]; /* Number of load commands. */ |
unsigned char sizeofcmds[4]; /* Total size of load commands. */ |
unsigned char flags[4]; /* Flags for special featues. */ |
}; |
/* Mach-O header (64-bit version). */ |
struct mach_o_header_64 |
{ |
unsigned char magic[4]; /* Magic number. */ |
unsigned char cputype[4]; /* CPU that this object is for. */ |
unsigned char cpusubtype[4]; /* CPU subtype. */ |
unsigned char filetype[4]; /* Type of file. */ |
unsigned char ncmds[4]; /* Number of load commands. */ |
unsigned char sizeofcmds[4]; /* Total size of load commands. */ |
unsigned char flags[4]; /* Flags for special featues. */ |
unsigned char reserved[4]; /* Reserved. Duh. */ |
}; |
/* For magic field in header. */ |
#define MACH_O_MH_MAGIC 0xfeedface |
#define MACH_O_MH_MAGIC_64 0xfeedfacf |
/* For filetype field in header. */ |
#define MACH_O_MH_OBJECT 0x01 |
/* A Mach-O file is a list of load commands. This is the header of a |
load command. */ |
struct mach_o_load_command |
{ |
unsigned char cmd[4]; /* The type of load command. */ |
unsigned char cmdsize[4]; /* Size in bytes of entire command. */ |
}; |
/* For cmd field in load command. */ |
#define MACH_O_LC_SEGMENT 0x01 |
#define MACH_O_LC_SEGMENT_64 0x19 |
/* LC_SEGMENT load command. */ |
struct mach_o_segment_command_32 |
{ |
unsigned char cmd[4]; /* The type of load command (LC_SEGMENT). */ |
unsigned char cmdsize[4]; /* Size in bytes of entire command. */ |
unsigned char segname[16]; /* Name of this segment. */ |
unsigned char vmaddr[4]; /* Virtual memory address of this segment. */ |
unsigned char vmsize[4]; /* Size there, in bytes. */ |
unsigned char fileoff[4]; /* Offset in bytes of the data to be mapped. */ |
unsigned char filesize[4]; /* Size in bytes on disk. */ |
unsigned char maxprot[4]; /* Maximum permitted vmem protection. */ |
unsigned char initprot[4]; /* Initial vmem protection. */ |
unsigned char nsects[4]; /* Number of sections in this segment. */ |
unsigned char flags[4]; /* Flags that affect the loading. */ |
}; |
/* LC_SEGMENT_64 load command. */ |
struct mach_o_segment_command_64 |
{ |
unsigned char cmd[4]; /* The type of load command (LC_SEGMENT_64). */ |
unsigned char cmdsize[4]; /* Size in bytes of entire command. */ |
unsigned char segname[16]; /* Name of this segment. */ |
unsigned char vmaddr[8]; /* Virtual memory address of this segment. */ |
unsigned char vmsize[8]; /* Size there, in bytes. */ |
unsigned char fileoff[8]; /* Offset in bytes of the data to be mapped. */ |
unsigned char filesize[8]; /* Size in bytes on disk. */ |
unsigned char maxprot[4]; /* Maximum permitted vmem protection. */ |
unsigned char initprot[4]; /* Initial vmem protection. */ |
unsigned char nsects[4]; /* Number of sections in this segment. */ |
unsigned char flags[4]; /* Flags that affect the loading. */ |
}; |
/* 32-bit section header. */ |
struct mach_o_section_32 |
{ |
unsigned char sectname[16]; /* Section name. */ |
unsigned char segname[16]; /* Segment that the section belongs to. */ |
unsigned char addr[4]; /* Address of this section in memory. */ |
unsigned char size[4]; /* Size in bytes of this section. */ |
unsigned char offset[4]; /* File offset of this section. */ |
unsigned char align[4]; /* log2 of this section's alignment. */ |
unsigned char reloff[4]; /* File offset of this section's relocs. */ |
unsigned char nreloc[4]; /* Number of relocs for this section. */ |
unsigned char flags[4]; /* Section flags/attributes. */ |
unsigned char reserved1[4]; |
unsigned char reserved2[4]; |
}; |
/* 64-bit section header. */ |
struct mach_o_section_64 |
{ |
unsigned char sectname[16]; /* Section name. */ |
unsigned char segname[16]; /* Segment that the section belongs to. */ |
unsigned char addr[8]; /* Address of this section in memory. */ |
unsigned char size[8]; /* Size in bytes of this section. */ |
unsigned char offset[4]; /* File offset of this section. */ |
unsigned char align[4]; /* log2 of this section's alignment. */ |
unsigned char reloff[4]; /* File offset of this section's relocs. */ |
unsigned char nreloc[4]; /* Number of relocs for this section. */ |
unsigned char flags[4]; /* Section flags/attributes. */ |
unsigned char reserved1[4]; |
unsigned char reserved2[4]; |
unsigned char reserved3[4]; |
}; |
/* Flags for Mach-O sections. */ |
#define MACH_O_S_ATTR_DEBUG 0x02000000 |
/* The length of a segment or section name. */ |
#define MACH_O_NAME_LEN (16) |
/* A GNU specific extension for long section names. */ |
#define GNU_SECTION_NAMES "__section_names" |
/* A GNU-specific extension to wrap multiple sections using three |
mach-o sections within a given segment. The section '__wrapper_sects' |
is subdivided according to the index '__wrapper_index' and each sub |
sect is named according to the names supplied in '__wrapper_names'. */ |
#define GNU_WRAPPER_SECTS "__wrapper_sects" |
#define GNU_WRAPPER_INDEX "__wrapper_index" |
#define GNU_WRAPPER_NAMES "__wrapper_names" |
/* Private data for an simple_object_read. */ |
struct simple_object_mach_o_read |
{ |
/* User specified segment name. */ |
char *segment_name; |
/* Magic number. */ |
unsigned int magic; |
/* Whether this file is big-endian. */ |
int is_big_endian; |
/* CPU type from header. */ |
unsigned int cputype; |
/* CPU subtype from header. */ |
unsigned int cpusubtype; |
/* Number of commands, from header. */ |
unsigned int ncmds; |
/* Flags from header. */ |
unsigned int flags; |
/* Reserved field from header, only used on 64-bit. */ |
unsigned int reserved; |
}; |
/* Private data for an simple_object_attributes. */ |
struct simple_object_mach_o_attributes |
{ |
/* Magic number. */ |
unsigned int magic; |
/* Whether this file is big-endian. */ |
int is_big_endian; |
/* CPU type from header. */ |
unsigned int cputype; |
/* CPU subtype from header. */ |
unsigned int cpusubtype; |
/* Flags from header. */ |
unsigned int flags; |
/* Reserved field from header, only used on 64-bit. */ |
unsigned int reserved; |
}; |
/* See if we have a Mach-O MH_OBJECT file: |
A standard MH_OBJECT (from as) will have three load commands: |
0 - LC_SEGMENT/LC_SEGMENT64 |
1 - LC_SYMTAB |
2 - LC_DYSYMTAB |
The LC_SEGMENT/LC_SEGMENT64 will introduce a single anonymous segment |
containing all the sections. |
Files written by simple-object will have only the segment command |
(no symbol tables). */ |
static void * |
simple_object_mach_o_match ( |
unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], |
int descriptor, |
off_t offset, |
const char *segment_name, |
const char **errmsg, |
int *err) |
{ |
unsigned int magic; |
int is_big_endian; |
unsigned int (*fetch_32) (const unsigned char *); |
unsigned int filetype; |
struct simple_object_mach_o_read *omr; |
unsigned char buf[sizeof (struct mach_o_header_64)]; |
unsigned char *b; |
magic = simple_object_fetch_big_32 (header); |
if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64) |
is_big_endian = 1; |
else |
{ |
magic = simple_object_fetch_little_32 (header); |
if (magic == MACH_O_MH_MAGIC || magic == MACH_O_MH_MAGIC_64) |
is_big_endian = 0; |
else |
{ |
*errmsg = NULL; |
*err = 0; |
return NULL; |
} |
} |
#ifndef UNSIGNED_64BIT_TYPE |
if (magic == MACH_O_MH_MAGIC_64) |
{ |
*errmsg = "64-bit Mach-O objects not supported"; |
*err = 0; |
return NULL; |
} |
#endif |
/* We require the user to provide a segment name. This is |
unfortunate but I don't see any good choices here. */ |
if (segment_name == NULL) |
{ |
*errmsg = "Mach-O file found but no segment name specified"; |
*err = 0; |
return NULL; |
} |
if (strlen (segment_name) > MACH_O_NAME_LEN) |
{ |
*errmsg = "Mach-O segment name too long"; |
*err = 0; |
return NULL; |
} |
/* The 32-bit and 64-bit headers are similar enough that we can use |
the same code. */ |
fetch_32 = (is_big_endian |
? simple_object_fetch_big_32 |
: simple_object_fetch_little_32); |
if (!simple_object_internal_read (descriptor, offset, buf, |
(magic == MACH_O_MH_MAGIC |
? sizeof (struct mach_o_header_32) |
: sizeof (struct mach_o_header_64)), |
errmsg, err)) |
return NULL; |
b = &buf[0]; |
filetype = (*fetch_32) (b + offsetof (struct mach_o_header_32, filetype)); |
if (filetype != MACH_O_MH_OBJECT) |
{ |
*errmsg = "Mach-O file is not object file"; |
*err = 0; |
return NULL; |
} |
omr = XNEW (struct simple_object_mach_o_read); |
omr->segment_name = xstrdup (segment_name); |
omr->magic = magic; |
omr->is_big_endian = is_big_endian; |
omr->cputype = (*fetch_32) (b + offsetof (struct mach_o_header_32, cputype)); |
omr->cpusubtype = (*fetch_32) (b |
+ offsetof (struct mach_o_header_32, |
cpusubtype)); |
omr->ncmds = (*fetch_32) (b + offsetof (struct mach_o_header_32, ncmds)); |
omr->flags = (*fetch_32) (b + offsetof (struct mach_o_header_32, flags)); |
if (magic == MACH_O_MH_MAGIC) |
omr->reserved = 0; |
else |
omr->reserved = (*fetch_32) (b |
+ offsetof (struct mach_o_header_64, |
reserved)); |
return (void *) omr; |
} |
/* Get the file offset and size from a section header. */ |
static void |
simple_object_mach_o_section_info (int is_big_endian, int is_32, |
const unsigned char *sechdr, off_t *offset, |
size_t *size) |
{ |
unsigned int (*fetch_32) (const unsigned char *); |
ulong_type (*fetch_64) (const unsigned char *); |
fetch_32 = (is_big_endian |
? simple_object_fetch_big_32 |
: simple_object_fetch_little_32); |
fetch_64 = NULL; |
#ifdef UNSIGNED_64BIT_TYPE |
fetch_64 = (is_big_endian |
? simple_object_fetch_big_64 |
: simple_object_fetch_little_64); |
#endif |
if (is_32) |
{ |
*offset = fetch_32 (sechdr |
+ offsetof (struct mach_o_section_32, offset)); |
*size = fetch_32 (sechdr |
+ offsetof (struct mach_o_section_32, size)); |
} |
else |
{ |
*offset = fetch_32 (sechdr |
+ offsetof (struct mach_o_section_64, offset)); |
*size = fetch_64 (sechdr |
+ offsetof (struct mach_o_section_64, size)); |
} |
} |
/* Handle a segment in a Mach-O Object file. |
This will callback to the function pfn for each "section found" the meaning |
of which depends on gnu extensions to mach-o: |
If we find mach-o sections (with the segment name as specified) which also |
contain: a 'sects' wrapper, an index, and a name table, we expand this into |
as many sections as are specified in the index. In this case, there will |
be a callback for each of these. |
We will also allow an extension that permits long names (more than 16 |
characters) to be used with mach-o. In this case, the section name has |
a specific format embedding an index into a name table, and the file must |
contain such name table. |
Return 1 if we should continue, 0 if the caller should return. */ |
#define SOMO_SECTS_PRESENT 0x01 |
#define SOMO_INDEX_PRESENT 0x02 |
#define SOMO_NAMES_PRESENT 0x04 |
#define SOMO_LONGN_PRESENT 0x08 |
#define SOMO_WRAPPING (SOMO_SECTS_PRESENT | SOMO_INDEX_PRESENT \ |
| SOMO_NAMES_PRESENT) |
static int |
simple_object_mach_o_segment (simple_object_read *sobj, off_t offset, |
const unsigned char *segbuf, |
int (*pfn) (void *, const char *, off_t offset, |
off_t length), |
void *data, |
const char **errmsg, int *err) |
{ |
struct simple_object_mach_o_read *omr = |
(struct simple_object_mach_o_read *) sobj->data; |
unsigned int (*fetch_32) (const unsigned char *); |
int is_32; |
size_t seghdrsize; |
size_t sechdrsize; |
size_t segname_offset; |
size_t sectname_offset; |
unsigned int nsects; |
unsigned char *secdata; |
unsigned int i; |
unsigned int gnu_sections_found; |
unsigned int strtab_index; |
unsigned int index_index; |
unsigned int nametab_index; |
unsigned int sections_index; |
char *strtab; |
char *nametab; |
unsigned char *index; |
size_t strtab_size; |
size_t nametab_size; |
size_t index_size; |
unsigned int n_wrapped_sects; |
size_t wrapper_sect_size; |
off_t wrapper_sect_offset = 0; |
fetch_32 = (omr->is_big_endian |
? simple_object_fetch_big_32 |
: simple_object_fetch_little_32); |
is_32 = omr->magic == MACH_O_MH_MAGIC; |
if (is_32) |
{ |
seghdrsize = sizeof (struct mach_o_segment_command_32); |
sechdrsize = sizeof (struct mach_o_section_32); |
segname_offset = offsetof (struct mach_o_section_32, segname); |
sectname_offset = offsetof (struct mach_o_section_32, sectname); |
nsects = (*fetch_32) (segbuf |
+ offsetof (struct mach_o_segment_command_32, |
nsects)); |
} |
else |
{ |
seghdrsize = sizeof (struct mach_o_segment_command_64); |
sechdrsize = sizeof (struct mach_o_section_64); |
segname_offset = offsetof (struct mach_o_section_64, segname); |
sectname_offset = offsetof (struct mach_o_section_64, sectname); |
nsects = (*fetch_32) (segbuf |
+ offsetof (struct mach_o_segment_command_64, |
nsects)); |
} |
/* Fetch the section headers from the segment command. */ |
secdata = XNEWVEC (unsigned char, nsects * sechdrsize); |
if (!simple_object_internal_read (sobj->descriptor, offset + seghdrsize, |
secdata, nsects * sechdrsize, errmsg, err)) |
{ |
XDELETEVEC (secdata); |
return 0; |
} |
/* Scan for special sections that signal GNU extensions to the format. */ |
gnu_sections_found = 0; |
index_index = nsects; |
sections_index = nsects; |
strtab_index = nsects; |
nametab_index = nsects; |
for (i = 0; i < nsects; ++i) |
{ |
size_t nameoff; |
nameoff = i * sechdrsize + segname_offset; |
if (strcmp ((char *) secdata + nameoff, omr->segment_name) != 0) |
continue; |
nameoff = i * sechdrsize + sectname_offset; |
if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_NAMES) == 0) |
{ |
nametab_index = i; |
gnu_sections_found |= SOMO_NAMES_PRESENT; |
} |
else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_INDEX) == 0) |
{ |
index_index = i; |
gnu_sections_found |= SOMO_INDEX_PRESENT; |
} |
else if (strcmp ((char *) secdata + nameoff, GNU_WRAPPER_SECTS) == 0) |
{ |
sections_index = i; |
gnu_sections_found |= SOMO_SECTS_PRESENT; |
} |
else if (strcmp ((char *) secdata + nameoff, GNU_SECTION_NAMES) == 0) |
{ |
strtab_index = i; |
gnu_sections_found |= SOMO_LONGN_PRESENT; |
} |
} |
/* If any of the special wrapper section components is present, then |
they all should be. */ |
if ((gnu_sections_found & SOMO_WRAPPING) != 0) |
{ |
off_t nametab_offset; |
off_t index_offset; |
if ((gnu_sections_found & SOMO_WRAPPING) != SOMO_WRAPPING) |
{ |
*errmsg = "GNU Mach-o section wrapper: required section missing"; |
*err = 0; /* No useful errno. */ |
XDELETEVEC (secdata); |
return 0; |
} |
/* Fetch the name table. */ |
simple_object_mach_o_section_info (omr->is_big_endian, is_32, |
secdata + nametab_index * sechdrsize, |
&nametab_offset, &nametab_size); |
nametab = XNEWVEC (char, nametab_size); |
if (!simple_object_internal_read (sobj->descriptor, |
sobj->offset + nametab_offset, |
(unsigned char *) nametab, nametab_size, |
errmsg, err)) |
{ |
XDELETEVEC (nametab); |
XDELETEVEC (secdata); |
return 0; |
} |
/* Fetch the index. */ |
simple_object_mach_o_section_info (omr->is_big_endian, is_32, |
secdata + index_index * sechdrsize, |
&index_offset, &index_size); |
index = XNEWVEC (unsigned char, index_size); |
if (!simple_object_internal_read (sobj->descriptor, |
sobj->offset + index_offset, |
index, index_size, |
errmsg, err)) |
{ |
XDELETEVEC (index); |
XDELETEVEC (nametab); |
XDELETEVEC (secdata); |
return 0; |
} |
/* The index contains 4 unsigned ints per sub-section: |
sub-section offset/length, sub-section name/length. |
We fix this for both 32 and 64 bit mach-o for now, since |
other fields limit the maximum size of an object to 4G. */ |
n_wrapped_sects = index_size / 16; |
/* Get the parameters for the wrapper too. */ |
simple_object_mach_o_section_info (omr->is_big_endian, is_32, |
secdata + sections_index * sechdrsize, |
&wrapper_sect_offset, |
&wrapper_sect_size); |
} |
else |
{ |
index = NULL; |
index_size = 0; |
nametab = NULL; |
nametab_size = 0; |
n_wrapped_sects = 0; |
} |
/* If we have a long names section, fetch it. */ |
if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0) |
{ |
off_t strtab_offset; |
simple_object_mach_o_section_info (omr->is_big_endian, is_32, |
secdata + strtab_index * sechdrsize, |
&strtab_offset, &strtab_size); |
strtab = XNEWVEC (char, strtab_size); |
if (!simple_object_internal_read (sobj->descriptor, |
sobj->offset + strtab_offset, |
(unsigned char *) strtab, strtab_size, |
errmsg, err)) |
{ |
XDELETEVEC (strtab); |
XDELETEVEC (index); |
XDELETEVEC (nametab); |
XDELETEVEC (secdata); |
return 0; |
} |
} |
else |
{ |
strtab = NULL; |
strtab_size = 0; |
strtab_index = nsects; |
} |
/* Process the sections. */ |
for (i = 0; i < nsects; ++i) |
{ |
const unsigned char *sechdr; |
char namebuf[MACH_O_NAME_LEN * 2 + 2]; |
char *name; |
off_t secoffset; |
size_t secsize; |
int l; |
sechdr = secdata + i * sechdrsize; |
/* We've already processed the long section names. */ |
if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0 |
&& i == strtab_index) |
continue; |
/* We only act on the segment named. */ |
if (strcmp ((char *) sechdr + segname_offset, omr->segment_name) != 0) |
continue; |
/* Process sections associated with the wrapper. */ |
if ((gnu_sections_found & SOMO_WRAPPING) != 0) |
{ |
if (i == nametab_index || i == index_index) |
continue; |
if (i == sections_index) |
{ |
unsigned int j; |
for (j = 0; j < n_wrapped_sects; ++j) |
{ |
unsigned int subsect_offset, subsect_length, name_offset; |
subsect_offset = (*fetch_32) (index + 16 * j); |
subsect_length = (*fetch_32) (index + 16 * j + 4); |
name_offset = (*fetch_32) (index + 16 * j + 8); |
/* We don't need the name_length yet. */ |
secoffset = wrapper_sect_offset + subsect_offset; |
secsize = subsect_length; |
name = nametab + name_offset; |
if (!(*pfn) (data, name, secoffset, secsize)) |
{ |
*errmsg = NULL; |
*err = 0; |
XDELETEVEC (index); |
XDELETEVEC (nametab); |
XDELETEVEC (strtab); |
XDELETEVEC (secdata); |
return 0; |
} |
} |
continue; |
} |
} |
if ((gnu_sections_found & SOMO_LONGN_PRESENT) != 0) |
{ |
memcpy (namebuf, sechdr + sectname_offset, MACH_O_NAME_LEN); |
namebuf[MACH_O_NAME_LEN] = '\0'; |
name = &namebuf[0]; |
if (strtab != NULL && name[0] == '_' && name[1] == '_') |
{ |
unsigned long stringoffset; |
if (sscanf (name + 2, "%08lX", &stringoffset) == 1) |
{ |
if (stringoffset >= strtab_size) |
{ |
*errmsg = "section name offset out of range"; |
*err = 0; |
XDELETEVEC (index); |
XDELETEVEC (nametab); |
XDELETEVEC (strtab); |
XDELETEVEC (secdata); |
return 0; |
} |
name = strtab + stringoffset; |
} |
} |
} |
else |
{ |
/* Otherwise, make a name like __segment,__section as per the |
convention in mach-o asm. */ |
name = &namebuf[0]; |
memcpy (namebuf, (char *) sechdr + segname_offset, MACH_O_NAME_LEN); |
namebuf[MACH_O_NAME_LEN] = '\0'; |
l = strlen (namebuf); |
namebuf[l] = ','; |
memcpy (namebuf + l + 1, (char *) sechdr + sectname_offset, |
MACH_O_NAME_LEN); |
namebuf[l + 1 + MACH_O_NAME_LEN] = '\0'; |
} |
simple_object_mach_o_section_info (omr->is_big_endian, is_32, sechdr, |
&secoffset, &secsize); |
if (!(*pfn) (data, name, secoffset, secsize)) |
{ |
*errmsg = NULL; |
*err = 0; |
XDELETEVEC (index); |
XDELETEVEC (nametab); |
XDELETEVEC (strtab); |
XDELETEVEC (secdata); |
return 0; |
} |
} |
XDELETEVEC (index); |
XDELETEVEC (nametab); |
XDELETEVEC (strtab); |
XDELETEVEC (secdata); |
return 1; |
} |
/* Find all sections in a Mach-O file. */ |
static const char * |
simple_object_mach_o_find_sections (simple_object_read *sobj, |
int (*pfn) (void *, const char *, |
off_t offset, off_t length), |
void *data, |
int *err) |
{ |
struct simple_object_mach_o_read *omr = |
(struct simple_object_mach_o_read *) sobj->data; |
off_t offset; |
size_t seghdrsize; |
unsigned int (*fetch_32) (const unsigned char *); |
const char *errmsg; |
unsigned int i; |
if (omr->magic == MACH_O_MH_MAGIC) |
{ |
offset = sizeof (struct mach_o_header_32); |
seghdrsize = sizeof (struct mach_o_segment_command_32); |
} |
else |
{ |
offset = sizeof (struct mach_o_header_64); |
seghdrsize = sizeof (struct mach_o_segment_command_64); |
} |
fetch_32 = (omr->is_big_endian |
? simple_object_fetch_big_32 |
: simple_object_fetch_little_32); |
for (i = 0; i < omr->ncmds; ++i) |
{ |
unsigned char loadbuf[sizeof (struct mach_o_load_command)]; |
unsigned int cmd; |
unsigned int cmdsize; |
if (!simple_object_internal_read (sobj->descriptor, |
sobj->offset + offset, |
loadbuf, |
sizeof (struct mach_o_load_command), |
&errmsg, err)) |
return errmsg; |
cmd = (*fetch_32) (loadbuf + offsetof (struct mach_o_load_command, cmd)); |
cmdsize = (*fetch_32) (loadbuf |
+ offsetof (struct mach_o_load_command, cmdsize)); |
if (cmd == MACH_O_LC_SEGMENT || cmd == MACH_O_LC_SEGMENT_64) |
{ |
unsigned char segbuf[sizeof (struct mach_o_segment_command_64)]; |
int r; |
if (!simple_object_internal_read (sobj->descriptor, |
sobj->offset + offset, |
segbuf, seghdrsize, &errmsg, err)) |
return errmsg; |
r = simple_object_mach_o_segment (sobj, offset, segbuf, pfn, |
data, &errmsg, err); |
if (!r) |
return errmsg; |
} |
offset += cmdsize; |
} |
return NULL; |
} |
/* Fetch the attributes for an simple_object_read. */ |
static void * |
simple_object_mach_o_fetch_attributes (simple_object_read *sobj, |
const char **errmsg ATTRIBUTE_UNUSED, |
int *err ATTRIBUTE_UNUSED) |
{ |
struct simple_object_mach_o_read *omr = |
(struct simple_object_mach_o_read *) sobj->data; |
struct simple_object_mach_o_attributes *ret; |
ret = XNEW (struct simple_object_mach_o_attributes); |
ret->magic = omr->magic; |
ret->is_big_endian = omr->is_big_endian; |
ret->cputype = omr->cputype; |
ret->cpusubtype = omr->cpusubtype; |
ret->flags = omr->flags; |
ret->reserved = omr->reserved; |
return ret; |
} |
/* Release the private data for an simple_object_read. */ |
static void |
simple_object_mach_o_release_read (void *data) |
{ |
struct simple_object_mach_o_read *omr = |
(struct simple_object_mach_o_read *) data; |
free (omr->segment_name); |
XDELETE (omr); |
} |
/* Compare two attributes structures. */ |
static const char * |
simple_object_mach_o_attributes_merge (void *todata, void *fromdata, int *err) |
{ |
struct simple_object_mach_o_attributes *to = |
(struct simple_object_mach_o_attributes *) todata; |
struct simple_object_mach_o_attributes *from = |
(struct simple_object_mach_o_attributes *) fromdata; |
if (to->magic != from->magic |
|| to->is_big_endian != from->is_big_endian |
|| to->cputype != from->cputype) |
{ |
*err = 0; |
return "Mach-O object format mismatch"; |
} |
return NULL; |
} |
/* Release the private data for an attributes structure. */ |
static void |
simple_object_mach_o_release_attributes (void *data) |
{ |
XDELETE (data); |
} |
/* Prepare to write out a file. */ |
static void * |
simple_object_mach_o_start_write (void *attributes_data, |
const char **errmsg ATTRIBUTE_UNUSED, |
int *err ATTRIBUTE_UNUSED) |
{ |
struct simple_object_mach_o_attributes *attrs = |
(struct simple_object_mach_o_attributes *) attributes_data; |
struct simple_object_mach_o_attributes *ret; |
/* We're just going to record the attributes, but we need to make a |
copy because the user may delete them. */ |
ret = XNEW (struct simple_object_mach_o_attributes); |
*ret = *attrs; |
return ret; |
} |
/* Write out the header of a Mach-O file. */ |
static int |
simple_object_mach_o_write_header (simple_object_write *sobj, int descriptor, |
size_t nsects, const char **errmsg, |
int *err) |
{ |
struct simple_object_mach_o_attributes *attrs = |
(struct simple_object_mach_o_attributes *) sobj->data; |
void (*set_32) (unsigned char *, unsigned int); |
unsigned char hdrbuf[sizeof (struct mach_o_header_64)]; |
unsigned char *hdr; |
size_t wrsize; |
set_32 = (attrs->is_big_endian |
? simple_object_set_big_32 |
: simple_object_set_little_32); |
memset (hdrbuf, 0, sizeof hdrbuf); |
/* The 32-bit and 64-bit headers start out the same. */ |
hdr = &hdrbuf[0]; |
set_32 (hdr + offsetof (struct mach_o_header_32, magic), attrs->magic); |
set_32 (hdr + offsetof (struct mach_o_header_32, cputype), attrs->cputype); |
set_32 (hdr + offsetof (struct mach_o_header_32, cpusubtype), |
attrs->cpusubtype); |
set_32 (hdr + offsetof (struct mach_o_header_32, filetype), MACH_O_MH_OBJECT); |
set_32 (hdr + offsetof (struct mach_o_header_32, ncmds), 1); |
set_32 (hdr + offsetof (struct mach_o_header_32, flags), attrs->flags); |
if (attrs->magic == MACH_O_MH_MAGIC) |
{ |
wrsize = sizeof (struct mach_o_header_32); |
set_32 (hdr + offsetof (struct mach_o_header_32, sizeofcmds), |
(sizeof (struct mach_o_segment_command_32) |
+ nsects * sizeof (struct mach_o_section_32))); |
} |
else |
{ |
set_32 (hdr + offsetof (struct mach_o_header_64, sizeofcmds), |
(sizeof (struct mach_o_segment_command_64) |
+ nsects * sizeof (struct mach_o_section_64))); |
set_32 (hdr + offsetof (struct mach_o_header_64, reserved), |
attrs->reserved); |
wrsize = sizeof (struct mach_o_header_64); |
} |
return simple_object_internal_write (descriptor, 0, hdrbuf, wrsize, |
errmsg, err); |
} |
/* Write a Mach-O section header. */ |
static int |
simple_object_mach_o_write_section_header (simple_object_write *sobj, |
int descriptor, |
size_t sechdr_offset, |
const char *name, const char *segn, |
size_t secaddr, size_t secsize, |
size_t offset, unsigned int align, |
const char **errmsg, int *err) |
{ |
struct simple_object_mach_o_attributes *attrs = |
(struct simple_object_mach_o_attributes *) sobj->data; |
void (*set_32) (unsigned char *, unsigned int); |
unsigned char hdrbuf[sizeof (struct mach_o_section_64)]; |
unsigned char *hdr; |
size_t sechdrsize; |
set_32 = (attrs->is_big_endian |
? simple_object_set_big_32 |
: simple_object_set_little_32); |
memset (hdrbuf, 0, sizeof hdrbuf); |
hdr = &hdrbuf[0]; |
if (attrs->magic == MACH_O_MH_MAGIC) |
{ |
strncpy ((char *) hdr + offsetof (struct mach_o_section_32, sectname), |
name, MACH_O_NAME_LEN); |
strncpy ((char *) hdr + offsetof (struct mach_o_section_32, segname), |
segn, MACH_O_NAME_LEN); |
set_32 (hdr + offsetof (struct mach_o_section_32, addr), secaddr); |
set_32 (hdr + offsetof (struct mach_o_section_32, size), secsize); |
set_32 (hdr + offsetof (struct mach_o_section_32, offset), offset); |
set_32 (hdr + offsetof (struct mach_o_section_32, align), align); |
/* reloff left as zero. */ |
/* nreloc left as zero. */ |
set_32 (hdr + offsetof (struct mach_o_section_32, flags), |
MACH_O_S_ATTR_DEBUG); |
/* reserved1 left as zero. */ |
/* reserved2 left as zero. */ |
sechdrsize = sizeof (struct mach_o_section_32); |
} |
else |
{ |
#ifdef UNSIGNED_64BIT_TYPE |
void (*set_64) (unsigned char *, ulong_type); |
set_64 = (attrs->is_big_endian |
? simple_object_set_big_64 |
: simple_object_set_little_64); |
strncpy ((char *) hdr + offsetof (struct mach_o_section_64, sectname), |
name, MACH_O_NAME_LEN); |
strncpy ((char *) hdr + offsetof (struct mach_o_section_64, segname), |
segn, MACH_O_NAME_LEN); |
set_64 (hdr + offsetof (struct mach_o_section_64, addr), secaddr); |
set_64 (hdr + offsetof (struct mach_o_section_64, size), secsize); |
set_32 (hdr + offsetof (struct mach_o_section_64, offset), offset); |
set_32 (hdr + offsetof (struct mach_o_section_64, align), align); |
/* reloff left as zero. */ |
/* nreloc left as zero. */ |
set_32 (hdr + offsetof (struct mach_o_section_64, flags), |
MACH_O_S_ATTR_DEBUG); |
/* reserved1 left as zero. */ |
/* reserved2 left as zero. */ |
/* reserved3 left as zero. */ |
#endif |
sechdrsize = sizeof (struct mach_o_section_64); |
} |
return simple_object_internal_write (descriptor, sechdr_offset, hdr, |
sechdrsize, errmsg, err); |
} |
/* Write out the single (anonymous) segment containing the sections of a Mach-O |
Object file. |
As a GNU extension to mach-o, when the caller specifies a segment name in |
sobj->segment_name, all the sections passed will be output under a single |
mach-o section header. The caller's sections are indexed within this |
'wrapper' section by a table stored in a second mach-o section. Finally, |
arbitrary length section names are permitted by the extension and these are |
stored in a table in a third mach-o section. |
Note that this is only likely to make any sense for the __GNU_LTO segment |
at present. |
If the wrapper extension is not in force, we assume that the section name |
is in the form __SEGMENT_NAME,__section_name as per Mach-O asm. */ |
static int |
simple_object_mach_o_write_segment (simple_object_write *sobj, int descriptor, |
size_t *nsects, const char **errmsg, |
int *err) |
{ |
struct simple_object_mach_o_attributes *attrs = |
(struct simple_object_mach_o_attributes *) sobj->data; |
void (*set_32) (unsigned char *, unsigned int); |
size_t hdrsize; |
size_t seghdrsize; |
size_t sechdrsize; |
size_t cmdsize; |
size_t offset; |
size_t sechdr_offset; |
size_t secaddr; |
unsigned int name_offset; |
simple_object_write_section *section; |
unsigned char hdrbuf[sizeof (struct mach_o_segment_command_64)]; |
unsigned char *hdr; |
size_t nsects_in; |
unsigned int *index; |
char *snames; |
unsigned int sect; |
set_32 = (attrs->is_big_endian |
? simple_object_set_big_32 |
: simple_object_set_little_32); |
/* Write out the sections first. */ |
if (attrs->magic == MACH_O_MH_MAGIC) |
{ |
hdrsize = sizeof (struct mach_o_header_32); |
seghdrsize = sizeof (struct mach_o_segment_command_32); |
sechdrsize = sizeof (struct mach_o_section_32); |
} |
else |
{ |
hdrsize = sizeof (struct mach_o_header_64); |
seghdrsize = sizeof (struct mach_o_segment_command_64); |
sechdrsize = sizeof (struct mach_o_section_64); |
} |
name_offset = 0; |
*nsects = nsects_in = 0; |
/* Count the number of sections we start with. */ |
for (section = sobj->sections; section != NULL; section = section->next) |
nsects_in++; |
if (sobj->segment_name != NULL) |
{ |
/* We will only write 3 sections: wrapped data, index and names. */ |
*nsects = 3; |
/* The index has four entries per wrapped section: |
Section Offset, length, Name offset, length. |
Where the offsets are based at the start of the wrapper and name |
sections respectively. |
The values are stored as 32 bit int for both 32 and 64 bit mach-o |
since the size of a mach-o MH_OBJECT cannot exceed 4G owing to |
other constraints. */ |
index = XNEWVEC (unsigned int, nsects_in * 4); |
/* We now need to figure out the size of the names section. This just |
stores the names as null-terminated c strings, packed without any |
alignment padding. */ |
for (section = sobj->sections, sect = 0; section != NULL; |
section = section->next, sect++) |
{ |
index[sect*4+2] = name_offset; |
index[sect*4+3] = strlen (section->name) + 1; |
name_offset += strlen (section->name) + 1; |
} |
snames = XNEWVEC (char, name_offset); |
} |
else |
{ |
*nsects = nsects_in; |
index = NULL; |
snames = NULL; |
} |
sechdr_offset = hdrsize + seghdrsize; |
cmdsize = seghdrsize + *nsects * sechdrsize; |
offset = hdrsize + cmdsize; |
secaddr = 0; |
for (section = sobj->sections, sect = 0; |
section != NULL; section = section->next, sect++) |
{ |
size_t mask; |
size_t new_offset; |
size_t secsize; |
struct simple_object_write_section_buffer *buffer; |
mask = (1U << section->align) - 1; |
new_offset = offset + mask; |
new_offset &= ~ mask; |
while (new_offset > offset) |
{ |
unsigned char zeroes[16]; |
size_t write; |
memset (zeroes, 0, sizeof zeroes); |
write = new_offset - offset; |
if (write > sizeof zeroes) |
write = sizeof zeroes; |
if (!simple_object_internal_write (descriptor, offset, zeroes, write, |
errmsg, err)) |
return 0; |
offset += write; |
} |
secsize = 0; |
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) |
{ |
if (!simple_object_internal_write (descriptor, offset + secsize, |
((const unsigned char *) |
buffer->buffer), |
buffer->size, errmsg, err)) |
return 0; |
secsize += buffer->size; |
} |
if (sobj->segment_name != NULL) |
{ |
index[sect*4+0] = (unsigned int) offset; |
index[sect*4+1] = secsize; |
/* Stash the section name in our table. */ |
memcpy (snames + index[sect * 4 + 2], section->name, |
index[sect * 4 + 3]); |
} |
else |
{ |
char namebuf[MACH_O_NAME_LEN + 1]; |
char segnbuf[MACH_O_NAME_LEN + 1]; |
char *comma; |
/* Try to extract segment,section from the input name. */ |
memset (namebuf, 0, sizeof namebuf); |
memset (segnbuf, 0, sizeof segnbuf); |
comma = strchr (section->name, ','); |
if (comma != NULL) |
{ |
int len = comma - section->name; |
len = len > MACH_O_NAME_LEN ? MACH_O_NAME_LEN : len; |
strncpy (namebuf, section->name, len); |
strncpy (segnbuf, comma + 1, MACH_O_NAME_LEN); |
} |
else /* just try to copy the name, leave segment blank. */ |
strncpy (namebuf, section->name, MACH_O_NAME_LEN); |
if (!simple_object_mach_o_write_section_header (sobj, descriptor, |
sechdr_offset, |
namebuf, segnbuf, |
secaddr, secsize, |
offset, |
section->align, |
errmsg, err)) |
return 0; |
sechdr_offset += sechdrsize; |
} |
offset += secsize; |
secaddr += secsize; |
} |
if (sobj->segment_name != NULL) |
{ |
size_t secsize; |
unsigned int i; |
/* Write the section header for the wrapper. */ |
/* Account for any initial aligment - which becomes the alignment for this |
created section. */ |
secsize = (offset - index[0]); |
if (!simple_object_mach_o_write_section_header (sobj, descriptor, |
sechdr_offset, |
GNU_WRAPPER_SECTS, |
sobj->segment_name, |
0 /*secaddr*/, |
secsize, index[0], |
sobj->sections->align, |
errmsg, err)) |
return 0; |
/* Subtract the wrapper section start from the begining of each sub |
section. */ |
for (i = 1; i < nsects_in; ++i) |
index[4 * i] -= index[0]; |
index[0] = 0; |
sechdr_offset += sechdrsize; |
/* Write out the section names. |
... the header ... |
name_offset contains the length of the section. It is not aligned. */ |
if (!simple_object_mach_o_write_section_header (sobj, descriptor, |
sechdr_offset, |
GNU_WRAPPER_NAMES, |
sobj->segment_name, |
0 /*secaddr*/, |
name_offset, |
offset, |
0, errmsg, err)) |
return 0; |
/* ... and the content.. */ |
if (!simple_object_internal_write (descriptor, offset, |
(const unsigned char *) snames, |
name_offset, errmsg, err)) |
return 0; |
sechdr_offset += sechdrsize; |
secaddr += name_offset; |
offset += name_offset; |
/* Now do the index, we'll align this to 4 bytes although the read code |
will handle unaligned. */ |
offset += 3; |
offset &= ~0x03; |
if (!simple_object_mach_o_write_section_header (sobj, descriptor, |
sechdr_offset, |
GNU_WRAPPER_INDEX, |
sobj->segment_name, |
0 /*secaddr*/, |
nsects_in * 16, |
offset, |
2, errmsg, err)) |
return 0; |
/* ... and the content.. */ |
if (!simple_object_internal_write (descriptor, offset, |
(const unsigned char *) index, |
nsects_in*16, errmsg, err)) |
return 0; |
XDELETEVEC (index); |
XDELETEVEC (snames); |
} |
/* Write out the segment header. */ |
memset (hdrbuf, 0, sizeof hdrbuf); |
hdr = &hdrbuf[0]; |
if (attrs->magic == MACH_O_MH_MAGIC) |
{ |
set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmd), |
MACH_O_LC_SEGMENT); |
set_32 (hdr + offsetof (struct mach_o_segment_command_32, cmdsize), |
cmdsize); |
/* MH_OBJECTS have a single, anonymous, segment - so the segment name |
is left empty. */ |
/* vmaddr left as zero. */ |
/* vmsize left as zero. */ |
set_32 (hdr + offsetof (struct mach_o_segment_command_32, fileoff), |
hdrsize + cmdsize); |
set_32 (hdr + offsetof (struct mach_o_segment_command_32, filesize), |
offset - (hdrsize + cmdsize)); |
/* maxprot left as zero. */ |
/* initprot left as zero. */ |
set_32 (hdr + offsetof (struct mach_o_segment_command_32, nsects), |
*nsects); |
/* flags left as zero. */ |
} |
else |
{ |
#ifdef UNSIGNED_64BIT_TYPE |
void (*set_64) (unsigned char *, ulong_type); |
set_64 = (attrs->is_big_endian |
? simple_object_set_big_64 |
: simple_object_set_little_64); |
set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmd), |
MACH_O_LC_SEGMENT); |
set_32 (hdr + offsetof (struct mach_o_segment_command_64, cmdsize), |
cmdsize); |
/* MH_OBJECTS have a single, anonymous, segment - so the segment name |
is left empty. */ |
/* vmaddr left as zero. */ |
/* vmsize left as zero. */ |
set_64 (hdr + offsetof (struct mach_o_segment_command_64, fileoff), |
hdrsize + cmdsize); |
set_64 (hdr + offsetof (struct mach_o_segment_command_64, filesize), |
offset - (hdrsize + cmdsize)); |
/* maxprot left as zero. */ |
/* initprot left as zero. */ |
set_32 (hdr + offsetof (struct mach_o_segment_command_64, nsects), |
*nsects); |
/* flags left as zero. */ |
#endif |
} |
return simple_object_internal_write (descriptor, hdrsize, hdr, seghdrsize, |
errmsg, err); |
} |
/* Write out a complete Mach-O file. */ |
static const char * |
simple_object_mach_o_write_to_file (simple_object_write *sobj, int descriptor, |
int *err) |
{ |
size_t nsects = 0; |
const char *errmsg; |
if (!simple_object_mach_o_write_segment (sobj, descriptor, &nsects, |
&errmsg, err)) |
return errmsg; |
if (!simple_object_mach_o_write_header (sobj, descriptor, nsects, |
&errmsg, err)) |
return errmsg; |
return NULL; |
} |
/* Release the private data for an simple_object_write structure. */ |
static void |
simple_object_mach_o_release_write (void *data) |
{ |
XDELETE (data); |
} |
/* The Mach-O functions. */ |
const struct simple_object_functions simple_object_mach_o_functions = |
{ |
simple_object_mach_o_match, |
simple_object_mach_o_find_sections, |
simple_object_mach_o_fetch_attributes, |
simple_object_mach_o_release_read, |
simple_object_mach_o_attributes_merge, |
simple_object_mach_o_release_attributes, |
simple_object_mach_o_start_write, |
simple_object_mach_o_write_to_file, |
simple_object_mach_o_release_write |
}; |
/contrib/toolchain/binutils/libiberty/simple-object-xcoff.c |
---|
0,0 → 1,898 |
/* simple-object-coff.c -- routines to manipulate XCOFF object files. |
Copyright 2013 Free Software Foundation, Inc. |
Written by Ian Lance Taylor, Google and David Edelsohn, IBM. |
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, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#include "config.h" |
#include "libiberty.h" |
#include "simple-object.h" |
#include <errno.h> |
#include <stddef.h> |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STDINT_H |
#include <stdint.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifdef HAVE_INTTYPES_H |
#include <inttypes.h> |
#endif |
#include "simple-object-common.h" |
/* XCOFF structures and constants. */ |
/* XCOFF file header. */ |
struct external_filehdr |
{ |
unsigned char f_magic[2]; /* magic number */ |
unsigned char f_nscns[2]; /* number of sections */ |
unsigned char f_timdat[4]; /* time & date stamp */ |
union |
{ |
struct |
{ |
unsigned char f_symptr[4]; /* file pointer to symtab */ |
unsigned char f_nsyms[4]; /* number of symtab entries */ |
unsigned char f_opthdr[2]; /* sizeof(optional hdr) */ |
unsigned char f_flags[2]; /* flags */ |
} xcoff32; |
struct |
{ |
unsigned char f_symptr[8]; /* file pointer to symtab */ |
unsigned char f_opthdr[2]; /* sizeof(optional hdr) */ |
unsigned char f_flags[2]; /* flags */ |
unsigned char f_nsyms[4]; /* number of symtab entries */ |
} xcoff64; |
} u; |
}; |
/* Bits for filehdr f_flags field. */ |
#define F_EXEC (0x0002) |
/* The known values of f_magic in an XCOFF file header. */ |
#define U802WRMAGIC 0730 /* Writeable text segments. */ |
#define U802ROMAGIC 0735 /* Readonly sharable text segments. */ |
#define U802TOCMAGIC 0737 /* Readonly text segments and TOC. */ |
#define U803XTOCMAGIC 0757 /* Aix 4.3 64-bit XCOFF. */ |
#define U64_TOCMAGIC 0767 /* AIX 5+ 64-bit XCOFF. */ |
/* XCOFF section header. */ |
struct external_scnhdr |
{ |
unsigned char s_name[8]; /* section name */ |
union |
{ |
struct |
{ |
unsigned char s_paddr[4]; /* physical address, aliased s_nlib */ |
unsigned char s_vaddr[4]; /* virtual address */ |
unsigned char s_size[4]; /* section size */ |
unsigned char s_scnptr[4]; /* file ptr to raw data for section */ |
unsigned char s_relptr[4]; /* file ptr to relocation */ |
unsigned char s_lnnoptr[4]; /* file ptr to line numbers */ |
unsigned char s_nreloc[2]; /* number of relocation entries */ |
unsigned char s_nlnno[2]; /* number of line number entries */ |
unsigned char s_flags[4]; /* flags */ |
} xcoff32; |
struct |
{ |
unsigned char s_paddr[8]; /* physical address, aliased s_nlib */ |
unsigned char s_vaddr[8]; /* virtual address */ |
unsigned char s_size[8]; /* section size */ |
unsigned char s_scnptr[8]; /* file ptr to raw data for section */ |
unsigned char s_relptr[8]; /* file ptr to relocation */ |
unsigned char s_lnnoptr[8]; /* file ptr to line numbers */ |
unsigned char s_nreloc[4]; /* number of relocation entries */ |
unsigned char s_nlnno[4]; /* number of line number entries */ |
unsigned char s_flags[4]; /* flags */ |
} xcoff64; |
} u; |
}; |
#define SCNHSZ32 (40) |
#define SCNHSZ64 (68) |
/* The length of the s_name field in struct external_scnhdr. */ |
#define SCNNMLEN (8) |
/* Bits for scnhdr s_flags field. */ |
#define STYP_DATA 0x40 |
/* XCOFF symbol table entry. */ |
#define N_SYMNMLEN (8) /* # characters in a symbol name */ |
/* The format of an XCOFF symbol-table entry. */ |
struct external_syment |
{ |
union { |
struct { |
union { |
/* The name of the symbol. There is an implicit null character |
after the end of the array. */ |
char n_name[N_SYMNMLEN]; |
struct { |
/* If n_zeroes is zero, n_offset is the offset the name from |
the start of the string table. */ |
unsigned char n_zeroes[4]; |
unsigned char n_offset[4]; |
} n; |
} n; |
/* The symbol's value. */ |
unsigned char n_value[4]; |
} xcoff32; |
struct { |
/* The symbol's value. */ |
unsigned char n_value[8]; |
/* The offset of the symbol from the start of the string table. */ |
unsigned char n_offset[4]; |
} xcoff64; |
} u; |
/* The number of the section to which this symbol belongs. */ |
unsigned char n_scnum[2]; |
/* The type of symbol. (It can be interpreted as an n_lang |
and an n_cpu byte, but we don't care about that here.) */ |
unsigned char n_type[2]; |
/* The class of symbol (a C_* value). */ |
unsigned char n_sclass[1]; |
/* The number of auxiliary symbols attached to this entry. */ |
unsigned char n_numaux[1]; |
}; |
#define SYMESZ (18) |
/* Length allowed for filename in aux sym format 4. */ |
#define FILNMLEN (14) |
/* Omits x_sym and other unused variants. */ |
union external_auxent |
{ |
/* Aux sym format 4: file. */ |
union |
{ |
char x_fname[FILNMLEN]; |
struct |
{ |
unsigned char x_zeroes[4]; |
unsigned char x_offset[4]; |
unsigned char x_pad[FILNMLEN-8]; |
unsigned char x_ftype; |
} _x; |
} x_file; |
/* Aux sym format 5: section. */ |
struct |
{ |
unsigned char x_scnlen[4]; /* section length */ |
unsigned char x_nreloc[2]; /* # relocation entries */ |
unsigned char x_nlinno[2]; /* # line numbers */ |
} x_scn; |
/* CSECT auxiliary entry. */ |
union |
{ |
struct |
{ |
struct |
{ |
unsigned char x_scnlen[4]; /* csect length */ |
unsigned char x_parmhash[4]; /* parm type hash index */ |
unsigned char x_snhash[2]; /* sect num with parm hash */ |
unsigned char x_smtyp; /* symbol align and type */ |
unsigned char x_smclas; /* storage mapping class */ |
unsigned char x_stab; /* dbx stab info index */ |
unsigned char x_snstab[2]; /* sect num with dbx stab */ |
} x_csect; |
} xcoff32; |
struct |
{ |
struct |
{ |
unsigned char x_scnlen_lo[4]; /* csect length */ |
unsigned char x_parmhash[4]; /* parm type hash index */ |
unsigned char x_snhash[2]; /* sect num with parm hash */ |
unsigned char x_smtyp; /* symbol align and type */ |
unsigned char x_smclas; /* storage mapping class */ |
unsigned char x_scnlen_hi[4]; |
unsigned char pad; |
unsigned char x_auxtype; |
} x_csect; |
} xcoff64; |
} u; |
/* SECTION/DWARF auxiliary entry. */ |
struct |
{ |
unsigned char x_scnlen[4]; /* section length */ |
unsigned char pad1[4]; |
unsigned char x_nreloc[4]; /* number RLDs */ |
} x_sect; |
}; |
/* Symbol-related constants. */ |
#define N_DEBUG (-2) |
#define IMAGE_SYM_TYPE_NULL (0) |
#define IMAGE_SYM_DTYPE_NULL (0) |
#define IMAGE_SYM_CLASS_STATIC (3) |
#define IMAGE_SYM_CLASS_FILE (103) |
#define IMAGE_SYM_TYPE \ |
((IMAGE_SYM_DTYPE_NULL << 4) | IMAGE_SYM_TYPE_NULL) |
#define C_STAT (3) |
#define C_FILE (103) |
/* Private data for an simple_object_read. */ |
struct simple_object_xcoff_read |
{ |
/* Magic number. */ |
unsigned short magic; |
/* Number of sections. */ |
unsigned short nscns; |
/* File offset of symbol table. */ |
off_t symptr; |
/* Number of symbol table entries. */ |
unsigned int nsyms; |
/* Flags. */ |
unsigned short flags; |
/* Offset of section headers in file. */ |
off_t scnhdr_offset; |
}; |
/* Private data for an simple_object_attributes. */ |
struct simple_object_xcoff_attributes |
{ |
/* Magic number. */ |
unsigned short magic; |
/* Flags. */ |
unsigned short flags; |
}; |
/* See if we have a XCOFF file. */ |
static void * |
simple_object_xcoff_match (unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN], |
int descriptor, off_t offset, |
const char *segment_name ATTRIBUTE_UNUSED, |
const char **errmsg, int *err) |
{ |
unsigned short magic; |
unsigned short (*fetch_16) (const unsigned char *); |
unsigned int (*fetch_32) (const unsigned char *); |
ulong_type (*fetch_64) (const unsigned char *); |
unsigned char hdrbuf[sizeof (struct external_filehdr)]; |
struct simple_object_xcoff_read *ocr; |
int u64; |
magic = simple_object_fetch_big_16 (header); |
if (magic != U802TOCMAGIC && magic != U64_TOCMAGIC) |
{ |
*errmsg = NULL; |
*err = 0; |
return NULL; |
} |
fetch_16 = simple_object_fetch_big_16; |
fetch_32 = simple_object_fetch_big_32; |
fetch_64 = simple_object_fetch_big_64; |
if (!simple_object_internal_read (descriptor, offset, hdrbuf, sizeof hdrbuf, |
errmsg, err)) |
return NULL; |
u64 = magic == U64_TOCMAGIC; |
ocr = XNEW (struct simple_object_xcoff_read); |
ocr->magic = magic; |
ocr->nscns = fetch_16 (hdrbuf + offsetof (struct external_filehdr, f_nscns)); |
if (u64) |
{ |
ocr->symptr = fetch_64 (hdrbuf |
+ offsetof (struct external_filehdr, |
u.xcoff64.f_symptr)); |
ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, |
u.xcoff64.f_nsyms)); |
ocr->scnhdr_offset = (sizeof (struct external_filehdr) |
+ fetch_16 (hdrbuf + offsetof (struct external_filehdr, |
u.xcoff64.f_opthdr))); |
} |
else |
{ |
ocr->symptr = fetch_32 (hdrbuf |
+ offsetof (struct external_filehdr, |
u.xcoff32.f_symptr)); |
ocr->nsyms = fetch_32 (hdrbuf + offsetof (struct external_filehdr, |
u.xcoff32.f_nsyms)); |
ocr->scnhdr_offset = (sizeof (struct external_filehdr) - 4 |
+ fetch_16 (hdrbuf + offsetof (struct external_filehdr, |
u.xcoff32.f_opthdr))); |
} |
return (void *) ocr; |
} |
/* Read the string table in a XCOFF file. */ |
static char * |
simple_object_xcoff_read_strtab (simple_object_read *sobj, size_t *strtab_size, |
const char **errmsg, int *err) |
{ |
struct simple_object_xcoff_read *ocr = |
(struct simple_object_xcoff_read *) sobj->data; |
off_t strtab_offset; |
unsigned char strsizebuf[4]; |
size_t strsize; |
char *strtab; |
strtab_offset = sobj->offset + ocr->symptr |
+ ocr->nsyms * SYMESZ; |
if (!simple_object_internal_read (sobj->descriptor, strtab_offset, |
strsizebuf, 4, errmsg, err)) |
return NULL; |
strsize = simple_object_fetch_big_32 (strsizebuf); |
strtab = XNEWVEC (char, strsize); |
if (!simple_object_internal_read (sobj->descriptor, strtab_offset, |
(unsigned char *) strtab, strsize, errmsg, |
err)) |
{ |
XDELETEVEC (strtab); |
return NULL; |
} |
*strtab_size = strsize; |
return strtab; |
} |
/* Find all sections in a XCOFF file. */ |
static const char * |
simple_object_xcoff_find_sections (simple_object_read *sobj, |
int (*pfn) (void *, const char *, |
off_t offset, off_t length), |
void *data, |
int *err) |
{ |
struct simple_object_xcoff_read *ocr = |
(struct simple_object_xcoff_read *) sobj->data; |
int u64 = ocr->magic == U64_TOCMAGIC; |
size_t scnhdr_size; |
unsigned char *scnbuf; |
const char *errmsg; |
unsigned int (*fetch_32) (const unsigned char *); |
ulong_type (*fetch_64) (const unsigned char *); |
unsigned int nscns; |
char *strtab; |
size_t strtab_size; |
unsigned int i; |
scnhdr_size = u64 ? SCNHSZ64 : SCNHSZ32; |
scnbuf = XNEWVEC (unsigned char, scnhdr_size * ocr->nscns); |
if (!simple_object_internal_read (sobj->descriptor, |
sobj->offset + ocr->scnhdr_offset, |
scnbuf, scnhdr_size * ocr->nscns, &errmsg, |
err)) |
{ |
XDELETEVEC (scnbuf); |
return errmsg; |
} |
fetch_32 = simple_object_fetch_big_32; |
fetch_64 = simple_object_fetch_big_64; |
nscns = ocr->nscns; |
strtab = NULL; |
strtab_size = 0; |
for (i = 0; i < nscns; ++i) |
{ |
unsigned char *scnhdr; |
unsigned char *scnname; |
char namebuf[SCNNMLEN + 1]; |
char *name; |
off_t scnptr; |
unsigned int size; |
scnhdr = scnbuf + i * scnhdr_size; |
scnname = scnhdr + offsetof (struct external_scnhdr, s_name); |
memcpy (namebuf, scnname, SCNNMLEN); |
namebuf[SCNNMLEN] = '\0'; |
name = &namebuf[0]; |
if (namebuf[0] == '/') |
{ |
size_t strindex; |
char *end; |
strindex = strtol (namebuf + 1, &end, 10); |
if (*end == '\0') |
{ |
/* The real section name is found in the string |
table. */ |
if (strtab == NULL) |
{ |
strtab = simple_object_xcoff_read_strtab (sobj, |
&strtab_size, |
&errmsg, err); |
if (strtab == NULL) |
{ |
XDELETEVEC (scnbuf); |
return errmsg; |
} |
} |
if (strindex < 4 || strindex >= strtab_size) |
{ |
XDELETEVEC (strtab); |
XDELETEVEC (scnbuf); |
*err = 0; |
return "section string index out of range"; |
} |
name = strtab + strindex; |
} |
} |
if (u64) |
{ |
scnptr = fetch_64 (scnhdr + offsetof (struct external_scnhdr, |
u.xcoff64.s_scnptr)); |
size = fetch_64 (scnhdr + offsetof (struct external_scnhdr, |
u.xcoff64.s_size)); |
} |
else |
{ |
scnptr = fetch_32 (scnhdr + offsetof (struct external_scnhdr, |
u.xcoff32.s_scnptr)); |
size = fetch_32 (scnhdr + offsetof (struct external_scnhdr, |
u.xcoff32.s_size)); |
} |
if (!(*pfn) (data, name, scnptr, size)) |
break; |
} |
if (strtab != NULL) |
XDELETEVEC (strtab); |
XDELETEVEC (scnbuf); |
return NULL; |
} |
/* Fetch the attributes for an simple_object_read. */ |
static void * |
simple_object_xcoff_fetch_attributes (simple_object_read *sobj, |
const char **errmsg ATTRIBUTE_UNUSED, |
int *err ATTRIBUTE_UNUSED) |
{ |
struct simple_object_xcoff_read *ocr = |
(struct simple_object_xcoff_read *) sobj->data; |
struct simple_object_xcoff_attributes *ret; |
ret = XNEW (struct simple_object_xcoff_attributes); |
ret->magic = ocr->magic; |
ret->flags = ocr->flags; |
return ret; |
} |
/* Release the private data for an simple_object_read. */ |
static void |
simple_object_xcoff_release_read (void *data) |
{ |
XDELETE (data); |
} |
/* Compare two attributes structures. */ |
static const char * |
simple_object_xcoff_attributes_merge (void *todata, void *fromdata, int *err) |
{ |
struct simple_object_xcoff_attributes *to = |
(struct simple_object_xcoff_attributes *) todata; |
struct simple_object_xcoff_attributes *from = |
(struct simple_object_xcoff_attributes *) fromdata; |
if (to->magic != from->magic) |
{ |
*err = 0; |
return "XCOFF object format mismatch"; |
} |
return NULL; |
} |
/* Release the private data for an attributes structure. */ |
static void |
simple_object_xcoff_release_attributes (void *data) |
{ |
XDELETE (data); |
} |
/* Prepare to write out a file. */ |
static void * |
simple_object_xcoff_start_write (void *attributes_data, |
const char **errmsg ATTRIBUTE_UNUSED, |
int *err ATTRIBUTE_UNUSED) |
{ |
struct simple_object_xcoff_attributes *attrs = |
(struct simple_object_xcoff_attributes *) attributes_data; |
struct simple_object_xcoff_attributes *ret; |
/* We're just going to record the attributes, but we need to make a |
copy because the user may delete them. */ |
ret = XNEW (struct simple_object_xcoff_attributes); |
*ret = *attrs; |
return ret; |
} |
/* Write out a XCOFF filehdr. */ |
static int |
simple_object_xcoff_write_filehdr (simple_object_write *sobj, int descriptor, |
unsigned int nscns, size_t symtab_offset, |
unsigned int nsyms, const char **errmsg, |
int *err) |
{ |
struct simple_object_xcoff_attributes *attrs = |
(struct simple_object_xcoff_attributes *) sobj->data; |
int u64 = attrs->magic == U64_TOCMAGIC; |
unsigned char hdrbuf[sizeof (struct external_filehdr)]; |
unsigned char *hdr; |
void (*set_16) (unsigned char *, unsigned short); |
void (*set_32) (unsigned char *, unsigned int); |
void (*set_64) (unsigned char *, ulong_type); |
hdr = &hdrbuf[0]; |
set_16 = simple_object_set_big_16; |
set_32 = simple_object_set_big_32; |
set_64 = simple_object_set_big_64; |
memset (hdr, 0, sizeof (struct external_filehdr)); |
set_16 (hdr + offsetof (struct external_filehdr, f_magic), attrs->magic); |
set_16 (hdr + offsetof (struct external_filehdr, f_nscns), nscns); |
/* f_timdat left as zero. */ |
if (u64) |
{ |
set_64 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr), |
symtab_offset); |
set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms), |
nsyms); |
/* f_opthdr left as zero. */ |
set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags), |
attrs->flags); |
} |
else |
{ |
set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_symptr), |
symtab_offset); |
set_32 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_nsyms), |
nsyms); |
/* f_opthdr left as zero. */ |
set_16 (hdr + offsetof (struct external_filehdr, u.xcoff64.f_flags), |
attrs->flags); |
} |
return simple_object_internal_write (descriptor, 0, hdrbuf, |
sizeof (struct external_filehdr), |
errmsg, err); |
} |
/* Write out a XCOFF section header. */ |
static int |
simple_object_xcoff_write_scnhdr (simple_object_write *sobj, |
int descriptor, |
const char *name, size_t *name_offset, |
off_t scnhdr_offset, size_t scnsize, |
off_t offset, unsigned int align, |
const char **errmsg, int *err) |
{ |
struct simple_object_xcoff_read *ocr = |
(struct simple_object_xcoff_read *) sobj->data; |
int u64 = ocr->magic == U64_TOCMAGIC; |
void (*set_32) (unsigned char *, unsigned int); |
void (*set_64) (unsigned char *, unsigned int); |
unsigned char hdrbuf[sizeof (struct external_scnhdr)]; |
unsigned char *hdr; |
size_t namelen; |
unsigned int flags; |
set_32 = simple_object_set_big_32; |
set_64 = simple_object_set_big_32; |
memset (hdrbuf, 0, sizeof hdrbuf); |
hdr = &hdrbuf[0]; |
namelen = strlen (name); |
if (namelen <= SCNNMLEN) |
strncpy ((char *) hdr + offsetof (struct external_scnhdr, s_name), |
name, SCNNMLEN); |
else |
{ |
snprintf ((char *) hdr + offsetof (struct external_scnhdr, s_name), |
SCNNMLEN, "/%lu", (unsigned long) *name_offset); |
*name_offset += namelen + 1; |
} |
/* s_paddr left as zero. */ |
/* s_vaddr left as zero. */ |
if (u64) |
{ |
set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_size), |
scnsize); |
set_64 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_scnptr), |
offset); |
} |
else |
{ |
set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_size), |
scnsize); |
set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_scnptr), |
offset); |
} |
/* s_relptr left as zero. */ |
/* s_lnnoptr left as zero. */ |
/* s_nreloc left as zero. */ |
/* s_nlnno left as zero. */ |
flags = STYP_DATA; |
if (align > 13) |
align = 13; |
if (u64) |
set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff64.s_flags), flags); |
else |
set_32 (hdr + offsetof (struct external_scnhdr, u.xcoff32.s_flags), flags); |
return simple_object_internal_write (descriptor, scnhdr_offset, hdrbuf, |
u64 ? SCNHSZ64 : SCNHSZ32, |
errmsg, err); |
} |
/* Write out a complete XCOFF file. */ |
static const char * |
simple_object_xcoff_write_to_file (simple_object_write *sobj, int descriptor, |
int *err) |
{ |
struct simple_object_xcoff_read *ocr = |
(struct simple_object_xcoff_read *) sobj->data; |
int u64 = ocr->magic == U64_TOCMAGIC; |
unsigned int nscns, secnum; |
simple_object_write_section *section; |
off_t scnhdr_offset; |
size_t symtab_offset; |
off_t secsym_offset; |
unsigned int nsyms; |
size_t offset; |
size_t name_offset; |
const char *errmsg; |
unsigned char strsizebuf[4]; |
/* The interface doesn't give us access to the name of the input file |
yet. We want to use its basename for the FILE symbol. This is |
what 'gas' uses when told to assemble from stdin. */ |
const char *source_filename = "fake"; |
size_t sflen; |
union |
{ |
struct external_syment sym; |
union external_auxent aux; |
} syms[2]; |
void (*set_16) (unsigned char *, unsigned short); |
void (*set_32) (unsigned char *, unsigned int); |
set_16 = simple_object_set_big_16; |
set_32 = simple_object_set_big_32; |
nscns = 0; |
for (section = sobj->sections; section != NULL; section = section->next) |
++nscns; |
scnhdr_offset = sizeof (struct external_filehdr) - (u64 ? 4 : 0); |
offset = scnhdr_offset + nscns * (u64 ? SCNHSZ64 : SCNHSZ32); |
name_offset = 4; |
for (section = sobj->sections; section != NULL; section = section->next) |
{ |
size_t mask; |
size_t new_offset; |
size_t scnsize; |
struct simple_object_write_section_buffer *buffer; |
mask = (1U << section->align) - 1; |
new_offset = offset & mask; |
new_offset &= ~ mask; |
while (new_offset > offset) |
{ |
unsigned char zeroes[16]; |
size_t write; |
memset (zeroes, 0, sizeof zeroes); |
write = new_offset - offset; |
if (write > sizeof zeroes) |
write = sizeof zeroes; |
if (!simple_object_internal_write (descriptor, offset, zeroes, write, |
&errmsg, err)) |
return errmsg; |
} |
scnsize = 0; |
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) |
{ |
if (!simple_object_internal_write (descriptor, offset + scnsize, |
((const unsigned char *) |
buffer->buffer), |
buffer->size, &errmsg, err)) |
return errmsg; |
scnsize += buffer->size; |
} |
if (!simple_object_xcoff_write_scnhdr (sobj, descriptor, section->name, |
&name_offset, scnhdr_offset, |
scnsize, offset, section->align, |
&errmsg, err)) |
return errmsg; |
scnhdr_offset += u64 ? SCNHSZ64 : SCNHSZ32; |
offset += scnsize; |
} |
/* Symbol table is always half-word aligned. */ |
offset += (offset & 1); |
/* There is a file symbol and a section symbol per section, |
and each of these has a single auxiliary symbol following. */ |
nsyms = 2 * (nscns + 1); |
symtab_offset = offset; |
/* Advance across space reserved for symbol table to locate |
start of string table. */ |
offset += nsyms * SYMESZ; |
/* Write out file symbol. */ |
memset (&syms[0], 0, sizeof (syms)); |
if (!u64) |
strcpy ((char *)&syms[0].sym.u.xcoff32.n.n_name[0], ".file"); |
set_16 (&syms[0].sym.n_scnum[0], N_DEBUG); |
set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE); |
syms[0].sym.n_sclass[0] = C_FILE; |
syms[0].sym.n_numaux[0] = 1; |
/* The name need not be nul-terminated if it fits into the x_fname field |
directly, but must be if it has to be placed into the string table. */ |
sflen = strlen (source_filename); |
if (sflen <= FILNMLEN) |
memcpy (&syms[1].aux.x_file.x_fname[0], source_filename, sflen); |
else |
{ |
set_32 (&syms[1].aux.x_file._x.x_offset[0], name_offset); |
if (!simple_object_internal_write (descriptor, offset + name_offset, |
((const unsigned char *) |
source_filename), |
sflen + 1, &errmsg, err)) |
return errmsg; |
name_offset += strlen (source_filename) + 1; |
} |
if (!simple_object_internal_write (descriptor, symtab_offset, |
(const unsigned char *) &syms[0], |
sizeof (syms), &errmsg, err)) |
return errmsg; |
/* Write the string table length, followed by the strings and section |
symbols in step with each other. */ |
set_32 (strsizebuf, name_offset); |
if (!simple_object_internal_write (descriptor, offset, strsizebuf, 4, |
&errmsg, err)) |
return errmsg; |
name_offset = 4; |
secsym_offset = symtab_offset + sizeof (syms); |
memset (&syms[0], 0, sizeof (syms)); |
set_16 (&syms[0].sym.n_type[0], IMAGE_SYM_TYPE); |
syms[0].sym.n_sclass[0] = C_STAT; |
syms[0].sym.n_numaux[0] = 1; |
secnum = 1; |
for (section = sobj->sections; section != NULL; section = section->next) |
{ |
size_t namelen; |
size_t scnsize; |
struct simple_object_write_section_buffer *buffer; |
namelen = strlen (section->name); |
set_16 (&syms[0].sym.n_scnum[0], secnum++); |
scnsize = 0; |
for (buffer = section->buffers; buffer != NULL; buffer = buffer->next) |
scnsize += buffer->size; |
set_32 (&syms[1].aux.x_scn.x_scnlen[0], scnsize); |
if (namelen > SCNNMLEN) |
{ |
set_32 (&syms[0].sym.u.xcoff32.n.n.n_zeroes[0], 0); |
set_32 (&syms[0].sym.u.xcoff32.n.n.n_offset[0], name_offset); |
if (!simple_object_internal_write (descriptor, offset + name_offset, |
((const unsigned char *) |
section->name), |
namelen + 1, &errmsg, err)) |
return errmsg; |
name_offset += namelen + 1; |
} |
else |
{ |
memcpy (&syms[0].sym.u.xcoff32.n.n_name[0], section->name, |
strlen (section->name)); |
memset (&syms[0].sym.u.xcoff32.n.n_name[strlen (section->name)], 0, |
N_SYMNMLEN - strlen (section->name)); |
} |
if (!simple_object_internal_write (descriptor, secsym_offset, |
(const unsigned char *) &syms[0], |
sizeof (syms), &errmsg, err)) |
return errmsg; |
secsym_offset += sizeof (syms); |
} |
if (!simple_object_xcoff_write_filehdr (sobj, descriptor, nscns, |
symtab_offset, nsyms, &errmsg, err)) |
return errmsg; |
return NULL; |
} |
/* Release the private data for an simple_object_write structure. */ |
static void |
simple_object_xcoff_release_write (void *data) |
{ |
XDELETE (data); |
} |
/* The XCOFF functions. */ |
const struct simple_object_functions simple_object_xcoff_functions = |
{ |
simple_object_xcoff_match, |
simple_object_xcoff_find_sections, |
simple_object_xcoff_fetch_attributes, |
simple_object_xcoff_release_read, |
simple_object_xcoff_attributes_merge, |
simple_object_xcoff_release_attributes, |
simple_object_xcoff_start_write, |
simple_object_xcoff_write_to_file, |
simple_object_xcoff_release_write |
}; |
/contrib/toolchain/binutils/libiberty/simple-object.c |
---|
0,0 → 1,423 |
/* simple-object.c -- simple routines to read and write object files. |
Copyright 2010 Free Software Foundation, Inc. |
Written by Ian Lance Taylor, Google. |
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, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#include "config.h" |
#include "libiberty.h" |
#include "simple-object.h" |
#include <errno.h> |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STDINT_H |
#include <stdint.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifdef HAVE_INTTYPES_H |
#include <inttypes.h> |
#endif |
#ifndef SEEK_SET |
#define SEEK_SET 0 |
#endif |
#include "simple-object-common.h" |
/* The known object file formats. */ |
static const struct simple_object_functions * const format_functions[] = |
{ |
&simple_object_elf_functions, |
&simple_object_mach_o_functions, |
&simple_object_coff_functions, |
&simple_object_xcoff_functions |
}; |
/* Read data from a file using the simple_object error reporting |
conventions. */ |
int |
simple_object_internal_read (int descriptor, off_t offset, |
unsigned char *buffer, size_t size, |
const char **errmsg, int *err) |
{ |
ssize_t got; |
if (lseek (descriptor, offset, SEEK_SET) < 0) |
{ |
*errmsg = "lseek"; |
*err = errno; |
return 0; |
} |
got = read (descriptor, buffer, size); |
if (got < 0) |
{ |
*errmsg = "read"; |
*err = errno; |
return 0; |
} |
if ((size_t) got < size) |
{ |
*errmsg = "file too short"; |
*err = 0; |
return 0; |
} |
return 1; |
} |
/* Write data to a file using the simple_object error reporting |
conventions. */ |
int |
simple_object_internal_write (int descriptor, off_t offset, |
const unsigned char *buffer, size_t size, |
const char **errmsg, int *err) |
{ |
ssize_t wrote; |
if (lseek (descriptor, offset, SEEK_SET) < 0) |
{ |
*errmsg = "lseek"; |
*err = errno; |
return 0; |
} |
wrote = write (descriptor, buffer, size); |
if (wrote < 0) |
{ |
*errmsg = "write"; |
*err = errno; |
return 0; |
} |
if ((size_t) wrote < size) |
{ |
*errmsg = "short write"; |
*err = 0; |
return 0; |
} |
return 1; |
} |
/* Open for read. */ |
simple_object_read * |
simple_object_start_read (int descriptor, off_t offset, |
const char *segment_name, const char **errmsg, |
int *err) |
{ |
unsigned char header[SIMPLE_OBJECT_MATCH_HEADER_LEN]; |
size_t len, i; |
if (!simple_object_internal_read (descriptor, offset, header, |
SIMPLE_OBJECT_MATCH_HEADER_LEN, |
errmsg, err)) |
return NULL; |
len = sizeof (format_functions) / sizeof (format_functions[0]); |
for (i = 0; i < len; ++i) |
{ |
void *data; |
data = format_functions[i]->match (header, descriptor, offset, |
segment_name, errmsg, err); |
if (data != NULL) |
{ |
simple_object_read *ret; |
ret = XNEW (simple_object_read); |
ret->descriptor = descriptor; |
ret->offset = offset; |
ret->functions = format_functions[i]; |
ret->data = data; |
return ret; |
} |
} |
*errmsg = "file not recognized"; |
*err = 0; |
return NULL; |
} |
/* Find all sections. */ |
const char * |
simple_object_find_sections (simple_object_read *sobj, |
int (*pfn) (void *, const char *, off_t, off_t), |
void *data, |
int *err) |
{ |
return sobj->functions->find_sections (sobj, pfn, data, err); |
} |
/* Internal data passed to find_one_section. */ |
struct find_one_section_data |
{ |
/* The section we are looking for. */ |
const char *name; |
/* Where to store the section offset. */ |
off_t *offset; |
/* Where to store the section length. */ |
off_t *length; |
/* Set if the name is found. */ |
int found; |
}; |
/* Internal function passed to find_sections. */ |
static int |
find_one_section (void *data, const char *name, off_t offset, off_t length) |
{ |
struct find_one_section_data *fosd = (struct find_one_section_data *) data; |
if (strcmp (name, fosd->name) != 0) |
return 1; |
*fosd->offset = offset; |
*fosd->length = length; |
fosd->found = 1; |
/* Stop iteration. */ |
return 0; |
} |
/* Find a section. */ |
int |
simple_object_find_section (simple_object_read *sobj, const char *name, |
off_t *offset, off_t *length, |
const char **errmsg, int *err) |
{ |
struct find_one_section_data fosd; |
fosd.name = name; |
fosd.offset = offset; |
fosd.length = length; |
fosd.found = 0; |
*errmsg = simple_object_find_sections (sobj, find_one_section, |
(void *) &fosd, err); |
if (*errmsg != NULL) |
return 0; |
if (!fosd.found) |
return 0; |
return 1; |
} |
/* Fetch attributes. */ |
simple_object_attributes * |
simple_object_fetch_attributes (simple_object_read *sobj, const char **errmsg, |
int *err) |
{ |
void *data; |
simple_object_attributes *ret; |
data = sobj->functions->fetch_attributes (sobj, errmsg, err); |
if (data == NULL) |
return NULL; |
ret = XNEW (simple_object_attributes); |
ret->functions = sobj->functions; |
ret->data = data; |
return ret; |
} |
/* Release an simple_object_read. */ |
void |
simple_object_release_read (simple_object_read *sobj) |
{ |
sobj->functions->release_read (sobj->data); |
XDELETE (sobj); |
} |
/* Merge attributes. */ |
const char * |
simple_object_attributes_merge (simple_object_attributes *to, |
simple_object_attributes *from, |
int *err) |
{ |
if (to->functions != from->functions) |
{ |
*err = 0; |
return "different object file format"; |
} |
return to->functions->attributes_merge (to->data, from->data, err); |
} |
/* Release an attributes structure. */ |
void |
simple_object_release_attributes (simple_object_attributes *attrs) |
{ |
attrs->functions->release_attributes (attrs->data); |
XDELETE (attrs); |
} |
/* Start creating an object file. */ |
simple_object_write * |
simple_object_start_write (simple_object_attributes *attrs, |
const char *segment_name, const char **errmsg, |
int *err) |
{ |
void *data; |
simple_object_write *ret; |
data = attrs->functions->start_write (attrs->data, errmsg, err); |
if (data == NULL) |
return NULL; |
ret = XNEW (simple_object_write); |
ret->functions = attrs->functions; |
ret->segment_name = xstrdup (segment_name); |
ret->sections = NULL; |
ret->last_section = NULL; |
ret->data = data; |
return ret; |
} |
/* Start creating a section. */ |
simple_object_write_section * |
simple_object_write_create_section (simple_object_write *sobj, const char *name, |
unsigned int align, |
const char **errmsg ATTRIBUTE_UNUSED, |
int *err ATTRIBUTE_UNUSED) |
{ |
simple_object_write_section *ret; |
ret = XNEW (simple_object_write_section); |
ret->next = NULL; |
ret->name = xstrdup (name); |
ret->align = align; |
ret->buffers = NULL; |
ret->last_buffer = NULL; |
if (sobj->last_section == NULL) |
{ |
sobj->sections = ret; |
sobj->last_section = ret; |
} |
else |
{ |
sobj->last_section->next = ret; |
sobj->last_section = ret; |
} |
return ret; |
} |
/* Add data to a section. */ |
const char * |
simple_object_write_add_data (simple_object_write *sobj ATTRIBUTE_UNUSED, |
simple_object_write_section *section, |
const void *buffer, |
size_t size, int copy, |
int *err ATTRIBUTE_UNUSED) |
{ |
struct simple_object_write_section_buffer *wsb; |
wsb = XNEW (struct simple_object_write_section_buffer); |
wsb->next = NULL; |
wsb->size = size; |
if (!copy) |
{ |
wsb->buffer = buffer; |
wsb->free_buffer = NULL; |
} |
else |
{ |
wsb->free_buffer = (void *) XNEWVEC (char, size); |
memcpy (wsb->free_buffer, buffer, size); |
wsb->buffer = wsb->free_buffer; |
} |
if (section->last_buffer == NULL) |
{ |
section->buffers = wsb; |
section->last_buffer = wsb; |
} |
else |
{ |
section->last_buffer->next = wsb; |
section->last_buffer = wsb; |
} |
return NULL; |
} |
/* Write the complete object file. */ |
const char * |
simple_object_write_to_file (simple_object_write *sobj, int descriptor, |
int *err) |
{ |
return sobj->functions->write_to_file (sobj, descriptor, err); |
} |
/* Release an simple_object_write. */ |
void |
simple_object_release_write (simple_object_write *sobj) |
{ |
simple_object_write_section *section; |
free (sobj->segment_name); |
section = sobj->sections; |
while (section != NULL) |
{ |
struct simple_object_write_section_buffer *buffer; |
simple_object_write_section *next_section; |
buffer = section->buffers; |
while (buffer != NULL) |
{ |
struct simple_object_write_section_buffer *next_buffer; |
if (buffer->free_buffer != NULL) |
XDELETEVEC (buffer->free_buffer); |
next_buffer = buffer->next; |
XDELETE (buffer); |
buffer = next_buffer; |
} |
next_section = section->next; |
free (section->name); |
XDELETE (section); |
section = next_section; |
} |
sobj->functions->release_write (sobj->data); |
XDELETE (sobj); |
} |
/contrib/toolchain/binutils/libiberty/sort.c |
---|
0,0 → 1,186 |
/* Sorting algorithms. |
Copyright (C) 2000 Free Software Foundation, Inc. |
Contributed by Mark Mitchell <mark@codesourcery.com>. |
This file is part of GNU CC. |
GNU CC 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. |
GNU CC 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 GNU CC; see the file COPYING. If not, write to |
the Free Software Foundation, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "libiberty.h" |
#include "sort.h" |
#ifdef HAVE_LIMITS_H |
#include <limits.h> |
#endif |
#ifdef HAVE_SYS_PARAM_H |
#include <sys/param.h> |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifndef UCHAR_MAX |
#define UCHAR_MAX ((unsigned char)(-1)) |
#endif |
/* POINTERS and WORK are both arrays of N pointers. When this |
function returns POINTERS will be sorted in ascending order. */ |
void sort_pointers (size_t n, void **pointers, void **work) |
{ |
/* The type of a single digit. This can be any unsigned integral |
type. When changing this, DIGIT_MAX should be changed as |
well. */ |
typedef unsigned char digit_t; |
/* The maximum value a single digit can have. */ |
#define DIGIT_MAX (UCHAR_MAX + 1) |
/* The Ith entry is the number of elements in *POINTERSP that have I |
in the digit on which we are currently sorting. */ |
unsigned int count[DIGIT_MAX]; |
/* Nonzero if we are running on a big-endian machine. */ |
int big_endian_p; |
size_t i; |
size_t j; |
/* The algorithm used here is radix sort which takes time linear in |
the number of elements in the array. */ |
/* The algorithm here depends on being able to swap the two arrays |
an even number of times. */ |
if ((sizeof (void *) / sizeof (digit_t)) % 2 != 0) |
abort (); |
/* Figure out the endianness of the machine. */ |
for (i = 0, j = 0; i < sizeof (size_t); ++i) |
{ |
j *= (UCHAR_MAX + 1); |
j += i; |
} |
big_endian_p = (((char *)&j)[0] == 0); |
/* Move through the pointer values from least significant to most |
significant digits. */ |
for (i = 0; i < sizeof (void *) / sizeof (digit_t); ++i) |
{ |
digit_t *digit; |
digit_t *bias; |
digit_t *top; |
unsigned int *countp; |
void **pointerp; |
/* The offset from the start of the pointer will depend on the |
endianness of the machine. */ |
if (big_endian_p) |
j = sizeof (void *) / sizeof (digit_t) - i; |
else |
j = i; |
/* Now, perform a stable sort on this digit. We use counting |
sort. */ |
memset (count, 0, DIGIT_MAX * sizeof (unsigned int)); |
/* Compute the address of the appropriate digit in the first and |
one-past-the-end elements of the array. On a little-endian |
machine, the least-significant digit is closest to the front. */ |
bias = ((digit_t *) pointers) + j; |
top = ((digit_t *) (pointers + n)) + j; |
/* Count how many there are of each value. At the end of this |
loop, COUNT[K] will contain the number of pointers whose Ith |
digit is K. */ |
for (digit = bias; |
digit < top; |
digit += sizeof (void *) / sizeof (digit_t)) |
++count[*digit]; |
/* Now, make COUNT[K] contain the number of pointers whose Ith |
digit is less than or equal to K. */ |
for (countp = count + 1; countp < count + DIGIT_MAX; ++countp) |
*countp += countp[-1]; |
/* Now, drop the pointers into their correct locations. */ |
for (pointerp = pointers + n - 1; pointerp >= pointers; --pointerp) |
work[--count[((digit_t *) pointerp)[j]]] = *pointerp; |
/* Swap WORK and POINTERS so that POINTERS contains the sorted |
array. */ |
pointerp = pointers; |
pointers = work; |
work = pointerp; |
} |
} |
/* Everything below here is a unit test for the routines in this |
file. */ |
#ifdef UNIT_TEST |
#include <stdio.h> |
void *xmalloc (size_t n) |
{ |
return malloc (n); |
} |
int main (int argc, char **argv) |
{ |
int k; |
int result; |
size_t i; |
void **pointers; |
void **work; |
if (argc > 1) |
k = atoi (argv[1]); |
else |
k = 10; |
pointers = XNEWVEC (void*, k); |
work = XNEWVEC (void*, k); |
for (i = 0; i < k; ++i) |
{ |
pointers[i] = (void *) random (); |
printf ("%x\n", pointers[i]); |
} |
sort_pointers (k, pointers, work); |
printf ("\nSorted\n\n"); |
result = 0; |
for (i = 0; i < k; ++i) |
{ |
printf ("%x\n", pointers[i]); |
if (i > 0 && (char*) pointers[i] < (char*) pointers[i - 1]) |
result = 1; |
} |
free (pointers); |
free (work); |
return result; |
} |
#endif |
/contrib/toolchain/binutils/libiberty/spaces.c |
---|
0,0 → 1,69 |
/* Allocate memory region filled with spaces. |
Copyright (C) 1991 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Extension char* spaces (int @var{count}) |
Returns a pointer to a memory region filled with the specified |
number of spaces and null terminated. The returned pointer is |
valid until at least the next call. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#if VMS |
#include <stdlib.h> |
#include <unixlib.h> |
#else |
/* For systems with larger pointers than ints, these must be declared. */ |
extern PTR malloc (size_t); |
extern void free (PTR); |
#endif |
const char * |
spaces (int count) |
{ |
register char *t; |
static char *buf; |
static int maxsize; |
if (count > maxsize) |
{ |
free (buf); |
buf = (char *) malloc (count + 1); |
if (buf == (char *) 0) |
return 0; |
for (t = buf + count ; t != buf ; ) |
{ |
*--t = ' '; |
} |
maxsize = count; |
buf[count] = '\0'; |
} |
return (const char *) (buf + maxsize - count); |
} |
/contrib/toolchain/binutils/libiberty/splay-tree.c |
---|
0,0 → 1,593 |
/* A splay-tree datatype. |
Copyright (C) 1998, 1999, 2000, 2001, 2009, |
2010, 2011 Free Software Foundation, Inc. |
Contributed by Mark Mitchell (mark@markmitchell.com). |
This file is part of GNU CC. |
GNU CC 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. |
GNU CC 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 GNU CC; see the file COPYING. If not, write to |
the Free Software Foundation, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* For an easily readable description of splay-trees, see: |
Lewis, Harry R. and Denenberg, Larry. Data Structures and Their |
Algorithms. Harper-Collins, Inc. 1991. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#include <stdio.h> |
#include "libiberty.h" |
#include "splay-tree.h" |
static void splay_tree_delete_helper (splay_tree, splay_tree_node); |
static inline void rotate_left (splay_tree_node *, |
splay_tree_node, splay_tree_node); |
static inline void rotate_right (splay_tree_node *, |
splay_tree_node, splay_tree_node); |
static void splay_tree_splay (splay_tree, splay_tree_key); |
static int splay_tree_foreach_helper (splay_tree_node, |
splay_tree_foreach_fn, void*); |
/* Deallocate NODE (a member of SP), and all its sub-trees. */ |
static void |
splay_tree_delete_helper (splay_tree sp, splay_tree_node node) |
{ |
splay_tree_node pending = 0; |
splay_tree_node active = 0; |
if (!node) |
return; |
#define KDEL(x) if (sp->delete_key) (*sp->delete_key)(x); |
#define VDEL(x) if (sp->delete_value) (*sp->delete_value)(x); |
KDEL (node->key); |
VDEL (node->value); |
/* We use the "key" field to hold the "next" pointer. */ |
node->key = (splay_tree_key)pending; |
pending = (splay_tree_node)node; |
/* Now, keep processing the pending list until there aren't any |
more. This is a little more complicated than just recursing, but |
it doesn't toast the stack for large trees. */ |
while (pending) |
{ |
active = pending; |
pending = 0; |
while (active) |
{ |
splay_tree_node temp; |
/* active points to a node which has its key and value |
deallocated, we just need to process left and right. */ |
if (active->left) |
{ |
KDEL (active->left->key); |
VDEL (active->left->value); |
active->left->key = (splay_tree_key)pending; |
pending = (splay_tree_node)(active->left); |
} |
if (active->right) |
{ |
KDEL (active->right->key); |
VDEL (active->right->value); |
active->right->key = (splay_tree_key)pending; |
pending = (splay_tree_node)(active->right); |
} |
temp = active; |
active = (splay_tree_node)(temp->key); |
(*sp->deallocate) ((char*) temp, sp->allocate_data); |
} |
} |
#undef KDEL |
#undef VDEL |
} |
/* Rotate the edge joining the left child N with its parent P. PP is the |
grandparents' pointer to P. */ |
static inline void |
rotate_left (splay_tree_node *pp, splay_tree_node p, splay_tree_node n) |
{ |
splay_tree_node tmp; |
tmp = n->right; |
n->right = p; |
p->left = tmp; |
*pp = n; |
} |
/* Rotate the edge joining the right child N with its parent P. PP is the |
grandparents' pointer to P. */ |
static inline void |
rotate_right (splay_tree_node *pp, splay_tree_node p, splay_tree_node n) |
{ |
splay_tree_node tmp; |
tmp = n->left; |
n->left = p; |
p->right = tmp; |
*pp = n; |
} |
/* Bottom up splay of key. */ |
static void |
splay_tree_splay (splay_tree sp, splay_tree_key key) |
{ |
if (sp->root == 0) |
return; |
do { |
int cmp1, cmp2; |
splay_tree_node n, c; |
n = sp->root; |
cmp1 = (*sp->comp) (key, n->key); |
/* Found. */ |
if (cmp1 == 0) |
return; |
/* Left or right? If no child, then we're done. */ |
if (cmp1 < 0) |
c = n->left; |
else |
c = n->right; |
if (!c) |
return; |
/* Next one left or right? If found or no child, we're done |
after one rotation. */ |
cmp2 = (*sp->comp) (key, c->key); |
if (cmp2 == 0 |
|| (cmp2 < 0 && !c->left) |
|| (cmp2 > 0 && !c->right)) |
{ |
if (cmp1 < 0) |
rotate_left (&sp->root, n, c); |
else |
rotate_right (&sp->root, n, c); |
return; |
} |
/* Now we have the four cases of double-rotation. */ |
if (cmp1 < 0 && cmp2 < 0) |
{ |
rotate_left (&n->left, c, c->left); |
rotate_left (&sp->root, n, n->left); |
} |
else if (cmp1 > 0 && cmp2 > 0) |
{ |
rotate_right (&n->right, c, c->right); |
rotate_right (&sp->root, n, n->right); |
} |
else if (cmp1 < 0 && cmp2 > 0) |
{ |
rotate_right (&n->left, c, c->right); |
rotate_left (&sp->root, n, n->left); |
} |
else if (cmp1 > 0 && cmp2 < 0) |
{ |
rotate_left (&n->right, c, c->left); |
rotate_right (&sp->root, n, n->right); |
} |
} while (1); |
} |
/* Call FN, passing it the DATA, for every node below NODE, all of |
which are from SP, following an in-order traversal. If FN every |
returns a non-zero value, the iteration ceases immediately, and the |
value is returned. Otherwise, this function returns 0. */ |
static int |
splay_tree_foreach_helper (splay_tree_node node, |
splay_tree_foreach_fn fn, void *data) |
{ |
int val; |
splay_tree_node *stack; |
int stack_ptr, stack_size; |
/* A non-recursive implementation is used to avoid filling the stack |
for large trees. Splay trees are worst case O(n) in the depth of |
the tree. */ |
#define INITIAL_STACK_SIZE 100 |
stack_size = INITIAL_STACK_SIZE; |
stack_ptr = 0; |
stack = XNEWVEC (splay_tree_node, stack_size); |
val = 0; |
for (;;) |
{ |
while (node != NULL) |
{ |
if (stack_ptr == stack_size) |
{ |
stack_size *= 2; |
stack = XRESIZEVEC (splay_tree_node, stack, stack_size); |
} |
stack[stack_ptr++] = node; |
node = node->left; |
} |
if (stack_ptr == 0) |
break; |
node = stack[--stack_ptr]; |
val = (*fn) (node, data); |
if (val) |
break; |
node = node->right; |
} |
XDELETEVEC (stack); |
return val; |
} |
/* An allocator and deallocator based on xmalloc. */ |
static void * |
splay_tree_xmalloc_allocate (int size, void *data ATTRIBUTE_UNUSED) |
{ |
return (void *) xmalloc (size); |
} |
static void |
splay_tree_xmalloc_deallocate (void *object, void *data ATTRIBUTE_UNUSED) |
{ |
free (object); |
} |
/* Allocate a new splay tree, using COMPARE_FN to compare nodes, |
DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate |
values. Use xmalloc to allocate the splay tree structure, and any |
nodes added. */ |
splay_tree |
splay_tree_new (splay_tree_compare_fn compare_fn, |
splay_tree_delete_key_fn delete_key_fn, |
splay_tree_delete_value_fn delete_value_fn) |
{ |
return (splay_tree_new_with_allocator |
(compare_fn, delete_key_fn, delete_value_fn, |
splay_tree_xmalloc_allocate, splay_tree_xmalloc_deallocate, 0)); |
} |
/* Allocate a new splay tree, using COMPARE_FN to compare nodes, |
DELETE_KEY_FN to deallocate keys, and DELETE_VALUE_FN to deallocate |
values. */ |
splay_tree |
splay_tree_new_with_allocator (splay_tree_compare_fn compare_fn, |
splay_tree_delete_key_fn delete_key_fn, |
splay_tree_delete_value_fn delete_value_fn, |
splay_tree_allocate_fn allocate_fn, |
splay_tree_deallocate_fn deallocate_fn, |
void *allocate_data) |
{ |
return |
splay_tree_new_typed_alloc (compare_fn, delete_key_fn, delete_value_fn, |
allocate_fn, allocate_fn, deallocate_fn, |
allocate_data); |
} |
/* |
@deftypefn Supplemental splay_tree splay_tree_new_with_typed_alloc @ |
(splay_tree_compare_fn @var{compare_fn}, @ |
splay_tree_delete_key_fn @var{delete_key_fn}, @ |
splay_tree_delete_value_fn @var{delete_value_fn}, @ |
splay_tree_allocate_fn @var{tree_allocate_fn}, @ |
splay_tree_allocate_fn @var{node_allocate_fn}, @ |
splay_tree_deallocate_fn @var{deallocate_fn}, @ |
void * @var{allocate_data}) |
This function creates a splay tree that uses two different allocators |
@var{tree_allocate_fn} and @var{node_allocate_fn} to use for allocating the |
tree itself and its nodes respectively. This is useful when variables of |
different types need to be allocated with different allocators. |
The splay tree will use @var{compare_fn} to compare nodes, |
@var{delete_key_fn} to deallocate keys, and @var{delete_value_fn} to |
deallocate values. |
@end deftypefn |
*/ |
splay_tree |
splay_tree_new_typed_alloc (splay_tree_compare_fn compare_fn, |
splay_tree_delete_key_fn delete_key_fn, |
splay_tree_delete_value_fn delete_value_fn, |
splay_tree_allocate_fn tree_allocate_fn, |
splay_tree_allocate_fn node_allocate_fn, |
splay_tree_deallocate_fn deallocate_fn, |
void * allocate_data) |
{ |
splay_tree sp = (splay_tree) (*tree_allocate_fn) |
(sizeof (struct splay_tree_s), allocate_data); |
sp->root = 0; |
sp->comp = compare_fn; |
sp->delete_key = delete_key_fn; |
sp->delete_value = delete_value_fn; |
sp->allocate = node_allocate_fn; |
sp->deallocate = deallocate_fn; |
sp->allocate_data = allocate_data; |
return sp; |
} |
/* Deallocate SP. */ |
void |
splay_tree_delete (splay_tree sp) |
{ |
splay_tree_delete_helper (sp, sp->root); |
(*sp->deallocate) ((char*) sp, sp->allocate_data); |
} |
/* Insert a new node (associating KEY with DATA) into SP. If a |
previous node with the indicated KEY exists, its data is replaced |
with the new value. Returns the new node. */ |
splay_tree_node |
splay_tree_insert (splay_tree sp, splay_tree_key key, splay_tree_value value) |
{ |
int comparison = 0; |
splay_tree_splay (sp, key); |
if (sp->root) |
comparison = (*sp->comp)(sp->root->key, key); |
if (sp->root && comparison == 0) |
{ |
/* If the root of the tree already has the indicated KEY, just |
replace the value with VALUE. */ |
if (sp->delete_value) |
(*sp->delete_value)(sp->root->value); |
sp->root->value = value; |
} |
else |
{ |
/* Create a new node, and insert it at the root. */ |
splay_tree_node node; |
node = ((splay_tree_node) |
(*sp->allocate) (sizeof (struct splay_tree_node_s), |
sp->allocate_data)); |
node->key = key; |
node->value = value; |
if (!sp->root) |
node->left = node->right = 0; |
else if (comparison < 0) |
{ |
node->left = sp->root; |
node->right = node->left->right; |
node->left->right = 0; |
} |
else |
{ |
node->right = sp->root; |
node->left = node->right->left; |
node->right->left = 0; |
} |
sp->root = node; |
} |
return sp->root; |
} |
/* Remove KEY from SP. It is not an error if it did not exist. */ |
void |
splay_tree_remove (splay_tree sp, splay_tree_key key) |
{ |
splay_tree_splay (sp, key); |
if (sp->root && (*sp->comp) (sp->root->key, key) == 0) |
{ |
splay_tree_node left, right; |
left = sp->root->left; |
right = sp->root->right; |
/* Delete the root node itself. */ |
if (sp->delete_value) |
(*sp->delete_value) (sp->root->value); |
(*sp->deallocate) (sp->root, sp->allocate_data); |
/* One of the children is now the root. Doesn't matter much |
which, so long as we preserve the properties of the tree. */ |
if (left) |
{ |
sp->root = left; |
/* If there was a right child as well, hang it off the |
right-most leaf of the left child. */ |
if (right) |
{ |
while (left->right) |
left = left->right; |
left->right = right; |
} |
} |
else |
sp->root = right; |
} |
} |
/* Lookup KEY in SP, returning VALUE if present, and NULL |
otherwise. */ |
splay_tree_node |
splay_tree_lookup (splay_tree sp, splay_tree_key key) |
{ |
splay_tree_splay (sp, key); |
if (sp->root && (*sp->comp)(sp->root->key, key) == 0) |
return sp->root; |
else |
return 0; |
} |
/* Return the node in SP with the greatest key. */ |
splay_tree_node |
splay_tree_max (splay_tree sp) |
{ |
splay_tree_node n = sp->root; |
if (!n) |
return NULL; |
while (n->right) |
n = n->right; |
return n; |
} |
/* Return the node in SP with the smallest key. */ |
splay_tree_node |
splay_tree_min (splay_tree sp) |
{ |
splay_tree_node n = sp->root; |
if (!n) |
return NULL; |
while (n->left) |
n = n->left; |
return n; |
} |
/* Return the immediate predecessor KEY, or NULL if there is no |
predecessor. KEY need not be present in the tree. */ |
splay_tree_node |
splay_tree_predecessor (splay_tree sp, splay_tree_key key) |
{ |
int comparison; |
splay_tree_node node; |
/* If the tree is empty, there is certainly no predecessor. */ |
if (!sp->root) |
return NULL; |
/* Splay the tree around KEY. That will leave either the KEY |
itself, its predecessor, or its successor at the root. */ |
splay_tree_splay (sp, key); |
comparison = (*sp->comp)(sp->root->key, key); |
/* If the predecessor is at the root, just return it. */ |
if (comparison < 0) |
return sp->root; |
/* Otherwise, find the rightmost element of the left subtree. */ |
node = sp->root->left; |
if (node) |
while (node->right) |
node = node->right; |
return node; |
} |
/* Return the immediate successor KEY, or NULL if there is no |
successor. KEY need not be present in the tree. */ |
splay_tree_node |
splay_tree_successor (splay_tree sp, splay_tree_key key) |
{ |
int comparison; |
splay_tree_node node; |
/* If the tree is empty, there is certainly no successor. */ |
if (!sp->root) |
return NULL; |
/* Splay the tree around KEY. That will leave either the KEY |
itself, its predecessor, or its successor at the root. */ |
splay_tree_splay (sp, key); |
comparison = (*sp->comp)(sp->root->key, key); |
/* If the successor is at the root, just return it. */ |
if (comparison > 0) |
return sp->root; |
/* Otherwise, find the leftmost element of the right subtree. */ |
node = sp->root->right; |
if (node) |
while (node->left) |
node = node->left; |
return node; |
} |
/* Call FN, passing it the DATA, for every node in SP, following an |
in-order traversal. If FN every returns a non-zero value, the |
iteration ceases immediately, and the value is returned. |
Otherwise, this function returns 0. */ |
int |
splay_tree_foreach (splay_tree sp, splay_tree_foreach_fn fn, void *data) |
{ |
return splay_tree_foreach_helper (sp->root, fn, data); |
} |
/* Splay-tree comparison function, treating the keys as ints. */ |
int |
splay_tree_compare_ints (splay_tree_key k1, splay_tree_key k2) |
{ |
if ((int) k1 < (int) k2) |
return -1; |
else if ((int) k1 > (int) k2) |
return 1; |
else |
return 0; |
} |
/* Splay-tree comparison function, treating the keys as pointers. */ |
int |
splay_tree_compare_pointers (splay_tree_key k1, splay_tree_key k2) |
{ |
if ((char*) k1 < (char*) k2) |
return -1; |
else if ((char*) k1 > (char*) k2) |
return 1; |
else |
return 0; |
} |
/contrib/toolchain/binutils/libiberty/stack-limit.c |
---|
0,0 → 1,63 |
/* Increase stack size limit if possible. |
Copyright (C) 2011 Free Software Foundation, Inc. |
This file is part of the libiberty library. This 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. |
This 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. |
You should have received a copy of the GNU General Public License |
along with GNU CC; see the file COPYING. If not, write to |
the Free Software Foundation, 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. |
As a special exception, if you link this library with files |
compiled with a GNU compiler to produce an executable, this does not cause |
the resulting executable to be covered by the GNU General Public License. |
This exception does not however invalidate any other reasons why |
the executable file might be covered by the GNU General Public License. */ |
/* |
@deftypefn Extension void stack_limit_increase (unsigned long @var{pref}) |
Attempt to increase stack size limit to @var{pref} bytes if possible. |
@end deftypefn |
*/ |
#include "config.h" |
#include "ansidecl.h" |
#ifdef HAVE_STDINT_H |
#include <stdint.h> |
#endif |
#ifdef HAVE_SYS_RESOURCE_H |
#include <sys/resource.h> |
#endif |
void |
stack_limit_increase (unsigned long pref ATTRIBUTE_UNUSED) |
{ |
#if defined(HAVE_SETRLIMIT) && defined(HAVE_GETRLIMIT) \ |
&& defined(RLIMIT_STACK) && defined(RLIM_INFINITY) |
struct rlimit rlim; |
if (getrlimit (RLIMIT_STACK, &rlim) == 0 |
&& rlim.rlim_cur != RLIM_INFINITY |
&& rlim.rlim_cur < pref |
&& (rlim.rlim_max == RLIM_INFINITY || rlim.rlim_cur < rlim.rlim_max)) |
{ |
rlim.rlim_cur = pref; |
if (rlim.rlim_max != RLIM_INFINITY && rlim.rlim_cur > rlim.rlim_max) |
rlim.rlim_cur = rlim.rlim_max; |
setrlimit (RLIMIT_STACK, &rlim); |
} |
#endif |
} |
/contrib/toolchain/binutils/libiberty/stpcpy.c |
---|
0,0 → 1,43 |
/* Implement the stpcpy function. |
Copyright (C) 2003 Free Software Foundation, Inc. |
Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Supplemental char* stpcpy (char *@var{dst}, const char *@var{src}) |
Copies the string @var{src} into @var{dst}. Returns a pointer to |
@var{dst} + strlen(@var{src}). |
@end deftypefn |
*/ |
#include <ansidecl.h> |
#include <stddef.h> |
extern size_t strlen (const char *); |
extern PTR memcpy (PTR, const PTR, size_t); |
char * |
stpcpy (char *dst, const char *src) |
{ |
const size_t len = strlen (src); |
return (char *) memcpy (dst, src, len + 1) + len; |
} |
/contrib/toolchain/binutils/libiberty/stpncpy.c |
---|
0,0 → 1,48 |
/* Implement the stpncpy function. |
Copyright (C) 2003, 2011 Free Software Foundation, Inc. |
Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Supplemental char* stpncpy (char *@var{dst}, const char *@var{src}, @ |
size_t @var{len}) |
Copies the string @var{src} into @var{dst}, copying exactly @var{len} |
and padding with zeros if necessary. If @var{len} < strlen(@var{src}) |
then return @var{dst} + @var{len}, otherwise returns @var{dst} + |
strlen(@var{src}). |
@end deftypefn |
*/ |
#include <ansidecl.h> |
#include <stddef.h> |
extern size_t strlen (const char *); |
extern char *strncpy (char *, const char *, size_t); |
char * |
stpncpy (char *dst, const char *src, size_t len) |
{ |
size_t n = strlen (src); |
if (n > len) |
n = len; |
return strncpy (dst, src, len) + n; |
} |
/contrib/toolchain/binutils/libiberty/strcasecmp.c |
---|
0,0 → 1,87 |
/* |
* Copyright (c) 1987 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that this notice is preserved and that due credit is given |
* to the University of California at Berkeley. The name of the University |
* may not be used to endorse or promote products derived from this |
* software without specific written prior permission. This software |
* is provided ``as is'' without express or implied warranty. |
*/ |
/* |
@deftypefn Supplemental int strcasecmp (const char *@var{s1}, const char *@var{s2}) |
A case-insensitive @code{strcmp}. |
@end deftypefn |
*/ |
#if defined(LIBC_SCCS) && !defined(lint) |
static char sccsid[] = "@(#)strcasecmp.c 5.5 (Berkeley) 11/24/87"; |
#endif /* LIBC_SCCS and not lint */ |
#include <ansidecl.h> |
#include <stddef.h> |
/* |
* This array is designed for mapping upper and lower case letter |
* together for a case independent comparison. The mappings are |
* based upon ascii character sequences. |
*/ |
typedef unsigned char uc; |
static const unsigned char charmap[] = { |
(uc)'\000',(uc)'\001',(uc)'\002',(uc)'\003',(uc)'\004',(uc)'\005',(uc)'\006',(uc)'\007', |
(uc)'\010',(uc)'\011',(uc)'\012',(uc)'\013',(uc)'\014',(uc)'\015',(uc)'\016',(uc)'\017', |
(uc)'\020',(uc)'\021',(uc)'\022',(uc)'\023',(uc)'\024',(uc)'\025',(uc)'\026',(uc)'\027', |
(uc)'\030',(uc)'\031',(uc)'\032',(uc)'\033',(uc)'\034',(uc)'\035',(uc)'\036',(uc)'\037', |
(uc)'\040',(uc)'\041',(uc)'\042',(uc)'\043',(uc)'\044',(uc)'\045',(uc)'\046',(uc)'\047', |
(uc)'\050',(uc)'\051',(uc)'\052',(uc)'\053',(uc)'\054',(uc)'\055',(uc)'\056',(uc)'\057', |
(uc)'\060',(uc)'\061',(uc)'\062',(uc)'\063',(uc)'\064',(uc)'\065',(uc)'\066',(uc)'\067', |
(uc)'\070',(uc)'\071',(uc)'\072',(uc)'\073',(uc)'\074',(uc)'\075',(uc)'\076',(uc)'\077', |
(uc)'\100',(uc)'\141',(uc)'\142',(uc)'\143',(uc)'\144',(uc)'\145',(uc)'\146',(uc)'\147', |
(uc)'\150',(uc)'\151',(uc)'\152',(uc)'\153',(uc)'\154',(uc)'\155',(uc)'\156',(uc)'\157', |
(uc)'\160',(uc)'\161',(uc)'\162',(uc)'\163',(uc)'\164',(uc)'\165',(uc)'\166',(uc)'\167', |
(uc)'\170',(uc)'\171',(uc)'\172',(uc)'\133',(uc)'\134',(uc)'\135',(uc)'\136',(uc)'\137', |
(uc)'\140',(uc)'\141',(uc)'\142',(uc)'\143',(uc)'\144',(uc)'\145',(uc)'\146',(uc)'\147', |
(uc)'\150',(uc)'\151',(uc)'\152',(uc)'\153',(uc)'\154',(uc)'\155',(uc)'\156',(uc)'\157', |
(uc)'\160',(uc)'\161',(uc)'\162',(uc)'\163',(uc)'\164',(uc)'\165',(uc)'\166',(uc)'\167', |
(uc)'\170',(uc)'\171',(uc)'\172',(uc)'\173',(uc)'\174',(uc)'\175',(uc)'\176',(uc)'\177', |
(uc)'\200',(uc)'\201',(uc)'\202',(uc)'\203',(uc)'\204',(uc)'\205',(uc)'\206',(uc)'\207', |
(uc)'\210',(uc)'\211',(uc)'\212',(uc)'\213',(uc)'\214',(uc)'\215',(uc)'\216',(uc)'\217', |
(uc)'\220',(uc)'\221',(uc)'\222',(uc)'\223',(uc)'\224',(uc)'\225',(uc)'\226',(uc)'\227', |
(uc)'\230',(uc)'\231',(uc)'\232',(uc)'\233',(uc)'\234',(uc)'\235',(uc)'\236',(uc)'\237', |
(uc)'\240',(uc)'\241',(uc)'\242',(uc)'\243',(uc)'\244',(uc)'\245',(uc)'\246',(uc)'\247', |
(uc)'\250',(uc)'\251',(uc)'\252',(uc)'\253',(uc)'\254',(uc)'\255',(uc)'\256',(uc)'\257', |
(uc)'\260',(uc)'\261',(uc)'\262',(uc)'\263',(uc)'\264',(uc)'\265',(uc)'\266',(uc)'\267', |
(uc)'\270',(uc)'\271',(uc)'\272',(uc)'\273',(uc)'\274',(uc)'\275',(uc)'\276',(uc)'\277', |
(uc)'\300',(uc)'\341',(uc)'\342',(uc)'\343',(uc)'\344',(uc)'\345',(uc)'\346',(uc)'\347', |
(uc)'\350',(uc)'\351',(uc)'\352',(uc)'\353',(uc)'\354',(uc)'\355',(uc)'\356',(uc)'\357', |
(uc)'\360',(uc)'\361',(uc)'\362',(uc)'\363',(uc)'\364',(uc)'\365',(uc)'\366',(uc)'\367', |
(uc)'\370',(uc)'\371',(uc)'\372',(uc)'\333',(uc)'\334',(uc)'\335',(uc)'\336',(uc)'\337', |
(uc)'\340',(uc)'\341',(uc)'\342',(uc)'\343',(uc)'\344',(uc)'\345',(uc)'\346',(uc)'\347', |
(uc)'\350',(uc)'\351',(uc)'\352',(uc)'\353',(uc)'\354',(uc)'\355',(uc)'\356',(uc)'\357', |
(uc)'\360',(uc)'\361',(uc)'\362',(uc)'\363',(uc)'\364',(uc)'\365',(uc)'\366',(uc)'\367', |
(uc)'\370',(uc)'\371',(uc)'\372',(uc)'\373',(uc)'\374',(uc)'\375',(uc)'\376',(uc)'\377', |
}; |
int |
strcasecmp(const char *s1, const char *s2) |
{ |
register unsigned char u1, u2; |
for (;;) { |
u1 = (unsigned char) *s1++; |
u2 = (unsigned char) *s2++; |
if (charmap[u1] != charmap[u2]) { |
return charmap[u1] - charmap[u2]; |
} |
if (u1 == '\0') { |
return 0; |
} |
} |
} |
/contrib/toolchain/binutils/libiberty/strerror.c |
---|
0,0 → 1,809 |
/* Extended support for using errno values. |
Written by Fred Fish. fnf@cygnus.com |
This file is in the public domain. --Per Bothner. */ |
#include "config.h" |
#ifdef HAVE_SYS_ERRLIST |
/* Note that errno.h (not sure what OS) or stdio.h (BSD 4.4, at least) |
might declare sys_errlist in a way that the compiler might consider |
incompatible with our later declaration, perhaps by using const |
attributes. So we hide the declaration in errno.h (if any) using a |
macro. */ |
#define sys_nerr sys_nerr__ |
#define sys_errlist sys_errlist__ |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#include <stdio.h> |
#include <errno.h> |
#ifdef HAVE_SYS_ERRLIST |
#undef sys_nerr |
#undef sys_errlist |
#endif |
/* Routines imported from standard C runtime libraries. */ |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#else |
extern PTR malloc (); |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#else |
extern PTR memset (); |
#endif |
#ifndef MAX |
# define MAX(a,b) ((a) > (b) ? (a) : (b)) |
#endif |
static void init_error_tables (void); |
/* Translation table for errno values. See intro(2) in most UNIX systems |
Programmers Reference Manuals. |
Note that this table is generally only accessed when it is used at runtime |
to initialize errno name and message tables that are indexed by errno |
value. |
Not all of these errnos will exist on all systems. This table is the only |
thing that should have to be updated as new error numbers are introduced. |
It's sort of ugly, but at least its portable. */ |
struct error_info |
{ |
const int value; /* The numeric value from <errno.h> */ |
const char *const name; /* The equivalent symbolic value */ |
#ifndef HAVE_SYS_ERRLIST |
const char *const msg; /* Short message about this value */ |
#endif |
}; |
#ifndef HAVE_SYS_ERRLIST |
# define ENTRY(value, name, msg) {value, name, msg} |
#else |
# define ENTRY(value, name, msg) {value, name} |
#endif |
static const struct error_info error_table[] = |
{ |
#if defined (EPERM) |
ENTRY(EPERM, "EPERM", "Not owner"), |
#endif |
#if defined (ENOENT) |
ENTRY(ENOENT, "ENOENT", "No such file or directory"), |
#endif |
#if defined (ESRCH) |
ENTRY(ESRCH, "ESRCH", "No such process"), |
#endif |
#if defined (EINTR) |
ENTRY(EINTR, "EINTR", "Interrupted system call"), |
#endif |
#if defined (EIO) |
ENTRY(EIO, "EIO", "I/O error"), |
#endif |
#if defined (ENXIO) |
ENTRY(ENXIO, "ENXIO", "No such device or address"), |
#endif |
#if defined (E2BIG) |
ENTRY(E2BIG, "E2BIG", "Arg list too long"), |
#endif |
#if defined (ENOEXEC) |
ENTRY(ENOEXEC, "ENOEXEC", "Exec format error"), |
#endif |
#if defined (EBADF) |
ENTRY(EBADF, "EBADF", "Bad file number"), |
#endif |
#if defined (ECHILD) |
ENTRY(ECHILD, "ECHILD", "No child processes"), |
#endif |
#if defined (EWOULDBLOCK) /* Put before EAGAIN, sometimes aliased */ |
ENTRY(EWOULDBLOCK, "EWOULDBLOCK", "Operation would block"), |
#endif |
#if defined (EAGAIN) |
ENTRY(EAGAIN, "EAGAIN", "No more processes"), |
#endif |
#if defined (ENOMEM) |
ENTRY(ENOMEM, "ENOMEM", "Not enough space"), |
#endif |
#if defined (EACCES) |
ENTRY(EACCES, "EACCES", "Permission denied"), |
#endif |
#if defined (EFAULT) |
ENTRY(EFAULT, "EFAULT", "Bad address"), |
#endif |
#if defined (ENOTBLK) |
ENTRY(ENOTBLK, "ENOTBLK", "Block device required"), |
#endif |
#if defined (EBUSY) |
ENTRY(EBUSY, "EBUSY", "Device busy"), |
#endif |
#if defined (EEXIST) |
ENTRY(EEXIST, "EEXIST", "File exists"), |
#endif |
#if defined (EXDEV) |
ENTRY(EXDEV, "EXDEV", "Cross-device link"), |
#endif |
#if defined (ENODEV) |
ENTRY(ENODEV, "ENODEV", "No such device"), |
#endif |
#if defined (ENOTDIR) |
ENTRY(ENOTDIR, "ENOTDIR", "Not a directory"), |
#endif |
#if defined (EISDIR) |
ENTRY(EISDIR, "EISDIR", "Is a directory"), |
#endif |
#if defined (EINVAL) |
ENTRY(EINVAL, "EINVAL", "Invalid argument"), |
#endif |
#if defined (ENFILE) |
ENTRY(ENFILE, "ENFILE", "File table overflow"), |
#endif |
#if defined (EMFILE) |
ENTRY(EMFILE, "EMFILE", "Too many open files"), |
#endif |
#if defined (ENOTTY) |
ENTRY(ENOTTY, "ENOTTY", "Not a typewriter"), |
#endif |
#if defined (ETXTBSY) |
ENTRY(ETXTBSY, "ETXTBSY", "Text file busy"), |
#endif |
#if defined (EFBIG) |
ENTRY(EFBIG, "EFBIG", "File too large"), |
#endif |
#if defined (ENOSPC) |
ENTRY(ENOSPC, "ENOSPC", "No space left on device"), |
#endif |
#if defined (ESPIPE) |
ENTRY(ESPIPE, "ESPIPE", "Illegal seek"), |
#endif |
#if defined (EROFS) |
ENTRY(EROFS, "EROFS", "Read-only file system"), |
#endif |
#if defined (EMLINK) |
ENTRY(EMLINK, "EMLINK", "Too many links"), |
#endif |
#if defined (EPIPE) |
ENTRY(EPIPE, "EPIPE", "Broken pipe"), |
#endif |
#if defined (EDOM) |
ENTRY(EDOM, "EDOM", "Math argument out of domain of func"), |
#endif |
#if defined (ERANGE) |
ENTRY(ERANGE, "ERANGE", "Math result not representable"), |
#endif |
#if defined (ENOMSG) |
ENTRY(ENOMSG, "ENOMSG", "No message of desired type"), |
#endif |
#if defined (EIDRM) |
ENTRY(EIDRM, "EIDRM", "Identifier removed"), |
#endif |
#if defined (ECHRNG) |
ENTRY(ECHRNG, "ECHRNG", "Channel number out of range"), |
#endif |
#if defined (EL2NSYNC) |
ENTRY(EL2NSYNC, "EL2NSYNC", "Level 2 not synchronized"), |
#endif |
#if defined (EL3HLT) |
ENTRY(EL3HLT, "EL3HLT", "Level 3 halted"), |
#endif |
#if defined (EL3RST) |
ENTRY(EL3RST, "EL3RST", "Level 3 reset"), |
#endif |
#if defined (ELNRNG) |
ENTRY(ELNRNG, "ELNRNG", "Link number out of range"), |
#endif |
#if defined (EUNATCH) |
ENTRY(EUNATCH, "EUNATCH", "Protocol driver not attached"), |
#endif |
#if defined (ENOCSI) |
ENTRY(ENOCSI, "ENOCSI", "No CSI structure available"), |
#endif |
#if defined (EL2HLT) |
ENTRY(EL2HLT, "EL2HLT", "Level 2 halted"), |
#endif |
#if defined (EDEADLK) |
ENTRY(EDEADLK, "EDEADLK", "Deadlock condition"), |
#endif |
#if defined (ENOLCK) |
ENTRY(ENOLCK, "ENOLCK", "No record locks available"), |
#endif |
#if defined (EBADE) |
ENTRY(EBADE, "EBADE", "Invalid exchange"), |
#endif |
#if defined (EBADR) |
ENTRY(EBADR, "EBADR", "Invalid request descriptor"), |
#endif |
#if defined (EXFULL) |
ENTRY(EXFULL, "EXFULL", "Exchange full"), |
#endif |
#if defined (ENOANO) |
ENTRY(ENOANO, "ENOANO", "No anode"), |
#endif |
#if defined (EBADRQC) |
ENTRY(EBADRQC, "EBADRQC", "Invalid request code"), |
#endif |
#if defined (EBADSLT) |
ENTRY(EBADSLT, "EBADSLT", "Invalid slot"), |
#endif |
#if defined (EDEADLOCK) |
ENTRY(EDEADLOCK, "EDEADLOCK", "File locking deadlock error"), |
#endif |
#if defined (EBFONT) |
ENTRY(EBFONT, "EBFONT", "Bad font file format"), |
#endif |
#if defined (ENOSTR) |
ENTRY(ENOSTR, "ENOSTR", "Device not a stream"), |
#endif |
#if defined (ENODATA) |
ENTRY(ENODATA, "ENODATA", "No data available"), |
#endif |
#if defined (ETIME) |
ENTRY(ETIME, "ETIME", "Timer expired"), |
#endif |
#if defined (ENOSR) |
ENTRY(ENOSR, "ENOSR", "Out of streams resources"), |
#endif |
#if defined (ENONET) |
ENTRY(ENONET, "ENONET", "Machine is not on the network"), |
#endif |
#if defined (ENOPKG) |
ENTRY(ENOPKG, "ENOPKG", "Package not installed"), |
#endif |
#if defined (EREMOTE) |
ENTRY(EREMOTE, "EREMOTE", "Object is remote"), |
#endif |
#if defined (ENOLINK) |
ENTRY(ENOLINK, "ENOLINK", "Link has been severed"), |
#endif |
#if defined (EADV) |
ENTRY(EADV, "EADV", "Advertise error"), |
#endif |
#if defined (ESRMNT) |
ENTRY(ESRMNT, "ESRMNT", "Srmount error"), |
#endif |
#if defined (ECOMM) |
ENTRY(ECOMM, "ECOMM", "Communication error on send"), |
#endif |
#if defined (EPROTO) |
ENTRY(EPROTO, "EPROTO", "Protocol error"), |
#endif |
#if defined (EMULTIHOP) |
ENTRY(EMULTIHOP, "EMULTIHOP", "Multihop attempted"), |
#endif |
#if defined (EDOTDOT) |
ENTRY(EDOTDOT, "EDOTDOT", "RFS specific error"), |
#endif |
#if defined (EBADMSG) |
ENTRY(EBADMSG, "EBADMSG", "Not a data message"), |
#endif |
#if defined (ENAMETOOLONG) |
ENTRY(ENAMETOOLONG, "ENAMETOOLONG", "File name too long"), |
#endif |
#if defined (EOVERFLOW) |
ENTRY(EOVERFLOW, "EOVERFLOW", "Value too large for defined data type"), |
#endif |
#if defined (ENOTUNIQ) |
ENTRY(ENOTUNIQ, "ENOTUNIQ", "Name not unique on network"), |
#endif |
#if defined (EBADFD) |
ENTRY(EBADFD, "EBADFD", "File descriptor in bad state"), |
#endif |
#if defined (EREMCHG) |
ENTRY(EREMCHG, "EREMCHG", "Remote address changed"), |
#endif |
#if defined (ELIBACC) |
ENTRY(ELIBACC, "ELIBACC", "Can not access a needed shared library"), |
#endif |
#if defined (ELIBBAD) |
ENTRY(ELIBBAD, "ELIBBAD", "Accessing a corrupted shared library"), |
#endif |
#if defined (ELIBSCN) |
ENTRY(ELIBSCN, "ELIBSCN", ".lib section in a.out corrupted"), |
#endif |
#if defined (ELIBMAX) |
ENTRY(ELIBMAX, "ELIBMAX", "Attempting to link in too many shared libraries"), |
#endif |
#if defined (ELIBEXEC) |
ENTRY(ELIBEXEC, "ELIBEXEC", "Cannot exec a shared library directly"), |
#endif |
#if defined (EILSEQ) |
ENTRY(EILSEQ, "EILSEQ", "Illegal byte sequence"), |
#endif |
#if defined (ENOSYS) |
ENTRY(ENOSYS, "ENOSYS", "Operation not applicable"), |
#endif |
#if defined (ELOOP) |
ENTRY(ELOOP, "ELOOP", "Too many symbolic links encountered"), |
#endif |
#if defined (ERESTART) |
ENTRY(ERESTART, "ERESTART", "Interrupted system call should be restarted"), |
#endif |
#if defined (ESTRPIPE) |
ENTRY(ESTRPIPE, "ESTRPIPE", "Streams pipe error"), |
#endif |
#if defined (ENOTEMPTY) |
ENTRY(ENOTEMPTY, "ENOTEMPTY", "Directory not empty"), |
#endif |
#if defined (EUSERS) |
ENTRY(EUSERS, "EUSERS", "Too many users"), |
#endif |
#if defined (ENOTSOCK) |
ENTRY(ENOTSOCK, "ENOTSOCK", "Socket operation on non-socket"), |
#endif |
#if defined (EDESTADDRREQ) |
ENTRY(EDESTADDRREQ, "EDESTADDRREQ", "Destination address required"), |
#endif |
#if defined (EMSGSIZE) |
ENTRY(EMSGSIZE, "EMSGSIZE", "Message too long"), |
#endif |
#if defined (EPROTOTYPE) |
ENTRY(EPROTOTYPE, "EPROTOTYPE", "Protocol wrong type for socket"), |
#endif |
#if defined (ENOPROTOOPT) |
ENTRY(ENOPROTOOPT, "ENOPROTOOPT", "Protocol not available"), |
#endif |
#if defined (EPROTONOSUPPORT) |
ENTRY(EPROTONOSUPPORT, "EPROTONOSUPPORT", "Protocol not supported"), |
#endif |
#if defined (ESOCKTNOSUPPORT) |
ENTRY(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "Socket type not supported"), |
#endif |
#if defined (EOPNOTSUPP) |
ENTRY(EOPNOTSUPP, "EOPNOTSUPP", "Operation not supported on transport endpoint"), |
#endif |
#if defined (EPFNOSUPPORT) |
ENTRY(EPFNOSUPPORT, "EPFNOSUPPORT", "Protocol family not supported"), |
#endif |
#if defined (EAFNOSUPPORT) |
ENTRY(EAFNOSUPPORT, "EAFNOSUPPORT", "Address family not supported by protocol"), |
#endif |
#if defined (EADDRINUSE) |
ENTRY(EADDRINUSE, "EADDRINUSE", "Address already in use"), |
#endif |
#if defined (EADDRNOTAVAIL) |
ENTRY(EADDRNOTAVAIL, "EADDRNOTAVAIL","Cannot assign requested address"), |
#endif |
#if defined (ENETDOWN) |
ENTRY(ENETDOWN, "ENETDOWN", "Network is down"), |
#endif |
#if defined (ENETUNREACH) |
ENTRY(ENETUNREACH, "ENETUNREACH", "Network is unreachable"), |
#endif |
#if defined (ENETRESET) |
ENTRY(ENETRESET, "ENETRESET", "Network dropped connection because of reset"), |
#endif |
#if defined (ECONNABORTED) |
ENTRY(ECONNABORTED, "ECONNABORTED", "Software caused connection abort"), |
#endif |
#if defined (ECONNRESET) |
ENTRY(ECONNRESET, "ECONNRESET", "Connection reset by peer"), |
#endif |
#if defined (ENOBUFS) |
ENTRY(ENOBUFS, "ENOBUFS", "No buffer space available"), |
#endif |
#if defined (EISCONN) |
ENTRY(EISCONN, "EISCONN", "Transport endpoint is already connected"), |
#endif |
#if defined (ENOTCONN) |
ENTRY(ENOTCONN, "ENOTCONN", "Transport endpoint is not connected"), |
#endif |
#if defined (ESHUTDOWN) |
ENTRY(ESHUTDOWN, "ESHUTDOWN", "Cannot send after transport endpoint shutdown"), |
#endif |
#if defined (ETOOMANYREFS) |
ENTRY(ETOOMANYREFS, "ETOOMANYREFS", "Too many references: cannot splice"), |
#endif |
#if defined (ETIMEDOUT) |
ENTRY(ETIMEDOUT, "ETIMEDOUT", "Connection timed out"), |
#endif |
#if defined (ECONNREFUSED) |
ENTRY(ECONNREFUSED, "ECONNREFUSED", "Connection refused"), |
#endif |
#if defined (EHOSTDOWN) |
ENTRY(EHOSTDOWN, "EHOSTDOWN", "Host is down"), |
#endif |
#if defined (EHOSTUNREACH) |
ENTRY(EHOSTUNREACH, "EHOSTUNREACH", "No route to host"), |
#endif |
#if defined (EALREADY) |
ENTRY(EALREADY, "EALREADY", "Operation already in progress"), |
#endif |
#if defined (EINPROGRESS) |
ENTRY(EINPROGRESS, "EINPROGRESS", "Operation now in progress"), |
#endif |
#if defined (ESTALE) |
ENTRY(ESTALE, "ESTALE", "Stale NFS file handle"), |
#endif |
#if defined (EUCLEAN) |
ENTRY(EUCLEAN, "EUCLEAN", "Structure needs cleaning"), |
#endif |
#if defined (ENOTNAM) |
ENTRY(ENOTNAM, "ENOTNAM", "Not a XENIX named type file"), |
#endif |
#if defined (ENAVAIL) |
ENTRY(ENAVAIL, "ENAVAIL", "No XENIX semaphores available"), |
#endif |
#if defined (EISNAM) |
ENTRY(EISNAM, "EISNAM", "Is a named type file"), |
#endif |
#if defined (EREMOTEIO) |
ENTRY(EREMOTEIO, "EREMOTEIO", "Remote I/O error"), |
#endif |
ENTRY(0, NULL, NULL) |
}; |
#ifdef EVMSERR |
/* This is not in the table, because the numeric value of EVMSERR (32767) |
lies outside the range of sys_errlist[]. */ |
static struct { int value; const char *name, *msg; } |
evmserr = { EVMSERR, "EVMSERR", "VMS-specific error" }; |
#endif |
/* Translation table allocated and initialized at runtime. Indexed by the |
errno value to find the equivalent symbolic value. */ |
static const char **error_names; |
static int num_error_names = 0; |
/* Translation table allocated and initialized at runtime, if it does not |
already exist in the host environment. Indexed by the errno value to find |
the descriptive string. |
We don't export it for use in other modules because even though it has the |
same name, it differs from other implementations in that it is dynamically |
initialized rather than statically initialized. */ |
#ifndef HAVE_SYS_ERRLIST |
#define sys_nerr sys_nerr__ |
#define sys_errlist sys_errlist__ |
static int sys_nerr; |
static const char **sys_errlist; |
#else |
extern int sys_nerr; |
extern char *sys_errlist[]; |
#endif |
/* |
NAME |
init_error_tables -- initialize the name and message tables |
SYNOPSIS |
static void init_error_tables (); |
DESCRIPTION |
Using the error_table, which is initialized at compile time, generate |
the error_names and the sys_errlist (if needed) tables, which are |
indexed at runtime by a specific errno value. |
BUGS |
The initialization of the tables may fail under low memory conditions, |
in which case we don't do anything particularly useful, but we don't |
bomb either. Who knows, it might succeed at a later point if we free |
some memory in the meantime. In any case, the other routines know |
how to deal with lack of a table after trying to initialize it. This |
may or may not be considered to be a bug, that we don't specifically |
warn about this particular failure mode. |
*/ |
static void |
init_error_tables (void) |
{ |
const struct error_info *eip; |
int nbytes; |
/* If we haven't already scanned the error_table once to find the maximum |
errno value, then go find it now. */ |
if (num_error_names == 0) |
{ |
for (eip = error_table; eip -> name != NULL; eip++) |
{ |
if (eip -> value >= num_error_names) |
{ |
num_error_names = eip -> value + 1; |
} |
} |
} |
/* Now attempt to allocate the error_names table, zero it out, and then |
initialize it from the statically initialized error_table. */ |
if (error_names == NULL) |
{ |
nbytes = num_error_names * sizeof (char *); |
if ((error_names = (const char **) malloc (nbytes)) != NULL) |
{ |
memset (error_names, 0, nbytes); |
for (eip = error_table; eip -> name != NULL; eip++) |
{ |
error_names[eip -> value] = eip -> name; |
} |
} |
} |
#ifndef HAVE_SYS_ERRLIST |
/* Now attempt to allocate the sys_errlist table, zero it out, and then |
initialize it from the statically initialized error_table. */ |
if (sys_errlist == NULL) |
{ |
nbytes = num_error_names * sizeof (char *); |
if ((sys_errlist = (const char **) malloc (nbytes)) != NULL) |
{ |
memset (sys_errlist, 0, nbytes); |
sys_nerr = num_error_names; |
for (eip = error_table; eip -> name != NULL; eip++) |
{ |
sys_errlist[eip -> value] = eip -> msg; |
} |
} |
} |
#endif |
} |
/* |
@deftypefn Extension int errno_max (void) |
Returns the maximum @code{errno} value for which a corresponding |
symbolic name or message is available. Note that in the case where we |
use the @code{sys_errlist} supplied by the system, it is possible for |
there to be more symbolic names than messages, or vice versa. In |
fact, the manual page for @code{perror(3C)} explicitly warns that one |
should check the size of the table (@code{sys_nerr}) before indexing |
it, since new error codes may be added to the system before they are |
added to the table. Thus @code{sys_nerr} might be smaller than value |
implied by the largest @code{errno} value defined in @code{<errno.h>}. |
We return the maximum value that can be used to obtain a meaningful |
symbolic name or message. |
@end deftypefn |
*/ |
int |
errno_max (void) |
{ |
int maxsize; |
if (error_names == NULL) |
{ |
init_error_tables (); |
} |
maxsize = MAX (sys_nerr, num_error_names); |
return (maxsize - 1); |
} |
#ifndef HAVE_STRERROR |
/* |
@deftypefn Supplemental char* strerror (int @var{errnoval}) |
Maps an @code{errno} number to an error message string, the contents |
of which are implementation defined. On systems which have the |
external variables @code{sys_nerr} and @code{sys_errlist}, these |
strings will be the same as the ones used by @code{perror}. |
If the supplied error number is within the valid range of indices for |
the @code{sys_errlist}, but no message is available for the particular |
error number, then returns the string @samp{Error @var{num}}, where |
@var{num} is the error number. |
If the supplied error number is not a valid index into |
@code{sys_errlist}, returns @code{NULL}. |
The returned string is only guaranteed to be valid only until the |
next call to @code{strerror}. |
@end deftypefn |
*/ |
char * |
strerror (int errnoval) |
{ |
const char *msg; |
static char buf[32]; |
#ifndef HAVE_SYS_ERRLIST |
if (error_names == NULL) |
{ |
init_error_tables (); |
} |
#endif |
if ((errnoval < 0) || (errnoval >= sys_nerr)) |
{ |
#ifdef EVMSERR |
if (errnoval == evmserr.value) |
msg = evmserr.msg; |
else |
#endif |
/* Out of range, just return NULL */ |
msg = NULL; |
} |
else if ((sys_errlist == NULL) || (sys_errlist[errnoval] == NULL)) |
{ |
/* In range, but no sys_errlist or no entry at this index. */ |
sprintf (buf, "Error %d", errnoval); |
msg = buf; |
} |
else |
{ |
/* In range, and a valid message. Just return the message. */ |
msg = (char *) sys_errlist[errnoval]; |
} |
return (msg); |
} |
#endif /* ! HAVE_STRERROR */ |
/* |
@deftypefn Replacement {const char*} strerrno (int @var{errnum}) |
Given an error number returned from a system call (typically returned |
in @code{errno}), returns a pointer to a string containing the |
symbolic name of that error number, as found in @code{<errno.h>}. |
If the supplied error number is within the valid range of indices for |
symbolic names, but no name is available for the particular error |
number, then returns the string @samp{Error @var{num}}, where @var{num} |
is the error number. |
If the supplied error number is not within the range of valid |
indices, then returns @code{NULL}. |
The contents of the location pointed to are only guaranteed to be |
valid until the next call to @code{strerrno}. |
@end deftypefn |
*/ |
const char * |
strerrno (int errnoval) |
{ |
const char *name; |
static char buf[32]; |
if (error_names == NULL) |
{ |
init_error_tables (); |
} |
if ((errnoval < 0) || (errnoval >= num_error_names)) |
{ |
#ifdef EVMSERR |
if (errnoval == evmserr.value) |
name = evmserr.name; |
else |
#endif |
/* Out of range, just return NULL */ |
name = NULL; |
} |
else if ((error_names == NULL) || (error_names[errnoval] == NULL)) |
{ |
/* In range, but no error_names or no entry at this index. */ |
sprintf (buf, "Error %d", errnoval); |
name = (const char *) buf; |
} |
else |
{ |
/* In range, and a valid name. Just return the name. */ |
name = error_names[errnoval]; |
} |
return (name); |
} |
/* |
@deftypefn Extension int strtoerrno (const char *@var{name}) |
Given the symbolic name of a error number (e.g., @code{EACCES}), map it |
to an errno value. If no translation is found, returns 0. |
@end deftypefn |
*/ |
int |
strtoerrno (const char *name) |
{ |
int errnoval = 0; |
if (name != NULL) |
{ |
if (error_names == NULL) |
{ |
init_error_tables (); |
} |
for (errnoval = 0; errnoval < num_error_names; errnoval++) |
{ |
if ((error_names[errnoval] != NULL) && |
(strcmp (name, error_names[errnoval]) == 0)) |
{ |
break; |
} |
} |
if (errnoval == num_error_names) |
{ |
#ifdef EVMSERR |
if (strcmp (name, evmserr.name) == 0) |
errnoval = evmserr.value; |
else |
#endif |
errnoval = 0; |
} |
} |
return (errnoval); |
} |
/* A simple little main that does nothing but print all the errno translations |
if MAIN is defined and this file is compiled and linked. */ |
#ifdef MAIN |
#include <stdio.h> |
int |
main (void) |
{ |
int errn; |
int errnmax; |
const char *name; |
const char *msg; |
char *strerror (); |
errnmax = errno_max (); |
printf ("%d entries in names table.\n", num_error_names); |
printf ("%d entries in messages table.\n", sys_nerr); |
printf ("%d is max useful index.\n", errnmax); |
/* Keep printing values until we get to the end of *both* tables, not |
*either* table. Note that knowing the maximum useful index does *not* |
relieve us of the responsibility of testing the return pointer for |
NULL. */ |
for (errn = 0; errn <= errnmax; errn++) |
{ |
name = strerrno (errn); |
name = (name == NULL) ? "<NULL>" : name; |
msg = strerror (errn); |
msg = (msg == NULL) ? "<NULL>" : msg; |
printf ("%-4d%-18s%s\n", errn, name, msg); |
} |
return 0; |
} |
#endif |
/contrib/toolchain/binutils/libiberty/strncasecmp.c |
---|
0,0 → 1,86 |
/* |
* Copyright (c) 1987 Regents of the University of California. |
* All rights reserved. |
* |
* Redistribution and use in source and binary forms are permitted |
* provided that this notice is preserved and that due credit is given |
* to the University of California at Berkeley. The name of the University |
* may not be used to endorse or promote products derived from this |
* software without specific written prior permission. This software |
* is provided ``as is'' without express or implied warranty. |
*/ |
/* |
@deftypefn Supplemental int strncasecmp (const char *@var{s1}, const char *@var{s2}) |
A case-insensitive @code{strncmp}. |
@end deftypefn |
*/ |
#if defined(LIBC_SCCS) && !defined(lint) |
static char sccsid[] = "@(#)strcasecmp.c 5.5 (Berkeley) 11/24/87"; |
#endif /* LIBC_SCCS and not lint */ |
#include <ansidecl.h> |
#include <stddef.h> |
/* |
* This array is designed for mapping upper and lower case letter |
* together for a case independent comparison. The mappings are |
* based upon ascii character sequences. |
*/ |
static const unsigned char charmap[] = { |
'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', |
'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', |
'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', |
'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', |
'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', |
'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', |
'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', |
'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', |
'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', |
'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', |
'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', |
'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', |
'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', |
'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', |
'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', |
'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', |
'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', |
'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', |
'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', |
'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', |
'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', |
'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', |
'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', |
'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', |
'\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347', |
'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', |
'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', |
'\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337', |
'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', |
'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', |
'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', |
'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', |
}; |
int |
strncasecmp(const char *s1, const char *s2, register size_t n) |
{ |
register unsigned char u1, u2; |
for (; n != 0; --n) { |
u1 = (unsigned char) *s1++; |
u2 = (unsigned char) *s2++; |
if (charmap[u1] != charmap[u2]) { |
return charmap[u1] - charmap[u2]; |
} |
if (u1 == '\0') { |
return 0; |
} |
} |
return 0; |
} |
/contrib/toolchain/binutils/libiberty/strndup.c |
---|
0,0 → 1,55 |
/* Implement the strndup function. |
Copyright (C) 2005 Free Software Foundation, Inc. |
Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Extension char* strndup (const char *@var{s}, size_t @var{n}) |
Returns a pointer to a copy of @var{s} with at most @var{n} characters |
in memory obtained from @code{malloc}, or @code{NULL} if insufficient |
memory was available. The result is always NUL terminated. |
@end deftypefn |
*/ |
#include "ansidecl.h" |
#include <stddef.h> |
extern size_t strlen (const char*); |
extern PTR malloc (size_t); |
extern PTR memcpy (PTR, const PTR, size_t); |
char * |
strndup (const char *s, size_t n) |
{ |
char *result; |
size_t len = strlen (s); |
if (n < len) |
len = n; |
result = (char *) malloc (len + 1); |
if (!result) |
return 0; |
result[len] = '\0'; |
return (char *) memcpy (result, s, len); |
} |
/contrib/toolchain/binutils/libiberty/strnlen.c |
---|
0,0 → 1,30 |
/* Portable version of strnlen. |
This function is in the public domain. */ |
/* |
@deftypefn Supplemental size_t strnlen (const char *@var{s}, size_t @var{maxlen}) |
Returns the length of @var{s}, as with @code{strlen}, but never looks |
past the first @var{maxlen} characters in the string. If there is no |
'\0' character in the first @var{maxlen} characters, returns |
@var{maxlen}. |
@end deftypefn |
*/ |
#include "config.h" |
#include <stddef.h> |
size_t |
strnlen (const char *s, size_t maxlen) |
{ |
size_t i; |
for (i = 0; i < maxlen; ++i) |
if (s[i] == '\0') |
break; |
return i; |
} |
/contrib/toolchain/binutils/libiberty/strsignal.c |
---|
0,0 → 1,610 |
/* Extended support for using signal values. |
Written by Fred Fish. fnf@cygnus.com |
This file is in the public domain. */ |
#include "config.h" |
#include "ansidecl.h" |
#include "libiberty.h" |
/* We need to declare sys_siglist, because even if the system provides |
it we can't assume that it is declared in <signal.h> (for example, |
SunOS provides sys_siglist, but it does not declare it in any |
header file). However, we can't declare sys_siglist portably, |
because on some systems it is declared with const and on some |
systems it is declared without const. If we were using autoconf, |
we could work out the right declaration. Until, then we just |
ignore any declaration in the system header files, and always |
declare it ourselves. With luck, this will always work. */ |
#define sys_siglist no_such_symbol |
#define sys_nsig sys_nsig__no_such_symbol |
#include <stdio.h> |
#include <signal.h> |
/* Routines imported from standard C runtime libraries. */ |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#else |
extern PTR malloc (); |
#endif |
#ifdef HAVE_STRING_H |
#include <string.h> |
#else |
extern PTR memset (); |
#endif |
/* Undefine the macro we used to hide the definition of sys_siglist |
found in the system header files. */ |
#undef sys_siglist |
#undef sys_nsig |
#ifndef NULL |
# define NULL (void *) 0 |
#endif |
#ifndef MAX |
# define MAX(a,b) ((a) > (b) ? (a) : (b)) |
#endif |
static void init_signal_tables (void); |
/* Translation table for signal values. |
Note that this table is generally only accessed when it is used at runtime |
to initialize signal name and message tables that are indexed by signal |
value. |
Not all of these signals will exist on all systems. This table is the only |
thing that should have to be updated as new signal numbers are introduced. |
It's sort of ugly, but at least its portable. */ |
struct signal_info |
{ |
const int value; /* The numeric value from <signal.h> */ |
const char *const name; /* The equivalent symbolic value */ |
#ifndef HAVE_SYS_SIGLIST |
const char *const msg; /* Short message about this value */ |
#endif |
}; |
#ifndef HAVE_SYS_SIGLIST |
# define ENTRY(value, name, msg) {value, name, msg} |
#else |
# define ENTRY(value, name, msg) {value, name} |
#endif |
static const struct signal_info signal_table[] = |
{ |
#if defined (SIGHUP) |
ENTRY(SIGHUP, "SIGHUP", "Hangup"), |
#endif |
#if defined (SIGINT) |
ENTRY(SIGINT, "SIGINT", "Interrupt"), |
#endif |
#if defined (SIGQUIT) |
ENTRY(SIGQUIT, "SIGQUIT", "Quit"), |
#endif |
#if defined (SIGILL) |
ENTRY(SIGILL, "SIGILL", "Illegal instruction"), |
#endif |
#if defined (SIGTRAP) |
ENTRY(SIGTRAP, "SIGTRAP", "Trace/breakpoint trap"), |
#endif |
/* Put SIGIOT before SIGABRT, so that if SIGIOT==SIGABRT then SIGABRT |
overrides SIGIOT. SIGABRT is in ANSI and POSIX.1, and SIGIOT isn't. */ |
#if defined (SIGIOT) |
ENTRY(SIGIOT, "SIGIOT", "IOT trap"), |
#endif |
#if defined (SIGABRT) |
ENTRY(SIGABRT, "SIGABRT", "Aborted"), |
#endif |
#if defined (SIGEMT) |
ENTRY(SIGEMT, "SIGEMT", "Emulation trap"), |
#endif |
#if defined (SIGFPE) |
ENTRY(SIGFPE, "SIGFPE", "Arithmetic exception"), |
#endif |
#if defined (SIGKILL) |
ENTRY(SIGKILL, "SIGKILL", "Killed"), |
#endif |
#if defined (SIGBUS) |
ENTRY(SIGBUS, "SIGBUS", "Bus error"), |
#endif |
#if defined (SIGSEGV) |
ENTRY(SIGSEGV, "SIGSEGV", "Segmentation fault"), |
#endif |
#if defined (SIGSYS) |
ENTRY(SIGSYS, "SIGSYS", "Bad system call"), |
#endif |
#if defined (SIGPIPE) |
ENTRY(SIGPIPE, "SIGPIPE", "Broken pipe"), |
#endif |
#if defined (SIGALRM) |
ENTRY(SIGALRM, "SIGALRM", "Alarm clock"), |
#endif |
#if defined (SIGTERM) |
ENTRY(SIGTERM, "SIGTERM", "Terminated"), |
#endif |
#if defined (SIGUSR1) |
ENTRY(SIGUSR1, "SIGUSR1", "User defined signal 1"), |
#endif |
#if defined (SIGUSR2) |
ENTRY(SIGUSR2, "SIGUSR2", "User defined signal 2"), |
#endif |
/* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD |
overrides SIGCLD. SIGCHLD is in POXIX.1 */ |
#if defined (SIGCLD) |
ENTRY(SIGCLD, "SIGCLD", "Child status changed"), |
#endif |
#if defined (SIGCHLD) |
ENTRY(SIGCHLD, "SIGCHLD", "Child status changed"), |
#endif |
#if defined (SIGPWR) |
ENTRY(SIGPWR, "SIGPWR", "Power fail/restart"), |
#endif |
#if defined (SIGWINCH) |
ENTRY(SIGWINCH, "SIGWINCH", "Window size changed"), |
#endif |
#if defined (SIGURG) |
ENTRY(SIGURG, "SIGURG", "Urgent I/O condition"), |
#endif |
#if defined (SIGIO) |
/* "I/O pending" has also been suggested, but is misleading since the |
signal only happens when the process has asked for it, not everytime |
I/O is pending. */ |
ENTRY(SIGIO, "SIGIO", "I/O possible"), |
#endif |
#if defined (SIGPOLL) |
ENTRY(SIGPOLL, "SIGPOLL", "Pollable event occurred"), |
#endif |
#if defined (SIGSTOP) |
ENTRY(SIGSTOP, "SIGSTOP", "Stopped (signal)"), |
#endif |
#if defined (SIGTSTP) |
ENTRY(SIGTSTP, "SIGTSTP", "Stopped (user)"), |
#endif |
#if defined (SIGCONT) |
ENTRY(SIGCONT, "SIGCONT", "Continued"), |
#endif |
#if defined (SIGTTIN) |
ENTRY(SIGTTIN, "SIGTTIN", "Stopped (tty input)"), |
#endif |
#if defined (SIGTTOU) |
ENTRY(SIGTTOU, "SIGTTOU", "Stopped (tty output)"), |
#endif |
#if defined (SIGVTALRM) |
ENTRY(SIGVTALRM, "SIGVTALRM", "Virtual timer expired"), |
#endif |
#if defined (SIGPROF) |
ENTRY(SIGPROF, "SIGPROF", "Profiling timer expired"), |
#endif |
#if defined (SIGXCPU) |
ENTRY(SIGXCPU, "SIGXCPU", "CPU time limit exceeded"), |
#endif |
#if defined (SIGXFSZ) |
ENTRY(SIGXFSZ, "SIGXFSZ", "File size limit exceeded"), |
#endif |
#if defined (SIGWIND) |
ENTRY(SIGWIND, "SIGWIND", "SIGWIND"), |
#endif |
#if defined (SIGPHONE) |
ENTRY(SIGPHONE, "SIGPHONE", "SIGPHONE"), |
#endif |
#if defined (SIGLOST) |
ENTRY(SIGLOST, "SIGLOST", "Resource lost"), |
#endif |
#if defined (SIGWAITING) |
ENTRY(SIGWAITING, "SIGWAITING", "Process's LWPs are blocked"), |
#endif |
#if defined (SIGLWP) |
ENTRY(SIGLWP, "SIGLWP", "Signal LWP"), |
#endif |
#if defined (SIGDANGER) |
ENTRY(SIGDANGER, "SIGDANGER", "Swap space dangerously low"), |
#endif |
#if defined (SIGGRANT) |
ENTRY(SIGGRANT, "SIGGRANT", "Monitor mode granted"), |
#endif |
#if defined (SIGRETRACT) |
ENTRY(SIGRETRACT, "SIGRETRACT", "Need to relinguish monitor mode"), |
#endif |
#if defined (SIGMSG) |
ENTRY(SIGMSG, "SIGMSG", "Monitor mode data available"), |
#endif |
#if defined (SIGSOUND) |
ENTRY(SIGSOUND, "SIGSOUND", "Sound completed"), |
#endif |
#if defined (SIGSAK) |
ENTRY(SIGSAK, "SIGSAK", "Secure attention"), |
#endif |
ENTRY(0, NULL, NULL) |
}; |
/* Translation table allocated and initialized at runtime. Indexed by the |
signal value to find the equivalent symbolic value. */ |
static const char **signal_names; |
static int num_signal_names = 0; |
/* Translation table allocated and initialized at runtime, if it does not |
already exist in the host environment. Indexed by the signal value to find |
the descriptive string. |
We don't export it for use in other modules because even though it has the |
same name, it differs from other implementations in that it is dynamically |
initialized rather than statically initialized. */ |
#ifndef HAVE_SYS_SIGLIST |
static int sys_nsig; |
static const char **sys_siglist; |
#else |
#ifdef NSIG |
static int sys_nsig = NSIG; |
#else |
#ifdef _NSIG |
static int sys_nsig = _NSIG; |
#endif |
#endif |
extern const char * const sys_siglist[]; |
#endif |
/* |
NAME |
init_signal_tables -- initialize the name and message tables |
SYNOPSIS |
static void init_signal_tables (); |
DESCRIPTION |
Using the signal_table, which is initialized at compile time, generate |
the signal_names and the sys_siglist (if needed) tables, which are |
indexed at runtime by a specific signal value. |
BUGS |
The initialization of the tables may fail under low memory conditions, |
in which case we don't do anything particularly useful, but we don't |
bomb either. Who knows, it might succeed at a later point if we free |
some memory in the meantime. In any case, the other routines know |
how to deal with lack of a table after trying to initialize it. This |
may or may not be considered to be a bug, that we don't specifically |
warn about this particular failure mode. |
*/ |
static void |
init_signal_tables (void) |
{ |
const struct signal_info *eip; |
int nbytes; |
/* If we haven't already scanned the signal_table once to find the maximum |
signal value, then go find it now. */ |
if (num_signal_names == 0) |
{ |
for (eip = signal_table; eip -> name != NULL; eip++) |
{ |
if (eip -> value >= num_signal_names) |
{ |
num_signal_names = eip -> value + 1; |
} |
} |
} |
/* Now attempt to allocate the signal_names table, zero it out, and then |
initialize it from the statically initialized signal_table. */ |
if (signal_names == NULL) |
{ |
nbytes = num_signal_names * sizeof (char *); |
if ((signal_names = (const char **) malloc (nbytes)) != NULL) |
{ |
memset (signal_names, 0, nbytes); |
for (eip = signal_table; eip -> name != NULL; eip++) |
{ |
signal_names[eip -> value] = eip -> name; |
} |
} |
} |
#ifndef HAVE_SYS_SIGLIST |
/* Now attempt to allocate the sys_siglist table, zero it out, and then |
initialize it from the statically initialized signal_table. */ |
if (sys_siglist == NULL) |
{ |
nbytes = num_signal_names * sizeof (char *); |
if ((sys_siglist = (const char **) malloc (nbytes)) != NULL) |
{ |
memset (sys_siglist, 0, nbytes); |
sys_nsig = num_signal_names; |
for (eip = signal_table; eip -> name != NULL; eip++) |
{ |
sys_siglist[eip -> value] = eip -> msg; |
} |
} |
} |
#endif |
} |
/* |
@deftypefn Extension int signo_max (void) |
Returns the maximum signal value for which a corresponding symbolic |
name or message is available. Note that in the case where we use the |
@code{sys_siglist} supplied by the system, it is possible for there to |
be more symbolic names than messages, or vice versa. In fact, the |
manual page for @code{psignal(3b)} explicitly warns that one should |
check the size of the table (@code{NSIG}) before indexing it, since |
new signal codes may be added to the system before they are added to |
the table. Thus @code{NSIG} might be smaller than value implied by |
the largest signo value defined in @code{<signal.h>}. |
We return the maximum value that can be used to obtain a meaningful |
symbolic name or message. |
@end deftypefn |
*/ |
int |
signo_max (void) |
{ |
int maxsize; |
if (signal_names == NULL) |
{ |
init_signal_tables (); |
} |
maxsize = MAX (sys_nsig, num_signal_names); |
return (maxsize - 1); |
} |
/* |
@deftypefn Supplemental {const char *} strsignal (int @var{signo}) |
Maps an signal number to an signal message string, the contents of |
which are implementation defined. On systems which have the external |
variable @code{sys_siglist}, these strings will be the same as the |
ones used by @code{psignal()}. |
If the supplied signal number is within the valid range of indices for |
the @code{sys_siglist}, but no message is available for the particular |
signal number, then returns the string @samp{Signal @var{num}}, where |
@var{num} is the signal number. |
If the supplied signal number is not a valid index into |
@code{sys_siglist}, returns @code{NULL}. |
The returned string is only guaranteed to be valid only until the next |
call to @code{strsignal}. |
@end deftypefn |
*/ |
#ifndef HAVE_STRSIGNAL |
char * |
strsignal (int signo) |
{ |
char *msg; |
static char buf[32]; |
#ifndef HAVE_SYS_SIGLIST |
if (signal_names == NULL) |
{ |
init_signal_tables (); |
} |
#endif |
if ((signo < 0) || (signo >= sys_nsig)) |
{ |
/* Out of range, just return NULL */ |
msg = NULL; |
} |
else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL)) |
{ |
/* In range, but no sys_siglist or no entry at this index. */ |
sprintf (buf, "Signal %d", signo); |
msg = buf; |
} |
else |
{ |
/* In range, and a valid message. Just return the message. We |
can safely cast away const, since POSIX says the user must |
not modify the result. */ |
msg = (char *) sys_siglist[signo]; |
} |
return (msg); |
} |
#endif /* ! HAVE_STRSIGNAL */ |
/* |
@deftypefn Extension {const char*} strsigno (int @var{signo}) |
Given an signal number, returns a pointer to a string containing the |
symbolic name of that signal number, as found in @code{<signal.h>}. |
If the supplied signal number is within the valid range of indices for |
symbolic names, but no name is available for the particular signal |
number, then returns the string @samp{Signal @var{num}}, where |
@var{num} is the signal number. |
If the supplied signal number is not within the range of valid |
indices, then returns @code{NULL}. |
The contents of the location pointed to are only guaranteed to be |
valid until the next call to @code{strsigno}. |
@end deftypefn |
*/ |
const char * |
strsigno (int signo) |
{ |
const char *name; |
static char buf[32]; |
if (signal_names == NULL) |
{ |
init_signal_tables (); |
} |
if ((signo < 0) || (signo >= num_signal_names)) |
{ |
/* Out of range, just return NULL */ |
name = NULL; |
} |
else if ((signal_names == NULL) || (signal_names[signo] == NULL)) |
{ |
/* In range, but no signal_names or no entry at this index. */ |
sprintf (buf, "Signal %d", signo); |
name = (const char *) buf; |
} |
else |
{ |
/* In range, and a valid name. Just return the name. */ |
name = signal_names[signo]; |
} |
return (name); |
} |
/* |
@deftypefn Extension int strtosigno (const char *@var{name}) |
Given the symbolic name of a signal, map it to a signal number. If no |
translation is found, returns 0. |
@end deftypefn |
*/ |
int |
strtosigno (const char *name) |
{ |
int signo = 0; |
if (name != NULL) |
{ |
if (signal_names == NULL) |
{ |
init_signal_tables (); |
} |
for (signo = 0; signo < num_signal_names; signo++) |
{ |
if ((signal_names[signo] != NULL) && |
(strcmp (name, signal_names[signo]) == 0)) |
{ |
break; |
} |
} |
if (signo == num_signal_names) |
{ |
signo = 0; |
} |
} |
return (signo); |
} |
/* |
@deftypefn Supplemental void psignal (int @var{signo}, char *@var{message}) |
Print @var{message} to the standard error, followed by a colon, |
followed by the description of the signal specified by @var{signo}, |
followed by a newline. |
@end deftypefn |
*/ |
#ifndef HAVE_PSIGNAL |
void |
psignal (int signo, char *message) |
{ |
if (signal_names == NULL) |
{ |
init_signal_tables (); |
} |
if ((signo <= 0) || (signo >= sys_nsig)) |
{ |
fprintf (stderr, "%s: unknown signal\n", message); |
} |
else |
{ |
fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]); |
} |
} |
#endif /* ! HAVE_PSIGNAL */ |
/* A simple little main that does nothing but print all the signal translations |
if MAIN is defined and this file is compiled and linked. */ |
#ifdef MAIN |
#include <stdio.h> |
int |
main (void) |
{ |
int signo; |
int maxsigno; |
const char *name; |
const char *msg; |
maxsigno = signo_max (); |
printf ("%d entries in names table.\n", num_signal_names); |
printf ("%d entries in messages table.\n", sys_nsig); |
printf ("%d is max useful index.\n", maxsigno); |
/* Keep printing values until we get to the end of *both* tables, not |
*either* table. Note that knowing the maximum useful index does *not* |
relieve us of the responsibility of testing the return pointer for |
NULL. */ |
for (signo = 0; signo <= maxsigno; signo++) |
{ |
name = strsigno (signo); |
name = (name == NULL) ? "<NULL>" : name; |
msg = strsignal (signo); |
msg = (msg == NULL) ? "<NULL>" : msg; |
printf ("%-4d%-18s%s\n", signo, name, msg); |
} |
return 0; |
} |
#endif |
/contrib/toolchain/binutils/libiberty/strverscmp.c |
---|
0,0 → 1,157 |
/* Compare strings while treating digits characters numerically. |
Copyright (C) 1997, 2002, 2005 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Contributed by Jean-François Bignolles <bignolle@ecoledoc.ibp.fr>, 1997. |
Libiberty is free software; you can redistribute it and/or |
modify it under the terms of the GNU Lesser General Public |
License as published by the Free Software Foundation; either |
version 2.1 of the License, or (at your option) any later version. |
Libiberty 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 |
Lesser General Public License for more details. |
You should have received a copy of the GNU Lesser General Public |
License along with the GNU C Library; if not, write to the Free |
Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
02110-1301 USA. */ |
#include "libiberty.h" |
#include "safe-ctype.h" |
/* |
@deftypefun int strverscmp (const char *@var{s1}, const char *@var{s2}) |
The @code{strverscmp} function compares the string @var{s1} against |
@var{s2}, considering them as holding indices/version numbers. Return |
value follows the same conventions as found in the @code{strverscmp} |
function. In fact, if @var{s1} and @var{s2} contain no digits, |
@code{strverscmp} behaves like @code{strcmp}. |
Basically, we compare strings normally (character by character), until |
we find a digit in each string - then we enter a special comparison |
mode, where each sequence of digits is taken as a whole. If we reach the |
end of these two parts without noticing a difference, we return to the |
standard comparison mode. There are two types of numeric parts: |
"integral" and "fractional" (those begin with a '0'). The types |
of the numeric parts affect the way we sort them: |
@itemize @bullet |
@item |
integral/integral: we compare values as you would expect. |
@item |
fractional/integral: the fractional part is less than the integral one. |
Again, no surprise. |
@item |
fractional/fractional: the things become a bit more complex. |
If the common prefix contains only leading zeroes, the longest part is less |
than the other one; else the comparison behaves normally. |
@end itemize |
@smallexample |
strverscmp ("no digit", "no digit") |
@result{} 0 // @r{same behavior as strcmp.} |
strverscmp ("item#99", "item#100") |
@result{} <0 // @r{same prefix, but 99 < 100.} |
strverscmp ("alpha1", "alpha001") |
@result{} >0 // @r{fractional part inferior to integral one.} |
strverscmp ("part1_f012", "part1_f01") |
@result{} >0 // @r{two fractional parts.} |
strverscmp ("foo.009", "foo.0") |
@result{} <0 // @r{idem, but with leading zeroes only.} |
@end smallexample |
This function is especially useful when dealing with filename sorting, |
because filenames frequently hold indices/version numbers. |
@end deftypefun |
*/ |
/* states: S_N: normal, S_I: comparing integral part, S_F: comparing |
fractional parts, S_Z: idem but with leading Zeroes only */ |
#define S_N 0x0 |
#define S_I 0x4 |
#define S_F 0x8 |
#define S_Z 0xC |
/* result_type: CMP: return diff; LEN: compare using len_diff/diff */ |
#define CMP 2 |
#define LEN 3 |
/* Compare S1 and S2 as strings holding indices/version numbers, |
returning less than, equal to or greater than zero if S1 is less than, |
equal to or greater than S2 (for more info, see the Glibc texinfo doc). */ |
int |
strverscmp (const char *s1, const char *s2) |
{ |
const unsigned char *p1 = (const unsigned char *) s1; |
const unsigned char *p2 = (const unsigned char *) s2; |
unsigned char c1, c2; |
int state; |
int diff; |
/* Symbol(s) 0 [1-9] others (padding) |
Transition (10) 0 (01) d (00) x (11) - */ |
static const unsigned int next_state[] = |
{ |
/* state x d 0 - */ |
/* S_N */ S_N, S_I, S_Z, S_N, |
/* S_I */ S_N, S_I, S_I, S_I, |
/* S_F */ S_N, S_F, S_F, S_F, |
/* S_Z */ S_N, S_F, S_Z, S_Z |
}; |
static const int result_type[] = |
{ |
/* state x/x x/d x/0 x/- d/x d/d d/0 d/- |
0/x 0/d 0/0 0/- -/x -/d -/0 -/- */ |
/* S_N */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, |
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, |
/* S_I */ CMP, -1, -1, CMP, +1, LEN, LEN, CMP, |
+1, LEN, LEN, CMP, CMP, CMP, CMP, CMP, |
/* S_F */ CMP, CMP, CMP, CMP, CMP, LEN, CMP, CMP, |
CMP, CMP, CMP, CMP, CMP, CMP, CMP, CMP, |
/* S_Z */ CMP, +1, +1, CMP, -1, CMP, CMP, CMP, |
-1, CMP, CMP, CMP |
}; |
if (p1 == p2) |
return 0; |
c1 = *p1++; |
c2 = *p2++; |
/* Hint: '0' is a digit too. */ |
state = S_N | ((c1 == '0') + (ISDIGIT (c1) != 0)); |
while ((diff = c1 - c2) == 0 && c1 != '\0') |
{ |
state = next_state[state]; |
c1 = *p1++; |
c2 = *p2++; |
state |= (c1 == '0') + (ISDIGIT (c1) != 0); |
} |
state = result_type[state << 2 | (((c2 == '0') + (ISDIGIT (c2) != 0)))]; |
switch (state) |
{ |
case CMP: |
return diff; |
case LEN: |
while (ISDIGIT (*p1++)) |
if (!ISDIGIT (*p2++)) |
return 1; |
return ISDIGIT (*p2) ? -1 : diff; |
default: |
return state; |
} |
} |
/contrib/toolchain/binutils/libiberty/timeval-utils.c |
---|
0,0 → 1,87 |
/* Basic struct timeval utilities. |
Copyright (C) 2011 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If not, |
write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#include "config.h" |
/* On some systems (such as WindISS), you must include <sys/types.h> |
to get the definition of "time_t" before you include <time.h>. */ |
#include <sys/types.h> |
#ifdef TIME_WITH_SYS_TIME |
# include <sys/time.h> |
# include <time.h> |
#else |
# if HAVE_SYS_TIME_H |
# include <sys/time.h> |
# else |
# ifdef HAVE_TIME_H |
# include <time.h> |
# endif |
# endif |
#endif |
#include "timeval-utils.h" |
/* |
@deftypefn Extension void timeval_add (struct timeval *@var{a}, @ |
struct timeval *@var{b}, struct timeval *@var{result}) |
Adds @var{a} to @var{b} and stores the result in @var{result}. |
@end deftypefn |
*/ |
void |
timeval_add (struct timeval *result, |
const struct timeval *a, const struct timeval *b) |
{ |
result->tv_sec = a->tv_sec + b->tv_sec; |
result->tv_usec = a->tv_usec + b->tv_usec; |
if (result->tv_usec >= 1000000) |
{ |
++result->tv_sec; |
result->tv_usec -= 1000000; |
} |
} |
/* |
@deftypefn Extension void timeval_sub (struct timeval *@var{a}, @ |
struct timeval *@var{b}, struct timeval *@var{result}) |
Subtracts @var{b} from @var{a} and stores the result in @var{result}. |
@end deftypefn |
*/ |
void |
timeval_sub (struct timeval *result, |
const struct timeval *a, const struct timeval *b) |
{ |
result->tv_sec = a->tv_sec - b->tv_sec; |
result->tv_usec = a->tv_usec - b->tv_usec; |
if (result->tv_usec < 0) |
{ |
--result->tv_sec; |
result->tv_usec += 1000000; |
} |
} |
/contrib/toolchain/binutils/libiberty/unlink-if-ordinary.c |
---|
0,0 → 1,72 |
/* unlink-if-ordinary.c - remove link to a file unless it is special |
Copyright (C) 2004, 2005 Free Software Foundation, Inc. |
This file is part of the libiberty library. This 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. |
This 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. |
You should have received a copy of the GNU General Public License |
along with GNU CC; see the file COPYING. If not, write to |
the Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. |
As a special exception, if you link this library with files |
compiled with a GNU compiler to produce an executable, this does not cause |
the resulting executable to be covered by the GNU General Public License. |
This exception does not however invalidate any other reasons why |
the executable file might be covered by the GNU General Public License. */ |
/* |
@deftypefn Supplemental int unlink_if_ordinary (const char*) |
Unlinks the named file, unless it is special (e.g. a device file). |
Returns 0 when the file was unlinked, a negative value (and errno set) when |
there was an error deleting the file, and a positive value if no attempt |
was made to unlink the file because it is special. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <sys/types.h> |
#ifdef HAVE_UNISTD_H |
#include <unistd.h> |
#endif |
#if HAVE_SYS_STAT_H |
#include <sys/stat.h> |
#endif |
#include "libiberty.h" |
#ifndef S_ISLNK |
#ifdef S_IFLNK |
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) |
#else |
#define S_ISLNK(m) 0 |
#define lstat stat |
#endif |
#endif |
int |
unlink_if_ordinary (const char *name) |
{ |
struct stat st; |
if (lstat (name, &st) == 0 |
&& (S_ISREG (st.st_mode) || S_ISLNK (st.st_mode))) |
return unlink (name); |
return 1; |
} |
/contrib/toolchain/binutils/libiberty/vasprintf.c |
---|
0,0 → 1,197 |
/* Like vsprintf but provides a pointer to malloc'd storage, which must |
be freed by the caller. |
Copyright (C) 1994, 2003, 2011 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <ansidecl.h> |
#include <stdarg.h> |
#if !defined (va_copy) && defined (__va_copy) |
# define va_copy(d,s) __va_copy((d),(s)) |
#endif |
#include <stdio.h> |
#ifdef HAVE_STRING_H |
#include <string.h> |
#endif |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#else |
extern unsigned long strtoul (); |
extern PTR malloc (); |
#endif |
#include "libiberty.h" |
#ifdef TEST |
int global_total_width; |
#endif |
/* |
@deftypefn Extension int vasprintf (char **@var{resptr}, @ |
const char *@var{format}, va_list @var{args}) |
Like @code{vsprintf}, but instead of passing a pointer to a buffer, |
you pass a pointer to a pointer. This function will compute the size |
of the buffer needed, allocate memory with @code{malloc}, and store a |
pointer to the allocated memory in @code{*@var{resptr}}. The value |
returned is the same as @code{vsprintf} would return. If memory could |
not be allocated, minus one is returned and @code{NULL} is stored in |
@code{*@var{resptr}}. |
@end deftypefn |
*/ |
static int int_vasprintf (char **, const char *, va_list); |
static int |
int_vasprintf (char **result, const char *format, va_list args) |
{ |
const char *p = format; |
/* Add one to make sure that it is never zero, which might cause malloc |
to return NULL. */ |
int total_width = strlen (format) + 1; |
va_list ap; |
#ifdef va_copy |
va_copy (ap, args); |
#else |
memcpy ((PTR) &ap, (PTR) &args, sizeof (va_list)); |
#endif |
while (*p != '\0') |
{ |
if (*p++ == '%') |
{ |
while (strchr ("-+ #0", *p)) |
++p; |
if (*p == '*') |
{ |
++p; |
total_width += abs (va_arg (ap, int)); |
} |
else |
total_width += strtoul (p, (char **) &p, 10); |
if (*p == '.') |
{ |
++p; |
if (*p == '*') |
{ |
++p; |
total_width += abs (va_arg (ap, int)); |
} |
else |
total_width += strtoul (p, (char **) &p, 10); |
} |
while (strchr ("hlL", *p)) |
++p; |
/* Should be big enough for any format specifier except %s and floats. */ |
total_width += 30; |
switch (*p) |
{ |
case 'd': |
case 'i': |
case 'o': |
case 'u': |
case 'x': |
case 'X': |
case 'c': |
(void) va_arg (ap, int); |
break; |
case 'f': |
case 'e': |
case 'E': |
case 'g': |
case 'G': |
(void) va_arg (ap, double); |
/* Since an ieee double can have an exponent of 307, we'll |
make the buffer wide enough to cover the gross case. */ |
total_width += 307; |
break; |
case 's': |
total_width += strlen (va_arg (ap, char *)); |
break; |
case 'p': |
case 'n': |
(void) va_arg (ap, char *); |
break; |
} |
p++; |
} |
} |
#ifdef va_copy |
va_end (ap); |
#endif |
#ifdef TEST |
global_total_width = total_width; |
#endif |
*result = (char *) malloc (total_width); |
if (*result != NULL) |
return vsprintf (*result, format, args); |
else |
return -1; |
} |
int |
vasprintf (char **result, const char *format, |
#if defined (_BSD_VA_LIST_) && defined (__FreeBSD__) |
_BSD_VA_LIST_ args) |
#else |
va_list args) |
#endif |
{ |
return int_vasprintf (result, format, args); |
} |
#ifdef TEST |
static void ATTRIBUTE_PRINTF_1 |
checkit (const char *format, ...) |
{ |
char *result; |
VA_OPEN (args, format); |
VA_FIXEDARG (args, const char *, format); |
vasprintf (&result, format, args); |
VA_CLOSE (args); |
if (strlen (result) < (size_t) global_total_width) |
printf ("PASS: "); |
else |
printf ("FAIL: "); |
printf ("%d %s\n", global_total_width, result); |
free (result); |
} |
extern int main (void); |
int |
main (void) |
{ |
checkit ("%d", 0x12345678); |
checkit ("%200d", 5); |
checkit ("%.300d", 6); |
checkit ("%100.150d", 7); |
checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\ |
777777777777777777333333333333366666666666622222222222777777777777733333"); |
checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx"); |
return 0; |
} |
#endif /* TEST */ |
/contrib/toolchain/binutils/libiberty/xatexit.c |
---|
0,0 → 1,99 |
/* |
* Copyright (c) 1990 Regents of the University of California. |
* All rights reserved. |
* |
* %sccs.include.redist.c% |
*/ |
/* |
@deftypefun int xatexit (void (*@var{fn}) (void)) |
Behaves as the standard @code{atexit} function, but with no limit on |
the number of registered functions. Returns 0 on success, or @minus{}1 on |
failure. If you use @code{xatexit} to register functions, you must use |
@code{xexit} to terminate your program. |
@end deftypefun |
*/ |
/* Adapted from newlib/libc/stdlib/{,at}exit.[ch]. |
If you use xatexit, you must call xexit instead of exit. */ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#include <stdio.h> |
#include <stddef.h> |
#if VMS |
#include <stdlib.h> |
#include <unixlib.h> |
#else |
/* For systems with larger pointers than ints, this must be declared. */ |
PTR malloc (size_t); |
#endif |
static void xatexit_cleanup (void); |
/* Pointer to function run by xexit. */ |
extern void (*_xexit_cleanup) (void); |
#define XATEXIT_SIZE 32 |
struct xatexit { |
struct xatexit *next; /* next in list */ |
int ind; /* next index in this table */ |
void (*fns[XATEXIT_SIZE]) (void); /* the table itself */ |
}; |
/* Allocate one struct statically to guarantee that we can register |
at least a few handlers. */ |
static struct xatexit xatexit_first; |
/* Points to head of LIFO stack. */ |
static struct xatexit *xatexit_head = &xatexit_first; |
/* Register function FN to be run by xexit. |
Return 0 if successful, -1 if not. */ |
int |
xatexit (void (*fn) (void)) |
{ |
register struct xatexit *p; |
/* Tell xexit to call xatexit_cleanup. */ |
if (!_xexit_cleanup) |
_xexit_cleanup = xatexit_cleanup; |
p = xatexit_head; |
if (p->ind >= XATEXIT_SIZE) |
{ |
if ((p = (struct xatexit *) malloc (sizeof *p)) == NULL) |
return -1; |
p->ind = 0; |
p->next = xatexit_head; |
xatexit_head = p; |
} |
p->fns[p->ind++] = fn; |
return 0; |
} |
/* Call any cleanup functions. */ |
static void |
xatexit_cleanup (void) |
{ |
register struct xatexit *p; |
register int n; |
for (p = xatexit_head; p; p = p->next) |
for (n = p->ind; --n >= 0;) |
(*p->fns[n]) (); |
} |
/contrib/toolchain/binutils/libiberty/xexit.c |
---|
0,0 → 1,52 |
/* xexit.c -- Run any exit handlers, then exit. |
Copyright (C) 1994, 95, 1997 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If not, write |
to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Replacement void xexit (int @var{code}) |
Terminates the program. If any functions have been registered with |
the @code{xatexit} replacement function, they will be called first. |
Termination is handled via the system's normal @code{exit} call. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <stdio.h> |
#ifdef HAVE_STDLIB_H |
#include <stdlib.h> |
#endif |
#include "libiberty.h" |
/* This variable is set by xatexit if it is called. This way, xmalloc |
doesn't drag xatexit into the link. */ |
void (*_xexit_cleanup) (void); |
void |
xexit (int code) |
{ |
if (_xexit_cleanup != NULL) |
(*_xexit_cleanup) (); |
exit (code); |
} |
/contrib/toolchain/binutils/libiberty/xmalloc.c |
---|
0,0 → 1,184 |
/* memory allocation routines with error checking. |
Copyright 1989, 90, 91, 92, 93, 94 Free Software Foundation, Inc. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Replacement void* xmalloc (size_t) |
Allocate memory without fail. If @code{malloc} fails, this will print |
a message to @code{stderr} (using the name set by |
@code{xmalloc_set_program_name}, |
if any) and then call @code{xexit}. Note that it is therefore safe for |
a program to contain @code{#define malloc xmalloc} in its source. |
@end deftypefn |
@deftypefn Replacement void* xrealloc (void *@var{ptr}, size_t @var{size}) |
Reallocate memory without fail. This routine functions like @code{realloc}, |
but will behave the same as @code{xmalloc} if memory cannot be found. |
@end deftypefn |
@deftypefn Replacement void* xcalloc (size_t @var{nelem}, size_t @var{elsize}) |
Allocate memory without fail, and set it to zero. This routine functions |
like @code{calloc}, but will behave the same as @code{xmalloc} if memory |
cannot be found. |
@end deftypefn |
@deftypefn Replacement void xmalloc_set_program_name (const char *@var{name}) |
You can use this to set the name of the program used by |
@code{xmalloc_failed} when printing a failure message. |
@end deftypefn |
@deftypefn Replacement void xmalloc_failed (size_t) |
This function is not meant to be called by client code, and is listed |
here for completeness only. If any of the allocation routines fail, this |
function will be called to print an error message and terminate execution. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#include <stdio.h> |
#include <stddef.h> |
#if VMS |
#include <stdlib.h> |
#include <unixlib.h> |
#else |
/* For systems with larger pointers than ints, these must be declared. */ |
# if HAVE_STDLIB_H && HAVE_UNISTD_H && HAVE_DECL_MALLOC \ |
&& HAVE_DECL_REALLOC && HAVE_DECL_CALLOC && HAVE_DECL_SBRK |
# include <stdlib.h> |
# include <unistd.h> |
# else |
# ifdef __cplusplus |
extern "C" { |
# endif /* __cplusplus */ |
void *malloc (size_t); |
void *realloc (void *, size_t); |
void *calloc (size_t, size_t); |
void *sbrk (ptrdiff_t); |
# ifdef __cplusplus |
} |
# endif /* __cplusplus */ |
# endif /* HAVE_STDLIB_H ... */ |
#endif /* VMS */ |
/* The program name if set. */ |
static const char *name = ""; |
#ifdef HAVE_SBRK |
/* The initial sbrk, set when the program name is set. Not used for win32 |
ports other than cygwin32. */ |
static char *first_break = NULL; |
#endif /* HAVE_SBRK */ |
void |
xmalloc_set_program_name (const char *s) |
{ |
name = s; |
#ifdef HAVE_SBRK |
/* Win32 ports other than cygwin32 don't have brk() */ |
if (first_break == NULL) |
first_break = (char *) sbrk (0); |
#endif /* HAVE_SBRK */ |
} |
void |
xmalloc_failed (size_t size) |
{ |
#ifdef HAVE_SBRK |
extern char **environ; |
size_t allocated; |
if (first_break != NULL) |
allocated = (char *) sbrk (0) - first_break; |
else |
allocated = (char *) sbrk (0) - (char *) &environ; |
fprintf (stderr, |
"\n%s%sout of memory allocating %lu bytes after a total of %lu bytes\n", |
name, *name ? ": " : "", |
(unsigned long) size, (unsigned long) allocated); |
#else /* HAVE_SBRK */ |
fprintf (stderr, |
"\n%s%sout of memory allocating %lu bytes\n", |
name, *name ? ": " : "", |
(unsigned long) size); |
#endif /* HAVE_SBRK */ |
xexit (1); |
} |
PTR |
xmalloc (size_t size) |
{ |
PTR newmem; |
if (size == 0) |
size = 1; |
newmem = malloc (size); |
if (!newmem) |
xmalloc_failed (size); |
return (newmem); |
} |
PTR |
xcalloc (size_t nelem, size_t elsize) |
{ |
PTR newmem; |
if (nelem == 0 || elsize == 0) |
nelem = elsize = 1; |
newmem = calloc (nelem, elsize); |
if (!newmem) |
xmalloc_failed (nelem * elsize); |
return (newmem); |
} |
PTR |
xrealloc (PTR oldmem, size_t size) |
{ |
PTR newmem; |
if (size == 0) |
size = 1; |
if (!oldmem) |
newmem = malloc (size); |
else |
newmem = realloc (oldmem, size); |
if (!newmem) |
xmalloc_failed (size); |
return (newmem); |
} |
/contrib/toolchain/binutils/libiberty/xmemdup.c |
---|
0,0 → 1,39 |
/* xmemdup.c -- Duplicate a memory buffer, using xcalloc. |
This trivial function is in the public domain. |
Jeff Garzik, September 1999. */ |
/* |
@deftypefn Replacement void* xmemdup (void *@var{input}, @ |
size_t @var{copy_size}, size_t @var{alloc_size}) |
Duplicates a region of memory without fail. First, @var{alloc_size} bytes |
are allocated, then @var{copy_size} bytes from @var{input} are copied into |
it, and the new memory is returned. If fewer bytes are copied than were |
allocated, the remaining memory is zeroed. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
#include <sys/types.h> /* For size_t. */ |
#ifdef HAVE_STRING_H |
#include <string.h> |
#else |
# ifdef HAVE_STRINGS_H |
# include <strings.h> |
# endif |
#endif |
PTR |
xmemdup (const PTR input, size_t copy_size, size_t alloc_size) |
{ |
PTR output = xcalloc (1, alloc_size); |
return (PTR) memcpy (output, input, copy_size); |
} |
/contrib/toolchain/binutils/libiberty/xstrdup.c |
---|
0,0 → 1,36 |
/* xstrdup.c -- Duplicate a string in memory, using xmalloc. |
This trivial function is in the public domain. |
Ian Lance Taylor, Cygnus Support, December 1995. */ |
/* |
@deftypefn Replacement char* xstrdup (const char *@var{s}) |
Duplicates a character string without fail, using @code{xmalloc} to |
obtain memory. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <sys/types.h> |
#ifdef HAVE_STRING_H |
#include <string.h> |
#else |
# ifdef HAVE_STRINGS_H |
# include <strings.h> |
# endif |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
char * |
xstrdup (const char *s) |
{ |
register size_t len = strlen (s) + 1; |
register char *ret = XNEWVEC (char, len); |
return (char *) memcpy (ret, s, len); |
} |
/contrib/toolchain/binutils/libiberty/xstrerror.c |
---|
0,0 → 1,79 |
/* xstrerror.c -- jacket routine for more robust strerror() usage. |
Fri Jun 16 18:30:00 1995 Pat Rankin <rankin@eql.caltech.edu> |
This code is in the public domain. */ |
/* |
@deftypefn Replacement char* xstrerror (int @var{errnum}) |
Behaves exactly like the standard @code{strerror} function, but |
will never return a @code{NULL} pointer. |
@end deftypefn |
*/ |
#include <stdio.h> |
#include "config.h" |
#include "libiberty.h" |
#ifdef VMS |
# include <errno.h> |
# if !defined (__STRICT_ANSI__) && !defined (__HIDE_FORBIDDEN_NAMES) |
# ifdef __cplusplus |
extern "C" { |
# endif /* __cplusplus */ |
extern char *strerror (int,...); |
# define DONT_DECLARE_STRERROR |
# ifdef __cplusplus |
} |
# endif /* __cplusplus */ |
# endif |
#endif /* VMS */ |
#ifndef DONT_DECLARE_STRERROR |
# ifdef __cplusplus |
extern "C" { |
# endif /* __cplusplus */ |
extern char *strerror (int); |
# ifdef __cplusplus |
} |
# endif /* __cplusplus */ |
#endif |
/* If strerror returns NULL, we'll format the number into a static buffer. */ |
#define ERRSTR_FMT "undocumented error #%d" |
static char xstrerror_buf[sizeof ERRSTR_FMT + 20]; |
/* Like strerror, but result is never a null pointer. */ |
char * |
xstrerror (int errnum) |
{ |
char *errstr; |
#ifdef VMS |
char *(*vmslib_strerror) (int,...); |
/* Override any possibly-conflicting declaration from system header. */ |
vmslib_strerror = (char *(*) (int,...)) strerror; |
/* Second argument matters iff first is EVMSERR, but it's simpler to |
pass it unconditionally. `vaxc$errno' is declared in <errno.h> |
and maintained by the run-time library in parallel to `errno'. |
We assume that `errnum' corresponds to the last value assigned to |
errno by the run-time library, hence vaxc$errno will be relevant. */ |
errstr = (*vmslib_strerror) (errnum, vaxc$errno); |
#else |
errstr = strerror (errnum); |
#endif |
/* If `errnum' is out of range, result might be NULL. We'll fix that. */ |
if (!errstr) |
{ |
sprintf (xstrerror_buf, ERRSTR_FMT, errnum); |
errstr = xstrerror_buf; |
} |
return errstr; |
} |
/contrib/toolchain/binutils/libiberty/xstrndup.c |
---|
0,0 → 1,60 |
/* Implement the xstrndup function. |
Copyright (C) 2005 Free Software Foundation, Inc. |
Written by Kaveh R. Ghazi <ghazi@caip.rutgers.edu>. |
This file is part of the libiberty library. |
Libiberty 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. |
Libiberty 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 libiberty; see the file COPYING.LIB. If |
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, |
Boston, MA 02110-1301, USA. */ |
/* |
@deftypefn Replacement char* xstrndup (const char *@var{s}, size_t @var{n}) |
Returns a pointer to a copy of @var{s} with at most @var{n} characters |
without fail, using @code{xmalloc} to obtain memory. The result is |
always NUL terminated. |
@end deftypefn |
*/ |
#ifdef HAVE_CONFIG_H |
#include "config.h" |
#endif |
#include <sys/types.h> |
#ifdef HAVE_STRING_H |
#include <string.h> |
#else |
# ifdef HAVE_STRINGS_H |
# include <strings.h> |
# endif |
#endif |
#include "ansidecl.h" |
#include "libiberty.h" |
char * |
xstrndup (const char *s, size_t n) |
{ |
char *result; |
size_t len = strlen (s); |
if (n < len) |
len = n; |
result = XNEWVEC (char, len + 1); |
result[len] = '\0'; |
return (char *) memcpy (result, s, len); |
} |