summaryrefslogtreecommitdiff
path: root/include/libast_internal.h
blob: e9b60212485939cf5a90a2086128387607e6e8be (plain)
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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
/*
 * Copyright (C) 1997-2004, Michael Jennings
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies of the Software, its documentation and marketing & publicity
 * materials, and acknowledgment shall be given in the documentation, materials
 * and software packages that this Software was used.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * @file libast_internal.h
 * LibAST header file for internal-use-only stuff.
 *
 * This file contains all macros, structure definitions, etc. which
 * are restricted to internal LibAST use only.
 *
 * @author Michael Jennings <mej@eterm.org>
 * @version $Revision$
 * @date $Date$
 */

#ifndef _LIBAST_INTERNAL_H_
#define _LIBAST_INTERNAL_H_

/* This GNU goop has to go before the system headers */
#ifdef __GNUC__
# ifndef __USE_GNU
#  define __USE_GNU
# endif
# ifndef _GNU_SOURCE
#  define _GNU_SOURCE
# endif
# ifndef _BSD_SOURCE
#  define _BSD_SOURCE
# endif
#endif

#include "config.h"
#include "libast.h"

#ifdef HAVE_STDARG_H
# include <stdarg.h>
#endif

/******************************** MSGS GOOP ***********************************/
extern spif_charptr_t libast_program_name, libast_program_version;



/********************************* MEM GOOP ***********************************/
/**
 * Filename length limit.
 *
 * This is used to limit the maximum length of a source filename.
 * When tracking memory allocation, the filename and line number for
 * each MALLOC()/REALLOC()/CALLOC()/FREE() call is recorded.  A small
 * buffer of static length is used to speed things up.
 *
 * @see MALLOC(), REALLOC(), CALLOC(), FREE()
 * @ingroup DOXGRP_MEM
 */
#define LIBAST_FNAME_LEN  20

/**
 * Pointer tracking structure.
 *
 * This structure is used by LibAST's memory management system to keep
 * track of what pointers have been allocated, where they were
 * allocated, and how much space was requested.
 *
 * @see MALLOC(), REALLOC(), CALLOC(), FREE()
 * @ingroup DOXGRP_MEM
 */
typedef struct ptr_t_struct {
    /** The allocated pointer.  The allocated pointer. */
    void *ptr;
    /** The pointer's size, in bytes.  The pointer's size, in bytes. */
    size_t size;
    /** Filename.  The file which last (re)allocated the pointer. */
    spif_char_t file[LIBAST_FNAME_LEN + 1];
    /** Line number.  The line number where the pointer was last (re)allocated. */
    spif_uint32_t line;
} ptr_t;
/**
 * Pointer list structure.
 *
 * This structure is used by LibAST's memory management system to hold
 * the list of pointers being tracked.  This list is maintained as an
 * array for simplicity.
 *
 * @see MALLOC(), REALLOC(), CALLOC(), FREE(), ptr_t_struct
 * @ingroup DOXGRP_MEM
 */
typedef struct memrec_t_struct {
    /** Pointer count.  The number of pointers being tracked. */
    size_t cnt;
    /** Pointer list.  The list of tracked pointers. */
    ptr_t *ptrs;
} memrec_t;



/******************************** CONF GOOP ***********************************/
/**
 * Convert context name to ID.
 *
 * This macro converts a context name as read from a config file into
 * the corresponding ID number.  If the context name is not found, an
 * error message is printed, and the ID number of 0 (the "null"
 * context) is returned.
 *
 * @bug This probably should not be a macro.
 * @bug The @a i parameter really isn't needed.
 *
 * @param the_id The return value -- the context ID.
 * @param n      The name of the context.
 * @param i      An arbitrary counter variable.
 *
 * @see @link DOXGRP_CONF_CTX Context Handling @endlink
 * @ingroup DOXGRP_CONF_CTX
 */
#define ctx_name_to_id(the_id, n, i) do { \
                                       for ((i)=0; (i) <= ctx_idx; (i)++) { \
                                         if (!strcasecmp(SPIF_CAST_C(char *) (n), \
                                                         SPIF_CAST_C(char *) context[(i)].name)) { \
                                           (the_id) = (i); \
                                           break; \
                                         } \
                                       } \
                                       if ((i) > ctx_idx) { \
                                         libast_print_error("Parsing file %s, line %lu:  No such context \"%s\"\n", \
                                                            file_peek_path(), file_peek_line(), (n)); \
                                         (the_id) = 0; \
                                       } \
                                     } while (0)
