Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

pdl_main.c

Go to the documentation of this file.
00001 /*
00002  *   Copyright (c) 2003 EU DataGrid        http://www.eu-datagrid.org/
00003  *
00004  *   $Id: pdl_main.c,v 1.31 2003/09/11 11:20:28 venekamp Exp $
00005  *
00006  *   Copyright (c) 2003 by
00007  *      G.M. Venekamp <venekamp@nikhef.nl>
00008  *      NIKHEF Amsterdam, the Netherlands
00009  *
00010  *   This software is distributed under a BSD-style open source
00011  *   licence. For a complete description of the licence take a look
00012  *   at: http://eu-datagrid.web.cern.ch/eu-datagrid/license.html
00013  *
00014  */
00015 
00016 
00034 #include <stdarg.h>
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038 
00039 #include "lcmaps_log.h"
00040 #include "pdl.h"
00041 #include "pdl_variable.h"
00042 #include "pdl_policy.h"
00043 #include "pdl_rule.h"
00044 
00045 static const char* script_name  = NULL;           
00046 static const char* d_path       = "/usr/lib";     
00047 static const char* path         = 0;              
00048 static int path_lineno          = 0;              
00049 static plugin_t* top_plugin     = NULL;           
00050 static BOOL default_path        = TRUE;           
00051 static BOOL parse_error         = FALSE;          
00052 static char* level_str[PDL_SAME];                 
00053 
00054 unsigned int lineno = 1;   
00055 
00056 void _set_path(const record_t* _path);
00057 record_t* _concat_strings(const record_t* s1, const record_t* s2, const char* extra);
00058 void reduce_policies(void);
00059 void init_name_args(plugin_t** plugin, const rule_t* rule, rule_type_t type);
00060 BOOL plugin_exists(const char* string);
00061 int find_first_space(const char* string);
00062 
00063 
00073 int pdl_init(const char* name)
00074 {
00075   if (name) {
00076     FILE* file;
00077 
00078     script_name = strdup(name);
00079 
00080     file = fopen(name, "r");
00081     if (file)
00082       yyin = file;
00083     else {
00084       warning(PDL_ERROR, "Could not open file '%s'.", name);
00085       return -1;
00086     }
00087   }
00088 
00089   /*  Set the default path  */
00090   path = d_path;
00091   default_path = TRUE;
00092 
00093   /*
00094    *  Check if there are plugins, if so clear top_plugin and free
00095    *  all allocated memory.
00096    */
00097   while (top_plugin) {
00098     free(top_plugin->name);
00099     free(top_plugin->args);
00100     top_plugin = top_plugin->next;
00101   }
00102 
00103   /*  Init the levels with the appropriate print text.  */
00104   level_str[PDL_INFO]    = "info";
00105   level_str[PDL_WARNING] = "warning";
00106   level_str[PDL_ERROR]   = "error";
00107   level_str[PDL_UNKNOWN] = "<unknown>";
00108 
00109   parse_error = FALSE;
00110 
00111   return 0;
00112 }
00113 
00114 
00121 int yyparse_errors(void)
00122 {
00123   return parse_error ? -1 : 0;
00124 }
00125 
00126 
00133 const plugin_t* get_plugins(void)
00134 {
00135   plugin_t* plugin;
00136   policy_t* policy;
00137 
00138   /*
00139    *  Check if the policies have been reduced. If not, then getting
00140    *  the plugins and their arguments is useless; the variables have
00141    *  not been substituted yet.
00142    */
00143   if (!policies_have_been_reduced()) {
00144     lcmaps_log(1, "The policies have not been reduced. Probably the startElevaluationManager has failed or has not been called yet.\n");
00145     return 0;
00146   }
00147 
00148   /*
00149    *  Check if evaluation has been done before, if so use the old
00150    *  results.
00151    */
00152   if (top_plugin)
00153     return top_plugin;
00154 
00155   policy = get_policies();
00156 
00157   while (policy) {
00158     rule_t* rule = policy->rule;
00159 
00160     lcmaps_log_debug(1, "processing policy: %s\n", policy->name);
00161     while (rule) {
00162       lcmaps_log_debug(1, "  processing rule: %s -> %s | %s\n", rule->state, rule->true_branch, rule->false_branch);
00163 
00164       lcmaps_log_debug(1, "  get_plugins:  initializing...\n");
00165       init_name_args(&plugin, rule, STATE);
00166       init_name_args(&plugin, rule, TRUE_BRANCH);
00167       init_name_args(&plugin, rule, FALSE_BRANCH);
00168       lcmaps_log_debug(1, "  get_plugins:  initializing done.\n");
00169 
00170       rule = rule->next;
00171     }
00172     policy = policy->next;
00173   }
00174   
00175   return top_plugin;
00176 }
00177 
00178 
00186 BOOL plugin_exists(const char* string)
00187 {
00188   int space, remainder;
00189   plugin_t *plugin;
00190 
00191   space     = find_first_space(string);
00192   remainder = strlen(string) - space - 1;
00193   plugin    = top_plugin;
00194 
00195   while (plugin) {
00196     if (plugin->name && strncmp(plugin->name, string, space)==0) {
00197       if (plugin->args)
00198         if (strncmp(plugin->args, string+space+1, remainder)!=0) {
00199           plugin = plugin->next;
00200           continue;
00201         }
00202       return TRUE;
00203     }
00204     plugin = plugin->next;
00205   }
00206   
00207   return FALSE;
00208 }
00209 
00210 
00214 void init_name_args(plugin_t** plugin, const rule_t* rule, rule_type_t type)
00215 {
00216   int space, remainder;
00217   const char* string;
00218 
00219   switch (type) {
00220   case STATE:
00221     string = rule->state;
00222     break;
00223   case TRUE_BRANCH:
00224     string = rule->true_branch;
00225     break;
00226   case FALSE_BRANCH:
00227     string = rule->false_branch;
00228     break;
00229   default:
00230     warning(PDL_ERROR, "init_name_args: unknown type!");
00231     return;
00232   }
00233 
00234   lcmaps_log_debug(1, "  init_name_args: processing: %s\n", string);
00235 
00236   if (!string || plugin_exists(string)) {
00237     lcmaps_log_debug(1, "  init_name_args: Either the plugin exists or string == 0.\n");
00238     return;
00239   }
00240 
00241   lcmaps_log_debug(1, "  init_name_args: plugin does not exists.\n");
00242 
00243   if (!top_plugin) {
00244     top_plugin = (plugin_t*)malloc(sizeof(plugin_t));
00245     *plugin = top_plugin;
00246   }
00247   else {
00248     (*plugin)->next = (plugin_t*)malloc(sizeof(plugin_t));
00249     *plugin = (*plugin)->next;
00250   }
00251 
00252   (*plugin)->name = (*plugin)->args = 0;
00253   (*plugin)->next = 0;
00254 
00255   space = find_first_space(string);
00256 
00257   lcmaps_log_debug(1, "  init_name_args: space found a pos: %d  strlen = %d.\n", space, strlen(string));
00258 
00259   (*plugin)->name = (char *)malloc(space+1);
00260   strncpy((*plugin)->name, string, space);
00261   *((*plugin)->name+space) = '\0';
00262   
00263   remainder = strlen(string)-space-1;
00264   if (remainder > 0) {
00265     (*plugin)->args   = (char *)malloc(remainder+1);
00266     strncpy((*plugin)->args, string+space+1, remainder);
00267     *((*plugin)->args+remainder) = '\0';
00268   } else
00269     (*plugin)->args = 0;
00270 
00271   (*plugin)->lineno = rule->lineno;
00272   (*plugin)->next   = 0;
00273 
00274   lcmaps_log_debug(1, "  init_name_args: plugin->name = %s\n", (*plugin)->name);
00275   lcmaps_log_debug(1, "  init_name_args: plugin->args = %s\n", (*plugin)->args);
00276 }
00277 
00278 
00288 int find_first_space(const char* string)
00289 {
00290   int space, max_length;
00291   space = 0;
00292   max_length = strlen(string);
00293 
00294   for (; *string++ != ' ' && space < max_length; ++space);
00295 
00296   return space;
00297 }
00298 
00299 
00305 const char *pdl_path(void)
00306 {
00307   return path;
00308 };
00309 
00310 
00318 int yyerror(const char* s)
00319 {
00320   //  lcmaps_log_debug(1, "%s\n", token_name());
00321 
00322   warning(PDL_ERROR, s);
00323 
00324   return 0;
00325 }
00326 
00327 
00335 void set_path(record_t* path)
00336 {
00337   _set_path(path);
00338 
00339   free(path->string);
00340   free(path);
00341 }
00342 
00343 
00352 void _set_path(const record_t* _path)
00353 {
00354   //  lcmaps_log_debug(1, "set_path: '%s'.\n", _path);
00355 
00356   if (!default_path) {
00357     warning(PDL_ERROR, "path already defined in: %d; ignoring this instance.", path_lineno);
00358     return;
00359   }
00360 
00361   default_path = FALSE;
00362   path_lineno  = _path->lineno;
00363   path         = strdup(_path->string);
00364 }
00365 
00366 
00367 
00371 void free_path(void)
00372 {
00373   if (!default_path && path) {
00374     free((char*)path);
00375     default_path = TRUE;
00376     path = 0;
00377   }
00378 }
00379 
00380 
00381 
00392 record_t* concat_strings(record_t* s1, record_t* s2)
00393 {
00394   record_t* r = _concat_strings(s1, s2, 0);
00395 
00396   free(s1->string);
00397   free(s2->string);
00398   free(s1);
00399   free(s2);
00400 
00401   return r;
00402 }
00403 
00404 
00413 record_t* _concat_strings(const record_t* s1, const record_t* s2,
00414                           const char* extra)
00415 {
00416   int len       = strlen(s1->string);
00417   int len_extra = extra ? strlen(extra) : 0;
00418 
00419   record_t* record = (record_t *)malloc(sizeof(record_t));
00420 
00421   if (!(record->string = (char *)malloc(len + len_extra + strlen(s2->string)+1))) {
00422     warning(PDL_ERROR, "out of memory");
00423     return 0;
00424   }
00425 
00426   strcpy(record->string, s1->string);
00427   if (extra)
00428     strcpy(record->string+len, extra);
00429   strcpy(record->string+len+len_extra, s2->string);
00430 
00431   //lcmaps_log_debug(1, "concat_strings: '%s' + '%s' = '%s'.\n", s1, s2, s3);
00432 
00433   return record;
00434 }
00435 
00436 
00447 record_t* concat_strings_with_space(record_t* s1, record_t* s2)
00448 {
00449   record_t* r;
00450 
00451   /*  Check if there is a string to add.  */
00452   if (strlen(s2->string)!=0) {
00453     /*
00454      *  When the first and second string end with ", do not an extra
00455      *  space. This is the result of an sequence of escaped ".
00456      */
00457     if ((s1->string[strlen(s1->string)-1]=='"') &&
00458         (s2->string[strlen(s2->string)-1]=='"'))
00459       r = _concat_strings(s1, s2, 0);
00460     else
00461       r = _concat_strings(s1, s2, " ");
00462 
00463     free(s1->string);
00464     free(s2->string);
00465     free(s1);
00466     free(s2);
00467   } else {
00468     /*
00469      *  Since there is nothing to concatenate, we simply copy the
00470      *  first string (s1) to the result.
00471      */
00472     r = (record_t*)malloc(sizeof(r));
00473     memcpy(r, s1, sizeof(r));
00474   }
00475 
00476   return r;
00477 }
00478 
00479 
00497 const char* pdl_next_plugin(plugin_status_t status)
00498 {
00499   const static policy_t* current_policy = 0;
00500   const static rule_t*   current_rule   = 0;
00501   char* string      = 0;
00502   const char* state = 0;
00503 
00504   switch (status) {
00505   case EVALUATION_START:
00506     /*  Make sure that there is a policy list.  */
00507     if (!(current_policy = get_policies()))
00508       return 0;
00509     if (!(current_rule = current_policy->rule))
00510       return 0;
00511 
00512     state = current_rule->state;
00513     break;
00514 
00515   case EVALUATION_SUCCESS:
00516     if (current_rule)
00517       state = current_rule->true_branch;
00518 
00519     if (current_policy && state)
00520       current_rule = find_state(current_policy->rule, state);
00521     else
00522       current_rule = 0;
00523     break;
00524 
00525   case EVALUATION_FAILURE:
00526     /*
00527      *  Find the next rule for evalaution. The plugins specified by
00528      *  that rule will not be returned by this iterating of the
00529      *  function. Instead the static variables are setup, such that on
00530      *  the next iteration the next plugin is returned. Only after the
00531      *  evaluation of the plugin found during this iteration can a
00532      *  decision be made which plugin to return.
00533      *
00534      *  When the last rule has been evaluated, there is the
00535      *  possibility that there is another policy in the configration.
00536      *  Instead of stopping at the end of a rule chain, setup the
00537      *  variables for the next policy rule.
00538      *
00539      */
00540     if (current_rule)
00541       state = current_rule->false_branch;
00542 
00543     /* 
00544      *  Check if either there is a current_rule or a state. If so, we
00545      *  can continue. If there is no current rule, there might be a
00546      *  next policy. This needs to be evaluated next. If there is no
00547      *  state, this is because the false branch does not exist and
00548      *  hence we need to evaluate possible next policies.
00549      *
00550      */
00551     if (!(current_rule && state)) {
00552       if (current_policy && (current_policy = current_policy->next)) {
00553         if ((current_rule = current_policy->rule))
00554           state = current_rule->state;
00555       }
00556     } else {
00557        /*  We have a valid next state. Let's find  the next rule.  */
00558       if (current_policy)
00559         current_rule = find_state(current_policy->rule, state);
00560     }
00561 
00562     break;
00563   }
00564 
00565   /*
00566    *  Create the full plugin name, i.e. including the path. The rules
00567    *  do not specify the path, this must be added so that a single
00568    *  string can be returned. State holde the current plugin name.
00569    *
00570    */
00571   if (state) {
00572     const char* tmp;
00573     int state_length, path_length;
00574 
00575     tmp = state;
00576     state_length = path_length = 0;
00577 
00578     while (*tmp!=' ' && *tmp++!='\0') {
00579       ++state_length;
00580     }
00581     path_length = strlen(pdl_path());
00582 
00583     /*  Allocate memory and initialize the string.  */
00584     string = (char*)malloc(state_length + path_length + 2);
00585     strcpy(string, pdl_path());
00586 
00587     /*  Make sure the path ends in '/'.  */
00588     if (string[path_length-1] != '/')
00589       string[path_length++] = '/';
00590     strncpy(string + path_length, state, state_length);
00591     string[path_length + state_length] = '\0';
00592   }
00593 
00594   return string;
00595 }
00596 
00597 
00602 void free_resources(void)
00603 {
00604   if (script_name) {
00605     free((char*)script_name);
00606     script_name = 0;
00607   }
00608 
00609   free_path();
00610 
00611   free_variables();
00612   free_policies();
00613 
00614   /*
00615    *  YACC takes its input from the stdin by default. When the input
00616    *  is taken from a file, the yyin variable will have a different
00617    *  value from stdin and stderr. If so, it is necessary to close it.
00618    */
00619   if (yyin!=stdin && yyin!=stderr) {
00620     fclose(yyin);
00621     yyin=stdin;
00622   }
00623 
00624 #ifdef HAVE_FLEX
00625   delete_lex_buffer();
00626 #endif
00627 }
00628 
00629 
00638 void warning(pdl_error_t error, const char* s, ...)
00639 {
00640   static char* level = 0;
00641   char buf[2048];
00642   int res;
00643 
00644   va_list args;
00645 
00646   if (error == PDL_ERROR)
00647     parse_error = TRUE;
00648 
00649   if (!level)
00650     level = level_str[PDL_UNKNOWN];
00651 
00652   if (error != PDL_SAME)
00653     level = level_str[error];
00654 
00655   /*
00656    *  Prepend a standard text before the message. This makes reading
00657    *  the errors/warnings a little easier.
00658    */
00659   res = sprintf(buf, "%s:%d: [%s] ", script_name, lineno, level);
00660 
00661   /*  Print (format) the actual message.  */
00662   va_start(args, s);
00663   res += vsnprintf(buf+res, sizeof(buf)-res-2, s, args);
00664   va_end(args);
00665 
00666   /*
00667    *  The string needs to end in a new line and of course strings are
00668    *  termintated by the end of string character. Make sure it happens
00669    *  and respect the buffer size!
00670    */
00671   buf[res<sizeof(buf)-1 ? res++ : sizeof(buf)-2] = '\n';
00672   buf[res<sizeof(buf)   ? res   : sizeof(buf)-1] = '\0';
00673 
00674   lcmaps_log(0, buf);
00675 }
00676 

Generated at Tue Sep 23 15:48:09 2003 for edg-lcmaps by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001