OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [tools/] [src/] [libcdl/] [cdlmisc.cxx] - Blame information for rev 357

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 26 unneback
//{{{  Banner                                                   
2
 
3
//============================================================================
4
//
5
//      cdlmisc.cxx
6
//
7
//      Implementation of the various CDL utility member functions.
8
//
9
//============================================================================
10
//####COPYRIGHTBEGIN####
11
//                                                                          
12
// ----------------------------------------------------------------------------
13
// Copyright (C) 1998, 1999, 2000 Red Hat, Inc.
14
//
15
// This file is part of the eCos host tools.
16
//
17
// This program is free software; you can redistribute it and/or modify it 
18
// under the terms of the GNU General Public License as published by the Free 
19
// Software Foundation; either version 2 of the License, or (at your option) 
20
// any later version.
21
// 
22
// This program is distributed in the hope that it will be useful, but WITHOUT 
23
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
24
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
25
// more details.
26
// 
27
// You should have received a copy of the GNU General Public License along with
28
// this program; if not, write to the Free Software Foundation, Inc., 
29
// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
30
//
31
// ----------------------------------------------------------------------------
32
//                                                                          
33
//####COPYRIGHTEND####
34
//============================================================================
35
//#####DESCRIPTIONBEGIN####
36
//
37
// Author(s):   bartv
38
// Contact(s):  bartv
39
// Date:        1998/03/04
40
// Version:     0.01
41
//
42
//####DESCRIPTIONEND####
43
//============================================================================
44
 
45
//}}}
46
//{{{  #include's                                               
47
 
48
// ----------------------------------------------------------------------------
49
#include "cdlconfig.h"
50
 
51
// Get the infrastructure types, assertions, tracing and similar
52
// facilities.
53
#include <cyg/infra/cyg_ass.h>
54
#include <cyg/infra/cyg_trac.h>
55
 
56
// <cdlcore.hxx> defines everything implemented in this module.
57
// It implicitly supplies <string>, <vector> and <map> because
58
// the class definitions rely on these headers.
59
#include <cdlcore.hxx>
60
 
61
// For access to the isdigit(), isupper(), tolower(), ... functions
62
#include <cctype>
63
 
64
// For access to sprintf(), specifically double to string conversions.
65
#include <cstdio>
66
 
67
// For access to strtod()
68
#include <cstdlib>
69
 
70
// strtod() involves errno...
71
#include <cerrno>
72
 
73
// For access to fmod()
74
#include <cmath>
75
 
76
// For access to DBL_DIG
77
#include <cfloat>
78
 
79
//}}}
80
 
81
//{{{  Cdl::is_valid_xxx()                                      
82
 
83
// ---------------------------------------------------------------------------
84
 
85
bool
86
Cdl::is_valid_value_flavor(CdlValueFlavor data)
87
{
88
    bool result = false;
89
 
90
    switch(data) {
91
      case CdlValueFlavor_None     :
92
      case CdlValueFlavor_Bool     :
93
      case CdlValueFlavor_BoolData :
94
      case CdlValueFlavor_Data     :
95
        result = true;
96
        break;
97
 
98
      default:
99
        break;
100
    }
101
 
102
    return result;
103
}
104
 
105
bool
106
Cdl::is_valid_value_source(CdlValueSource data)
107
{
108
    bool result = false;
109
 
110
    switch(data) {
111
      case CdlValueSource_Default         :
112
      case CdlValueSource_User            :
113
      case CdlValueSource_Wizard          :
114
      case CdlValueSource_Inferred        :
115
        result = true;
116
        break;
117
 
118
      default:
119
        break;
120
    }
121
 
122
    return result;
123
}
124
 
125
// ----------------------------------------------------------------------------
126
// For now CDL names are restricted to what is acceptable to the C
127
// preprocessor. This may cause problems in future, e.g. i18n.
128
 
129
bool
130
Cdl::is_valid_cdl_name(const std::string& name)
131
{
132
    CYG_REPORT_FUNCNAMETYPE("Cdl::is_valid_cdl_name", "result %d");
133
 
134
    bool result = is_valid_c_preprocessor_symbol(name);
135
 
136
    CYG_REPORT_RETVAL(result);
137
    return result;
138
}
139
 
