source: orange/source/orange/vars.cpp @ 11696:1c9c5bda6959

Revision 11696:1c9c5bda6959, 22.7 KB checked in by Ales Erjavec <ales.erjavec@…>, 7 months ago (diff)

Check for negative index values.

Line 
1/*
2    This file is part of Orange.
3
4    Copyright 1996-2010 Faculty of Computer and Information Science, University of Ljubljana
5    Contact: janez.demsar@fri.uni-lj.si
6
7    Orange is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Orange is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Orange.  If not, see <http://www.gnu.org/licenses/>.
19*/
20
21
22// to include Python.h before STL defines a template set (doesn't work with VC 6.0)
23#include "garbage.hpp"
24
25#include <set>
26#include <stack>
27#include <map>
28#include <algorithm>
29#include <queue>
30#include <list>
31#include <float.h>
32#include <locale>
33
34#ifdef DARWIN
35#include <strings.h>
36#endif
37
38#include "stladdon.hpp"
39#include "errors.hpp"
40#include "examples.hpp"
41#include "examplegen.hpp"
42#include "classify.hpp"
43#include "domain.hpp"
44#include "random.hpp"
45#include "orvector.hpp"
46#include "stringvars.hpp"
47
48#include "vars.hpp"
49
50DEFINE_TOrangeVector_classDescription(PVariable, "TVarList", true, ORANGE_API)
51DEFINE_TOrangeVector_classDescription(PVarList, "TVarListList", true, ORANGE_API)
52
53DEFINE_AttributedList_classDescription(TAttributedFloatList, TFloatList)
54DEFINE_AttributedList_classDescription(TAttributedBoolList, TBoolList)
55
56
57#ifdef _MSC_VER_60
58 TClassDescription template TOrangeVector<TValue, false>::st_classDescription;
59 ORANGE_EXTERN template class ORANGE_API TOrangeVector<TValue, false>;
60#else
61 DEFINE_TOrangeVector_classDescription(TValue, "TOrangeVector<TValue, false>", false, ORANGE_API)
62#endif
63
64#include "vars.ppp"
65
66bool mmvDeallocated = 0;
67
68/* The following class is to be used only for the allVariablesMap variable.
69 * It sets a flag after it has been deallocated, so that after program shutdown
70 * the deallocated TVariable instances do not try to remove themselves from the
71 * map. Besides, this class overrides the non-virtual destructor of STL
72 * multimap, so it's not functional if the variable is declared using MMV's
73 * supertype!
74 */
75class MMV : public multimap<string, TVariable *> {
76public:
77    ~MMV() {
78        mmvDeallocated = 1;
79    }
80};
81
82
83MMV TVariable::allVariablesMap;
84
85const char *sortedDaNe[] = {"da", "ne", 0 };
86const char *resortedDaNe[] = {"ne", "da", 0};
87
88const char **specialSortCases[] = { sortedDaNe, 0};
89const char **specialCasesResorted[] = { resortedDaNe, 0};
90
91const char *putAtBeginning[] = {"no", "none", "absent", "normal", 0};
92
93TVariable *TVariable::getExisting(const string &name, const int &varType, TStringList *fixedOrderValues, set<string> *values,
94                                  const int failOn, int *status)
95{
96  if ((fixedOrderValues && fixedOrderValues->size() ) && (varType != TValue::INTVAR))
97    ::raiseErrorWho("Variable", "cannot specify the value list for non-discrete attributes");
98
99  if (failOn == TVariable::OK) {
100    if (status)
101      *status = TVariable::OK;
102    return NULL;
103  }
104
105  vector<pair<TVariable *, int> > candidates;
106  TStringList::const_iterator vvi, vve;
107
108   pair<MMV::iterator,MMV::iterator> rp = allVariablesMap.equal_range(name);
109   MMV::iterator it;
110 
111   for (it=rp.first; it!=rp.second; ++it) { 
112     if ((it->second)->varType == varType) {
113
114      int tempStat = TVariable::OK;
115
116      // non-discrete attributes are always ok,
117      // discrete ones need further checking if they have any defined values
118      TEnumVariable *evar = dynamic_cast<TEnumVariable *>(it->second);
119      if (evar && evar->values->size()) {
120
121        if (fixedOrderValues && !evar->checkValuesOrder(*fixedOrderValues))
122          tempStat = TVariable::Incompatible;
123
124        if ((tempStat == TVariable::OK)
125            && (values && values->size() || fixedOrderValues && fixedOrderValues->size())) {
126          for(vvi = evar->values->begin(), vve = evar->values->end();
127              (vvi != vve)
128               && (!values || (values->find(*vvi) == values->end()))
129               && (!fixedOrderValues || (find(fixedOrderValues->begin(), fixedOrderValues->end(), *vvi) == fixedOrderValues->end()));
130              vvi++);
131          if (vvi == vve)
132            tempStat = TVariable::NoRecognizedValues;
133         }
134
135         if ((tempStat == TVariable::OK) && fixedOrderValues) {
136           for(vvi = fixedOrderValues->begin(), vve = fixedOrderValues->end();
137               (vvi != vve) && evar->hasValue(*vvi);
138               vvi++);
139           if (vvi != vve)
140             tempStat = TVariable::MissingValues;
141         }
142
143         if ((tempStat == TVariable::OK) && values) {
144           set<string>::const_iterator vsi(values->begin()), vse(values->end());
145           for(; (vsi != vse) && evar->hasValue(*vsi); vsi++);
146           if (vsi != vse)
147             tempStat = TVariable::MissingValues;
148         }
149       }
150
151      candidates.push_back(make_pair(it->second, tempStat));
152      if (tempStat == TVariable::OK)
153        break;
154    }
155  }
156
157  TVariable *var = NULL;
158
159  int intStatus;
160  if (!status)
161    status = &intStatus;
162  *status = TVariable::NotFound;
163
164  const int actFailOn = failOn > TVariable::Incompatible ? TVariable::Incompatible : failOn;
165  for(vector<pair<TVariable *, int> >::const_iterator ci(candidates.begin()), ce(candidates.end());
166      ci != ce; ci++)
167    if (ci->second < *status) {
168      *status = ci->second;
169      if (*status < actFailOn)
170        var = ci->first;
171    }
172
173  //var = mlnew TEnumVariable(name);
174  TEnumVariable *evar = dynamic_cast<TEnumVariable *>(var);
175  if (evar) {
176    if (fixedOrderValues)
177      const_PITERATE(TStringList, si, fixedOrderValues)
178        evar->addValue(*si);
179
180    if (values) {
181      vector<string> sorted;
182      TEnumVariable::presortValues(*values, sorted);
183      const_ITERATE(vector<string>, ssi, sorted)
184        evar->addValue(*ssi);
185    }
186  }
187
188  return var;
189}
190
191
192TVariable *TVariable::make(const string &name, const int &varType, TStringList *fixedOrderValues, set<string> *values,
193                           const int createNewOn, int *status)
194{
195  int intStatus;
196  if (!status)
197    status = &intStatus;
198
199  TVariable *var;
200  if (createNewOn == TVariable::OK) {
201    var = NULL;
202    *status = TVariable::OK;
203  }
204  else {
205    var = getExisting(name, varType, fixedOrderValues, values, createNewOn, status);
206  }
207
208  if (!var) {
209      switch (varType) {
210        case TValue::INTVAR: {
211          var = mlnew TEnumVariable(name);
212          TEnumVariable *evar = dynamic_cast<TEnumVariable *>(var);
213          if (evar) {
214            if (fixedOrderValues)
215              const_PITERATE(TStringList, si, fixedOrderValues)
216                evar->addValue(*si);
217
218            if (values) {
219              vector<string> sorted;
220              TEnumVariable::presortValues(*values, sorted);
221              const_ITERATE(vector<string>, ssi, sorted)
222                evar->addValue(*ssi);
223            }
224          }
225          break;
226        }
227
228        case TValue::FLOATVAR:
229          var = mlnew TFloatVariable(name);
230          break;
231
232        case STRINGVAR:
233          var = mlnew TStringVariable(name);
234          break;
235      }
236  }
237
238  return var;
239}
240
241
242bool TVariable::isEquivalentTo(const TVariable &old) const {
243  return    (varType == old.varType) && (ordered == old.ordered) && (distributed == old.distributed)
244         && (!sourceVariable || !old.sourceVariable || (sourceVariable == old.sourceVariable))
245         && (!getValueFrom || !old.getValueFrom || (getValueFrom == old.getValueFrom));
246}
247
248
249void TVariable::registerVariable() {
250  allVariablesMap.insert(pair<string, TVariable *>(name, this));
251}
252
253void TVariable::removeVariable() {
254      pair<MMV::iterator,MMV::iterator> rp = allVariablesMap.equal_range(name);
255      MMV::iterator it;
256
257      for (it=rp.first; it!=rp.second; ++it) {
258          if (it->second == this) {
259              allVariablesMap.erase(it);
260              break;
261          }
262      }
263}
264
265TVariable::~TVariable()
266{
267    /* When the program shuts down, it may happen that the list is destroyed before
268       the variables. We do nothing in this case. */
269    if (!mmvDeallocated) {
270        removeVariable();
271    }
272}
273
274TVariable::TVariable(const int &avarType, const bool &ord)
275: varType(avarType),
276  ordered(ord),
277  distributed(false),
278  getValueFromLocked(false),
279  DC_value(varType, valueDC),
280  DK_value(varType, valueDK),
281  defaultMetaId(0)
282{
283  registerVariable();
284}
285
286
287TVariable::TVariable(const string &aname, const int &avarType, const bool &ord)
288: varType(avarType),
289  ordered(ord),
290  distributed(false),
291  getValueFromLocked(false),
292  DC_value(varType, valueDC),
293  DK_value(varType, valueDK),
294  defaultMetaId(0)
295{ name = aname; 
296  registerVariable();
297};
298
299
300const TValue &TVariable::DC() const
301{ return DC_value; }
302
303
304const TValue &TVariable::DK() const
305{ return DK_value; }
306
307
308TValue  TVariable::specialValue(int spec) const
309{ return TValue(varType, spec); }
310
311/*  Converts a human-readable string, representing the value (as read from the file, for example) to TValue.
312    TVariable::str2val_add interprets ? as DK and ~ as DC; otherwise it sets val.varType to varType, other fields
313    are left intact.*/
314bool TVariable::str2special(const string &valname, TValue &valu) const
315{ if ((valname=="?") || !valname.length()){
316    valu = TValue(DK());
317    return true;
318  }
319  else if (valname=="~") {
320    valu = TValue(DC());
321    return true;
322  }
323  return false;
324}
325
326
327bool TVariable::special2str(const TValue &val, string &str) const
328{ switch (val.valueType) {
329    case 0: return false;
330    case valueDC : str="~"; break;
331    case valueDK : str="?"; break;
332    default: str = ".";
333  }
334  return true;
335}
336
337
338
339bool TVariable::str2val_try(const string &valname, TValue &valu)
340{ try {
341    str2val(valname, valu);
342    return true;
343  } catch (exception) {
344    return false;
345  }
346}
347
348
349void TVariable::str2val_add(const string &valname, TValue &valu)
350{ str2val(valname, valu); }
351
352
353void TVariable::filestr2val(const string &valname, TValue &valu, TExample &)
354{ str2val_add(valname, valu); }
355
356
357void TVariable::val2filestr(const TValue &val, string &str, const TExample &) const
358{ val2str(val, str); }
359
360
361// Calls classifier, specified in getValueFrom, if one is available
362TValue TVariable::computeValue(const TExample &ex)
363{ if (getValueFrom && !getValueFromLocked)
364    try {
365      if (distributed) {
366        getValueFromLocked = true;
367        const PSomeValue val = PSomeValue(getValueFrom->classDistribution(ex));
368        getValueFromLocked = false;
369        return TValue(PSomeValue(val));
370      }
371      else {
372        getValueFromLocked = true;
373        const TValue val = getValueFrom->operator()(ex);
374        getValueFromLocked = false;
375        return val;
376      }
377    }
378    catch (...) {
379      getValueFromLocked = false;
380      throw;
381    }
382  else
383    return DK();
384}
385
386
387bool TVariable::firstValue(TValue &val) const
388{
389  raiseError("attribute '%s' does not support 'firstValue' method", name.c_str());
390  return false;
391}
392
393bool TVariable::nextValue(TValue &val) const
394{
395  raiseError("attribute '%s' does not support 'nextValue' method", name.c_str());
396  return false;
397}
398
399TValue TVariable::randomValue(const int &rand)
400{
401  raiseError("attribute '%s' does not support 'randomValue' method", name.c_str());
402  return TValue();
403}
404
405
406// Sets autoValues to true, maxLen to 2 and varType to TValue::INVAR
407TEnumVariable::TEnumVariable()
408: TVariable(TValue::INTVAR, false),
409  values(mlnew TStringList()),
410  baseValue(-1)
411{}
412
413
414
415TEnumVariable::TEnumVariable(const string &aname)
416: TVariable(aname, TValue::INTVAR, false),
417  values(mlnew TStringList()),
418  baseValue(-1)
419{}
420
421
422TEnumVariable::TEnumVariable(const string &aname, PStringList val)
423: TVariable(aname, TValue::INTVAR, false),
424  values(val),
425  baseValue(-1)
426{}
427
428
429TEnumVariable::TEnumVariable(const TEnumVariable &var)
430: TVariable(var),
431  values(mlnew TStringList(var.values.getReference())),
432  baseValue(var.baseValue)
433{}
434
435
436bool TEnumVariable::isEquivalentTo(const TVariable &old) const
437{
438  TEnumVariable const *eold = dynamic_cast<TEnumVariable const *>(&old);
439
440  if (!eold || !TVariable::isEquivalentTo(old) ||
441         ((baseValue != -1) && (eold->baseValue != -1) && (baseValue != eold->baseValue)))
442     return false;
443
444  TStringList::const_iterator vi1(values->begin()), ve1(values->end());
445  TStringList::const_iterator vi2(eold->values->begin()), ve2(eold->values->end());
446  for(; (vi1 != ve1) && (vi2 != ve2) && (*vi1 == *vi2); vi1++, vi2++);
447  return (vi1 == ve1) || (vi2 == ve2);
448}
449
450
451int  TEnumVariable::noOfValues() const
452{ return values->size(); };
453
454
455bool TEnumVariable::firstValue(TValue &val) const
456{ if (values->size()) {
457    val = TValue(0);
458    return true;
459  }
460  else {
461    val = TValue(DK());
462    return false;
463  }
464}
465
466
467
468bool TEnumVariable::nextValue(TValue &val) const
469{ return (++val.intV<int(values->size())); }
470
471
472
473TValue TEnumVariable::randomValue(const int &rand)
474{
475  if (!randomGenerator)
476    randomGenerator = mlnew TRandomGenerator;
477
478  if (!values->size())
479    raiseErrorWho("randomValue", "no values");
480
481  return TValue(int(rand<=0 ? randomGenerator->randint(values->size()) : rand%values->size()));
482}
483
484
485void TEnumVariable::addValue(const string &val)
486{
487  if (values->size() > 50) {
488    if (valuesTree.empty())
489      createValuesTree();
490
491    map<string, int>::iterator lb = valuesTree.lower_bound(val);
492    if ((lb == valuesTree.end()) || (lb->first != val)) {
493      // watch the order!
494      valuesTree.insert(lb, make_pair(val, values->size()));
495      values->push_back(val);
496    }
497  }
498
499  else {
500    if (!exists(values->begin(), values->end(), val))
501      values->push_back(val);
502
503    if ((values->size() == 5) && ((values->front() == "f") || (values->front() == "float"))) {
504      TStringList::const_iterator vi(values->begin()), ve(values->end());
505      char *eptr;
506      char numtest[32];
507      while(++vi != ve) { // skip the first (f/float)
508        if ((*vi).length() > 31)
509          break;
510
511        strcpy(numtest, (*vi).c_str());
512        for(eptr = numtest; *eptr; eptr++)
513          if (*eptr == ',')
514            *eptr = '.';
515
516        strtod(numtest, &eptr);
517        while (*eptr==32)
518          eptr++;
519
520        if (*eptr)
521          break;
522      }
523
524      if (vi==ve)
525        raiseWarning("is '%s' a continuous attribute unintentionally defined by '%s'?", get_name().c_str(), values->front().c_str());
526    }
527  }
528}
529
530
531bool TEnumVariable::hasValue(const string &s)
532{
533  if (!valuesTree.empty())
534    return valuesTree.lower_bound(s) != valuesTree.end();
535
536  PITERATE(TStringList, vli, values)
537    if (*vli == s)
538      return true;
539
540  return false;
541}
542
543
544/*  Converts a value from string representation to TValue by searching for it in value list.
545    If value is not found, it is added to the list if 'autoValues'==true, else exception is raised. */
546void TEnumVariable::str2val_add(const string &valname, TValue &valu)
547{
548  const int noValues = values->size();
549
550  if (noValues > 50) {
551    if (valuesTree.empty())
552      createValuesTree();
553
554    map<string, int>::iterator lb = valuesTree.lower_bound(valname);
555    if ((lb != valuesTree.end()) && (lb->first == valname))
556      valu = TValue(lb->second);
557    else if (!str2special(valname, valu)) {
558      valuesTree.insert(lb, make_pair(valname, noValues));
559      values->push_back(valname);
560      valu = TValue(noValues);
561    }
562  }
563
564  else {
565    TStringList::iterator vi = find(values->begin(), values->end(), valname);
566    if (vi!=values->end())
567      valu = TValue(int(vi - values->begin()));
568    else if (!str2special(valname, valu)) {
569      addValue(valname);
570      valu = TValue(noValues);
571    }
572  }
573}
574
575
576void TEnumVariable::str2val(const string &valname, TValue &valu)
577{
578  if (values->size() > 50) {
579    if (valuesTree.empty())
580      createValuesTree();
581
582    map<string, int>::const_iterator vi = valuesTree.find(valname);
583    if (vi != valuesTree.end())
584      valu = TValue(vi->second);
585    else if (!str2special(valname, valu))
586      raiseError("attribute '%s' does not have value '%s'", get_name().c_str(), valname.c_str());
587  }
588
589  else {
590    TStringList::const_iterator vi = find(values->begin(), values->end(), valname);
591    if (vi!=values->end())
592      valu = TValue(int(vi - values->begin()));
593    else if (!str2special(valname, valu))
594      raiseError("attribute '%s' does not have value '%s'", get_name().c_str(), valname.c_str());
595  }
596}
597
598
599
600bool TEnumVariable::str2val_try(const string &valname, TValue &valu)
601{
602  if (values->size() > 50) {
603    if (valuesTree.empty())
604      createValuesTree();
605
606    map<string, int>::const_iterator vi = valuesTree.find(valname);
607    if (vi != valuesTree.end()) {
608      valu = TValue(vi->second);
609      return true;
610    }
611    return str2special(valname, valu);
612  }
613
614  else {
615    TStringList::const_iterator vi = find(values->begin(), values->end(), valname);
616    if (vi!=values->end()) {
617      valu = TValue(int(vi - values->begin()));
618      return true;
619    }
620    return str2special(valname, valu);
621  }
622}
623
624
625
626// Converts TValue into a string representation of value. If invalid, string 'ERR' is returned.
627void TEnumVariable::val2str(const TValue &val, string &str) const
628{ if (val.isSpecial()) {
629    special2str(val, str);
630    return;
631  }
632
633  if (val.svalV) {
634    const TDiscDistribution *dval = dynamic_cast<const TDiscDistribution *>(val.svalV.getUnwrappedPtr());
635    if (!dval)
636      raiseError("invalid value type");
637
638    str = "(";
639    char buf[12];
640    const_PITERATE(TDiscDistribution, di, dval) {
641      if (di != dval->begin())
642        str+=", ";
643      sprintf(buf, "%1.3f", *di);
644      str += buf;
645    }
646    str += ")";
647  }
648
649  if (val.intV < values->size() && val.intV >= 0) {
650    str = values->operator[](val.intV);
651  } else {
652    str = "#RNGE";
653  }
654}
655
656
657void TEnumVariable::createValuesTree()
658{
659  int i = 0;
660  const_PITERATE(TStringList, vi, values)
661    valuesTree[*vi] = i++;
662}
663
664
665bool TEnumVariable::checkValuesOrder(const TStringList &refValues)
666{
667  for(TStringList::const_iterator ni(refValues.begin()), ne(refValues.end()), ei(values->begin()), ee(values->end());
668      (ei != ee) && (ni != ne); ei++, ni++)
669    if (*ei != *ni)
670      return false;
671  return true;
672}
673
674
675void TEnumVariable::presortValues(const set<string> &unsorted, vector<string> &sorted)
676{
677  sorted.clear();
678  sorted.insert(sorted.begin(), unsorted.begin(), unsorted.end());
679
680  vector<string>::iterator si, se(sorted.end());
681  const char ***ssi, **ssii, ***rssi;
682  for(ssi = specialSortCases, rssi = specialCasesResorted; *ssi; ssi++, rssi++) {
683    for(si = sorted.begin(), ssii = *ssi; *ssii && (si != se) && !stricmp(*ssii, si->c_str()); *ssii++);
684    if (!*ssii && (si==se)) {
685      sorted.clear();
686      sorted.insert(sorted.begin(), *rssi, *rssi + (ssii - *ssi));
687      return;
688    }
689  }
690
691  se = sorted.end();
692  for(ssii = putAtBeginning; *ssii; ssii++) {
693    for(si = sorted.begin(); (si != se) && stricmp(*ssii, si->c_str()); si++);
694    if (si != se) {
695      const string toMove = *si;
696      sorted.erase(si);
697      sorted.insert(sorted.begin(), toMove);
698      break;
699    }
700  }
701}
702
703
704TFloatVariable::TFloatVariable()
705: TVariable(TValue::FLOATVAR, true),
706  startValue(-1.0),
707  endValue(0.0),
708  stepValue(-1.0),
709  numberOfDecimals(3),
710  scientificFormat(false),
711  adjustDecimals(2)
712{}
713
714
715TFloatVariable::TFloatVariable(const string &aname)
716: TVariable(aname, TValue::FLOATVAR, true),
717  startValue(-1.0),
718  endValue(0.0),
719  stepValue(-1.0),
720  numberOfDecimals(3),
721  scientificFormat(false),
722  adjustDecimals(2)
723{}
724
725bool TFloatVariable::isEquivalentTo(const TVariable &old) const
726{
727  TFloatVariable const *eold = dynamic_cast<TFloatVariable const *>(&old);
728  return eold && TVariable::isEquivalentTo(old) &&
729         (startValue == eold->startValue) && (endValue == eold->endValue) && (stepValue == eold->stepValue);
730}
731
732
733bool TFloatVariable::firstValue(TValue &val) const
734{ if ((stepValue<=0) || (startValue<endValue))
735    return false;
736  val = TValue(startValue);
737  return true;
738}
739
740
741bool TFloatVariable::nextValue(TValue &val) const
742{ if (stepValue<=0)
743    return false;
744  return ((val.floatV+=stepValue)<=endValue);
745}
746
747
748TValue TFloatVariable::randomValue(const int &rand)
749{ if ((stepValue<=0) || (startValue>=endValue))
750    raiseError("randomValue: interval not given");
751
752  if (!randomGenerator)
753    randomGenerator = mlnew TRandomGenerator();
754
755  if (rand<0)
756    return TValue(randomGenerator->randfloat(startValue, endValue));
757  else
758    return TValue(float(double(rand)/double(4294967295.0)*(endValue-startValue)+startValue));
759}
760
761
762int  TFloatVariable::noOfValues() const
763{ return stepValue>0 ? int((endValue-startValue)/stepValue) : -1; }
764
765
766inline int getNumberOfDecimals(const char *vals, bool &hasE)
767{
768  const char *valsi;
769  for(valsi = vals; *valsi && ((*valsi<'0') || (*valsi>'9')) && (*valsi != '.'); valsi++);
770  if (!*valsi)
771    return -1;
772
773  if ((*valsi=='e') || (*valsi=='E')) {
774    hasE = true;
775    return 0;
776  }
777
778  for(; *valsi && (*valsi!='.'); valsi++);
779  if (!*valsi)
780    return 0;
781
782  int decimals = 0;
783  for(valsi++; *valsi && (*valsi>='0') && (*valsi<='9'); valsi++, decimals++);
784
785  hasE = hasE || (*valsi == 'e') || (*valsi == 'E');
786  return decimals;
787}
788
789
790int TFloatVariable::str2val_low(const string &valname, TValue &valu)
791{
792  if (str2special(valname, valu))
793    return 1;
794
795  const char *vals;
796  char *tmp = NULL;
797
798  const char radix = *localeconv()->decimal_point;
799  const char notGood = radix=='.' ? ',' : '.';
800  int cp = valname.find(notGood);
801  if (cp!=string::npos) {
802    vals = tmp = strcpy(new char[valname.size()+1], valname.c_str());
803    tmp[cp] = radix;
804  }
805  else
806    vals = valname.c_str();
807
808  float f;
809  int ssr = sscanf(vals, "%f", &f);
810
811  int res;
812
813  if (!ssr || (ssr==(char)EOF)) {
814    res = -1;
815  }
816  else {
817    valu = TValue(f);
818
819    if (((startValue<=endValue) && (stepValue>0) && ((f<startValue) || (f>endValue)))) {
820      res = -2;
821    }
822
823    else {
824      res = 1;
825
826      valu = TValue(f);
827
828      int decimals;
829      switch (adjustDecimals) {
830        case 2:
831          numberOfDecimals = getNumberOfDecimals(vals, scientificFormat);
832          adjustDecimals = 1;
833          break;
834        case 1:
835          decimals = getNumberOfDecimals(vals, scientificFormat);
836          if (decimals > numberOfDecimals)
837            numberOfDecimals = decimals;
838      }
839    }
840  }
841
842  if (tmp)
843    delete tmp;
844
845  return res;
846}
847
848
849void TFloatVariable::str2val(const string &valname, TValue &valu)
850{
851  switch (str2val_low(valname, valu)) {
852    case -1: raiseError("'%s' is not a legal value for continuous attribute '%s'", valname.c_str(), get_name().c_str());
853    case -2: raiseError("value %5.3f out of range %5.3f-%5.3f", valu.floatV, startValue, endValue);
854  }
855}
856
857bool TFloatVariable::str2val_try(const string &valname, TValue &valu)
858{
859  return str2val_low(valname, valu) == 1;
860}
861
862
863void TFloatVariable::val2str(const TValue &valu, string &vname) const
864{ if (valu.isSpecial())
865    special2str(valu, vname);
866  else {
867    char buf[64];
868    const float f = fabs(valu.floatV);
869    if (scientificFormat)
870      sprintf(buf, "%g", valu.floatV);
871    else
872      sprintf(buf, "%.*f", numberOfDecimals, valu.floatV);
873    vname = buf;
874  }
875}
876
Note: See TracBrowser for help on using the repository browser.