/*
 * tardy - a tar post-processor
 * Copyright (C) 1993, 1995, 1998-2003, 2008-2011 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/>.
 */

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

/*
 * make sure targets are removed before the recipe body is run,
 * and make sure that directories are created then too.
 */
set mkdir unlink;

/*
 * You may want to change some of these options.
 * ([debug] must be defined, even if empty, use comments.)
 *
 * Change ``main.h'' to add the DEBUG define.
 * All files reference this file, so this will cause recompilation
 * of all files, both in the change and in the baseline.
 */
debug = -g ;

/*
 * Make sure the [project], [change] and [version] 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 with 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 with 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 with 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 with is not a development build" set silent;
echo "or an integration build, use the make command, not cook." set silent;
fail;
#endif

/*
 * The build command will seat c ``search path'' variable, this is the
 * heirachy of aegis branch baseline and the currect change directory.
 * Split the colon separated search path into a list of strings.  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;
}

/*
 * 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
{
    /*
     * The develop_begin_command in the config file
     * always creates the "bl" symbolic link.
     */
    baseline = bl;
}

if [defined baseline] then
{
    /*
     * Use finigerprints in development builds.
     */
    set fingerprint;
}
else
{
    /*
     * Turn on aggressive updating to ensure the smallest possible
     * range of mod times at aeipass.  This also ensures mod time
     * consistency on fast machines.
     */
    set time-adjust-back;
}

/*
 * use GNU awk
 */
awk = gawk;

version_short = [fromto %1.C%2 %1 [subst D C [version]]];

/*
 * 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 c++]] then
    c++ = ['if' [find_command g++] 'then' g++ 'else' c++];

/*
 * The source files.
 * This is given to us by aegis.
 */
vs_file = libtardy/patchlevel.h;
change_files =
    [collect aegis -l chafil -ter -p [project] -c [change]]
    [vs_file]
    ;
project_files =
    [collect aegis -l profil -ter -p [project] -c [change]]
    ;
source_files =
    [sort [stringset [project_files] [change_files]]]
    ;

common_obj =
    [arch]/libtardy/libtardy.a
    [arch]/libtardy/versi_stamp.o
    ;

common_lib_obj =
    [stringset
        [fromto libtardy/%0%.cc [arch]/libtardy/%0%.o
            [match_mask libtardy/%0%.cc [source_files]]
        ]
        [fromto libtardy/%.c [arch]/libtardy/%.o
            [match_mask libtardy/%.c [source_files]]
        ]
    -
        [common_obj]
    ]
    ;

tardy_obj =
    [fromto tardy/%0%.cc [arch]/tardy/%0%.o
        [match_mask tardy/%0%.cc [source_files]]
    ]
    [common_obj]
    ;


/*
 * There is a special list of files you must use, in preference to the
 * standard C files.  This ensures appropriate operating system insulation
 * is always in place.
 */
c_incl_excludes =
    [fromto libtardy/ac/%0%.h -ex\=%0%.h
        [match_mask libtardy/ac/%0%.h [source_files]]
    ];

/*
 * The default recipe
 */
all =
    [arch]/libtardy/config.h
    [arch]/bin/tardy
    [arch]/bin/test_prelude
    doc.targets
    ;

all: [all];

/*
 * how to compile C sources
 */
c++_flags = -O [debug];
c++_include_flags = ;

/*
 * this next section is for gcc
 *      comment it out if you don't have gcc
 *
 * The gcc include files MUST be first.
 */
c++_flags += -Wall -Wextra -Wshadow -Werror;

/*
 * include search path
 */
c++_include_flags =
    [c++_include_flags]
    [prepost "-I" "/"[arch] [search_list]]
    [addprefix "-I" [search_list]]
    ;


/*
 * Build %1/%2.o from %1/%2.cc
 */

[arch]/%1/%0%2.o: %1/%0%2.cc
{
    if [defined %2_flags] then
        extra = [%2_flags];
    else
        extra = ;
    [c++] [c++_flags] [extra]
        [c++_include_flags]
        -c [resolve %1/%0%2.cc]
        ['if' [in gcc [c++]] 'then' -o [target]];
    if [not [in gcc [c++]]] then
        mv %2.o [target];
}

