/*
 * fhist - file history and comparison tools
 * Copyright (C) 1991-1995, 1998-2006, 2008, 2010, 2012 Peter Miller
 *
 * 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 3 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * The build by defalt only indicates the command.  If you want to see
 * the whole command, but verbose=1 on the aeb command line.
 */
if [not [defined verbose]] then
    verbose = 0;
quiet = [not [verbose]];
if [quiet] then
    set silent;
else
    set tell-position star;

function if_quiet =
{
    if [quiet] then
        function print [@1] [target];
    else if [in [count [younger]] 0 1 2 3] then
        function print Building [target] because of [younger];
    else
        function print Building [target] because of [wordlist 1 3 [younger]]...;
}

/*
 * Turn on updating to ensure mod-time
 * consistency on fast machines.
 */
set update;

/*
 * Remove the target and make the directories above the target before
 * the recipe body is run,
 */
set mkdir unlink;

/*
 * You may want to change some of these options.
 * ([debug] must be defined, even if empty, use comments.)
 *
 * If you want to turn the DEBUG compile flag on,
 * edit the common/main.h file.
 */
debug = /* -g */ ;

/*
 * Make sure the [project], [change], [version] and [arch] variables are set.
 */
#ifndef project
echo "The [project] variable was not set from the command line." set silent;
echo "If you want to do a build which is not a development build" set silent;
echo "or an integration build, use the make command, not cook." set silent;
fail;
#endif
#ifndef change
echo "The [change] variable was not set from the command line." set silent;
echo "If you want to do a build which is not a development build" set silent;
echo "or an integration build, use the make command, not cook." set silent;
fail;
#endif
#ifndef version
echo "The [version] variable was not set from the command line." set silent;
echo "If you want to do a build which is not a development build" set silent;
echo "or an integration build, use the make command, not cook." set silent;
fail;
#endif
#ifndef arch
echo "The [arch] variable was not set from the command line." set silent;
echo "If you want to do a build which is not a development build" set silent;
echo "or an integration build, use the make command, not cook." set silent;
fail;
#endif

awk = gawk;
c_incl = c_incl;

/*
 * The first item in search list should be the absolute path of the
 * current directory.  Assume that it is.
 */
search_list = .;
search_tmp = [tail [split ':' [search_path]]];

/*
 * Try to shorten the search path in command lines, too.
 *
 * This takes a little getting used to....
 * 1. For development builds, the search path is dev dir, then branch bl,
 *    then ... project bl.  Thus, bl in a dev dir winds up pointing to
 *    the branch reporitory.
 * 2. For integration builds, aegis deliberately omits the branch
 *    baseline from the path, but include's the branch's parents and
 *    ancestors.  Thus, bl in an int dir winds up pointing to the
 *    branch's parent's reporitory.
 * The idea is that integration builds in a branch are like a
 * development build of the branch's dev dir.
 */
search_name = bl;
loop
{
    search_dir = [head [search_tmp]];
    if [not [search_dir]] then
        loopstop;
    search_tmp = [tail [search_tmp]];

    if [not [exists [search_name]]] then
        ln -s [search_dir] [search_name]
            set clearstat;
    search_list = [search_list] [search_name];
    search_name = [search_name]bl;
}

/*
 * This file is generated by autoconf.
 * It is architecture specific.
 * If it is not found (not cooked yet) the following
 * symbols will be undefined.
 *
 *      Must be included *after* the search_list is defined.
 */
#include-cooked-nowarn [arch]/etc/Howto.conf
if [not [defined prefix]] then
    prefix = /usr/local;
if [not [defined exec_prefix]] then
    exec_prefix = [prefix];
if [not [defined yacc]] then
    yacc = yacc;
if [not [defined libs]] then
    libs = ;
if [not [defined cc]] then
    cc = ['if' [find_command gcc] 'then' gcc 'else' cc];

/*
 * determine the short version:
 * no change or delta number
 */
version_short = [fromto %1.C%2 %1 [subst D C [version]]];

version_shorter = [split "." [version_short]] _ _;
version_shorter = [unsplit "." [word 1 [version_shorter]]
    [word 2 [version_shorter]]];
project_short = [fromto %.[version_short] % [project]];
project_minus = [project_short]-[version_short];

change_source_files = ;
#include-cooked-nowarn etc/cook/change_files.[version]
etc/cook/change_files.[version]:
    set shallow nodefault
{
    echo "'change_source_files ='" > [target];
    aelcf -p [project] -c [change] >> [target];
    echo "';'" >> [target];
}
project_source_files = ;
#include-cooked-nowarn etc/cook/project_files.[version]
etc/cook/project_files.[version]:
    set shallow nodefault
{
    echo "'project_source_files ='" > [target];
    aelpf -p [project] -c [change] >> [target];
    echo "';'" >> [target];
}
source_files = [sort [project_source_files] [change_source_files]];

