File: jx_match.h

package info (click to toggle)
cctools 9.9-2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 44,624 kB
  • sloc: ansic: 192,539; python: 20,827; cpp: 20,199; sh: 11,719; perl: 4,106; xml: 3,688; makefile: 1,224
file content (207 lines) | stat: -rw-r--r-- 7,016 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
Copyright (C) 2016- The University of Notre Dame
This software is distributed under the GNU General Public License.
See the file COPYING for details.
*/

/** @file jx_match.h Unwrap JX types
 *
 * The functions in this header are intended to make JX types more usable
 * from C code. All unwrap JX values in some manner, allowing access to
 * native C types. For the arrays, the match function can be
 * used to destructure its arguments, extracting and type-checking
 * components in a single call.
 * The match functions for single values return an int indicating the
 * result of the match. On match failure, 0 is returned, or 1 on success.
 * The match functions can also give the caller a copy of
 * the matched value. For heap-allocated types, the caller is responsible
 * for free()ing/jx_delete()ing the copied values. In the case that the
 * caller requested a heap-allocated copy but malloc() fails, the match
 * as a whole will fail. This ensures that it is always safe to dereference
 * the copy given back, but might falsely indicate an incorrect type. Code
 * that needs to run in out of memory conditions must not request copies.
 *
 * The common use case is that programs will have some stack allocated
 * variables for local use, and would like to read the value in a JX struct.
 *
 * @code
 *     double val;
 *     if (jx_match_double(j, &val)) {
 *         printf("got value %f\n", val);
 *     } else {
 *         printf("not a valid double\n");
 *     }
 * @endcode
 *
 * Here, the return value is used to check that the given JX struct was
 * in fact a double, and to copy the value onto the local function's
 * stack. If a function needs to modify the JX structure, it must
 * access the struct fields directly.
 *
 * There is also a matching function to extract multiple positional
 * values from an array and validate types in a single call.
 * This function has a scanf()-like interface.
 * The array matching function takes a JX struct
 * and a sequence of item specifications. Each item
 * spec includes a JX type and the location of a pointer that will reference
 * the extracted value. The match function
 * processes each specification in turn, stopping on an invalid spec,
 * or NULL, and returning the number of items succesfully matched.
 *
 * @code
 *     jx_int_t a;
 *     double b;
 *     switch (jx_match_array(j, &a, JX_INTEGER, &b, JX_DOUBLE, NULL)) {
 *     case 1:
 *         printf("got int %d\n", a);
 *     case 2:
 *         printf("got %d and %f\n", a, b)
 *     default:
 *         printf("bad match\n");
 *     }
 * @endcode
 *
 * It's also possible to match on a position without looking at the
 * type of the matched value. The pseudo-type JX_ANY is provided
 * for this purpose. Since the type of the value matched by JX_ANY is
 * unknown, the caller might want to use the other match functions to
 * handle whatever cases they're interested in. The following example
 * uses most of the matching functionality.
 *
 * @code
 *     struct jx *a;
 *     struct jx *b;
 *     if (jx_match_array(j, &a, JX_ARRAY, &b, JX_ANY, NULL) == 2) {
 *         printf("got JX_ARRAY at %p\n", a);
 *         if (jx_istype(b, JX_STRING)) {
 *             printf("no longer supported\n");
 *             return 0;
 *         }
 *         jx_int_t val;
 *         if (jx_match_integer(b, &val)) {
 *             return val % 8;
 *         }
 *     }
 * @endcode
 */

#ifndef JX_MATCH_H
#define JX_MATCH_H

#include "jx.h"

#ifndef JX_ANY
#define JX_ANY -1
#endif

/*
 * Macro to test if we're using a GNU C compiler of a specific vintage
 * or later, for e.g. features that appeared in a particular version
 * of GNU C.  Usage:
 *
 * #if __GNUC_PREREQ__(major, minor)
 * ...cool feature...
 * #else
 * ...delete feature...
 * #endif
 */
#ifndef __GNUC_PREREQ__
#ifdef __GNUC__
#define __GNUC_PREREQ__(x, y) \
	((__GNUC__ == (x) && __GNUC_MINOR__ >= (y)) || \
	 (__GNUC__ > (x)))
#else
#define __GNUC_PREREQ__(x, y) 0
#endif
#endif

#ifndef __wur
#if __GNUC_PREREQ__(3, 4)
#define __wur __attribute__((warn_unused_result))
#else
#define __wur
#endif
#endif

#ifndef __sentinel
#if __GNUC_PREREQ__(4, 0)
#define __sentinel __attribute__((sentinel))
#else
#define __sentinel
#endif
#endif

/** Unwrap a boolean value.
 * @param j The JX structure to match.
 * @param v An address to copy the boolean value to, or NULL if copying
 * the value is unnecessary.
 * @return A truth value indicating the result of the match.
 */
int jx_match_boolean(struct jx *j, int *v) __wur;

/** Unwrap an integer value.
 * @param j The JX structure to match.
 * @param v An address to copy the integer value to, or NULL if copying
 * the value is unnecessary.
 * @return A truth value indicating the result of the match.
 */
int jx_match_integer(struct jx *j, jx_int_t *v) __wur;

/** Unwrap a double value.
 * @param j The JX structure to match.
 * @param v An address to copy the double value to, or NULL if copying
 * the value is unnecessary.
 * @return A truth value indicating the result of the match.
 */
int jx_match_double(struct jx *j, double *v) __wur;

/** Unwrap a string value.
 * Since C strings are just pointers to char arrays, the interface
 * here is a little awkward. If the caller has a stack-allocated
 * (char *), this function can allocate a copy of the string value
 * and store the address in the caller's pointer variable, e.g.
 *
 * @code
 *     char *val;
 *     if (jx_match_string(j, &val)) {
 *         printf("got value %s\n", val);
 *     }
 * @endcode
 *
 * @param j The JX structure to match.
 * @param v The address of a (char *) in which to store the address of
 * the newly malloc()ed string, or NULL if copying the value is unnecessary.
 * @return A truth value indicating the result of the match.
 */
int jx_match_string(struct jx *j, char **v) __wur;

/** Unwrap a symbol value.
 * This function accesses the symbol name as a string.
 * See @ref jx_match_string for details.
 *
 * @param j The JX structure to match.
 * @param v The address of a (char *) in which to store the address of
 * the newly malloc()ed symbol name, or NULL
 * if copying the value is unnecessary.
 * @return A truth value indicating the result of the match.
 */
int jx_match_symbol(struct jx *j, char **v) __wur;

/** Destructure an array.
 * This function accepts an arbitrary number of positional specifications
 * to attempt to match. Each specification is of the form
 *
 *     `<address>`, `<jx type>`
 *
 * where `<jx type>` is JX_INTEGER, JX_ANY, etc. and `<address>` is the address
 * to store the matched value. The last argument must be NULL to mark the
 * end of the specifications. The specifications will be matched
 * in the order given, and matching ends on the first failure. If the JX
 * value passed in was not an array, this is considered a failure before
 * any matches succeed, so 0 is returned.
 * @param j The JX structure to match.
 * @return The number of elements successfully matched.
 */
int jx_match_array(struct jx *j, ...) __wur __sentinel;

#endif