1package Config::Auto;
2
3use strict;
4use warnings;
5
6use Carp qw[croak];
7
8use vars qw[$VERSION $DisablePerl $Untaint $Debug];
9
10$VERSION        = '0.44';
11$DisablePerl    = 0;
12$Untaint        = 0;
13$Debug          = 0;
14
15=head1 NAME
16
17Config::Auto - Magical config file parser
18
19=head1 SYNOPSIS
20
21    use Config::Auto;
22
23    ### Not very magical at all.
24    $config = Config::Auto::parse("myprogram.conf", format => "colon");
25
26    ### Considerably more magical.
27    $config = Config::Auto::parse("myprogram.conf");
28
29    ### Highly magical.
30    $config = Config::Auto::parse();
31
32    ### Using the OO interface
33    $ca     = Config::Auto->new( source => $text );
34    $ca     = Config::Auto->new( source => $fh );
35    $ca     = Config::Auto->new( source => $filename );
36
37    $href   = $ca->score;           # compute the score for various formats
38
39    $config = $ca->parse;           # parse the config
40
41    $format = $ca->format;          # detected (or provided) config format
42    $str    = $ca->as_string;       # config file stringified
43    $fh     = $ca->fh;              # config file handle
44    $file   = $ca->file;            # config filename
45    $aref   = $ca->data;            # data from your config, split by newlines
46
47=cut
48
49
50=head1 DESCRIPTION
51
52This module was written after having to write Yet Another Config File Parser
53for some variety of colon-separated config. I decided "never again".
54
55Config::Auto aims to be the most C<DWIM> config parser available, by detecting
56configuration styles, include paths and even config filenames automagically.
57
58See the L<HOW IT WORKS> section below on implementation details.
59
60=cut
61
62=head1 ACCESSORS
63
64=head2 @formats = Config::Auto->formats
65
66Returns a list of supported formats for your config files. These formats
67are also the keys as used by the C<score()> method.
68
69C<Config::Auto> recognizes the following formats:
70
71=over 4
72
73=item * perl    => perl code
74
75=item * colon   => colon separated (e.g., key:value)
76
77=item * space   => space separated (e.g., key value)
78
79=item * equal   => equal separated (e.g., key=value)
80
81=item * bind    => bind style (not available)
82
83=item * irssi   => irssi style (not available)
84
85=item * xml     => xml (via XML::Simple)
86
87=item * ini     => .ini format (via Config::IniFiles)
88
89=item * list    => list (e.g., foo bar baz)
90
91=item * yaml    => yaml (via YAML.pm)
92
93=back
94
95=cut
96
97my %Methods = (
98    perl   => \&_eval_perl,
99    colon  => \&_colon_sep,
100    space  => \&_space_sep,
101    equal  => \&_equal_sep,
102    bind   => \&_bind_style,
103    irssi  => \&_irssi_style,
104    ini    => \&_parse_ini,
105    list   => \&_return_list,
106    yaml   => \&_yaml,
107    xml    => \&_parse_xml,
108);
109
110sub formats { return keys %Methods }
111
112=head1 METHODS
113
114=head2 $obj = Config::Auto->new( [source => $text|$fh|$filename, path => \@paths, format => FORMAT_NAME] );
115
116Returns a C<Config::Auto> object based on your configs source. This can either be:
117
118=over 4
119
120=item a filehandle
121
122Any opened filehandle, or C<IO::Handle>/C<IO::String> object.
123
124=item a plain text string
125
126Any plain string containing one or more newlines.
127
128=item a filename
129
130Any plain string pointing to a file on disk
131
132=item nothing
133
134A heuristic will be applied to find your config file, based on the name of
135your script; C<$0>.
136
137=back
138
139Although C<Config::Auto> is at its most magical when called with no parameters,
140its behavior can be controlled explicitly by using one or two arguments.
141
142If a filename is passed as the C<source> argument, the same paths are checked,
143but C<Config::Auto> will look for a file with the passed name instead of the
144C<$0>-based names.
145
146Supplying the C<path> parameter will add additional directories to the search
147paths. The current directory is searched first, then the paths specified with
148the path parameter. C<path> can either be a scalar or a reference to an array
149of paths to check.
150
151The C<format> parameters forces C<Config::Auto> to interpret the contents of
152the configuration file in the given format without trying to guess.
153
154=cut
155
156### generate accessors
157{   no strict 'refs';
158    for my $meth ( qw[format path source _fh _data _file _score _tmp_fh] ) {
159        *$meth = sub {
160            my $self        = shift;
161            $self->{$meth}  = shift if @_;
162            return $self->{$meth};
163        };
164    }
165}
166
167sub new {
168    my $class   = shift;
169    my %hash    = @_;
170    my $self    = bless {}, $class;
171
172    if( my $format = $hash{'format'} ) {
173
174        ### invalid format
175        croak "No such format '$format'" unless $Methods{$format};
176
177        $self->format( $format );
178    }
179
180    ### set the other values that could be passed
181    for my $key ( qw[source path] ) {
182        $self->$key( defined $hash{$key} ? $hash{$key} : '' );
183    }
184
185    return $self;
186}
187
188=head2 $rv = $obj->parse | Config::Auto::parse( [$text|$fh|$filename, path => \@paths, format => FORMAT_NAME] );
189
190Parses the source you provided in the C<new()> call and returns a data
191structure representing your configuration file.
192
193You can also call it in a procedural context (C<Config::Auto::parse()>), where
194the first argument is the source, and the following arguments are named. This
195function is provided for backwards compatiblity with releases prior to 0.29.
196
197=cut
198
199sub parse {
200    my $self = shift;
201
202    ### XXX todo: re-implement magic configuration file finding based on $0
203
204    ### procedural invocation, fix to OO
205    unless( UNIVERSAL::isa( $self, __PACKAGE__ ) ) {
206        $self = __PACKAGE__->new( source => $self, @_ )
207                    or croak( "Could not parse '$self' => @_" );
208    }
209
210    my $file = $self->file;
211    croak "No config file found!"           unless defined $file;
212    croak "Config file $file not readable!" unless -e $file;
213
214    ### from Toru Marumoto: Config-Auto return undef if -B $file
215    ### <21d48be50604271656n153e6db6m9b059f57548aaa32@mail.gmail.com>
216    # If a config file "$file" contains multibyte charactors like japanese,
217    # -B returns "true" in old version of perl such as 5.005_003. It seems
218    # there is no problem in perl 5.6x or newer.
219    ### so check -B and only return only if
220    unless( $self->format ) {
221        return if $self->file and -B $self->file and $] >= '5.006';
222
223        my $score = $self->score;
224
225        ### no perl?
226        delete $score->{perl} if exists $score->{perl} and $DisablePerl;
227
228        ### no formats found
229        croak "Unparsable file format!" unless keys %$score;
230
231        ### Clear winner?
232        {   my @methods = sort { $score->{$b} <=> $score->{$a} } keys %$score;
233            if (@methods > 1) {
234                croak "File format unclear! " .
235                    join ",", map { "$_ => $score->{$_}"} @methods
236                        if $score->{ $methods[0] } == $score->{ $methods[1] };
237            }
238            $self->format( $methods[0] );
239
240            $self->_debug( "Using the following format for parsing: " . $self->format );
241        }
242    }
243
244    return $Methods{ $self->format }->($self);
245}
246
247=head2 $href = $obj->score;
248
249Takes a look at the contents of your configuration data and produces a
250'score' determining which format it most likely contains.
251
252They keys are equal to formats as returned by the C<< Config::Auto->formats >>
253and their values are a score between 1 and 100. The format with the highest
254score will be used to parse your configuration data, unless you provided the
255C<format> option explicitly to the C<new()> method.
256
257=cut
258
259sub score {
260    my $self = shift;
261
262    return $self->_score if $self->_score;
263
264    my $data = $self->data;
265
266    return { xml  => 100 }  if $data->[0] =~ /^\s*<\?xml/;
267    return { perl => 100 }  if $data->[0] =~ /^#!.*perl/;
268    my %score;
269
270    for (@$data) {
271        ### it's almost definately YAML if the first line matches this
272        $score{yaml} += 20              if /(?:\#|%)    # a #YAML or %YAML
273                                            YAML
274                                            (?::|\s)    # a YAML: or YAML[space]
275                                        /x and $data->[0] eq $_;
276        $score{yaml} += 20              if /^---/ and $data->[0] eq $_;
277        $score{yaml} += 10              if /^\s+-\s\w+:\s\w+/;
278
279        # Easy to comment out foo=bar syntax
280        $score{equal}++                 if /^\s*#\s*\w+\s*=/;
281        next if /^\s*#/;
282
283        $score{xml}++                   for /(<\w+.*?>)/g;
284        $score{xml}+= 2                 for m|(</\w+.*?>)|g;
285        $score{xml}+= 5                 for m|(/>)|g;
286        next unless /\S/;
287
288        $score{equal}++, $score{ini}++  if m|^.*=.*$|;
289        $score{equal}++, $score{ini}++  if m|^\S+\s+=\s+|;
290        $score{colon}++                 if /^[^:]+:[^:=]+/;
291        $score{colon}+=2                if /^\s*\w+\s*:[^:]+$/;
292        $score{colonequal}+= 3          if /^\s*\w+\s*:=[^:]+$/; # Debian foo.
293        $score{perl}+= 10               if /^\s*\$\w+(\{.*?\})*\s*=.*/;
294        $score{space}++                 if m|^[^\s:]+\s+\S+$|;
295
296        # mtab, fstab, etc.
297        $score{space}++                 if m|^(\S+)\s+(\S+\s*)+|;
298        $score{bind}+= 5                if /\s*\S+\s*{$/;
299        $score{list}++                  if /^[\w\/\-\+]+$/;
300        $score{bind}+= 5                if /^\s*}\s*$/  and exists $score{bind};
301        $score{irssi}+= 5               if /^\s*};\s*$/ and exists $score{irssi};
302        $score{irssi}+= 10              if /(\s*|^)\w+\s*=\s*{/;
303        $score{perl}++                  if /\b([@%\$]\w+)/g;
304        $score{perl}+= 2                if /;\s*$/;
305        $score{perl}+=10                if /(if|for|while|until|unless)\s*\(/;
306        $score{perl}++                  for /([\{\}])/g;
307        $score{equal}++, $score{ini}++  if m|^\s*\w+\s*=.*$|;
308        $score{ini} += 10               if /^\s*\[[\s\w]+\]\s*$/;
309    }
310
311    # Choose between Win INI format and foo = bar
312    if (exists $score{ini}) {
313        no warnings 'uninitialized';
314        $score{ini} > $score{equal}
315            ? delete $score{equal}
316            : delete $score{ini};
317    }
318
319    # Some general sanity checks
320    if (exists $score{perl}) {
321        $score{perl} /= 2   unless ("@$data" =~ /;/) > 3 or $#$data < 3;
322        delete $score{perl} unless ("@$data" =~ /;/);
323        delete $score{perl} unless ("@$data" =~ /([\$\@\%]\w+)/);
324    }
325
326    if ( $score{equal} && $score{space} && $score{equal} == $score{space} ) {
327      $score{equal}++;
328    }
329
330    $self->_score( \%score );
331
332    return \%score;
333}
334
335=head2 $aref = $obj->data;
336
337Returns an array ref of your configuration data, split by newlines.
338
339=cut
340
341sub data {
342    my $self = shift;
343    return $self->_data if $self->_data;
344
345    my $src = $self->source;
346
347    ### filehandle
348    if( ref $src ) {
349        my @data = <$src>;
350        $self->_data( \@data );
351
352        seek $src, 0, 0; # reset position!
353
354    ### data
355    } elsif ( $src =~ /\n/ ) {
356        $self->_data( [ split $/, $src, -1 ] );
357
358    ### filename
359    } else {
360        my $fh = $self->fh;
361        my @data = <$fh>;
362        $self->_data( \@data );
363
364        seek $fh, 0, 0; # reset position!
365    }
366
367    return $self->_data;
368}
369
370=head2 $fh = $obj->fh;
371
372Returns a filehandle, opened for reading, containing your configuration
373data. This works even if you provided a plain text string or filename to
374parse.
375
376=cut
377
378sub fh {
379    my $self = shift;
380    return $self->_fh if $self->_fh;
381
382    my $src = $self->source;
383
384    ### filehandle
385    if( ref $src ) {
386        $self->_fh( $src );
387
388    ### data
389    } elsif ( $src =~ /\n/ ) {
390        require IO::String;
391
392        my $fh = IO::String->new;
393        print $fh $src;
394        $fh->setpos(0);
395
396        $self->_fh( $fh );
397
398    } else {
399        my $fh;
400        my $file = $self->file;
401
402        if( open $fh, $file ) {
403            $self->_fh( $fh );
404        } else {
405            $self->_debug( "Could not open '$file': $!" );
406            return;
407        }
408    }
409
410    return $self->_fh;
411}
412
413=head2 $filename = $obj->file;
414
415Returns a filename containing your configuration data. This works even
416if you provided a plaintext string or filehandle to parse. In that case,
417a temporary file will be written holding your configuration data.
418
419=cut
420
421sub file {
422    my $self = shift;
423    return $self->_file if $self->_file;
424
425    my $src = $self->source;
426
427    ### filehandle or datastream, no file attached =/
428    ### so write a temp file
429    if( ref $src or $src =~ /\n/ ) {
430
431        ### require only when needed
432        require File::Temp;
433
434        my $tmp = File::Temp->new;
435        $tmp->print( ref $src ? <$src> : $src );
436        $tmp->close;                    # write to disk
437
438        $self->_tmp_fh( $tmp );         # so it won't get destroyed
439        $self->_file( $tmp->filename );
440
441        seek $src, 0, 0 if ref $src;    # reset position!
442
443    } else {
444        my $file = $self->_find_file( $src, $self->path ) or return;
445
446        $self->_file( $file );
447    }
448
449    return $self->_file;
450}
451
452=head2 $str = $obj->as_string;
453
454Returns a string representation of your configuration data.
455
456=cut
457
458sub as_string {
459    my $self = shift;
460    my $data = $self->data;
461
462    return join $/, @$data;
463}
464
465sub _find_file {
466    my ($self, $file, $path) = @_;
467
468
469    ### moved here so they are only loaded when looking for a file
470    ### all to keep memory usage down.
471    {   require File::Spec::Functions;
472        File::Spec::Functions->import('catfile');
473
474        require File::Basename;
475        File::Basename->import(qw[dirname basename]);
476    }
477
478    my $bindir = dirname($0);
479    my $whoami = basename($0);
480
481    $whoami =~ s/\.(pl|t)$//;
482
483    my @filenames = $file ||
484                     ("${whoami}config", "${whoami}.config",
485                      "${whoami}rc",    ".${whoami}rc");
486
487    my $try;
488    for my $name (@filenames) {
489
490        return $name        if -e $name;
491        return $try         if ( $try = $self->_chkpaths($path, $name) ) and -e $try;
492        return $try         if -e ( $try = catfile($bindir,     $name) );
493        return $try         if $ENV{HOME} && -e ( $try = catfile($ENV{HOME},  $name) );
494        return "/etc/$name" if -e "/etc/$name";
495        return "/usr/local/etc/$name"
496                            if -e "/usr/local/etc/$name";
497    }
498
499    $self->_debug( "Could not find file for '". $self->source ."'" );
500
501    return;
502}
503
504sub _chkpaths {
505    my ($self, $paths, $filename) = @_;
506
507    ### no paths? no point in checking
508    return unless defined $paths;
509
510    my $file;
511    for my $path ( ref($paths) eq 'ARRAY' ? @$paths : $paths ) {
512        return $file if -e ($file = catfile($path, $filename));
513    }
514
515    return;
516}
517
518sub _eval_perl   {
519
520    my $self = shift;
521    my $str  = $self->as_string;
522
523    ($str) = $str =~ m/^(.*)$/s if $Untaint;
524
525    my $cfg = eval "$str";
526    croak __PACKAGE__ . " couldn't parse perl data: $@" if $@;
527    return $cfg;
528}
529
530sub _parse_xml   {
531    my $self = shift;
532
533    ### Check if XML::Simple is already loaded
534    unless ( exists $INC{'XML/Simple.pm'} ) {
535        ### make sure we give good diagnostics when XML::Simple is not
536        ### available, but required to parse a config
537        eval { require XML::Simple; XML::Simple->import; 1 };
538        croak "XML::Simple not available. Can not parse " .
539              $self->as_string . "\nError: $@\n" if $@;
540    }
541
542    return XML::Simple::XMLin( $self->as_string );
543}
544
545sub _parse_ini   {
546    my $self = shift;
547
548    ### Check if Config::IniFiles is already loaded
549    unless ( exists $INC{'Config/IniFiles.pm'} ) {
550        ### make sure we give good diagnostics when XML::Simple is not
551        ### available, but required to parse a config
552        eval { require Config::IniFiles; Config::IniFiles->import; 1 };
553        croak "Config::IniFiles not available. Can not parse " .
554              $self->as_string . "\nError: $@\n" if $@;
555    }
556
557    tie my %ini, 'Config::IniFiles', ( -file => $self->file );
558    return \%ini;
559}
560
561sub _return_list {
562    my $self = shift;
563
564    ### there shouldn't be any trailing newlines or empty entries here
565    return [ grep { length } map { chomp; $_ } @{ $self->data } ];
566}
567
568### Changed to YAML::Any which selects the fastest YAML parser available
569### (req YAML 0.67)
570sub _yaml {
571    my $self = shift;
572    require YAML::Any;
573
574    return YAML::Any::Load( $self->as_string );
575}
576
577sub _bind_style  { croak "BIND8-style config not supported in this release" }
578sub _irssi_style { croak "irssi-style config not supported in this release" }
579
580# BUG: These functions are too similar. How can they be unified?
581
582sub _colon_sep {
583    my $self = shift;
584    my $fh   = $self->fh;
585
586    my %config;
587    local $_;
588    while (<$fh>) {
589        next if /^\s*#/;
590        /^\s*(.*?)\s*:\s*(.*)/ or next;
591        my ($k, $v) = ($1, $2);
592        my @v;
593        if ($v =~ /:/) {
594            @v =  split /:/, $v;
595        } elsif ($v =~ /, /) {
596            @v = split /\s*,\s*/, $v;
597        } elsif ($v =~ / /) {
598            @v = split /\s+/, $v;
599        } elsif ($v =~ /,/) { # Order is important
600            @v = split /\s*,\s*/, $v;
601        } else {
602            @v = $v;
603        }
604        $self->_check_hash_and_assign(\%config, $k, @v);
605    }
606    return \%config;
607}
608
609sub _check_hash_and_assign {
610    my $self = shift;
611
612    my ($c, $k, @v) = @_;
613    if (exists $c->{$k} and !ref $c->{$k}) {
614        $c->{$k} = [$c->{$k}];
615    }
616
617    if (grep /=/, @v) { # Bugger, it's really a hash
618        for (@v) {
619            my ($subkey, $subvalue);
620
621            ### If the array element has an equal sign in it...
622            if (/(.*)=(.*)/) {
623                ($subkey, $subvalue) = ($1,$2);
624
625            ###...otherwise, if the array element does not contain an equals sign:
626            } else {
627                $subkey     = $_;
628                $subvalue   = 1;
629            }
630
631            if (exists $c->{$k} and ref $c->{$k} ne "HASH") {
632                # Can we find a hash in here?
633                my $h=undef;
634                for (@{$c->{$k}}) {
635                    last if ref ($h = $_) eq "hash";
636                }
637                if ($h) { $h->{$subkey} = $subvalue; }
638                else { push @{$c->{$k}}, { $subkey => $subvalue } }
639            } else {
640                $c->{$k}{$subkey} = $subvalue;
641            }
642        }
643    } elsif (@v == 1) {
644        if (exists $c->{$k}) {
645            if (ref $c->{$k} eq "HASH") { $c->{$k}{$v[0]} = 1; }
646            else {push @{$c->{$k}}, @v}
647        } else { $c->{$k} = $v[0]; }
648    } else {
649        if (exists $c->{$k}) {
650            if (ref $c->{$k} eq "HASH") { $c->{$k}{$_} = 1 for @v }
651            else {push @{$c->{$k}}, @v }
652        }
653        else { $c->{$k} = [@v]; }
654    }
655}
656
657{   ### only load Text::ParseWords once;
658    my $loaded_tp;
659
660    sub _equal_sep {
661        my $self = shift;
662        my $fh   = $self->fh;
663
664        my %config;
665        local $_;
666        while ( <$fh>) {
667            next if     /^\s*#/;
668            next unless /^\s*(.*?)\s*=\s*(.*?)\s*$/;
669
670            my ($k, $v) = ($1, $2);
671
672            ### multiple enries, but no shell tokens?
673            if ($v=~ /,/ and $v !~ /(["']).*?,.*?\1/) {
674                $config{$k} = [ split /\s*,\s*/, $v ];
675            } elsif ($v =~ /\s/) { # XXX: Foo = "Bar baz"
676
677                ### only load once
678                require Text::ParseWords unless $loaded_tp++;
679
680                $config{$k} = [ Text::ParseWords::shellwords($v) ];
681
682            } else {
683                $config{$k} = $v;
684            }
685        }
686
687        return \%config;
688    }
689
690    sub _space_sep {
691        my $self = shift;
692        my $fh   = $self->fh;
693
694        my %config;
695        local $_;
696        while (<$fh>) {
697            next if     /^\s*#/;
698            next unless /\s*(\S+)\s+(.*)/;
699            my ($k, $v) = ($1, $2);
700            my @v;
701
702            ### multiple enries, but no shell tokens?
703            if ($v=~ /,/ and $v !~ /(["']).*?,.*?\1/) {
704                @v = split /\s*,\s*/, $v;
705            } elsif ($v =~ /\s/) { # XXX: Foo = "Bar baz"
706
707                ### only load once
708                require Text::ParseWords unless $loaded_tp++;
709
710                @v = Text::ParseWords::shellwords($v);
711
712            } else {
713                @v = $v;
714            }
715            $self->_check_hash_and_assign(\%config, $k, @v);
716        }
717        return \%config;
718
719    }
720}
721sub _debug {
722    my $self = shift;
723    my $msg  = shift or return;
724
725    Carp::confess( __PACKAGE__ . $msg ) if $Debug;
726}
727
7281;
729
730
731__END__
732
733=head1 GLOBAL VARIABLES
734
735=head3 $DisablePerl
736
737Set this variable to true if you do not wish to C<eval> perl style configuration
738files.
739
740Default is C<false>
741
742=head3 $Untaint
743
744Set this variable to true if you automatically want to untaint values obtained
745from a perl style configuration. See L<perldoc perlsec> for details on tainting.
746
747Default is C<false>
748
749=head3 $Debug
750
751Set this variable to true to get extra debug information from C<Config::Auto>
752when finding and/or parsing config files fails.
753
754Default is C<false>
755
756=head1 HOW IT WORKS
757
758When you call C<< Config::Auto->new >> or C<Config::Auto::parse> with no
759arguments, we first look at C<$0> to determine the program's name. Let's
760assume that's C<snerk>. We look for the following files:
761
762    snerkconfig
763    ~/snerkconfig
764    /etc/snerkconfig
765    /usr/local/etc/snerkconfig
766
767    snerk.config
768    ~/snerk.config
769    /etc/snerk.config
770    /usr/local/etc/snerk.config
771
772    snerkrc
773    ~/snerkrc
774    /etc/snerkrc
775    /usr/local/etc/snerkrc
776
777    .snerkrc
778    ~/.snerkrc
779    /etc/.snerkrc
780    /usr/local/etc/.snerkrc
781
782Additional search paths can be specified with the C<path> option.
783
784We take the first one we find, and examine it to determine what format
785it's in. The algorithm used is a heuristic "which is a fancy way of
786saying that it doesn't work." (Mark Dominus.) We know about colon
787separated, space separated, equals separated, XML, Perl code, Windows
788INI, BIND9 and irssi style config files. If it chooses the wrong one,
789you can force it with the C<format> option.
790
791If you don't want it ever to detect and execute config files which are made
792up of Perl code, set C<$Config::Auto::DisablePerl = 1>.
793
794When using the perl format, your configuration file will be eval'd. This will
795cause taint errors. To avoid these warnings, set C<$Config::Auto::Untaint = 1>.
796This setting will not untaint the data in your configuration file and should only
797be used if you trust the source of the filename.
798
799Then the file is parsed and a data structure is returned. Since we're
800working magic, we have to do the best we can under the circumstances -
801"You rush a miracle man, you get rotten miracles." (Miracle Max) So
802there are no guarantees about the structure that's returned. If you have
803a fairly regular config file format, you'll get a regular data
804structure back. If your config file is confusing, so will the return
805structure be. Isn't life tragic?
806
807=head1 EXAMPLES
808
809Here's what we make of some common Unix config files:
810
811F</etc/resolv.conf>:
812
813    $VAR1 = {
814        'nameserver' => [ '163.1.2.1', '129.67.1.1', '129.67.1.180' ],
815        'search' => [ 'oucs.ox.ac.uk', 'ox.ac.uk' ]
816    };
817
818F</etc/passwd>:
819
820    $VAR1 = {
821        'root' => [ 'x', '0', '0', 'root', '/root', '/bin/bash' ],
822        ...
823    };
824
825F</etc/gpm.conf>:
826
827    $VAR1 = {
828        'append' => '""',
829        'responsiveness' => '',
830        'device' => '/dev/psaux',
831        'type' => 'ps2',
832        'repeat_type' => 'ms3'
833    };
834
835F</etc/nsswitch.conf>:
836
837    $VAR1 = {
838        'netgroup' => 'nis',
839        'passwd' => 'compat',
840        'hosts' => [ 'files', 'dns' ],
841        ...
842    };
843
844=cut
845
846=head1 MEMORY USAGE
847
848This module is as light as possible on memory, only using modules when they
849are absolutely needed for configuration file parsing.
850
851=head1 TROUBLESHOOTING
852
853=over 4
854
855=item When using a Perl config file, the configuration is borked
856
857Give C<Config::Auto> more hints (e.g., add #!/usr/bin/perl to beginning of
858file) or indicate the format in the C<new>/C<parse()> command.
859
860=back
861
862=head1 TODO
863
864BIND9 and irssi file format parsers currently don't exist. It would be
865good to add support for C<mutt> and C<vim> style C<set>-based RCs.
866
867=head1 BUG REPORTS
868
869Please report bugs or other issues to E<lt>bug-config-auto@rt.cpan.orgE<gt>.
870
871=head1 AUTHOR
872
873Versions 0.04 and higher of this module by Jos Boumans E<lt>kane@cpan.orgE<gt>.
874
875This module originally by Simon Cozens.
876
877=head1 COPYRIGHT
878
879This library is free software; you may redistribute and/or modify it
880under the same terms as Perl itself.
881
882=cut
883