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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [host/] [libcdl/] [config.cxx] - Blame information for rev 838

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

Line No. Rev Author Line
1 786 skrzyp
//{{{  Banner                                           
2
 
3
//============================================================================
4
//
5
//     config.cxx
6
//
7
//     Implementation of the CdlConfiguration class
8
//
9
//============================================================================
10
// ####ECOSHOSTGPLCOPYRIGHTBEGIN####                                        
11
// -------------------------------------------                              
12
// This file is part of the eCos host tools.                                
13
// Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.      
14
//
15
// This program is free software; you can redistribute it and/or modify     
16
// it under the terms of the GNU General Public License as published by     
17
// the Free Software Foundation; either version 2 or (at your option) any   
18
// later version.                                                           
19
//
20
// This program is distributed in the hope that it will be useful, but      
21
// WITHOUT ANY WARRANTY; without even the implied warranty of               
22
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        
23
// General Public License for more details.                                 
24
//
25
// You should have received a copy of the GNU General Public License        
26
// along with this program; if not, write to the                            
27
// Free Software Foundation, Inc., 51 Franklin Street,                      
28
// Fifth Floor, Boston, MA  02110-1301, USA.                                
29
// -------------------------------------------                              
30
// ####ECOSHOSTGPLCOPYRIGHTEND####                                          
31
//============================================================================
32
//#####DESCRIPTIONBEGIN####
33
//
34
// Author(s):   bartv
35
// Contact(s):  bartv
36
// Date:        1999/03/06
37
// Version:     0.02
38
//
39
//####DESCRIPTIONEND####
40
//============================================================================
41
 
42
//}}}
43
//{{{  #include's                                       
44
 
45
// ----------------------------------------------------------------------------
46
#include "cdlconfig.h"
47
 
48
// Get the infrastructure types, assertions, tracing and similar
49
// facilities.
50
#include <cyg/infra/cyg_ass.h>
51
#include <cyg/infra/cyg_trac.h>
52
 
53
// <cdl.hxx> defines everything implemented in this module.
54
// It implicitly supplies <string>, <vector> and <map> because
55
// the class definitions rely on these headers.
56
#include <cdl.hxx>
57
 
58
//}}}
59
 
60
//{{{  CdlConfiguration constants and statics           
61
 
62
// ----------------------------------------------------------------------------
63
CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlConfigurationBody);
64
 
65
//}}}
66
//{{{  CdlConfiguration:: creation                      
67
 
68
// ----------------------------------------------------------------------------
69
// The toplevel class will take care of just about everything.
70
 
71
CdlConfigurationBody::CdlConfigurationBody(std::string name, CdlPackagesDatabase db, CdlInterpreter interp)
72
    : CdlNodeBody(name),
73
      CdlToplevelBody(interp)
74
{
75
    CYG_REPORT_FUNCNAME("CdlConfiguration:: constructor");
76
    CYG_REPORT_FUNCARG1XV(this);
77
 
78
    current_hardware    = "";
79
    current_template    = "";
80
    database            = db;
81
    save_file           = "";
82
    description         = "";
83
 
84
    cdlconfigurationbody_cookie = CdlConfigurationBody_Magic;
85
    CYGDBG_MEMLEAK_CONSTRUCTOR();
86
 
87
    CYG_POSTCONDITION_THISC();
88
    CYG_REPORT_RETURN();
89
}
90
 
91
// ----------------------------------------------------------------------------
92
// The exported interface
93
 
94
CdlConfiguration
95
CdlConfigurationBody::make(std::string name, CdlPackagesDatabase db, CdlInterpreter interp)
96
{
97
    CYG_REPORT_FUNCNAMETYPE("CdlConfiguration::make", "result %p");
98
    CYG_REPORT_FUNCARG2XV(db, interp);
99
    CYG_PRECONDITIONC("" != name);
100
    CYG_PRECONDITION_CLASSC(db);
101
    CYG_PRECONDITION_CLASSC(interp);
102
 
103
    CdlConfiguration result = new CdlConfigurationBody(name, db, interp);
104
    CYG_REPORT_RETVAL(result);
105
    return result;
106
}
107
 
108
//}}}
109
//{{{  CdlConfiguration:: destructor                    
110
 
111
// ----------------------------------------------------------------------------
112
CdlConfigurationBody::~CdlConfigurationBody()
113
{
114
    CYG_REPORT_FUNCNAME("CdlConfiguration:: default destructor");
115
    CYG_REPORT_FUNCARG1("this %p", this);
116
    CYG_PRECONDITION_THISC();
117
 
118
    // Removing all the packages has to happen here, and in the
119
    // context of a transaction. The main reason is the extensive
120
    // use of dynamic casts, after this destructor returns
121
    // any dynamic casts for this configuration will fail.
122
    //
123
    // Arguably some of the unloads should happen by clearing
124
    // the hardware and template (assuming those are currently
125
    // set). In practice that would not really gain anything.
126
    //
127
    // Unloading the individual packages is a bit more expensive
128
    // than it should be, since lots of care is taken to keep
129
    // remaining packages consistent and then those get unloaded
130
    // as well. However it is the safe approach.
131
    CdlLocalTransaction transaction(this);
132
    const std::vector<CdlLoadable>& loadables = this->get_loadables();
133
    for (int i = loadables.size() - 1; i >= 0; i--) {
134
        CdlPackage pkg = dynamic_cast<CdlPackage>(loadables[i]);
135
        if (0 != pkg) {
136
            this->unload_package(transaction.get(), pkg);
137
        }
138
    }
139
    transaction.propagate();
140
    transaction.commit();
141
 
142
    cdlconfigurationbody_cookie = CdlConfigurationBody_Invalid;
143
    current_hardware            = "";
144
    current_template            = "";
145
    database                    = 0;
146
    save_file                   = "";
147
 
148
    CYGDBG_MEMLEAK_DESTRUCTOR();
149
 
150
    CYG_REPORT_RETURN();
151
}
152
 
153
//}}}
154
//{{{  CdlConfiguration::check_this()                   
155
 
156
// ----------------------------------------------------------------------------
157
// There is very little information associated with a configuration.
158
 
159
bool
160
CdlConfigurationBody::check_this(cyg_assert_class_zeal zeal) const
161
{
162
    if (CdlConfigurationBody_Magic != cdlconfigurationbody_cookie) {
163
        return false;
164
    }
165
    CYGDBG_MEMLEAK_CHECKTHIS();
166
 
167
    switch(zeal) {
168
      case cyg_system_test      :
169
      case cyg_extreme          :
170
          if ((0 == database) || !database->check_this(cyg_quick)) {
171
              return false;
172
          }
173
      case cyg_thorough         :
174
          if (("" != current_hardware) && !database->is_known_target(current_hardware)) {
175
              return false;
176
          }
177
          if (("" != current_template) && !database->is_known_template(current_template)) {
178
              return false;
179
          }
180
      case cyg_quick            :
181
          if (0 == database) {
182
              return false;
183
          }
184
      case cyg_trivial          :
185
      case cyg_none             :
186
      default                   :
187
          break;
188
    }
189
 
190
    return CdlNodeBody::check_this(zeal) && CdlContainerBody::check_this(zeal) && CdlToplevelBody::check_this(zeal);
191
}
192
 
193
//}}}
194
//{{{  CdlConfiguration:: basic info                    
195
 
196
// ----------------------------------------------------------------------------
197
// Provide ready access to configuration-specific data.
198
 
199
CdlPackagesDatabase
200
CdlConfigurationBody::get_database() const
201
{
202
    CYG_REPORT_FUNCNAMETYPE("CdlConfiguration::get_database", "result %p");
203
    CYG_REPORT_FUNCARG1XV(this);
204
    CYG_PRECONDITION_THISC();
205
 
206
    CYG_REPORT_RETVAL(database);
207
    return database;
208
}
209
 
210
std::string
211
CdlConfigurationBody::get_hardware() const
212
{
213
    CYG_REPORT_FUNCNAME("CdlConfiguration::get_hardware");
214
    CYG_REPORT_FUNCARG1XV(this);
215
    CYG_PRECONDITION_THISC();
216
 
217
    CYG_REPORT_RETURN();
218
    return current_hardware;
219
}
220
 
221
void
222
CdlConfigurationBody::set_hardware_name(std::string new_name)
223
{
224
    CYG_REPORT_FUNCNAME("CdlConfiguration::set_hardware_name");
225
    CYG_REPORT_FUNCARG1XV(this);
226
    CYG_PRECONDITION_THISC();
227
 
228
    current_hardware = new_name;
229
 
230
    CYG_REPORT_RETURN();
231
}
232
 
233
std::string
234
CdlConfigurationBody::get_template() const
235
{
236
    CYG_REPORT_FUNCNAME("CdlConfiguration::get_template");
237
    CYG_REPORT_FUNCARG1XV(this);
238
    CYG_PRECONDITION_THISC();
239
 
240
    CYG_REPORT_RETURN();
241
    return current_template;
242
}
243
 
244
void
245
CdlConfigurationBody::set_template_name(std::string new_name)
246
{
247
    CYG_REPORT_FUNCNAME("CdlConfiguration::set_template_name");
248
    CYG_REPORT_FUNCARG1XV(this);
249
    CYG_PRECONDITION_THISC();
250
 
251
    current_template = new_name;
252
 
253
    CYG_REPORT_RETURN();
254
}
255
 
256
std::string
257
CdlConfigurationBody::get_save_file() const
258
{
259
    CYG_REPORT_FUNCNAME("CdlConfiguration::get_save_file");
260
    CYG_REPORT_FUNCARG1XV(this);
261
    CYG_PRECONDITION_THISC();
262
 
263
    CYG_REPORT_RETURN();
264
    return save_file;
265
}
266
 
267
// ----------------------------------------------------------------------------
268
 
