xenocara/app/xrdb-cpp/arith.h
matthieu a2223c7302 Import a copy of ucpp, lightweight cpp for use by xrdb so that it
doesn't depend on the 'comp'  set. ok espie@ deraadt@
2014-07-12 14:25:39 +00:00

256 lines
10 KiB
C

/*
* Integer arithmetic evaluation, header file.
*
* (c) Thomas Pornin 2002
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. The name of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* This arithmetic evaluator uses two files: this header file (arith.h)
* and the source file (arith.c). To use this code, the source file should
* be included from another .c file which defines some macros (see below).
* Then the functions defined in the arith.c file become available to the
* including source file. If those functions are defined with external
* linkage (that is, `ARITH_FUNCTION_HEADER' does not contain `static'),
* it is possible for other source files to use the arithmetic functions
* by including the arith.h header only. The source file which includes
* arith.c should *not* include arith.h.
*
* If the #include is for arith.h, the following macros should be
* defined:
*
* -- If the evaluator is supposed to use a native type:
* NATIVE_SIGNED the native signed integer type
* NATIVE_UNSIGNED the native unsigned integer type
*
* -- If the evaluator is supposed to use an emulated type:
* SIMUL_ARITH_SUBTYPE the native unsigned type used for the simulation
* SIMUL_SUBTYPE_BITS the native unsigned type size
* SIMUL_NUMBITS the emulated type size
*
* -- For both cases:
* ARITH_TYPENAME the central arithmetic type name
* ARITH_FUNCTION_HEADER the qualifiers to add to function definitions
*
* The presence (respectively absence) of the NATIVE_SIGNED macro triggers
* the use of the native type evaluator (respectively simulated type
* evaluator).
*
* If the #include is for arith.c, the macros for arith.h should be defined,
* and the following should be defined as well:
*
* -- If the evaluator is supposed to use a native type:
* NATIVE_UNSIGNED_BITS the native unsigned type size
* NATIVE_SIGNED_MIN the native signed minimum value
* NATIVE_SIGNED_MAX the native signed maximum value
* (the last two macros must evaluate to signed constant expressions)
*
* -- For both cases:
* ARITH_WARNING(type) code to perform on warning
* ARITH_ERROR(type) code to perform on error
*
* The macro ARITH_WARNING() and ARITH_ERROR() are invoked with a
* numerical argument which is one of the enumeration constants
* defined below (ARITH_EXCEP_*) that identifies the specific problem.
*
* If the #include is for arith.c, the macro ARITHMETIC_CHECKS may be
* defined. When this macro is defined, checks are performed so that all
* operation which would lead to undefined or implementation-defined
* behaviour are first reported through ARITH_WARNING(). Code is smaller
* and faster without these checks, of course. Regardless of the status
* of that macro, divisions by 0 and overflows on signed division are
* reported as errors through ARITH_ERROR().
*
*/
#ifndef ARITH_H__
#define ARITH_H__
enum {
/* Warnings */
ARITH_EXCEP_CONV_O, /* overflow on conversion */
ARITH_EXCEP_NEG_O, /* overflow on unary minus */
ARITH_EXCEP_NOT_T, /* trap representation on bitwise inversion */
ARITH_EXCEP_PLUS_O, /* overflow on addition */
ARITH_EXCEP_PLUS_U, /* underflow on addition */
ARITH_EXCEP_MINUS_O, /* overflow on subtraction */
ARITH_EXCEP_MINUS_U, /* underflow on subtraction */
ARITH_EXCEP_AND_T, /* trap representation on bitwise and */
ARITH_EXCEP_XOR_T, /* trap representation on bitwise xor */
ARITH_EXCEP_OR_T, /* trap representation on bitwise or */
ARITH_EXCEP_LSH_W, /* left shift by type width or more */
ARITH_EXCEP_LSH_C, /* left shift by negative count */
ARITH_EXCEP_LSH_O, /* overflow on left shift */
ARITH_EXCEP_LSH_U, /* underflow on left shift */
ARITH_EXCEP_RSH_W, /* right shift by type width or more */
ARITH_EXCEP_RSH_C, /* right shift by negative count */
ARITH_EXCEP_RSH_N, /* right shift of negative value */
ARITH_EXCEP_STAR_O, /* overflow on multiplication */
ARITH_EXCEP_STAR_U, /* underflow on multiplication */
/* Errors */
ARITH_EXCEP_SLASH_D, /* division by 0 */
ARITH_EXCEP_SLASH_O, /* overflow on division */
ARITH_EXCEP_PCT_D, /* division by 0 on modulus operator */
ARITH_EXCEP_CONST_O /* constant too large */
};
#define arith_strc_(x, y) x ## y
#define arith_strc(x, y) arith_strc_(x, y)
#define arith_u arith_strc(u_, ARITH_TYPENAME)
#define arith_s arith_strc(s_, ARITH_TYPENAME)
#define arith_op_u(op) arith_strc(ARITH_TYPENAME, arith_strc(_u_, op))
#define arith_op_s(op) arith_strc(ARITH_TYPENAME, arith_strc(_s_, op))
#define ARITH_DECL_MONO_U_U(op) ARITH_FUNCTION_HEADER arith_u \
arith_op_u(op)(arith_u x)
#define ARITH_DECL_MONO_U_S(op) ARITH_FUNCTION_HEADER arith_s \
arith_op_u(op)(arith_u x)
#define ARITH_DECL_MONO_U_I(op) ARITH_FUNCTION_HEADER int \
arith_op_u(op)(arith_u x)
#define ARITH_DECL_MONO_U_L(op) ARITH_FUNCTION_HEADER unsigned long \
arith_op_u(op)(arith_u x)
#define ARITH_DECL_MONO_S_U(op) ARITH_FUNCTION_HEADER arith_u \
arith_op_s(op)(arith_s x)
#define ARITH_DECL_MONO_S_S(op) ARITH_FUNCTION_HEADER arith_s \
arith_op_s(op)(arith_s x)
#define ARITH_DECL_MONO_S_I(op) ARITH_FUNCTION_HEADER int \
arith_op_s(op)(arith_s x)
#define ARITH_DECL_MONO_S_L(op) ARITH_FUNCTION_HEADER long \
arith_op_s(op)(arith_s x)
#define ARITH_DECL_MONO_I_U(op) ARITH_FUNCTION_HEADER arith_u \
arith_op_u(op)(int x)
#define ARITH_DECL_MONO_L_U(op) ARITH_FUNCTION_HEADER arith_u \
arith_op_u(op)(unsigned long x)
#define ARITH_DECL_MONO_I_S(op) ARITH_FUNCTION_HEADER arith_s \
arith_op_s(op)(int x)
#define ARITH_DECL_MONO_L_S(op) ARITH_FUNCTION_HEADER arith_s \
arith_op_s(op)(long x)
#define ARITH_DECL_MONO_ST_US(op) ARITH_FUNCTION_HEADER char *arith_op_u(op) \
(char *c, arith_u *ru, arith_s *rs, int *sp)
#define ARITH_DECL_BI_UU_U(op) ARITH_FUNCTION_HEADER arith_u \
arith_op_u(op)(arith_u x, arith_u y)
#define ARITH_DECL_BI_UI_U(op) ARITH_FUNCTION_HEADER arith_u \
arith_op_u(op)(arith_u x, int y)
#define ARITH_DECL_BI_UU_I(op) ARITH_FUNCTION_HEADER int \
arith_op_u(op)(arith_u x, arith_u y)
#define ARITH_DECL_BI_SS_S(op) ARITH_FUNCTION_HEADER arith_s \
arith_op_s(op)(arith_s x, arith_s y)
#define ARITH_DECL_BI_SI_S(op) ARITH_FUNCTION_HEADER arith_s \
arith_op_s(op)(arith_s x, int y)
#define ARITH_DECL_BI_SS_I(op) ARITH_FUNCTION_HEADER int \
arith_op_s(op)(arith_s x, arith_s y)
#endif
#ifdef NATIVE_SIGNED
typedef NATIVE_SIGNED arith_s;
typedef NATIVE_UNSIGNED arith_u;
#else
#if SIMUL_NUMBITS > (2 * SIMUL_SUBTYPE_BITS)
#error Native subtype too small for arithmetic simulation.
#endif
#define SIMUL_MSW_WIDTH (SIMUL_NUMBITS / 2)
#define SIMUL_LSW_WIDTH ((SIMUL_NUMBITS + 1) / 2)
typedef struct {
SIMUL_ARITH_SUBTYPE msw, lsw;
} arith_u, arith_s;
#endif
/* functions with the unsigned type */
ARITH_DECL_MONO_S_U(to_u);
ARITH_DECL_MONO_I_U(fromint);
ARITH_DECL_MONO_L_U(fromulong);
ARITH_DECL_MONO_U_I(toint);
ARITH_DECL_MONO_U_L(toulong);
ARITH_DECL_MONO_U_U(neg);
ARITH_DECL_MONO_U_U(not);
ARITH_DECL_MONO_U_I(lnot);
ARITH_DECL_MONO_U_I(lval);
ARITH_DECL_BI_UU_U(plus);
ARITH_DECL_BI_UU_U(minus);
ARITH_DECL_BI_UI_U(lsh);
ARITH_DECL_BI_UI_U(rsh);
ARITH_DECL_BI_UU_I(lt);
ARITH_DECL_BI_UU_I(leq);
ARITH_DECL_BI_UU_I(gt);
ARITH_DECL_BI_UU_I(geq);
ARITH_DECL_BI_UU_I(same);
ARITH_DECL_BI_UU_I(neq);
ARITH_DECL_BI_UU_U(and);
ARITH_DECL_BI_UU_U(xor);
ARITH_DECL_BI_UU_U(or);
ARITH_DECL_BI_UU_U(star);
ARITH_DECL_BI_UU_U(slash);
ARITH_DECL_BI_UU_U(pct);
/* functions with the signed type */
ARITH_DECL_MONO_U_S(to_s);
ARITH_DECL_MONO_I_S(fromint);
ARITH_DECL_MONO_L_S(fromlong);
ARITH_DECL_MONO_S_I(toint);
ARITH_DECL_MONO_S_L(tolong);
ARITH_DECL_MONO_S_S(neg);
ARITH_DECL_MONO_S_S(not);
ARITH_DECL_MONO_S_I(lnot);
ARITH_DECL_MONO_S_I(lval);
ARITH_DECL_BI_SS_S(plus);
ARITH_DECL_BI_SS_S(minus);
ARITH_DECL_BI_SI_S(lsh);
ARITH_DECL_BI_SI_S(rsh);
ARITH_DECL_BI_SS_I(lt);
ARITH_DECL_BI_SS_I(leq);
ARITH_DECL_BI_SS_I(gt);
ARITH_DECL_BI_SS_I(geq);
ARITH_DECL_BI_SS_I(same);
ARITH_DECL_BI_SS_I(neq);
ARITH_DECL_BI_SS_S(and);
ARITH_DECL_BI_SS_S(xor);
ARITH_DECL_BI_SS_S(or);
ARITH_DECL_BI_SS_S(star);
ARITH_DECL_BI_SS_S(slash);
ARITH_DECL_BI_SS_S(pct);
/* conversions from string */
ARITH_DECL_MONO_ST_US(octconst);
ARITH_DECL_MONO_ST_US(hexconst);
ARITH_DECL_MONO_ST_US(decconst);