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

Subversion Repositories openrisc

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

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

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

powered by: WebSVN 2.1.0

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