269
std::string
270
CdlConfigurationBody::get_class_name() const
271
{
272
    CYG_REPORT_FUNCNAME("CdlConfiguration::get_class_name");
273
    CYG_PRECONDITION_THISC();
274
    CYG_REPORT_RETURN();
275
    return "CdlConfiguration";
276
}
277
 
278
//}}}
279
//{{{  Load and unload operations - wrappers            
280
 
281
// ----------------------------------------------------------------------------
282
// These members are basically wrappers for the functions that do the
283
// real work. They do things like running the real functions inside
284
// a newly created transaction.
285
 
286
void
287
CdlConfigurationBody::load_package(std::string name, std::string version,
288
                                   CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
289
{
290
    CYG_REPORT_FUNCNAME("CdlConfiguration::load_package");
291
    CYG_REPORT_FUNCARG1XV(this);
292
    CYG_PRECONDITION_THISC();
293
 
294
    CdlLocalTransaction transaction(this);
295
    this->load_package(transaction.get(), name, version, error_fn, warn_fn, limbo);
296
    transaction.body();
297
 
298
    CYG_REPORT_RETURN();
299
}
300
 
301
void
302
CdlConfigurationBody::unload_package(std::string name, bool limbo)
303
{
304
    CYG_REPORT_FUNCNAME("CdlConfiguration::unload_package");
305
    CYG_REPORT_FUNCARG1XV(this);
306
    CYG_PRECONDITION_THISC();
307
 
308
    CdlLocalTransaction transaction(this);
309
    this->unload_package(transaction.get(), name, limbo);
310
    transaction.body();
311
 
312
    CYG_REPORT_RETURN();
313
}
314
 
315
void
316
CdlConfigurationBody::unload_package(CdlPackage package, bool limbo)
317
{
318
    CYG_REPORT_FUNCNAME("CdlConfiguration::unload_package");
319
    CYG_REPORT_FUNCARG1XV(this);
320
 
321
    CdlLocalTransaction transaction(this);
322
    this->unload_package(transaction.get(), package, limbo);
323
    transaction.body();
324
 
325
    CYG_REPORT_RETURN();
326
}
327
 
328
void
329
CdlConfigurationBody::unload_package(CdlTransaction transaction, std::string name, bool limbo)
330
{
331
    CYG_REPORT_FUNCNAME("CdlConfiguration::unload_package");
332
    CYG_REPORT_FUNCARG3XV(this, transaction, limbo);
333
    CYG_INVARIANT_THISC(CdlConfigurationBody);
334
    CYG_PRECONDITION_CLASSC(transaction);
335
 
336
    CdlNode node = lookup(name);
337
    CYG_ASSERTC(0 != node);
338
    CdlPackage package  = dynamic_cast<CdlPackage>(node);
339
    CYG_ASSERTC(0 != package);
340
 
341
    this->unload_package(transaction, package, limbo);
342
 
343
    CYG_REPORT_RETURN();
344
}
345
 
346
void
347
CdlConfigurationBody::change_package_version(std::string name, std::string version,
348
                                             CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
349
{
350
    CYG_REPORT_FUNCNAME("CdlConfiguration::change_package_version");
351
    CYG_REPORT_FUNCARG1XV(this);
352
 
353
    CdlLocalTransaction transaction(this);
354
    this->change_package_version(transaction.get(), name, version, error_fn, warn_fn, limbo);
355
    transaction.body();
356
 
357
    CYG_REPORT_RETURN();
358
}
359
 
360
void
361
CdlConfigurationBody::change_package_version(CdlPackage package, std::string version,
362
                                             CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
363
{
364
    CYG_REPORT_FUNCNAME("CdlConfiguration::change_package_version");
365
    CYG_REPORT_FUNCARG1XV(this);
366
 
367
    CdlLocalTransaction transaction(this);
368
    this->change_package_version(transaction.get(), package, version, error_fn, warn_fn, limbo);
369
    transaction.body();
370
 
371
    CYG_REPORT_RETURN();
372
}
373
 
374
void
375
CdlConfigurationBody::change_package_version(CdlTransaction transaction, std::string name, std::string new_version,
376
                                             CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
377
{
378
    CYG_REPORT_FUNCNAME("CdlConfiguration::change_package_version");
379
    CYG_REPORT_FUNCARG2XV(this, transaction);
380
    CYG_PRECONDITION_THISC();
381
    CYG_PRECONDITION_CLASSC(transaction);
382
    CYG_PRECONDITIONC("" != name);
383
 
384
    CdlPackage package = 0;
385
    CdlNode node = this->lookup(name);
386
    if (0 != node) {
387
        package = dynamic_cast<CdlPackage>(node);
388
    }
389
    // For now it is illegal to change the version of package that has
390
    // not been loaded yet
391
    if (0 == package) {
392
        throw CdlInputOutputException(std::string("Cannot change version of \"") + name + "\" , this package is not loaded");
393
    }
394
    CYG_ASSERT_CLASSC(package);
395
 
396
    this->change_package_version(transaction, package, new_version, error_fn, warn_fn, limbo);
397
 
398
    CYG_REPORT_RETURN();
399
}
400
 
401
void
402
CdlConfigurationBody::add(std::string filename,
403
                          CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn)
404
{
405
    CYG_REPORT_FUNCNAME("CdlConfiguration::add");
406
    CYG_REPORT_FUNCARG1XV(this);
407
 
408
    CdlLocalTransaction transaction(this);
409
    this->add(transaction.get(), filename, error_fn, warn_fn);
410
    transaction.body();
411
 
412
    CYG_REPORT_RETURN();
413
}
414
 
415
void
416
CdlConfigurationBody::set_template(std::string name, std::string version,
417
                                   CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
418
{
419
    CYG_REPORT_FUNCNAME("CdlConfiguration::set_template");
420
    CYG_REPORT_FUNCARG1XV(this);
421
 
422
    CdlLocalTransaction transaction(this);
423
    this->set_template(transaction.get(), name, version, error_fn, warn_fn, limbo);
424
    transaction.body();
425
 
426
    CYG_REPORT_RETURN();
427
}
428
 
429
void
430
CdlConfigurationBody::set_template_file(std::string filename,
431
                                        CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
432
{
433
    CYG_REPORT_FUNCNAME("CdlConfiguration::set_template_file");
434
    CYG_REPORT_FUNCARG1XV(this);
435
 
436
    CdlLocalTransaction transaction(this);
437
    this->set_template_file(transaction.get(), filename, error_fn, warn_fn, limbo);
438
    transaction.body();
439
 
440
    CYG_REPORT_RETURN();
441
}
442
 
443
void
444
CdlConfigurationBody::set_template(CdlTransaction transaction, std::string template_name, std::string version,
445
                                   CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
446
{
447
    CYG_REPORT_FUNCNAME("CdlConfiguration::set_template");
448
    CYG_REPORT_FUNCARG2XV(this, transaction);
449
 
450
    // Some consistency checks before doing anything damaging
451
    if (!this->database->is_known_template(template_name)) {
452
        throw CdlInputOutputException("Unknown template " + template_name);
453
    }
454
    std::string template_filename = this->database->get_template_filename(template_name, version);
455
    if ("" == template_filename) {
456
        if ("" == version) {
457
            throw CdlInputOutputException("There is no template file corresponding to " + template_name);
458
        } else {
459
            throw CdlInputOutputException("There is no temmplate file corresponding to version "
460
                                          + version + " of " + template_name);
461
        }
462
    }
463
 
464
    // Now use set_template_file() to do the hard work.
465
    this->set_template_file(transaction, template_filename, error_fn, warn_fn, limbo);
466
    current_template = template_name;
467
 
468
    CYG_REPORT_RETURN();
469
}
470
 
471
void
472
CdlConfigurationBody::unload_template(bool limbo)
473
{
474
    CYG_REPORT_FUNCNAME("CdlConfiguration::unload_template");
475
    CYG_REPORT_FUNCARG1XV(this);
476
 
477
    CdlLocalTransaction transaction(this);
478
    this->unload_template(transaction.get(), limbo);
479
    transaction.body();
480
 
481
    CYG_REPORT_RETURN();
482
}
483
 
484
void
485
CdlConfigurationBody::set_hardware(std::string name,
486
                                   CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
487
{
488
    CYG_REPORT_FUNCNAME("CdlConfiguration::set_hardware");
489
    CYG_REPORT_FUNCARG1XV(this);
490
 
491
    CdlLocalTransaction transaction(this);
492
    this->set_hardware(transaction.get(), name, error_fn, warn_fn, limbo);
493
    transaction.body();
494
 
495
    CYG_REPORT_RETURN();
496
}
497
 
498
void
499
CdlConfigurationBody::unload_hardware(bool limbo)
500
{
501
    CYG_REPORT_FUNCNAME("CdlConfiguration::unload_hardware");
502
    CYG_REPORT_FUNCARG1XV(this);
503
 
504
    CdlLocalTransaction transaction(this);
505
    this->unload_hardware(transaction.get(), limbo);
506
    transaction.body();
507
 
508
    CYG_REPORT_RETURN();
509
}
510
 
511
//}}}
512
//{{{  Load and unload - transaction support            
513
 
514
// ----------------------------------------------------------------------------
515
// A number of commit/cancel auxiliary classes are needed to allow the
516
// load/unload code to integrate properly with the transaction code.
517
 
518
class CdlConfiguration_CommitCancelLoad :
519
    public CdlTransactionCommitCancelOp
520
{
521
    friend class CdlTest;
522
 
523
  public:
524
 
525
    CdlConfiguration_CommitCancelLoad(CdlPackage package_arg)
526
        : CdlTransactionCommitCancelOp()
527
    {
528
        CYG_ASSERT_CLASSC(package_arg);
529
        package = package_arg;
530
    }
531
    ~CdlConfiguration_CommitCancelLoad()
532
    {
533
        package = 0;
534
    }
535
    void commit(CdlTransaction transaction)
536
    {
537
        CYG_ASSERT_CLASSC(package);
538
        CdlLoadableBody::transaction_commit_load(transaction, package);
539
        package = 0;
540
    }
541
    void cancel(CdlTransaction transaction)
542
    {
543
        CYG_ASSERT_CLASSC(package);
544
        CdlLoadableBody::transaction_cancel_load(transaction, package);
545
        package = 0;
546
    }
547
 
548
  protected:
549
 
550
  private:
551
    CdlConfiguration_CommitCancelLoad()
552
    {
553
    }
554
    CdlPackage  package;
555
};
556
 
557
class CdlConfiguration_CommitCancelUnload :
558
    public CdlTransactionCommitCancelOp
559
{
560
    friend class CdlTest;
561
 
562
  public:
563
    CdlConfiguration_CommitCancelUnload(CdlPackage package_arg)
564
        : CdlTransactionCommitCancelOp()
565
    {
566
        CYG_ASSERT_CLASSC(package_arg);
567
        package = package_arg;
568
    }
569
    ~CdlConfiguration_CommitCancelUnload()
570
    {
571
        package = 0;
572
    }
573
    void commit(CdlTransaction transaction)
574
    {
575
        CYG_PRECONDITION_CLASSC(package);
576
        CdlLoadableBody::transaction_commit_unload(transaction, package);
577
        package = 0;
578
    }
579
    void cancel(CdlTransaction transaction)
580
    {
581
        CYG_PRECONDITION_CLASSC(package);
582
        CdlLoadableBody::transaction_cancel_unload(transaction, package);
583
        package = 0;
584
    }
585
 
586
  protected:
587
 
588
  private:
589
    CdlConfiguration_CommitCancelUnload()
590
    {
591
    }
592
    CdlPackage package;
593
};
594
 
595
// These utility classes can be used to control the hardware and
596
// template names. If the transaction is cancelled the previous
597
// name gets re-installed
598
class CdlConfiguration_CommitCancelHardwareName :
599
    public CdlTransactionCommitCancelOp
600
{
601
    friend class CdlTest;
602
 
603
  public:
604
    CdlConfiguration_CommitCancelHardwareName(std::string old_name_arg)
605
        : CdlTransactionCommitCancelOp()
606
    {
607
        old_name = old_name_arg;
608
    }
609
    ~CdlConfiguration_CommitCancelHardwareName()
610
    {
611
        old_name = "";
612
    }
613
    void commit(CdlTransaction transaction)
614
    {
615
        // The new name is already installed, nothing more needs to happen.
616
        CYG_UNUSED_PARAM(CdlTransaction, transaction);
617
    }
618
    void cancel(CdlTransaction transaction)
619
    {
620
        // Restore the old name
621
        CdlToplevel toplevel = transaction->get_toplevel();
622
        CYG_ASSERTC(0 != toplevel);
623
        CdlConfiguration configuration = dynamic_cast<CdlConfiguration>(toplevel);
624
        CYG_ASSERT_CLASSC(configuration);
625
 
626
        configuration->set_hardware_name(old_name);
627
        CYG_UNUSED_PARAM(CdlTransaction, transaction);
628
    }
629
 
630
  protected:
631
 
632
  private:
633
    CdlConfiguration_CommitCancelHardwareName()
634
    {
635
    }
636
    std::string old_name;
637
};
638
 
639
class CdlConfiguration_CommitCancelTemplateName :
640
    public CdlTransactionCommitCancelOp
641
{
642
    friend class CdlTest;
643
 
644
  public:
645
    CdlConfiguration_CommitCancelTemplateName(std::string old_name_arg)
646
        : CdlTransactionCommitCancelOp()
647
    {
648
        old_name = old_name_arg;
649
    }
650
    ~CdlConfiguration_CommitCancelTemplateName()
651
    {
652
        old_name = "";
653
    }
654
    void commit(CdlTransaction transaction)
655
    {
656
        // The new name is already installed, nothing more needs to happen.
657
        CYG_UNUSED_PARAM(CdlTransaction, transaction);
658
    }
659
    void cancel(CdlTransaction transaction)
660
    {
661
        // Restore the old name
662
        CdlToplevel toplevel = transaction->get_toplevel();
663
        CYG_ASSERTC(0 != toplevel);
664
        CdlConfiguration configuration = dynamic_cast<CdlConfiguration>(toplevel);
665
        CYG_ASSERT_CLASSC(configuration);
666
 
667
        configuration->set_template_name(old_name);
668
        CYG_UNUSED_PARAM(CdlTransaction, transaction);
669
    }
670
 
671
  protected:
672
 
673
  private:
674
    CdlConfiguration_CommitCancelTemplateName()
675
    {
676
    }
677
    std::string old_name;
678
};
679
 
680
//}}}
681
//{{{  CdlConfiguration::load_package()                 
682
 
683
// ----------------------------------------------------------------------------
684
// Loading a package into the current level. This involves the following
685
// stages.
686
//
687
//  1) check that the specified package name and version is valid, by
688
//     comparing it with the database. When the database was created there
689
//     will have been checks to make sure that the initial CDL script was
690
//     present, but more checks can be done here.
691
//
692
//  2) before allocating any resources, check that there is no name conflict
693
//     for the package itself.
694
//
695
//  3) create the package object, and add it to the toplevel of the current
696
//     configuration. It may get reparented later on. Part of the creation
697
//     process is to allocate a new slave interpreter, which can be updated
698
//     with various bits of information.
699
//
700
//  4) evaluate the toplevel script. Subsidiary component scripts will
701
//     get evaluated as a side effect. The various nodes will be added
702
//     to the hierarchy as they are created, but no property binding
703
//     happens yet.
704
//
705
//     Any failure up to this point should result in the entire package
706
//     being removed from the hierarchy and then destroyed, thus leaving
707
//     the configuration in its original state.
708
//
709
//  5) now property binding needs to take place. This can have lots
710
//     of side effects, e.g. default values may get calculated, the
711
//     hierarchy may change because of parent properties, etc.
712
//     The work is done inside CdlLoadable::bind() which will undo
713
//     everything on failure - although bad_alloc is the only
714
//     failure that should occur.
715
//
716
//  6) load operations can get cancelled, so a suitable commit/cancel
717
//     operation needs to allocated and added to the transaction.
718
//
719
//  7) if limbo is enabled, previous values should be extracted from
720
//     limbo if at all possible. In addition the package's value can
721
//     be set to its version.
722
 
723
void
724
CdlConfigurationBody::load_package(CdlTransaction transaction, std::string name, std::string version,
725
                                   CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
726
{
727
    CYG_REPORT_FUNCNAME("CdlConfiguration::load_package");
728
    CYG_REPORT_FUNCARG1XV(this);
729
    CYG_PRECONDITION_THISC();
730
    CYG_PRECONDITION_CLASSC(transaction);
731
    CYG_PRECONDITIONC("" != name);
732
 
733
    // Locate the database entry. Also check the version (filling it in if necessary).
734
    // Get hold of the package directory and the initial script.
735
    if (!database->is_known_package(name)) {
736
        throw CdlInputOutputException("Unknown package " + name);
737
    }
738
    const std::vector<std::string>& versions = database->get_package_versions(name);
739
    if ("" == version) {
740
        version = *(versions.begin());
741
    } else {
742
        if (std::find(versions.begin(), versions.end(), version) == versions.end()) {
743
            throw CdlInputOutputException("Package " + name + " does not have an installed version `" + version + "'.");
744
        }
745
    }
746
    std::string repository      = database->get_package_repository(name, version);
747
    std::string directory       = database->get_package_directory(name);
748
    std::string script          = database->get_package_script(name);
749
    CYG_ASSERTC(("" != directory) && ("" != script));
750
 
751
    // Check that the directory actually exists. For this the configuration's own
752
    // interpreter can be used.
753
    CdlInterpreter interp = get_interpreter();
754
    CYG_ASSERT_CLASSC(interp);
755
 
756
    std::string tcl_cmd = "regsub -all -- {\\\\} [file join " + directory + " " + version + "] / result; return $result";
757
    std::string tcl_result;
758
    if (TCL_OK != interp->eval(tcl_cmd, tcl_result)) {
759
        throw CdlInputOutputException("Cannot load package `" + name + "', internal error constructing pathname.");
760
    }
761
    directory = tcl_result;
762
 
763
    tcl_cmd   = "file isdirectory [file join \"" + repository + "\" " + directory + "]";
764
    if ((TCL_OK != interp->eval(tcl_cmd, tcl_result)) || ("1" != tcl_result)) {
765
        throw CdlInputOutputException("Cannot load package `" + name + "', there is no directory `" + directory + "'.");
766
    }
767
 
768
    // Make sure that there is no name conflict. No resources have been allocated
769
    // yet, so this is a good time.
770
    CdlNode node = lookup(name);
771
    if (0 != node) {
772
        if (0 != dynamic_cast<CdlPackage>(node)) {
773
            throw CdlInputOutputException("Package `" + name + "' is already loaded.");
774
        } else {
775
 
776
            std::string msg = "Name clash for package `" + name + "',there is a `" +
777
                node->get_class_name() + " " + name + "' already loaded";
778
            CdlLoadable owner_pkg = node->get_owner();
779
            if (0 != owner_pkg) {
780
                msg += " in package " + owner_pkg->get_name();
781
            }
782
            throw CdlInputOutputException(msg);
783
        }
784
    }
785
 
786
    // Now create the package object itself.
787
    CdlPackage package  = 0;
788
    bool       bound    = false;
789
    CdlConfiguration_CommitCancelLoad* load_op  = 0;
790
 
791
    try {
792
        package = new CdlPackageBody(name, this, repository, directory);
793
 
794
        // The package should be added to the hierarchy immediately.
795
        // All nodes will get added to the hierarchy as they are
796
        // created, an operation that has to be undone during
797
        // failure. 
798
        this->add_node(package, this, package);
799
 
800
        // Load the package data. The various nodes will all end up
801
        // in a hierarchy below the package, but without any checks
802
        // for name conflicts etc and ignoring any re-parenting.
803
        CdlInterpreter interp = package->get_interpreter();
804
        CYG_ASSERT_CLASSC(interp);
805
 
806
        interp->add_command("unknown",  &CdlParse::unknown_command);
807
        CdlInterpreterBody::DiagSupport diag_support(interp, error_fn, warn_fn);
808
 
809
        // Next figure out the script name, and make sure that it exists.
810
        std::string actual_script = package->find_absolute_file(script, "cdl");
811
        if ("" == actual_script) {
812
            throw CdlInputOutputException("Package " + name + ", unable to find initial script " + script);
813
        }
814
        tcl_cmd = "file isfile \"" + actual_script + "\"";
815
        if ((TCL_OK != interp->eval(tcl_cmd, tcl_result)) || ("1" != tcl_result)) {
816
            throw CdlInputOutputException("Package " + name + ", " + actual_script + " is not a CDL script");
817
        }
818
 
819
        // The script is valid. Set up the interpreter appropriately.
820
        CdlParse::clear_error_count(interp);
821
        static CdlInterpreterCommandEntry commands[] =
822
        {
823
            CdlInterpreterCommandEntry("cdl_package",    &CdlPackageBody::parse_package     ),
824
            CdlInterpreterCommandEntry("cdl_component",  &CdlComponentBody::parse_component ),
825
            CdlInterpreterCommandEntry("cdl_option",     &CdlOptionBody::parse_option       ),
826
            CdlInterpreterCommandEntry("cdl_interface",  &CdlInterfaceBody::parse_interface ),
827
            CdlInterpreterCommandEntry("cdl_dialog",     &CdlDialogBody::parse_dialog       ),
828
            CdlInterpreterCommandEntry("cdl_wizard",     &CdlWizardBody::parse_wizard       ),
829
            CdlInterpreterCommandEntry("",               0                                  )
830
        };
831
        CdlInterpreterBody::CommandSupport   interp_cmds(interp, commands);
832
        CdlInterpreterBody::ContainerSupport interp_container(interp, package);
833
        CdlInterpreterBody::ContextSupport   interp_context(interp, actual_script);
834
 
835
        // The interpreter is now ready.
836
        (void) interp->eval_file(actual_script);
837
 
838
        // Clean out the commands etc. This interpreter may get used again
839
        // in future, and it should not be possible to define new options
840
        // etc. in that invocation.
841
        interp->remove_command("unknown");
842
 
843
        // All the data has been read in without generating an
844
        // exception. However there may have been errors reported via
845
        // the parse_error_fn, and any errors at all should result
846
        // in an exception.
847
        int error_count = CdlParse::get_error_count(interp);
848
        if (error_count > 0) {
849
            std::string tmp;
850
            Cdl::integer_to_string(error_count, tmp);
851
            throw CdlParseException("Package " + name + ", " + tmp + " error" +
852
                                    ((error_count > 1) ? "s" : "") +
853
                                    " occurred while reading in the CDL data.");
854
        }
855
 
856
        // All the data has been read in, implying that there are no
857
        // fatal problems with the data. Now try to bind all
858
        // references to and from this loadable.
859
        package->bind(transaction);
860
        bound = true;
861
 
862
        // Finally, create a suitable transaction commit/cancel object
863
        // and add it to the transaction.
864
        load_op = new CdlConfiguration_CommitCancelLoad(package);
865
        transaction->add_commit_cancel_op(load_op);
866
 
867
    } catch (...) {
868
 
869
        // Something went wrong during the create or load. It is necessary
870
        // to delete the package. Undo all the operations above, in
871
        // reverse order. The add_commit_cancel_op() was the last step,
872
        // so need not be undone here.
873
        if (0 != load_op) {
874
            delete load_op;
875
        }
876
 
877
        if (0 != package) {
878
            // Note: no attempt is made to recover from errors here
879
            if (bound) {
880
                package->unbind(transaction);
881
            }
882
            this->remove_loadable_from_toplevel(package);
883
            delete package;
884
        }
885
        throw;
886
    }
887
 
888
    // FIXME: implement limbo support
889
 
890
    // We also have a sensible value for the package as a whole.
891
    // Use this value for both default and user - after all the
892
    // user has selected the package.
893
    package->enable_and_set_value(transaction, version, CdlValueSource_Default);
894
    package->enable_and_set_value(transaction, version, CdlValueSource_User);
895
 
896
    CYG_REPORT_RETURN();
897
}
898
 
899
//}}}
900
//{{{  CdlConfiguration::unload_package()               
901
 
902
// ----------------------------------------------------------------------------
903
// Unloading a package is very simple. If requested, save all current
904
// values to limbo: there is no point in saving default values, these
905
// will get recalculated from the default_value property anyway;
906
// inferred values should be saved, there is no guarantee that the exact
907
// same value will be calculated again, and if the inferred value is no
908
// longer correct then the inference engine can freely update it.
909
//
910
// Next, unbind the package and remove it from the hierarchy. These
911
// operations are reversible if the transaction gets cancelled.
912
// A suitable transaction commit/cancel object is created and
913
// added to the transaction.
914
void
915
CdlConfigurationBody::unload_package(CdlTransaction transaction, CdlPackage package, bool limbo)
916
{
917
    CYG_REPORT_FUNCNAME("CdlConfiguration::unload_package");
918
    CYG_REPORT_FUNCARG4XV(this, transaction, package, limbo);
919
    CYG_INVARIANT_THISC(CdlConfigurationBody);
920
    CYG_INVARIANT_CLASSC(CdlTransactionBody, transaction);
921
    CYG_PRECONDITION_CLASSC(package);
922
 
923
    if (limbo) {
924
        const std::vector<CdlNode>& pkg_contents = package->get_owned();
925
        std::vector<CdlNode>::const_iterator node_i;
926
 
927
        for (node_i = pkg_contents.begin(); node_i != pkg_contents.end(); node_i++) {
928
            CdlValuable valuable = dynamic_cast<CdlValuable>(*node_i);
929
            if (0 != valuable) {
930
                if (valuable->has_source(CdlValueSource_Inferred) ||
931
                    valuable->has_source(CdlValueSource_Wizard)   ||
932
                    valuable->has_source(CdlValueSource_User)) {
933
 
934
                    set_limbo_value(valuable);
935
                }
936
            }
937
        }
938
    }
939
 
940
    bool unbound = false;
941
    bool removed = false;
942
    CdlConfiguration_CommitCancelUnload* unload_op = 0;
943
    try {
944
 
945
        package->unbind(transaction);
946
        unbound = true;
947
        this->remove_loadable_from_toplevel(package);
948
        removed = true;
949
        unload_op = new CdlConfiguration_CommitCancelUnload(package);
950
        transaction->add_commit_cancel_op(unload_op);
951
 
952
    } catch(...) {
953
        if (0 != unload_op) {
954
            delete unload_op;
955
        }
956
        if (removed) {
957
            this->add_loadable_to_toplevel(package);
958
        }
959
        if (unbound) {
960
            package->bind(transaction);
961
        }
962
        throw;
963
    }
964
 
965
    CYG_REPORT_RETURN();
966
}
967
 
968
//}}}
969
//{{{  CdlConfiguration::change_package_version()       
970
 
971
// ----------------------------------------------------------------------------
972
// Changing a package version is just a case of unloading the old version
973
// and then loading in the new version. Because this all happens in the
974
// context of a transaction it is possible to undo the unload on
975
// failure, and the whole transaction can be cancelled at a higher level.
976
 
977
void
978
CdlConfigurationBody::change_package_version(CdlTransaction transaction, CdlPackage package, std::string new_version,
979
                                             CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
980
{
981
    CYG_REPORT_FUNCNAME("CdlConfiguration::change_package_version");
982
    CYG_REPORT_FUNCARG3XV(this, transaction, package);
983
    CYG_PRECONDITION_THISC();
984
    CYG_INVARIANT_CLASSC(CdlTransactionBody, transaction);
985
    CYG_PRECONDITION_CLASSC(package);
986
    // "" is valid for the version, it indicates the default
987
 
988
    // Since the package is already loaded it must be in the database,
989
    // but it is possible that the desired version does not exist.
990
    std::string name = package->get_name();
991
    const std::vector<std::string>& pkg_versions = database->get_package_versions(name);
992
    if ("" == new_version) {
993
        new_version = *(pkg_versions.begin());
994
    } else if (std::find(pkg_versions.begin(), pkg_versions.end(), new_version) == pkg_versions.end()) {
995
        throw CdlInputOutputException("Version " + new_version + " of package " + name + " is not installed.");
996
    }
997
 
998
    bool unloaded = false;
999
    try {
1000
        this->unload_package(transaction, package, limbo);
1001
        unloaded = true;
1002
        this->load_package(transaction, name, new_version, error_fn, warn_fn, limbo);
1003
    } catch(...) {
1004
        if (unloaded) {
1005
            // There should be a commit/cancel op for the unload package step.
1006
            // This can be undone.
1007
            CdlTransactionCommitCancelOp* unload_op = transaction->get_last_commit_cancel_op();
1008
            CYG_ASSERTC(0 != unload_op);
1009
            CYG_ASSERTC(0 != dynamic_cast<CdlConfiguration_CommitCancelUnload*>(unload_op));
1010
            transaction->cancel_last_commit_cancel_op();
1011
            CYG_UNUSED_PARAM(CdlTransactionCommitCancelOp*, unload_op);
1012
        }
1013
        throw;
1014
    }
1015
 
1016
    CYG_REPORT_RETURN();
1017
}
1018
 
1019
//}}}
1020
//{{{  CdlConfiguration::set_hardware() etc.            
1021
 
1022
// ----------------------------------------------------------------------------
1023
// Setting the hardware involves unloading the old hardware, if any, and
1024
// then loading in the new one. Obviously this should only happen if
1025
// the new hardware name is valid. It would be possible to optimise for
1026
// the case where the old and new hardware are the same, subject
1027
// to dynamic database reload support.
1028
 
1029
void
1030
CdlConfigurationBody::set_hardware(CdlTransaction transaction, std::string target_name,
1031
                                   CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
1032
{
1033
    CYG_REPORT_FUNCNAME("CdlConfiguration::set_hardware");
1034
    CYG_REPORT_FUNCARG2XV(this, transaction);
1035
    CYG_PRECONDITION_THISC();
1036
    CYG_PRECONDITION_CLASSC(transaction);
1037
 
1038
    // Minimal consistency check before attempting anything complicated.
1039
    if (!database->is_known_target(target_name)) {
1040
        throw CdlInputOutputException("Unknown target " + target_name);
1041
    }
1042
 
1043
    CdlInterpreter interp = this->get_interpreter();
1044
    CdlInterpreterBody::DiagSupport    diag_support(interp, error_fn, warn_fn);
1045
    CdlInterpreterBody::ContextSupport context_support(interp, "Hardware selection");
1046
 
1047
    CdlConfiguration_CommitCancelHardwareName* rename_op = new CdlConfiguration_CommitCancelHardwareName(current_hardware);
1048
    try {
1049
        transaction->add_commit_cancel_op(rename_op);
1050
        const std::vector<CdlLoadable>& loadables = this->get_loadables();
1051
        int i;
1052
        for (i = (int) loadables.size() - 1; i >= 0; i--) {
1053
            CdlPackage package = dynamic_cast<CdlPackage>(loadables[i]);
1054
            if ((0 != package) && package->belongs_to_hardware()) {
1055
                this->unload_package(transaction, package, limbo);
1056
            }
1057
        }
1058
        current_hardware = "";
1059
 
1060
        if ("" != target_name) {
1061
 
1062
            const std::vector<std::string>& packages = database->get_target_packages(target_name);
1063
            std::vector<std::string>::const_iterator    name_i;
1064
            for (name_i = packages.begin(); name_i != packages.end(); name_i++) {
1065
                // Target specifications may refer to packages that are not
1066
                // installed. This is useful in e.g. an anoncvs environment.
1067
                if (database->is_known_package(*name_i)) {
1068
                    // It is possible for a hardware package to have been
1069
                    // loaded separately, in which case there is no point in
1070
                    // loading it again.
1071
                    if (0 == this->lookup(*name_i)) {
1072
                        this->load_package(transaction, *name_i, "",
1073
                                           error_fn, warn_fn, limbo);
1074
                        CdlPackage package = dynamic_cast<CdlPackage>(this->lookup(*name_i));
1075
                        CYG_LOOP_INVARIANT_CLASSC(package);
1076
                        package->loaded_for_hardware = true;
1077
                    }
1078
                } else {
1079
                    CdlParse::report_warning(interp, "",
1080
                                             std::string("The target specification lists a package `") + *name_i +
1081
                                             "' which is not present in the component repository.");
1082
                }
1083
            }
1084
        }
1085
        current_hardware = target_name;
1086
 
1087
    } catch(...) {
1088
        // Cancel all operations up to and including the rename_op
1089
        CdlTransactionCommitCancelOp* cancel_op = 0;
1090
        do {
1091
            cancel_op = transaction->get_last_commit_cancel_op();
1092
            CYG_LOOP_INVARIANTC(0 != cancel_op);
1093
            transaction->cancel_last_commit_cancel_op();
1094
        } while(cancel_op != rename_op);
1095
        throw;
1096
    }
1097
 
1098
    // There may have been enables/disables and value data for that target
1099
    // FIXME: any problems get ignored quietly. There should at least
1100
    // be some warnings.
1101
    if ("" != target_name) {
1102
        const std::vector<std::string>& enables  = database->get_target_enables(target_name);
1103
        const std::vector<std::string>& disables = database->get_target_disables(target_name);
1104
        const std::vector<std::pair<std::string, std::string> >& set_values = database->get_target_set_values(target_name);
1105
 
1106
        if ((0 != enables.size()) || (0 != disables.size()) || (0 != set_values.size())) {
1107
            std::vector<std::string>::const_iterator opt_i;
1108
            CdlNode     node;
1109
            CdlValuable valuable;
1110
            CdlValueFlavor flavor;
1111
 
1112
            for (opt_i = enables.begin(); opt_i != enables.end(); opt_i++) {
1113
                valuable = 0;
1114
                node     = this->lookup(*opt_i);
1115
                if (0 != node) {
1116
                    valuable = dynamic_cast<CdlValuable>(node);
1117
                    if (0 != valuable) {
1118
                    }
1119
                }
1120
                if (0 != valuable) {
1121
                    flavor = valuable->get_flavor();
1122
                    if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
1123
                        valuable->enable(transaction, CdlValueSource_User);
1124
                    } else {
1125
                        CdlParse::report_warning(interp, std::string("target `") + target_name + "'",
1126
                                                 std::string("The option `") + *opt_i +
1127
                                                 "' is supposed to be enabled for this target.\n" +
1128
                                                 "However the option does not have a bool or booldata flavors.");
1129
                    }
1130
                } else {
1131
                    CdlParse::report_warning(interp, std::string("target `") + target_name + "'",
1132
                                             std::string("The option `") + *opt_i +
1133
                                             "' is supposed to be enabled for this target.\n" +
1134
                                             "However this option is not in the current configuration.");
1135
                }
1136
            }
1137
            for (opt_i = disables.begin(); opt_i != disables.end(); opt_i++) {
1138
                valuable = 0;
1139
                node = this->lookup(*opt_i);
1140
                if (0 != node) {
1141
                    valuable = dynamic_cast<CdlValuable>(node);
1142
                }
1143
                if (0 != valuable) {
1144
                    flavor = valuable->get_flavor();
1145
                    if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
1146
                        valuable->disable(transaction, CdlValueSource_User);
1147
                    } else {
1148
                        CdlParse::report_warning(interp, std::string("target `") + target_name + "'",
1149
                                                 std::string("The option `") + *opt_i +
1150
                                                 "' is supposed to be disabled for this target.\n" +
1151
                                                 "However the option does not have a bool or booldata flavors.");
1152
                    }
1153
                } else {
1154
                    CdlParse::report_warning(interp, std::string("target `") + target_name + "'",
1155
                                             std::string("The option `") + *opt_i +
1156
                                             "' is supposed to be disabled for this target.\n" +
1157
                                             "However this option is not in the current configuration.");
1158
                }
1159
            }
1160
            std::vector<std::pair<std::string,std::string> >::const_iterator value_i;
1161
            for (value_i = set_values.begin(); value_i != set_values.end(); value_i++) {
1162
                valuable = 0;
1163
                node = this->lookup(value_i->first);
1164
                if (0 != node) {
1165
                    valuable = dynamic_cast<CdlValuable>(node);
1166
                }
1167
                if (0 != valuable) {
1168
                    flavor = valuable->get_flavor();
1169
                    if ((CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor)) {
1170
                        valuable->set_value(transaction, value_i->second, CdlValueSource_User);
1171
                    } else {
1172
                        CdlParse::report_warning(interp, std::string("target `") + target_name + "'",
1173
                                                 std::string("The option `") + *opt_i +
1174
                                                 "' is supposed to be given the value `" + value_i->second +
1175
                                                 "' for this target.\n" +
1176
                                                 "However the option does not have a data or booldata flavor.");
1177
                    }
1178
                } else {
1179
                    CdlParse::report_warning(interp, std::string("target `") + target_name + "'",
1180
                                             std::string("The option `") + *opt_i +
1181
                                             "' is supposed to be given the value `" + value_i->second +
1182
                                             "' for this target.\n" +
1183
                                             "However this option is not in the current configuration.");
1184
                }
1185
            }
1186
        }
1187
    }
1188
 
1189
    CYG_REPORT_RETURN();
1190
}
1191
 
1192
void
1193
CdlConfigurationBody::unload_hardware(CdlTransaction transaction, bool limbo)
1194
{
1195
    CYG_REPORT_FUNCNAME("CdlConfiguration::unload_hardware");
1196
    CYG_REPORT_FUNCARG3XV(this, transaction, limbo);
1197
    CYG_PRECONDITION_THISC();
1198
 
1199
    CdlConfiguration_CommitCancelHardwareName* rename_op = new CdlConfiguration_CommitCancelHardwareName(current_hardware);
1200
    try {
1201
        transaction->add_commit_cancel_op(rename_op);
1202
    } catch(...) {
1203
        delete rename_op;
1204
        throw;
1205
    }
1206
    current_hardware = "";
1207
 
1208
    try {
1209
        const std::vector<CdlLoadable>& loadables = this->get_loadables();
1210
        for (int i = (int) loadables.size() - 1; i >= 0; i--) {
1211
            CdlPackage package = dynamic_cast<CdlPackage>(loadables[i]);
1212
            if ((0 != package) && package->belongs_to_hardware()) {
1213
                this->unload_package(transaction, package, limbo);
1214
            }
1215
        }
1216
    } catch(...) {
1217
        CdlTransactionCommitCancelOp* cancel_op = 0;
1218
        do {
1219
            cancel_op = transaction->get_last_commit_cancel_op();
1220
            CYG_LOOP_INVARIANTC(0 != cancel_op);
1221
            transaction->cancel_last_commit_cancel_op();
1222
        } while(cancel_op != rename_op);
1223
        throw;
1224
    }
1225
 
1226
    CYG_REPORT_RETURN();
1227
}
1228
 
1229
//}}}
1230
//{{{  CdlConfiguration::set_template() etc             
1231
 
1232
// ----------------------------------------------------------------------------
1233
void
1234
CdlConfigurationBody::set_template_file(CdlTransaction transaction, std::string filename,
1235
                                        CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn, bool limbo)
1236
{
1237
    CYG_REPORT_FUNCNAME("CdlConfiguration::set_template_file");
1238
    CYG_REPORT_FUNCARG3XV(this, transaction, limbo);
1239
    CYG_PRECONDITION_THISC();
1240
 
1241
    int i;
1242
    CdlConfiguration_CommitCancelTemplateName* rename_op = new CdlConfiguration_CommitCancelTemplateName(current_template);
1243
 
1244
    // The hard work is done by add(), which loads in a partial savefile.
1245
    // This can have undesirable side effects: changing the name,
1246
    // description, or hardware settings. It must be possible to undo
1247
    // these.
1248
    std::string saved_name        = this->get_name();
1249
    std::string saved_description = this->get_description();
1250
    std::string saved_hardware    = this->get_hardware();
1251
 
1252
    // New packages will end up at the end of the loadables vector.
1253
    // Each new package needs to be registered as a template one.
1254
    // NOTE: this may break if we start doing more interesting things
1255
    // with savefiles.
1256
 
1257
    try {
1258
        transaction->add_commit_cancel_op(rename_op);
1259
        const std::vector<CdlLoadable>& loadables = this->get_loadables();
1260
        unsigned int load_i;
1261
        for (i = (int) loadables.size() - 1; i >= 0; i--) {
1262
            CdlPackage package = dynamic_cast<CdlPackage>(loadables[i]);
1263
            if ((0 != package) && package->belongs_to_template()) {
1264
                this->unload_package(transaction, package, limbo);
1265
            }
1266
        }
1267
        current_template = "";
1268
        load_i = loadables.size();
1269
 
1270
        this->add(transaction, filename, error_fn, warn_fn);
1271
        this->current_template = filename;
1272
        this->set_name(saved_name);
1273
        this->description = saved_description;
1274
        this->current_hardware = saved_hardware;
1275
 
1276
        for ( ; load_i < loadables.size(); load_i++) {
1277
            CdlPackage pkg = dynamic_cast<CdlPackage>(loadables[load_i]);
1278
            CYG_ASSERT_CLASSC(pkg);
1279
            pkg->loaded_for_template = true;
1280
        }
1281
 
1282
    } catch(...) {
1283
 
1284
        this->set_name(saved_name);
1285
        this->description = saved_description;
1286
        this->current_hardware = saved_hardware;
1287
 
1288
        // Cancel all operations up to and including the rename_op
1289
        CdlTransactionCommitCancelOp* cancel_op = 0;
1290
        do {
1291
            cancel_op = transaction->get_last_commit_cancel_op();
1292
            CYG_LOOP_INVARIANTC(0 != cancel_op);
1293
            transaction->cancel_last_commit_cancel_op();
1294
        } while(cancel_op != rename_op);
1295
        throw;
1296
    }
1297
 
1298
 
1299
    CYG_REPORT_RETURN();
1300
}
1301
 
1302
void
1303
CdlConfigurationBody::unload_template(CdlTransaction transaction, bool limbo)
1304
{
1305
    CYG_REPORT_FUNCNAME("CdlConfiguration::unload_template");
1306
    CYG_REPORT_FUNCARG2XV(this, transaction);
1307
    CYG_PRECONDITION_THISC();
1308
    CYG_PRECONDITION_CLASSC(transaction);
1309
 
1310
    CdlConfiguration_CommitCancelTemplateName* rename_op = new CdlConfiguration_CommitCancelTemplateName(current_template);
1311
    try {
1312
        transaction->add_commit_cancel_op(rename_op);
1313
    } catch(...) {
1314
        delete rename_op;
1315
        throw;
1316
    }
1317
    current_template = "";
1318
 
1319
    try {
1320
        const std::vector<CdlLoadable>& loadables = this->get_loadables();
1321
        for (int i = (int) loadables.size() - 1; i >= 0; i--) {
1322
            CdlPackage package = dynamic_cast<CdlPackage>(loadables[i]);
1323
            if ((0 != package) && package->belongs_to_template()) {
1324
                this->unload_package(transaction, package, limbo);
1325
            }
1326
        }
1327
    } catch(...) {
1328
        CdlTransactionCommitCancelOp* cancel_op = 0;
1329
        do {
1330
            cancel_op = transaction->get_last_commit_cancel_op();
1331
            CYG_LOOP_INVARIANTC(0 != cancel_op);
1332
            transaction->cancel_last_commit_cancel_op();
1333
        } while(cancel_op != rename_op);
1334
        throw;
1335
    }
1336
 
1337
    CYG_REPORT_RETURN();
1338
}
1339
 
1340
//}}}
1341
//{{{  Persistence support                              
1342
 
1343
//{{{  initialize_savefile_support()                    
1344
 
1345
// ----------------------------------------------------------------------------
1346
// Initialization. The purpose of this code is to determine all the
1347
// commands that can end up in a particular savefile. This includes
1348
// the cdl_configuration command, commands relevant to packages,
1349
// options, and components, the generic library commands, and
1350
// application-specific commands.
1351
//
1352
// This is a virtual function, it may get invoked indirectly from
1353
// e.g. CdlToplevel::add_savefile_command().
1354
 
1355
void
1356
CdlConfigurationBody::initialize_savefile_support()
1357
{
1358
    CYG_REPORT_FUNCNAME("CdlConfiguration::initialize_savefile_support");
1359
    CYG_REPORT_FUNCARG1XV(this);
1360
    CYG_PRECONDITION_THISC();
1361
 
1362
    // Start with the generic stuff such as cdl_savefile_version and
1363
    // cdl_command.
1364
    this->CdlToplevelBody::initialize_savefile_support();
1365
 
1366
    // Now add in the cdl_configuration command and its subcommands.
1367
    this->add_savefile_command("cdl_configuration", 0, &savefile_configuration_command);
1368
    this->add_savefile_subcommand("cdl_configuration", "description", 0, &savefile_description_command);
1369
    this->add_savefile_subcommand("cdl_configuration", "hardware",    0, &savefile_hardware_command);
1370
    this->add_savefile_subcommand("cdl_configuration", "template",    0, &savefile_template_command);
1371
    this->add_savefile_subcommand("cdl_configuration", "package",     0, &savefile_package_command);
1372
 
1373
    CdlPackageBody::initialize_savefile_support(this);
1374
    CdlComponentBody::initialize_savefile_support(this);
1375
    CdlOptionBody::initialize_savefile_support(this);
1376
    CdlInterfaceBody::initialize_savefile_support(this);
1377
}
1378
 
1379
//}}}
1380
//{{{  CdlConfiguration::save() - internal              
1381
 
1382
// ----------------------------------------------------------------------------
1383
// The exported interface is CdlConfiguration::save(). This takes a single
1384
// argument, a filename. It opens the file, and then invokes various
1385
// functions that output the relevants bits of the file.
1386
//
1387
// This member function is responsible for outputting a cdl_configuration
1388
// command.
1389
 
1390
void
1391
CdlConfigurationBody::save(CdlInterpreter interp, Tcl_Channel chan, int indentation, bool minimal)
1392
{
1393
    CYG_REPORT_FUNCNAME("CdlConfiguration::save");
1394
    CYG_REPORT_FUNCARG5XV(this, interp, chan, indentation, minimal);
1395
    CYG_PRECONDITION_THISC();
1396
    CYG_PRECONDITION_CLASSC(interp);
1397
    CYG_PRECONDITIONC(0 == indentation);
1398
 
1399
    std::string text = "";
1400
    if (!minimal) {
1401
      text =
1402
"# This section defines the toplevel configuration object. The only\n\
1403
# values that can be changed are the name of the configuration and\n\
1404
# the description field. It is not possible to modify the target,\n\
1405
# the template or the set of packages simply by editing the lines\n\
1406
# below because these changes have wide-ranging effects. Instead\n\
1407
# the appropriate tools should be used to make such modifications.\n\
1408
\n";
1409
    }
1410
 
1411
    text += "cdl_configuration " + CdlInterpreterBody::quote(this->get_name()) + " {\n";
1412
 
1413
    std::string config_data = this->get_description();
1414
    if (!minimal || ("" != text)) {
1415
        text += "    description " + CdlInterpreterBody::quote(config_data) + " ;\n";
1416
    }
1417
 
1418
    // Repeat the warning.
1419
    if (!minimal) {
1420
        text += "\n    # These fields should not be modified.\n";
1421
    }
1422
    config_data = this->get_hardware();
1423
    if ("" != config_data) {
1424
        text += "    hardware    " + CdlInterpreterBody::quote(config_data) + " ;\n";
1425
    }
1426
    config_data = this->get_template();
1427
    if ("" != config_data) {
1428
        text += "    template    " + CdlInterpreterBody::quote(config_data) + " ;\n";
1429
    }
1430
    std::vector<CdlLoadable>::const_iterator load_i;
1431
    const std::vector<CdlLoadable>& packages = get_loadables();
1432
    for (load_i = packages.begin(); load_i != packages.end(); load_i++) {
1433
        CdlPackage pkg = dynamic_cast<CdlPackage>(*load_i);
1434
        CYG_ASSERT_CLASSC(pkg);
1435
        text += "    package ";
1436
        if (pkg->belongs_to_template()) {
1437
            text += "-template ";
1438
        }
1439
        if (pkg->belongs_to_hardware()) {
1440
            text += "-hardware ";
1441
        }
1442
        text += CdlInterpreterBody::quote(pkg->get_name()) + " " + CdlInterpreterBody::quote(pkg->get_value()) + " ;\n";
1443
    }
1444
 
1445
    interp->write_data(chan, text);
1446
 
1447
    // If the package was loaded from a file then there may be additional
1448
    // data associated with the configuration that is not currently
1449
    // recognised. This call preserves that data.
1450
    this->CdlNodeBody::save(interp, chan, indentation + 4, minimal);
1451
 
1452
    interp->write_data(chan, "};\n\n");
1453
 
1454
    CYG_REPORT_RETURN();
1455
}
1456
 
1457
//}}}
1458
//{{{  CdlConfiguration::save() - exported interface    
1459
 
1460
// ----------------------------------------------------------------------------
1461
// This is the exported interface for saving a configuration. The specified
1462
// file is opened via the appropriate Tcl library routines, and then the
1463
// relevant member functions are invoked to output the actual configuration
1464
// date.
1465
 
1466
void
1467
CdlConfigurationBody::save(std::string filename, bool minimal)
1468
{
1469
    CYG_REPORT_FUNCNAME("CdlConfiguration::save");
1470
    CYG_REPORT_FUNCARG2XV(this, minimal);
1471
    CYG_PRECONDITION_THISC();
1472
    CYG_PRECONDITIONC("" != filename);
1473
 
1474
    // Make sure that the savefile support is properly initialized.
1475
    // This happens during the first save or load operation, or when
1476
    // the application starts to register its own savefile extensions.
1477
    if (!CdlToplevelBody::savefile_support_initialized()) {
1478
        this->initialize_savefile_support();
1479
    }
1480
 
1481
    // A Tcl interpreter is needed for the call to OpenFileChannel(),
1482
    // and will also be passed to the individual save functions.
1483
    CdlInterpreter interp = this->get_interpreter();
1484
    CYG_ASSERT_CLASSC(interp);
1485
 
1486
    // Do not worry about forward vs. backward slashes, since the filename
1487
    // is not manipulated in any way. Instead just pass it to Tcl.
1488
    Tcl_Channel chan = Tcl_OpenFileChannel(interp->get_tcl_interpreter(), const_cast<char*>(filename.c_str()), "w", 0666);
1489
    if (0 == chan) {
1490
        throw CdlInputOutputException("Unable to open file " + filename + "\n" + interp->get_result());
1491
    }
1492
 
1493
    // The channel may end up being registered in various different
1494
    // interpreters, so Tcl_Close() is not the right way to close down
1495
    // the channel. Instead Tcl_RegisterChannel() should be used here
1496
    // to provide reference counting semantics.
1497
    Tcl_RegisterChannel(0, chan);
1498
 
1499
    // A try/catch body is needed here to make sure that the file gets
1500
    // properly cleaned up.
1501
    std::string tmp;
1502
    try {
1503
 
1504
        if (!minimal) {
1505
            interp->write_data(chan, "# eCos saved configuration\n\n");
1506
        }
1507
 
1508
        CdlToplevelBody::save_separator(interp, chan, "commands", minimal);
1509
        this->CdlToplevelBody::save_command_details(interp, chan, 0, minimal);
1510
        CdlToplevelBody::save_separator(interp, chan, "toplevel", minimal);
1511
        this->save(interp, chan, 0, minimal);
1512
        CdlToplevelBody::save_separator(interp, chan, "conflicts", minimal);
1513
        this->CdlToplevelBody::save_conflicts(interp, chan, 0, minimal);
1514
        CdlToplevelBody::save_separator(interp, chan, "contents", minimal);
1515
        this->CdlContainerBody::save(interp, chan, 0, minimal);
1516
        this->save_unsupported_commands(interp, chan, 0, minimal);
1517
 
1518
    } catch(...) {
1519
        Tcl_UnregisterChannel(0, chan);
1520
        // NOTE: deleting the file is necessary, it is a bad idea to
1521
        // end up with incomplete save files. It would be even better
1522
        // to write to a temporary file and only overwrite the old
1523
        // savefile on success.
1524
        //
1525
        // Tcl does not provide direct access to the file delete
1526
        // facility, so it is necessary to evaluate a script. This
1527
        // introduces quoting and security problems, since the
1528
        // filename might contain spaces, square brackets, braces...
1529
        // To avoid these problems a variable is used.
1530
        interp->set_variable("__cdlconfig_filename", filename);
1531
        interp->eval("file delete $__cdlconfig_filename", tmp);
1532
        interp->unset_variable("__cdlconfig_filename");
1533
 
1534
        throw;
1535
    }
1536
 
1537
    // This call will perform the appropriate close.
1538
    Tcl_UnregisterChannel(0, chan);
1539
}
1540
 
1541
//}}}
1542
//{{{  CdlConfiguration::load() and add()               
1543
 
1544
// ----------------------------------------------------------------------------
1545
// Most of the work is done in add(). load() simply creates a new configuration
1546
// and then invokes add().
1547
CdlConfiguration
1548
CdlConfigurationBody::load(std::string filename, CdlPackagesDatabase db, CdlInterpreter interp,
1549
                           CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn)
1550
{
1551
    CYG_REPORT_FUNCNAMETYPE("CdlConfiguration::load", "result %p");
1552
    CYG_REPORT_FUNCARG4XV(db, interp, error_fn, warn_fn);
1553
    CYG_PRECONDITION_CLASSC(db);
1554
    CYG_PRECONDITION_CLASSC(interp);
1555
 
1556
    CdlConfiguration result = CdlConfigurationBody::make("eCos", db, interp);
1557
    if (0 == result) {
1558
        CYG_REPORT_RETVAL(result);
1559
        return result;
1560
    }
1561
 
1562
    try {
1563
        result->add(filename, error_fn, warn_fn);
1564
        result->save_file = filename;
1565
    } catch(...) {
1566
        delete result;
1567
        throw;
1568
    }
1569
 
1570
    CYG_REPORT_RETVAL(result);
1571
    return result;
1572
}
1573
 
1574
// ----------------------------------------------------------------------------
1575
void
1576
CdlConfigurationBody::add(CdlTransaction transaction, std::string filename,
1577
                          CdlDiagnosticFnPtr error_fn, CdlDiagnosticFnPtr warn_fn)
1578
{
1579
    CYG_REPORT_FUNCNAME("CdlConfiguration::add");
1580
    CYG_REPORT_FUNCARG3XV(this, error_fn, warn_fn);
1581
    CYG_PRECONDITION_THISC();
1582
 
1583
    // Initialize the savefile support, so that it is known what
1584
    // commands can occur in a savefile.
1585
    if (!CdlToplevelBody::savefile_support_initialized()) {
1586
        this->initialize_savefile_support();
1587
    }
1588
 
1589
    // The interpreter should not have any left-over junk.
1590
    CdlInterpreter interp = this->get_interpreter();
1591
    CYG_PRECONDITION_CLASSC(interp);
1592
    CYG_ASSERTC(0 == interp->get_loadable());
1593
    CYG_ASSERTC(0 == interp->get_container());
1594
    CYG_ASSERTC(0 == interp->get_node());
1595
    CYG_ASSERTC(0 == interp->get_transaction());
1596
 
1597
    // Keep track of enough information to undo all the changes.
1598
    CdlParse::clear_error_count(interp);
1599
    CdlInterpreterBody::DiagSupport    diag_support(interp, error_fn, warn_fn);
1600
    CdlInterpreterBody::ContextSupport context_support(interp, filename);
1601
 
1602
    try {
1603
        interp->set_transaction(transaction);
1604
 
1605
        std::vector<CdlInterpreterCommandEntry> commands;
1606
        this->get_savefile_commands(commands);
1607
        CdlInterpreterBody::CommandSupport interp_cmds(interp, commands);
1608
 
1609
        interp->eval_file(filename);
1610
 
1611
        // All the data has been read in without generating an
1612
        // exception. However there may have been errors reported via
1613
        // the error_fn handling, and any errors at all should result
1614
        // in an exception.
1615
        int error_count = CdlParse::get_error_count(interp);
1616
        if (error_count > 0) {
1617
            std::string tmp;
1618
            Cdl::integer_to_string(error_count, tmp);
1619
            throw CdlInputOutputException("Invalid savefile \"" + filename + "\".\n" +
1620
                                          tmp + " error" + ((error_count > 1) ? "s" : "") +
1621
                                          " occurred while reading in the savefile data.");
1622
        }
1623
 
1624
    } catch(...) {
1625
        interp->set_transaction(0);
1626
        throw;
1627
    }
1628
 
1629
    interp->set_transaction(0);
1630
 
1631
    CYG_REPORT_RETURN();
1632
}
1633
 
1634
//}}}
1635
//{{{  savefile commands                                
1636
 
1637
// ----------------------------------------------------------------------------
1638
// A cdl_configuration command does not actually do very much. It acts as
1639
// a container for subcommands, and it can be used to change the name.
1640
//
1641
// The command could also check that the current configuration is empty.
1642
// This is not done, to allow multiple savefiles to be loaded into
1643
// a single configuration in future.
1644
int
1645
CdlConfigurationBody::savefile_configuration_command(CdlInterpreter interp, int argc, const char* argv[])
1646
{
1647
    CYG_REPORT_FUNCNAMETYPE("CdlConfiguration::savefile_configuration_command", "result %d");
1648
    CYG_PRECONDITION_CLASSC(interp);
1649
 
1650
    int result = TCL_OK;
1651
    CdlToplevel toplevel = interp->get_toplevel();
1652
    CYG_ASSERT_CLASSC(toplevel);
1653
    CdlConfiguration config = dynamic_cast<CdlConfiguration>(toplevel);
1654
    CYG_ASSERT_CLASSC(config);
1655
 
1656
    std::vector<CdlInterpreterCommandEntry> subcommands;
1657
    std::vector<CdlInterpreterCommandEntry>* toplevel_commands = 0;
1658
 
1659
    try {
1660
        std::vector<std::pair<std::string,std::string> > options;
1661
        int data_index = CdlParse::parse_options(interp, "cdl_configuration command", 0, argc, argv, 1, options);
1662
 
1663
        // A broken cdl_configuration command is pretty fatal, chances are
1664
        // that the entire load is going to fail.
1665
        if (data_index != (argc - 2)) {
1666
            CdlParse::report_error(interp, "", "Invalid cdl_configuration command in savefile, expecting two arguments.");
1667
        } else {
1668
            config->set_name(argv[1]);
1669
            config->get_savefile_subcommands("cdl_configuration", subcommands);
1670
            toplevel_commands = interp->push_commands(subcommands);
1671
 
1672
            std::string tcl_result;
1673
            result = interp->eval(argv[2], tcl_result);
1674
 
1675
            interp->pop_commands(toplevel_commands);
1676
            toplevel_commands = 0;
1677
        }
1678
 
1679
    } catch(...) {
1680
        if (0 != toplevel_commands) {
1681
            interp->pop_commands(toplevel_commands);
1682
        }
1683
        throw;
1684
    }
1685
 
1686
    CYG_REPORT_RETVAL(result);
1687
    return result;
1688
}
1689
 
1690
// ----------------------------------------------------------------------------
1691
int
1692
CdlConfigurationBody::savefile_description_command(CdlInterpreter interp, int argc, const char* argv[])
1693
{
1694
    CYG_REPORT_FUNCNAME("CdlConfiguration::savefile_description_command");
1695
    CYG_PRECONDITION_CLASSC(interp);
1696
 
1697
    CdlToplevel toplevel = interp->get_toplevel();
1698
    CYG_ASSERT_CLASSC(toplevel);
1699
    CdlConfiguration config = dynamic_cast<CdlConfiguration>(toplevel);
1700
    CYG_ASSERT_CLASSC(config);
1701
 
1702
    std::vector<std::pair<std::string,std::string> > options;
1703
    int data_index = CdlParse::parse_options(interp, "cdl_configuration/description command", 0, argc, argv, 1, options);
1704
 
1705
    if (data_index != (argc - 1)) {
1706
        CdlParse::report_warning(interp, "",
1707
                                 "Ignoring invalid configuration description command, expecting a single argument.");
1708
    } else {
1709
        config->description = argv[1];
1710
    }
1711
    return TCL_OK;
1712
}
1713
 
1714
// ----------------------------------------------------------------------------
1715
int
1716
CdlConfigurationBody::savefile_hardware_command(CdlInterpreter interp, int argc, const char* argv[])
1717
{
1718
    CYG_REPORT_FUNCNAME("CdlConfiguration::savefile_hardware_command");
1719
    CYG_PRECONDITION_CLASSC(interp);
1720
 
1721
    CdlToplevel toplevel = interp->get_toplevel();
1722
    CYG_ASSERT_CLASSC(toplevel);
1723
    CdlConfiguration config = dynamic_cast<CdlConfiguration>(toplevel);
1724
    CYG_ASSERT_CLASSC(config);
1725
 
1726
    std::vector<std::pair<std::string,std::string> > options;
1727
    int data_index = CdlParse::parse_options(interp, "cdl_configuration/hardware command", 0, argc, argv, 1, options);
1728
 
1729
    if (data_index != (argc - 1)) {
1730
        CdlParse::report_warning(interp, "", "Ignoring invalid configuration hardware command, expecting a single argument.");
1731
    } else {
1732
        config->current_hardware = argv[1];
1733
    }
1734
 
1735
    return TCL_OK;
1736
}
1737
 
1738
// ----------------------------------------------------------------------------
1739
int
1740
CdlConfigurationBody::savefile_template_command(CdlInterpreter interp, int argc, const char* argv[])
1741
{
1742
    CYG_REPORT_FUNCNAME("CdlConfiguration::savefile_template_command");
1743
    CYG_PRECONDITION_CLASSC(interp);
1744
 
1745
    CdlToplevel toplevel = interp->get_toplevel();
1746
    CYG_ASSERT_CLASSC(toplevel);
1747
    CdlConfiguration config = dynamic_cast<CdlConfiguration>(toplevel);
1748
    CYG_ASSERT_CLASSC(config);
1749
 
1750
    std::vector<std::pair<std::string,std::string> > options;
1751
    int data_index = CdlParse::parse_options(interp, "cdl_configuration/template command", 0, argc, argv, 1, options);
1752
 
1753
    if (data_index != (argc - 1)) {
1754
        CdlParse::report_warning(interp, "", "Ignoring invalid configuration template command, expecting a single argument.");
1755
    } else {
1756
        config->current_template = argv[1];
1757
    }
1758
 
1759
    return TCL_OK;
1760
}
1761
 
1762
// ----------------------------------------------------------------------------
1763
int
1764
CdlConfigurationBody::savefile_package_command(CdlInterpreter interp, int argc, const char* argv[])
1765
{
1766
    CYG_REPORT_FUNCNAME("CdlConfiguration::savefile_package_command");
1767
    CYG_PRECONDITION_CLASSC(interp);
1768
 
1769
    CdlToplevel toplevel = interp->get_toplevel();
1770
    CYG_ASSERT_CLASSC(toplevel);
1771
    CdlConfiguration config = dynamic_cast<CdlConfiguration>(toplevel);
1772
    CYG_ASSERT_CLASSC(config);
1773
    CdlPackagesDatabase db = config->get_database();
1774
    CYG_ASSERT_CLASSC(db);
1775
 
1776
    std::string pkgname;
1777
    std::string pkgversion;
1778
    CdlPackage  pkg = 0;
1779
 
1780
    std::vector<std::pair<std::string,std::string> > options;
1781
    static const char* optlist[] = {
1782
        "template:f",
1783
        "hardware:f",
1784
 
1785
    };
1786
    int data_index = CdlParse::parse_options(interp, "cdl_configuration/package command", optlist, argc, argv, 1, options);
1787
 
1788
    if (data_index == (argc - 1)) {
1789
        // If no version is specified, silently default to the most recent.
1790
        pkgname = argv[argc - 1];
1791
        pkgversion = "";
1792
    } else if (data_index == (argc - 2)) {
1793
        pkgname = argv[argc - 2];
1794
        pkgversion = argv[argc - 1];
1795
    } else {
1796
        // If we cannot load all the packages then much of the
1797
        // savefile is likely to be problematical.
1798
        CdlParse::report_error(interp, "", "Invalid cdl_configuration/package command, expecting name and version");
1799
        CYG_REPORT_RETURN();
1800
        return TCL_OK;
1801
    }
1802
 
1803
    if (0 != config->lookup(pkgname)) {
1804
        // If the package was already loaded, check the version string. If the versions
1805
        // are identical then we do not need to worry any further. Otherwise a mismatch
1806
        // warning is appropriate.
1807
        CdlNode node = config->lookup(pkgname);
1808
        CYG_ASSERT_CLASSC(node);
1809
        pkg = dynamic_cast<CdlPackage>(node);
1810
        if (0 == pkg) {
1811
            // The name is in use, but it is not a package
1812
            CdlParse::report_error(interp, "",
1813
                                   std::string("Unable to load package `") + pkgname + "', the name is already in use.");
1814
        } else if (pkgversion != pkg->get_value()) {
1815
            CdlParse::report_warning(interp, "",
1816
                                     std::string("Cannot load version `") + pkgversion + "' of package `" +
1817
                                     pkgname + "', version `" + pkg->get_value() + "' is already loaded.");
1818
        }
1819
    } else if (!db->is_known_package(pkgname)) {
1820
        CdlParse::report_error(interp, "",
1821
                               std::string("Attempt to load an unknown package `") + pkgname + "'.");
1822
    } else {
1823
        if ("" != pkgversion) {
1824
            const std::vector<std::string>& versions = db->get_package_versions(pkgname);
1825
            if (versions.end() == std::find(versions.begin(), versions.end(), pkgversion)) {
1826
                CdlParse::report_warning(interp, "",
1827
                                         std::string("The savefile specifies version `") + pkgversion +
1828
                                         "' for package `" + pkgname + "'\nThis version is not available.\n" +
1829
                                         "Using the most recent version instead.");
1830
                pkgversion = "";
1831
            }
1832
        }
1833
        CdlDiagnosticFnPtr error_fn    = interp->get_error_fn_ptr();
1834
        CdlDiagnosticFnPtr warn_fn     = interp->get_warning_fn_ptr();
1835
        CdlTransaction     transaction = interp->get_transaction();
1836
        config->load_package(transaction, pkgname, pkgversion, error_fn, warn_fn, false);
1837
        CdlNode pkg_node = config->lookup(pkgname);
1838
        CYG_ASSERTC(0 != pkg_node);
1839
        pkg = dynamic_cast<CdlPackage>(pkg_node);
1840
        CYG_ASSERT_CLASSC(pkg);
1841
    }
1842
 
1843
    if ((0 != pkg) && (0 != options.size())) {
1844
        std::vector<std::pair<std::string,std::string> >::const_iterator opt_i;
1845
        for (opt_i = options.begin(); opt_i != options.end(); opt_i++) {
1846
            if (opt_i->first == "template") {
1847
                pkg->loaded_for_template = true;
1848
            } else if (opt_i->first == "hardware") {
1849
                pkg->loaded_for_hardware = true;
1850
            }
1851
        }
1852
    }
1853
 
1854
    return TCL_OK;
1855
}
1856
 
1857
//}}}
1858
 
1859
//}}}
1860
 

powered by: WebSVN 2.1.0

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