%1/%0%2.cc.d: %1/%0%2.cc
    set nocascade
{
    c_incl -nc -ns -eia -nrec
        [c++_include_flags]
        -prefix "'cascade %1/%0%2.cc ='"
        -suffix "';'" [resolve %1/%0%2.cc]
            [addprefix '-rlp=' [search_list]]
            -slp [arch] "'[arch]'"
        ['if' [not [filter libtardy/ac/%%0%% %1/%0%2.cc]]
            'then' [c_incl_excludes]]
        > [target];
}

%1/%0%2.h.d: %1/%0%2.h
    set nocascade
{
    c_incl -nc -ns -eia -nrec
        [c++_include_flags]
        -prefix "'cascade %1/%0%2.h ='"
        -suffix "';'" [resolve %1/%0%2.h]
            [addprefix '-rlp=' [search_list]]
            -slp [arch] "'[arch]'"
        ['if' [not [filter libtardy/ac/%%0%% %1/%0%2.h]]
            'then' [c_incl_excludes]]
        > [target];
}


/*
 * Build %1/%2.o from %1/%2.c
 */

[arch]/%1/%0%2.o: %1/%0%2.c
{
    if [defined %2_flags] then
        extra = [%2_flags];
    else
        extra = ;
    [c++] [c++_flags] [extra]
        [c++_include_flags]
        -c [resolve %1/%0%2.c]
        ['if' [in gcc [c++]] 'then' -o [target]];
    if [not [in gcc [c++]]] then
        mv %2.o [target];
}

%1/%0%2.c.d: %1/%0%2.c
    set nocascade
{
    c_incl -nc -ns -eia -nrec
        [c++_include_flags]
        -prefix "'cascade %1/%0%2.c ='"
        -suffix "';'" [resolve %1/%0%2.c]
        [addprefix '-rlp=' [search_list]]
        -slp [arch] "'[arch]'"
        ['if' [not [filter libtardy/ac/%%0%% %1/%0%2.c]]
            'then' [c_incl_excludes]]
        > [target];
}

c-dep-files =
    [addsuffix ".d"
        [match_mask %1/%0%2.c  [source_files]]
        [match_mask %1/%0%2.cc [source_files]]
        [match_mask %1/%0%2.h  [source_files]]
    ]
    [fromto %1/%0%2.y %1/%0%2.gen.c.d
        [match_mask %1/%0%2.y [source_files]]
    ]
    [fromto man1/%.so man1/%.h.d
        [match_mask man1/%.so [source_files]]
    ]
    ;

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

/*
 * A few explicit things, to make sure the .d files
 * are constructed correctly.  Sigh.
 */
cascade [match_mask libtardy/ac/%0%.h [source_files]] =
    [arch]/libtardy/config.h ;
cascade etc/README.man = etc/new.so etc/version.so ;
cascade tardy/main.cc = man/man1/tardy.h;
cascade libtardy/roff.cc = man/man1/o__rules.h;
cascade libtardy/roff.cc = man/man1/o_help.h;
cascade libtardy/roff.cc = man/man1/z_exit.h;
cascade libtardy/version.cc = man/man1/tardy_license.h;

/*
 * How to use yacc sources.
 */

yacc = yacc;
yacc_flags = ;

%1/%2.gen.c %1/%2.gen.h: %1/%2.y
    single-thread yy.tab.c yy.tab.h
{
    if [exists %1/%2.list] then
        rm %1/%2.list
            set clearstat;
    if [exists y.output] then
        rm y.output
            set clearstat;
    [yacc] -d [yacc_flags] [resolve %1/%2.y];
    sed "'s/[yY][yY]/%2_/g'" < y.tab.c > %1/%2.gen.c;
    rm y.tab.c;
    sed "'s/[yY][yY]/%2_/g'" < y.tab.h > %1/%2.gen.h;
    rm y.tab.h;
    if [exists y.output] then
        mv y.output %1/%2.list
            set clearstat;
}


