source: trunk/src/core/RpUnits.cc @ 591

Last change on this file since 591 was 568, checked in by dkearney, 18 years ago

reworking of the Rappture Units code.
Rappture Units no longer creates an object for each metric extension of every
metric unit. Now the metric prefixes are kept in the dictionary as unit objects,
and when a unit is parsed out of the string received from the user, the unit
is checked to see if it acccepts metric prefixes, if so, a search is done for
the prefix. This allows Rappture Units code to more easily tackle case insensitive
unit name searches. Eventually the prefixes will be removed as direct Rappture Units objects and be turned into (possibly a derived object) rappture units prefix objects.

The find function of the core Rappture Units code now accepts
a "hints" function pointer. The function pointer is executed by the dictionary when
the dictionary thinks it found a matching object. This allows the user of the
dictionary to insert different objects with the same key. For Rappture Units,
multiple units objects with the same key can be inserted into the dictionary.
This is important for units like "A" which could stand for angstroms or amperes.

Additionally, the "make metric" functions were removed because the idea of being a
metric unit has been reduced to a flag inside the Rappture Units object and some
newly added logic. The role of setting the metric flag has been added to the define()
function as an additional function input. The fortran and c code has been updated to
reflect the removal of the function. No updates were made to the define function in
the fortran and c code.

The units.test file was also updated with new tests. Old tests were updated, removing
derived units from the list of compatible units. When searching for micro-meters (um),
compatible units of (A,in,m) will be provided instead of (A,in,m,um).

