Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Related Pages

hook.c

00001 /* 00002 * Copyright (C) 1997-2004 The CDG Team <cdg@nats.informatik.uni-hamburg.de> 00003 * 00004 * This file is free software; as a special exception the author gives 00005 * unlimited permission to copy and/or distribute it, with or without 00006 * modifications, as long as this notice is preserved. 00007 * 00008 * This program is distributed in the hope that it will be useful, but 00009 * WITHOUT ANY WARRANTY, to the extent permitted by law; without even the 00010 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00011 * 00012 * Author: Michael Schulz (see also AUTHORS and THANKS) 00013 * Birth: 12 Juli 1998 00014 * 00015 * $Id: hook.c,v 1.38 2004/09/27 17:07:04 micha Exp $ 00016 */ 00017 00018 /* ------------------------------------------------------------------------- 00019 * @addtogroup HookCore HookCore - C Part in the core system 00020 * @ingroup Hook 00021 * @{ 00022 * 00023 * The Hook module connects the core of the library to its outside world by a callback 00024 * mechanism. 00025 * Hook functions are to be supplied by the application programmer and will 00026 * be called at strategic points in the application. For instance, a 00027 * commonly used hook is \ref HOOK_PRINTF, that handles the output channels (see below). 00028 * 00029 * So hooking the \ref HOOK_PRINTF callback allows you to redefine and redirect the channels. 00030 * The following callbacks are defined: 00031 * - \ref HOOK_CNBUILDNODES 00032 * - \ref HOOK_EVAL 00033 * - \ref HOOK_NSSEARCH 00034 * - \ref HOOK_PRINTF 00035 * - \ref HOOK_FLUSH 00036 * - \ref HOOK_GLSINTERACTION 00037 * - \ref HOOK_GETS 00038 * - \ref HOOK_PROGRESS 00039 * - \ref HOOK_PARTIALRESULT 00040 * - \ref HOOK_ICINTERACTION 00041 * - \ref HOOK_RESET 00042 * 00043 * As a part of that the output channels are handled here. The following output 00044 * channels exist: 00045 * - \ref CDG_HINT 00046 * - \ref CDG_INFO 00047 * - \ref CDG_WARNING 00048 * - \ref CDG_PROLOG 00049 * - \ref CDG_EVAL 00050 * - \ref CDG_SEARCHRESULT 00051 * - \ref CDG_PROFILE 00052 * - \ref CDG_HOOK 00053 * - \ref CDG_ERROR 00054 * - \ref CDG_DEBUG 00055 * - \ref CDG_DEFAULT 00056 * - \ref CDG_PROGRESS 00057 * - \ref CDG_XML 00058 * 00059 * Note, that the term \e hook and \e callback are used mostly as synonyms. 00060 * (Actually the term hook should be replaced by callback for clarity.) 00061 * 00062 * As oposed to other modules some of the functions in this 00063 * module are not prefixed by \c hk as the \ref CodingStyle dictates. The reason 00064 * for that lies in the relative importance of this module and some of its 00065 * functions to the overall system, i.e. cdgPrintf(). 00066 */ 00067 00068 /* -- INCLUDES ---------------------------------------------------------- */ 00069 #include <config.h> 00070 00071 #include <stdio.h> 00072 #include <string.h> 00073 #include <stdarg.h> 00074 #include <blah.h> 00075 #include "cdg.h" 00076 #include "hook.h" 00077 #include "gls.h" 00078 #include "set.h" 00079 #include "write.h" 00080 00081 /* -- VARIABLES --------------------------------------------------------- */ 00082 00083 /* ------------------------------------------------------------------------- 00084 * This Vector holds all defined hooks. It is initialized by the function 00085 * hkInitialize(). After that, the symbolic constants can be used 00086 * to execute any of the hooks. 00087 */ 00088 Vector hkHooks = NULL; 00089 00090 /* ------------------------------------------------------------------------- 00091 * bitwise encoding of active output channels. 00092 * 00093 * This variable controls the currently active output channels. 00094 * All output is performed by the function cdgPrintf(), whose first argument 00095 * is a bitwise encoding denoting the output channels (e.g. \ref CDG_INFO, \ref CDG_ERROR, 00096 * or \ref CDG_DEBUG output) to which a message is to be routed. 00097 * 00098 * All messages tagged with a bit that is not set in \c hkVerbosity 00099 * are suppressed. 00100 */ 00101 unsigned long int hkVerbosity = CDG_DEFAULT | CDG_ERROR | CDG_INFO | CDG_WARNING | CDG_SEARCHRESULT; 00102 00103 /* -- FUNCTIONS --------------------------------------------------------- */ 00104 00105 /* ---------------------------------------------------------------------- 00106 * validate access to variables in this module. 00107 * 00108 * This function is installed using setRegister() in the hkInitialize() 00109 * function of this module. 00110 * It is monitoring the access to the variable \c xml being 00111 * registered in hkInitialize(). 00112 */ 00113 Boolean hkValidate(String name, String value, Boolean *var) 00114 { 00115 if (!var) { 00116 return FALSE; 00117 } 00118 00119 if (strcmp(name, "xml") == 0) { 00120 if ((strcmp(value, "on") == 0 && *var == TRUE) || 00121 (strcmp(value, "off") == 0 && *var == FALSE)) { 00122 return TRUE; 00123 } 00124 } 00125 00126 return FALSE; 00127 } 00128 00129 /* ---------------------------------------------------------------------- 00130 * monitor access to variables in this module. 00131 * 00132 * This function is installed using setRegister() in the hkInitialize() 00133 * function of this module. When a variable is changed hkCallback() is 00134 * called handling appropriate sideeffects depending on the new variable 00135 * value. Right now only the variable \c xml is handled here. 00136 * 00137 * Switching on \c xml writes an appropriate xml header to the CDG_XML 00138 * channel. Switching off \c xml finishes all open xml tags. 00139 * See the write module for more information on the xml output channel. 00140 */ 00141 void hkCallback(String name, Boolean *var) 00142 { 00143 if (strcmp(name, "xml") == 0) { 00144 if (*var) { 00145 writeXmlHeader(); 00146 } else { 00147 writeXmlEndAll(); 00148 } 00149 } 00150 } 00151 00152 /* ---------------------------------------------------------------------- 00153 * initialization of the hook module. 00154 * This function must be called before the \c CDG library is functional. 00155 */ 00156 void hkInitialize(void) 00157 { 00158 Hook hook; 00159 00160 hkHooks = vectorNew(20); 00161 00162 hook = (HookStruct *)memMalloc(sizeof(HookStruct)); 00163 hook->count = 0; 00164 hook->name = "printf"; 00165 hook->active = TRUE; 00166 hook->function = (HookFunction *)vprintf; 00167 00168 hook->no = HOOK_PRINTF; 00169 hook->cmd = NULL; 00170 vectorSetElement(hkHooks, hook, hook->no); 00171 00172 hook = (HookStruct *)memMalloc(sizeof(HookStruct)); 00173 hook->count = 0; 00174 hook->name = "flush"; 00175 hook->active = TRUE; 00176 hook->function = NULL; 00177 hook->no = HOOK_FLUSH; 00178 hook->cmd = NULL; 00179 vectorSetElement(hkHooks, hook, hook->no); 00180 00181 hook = (HookStruct *)memMalloc(sizeof(HookStruct)); 00182 hook->count = 0; 00183 hook->name = "buildnodes"; 00184 hook->active = FALSE; 00185 hook->function = NULL; 00186 hook->no = HOOK_CNBUILDNODES; 00187 hook->cmd = NULL; 00188 vectorSetElement(hkHooks, hook, hook->no); 00189 00190 hook = (HookStruct *)memMalloc(sizeof(HookStruct)); 00191 hook->count = 0; 00192 hook->name = "eval"; 00193 hook->active = FALSE; 00194 hook->function = NULL; 00195 hook->no = HOOK_EVAL; 00196 hook->cmd = NULL; 00197 vectorSetElement(hkHooks, hook, hook->no); 00198 00199 hook = (HookStruct *)memMalloc(sizeof(HookStruct)); 00200 hook->count = 0; 00201 hook->name = "netsearch"; 00202 hook->active = FALSE; 00203 hook->function = NULL; 00204 hook->no = HOOK_NSSEARCH; 00205 hook->cmd = NULL; 00206 vectorSetElement(hkHooks, hook, hook->no); 00207 00208 hook = (HookStruct *)memMalloc(sizeof(HookStruct)); 00209 hook->count = 0; 00210 hook->name = "reset"; 00211 hook->active = TRUE; 00212 hook->function = NULL; 00213 hook->no = HOOK_RESET; 00214 hook->cmd = NULL; 00215 vectorSetElement(hkHooks, hook, hook->no); 00216 00217 hook = (HookStruct *)memMalloc(sizeof(HookStruct)); 00218 hook->count = 0; 00219 hook->name = "glsInteraction"; 00220 hook->active = TRUE; 00221 hook->function = glsInteraction; 00222 hook->no = HOOK_GLSINTERACTION; 00223 hook->cmd = NULL; 00224 vectorSetElement(hkHooks, hook, hook->no); 00225 00226 hook = (HookStruct *)memMalloc(sizeof(HookStruct)); 00227 hook->count = 0; 00228 hook->name = "gets"; 00229 hook->active = TRUE; 00230 hook->function = NULL; 00231 hook->no = HOOK_GETS; 00232 hook->cmd = NULL; 00233 vectorSetElement(hkHooks, hook, hook->no); 00234 00235 hook = (HookStruct *)memMalloc(sizeof(HookStruct)); 00236 hook->count = 0; 00237 hook->name = "progress"; 00238 hook->active = TRUE; 00239 hook->function = NULL; 00240 hook->no = HOOK_PROGRESS; 00241 hook->cmd = NULL; 00242 vectorSetElement(hkHooks, hook, hook->no); 00243 00244 hook = (HookStruct *)memMalloc(sizeof(HookStruct)); 00245 hook->count = 0; 00246 hook->name = "partialresult"; 00247 hook->active = TRUE; 00248 hook->function = NULL; 00249 hook->no = HOOK_PARTIALRESULT; 00250 hook->cmd = NULL; 00251 vectorSetElement(hkHooks, hook, hook->no); 00252 00253 hook = (HookStruct *)memMalloc(sizeof(HookStruct)); 00254 hook->count = 0; 00255 hook->name = "IC interaction"; 00256 hook->active = TRUE; 00257 hook->function = NULL; 00258 hook->no = HOOK_ICINTERACTION; 00259 hook->cmd = NULL; 00260 vectorSetElement(hkHooks, hook, hook->no); 00261 00262 setRegister("verbosity", SET_UNSLONG, &hkVerbosity, NULL, NULL, NULL, 00263 "on", CDG_DEFAULT | CDG_ERROR | CDG_HINT | CDG_INFO | CDG_WARNING | CDG_SEARCHRESULT, 00264 "off", CDG_WARNING, 00265 NULL); 00266 setRegister("hint", SET_BIT, &hkVerbosity, NULL, NULL, NULL, CDG_HINT, NULL); 00267 setRegister("info", SET_BIT, &hkVerbosity, NULL, NULL, NULL, CDG_INFO, NULL); 00268 setRegister("debug", SET_BIT, &hkVerbosity, NULL, NULL, NULL, CDG_DEBUG, NULL); 00269 setRegister("error", SET_BIT, &hkVerbosity, NULL, NULL, NULL, CDG_ERROR, NULL); 00270 setRegister("warning", SET_BIT, &hkVerbosity, NULL, NULL, NULL, CDG_WARNING, NULL); 00271 setRegister("prolog", SET_BIT, &hkVerbosity, NULL, NULL, NULL, CDG_PROLOG, NULL); 00272 setRegister("searchresult", SET_BIT, &hkVerbosity, NULL, NULL, NULL, CDG_SEARCHRESULT, NULL); 00273 setRegister("eval", SET_BIT, &hkVerbosity, NULL, NULL, NULL, CDG_EVAL, NULL); 00274 setRegister("profile", SET_BIT, &hkVerbosity, NULL, NULL, NULL, CDG_PROFILE, NULL); 00275 setRegister("progress", SET_BIT, &hkVerbosity, NULL, NULL, NULL, CDG_PROGRESS, NULL); 00276 setRegister("xml", SET_BIT, &hkVerbosity, NULL, hkValidate, hkCallback, CDG_XML, NULL); 00277 00278 } 00279 00280 /* ---------------------------------------------------------------------- 00281 * finalization of this module. 00282 * After this call the \c CDG library is nearly shut down. That's why 00283 * this finalizer is to be called at last after calling the finalizer of 00284 * all other modules. 00285 */ 00286 void hkFinalize(void) 00287 { 00288 int i; 00289 for (i=0; i<vectorSize(hkHooks); i++) { 00290 memFree(vectorElement(hkHooks, i)); 00291 } 00292 vectorDelete(hkHooks); 00293 } 00294 00295 /* ---------------------------------------------------------------------- 00296 * execute a defined callback. 00297 * This is the standard way to call a hook. 00298 * If the corresponding HookStruct::active is set, its HookStruct::count is 00299 * increased and its HookStruct::function is called handing over a pointer 00300 * to the HookStruct we are executing and the entire va_list passed to this function. 00301 * For example, \c cdgExecHook(HOOK_PARTIALRESULT, parse) is executing 00302 * \c HookStruct::function(hook, parse). 00303 * \param hookNo the identifier of the hook to be called, 00304 * e.g. HOOK_PROGRESS 00305 */ 00306 void cdgExecHook(int hookNo, ...) 00307 { 00308 #define DEBUG_CDGEXECHOOK 0 00309 va_list ap; 00310 Hook hook; 00311 00312 if (hookNo >= vectorSize(hkHooks)) { 00313 cdgPrintf(CDG_ERROR, "ERROR: unknown hook `%d' called\n", hookNo); 00314 return; 00315 } 00316 00317 hook = (Hook) vectorElement(hkHooks, hookNo); 00318 #if DEBUG_CDGEXECHOOK 00319 printf("DEBUG: hook = %p\n", hook); 00320 printf(" name = %s\n", hook->name); 00321 printf(" active = %d\n", hook->active); 00322 printf(" count = %ld\n", hook->count); 00323 printf(" function = %p\n", hook->function); 00324 #endif 00325 if(hook->active) { 00326 hook->count++; 00327 if(hook->function) { 00328 va_start(ap, hookNo); 00329 (hook->function)(hook, ap); 00330 va_end(ap); 00331 } else { 00332 /* printf("ERROR: hook function of `%s' not set\n", hook->name);*/ 00333 } 00334 } 00335 #if DEBUG_CDGEXECHOOK 00336 printf("DEBUG: done hook\n"); 00337 #endif 00338 } 00339 00340 00341 /* ---------------------------------------------------------------------- 00342 * get the numerical identifier of a named hook. 00343 * \param name the name of a known hook 00344 * \returns the numerical identifier on success or -1 of no hook of that 00345 * name exists. 00346 */ 00347 int hkFindNoOfHook(String name) 00348 { 00349 int index; 00350 Hook hook; 00351 Boolean found; 00352 00353 for(index=0, found=FALSE; 00354 index < vectorSize(hkHooks) && !found; 00355 index++) { 00356 00357 hook = (Hook)vectorElement(hkHooks, index); 00358 found = (strcmp(hook->name, name) == 0); 00359 } 00360 00361 return (found?index-1:-1); 00362 } 00363 00364 /* ---------------------------------------------------------------------- 00365 * default get string callback. 00366 * This function gets one newline-terminated chunk of console input from 00367 * the user. Up to \c size characters are transferred into 00368 * \c buffer. For this purpose, \ref HOOK_GETS is executed. It this 00369 * hook has no associated function, \c fgets() is called instead with 00370 * an additional argument of \c stdin. This provides a transparent 00371 * way of reading input from a user. (Note that the normal interaction 00372 * with the shell of the cdgp parser uses a different and non-transparent 00373 * input routine.) 00374 */ 00375 void cdgGetString(String buffer, int size) { 00376 00377 Hook hook; 00378 00379 hook = vectorElement(hkHooks, HOOK_GETS); 00380 hook->count++; 00381 if(hook->function) { 00382 (hook->function)(hook, buffer, size); 00383 } 00384 else { 00385 fgets(buffer, size, stdin); 00386 } 00387 } 00388 00389 /* ---------------------------------------------------------------------- 00390 * output channel router. 00391 * This function takes care of routing messages to appropriate output 00392 * channels. 00393 * The first argument \c mode defines bitwise the channels this message 00394 * is to be routed to. The rest of the arguments is passed to the 00395 * \ref HOOK_PRINTF in printf mannor (so see the manual pages for printf). 00396 * We use \ref HOOK_PROGRESS exclusive here when the 00397 * \ref hkVerbosity contains the \ref CDG_PROGRESS flag and only 00398 * \ref HOOK_PRINTF otherwise. If we are producing xml output 00399 * and the \ref CDG_WARNING or \ref CDG_ERROR channel is used, then 00400 * the message doubled according to the cdg-logfile.dtd by 00401 * writeXmlVaNotification(). 00402 */ 00403 void cdgPrintf(int mode, String format, ...) 00404 { 00405 va_list ap; 00406 Hook hook; 00407 00408 if (hkVerbosity & mode) { 00409 va_start(ap, format); 00410 00411 /* special handling of progress messages */ 00412 if (mode & CDG_PROGRESS) { 00413 hook = vectorElement(hkHooks, HOOK_PROGRESS); 00414 hook->count++; 00415 00416 /* check wether the progress hook is filled */ 00417 if (hook->function != NULL) { 00418 (hook->function)(hook, format, ap); 00419 } 00420 00421 /* ... else fall back to normal cdgPrintf'ing */ 00422 else { 00423 hook = vectorElement(hkHooks, HOOK_PRINTF); 00424 (hook->function) (format, ap); 00425 } 00426 00427 /* flush the progress output of the cdg system */ 00428 cdgFlush(); 00429 00430 } else { 00431 /* some verbosity generates XML messages */ 00432 if (mode & CDG_WARNING) { 00433 writeXmlVaNotification("warning", format, ap); 00434 } else if (mode & CDG_ERROR) { 00435 writeXmlVaNotification("error", format, ap); 00436 } 00437 00438 hook = vectorElement(hkHooks, HOOK_PRINTF); 00439 hook->count++; 00440 (hook->function) (format, ap); 00441 } 00442 00443 va_end(ap); 00444 } 00445 } 00446 00447 /* ---------------------------------------------------------------------- 00448 * default flush callback. 00449 * This is the default callback for \ref HOOK_FLUSH. If no hook is 00450 * installed, i.e. HookStruct::function is \ref NULL, then \c fflush 00451 * is called. In addition writeXmlFlush() is called to sync the 00452 * \ref CDG_XML output channel. 00453 */ 00454 void cdgFlush(void) 00455 { 00456 Hook hook; 00457 00458 hook = vectorElement(hkHooks, HOOK_FLUSH); 00459 hook->count++; 00460 if(hook->function) 00461 (hook->function)(); 00462 else { 00463 fflush(stdout); 00464 } 00465 00466 writeXmlFlush(); 00467 } 00468 00469 /* ---------------------------------------------------------------------- */ 00470 /* -- ENDOFFILE --------------------------------------------------------- */ 00471 /** @} */ 00472

CDG 0.95 (20 Oct 2004)