Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
dholland | b55a0f6c5c |
|
@ -0,0 +1,4 @@
|
|||
repo: 67fa1db0651cd970068d0660e1b695e30b04f904
|
||||
node: 9aa91d3fe3a39cb8af08f231ba22a3aa1bbd57eb
|
||||
branch: default
|
||||
tag: release-0.5.3
|
|
@ -0,0 +1,9 @@
|
|||
8a955e3dda2ce67fd729944f4e19316d005c0731 posted-20101220
|
||||
1e4eef5bf88d70a98396b175cd0891a41d79388e release-0.1
|
||||
3ad1cd80f5a07b0ce19131f3e58f2560e4a30d9d release-0.2
|
||||
31fc4251ec3bd624af9d00592b7a9ec9d22a611a release-0.3
|
||||
85b66cc0344e6222c92b8dd324542ec6f64239e9 release-0.3.1
|
||||
281317d304782fe3d60f4786a1480fe5ce485ebd release-0.4
|
||||
557824449ec7df3d63b491efbf53c9b73589346d release-0.5
|
||||
ab06d46bf5cc46cdacba18d82a6b380bfe09d81e release-0.5.1
|
||||
18b872f362175fd78ddf1f12ee24f85ef19b6254 release-0.5.2
|
|
@ -0,0 +1,91 @@
|
|||
release 0.5.3 (20190121)
|
||||
- Fix markup typo in the man page.
|
||||
- Abort on line numbering or column numbering overflow. Line
|
||||
numbers are limited to values that fit in "unsigned int". Also
|
||||
reject input lines longer than 2^32-1 characters. It seems
|
||||
reasonable to presume that any input that violates these
|
||||
constraints is someone screwing around and not a serious attempt
|
||||
to compile or preprocess anything useful. Done in response to
|
||||
n2129, but without getting into any of the silliness found there.
|
||||
- Recognize __ia64__ for IA64 builds.
|
||||
- Recognize __aarch64__ for 64-bit ARM builds, as sent in by
|
||||
various people.
|
||||
- Recognize __riscv__ and __riscv64__ for risc-v builds.
|
||||
|
||||
release 0.5.2 (20160904)
|
||||
- Fix typo in -U usage message, noticed by Joerg.
|
||||
- Add a -debuglog option to send an execution trace to a file.
|
||||
Intended to be used when debugging imake templates and other
|
||||
complex input, not for debugging tradcpp itself.
|
||||
|
||||
release 0.5.1 (20150612)
|
||||
- Fix a stupid regression in 0.5 that causes it to not recognize a
|
||||
pile of options.
|
||||
- Fix output corruption caused by mishandling which macros are
|
||||
currently in use. In particular, "curmacro" is only valid while
|
||||
we're parsing a macro name and arguments, and can change once we
|
||||
start expanding, so don't use it to clear the in-use flag. This
|
||||
problem has been around all along but was only just exposed.
|
||||
- Also don't set curmacro to null after calling expand_domacro as
|
||||
that can cause us to think a macro name we just read is defined().
|
||||
This one was introduced in 0.5.
|
||||
- Don't use "remove" as a local variable as gcc 4.1 gets upset
|
||||
about it vs. remove(3) in stdio.h.
|
||||
|
||||
release 0.5 (20150612)
|
||||
- Don't report unclosed comments as "No newline at end of file".
|
||||
- Don't rely on <stdbool.h> existing, as (predictably) it doesn't
|
||||
work on Solaris.
|
||||
- Similarly, don't rely on C11 anonymous unions as the Solaris
|
||||
compiler vomits on them.
|
||||
- Typo fix in man page from Jason McIntyre; and change "Usage" to
|
||||
"usage" in usage for pedantic reasons, from Igor Sobrado.
|
||||
- Accept "-" as either input or output file name to mean stdin or
|
||||
stdout respectively. Suggested by Jonathan Gray.
|
||||
- Fix output spacing behavior to match gcc when newlines appear in or
|
||||
while looking for macro arguments. Partly from Joerg Sonnenberger.
|
||||
- Implement __FILE__ and __LINE__ macros. Mostly from Joerg Sonnenberger.
|
||||
- Implement #line. Partly from Joerg Sonnenberger.
|
||||
- Declare usage() with PF(). From wiz.
|
||||
|
||||
release 0.4 (20130713)
|
||||
- Fix stupid build problem introduced in 0.3.1.
|
||||
- Accept and ignore -m32, which imake issues willy-nilly on a bunch
|
||||
of platforms. I thought this had already been done, but apparently
|
||||
not.
|
||||
- Don't use the <err.h> functions. There are still people out there
|
||||
using legacy systems missing them.
|
||||
- Sort out some more issues pertaining to handling quoted strings.
|
||||
- Add some more tests.
|
||||
|
||||
release 0.3.1 (20130709)
|
||||
- Don't leak memory and assert if a bad command-line option comes
|
||||
after a -D or a -include foo.
|
||||
- Since imake is a principal application for tradcpp and imake carefully
|
||||
hides what it's doing when you run it, when rejecting an invalid option
|
||||
be sure to report *what* that option is.
|
||||
|
||||
release 0.3 (20130616)
|
||||
- Don't eval the control expression of the first #if of a block when
|
||||
already in a false block; it might not be valid. Reported by
|
||||
Baptiste Daroussin.
|
||||
- Don't recognize comments within character constants.
|
||||
- Don't recognize macro argument parentheses or commas within strings,
|
||||
or within character constants either.
|
||||
|
||||
release 0.2 (20130611)
|
||||
- auto-recognize more builtin PowerPC and mips macros
|
||||
- pass -Wunused (partly from Baptiste Daroussin)
|
||||
- allow absolute paths in include files (partly from Baptiste Daroussin)
|
||||
- don't use getprogname() in the name of portability
|
||||
- add tests arising from December 2010 tech-toolchain thread (one
|
||||
from der Mouse, one of mine)
|
||||
- clean out usage of sys/cdefs.h macros and don't use the implementation
|
||||
namespace
|
||||
- make -Wcomment work again
|
||||
- fix handling of relative includes
|
||||
- provide a man page
|
||||
- other minor improvements
|
||||
|
||||
release 0.1 (20130610)
|
||||
- first release, works with at least some imake templates
|
|
@ -0,0 +1,11 @@
|
|||
# $NetBSD: Makefile,v 1.1.1.1 2022/08/27 21:46:47 dholland Exp $
|
||||
|
||||
PROG= tradcpp
|
||||
SRCS= main.c \
|
||||
files.c directive.c eval.c macro.c output.c \
|
||||
place.c array.c utils.c
|
||||
WARNS= 5
|
||||
|
||||
#DBG=-g
|
||||
|
||||
.include <bsd.prog.mk>
|
|
@ -0,0 +1,37 @@
|
|||
not implemented:
|
||||
- mode.input_allow_dollars.
|
||||
- column counts do not take tabstops into account.
|
||||
- mode.output_linenumbers.
|
||||
- mode.do_depend.
|
||||
- mode.do_macrolist.
|
||||
- mode.do_trace.
|
||||
- warns.endiflabels. (they cause errors)
|
||||
- warns.unused.
|
||||
- the -iremap option.
|
||||
- $CPP_RESTRICTED
|
||||
- other environment variables
|
||||
|
||||
tidy up:
|
||||
- get rid of inlinedefs.h
|
||||
- use of places in and below macro.c is pretty bogus.
|
||||
- macro code should be reworked.
|
||||
- place_changefile is manky and wastes memory. Also, in an ideal
|
||||
world we'd remember the place #line changed the name and refer
|
||||
to it when printing errors.
|
||||
|
||||
fix:
|
||||
- "#if 0 && 1/0" should not crash; fix eval method.
|
||||
- quote characters and comment delimiters that are emitted by
|
||||
macros are not recognized. See:
|
||||
t34 (should produce a quote and FOO Q)
|
||||
t35 (similarly, this test may be redundant once it's fixed)
|
||||
t36 (C(3) should produce nothing)
|
||||
t37 (BC foo EC should produce nothing)
|
||||
Joerg says comments like in t36 should be stripped exactly
|
||||
twice, once when the macro is defined and again when it's
|
||||
expanded. Note that gcc's cpp -traditional is getting t37
|
||||
wrong, and it gets t36 wrong with -C.
|
||||
- remove the intentionally undocumented -p option and generate
|
||||
proper linenumber output. (also, in this code what happens if
|
||||
a comment spans files? I bet currently it will emit the line
|
||||
number into the comment.)
|
|
@ -0,0 +1,115 @@
|
|||
/*-
|
||||
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ARRAYINLINE
|
||||
#include "array.h"
|
||||
|
||||
struct array *
|
||||
array_create(void)
|
||||
{
|
||||
struct array *a;
|
||||
|
||||
a = domalloc(sizeof(*a));
|
||||
array_init(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
void
|
||||
array_destroy(struct array *a)
|
||||
{
|
||||
array_cleanup(a);
|
||||
dofree(a, sizeof(*a));
|
||||
}
|
||||
|
||||
void
|
||||
array_init(struct array *a)
|
||||
{
|
||||
a->num = a->max = 0;
|
||||
a->v = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
array_cleanup(struct array *a)
|
||||
{
|
||||
arrayassert(a->num == 0);
|
||||
dofree(a->v, a->max * sizeof(a->v[0]));
|
||||
#ifdef ARRAYS_CHECKED
|
||||
a->v = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
array_setsize(struct array *a, unsigned num)
|
||||
{
|
||||
unsigned newmax;
|
||||
void **newptr;
|
||||
|
||||
if (num > a->max) {
|
||||
newmax = a->max;
|
||||
while (num > newmax) {
|
||||
newmax = newmax ? newmax*2 : 4;
|
||||
}
|
||||
newptr = dorealloc(a->v, a->max * sizeof(a->v[0]),
|
||||
newmax * sizeof(a->v[0]));
|
||||
a->v = newptr;
|
||||
a->max = newmax;
|
||||
}
|
||||
a->num = num;
|
||||
}
|
||||
|
||||
void
|
||||
array_insert(struct array *a, unsigned index_)
|
||||
{
|
||||
unsigned movers;
|
||||
|
||||
arrayassert(a->num <= a->max);
|
||||
arrayassert(index_ < a->num);
|
||||
|
||||
movers = a->num - index_;
|
||||
|
||||
array_setsize(a, a->num + 1);
|
||||
|
||||
memmove(a->v + index_+1, a->v + index_, movers*sizeof(*a->v));
|
||||
}
|
||||
|
||||
void
|
||||
array_remove(struct array *a, unsigned index_)
|
||||
{
|
||||
unsigned movers;
|
||||
|
||||
arrayassert(a->num <= a->max);
|
||||
arrayassert(index_ < a->num);
|
||||
|
||||
movers = a->num - (index_ + 1);
|
||||
memmove(a->v + index_, a->v + index_+1, movers*sizeof(*a->v));
|
||||
a->num--;
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
/*-
|
||||
* Copyright (c) 2009 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#include "inlinedefs.h" // XXX
|
||||
#include "utils.h"
|
||||
|
||||
#define ARRAYS_CHECKED
|
||||
|
||||
#ifdef ARRAYS_CHECKED
|
||||
#include <assert.h>
|
||||
#define arrayassert assert
|
||||
#else
|
||||
#define arrayassert(x) ((void)(x))
|
||||
#endif
|
||||
|
||||
#ifndef ARRAYINLINE
|
||||
#define ARRAYINLINE C99INLINE
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// type and base operations
|
||||
|
||||
struct array {
|
||||
void **v;
|
||||
unsigned num, max;
|
||||
};
|
||||
|
||||
struct array *array_create(void);
|
||||
void array_destroy(struct array *);
|
||||
void array_init(struct array *);
|
||||
void array_cleanup(struct array *);
|
||||
ARRAYINLINE unsigned array_num(const struct array *);
|
||||
ARRAYINLINE void *array_get(const struct array *, unsigned index_);
|
||||
ARRAYINLINE void array_set(const struct array *, unsigned index_, void *val);
|
||||
void array_setsize(struct array *, unsigned num);
|
||||
ARRAYINLINE void array_add(struct array *, void *val, unsigned *index_ret);
|
||||
void array_insert(struct array *a, unsigned index_);
|
||||
void array_remove(struct array *a, unsigned index_);
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// inlining for base operations
|
||||
|
||||
ARRAYINLINE unsigned
|
||||
array_num(const struct array *a)
|
||||
{
|
||||
return a->num;
|
||||
}
|
||||
|
||||
ARRAYINLINE void *
|
||||
array_get(const struct array *a, unsigned index_)
|
||||
{
|
||||
arrayassert(index_ < a->num);
|
||||
return a->v[index_];
|
||||
}
|
||||
|
||||
ARRAYINLINE void
|
||||
array_set(const struct array *a, unsigned index_, void *val)
|
||||
{
|
||||
arrayassert(index_ < a->num);
|
||||
a->v[index_] = val;
|
||||
}
|
||||
|
||||
ARRAYINLINE void
|
||||
array_add(struct array *a, void *val, unsigned *index_ret)
|
||||
{
|
||||
unsigned index_ = a->num;
|
||||
array_setsize(a, index_+1);
|
||||
a->v[index_] = val;
|
||||
if (index_ret != NULL) {
|
||||
*index_ret = index_;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// bits for declaring and defining typed arrays
|
||||
|
||||
/*
|
||||
* Usage:
|
||||
*
|
||||
* DECLARRAY_BYTYPE(foo, bar, INLINE) declares "struct foo", which is
|
||||
* an array of pointers to "bar", plus the operations on it.
|
||||
*
|
||||
* DECLARRAY(foo, INLINE) is equivalent to
|
||||
* DECLARRAY_BYTYPE(fooarray, struct foo, INLINE).
|
||||
*
|
||||
* DEFARRAY_BYTYPE and DEFARRAY are the same as DECLARRAY except that
|
||||
* they define the operations.
|
||||
*
|
||||
* The argument INLINE can be used as follows:
|
||||
*
|
||||
* 1. For no inlining:
|
||||
* In foo.h:
|
||||
* DECLARRAY(foo, );
|
||||
* In foo.c:
|
||||
* DEFARRAY(foo, );
|
||||
*
|
||||
* 2. To be file-static:
|
||||
* In foo.c:
|
||||
* DECLARRAY(foo, static);
|
||||
* DEFARRAY(foo, static);
|
||||
*
|
||||
* 3. To inline using C99:
|
||||
* In foo.h:
|
||||
* DECLARRAY(foo, inline);
|
||||
* DEFARRAY(foo, inline);
|
||||
*
|
||||
* 4. To inline with old gcc:
|
||||
* In foo.h:
|
||||
* #ifndef FOO_INLINE
|
||||
* #define FOO_INLINE extern inline
|
||||
* #endif
|
||||
* DECLARRAY(foo, );
|
||||
* DEFARRAY(foo, FOO_INLINE);
|
||||
* In foo.c:
|
||||
* #define FOO_INLINE
|
||||
* #include "foo.h"
|
||||
*
|
||||
* 5. To inline such that it works both with old gcc and C99:
|
||||
* In foo.h:
|
||||
* #ifndef FOO_INLINE
|
||||
* #define FOO_INLINE extern inline
|
||||
* #endif
|
||||
* DECLARRAY(foo, FOO_INLINE);
|
||||
* DEFARRAY(foo, FOO_INLINE);
|
||||
* In foo.c:
|
||||
* #define FOO_INLINE
|
||||
* #include "foo.h"
|
||||
*
|
||||
* The mechanism in case (4) ensures that an externally linkable
|
||||
* definition exists.
|
||||
*/
|
||||
|
||||
#define DECLARRAY_BYTYPE(ARRAY, T, INLINE) \
|
||||
struct ARRAY { \
|
||||
struct array arr; \
|
||||
}; \
|
||||
\
|
||||
INLINE struct ARRAY *ARRAY##_create(void); \
|
||||
INLINE void ARRAY##_destroy(struct ARRAY *a); \
|
||||
INLINE void ARRAY##_init(struct ARRAY *a); \
|
||||
INLINE void ARRAY##_cleanup(struct ARRAY *a); \
|
||||
INLINE unsigned ARRAY##_num(const struct ARRAY *a); \
|
||||
INLINE T *ARRAY##_get(const struct ARRAY *a, unsigned index_); \
|
||||
INLINE void ARRAY##_set(struct ARRAY *a, unsigned index_, T *val); \
|
||||
INLINE void ARRAY##_setsize(struct ARRAY *a, unsigned num); \
|
||||
INLINE void ARRAY##_add(struct ARRAY *a, T *val, unsigned *index_ret);\
|
||||
INLINE void ARRAY##_insert(struct ARRAY *a, unsigned index_); \
|
||||
INLINE void ARRAY##_remove(struct ARRAY *a, unsigned index_)
|
||||
|
||||
|
||||
#define DEFARRAY_BYTYPE(ARRAY, T, INLINE) \
|
||||
INLINE void \
|
||||
ARRAY##_init(struct ARRAY *a) \
|
||||
{ \
|
||||
array_init(&a->arr); \
|
||||
} \
|
||||
\
|
||||
INLINE void \
|
||||
ARRAY##_cleanup(struct ARRAY *a) \
|
||||
{ \
|
||||
array_cleanup(&a->arr); \
|
||||
} \
|
||||
\
|
||||
INLINE struct \
|
||||
ARRAY *ARRAY##_create(void) \
|
||||
{ \
|
||||
struct ARRAY *a; \
|
||||
\
|
||||
a = domalloc(sizeof(*a)); \
|
||||
ARRAY##_init(a); \
|
||||
return a; \
|
||||
} \
|
||||
\
|
||||
INLINE void \
|
||||
ARRAY##_destroy(struct ARRAY *a) \
|
||||
{ \
|
||||
ARRAY##_cleanup(a); \
|
||||
dofree(a, sizeof(*a)); \
|
||||
} \
|
||||
\
|
||||
INLINE unsigned \
|
||||
ARRAY##_num(const struct ARRAY *a) \
|
||||
{ \
|
||||
return array_num(&a->arr); \
|
||||
} \
|
||||
\
|
||||
INLINE T * \
|
||||
ARRAY##_get(const struct ARRAY *a, unsigned index_) \
|
||||
{ \
|
||||
return (T *)array_get(&a->arr, index_); \
|
||||
} \
|
||||
\
|
||||
INLINE void \
|
||||
ARRAY##_set(struct ARRAY *a, unsigned index_, T *val) \
|
||||
{ \
|
||||
array_set(&a->arr, index_, (void *)val); \
|
||||
} \
|
||||
\
|
||||
INLINE void \
|
||||
ARRAY##_setsize(struct ARRAY *a, unsigned num) \
|
||||
{ \
|
||||
array_setsize(&a->arr, num); \
|
||||
} \
|
||||
\
|
||||
INLINE void \
|
||||
ARRAY##_add(struct ARRAY *a, T *val, unsigned *ret) \
|
||||
{ \
|
||||
array_add(&a->arr, (void *)val, ret); \
|
||||
} \
|
||||
\
|
||||
INLINE void \
|
||||
ARRAY##_insert(struct ARRAY *a, unsigned index_) \
|
||||
{ \
|
||||
array_insert(&a->arr, index_); \
|
||||
} \
|
||||
\
|
||||
INLINE void \
|
||||
ARRAY##_remove(struct ARRAY *a, unsigned index_) \
|
||||
{ \
|
||||
array_remove(&a->arr, index_); \
|
||||
}
|
||||
|
||||
#define DECLARRAY(T, INLINE) DECLARRAY_BYTYPE(T##array, struct T, INLINE)
|
||||
#define DEFARRAY(T, INLINE) DEFARRAY_BYTYPE(T##array, struct T, INLINE)
|
||||
|
||||
#define DESTROYALL_ARRAY(T, INLINE) \
|
||||
INLINE void T##array_destroyall(struct T##array *arr); \
|
||||
\
|
||||
INLINE void \
|
||||
T##array_destroyall(struct T##array *arr) \
|
||||
{ \
|
||||
unsigned i, num; \
|
||||
struct T *t; \
|
||||
\
|
||||
num = T##array_num(arr); \
|
||||
for (i=0; i<num; i++) { \
|
||||
t = T##array_get(arr, i); \
|
||||
T##_destroy(t); \
|
||||
} \
|
||||
T##array_setsize(arr, 0); \
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// basic array types
|
||||
|
||||
DECLARRAY_BYTYPE(stringarray, char, ARRAYINLINE);
|
||||
DEFARRAY_BYTYPE(stringarray, char, ARRAYINLINE);
|
||||
|
||||
#endif /* ARRAY_H */
|
|
@ -0,0 +1,41 @@
|
|||
/*-
|
||||
* Copyright (c) 2015 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 BOOL_H
|
||||
#define BOOL_H
|
||||
|
||||
#if __STDC__ > 199901
|
||||
#include <stdbool.h>
|
||||
#else
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
#endif /* BOOL_H */
|
|
@ -0,0 +1,174 @@
|
|||
/*-
|
||||
* Copyright (c) 2010, 2013 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Config for predefined macros. If this doesn't do what you want you
|
||||
* can set any or all of the CONFIG_ defines from the compiler command
|
||||
* line; or patch the list in main.c; or both.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Paths
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_LOCALINCLUDE
|
||||
#define CONFIG_LOCALINCLUDE "/usr/local/include"
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_SYSTEMINCLUDE
|
||||
#define CONFIG_SYSTEMINCLUDE "/usr/include"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Operating system
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_OS
|
||||
#if defined(__NetBSD__)
|
||||
#define CONFIG_OS "__NetBSD__"
|
||||
#define CONFIG_OS_2 "__unix__"
|
||||
#elif defined(__FreeBSD__)
|
||||
#define CONFIG_OS "__FreeBSD__"
|
||||
#define CONFIG_OS_2 "__unix__"
|
||||
#elif defined(__OpenBSD__)
|
||||
#define CONFIG_OS "__OpenBSD__"
|
||||
#define CONFIG_OS_2 "__unix__"
|
||||
#elif defined(__DragonFly__)
|
||||
#define CONFIG_OS "__DragonFly__"
|
||||
#define CONFIG_OS_2 "__unix__"
|
||||
#elif defined(__bsdi__)
|
||||
#define CONFIG_OS "__bsdi__"
|
||||
#define CONFIG_OS_2 "__unix__"
|
||||
#elif defined(__sun)
|
||||
#define CONFIG_OS "__sun"
|
||||
#define CONFIG_OS_2 "__unix__"
|
||||
#elif defined(__sgi)
|
||||
#define CONFIG_OS "__sgi"
|
||||
#define CONFIG_OS_2 "__unix__"
|
||||
#elif defined(__SVR4)
|
||||
#define CONFIG_OS "__SVR4"
|
||||
#define CONFIG_OS_2 "__unix__"
|
||||
#elif defined(__APPLE__)
|
||||
#define CONFIG_OS "__APPLE__"
|
||||
#define CONFIG_OS_2 "__unix__"
|
||||
#elif defined(__linux__)
|
||||
#define CONFIG_OS "__linux__"
|
||||
#elif defined(__CYGWIN__)
|
||||
#define CONFIG_OS "__CYGWIN__"
|
||||
#elif defined(__INTERIX)
|
||||
#define CONFIG_OS "__INTERIX"
|
||||
#elif defined(__MINGW32)
|
||||
#define CONFIG_OS "__MINGW32"
|
||||
#else
|
||||
/* we could error... but let's instead assume generic unix */
|
||||
#define CONFIG_OS "__unix__"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* CPU
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_CPU
|
||||
#if defined(__x86_64__)
|
||||
#define CONFIG_CPU "__x86_64__"
|
||||
#define CONFIG_CPU_2 "__amd64__"
|
||||
#elif defined(__i386__) || defined(__i386)
|
||||
#define CONFIG_CPU "__i386__"
|
||||
#define CONFIG_CPU_2 "__i386"
|
||||
#elif defined(__sparc)
|
||||
#define CONFIG_CPU "__sparc"
|
||||
#elif defined(__mips)
|
||||
#define CONFIG_CPU "__mips"
|
||||
#elif defined(__mips__)
|
||||
#define CONFIG_CPU "__mips__"
|
||||
#elif defined(__mipsel__)
|
||||
#define CONFIG_CPU "__mipsel__"
|
||||
#elif defined(__POWERPC__)
|
||||
#define CONFIG_CPU "__POWERPC__"
|
||||
#elif defined(__POWERPC__)
|
||||
#define CONFIG_CPU "__powerpc__"
|
||||
#elif defined(__PPC__)
|
||||
#define CONFIG_CPU "__PPC__"
|
||||
#elif defined(__ppc__)
|
||||
#define CONFIG_CPU "__ppc__"
|
||||
#elif defined(__PPC64__)
|
||||
#define CONFIG_CPU "__PPC64__"
|
||||
#elif defined(__ppc64__)
|
||||
#define CONFIG_CPU "__ppc64__"
|
||||
#elif defined(__ARM__)
|
||||
#define CONFIG_CPU "__ARM__"
|
||||
#elif defined(__AARCH64__)
|
||||
#define CONFIG_CPU "__AARCH64__"
|
||||
#elif defined(__aarch64__)
|
||||
#define CONFIG_CPU "__aarch64__"
|
||||
#elif defined(__RISCV__)
|
||||
#define CONFIG_CPU "__RISCV__"
|
||||
#elif defined(__riscv__)
|
||||
#define CONFIG_CPU "__riscv__"
|
||||
#elif defined(__RISCV64__)
|
||||
#define CONFIG_CPU "__RISCV64__"
|
||||
#elif defined(__riscv64__)
|
||||
#define CONFIG_CPU "__riscv64__"
|
||||
#elif defined(__riscv64)
|
||||
#define CONFIG_CPU "__riscv64"
|
||||
#elif defined(__ia64__)
|
||||
#define CONFIG_CPU "__ia64__"
|
||||
#else
|
||||
/* let it go */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Other stuff
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_SIZE
|
||||
#ifdef __LP64__
|
||||
#define CONFIG_SIZE "__LP64__"
|
||||
#else
|
||||
#define CONFIG_SIZE "__ILP32__"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BINFMT
|
||||
#ifdef __ELF__
|
||||
#define CONFIG_BINFMT "__ELF__"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We are __TRADCPP__ by default, but if you want to masquerade as
|
||||
* some other compiler this is a convenient place to change it.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_COMPILER
|
||||
#define CONFIG_COMPILER "__TRADCPP__"
|
||||
#define CONFIG_COMPILER_MINOR "__TRADCPP_MINOR__"
|
||||
#endif
|
|
@ -0,0 +1,733 @@
|
|||
/*-
|
||||
* Copyright (c) 2010, 2013 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "bool.h"
|
||||
#include "utils.h"
|
||||
#include "mode.h"
|
||||
#include "place.h"
|
||||
#include "files.h"
|
||||
#include "directive.h"
|
||||
#include "macro.h"
|
||||
#include "eval.h"
|
||||
#include "output.h"
|
||||
|
||||
struct ifstate {
|
||||
struct ifstate *prev;
|
||||
struct place startplace;
|
||||
bool curtrue;
|
||||
bool evertrue;
|
||||
bool seenelse;
|
||||
};
|
||||
|
||||
static struct ifstate *ifstate;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// common parsing bits
|
||||
|
||||
static
|
||||
void
|
||||
uncomment(char *buf)
|
||||
{
|
||||
char *s, *t, *u = NULL;
|
||||
bool incomment = false;
|
||||
bool inesc = false;
|
||||
bool inquote = false;
|
||||
char quote = '\0';
|
||||
|
||||
for (s = t = buf; *s; s++) {
|
||||
if (incomment) {
|
||||
if (s[0] == '*' && s[1] == '/') {
|
||||
s++;
|
||||
incomment = false;
|
||||
}
|
||||
} else {
|
||||
if (!inquote && s[0] == '/' && s[1] == '*') {
|
||||
incomment = true;
|
||||
} else {
|
||||
if (inesc) {
|
||||
inesc = false;
|
||||
} else if (s[0] == '\\') {
|
||||
inesc = true;
|
||||
} else if (!inquote &&
|
||||
(s[0] == '"' || s[0] == '\'')) {
|
||||
inquote = true;
|
||||
quote = s[0];
|
||||
} else if (inquote && s[0] == quote) {
|
||||
inquote = false;
|
||||
}
|
||||
|
||||
if (t != s) {
|
||||
*t = *s;
|
||||
}
|
||||
if (!strchr(ws, *t)) {
|
||||
u = t;
|
||||
}
|
||||
t++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (u) {
|
||||
/* end string after last non-whitespace char */
|
||||
u[1] = '\0';
|
||||
} else {
|
||||
*t = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
oneword(const char *what, struct place *p2, char *line)
|
||||
{
|
||||
size_t pos;
|
||||
|
||||
pos = strcspn(line, ws);
|
||||
if (line[pos] != '\0') {
|
||||
place_addcolumns(p2, pos);
|
||||
complain(p2, "Garbage after %s argument", what);
|
||||
complain_fail();
|
||||
line[pos] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// if handling
|
||||
|
||||
static
|
||||
struct ifstate *
|
||||
ifstate_create(struct ifstate *prev, struct place *p, bool startstate)
|
||||
{
|
||||
struct ifstate *is;
|
||||
|
||||
is = domalloc(sizeof(*is));
|
||||
is->prev = prev;
|
||||
if (p != NULL) {
|
||||
is->startplace = *p;
|
||||
} else {
|
||||
place_setbuiltin(&is->startplace, 1);
|
||||
}
|
||||
is->curtrue = startstate;
|
||||
is->evertrue = is->curtrue;
|
||||
is->seenelse = false;
|
||||
return is;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ifstate_destroy(struct ifstate *is)
|
||||
{
|
||||
dofree(is, sizeof(*is));
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ifstate_push(struct place *p, bool startstate)
|
||||
{
|
||||
struct ifstate *newstate;
|
||||
|
||||
newstate = ifstate_create(ifstate, p, startstate);
|
||||
if (!ifstate->curtrue) {
|
||||
newstate->curtrue = false;
|
||||
newstate->evertrue = true;
|
||||
}
|
||||
ifstate = newstate;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
ifstate_pop(void)
|
||||
{
|
||||
struct ifstate *is;
|
||||
|
||||
is = ifstate;
|
||||
ifstate = ifstate->prev;
|
||||
ifstate_destroy(is);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_if(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
bool doprint;
|
||||
char *expr;
|
||||
bool val;
|
||||
struct place p3 = *p2;
|
||||
size_t oldlen;
|
||||
|
||||
doprint = ifstate->curtrue;
|
||||
|
||||
expr = macroexpand(p2, line, strlen(line), true);
|
||||
|
||||
oldlen = strlen(expr);
|
||||
uncomment(expr);
|
||||
/* trim to fit, so the malloc debugging won't complain */
|
||||
expr = dorealloc(expr, oldlen + 1, strlen(expr) + 1);
|
||||
|
||||
if (ifstate->curtrue) {
|
||||
val = eval(&p3, expr);
|
||||
} else {
|
||||
val = 0;
|
||||
}
|
||||
ifstate_push(&lp->current, val);
|
||||
dostrfree(expr);
|
||||
|
||||
if (doprint) {
|
||||
debuglog(&lp->current, "#if: %s",
|
||||
ifstate->curtrue ? "taken" : "not taken");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_ifdef(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
bool doprint;
|
||||
|
||||
doprint = ifstate->curtrue;
|
||||
|
||||
uncomment(line);
|
||||
oneword("#ifdef", p2, line);
|
||||
ifstate_push(&lp->current, macro_isdefined(line));
|
||||
|
||||
if (doprint) {
|
||||
debuglog(&lp->current, "#ifdef %s: %s",
|
||||
line, ifstate->curtrue ? "taken" : "not taken");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_ifndef(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
bool doprint;
|
||||
|
||||
doprint = ifstate->curtrue;
|
||||
|
||||
uncomment(line);
|
||||
oneword("#ifndef", p2, line);
|
||||
ifstate_push(&lp->current, !macro_isdefined(line));
|
||||
|
||||
if (doprint) {
|
||||
debuglog(&lp->current, "#ifndef %s: %s",
|
||||
line, ifstate->curtrue ? "taken" : "not taken");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_elif(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
bool doprint;
|
||||
char *expr;
|
||||
struct place p3 = *p2;
|
||||
size_t oldlen;
|
||||
|
||||
if (ifstate->seenelse) {
|
||||
complain(&lp->current, "#elif after #else");
|
||||
complain_fail();
|
||||
}
|
||||
|
||||
doprint = ifstate->curtrue;
|
||||
|
||||
if (ifstate->evertrue) {
|
||||
ifstate->curtrue = false;
|
||||
} else {
|
||||
expr = macroexpand(p2, line, strlen(line), true);
|
||||
|
||||
oldlen = strlen(expr);
|
||||
uncomment(expr);
|
||||
/* trim to fit, so the malloc debugging won't complain */
|
||||
expr = dorealloc(expr, oldlen + 1, strlen(expr) + 1);
|
||||
|
||||
ifstate->curtrue = eval(&p3, expr);
|
||||
ifstate->evertrue = ifstate->curtrue;
|
||||
dostrfree(expr);
|
||||
}
|
||||
|
||||
if (doprint) {
|
||||
debuglog2(&lp->current, &ifstate->startplace, "#elif: %s",
|
||||
ifstate->curtrue ? "taken" : "not taken");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_else(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
bool doprint;
|
||||
|
||||
(void)p2;
|
||||
(void)line;
|
||||
|
||||
if (ifstate->seenelse) {
|
||||
complain(&lp->current,
|
||||
"Multiple #else directives in one conditional");
|
||||
complain_fail();
|
||||
}
|
||||
|
||||
doprint = ifstate->curtrue;
|
||||
|
||||
ifstate->curtrue = !ifstate->evertrue;
|
||||
ifstate->evertrue = true;
|
||||
ifstate->seenelse = true;
|
||||
|
||||
if (doprint) {
|
||||
debuglog2(&lp->current, &ifstate->startplace, "#else: %s",
|
||||
ifstate->curtrue ? "taken" : "not taken");
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_endif(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
(void)p2;
|
||||
(void)line;
|
||||
|
||||
if (ifstate->prev == NULL) {
|
||||
complain(&lp->current, "Unmatched #endif");
|
||||
complain_fail();
|
||||
} else {
|
||||
debuglog2(&lp->current, &ifstate->startplace, "#endif");
|
||||
ifstate_pop();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// macros
|
||||
|
||||
static
|
||||
void
|
||||
d_define(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
size_t pos, argpos;
|
||||
struct place p3, p4;
|
||||
|
||||
(void)lp;
|
||||
|
||||
/*
|
||||
* line may be:
|
||||
* macro expansion
|
||||
* macro(arg, arg, ...) expansion
|
||||
*/
|
||||
|
||||
pos = strcspn(line, " \t\f\v(");
|
||||
if (line[pos] == '(') {
|
||||
line[pos++] = '\0';
|
||||
argpos = pos;
|
||||
pos = pos + strcspn(line+pos, "()");
|
||||
if (line[pos] == '(') {
|
||||
place_addcolumns(p2, pos);
|
||||
complain(p2, "Left parenthesis in macro parameters");
|
||||
complain_fail();
|
||||
return;
|
||||
}
|
||||
if (line[pos] != ')') {
|
||||
place_addcolumns(p2, pos);
|
||||
complain(p2, "Unclosed macro parameter list");
|
||||
complain_fail();
|
||||
return;
|
||||
}
|
||||
line[pos++] = '\0';
|
||||
#if 0
|
||||
if (!strchr(ws, line[pos])) {
|
||||
p2->column += pos;
|
||||
complain(p2, "Trash after macro parameter list");
|
||||
complain_fail();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
} else if (line[pos] == '\0') {
|
||||
argpos = 0;
|
||||
} else {
|
||||
line[pos++] = '\0';
|
||||
argpos = 0;
|
||||
}
|
||||
|
||||
pos += strspn(line+pos, ws);
|
||||
|
||||
p3 = *p2;
|
||||
place_addcolumns(&p3, argpos);
|
||||
|
||||
p4 = *p2;
|
||||
place_addcolumns(&p4, pos);
|
||||
|
||||
if (argpos) {
|
||||
debuglog(&lp->current, "Defining %s()", line);
|
||||
macro_define_params(p2, line, &p3,
|
||||
line + argpos, &p4,
|
||||
line + pos);
|
||||
} else {
|
||||
debuglog(&lp->current, "Defining %s", line);
|
||||
macro_define_plain(p2, line, &p4, line + pos);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_undef(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
(void)lp;
|
||||
|
||||
uncomment(line);
|
||||
oneword("#undef", p2, line);
|
||||
debuglog(&lp->current, "Undef %s", line);
|
||||
macro_undef(line);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// includes
|
||||
|
||||
static
|
||||
bool
|
||||
tryinclude(struct place *p, char *line)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = strlen(line);
|
||||
if (len > 2 && line[0] == '"' && line[len-1] == '"') {
|
||||
line[len-1] = '\0';
|
||||
debuglog(p, "Entering include file \"%s\"", line+1);
|
||||
file_readquote(p, line+1);
|
||||
debuglog(p, "Leaving include file \"%s\"", line+1);
|
||||
line[len-1] = '"';
|
||||
return true;
|
||||
}
|
||||
if (len > 2 && line[0] == '<' && line[len-1] == '>') {
|
||||
line[len-1] = '\0';
|
||||
debuglog(p, "Entering include file <%s>", line+1);
|
||||
file_readbracket(p, line+1);
|
||||
debuglog(p, "Leaving include file <%s>", line+1);
|
||||
line[len-1] = '>';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_include(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
char *text;
|
||||
size_t oldlen;
|
||||
|
||||
uncomment(line);
|
||||
if (tryinclude(&lp->current, line)) {
|
||||
return;
|
||||
}
|
||||
text = macroexpand(p2, line, strlen(line), false);
|
||||
|
||||
oldlen = strlen(text);
|
||||
uncomment(text);
|
||||
/* trim to fit, so the malloc debugging won't complain */
|
||||
text = dorealloc(text, oldlen + 1, strlen(text) + 1);
|
||||
|
||||
if (tryinclude(&lp->current, text)) {
|
||||
dostrfree(text);
|
||||
return;
|
||||
}
|
||||
complain(&lp->current, "Illegal #include directive");
|
||||
complain(&lp->current, "Before macro expansion: #include %s", line);
|
||||
complain(&lp->current, "After macro expansion: #include %s", text);
|
||||
dostrfree(text);
|
||||
complain_fail();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_line(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
char *text;
|
||||
size_t oldlen;
|
||||
unsigned long val;
|
||||
char *moretext;
|
||||
size_t moretextlen;
|
||||
char *filename;
|
||||
|
||||
text = macroexpand(p2, line, strlen(line), true);
|
||||
|
||||
oldlen = strlen(text);
|
||||
uncomment(text);
|
||||
/* trim to fit, so the malloc debugging won't complain */
|
||||
text = dorealloc(text, oldlen + 1, strlen(text) + 1);
|
||||
|
||||
/*
|
||||
* What we should have here: either 1234 "file.c",
|
||||
* or just 1234.
|
||||
*/
|
||||
|
||||
errno = 0;
|
||||
val = strtoul(text, &moretext, 10);
|
||||
if (errno) {
|
||||
complain(&lp->current,
|
||||
"Invalid line number in #line directive");
|
||||
goto fail;
|
||||
}
|
||||
#if UINT_MAX < ULONG_MAX
|
||||
if (val > UINT_MAX) {
|
||||
complain(&lp->current,
|
||||
"Line number in #line directive too large");
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
moretext += strspn(moretext, ws);
|
||||
moretextlen = strlen(moretext);
|
||||
place_addcolumns(&lp->current, moretext - text);
|
||||
|
||||
if (moretextlen > 2 &&
|
||||
moretext[0] == '"' && moretext[moretextlen-1] == '"') {
|
||||
filename = dostrndup(moretext+1, moretextlen-2);
|
||||
place_changefile(&lp->nextline, filename);
|
||||
dostrfree(filename);
|
||||
}
|
||||
else if (moretextlen > 0) {
|
||||
complain(&lp->current,
|
||||
"Invalid file name in #line directive");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lp->nextline.line = val;
|
||||
dostrfree(text);
|
||||
return;
|
||||
|
||||
fail:
|
||||
complain(&lp->current, "Before macro expansion: #line %s", line);
|
||||
complain(&lp->current, "After macro expansion: #line %s", text);
|
||||
complain_fail();
|
||||
dostrfree(text);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// messages
|
||||
|
||||
static
|
||||
void
|
||||
d_warning(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
msg = macroexpand(p2, line, strlen(line), false);
|
||||
complain(&lp->current, "#warning: %s", msg);
|
||||
if (mode.werror) {
|
||||
complain_fail();
|
||||
}
|
||||
dostrfree(msg);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_error(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
msg = macroexpand(p2, line, strlen(line), false);
|
||||
complain(&lp->current, "#error: %s", msg);
|
||||
complain_fail();
|
||||
dostrfree(msg);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// other
|
||||
|
||||
static
|
||||
void
|
||||
d_pragma(struct lineplace *lp, struct place *p2, char *line)
|
||||
{
|
||||
(void)p2;
|
||||
|
||||
complain(&lp->current, "#pragma %s", line);
|
||||
complain_fail();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// directive table
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
bool ifskip;
|
||||
void (*func)(struct lineplace *, struct place *, char *line);
|
||||
} directives[] = {
|
||||
{ "define", true, d_define },
|
||||
{ "elif", false, d_elif },
|
||||
{ "else", false, d_else },
|
||||
{ "endif", false, d_endif },
|
||||
{ "error", true, d_error },
|
||||
{ "if", false, d_if },
|
||||
{ "ifdef", false, d_ifdef },
|
||||
{ "ifndef", false, d_ifndef },
|
||||
{ "include", true, d_include },
|
||||
{ "line", true, d_line },
|
||||
{ "pragma", true, d_pragma },
|
||||
{ "undef", true, d_undef },
|
||||
{ "warning", true, d_warning },
|
||||
};
|
||||
static const unsigned numdirectives = HOWMANY(directives);
|
||||
|
||||
static
|
||||
void
|
||||
directive_gotdirective(struct lineplace *lp, char *line)
|
||||
{
|
||||
struct place p2;
|
||||
size_t len, skip;
|
||||
unsigned i;
|
||||
|
||||
p2 = lp->current;
|
||||
for (i=0; i<numdirectives; i++) {
|
||||
len = strlen(directives[i].name);
|
||||
if (!strncmp(line, directives[i].name, len) &&
|
||||
strchr(ws, line[len])) {
|
||||
if (directives[i].ifskip && !ifstate->curtrue) {
|
||||
return;
|
||||
}
|
||||
skip = len + strspn(line+len, ws);
|
||||
place_addcolumns(&p2, skip);
|
||||
line += skip;
|
||||
|
||||
len = strlen(line);
|
||||
len = notrailingws(line, len);
|
||||
if (len < strlen(line)) {
|
||||
line[len] = '\0';
|
||||
}
|
||||
directives[i].func(lp, &p2, line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* ugh. allow # by itself, including with a comment after it */
|
||||
uncomment(line);
|
||||
if (line[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
skip = strcspn(line, ws);
|
||||
complain(&lp->current, "Unknown directive #%.*s", (int)skip, line);
|
||||
complain_fail();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for nested comment delimiters in LINE.
|
||||
*/
|
||||
static
|
||||
size_t
|
||||
directive_scancomments(const struct lineplace *lp, char *line, size_t len)
|
||||
{
|
||||
size_t pos;
|
||||
bool incomment;
|
||||
struct place p2;
|
||||
|
||||
p2 = lp->current;
|
||||
incomment = 0;
|
||||
for (pos = 0; pos+1 < len; pos++) {
|
||||
if (line[pos] == '/' && line[pos+1] == '*') {
|
||||
if (incomment) {
|
||||
complain(&p2, "Warning: %c%c within comment",
|
||||
'/', '*');
|
||||
if (mode.werror) {
|
||||
complain_failed();
|
||||
}
|
||||
} else {
|
||||
incomment = true;
|
||||
}
|
||||
pos++;
|
||||
} else if (line[pos] == '*' && line[pos+1] == '/') {
|
||||
if (incomment) {
|
||||
incomment = false;
|
||||
} else {
|
||||
/* stray end-comment; should we care? */
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
if (line[pos] == '\n') {
|
||||
place_addlines(&p2, 1);
|
||||
p2.column = 0;
|
||||
} else {
|
||||
place_addcolumns(&p2, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* multiline comments are supposed to arrive in a single buffer */
|
||||
assert(!incomment);
|
||||
return len;
|
||||
}
|
||||
|
||||
void
|
||||
directive_gotline(struct lineplace *lp, char *line, size_t len)
|
||||
{
|
||||
size_t skip;
|
||||
|
||||
if (warns.nestcomment) {
|
||||
directive_scancomments(lp, line, len);
|
||||
}
|
||||
|
||||
/* check if we have a directive line (# exactly in column 0) */
|
||||
if (len > 0 && line[0] == '#') {
|
||||
skip = 1 + strspn(line + 1, ws);
|
||||
assert(skip <= len);
|
||||
place_addcolumns(&lp->current, skip);
|
||||
assert(line[len] == '\0');
|
||||
directive_gotdirective(lp, line+skip /*, length = len-skip */);
|
||||
place_addcolumns(&lp->current, len-skip);
|
||||
} else if (ifstate->curtrue) {
|
||||
macro_sendline(&lp->current, line, len);
|
||||
place_addcolumns(&lp->current, len);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
directive_goteof(struct place *p)
|
||||
{
|
||||
while (ifstate->prev != NULL) {
|
||||
complain(p, "Missing #endif");
|
||||
complain(&ifstate->startplace, "...opened at this point");
|
||||
complain_failed();
|
||||
ifstate_pop();
|
||||
}
|
||||
macro_sendeof(p);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// module initialization
|
||||
|
||||
void
|
||||
directive_init(void)
|
||||
{
|
||||
ifstate = ifstate_create(NULL, NULL, true);
|
||||
}
|
||||
|
||||
void
|
||||
directive_cleanup(void)
|
||||
{
|
||||
assert(ifstate->prev == NULL);
|
||||
ifstate_destroy(ifstate);
|
||||
ifstate = NULL;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*-
|
||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 "place.h"
|
||||
|
||||
/*
|
||||
* Relevant places while we're processing a line:
|
||||
* the place in the current line
|
||||
* the beginning of the next line
|
||||
*/
|
||||
struct lineplace {
|
||||
struct place current;
|
||||
struct place nextline;
|
||||
};
|
||||
|
||||
void directive_init(void);
|
||||
void directive_cleanup(void);
|
||||
|
||||
void directive_gotline(struct lineplace *lp, char *line, size_t len);
|
||||
void directive_goteof(struct place *p);
|
||||
|
|
@ -0,0 +1,767 @@
|
|||
/*-
|
||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
//#define DEBUG
|
||||
#ifdef DEBUG
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "utils.h"
|
||||
#include "array.h"
|
||||
#include "mode.h"
|
||||
#include "place.h"
|
||||
#include "eval.h"
|
||||
|
||||
/*
|
||||
* e ::=
|
||||
* e1 ? e2 : e3
|
||||
* e1 || e2
|
||||
* e1 && e2
|
||||
* e1 | e2
|
||||
* e1 ^ e2
|
||||
* e1 & e2
|
||||
* e1 == e2 | e1 != e2
|
||||
* e1 < e2 | e1 <= e2 | e1 > e2 | e1 >= e2
|
||||
* e1 << e2 | e1 >> e2
|
||||
* e1 + e2 | e1 - e2
|
||||
* e1 * e2 | e1 / e2 | e1 % e2
|
||||
* !e | ~e | -e | +e
|
||||
* ( e ) | ident
|
||||
*/
|
||||
|
||||
enum tokens {
|
||||
T_EOF, /* end of input */
|
||||
T_VAL, /* value */
|
||||
T_LPAREN, /* parens */
|
||||
T_RPAREN,
|
||||
T_PIPEPIPE, /* operators */
|
||||
T_AMPAMP,
|
||||
T_EQEQ,
|
||||
T_BANGEQ,
|
||||
T_LTEQ,
|
||||
T_GTEQ,
|
||||
T_LTLT,
|
||||
T_GTGT,
|
||||
T_QUES,
|
||||
T_COLON,
|
||||
T_PIPE,
|
||||
T_CARET,
|
||||
T_AMP,
|
||||
T_LT,
|
||||
T_GT,
|
||||
T_PLUS,
|
||||
T_MINUS,
|
||||
T_STAR,
|
||||
T_SLASH,
|
||||
T_PCT,
|
||||
T_BANG,
|
||||
T_TILDE,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
char c1, c2;
|
||||
enum tokens tok;
|
||||
} tokens_2[] = {
|
||||
{ '|', '|', T_PIPEPIPE },
|
||||
{ '&', '&', T_AMPAMP },
|
||||
{ '=', '=', T_EQEQ },
|
||||
{ '!', '=', T_BANGEQ },
|
||||
{ '<', '=', T_LTEQ },
|
||||
{ '>', '=', T_GTEQ },
|
||||
{ '<', '<', T_LTLT },
|
||||
{ '>', '>', T_GTGT },
|
||||
};
|
||||
static const unsigned num_tokens_2 = HOWMANY(tokens_2);
|
||||
|
||||
static const struct {
|
||||
char c1;
|
||||
enum tokens tok;
|
||||
} tokens_1[] = {
|
||||
{ '?', T_QUES },
|
||||
{ ':', T_COLON },
|
||||
{ '|', T_PIPE },
|
||||
{ '^', T_CARET },
|
||||
{ '&', T_AMP },
|
||||
{ '<', T_LT },
|
||||
{ '>', T_GT },
|
||||
{ '+', T_PLUS },
|
||||
{ '-', T_MINUS },
|
||||
{ '*', T_STAR },
|
||||
{ '/', T_SLASH },
|
||||
{ '%', T_PCT },
|
||||
{ '!', T_BANG },
|
||||
{ '~', T_TILDE },
|
||||
{ '(', T_LPAREN },
|
||||
{ ')', T_RPAREN },
|
||||
};
|
||||
static const unsigned num_tokens_1 = HOWMANY(tokens_1);
|
||||
|
||||
struct token {
|
||||
struct place place;
|
||||
enum tokens tok;
|
||||
int val;
|
||||
};
|
||||
DECLARRAY(token, static UNUSED);
|
||||
DEFARRAY(token, static);
|
||||
|
||||
static struct tokenarray tokens;
|
||||
|
||||
static
|
||||
struct token *
|
||||
token_create(const struct place *p, enum tokens tok, int val)
|
||||
{
|
||||
struct token *t;
|
||||
|
||||
t = domalloc(sizeof(*t));
|
||||
t->place = *p;
|
||||
t->tok = tok;
|
||||
t->val = val;
|
||||
return t;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
token_destroy(struct token *t)
|
||||
{
|
||||
dofree(t, sizeof(*t));
|
||||
}
|
||||
|
||||
DESTROYALL_ARRAY(token, );
|
||||
|
||||
#ifdef DEBUG
|
||||
static
|
||||
void
|
||||
printtokens(void)
|
||||
{
|
||||
unsigned i, num;
|
||||
struct token *t;
|
||||
|
||||
fprintf(stderr, "tokens:");
|
||||
num = tokenarray_num(&tokens);
|
||||
for (i=0; i<num; i++) {
|
||||
t = tokenarray_get(&tokens, i);
|
||||
switch (t->tok) {
|
||||
case T_EOF: fprintf(stderr, " <eof>"); break;
|
||||
case T_VAL: fprintf(stderr, " %d", t->val); break;
|
||||
case T_LPAREN: fprintf(stderr, " ("); break;
|
||||
case T_RPAREN: fprintf(stderr, " )"); break;
|
||||
case T_PIPEPIPE: fprintf(stderr, " ||"); break;
|
||||
case T_AMPAMP: fprintf(stderr, " &&"); break;
|
||||
case T_EQEQ: fprintf(stderr, " =="); break;
|
||||
case T_BANGEQ: fprintf(stderr, " !="); break;
|
||||
case T_LTEQ: fprintf(stderr, " <="); break;
|
||||
case T_GTEQ: fprintf(stderr, " >="); break;
|
||||
case T_LTLT: fprintf(stderr, " <<"); break;
|
||||
case T_GTGT: fprintf(stderr, " >>"); break;
|
||||
case T_QUES: fprintf(stderr, " ?"); break;
|
||||
case T_COLON: fprintf(stderr, " :"); break;
|
||||
case T_PIPE: fprintf(stderr, " |"); break;
|
||||
case T_CARET: fprintf(stderr, " ^"); break;
|
||||
case T_AMP: fprintf(stderr, " &"); break;
|
||||
case T_LT: fprintf(stderr, " <"); break;
|
||||
case T_GT: fprintf(stderr, " >"); break;
|
||||
case T_PLUS: fprintf(stderr, " +"); break;
|
||||
case T_MINUS: fprintf(stderr, " -"); break;
|
||||
case T_STAR: fprintf(stderr, " *"); break;
|
||||
case T_SLASH: fprintf(stderr, " /"); break;
|
||||
case T_PCT: fprintf(stderr, " %%"); break;
|
||||
case T_BANG: fprintf(stderr, " !"); break;
|
||||
case T_TILDE: fprintf(stderr, " ~"); break;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static
|
||||
bool
|
||||
isuop(enum tokens tok)
|
||||
{
|
||||
switch (tok) {
|
||||
case T_BANG:
|
||||
case T_TILDE:
|
||||
case T_MINUS:
|
||||
case T_PLUS:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static
|
||||
bool
|
||||
isbop(enum tokens tok)
|
||||
{
|
||||
switch (tok) {
|
||||
case T_EOF:
|
||||
case T_VAL:
|
||||
case T_LPAREN:
|
||||
case T_RPAREN:
|
||||
case T_COLON:
|
||||
case T_QUES:
|
||||
case T_BANG:
|
||||
case T_TILDE:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool
|
||||
isop(enum tokens tok)
|
||||
{
|
||||
switch (tok) {
|
||||
case T_EOF:
|
||||
case T_VAL:
|
||||
case T_LPAREN:
|
||||
case T_RPAREN:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
getprec(enum tokens tok)
|
||||
{
|
||||
switch (tok) {
|
||||
case T_BANG: case T_TILDE: return -1;
|
||||
case T_STAR: case T_SLASH: case T_PCT: return 0;
|
||||
case T_PLUS: case T_MINUS: return 1;
|
||||
case T_LTLT: case T_GTGT: return 2;
|
||||
case T_LT: case T_LTEQ: case T_GT: case T_GTEQ: return 3;
|
||||
case T_EQEQ: case T_BANGEQ: return 4;
|
||||
case T_AMP: return 5;
|
||||
case T_CARET: return 6;
|
||||
case T_PIPE: return 7;
|
||||
case T_AMPAMP: return 8;
|
||||
case T_PIPEPIPE: return 9;
|
||||
default: break;
|
||||
}
|
||||
return 10;
|
||||
}
|
||||
|
||||
static
|
||||
bool
|
||||
looser(enum tokens t1, enum tokens t2)
|
||||
{
|
||||
return getprec(t1) >= getprec(t2);
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
eval_uop(enum tokens op, int val)
|
||||
{
|
||||
switch (op) {
|
||||
case T_BANG: val = !val; break;
|
||||
case T_TILDE: val = (int)~(unsigned)val; break;
|
||||
case T_MINUS: val = -val; break;
|
||||
case T_PLUS: break;
|
||||
default: assert(0); break;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
eval_bop(struct place *p, int lv, enum tokens op, int rv)
|
||||
{
|
||||
unsigned mask;
|
||||
|
||||
switch (op) {
|
||||
case T_PIPEPIPE: return lv || rv;
|
||||
case T_AMPAMP: return lv && rv;
|
||||
case T_PIPE: return (int)((unsigned)lv | (unsigned)rv);
|
||||
case T_CARET: return (int)((unsigned)lv ^ (unsigned)rv);
|
||||
case T_AMP: return (int)((unsigned)lv & (unsigned)rv);
|
||||
case T_EQEQ: return lv == rv;
|
||||
case T_BANGEQ: return lv != rv;
|
||||
case T_LT: return lv < rv;
|
||||
case T_GT: return lv > rv;
|
||||
case T_LTEQ: return lv <= rv;
|
||||
case T_GTEQ: return lv >= rv;
|
||||
|
||||
case T_LTLT:
|
||||
case T_GTGT:
|
||||
if (rv < 0) {
|
||||
complain(p, "Negative bit-shift");
|
||||
complain_fail();
|
||||
rv = 0;
|
||||
}
|
||||
if ((unsigned)rv >= CHAR_BIT * sizeof(unsigned)) {
|
||||
complain(p, "Bit-shift farther than type width");
|
||||
complain_fail();
|
||||
rv = 0;
|
||||
}
|
||||
if (op == T_LTLT) {
|
||||
return (int)((unsigned)lv << (unsigned)rv);
|
||||
}
|
||||
mask = ((unsigned)-1) << (CHAR_BIT * sizeof(unsigned) - rv);
|
||||
lv = (int)(((unsigned)lv >> (unsigned)rv) | mask);
|
||||
return lv;
|
||||
|
||||
case T_MINUS:
|
||||
if (rv == INT_MIN) {
|
||||
if (lv == INT_MIN) {
|
||||
return 0;
|
||||
}
|
||||
lv--;
|
||||
rv++;
|
||||
}
|
||||
rv = -rv;
|
||||
/* FALLTHROUGH */
|
||||
case T_PLUS:
|
||||
if (rv > 0 && lv > (INT_MAX - rv)) {
|
||||
complain(p, "Integer overflow");
|
||||
complain_fail();
|
||||
return INT_MAX;
|
||||
}
|
||||
if (rv < 0 && lv < (INT_MIN - rv)) {
|
||||
complain(p, "Integer underflow");
|
||||
complain_fail();
|
||||
return INT_MIN;
|
||||
}
|
||||
return lv + rv;
|
||||
|
||||
case T_STAR:
|
||||
if (rv == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (rv == 1) {
|
||||
return lv;
|
||||
}
|
||||
if (rv == -1 && lv == INT_MIN) {
|
||||
lv++;
|
||||
lv = -lv;
|
||||
if (lv == INT_MAX) {
|
||||
complain(p, "Integer overflow");
|
||||
complain_fail();
|
||||
return INT_MAX;
|
||||
}
|
||||
lv++;
|
||||
return lv;
|
||||
}
|
||||
if (lv == INT_MIN && rv < 0) {
|
||||
complain(p, "Integer overflow");
|
||||
complain_fail();
|
||||
return INT_MAX;
|
||||
}
|
||||
if (lv == INT_MIN && rv > 0) {
|
||||
complain(p, "Integer underflow");
|
||||
complain_fail();
|
||||
return INT_MIN;
|
||||
}
|
||||
if (rv < 0) {
|
||||
rv = -rv;
|
||||
lv = -lv;
|
||||
}
|
||||
if (lv > 0 && lv > INT_MAX / rv) {
|
||||
complain(p, "Integer overflow");
|
||||
complain_fail();
|
||||
return INT_MAX;
|
||||
}
|
||||
if (lv < 0 && lv < INT_MIN / rv) {
|
||||
complain(p, "Integer underflow");
|
||||
complain_fail();
|
||||
return INT_MIN;
|
||||
}
|
||||
return lv * rv;
|
||||
|
||||
case T_SLASH:
|
||||
if (rv == 0) {
|
||||
complain(p, "Division by zero");
|
||||
complain_fail();
|
||||
return 0;
|
||||
}
|
||||
return lv / rv;
|
||||
|
||||
case T_PCT:
|
||||
if (rv == 0) {
|
||||
complain(p, "Modulus by zero");
|
||||
complain_fail();
|
||||
return 0;
|
||||
}
|
||||
return lv % rv;
|
||||
|
||||
default: assert(0); break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
tryreduce(void)
|
||||
{
|
||||
unsigned num;
|
||||
struct token *t1, *t2, *t3, *t4, *t5, *t6;
|
||||
|
||||
while (1) {
|
||||
#ifdef DEBUG
|
||||
printtokens();
|
||||
#endif
|
||||
num = tokenarray_num(&tokens);
|
||||
t1 = (num >= 1) ? tokenarray_get(&tokens, num-1) : NULL;
|
||||
t2 = (num >= 2) ? tokenarray_get(&tokens, num-2) : NULL;
|
||||
t3 = (num >= 3) ? tokenarray_get(&tokens, num-3) : NULL;
|
||||
|
||||
if (num >= 3 &&
|
||||
t3->tok == T_LPAREN &&
|
||||
t2->tok == T_VAL &&
|
||||
t1->tok == T_RPAREN) {
|
||||
/* (x) -> x */
|
||||
t2->place = t3->place;
|
||||
token_destroy(t1);
|
||||
token_destroy(t3);
|
||||
tokenarray_remove(&tokens, num-1);
|
||||
tokenarray_remove(&tokens, num-3);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (num >= 2 &&
|
||||
(num == 2 || isop(t3->tok) || t3->tok == T_LPAREN) &&
|
||||
isuop(t2->tok) &&
|
||||
t1->tok == T_VAL) {
|
||||
/* unary operator */
|
||||
t1->val = eval_uop(t2->tok, t1->val);
|
||||
t1->place = t2->place;
|
||||
token_destroy(t2);
|
||||
tokenarray_remove(&tokens, num-2);
|
||||
continue;
|
||||
}
|
||||
if (num >= 2 &&
|
||||
(num == 2 || isop(t3->tok) || t3->tok == T_LPAREN) &&
|
||||
t2->tok != T_LPAREN && t2->tok != T_VAL &&
|
||||
t1->tok == T_VAL) {
|
||||
complain(&t2->place, "Invalid unary operator");
|
||||
complain_fail();
|
||||
token_destroy(t2);
|
||||
tokenarray_remove(&tokens, num-2);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
t4 = (num >= 4) ? tokenarray_get(&tokens, num-4) : NULL;
|
||||
|
||||
if (num >= 4 &&
|
||||
t4->tok == T_VAL &&
|
||||
isbop(t3->tok) &&
|
||||
t2->tok == T_VAL) {
|
||||
/* binary operator */
|
||||
if (looser(t1->tok, t3->tok)) {
|
||||
t4->val = eval_bop(&t3->place,
|
||||
t4->val, t3->tok, t2->val);
|
||||
token_destroy(t2);
|
||||
token_destroy(t3);
|
||||
tokenarray_remove(&tokens, num-2);
|
||||
tokenarray_remove(&tokens, num-3);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
t5 = (num >= 5) ? tokenarray_get(&tokens, num-5) : NULL;
|
||||
t6 = (num >= 6) ? tokenarray_get(&tokens, num-6) : NULL;
|
||||
|
||||
if (num >= 6 &&
|
||||
t6->tok == T_VAL &&
|
||||
t5->tok == T_QUES &&
|
||||
t4->tok == T_VAL &&
|
||||
t3->tok == T_COLON &&
|
||||
t2->tok == T_VAL &&
|
||||
!isop(t1->tok)) {
|
||||
/* conditional expression */
|
||||
t6->val = t6->val ? t4->val : t2->val;
|
||||
token_destroy(t2);
|
||||
token_destroy(t3);
|
||||
token_destroy(t4);
|
||||
token_destroy(t5);
|
||||
tokenarray_remove(&tokens, num-2);
|
||||
tokenarray_remove(&tokens, num-3);
|
||||
tokenarray_remove(&tokens, num-4);
|
||||
tokenarray_remove(&tokens, num-5);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (num >= 2 &&
|
||||
t2->tok == T_LPAREN &&
|
||||
t1->tok == T_RPAREN) {
|
||||
complain(&t1->place, "Value expected within ()");
|
||||
complain_fail();
|
||||
t1->tok = T_VAL;
|
||||
t1->val = 0;
|
||||
token_destroy(t1);
|
||||
tokenarray_remove(&tokens, num-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (num >= 2 &&
|
||||
t2->tok == T_VAL &&
|
||||
t1->tok == T_VAL) {
|
||||
complain(&t1->place, "Operator expected");
|
||||
complain_fail();
|
||||
token_destroy(t1);
|
||||
tokenarray_remove(&tokens, num-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (num >= 2 &&
|
||||
isop(t2->tok) &&
|
||||
t1->tok == T_EOF) {
|
||||
complain(&t1->place, "Value expected after operator");
|
||||
complain_fail();
|
||||
token_destroy(t2);
|
||||
tokenarray_remove(&tokens, num-2);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (num == 2 &&
|
||||
t2->tok == T_VAL &&
|
||||
t1->tok == T_RPAREN) {
|
||||
complain(&t1->place, "Excess right parenthesis");
|
||||
complain_fail();
|
||||
token_destroy(t1);
|
||||
tokenarray_remove(&tokens, num-1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (num == 3 &&
|
||||
t3->tok == T_LPAREN &&
|
||||
t2->tok == T_VAL &&
|
||||
t1->tok == T_EOF) {
|
||||
complain(&t1->place, "Unclosed left parenthesis");
|
||||
complain_fail();
|
||||
token_destroy(t3);
|
||||
tokenarray_remove(&tokens, num-3);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (num == 2 &&
|
||||
t2->tok == T_VAL &&
|
||||
t1->tok == T_EOF) {
|
||||
/* accepting state */
|
||||
break;
|
||||
}
|
||||
|
||||
if (num >= 1 &&
|
||||
t1->tok == T_EOF) {
|
||||
/* any other configuration at eof is an error */
|
||||
complain(&t1->place, "Parse error");
|
||||
complain_fail();
|
||||
break;
|
||||
}
|
||||
|
||||
/* otherwise, wait for more input */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
token(struct place *p, enum tokens tok, int val)
|
||||
{
|
||||
struct token *t;
|
||||
|
||||
t = token_create(p, tok, val);
|
||||
|
||||
tokenarray_add(&tokens, t, NULL);
|
||||
tryreduce();
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
wordval(struct place *p, char *word)
|
||||
{
|
||||
unsigned long val;
|
||||
char *t;
|
||||
|
||||
if (word[0] >= '0' && word[0] <= '9') {
|
||||
errno = 0;
|
||||
val = strtoul(word, &t, 0);
|
||||
if (errno) {
|
||||
complain(p, "Invalid integer constant");
|
||||
complain_fail();
|
||||
return 0;
|
||||
}
|
||||
while (*t == 'U' || *t == 'L') {
|
||||
t++;
|
||||
}
|
||||
if (*t != '\0') {
|
||||
complain(p, "Trailing garbage after integer constant");
|
||||
complain_fail();
|
||||
return 0;
|
||||
}
|
||||
if (val > INT_MAX) {
|
||||
complain(p, "Integer constant too large");
|
||||
complain_fail();
|
||||
return INT_MAX;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/* if it's a symbol, warn and substitute 0. */
|
||||
if (warns.undef) {
|
||||
complain(p, "Warning: value of undefined symbol %s is 0",
|
||||
word);
|
||||
if (mode.werror) {
|
||||
complain_fail();
|
||||
}
|
||||
}
|
||||
debuglog(p, "Undefined symbol %s; substituting 0", word);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
bool
|
||||
check_word(struct place *p, char *expr, size_t pos, size_t *len_ret)
|
||||
{
|
||||
size_t len;
|
||||
int val;
|
||||
char tmp;
|
||||
|
||||
if (!strchr(alnum, expr[pos])) {
|
||||
return false;
|
||||
}
|
||||
len = strspn(expr + pos, alnum);
|
||||
tmp = expr[pos + len];
|
||||
expr[pos + len] = '\0';
|
||||
val = wordval(p, expr + pos);
|
||||
expr[pos + len] = tmp;
|
||||
token(p, T_VAL, val);
|
||||
*len_ret = len;
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
bool
|
||||
check_tokens_2(struct place *p, char *expr, size_t pos)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<num_tokens_2; i++) {
|
||||
if (expr[pos] == tokens_2[i].c1 &&
|
||||
expr[pos+1] == tokens_2[i].c2) {
|
||||
token(p, tokens_2[i].tok, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static
|
||||
bool
|
||||
check_tokens_1(struct place *p, char *expr, size_t pos)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
for (i=0; i<num_tokens_1; i++) {
|
||||
if (expr[pos] == tokens_1[i].c1) {
|
||||
token(p, tokens_1[i].tok, 0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
tokenize(struct place *p, char *expr)
|
||||
{
|
||||
size_t pos, len;
|
||||
|
||||
pos = 0;
|
||||
while (expr[pos] != '\0') {
|
||||
len = strspn(expr+pos, ws);
|
||||
pos += len;
|
||||
place_addcolumns(p, len);
|
||||
/* trailing whitespace is supposed to have been pruned */
|
||||
assert(expr[pos] != '\0');
|
||||
if (check_word(p, expr, pos, &len)) {
|
||||
pos += len;
|
||||
place_addcolumns(p, len);
|
||||
continue;
|
||||
}
|
||||
if (check_tokens_2(p, expr, pos)) {
|
||||
pos += 2;
|
||||
place_addcolumns(p, 2);
|
||||
continue;
|
||||
}
|
||||
if (check_tokens_1(p, expr, pos)) {
|
||||
pos++;
|
||||
place_addcolumns(p, 1);
|
||||
continue;
|
||||
}
|
||||
complain(p, "Invalid character %u in #if-expression",
|
||||
(unsigned char)expr[pos]);
|
||||
complain_fail();
|
||||
pos++;
|
||||
place_addcolumns(p, 1);
|
||||
}
|
||||
token(p, T_EOF, 0);
|
||||
}
|
||||
|
||||
bool
|
||||
eval(struct place *p, char *expr)
|
||||
{
|
||||
struct token *t1, *t2;
|
||||
unsigned num;
|
||||
bool result;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "eval: %s\n", expr);
|
||||
#endif
|
||||
debuglog(p, "eval: %s", expr);
|
||||
|
||||
tokenarray_init(&tokens);
|
||||
tokenize(p, expr);
|
||||
|
||||
result = false;
|
||||
num = tokenarray_num(&tokens);
|
||||
if (num == 2) {
|
||||
t1 = tokenarray_get(&tokens, num-1);
|
||||
t2 = tokenarray_get(&tokens, num-2);
|
||||
if (t2->tok == T_VAL &&
|
||||
t1->tok == T_EOF) {
|
||||
result = t2->val != 0;
|
||||
}
|
||||
}
|
||||
|
||||
tokenarray_destroyall(&tokens);
|
||||
tokenarray_cleanup(&tokens);
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*-
|
||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 "bool.h"
|
||||
|
||||
bool eval(struct place *p, char *expr);
|
|
@ -0,0 +1,441 @@
|
|||
/*-
|
||||
* Copyright (c) 2010, 2013 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "bool.h"
|
||||
#include "array.h"
|
||||
#include "mode.h"
|
||||
#include "place.h"
|
||||
#include "files.h"
|
||||
#include "directive.h"
|
||||
|
||||
struct incdir {
|
||||
const char *name;
|
||||
bool issystem;
|
||||
};
|
||||
|
||||
DECLARRAY(incdir, static UNUSED);
|
||||
DEFARRAY(incdir, static);
|
||||
|
||||
static struct incdirarray quotepath, bracketpath;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// management
|
||||
|
||||
static
|
||||
struct incdir *
|
||||
incdir_create(const char *name, bool issystem)
|
||||
{
|
||||
struct incdir *id;
|
||||
|
||||
id = domalloc(sizeof(*id));
|
||||
id->name = name;
|
||||
id->issystem = issystem;
|
||||
return id;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
incdir_destroy(struct incdir *id)
|
||||
{
|
||||
dofree(id, sizeof(*id));
|
||||
}
|
||||
|
||||
void
|
||||
files_init(void)
|
||||
{
|
||||
incdirarray_init("epath);
|
||||
incdirarray_init(&bracketpath);
|
||||
}
|
||||
|
||||
DESTROYALL_ARRAY(incdir, );
|
||||
|
||||
void
|
||||
files_cleanup(void)
|
||||
{
|
||||
incdirarray_destroyall("epath);
|
||||
incdirarray_cleanup("epath);
|
||||
incdirarray_destroyall(&bracketpath);
|
||||
incdirarray_cleanup(&bracketpath);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// path setup
|
||||
|
||||
void
|
||||
files_addquotepath(const char *dir, bool issystem)
|
||||
{
|
||||
struct incdir *id;
|
||||
|
||||
id = incdir_create(dir, issystem);
|
||||
incdirarray_add("epath, id, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
files_addbracketpath(const char *dir, bool issystem)
|
||||
{
|
||||
struct incdir *id;
|
||||
|
||||
id = incdir_create(dir, issystem);
|
||||
incdirarray_add(&bracketpath, id, NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// parsing
|
||||
|
||||
/*
|
||||
* Find the end of the logical line. End of line characters that are
|
||||
* commented out do not count.
|
||||
*/
|
||||
static
|
||||
size_t
|
||||
findeol(const char *buf, size_t start, size_t limit)
|
||||
{
|
||||
size_t i;
|
||||
int incomment = 0;
|
||||
bool inquote = false;
|
||||
char quote = '\0';
|
||||
|
||||
for (i=start; i<limit; i++) {
|
||||
if (incomment) {
|
||||
if (i+1 < limit && buf[i] == '*' && buf[i+1] == '/') {
|
||||
i++;
|
||||
incomment = 0;
|
||||
}
|
||||
} else if (!inquote && i+1 < limit &&
|
||||
buf[i] == '/' && buf[i+1] == '*') {
|
||||
i++;
|
||||
incomment = 1;
|
||||
} else if (i+1 < limit &&
|
||||
buf[i] == '\\' && buf[i+1] != '\n') {
|
||||
i++;
|
||||
} else if (!inquote && (buf[i] == '"' || buf[i] == '\'')) {
|
||||
inquote = true;
|
||||
quote = buf[i];
|
||||
} else if (inquote && buf[i] == quote) {
|
||||
inquote = false;
|
||||
} else if (buf[i] == '\n') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return limit;
|
||||
}
|
||||
|
||||
static
|
||||
unsigned
|
||||
countnls(const char *buf, size_t start, size_t limit)
|
||||
{
|
||||
size_t i;
|
||||
unsigned count = 0;
|
||||
|
||||
for (i=start; i<limit; i++) {
|
||||
if (buf[i] == '\n') {
|
||||
count++;
|
||||
if (count == 0) {
|
||||
/* just return the max and error downstream */
|
||||
return count - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
file_read(const struct placefile *pf, int fd, const char *name, bool toplevel)
|
||||
{
|
||||
struct lineplace places;
|
||||
struct place ptmp;
|
||||
size_t bufend, bufmax, linestart, lineend, nextlinestart, tmp;
|
||||
ssize_t result;
|
||||
bool ateof = false;
|
||||
char *buf;
|
||||
|
||||
place_setfilestart(&places.current, pf);
|
||||
places.nextline = places.current;
|
||||
|
||||
if (name) {
|
||||
debuglog(&places.current, "Reading file %s", name);
|
||||
} else {
|
||||
debuglog(&places.current, "Reading standard input");
|
||||
}
|
||||
|
||||
bufmax = 128;
|
||||
bufend = 0;
|
||||
linestart = 0;
|
||||
lineend = 0;
|
||||
buf = domalloc(bufmax);
|
||||
|
||||
while (1) {
|
||||
if (lineend >= bufend) {
|
||||
/* do not have a whole line in the buffer; read more */
|
||||
assert(bufend >= linestart);
|
||||
if (linestart > 0 && bufend > linestart) {
|
||||
/* slide to beginning of buffer */
|
||||
memmove(buf, buf+linestart, bufend-linestart);
|
||||
bufend -= linestart;
|
||||
lineend -= linestart;
|
||||
linestart = 0;
|
||||
}
|
||||
if (bufend >= bufmax) {
|
||||
/* need bigger buffer */
|
||||
buf = dorealloc(buf, bufmax, bufmax*2);
|
||||
bufmax = bufmax*2;
|
||||
/* just in case someone's screwing around */
|
||||
if (bufmax > 0xffffffff) {
|
||||
complain(&places.current,
|
||||
"Input line too long");
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
if (ateof) {
|
||||
/* don't read again, in case it's a socket */
|
||||
result = 0;
|
||||
} else {
|
||||
result = read(fd, buf+bufend, bufmax - bufend);
|
||||
}
|
||||
|
||||
if (result == -1) {
|
||||
/* read error */
|
||||
complain(NULL, "%s: %s",
|
||||
name, strerror(errno));
|
||||
complain_fail();
|
||||
} else if (result == 0 && bufend == linestart) {
|
||||
/* eof */
|
||||
ateof = true;
|
||||
break;
|
||||
} else if (result == 0) {
|
||||
/* eof in middle of line */
|
||||
ateof = true;
|
||||
ptmp = places.current;
|
||||
place_addcolumns(&ptmp, bufend - linestart);
|
||||
if (buf[bufend - 1] == '\n') {
|
||||
complain(&ptmp, "Unclosed comment");
|
||||
complain_fail();
|
||||
} else {
|
||||
complain(&ptmp,
|
||||
"No newline at end of file");
|
||||
}
|
||||
if (mode.werror) {
|
||||
complain_fail();
|
||||
}
|
||||
assert(bufend < bufmax);
|
||||
lineend = bufend++;
|
||||
buf[lineend] = '\n';
|
||||
} else {
|
||||
bufend += (size_t)result;
|
||||
lineend = findeol(buf, linestart, bufend);
|
||||
}
|
||||
/* loop in case we still don't have a whole line */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* have a line */
|
||||
assert(buf[lineend] == '\n');
|
||||
buf[lineend] = '\0';
|
||||
nextlinestart = lineend+1;
|
||||
place_addlines(&places.nextline, 1);
|
||||
|
||||
/* check for CR/NL */
|
||||
if (lineend > 0 && buf[lineend-1] == '\r') {
|
||||
buf[lineend-1] = '\0';
|
||||
lineend--;
|
||||
}
|
||||
|
||||
/* check for continuation line */
|
||||
if (lineend > 0 && buf[lineend-1]=='\\') {
|
||||
lineend--;
|
||||
tmp = nextlinestart - lineend;
|
||||
if (bufend > nextlinestart) {
|
||||
memmove(buf+lineend, buf+nextlinestart,
|
||||
bufend - nextlinestart);
|
||||
}
|
||||
bufend -= tmp;
|
||||
nextlinestart -= tmp;
|
||||
lineend = findeol(buf, linestart, bufend);
|
||||
/* might not have a whole line, so loop */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* line now goes from linestart to lineend */
|
||||
assert(buf[lineend] == '\0');
|
||||
|
||||
/* count how many commented-out newlines we swallowed */
|
||||
place_addlines(&places.nextline,
|
||||
countnls(buf, linestart, lineend));
|
||||
|
||||
/* process the line (even if it's empty) */
|
||||
directive_gotline(&places, buf+linestart, lineend-linestart);
|
||||
|
||||
linestart = nextlinestart;
|
||||
lineend = findeol(buf, linestart, bufend);
|
||||
places.current = places.nextline;
|
||||
}
|
||||
|
||||
if (toplevel) {
|
||||
directive_goteof(&places.current);
|
||||
}
|
||||
dofree(buf, bufmax);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// path search
|
||||
|
||||
static
|
||||
char *
|
||||
mkfilename(struct place *place, const char *dir, const char *file)
|
||||
{
|
||||
size_t dlen, flen, rlen;
|
||||
char *ret;
|
||||
bool needslash = false;
|
||||
|
||||
if (dir == NULL) {
|
||||
dir = place_getparsedir(place);
|
||||
}
|
||||
|
||||
dlen = strlen(dir);
|
||||
flen = strlen(file);
|
||||
if (dlen > 0 && dir[dlen-1] != '/') {
|
||||
needslash = true;
|
||||
}
|
||||
|
||||
rlen = dlen + (needslash ? 1 : 0) + flen;
|
||||
ret = domalloc(rlen + 1);
|
||||
strcpy(ret, dir);
|
||||
if (needslash) {
|
||||
strcat(ret, "/");
|
||||
}
|
||||
strcat(ret, file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
file_tryopen(const char *file)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* XXX check for non-regular files */
|
||||
|
||||
fd = open(file, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
if (errno != ENOENT && errno != ENOTDIR) {
|
||||
complain(NULL, "%s: %s", file, strerror(errno));
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
file_search(struct place *place, struct incdirarray *path, const char *name)
|
||||
{
|
||||
unsigned i, num;
|
||||
struct incdir *id;
|
||||
const struct placefile *pf;
|
||||
char *file;
|
||||
int fd;
|
||||
|
||||
assert(place != NULL);
|
||||
|
||||
if (name[0] == '/') {
|
||||
fd = file_tryopen(name);
|
||||
if (fd >= 0) {
|
||||
pf = place_addfile(place, name, true);
|
||||
file_read(pf, fd, name, false);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
num = incdirarray_num(path);
|
||||
for (i=0; i<num; i++) {
|
||||
id = incdirarray_get(path, i);
|
||||
file = mkfilename(place, id->name, name);
|
||||
fd = file_tryopen(file);
|
||||
if (fd >= 0) {
|
||||
pf = place_addfile(place, file, id->issystem);
|
||||
file_read(pf, fd, file, false);
|
||||
dostrfree(file);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
dostrfree(file);
|
||||
}
|
||||
}
|
||||
complain(place, "Include file %s not found", name);
|
||||
complain_fail();
|
||||
}
|
||||
|
||||
void
|
||||
file_readquote(struct place *place, const char *name)
|
||||
{
|
||||
file_search(place, "epath, name);
|
||||
}
|
||||
|
||||
void
|
||||
file_readbracket(struct place *place, const char *name)
|
||||
{
|
||||
file_search(place, &bracketpath, name);
|
||||
}
|
||||
|
||||
void
|
||||
file_readabsolute(struct place *place, const char *name)
|
||||
{
|
||||
const struct placefile *pf;
|
||||
int fd;
|
||||
|
||||
assert(place != NULL);
|
||||
|
||||
if (name == NULL) {
|
||||
fd = STDIN_FILENO;
|
||||
pf = place_addfile(place, "<standard-input>", false);
|
||||
} else {
|
||||
fd = file_tryopen(name);
|
||||
if (fd < 0) {
|
||||
complain(NULL, "%s: %s", name, strerror(errno));
|
||||
die();
|
||||
}
|
||||
pf = place_addfile(place, name, false);
|
||||
}
|
||||
|
||||
file_read(pf, fd, name, true);
|
||||
|
||||
if (name != NULL) {
|
||||
close(fd);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*-
|
||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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.
|
||||
*/
|
||||
|
||||
struct place;
|
||||
|
||||
void files_init(void);
|
||||
void files_cleanup(void);
|
||||
|
||||
void files_addquotepath(const char *dir, bool issystem);
|
||||
void files_addbracketpath(const char *dir, bool issystem);
|
||||
|
||||
void file_readquote(struct place *, const char *name);
|
||||
void file_readbracket(struct place *, const char *name);
|
||||
void file_readabsolute(struct place *, const char *name);
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2009 David A. Holland.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the Author nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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.
|
||||
*/
|
||||
|
||||
#if defined(__GNUC__) && !defined(__GNUC_STDC_INLINE__)
|
||||
/* gcc's non-C99 inline semantics */
|
||||
#define C99INLINE extern inline
|
||||
#elif defined(__STDC__) && __STDC_VERSION__ >= 199901L
|
||||
/* C99 */
|
||||
#define C99INLINE inline
|
||||
#else
|
||||
/* something else; static inline is safest */
|
||||
#define C99INLINE static inline
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,51 @@
|
|||
/*-
|
||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 "bool.h"
|
||||
|
||||
struct place;
|
||||
|
||||
void macros_init(void);
|
||||
void macros_cleanup(void);
|
||||
|
||||
void macro_define_plain(struct place *, const char *macro,
|
||||
struct place *, const char *expansion);
|
||||
void macro_define_params(struct place *, const char *macro,
|
||||
struct place *, const char *params,
|
||||
struct place *, const char *expansion);
|
||||
void macro_define_magic(struct place *, const char *macro);
|
||||
void macro_undef(const char *macro);
|
||||
bool macro_isdefined(const char *macro);
|
||||
|
||||
char *macroexpand(struct place *, const char *buf, size_t len,
|
||||
bool honordefined);
|
||||
|
||||
void macro_sendline(struct place *, const char *buf, size_t len);
|
||||
void macro_sendeof(struct place *);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,66 @@
|
|||
/*-
|
||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 "bool.h"
|
||||
|
||||
struct mode {
|
||||
bool werror;
|
||||
bool input_allow_dollars;
|
||||
unsigned input_tabstop;
|
||||
bool do_stdinc;
|
||||
bool do_stddef;
|
||||
bool do_output;
|
||||
bool output_linenumbers;
|
||||
bool output_cheaplinenumbers;
|
||||
bool output_retain_comments;
|
||||
const char *output_file;
|
||||
bool do_depend;
|
||||
bool depend_report_system;
|
||||
bool depend_assume_generated;
|
||||
bool depend_issue_fakerules;
|
||||
bool depend_quote_target;
|
||||
const char *depend_target;
|
||||
const char *depend_file;
|
||||
bool do_macrolist;
|
||||
bool macrolist_include_stddef;
|
||||
bool macrolist_include_expansions;
|
||||
bool do_trace;
|
||||
bool trace_namesonly;
|
||||
bool trace_indented;
|
||||
};
|
||||
|
||||
struct warns {
|
||||
bool endiflabels;
|
||||
bool nestcomment;
|
||||
bool undef;
|
||||
bool unused;
|
||||
};
|
||||
|
||||
extern struct mode mode;
|
||||
extern struct warns warns;
|
|
@ -0,0 +1,203 @@
|
|||
/*-
|
||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "mode.h"
|
||||
#include "place.h"
|
||||
#include "output.h"
|
||||
|
||||
static int outputfd = -1;
|
||||
static bool incomment = false;
|
||||
static char *linebuf;
|
||||
static size_t linebufpos, linebufmax;
|
||||
static struct place linebufplace;
|
||||
|
||||
static
|
||||
void
|
||||
output_open(void)
|
||||
{
|
||||
if (mode.output_file == NULL) {
|
||||
outputfd = STDOUT_FILENO;
|
||||
} else {
|
||||
outputfd = open(mode.output_file, O_WRONLY|O_CREAT|O_TRUNC,
|
||||
0664);
|
||||
if (outputfd < 0) {
|
||||
complain(NULL, "%s: %s",
|
||||
mode.output_file, strerror(errno));
|
||||
die();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
dowrite(const char *buf, size_t len)
|
||||
{
|
||||
size_t done;
|
||||
ssize_t result;
|
||||
static unsigned write_errors = 0;
|
||||
|
||||
if (!mode.do_output) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (outputfd < 0) {
|
||||
output_open();
|
||||
}
|
||||
|
||||
done = 0;
|
||||
while (done < len) {
|
||||
result = write(outputfd, buf+done, len-done);
|
||||
if (result == -1) {
|
||||
complain(NULL, "%s: write: %s",
|
||||
mode.output_file, strerror(errno));
|
||||
complain_failed();
|
||||
write_errors++;
|
||||
if (write_errors > 5) {
|
||||
complain(NULL, "%s: giving up",
|
||||
mode.output_file);
|
||||
die();
|
||||
}
|
||||
/* XXX is this really a good idea? */
|
||||
sleep(1);
|
||||
}
|
||||
done += (size_t)result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
filter_output(const char *buf, size_t len)
|
||||
{
|
||||
size_t pos, start;
|
||||
bool inesc = false;
|
||||
bool inquote = false;
|
||||
char quote = '\0';
|
||||
|
||||
start = 0;
|
||||
for (pos = 0; pos < len - 1; pos++) {
|
||||
if (!inquote && buf[pos] == '/' && buf[pos+1] == '*') {
|
||||
if (!incomment) {
|
||||
if (pos > start) {
|
||||
dowrite(buf + start, pos - start);
|
||||
}
|
||||
start = pos;
|
||||
pos += 2;
|
||||
incomment = true;
|
||||
/* cancel out the loop's pos++ */
|
||||
pos--;
|
||||
continue;
|
||||
}
|
||||
} else if (buf[pos] == '*' && buf[pos+1] == '/') {
|
||||
if (incomment) {
|
||||
pos += 2;
|
||||
if (mode.output_retain_comments) {
|
||||
dowrite(buf + start, pos - start);
|
||||
}
|
||||
start = pos;
|
||||
incomment = false;
|
||||
/* cancel out the loop's pos++ */
|
||||
pos--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (incomment) {
|
||||
/* nothing */
|
||||
} else if (inesc) {
|
||||
inesc = false;
|
||||
} else if (buf[pos] == '\\') {
|
||||
inesc = true;
|
||||
} else if (!inquote && (buf[pos] == '"' || buf[pos] == '\'')) {
|
||||
inquote = true;
|
||||
quote = buf[pos];
|
||||
} else if (inquote && buf[pos] == quote) {
|
||||
inquote = false;
|
||||
}
|
||||
}
|
||||
pos++;
|
||||
|
||||
if (pos > start) {
|
||||
if (!incomment || mode.output_retain_comments) {
|
||||
dowrite(buf + start, pos - start);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
output(const struct place *p, const char *buf, size_t len)
|
||||
{
|
||||
size_t oldmax;
|
||||
|
||||
if (linebufpos + len > linebufmax) {
|
||||
oldmax = linebufmax;
|
||||
if (linebufmax == 0) {
|
||||
linebufmax = 64;
|
||||
}
|
||||
while (linebufpos + len > linebufmax) {
|
||||
linebufmax *= 2;
|
||||
}
|
||||
linebuf = dorealloc(linebuf, oldmax, linebufmax);
|
||||
}
|
||||
if (linebufpos == 0) {
|
||||
if (!place_samefile(&linebufplace, p)) {
|
||||
if (mode.output_cheaplinenumbers) {
|
||||
char str[256];
|
||||
|
||||
snprintf(str, sizeof(str), "# %u \"%s\"\n",
|
||||
p->line, place_getname(p));
|
||||
dowrite(str, strlen(str));
|
||||
}
|
||||
}
|
||||
linebufplace = *p;
|
||||
}
|
||||
memcpy(linebuf + linebufpos, buf, len);
|
||||
linebufpos += len;
|
||||
|
||||
if (len == 1 && buf[0] == '\n') {
|
||||
filter_output(linebuf, linebufpos);
|
||||
linebufpos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
output_eof(void)
|
||||
{
|
||||
if (mode.output_file != NULL && outputfd >= 0) {
|
||||
close(outputfd);
|
||||
}
|
||||
outputfd = -1;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*-
|
||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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.
|
||||
*/
|
||||
|
||||
void output(const struct place *p, const char *buf, size_t len);
|
||||
void output_eof(void);
|
|
@ -0,0 +1,395 @@
|
|||
/*-
|
||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "array.h"
|
||||
#include "place.h"
|
||||
|
||||
struct placefile {
|
||||
struct place includedfrom;
|
||||
char *dir;
|
||||
char *name;
|
||||
int depth;
|
||||
bool fromsystemdir;
|
||||
};
|
||||
DECLARRAY(placefile, static UNUSED);
|
||||
DEFARRAY(placefile, static);
|
||||
|
||||
static struct placefilearray placefiles;
|
||||
static bool overall_failure;
|
||||
|
||||
static const char *myprogname;
|
||||
|
||||
static FILE *debuglogfile;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// placefiles
|
||||
|
||||
static
|
||||
struct placefile *
|
||||
placefile_create(const struct place *from, const char *name,
|
||||
bool fromsystemdir)
|
||||
{
|
||||
struct placefile *pf;
|
||||
const char *s;
|
||||
size_t len;
|
||||
|
||||
pf = domalloc(sizeof(*pf));
|
||||
pf->includedfrom = *from;
|
||||
|
||||
s = strrchr(name, '/');
|
||||
len = (s == NULL) ? 0 : s - name;
|
||||
pf->dir = dostrndup(name, len);
|
||||
|
||||
pf->name = dostrdup(name);
|
||||
pf->fromsystemdir = fromsystemdir;
|
||||
|
||||
if (from->file != NULL) {
|
||||
pf->depth = from->file->depth + 1;
|
||||
} else {
|
||||
pf->depth = 1;
|
||||
}
|
||||
return pf;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
placefile_destroy(struct placefile *pf)
|
||||
{
|
||||
dostrfree(pf->name);
|
||||
dofree(pf, sizeof(*pf));
|
||||
}
|
||||
|
||||
DESTROYALL_ARRAY(placefile, );
|
||||
|
||||
const char *
|
||||
place_getparsedir(const struct place *place)
|
||||
{
|
||||
if (place->file == NULL) {
|
||||
return ".";
|
||||
}
|
||||
return place->file->dir;
|
||||
}
|
||||
|
||||
static
|
||||
struct placefile *
|
||||
placefile_find(const struct place *incfrom, const char *name)
|
||||
{
|
||||
unsigned i, num;
|
||||
struct placefile *pf;
|
||||
|
||||
num = placefilearray_num(&placefiles);
|
||||
for (i=0; i<num; i++) {
|
||||
pf = placefilearray_get(&placefiles, i);
|
||||
if (place_eq(incfrom, &pf->includedfrom) &&
|
||||
!strcmp(name, pf->name)) {
|
||||
return pf;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
place_changefile(struct place *p, const char *name)
|
||||
{
|
||||
struct placefile *pf;
|
||||
|
||||
assert(p->type == P_FILE);
|
||||
if (!strcmp(name, p->file->name)) {
|
||||
return;
|
||||
}
|
||||
pf = placefile_find(&p->file->includedfrom, name);
|
||||
if (pf == NULL) {
|
||||
pf = placefile_create(&p->file->includedfrom, name,
|
||||
p->file->fromsystemdir);
|
||||
placefilearray_add(&placefiles, pf, NULL);
|
||||
}
|
||||
p->file = pf;
|
||||
}
|
||||
|
||||
const struct placefile *
|
||||
place_addfile(const struct place *place, const char *file, bool issystem)
|
||||
{
|
||||
struct placefile *pf;
|
||||
|
||||
pf = placefile_create(place, file, issystem);
|
||||
placefilearray_add(&placefiles, pf, NULL);
|
||||
if (pf->depth > 120) {
|
||||
complain(place, "Maximum include nesting depth exceeded");
|
||||
die();
|
||||
}
|
||||
return pf;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// places
|
||||
|
||||
void
|
||||
place_setnowhere(struct place *p)
|
||||
{
|
||||
p->type = P_NOWHERE;
|
||||
p->file = NULL;
|
||||
p->line = 0;
|
||||
p->column = 0;
|
||||
}
|
||||
|
||||
void
|
||||
place_setbuiltin(struct place *p, unsigned num)
|
||||
{
|
||||
p->type = P_BUILTIN;
|
||||
p->file = NULL;
|
||||
p->line = num;
|
||||
p->column = 1;
|
||||
}
|
||||
|
||||
void
|
||||
place_setcommandline(struct place *p, unsigned line, unsigned column)
|
||||
{
|
||||
p->type = P_COMMANDLINE;
|
||||
p->file = NULL;
|
||||
p->line = line;
|
||||
p->column = column;
|
||||
}
|
||||
|
||||
void
|
||||
place_setfilestart(struct place *p, const struct placefile *pf)
|
||||
{
|
||||
p->type = P_FILE;
|
||||
p->file = pf;
|
||||
p->line = 1;
|
||||
p->column = 1;
|
||||
}
|
||||
|
||||
void
|
||||
place_addcolumns(struct place *p, unsigned cols)
|
||||
{
|
||||
unsigned newcol;
|
||||
|
||||
newcol = p->column + cols;
|
||||
if (newcol < p->column) {
|
||||
/* overflow (use the old place to complain) */
|
||||
complain(p, "Column numbering overflow");
|
||||
die();
|
||||
}
|
||||
p->column = newcol;
|
||||
}
|
||||
|
||||
void
|
||||
place_addlines(struct place *p, unsigned lines)
|
||||
{
|
||||
unsigned nextline;
|
||||
|
||||
nextline = p->line + lines;
|
||||
if (nextline < p->line) {
|
||||
/* overflow (use the old place to complain) */
|
||||
complain(p, "Line numbering overflow");
|
||||
die();
|
||||
}
|
||||
p->line = nextline;
|
||||
}
|
||||
|
||||
const char *
|
||||
place_getname(const struct place *p)
|
||||
{
|
||||
switch (p->type) {
|
||||
case P_NOWHERE: return "<nowhere>";
|
||||
case P_BUILTIN: return "<built-in>";
|
||||
case P_COMMANDLINE: return "<command-line>";
|
||||
case P_FILE: return p->file->name;
|
||||
}
|
||||
assert(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
place_samefile(const struct place *a, const struct place *b)
|
||||
{
|
||||
if (a->type != b->type) {
|
||||
return false;
|
||||
}
|
||||
if (a->file != b->file) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
place_eq(const struct place *a, const struct place *b)
|
||||
{
|
||||
if (!place_samefile(a, b)) {
|
||||
return false;
|
||||
}
|
||||
if (a->line != b->line || a->column != b->column) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
place_printfrom(const struct place *p)
|
||||
{
|
||||
const struct place *from;
|
||||
|
||||
if (p->file == NULL) {
|
||||
return;
|
||||
}
|
||||
from = &p->file->includedfrom;
|
||||
if (from->type != P_NOWHERE) {
|
||||
place_printfrom(from);
|
||||
fprintf(stderr, "In file included from %s:%u:%u:\n",
|
||||
place_getname(from), from->line, from->column);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// complaints
|
||||
|
||||
void
|
||||
complain_init(const char *pn)
|
||||
{
|
||||
myprogname = pn;
|
||||
}
|
||||
|
||||
void
|
||||
complain(const struct place *p, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (p != NULL) {
|
||||
place_printfrom(p);
|
||||
fprintf(stderr, "%s:%u:%u: ", place_getname(p),
|
||||
p->line, p->column);
|
||||
} else {
|
||||
fprintf(stderr, "%s: ", myprogname);
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
complain_fail(void)
|
||||
{
|
||||
overall_failure = true;
|
||||
}
|
||||
|
||||
bool
|
||||
complain_failed(void)
|
||||
{
|
||||
return overall_failure;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// debug logging
|
||||
|
||||
void
|
||||
debuglog_open(const struct place *p, /*const*/ char *file)
|
||||
{
|
||||
assert(debuglogfile == NULL);
|
||||
debuglogfile = fopen(file, "w");
|
||||
if (debuglogfile == NULL) {
|
||||
complain(p, "%s: %s", file, strerror(errno));
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
debuglog_close(void)
|
||||
{
|
||||
if (debuglogfile != NULL) {
|
||||
fclose(debuglogfile);
|
||||
debuglogfile = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PF(2, 3) void
|
||||
debuglog(const struct place *p, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (debuglogfile == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(debuglogfile, "%s:%u: ", place_getname(p), p->line);
|
||||
va_start(ap, fmt);
|
||||
vfprintf(debuglogfile, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(debuglogfile, "\n");
|
||||
fflush(debuglogfile);
|
||||
}
|
||||
|
||||
PF(3, 4) void
|
||||
debuglog2(const struct place *p, const struct place *p2, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (debuglogfile == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(debuglogfile, "%s:%u: ", place_getname(p), p->line);
|
||||
if (place_samefile(p, p2)) {
|
||||
fprintf(debuglogfile, "(block began at line %u) ",
|
||||
p2->line);
|
||||
} else {
|
||||
fprintf(debuglogfile, "(block began at %s:%u)",
|
||||
place_getname(p2), p2->line);
|
||||
}
|
||||
va_start(ap, fmt);
|
||||
vfprintf(debuglogfile, fmt, ap);
|
||||
va_end(ap);
|
||||
fprintf(debuglogfile, "\n");
|
||||
fflush(debuglogfile);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// module init and cleanup
|
||||
|
||||
void
|
||||
place_init(void)
|
||||
{
|
||||
placefilearray_init(&placefiles);
|
||||
}
|
||||
|
||||
void
|
||||
place_cleanup(void)
|
||||
{
|
||||
placefilearray_destroyall(&placefiles);
|
||||
placefilearray_cleanup(&placefiles);
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*-
|
||||
* Copyright (c) 2010 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by David A. Holland.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION 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 PLACE_H
|
||||
#define PLACE_H
|
||||
|
||||
#include "bool.h"
|
||||
|
||||
enum places {
|
||||
P_NOWHERE,
|
||||
P_BUILTIN,
|
||||
P_COMMANDLINE,
|
||||
P_FILE,
|
||||
};
|
||||
struct place {
|
||||
enum places type;
|
||||
const struct placefile *file;
|
||||
unsigned line;
|
||||
unsigned column;
|
||||
};
|
||||
|
||||
void place_init(void);
|
||||
void place_cleanup(void);
|
||||
|
||||
void place_setnowhere(struct place *p);
|
||||
void place_setbuiltin(struct place *p, unsigned num);
|
||||
void place_setcommandline(struct place *p, unsigned word, unsigned column);
|
||||
void place_setfilestart(struct place *p, const struct placefile *pf);
|
||||
|
||||
void place_addcolumns(struct place *, unsigned cols);
|
||||
void place_addlines(struct place *, unsigned lines);
|
||||
|
||||
const char *place_getname(const struct place *);
|
||||
const char *place_getparsedir(const struct place *incplace);
|
||||
bool place_eq(const struct place *, const struct place *);
|
||||
bool place_samefile(const struct place *, const struct place *);
|
||||
|
||||
void place_changefile(struct place *p, const char *name);
|
||||
|
||||
const struct placefile *place_addfile(const struct place *incplace,
|
||||
const char *name, bool fromsystemdir);
|
||||
|
||||
#endif /* PLACE_H */
|
|
@ -0,0 +1,45 @@
|
|||
TRADCPP_OBJDIR!= ${MAKE} -C ${.CURDIR}/.. -V .OBJDIR
|
||||
TRADCPP= ${TRADCPP_OBJDIR}/tradcpp
|
||||
|
||||
TESTS=\
|
||||
t01 t02 t03 t04 t05 t06 t07 t08 t09 t10 t11 t12 t13 t14 t15 t16 \
|
||||
t17 t18 t19 t20 t21 t22 t23 t24 t25 t26 t27 t28 t29 t30 t31 t32 \
|
||||
t33 t34 t35 t36 t37 t38 t39 t40
|
||||
|
||||
all: run-tests .WAIT show-diffs
|
||||
|
||||
.for T in $(TESTS)
|
||||
run-tests: $(T).diff
|
||||
|
||||
$(T).diff: $(T).run $(T).good $(TRADCPP)
|
||||
-diff -u $(T).good $(T).run > $(T).diff
|
||||
|
||||
$(T).run: $(TRADCPP) $(T).c
|
||||
$(TRADCPP) $(T).c > $(T).run 2>&1 || echo FAILED >> $(T).run
|
||||
.endfor
|
||||
|
||||
show-diffs:
|
||||
@echo '*** Test diffs ***'
|
||||
.for T in $(TESTS)
|
||||
@cat $(T).diff
|
||||
.endfor
|
||||
|
||||
clean:
|
||||
.for T in $(TESTS)
|
||||
rm -f $(T).run $(T).diff
|
||||
.endfor
|
||||
|
||||
good:
|
||||
.for T in $(TESTS)
|
||||
cp $(T).run $(T).good
|
||||
.endfor
|
||||
|
||||
.PHONY: all run-tests show-diffs clean good
|
||||
|
||||
############################################################
|
||||
|
||||
.if defined(ALLOW_BROKEN_ATF_POLLUTION)
|
||||
TESTDIR= ${TESTSBASE}/usr.bin/tradcpp
|
||||
TESTS_SH+= tradcpp
|
||||
.include <bsd.test.mk>
|
||||
.endif
|
|
@ -0,0 +1 @@
|
|||
hello
|
|
@ -0,0 +1 @@
|
|||
glop.
|
|
@ -0,0 +1 @@
|
|||
glop.
|
|
@ -0,0 +1,2 @@
|
|||
#define glop flop
|
||||
glop
|
|
@ -0,0 +1 @@
|
|||
flop
|
|
@ -0,0 +1,2 @@
|
|||
#define glop(x) flop x
|
||||
glop(boo)
|
|
@ -0,0 +1 @@
|
|||
flop boo
|
|
@ -0,0 +1,2 @@
|
|||
#define string(x) "x"
|
||||
string(abc)
|
|
@ -0,0 +1 @@
|
|||
"abc"
|
|
@ -0,0 +1,2 @@
|
|||
#define concat(a, b) a/**/b
|
||||
concat(abc,def)
|
|
@ -0,0 +1 @@
|
|||
abcdef
|
|
@ -0,0 +1,2 @@
|
|||
/*glop*/
|
||||
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
/*
|
||||
* gloop
|
||||
*/
|
|
@ -0,0 +1 @@
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/*#include <stdio.h>*/
|
||||
|
||||
int d =
|
||||
#if 2 > 1 ? 0 : 0 ? 1 : 1
|
||||
1
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
;
|
||||
|
||||
int e =
|
||||
#if (2 > 1 ? 0 : 0) ? 1 : 1
|
||||
1
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
;
|
||||
|
||||
int f =
|
||||
#if 2 > 1 ? 0 : (0 ? 1 : 1)
|
||||
1
|
||||
#else
|
||||
0
|
||||
#endif
|
||||
;
|
||||
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
int a, b, c;
|
||||
|
||||
a = 2 > 1 ? 0 : 0 ? 1 : 1;
|
||||
b = (2 > 1 ? 0 : 0) ? 1 : 1;
|
||||
c = 2 > 1 ? 0 : (0 ? 1 : 1);
|
||||
|
||||
printf("%d %d %d\n", a, b, c);
|
||||
printf("%d %d %d\n", d, e, f);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
int d =
|
||||
0
|
||||
;
|
||||
int e =
|
||||
1
|
||||
;
|
||||
int f =
|
||||
0
|
||||
;
|
||||
int
|
||||
main()
|
||||
{
|
||||
int a, b, c;
|
||||
a = 2 > 1 ? 0 : 0 ? 1 : 1;
|
||||
b = (2 > 1 ? 0 : 0) ? 1 : 1;
|
||||
c = 2 > 1 ? 0 : (0 ? 1 : 1);
|
||||
printf("%d %d %d\n", a, b, c);
|
||||
printf("%d %d %d\n", d, e, f);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#define STOP */
|
||||
#define START /*
|
||||
|
||||
/*
|
||||
* blah blah blah STOP fnord START goop moop
|
||||
*/
|
|
@ -0,0 +1,3 @@
|
|||
#define mac(r)o
|
||||
mac(3)
|
||||
mac()
|
|
@ -0,0 +1,2 @@
|
|||
o
|
||||
o
|
|
@ -0,0 +1,2 @@
|
|||
#define BOO BOO
|
||||
BOO
|
|
@ -0,0 +1 @@
|
|||
BOO
|
|
@ -0,0 +1,2 @@
|
|||
#define BOO(yah) BOO(yah)
|
||||
BOO(yah)
|
|
@ -0,0 +1 @@
|
|||
BOO(yah)
|
|
@ -0,0 +1,4 @@
|
|||
/*
|
||||
#define FOO BAR
|
||||
*/
|
||||
FOO
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
FOO
|
|
@ -0,0 +1,4 @@
|
|||
/*
|
||||
#define FOO BAR */
|
||||
FOO
|
||||
FOO
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
FOO
|
||||
FOO
|
|
@ -0,0 +1,3 @@
|
|||
#define FOO /* BAR */ BAZ
|
||||
FOO
|
||||
FOO
|
|
@ -0,0 +1,2 @@
|
|||
BAZ
|
||||
BAZ
|
|
@ -0,0 +1,11 @@
|
|||
#define a() x
|
||||
a()
|
||||
a ()
|
||||
#define b(p) p
|
||||
x/**/b(1)/**/x
|
||||
x/**/b (1)/**/x
|
||||
x/**/b()/**/x
|
||||
#define c(p,q) p/**/q
|
||||
x/**/c(1,2)/**/x
|
||||
x/**/c(1)/**/x
|
||||
x/**/c()/**/x
|
|
@ -0,0 +1,11 @@
|
|||
x
|
||||
x
|
||||
x1x
|
||||
x1x
|
||||
xx
|
||||
x12x
|
||||
t16.c:10:1: Wrong number of arguments for macro c; found 1, expected 2
|
||||
x1x
|
||||
t16.c:11:1: Wrong number of arguments for macro c; found 0, expected 2
|
||||
xx
|
||||
FAILED
|
|
@ -0,0 +1,2 @@
|
|||
#define file "subdir/test.h"
|
||||
#include file
|
|
@ -0,0 +1 @@
|
|||
hello
|
|
@ -0,0 +1,2 @@
|
|||
#if FOO /* ignore me */
|
||||
#endif
|
|
@ -0,0 +1,3 @@
|
|||
#define foo /* comment continues
|
||||
into the next line */ baz
|
||||
baz
|
|
@ -0,0 +1 @@
|
|||
baz
|
|
@ -0,0 +1 @@
|
|||
#undef foo /* blah */
|
|
@ -0,0 +1,3 @@
|
|||
# define FOO BAR
|
||||
#undef FOO /* would be wrong */
|
||||
FOO
|
|
@ -0,0 +1,2 @@
|
|||
#undef BAR
|
||||
BAR
|
|
@ -0,0 +1,2 @@
|
|||
pa/*
|
||||
*/ste
|
|
@ -0,0 +1 @@
|
|||
paste
|
|
@ -0,0 +1,8 @@
|
|||
/*
|
||||
fnord1
|
||||
/*
|
||||
fnord2
|
||||
*/
|
||||
foo
|
||||
*/
|
||||
bar
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
foo
|
||||
*/
|
||||
bar
|
|
@ -0,0 +1,67 @@
|
|||
#if 0
|
||||
wrong
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
right
|
||||
#endif
|
||||
|
||||
#if -1
|
||||
right
|
||||
#endif
|
||||
|
||||
#if 0 + 0
|
||||
wrong
|
||||
#endif
|
||||
|
||||
#if 1 + 1
|
||||
right
|
||||
#endif
|
||||
|
||||
#if 1 - 1
|
||||
wrong
|
||||
#endif
|
||||
|
||||
#if -1 + 1
|
||||
wrong
|
||||
#endif
|
||||
|
||||
#if 3 - 2 - 1
|
||||
wrong
|
||||
#endif
|
||||
|
||||
#if 3 * 2 - 6
|
||||
wrong
|
||||
#endif
|
||||
|
||||
#if 6 - 2 * 3
|
||||
wrong
|
||||
#endif
|
||||
|
||||
#if 3 - 3 && 1
|
||||
wrong
|
||||
#endif
|
||||
|
||||
#if 3 - 3 || 0
|
||||
wrong
|
||||
#endif
|
||||
|
||||
#if 1 && 0
|
||||
wrong
|
||||
#endif
|
||||
|
||||
#if 0 && 1
|
||||
wrong
|
||||
#endif
|
||||
|
||||
#if 1 || 0
|
||||
right
|
||||
#endif
|
||||
|
||||
#if 0 || 1
|
||||
right
|
||||
#endif
|
||||
|
||||
#if (0 || 1) && (0 || 0)
|
||||
wrong
|
||||
#endif
|
|
@ -0,0 +1,5 @@
|
|||
right
|
||||
right
|
||||
right
|
||||
right
|
||||
right
|
|
@ -0,0 +1,4 @@
|
|||
#define FOO foo /*
|
||||
#undef FOO
|
||||
#define FOO bar */
|
||||
FOO
|
|
@ -0,0 +1 @@
|
|||
foo
|
|
@ -0,0 +1,4 @@
|
|||
#define FOO foo
|
||||
FOO
|
||||
"FOO"
|
||||
'FOO'
|
|
@ -0,0 +1,3 @@
|
|||
foo
|
||||
"FOO"
|
||||
'FOO'
|
|
@ -0,0 +1,29 @@
|
|||
1.
|
||||
#define A(a) a
|
||||
A();
|
||||
|
||||
2.
|
||||
#define B(a, b) (a,b)
|
||||
B(a, );
|
||||
B(, b);
|
||||
B( , );
|
||||
B(a,);
|
||||
B(,b);
|
||||
B(,);
|
||||
|
||||
3.
|
||||
#define C(a, b, c) (a,b,c)
|
||||
C(a, b, );
|
||||
C(a, , c);
|
||||
C(, , c);
|
||||
C(a, , );
|
||||
C(, b, );
|
||||
C(, , c);
|
||||
C(, , )
|
||||
C(a,b,);
|
||||
C(a,,c);
|
||||
C(,,c);
|
||||
C(a,,);
|
||||
C(,b,);
|
||||
C(,,c);
|
||||
C(,,)
|
|
@ -0,0 +1,24 @@
|
|||
1.
|
||||
;
|
||||
2.
|
||||
(a, );
|
||||
(, b);
|
||||
( , );
|
||||
(a,);
|
||||
(,b);
|
||||
(,);
|
||||
3.
|
||||
(a, b, );
|
||||
(a, , c);
|
||||
(, , c);
|
||||
(a, , );
|
||||
(, b, );
|
||||
(, , c);
|
||||
(, , )
|
||||
(a,b,);
|
||||
(a,,c);
|
||||
(,,c);
|
||||
(a,,);
|
||||
(,b,);
|
||||
(,,c);
|
||||
(,,)
|
|
@ -0,0 +1,53 @@
|
|||
#if 1
|
||||
. right
|
||||
|
||||
# if 1
|
||||
.. right
|
||||
# elif 1
|
||||
.. wrong
|
||||
# elif 0
|
||||
.. wrong
|
||||
# else
|
||||
.. wrong
|
||||
# endif
|
||||
|
||||
#elif 1
|
||||
. wrong
|
||||
|
||||
# if 1
|
||||
.. wrong
|
||||
# elif 1
|
||||
.. wrong
|
||||
# elif 0
|
||||
.. wrong
|
||||
# else
|
||||
.. wrong
|
||||
# endif
|
||||
|
||||
#elif 0
|
||||
. wrong
|
||||
|
||||
# if 1
|
||||
.. wrong
|
||||
# elif 1
|
||||
.. wrong
|
||||
# elif 0
|
||||
.. wrong
|
||||
# else
|
||||
.. wrong
|
||||
# endif
|
||||
|
||||
#else
|
||||
. wrong
|
||||
|
||||
# if 1
|
||||
.. wrong
|
||||
# elif 1
|
||||
.. wrong
|
||||
# elif 0
|
||||
.. wrong
|
||||
# else
|
||||
.. wrong
|
||||
# endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,2 @@
|
|||
. right
|
||||
.. right
|
|
@ -0,0 +1,4 @@
|
|||
#if 0
|
||||
# if this is a syntax error
|
||||
# endif
|
||||
#endif
|
|
@ -0,0 +1,2 @@
|
|||
#define x(a,b,c) a;b;c;
|
||||
x((,),x,",")
|
|
@ -0,0 +1 @@
|
|||
(,);x;",";
|
|
@ -0,0 +1,6 @@
|
|||
this line 'has /* no' comment */ in it
|
||||
|
||||
#define BELCH(x) 'x'
|
||||
"BELCH(123)": BELCH(123)
|
||||
'BELCH(123)': BELCH(123)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
this line 'has /* no' comment */ in it
|
||||
"BELCH(123)": '123'
|
||||
'BELCH(123)': '123'
|
|
@ -0,0 +1,21 @@
|
|||
#define foo(x) "x"
|
||||
#define bar(x) 'x'
|
||||
#define baz frob
|
||||
foo(3)
|
||||
bar(3)
|
||||
foo(baz)
|
||||
bar(baz)
|
||||
"baz"
|
||||
'baz'
|
||||
"foo(baz)"
|
||||
"bar(baz)"
|
||||
|
||||
#define foo2(x) foo(x)
|
||||
#define bar2(x) bar(x)
|
||||
foo2(baz)
|
||||
bar2(baz)
|
||||
|
||||
#define foo3(x) foo2(x)
|
||||
#define bar3(x) bar2(x)
|
||||
foo3(baz)
|
||||
bar3(baz)
|
|
@ -0,0 +1,12 @@
|
|||
"3"
|
||||
'3'
|
||||
"baz"
|
||||
'baz'
|
||||
"baz"
|
||||
'baz'
|
||||
"foo(baz)"
|
||||
"bar(baz)"
|
||||
"baz"
|
||||
'baz'
|
||||
"baz"
|
||||
'baz'
|
|
@ -0,0 +1,6 @@
|
|||
/* make sure that R gets defined and doesn't end up part of a string */
|
||||
#define Q "
|
||||
#define R r
|
||||
#define S "
|
||||
R
|
||||
Q
|
|
@ -0,0 +1,3 @@
|
|||
|
||||
r
|
||||
"
|
|
@ -0,0 +1,5 @@
|
|||
#define Q "
|
||||
#define FOO foo
|
||||
Q FOO Q
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
" foo "
|
|
@ -0,0 +1,6 @@
|
|||
#define Q "
|
||||
#define FOO foo
|
||||
|
||||
Q FOO Q 'I like "FOO" and "BAR"'
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
" foo " 'I like "FOO" and "BAR"'
|
|
@ -0,0 +1,7 @@
|
|||
#define C(x) //**/* x */**//
|
||||
C(3)
|
||||
C(abc /* def */ ghi)
|
||||
|
||||
#define D(x) ///**/**/**///**/* x */**///**/**/**///
|
||||
D(3)
|
||||
D(abc /* def */ ghi)
|
|
@ -0,0 +1,4 @@
|
|||
/* 3 */
|
||||
/* abc ghi */
|
||||
//**/* 3 */**//
|
||||
//**/* abc ghi */**//
|
|
@ -0,0 +1,19 @@
|
|||
#define BC //**/*
|
||||
#define EC */**//
|
||||
|
||||
BC
|
||||
comment?
|
||||
EC
|
||||
|
||||
BC comment? EC
|
||||
|
||||
#define FOO(x) x
|
||||
FOO(abc BC def EC ghi)
|
||||
|
||||
#define BAR(x, y) x y
|
||||
BAR(abc BC def, ghi EC jkl)
|
||||
|
||||
BC
|
||||
#define BAZ baz
|
||||
EC
|
||||
BAZ
|
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
comment?
|
||||
*/
|
||||
/* comment? */
|
||||
abc /* def */ ghi
|
||||
abc /* def ghi */ jkl
|
||||
/*
|
||||
*/
|
||||
baz
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue