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