00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "Parameters.h"
00019 #include "Constant.h"
00020 #include "MathConstant.h"
00021 #include "Error.h"
00022
00023 #include <stdio.h>
00024 #include <ctype.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <stdexcept>
00028
00029 int Parameter::nameCol = 30;
00030 int Parameter::statusCol = 15;
00031
00032 Parameter::Parameter(char c, const char * desc, void * v)
00033 {
00034 ch = (char) tolower(c);
00035 description = new char [strlen(desc) + 1];
00036 strcpy(description, desc);
00037 var = v;
00038 warnings = NULL;
00039 }
00040
00041 bool Parameter::Read(int , char ** argv, int argn)
00042 {
00043 int p = 0;
00044 char c = (char) tolower(argv[argn][p]);
00045
00046 if ((c == '-') || (c == '/'))
00047 {
00048 p++;
00049 c = (char) tolower(argv[argn][p]);
00050 }
00051
00052 if (c == ch)
00053 {
00054 Translate(&(argv[argn][++p]));
00055 return true;
00056 }
00057 return false;
00058 }
00059
00060 bool Parameter::TranslateExtras(const char * , const char *)
00061 {
00062 return false;
00063 }
00064
00065 void Parameter::warning(const char * format, ...)
00066 {
00067 String buffer;
00068
00069 va_list ap;
00070 va_start(ap, format);
00071 buffer.vprintf(format, ap);
00072 va_end(ap);
00073
00074 if (warnings == NULL)
00075 ::warning(buffer);
00076 else
00077 (*warnings) += buffer;
00078 }
00079
00080 void IntParameter::Translate(const char * value)
00081 {
00082 *(int *) var = atoi(value);
00083 }
00084
00085 bool IntParameter::TranslateExtras(const char * value, const char * extras)
00086 {
00087 if (value[0] != 0 || !CheckInteger(extras))
00088 return false;
00089
00090 Translate(extras);
00091
00092 return true;
00093 }
00094
00095 void IntParameter::Status()
00096 {
00097 fprintf(stderr, "%*s : %*d (-%c9999)\n", nameCol, description,
00098 statusCol, *(int *) var, ch);
00099 }
00100
00101 void SwitchParameter::Translate(const char * value)
00102 {
00103 switch (*value)
00104 {
00105 case '+' :
00106 *(bool *) var = true;
00107 break;
00108 case '-' :
00109 *(bool *) var = false;
00110 break;
00111 case 0 :
00112 *(bool *) var = ! * (bool *) var;
00113 break;
00114 default :
00115 warning("Command line parameter -%c%s: the option '%c' has no meaning\n",
00116 ch, value, value[0]);
00117 }
00118 }
00119
00120 void SwitchParameter::Status()
00121 {
00122 fprintf(stderr, "%*s : %*s (-%c[+|-])\n", nameCol, description,
00123 statusCol, *(bool *) var == false ? "OFF" : "ON", ch);
00124 }
00125
00126 DoubleParameter::DoubleParameter(char c, const char * desc, double & v)
00127 : Parameter(c, desc, &v)
00128 {
00129 precision = 2;
00130 }
00131
00132 void DoubleParameter::Translate(const char * value)
00133 {
00134 if (value[0])
00135 *(double *) var = atof(value);
00136 else
00137 *(double *) var = _NAN_;
00138 }
00139
00140 bool DoubleParameter::TranslateExtras(const char * value, const char * extras)
00141 {
00142 if (value[0] != 0 || !CheckDouble(extras))
00143 return false;
00144
00145 Translate(extras);
00146
00147 return true;
00148 }
00149
00150 void DoubleParameter::Status()
00151 {
00152 double absolute_value = fabs(* (double *) var);
00153
00154 if (*(double *) var == _NAN_)
00155 fprintf(stderr, "%*s : %*s (-%c99.999)\n", nameCol, description,
00156 statusCol, "NAN", ch);
00157 else if (absolute_value >= 0.00095)
00158 fprintf(stderr, "%*s : % *.*f (-%c99.999)\n", nameCol, description,
00159 statusCol, precision, * (double *) var, ch);
00160 else if (absolute_value <= 1e-15)
00161 fprintf(stderr, "%*s : % *.0f (-%c99.999)\n", nameCol, description,
00162 statusCol, * (double *) var, ch);
00163 else
00164 fprintf(stderr, "%*s : %*.0e (-%c99.999)\n", nameCol, description,
00165 statusCol, *(double *) var, ch);
00166 }
00167
00168 void StringParameter::Translate(const char * value)
00169 {
00170 String * s = (String *) var;
00171
00172 *s = value;
00173 }
00174
00175 bool StringParameter::TranslateExtras(const char * value, const char * extras)
00176 {
00177 if ((value[0] != 0) || ((!required) && (extras[0] == '-')))
00178 return false;
00179
00180 String * s = (String *) var;
00181
00182 *s = extras;
00183
00184 return true;
00185 }
00186
00187 void StringParameter::Status()
00188 {
00189 fprintf(stderr, "%*s : %*s (-%cname)\n", nameCol, description,
00190 statusCol, (const char *)(*(String *) var), ch);
00191 }
00192
00193 void ListParameter::Status()
00194 {
00195 OptionList * l;
00196
00197 for (l = options; l->ch != 0; l++)
00198 if (l->code == *((int *)var))
00199 break;
00200
00201 fprintf(stderr, "%*s : %*s (-%c[%s])\n", nameCol, description,
00202 statusCol, l->description, ch, (const char *) key);
00203 }
00204
00205 void ListParameter::Translate(const char * value)
00206 {
00207 OptionList * l;
00208
00209 for (l = options; l->ch != 0; l++)
00210 if (tolower(l->ch) == tolower(value[0]))
00211 break;
00212
00213 if (l->ch == 0 && tolower(value[0]) != 0)
00214 warning("Command line parameter -%c%s: the option '%c' has no meaning\n",
00215 ch, value, value[0], (const char *) key);
00216
00217 *((int*) var) = l->code;
00218 }
00219
00220 ListParameter::ListParameter(char c, const char * desc, int & v, OptionList * opt)
00221 : Parameter(c, desc, &v)
00222 {
00223 options = opt;
00224
00225 for (OptionList * l = options; l->ch != 0; l++)
00226 {
00227 key += l->ch;
00228 key += '|';
00229 }
00230
00231 key.SetLength(key.Length() - 1);
00232 }
00233
00234 SetParameter::SetParameter(char c, const char * desc, int & v, OptionList * opt)
00235 : Parameter(c, desc, &v)
00236 {
00237 options = opt;
00238
00239 for (OptionList * l = options; l->ch != 0; l++)
00240 {
00241 key += l->ch;
00242 key += '|';
00243 }
00244 key.SetLength(key.Length() - 1);
00245 }
00246
00247 void SetParameter::Status()
00248 {
00249 bool first = 0;
00250 int temp = * (int *) var;
00251
00252 for (OptionList * l = options; l->ch != 0; l++)
00253 if ((l->code & temp) || (l->code == *(int *) var))
00254 {
00255 if (!first)
00256 fprintf(stderr, "%*s : %*s (-%c{%s})\n", nameCol, description,
00257 statusCol, l->description, ch, (const char *) key);
00258 else
00259 fprintf(stderr, "%*s & %*s\n", nameCol, "",
00260 statusCol, l->description);
00261 first = true;
00262 temp &= ~l->code;
00263 }
00264 }
00265
00266 void SetParameter::Translate(const char * value)
00267 {
00268 *(int*)var = 0;
00269
00270 for (const char * chr = value; *chr != 0; chr++)
00271 {
00272 int valid = false;
00273
00274 for (OptionList * l = options; l->ch != 0; l++)
00275 if (tolower(l->ch) == tolower(*chr))
00276 {
00277 *((int*) var) |= l->code;
00278 valid = true;
00279 }
00280
00281 if (!valid)
00282 warning("Command line parameter -%c%s: the option '%c' has no meaning\n",
00283 ch, value, *chr);
00284 }
00285 }
00286
00287 LongParameters::LongParameters(const char * desc, LongParameterList * lst)
00288 : Parameter('-', desc, NULL)
00289 {
00290 list = lst;
00291
00292 index.Clear();
00293 legacyIndex.Clear();
00294 group_len = 0;
00295
00296 LongParameterList * ptr = list + 1;
00297
00298 while (ptr->description != NULL)
00299 {
00300 if (ptr->type == LP_LEGACY_PARAMETERS)
00301 break;
00302
00303 if (ptr->value != NULL)
00304 index.Add(ptr->description, ptr);
00305 else
00306 group_len = max(strlen(ptr->description), group_len);
00307
00308 ptr++;
00309 }
00310
00311 while (ptr->description != NULL)
00312 {
00313 if (ptr->value != NULL)
00314 legacyIndex.Add(ptr->description, ptr);
00315
00316 ptr++;
00317 }
00318
00319 precision = 2;
00320 }
00321
00322 void LongParameters::ExplainAmbiguity(const char * cstr)
00323 {
00324 String value(cstr);
00325
00326 int p = value.FastFindChar(':');
00327 String stem = p == -1 ? value : value.Left(p);
00328 String matches;
00329
00330 for (int i = 0; i < index.Length(); i++)
00331 if (index[i].SlowCompareToStem(stem) == 0)
00332 {
00333 if (matches.Length() + index[i].Length() > 50)
00334 {
00335 matches += " ...";
00336 break;
00337 }
00338
00339 matches.catprintf(" --%s", (const char *) index[i]);
00340 }
00341
00342 warning("Ambiguous --%s matches%s\n",
00343 (const char *) value, (const char *) matches);
00344 }
00345
00346 void LongParameters::Translate(const char * cstr)
00347 {
00348 String value(cstr);
00349
00350 int p = value.FastFindChar(':');
00351 int option = p == -1 ? index.FindStem(value) : index.FindStem(value.Left(p));
00352
00353 if (option == -2)
00354 {
00355 ExplainAmbiguity(cstr);
00356 return;
00357 }
00358
00359 LongParameterList * ptr;
00360
00361 if (option >= 0)
00362 ptr = (LongParameterList *) index.Object(option);
00363 else
00364 {
00365 int alternate = p == -1 ? legacyIndex.FindFirstStem(value) :
00366 legacyIndex.FindFirstStem(value.Left(p));
00367
00368 if (alternate < 0)
00369 {
00370 warning("Command line parameter --%s is undefined\n", (const char *) value);
00371 return;
00372 }
00373
00374 ptr = (LongParameterList *) legacyIndex.Object(alternate);
00375 ptr->touched = true;
00376 }
00377
00378 if (ptr->type == LP_BOOL_PARAMETER)
00379 {
00380 if (p == -1)
00381 * (bool *) ptr->value ^= true;
00382 else
00383 *(bool *) ptr->value = value.SubStr(p + 1).SlowCompare("ON") == 0;
00384
00385
00386 if (ptr->exclusive)
00387 {
00388 for (int i = -1; ptr[i].exclusive; i--) *(bool *)ptr[i].value = false;
00389 for (int i = 1; ptr[i].exclusive; i++) *(bool *)ptr[i].value = false;
00390 }
00391 }
00392 else if (ptr->type == LP_INT_PARAMETER)
00393 if (p == -1)
00394 * (int *) ptr->value = * (int *) ptr->value ? 0 : 1;
00395 else
00396 *(int *) ptr->value = value.SubStr(p + 1).SlowCompare("ON") == 0 ?
00397 1 : value.SubStr(p + 1).AsInteger();
00398 else if (ptr->type == LP_DOUBLE_PARAMETER)
00399 {
00400 if (p != -1)
00401 * (double *) ptr->value = value.SubStr(p + 1).AsDouble();
00402 }
00403 else if (ptr->type == LP_STRING_PARAMETER)
00404 {
00405 if (p != -1)
00406 * (String *) ptr->value = value.SubStr(p + 1);
00407 }
00408 }
00409
00410 bool LongParameters::TranslateExtras(const char * cstr, const char * extras)
00411 {
00412 if (strchr(cstr, ':') != NULL)
00413 return false;
00414
00415 int option = index.FindStem(cstr);
00416
00417 if (option == -2)
00418 {
00419
00420
00421
00422 return false;
00423 }
00424
00425 LongParameterList * ptr;
00426
00427 if (option >= 0)
00428 ptr = (LongParameterList *) index.Object(option);
00429 else
00430 {
00431 option = legacyIndex.FindFirstStem(cstr);
00432
00433 if (option < 0)
00434 return false;
00435
00436 ptr = (LongParameterList *) legacyIndex.Object(option);
00437 ptr->touched = true;
00438 }
00439
00440 if (ptr->type == LP_INT_PARAMETER && CheckInteger(extras))
00441 {
00442 *(int *) ptr->value = atoi(extras);
00443 return true;
00444 }
00445 else if (ptr->type == LP_DOUBLE_PARAMETER && CheckDouble(extras))
00446 {
00447 *(double *) ptr->value = atof(extras);
00448 return true;
00449 }
00450 else if (ptr->type == LP_STRING_PARAMETER)
00451 {
00452 *(String *) ptr->value = extras;
00453 return true;
00454 }
00455
00456 return false;
00457 }
00458
00459 void LongParameters::Status(LongParameterList * ptr, int & line_len, bool & need_a_comma)
00460 {
00461 String state;
00462 int line_start = group_len ? group_len + 5 : 0;
00463
00464 if (ptr->value == NULL)
00465 {
00466 fprintf(stderr, "%s %*s :", need_a_comma ? "\n" : "", group_len + 2, ptr->description);
00467 need_a_comma = false;
00468 line_len = line_start;
00469 }
00470 else
00471 {
00472 if (ptr->type == LP_BOOL_PARAMETER)
00473 state = * (bool *) ptr->value ? " [ON]" : "";
00474 else if (ptr->type == LP_INT_PARAMETER)
00475 if (((* (int *) ptr->value == 1) && (ptr->exclusive)) || (* (int *) ptr->value == 0))
00476 state = * (int *) ptr->value ? " [ON]" : "";
00477 else
00478 state = " [", state += * (int *) ptr->value, state += ']';
00479 else if (ptr->type == LP_DOUBLE_PARAMETER)
00480 if (* (double *) ptr->value != _NAN_)
00481 {
00482 double value = * (double *) ptr->value;
00483
00484 state = " [";
00485 if (value == 0.0 || value >= 0.01)
00486 state.catprintf("%.*f", precision, value);
00487 else
00488 state.catprintf("%.1e", value);
00489 state += ']';
00490 }
00491 else
00492 state = "";
00493 else if (ptr->type == LP_STRING_PARAMETER)
00494 state = " [" + * (String *) ptr->value + "]";
00495
00496 int item_len = 3 + strlen(ptr->description) + need_a_comma + state.Length();
00497
00498 if (item_len + line_len > 78 && line_len > line_start)
00499 {
00500 line_len = line_start;
00501 fprintf(stderr, "%s\n%*s", need_a_comma ? "," : "", line_len, "");
00502 need_a_comma = 0;
00503 item_len -= 1;
00504 }
00505
00506 fprintf(stderr, "%s --%s%s", need_a_comma ? "," : (need_a_comma = true, ""),
00507 ptr->description, (const char *) state);
00508
00509 need_a_comma = true;
00510 line_len += item_len;
00511 }
00512 }
00513
00514 void LongParameters::Status()
00515 {
00516 if (description != NULL && description[0] != 0)
00517 fprintf(stderr, "\n%s\n", description);
00518
00519 bool need_a_comma = false;
00520 int line_len = 0;
00521
00522 bool legacy_parameters = false;
00523 bool legacy_count = 0;
00524
00525 for (LongParameterList * ptr = list + 1; ptr->description != NULL; ptr++)
00526 if (ptr->type == LP_LEGACY_PARAMETERS)
00527 legacy_parameters = true;
00528 else if (legacy_parameters == false)
00529 Status(ptr, line_len, need_a_comma);
00530 else if (ptr->touched)
00531 {
00532 if (legacy_count == 0)
00533 {
00534 fprintf(stderr, "\n\nAdditional Options:\n %*s ", group_len + 3, "");
00535 line_len = group_len + 5;
00536 need_a_comma = false;
00537 }
00538
00539 Status(ptr, line_len, need_a_comma);
00540 legacy_count++;
00541 }
00542
00543 fprintf(stderr, "\n");
00544 }
00545
00546 void ParameterList::Add(Parameter * p)
00547 {
00548 if (count + 1 >= size)
00549 error("Parameter list size should be increased");
00550
00551 p->SetWarningBuffer(warnings);
00552 pl[count++] = p;
00553 };
00554
00555 void ParameterList::Read(int argc, char ** argv, int start)
00556 {
00557 MakeString(argc, argv, start);
00558 for (int i=start; i < argc; i++)
00559 {
00560 bool success = false;
00561
00562 if (argv[i][0] == '-' && argv[i][1])
00563 for (int j=0; j<count; j++)
00564 {
00565 success = tolower(argv[i][1]) == pl[j]->ch;
00566
00567 if (success)
00568 {
00569 if ((i+1 < argc) && pl[j]->TranslateExtras(argv[i]+2, argv[i+1]))
00570 i++;
00571 else if (argv[i][2] == 0 && (i+1 < argc) && (argv[i + 1][0] != '-'))
00572 pl[j]->Translate(argv[++i]);
00573 else
00574 pl[j]->Translate(argv[i] + 2);
00575 break;
00576 }
00577 }
00578
00579 if (!success)
00580 {
00581 String warning;
00582
00583 warning.printf("Command line parameter %s (#%d) ignored\n", argv[i], i);
00584 warnings += warning;
00585 }
00586 }
00587
00588 if (warnings.Length())
00589 {
00590 ::warning("Problems encountered parsing command line:\n\n%s",
00591 (const char *) warnings);
00592 warnings.Clear();
00593 }
00594 }
00595
00596 int ParameterList::ReadWithTrailer(int argc, char ** argv, int start)
00597 {
00598 MakeString(argc, argv, start);
00599
00600 int last_success = start - 1;
00601 bool split = false;
00602
00603 for (int i=start; i < argc; i++)
00604 {
00605 bool success = false;
00606
00607 if (argv[i][0] == '-' && argv[i][1])
00608 for (int j=0; j<count; j++)
00609 {
00610 success = tolower(argv[i][1]) == pl[j]->ch;
00611
00612 if (success)
00613 {
00614 if ((i+1 < argc) && pl[j]->TranslateExtras(argv[i]+2, argv[i+1]))
00615 split = true;
00616 else if (argv[i][2] == 0 && (i+1 < argc) && (argv[i + 1][0] != '-'))
00617 pl[j]->Translate(argv[i + 1]), split = true;
00618 else
00619 pl[j]->Translate(argv[i] + 2);
00620 break;
00621 }
00622 }
00623
00624 if (success)
00625 for (last_success++; last_success < i; last_success++)
00626 warnings.printf("Command line parameter %s (#%d) ignored\n",
00627 argv[last_success], last_success);
00628
00629 if (split)
00630 {
00631 split = false;
00632 last_success++;
00633 i++;
00634 }
00635 }
00636
00637 if (warnings.Length())
00638 {
00639 ::warning("Problems encountered parsing command line:\n\n%s",
00640 (const char *) warnings);
00641 warnings.Clear();
00642 }
00643
00644 return last_success;
00645 };
00646
00647
00648 void ParameterList::Status()
00649 {
00650 fprintf(stderr, "\nThe following parameters are available. Ones with \"[]\" are in effect:\n");
00651
00652 for (int i=0; i<count; i++)
00653 pl[i]->Status();
00654
00655 fprintf(stderr, "\n");
00656
00657 if (messages.Length())
00658 fprintf(stderr, "NOTES:\n%s\n", (const char *) messages);
00659 }
00660
00661 void ParameterList::MakeString(int argc, char ** argv, int start)
00662 {
00663 int len = 0;
00664
00665 for (int i=start; i<argc; i++)
00666 len += strlen(argv[i]) + 1;
00667
00668 string = new char [len+1];
00669 string[0] = 0;
00670
00671 for (int i=start; i<argc; i++)
00672 {
00673 strcat(string, argv[i]);
00674 strcat(string, " ");
00675 }
00676 }
00677
00678 ParameterList::~ParameterList()
00679 {
00680 for (int i = 0; i < count; i++)
00681 delete pl[i];
00682 delete [] pl;
00683 delete [] string;
00684 };
00685
00686 bool Parameter::CheckInteger(const char * value)
00687 {
00688 if (value[0] != '+' && value[0] != '-' &&
00689 (value[0] < '0' || value[0] > '9'))
00690 return false;
00691
00692 int pos = 1;
00693 while (value[pos] != 0)
00694 if (value[pos] < '0' || value[pos] > '9')
00695 return false;
00696 else
00697 pos++;
00698
00699 return true;
00700 }
00701
00702 bool Parameter::CheckDouble(const char * value)
00703 {
00704 if (value[0] != '+' && value[0] != '-' && value[0] != '.' &&
00705 (value[0] < '0' || value[0] > '9'))
00706 {
00707 return false;
00708 }
00709
00710 bool decimal = value[0] == '.';
00711
00712 for (int pos = 1; value[pos] != 0; pos++)
00713 {
00714 if (value[pos] < '0' || value[pos] > '9')
00715 {
00716 if (!decimal && value[pos] == '.')
00717 {
00718 decimal = true;
00719 }
00720 else if (value[pos] == 'e' || value[pos] == 'E')
00721 {
00722 return CheckInteger(value + pos + 1);
00723 }
00724 }
00725 }
00726
00727 return true;
00728 }
00729
00730 void ParameterList::Enforce(bool & var, bool value, const char * format, ...)
00731 {
00732 if (var == value)
00733 return;
00734
00735 var = value;
00736
00737 String buffer;
00738
00739 va_list ap;
00740 va_start(ap, format);
00741 buffer.vprintf(format, ap);
00742 va_end(ap);
00743
00744 messages += buffer;
00745 }
00746
00747 void ParameterList::Enforce(int & var, int value, const char * format, ...)
00748 {
00749 if (var == value)
00750 return;
00751
00752 var = value;
00753
00754 String buffer;
00755
00756 va_list ap;
00757 va_start(ap, format);
00758 buffer.vprintf(format, ap);
00759 va_end(ap);
00760
00761 messages += buffer;
00762 }
00763
00764 void ParameterList::Enforce(double & var, double value, const char * format, ...)
00765 {
00766 if (var == value)
00767 return;
00768
00769 var = value;
00770
00771 String buffer;
00772
00773 va_list ap;
00774 va_start(ap, format);
00775 buffer.vprintf(format, ap);
00776 va_end(ap);
00777
00778 messages += buffer;
00779 }
00780
00781 void ParameterList::Enforce(String & var, const char * value, const char * format, ...)
00782 {
00783 if (var.SlowCompare(value) == 0)
00784 return;
00785
00786 var = value;
00787
00788 String buffer;
00789 va_list ap;
00790 va_start(ap, format);
00791 buffer.vprintf(format, ap);
00792 va_end(ap);
00793
00794 messages += buffer;
00795 }
00796
00797
00798 LongParamContainer::LongParamContainer()
00799 : myEndIndex(0)
00800 {
00801
00802 add(NULL, NULL, false, 0, 0);
00803 }
00804
00805
00806 LongParamContainer::~LongParamContainer()
00807 {
00808 }
00809
00810
00811 void LongParamContainer::add(const char * label, void * val, bool excl,
00812 int paramType, bool touch)
00813 {
00814 if(myEndIndex+1 < MAX_PARAM_ARRAY_SIZE)
00815 {
00816
00817 myArray[myEndIndex].description = label;
00818 myArray[myEndIndex].value = val;
00819 myArray[myEndIndex].exclusive = excl;
00820 myArray[myEndIndex].type = paramType;
00821 myArray[myEndIndex].touched = touch;
00822 ++myEndIndex;
00823
00824
00825 myArray[myEndIndex].description = NULL;
00826 myArray[myEndIndex].value = NULL;
00827 myArray[myEndIndex].exclusive = false;
00828 myArray[myEndIndex].type = 0;
00829 myArray[myEndIndex].touched = 0;
00830 }
00831 else
00832 {
00833 throw std::runtime_error("Tool Error: trying to add more parameters than allowed in LongParamContainer.\n");
00834 }
00835 }
00836
00837