source: trunk/source/intercoms/src/G4UIparameter.cc @ 1331

Last change on this file since 1331 was 1228, checked in by garnier, 14 years ago

update geant4.9.3 tag

File size: 22.8 KB
Line 
1//
2// ********************************************************************
3// * License and Disclaimer                                           *
4// *                                                                  *
5// * The  Geant4 software  is  copyright of the Copyright Holders  of *
6// * the Geant4 Collaboration.  It is provided  under  the terms  and *
7// * conditions of the Geant4 Software License,  included in the file *
8// * LICENSE and available at  http://cern.ch/geant4/license .  These *
9// * include a list of copyright holders.                             *
10// *                                                                  *
11// * Neither the authors of this software system, nor their employing *
12// * institutes,nor the agencies providing financial support for this *
13// * work  make  any representation or  warranty, express or implied, *
14// * regarding  this  software system or assume any liability for its *
15// * use.  Please see the license in the file  LICENSE  and URL above *
16// * for the full disclaimer and the limitation of liability.         *
17// *                                                                  *
18// * This  code  implementation is the result of  the  scientific and *
19// * technical work of the GEANT4 collaboration.                      *
20// * By using,  copying,  modifying or  distributing the software (or *
21// * any work based  on the software)  you  agree  to acknowledge its *
22// * use  in  resulting  scientific  publications,  and indicate your *
23// * acceptance of all terms of the Geant4 Software license.          *
24// ********************************************************************
25//
26//
27// $Id: G4UIparameter.cc,v 1.14 2006/06/29 19:09:09 gunter Exp $
28// GEANT4 tag $Name: geant4-09-03 $
29//
30
31#include "G4UIparameter.hh"
32#include "G4UIcommandStatus.hh"
33#include "G4Tokenizer.hh"
34#include "G4ios.hh"
35#include <sstream>
36
37
38G4UIparameter::G4UIparameter():paramERR(0)
39{
40  G4String nullString;
41  parameterName = nullString;
42  parameterType = '\0';
43  omittable = false;
44  parameterGuidance = nullString;
45  defaultValue = nullString;
46  parameterRange = nullString;
47  currentAsDefaultFlag = false;
48  parameterCandidate = nullString;
49  widget = 0;
50}
51
52G4UIparameter::G4UIparameter(char theType):paramERR(0)
53{
54  G4String nullString;
55  parameterName = nullString;
56  parameterType = theType;
57  omittable = false;
58  parameterGuidance = nullString;
59  defaultValue = nullString;
60  parameterRange = nullString;
61  currentAsDefaultFlag = false;
62  parameterCandidate = nullString;
63  widget = 0;
64}
65
66G4UIparameter::G4UIparameter(const char * theName, char theType, G4bool theOmittable):paramERR(0)
67{
68  parameterName = theName;
69  parameterType = theType;
70  omittable = theOmittable;
71  G4String nullString;
72  parameterGuidance = nullString;
73  defaultValue = nullString;
74  parameterRange = nullString;
75  currentAsDefaultFlag = false;
76  parameterCandidate = nullString;
77  widget = 0;
78}
79
80G4UIparameter::~G4UIparameter()
81{ }
82
83G4int G4UIparameter::operator==(const G4UIparameter &right) const
84{
85  return ( this == &right );
86}
87
88G4int G4UIparameter::operator!=(const G4UIparameter &right) const
89{
90  return ( this != &right );
91}
92
93void G4UIparameter::List()
94{
95  G4cout << G4endl << "Parameter : " << parameterName << G4endl;
96  if( ! parameterGuidance.isNull() )
97  G4cout << parameterGuidance << G4endl ;
98  G4cout << " Parameter type  : " << parameterType << G4endl;
99  if(omittable)
100  { G4cout << " Omittable       : True" << G4endl; }
101  else
102  { G4cout << " Omittable       : False" << G4endl; }
103  if( currentAsDefaultFlag )
104  { G4cout << " Default value   : taken from the current value" << G4endl; }
105  else if( ! defaultValue.isNull() )
106  { G4cout << " Default value   : " << defaultValue << G4endl; }
107  if( ! parameterRange.isNull() )
108  G4cout << " Parameter range : " << parameterRange << G4endl;
109  if( ! parameterCandidate.isNull() )
110  G4cout << " Candidates      : " << parameterCandidate << G4endl;
111}
112
113void G4UIparameter::SetDefaultValue(G4int theDefaultValue)
114{
115  std::ostringstream os;
116  os << theDefaultValue;
117  defaultValue = os.str();
118}
119
120void G4UIparameter::SetDefaultValue(G4double theDefaultValue)
121{
122  std::ostringstream os;
123  os << theDefaultValue;
124  defaultValue = os.str();
125}
126
127
128// ---------- CheckNewValue() related routines -----------
129#include <ctype.h>
130#include "G4UItokenNum.hh"
131
132//#include "checkNewValue_debug.icc"
133//#define DEBUG 1
134
135G4int G4UIparameter::
136CheckNewValue(const char* newValue ) {
137    if( TypeCheck(newValue) == 0) return fParameterUnreadable;
138    if( ! parameterRange.isNull() )
139    { if( RangeCheck(newValue) == 0 ) return fParameterOutOfRange; }
140    if( ! parameterCandidate.isNull() )
141    { if( CandidateCheck(newValue) == 0 ) return fParameterOutOfCandidates; }
142    return 0;   // succeeded
143}
144
145G4int G4UIparameter::
146CandidateCheck(const char* newValue) {
147    G4Tokenizer candidateTokenizer(parameterCandidate);
148    G4String aToken;
149    G4int iToken = 0;
150    while( ! (aToken=candidateTokenizer()).isNull() )
151    {
152      iToken++;
153      if(aToken==newValue) return iToken;
154    } 
155    G4cerr << "parameter value is not listed in the candidate List." << G4endl;
156    return 0;
157}
158
159G4int G4UIparameter::
160RangeCheck(const char* newValue) {
161    yystype result;
162    bp = 0;                   // reset buffer pointer for G4UIpGetc()
163    std::istringstream is(newValue); 
164    char type = toupper( parameterType );
165    switch (type) {
166        case 'D': { is >> newVal.D; } break;
167        case 'I': { is >> newVal.I; } break;
168        default:   ;
169    }
170   // PrintToken();          // Print tokens (consumes all tokens)
171   token= Yylex();
172   result = Expression();
173   if( paramERR == 1 ) return 0;
174   if( result.type != CONSTINT) {
175      G4cerr << "Illegal Expression in parameter range." << G4endl;
176      return 0;
177   }
178   if ( result.I ) return 1;
179   G4cerr << "parameter out of range: "<< parameterRange << G4endl;
180   return 0;
181}
182
183
184G4int G4UIparameter::
185TypeCheck(const char* newValue)
186{
187    G4String newValueString(newValue);
188    char type = toupper( parameterType );
189    switch(type) {
190        case 'D':
191            if( IsDouble(newValueString.data())== 0) {
192                G4cerr<<newValue<<": double value expected."
193                    << G4endl;
194                return 0;
195             } break;
196        case 'I':
197            if( IsInt(newValueString.data(),20)== 0) {
198                G4cerr<<newValue<<": integer expected."
199                    << G4endl;
200                return 0;
201             } break;
202        case 'S': break;
203        case 'B':
204             newValueString.toUpper();
205             if (  newValueString == "Y" || newValueString == "N"
206                  ||newValueString == "YES" || newValueString == "NO"
207                  ||newValueString == "1"   || newValueString == "0"
208                  ||newValueString == "T" || newValueString == "F"
209                  ||newValueString == "TRUE" || newValueString == "FALSE") 
210                  return 1;
211             else {
212                    G4cerr<<newValue<<": bool expected." << G4endl;
213                    return 0; 
214             } 
215        default: ;
216    }
217    return 1;
218}
219
220
221G4int G4UIparameter::
222IsInt(const char* buf, short maxDigits)  // do not allow any std::ws
223{
224    const char* p= buf;
225    G4int length=0;
226    if( *p == '+' || *p == '-') { ++p; }
227    if( isdigit( (G4int)(*p) )) {
228        while( isdigit( (G4int)(*p) )) { ++p;  ++length; }
229        if( *p == '\0' ) {
230            if( length > maxDigits) {
231                G4cerr <<"digit length exceeds"<<G4endl;
232                return 0;
233            }
234            return 1;
235        } else {
236            // G4cerr <<"illegal character after int:"<<buf<<G4endl;
237        }
238    } else {
239        // G4cerr <<"illegal int:"<<buf<<G4endl;
240    }
241    return 0;
242}
243
244
245G4int G4UIparameter::
246ExpectExponent(const char* str)   // used only by IsDouble()
247{
248    G4int maxExplength;
249    if( IsInt( str, maxExplength=7 )) return 1;
250    else return 0;
251}
252
253G4int G4UIparameter::
254IsDouble(const char* buf)  // see state diagram for this spec.
255{
256    const char* p= buf;
257    switch( *p) {
258        case '+':  case '-': ++p;
259            if( isdigit(*p) ) {
260                 while( isdigit( (G4int)(*p) )) { ++p; }
261                 switch ( *p ) {
262                     case '\0':    return 1;  //break;
263                     case 'E':  case 'e':
264                         return ExpectExponent(++p );  //break;
265                     case '.':  ++p;
266                         if( *p == '\0' )  return 1;
267                         if( *p == 'e' || *p =='E' ) return ExpectExponent(++p );
268                         if( isdigit(*p) ) {
269                             while( isdigit( (G4int)(*p) )) { ++p; }
270                             if( *p == '\0' )  return 1;
271                             if( *p == 'e' || *p =='E') return ExpectExponent(++p);
272                         } else return 0;   break;
273                     default: return 0;
274                 }
275            }
276            if( *p == '.' ) { ++p;
277                 if( isdigit(*p) ) {
278                     while( isdigit( (G4int)(*p) )) { ++p; }
279                     if( *p == '\0' )  return 1;
280                     if( *p == 'e' || *p =='E')  return ExpectExponent(++p);
281                 }
282            }
283            break;
284        case '.':  ++p;
285            if( isdigit(*p) ) {
286                 while( isdigit( (G4int)(*p) )) { ++p; }
287                 if( *p == '\0' )  return 1;
288                 if( *p == 'e' || *p =='E' )  return ExpectExponent(++p);
289            }    break;
290        default: // digit is expected
291            if( isdigit(*p) ) {
292                 while( isdigit( (G4int)(*p) )) { ++p; }
293                 if( *p == '\0' )  return 1;
294                 if( *p == 'e' || *p =='E')  return ExpectExponent(++p);
295                 if( *p == '.' ) { ++p;
296                      if( *p == '\0' )  return 1;
297                      if( *p == 'e' || *p =='E')  return ExpectExponent(++p);
298                      if( isdigit(*p) ) {
299                          while( isdigit( (G4int)(*p) )) { ++p; }
300                          if( *p == '\0' )  return 1;
301                          if( *p == 'e' || *p =='E') return ExpectExponent(++p);
302                      }
303                 }
304            }
305     }
306     return 0;
307}
308
309
310// ------------------ syntax node functions  ------------------
311
312yystype G4UIparameter:: 
313Expression(void)
314{
315    yystype result;
316    #ifdef DEBUG
317        G4cerr << " Expression()" << G4endl;
318    #endif
319    result = LogicalORExpression();
320    return result;
321}
322
323yystype G4UIparameter:: 
324LogicalORExpression(void)
325{
326    yystype result;
327    yystype p;
328    p = LogicalANDExpression();
329    if( token != LOGICALOR)  return p;
330    if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
331        G4cerr << "Parameter range: illegal type at '||'" << G4endl;
332        paramERR = 1;
333    }
334    result.I = p.I;
335    while (token == LOGICALOR) 
336    { 
337        token = Yylex();
338        p = LogicalANDExpression();
339        if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
340            G4cerr << "Parameter range: illegal type at '||'" <<G4endl;
341            paramERR = 1;
342        }
343        switch (p.type) {
344            case CONSTINT: 
345                result.+= p.I; 
346                result.type = CONSTINT;      break;
347            case CONSTDOUBLE:
348                result.I += (p.D != 0.0); 
349                result.type = CONSTINT;      break;
350            default: 
351                G4cerr << "Parameter range: unknown type"<<G4endl; 
352                paramERR = 1;
353        } 
354    }
355    return result;
356}
357
358yystype G4UIparameter:: 
359LogicalANDExpression(void)
360{
361    yystype result;
362    yystype p;
363    p = EqualityExpression();
364    if( token != LOGICALAND)  return p;
365    if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
366        G4cerr << "Parameter range: illegal type at '&&'" << G4endl;
367        paramERR = 1;
368    }
369    result.I = p.I;
370    while (token == LOGICALAND)
371    {
372        token = Yylex();
373        p = EqualityExpression();
374        if( p.type == CONSTSTRING || p.type == IDENTIFIER ) {
375            G4cerr << "Parameter range: illegal type at '&&'" << G4endl;
376            paramERR = 1;
377        }
378        switch (p.type) {
379            case CONSTINT:
380                result.*= p.I;
381                result.type = CONSTINT;      break;
382            case CONSTDOUBLE:
383                result.I *= (p.D != 0.0);
384                result.type = CONSTINT;      break;
385            default:
386                G4cerr << "Parameter range: unknown type."<< G4endl;
387                paramERR = 1;
388        } 
389    }
390    return result;
391}
392
393
394yystype G4UIparameter:: 
395EqualityExpression(void)
396{ 
397    yystype  arg1, arg2;
398    G4int operat;
399    yystype result;
400    #ifdef DEBUG
401        G4cerr << " EqualityExpression()" <<G4endl;
402    #endif
403    result = RelationalExpression();
404    if( token==EQ || token==NE ) {
405        operat = token;
406        token =  Yylex();
407        arg1 = result;
408        arg2 = RelationalExpression();
409        result.I = Eval2( arg1, operat, arg2 );   // semantic action
410        result.type = CONSTINT;
411        #ifdef DEBUG
412            G4cerr << " return code of Eval2(): " << result.I <<G4endl;
413        #endif
414    } else {
415        if (result.type != CONSTINT && result.type != CONSTDOUBLE) { 
416            G4cerr << "Parameter range: error at EqualityExpression"
417                 << G4endl;
418            paramERR = 1;
419        }
420    }
421    return  result;
422}
423
424
425yystype G4UIparameter:: 
426RelationalExpression(void)
427{ 
428    yystype  arg1, arg2;
429    G4int operat;
430    yystype result;
431    #ifdef DEBUG
432        G4cerr << " RelationalExpression()" <<G4endl;
433    #endif
434
435    arg1 = AdditiveExpression();
436    if( token==GT || token==GE || token==LT || token==LE  ) {
437        operat = token;
438        token =  Yylex();
439        arg2 = AdditiveExpression();
440        result.I = Eval2( arg1, operat, arg2 );    // semantic action
441        result.type = CONSTINT;
442        #ifdef DEBUG
443            G4cerr << " return  Eval2(): " << G4endl;
444        #endif
445    } else {
446        result = arg1;
447    }
448    #ifdef DEBUG
449       G4cerr <<" return RelationalExpression()" <<G4endl;
450    #endif
451    return  result;
452}
453
454yystype G4UIparameter::
455AdditiveExpression(void)
456{   yystype result;
457    result = MultiplicativeExpression();
458    if( token != '+' && token != '-' )  return result;
459    G4cerr << "Parameter range: operator " 
460         << (char)token
461         << " is not supported." << G4endl;
462    paramERR = 1;
463    return  result;
464}
465
466yystype G4UIparameter::
467MultiplicativeExpression(void)
468{   yystype result;
469    result = UnaryExpression();
470    if( token != '*' && token != '/' && token != '%' ) return result;
471    G4cerr << "Parameter range: operator "
472         << (char)token
473         << " is not supported." << G4endl;
474    paramERR = 1;
475    return  result;
476}
477
478yystype G4UIparameter::
479UnaryExpression(void)
480{
481    yystype result;
482    yystype p;
483    #ifdef DEBUG
484        G4cerr <<" UnaryExpression"<< G4endl;
485    #endif
486    switch(token) {
487        case '-':
488            token = Yylex();
489            p = UnaryExpression();
490            if (p.type == CONSTINT) {
491                result.I = - p.I;
492                result.type = CONSTINT;
493            }
494            if (p.type == CONSTDOUBLE) {
495                result.D = - p.D;
496                result.type = CONSTDOUBLE;
497            }                              break;
498        case '+':
499            token = Yylex();
500            result = UnaryExpression();   break;
501        case '!':
502            token = Yylex();
503            G4cerr << "Parameter range error: "
504                 << "operator '!' is not supported (sorry)."
505                 << G4endl;
506            paramERR = 1;
507            result = UnaryExpression();   break;
508        default:
509            result = PrimaryExpression();
510    }
511    return result;
512}
513
514
515yystype G4UIparameter:: 
516PrimaryExpression(void)
517{
518     yystype result;
519     #ifdef DEBUG
520         G4cerr <<" PrimaryExpression" << G4endl;
521     #endif
522     switch (token) {
523         case IDENTIFIER:
524              result.S = yylval.S;
525              result.type =  token;
526              token = Yylex();           break;
527         case CONSTINT:
528              result.I = yylval.I;
529              result.type =  token;
530              token= Yylex();            break;
531         case CONSTDOUBLE:
532              result.D = yylval.D;
533              result.type =  token;
534              token = Yylex();           break;
535         case '(' :
536              token= Yylex();
537              result = Expression();
538              if( token !=  ')'  ) {
539                  G4cerr << " ')' expected" << G4endl;
540                  paramERR = 1;
541              }
542              token = Yylex();
543                                         break;
544         default:
545         return result;
546    }
547    return result; // never executed
548}
549
550//---------------- semantic routines ---------------------------------
551
552G4int G4UIparameter::
553Eval2(yystype arg1, G4int op, yystype arg2)
554{
555    if( (arg1.type != IDENTIFIER) && (arg2.type != IDENTIFIER)) {
556        G4cerr << parameterName
557             << ": meaningless comparison "
558             << G4int(arg1.type) << " " << G4int(arg2.type) << G4endl;
559        paramERR = 1;
560    }
561    char type = toupper( parameterType );
562    if( arg1.type == IDENTIFIER) {
563        switch (type) {
564            case 'I':
565                if ( arg2.type == CONSTINT ) {
566                    return CompareInt( newVal.I, op, arg2.I );
567                } else {
568                    G4cerr << "integer operand expected for "
569                         << parameterRange << '.' 
570                         << G4endl; 
571                }
572                 break;
573            case 'D': 
574                if ( arg2.type == CONSTDOUBLE ) {
575                    return CompareDouble( newVal.D, op, arg2.D );
576                } else
577                if ( arg2.type == CONSTINT ) { // integral promotion
578                    return CompareDouble( newVal.D, op, arg2.I );
579                } break;
580            default: ;
581        }
582    }
583    if( arg2.type == IDENTIFIER) {
584        switch (type) {
585            case 'I':
586                if ( arg1.type == CONSTINT ) {
587                    return CompareInt( arg1.I, op, newVal.I );
588                } else {
589                    G4cerr << "integer operand expected for "
590                         << parameterRange << '.' 
591                         << G4endl; 
592                }
593                 break;
594            case 'D': 
595                if ( arg1.type == CONSTDOUBLE ) {
596                    return CompareDouble( arg1.D, op, newVal.D );
597                } else
598                if ( arg1.type == CONSTINT ) { // integral promotion
599                    return CompareDouble( arg1.I, op, newVal.D );
600                } break;
601            default: ;
602        }
603    }
604    G4cerr << "no param name is specified at the param range."<<G4endl;
605    return 0;
606}
607
608G4int G4UIparameter::
609CompareInt(G4int arg1, G4int op, G4int arg2)
610{   
611    G4int result=-1;
612    G4String opr;
613    switch (op) {
614       case GT:  result = ( arg1 >  arg2); opr= ">" ;  break;
615       case GE:  result = ( arg1 >= arg2); opr= ">=";  break;
616       case LT:  result = ( arg1 <  arg2); opr= "<" ;  break;
617       case LE:  result = ( arg1 <= arg2); opr= "<=";  break;
618       case EQ:  result = ( arg1 == arg2); opr= "==";  break;
619       case NE:  result = ( arg1 != arg2); opr= "!=";  break;
620       default: 
621           G4cerr << "Parameter range: error at CompareInt" << G4endl;
622           paramERR = 1;
623    }
624    #ifdef DEBUG
625        G4cerr << "CompareInt "
626             << arg1 << " " << opr << arg2
627             << " result: " << result
628             << G4endl;
629    #endif
630    return result;
631}
632
633G4int G4UIparameter::
634CompareDouble(G4double arg1, G4int op, G4double arg2)
635{   
636    G4int result=-1;
637    G4String opr;
638    switch (op) {
639        case GT:  result = ( arg1 >  arg2); opr= ">";   break;
640        case GE:  result = ( arg1 >= arg2); opr= ">=";  break;
641        case LT:  result = ( arg1 <  arg2); opr= "<";   break;
642        case LE:  result = ( arg1 <= arg2); opr= "<=";  break;
643        case EQ:  result = ( arg1 == arg2); opr= "==";  break;
644        case NE:  result = ( arg1 != arg2); opr= "!=";  break;
645        default:
646           G4cerr << "Parameter range: error at CompareDouble" << G4endl;
647           paramERR = 1;
648    }
649    #ifdef DEBUG
650        G4cerr << "CompareDouble " 
651             << arg1 <<" " << opr << " "<< arg2
652             << " result: " << result
653             << G4endl;
654    #endif
655    return result;
656}
657
658// --------------------- utility functions --------------------------
659
660tokenNum G4UIparameter::
661Yylex()         // reads input and returns token number KR486
662{               // (returns EOF)
663    G4int c;             
664    G4String buf;
665
666    while(( c= G4UIpGetc())==' '|| c=='\t' || c== '\n' )
667        ;
668    if (c== EOF)
669        return (tokenNum)EOF;            // KR488
670    buf= "";
671    if (isdigit(c) || c== '.') {         // I or D
672        do {
673             buf += G4String((unsigned char)c);
674             c=G4UIpGetc();
675         }  while (c=='.' || isdigit(c) || 
676                   c=='e' || c=='E' || c=='+' || c=='-');
677         G4UIpUngetc(c);
678         const char* t = buf;
679         std::istringstream is(t);
680         if ( IsInt(buf.data(),20) ) {
681             is >> yylval.I;
682             return  CONSTINT;
683         } else 
684         if ( IsDouble(buf.data()) ) {
685             is >> yylval.D;
686             return  CONSTDOUBLE;
687         } else {
688             G4cerr << buf<<": numeric format error."<<G4endl;
689         }
690    }
691    buf="";
692    if (isalpha(c)|| c=='_') {           // IDENTIFIER
693        do {
694            buf += G4String((unsigned char)c); 
695        } while ((c=G4UIpGetc()) != EOF && (isalnum(c) || c=='_'));
696        G4UIpUngetc(c);
697        if( buf == parameterName ) {
698            yylval.S =buf;
699            return IDENTIFIER;
700        } else {
701            G4cerr << buf << " is not a parameter name."<< G4endl;
702            paramERR = 1;
703       }
704    }
705    switch (c) {
706      case '>':   return (tokenNum) Follow('=', GE,        GT);
707      case '<':   return (tokenNum) Follow('=', LE,        LT);
708      case '=':   return (tokenNum) Follow('=', EQ,        '=');
709      case '!':   return (tokenNum) Follow('=', NE,        '!');
710      case '|':   return (tokenNum) Follow('|', LOGICALOR, '|');
711      case '&':   return (tokenNum) Follow('&', LOGICALAND, '&');
712      default:
713          return (tokenNum) c;
714    }
715}
716
717
718G4int G4UIparameter::
719Follow(G4int expect, G4int ifyes, G4int ifno)
720{
721    G4int c = G4UIpGetc();
722    if ( c== expect)
723          return ifyes;
724    G4UIpUngetc(c);
725    return ifno;
726}
727
728//------------------ low level routines -----------------------------
729G4int G4UIparameter::
730G4UIpGetc() {                        // emulation of getc()
731    G4int length = parameterRange.length();
732    if( bp < length)
733        return  parameterRange(bp++);
734    else 
735        return EOF;
736}
737G4int G4UIparameter::
738G4UIpUngetc(G4int c) {                 // emulation of ungetc()
739    if (c<0) return -1;
740    if (bp >0 && c == parameterRange(bp-1)) {
741         --bp;
742    } else {
743         G4cerr << "G4UIpUngetc() failed." << G4endl;
744         G4cerr << "bp="<<bp <<" c="<<c
745              << " pR(bp-1)=" << parameterRange(bp-1)
746              << G4endl;
747         paramERR = 1;
748         return -1;
749    }
750    return 0;
751}
752// *****  end of CheckNewValue() related code  ******
753
Note: See TracBrowser for help on using the repository browser.