#! /bin/sh
#
# My Own Building System main script.
# $Revision: 69 $
#
#   Copyright (C) 2005,2006 Rau'l Nu'n~ez de Arenas Coronado
#   Report bugs to DervishD <bugs@dervishd.net>
#
#       This program is free software; you can redistribute it and/or
#        modify it under the terms of the GNU General Public License
#          version 2 as published by the Free Software Foundation.
#
#      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.
#
#     You should have received a copy of the GNU General Public License
#            ('GPL') along with this program; if not, write to:
#
#                      Free Software Foundation, Inc.
#                        59 Temple Place, Suite 330
#                        Boston, MA 02111-1307  USA
################
# Some variables we need for proper functioning
export LC_ALL=C
export LANG=C
export LANGUAGE=C
COPYRIGHT="Copyright (C) 2005,2006 Rau'l Nu'n~ez de Arenas Coronado"

# This is for fixing non SUSv3 behaviour on some shells
eval ${ZSH_VERSION:+emulate sh; export NULLCMD=":"}
eval ${BASH_VERSION:+set -o posix}

# Ensure we are on the proper directory.
cd "`dirname $0`"

# Test if we can write to the current directory.
#   NOTE: It doesn't matter if this test passes, we must check for errors
# every time we create a file because the current directory can go write
# protect between now and the moment of file creation. This test exists to
# allow us to spot a readonly directory ASAP.
[ -w . ] || {
    printf -- "*** Cannot write to current directory, what's up?\n"
    exit 1
}


# Set up the log file.

#   NOTE: the file is rm'd before creation because otherwise the redirection
# used to create the file can fail even on a writeable directory if the file
# happens to be read-only! The same applies to the write test: the file may
# have been correctly created because we have write permission on the current
# directory, but the umask may be set to a weird value, so the newly created
# file may be read-only. It is weird, but it is the safest way I can think of.
zero_tmp="0.log"
(rm -f "$zero_tmp" && :> "$zero_tmp") 2> /dev/null || {
    printf -- "*** Cannot create logfile '%s'.\n" "$zero_tmp"
    (exit 1); exit 1
}

(:> "$zero_tmp") 2> /dev/null || {
    printf -- "*** Cannot write to logfile '%s'.\n" "$zero_tmp"
    (exit 1); exit 1
}

# From now on, stderr will be redirected to the file "0.log"
exec 2> "$zero_tmp"
zero_tmp=

printf -- "=L { logfile [%s]\n" "$(date +"%Y-%m-%d %H:%M:%S")" >&2

# Clean if we exit with nonzero return code
# NOTE: when we do "exit N" this trap is called, and "$?" is set to the exit
# status of the last command run before the trap is called. Unfortunately, the
# SUS standard doesn't make clear if, when we do "exit N", the last command is
# the "exit" itself or the last command *before* the "exit". So, we don't know
# if "$?" will be "N" if we do "exit N"! It may be 0, for example, if we print
# something just before exiting. So, we have to do a little trick. Instead of
# just doing "exit N" in our script, we are going to do "(exit N); exit N".
# The first "exit" will run in a subshell and will set "$?" to "N", no matter
# how the shell sets "$?" when entering the trap, and the second exit will
# invoke the trap with the correct value. This is taken from "GNU autoconf"
# code. I don't know the author of this idea, sorry :(
#
# In addition to this, we set up multiple identical traps because not all
# shells out there will run the EXIT trap within other traps...
for zero_signal in EXIT HUP INT PIPE QUIT TERM
do
    printf -- "=L Setting up '%s' trap.\n" "$zero_signal" >&2
    trap '
        zero_tmp=$?
        printf -- "=L Trapped '"'SIG%s'"'...\n" '"$zero_signal"' >&2
        [ '"$zero_signal"' != EXIT ] || [ $zero_tmp -ne 0 ] && {
            printf -- "=L Cleaning up.\n" >&2
            rm -f Makefile config.mk > /dev/null 2>&1
            rm -f config.h > /dev/null 2>&1
            printf -- "=L Done cleaning, exiting now.\n" >&2
            printf "=L } Bye...\n" >&2
            (exit 1); exit 1
        }
        printf "=L } Bye...\n" >&2
        (exit 0); exit 0
    ' $zero_signal
done
printf -- "=L No more signal traps.\n" >&2

#   First of all, check whether '0.conf' and 'Makefile.in' exist.
[ -r "0.conf" ] || {
    printf -- "*** '0.conf' doesn't exist. You must create one.\n"
    printf -- "=E Missing or not readable '0.conf'.\n" >&2
    (exit 1); exit 1
}
printf -- "=L '0.conf' exists and is readable.\n" >&2

[ -r "Makefile.in" ] || {
    printf -- "*** 'Makefile.in' doesn't exist. You must create one.\n"
    printf -- "=E Missing or not readable 'Makefile.in'.\n" >&2
    (exit 1); exit 1
}
printf -- "=L 'Makefile.in' exists and is readable.\n" >&2

#   Now read and validate '0.conf'. This means that if the file
# contents are invalid, not even '--help' or '--version' will work,
# but this is harmless since the end user should *NOT* receive a
# project whose '0.conf' has flaws.
#
#   In addition to this, processing '0.conf' at the very beginning of
# this script gives the opportunity of showing more information in
# '--help', for example.

