Cpp / Qt: Reduce boost usage (memory and tuple)
[gpgme.git] / lang / cpp / src / configuration.cpp
1 /*
2   configuration.cpp - wraps gpgme configuration components
3   Copyright (C) 2010 Klarälvdalens Datakonsult AB
4
5   This file is part of GPGME++.
6
7   GPGME++ is free software; you can redistribute it and/or
8   modify it under the terms of the GNU Library General Public
9   License as published by the Free Software Foundation; either
10   version 2 of the License, or (at your option) any later version.
11
12   GPGME++ is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU Library General Public License for more details.
16
17   You should have received a copy of the GNU Library General Public License
18   along with GPGME++; see the file COPYING.LIB.  If not, write to the
19   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20   Boston, MA 02110-1301, USA.
21 */
22
23 #include "configuration.h"
24 #include "error.h"
25 #include "util.h"
26
27 #include <gpgme.h>
28
29 #include <boost/foreach.hpp>
30
31 #include <iterator>
32 #include <algorithm>
33 #include <ostream>
34 #include <cstring>
35 #include <assert.h>
36
37 using namespace GpgME;
38 using namespace GpgME::Configuration;
39
40 typedef std::shared_ptr< boost::remove_pointer<gpgme_conf_opt_t>::type > shared_gpgme_conf_opt_t;
41 typedef std::weak_ptr< boost::remove_pointer<gpgme_conf_opt_t>::type > weak_gpgme_conf_opt_t;
42
43 typedef std::shared_ptr< boost::remove_pointer<gpgme_conf_arg_t>::type > shared_gpgme_conf_arg_t;
44 typedef std::weak_ptr< boost::remove_pointer<gpgme_conf_arg_t>::type > weak_gpgme_conf_arg_t;
45
46 typedef std::shared_ptr< boost::remove_pointer<gpgme_ctx_t>::type > shared_gpgme_ctx_t;
47 typedef std::weak_ptr< boost::remove_pointer<gpgme_ctx_t>::type > weak_gpgme_ctx_t;
48
49 namespace
50 {
51 struct nodelete {
52     template <typename T> void operator()(T *) {}
53 };
54 }
55
56 // static
57 std::vector<Component> Component::load(Error &returnedError)
58 {
59
60     //
61     // 1. get a context:
62     //
63     gpgme_ctx_t ctx_native = 0;
64     if (const gpgme_error_t err = gpgme_new(&ctx_native)) {
65         returnedError = Error(err);
66         return std::vector<Component>();
67     }
68     const shared_gpgme_ctx_t ctx(ctx_native, &gpgme_release);
69
70     //
71     // 2. load the config:
72     //
73     gpgme_conf_comp_t conf_list_native = 0;
74     if (const gpgme_error_t err = gpgme_op_conf_load(ctx_native, &conf_list_native)) {
75         returnedError = Error(err);
76         return std::vector<Component>();
77     }
78     shared_gpgme_conf_comp_t head(conf_list_native, &gpgme_conf_release);
79
80     //
81     // 3. convert to vector<Component>:
82     //
83     std::vector<Component> result;
84
85     while (head) {
86         // secure 'head->next' (if any) against memleaks:
87         shared_gpgme_conf_comp_t next;
88         if (head->next) {
89             next.reset(head->next, &gpgme_conf_release);
90         }
91
92         // now prevent double-free of next.get() and following:
93         head->next = 0;
94
95         // now add a new Component to 'result' (may throw):
96         result.resize(result.size() + 1);
97         result.back().comp.swap(head);   // .comp = std::move( head );
98         head.swap(next);                 //  head = std::move( next );
99     }
100
101     return result;
102 }
103
104 Error Component::save() const
105 {
106
107     if (isNull()) {
108         return Error(make_error(GPG_ERR_INV_ARG));
109     }
110
111     //
112     // 1. get a context:
113     //
114     gpgme_ctx_t ctx_native = 0;
115     if (const gpgme_error_t err = gpgme_new(&ctx_native)) {
116         return Error(err);
117     }
118     const shared_gpgme_ctx_t ctx(ctx_native, &gpgme_release);
119
120     //
121     // 2. save the config:
122     //
123     return Error(gpgme_op_conf_save(ctx.get(), comp.get()));
124 }
125
126 const char *Component::name() const
127 {
128     return comp ? comp->name : 0 ;
129 }
130
131 const char *Component::description() const
132 {
133     return comp ? comp->description : 0 ;
134 }
135
136 const char *Component::programName() const
137 {
138     return comp ? comp->program_name : 0 ;
139 }
140
141 Option Component::option(unsigned int idx) const
142 {
143     gpgme_conf_opt_t opt = 0;
144     if (comp) {
145         opt = comp->options;
146     }
147     while (opt && idx) {
148         opt = opt->next;
149         --idx;
150     }
151     if (opt) {
152         return Option(comp, opt);
153     }
154     return Option();
155 }
156
157 Option Component::option(const char *name) const
158 {
159     gpgme_conf_opt_t opt = 0;
160     if (comp) {
161         opt = comp->options;
162     }
163     using namespace std; // for strcmp
164     while (opt && strcmp(name, opt->name) != 0) {
165         opt = opt->next;
166     }
167     if (opt) {
168         return Option(comp, opt);
169     }
170     return Option();
171 }
172
173 unsigned int Component::numOptions() const
174 {
175     unsigned int result = 0;
176     for (gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next) {
177         ++result;
178     }
179     return result;
180 }
181
182 std::vector<Option> Component::options() const
183 {
184     std::vector<Option> result;
185     for (gpgme_conf_opt_t opt = comp ? comp->options : 0 ; opt ; opt = opt->next) {
186         result.push_back(Option(comp, opt));
187     }
188     return result;
189 }
190
191 static gpgme_conf_arg_t mygpgme_conf_arg_copy(gpgme_conf_arg_t other, gpgme_conf_type_t type)
192 {
193     gpgme_conf_arg_t result = 0, last = 0;
194     for (gpgme_conf_arg_t a = other ; a ; a = a->next) {
195         gpgme_conf_arg_t arg = 0;
196         const gpgme_error_t err
197             = gpgme_conf_arg_new(&arg, type,
198                                  a->no_arg                 ? 0 :
199                                  type == GPGME_CONF_STRING ? a->value.string :
200                                  /* else */                  static_cast<void *>(&a->value));
201         if (err) {
202             gpgme_conf_arg_release(result, type);
203             return 0;
204         }
205         assert(arg);
206         if (result) {
207             last->next = arg;
208         } else {
209             result = arg;
210         }
211         last = arg;
212     }
213     return result;
214 }
215
216 Component Option::parent() const
217 {
218     return Component(comp.lock());
219 }
220
221 unsigned int Option::flags() const
222 {
223     return isNull() ? 0 : opt->flags;
224 }
225
226 Level Option::level() const
227 {
228     return isNull() ? Internal : static_cast<Level>(opt->level) ;
229 }
230
231 const char *Option::name() const
232 {
233     return isNull() ? 0 : opt->name ;
234 }
235
236 const char *Option::description() const
237 {
238     return isNull() ? 0 : opt->description ;
239 }
240
241 const char *Option::argumentName() const
242 {
243     return isNull() ? 0 : opt->argname ;
244 }
245
246 Type Option::type() const
247 {
248     return isNull() ? NoType : static_cast<Type>(opt->type) ;
249 }
250
251 Type Option::alternateType() const
252 {
253     return isNull() ? NoType : static_cast<Type>(opt->alt_type) ;
254 }
255
256 #if 0
257 static Option::Variant argument_to_variant(gpgme_conf_type_t type, bool list, gpgme_conf_arg_t arg)
258 {
259     assert(arg);
260     switch (type) {
261     case GPGME_CONF_NONE:
262         if (list) {
263             // return the count (number of times set):
264             return arg->value.count;
265         } else {
266             return none;
267         }
268     case GPGME_CONF_INT32:
269         if (list) {
270             std::vector<int> result;
271             for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
272                 result.push_back(a->value.int32);
273             }
274             return result;
275         } else {
276             return arg->value.int32;
277         }
278     case GPGME_CONF_UINT32:
279         if (list) {
280             std::vector<unsigned int> result;
281             for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
282                 result.push_back(a->value.uint32);
283             }
284             return result;
285         } else {
286             return arg->value.uint32;
287         }
288     case GPGME_CONF_FILENAME:
289     case GPGME_CONF_LDAP_SERVER:
290     case GPGME_CONF_KEY_FPR:
291     case GPGME_CONF_PUB_KEY:
292     case GPGME_CONF_SEC_KEY:
293     case GPGME_CONF_ALIAS_LIST:
294     // these should not happen in alt_type, but fall through
295     case GPGME_CONF_STRING:
296         if (list) {
297             std::vector<const char *> result;
298             for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
299                 result.push_back(a->value.string);
300             }
301             return result;
302         } else {
303             return arg->value.string;
304         }
305     }
306     assert(!"Option: unknown alt_type!");
307     return Option::Variant();
308 }
309
310 namespace
311 {
312 inline const void *to_void_star(const char *s)
313 {
314     return s;
315 }
316 inline const void *to_void_star(const std::string &s)
317 {
318     return s.c_str();
319 }
320 inline const void *to_void_star(const int &i)
321 {
322     return &i;    // const-&: sic!
323 }
324 inline const void *to_void_star(const unsigned int &i)
325 {
326     return &i;    // const-&: sic!
327 }
328
329 struct VariantToArgumentVisitor : boost::static_visitor<gpgme_conf_arg_t> {
330     static gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const void *value)
331     {
332         gpgme_conf_arg_t arg = 0;
333 #ifdef HAVE_GPGME_CONF_ARG_NEW_WITH_CONST_VALUE
334         if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, value)) {
335             return 0;
336         }
337 #else
338         if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, const_cast<void *>(value))) {
339             return 0;
340         }
341 #endif
342         else {
343             return arg;
344         }
345     }
346
347     gpgme_conf_arg_t operator()(bool v) const
348     {
349         return v ? make_argument(0) : 0 ;
350     }
351
352     gpgme_conf_arg_t operator()(const char *s) const
353     {
354         return make_argument(s ? s : "");
355     }
356
357     gpgme_conf_arg_t operator()(const std::string &s) const
358     {
359         return operator()(s.c_str());
360     }
361
362     gpgme_conf_arg_t operator()(int i) const
363     {
364         return make_argument(&i);
365     }
366
367     gpgme_conf_arg_t operator()(unsigned int i) const
368     {
369         return make_argument(&i);
370     }
371
372     template <typename T>
373     gpgme_conf_arg_t operator()(const std::vector<T> &value) const
374     {
375         gpgme_conf_arg_t result = 0;
376         gpgme_conf_arg_t last = 0;
377         for (typename std::vector<T>::const_iterator it = value.begin(), end = value.end() ; it != end ; ++it) {
378             if (gpgme_conf_arg_t arg = make_argument(to_void_star(*it))) {
379                 if (last) {
380                     last = last->next = arg;
381                 } else {
382                     result = last = arg;
383                 }
384             }
385         }
386         return result;
387     }
388
389 };
390 }
391
392 static gpgme_conf_arg_t variant_to_argument(const Option::Variant &value)
393 {
394     VariantToArgumentVisitor v;
395     return apply_visitor(v, value);
396 }
397
398 optional<Option::Variant> Option::defaultValue() const
399 {
400     if (isNull()) {
401         return optional<Variant>();
402     } else {
403         return argument_to_variant(opt->alt_type, opt->flags & GPGME_CONF_LIST, opt->default_value);
404     }
405 }
406 #endif
407
408 Argument Option::defaultValue() const
409 {
410     if (isNull()) {
411         return Argument();
412     } else {
413         return Argument(comp.lock(), opt, opt->default_value, false);
414     }
415 }
416
417 const char *Option::defaultDescription() const
418 {
419     return isNull() ? 0 : opt->default_description ;
420 }
421
422 Argument Option::noArgumentValue() const
423 {
424     if (isNull()) {
425         return Argument();
426     } else {
427         return Argument(comp.lock(), opt, opt->no_arg_value, false);
428     }
429 }
430
431 const char *Option::noArgumentDescription() const
432 {
433     return isNull() ? 0 : opt->no_arg_description ;
434 }
435
436 Argument Option::activeValue() const
437 {
438     if (isNull()) {
439         return Argument();
440     } else {
441         return Argument(comp.lock(), opt, opt->value, false);
442     }
443 }
444
445 Argument Option::currentValue() const
446 {
447     if (isNull()) {
448         return Argument();
449     }
450     const gpgme_conf_arg_t arg =
451         opt->change_value ? opt->new_value ? opt->new_value : opt->default_value :
452         opt->value        ? opt->value :
453         /* else */          opt->default_value ;
454     return Argument(comp.lock(), opt, arg, false);
455 }
456
457 Argument Option::newValue() const
458 {
459     if (isNull()) {
460         return Argument();
461     } else {
462         return Argument(comp.lock(), opt, opt->new_value, false);
463     }
464 }
465
466 bool Option::set() const
467 {
468     if (isNull()) {
469         return false;
470     } else if (opt->change_value) {
471         return opt->new_value;
472     } else {
473         return opt->value;
474     }
475 }
476
477 bool Option::dirty() const
478 {
479     return !isNull() && opt->change_value ;
480 }
481
482 Error Option::setNewValue(const Argument &argument)
483 {
484     if (isNull()) {
485         return Error(make_error(GPG_ERR_INV_ARG));
486     } else if (argument.isNull()) {
487         return resetToDefaultValue();
488     } else if (const gpgme_conf_arg_t arg = mygpgme_conf_arg_copy(argument.arg, opt->alt_type)) {
489         return Error(gpgme_conf_opt_change(opt, 0, arg));
490     } else {
491         return Error(make_error(GPG_ERR_ENOMEM));
492     }
493 }
494
495 Error Option::resetToActiveValue()
496 {
497     if (isNull()) {
498         return Error(make_error(GPG_ERR_INV_ARG));
499     } else {
500         return Error(gpgme_conf_opt_change(opt, 1, 0));
501     }
502 }
503
504 Error Option::resetToDefaultValue()
505 {
506     if (isNull()) {
507         return Error(make_error(GPG_ERR_INV_ARG));
508     } else {
509         return Error(gpgme_conf_opt_change(opt, 0, 0));
510     }
511 }
512
513 static gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const void *value)
514 {
515     gpgme_conf_arg_t arg = 0;
516     if (const gpgme_error_t err = gpgme_conf_arg_new(&arg, type, value)) {
517         return 0;
518     } else {
519         return arg;
520     }
521 }
522
523 Argument Option::createNoneArgument(bool set) const
524 {
525     if (isNull() || alternateType() != NoType) {
526         return Argument();
527     } else {
528         if (set) {
529             return createNoneListArgument(1);
530         }
531     }
532     return Argument();
533 }
534
535 Argument Option::createStringArgument(const char *value) const
536 {
537     if (isNull() || alternateType() != StringType) {
538         return Argument();
539     } else {
540         return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true);
541     }
542 }
543
544 Argument Option::createStringArgument(const std::string &value) const
545 {
546     if (isNull() || alternateType() != StringType) {
547         return Argument();
548     } else {
549         return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value.c_str()), true);
550     }
551 }
552
553 Argument Option::createIntArgument(int value) const
554 {
555     if (isNull() || alternateType() != IntegerType) {
556         return Argument();
557     } else {
558         return Argument(comp.lock(), opt, make_argument(GPGME_CONF_INT32, &value), true);
559     }
560 }
561
562 Argument Option::createUIntArgument(unsigned int value) const
563 {
564     if (isNull() || alternateType() != UnsignedIntegerType) {
565         return Argument();
566     } else {
567         return Argument(comp.lock(), opt, make_argument(GPGME_CONF_UINT32, &value), true);
568     }
569 }
570
571 namespace
572 {
573 const void *to_void_star(const char *s)
574 {
575     return s;
576 }
577 const void *to_void_star(const std::string &s)
578 {
579     return s.c_str();
580 }
581 const void *to_void_star(const int &i)
582 {
583     return &i;    // const-&: sic!
584 }
585 const void *to_void_star(const unsigned int &i)
586 {
587     return &i;    // const-&: sic!
588 }
589
590 template <typename T>
591 gpgme_conf_arg_t make_argument(gpgme_conf_type_t type, const std::vector<T> &value)
592 {
593     gpgme_conf_arg_t result = 0;
594     gpgme_conf_arg_t last = 0;
595     for (typename std::vector<T>::const_iterator it = value.begin(), end = value.end() ; it != end ; ++it) {
596         if (gpgme_conf_arg_t arg = make_argument(type, to_void_star(*it))) {
597             if (last) {
598                 last = last->next = arg;
599             } else {
600                 result = last = arg;
601             }
602         }
603     }
604     return result;
605 }
606 }
607
608 Argument Option::createNoneListArgument(unsigned int value) const
609 {
610     if (value) {
611         return Argument(comp.lock(), opt, make_argument(GPGME_CONF_NONE, &value), true);
612     }
613     return Argument();
614 }
615
616 Argument Option::createStringListArgument(const std::vector<const char *> &value) const
617 {
618     return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true);
619 }
620
621 Argument Option::createStringListArgument(const std::vector<std::string> &value) const
622 {
623     return Argument(comp.lock(), opt, make_argument(GPGME_CONF_STRING, value), true);
624 }
625
626 Argument Option::createIntListArgument(const std::vector<int> &value) const
627 {
628     return Argument(comp.lock(), opt, make_argument(GPGME_CONF_INT32, value), true);
629 }
630
631 Argument Option::createUIntListArgument(const std::vector<unsigned int> &value) const
632 {
633     return Argument(comp.lock(), opt, make_argument(GPGME_CONF_UINT32, value), true);
634 }
635
636 Argument::Argument(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg, bool owns)
637     : comp(comp),
638       opt(opt),
639       arg(owns ? arg : mygpgme_conf_arg_copy(arg, opt ? opt->alt_type : GPGME_CONF_NONE))
640 {
641
642 }
643
644 #if 0
645 Argument::Argument(const shared_gpgme_conf_comp_t &comp, gpgme_conf_opt_t opt, gpgme_conf_arg_t arg)
646     : comp(comp),
647       opt(opt),
648       arg(mygpgme_conf_arg_copy(arg, opt ? opt->alt_type : GPGME_CONF_NONE))
649 {
650
651 }
652 #endif
653
654 Argument::Argument(const Argument &other)
655     : comp(other.comp),
656       opt(other.opt),
657       arg(mygpgme_conf_arg_copy(other.arg, opt ? opt->alt_type : GPGME_CONF_NONE))
658 {
659
660 }
661
662 Argument::~Argument()
663 {
664     gpgme_conf_arg_release(arg, opt ? opt->alt_type : GPGME_CONF_NONE);
665 }
666
667 Option Argument::parent() const
668 {
669     return Option(comp.lock(), opt);
670 }
671
672 bool Argument::boolValue() const
673 {
674     return numberOfTimesSet();
675 }
676
677 unsigned int Argument::numElements() const
678 {
679     if (isNull()) {
680         return 0;
681     }
682     unsigned int result = 0;
683     for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
684         ++result;
685     }
686     return result;
687 }
688
689 const char *Argument::stringValue(unsigned int idx) const
690 {
691     if (isNull() || opt->alt_type != GPGME_CONF_STRING) {
692         return 0;
693     }
694     gpgme_conf_arg_t a = arg;
695     while (a && idx) {
696         a = a->next;
697         --idx;
698     }
699     return a ? a->value.string : 0 ;
700 }
701
702 int Argument::intValue(unsigned int idx) const
703 {
704     if (isNull() || opt->alt_type != GPGME_CONF_INT32) {
705         return 0;
706     }
707     gpgme_conf_arg_t a = arg;
708     while (a && idx) {
709         a = a->next;
710         --idx;
711     }
712     return a ? a->value.int32 : 0 ;
713 }
714
715 unsigned int Argument::uintValue(unsigned int idx) const
716 {
717     if (isNull() || opt->alt_type != GPGME_CONF_UINT32) {
718         return 0;
719     }
720     gpgme_conf_arg_t a = arg;
721     while (a && idx) {
722         a = a->next;
723         --idx;
724     }
725     return a ? a->value.uint32 : 0 ;
726 }
727
728 unsigned int Argument::numberOfTimesSet() const
729 {
730     if (isNull() || opt->alt_type != GPGME_CONF_NONE) {
731         return 0;
732     }
733     return arg->value.count;
734 }
735
736 std::vector<const char *> Argument::stringValues() const
737 {
738     if (isNull() || opt->alt_type != GPGME_CONF_STRING) {
739         return std::vector<const char *>();
740     }
741     std::vector<const char *> result;
742     for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
743         result.push_back(a->value.string);
744     }
745     return result;
746 }
747
748 std::vector<int> Argument::intValues() const
749 {
750     if (isNull() || opt->alt_type != GPGME_CONF_INT32) {
751         return std::vector<int>();
752     }
753     std::vector<int> result;
754     for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
755         result.push_back(a->value.int32);
756     }
757     return result;
758 }
759
760 std::vector<unsigned int> Argument::uintValues() const
761 {
762     if (isNull() || opt->alt_type != GPGME_CONF_UINT32) {
763         return std::vector<unsigned int>();
764     }
765     std::vector<unsigned int> result;
766     for (gpgme_conf_arg_t a = arg ; a ; a = a->next) {
767         result.push_back(a->value.uint32);
768     }
769     return result;
770 }
771
772 std::ostream &Configuration::operator<<(std::ostream &os, Level level)
773 {
774     switch (level) {
775     case Basic:     return os << "Basic";
776     case Advanced:  return os << "Advanced";
777     case Expert:    return os << "Expert";
778     case Invisible: return os << "Invisible";
779     case Internal:  return os << "Internal";
780     case NumLevels: ;
781     }
782     return os << "<unknown>";
783 }
784
785 std::ostream &Configuration::operator<<(std::ostream &os, Type type)
786 {
787     switch (type) {
788     case NoType:              return os << "None";
789     case StringType:          return os << "String";
790     case IntegerType:         return os << "Integer";
791     case UnsignedIntegerType: return os << "UnsignedInteger";
792     case FilenameType:        return os << "Filename";
793     case LdapServerType:      return os << "LdapServer";
794     case KeyFingerprintType:  return os << "KeyFingerprint";
795     case PublicKeyType:       return os << "PublicKey";
796     case SecretKeyType:       return os << "SecretKey";
797     case AliasListType:       return os << "AliasList";
798     case MaxType: ;
799     }
800     return os << "<unknown>";
801 }
802
803 std::ostream &Configuration::operator<<(std::ostream &os, Flag f)
804 {
805     unsigned int flags = f;
806     std::vector<const char *> s;
807     if (flags & Group) {
808         s.push_back("Group");
809     }
810     if (flags & Optional) {
811         s.push_back("Optional");
812     }
813     if (flags & List) {
814         s.push_back("List");
815     }
816     if (flags & Runtime) {
817         s.push_back("Runtime");
818     }
819     if (flags & Default) {
820         s.push_back("Default");
821     }
822     if (flags & DefaultDescription) {
823         s.push_back("DefaultDescription");
824     }
825     if (flags & NoArgumentDescription) {
826         s.push_back("NoArgumentDescription");
827     }
828     if (flags & NoChange) {
829         s.push_back("NoChange");
830     }
831     flags &= ~(Group | Optional | List | Runtime | Default | DefaultDescription | NoArgumentDescription | NoChange);
832     if (flags) {
833         s.push_back("other flags(");
834     }
835     std::copy(s.begin(), s.end(),
836               std::ostream_iterator<const char *>(os, "|"));
837     if (flags) {
838         os << flags << ')';
839     }
840     return os;
841 }
842
843 std::ostream &Configuration::operator<<(std::ostream &os, const Component &c)
844 {
845     os << "Component["
846        << "\n  name       : " << protect(c.name())
847        << "\n  description: " << protect(c.description())
848        << "\n  programName: " << protect(c.programName())
849        << "\n  options    : \n";
850     const std::vector<Option> options = c.options();
851     std::copy(options.begin(), options.end(),
852               std::ostream_iterator<Option>(os, "\n"));
853     os << "\n]";
854     return os;
855 }
856
857 std::ostream &Configuration::operator<<(std::ostream &os, const Option &o)
858 {
859     return os << "Option["
860            << "\n  name:       : " << protect(o.name())
861            << "\n  description : " << protect(o.description())
862            << "\n  argName     : " << protect(o.argumentName())
863            << "\n  flags       : " << static_cast<Flag>(o.flags())
864            << "\n  level       : " << o.level()
865            << "\n  type        : " << o.type()
866            << "\n  alt_type    : " << o.alternateType()
867            << "\n  default_val : " << o.defaultValue()
868            << "\n  default_desc: " << protect(o.defaultDescription())
869            << "\n  no_arg_value: " << o.noArgumentValue()
870            << "\n  no_arg_desc : " << protect(o.noArgumentDescription())
871            << "\n  active_value: " << o.activeValue()
872            << "\n  new_value   : " << o.newValue()
873            << "\n  --> cur_val : " << o.currentValue()
874            << "\n  set         : " << o.set()
875            << "\n  dirty       : " << o.dirty()
876            << "\n]"
877            ;
878 }
879
880 std::ostream &Configuration::operator<<(std::ostream &os, const Argument &a)
881 {
882     const Option o = a.parent();
883     const bool list = o.flags() & List;
884     os << "Argument[";
885     if (a) {
886         switch (o.alternateType()) {
887         case NoType:
888             if (list) {
889                 os << a.numberOfTimesSet() << 'x';
890             } else {
891                 os << a.boolValue();
892             }
893             break;
894         default:
895         case StringType:
896             if (list) {
897                 const std::vector<const char *> v = a.stringValues();
898                 os << v.size() << ':';
899                 // can't use std::copy + ostream_iterator here, since we need the protect() call
900                 bool first = true;
901                 BOOST_FOREACH(const char *s, v) {
902                     if (first) {
903                         first = false;
904                     } else {
905                         os << ',';
906                     }
907                     os << protect(s);
908                 }
909             } else {
910                 os << protect(a.stringValue());
911             }
912             break;
913         case IntegerType:
914             if (list) {
915                 const std::vector<int> v = a.intValues();
916                 os << v.size() << ':';
917                 std::copy(v.begin(), v.end(),
918                           std::ostream_iterator<int>(os, ","));
919             } else {
920                 os << a.intValue();
921             }
922             break;
923         case UnsignedIntegerType:
924             if (list) {
925                 const std::vector<unsigned int> v = a.uintValues();
926                 os << v.size() << ':';
927                 std::copy(v.begin(), v.end(),
928                           std::ostream_iterator<unsigned int>(os, ","));
929             } else {
930                 os << a.intValue();
931             }
932             break;
933         }
934     }
935     return os << ']';
936 }