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