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