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