140
bool
141
Cdl::is_valid_c_preprocessor_symbol(const std::string& symbol)
142
{
143
    CYG_REPORT_FUNCNAMETYPE("Cdl::is_valid_c_preprocessor_symbol", "result %d");
144
 
145
    bool result = true;
146
    if ("" == symbol) {
147
        result = false;
148
    } else {
149
        // A valid preprocessor symbol should begin with either an underscore
150
        // or a letter. It should then be followed by some number of underscores,
151
        // letters, or digits.
152
        //
153
        // In some locales isalpha() may succeed for characters which are not
154
        // legal for C preprocessor symbols. Instead ASCII is assumed here.
155
        if (('_' != symbol[0]) &&
156
            !(('a' <= symbol[0]) && (symbol[0] <= 'z')) &&
157
            !(('A' <= symbol[0]) && (symbol[0] <= 'Z'))) {
158
 
159
            result = false;
160
        } else {
161
            for (unsigned int i = 1; i < symbol.size(); i++) {
162
                if (('_' != symbol[i]) &&
163
                    !(('a' <= symbol[i]) && (symbol[i] <= 'z')) &&
164
                    !(('A' <= symbol[i]) && (symbol[i] <= 'Z')) &&
165
                    !(('0' <= symbol[i]) && (symbol[i] <= '9'))) {
166
 
167
                    result = false;
168
                    break;
169
                }
170
            }
171
        }
172
    }
173
 
174
    CYG_REPORT_RETVAL(result);
175
    return result;
176
}
177
 
178
//}}}
179
//{{{  Cdl::xxx_to_yyy() - strings, ints, doubles, ...          
180
 
181
// ---------------------------------------------------------------------------
182
// Conversion routines between strings, integers, doubles, bools, ...
183
//
184
// Conversions to/from integers are complicated somewhat because the
185
// data type in question is cdl_int. In the initial implementation this
186
// is 64 bits. In the long term it will be arbitrary precision and
187
// the conversion routines will need to be reimplemented.
188
//
189
// ASCII rather than EBCDIC is assumed.
190
//
191
// Some of the routines may fail, e.g. string to integer conversions.
192
// Others are guaranteed to succeed. 
193
 
194
//{{{  string_to_integer()                      
195
 
196
// ----------------------------------------------------------------------------
197
bool
198
Cdl::string_to_integer(std::string data, cdl_int& target)
199
{
200
    CYG_REPORT_FUNCNAMETYPE("Cdl::string_to_integer", "success %d");
201
 
202
    bool negative       = false;
203
    bool seen_plus      = false;
204
    bool seen_minus     = false;
205
 
206
    // Life is a bit easier if I can check for '\0'
207
    const char* ptr           = data.c_str();
208
 
209
    // Not essential but harmless.
210
    while (isspace(*ptr))
211
        ptr++;
212
 
213
    if ('+' == *ptr) {
214
        if (seen_plus) {
215
            target = 0;
216
            CYG_REPORT_RETVAL(false);
217
            return false;
218
        }
219
        seen_plus = true;
220
        ptr++;
221
    }
222
 
223
    if ('-' == *ptr) {
224
        if (seen_minus) {
225
            target = 0;
226
            CYG_REPORT_RETVAL(false);
227
            return false;
228
        }
229
        seen_minus = true;
230
        negative = true;
231
        ptr++;
232
    }
233
 
234
    cdl_int acc = 0;
235
    if ('0' == *ptr) {
236
        // This happens sufficiently often to be worth a special case.
237
        if ('\0' == ptr[1]) {
238
            target = 0;
239
            CYG_REPORT_RETVAL(true);
240
            return true;
241
        }
242
        // Hex is always worth supporting. 
243
        if (('x' == ptr[1]) || ('X' == ptr[1])) {
244
            ptr++; ptr++;
245
            if (!isxdigit(*ptr)) {
246
                CYG_REPORT_RETVAL(false);
247
                return false;
248
            }
249
            while (isxdigit(*ptr)) {
250
                cdl_int new_acc = acc * 16;
251
                if (isdigit(*ptr)) {
252
                    new_acc += (*ptr - '0');
253
                } else if (('a' <= *ptr) && (*ptr <= 'f')) {
254
                    new_acc += (*ptr + 10 - 'a');
255
                } else if (('A' <= *ptr) && (*ptr <= 'F')) {
256
                    new_acc += (*ptr + 10 - 'A');
257
                } else {
258
                    CYG_FAIL("this platform's implementation of isxdigit() is broken");
259
                }
260
                if (new_acc < acc) {
261
                    CYG_REPORT_RETVAL(false);
262
                    return false;
263
                }
264
                acc = new_acc;
265
                ptr++;
266
            }
267
            if ('\0' != *ptr) {
268
                CYG_REPORT_RETVAL(false);
269
                return false;
270
            }
271
            if (negative) {
272
                cdl_int new_acc = 0 - acc;
273
                if (new_acc > 0) {
274
                    CYG_REPORT_RETVAL(false);
275
                    return false;
276
                } else {
277
                    acc = new_acc;
278
                }
279
            }
280
            target = acc;
281
            CYG_REPORT_RETVAL(true);
282
            return true;
283
        }
284
 
285
        // Octal? Oh well, might as well be complete.
286
        if (('0' <= ptr[1]) && (ptr[1] <= '7')) {
287
            ptr++;
288
            do {
289
                cdl_int new_acc = 8 * acc;
290
                new_acc += (*ptr - '0');
291
                if (new_acc < acc) {
292
                    CYG_REPORT_RETVAL(false);
293
                    return false;
294
                }
295
                acc = new_acc;
296
                ptr++;
297
            } while (('0' <= *ptr) && (*ptr <= '7'));
298
            if ('\0' != *ptr) {
299
                CYG_REPORT_RETVAL(false);
300
                return false;
301
            }
302
            if (negative) {
303
                cdl_int new_acc = 0 - acc;
304
                if (new_acc > 0) {
305
                    CYG_REPORT_RETVAL(false);
306
                    return false;
307
                }
308
                else {
309
                    acc = new_acc;
310
                }
311
            }
312
            target = acc;
313
            CYG_REPORT_RETVAL(true);
314
            return true;
315
        }
316
 
317
        // Drop through for the case of a decimal.
318
    }
319
 
320
    while(isdigit(*ptr)) {
321
        cdl_int new_acc = 10 * acc;
322
        new_acc += (*ptr - '0');
323
        if (new_acc < acc) {
324
            CYG_REPORT_RETVAL(false);
325
            return false;
326
        }
327
        acc = new_acc;
328
        ptr++;
329
    }
330
    if ('\0' != *ptr) {
331
        CYG_REPORT_RETVAL(false);
332
        return false;
333
    }
334
    if (negative) {
335
        cdl_int new_acc = 0 - acc;
336
        if (new_acc > 0) {
337
            CYG_REPORT_RETVAL(false);
338
            return false;
339
        } else {
340
            acc = new_acc;
341
        }
342
    }
343
    target = acc;
344
    CYG_REPORT_RETVAL(true);
345
    return true;
346
}
347
 
