00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00038 #include "fastlib/fx/fx.h"
00039 
00040 
00041 #include "fastlib/base/debug.h"
00042 
00043 #include <stdarg.h>
00044 #include <unistd.h>
00045 #include <sys/resource.h>
00046 #include <sys/time.h>
00047 #include <sys/utsname.h>
00048 #include <pthread.h>
00049 
00050 
00051 
00052 
00053 
00054 
00055 fx_module *fx_root = NULL;
00056 int fx_docs_nagging = 1;
00057 
00058 
00059 
00060 char fx_mod_marker[] = "UMPQVPDRT";
00061 
00062 const char *fx_mod_name[] = {
00063   "unknown",
00064   "submodule",
00065   "parameter",
00066   "required parameter",
00067   "reserved parameter",
00068   "provided parameter",
00069   "default parameter",
00070   "result",
00071   "timer"
00072 };
00073 
00074 const char *fx_val_name[] = {
00075   "string",
00076   "double",
00077   "int",
00078   "bool",
00079   "string list",
00080   "double list",
00081   "int list",
00082   "bool list"
00083 };
00084 
00085 
00086 
00087 
00088 
00089 
00090 
00091 
00092 
00093 #define FX__BUF_SIZE (3 * (sizeof(long long) > 8 ? sizeof(long long) : 8))
00094 
00095 
00096 
00097 const fx_entry_doc fx__fx_entries[] = {
00098   {"load", FX_PARAM, FX_STR_LIST, NULL,
00099    "  Load files containing additional input parameters.\n"},
00100   {"output", FX_PARAM, FX_STR, NULL,
00101    "  Output results to this file.\n"},
00102   {"timing", FX_PARAM, FX_BOOL, NULL,
00103    "  Whether to attempt speed up for a timing run.\n"},
00104   {"rusage", FX_PARAM, FX_BOOL, NULL,
00105    "  Whether to emit rusage data in \"info\".\n"},
00106   {"silent", FX_PARAM, FX_BOOL, NULL,
00107    "  Whether to skip the printing of results to screen.\n"},
00108   {"no_output_types", FX_PARAM, FX_BOOL, NULL,
00109    "  Whether to skip the printing of entry types (e.g. \"/param:P\").\n"},
00110   {"no_docs_nagging", FX_PARAM, FX_BOOL, NULL,
00111    "  Whether to suppress messages about missing documentation.\n"},
00112   FX_ENTRY_DOC_DONE
00113 };
00114 
00115 const fx_module_doc fx__fx_doc = {
00116   fx__fx_entries, NULL,
00117   "Options for the FASTexec experiment-running system.\n"
00118 };
00119 
00120 const fx_entry_doc fx__debug_entries[] = {
00121   {"verbosity_level", FX_PARAM, FX_DOUBLE, NULL,
00122    "  Controls the amount of debug info to print.\n"},
00123   {"print_got_heres", FX_PARAM, FX_BOOL, NULL,
00124    "  Whether to print \"got here\" notices.\n"},
00125   {"print_warnings", FX_PARAM, FX_BOOL, NULL,
00126    "  Whether to print warning messages.\n"},
00127   {"abort_on_nonfatal", FX_PARAM, FX_BOOL, NULL,
00128    "  Whether to treat nonfatal errors as fatal.\n"},
00129   {"pause_on_nonfatal", FX_PARAM, FX_BOOL, NULL,
00130    "  Whether to wait for user feedback on nonfatal errors.\n"},
00131   {"print_notify_locs", FX_PARAM, FX_BOOL, NULL,
00132    "  Whether to print \"file:function:line:\" before notifications.\n"},
00133   FX_ENTRY_DOC_DONE
00134 };
00135 
00136 const fx_module_doc fx__debug_doc = {
00137   fx__debug_entries, NULL,
00138   "Options for FASTlib's debugging features.\n"
00139 };
00140 
00141 const fx_entry_doc fx__rusage_entries[] = {
00142   {"utime/sec", FX_RESULT, FX_INT, NULL,
00143    "  Seconds of computation in user-time.\n"},
00144   {"utime/usec", FX_RESULT, FX_INT, NULL,
00145    "  Additional microseconds spent in user-time.\n"},
00146   {"stime/sec", FX_RESULT, FX_INT, NULL,
00147    "  Seconds of computation in system-time.\n"},
00148   {"stime/usec", FX_RESULT, FX_INT, NULL,
00149    "  Additional microseconds spent in system-time.\n"},
00150   {"minflt", FX_RESULT, FX_INT, NULL,
00151    "  (See getrusage documentation.)\n"},
00152   {"majflt", FX_RESULT, FX_INT, NULL,
00153    "  (See getrusage documentation.)\n"},
00154   {"maxrss", FX_RESULT, FX_INT, NULL,
00155    "  (See getrusage documentation.)\n"},
00156   {"ixrss", FX_RESULT, FX_INT, NULL,
00157    "  (See getrusage documentation.)\n"},
00158   {"idrss", FX_RESULT, FX_INT, NULL,
00159    "  (See getrusage documentation.)\n"},
00160   {"isrss", FX_RESULT, FX_INT, NULL,
00161    "  (See getrusage documentation.)\n"},
00162   {"nswap", FX_RESULT, FX_INT, NULL,
00163    "  (See getrusage documentation.)\n"},
00164   {"inblock", FX_RESULT, FX_INT, NULL,
00165    "  (See getrusage documentation.)\n"},
00166   {"oublock", FX_RESULT, FX_INT, NULL,
00167    "  (See getrusage documentation.)\n"},
00168   {"msgsnd", FX_RESULT, FX_INT, NULL,
00169    "  (See getrusage documentation.)\n"},
00170   {"msgrcv", FX_RESULT, FX_INT, NULL,
00171    "  (See getrusage documentation.)\n"},
00172   {"nsignals", FX_RESULT, FX_INT, NULL,
00173    "  (See getrusage documentation.)\n"},
00174   {"nvcsw", FX_RESULT, FX_INT, NULL,
00175    "  (See getrusage documentation.)\n"},
00176   {"nivcsw", FX_RESULT, FX_INT, NULL,
00177    "  (See getrusage documentation.)\n"},
00178   FX_ENTRY_DOC_DONE
00179 };
00180 
00181 const fx_module_doc fx__rusage_doc = {
00182   fx__rusage_entries, NULL,
00183   "Resource usage information generated by getrusage.\n"
00184 };
00185 
00186 const fx_submodule_doc fx__info_submods[] = {
00187   {"rusage/self", &fx__rusage_doc,
00188    "  Resources consumed by the experiment's main thread.\n"},
00189   {"rusage/children", &fx__rusage_doc,
00190    "  Resources consumed by all child threads.\n"},
00191   FX_SUBMODULE_DOC_DONE
00192 };
00193 
00194 const fx_entry_doc fx__info_entries[] = {
00195   {"sys/node/name", FX_RESULT, FX_STR, NULL,
00196    "  The host computer of the experiment.\n"},
00197   {"sys/arch/name", FX_RESULT, FX_STR, NULL,
00198    "  The host computer's architecture, i.e. 64-bit x86.\n"},
00199   {"sys/kernel/name", FX_RESULT, FX_STR, NULL,
00200    "  The name of operating system.\n"},
00201   {"sys/kernel/release", FX_RESULT, FX_STR, NULL,
00202    "  The version of the operating system.\n"},
00203   {"sys/kernel/build", FX_RESULT, FX_STR, NULL,
00204    "  Further OS version details.\n"},
00205   FX_ENTRY_DOC_DONE
00206 };
00207 
00208 const fx_module_doc fx__info_doc = {
00209   fx__info_entries, fx__info_submods,
00210   "Extraneous system details pertaining to an experiment.\n"
00211 };
00212 
00213 const fx_submodule_doc fx__std_submods[] = {
00214   {"fx", &fx__fx_doc,
00215    "  Options for the FASTexec experiment-running system.\n"},
00216   {"debug", &fx__debug_doc,
00217    "  Options for FASTlib's debugging feautres.\n"},
00218   {"info", &fx__info_doc,
00219    "  Extraneous system details pertaining to an experiment.\n"},
00220   FX_SUBMODULE_DOC_DONE
00221 };
00222 
00223 const fx_entry_doc fx__std_entries[] = {
00224   {"help", FX_PARAM, FX_STR, NULL,
00225    "  Prints this information.  Permits --help=path/to/submod.\n"},
00226   {"total_time", FX_TIMER, FX_CUSTOM, NULL,
00227    "  The measured running time of the program.\n"},
00228   FX_ENTRY_DOC_DONE
00229 };
00230 
00231 const fx_module_doc fx__std_doc = {
00232   fx__std_entries, fx__std_submods,
00233   "Standard FASTlib options:\n"
00234 };
00235 
00236 
00237 
00238 const fx_entry_doc fx__timer_entries[] = {
00239   {"cycles", FX_TIMER, FX_INT, NULL, "text"},
00240   {"real", FX_TIMER, FX_DOUBLE, NULL, "text"},
00241   {"user", FX_TIMER, FX_DOUBLE, NULL, "text"},
00242   {"sys", FX_TIMER, FX_DOUBLE, NULL, "text"},
00243   FX_ENTRY_DOC_DONE
00244 };
00245 
00246 const fx_module_doc fx__timer_doc = {
00247   fx__timer_entries, NULL, "text"
00248 };
00249 
00250 
00251 
00252 static void fx__write_path(fx_module *entry, FILE *stream)
00253 {
00254   if (entry->parent) {
00255     fx__write_path(entry->parent, stream);
00256     putc('/', stream);
00257   }
00258   fprintf(stream, "%s", entry->key);
00259 }
00260 
00261 COMPILER_NO_RETURN
00262 static void fx__print_fatal_msg(const char *file, const char *func, int line,
00263                                 const char *prefix, fx_module *entry,
00264                                 const char *suffix, ...)
00265 {
00266   va_list vl;
00267 
00268   fl_print_msg_header(fl_msg_marker[FL_MSG_FATAL],
00269                       fl_msg_color[FL_MSG_FATAL]);
00270   fl_print_msg_loc(file, func, line);
00271 
00272   va_start(vl, suffix);
00273   vfprintf(stderr, prefix, vl);
00274   fx__write_path(entry, stderr);
00275   vfprintf(stderr, suffix, vl);
00276   va_end(vl);
00277 
00278   fprintf(stderr, "\n");
00279 
00280   fl_abort();
00281 }
00282 
00283 static void fx__print_msg(const char *file, const char *func, int line,
00284                           fl_msg_t msg_type, const char *prefix,
00285                           fx_module *entry, const char *suffix, ...)
00286 {
00287   va_list vl;
00288 
00289   fl_print_msg_header(fl_msg_marker[msg_type], fl_msg_color[msg_type]);
00290   if (msg_type < FL_MSG_NOTIFY_STAR || print_notify_locs) {
00291     fl_print_msg_loc(file, func, line);
00292   }
00293 
00294   va_start(vl, suffix);
00295   vfprintf(stderr, prefix, vl);
00296   fx__write_path(entry, stderr);
00297   vfprintf(stderr, suffix, vl);
00298   va_end(vl);
00299 
00300   fprintf(stderr, "\n");
00301 
00302   if (msg_type < FL_MSG_NOTIFY_STAR) {
00303     if (msg_type == FL_MSG_FATAL || abort_on_nonfatal) {
00304       fl_abort();
00305     } else if (pause_on_nonfatal) {
00306       fl_pause();
00307     }
00308   }
00309 }
00310 
00311 #define FX__FATAL(prefix, entry, msg_params...) \
00312     fx__print_fatal_msg(__FILE__, __FUNCTION__, __LINE__, \
00313         prefix, entry, msg_params)
00314 
00315 #define FX__NONFATAL(prefix, entry, msg_params...) \
00316     fx__print_msg(__FILE__, __FUNCTION__, __LINE__, \
00317         FL_MSG_NONFATAL, prefix, entry, msg_params)
00318 
00319 #define FX__SEMIFATAL(success, prefix, entry, msg_params...) \
00320     if (!success) { \
00321       FX__FATAL(prefix, entry, msg_params); \
00322     } else if (!FAILED(*success)) { \
00323       *success = SUCCESS_FAIL; \
00324       FX__NONFATAL(prefix, entry, msg_params); \
00325     } else NOP
00326 
00327 
00328 
00329 int fx_module_is_type(fx_module *entry, fx_mod_t mod_type)
00330 {
00331   if (mod_type >= FX_RESERVED) { 
00332     return entry->mod_type == mod_type;
00333   } else if (mod_type >= FX_PARAM) { 
00334     return entry->mod_type >= mod_type && entry->mod_type < FX_TIMER;
00335   } else { 
00336     return entry->mod_type >= mod_type;
00337   }
00338 }
00339 
00340 static success_t fx__check_mod_type(const char *header, fx_mod_t mod_type,
00341                                     fx_module *entry)
00342 {
00343   if (unlikely(!fx_module_is_type(entry, mod_type))) {
00344     if (entry->mod_type < FX_PARAM) {
00345       if (fx_docs_nagging) {
00346         FX__NONFATAL("%s %s \"", entry, "\" is not documented.",
00347             header, fx_mod_name[mod_type]);
00348       }
00349       return SUCCESS_WARN;
00350     } else {
00351       FX__NONFATAL("%s %s \"", entry, "\" is documented as a %s.",
00352           header, fx_mod_name[mod_type], fx_mod_name[entry->mod_type]);
00353       return SUCCESS_FAIL;
00354     }
00355   }
00356   return SUCCESS_PASS;
00357 }
00358 
00359 static success_t fx__check_val_type(const char *header, fx_val_t val_type,
00360                                     fx_module *entry)
00361 {
00362   if (unlikely(entry->val_type != val_type)) {
00363     if (entry->val_type < 0) {
00364       FX__NONFATAL("%s %s \"", entry, "\" is of custom type.",
00365           header, fx_val_name[val_type]);
00366       return SUCCESS_FAIL;
00367     } else {
00368       FX__NONFATAL("%s %s \"", entry, "\" is of type %s.",
00369           header, fx_val_name[val_type], fx_val_name[entry->val_type]);
00370       return SUCCESS_WARN;
00371     }
00372   }
00373   return SUCCESS_PASS;
00374 }
00375 
00376 
00377 
00378 static double fx__scan_double_impl(fx_module *entry, const char *val,
00379                                    success_t *success_ptr, int list)
00380 {
00381   double retval = 0.0;
00382 
00383   if (unlikely(sscanf(val, "%lf", &retval) != 1)) {
00384     FX__SEMIFATAL(success_ptr,
00385         "%c%s \"", entry, "\" is not a double%s: \"%s\".",
00386         toupper(*fx_mod_name[entry->mod_type]),
00387         fx_mod_name[entry->mod_type] + 1,
00388         list ? " list" : "", entry->val);
00389   }
00390 
00391   return retval;
00392 }
00393 
00394 static long long fx__scan_int_impl(fx_module *entry, const char *val,
00395                                    success_t *success_ptr, int list)
00396 {
00397   long long retval = 0;
00398 
00399   if (sscanf(val, "%lld", &retval) != 1) {
00400     FX__SEMIFATAL(success_ptr,
00401         "%c%s \"", entry, "\" is not an int%s: \"%s\".",
00402         toupper(*fx_mod_name[entry->mod_type]),
00403         fx_mod_name[entry->mod_type] + 1,
00404         list ? " list" : "", entry->val);
00405   }
00406 
00407   return retval;
00408 }
00409 
00410 static int fx__scan_bool_impl(fx_module *entry, const char *val,
00411                               success_t *success_ptr, int list)
00412 {
00413   int retval = 0;
00414 
00415   if (strchr("1tTyY", val[0])) {
00416     retval = 1;
00417   } else if (!strchr("0fFnN", val[0])) {
00418     FX__SEMIFATAL(success_ptr,
00419         "%c%s \"", entry, "\" is not a bool%s: \"%s\".",
00420         toupper(*fx_mod_name[entry->mod_type]),
00421         fx_mod_name[entry->mod_type] + 1,
00422         list ? " list" : "", entry->val);
00423   }
00424 
00425   return retval;
00426 }
00427 
00428 
00429 
00430 static double fx__scan_double(fx_module *entry)
00431 {
00432   return fx__scan_double_impl(entry, entry->val, NULL, 0);
00433 }
00434 
00435 static long long fx__scan_int(fx_module *entry)
00436 {
00437   return fx__scan_int_impl(entry, entry->val, NULL, 0);
00438 }
00439 
00440 static int fx__scan_bool(fx_module *entry)
00441 {
00442   return fx__scan_bool_impl(entry, entry->val, NULL, 0);
00443 }
00444 
00445 
00446 
00447 static size_t fx__list_size(fx_module *entry, size_t req_size,
00448                             success_t *success_ptr)
00449 {
00450   char *val = entry->val;
00451   size_t count = 1;
00452 
00453   while ((val = strchr(val, ','))) {
00454     ++count;
00455     ++val;
00456   }
00457 
00458   if (req_size && count != req_size) {
00459     FX__SEMIFATAL(success_ptr,
00460         "%c%s \"", entry, "\" is not of length %d: \"%s\".",
00461         toupper(*fx_mod_name[entry->mod_type]),
00462         fx_mod_name[entry->mod_type] + 1,
00463         req_size, entry->val);
00464   }
00465 
00466   return count;
00467 }
00468 
00469 static const char **fx__scan_str_list(fx_module *mod, size_t *size_ptr,
00470                                       success_t *success_ptr)
00471 {
00472   char **retval;
00473   char **elem;
00474   char *str;
00475 
00476   size_t len = strlen(mod->val);
00477   size_t count = fx__list_size(mod, *size_ptr, success_ptr);
00478 
00479   
00480   mod->val = realloc(mod->val,
00481       stride_align(2 * len + 2, char *) + count * sizeof(char *));
00482 
00483   retval = (char **)(mod->val + stride_align(2 * len + 2, char *));
00484   *size_ptr = count;
00485 
00486   
00487   str = mod->val + len;
00488   strcpy(str + 1, mod->val);
00489 
00490   
00491   elem = retval;
00492   do {
00493     *str++ = '\0';
00494     *elem++ = str;
00495   } while ((str = strchr(str, ',')));
00496 
00497   
00498   while (elem-- > retval) {
00499     unhex_in_place(*elem);
00500   }
00501 
00502   return (const char **)retval;
00503 }
00504 
00505 static double *fx__scan_double_list(fx_module *mod, size_t *size_ptr,
00506                                     success_t *success_ptr)
00507 {
00508   double *retval;
00509   double *elem;
00510   const char *str;
00511 
00512   size_t len = strlen(mod->val);
00513   size_t count = fx__list_size(mod, *size_ptr, success_ptr);
00514 
00515   
00516   mod->val = realloc(mod->val,
00517       stride_align(len + 1, double) + count * sizeof(double));
00518 
00519   retval = (double *)(mod->val + stride_align(len + 1, double));
00520   *size_ptr = count;
00521 
00522   
00523   str = mod->val - 1;
00524 
00525   
00526   elem = retval;
00527   do {
00528     *elem++ = fx__scan_double_impl(mod, ++str, success_ptr, 1);
00529   } while ((str = strchr(str, ',')));
00530 
00531   return retval;
00532 }
00533 
00534 static long long *fx__scan_int_list(fx_module *mod, size_t *size_ptr,
00535                                     success_t *success_ptr)
00536 {
00537   long long *retval;
00538   long long *elem;
00539   const char *str;
00540 
00541   size_t len = strlen(mod->val);
00542   size_t count = fx__list_size(mod, *size_ptr, success_ptr);
00543 
00544   
00545   mod->val = realloc(mod->val,
00546       stride_align(len + 1, long long) + count * sizeof(long long));
00547 
00548   retval = (long long *)(mod->val + stride_align(len + 1, long long));
00549   *size_ptr = count;
00550 
00551   
00552   str = mod->val - 1;
00553 
00554   
00555   elem = retval;
00556   do {
00557     *elem++ = fx__scan_int_impl(mod, ++str, success_ptr, 1);
00558   } while ((str = strchr(str, ',')));
00559 
00560   return retval;
00561 }
00562 
00563 static int *fx__scan_bool_list(fx_module *mod, size_t *size_ptr,
00564                                success_t *success_ptr)
00565 {
00566   int *retval;
00567   int *elem;
00568   const char *str;
00569 
00570   size_t len = strlen(mod->val);
00571   size_t count = fx__list_size(mod, *size_ptr, success_ptr);
00572 
00573   
00574   mod->val = realloc(mod->val,
00575       stride_align(len + 1, int) + count * sizeof(int));
00576 
00577   retval = (int *)(mod->val + stride_align(len + 1, int));
00578   *size_ptr = count;
00579 
00580   
00581   str = mod->val - 1;
00582 
00583   
00584   elem = retval;
00585   do {
00586     *elem++ = fx__scan_bool_impl(mod, ++str, success_ptr, 1);
00587   } while ((str = strchr(str, ',')));
00588 
00589   return retval;
00590 }
00591 
00592 
00593 
00594 static char *fx__alloc_double(double val)
00595 {
00596   char *retval = malloc(FX__BUF_SIZE * sizeof(char));
00597 
00598   sprintf(retval, "%.16g", val);
00599 
00600   return retval;
00601 }
00602 
00603 static char *fx__alloc_int(long long val)
00604 {
00605   char *retval = malloc(FX__BUF_SIZE * sizeof(char));
00606 
00607   sprintf(retval, "%lld", val);
00608 
00609   return retval;
00610 }
00611 
00612 static char *fx__alloc_bool(int val)
00613 {
00614   return strdup(val ? "t" : "f");
00615 }
00616 
00617 
00618 
00619 static char *fx__alloc_str_list(size_t size, va_list vl)
00620 {
00621   if (size == 0) {
00622     return strdup("");
00623   } else {
00624     va_list vl_temp;
00625     char *retval;
00626     char *str;
00627     size_t len;
00628     size_t i;
00629 
00630     va_copy(vl_temp, vl);
00631     len = 0;
00632     for (i = 0; i < size; ++i) {
00633       len += strlen(va_arg(vl_temp, const char *));
00634     }
00635     va_end(vl_temp);
00636 
00637     retval = malloc((3 * len + size) * sizeof(char));
00638 
00639     str = hex_to_string(retval, va_arg(vl, const char *), "_.-+");
00640     while (--size) {
00641       *str++ = ',';
00642       str = hex_to_string(str, va_arg(vl, const char *), "_.-+");
00643     }
00644 
00645     return retval;
00646   }
00647 }
00648 
00649 static char *fx__alloc_double_list(size_t size, va_list vl)
00650 {
00651   if (size == 0) {
00652     return strdup("");
00653   } else {
00654     char *retval = malloc(size * FX__BUF_SIZE * sizeof(char));
00655     char *str = retval;
00656 
00657     str += sprintf(str, "%.16g", va_arg(vl, double));
00658     while (--size) {
00659       str += sprintf(str, ",%.16g", va_arg(vl, double));
00660     }
00661 
00662     return retval;
00663   }
00664 }
00665 
00666 static char *fx__alloc_int_list(size_t size, va_list vl)
00667 {
00668   if (size == 0) {
00669     return strdup("");
00670   } else {
00671     char *retval = malloc(size * FX__BUF_SIZE * sizeof(char));
00672     char *str = retval;
00673 
00674     str += sprintf(str, "%lld", va_arg(vl, long long));
00675     while (--size) {
00676       str += sprintf(str, ",%lld", va_arg(vl, long long));
00677     }
00678 
00679     return retval;
00680   }
00681 }
00682 
00683 static char *fx__alloc_bool_list(size_t size, va_list vl)
00684 {
00685   if (size == 0) {
00686     return strdup("");
00687   } else {
00688     char *retval = malloc(size * 2 * sizeof(char));
00689     char *str = retval;
00690 
00691     *str++ = va_arg(vl, int) ? 't' : 'f';
00692     while (--size) {
00693       *str++ = ',';
00694       *str++ = va_arg(vl, int) ? 't' : 'f';
00695     }
00696     *str = '\0';
00697 
00698     return retval;
00699   }
00700 }
00701 
00702 
00703 
00704 static char *fx__alloc_str_array(size_t size, const char *const *list)
00705 {
00706   if (size == 0) {
00707     return strdup("");
00708   } else {
00709     char *retval;
00710     char *str;
00711     size_t len;
00712     size_t i;
00713 
00714     len = 0;
00715     for (i = 0; i < size; ++i) {
00716       len += strlen(list[i]);
00717     }
00718 
00719     retval = malloc((3 * len + size) * sizeof(char));
00720 
00721     str = hex_to_string(retval, *list++, "_.-+");
00722     while (--size) {
00723       *str++ = ',';
00724       str = hex_to_string(str, *list++, "_.-+");
00725     }
00726 
00727     return retval;
00728   }
00729 }
00730 
00731 static char *fx__alloc_double_array(size_t size, const double *list)
00732 {
00733   if (size == 0) {
00734     return strdup("");
00735   } else {
00736     char *retval = malloc(size * FX__BUF_SIZE * sizeof(char));
00737     char *str = retval;
00738 
00739     str += sprintf(str, "%.16g", *list++);
00740     while (--size) {
00741       str += sprintf(str, ",%.16g", *list++);
00742     }
00743 
00744     return retval;
00745   }
00746 }
00747 
00748 static char *fx__alloc_int_array(size_t size, const long long *list)
00749 {
00750   if (size == 0) {
00751     return strdup("");
00752   } else {
00753     char *retval = malloc(size * FX__BUF_SIZE * sizeof(char));
00754     char *str = retval;
00755 
00756     str += sprintf(str, "%lld", *list++);
00757     while (--size) {
00758       str += sprintf(str, ",%lld", *list++);
00759     }
00760 
00761     return retval;
00762   }
00763 }
00764 
00765 static char *fx__alloc_bool_array(size_t size, const int *list)
00766 {
00767   if (size == 0) {
00768     return strdup("");
00769   } else {
00770     char *retval = malloc(size * 2 * sizeof(char));
00771     char *str = retval;
00772 
00773     *str++ = *list++ ? 't' : 'f';
00774     while (--size) {
00775       *str++ = ',';
00776       *str++ = *list++ ? 't' : 'f';
00777     }
00778     *str = '\0';
00779 
00780     return retval;
00781   }
00782 }
00783 
00784 
00785 
00786 static char *fx__alloc_format(const char *format, va_list vl)
00787 {
00788   va_list vl_temp;
00789   char *retval;
00790   size_t len;
00791 
00792   va_copy(vl_temp, vl);
00793   len = vsnprintf(NULL, 0, format, vl_temp);
00794   va_end(vl_temp);
00795 
00796   retval = malloc((len + 1) * sizeof(char));
00797   vsprintf(retval, format, vl);
00798 
00799   return retval;
00800 }
00801 
00802 static char *fx__alloc_format_list(size_t size, va_list vl)
00803 {
00804   if (size == 0) {
00805     return strdup("");
00806   } else {
00807     va_list vl_temp;
00808     char *retval;
00809     char *str;
00810     char *temp;
00811     size_t len;
00812     size_t i;
00813 
00814     va_copy(vl_temp, vl);
00815     len = 0;
00816     for (i = 0; i < size; ++i) {
00817       len += vsnprintf(NULL, 0, va_arg(vl_temp, const char *), vl_temp);
00818     }
00819     va_end(vl_temp);
00820 
00821     retval = malloc((4 * len + size + 1) * sizeof(char));
00822     temp = retval + 3 * len + size;
00823 
00824     vsprintf(temp, va_arg(vl, const char *), vl);
00825     str = hex_to_string(retval, temp, "_.-+");
00826     while (--size) {
00827       *str++ = ',';
00828       vsprintf(temp, va_arg(vl, const char *), vl);
00829       str = hex_to_string(retval, temp, "_.-+");
00830     }
00831 
00832     return retval;
00833   }
00834 }
00835 
00836 
00837 
00838 static fx_module *fx__lookup(fx_module *mod, const char *key)
00839 {
00840   return datanode_lookup(mod ? mod : fx_root, key, 1);
00841 }
00842 
00843 static void fx__check_lookup(fx_mod_t mod_type, fx_val_t val_type,
00844                              fx_module *entry)
00845 {
00846   if (PASSED(fx__check_mod_type("Requested", mod_type, entry))) {
00847     fx__check_val_type("Requested", val_type, entry);
00848   }
00849 }
00850 
00851 static fx_module *fx__get_entry(fx_module *mod, const char *key,
00852                                 fx_mod_t mod_type, fx_val_t val_type)
00853 {
00854   fx_module *retval = fx__lookup(mod, key);
00855   DEBUG_ONLY(fx__check_lookup(mod_type, val_type, retval));
00856   return retval;
00857 }
00858 
00859 
00860 
00861 static fx_module *fx__param(fx_module *mod, const char *key,
00862                             fx_val_t val_type)
00863 {
00864   fx_module *retval = fx__get_entry(mod, key, FX_PARAM, val_type);
00865 
00866   if (retval->mod_type == FX_PARAM) {
00867     if (retval->val) {
00868       retval->mod_type = FX_PROVIDED;
00869     } else {
00870       retval->mod_type = FX_DEFAULT;
00871     }
00872   }
00873 
00874   return retval;
00875 }
00876 
00877 static fx_module *fx__param_req(fx_module *mod, const char *key,
00878                                 fx_val_t val_type)
00879 {
00880   fx_module *retval = fx__get_entry(mod, key, FX_REQUIRED, val_type);
00881 
00882   if (!retval->val) {
00883     FX__FATAL("Required parameter \"", retval, "\" is unspecified.");
00884   }
00885 
00886   return retval;
00887 }
00888 
00889 
00890 
00891 const char *fx_param_str_req(fx_module *mod, const char *key)
00892 {
00893   return fx__param_req(mod, key, FX_STR)->val;
00894 }
00895 
00896 double fx_param_double_req(fx_module *mod, const char *key)
00897 {
00898   return fx__scan_double(fx__param_req(mod, key, FX_DOUBLE));
00899 }
00900 
00901 long long fx_param_int_req(fx_module *mod, const char *key)
00902 {
00903   return fx__scan_int(fx__param_req(mod, key, FX_INT));
00904 }
00905 
00906 int fx_param_bool_req(fx_module *mod, const char *key)
00907 {
00908   return fx__scan_bool(fx__param_req(mod, key, FX_BOOL));
00909 }
00910 
00911 
00912 
00913 const char **fx_param_str_list_req(fx_module *mod, const char *key,
00914                                    size_t *size_ptr)
00915 {
00916   fx_module *param = fx__param_req(mod, key, FX_STR_LIST);
00917   return fx__scan_str_list(param, size_ptr, NULL);
00918 }
00919 
00920 double *fx_param_double_list_req(fx_module *mod, const char *key,
00921                                  size_t *size_ptr)
00922 {
00923   fx_module *param = fx__param_req(mod, key, FX_DOUBLE_LIST);
00924   return fx__scan_double_list(param, size_ptr, NULL);
00925 }
00926 
00927 long long *fx_param_int_list_req(fx_module *mod, const char *key,
00928                                  size_t *size_ptr)
00929 {
00930   fx_module *param = fx__param_req(mod, key, FX_INT_LIST);
00931   return fx__scan_int_list(param, size_ptr, NULL);
00932 }
00933 
00934 int *fx_param_bool_list_req(fx_module *mod, const char *key,
00935                             size_t *size_ptr)
00936 {
00937   fx_module *param = fx__param_req(mod, key, FX_BOOL_LIST);
00938   return fx__scan_bool_list(param, size_ptr, NULL);
00939 }
00940 
00941 
00942 
00943 const char *fx_param_str(fx_module *mod, const char *key, const char *def)
00944 {
00945   fx_module *param = fx__param(mod, key, FX_STR);
00946 
00947   if (!param->val) {
00948     param->val = strdup(def);
00949   }
00950 
00951   return param->val;
00952 }
00953 
00954 double fx_param_double(fx_module *mod, const char *key, double def)
00955 {
00956   fx_module *param = fx__param(mod, key, FX_DOUBLE);
00957 
00958   if (!param->val) {
00959     param->val = fx__alloc_double(def);
00960   } else {
00961     def = fx__scan_double(param);
00962   }
00963 
00964   return def;
00965 }
00966 
00967 long long fx_param_int(fx_module *mod, const char *key, long long def)
00968 {
00969   fx_module *param = fx__param(mod, key, FX_INT);
00970 
00971   if (!param->val) {
00972     param->val = fx__alloc_int(def);
00973   } else {
00974     def = fx__scan_int(param);
00975   }
00976 
00977   return def;
00978 }
00979 
00980 int fx_param_bool(fx_module *mod, const char *key, int def)
00981 {
00982   fx_module *param = fx__param(mod, key, FX_BOOL);
00983 
00984   if (!param->val) {
00985     param->val = fx__alloc_bool(def);
00986   } else {
00987     def = fx__scan_bool(param);
00988   }
00989 
00990   return def;
00991 }
00992 
00993 
00994 
00995 const char **fx_param_str_list(fx_module *mod, const char *key,
00996                                size_t *size_ptr, size_t def_size, ...)
00997 {
00998   fx_module *param = fx__param(mod, key, FX_STR_LIST);
00999 
01000   if (!param->val) {
01001     va_list vl;
01002 
01003     va_start(vl, def_size);
01004     param->val = fx__alloc_str_list(def_size, vl);
01005     va_end(vl);
01006   }
01007 
01008   return fx__scan_str_list(param, size_ptr, NULL);
01009 }
01010 
01011 double *fx_param_double_list(fx_module *mod, const char *key,
01012                              size_t *size_ptr, size_t def_size, ...)
01013 {
01014   fx_module *param = fx__param(mod, key, FX_DOUBLE_LIST);
01015 
01016   if (!param->val) {
01017     va_list vl;
01018 
01019     va_start(vl, def_size);
01020     param->val = fx__alloc_double_list(def_size, vl);
01021     va_end(vl);
01022   }
01023 
01024   return fx__scan_double_list(param, size_ptr, NULL);
01025 }
01026 
01027 long long *fx_param_int_list(fx_module *mod, const char *key,
01028                              size_t *size_ptr, size_t def_size, ...)
01029 {
01030   fx_module *param = fx__param(mod, key, FX_INT_LIST);
01031 
01032   if (!param->val) {
01033     va_list vl;
01034 
01035     va_start(vl, def_size);
01036     param->val = fx__alloc_int_list(def_size, vl);
01037     va_end(vl);
01038   }
01039 
01040   return fx__scan_int_list(param, size_ptr, NULL);
01041 }
01042 
01043 int *fx_param_bool_list(fx_module *mod, const char *key,
01044                         size_t *size_ptr, size_t def_size, ...)
01045 {
01046   fx_module *param = fx__param(mod, key, FX_BOOL_LIST);
01047 
01048   if (!param->val) {
01049     va_list vl;
01050 
01051     va_start(vl, def_size);
01052     param->val = fx__alloc_bool_list(def_size, vl);
01053     va_end(vl);
01054   }
01055 
01056   return fx__scan_bool_list(param, size_ptr, NULL);
01057 }
01058 
01059 
01060 
01061 const char **fx_param_str_array(fx_module *mod, const char *key,
01062                                 size_t *size_ptr, size_t def_size,
01063                                 const char *const *def_array)
01064 {
01065   fx_module *param = fx__param(mod, key, FX_STR_LIST);
01066 
01067   if (!param->val) {
01068     param->val = fx__alloc_str_array(def_size, def_array);
01069   }
01070 
01071   return fx__scan_str_list(param, size_ptr, NULL);
01072 }
01073 
01074 double *fx_param_double_array(fx_module *mod, const char *key,
01075                               size_t *size_ptr, size_t def_size,
01076                               const double *def_array)
01077 {
01078   fx_module *param = fx__param(mod, key, FX_DOUBLE_LIST);
01079 
01080   if (!param->val) {
01081     param->val = fx__alloc_double_array(def_size, def_array);
01082   }
01083 
01084   return fx__scan_double_list(param, size_ptr, NULL);
01085 }
01086 
01087 long long *fx_param_int_array(fx_module *mod, const char *key,
01088                               size_t *size_ptr, size_t def_size,
01089                               const long long *def_array)
01090 {
01091   fx_module *param = fx__param(mod, key, FX_INT_LIST);
01092 
01093   if (!param->val) {
01094     param->val = fx__alloc_int_array(def_size, def_array);
01095   }
01096 
01097   return fx__scan_int_list(param, size_ptr, NULL);
01098 }
01099 
01100 int *fx_param_bool_array(fx_module *mod, const char *key,
01101                          size_t *size_ptr, size_t def_size,
01102                          const int *def_array)
01103 {
01104   fx_module *param = fx__param(mod, key, FX_BOOL_LIST);
01105 
01106   if (!param->val) {
01107     param->val = fx__alloc_bool_array(def_size, def_array);
01108   }
01109 
01110   return fx__scan_bool_list(param, size_ptr, NULL);
01111 }
01112 
01113 
01114 
01115 void fx_set_param_str(fx_module *mod, const char *key, const char *val)
01116 {
01117   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_STR);
01118 
01119   free(param->val);
01120   param->val = strdup(val);
01121 }
01122 
01123 void fx_set_param_double(fx_module *mod, const char *key, double val)
01124 {
01125   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_DOUBLE);
01126 
01127   free(param->val);
01128   param->val = fx__alloc_double(val);
01129 }
01130 
01131 void fx_set_param_int(fx_module *mod, const char *key, long long val)
01132 {
01133   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_INT);
01134 
01135   free(param->val);
01136   param->val = fx__alloc_int(val);
01137 }
01138 
01139 void fx_set_param_bool(fx_module *mod, const char *key, int val)
01140 {
01141   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_BOOL);
01142 
01143   free(param->val);
01144   param->val = fx__alloc_bool(val);
01145 }
01146 
01147 
01148 
01149 void fx_set_param_str_list(fx_module *mod, const char *key,
01150                            size_t size, ...)
01151 {
01152   va_list vl;
01153   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_STR_LIST);
01154 
01155   va_start(vl, size);
01156   free(param->val);
01157   param->val = fx__alloc_str_list(size, vl);
01158   va_end(vl);
01159 }
01160 
01161 void fx_set_param_double_list(fx_module *mod, const char *key,
01162                               size_t size, ...)
01163 {
01164   va_list vl;
01165   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_DOUBLE_LIST);
01166 
01167   va_start(vl, size);
01168   free(param->val);
01169   param->val = fx__alloc_double_list(size, vl);
01170   va_end(vl);
01171 }
01172 
01173 void fx_set_param_int_list(fx_module *mod, const char *key,
01174                            size_t size, ...)
01175 {
01176   va_list vl;
01177   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_INT_LIST);
01178 
01179   va_start(vl, size);
01180   free(param->val);
01181   param->val = fx__alloc_int_list(size, vl);
01182   va_end(vl);
01183 }
01184 
01185 void fx_set_param_bool_list(fx_module *mod, const char *key,
01186                             size_t size, ...)
01187 {
01188   va_list vl;
01189   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_BOOL_LIST);
01190 
01191   va_start(vl, size);
01192   free(param->val);
01193   param->val = fx__alloc_bool_list(size, vl);
01194   va_end(vl);
01195 }
01196 
01197 
01198 
01199 void fx_set_param_str_array(fx_module *mod, const char *key,
01200                             size_t size, const char *const *array)
01201 {
01202   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_STR_LIST);
01203 
01204   free(param->val);
01205   param->val = fx__alloc_str_array(size, array);
01206 }
01207 
01208 void fx_set_param_double_array(fx_module *mod, const char *key,
01209                                size_t size, const double *array)
01210 {
01211   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_DOUBLE_LIST);
01212 
01213   free(param->val);
01214   param->val = fx__alloc_double_array(size, array);
01215 }
01216 
01217 void fx_set_param_int_array(fx_module *mod, const char *key,
01218                             size_t size, const long long *array)
01219 {
01220   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_INT_LIST);
01221 
01222   free(param->val);
01223   param->val = fx__alloc_int_array(size, array);
01224 }
01225 
01226 void fx_set_param_bool_array(fx_module *mod, const char *key,
01227                              size_t size, const int *array)
01228 {
01229   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_BOOL_LIST);
01230 
01231   free(param->val);
01232   param->val = fx__alloc_bool_array(size, array);
01233 }
01234 
01235 
01236 
01237 void fx_default_param(fx_module *mod, const char *key,
01238                       const char *def_format, ...)
01239 {
01240   fx_module *param = fx__param(mod, key, FX_STR);
01241 
01242   if (!param->val) {
01243     va_list vl;
01244 
01245     va_start(vl, def_format);
01246     param->val = fx__alloc_format(def_format, vl);
01247     va_end(vl);
01248   }
01249 }
01250 
01251 void fx_default_param_list(fx_module *mod, const char *key,
01252                            size_t *size_ptr, size_t def_size, ...)
01253 {
01254   fx_module *param = fx__param(mod, key, FX_STR_LIST);
01255 
01256   if (!param->val) {
01257     va_list vl;
01258 
01259     va_start(vl, def_size);
01260     param->val = fx__alloc_format_list(def_size, vl);
01261     va_end(vl);
01262   }
01263 }
01264 
01265 void fx_format_param(fx_module *mod, const char *key,
01266                      const char *format, ...)
01267 {
01268   va_list vl;
01269   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_STR);
01270 
01271   va_start(vl, format);
01272   free(param->val);
01273   param->val = fx__alloc_format(format, vl);
01274   va_end(vl);
01275 }
01276 
01277 void fx_format_param_list(fx_module *mod, const char *key,
01278                           size_t size, ...)
01279 {
01280   va_list vl;
01281   fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_STR_LIST);
01282 
01283   va_start(vl, size);
01284   free(param->val);
01285   param->val = fx__alloc_format_list(size, vl);
01286   va_end(vl);
01287 }
01288 
01289 
01290 
01291 void fx_clear_param(fx_module *mod, const char *key)
01292 {
01293   fx_module *param = fx__lookup(mod, key);
01294 
01295   DEBUG_ONLY(fx__check_mod_type("Requested", FX_RESERVED, param));
01296 
01297   free(param->val);
01298   param->val = NULL;
01299 }
01300 
01301 int fx_param_exists(fx_module *mod, const char *key)
01302 {
01303   fx_module *param = fx__lookup(mod, key);
01304 
01305   DEBUG_ONLY(fx__check_mod_type("Requested", FX_PARAM, param));
01306 
01307   if (param->mod_type == FX_PARAM) {
01308     if (param->val) {
01309       param->mod_type = FX_PROVIDED;
01310     }
01311   }
01312 
01313   return param->val != 0;
01314 }
01315 
01316 
01317 
01318 static fx_module *fx__get_result(fx_module *mod, const char *key,
01319                                  fx_val_t val_type)
01320 {
01321   fx_module *retval = fx__get_entry(mod, key, FX_RESULT, val_type);
01322 
01323   if (!retval->val) {
01324     FX__FATAL("Accessed result \"", retval, "\" is unspecified.");
01325   }
01326 
01327   return retval;
01328 }
01329 
01330 
01331 
01332 const char *fx_get_result_str(fx_module *mod, const char *key)
01333 {
01334   return fx__get_result(mod, key, FX_STR)->val;
01335 }
01336 
01337 double fx_get_result_double(fx_module *mod, const char *key)
01338 {
01339   return fx__scan_double(fx__get_result(mod, key, FX_DOUBLE));
01340 }
01341 
01342 long long fx_get_result_int(fx_module *mod, const char *key)
01343 {
01344   return fx__scan_int(fx__get_result(mod, key, FX_INT));
01345 }
01346 
01347 int fx_get_result_bool(fx_module *mod, const char *key)
01348 {
01349   return fx__scan_bool(fx__get_result(mod, key, FX_BOOL));
01350 }
01351 
01352 
01353 
01354 const char **fx_get_result_str_list(fx_module *mod, const char *key,
01355                                     size_t *size_ptr)
01356 {
01357   fx_module *result = fx__get_result(mod, key, FX_STR_LIST);
01358   return fx__scan_str_list(result, size_ptr, NULL);
01359 }
01360 
01361 double *fx_get_result_double_list(fx_module *mod, const char *key,
01362                                   size_t *size_ptr)
01363 {
01364   fx_module *result = fx__get_result(mod, key, FX_DOUBLE_LIST);
01365   return fx__scan_double_list(result, size_ptr, NULL);
01366 }
01367 
01368 long long *fx_get_result_int_list(fx_module *mod, const char *key,
01369                                   size_t *size_ptr)
01370 {
01371   fx_module *result = fx__get_result(mod, key, FX_INT_LIST);
01372   return fx__scan_int_list(result, size_ptr, NULL);
01373 }
01374 
01375 int *fx_get_result_bool_list(fx_module *mod, const char *key,
01376                              size_t *size_ptr)
01377 {
01378   fx_module *result = fx__get_result(mod, key, FX_BOOL_LIST);
01379   return fx__scan_bool_list(result, size_ptr, NULL);
01380 }
01381 
01382 
01383 
01384 void fx_result_str(fx_module *mod, const char *key, const char *val)
01385 {
01386   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_STR);
01387 
01388   free(result->val);
01389   result->val = strdup(val);
01390 }
01391 
01392 void fx_result_double(fx_module *mod, const char *key, double val)
01393 {
01394   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_DOUBLE);
01395 
01396   free(result->val);
01397   result->val = fx__alloc_double(val);
01398 }
01399 
01400 void fx_result_int(fx_module *mod, const char *key, long long val)
01401 {
01402   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_INT);
01403 
01404   free(result->val);
01405   result->val = fx__alloc_int(val);
01406 }
01407 
01408 void fx_result_bool(fx_module *mod, const char *key, int val)
01409 {
01410   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_BOOL);
01411 
01412   free(result->val);
01413   result->val = fx__alloc_bool(val);
01414 }
01415 
01416 
01417 
01418 void fx_result_str_list(fx_module *mod, const char *key,
01419                         size_t size, ...)
01420 {
01421   va_list vl;
01422   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_STR_LIST);
01423 
01424   va_start(vl, size);
01425   free(result->val);
01426   result->val = fx__alloc_str_list(size, vl);
01427   va_end(vl);
01428 }
01429 
01430 void fx_result_double_list(fx_module *mod, const char *key,
01431                            size_t size, ...)
01432 {
01433   va_list vl;
01434   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_DOUBLE_LIST);
01435 
01436   va_start(vl, size);
01437   free(result->val);
01438   result->val = fx__alloc_double_list(size, vl);
01439   va_end(vl);
01440 }
01441 
01442 void fx_result_int_list(fx_module *mod, const char *key,
01443                         size_t size, ...)
01444 {
01445   va_list vl;
01446   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_INT_LIST);
01447 
01448   va_start(vl, size);
01449   free(result->val);
01450   result->val = fx__alloc_int_list(size, vl);
01451   va_end(vl);
01452 }
01453 
01454 void fx_result_bool_list(fx_module *mod, const char *key,
01455                          size_t size, ...)
01456 {
01457   va_list vl;
01458   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_BOOL_LIST);
01459 
01460   va_start(vl, size);
01461   free(result->val);
01462   result->val = fx__alloc_bool_list(size, vl);
01463   va_end(vl);
01464 }
01465 
01466 
01467 
01468 void fx_result_str_array(fx_module *mod, const char *key,
01469                          size_t size, const char *const *array)
01470 {
01471   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_STR_LIST);
01472 
01473   free(result->val);
01474   result->val = fx__alloc_str_array(size, array);
01475 }
01476 
01477 void fx_result_double_array(fx_module *mod, const char *key,
01478                             size_t size, const double *array)
01479 {
01480   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_DOUBLE_LIST);
01481 
01482   free(result->val);
01483   result->val = fx__alloc_double_array(size, array);
01484 }
01485 
01486 void fx_result_int_array(fx_module *mod, const char *key,
01487                          size_t size, const long long *array)
01488 {
01489   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_INT_LIST);
01490 
01491   free(result->val);
01492   result->val = fx__alloc_int_array(size, array);
01493 }
01494 
01495 void fx_result_bool_array(fx_module *mod, const char *key,
01496                           size_t size, const int *array)
01497 {
01498   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_BOOL_LIST);
01499 
01500   free(result->val);
01501   result->val = fx__alloc_bool_array(size, array);
01502 }
01503 
01504 
01505 
01506 void fx_format_result(fx_module *mod, const char *key,
01507                       const char *format, ...)
01508 {
01509   va_list vl;
01510   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_STR);
01511 
01512   va_start(vl, format);
01513   free(result->val);
01514   result->val = fx__alloc_format(format, vl);
01515   va_end(vl);
01516 }
01517 
01518 void fx_format_result_list(fx_module *mod, const char *key,
01519                            size_t size, ...)
01520 {
01521   va_list vl;
01522   fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_STR_LIST);
01523 
01524   va_start(vl, size);
01525   free(result->val);
01526   result->val = fx__alloc_format_list(size, vl);
01527   va_end(vl);
01528 }
01529 
01530 
01531 
01532 void fx_clear_result(fx_module *mod, const char *key)
01533 {
01534   fx_module *result = fx__lookup(mod, key);
01535 
01536   DEBUG_ONLY(fx__check_mod_type("Requested", FX_RESULT, result));
01537 
01538   free(result->val);
01539   result->val = NULL;
01540 }
01541 
01542 int fx_result_exists(fx_module *mod, const char *key)
01543 {
01544   fx_module *result = fx__lookup(mod, key);
01545 
01546   DEBUG_ONLY(fx__check_mod_type("Requested", FX_RESULT, result));
01547 
01548   return result->val != NULL;
01549 }
01550 
01551 
01552 
01553 fx_timer *fx_get_timer(fx_module *mod, const char *key) {
01554   fx_module *timer = fx__lookup(mod, key);
01555 
01556   DEBUG_ONLY(fx__check_mod_type("Requested", FX_TIMER, timer));
01557 
01558   if (!timer->val) {
01559     timer->mod_type = FX_TIMER;
01560     timer->val_type = FX_CUSTOM;
01561     timer->val = malloc(sizeof(fx_timer));
01562     stopwatch_init( (fx_timer *)(timer->val) );
01563   }
01564 
01565   return (fx_timer *)(timer->val);
01566 }
01567 
01568 void fx_timer_start(fx_module *mod, const char *key)
01569 {
01570   stopwatch_start(fx_get_timer(mod, key));
01571 }
01572 
01573 void fx_timer_stop(fx_module *mod, const char *key)
01574 {
01575   struct timestamp now;
01576   timestamp_now(&now);
01577 
01578   stopwatch_stop(fx_get_timer(mod, key), &now);
01579 }
01580 
01581 void fx_reset_timer(fx_module *mod, const char *key)
01582 {
01583   stopwatch_init(fx_get_timer(mod, key));
01584 }
01585 
01586 
01587 
01588 fx_module *fx_submodule(fx_module *mod, const char *key)
01589 {
01590   fx_module *submod = fx__lookup(mod, key);
01591 
01592   DEBUG_ONLY(fx__check_mod_type("Requested", FX_MODULE, submod));
01593 
01594   return submod;
01595 }
01596 
01597 fx_module *fx_copy_module(fx_module *mod, const char *src_key,
01598                           const char *dest_format, ...)
01599 {
01600   va_list vl;
01601   char *dest_key;
01602   fx_module *dest_mod;
01603 
01604   va_start(vl, dest_format);
01605   dest_key = fx__alloc_format(dest_format, vl);
01606   va_end(vl);
01607 
01608   dest_mod = fx__lookup(mod, dest_key);
01609   if (src_key) {
01610     datanode_copy(dest_mod, fx__lookup(mod, src_key), 1);
01611 
01612     if (fx_module_is_type(dest_mod, FX_MODULE)) {
01613       fx_module *parent = dest_mod;
01614 
01615       while ((parent = parent->parent) && parent->mod_type == FX_UNKNOWN) {
01616         parent->mod_type = FX_MODULE;
01617       }
01618     }
01619   }
01620 
01621   DEBUG_ONLY(fx__check_mod_type("Requested", FX_MODULE, dest_mod));
01622 
01623   free(dest_key);
01624   return dest_mod;
01625 }
01626 
01627 
01628 
01629 static const char *fx__match_prefix(const char *key, const char *prefix)
01630 {
01631   for (; *key == '/'; ++key);  
01632   for (; *prefix == '/'; ++prefix);  
01633 
01634   while (*prefix) {
01635     const char *slash = strchr(prefix, '/');
01636     size_t len = slash ? slash - prefix : strlen(prefix);
01637 
01638     if (strncmp(key, prefix, len) == 0
01639         && (key[len] == '\0' || key[len] == '/')) {
01640       for (key += len; *key == '/'; ++key);
01641       for (prefix += len; *prefix == '/'; ++prefix);
01642     } else {
01643       return NULL;
01644     }
01645   }
01646 
01647   return key;
01648 }
01649 
01650 success_t fx_help(const fx_module_doc *doc, const char *key)
01651 {
01652   success_t retval = SUCCESS_WARN;
01653 
01654   for (; *key == '/'; ++key);
01655 
01656   if (*key == '\0') {
01657     retval = SUCCESS_PASS;
01658     printf("%s\n", doc->text);
01659   }
01660 
01661   if (doc->entries) {
01662     const fx_entry_doc *entry_doc;
01663 
01664     if (*key == '\0') {
01665       printf("Entries:\n");
01666     }
01667 
01668     for (entry_doc = doc->entries; entry_doc->key; ++entry_doc) {
01669       if (entry_doc->text) {
01670         if (fx__match_prefix(entry_doc->key, key)) {
01671           retval = SUCCESS_PASS;
01672           if (entry_doc->val_type < 0) {
01673             printf("\"%s\", %s:\n", entry_doc->key,
01674                    fx_mod_name[entry_doc->mod_type]);
01675           } else {
01676             printf("\"%s\", %s (%s):\n", entry_doc->key,
01677                    fx_mod_name[entry_doc->mod_type],
01678                    fx_val_name[entry_doc->val_type]);
01679           }
01680           printf("%s\n", entry_doc->text);
01681         }
01682       }
01683     }
01684   }
01685 
01686   if (doc->submodules) {
01687     const fx_submodule_doc *submod_doc;
01688 
01689     if (*key == '\0') {
01690       printf("Submodules:\n");
01691     }
01692 
01693     for (submod_doc = doc->submodules; submod_doc->key; ++submod_doc) {
01694       const char *match = fx__match_prefix(key, submod_doc->key);
01695 
01696       if (match) {
01697         retval |= fx_help(submod_doc->doc, match);
01698       } else if (submod_doc->text) {
01699         if (fx__match_prefix(submod_doc->key, key)) {
01700           retval = SUCCESS_PASS;
01701           printf("\"%s\":\n%s\n", submod_doc->key, submod_doc->text);
01702         }
01703       }
01704     }
01705   }
01706 
01707   return retval;
01708 }
01709 
01710 COMPILER_NO_RETURN
01711 static void fx__std_help(const char *prog, const char *help,
01712                          const fx_module_doc *doc)
01713 {
01714   success_t success;
01715 
01716   printf("%s --help%c%s\n\n", prog, *help ? '=' : ' ', help);
01717 
01718   if (doc) {
01719     success = fx_help(doc, help);
01720   } else {
01721     NONFATAL("Program \"%s\" is not documented.\n", prog);
01722     success = SUCCESS_WARN;
01723   }
01724   success |= fx_help(&fx__std_doc, help);
01725 
01726   if (!PASSED(success)) {
01727     NONFATAL("No documentation available for \"%s\".\n", help);
01728   }
01729 
01730   exit(1);
01731 }
01732 
01733 
01734 
01735 static void fx__fill_docs(fx_module *mod, const fx_module_doc *doc)
01736 {
01737   if (mod->mod_type == FX_UNKNOWN) {
01738     mod->mod_type = FX_MODULE;
01739   }
01740 
01741   if (doc->submodules) {
01742     const fx_submodule_doc *submod_doc;
01743 
01744     for (submod_doc = doc->submodules; submod_doc->key; ++submod_doc) {
01745       fx_module *submod = datanode_lookup(mod, submod_doc->key, 1);
01746 
01747       fx__fill_docs(submod, submod_doc->doc);
01748 
01749       while ((submod = submod->parent) && submod->mod_type == FX_UNKNOWN) {
01750         submod->mod_type = FX_MODULE;
01751       }
01752     }
01753   }
01754 
01755   if (doc->entries) {
01756     const fx_entry_doc *entry_doc;
01757 
01758     for (entry_doc = doc->entries; entry_doc->key; ++entry_doc) {
01759       fx_module *entry = datanode_lookup(mod, entry_doc->key, 1);
01760 
01761       DEBUG_ASSERT(entry_doc->mod_type != FX_UNKNOWN);
01762       DEBUG_ASSERT(entry_doc->mod_type != FX_PROVIDED);
01763       DEBUG_ASSERT(entry_doc->mod_type != FX_DEFAULT);
01764 
01765       DEBUG_ASSERT(entry_doc->mod_type != FX_PARAM
01766                    || entry_doc->val_type != FX_CUSTOM);
01767 
01768       entry->mod_type = entry_doc->mod_type;
01769       entry->val_type = entry_doc->val_type;
01770       entry->meta = entry_doc->meta;
01771 
01772       while ((entry = entry->parent) && entry->mod_type == FX_UNKNOWN) {
01773         entry->mod_type = FX_MODULE;
01774       }
01775     }
01776   }
01777 }
01778 
01779 static void fx__parse_cmd_line(fx_module *root, int argc, char *argv[])
01780 {
01781   int i;
01782 
01783   for (i = 0; i < argc; ++i) {
01784     if (argv[i][0] != '-' || argv[i][1] != '-') {
01785       NONFATAL("Ignoring argument missing \"--\": \"%s\".", argv[i]);
01786     } else {
01787       char *arg = strdup(argv[i] + 2);
01788       char *val = strchr(arg, '=');
01789       fx_module *entry;
01790 
01791       if (val) {
01792         *val++ = '\0';
01793         unhex_in_place(val);
01794       } else {
01795         val = "";
01796       }
01797       unhex_in_place(arg);
01798 
01799       entry = datanode_lookup_expert(root, arg, 1);
01800       if (entry->val) {
01801         FX__NONFATAL("Repeated \"--", entry, "=%s\" overwriting \"%s\".",
01802             val, entry->val);
01803         free(entry->val);
01804       }
01805       entry->val = strdup(val);
01806 
01807       free(arg);
01808     }
01809   }
01810 }
01811 
01812 static void fx__load_param_files(fx_module *root)
01813 {
01814   size_t size = 0;
01815   const char **load = fx_param_str_list_req(root, "fx/load", &size);
01816 
01817   while (size--) {
01818     FILE *stream = fopen(*load++, "r");
01819     if (likely(stream)) {
01820       datanode_read(root, stream, NULL, 0);
01821     } else {
01822       FATAL("Cannot open file for \"--fx/load=%s\".", *(load - 1));
01823     }
01824     fclose(stream);
01825   }
01826 }
01827 
01828 static success_t fx__check_param(fx_module *param)
01829 {
01830   success_t success = SUCCESS_PASS;
01831   size_t size = 0;
01832 
01833   
01834   switch (param->val_type) {
01835   case FX_STR:
01836     break;
01837   case FX_DOUBLE:
01838     fx__scan_double_impl(param, param->val, &success, 0);
01839     break;
01840   case FX_INT:
01841     fx__scan_int_impl(param, param->val, &success, 0);
01842     break;
01843   case FX_BOOL:
01844     fx__scan_bool_impl(param, param->val, &success, 0);
01845     break;
01846   case FX_STR_LIST:
01847     break;
01848   case FX_DOUBLE_LIST:
01849     fx__scan_double_list(param, &size, &success);
01850     break;
01851   case FX_INT_LIST:
01852     fx__scan_int_list(param, &size, &success);
01853     break;
01854   case FX_BOOL_LIST:
01855     fx__scan_bool_list(param, &size, &success);
01856     break;
01857   }
01858 
01859   return success;
01860 }
01861 
01862 static success_t fx__check_inputs(fx_module *mod)
01863 {
01864   fx_module *child;
01865   success_t success = SUCCESS_PASS;
01866 
01867   if (mod->mod_type == FX_REQUIRED && !mod->val) {
01868     FX__NONFATAL("Required parameter \"", mod, "\" is unspecified.");
01869     success = SUCCESS_FAIL;
01870   } else if (mod->mod_type == FX_RESERVED && mod->val) {
01871     FX__NONFATAL("Reserved parameter \"", mod, "\" must not be specified.");
01872     success = SUCCESS_FAIL;
01873   } else if (mod->val) {
01874     success = fx__check_mod_type("Input", FX_PARAM, mod);
01875     if (PASSED(success)) {
01876       success &= fx__check_param(mod);
01877     }
01878   }
01879 
01880   for (child = mod->first_child; child; child = child->next) {
01881     success &= fx__check_inputs(child);
01882   }
01883 
01884   return success;
01885 }
01886 
01887 static void fx__report_sys(fx_module *sys)
01888 {
01889   struct utsname info;
01890 
01891   uname(&info);
01892 
01893   fx_result_str(sys, "node/name", info.nodename);
01894   fx_result_str(sys, "arch/name", info.machine);
01895   fx_result_str(sys, "kernel/name", info.sysname);
01896   fx_result_str(sys, "kernel/release", info.release);
01897   fx_result_str(sys, "kernel/build", info.version);
01898 }
01899 
01900 static void fx__read_debug_params(fx_module *debug)
01901 {
01902   
01903   verbosity_level = fx_param_double(debug, "verbosity_level", 1.0);
01904   print_got_heres = fx_param_bool(debug, "print_got_heres", 1);
01905   print_warnings = fx_param_bool(debug, "print_warnings", 1);
01906   abort_on_nonfatal = fx_param_bool(debug, "abort_on_nonfatal", 0);
01907   pause_on_nonfatal = fx_param_bool(debug, "pause_on_nonfatal", 0);
01908   print_notify_locs = fx_param_bool(debug, "print_notify_locs", 0);
01909 }
01910 
01911 static void fx__attempt_speedup(fx_module *root)
01912 {
01913   
01914   sync();
01915   sleep(3);
01916 
01917   
01918   fx_timer_start(root, "total_time");
01919   fx_timer_stop(root, "total_time");
01920   fx_reset_timer(root, "total_time");
01921 }
01922 
01923 fx_module *fx_init(int argc, char *argv[], const fx_module_doc *doc)
01924 {
01925   fx_module *root = malloc(sizeof(fx_module));
01926 
01927   
01928   if (!fx_root) {
01929     fx_root = root;
01930   }
01931 
01932   datanode_init(root, "");
01933   fx__fill_docs(root, &fx__std_doc);
01934   if (doc) {
01935     fx__fill_docs(root, doc);
01936   }
01937 
01938   
01939   if (argc > 0) {
01940     fx__parse_cmd_line(root, argc - 1, argv + 1);
01941 
01942     if (fx_param_exists(root, "help")) {
01943       fx__std_help(argv[0], fx_param_str_req(root, "help"), doc);
01944     }
01945 
01946     if (fx_param_exists(root, "fx/load")) {
01947       fx__load_param_files(root);
01948     }
01949 
01950     if (fx_param_bool(root, "fx/no_docs_nagging", 0)) {
01951       fx_docs_nagging = 0;
01952     }
01953     MUST_NOT_FAIL_MSG(fx__check_inputs(root),
01954         "There were problems with input parameters; try --help.");
01955 
01956     fx__report_sys(fx_submodule(root, "info/sys"));
01957     fx__read_debug_params(fx_submodule(root, "debug"));
01958 
01959     if (fx_param_bool(root, "fx/timing", 0)) {
01960       fx__attempt_speedup(root);
01961     }
01962   }
01963 
01964   fx_timer_start(root, "total_time");
01965 
01966   return root;
01967 }
01968 
01969 
01970 
01971 static void fx__timer_double(fx_module *mod, const char *key, double val)
01972 {
01973   fx_module *timer = fx__lookup(mod, key);
01974 
01975   DEBUG_ONLY(fx__check_lookup(FX_TIMER, FX_DOUBLE, timer));
01976 
01977   free(timer->val);
01978   timer->val = fx__alloc_double(val);
01979 }
01980 
01981 
01982 #ifdef HAVE_RDTSC
01983 static void fx__timer_int(fx_module *mod, const char *key, long long val)
01984 {
01985   fx_module *timer = fx__lookup(mod, key);
01986 
01987   DEBUG_ONLY(fx__check_lookup(FX_TIMER, FX_INT, timer));
01988 
01989   free(timer->val);
01990   timer->val = fx__alloc_int(val);
01991 }
01992 #endif
01993 
01994 static void fx__stop_timers(fx_module *mod, struct timestamp *now)
01995 {
01996   fx_module *child;
01997 
01998   for (child = mod->first_child; child; child = child->next) {
01999     fx__stop_timers(child, now);
02000   }
02001 
02002   if (mod->mod_type == FX_TIMER && mod->val_type == FX_CUSTOM && mod->val) {
02003     fx_timer *timer = (fx_timer *)mod->val;
02004     if (STOPWATCH_ACTIVE(timer)) {
02005       stopwatch_stop(timer, now);
02006     }
02007 
02008     
02009     fx__fill_docs(mod, &fx__timer_doc);
02010 
02011 #ifdef HAVE_RDTSC
02012     fx__timer_int(mod, "cycles", timer->total.cycles);
02013 #endif
02014     fx__timer_double(mod, "real", timer->total.micros / 1e6);
02015     fx__timer_double(mod, "user",
02016         (double) timer->total.cpu.tms_utime / sysconf(_SC_CLK_TCK));
02017     fx__timer_double(mod, "sys",
02018         (double) timer->total.cpu.tms_stime / sysconf(_SC_CLK_TCK));
02019   }
02020 }
02021 
02022 static void fx__report_rusage(fx_module *mod, int usage_type)
02023 {
02024   struct rusage usage;
02025 
02026   getrusage(usage_type, &usage);
02027 
02028   
02029   fx_result_int(mod, "utime/sec", usage.ru_utime.tv_sec);
02030   fx_result_int(mod, "utime/usec", usage.ru_utime.tv_usec);
02031   fx_result_int(mod, "stime/sec", usage.ru_stime.tv_sec);
02032   fx_result_int(mod, "stime/usec", usage.ru_stime.tv_usec);
02033   fx_result_int(mod, "minflt", usage.ru_minflt);
02034   fx_result_int(mod, "majflt", usage.ru_majflt);
02035   fx_result_int(mod, "maxrss", usage.ru_maxrss);
02036   fx_result_int(mod, "ixrss", usage.ru_ixrss);
02037   fx_result_int(mod, "idrss", usage.ru_idrss);
02038   fx_result_int(mod, "isrss", usage.ru_isrss);
02039   fx_result_int(mod, "nswap", usage.ru_nswap);
02040   fx_result_int(mod, "inblock", usage.ru_inblock);
02041   fx_result_int(mod, "oublock", usage.ru_oublock);
02042   fx_result_int(mod, "msgsnd", usage.ru_msgsnd);
02043   fx_result_int(mod, "msgrcv", usage.ru_msgrcv);
02044   fx_result_int(mod, "nsignals", usage.ru_nsignals);
02045   fx_result_int(mod, "nvcsw", usage.ru_nvcsw);
02046   fx_result_int(mod, "nivcsw", usage.ru_nivcsw);
02047 }
02048 
02049 static void fx__output_results(fx_module *root)
02050 {
02051   char *type_char = fx_mod_marker;
02052 
02053   
02054   if (fx_param_bool(root, "fx/no_output_types", 0)) {
02055     type_char = NULL;
02056   }
02057 
02058   
02059   if (fx_param_exists(root, "fx/output")) {
02060     FILE *stream = fopen(fx_param_str_req(root, "fx/output"), "w");
02061     datanode_write(root, stream, type_char);
02062     fclose(stream);
02063   }
02064 
02065   
02066   if (!fx_param_bool(root, "fx/silent", 0)) {
02067     datanode_write(root, stdout, type_char);
02068   }
02069 }
02070 
02071 void fx_done(fx_module *root)
02072 {
02073   struct timestamp now;
02074   timestamp_now(&now);
02075 
02076   
02077   if (!root) {
02078     root = fx_root;
02079     fx_root = NULL;
02080   }
02081 
02082   DEBUG_ASSERT_MSG(root != NULL,
02083       "Cannot call fx_done without first calling fx_init.");
02084 
02085   fx__stop_timers(root, &now);
02086 
02087   if (fx_param_bool(root, "fx/rusage", 0)) {
02088     fx__report_rusage(
02089         fx_submodule(root, "info/rusage/self"), RUSAGE_SELF);
02090     fx__report_rusage(
02091         fx_submodule(root, "info/rusage/children"), RUSAGE_CHILDREN);
02092   }
02093 
02094   fx__output_results(root);
02095 
02096   datanode_destroy(root);
02097   free(root);
02098 }