~ubuntu-branches/ubuntu/intrepid/schroot/intrepid

« back to all changes in this revision

Viewing changes to sbuild/sbuild-keyfile.h

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2006-07-08 18:33:28 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20060708183328-rlo4mpldmyoda55q
Tags: 0.99.2-2ubuntu1
* remerge ubuntu changes:
  + debian/control: libpam-dev (>> 0.79-3ubuntu6)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright © 2005-2006  Roger Leigh <rleigh@debian.org>
 
2
 *
 
3
 * schroot is free software; you can redistribute it and/or modify it
 
4
 * under the terms of the GNU General Public License as published by
 
5
 * the Free Software Foundation; either version 2 of the License, or
 
6
 * (at your option) any later version.
 
7
 *
 
8
 * schroot is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11
 * General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License
 
14
 * along with this program; if not, write to the Free Software
 
15
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 
16
 * MA  02111-1307  USA
 
17
 *
 
18
 *********************************************************************/
 
19
 
 
20
#ifndef SBUILD_KEYFILE_H
 
21
#define SBUILD_KEYFILE_H
 
22
 
 
23
#include <sbuild/sbuild-i18n.h>
 
24
#include <sbuild/sbuild-log.h>
 
25
#include <sbuild/sbuild-parse-error.h>
 
26
#include <sbuild/sbuild-parse-value.h>
 
27
#include <sbuild/sbuild-types.h>
 
28
#include <sbuild/sbuild-tr1types.h>
 
29
#include <sbuild/sbuild-util.h>
 
30
 
 
31
#include <cassert>
 
32
#include <map>
 
33
#include <string>
 
34
#include <sstream>
 
35
 
 
36
#include <boost/format.hpp>
 
37
 
 
38
namespace sbuild
 
