gui: Allow File|Open to select an encoding for system files.
[pspp] / src / libpspp / cast.h
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #ifndef LIBPSPP_CAST_H
18 #define LIBPSPP_CAST_H 1
19
20 #include <stddef.h>
21 #include "gl/verify.h"
22
23 /* Expands to a void expression that checks that POINTER is an
24    expression whose type is a qualified or unqualified version of
25    a type compatible with TYPE (a pointer type) and, if not,
26    causes a compiler warning to be issued (on typical compilers).
27
28    Examples:
29
30    int *ip;
31    const int *cip;
32    const int **cipp;
33    int ***ippp;
34    double *dp;
35
36    // None of these causes a warning:
37    CHECK_POINTER_HAS_TYPE (ip, int *);
38    CHECK_POINTER_HAS_TYPE (ip, const int *);
39    CHECK_POINTER_HAS_TYPE (cip, int *);
40    CHECK_POINTER_HAS_TYPE (cip, const int *);
41    CHECK_POINTER_HAS_TYPE (dp, double *);
42    CHECK_POINTER_HAS_TYPE (dp, const double *);
43    CHECK_POINTER_HAS_TYPE (cipp, const int **);
44    CHECK_POINTER_HAS_TYPE (cipp, const int *const *);
45    CHECK_POINTER_HAS_TYPE (ippp, int ***);
46    CHECK_POINTER_HAS_TYPE (ippp, int **const *);
47
48    // None of these causes a warning either, although it is unusual to
49    // const-qualify a pointer like this (it's like declaring a "const int",
50    // for example).
51    CHECK_POINTER_HAS_TYPE (ip, int *const);
52    CHECK_POINTER_HAS_TYPE (ip, const int *const);
53    CHECK_POINTER_HAS_TYPE (cip, int *const);
54    CHECK_POINTER_HAS_TYPE (cip, const int *const);
55    CHECK_POINTER_HAS_TYPE (cipp, const int **const);
56    CHECK_POINTER_HAS_TYPE (cipp, const int *const *const);
57    CHECK_POINTER_HAS_TYPE (ippp, int ***const);
58    CHECK_POINTER_HAS_TYPE (ippp, int **const *const);
59
60    // Provokes a warning because "int" is not compatible with "double":
61    CHECK_POINTER_HAS_TYPE (dp, int *);
62
63    // Provoke warnings because C's type compatibility rules only allow
64    // adding a "const" qualifier to the outermost pointer:
65    CHECK_POINTER_HAS_TYPE (ippp, const int ***);
66    CHECK_POINTER_HAS_TYPE (ippp, int *const**);
67 */
68 #define CHECK_POINTER_HAS_TYPE(POINTER, TYPE)           \
69         ((void) sizeof ((TYPE) (POINTER) == (POINTER)))
70
71 /* Given expressions A and B, both of which have pointer type,
72    expands to a void expression that causes a compiler warning if
73    A and B are not pointers to qualified or unqualified versions
74    of compatible types.
75
76    Examples similar to those given for CHECK_POINTER_HAS_TYPE,
77    above, can easily be devised. */
78 #define CHECK_POINTER_COMPATIBILITY(A, B) ((void) sizeof ((A) == (B)))
79
80 /* Equivalent to casting POINTER to TYPE, but also issues a
81    warning if the cast changes anything other than an outermost
82    "const" or "volatile" qualifier. */
83 #define CONST_CAST(TYPE, POINTER)                       \
84         (CHECK_POINTER_HAS_TYPE (POINTER, TYPE),        \
85          (TYPE) (POINTER))
86
87 /* Casts POINTER to TYPE.  Yields a compiler diagnostic if either TYPE or
88    POINTER is not a pointer to character type.
89
90    PSPP uses "unsigned char" (actually uint8_t) in "union value" and "char"
91    elsewhere to emphasize that data in union value usually requires reencoding
92    when transferred to and from other string types.  These macros suppress the
93    warning when implicitly converting between pointers to different character
94    types, so their use normally marks a bug that should eventually be fixed.
95    However, until these bugs are fixed, suppressing the warnings is much less
96    annoying.
97
98    Use CHAR_CAST_BUG if you think there is a bug to be fixed, or if you have
99    not yet carefully examined the situation, or if you are not sure.
100    Use CHAR_CAST if you are convinced that this is actually a correct cast. */
101 #define CHAR_CAST(TYPE, POINTER)                                \
102   ((void) verify_expr (sizeof (*(POINTER)) == 1, 1),            \
103    (void) (sizeof (*(POINTER) + 1)),                            \
104    (void) verify_expr (sizeof (*(TYPE) NULL) == 1, 1),          \
105    (void) (sizeof (*(TYPE) NULL + 1)),                          \
106    (TYPE) (POINTER))
107 #define CHAR_CAST_BUG(TYPE, POINTER) CHAR_CAST(TYPE, POINTER)
108
109 /* Given POINTER, a pointer to the given MEMBER within structure
110    STRUCT, returns the address of the STRUCT. */
111 #define UP_CAST(POINTER, STRUCT, MEMBER)                                \
112         (CHECK_POINTER_COMPATIBILITY (&((STRUCT *) 0)->MEMBER, POINTER), \
113          (STRUCT *) ((char *) (POINTER) - offsetof (STRUCT, MEMBER)))
114
115 /* A null pointer constant suitable for use in a varargs parameter list.
116
117    This is useful because a literal 0 may not have the same width as a null
118    pointer.  NULL by itself is also insufficient because in C it may expand to
119    simply 0. */
120 #define NULL_SENTINEL ((void *) NULL)
121
122 #endif /* libpspp/cast.h */