fx.c

Go to the documentation of this file.
00001 /* MLPACK 0.2
00002  *
00003  * Copyright (c) 2008, 2009 Alexander Gray,
00004  *                          Garry Boyer,
00005  *                          Ryan Riegel,
00006  *                          Nikolaos Vasiloglou,
00007  *                          Dongryeol Lee,
00008  *                          Chip Mappus, 
00009  *                          Nishant Mehta,
00010  *                          Hua Ouyang,
00011  *                          Parikshit Ram,
00012  *                          Long Tran,
00013  *                          Wee Chin Wong
00014  *
00015  * Copyright (c) 2008, 2009 Georgia Institute of Technology
00016  *
00017  * This program is free software; you can redistribute it and/or
00018  * modify it under the terms of the GNU General Public License as
00019  * published by the Free Software Foundation; either version 2 of the
00020  * License, or (at your option) any later version.
00021  *
00022  * This program is distributed in the hope that it will be useful, but
00023  * WITHOUT ANY WARRANTY; without even the implied warranty of
00024  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00025  * General Public License for more details.
00026  *
00027  * You should have received a copy of the GNU General Public License
00028  * along with this program; if not, write to the Free Software
00029  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00030  * 02110-1301, USA.
00031  */
00038 #include "fastlib/fx/fx.h"
00039 /*#include "fx.h"*/
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 /* TODO: Use this mutex where appropriate */
00053 // static pthread_mutex_t fx__mutex;
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 /* Long enough to store a double, long long, or bool as a string
00088  * - doubles have 16 sig figs, as in: -X.XXXXXXXXXXXXXXXe-XXX
00089  * - ints have at most 3 sig figs per byte; they need 2 more chars for
00090  *   sign and null, but have enough spare even if just 4 bytes
00091  * - bools are strings "true" or "false"
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) { /* Types without subtypes */
00332     return entry->mod_type == mod_type;
00333   } else if (mod_type >= FX_PARAM) { /* (Required) parameters */
00334     return entry->mod_type >= mod_type && entry->mod_type < FX_TIMER;
00335   } else { /* Modules and unknowns */
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   /* Allocate space for string, elements, and array */
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   /* Copy string to form elements; simulate "leading comma" */
00487   str = mod->val + len;
00488   strcpy(str + 1, mod->val);
00489 
00490   /* Demark elements and add to array */
00491   elem = retval;
00492   do {
00493     *str++ = '\0';
00494     *elem++ = str;
00495   } while ((str = strchr(str, ',')));
00496 
00497   /* Parse escaped characters */
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   /* Allocate space for string and array */
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   /* Backstep once to simulate "leading comma" */
00523   str = mod->val - 1;
00524 
00525   /* Fill the array */
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   /* Allocate space for string and array */
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   /* Backstep once to simulate "leading comma" */
00552   str = mod->val - 1;
00553 
00554   /* Fill the array */
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   /* Allocate space for string and array */
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   /* Backstep once to simulate "leading comma" */
00581   str = mod->val - 1;
00582 
00583   /* Fill the array */
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   /* Note: Params can't be FX_CUSTOM */
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   /* TODO: Default to current settings for customizability? */
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   /* Try to minimize disk access */
01914   sync();
01915   sleep(3);
01916 
01917   /* Start and stop default timer to bring code into cache */
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   /* First fx_init sets true root but can call to create more trees */
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   /* Set argc = 0 to omit command line parsing */
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 /* #ifdef because gcc whines about not using this function */
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     /* Squelch "undocumented" nagging with bonus timer docs */
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   /* Note: Many of these are unsupported by various OSes */
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   /* Disable the printing of type characters if appropriate */
02054   if (fx_param_bool(root, "fx/no_output_types", 0)) {
02055     type_char = NULL;
02056   }
02057 
02058   /* Pipe a transcript of the params if output specified */
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   /* Still pipe to stdout unless explicitly silenced */
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   /* Can input NULL, but also additionally created trees */
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 }
Generated on Mon Jan 24 12:04:37 2011 for FASTlib by  doxygen 1.6.3