348
//}}}
349
//{{{  string_to_double()                       
350
 
351
// ----------------------------------------------------------------------------
352
// There is no point in doing this the hard way, just use standard
353
// library calls.
354
//
355
// There is an obvious question as to how much precision can get lost
356
// doing the conversion to a string. In practice this should not matter
357
// too much, since the expression handling code generally keeps the
358
// original double precision lying around to be re-used. However it may
359
// be desirable to keep the libcdl behaviour in synch with Tcl's
360
// tcl_precision variable.
361
 
362
bool
363
Cdl::string_to_double(std::string value, double& target)
364
{
365
    CYG_REPORT_FUNCNAMETYPE("Cdl::string_to_double", "success %d");
366
 
367
    bool        result      = true;
368
    const char* start_ptr   = value.c_str();
369
    char*       end_ptr;
370
    int         old_errno   = errno;
371
 
372
    errno                   = 0;
373
    double conv             = strtod(start_ptr, &end_ptr);
374
    if (0 != errno) {
375
        CYG_ASSERT(ERANGE == errno, "standard-compliant C library");
376
        result = false;
377
    } else if ('\0' != *end_ptr) {
378
        result = false;
379
    } else {
380
        target = conv;
381
        result = true;
382
    }
383
 
384
    errno = old_errno;
385
    CYG_REPORT_RETVAL(result);
386
    return result;
387
}
388
 
389
//}}}
390
//{{{  string_to_bool()                         
391
 
392
// ----------------------------------------------------------------------------
393
// Conversions to and from bools. The only real issue here is exactly
394
// what strings should be accepted as synonyms for true and false.
395
// It is not actually clear that these functions are useful.
396
bool
397
Cdl::string_to_bool(std::string data, bool& target)
398
{
399
    CYG_REPORT_FUNCNAMETYPE("Cdl::string_to_bool", "success %d");
400
 
401
    // Arguably there should be a precondition ( "" != data )
402
    bool result = false;
403
 
404
    // What is truth ?
405
    if (( data == "1"   ) || (data == "true") ||
406
        ( data == "True") || (data == "TRUE") ) {
407
        result = true;
408
        target = true;
409
    } else if ((data == "0"    ) || (data == "false") ||
410
               (data == "False") || (data == "FALSE") ) {
411
        result = true;
412
        target = false;
413
    }
414
 
415
    CYG_REPORT_RETVAL(result);
416
    return result;
417
}
418
 
419
//}}}
420
 
