#! /usr/bin/perl -w

##   dacodeconfig: configure daCode files before uploading to webserver
##
##   $Id: dacodeconfig,v 1.10.4.1 2001/12/18 08:12:30 netsabes Exp $
##
##   Copyright 2001 Denis Barbier, All Rights Reserved.
##   This program is free software; you can redistribute it and/or modify
##   it under the terms of the GNU General Public License as published by
##   the Free Software Foundation; either version 2 of the License, or
##   (at your option) any later version.
##
##   This program is distributed in the hope that it will be useful,
##   but WITHOUT ANY WARRANTY; without even the implied warranty of
##   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##   GNU General Public License for more details.

use Getopt::Long;
use File::Find;

use strict;

package DaCode::Config::Utils;

#
#   File utilities needed by DaCode::Config
#

sub copy {
        my ($from, $to) = @_;

        local($/) = undef;
        open(FROM, $from) || die "Cannot read \`$from'\n";
        my $content = <FROM>;
        close(FROM);
        open(TO, "> $to") || die "Cannot write \`$to'\n";
        print TO $content;
        close(TO);
}

sub mkdir {
        my ($dir) = shift;
        my ($mode) = 0755;

        my $path = '';
        foreach (split('/', $dir)) {
                -d $path.$_ || mkdir $path.$_, $mode || return 0;
                $path .= $_ . '/';
        }
        return 1;
}

package DaCode::Config::Options;

sub new {
        my $proto = shift;

        my $class = ref($proto) || $proto;
        my $self  = { 'opts' => {} };
        bless ($self, $class);
        return $self;
}

sub set {
        my ($this, $args) = @_;

        foreach (keys %$args) {
                $this->{opts}->{$_} = $args->{$_};
        }
}

sub verbose {
        my ($this, $txt) = @_;

        print STDERR $txt."\n" if $this->{opts}->{verbose};
}

package DaCode::Config::Actions;

@DaCode::Config::Actions::ISA = ("DaCode::Config::Options");

sub options {
        my ($this, $cfg, $actions) = @_;

        $this->{opts} = $cfg->{opts};
        $this->{opts}->{listactions} = $actions;
        foreach (split(/,/, $this->{opts}->{listactions})) {
                $this->{exec}->{$_} = 0;
        }
        foreach (split(/,/, $this->{opts}->{actions})) {
                $this->{exec}->{$_} = 1;
        }
}

sub execute {
        my ($this) = shift;

        foreach (split(/,/, $this->{opts}->{listactions})) {
                $this->$_() if $this->{exec}->{$_};
        }
}

sub create_dirs {
        my $this = shift;

        my $src         = $this->{opts}->{src};
        my $dest        = $this->{opts}->{dest};
        my $htdocs_dir  = $this->{opts}->{htdocs};
        my $phplib_dir  = $this->{opts}->{phplib};

        $this->verbose("Create target directories under \`$dest'");
        -d $dest || DaCode::Config::Utils::mkdir($dest) || die "Cannot create \`$dest'\n";
        _create_dirs($src.'/htdocs', $dest.'/'.$htdocs_dir);
        _create_dirs($src.'/phplib', $dest.'/'.$phplib_dir);
}

sub _create_dirs {
        my ($src, $dest) = @_;

        opendir(DIR, $src) || die "Cannot open \`$src'\n";
        my (@files) = readdir(DIR);
        closedir(DIR);
        foreach (@files) {
                next if $_ eq '.' || $_ eq '..' || $_ eq 'CVS';
                if (-d $src.'/'.$_) {
                        DaCode::Config::Utils::mkdir($dest.'/'.$_);
                        _create_dirs($src.'/'.$_, $dest.'/'.$_);
                }
        }
}

sub copy_files {
        my $this = shift;

        my $src         = $this->{opts}->{src};
        my $dest        = $this->{opts}->{dest};
        my $htdocs_dir  = $this->{opts}->{htdocs};
        my $phplib_dir  = $this->{opts}->{phplib};
        my $ext         = $this->{opts}->{suffix};

        $this->verbose("Copy .php3 files from \`src' to \`$dest' with \`$ext' suffix");
        _copy_files($src.'/htdocs', $dest.'/'.$htdocs_dir, $ext);
        _copy_files($src.'/phplib', $dest.'/'.$phplib_dir, $ext);

        $this->verbose("Copy other files from \`src' to \`$dest'");
        _copy_files($src.'/htdocs', $dest.'/'.$htdocs_dir, '');
        _copy_files($src.'/phplib', $dest.'/'.$phplib_dir, '');
}