/*
 * building things which require txt2c to build
 *
 * Build %.h from %.1
 */

man/man1/%.h: man/man1/%.1: etc/txt2c.awk
{
    [awk] -f [resolve etc/txt2c.awk] [resolve man/man1/%.1] > [target];
}

man/man1/%.h: man/man1/%.so: etc/txt2c.awk
{
    [awk] -f [resolve etc/txt2c.awk] [resolve man/man1/%.so] > [target];
}

ranlib = [find_command ranlib];

[arch]/libtardy/libtardy.a: [common_lib_obj]
{
    ar qc [target] [resolve [common_lib_obj]];
    if [ranlib] then
        [ranlib] [target];
}


/*
 * build the programs from their objects
 */

[arch]/bin/%: [%_obj]
    set gate-first shallow
    if [defined %_obj]
{
    [c++] -o [target] [resolve [%_obj]] [libs];

    chmod og\=u-w [target];
}


/*
 * The version stamp is to be updated for every
 * integration and development build.
 *
 * The file is deleted by the integrate_begin_command in the project config file
 */

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

if [not [exists [vs_file]]] then
{
    if [not [exists [dirname [vs_file]]]] then
        mkdir -p [dirname [vs_file]]
            set clearstat;
    echo "'#define PATCHLEVEL \""[version]"\"'" > [vs_file]
        set clearstat;
    echo "'#define COPYRIGHT_YEARS \""[copyright_years]"\"'" >> [vs_file];
}

#ifndef baseline

if [not [exists etc/version.so]] then
{
    if [not [exists etc]] then
        mkdir etc
            set clearstat;
    echo "'.ds V) "[version]"'" > etc/version.so
        set clearstat;
    echo "'.ds v) "[version_short]"'" >> etc/version.so
        set clearstat;
    aegis -list version -p [project] -c [change]
        | [awk] -F'\'"\'' "'/previous/{print $2}'"
        | [awk] -F. "'{print \".ds w) \"$1\".\"$2}'"
        >> etc/version.so;
    echo "'.ds Y) "[copyright_years]"'" >> etc/version.so
        set clearstat;
    cooktime -m 2-jan-70 etc/version.so;
}

#endif

etc/new.so: [match_mask etc/new.%.so [source_files]]
    etc/so.sh
{
    sh [resolve etc/so.sh]
        /* DO NOT resolve these next arguments... */
        [match_mask etc/new.%.so [source_files]]
    > [target];
}

etc/newest.so: etc/new.so
{
    head -6 [resolve etc/new.so] > [target];
}

/*
 * formatting documents and manual entries
 */
doc.targets: cat txt special;

/*
 * manual entries
 */
cat =
    [fromto man/man%1/%2.%1 man/cat%1/%2.%1
        [match_mask man/man%1/%2.%1 [source_files]]
    ];
cat: [cat];

man/cat%1/%2.%1: man/man%1/%2.%1
{
    roffpp [addprefix "-I" [search_list]] [resolve man/man%1/%2.%1]
        | groff -Tascii -P-h -t -man
        > [target];
}

man/man%1/%2.%1.d: man/man%1/%2.%1
    set nocascade
{
    c_incl -nc -ns -eia -r
        -nrec
        [stringset [c++_include_flags] [addprefix "-I" [search_list]]]
        -prefix "'cascade man/man%1/%2.%1 ='"
        -suffix "';'"
        [resolve man/man%1/%2.%1]
        [addprefix '-rlp=' [search_list]]
        -slp [arch] "'[arch]'"
        > [target];
}

man-dep-files = [addsuffix ".d" [match_mask man/man%1/%2.%1 [source_files]]];

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


/*
 * user manuals
 */

txt = [fromto doc/%.ms doc/%.ps.gz [match_mask doc/%.ms [source_files]]];
txt: [txt];

doc/%.ps.gz: doc/%.ms
{
    roffpp [addprefix "-I" [search_list]] [resolve doc/%.ms]
        | groff -p -t -ms
        | gzip
        > [target];
}


