mirror of
https://github.com/openbsd/src.git
synced 2026-06-18 07:13:36 +02:00
Add tradcpp 0.4, a standalone traditional whitespace preserving cpp
by David A. Holland of NetBSD.
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
PROG= tradcpp
|
||||
SRCS= main.c \
|
||||
files.c directive.c eval.c macro.c output.c \
|
||||
place.c array.c utils.c
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
@@ -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) \
|
||||
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,158 @@
|
||||
/*-
|
||||
* 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__"
|
||||
#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,626 @@
|
||||
/*-
|
||||
* 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 <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.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') {
|
||||
p2->column += 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 place *p, struct place *p2, char *line)
|
||||
{
|
||||
char *expr;
|
||||
bool val;
|
||||
struct place p3 = *p2;
|
||||
size_t oldlen;
|
||||
|
||||
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(p, val);
|
||||
dostrfree(expr);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_ifdef(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
uncomment(line);
|
||||
oneword("#ifdef", p2, line);
|
||||
ifstate_push(p, macro_isdefined(line));
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_ifndef(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
uncomment(line);
|
||||
oneword("#ifndef", p2, line);
|
||||
ifstate_push(p, !macro_isdefined(line));
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_elif(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
char *expr;
|
||||
struct place p3 = *p2;
|
||||
size_t oldlen;
|
||||
|
||||
if (ifstate->seenelse) {
|
||||
complain(p, "#elif after #else");
|
||||
complain_fail();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_else(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
(void)p2;
|
||||
(void)line;
|
||||
|
||||
if (ifstate->seenelse) {
|
||||
complain(p, "Multiple #else directives in one conditional");
|
||||
complain_fail();
|
||||
}
|
||||
|
||||
ifstate->curtrue = !ifstate->evertrue;
|
||||
ifstate->evertrue = true;
|
||||
ifstate->seenelse = true;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_endif(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
(void)p2;
|
||||
(void)line;
|
||||
|
||||
if (ifstate->prev == NULL) {
|
||||
complain(p, "Unmatched #endif");
|
||||
complain_fail();
|
||||
} else {
|
||||
ifstate_pop();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// macros
|
||||
|
||||
static
|
||||
void
|
||||
d_define(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
size_t pos, argpos;
|
||||
struct place p3, p4;
|
||||
|
||||
(void)p;
|
||||
|
||||
/*
|
||||
* 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] == '(') {
|
||||
p2->column += pos;
|
||||
complain(p2, "Left parenthesis in macro parameters");
|
||||
complain_fail();
|
||||
return;
|
||||
}
|
||||
if (line[pos] != ')') {
|
||||
p2->column += 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;
|
||||
p3.column += argpos;
|
||||
|
||||
p4 = *p2;
|
||||
p4.column += pos;
|
||||
|
||||
if (argpos) {
|
||||
macro_define_params(p2, line, &p3,
|
||||
line + argpos, &p4,
|
||||
line + pos);
|
||||
} else {
|
||||
macro_define_plain(p2, line, &p4, line + pos);
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_undef(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
(void)p;
|
||||
|
||||
uncomment(line);
|
||||
oneword("#undef", p2, 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';
|
||||
file_readquote(p, line+1);
|
||||
line[len-1] = '"';
|
||||
return true;
|
||||
}
|
||||
if (len > 2 && line[0] == '<' && line[len-1] == '>') {
|
||||
line[len-1] = '\0';
|
||||
file_readbracket(p, line+1);
|
||||
line[len-1] = '>';
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_include(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
char *text;
|
||||
size_t oldlen;
|
||||
|
||||
uncomment(line);
|
||||
if (tryinclude(p, 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(p, text)) {
|
||||
dostrfree(text);
|
||||
return;
|
||||
}
|
||||
complain(p, "Illegal #include directive");
|
||||
complain(p, "Before macro expansion: #include %s", line);
|
||||
complain(p, "After macro expansion: #include %s", text);
|
||||
dostrfree(text);
|
||||
complain_fail();
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_line(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
(void)p2;
|
||||
(void)line;
|
||||
|
||||
/* XXX */
|
||||
complain(p, "Sorry, no #line yet");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// messages
|
||||
|
||||
static
|
||||
void
|
||||
d_warning(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
msg = macroexpand(p2, line, strlen(line), false);
|
||||
complain(p, "#warning: %s", msg);
|
||||
if (mode.werror) {
|
||||
complain_fail();
|
||||
}
|
||||
dostrfree(msg);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
d_error(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
char *msg;
|
||||
|
||||
msg = macroexpand(p2, line, strlen(line), false);
|
||||
complain(p, "#error: %s", msg);
|
||||
complain_fail();
|
||||
dostrfree(msg);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// other
|
||||
|
||||
static
|
||||
void
|
||||
d_pragma(struct place *p, struct place *p2, char *line)
|
||||
{
|
||||
(void)p2;
|
||||
|
||||
complain(p, "#pragma %s", line);
|
||||
complain_fail();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// directive table
|
||||
|
||||
static const struct {
|
||||
const char *name;
|
||||
bool ifskip;
|
||||
void (*func)(struct place *, 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 place *p, char *line)
|
||||
{
|
||||
struct place p2;
|
||||
size_t len, skip;
|
||||
unsigned i;
|
||||
|
||||
p2 = *p;
|
||||
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);
|
||||
p2.column += skip;
|
||||
line += skip;
|
||||
|
||||
len = strlen(line);
|
||||
len = notrailingws(line, len);
|
||||
if (len < strlen(line)) {
|
||||
line[len] = '\0';
|
||||
}
|
||||
directives[i].func(p, &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(p, "Unknown directive #%.*s", (int)skip, line);
|
||||
complain_fail();
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for nested comment delimiters in LINE.
|
||||
*/
|
||||
static
|
||||
size_t
|
||||
directive_scancomments(const struct place *p, char *line, size_t len)
|
||||
{
|
||||
size_t pos;
|
||||
bool incomment;
|
||||
struct place p2;
|
||||
|
||||
p2 = *p;
|
||||
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') {
|
||||
p2.line++;
|
||||
p2.column = 0;
|
||||
} else {
|
||||
p2.column++;
|
||||
}
|
||||
}
|
||||
|
||||
/* multiline comments are supposed to arrive in a single buffer */
|
||||
assert(!incomment);
|
||||
return len;
|
||||
}
|
||||
|
||||
void
|
||||
directive_gotline(struct place *p, char *line, size_t len)
|
||||
{
|
||||
size_t skip;
|
||||
|
||||
if (warns.nestcomment) {
|
||||
directive_scancomments(p, line, len);
|
||||
}
|
||||
|
||||
/* check if we have a directive line (# exactly in column 0) */
|
||||
if (line[0] == '#') {
|
||||
skip = 1 + strspn(line + 1, ws);
|
||||
assert(skip <= len);
|
||||
p->column += skip;
|
||||
assert(line[len] == '\0');
|
||||
directive_gotdirective(p, line+skip /*, length = len-skip */);
|
||||
p->column += len-skip;
|
||||
} else if (ifstate->curtrue) {
|
||||
macro_sendline(p, line, len);
|
||||
p->column += 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,39 @@
|
||||
/*-
|
||||
* 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>
|
||||
|
||||
struct place;
|
||||
|
||||
void directive_init(void);
|
||||
void directive_cleanup(void);
|
||||
|
||||
void directive_gotline(struct place *p, char *line, size_t len);
|
||||
void directive_goteof(struct place *p);
|
||||
|
||||
@@ -0,0 +1,765 @@
|
||||
/*-
|
||||
* 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();
|
||||
}
|
||||
}
|
||||
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;
|
||||
p->column += len;
|
||||
/* trailing whitespace is supposed to have been pruned */
|
||||
assert(expr[pos] != '\0');
|
||||
if (check_word(p, expr, pos, &len)) {
|
||||
pos += len;
|
||||
p->column += len;
|
||||
continue;
|
||||
}
|
||||
if (check_tokens_2(p, expr, pos)) {
|
||||
pos += 2;
|
||||
p->column += 2;
|
||||
continue;
|
||||
}
|
||||
if (check_tokens_1(p, expr, pos)) {
|
||||
pos++;
|
||||
p->column++;
|
||||
continue;
|
||||
}
|
||||
complain(p, "Invalid character %u in #if-expression",
|
||||
(unsigned char)expr[pos]);
|
||||
complain_fail();
|
||||
pos++;
|
||||
p->column++;
|
||||
}
|
||||
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
|
||||
|
||||
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 <stdbool.h>
|
||||
|
||||
bool eval(struct place *p, char *expr);
|
||||
@@ -0,0 +1,420 @@
|
||||
/*-
|
||||
* 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 <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.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++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
file_read(const struct placefile *pf, int fd, const char *name, bool toplevel)
|
||||
{
|
||||
struct place linestartplace, nextlinestartplace, ptmp;
|
||||
size_t bufend, bufmax, linestart, lineend, nextlinestart, tmp;
|
||||
ssize_t result;
|
||||
bool ateof = false;
|
||||
char *buf;
|
||||
|
||||
place_setfilestart(&linestartplace, pf);
|
||||
nextlinestartplace = linestartplace;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 = linestartplace;
|
||||
ptmp.column += bufend - linestart;
|
||||
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;
|
||||
nextlinestartplace.line++;
|
||||
|
||||
/* 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 */
|
||||
nextlinestartplace.line += countnls(buf, linestart, lineend);
|
||||
|
||||
/* if the line isn't empty, process it */
|
||||
if (lineend > linestart) {
|
||||
directive_gotline(&linestartplace,
|
||||
buf+linestart, lineend-linestart);
|
||||
}
|
||||
|
||||
linestart = nextlinestart;
|
||||
lineend = findeol(buf, linestart, bufend);
|
||||
linestartplace = nextlinestartplace;
|
||||
}
|
||||
|
||||
if (toplevel) {
|
||||
directive_goteof(&linestartplace);
|
||||
}
|
||||
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,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 <stdbool.h>
|
||||
#include <stddef.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_undef(const char *macro);
|
||||
bool macro_isdefined(const char *macro);
|
||||
|
||||
char *macroexpand(struct place *, char *buf, size_t len, bool honordefined);
|
||||
|
||||
void macro_sendline(struct place *, char *buf, size_t len);
|
||||
void macro_sendeof(struct place *);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,65 @@
|
||||
/*-
|
||||
* 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 <stdbool.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_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,193 @@
|
||||
/*-
|
||||
* 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 <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) {
|
||||
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,241 @@
|
||||
/*-
|
||||
* 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 "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;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// seenfiles
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// module init and cleanup
|
||||
|
||||
void
|
||||
place_init(void)
|
||||
{
|
||||
placefilearray_init(&placefiles);
|
||||
}
|
||||
|
||||
void
|
||||
place_cleanup(void)
|
||||
{
|
||||
placefilearray_destroyall(&placefiles);
|
||||
placefilearray_cleanup(&placefiles);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*-
|
||||
* 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 <stdbool.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);
|
||||
|
||||
const char *place_getparsedir(const struct place *incplace);
|
||||
|
||||
const struct placefile *place_addfile(const struct place *incplace,
|
||||
const char *name, bool fromsystemdir);
|
||||
@@ -0,0 +1,353 @@
|
||||
.\"
|
||||
.\" Copyright (c) 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.
|
||||
.\"
|
||||
.Dd June 11, 2013
|
||||
.Dt TRADCPP 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm tradcpp
|
||||
.Nd traditional (K&R-style) C macro preprocessor
|
||||
.Sh SYNOPSIS
|
||||
.Nm tradcpp
|
||||
.Op Fl options
|
||||
.Op Ar input-file Op Ar output-file
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm
|
||||
command provides a traditional K&R-style C macro preprocessor.
|
||||
It is intended to be suitable for historical Unix uses of the
|
||||
preprocessor, such as
|
||||
.Xr imake 1 ,
|
||||
particularly those that depend on preservation of whitespace.
|
||||
.Pp
|
||||
The chief ways in which traditional cpp differs from
|
||||
Standard C are:
|
||||
.Bl -bullet -offset indent
|
||||
.It
|
||||
Macro arguments are expanded within quoted strings.
|
||||
There is no stringize operator.
|
||||
.It
|
||||
There is no token pasting operator; tokens can be concatenated by
|
||||
placing comments between them.
|
||||
This process is also not limited to valid C language tokens.
|
||||
.It
|
||||
Whitespace is preserved, and in particular tabs are not expanded into
|
||||
spaces.
|
||||
Furthermore, additional whitespace is not injected.
|
||||
.El
|
||||
.Sh OPTIONS
|
||||
.Nm
|
||||
has many options, many of which are defined for compatibility with
|
||||
.Xr gcc 1
|
||||
or other compilers.
|
||||
Many of the options are not yet implemented.
|
||||
.\" The option lists have been sorted in what I hope is a sensible
|
||||
.\" order. Please don't arbitrarily alphabetize them.
|
||||
.Ss Common Options
|
||||
.Bl -tag -width bubblebabble
|
||||
.It Fl C
|
||||
Retain comments in output.
|
||||
.It Fl Dmacro[=expansion]
|
||||
Provide a definition for the named macro.
|
||||
If no expansion is provided, the value
|
||||
.Dq 1
|
||||
is used.
|
||||
Note that like many Unix compilers,
|
||||
.Nm
|
||||
does not accept a space between the
|
||||
.Dq D
|
||||
and the macro name.
|
||||
.It Fl Ipath
|
||||
Add the specified path to the main list of include directories.
|
||||
Note that like many Unix compilers,
|
||||
.Nm
|
||||
does not accept a space between the
|
||||
.Dq I
|
||||
and the directory name.
|
||||
.It Fl nostdinc
|
||||
Do not search the standard system include directories.
|
||||
.It Fl P
|
||||
Suppress line number information in the output.
|
||||
Currently line number information is not generated at all and this
|
||||
option has no effect.
|
||||
.It Fl Umacro
|
||||
Remove any existing defintion for the named macro.
|
||||
Note that like many Unix compilers,
|
||||
.Nm
|
||||
does not accept a space between the
|
||||
.Dq U
|
||||
and the macro name.
|
||||
.It Fl undef
|
||||
Remove all predefined macros.
|
||||
.El
|
||||
.Ss Warning Options
|
||||
Warning options can be disabled or enabled by inserting, or not, the
|
||||
string
|
||||
.Dq no-
|
||||
between the
|
||||
.Dq W
|
||||
and the warning name.
|
||||
Herein the
|
||||
.Dq Fl Wno-
|
||||
form is shown for options that are enabled by default.
|
||||
.Bl -tag -width bubblebabble
|
||||
.It Fl Wall
|
||||
Turn on all warnings.
|
||||
The option
|
||||
.Fl Wno-all
|
||||
disables only the warnings that are disabled by default.
|
||||
.It Fl w
|
||||
Turn off all warnings.
|
||||
.It Fl Werror
|
||||
Make warnings into fatal errors.
|
||||
.It Fl Wcomment
|
||||
Warn about nested comments.
|
||||
.It Fl Wno-endif-labels
|
||||
Don't warn about symbols attached to #endif directives.
|
||||
(The warning is currently not implemented.)
|
||||
.It Fl Wundef
|
||||
Warn about undefined symbols appearing in #if and #elif expressions.
|
||||
.It Fl Wunused-macros
|
||||
Warn about macros that are defined and never used.
|
||||
Not implemented.
|
||||
.El
|
||||
.Ss Depend Options
|
||||
.Bl -tag -width bubblebabble
|
||||
.It Fl M
|
||||
Generate dependency information for
|
||||
.Xr make 1
|
||||
on the standard output, instead of preprocessing.
|
||||
Not implemented.
|
||||
.It Fl MD
|
||||
Like
|
||||
.Fl M
|
||||
but skip system headers.
|
||||
Not implemented.
|
||||
.It Fl MM
|
||||
Like
|
||||
.Fl M
|
||||
but write the dependency information to a file named after the input
|
||||
file with extension
|
||||
.Pa \.d
|
||||
and preprocess normally to standard output.
|
||||
Not implemented.
|
||||
.It Fl MMD
|
||||
Like
|
||||
.Fl MM
|
||||
but skip system headers.
|
||||
Not implemented.
|
||||
.It Fl MF Ar file
|
||||
Send dependency output to the named file instead of the default
|
||||
location.
|
||||
Not implemented.
|
||||
.It Fl MG
|
||||
When generating dependency information, assume that missing files are
|
||||
generated instead of failing.
|
||||
Not implemented.
|
||||
.It Fl MP
|
||||
Issue dummy rules for all include files.
|
||||
This prevents
|
||||
.Xr make 1
|
||||
from choking if an include file is removed.
|
||||
Not implemented.
|
||||
.It Fl MQ Ar target
|
||||
Same as
|
||||
.Fl MT
|
||||
except that any
|
||||
.Xr make 1
|
||||
metacharacters appearing in the target are escaped.
|
||||
.It Fl MT Ar target
|
||||
Set the name of the
|
||||
.Xr make 1
|
||||
target appearing in the generated dependency information.
|
||||
The default is the name of the input file with its suffix replaced
|
||||
with the suffix for object files, normally
|
||||
.Pa .o .
|
||||
.\" If this option is given more than once, all named targets will
|
||||
.\" be emitted.
|
||||
.\" (The current operating mode framework doesn't support that.)
|
||||
.El
|
||||
.Ss More Include Path Options
|
||||
.Bl -tag -width bubblebabble
|
||||
.It Fl idirafter Ar path
|
||||
Add the specified path to the
|
||||
.Dq afterwards
|
||||
include path.
|
||||
This path is searched after all directories specified with
|
||||
.Fl I
|
||||
and the standard system directories.
|
||||
Directories on this path are treated as containing system include
|
||||
files.
|
||||
.It Fl imacros Ar file
|
||||
Read in
|
||||
.Ar file
|
||||
prior to reading the main input file, and preprocess it, but throw
|
||||
away the output and retain only the macro definitions.
|
||||
.It Fl include Ar file
|
||||
Read in and preprocess
|
||||
.Ar file
|
||||
prior to reading the main input file.
|
||||
.It Fl iprefix Ar prefix
|
||||
Set the path prefix used with the
|
||||
.Fl iwithprefix
|
||||
option.
|
||||
.It Fl iquote Ar path
|
||||
Add
|
||||
.Ar path
|
||||
to the list of directories searched for include directives written
|
||||
with quotes.
|
||||
This list is not searched for include directives written with angle
|
||||
brackets.
|
||||
.It Fl iremap Ar string:replacement
|
||||
Substitute
|
||||
.Ar replacement
|
||||
for
|
||||
.Ar string
|
||||
in the
|
||||
.Dv __FILE__
|
||||
built-in macro.
|
||||
Not supported.
|
||||
.It Fl isysroot Ar path
|
||||
Use
|
||||
.Ar path
|
||||
as the
|
||||
.Dq system root ,
|
||||
that is, the directory under which the standard system paths are found.
|
||||
.It Fl isystem Ar path
|
||||
Add
|
||||
.Ar path
|
||||
to the list of system include directories.
|
||||
This list is searched after the list given with
|
||||
.Ar I .
|
||||
Files found on this path are treated as system headers.
|
||||
.It Fl iwithprefix Ar dir
|
||||
Splice
|
||||
.Ar dir
|
||||
onto the prefix given with
|
||||
.Fl iprefix
|
||||
and add this directory as if it were specified with
|
||||
.Fl idirafter .
|
||||
.It Fl iwithprefixbefore
|
||||
Like
|
||||
-Fl iwithprefix
|
||||
but adds the result as if it were specified with
|
||||
.Fl I .
|
||||
.El
|
||||
.Ss Diagnostic Options
|
||||
.Bl -tag -width bubblebabble
|
||||
.It Fl dD
|
||||
Dump all macro definitions, except for the predefined macros, after
|
||||
the normal preprocessing output.
|
||||
Not implemented.
|
||||
.It Fl dI
|
||||
Dump all include directives along with the normal preprocessing
|
||||
output.
|
||||
Not implemented.
|
||||
.It Fl dM
|
||||
Dump all macro definitions instead of the normal preprocessing
|
||||
output.
|
||||
Not implemented.
|
||||
.It Fl dN
|
||||
Like
|
||||
.Fl dD
|
||||
but emits only macro names and not the expansions.
|
||||
Not implemented.
|
||||
.It Fl H
|
||||
Output a trace of the include tree as it gets processed.
|
||||
Not implemented.
|
||||
.El
|
||||
.Ss Other Options
|
||||
.Bl -tag -width bubblebabble
|
||||
.It Fl CC
|
||||
Retain comments in output.
|
||||
Same as
|
||||
.Fl C ,
|
||||
accepted for compatibility with
|
||||
.Xr gcc 1 .
|
||||
.It Fl fdollars-in-identifiers , Fl fno-dollars-in-identifiers
|
||||
Enable
|
||||
.Pq or disable, respectively
|
||||
the use of the dollar sign in identifiers.
|
||||
Not implemented.
|
||||
.It Fl ftabstop=num
|
||||
Set the tab width to the specified value, for reporting column
|
||||
positions in diagnostics.
|
||||
The default is 8.
|
||||
Not implemented.
|
||||
.It Fl std=standard
|
||||
Ask
|
||||
.Nm
|
||||
to conform to the named standard.
|
||||
The default, and the only supported value, is
|
||||
.Dq krc .
|
||||
.It Fl traditional
|
||||
This option is accepted for compatibility with
|
||||
.Xr gcc 1
|
||||
and ignored.
|
||||
.It Fl x Ar lang
|
||||
Adjust the preprocessor for the given language.
|
||||
The only values accepted for
|
||||
.Ar lang
|
||||
are
|
||||
.Dq assembler-with-cpp
|
||||
and
|
||||
.Dq c ,
|
||||
neither of which have any effect on the behavior of
|
||||
.Nm .
|
||||
.El
|
||||
.Sh FILES
|
||||
The default list of directories searched for include files is:
|
||||
.Bl -item -offset indent -compact
|
||||
.It
|
||||
.Pa /usr/local/include
|
||||
.It
|
||||
.Pa /usr/include
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr cc 1 ,
|
||||
.Xr cpp 1 ,
|
||||
.Xr make 1
|
||||
.Sh STANDARDS
|
||||
None.
|
||||
The whole point of a traditional cpp is that it reflects practices
|
||||
in pre-standardization implementations of C.
|
||||
Some information is available from the first edition of Kernighan and
|
||||
Ritchie.
|
||||
Much of the rest of the behavior is based on lore, pragmatism,
|
||||
material encountered in the wild, and comparison to other
|
||||
implementations.
|
||||
.Sh HISTORY
|
||||
The original version of
|
||||
.Nm
|
||||
was written one evening in late 2010.
|
||||
This version had some problems and was put aside.
|
||||
The first working version was released in June 2013.
|
||||
.\" .Sh AUTHORS
|
||||
.\" .An David A. Holland
|
||||
.Sh BUGS
|
||||
Probably plenty.
|
||||
@@ -0,0 +1,246 @@
|
||||
/*-
|
||||
* 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define MALLOCDEBUG
|
||||
|
||||
const char ws[] =
|
||||
" \t\f\v"
|
||||
;
|
||||
const char alnum[] =
|
||||
"0123456789"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"_"
|
||||
;
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// malloc
|
||||
|
||||
#define ROUNDUP(len, size) ((size) * (((len) + (size) - 1) / (size)))
|
||||
|
||||
#ifdef MALLOCDEBUG
|
||||
|
||||
struct mallocheader {
|
||||
struct mallocheader *self;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static
|
||||
size_t
|
||||
adjustsize(size_t len)
|
||||
{
|
||||
const size_t sz = sizeof(struct mallocheader);
|
||||
return ROUNDUP(len, sz) + 2*sz;
|
||||
}
|
||||
|
||||
static
|
||||
void *
|
||||
placeheaders(void *block, size_t len)
|
||||
{
|
||||
struct mallocheader *bothdr, *tophdr;
|
||||
size_t roundedlen;
|
||||
void *ret;
|
||||
|
||||
roundedlen = ROUNDUP(len, sizeof(struct mallocheader));
|
||||
bothdr = block;
|
||||
bothdr->len = len;
|
||||
bothdr->self = block;
|
||||
ret = bothdr + 1;
|
||||
tophdr = (void *)(((unsigned char *)ret) + roundedlen);
|
||||
tophdr->len = len;
|
||||
tophdr->self = bothdr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static
|
||||
void *
|
||||
checkheaders(void *block, size_t len)
|
||||
{
|
||||
struct mallocheader *bothdr, *tophdr;
|
||||
size_t roundedlen;
|
||||
|
||||
if (block == NULL) {
|
||||
assert(len == 0);
|
||||
return block;
|
||||
}
|
||||
|
||||
roundedlen = ROUNDUP(len, sizeof(struct mallocheader));
|
||||
bothdr = block;
|
||||
bothdr--;
|
||||
assert(bothdr->self == bothdr);
|
||||
assert(bothdr->len == len);
|
||||
tophdr = (void *)(((unsigned char *)(bothdr + 1)) + roundedlen);
|
||||
assert(tophdr->self == bothdr);
|
||||
assert(tophdr->len == len);
|
||||
return bothdr;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define adjustsize(len) (len)
|
||||
#define placeheaders(block, len) ((void)(len), (block))
|
||||
#define checkheaders(ptr, len) ((void)(len), (ptr))
|
||||
|
||||
#endif /* MALLOCDEBUG */
|
||||
|
||||
void *
|
||||
domalloc(size_t len)
|
||||
{
|
||||
void *ret;
|
||||
size_t blocklen;
|
||||
|
||||
blocklen = adjustsize(len);
|
||||
ret = malloc(blocklen);
|
||||
if (ret == NULL) {
|
||||
complain(NULL, "Out of memory");
|
||||
die();
|
||||
}
|
||||
|
||||
return placeheaders(ret, len);
|
||||
}
|
||||
|
||||
void *
|
||||
dorealloc(void *ptr, size_t oldlen, size_t newlen)
|
||||
{
|
||||
void *ret;
|
||||
void *blockptr;
|
||||
size_t newblocklen;
|
||||
|
||||
blockptr = checkheaders(ptr, oldlen);
|
||||
newblocklen = adjustsize(newlen);
|
||||
|
||||
ret = realloc(blockptr, newblocklen);
|
||||
if (ret == NULL) {
|
||||
complain(NULL, "Out of memory");
|
||||
die();
|
||||
}
|
||||
|
||||
return placeheaders(ret, newlen);
|
||||
}
|
||||
|
||||
void
|
||||
dofree(void *ptr, size_t len)
|
||||
{
|
||||
void *blockptr;
|
||||
|
||||
blockptr = checkheaders(ptr, len);
|
||||
free(blockptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// string allocators
|
||||
|
||||
char *
|
||||
dostrdup(const char *s)
|
||||
{
|
||||
char *ret;
|
||||
size_t len;
|
||||
|
||||
len = strlen(s);
|
||||
ret = domalloc(len+1);
|
||||
strcpy(ret, s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
dostrdup2(const char *s, const char *t)
|
||||
{
|
||||
char *ret;
|
||||
size_t len;
|
||||
|
||||
len = strlen(s) + strlen(t);
|
||||
ret = domalloc(len+1);
|
||||
strcpy(ret, s);
|
||||
strcat(ret, t);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
dostrdup3(const char *s, const char *t, const char *u)
|
||||
{
|
||||
char *ret;
|
||||
size_t len;
|
||||
|
||||
len = strlen(s) + strlen(t) + strlen(u);
|
||||
ret = domalloc(len+1);
|
||||
strcpy(ret, s);
|
||||
strcat(ret, t);
|
||||
strcat(ret, u);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *
|
||||
dostrndup(const char *s, size_t len)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
ret = domalloc(len+1);
|
||||
memcpy(ret, s, len);
|
||||
ret[len] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
dostrfree(char *s)
|
||||
{
|
||||
dofree(s, strlen(s)+1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// other stuff
|
||||
|
||||
size_t
|
||||
notrailingws(char *buf, size_t len)
|
||||
{
|
||||
while (len > 0 && strchr(ws, buf[len-1])) {
|
||||
buf[--len] = '\0';
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
bool
|
||||
is_identifier(const char *str)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = strlen(str);
|
||||
if (len != strspn(str, alnum)) {
|
||||
return false;
|
||||
}
|
||||
if (str[0] >= '0' && str[0] <= '9') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*-
|
||||
* 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 <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct place;
|
||||
|
||||
#if defined(__CLANG__) || defined(__GNUC__)
|
||||
#define PF(a, b) __attribute__((__format__(__printf__, a, b)))
|
||||
#define DEAD __attribute__((__noreturn__))
|
||||
#define UNUSED __attribute__((__unused__))
|
||||
#else
|
||||
#define PF(a, b)
|
||||
#define DEAD
|
||||
#define UNUSED
|
||||
#endif
|
||||
|
||||
#define HOWMANY(arr) (sizeof(arr)/sizeof((arr)[0]))
|
||||
|
||||
extern const char ws[];
|
||||
extern const char alnum[];
|
||||
|
||||
|
||||
void *domalloc(size_t len);
|
||||
void *dorealloc(void *ptr, size_t oldlen, size_t newlen);
|
||||
void dofree(void *ptr, size_t len);
|
||||
|
||||
char *dostrdup(const char *s);
|
||||
char *dostrdup2(const char *s, const char *t);
|
||||
char *dostrdup3(const char *s, const char *t, const char *u);
|
||||
char *dostrndup(const char *s, size_t len);
|
||||
void dostrfree(char *s);
|
||||
|
||||
size_t notrailingws(char *buf, size_t len);
|
||||
bool is_identifier(const char *str);
|
||||
|
||||
/* in place.c */
|
||||
void complain_init(const char *progname);
|
||||
void complain(const struct place *, const char *fmt, ...) PF(2, 3);
|
||||
void complain_fail(void);
|
||||
bool complain_failed(void);
|
||||
|
||||
/* in main.c */
|
||||
void freestringlater(char *s);
|
||||
DEAD void die(void);
|
||||
@@ -0,0 +1,33 @@
|
||||
/*-
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#define VERSION_MAJOR "0"
|
||||
#define VERSION_MINOR "4"
|
||||
#define VERSION_STRING "0.4"
|
||||
#define VERSION_LONG "NetBSD tradcpp 0.4"
|
||||
Reference in New Issue
Block a user