Import a copy of ucpp, lightweight cpp for use by xrdb so that it
doesn't depend on the 'comp' set. ok espie@ deraadt@
This commit is contained in:
parent
c536fefa02
commit
a2223c7302
21
app/xrdb-cpp/CHANGELOG
Normal file
21
app/xrdb-cpp/CHANGELOG
Normal file
@ -0,0 +1,21 @@
|
||||
ucpp-1.3.2
|
||||
* Fixed Issue 8, Included files missing a "terminating carriage
|
||||
return character" will interrupt preprocessing in sample.c/LEXER
|
||||
mode.
|
||||
(http://code.google.com/p/ucpp/issues/detail?id=8)
|
||||
|
||||
ucpp-1.3.1
|
||||
* Fixed Issue 5, "\r\n" carriage return characters are double
|
||||
counted.
|
||||
(http://code.google.com/p/ucpp/issues/detail?id=5)
|
||||
* Fixed Issue 6, Included files missing a "terminating carriage
|
||||
return character" will interrupt preprocessing in ucpp
|
||||
(STAND_ALONE mode).
|
||||
(http://code.google.com/p/ucpp/issues/detail?id=6)
|
||||
* Fixed Issue 7, STD_MACROS & STD_ASSERTS undefined when trying to
|
||||
build ucpp -DSTAND_ALONE.
|
||||
(http://code.google.com/p/ucpp/issues/detail?id=7)
|
||||
* Build ucpp & libucpp with 'make'.
|
||||
|
||||
ucpp-1.3
|
||||
* Original import into svn at code.google.com/p/ucpp
|
115
app/xrdb-cpp/Makefile
Normal file
115
app/xrdb-cpp/Makefile
Normal file
@ -0,0 +1,115 @@
|
||||
# Makefile for ucpp
|
||||
#
|
||||
# (c) Thomas Pornin 1999 - 2002
|
||||
#
|
||||
# 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.
|
||||
# 4. The name of the authors may not be used to endorse or promote
|
||||
# products derived from this software without specific prior written
|
||||
# permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
|
||||
.POSIX:
|
||||
|
||||
# ----- user configurable part -----
|
||||
|
||||
# Edit the variables to suit your system.
|
||||
#
|
||||
# use -DAUDIT to enable some internal sanity checks
|
||||
# use -DMEM_CHECK to check the return value of malloc()
|
||||
# (superseded by AUDIT)
|
||||
# use -DMEM_DEBUG to enable memory leak research (warning: this
|
||||
# slows down ucpp a bit, and greatly increases memory consumption)
|
||||
# use -DINLINE=foobar to enable use of the 'foobar'
|
||||
# non standard qualifier, as an equivalent to the C99 'inline'
|
||||
# qualifier. See tune.h for details.
|
||||
#
|
||||
# Two FLAGS lines are given for each system type; chose the first one for
|
||||
# debug, the second one for a fast binary.
|
||||
|
||||
# for a generic compiler called cc
|
||||
#CC = cc
|
||||
#FLAGS = -DAUDIT
|
||||
#FLAGS = -O -DMEM_CHECK
|
||||
|
||||
# for Minix-86
|
||||
#CC = cc
|
||||
#LDFLAGS = -i
|
||||
#FLAGS = -m -DAUDIT
|
||||
#FLAGS = -O -m -DMEM_CHECK
|
||||
|
||||
# for gcc
|
||||
CC = gcc
|
||||
FLAGS = -O3 -W -Wall -ansi
|
||||
#FLAGS = -g -W -Wall -ansi -DAUDIT -DMEM_DEBUG
|
||||
#FLAGS = -O3 -mcpu=pentiumpro -fomit-frame-pointer -W -Wall -ansi -DMEM_CHECK
|
||||
#FLAGS = -O -pg -W -Wall -ansi -DMEM_CHECK
|
||||
#LDFLAGS = -pg
|
||||
|
||||
# for the Compaq C compiler on Alpha/Linux
|
||||
#CC = ccc
|
||||
#FLAGS = -w0 -g -DAUDIT
|
||||
#FLAGS = -w0 -fast -DMEM_CHECK
|
||||
|
||||
# for the Sun Workshop C Compiler
|
||||
#CC = cc
|
||||
#FLAGS = -g -Xa -DAUDIT
|
||||
#FLAGS = -Xa -fast -DMEM_CHECK
|
||||
|
||||
# flags for the link step
|
||||
LIBS =
|
||||
#LIBS = libefence.a
|
||||
#LIBS = -lgc_dbg
|
||||
|
||||
STAND_ALONE = -DSTAND_ALONE
|
||||
|
||||
ifdef STAND_ALONE
|
||||
CSRC = mem.c nhash.c cpp.c lexer.c assert.c macro.c eval.c
|
||||
FINAL_STEP = $(CC) $(LDFLAGS) -DUCPP_CONFIG $(STAND_ALONE) -o ucpp $(CSRC) $(LIBS)
|
||||
endif
|
||||
|
||||
# ----- nothing should be changed below this line -----
|
||||
|
||||
COBJ = mem.o nhash.o cpp.o lexer.o assert.o macro.o eval.o
|
||||
CFLAGS = $(FLAGS)
|
||||
|
||||
all: ucpp
|
||||
@ar cq libucpp.a *.o
|
||||
|
||||
clean:
|
||||
@rm -f *.o ucpp core *.a
|
||||
|
||||
ucpp: $(COBJ)
|
||||
@$(FINAL_STEP)
|
||||
|
||||
assert.o: tune.h ucppi.h cpp.h nhash.h mem.h
|
||||
@$(CC) $(CFLAGS) -c assert.c
|
||||
cpp.o: tune.h ucppi.h cpp.h nhash.h mem.h
|
||||
@$(CC) $(CFLAGS) -c cpp.c
|
||||
eval.o: tune.h ucppi.h cpp.h nhash.h mem.h arith.c arith.h
|
||||
@$(CC) $(CFLAGS) -c eval.c
|
||||
lexer.o: tune.h ucppi.h cpp.h nhash.h mem.h
|
||||
@$(CC) $(CFLAGS) -c lexer.c
|
||||
macro.o: tune.h ucppi.h cpp.h nhash.h mem.h
|
||||
@$(CC) $(CFLAGS) -c macro.c
|
||||
mem.o: mem.h
|
||||
@$(CC) $(CFLAGS) -c mem.c
|
||||
nhash.o: nhash.h mem.h
|
||||
@$(CC) $(CFLAGS) -c nhash.c
|
877
app/xrdb-cpp/README
Normal file
877
app/xrdb-cpp/README
Normal file
@ -0,0 +1,877 @@
|
||||
ucpp-1.3 is a C preprocessor compliant to ISO-C99.
|
||||
|
||||
Author: Thomas Pornin <pornin@bolet.org>
|
||||
Main site: http://pornin.nerim.net/ucpp/
|
||||
|
||||
|
||||
|
||||
INTRODUCTION
|
||||
------------
|
||||
|
||||
A C preprocessor is a part of a C compiler responsible for macro
|
||||
replacement, conditional compilation and inclusion of header files.
|
||||
It is often found as a stand-alone program on Unix systems.
|
||||
|
||||
ucpp is such a preprocessor; it is designed to be quick and light,
|
||||
but anyway fully compliant to the ISO standard 9899:1999, also known
|
||||
as C99. ucpp can be compiled as a stand-alone program, or linked to
|
||||
some other code; in the latter case, ucpp will output tokens, one
|
||||
at a time, on demand, as an integrated lexer.
|
||||
|
||||
ucpp operates in two modes:
|
||||
-- lexer mode: ucpp is linked to some other code and outputs a stream of
|
||||
tokens (each call to the lex() function will yield one token)
|
||||
-- non-lexer mode: ucpp preprocesses text and outputs the resulting text
|
||||
to a file descriptor; if linked to some other code, the cpp() function
|
||||
must be called repeatedly, otherwise ucpp is a stand-alone binary.
|
||||
|
||||
|
||||
|
||||
INSTALLATION
|
||||
------------
|
||||
|
||||
1. Uncompress the archive file and extract the source files.
|
||||
|
||||
2. Edit tune.h. Here is a short explanation of compile-time options:
|
||||
|
||||
LOW_MEM
|
||||
Enable memory-saving functions; this is for low-end and old systems,
|
||||
but seems to be good for larger systems too. Keep it.
|
||||
NO_LIBC_BUF
|
||||
NO_UCPP_BUF
|
||||
Two options used to disable the two bufferings inside ucpp. Define
|
||||
both options for maximum memory savings but you will probably want
|
||||
to keep libc buffering for decent performance. Define none on large
|
||||
systems (modern 32 or 64-bit systems).
|
||||
UCPP_MMAP
|
||||
With this option, if ucpp internal buffering is active, ucpp will
|
||||
try to mmap() the input files. This might yield a slight performance
|
||||
improvement, but will work only on a limited set of architectures.
|
||||
PRAGMA_TOKENIZE
|
||||
Make ucpp generate tokenized PRAGMA tokens on #pragma and _Pragma();
|
||||
tokenization is made this way: tokens are assembled as a null
|
||||
terminated array of unsigned chars; if a token has a string value
|
||||
(as defined by the STRING_TOKEN macro), the value follows the token,
|
||||
terminated by PRAGMA_TOKEN_END (by default, a newline character cast
|
||||
to unsigned char). Whitespace tokens are skipped. The "name" value
|
||||
of the PRAGMA token is a pointer to that array. This setting is
|
||||
irrelevant in non-lexer mode.
|
||||
PRAGMA_DUMP
|
||||
In non-lexer mode, keep #pragma in output; non-void _Pragma() are
|
||||
translated to the equivalent #pragma. Irrelevant in lexer mode.
|
||||
NO_PRAGMA_IN_DIRECTIVE
|
||||
Do not evaluate _Pragma() inside #if, #include, #include_next and #line
|
||||
directives; instead, emit an error (since the remaining _Pragma will
|
||||
surely imply a syntax error).
|
||||
DSHARP_TOKEN_MERGE
|
||||
When two tokens are to be merged with the `##' operator, but fail
|
||||
because they do not merge into a single valid token, ucpp keeps those
|
||||
two tokens separate by adding an extra space between them in text
|
||||
output. With this option on, that extra space is not added, which means
|
||||
that some tokens may merge partially if the text output is preprocessed
|
||||
again. See tune.h for details.
|
||||
INMACRO_FLAG
|
||||
In lexer mode, set the inmacro flag to 1 if the current token comes
|
||||
from a macro replacement, 0 otherwise. macro_count maintains an
|
||||
increasing counter of such replacements. CONTEXT tokens count as
|
||||
one macro replacement each. #pragma, and _Pragma() that do not come
|
||||
from a macro replacement, also count as one macro replacement each.
|
||||
This setting is irrelevant in non-lexer mode.
|
||||
STD_INCLUDE_PATH
|
||||
Default include path in stand-alone ucpp.
|
||||
STD_MACROS
|
||||
Default predefined macros in stand-alone ucpp.
|
||||
STD_ASSERT
|
||||
Default assertions in stand-alone ucpp.
|
||||
NATIVE_SIGNED
|
||||
NATIVE_UNSIGNED
|
||||
NATIVE_UNSIGNED_BITS
|
||||
NATIVE_SIGNED_MIN
|
||||
NATIVE_SIGNED_MAX
|
||||
SIMUL_ARITH_SUBTYPE
|
||||
SIMUL_SUBTYPE_BITS
|
||||
SIMUL_NUMBITS
|
||||
WCHAR_SIGNEDNESS
|
||||
Those options define how #if expressions are evaluated; see the
|
||||
cross-compilation section of this file for more info, and the
|
||||
comments in tune.h. Extra info is found in arith.h and arith.c,
|
||||
at the possible expense of your mental health.
|
||||
DEFAULT_LEXER_FLAGS
|
||||
DEFAULT_CPP_FLAGS
|
||||
Default flags in respectively lexer and non-lexer modes.
|
||||
POSIX_JMP
|
||||
Define this if your architecture defines sigsetjmp() and
|
||||
siglongjmp(); it is known to (very slightly) improve performance
|
||||
on AIX systems.
|
||||
MAX_CHAR_VAL
|
||||
ucpp will consider characters whose value is equal or above
|
||||
MAX_CHAR_VAL as outside the C source charset (so they will be
|
||||
treated just like '@', for instance). For ASCII systems, 128
|
||||
is fine. 256 is a safer value, but uses more (static) memory.
|
||||
For performance reasons, use a power of two. If MAX_CHAR_VAL is
|
||||
correctly adjusted, ucpp should be compatible with any character
|
||||
set.
|
||||
UNBREAKABLE_SPACE
|
||||
If you want an extra-whitespace character, define this macro to that
|
||||
character. For instance, define this to 160 on an ISO-8859-1 system
|
||||
if you want the 'unbreakable space' to be considered as whitespace.
|
||||
SEMPER_FIDELIS
|
||||
With this option set, ucpp, when used as a lexer, will pass
|
||||
whitespace tokens to its caller, and those tokens will have their
|
||||
true content; this is intended for reconstruction of the source
|
||||
line. Beware that some comments may have embedded newlines.
|
||||
COPY_LINE_LENGTH
|
||||
ucpp can maintain a copy of the current source line, up to that
|
||||
length. Irrelevant to stand-alone version.
|
||||
*_MEMG
|
||||
Those settings modify ucpp behaviour, wrt memory allocations. With
|
||||
higher values, ucpp will perform less malloc() calls and will run
|
||||
faster, but it will use more memory. Reduce INPUT_BUF_MEMG and
|
||||
OUTPUT_BUF_MEMG on low-memory systems, if you kept ucpp buffering
|
||||
(see NO_UCPP_BUF option).
|
||||
|
||||
3. Edit the Makefile. You should define the variables CC and FLAGS;
|
||||
there are the following options:
|
||||
|
||||
-DAUDIT
|
||||
Enable internal sanity checks; this slows down a bit ucpp. Do not
|
||||
define unless you plan to debug ucpp.
|
||||
-DMEM_CHECK
|
||||
With this setting, ucpp will check for the return value of malloc()
|
||||
and exit with a diagnostic when out of memory. MEM_CHECK is implied
|
||||
by AUDIT.
|
||||
-DMEM_DEBUG
|
||||
Enable memory debug code. This will track memory leaks and several
|
||||
occurrences of memory management errors; it will also slow down
|
||||
things and increase memory consumption, so you probably do not
|
||||
want to use this option.
|
||||
-DINLINE=foobar
|
||||
The ucpp code uses "inline" qualifier for some functions; by
|
||||
default, that qualifier is macro-replaced with nothing. Define
|
||||
INLINE to the correct replacement for your compiler, if supported.
|
||||
Note that all "inline" functions in ucpp are also "static". For any
|
||||
C99-compliant compiler, the GNU compiler (gcc), and the Compaq C
|
||||
compiler under Linux/Alpha, no -DINLINE is needed (see tune.h for
|
||||
details).
|
||||
|
||||
4. Compile by typing "make". This should produce the ucpp executable
|
||||
file. You might see some warning messages, especially with gcc:
|
||||
gcc believes some variables might be used prior to their
|
||||
initialization; ignore those messages.
|
||||
|
||||
5. Install wherever you want the binary and the man page ucpp.1. I
|
||||
have not provided an install sequence because I didn't bother.
|
||||
|
||||
6. If you do not have the make utility, compile each file separately
|
||||
and link them together. The exact details depend on your compiler.
|
||||
You must define the macro STAND_ALONE when compiling cpp.c (there
|
||||
is such a definition, commented out, in cpp.c, line 34).
|
||||
|
||||
There is no "configure" script because:
|
||||
-- I do not like the very idea of a "configure" script.
|
||||
-- ucpp is written in ANSI-C and should be fairly portable.
|
||||
-- There is no such thing as "standard" settings for a C preprocessor.
|
||||
The predefined system macros, standard assertions,... must be tuned
|
||||
by the sysadmin.
|
||||
-- The primary goal of ucpp is to be included in compilers. The
|
||||
stand-alone version is mainly a debugging tool.
|
||||
|
||||
Please note that you need an ISO-C90 (formerly ANSI) C compiler suite
|
||||
(including the standard library) to compile ucpp. If your compiler is
|
||||
not C99 (or later), read the cross-compilation section in this README
|
||||
file.
|
||||
|
||||
The C90 and C99 standards state that external linkage names might be
|
||||
considered equal or different based upon only their first 6 characters;
|
||||
this rule might make ucpp not compile on a conformant C implementation.
|
||||
I have yet to see such an implementation, however.
|
||||
|
||||
If you want to use ucpp as an integrated preprocessor and lexer, see the
|
||||
section REUSE. Compiling ucpp as a library is an exercise left to the
|
||||
reader.
|
||||
|
||||
With the LOW_MEM code enabled, ucpp can run on a Minix-i86 or Msdos
|
||||
16-bit small-memory-model machine. It will not be fully compliant
|
||||
on such an architecture to C99, since C99 states that at least one
|
||||
source code with 4095 simultaneously defined macros must be processed;
|
||||
ucpp will be limited to about 1500 macros (at most) due to memory
|
||||
restrictions. At least ucpp can preprocess its own code in these
|
||||
conditions. LOW_MEM is on by default because it seems to improve
|
||||
performance on large systems.
|
||||
|
||||
|
||||
|
||||
LICENSE
|
||||
-------
|
||||
|
||||
The copyright notice and license is at the beginning of the Makefile and
|
||||
each source file. It is basically a BSD license, without the advertising
|
||||
subclause (which BSD dropped recently anyway) and with no reference to
|
||||
Berkeley (since the code is all mine, written from scratch). Informally,
|
||||
this means that you can reuse and redistribute the code as you want,
|
||||
provided that you state in the documentation (or any substantial part of
|
||||
the software) of redistributed code that I am the original author. (If
|
||||
you press a cdrom with 200 software packages, I do not insist on having
|
||||
my name on the cover of the cdrom -- just keep a Readme file somewhere
|
||||
on the cdrom, with the copyright notice included.)
|
||||
|
||||
As a courteous gesture, if you reuse my code, please drop me a mail.
|
||||
It raises my self-esteem.
|
||||
|
||||
|
||||
|
||||
REUSE
|
||||
-----
|
||||
|
||||
The code has been thought as part of a bigger project; it might be
|
||||
used as an integrated lexer, that will read files, process them as a
|
||||
C preprocessor, and output a stream of C tokens. To include this code
|
||||
into a project, compile with STAND_ALONE undefined.
|
||||
|
||||
To use the preprocessor and lexer, several steps should be performed.
|
||||
See the file 'sample.c' for an example.
|
||||
|
||||
1. call init_cpp(). This function initializes the lexer automaton.
|
||||
|
||||
2. set the following global variables:
|
||||
no_special_macros
|
||||
non-zero if the special macros (__FILE__ and others)
|
||||
should not be defined. This is a global flag since
|
||||
it affects the redefinition of such macros (which are
|
||||
allowed if the special macros are not defined)
|
||||
c99_compliant
|
||||
if non-zero, define __STDC_VERSION__ to 199901L; this
|
||||
is the default; otherwise, do not define __STDC_VERSION__.
|
||||
Note that ucpp will accept to undefine __STDC_VERSION__
|
||||
with a #undef directive.
|
||||
c99_hosted
|
||||
if strictly positive, define __STDC_HOSTED__ to 1.
|
||||
If zero, define __STDC_HOSTED__ to 0. If negative,
|
||||
do not define __STDC_HOSTED__. The default is 1.
|
||||
emit_defines and emit_assertions should be set to 0 for
|
||||
the step 3.
|
||||
|
||||
3. call init_tables(). This function initializes the macro table
|
||||
and other things; it will intialize assertions if it has a non-zero
|
||||
argument.
|
||||
|
||||
4. call init_include_path(). This function will reset the include
|
||||
path to the list of paths given as argument.
|
||||
|
||||
5. set the following global variables
|
||||
emit_dependencies
|
||||
set to 1 if dependencies should be emitted during
|
||||
preprocessing
|
||||
set to 2 if dependencies should also be emitted for
|
||||
system include files
|
||||
emit_defines
|
||||
set to non-zero if #define macro definitions should be
|
||||
emitted when macros are defined
|
||||
emit_assertions
|
||||
set to non-zero if #define macro definitions should be
|
||||
emitted when macros are defined
|
||||
emit_output
|
||||
the FILE * where the above items are sent if one of the
|
||||
three emit_ variables is set to non zero
|
||||
transient_characters
|
||||
this is for some cross-compilation; see the relevant
|
||||
part in this README file for details
|
||||
|
||||
6. call set_init_filename() with the initial filename as argument;
|
||||
the second argument indicates whether the filename is real or
|
||||
conventional ("real" means "an fopen() on it will work").
|
||||
|
||||
7. initialize your struct lexer_state:
|
||||
call init_lexer_state()
|
||||
call init_lexer_mode() if the preprocessor is supposed to
|
||||
output a list of tokens, otherwise set the flags field
|
||||
to DEFAULT_CPP_FLAGS and set the output field to the
|
||||
FILE * where output should be sent
|
||||
(init_lexer_mode(), if called at all, must be called after
|
||||
init_lexer_state())
|
||||
adjust the flags field; here is the meaning of flags:
|
||||
|
||||
WARN_STANDARD
|
||||
emit the standard warnings
|
||||
WARN_ANNOYING
|
||||
emit the useless and annoying warnings
|
||||
WARN_TRIGRAPHS
|
||||
count trigraphs encountered; it is up to the caller to emit
|
||||
a warning if some trigraphs were indeed encountered; the count
|
||||
is stored in the count_trigraphs field of the struct lexer_state
|
||||
WARN_TRIGRAPHS_MORE
|
||||
emit a warning for each trigraph encountered
|
||||
WARN_PRAGMA
|
||||
emit a warning for each non-void _Pragma encountered in non-lexer
|
||||
mode (because these are dumped as #pragma in the output) and for each
|
||||
#pragma too, if ucpp was compiled without PRAGMA_DUMP
|
||||
FAIL_SHARP
|
||||
emit errors on '#' tokens beginning a line and not followed
|
||||
by a valid cpp directive
|
||||
CCHARSET
|
||||
emit errors when non-C characters are encountered; if this flag
|
||||
is not set, each non-C character will be considered as a BUNCH
|
||||
token (since C99 states that non-C characters are allowed as
|
||||
long as they "disappear" during preprocessing [through macro
|
||||
replacement and stringification for instance], this flag must
|
||||
not be set, for maximum C99 compliance)
|
||||
DISCARD_COMMENTS
|
||||
do not keep comments in output (irrelevant in lexer mode)
|
||||
CPLUSPLUS_COMMENTS
|
||||
understand new style comments (//) (mandatory for C99)
|
||||
LINE_NUM
|
||||
emit #line directives when entering a file, if not in lexer mode;
|
||||
emit CONTEXT token in lexer mode for #line and new files
|
||||
GCC_LINE_NUM
|
||||
if LINE_NUM is set, emit gcc-like directives instead of #line
|
||||
HANDLE_ASSERTIONS
|
||||
understand assertions in #if expressions (and #assert, #unassert)
|
||||
HANDLE_PRAGMA
|
||||
make PRAGMA tokens for #pragma; irrelevant in non-lexer mode
|
||||
(handling of some pragmas is required in C99 but is not of
|
||||
the competence of the preprocessor; without this flag, ucpp will
|
||||
ignore the contents of #pragma and _Pragma directives)
|
||||
MACRO_VAARG
|
||||
understand macros with a variable number of arguments (mandatory
|
||||
for C99)
|
||||
UTF8_SOURCE
|
||||
understand UTF-8 encoding: multibyte characters are considered
|
||||
equivalent to letters as far as syntax is concerned (they can
|
||||
be used in identifiers)
|
||||
LEXER
|
||||
act as a lexer, outputting tokens
|
||||
TEXT_OUTPUT
|
||||
this flag should be set to 0 if ucpp works as a lexer, 1 otherwise.
|
||||
It is somehow redundant with the LEXER flag, but the presence of
|
||||
those two different flags is needed in ucpp.
|
||||
KEEP_OUTPUT
|
||||
in non-lexer mode, emit the result of preprocessing
|
||||
COPY_LINE
|
||||
maintain a copy of the last read line in the copy_line field of
|
||||
the struct lexer_state ; see below for how to use this buffer
|
||||
HANDLE_TRIGRAPHS
|
||||
understand trigraphs, such as ??/ for \. This option should be
|
||||
set by default, except for some legacy code.
|
||||
|
||||
There are other flags, but they are for private usage of ucpp.
|
||||
|
||||
8. adjust the input field in the lexer_state to the FILE * from where
|
||||
source file is read. If you use the UCPP_MMAP compile-time option,
|
||||
and your input file is eligible to mmap(), then you can call
|
||||
fopen_mmap_file() to open it, then set_input_file() to set ls->input
|
||||
and some other internal options. Do not call set_input_file() unless
|
||||
you just called fopen_mmap_file() just before on the same file.
|
||||
|
||||
9. call add_incpath() to add an include path, define_macro() and
|
||||
undef_macro() to add or remove macros, make_assertion() and
|
||||
destroy_assertion() to add or remove assertions.
|
||||
|
||||
10. call enter_file() (this is needed only in non-lexer mode, or if
|
||||
LINE_NUM is set).
|
||||
|
||||
|
||||
Afterwards:
|
||||
|
||||
-- if you are in lexer mode, call lex(); each call will make the ctok
|
||||
field point to the next token. A non-zero return value is an error.
|
||||
lex() skips whitespace tokens. The memory used by the string value
|
||||
of some tokens (identifiers, numbers...) is automatically freed,
|
||||
so copy the contents of each such token if you want to keep it
|
||||
(tokens with a string content are identified by the STRING_TOKEN
|
||||
macro applied to their type).
|
||||
When lex() returned a non-zero value: if it is CPPERR_EOF, then
|
||||
end-of-input was reached. Otherwise, it is a genuine error and
|
||||
ls->ctok is an undefined token; skip it and call lex() again to
|
||||
ignore the error.
|
||||
|
||||
-- otherwise, call cpp(); each call will analyze one or more tokens
|
||||
(one token if it did find neither a cpp directive nor a macro name).
|
||||
A positive return value is an error.
|
||||
|
||||
For both functions, if the return value is CPPERR_EOF (which is a
|
||||
strictly positive value), then it means that the end of file was
|
||||
reached. Call check_cpp_errors() after end of file for pending errors
|
||||
(unfinished #if constructions for instance). In non-lexer mode,
|
||||
call flush_output().
|
||||
|
||||
In the struct lexer_state, the following fields might be read:
|
||||
line the current input line number
|
||||
oline the current output line number (in non-lexer mode)
|
||||
flags the flags described above
|
||||
count_trigraphs the number of trigraphs encountered
|
||||
inmacro the current token comes from a macro
|
||||
macro_count the current macro counter
|
||||
"flags" is an unsigned long and might be modified; the three others
|
||||
are of long type.
|
||||
|
||||
|
||||
To perform another preprocessing: use free_lexer_state() to release
|
||||
memory used by the buffers referenced in lexer_state, and go back to
|
||||
step 2. The different tables (macros, assertions...) should be reset to
|
||||
their respective initial contents.
|
||||
|
||||
There is also the wipeout() function: when called, it should release
|
||||
(almost) all memory blocks allocated dynamically. After a wipeout(),
|
||||
ucpp should be back to its state at step 2 (init_cpp() initializes only
|
||||
static tables, that are never freed nor modified afterwards).
|
||||
|
||||
|
||||
The COPY_LINE buffer: the struct lexer_state contains two interesting
|
||||
fields, copy_line[] and cli. If the COPY_LINE flag is on, each read
|
||||
line is stored in this buffer, up to (at most) COPY_LINE_LENGTH - 1
|
||||
characters (COPY_LINE_LENGTH is defined in tune.h). The last character
|
||||
of the buffer is always a zero, and if the line was read entirely, it is
|
||||
zero terminated; the trailing newline is not included.
|
||||
|
||||
The purpose of this buffer is error-reporting. When an error occurs
|
||||
(cpp() returns a strictly positive value, or lex() returns a non-zero
|
||||
value), if your struct lexer_state is called ls, use this code:
|
||||
|
||||
if (ls.cli != 0) ls.copy_line[ls.cli] = 0;
|
||||
|
||||
This will add a trailing 0 if the line was not read entirely.
|
||||
|
||||
|
||||
ucpp may be configured at runtime to accept alternate characters as
|
||||
possible parts of identifiers. Typical intended usage is for the '$'
|
||||
and '@' characters. The two relevant functions are set_identifier_char()
|
||||
and unset_identifier_char(). When this call is issued:
|
||||
set_identifier_char('$');
|
||||
then for all the remaining input, the '$' character will be considered
|
||||
as just another letter, as far as identifier tokenizing is concerned. This
|
||||
is for identifiers only; numeric constants are not modified by that setting.
|
||||
This call resets things back:
|
||||
unset_identifier_char('$');
|
||||
Those two functions modify the static table which is initialized by
|
||||
init_cpp(). You may call init_cpp() at any time to restore the table
|
||||
to its standard state.
|
||||
|
||||
When using this feature, take care of the following points:
|
||||
|
||||
-- Do NOT use a character whose numeric value (as an `unsigned char'
|
||||
cast into an `int') is greater than or equal to MAX_CHAR_VAL (in tune.h).
|
||||
This would lead to unpredictable results, including an abrupt crash of
|
||||
ucpp. ucpp makes absolutely no check whatsoever on that matter: this is
|
||||
the programmer's responsibility.
|
||||
|
||||
-- If you use a standard character such as '+' or '{', tokens which
|
||||
begin with those characters cease to exist. This can be troublesome.
|
||||
If you use set_identifier_char() on the '<' character, the handling of
|
||||
#include directives will be greatly disturbed. Therefore the use of any
|
||||
standard C character in set_identifier_char() of unset_identifier_char()
|
||||
is declared unsupported, forbidden and altogether unwise.
|
||||
|
||||
-- Stricto sensu, when an extra character is declared as part of an
|
||||
identifier, ucpp behaviour cease to conform to C99, which mandates that
|
||||
characters such as '$' or '@' must be treated as independant tokens of
|
||||
their own. Therefore, if your purpose is to use ucpp in a conformant
|
||||
C implementation, the use of set_identifier_char() should be made at
|
||||
least a runtime option.
|
||||
|
||||
-- When enabling a new character in the middle of a macro replacement,
|
||||
the effect of that replacement may be delayed up to the end of that
|
||||
macro (but this is a "may" !). If you wish to trigger this feature with
|
||||
a custom #pragma or _Pragma(), you should remember it (for instance,
|
||||
usine _Pragma() in a macro replacement, and then the extra character
|
||||
in the same macro replacement, is not reliable).
|
||||
|
||||
|
||||
|
||||
COMPATIBILITY NOTES
|
||||
-------------------
|
||||
|
||||
The C language has a lengthening history. Nowadays, C comes in three
|
||||
flavours:
|
||||
|
||||
-- Traditional C, aka "K&R". This is the language first described by
|
||||
Brian Kernighan and Dennis Ritchie, and implemented in the first C
|
||||
compiler that was ever coded. There are actually several dialects of
|
||||
K&R, and all of them are considered deprecated.
|
||||
|
||||
-- ISO 9899:1990, aka C90, aka C89, aka ANSI-C. Formalized by ANSI
|
||||
in 1989 and adopted by ISO the next year, it is the C flavour many C
|
||||
compilers understand. It is mostly backward compatible with K&R C, but
|
||||
with enhancements, clarifications and several new features.
|
||||
|
||||
-- ISO 9899:1999, aka C99. This is an evolution on C90, almost fully
|
||||
backward compatible with C90. C99 introduces many new and useful
|
||||
features, however, including in the preprocessor.
|
||||
|
||||
There was also a normative addendum in 1995, that added a few features
|
||||
to C90 (for instance, digraphs) that are also present in C99. It is
|
||||
sometimes refered to as "C95" or "AMD 1".
|
||||
|
||||
|
||||
ucpp implements the C99 standard, but can be used in a stricter mode,
|
||||
to enforce C90 compatibility (it will, however, still recognize some
|
||||
constructions that are not in plain C90).
|
||||
|
||||
ucpp also knows about several extensions to C99:
|
||||
|
||||
-- Assertions: this is an extension to the defined() operator, with
|
||||
its own namespace. Assertions seem to be used in several places,
|
||||
therefore ucpp knows about them. It is recommended to enable
|
||||
assertions by default on Solaris systems.
|
||||
-- Unicode: the C99 norm specifies that extended characters, from
|
||||
the ISO-10646 charset (aka "unicode") can be used in identifiers
|
||||
with the notations \u and \U. ucpp also accepts (with the proper
|
||||
flag) the UTF-8 encoding in the source file for such characters.
|
||||
-- #include_next directive: it works as a #include, but will look
|
||||
for files only in the directories specified in the include path
|
||||
after the one the current file was found. This is a GNU-ism that
|
||||
is useful for writing transparent wrappers around header files.
|
||||
|
||||
Assertions and unicode are activated by specific flags; the #include_next
|
||||
support is always active.
|
||||
|
||||
The ucpp code itself should be compatible with any ISO-C90 compiler.
|
||||
The cpp.c file is rather big (~ 64kB), it might confuse old 16-bit C
|
||||
compilers; the macro.c file is somewhat large also (~ 47kB).
|
||||
|
||||
The evaluation of #if expressions is subject to some subtleties, see the
|
||||
section "cross-compilation".
|
||||
|
||||
The lexer code makes no assumption about the source character set, but
|
||||
the following: source characters (those which have a syntactic value in
|
||||
C; comment and string literal contents are not concerned) must have a
|
||||
strictly positive value that is strictly lower than MAX_CHAR_VAL. The
|
||||
strict positivity is already assured by the C standard, so you just need
|
||||
to adjust MAX_CHAR_VAL.
|
||||
|
||||
ucpp has been tested succesfully on ASCII/ISO-8859-1 and EBCDIC systems.
|
||||
Beware that UTF-8 is NOT compatible with EBCDIC.
|
||||
|
||||
Pragma handling: when used in non-lexer mode, ucpp tries to output a
|
||||
source text that, when read again, will yield the exact same stream of
|
||||
tokens. This is not completely true with regards to line numbering in
|
||||
some tricky macro replacements, but it should work correctly otherwise,
|
||||
especially with pragma directives if the compile-time option PRAGMA_DUMP
|
||||
was set: #pragma are dumped, non-void _Pragma() are converted to the
|
||||
corresponding #pragma and dumped also.
|
||||
|
||||
ucpp does not macro-replace the contents of #pragma and _Pragma();
|
||||
If you want a macro-replaced pragma, use this:
|
||||
|
||||
#define pragma_(x) _Pragma(#x)
|
||||
#define pragma(x) pragma_(x)
|
||||
|
||||
Anyway, pragmas do not nest (an _Pragma() cannot be evaluated if it is
|
||||
inside a #pragma or another _Pragma).
|
||||
|
||||
|
||||
I wrote ucpp according to what is found in "The C Programming Language"
|
||||
from Brian Kernighan and Dennis Ritchie (2nd edition) and the C99
|
||||
standard; but I could have misinterpreted some points. On some tricky
|
||||
points I got help from the helpful people from the comp.std.c newsgroup.
|
||||
For assertions and #include_next, I mimicked the behaviour of GNU cpp,
|
||||
as is stated in the GNU cpp info documentation. An open question is
|
||||
related to the following code:
|
||||
|
||||
#define undefined !
|
||||
#define makeun(x) un ## x
|
||||
#if makeun(defined foo)
|
||||
qux
|
||||
#else
|
||||
bar
|
||||
#endif
|
||||
|
||||
ucpp will replace 'defined foo' with 0 first (since foo is not defined),
|
||||
then it will replace the macro makeun, and the expression will become
|
||||
'un0', which is replaced by 0 since this is a remaining identifier. The
|
||||
expression evaluates to false, and 'bar' is emitted.
|
||||
However, some other preprocessors will replace makeun first, considering
|
||||
that it is not part of a 'defined' operator application; this will
|
||||
produce the macro 'undefined', which is replaced, and the expression
|
||||
becomes '!foo'. 'foo' is replaced by 0, the expression evaluates to
|
||||
true, and 'qux' is emitted.
|
||||
|
||||
My opinion is that the behaviour is undefined, because use of the
|
||||
'defined' operator does not match an allowed form prior to macro
|
||||
replacement (I mean, its syntax matches, but its use is reconverted
|
||||
to inexistant and therefore is not anymore matching). Other people
|
||||
think that the behaviour is well-specified, and contrary to what ucpp
|
||||
does. The only thing clear to me is that the wording of the standard
|
||||
(paragraph 6.10.1.3) is unclear.
|
||||
|
||||
Since the ucpp behaviour makes ucpp code simpler and cleaner, and
|
||||
that it is unlikely that any real-life code would ever be disturbed
|
||||
by that interpretation of the standard, ucpp will keep its current
|
||||
behaviour until convincing evidence of my misinterpretation of the
|
||||
standard is given to me. The problem can only occur if one uses ## to
|
||||
make a 'defined' operator disappear from a #if expression (everybody
|
||||
agrees that the generation of a 'defined' operator triggers undefined
|
||||
behaviour).
|
||||
|
||||
|
||||
Another point about macro replacement has been discussed at length in
|
||||
several occasions. It is about the following code:
|
||||
|
||||
#define CAT(a, b) CAT_(a, b)
|
||||
#define CAT_(a, b) a ## b
|
||||
#define AB(x, y) CAT(x, y)
|
||||
CAT(A, B)(X, Y)
|
||||
|
||||
ucpp will produce `CAT(X,Y)' as replacement for the last line, whereas
|
||||
some other preprocessors output `XY'. The answer to the question
|
||||
"which behaviour is correct" seems to be "this is not defined by the
|
||||
C standard". It is the answer that has been actually given by the C
|
||||
standardization committee in 1992, to the defect report #017, question
|
||||
23, which asked that very same question. Since the wording of the
|
||||
standard has not changed in these parts from the 1990 to the 1999
|
||||
version, the preprocessor behaviour on the above-stated code should
|
||||
still be considered as undefined.
|
||||
|
||||
It seems, however, that there used to be a time (around 1988) when the
|
||||
committee members agreed upon a precise macro-replacement algorithm,
|
||||
which specified quite clearly the preprocessor behaviour in such
|
||||
situation. ucpp behaviour is occasionnaly claimed as "incorrect" with
|
||||
regards to that algorithm. Since that macro replacement algorithm has
|
||||
never been published, and the committee itself backed out from it in
|
||||
1992, I decided to disregard those feeble claims.
|
||||
|
||||
It is possible, however, that at some point in the future I rewrite the
|
||||
ucpp macro replacement code, since that code is a bit messy and might be
|
||||
made to use less memory in some occasions. It is then possible that, in
|
||||
the aftermath of such a rewrite, the ucpp behaviour for the above stated
|
||||
code become tunable. Don't hold your breath, though.
|
||||
|
||||
|
||||
About _Pragma: the standard is not clear about when this operator is
|
||||
evaluated, and if it is allowed inside #if directives and such. For
|
||||
ucpp, I coded _Pragma as a special macro with lazy replacement: it will
|
||||
be evaluated wherever a macro could be replaced, and only at the end of
|
||||
the macro replacement (for practical purposes, _Pragma can be considered
|
||||
as a macro taking one argument, and being replaced by nothing, except
|
||||
for some tricky uses of the # and ## operators). This means that, by
|
||||
default, ucpp will evaluate _Pragma inside some directives (mainly, #if,
|
||||
#include, #include_next and #line), but it can be taught not to do so by
|
||||
defining NO_PRAGMA_IN_DIRECTIVE in tune.h.
|
||||
|
||||
|
||||
|
||||
CROSS-COMPILATION
|
||||
-----------------
|
||||
|
||||
If compiled with a C99 development suite, ucpp should be fully
|
||||
C99-compliant on the host platform (up to my own understanding of the
|
||||
standard -- remember that this software is distributed as-is, without
|
||||
any guarantee). However, if a pre-C99 compiler is used, or if the
|
||||
target machine is not the host machine (for instance when you build a
|
||||
cross-compiler), the evaluation of #if expressions is subject to some
|
||||
cross-compiling issues:
|
||||
|
||||
|
||||
-- character constants: when evaluating expressions, character constants
|
||||
are interpreted in the source character set context; this is allowed
|
||||
by the standard but this can lead to problems with code that expects
|
||||
this interpretation to match the one made in the C code. To ease
|
||||
cross-compilation, you can define a conversion array, and make the
|
||||
global variable transient_characters point to it. The array should
|
||||
contain 256 int; transient_characters[x] is the value of the character
|
||||
whose value is x in the source character set.
|
||||
|
||||
This facility is provided for inclusion of ucpp inside another code;
|
||||
if you want a stand-alone ucpp with that conversion, hard-code the
|
||||
conversion table into eval.c and make transient_characters[] statically
|
||||
point to it. Alternatively, you could provide an option syntax to
|
||||
provide such a table on command-line, if you feel like it.
|
||||
|
||||
|
||||
-- wide character constants signedness: by default, ucpp makes wide
|
||||
characters as signed as what plain chars are on the build host. To
|
||||
force wide character constant signedness, define WCHAR_SIGNEDNESS to 0
|
||||
(for unsigned) or 1 (for signed). Beware, however, that "native" wide
|
||||
character constants, even signed, are considered positive. Non-wide
|
||||
character constants are, according to the C99 standard, of type int, and
|
||||
therefore always signed.
|
||||
|
||||
|
||||
-- evaluation type: C90 states that all constants in #if expressions
|
||||
are considered as either long or unsigned long, and that the evaluation
|
||||
is performed with operands of that size. In C99, the situation is
|
||||
equivalent, except that the types used are intmax_t and uintmax_t, as
|
||||
defined in <stdint.h>.
|
||||
|
||||
ucpp can use two expression evaluators: one uses native integer types
|
||||
(one signed and one unsigned), the other evaluator emulates big integer
|
||||
numbers by representing them with two values of some unsigned type. The
|
||||
emulated type handles signed values in two's complement representation,
|
||||
and can be any width ranging from 2 bits to twice the size of the
|
||||
underlying native unsigned type used. An odd width is allowed. When
|
||||
right shifting an emulated signed negative value, it is left-padded with
|
||||
bits set to 1 (this is sign extension).
|
||||
|
||||
When the ARITHMETIC_CHECKS macro is defined in tune.h, all occurrences
|
||||
of implementation-defined or undefined behaviour during arithmetic
|
||||
evaluation are reported as errors or warned upon. This includes all
|
||||
overflows and underflows on signed quantities, constants too large,
|
||||
and so on. Errors (which terminate immediately evaluation) are emitted
|
||||
for division by 0 (on / and % operators) and overflow (on / operator);
|
||||
otherwise, warnings are emitted and the faulty evaluation takes place.
|
||||
This prevents ucpp from crashing on typical x86 machines, while still
|
||||
allowing to use some extensions.
|
||||
|
||||
|
||||
|
||||
FUTURE EVOLUTIONS
|
||||
-----------------
|
||||
|
||||
ucpp is quite complete now. There was a longstanding project of
|
||||
"traditional" preprocessing, but I dropped it because it would not
|
||||
map cleanly on the token-based ucpp structure. Maybe I will code a
|
||||
string-based preprocessor one day; it would certainly use some of the
|
||||
code from lexer.c, eval.c, mem.c and nhash.c. However, making such a
|
||||
tool is almost irrelevant nowadays. If one wants to handle such project,
|
||||
using ucpp as code base, I would happily provide some help, if needed.
|
||||
|
||||
|
||||
|
||||
CHANGES
|
||||
-------
|
||||
|
||||
From 1.2 to 1.3:
|
||||
|
||||
* brand new integer evaluation code, with precise evaluation and checks
|
||||
* new hash table implementation, with binary trees
|
||||
* relaxed attitude on failed `##' operators
|
||||
* bugfix on macro definition on command-line wrt nesting macros
|
||||
* support for up to 32766 macro arguments in LOW_MEM code
|
||||
* support for optional additional "identifier" characters such as '$' or '@'
|
||||
* bugfix: memory leak on void #assert
|
||||
|
||||
From 1.1 to 1.2:
|
||||
|
||||
* bugfix: numerous memory leaks
|
||||
* new function: wipeout(); this should release all malloc() blocks
|
||||
* bugfix: missing "newline" and trailing "context" tokens
|
||||
* improved included files name caching
|
||||
* included memory leak detection code
|
||||
|
||||
From 1.0 to 1.1:
|
||||
|
||||
* bugfix: missing newline when exiting from a non-newline-terminated file
|
||||
* bugfix: crash when resetting due to definition of the _Pragma pseudo-macro
|
||||
* bugfix: handling of additional "optional" whitespace with SEMPER_FIDELIS
|
||||
* improved handling of unreplaced arg macros wrt output line
|
||||
* tricky handling of utterly tricky #include
|
||||
* bugfix: spurious token `~=' eliminated
|
||||
|
||||
From 0.9 to 1.0:
|
||||
|
||||
* bugfix: crash after erroneous #assert
|
||||
* changed ERR_SHARP to FAIL_SHARP, EMUL_UINTMAX to SIMUL_UINTMAX
|
||||
* made "inline" default on gcc and DEC ccc (Linux/Alpha)
|
||||
* semantic of -I is now Unix-like (added directories are looked first)
|
||||
* added -J flag (to add include directories after the system ones)
|
||||
* cleaned up non-ascii issues
|
||||
* bugfix: missing brace in no-LOW_MEM code
|
||||
* bugfix: argument number check in variadic macros
|
||||
* bugfix: crash in non-lexer mode after some cases of unreplaced macro
|
||||
* bugfix: _Pragma() handling wrt # and ##
|
||||
* made evaluation of _Pragma() optional in #if, #include and #line
|
||||
* bugfix: re-dump of multiline #pragma
|
||||
* added the inmacro and macro_count flags
|
||||
* added mmap() support
|
||||
* added option to retain whitespace content in lexer mode
|
||||
|
||||
From 0.8 to 0.9:
|
||||
|
||||
* added check for division by 0 in #if evaluation
|
||||
* added check for non-standard line numbers
|
||||
* added check for trailing garbage in most directives
|
||||
* corrected signedness of char constants (always int, therefore always signed)
|
||||
* made LOW_MEM code, so that ucpp runs smoothly on low memory architectures
|
||||
* multiple bugfixes (using the GNU cpp testsuite)
|
||||
* added handling of _Pragma (as a macro)
|
||||
* added tokenization of pragma directives
|
||||
* added conservation of pragma directives in text output
|
||||
* produced Msdos 16-bit small memory model executable
|
||||
* produced Minix-86 executable
|
||||
|
||||
From 0.7 to 0.8:
|
||||
|
||||
* added some support for Amiga systems
|
||||
* fixed extra spacing in stringified tokens
|
||||
* fixed bug related to %:% and tolerated rogue sharps
|
||||
* namespace cleanup
|
||||
* bugfix for macro redefinition
|
||||
* added warning for evaluated comma operators in #if (ISO requirement)
|
||||
* -Dfoo now defines foo with content 1 (and not void content)
|
||||
* trigraphs can be disabled (for incorrect but legacy code)
|
||||
* fixed semantics for #include "file" (local directory)
|
||||
* fixed detection of protected files
|
||||
* produced a Msdos 16-bit executable
|
||||
|
||||
From 0.6 to 0.7:
|
||||
|
||||
* officially changed the goal to full C99 compliance
|
||||
* added the CONTEXT token and let NEWLINE tokens go
|
||||
* added report_context() for error reporting
|
||||
* enforced matching of #if/#endif (file-global nesting level = 0)
|
||||
* added support of C99 digraphs
|
||||
* added UTF-8 encoding support
|
||||
* added universal character names
|
||||
* rewrote #if expressions (sizes fixed, bignum, signed/unsigned fixed)
|
||||
* fixed incomplete evaluation of #if expressions
|
||||
* added transient_characters[]
|
||||
|
||||
From 0.5 to 0.6:
|
||||
|
||||
* disappearance of error_nonl()
|
||||
* added extra optional warnings for trigraphs
|
||||
* some bugfixes, especially in lexer mode
|
||||
* handled MacIntosh files correctly
|
||||
|
||||
From 0.4 to 0.5:
|
||||
|
||||
* nicer #pragma handling (a token can be emitted)
|
||||
* bugfix in lexer mode after #line and #error
|
||||
* sample.c an example of code linked with ucpp
|
||||
* made #if expressions conforming to standard signed/unsigned handling
|
||||
* added the copy_line[] buffer feature
|
||||
|
||||
From 0.3 to 0.4:
|
||||
|
||||
* relaxed interpretation of '#include foo' when foo ends up, after macro
|
||||
substitution, with a '<bar>' content
|
||||
* corrected the 'double-dot' bug
|
||||
* corrected two bugs related to the treatment of macro aborted calls (due
|
||||
to lack of arguments)
|
||||
* some namespaces cleanup, to ease integration into other code
|
||||
* documented the way to include ucpp into another program
|
||||
* made newlines embedded into strings illegal (and reported as such)
|
||||
|
||||
From 0.2 to 0.3:
|
||||
|
||||
* added support for system predefined macros
|
||||
* made several bugfixes
|
||||
* checked C99 compliance for most of the features
|
||||
* ucpp now accepts non-C characters on standard when used stand-alone
|
||||
* removed many useless spaces in the output
|
||||
|
||||
From 0.1 to 0.2:
|
||||
|
||||
* added support for assertions
|
||||
* added support for macros with variable arguments
|
||||
* split the pharaonic cpp.c file into many
|
||||
* made several bugfixes
|
||||
* relaxed the behaviour with regards to the void arguments
|
||||
* made C++-like comments an option
|
||||
|
||||
|
||||
|
||||
THANKS TO
|
||||
---------
|
||||
|
||||
Volker Barthelmann, Neil Booth, Stephen Davies, Stéphane Ecolivet,
|
||||
Marc Espie, Marcus Holland-Moritz, Antoine Leca, Cyrille Lefevre,
|
||||
Dave Rivers, Loic Tortay and Laurent Wacrenier, for suggestions and
|
||||
beta-testing.
|
||||
|
||||
Paul Eggert, Douglas A. Gwyn, Clive D.W. Feather, and the other guys from
|
||||
comp.std.c, for explanations about the standard.
|
||||
|
||||
Dave Brolley, Jamie Lokier and Neil Booth, for discussion about tricky
|
||||
points on nesting macros.
|
||||
|
||||
Brian Kernighan and Dennis Ritchie, for bringing C to mortal Men.
|
1462
app/xrdb-cpp/arith.c
Normal file
1462
app/xrdb-cpp/arith.c
Normal file
File diff suppressed because it is too large
Load Diff
255
app/xrdb-cpp/arith.h
Normal file
255
app/xrdb-cpp/arith.h
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
* Integer arithmetic evaluation, header file.
|
||||
*
|
||||
* (c) Thomas Pornin 2002
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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 arithmetic evaluator uses two files: this header file (arith.h)
|
||||
* and the source file (arith.c). To use this code, the source file should
|
||||
* be included from another .c file which defines some macros (see below).
|
||||
* Then the functions defined in the arith.c file become available to the
|
||||
* including source file. If those functions are defined with external
|
||||
* linkage (that is, `ARITH_FUNCTION_HEADER' does not contain `static'),
|
||||
* it is possible for other source files to use the arithmetic functions
|
||||
* by including the arith.h header only. The source file which includes
|
||||
* arith.c should *not* include arith.h.
|
||||
*
|
||||
* If the #include is for arith.h, the following macros should be
|
||||
* defined:
|
||||
*
|
||||
* -- If the evaluator is supposed to use a native type:
|
||||
* NATIVE_SIGNED the native signed integer type
|
||||
* NATIVE_UNSIGNED the native unsigned integer type
|
||||
*
|
||||
* -- If the evaluator is supposed to use an emulated type:
|
||||
* SIMUL_ARITH_SUBTYPE the native unsigned type used for the simulation
|
||||
* SIMUL_SUBTYPE_BITS the native unsigned type size
|
||||
* SIMUL_NUMBITS the emulated type size
|
||||
*
|
||||
* -- For both cases:
|
||||
* ARITH_TYPENAME the central arithmetic type name
|
||||
* ARITH_FUNCTION_HEADER the qualifiers to add to function definitions
|
||||
*
|
||||
* The presence (respectively absence) of the NATIVE_SIGNED macro triggers
|
||||
* the use of the native type evaluator (respectively simulated type
|
||||
* evaluator).
|
||||
*
|
||||
* If the #include is for arith.c, the macros for arith.h should be defined,
|
||||
* and the following should be defined as well:
|
||||
*
|
||||
* -- If the evaluator is supposed to use a native type:
|
||||
* NATIVE_UNSIGNED_BITS the native unsigned type size
|
||||
* NATIVE_SIGNED_MIN the native signed minimum value
|
||||
* NATIVE_SIGNED_MAX the native signed maximum value
|
||||
* (the last two macros must evaluate to signed constant expressions)
|
||||
*
|
||||
* -- For both cases:
|
||||
* ARITH_WARNING(type) code to perform on warning
|
||||
* ARITH_ERROR(type) code to perform on error
|
||||
*
|
||||
* The macro ARITH_WARNING() and ARITH_ERROR() are invoked with a
|
||||
* numerical argument which is one of the enumeration constants
|
||||
* defined below (ARITH_EXCEP_*) that identifies the specific problem.
|
||||
*
|
||||
* If the #include is for arith.c, the macro ARITHMETIC_CHECKS may be
|
||||
* defined. When this macro is defined, checks are performed so that all
|
||||
* operation which would lead to undefined or implementation-defined
|
||||
* behaviour are first reported through ARITH_WARNING(). Code is smaller
|
||||
* and faster without these checks, of course. Regardless of the status
|
||||
* of that macro, divisions by 0 and overflows on signed division are
|
||||
* reported as errors through ARITH_ERROR().
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ARITH_H__
|
||||
#define ARITH_H__
|
||||
|
||||
enum {
|
||||
/* Warnings */
|
||||
ARITH_EXCEP_CONV_O, /* overflow on conversion */
|
||||
ARITH_EXCEP_NEG_O, /* overflow on unary minus */
|
||||
ARITH_EXCEP_NOT_T, /* trap representation on bitwise inversion */
|
||||
ARITH_EXCEP_PLUS_O, /* overflow on addition */
|
||||
ARITH_EXCEP_PLUS_U, /* underflow on addition */
|
||||
ARITH_EXCEP_MINUS_O, /* overflow on subtraction */
|
||||
ARITH_EXCEP_MINUS_U, /* underflow on subtraction */
|
||||
ARITH_EXCEP_AND_T, /* trap representation on bitwise and */
|
||||
ARITH_EXCEP_XOR_T, /* trap representation on bitwise xor */
|
||||
ARITH_EXCEP_OR_T, /* trap representation on bitwise or */
|
||||
ARITH_EXCEP_LSH_W, /* left shift by type width or more */
|
||||
ARITH_EXCEP_LSH_C, /* left shift by negative count */
|
||||
ARITH_EXCEP_LSH_O, /* overflow on left shift */
|
||||
ARITH_EXCEP_LSH_U, /* underflow on left shift */
|
||||
ARITH_EXCEP_RSH_W, /* right shift by type width or more */
|
||||
ARITH_EXCEP_RSH_C, /* right shift by negative count */
|
||||
ARITH_EXCEP_RSH_N, /* right shift of negative value */
|
||||
ARITH_EXCEP_STAR_O, /* overflow on multiplication */
|
||||
ARITH_EXCEP_STAR_U, /* underflow on multiplication */
|
||||
|
||||
/* Errors */
|
||||
ARITH_EXCEP_SLASH_D, /* division by 0 */
|
||||
ARITH_EXCEP_SLASH_O, /* overflow on division */
|
||||
ARITH_EXCEP_PCT_D, /* division by 0 on modulus operator */
|
||||
ARITH_EXCEP_CONST_O /* constant too large */
|
||||
};
|
||||
|
||||
#define arith_strc_(x, y) x ## y
|
||||
#define arith_strc(x, y) arith_strc_(x, y)
|
||||
|
||||
#define arith_u arith_strc(u_, ARITH_TYPENAME)
|
||||
#define arith_s arith_strc(s_, ARITH_TYPENAME)
|
||||
#define arith_op_u(op) arith_strc(ARITH_TYPENAME, arith_strc(_u_, op))
|
||||
#define arith_op_s(op) arith_strc(ARITH_TYPENAME, arith_strc(_s_, op))
|
||||
|
||||
#define ARITH_DECL_MONO_U_U(op) ARITH_FUNCTION_HEADER arith_u \
|
||||
arith_op_u(op)(arith_u x)
|
||||
#define ARITH_DECL_MONO_U_S(op) ARITH_FUNCTION_HEADER arith_s \
|
||||
arith_op_u(op)(arith_u x)
|
||||
#define ARITH_DECL_MONO_U_I(op) ARITH_FUNCTION_HEADER int \
|
||||
arith_op_u(op)(arith_u x)
|
||||
#define ARITH_DECL_MONO_U_L(op) ARITH_FUNCTION_HEADER unsigned long \
|
||||
arith_op_u(op)(arith_u x)
|
||||
#define ARITH_DECL_MONO_S_U(op) ARITH_FUNCTION_HEADER arith_u \
|
||||
arith_op_s(op)(arith_s x)
|
||||
#define ARITH_DECL_MONO_S_S(op) ARITH_FUNCTION_HEADER arith_s \
|
||||
arith_op_s(op)(arith_s x)
|
||||
#define ARITH_DECL_MONO_S_I(op) ARITH_FUNCTION_HEADER int \
|
||||
arith_op_s(op)(arith_s x)
|
||||
#define ARITH_DECL_MONO_S_L(op) ARITH_FUNCTION_HEADER long \
|
||||
arith_op_s(op)(arith_s x)
|
||||
#define ARITH_DECL_MONO_I_U(op) ARITH_FUNCTION_HEADER arith_u \
|
||||
arith_op_u(op)(int x)
|
||||
#define ARITH_DECL_MONO_L_U(op) ARITH_FUNCTION_HEADER arith_u \
|
||||
arith_op_u(op)(unsigned long x)
|
||||
#define ARITH_DECL_MONO_I_S(op) ARITH_FUNCTION_HEADER arith_s \
|
||||
arith_op_s(op)(int x)
|
||||
#define ARITH_DECL_MONO_L_S(op) ARITH_FUNCTION_HEADER arith_s \
|
||||
arith_op_s(op)(long x)
|
||||
#define ARITH_DECL_MONO_ST_US(op) ARITH_FUNCTION_HEADER char *arith_op_u(op) \
|
||||
(char *c, arith_u *ru, arith_s *rs, int *sp)
|
||||
|
||||
#define ARITH_DECL_BI_UU_U(op) ARITH_FUNCTION_HEADER arith_u \
|
||||
arith_op_u(op)(arith_u x, arith_u y)
|
||||
#define ARITH_DECL_BI_UI_U(op) ARITH_FUNCTION_HEADER arith_u \
|
||||
arith_op_u(op)(arith_u x, int y)
|
||||
#define ARITH_DECL_BI_UU_I(op) ARITH_FUNCTION_HEADER int \
|
||||
arith_op_u(op)(arith_u x, arith_u y)
|
||||
#define ARITH_DECL_BI_SS_S(op) ARITH_FUNCTION_HEADER arith_s \
|
||||
arith_op_s(op)(arith_s x, arith_s y)
|
||||
#define ARITH_DECL_BI_SI_S(op) ARITH_FUNCTION_HEADER arith_s \
|
||||
arith_op_s(op)(arith_s x, int y)
|
||||
#define ARITH_DECL_BI_SS_I(op) ARITH_FUNCTION_HEADER int \
|
||||
arith_op_s(op)(arith_s x, arith_s y)
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NATIVE_SIGNED
|
||||
|
||||
typedef NATIVE_SIGNED arith_s;
|
||||
typedef NATIVE_UNSIGNED arith_u;
|
||||
|
||||
#else
|
||||
|
||||
#if SIMUL_NUMBITS > (2 * SIMUL_SUBTYPE_BITS)
|
||||
#error Native subtype too small for arithmetic simulation.
|
||||
#endif
|
||||
|
||||
#define SIMUL_MSW_WIDTH (SIMUL_NUMBITS / 2)
|
||||
#define SIMUL_LSW_WIDTH ((SIMUL_NUMBITS + 1) / 2)
|
||||
|
||||
typedef struct {
|
||||
SIMUL_ARITH_SUBTYPE msw, lsw;
|
||||
} arith_u, arith_s;
|
||||
|
||||
#endif
|
||||
|
||||
/* functions with the unsigned type */
|
||||
|
||||
ARITH_DECL_MONO_S_U(to_u);
|
||||
ARITH_DECL_MONO_I_U(fromint);
|
||||
ARITH_DECL_MONO_L_U(fromulong);
|
||||
ARITH_DECL_MONO_U_I(toint);
|
||||
ARITH_DECL_MONO_U_L(toulong);
|
||||
|
||||
ARITH_DECL_MONO_U_U(neg);
|
||||
ARITH_DECL_MONO_U_U(not);
|
||||
ARITH_DECL_MONO_U_I(lnot);
|
||||
ARITH_DECL_MONO_U_I(lval);
|
||||
|
||||
ARITH_DECL_BI_UU_U(plus);
|
||||
ARITH_DECL_BI_UU_U(minus);
|
||||
ARITH_DECL_BI_UI_U(lsh);
|
||||
ARITH_DECL_BI_UI_U(rsh);
|
||||
ARITH_DECL_BI_UU_I(lt);
|
||||
ARITH_DECL_BI_UU_I(leq);
|
||||
ARITH_DECL_BI_UU_I(gt);
|
||||
ARITH_DECL_BI_UU_I(geq);
|
||||
ARITH_DECL_BI_UU_I(same);
|
||||
ARITH_DECL_BI_UU_I(neq);
|
||||
ARITH_DECL_BI_UU_U(and);
|
||||
ARITH_DECL_BI_UU_U(xor);
|
||||
ARITH_DECL_BI_UU_U(or);
|
||||
ARITH_DECL_BI_UU_U(star);
|
||||
ARITH_DECL_BI_UU_U(slash);
|
||||
ARITH_DECL_BI_UU_U(pct);
|
||||
|
||||
/* functions with the signed type */
|
||||
|
||||
ARITH_DECL_MONO_U_S(to_s);
|
||||
ARITH_DECL_MONO_I_S(fromint);
|
||||
ARITH_DECL_MONO_L_S(fromlong);
|
||||
ARITH_DECL_MONO_S_I(toint);
|
||||
ARITH_DECL_MONO_S_L(tolong);
|
||||
|
||||
ARITH_DECL_MONO_S_S(neg);
|
||||
ARITH_DECL_MONO_S_S(not);
|
||||
ARITH_DECL_MONO_S_I(lnot);
|
||||
ARITH_DECL_MONO_S_I(lval);
|
||||
|
||||
ARITH_DECL_BI_SS_S(plus);
|
||||
ARITH_DECL_BI_SS_S(minus);
|
||||
ARITH_DECL_BI_SI_S(lsh);
|
||||
ARITH_DECL_BI_SI_S(rsh);
|
||||
ARITH_DECL_BI_SS_I(lt);
|
||||
ARITH_DECL_BI_SS_I(leq);
|
||||
ARITH_DECL_BI_SS_I(gt);
|
||||
ARITH_DECL_BI_SS_I(geq);
|
||||
ARITH_DECL_BI_SS_I(same);
|
||||
ARITH_DECL_BI_SS_I(neq);
|
||||
ARITH_DECL_BI_SS_S(and);
|
||||
ARITH_DECL_BI_SS_S(xor);
|
||||
ARITH_DECL_BI_SS_S(or);
|
||||
ARITH_DECL_BI_SS_S(star);
|
||||
ARITH_DECL_BI_SS_S(slash);
|
||||
ARITH_DECL_BI_SS_S(pct);
|
||||
|
||||
/* conversions from string */
|
||||
ARITH_DECL_MONO_ST_US(octconst);
|
||||
ARITH_DECL_MONO_ST_US(hexconst);
|
||||
ARITH_DECL_MONO_ST_US(decconst);
|
420
app/xrdb-cpp/assert.c
Normal file
420
app/xrdb-cpp/assert.c
Normal file
@ -0,0 +1,420 @@
|
||||
/*
|
||||
* (c) Thomas Pornin 1999 - 2002
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tune.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <time.h>
|
||||
#include "ucppi.h"
|
||||
#include "mem.h"
|
||||
#include "nhash.h"
|
||||
|
||||
/*
|
||||
* Assertion support. Each assertion is indexed by its predicate, and
|
||||
* the list of 'questions' which yield a true answer.
|
||||
*/
|
||||
|
||||
static HTT assertions;
|
||||
static int assertions_init_done = 0;
|
||||
|
||||
static struct assert *new_assertion(void)
|
||||
{
|
||||
struct assert *a = getmem(sizeof(struct assert));
|
||||
|
||||
a->nbval = 0;
|
||||
return a;
|
||||
}
|
||||
|
||||
static void del_token_fifo(struct token_fifo *tf)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < tf->nt; i ++)
|
||||
if (S_TOKEN(tf->t[i].type)) freemem(tf->t[i].name);
|
||||
if (tf->nt) freemem(tf->t);
|
||||
}
|
||||
|
||||
static void del_assertion(void *va)
|
||||
{
|
||||
struct assert *a = va;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < a->nbval; i ++) del_token_fifo(a->val + i);
|
||||
if (a->nbval) freemem(a->val);
|
||||
freemem(a);
|
||||
}
|
||||
|
||||
/*
|
||||
* print the contents of a token list
|
||||
*/
|
||||
static void print_token_fifo(struct token_fifo *tf)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < tf->nt; i ++)
|
||||
if (ttMWS(tf->t[i].type)) fputc(' ', emit_output);
|
||||
else fputs(token_name(tf->t + i), emit_output);
|
||||
}
|
||||
|
||||
/*
|
||||
* print all assertions related to a given name
|
||||
*/
|
||||
static void print_assert(void *va)
|
||||
{
|
||||
struct assert *a = va;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < a->nbval; i ++) {
|
||||
fprintf(emit_output, "#assert %s(", HASH_ITEM_NAME(a));
|
||||
print_token_fifo(a->val + i);
|
||||
fprintf(emit_output, ")\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* compare two token_fifo, return 0 if they are identical, 1 otherwise.
|
||||
* All whitespace tokens are considered identical, but sequences of
|
||||
* whitespace are not shrinked.
|
||||
*/
|
||||
int cmp_token_list(struct token_fifo *f1, struct token_fifo *f2)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (f1->nt != f2->nt) return 1;
|
||||
for (i = 0; i < f1->nt; i ++) {
|
||||
if (ttMWS(f1->t[i].type) && ttMWS(f2->t[i].type)) continue;
|
||||
if (f1->t[i].type != f2->t[i].type) return 1;
|
||||
if (f1->t[i].type == MACROARG
|
||||
&& f1->t[i].line != f2->t[i].line) return 1;
|
||||
if (S_TOKEN(f1->t[i].type)
|
||||
&& strcmp(f1->t[i].name, f2->t[i].name)) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* for #assert
|
||||
* Assertions are not part of the ISO-C89 standard, but they are sometimes
|
||||
* encountered, for instance in Solaris standard include files.
|
||||
*/
|
||||
int handle_assert(struct lexer_state *ls)
|
||||
{
|
||||
int ina = 0, ltww;
|
||||
struct token t;
|
||||
struct token_fifo *atl = 0;
|
||||
struct assert *a;
|
||||
char *aname;
|
||||
int ret = -1;
|
||||
long l = ls->line;
|
||||
int nnp;
|
||||
size_t i;
|
||||
|
||||
while (!next_token(ls)) {
|
||||
if (ls->ctok->type == NEWLINE) break;
|
||||
if (ttMWS(ls->ctok->type)) continue;
|
||||
if (ls->ctok->type == NAME) {
|
||||
if (!(a = HTT_get(&assertions, ls->ctok->name))) {
|
||||
a = new_assertion();
|
||||
aname = sdup(ls->ctok->name);
|
||||
ina = 1;
|
||||
}
|
||||
goto handle_assert_next;
|
||||
}
|
||||
error(l, "illegal assertion name for #assert");
|
||||
goto handle_assert_warp_ign;
|
||||
}
|
||||
goto handle_assert_trunc;
|
||||
|
||||
handle_assert_next:
|
||||
while (!next_token(ls)) {
|
||||
if (ls->ctok->type == NEWLINE) break;
|
||||
if (ttMWS(ls->ctok->type)) continue;
|
||||
if (ls->ctok->type != LPAR) {
|
||||
error(l, "syntax error in #assert");
|
||||
goto handle_assert_warp_ign;
|
||||
}
|
||||
goto handle_assert_next2;
|
||||
}
|
||||
goto handle_assert_trunc;
|
||||
|
||||
handle_assert_next2:
|
||||
atl = getmem(sizeof(struct token_fifo));
|
||||
atl->art = atl->nt = 0;
|
||||
for (nnp = 1, ltww = 1; nnp && !next_token(ls);) {
|
||||
if (ls->ctok->type == NEWLINE) break;
|
||||
if (ltww && ttMWS(ls->ctok->type)) continue;
|
||||
ltww = ttMWS(ls->ctok->type);
|
||||
if (ls->ctok->type == LPAR) nnp ++;
|
||||
else if (ls->ctok->type == RPAR) {
|
||||
if (!(-- nnp)) goto handle_assert_next3;
|
||||
}
|
||||
t.type = ls->ctok->type;
|
||||
if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
|
||||
aol(atl->t, atl->nt, t, TOKEN_LIST_MEMG);
|
||||
}
|
||||
goto handle_assert_trunc;
|
||||
|
||||
handle_assert_next3:
|
||||
while (!next_token(ls) && ls->ctok->type != NEWLINE) {
|
||||
if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
|
||||
warning(l, "trailing garbage in #assert");
|
||||
}
|
||||
}
|
||||
if (atl->nt && ttMWS(atl->t[atl->nt - 1].type) && (-- atl->nt) == 0)
|
||||
freemem(atl->t);
|
||||
if (atl->nt == 0) {
|
||||
error(l, "void assertion in #assert");
|
||||
goto handle_assert_error;
|
||||
}
|
||||
for (i = 0; i < a->nbval && cmp_token_list(atl, a->val + i); i ++);
|
||||
if (i != a->nbval) {
|
||||
/* we already have it */
|
||||
ret = 0;
|
||||
goto handle_assert_error;
|
||||
}
|
||||
|
||||
/* This is a new assertion. Let's keep it. */
|
||||
aol(a->val, a->nbval, *atl, TOKEN_LIST_MEMG);
|
||||
if (ina) {
|
||||
HTT_put(&assertions, a, aname);
|
||||
freemem(aname);
|
||||
}
|
||||
if (emit_assertions) {
|
||||
fprintf(emit_output, "#assert %s(", HASH_ITEM_NAME(a));
|
||||
print_token_fifo(atl);
|
||||
fputs(")\n", emit_output);
|
||||
}
|
||||
freemem(atl);
|
||||
return 0;
|
||||
|
||||
handle_assert_trunc:
|
||||
error(l, "unfinished #assert");
|
||||
handle_assert_error:
|
||||
if (atl) {
|
||||
del_token_fifo(atl);
|
||||
freemem(atl);
|
||||
}
|
||||
if (ina) {
|
||||
freemem(aname);
|
||||
freemem(a);
|
||||
}
|
||||
return ret;
|
||||
handle_assert_warp_ign:
|
||||
while (!next_token(ls) && ls->ctok->type != NEWLINE);
|
||||
if (ina) {
|
||||
freemem(aname);
|
||||
freemem(a);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* for #unassert
|
||||
*/
|
||||
int handle_unassert(struct lexer_state *ls)
|
||||
{
|
||||
int ltww;
|
||||
struct token t;
|
||||
struct token_fifo atl;
|
||||
struct assert *a;
|
||||
int ret = -1;
|
||||
long l = ls->line;
|
||||
int nnp;
|
||||
size_t i;
|
||||
|
||||
atl.art = atl.nt = 0;
|
||||
while (!next_token(ls)) {
|
||||
if (ls->ctok->type == NEWLINE) break;
|
||||
if (ttMWS(ls->ctok->type)) continue;
|
||||
if (ls->ctok->type == NAME) {
|
||||
if (!(a = HTT_get(&assertions, ls->ctok->name))) {
|
||||
ret = 0;
|
||||
goto handle_unassert_warp;
|
||||
}
|
||||
goto handle_unassert_next;
|
||||
}
|
||||
error(l, "illegal assertion name for #unassert");
|
||||
goto handle_unassert_warp;
|
||||
}
|
||||
goto handle_unassert_trunc;
|
||||
|
||||
handle_unassert_next:
|
||||
while (!next_token(ls)) {
|
||||
if (ls->ctok->type == NEWLINE) break;
|
||||
if (ttMWS(ls->ctok->type)) continue;
|
||||
if (ls->ctok->type != LPAR) {
|
||||
error(l, "syntax error in #unassert");
|
||||
goto handle_unassert_warp;
|
||||
}
|
||||
goto handle_unassert_next2;
|
||||
}
|
||||
if (emit_assertions)
|
||||
fprintf(emit_output, "#unassert %s\n", HASH_ITEM_NAME(a));
|
||||
HTT_del(&assertions, HASH_ITEM_NAME(a));
|
||||
return 0;
|
||||
|
||||
handle_unassert_next2:
|
||||
for (nnp = 1, ltww = 1; nnp && !next_token(ls);) {
|
||||
if (ls->ctok->type == NEWLINE) break;
|
||||
if (ltww && ttMWS(ls->ctok->type)) continue;
|
||||
ltww = ttMWS(ls->ctok->type);
|
||||
if (ls->ctok->type == LPAR) nnp ++;
|
||||
else if (ls->ctok->type == RPAR) {
|
||||
if (!(-- nnp)) goto handle_unassert_next3;
|
||||
}
|
||||
t.type = ls->ctok->type;
|
||||
if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
|
||||
aol(atl.t, atl.nt, t, TOKEN_LIST_MEMG);
|
||||
}
|
||||
goto handle_unassert_trunc;
|
||||
|
||||
handle_unassert_next3:
|
||||
while (!next_token(ls) && ls->ctok->type != NEWLINE) {
|
||||
if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
|
||||
warning(l, "trailing garbage in #unassert");
|
||||
}
|
||||
}
|
||||
if (atl.nt && ttMWS(atl.t[atl.nt - 1].type) && (-- atl.nt) == 0)
|
||||
freemem(atl.t);
|
||||
if (atl.nt == 0) {
|
||||
error(l, "void assertion in #unassert");
|
||||
return ret;
|
||||
}
|
||||
for (i = 0; i < a->nbval && cmp_token_list(&atl, a->val + i); i ++);
|
||||
if (i != a->nbval) {
|
||||
/* we have it, undefine it */
|
||||
del_token_fifo(a->val + i);
|
||||
if (i < (a->nbval - 1))
|
||||
mmvwo(a->val + i, a->val + i + 1, (a->nbval - i - 1)
|
||||
* sizeof(struct token_fifo));
|
||||
if ((-- a->nbval) == 0) freemem(a->val);
|
||||
if (emit_assertions) {
|
||||
fprintf(emit_output, "#unassert %s(",
|
||||
HASH_ITEM_NAME(a));
|
||||
print_token_fifo(&atl);
|
||||
fputs(")\n", emit_output);
|
||||
}
|
||||
}
|
||||
ret = 0;
|
||||
goto handle_unassert_finish;
|
||||
|
||||
handle_unassert_trunc:
|
||||
error(l, "unfinished #unassert");
|
||||
handle_unassert_finish:
|
||||
if (atl.nt) del_token_fifo(&atl);
|
||||
return ret;
|
||||
handle_unassert_warp:
|
||||
while (!next_token(ls) && ls->ctok->type != NEWLINE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the given assertion (as string).
|
||||
*/
|
||||
int make_assertion(char *aval)
|
||||
{
|
||||
struct lexer_state lls;
|
||||
size_t n = strlen(aval) + 1;
|
||||
char *c = sdup(aval);
|
||||
int ret;
|
||||
|
||||
*(c + n - 1) = '\n';
|
||||
init_buf_lexer_state(&lls, 0);
|
||||
lls.flags = DEFAULT_LEXER_FLAGS;
|
||||
lls.input = 0;
|
||||
lls.input_string = (unsigned char *)c;
|
||||
lls.pbuf = 0;
|
||||
lls.ebuf = n;
|
||||
lls.line = -1;
|
||||
ret = handle_assert(&lls);
|
||||
freemem(c);
|
||||
free_lexer_state(&lls);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the given assertion (as string).
|
||||
*/
|
||||
int destroy_assertion(char *aval)
|
||||
{
|
||||
struct lexer_state lls;
|
||||
size_t n = strlen(aval) + 1;
|
||||
char *c = sdup(aval);
|
||||
int ret;
|
||||
|
||||
*(c + n - 1) = '\n';
|
||||
init_buf_lexer_state(&lls, 0);
|
||||
lls.flags = DEFAULT_LEXER_FLAGS;
|
||||
lls.input = 0;
|
||||
lls.input_string = (unsigned char *)c;
|
||||
lls.pbuf = 0;
|
||||
lls.ebuf = n;
|
||||
lls.line = -1;
|
||||
ret = handle_unassert(&lls);
|
||||
freemem(c);
|
||||
free_lexer_state(&lls);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* erase the assertion table
|
||||
*/
|
||||
void wipe_assertions(void)
|
||||
{
|
||||
if (assertions_init_done) HTT_kill(&assertions);
|
||||
assertions_init_done = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize the assertion table
|
||||
*/
|
||||
void init_assertions(void)
|
||||
{
|
||||
wipe_assertions();
|
||||
HTT_init(&assertions, del_assertion);
|
||||
assertions_init_done = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* retrieve an assertion from the hash table
|
||||
*/
|
||||
struct assert *get_assertion(char *name)
|
||||
{
|
||||
return HTT_get(&assertions, name);
|
||||
}
|
||||
|
||||
/*
|
||||
* print already defined assertions
|
||||
*/
|
||||
void print_assertions(void)
|
||||
{
|
||||
HTT_scan(&assertions, print_assert);
|
||||
}
|
236
app/xrdb-cpp/atest.c
Normal file
236
app/xrdb-cpp/atest.c
Normal file
@ -0,0 +1,236 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
#if defined TEST_NATIVE
|
||||
|
||||
#define NATIVE_SIGNED int
|
||||
#define NATIVE_UNSIGNED unsigned
|
||||
|
||||
#define NATIVE_UNSIGNED_BITS 32
|
||||
#define NATIVE_SIGNED_MIN LONG_MIN
|
||||
#define NATIVE_SIGNED_MAX LONG_MAX
|
||||
|
||||
#elif defined TEST_SIMUL
|
||||
|
||||
#define SIMUL_ARITH_SUBTYPE unsigned short
|
||||
#define SIMUL_SUBTYPE_BITS 16
|
||||
#define SIMUL_NUMBITS 31
|
||||
|
||||
#else
|
||||
|
||||
#error ====== Either TEST_NATIVE or TEST_SIMUL must be defined.
|
||||
|
||||
#endif
|
||||
|
||||
#define ARITH_TYPENAME zoinx
|
||||
#define ARITH_FUNCTION_HEADER static inline
|
||||
|
||||
#define ARITH_WARNING(type) z_warn(type)
|
||||
#define ARITH_ERROR(type) z_error(type)
|
||||
|
||||
void z_warn(int type);
|
||||
void z_error(int type);
|
||||
|
||||
#include "arith.c"
|
||||
|
||||
#if defined TEST_NATIVE
|
||||
|
||||
static inline u_zoinx unsigned_to_uz(unsigned x)
|
||||
{
|
||||
return (u_zoinx)x;
|
||||
}
|
||||
|
||||
static inline s_zoinx int_to_sz(int x)
|
||||
{
|
||||
return (s_zoinx)x;
|
||||
}
|
||||
|
||||
static inline void print_uz(u_zoinx x)
|
||||
{
|
||||
printf("%u", x);
|
||||
}
|
||||
|
||||
static inline void print_sz(s_zoinx x)
|
||||
{
|
||||
printf("%d", x);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static inline u_zoinx unsigned_to_uz(unsigned x)
|
||||
{
|
||||
u_zoinx v;
|
||||
v.msw = (x >> 16) & 0x7FFFU;
|
||||
v.lsw = x & 0xFFFFU;
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline s_zoinx int_to_sz(int x)
|
||||
{
|
||||
return unsigned_to_uz((unsigned)x);
|
||||
}
|
||||
|
||||
static inline void print_uz(u_zoinx x)
|
||||
{
|
||||
printf("%u", ((unsigned)(x.msw) << 16) + (unsigned)(x.lsw));
|
||||
}
|
||||
|
||||
static inline void print_sz(s_zoinx x)
|
||||
{
|
||||
if (x.msw & 0x4000U) {
|
||||
putchar('-');
|
||||
x = zoinx_u_neg(x);
|
||||
}
|
||||
print_uz(x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline void print_int(int x)
|
||||
{
|
||||
printf("%d", x);
|
||||
}
|
||||
|
||||
static jmp_buf jbuf;
|
||||
|
||||
void z_warn(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case ARITH_EXCEP_CONV_O:
|
||||
fputs("[overflow on conversion] ", stdout); break;
|
||||
case ARITH_EXCEP_NEG_O:
|
||||
fputs("[overflow on unary minus] ", stdout); break;
|
||||
case ARITH_EXCEP_NOT_T:
|
||||
fputs("[trap representation on bitwise inversion] ", stdout);
|
||||
break;
|
||||
case ARITH_EXCEP_PLUS_O:
|
||||
fputs("[overflow on addition] ", stdout); break;
|
||||
case ARITH_EXCEP_PLUS_U:
|
||||
fputs("[underflow on addition] ", stdout); break;
|
||||
case ARITH_EXCEP_MINUS_O:
|
||||
fputs("[overflow on subtraction] ", stdout); break;
|
||||
case ARITH_EXCEP_MINUS_U:
|
||||
fputs("[underflow on subtraction] ", stdout); break;
|
||||
case ARITH_EXCEP_AND_T:
|
||||
fputs("[trap representation on bitwise and] ", stdout); break;
|
||||
case ARITH_EXCEP_XOR_T:
|
||||
fputs("[trap representation on bitwise xor] ", stdout); break;
|
||||
case ARITH_EXCEP_OR_T:
|
||||
fputs("[trap representation on bitwise or] ", stdout); break;
|
||||
case ARITH_EXCEP_LSH_W:
|
||||
fputs("[left shift by type width or more] ", stdout); break;
|
||||
case ARITH_EXCEP_LSH_C:
|
||||
fputs("[left shift by negative count] ", stdout); break;
|
||||
case ARITH_EXCEP_LSH_O:
|
||||
fputs("[overflow on left shift] ", stdout); break;
|
||||
case ARITH_EXCEP_LSH_U:
|
||||
fputs("[underflow on left shift] ", stdout); break;
|
||||
case ARITH_EXCEP_RSH_W:
|
||||
fputs("[right shift by type width or more] ", stdout); break;
|
||||
case ARITH_EXCEP_RSH_C:
|
||||
fputs("[right shift by negative count] ", stdout); break;
|
||||
case ARITH_EXCEP_RSH_N:
|
||||
fputs("[right shift of negative value] ", stdout); break;
|
||||
case ARITH_EXCEP_STAR_O:
|
||||
fputs("[overflow on multiplication] ", stdout); break;
|
||||
case ARITH_EXCEP_STAR_U:
|
||||
fputs("[underflow on multiplication] ", stdout); break;
|
||||
default:
|
||||
fprintf(stdout, "UNKNOWN WARNING TYPE: %d\n", type);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void z_error(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case ARITH_EXCEP_SLASH_D:
|
||||
fputs("division by 0\n", stdout);
|
||||
break;
|
||||
case ARITH_EXCEP_SLASH_O:
|
||||
fputs("overflow on division\n", stdout);
|
||||
break;
|
||||
case ARITH_EXCEP_PCT_D:
|
||||
fputs("division by 0 on modulus operator\n", stdout);
|
||||
break;
|
||||
default:
|
||||
fprintf(stdout, "UNKNOWN ERROR TYPE: %d\n", type);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
longjmp(jbuf, 1);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
|
||||
#define OPTRY_GEN(op, x, y, convx, convy, printz) do { \
|
||||
printf("%s %s %s -> ", #x, #op, #y); \
|
||||
if (!setjmp(jbuf)) { \
|
||||
printz(zoinx_ ## op (convx(x), convy(y))); \
|
||||
putchar('\n'); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define IDENT(x) x
|
||||
|
||||
#define OPTRY_UU_U(op, x, y) \
|
||||
OPTRY_GEN(op, x, y, unsigned_to_uz, unsigned_to_uz, print_uz)
|
||||
|
||||
#define OPTRY_UI_U(op, x, y) \
|
||||
OPTRY_GEN(op, x, y, unsigned_to_uz, IDENT, print_uz)
|
||||
|
||||
#define OPTRY_UU_I(op, x, y) \
|
||||
OPTRY_GEN(op, x, y, unsigned_to_uz, unsigned_to_uz, print_int)
|
||||
|
||||
#define OPTRY_SS_S(op, x, y) \
|
||||
OPTRY_GEN(op, x, y, int_to_sz, int_to_sz, print_sz)
|
||||
|
||||
#define OPTRY_SI_S(op, x, y) \
|
||||
OPTRY_GEN(op, x, y, int_to_sz, IDENT, print_sz)
|
||||
|
||||
#define OPTRY_SS_I(op, x, y) \
|
||||
OPTRY_GEN(op, x, y, int_to_sz, int_to_sz, print_int)
|
||||
|
||||
OPTRY_UU_U(u_plus, 3, 4);
|
||||
OPTRY_UU_U(u_plus, 1549587182, 1790478233);
|
||||
OPTRY_UU_U(u_minus, 1549587182, 1790478233);
|
||||
OPTRY_UU_U(u_minus, 1790478233, 1549587182);
|
||||
OPTRY_UU_U(u_star, 432429875, 347785487);
|
||||
OPTRY_UU_U(u_slash, 432429875, 34487);
|
||||
OPTRY_UU_U(u_pct, 432429875, 34487);
|
||||
OPTRY_UI_U(u_lsh, 1783, 19);
|
||||
OPTRY_UI_U(u_lsh, 1783, 20);
|
||||
OPTRY_UI_U(u_lsh, 1783, 21);
|
||||
OPTRY_UI_U(u_rsh, 475902857, 7);
|
||||
OPTRY_UI_U(u_rsh, 475902857, 17);
|
||||
OPTRY_UI_U(u_rsh, 475902857, 38);
|
||||
|
||||
OPTRY_SS_S(s_plus, 3, 4);
|
||||
OPTRY_SS_S(s_plus, 1549587182, 1790478233);
|
||||
OPTRY_SS_S(s_plus, -1549587182, -1790478233);
|
||||
OPTRY_SS_S(s_minus, 1549587182, 1790478233);
|
||||
OPTRY_SS_S(s_minus, 1790478233, 1549587182);
|
||||
OPTRY_SS_S(s_minus, -1790478233, -1549587182);
|
||||
OPTRY_SS_S(s_minus, -1790478233, 1549587182);
|
||||
OPTRY_SS_S(s_star, 432429875, 347785487);
|
||||
OPTRY_SS_S(s_star, 432429875, -347785487);
|
||||
OPTRY_SS_S(s_slash, 432429875, 34487);
|
||||
OPTRY_SS_S(s_slash, -432429875, 34487);
|
||||
OPTRY_SS_S(s_slash, 432429875, -34487);
|
||||
OPTRY_SS_S(s_slash, -432429875, -34487);
|
||||
OPTRY_SS_S(s_slash, 432429875, 0);
|
||||
OPTRY_SS_S(s_slash, -2147483647 - 1, -1);
|
||||
OPTRY_SS_S(s_pct, 432429875, 34487);
|
||||
OPTRY_SS_S(s_pct, 432429875, 0);
|
||||
OPTRY_SI_S(s_lsh, -1, 10);
|
||||
OPTRY_SI_S(s_lsh, 1783, 19);
|
||||
OPTRY_SI_S(s_lsh, 1783, 20);
|
||||
OPTRY_SI_S(s_lsh, 1783, 21);
|
||||
OPTRY_SI_S(s_rsh, -1024, 8);
|
||||
OPTRY_SI_S(s_rsh, 475902857, 7);
|
||||
OPTRY_SI_S(s_rsh, 475902857, 17);
|
||||
|
||||
return 0;
|
||||
}
|
352
app/xrdb-cpp/config.h
Normal file
352
app/xrdb-cpp/config.h
Normal file
@ -0,0 +1,352 @@
|
||||
/*
|
||||
* (c) Thomas Pornin 1999 - 2002
|
||||
* (c) Louis P. Santillan 2011
|
||||
* This file is derived from tune.h
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* The LOW_MEM macro triggers the use of macro storage which uses less
|
||||
* memory. It actually also improves performance on large, modern machines
|
||||
* (due to less cache pressure). This option implies no limitation (except
|
||||
* on the number of arguments a macro may, which is then limited to 32766)
|
||||
* so it is on by default. Non-LOW_MEM code is considered deprecated.
|
||||
*/
|
||||
#define LOW_MEM
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Define AMIGA for systems using "drive letters" at the beginning of
|
||||
* some paths; define MSDOS on systems with drive letters and using
|
||||
* backslashes to seperate directory components.
|
||||
*/
|
||||
/* #define AMIGA */
|
||||
/* #define MSDOS */
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Define this if your compiler does not know the strftime() function;
|
||||
* TurboC 2.01 under Msdos does not know strftime().
|
||||
*/
|
||||
/* #define NOSTRFTIME */
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Buffering: there are two levels of buffering on input and output streams:
|
||||
* the standard libc buffering (manageable with setbuf() and setvbuf())
|
||||
* and some buffering provided by ucpp itself. The ucpp buffering uses
|
||||
* two buffers, of size respectively INPUT_BUF_MEMG and OUTPUT_BUF_MEMG
|
||||
* (as defined below).
|
||||
* You can disable one or both of these bufferings by defining the macros
|
||||
* NO_LIBC_BUF and NO_UCPP_BUF.
|
||||
*/
|
||||
/* #define NO_LIBC_BUF */
|
||||
/* #define NO_UCPP_BUF */
|
||||
|
||||
/*
|
||||
* On Unix stations, the system call mmap() might be used on input files.
|
||||
* This option is a subclause of ucpp internal buffering. On one station,
|
||||
* a 10% speed improvement was observed. Do not define this unless the
|
||||
* host architecture has the following characteristics:
|
||||
* -- Posix / Single Unix compliance
|
||||
* -- Text files correspond one to one with memory representation
|
||||
* If a file is not seekable or not mmapable, ucpp will revert to the
|
||||
* standard fread() solution.
|
||||
*
|
||||
* This feature is still considered beta quality. On some systems where
|
||||
* files can be bigger than memory address space (mainly, 32-bit systems
|
||||
* with files bigger than 4 GB), this option makes ucpp fail to operate
|
||||
* on those extremely large files.
|
||||
*/
|
||||
#define UCPP_MMAP
|
||||
|
||||
/*
|
||||
* Performance issues:
|
||||
* -- On memory-starved systems, such as Minix-i86, do not use ucpp
|
||||
* buffering; keep only libc buffering.
|
||||
* -- If you do not use libc buffering, activate the UCPP_MMAP option.
|
||||
* Note that the UCPP_MMAP option is ignored if ucpp buffering is not
|
||||
* activated.
|
||||
*
|
||||
* On an Athlon 1200 running FreeBSD 4.7, the best performances are
|
||||
* achieved when libc buffering is activated and/or UCPP_MMAP is on.
|
||||
*/
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Define this if you want ucpp to generate tokenized PRAGMA tokens;
|
||||
* otherwise, it will generate raw string contents. This setting is
|
||||
* irrelevant to the stand-alone version of ucpp.
|
||||
*/
|
||||
#define PRAGMA_TOKENIZE
|
||||
|
||||
/*
|
||||
* Define this to the special character that marks the end of tokens with
|
||||
* a string value inside a tokenized PRAGMA token. The #pragma and _Pragma()
|
||||
* directives which use this character will be a bit more difficult to
|
||||
* decode (but ucpp will not mind). 0 cannot be used. '\n' is fine because
|
||||
* it cannot appear inside a #pragma or _Pragma(), since newlines cannot be
|
||||
* embedded inside tokens, neither directly nor by macro substitution and
|
||||
* stringization. Besides, '\n' is portable.
|
||||
*/
|
||||
#define PRAGMA_TOKEN_END ((unsigned char)'\n')
|
||||
|
||||
/*
|
||||
* Define this if you want ucpp to include encountered #pragma directives
|
||||
* in its output in non-lexer mode; _Pragma() are translated to equivalent
|
||||
* #pragma directives.
|
||||
*/
|
||||
#define PRAGMA_DUMP
|
||||
|
||||
/*
|
||||
* According to my interpretation of the C99 standard, _Pragma() are
|
||||
* evaluated wherever macro expansion could take place. However, Neil Booth,
|
||||
* whose mother language is English (contrary to me) and who is well aware
|
||||
* of the C99 standard (and especially the C preprocessor) told me that
|
||||
* it was unclear whether _Pragma() are evaluated inside directives such
|
||||
* as #if, #include and #line. If you want to disable the evaluation of
|
||||
* _Pragma() inside such directives, define the following macro.
|
||||
*/
|
||||
/* #define NO_PRAGMA_IN_DIRECTIVE */
|
||||
|
||||
/*
|
||||
* The C99 standard mandates that the operator `##' must yield a single,
|
||||
* valid token, lest undefined behaviour befall upon thy head. Hence,
|
||||
* for instance, `+ ## +=' is forbidden, because `++=' is not a valid
|
||||
* token (although it is a valid list of two tokens, `++' and `=').
|
||||
* However, ucpp only emits a warning for such sin, and unmerges the
|
||||
* tokens (thus emitting `+' then `+=' for that example). When ucpp
|
||||
* produces text output, those two tokens will be separated by a space
|
||||
* character so that the basic rule of text output is preserved: when
|
||||
* parsed again, text output yields the exact same stream of tokens.
|
||||
* That extra space is virtual: it does not count as a true whitespace
|
||||
* token for stringization.
|
||||
*
|
||||
* However, it might be desirable, for some uses other than preprocessing
|
||||
* C source code, not to emit that extra space at all. To make ucpp behave
|
||||
* that way, define the DSHARP_TOKEN_MERGE macro. Please note that this
|
||||
* can trigger spurious token merging. For instance, with that macro
|
||||
* activated, `+ ## +=' will be output as `++=' which, if preprocessed
|
||||
* again, will read as `++' followed by `='.
|
||||
*
|
||||
* All this is irrelevant to lexer mode; and trying to merge incompatible
|
||||
* tokens is a shooting offence, anyway.
|
||||
*/
|
||||
/* #define DSHARP_TOKEN_MERGE */
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Define INMACRO_FLAG to include two flags to the structure lexer_state,
|
||||
* that tell whether tokens come from a macro-replacement, and count those
|
||||
* macro-replacements.
|
||||
*/
|
||||
/* #define INMACRO_FLAG */
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Paths where files are looked for by default, when #include is used.
|
||||
* Typical path is /usr/local/include and /usr/include, in that order.
|
||||
* If you want to set up no path, define the macro to 0.
|
||||
*
|
||||
* For Linux, get gcc includes too, or you will miss things like stddef.h.
|
||||
* The exact path varies much, depending on the distribution.
|
||||
*/
|
||||
#define STD_INCLUDE_PATH "/usr/local/include", "/usr/include"
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Arithmetic code for evaluation of #if expressions. Evaluation
|
||||
* uses either a native machine type, or an emulated two's complement
|
||||
* type. Division by 0 and overflow on division are considered as errors
|
||||
* and reported as such. If ARITHMETIC_CHECKS is defined, all other
|
||||
* operations that imply undefined or implementation-defined behaviour
|
||||
* are reported as warnings but otherwise performed nonetheless.
|
||||
*
|
||||
* For native type evaluation, the following macros should be defined:
|
||||
* NATIVE_SIGNED the native signed type
|
||||
* NATIVE_UNSIGNED the native corresponding unsigned type
|
||||
* NATIVE_UNSIGNED_BITS the native unsigned type width, in bits
|
||||
* NATIVE_SIGNED_MIN the native signed type minimum value
|
||||
* NATIVE_SIGNED_MAX the native signed type maximum value
|
||||
*
|
||||
* The code in the arith.c file performs some tricky detection
|
||||
* operations on the native type representation and possible existence
|
||||
* of a trap representation. These operations assume a C99-compliant
|
||||
* compiler; on a C90-only compiler, the operations are valid but may
|
||||
* yield incorrect results. You may force those settings with some
|
||||
* more macros: see the comments in arith.c (look for "ARCH_DEFINED").
|
||||
* Remember that this is mostly a non-issue, unless you are building
|
||||
* ucpp with a pre-C99 cross-compiler and either the host or target
|
||||
* architecture uses a non-two's complement representation of signed
|
||||
* integers. Such a combination is pretty rare nowadays, so the best
|
||||
* you can do is forgetting completely this paragraph and live in peace.
|
||||
*
|
||||
*
|
||||
* If you do not have a handy native type (for instance, you compile ucpp
|
||||
* with a C90 compiler which lacks the "long long" type, or you compile
|
||||
* ucpp for a cross-compiler which should support an evaluation integer
|
||||
* type of a size that is not available on the host machine), you may use
|
||||
* a simulated type. The type uses two's complement representation and
|
||||
* may have any width from 2 bits to twice the underlying native type
|
||||
* width, inclusive (odd widths are allowed). To use an emulated type,
|
||||
* make sure that NATIVE_SIGNED is not defined, and define the following
|
||||
* macros:
|
||||
* SIMUL_ARITH_SUBTYPE the native underlying type to use
|
||||
* SIMUL_SUBTYPE_BITS the native underlying type width
|
||||
* SIMUL_NUMBITS the emulated type width
|
||||
*
|
||||
* Undefined and implementation-defined behaviours are warned upon, if
|
||||
* ARITHMETIC_CHECKS is defined. Results are truncated to the type
|
||||
* width; shift count for the << and >> operators is reduced modulo the
|
||||
* emulatd type width; right shifting of a signed negative value performs
|
||||
* sign extension (the result is left-padded with bits set to 1).
|
||||
*/
|
||||
|
||||
/*
|
||||
* For native type evaluation with a 64-bit "long long" type.
|
||||
*/
|
||||
#define NATIVE_SIGNED long long
|
||||
#define NATIVE_UNSIGNED unsigned long long
|
||||
#define NATIVE_UNSIGNED_BITS 64
|
||||
#define NATIVE_SIGNED_MIN (-9223372036854775807LL - 1)
|
||||
#define NATIVE_SIGNED_MAX 9223372036854775807LL
|
||||
|
||||
/*
|
||||
* For emulation of a 64-bit type using a native 32-bit "unsigned long"
|
||||
* type.
|
||||
#undef NATIVE_SIGNED
|
||||
#define SIMUL_ARITH_SUBTYPE unsigned long
|
||||
#define SIMUL_SUBTYPE_BITS 32
|
||||
#define SIMUL_NUMBITS 64
|
||||
*/
|
||||
|
||||
/*
|
||||
* Comment out the following line if you want to deactivate arithmetic
|
||||
* checks (warnings upon undefined and implementation-defined
|
||||
* behaviour). Arithmetic checks slow down a bit arithmetic operations,
|
||||
* especially multiplications, but this should not be an issue with
|
||||
* typical C source code.
|
||||
*/
|
||||
#define ARITHMETIC_CHECKS
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* To force signedness of wide character constants, define WCHAR_SIGNEDNESS
|
||||
* to 0 for unsigned, 1 for signed. By default, wide character constants
|
||||
* are signed if the native `char' type is signed, and unsigned otherwise.
|
||||
#define WCHAR_SIGNEDNESS 0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Standard assertions. They should include one cpu() assertion, one machine()
|
||||
* assertion (identical to cpu()), and one or more system() assertions.
|
||||
*
|
||||
* for Linux/PC: cpu(i386), machine(i386), system(unix), system(linux)
|
||||
* for Linux/Alpha: cpu(alpha), machine(alpha), system(unix), system(linux)
|
||||
* for Sparc/Solaris: cpu(sparc), machine(sparc), system(unix), system(solaris)
|
||||
*
|
||||
* These are only suggestions. On Solaris, machine() should be defined
|
||||
* for i386 or sparc (standard system header use such an assertion). For
|
||||
* cross-compilation, define assertions related to the target architecture.
|
||||
*
|
||||
* If you want no standard assertion, define STD_ASSERT to 0.
|
||||
*/
|
||||
#define STD_ASSERT 0
|
||||
/*
|
||||
#define STD_ASSERT "cpu(i386)", "machine(i386)", "system(unix)", \
|
||||
"system(freebsd)"
|
||||
*/
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* System predefined macros. Nothing really mandatory, but some programs
|
||||
* might rely on those.
|
||||
* Each string must be either "name" or "name=token-list". If you want
|
||||
* no predefined macro, define STD_MACROS to 0.
|
||||
*/
|
||||
#define STD_MACROS 0
|
||||
/*
|
||||
#define STD_MACROS "__FreeBSD=4", "__unix", "__i386", \
|
||||
"__FreeBSD__=4", "__unix__", "__i386__"
|
||||
*/
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Default flags; HANDLE_ASSERTIONS is required for Solaris system headers.
|
||||
* See cpp.h for the definition of these flags.
|
||||
*/
|
||||
#define DEFAULT_CPP_FLAGS (DISCARD_COMMENTS | WARN_STANDARD \
|
||||
| WARN_PRAGMA | FAIL_SHARP | MACRO_VAARG \
|
||||
| CPLUSPLUS_COMMENTS | LINE_NUM | TEXT_OUTPUT \
|
||||
| KEEP_OUTPUT | HANDLE_TRIGRAPHS \
|
||||
| HANDLE_ASSERTIONS)
|
||||
#define DEFAULT_LEXER_FLAGS (DISCARD_COMMENTS | WARN_STANDARD | FAIL_SHARP \
|
||||
| MACRO_VAARG | CPLUSPLUS_COMMENTS | LEXER \
|
||||
| HANDLE_TRIGRAPHS | HANDLE_ASSERTIONS)
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Define this to use sigsetjmp()/siglongjmp() instead of setjmp()/longjmp().
|
||||
* This is non-ANSI, but it improves performance on some POSIX system.
|
||||
* On typical C source code, such improvement is completely negligeable.
|
||||
*/
|
||||
/* #define POSIX_JMP */
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Maximum value (plus one) of a character handled by the lexer; 128 is
|
||||
* alright for ASCII native source code, but 256 is needed for EBCDIC.
|
||||
* 256 is safe in both cases; you will have big problems if you set
|
||||
* this value to INT_MAX or above. On Minix-i86 or Msdos (small memory
|
||||
* model), define MAX_CHAR_VAL to 128.
|
||||
*
|
||||
* Set MAX_CHAR_VAL to a power of two to increase lexing speed. Beware
|
||||
* that lexer.c defines a static array of size MSTATE * MAX_CHAR_VAL
|
||||
* values of type int (MSTATE is defined in lexer.c and is about 40).
|
||||
*/
|
||||
#define MAX_CHAR_VAL 128
|
||||
|
||||
/*
|
||||
* If you want some extra character to be considered as whitespace,
|
||||
* define this macro to that space. On ISO-8859-1 machines, 160 is
|
||||
* the code for the unbreakable space.
|
||||
*/
|
||||
/* #define UNBREAKABLE_SPACE 160 */
|
||||
|
||||
/*
|
||||
* If you want whitespace tokens contents to be recorded (making them
|
||||
* tokens with a string content), define this. The macro STRING_TOKEN
|
||||
* will be adjusted accordingly.
|
||||
* Without this option, whitespace tokens are not even returned by the
|
||||
* lex() function. This is irrelevant for the non-lexer mode (almost --
|
||||
* it might slow down a bit ucpp, and with this option, comments will be
|
||||
* kept inside #pragma directives).
|
||||
*/
|
||||
/* #define SEMPER_FIDELIS */
|
||||
|
||||
/* End of options overridable by UCPP_CONFIG and config.h */
|
2565
app/xrdb-cpp/cpp.c
Normal file
2565
app/xrdb-cpp/cpp.c
Normal file
File diff suppressed because it is too large
Load Diff
317
app/xrdb-cpp/cpp.h
Normal file
317
app/xrdb-cpp/cpp.h
Normal file
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* (c) Thomas Pornin 1999 - 2002
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UCPP__CPP__
|
||||
#define UCPP__CPP__
|
||||
|
||||
/*
|
||||
* Uncomment the following if you want ucpp to use externally provided
|
||||
* error-reporting functions (ucpp_warning(), ucpp_error() and ucpp_ouch())
|
||||
*/
|
||||
/* #define NO_UCPP_ERROR_FUNCTIONS */
|
||||
|
||||
/*
|
||||
* Tokens (do not change the order unless checking operators_name[] in cpp.c)
|
||||
*
|
||||
* It is important that the token NONE is 0
|
||||
* Check the STRING_TOKEN macro
|
||||
*/
|
||||
#define CPPERR 512
|
||||
enum {
|
||||
NONE, /* whitespace */
|
||||
NEWLINE, /* newline */
|
||||
COMMENT, /* comment */
|
||||
NUMBER, /* number constant */
|
||||
NAME, /* identifier */
|
||||
BUNCH, /* non-C characters */
|
||||
PRAGMA, /* a #pragma directive */
|
||||
CONTEXT, /* new file or #line */
|
||||
STRING, /* constant "xxx" */
|
||||
CHAR, /* constant 'xxx' */
|
||||
SLASH, /* / */
|
||||
ASSLASH, /* /= */
|
||||
MINUS, /* - */
|
||||
MMINUS, /* -- */
|
||||
ASMINUS, /* -= */
|
||||
ARROW, /* -> */
|
||||
PLUS, /* + */
|
||||
PPLUS, /* ++ */
|
||||
ASPLUS, /* += */
|
||||
LT, /* < */
|
||||
LEQ, /* <= */
|
||||
LSH, /* << */
|
||||
ASLSH, /* <<= */
|
||||
GT, /* > */
|
||||
GEQ, /* >= */
|
||||
RSH, /* >> */
|
||||
ASRSH, /* >>= */
|
||||
ASGN, /* = */
|
||||
SAME, /* == */
|
||||
#ifdef CAST_OP
|
||||
CAST, /* => */
|
||||
#endif
|
||||
NOT, /* ~ */
|
||||
NEQ, /* != */
|
||||
AND, /* & */
|
||||
LAND, /* && */
|
||||
ASAND, /* &= */
|
||||
OR, /* | */
|
||||
LOR, /* || */
|
||||
ASOR, /* |= */
|
||||
PCT, /* % */
|
||||
ASPCT, /* %= */
|
||||
STAR, /* * */
|
||||
ASSTAR, /* *= */
|
||||
CIRC, /* ^ */
|
||||
ASCIRC, /* ^= */
|
||||
LNOT, /* ! */
|
||||
LBRA, /* { */
|
||||
RBRA, /* } */
|
||||
LBRK, /* [ */
|
||||
RBRK, /* ] */
|
||||
LPAR, /* ( */
|
||||
RPAR, /* ) */
|
||||
COMMA, /* , */
|
||||
QUEST, /* ? */
|
||||
SEMIC, /* ; */
|
||||
COLON, /* : */
|
||||
DOT, /* . */
|
||||
MDOTS, /* ... */
|
||||
SHARP, /* # */
|
||||
DSHARP, /* ## */
|
||||
|
||||
OPT_NONE, /* optional space to separate tokens in text output */
|
||||
|
||||
DIGRAPH_TOKENS, /* there begin digraph tokens */
|
||||
|
||||
/* for DIG_*, do not change order, unless checking undig() in cpp.c */
|
||||
DIG_LBRK, /* <: */
|
||||
DIG_RBRK, /* :> */
|
||||
DIG_LBRA, /* <% */
|
||||
DIG_RBRA, /* %> */
|
||||
DIG_SHARP, /* %: */
|
||||
DIG_DSHARP, /* %:%: */
|
||||
|
||||
DIGRAPH_TOKENS_END, /* digraph tokens end here */
|
||||
|
||||
LAST_MEANINGFUL_TOKEN, /* reserved words will go there */
|
||||
|
||||
MACROARG, /* special token for representing macro arguments */
|
||||
|
||||
UPLUS = CPPERR, /* unary + */
|
||||
UMINUS /* unary - */
|
||||
};
|
||||
|
||||
#include "tune.h"
|
||||
#include <stdio.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
struct token {
|
||||
int type;
|
||||
long line;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct token_fifo {
|
||||
struct token *t;
|
||||
size_t nt, art;
|
||||
};
|
||||
|
||||
struct lexer_state {
|
||||
/* input control */
|
||||
FILE *input;
|
||||
#ifndef NO_UCPP_BUF
|
||||
unsigned char *input_buf;
|
||||
#ifdef UCPP_MMAP
|
||||
int from_mmap;
|
||||
unsigned char *input_buf_sav;
|
||||
#endif
|
||||
#endif
|
||||
unsigned char *input_string;
|
||||
size_t ebuf;
|
||||
size_t pbuf;
|
||||
int lka[2];
|
||||
int nlka;
|
||||
int macfile;
|
||||
int last;
|
||||
int discard;
|
||||
unsigned long utf8;
|
||||
unsigned char copy_line[COPY_LINE_LENGTH];
|
||||
int cli;
|
||||
|
||||
/* output control */
|
||||
FILE *output;
|
||||
struct token_fifo *output_fifo, *toplevel_of;
|
||||
#ifndef NO_UCPP_BUF
|
||||
unsigned char *output_buf;
|
||||
#endif
|
||||
size_t sbuf;
|
||||
|
||||
/* token control */
|
||||
struct token *ctok;
|
||||
struct token *save_ctok;
|
||||
size_t tknl;
|
||||
int ltwnl;
|
||||
int pending_token;
|
||||
#ifdef INMACRO_FLAG
|
||||
int inmacro;
|
||||
long macro_count;
|
||||
#endif
|
||||
|
||||
/* lexer options */
|
||||
long line;
|
||||
long oline;
|
||||
unsigned long flags;
|
||||
long count_trigraphs;
|
||||
struct garbage_fifo *gf;
|
||||
int ifnest;
|
||||
int condnest;
|
||||
int condcomp;
|
||||
int condmet;
|
||||
unsigned long condf[2];
|
||||
};
|
||||
|
||||
/*
|
||||
* Flags for struct lexer_state
|
||||
*/
|
||||
/* warning flags */
|
||||
#define WARN_STANDARD 0x000001UL /* emit standard warnings */
|
||||
#define WARN_ANNOYING 0x000002UL /* emit annoying warnings */
|
||||
#define WARN_TRIGRAPHS 0x000004UL /* warn when trigraphs are used */
|
||||
#define WARN_TRIGRAPHS_MORE 0x000008UL /* extra-warn for trigraphs */
|
||||
#define WARN_PRAGMA 0x000010UL /* warn for pragmas in non-lexer mode */
|
||||
|
||||
/* error flags */
|
||||
#define FAIL_SHARP 0x000020UL /* emit errors on rogue '#' */
|
||||
#define CCHARSET 0x000040UL /* emit errors on non-C characters */
|
||||
|
||||
/* emission flags */
|
||||
#define DISCARD_COMMENTS 0x000080UL /* discard comments from text output */
|
||||
#define CPLUSPLUS_COMMENTS 0x000100UL /* understand C++-like comments */
|
||||
#define LINE_NUM 0x000200UL /* emit #line directives in output */
|
||||
#define GCC_LINE_NUM 0x000400UL /* same as #line, with gcc-syntax */
|
||||
|
||||
/* language flags */
|
||||
#define HANDLE_ASSERTIONS 0x000800UL /* understand assertions */
|
||||
#define HANDLE_PRAGMA 0x001000UL /* emit PRAGMA tokens in lexer mode */
|
||||
#define MACRO_VAARG 0x002000UL /* understand macros with '...' */
|
||||
#define UTF8_SOURCE 0x004000UL /* identifiers are in UTF8 encoding */
|
||||
#define HANDLE_TRIGRAPHS 0x008000UL /* handle trigraphs */
|
||||
|
||||
/* global ucpp behaviour */
|
||||
#define LEXER 0x010000UL /* behave as a lexer */
|
||||
#define KEEP_OUTPUT 0x020000UL /* emit the result of preprocessing */
|
||||
#define COPY_LINE 0x040000UL /* make a copy of the parsed line */
|
||||
|
||||
/* internal flags */
|
||||
#define READ_AGAIN 0x080000UL /* emit again the last token */
|
||||
#define TEXT_OUTPUT 0x100000UL /* output text */
|
||||
|
||||
/*
|
||||
* Public function prototypes
|
||||
*/
|
||||
|
||||
#ifndef NO_UCPP_BUF
|
||||
void flush_output(struct lexer_state *);
|
||||
#endif
|
||||
|
||||
void init_assertions(void);
|
||||
int make_assertion(char *);
|
||||
int destroy_assertion(char *);
|
||||
void print_assertions(void);
|
||||
|
||||
void init_macros(void);
|
||||
int define_macro(struct lexer_state *, char *);
|
||||
int undef_macro(struct lexer_state *, char *);
|
||||
void print_defines(void);
|
||||
|
||||
void set_init_filename(char *, int);
|
||||
void init_cpp(void);
|
||||
void init_include_path(char *[]);
|
||||
void init_lexer_state(struct lexer_state *);
|
||||
void init_lexer_mode(struct lexer_state *);
|
||||
void free_lexer_state(struct lexer_state *);
|
||||
void wipeout(void);
|
||||
int lex(struct lexer_state *);
|
||||
int check_cpp_errors(struct lexer_state *);
|
||||
void add_incpath(char *);
|
||||
void init_tables(int);
|
||||
int enter_file(struct lexer_state *, unsigned long);
|
||||
int cpp(struct lexer_state *);
|
||||
void set_identifier_char(int c);
|
||||
void unset_identifier_char(int c);
|
||||
|
||||
#ifdef UCPP_MMAP
|
||||
FILE *fopen_mmap_file(char *);
|
||||
void set_input_file(struct lexer_state *, FILE *);
|
||||
#endif
|
||||
|
||||
struct stack_context {
|
||||
char *long_name, *name;
|
||||
long line;
|
||||
};
|
||||
struct stack_context *report_context(void);
|
||||
|
||||
extern int no_special_macros, system_macros,
|
||||
emit_dependencies, emit_defines, emit_assertions;
|
||||
extern int c99_compliant, c99_hosted;
|
||||
extern FILE *emit_output;
|
||||
extern char *current_filename, *current_long_filename;
|
||||
extern char *operators_name[];
|
||||
extern struct protect {
|
||||
char *macro;
|
||||
int state;
|
||||
struct found_file *ff;
|
||||
} protect_detect;
|
||||
|
||||
void ucpp_ouch(char *, ...);
|
||||
void ucpp_error(long, char *, ...);
|
||||
void ucpp_warning(long, char *, ...);
|
||||
|
||||
extern int *transient_characters;
|
||||
|
||||
/*
|
||||
* Errors from CPPERR_EOF and above are not real erros, only show-stoppers.
|
||||
* Errors below CPPERR_EOF are real ones.
|
||||
*/
|
||||
#define CPPERR_NEST 900
|
||||
#define CPPERR_EOF 1000
|
||||
|
||||
/*
|
||||
* This macro tells whether the name field of a given token type is
|
||||
* relevant, or not. Irrelevant name field means that it might point
|
||||
* to outerspace.
|
||||
*/
|
||||
#ifdef SEMPER_FIDELIS
|
||||
#define STRING_TOKEN(x) ((x) == NONE || ((x) >= COMMENT && (x) <= CHAR))
|
||||
#else
|
||||
#define STRING_TOKEN(x) ((x) >= NUMBER && (x) <= CHAR)
|
||||
#endif
|
||||
|
||||
#endif
|
699
app/xrdb-cpp/eval.c
Normal file
699
app/xrdb-cpp/eval.c
Normal file
@ -0,0 +1,699 @@
|
||||
/*
|
||||
* (c) Thomas Pornin 1999 - 2002
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "tune.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <setjmp.h>
|
||||
#include <limits.h>
|
||||
#include "ucppi.h"
|
||||
#include "mem.h"
|
||||
|
||||
JMP_BUF eval_exception;
|
||||
long eval_line;
|
||||
static int emit_eval_warnings;
|
||||
|
||||
/*
|
||||
* If you want to hardcode a conversion table, define a static array
|
||||
* of 256 int, and make transient_characters point to it.
|
||||
*/
|
||||
int *transient_characters = 0;
|
||||
|
||||
#define OCTAL(x) ((x) >= '0' && (x) <= '7')
|
||||
#define DECIM(x) ((x) >= '0' && (x) <= '9')
|
||||
#define HEXAD(x) (DECIM(x) \
|
||||
|| (x) == 'a' || (x) == 'b' || (x) == 'c' \
|
||||
|| (x) == 'd' || (x) == 'e' || (x) == 'f' \
|
||||
|| (x) == 'A' || (x) == 'B' || (x) == 'C' \
|
||||
|| (x) == 'D' || (x) == 'E' || (x) == 'F')
|
||||
#define OVAL(x) ((int)((x) - '0'))
|
||||
#define DVAL(x) ((int)((x) - '0'))
|
||||
#define HVAL(x) (DECIM(x) ? DVAL(x) \
|
||||
: (x) == 'a' || (x) == 'A' ? 10 \
|
||||
: (x) == 'b' || (x) == 'B' ? 11 \
|
||||
: (x) == 'c' || (x) == 'C' ? 12 \
|
||||
: (x) == 'd' || (x) == 'D' ? 13 \
|
||||
: (x) == 'e' || (x) == 'E' ? 14 : 15)
|
||||
|
||||
#define ARITH_TYPENAME big
|
||||
#define ARITH_FUNCTION_HEADER static inline
|
||||
|
||||
#define ARITH_ERROR(type) z_error(type)
|
||||
static void z_error(int type);
|
||||
|
||||
#ifdef ARITHMETIC_CHECKS
|
||||
#define ARITH_WARNING(type) z_warn(type)
|
||||
static void z_warn(int type);
|
||||
#endif
|
||||
|
||||
#include "arith.c"
|
||||
|
||||
static void z_error(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case ARITH_EXCEP_SLASH_D:
|
||||
error(eval_line, "division by 0");
|
||||
break;
|
||||
case ARITH_EXCEP_SLASH_O:
|
||||
error(eval_line, "overflow on division");
|
||||
break;
|
||||
case ARITH_EXCEP_PCT_D:
|
||||
error(eval_line, "division by 0 on modulus operator");
|
||||
break;
|
||||
case ARITH_EXCEP_CONST_O:
|
||||
error(eval_line, "constant too large for destination type");
|
||||
break;
|
||||
#ifdef AUDIT
|
||||
default:
|
||||
ouch("erroneous integer error: %d", type);
|
||||
#endif
|
||||
}
|
||||
throw(eval_exception);
|
||||
}
|
||||
|
||||
#ifdef ARITHMETIC_CHECKS
|
||||
static void z_warn(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case ARITH_EXCEP_CONV_O:
|
||||
warning(eval_line, "overflow on integer conversion");
|
||||
break;
|
||||
case ARITH_EXCEP_NEG_O:
|
||||
warning(eval_line, "overflow on unary minus");
|
||||
break;
|
||||
case ARITH_EXCEP_NOT_T:
|
||||
warning(eval_line,
|
||||
"bitwise inversion yields trap representation");
|
||||
break;
|
||||
case ARITH_EXCEP_PLUS_O:
|
||||
warning(eval_line, "overflow on addition");
|
||||
break;
|
||||
case ARITH_EXCEP_PLUS_U:
|
||||
warning(eval_line, "underflow on addition");
|
||||
break;
|
||||
case ARITH_EXCEP_MINUS_O:
|
||||
warning(eval_line, "overflow on subtraction");
|
||||
break;
|
||||
case ARITH_EXCEP_MINUS_U:
|
||||
warning(eval_line, "underflow on subtraction");
|
||||
break;
|
||||
case ARITH_EXCEP_AND_T:
|
||||
warning(eval_line,
|
||||
"bitwise AND yields trap representation");
|
||||
break;
|
||||
case ARITH_EXCEP_XOR_T:
|
||||
warning(eval_line,
|
||||
"bitwise XOR yields trap representation");
|
||||
break;
|
||||
case ARITH_EXCEP_OR_T:
|
||||
warning(eval_line,
|
||||
"bitwise OR yields trap representation");
|
||||
break;
|
||||
case ARITH_EXCEP_LSH_W:
|
||||
warning(eval_line, "left shift count greater than "
|
||||
"or equal to type width");
|
||||
break;
|
||||
case ARITH_EXCEP_LSH_C:
|
||||
warning(eval_line, "left shift count negative");
|
||||
break;
|
||||
case ARITH_EXCEP_LSH_O:
|
||||
warning(eval_line, "overflow on left shift");
|
||||
break;
|
||||
case ARITH_EXCEP_RSH_W:
|
||||
warning(eval_line, "right shift count greater than "
|
||||
"or equal to type width");
|
||||
break;
|
||||
case ARITH_EXCEP_RSH_C:
|
||||
warning(eval_line, "right shift count negative");
|
||||
break;
|
||||
case ARITH_EXCEP_RSH_N:
|
||||
warning(eval_line, "right shift of negative value");
|
||||
break;
|
||||
case ARITH_EXCEP_STAR_O:
|
||||
warning(eval_line, "overflow on multiplication");
|
||||
break;
|
||||
case ARITH_EXCEP_STAR_U:
|
||||
warning(eval_line, "underflow on multiplication");
|
||||
break;
|
||||
#ifdef AUDIT
|
||||
default:
|
||||
ouch("erroneous integer warning: %d", type);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int sign;
|
||||
union {
|
||||
u_big uv;
|
||||
s_big sv;
|
||||
} u;
|
||||
} ppval;
|
||||
|
||||
static int boolval(ppval x)
|
||||
{
|
||||
return x.sign ? big_s_lval(x.u.sv) : big_u_lval(x.u.uv);
|
||||
}
|
||||
|
||||
#if !defined(WCHAR_SIGNEDNESS)
|
||||
# if CHAR_MIN == 0
|
||||
# define WCHAR_SIGNEDNESS 0
|
||||
# else
|
||||
# define WCHAR_SIGNEDNESS 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check the suffix, return 1 if it is signed, 0 otherwise. 1 is
|
||||
* returned for a void suffix. Legal suffixes are:
|
||||
* unsigned: u U ul uL Ul UL lu Lu lU LU ull uLL Ull ULL llu LLu llU LLU
|
||||
* signed: l L ll LL
|
||||
*/
|
||||
static int pp_suffix(char *d, char *refc)
|
||||
{
|
||||
if (!*d) return 1;
|
||||
if (*d == 'u' || *d == 'U') {
|
||||
if (!*(++ d)) return 0;
|
||||
if (*d == 'l' || *d == 'L') {
|
||||
char *e = d + 1;
|
||||
|
||||
if (*e && *e != *d) goto suffix_error;
|
||||
if (!*e || !*(e + 1)) return 0;
|
||||
goto suffix_error;
|
||||
}
|
||||
goto suffix_error;
|
||||
}
|
||||
if (*d == 'l' || *d == 'L') {
|
||||
if (!*(++ d)) return 1;
|
||||
if (*d == *(d - 1)) {
|
||||
d ++;
|
||||
if (!*d) return 1;
|
||||
}
|
||||
if (*d == 'u' || *d == 'U') {
|
||||
d ++;
|
||||
if (!*d) return 0;
|
||||
}
|
||||
goto suffix_error;
|
||||
}
|
||||
suffix_error:
|
||||
error(eval_line, "invalid integer constant '%s'", refc);
|
||||
throw(eval_exception);
|
||||
return 666;
|
||||
}
|
||||
|
||||
static unsigned long pp_char(char *c, char *refc)
|
||||
{
|
||||
unsigned long r = 0;
|
||||
|
||||
c ++;
|
||||
if (*c == '\\') {
|
||||
int i;
|
||||
|
||||
c ++;
|
||||
switch (*c) {
|
||||
case 'n': r = '\n'; c ++; break;
|
||||
case 't': r = '\t'; c ++; break;
|
||||
case 'v': r = '\v'; c ++; break;
|
||||
case 'b': r = '\b'; c ++; break;
|
||||
case 'r': r = '\r'; c ++; break;
|
||||
case 'f': r = '\f'; c ++; break;
|
||||
case 'a': r = '\a'; c ++; break;
|
||||
case '\\': r = '\\'; c ++; break;
|
||||
case '\?': r = '\?'; c ++; break;
|
||||
case '\'': r = '\''; c ++; break;
|
||||
case '\"': r = '\"'; c ++; break;
|
||||
case 'u':
|
||||
for (i = 0, c ++; i < 4 && HEXAD(*c); i ++, c ++) {
|
||||
r = (r * 16) + HVAL(*c);
|
||||
}
|
||||
if (i != 4) {
|
||||
error(eval_line, "malformed UCN in %s", refc);
|
||||
throw(eval_exception);
|
||||
}
|
||||
break;
|
||||
case 'U':
|
||||
for (i = 0, c ++; i < 8 && HEXAD(*c); i ++, c ++) {
|
||||
r = (r * 16) + HVAL(*c);
|
||||
}
|
||||
if (i != 8) {
|
||||
error(eval_line, "malformed UCN in %s", refc);
|
||||
throw(eval_exception);
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
for (c ++; HEXAD(*c); c ++) r = (r * 16) + HVAL(*c);
|
||||
break;
|
||||
default:
|
||||
if (OCTAL(*c)) {
|
||||
r = OVAL(*(c ++));
|
||||
if (OCTAL(*c)) r = (r * 8) + OVAL(*(c ++));
|
||||
if (OCTAL(*c)) r = (r * 8) + OVAL(*(c ++));
|
||||
} else {
|
||||
error(eval_line, "invalid escape sequence "
|
||||
"'\\%c'", *c);
|
||||
throw(eval_exception);
|
||||
}
|
||||
}
|
||||
} else if (*c == '\'') {
|
||||
error(eval_line, "empty character constant");
|
||||
throw(eval_exception);
|
||||
} else {
|
||||
r = *((unsigned char *)(c ++));
|
||||
}
|
||||
|
||||
if (transient_characters && r < 256) {
|
||||
r = transient_characters[(size_t)r];
|
||||
}
|
||||
|
||||
if (*c != '\'' && emit_eval_warnings) {
|
||||
warning(eval_line, "multicharacter constant");
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static ppval pp_strtoconst(char *refc)
|
||||
{
|
||||
ppval q;
|
||||
char *c = refc, *d;
|
||||
u_big ru;
|
||||
s_big rs;
|
||||
int sp, dec;
|
||||
|
||||
if (*c == '\'' || *c == 'L') {
|
||||
q.sign = (*c == 'L') ? WCHAR_SIGNEDNESS : 1;
|
||||
if (*c == 'L' && *(++ c) != '\'') {
|
||||
error(eval_line,
|
||||
"invalid wide character constant: %s", refc);
|
||||
throw(eval_exception);
|
||||
}
|
||||
if (q.sign) {
|
||||
q.u.sv = big_s_fromlong(pp_char(c, refc));
|
||||
} else {
|
||||
q.u.uv = big_u_fromulong(pp_char(c, refc));
|
||||
}
|
||||
return q;
|
||||
}
|
||||
if (*c == '0') {
|
||||
/* octal or hexadecimal */
|
||||
dec = 0;
|
||||
c ++;
|
||||
if (*c == 'x' || *c == 'X') {
|
||||
c ++;
|
||||
d = big_u_hexconst(c, &ru, &rs, &sp);
|
||||
} else {
|
||||
d = big_u_octconst(c, &ru, &rs, &sp);
|
||||
}
|
||||
} else {
|
||||
dec = 1;
|
||||
d = big_u_decconst(c, &ru, &rs, &sp);
|
||||
}
|
||||
q.sign = pp_suffix(d, refc);
|
||||
if (q.sign) {
|
||||
if (!sp) {
|
||||
if (dec) {
|
||||
error(eval_line, "constant too large "
|
||||
"for destination type");
|
||||
throw(eval_exception);
|
||||
} else {
|
||||
warning(eval_line, "constant is so large "
|
||||
"that it is unsigned");
|
||||
}
|
||||
q.u.uv = ru;
|
||||
q.sign = 0;
|
||||
} else {
|
||||
q.u.sv = rs;
|
||||
}
|
||||
} else {
|
||||
q.u.uv = ru;
|
||||
}
|
||||
return q;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used by #line directives -- anything beyond what can be put in an
|
||||
* unsigned long, is considered absurd.
|
||||
*/
|
||||
unsigned long strtoconst(char *c)
|
||||
{
|
||||
ppval q = pp_strtoconst(c);
|
||||
|
||||
if (q.sign) q.u.uv = big_s_to_u(q.u.sv);
|
||||
return big_u_toulong(q.u.uv);
|
||||
}
|
||||
|
||||
#define OP_UN(x) ((x) == LNOT || (x) == NOT || (x) == UPLUS \
|
||||
|| (x) == UMINUS)
|
||||
|
||||
static ppval eval_opun(int op, ppval v)
|
||||
{
|
||||
if (op == LNOT) {
|
||||
v.sign = 1;
|
||||
v.u.sv = big_s_fromint(big_s_lnot(v.u.sv));
|
||||
return v;
|
||||
}
|
||||
if (v.sign) {
|
||||
switch (op) {
|
||||
case NOT: v.u.sv = big_s_not(v.u.sv); break;
|
||||
case UPLUS: break;
|
||||
case UMINUS: v.u.sv = big_s_neg(v.u.sv); break;
|
||||
}
|
||||
} else {
|
||||
switch (op) {
|
||||
case NOT: v.u.uv = big_u_not(v.u.uv); break;
|
||||
case UPLUS: break;
|
||||
case UMINUS: v.u.uv = big_u_neg(v.u.uv); break;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
#define OP_BIN(x) ((x) == STAR || (x) == SLASH || (x) == PCT \
|
||||
|| (x) == PLUS || (x) == MINUS || (x) == LSH \
|
||||
|| (x) == RSH || (x) == LT || (x) == LEQ \
|
||||
|| (x) == GT || (x) == GEQ || (x) == SAME \
|
||||
|| (x) == NEQ || (x) == AND || (x) == CIRC \
|
||||
|| (x) == OR || (x) == LAND || (x) == LOR \
|
||||
|| (x) == COMMA)
|
||||
|
||||
static ppval eval_opbin(int op, ppval v1, ppval v2)
|
||||
{
|
||||
ppval r;
|
||||
int iv2 = 0;
|
||||
|
||||
switch (op) {
|
||||
case STAR: case SLASH: case PCT:
|
||||
case PLUS: case MINUS: case AND:
|
||||
case CIRC: case OR:
|
||||
/* promote operands, adjust signedness of result */
|
||||
if (!v1.sign || !v2.sign) {
|
||||
if (v1.sign) {
|
||||
v1.u.uv = big_s_to_u(v1.u.sv);
|
||||
v1.sign = 0;
|
||||
} else if (v2.sign) {
|
||||
v2.u.uv = big_s_to_u(v2.u.sv);
|
||||
v2.sign = 0;
|
||||
}
|
||||
r.sign = 0;
|
||||
} else {
|
||||
r.sign = 1;
|
||||
}
|
||||
break;
|
||||
case LT: case LEQ: case GT:
|
||||
case GEQ: case SAME: case NEQ:
|
||||
/* promote operands */
|
||||
if (!v1.sign || !v2.sign) {
|
||||
if (v1.sign) {
|
||||
v1.u.uv = big_s_to_u(v1.u.sv);
|
||||
v1.sign = 0;
|
||||
} else if (v2.sign) {
|
||||
v2.u.uv = big_s_to_u(v2.u.sv);
|
||||
v2.sign = 0;
|
||||
}
|
||||
}
|
||||
/* fall through */
|
||||
case LAND:
|
||||
case LOR:
|
||||
/* result is signed anyway */
|
||||
r.sign = 1;
|
||||
break;
|
||||
case LSH:
|
||||
case RSH:
|
||||
/* result is as signed as left operand; convert right
|
||||
operand to int */
|
||||
r.sign = v1.sign;
|
||||
if (v2.sign) {
|
||||
iv2 = big_s_toint(v2.u.sv);
|
||||
} else {
|
||||
iv2 = big_u_toint(v2.u.uv);
|
||||
}
|
||||
break;
|
||||
case COMMA:
|
||||
if (emit_eval_warnings) {
|
||||
warning(eval_line, "ISO C forbids evaluated comma "
|
||||
"operators in #if expressions");
|
||||
}
|
||||
r.sign = v2.sign;
|
||||
break;
|
||||
#ifdef AUDIT
|
||||
default: ouch("a good operator is a dead operator");
|
||||
#endif
|
||||
}
|
||||
|
||||
#define SBINOP(x) if (r.sign) r.u.sv = big_s_ ## x (v1.u.sv, v2.u.sv); \
|
||||
else r.u.uv = big_u_ ## x (v1.u.uv, v2.u.uv);
|
||||
|
||||
#define NSSBINOP(x) if (v1.sign) r.u.sv = big_s_fromint(big_s_ ## x \
|
||||
(v1.u.sv, v2.u.sv)); else r.u.sv = big_s_fromint( \
|
||||
big_u_ ## x (v1.u.uv, v2.u.uv));
|
||||
|
||||
#define LBINOP(x) if (v1.sign) r.u.sv = big_s_fromint( \
|
||||
big_s_lval(v1.u.sv) x big_s_lval(v2.u.sv)); \
|
||||
else r.u.sv = big_s_fromint( \
|
||||
big_u_lval(v1.u.uv) x big_u_lval(v2.u.uv));
|
||||
|
||||
#define ABINOP(x) if (r.sign) r.u.sv = big_s_ ## x (v1.u.sv, iv2); \
|
||||
else r.u.uv = big_u_ ## x (v1.u.uv, iv2);
|
||||
|
||||
switch (op) {
|
||||
case STAR: SBINOP(star); break;
|
||||
case SLASH: SBINOP(slash); break;
|
||||
case PCT: SBINOP(pct); break;
|
||||
case PLUS: SBINOP(plus); break;
|
||||
case MINUS: SBINOP(minus); break;
|
||||
case LSH: ABINOP(lsh); break;
|
||||
case RSH: ABINOP(rsh); break;
|
||||
case LT: NSSBINOP(lt); break;
|
||||
case LEQ: NSSBINOP(leq); break;
|
||||
case GT: NSSBINOP(gt); break;
|
||||
case GEQ: NSSBINOP(geq); break;
|
||||
case SAME: NSSBINOP(same); break;
|
||||
case NEQ: NSSBINOP(neq); break;
|
||||
case AND: SBINOP(and); break;
|
||||
case CIRC: SBINOP(xor); break;
|
||||
case OR: SBINOP(or); break;
|
||||
case LAND: LBINOP(&&); break;
|
||||
case LOR: LBINOP(||); break;
|
||||
case COMMA: r = v2; break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
#define ttOP(x) (OP_UN(x) || OP_BIN(x) || (x) == QUEST || (x) == COLON)
|
||||
|
||||
static int op_prec(int op)
|
||||
{
|
||||
switch (op) {
|
||||
case LNOT:
|
||||
case NOT:
|
||||
case UPLUS:
|
||||
case UMINUS:
|
||||
return 13;
|
||||
case STAR:
|
||||
case SLASH:
|
||||
case PCT:
|
||||
return 12;
|
||||
case PLUS:
|
||||
case MINUS:
|
||||
return 11;
|
||||
case LSH:
|
||||
case RSH:
|
||||
return 10;
|
||||
case LT:
|
||||
case LEQ:
|
||||
case GT:
|
||||
case GEQ:
|
||||
return 9;
|
||||
case SAME:
|
||||
case NEQ:
|
||||
return 8;
|
||||
case AND:
|
||||
return 7;
|
||||
case CIRC:
|
||||
return 6;
|
||||
case OR:
|
||||
return 5;
|
||||
case LAND:
|
||||
return 4;
|
||||
case LOR:
|
||||
return 3;
|
||||
case QUEST:
|
||||
return 2;
|
||||
case COMMA:
|
||||
return 1;
|
||||
}
|
||||
#ifdef AUDIT
|
||||
ouch("an unknown species should have a higher precedence");
|
||||
#endif
|
||||
return 666;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the hard work of evaluation.
|
||||
*
|
||||
* This function works because:
|
||||
* -- all unary operators are right to left associative, and with
|
||||
* identical precedence
|
||||
* -- all binary operators are left to right associative
|
||||
* -- there is only one non-unary and non-binary operator: the quest-colon
|
||||
*
|
||||
* If do_eval is 0, the evaluation of operators is not done. This is
|
||||
* for sequence point operators (&&, || and ?:).
|
||||
*/
|
||||
static ppval eval_shrd(struct token_fifo *tf, int minprec, int do_eval)
|
||||
{
|
||||
ppval top;
|
||||
struct token *ct;
|
||||
|
||||
top.sign = 1;
|
||||
if (tf->art == tf->nt) goto trunc_err;
|
||||
ct = tf->t + (tf->art ++);
|
||||
if (ct->type == LPAR) {
|
||||
top = eval_shrd(tf, 0, do_eval);
|
||||
if (tf->art == tf->nt) goto trunc_err;
|
||||
ct = tf->t + (tf->art ++);
|
||||
if (ct->type != RPAR) {
|
||||
error(eval_line, "a right parenthesis was expected");
|
||||
throw(eval_exception);
|
||||
}
|
||||
} else if (ct->type == NUMBER || ct->type == CHAR) {
|
||||
top = pp_strtoconst(ct->name);
|
||||
} else if (OP_UN(ct->type)) {
|
||||
top = eval_opun(ct->type, eval_shrd(tf,
|
||||
op_prec(ct->type), do_eval));
|
||||
goto eval_loop;
|
||||
} else if (ttOP(ct->type)) goto rogue_op_err;
|
||||
else {
|
||||
goto invalid_token_err;
|
||||
}
|
||||
|
||||
eval_loop:
|
||||
if (tf->art == tf->nt) {
|
||||
return top;
|
||||
}
|
||||
ct = tf->t + (tf->art ++);
|
||||
if (OP_BIN(ct->type)) {
|
||||
int bp = op_prec(ct->type);
|
||||
|
||||
if (bp > minprec) {
|
||||
ppval tr;
|
||||
|
||||
if ((ct->type == LOR && boolval(top))
|
||||
|| (ct->type == LAND && !boolval(top))) {
|
||||
tr = eval_shrd(tf, bp, 0);
|
||||
if (do_eval) {
|
||||
top.sign = 1;
|
||||
if (ct->type == LOR)
|
||||
top.u.sv = big_s_fromint(1);
|
||||
if (ct->type == LAND)
|
||||
top.u.sv = big_s_fromint(0);
|
||||
}
|
||||
} else {
|
||||
tr = eval_shrd(tf, bp, do_eval);
|
||||
if (do_eval)
|
||||
top = eval_opbin(ct->type, top, tr);
|
||||
}
|
||||
goto eval_loop;
|
||||
}
|
||||
} else if (ct->type == QUEST) {
|
||||
int bp = op_prec(QUEST);
|
||||
ppval r1, r2;
|
||||
|
||||
if (bp >= minprec) {
|
||||
int qv = boolval(top);
|
||||
|
||||
r1 = eval_shrd(tf, bp, qv ? do_eval : 0);
|
||||
if (tf->art == tf->nt) goto trunc_err;
|
||||
ct = tf->t + (tf->art ++);
|
||||
if (ct->type != COLON) {
|
||||
error(eval_line, "a colon was expected");
|
||||
throw(eval_exception);
|
||||
}
|
||||
r2 = eval_shrd(tf, bp, qv ? 0 : do_eval);
|
||||
if (do_eval) {
|
||||
if (qv) top = r1; else top = r2;
|
||||
}
|
||||
goto eval_loop;
|
||||
}
|
||||
}
|
||||
tf->art --;
|
||||
return top;
|
||||
|
||||
trunc_err:
|
||||
error(eval_line, "truncated constant integral expression");
|
||||
throw(eval_exception);
|
||||
rogue_op_err:
|
||||
error(eval_line, "rogue operator '%s' in constant integral "
|
||||
"expression", operators_name[ct->type]);
|
||||
throw(eval_exception);
|
||||
invalid_token_err:
|
||||
error(eval_line, "invalid token in constant integral expression");
|
||||
throw(eval_exception);
|
||||
}
|
||||
|
||||
#define UNARY(x) ((x) != NUMBER && (x) != NAME && (x) != CHAR \
|
||||
&& (x) != RPAR)
|
||||
|
||||
/*
|
||||
* Evaluate the integer expression contained in the given token_fifo.
|
||||
* Evaluation is made by precedence of operators, as described in the
|
||||
* Dragon Book. The unary + and - are distinguished from their binary
|
||||
* counterparts using the Fortran way: a + or a - is considered unary
|
||||
* if it does not follow a constant, an identifier or a right parenthesis.
|
||||
*/
|
||||
unsigned long eval_expr(struct token_fifo *tf, int *ret, int ew)
|
||||
{
|
||||
size_t sart;
|
||||
ppval r;
|
||||
|
||||
emit_eval_warnings = ew;
|
||||
if (catch(eval_exception)) goto eval_err;
|
||||
/* first, distinguish unary + and - from binary + and - */
|
||||
for (sart = tf->art; tf->art < tf->nt; tf->art ++) {
|
||||
if (tf->t[tf->art].type == PLUS) {
|
||||
if (sart == tf->art || UNARY(tf->t[tf->art - 1].type))
|
||||
tf->t[tf->art].type = UPLUS;
|
||||
} else if (tf->t[tf->art].type == MINUS) {
|
||||
if (sart == tf->art || UNARY(tf->t[tf->art - 1].type))
|
||||
tf->t[tf->art].type = UMINUS;
|
||||
}
|
||||
}
|
||||
tf->art = sart;
|
||||
r = eval_shrd(tf, 0, 1);
|
||||
if (tf->art < tf->nt) {
|
||||
error(eval_line, "trailing garbage in constant integral "
|
||||
"expression");
|
||||
goto eval_err;
|
||||
}
|
||||
*ret = 0;
|
||||
return boolval(r);
|
||||
eval_err:
|
||||
*ret = 1;
|
||||
return 0;
|
||||
}
|
329
app/xrdb-cpp/hash.c
Normal file
329
app/xrdb-cpp/hash.c
Normal file
@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Generic hash table routines.
|
||||
* (c) Thomas Pornin 1998, 1999, 2000
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "hash.h"
|
||||
#include "mem.h"
|
||||
#include "tune.h"
|
||||
|
||||
/*
|
||||
* hash_string() is a sample hash function for strings
|
||||
*/
|
||||
int hash_string(char *s)
|
||||
{
|
||||
#ifdef FAST_HASH
|
||||
unsigned h = 0, g;
|
||||
|
||||
while (*s) {
|
||||
h = (h << 4) + *(unsigned char *)(s ++);
|
||||
if ((g = h & 0xF000U) != 0) h ^= (g >> 12);
|
||||
h &= ~g;
|
||||
}
|
||||
return (h ^ (h >> 9)) & 127U;
|
||||
#else
|
||||
unsigned char h = 0;
|
||||
|
||||
for (; *s; s ++) h ^= (unsigned char)(*s);
|
||||
return ((int)h);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* struct hash_item is the basic data type to internally handle hash tables
|
||||
*/
|
||||
struct hash_item {
|
||||
void *data;
|
||||
struct hash_item *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function adds an entry to the struct hash_item list
|
||||
*/
|
||||
static struct hash_item *add_entry(struct hash_item *blist, void *data)
|
||||
{
|
||||
struct hash_item *t = getmem(sizeof(struct hash_item));
|
||||
|
||||
t->data = data;
|
||||
t->next = blist;
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function finds a struct hash_item in a list, using the
|
||||
* comparison function provided as cmpdata (*cmpdata() returns
|
||||
* non-zero if the two parameters are to be considered identical).
|
||||
*
|
||||
* It returns 0 if the item is not found.
|
||||
*/
|
||||
static struct hash_item *get_entry(struct hash_item *blist, void *data,
|
||||
int (*cmpdata)(void *, void *))
|
||||
{
|
||||
while (blist) {
|
||||
if ((*cmpdata)(data, blist->data)) return blist;
|
||||
blist = blist->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function acts like get_entry but deletes the found item, using
|
||||
* the provided function deldata(); it returns 0 if the given data was
|
||||
* not found.
|
||||
*/
|
||||
static struct hash_item *del_entry(struct hash_item *blist, void *data,
|
||||
int (*cmpdata)(void *, void *), void (*deldata)(void *))
|
||||
{
|
||||
struct hash_item *prev = 0, *save = blist;
|
||||
|
||||
while (blist) {
|
||||
if ((*cmpdata)(data, blist->data)) {
|
||||
if (deldata) (*deldata)(blist->data);
|
||||
if (prev) prev->next = blist->next;
|
||||
if (save == blist) save = blist->next;
|
||||
freemem(blist);
|
||||
return save;
|
||||
}
|
||||
prev = blist;
|
||||
blist = blist->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function creates a new hashtable, with the hashing and comparison
|
||||
* functions given as parameters
|
||||
*/
|
||||
struct HT *newHT(int n, int (*cmpdata)(void *, void *), int (*hash)(void *),
|
||||
void (*deldata)(void *))
|
||||
{
|
||||
struct HT *t = getmem(sizeof(struct HT));
|
||||
int i;
|
||||
|
||||
t->lists = getmem(n * sizeof(struct hash_item *));
|
||||
for (i = 0; i < n; i ++) t->lists[i] = 0;
|
||||
t->nb_lists = n;
|
||||
t->cmpdata = cmpdata;
|
||||
t->hash = hash;
|
||||
t->deldata = deldata;
|
||||
return t;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function adds a new entry in the hashtable ht; it returns 0
|
||||
* on success, or a pointer to the already present item otherwise.
|
||||
*/
|
||||
void *putHT(struct HT *ht, void *data)
|
||||
{
|
||||
int h;
|
||||
struct hash_item *d;
|
||||
|
||||
h = ((*(ht->hash))(data));
|
||||
#ifndef FAST_HASH
|
||||
h %= ht->nb_lists;
|
||||
#endif
|
||||
if ((d = get_entry(ht->lists[h], data, ht->cmpdata)))
|
||||
return d->data;
|
||||
ht->lists[h] = add_entry(ht->lists[h], data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function adds a new entry in the hashtable ht, even if an equal
|
||||
* entry is already there. Exercise caution !
|
||||
* The new entry will "hide" the old one, which means that the new will be
|
||||
* found upon lookup/delete, not the old one.
|
||||
*/
|
||||
void *forceputHT(struct HT *ht, void *data)
|
||||
{
|
||||
int h;
|
||||
|
||||
h = ((*(ht->hash))(data));
|
||||
#ifndef FAST_HASH
|
||||
h %= ht->nb_lists;
|
||||
#endif
|
||||
ht->lists[h] = add_entry(ht->lists[h], data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function finds the entry corresponding to *data in the
|
||||
* hashtable ht (using the comparison function given as argument
|
||||
* to newHT)
|
||||
*/
|
||||
void *getHT(struct HT *ht, void *data)
|
||||
{
|
||||
int h;
|
||||
struct hash_item *t;
|
||||
|
||||
h = ((*(ht->hash))(data));
|
||||
#ifndef FAST_HASH
|
||||
h %= ht->nb_lists;
|
||||
#endif
|
||||
if ((t = get_entry(ht->lists[h], data, ht->cmpdata)) == 0)
|
||||
return 0;
|
||||
return (t->data);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function finds and delete the entry corresponding to *data
|
||||
* in the hashtable ht (using the comparison function given as
|
||||
* argument to newHT).
|
||||
*/
|
||||
|
||||
int delHT(struct HT *ht, void *data)
|
||||
{
|
||||
int h;
|
||||
|
||||
h = ((*(ht->hash))(data));
|
||||
#ifndef FAST_HASH
|
||||
h %= ht->nb_lists;
|
||||
#endif
|
||||
ht->lists[h] = del_entry(ht->lists[h], data, ht->cmpdata, ht->deldata);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function completely eradicates from memory a given hash table,
|
||||
* releasing all objects
|
||||
*/
|
||||
void killHT(struct HT *ht)
|
||||
{
|
||||
int i;
|
||||
struct hash_item *t, *n;
|
||||
void (*dd)(void *) = ht->deldata;
|
||||
|
||||
for (i = 0; i < ht->nb_lists; i ++) for (t = ht->lists[i]; t;) {
|
||||
n = t->next;
|
||||
if (dd) (*dd)(t->data);
|
||||
freemem(t);
|
||||
t = n;
|
||||
}
|
||||
freemem(ht->lists);
|
||||
freemem(ht);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function stores a backup of the hash table, for context stacking.
|
||||
*/
|
||||
void saveHT(struct HT *ht, void **buffer)
|
||||
{
|
||||
struct hash_item **b = (struct hash_item **)buffer;
|
||||
|
||||
mmv(b, ht->lists, ht->nb_lists * sizeof(struct hash_item *));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function restores the saved state of the hash table.
|
||||
* Do NOT use if some of the entries that were present before the backup
|
||||
* have been removed (even temporarily).
|
||||
*/
|
||||
void restoreHT(struct HT *ht, void **buffer)
|
||||
{
|
||||
struct hash_item **b = (struct hash_item **)buffer;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ht->nb_lists; i ++) {
|
||||
struct hash_item *t = ht->lists[i], *n;
|
||||
|
||||
while (t != b[i]) {
|
||||
n = t->next;
|
||||
(*(ht->deldata))(t->data);
|
||||
freemem(t);
|
||||
t = n;
|
||||
}
|
||||
ht->lists[i] = b[i];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is evil. It inserts a new item in a saved hash table,
|
||||
* tweaking the save buffer and the hash table in order to keep things
|
||||
* stable. There are no checks.
|
||||
*/
|
||||
void tweakHT(struct HT *ht, void **buffer, void *data)
|
||||
{
|
||||
int h;
|
||||
struct hash_item *d, *e;
|
||||
|
||||
h = ((*(ht->hash))(data));
|
||||
#ifndef FAST_HASH
|
||||
h %= ht->nb_lists;
|
||||
#endif
|
||||
for (d = ht->lists[h]; d != buffer[h]; d = d->next);
|
||||
d = add_entry(buffer[h], data);
|
||||
if (buffer[h] == ht->lists[h]) {
|
||||
buffer[h] = ht->lists[h] = d;
|
||||
return;
|
||||
}
|
||||
for (e = ht->lists[h]; e->next != buffer[h]; e = e->next);
|
||||
e->next = d;
|
||||
buffer[h] = d;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function scans the whole table and calls the given function on
|
||||
* each entry.
|
||||
*/
|
||||
void scanHT(struct HT *ht, void (*action)(void *))
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ht->nb_lists; i ++) {
|
||||
struct hash_item *t = ht->lists[i];
|
||||
|
||||
while (t) {
|
||||
(*action)(t->data);
|
||||
t = t->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The two following fonctions are generic for storing structures
|
||||
* uniquely identified by their name, which must be the first
|
||||
* field of the structure.
|
||||
*/
|
||||
int hash_struct(void *m)
|
||||
{
|
||||
char *n = *(char **)m;
|
||||
|
||||
#ifdef FAST_HASH
|
||||
return hash_string(n);
|
||||
#else
|
||||
return hash_string(n) & 127;
|
||||
#endif
|
||||
}
|
||||
|
||||
int cmp_struct(void *m1, void *m2)
|
||||
{
|
||||
char *n1 = *(char **)m1, *n2 = *(char **)m2;
|
||||
|
||||
return !strcmp(n1, n2);
|
||||
}
|
58
app/xrdb-cpp/hash.h
Normal file
58
app/xrdb-cpp/hash.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* (c) Thomas Pornin 1998, 1999, 2000
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UCPP__HASH__
|
||||
#define UCPP__HASH__
|
||||
|
||||
struct hash_item;
|
||||
|
||||
struct HT {
|
||||
struct hash_item **lists;
|
||||
int nb_lists;
|
||||
int (*cmpdata)(void *, void *);
|
||||
int (*hash)(void *);
|
||||
void (*deldata)(void *);
|
||||
};
|
||||
|
||||
int hash_string(char *);
|
||||
struct HT *newHT(int, int (*)(void *, void *), int (*)(void *),
|
||||
void (*)(void *));
|
||||
void *putHT(struct HT *, void *);
|
||||
void *forceputHT(struct HT *, void *);
|
||||
void *getHT(struct HT *, void *);
|
||||
int delHT(struct HT *, void *);
|
||||
void killHT(struct HT *);
|
||||
void saveHT(struct HT *, void **);
|
||||
void restoreHT(struct HT *, void **);
|
||||
void tweakHT(struct HT *, void **, void *);
|
||||
void scanHT(struct HT *, void (*)(void *));
|
||||
int hash_struct(void *);
|
||||
int cmp_struct(void *, void *);
|
||||
|
||||
#endif
|
1020
app/xrdb-cpp/lexer.c
Normal file
1020
app/xrdb-cpp/lexer.c
Normal file
File diff suppressed because it is too large
Load Diff
1921
app/xrdb-cpp/macro.c
Normal file
1921
app/xrdb-cpp/macro.c
Normal file
File diff suppressed because it is too large
Load Diff
328
app/xrdb-cpp/mem.c
Normal file
328
app/xrdb-cpp/mem.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* Memory manipulation routines
|
||||
* (c) Thomas Pornin 1998 - 2002
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "mem.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Shifting a pointer of that some bytes is supposed to satisfy
|
||||
* alignment requirements. This is *not* guaranteed by the standard
|
||||
* but should work everywhere anyway.
|
||||
*/
|
||||
#define ALIGNSHIFT (sizeof(long) > sizeof(long double) \
|
||||
? sizeof(long) : sizeof(long double))
|
||||
|
||||
#ifdef AUDIT
|
||||
void die(void)
|
||||
{
|
||||
abort();
|
||||
}
|
||||
|
||||
static void suicide(unsigned long e)
|
||||
{
|
||||
fprintf(stderr, "ouch: Schrodinger's beef is not dead ! %lx\n", e);
|
||||
die();
|
||||
}
|
||||
#else
|
||||
void die(void)
|
||||
{
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined AUDIT || defined MEM_CHECK || defined MEM_DEBUG
|
||||
/*
|
||||
* This function is equivalent to a malloc(), but will display an error
|
||||
* message and exit if the wanted memory is not available
|
||||
*/
|
||||
#ifdef MEM_DEBUG
|
||||
static void *getmem_raw(size_t x)
|
||||
#else
|
||||
void *(getmem)(size_t x)
|
||||
#endif
|
||||
{
|
||||
void *m;
|
||||
|
||||
#ifdef AUDIT
|
||||
m = malloc(x + ALIGNSHIFT);
|
||||
#else
|
||||
m = malloc(x);
|
||||
#endif
|
||||
if (m == 0) {
|
||||
fprintf(stderr, "ouch: malloc() failed\n");
|
||||
die();
|
||||
}
|
||||
#ifdef AUDIT
|
||||
*((unsigned long *)m) = 0xdeadbeefUL;
|
||||
return (void *)(((char *)m) + ALIGNSHIFT);
|
||||
#else
|
||||
return m;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MEM_DEBUG
|
||||
/*
|
||||
* This function is equivalent to a realloc(); if the realloc() call
|
||||
* fails, it will try a malloc() and a memcpy(). If not enough memory is
|
||||
* available, the program exits with an error message
|
||||
*/
|
||||
void *(incmem)(void *m, size_t x, size_t nx)
|
||||
{
|
||||
void *nm;
|
||||
|
||||
#ifdef AUDIT
|
||||
m = (void *)(((char *)m) - ALIGNSHIFT);
|
||||
if (*((unsigned long *)m) != 0xdeadbeefUL)
|
||||
suicide(*((unsigned long *)m));
|
||||
x += ALIGNSHIFT; nx += ALIGNSHIFT;
|
||||
#endif
|
||||
if (!(nm = realloc(m, nx))) {
|
||||
if (x > nx) x = nx;
|
||||
nm = (getmem)(nx);
|
||||
memcpy(nm, m, x);
|
||||
/* free() and not freemem(), because of the Schrodinger beef */
|
||||
free(m);
|
||||
}
|
||||
#ifdef AUDIT
|
||||
return (void *)(((char *)nm) + ALIGNSHIFT);
|
||||
#else
|
||||
return nm;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined AUDIT || defined MEM_DEBUG
|
||||
/*
|
||||
* This function frees the given block
|
||||
*/
|
||||
#ifdef MEM_DEBUG
|
||||
static void freemem_raw(void *x)
|
||||
#else
|
||||
void (freemem)(void *x)
|
||||
#endif
|
||||
{
|
||||
#ifdef AUDIT
|
||||
void *y = (void *)(((char *)x) - ALIGNSHIFT);
|
||||
|
||||
if ((*((unsigned long *)y)) != 0xdeadbeefUL)
|
||||
suicide(*((unsigned long *)y));
|
||||
*((unsigned long *)y) = 0xfeedbabeUL;
|
||||
free(y);
|
||||
#else
|
||||
free(x);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef AUDIT
|
||||
/*
|
||||
* This function copies n bytes from src to dest
|
||||
*/
|
||||
void *mmv(void *dest, void *src, size_t n)
|
||||
{
|
||||
return memcpy(dest, src, n);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function copies n bytes from src to dest
|
||||
*/
|
||||
void *mmvwo(void *dest, void *src, size_t n)
|
||||
{
|
||||
return memmove(dest, src, n);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef MEM_DEBUG
|
||||
/*
|
||||
* This function creates a new char * and fills it with a copy of src
|
||||
*/
|
||||
char *(sdup)(char *src)
|
||||
{
|
||||
size_t n = 1 + strlen(src);
|
||||
char *x = getmem(n);
|
||||
|
||||
mmv(x, src, n);
|
||||
return x;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MEM_DEBUG
|
||||
/*
|
||||
* We include here special versions of getmem(), freemem() and incmem()
|
||||
* that track allocations and are used to detect memory leaks.
|
||||
*
|
||||
* Each allocation is referenced in a list, with a serial number.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define "true" functions for applications that need pointers
|
||||
* to such functions.
|
||||
*/
|
||||
void *(getmem)(size_t n)
|
||||
{
|
||||
return getmem(n);
|
||||
}
|
||||
|
||||
void (freemem)(void *x)
|
||||
{
|
||||
freemem(x);
|
||||
}
|
||||
|
||||
void *(incmem)(void *x, size_t s, size_t ns)
|
||||
{
|
||||
return incmem(x, s, ns);
|
||||
}
|
||||
|
||||
char *(sdup)(char *s)
|
||||
{
|
||||
return sdup(s);
|
||||
}
|
||||
|
||||
static long current_serial = 0L;
|
||||
|
||||
/* must be a power of two */
|
||||
#define MEMDEBUG_MEMG 128U
|
||||
|
||||
static struct mem_track {
|
||||
void *block;
|
||||
long serial;
|
||||
char *file;
|
||||
int line;
|
||||
} *mem = 0;
|
||||
|
||||
static size_t meml = 0;
|
||||
|
||||
static unsigned int current_ptr = 0;
|
||||
|
||||
static void *true_incmem(void *x, size_t old_size, size_t new_size)
|
||||
{
|
||||
void * y = realloc(x, new_size);
|
||||
|
||||
if (y == 0) {
|
||||
y = malloc(new_size);
|
||||
if (y == 0) {
|
||||
fprintf(stderr, "ouch: malloc() failed\n");
|
||||
die();
|
||||
}
|
||||
mmv(y, x, old_size < new_size ? old_size : new_size);
|
||||
free(x);
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
static long find_free_block(void)
|
||||
{
|
||||
unsigned int n;
|
||||
size_t i;
|
||||
|
||||
for (i = 0, n = current_ptr; i < meml; i ++) {
|
||||
if (mem[n].block == 0) {
|
||||
current_ptr = n;
|
||||
return n;
|
||||
}
|
||||
n = (n + 1) & (meml - 1U);
|
||||
}
|
||||
if (meml == 0) {
|
||||
size_t j;
|
||||
|
||||
meml = MEMDEBUG_MEMG;
|
||||
mem = malloc(meml * sizeof(struct mem_track));
|
||||
current_ptr = 0;
|
||||
for (j = 0; j < meml ; j ++) mem[j].block = 0;
|
||||
} else {
|
||||
size_t j;
|
||||
|
||||
mem = true_incmem(mem, meml * sizeof(struct mem_track),
|
||||
2 * meml * sizeof(struct mem_track));
|
||||
current_ptr = meml;
|
||||
for (j = meml; j < 2 * meml ; j ++) mem[j].block = 0;
|
||||
meml *= 2;
|
||||
}
|
||||
return current_ptr;
|
||||
}
|
||||
|
||||
void *getmem_debug(size_t n, char *file, int line)
|
||||
{
|
||||
void *x = getmem_raw(n + ALIGNSHIFT);
|
||||
long i = find_free_block();
|
||||
|
||||
*(long *)x = i;
|
||||
mem[i].block = x;
|
||||
mem[i].serial = current_serial ++;
|
||||
mem[i].file = file;
|
||||
mem[i].line = line;
|
||||
return (void *)((unsigned char *)x + ALIGNSHIFT);
|
||||
}
|
||||
|
||||
void freemem_debug(void *x, char *file, int line)
|
||||
{
|
||||
void *y = (unsigned char *)x - ALIGNSHIFT;
|
||||
long i = *(long *)y;
|
||||
|
||||
if (i < 0 || (size_t)i >= meml || mem[i].block != y) {
|
||||
fprintf(stderr, "ouch: freeing free people (from %s:%d)\n",
|
||||
file, line);
|
||||
die();
|
||||
}
|
||||
mem[i].block = 0;
|
||||
freemem_raw(y);
|
||||
}
|
||||
|
||||
void *incmem_debug(void *x, size_t ol, size_t nl, char *file, int line)
|
||||
{
|
||||
void *y = getmem_debug(nl, file, line);
|
||||
mmv(y, x, ol < nl ? ol : nl);
|
||||
freemem_debug(x, file, line);
|
||||
return y;
|
||||
}
|
||||
|
||||
char *sdup_debug(char *src, char *file, int line)
|
||||
{
|
||||
size_t n = 1 + strlen(src);
|
||||
char *x = getmem_debug(n, file, line);
|
||||
|
||||
mmv(x, src, n);
|
||||
return x;
|
||||
}
|
||||
|
||||
void report_leaks(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < meml; i ++) {
|
||||
if (mem[i].block) fprintf(stderr, "leak: serial %ld, %s:%d\n",
|
||||
mem[i].serial, mem[i].file, mem[i].line);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
155
app/xrdb-cpp/mem.h
Normal file
155
app/xrdb-cpp/mem.h
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* (c) Thomas Pornin 1998 - 2002
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UCPP__MEM__
|
||||
#define UCPP__MEM__
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
void die(void);
|
||||
|
||||
#if defined AUDIT || defined MEM_CHECK || defined MEM_DEBUG
|
||||
void *getmem(size_t);
|
||||
#else
|
||||
#define getmem malloc
|
||||
#endif
|
||||
|
||||
#if defined MEM_DEBUG
|
||||
void *getmem_debug(size_t, char *, int);
|
||||
#undef getmem
|
||||
#define getmem(x) getmem_debug(x, __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
#if defined AUDIT || defined MEM_DEBUG
|
||||
void freemem(void *);
|
||||
#else
|
||||
#define freemem free
|
||||
#endif
|
||||
|
||||
#if defined MEM_DEBUG
|
||||
void freemem_debug(void *, char *, int);
|
||||
#undef freemem
|
||||
#define freemem(x) freemem_debug(x, __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
void *incmem(void *, size_t, size_t);
|
||||
char *sdup(char *);
|
||||
|
||||
#if defined MEM_DEBUG
|
||||
void *incmem_debug(void *, size_t, size_t, char *, int);
|
||||
#undef incmem
|
||||
#define incmem(x, y, z) incmem_debug(x, y, z, __FILE__, __LINE__)
|
||||
void report_leaks(void);
|
||||
char *sdup_debug(char *, char *, int);
|
||||
#define sdup(x) sdup_debug(x, __FILE__, __LINE__)
|
||||
#endif
|
||||
|
||||
#ifdef AUDIT
|
||||
void *mmv(void *, void *, size_t);
|
||||
void *mmvwo(void *, void *, size_t);
|
||||
#else
|
||||
#define mmv memcpy
|
||||
#define mmvwo memmove
|
||||
#endif
|
||||
|
||||
/*
|
||||
* this macro adds the object obj at the end of the array list, handling
|
||||
* memory allocation when needed; ptr contains the number of elements in
|
||||
* the array, and memg is the granularity of memory allocations (a power
|
||||
* of 2 is recommanded, for optimization reasons).
|
||||
*
|
||||
* list and ptr may be updated, and thus need to be lvalues.
|
||||
*/
|
||||
#define aol(list, ptr, obj, memg) do { \
|
||||
if (((ptr) % (memg)) == 0) { \
|
||||
if ((ptr) != 0) { \
|
||||
(list) = incmem((list), (ptr) * sizeof(obj), \
|
||||
((ptr) + (memg)) * sizeof(obj)); \
|
||||
} else { \
|
||||
(list) = getmem((memg) * sizeof(obj)); \
|
||||
} \
|
||||
} \
|
||||
(list)[(ptr) ++] = (obj); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* bol() does the same as aol(), but adds the new item at the beginning
|
||||
* of the list; beware, the computational cost is greater.
|
||||
*/
|
||||
#define bol(list, ptr, obj, memg) do { \
|
||||
if (((ptr) % (memg)) == 0) { \
|
||||
if ((ptr) != 0) { \
|
||||
(list) = incmem((list), (ptr) * sizeof(obj), \
|
||||
((ptr) + (memg)) * sizeof(obj)); \
|
||||
} else { \
|
||||
(list) = getmem((memg) * sizeof(obj)); \
|
||||
} \
|
||||
} \
|
||||
if ((ptr) != 0) \
|
||||
mmvwo((list) + 1, (list), (ptr) * sizeof(obj)); \
|
||||
(ptr) ++; \
|
||||
(list)[0] = (obj); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* mbol() does the same as bol(), but adds the new item at the given
|
||||
* emplacement; bol() is equivalent to mbol with 0 as last argument.
|
||||
*/
|
||||
#define mbol(list, ptr, obj, memg, n) do { \
|
||||
if (((ptr) % (memg)) == 0) { \
|
||||
if ((ptr) != 0) { \
|
||||
(list) = incmem((list), (ptr) * sizeof(obj), \
|
||||
((ptr) + (memg)) * sizeof(obj)); \
|
||||
} else { \
|
||||
(list) = getmem((memg) * sizeof(obj)); \
|
||||
} \
|
||||
} \
|
||||
if ((ptr) > n) \
|
||||
mmvwo((list) + n + 1, (list) + n, \
|
||||
((ptr) - n) * sizeof(obj)); \
|
||||
(ptr) ++; \
|
||||
(list)[n] = (obj); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* this macro adds the object obj at the end of the array list, doubling
|
||||
* the size of list when needed; as for aol(), ptr and list must be
|
||||
* lvalues, and so must be llng
|
||||
*/
|
||||
|
||||
#define wan(list, ptr, obj, llng) do { \
|
||||
if ((ptr) == (llng)) { \
|
||||
(llng) += (llng); \
|
||||
(list) = incmem((list), (ptr) * sizeof(obj), \
|
||||
(llng) * sizeof(obj)); \
|
||||
} \
|
||||
(list)[(ptr) ++] = (obj); \
|
||||
} while (0)
|
||||
|
||||
#endif
|
481
app/xrdb-cpp/nhash.c
Normal file
481
app/xrdb-cpp/nhash.c
Normal file
@ -0,0 +1,481 @@
|
||||
/*
|
||||
* Mixed hash table / binary tree code.
|
||||
* (c) Thomas Pornin 2002
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include "nhash.h"
|
||||
#include "mem.h"
|
||||
|
||||
/*
|
||||
* Hash a string into an `unsigned' value. This function is derived
|
||||
* from the hash function used in the ELF binary object file format
|
||||
* hash tables. The result size is a 32-bit number if the `unsigned'
|
||||
* type is big enough to hold 32-bit arbitrary numbers, a 16-bit number
|
||||
* otherwise.
|
||||
*/
|
||||
static unsigned hash_string(char *name)
|
||||
{
|
||||
unsigned h = 0;
|
||||
|
||||
for (h = 0; *name; name ++) {
|
||||
unsigned g;
|
||||
|
||||
h = (h << 4) + *(unsigned char *)name;
|
||||
#if UINT_MAX >= 0xffffffffU
|
||||
g = h & 0xF0000000U;
|
||||
h ^= (g >> 24);
|
||||
#else
|
||||
g = h & 0xF000U;
|
||||
h ^= (g >> 12);
|
||||
#endif
|
||||
h &= ~g;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/*
|
||||
* Each item in the table is a structure beginning with a `hash_item_header'
|
||||
* structure. Those headers define binary trees such that all left-descendants
|
||||
* (respectively right-descendants) of a given tree node have an associated
|
||||
* hash value strictly smaller (respectively greater) than the hash value
|
||||
* associated with this node.
|
||||
*
|
||||
* The `ident' field points to an array of char. The `sizeof(unsigned)'
|
||||
* first `char' contain a copy of an `unsigned' value which is the hashed
|
||||
* string, except the least significant bit. When this bit is set to 0,
|
||||
* the node contains the unique item using that hash value. If the bit
|
||||
* is set to 1, then there are several items with that hash value.
|
||||
*
|
||||
* When several items share the same hash value, they are linked together
|
||||
* in a linked list by their `left' field. The node contains no data;
|
||||
* it is a "fake item".
|
||||
*
|
||||
* The `char' following the hash value encode the item name for true items.
|
||||
* For fake items, they contain the pointer to the first true item of the
|
||||
* corresponding link list (suitably aligned).
|
||||
*
|
||||
* There are HTT_NUM_TREES trees; the items are sorted among trees by the
|
||||
* lest significant bits of their hash value.
|
||||
*/
|
||||
|
||||
static void internal_init(HTT *htt, void (*deldata)(void *), int reduced)
|
||||
{
|
||||
htt->deldata = deldata;
|
||||
if (reduced) {
|
||||
HTT2 *htt2 = (HTT2 *)htt;
|
||||
|
||||
htt2->tree[0] = htt2->tree[1] = NULL;
|
||||
} else {
|
||||
unsigned u;
|
||||
|
||||
for (u = 0; u < HTT_NUM_TREES; u ++) htt->tree[u] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
void HTT_init(HTT *htt, void (*deldata)(void *))
|
||||
{
|
||||
internal_init(htt, deldata, 0);
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
void HTT2_init(HTT2 *htt, void (*deldata)(void *))
|
||||
{
|
||||
internal_init((HTT *)htt, deldata, 1);
|
||||
}
|
||||
|
||||
#define PTR_SHIFT (sizeof(hash_item_header *) * \
|
||||
((sizeof(unsigned) + sizeof(hash_item_header *) - 1) / \
|
||||
sizeof(hash_item_header *)))
|
||||
|
||||
#define TREE(u) (*(reduced ? ((HTT2 *)htt)->tree + ((u) & 1) \
|
||||
: htt->tree + ((u) & (HTT_NUM_TREES - 1))))
|
||||
|
||||
/*
|
||||
* Find a node for the given hash value. If `father' is not NULL, fill
|
||||
* `*father' with a pointer to the node's father.
|
||||
* If the return value is NULL, then no existing node was found; if `*father'
|
||||
* is also NULL, the tree is empty. If the return value is not NULL but
|
||||
* `*father' is NULL, then the found node is the tree root.
|
||||
*
|
||||
* If `father' is not NULL, then `*leftson' is filled with 1 if the node
|
||||
* was looked for as the father left son, 0 otherwise.
|
||||
*/
|
||||
static hash_item_header *find_node(HTT *htt, unsigned u,
|
||||
hash_item_header **father, int *leftson, int reduced)
|
||||
{
|
||||
hash_item_header *node = TREE(u);
|
||||
hash_item_header *nodef = NULL;
|
||||
int ls;
|
||||
|
||||
u &= ~1U;
|
||||
while (node != NULL) {
|
||||
unsigned v = *(unsigned *)(node->ident);
|
||||
unsigned w = v & ~1U;
|
||||
|
||||
if (u == w) break;
|
||||
nodef = node;
|
||||
if (u < w) {
|
||||
node = node->left;
|
||||
ls = 1;
|
||||
} else {
|
||||
node = node->right;
|
||||
ls = 0;
|
||||
}
|
||||
}
|
||||
if (father != NULL) {
|
||||
*father = nodef;
|
||||
*leftson = ls;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static void *internal_get(HTT *htt, char *name, int reduced)
|
||||
{
|
||||
unsigned u = hash_string(name), v;
|
||||
hash_item_header *node = find_node(htt, u, NULL, NULL, reduced);
|
||||
|
||||
if (node == NULL) return NULL;
|
||||
v = *(unsigned *)(node->ident);
|
||||
if ((v & 1U) == 0) {
|
||||
return (strcmp(HASH_ITEM_NAME(node), name) == 0) ? node : NULL;
|
||||
}
|
||||
node = *(hash_item_header **)(node->ident + PTR_SHIFT);
|
||||
while (node != NULL) {
|
||||
if (strcmp(HASH_ITEM_NAME(node), name) == 0) return node;
|
||||
node = node->left;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
void *HTT_get(HTT *htt, char *name)
|
||||
{
|
||||
return internal_get(htt, name, 0);
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
void *HTT2_get(HTT2 *htt, char *name)
|
||||
{
|
||||
return internal_get((HTT *)htt, name, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make an item identifier from its name and its hash value.
|
||||
*/
|
||||
static char *make_ident(char *name, unsigned u)
|
||||
{
|
||||
size_t n = strlen(name) + 1;
|
||||
char *ident = getmem(n + sizeof(unsigned));
|
||||
|
||||
*(unsigned *)ident = u & ~1U;
|
||||
memcpy(ident + sizeof(unsigned), name, n);
|
||||
return ident;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make an identifier for a fake item, pointing to a true item.
|
||||
*/
|
||||
static char *make_fake_ident(unsigned u, hash_item_header *next)
|
||||
{
|
||||
char *ident = getmem(PTR_SHIFT + sizeof(hash_item_header *));
|
||||
|
||||
*(unsigned *)ident = u | 1U;
|
||||
*(hash_item_header **)(ident + PTR_SHIFT) = next;
|
||||
return ident;
|
||||
}
|
||||
|
||||
/*
|
||||
* Adding an item is straightforward:
|
||||
* 1. look for its emplacement
|
||||
* 2. if no node is found, use the item as a new node and link it to the tree
|
||||
* 3. if a node is found:
|
||||
* 3.1. if the node is real, check for name inequality, then create a
|
||||
* fake node and assemble the two-element linked list
|
||||
* 3.2. if the node is fake, look for the name in the list; if not found,
|
||||
* add the node at the list end
|
||||
*/
|
||||
static void *internal_put(HTT *htt, void *item, char *name, int reduced)
|
||||
{
|
||||
unsigned u = hash_string(name), v;
|
||||
int ls;
|
||||
hash_item_header *father;
|
||||
hash_item_header *node = find_node(htt, u, &father, &ls, reduced);
|
||||
hash_item_header *itemg = item, *pnode;
|
||||
|
||||
if (node == NULL) {
|
||||
itemg->left = itemg->right = NULL;
|
||||
itemg->ident = make_ident(name, u);
|
||||
if (father == NULL) {
|
||||
TREE(u) = itemg;
|
||||
} else if (ls) {
|
||||
father->left = itemg;
|
||||
} else {
|
||||
father->right = itemg;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
v = *(unsigned *)(node->ident);
|
||||
if ((v & 1U) == 0) {
|
||||
if (strcmp(HASH_ITEM_NAME(node), name) == 0)
|
||||
return node;
|
||||
pnode = getmem(sizeof *pnode);
|
||||
pnode->left = node->left;
|
||||
pnode->right = node->right;
|
||||
pnode->ident = make_fake_ident(u, node);
|
||||
node->left = itemg;
|
||||
node->right = NULL;
|
||||
itemg->left = itemg->right = NULL;
|
||||
itemg->ident = make_ident(name, u);
|
||||
if (father == NULL) {
|
||||
TREE(u) = pnode;
|
||||
} else if (ls) {
|
||||
father->left = pnode;
|
||||
} else {
|
||||
father->right = pnode;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
node = *(hash_item_header **)(node->ident + PTR_SHIFT);
|
||||
while (node != NULL) {
|
||||
if (strcmp(HASH_ITEM_NAME(node), name) == 0) return node;
|
||||
pnode = node;
|
||||
node = node->left;
|
||||
}
|
||||
itemg->left = itemg->right = NULL;
|
||||
itemg->ident = make_ident(name, u);
|
||||
pnode->left = itemg;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
void *HTT_put(HTT *htt, void *item, char *name)
|
||||
{
|
||||
return internal_put(htt, item, name, 0);
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
void *HTT2_put(HTT2 *htt, void *item, char *name)
|
||||
{
|
||||
return internal_put((HTT *)htt, item, name, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* A fake node subnode list has shrunk to one item only; make the
|
||||
* node real again.
|
||||
* fnode the fake node
|
||||
* node the last remaining node
|
||||
* father the fake node father (NULL if the fake node is root)
|
||||
* leftson 1 if the fake node is a left son, 0 otehrwise
|
||||
* u the hash value for this node
|
||||
*/
|
||||
static void shrink_node(HTT *htt, hash_item_header *fnode,
|
||||
hash_item_header *node, hash_item_header *father, int leftson,
|
||||
unsigned u, int reduced)
|
||||
{
|
||||
node->left = fnode->left;
|
||||
node->right = fnode->right;
|
||||
if (father == NULL) {
|
||||
TREE(u) = node;
|
||||
} else if (leftson) {
|
||||
father->left = node;
|
||||
} else {
|
||||
father->right = node;
|
||||
}
|
||||
freemem(fnode->ident);
|
||||
freemem(fnode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Deletion algorithm:
|
||||
* 1. look for the node; if not found, exit
|
||||
* 2. if the node is real:
|
||||
* 2.1. check for equality; exit otherwise
|
||||
* 2.2. delete the node
|
||||
* 2.3. promote the leftest of right descendants or rightest of left
|
||||
* descendants
|
||||
* 3. if the node is fake:
|
||||
* 3.1. check the list items for equality; exit otherwise
|
||||
* 3.2. delete the correct item
|
||||
* 3.3. if there remains only one item, supress the fake node
|
||||
*/
|
||||
static int internal_del(HTT *htt, char *name, int reduced)
|
||||
{
|
||||
unsigned u = hash_string(name), v;
|
||||
int ls;
|
||||
hash_item_header *father;
|
||||
hash_item_header *node = find_node(htt, u, &father, &ls, reduced);
|
||||
hash_item_header *pnode, *fnode, *znode;
|
||||
char *tmp;
|
||||
|
||||
if (node == NULL) return 0;
|
||||
v = *(unsigned *)(node->ident);
|
||||
if ((v & 1U) != 0) {
|
||||
fnode = node;
|
||||
node = znode = *(hash_item_header **)(node->ident + PTR_SHIFT);
|
||||
pnode = NULL;
|
||||
while (node != NULL) {
|
||||
if (strcmp(HASH_ITEM_NAME(node), name) == 0) break;
|
||||
pnode = node;
|
||||
node = node->left;
|
||||
}
|
||||
if (node == NULL) return 0;
|
||||
if (pnode == NULL) {
|
||||
/*
|
||||
* We supress the first item in the list.
|
||||
*/
|
||||
*(hash_item_header **)(fnode->ident + PTR_SHIFT) =
|
||||
node->left;
|
||||
if (node->left->left == NULL) {
|
||||
shrink_node(htt, fnode, node->left,
|
||||
father, ls, u, reduced);
|
||||
}
|
||||
} else {
|
||||
pnode->left = node->left;
|
||||
if (pnode->left == NULL && znode == pnode) {
|
||||
shrink_node(htt, fnode, pnode,
|
||||
father, ls, u, reduced);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (strcmp(HASH_ITEM_NAME(node), name) != 0) return 0;
|
||||
if (node->left != NULL) {
|
||||
for (znode = node, pnode = node->left; pnode->right;
|
||||
znode = pnode, pnode = pnode->right);
|
||||
if (znode != node) {
|
||||
znode->right = pnode->left;
|
||||
pnode->left = node->left;
|
||||
}
|
||||
pnode->right = node->right;
|
||||
} else if (node->right != NULL) {
|
||||
for (znode = node, pnode = node->right; pnode->left;
|
||||
znode = pnode, pnode = pnode->left);
|
||||
if (znode != node) {
|
||||
znode->left = pnode->right;
|
||||
pnode->right = node->right;
|
||||
}
|
||||
pnode->left = node->left;
|
||||
} else pnode = NULL;
|
||||
if (father == NULL) {
|
||||
TREE(u) = pnode;
|
||||
} else if (ls) {
|
||||
father->left = pnode;
|
||||
} else {
|
||||
father->right = pnode;
|
||||
}
|
||||
}
|
||||
tmp = node->ident;
|
||||
htt->deldata(node);
|
||||
freemem(tmp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
int HTT_del(HTT *htt, char *name)
|
||||
{
|
||||
return internal_del(htt, name, 0);
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
int HTT2_del(HTT2 *htt, char *name)
|
||||
{
|
||||
return internal_del((HTT *)htt, name, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply `action()' on all nodes of the tree whose root is given as
|
||||
* parameter `node'. If `wipe' is non-zero, the nodes are removed
|
||||
* from memory.
|
||||
*/
|
||||
static void scan_node(hash_item_header *node, void (*action)(void *), int wipe)
|
||||
{
|
||||
unsigned v;
|
||||
|
||||
if (node == NULL) return;
|
||||
scan_node(node->left, action, wipe);
|
||||
scan_node(node->right, action, wipe);
|
||||
v = *(unsigned *)(node->ident);
|
||||
if ((v & 1U) != 0) {
|
||||
hash_item_header *pnode, *nnode;
|
||||
|
||||
for (pnode = *(hash_item_header **)(node->ident + PTR_SHIFT);
|
||||
pnode != NULL; pnode = nnode) {
|
||||
char *tmp = pnode->ident;
|
||||
|
||||
nnode = pnode->left;
|
||||
action(pnode);
|
||||
if (wipe) freemem(tmp);
|
||||
}
|
||||
if (wipe) {
|
||||
freemem(node->ident);
|
||||
freemem(node);
|
||||
}
|
||||
} else {
|
||||
char *tmp = node->ident;
|
||||
|
||||
action(node);
|
||||
if (wipe) freemem(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
void HTT_scan(HTT *htt, void (*action)(void *))
|
||||
{
|
||||
unsigned u;
|
||||
|
||||
for (u = 0; u < HTT_NUM_TREES; u ++) {
|
||||
scan_node(htt->tree[u], action, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
void HTT2_scan(HTT2 *htt, void (*action)(void *))
|
||||
{
|
||||
scan_node(htt->tree[0], action, 0);
|
||||
scan_node(htt->tree[1], action, 0);
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
void HTT_kill(HTT *htt)
|
||||
{
|
||||
unsigned u;
|
||||
|
||||
for (u = 0; u < HTT_NUM_TREES; u ++) {
|
||||
scan_node(htt->tree[u], htt->deldata, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* see nhash.h */
|
||||
void HTT2_kill(HTT2 *htt)
|
||||
{
|
||||
scan_node(htt->tree[0], htt->deldata, 1);
|
||||
scan_node(htt->tree[1], htt->deldata, 1);
|
||||
}
|
132
app/xrdb-cpp/nhash.h
Normal file
132
app/xrdb-cpp/nhash.h
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* (c) Thomas Pornin 2002
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UCPP__NHASH__
|
||||
#define UCPP__NHASH__
|
||||
|
||||
/*
|
||||
* Each item stored in the hash table should be a structure beginning
|
||||
* with the following header.
|
||||
*/
|
||||
typedef struct hash_item_header_ {
|
||||
char *ident;
|
||||
struct hash_item_header_ *left, *right;
|
||||
} hash_item_header;
|
||||
|
||||
/*
|
||||
* This macro takes as argument a pointer to a hash table item (a
|
||||
* structure beginning with `hash_item_header') and returns a pointer to
|
||||
* the item name. This name should be considered as read-only. The
|
||||
* retrieved pointer can become invalid whenever a new item is inserted
|
||||
* in or removed from the table.
|
||||
*/
|
||||
#define HASH_ITEM_NAME(s) (((hash_item_header *)(s))->ident + sizeof(unsigned))
|
||||
|
||||
/*
|
||||
* Number of lists for the primary hash step. Can be reduced to save more
|
||||
* memory, or increased to speed things up. It should be a power of 2
|
||||
* greater or equal than 2 and smaller than UINT_MAX.
|
||||
*/
|
||||
#define HTT_NUM_TREES 128
|
||||
|
||||
/*
|
||||
* Type for a hash table.
|
||||
*/
|
||||
typedef struct {
|
||||
void (*deldata)(void *);
|
||||
hash_item_header *tree[HTT_NUM_TREES];
|
||||
} HTT;
|
||||
|
||||
/*
|
||||
* Type for a reduced version of HTT with only two binary trees. That
|
||||
* version has a lower initialization time and is suitable for situation
|
||||
* where only a limited number of elements will be stored, but new tables
|
||||
* need frequent initializations.
|
||||
*/
|
||||
typedef struct {
|
||||
void (*deldata)(void *);
|
||||
hash_item_header *tree[2];
|
||||
} HTT2;
|
||||
|
||||
/*
|
||||
* Initialize a hash table. The `deldata' parameter should point to a
|
||||
* function which will be invoked on any item removed from the table;
|
||||
* that function should take care of the release of memory allocated for
|
||||
* that item (except the hash_item_header contents, which are handled
|
||||
* internally).
|
||||
*/
|
||||
void HTT_init(HTT *htt, void (*deldata)(void *));
|
||||
|
||||
/*
|
||||
* Link an item into the hash table under the given name. If another
|
||||
* item of identical name is already present in the table, a pointer to
|
||||
* that item is returned; otherwise, the new item is linked into the
|
||||
* table and NULL is returned. The object pointed to by `item' is
|
||||
* linked from the table, but not the string pointed to by `name'.
|
||||
*/
|
||||
void *HTT_put(HTT *htt, void *item, char *name);
|
||||
|
||||
/*
|
||||
* Retrieve an item by name from the hash table. NULL is returned if
|
||||
* the object is not found.
|
||||
*/
|
||||
void *HTT_get(HTT *htt, char *name);
|
||||
|
||||
/*
|
||||
* Remove an item from the hash table. 1 is returned if the item was
|
||||
* removed, 0 if it was not found.
|
||||
*/
|
||||
int HTT_del(HTT *htt, char *name);
|
||||
|
||||
/*
|
||||
* For all items stored within the hash table, invoke the provided
|
||||
* function with the item as parameter. The function may abort the
|
||||
* scan by performing a longjmp() to a context encapsulating the
|
||||
* call to that function.
|
||||
*/
|
||||
void HTT_scan(HTT *htt, void (*action)(void *));
|
||||
|
||||
/*
|
||||
* Release the whole table contents. After a call to this function,
|
||||
* the table is ready to accept new items.
|
||||
*/
|
||||
void HTT_kill(HTT *htt);
|
||||
|
||||
/*
|
||||
* The following functions are identical to the HTT_*() functions, except
|
||||
* that they operate on the reduced HTT2 tables.
|
||||
*/
|
||||
void HTT2_init(HTT2 *htt, void (*deldata)(void *));
|
||||
void *HTT2_put(HTT2 *htt, void *item, char *name);
|
||||
void *HTT2_get(HTT2 *htt, char *name);
|
||||
int HTT2_del(HTT2 *htt, char *name);
|
||||
void HTT2_scan(HTT2 *htt, void (*action)(void *));
|
||||
void HTT2_kill(HTT2 *htt);
|
||||
|
||||
#endif
|
114
app/xrdb-cpp/sample.c
Normal file
114
app/xrdb-cpp/sample.c
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Sample code showing how to use ucpp as an integrated lexer.
|
||||
* This file is public domain.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is an example of how to use ucpp as a preprocessor and lexer
|
||||
* into another project. The steps are those described in ucpp README
|
||||
* file. To use this code, compile the ucpp source files with
|
||||
* STAND_ALONE not defined, and link them with this code. The resulting
|
||||
* binary will take a C source file as standard input, preprocess it,
|
||||
* and output each non-whitespace token on stdout, with its numerical
|
||||
* value (defined as an enum in cpp.h) and its contents. This code
|
||||
* defines no system include path.
|
||||
*
|
||||
* This code supposes that the ucpp files are compiled with PRAGMA_TOKENIZE
|
||||
* enabled (see the tune.h file).
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "mem.h"
|
||||
#include "cpp.h"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, r;
|
||||
struct lexer_state ls;
|
||||
|
||||
/* step 1 */
|
||||
init_cpp();
|
||||
|
||||
/* step 2 */
|
||||
no_special_macros = 0;
|
||||
emit_defines = emit_assertions = 0;
|
||||
|
||||
/* step 3 -- with assertions */
|
||||
init_tables(1);
|
||||
|
||||
/* step 4 -- no default include path */
|
||||
init_include_path(0);
|
||||
|
||||
/* step 5 -- no need to reset the two emit_* variables set in 2 */
|
||||
emit_dependencies = 0;
|
||||
|
||||
/* step 6 -- we work with stdin, this is not a real filename */
|
||||
set_init_filename("[stdin]", 0);
|
||||
|
||||
/* step 7 -- we make sure that assertions are on, and pragma are
|
||||
handled */
|
||||
init_lexer_state(&ls);
|
||||
init_lexer_mode(&ls);
|
||||
ls.flags |= HANDLE_ASSERTIONS | HANDLE_PRAGMA | LINE_NUM;
|
||||
|
||||
/* step 8 -- input is from stdin */
|
||||
ls.input = stdin;
|
||||
|
||||
/* step 9 -- we do not have any macro to define, but we add any
|
||||
argument as an include path */
|
||||
for (i = 1; i < argc; i ++) add_incpath(argv[i]);
|
||||
|
||||
/* step 10 -- we are a lexer and we want CONTEXT tokens */
|
||||
enter_file(&ls, ls.flags);
|
||||
|
||||
/* read tokens until end-of-input is reached -- errors (non-zero
|
||||
return values different from CPPERR_EOF) are ignored */
|
||||
while ((r = lex(&ls)) < CPPERR_EOF) {
|
||||
if (r) {
|
||||
/* error condition -- no token was retrieved */
|
||||
continue;
|
||||
}
|
||||
/* we print each token: its numerical value, and its
|
||||
string content; if this is a PRAGMA token, the
|
||||
string content is in fact a compressed token list,
|
||||
that we uncompress and print. */
|
||||
if (ls.ctok->type == PRAGMA) {
|
||||
unsigned char *c = (unsigned char *)(ls.ctok->name);
|
||||
|
||||
printf("line %ld: <#pragma>\n", ls.line);
|
||||
for (; *c; c ++) {
|
||||
int t = *c;
|
||||
|
||||
if (STRING_TOKEN(t)) {
|
||||
printf(" <%2d> ", t);
|
||||
for (c ++; *c != PRAGMA_TOKEN_END;
|
||||
c ++) putchar(*c);
|
||||
putchar('\n');
|
||||
} else {
|
||||
printf(" <%2d> `%s'\n", t,
|
||||
operators_name[t]);
|
||||
}
|
||||
}
|
||||
} else if (ls.ctok->type == CONTEXT) {
|
||||
printf("new context: file '%s', line %ld\n",
|
||||
ls.ctok->name, ls.ctok->line);
|
||||
} else if (ls.ctok->type == NEWLINE) {
|
||||
printf("[newline]\n");
|
||||
} else {
|
||||
printf("line %ld: <%2d> `%s'\n", ls.ctok->line,
|
||||
ls.ctok->type,
|
||||
STRING_TOKEN(ls.ctok->type) ? ls.ctok->name
|
||||
: operators_name[ls.ctok->type]);
|
||||
}
|
||||
}
|
||||
|
||||
/* give back memory and exit */
|
||||
wipeout();
|
||||
free_lexer_state(&ls);
|
||||
#ifdef MEM_DEBUG
|
||||
report_leaks();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
422
app/xrdb-cpp/tune.h
Normal file
422
app/xrdb-cpp/tune.h
Normal file
@ -0,0 +1,422 @@
|
||||
/*
|
||||
* (c) Thomas Pornin 1999 - 2002
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UCPP__TUNE__
|
||||
#define UCPP__TUNE__
|
||||
|
||||
#ifdef UCPP_CONFIG
|
||||
#include "config.h"
|
||||
#else
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* The LOW_MEM macro triggers the use of macro storage which uses less
|
||||
* memory. It actually also improves performance on large, modern machines
|
||||
* (due to less cache pressure). This option implies no limitation (except
|
||||
* on the number of arguments a macro may, which is then limited to 32766)
|
||||
* so it is on by default. Non-LOW_MEM code is considered deprecated.
|
||||
*/
|
||||
#define LOW_MEM
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Define AMIGA for systems using "drive letters" at the beginning of
|
||||
* some paths; define MSDOS on systems with drive letters and using
|
||||
* backslashes to seperate directory components.
|
||||
*/
|
||||
/* #define AMIGA */
|
||||
/* #define MSDOS */
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Define this if your compiler does not know the strftime() function;
|
||||
* TurboC 2.01 under Msdos does not know strftime().
|
||||
*/
|
||||
/* #define NOSTRFTIME */
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Buffering: there are two levels of buffering on input and output streams:
|
||||
* the standard libc buffering (manageable with setbuf() and setvbuf())
|
||||
* and some buffering provided by ucpp itself. The ucpp buffering uses
|
||||
* two buffers, of size respectively INPUT_BUF_MEMG and OUTPUT_BUF_MEMG
|
||||
* (as defined below).
|
||||
* You can disable one or both of these bufferings by defining the macros
|
||||
* NO_LIBC_BUF and NO_UCPP_BUF.
|
||||
*/
|
||||
/* #define NO_LIBC_BUF */
|
||||
/* #define NO_UCPP_BUF */
|
||||
|
||||
/*
|
||||
* On Unix stations, the system call mmap() might be used on input files.
|
||||
* This option is a subclause of ucpp internal buffering. On one station,
|
||||
* a 10% speed improvement was observed. Do not define this unless the
|
||||
* host architecture has the following characteristics:
|
||||
* -- Posix / Single Unix compliance
|
||||
* -- Text files correspond one to one with memory representation
|
||||
* If a file is not seekable or not mmapable, ucpp will revert to the
|
||||
* standard fread() solution.
|
||||
*
|
||||
* This feature is still considered beta quality. On some systems where
|
||||
* files can be bigger than memory address space (mainly, 32-bit systems
|
||||
* with files bigger than 4 GB), this option makes ucpp fail to operate
|
||||
* on those extremely large files.
|
||||
*/
|
||||
#define UCPP_MMAP
|
||||
|
||||
/*
|
||||
* Performance issues:
|
||||
* -- On memory-starved systems, such as Minix-i86, do not use ucpp
|
||||
* buffering; keep only libc buffering.
|
||||
* -- If you do not use libc buffering, activate the UCPP_MMAP option.
|
||||
* Note that the UCPP_MMAP option is ignored if ucpp buffering is not
|
||||
* activated.
|
||||
*
|
||||
* On an Athlon 1200 running FreeBSD 4.7, the best performances are
|
||||
* achieved when libc buffering is activated and/or UCPP_MMAP is on.
|
||||
*/
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Define this if you want ucpp to generate tokenized PRAGMA tokens;
|
||||
* otherwise, it will generate raw string contents. This setting is
|
||||
* irrelevant to the stand-alone version of ucpp.
|
||||
*/
|
||||
#define PRAGMA_TOKENIZE
|
||||
|
||||
/*
|
||||
* Define this to the special character that marks the end of tokens with
|
||||
* a string value inside a tokenized PRAGMA token. The #pragma and _Pragma()
|
||||
* directives which use this character will be a bit more difficult to
|
||||
* decode (but ucpp will not mind). 0 cannot be used. '\n' is fine because
|
||||
* it cannot appear inside a #pragma or _Pragma(), since newlines cannot be
|
||||
* embedded inside tokens, neither directly nor by macro substitution and
|
||||
* stringization. Besides, '\n' is portable.
|
||||
*/
|
||||
#define PRAGMA_TOKEN_END ((unsigned char)'\n')
|
||||
|
||||
/*
|
||||
* Define this if you want ucpp to include encountered #pragma directives
|
||||
* in its output in non-lexer mode; _Pragma() are translated to equivalent
|
||||
* #pragma directives.
|
||||
*/
|
||||
#define PRAGMA_DUMP
|
||||
|
||||
/*
|
||||
* According to my interpretation of the C99 standard, _Pragma() are
|
||||
* evaluated wherever macro expansion could take place. However, Neil Booth,
|
||||
* whose mother language is English (contrary to me) and who is well aware
|
||||
* of the C99 standard (and especially the C preprocessor) told me that
|
||||
* it was unclear whether _Pragma() are evaluated inside directives such
|
||||
* as #if, #include and #line. If you want to disable the evaluation of
|
||||
* _Pragma() inside such directives, define the following macro.
|
||||
*/
|
||||
/* #define NO_PRAGMA_IN_DIRECTIVE */
|
||||
|
||||
/*
|
||||
* The C99 standard mandates that the operator `##' must yield a single,
|
||||
* valid token, lest undefined behaviour befall upon thy head. Hence,
|
||||
* for instance, `+ ## +=' is forbidden, because `++=' is not a valid
|
||||
* token (although it is a valid list of two tokens, `++' and `=').
|
||||
* However, ucpp only emits a warning for such sin, and unmerges the
|
||||
* tokens (thus emitting `+' then `+=' for that example). When ucpp
|
||||
* produces text output, those two tokens will be separated by a space
|
||||
* character so that the basic rule of text output is preserved: when
|
||||
* parsed again, text output yields the exact same stream of tokens.
|
||||
* That extra space is virtual: it does not count as a true whitespace
|
||||
* token for stringization.
|
||||
*
|
||||
* However, it might be desirable, for some uses other than preprocessing
|
||||
* C source code, not to emit that extra space at all. To make ucpp behave
|
||||
* that way, define the DSHARP_TOKEN_MERGE macro. Please note that this
|
||||
* can trigger spurious token merging. For instance, with that macro
|
||||
* activated, `+ ## +=' will be output as `++=' which, if preprocessed
|
||||
* again, will read as `++' followed by `='.
|
||||
*
|
||||
* All this is irrelevant to lexer mode; and trying to merge incompatible
|
||||
* tokens is a shooting offence, anyway.
|
||||
*/
|
||||
/* #define DSHARP_TOKEN_MERGE */
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Define INMACRO_FLAG to include two flags to the structure lexer_state,
|
||||
* that tell whether tokens come from a macro-replacement, and count those
|
||||
* macro-replacements.
|
||||
*/
|
||||
/* #define INMACRO_FLAG */
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Paths where files are looked for by default, when #include is used.
|
||||
* Typical path is /usr/local/include and /usr/include, in that order.
|
||||
* If you want to set up no path, define the macro to 0.
|
||||
*
|
||||
* For Linux, get gcc includes too, or you will miss things like stddef.h.
|
||||
* The exact path varies much, depending on the distribution.
|
||||
*/
|
||||
#define STD_INCLUDE_PATH "/usr/local/include", "/usr/include"
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Arithmetic code for evaluation of #if expressions. Evaluation
|
||||
* uses either a native machine type, or an emulated two's complement
|
||||
* type. Division by 0 and overflow on division are considered as errors
|
||||
* and reported as such. If ARITHMETIC_CHECKS is defined, all other
|
||||
* operations that imply undefined or implementation-defined behaviour
|
||||
* are reported as warnings but otherwise performed nonetheless.
|
||||
*
|
||||
* For native type evaluation, the following macros should be defined:
|
||||
* NATIVE_SIGNED the native signed type
|
||||
* NATIVE_UNSIGNED the native corresponding unsigned type
|
||||
* NATIVE_UNSIGNED_BITS the native unsigned type width, in bits
|
||||
* NATIVE_SIGNED_MIN the native signed type minimum value
|
||||
* NATIVE_SIGNED_MAX the native signed type maximum value
|
||||
*
|
||||
* The code in the arith.c file performs some tricky detection
|
||||
* operations on the native type representation and possible existence
|
||||
* of a trap representation. These operations assume a C99-compliant
|
||||
* compiler; on a C90-only compiler, the operations are valid but may
|
||||
* yield incorrect results. You may force those settings with some
|
||||
* more macros: see the comments in arith.c (look for "ARCH_DEFINED").
|
||||
* Remember that this is mostly a non-issue, unless you are building
|
||||
* ucpp with a pre-C99 cross-compiler and either the host or target
|
||||
* architecture uses a non-two's complement representation of signed
|
||||
* integers. Such a combination is pretty rare nowadays, so the best
|
||||
* you can do is forgetting completely this paragraph and live in peace.
|
||||
*
|
||||
*
|
||||
* If you do not have a handy native type (for instance, you compile ucpp
|
||||
* with a C90 compiler which lacks the "long long" type, or you compile
|
||||
* ucpp for a cross-compiler which should support an evaluation integer
|
||||
* type of a size that is not available on the host machine), you may use
|
||||
* a simulated type. The type uses two's complement representation and
|
||||
* may have any width from 2 bits to twice the underlying native type
|
||||
* width, inclusive (odd widths are allowed). To use an emulated type,
|
||||
* make sure that NATIVE_SIGNED is not defined, and define the following
|
||||
* macros:
|
||||
* SIMUL_ARITH_SUBTYPE the native underlying type to use
|
||||
* SIMUL_SUBTYPE_BITS the native underlying type width
|
||||
* SIMUL_NUMBITS the emulated type width
|
||||
*
|
||||
* Undefined and implementation-defined behaviours are warned upon, if
|
||||
* ARITHMETIC_CHECKS is defined. Results are truncated to the type
|
||||
* width; shift count for the << and >> operators is reduced modulo the
|
||||
* emulatd type width; right shifting of a signed negative value performs
|
||||
* sign extension (the result is left-padded with bits set to 1).
|
||||
*/
|
||||
|
||||
/*
|
||||
* For native type evaluation with a 64-bit "long long" type.
|
||||
*/
|
||||
#define NATIVE_SIGNED long long
|
||||
#define NATIVE_UNSIGNED unsigned long long
|
||||
#define NATIVE_UNSIGNED_BITS 64
|
||||
#define NATIVE_SIGNED_MIN (-9223372036854775807LL - 1)
|
||||
#define NATIVE_SIGNED_MAX 9223372036854775807LL
|
||||
|
||||
/*
|
||||
* For emulation of a 64-bit type using a native 32-bit "unsigned long"
|
||||
* type.
|
||||
#undef NATIVE_SIGNED
|
||||
#define SIMUL_ARITH_SUBTYPE unsigned long
|
||||
#define SIMUL_SUBTYPE_BITS 32
|
||||
#define SIMUL_NUMBITS 64
|
||||
*/
|
||||
|
||||
/*
|
||||
* Comment out the following line if you want to deactivate arithmetic
|
||||
* checks (warnings upon undefined and implementation-defined
|
||||
* behaviour). Arithmetic checks slow down a bit arithmetic operations,
|
||||
* especially multiplications, but this should not be an issue with
|
||||
* typical C source code.
|
||||
*/
|
||||
#define ARITHMETIC_CHECKS
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* To force signedness of wide character constants, define WCHAR_SIGNEDNESS
|
||||
* to 0 for unsigned, 1 for signed. By default, wide character constants
|
||||
* are signed if the native `char' type is signed, and unsigned otherwise.
|
||||
#define WCHAR_SIGNEDNESS 0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Standard assertions. They should include one cpu() assertion, one machine()
|
||||
* assertion (identical to cpu()), and one or more system() assertions.
|
||||
*
|
||||
* for Linux/PC: cpu(i386), machine(i386), system(unix), system(linux)
|
||||
* for Linux/Alpha: cpu(alpha), machine(alpha), system(unix), system(linux)
|
||||
* for Sparc/Solaris: cpu(sparc), machine(sparc), system(unix), system(solaris)
|
||||
*
|
||||
* These are only suggestions. On Solaris, machine() should be defined
|
||||
* for i386 or sparc (standard system header use such an assertion). For
|
||||
* cross-compilation, define assertions related to the target architecture.
|
||||
*
|
||||
* If you want no standard assertion, define STD_ASSERT to 0.
|
||||
*/
|
||||
/*
|
||||
#define STD_ASSERT "cpu(i386)", "machine(i386)", "system(unix)", \
|
||||
"system(freebsd)"
|
||||
*/
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* System predefined macros. Nothing really mandatory, but some programs
|
||||
* might rely on those.
|
||||
* Each string must be either "name" or "name=token-list". If you want
|
||||
* no predefined macro, define STD_MACROS to 0.
|
||||
*/
|
||||
/*
|
||||
#define STD_MACROS "__FreeBSD=4", "__unix", "__i386", \
|
||||
"__FreeBSD__=4", "__unix__", "__i386__"
|
||||
*/
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Default flags; HANDLE_ASSERTIONS is required for Solaris system headers.
|
||||
* See cpp.h for the definition of these flags.
|
||||
*/
|
||||
#define DEFAULT_CPP_FLAGS (DISCARD_COMMENTS | WARN_STANDARD \
|
||||
| WARN_PRAGMA | FAIL_SHARP | MACRO_VAARG \
|
||||
| CPLUSPLUS_COMMENTS | LINE_NUM | TEXT_OUTPUT \
|
||||
| KEEP_OUTPUT | HANDLE_TRIGRAPHS \
|
||||
| HANDLE_ASSERTIONS)
|
||||
#define DEFAULT_LEXER_FLAGS (DISCARD_COMMENTS | WARN_STANDARD | FAIL_SHARP \
|
||||
| MACRO_VAARG | CPLUSPLUS_COMMENTS | LEXER \
|
||||
| HANDLE_TRIGRAPHS | HANDLE_ASSERTIONS)
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Define this to use sigsetjmp()/siglongjmp() instead of setjmp()/longjmp().
|
||||
* This is non-ANSI, but it improves performance on some POSIX system.
|
||||
* On typical C source code, such improvement is completely negligeable.
|
||||
*/
|
||||
/* #define POSIX_JMP */
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Maximum value (plus one) of a character handled by the lexer; 128 is
|
||||
* alright for ASCII native source code, but 256 is needed for EBCDIC.
|
||||
* 256 is safe in both cases; you will have big problems if you set
|
||||
* this value to INT_MAX or above. On Minix-i86 or Msdos (small memory
|
||||
* model), define MAX_CHAR_VAL to 128.
|
||||
*
|
||||
* Set MAX_CHAR_VAL to a power of two to increase lexing speed. Beware
|
||||
* that lexer.c defines a static array of size MSTATE * MAX_CHAR_VAL
|
||||
* values of type int (MSTATE is defined in lexer.c and is about 40).
|
||||
*/
|
||||
#define MAX_CHAR_VAL 128
|
||||
|
||||
/*
|
||||
* If you want some extra character to be considered as whitespace,
|
||||
* define this macro to that space. On ISO-8859-1 machines, 160 is
|
||||
* the code for the unbreakable space.
|
||||
*/
|
||||
/* #define UNBREAKABLE_SPACE 160 */
|
||||
|
||||
/*
|
||||
* If you want whitespace tokens contents to be recorded (making them
|
||||
* tokens with a string content), define this. The macro STRING_TOKEN
|
||||
* will be adjusted accordingly.
|
||||
* Without this option, whitespace tokens are not even returned by the
|
||||
* lex() function. This is irrelevant for the non-lexer mode (almost --
|
||||
* it might slow down a bit ucpp, and with this option, comments will be
|
||||
* kept inside #pragma directives).
|
||||
*/
|
||||
/* #define SEMPER_FIDELIS */
|
||||
|
||||
#endif
|
||||
/* End of options overridable by UCPP_CONFIG and config.h */
|
||||
|
||||
/* ====================================================================== */
|
||||
/*
|
||||
* Some constants used for memory increment granularity. Increasing these
|
||||
* values reduces the number of calls to malloc() but increases memory
|
||||
* consumption.
|
||||
*
|
||||
* Values should be powers of 2.
|
||||
*/
|
||||
|
||||
/* for cpp.c */
|
||||
#define COPY_LINE_LENGTH 80
|
||||
#define INPUT_BUF_MEMG 8192
|
||||
#define OUTPUT_BUF_MEMG 8192
|
||||
#define TOKEN_NAME_MEMG 64 /* must be at least 4 */
|
||||
#define TOKEN_LIST_MEMG 32
|
||||
#define INCPATH_MEMG 16
|
||||
#define GARBAGE_LIST_MEMG 32
|
||||
#define LS_STACK_MEMG 4
|
||||
#define FNAME_MEMG 32
|
||||
|
||||
/* ====================================================================== */
|
||||
|
||||
/* To protect the innocent. */
|
||||
#if defined(NO_UCPP_BUF) && defined(UCPP_MMAP)
|
||||
#undef UCPP_MMAP
|
||||
#endif
|
||||
|
||||
#if defined(UCPP_MMAP) || defined(POSIX_JMP)
|
||||
#ifndef _POSIX_SOURCE
|
||||
#define _POSIX_SOURCE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* C90 does not know about the "inline" keyword, but C99 does know,
|
||||
* and some C90 compilers know it as an extension. This part detects
|
||||
* these occurrences.
|
||||
*/
|
||||
|
||||
#ifndef INLINE
|
||||
|
||||
#if __STDC__ && __STDC_VERSION__ >= 199901L
|
||||
/* this is a C99 compiler, keep inline unchanged */
|
||||
#elif defined(__GNUC__)
|
||||
/* this is GNU gcc; modify inline. The semantics is not identical to C99
|
||||
but the differences are irrelevant as long as inline functions are static */
|
||||
#undef inline
|
||||
#define inline __inline__
|
||||
#elif defined(__DECC) && defined(__linux__)
|
||||
/* this is Compaq C under Linux, use __inline__ */
|
||||
#undef inline
|
||||
#define inline __inline__
|
||||
#else
|
||||
/* unknown compiler -> deactivate inline */
|
||||
#undef inline
|
||||
#define inline
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* INLINE has been set, use its value */
|
||||
#undef inline
|
||||
#define inline INLINE
|
||||
#endif
|
||||
|
||||
#endif
|
212
app/xrdb-cpp/ucpp.1
Normal file
212
app/xrdb-cpp/ucpp.1
Normal file
@ -0,0 +1,212 @@
|
||||
.TH UCPP 1 "Oct 21 2000"
|
||||
.SH NAME
|
||||
ucpp \- C preprocessor
|
||||
.SH SYNOPSIS
|
||||
.B ucpp
|
||||
[
|
||||
.I options
|
||||
]
|
||||
[
|
||||
.I file
|
||||
]
|
||||
.SH DESCRIPTION
|
||||
.LP
|
||||
.B ucpp
|
||||
is a C preprocessor mostly compatible with ISO-C99.
|
||||
It is rather strict and uses only a small amount of memory. It uses
|
||||
standard input as primary input if no file argument is given.
|
||||
.SH OPTIONS
|
||||
There are several classes of options.
|
||||
.TP
|
||||
.B Language Options
|
||||
.TP
|
||||
.BI \-C
|
||||
keep comments in the output.
|
||||
.TP
|
||||
.BI \-s
|
||||
if a rogue '#' is encountered, do not emit an error and keep it in
|
||||
the output.
|
||||
.TP
|
||||
.BI \-l
|
||||
supress the emission of '#line' directives in the output.
|
||||
.TP
|
||||
.BI \-lg
|
||||
convert the '#line' to the gcc-style equivalent.
|
||||
.TP
|
||||
.BI \-CC
|
||||
disable C++-like comments (a '//' begins a comment, up to the end
|
||||
of the line). Use this option to get closer to C90 behaviour.
|
||||
.TP
|
||||
.B \-a, \-na
|
||||
handle assertions (defined with #assert);
|
||||
.B \-a
|
||||
also defines the standard assertions
|
||||
.I #machine
|
||||
,
|
||||
.I #cpu
|
||||
and
|
||||
.I #system
|
||||
(see
|
||||
.B \-e
|
||||
to get the local definition of such assertions).
|
||||
.TP
|
||||
.BI \-a0
|
||||
disable assertion support.
|
||||
.TP
|
||||
.BI \-V
|
||||
disable support for macros with a variable number of arguments: in C99,
|
||||
a macro may be declared with
|
||||
.I ...
|
||||
as the last argument; inside the replacement list,
|
||||
.I __VA_ARGS__
|
||||
is replaced with the optional extra arguments given in the call to the macro.
|
||||
Use this option to get closer to C90 behaviour.
|
||||
.TP
|
||||
.BI \-u
|
||||
enable UTF-8 support: with this option, the source is considered as
|
||||
an ISO/10646 source, encoded in UTF-8. Characters represented as two bytes
|
||||
or more are considered as alphabetic characters, like letters, and
|
||||
therefore usable in identifiers. These characters hold the same
|
||||
syntactic value than the corresponding Universal Character Names.
|
||||
.TP
|
||||
.BI \-X
|
||||
enable
|
||||
.B \-a, \-u
|
||||
and
|
||||
.B \-Y.
|
||||
This should make
|
||||
.B ucpp
|
||||
behave closer to what is requested from a "modern" C preprocessor.
|
||||
.TP
|
||||
.BI \-c90
|
||||
enable
|
||||
.B \-V
|
||||
and
|
||||
.B \-CC,
|
||||
and do not define
|
||||
.B __STDC_VERSION__.
|
||||
This should make
|
||||
.B ucpp
|
||||
mimic older C90 behaviour.
|
||||
.TP
|
||||
.BI \-t
|
||||
disable trigraph support; this seems to be required for some legacy code.
|
||||
.TP
|
||||
.B Warning Options
|
||||
.TP
|
||||
.BI \-wt
|
||||
emit a final warning when trigraphs are encountered.
|
||||
.TP
|
||||
.BI \-wtt
|
||||
emit warnings for each trigraph encountered.
|
||||
.TP
|
||||
.BI \-wa
|
||||
emit annoying warnings (these are usually useless).
|
||||
.TP
|
||||
.BI \-w0
|
||||
supress standard warnings.
|
||||
.TP
|
||||
.B Directory Options
|
||||
.TP
|
||||
.BI \-I directory
|
||||
.TP
|
||||
.BI "\-I " directory
|
||||
add
|
||||
.I directory
|
||||
to the include path, before the standard include path.
|
||||
.TP
|
||||
.BI \-J directory
|
||||
.TP
|
||||
.BI "\-J " directory
|
||||
add
|
||||
.I directory
|
||||
to the include path, after the standard include path.
|
||||
.TP
|
||||
.BI \-zI
|
||||
do not use the standard (compile-time) include path.
|
||||
.TP
|
||||
.BI \-M
|
||||
emit only the names of encountered files, separated by spaces; this is
|
||||
intended for automatic generation of Makefile dependencies.
|
||||
.TP
|
||||
.BI \-Ma
|
||||
do the same as
|
||||
.B \-M
|
||||
but also for system files.
|
||||
.TP
|
||||
.BI "\-o " file
|
||||
direct the ouput to
|
||||
.I file
|
||||
instead of standard output.
|
||||
.TP
|
||||
.B Macro Options
|
||||
.TP
|
||||
.BI \-D macro
|
||||
predefine
|
||||
.I macro
|
||||
with content
|
||||
.B 1.
|
||||
.TP
|
||||
.BI \-D macro=def
|
||||
predefine
|
||||
.I macro
|
||||
with the content
|
||||
.I def.
|
||||
.TP
|
||||
.BI \-U macro
|
||||
undefine
|
||||
.I macro.
|
||||
.TP
|
||||
.BI \-Y
|
||||
predefine system-dependant macros.
|
||||
.TP
|
||||
.BI \-Z
|
||||
do not predefine special macros such as
|
||||
.B __TIME__.
|
||||
.TP
|
||||
.BI \-A foo(bar)
|
||||
add
|
||||
.I foo(bar)
|
||||
to the list of assertions.
|
||||
.TP
|
||||
.BI \-B foo(bar)
|
||||
remove
|
||||
.I foo(bar)
|
||||
of the list of assertions; you may also use
|
||||
.BI \-B foo
|
||||
to remove all
|
||||
.BI \-B foo(xxx)
|
||||
from the list of assertions.
|
||||
.TP
|
||||
.BI \-d
|
||||
instead of normal output, emit '#define' directives representing all
|
||||
macros defined during processing.
|
||||
.TP
|
||||
.BI \-e
|
||||
instead of normal output, emit '#assert' directives representing all
|
||||
assertions defined during processing.
|
||||
.TP
|
||||
.B Miscellaneous Options
|
||||
.TP
|
||||
.BI \-v
|
||||
print version number, include path and (optionaly) defined assertions.
|
||||
.TP
|
||||
.BI \-h
|
||||
print some help.
|
||||
.SH ENVIRONMENT
|
||||
.PP
|
||||
.B ucpp
|
||||
is not itself affected by environment variables. However, it uses
|
||||
library functions that might be affected, depending on the system.
|
||||
.SH AUTHOR
|
||||
Thomas Pornin <pornin@bolet.org>
|
||||
.SH BUGS
|
||||
.PP
|
||||
.B ucpp
|
||||
is considered stable software. However improbable it is, please report
|
||||
bugs to the author (possibly with a file that exhibits the problem) if
|
||||
the latest version, available from this site:
|
||||
.TP
|
||||
http://pornin.nerim.net/ucpp/
|
||||
.PP
|
||||
has the bug.
|
196
app/xrdb-cpp/ucppi.h
Normal file
196
app/xrdb-cpp/ucppi.h
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* (c) Thomas Pornin 1999 - 2002
|
||||
*
|
||||
* 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.
|
||||
* 4. The name of the authors may not be used to endorse or promote
|
||||
* products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef UCPP__UCPPI__
|
||||
#define UCPP__UCPPI__
|
||||
|
||||
#include "tune.h"
|
||||
#include "cpp.h"
|
||||
#include "nhash.h"
|
||||
|
||||
/*
|
||||
* A macro represented in a compact form; simple tokens are represented
|
||||
* by one byte, containing their number. Tokens with a string value are
|
||||
* followed by the value (string finished by a 0). Macro arguments are
|
||||
* followed by the argument number (in one byte -- thus implying a hard
|
||||
* limit of 254 arguments (number 255 is for __VA_ARGS__).
|
||||
*/
|
||||
struct comp_token_fifo {
|
||||
size_t length;
|
||||
size_t rp;
|
||||
unsigned char *t;
|
||||
};
|
||||
|
||||
/* These declarations are used only internally by ucpp */
|
||||
|
||||
/*
|
||||
* S_TOKEN(x) checks whether x is a token type with an embedded string
|
||||
* ttMWS(x) checks whether x is macro whitespace (space, comment...)
|
||||
* ttWHI(x) checks whether x is whitespace (MWS or newline)
|
||||
*/
|
||||
#define S_TOKEN(x) STRING_TOKEN(x)
|
||||
#define ttMWS(x) ((x) == NONE || (x) == COMMENT || (x) == OPT_NONE)
|
||||
#define ttWHI(x) (ttMWS(x) || (x) == NEWLINE)
|
||||
|
||||
/*
|
||||
* Function prototypes
|
||||
*/
|
||||
/*
|
||||
* from lexer.c
|
||||
*/
|
||||
#define init_cppm ucpp_init_cppm
|
||||
#define put_char ucpp_put_char
|
||||
#define discard_char ucpp_discard_char
|
||||
#define next_token ucpp_next_token
|
||||
#define grap_char ucpp_grap_char
|
||||
#define space_char ucpp_space_char
|
||||
|
||||
void init_cppm(void);
|
||||
void put_char(struct lexer_state *, unsigned char);
|
||||
void discard_char(struct lexer_state *);
|
||||
int next_token(struct lexer_state *);
|
||||
int grap_char(struct lexer_state *);
|
||||
int space_char(int);
|
||||
|
||||
/*
|
||||
* from assert.c
|
||||
*/
|
||||
struct assert {
|
||||
hash_item_header head; /* first field */
|
||||
size_t nbval;
|
||||
struct token_fifo *val;
|
||||
};
|
||||
|
||||
#define cmp_token_list ucpp_cmp_token_list
|
||||
#define handle_assert ucpp_handle_assert
|
||||
#define handle_unassert ucpp_handle_unassert
|
||||
#define get_assertion ucpp_get_assertion
|
||||
#define wipe_assertions ucpp_wipe_assertions
|
||||
|
||||
int cmp_token_list(struct token_fifo *, struct token_fifo *);
|
||||
int handle_assert(struct lexer_state *);
|
||||
int handle_unassert(struct lexer_state *);
|
||||
struct assert *get_assertion(char *);
|
||||
void wipe_assertions(void);
|
||||
|
||||
/*
|
||||
* from macro.c
|
||||
*/
|
||||
struct macro {
|
||||
hash_item_header head; /* first field */
|
||||
int narg;
|
||||
char **arg;
|
||||
int nest;
|
||||
int vaarg;
|
||||
#ifdef LOW_MEM
|
||||
struct comp_token_fifo cval;
|
||||
#else
|
||||
struct token_fifo val;
|
||||
#endif
|
||||
};
|
||||
|
||||
#define print_token ucpp_print_token
|
||||
#define handle_define ucpp_handle_define
|
||||
#define handle_undef ucpp_handle_undef
|
||||
#define handle_ifdef ucpp_handle_ifdef
|
||||
#define handle_ifndef ucpp_handle_ifndef
|
||||
#define substitute_macro ucpp_substitute_macro
|
||||
#define get_macro ucpp_get_macro
|
||||
#define wipe_macros ucpp_wipe_macros
|
||||
#define dsharp_lexer ucpp_dsharp_lexer
|
||||
#define compile_time ucpp_compile_time
|
||||
#define compile_date ucpp_compile_date
|
||||
#ifdef PRAGMA_TOKENIZE
|
||||
#define tokenize_lexer ucpp_tokenize_lexer
|
||||
#endif
|
||||
|
||||
void print_token(struct lexer_state *, struct token *, long);
|
||||
int handle_define(struct lexer_state *);
|
||||
int handle_undef(struct lexer_state *);
|
||||
int handle_ifdef(struct lexer_state *);
|
||||
int handle_ifndef(struct lexer_state *);
|
||||
int substitute_macro(struct lexer_state *, struct macro *,
|
||||
struct token_fifo *, int, int, long);
|
||||
struct macro *get_macro(char *);
|
||||
void wipe_macros(void);
|
||||
|
||||
extern struct lexer_state dsharp_lexer;
|
||||
extern char compile_time[], compile_date[];
|
||||
#ifdef PRAGMA_TOKENIZE
|
||||
extern struct lexer_state tokenize_lexer;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* from eval.c
|
||||
*/
|
||||
#define strtoconst ucpp_strtoconst
|
||||
#define eval_expr ucpp_eval_expr
|
||||
#define eval_line ucpp_eval_line
|
||||
|
||||
unsigned long strtoconst(char *);
|
||||
unsigned long eval_expr(struct token_fifo *, int *, int);
|
||||
extern long eval_line;
|
||||
|
||||
#define eval_exception ucpp_eval_exception
|
||||
|
||||
#ifdef POSIX_JMP
|
||||
#define JMP_BUF sigjmp_buf
|
||||
#define catch(x) sigsetjmp((x), 0)
|
||||
#define throw(x) siglongjmp((x), 1)
|
||||
#else
|
||||
#define JMP_BUF jmp_buf
|
||||
#define catch(x) setjmp((x))
|
||||
#define throw(x) longjmp((x), 1)
|
||||
#endif
|
||||
extern JMP_BUF eval_exception;
|
||||
|
||||
/*
|
||||
* from cpp.c
|
||||
*/
|
||||
#define token_name ucpp_token_name
|
||||
#define throw_away ucpp_throw_away
|
||||
#define garbage_collect ucpp_garbage_collect
|
||||
#define init_buf_lexer_state ucpp_init_buf_lexer_state
|
||||
#ifdef PRAGMA_TOKENIZE
|
||||
#define compress_token_list ucpp_compress_token_list
|
||||
#endif
|
||||
|
||||
char *token_name(struct token *);
|
||||
void throw_away(struct garbage_fifo *, char *);
|
||||
void garbage_collect(struct garbage_fifo *);
|
||||
void init_buf_lexer_state(struct lexer_state *, int);
|
||||
#ifdef PRAGMA_TOKENIZE
|
||||
struct comp_token_fifo compress_token_list(struct token_fifo *);
|
||||
#endif
|
||||
|
||||
#define ouch ucpp_ouch
|
||||
#define error ucpp_error
|
||||
#define warning ucpp_warning
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user