421
//{{{  integer_to_string()                      
422
 
423
// ----------------------------------------------------------------------------
424
 
425
std::string
426
Cdl::integer_to_string(cdl_int value, CdlValueFormat format)
427
{
428
    std::string result;
429
    Cdl::integer_to_string(value, result, format);
430
    return result;
431
}
432
 
433
void
434
Cdl::integer_to_string(cdl_int value, std::string& target, CdlValueFormat format)
435
{
436
    CYG_REPORT_FUNCNAME("Cdl::integer_to_string");
437
    CYG_REPORT_FUNCARG2XV((long) value, format);
438
 
439
    // Optimise this special case.
440
    if (0 == value) {
441
        if (CdlValueFormat_Hex == format) {
442
            target = "0x0";
443
        } else {
444
            target = "0";
445
        }
446
        CYG_REPORT_RETVAL(true);
447
        return;
448
    }
449
 
450
    // A local buffer to construct partial strings. This avoids
451
    // unnecessary std::string reallocation.
452
    // 64 bits and three bits at a time for octal numbers gives 21 digits,
453
    // plus spares for the leading '0' and the terminator.
454
    char local_buf[24];
455
    char *local_ptr = &(local_buf[23]);
456
    *local_ptr-- = '\0';
457
 
458
    if (CdlValueFormat_Hex == format) {
459
 
460
        // Output the data as 0x... with either 8 or 16 digits,
461
        // depending on the size.
462
        int i;
463
        for (i = 0; i < 8; i++) {
464
            int tmp = (int) (value & 0x0F);
465
            value   = value >> 4;
466
            if (tmp < 10) {
467
                *local_ptr-- = '0' + tmp;
468
            } else {
469
                *local_ptr-- = 'A' + (tmp - 10);
470
            }
471
        }
472
        // Beware of right shifts that preserve the sign bit.
473
        {
474
            int tmp1 = (value & 0x0FFFF);
475
            int tmp2 = ((value >> 16) & 0x0FFFF);
476
            value    = (tmp2 << 16) + tmp1;
477
        }
478
        if (value != 0) {
479
            for (i = 0; i < 8; i++) {
480
                int tmp = (int) (value & 0x0F);
481
                value   = value >> 4;
482
                if (tmp < 10) {
483
                    *local_ptr-- = '0' + tmp;
484
                } else {
485
                    *local_ptr-- = 'A' + (tmp - 10);
486
                }
487
            }
488
        }
489
        *local_ptr-- = 'x';
490
        *local_ptr   = '0';
491
        target = std::string(local_ptr);
492
 
493
    } else if (CdlValueFormat_Octal == format) {
494
 
495
        // Simply output the data three bits at a time, do not worry about any
496
        // particular width restrictions. However it is necessary to worry
497
        // about masking.
498
        cdl_int mask = 0x1FFFFFFF;
499
        mask = (mask << 16) | 0x0FFFF;
500
        mask = (mask << 16) | 0x0FFFF;
501
 
502
        target = "";
503
        while (value > 0) {
504
            int tmp = value & 0x07;
505
            value   = (value >> 3) & mask;
506
            *local_ptr-- = '0' + tmp;
507
        }
508
        *local_ptr = '0';
509
        target = std::string(local_ptr);
510
 
511
    } else {
512
        // A simple decimal number      
513
        // Switch to positive arithmetic.
514
        bool negative = false;
515
        if (value < 0) {
516
            negative = true;
517
            value    = 0 - value;
518
            // Only MININT cannot be converted using the above line
519
            if (value < 0) {
520
                target = "-9223372036854775808";
521
                CYG_REPORT_RETVAL(true);
522
                return;
523
            }
524
        }
525
 
526
        while (value > 0) {
527
            int rem = (int) (value % 10);
528
            value   = value / 10;
529
            *local_ptr-- = '0' + rem;
530
        }
531
        if (negative) {
532
            *local_ptr-- = '-';
533
        }
534
        local_ptr++;
535
        target = std::string(local_ptr);
536
    }
537
 
538
    CYG_REPORT_RETURN();
539
    return;
540
}
541
 
542
//}}}
543
//{{{  double_to_string()                       
544
 
545
// ----------------------------------------------------------------------------
546
 
547
std::string
548
Cdl::double_to_string(double value, CdlValueFormat format)
549
{
550
    std::string result;
551
    Cdl::double_to_string(value, result, format);
552
    return result;
553
}
554
 