# Read project name, version, author identity and hook name from '0.conf'.
# NOTE: '0' picks the FIRST ocurrence of the tags...
zero_project="`sed -ne '
/^PROJECT/ {
    s/[[:cntrl:]]/ /g
    s/^PROJECT[[:space:]]\+\(.*\)$/\1/
    s/[[:space:]]*$//p
    q
}' 0.conf`"
printf -- "=L Got project name '%s'.\n" "$zero_project" >&2

zero_version="`sed -ne '
/^VERSION/ {
    s/[[:cntrl:]]/ /g
    s/^VERSION[[:space:]]\+\(.*\)$/\1/
    s/[[:space:]]*$//p
    q
}' 0.conf`"
printf -- "=L Got version code '%s'.\n" "$zero_version" >&2

zero_author="`sed -ne '
/^AUTHOR/ {
    s/[[:cntrl:]]/ /g
    s/^AUTHOR[[:space:]]\+\(.*\)$/\1/
    s/[\\]"/"/g
    s/"/\\\\"/g
    s/[[:space:]]*$//p
    q
}' 0.conf`"
printf -- "=L Got author identity '%s'.\n" "$zero_author" >&2

zero_hook="`sed -ne '
/^HOOK/ {
    s/[[:cntrl:]]/ /g
    s/^HOOK[[:space:]]\+\(.*\)$/\1/
    s/[[:space:]]*$//p
    q
}' 0.conf`"
printf -- "=L Got hook name '%s'.\n" "$zero_hook" >&2

printf -- "=L Validating project metadata.\n" >&2
#   NOTE: The validation for the AUTHOR tag is... picky. If we validate
# using the C locale, then the author won't be able to use any local
# characters, but since we don't know which locale is being used in
# the end user environment, we cannot use a locale different from the
# 'C' locale! So we won't do any validation and expect AUTHOR to be a
# properly quoted valid C string literal.

# Validate the project name.
[ -z "$zero_project" ] && {
    printf -- "*** Project name cannot be empty.\n"
    printf -- "Check '0.conf'!\n"
    printf -- "=E Empty project name.\n" >&2
    (exit 1); exit 1
}
zero_tmp="`expr "x$zero_project" : "x[[:alnum:]][-_.[:alnum:]]*"`"
[ $zero_tmp -le ${#zero_project} ] && {
    printf -- "*** Invalid character '%c' in project name '%s'.\n"\
        "`expr "x$zero_project" : ".\{$zero_tmp\}\(.\)"`"\
        "$zero_project"
cat << EOF
    Check '0.conf': valid project names must start with an alphanumeric
character, followed by any combination of alphanumeric characters, dots,
underscores and hyphens.
EOF
    printf -- "=E Invalid project name '%s'.\n" "$zero_project" >&2
    (exit 1); exit 1
}
printf -- "=L Valid project name '%s'.\n" "$zero_project" >&2


# Validate the project version.
[ -z "$zero_version" ] && {
    printf -- "*** Project version code cannot be empty.\n"
    printf -- "Check '0.conf'!\n"
    printf -- "=E Empty version code.\n" >&2
    (exit 1); exit 1
}
zero_tmp="`expr "x$zero_version" : "x[0-9][-_.[:alnum:]]*"`"
[ $zero_tmp -le ${#zero_version} ] && {
    printf -- "*** Invalid character '%c' in version code '%s'.\n"\
        "`expr "x$zero_version" : ".\{$zero_tmp\}\(.\)"`"\
        "$zero_version"
cat << EOF
    Check '0.conf': valid version codes are almost free form. They must start
with a digit because IMHO they should carry at least a little bit of numeric
information, but the rest can be any combination of alphanumeric characters,
underscores, hyphens and dots.
EOF
    printf -- "=E Invalid version code '%s'.\n" "$zero_version" >&2
    (exit 1); exit 1
}
printf -- "=L Valid version code '%s'.\n" "$zero_version" >&2


# Validate the hook name.
zero_tmp="`expr "x$zero_hook" : "x[[:alnum:]]\+\.\{0,1\}[[:alnum:]]\+"`"
[ "$zero_hook" ] && [ $zero_tmp -le ${#zero_hook} ] && {
    printf -- "*** Invalid character '%c' in hook name '%s'.\n"\
        "`expr "x$zero_hook" : ".\{$zero_tmp\}\(.\)"`"\
        "$zero_hook"
cat << EOF
    Check '0.conf': valid hook names are a bit more restrictive than the
previous elements, because they must be valid file names. They must consist
only on alphanumeric characters, optionally followed by a dot and a suffix,
being the suffix alphanumeric too. And I mean at most ONE dot and at most ONE
suffix ;)))) (Keep the suffix short...)
EOF
    printf -- "=E Invalid hook name '%s'.\n" "$zero_hook" >&2
    (exit 1); exit 1
}
printf -- "=L Valid hook name '%s'.\n" "${zero_hook:-(empty)}" >&2


