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

Last change on this file since 1782 was 1782, checked in by dkearney, 14 years ago

patching units code to ignore whitespace within unit strings. adding test cases to the units test suite. this patch is in regard to nanohub ticket #257716

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