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 }