555
void
556
Cdl::double_to_string(double value, std::string& result, CdlValueFormat format)
557
{
558
    CYG_REPORT_FUNCNAME("Cdl::double_to_String");
559
 
560
    char buf[256];      // This should be plenty :-)
561
    sprintf(buf, "%.*G", DBL_DIG, value);
562
    result = buf;
563
 
564
    CYG_UNUSED_PARAM(CdlValueFormat, format);
565
    CYG_REPORT_RETURN();
566
}
567
 
568
//}}}
569
//{{{  bool_to_string()                         
570
 
571
// ----------------------------------------------------------------------------
572
// Should the string results be 1/0 or true/false? Not that
573
// it really matters. The testcase in cdl1.cxx expects 1/0.
574
std::string
575
Cdl::bool_to_string(bool value)
576
{
577
    std::string result;
578
    Cdl::bool_to_string(value, result);
579
    return result;
580
}
581
 
582
void
583
Cdl::bool_to_string(bool value, std::string& target)
584
{
585
    CYG_REPORT_FUNCNAME("Cdl::bool_to_string");
586
    CYG_REPORT_FUNCARG1( "value arg %ld", (long) value);
587
 
588
    if (value)
589
        target = "1";
590
    else
591
        target = "0";
592
 
593
    CYG_REPORT_RETURN();
594
}
595
 
596
//}}}
597
 
598
//{{{  integer_to_double()                      
599
 
600
// ----------------------------------------------------------------------------
601
// Currently integer to double cannot fail, although there may well be loss
602
// of accurary. Eventually cdl_int may be an arbitrary precision integer
603
// in which case conversion to double is not guaranteed.
604
double
605
Cdl::integer_to_double(cdl_int value)
606
{
607
    CYG_REPORT_FUNCNAME("Cdl::integer_to_double");
608
 
609
    double result = (double) value;
610
 
611
    CYG_REPORT_RETURN();
612
    return result;
613
}
614
 
615
void
616
Cdl::integer_to_double(cdl_int value, double& target)
617
{
618
    CYG_REPORT_FUNCNAME("Cdl::integer_to_double");
619
 
620
    target = (double) value;
621
 
622
    CYG_REPORT_RETURN();
623
}
624
 
625
//}}}
626
//{{{  double_to_integer()                      
627
 
628
// Conversion from double to integer is only allowed if there is no loss
629
// of data. modf() is useful here
630
bool
631
Cdl::double_to_integer(double value, cdl_int& target)
632
{
633
    CYG_REPORT_FUNCNAMETYPE("Cdl::double_to_integer", "result %d");
634
 
635
    bool   result = false;
636
 
637
    double integral;
638
    double frac;
639
 
640
    frac = modf(value, &integral);
641
    if (0.0 == frac) {
642
        // Looking good, but integral may still be too big.
643
        cdl_int tmp = (cdl_int) integral;
644
        if (tmp == value) {
645
            // No fraction, no loss of data, everything looking good
646
            target = tmp;
647
            result = true;
648
        }
649
    }
650
 
651
    CYG_REPORT_RETVAL(result);
652
    return result;
653
}
654
 
655
//}}}
656
 
657
//}}}
658
//{{{  Cdl::xxx_to_yyy() - CDL-specific data types              
659
 
660
// ----------------------------------------------------------------------------
661
// Conversions between strings and flavors.
662
 
663
static struct {
664
    char*               name;
665
    CdlValueFlavor      flavor;
666
} valid_flavors[] = {
667
    { "none",           CdlValueFlavor_None     },
668
    { "bool",           CdlValueFlavor_Bool     },
669
    { "booldata",       CdlValueFlavor_BoolData },
670
    { "data",           CdlValueFlavor_Data     },
671
    { 0,                CdlValueFlavor_Invalid  }
672
};
673
 
674
bool
675
Cdl::string_to_flavor(std::string name, CdlValueFlavor& target)
676
{
677
    CYG_REPORT_FUNCNAMETYPE("Cdl::string_to_flavor", "success %d");
678
 
679
    bool result = false;
680
 
681
    // First convert the argument to lower case. Arguably this is incorrect,
682
    // Tcl is a case-sensitive language, but the conversion is unlikely ever
683
    // to be harmfull.
684
    for (std::string::iterator str_i = name.begin(); str_i != name.end(); str_i++) {
685
        if (isupper(*str_i)) {
686
            *str_i = tolower(*str_i);
687
        }
688
    }
689
 
690
    // Now look for a match in the table.
691
    int match           = -1;
692
    int i;
693
    const char* c_str   = name.c_str();
694
    int len             = strlen(c_str);
695
 
696
    for (i = 0; 0 != valid_flavors[i].name; i++) {
697
        if (0 == strncmp(c_str, valid_flavors[i].name, len)) {
698
            // Check for an ambiguous string match.
699
            // This cannot actually happen with the current flavor names.
700
            if ( -1 != match) {
701
                break;
702
            }
703
            match = i;
704
        }
705
 
706
    }
707
    if (-1 != match) {
708
        target = valid_flavors[match].flavor;
709
        result = true;
710
    }
711
    CYG_REPORT_RETVAL(result);
712
    return result;
713
}
714
 
