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