1/**
2 * \file libyasm/valparam.h
3 * \brief YASM value/parameter interface.
4 *
5 * \license
6 *  Copyright (C) 2001-2007  Peter Johnson
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *  - Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 *  - Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
21 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 * \endlicense
29 */
30#ifndef YASM_VALPARAM_H
31#define YASM_VALPARAM_H
32
33#ifndef YASM_LIB_DECL
34#define YASM_LIB_DECL
35#endif
36
37/** Value/parameter pair.  \internal */
38struct yasm_valparam {
39    /*@reldef@*/ STAILQ_ENTRY(yasm_valparam) link;  /**< Next pair in list */
40    /*@owned@*/ /*@null@*/ char *val;           /**< Value */
41
42    /** Parameter type. */
43    enum yasm_param_type {
44        YASM_PARAM_ID,                          /**< Identifier */
45        YASM_PARAM_STRING,                      /**< String */
46        YASM_PARAM_EXPR                         /**< Expression */
47    } type;                                     /**< Parameter type */
48
49    /** Parameter value. */
50    union yasm_param {
51        /*@owned@*/ char *id;                   /**< Identifier */
52        /*@owned@*/ char *str;                  /**< String */
53        /*@owned@*/ yasm_expr *e;               /**< Expression */
54    } param;                                    /**< Parameter */
55
56    /** Prefix character that indicates a raw identifier.  When
57     * yasm_vp_string() is called on a #YASM_PARAM_ID, all characters are
58     * returned.  When yasm_vp_id() is called on a #YASM_PARAM_ID, if the
59     * identifier begins with this character, this character is stripped
60     * from the returned value.
61     */
62    char id_prefix;
63};
64
65/** Linked list of value/parameter pairs.  \internal */
66/*@reldef@*/ STAILQ_HEAD(yasm_valparamhead, yasm_valparam);
67
68/** Directive list entry structure. */
69struct yasm_directive {
70    /** Directive name.  GAS directives should include the ".", NASM
71     * directives should just be the raw name (not including the []).
72     * NULL entry required to terminate list of directives.
73     */
74    /*@null@*/ const char *name;
75
76    const char *parser;                     /**< Parser keyword */
77
78    /** Handler callback function for the directive.
79     * \param object            object
80     * \param valparams         value/parameters
81     * \param objext_valparams  object format-specific value/parameters
82     * \param line              virtual line (from yasm_linemap)
83     */
84    void (*handler) (yasm_object *object, yasm_valparamhead *valparams,
85                     yasm_valparamhead *objext_valparams, unsigned long line);
86
87    /** Flags for pre-handler parameter checking. */
88    enum yasm_directive_flags {
89        YASM_DIR_ANY = 0,           /**< Any valparams accepted */
90        YASM_DIR_ARG_REQUIRED = 1,  /**< Require at least 1 valparam */
91        YASM_DIR_ID_REQUIRED = 2    /**< First valparam must be ID */
92    } flags;
93};
94
95/** Call a directive.  Performs any valparam checks asked for by the
96 * directive prior to call.  Note that for a variety of reasons, a directive
97 * can generate an error.
98 * \param directive             directive
99 * \param object                object
100 * \param valparams             value/parameters
101 * \param objext_valparams      object format-specific value/parameters
102 * \param line                  virtual line (from yasm_linemap)
103 */
104YASM_LIB_DECL
105void yasm_call_directive(const yasm_directive *directive, yasm_object *object,
106                         yasm_valparamhead *valparams,
107                         yasm_valparamhead *objext_valparams,
108                         unsigned long line);
109
110/** Create a new valparam with identifier parameter.
111 * \param v             value
112 * \param p             parameter
113 * \param id_prefix     identifier prefix for raw identifiers
114 * \return Newly allocated valparam.
115 */
116YASM_LIB_DECL
117yasm_valparam *yasm_vp_create_id(/*@keep@*/ char *v, /*@keep@*/ char *p,
118                                 int id_prefix);
119
120/** Create a new valparam with string parameter.
121 * \param v     value
122 * \param p     parameter
123 * \return Newly allocated valparam.
124 */
125YASM_LIB_DECL
126yasm_valparam *yasm_vp_create_string(/*@keep@*/ char *v, /*@keep@*/ char *p);
127
128/** Create a new valparam with expression parameter.
129 * \param v     value
130 * \param p     parameter
131 * \return Newly allocated valparam.
132 */
133YASM_LIB_DECL
134yasm_valparam *yasm_vp_create_expr(/*@keep@*/ char *v,
135                                   /*@keep@*/ yasm_expr *p);
136
137/** Get a valparam parameter as an expr.  If the parameter is an identifier,
138 * it's treated as a symbol (yasm_symtab_use() is called to convert it).
139 * \param vp            valparam
140 * \param symtab        symbol table
141 * \param line          virtual line
142 * \return Expression, or NULL if vp is NULL or the parameter cannot be
143 *         converted to an expression.
144 */
145YASM_LIB_DECL
146/*@null@*/ /*@only@*/ yasm_expr *yasm_vp_expr
147    (const yasm_valparam *vp, yasm_symtab *symtab, unsigned long line);
148
149/** Get a valparam parameter as a string.  If the parameter is an identifier,
150 * it's treated as a string.
151 * \param vp            valparam
152 * \return String, or NULL if vp is NULL or the parameter cannot be realized
153 *         as a string.
154 */
155YASM_LIB_DECL
156/*@null@*/ /*@dependent@*/ const char *yasm_vp_string(const yasm_valparam *vp);
157
158/** Get a valparam parameter as an identifier.
159 * \param vp            valparam
160 * \return Identifier (string), or NULL if vp is NULL or the parameter is not
161 *         an identifier.
162 */
163YASM_LIB_DECL
164/*@null@*/ /*@dependent@*/ const char *yasm_vp_id(const yasm_valparam *vp);
165
166/** Create a new linked list of valparams.
167 * \return Newly allocated valparam list.
168 */
169YASM_LIB_DECL
170yasm_valparamhead *yasm_vps_create(void);
171
172/** Destroy a list of valparams (created with yasm_vps_create).
173 * \param headp         list of valparams
174 */
175YASM_LIB_DECL
176void yasm_vps_destroy(yasm_valparamhead *headp);
177
178/** Initialize linked list of valparams.
179 * \param headp linked list
180 */
181void yasm_vps_initialize(/*@out@*/ yasm_valparamhead *headp);
182#ifndef YASM_DOXYGEN
183#define yasm_vps_initialize(headp)      STAILQ_INIT(headp)
184#endif
185
186/** Destroy (free allocated memory for) linked list of valparams (created with
187 * yasm_vps_initialize).
188 * \warning Deletes val/params.
189 * \param headp linked list
190 */
191YASM_LIB_DECL
192void yasm_vps_delete(yasm_valparamhead *headp);
193
194/** Append valparam to tail of linked list.
195 * \param headp linked list
196 * \param vp    valparam
197 */
198void yasm_vps_append(yasm_valparamhead *headp, /*@keep@*/ yasm_valparam *vp);
199#ifndef YASM_DOXYGEN
200#define yasm_vps_append(headp, vp)      do {        \
201        if (vp)                                     \
202            STAILQ_INSERT_TAIL(headp, vp, link);    \
203    } while(0)
204#endif
205
206/** Get first valparam in linked list.
207 * \param headp linked list
208 * \return First valparam in linked list.
209 */
210/*@null@*/ /*@dependent@*/ yasm_valparam *yasm_vps_first
211    (yasm_valparamhead *headp);
212#ifndef YASM_DOXYGEN
213#define yasm_vps_first(headp)       STAILQ_FIRST(headp)
214#endif
215
216/** Get next valparam in linked list.
217 * \param cur   previous valparam in linked list
218 * \return Next valparam in linked list.
219 */
220/*@null@*/ /*@dependent@*/ yasm_valparam *yasm_vps_next(yasm_valparam *cur);
221#ifndef YASM_DOXYGEN
222#define yasm_vps_next(cur)          STAILQ_NEXT(cur, link)
223#endif
224
225/** Iterate through linked list of valparams.
226 * \internal
227 * \param iter      iterator variable
228 * \param headp     linked list
229 */
230#ifndef YASM_DOXYGEN
231#define yasm_vps_foreach(iter, headp)   STAILQ_FOREACH(iter, headp, link)
232#endif
233
234/** Print linked list of valparams.  For debugging purposes.
235 * \param f     file
236 * \param headp linked list
237 */
238YASM_LIB_DECL
239void yasm_vps_print(/*@null@*/ const yasm_valparamhead *headp, FILE *f);
240
241/** Directive valparam parse helper structure. */
242typedef struct yasm_dir_help {
243    /** Value portion of val=param (if needsparam=1), or standalone identifier
244     * (if needsparam=0).
245     */
246    const char *name;
247
248    /** 1 if value requires parameter, 0 if it must not have a parameter. */
249    int needsparam;
250
251    /** Helper callback function if name and parameter existence match.
252     * \param obj       obj passed into yasm_dir_helper()
253     * \param vp        value/parameter
254     * \param line      line passed into yasm_dir_helper()
255     * \param data      data passed into yasm_dir_helper() plus
256                        #yasm_dir_help.off offset
257     * \param arg       #yasm_dir_help.arg argument
258     * \return -1 on error, 0 otherwise.
259     */
260    int (*helper) (void *obj, yasm_valparam *vp, unsigned long line,
261                   void *data, uintptr_t arg);
262
263    /** Offset added to data pointer passed into yasm_dir_helper() before
264     * data pointer is given to #yasm_dir_help.helper().  This is so that
265     * a structure can be passed into yasm_dir_helper() and this can be an
266     * offsetof() to point the helper function to a specific structure
267     * member.
268     */
269    size_t off;
270
271    /** Argument to pass in as the arg parameter to #yasm_dir_help.helper().
272     */
273    uintptr_t arg;
274} yasm_dir_help;
275
276/** Help parse a list of directive value/parameters.  Takes an array of
277 * #yasm_dir_help structures and tries to match val=param (or just val)
278 * against the passed value/parameters.  When no match is found in the
279 * array of help structures, calls helper_valparam.
280 * \param obj       object to be passed to yasm_dir_help.helper() or
281 *                  helper_valparam() callback
282 * \param vp_first  first value/parameter to examine
283 * \param line      virtual line number; passed down to helper callback
284 * \param help      array of #yasm_dir_help structures
285 * \param nhelp     number of array elements
286 * \param data      base data pointer; if a match is found,
287 *                  the respective #yasm_dir_help.off is added to this
288 *                  prior to it being passed to the helper callback
289 * \param helper_valparam   catch-all callback; should return -1 on error,
290 *                          0 if not matched, 1 if matched.
291 * \return -1 on error, 1 if any arguments matched (including via
292 *         catch-all callback), 0 if no match.
293 */
294YASM_LIB_DECL
295int yasm_dir_helper(void *obj, yasm_valparam *vp_first, unsigned long line,
296                    const yasm_dir_help *help, size_t nhelp, void *data,
297                    int (*helper_valparam) (void *object,
298                                            yasm_valparam *vp,
299                                            unsigned long line,
300                                            void *data));
301
302/** Standard helper for yasm_dir_helper() that simply sets a flag when called.
303 * It does not look at the vp; rather, it uses the value of the arg parameter,
304 * and stores an unsigned long value to data.
305 * \param obj   unused
306 * \param vp    unused
307 * \param line  unused
308 * \param data  pointer to an unsigned long
309 * \param arg   flag to set
310 * \return 0
311 */
312YASM_LIB_DECL
313int yasm_dir_helper_flag_set(void *obj, yasm_valparam *vp, unsigned long line,
314                             void *data, uintptr_t arg);
315
316/** Standard helper for yasm_dir_helper() that simply ORs a flag when called.
317 * It does not look at the vp; rather, it uses the value of the arg parameter,
318 * and ORs it with the unsigned long value in data.
319 * \param obj   unused
320 * \param vp    unused
321 * \param line  unused
322 * \param data  pointer to an unsigned long
323 * \param arg   flag to OR
324 * \return 0
325 */
326YASM_LIB_DECL
327int yasm_dir_helper_flag_or(void *obj, yasm_valparam *vp, unsigned long line,
328                            void *data, uintptr_t arg);
329
330/** Standard helper for yasm_dir_helper() that simply ANDs a flag when called.
331 * It does not look at the vp; rather, it uses the value of the arg parameter,
332 * and ANDs its inverse (~) with the unsigned long value in data.
333 * \param obj   unused
334 * \param vp    unused
335 * \param line  unused
336 * \param data  pointer to an unsigned long
337 * \param arg   flag to AND
338 * \return 0
339 */
340YASM_LIB_DECL
341int yasm_dir_helper_flag_and(void *obj, yasm_valparam *vp, unsigned long line,
342                             void *data, uintptr_t arg);
343
344/** Standard helper for yasm_dir_helper() that parses an expr parameter.
345 * The #yasm_dir_help structure that uses this function should have
346 * needsparam=1.  The obj parameter to yasm_dir_helper() when this helper
347 * is used MUST point to a #yasm_object.  In addition, the data parameter
348 * that is ultimately passed to this function (e.g. yasm_dir_helper() data
349 * parameter plus #yasm_dir_help.off) must point to a #yasm_expr *
350 * initialized to NULL.
351 * \param obj   object; must be #yasm_object
352 * \param vp    valparam
353 * \param line  virtual line number
354 * \param data  pointer to #yasm_expr *
355 * \param arg   unused argument
356 * \return -1 on error, 0 otherwise.
357 */
358YASM_LIB_DECL
359int yasm_dir_helper_expr(void *obj, yasm_valparam *vp, unsigned long line,
360                         void *data, uintptr_t arg);
361
362/** Standard helper for yasm_dir_helper() that parses an intnum parameter.
363 * The #yasm_dir_help structure that uses this function should have
364 * needsparam=1.  The obj parameter to yasm_dir_helper() when this helper
365 * is used MUST point to a #yasm_object.  In addition, the data parameter
366 * that is ultimately passed to this function (e.g. yasm_dir_helper() data
367 * parameter plus #yasm_dir_help.off) must point to a #yasm_intnum *
368 * initialized to NULL.
369 * \param obj   object; must be #yasm_object
370 * \param vp    valparam
371 * \param line  virtual line number
372 * \param data  pointer to #yasm_intnum *
373 * \param arg   unused argument
374 * \return -1 on error, 0 otherwise.
375 */
376YASM_LIB_DECL
377int yasm_dir_helper_intn(void *obj, yasm_valparam *vp, unsigned long line,
378                         void *data, uintptr_t arg);
379
380/** Standard helper for yasm_dir_helper() that parses an string (or
381 * standalone identifier) parameter.
382 * The #yasm_dir_help structure that uses this function should have
383 * needsparam=1.  The data parameter that is ultimately passed to this
384 * function (e.g. yasm_dir_helper() data parameter plus #yasm_dir_help.off)
385 * must point to a char * initialized to NULL.
386 * \param obj   unused
387 * \param vp    valparam
388 * \param line  unused
389 * \param data  pointer to char *
390 * \param arg   unused
391 * \return -1 on error, 0 otherwise.
392 */
393YASM_LIB_DECL
394int yasm_dir_helper_string(void *obj, yasm_valparam *vp, unsigned long line,
395                           void *data, uintptr_t arg);
396
397/** Standard catch-all callback fro yasm_dir_helper().  Generates standard
398 * warning for all valparams.
399 * \param obj   unused
400 * \param vp    valparam
401 * \param line  unused
402 * \param data  unused
403 * \return 0
404 */
405YASM_LIB_DECL
406int yasm_dir_helper_valparam_warn(void *obj, yasm_valparam *vp,
407                                  unsigned long line, void *data);
408#endif
409