715
bool
716
Cdl::flavor_to_string(CdlValueFlavor flavor, std::string& target)
717
{
718
    CYG_REPORT_FUNCNAMETYPE("Cdl::flavor_to_string", "success %d");
719
 
720
    bool result = false;
721
 
722
    for (int i = 0; 0 != valid_flavors[i].name; i++) {
723
        if (flavor == valid_flavors[i].flavor) {
724
            target = valid_flavors[i].name;
725
            result = true;
726
            break;
727
        }
728
    }
729
 
730
    CYG_REPORT_RETVAL(result);
731
    return result;
732
}
733
 
734
// ----------------------------------------------------------------------------
735
// Similar support for value sources.
736
 
737
static struct {
738
    char*               name;
739
    CdlValueSource      source;
740
} valid_sources[] = {
741
    { "default",        CdlValueSource_Default  },
742
    { "inferred",       CdlValueSource_Inferred },
743
    { "wizard",         CdlValueSource_Wizard   },
744
    { "user",           CdlValueSource_User     },
745
    { 0,                CdlValueSource_Invalid  }
746
};
747
 
748
bool
749
Cdl::string_to_source(std::string name, CdlValueSource& target)
750
{
751
    CYG_REPORT_FUNCNAMETYPE("Cdl::string_to_source", "success %d");
752
 
753
    bool result = false;
754
 
755
    // First convert the argument to lower case. Arguably this is incorrect,
756
    // Tcl is a case-sensitive language, but the conversion is unlikely ever
757
    // to be harmfull.
758
    for (std::string::iterator str_i = name.begin(); str_i != name.end(); str_i++) {
759
        if (isupper(*str_i)) {
760
            *str_i = tolower(*str_i);
761
        }
762
    }
763
 
764
    // Now look for a match in the table.
765
    int match           = -1;
766
    int i;
767
    const char* c_str   = name.c_str();
768
    int len             = strlen(c_str);
769
 
770
    for (i = 0; 0 != valid_sources[i].name; i++) {
771
        if (0 == strncmp(c_str, valid_sources[i].name, len)) {
772
            // Check for an ambiguous string match.
773
            // This cannot actually happen with the current source names.
774
            if ( -1 != match) {
775
                break;
776
            }
777
            match = i;
778
        }
779
 
780
    }
781
    if (-1 != match) {
782
        target = valid_sources[match].source;
783
        result = true;
784
    }
785
    CYG_REPORT_RETVAL(result);
786
    return result;
787
}
788
 
789
bool
790
Cdl::source_to_string(CdlValueSource source, std::string& target)
791
{
792
    CYG_REPORT_FUNCNAMETYPE("Cdl::source_to_string", "success %d");
793
 
794
    bool result = false;
795
 
796
    for (int i = 0; 0 != valid_sources[i].name; i++) {
797
        if (source == valid_sources[i].source) {
798
            target = valid_sources[i].name;
799
            result = true;
800
            break;
801
        }
802
    }
803
 
804
    CYG_REPORT_RETVAL(result);
805
    return result;
806
}
807
 
808
//}}}
809
//{{{  Cdl::get_library_version()                               
810
 
811
// ----------------------------------------------------------------------------
812
// The version of the library actually lives inside configure.in. It gets
813
// exported into cdlconfig.h
814
std::string
815
Cdl::get_library_version(void)
816
{
817
    return std::string(CYGNUM_LIBCDL_VERSION);
818
}
819
 
820
//}}}
821
//{{{  Cdl::set_interactive()                                   
822
 
823
// ----------------------------------------------------------------------------
824
// Some CDL scripts and some bits of the library may want to adapt depending
825
// on whether or not the application is running fully interactively or in
826
// batch mode. The primary distinction is that a batch program should never
827
// attempt to obtain user input, whether via Tk widgets or by other means.
828
 
829
bool Cdl::interactive   = false;
830
 
831
void
832
Cdl::set_interactive(bool value)
833
{
834
    CYG_REPORT_FUNCNAME("Cdl::set_interactive");
835
    CYG_REPORT_FUNCARG1D(value);
836
 
837
    interactive = value;
838
}
839
 