/**
 * Convert context ID to name.
 *
 * This macro converts a context ID to its name.
 *
 * @param id The context ID number.
 * @return   The name of the context.
 *
 * @see @link DOXGRP_CONF_CTX Context Handling @endlink
 * @ingroup DOXGRP_CONF_CTX
 */
#define ctx_id_to_name(id)         (context[(id)].name)
/**
 * Convert context ID to handler.
 *
 * This macro returns the function pointer (a ctx_handler_t)
 * corresponding to the assigned handler function for the given
 * context.
 *
 * @param id The context ID number.
 * @return   The name of the context.
 *
 * @see @link DOXGRP_CONF_CTX Context Handling @endlink
 * @ingroup DOXGRP_CONF_CTX
 */
#define ctx_id_to_func(id)         (context[(id)].handler)

/*@{*/
/**
 * @name Internal Context State Stack Manipulation Macros
 * Facilitate use of the context state stack.
 *
 * These macros provide a function-style interface to the CSS.
 *
 * @bug All this goop will be replaced with a spif object class.
 * @ingroup DOXGRP_CONF_CTX
 */

/**
 * Pushes a context onto the stack.  Pushes a context onto the stack.
 *
 * @param ctx The context ID for the new context.
 */
#define ctx_push(ctx)              spifconf_register_context_state(ctx)
/**
 * Pops a context structure off the stack.  Pops a context structure
 * off the stack.
 */
#define ctx_pop()                  (ctx_state_idx--)
/**
 * Returns the context structure atop the stack.  Returns the context
 * structure atop the stack.
 *
 * @return The current context.
 */
#define ctx_peek()                 (ctx_state[ctx_state_idx])
/**
 * Returns the context ID from the context structure atop the stack.
 * Returns the context ID from the context structure atop the stack.
 *
 * @return The current context ID.
 */
#define ctx_peek_id()              (ctx_state[ctx_state_idx].ctx_id)
/**
 * Returns the context state from the context structure atop the
 * stack.  Returns the context state from the context structure atop
 * the stack.
 *
 * @return The current context state.
 */
#define ctx_peek_state()           (ctx_state[ctx_state_idx].state)
/**
 * Returns the context ID from the context structure one level below
 * the top of the stack.  Returns the context ID from the context
 * structure one level below the top of the stack.
 *
 * @return The previous context ID.
 */
#define ctx_peek_last_id()         (ctx_state[(ctx_state_idx?ctx_state_idx-1:0)].ctx_id)
/**
 * Returns the context state from the context structure one level
 * below the top of the stack.  Returns the context state from the
 * context structure one level below the top of the stack.
 *
 * @return The previous context state.
 */
#define ctx_peek_last_state()      (ctx_state[(ctx_state_idx?ctx_state_idx-1:0)].state)
/**
 * Sets the current context state.  Sets the current context state.
 *
 * @param q The new state for the current context.
 */
#define ctx_poke_state(q)          ((ctx_state[ctx_state_idx].state) = (q))
/**
 * Gets the current depth of the context stack.  Gets the current
 * depth of the context stack.
 *
 * @return The current context stack depth.
 */
#define ctx_get_depth()            (ctx_state_idx)
/**
 * Convenience macro for beginning a new context.
 *
 * This macro simplifies the beginning of a new context.  The name
 * read from the config file is turned into a context ID which is then
 * registered with the parser.  The context handler for the new
 * context is called with CONF_BEGIN_STRING.  The returned state is
 * saved in the context structure atop the stack.
 *
 * @param idx The word number of the context name.
 */
#define ctx_begin(idx)             do { \
                                     spif_charptr_t name; \
                                     name = spiftool_get_word(idx, buff); \
                                     ctx_name_to_id(id, name, i); \
                                     ctx_push(id); \
                                     state = (*ctx_id_to_func(id))(SPIF_CAST(charptr) SPIFCONF_BEGIN_STRING, \
                                                                   ctx_peek_last_state()); \
                                     ctx_poke_state(state); \
                                     FREE(name); \
                                   } while (0)
/**
 * Convenience macro for ending a context.
 *
 * This macro simplifies the ending of a context.  The context handler
 * for the context is called with SPIFCONF_END_STRING.  The old context is
 * then popped off the stack, and the returned state is saved for the
 * parent context.
 *
 */
#define ctx_end()                  do { \
                                     if (ctx_get_depth()) { \
                                       state = (*ctx_id_to_func(id))(SPIF_CAST(charptr) SPIFCONF_END_STRING, \
                                                                     ctx_peek_state()); \
                                       ctx_poke_state(NULL); \
                                       ctx_pop(); \
                                       id = ctx_peek_id(); \
                                       ctx_poke_state(state); \
                                       file_poke_skip(0); \
                                     } \
                                   } while (0)