File size: 88.1 KB
Line 
1/*
2 * ----------------------------------------------------------------------
3 *  RpUnits.cc
4 *
5 *   Data Members and member functions for the RpUnits class
6 *
7 * ======================================================================
8 *  AUTHOR:  Derrick Kearney, Purdue University
9 *  Copyright (c) 2004-2007  Purdue Research Foundation
10 *
11 *  See the file "license.terms" for information on usage and
12 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13 * ======================================================================
14 */
15
16#include "RpUnits.h"
17
18// dict pointer
19// set the dictionary to be case insensitive for seaches and storage
20RpDict<std::string,RpUnits*,RpUnits::_key_compare>* RpUnits::dict =
21    new RpDict<std::string,RpUnits*,RpUnits::_key_compare>(
22        RPUNITS_CASE_INSENSITIVE);
23
24// install predefined units
25static RpUnitsPreset loader;
26
27/**********************************************************************/
28// METHOD: define()
29/// Define a unit type to be stored as a Rappture Unit.
30/**
31 */
32
33RpUnits *
34RpUnits::define(    const std::string units,
35                    const RpUnits* basis,
36                    const std::string type,
37                    bool metric,
38                    bool caseInsensitive    ) {
39
40    RpUnits* newRpUnit = NULL;
41
42    std::string searchStr = units;
43    std::string sendStr = "";
44    int len = searchStr.length();
45    int idx = len-1;
46    double exponent = 1;
47
48    RpUnitsTypes::RpUnitsTypesHint hint = NULL;
49
50    if (units.empty()) {
51        // raise error, user sent null units!
52        return NULL;
53    }
54
55    // check to see if the user is trying to trick me!
56    if ( (basis) && (units == basis->getUnits()) ) {
57        // dont trick me!
58        return NULL;
59    }
60
61    // check to see if the said unit can already be found in the dictionary
62    hint = RpUnitsTypes::getTypeHint(type);
63    if (RpUnits::find(units,hint)) {
64        return NULL;
65    }
66
67    //default exponent
68    exponent = 1;
69
70    // check to see if there is an exponent at the end
71    // of the search string
72    idx = RpUnits::grabExponent(searchStr, &exponent);
73    searchStr.erase(idx);
74
75    // move idx pointer back to where last character was found
76    idx--;
77
78    if ( searchStr[0] == '/') {
79        // need to negate all of the previous exponents
80        exponent = -1*exponent;
81        sendStr = searchStr.c_str()+1;
82    }
83    else {
84        // sendStr = searchStr.substr(idx+1,);
85        // we have a unit string to parse
86        sendStr = searchStr;
87    }
88
89    newRpUnit = new RpUnits(    sendStr,
90                                exponent,
91                                basis,
92                                type,
93                                metric,
94                                caseInsensitive );
95    if (newRpUnit) {
96        insert(newRpUnit->getUnitsName(),newRpUnit);
97    }
98
99    // return a copy of the new object to user
100    return newRpUnit;
101}
102
103/**********************************************************************/
104// METHOD: incarnate()
105/// Link two RpUnits where the entity is an incarnate of the abstraction
106/**
107 */
108
109int
110RpUnits::incarnate(const RpUnits* abstraction, const RpUnits* entity) {
111
112    int retVal = 1;
113
114    abstraction->connectIncarnation(entity);
115    entity->connectIncarnation(abstraction);
116
117    retVal = 0;
118    return retVal;
119}
120
121/**********************************************************************/
122// METHOD: grabExponent()
123/// Return exponent from a units string containing a unit name and exponent
124/**
125 */
126
127int
128RpUnits::grabExponent(const std::string& inStr, double* exp) {
129
130    int len = inStr.length();
131    int idx = len - 1;
132
133    *exp = 1;
134
135    while (isdigit(inStr[idx])) {
136        idx--;
137    }
138
139    if ( (inStr[idx] == '+') || (inStr[idx] == '-') ) {
140        idx--;
141    }
142
143    idx++;
144
145    if (idx != len) {
146        // process the exponent.
147        *exp = strtod(inStr.c_str()+idx,NULL);
148    }
149
150    return idx;
151}
152
153/**********************************************************************/
154// METHOD: grabUnitString()
155/// Return units name from a units string containing a unit name and exponent
156/**
157 * this function will be the cause of problems related to adding symbols like %
158 */
159
160int
161RpUnits::grabUnitString ( const std::string& inStr ) {
162
163    int idx = inStr.length() - 1;
164
165    while ((idx >= 0) && isalpha(inStr[idx])) {
166        idx--;
167    }
168
169    // move the index forward one position to
170    // represent the start of the unit string
171    idx++;
172
173    return idx;
174}
175
176/**********************************************************************/
177// METHOD: grabUnits()
178/// Search for the provided units exponent pair in the dictionary.
179/**
180 */
181
182int
183RpUnits::grabUnits (    std::string inStr,
184                        int* offset,
185                        const RpUnits** unit,
186                        const RpUnits** prefix   ) {
187
188    int len = inStr.length();
189    std::string preStr = "";
190
191    if ( (unit == NULL) || (prefix == NULL) ) {
192        // incorrect function call, return error
193        return -1;
194    }
195
196    *unit = NULL;
197    *prefix = NULL;
198
199    while ( ! inStr.empty() ) {
200        *unit = RpUnits::find(inStr,&RpUnitsTypes::hintTypeNonPrefix);
201        if (*unit) {
202            *offset = len - inStr.length();
203
204            if ((*unit)->metric) {
205                RpUnits::checkMetricPrefix(preStr,offset,prefix);
206            }
207
208            break;
209        }
210        preStr = preStr + inStr.substr(0,1);
211        inStr.erase(0,1);
212    }
213
214    return 0;
215}
216
217/**********************************************************************/
218// METHOD: checkMetrixPrefix()
219/// Compare a string with available metric prefixes
220/**
221 * The metric prefix only has one or two letters before the main unit.
222 * We take in the string of characters before the found unit and search
223 * for the two characters closest to the found unit. If those two
224 * characters are not found in the dictionary as a prefix, then we erase
225 * the 0th character, and search for the 1th character. The 1th character
226 * is the character closest to the found unit. If it is found as a prefix
227 * in the dictionary, it is returned. If no prefix is found, NULL is
228 * returned.
229 */
230
231int
232RpUnits::checkMetricPrefix  (   std::string inStr,
233                                int* offset,
234                                const RpUnits** prefix   ) {
235
236    int inStrLen = 0;
237    std::string searchStr = "";
238
239    inStrLen = inStr.length();
240
241    if (inStrLen == 0) {
242        // no prefix to search for, exit
243        return 0;
244    }
245
246    if (prefix == NULL) {
247        // incorrect function call, return error
248        return -1;
249    }
250
251
252    if (inStrLen > 2) {
253        searchStr = inStr.substr( inStrLen-2 );
254    }
255    else {
256        searchStr = inStr;
257    }
258
259    *prefix = NULL;
260
261    *prefix = RpUnits::find(searchStr,&RpUnitsTypes::hintTypePrefix);
262    if ( (*prefix) == NULL ) {
263        // the two letter prefix was not found,
264        // try the one letter prefix
265        searchStr.erase(0,1);
266        *prefix = RpUnits::find(searchStr,&RpUnitsTypes::hintTypePrefix);
267    }
268
269    if (*prefix != NULL) {
270        // if a prefix was found, adjust the offset to reflect
271        // the need to erase the prefix as well as the unit name
272        *offset = *offset - searchStr.length();
273    }
274
275    return 0;
276}
277
278/**********************************************************************/
279// METHOD: getType()
280/// Return the type of an RpUnits object.
281/**
282 */
283std::string
284RpUnits::getType() const {
285    return this->type;
286}
287
288/**********************************************************************/
289// METHOD: getCI()
290/// Return the case insensitivity of an RpUnits object.
291/**
292 */
293bool
294RpUnits::getCI() const {
295    return this->ci;
296}
297
298/**********************************************************************/
299// METHOD: getCompatible()
300/// Return a list of units compatible with this RpUnits object.
301/**
302 */
303std::list<std::string>
304RpUnits::getCompatible(double expMultiplier) const {
305
306    std::list<std::string> compatList;
307    std::list<std::string> basisCompatList;
308    std::list<std::string> incarnationCompatList;
309    std::stringstream myName;
310    std::stringstream otherName;
311    std::string otherBasisName  = "";
312    std::string blank           = "";
313    double otherExp             = 1.0;
314    double myExp                = 1.0;
315    double incExp               = 1.0;
316    convEntry* myConversions    = this->convList;
317    incarnationEntry* myIncarnations = this->incarnationList;
318    const RpUnits * basis       = NULL;
319
320    myName.str("");
321    myName << getUnits();
322    myExp = getExponent() * expMultiplier;
323
324    if (this->basis) {
325        basisCompatList = this->basis->getCompatible(expMultiplier);
326        compatList.merge(basisCompatList);
327    }
328    else {
329        // only basis units should be in here
330        //
331        // run through the conversion list
332        // for each entry, look at the name
333        // if the name is not equal to the name of this RpUnits object,
334        // store the fromPtr->getUnitsName() into compatList
335        // else store the toPtr->getUnitsName() into compatList
336        //
337        while (myConversions != NULL) {
338
339            otherName.str("");
340            // otherName << myConversions->conv->toPtr->getUnitsName();
341            otherName << myConversions->conv->toPtr->getUnits();
342            otherExp = myConversions->conv->toPtr->getExponent();
343            basis = myConversions->conv->toPtr->basis;
344
345            if (myName.str() == otherName.str()) {
346                otherName.str("");
347                // otherName << myConversions->conv->fromPtr->getUnitsName();
348                otherName << myConversions->conv->fromPtr->getUnits();
349                otherExp = myConversions->conv->fromPtr->getExponent();
350                basis = myConversions->conv->fromPtr->basis;
351            }
352
353            // check to see if they are the same basis,
354            // no need to list all of the metric conversions.
355            if (basis) {
356                if (basis->getUnitsName() == myName.str()) {
357                    // do not add this unit to the conversion
358                    // because its a derived unit.
359                    myConversions = myConversions->next;
360                    continue;
361                }
362            }
363
364            // adjust the exponent as requested by fxn caller
365            otherExp = otherExp * expMultiplier;
366
367            // adjust the other units name to match exponent
368            if ( (otherExp > 0) && (otherExp != 1) ) {
369                otherName << otherExp;
370            }
371            else if (otherExp < 0) {
372                otherName.str("/"+otherName.str());
373                if (otherExp < -1) {
374                    otherName.seekp(0,std::ios_base::end);
375                    otherName << otherExp*-1;
376                }
377            }
378
379            // add the other unit's name to the list of compatible units
380            compatList.push_back(otherName.str());
381            // compatList.push_back(otherName);
382
383            // advance to the next conversion
384            myConversions = myConversions->next;
385        }
386
387        // now go throught the incarnation list to see if there are other
388        // compatible units listed there.
389        while (myIncarnations != NULL) {
390            incExp = myIncarnations->unit->getExponent();
391            if (incExp == myExp) {
392                incarnationCompatList = myIncarnations->unit->getCompatible();
393                compatList.merge(incarnationCompatList);
394                break;
395            }
396            else if ((-1.0*incExp) == myExp) {
397                incarnationCompatList = myIncarnations->unit->getCompatible(-1);
398                compatList.merge(incarnationCompatList);
399                break;
400            }
401            else if (   (myExp == int(myExp))   &&
402                        (incExp == int(incExp)) &&
403                        ( (int(myExp)%int(incExp)) == 0) &&
404                        ( (myExp/incExp) != 1)  &&
405                        ( (myExp/incExp) != -1) &&
406                        ( myExp != 1 )          &&
407                        ( myExp != -1 )         &&
408                        ( incExp != 1 )         &&
409                        ( incExp != -1 )        ) {
410                incarnationCompatList = myIncarnations->unit->getCompatible(myExp/incExp);
411                compatList.merge(incarnationCompatList);
412                break;
413            }
414            else {
415                // do nothing
416            }
417            myIncarnations = myIncarnations->next;
418        }
419    }
420
421    // adjust the exponent as requested by fxn caller
422    // myExp = myExp * expMultiplier;
423
424    // adjust the other units name to match exponent
425    if ( (expMultiplier > 0) && (expMultiplier != 1) ) {
426        // myName << expMultiplier;
427        myName << myExp;
428    }
429    else if (expMultiplier < 0) {
430        myName.str("/"+myName.str());
431        if (myExp < -1) {
432            myName.seekp(0,std::ios_base::end);
433            myName << myExp*-1;
434        }
435    }
436
437    compatList.push_back(myName.str());
438    compatList.sort();
439    compatList.unique();
440    return compatList;
441
442}
443
444
445
446
447/**********************************************************************/
448// METHOD: define()
449/// Define a unit conversion with one arg double function pointers.
450/**
451 */
452
453RpUnits *
454RpUnits::define(  const RpUnits* from,
455                  const RpUnits* to,
456                  double (*convForwFxnPtr)(double),
457                  double (*convBackFxnPtr)(double)  ) {
458
459    // this is kinda the wrong way to get the job done...
460    // how do we only create 1 conversion object and share it between atleast two RpUnits
461    // objs so that when the RpUnits objs are deleted, we are not trying to delete already
462    // deleted memory.
463    // so for the sake of safety we get the following few lines of code.
464
465    conversion* conv1 = NULL;
466    conversion* conv2 = NULL;
467
468    if (from && to) {
469
470        conv1 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
471        conv2 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
472
473        from->connectConversion(conv1);
474        to->connectConversion(conv2);
475    }
476
477    return NULL;
478}
479
480/**********************************************************************/
481// METHOD: define()
482/// Define a unit conversion with two arg double function pointers.
483/**
484 */
485
486RpUnits *
487RpUnits::define(  const RpUnits* from,
488                  const RpUnits* to,
489                  double (*convForwFxnPtr)(double,double),
490                  double (*convBackFxnPtr)(double,double)) {
491
492    // this is kinda the wrong way to get the job done...
493    // how do we only create 1 conversion object and share it between
494    // atleast two RpUnits objs so that when the RpUnits objs are
495    // deleted, we are not trying to delete already deleted memory.
496    // so for the sake of safety we get the following few lines of code.
497
498    conversion* conv1 = NULL;
499    conversion* conv2 = NULL;
500
501    if (from && to) {
502        conv1 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
503        conv2 = new conversion (from,to,convForwFxnPtr,convBackFxnPtr);
504
505        from->connectConversion(conv1);
506        to->connectConversion(conv2);
507    }
508
509    return NULL;
510}
511
512/**********************************************************************/
513// METHOD: define()
514/// Define a unit conversion with two arg void* function pointers.
515/**
516 */
517
518RpUnits *
519RpUnits::define(  const RpUnits* from,
520                  const RpUnits* to,
521                  void* (*convForwFxnPtr)(void*, void*),
522                  void* convForwData,
523                  void* (*convBackFxnPtr)(void*, void*),
524                  void* convBackData) {
525
526    // this is kinda the wrong way to get the job done...
527    // how do we only create 1 conversion object and share it between at
528    // least two RpUnits objs so that when the RpUnits objs are deleted,
529    // we are not trying to delete already deleted memory.
530    // so for the sake of safety we get the following few lines of code.
531
532    conversion* conv1 = NULL;
533    conversion* conv2 = NULL;
534
535    if (from && to) {
536        conv1 = new conversion ( from, to, convForwFxnPtr,convForwData,
537                                 convBackFxnPtr,convBackData);
538        conv2 = new conversion ( from,to,convForwFxnPtr,convForwData,
539                                 convBackFxnPtr,convBackData);
540
541        from->connectConversion(conv1);
542        to->connectConversion(conv2);
543    }
544
545    return NULL;
546}
547
548
549/**********************************************************************/
550// METHOD: getUnits()
551/// Report the text portion of the units of this object back to caller.
552/**
553 * \sa {getUnitsName}
554 */
555
556std::string
557RpUnits::getUnits() const {
558
559    return units;
560}
561
562/**********************************************************************/
563// METHOD: getUnitsName()
564/// Report the full name of the units of this object back to caller.
565/**
566 * Reports the full text and exponent of the units represented by this
567 * object, back to the caller. Note that if the exponent == 1, no
568 * exponent will be printed.
569 */
570
571std::string
572RpUnits::getUnitsName(int flags) const {
573
574    std::stringstream unitText;
575    double exponent;
576
577    exponent = getExponent();
578
579    if ( (RPUNITS_ORIG_EXP & flags) == RPUNITS_POS_EXP)  {
580        if (exponent < 0) {
581            exponent = exponent * -1;
582        }
583    }
584    else if ( (RPUNITS_ORIG_EXP & flags) == RPUNITS_NEG_EXP)  {
585        if (exponent > 0) {
586            exponent = exponent * -1;
587        }
588    }
589
590    if (exponent == 1) {
591        unitText << units;
592    }
593    else {
594        unitText << units << exponent;
595    }
596
597    return (std::string(unitText.str()));
598}
599
600/**********************************************************************/
601// METHOD: getSearchName()
602/// Report the units name used when searching through the units dictionary.
603/**
604 * Reports the search name used to store and retrieve this object from
605 * the units dictionary.
606 */
607
608std::string
609RpUnits::getSearchName() const {
610
611    std::string searchName = getUnitsName();
612
613    std::transform( searchName.begin(),
614                    searchName.end(),
615                    searchName.begin(),
616                    tolower );
617
618    return (searchName);
619}
620
621/**********************************************************************/
622// METHOD: getExponent()
623/// Report the exponent of the units of this object back to caller.
624/**
625 * Reports the exponent of the units represented by this
626 * object, back to the caller. Note that if the exponent == 1, no
627 * exponent will be printed.
628 */
629
630double
631RpUnits::getExponent() const {
632
633    return exponent;
634}
635
636/**********************************************************************/
637// METHOD: getBasis()
638/// Retrieve the RpUnits object representing the basis of this object.
639/**
640 * Returns a pointer to a RpUnits object which, on success, points to the
641 * RpUnits object that is the basis of the calling object.
642 */
643
644const RpUnits *
645RpUnits::getBasis() const {
646
647    return basis;
648}
649
650/**********************************************************************/
651// METHOD: setMetric()
652/// Set the metric flag of the object.
653/**
654 * Set the metric flag of the object
655 */
656
657RpUnits&
658RpUnits::setMetric(bool newVal) {
659
660    metric = newVal;
661    return *this;
662}
663
664/**********************************************************************/
665// METHOD: makeBasis()
666/// Convert a value into its RpUnits's basis.
667/**
668 *  convert the current unit to its basis units
669 *
670 *  Return Codes
671 *      0) no error (could also mean or no prefix was found)
672 *          in some cases, this means the value is in its basis format
673 *      1) the prefix found does not have a built in factor associated.
674 *
675 */
676
677double
678RpUnits::makeBasis(double value, int* result) const {
679
680    double retVal = value;
681
682    if (result) {
683        *result = 0;
684    }
685
686    if (basis == NULL) {
687        // this unit is a basis
688        // do nothing
689    }
690    else {
691        retVal = convert(basis,value,result);
692    }
693
694    return retVal;
695}
696
697/**********************************************************************/
698// METHOD: makeBasis()
699/// Convert a value into its RpUnits's basis.
700/**
701 *
702 */
703
704const RpUnits&
705RpUnits::makeBasis(double* value, int* result) const {
706    double retVal = *value;
707    int convResult = 1;
708
709    if (basis == NULL) {
710        // this unit is a basis
711        // do nothing
712    }
713    else {
714        retVal = convert(basis,retVal,&convResult);
715    }
716
717    if ( (convResult == 0) ) {
718        *value = retVal;
719    }
720
721    if (result) {
722        *result = convResult;
723    }
724
725    return *this;
726}
727
728/**********************************************************************/
729// METHOD: makeMetric()
730/// Define a unit type to be stored as a Rappture Unit.
731/**
732 *  static int makeMetric(RpUnits * basis);
733 *  create the metric attachments for the given basis.
734 *  should only be used if this unit is of metric type
735 */
736
737/*
738int
739RpUnits::makeMetric(RpUnits* basis) {
740
741    if (!basis) {
742        return 0;
743    }
744
745    basis->setMetric(true);
746
747    return 0;
748}
749*/
750
751/**********************************************************************/
752// METHOD: find()
753/// Find a simple RpUnits Object from the provided string.
754/**
755 */
756
757const RpUnits*
758RpUnits::find(std::string key,
759        RpDict<std::string,RpUnits*,_key_compare>::RpDictHint hint ) {
760
761    RpDictEntry<std::string,RpUnits*,_key_compare>*
762        unitEntry = &(dict->getNullEntry());
763    RpDictEntry<std::string,RpUnits*,_key_compare>*
764        nullEntry = &(dict->getNullEntry());
765    double exponent = 1;
766    int idx = 0;
767    std::stringstream tmpKey;
768
769    if (key[0] == '/') {
770        // check to see if there is an exponent at the end
771        // of the search string
772        idx = RpUnits::grabExponent(key, &exponent);
773        tmpKey << key.substr(1,idx-1) << (-1*exponent);
774        key = tmpKey.str();
775    }
776
777    if (unitEntry == nullEntry) {
778        // pass 1 - look for the unit name as it was stated by the user
779        // dict->toggleCI();
780        unitEntry = &(dict->find(key,hint,!RPUNITS_CASE_INSENSITIVE));
781        // dict->toggleCI();
782    }
783
784    if (unitEntry == nullEntry) {
785        // pass 2 - use case insensitivity to look for the unit
786        unitEntry = &(dict->find(key,hint,RPUNITS_CASE_INSENSITIVE));
787    }
788
789    if ( (!unitEntry->isValid()) || (unitEntry == nullEntry) ) {
790        // unitEntry = NULL;
791        return NULL;
792    }
793
794    return *(unitEntry->getValue());
795}
796
797/**********************************************************************/
798// METHOD: validate()
799/// Split a string of units and check that each unit is available as an object
800/**
801 * Splits a string of units like cm2/kVns into a list of units like
802 * cm2, kV1, ns1 where an exponent is provided for each list entry.
803 * It checks to see that each unit actually exists as a valid defined unit.
804 * If the unit exists or can be interpreted, the function keeps parsing the
805 * string until it reaches the end of the string. If the function comes
806 * across a unit that is unrecognized or can not be interpreted, then it
807 * returns error (a non-zero value).
808 *
809 * if &compatList == NULL, no compatible list of units will be generated.
810 * this function does not do a good job of placing the available units
811 * back into the original formula. i still need to work on this.
812 */
813
814int
815RpUnits::validate ( std::string& inUnits,
816                    std::string& type,
817                    std::list<std::string>* compatList ) {
818
819    std::string sendUnitStr = "";
820    double exponent         = 1;
821    int err                 = 0;
822    const RpUnits* unit     = NULL;
823    std::list<std::string> basisCompatList;
824    std::list<std::string>::iterator compatListIter;
825    std::stringstream unitWExp;
826    RpUnitsList inUnitsList;
827    RpUnitsListIter inIter;
828
829    // err tells us if we encountered any unrecognized units
830    err = RpUnits::units2list(inUnits,inUnitsList,type);
831    RpUnits::list2units(inUnitsList,inUnits);
832    inIter = inUnitsList.begin();
833
834    while ( inIter != inUnitsList.end() ) {
835
836        unit = inIter->getUnitsObj();
837        exponent = inIter->getExponent();
838
839        // merge the compatible units
840        if (compatList) {
841
842            basisCompatList = unit->getCompatible(exponent);
843            compatList->merge(basisCompatList);
844        }
845
846        inIter++;
847    }
848
849    // clean out any duplicate entries.
850    if (compatList) {
851        compatList->unique();
852    }
853
854    return err;
855}
856
857
858/**********************************************************************/
859// METHOD: negateListExponents()
860/// Negate the exponents on every element in unitsList
861/**
862 */
863
864int
865RpUnits::negateListExponents(RpUnitsList& unitsList) {
866    RpUnitsListIter iter = unitsList.begin();
867    int nodeCnt = unitsList.size();
868
869    if (nodeCnt > 0) {
870        for (; iter != unitsList.end(); iter++) {
871            iter->negateExponent();
872            nodeCnt--;
873        }
874    }
875
876    return nodeCnt;
877}
878
879/**********************************************************************/
880// METHOD: negateExponent()
881/// Negate the exponent on the current RpUnitsListEntry
882/**
883 */
884
885void
886RpUnitsListEntry::negateExponent() const {
887    exponent = exponent * -1;
888    return;
889}
890
891/**********************************************************************/
892// METHOD: name()
893/// Provide the caller with the name of this object
894/**
895 */
896
897std::string
898RpUnitsListEntry::name(int flags) const {
899    std::stringstream name;
900    double myExp = exponent;
901
902    if ( (RPUNITS_ORIG_EXP & flags) == RPUNITS_POS_EXP)  {
903        if (myExp < 0) {
904            myExp = myExp * -1;
905        }
906    }
907    else if ( (RPUNITS_ORIG_EXP & flags) == RPUNITS_NEG_EXP)  {
908        if (myExp > 0) {
909            myExp = myExp * -1;
910        }
911    }
912
913    if (prefix != NULL) {
914        name << prefix->getUnits();
915    }
916
917    name << unit->getUnits();
918
919    if ((RPUNITS_ORIG_EXP & flags) == RPUNITS_STRICT_NAME) {
920        // if the user asks for strict naming,
921        // always place the exponent on the name
922        name << myExp;
923    }
924    else if (myExp != 1.0) {
925        // if the user does not ask for strict naming,
926        // check to see if the exponent == 1.
927        // If not, then add exponent to name
928        name << myExp;
929    }
930
931    return std::string(name.str());
932}
933
934/**********************************************************************/
935// METHOD: getBasis()
936/// Provide the caller with the basis of the RpUnits object being stored
937/**
938 */
939
940const RpUnits*
941RpUnitsListEntry::getBasis() const {
942    return unit->getBasis();
943}
944
945/**********************************************************************/
946// METHOD: getUnitsObj()
947/// Return the RpUnits Object from a RpUnitsListEntry.
948/**
949 */
950
951const RpUnits*
952RpUnitsListEntry::getUnitsObj() const {
953    return unit;
954}
955
956/**********************************************************************/
957// METHOD: getExponent()
958/// Return the exponent of an RpUnitsListEntry.
959/**
960 */
961
962double
963RpUnitsListEntry::getExponent() const {
964    return exponent;
965}
966
967/**********************************************************************/
968// METHOD: getPrefix()
969/// Return the prefix of an RpUnitsListEntry.
970/**
971 */
972
973const RpUnits*
974RpUnitsListEntry::getPrefix() const {
975    return prefix;
976}
977
978/**********************************************************************/
979// METHOD: printList()
980/// Traverse a RpUnitsList and print out the name of each element.
981/**
982 */
983
984int
985RpUnits::printList(RpUnitsList& unitsList) {
986    RpUnitsListIter iter = unitsList.begin();
987    int nodeCnt = unitsList.size();
988
989    if (nodeCnt > 0) {
990        for (; iter != unitsList.end(); iter++) {
991            std::cout << iter->name() << " ";
992            nodeCnt--;
993        }
994        std::cout << std::endl;
995    }
996
997    return nodeCnt;
998}
999
1000/**********************************************************************/
1001// METHOD: units2list()
1002/// Split a string of units into a list of units with exponents and prefixes.
1003/**
1004 * Splits a string of units like cm2/kVns into a list of units like
1005 * cm2, kV-1, ns-1 where an exponent is provided for each list entry.
1006 * List entries are found by comparing units strings to the names
1007 * in the dictionary.
1008 */
1009
1010int
1011RpUnits::units2list ( const std::string& inUnits,
1012                      RpUnitsList& outList,
1013                      std::string& type ) {
1014
1015    std::string myInUnits   = inUnits;
1016    std::stringstream sendUnitStr;
1017    double exponent         = 1;
1018    int offset              = 0;
1019    int idx                 = 0;
1020    int last                = 0;
1021    int err                 = 0;
1022    const RpUnits* unit     = NULL;
1023    const RpUnits* prefix   = NULL;
1024
1025
1026    while ( !myInUnits.empty() ) {
1027
1028        // check to see if we came across a '/' character
1029        last = myInUnits.length()-1;
1030        if (myInUnits[last] == '/') {
1031            type = myInUnits[last] + type;
1032            myInUnits.erase(last);
1033            // multiply previous exponents by -1
1034            if ( ! outList.empty() ) {
1035                RpUnits::negateListExponents(outList);
1036            }
1037            continue;
1038        }
1039
1040        // check to see if we came across a '*' character
1041        if (myInUnits[last] == '*') {
1042            // type = myInUnits[last] + type;
1043            // ignore * because we assume everything is multiplied together
1044            myInUnits.erase(last);
1045            continue;
1046        }
1047
1048        // get the exponent
1049        offset = RpUnits::grabExponent(myInUnits,&exponent);
1050        myInUnits.erase(offset);
1051        idx = offset - 1;
1052        last = myInUnits.length()-1;
1053        if (last == -1) {
1054            // the string is empty, units were not correctly entered
1055            err = 1;
1056            break;
1057        }
1058
1059        // grab the largest string we can find
1060        offset = RpUnits::grabUnitString(myInUnits);
1061
1062        // if offset > length, then the grabUnitString went through the whole
1063        // string and did not find a good string we could use as units.
1064        // this generally means the string was filled with non alphabetical
1065        // symbols like *&^%$#@!)(~`{}[]:;"'?/><,.-_=+\ or |
1066
1067        if (offset > last) {
1068            err = 1;
1069            // erase the last offending character
1070            myInUnits.erase(last);
1071            // reset our vars and try again
1072            idx = 0;
1073            offset = 0;
1074            exponent = 1;
1075            continue;
1076        }
1077        else {
1078            idx = offset;
1079        }
1080
1081        // figure out if we have some defined units in that string
1082        sendUnitStr.str(myInUnits.substr(offset,std::string::npos));
1083        grabUnits(sendUnitStr.str(),&offset,&unit,&prefix);
1084        if (unit) {
1085            // a unit was found
1086            // add this unit to the list
1087            // erase the found unit's name from our search string
1088            outList.push_front(RpUnitsListEntry(unit,exponent,prefix));
1089            if (type.compare("") == 0) {
1090                type = unit->getType();
1091            }
1092            else if (type[0] == '/') {
1093                type = unit->getType() + type;
1094            }
1095            else {
1096                type = unit->getType() + "*" + type;
1097            }
1098            myInUnits.erase(idx+offset);
1099        }
1100        else {
1101            // we came across a unit we did not recognize
1102            // raise error and delete character for now
1103            err = 1;
1104            myInUnits.erase(idx);
1105        }
1106
1107        /*
1108        // if the exponent != 1,-1 then do a second search
1109        // for the unit+exponent string that might be defined.
1110        // this is to cover the case were we have defined conversions
1111        // m3<->gal, m3<->L but m is defined
1112        if ( (exponent != 1) && (exponent != -1) ) {
1113            sendUnitStr.str("");
1114            sendUnitStr << unit->getUnits() << exponent;
1115            unit = grabUnits(sendUnitStr.str(),&offset);
1116            if (unit) {
1117                // a unit was found
1118                // add this unit to the list
1119                outList.push_front(RpUnitsListEntry(unit,1.0));
1120            }
1121            else {
1122                // we came across a unit we did not recognize
1123                // do nothing
1124            }
1125        }
1126        */
1127
1128        // reset our vars
1129        idx = 0;
1130        offset = 0;
1131        exponent = 1;
1132    }
1133
1134    return err;
1135}
1136
1137/**********************************************************************/
1138// METHOD: list2units()
1139/// Join a list of units into a string with proper exponents.
1140/**
1141 * Joins a list of units like cm2, kV-1, ns-1, creating a string
1142 * like cm2/kVns.
1143 */
1144
1145int
1146RpUnits::list2units ( RpUnitsList& inList,
1147                      std::string& outUnitsStr) {
1148
1149    RpUnitsListIter inListIter;
1150    std::string inUnits     = "";
1151    double exp              = 0;
1152    int err                 = 0;
1153    std::string numerator   = "";
1154    std::string denominator = "";
1155
1156    inListIter = inList.begin();
1157
1158    while (inListIter != inList.end()) {
1159        exp = inListIter->getExponent();
1160        if (exp > 0) {
1161            numerator += inListIter->name();
1162        }
1163        else if (exp < 0) {
1164            denominator += inListIter->name(RPUNITS_POS_EXP);
1165        }
1166        else {
1167            // we shouldn't get units with exponents of zero
1168        }
1169        inListIter++;
1170    }
1171
1172    outUnitsStr = numerator;
1173    if ( denominator.compare("") != 0 ) {
1174        outUnitsStr += "/" + denominator;
1175    }
1176
1177    return err;
1178}
1179
1180/**********************************************************************/
1181// METHOD: compareListEntryBasis()
1182/// Compare two RpUnits objects to see if they are related by a basis
1183/**
1184 * One step in converting between Rappture Units Objects is to check
1185 * to see if the conversion is an intra-basis conversion. Intra-basis
1186 * conversions include those where all conversions are done within
1187 * the same basis.
1188 *
1189 * Examples of intra-basis conversions include:
1190 *     m -> cm  ( meters to centimeters )
1191 *     cm -> m  ( centimeters to meters )
1192 *     cm -> nm ( centimenters to nanometers )
1193 */
1194
1195int RpUnits::compareListEntryBasis ( RpUnitsList& fromList,
1196                                     RpUnitsListIter& fromIter,
1197                                     RpUnitsListIter& toIter ) {
1198
1199    const RpUnits* toBasis = NULL;
1200    const RpUnits* fromBasis = NULL;
1201    int retVal = 1;
1202    double fromExp = 0;
1203    double toExp = 0;
1204
1205    fromIter = fromList.begin();
1206
1207    // get the basis of the object being stored
1208    // if the basis is NULL, then we'll compare the object
1209    // itself because the object is the basis.
1210    toBasis = toIter->getBasis();
1211    if (toBasis == NULL) {
1212        toBasis = toIter->getUnitsObj();
1213    }
1214
1215    toExp   = toIter->getExponent();
1216
1217    while ( fromIter != fromList.end() ) {
1218
1219        fromExp = fromIter->getExponent();
1220
1221        // in order to convert, exponents must be equal.
1222        if (fromExp == toExp) {
1223
1224            // get the basis of the object being stored
1225            // if the basis is NULL, then we'll compare the object
1226            // itself because the object is the basis.
1227            fromBasis = fromIter->getBasis();
1228            if (fromBasis == NULL) {
1229                fromBasis = fromIter->getUnitsObj();
1230            }
1231
1232            if (toBasis == fromBasis) {
1233                // conversion needed between 2 units of the same basis.
1234                // these two units could actually be the same unit (m->m)
1235                retVal = 0;
1236                break;
1237            }
1238        }
1239
1240        fromIter++;
1241    }
1242
1243    return retVal;
1244}
1245
1246/**********************************************************************/
1247// METHOD: compareListEntrySearch()
1248/// this function will soon be removed.
1249/**
1250 */
1251
1252int RpUnits::compareListEntrySearch ( RpUnitsList& fromList,
1253                                     RpUnitsListIter& fromIter,
1254                                     RpUnitsListIter& toIter ) {
1255
1256    const RpUnits* toBasis = NULL;
1257    const RpUnits* fromBasis = NULL;
1258    int retVal = 1;
1259
1260    fromIter = fromList.begin();
1261
1262    // get the basis of the object being stored
1263    // if the basis is NULL, then we'll compare the object
1264    // itself because the object is the basis.
1265    toBasis = toIter->getBasis();
1266    if (toBasis == NULL) {
1267        toBasis = toIter->getUnitsObj();
1268    }
1269
1270    while ( fromIter != fromList.end() ) {
1271
1272        // get the basis of the object being stored
1273        // if the basis is NULL, then we'll compare the object
1274        // itself because the object is the basis.
1275        fromBasis = fromIter->getBasis();
1276        if (fromBasis == NULL) {
1277            fromBasis = fromIter->getUnitsObj();
1278        }
1279
1280        if (toBasis == fromBasis) {
1281            // conversion needed between 2 units of the same basis.
1282            // these two units could actually be the same unit (m->m)
1283            retVal = 0;
1284            break;
1285        }
1286
1287        fromIter++;
1288    }
1289
1290    return retVal;
1291}
1292
1293/**********************************************************************/
1294// METHOD: convert()
1295/// Convert between RpUnits return a string value with or without units
1296/**
1297 * Convert function so people can just send in two strings and
1298 * we'll see if the units exists and do a conversion
1299 * Example:
1300 *     strVal = RpUnits::convert("300K","C",1);
1301 *
1302 * Returns a string with or without units.
1303 */
1304
1305
1306std::string
1307RpUnits::convert (  std::string val,
1308                    std::string toUnitsName,
1309                    int showUnits,
1310                    int* result ) {
1311
1312    RpUnitsList toUnitsList;
1313    RpUnitsList fromUnitsList;
1314
1315    RpUnitsListIter toIter;
1316    RpUnitsListIter fromIter;
1317    RpUnitsListIter tempIter;
1318
1319    const RpUnits* toUnits = NULL;
1320    const RpUnits* toPrefix = NULL;
1321    const RpUnits* fromUnits = NULL;
1322    const RpUnits* fromPrefix = NULL;
1323
1324    std::string tmpNumVal = "";
1325    std::string fromUnitsName = "";
1326    std::string convVal = "";
1327    std::string type = "";     // junk var used because units2list requires it
1328    std::string retStr = "";
1329    double origNumVal = 0;
1330    double numVal = 0;
1331    double toExp = 0;
1332    double fromExp = 0;
1333    int convErr = 0;
1334    std::stringstream outVal;
1335
1336    double copies = 0;
1337
1338    std::list<std::string> compatList;
1339    std::string listStr;
1340
1341    convertList cList;
1342    convertList totalConvList;
1343
1344
1345    // set  default result flag/error code
1346    if (result) {
1347        *result = 0;
1348    }
1349
1350    // search our string to see where the numeric part stops
1351    // and the units part starts
1352    //
1353    //  convert("5J", "neV") => 3.12075e+28neV
1354    //  convert("3.12075e+28neV", "J") => 4.99999J
1355    // now we can actually get the scientific notation portion of the string.
1356    //
1357
1358    convErr = unitSlice(val,fromUnitsName,numVal);
1359    origNumVal = numVal;
1360
1361    if (convErr != 0) {
1362        // no conversion was done.
1363        // number in incorrect format probably.
1364        if (result) {
1365            *result = 1;
1366        }
1367        return val;
1368    }
1369
1370    if (toUnitsName.empty())  {
1371        // there were no units in the input
1372        // string or no conversion needed
1373        // assume fromUnitsName = toUnitsName
1374        // return the correct value
1375        if (result) {
1376            *result = 0;
1377        }
1378
1379        if (showUnits == RPUNITS_UNITS_ON) {
1380            outVal << numVal << fromUnitsName;
1381        }
1382        else {
1383            outVal << numVal;
1384        }
1385
1386        return std::string(outVal.str());
1387    }
1388
1389    // check if the fromUnitsName is empty or
1390    // if the fromUnitsName == toUnitsName
1391    // these are conditions where no conversion is needed
1392    if ( (fromUnitsName.empty()) || (toUnitsName == fromUnitsName) )  {
1393        // there were no units in the input
1394        // string or no conversion needed
1395        // assume fromUnitsName = toUnitsName
1396        // return the correct value
1397        if (result) {
1398            *result = 0;
1399        }
1400
1401        if (showUnits == RPUNITS_UNITS_ON) {
1402            outVal << numVal << toUnitsName;
1403        }
1404        else {
1405            outVal << numVal;
1406        }
1407
1408        return std::string(outVal.str());
1409    }
1410
1411    convErr = RpUnits::units2list(toUnitsName,toUnitsList,type);
1412    if (convErr) {
1413        if (result) {
1414            *result = convErr;
1415        }
1416        retStr = "Unrecognized units: \"" + toUnitsName + "\". Please specify valid Rappture Units";
1417        return retStr;
1418    }
1419
1420    convErr = RpUnits::units2list(fromUnitsName,fromUnitsList,type);
1421    if (convErr) {
1422        if (result) {
1423            *result = convErr;
1424        }
1425        type = "";
1426        RpUnits::validate(toUnitsName,type,&compatList);
1427        list2str(compatList,listStr);
1428        retStr = "Unrecognized units: \"" + fromUnitsName
1429                + "\".\nShould be units of type " + type + " (" + listStr + ")";
1430        return retStr;
1431    }
1432
1433    fromIter = fromUnitsList.begin();
1434    toIter = toUnitsList.begin();
1435
1436    while ( (toIter != toUnitsList.end()) && (fromIter != fromUnitsList.end()) && (!convErr) ) {
1437        fromUnits = fromIter->getUnitsObj();
1438        fromPrefix = fromIter->getPrefix();
1439        toUnits = toIter->getUnitsObj();
1440        toPrefix = toIter->getPrefix();
1441
1442        cList.clear();
1443
1444        if (fromPrefix != NULL) {
1445            cList.push_back(fromPrefix->convList->conv->convForwFxnPtr);
1446        }
1447
1448        convErr = fromUnits->getConvertFxnList(toUnits, cList);
1449
1450        if (toPrefix != NULL) {
1451            cList.push_back(toPrefix->convList->conv->convBackFxnPtr);
1452        }
1453
1454        if (convErr == 0) {
1455
1456            toExp = toIter->getExponent();
1457            fromExp = fromIter->getExponent();
1458
1459            if (fromExp == toExp) {
1460                copies = fromExp;
1461                if (fromExp < 0) {
1462                    copies = copies * -1.00;
1463                    totalConvList.push_back(&invert);
1464                }
1465                while (copies > 0) {
1466                    combineLists(totalConvList,cList);
1467                    copies--;
1468                }
1469                if (fromExp < 0) {
1470                    totalConvList.push_back(&invert);
1471                }
1472            }
1473            else {
1474                // currently we cannot handle conversions of
1475                // units where the exponents are different
1476                convErr++;
1477            }
1478
1479        }
1480
1481        if (convErr == 0) {
1482            // successful conversion reported
1483            // remove the elements from the lists
1484            tempIter = toIter;
1485            toIter++;
1486            toUnitsList.erase(tempIter);
1487
1488            tempIter = fromIter;
1489            fromUnitsList.erase(tempIter);
1490            fromIter = fromUnitsList.begin();
1491        }
1492        else {
1493            // no conversion available?
1494            fromIter++;
1495            if (fromIter == fromUnitsList.end()) {
1496
1497                fromIter = fromUnitsList.begin();
1498                toIter++;
1499
1500                if (toIter == toUnitsList.end())  {
1501
1502                    toIter = toUnitsList.begin();
1503
1504                    // raise error that there was an
1505                    // unrecognized conversion request
1506
1507                    convErr++;
1508                    retStr = "Conversion unavailable: (";
1509                    while (fromIter != fromUnitsList.end()) {
1510                        /*
1511                        if (fromIter != fromUnitsList.begin()) {
1512                            retStr += " or ";
1513                        }
1514                        */
1515                        retStr += fromIter->name();
1516                        fromIter++;
1517                    }
1518                    retStr += ") -> (";
1519
1520                    // tempIter = toIter;
1521
1522                    while (toIter != toUnitsList.end()) {
1523                        retStr += toIter->name();
1524                        toIter++;
1525                    }
1526                    retStr += ")";
1527
1528                    type = "";
1529                    RpUnits::validate(toUnitsName,type,&compatList);
1530                    list2str(compatList,listStr);
1531                    retStr += "\nPlease enter units of type "
1532                                + type + " (" + listStr + ")";
1533
1534
1535                    // exit and report the error
1536
1537                    /*
1538                    toIter = tempIter;
1539                    toIter++;
1540                    toUnitsList.erase(tempIter);
1541                    */
1542                }
1543                else {
1544                    // keep searching for units to convert
1545                    // until we are out of units in the
1546                    // fromUnitsList and toUnitsList.
1547
1548                    convErr = 0;
1549                }
1550            }
1551            else {
1552                // keep searching for units to convert
1553                // until we are out of units in the
1554                // fromUnitsList and toUnitsList.
1555
1556                convErr = 0;
1557            }
1558        }
1559    }
1560
1561
1562
1563    if (convErr == 0) {
1564        // if ( (fromIter != fromUnitsList.end()) || (toIter != toUnitsList.end()) ) {
1565        if ( fromUnitsList.size() || toUnitsList.size() ) {
1566            // raise error that there was an
1567            // unrecognized conversion request
1568
1569            convErr++;
1570            retStr = "unmatched units in conversion: (";
1571
1572            fromIter = fromUnitsList.begin();
1573            while (fromIter != fromUnitsList.end()) {
1574                retStr += fromIter->name();
1575                fromIter++;
1576            }
1577
1578            if (fromUnitsList.size() && toUnitsList.size()) {
1579                retStr += ") -> (";
1580            }
1581
1582            toIter = toUnitsList.begin();
1583            while (toIter != toUnitsList.end()) {
1584                retStr += toIter->name();
1585                toIter++;
1586            }
1587            retStr += ")";
1588            type = "";
1589            RpUnits::validate(toUnitsName,type,&compatList);
1590            list2str(compatList,listStr);
1591            retStr += "\nPlease enter units of type "
1592                        + type + " (" + listStr + ")";
1593
1594        }
1595        else {
1596            // apply the conversion and check for errors
1597            convErr = applyConversion (&numVal, totalConvList);
1598            if (convErr == 0) {
1599                // outVal.flags(std::ios::fixed);
1600                // outVal.precision(10);
1601                if (showUnits == RPUNITS_UNITS_ON) {
1602                    outVal << numVal << toUnitsName;
1603                }
1604                else {
1605                    outVal << numVal;
1606                }
1607                retStr = outVal.str();
1608            }
1609            else {
1610
1611            }
1612        }
1613    }
1614
1615    if ( (result) && (*result == 0) ) {
1616        *result = convErr;
1617    }
1618
1619    return retStr;
1620
1621}
1622
1623/**********************************************************************/
1624// METHOD: convert()
1625/// Convert between RpUnits return a string value with or without units
1626/**
1627 * Returns a string value with or without units.
1628 */
1629
1630std::string
1631RpUnits::convert ( const  RpUnits* toUnits,
1632                   double val,
1633                   int showUnits,
1634                   int* result )  const {
1635
1636    double retVal = convert(toUnits,val,result);
1637    std::stringstream unitText;
1638
1639
1640    if (showUnits == RPUNITS_UNITS_ON) {
1641        unitText << retVal << toUnits->getUnitsName();
1642    }
1643    else {
1644        unitText << retVal;
1645    }
1646
1647    return (std::string(unitText.str()));
1648
1649}
1650
1651/**********************************************************************/
1652// METHOD: convert()
1653/// Convert between RpUnits using an RpUnits Object to describe toUnit.
1654/**
1655 * User function to convert a value to the provided RpUnits* toUnits
1656 * if it exists as a conversion from the basis
1657 * example
1658 *      cm.convert(meter,10)
1659 *      cm.convert(angstrum,100)
1660 *
1661 * Returns a double value without units.
1662 */
1663
1664double
1665RpUnits::convert(const RpUnits* toUnit, double val, int* result) const {
1666
1667    // currently we convert this object to its basis and look for the
1668    // connection to the toUnit object from the basis.
1669
1670    double value = val;
1671    const RpUnits* toBasis = toUnit->getBasis();
1672    const RpUnits* fromUnit = this;
1673    const RpUnits* dictToUnit = NULL;
1674    convEntry *p;
1675    int my_result = 0;
1676
1677    RpUnitsTypes::RpUnitsTypesHint hint = NULL;
1678
1679    // set *result to a default value
1680    if (result) {
1681        *result = 1;
1682    }
1683
1684    // guard against converting to the units you are converting from...
1685    // ie. meters->meters
1686    if (this->getUnitsName() == toUnit->getUnitsName()) {
1687        if (result) {
1688            *result = 0;
1689        }
1690        return val;
1691    }
1692
1693    // convert unit to the basis
1694    // makeBasis(&value);
1695    // trying to avoid the recursive way of converting to the basis.
1696    // need to rethink this.
1697    //
1698    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
1699        value = convert(basis,value,&my_result);
1700        if (my_result == 0) {
1701            fromUnit = basis;
1702        }
1703    }
1704
1705    // find the toUnit in our dictionary.
1706    // if the toUnits has a basis, we need to search for the basis
1707    // and convert between basis' and then convert again back to the
1708    // original unit.
1709    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1710        hint = RpUnitsTypes::getTypeHint(toBasis->getType());
1711        dictToUnit = find(toBasis->getUnitsName(), hint);
1712    }
1713    else {
1714        hint = RpUnitsTypes::getTypeHint(toUnit->getType());
1715        dictToUnit = find(toUnit->getUnitsName(), hint);
1716    }
1717
1718    // did we find the unit in the dictionary?
1719    if (dictToUnit == NULL) {
1720        // toUnit was not found in the dictionary
1721        return val;
1722    }
1723
1724    // search through the conversion list to find
1725    // the conversion to the toUnit.
1726
1727    if (basis) {
1728        p = basis->convList;
1729    }
1730    else {
1731        p = this->convList;
1732    }
1733
1734    if (p == NULL) {
1735        // there are no conversions
1736        return val;
1737    }
1738
1739    // loop through our conversion list looking for the correct conversion
1740    do {
1741
1742        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
1743            // we found our conversion
1744            // call the function pointer with value
1745
1746            // this should probably be re thought out
1747            // the problem is that convForwFxnPtr has the conversion for a
1748            // one arg conv function pointer and convForwFxnPtrDD has the
1749            // conversion for a two arg conv function pointer
1750            // need to make this simpler, more logical maybe only allow 2 arg
1751            if (       (p->conv->convForwFxnPtr)
1752                    && (! p->conv->convForwFxnPtrDD) ) {
1753
1754                value = p->conv->convForwFxnPtr(value);
1755            }
1756            else if (  (p->conv->convForwFxnPtrDD)
1757                    && (! p->conv->convForwFxnPtr) ) {
1758
1759                value =
1760                    p->conv->convForwFxnPtrDD(value, fromUnit->getExponent());
1761            }
1762
1763            // check to see if we converted to the actual requested unit
1764            // or to the requested unit's basis.
1765            // if we converted to the requested unit's basis. we need to
1766            // do one last conversion from the requested unit's basis back
1767            // to the requested unit.
1768            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1769                my_result = 0;
1770                value = toBasis->convert(toUnit,value,&my_result);
1771                if (my_result != 0) {
1772                    if (result) {
1773                        *result += 1;
1774                    }
1775                }
1776            }
1777
1778            // change the result code to zero, a conversion was performed
1779            // (we think)... its ture that it is possible to get to this
1780            // point and have skipped the conversion because the
1781            // conversion object was not properly created...
1782            // ie. both fxn ptrs were null or neither fxn ptr was null
1783            //
1784            if (result && (*result == 1)) {
1785                *result = 0;
1786            }
1787            break;
1788        }
1789
1790        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
1791            // we found our conversion
1792            // call the function pointer with value
1793
1794            // this should probably be re thought out
1795            // the problem is that convForwFxnPtr has the conversion for a
1796            // one arg conv function pointer and convForwFxnPtrDD has the
1797            // conversion for a two arg conv function pointer
1798            // need to make this simpler, more logical maybe only allow 2 arg
1799            if (       (p->conv->convBackFxnPtr)
1800                    && (! p->conv->convBackFxnPtrDD) ) {
1801
1802                value = p->conv->convBackFxnPtr(value);
1803            }
1804            else if (  (p->conv->convBackFxnPtrDD)
1805                    && (! p->conv->convBackFxnPtr) ) {
1806
1807                value =
1808                    p->conv->convBackFxnPtrDD(value, fromUnit->getExponent());
1809            }
1810
1811            // check to see if we converted to the actual requested unit
1812            // or to the requested unit's basis.
1813            // if we converted to the requested unit's basis. we need to
1814            // do one last conversion from the requested unit's basis back
1815            // to the requested unit.
1816            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1817                my_result = 0;
1818                value = toBasis->convert(toUnit,value,&my_result);
1819                if (my_result != 0) {
1820                    if (result) {
1821                        *result += 1;
1822                    }
1823                }
1824            }
1825
1826            // change the result code to zero, a conversion was performed
1827            // (we think)... its ture that it is possible to get to this
1828            // point and have skipped the conversion because the
1829            // conversion object was not properly created...
1830            // ie. both fxn ptrs were null or neither fxn ptr was null
1831            //
1832            if (result && (*result == 1)) {
1833                *result = 0;
1834            }
1835            break;
1836        }
1837
1838        p = p->next;
1839
1840    } while (p != NULL);
1841
1842
1843    if ( p == NULL) {
1844        // we did not find the conversion
1845        if (result) {
1846            *result += 1;
1847        }
1848        return val;
1849    }
1850
1851    // we found the conversion.
1852    // return the converted value.
1853    return value;
1854
1855}
1856
1857
1858/**********************************************************************/
1859// METHOD: convert()
1860/// Convert a value between RpUnits using user defined conversions
1861/**
1862 */
1863
1864void*
1865RpUnits::convert(const RpUnits* toUnit, void* val, int* result) const {
1866
1867    // currently we convert this object to its basis and look for the
1868    // connection ot the toUnit object from the basis.
1869
1870    void* value = val;
1871    const RpUnits* toBasis = toUnit->getBasis();
1872    const RpUnits* fromUnit = this;
1873    const RpUnits* dictToUnit = NULL;
1874    convEntry *p;
1875    int my_result = 0;
1876
1877    RpUnitsTypes::RpUnitsTypesHint hint = NULL;
1878
1879    // set *result to a default value
1880    if (result) {
1881        *result = 1;
1882    }
1883
1884    // guard against converting to the units you are converting from...
1885    // ie. meters->meters
1886    if (this->getUnitsName() == toUnit->getUnitsName()) {
1887        if (result) {
1888            *result = 0;
1889        }
1890        return val;
1891    }
1892
1893    // convert unit to the basis
1894    // makeBasis(&value);
1895    // trying to avoid the recursive way of converting to the basis.
1896    // need to rethink this.
1897    //
1898    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
1899        value = convert(basis,value,&my_result);
1900        if (my_result == 0) {
1901            fromUnit = basis;
1902        }
1903    }
1904
1905    // find the toUnit in our dictionary.
1906    // if the toUnits has a basis, we need to search for the basis
1907    // and convert between basis' and then convert again back to the
1908    // original unit.
1909    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1910        hint = RpUnitsTypes::getTypeHint(toBasis->getType());
1911        dictToUnit = find(toBasis->getUnitsName(), hint);
1912    }
1913    else {
1914        hint = RpUnitsTypes::getTypeHint(toUnit->getType());
1915        dictToUnit = find(toUnit->getUnitsName(), hint);
1916    }
1917
1918    // did we find the unit in the dictionary?
1919    if (dictToUnit == NULL) {
1920        // toUnit was not found in the dictionary
1921        return val;
1922    }
1923
1924    // search through the conversion list to find
1925    // the conversion to the toUnit.
1926
1927    if (basis) {
1928        p = basis->convList;
1929    }
1930    else {
1931        p = this->convList;
1932    }
1933
1934    if (p == NULL) {
1935        // there are no conversions
1936        return val;
1937    }
1938
1939    // loop through our conversion list looking for the correct conversion
1940    do {
1941
1942        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
1943            // we found our conversion
1944            // call the function pointer with value
1945
1946            value = p->conv->convForwFxnPtrVoid(p->conv->convForwData,value);
1947
1948            // check to see if we converted to the actual requested unit
1949            // or to the requested unit's basis.
1950            // if we converted to the requested unit's basis. we need to
1951            // do one last conversion from the requested unit's basis back
1952            // to the requested unit.
1953            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1954                my_result = 0;
1955                value = toBasis->convert(toUnit,value,&my_result);
1956                if (my_result != 0) {
1957                    if (result) {
1958                        *result += 1;
1959                    }
1960                }
1961            }
1962
1963            // change the result code to zero, a conversion was performed
1964            // (we think)... its ture that it is possible to get to this
1965            // point and have skipped the conversion because the
1966            // conversion object was not properly created...
1967            // ie. both fxn ptrs were null or neither fxn ptr was null
1968            //
1969            if (result && (*result == 1)) {
1970                *result = 0;
1971            }
1972            break;
1973        }
1974
1975        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
1976            // we found our conversion
1977            // call the function pointer with value
1978
1979            value = p->conv->convBackFxnPtrVoid(p->conv->convBackData,value);
1980
1981            // check to see if we converted to the actual requested unit
1982            // or to the requested unit's basis.
1983            // if we converted to the requested unit's basis. we need to
1984            // do one last conversion from the requested unit's basis back
1985            // to the requested unit.
1986            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1987                my_result = 0;
1988                value = toBasis->convert(toUnit,value,&my_result);
1989                if (my_result != 0) {
1990                    if (result) {
1991                        *result += 1;
1992                    }
1993                }
1994            }
1995
1996            // change the result code to zero, a conversion was performed
1997            // (we think)... its ture that it is possible to get to this
1998            // point and have skipped the conversion because the
1999            // conversion object was not properly created...
2000            // ie. both fxn ptrs were null or neither fxn ptr was null
2001            //
2002            if (result && (*result == 1)) {
2003                *result = 0;
2004            }
2005            break;
2006        }
2007
2008        p = p->next;
2009
2010    } while (p != NULL);
2011
2012
2013    if ( p == NULL) {
2014        // we did not find the conversion
2015        if (result) {
2016            *result += 1;
2017        }
2018        return val;
2019    }
2020
2021    // we found the conversion.
2022    // return the converted value.
2023    return value;
2024
2025}
2026
2027/**********************************************************************/
2028// METHOD: getConvertFxnList()
2029/// Return list of fxn pointers for converting two simple RpUnits objects.
2030/**
2031 * Return the conversion list that will convert from this RpUnits
2032 * object to the provided toUnits object if the conversion is defined
2033 * example
2034 *      cm.getConvertFxnList(meter,cList)
2035 *      cm.getConvertFxnList(angstrum,cList)
2036 *
2037 * Returns a list of conversion objects, represented by cList,
2038 * on success that a value can be applied to. The return value
2039 * will be zero (0).
2040 * Returns non-zero value on failure.
2041 */
2042
2043int
2044RpUnits::getConvertFxnList(const RpUnits* toUnit, convertList& cList) const {
2045
2046    // currently we convert this object to its basis and look for the
2047    // connection to the toUnit object from the basis.
2048
2049    const RpUnits* toBasis = toUnit->getBasis();
2050    const RpUnits* fromUnit = this;
2051    const RpUnits* dictToUnit = NULL;
2052    convEntry *p;
2053    int result = 0;
2054
2055    // guard against converting to the units you are converting from...
2056    // ie. meters->meters
2057    if (this->getUnitsName() == toUnit->getUnitsName()) {
2058        return result;
2059    }
2060
2061    // convert unit to the basis
2062    // makeBasis(&value);
2063    // trying to avoid the recursive way of converting to the basis.
2064    // need to rethink this.
2065    //
2066    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
2067        result = fromUnit->getConvertFxnList(basis,cList);
2068        if (result == 0) {
2069            fromUnit = basis;
2070        }
2071        else {
2072            // exit because an error occured while
2073            // trying to convert to the basis
2074            return result;
2075        }
2076    }
2077
2078    // find the toUnit in our dictionary.
2079    // if the toUnits has a basis, we need to search for the basis
2080    // and convert between basis' and then convert again back to the
2081    // original unit.
2082    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
2083        dictToUnit = find(  toBasis->getUnitsName(),
2084                            &RpUnitsTypes::hintTypeNonPrefix );
2085    }
2086    else {
2087        dictToUnit = find(  toUnit->getUnitsName(),
2088                            &RpUnitsTypes::hintTypeNonPrefix );
2089    }
2090
2091    // did we find the unit in the dictionary?
2092    if (dictToUnit == NULL) {
2093        // toUnit was not found in the dictionary
2094        result = 1;
2095        return result;
2096    }
2097
2098    // search through the conversion list to find
2099    // the conversion to the toUnit.
2100
2101    if (basis) {
2102        p = basis->convList;
2103    }
2104    else {
2105        p = this->convList;
2106    }
2107
2108    if (p == NULL) {
2109        // there are no conversions
2110        result = 1;
2111        return result;
2112    }
2113
2114    // loop through our conversion list looking for the correct conversion
2115    do {
2116
2117        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
2118            // we found our conversion
2119            // call the function pointer with value
2120
2121            // this should probably be re thought out
2122            // the problem is that convForwFxnPtr has the conversion for a
2123            // one arg conv function pointer and convForwFxnPtrDD has the
2124            // conversion for a two arg conv function pointer
2125            // need to make this simpler, more logical maybe only allow 2 arg
2126            if (       (p->conv->convForwFxnPtr)
2127                    && (! p->conv->convForwFxnPtrDD) ) {
2128
2129                // value = p->conv->convForwFxnPtr(value);
2130                cList.push_back(p->conv->convForwFxnPtr);
2131            }
2132            /*
2133            else if (  (p->conv->convForwFxnPtrDD)
2134                    && (! p->conv->convForwFxnPtr) ) {
2135
2136                // value = p->conv->convForwFxnPtrDD(value, fromUnit->getExponent());
2137                cList.pushback(conv);
2138            }
2139            */
2140
2141            // check to see if we converted to the actual requested unit
2142            // or to the requested unit's basis.
2143            // if we converted to the requested unit's basis. we need to
2144            // do one last conversion from the requested unit's basis back
2145            // to the requested unit.
2146            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
2147                result += toBasis->getConvertFxnList(toUnit,cList);
2148            }
2149
2150            break;
2151        }
2152
2153        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
2154            // we found our conversion
2155            // call the function pointer with value
2156
2157            // this should probably be re thought out
2158            // the problem is that convForwFxnPtr has the conversion for a
2159            // one arg conv function pointer and convForwFxnPtrDD has the
2160            // conversion for a two arg conv function pointer
2161            // need to make this simpler, more logical maybe only allow 2 arg
2162            if (       (p->conv->convBackFxnPtr)
2163                    && (! p->conv->convBackFxnPtrDD) ) {
2164
2165                // value = p->conv->convBackFxnPtr(value);
2166                cList.push_back(p->conv->convBackFxnPtr);
2167            }
2168            /*
2169            else if (  (p->conv->convBackFxnPtrDD)
2170                    && (! p->conv->convBackFxnPtr) ) {
2171
2172                // value = p->conv->convBackFxnPtrDD(value, fromUnit->getExponent());
2173                cList.pushback(conv);
2174            }
2175            */
2176
2177            // check to see if we converted to the actual requested unit
2178            // or to the requested unit's basis.
2179            // if we converted to the requested unit's basis. we need to
2180            // do one last conversion from the requested unit's basis back
2181            // to the requested unit.
2182            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
2183                result += toBasis->getConvertFxnList(toUnit,cList);
2184            }
2185
2186            break;
2187        }
2188
2189        p = p->next;
2190
2191    } while (p != NULL);
2192
2193
2194    if ( p == NULL) {
2195        // we did not find the conversion
2196        result += 1;
2197    }
2198
2199    // return the converted value and result flag
2200    return result;
2201}
2202
2203/**********************************************************************/
2204// METHOD: applyConversion()
2205/// Apply a list of conversions in cList to the value val
2206/**
2207 * Apply a list of conversions, represented by cList, to the value
2208 * val.
2209 *
2210 * Returns an integer value of zero (0) on success
2211 * Returns non-zero value on failure.
2212 */
2213
2214int
2215RpUnits::applyConversion(double* val, convertList& cList) {
2216
2217    convertList::iterator iter;
2218
2219    if(val == NULL) {
2220        return 1;
2221    }
2222
2223    for(iter = cList.begin(); iter != cList.end(); iter++)
2224    {
2225        *val = (*iter)(*val);
2226    }
2227
2228    return 0;
2229}
2230
2231/**********************************************************************/
2232// METHOD: combineLists()
2233/// combine two convertLists in an orderly fasion
2234/**
2235 *
2236 * elements of l2 are pushed onto l1 in the same order in which it
2237 * exists in l2. l1 is changed in this function.
2238 *
2239 * Returns an integer value of zero (0) on success
2240 * Returns non-zero value on failure.
2241 */
2242
2243int
2244RpUnits::combineLists(convertList& l1, convertList& l2) {
2245
2246    for (convertList::iterator iter = l2.begin(); iter != l2.end(); iter++) {
2247        l1.push_back(*iter);
2248    }
2249    return 0;
2250
2251}
2252
2253/**********************************************************************/
2254// METHOD: printList()
2255/// print a list
2256/**
2257 *
2258 * Returns an integer value of zero (0) on success
2259 * Returns non-zero value on failure.
2260 */
2261
2262int
2263RpUnits::printList(convertList& l1) {
2264
2265    for (convertList::iterator iter = l1.begin(); iter != l1.end(); iter++) {
2266        printf("%x\n", int((*iter)));
2267    }
2268    return 0;
2269
2270}
2271
2272/**********************************************************************/
2273// METHOD: insert()
2274/// Place an RpUnits Object into the Rappture Units Dictionary.
2275/**
2276 * Return whether the inserted key was new with a non-zero
2277 * value, or if the key already existed with a value of zero.
2278 */
2279
2280int
2281insert(std::string key,RpUnits* val) {
2282
2283    int newRecord = 0;
2284    RpUnitsTypes::RpUnitsTypesHint hint = NULL;
2285
2286    if (val == NULL) {
2287        return -1;
2288    }
2289
2290    hint = RpUnitsTypes::getTypeHint(val->getType());
2291
2292    RpUnits::dict->set(key,val,hint,&newRecord,val->getCI());
2293
2294    return newRecord;
2295}
2296
2297/**********************************************************************/
2298// METHOD: connectConversion()
2299/// Attach conversion information to a RpUnits Object.
2300/**
2301 */
2302
2303void
2304RpUnits::connectConversion(conversion* conv) const {
2305
2306    convEntry* p = convList;
2307
2308    if (p == NULL) {
2309        convList = new convEntry (conv,NULL,NULL);
2310    }
2311    else {
2312        while (p->next != NULL) {
2313            p = p->next;
2314        }
2315
2316        p->next = new convEntry (conv,p,NULL);
2317    }
2318
2319}
2320
2321/**********************************************************************/
2322// METHOD: connectIncarnation()
2323/// Attach incarnation object information to a RpUnits Object.
2324/**
2325 */
2326
2327void
2328RpUnits::connectIncarnation(const RpUnits* unit) const {
2329
2330    incarnationEntry* p = incarnationList;
2331
2332    if (p == NULL) {
2333        incarnationList = new incarnationEntry (unit,NULL,NULL);
2334    }
2335    else {
2336        while (p->next != NULL) {
2337            p = p->next;
2338        }
2339
2340        p->next = new incarnationEntry (unit,p,NULL);
2341    }
2342
2343}
2344
2345/**********************************************************************/
2346// METHOD: addPresets()
2347/// Add a specific set of predefined units to the dictionary
2348/**
2349 */
2350
2351int
2352RpUnits::addPresets (const std::string group) {
2353    int retVal = -1;
2354    if (group.compare("all") == 0) {
2355        retVal = RpUnitsPreset::addPresetAll();
2356    }
2357    else if (group.compare(RP_TYPE_ENERGY) == 0) {
2358        retVal = RpUnitsPreset::addPresetEnergy();
2359    }
2360    else if (group.compare(RP_TYPE_LENGTH) == 0) {
2361        retVal = RpUnitsPreset::addPresetLength();
2362    }
2363    else if (group.compare(RP_TYPE_TEMP) == 0) {
2364        retVal = RpUnitsPreset::addPresetTemp();
2365    }
2366    else if (group.compare(RP_TYPE_TIME) == 0) {
2367        retVal = RpUnitsPreset::addPresetTime();
2368    }
2369    else if (group.compare(RP_TYPE_VOLUME) == 0) {
2370        retVal = RpUnitsPreset::addPresetVolume();
2371    }
2372    else if (group.compare(RP_TYPE_ANGLE) == 0) {
2373        retVal = RpUnitsPreset::addPresetAngle();
2374    }
2375    else if (group.compare(RP_TYPE_MASS) == 0) {
2376        retVal = RpUnitsPreset::addPresetMass();
2377    }
2378    else if (group.compare(RP_TYPE_PREFIX) == 0) {
2379        retVal = RpUnitsPreset::addPresetPrefix();
2380    }
2381    else if (group.compare(RP_TYPE_PRESSURE) == 0) {
2382        retVal = RpUnitsPreset::addPresetPressure();
2383    }
2384    else if (group.compare(RP_TYPE_MISC) == 0) {
2385        retVal = RpUnitsPreset::addPresetMisc();
2386    }
2387
2388    return retVal;
2389}
2390
2391/**********************************************************************/
2392// METHOD: addPresetAll()
2393/// Call all of the addPreset* functions.
2394/**
2395 *
2396 * Add all predefined units to the units dictionary
2397 * Return codes: 0 success, anything else is error
2398 */
2399
2400int
2401RpUnitsPreset::addPresetAll () {
2402
2403    int result = 0;
2404
2405    result += addPresetPrefix();
2406    result += addPresetTime();
2407    result += addPresetTemp();
2408    result += addPresetLength();
2409    result += addPresetEnergy();
2410    result += addPresetVolume();
2411    result += addPresetAngle();
2412    result += addPresetMass();
2413    result += addPresetPressure();
2414    result += addPresetConcentration();
2415    result += addPresetMisc();
2416
2417    return 0;
2418}
2419
2420
2421/**********************************************************************/
2422// METHOD: addPresetPrefix()
2423///
2424/**
2425 * Defines the following unit prefixes:
2426 *   deci        (d)
2427 *   centi       (c)
2428 *   milli       (m)
2429 *   micro       (u)
2430 *   nano        (n)
2431 *   pico        (p)
2432 *   femto       (f)
2433 *   atto        (a)
2434 *   deca        (da)
2435 *   hecto       (h)
2436 *   kilo        (k)
2437 *   mega        (M)
2438 *   giga        (G)
2439 *   tera        (T)
2440 *   peta        (P)
2441 *   exa         (E)
2442 *
2443 * Return codes: 0 success, anything else is error
2444 */
2445
2446int
2447RpUnitsPreset::addPresetPrefix () {
2448
2449    std::string type = RP_TYPE_PREFIX;
2450    RpUnits* basis = NULL;
2451
2452    RpUnits * deci  = NULL;
2453    RpUnits * centi = NULL;
2454    RpUnits * milli = NULL;
2455    RpUnits * micro = NULL;
2456    RpUnits * nano  = NULL;
2457    RpUnits * pico  = NULL;
2458    RpUnits * femto = NULL;
2459    RpUnits * atto  = NULL;
2460    RpUnits * deca  = NULL;
2461    RpUnits * hecto = NULL;
2462    RpUnits * kilo  = NULL;
2463    RpUnits * mega  = NULL;
2464    RpUnits * giga  = NULL;
2465    RpUnits * tera  = NULL;
2466    RpUnits * peta  = NULL;
2467    RpUnits * exa   = NULL;
2468
2469    deci  = RpUnits::define ( "d",  basis, type);
2470    centi = RpUnits::define ( "c",  basis, type);
2471    milli = RpUnits::define ( "m",  basis, type, !RPUNITS_METRIC,
2472                              !RPUNITS_CASE_INSENSITIVE);
2473    micro = RpUnits::define ( "u",  basis, type);
2474    nano  = RpUnits::define ( "n",  basis, type);
2475    pico  = RpUnits::define ( "p",  basis, type, !RPUNITS_METRIC,
2476                              !RPUNITS_CASE_INSENSITIVE);
2477    femto = RpUnits::define ( "f",  basis, type);
2478    atto  = RpUnits::define ( "a",  basis, type);
2479    deca  = RpUnits::define ( "da", basis, type);
2480    hecto = RpUnits::define ( "h",  basis, type);
2481    kilo  = RpUnits::define ( "k",  basis, type);
2482    mega  = RpUnits::define ( "M",  basis, type, !RPUNITS_METRIC,
2483                              !RPUNITS_CASE_INSENSITIVE);
2484    giga  = RpUnits::define ( "G",  basis, type);
2485    tera  = RpUnits::define ( "T",  basis, type);
2486    peta  = RpUnits::define ( "P",  basis, type, !RPUNITS_METRIC,
2487                              !RPUNITS_CASE_INSENSITIVE);
2488    exa  = RpUnits::define  ( "E",  basis, type);
2489
2490    // the use of the unit as the from and the to unit is a hack
2491    // that can be resolved by creating a RpPrefix object
2492    // the define() function cannot handle NULL as to unit.
2493    RpUnits::define ( deci,  deci , deci2base,  base2deci);
2494    RpUnits::define ( centi, centi, centi2base, base2centi);
2495    RpUnits::define ( milli, milli, milli2base, base2milli);
2496    RpUnits::define ( micro, micro, micro2base, base2micro);
2497    RpUnits::define ( nano,  nano , nano2base,  base2nano);
2498    RpUnits::define ( pico,  pico , pico2base,  base2pico);
2499    RpUnits::define ( femto, femto, femto2base, base2femto);
2500    RpUnits::define ( atto,  atto , atto2base,  base2atto);
2501    RpUnits::define ( deca,  deca , deca2base,  base2deca);
2502    RpUnits::define ( hecto, hecto, hecto2base, base2hecto);
2503    RpUnits::define ( kilo,  kilo , kilo2base,  base2kilo);
2504    RpUnits::define ( mega,  mega , mega2base,  base2mega);
2505    RpUnits::define ( giga,  giga , giga2base,  base2giga);
2506    RpUnits::define ( tera,  tera , tera2base,  base2tera);
2507    RpUnits::define ( peta,  peta , peta2base,  base2peta);
2508    RpUnits::define ( exa,   exa  , exa2base,   base2exa);
2509
2510    return 0;
2511}
2512
2513/**********************************************************************/
2514// METHOD: addPresetTime()
2515/// Add Time related units to the dictionary
2516/**
2517 * Defines the following units:
2518 *   seconds  (s)
2519 *   minutes  (min)
2520 *   hours    (h)
2521 *   days     (d)
2522 *
2523 *   month and year are not included because simple
2524 *   day->month conversions may be misleading
2525 *   month->year conversions may be included in the future
2526 *
2527 * Return codes: 0 success, anything else is error
2528 */
2529
2530int
2531RpUnitsPreset::addPresetTime () {
2532
2533    RpUnits* second    = NULL;
2534    RpUnits* minute    = NULL;
2535    RpUnits* hour      = NULL;
2536    RpUnits* day       = NULL;
2537
2538    second    = RpUnits::define("s", NULL, RP_TYPE_TIME, RPUNITS_METRIC);
2539    minute    = RpUnits::define("min", second, RP_TYPE_TIME);
2540    hour      = RpUnits::define("h", second, RP_TYPE_TIME);
2541    day       = RpUnits::define("d", second, RP_TYPE_TIME);
2542
2543    // add time definitions
2544
2545    RpUnits::define(second, minute, sec2min, min2sec);
2546    RpUnits::define(second, hour, sec2hour, hour2sec);
2547    RpUnits::define(second, day, sec2day, day2sec);
2548
2549    return 0;
2550}
2551
2552/**********************************************************************/
2553// METHOD: addPresetTemp()
2554/// Add Temperature related units to the dictionary
2555/**
2556 * Defines the following units:
2557 *   fahrenheit  (F)
2558 *   celcius     (C)
2559 *   kelvin      (K)
2560 *   rankine     (R)
2561 *
2562 * Return codes: 0 success, anything else is error
2563 */
2564
2565int
2566RpUnitsPreset::addPresetTemp () {
2567
2568    RpUnits* fahrenheit = NULL;
2569    RpUnits* celcius    = NULL;
2570    RpUnits* kelvin     = NULL;
2571    RpUnits* rankine    = NULL;
2572
2573    fahrenheit = RpUnits::define("F", NULL, RP_TYPE_TEMP);
2574    celcius    = RpUnits::define("C", NULL, RP_TYPE_TEMP);
2575    kelvin     = RpUnits::define("K", NULL, RP_TYPE_TEMP);
2576    rankine    = RpUnits::define("R", NULL, RP_TYPE_TEMP);
2577
2578    // add temperature definitions
2579    RpUnits::define(fahrenheit, celcius, fahrenheit2centigrade, centigrade2fahrenheit);
2580    RpUnits::define(celcius, kelvin, centigrade2kelvin, kelvin2centigrade);
2581    RpUnits::define(fahrenheit, kelvin, fahrenheit2kelvin, kelvin2fahrenheit);
2582    RpUnits::define(rankine, kelvin, rankine2kelvin, kelvin2rankine);
2583    RpUnits::define(fahrenheit, rankine, fahrenheit2rankine, rankine2fahrenheit);
2584    RpUnits::define(celcius, rankine, celcius2rankine, rankine2celcius);
2585
2586    return 0;
2587}
2588
2589/**********************************************************************/
2590// METHOD: addPresetLength()
2591/// Add Length related units to the dictionary
2592/**
2593 * Defines the following units:
2594 *   meters         (m)
2595 *   angstrom       (A)
2596 *   inch           (in)
2597 *   feet           (ft)
2598 *   yard           (yd)
2599 *
2600 * Return codes: 0 success, anything else is error
2601 */
2602
2603int
2604RpUnitsPreset::addPresetLength () {
2605
2606    RpUnits* meters     = NULL;
2607    RpUnits* angstrom   = NULL;
2608    RpUnits* inch       = NULL;
2609    RpUnits* feet       = NULL;
2610    RpUnits* yard       = NULL;
2611
2612    meters     = RpUnits::define("m", NULL, RP_TYPE_LENGTH, RPUNITS_METRIC);
2613    angstrom   = RpUnits::define("A", NULL, RP_TYPE_LENGTH);
2614    inch       = RpUnits::define("in", NULL, RP_TYPE_LENGTH);
2615    feet       = RpUnits::define("ft", inch, RP_TYPE_LENGTH);
2616    yard       = RpUnits::define("yd", inch, RP_TYPE_LENGTH);
2617
2618    // RpUnits::makeMetric(meters);
2619
2620    // add length definitions
2621    RpUnits::define(angstrom, meters, angstrom2meter, meter2angstrom);
2622    RpUnits::define(inch, feet, inch2feet, feet2inch);
2623    RpUnits::define(inch, yard, inch2yard, yard2inch);
2624    RpUnits::define(inch, meters, inch2meter, meter2inch);
2625
2626    return 0;
2627}
2628
2629/**********************************************************************/
2630// METHOD: addPresetEnergy()
2631/// Add Energy related units to the dictionary
2632/**
2633 * Defines the following units:
2634 *   electron Volt (eV)
2635 *   joule         (J)
2636 *
2637 * Return codes: 0 success, anything else is error
2638 */
2639
2640int
2641RpUnitsPreset::addPresetEnergy () {
2642
2643    RpUnits* eVolt      = NULL;
2644    RpUnits* joule      = NULL;
2645
2646    eVolt      = RpUnits::define("eV", NULL, RP_TYPE_ENERGY, RPUNITS_METRIC);
2647    joule      = RpUnits::define("J", NULL, RP_TYPE_ENERGY, RPUNITS_METRIC);
2648
2649    // add energy definitions
2650    RpUnits::define(eVolt,joule,electronVolt2joule,joule2electronVolt);
2651
2652    return 0;
2653}
2654
2655/**********************************************************************/
2656// METHOD: addPresetVolume()
2657/// Add Volume related units to the dictionary
2658/**
2659 * Defines the following units:
2660 *   cubic feet (ft3)
2661 *   us gallons (gal)
2662 *   liter      (L)
2663 *
2664 * Return codes: 0 success, anything else is error
2665 */
2666
2667int
2668RpUnitsPreset::addPresetVolume () {
2669
2670    // RpUnits* cubic_meter  = RpUnits::define("m3", NULL, RP_TYPE_VOLUME);
2671    // RpUnits* cubic_feet   = RpUnits::define("ft3", NULL, RP_TYPE_VOLUME);
2672    RpUnits* us_gallon    = NULL;
2673    RpUnits* liter        = NULL;
2674
2675    us_gallon    = RpUnits::define("gal", NULL, RP_TYPE_VOLUME);
2676    liter        = RpUnits::define("L", NULL, RP_TYPE_VOLUME, RPUNITS_METRIC);
2677
2678    /*
2679    // RpUnits::makeMetric(cubic_meter);
2680    const RpUnits* meter = NULL;
2681    const RpUnits* foot = NULL;
2682
2683    meter = RpUnits::find("m");
2684    if (meter && cubic_meter) {
2685        RpUnits::incarnate(meter,cubic_meter);
2686    }
2687    else {
2688        // raise an error, could not find meter unit
2689    }
2690
2691    foot = RpUnits::find("ft");
2692    if (foot && cubic_feet) {
2693        RpUnits::incarnate(foot,cubic_feet);
2694    }
2695    else {
2696        // raise an error, could not find meter unit
2697    }
2698    */
2699
2700    // RpUnits::makeMetric(liter);
2701
2702
2703    // add volume definitions
2704    // RpUnits::define(cubic_meter,cubic_feet,meter2feet,feet2meter);
2705    // RpUnits::define(cubic_meter,us_gallon,cubicMeter2usGallon,usGallon2cubicMeter);
2706    // RpUnits::define(cubic_feet,us_gallon,cubicFeet2usGallon,usGallon2cubicFeet);
2707    // RpUnits::define(cubic_meter,liter,cubicMeter2liter,liter2cubicMeter);
2708    // RpUnits::define(liter,us_gallon,liter2us_gallon,us_gallon2liter);
2709
2710    return 0;
2711}
2712
2713/**********************************************************************/
2714// METHOD: addPresetAngle()
2715/// Add Angle related units to the dictionary
2716/**
2717 * Defines the following units:
2718 *   degrees  (deg)
2719 *   gradians (grad)
2720 *   radians  (rad) (and metric extensions)
2721 *
2722 * Return codes: 0 success, anything else is error
2723 */
2724
2725int
2726RpUnitsPreset::addPresetAngle () {
2727
2728    RpUnits* degree  = NULL;
2729    RpUnits* gradian = NULL;
2730    RpUnits* radian  = NULL;
2731
2732    degree  = RpUnits::define("deg",  NULL, RP_TYPE_ANGLE);
2733    gradian = RpUnits::define("grad", NULL, RP_TYPE_ANGLE);
2734    radian  = RpUnits::define("rad",  NULL, RP_TYPE_ANGLE, RPUNITS_METRIC);
2735
2736    // add angle definitions
2737    RpUnits::define(degree,gradian,deg2grad,grad2deg);
2738    RpUnits::define(radian,degree,rad2deg,deg2rad);
2739    RpUnits::define(radian,gradian,rad2grad,grad2rad);
2740
2741    return 0;
2742}
2743
2744/**********************************************************************/
2745// METHOD: addPresetMass()
2746/// Add Mass related units to the dictionary
2747/**
2748 * Defines the following units:
2749 *   gram  (g)
2750 *
2751 * Return codes: 0 success, anything else is error
2752 */
2753
2754int
2755RpUnitsPreset::addPresetMass () {
2756
2757    RpUnits* gram  = NULL;
2758
2759    gram  = RpUnits::define("g", NULL, RP_TYPE_MASS, RPUNITS_METRIC);
2760
2761    return 0;
2762}
2763
2764/**********************************************************************/
2765// METHOD: addPresetPressure()
2766/// Add pressure related units to the dictionary
2767/**
2768 * http://www.ilpi.com/msds/ref/pressureunits.html
2769 *
2770 * Defines the following units:
2771 *   atmosphere             (atm)
2772 *   bar                    (bar)
2773 *   pascal                 (Pa)
2774 *   pounds/(in^2)          (psi)
2775 *   torr                   (torr)
2776 *   millimeters Mercury    (mmHg)
2777 *
2778 * mmHg was added because as a convenience to those who have not
2779 * yet switched over to the new representation of torr.
2780 *
2781 * Return codes: 0 success, anything else is error
2782 */
2783
2784int
2785RpUnitsPreset::addPresetPressure () {
2786
2787    RpUnits* atmosphere = NULL;
2788    RpUnits* bar        = NULL;
2789    RpUnits* pascal     = NULL;
2790    RpUnits* psi        = NULL;
2791    RpUnits* torr       = NULL;
2792    RpUnits* mmHg       = NULL;
2793
2794    atmosphere  = RpUnits::define("atm", NULL, RP_TYPE_PRESSURE);
2795    bar     = RpUnits::define("bar",  NULL, RP_TYPE_PRESSURE, RPUNITS_METRIC);
2796    pascal  = RpUnits::define("Pa",   NULL, RP_TYPE_PRESSURE, RPUNITS_METRIC);
2797    psi     = RpUnits::define("psi",  NULL, RP_TYPE_PRESSURE);
2798    torr    = RpUnits::define("torr", NULL, RP_TYPE_PRESSURE);
2799    mmHg    = RpUnits::define("mmHg", torr, RP_TYPE_PRESSURE);
2800
2801    RpUnits::define(bar,pascal,bar2Pa,Pa2bar);
2802    RpUnits::define(bar,atmosphere,bar2atm,atm2bar);
2803    RpUnits::define(bar,psi,bar2psi,psi2bar);
2804    RpUnits::define(bar,torr,bar2torr,torr2bar);
2805    RpUnits::define(pascal,atmosphere,Pa2atm,atm2Pa);
2806    RpUnits::define(pascal,torr,Pa2torr,torr2Pa);
2807    RpUnits::define(pascal,psi,Pa2psi,psi2Pa);
2808    RpUnits::define(torr,atmosphere,torr2atm,atm2torr);
2809    RpUnits::define(torr,psi,torr2psi,psi2torr);
2810    RpUnits::define(atmosphere,psi,atm2psi,psi2atm);
2811
2812    RpUnits::define(torr,mmHg,torr2mmHg,mmHg2torr);
2813
2814    return 0;
2815}
2816
2817/**********************************************************************/
2818// METHOD: addPresetConcentration()
2819/// Add concentration related units to the dictionary
2820/**
2821 * http://www.ilpi.com/msds/ref/pressureunits.html
2822 *
2823 * Defines the following units:
2824 *   pH    (pH)
2825 *   pOH    (pOH)
2826 *
2827 * Return codes: 0 success, anything else is error
2828 */
2829
2830int
2831RpUnitsPreset::addPresetConcentration () {
2832
2833    RpUnits* pH  = NULL;
2834    RpUnits* pOH = NULL;
2835
2836    pH  = RpUnits::define("pH",  NULL, RP_TYPE_CONC);
2837    pOH = RpUnits::define("pOH", NULL, RP_TYPE_CONC);
2838
2839    // add concentration definitions
2840    RpUnits::define(pH,pOH,pH2pOH,pOH2pH);
2841
2842    return 0;
2843}
2844
2845/**********************************************************************/
2846// METHOD: addPresetMisc()
2847/// Add Misc related units to the dictionary
2848/**
2849 * Defines the following units:
2850 *   mole  (mol)
2851 *
2852 * Return codes: 0 success, anything else is error
2853 */
2854
2855int
2856RpUnitsPreset::addPresetMisc () {
2857
2858    RpUnits* volt      = NULL;
2859    RpUnits* mole      = NULL;
2860    RpUnits* hertz     = NULL;
2861    RpUnits* becquerel = NULL;
2862
2863    volt      = RpUnits::define("V",  NULL, RP_TYPE_EPOT, RPUNITS_METRIC);
2864    mole      = RpUnits::define("mol",NULL, RP_TYPE_MISC, RPUNITS_METRIC);
2865    hertz     = RpUnits::define("Hz", NULL, RP_TYPE_MISC, RPUNITS_METRIC);
2866    becquerel = RpUnits::define("Bq", NULL, RP_TYPE_MISC, RPUNITS_METRIC);
2867
2868    // RpUnits* percent   = RpUnits::define("%",  NULL, RP_TYPE_MISC);
2869
2870    return 0;
2871}
2872
2873RpUnitsTypes::RpUnitsTypesHint
2874RpUnitsTypes::getTypeHint (std::string type) {
2875
2876    if (type.compare(RP_TYPE_ENERGY) == 0) {
2877        return &RpUnitsTypes::hintTypeEnergy;
2878    }
2879    else if (type.compare(RP_TYPE_EPOT) == 0) {
2880        return &RpUnitsTypes::hintTypeEPot;
2881    }
2882    else if (type.compare(RP_TYPE_LENGTH) == 0) {
2883        return &RpUnitsTypes::hintTypeLength;
2884    }
2885    else if (type.compare(RP_TYPE_TEMP) == 0) {
2886        return &RpUnitsTypes::hintTypeTemp;
2887    }
2888    else if (type.compare(RP_TYPE_TIME) == 0) {
2889        return &RpUnitsTypes::hintTypeTime;
2890    }
2891    else if (type.compare(RP_TYPE_VOLUME) == 0) {
2892        return &RpUnitsTypes::hintTypeVolume;
2893    }
2894    else if (type.compare(RP_TYPE_ANGLE) == 0) {
2895        return &RpUnitsTypes::hintTypeAngle;
2896    }
2897    else if (type.compare(RP_TYPE_MASS) == 0) {
2898        return &RpUnitsTypes::hintTypeMass;
2899    }
2900    else if (type.compare(RP_TYPE_PREFIX) == 0) {
2901        return &RpUnitsTypes::hintTypePrefix;
2902    }
2903    else if (type.compare(RP_TYPE_PRESSURE) == 0) {
2904        return &RpUnitsTypes::hintTypePressure;
2905    }
2906    else if (type.compare(RP_TYPE_CONC) == 0) {
2907        return &RpUnitsTypes::hintTypeConc;
2908    }
2909    else if (type.compare(RP_TYPE_MISC) == 0) {
2910        return &RpUnitsTypes::hintTypeMisc;
2911    }
2912    else {
2913        return NULL;
2914    }
2915};
2916
2917bool
2918RpUnitsTypes::hintTypePrefix   (   RpUnits* unitObj    ) {
2919
2920    bool retVal = false;
2921
2922    if ( (unitObj->getType()).compare(RP_TYPE_PREFIX) == 0 ) {
2923        retVal = true;
2924    }
2925
2926    return retVal;
2927}
2928
2929bool
2930RpUnitsTypes::hintTypeNonPrefix    (   RpUnits* unitObj    ) {
2931
2932    bool retVal = true;
2933
2934    if ( (unitObj->getType()).compare(RP_TYPE_PREFIX) == 0 ) {
2935        retVal = false;
2936    }
2937
2938    return retVal;
2939}
2940
2941bool
2942RpUnitsTypes::hintTypeEnergy   (   RpUnits* unitObj    ) {
2943
2944    bool retVal = false;
2945
2946    if ( (unitObj->getType()).compare(RP_TYPE_ENERGY) == 0 ) {
2947        retVal = true;
2948    }
2949
2950    return retVal;
2951}
2952
2953bool
2954RpUnitsTypes::hintTypeEPot   (   RpUnits* unitObj    ) {
2955
2956    bool retVal = false;
2957
2958    if ( (unitObj->getType()).compare(RP_TYPE_EPOT) == 0 ) {
2959        retVal = true;
2960    }
2961
2962    return retVal;
2963}
2964
2965bool
2966RpUnitsTypes::hintTypeLength   (   RpUnits* unitObj    ) {
2967
2968    bool retVal = false;
2969
2970    if ( (unitObj->getType()).compare(RP_TYPE_LENGTH) == 0 ) {
2971        retVal = true;
2972    }
2973
2974    return retVal;
2975}
2976
2977bool
2978RpUnitsTypes::hintTypeTemp   (   RpUnits* unitObj    ) {
2979
2980    bool retVal = false;
2981
2982    if ( (unitObj->getType()).compare(RP_TYPE_TEMP) == 0 ) {
2983        retVal = true;
2984    }
2985
2986    return retVal;
2987}
2988
2989bool
2990RpUnitsTypes::hintTypeTime   (   RpUnits* unitObj    ) {
2991
2992    bool retVal = false;
2993
2994    if ( (unitObj->getType()).compare(RP_TYPE_TIME) == 0 ) {
2995        retVal = true;
2996    }
2997
2998    return retVal;
2999}
3000
3001bool
3002RpUnitsTypes::hintTypeVolume   (   RpUnits* unitObj    ) {
3003
3004    bool retVal = false;
3005
3006    if ( (unitObj->getType()).compare(RP_TYPE_VOLUME) == 0 ) {
3007        retVal = true;
3008    }
3009
3010    return retVal;
3011}
3012
3013bool
3014RpUnitsTypes::hintTypeAngle   (   RpUnits* unitObj    ) {
3015
3016    bool retVal = false;
3017
3018    if ( (unitObj->getType()).compare(RP_TYPE_ANGLE) == 0 ) {
3019        retVal = true;
3020    }
3021
3022    return retVal;
3023}
3024
3025bool
3026RpUnitsTypes::hintTypeMass   (   RpUnits* unitObj    ) {
3027
3028    bool retVal = false;
3029
3030    if ( (unitObj->getType()).compare(RP_TYPE_MASS) == 0 ) {
3031        retVal = true;
3032    }
3033
3034    return retVal;
3035}
3036
3037bool
3038RpUnitsTypes::hintTypePressure   (   RpUnits* unitObj    ) {
3039
3040    bool retVal = false;
3041
3042    if ( (unitObj->getType()).compare(RP_TYPE_PRESSURE) == 0 ) {
3043        retVal = true;
3044    }
3045
3046    return retVal;
3047}
3048
3049bool
3050RpUnitsTypes::hintTypeConc   (   RpUnits* unitObj    ) {
3051
3052    bool retVal = false;
3053
3054    if ( (unitObj->getType()).compare(RP_TYPE_CONC) == 0 ) {
3055        retVal = true;
3056    }
3057
3058    return retVal;
3059}
3060
3061bool
3062RpUnitsTypes::hintTypeMisc   (   RpUnits* unitObj    ) {
3063
3064    bool retVal = false;
3065
3066    if ( (unitObj->getType()).compare(RP_TYPE_MISC) == 0 ) {
3067        retVal = true;
3068    }
3069
3070    return retVal;
3071}
3072
3073// -------------------------------------------------------------------- //
3074
3075/**********************************************************************/
3076// FUNCTION: list2str()
3077/// Convert a std::list<std::string> into a comma delimited std::string
3078/**
3079 * Iterates through a std::list<std::string> and returns a comma
3080 * delimited std::string containing the elements of the inputted std::list.
3081 *
3082 * Returns 0 on success, anything else is error
3083 */
3084
3085int
3086list2str (std::list<std::string>& inList, std::string& outString)
3087{
3088    int retVal = 1;  // return Value 0 is success, everything else is failure
3089    unsigned int counter = 0; // check if we hit all elements of inList
3090    std::list<std::string>::iterator inListIter; // list interator
3091
3092    inListIter = inList.begin();
3093
3094    while (inListIter != inList.end()) {
3095        if ( outString.empty() ) {
3096            outString = *inListIter;
3097        }
3098        else {
3099            outString =  outString + "," + *inListIter;
3100        }
3101
3102        // increment the iterator and loop counter
3103        inListIter++;
3104        counter++;
3105    }
3106
3107    if (counter == inList.size()) {
3108        retVal = 0;
3109    }
3110
3111    return retVal;
3112}
3113
3114/**********************************************************************/
3115// FUNCTION: unitSlice()
3116/// Convert a std::string into what might be the value and units
3117/**
3118 * Returns 0 on success, anything else is error
3119 */
3120
3121int
3122unitSlice (std::string inStr, std::string& outUnits, double& outVal)
3123{
3124    int retVal      = 0;  // return val 0 is success, otherwise failure
3125    char *endptr    = NULL;
3126
3127    outVal = strtod(inStr.c_str(), &endptr);
3128
3129    if ( (outVal == 0) && (endptr == inStr.c_str()) ) {
3130        // no conversion performed
3131        retVal = 1;
3132    }
3133    else {
3134    }
3135
3136    outUnits = std::string(endptr);
3137
3138    return retVal;
3139}
Note: See TracBrowser for help on using the repository browser.