840
bool
841
Cdl::is_interactive(void)
842
{
843
    CYG_REPORT_FUNCNAMETYPE("Cdl::is_interactive", "interactive %d");
844
    CYG_REPORT_RETVAL(interactive);
845
    return interactive;
846
}
847
 
848
//}}}
849
//{{{  version support()                                        
850
 
851
// ----------------------------------------------------------------------------
852
// Packages may need to impose constraints on which versions of other
853
// packages they can coexist with. This requires some way of achieving
854
// a partial ordering of version numbers. Unfortunately there are many
855
// different ways of specifying a version number, and we cannot impose
856
// a single model on all third party package developers. Instead this
857
// routine performs some semi-intelligent comparisons of two version
858
// strings which should work in the vast majority of cases.
859
//
860
// The return value is as per strcmp(), -1 if the first entry is
861
// smaller (i.e. the more recent and hence hopefully the first in
862
// a list), +1 if the second entry is smaller, 0 if the two are
863
// identical.
864
//
865
// There is a big ambiguity between "derived" versions and "experimental"
866
// versions. Something like v0.3beta is experimental, i.e. it is older
867
// than the full release v0.3. On the other hand v0.3.p1 is a patched
868
// version of v0.3 and hence newer. This code uses the presence or otherwise
869
// of a separator to decide between the two cases.
870
 
871
// A utility routine which checks whether or not a character counts
872
// as a separator. Currently the characters . - and _ are all accepted
873
// as field separators.
874
//
875
// Arguably - should not be accepted as a separator. Instead if it preceeds
876
// a digit it could be interpreted as part of a prerelease number.
877
 
878
static bool
879
is_separator(int ch)
880
{
881
    return ('.' == ch) || ('-' == ch) || ('_' == ch);
882
}
883
 
884
int
885
Cdl::compare_versions(std::string arg1, std::string arg2)
886
{
887
    CYG_REPORT_FUNCNAMETYPE("Cdl::compare_versions", "result %d");
888
 
889
    if (arg1 == arg2) {
890
        CYG_REPORT_RETVAL(0);
891
        return 0;
892
    }
893
 
894
    // The version number "current" is special, it always indicates the most
895
    // recent version e.g. as checked out from a CVS repository.
896
    if ("current" == arg1) {
897
        CYG_REPORT_RETVAL(-1);
898
        return -1;
899
    }
900
    if ("current" == arg2) {
901
        CYG_REPORT_RETVAL(1);
902
        return 1;
903
    }
904
 
905
    const char* ptr1 = arg1.c_str();
906
    const char* ptr2 = arg2.c_str();
907
    int num1    = 0;
908
    int num2    = 0;
909
 
910
    // If both strings start with 'v' or 'V', skip this. A minor variation in
911
    // case at the start of a string should be ignored.
912
    if ((('v' == *ptr1) || ('V' == *ptr1)) &&
913
        (('v' == *ptr2) || ('V' == *ptr2))) {
914
        ptr1++;
915
        ptr2++;
916
    }
917
 
918
    // Now process the rest of the version string, one unit at a time.
919
    while (1) {
920
 
921
        if (('\0' == *ptr1) && ('\0' == *ptr2)) {
922
            // Both strings have terminated at the same time. There
923
            // may have been some spurious leading zeroes in numbers,
924
            // or irrelevant differences in the separators.
925
            CYG_REPORT_RETVAL(0);
926
            return 0;
927
        }
928
 
929
        if ('\0' == *ptr1) {
930
            // The first string has ended first. If the second string currently
931
            // points at a separator then arg2 is a derived version, e.g.
932
            // v0.3.p1, and hence newer. Otherwise arg2 is an experimental
933
            // version v0.3beta and hence older.
934
            if (is_separator(*ptr2)) {
935
                CYG_REPORT_RETVAL(1);
936
                return 1;
937
            } else {
938
                CYG_REPORT_RETVAL(-1);
939
                return -1;
940
            }
941
        }
942
 
943
        if ('\0' == *ptr2) {
944
            // As per the previous test.
945
            if (is_separator(*ptr1)) {
946
                CYG_REPORT_RETVAL(-1);
947
                return -1;
948
            } else {
949
                CYG_REPORT_RETVAL(1);
950
                return 1;
951
            }
952
        }
953
 
954
        // If both strings currently point at numerical data, do a conversion and
955
        // a numerical comparison.
956
        if (isdigit(*ptr1) && isdigit(*ptr2)) {
957
            num1 = 0;
958
            num2 = 0;
959
            // Strictly speaking there should be some overflow tests here, but it
960
            // is not worth the trouble.
961
            do {
962
                num1 = (10 * num1) + (*ptr1++ - '0');
963
            } while(isdigit(*ptr1));
964
            do {
965
                num2 = (10 * num2) + (*ptr2++ - '0');
966
            } while(isdigit(*ptr2));
967
            // v2.0 is newer than v1.0
968
            if (num1 < num2) {
969
                CYG_REPORT_RETVAL(1);
970
                return 1;
971
            } else if (num1 > num2) {
972
                CYG_REPORT_RETVAL(-1);
973
                return -1;
974
            } else {
975
                continue;
976
            }
977
        }
978
 
979
        // Non-numerical data. If the two characters are the same then
980
        // move on. Note: this has to happen after numerical conversions
981
        // to distinguish v10.0 and v1.0
982
        if (*ptr1 == *ptr2) {
983
            ptr1++; ptr2++;
984
            continue;
985
        }
986
 
987
        // If both strings are currently at a separator then move on. All
988
        // separators can be used interchangeably.
989
        if (is_separator(*ptr1) && is_separator(*ptr2)) {
990
            ptr1++; ptr2++;
991
            continue;
992
        }
993
 
994
        // If only one string is at a separator, special action
995
        // is needed. v1.1alpha is interpreted as earlier than
996
        // v1.1, but v1.1.3 is a later release.
997
        if (is_separator(*ptr1)) {
998
            return -1;
999
        } else if (is_separator(*ptr2)) {
1000
            return 1;
1001
        }
1002
 
1003
        // Two different characters, e.g. v1.0alpha vs. v1.0beta
1004
        if (*ptr1 < *ptr2) {
1005
            CYG_REPORT_RETVAL(1);
1006
            return 1;
1007
        } else {
1008
            CYG_REPORT_RETVAL(-1);
1009
            return -1;
1010
        }
1011
    }
1012
 
1013
    // Not reachable.
1014
}
1015
 
