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

Last change on this file since 1006 was 1006, checked in by dkearney, 16 years ago

changed printf formating from unsigned int to pointer in RpUnits and adjusted the outcome c interface to avoid accessing the private variables of the outcome. this is done to avoid compiler errors when compiling in hubzero and other 64bit environments.

File size: 89.7 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("%p\n", *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* bohr       = NULL;
2618    RpUnits* inch       = NULL;
2619    RpUnits* feet       = NULL;
2620    RpUnits* yard       = NULL;
2621    RpUnits* mile       = NULL;
2622
2623    meters     = RpUnits::define("m", NULL, RP_TYPE_LENGTH, RPUNITS_METRIC);
2624    angstrom   = RpUnits::define("A", NULL, RP_TYPE_LENGTH);
2625    bohr       = RpUnits::define("bohr", NULL, RP_TYPE_LENGTH);
2626    inch       = RpUnits::define("in", NULL, RP_TYPE_LENGTH);
2627    feet       = RpUnits::define("ft", inch, RP_TYPE_LENGTH);
2628    yard       = RpUnits::define("yd", inch, RP_TYPE_LENGTH);
2629    mile       = RpUnits::define("mi", inch, RP_TYPE_LENGTH);
2630
2631    // RpUnits::makeMetric(meters);
2632
2633    // add length definitions
2634    RpUnits::define(angstrom, meters, angstrom2meter, meter2angstrom);
2635    RpUnits::define(bohr, meters, bohr2meter, meter2bohr);
2636    RpUnits::define(inch, feet, inch2feet, feet2inch);
2637    RpUnits::define(inch, yard, inch2yard, yard2inch);
2638    RpUnits::define(inch, meters, inch2meter, meter2inch);
2639    RpUnits::define(inch, mile, inch2mile, mile2inch);
2640
2641    return 0;
2642}
2643
2644/**********************************************************************/
2645// METHOD: addPresetEnergy()
2646/// Add Energy related units to the dictionary
2647/**
2648 * Defines the following units:
2649 *   electron Volt (eV)
2650 *   joule         (J)
2651 *
2652 * Return codes: 0 success, anything else is error
2653 */
2654
2655int
2656RpUnitsPreset::addPresetEnergy () {
2657
2658    RpUnits* eVolt      = NULL;
2659    RpUnits* joule      = NULL;
2660
2661    eVolt      = RpUnits::define("eV", NULL, RP_TYPE_ENERGY, RPUNITS_METRIC);
2662    joule      = RpUnits::define("J", NULL, RP_TYPE_ENERGY, RPUNITS_METRIC);
2663
2664    // add energy definitions
2665    RpUnits::define(eVolt,joule,electronVolt2joule,joule2electronVolt);
2666
2667    return 0;
2668}
2669
2670/**********************************************************************/
2671// METHOD: addPresetVolume()
2672/// Add Volume related units to the dictionary
2673/**
2674 * Defines the following units:
2675 *   cubic feet (ft3)
2676 *   us gallons (gal)
2677 *   liter      (L)
2678 *
2679 * Return codes: 0 success, anything else is error
2680 */
2681
2682int
2683RpUnitsPreset::addPresetVolume () {
2684
2685    // RpUnits* cubic_meter  = RpUnits::define("m3", NULL, RP_TYPE_VOLUME);
2686    // RpUnits* cubic_feet   = RpUnits::define("ft3", NULL, RP_TYPE_VOLUME);
2687    RpUnits* us_gallon    = NULL;
2688    RpUnits* liter        = NULL;
2689
2690    us_gallon    = RpUnits::define("gal", NULL, RP_TYPE_VOLUME);
2691    liter        = RpUnits::define("L", NULL, RP_TYPE_VOLUME, RPUNITS_METRIC);
2692
2693    /*
2694    // RpUnits::makeMetric(cubic_meter);
2695    const RpUnits* meter = NULL;
2696    const RpUnits* foot = NULL;
2697
2698    meter = RpUnits::find("m");
2699    if (meter && cubic_meter) {
2700        RpUnits::incarnate(meter,cubic_meter);
2701    }
2702    else {
2703        // raise an error, could not find meter unit
2704    }
2705
2706    foot = RpUnits::find("ft");
2707    if (foot && cubic_feet) {
2708        RpUnits::incarnate(foot,cubic_feet);
2709    }
2710    else {
2711        // raise an error, could not find meter unit
2712    }
2713    */
2714
2715    // RpUnits::makeMetric(liter);
2716
2717
2718    // add volume definitions
2719    // RpUnits::define(cubic_meter,cubic_feet,meter2feet,feet2meter);
2720    // RpUnits::define(cubic_meter,us_gallon,cubicMeter2usGallon,usGallon2cubicMeter);
2721    // RpUnits::define(cubic_feet,us_gallon,cubicFeet2usGallon,usGallon2cubicFeet);
2722    // RpUnits::define(cubic_meter,liter,cubicMeter2liter,liter2cubicMeter);
2723    // RpUnits::define(liter,us_gallon,liter2us_gallon,us_gallon2liter);
2724
2725    return 0;
2726}
2727
2728/**********************************************************************/
2729// METHOD: addPresetAngle()
2730/// Add Angle related units to the dictionary
2731/**
2732 * Defines the following units:
2733 *   degrees  (deg)
2734 *   gradians (grad)
2735 *   radians  (rad) (and metric extensions)
2736 *
2737 * Return codes: 0 success, anything else is error
2738 */
2739
2740int
2741RpUnitsPreset::addPresetAngle () {
2742
2743    RpUnits* degree  = NULL;
2744    RpUnits* gradian = NULL;
2745    RpUnits* radian  = NULL;
2746
2747    degree  = RpUnits::define("deg",  NULL, RP_TYPE_ANGLE);
2748    gradian = RpUnits::define("grad", NULL, RP_TYPE_ANGLE);
2749    radian  = RpUnits::define("rad",  NULL, RP_TYPE_ANGLE, RPUNITS_METRIC);
2750
2751    // add angle definitions
2752    RpUnits::define(degree,gradian,deg2grad,grad2deg);
2753    RpUnits::define(radian,degree,rad2deg,deg2rad);
2754    RpUnits::define(radian,gradian,rad2grad,grad2rad);
2755
2756    return 0;
2757}
2758
2759/**********************************************************************/
2760// METHOD: addPresetMass()
2761/// Add Mass related units to the dictionary
2762/**
2763 * Defines the following units:
2764 *   gram  (g)
2765 *
2766 * Return codes: 0 success, anything else is error
2767 */
2768
2769int
2770RpUnitsPreset::addPresetMass () {
2771
2772    RpUnits* gram  = NULL;
2773
2774    gram  = RpUnits::define("g", NULL, RP_TYPE_MASS, RPUNITS_METRIC);
2775
2776    return 0;
2777}
2778
2779/**********************************************************************/
2780// METHOD: addPresetPressure()
2781/// Add pressure related units to the dictionary
2782/**
2783 * http://www.ilpi.com/msds/ref/pressureunits.html
2784 *
2785 * Defines the following units:
2786 *   atmosphere             (atm)
2787 *   bar                    (bar)
2788 *   pascal                 (Pa)
2789 *   pounds/(in^2)          (psi)
2790 *   torr                   (torr)
2791 *   millimeters Mercury    (mmHg)
2792 *
2793 * mmHg was added because as a convenience to those who have not
2794 * yet switched over to the new representation of torr.
2795 *
2796 * Return codes: 0 success, anything else is error
2797 */
2798
2799int
2800RpUnitsPreset::addPresetPressure () {
2801
2802    RpUnits* atmosphere = NULL;
2803    RpUnits* bar        = NULL;
2804    RpUnits* pascal     = NULL;
2805    RpUnits* psi        = NULL;
2806    RpUnits* torr       = NULL;
2807    RpUnits* mmHg       = NULL;
2808
2809    atmosphere  = RpUnits::define("atm", NULL, RP_TYPE_PRESSURE);
2810    bar     = RpUnits::define("bar",  NULL, RP_TYPE_PRESSURE, RPUNITS_METRIC);
2811    pascal  = RpUnits::define("Pa",   NULL, RP_TYPE_PRESSURE, RPUNITS_METRIC);
2812    psi     = RpUnits::define("psi",  NULL, RP_TYPE_PRESSURE);
2813    torr    = RpUnits::define("torr", NULL, RP_TYPE_PRESSURE);
2814    mmHg    = RpUnits::define("mmHg", torr, RP_TYPE_PRESSURE);
2815
2816    RpUnits::define(bar,pascal,bar2Pa,Pa2bar);
2817    RpUnits::define(bar,atmosphere,bar2atm,atm2bar);
2818    RpUnits::define(bar,psi,bar2psi,psi2bar);
2819    RpUnits::define(bar,torr,bar2torr,torr2bar);
2820    RpUnits::define(pascal,atmosphere,Pa2atm,atm2Pa);
2821    RpUnits::define(pascal,torr,Pa2torr,torr2Pa);
2822    RpUnits::define(pascal,psi,Pa2psi,psi2Pa);
2823    RpUnits::define(torr,atmosphere,torr2atm,atm2torr);
2824    RpUnits::define(torr,psi,torr2psi,psi2torr);
2825    RpUnits::define(atmosphere,psi,atm2psi,psi2atm);
2826
2827    RpUnits::define(torr,mmHg,torr2mmHg,mmHg2torr);
2828
2829    return 0;
2830}
2831
2832/**********************************************************************/
2833// METHOD: addPresetConcentration()
2834/// Add concentration related units to the dictionary
2835/**
2836 *
2837 * Defines the following units:
2838 *   pH    (pH)
2839 *   pOH    (pOH)
2840 *
2841 * Return codes: 0 success, anything else is error
2842 */
2843
2844int
2845RpUnitsPreset::addPresetConcentration () {
2846
2847    RpUnits* pH  = NULL;
2848    RpUnits* pOH = NULL;
2849
2850    pH  = RpUnits::define("pH",  NULL, RP_TYPE_CONC);
2851    pOH = RpUnits::define("pOH", NULL, RP_TYPE_CONC);
2852
2853    // add concentration definitions
2854    RpUnits::define(pH,pOH,pH2pOH,pOH2pH);
2855
2856    return 0;
2857}
2858
2859/**********************************************************************/
2860// METHOD: addPresetForce()
2861/// Add concentration related units to the dictionary
2862/**
2863 * http://en.wikipedia.org/wiki/Newton
2864 *
2865 * Defines the following units:
2866 *   newton    (N)
2867 *
2868 * Return codes: 0 success, anything else is error
2869 */
2870
2871int
2872RpUnitsPreset::addPresetForce () {
2873
2874    RpUnits* newton = NULL;
2875
2876    newton = RpUnits::define("N",  NULL, RP_TYPE_FORCE, RPUNITS_METRIC);
2877
2878    return 0;
2879}
2880
2881/**********************************************************************/
2882// METHOD: addPresetMisc()
2883/// Add Misc related units to the dictionary
2884/**
2885 * Defines the following units:
2886 *   mole  (mol)
2887 *
2888 * Return codes: 0 success, anything else is error
2889 */
2890
2891int
2892RpUnitsPreset::addPresetMisc () {
2893
2894    RpUnits* volt      = NULL;
2895    RpUnits* mole      = NULL;
2896    RpUnits* hertz     = NULL;
2897    RpUnits* becquerel = NULL;
2898    RpUnits* amu       = NULL;
2899    RpUnits* bel       = NULL;
2900
2901    volt      = RpUnits::define("V",  NULL, RP_TYPE_EPOT, RPUNITS_METRIC);
2902    mole      = RpUnits::define("mol",NULL, "quantity", RPUNITS_METRIC);
2903    hertz     = RpUnits::define("Hz", NULL, "frequency", RPUNITS_METRIC);
2904    becquerel = RpUnits::define("Bq", NULL, "radioactivity", RPUNITS_METRIC);
2905    amu       = RpUnits::define("amu", NULL, "mass_unit", !RPUNITS_METRIC);
2906    bel       = RpUnits::define("B", NULL, "audio_transmission", RPUNITS_METRIC);
2907
2908    // RpUnits* percent   = RpUnits::define("%",  NULL, RP_TYPE_MISC);
2909
2910    return 0;
2911}
2912
2913RpUnitsTypes::RpUnitsTypesHint
2914RpUnitsTypes::getTypeHint (std::string type) {
2915
2916    if (type.compare(RP_TYPE_ENERGY) == 0) {
2917        return &RpUnitsTypes::hintTypeEnergy;
2918    }
2919    else if (type.compare(RP_TYPE_EPOT) == 0) {
2920        return &RpUnitsTypes::hintTypeEPot;
2921    }
2922    else if (type.compare(RP_TYPE_LENGTH) == 0) {
2923        return &RpUnitsTypes::hintTypeLength;
2924    }
2925    else if (type.compare(RP_TYPE_TEMP) == 0) {
2926        return &RpUnitsTypes::hintTypeTemp;
2927    }
2928    else if (type.compare(RP_TYPE_TIME) == 0) {
2929        return &RpUnitsTypes::hintTypeTime;
2930    }
2931    else if (type.compare(RP_TYPE_VOLUME) == 0) {
2932        return &RpUnitsTypes::hintTypeVolume;
2933    }
2934    else if (type.compare(RP_TYPE_ANGLE) == 0) {
2935        return &RpUnitsTypes::hintTypeAngle;
2936    }
2937    else if (type.compare(RP_TYPE_MASS) == 0) {
2938        return &RpUnitsTypes::hintTypeMass;
2939    }
2940    else if (type.compare(RP_TYPE_PREFIX) == 0) {
2941        return &RpUnitsTypes::hintTypePrefix;
2942    }
2943    else if (type.compare(RP_TYPE_PRESSURE) == 0) {
2944        return &RpUnitsTypes::hintTypePressure;
2945    }
2946    else if (type.compare(RP_TYPE_CONC) == 0) {
2947        return &RpUnitsTypes::hintTypeConc;
2948    }
2949    else if (type.compare(RP_TYPE_CONC) == 0) {
2950        return &RpUnitsTypes::hintTypeForce;
2951    }
2952    else if (type.compare(RP_TYPE_MISC) == 0) {
2953        return &RpUnitsTypes::hintTypeMisc;
2954    }
2955    else {
2956        return NULL;
2957    }
2958};
2959
2960bool
2961RpUnitsTypes::hintTypePrefix   (   RpUnits* unitObj    ) {
2962
2963    bool retVal = false;
2964
2965    if ( (unitObj->getType()).compare(RP_TYPE_PREFIX) == 0 ) {
2966        retVal = true;
2967    }
2968
2969    return retVal;
2970}
2971
2972bool
2973RpUnitsTypes::hintTypeNonPrefix    (   RpUnits* unitObj    ) {
2974
2975    bool retVal = true;
2976
2977    if ( (unitObj->getType()).compare(RP_TYPE_PREFIX) == 0 ) {
2978        retVal = false;
2979    }
2980
2981    return retVal;
2982}
2983
2984bool
2985RpUnitsTypes::hintTypeEnergy   (   RpUnits* unitObj    ) {
2986
2987    bool retVal = false;
2988
2989    if ( (unitObj->getType()).compare(RP_TYPE_ENERGY) == 0 ) {
2990        retVal = true;
2991    }
2992
2993    return retVal;
2994}
2995
2996bool
2997RpUnitsTypes::hintTypeEPot   (   RpUnits* unitObj    ) {
2998
2999    bool retVal = false;
3000
3001    if ( (unitObj->getType()).compare(RP_TYPE_EPOT) == 0 ) {
3002        retVal = true;
3003    }
3004
3005    return retVal;
3006}
3007
3008bool
3009RpUnitsTypes::hintTypeLength   (   RpUnits* unitObj    ) {
3010
3011    bool retVal = false;
3012
3013    if ( (unitObj->getType()).compare(RP_TYPE_LENGTH) == 0 ) {
3014        retVal = true;
3015    }
3016
3017    return retVal;
3018}
3019
3020bool
3021RpUnitsTypes::hintTypeTemp   (   RpUnits* unitObj    ) {
3022
3023    bool retVal = false;
3024
3025    if ( (unitObj->getType()).compare(RP_TYPE_TEMP) == 0 ) {
3026        retVal = true;
3027    }
3028
3029    return retVal;
3030}
3031
3032bool
3033RpUnitsTypes::hintTypeTime   (   RpUnits* unitObj    ) {
3034
3035    bool retVal = false;
3036
3037    if ( (unitObj->getType()).compare(RP_TYPE_TIME) == 0 ) {
3038        retVal = true;
3039    }
3040
3041    return retVal;
3042}
3043
3044bool
3045RpUnitsTypes::hintTypeVolume   (   RpUnits* unitObj    ) {
3046
3047    bool retVal = false;
3048
3049    if ( (unitObj->getType()).compare(RP_TYPE_VOLUME) == 0 ) {
3050        retVal = true;
3051    }
3052
3053    return retVal;
3054}
3055
3056bool
3057RpUnitsTypes::hintTypeAngle   (   RpUnits* unitObj    ) {
3058
3059    bool retVal = false;
3060
3061    if ( (unitObj->getType()).compare(RP_TYPE_ANGLE) == 0 ) {
3062        retVal = true;
3063    }
3064
3065    return retVal;
3066}
3067
3068bool
3069RpUnitsTypes::hintTypeMass   (   RpUnits* unitObj    ) {
3070
3071    bool retVal = false;
3072
3073    if ( (unitObj->getType()).compare(RP_TYPE_MASS) == 0 ) {
3074        retVal = true;
3075    }
3076
3077    return retVal;
3078}
3079
3080bool
3081RpUnitsTypes::hintTypePressure   (   RpUnits* unitObj    ) {
3082
3083    bool retVal = false;
3084
3085    if ( (unitObj->getType()).compare(RP_TYPE_PRESSURE) == 0 ) {
3086        retVal = true;
3087    }
3088
3089    return retVal;
3090}
3091
3092bool
3093RpUnitsTypes::hintTypeConc   (   RpUnits* unitObj    ) {
3094
3095    bool retVal = false;
3096
3097    if ( (unitObj->getType()).compare(RP_TYPE_CONC) == 0 ) {
3098        retVal = true;
3099    }
3100
3101    return retVal;
3102}
3103
3104bool
3105RpUnitsTypes::hintTypeForce   (   RpUnits* unitObj    ) {
3106
3107    bool retVal = false;
3108
3109    if ( (unitObj->getType()).compare(RP_TYPE_FORCE) == 0 ) {
3110        retVal = true;
3111    }
3112
3113    return retVal;
3114}
3115
3116bool
3117RpUnitsTypes::hintTypeMisc   (   RpUnits* unitObj    ) {
3118
3119    bool retVal = false;
3120
3121    if ( (unitObj->getType()).compare(RP_TYPE_MISC) == 0 ) {
3122        retVal = true;
3123    }
3124
3125    return retVal;
3126}
3127
3128// -------------------------------------------------------------------- //
3129
3130/**********************************************************************/
3131// FUNCTION: list2str()
3132/// Convert a std::list<std::string> into a comma delimited std::string
3133/**
3134 * Iterates through a std::list<std::string> and returns a comma
3135 * delimited std::string containing the elements of the inputted std::list.
3136 *
3137 * Returns 0 on success, anything else is error
3138 */
3139
3140int
3141list2str (std::list<std::string>& inList, std::string& outString)
3142{
3143    int retVal = 1;  // return Value 0 is success, everything else is failure
3144    unsigned int counter = 0; // check if we hit all elements of inList
3145    std::list<std::string>::iterator inListIter; // list interator
3146
3147    inListIter = inList.begin();
3148
3149    while (inListIter != inList.end()) {
3150        if ( outString.empty() ) {
3151            outString = *inListIter;
3152        }
3153        else {
3154            outString =  outString + "," + *inListIter;
3155        }
3156
3157        // increment the iterator and loop counter
3158        inListIter++;
3159        counter++;
3160    }
3161
3162    if (counter == inList.size()) {
3163        retVal = 0;
3164    }
3165
3166    return retVal;
3167}
3168
3169/**********************************************************************/
3170// FUNCTION: unitSlice()
3171/// Convert a std::string into what might be the value and units
3172/**
3173 * Returns 0 on success, anything else is error
3174 */
3175
3176int
3177unitSlice (std::string inStr, std::string& outUnits, double& outVal)
3178{
3179    int retVal      = 0;  // return val 0 is success, otherwise failure
3180    char *endptr    = NULL;
3181
3182    outVal = strtod(inStr.c_str(), &endptr);
3183
3184    if ( (outVal == 0) && (endptr == inStr.c_str()) ) {
3185        // no conversion performed
3186        retVal = 1;
3187    }
3188    else {
3189    }
3190
3191    outUnits = std::string(endptr);
3192
3193    return retVal;
3194}
Note: See TracBrowser for help on using the repository browser.