sub _copy_files {
        my ($src, $dest, $ext) = @_;

        opendir(DIR, $src) || die "Cannot open \`$src'\n";
        my (@files) = readdir(DIR);
        closedir(DIR);
        foreach (@files) {
                next if $_ eq '.' || $_ eq '..' || $_ eq 'CVS' || $_ =~ m/^config\./;
                if (-d $src.'/'.$_) {
                        _copy_files($src.'/'.$_, $dest.'/'.$_, $ext);
                } elsif ($ext eq '' && $_ !~ m/\.php3$/) {
                        DaCode::Config::Utils::copy($src.'/'.$_, $dest.'/'.$_);
                } elsif ($ext ne '' && $_ =~ m/^(.*\.)php3$/) {
                        DaCode::Config::Utils::copy($src.'/'.$_, $dest.'/'.$1.$ext);
                }
        }
}

sub update_htdocs_dacode {
        my $this = shift;

        my $dest        = $this->{opts}->{dest};
        my $htdocs_dir  = $this->{opts}->{htdocs};
        my $phplib_dir  = $this->{opts}->{phplib};
        my $ext         = $this->{opts}->{suffix};

        $this->verbose("Updating \`$dest/$htdocs_dir/dacode.$ext'");
        open(IN, "< $dest/$htdocs_dir/dacode.$ext")
                || die "Unable to read \`$dest/$htdocs_dir/dacode.$ext'\n";
        my $txt = '';
        my $top2phplib = $phplib_dir;
        if ($htdocs_dir ne '.') {
                $top2phplib = $htdocs_dir;
                $top2phplib =~ s#[^/]+#..#g;
                $top2phplib .= '/'.$phplib_dir;
        }
        while (<IN>) {
                s/^(\s*\$php_ext\s*=\s*)(['"]).*\2;/$1$2$ext$2;/;
                s#^(\s*\$libdir\s*=\s*).*#$1\$topdir.'$top2phplib/';#;
                $txt .= $_;
        }
        close(IN);
        open(OUT, "> $dest/$htdocs_dir/dacode.$ext")
                || die "Unable to write \`$dest/$htdocs_dir/dacode.$ext'\n";
        print OUT $txt;
        close(OUT);
}

sub update_php_extension {
        my $this = shift;

        my $dest        = $this->{opts}->{dest};
        my $ext         = $this->{opts}->{suffix};

        $this->verbose("Update calls to \`dacode.$ext'");
        my $subst = sub {
                my ($ext, $file) = @_;

                open(IN, "< $file")
                        || die "Unable to read \`$File::Find::dir/$file'\n";
                my $txt = '';
                while (<IN>) {
                        s#(['"]/dacode\.)[^'"]*#$1$ext#;
                        s#(['"])\.\$config->php#$ext$1#g;
                        s#\.\$config->php#."$ext"#g;
                        $txt .= $_;
                }
                close(IN);
                open(OUT, "> $file")
                        || die "Unable to write \`$File::Find::dir/$file'\n";
                print OUT $txt;
                close(OUT);
        };
        my $phpfiles = sub {
                /\.$ext$/ && &$subst($ext, $_);
        };
        File::Find::find(\&$phpfiles, $dest);
}

sub inline_lecho {
        my $this = shift;

        my $dest        = $this->{opts}->{dest};
        my $phplib_dir  = $this->{opts}->{phplib};
        my $ext         = $this->{opts}->{suffix};
        my $lang        = $this->{opts}->{lang};

        $this->verbose("Inline calls to lecho()");
        #   Read lang.php3
        my (%lecho, $msg);
        {
                local($/) = undef;
                open(IN, "< $dest/$phplib_dir/lang.$ext")
                        || die "Unable to read \`$dest/$phplib_dir/lang.$ext'\n";
                my $l10n = <IN>;
                close(IN);
                if ($l10n =~ m/\$lang_en\s*=\s*array\s*\(\s*(.*?)\s*\);/s) {
                        #   daCode 1.0.x
                        my (%english, %curlang);
                        $msg = $1;
                        $msg =~ s/\\n/\\\\n/g;
                        $msg =~ s/\\"/\\\\\\"/g;
                        eval "\%english = ( $msg )";
                        if ($l10n !~ m/\$lang_$lang\s*=\s*array\s*\(\s*(.*?)\s*\);/s) {
                                print STDERR "Unable to determine translated strings\n";
                                return;
                        }
                        $msg = $1;
                        $msg =~ s/\\n/\\\\n/g;
                        $msg =~ s/\\"/\\\\\\"/g;
                        eval "\%curlang = ( $msg )";
                        %lecho = %curlang;
                        foreach (keys %english) {
                                $lecho{$english{$_}} = $curlang{$_};
                        }
                } elsif ($lang eq 'en' && $l10n =~ m/\$lang_en2fr\s*=\s*array\s*\(\s*(.*?)\s*\);/s) {
                        $msg = $1;
                        $msg =~ s/\\n/\\\\n/g;
                        $msg =~ s/\\"/\\\\\\"/g;
                        my %english;
                        eval "\%english = ( $msg )";
                        foreach (keys %english) {
                                $lecho{$_} = $_;
                        }
                } elsif ($l10n =~ m/\$lang_en2$lang\s*=\s*array\s*\(\s*(.*?)\s*\);/s) {
                        $msg = $1;
                        $msg =~ s/\\n/\\\\n/g;
                        $msg =~ s/\\"/\\\\\\"/g;
                        eval "\%lecho = ( $msg )";
                } else {
                        print STDERR "Unable to determine translated strings\n";
                        return;
                }
        }
        my $subst = sub {
                my ($ext, $file) = @_;
                my ($txt);

                open(IN, "< $file")
                        || die "Unable to read \`$File::Find::dir/$file'\n";
                $txt = '';
                while (my $line = <IN>) {
                        while ($line =~ s/^(.*?)lecho\s*\((['"])(.*?)\2\)//) {
                                $txt .= $1 . $2 . (defined($lecho{$3}) ?
                                        $lecho{$3} :
                                        $lecho{"This def doesn't exist in the lang table"}) . $2;
                        }
                        $txt .= $line;
                }
                close(IN);
                open(OUT, "> $file")
                        || die "Unable to write \`$File::Find::dir/$file'\n";
                print OUT $txt;
                close(OUT);
        };
        my $phpfiles = sub {
                /\.$ext$/ && &$subst($ext, $_);
        };
        File::Find::find(\&$phpfiles, $dest);
}

sub configure {
        my $this = shift;

        my $src         = $this->{opts}->{src};
        my $dest        = $this->{opts}->{dest};
        my $phplib_dir  = $this->{opts}->{phplib};
        my $ext         = $this->{opts}->{suffix};
        my $conffile    = $this->{opts}->{phpconf};

        $this->verbose("Re-creating config file $dest/$phplib_dir/config.$ext");
        #   Read config.site
        open(USERCONF, $conffile) || die "Unable to read \`$conffile'\n";
        open(SYSCONF, $src.'/phplib/config.sample')
                || die "Unable to read \`$src/phplib/config.sample'\n";

        #   Create destination directory
        -d $dest.'/'.$phplib_dir
                || DaCode::Config::Utils::mkdir($dest.'/'.$phplib_dir)
                || die "Cannot create \`$dest/$phplib_dir'\n";

        my ($userconf, $sysconf, $newconf);
        {
                local($/) = undef;
                $userconf = <USERCONF>;
                $sysconf = <SYSCONF>;
        }
        close(USERCONF);
        close(SYSCONF);

        #   Latest definitions must be protected, otherwise variable
        #   substituion will not work (e.g. cachedir)
        my $sysconf_bot = '';
        if ($sysconf =~ s/(PART 5 : Internal values.*)//s) {
                $sysconf_bot = $1;
        }

        $sysconf =~ s/"\.\$this->php/$ext"/g;
        while ($userconf =~ m/\$this->([^=]+?)\s*=\s*(
                (?:['"]|array\s*\( # )
                ) #(
                .*?['")]|\d+)\s*;/sgx) {
                my ($label, $value) = ($1, $2);
                $sysconf =~ s/(\n\s*\$this->$label\s*=\s*)
                        (?:(?:['"]|array\s*\( # )
                        ) #(
                        .*?['")]|\d+)\s*;/$1$value;/sgx;
        }

        $newconf = $sysconf.$sysconf_bot;
        open(OUT, "> $dest/$phplib_dir/config.$ext")
                        || die "Unable to write \`$dest/$phplib_dir/config.$ext'\n";
        print OUT $newconf;
        close(OUT);
}

sub instance_ref {
        my $this = shift;

        my $dest        = $this->{opts}->{dest};
        my $ext         = $this->{opts}->{suffix};
        my $phplib_dir  = $this->{opts}->{phplib};

        $this->verbose("Make instantiation by reference");
        my $subst = sub {
                my ($file) = @_;

                local($/) = undef;
                open(IN, "< $file")
                        || die "Unable to read \`$File::Find::dir/$file'\n";
                my $txt = <IN>;
                close(IN);
                $txt =~ s/=\s*LoadClass/=& LoadClass/g;
                open(OUT, "> $file")
                        || die "Unable to write \`$File::Find::dir/$file'\n";
                print OUT $txt;
                close(OUT);
        };
        my $phpfiles = sub {
                /\.$ext$/ && &$subst($_);
        };
        File::Find::find(\&$phpfiles, $dest);

        #  And update phplib/libdacode.php3
        local($/) = undef;
        open(IN, "< $dest/$phplib_dir/libdacode.$ext")
                || die "Unable to read \`$dest/$phplib_dir/libdacode.$ext'\n";
        my $txt = <IN>;
        close(IN);
        $txt =~ s/^(\s*Function\s+)(LoadClass)/$1&$2/m;
        open(OUT, "> $dest/$phplib_dir/libdacode.$ext")
                || die "Unable to write \`$dest/$phplib_dir/libdacode.$ext'\n";
        print OUT $txt;
        close(OUT);
}

sub instance_copy {
        my $this = shift;

        my $dest        = $this->{opts}->{dest};
        my $ext         = $this->{opts}->{suffix};
        my $phplib_dir  = $this->{opts}->{phplib};

        $this->verbose("Make instantiation by copy");
        my $subst = sub {
                my ($file) = @_;

                local($/) = undef;
                open(IN, "< $file")
                        || die "Unable to read \`$File::Find::dir/$file'\n";
                my $txt = <IN>;
                close(IN);
                $txt =~ s/=&\s*LoadClass/= LoadClass/g;
                open(OUT, "> $file")
                        || die "Unable to write \`$File::Find::dir/$file'\n";
                print OUT $txt;
                close(OUT);
        };
        my $phpfiles = sub {
                /\.$ext$/ && &$subst($_);
        };
        File::Find::find(\&$phpfiles, $dest);

        #  And update phplib/libdacode.php3
        local($/) = undef;
        open(IN, "< $dest/$phplib_dir/libdacode.$ext")
                || die "Unable to read \`$dest/$phplib_dir/libdacode.$ext'\n";
        my $txt = <IN>;
        close(IN);
        $txt =~ s/^(\s*Function\s+)&(LoadClass)/$1$2/m;
        open(OUT, "> $dest/$phplib_dir/libdacode.$ext")
                || die "Unable to write \`$dest/$phplib_dir/libdacode.$ext'\n";
        print OUT $txt;
        close(OUT);
}

package main;
use vars qw(
        $opt_C $opt_D $opt_H $opt_P $opt_S
        $opt_a $opt_c $opt_l $opt_n $opt_s $opt_h $opt_v
        $default_actions $all_actions $cfg $actions $temp
        @ARGVSAVE
);

sub usage {
        print STDERR "Usage: $0 [options]
  -h, --help            display this usage summary
  -v, --verbose         display some messages when processing
  -S, --source          source directory where PHP files reside (default: src)
  -D, --destination     destination directory (default: build)
  -H, --htdocs          subdirectory for PHP3 pages (default: htdocs)
  -P, --phplib          subdirectory for PHP3 library files (default: phplib)
  -s, --suffix          PHP extension (default: php3)
  -l, --language        choose a language (default: en)  
  -a, --actions         specify which actions to perform (default: all)  
  -C, --phpconf         user-defined configuration file for daCode
                        (default: config.site)
  -c, --config-file     dacodeconfig options file
                        (default: /etc/dacodeconfig.conf)
  -n, --no-conffile     ignore all dacodeconfig config files
\n";
        exit(0);
}

####
#   Process command-line options
#   Defaults
####

$default_actions = join(',', qw(
        create_dirs copy_files update_htdocs_dacode
        update_php_extension inline_lecho configure
));
$all_actions = join(',', qw(
        create_dirs copy_files update_htdocs_dacode
        update_php_extension inline_lecho configure
        instance_ref instance_copy
));

$opt_C = 'config.site';
$opt_S = 'src';
$opt_D = 'build';
$opt_H = 'htdocs';
$opt_P = 'phplib';
$opt_c = '/etc/dacodeconfig.conf';
$opt_l = 'en';
$opt_s = 'php3';
$opt_a = '';
$opt_h = $opt_n = $opt_v = 0;

sub process_options {
        $Getopt::Long::ignorecase = 0;
        if (not Getopt::Long::GetOptions(
                'C|phpconf=s',
                'D|destination=s',
                'H|htdocs=s',
                'P|phplib=s',
                'S|source=s',
                's|suffix=s',
                'l|language=s',
                'c|config-file=s',
                'a|actions=s',
                'n|no-conffile',
                'v|verbose',
                'h|help'
        )) {
                print STDERR "Try \`$0 --help' for more information.\n";
                exit(0);
        }
        $opt_a =~ s/[^a-z,+-]/_/g;
}

sub parse_rcfile {
        my $file = shift;

        -f $file || return;
        my $verbose;
        eval "\$verbose = sub { my \$txt = shift; print STDERR \$txt.\"\\n\" if $main::opt_v}";
        &$verbose("Reading config file: $file");
        open(CFG, $file) || return;
        while (my $line = <CFG>) {
                next if $line !~ m/^[A-Z]/;
                if ($line =~ m/^VERBOSE\s*=\s*(\S+)/) {
                        $opt_v = ($1 =~ m/yes|true|1/i ? 1 : 0);
                        &$verbose("  VERBOSE: $opt_v");
                } elsif ($line =~ m/^PHPCONF\s*=\s*(\S+)/) {
                        $opt_C = $1;
                        &$verbose("  PHPCONF: $opt_C");
                } elsif ($line =~ m/^DESTINATION\s*=\s*(\S+)/) {
                        $opt_D = $1;
                        &$verbose("  DESTINATION: $opt_D");
                } elsif ($line =~ m/^HTDOCS\s*=\s*(\S+)/) {
                        $opt_H = $1;
                        &$verbose("  HTDOCS: $opt_H");
                } elsif ($line =~ m/^PHPLIB\s*=\s*(\S+)/) {
                        $opt_P = $1;
                        &$verbose("  PHPLIB: $opt_P");
                } elsif ($line =~ m/^SOURCE\s*=\s*(\S+)/) {
                        $opt_S = $1;
                        &$verbose("  SOURCE: $opt_D");
                } elsif ($line =~ m/^LANGUAGE\s*=\s*(\S+)/) {
                        $opt_l = $1;
                        &$verbose("  LANGUAGE: $opt_l");
                } elsif ($line =~ m/^SUFFIX\s*=\s*(\S+)/) {
                        $opt_s = $1;
                        &$verbose("  SUFFIX: $opt_s");
                } elsif ($line =~ m/^ACTIONS\s*=\s*(\S+)/) {
                        $opt_a = $1;
                        &$verbose("  ACTIONS: $opt_a");
                }
        }
        close(CFG);
}

@ARGVSAVE = @ARGV;
#   First pass to catch -n and -c flag
main::process_options();

if (!$opt_n) {
        #   Initialize system-wide settings
        main::parse_rcfile($opt_c);

        #   ... config file in $HOME
        main::parse_rcfile($ENV{HOME}.'/.dacode.conf');

        #   ... in current working directory
        main::parse_rcfile('.dacode.conf');

        #   ... and parse again command-line options to override
        #   previous settings
        @ARGV = @ARGVSAVE;
        main::process_options();
}

if ($opt_h) {
        usage;
        exit(0);
}

die "Suffix must begin with the 3 letters \`php'!\n" if $opt_s !~ /^php/;

$cfg = new DaCode::Config::Options;

if ($opt_a eq '') {
        $opt_a = $default_actions;
} elsif ($opt_a eq 'all') {
        $opt_a = $all_actions;
} elsif ($opt_a =~ s/^\+//) {
        $opt_a = $default_actions . ','. $opt_a;
} elsif ($opt_a =~ s/^\-//) {
        $temp = ',' . $default_actions . ',';
        foreach (split (/,/, $opt_a)) {
                $temp =~ s/,$_,/,/g;
        }
        $temp =~ s/^,(.*),$/$1/;
        $opt_a = $temp;
}

#    Store options
$cfg->set({
        'phpconf'       => $opt_C,
        'dest'          => $opt_D,
        'src'           => $opt_S,
        'htdocs'        => $opt_H,
        'phplib'        => $opt_P,
        'lang'          => $opt_l,
        'suffix'        => $opt_s,
        'actions'       => $opt_a,
        'verbose'       => $opt_v
});

$actions = new DaCode::Config::Actions;
$actions->options($cfg, $all_actions);
$actions->execute();

##EOF##
__END__

=head1 NAME

dacodeconfig - prepare daCode files before uploading to webserver

=head1 VERSION

0.5.1

=head1 SYNOPSIS

B<dacodeconfig>
[B<-C> I<FILE>]
[B<-S> I<DIR>]
[B<-D> I<DIR>]
[B<-H> I<DIR>]
[B<-P> I<DIR>]
[B<-s> I<STRING>]
[B<-l> I<STRING>]
[B<-a> I<STRING>]
[B<-c> I<FILE>]
[B<-n>]
[B<-h>]
[B<-v>]

=head1 OPTIONS

=over

=item B<-h>, B<--help>

Display options sumary and exit.

=item B<-v>, B<--verbose>

Prints some useless messages.

=item B<-C>, B<--phpconf=>I<FILE>

Specify a file where daCode site options are stored.  This file is
merged with C<src/phplib/config.sample> to obtain a C<config.php3>
dedicated to this application.  B<Warning>: this is not a configuration file for
C<dacodeconfig>.

=item B<-S>, B<--source=>I<DIR>

Set source directory where PHP3 files reside (may be a relative or
absolute path).
Default: C<src>

=item B<-D>, B<--destination=>I<DIR>

Set build directory.
Default: C<build>

=item B<-H>, B<--htdocs=>I<DIR>

Specify a subdirectory of the destination directory containing the
daCode document root.
Default: C<htdocs>

=item B<-P>, B<--phplib=>I<DIR>

Specify a subdirectory of the destination directory containing the
daCode PHP class files. This may or not be a subdirectory of C<htdocs>.
Default: C<phplib>

=item B<-s>, B<--suffix=>I<STRING>

Suffix (without dot) of PHP files.
Default: php3

=item B<-l>, B<--language=>I<STRING>

Site language (currently only C<en> and C<fr> are available).
Default: C<en>

=item B<-a>, B<--actions=>I<STRING>

Comma separated list of actions to perform.  If prefixed by C<+>, add
actions to default.  If prefixed by C<->, remove actions from default.
Default: C<create_dirs,copy_files,update_htdocs_dacode,update_php_extension,inline_lecho,configure>

=item B<-c>, B<--config-file=>I<FILE>

Set system-wide configuration file.
Default: C</etc/dacodeconfig.conf>

=item B<-n>, B<--no-conffile>

Do not load any configuration files.

=back

=head1 ACTIONS

Here is a list of actions which can be executed through the B<-a> flag.

=over 4

=item create_dirs

Create a shadow directory tree under B<DESTINATION>.

=item copy_files

Copy all php3 files to B<DESTINATION> and change their suffix according
to the B<-s> flag.

=item update_htdocs_dacode

Update the F<B<DESTINATION>/htdocs/dacode.php3> file (or with another
suffix if B<-s> flag is used) to reflect changes in directory names.

=item update_php_extension

In all PHP files, replace C<$config-E<gt>php> by extension set with the
B<-s> flag.

=item inline_lecho

In all PHP files, replace calls to C<lecho> by message in current
locales.

=item configure

Merge F<config.site> and F<src/phplib/config.php3> files.

=item instance_ref

Objects are assigned by reference to save memory (does not work witl all
PHP versions).

=item instance_copy

Objects are copied (default).

=back

=head1 FILES

These options might also be set within configuration files, to save
keystrokes.  Their syntax is straightforward: files are parsed from top
to bottom, one statement per line, each statement consists of a keyword
composed of uppercase letters, followed by an equal sign and its value.
Known keywords are

     VERBOSE PHPCONF SOURCE DESTINATION
     HTDOCS PHPLIB LANGUAGE SUFFIX ACTIONS

Lines not following this scheme are silently ignored.

=over

=item C</etc/dacodeconfig.conf>

System-wide configuration file

=item C<~/.dacode.conf>

User configuration file

=item C<./.dacode.conf>

Configuration file specific to one application

=back

=head1 AUTHOR

Denis Barbier
barbier@linuxfr.org

=cut
