Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5190 → Rev 5191

/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 = &param;
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 ? &regs : (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);
}