c_incl_exclude =
    [addprefix "-ex="
        [fromto common/ac/%0%.h %0%.h
            [match_mask common/ac/%0%.h [source_files]]
        ]
    ];

/*
 * Speed up graph building by stating the leaves explictly.
 * This also gives more useful error messages.
 */
if [count [project_source_files]] then
if [count [change_source_files]] then
{
    leaf_file_accept = [project_source_files] [change_source_files];
    leaf_pattern_accept = /%0%;
}

/*
 * If this is a development build, the version will be x.y.Czzz,
 * so look to see if there is a C in the version string.
 * Include the baseline in the search path if this is
 * a development build.
 */
if [match_mask %1C%2 [version]] then
{
    baseline = bl;
    set time-adjust;
    set fingerprint;
}
else
{
    set time-adjust-back;
}

/*
 * This list of commands to build.
 */
commands = bogus;
if [count [source_files]] then
commands = [stringset [dirname [match_mask %/main.c [source_files]]]];

/*
 * The default recipe
 */
all =
    doc.targets
    [addprefix [arch]/bin/ [commands]]
    internationalization
    ;
if [not [defined baseline]] then
    all = [all] integration-build-targets;

all: [all]
    set default;


/*
 * The source files.
 * This is given to us by aegis.
 */
vs_file = common/patchlevel.h;
lib_obj =
    [stringset
        [fromto
            common/%0%.c
            [arch]/common/%0%.o
            [match_mask common/%0%.c [source_files]]
        ]
        [fromto
            common/%0%.y
            [arch]/common/%0%.yacc.o
            [match_mask common/%0%.y [source_files]]
        ]
    -
        [arch]/common/version_stmp.o
    ];
common_obj =
    [arch]/common/lib.a [arch]/common/version_stmp.o
    ;

command_list = [commands];
loop
{
    command = [head [command_list]];
    if [not [count [command]]] then
        loopstop;
    command_list = [tail [command_list]];

    [command]_obj =
        [fromto
            [command]/%0%.c
            [arch]/[command]/%0%.o
            [match_mask [command]/%0%.c [source_files]]
        ]
        [common_obj]
        ;
}

source_files_build =
    [collect ( aegis -l pf -p [project] -c [change] -unf ';'
        aegis -l cf -p [project] -c [change] -unf )
        | gawk "'/^build/{print $NF}'" ]
    ;
source_files_non_build =
    [stringset [source_files] - [source_files_build]];

/*
 * how to compile C sources
 */
if [defined [arch]_cc_flags] then
    cc_flags = [split "%" [[arch]_cc_flags]];

if [not [defined cc_flags]] then
    cc_flags = -O [debug];

if [defined [arch]_cc_include_flags] then
    cc_include_flags = [split "%" [[arch]_cc_include_flags]];

if [not [defined cc_include_flags]] then
    cc_include_flags = ;

if [defined [arch]_ld_flags] then
    ld_flags = [split "%" [[arch]_ld_flags]];

if [not [defined ld_flags]] then
    ld_flags = ;

/*
 * this next section is for gcc
 *      comment it out if you do not have gcc
 *
 * The gcc include files MUST be first.
 */
cc_flags +=
    -ansi
    -Wall
    -Wextra
    -Wstrict-prototypes
    -Wmissing-prototypes
    -Wshadow
    -Wmissing-declarations
    -Wpointer-arith
    -Wcast-align
    -Wwrite-strings
    -Werror
    ;

/*
 * include files from the common directory.
 */
cc_include_flags +=
    [prepost "-I" "/"[arch] [search_list]]
    [addprefix "-I" [search_list]]
    ;


/*
 * Build %.o from %.c
 */
[arch]/%1/%0%2.o: %1/%0%2.c
{
    function if_quiet Compile;
    if [defined %2_flags] then
        extra = [%2_flags];
    else
        extra = ;
    [cc] [cc_flags] [extra]
        [cc_include_flags]
        -c [resolve %1/%0%2.c]
        ['if' [in [cc] gcc] 'then' -o [target]];
    if [not [in [cc] gcc]] then
        mv %2.o [target];
}

