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