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

Last change on this file since 827 was 747, checked in by dkearney, 17 years ago

added decibel to list of recognized units.

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