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

Last change on this file since 5673 was 5673, checked in by ldelgass, 9 years ago

Fix line endings, set eol-style to native on all C/C++ sources.

  • Property svn:eol-style set to native
File size: 92.2 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-2012  HUBzero Foundation, LLC
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 numVal = 0;
1338    double toExp = 0;
1339    double fromExp = 0;
1340    int convErr = 0;
1341    std::stringstream outVal;
1342
1343    double copies = 0;
1344
1345    std::list<std::string> compatList;
1346    std::string listStr;
1347
1348    convertList cList;
1349    convertList totalConvList;
1350
1351
1352    // set  default result flag/error code
1353    if (result) {
1354        *result = 0;
1355    }
1356
1357    // search our string to see where the numeric part stops
1358    // and the units part starts
1359    //
1360    //  convert("5J", "neV") => 3.12075e+28neV
1361    //  convert("3.12075e+28neV", "J") => 4.99999J
1362    // now we can actually get the scientific notation portion of the string.
1363    //
1364
1365    convErr = unitSlice(val,fromUnitsName,numVal);
1366
1367    if (convErr != 0) {
1368        // no conversion was done.
1369        // number in incorrect format probably.
1370        if (result) {
1371            *result = 1;
1372        }
1373        return val;
1374    }
1375
1376    if (toUnitsName.empty())  {
1377        // there were no units in the input
1378        // string or no conversion needed
1379        // assume fromUnitsName = toUnitsName
1380        // return the correct value
1381        if (result) {
1382            *result = 0;
1383        }
1384
1385        if (showUnits == RPUNITS_UNITS_ON) {
1386            outVal << numVal << fromUnitsName;
1387        }
1388        else {
1389            outVal << numVal;
1390        }
1391
1392        return std::string(outVal.str());
1393    }
1394
1395    // check if the fromUnitsName is empty or
1396    // if the fromUnitsName == toUnitsName
1397    // these are conditions where no conversion is needed
1398    if ( (fromUnitsName.empty()) || (toUnitsName == fromUnitsName) )  {
1399        // there were no units in the input
1400        // string or no conversion needed
1401        // assume fromUnitsName = toUnitsName
1402        // return the correct value
1403        if (result) {
1404            *result = 0;
1405        }
1406
1407        if (showUnits == RPUNITS_UNITS_ON) {
1408            outVal << numVal << toUnitsName;
1409        }
1410        else {
1411            outVal << numVal;
1412        }
1413
1414        return std::string(outVal.str());
1415    }
1416
1417    convErr = RpUnits::units2list(toUnitsName,toUnitsList,type);
1418    if (convErr) {
1419        if (result) {
1420            *result = convErr;
1421        }
1422        retStr = "Unrecognized units: \"" + toUnitsName + "\". Please specify valid Rappture Units";
1423        return retStr;
1424    }
1425
1426    convErr = RpUnits::units2list(fromUnitsName,fromUnitsList,type);
1427    if (convErr) {
1428        if (result) {
1429            *result = convErr;
1430        }
1431        type = "";
1432        RpUnits::validate(toUnitsName,type,&compatList);
1433        list2str(compatList,listStr);
1434        retStr = "Unrecognized units: \"" + fromUnitsName
1435                + "\".\nShould be units of type " + type + " (" + listStr + ")";
1436        return retStr;
1437    }
1438
1439    fromIter = fromUnitsList.begin();
1440    toIter = toUnitsList.begin();
1441
1442    while ( (toIter != toUnitsList.end()) && (fromIter != fromUnitsList.end()) && (!convErr) ) {
1443        fromUnits = fromIter->getUnitsObj();
1444        fromPrefix = fromIter->getPrefix();
1445        toUnits = toIter->getUnitsObj();
1446        toPrefix = toIter->getPrefix();
1447
1448        cList.clear();
1449
1450        if (fromPrefix != NULL) {
1451            cList.push_back(fromPrefix->convList->conv->convForwFxnPtr);
1452        }
1453
1454        convErr = fromUnits->getConvertFxnList(toUnits, cList);
1455
1456        if (toPrefix != NULL) {
1457            cList.push_back(toPrefix->convList->conv->convBackFxnPtr);
1458        }
1459
1460        if (convErr == 0) {
1461
1462            toExp = toIter->getExponent();
1463            fromExp = fromIter->getExponent();
1464
1465            if (fromExp == toExp) {
1466                copies = fromExp;
1467                if (fromExp < 0) {
1468                    copies = copies * -1.00;
1469                    totalConvList.push_back(&invert);
1470                }
1471                while (copies > 0) {
1472                    combineLists(totalConvList,cList);
1473                    copies--;
1474                }
1475                if (fromExp < 0) {
1476                    totalConvList.push_back(&invert);
1477                }
1478            }
1479            else {
1480                // currently we cannot handle conversions of
1481                // units where the exponents are different
1482                convErr++;
1483            }
1484
1485        }
1486
1487        if (convErr == 0) {
1488            // successful conversion reported
1489            // remove the elements from the lists
1490            tempIter = toIter;
1491            toIter++;
1492            toUnitsList.erase(tempIter);
1493
1494            tempIter = fromIter;
1495            fromUnitsList.erase(tempIter);
1496            fromIter = fromUnitsList.begin();
1497        }
1498        else {
1499            // no conversion available?
1500            fromIter++;
1501            if (fromIter == fromUnitsList.end()) {
1502
1503                fromIter = fromUnitsList.begin();
1504                toIter++;
1505
1506                if (toIter == toUnitsList.end())  {
1507
1508                    toIter = toUnitsList.begin();
1509
1510                    // raise error that there was an
1511                    // unrecognized conversion request
1512
1513                    convErr++;
1514                    retStr = "Conversion unavailable: (";
1515                    while (fromIter != fromUnitsList.end()) {
1516                        /*
1517                        if (fromIter != fromUnitsList.begin()) {
1518                            retStr += " or ";
1519                        }
1520                        */
1521                        retStr += fromIter->name();
1522                        fromIter++;
1523                    }
1524                    retStr += ") -> (";
1525
1526                    // tempIter = toIter;
1527
1528                    while (toIter != toUnitsList.end()) {
1529                        retStr += toIter->name();
1530                        toIter++;
1531                    }
1532                    retStr += ")";
1533
1534                    type = "";
1535                    RpUnits::validate(toUnitsName,type,&compatList);
1536                    list2str(compatList,listStr);
1537                    retStr += "\nPlease enter units of type "
1538                                + type + " (" + listStr + ")";
1539
1540
1541                    // exit and report the error
1542
1543                    /*
1544                    toIter = tempIter;
1545                    toIter++;
1546                    toUnitsList.erase(tempIter);
1547                    */
1548                }
1549                else {
1550                    // keep searching for units to convert
1551                    // until we are out of units in the
1552                    // fromUnitsList and toUnitsList.
1553
1554                    convErr = 0;
1555                }
1556            }
1557            else {
1558                // keep searching for units to convert
1559                // until we are out of units in the
1560                // fromUnitsList and toUnitsList.
1561
1562                convErr = 0;
1563            }
1564        }
1565    }
1566
1567
1568
1569    if (convErr == 0) {
1570        // if ( (fromIter != fromUnitsList.end()) || (toIter != toUnitsList.end()) ) {
1571        if ( fromUnitsList.size() || toUnitsList.size() ) {
1572            // raise error that there was an
1573            // unrecognized conversion request
1574
1575            convErr++;
1576            retStr = "unmatched units in conversion: (";
1577
1578            fromIter = fromUnitsList.begin();
1579            while (fromIter != fromUnitsList.end()) {
1580                retStr += fromIter->name();
1581                fromIter++;
1582            }
1583
1584            if (fromUnitsList.size() && toUnitsList.size()) {
1585                retStr += ") -> (";
1586            }
1587
1588            toIter = toUnitsList.begin();
1589            while (toIter != toUnitsList.end()) {
1590                retStr += toIter->name();
1591                toIter++;
1592            }
1593            retStr += ")";
1594            type = "";
1595            RpUnits::validate(toUnitsName,type,&compatList);
1596            list2str(compatList,listStr);
1597            retStr += "\nPlease enter units of type "
1598                        + type + " (" + listStr + ")";
1599
1600        }
1601        else {
1602            // apply the conversion and check for errors
1603            convErr = applyConversion (&numVal, totalConvList);
1604            if (convErr == 0) {
1605                // outVal.flags(std::ios::fixed);
1606                // outVal.precision(10);
1607                if (showUnits == RPUNITS_UNITS_ON) {
1608                    outVal << numVal << toUnitsName;
1609                }
1610                else {
1611                    outVal << numVal;
1612                }
1613                retStr = outVal.str();
1614            }
1615            else {
1616
1617            }
1618        }
1619    }
1620
1621    if ( (result) && (*result == 0) ) {
1622        *result = convErr;
1623    }
1624
1625    return retStr;
1626
1627}
1628
1629/**********************************************************************/
1630// METHOD: convert()
1631/// Convert between RpUnits return a string value with or without units
1632/**
1633 * Returns a string value with or without units.
1634 */
1635
1636std::string
1637RpUnits::convert ( const  RpUnits* toUnits,
1638                   double val,
1639                   int showUnits,
1640                   int* result )  const {
1641
1642    double retVal = convert(toUnits,val,result);
1643    std::stringstream unitText;
1644
1645
1646    if (showUnits == RPUNITS_UNITS_ON) {
1647        unitText << retVal << toUnits->getUnitsName();
1648    }
1649    else {
1650        unitText << retVal;
1651    }
1652
1653    return (std::string(unitText.str()));
1654
1655}
1656
1657/**********************************************************************/
1658// METHOD: convert()
1659/// Convert between RpUnits using an RpUnits Object to describe toUnit.
1660/**
1661 * User function to convert a value to the provided RpUnits* toUnits
1662 * if it exists as a conversion from the basis
1663 * example
1664 *      cm.convert(meter,10)
1665 *      cm.convert(angstrum,100)
1666 *
1667 * Returns a double value without units.
1668 */
1669
1670double
1671RpUnits::convert(const RpUnits* toUnit, double val, int* result) const {
1672
1673    // currently we convert this object to its basis and look for the
1674    // connection to the toUnit object from the basis.
1675
1676    double value = val;
1677    const RpUnits* toBasis = toUnit->getBasis();
1678    const RpUnits* fromUnit = this;
1679    const RpUnits* dictToUnit = NULL;
1680    convEntry *p;
1681    int my_result = 0;
1682
1683    RpUnitsTypes::RpUnitsTypesHint hint = NULL;
1684
1685    // set *result to a default value
1686    if (result) {
1687        *result = 1;
1688    }
1689
1690    // guard against converting to the units you are converting from...
1691    // ie. meters->meters
1692    if (this->getUnitsName() == toUnit->getUnitsName()) {
1693        if (result) {
1694            *result = 0;
1695        }
1696        return val;
1697    }
1698
1699    // convert unit to the basis
1700    // makeBasis(&value);
1701    // trying to avoid the recursive way of converting to the basis.
1702    // need to rethink this.
1703    //
1704    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
1705        value = convert(basis,value,&my_result);
1706        if (my_result == 0) {
1707            fromUnit = basis;
1708        }
1709    }
1710
1711    // find the toUnit in our dictionary.
1712    // if the toUnits has a basis, we need to search for the basis
1713    // and convert between basis' and then convert again back to the
1714    // original unit.
1715    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1716        hint = RpUnitsTypes::getTypeHint(toBasis->getType());
1717        dictToUnit = find(toBasis->getUnitsName(), hint);
1718    }
1719    else {
1720        hint = RpUnitsTypes::getTypeHint(toUnit->getType());
1721        dictToUnit = find(toUnit->getUnitsName(), hint);
1722    }
1723
1724    // did we find the unit in the dictionary?
1725    if (dictToUnit == NULL) {
1726        // toUnit was not found in the dictionary
1727        return val;
1728    }
1729
1730    // search through the conversion list to find
1731    // the conversion to the toUnit.
1732
1733    if (basis) {
1734        p = basis->convList;
1735    }
1736    else {
1737        p = this->convList;
1738    }
1739
1740    if (p == NULL) {
1741        // there are no conversions
1742        return val;
1743    }
1744
1745    // loop through our conversion list looking for the correct conversion
1746    do {
1747
1748        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
1749            // we found our conversion
1750            // call the function pointer with value
1751
1752            // this should probably be re thought out
1753            // the problem is that convForwFxnPtr has the conversion for a
1754            // one arg conv function pointer and convForwFxnPtrDD has the
1755            // conversion for a two arg conv function pointer
1756            // need to make this simpler, more logical maybe only allow 2 arg
1757            if (       (p->conv->convForwFxnPtr)
1758                    && (! p->conv->convForwFxnPtrDD) ) {
1759
1760                value = p->conv->convForwFxnPtr(value);
1761            }
1762            else if (  (p->conv->convForwFxnPtrDD)
1763                    && (! p->conv->convForwFxnPtr) ) {
1764
1765                value =
1766                    p->conv->convForwFxnPtrDD(value, fromUnit->getExponent());
1767            }
1768
1769            // check to see if we converted to the actual requested unit
1770            // or to the requested unit's basis.
1771            // if we converted to the requested unit's basis. we need to
1772            // do one last conversion from the requested unit's basis back
1773            // to the requested unit.
1774            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1775                my_result = 0;
1776                value = toBasis->convert(toUnit,value,&my_result);
1777                if (my_result != 0) {
1778                    if (result) {
1779                        *result += 1;
1780                    }
1781                }
1782            }
1783
1784            // change the result code to zero, a conversion was performed
1785            // (we think)... its ture that it is possible to get to this
1786            // point and have skipped the conversion because the
1787            // conversion object was not properly created...
1788            // ie. both fxn ptrs were null or neither fxn ptr was null
1789            //
1790            if (result && (*result == 1)) {
1791                *result = 0;
1792            }
1793            break;
1794        }
1795
1796        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
1797            // we found our conversion
1798            // call the function pointer with value
1799
1800            // this should probably be re thought out
1801            // the problem is that convForwFxnPtr has the conversion for a
1802            // one arg conv function pointer and convForwFxnPtrDD has the
1803            // conversion for a two arg conv function pointer
1804            // need to make this simpler, more logical maybe only allow 2 arg
1805            if (       (p->conv->convBackFxnPtr)
1806                    && (! p->conv->convBackFxnPtrDD) ) {
1807
1808                value = p->conv->convBackFxnPtr(value);
1809            }
1810            else if (  (p->conv->convBackFxnPtrDD)
1811                    && (! p->conv->convBackFxnPtr) ) {
1812
1813                value =
1814                    p->conv->convBackFxnPtrDD(value, fromUnit->getExponent());
1815            }
1816
1817            // check to see if we converted to the actual requested unit
1818            // or to the requested unit's basis.
1819            // if we converted to the requested unit's basis. we need to
1820            // do one last conversion from the requested unit's basis back
1821            // to the requested unit.
1822            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1823                my_result = 0;
1824                value = toBasis->convert(toUnit,value,&my_result);
1825                if (my_result != 0) {
1826                    if (result) {
1827                        *result += 1;
1828                    }
1829                }
1830            }
1831
1832            // change the result code to zero, a conversion was performed
1833            // (we think)... its ture that it is possible to get to this
1834            // point and have skipped the conversion because the
1835            // conversion object was not properly created...
1836            // ie. both fxn ptrs were null or neither fxn ptr was null
1837            //
1838            if (result && (*result == 1)) {
1839                *result = 0;
1840            }
1841            break;
1842        }
1843
1844        p = p->next;
1845
1846    } while (p != NULL);
1847
1848
1849    if ( p == NULL) {
1850        // we did not find the conversion
1851        if (result) {
1852            *result += 1;
1853        }
1854        return val;
1855    }
1856
1857    // we found the conversion.
1858    // return the converted value.
1859    return value;
1860
1861}
1862
1863
1864/**********************************************************************/
1865// METHOD: convert()
1866/// Convert a value between RpUnits using user defined conversions
1867/**
1868 */
1869
1870void*
1871RpUnits::convert(const RpUnits* toUnit, void* val, int* result) const {
1872
1873    // currently we convert this object to its basis and look for the
1874    // connection ot the toUnit object from the basis.
1875
1876    void* value = val;
1877    const RpUnits* toBasis = toUnit->getBasis();
1878    const RpUnits* fromUnit = this;
1879    const RpUnits* dictToUnit = NULL;
1880    convEntry *p;
1881    int my_result = 0;
1882
1883    RpUnitsTypes::RpUnitsTypesHint hint = NULL;
1884
1885    // set *result to a default value
1886    if (result) {
1887        *result = 1;
1888    }
1889
1890    // guard against converting to the units you are converting from...
1891    // ie. meters->meters
1892    if (this->getUnitsName() == toUnit->getUnitsName()) {
1893        if (result) {
1894            *result = 0;
1895        }
1896        return val;
1897    }
1898
1899    // convert unit to the basis
1900    // makeBasis(&value);
1901    // trying to avoid the recursive way of converting to the basis.
1902    // need to rethink this.
1903    //
1904    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
1905        value = convert(basis,value,&my_result);
1906        if (my_result == 0) {
1907            fromUnit = basis;
1908        }
1909    }
1910
1911    // find the toUnit in our dictionary.
1912    // if the toUnits has a basis, we need to search for the basis
1913    // and convert between basis' and then convert again back to the
1914    // original unit.
1915    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1916        hint = RpUnitsTypes::getTypeHint(toBasis->getType());
1917        dictToUnit = find(toBasis->getUnitsName(), hint);
1918    }
1919    else {
1920        hint = RpUnitsTypes::getTypeHint(toUnit->getType());
1921        dictToUnit = find(toUnit->getUnitsName(), hint);
1922    }
1923
1924    // did we find the unit in the dictionary?
1925    if (dictToUnit == NULL) {
1926        // toUnit was not found in the dictionary
1927        return val;
1928    }
1929
1930    // search through the conversion list to find
1931    // the conversion to the toUnit.
1932
1933    if (basis) {
1934        p = basis->convList;
1935    }
1936    else {
1937        p = this->convList;
1938    }
1939
1940    if (p == NULL) {
1941        // there are no conversions
1942        return val;
1943    }
1944
1945    // loop through our conversion list looking for the correct conversion
1946    do {
1947
1948        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
1949            // we found our conversion
1950            // call the function pointer with value
1951
1952            value = p->conv->convForwFxnPtrVoid(p->conv->convForwData,value);
1953
1954            // check to see if we converted to the actual requested unit
1955            // or to the requested unit's basis.
1956            // if we converted to the requested unit's basis. we need to
1957            // do one last conversion from the requested unit's basis back
1958            // to the requested unit.
1959            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1960                my_result = 0;
1961                value = toBasis->convert(toUnit,value,&my_result);
1962                if (my_result != 0) {
1963                    if (result) {
1964                        *result += 1;
1965                    }
1966                }
1967            }
1968
1969            // change the result code to zero, a conversion was performed
1970            // (we think)... its ture that it is possible to get to this
1971            // point and have skipped the conversion because the
1972            // conversion object was not properly created...
1973            // ie. both fxn ptrs were null or neither fxn ptr was null
1974            //
1975            if (result && (*result == 1)) {
1976                *result = 0;
1977            }
1978            break;
1979        }
1980
1981        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
1982            // we found our conversion
1983            // call the function pointer with value
1984
1985            value = p->conv->convBackFxnPtrVoid(p->conv->convBackData,value);
1986
1987            // check to see if we converted to the actual requested unit
1988            // or to the requested unit's basis.
1989            // if we converted to the requested unit's basis. we need to
1990            // do one last conversion from the requested unit's basis back
1991            // to the requested unit.
1992            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
1993                my_result = 0;
1994                value = toBasis->convert(toUnit,value,&my_result);
1995                if (my_result != 0) {
1996                    if (result) {
1997                        *result += 1;
1998                    }
1999                }
2000            }
2001
2002            // change the result code to zero, a conversion was performed
2003            // (we think)... its ture that it is possible to get to this
2004            // point and have skipped the conversion because the
2005            // conversion object was not properly created...
2006            // ie. both fxn ptrs were null or neither fxn ptr was null
2007            //
2008            if (result && (*result == 1)) {
2009                *result = 0;
2010            }
2011            break;
2012        }
2013
2014        p = p->next;
2015
2016    } while (p != NULL);
2017
2018
2019    if ( p == NULL) {
2020        // we did not find the conversion
2021        if (result) {
2022            *result += 1;
2023        }
2024        return val;
2025    }
2026
2027    // we found the conversion.
2028    // return the converted value.
2029    return value;
2030
2031}
2032
2033/**********************************************************************/
2034// METHOD: getConvertFxnList()
2035/// Return list of fxn pointers for converting two simple RpUnits objects.
2036/**
2037 * Return the conversion list that will convert from this RpUnits
2038 * object to the provided toUnits object if the conversion is defined
2039 * example
2040 *      cm.getConvertFxnList(meter,cList)
2041 *      cm.getConvertFxnList(angstrum,cList)
2042 *
2043 * Returns a list of conversion objects, represented by cList,
2044 * on success that a value can be applied to. The return value
2045 * will be zero (0).
2046 * Returns non-zero value on failure.
2047 */
2048
2049int
2050RpUnits::getConvertFxnList(const RpUnits* toUnit, convertList& cList) const {
2051
2052    // currently we convert this object to its basis and look for the
2053    // connection to the toUnit object from the basis.
2054
2055    const RpUnits* toBasis = toUnit->getBasis();
2056    const RpUnits* fromUnit = this;
2057    const RpUnits* dictToUnit = NULL;
2058    convEntry *p;
2059    int result = 0;
2060
2061    // guard against converting to the units you are converting from...
2062    // ie. meters->meters
2063    if (this->getUnitsName() == toUnit->getUnitsName()) {
2064        return result;
2065    }
2066
2067    // convert unit to the basis
2068    // makeBasis(&value);
2069    // trying to avoid the recursive way of converting to the basis.
2070    // need to rethink this.
2071    //
2072    if ( (basis) && (basis->getUnitsName() != toUnit->getUnitsName()) ) {
2073        result = fromUnit->getConvertFxnList(basis,cList);
2074        if (result == 0) {
2075            fromUnit = basis;
2076        }
2077        else {
2078            // exit because an error occured while
2079            // trying to convert to the basis
2080            return result;
2081        }
2082    }
2083
2084    // find the toUnit in our dictionary.
2085    // if the toUnits has a basis, we need to search for the basis
2086    // and convert between basis' and then convert again back to the
2087    // original unit.
2088    if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
2089        dictToUnit = find(  toBasis->getUnitsName(),
2090                            &RpUnitsTypes::hintTypeNonPrefix );
2091    }
2092    else {
2093        dictToUnit = find(  toUnit->getUnitsName(),
2094                            &RpUnitsTypes::hintTypeNonPrefix );
2095    }
2096
2097    // did we find the unit in the dictionary?
2098    if (dictToUnit == NULL) {
2099        // toUnit was not found in the dictionary
2100        result = 1;
2101        return result;
2102    }
2103
2104    // search through the conversion list to find
2105    // the conversion to the toUnit.
2106
2107    if (basis) {
2108        p = basis->convList;
2109    }
2110    else {
2111        p = this->convList;
2112    }
2113
2114    if (p == NULL) {
2115        // there are no conversions
2116        result = 1;
2117        return result;
2118    }
2119
2120    // loop through our conversion list looking for the correct conversion
2121    do {
2122
2123        if ( (p->conv->toPtr == dictToUnit) && (p->conv->fromPtr == fromUnit) ) {
2124            // we found our conversion
2125            // call the function pointer with value
2126
2127            // this should probably be re thought out
2128            // the problem is that convForwFxnPtr has the conversion for a
2129            // one arg conv function pointer and convForwFxnPtrDD has the
2130            // conversion for a two arg conv function pointer
2131            // need to make this simpler, more logical maybe only allow 2 arg
2132            if (       (p->conv->convForwFxnPtr)
2133                    && (! p->conv->convForwFxnPtrDD) ) {
2134
2135                // value = p->conv->convForwFxnPtr(value);
2136                cList.push_back(p->conv->convForwFxnPtr);
2137            }
2138            /*
2139            else if (  (p->conv->convForwFxnPtrDD)
2140                    && (! p->conv->convForwFxnPtr) ) {
2141
2142                // value = p->conv->convForwFxnPtrDD(value, fromUnit->getExponent());
2143                cList.pushback(conv);
2144            }
2145            */
2146
2147            // check to see if we converted to the actual requested unit
2148            // or to the requested unit's basis.
2149            // if we converted to the requested unit's basis. we need to
2150            // do one last conversion from the requested unit's basis back
2151            // to the requested unit.
2152            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
2153                result += toBasis->getConvertFxnList(toUnit,cList);
2154            }
2155
2156            break;
2157        }
2158
2159        if ( (p->conv->toPtr == fromUnit) && (p->conv->fromPtr == dictToUnit) ) {
2160            // we found our conversion
2161            // call the function pointer with value
2162
2163            // this should probably be re thought out
2164            // the problem is that convForwFxnPtr has the conversion for a
2165            // one arg conv function pointer and convForwFxnPtrDD has the
2166            // conversion for a two arg conv function pointer
2167            // need to make this simpler, more logical maybe only allow 2 arg
2168            if (       (p->conv->convBackFxnPtr)
2169                    && (! p->conv->convBackFxnPtrDD) ) {
2170
2171                // value = p->conv->convBackFxnPtr(value);
2172                cList.push_back(p->conv->convBackFxnPtr);
2173            }
2174            /*
2175            else if (  (p->conv->convBackFxnPtrDD)
2176                    && (! p->conv->convBackFxnPtr) ) {
2177
2178                // value = p->conv->convBackFxnPtrDD(value, fromUnit->getExponent());
2179                cList.pushback(conv);
2180            }
2181            */
2182
2183            // check to see if we converted to the actual requested unit
2184            // or to the requested unit's basis.
2185            // if we converted to the requested unit's basis. we need to
2186            // do one last conversion from the requested unit's basis back
2187            // to the requested unit.
2188            if ( (toBasis) && (toBasis->getUnitsName() != fromUnit->getUnitsName()) ) {
2189                result += toBasis->getConvertFxnList(toUnit,cList);
2190            }
2191
2192            break;
2193        }
2194
2195        p = p->next;
2196
2197    } while (p != NULL);
2198
2199
2200    if ( p == NULL) {
2201        // we did not find the conversion
2202        result += 1;
2203    }
2204
2205    // return the converted value and result flag
2206    return result;
2207}
2208
2209/**********************************************************************/
2210// METHOD: applyConversion()
2211/// Apply a list of conversions in cList to the value val
2212/**
2213 * Apply a list of conversions, represented by cList, to the value
2214 * val.
2215 *
2216 * Returns an integer value of zero (0) on success
2217 * Returns non-zero value on failure.
2218 */
2219
2220int
2221RpUnits::applyConversion(double* val, convertList& cList) {
2222
2223    convertList::iterator iter;
2224
2225    if(val == NULL) {
2226        return 1;
2227    }
2228
2229    for(iter = cList.begin(); iter != cList.end(); iter++)
2230    {
2231        *val = (*iter)(*val);
2232    }
2233
2234    return 0;
2235}
2236
2237/**********************************************************************/
2238// METHOD: combineLists()
2239/// combine two convertLists in an orderly fasion
2240/**
2241 *
2242 * elements of l2 are pushed onto l1 in the same order in which it
2243 * exists in l2. l1 is changed in this function.
2244 *
2245 * Returns an integer value of zero (0) on success
2246 * Returns non-zero value on failure.
2247 */
2248
2249int
2250RpUnits::combineLists(convertList& l1, convertList& l2) {
2251
2252    for (convertList::iterator iter = l2.begin(); iter != l2.end(); iter++) {
2253        l1.push_back(*iter);
2254    }
2255    return 0;
2256
2257}
2258
2259/**********************************************************************/
2260// METHOD: printList()
2261/// print a list
2262/**
2263 *
2264 * Returns an integer value of zero (0) on success
2265 * Returns non-zero value on failure.
2266 */
2267
2268int
2269RpUnits::printList(convertList& l1) {
2270
2271    for (convertList::iterator iter = l1.begin(); iter != l1.end(); iter++) {
2272        printf("%p\n", *iter);
2273    }
2274    return 0;
2275
2276}
2277
2278/**********************************************************************/
2279// METHOD: insert()
2280/// Place an RpUnits Object into the Rappture Units Dictionary.
2281/**
2282 * Return whether the inserted key was new with a non-zero
2283 * value, or if the key already existed with a value of zero.
2284 */
2285
2286int
2287insert(std::string key,RpUnits* val) {
2288
2289    int newRecord = 0;
2290    RpUnitsTypes::RpUnitsTypesHint hint = NULL;
2291
2292    if (val == NULL) {
2293        return -1;
2294    }
2295
2296    hint = RpUnitsTypes::getTypeHint(val->getType());
2297
2298    RpUnits::dict->set(key,val,hint,&newRecord,val->getCI());
2299
2300    return newRecord;
2301}
2302
2303/**********************************************************************/
2304// METHOD: connectConversion()
2305/// Attach conversion information to a RpUnits Object.
2306/**
2307 */
2308
2309void
2310RpUnits::connectConversion(conversion* conv) const {
2311
2312    convEntry* p = convList;
2313
2314    if (p == NULL) {
2315        convList = new convEntry (conv,NULL,NULL);
2316    }
2317    else {
2318        while (p->next != NULL) {
2319            p = p->next;
2320        }
2321
2322        p->next = new convEntry (conv,p,NULL);
2323    }
2324
2325}
2326
2327/**********************************************************************/
2328// METHOD: connectIncarnation()
2329/// Attach incarnation object information to a RpUnits Object.
2330/**
2331 */
2332
2333void
2334RpUnits::connectIncarnation(const RpUnits* unit) const {
2335
2336    incarnationEntry* p = incarnationList;
2337
2338    if (p == NULL) {
2339        incarnationList = new incarnationEntry (unit,NULL,NULL);
2340    }
2341    else {
2342        while (p->next != NULL) {
2343            p = p->next;
2344        }
2345
2346        p->next = new incarnationEntry (unit,p,NULL);
2347    }
2348
2349}
2350
2351/**********************************************************************/
2352// METHOD: addPresets()
2353/// Add a specific set of predefined units to the dictionary
2354/**
2355 */
2356
2357int
2358RpUnits::addPresets (const std::string group) {
2359    int retVal = -1;
2360    if (group.compare("all") == 0) {
2361        retVal = RpUnitsPreset::addPresetAll();
2362    }
2363    else if (group.compare(RP_TYPE_ENERGY) == 0) {
2364        retVal = RpUnitsPreset::addPresetEnergy();
2365    }
2366    else if (group.compare(RP_TYPE_LENGTH) == 0) {
2367        retVal = RpUnitsPreset::addPresetLength();
2368    }
2369    else if (group.compare(RP_TYPE_TEMP) == 0) {
2370        retVal = RpUnitsPreset::addPresetTemp();
2371    }
2372    else if (group.compare(RP_TYPE_TIME) == 0) {
2373        retVal = RpUnitsPreset::addPresetTime();
2374    }
2375    else if (group.compare(RP_TYPE_VOLUME) == 0) {
2376        retVal = RpUnitsPreset::addPresetVolume();
2377    }
2378    else if (group.compare(RP_TYPE_ANGLE) == 0) {
2379        retVal = RpUnitsPreset::addPresetAngle();
2380    }
2381    else if (group.compare(RP_TYPE_MASS) == 0) {
2382        retVal = RpUnitsPreset::addPresetMass();
2383    }
2384    else if (group.compare(RP_TYPE_PREFIX) == 0) {
2385        retVal = RpUnitsPreset::addPresetPrefix();
2386    }
2387    else if (group.compare(RP_TYPE_PRESSURE) == 0) {
2388        retVal = RpUnitsPreset::addPresetPressure();
2389    }
2390    else if (group.compare(RP_TYPE_CONC) == 0) {
2391        retVal = RpUnitsPreset::addPresetConcentration();
2392    }
2393    else if (group.compare(RP_TYPE_FORCE) == 0) {
2394        retVal = RpUnitsPreset::addPresetForce();
2395    }
2396    else if (group.compare(RP_TYPE_MAGNETIC) == 0) {
2397        retVal = RpUnitsPreset::addPresetMagnetic();
2398    }
2399    else if (group.compare(RP_TYPE_MISC) == 0) {
2400        retVal = RpUnitsPreset::addPresetMisc();
2401    }
2402    else if (group.compare(RP_TYPE_POWER) == 0) {
2403        retVal = RpUnitsPreset::addPresetPower();
2404    }
2405
2406    return retVal;
2407}
2408
2409/**********************************************************************/
2410// METHOD: addPresetAll()
2411/// Call all of the addPreset* functions.
2412/**
2413 *
2414 * Add all predefined units to the units dictionary
2415 * Return codes: 0 success, anything else is error
2416 */
2417
2418int
2419RpUnitsPreset::addPresetAll () {
2420
2421    int result = 0;
2422
2423    result += addPresetPrefix();
2424    result += addPresetTime();
2425    result += addPresetTemp();
2426    result += addPresetLength();
2427    result += addPresetEnergy();
2428    result += addPresetVolume();
2429    result += addPresetAngle();
2430    result += addPresetMass();
2431    result += addPresetPressure();
2432    result += addPresetConcentration();
2433    result += addPresetForce();
2434    result += addPresetMagnetic();
2435    result += addPresetMisc();
2436    result += addPresetPower();
2437
2438    return 0;
2439}
2440
2441
2442/**********************************************************************/
2443// METHOD: addPresetPrefix()
2444///
2445/**
2446 * Defines the following unit prefixes:
2447 *   deci        (d)
2448 *   centi       (c)
2449 *   milli       (m)
2450 *   micro       (u)
2451 *   nano        (n)
2452 *   pico        (p)
2453 *   femto       (f)
2454 *   atto        (a)
2455 *   deca        (da)
2456 *   hecto       (h)
2457 *   kilo        (k)
2458 *   mega        (M)
2459 *   giga        (G)
2460 *   tera        (T)
2461 *   peta        (P)
2462 *   exa         (E)
2463 *
2464 * Return codes: 0 success, anything else is error
2465 */
2466
2467int
2468RpUnitsPreset::addPresetPrefix () {
2469
2470    std::string type = RP_TYPE_PREFIX;
2471    RpUnits* basis = NULL;
2472
2473    RpUnits * deci  = NULL;
2474    RpUnits * centi = NULL;
2475    RpUnits * milli = NULL;
2476    RpUnits * micro = NULL;
2477    RpUnits * nano  = NULL;
2478    RpUnits * pico  = NULL;
2479    RpUnits * femto = NULL;
2480    RpUnits * atto  = NULL;
2481    RpUnits * deca  = NULL;
2482    RpUnits * hecto = NULL;
2483    RpUnits * kilo  = NULL;
2484    RpUnits * mega  = NULL;
2485    RpUnits * giga  = NULL;
2486    RpUnits * tera  = NULL;
2487    RpUnits * peta  = NULL;
2488    RpUnits * exa   = NULL;
2489
2490    deci  = RpUnits::define ( "d",  basis, type);
2491    centi = RpUnits::define ( "c",  basis, type);
2492    milli = RpUnits::define ( "m",  basis, type, !RPUNITS_METRIC,
2493                              !RPUNITS_CASE_INSENSITIVE);
2494    micro = RpUnits::define ( "u",  basis, type);
2495    nano  = RpUnits::define ( "n",  basis, type, !RPUNITS_METRIC,
2496                              !RPUNITS_CASE_INSENSITIVE);
2497    pico  = RpUnits::define ( "p",  basis, type, !RPUNITS_METRIC,
2498                              !RPUNITS_CASE_INSENSITIVE);
2499    femto = RpUnits::define ( "f",  basis, type);
2500    atto  = RpUnits::define ( "a",  basis, type);
2501    deca  = RpUnits::define ( "da", basis, type);
2502    hecto = RpUnits::define ( "h",  basis, type);
2503    kilo  = RpUnits::define ( "k",  basis, type);
2504    mega  = RpUnits::define ( "M",  basis, type, !RPUNITS_METRIC,
2505                              !RPUNITS_CASE_INSENSITIVE);
2506    giga  = RpUnits::define ( "G",  basis, type);
2507    tera  = RpUnits::define ( "T",  basis, type);
2508    peta  = RpUnits::define ( "P",  basis, type, !RPUNITS_METRIC,
2509                              !RPUNITS_CASE_INSENSITIVE);
2510    exa  = RpUnits::define  ( "E",  basis, type);
2511
2512    // the use of the unit as the from and the to unit is a hack
2513    // that can be resolved by creating a RpPrefix object
2514    // the define() function cannot handle NULL as to unit.
2515    RpUnits::define ( deci,  deci , deci2base,  base2deci);
2516    RpUnits::define ( centi, centi, centi2base, base2centi);
2517    RpUnits::define ( milli, milli, milli2base, base2milli);
2518    RpUnits::define ( micro, micro, micro2base, base2micro);
2519    RpUnits::define ( nano,  nano , nano2base,  base2nano);
2520    RpUnits::define ( pico,  pico , pico2base,  base2pico);
2521    RpUnits::define ( femto, femto, femto2base, base2femto);
2522    RpUnits::define ( atto,  atto , atto2base,  base2atto);
2523    RpUnits::define ( deca,  deca , deca2base,  base2deca);
2524    RpUnits::define ( hecto, hecto, hecto2base, base2hecto);
2525    RpUnits::define ( kilo,  kilo , kilo2base,  base2kilo);
2526    RpUnits::define ( mega,  mega , mega2base,  base2mega);
2527    RpUnits::define ( giga,  giga , giga2base,  base2giga);
2528    RpUnits::define ( tera,  tera , tera2base,  base2tera);
2529    RpUnits::define ( peta,  peta , peta2base,  base2peta);
2530    RpUnits::define ( exa,   exa  , exa2base,   base2exa);
2531
2532    return 0;
2533}
2534
2535/**********************************************************************/
2536// METHOD: addPresetTime()
2537/// Add Time related units to the dictionary
2538/**
2539 * Defines the following units:
2540 *   seconds  (s)
2541 *   minutes  (min)
2542 *   hours    (h)
2543 *   days     (d)
2544 *
2545 *   month and year are not included because simple
2546 *   day->month conversions may be misleading
2547 *   month->year conversions may be included in the future
2548 *
2549 * Return codes: 0 success, anything else is error
2550 */
2551
2552int
2553RpUnitsPreset::addPresetTime () {
2554
2555    RpUnits* second    = NULL;
2556    RpUnits* minute    = NULL;
2557    RpUnits* hour      = NULL;
2558    RpUnits* day       = NULL;
2559
2560    second    = RpUnits::define("s", NULL, RP_TYPE_TIME, RPUNITS_METRIC);
2561    minute    = RpUnits::define("min", second, RP_TYPE_TIME);
2562    hour      = RpUnits::define("h", second, RP_TYPE_TIME);
2563    day       = RpUnits::define("d", second, RP_TYPE_TIME);
2564
2565    // add time definitions
2566
2567    RpUnits::define(second, minute, sec2min, min2sec);
2568    RpUnits::define(second, hour, sec2hour, hour2sec);
2569    RpUnits::define(second, day, sec2day, day2sec);
2570
2571    return 0;
2572}
2573
2574/**********************************************************************/
2575// METHOD: addPresetTemp()
2576/// Add Temperature related units to the dictionary
2577/**
2578 * Defines the following units:
2579 *   fahrenheit  (F)
2580 *   celcius     (C)
2581 *   kelvin      (K)
2582 *   rankine     (R)
2583 *
2584 * Return codes: 0 success, anything else is error
2585 */
2586
2587int
2588RpUnitsPreset::addPresetTemp () {
2589
2590    RpUnits* fahrenheit = NULL;
2591    RpUnits* celcius    = NULL;
2592    RpUnits* kelvin     = NULL;
2593    RpUnits* rankine    = NULL;
2594
2595    fahrenheit = RpUnits::define("F", NULL, RP_TYPE_TEMP);
2596    celcius    = RpUnits::define("C", NULL, RP_TYPE_TEMP, RPUNITS_METRIC);
2597    kelvin     = RpUnits::define("K", NULL, RP_TYPE_TEMP,RPUNITS_METRIC);
2598    rankine    = RpUnits::define("R", NULL, RP_TYPE_TEMP);
2599
2600    // add temperature definitions
2601    RpUnits::define(fahrenheit, celcius, fahrenheit2centigrade, centigrade2fahrenheit);
2602    RpUnits::define(celcius, kelvin, centigrade2kelvin, kelvin2centigrade);
2603    RpUnits::define(fahrenheit, kelvin, fahrenheit2kelvin, kelvin2fahrenheit);
2604    RpUnits::define(rankine, kelvin, rankine2kelvin, kelvin2rankine);
2605    RpUnits::define(fahrenheit, rankine, fahrenheit2rankine, rankine2fahrenheit);
2606    RpUnits::define(celcius, rankine, celcius2rankine, rankine2celcius);
2607
2608    return 0;
2609}
2610
2611/**********************************************************************/
2612// METHOD: addPresetLength()
2613/// Add Length related units to the dictionary
2614/**
2615 * Defines the following units:
2616 *   meters         (m)
2617 *   angstrom       (A)
2618 *   inch           (in)
2619 *   feet           (ft)
2620 *   yard           (yd)
2621 *
2622 * Return codes: 0 success, anything else is error
2623 */
2624
2625int
2626RpUnitsPreset::addPresetLength () {
2627
2628    RpUnits* meters     = NULL;
2629    RpUnits* angstrom   = NULL;
2630    RpUnits* bohr       = NULL;
2631    RpUnits* inch       = NULL;
2632    RpUnits* feet       = NULL;
2633    RpUnits* yard       = NULL;
2634    RpUnits* mile       = NULL;
2635
2636    meters     = RpUnits::define("m", NULL, RP_TYPE_LENGTH, RPUNITS_METRIC);
2637    angstrom   = RpUnits::define("A", NULL, RP_TYPE_LENGTH);
2638    bohr       = RpUnits::define("bohr", NULL, RP_TYPE_LENGTH);
2639    inch       = RpUnits::define("in", NULL, RP_TYPE_LENGTH);
2640    feet       = RpUnits::define("ft", inch, RP_TYPE_LENGTH);
2641    yard       = RpUnits::define("yd", inch, RP_TYPE_LENGTH);
2642    mile       = RpUnits::define("mi", inch, RP_TYPE_LENGTH);
2643
2644    // RpUnits::makeMetric(meters);
2645
2646    // add length definitions
2647    RpUnits::define(angstrom, meters, angstrom2meter, meter2angstrom);
2648    RpUnits::define(bohr, meters, bohr2meter, meter2bohr);
2649    RpUnits::define(inch, feet, inch2feet, feet2inch);
2650    RpUnits::define(inch, yard, inch2yard, yard2inch);
2651    RpUnits::define(inch, meters, inch2meter, meter2inch);
2652    RpUnits::define(inch, mile, inch2mile, mile2inch);
2653
2654    return 0;
2655}
2656
2657/**********************************************************************/
2658// METHOD: addPresetEnergy()
2659/// Add Energy related units to the dictionary
2660/**
2661 * Defines the following units:
2662 *   electron Volt (eV)
2663 *   joule         (J)
2664 *
2665 * Return codes: 0 success, anything else is error
2666 */
2667
2668int
2669RpUnitsPreset::addPresetEnergy () {
2670
2671    RpUnits* eVolt      = NULL;
2672    RpUnits* joule      = NULL;
2673
2674    eVolt      = RpUnits::define("eV", NULL, RP_TYPE_ENERGY, RPUNITS_METRIC);
2675    joule      = RpUnits::define("J", NULL, RP_TYPE_ENERGY, RPUNITS_METRIC);
2676
2677    // add energy definitions
2678    RpUnits::define(eVolt,joule,electronVolt2joule,joule2electronVolt);
2679
2680    return 0;
2681}
2682
2683/**********************************************************************/
2684// METHOD: addPresetVolume()
2685/// Add Volume related units to the dictionary
2686/**
2687 * Defines the following units:
2688 *   cubic feet (ft3)
2689 *   us gallons (gal)
2690 *   liter      (L)
2691 *
2692 * Return codes: 0 success, anything else is error
2693 */
2694
2695int
2696RpUnitsPreset::addPresetVolume () {
2697
2698    // RpUnits* cubic_meter  = RpUnits::define("m3", NULL, RP_TYPE_VOLUME);
2699    // RpUnits* cubic_feet   = RpUnits::define("ft3", NULL, RP_TYPE_VOLUME);
2700    // RpUnits* us_gallon    = NULL;
2701    // RpUnits* liter        = NULL;
2702
2703    RpUnits::define("gal", NULL, RP_TYPE_VOLUME);
2704    RpUnits::define("L", NULL, RP_TYPE_VOLUME, RPUNITS_METRIC);
2705
2706    /*
2707    // RpUnits::makeMetric(cubic_meter);
2708    const RpUnits* meter = NULL;
2709    const RpUnits* foot = NULL;
2710
2711    meter = RpUnits::find("m");
2712    if (meter && cubic_meter) {
2713        RpUnits::incarnate(meter,cubic_meter);
2714    }
2715    else {
2716        // raise an error, could not find meter unit
2717    }
2718
2719    foot = RpUnits::find("ft");
2720    if (foot && cubic_feet) {
2721        RpUnits::incarnate(foot,cubic_feet);
2722    }
2723    else {
2724        // raise an error, could not find meter unit
2725    }
2726    */
2727
2728    // RpUnits::makeMetric(liter);
2729
2730
2731    // add volume definitions
2732    // RpUnits::define(cubic_meter,cubic_feet,meter2feet,feet2meter);
2733    // RpUnits::define(cubic_meter,us_gallon,cubicMeter2usGallon,usGallon2cubicMeter);
2734    // RpUnits::define(cubic_feet,us_gallon,cubicFeet2usGallon,usGallon2cubicFeet);
2735    // RpUnits::define(cubic_meter,liter,cubicMeter2liter,liter2cubicMeter);
2736    // RpUnits::define(liter,us_gallon,liter2us_gallon,us_gallon2liter);
2737
2738    return 0;
2739}
2740
2741/**********************************************************************/
2742// METHOD: addPresetAngle()
2743/// Add Angle related units to the dictionary
2744/**
2745 * Defines the following units:
2746 *   degrees  (deg)
2747 *   gradians (grad)
2748 *   radians  (rad) (and metric extensions)
2749 *
2750 * Return codes: 0 success, anything else is error
2751 */
2752
2753int
2754RpUnitsPreset::addPresetAngle () {
2755
2756    RpUnits* degree  = NULL;
2757    RpUnits* gradian = NULL;
2758    RpUnits* radian  = NULL;
2759
2760    degree  = RpUnits::define("deg",  NULL, RP_TYPE_ANGLE);
2761    gradian = RpUnits::define("grad", NULL, RP_TYPE_ANGLE);
2762    radian  = RpUnits::define("rad",  NULL, RP_TYPE_ANGLE, RPUNITS_METRIC);
2763
2764    // add angle definitions
2765    RpUnits::define(degree,gradian,deg2grad,grad2deg);
2766    RpUnits::define(radian,degree,rad2deg,deg2rad);
2767    RpUnits::define(radian,gradian,rad2grad,grad2rad);
2768
2769    return 0;
2770}
2771
2772/**********************************************************************/
2773// METHOD: addPresetMass()
2774/// Add Mass related units to the dictionary
2775/**
2776 * Defines the following units:
2777 *   gram  (g)
2778 *
2779 * Return codes: 0 success, anything else is error
2780 */
2781
2782int
2783RpUnitsPreset::addPresetMass () {
2784
2785    RpUnits::define("g", NULL, RP_TYPE_MASS, RPUNITS_METRIC,!RPUNITS_CASE_INSENSITIVE);
2786
2787    return 0;
2788}
2789
2790/**********************************************************************/
2791// METHOD: addPresetPressure()
2792/// Add pressure related units to the dictionary
2793/**
2794 * http://www.ilpi.com/msds/ref/pressureunits.html
2795 *
2796 * Defines the following units:
2797 *   atmosphere             (atm)
2798 *   bar                    (bar)
2799 *   pascal                 (Pa)
2800 *   pounds/(in^2)          (psi)
2801 *   torr                   (torr)
2802 *   millimeters Mercury    (mmHg)
2803 *
2804 * mmHg was added because as a convenience to those who have not
2805 * yet switched over to the new representation of torr.
2806 *
2807 * Return codes: 0 success, anything else is error
2808 */
2809
2810int
2811RpUnitsPreset::addPresetPressure () {
2812
2813    RpUnits* atmosphere = NULL;
2814    RpUnits* bar        = NULL;
2815    RpUnits* pascal     = NULL;
2816    RpUnits* psi        = NULL;
2817    RpUnits* torr       = NULL;
2818    RpUnits* mmHg       = NULL;
2819
2820    atmosphere  = RpUnits::define("atm", NULL, RP_TYPE_PRESSURE);
2821    bar     = RpUnits::define("bar",  NULL, RP_TYPE_PRESSURE, RPUNITS_METRIC);
2822    pascal  = RpUnits::define("Pa",   NULL, RP_TYPE_PRESSURE, RPUNITS_METRIC);
2823    psi     = RpUnits::define("psi",  NULL, RP_TYPE_PRESSURE);
2824    torr    = RpUnits::define("torr", NULL, RP_TYPE_PRESSURE);
2825    mmHg    = RpUnits::define("mmHg", torr, RP_TYPE_PRESSURE);
2826
2827    RpUnits::define(bar,pascal,bar2Pa,Pa2bar);
2828    RpUnits::define(bar,atmosphere,bar2atm,atm2bar);
2829    RpUnits::define(bar,psi,bar2psi,psi2bar);
2830    RpUnits::define(bar,torr,bar2torr,torr2bar);
2831    RpUnits::define(pascal,atmosphere,Pa2atm,atm2Pa);
2832    RpUnits::define(pascal,torr,Pa2torr,torr2Pa);
2833    RpUnits::define(pascal,psi,Pa2psi,psi2Pa);
2834    RpUnits::define(torr,atmosphere,torr2atm,atm2torr);
2835    RpUnits::define(torr,psi,torr2psi,psi2torr);
2836    RpUnits::define(atmosphere,psi,atm2psi,psi2atm);
2837
2838    RpUnits::define(torr,mmHg,torr2mmHg,mmHg2torr);
2839
2840    return 0;
2841}
2842
2843/**********************************************************************/
2844// METHOD: addPresetConcentration()
2845/// Add concentration related units to the dictionary
2846/**
2847 *
2848 * Defines the following units:
2849 *   pH    (pH)
2850 *   pOH    (pOH)
2851 *
2852 * Return codes: 0 success, anything else is error
2853 */
2854
2855int
2856RpUnitsPreset::addPresetConcentration () {
2857
2858    RpUnits* pH  = NULL;
2859    RpUnits* pOH = NULL;
2860
2861    pH  = RpUnits::define("pH",  NULL, RP_TYPE_CONC);
2862    pOH = RpUnits::define("pOH", NULL, RP_TYPE_CONC);
2863
2864    // add concentration definitions
2865    RpUnits::define(pH,pOH,pH2pOH,pOH2pH);
2866
2867    return 0;
2868}
2869
2870/**********************************************************************/
2871// METHOD: addPresetForce()
2872/// Add concentration related units to the dictionary
2873/**
2874 * http://en.wikipedia.org/wiki/Newton
2875 *
2876 * Defines the following units:
2877 *   newton    (N)
2878 *
2879 * Return codes: 0 success, anything else is error
2880 */
2881
2882int
2883RpUnitsPreset::addPresetForce () {
2884
2885    RpUnits::define("N",  NULL, RP_TYPE_FORCE, RPUNITS_METRIC);
2886
2887    return 0;
2888}
2889
2890/**********************************************************************/
2891// METHOD: addPresetMagnetic()
2892/// Add concentration related units to the dictionary
2893/**
2894 *
2895 * http://en.wikipedia.org/wiki/Tesla_(unit)
2896 * http://en.wikipedia.org/wiki/Gauss_(unit)
2897 * http://en.wikipedia.org/wiki/Maxwell_(unit)
2898 * http://en.wikipedia.org/wiki/Weber_(unit)
2899 *
2900 * Defines the following units:
2901 *   tesla    (T)
2902 *   gauss    (G)
2903 *   maxwell  (Mx)
2904 *   weber    (Wb)
2905 *
2906 * Return codes: 0 success, anything else is error
2907 */
2908
2909int
2910RpUnitsPreset::addPresetMagnetic () {
2911
2912    RpUnits* tesla = NULL;
2913    RpUnits* gauss = NULL;
2914    RpUnits* maxwell = NULL;
2915    RpUnits* weber = NULL;
2916
2917    tesla = RpUnits::define("T",  NULL, RP_TYPE_MAGNETIC, RPUNITS_METRIC);
2918    gauss = RpUnits::define("G",  NULL, RP_TYPE_MAGNETIC, !RPUNITS_CASE_INSENSITIVE);
2919    maxwell = RpUnits::define("Mx",  NULL, RP_TYPE_MAGNETIC);
2920    weber = RpUnits::define("Wb", NULL, RP_TYPE_MAGNETIC, RPUNITS_METRIC);
2921
2922    RpUnits::define(tesla,gauss,tesla2gauss,gauss2tesla);
2923    RpUnits::define(maxwell,weber,maxwell2weber,weber2maxwell);
2924
2925    return 0;
2926}
2927
2928/**********************************************************************/
2929// METHOD: addPresetMisc()
2930/// Add Misc related units to the dictionary
2931/**
2932 * Defines the following units:
2933 *   volt  (V)
2934 *   mole  (mol)
2935 *   hertz (Hz)
2936 *   becquerel (Bq)
2937 *   amu
2938 *   bel (B)
2939 *   amp
2940 *   ohm
2941 * Return codes: 0 success, anything else is error
2942 */
2943
2944int
2945RpUnitsPreset::addPresetMisc () {
2946
2947    RpUnits::define("V",  NULL, RP_TYPE_EPOT, RPUNITS_METRIC);
2948    RpUnits::define("mol",NULL, "quantity", RPUNITS_METRIC);
2949    RpUnits::define("Hz", NULL, "frequency", RPUNITS_METRIC);
2950    RpUnits::define("Bq", NULL, "radioactivity", RPUNITS_METRIC);
2951    RpUnits::define("amu", NULL, "mass_unit", !RPUNITS_METRIC);
2952    RpUnits::define("B", NULL, "audio_transmission", RPUNITS_METRIC);
2953    RpUnits::define("amp", NULL, "electric_current", RPUNITS_METRIC);
2954    RpUnits::define("ohm", NULL, "electric_resistance", RPUNITS_METRIC);
2955
2956    // RpUnits* percent   = RpUnits::define("%",  NULL, RP_TYPE_MISC);
2957
2958    return 0;
2959}
2960
2961/**********************************************************************/
2962// METHOD: addPresetPower()
2963/// Add power related units to the dictionary
2964/**
2965 * Defines the following units:
2966 *   watt  (W)
2967 *
2968 * Return codes: 0 success, anything else is error
2969 */
2970
2971int
2972RpUnitsPreset::addPresetPower () {
2973
2974    // watts are derived units = J/s = kg*m2/s3 = Newton*m/s and Amps*Volt
2975    RpUnits::define("W",  NULL, RP_TYPE_POWER, RPUNITS_METRIC);
2976
2977    return 0;
2978}
2979
2980RpUnitsTypes::RpUnitsTypesHint
2981RpUnitsTypes::getTypeHint (std::string type) {
2982
2983    if (type.compare(RP_TYPE_ENERGY) == 0) {
2984        return &RpUnitsTypes::hintTypeEnergy;
2985    }
2986    else if (type.compare(RP_TYPE_EPOT) == 0) {
2987        return &RpUnitsTypes::hintTypeEPot;
2988    }
2989    else if (type.compare(RP_TYPE_LENGTH) == 0) {
2990        return &RpUnitsTypes::hintTypeLength;
2991    }
2992    else if (type.compare(RP_TYPE_TEMP) == 0) {
2993        return &RpUnitsTypes::hintTypeTemp;
2994    }
2995    else if (type.compare(RP_TYPE_TIME) == 0) {
2996        return &RpUnitsTypes::hintTypeTime;
2997    }
2998    else if (type.compare(RP_TYPE_VOLUME) == 0) {
2999        return &RpUnitsTypes::hintTypeVolume;
3000    }
3001    else if (type.compare(RP_TYPE_ANGLE) == 0) {
3002        return &RpUnitsTypes::hintTypeAngle;
3003    }
3004    else if (type.compare(RP_TYPE_MASS) == 0) {
3005        return &RpUnitsTypes::hintTypeMass;
3006    }
3007    else if (type.compare(RP_TYPE_PREFIX) == 0) {
3008        return &RpUnitsTypes::hintTypePrefix;
3009    }
3010    else if (type.compare(RP_TYPE_PRESSURE) == 0) {
3011        return &RpUnitsTypes::hintTypePressure;
3012    }
3013    else if (type.compare(RP_TYPE_CONC) == 0) {
3014        return &RpUnitsTypes::hintTypeConc;
3015    }
3016    else if (type.compare(RP_TYPE_FORCE) == 0) {
3017        return &RpUnitsTypes::hintTypeForce;
3018    }
3019    else if (type.compare(RP_TYPE_MAGNETIC) == 0) {
3020        return &RpUnitsTypes::hintTypeMagnetic;
3021    }
3022    else if (type.compare(RP_TYPE_MISC) == 0) {
3023        return &RpUnitsTypes::hintTypeMisc;
3024    }
3025    else if (type.compare(RP_TYPE_POWER) == 0) {
3026        return &RpUnitsTypes::hintTypePower;
3027    }
3028    else {
3029        return NULL;
3030    }
3031};
3032
3033bool
3034RpUnitsTypes::hintTypePrefix   (   RpUnits* unitObj    ) {
3035
3036    bool retVal = false;
3037
3038    if ( (unitObj->getType()).compare(RP_TYPE_PREFIX) == 0 ) {
3039        retVal = true;
3040    }
3041
3042    return retVal;
3043}
3044
3045bool
3046RpUnitsTypes::hintTypeNonPrefix    (   RpUnits* unitObj    ) {
3047
3048    bool retVal = true;
3049
3050    if ( (unitObj->getType()).compare(RP_TYPE_PREFIX) == 0 ) {
3051        retVal = false;
3052    }
3053
3054    return retVal;
3055}
3056
3057bool
3058RpUnitsTypes::hintTypeEnergy   (   RpUnits* unitObj    ) {
3059
3060    bool retVal = false;
3061
3062    if ( (unitObj->getType()).compare(RP_TYPE_ENERGY) == 0 ) {
3063        retVal = true;
3064    }
3065
3066    return retVal;
3067}
3068
3069bool
3070RpUnitsTypes::hintTypeEPot   (   RpUnits* unitObj    ) {
3071
3072    bool retVal = false;
3073
3074    if ( (unitObj->getType()).compare(RP_TYPE_EPOT) == 0 ) {
3075        retVal = true;
3076    }
3077
3078    return retVal;
3079}
3080
3081bool
3082RpUnitsTypes::hintTypeLength   (   RpUnits* unitObj    ) {
3083
3084    bool retVal = false;
3085
3086    if ( (unitObj->getType()).compare(RP_TYPE_LENGTH) == 0 ) {
3087        retVal = true;
3088    }
3089
3090    return retVal;
3091}
3092
3093bool
3094RpUnitsTypes::hintTypeTemp   (   RpUnits* unitObj    ) {
3095
3096    bool retVal = false;
3097
3098    if ( (unitObj->getType()).compare(RP_TYPE_TEMP) == 0 ) {
3099        retVal = true;
3100    }
3101
3102    return retVal;
3103}
3104
3105bool
3106RpUnitsTypes::hintTypeTime   (   RpUnits* unitObj    ) {
3107
3108    bool retVal = false;
3109
3110    if ( (unitObj->getType()).compare(RP_TYPE_TIME) == 0 ) {
3111        retVal = true;
3112    }
3113
3114    return retVal;
3115}
3116
3117bool
3118RpUnitsTypes::hintTypeVolume   (   RpUnits* unitObj    ) {
3119
3120    bool retVal = false;
3121
3122    if ( (unitObj->getType()).compare(RP_TYPE_VOLUME) == 0 ) {
3123        retVal = true;
3124    }
3125
3126    return retVal;
3127}
3128
3129bool
3130RpUnitsTypes::hintTypeAngle   (   RpUnits* unitObj    ) {
3131
3132    bool retVal = false;
3133
3134    if ( (unitObj->getType()).compare(RP_TYPE_ANGLE) == 0 ) {
3135        retVal = true;
3136    }
3137
3138    return retVal;
3139}
3140
3141bool
3142RpUnitsTypes::hintTypeMass   (   RpUnits* unitObj    ) {
3143
3144    bool retVal = false;
3145
3146    if ( (unitObj->getType()).compare(RP_TYPE_MASS) == 0 ) {
3147        retVal = true;
3148    }
3149
3150    return retVal;
3151}
3152
3153bool
3154RpUnitsTypes::hintTypePressure   (   RpUnits* unitObj    ) {
3155
3156    bool retVal = false;
3157
3158    if ( (unitObj->getType()).compare(RP_TYPE_PRESSURE) == 0 ) {
3159        retVal = true;
3160    }
3161
3162    return retVal;
3163}
3164
3165bool
3166RpUnitsTypes::hintTypeConc   (   RpUnits* unitObj    ) {
3167
3168    bool retVal = false;
3169
3170    if ( (unitObj->getType()).compare(RP_TYPE_CONC) == 0 ) {
3171        retVal = true;
3172    }
3173
3174    return retVal;
3175}
3176
3177bool
3178RpUnitsTypes::hintTypeForce   (   RpUnits* unitObj    ) {
3179
3180    bool retVal = false;
3181
3182    if ( (unitObj->getType()).compare(RP_TYPE_FORCE) == 0 ) {
3183        retVal = true;
3184    }
3185
3186    return retVal;
3187}
3188
3189bool
3190RpUnitsTypes::hintTypeMagnetic   (   RpUnits* unitObj    ) {
3191
3192    bool retVal = false;
3193
3194    if ( (unitObj->getType()).compare(RP_TYPE_MAGNETIC) == 0 ) {
3195        retVal = true;
3196    }
3197
3198    return retVal;
3199}
3200
3201bool
3202RpUnitsTypes::hintTypeMisc   (   RpUnits* unitObj    ) {
3203
3204    bool retVal = false;
3205
3206    if ( (unitObj->getType()).compare(RP_TYPE_MISC) == 0 ) {
3207        retVal = true;
3208    }
3209
3210    return retVal;
3211}
3212
3213bool
3214RpUnitsTypes::hintTypePower   (   RpUnits* unitObj    ) {
3215
3216    bool retVal = false;
3217
3218    if ( (unitObj->getType()).compare(RP_TYPE_POWER) == 0 ) {
3219        retVal = true;
3220    }
3221
3222    return retVal;
3223}
3224
3225// -------------------------------------------------------------------- //
3226
3227/**********************************************************************/
3228// FUNCTION: list2str()
3229/// Convert a std::list<std::string> into a comma delimited std::string
3230/**
3231 * Iterates through a std::list<std::string> and returns a comma
3232 * delimited std::string containing the elements of the inputted std::list.
3233 *
3234 * Returns 0 on success, anything else is error
3235 */
3236
3237int
3238list2str (std::list<std::string>& inList, std::string& outString)
3239{
3240    int retVal = 1;  // return Value 0 is success, everything else is failure
3241    unsigned int counter = 0; // check if we hit all elements of inList
3242    std::list<std::string>::iterator inListIter; // list interator
3243
3244    inListIter = inList.begin();
3245
3246    while (inListIter != inList.end()) {
3247        if ( outString.empty() ) {
3248            outString = *inListIter;
3249        }
3250        else {
3251            outString =  outString + "," + *inListIter;
3252        }
3253
3254        // increment the iterator and loop counter
3255        inListIter++;
3256        counter++;
3257    }
3258
3259    if (counter == inList.size()) {
3260        retVal = 0;
3261    }
3262
3263    return retVal;
3264}
3265
3266/**********************************************************************/
3267// FUNCTION: unitSlice()
3268/// Convert a std::string into what might be the value and units
3269/**
3270 * Returns 0 on success, anything else is error
3271 */
3272
3273int
3274unitSlice (std::string inStr, std::string& outUnits, double& outVal)
3275{
3276    int retVal      = 0;  // return val 0 is success, otherwise failure
3277    char *endptr    = NULL;
3278
3279    outVal = strtod(inStr.c_str(), &endptr);
3280
3281    if ( (outVal == 0) && (endptr == inStr.c_str()) ) {
3282        // no conversion performed
3283        retVal = 1;
3284    }
3285
3286    outUnits = std::string(endptr);
3287
3288    return retVal;
3289}
Note: See TracBrowser for help on using the repository browser.