39
{
 
40
 
 
41
  /**
 
42
   * Configuration file parser.  This class loads an INI-style
 
43
   * configuration file from a file or stream.  The format is
 
44
   * documented in schroot.conf(5).  It is based upon the Glib
 
45
   * GKeyFile class, which it is intended to replace.
 
46
   */
 
47
  class keyfile
 
48
  {
 
49
  private:
 
50
    /// Key-value-comment-line tuple.
 
51
    typedef std::tr1::tuple<std::string,std::string,std::string,unsigned int>
 
52
    item_type;
 
53
 
 
54
    /// Map between key name and key-value-comment tuple.
 
55
    typedef std::map<std::string,item_type> item_map_type;
 
56
 
 
57
    /// Group-items-comment-line tuple.
 
58
    typedef std::tr1::tuple<std::string,item_map_type,std::string,unsigned int> group_type;
 
59
 
 
60
    /// Map between group name and group-items-comment tuple.
 
61
    typedef std::map<std::string,group_type> group_map_type;
 
62
 
 
63
  public:
 
64
    /// Configuration parameter priority.
 
65
    enum priority
 
66
      {
 
67
        PRIORITY_OPTIONAL,   ///< The parameter is optional.
 
68
        PRIORITY_REQUIRED,   ///< The parameter is required.
 
69
        PRIORITY_DISALLOWED, ///< The parameter is not allowed in this context.
 
70
        PRIORITY_DEPRECATED, ///< The parameter is deprecated, but functional.
 
71
        PRIORITY_OBSOLETE    ///< The parameter is obsolete, and not functional.
 
72
      };
 
73
 
 
74
    /// Exception type.
 
75
    typedef parse_error error;
 
76
 
 
77
    /// The constructor.
 
78
    keyfile ();
 
79
 
 
80
    /**
 
81
     * The constructor.
 
82
     *
 
83
     * @param file the file to load the configuration from.
 
84
     */
 
85
    keyfile (std::string const& file);
 
86
 
 
87
    /**
 
88
     * The constructor.
 
89
     *
 
90
     * @param stream the stream to load the configuration from.
 
91
     */
 
92
    keyfile (std::istream& stream);
 
93
 
 
94
    /// The destructor.
 
95
    virtual ~keyfile ();
 
96
 
 
97
    /**
 
98
     * Get a list of groups.
 
99
     *
 
100
     * @returns a list of groups in the keyfile.  If no groups exist,
 
101
     * the list will be empty.
 
102
     */
 
103
    string_list
 
104
    get_groups () const;
 
105
 
 
106
    /**
 
107
     * Get a list of keys in a group.
 
108
     *
 
109
     * @param group the group to use.
 
110
     * @returns a list of keys in a group.  If no keys exist in the
 
111
     * group, or the group does not exist, the list will be empty.
 
112
     */
 
113
    string_list
 
114
    get_keys (std::string const& group) const;
 
115
 
 
116
    /**
 
117
     * Check if a group exists.
 
118
     *
 
119
     * @param group the group to check for.
 
120
     * @returns true if the group exists, otherwise false.
 
121
     */
 
122
    bool
 
123
    has_group (std::string const& group) const;
 
124
 
 
125
    /**
 
126
     * Check if a key exists.
 
127
     *
 
128
     * @param group the group the key is in.
 
129
     * @param key the key to check for.
 
130
     * @returns true if the key exists, otherwise false.
 
131
     */
 
132
    bool
 
133
    has_key (std::string const& group,
 
134
             std::string const& key) const;
 
135
 
 
136
    /**
 
137
     * Set a group.  The group will be created (and the comment set)
 
138
     * only if the group does not already exist.
 
139
     *
 
140
     * @param group the group to set.
 
141
     * @param comment the comment to set.
 
142
     */
 
143
    void
 
144
    set_group (std::string const& group,
 
145
               std::string const& comment);
 
146
 
 
147
  private:
 
148
    /**
 
149
     * Set a group.  The group will be created (and the comment set)
 
150
     * only if the group does not already exist.
 
151
     *
 
152
     * @param group the group to set.
 
153
     * @param comment the comment to set.
 
154
     * @param line the line number in the input file, or 0 otherwise.
 
155
     */
 
156
    void
 
157
    set_group (std::string const& group,
 
158
               std::string const& comment,
 
159
               unsigned int       line);
 
160
 
 
161
  public:
 
162
    /**
 
163
     * Get a group comment.
 
164
     *
 
165
     * @param group the group to find.
 
166
     * @returns the comment.
 
167
     */
 
168
    std::string
 
169
    get_comment (std::string const& group) const;
 
170
 
 
171
    /**
 
172
     * Get a key comment.
 
173
     *
 
174
     * @param group the group to find.
 
175
     * @param key the key to find.
 
176
     * @returns the comment.
 
177
     */
 
178
    std::string
 
179
    get_comment (std::string const& group,
 
180
                 std::string const& key) const;
 
181
 
 
182
    /**
 
183
     * Get a group line number.
 
184
     *
 
185
     * @param group the group to find.
 
186
     * @returns the line number, or 0 if not available.
 
187
     */
 
188
    unsigned int
 
189
    get_line (std::string const& group) const;
 
190
 
 
191
    /**
 
192
     * Get a key line number.
 
193
     *
 
194
     * @param group the group to find.
 
195
     * @param key the key to find.
 
196
     * @returns the line number, or 0 if not available.
 
197
     */
 
198
    unsigned int
 
199
    get_line (std::string const& group,
 
200
              std::string const& key) const;
 
201
 
 
202
    /**
 
203
     * Get a key value.
 
204
     *
 
205
     * @param group the group the key is in.
 
206
     * @param key the key to get.
 
207
     * @param value the value to store the key's value in.  This must
 
208
     * be settable from an istream and be copyable.
 
209
     * @returns true if the key was found, otherwise false (in which
 
210
     * case value will be unchanged).
 
211
     */
 
212
    template <typename T>
 
213
    bool
 
214
    get_value (std::string const& group,
 
215
               std::string const& key,
 
216
               T&                 value) const
 
217
    {
 
218
      log_debug(DEBUG_INFO) << "Getting keyfile group=" << group
 
219
                            << ", key=" << key << std::endl;
 
220
      const item_type *found_item = find_item(group, key);
 
221
      if (found_item)
 
222
        {
 
223
          std::string const& strval(std::tr1::get<1>(*found_item));
 
224
          try
 
225
            {
 
226
              parse_value(strval, value);
 
227
              return true;
 
228
            }
 
229
          catch (parse_error const& e)
 
230
            {
 
231
              error ep(group, key, parse_error::NONE, e.what());
 
232
              log_warning() << ep.what() << std::endl;
 
233
              return false;
 
234
            }
 
235
        }
 
236
      log_debug(DEBUG_NOTICE) << "key not found" << std::endl;
 
237
      return false;
 
238
    }
 
239
 
 
240
    /**
 
241
     * Get a key value.  If the value does not exist, is deprecated or
 
242
     * obsolete, warn appropriately.
 
243
     *
 
244
     * @param group the group the key is in.
 
245
     * @param key the key to get.
 
246
     * @param priority the priority of the option.
 
247
     * @param value the value to store the key's value in.  This must
 
248
     * be settable from an istream and be copyable.
 
249
     * @returns true if the key was found, otherwise false (in which
 
250
     * case value will be unchanged).
 
251
     */
 
252
    template <typename T>
 
253
    bool
 
254
    get_value (std::string const& group,
 
255
               std::string const& key,
 
256
               priority           priority,
 
257
               T&                 value) const
 
258
    {
 
259
      bool status = get_value(group, key, value);
 
260
      check_priority(group, key, priority, status);
 
261
      return status;
 
262
    }
 
263
 
 
264
    /**
 
265
     * Get a localised key string value.
 
266
     *
 
267
     * @param group the group the key is in.
 
268
     * @param key the key to get.
 
269
     * @param value the string to store the key's localised value in.
 
270
     * @returns true if the key was found, otherwise false (in which
 
271
     * case value will be unchanged).
 
272
     */
 
273
    bool
 
274
    get_locale_string (std::string const& group,
 
275
                       std::string const& key,
 
276
                       std::string&       value) const;
 
277
 
 
278
    /**
 
279
     * Get a localised key string value.  If the value does not exist,
 
280
     * is deprecated or obsolete, warn appropriately.
 
281
     *
 
282
     * @param group the group the key is in.
 
283
     * @param key the key to get.
 
284
     * @param priority the priority of the option.
 
285
     * @param value the string to store the key's localised value in.
 
286
     * @returns true if the key was found, otherwise false (in which
 
287
     * case value will be unchanged).
 
288
     */
 
289
    bool
 
290
    get_locale_string (std::string const& group,
 
291
                       std::string const& key,
 
292
                       priority           priority,
 
293
                       std::string&       value) const;
 
294
 
 
295
    /**
 
296
     * Get a localised key string value for a specific locale.
 
297
     *
 
298
     * @param group the group the key is in.
 
299
     * @param key the key to get.
 
300
     * @param locale the locale to use.
 
301
     * @param value the string to store the key's localised value in.
 
302
     * @returns true if the key was found, otherwise false (in which
 
303
     * case value will be unchanged).
 
304
     */
 
305
    bool
 
306
    get_locale_string (std::string const& group,
 
307
                       std::string const& key,
 
308
                       std::string const& locale,
 
309
                       std::string&       value) const;
 
310
 
 
311
    /**
 
312
     * Get a localised key string value for a specific locale.  If the
 
313
     * value does not exist, is deprecated or obsolete, warn
 
314
     * appropriately.
 
315
     *
 
316
     * @param group the group the key is in.
 
317
     * @param key the key to get.
 
318
     * @param locale the locale to use.
 
319
     * @param priority the priority of the option.
 
320
     * @param value the string to store the key's localised value in.
 
321
     * @returns true if the key was found, otherwise false (in which
 
322
     * case value will be unchanged).
 
323
     */
 
324
    bool
 
325
    get_locale_string (std::string const& group,
 
326
                       std::string const& key,
 
327
                       std::string const& locale,
 
328
                       priority           priority,
 
329
                       std::string&       value) const;
 
330
 
 
331
    /**
 
332
     * Get a key value as a list.
 
333
     *
 
334
     * @param group the group the key is in.
 
335
     * @param key the key to get.
 
336
     * @param container the container to store the key's value in.
 
337
     * The value type must be settable from an istream and be
 
338
     * copyable.  The list must be a container with a standard insert
 
339
     * method.
 
340
     * @returns true if the key was found, otherwise false (in which
 
341
     * case value will be undefined).
 
342
     */
 
343
    template <typename C>
 
344
    bool
 
345
    get_list_value (std::string const& group,
 
346
                    std::string const& key,
 
347
                    C&                 container) const
 
348
    {
 
349
      std::string item_value;
 
350
      if (get_value(group, key, item_value))
 
351
        {
 
352
          string_list items = split_string(item_value,
 
353
                                           std::string(1, this->separator));
 
354
          for (string_list::const_iterator pos = items.begin();
 
355
               pos != items.end();
 
356
               ++pos
 
357
               )
 
358
            {
 
359
              typename C::value_type tmp;
 
360
 
 
361
              try
 
362
                {
 
363
                  parse_value(*pos, tmp);
 
364
                }
 
365
              catch (parse_error const& e)
 
366
                {
 
367
                  error ep(group, key, parse_error::NONE, e.what());
 
368
                  log_warning() << ep.what() << std::endl;
 
369
                  return false;
 
370
                }
 
371
 
 
372
              container.push_back(tmp);
 
373
            }
 
374
          return true;
 
375
        }
 
376
      return false;
 
377
    }
 
378
 
 
379
    /**
 
380
     * Get a key value as a list.  If the value does not exist, is
 
381
     * deprecated or obsolete, warn appropriately.
 
382
     *
 
383
     * @param group the group the key is in.
 
384
     * @param key the key to get.
 
385
     * @param priority the priority of the option.
 
386
     * @param container the container to store the key's value in.
 
387
     * The value type must be settable from an istream and be
 
388
     * copyable.  The list must be a container with a standard insert
 
389
     * method.
 
390
     * @returns true if the key was found, otherwise false (in which
 
391
     * case value will be undefined).
 
392
     */
 
393
    template <typename C>
 
394
    bool
 
395
    get_list_value (std::string const& group,
 
396
                    std::string const& key,
 
397
                    priority           priority,
 
398
                    C&                 container) const
 
399
    {
 
400
      bool status = get_list_value(group, key, container);
 
401
      check_priority(group, key, priority, status);
 
402
      return status;
 
403
    }
 
404
 
 
405
    /**
 
406
     * Set a key value.
 
407
     *
 
408
     * @param group the group the key is in.
 
409
     * @param key the key to set.
 
410
     * @param value the value to get the key's value from.  This must
 
411
     * allow output to an ostream.
 
412
     */
 
413
    template <typename T>
 
414
    void
 
415
    set_value (std::string const& group,
 
416
               std::string const& key,
 
417
               T const&           value)
 
418
    {
 
419
      set_value(group, key, value, std::string());
 
420
    }
 
421
 
 
422
    /**
 
423
     * Set a key value.
 
424
     *
 
425
     * @param group the group the key is in.
 
426
     * @param key the key to set.
 
427
     * @param value the value to get the key's value from.  This must
 
428
     * @param comment the comment for this key.
 
429
     * allow output to an ostream.
 
430
     */
 
431
    template <typename T>
 
432
    void
 
433
    set_value (std::string const& group,
 
434
               std::string const& key,
 
435
               T const&           value,
 
436
               std::string const& comment)
 
437
    {
 
438
      std::ostringstream os;
 
439
      os.imbue(std::locale("C"));
 
440
      os << std::boolalpha << value;
 
441
 
 
442
      set_value(group, key, os.str(), comment, 0);
 
443
    }
 
444
 
 
445
  private:
 
446
    /**
 
447
     * Set a key value.
 
448
     *
 
449
     * @param group the group the key is in.
 
450
     * @param key the key to set.
 
451
     * @param value the value to get the key's value from.  This must
 
452
     * @param comment the comment for this key.
 
453
     * @param line the line number in the input file, or 0 otherwise.
 
454
     * allow output to an ostream.
 
455
     */
 
456
    void
 
457
    set_value (std::string const& group,
 
458
               std::string const& key,
 
459
               std::string const& value,
 
460
               std::string const& comment,
 
461
               unsigned int       line)
 
462
    {
 
463
      set_group(group, "");
 
464
      group_type *found_group = find_group(group);
 
465
      assert (found_group != 0); // should not fail
 
466
 
 
467
      item_map_type& items = std::tr1::get<1>(*found_group);
 
468
 
 
469
      item_map_type::iterator pos = items.find(key);
 
470
      if (pos != items.end())
 
471
        items.erase(pos);
 
472
      items.insert
 
473
        (item_map_type::value_type(key,
 
474
                                   item_type(key, value, comment, line)));
 
475
    }
 
476
 
 
477
  public:
 
478
    /**
 
479
     * Set a key value from a list.
 
480
     *
 
481
     * @param group the group the key is in.
 
482
     * @param key the key to set.
 
483
     * @param begin an iterator referring to the start of the
 
484
     * list. The value type must allow output to an ostream.
 
485
     * @param end an iterator referring to the end of the list.
 
486
     */
 
487
    template <typename I>
 
488
    void
 
489
    set_list_value (std::string const& group,
 
490
                    std::string const& key,
 
491
                    I                  begin,
 
492
                    I                  end)
 
493
    {
 
494
      set_list_value(group, key, begin, end, std::string());
 
495
    }
 
496
 
 
497
    /**
 
498
     * Set a key value from a list.
 
499
     *
 
500
     * @param group the group the key is in.
 
501
     * @param key the key to set.
 
502
     * @param begin an iterator referring to the start of the
 
503
     * list. The value type must allow output to an ostream.
 
504
     * @param end an iterator referring to the end of the list.
 
505
     * @param comment the comment for this key.
 
506
     */
 
507
    template <typename I>
 
508
    void
 
509
    set_list_value (std::string const& group,
 
510
                    std::string const& key,
 
511
                    I                  begin,
 
512
                    I                  end,
 
513
                    std::string const& comment)
 
514
    {
 
515
      std::string strval;
 
516
 
 
517
      for (I pos = begin; pos != end; ++ pos)
 
518
        {
 
519
          std::ostringstream os;
 
520
          os.imbue(std::locale("C"));
 
521
          os << std::boolalpha << *pos;
 
522
          if (os)
 
523
            {
 
524
              strval += os.str();
 
525
              if (pos + 1 != end)
 
526
                strval += this->separator;
 
527
            }
 
528
        }
 
529
 
 
530
      set_value (group, key, strval, comment);
 
531
    }
 
532
 
 
533
    /**
 
534
     * Remove a group.
 
535
     *
 
536
     * @param group the group to remove.
 
537
     */
 
538
    void
 
539
    remove_group (std::string const& group);
 
540
 
 
541
    /**
 
542
     * Remove a key.
 
543
     *
 
544
     * @param group the group the key is in.
 
545
     * @param key the key to remove.
 
546
     */
 
547
    void
 
548
    remove_key (std::string const& group,
 
549
                std::string const& key);
 
550
 
 
551
    /**
 
552
     * Add a keyfile to the keyfile.
 
553
     *
 
554
     * @param rhs the keyfile to add.
 
555
     * @returns the modified keyfile.
 
556
     */
 
557
    keyfile&
 
558
    operator += (keyfile const& rhs);
 
559
 
 
560
    /**
 
561
     * Add a keyfile to the keyfile.
 
562
     *
 
563
     * @param lhs the keyfile to add to.
 
564
     * @param rhs the values to add.
 
565
     * @returns the new keyfile.
 
566
     */
 
567
    friend keyfile
 
568
    operator + (keyfile const& lhs,
 
569
                keyfile const& rhs);
 
570
 
 
571
    /**
 
572
     * keyfile initialisation from an istream.
 
573
     */
 
574
    template <class charT, class traits>
 
575
    friend
 
576
    std::basic_istream<charT,traits>&
 
577
    operator >> (std::basic_istream<charT,traits>& stream,
 
578
                 keyfile&                          kf)
 
579
    {
 
580
      keyfile tmp;
 
581
      size_t linecount = 0;
 
582
      std::string line;
 
583
      std::string group;
 
584
      std::string comment;
 
585
      std::string key;
 
586
      std::string value;
 
587
 
 
588
      while (std::getline(stream, line))
 
589
      {
 
590
        linecount++;
 
591
 
 
592
        if (line.length() == 0)
 
593
          {
 
594
            // Empty line; do nothing.
 
595
          }
 
596
        else if (line[0] == '#') // Comment line
 
597
          {
 
598
            if (!comment.empty())
 
599
              comment += '\n';
 
600
            comment += line.substr(1);
 
601
          }
 
602
        else if (line[0] == '[') // Group
 
603
          {
 
604
            std::string::size_type fpos = line.find_first_of(']');
 
605
            std::string::size_type lpos = line.find_last_of(']');
 
606
            if (fpos == std::string::npos || lpos == std::string::npos ||
 
607
                fpos != lpos)
 
608
              {
 
609
                throw error(linecount, parse_error::INVALID_GROUP, line);
 
610
              }
 
611
            group = line.substr(1, fpos - 1);
 
612
 
 
613
            if (group.length() == 0)
 
614
              {
 
615
                throw error(linecount, parse_error::INVALID_GROUP, line);
 
616
              }
 
617
 
 
618
            // Insert group
 
619
            if (tmp.has_group(group))
 
620
              {
 
621
                error e(linecount, parse_error::DUPLICATE_GROUP, group);
 
622
                log_warning() << e.what() << std::endl;
 
623
              }
 
624
            else
 
625
              tmp.set_group(group, comment, linecount);
 
626
            comment.clear();
 
627
          }
 
628
        else // Item
 
629
          {
 
630
            std::string::size_type pos = line.find_first_of('=');
 
631
            if (pos == std::string::npos)
 
632
              {
 
633
                throw error(linecount, parse_error::INVALID_LINE, line);
 
634
              }
 
635
            if (pos == 0)
 
636
              {
 
637
                throw error(linecount, parse_error::NO_KEY, line);
 
638
              }
 
639
            key = line.substr(0, pos);
 
640
            if (pos == line.length() - 1)
 
641
              value = "";
 
642
            else
 
643
              value = line.substr(pos + 1);
 
644
 
 
645
            // No group specified
 
646
            if (group.empty())
 
647
              {
 
648
                throw error(linecount, parse_error::NO_GROUP, line);
 
649
              }
 
650
 
 
651
            // Insert item
 
652
            if (tmp.has_key(group, key))
 
653
              {
 
654
                error e(linecount, group, parse_error::DUPLICATE_KEY, key);
 
655
                log_warning() << e.what() << std::endl;
 
656
              }
 
657
            else
 
658
              tmp.set_value(group, key, value, comment, linecount);
 
659
            comment.clear();
 
660
          }
 
661
      }
 
662
 
 
663
      kf += tmp;
 
664
 
 
665
      return stream;
 
666
    }
 
667
 
 
668
    /**
 
669
     * keyfile output to an ostream.
 
670
     */
 
671
    template <class charT, class traits>
 
672
    friend
 
673
    std::basic_ostream<charT,traits>&
 
674
    operator << (std::basic_ostream<charT,traits>& stream,
 
675
                 keyfile const&                    kf)
 
676
    {
 
677
      unsigned int group_count = 0;
 
678
 
 
679
      for (group_map_type::const_iterator gp = kf.groups.begin();
 
680
           gp != kf.groups.end();
 
681
           ++gp, ++group_count)
 
682
        {
 
683
          if (group_count > 0)
 
684
            stream << '\n';
 
685
 
 
686
          group_type const& group = gp->second;
 
687
          std::string const& groupname = std::tr1::get<0>(group);
 
688
          std::string const& comment = std::tr1::get<2>(group);
 
689
 
 
690
          if (comment.length() > 0)
 
691
            print_comment(comment, stream);
 
692
 
 
693
          stream << '[' << groupname << ']' << '\n';
 
694
 
 
695
          item_map_type const& items(std::tr1::get<1>(group));
 
696
          for (item_map_type::const_iterator it = items.begin();
 
697
               it != items.end();
 
698
               ++it)
 
699
            {
 
700
              item_type const& item = it->second;
 
701
              std::string const& key(std::tr1::get<0>(item));
 
702
              std::string const& value(std::tr1::get<1>(item));
 
703
              std::string const& comment(std::tr1::get<2>(item));
 
704
 
 
705
              if (comment.length() > 0)
 
706
                print_comment(comment, stream);
 
707
 
 
708
              stream << key << '=' << value << '\n';
 
709
            }
 
710
        }
 
711
 
 
712
      return stream;
 
713
    }
 
714
 
 
715
  private:
 
716
    /**
 
717
     * Find a group by it's name.
 
718
     *
 
719
     * @param group the group to find.
 
720
     * @returns the group, or 0 if not found.
 
721
     */
 
722
    const group_type *
 
723
    find_group (std::string const& group) const;
 
724
 
 
725
    /**
 
726
     * Find a group by it's name.
 
727
     *
 
728
     * @param group the group to find.
 
729
     * @returns the group, or 0 if not found.
 
730
     */
 
731
    group_type *
 
732
    find_group (std::string const& group);
 
733
 
 
734
    /**
 
735
     * Find a key by it's group and name.
 
736
     *
 
737
     * @param group the group the key is in.
 
738
     * @param key the key to find
 
739
     * @returns the key, or 0 if not found.
 
740
     */
 
741
    const item_type *
 
742
    find_item (std::string const& group,
 
743
               std::string const& key) const;
 
744
 
 
745
    /**
 
746
     * Find a key by it's group and name.
 
747
     *
 
748
     * @param group the group the key is in.
 
749
     * @param key the key to find
 
750
     * @returns the key, or 0 if not found.
 
751
     */
 
752
    item_type *
 
753
    find_item (std::string const& group,
 
754
               std::string const& key);
 
755
 
 
756
    /**
 
757
     * Check if a key is missing or present when not permitted.
 
758
     *
 
759
     * @param group the group the key is in.
 
760
     * @param key the key to get.
 
761
     * @param priority the key priority.
 
762
     * @param valid true if key exists, false if not existing.
 
763
     */
 
764
    void
 
765
    check_priority (std::string const& group,
 
766
                    std::string const& key,
 
767
                    priority           priority,
 
768
                    bool               valid) const;
 
769
 
 
770
    /**
 
771
     * Print a comment to a stream.  The comment will have hash ('#')
 
772
     * marks printed at the start of each line.
 
773
     *
 
774
     * @param comment the comment to print.
 
775
     * @param stream the stream to output to.
 
776
     */
 
777
    static void
 
778
    print_comment (std::string const& comment,
 
779
                   std::ostream&      stream);
 
780
 
 
781
    /// The top-level groups.
 
782
    group_map_type groups;
 
783
    /// The separator used as a list item delimiter.
 
784
    char           separator;
 
785
 
 
786
  public:
 
787
    /**
 
788
     * Set a key value from an object method return value.  This is
 
789
     * the same as calling set_value directly, but handles exceptions
 
790
     * being thrown by the object method, which are turned into
 
791
     * parse_error exceptions.
 
792
     *
 
793
     * @param object the object to use.
 
794
     * @param method the object method to call.
 
795
     * @param keyfile the keyfile to use.
 
796
     * @param group the group the key is in.
 
797
     * @param key the key to set.
 
798
     */
 
799
    template<class C, typename T>
 
800
    static void
 
801
    set_object_value (C const&            object,
 
802
                      T             (C::* method)() const,
 
803
                      keyfile&            keyfile,
 
804
                      std::string const&  group,
 
805
                      std::string const&  key)
 
806
    {
 
807
      try
 
808
        {
 
809
          keyfile.set_value(group, key, (object.*method)());
 
810
        }
 
811
      catch (runtime_error const& e)
 
812
        {
 
813
          throw parse_error(group, key, parse_error::NONE, e.what());
 
814
        }
 
815
    }
 
816
 
 
817
    /**
 
818
     * Set a key value from an object method return value reference.
 
819
     * This is the same as calling set_value directly, but handles
 
820
     * exceptions being thrown by the object method, which are turned
 
821
     * into parse_error exceptions.
 
822
     *
 
823
     * @param object the object to use.
 
824
     * @param method the object method to call.
 
825
     * @param keyfile the keyfile to use.
 
826
     * @param group the group the key is in.
 
827
     * @param key the key to set.
 
828
     */
 
829
    template<class C, typename T>
 
830
    static void
 
831
    set_object_value (C const&            object,
 
832
                      T const&      (C::* method)() const,
 
833
                      keyfile&            keyfile,
 
834
                      std::string const&  group,
 
835
                      std::string const&  key)
 
836
    {
 
837
      try
 
838
        {
 
839
          keyfile.set_value(group, key, (object.*method)());
 
840
        }
 
841
      catch (runtime_error const& e)
 
842
        {
 
843
          throw parse_error(group, key, parse_error::NONE, e.what());
 
844
        }
 
845
    }
 
846
 
 
847
    /**
 
848
     * Set a key list value from an object method return value.  The
 
849
     * method must return a container with begin() and end() methods
 
850
     * which return forward iterators.  This is the same as calling
 
851
     * set_list_value directly, but handles exceptions being thrown by
 
852
     * the object method, which are turned into parse_error
 
853
     * exceptions.
 
854
     *
 
855
     * @param object the object to use.
 
856
     * @param method the object method to call.
 
857
     * @param keyfile the keyfile to use.
 
858
     * @param group the group the key is in.
 
859
     * @param key the key to set.
 
860
     */
 
861
    template<class C, typename T>
 
862
    static void
 
863
    set_object_list_value (C const&            object,
 
864
                           T             (C::* method)() const,
 
865
                           keyfile&            keyfile,
 
866
                           std::string const&  group,
 
867
                           std::string const&  key)
 
868
    {
 
869
      try
 
870
        {
 
871
          keyfile.set_list_value(group, key,
 
872
                                 (object.*method)().begin(),
 
873
                                 (object.*method)().end());
 
874
        }
 
875
      catch (runtime_error const& e)
 
876
        {
 
877
          throw parse_error(group, key, parse_error::NONE, e.what());
 
878
        }
 
879
    }
 
880
 
 
881
    /**
 
882
     * Set a key list value from an object method return value.  The
 
883
     * method must return a container reference with begin() and end()
 
884
     * methods which return forward iterators.  This is the same as
 
885
     * calling set_list_value directly, but handles exceptions being
 
886
     * thrown by the object method, which are turned into parse_error
 
887
     * exceptions.
 
888
     *
 
889
     * @param object the object to use.
 
890
     * @param method the object method to call.
 
891
     * @param keyfile the keyfile to use.
 
892
     * @param group the group the key is in.
 
893
     * @param key the key to set.
 
894
     */
 
895
    template<class C, typename T>
 
896
    static void
 
897
    set_object_list_value (C const&            object,
 
898
                           T const&      (C::* method)() const,
 
899
                           keyfile&            keyfile,
 
900
                           std::string const&  group,
 
901
                           std::string const&  key)
 
902
    {
 
903
      try
 
904
        {
 
905
          keyfile.set_list_value(group, key,
 
906
                                 (object.*method)().begin(),
 
907
                                 (object.*method)().end());
 
908
        }
 
909
      catch (runtime_error const& e)
 
910
        {
 
911
          throw parse_error(group, key, parse_error::NONE, e.what());
 
912
        }
 
913
    }
 
914
 
 
915
    /**
 
916
     * Get a key value and set it in an object using an object method.
 
917
     * This is the same as calling get_value directly, but handles
 
918
     * exceptions being thrown by the object method, and
 
919
     * deserialisation errors, which are turned into parse_error
 
920
     * exceptions pointing to the group, key and line number in the
 
921
     * input file.
 
922
     *
 
923
     * @param object the object to use.
 
924
     * @param method the object method to call.
 
925
     * @param keyfile the keyfile to use.
 
926
     * @param group the group the key is in.
 
927
     * @param key the key to set.
 
928
     * @param priority the key priority.
 
929
     */
 
930
    template<class C, typename T>
 
931
    static void
 
932
    get_object_value (C&                  object,
 
933
                      void          (C::* method)(T param),
 
934
                      keyfile const&      keyfile,
 
935
                      std::string const&  group,
 
936
                      std::string const&  key,
 
937
                      keyfile::priority   priority)
 
938
    {
 
939
      T value;
 
940
      if (keyfile.get_value(group, key, priority, value))
 
941
        {
 
942
          try
 
943
            {
 
944
              (object.*method)(value);
 
945
            }
 
946
          catch (runtime_error const& e)
 
947
            {
 
948
              throw parse_error(keyfile.get_line(group, key),
 
949
                                group, key, parse_error::NONE, e.what());
 
950
            }
 
951
        }
 
952
    }
 
953
 
 
954
    /**
 
955
     * Get a key value and set it by reference in an object using an
 
956
     * object method.  This is the same as calling get_value directly,
 
957
     * but handles exceptions being thrown by the object method, and
 
958
     * deserialisation errors, which are turned into parse_error
 
959
     * exceptions pointing to the group, key and line number in the
 
960
     * input file.
 
961
     *
 
962
     * @param object the object to use.
 
963
     * @param method the object method to call.
 
964
     * @param keyfile the keyfile to use.
 
965
     * @param group the group the key is in.
 
966
     * @param key the key to set.
 
967
     * @param priority the key priority.
 
968
     */
 
969
    template<class C, typename T>
 
970
    static void
 
971
    get_object_value (C&                  object,
 
972
                      void          (C::* method)(T const& param),
 
973
                      keyfile const&      keyfile,
 
974
                      std::string const&  group,
 
975
                      std::string const&  key,
 
976
                      keyfile::priority   priority)
 
977
    {
 
978
      T value;
 
979
      if (keyfile.get_value(group, key, priority, value))
 
980
        {
 
981
          try
 
982
            {
 
983
              (object.*method)(value);
 
984
            }
 
985
          catch (runtime_error const& e)
 
986
            {
 
987
              throw parse_error(keyfile.get_line(group, key),
 
988
                                group, key, parse_error::NONE, e.what());
 
989
            }
 
990
        }
 
991
    }
 
992
 
 
993
    /**
 
994
     * Get a key list value and set it in an object using an object
 
995
     * method.  This is the same as calling get_list_value directly,
 
996
     * but handles exceptions being thrown by the object method, and
 
997
     * deserialisation errors, which are turned into parse_error
 
998
     * exceptions pointing to the group, key and line number in the
 
999
     * input file.
 
1000
     *
 
1001
     * @param object the object to use.
 
1002
     * @param method the object method to call.
 
1003
     * @param keyfile the keyfile to use.
 
1004
     * @param group the group the key is in.
 
1005
     * @param key the key to set.
 
1006
     * @param priority the key priority.
 
1007
     */
 
1008
    template<class C, typename T>
 
1009
    static void
 
1010
    get_object_list_value (C&                  object,
 
1011
                           void          (C::* method)(T param),
 
1012
                           keyfile const&      keyfile,
 
1013
                           std::string const&  group,
 
1014
                           std::string const&  key,
 
1015
                           keyfile::priority   priority)
 
1016
    {
 
1017
      T value;
 
1018
      if (keyfile.get_list_value(group, key, priority, value))
 
1019
        {
 
1020
          try
 
1021
            {
 
1022
              (object.*method)(value);
 
1023
            }
 
1024
          catch (runtime_error const& e)
 
1025
            {
 
1026
              throw parse_error(keyfile.get_line(group, key),
 
1027
                                group, key, parse_error::NONE, e.what());
 
1028
            }
 
1029
        }
 
1030
    }
 
1031
 
 
1032
    /**
 
1033
     * Get a key list value and set it by reference in an object using
 
1034
     * an object method.  This is the same as calling get_list_value
 
1035
     * directly, but handles exceptions being thrown by the object
 
1036
     * method, and deserialisation errors, which are turned into
 
1037
     * parse_error exceptions pointing to the group, key and line
 
1038
     * number in the input file.
 
1039
     *
 
1040
     * @param object the object to use.
 
1041
     * @param method the object method to call.
 
1042
     * @param keyfile the keyfile to use.
 
1043
     * @param group the group the key is in.
 
1044
     * @param key the key to set.
 
1045
     * @param priority the key priority.
 
1046
     */
 
1047
    template<class C, typename T>
 
1048
    static void
 
1049
    get_object_list_value (C&                  object,
 
1050
                           void          (C::* method)(T const& param),
 
1051
                           keyfile const&      keyfile,
 
1052
                           std::string const&  group,
 
1053
                           std::string const&  key,
 
1054
                           keyfile::priority   priority)
 
1055
    {
 
1056
      T value;
 
1057
      if (keyfile.get_list_value(group, key, priority, value))
 
1058
        {
 
1059
          try
 
1060
            {
 
1061
              (object.*method)(value);
 
1062
            }
 
1063
          catch (runtime_error const& e)
 
1064
            {
 
1065
              throw parse_error(keyfile.get_line(group, key),
 
1066
                                group, key, parse_error::NONE, e.what());
 
1067
            }
 
1068
        }
 
1069
    }
 
1070
  };
 
1071
 
 
1072
}
 
1073
 
 
1074
#endif /* SBUILD_KEYFILE_H */
 
1075
 
 
1076
/*
 
1077
 * Local Variables:
 
1078
 * mode:C++
 
1079
 * End:
 
1080
 */