%1/%0%2.c.d: %1/%0%2.c
    set nocascade
{
    function if_quiet Depends;
    c_incl -nc -ns -eia -nrec
        [cc_include_flags]
        -nsri /* no source relative includes */
        ['if' [not [filter common/ac/%%0%% %1/%0%2.c]]
         'then' [c_incl_exclude]]
        -prefix "'cascade %1/%0%2.c ='"
        -suffix "';'"
        [resolve %1/%0%2.c]
        [prepost "-rlp=" "" [search_list]] /* remove leading path */
        -slp [arch] "'[arch]'"  /* substitute leading path */
        -o [target];
}

%1/%0%2.h.d: %1/%0%2.h
    set nocascade
{
    function if_quiet Depends;
    c_incl -nc -ns -eia -nrec
        [cc_include_flags]
        -nsri /* no source relative includes */
        ['if' [not [filter common/ac/%%0%% %1/%0%2.c]]
         'then' [c_incl_exclude]]
        -prefix "'cascade %1/%0%2.h ='"
        -suffix "';'"
        [resolve %1/%0%2.h]
        [prepost "-rlp=" "" [search_list]] /* remove leading path */
        -slp [arch] "'[arch]'"  /* substitute leading path */
        -o [target];
}

c-dep-files =
    [addsuffix .d [match_mask %1/%0%2.c [source_files]]]
    [addsuffix .d [match_mask %1/%0%2.h [source_files]]]
    [fromto %0%.y %0%.yacc.c.d [match_mask %0%.y [source_files]]]
    ;

#include-cooked-nowarn [c-dep-files]

/*
 * A few explicit things, to make sure the .d files
 * are constructed correctly.  Sigh.
 */

cascade common/ac/ctype.h = [arch]/common/config.h;
cascade common/ac/dirent.h = [arch]/common/config.h;
cascade common/ac/errno.h = [arch]/common/config.h;
cascade common/ac/grp.h = [arch]/common/config.h;
cascade common/ac/libintl.h = [arch]/common/config.h;
cascade common/ac/limits.h = [arch]/common/config.h;
cascade common/ac/locale.h = [arch]/common/config.h;
cascade common/ac/pwd.h = [arch]/common/config.h;
cascade common/ac/signal.h = [arch]/common/config.h;
cascade common/ac/stdarg.h = [arch]/common/config.h;
cascade common/ac/stddef.h = [arch]/common/config.h;
cascade common/ac/stdio.h = [arch]/common/config.h;
cascade common/ac/stdlib.h = [arch]/common/config.h;
cascade common/ac/string.h = [arch]/common/config.h;
cascade common/ac/sys/stat.h = [arch]/common/config.h;
cascade common/ac/sys/types.h = [arch]/common/config.h;
cascade common/ac/termios.h = [arch]/common/config.h;
cascade common/ac/time.h = [arch]/common/config.h;
cascade common/ac/unistd.h = [arch]/common/config.h;
cascade common/ac/wchar.h = [arch]/common/config.h;
cascade common/ac/wctype.h = [arch]/common/config.h;
cascade common/input/private.c = [arch]/common/config.h;
cascade common/libdir.c = [arch]/etc/libdir-h;
cascade common/sub/expr_lex.c = common/sub/expr_gram.yacc.h;
cascade common/version_stmp.c = common/patchlevel.h;

/*
 * How to use yacc sources.
 */
yacc_flags = -v;

%1/%0%2.yacc.c %1/%0%2.yacc.h: %1/%0%2.y
    single-thread y.tab.c y.tab.h y.output
{
    function if_quiet Yacc;
    rm -f %1/%0%2.list y.output
        set silent;
    if [exists %1/%0%2.yacc.c] then
        rm %1/%0%2.yacc.c
            set clearstat;
    if [exists %1/%0%2.yacc.h] then
        rm %1/%0%2.yacc.h
            set clearstat;
    [yacc] -d [yacc_flags] [resolve %1/%0%2.y];
    yy = [collect echo %0%2 | sed "'s/[^a-zA-Z0-9]/_/g'"];
    sed     -e \'s/\[yY\]\[yY\]/[yy]_/g\'
        -e \'/<stdio.h>/d\'
        -e \'/<stdlib.h>/d\'
        -e \'/<stddef.h>/d\'
        -e \'/<libintl.h>/d\'
        y.tab.c > %1/%0%2.yacc.c;
    rm y.tab.c;
    sed     -e \'s/\[yY\]\[yY\]/[yy]_/g\'
        -e \'s/Y_TAB_H/[yy]_TAB_H/\'
        y.tab.h > %1/%0%2.yacc.h;
    rm y.tab.h;
    if [exists y.output] then
        mv y.output %1/%0%2.list
            set clearstat;
}

/*
 * build the programs
 */