# Build a list of valid features, if any
zero_vfeatures="`sed -ne '
/^FEATURE/{
    s/[[:cntrl:]]/ /g
    s/^FEATURE[[:space:]]\+\([^[:space:]]\+\)\([[:space:]]\+.*\)\{0,1\}/\1/p
}' 0.conf`"
zero_tmp="`printf -- "%s\n%s" "$zero_vfeatures" | sort | uniq -d`"
[ -z $zero_tmp ] || {
    printf -- "*** Repeated feature name '%s'.\n" "$zero_tmp"
cat << EOF
    Check '0.conf': feature names cannot be repeated. Repeated feature
names usually hide subtle typographical bugs, or copy/paste problems.
EOF
    printf -- "=E Repeated feature name '%s'.\n" "$zero_tmp" >&2
    (exit 1); exit 1
}
for zero_feature in $zero_vfeatures
do
    [ "$zero_feature" = "debug" ] && {
        printf -- "*** Reserved feature name 'debug' used.\n"
cat << EOF
    Check '0.conf': 'debug' is a reserved feature name and cannot be used.
EOF
        printf -- "=E Reserved feature name 'debug' used.\n" >&2
        (exit 1); exit 1
    }
    zero_tmp="`expr "x$zero_feature" : "x[a-z][_a-z0-9]*"`"
    [ $zero_tmp -le ${#zero_feature} ] && {
        [ $zero_tmp -eq 0 ] && zero_tmp=1
        printf -- "*** Invalid character '%c' in feature name '%s'.\n"\
                  "`expr "x$zero_feature" : ".\{$zero_tmp\}\(.\)"`"\
                  "$zero_feature"
cat << EOF
    Check '0.conf': valid feature names must be lowercase, start with an
alphabetic character, followed by any combination of alphanumeric chars
and underscores and at most 20 chars long.
EOF
        printf -- "=E Invalid feature name '%s'.\n" "$zero_feature" >&2
        (exit 1); exit 1
    }
    [ ${#zero_feature} -gt 20 ] && {
        printf -- "*** Feature name '%s' is too long.\n" "$zero_feature"
cat << EOF
    Check '0.conf': valid feature names must be at most 20 chars long.
EOF
        printf -- "=E Feature name '%s' is too long.\n" "$zero_feature" >&2
        (exit 1); exit 1
    }
    printf -- "=L Valid feature name '%s'.\n" "$zero_feature" >&2
done

# Build a list of valid parameters, if any
zero_vparams="`sed -ne '
/^PARAM/{
    s/[[:cntrl:]]/ /g
    s/^PARAM[[:space:]]\+\([^[:space:]]\+\)\([[:space:]]\+.*\)\{0,1\}/\1/p
}' 0.conf`"
zero_tmp="`printf -- "%s\n%s" "$zero_vparams" | sort | uniq -d`"
[ -z $zero_tmp ] || {
    printf -- "*** Repeated parameter name '%s'.\n" "$zero_tmp"
cat << EOF
    Check '0.conf': parameter names cannot be repeated. Repeated parameter
names usually hide subtle typographical bugs, or copy/paste problems.
EOF
    printf -- "=E Repeated parameter name '%s'.\n" "$zero_tmp" >&2
    (exit 1); exit 1
}
for zero_param in $zero_vparams
do
    zero_tmp="`expr "x$zero_param" : "x[a-z][_a-z0-9]*"`"
    [ $zero_tmp -le ${#zero_param} ] && {
        [ $zero_tmp -eq 0 ] && zero_tmp=1
        printf -- "*** Invalid character '%c' in parameter name '%s'.\n"\
                  "`expr "x$zero_param" : ".\{$zero_tmp\}\(.\)"`"\
                  "$zero_param"
cat << EOF
    Check '0.conf': valid parameter names must be lowercase, start with an
alphabetic character, followed by any combination of alphanumeric chars and
underscores and at most 20 chars long.
EOF
        (exit 1); exit 1
    }
    [ ${#zero_param} -gt 20 ] && {
        printf -- "*** Parameter name '%s' is too long.\n" "$zero_param"
cat << EOF
    Check '0.conf': valid parameter names must be at most 20 chars long.
EOF
        printf -- "=E Parameter name '%s' is too long.\n" "$zero_feature" >&2
        (exit 1); exit 1
    }
    printf -- "=L Valid parameter name '%s'.\n" "$zero_param" >&2
done


# Check for 'special' parameters '--help' and '--version'.
for zero_parameter
do
    [ "x$zero_parameter" = "x--help" ] && {
        cat << EOF
This script configures '${zero_project}'

Usage: $0 [OPTION]... | --help | --version

  --help                Shows this help and exits.
  --version             Shows version and exits.

OPTIONs are:
  --prefix=PREFIX       Installation prefix is "PREFIX".
  --bindir=DIRECTORY    Place user binaries in "DIRECTORY".
  --sbindir=DIRECTORY   Place system binaries in "DIRECTORY".
  --xbindir=DIRECTORY   Place program binaries in "DIRECTORY".
  --confdir=DIRECTOR    Place configuration files in "DIRECTORY".
  --datadir=DIRECTORY   Place static data files in "DIRECTORY".
  --infodir=DIRECTORY   Place TeXinfo files in "DIRECTORY".
  --mandir=DIRECTORY    Place manpages in "DIRECTORY".
  --docdir=DIRECTORY    Place misc documentation in "DIRECTORY".
  --libdir=DIRECTORY    Place libraries in "DIRECTORY".
  --incdir=DIRECTORY    Place header files in "DIRECTORY".

  --enable-FEATURE      Enable package feature "FEATURE".
  --disable-FEATURE     Disable package feature "FEATURE".
  --with-PARAM=VALUE    Set package parameter "PARAM" to "VALUE".
EOF

        printf -- "\n"
        printf -- "Valid FEATURE's for '%s' are:\n" "$zero_project"
        for zero_feature in debug $zero_vfeatures
        do
            zero_tmp=""
            if [ "$zero_feature" = "debug" ]
            then zero_tmp="Enable or disable debugging support."
            else zero_tmp="`sed -ne '
                s/[[:cntrl:]]/ /g
                /^FEATURE[[:space:]]\+'"$zero_feature"'/ {
                    s/^FEATURE[[:space:]]\+//
                    s/^'"$zero_feature"'[[:space:]]*//
                    p;q
                }' 0.conf`"
            fi
            if [ -z $COLUMNS -o $COLUMNS -le 23 ]
            then
                printf -- "  %-22s%s\n" "$zero_feature" "$zero_tmp"
            else
                printf -- "%s\n" "$zero_tmp" |\
                fold -w $(($COLUMNS-23)) -s  |\
                while read line
                do
                    printf -- "  %-22s%.$(($COLUMNS-23))s\n"\
                        "$zero_feature"\
                        "$line"
                    zero_feature=" "
                done
            fi
        done
    
        [ ! -z "$zero_vparams" ] && {
            printf -- "\n"
            printf -- "Valid PARAM's for '%s' are:\n" "$zero_project"
            for zero_param in $zero_vparams
            do
                zero_tmp="`sed -ne '
                    s/[[:cntrl:]]/ /g
                    /^PARAM[[:space:]]\+'${zero_param}'/ {
                        s/^PARAM[[:space:]]\+//
                        s/^'${zero_param}'[[:space:]]*//
                        p;q
                    }' 0.conf`"
                if [ -z $COLUMNS -o $COLUMNS -le 23 ]
                then
                    printf -- "  %-22s%s\n" "$zero_param" "$zero_tmp"
                else
                    printf -- "%s\n" "$zero_tmp" |\
                    fold -w $(($COLUMNS-23)) -s  |\
                    while read line
                    do
                        printf -- "  %-22s%.$(($COLUMNS-23))s\n"\
                            "$zero_param"\
                            "$line"
                        zero_param=" "
                    done
                fi
            done
        } ; true

        printf -- "\n"
        printf -- "Report bugs to '%s'.\n" "$zero_author"
        (exit 0); exit 0
    }
    [ "x$zero_parameter" = "x--version" ] && {
        printf -- "This is the '%s' script for '%s'\n"\
                  "`basename $0`"\
                  "${zero_project}-${zero_version}"
        (exit 0); exit 0
    }
done



# Evaluate OPTIONs
for zero_option
do

    printf -- "=L Got raw command line item '%s'.\n" "$zero_option" >&2

    # Translate 'problematic' options and arguments ;)
    zero_option=`printf -- "%s" "$zero_option" | tr "[:cntrl:]" " "`
    
    # Separate option and argument
    zero_argument=`expr "x$zero_option" : 'x[^=]*=\(.*\)'`
    zero_option=${zero_option%"$zero_argument"}
    zero_option=${zero_option%\=}

    printf -- "=L Got cooked option '%s'.\n" "$zero_option" >&2
    printf -- "=L Got cooked argument '%s'.\n" "$zero_argument" >&2

    case "$zero_option" in

    --prefix|\
    --bindir|--sbindir|--xbindir|\
    --confdir|--datadir|\
    --infodir|--mandir|--docdir|\
    --libdir|--incdir)
        zero_argument=${zero_argument#\=}
        [ -z "$zero_argument" ] && {
            printf -- "*** Missing directory in '%s'.\n" "$zero_option"
            printf -- "=E Missing directory in '%s'.\n" "$zero_option" >&2
            (exit 1); exit 1
        }
        printf -- "=L Got raw directory name '%s'.\n" "$zero_argument" >&2
        #   Validate and normalize the directory name
        #   First, make sure the directory names doesn't
        # contain the forbidden char (currently '|')
        zero_tmp=`expr "x$zero_argument" : "x[^|]*"`
        [ $zero_tmp -le ${#zero_argument} ] && {
            [ $zero_tmp -eq 0 ] && zero_tmp=1
            printf -- "*** Invalid character '%c' in directory name '%s'.\n"\
                "`expr "x$zero_argument" : ".\{$zero_tmp\}\(.\)"`"\
                "$zero_argument"
cat << EOF
    Valid directory names cannot contain '|' characters.
EOF
            printf -- "=E Invalid directory name '%s'.\n" "$zero_argument" >&2
            (exit 1); exit 1
        }
        
        # First normalization: leading and trailing '/'
        case $zero_argument in
        /* ) zero_argument="$zero_argument/";;
        *)   zero_argument="`pwd`/$zero_argument/" ;;
        esac
        printf -- "=L 1st path normalization: '%s'.\n" "$zero_argument" >&2

        # Second normalization:
        #   - Dereference relative path elements
        #   - Change multiple '/' to one
        #   - Delete trailing '/'
        zero_argument=`printf -- "%s" "$zero_argument" | sed -n '
            :again
            s|//|/|
            t again
            s|/\./|/|
            t again
            s|^/\.\./|/|
            t again
            s|/[^/]*/\.\./|/|
            t again
            s|^/$|//|
            s|/$||
            p
        '`
        printf -- "=L 2nd path normalization: '%s'.\n" "$zero_argument" >&2

        # Well, now validate with 'expr'
        zero_tmp=`expr "x$zero_argument" : "x[-[:alnum:]./_,;:~@]\{1,\}"`
        [ $zero_tmp -le ${#zero_argument} ] && {
            [ $zero_tmp -eq 0 ] && zero_tmp=1
            printf -- "*** Invalid character '%c' in directory name '%s'.\n"\
                "`expr "x$zero_argument" : ".\{$zero_tmp\}\(.\)"`"\
                "$zero_argument"
cat << EOF
    Valid directory names must contain only alphanumeric characters, hyphens,
dots, slashes (of course...), underscores, commas, semicolons, colons, tildes
and at-signs. Any other character is forbidden...
EOF
            printf -- "=E Invalid directory name '%s'.\n" "$zero_argument" >&2
            (exit 1); exit 1
        }
        zero_option=${zero_option#--}
        eval zero_$zero_option=\"\$zero_argument\"
    ;;
    --enable | --enable-* | --disable | --disable-*)

        [ ! -z "$zero_argument" ] && {
            printf -- "*** You cannot assign a value to a FEATURE.\n"
            printf -- "=E Tried to assign a value to a FEATURE.\n" >&2
            (exit 1); exit 1
        }

        # Strip dashes...
        zero_option=${zero_option#--}

        # Save the 'feature' in $zero_argument
        zero_argument=${zero_option#*able}
        zero_argument=${zero_argument#-}

        [ -z "$zero_argument" ] && {
            printf -- "*** Missing feature in '--%s' option.\n"\
                "$zero_option"
            printf -- "=E Missing feature in '--%s' option.\n"\
                "$zero_option" >&2
            (exit 1); exit 1
        }

        zero_option=${zero_option%-*}

        # Compare the provided feature with the list of valid features.
        zero_tmp=""
        for zero_feature in debug $zero_vfeatures
        do
            [ "$zero_argument" = "$zero_feature" ] && zero_tmp="$zero_feature"
        done
        [ -z "$zero_tmp" ] && {
            printf -- "*** Invalid feature '%s'.\n" "$zero_argument"
            printf -- "*** Valid package features are:\n"
            for zero_feature in debug $zero_vfeatures
            do
                printf -- "\t%s\n" "$zero_feature"
            done
            printf -- "=E Invalid feature '%s'.\n" "$zero_argument" >&2
            (exit 1); exit 1
        }
        printf -- "=L Got feature name '%s'.\n" "$zero_argument" >&2

        #   A new parameter named zero_f_<FEATURE> is created for every
        # --enable/--disable-FEATURE option given, and a value of 'enable'
        # or 'disable' is assigned to it. Afterwards, that parameter is
        # added to a list that will be sort'd and uniq'd so the list at
        # the end has only ONE copy of each zero_f_<FEATURE> with a value
        # showing whether it was enabled or disabled in the command line.
        eval zero_f_$zero_argument=${zero_option}
        zero_features="$zero_features zero_f_$zero_argument"
    ;;

    --with | --with-*)
        [ -z "$zero_vparams" ] && {
            printf -- "*** This project does not accept '--with' options.\n"
            printf -- "=E This project does not accept '--with' options.\n" >&2
            (exit 1); exit 1
        }

        # Save the 'parameter' in $zero_option
        zero_option=${zero_option#--with}
        zero_option=${zero_option#-}
        
        [ -z "$zero_option" ] && {
            printf -- "*** Missing parameter in '--with' option.\n"
            printf -- "=E Missing parameter in '--with' option.\n" >&2
            (exit 1); exit 1
        }

        # Validate parameter name
        zero_tmp=""
        for zero_param in $zero_vparams
        do
            [ "$zero_option" = "$zero_param" ] && zero_tmp="$zero_param"
        done
        [ -z $zero_tmp ] && {
            printf -- "*** Invalid parameter '%s'.\n" "$zero_option"
            printf -- "*** Valid parameters are:\n"
            for zero_param in $zero_vparams
            do
                printf -- "\t%s\n" "$zero_param"
            done
            printf -- "=E Invalid parameter '%s'.\n" "$zero_option" >&2
            (exit 1); exit 1
        }
        printf -- "=L Got parameter name '%s'.\n" "$zero_option" >&2

        # Missing value for a valid parameter?
        [ -z "$zero_argument" ] && {
            printf -- "*** Missing value in parameter '%s'.\n" "$zero_option"
            printf -- "=E Missing value in parameter '%s'.\n"\
                "$zero_option" >&2
            (exit 1); exit 1
        }

        # Validate the parameter's value.
        # Use 'expr' for that and just forbid characters.
        zero_argument=`printf -- "%s" "$zero_argument" | tr "[:cntrl:]" " "`
        zero_tmp=`expr "x$zero_argument" : "x[[:alnum:]./_~]\{1,\}"`
        [ $zero_tmp -le ${#zero_argument} ] && {
            [ $zero_tmp -eq 0 ] && zero_tmp=1
            printf -- "*** Invalid character '%c' in parameter value '%s'.\n"\
                "`expr "x$zero_argument" : ".\{$zero_tmp\}\(.\)"`"\
                "$zero_argument"
cat << EOF
    Valid values for parameters must consist only in alphanumeric characters,
dots, slashes, underscores and tildes, and must be quoted from the shell!.
EOF
            printf -- "=E Invalid value '%s'.\n" "$zero_argument" >&2
            (exit 1); exit 1
        }
        printf -- "=L Got parameter value '%s'.\n" "$zero_argument" >&2
        
        #   A new parameter named zero_p_<PARAMETER> is created for every
        # --with-PARAMETER=VALUE option given, and it is assigned 'VALUE'.
        # Afterwards, that parameter is added to a list that will be sort'd
        # and uniq'd so the list has only ONE copy of each '--with' option
        # given in the command line with the last 'VALUE'.

        eval zero_p_$zero_option="${zero_argument}"
        zero_params="$zero_params zero_p_$zero_option"
    ;;

    *)  printf -- "*** Unknown option '%s', dammit!\n" "$zero_option"
        printf -- "\n"
        printf -- "Use '$0 --help' to show usage, please.\n"
        printf -- "=E Unknown option '%s'.\n" "$zero_option" >&2
        (exit 1); exit 1
    ;;
    esac
done

#   Process lists of FEATURE's and PARAM's so they are sorted and
# don't contain multiple copies of any FEATURE or PARAM.
zero_features=$(\
    printf -- "%s" "$zero_features" |\
    tr -s ' ' '\n'                  |\
    sort                            |\
    uniq                            |\
    tr -s '\n' ' '\
)
printf -- "=L Got feature '%s'.\n" $zero_features >&2
zero_params=$(\
    printf -- "%s" "$zero_params"   |\
    tr -s ' ' '\n'                  |\
    sort                            |\
    uniq                            |\
    tr -s '\n' ' '\
)
printf -- "=L Got parameter '%s'.\n" $zero_params >&2

# Just in case, a quite usual default prefix...
zero_prefix="${zero_prefix:-/usr/local}"

# This is for a '/usr' install ;)
if [ "$zero_prefix" = "/usr" ]
then
    : ${zero_confdir:=/etc}
fi

# And this for a root install ;)
if [ "$zero_prefix" = "/" ]
then
    :  ${zero_xbindir:=/usr/lib}
    :  ${zero_datadir:=/usr/share}
    :  ${zero_infodir:=/usr/share/info}
    :   ${zero_mandir:=/usr/share/man}
    :   ${zero_docdir:=/usr/share/doc/$zero_project}
    :   ${zero_libdir:=/usr/lib}
    :   ${zero_incdir:=/usr/include/$zero_project}

fi

# Now set default values for unset installation variables
[ "$zero_prefix" = "/" ] && zero_prefix=""
:   ${zero_bindir:=$zero_prefix/bin}
:  ${zero_sbindir:=$zero_prefix/sbin}
:  ${zero_xbindir:=$zero_prefix/lib}
:  ${zero_confdir:=$zero_prefix/etc}
:  ${zero_datadir:=$zero_prefix/share}
:  ${zero_infodir:=$zero_prefix/share/info}
:   ${zero_mandir:=$zero_prefix/share/man}
:   ${zero_docdir:=$zero_prefix/share/doc/$zero_project}
:   ${zero_libdir:=$zero_prefix/lib}
:   ${zero_incdir:=$zero_prefix/include/$zero_project}
[ "$zero_prefix" = "" ] && zero_prefix="/"

# Dump directories to logfile
printf -- "=L PREFIX   "%s"\n" "$zero_prefix"   >&2
printf -- "=L BINDIR   "%s"\n" "$zero_bindir"   >&2
printf -- "=L SBINDIR  "%s"\n" "$zero_sbindir"  >&2
printf -- "=L XBINDIR  "%s"\n" "$zero_xbindir"  >&2
printf -- "=L CONFDIR  "%s"\n" "$zero_confdir"  >&2
printf -- "=L DATADIR  "%s"\n" "$zero_datadir"  >&2
printf -- "=L INFODIR  "%s"\n" "$zero_infodir"  >&2
printf -- "=L MANDIR   "%s"\n" "$zero_mandir"   >&2
printf -- "=L DOCDIR   "%s"\n" "$zero_docdir"   >&2
printf -- "=L LIBDIR   "%s"\n" "$zero_libdir"   >&2
printf -- "=L INCDIR   "%s"\n" "$zero_incdir"   >&2


#   NOTE: There's a race condition in the generation of the files, very weird
# and pretty harmless, but ugly... and unavoidable. If any of the generated
# files is write protected while it is dumped the shell will complain. Since I
# need to generate the file using a redirection, this is unavoidable, as the
# user always can change the permissions of the generated file *while it is
# being generated* no matter if the name is known or random. This is very
# weird, since I can't think of a reason for doing that, taking into account
# that no harm can be done. Anyway, this note is just a reminder...
#   The explanation of the way we create the files is at the beginning of this
# file, when the log file is created...

# Create generated files:
for zero_tmp in config.h config.mk Makefile
do
    printf "=L Creating '%s'.\n" "$zero_tmp" >&2
    (rm -f "$zero_tmp" && :> "$zero_tmp") 1>&2 || {
        printf -- "*** Cannot create '%s'.\n" "$zero_tmp"
        printf -- "=E Cannot create '%s'.\n" "$zero_tmp" >&2
        (exit 1); exit 1
    }
    printf "=L '%s' created.\n" "$zero_tmp" >&2
done


# Dump the configuration header 'config.h'
printf -- "Generating 'config.h'... "
printf -- "=L Generating 'config.h'.\n" >&2
{
cat << EOF
/*  config.h - mobs automatically generated header.
 *  This file will be overwritten, DO NOT EDIT!
 *
 *  $COPYRIGHT
 *
 *  This header is free (as in speech) software;
 *  the copyright holder gives unlimited permission
 *  to copy, distribute and modify it.
 *
 *  This makefile 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.
 ***************/

#ifndef MOBS_CONFIG_H
#define MOBS_CONFIG_H

EOF

printf -- "\n/* Project information */\n"
printf -- "#define PROJECT \"%s\"\n" "$zero_project"
printf -- "#define VERSION \"%s\"\n" "$zero_version"
[ -z "$mobs_author" ] && printf -- "#define AUTHOR  \"%s\"\n" "$zero_author"

printf -- "\n/* User configurable directories */\n"
printf -- "#define PREFIX   \"%s\"\n" "$zero_prefix"
printf -- "#define XBINDIR  \"%s\"\n" "$zero_xbindir"
printf -- "#define CONFDIR  \"%s\"\n" "$zero_confdir"
printf -- "#define DATADIR  \"%s\"\n" "$zero_datadir"

[ ! -z "$zero_features" ] && {
    printf -- "\n/* Package features */\n"
    for zero_feature in $zero_features
    do
        eval zero_tmp="\${$zero_feature}_${zero_feature#zero_f_}"
        printf -- "#define "
        printf -- "%s\n" "$zero_tmp" | tr '[:lower:]' '[:upper:]'
    done
} ; true

[ ! -z "$zero_params" ] && {
    printf -- "\n/* Package parameters */\n"
    for zero_param in $zero_params
    do
        eval zero_tmp="\$$zero_param"
        printf -- "#define "
        printf -- "P_%s " "${zero_param#zero_p_}" | tr '[:lower:]' '[:upper:]'
        printf -- "%s\n" "$zero_tmp"
        printf -- "#define "
        printf -- "S_%s " "${zero_param#zero_p_}" | tr '[:lower:]' '[:upper:]'
        printf -- "\"%s\"\n" "$zero_tmp"
        
    done
} ; true

printf -- "\n#endif\n" 

} > config.h || {
    printf -- "ERROR!\n"
    printf -- "*** Cannot write to 'config.h'.\n"
    printf -- "=E Cannot write to 'config.h'.\n" >&2
    (exit 1); exit 1
}
printf -- "done.\n"
printf -- "=L 'config.h' generated successfully.\n" >&2


# Dump 'config.mk'
printf -- "Generating 'config.mk'... "
printf -- "=L Generating 'config.mk'.\n" >&2
{
cat << EOF
# config.mk - mobs automatically generated makefile.
# This file will be overwritten, DO NOT EDIT!
#
# $COPYRIGHT
#
# This makefile is free (as in speech) software;
# the copyright holder gives unlimited permission
# to copy, distribute and modify it.
#
# This makefile 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.
################

EOF
printf -- "##### Project information\n"
printf -- "override PROJECT:=%s\n"  "$zero_project"
printf -- "override VERSION:=%s\n"  "$zero_version"
printf -- "\n"
printf -- "##### User configurable directories\n"
printf -- "override   PREFIX:=\$(DESTDIR)%s\n"   "$zero_prefix"
printf -- "override   BINDIR:=\$(DESTDIR)%s\n"   "$zero_bindir"
printf -- "override  SBINDIR:=\$(DESTDIR)%s\n"  "$zero_sbindir"
printf -- "override  XBINDIR:=\$(DESTDIR)%s\n"  "$zero_xbindir"
printf -- "override  CONFDIR:=\$(DESTDIR)%s\n"  "$zero_confdir"
printf -- "override  DATADIR:=\$(DESTDIR)%s\n"  "$zero_datadir"
printf -- "override  INFODIR:=\$(DESTDIR)%s\n"  "$zero_infodir"
printf -- "override   MANDIR:=\$(DESTDIR)%s\n"   "$zero_mandir"
printf -- "override   DOCDIR:=\$(DESTDIR)%s\n"   "$zero_docdir"
printf -- "override   LIBDIR:=\$(DESTDIR)%s\n"   "$zero_libdir"
printf -- "override   INCDIR:=\$(DESTDIR)%s\n"   "$zero_incdir"
printf -- "\n"

# Process requested features and dump them
[ ! -z "$zero_features" ] && {
    printf -- "##### Package features\n"
    for zero_feature in $zero_features
    do
        eval zero_tmp="\${${zero_feature}}_${zero_feature#zero_f_}"
        printf -- "override "
        printf -- "%s:=1\n" "$zero_tmp" | tr '[:lower:]' '[:upper:]'
        eval zero_tmp="\$$zero_feature"
        printf -- "override "
        printf -- "F_%s" "${zero_feature#zero_f_}" |\
            tr '[:lower:]' '[:upper:]'
        printf -- ":=%sd\n" "$zero_tmp"
    done
    printf -- "\n"
} ; true

[ ! -z "$zero_params" ] && {
    printf -- "##### Package parameters\n"
    for zero_param in $zero_params
    do
        printf -- "override "
        printf -- "P_%s:=" "${zero_param#zero_p_}" |\
            tr '[:lower:]' '[:upper:]'
        eval zero_tmp="\$$zero_param"
        printf -- "\"%s\"\n" "$zero_tmp"
    done
    printf -- "\n"
} ; true
} > config.mk || {
    printf -- "ERROR!\n"
    printf -- "*** Cannot write to 'config.mk'.\n"
    printf -- "=E Cannot write to 'config.mk'.\n" >&2
    (exit 1); exit 1
}
printf -- "done.\n"
printf -- "=L 'config.h' generated successfully.\n" >&2


#   By now, we just copy 'Makefile.in' into 'Makefile' and add some code
# at the head and the tail. In the future more processing may be done.
printf -- "Generating 'Makefile'... "
printf -- "=L Generating 'Makefile'.\n" >&2
{
cat << EOF
# Makefile - mobs automatically generated Makefile.
# This file will be overwritten, DO NOT EDIT!
#
# This makefile is distributed under the same terms
# than the file 'Makefile.in'. The copyright holder
# of 'Makefile.in' is considered to be the copyright
# holder of this file. See 'Makefile.in' for details.
#
###################
include mobs.mk   #
include config.mk #
###################
EOF
cat Makefile.in
cat << 'EOF'

##### Dependency handling
ifneq ($(DEPENDENCIES),)
-include $(sort $(DEPENDENCIES))
endif
EOF
} > Makefile || {
    printf -- "ERROR!\n"
    printf -- "*** Cannot write to 'Makefile'.\n"
    printf -- "=E Cannot write to 'Makefile'.\n" >&2
    (exit 1); exit
}
printf -- "done.\n"
printf -- "=L 'config.h' generated successfully.\n" >&2



# If no hook is present, dump the gathered information.
[ -z "$zero_hook" ] && {

    printf -- "=L This project doesn't have a hook.\n" >&2

    printf -- "\n"
    printf -- "Your installation directories are:\n"
    printf -- "    PREFIX "%s"\n" "$zero_prefix"
    printf -- "    BINDIR "%s"\n" "$zero_bindir"
    printf -- "   SBINDIR "%s"\n" "$zero_sbindir"
    printf -- "   XBINDIR "%s"\n" "$zero_xbindir"
    printf -- "   CONFDIR "%s"\n" "$zero_confdir"
    printf -- "   DATADIR "%s"\n" "$zero_datadir"
    printf -- "   INFODIR "%s"\n" "$zero_infodir"
    printf -- "    MANDIR "%s"\n" "$zero_mandir"
    printf -- "    DOCDIR "%s"\n" "$zero_docdir"
    printf -- "    LIBDIR "%s"\n" "$zero_libdir"
    printf -- "    INCDIR "%s"\n" "$zero_incdir"
    printf -- "\n"

    [ ! -z "$zero_features" ] && {
        printf -- "Your package features are:\n"
        for zero_feature in $zero_features
        do
            eval zero_tmp="\$$zero_feature"
            printf -- "  %-22s%sd\n" "${zero_feature#zero_f_}" "$zero_tmp"
        done
        printf -- "\n"
    }

    [ ! -z "$zero_params" ] && {
        printf -- "Your package parameters are:\n"
        for zero_param in $zero_params
        do
            eval zero_tmp="\$$zero_param"
            printf -- "  %-22s%s\n" "${zero_param#zero_p_}" "$zero_tmp"
        done
        printf -- "\n"
    }
    printf -- "=L This is the end...\n" >&2
    (exit 0); exit 0
}


# Now, go for the hook!.
printf -- "Running hook '%s'...\n" $zero_hook

[ -e "$zero_hook" ] || {
    printf -- "*** Cannot run hook: it does not exist.\n"
    printf -- "=E Hook does not exist.\n" >&2
    (exit 1); exit 1
}

[ -f "$zero_hook" ] || {
    printf -- "*** Cannot run hook: it is not a regular file.\n"
    printf -- "=E Hook is not a regular file.\n" >&2
    (exit 1); exit 1
}

[ -r "$zero_hook" ] || {
    printf -- "*** Cannot run hook: it is not readable.\n"
    printf -- "=E Hook is not readable.\n" >&2
    (exit 1); exit 1
}

[ -x "$zero_hook" ] || {
    printf -- "*** Cannot run hook: it is not executable.\n"
    printf -- "=E Hook is not executable.\n" >&2
    (exit 1); exit 1
}

# Export needed variables
export  PROJECT="$zero_project"
export  VERSION="$zero_version"
export   PREFIX="$zero_prefix"
export   BINDIR="$zero_bindir"
export  SBINDIR="$zero_sbindir"
export  XBINDIR="$zero_xbindir"
export  CONFDIR="$zero_confdir"
export  DATADIR="$zero_datadir"
export  INFODIR="$zero_infodir"
export   MANDIR="$zero_mandir"
export   DOCDIR="$zero_docdir"
export   LIBDIR="$zero_libdir"
export   INCDIR="$zero_incdir"

for zero_feature in $zero_features
do
    zero_tmp=$(\
        printf -- "F_%s" "${zero_feature#zero_f_}" |\
        tr '[:lower:]' '[:upper:]'\
    )
    eval export $zero_tmp="\${$zero_feature}d"
done

for zero_param in $zero_params
do
    zero_tmp=$(\
        printf -- "P_%s" "${zero_param#zero_p_}" |\
        tr '[:lower:]' '[:upper:]'\
    )
    eval export $zero_tmp=\""\$$zero_param"\"
done

printf -- "=H\n" >&2
./$zero_hook && {
    printf -- "=H\n" >&2
    (exit 0); exit 0
}
zero_tmp=$?
printf -- "*** Error running hook!\n"
printf -- "=H\n" >&2
printf -- "=E Hook returned error '%d'.\n" $zero_tmp >&2

(exit 1) ; exit 1