/*
 * specials
 */

special: [fromto etc/%.man % [match_mask etc/%.man [source_files]]]
        ;

%: etc/%.man
{
    roffpp [addprefix "-I" [search_list]] [resolve etc/%.man]
        | groff -Tascii -P-hub -t -man
        > [target];
}

etc/%.d: etc/%.man
    set nocascade
{
    c_incl -nc -ns -eia -r
        [stringset [c++_include_flags] [prepost "-I" "/etc" [search_list]]]
        -prefix "'cascade etc/%.man ='"
        -suffix "';'" [resolve etc/%.man]
        [addprefix '-rlp=' [search_list]]
        -slp [arch] "'[arch]'"
        > [target];
}

etc/%.txt: etc/%.roff
    set shallow
{
    groff [addprefix "-I" [search_list]]
        -Tascii -P-hub -t
        [resolve etc/%.roff]
    | cat -s
        > [target];
}

etc/%.roff.d: etc/%.roff
    set nocascade
{
    c_incl -nc -ns -eia -r
        -nrec
        [stringset [c++_include_flags] [prepost "-I" "/etc" [search_list]]]
        -prefix "'cascade etc/%.roff ='"
        -suffix "';'" [resolve etc/%.man]
        [addprefix '-rlp=' [search_list]]
        -slp [arch] "'[arch]'"
        > [target];
}

etc/%.so.d: etc/%.so
    set nocascade
{
    c_incl -nc -ns -eia -r
        -nrec
        [stringset [c++_include_flags] [prepost "-I" "/etc" [search_list]]]
        -prefix "'cascade etc/%.so ='"
        -suffix "';'" [resolve etc/%.so]
        [addprefix '-rlp=' [search_list]]
        -slp [arch] "'[arch]'"
        > [target];
}

etc-dep-files =
    [fromto etc/%.man etc/%.d [match_mask etc/%.man [source_files]]]
    [addsuffix ".d" [match_mask etc/%.roff [source_files]]]
    etc/new.so.d
    etc/newest.so.d
    ;

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


configure: etc/configure.ac install-sh
{
    /*
     * unfortunately,
     * install-sh must be in the current directory
     */
    if [not [exists install-sh]] then
        cp [resolve install-sh] install-sh
            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 linstall-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]
{
    cp [need] [target];
    chmod 755 [target];
}

[arch]/config.status: configure install-sh
{
    /*
     * unfortunately,
     * install-sh must be in the current directory
     */
    if [not [exists install-sh]] then
        cp [resolve install-sh] install-sh
            set clearstat;
    ./[resolve configure] --cache-file\=/dev/null --verbose --no-create;
    mv config.status [arch]/config.status;
}

libtardy/config.h.in: etc/configure.ac
{
    autoheader [resolve etc/configure.ac] > [target];
}

[arch]/%0%.h: %0%.h.in [arch]/config.status
    single-thread conftest.subs
{
    CONFIG_FILES\= CONFIG_HEADERS\=[target]\:[resolve %0%.h.in]
        [resolve [arch]/config.status];
}

[arch]/%0%: %0%.in [arch]/config.status
    single-thread conftest.subs
{
    CONFIG_FILES\=[target]\:[resolve %0%.in] CONFIG_HEADERS\=
        [resolve [arch]/config.status];
}


/*
 * Make sure this directory is here,
 * otherwise the "../man1/?????.h" include files will
 * be found in the baseline.
 */
#ifdef baseline
if [not [exists [arch]/libtardy]] then
    mkdir -p [arch]/libtardy
        set clearstat;
#endif

[arch]/bin/%: [arch]/script/%
    if [and [not [defined %_obj]] [not [match %%.in %]] ]
{
    cp [need] [target];
    chmod 0755 [target];
}

all += etc/freshmeat.txt;


#include [resolve etc/archive.cook]
#include [resolve etc/doxygen.cook]
#include [resolve etc/tags.cook]
#include-cooked [resolve etc/refman.cook]
