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