1 /*
2  * Copyright (C) 1997-2004, Michael Jennings
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 /**
25  * @file libast_internal.h
26  * LibAST header file for internal-use-only stuff.
27  *
28  * This file contains all macros, structure definitions, etc. which
29  * are restricted to internal LibAST use only.
30  *
31  * @author Michael Jennings <mej@eterm.org>
32  * @version $Revision: 1.21 $
33  * @date $Date: 2004/07/21 22:17:49 $
34  */
35 
36 #ifndef _LIBAST_INTERNAL_H_
37 #define _LIBAST_INTERNAL_H_
38 
39 /* This GNU goop has to go before the system headers */
40 #ifdef __GNUC__
41 # ifndef __USE_GNU
42 #  define __USE_GNU
43 # endif
44 # ifndef _GNU_SOURCE
45 #  define _GNU_SOURCE
46 # endif
47 # ifndef _BSD_SOURCE
48 #  define _BSD_SOURCE
49 # endif
50 #endif
51 
52 #include "config.h"
53 #include "libast.h"
54 
55 #ifdef HAVE_STDARG_H
56 # include <stdarg.h>
57 #endif
58 
59 /******************************** MSGS GOOP ***********************************/
60 extern spif_charptr_t libast_program_name, libast_program_version;
61 
62 
63 
64 /********************************* MEM GOOP ***********************************/
65 /**
66  * Filename length limit.
67  *
68  * This is used to limit the maximum length of a source filename.
69  * When tracking memory allocation, the filename and line number for
70  * each MALLOC()/REALLOC()/CALLOC()/FREE() call is recorded.  A small
71  * buffer of static length is used to speed things up.
72  *
73  * @see MALLOC(), REALLOC(), CALLOC(), FREE()
74  * @ingroup DOXGRP_MEM
75  */
76 #define LIBAST_FNAME_LEN  20
77 
78 /**
79  * Pointer tracking structure.
80  *
81  * This structure is used by LibAST's memory management system to keep
82  * track of what pointers have been allocated, where they were
83  * allocated, and how much space was requested.
84  *
85  * @see MALLOC(), REALLOC(), CALLOC(), FREE()
86  * @ingroup DOXGRP_MEM
87  */
88 typedef struct ptr_t_struct {
89     /** The allocated pointer.  The allocated pointer. */
90     void *ptr;
91     /** The pointer's size, in bytes.  The pointer's size, in bytes. */
92     size_t size;
93     /** Filename.  The file which last (re)allocated the pointer. */
94     spif_char_t file[LIBAST_FNAME_LEN + 1];
95     /** Line number.  The line number where the pointer was last (re)allocated. */
96     spif_uint32_t line;
97 } ptr_t;
98 /**
99  * Pointer list structure.
100  *
101  * This structure is used by LibAST's memory management system to hold
102  * the list of pointers being tracked.  This list is maintained as an
103  * array for simplicity.
104  *
105  * @see MALLOC(), REALLOC(), CALLOC(), FREE(), ptr_t_struct
106  * @ingroup DOXGRP_MEM
107  */
108 typedef struct memrec_t_struct {
109     /** Pointer count.  The number of pointers being tracked. */
110     size_t cnt;
111     /** Pointer list.  The list of tracked pointers. */
112     ptr_t *ptrs;
113 } memrec_t;
114 
115 
116 
117 /******************************** CONF GOOP ***********************************/
118 /**
119  * Convert context name to ID.
120  *
121  * This macro converts a context name as read from a config file into
122  * the corresponding ID number.  If the context name is not found, an
123  * error message is printed, and the ID number of 0 (the "null"
124  * context) is returned.
125  *
126  * @bug This probably should not be a macro.
127  * @bug The @a i parameter really isn't needed.
128  *
129  * @param the_id The return value -- the context ID.
130  * @param n      The name of the context.
131  * @param i      An arbitrary counter variable.
132  *
133  * @see @link DOXGRP_CONF_CTX Context Handling @endlink
134  * @ingroup DOXGRP_CONF_CTX
135  */
136 #define ctx_name_to_id(the_id, n, i) do { \
137                                        for ((i)=0; (i) <= ctx_idx; (i)++) { \
138                                          if (!strcasecmp(SPIF_CAST_C(char *) (n), \
139                                                          SPIF_CAST_C(char *) context[(i)].name)) { \
140                                            (the_id) = (i); \
141                                            break; \
142                                          } \
143                                        } \
144                                        if ((i) > ctx_idx) { \
145                                          libast_print_error("Parsing file %s, line %lu:  No such context \"%s\"\n", \
146                                                             file_peek_path(), file_peek_line(), (n)); \
147                                          (the_id) = 0; \
148                                        } \
149                                      } while (0)
150 /**
151  * Convert context ID to name.
152  *
153  * This macro converts a context ID to its name.
154  *
155  * @param id The context ID number.
156  * @return   The name of the context.
157  *
158  * @see @link DOXGRP_CONF_CTX Context Handling @endlink
159  * @ingroup DOXGRP_CONF_CTX
160  */
161 #define ctx_id_to_name(id)         (context[(id)].name)
162 /**
163  * Convert context ID to handler.
164  *
165  * This macro returns the function pointer (a ctx_handler_t)
166  * corresponding to the assigned handler function for the given
167  * context.
168  *
169  * @param id The context ID number.
170  * @return   The name of the context.
171  *
172  * @see @link DOXGRP_CONF_CTX Context Handling @endlink
173  * @ingroup DOXGRP_CONF_CTX
174  */
175 #define ctx_id_to_func(id)         (context[(id)].handler)
176 
177 /*@{*/
178 /**
179  * @name Internal Context State Stack Manipulation Macros
180  * Facilitate use of the context state stack.
181  *
182  * These macros provide a function-style interface to the CSS.
183  *
184  * @bug All this goop will be replaced with a spif object class.
185  * @ingroup DOXGRP_CONF_CTX
186  */
187 
188 /**
189  * Pushes a context onto the stack.  Pushes a context onto the stack.
190  *
191  * @param ctx The context ID for the new context.
192  */
193 #define ctx_push(ctx)              spifconf_register_context_state(ctx)
194 /**
195  * Pops a context structure off the stack.  Pops a context structure
196  * off the stack.
197  */
198 #define ctx_pop()                  (ctx_state_idx--)
199 /**
200  * Returns the context structure atop the stack.  Returns the context
201  * structure atop the stack.
202  *
203  * @return The current context.
204  */
205 #define ctx_peek()                 (ctx_state[ctx_state_idx])
206 /**
207  * Returns the context ID from the context structure atop the stack.
208  * Returns the context ID from the context structure atop the stack.
209  *
210  * @return The current context ID.
211  */
212 #define ctx_peek_id()              (ctx_state[ctx_state_idx].ctx_id)
213 /**
214  * Returns the context state from the context structure atop the
215  * stack.  Returns the context state from the context structure atop
216  * the stack.
217  *
218  * @return The current context state.
219  */
220 #define ctx_peek_state()           (ctx_state[ctx_state_idx].state)
221 /**
222  * Returns the context ID from the context structure one level below
223  * the top of the stack.  Returns the context ID from the context
224  * structure one level below the top of the stack.
225  *
226  * @return The previous context ID.
227  */
228 #define ctx_peek_last_id()         (ctx_state[(ctx_state_idx?ctx_state_idx-1:0)].ctx_id)
229 /**
230  * Returns the context state from the context structure one level
231  * below the top of the stack.  Returns the context state from the
232  * context structure one level below the top of the stack.
233  *
234  * @return The previous context state.
235  */
236 #define ctx_peek_last_state()      (ctx_state[(ctx_state_idx?ctx_state_idx-1:0)].state)
237 /**
238  * Sets the current context state.  Sets the current context state.
239  *
240  * @param q The new state for the current context.
241  */
242 #define ctx_poke_state(q)          ((ctx_state[ctx_state_idx].state) = (q))
243 /**
244  * Gets the current depth of the context stack.  Gets the current
245  * depth of the context stack.
246  *
247  * @return The current context stack depth.
248  */
249 #define ctx_get_depth()            (ctx_state_idx)
250 /**
251  * Convenience macro for beginning a new context.
252  *
253  * This macro simplifies the beginning of a new context.  The name
254  * read from the config file is turned into a context ID which is then
255  * registered with the parser.  The context handler for the new
256  * context is called with CONF_BEGIN_STRING.  The returned state is
257  * saved in the context structure atop the stack.
258  *
259  * @param idx The word number of the context name.
260  */
261 #define ctx_begin(idx)             do { \
262                                      spif_charptr_t name; \
263                                      name = spiftool_get_word(idx, buff); \
264                                      ctx_name_to_id(id, name, i); \
265                                      ctx_push(id); \
266                                      state = (*ctx_id_to_func(id))(SPIF_CAST(charptr) SPIFCONF_BEGIN_STRING, \
267                                                                    ctx_peek_last_state()); \
268                                      ctx_poke_state(state); \
269                                      FREE(name); \
270                                    } while (0)
271 /**
272  * Convenience macro for ending a context.
273  *
274  * This macro simplifies the ending of a context.  The context handler
275  * for the context is called with SPIFCONF_END_STRING.  The old context is
276  * then popped off the stack, and the returned state is saved for the
277  * parent context.
278  *
279  */
280 #define ctx_end()                  do { \
281                                      if (ctx_get_depth()) { \
282                                        state = (*ctx_id_to_func(id))(SPIF_CAST(charptr) SPIFCONF_END_STRING, \
283                                                                      ctx_peek_state()); \
284                                        ctx_poke_state(NULL); \
285                                        ctx_pop(); \
286                                        id = ctx_peek_id(); \
287                                        ctx_poke_state(state); \
288                                        file_poke_skip(0); \
289                                      } \
290                                    } while (0)
291 /*@}*/
292 
293 /**
294  * Context structure.
295  *
296  * This structure is used to hold context names and their respective
297  * handlers (#ctx_handler_t).
298  *
299  * @bug This needs to be turned into a spif object class.
300  * @see @link DOXGRP_CONF_CTX Context Handling @endlink
301  * @ingroup DOXGRP_CONF_CTX
302  */
303 typedef struct ctx_t_struct {
304     /**
305      * Context name.
306      *
307      * The string representation of the context name.  The word
308      * immediately after the keyword @c begin is compared with this
309      * value to find the handler for the requested context.  This
310      * comparison is case-insensitive.
311      */
312     spif_charptr_t name;
313     /**
314      * Context handler.
315      *
316      * Pointer to the function which will handle this context.
317      * Context handlers must accept two parameters, a spif_charptr_t
318      * containing either the config file line or a begin/end magic
319      * string, and a void * containing state information; they must
320      * return a void * which will be passed to the next invocation of
321      * the handler as the aforementioned state information parameter.
322      */
323     ctx_handler_t handler;
324 } ctx_t;
325 
326 /**
327  * Context state structure.
328  *
329  * This structure is used as part of the context stack to track the
330  * current context and its state information.
331  *
332  * @bug This needs to be turned into a spif object class.
333  * @see @link DOXGRP_CONF_CTX Context Handling @endlink
334  * @ingroup DOXGRP_CONF_CTX
335  */
336 typedef struct ctx_state_t_struct {
337     /**
338      * Context ID.
339      *
340      * The ID number of the context.
341      */
342     unsigned char ctx_id;
343     /**
344      * Context state.
345      *
346      * The state for the context.  This holds the state variable in
347      * between calls to the handler (ctx_t_struct#handler).
348      */
349     void *state;
350 } ctx_state_t;
351 
352 /**
353  * Built-in config file function.
354  *
355  * This structure holds the name and a pointer to the handler for
356  * built-in config file functions (%get(), %random(), etc.).
357  *
358  * @bug This needs to be turned into a spif object class.
359  * @see @link DOXGRP_CONF_CTX Context Handling @endlink
360  * @ingroup DOXGRP_CONF_CTX
361  */
362 typedef struct spifconf_func_t_struct {
363     /**
364      * Function name.
365      *
366      * The string representation of the built-in function name, not
367      * including the leading percent sign ('%').
368      */
369     spif_charptr_t name;
370     /**
371      * Function handler pointer.
372      *
373      * Pointer to the handler for the built-in function.
374      */
375     spifconf_func_ptr_t ptr;
376 } spifconf_func_t;
377 
378 /**
379  * Linked list for user-defined config file variables.
380  *
381  * This structure holds the name and value for user-defined config
382  * file variables set/retrieved using the %get() and %put() built-in
383  * functions.
384  *
385  * @bug This needs to be turned into a spif object class.
386  * @see @link DOXGRP_CONF_CTX Context Handling @endlink, builtin_get(), builtin_put()
387  * @ingroup DOXGRP_CONF_CTX
388  */
389 typedef struct spifconf_var_t_struct {
390     /**
391      * Variable name.
392      *
393      * The string representation of the variable name.  Variable names
394      * ARE case-sensitive!
395      */
396     spif_charptr_t var;
397     /**
398      * Variable value.
399      *
400      * The value of the user-defined variable.  The value must be a
401      * text string (obviously, since the config files are text-based.
402      */
403     spif_charptr_t value;
404     /**
405      * Linked list pointer.
406      *
407      * Pointer to the next variable in the list.
408      */
409     struct spifconf_var_t_struct *next;
410 } spifconf_var_t;
411 
412 
413 
414 /******************************* OPTIONS GOOP **********************************/
415 
416 /**
417  * Increment and check bad option counter.
418  *
419  * This is a convenience macro which is invoked each time an option
420  * parsing error is encountered.  This macro increments the bad option
421  * count within the parser and checks to see if the count has now
422  * exceeded the threshold.  If so, the registered help handler
423  * (spifopt_settings_t_struct#help_handler) via the
424  * #SPIFOPT_HELPHANDLER() macro.  If not, an error message is printed
425  * noting that behavior may be abnormal but that parsing will
426  * continue.
427  *
428  * @see @link DOXGRP_OPT Command Line Option Parser @endlink
429  * @ingroup DOXGRP_OPT
430  */
431 #define CHECK_BAD()  do { \
432                        SPIFOPT_BADOPTS_SET(SPIFOPT_BADOPTS_GET() + 1); \
433                        if (SPIFOPT_BADOPTS_GET() > SPIFOPT_ALLOWBAD_GET()) { \
434                          libast_print_error("Error threshold exceeded, giving up.\n"); \
435                          SPIFOPT_HELPHANDLER(); \
436                        } else { \
437                          libast_print_error("Attempting to continue, but strange things may happen.\n"); \
438                        } \
439                      } while(0)
440 
441 
442 #endif /* _LIBAST_INTERNAL_H_ */
443