1016
// ----------------------------------------------------------------------------
1017
// Given a version string, extract major, minor and release numbers.
1018
// Some or all of these may be absent. Basically the code just
1019
// iterates through the string looking for sequences of numbers.
1020
 
1021
static void
1022
version_extract_number(const std::string& version, unsigned int& index, std::string& result)
1023
{
1024
    CYG_REPORT_FUNCNAME("version_extract_number");
1025
 
1026
    // The calling code is expected to supply a sensible default.
1027
    // Search for a digit
1028
    for ( ; index < version.size(); index++) {
1029
        if (isdigit(version[index])) {
1030
            break;
1031
        }
1032
    }
1033
    if (index != version.size()) {
1034
        result = "";
1035
        if ((index > 0) && ('-' == version[index-1])) {
1036
            result = "-";
1037
        }
1038
        do {
1039
            result += version[index++];
1040
        } while ((index < version.size()) && isdigit(version[index]));
1041
    }
1042
 
1043
    CYG_REPORT_RETURN();
1044
}
1045
 
1046
void
1047
Cdl::split_version_string(const std::string& version, std::string& major, std::string& minor, std::string& release)
1048
{
1049
    CYG_REPORT_FUNCNAME("CdlMisc::split_version_string");
1050
 
1051
    unsigned int index = 0;
1052
    version_extract_number(version, index, major);
1053
    version_extract_number(version, index, minor);
1054
    version_extract_number(version, index, release);
1055
 
1056
    CYG_REPORT_RETURN();
1057
}
1058
 
1059
//}}}
1060
//{{{  Cdl::get_short_form()                                    
1061
 
1062
// ----------------------------------------------------------------------------
1063
// It is occasionally useful to take a full CDL name such as CYgpkg_KERNEL
1064
// and turn it into a short form such as "kernel". This involves discarding
1065
// everything up to and including the first underscore, then lowercasing
1066
// all subsequent characters.
1067
std::string
1068
Cdl::get_short_form(const std::string& original)
1069
{
1070
    CYG_REPORT_FUNCNAME("CdlMisc::get_short_form");
1071
 
1072
    std::string  result = "";
1073
    unsigned int size = original.size();
1074
    unsigned int i;
1075
    for (i = 0; i < size; i++) {
1076
        if ('_' == original[i]) {
1077
            i++;
1078
            break;
1079
        }
1080
    }
1081
 
1082
    // Either at end of string, or just past the first underscore
1083
    for ( ; i < size; i++) {
1084
        if (isupper(original[i])) {
1085
            result += tolower(original[i]);
1086
        } else {
1087
            result += original[i];
1088
        }
1089
    }
1090
 
1091
    CYG_REPORT_RETURN();
1092
    return result;
1093
}
1094
 
1095
//}}}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.