[arch]/bin/%: [%_obj]
{
    function if_quiet Link;
    [cc] -o [target] [resolve [%_obj]] [ld_flags] [libs];
    chmod 755 [target];
}

ranlib = [find_command ranlib];

[arch]/common/lib.a: [lib_obj]
{
    function if_quiet Link;
    ar cq [target] [resolve [lib_obj]];
    if [ranlib] then
        [ranlib] [target];
}


/*
 * The version stamp is to be updated for every
 * integration and development build.
 */

copyright_years =
    [collect
        aegis -list version -p [project] -c [change]
        | gawk "-F'[[\\\\]]'" "'/^copyright_years/{print $2}'"
    ];

[vs_file]:
    set shallow
{
    function if_quiet Generate;
    echo "'#define PATCHLEVEL \""[version]"\"'" > [target];
    echo "'#define COPYRIGHT_YEARS \""[copyright_years]"\"'" >> [target];
}


etc/CHANGES.[version_short]: etc/CHANGES.sh [vs_file]
{
    function if_quiet Generate;
    if [not [exists [dirname [target]]]] then
        mkdir -p [dirname [target]]
            set clearstat;
    if [exists [target]] then
        rm [target]
            set clearstat;
    sh [resolve etc/CHANGES.sh] [project] > [target];
}


configure: aegis.conf.d/site.conf etc/configure.ac install-sh
{
    function if_quiet Generate;
    if [exists [target]] then
        rm [target]
            set clearstat;
    autoconf [resolve etc/configure.ac] > [target];
    chmod 755 [target];
}

/*
 * Different Linux install methods put the packages in different places.
 * We need to find the autoconf package to get the install-sh script.
 */
loop install-sh-maybe =
    /usr/share/autoconf/install-sh
    [glob /usr/share/automake*/install-sh]
    /usr/local/share/autoconf/install-sh
    [glob /usr/local/share/automake*/install-sh]
{
    if [exists [install-sh-maybe]] then
    {
        install-sh = [install-sh-maybe];
        loopstop;
    }
}
if [not [install-sh]] then
    fail "Can't locate the ``install-sh'' script from GNU automake";

install-sh: [install-sh]
{
    function if_quiet Copy;
    cp [need] [target];
    chmod 755 [target];
}


[arch]/config.status: configure
{
    function if_quiet Generate;
    if [not [exists install-sh]] then
    {
        /*
         * Cook says it is up-to-date, so it must be in the
         * baseline; autoconf needs it in the current directory.
         */
        cp [resolve install-sh] .
            set clearstat;
    }

    local flags =;
    if [defined [arch]_cc_flags] then
        flags += CFLAGS\=[quote [unsplit " "
                       [split "%" [[arch]_cc_flags]]]];
    else if [defined cc_flags] then
        flags += CFLAGS\=[quote [unsplit " " [split "%" [cc_flags]]]];

    if [defined [arch]_ld_flags] then
        flags += LDFLAGS\=[quote [unsplit " "
                      [split "%" [[arch]_ld_flags]]]];
    else if [defined ld_flags] then
        flags += LDFLAGS\=[quote [unsplit " " [split "%" [ld_flags]]]];

    if [defined [arch]_libs] then
        flags += LIBS\=[quote [unsplit " " [split "%" [[arch]_libs]]]];
    else if [defined libs] then
        flags += LIBS\=[quote [unsplit " " [split "%" [libs]]]];

    [unsplit " "
        CC\=[quote [unsplit " " [cc]]]
        [unsplit " " [flags]]

        [pathname [resolve configure]] --cache-file\=/dev/null --verbose
            --no-create --srcdir\=. --sysconfdir\=/etc
            ['if' [quiet] 'then' --quiet]

        && mv config.status [arch]/config.status
    ];
}

common/config.h.in: etc/configure.ac
{
    function if_quiet Generate;
    autoheader [resolve etc/configure.ac] > [target];
}

[arch]/%0%.h: %0%.h.in [arch]/config.status
{
    /* these 2 env vars control what is generated */
    CONFIG_FILES\= CONFIG_HEADERS\=[target]\:[resolve %0%.h.in]
        [resolve [arch]/config.status];
}

[arch]/%0%: %0%.in [arch]/config.status
{
    /* these 2 env vars control what is generated */
    CONFIG_FILES\=[target]\:[resolve %0%.in] CONFIG_HEADERS\=
        [resolve [arch]/config.status];
}


#include-cooked etc/document.cook /* must be before archive.cook */
#include-cooked etc/archive.cook
#include-cooked etc/i18n.cook
#include-cooked etc/cfmt.cook
#include-cooked etc/tags.cook


/* vim: set ts=8 sw=4 et : */
