1 /*
2 * Copyright (C) 2010 Regents of the University of Michigan
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "Parameters.h"
19 #include "Constant.h"
20 #include "MathConstant.h"
21 #include "Error.h"
22 #include "PhoneHome.h"
23
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdexcept>
29
30 int Parameter::nameCol = 30;
31 int Parameter::statusCol = 15;
32
Parameter(char c,const char * desc,void * v)33 Parameter::Parameter(char c, const char * desc, void * v)
34 {
35 ch = (char) tolower(c);
36 description = new char [strlen(desc) + 1];
37 strcpy(description, desc);
38 var = v;
39 warnings = NULL;
40
41 myNoPhoneHome = true;
42 myVersion.Clear();
43 }
44
Read(int,char ** argv,int argn)45 bool Parameter::Read(int , char ** argv, int argn)
46 {
47 int p = 0;
48 char c = (char) tolower(argv[argn][p]);
49
50 if ((c == '-') || (c == '/'))
51 {
52 p++;
53 c = (char) tolower(argv[argn][p]);
54 }
55
56 if (c == ch)
57 {
58 Translate(&(argv[argn][++p]));
59 return true;
60 }
61 return false;
62 }
63
TranslateExtras(const char *,const char *)64 bool Parameter::TranslateExtras(const char * , const char *)
65 {
66 return false;
67 }
68
warning(const char * format,...)69 void Parameter::warning(const char * format, ...)
70 {
71 String buffer;
72
73 va_list ap;
74 va_start(ap, format);
75 buffer.vprintf(format, ap);
76 va_end(ap);
77
78 if (warnings == NULL)
79 ::warning(buffer);
80 else
81 (*warnings) += buffer;
82 }
83
Translate(const char * value)84 void IntParameter::Translate(const char * value)
85 {
86 *(int *) var = atoi(value);
87 }
88
TranslateExtras(const char * value,const char * extras)89 bool IntParameter::TranslateExtras(const char * value, const char * extras)
90 {
91 if (value[0] != 0 || !CheckInteger(extras))
92 return false;
93
94 Translate(extras);
95
96 return true;
97 }
98
Status()99 void IntParameter::Status()
100 {
101 fprintf(stderr, "%*s : %*d (-%c9999)\n", nameCol, description,
102 statusCol, *(int *) var, ch);
103 }
104
Translate(const char * value)105 void SwitchParameter::Translate(const char * value)
106 {
107 switch (*value)
108 {
109 case '+' :
110 *(bool *) var = true;
111 break;
112 case '-' :
113 *(bool *) var = false;
114 break;
115 case 0 :
116 *(bool *) var = ! * (bool *) var;
117 break;
118 default :
119 warning("Command line parameter -%c%s: the option '%c' has no meaning\n",
120 ch, value, value[0]);
121 }
122 }
123
Status()124 void SwitchParameter::Status()
125 {
126 fprintf(stderr, "%*s : %*s (-%c[+|-])\n", nameCol, description,
127 statusCol, *(bool *) var == false ? "OFF" : "ON", ch);
128 }
129
DoubleParameter(char c,const char * desc,double & v)130 DoubleParameter::DoubleParameter(char c, const char * desc, double & v)
131 : Parameter(c, desc, &v)
132 {
133 precision = 2;
134 }
135
Translate(const char * value)136 void DoubleParameter::Translate(const char * value)
137 {
138 if (value[0])
139 *(double *) var = atof(value);
140 else
141 *(double *) var = _NAN_;
142 }
143
TranslateExtras(const char * value,const char * extras)144 bool DoubleParameter::TranslateExtras(const char * value, const char * extras)
145 {
146 if (value[0] != 0 || !CheckDouble(extras))
147 return false;
148
149 Translate(extras);
150
151 return true;
152 }
153
Status()154 void DoubleParameter::Status()
155 {
156 double absolute_value = fabs(* (double *) var);
157
158 if (*(double *) var == _NAN_)
159 fprintf(stderr, "%*s : %*s (-%c99.999)\n", nameCol, description,
160 statusCol, "NAN", ch);
161 else if (absolute_value >= 0.00095)
162 fprintf(stderr, "%*s : % *.*f (-%c99.999)\n", nameCol, description,
163 statusCol, precision, * (double *) var, ch);
164 else if (absolute_value <= 1e-15)
165 fprintf(stderr, "%*s : % *.0f (-%c99.999)\n", nameCol, description,
166 statusCol, * (double *) var, ch);
167 else
168 fprintf(stderr, "%*s : %*.0e (-%c99.999)\n", nameCol, description,
169 statusCol, *(double *) var, ch);
170 }
171
Translate(const char * value)172 void StringParameter::Translate(const char * value)
173 {
174 String * s = (String *) var;
175
176 *s = value;
177 }
178
TranslateExtras(const char * value,const char * extras)179 bool StringParameter::TranslateExtras(const char * value, const char * extras)
180 {
181 if ((value[0] != 0) || ((!required) && (extras[0] == '-')))
182 return false;
183
184 String * s = (String *) var;
185
186 *s = extras;
187
188 return true;
189 }
190
Status()191 void StringParameter::Status()
192 {
193 fprintf(stderr, "%*s : %*s (-%cname)\n", nameCol, description,
194 statusCol, (const char *)(*(String *) var), ch);
195 }
196
Status()197 void ListParameter::Status()
198 {
199 OptionList * l;
200
201 for (l = options; l->ch != 0; l++)
202 if (l->code == *((int *)var))
203 break;
204
205 fprintf(stderr, "%*s : %*s (-%c[%s])\n", nameCol, description,
206 statusCol, l->description, ch, (const char *) key);
207 }
208
Translate(const char * value)209 void ListParameter::Translate(const char * value)
210 {
211 OptionList * l;
212
213 for (l = options; l->ch != 0; l++)
214 if (tolower(l->ch) == tolower(value[0]))
215 break;
216
217 if (l->ch == 0 && tolower(value[0]) != 0)
218 warning("Command line parameter -%c%s: the option '%c' has no meaning\n",
219 ch, value, value[0], (const char *) key);
220
221 *((int*) var) = l->code;
222 }
223
ListParameter(char c,const char * desc,int & v,OptionList * opt)224 ListParameter::ListParameter(char c, const char * desc, int & v, OptionList * opt)
225 : Parameter(c, desc, &v)
226 {
227 options = opt;
228
229 for (OptionList * l = options; l->ch != 0; l++)
230 {
231 key += l->ch;
232 key += '|';
233 }
234
235 key.SetLength(key.Length() - 1);
236 }
237
SetParameter(char c,const char * desc,int & v,OptionList * opt)238 SetParameter::SetParameter(char c, const char * desc, int & v, OptionList * opt)
239 : Parameter(c, desc, &v)
240 {
241 options = opt;
242
243 for (OptionList * l = options; l->ch != 0; l++)
244 {
245 key += l->ch;
246 key += '|';
247 }
248 key.SetLength(key.Length() - 1);
249 }
250
Status()251 void SetParameter::Status()
252 {
253 bool first = 0;
254 int temp = * (int *) var;
255
256 for (OptionList * l = options; l->ch != 0; l++)
257 if ((l->code & temp) || (l->code == *(int *) var))
258 {
259 if (!first)
260 fprintf(stderr, "%*s : %*s (-%c{%s})\n", nameCol, description,
261 statusCol, l->description, ch, (const char *) key);
262 else
263 fprintf(stderr, "%*s & %*s\n", nameCol, "",
264 statusCol, l->description);
265 first = true;
266 temp &= ~l->code;
267 }
268 }
269
Translate(const char * value)270 void SetParameter::Translate(const char * value)
271 {
272 *(int*)var = 0;
273
274 for (const char * chr = value; *chr != 0; chr++)
275 {
276 int valid = false;
277
278 for (OptionList * l = options; l->ch != 0; l++)
279 if (tolower(l->ch) == tolower(*chr))
280 {
281 *((int*) var) |= l->code;
282 valid = true;
283 }
284
285 if (!valid)
286 warning("Command line parameter -%c%s: the option '%c' has no meaning\n",
287 ch, value, *chr);
288 }
289 }
290
LongParameters(const char * desc,LongParameterList * lst)291 LongParameters::LongParameters(const char * desc, LongParameterList * lst)
292 : Parameter('-', desc, NULL)
293 {
294 list = lst;
295
296 index.Clear();
297 legacyIndex.Clear();
298 group_len = 0;
299
300 LongParameterList * ptr = list + 1;
301
302 while (ptr->description != NULL)
303 {
304 if (ptr->type == LP_LEGACY_PARAMETERS)
305 break;
306 if(ptr->type == LP_PHONEHOME_VERSION)
307 {
308 // Phone home is turned on, so add
309 // the parameter for the user to turn it off.
310 myNoPhoneHome = false;
311 myVersion = ptr->description;
312 ptr->description = "noPhoneHome";
313 ptr->value = &myNoPhoneHome;
314 ptr->type = LP_BOOL_PARAMETER;
315 index.Add(ptr->description, ptr);
316 }
317 else
318 {
319 if (ptr->value != NULL)
320 index.Add(ptr->description, ptr);
321 else
322 group_len = max(strlen(ptr->description), group_len);
323 }
324 ptr++;
325 }
326
327 while (ptr->description != NULL)
328 {
329 if(ptr->type == LP_PHONEHOME_VERSION)
330 {
331 // Phone home is turned on, so add
332 // the parameter for the user to turn it off.
333 myNoPhoneHome = false;
334 myVersion = ptr->description;
335 ptr->description = "noPhoneHome";
336 ptr->value = &myNoPhoneHome;
337 ptr->type = LP_BOOL_PARAMETER;
338 legacyIndex.Add(ptr->description, ptr);
339 }
340 else
341 {
342 if (ptr->value != NULL)
343 legacyIndex.Add(ptr->description, ptr);
344 }
345 ptr++;
346 }
347
348 precision = 2;
349 }
350
ExplainAmbiguity(const char * cstr)351 void LongParameters::ExplainAmbiguity(const char * cstr)
352 {
353 String value(cstr);
354
355 int p = value.FastFindChar(':');
356 String stem = p == -1 ? value : value.Left(p);
357 String matches;
358
359 for (int i = 0; i < index.Length(); i++)
360 if (index[i].SlowCompareToStem(stem) == 0)
361 {
362 if (matches.Length() + index[i].Length() > 50)
363 {
364 matches += " ...";
365 break;
366 }
367
368 matches.catprintf(" --%s", (const char *) index[i]);
369 }
370
371 warning("Ambiguous --%s matches%s\n",
372 (const char *) value, (const char *) matches);
373 }
374
Translate(const char * cstr)375 void LongParameters::Translate(const char * cstr)
376 {
377 String value(cstr);
378
379 int p = value.FastFindChar(':');
380 int option = p == -1 ? index.FindStem(value) : index.FindStem(value.Left(p));
381
382 if (option == -2)
383 {
384 ExplainAmbiguity(cstr);
385 return;
386 }
387
388 LongParameterList * ptr;
389
390 if (option >= 0)
391 ptr = (LongParameterList *) index.Object(option);
392 else
393 {
394 int alternate = p == -1 ? legacyIndex.FindFirstStem(value) :
395 legacyIndex.FindFirstStem(value.Left(p));
396
397 if (alternate < 0)
398 {
399 warning("Command line parameter --%s is undefined\n", (const char *) value);
400 return;
401 }
402
403 ptr = (LongParameterList *) legacyIndex.Object(alternate);
404 ptr->touched = true;
405 }
406 ptr->touched = true;
407
408 if (ptr->type == LP_BOOL_PARAMETER)
409 {
410 if (p == -1)
411 * (bool *) ptr->value ^= true;
412 else
413 *(bool *) ptr->value = value.SubStr(p + 1).SlowCompare("ON") == 0;
414
415 // In exclusive groups, only one option may be selected
416 if (ptr->exclusive)
417 {
418 for (int i = -1; ptr[i].exclusive; i--) *(bool *)ptr[i].value = false;
419 for (int i = 1; ptr[i].exclusive; i++) *(bool *)ptr[i].value = false;
420 }
421 }
422 else if (ptr->type == LP_INT_PARAMETER)
423 if (p == -1)
424 * (int *) ptr->value = * (int *) ptr->value ? 0 : 1;
425 else
426 *(int *) ptr->value = value.SubStr(p + 1).SlowCompare("ON") == 0 ?
427 1 : value.SubStr(p + 1).AsInteger();
428 else if (ptr->type == LP_DOUBLE_PARAMETER)
429 {
430 if (p != -1)
431 * (double *) ptr->value = value.SubStr(p + 1).AsDouble();
432 }
433 else if (ptr->type == LP_STRING_PARAMETER)
434 {
435 if (p != -1)
436 * (String *) ptr->value = value.SubStr(p + 1);
437 }
438 }
439
TranslateExtras(const char * cstr,const char * extras)440 bool LongParameters::TranslateExtras(const char * cstr, const char * extras)
441 {
442 if (strchr(cstr, ':') != NULL)
443 return false;
444
445 int option = index.FindStem(cstr);
446
447 if (option == -2)
448 {
449 // No need to explain ambiguity here ... will be handle by later call
450 // to Translate()
451 // ExplainAmbiguity(cstr);
452 return false;
453 }
454
455 LongParameterList * ptr;
456
457 if (option >= 0)
458 ptr = (LongParameterList *) index.Object(option);
459 else
460 {
461 option = legacyIndex.FindFirstStem(cstr);
462
463 if (option < 0)
464 return false;
465
466 ptr = (LongParameterList *) legacyIndex.Object(option);
467 ptr->touched = true;
468 }
469
470 if (ptr->type == LP_INT_PARAMETER && CheckInteger(extras))
471 {
472 *(int *) ptr->value = atoi(extras);
473 ptr->touched = true;
474 return true;
475 }
476 else if (ptr->type == LP_DOUBLE_PARAMETER && CheckDouble(extras))
477 {
478 *(double *) ptr->value = atof(extras);
479 ptr->touched = true;
480 return true;
481 }
482 else if (ptr->type == LP_STRING_PARAMETER)
483 {
484 *(String *) ptr->value = extras;
485 ptr->touched = true;
486 return true;
487 }
488
489 return false;
490 }
491
Status(LongParameterList * ptr,int & line_len,bool & need_a_comma)492 void LongParameters::Status(LongParameterList * ptr, int & line_len, bool & need_a_comma)
493 {
494 String state;
495 int line_start = group_len ? group_len + 5 : 0;
496
497 if (ptr->value == NULL)
498 {
499 fprintf(stderr, "%s %*s :", need_a_comma ? "\n" : "", group_len + 2, ptr->description);
500 need_a_comma = false;
501 line_len = line_start;
502 }
503 else
504 {
505 if (ptr->type == LP_BOOL_PARAMETER)
506 state = * (bool *) ptr->value ? " [ON]" : "";
507 else if (ptr->type == LP_INT_PARAMETER)
508 if (((* (int *) ptr->value == 1) && (ptr->exclusive)) || (* (int *) ptr->value == 0))
509 state = * (int *) ptr->value ? " [ON]" : "";
510 else
511 state = " [", state += * (int *) ptr->value, state += ']';
512 else if (ptr->type == LP_DOUBLE_PARAMETER)
513 if (* (double *) ptr->value != _NAN_)
514 {
515 double value = * (double *) ptr->value;
516
517 state = " [";
518 if (value == 0.0 || value >= 0.01)
519 state.catprintf("%.*f", precision, value);
520 else
521 state.catprintf("%.1e", value);
522 state += ']';
523 }
524 else
525 state = "";
526 else if (ptr->type == LP_STRING_PARAMETER)
527 state = " [" + * (String *) ptr->value + "]";
528
529 int item_len = 3 + strlen(ptr->description) + need_a_comma + state.Length();
530
531 if (item_len + line_len > 78 && line_len > line_start)
532 {
533 line_len = line_start;
534 fprintf(stderr, "%s\n%*s", need_a_comma ? "," : "", line_len, "");
535 need_a_comma = 0;
536 item_len -= 1;
537 }
538
539 fprintf(stderr, "%s --%s%s", need_a_comma ? "," : (need_a_comma = true, ""),
540 ptr->description, (const char *) state);
541
542 need_a_comma = true;
543 line_len += item_len;
544 }
545 }
546
Status()547 void LongParameters::Status()
548 {
549 if (description != NULL && description[0] != 0)
550 fprintf(stderr, "\n%s\n", description);
551
552 bool need_a_comma = false;
553 int line_len = 0;
554
555 bool legacy_parameters = false;
556 int legacy_count = 0;
557
558 for (LongParameterList * ptr = list + 1; ptr->description != NULL; ptr++)
559 if (ptr->type == LP_LEGACY_PARAMETERS)
560 legacy_parameters = true;
561 else if (legacy_parameters == false)
562 Status(ptr, line_len, need_a_comma);
563 else if (ptr->touched)
564 {
565 if (legacy_count == 0)
566 {
567 fprintf(stderr, "\n\nAdditional Options:\n %*s ", group_len + 3, "");
568 line_len = group_len + 5;
569 need_a_comma = false;
570 }
571
572 Status(ptr, line_len, need_a_comma);
573 legacy_count++;
574 }
575
576 fprintf(stderr, "\n");
577 }
578
addParamsToString(String & params)579 void LongParameters::addParamsToString(String& params)
580 {
581 for (LongParameterList * ptr = list + 1; ptr->description != NULL; ptr++)
582 {
583 if (ptr->touched)
584 {
585 if(!params.IsEmpty())
586 {
587 params += PARAM_STR_SEP;
588 }
589 params += ptr->description;
590 }
591 }
592 }
593
Add(Parameter * p)594 void ParameterList::Add(Parameter * p)
595 {
596 if (count + 1 >= size)
597 error("Parameter list size should be increased");
598
599 p->SetWarningBuffer(warnings);
600 pl[count++] = p;
601 };
602
Read(int argc,char ** argv,int start)603 void ParameterList::Read(int argc, char ** argv, int start)
604 {
605 MakeString(argc, argv, start);
606 for (int i=start; i < argc; i++)
607 {
608 bool success = false;
609
610 if (argv[i][0] == '-' && argv[i][1])
611 for (int j=0; j<count; j++)
612 {
613 success = tolower(argv[i][1]) == pl[j]->ch;
614
615 if (success)
616 {
617 if ((i+1 < argc) && pl[j]->TranslateExtras(argv[i]+2, argv[i+1]))
618 i++;
619 else if (argv[i][2] == 0 && (i+1 < argc) && (argv[i + 1][0] != '-'))
620 pl[j]->Translate(argv[++i]);
621 else
622 pl[j]->Translate(argv[i] + 2);
623
624 break;
625 }
626 }
627
628 if (!success)
629 {
630 String warning;
631
632 warning.printf("Command line parameter %s (#%d) ignored\n", argv[i], i);
633 warnings += warning;
634 }
635 }
636
637 if (warnings.Length())
638 {
639 ::warning("Problems encountered parsing command line:\n\n%s",
640 (const char *) warnings);
641 warnings.Clear();
642 }
643
644 HandlePhoneHome(argc, argv, start);
645 }
646
ReadWithTrailer(int argc,char ** argv,int start)647 int ParameterList::ReadWithTrailer(int argc, char ** argv, int start)
648 {
649 MakeString(argc, argv, start);
650
651 int last_success = start - 1;
652 bool split = false;
653
654 for (int i=start; i < argc; i++)
655 {
656 bool success = false;
657
658 if (argv[i][0] == '-' && argv[i][1])
659 for (int j=0; j<count; j++)
660 {
661 success = tolower(argv[i][1]) == pl[j]->ch;
662
663 if (success)
664 {
665 if ((i+1 < argc) && pl[j]->TranslateExtras(argv[i]+2, argv[i+1]))
666 split = true;
667 else if (argv[i][2] == 0 && (i+1 < argc) && (argv[i + 1][0] != '-'))
668 pl[j]->Translate(argv[i + 1]), split = true;
669 else
670 pl[j]->Translate(argv[i] + 2);
671 break;
672 }
673 }
674
675 if (success)
676 for (last_success++; last_success < i; last_success++)
677 warnings.printf("Command line parameter %s (#%d) ignored\n",
678 argv[last_success], last_success);
679
680 if (split)
681 {
682 split = false;
683 last_success++;
684 i++;
685 }
686 }
687
688 if (warnings.Length())
689 {
690 ::warning("Problems encountered parsing command line:\n\n%s",
691 (const char *) warnings);
692 warnings.Clear();
693 }
694
695 HandlePhoneHome(argc, argv, start);
696
697 return last_success;
698 };
699
700
Status()701 void ParameterList::Status()
702 {
703 for (int i=0; i<count; i++)
704 pl[i]->Status();
705
706 fprintf(stderr, "\n");
707
708 if (messages.Length())
709 fprintf(stderr, "NOTES:\n%s\n", (const char *) messages);
710 }
711
MakeString(int argc,char ** argv,int start)712 void ParameterList::MakeString(int argc, char ** argv, int start)
713 {
714 int len = 0;
715
716 for (int i=start; i<argc; i++)
717 len += strlen(argv[i]) + 1;
718
719 string = new char [len+1];
720 string[0] = 0;
721
722 for (int i=start; i<argc; i++)
723 {
724 strcat(string, argv[i]);
725 strcat(string, " ");
726 }
727 }
728
729
HandlePhoneHome(int argc,char ** argv,int start)730 void ParameterList::HandlePhoneHome(int argc, char ** argv, int start)
731 {
732 // Determine the tool name : args prior to start.
733 String programName = "";
734 for(int i = 0; i < start; i++)
735 {
736 if(i == 0)
737 {
738 programName = argv[i];
739 }
740 else
741 {
742 programName += ":";
743 programName += argv[i];
744 }
745 }
746
747 // Loop through and get the params
748 String params = "";
749 String version = "";
750
751 for (int i=0; i<count; i++)
752 {
753 pl[i]->addParamsToString(params);
754 // Check if phonehome is enabled.
755 if(!pl[i]->myVersion.IsEmpty() && (!pl[i]->myNoPhoneHome))
756 {
757 // Version specified & phoneHome enabled, so
758 // phonehome.
759 version = pl[i]->myVersion;
760 }
761 }
762
763 if(!version.IsEmpty())
764 {
765 PhoneHome::checkVersion(programName.c_str(),
766 version.c_str(),
767 params.c_str());
768 }
769 }
770
771
~ParameterList()772 ParameterList::~ParameterList()
773 {
774 for (int i = 0; i < count; i++)
775 delete pl[i];
776 delete [] pl;
777 delete [] string;
778 };
779
CheckInteger(const char * value)780 bool Parameter::CheckInteger(const char * value)
781 {
782 if (value[0] != '+' && value[0] != '-' &&
783 (value[0] < '0' || value[0] > '9'))
784 return false;
785
786 int pos = 1;
787 while (value[pos] != 0)
788 if (value[pos] < '0' || value[pos] > '9')
789 return false;
790 else
791 pos++;
792
793 return true;
794 }
795
CheckDouble(const char * value)796 bool Parameter::CheckDouble(const char * value)
797 {
798 if (value[0] != '+' && value[0] != '-' && value[0] != '.' &&
799 (value[0] < '0' || value[0] > '9'))
800 {
801 return false;
802 }
803
804 bool decimal = value[0] == '.';
805
806 for (int pos = 1; value[pos] != 0; pos++)
807 {
808 if (value[pos] < '0' || value[pos] > '9')
809 {
810 if (!decimal && value[pos] == '.')
811 {
812 decimal = true;
813 }
814 else if (value[pos] == 'e' || value[pos] == 'E')
815 {
816 return CheckInteger(value + pos + 1);
817 }
818 }
819 }
820
821 return true;
822 }
823
Enforce(bool & var,bool value,const char * format,...)824 void ParameterList::Enforce(bool & var, bool value, const char * format, ...)
825 {
826 if (var == value)
827 return;
828
829 var = value;
830
831 String buffer;
832
833 va_list ap;
834 va_start(ap, format);
835 buffer.vprintf(format, ap);
836 va_end(ap);
837
838 messages += buffer;
839 }
840
Enforce(int & var,int value,const char * format,...)841 void ParameterList::Enforce(int & var, int value, const char * format, ...)
842 {
843 if (var == value)
844 return;
845
846 var = value;
847
848 String buffer;
849
850 va_list ap;
851 va_start(ap, format);
852 buffer.vprintf(format, ap);
853 va_end(ap);
854
855 messages += buffer;
856 }
857
Enforce(double & var,double value,const char * format,...)858 void ParameterList::Enforce(double & var, double value, const char * format, ...)
859 {
860 if (var == value)
861 return;
862
863 var = value;
864
865 String buffer;
866
867 va_list ap;
868 va_start(ap, format);
869 buffer.vprintf(format, ap);
870 va_end(ap);
871
872 messages += buffer;
873 }
874
Enforce(String & var,const char * value,const char * format,...)875 void ParameterList::Enforce(String & var, const char * value, const char * format, ...)
876 {
877 if (var.SlowCompare(value) == 0)
878 return;
879
880 var = value;
881
882 String buffer;
883 va_list ap;
884 va_start(ap, format);
885 buffer.vprintf(format, ap);
886 va_end(ap);
887
888 messages += buffer;
889 }
890
891
LongParamContainer()892 LongParamContainer::LongParamContainer()
893 : myEndIndex(0)
894 {
895 // Add the first (also adds ending) indicators.
896 add(NULL, NULL, false, 0, 0);
897 }
898
899
~LongParamContainer()900 LongParamContainer::~LongParamContainer()
901 {
902 }
903
904
add(const char * label,void * val,bool excl,int paramType,bool touch)905 void LongParamContainer::add(const char * label, void * val, bool excl,
906 int paramType, bool touch)
907 {
908 if(myEndIndex+1 < MAX_PARAM_ARRAY_SIZE)
909 {
910 // Overwrite the previous end record.
911 myArray[myEndIndex].description = label;
912 myArray[myEndIndex].value = val;
913 myArray[myEndIndex].exclusive = excl;
914 myArray[myEndIndex].type = paramType;
915 myArray[myEndIndex].touched = touch;
916 ++myEndIndex;
917
918 // Add a new empty entry to the end.
919 myArray[myEndIndex].description = NULL;
920 myArray[myEndIndex].value = NULL;
921 myArray[myEndIndex].exclusive = false;
922 myArray[myEndIndex].type = 0;
923 myArray[myEndIndex].touched = 0;
924 }
925 else
926 {
927 throw std::runtime_error("Tool Error: trying to add more parameters than allowed in LongParamContainer.\n");
928 }
929 }
930