/*@}*/

/**
 * Context structure.
 *
 * This structure is used to hold context names and their respective
 * handlers (#ctx_handler_t).
 *
 * @bug This needs to be turned into a spif object class.
 * @see @link DOXGRP_CONF_CTX Context Handling @endlink
 * @ingroup DOXGRP_CONF_CTX
 */
typedef struct ctx_t_struct {
    /**
     * Context name.
     *
     * The string representation of the context name.  The word
     * immediately after the keyword @c begin is compared with this
     * value to find the handler for the requested context.  This
     * comparison is case-insensitive.
     */
    spif_charptr_t name;
    /**
     * Context handler.
     *
     * Pointer to the function which will handle this context.
     * Context handlers must accept two parameters, a spif_charptr_t 
     * containing either the config file line or a begin/end magic
     * string, and a void * containing state information; they must
     * return a void * which will be passed to the next invocation of
     * the handler as the aforementioned state information parameter.
     */
    ctx_handler_t handler;
} ctx_t;

/**
 * Context state structure.
 *
 * This structure is used as part of the context stack to track the
 * current context and its state information.
 *
 * @bug This needs to be turned into a spif object class.
 * @see @link DOXGRP_CONF_CTX Context Handling @endlink
 * @ingroup DOXGRP_CONF_CTX
 */
typedef struct ctx_state_t_struct {
    /**
     * Context ID.
     *
     * The ID number of the context.
     */
    unsigned char ctx_id;
    /**
     * Context state.
     *
     * The state for the context.  This holds the state variable in
     * between calls to the handler (ctx_t_struct#handler).
     */
    void *state;
} ctx_state_t;

/**
 * Built-in config file function.
 *
 * This structure holds the name and a pointer to the handler for
 * built-in config file functions (%get(), %random(), etc.).
 *
 * @bug This needs to be turned into a spif object class.
 * @see @link DOXGRP_CONF_CTX Context Handling @endlink
 * @ingroup DOXGRP_CONF_CTX
 */
typedef struct spifconf_func_t_struct {
    /**
     * Function name.
     *
     * The string representation of the built-in function name, not
     * including the leading percent sign ('%').
     */
    spif_charptr_t name;
    /**
     * Function handler pointer.
     *
     * Pointer to the handler for the built-in function.
     */
    spifconf_func_ptr_t ptr;
} spifconf_func_t;

/**
 * Linked list for user-defined config file variables.
 *
 * This structure holds the name and value for user-defined config
 * file variables set/retrieved using the %get() and %put() built-in
 * functions.
 *
 * @bug This needs to be turned into a spif object class.
 * @see @link DOXGRP_CONF_CTX Context Handling @endlink, builtin_get(), builtin_put()
 * @ingroup DOXGRP_CONF_CTX
 */
typedef struct spifconf_var_t_struct {
    /**
     * Variable name.
     *
     * The string representation of the variable name.  Variable names
     * ARE case-sensitive!
     */
    spif_charptr_t var;
    /**
     * Variable value.
     *
     * The value of the user-defined variable.  The value must be a
     * text string (obviously, since the config files are text-based.
     */
    spif_charptr_t value;
    /**
     * Linked list pointer.
     *
     * Pointer to the next variable in the list.
     */
    struct spifconf_var_t_struct *next;
} spifconf_var_t;



/******************************* OPTIONS GOOP **********************************/

/**
 * Increment and check bad option counter.
 *
 * This is a convenience macro which is invoked each time an option
 * parsing error is encountered.  This macro increments the bad option
 * count within the parser and checks to see if the count has now
 * exceeded the threshold.  If so, the registered help handler
 * (spifopt_settings_t_struct#help_handler) via the
 * #SPIFOPT_HELPHANDLER() macro.  If not, an error message is printed
 * noting that behavior may be abnormal but that parsing will
 * continue.
 *
 * @see @link DOXGRP_OPT Command Line Option Parser @endlink
 * @ingroup DOXGRP_OPT
 */
#define CHECK_BAD()  do { \
                       SPIFOPT_BADOPTS_SET(SPIFOPT_BADOPTS_GET() + 1); \
                       if (SPIFOPT_BADOPTS_GET() > SPIFOPT_ALLOWBAD_GET()) { \
                         libast_print_error("Error threshold exceeded, giving up.\n"); \
                         SPIFOPT_HELPHANDLER(); \
                       } else { \
                         libast_print_error("Attempting to continue, but strange things may happen.\n"); \
                       } \
                     } while(0)


#endif /* _LIBAST_INTERNAL_H_ */