#!/bin/sh
#
# Generated by qconf 2.0 ( https://github.com/psi-plus/qconf )
#

show_usage() {
cat <<EOT
Usage: $0 [OPTION]...

This script creates necessary configuration files to build/install.

Main options:
  --prefix=[path]       Base path for build/install.  Default: /usr/local
  --bindir=[path]       Directory for binaries.  Default: PREFIX/bin
  --libdir=[path]       Directory for libraries.  Default: PREFIX/lib
  --datadir=[path]      Directory for data.  Default: PREFIX/share
  --qtdir=[path]        Directory where Qt is installed.
  --extraconf=[conf]    Extra configuration for nonstandard cases.
  --verbose             Show extra configure output.
  --qtselect=[N]        Select major Qt version (4 or 5).
  --help                This help text.

Project options:
  --release                   Build with debugging turned off (default).
  --debug                     Build with debugging turned on.
  --no-separate-debug-info    Do not store debug information in a separate
                              file (default for mac).
  --separate-debug-info       Strip debug information into a separate .debug
                              file (default for non-mac).
  --psiplus                   Build Psi+ instead of Psi

Dependency options:
  --with-idn-inc=[path]            Path to libidn include files
  --with-idn-lib=[path]            Path to libidn library or framework files
  --with-qca-inc=[path]            Path to QCA include files
  --with-qca-lib=[path]            Path to QCA library or framework files
  --with-zlib-inc=[path]           Path to zlib include files
  --with-zlib-lib=[path]           Path to zlib library files
  --with-qjdns-inc=[path]          Path to QJDns include files
  --with-qjdns-lib=[path]          Path to QJDns library files
  --enable-universal               Enable use of Mac OS X universal binary
                                   support
  --disable-qdbus                  Disable use of QDBUS
  --disable-keychain               Disable use of Qt Keychain
  --enable-webkit                  Enable use of webkit
  --with-webkit=[type]             type of webkit QtWebKit/QtWebEngine
  --with-http-parser-inc=[path]    Path to HTTP Parser include files
  --with-http-parser-lib=[path]    Path to HTTP Parser library files
  --bundled-http-parser            Build with bundled HTTP Parser
  --with-b2-inc=[path]             Path to libb2 include files
  --with-b2-lib=[path]             Path to libb2 library or framework files
  --disable-growl                  Disable use of Growl
  --with-growl=[path]              Path to the Growl framework
  --enable-whiteboarding           Enable use of White Board support
  --disable-xss                    Disable use of the XScreenSaver extension
  --disable-aspell                 Disable use of aspell
  --with-aspell-inc=[path]         Path to Aspell include files
  --with-aspell-lib=[path]         Path to Aspell library files
  --disable-enchant                Disable use of enchant
  --disable-hunspell               Disable use of hunspell
  --with-hunspell-inc=[path]       Path to Hunspell include files
  --with-hunspell-lib=[path]       Path to Hunspell library files
  --disable-plugins                Disable use of Psi Plugin support

EOT
}

# which/make detection adapted from Qt
which_command() {
    ALL_MATCHES=
    if [ "$1" = "-a" ]; then
        ALL_MATCHES="-a"
        shift
    fi

    OLD_HOME=$HOME
    HOME=/dev/null
    export HOME

    WHICH=`which which 2>/dev/null`
    if echo $WHICH | grep 'shell built-in command' >/dev/null 2>&1; then
        WHICH=which
    elif [ -z "$WHICH" ]; then
        if which which >/dev/null 2>&1; then
            WHICH=which
        else
            for a in /usr/ucb /usr/bin /bin /usr/local/bin; do
                if [ -x $a/which ]; then
                    WHICH=$a/which
                    break
                fi
            done
        fi
    fi

    RET_CODE=1
    if [ -z "$WHICH" ]; then
        OLD_IFS=$IFS
        IFS=:
        for a in $PATH; do
            if [ -x $a/$1 ]; then
                echo "$a/$1"
                RET_CODE=0
                [ -z "$ALL_MATCHES" ] && break
            fi
        done
        IFS=$OLD_IFS
        export IFS
    else
        a=`"$WHICH" "$ALL_MATCHES" "$1" 2>/dev/null`
        if [ ! -z "$a" -a -x "$a" ]; then
            echo "$a"
            RET_CODE=0
        fi
    fi
    HOME=$OLD_HOME
    export HOME
    return $RET_CODE
}
WHICH=which_command

# find a make command
if [ -z "$MAKE" ]; then
    MAKE=
    for mk in gmake make; do
        if $WHICH $mk >/dev/null 2>&1; then
            MAKE=`$WHICH $mk`
            break
        fi
    done
    if [ -z "$MAKE" ]; then
        echo "You don't seem to have 'make' or 'gmake' in your PATH."
        echo "Cannot proceed."
        exit 1
    fi
fi

show_qt_info() {
    printf "Be sure you have a proper Qt 4.0+ build environment set up.  This means not\n"
    printf "just Qt, but also a C++ compiler, a make tool, and any other packages\n"
    printf "necessary for compiling C++ programs.\n"
    printf "\n"
    printf "If you are certain everything is installed, then it could be that Qt is not\n"
    printf "being recognized or that a different version of Qt is being detected by\n"
    printf "mistake (for example, this could happen if \$QTDIR is pointing to a Qt 3\n"
    printf "installation).  At least one of the following conditions must be satisfied:\n"
    printf "\n"
    printf " 1) --qtdir is set to the location of Qt\n"
    printf " 2) \$QTDIR is set to the location of Qt\n"
    printf " 3) QtCore is in the pkg-config database\n"
    printf " 4) qmake is in the \$PATH\n"
    printf "\n"
    printf "This script will use the first one it finds to be true, checked in the above\n"
    printf "order.  #3 and #4 are the recommended options.  #1 and #2 are mainly for\n"
    printf "overriding the system configuration.\n"
    printf "\n"
}

while [ $# -gt 0 ]; do
    optarg=`expr "x$1" : 'x[^=]*=\(.*\)'`
    case "$1" in
        --prefix=*)
            PREFIX=$optarg
            shift
            ;;

        --bindir=*)
            BINDIR=$optarg
            shift
            ;;

        --libdir=*)
            LIBDIR=$optarg
            shift
            ;;

        --datadir=*)
            DATADIR=$optarg
            shift
            ;;

        --qtdir=*)
            EX_QTDIR=$optarg
            shift
            ;;

        --extraconf=*)
            QC_EXTRACONF=$optarg
            shift
            ;;

        --release)
            QC_RELEASE="Y"
            shift
            ;;

        --debug)
            QC_DEBUG="Y"
            shift
            ;;

        --no-separate-debug-info)
            QC_NO_SEPARATE_DEBUG_INFO="Y"
            shift
            ;;

        --separate-debug-info)
            QC_SEPARATE_DEBUG_INFO="Y"
            shift
            ;;

        --psiplus)
            QC_PSIPLUS="Y"
            shift
            ;;

        --with-idn-inc=*)
            QC_WITH_IDN_INC=$optarg
            shift
            ;;

        --with-idn-lib=*)
            QC_WITH_IDN_LIB=$optarg
            shift
            ;;

        --with-qca-inc=*)
            QC_WITH_QCA_INC=$optarg
            shift
            ;;

        --with-qca-lib=*)
            QC_WITH_QCA_LIB=$optarg
            shift
            ;;

        --with-zlib-inc=*)
            QC_WITH_ZLIB_INC=$optarg
            shift
            ;;

        --with-zlib-lib=*)
            QC_WITH_ZLIB_LIB=$optarg
            shift
            ;;

        --with-qjdns-inc=*)
            QC_WITH_QJDNS_INC=$optarg
            shift
            ;;

        --with-qjdns-lib=*)
            QC_WITH_QJDNS_LIB=$optarg
            shift
            ;;

        --enable-universal)
            QC_ENABLE_universal="Y"
            shift
            ;;

        --disable-universal)
            QC_DEFAULT_DISABLE_universal="Y"
            shift
            ;;

        --disable-qdbus)
            QC_DISABLE_qdbus="Y"
            shift
            ;;

        --enable-qdbus)
            QC_DEFAULT_ENABLE_qdbus="Y"
            shift
            ;;

        --disable-keychain)
            QC_DISABLE_keychain="Y"
            shift
            ;;

        --enable-keychain)
            QC_DEFAULT_ENABLE_keychain="Y"
            shift
            ;;

        --enable-webkit)
            QC_ENABLE_webkit="Y"
            shift
            ;;

        --disable-webkit)
            QC_DEFAULT_DISABLE_webkit="Y"
            shift
            ;;

        --with-webkit=*)
            QC_WITH_WEBKIT=$optarg
            shift
            ;;

        --with-http-parser-inc=*)
            QC_WITH_HTTP_PARSER_INC=$optarg
            shift
            ;;

        --with-http-parser-lib=*)
            QC_WITH_HTTP_PARSER_LIB=$optarg
            shift
            ;;

        --bundled-http-parser)
            QC_BUNDLED_HTTP_PARSER="Y"
            shift
            ;;

        --with-b2-inc=*)
            QC_WITH_B2_INC=$optarg
            shift
            ;;

        --with-b2-lib=*)
            QC_WITH_B2_LIB=$optarg
            shift
            ;;

        --disable-growl)
            QC_DISABLE_growl="Y"
            shift
            ;;

        --enable-growl)
            QC_DEFAULT_ENABLE_growl="Y"
            shift
            ;;

        --with-growl=*)
            QC_WITH_GROWL=$optarg
            shift
            ;;

        --enable-whiteboarding)
            QC_ENABLE_whiteboarding="Y"
            shift
            ;;

        --disable-whiteboarding)
            QC_DEFAULT_DISABLE_whiteboarding="Y"
            shift
            ;;

        --disable-xss)
            QC_DISABLE_xss="Y"
            shift
            ;;

        --enable-xss)
            QC_DEFAULT_ENABLE_xss="Y"
            shift
            ;;

        --disable-aspell)
            QC_DISABLE_aspell="Y"
            shift
            ;;

        --enable-aspell)
            QC_DEFAULT_ENABLE_aspell="Y"
            shift
            ;;

        --with-aspell-inc=*)
            QC_WITH_ASPELL_INC=$optarg
            shift
            ;;

        --with-aspell-lib=*)
            QC_WITH_ASPELL_LIB=$optarg
            shift
            ;;

        --disable-enchant)
            QC_DISABLE_enchant="Y"
            shift
            ;;

        --enable-enchant)
            QC_DEFAULT_ENABLE_enchant="Y"
            shift
            ;;

        --disable-hunspell)
            QC_DISABLE_hunspell="Y"
            shift
            ;;

        --enable-hunspell)
            QC_DEFAULT_ENABLE_hunspell="Y"
            shift
            ;;

        --with-hunspell-inc=*)
            QC_WITH_HUNSPELL_INC=$optarg
            shift
            ;;

        --with-hunspell-lib=*)
            QC_WITH_HUNSPELL_LIB=$optarg
            shift
            ;;

        --disable-plugins)
            QC_DISABLE_plugins="Y"
            shift
            ;;

        --enable-plugins)
            QC_DEFAULT_ENABLE_plugins="Y"
            shift
            ;;

        --verbose)
            QC_VERBOSE="Y"
            shift
            ;;
        --qtselect=*)
            QC_QTSELECT="${optarg}"
            shift
            ;;
        --help) show_usage; exit ;;
        *) echo "configure: WARNING: unrecognized options: $1" >&2; shift; ;;
    esac
done

PREFIX=${PREFIX:-/usr/local}
BINDIR=${BINDIR:-$PREFIX/bin}
LIBDIR=${LIBDIR:-$PREFIX/lib}
DATADIR=${DATADIR:-$PREFIX/share}

echo "Configuring Psi ..."

if [ "$QC_VERBOSE" = "Y" ]; then
echo
echo PREFIX=$PREFIX
echo BINDIR=$BINDIR
echo LIBDIR=$LIBDIR
echo DATADIR=$DATADIR
echo EX_QTDIR=$EX_QTDIR
echo QC_EXTRACONF=$QC_EXTRACONF
echo QC_RELEASE=$QC_RELEASE
echo QC_DEBUG=$QC_DEBUG
echo QC_NO_SEPARATE_DEBUG_INFO=$QC_NO_SEPARATE_DEBUG_INFO
echo QC_SEPARATE_DEBUG_INFO=$QC_SEPARATE_DEBUG_INFO
echo QC_PSIPLUS=$QC_PSIPLUS
echo QC_WITH_IDN_INC=$QC_WITH_IDN_INC
echo QC_WITH_IDN_LIB=$QC_WITH_IDN_LIB
echo QC_WITH_QCA_INC=$QC_WITH_QCA_INC
echo QC_WITH_QCA_LIB=$QC_WITH_QCA_LIB
echo QC_WITH_ZLIB_INC=$QC_WITH_ZLIB_INC
echo QC_WITH_ZLIB_LIB=$QC_WITH_ZLIB_LIB
echo QC_WITH_QJDNS_INC=$QC_WITH_QJDNS_INC
echo QC_WITH_QJDNS_LIB=$QC_WITH_QJDNS_LIB
echo QC_ENABLE_universal=$QC_ENABLE_universal
echo QC_DEFAULT_DISABLE_universal=$QC_DEFAULT_DISABLE_universal
echo QC_DISABLE_qdbus=$QC_DISABLE_qdbus
echo QC_DEFAULT_ENABLE_qdbus=$QC_DEFAULT_ENABLE_qdbus
echo QC_DISABLE_keychain=$QC_DISABLE_keychain
echo QC_DEFAULT_ENABLE_keychain=$QC_DEFAULT_ENABLE_keychain
echo QC_ENABLE_webkit=$QC_ENABLE_webkit
echo QC_DEFAULT_DISABLE_webkit=$QC_DEFAULT_DISABLE_webkit
echo QC_WITH_WEBKIT=$QC_WITH_WEBKIT
echo QC_WITH_HTTP_PARSER_INC=$QC_WITH_HTTP_PARSER_INC
echo QC_WITH_HTTP_PARSER_LIB=$QC_WITH_HTTP_PARSER_LIB
echo QC_BUNDLED_HTTP_PARSER=$QC_BUNDLED_HTTP_PARSER
echo QC_WITH_B2_INC=$QC_WITH_B2_INC
echo QC_WITH_B2_LIB=$QC_WITH_B2_LIB
echo QC_DISABLE_growl=$QC_DISABLE_growl
echo QC_DEFAULT_ENABLE_growl=$QC_DEFAULT_ENABLE_growl
echo QC_WITH_GROWL=$QC_WITH_GROWL
echo QC_ENABLE_whiteboarding=$QC_ENABLE_whiteboarding
echo QC_DEFAULT_DISABLE_whiteboarding=$QC_DEFAULT_DISABLE_whiteboarding
echo QC_DISABLE_xss=$QC_DISABLE_xss
echo QC_DEFAULT_ENABLE_xss=$QC_DEFAULT_ENABLE_xss
echo QC_DISABLE_aspell=$QC_DISABLE_aspell
echo QC_DEFAULT_ENABLE_aspell=$QC_DEFAULT_ENABLE_aspell
echo QC_WITH_ASPELL_INC=$QC_WITH_ASPELL_INC
echo QC_WITH_ASPELL_LIB=$QC_WITH_ASPELL_LIB
echo QC_DISABLE_enchant=$QC_DISABLE_enchant
echo QC_DEFAULT_ENABLE_enchant=$QC_DEFAULT_ENABLE_enchant
echo QC_DISABLE_hunspell=$QC_DISABLE_hunspell
echo QC_DEFAULT_ENABLE_hunspell=$QC_DEFAULT_ENABLE_hunspell
echo QC_WITH_HUNSPELL_INC=$QC_WITH_HUNSPELL_INC
echo QC_WITH_HUNSPELL_LIB=$QC_WITH_HUNSPELL_LIB
echo QC_DISABLE_plugins=$QC_DISABLE_plugins
echo QC_DEFAULT_ENABLE_plugins=$QC_DEFAULT_ENABLE_plugins
echo
fi

printf "Verifying Qt build environment ... "

if [ -z "$QC_QTSELECT" ]; then
    QC_QTSELECT="$(echo $QT_SELECT | tr -d "qt")"
fi

if [ ! -z "$QC_QTSELECT" ]; then
    QTSEARCHTEXT="$QC_QTSELECT"
else
    QTSEARCHTEXT="4 or 5"
fi

# run qmake and check version
qmake_check() {
    if [ -x "$1" ]; then
        cmd="\"$1\" -query QT_VERSION"
        if [ "$QC_VERBOSE" = "Y" ]; then
            echo "running: $cmd"
        fi
        vout=`/bin/sh -c "$cmd" 2>&1`
        case "${vout}" in
            *.*.*)
                vmaj="${vout%%.*}"
                if [ ! -z "$QC_QTSELECT" ]; then
                    if [ "$vmaj" = "$QC_QTSELECT" ]; then
                        return 0
                    fi
                else
                    if [ "$vmaj" = "4" ] || [ "$vmaj" = "5" ]; then
                        return 0
                    fi
                fi
                ;;
        esac
        if [ "$QC_VERBOSE" = "Y" ]; then
            echo "Warning: $1 not for Qt ${QTSEARCHTEXT}"
        fi
    fi
    return 1
}

if [ "$QC_VERBOSE" = "Y" ]; then
    echo
fi

qm=""
qt4_names="qmake-qt4 qmake4"
qt5_names="qmake-qt5 qmake5"
names="qmake"
if [ -z "$QC_QTSELECT" ]; then
    names="${qt5_names} ${qt4_names} $names"
else
    if [ "$QC_QTSELECT" = "4" ]; then
        names="${qt4_names} $names"
    elif [ "$QC_QTSELECT" -ge "5" ]; then
        names="${qt5_names} $names"
    fi
fi

if [ -z "$qm" ] && [ ! -z "$EX_QTDIR" ]; then
    # qt4 check: --qtdir
    for n in $names; do
        qstr=$EX_QTDIR/bin/$n
        if qmake_check "$qstr"; then
            qm=$qstr
            break
        fi
    done
    if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then
        echo "Warning: qmake not found via --qtdir"
    fi

elif [ -z "$qm" ] && [ ! -z "$QTDIR" ]; then
    # qt4 check: QTDIR
    for n in $names; do
        qstr=$QTDIR/bin/$n
        if qmake_check "$qstr"; then
            qm=$qstr
            break
        fi
    done
    if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then
        echo "Warning: qmake not found via \$QTDIR"
    fi

else
    # Try all other implicit checks

    # qtchooser
    if [ -z "$qm" ]; then
        qtchooser=$($WHICH qtchooser 2>/dev/null)
        if [ ! -z "$qtchooser" ]; then
            if [ ! -z "$QC_QTSELECT" ]; then
                versions="$QC_QTSELECT"
            else
                cmd="$qtchooser --list-versions"
                if [ "$QC_VERBOSE" = "Y" ]; then
                    echo "running: $cmd"
                fi
                versions=`$cmd`
            fi
            for version in $versions; do
                cmd="$qtchooser -run-tool=qmake -qt=${version} -query QT_INSTALL_BINS"
                if [ "$QC_VERBOSE" = "Y" ]; then
                    echo "running: $cmd"
                fi
                qtbins=`$cmd 2>/dev/null`
                if [ ! -z "$qtbins" ] && qmake_check "$qtbins/qmake"; then
                    qm="$qtbins/qmake"
                    break
                fi
            done
        fi
    fi
    if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then
        echo "Warning: qmake not found via qtchooser"
    fi

    # qt4: pkg-config
    if [ -z "$qm" ]; then
        cmd="pkg-config QtCore --variable=exec_prefix"
        if [ "$QC_VERBOSE" = "Y" ]; then
            echo "running: $cmd"
        fi
        str=`$cmd 2>/dev/null`
        if [ ! -z "$str" ]; then
            for n in $names; do
                qstr=$str/bin/$n
                if qmake_check "$qstr"; then
                    qm=$qstr
                    break
                fi
            done
        fi
    fi
    if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then
        echo "Warning: qmake not found via pkg-config"
    fi

    # qmake in PATH
    if [ -z "$qm" ]; then
        for n in $names; do
            qstr=`$WHICH -a $n 2>/dev/null`
            for q in $qstr; do
                if qmake_check "$q"; then
                    qm="$q"
                    break
                fi
            done
            if [ ! -z "$qm" ]; then
                break
            fi
        done
    fi
    if [ -z "$qm" ] && [ "$QC_VERBOSE" = "Y" ]; then
        echo "Warning: qmake not found via \$PATH"
    fi

    # end of implicit checks
fi

if [ -z "$qm" ]; then
    if [ "$QC_VERBOSE" = "Y" ]; then
        echo " -> fail"
    else
        echo "fail"
    fi
    printf "\n"
    printf "Reason: Unable to find the 'qmake' tool for Qt ${QTSEARCHTEXT}.\n"
    printf "\n"
    show_qt_info
    exit 1;
fi
if [ "$QC_VERBOSE" = "Y" ]; then
    echo qmake found in "$qm"
fi

# try to determine the active makespec
defmakespec=$QMAKESPEC
if [ -z "$defmakespec" ]; then
    if $WHICH readlink >/dev/null 2>&1; then
        READLINK=`$WHICH readlink`
    fi
    if [ ! -z "$READLINK" ]; then
        qt_mkspecsdir=`"$qm" -query QT_INSTALL_DATA`/mkspecs
        if [ -d "$qt_mkspecsdir" ] && [ -h "$qt_mkspecsdir/default" ]; then
            defmakespec=`$READLINK $qt_mkspecsdir/default`
        fi
    fi
fi

if [ "$QC_VERBOSE" = "Y" ]; then
    echo makespec is $defmakespec
fi

qm_spec=""
# if the makespec is macx-xcode, force macx-g++
if [ "$defmakespec" = "macx-xcode" ]; then
    qm_spec=macx-g++
    QMAKESPEC=$qm_spec
    export QMAKESPEC
    if [ "$QC_VERBOSE" = "Y" ]; then
        echo overriding makespec to $qm_spec
    fi
fi

gen_files() {
cat >"$1/modules.cpp" <<EOT
#line 1 "qt5.qcm"
/*
-----BEGIN QCMOD-----
name: Qt >= 5.0.0
-----END QCMOD-----
*/
class qc_qt5 : public ConfObj {
public:
    qc_qt5(Conf *c) : ConfObj(c) { }
    QString name() const { return "Qt >= 5.0.0"; }
    QString shortname() const { return "qt5"; }
    bool    exec() { return (QT_VERSION >= 0x050000); }

    QString resultString() const { return QT_VERSION_STR; }
};

class QtCompFinder : public ConfObj {
protected:
    QString compId;
    QString compShortName;
    QString compName;
    QString extraConfIfFound;
    QString finderResult;

public:
    /**
     * id - (QT += <id>)
     * shortName - used with QC_ENABLE_<shortName> | QC_DISABLE_<shortName> env vars
     *             MUST MATCH with qcm module name without extension
     * name - something visible in the log
     * extraConfIfFound - extra string added to conf.pri if found
     */
    QtCompFinder(const QString &id, const QString &shortName, const QString &name, const QString &extraConfIfFound,
                 Conf *c) :
        ConfObj(c),
        compId(id), compShortName(shortName), compName(name), extraConfIfFound(extraConfIfFound)
    {
    }

    QString name() const { return compName; }
    QString shortname() const { return compShortName; }
    QString resultString() const
    {
        if (!finderResult.isEmpty())
            return finderResult;

        return ConfObj::resultString();
    }

    bool exec()
    {
        if (!conf->getenv("QC_DISABLE_" + compShortName).isEmpty()) {
            finderResult = "disabled";
            return false;
        }

        QString proextra = "CONFIG += qt\\n"
                           "QT -= gui\\n"
                           "QT += ";

        proextra += compId;

        QString str = "\\n"
                      "int main()\\n"
                      "{\\n"
                      "    return 0;\\n"
                      "}\\n";

        int ret;
        if (!conf->doCompileAndLink(str, QStringList(), QString(), proextra, &ret))
            return false;
        if (ret != 0)
            return false;

        if (!extraConfIfFound.isEmpty()) {
            conf->addExtra(extraConfIfFound);
        }

        return true;
    }
};

#define QC_AS_STR(s) #s

#define QC_SILENT_NOT_FOUND(modname)                                                                                   \\
    class qc_##modname : public ConfObj {                                                                              \\
    public:                                                                                                            \\
        qc_##modname(Conf *c) : ConfObj(c) { }                                                                         \\
        QString name() const { return QC_AS_STR(modname); }                                                            \\
        QString shortname() const { return QC_AS_STR(modname); }                                                       \\
        QString checkString() const { return QString(); }                                                              \\
        bool    exec() { return false; }                                                                               \\
    };

#define QC_FIND_QT_COMP_BASE(id, shortname, name, extraConfIfFound, suffix)                                            \\
    class qc_##shortname##suffix : public QtCompFinder {                                                               \\
    public:                                                                                                            \\
        qc_##shortname##suffix(Conf *c) :                                                                              \\
            QtCompFinder(QC_AS_STR(id), QC_AS_STR(shortname), QC_AS_STR(name), extraConfIfFound, c)                    \\
        {                                                                                                              \\
        }                                                                                                              \\
    };

#define QC_FIND_QT_COMP_E(id, shortname, name, extraConfIfFound)                                                       \\
    QC_FIND_QT_COMP_BASE(id, shortname, name, extraConfIfFound, )
#define QC_FIND_QT_COMP(id, shortname, name) QC_FIND_QT_COMP_E(id, shortname, name, "")
#line 1 "buildmodeapp.qcm"
/*
-----BEGIN QCMOD-----
name: buildmodeapp
section: project
arg: release,Build with debugging turned off (default).
arg: debug,Build with debugging turned on.
arg: no-separate-debug-info,Do not store debug information in a separate file (default for mac).
arg: separate-debug-info,Strip debug information into a separate .debug file (default for non-mac).
arg: psiplus,Build Psi+ instead of Psi
-----END QCMOD-----
arg: debug-and-release,Build two versions, with and without debugging turned on (mac only).
*/

#include <QRegExp>

#define QC_BUILDMODE
bool    qc_buildmode_release             = false;
bool    qc_buildmode_debug               = false;
bool    qc_buildmode_separate_debug_info = false;
bool    qc_psiplus                       = false;
QString qc_psi_dir_name                  = "psi";

static QString sourceDir;

// this is a utility function required by few other modules
static bool psiGenerateFile(const QString &inFile, const QString &outFile, const QHash<QString, QString> &vars)
{
    QFile fin(inFile);
    QFile fout(outFile);
    if (!fin.open(QIODevice::ReadOnly | QIODevice::Text) || !fout.open(QIODevice::WriteOnly | QIODevice::Truncate))
        return false;

    QRegExp     re("@[^@]*@");
    QTextStream tin(&fin);
    QTextStream tout(&fout);
    while (!tin.atEnd()) {
        QString line = tin.readLine();

        QHashIterator<QString, QString> it(vars);
        while (it.hasNext()) {
            it.next();
            line.replace("@" + it.key() + "@", it.value());
        }
        line.replace(re, "");
        line.replace("#cmakedefine", "#define");

        tout << line << endl;
    }

    return true;
}

void copyPath(QString src, QString dst)
{
    QDir dir(src);
    if (!dir.exists())
        return;

    for (const QString &d : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
        QString dst_path = dst + QDir::separator() + d;
        dir.mkpath(dst_path);
        copyPath(src + QDir::separator() + d, dst_path);
    }

    for (const QString &f : dir.entryList(QDir::Files)) {
        QFile::copy(src + QDir::separator() + f, dst + QDir::separator() + f);
    }
}

class qc_buildmodeapp : public ConfObj {
public:
    qc_buildmodeapp(Conf *c) : ConfObj(c) { }
    QString name() const { return "buildmodeapp"; }
    QString shortname() const { return "buildmodeapp"; }

    // no output
    QString checkString() const { return QString(); }

    bool exec()
    {
        QFileInfo fi(qc_getenv("QC_COMMAND"));
        sourceDir = fi.absolutePath();

        // first, parse out the options
        bool opt_release                = false;
        bool opt_debug                  = false;
        bool opt_debug_and_release      = false;
        bool opt_no_separate_debug_info = false;
        bool opt_separate_debug_info    = false;

        if (conf->getenv("QC_RELEASE") == "Y")
            opt_release = true;
        if (conf->getenv("QC_DEBUG") == "Y")
            opt_debug = true;
        if (conf->getenv("QC_DEBUG_AND_RELEASE") == "Y")
            opt_debug_and_release = true;
        if (conf->getenv("QC_NO_SEPARATE_DEBUG_INFO") == "Y")
            opt_no_separate_debug_info = true;
        if (conf->getenv("QC_SEPARATE_DEBUG_INFO") == "Y")
            opt_separate_debug_info = true;

        bool staticmode = false;
        if (conf->getenv("QC_STATIC") == "Y")
            staticmode = true;

#ifndef Q_OS_MAC
        if (opt_debug_and_release) {
            printf("\\nError: The --debug-and-release option is for mac only.\\n");
            exit(1);
        }
#endif

        // sanity check exclusive options
        int x;

        // build mode
        x = 0;
        if (opt_release)
            ++x;
        if (opt_debug)
            ++x;
        if (opt_debug_and_release)
            ++x;
        if (x > 1) {
            printf("\\nError: Use only one of --release, --debug, or --debug-and-release.\\n");
            exit(1);
        }

        // debug info
        x = 0;
        if (opt_no_separate_debug_info)
            ++x;
        if (opt_separate_debug_info)
            ++x;
        if (x > 1) {
            printf("\\nError: Use only one of --separate-debug-info or --no-separate-debug-info\\n");
            exit(1);
        }

        // now process the options

        if (opt_release)
            qc_buildmode_release = true;
        else if (opt_debug)
            qc_buildmode_debug = true;
        else if (opt_debug_and_release) {
            qc_buildmode_release = true;
            qc_buildmode_debug   = true;
        } else // default
            qc_buildmode_release = true;

        if (opt_separate_debug_info)
            qc_buildmode_separate_debug_info = true;
        else if (opt_no_separate_debug_info) {
            // nothing to do
        } else // default
        {
#ifndef Q_OS_MAC
            qc_buildmode_separate_debug_info = true;
#endif
        }

        // make the string
        QStringList opts;
        QString     other;

        if (qc_buildmode_release && qc_buildmode_debug) {
            opts += "debug_and_release";
            opts += "build_all";
        } else if (qc_buildmode_release)
            opts += "release";
        else // qc_buildmode_debug
            opts += "debug";

        if (qc_buildmode_separate_debug_info) {
            opts += "separate_debug_info";
            other += "*-g++*:QMAKE_CFLAGS += -g\\n";
            other += "*-g++*:QMAKE_CXXFLAGS += -g\\n";
        }

        QString str = "CONFIG -= debug_and_release debug release\\n";
        str += QString("CONFIG += ") + opts.join(" ") + '\\n';
        conf->addExtra(str);

        if (!other.isEmpty())
            conf->addExtra(other);

        // rebranding
        qc_psiplus = conf->getenv("QC_PSIPLUS") == "Y";
        if (qc_psiplus) {
            qc_psi_dir_name = "psi-plus";
            conf->addDefine("PSI_PLUS");
            conf->addExtra("CONFIG += psiplus");
        }

        return true;
    }
};
#line 1 "idn.qcm"
/*
-----BEGIN QCMOD-----
name: libidn
arg: with-idn-inc=[path],Path to libidn include files
arg: with-idn-lib=[path],Path to libidn library or framework files
-----END QCMOD-----
*/

/*
Warning: libidn is somewhat deprecated in favor of libidn2, but we can't just
drop it since IDNA2008 doesn't include XMPP profiles and has nothing from
stringprep. This stuff was moved to RFC8264 and RFC8265 and its usage was
described in RFC7622. There are no known C/C++ implementations of these specs
at the moment of this writing. A partial and not sufficient implementation can
be found at https://gitlab.com/gnutls/gnutls/blob/master/lib/str-unicode.c. It
implements OpaqueString Profile but doesn't implement UsernameCaseMapped
profile required by RFC7622. Note it may be also desired to implement RFC8266.

Some implementations in other languages:
Go: https://godoc.org/golang.org/x/text/secure/precis
Python: https://pypi.org/project/precis-i18n/
Perl: https://metacpan.org/release/Unicode-Precis
PHP: https://github.com/tom--/precis

We can try to use https://github.com/lpereira/gomoku to convert from Go.
*/

//----------------------------------------------------------------------------
// qc_idn
//----------------------------------------------------------------------------
class qc_idn : public ConfObj {
public:
    qc_idn(Conf *c) : ConfObj(c) { }
    QString name() const { return "LibIDN"; }
    QString shortname() const { return "libidn"; }
    bool    exec()
    {
        QString idn_incdir, idn_libdir, idn_prefixdir;
        idn_incdir    = conf->getenv("QC_WITH_IDN_INC");
        idn_libdir    = conf->getenv("QC_WITH_IDN_LIB");
        idn_prefixdir = conf->getenv("PREFIX");

        if (!idn_incdir.isEmpty() || !idn_libdir.isEmpty() || !idn_prefixdir.isEmpty()) { // prefer this if given
            if ((!idn_incdir.isEmpty() && conf->checkHeader(idn_incdir, "stringprep.h"))
                || (idn_incdir.isEmpty() && conf->findHeader("stringprep.h", QStringList(), &idn_incdir))) {
                conf->addIncludePath(idn_incdir);
            } else {
                printf("Headers not found!\\n");
                return false;
            }

#ifdef Q_OS_WIN
            conf->addDefine("LIBIDN_STATIC"); // it's need only for iris anyway
            QString     staticLibName  = qc_buildmode_debug ? "libidnd" : "libidn";
            QString     dynamicLibName = qc_buildmode_debug ? "idnd" : "idn";
            QStringList libNames       = QStringList() << staticLibName << dynamicLibName;
#else
            QStringList libNames = QStringList() << "idn";
#endif
            bool libFound = false;
            for (const QString &libName : libNames) {
                if ((!idn_libdir.isEmpty() && conf->checkLibrary(idn_libdir, libName))
                    || (idn_libdir.isEmpty() && conf->findLibrary(libName, &idn_libdir))) {
                    conf->addLib(idn_libdir.isEmpty() ? QString("-l") + libName
                                                      : QString("-L%1 -l%2").arg(idn_libdir, libName));
                    libFound = true;
                    break;
                }
            }
            if (!libFound) {
                printf("Libraries not found!\\n");
            }
            return libFound;
        }

        QStringList incs;
        QString     version, libs, other;
        if (conf->findPkgConfig("libidn", VersionAny, QString(), &version, &incs, &libs, &other)) {
            for (int n = 0; n < incs.count(); ++n)
                conf->addIncludePath(incs[n]);
            if (!libs.isEmpty())
                conf->addLib(libs);
            return true;
        }

        return false;
    }
};
#line 1 "qca.qcm"
/*
-----BEGIN QCMOD-----
name: QCA >= 2.0
arg: with-qca-inc=[path],Path to QCA include files
arg: with-qca-lib=[path],Path to QCA library or framework files
-----END QCMOD-----
*/

// adapted from crypto.prf
static QString internal_crypto_prf(const QString &incdir, const QString &libdir, const QString &frameworkdir)
{
    QString out = QString("QCA_INCDIR = %1\\n"
                          "QCA_LIBDIR = %2\\n"
                          "QMAKE_RPATHDIR = %2\\n"
                          "QCA_FRAMEWORKDIR = %3\\n"
                          "\\n"
                          "CONFIG *= qt\\n"
                          "\\n"
                          "LINKAGE =\\n"
                          "QCA_NAME = qca-qt5\\n"
                          "\\n"
                          "!isEmpty(QCA_FRAMEWORKDIR): {\\n"
                          "    framework_dir = \$\$QCA_FRAMEWORKDIR\\n"
                          "    exists(\$\$framework_dir/\$\${QCA_NAME}.framework) {\\n"
                          "        #QMAKE_FRAMEWORKPATH *= \$\$framework_dir\\n"
                          "        LIBS *= -F\$\$framework_dir\\n"
                          "        INCLUDEPATH += \$\$framework_dir/\$\${QCA_NAME}.framework/Headers\\n"
                          "        LINKAGE = -framework \$\${QCA_NAME}\\n"
                          "    }\\n"
                          "}\\n"
                          "\\n"
                          "# else, link normally\\n"
                          "isEmpty(LINKAGE) {\\n"
                          "    !isEmpty(QCA_INCDIR):INCLUDEPATH += \$\$QCA_INCDIR/QtCrypto\\n"
                          "    !isEmpty(QCA_LIBDIR):LIBS += -L\$\$QCA_LIBDIR\\n"
                          "    LINKAGE = -l\$\${QCA_NAME}\\n"
                          "    CONFIG(debug, debug|release) {\\n"
                          "        windows:LINKAGE = -l\$\${QCA_NAME}d\\n"
                          "        mac:LINKAGE = -l\$\${QCA_NAME}_debug\\n"
                          "    }\\n"
                          "}\\n"
                          "\\n"
                          "LIBS += \$\$LINKAGE\\n")
                      .arg(incdir, libdir, frameworkdir);
    return out;
}

// set either libdir or frameworkdir, but not both
static bool qca_try(Conf *conf, const QString &incdir, const QString &libdir, const QString &frameworkdir, bool release,
                    bool debug, QString *_prf)
{
    QString proextra;
    QString prf;
    if (!incdir.isEmpty() || !libdir.isEmpty() || !frameworkdir.isEmpty()) {
        prf = internal_crypto_prf(conf->escapePath(incdir), conf->escapePath(libdir), frameworkdir);
    } else {
        prf = "CONFIG += crypto\\n";
    }
    proextra = "CONFIG += qt\\n"
               "CONFIG -= debug_and_release debug release\\n"
               "QT -= gui\\n";
    proextra += prf;

    QString str = "#include <QtCrypto>\\n"
                  "\\n"
                  "int main()\\n"
                  "{\\n"
                  "    unsigned long x = QCA_VERSION;\\n"
                  "    if(x >= 0x020000 && x < 0x030000) return 0; else return 1;\\n"
                  "}\\n";

    // test desired versions, potentially both release and debug

    if (release) {
        int ret;
        if (!conf->doCompileAndLink(str, QStringList(), QString(), proextra + "CONFIG += release\\n", &ret) || ret != 0)
            return false;
    }

    if (debug) {
        int ret;
        if (!conf->doCompileAndLink(str, QStringList(), QString(), proextra + "CONFIG += debug\\n", &ret) || ret != 0)
            return false;
    }

    *_prf = prf;
    return true;
}

static bool qca_try_lib(Conf *conf, const QString &incdir, const QString &libdir, bool release, bool debug,
                        QString *prf)
{
    return qca_try(conf, incdir, libdir, QString(), release, debug, prf)
        || qca_try(conf, incdir + "/Qca-qt5", libdir, QString(), release, debug, prf);
}

static bool qca_try_framework(Conf *conf, const QString &frameworkdir, bool release, bool debug, QString *prf)
{
    return qca_try(conf, QString(), QString(), frameworkdir, release, debug, prf);
}

static bool qca_try_ext_prf(Conf *conf, bool release, bool debug, QString *prf)
{
    return qca_try(conf, QString(), QString(), QString(), release, debug, prf);
}

//----------------------------------------------------------------------------
// qc_qca
//----------------------------------------------------------------------------
class qc_qca : public ConfObj {
public:
    qc_qca(Conf *c) : ConfObj(c) { }
    QString name() const { return "QCA >= 2.0"; }
    QString shortname() const { return "qca"; }
    bool    exec()
    {
        // get the build mode
#ifdef QC_BUILDMODE
        bool release = qc_buildmode_release;
        bool debug   = qc_buildmode_debug;
#else
        // else, default to just release mode
        bool release = true;
        bool debug   = false;
#endif

        QString qca_incdir, qca_libdir, qca_crypto_prf;
        qca_incdir = conf->getenv("QC_WITH_QCA_INC");
        qca_libdir = conf->getenv("QC_WITH_QCA_LIB");

#if defined(Q_OS_MAC)
        if (!qca_libdir.isEmpty() && qca_try_framework(conf, qca_libdir, release, debug, &qca_crypto_prf)) {
            conf->addExtra(qca_crypto_prf);
            return true;
        }
#endif

        if (!qca_incdir.isEmpty() && !qca_libdir.isEmpty()
            && qca_try_lib(conf, qca_incdir, qca_libdir, release, debug, &qca_crypto_prf)) {
            conf->addExtra(qca_crypto_prf);
            return true;
        }

        if (qca_try_ext_prf(conf, release, debug, &qca_crypto_prf)) {
            conf->addExtra(qca_crypto_prf);
            return true;
        }

        QStringList incs;
        QString     version, libs, other;

        if (conf->findPkgConfig("qca2-qt5", VersionMin, "2.0.0", &version, &incs, &libs, &other)) {
            for (int n = 0; n < incs.count(); ++n)
                conf->addIncludePath(incs[n]);
            if (!libs.isEmpty())
                conf->addLib(libs);
            return true;
        }

        QStringList prefixes;
#ifndef Q_OS_WIN
        prefixes += "/usr";
        prefixes += "/usr/local";
#endif
        QString prefix = conf->getenv("PREFIX");
        if (!prefix.isEmpty()) {
            prefixes += prefix;
        }

        for (int n = 0; n < prefixes.count(); ++n) {
            const QString &prefix = prefixes[n];
            if (qca_try_lib(conf, prefix + "/include", prefix + "/lib", release, debug, &qca_crypto_prf)) {
                conf->addExtra(qca_crypto_prf);
                return true;
            }
        }

        return false;
    }
};
#line 1 "zlib.qcm"
/*
-----BEGIN QCMOD-----
name: zlib
arg: with-zlib-inc=[path],Path to zlib include files
arg: with-zlib-lib=[path],Path to zlib library files
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_zlib
//----------------------------------------------------------------------------
class qc_zlib : public ConfObj {
public:
    qc_zlib(Conf *c) : ConfObj(c) { }
    QString name() const { return "zlib"; }
    QString shortname() const { return "zlib"; }

    bool exec()
    {
        QStringList incs;
        QString     version, libs, other;
        QString     s;

        if (!conf->findPkgConfig("zlib", VersionAny, "", &version, &incs, &libs, &other)) {

            s = conf->getenv("QC_WITH_ZLIB_INC");
            if (!s.isEmpty()) {
                if (!conf->checkHeader(s, "zlib.h"))
                    return false;
            } else {
                if (!conf->findHeader("zlib.h", QStringList(), &s))
                    return false;
            }

            QStringList libNames = QStringList() << "z";
            QString     libName;
#ifdef Q_OS_WIN
            libNames << (qc_buildmode_debug ? "zlibd" : "zlib");
#endif
            for (;;) {
                s = conf->getenv("QC_WITH_ZLIB_LIB");
                if (!s.isEmpty()) {
                    for (const QString l : libNames)
                        if (conf->checkLibrary(s, l)) {
                            libName = l;
                            break;
                        }
                } else {
                    for (const QString l : libNames)
                        if (conf->findLibrary(l, &s)) {
                            libName = l;
                            break;
                        }
                }

                if (!libName.isEmpty())
                    break;

                return false;
            }
            if (!s.isEmpty()) {
                libs = QString("-L%1 -l%2").arg(s, libName);
            } else {
                libs = s.isEmpty() ? QString("-l") + libName : QString("-L%1 -l%2").arg(s, libName);
            }
        }

        for (const QString &inc : incs) {
            conf->addIncludePath(inc);
        }
        conf->addLib(libs);

#ifdef Q_OS_WIN
        // HACK: on windows, always use psi's bundled minizip
        conf->addExtra("CONFIG += psi-minizip");
        return true;
#else
        incs.clear();
        libs.clear();
        if (!conf->findPkgConfig("minizip", VersionAny, "", &version, &incs, &libs, &other)) {

            s = conf->getenv("QC_WITH_MINIZIP_INC");
            if ((!s.isEmpty() && conf->checkHeader(s, "unzip.h"))
                || (s.isEmpty() && conf->findHeader("unzip.h", QStringList(), &s))) {
                incs.append(s);
            }

            s = conf->getenv("QC_WITH_MINIZIP_LIB");
            if ((!s.isEmpty() && conf->checkLibrary(s, "minizip"))
                || (s.isEmpty() && conf->findLibrary("minizip", &s))) {
                libs = s.isEmpty() ? "-lminizip" : QString("-L%1 -lminizip").arg(s);
            }
        }

        if (!incs.isEmpty() && !libs.isEmpty()) {
            for (const QString &inc : incs) {
                conf->addIncludePath(inc);
            }
            conf->addLib(libs);
        } else {
            conf->addExtra("CONFIG += psi-minizip");
            conf->addExtra("bsd:DEFINES += IOAPI_NO_64");
        }

        return true;
#endif
    }
};
#line 1 "qjdns.qcm"
/*
-----BEGIN QCMOD-----
name: jdns
arg: with-qjdns-inc=[path],Path to QJDns include files
arg: with-qjdns-lib=[path],Path to QJDns library files
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_qjdns
//----------------------------------------------------------------------------
class qc_qjdns : public ConfObj {
public:
    qc_qjdns(Conf *c) : ConfObj(c) { }
    QString name() const { return "QJDns"; }
    QString shortname() const { return "qjdns"; }
    QString resultString() const
    {
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
        return "Disabled for Qt5 and above";
#else
        return ConfObj::resultString();
#endif
    }
    bool exec()
    {
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
        return true; // hack. TODO: figure out how to force jdns
#endif
        conf->addExtra("CONFIG += need_jdns");
#if defined Q_OS_WIN || defined Q_OS_MAC
        // HACK: on Windows and Mac OS X, always use psi's bundled qjdns
        conf->addExtra("CONFIG += iris-qjdns");
        return true;
#else
        QStringList incs;
        QString     version, libs, other;
        QString     s;

        bool found = conf->findPkgConfig("qjdns-qt5", VersionMin, "2.0.3", &version, &incs, &libs, &other);
        if (!found && !conf->findPkgConfig("qjdns", VersionMin, "2.0.0", &version, &incs, &libs, &other)) {
            s = conf->getenv("QC_WITH_QJDNS_INC");
            if ((!s.isEmpty() && conf->checkHeader(s, "qjdns.h"))
                || (s.isEmpty() && conf->findHeader("qjdns.h", QStringList(), &s))) {
                incs.append(s);
            }

            s = conf->getenv("QC_WITH_QJDNS_LIB");
            if ((!s.isEmpty() && conf->checkLibrary(s, "qjdns")) || (s.isEmpty() && conf->findLibrary("qjdns", &s))) {
                libs = s.isEmpty() ? "-lqjdns -ljdns" : QString("-L%1 -lqjdns -ljdns").arg(s);
            }
        }

        if (!incs.isEmpty() && !libs.isEmpty()) {
            for (const QString &inc : incs) {
                conf->addIncludePath(inc);
            }
            conf->addLib(libs);
            conf->addExtra("CONFIG += ext-qjdns");
        }

        return true;
#endif
    }
};
#line 1 "x11.qcm"
/*
-----BEGIN QCMOD-----
name: Xorg X11
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_x11
//----------------------------------------------------------------------------
class qc_x11 : public ConfObj {
public:
    qc_x11(Conf *c) : ConfObj(c) { }

    QString name() const { return "Xorg X11"; }
    QString shortname() const { return "x11"; }
    QString checkString() const { return QString(); }

    bool exec()
    {
        QString str = "int main()\\n"
                      "{\\n"
                      "    return 0;\\n"
                      "}\\n";
        QString proextra = "CONFIG += x11\\n";
#if QT_VERSION >= 0x050000 && defined Q_OS_LINUX
        proextra += "LIBS += -lxcb\\n";
        proextra += "QT += x11extras\\n";
#endif
        return conf->doCompileAndLink(str, QStringList(), QString(), proextra, nullptr);
    }
};
#line 1 "universal.qcm"
/*
-----BEGIN QCMOD-----
name: Mac OS X universal binary support
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_universal
//----------------------------------------------------------------------------
class qc_universal : public ConfObj {
public:
    qc_universal(Conf *c) : ConfObj(c) { }
    QString name() const { return "universal binary support"; }
    QString shortname() const { return "universal"; }
    QString checkString() const { return QString(); }

    bool exec()
    {
#ifdef Q_OS_MAC
        conf->addExtra("CONFIG += qc_universal");
#endif
        return true;
    }
};
#line 1 "qdbus.qcm"
/*
-----BEGIN QCMOD-----
name: QDBUS
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_qdbus
//----------------------------------------------------------------------------

#ifdef Q_OS_WIN
QC_SILENT_NOT_FOUND(qdbus)
#else
// id, shortname, name, extraConfIfFound
QC_FIND_QT_COMP_E(dbus, qdbus, QtDbus, "CONFIG += dbus")
#endif
#line 1 "keychain.qcm"
/*
-----BEGIN QCMOD-----
name: Qt Keychain
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_keychain
//----------------------------------------------------------------------------
// id, shortname, name, extraConfIfFound
QC_FIND_QT_COMP_BASE(Qt5Keychain, keychain, Qt Keychain, "CONFIG += keychain", _base)

class qc_keychain : public qc_keychain_base {
public:
    qc_keychain(Conf *c) : qc_keychain_base(c) { }

    bool exec()
    {
        if (qc_keychain_base::exec()) {
            conf->addExtra("CONFIG += keychain_with_qtmodule");

            // some systems with keychain < 0.10.0 have invalid Qt module for Qt5Keychain. let's check.
            QString str = "int main()\\n"
                          "{\\n"
                          "    QKeychain::Job().settings();\\n"
                          "    return 0;\\n"
                          "}\\n";
            if (conf->doCompileAndLink(str, QStringList(), QString(), "QT += Qt5Keychain"))
                return true;
        }

        // try to find by path
        QString s;
        if (!conf->findHeader("qt5keychain/keychain.h", QStringList(), &s)) {
            qWarning("keychain header qt5keychain/keychain.h is not found");
            return false;
        }

        QStringList libnames;
#ifdef _MSC_VER
#ifdef QC_BUILDMODE
        libnames += (qc_buildmode_debug ? "libqt5keychaind" : "libqt5keychain"); // possibly static
        libnames += (qc_buildmode_debug ? "qt5keychaind" : "qt5keychain");       // possibly dynamic
#else
        libnames << "libqt5keychain"
                 << "qt5keychain";
#endif
#else
        libnames << "qt5keychain";
#endif
        QString libName;
        for (const QString l : libnames)
            if (conf->findLibrary(l, &s)) {
                libName = l;
                break;
            }

        if (libName.isEmpty()) {
            qWarning("keychain library qt5keychain is not found");
            return false;
        }
        conf->addLib(QString("-L%1 -l%2").arg(s, libName));

        // header and library were found by default paths. lets just add extra
        conf->addExtra(extraConfIfFound);
        return true;
    }
};
#line 1 "qtmultimedia.qcm"
/*
-----BEGIN QCMOD-----
name: QtMultimedia
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_qtmultimedia
//----------------------------------------------------------------------------
// id, shortname, name
QC_FIND_QT_COMP(multimedia, qtmultimedia, QtMultimedia)
#line 1 "qtconcurrent.qcm"
/*
-----BEGIN QCMOD-----
name: QtConcurrent
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_qtconcurrent
//----------------------------------------------------------------------------
// id, shortname, name
QC_FIND_QT_COMP(concurrent, qtconcurrent, QtConcurrent)
#line 1 "qtsql.qcm"
/*
-----BEGIN QCMOD-----
name: QtSql
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_qtsql
//----------------------------------------------------------------------------
// id, shortname, name
QC_FIND_QT_COMP(sql, qtsql, QtSql)
#line 1 "qtwidgets.qcm"
/*
-----BEGIN QCMOD-----
name: QtWidgets
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_qtwidgets
//----------------------------------------------------------------------------
// id, shortname, name
QC_FIND_QT_COMP(widgets, qtwidgets, QtWidgets)
#line 1 "qtnetwork.qcm"
/*
-----BEGIN QCMOD-----
name: QtNetwork
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_qtnetwork
//----------------------------------------------------------------------------
// id, shortname, name
QC_FIND_QT_COMP(network, qtnetwork, QtNetwork)
#line 1 "qtsvg.qcm"
/*
-----BEGIN QCMOD-----
name: QtSvg
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_qtsvg
//----------------------------------------------------------------------------
// id, shortname, name
QC_FIND_QT_COMP(network, qtsvg, QtSvg)
#line 1 "qtxml.qcm"
/*
-----BEGIN QCMOD-----
name: QtXml
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_qtxml
//----------------------------------------------------------------------------
// id, shortname, name
QC_FIND_QT_COMP(xml, qtxml, QtXml)
#line 1 "webkit.qcm"
/*
-----BEGIN QCMOD-----
name: webkit
arg: with-webkit=[type],type of webkit QtWebKit/QtWebEngine
-----END QCMOD-----
*/

QString qc_webkit_type;

//----------------------------------------------------------------------------
// qc_webkit
//----------------------------------------------------------------------------
class qc_webkit : public ConfObj {
    QString webkitType;

public:
    qc_webkit(Conf *c) : ConfObj(c) { }
    QString name() const { return "QtWebKit"; }
    QString shortname() const { return "webkit"; }
    bool    exec()
    {
        if (!conf->getenv("QC_DISABLE_webkit").isEmpty()) {
            webkitType = "disabled";
            return false;
        }

        QStringList tryList;
        QString     wt = conf->getenv("QC_WITH_WEBKIT").toLower();
        if (wt.isEmpty() || !(wt == "qtwebkit" || wt == "qtwebengine")) {
#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
            tryList << "qtwebengine"
                    << "qtwebkit";
#else
            tryList << "qtwebkit";
#endif
        } else {
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0)
            if (wt == "qtwebengine") {
                webkitType = "unsupported";
                return false;
            }
#endif
            tryList << wt;
        }

        QString qt;
        for (const QString &wt : tryList) {
            if (wt == "qtwebengine") {
                webkitType = "QtWebEngine";
                qt         = "webenginewidgets webchannel";
            } else {
                webkitType = "QtWebKit";
                qt         = "webkit webkitwidgets";
            }

            QString proextra = "CONFIG += qt webkit\\n";
            proextra += "QT += " + qt + "\\n";

            QString str = "\\n"
                          "int main()\\n"
                          "{\\n"
                          "    return 0;\\n"
                          "}\\n";

            int ret;
            if (!conf->doCompileAndLink(str, QStringList(), QString(), proextra, &ret))
                continue;
            if (ret != 0)
                continue;

            conf->addExtra("CONFIG += " + wt);
            qc_webkit_type = wt;
            return true;
        }

        webkitType = "not found";

        return false;
    }

    QString resultString() const { return webkitType; }
};
#line 1 "http-parser.qcm"
/*
-----BEGIN QCMOD-----
name: hunspell
arg: with-http-parser-inc=[path],Path to HTTP Parser include files
arg: with-http-parser-lib=[path],Path to HTTP Parser library files
arg: bundled-http-parser,Build with bundled HTTP Parser
-----END QCMOD-----
*/

#define QC_HTTP_PARSER
bool qc_use_http_parser = false;

//----------------------------------------------------------------------------
// qc_http_parser
//----------------------------------------------------------------------------
class qc_http_parser : public ConfObj {
    bool use_bundled;

public:
    qc_http_parser(Conf *c) : ConfObj(c), use_bundled(false) { }
    QString name() const { return "HTTP Parser"; }
    QString shortname() const { return "httpparser"; }

    QString resultString() const
    {
        if (qc_use_http_parser) {
            if (use_bundled)
                return "bundled";
            return ConfObj::resultString();
        }
        return "Not needed w/o webengine";
    }

    bool exec()
    {
#ifdef Q_OS_UNIX
        qc_use_http_parser = true;
#else
        qc_use_http_parser = (qc_webkit_type == "qtwebengine");
#endif
        if (!qc_use_http_parser)
            return true; // http parser is not needed. success.

        QString s;
        if (conf->getenv("QC_BUNDLED_HTTP_PARSER") == "Y") {
            goto use_bundled_lbl;
        }

#if !(defined(Q_OS_WIN) || defined(Q_OS_MAC))
        s = conf->getenv("QC_WITH_HTTP_PARSER_INC");
        if (!s.isEmpty()) {
            if (!conf->checkHeader(s, "http_parser.h")) {
                qWarning("HTTP Parser includes not found!");
                return false;
            }
            conf->addIncludePath(s);
        } else {
            QStringList sl;
            sl += "/usr/include";
            sl += "/usr/local/include";
            sl += "/sw/include";
            if (!conf->findHeader("http_parser.h", sl, &s)) {
                qWarning("HTTP Parser includes not found. Use bundled");
                goto use_bundled_lbl;
            }
            conf->addIncludePath(s);
        }

        s = conf->getenv("QC_WITH_HTTP_PARSER_LIB");
        if (!s.isEmpty()) {
            if (!conf->checkLibrary(s, "http_parser")) {
                qWarning("HTTP Parser libraries not found!");
                return false;
            }
            conf->addLib(QString("-L") + s);
        } else {
            if (!conf->findLibrary("http_parser", &s)) {
                qWarning("HTTP Parser libraries not found. Use bundled");
                goto use_bundled_lbl;
            }
            if (!s.isEmpty())
                conf->addLib(QString("-L") + s);
        }

        conf->addLib("-lhttp_parser");

        return true;
#endif
    use_bundled_lbl:
        use_bundled = true;
        conf->addExtra("CONFIG += bundled_http_parser");
        return true;
    }
};
#line 1 "b2.qcm"
/*
-----BEGIN QCMOD-----
name: libb2
arg: with-b2-inc=[path],Path to libb2 include files
arg: with-b2-lib=[path],Path to libb2 library or framework files
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_b2
//----------------------------------------------------------------------------
class qc_b2 : public ConfObj {
    bool use_system = false;

public:
    qc_b2(Conf *c) : ConfObj(c) { }
    QString name() const { return "LibB2"; }
    QString shortname() const { return "libb2"; }
    QString resultString() const { return use_system ? "system" : "bundled"; }
    bool    exec()
    {
        QString b2_incdir, b2_libdir;
        b2_incdir = conf->getenv("QC_WITH_B2_INC");
        b2_libdir = conf->getenv("QC_WITH_B2_LIB");

        if (b2_incdir.isEmpty() && b2_libdir.isEmpty()) {
            if (!checkCustomDirs(b2_incdir, b2_libdir)) {
                printf("b2 search paths provided but library is not found there. use bundled");
                return true;
            }
            use_system = true;
        } else {
            QStringList incs;
            QString     version, libs, other;
            if (conf->findPkgConfig("libb2", VersionAny, QString::null, &version, &incs, &libs, &other)) {
                for (int n = 0; n < incs.count(); ++n)
                    conf->addIncludePath(incs[n]);
                if (!libs.isEmpty())
                    conf->addLib(libs);
                use_system = true;
            }
        }

        if (use_system) {
            conf->addExtra("CONFIG += bundled_blake2");
        }

        return true;
    }

    bool checkCustomDirs(QString &b2_incdir, QString &b2_libdir)
    {
        if ((b2_incdir.isEmpty() && !conf->findHeader("blake2.h", QStringList(), &b2_incdir))
            || (!b2_incdir.isEmpty() && !conf->checkHeader(b2_incdir, "blake2.h"))) {
            printf("Headers not found!\\n");
            return false;
        }

        if ((!b2_libdir.isEmpty() && conf->checkLibrary(b2_libdir, "b2"))
            || (b2_libdir.isEmpty() && conf->findLibrary("b2", &b2_libdir))) {
            conf->addLib(b2_libdir.isEmpty() ? "-lb2" : QString("-L%1 -lb2").arg(b2_libdir));
            conf->addIncludePath(b2_incdir);
            return true;
        }

        printf("Libraries not found!\\n");
        return false;
    }
};
#line 1 "growl.qcm"
/*
-----BEGIN QCMOD-----
name: Growl
arg: with-growl=[path],Path to the Growl framework
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_growl
//----------------------------------------------------------------------------
class qc_growl : public ConfObj {
public:
    qc_growl(Conf *c) : ConfObj(c) { }
    QString name() const { return "Growl"; }
    QString shortname() const { return "growl"; }
#ifndef Q_OS_MAC
    QString checkString() const { return QString(); }
#endif

    // TODO: This should go into ConfObj
    bool checkFramework(const QString &path, const QString &name)
    {
        QString str = "int main()\\n"
                      "{\\n"
                      "    return 0;\\n"
                      "}\\n";

        QString extra;
        if (!path.isEmpty())
            extra += QString("-F") + path + ' ';
        extra += QString("-framework ") + name;
        if (!conf->doCompileAndLink(str, QStringList(), extra, "", nullptr))
            return false;
        return true;
    }

    // TODO: This should go into ConfObj
    void addFrameworkPath(const QString &str)
    {
        conf->addExtra("QMAKE_CXXFLAGS += -F" + str);
        conf->addExtra("QMAKE_OBJECTIVE_CFLAGS += -F" + str);
        conf->addLib("-F" + str);
    }

    bool exec()
    {
#ifdef Q_OS_MAC
        QString growl_path = conf->getenv("QC_WITH_GROWL");
        if (!checkFramework(growl_path, "Growl"))
            return false;

        if (!growl_path.isEmpty())
            addFrameworkPath(growl_path);
        conf->addLib("-framework Growl");
        conf->addDefine("HAVE_GROWL");

        return true;
#else
        return false;
#endif
    }
};
#line 1 "whiteboarding.qcm"
/*
-----BEGIN QCMOD-----
name: White Board support
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_whiteboarding
//----------------------------------------------------------------------------
static bool qc_qtsvg_found = false;
class qc_whiteboarding : public QtCompFinder {
public:
    qc_whiteboarding(Conf *c) : QtCompFinder("svg", "whiteboarding", "White Board support", "", c) { }
    QString resultString() const
    {
        if (!qc_qtsvg_found) {
            return "QtSVG is not found";
        }
        return ConfObj::resultString();
    }

    bool exec()
    {
        if (!QtCompFinder::exec()) {
            return false;
        }
        qc_qtsvg_found = true;

        conf->addDefine("WHITEBOARDING");

        // Finish
        conf->addExtra("CONFIG += whiteboarding");

        qWarning("");
        qWarning("");
        qWarning("        !!!!!!!!!!!!!! WARNING !!!!!!!!!!!!!!!");
        qWarning("        WHITEBOARDING SUPPORT IS STILL UNFINISHED !!!");
        qWarning("        USE AT YOUR OWN RISK !!!");

        return true;
    }
};
#line 1 "xss.qcm"
/*
-----BEGIN QCMOD-----
name: the XScreenSaver extension
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_xss
//----------------------------------------------------------------------------
class qc_xss : public ConfObj {
public:
    qc_xss(Conf *c) : ConfObj(c) { }

    QString name() const { return "the XScreenSaver extension"; }
    QString shortname() const { return "xss"; }
#ifdef Q_OS_WIN
    QString checkString() const { return QString(); }
#endif

    bool exec()
    {
#ifdef Q_OS_WIN
        // skip XSS support on windows
        return false;
#else
        QString str = "#include<X11/Xlib.h>\\n"
                      "#include<X11/Xutil.h>\\n"
                      "#include<X11/extensions/scrnsaver.h>\\n"
                      "\\n"
                      "int main()\\n"
                      "{\\n"
                      "    XScreenSaverQueryExtension(NULL, NULL, NULL);\\n"
                      "    return 0;\\n"
                      "}\\n";
        QString proextra = "CONFIG += x11\\n";

        if (!conf->doCompileAndLink(str, QStringList(), "-lXss", proextra, NULL)) {
            if (!conf->doCompileAndLink(str, QStringList(), QString(), proextra, NULL)) {
                return false;
            }
        } else {
            conf->addLib("-lXss");
        }

        conf->addDefine("HAVE_XSS");
        return true;
#endif
    }
};
#line 1 "aspell.qcm"
/*
-----BEGIN QCMOD-----
name: aspell
arg: with-aspell-inc=[path],Path to Aspell include files
arg: with-aspell-lib=[path],Path to Aspell library files
-----END QCMOD-----
*/

#define QC_ASPELL
bool        qc_aspell_have = false;
QStringList qc_aspell_defs;
QStringList qc_aspell_incs;
QStringList qc_aspell_libs;

//----------------------------------------------------------------------------
// qc_aspell
//----------------------------------------------------------------------------
class qc_aspell : public ConfObj {
public:
    qc_aspell(Conf *c) : ConfObj(c) { }
    QString name() const { return "aspell"; }
    QString shortname() const { return "aspell"; }

    // no output
    QString checkString() const { return QString(); }

    bool exec()
    {
        // on mac, always use built-in spell check
#ifdef Q_OS_MAC
        return false;
#else
        qc_aspell_have = false;
        qc_aspell_defs.clear();
        qc_aspell_incs.clear();
        qc_aspell_libs.clear();

        QString s;

#ifdef Q_OS_WIN
        s = conf->getenv("QC_WITH_ASPELL_INC");
        if (!s.isEmpty()) {
            if (!conf->checkHeader(s, "aspell.h")) {
                conf->debug("Aspell includes not found!");
                return false;
            }
            qc_aspell_incs += s;
        } else
            return false;

        QString a_lib = conf->getenv("QC_WITH_ASPELL_LIB");
        if (a_lib.isEmpty())
            return false;

        QStringList libnames;
        libnames += "aspell-15";
        libnames += "aspell";

        bool    success;
        QString libname_success;
        for (const QString &libname : libnames) {
            conf->debug(QString("Trying %1").arg(libname));
            if (conf->checkLibrary(a_lib, libname)) {
                success         = true;
                libname_success = libname;
                break;
            }
        }

        if (!success)
            return false;

        qc_aspell_defs += "HAVE_ASPELL";
        qc_aspell_libs += QString("-L") + a_lib;
        qc_aspell_libs += QString("-l") + libname_success;
        qc_aspell_have = true;
#else
        s = conf->getenv("QC_WITH_ASPELL_INC");
        if (!s.isEmpty()) {
            if (!conf->checkHeader(s, "aspell.h")) {
                conf->debug("Aspell includes not found!");
                return false;
            }
            qc_aspell_incs += s;
        } else {
            QStringList sl;
            sl += "/usr/include";
            sl += "/usr/local/include";
            sl += "/sw/include";
            if (!conf->findHeader("aspell.h", sl, &s)) {
                conf->debug("Aspell includes not found!");
                return false;
            }
            qc_aspell_incs += s;
        }

        s = conf->getenv("QC_WITH_ASPELL_LIB");
        if (!s.isEmpty()) {
            if (!conf->checkLibrary(s, "aspell")) {
                conf->debug("Aspell libraries not found!");
                return false;
            }
            qc_aspell_libs += QString("-L") + s;
        } else {
            if (!conf->findLibrary("aspell", &s)) {
                conf->debug("Aspell libraries not found!");
                return false;
            }
            if (!s.isEmpty())
                qc_aspell_libs += QString("-L") + s;
        }

        qc_aspell_defs += "HAVE_ASPELL";
        qc_aspell_libs += "-laspell";
        qc_aspell_have = true;
#endif

        return true;
#endif
    }
};
#line 1 "enchant.qcm"
/*
-----BEGIN QCMOD-----
name: enchant
-----END QCMOD-----
*/

#define QC_ENCHANT
bool        qc_enchant_have = false;
QStringList qc_enchant_defs;
QStringList qc_enchant_incs;
QStringList qc_enchant_libs;

//----------------------------------------------------------------------------
// qc_enchant
//----------------------------------------------------------------------------
class qc_enchant : public ConfObj {
public:
    qc_enchant(Conf *c) : ConfObj(c) { }
    QString name() const { return "enchant"; }
    QString shortname() const { return "enchant"; }

    // no output
    QString checkString() const { return QString(); }

    bool exec()
    {
        // on mac, always use built-in spell check
#ifdef Q_OS_MAC
        return false;
#endif

        qc_enchant_have = false;
        qc_enchant_defs.clear();
        qc_enchant_incs.clear();
        qc_enchant_libs.clear();

        QStringList incs;
        QString     version, libs, other;
        if (!conf->findPkgConfig("enchant", VersionMin, "1.3.0", &version, &incs, &libs, &other))
            if (conf->findPkgConfig("enchant-2", VersionMin, "2.0.0", &version, &incs, &libs, &other)) {
                qc_enchant_defs += "HAVE_ENCHANT2";
            } else {
                return false;
            }

        qc_enchant_defs += "HAVE_ENCHANT";
        qc_enchant_incs += incs;
        qc_enchant_libs += libs;
        qc_enchant_have = true;

        return true;
    }
};
#line 1 "hunspell.qcm"
/*
-----BEGIN QCMOD-----
name: hunspell
arg: with-hunspell-inc=[path],Path to Hunspell include files
arg: with-hunspell-lib=[path],Path to Hunspell library files
-----END QCMOD-----
*/

#define QC_HUNSPELL
bool        qc_hunspell_have = false;
QStringList qc_hunspell_defs;
QStringList qc_hunspell_incs;
QStringList qc_hunspell_libs;

//----------------------------------------------------------------------------
// qc_hunspell
//----------------------------------------------------------------------------
class qc_hunspell : public ConfObj {
public:
    qc_hunspell(Conf *c) : ConfObj(c) { }
    QString name() const { return "hunspell"; }
    QString shortname() const { return "hunspell"; }

    // no output
    QString checkString() const { return QString(); }

    bool exec()
    {
        // on mac, always use built-in spell check
#ifdef Q_OS_MAC
        return false;
#else
        qc_hunspell_have = false;
        qc_hunspell_defs.clear();
        qc_hunspell_incs.clear();
        qc_hunspell_libs.clear();

#ifdef Q_OS_WIN
        QStringList libnames;
#ifdef _MSC_VER
        qc_hunspell_defs += "HUNSPELL_STATIC"; // at least it's static by default when their msvc sln is in use.
#ifdef QC_BUILDMODE
        libnames += (qc_buildmode_debug ? "libhunspelld" : "libhunspell"); // possibly static
        libnames += (qc_buildmode_debug ? "hunspelld" : "hunspell");       // possibly dynamic
#else
        libnames << "libhunspell"
                 << "hunspell";
#endif
#else // mingw?
        libnames << "hunspell-1.3"
                 << "hunspell";
#endif
        QString libs, incs;
        for (const QString libname : libnames)
            if (conf->findSimpleLibrary("QC_WITH_HUNSPELL_INC", "QC_WITH_HUNSPELL_LIB", "hunspell/hunspell.hxx",
                                        libname, &incs, &libs)) {
                break;
            }

        if (libs.isEmpty()) {
            printf("hunspell library is not found");
            return false;
        }
        conf->addLib(libs);

        qc_hunspell_defs += "HAVE_HUNSPELL";
        qc_hunspell_libs += libs;
        qc_hunspell_incs += incs + "/hunspell";
        qc_hunspell_have = true;
#else  // Q_OS_WIN. unix below
        qc_hunspell_have = false;
        qc_hunspell_defs.clear();
        qc_hunspell_incs.clear();
        qc_hunspell_libs.clear();

        QStringList incs;
        QString     version, libs, other;
        if (!conf->findPkgConfig("hunspell", VersionMin, "1.3.0", &version, &incs, &libs, &other))
            return false;

        qc_hunspell_defs += "HAVE_HUNSPELL";
        qc_hunspell_incs += incs;
        qc_hunspell_libs += libs;
        qc_hunspell_have = true;
#endif // Q_OS_WIN

        return true;
#endif // Q_OS_MAC
    }
};
#line 1 "spell.qcm"
/*
-----BEGIN QCMOD-----
name: spellcheck engine
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_spell
//----------------------------------------------------------------------------
class qc_spell : public ConfObj {
public:
    QString engine;

    qc_spell(Conf *c) : ConfObj(c) { }
    QString name() const { return "spellcheck engine"; }
    QString shortname() const { return "spell"; }

    bool exec()
    {
        // on mac, always use built-in spell check
#ifdef Q_OS_MAC
        engine = "using Mac built-in";
        return true;
#endif

        bool        have = false;
        QStringList defs, incs, libs;

#ifdef QC_ENCHANT
        if (!have && qc_enchant_have) {
            defs   = qc_enchant_defs;
            incs   = qc_enchant_incs;
            libs   = qc_enchant_libs;
            engine = "enchant";
            have   = true;
        }
#endif
#ifdef QC_ASPELL
        if (!have && qc_aspell_have) {
            defs   = qc_aspell_defs;
            incs   = qc_aspell_incs;
            libs   = qc_aspell_libs;
            engine = "aspell";
            have   = true;
        }
#endif
#ifdef QC_HUNSPELL
        if (!have && qc_hunspell_have) {
            defs   = qc_hunspell_defs;
            incs   = qc_hunspell_incs;
            libs   = qc_hunspell_libs;
            engine = "hunspell";
            have   = true;
        }
#endif

        if (!have)
            return true;

        for (int n = 0; n < defs.count(); ++n)
            conf->addDefine(defs[n]);
        for (int n = 0; n < incs.count(); ++n)
            conf->addIncludePath(incs[n]);
        for (int n = 0; n < libs.count(); ++n)
            conf->addLib(libs[n]);

        return true;
    }

    QString resultString() const
    {
        if (!engine.isEmpty())
            return engine;
        else
            return "no";
    }
};
#line 1 "plugins.qcm"
/*
-----BEGIN QCMOD-----
name: Psi Plugin support
-----END QCMOD-----
*/

//----------------------------------------------------------------------------
// qc_plugins
//----------------------------------------------------------------------------
class qc_plugins : public ConfObj {
public:
    qc_plugins(Conf *c) : ConfObj(c) { }
    QString name() const { return "Psi Plugin support"; }
    QString shortname() const { return "plugins"; }
    bool    exec()
    {
        QFileInfo fi(qc_getenv("QC_COMMAND"));
        QString   sourceDir = fi.absolutePath();

        conf->addDefine("PSI_PLUGINS");

        // Finish
        conf->addExtra("CONFIG += psi_plugins");

        QHash<QString, QString> vars;
#ifdef Q_OS_WIN
        vars["plugins_dir"] = "";
        vars["data_dir"]    = "";
        vars["include_dir"] = "";
#else
        vars["plugins_dir"]         = conf->getenv("LIBDIR") + "/" + qc_psi_dir_name + "/plugins";
        vars["data_dir"]            = conf->getenv("DATADIR") + "/" + qc_psi_dir_name;
        vars["plugins_include_dir"] = conf->getenv("PREFIX") + "/include/" + qc_psi_dir_name + "/plugins";
#endif
        QStringList psiFeatures;
        if (!qc_webkit_type.isEmpty()) {
            psiFeatures << qc_webkit_type;
        }
        vars["features"] = psiFeatures.join(" ");
        psiGenerateFile(sourceDir + "/pluginsconf.pri.in", "pluginsconf-dist.pri", vars);

        return true;
    }
};
#line 1 "conf.qcm"
/*
-----BEGIN QCMOD-----
name: Psi Configuration
-----END QCMOD-----
*/

#include <QDateTime>

static QString psiGetVersion()
{
    QString str;

    {
        QFile file(sourceDir + "/version");
        if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            QTextStream ts(&file);
            if (!ts.atEnd())
                str = ts.readLine();
        }

        if (str.isEmpty())
            str = "UnknownVersion";
    }

    QString nowstr = QDateTime::currentDateTime().toString("yyyyMMdd");
    str.replace("@@DATE@@", nowstr);
    return str;
}

class qc_conf : public ConfObj {
public:
    qc_conf(Conf *c) : ConfObj(c) { }
    QString name() const { return qc_psiplus ? "Psi+ Configuration" : "Psi Configuration"; }
    QString shortname() const { return "conf"; }
    QString checkString() const { return QString(); }
    bool    exec()
    {
        QString version = psiGetVersion();
        QRegExp verre("^\\\\d+(?:\\\\.\\\\d+)+");
        if (verre.indexIn(version) == -1) {
            conf->debug("Failed to parse version file");
            return false;
        }
        conf->addExtra(QString("PSI_VERSION = %1").arg(verre.cap(0)));

        QHash<QString, QString> vars;
        vars["VERSION"] = version;
        QDir::current().mkpath("mac");
        psiGenerateFile(sourceDir + "/mac/Info.plist.in", "mac/Info.plist", vars);

        vars.clear();
        vars["source_dir"] = sourceDir;
        vars["build_dir"]  = QDir::currentPath();
        psiGenerateFile(sourceDir + "/.qmake.cache.in", ".qmake.cache", vars);

#ifndef Q_OS_WIN
        conf->addExtra(QString("PSI_LIBDIR=%1/%2").arg(conf->getenv("LIBDIR"), qc_psi_dir_name));
        conf->addExtra(QString("PSI_DATADIR=%1/%2").arg(conf->getenv("DATADIR"), qc_psi_dir_name));
#endif

        QDir(".").mkdir("src");
        auto now = QDateTime::currentDateTime();
        vars     = {
            { "CLIENT_NAME", qc_psiplus ? "Psi+" : "Psi" },
            { "CLIENT_SNAME", qc_psiplus ? "psi+" : "psi" },
            { "CLIENT_CAPS_NODE", qc_psiplus ? "https://psi-plus.com" : "https://psi-im.org" },
            { "PRODUCTION", "" },
#ifndef Q_OS_WIN
            { "PSI_LIBDIR", conf->getenv("LIBDIR") + "/" + qc_psi_dir_name },
            { "PSI_DATADIR", conf->getenv("DATADIR") + "/" + qc_psi_dir_name },
#endif
            { "PSI_VERSION", version },
            { "PSI_REVISION", "" },
            { "PSI_PLUS_REVISION", "" },
            { "PSI_COMPILATION_DATE", now.toString("yyyy-MM-dd") },
            { "PSI_COMPILATION_TIME", now.toString("HH:mm:ss") },
        };
        psiGenerateFile(sourceDir + "/src/config.h.in", "src/config.h", vars);

        vars = { { "PSILOGO_PREFIX", qc_psiplus ? "psiplus/" : "" },
                 { "MAIN_ICON", qc_psiplus ? "psiplus_icon.png" : "psimain.png" } };

        auto buildIconDir = QDir::current().absoluteFilePath("iconsets");
        copyPath(sourceDir + "/iconsets", buildIconDir);
        psiGenerateFile(sourceDir + "/iconsets.qrc.in", "iconsets.qrc", vars);
        psiGenerateFile(sourceDir + "/icondef.xml.in", buildIconDir + "/system/default/icondef.xml", vars);

        conf->addDefine("HAVE_CONFIG");

        return true;
    }
};

EOT
cat >"$1/modules_new.cpp" <<EOT
    o = new qc_qt5(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_buildmodeapp(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_idn(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_qca(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_zlib(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_qjdns(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_x11(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_universal(conf);
    o->required = false;
    o->disabled = true;
    o = new qc_qdbus(conf);
    o->required = false;
    o->disabled = false;
    o = new qc_keychain(conf);
    o->required = false;
    o->disabled = false;
    o = new qc_qtmultimedia(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_qtconcurrent(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_qtsql(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_qtwidgets(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_qtnetwork(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_qtsvg(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_qtxml(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_webkit(conf);
    o->required = false;
    o->disabled = true;
    o = new qc_http_parser(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_b2(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_growl(conf);
    o->required = false;
    o->disabled = false;
    o = new qc_whiteboarding(conf);
    o->required = false;
    o->disabled = true;
    o = new qc_xss(conf);
    o->required = false;
    o->disabled = false;
    o = new qc_aspell(conf);
    o->required = false;
    o->disabled = false;
    o = new qc_enchant(conf);
    o->required = false;
    o->disabled = false;
    o = new qc_hunspell(conf);
    o->required = false;
    o->disabled = false;
    o = new qc_spell(conf);
    o->required = true;
    o->disabled = false;
    o = new qc_plugins(conf);
    o->required = false;
    o->disabled = false;
    o = new qc_conf(conf);
    o->required = true;
    o->disabled = false;

EOT
cat >"$1/conf4.h" <<EOT
/*
Copyright (C) 2004-2008  Justin Karneges

This file is free software; unlimited permission is given to copy and/or
distribute it, with or without modifications, as long as this notice is
preserved.
*/

#ifndef QC_CONF4_H
#define QC_CONF4_H

#include <QtCore>

class Conf;

enum VersionMode { VersionMin, VersionExact, VersionMax, VersionAny };

// ConfObj
//
// Subclass ConfObj to create a new configuration module.
class ConfObj {
public:
    Conf *conf;
    bool  required;
    bool  disabled;
    bool  success;

    ConfObj(Conf *c);
    virtual ~ConfObj();

    // long or descriptive name of what is being checked/performed
    // example: "KDE >= 3.3"
    virtual QString name() const = 0;

    // short name
    // example: "kde"
    virtual QString shortname() const = 0;

    // string to display during check
    // default: "Checking for [name] ..."
    virtual QString checkString() const;

    // string to display after check
    // default: "yes" or "no", based on result of exec()
    virtual QString resultString() const;

    // this is where the checking code goes
    virtual bool exec() = 0;
};

// Conf
//
// Interact with this class from your ConfObj to perform detection
// operations and to output configuration parameters.
class Conf {
public:
    bool    debug_enabled;
    QString qmake_path;
    QString qmakespec;
    QString maketool;

    QString     DEFINES;
    QStringList INCLUDEPATH;
    QStringList LIBS;
    QString     extra;

    QList<ConfObj *>       list;
    QMap<QString, QString> vars;

    Conf();
    ~Conf();

    QString        getenv(const QString &var);
    QString        qvar(const QString &s);
    QString        normalizePath(const QString &s) const;
    QString        escapeQmakeVar(const QString &s) const;
    inline QString escapePath(const QString &s) /* prepare fs path for qmake file */
    {
        return escapeQmakeVar(normalizePath(s));
    }
    QString escapedIncludes() const;
    QString escapedLibs() const;

    bool exec();

    void debug(const QString &s);

    QString expandIncludes(const QString &inc);
    QString expandLibs(const QString &lib);

    int doCommand(const QString &s, QByteArray *out = 0);
    int doCommand(const QString &prog, const QStringList &args, QByteArray *out = 0);

    bool    doCompileAndLink(const QString &filedata, const QStringList &incs, const QString &libs,
                             const QString &proextra, int *retcode = 0);
    bool    checkHeader(const QString &path, const QString &h);
    bool    findHeader(const QString &h, const QStringList &ext, QString *inc);
    bool    checkLibrary(const QString &path, const QString &name);
    bool    findLibrary(const QString &name, QString *lib);
    QString findProgram(const QString &prog);
    bool findSimpleLibrary(const QString &incvar, const QString &libvar, const QString &incname, const QString &libname,
                           QString *incpath, QString *libs);
    bool findFooConfig(const QString &path, QString *version, QStringList *incs, QString *libs, QString *otherflags);
    bool findPkgConfig(const QString &name, VersionMode mode, const QString &req_version, QString *version,
                       QStringList *incs, QString *libs, QString *otherflags);

    void addDefine(const QString &str);
    void addLib(const QString &str);
    void addIncludePath(const QString &str);
    void addExtra(const QString &str);

private:
    bool first_debug;

    friend class ConfObj;
    void added(ConfObj *o);
};

#endif

EOT
cat >"$1/conf4.cpp" <<EOT
/*
Copyright (C) 2004-2008  Justin Karneges

This file is free software; unlimited permission is given to copy and/or
distribute it, with or without modifications, as long as this notice is
preserved.
*/

#include "conf4.h"

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef PATH_MAX
#ifdef Q_OS_WIN
#define PATH_MAX 260
#endif
#endif

class MocTestObject : public QObject {

    Q_OBJECT
public:
    MocTestObject() {}
};

QString qc_getenv(const QString &var)
{
    char *p = ::getenv(var.toLatin1().data());
    if (!p)
        return QString();
    return QString(p);
}

QStringList qc_pathlist()
{
    QStringList list;
    QString     path = qc_getenv("PATH");
    if (!path.isEmpty()) {
#ifdef Q_OS_WIN
        list = path.split(';', QString::SkipEmptyParts);
#else
        list = path.split(':', QString::SkipEmptyParts);
#endif
    }
#ifdef Q_OS_WIN
    list.prepend(".");
#endif
    return list;
}

QString qc_findprogram(const QString &prog)
{
    QString     out;
    QStringList list = qc_pathlist();
    for (int n = 0; n < list.count(); ++n) {
        QFileInfo fi(list[n] + '/' + prog);
        if (fi.exists() && fi.isExecutable()) {
            out = fi.filePath();
            break;
        }

#ifdef Q_OS_WIN
        // on windows, be sure to look for .exe
        if (prog.right(4).toLower() != ".exe") {
            fi = QFileInfo(list[n] + '/' + prog + ".exe");
            if (fi.exists() && fi.isExecutable()) {
                out = fi.filePath();
                break;
            }
        }
#endif
    }
    return out;
}

QString qc_findself(const QString &argv0)
{
#ifdef Q_OS_WIN
    if (argv0.contains('\\\\'))
#else
    if (argv0.contains('/'))
#endif
        return argv0;
    else
        return qc_findprogram(argv0);
}

int qc_run_program_or_command(const QString &prog, const QStringList &args, const QString &command, QByteArray *out,
                              bool showOutput)
{
    if (out)
        out->clear();

    QProcess process;
    process.setReadChannel(QProcess::StandardOutput);

    if (!prog.isEmpty())
        process.start(prog, args);
    else if (!command.isEmpty())
        process.start(command);
    else
        return -1;

    if (!process.waitForStarted(-1))
        return -1;

    QByteArray buf;

    while (process.waitForReadyRead(-1)) {
        buf = process.readAllStandardOutput();
        if (out)
            out->append(buf);
        if (showOutput)
            fprintf(stdout, "%s", buf.data());

        buf = process.readAllStandardError();
        if (showOutput)
            fprintf(stderr, "%s", buf.data());
    }

    buf = process.readAllStandardError();
    if (showOutput)
        fprintf(stderr, "%s", buf.data());

    // calling waitForReadyRead will cause the process to eventually be
    //   marked as finished, so we should not need to separately call
    //   waitForFinished. however, we will do it anyway just to be safe.
    //   we won't check the return value since false could still mean
    //   success (if the process had already been marked as finished).
    process.waitForFinished(-1);

    if (process.exitStatus() != QProcess::NormalExit)
        return -1;

    return process.exitCode();
}

int qc_runcommand(const QString &command, QByteArray *out, bool showOutput)
{
    return qc_run_program_or_command(QString(), QStringList(), command, out, showOutput);
}

int qc_runprogram(const QString &prog, const QStringList &args, QByteArray *out, bool showOutput)
{
    return qc_run_program_or_command(prog, args, QString(), out, showOutput);
}

bool qc_removedir(const QString &dirPath)
{
    QDir dir(dirPath);
    if (!dir.exists())
        return false;
    QStringList list = dir.entryList();
    foreach (QString s, list) {
        if (s == "." || s == "..")
            continue;
        QFileInfo fi(dir.filePath(s));
        if (fi.isDir()) {
            if (!qc_removedir(fi.filePath()))
                return false;
        } else {
            if (!dir.remove(s))
                return false;
        }
    }
    QString dirName = dir.dirName();
    if (!dir.cdUp())
        return false;
    if (!dir.rmdir(dirName))
        return false;
    return true;
}

// simple command line arguemnts splitter able to understand quoted args.
// the splitter removes quotes and unescapes symbols as well.
QStringList qc_splitflags(const QString &flags)
{
    QStringList ret;
    bool        searchStart = true;
    bool        inQuotes    = false;
    bool        escaped     = false;
    QChar       quote, backslash = QLatin1Char('\\\\');
    QString     buf;
#ifdef PATH_MAX
    buf.reserve(PATH_MAX);
#endif
    for (int i = 0; i < flags.length(); i++) {
        if (searchStart && flags[i].isSpace()) {
            continue;
        }
        if (searchStart) {
            searchStart = false;
            buf.clear();
        }
        if (escaped) {
            buf += flags[i];
            escaped = false;
            continue;
        }
        // buf += flags[i];
        if (inQuotes) {
            if (quote == QLatin1Char('\\'')) {
                if (flags[i] == quote) {
                    inQuotes = false;
                    continue;
                }
            } else { // we are in double quoetes
                if (flags[i] == backslash && i < flags.length() - 1
                    && (flags[i + 1] == QLatin1Char('"') || flags[i + 1] == backslash)) {
                    // if next symbol is one of in parentheses ("\\)
                    escaped = true;
                    continue;
                }
            }
        } else {
            if (flags[i].isSpace()) {
                ret.append(buf);
                searchStart = true;
                buf.clear();
                continue;
#ifndef Q_OS_WIN /* on windows backslash is just a path separator */
            } else if (flags[i] == backslash) {
                escaped = true;
                continue; // just add next symbol
#endif
            } else if (flags[i] == QLatin1Char('\\'') || flags[i] == QLatin1Char('"')) {
                inQuotes = true;
                quote    = flags[i];
                continue;
            }
        }
        buf += flags[i];
    }
    if (buf.size()) {
        ret.append(buf);
    }
    return ret;
}

void qc_splitcflags(const QString &cflags, QStringList *incs, QStringList *otherflags)
{
    incs->clear();
    otherflags->clear();

    QStringList cflagsList = qc_splitflags(cflags);
    for (int n = 0; n < cflagsList.count(); ++n) {
        QString str = cflagsList[n];
        if (str.startsWith("-I")) {
            // we want everything except the leading "-I"
            incs->append(str.remove(0, 2));
        } else {
            // we want whatever is left
            otherflags->append(str);
        }
    }
}

QString qc_escapeArg(const QString &str)
{
    QString out;
    for (int n = 0; n < (int)str.length(); ++n) {
        if (str[n] == '-')
            out += '_';
        else
            out += str[n];
    }
    return out;
}

QString qc_trim_char(const QString &s, const QChar &ch)
{
    if (s.startsWith(ch) && s.endsWith(ch)) {
        return s.mid(1, s.size() - 2);
    }
    return s;
}

// removes surrounding quotes, removes trailing slashes, converts to native separators.
// accepts unescaped but possible quoted path
QString qc_normalize_path(const QString &str)
{
    QString path = str.trimmed();
    path         = qc_trim_char(path, QLatin1Char('"'));
    path         = qc_trim_char(path, QLatin1Char('\\''));

    // It's OK to use unix style'/' paths on windows Qt handles this without any problems.
    // Using Windows-style '\\\\' can leads strange compilation error with MSYS which uses
    // unix style.
    QLatin1Char nativeSep('/');
#ifdef Q_OS_WIN
    path.replace(QLatin1Char('\\\\'), QLatin1Char('/'));
#endif
    // trim trailing slashes
    while (path.length() && path[path.length() - 1] == nativeSep) {
        path.resize(path.length() - 1);
    }
    return path;
}

// escape filesystem path to be added to qmake pro/pri file.
QString qc_escape_string_var(const QString &str)
{
    QString path = str;
    path.replace(QLatin1Char('\\\\'), QLatin1String("\\\\\\\\")).replace(QLatin1Char('"'), QLatin1String("\\\\\\""));
    if (path.indexOf(QLatin1Char(' ')) != -1) { // has spaces
        return QLatin1Char('"') + path + QLatin1Char('"');
    }
    return path;
}

// escapes each path in incs and join into single string suiable for INCLUDEPATH var
QString qc_prepare_includepath(const QStringList &incs)
{
    if (incs.empty()) {
        return QString();
    }
    QStringList ret;
    foreach (const QString &path, incs) {
        ret.append(qc_escape_string_var(path));
    }
    return ret.join(QLatin1String(" "));
}

// escapes each path in libs and to make it suiable for LIBS var
// notice, entries of libs are every single arg for linker.
QString qc_prepare_libs(const QStringList &libs)
{
    if (libs.isEmpty()) {
        return QString();
    }
    QSet<QString> pathSet;
    QStringList   paths;
    QStringList   ordered;
    foreach (const QString &arg, libs) {
        if (arg.startsWith(QLatin1String("-L"))) {
            QString path = qc_escape_string_var(arg.mid(2));
            if (!pathSet.contains(path)) {
                pathSet.insert(path);
                paths.append(path);
            }
        } else if (arg.startsWith(QLatin1String("-l"))) {
            ordered.append(arg);
        } else {
            ordered.append(qc_escape_string_var(arg));
        }
    }
    QString ret;
    if (paths.size()) {
        ret += (QLatin1String(" -L") + paths.join(QLatin1String(" -L")) + QLatin1Char(' '));
    }
    return ret + ordered.join(QLatin1String(" "));
}

//----------------------------------------------------------------------------
// ConfObj
//----------------------------------------------------------------------------
ConfObj::ConfObj(Conf *c)
{
    conf = c;
    conf->added(this);
    required = false;
    disabled = false;
    success  = false;
}

ConfObj::~ConfObj() {}

QString ConfObj::checkString() const { return QString("Checking for %1 ...").arg(name()); }

QString ConfObj::resultString() const
{
    if (success)
        return "yes";
    else
        return "no";
}

//----------------------------------------------------------------------------
// qc_internal_pkgconfig
//----------------------------------------------------------------------------
class qc_internal_pkgconfig : public ConfObj {
public:
    QString     pkgname, desc;
    VersionMode mode;
    QString     req_ver;

    qc_internal_pkgconfig(Conf *c, const QString &_name, const QString &_desc, VersionMode _mode,
                          const QString &_req_ver) :
        ConfObj(c),
        pkgname(_name), desc(_desc), mode(_mode), req_ver(_req_ver)
    {
    }

    QString name() const { return desc; }
    QString shortname() const { return pkgname; }

    bool exec()
    {
        QStringList incs;
        QString     version, libs, other;
        if (!conf->findPkgConfig(pkgname, mode, req_ver, &version, &incs, &libs, &other))
            return false;

        for (int n = 0; n < incs.count(); ++n)
            conf->addIncludePath(incs[n]);
        if (!libs.isEmpty())
            conf->addLib(libs);
        // if(!other.isEmpty())
        //    conf->addExtra(QString("QMAKE_CFLAGS += %1\\n").arg(other));

        if (!required)
            conf->addDefine("HAVE_PKG_" + qc_escapeArg(pkgname).toUpper());

        return true;
    }
};

//----------------------------------------------------------------------------
// Conf
//----------------------------------------------------------------------------
Conf::Conf()
{
    // TODO: no more vars?
    // vars.insert("QMAKE_INCDIR_X11", new QString(X11_INC));
    // vars.insert("QMAKE_LIBDIR_X11", new QString(X11_LIBDIR));
    // vars.insert("QMAKE_LIBS_X11",   new QString(X11_LIB));
    // vars.insert("QMAKE_CC", CC);

    debug_enabled = false;
    first_debug   = true;
}

Conf::~Conf() { qDeleteAll(list); }

void Conf::added(ConfObj *o) { list.append(o); }

QString Conf::getenv(const QString &var) { return qc_getenv(var); }

void Conf::debug(const QString &s)
{
    if (debug_enabled) {
        if (first_debug)
            printf("\\n");
        first_debug = false;
        printf(" * %s\\n", qPrintable(s));
    }
}

bool Conf::exec()
{
    for (int n = 0; n < list.count(); ++n) {
        ConfObj *o = list[n];

        // if this was a disabled-by-default option, check if it was enabled
        if (o->disabled) {
            QString v = QString("QC_ENABLE_") + qc_escapeArg(o->shortname());
            if (getenv(v) != "Y")
                continue;
        }
        // and the opposite?
        else {
            QString v = QString("QC_DISABLE_") + qc_escapeArg(o->shortname());
            if (getenv(v) == "Y")
                continue;
        }

        bool    output = true;
        QString check  = o->checkString();
        if (check.isEmpty())
            output = false;

        if (output) {
            printf("%s", check.toLatin1().data());
            fflush(stdout);
        }

        first_debug = true;
        bool ok     = o->exec();
        o->success  = ok;

        if (output) {
            QString result = o->resultString();
            if (!first_debug)
                printf(" -> %s\\n", result.toLatin1().data());
            else
                printf(" %s\\n", result.toLatin1().data());
        }

        if (!ok && o->required) {
            printf("\\nError: need %s!\\n", o->name().toLatin1().data());
            return false;
        }
    }
    return true;
}

QString Conf::qvar(const QString &s) { return vars.value(s); }

QString Conf::normalizePath(const QString &s) const { return qc_normalize_path(s); }

QString Conf::escapeQmakeVar(const QString &s) const { return qc_escape_string_var(s); }

QString Conf::escapedIncludes() const { return qc_prepare_includepath(INCLUDEPATH); }

QString Conf::escapedLibs() const { return qc_prepare_libs(LIBS); }

QString Conf::expandIncludes(const QString &inc) { return QLatin1String("-I") + inc; }

QString Conf::expandLibs(const QString &lib) { return QLatin1String("-L") + lib; }

int Conf::doCommand(const QString &s, QByteArray *out)
{
    debug(QString("[%1]").arg(s));
    int r = qc_runcommand(s, out, debug_enabled);
    debug(QString("returned: %1").arg(r));
    return r;
}

int Conf::doCommand(const QString &prog, const QStringList &args, QByteArray *out)
{
    QString fullcmd = prog;
    QString argstr  = args.join(QLatin1String(" "));
    if (!argstr.isEmpty())
        fullcmd += QString(" ") + argstr;
    debug(QString("[%1]").arg(fullcmd));
    int r = qc_runprogram(prog, args, out, debug_enabled);
    debug(QString("returned: %1").arg(r));
    return r;
}

bool Conf::doCompileAndLink(const QString &filedata, const QStringList &incs, const QString &libs,
                            const QString &proextra, int *retcode)
{
#ifdef Q_OS_WIN
    QDir tmp("qconftemp");
#else
    QDir tmp(".qconftemp");
#endif
    QStringList normalizedLibs;
    foreach (const QString &l, qc_splitflags(libs)) {
        normalizedLibs.append(qc_normalize_path(l));
    }

    if (!tmp.mkdir("atest")) {
        debug(QString("unable to create atest dir: %1").arg(tmp.absoluteFilePath("atest")));
        return false;
    }
    QDir dir(tmp.filePath("atest"));
    if (!dir.exists()) {
        debug("atest dir does not exist");
        return false;
    }

    QString fname = dir.filePath("atest.cpp");
    QString out   = "atest";
    QFile   f(fname);
    if (!f.open(QFile::WriteOnly | QFile::Truncate)) {
        debug("unable to open atest.cpp for writing");
        return false;
    }
    if (f.write(filedata.toLatin1()) == -1) {
        debug("error writing to atest.cpp");
        return false;
    }
    f.close();

    debug(QString("Wrote atest.cpp:\\n%1").arg(filedata));

    QString pro = QString("CONFIG  += console\\n"
                          "CONFIG  -= qt app_bundle\\n"
                          "DESTDIR  = \$\$PWD\\n"
                          "SOURCES += atest.cpp\\n");
    QString inc = qc_prepare_includepath(incs);
    if (!inc.isEmpty())
        pro += "INCLUDEPATH += " + inc + '\\n';
    QString escaped_libs = qc_prepare_libs(normalizedLibs);
    if (!escaped_libs.isEmpty())
        pro += "LIBS += " + escaped_libs + '\\n';
    pro += proextra;

    fname = dir.filePath("atest.pro");
    f.setFileName(fname);
    if (!f.open(QFile::WriteOnly | QFile::Truncate)) {
        debug("unable to open atest.pro for writing");
        return false;
    }
    if (f.write(pro.toLatin1()) == -1) {
        debug("error writing to atest.pro");
        return false;
    }
    f.close();

    debug(QString("Wrote atest.pro:\\n%1").arg(pro));

    QString oldpath = QDir::currentPath();
    QDir::setCurrent(dir.path());

    bool ok = false;
    int  r  = doCommand(qmake_path, QStringList() << "atest.pro");
    if (r == 0) {
        r = doCommand(maketool, QStringList());
        if (r == 0) {
            ok = true;
            if (retcode) {
                QString runatest = out;
#ifdef Q_OS_UNIX
                runatest.prepend("./");
#endif
                *retcode = doCommand(runatest, QStringList());
            }
        }
        r = doCommand(maketool, QStringList() << "distclean");
        if (r != 0)
            debug("error during atest distclean");
    }

    QDir::setCurrent(oldpath);

    // cleanup
    // dir.remove("atest.pro");
    // dir.remove("atest.cpp");
    // tmp.rmdir("atest");

    // remove whole dir since distclean doesn't always work
    qc_removedir(tmp.filePath("atest"));

    if (!ok)
        return false;
    return true;
}

bool Conf::checkHeader(const QString &path, const QString &h) { return QDir(path).exists(h); }

bool Conf::findHeader(const QString &h, const QStringList &ext, QString *inc)
{
    if (checkHeader("/usr/include", h)) {
        *inc = "";
        return true;
    }
    QStringList dirs;
    dirs += "/usr/local/include";
    dirs += ext;

    QString prefix = qc_getenv("PREFIX");
    if (!prefix.isEmpty()) {
        prefix += "/include";
        prefix = qc_normalize_path(prefix);
        if (!dirs.contains(prefix))
            dirs << prefix;
    }

    for (QStringList::ConstIterator it = dirs.begin(); it != dirs.end(); ++it) {
        if (checkHeader(*it, h)) {
            *inc = *it;
            return true;
        }
    }
    return false;
}

bool Conf::checkLibrary(const QString &path, const QString &name)
{
    QString str =
        //"#include <stdio.h>\\n"
        "int main()\\n"
        "{\\n"
        //"    printf(\\"library checker running\\\\\\\\n\\");\\n"
        "    return 0;\\n"
        "}\\n";

    QString libs;
    if (!path.isEmpty())
        libs += QString("-L") + path + ' ';
    libs += QString("-l") + name;
    if (!doCompileAndLink(str, QStringList(), libs, QString()))
        return false;
    return true;
}

bool Conf::findLibrary(const QString &name, QString *lib)
{
    if (checkLibrary("", name)) {
        *lib = "";
        return true;
    }
    if (checkLibrary("/usr/local/lib", name)) {
        *lib = "/usr/local/lib";
        return true;
    }

    QString prefix = qc_getenv("PREFIX");
    if (!prefix.isEmpty()) {
        prefix += "/lib";
        prefix = qc_normalize_path(prefix);
        if (checkLibrary(prefix, name)) {
            *lib = prefix;
            return true;
        }
    }

    return false;
}

QString Conf::findProgram(const QString &prog) { return qc_findprogram(prog); }

bool Conf::findSimpleLibrary(const QString &incvar, const QString &libvar, const QString &incname,
                             const QString &libname, QString *incpath, QString *libs)
{
    QString inc, lib;
    QString s;

    s = getenv(incvar).trimmed();
    if (!s.isEmpty()) {
        if (!checkHeader(s, incname)) {
            if (debug_enabled)
                printf("%s is not found in \\"%s\\"\\n", qPrintable(incname), qPrintable(s));
            return false;
        }
        inc = s;
    } else {
        if (!findHeader(incname, QStringList(), &s)) {
            if (debug_enabled)
                printf("%s is not found anywhere\\n", qPrintable(incname));
            return false;
        }
        inc = s;
    }

    s = getenv(libvar).trimmed();
    if (!s.isEmpty()) {
        if (!checkLibrary(s, libname)) {
            if (debug_enabled)
                printf("%s is not found in \\"%s\\"\\n", qPrintable(libname), qPrintable(s));
            return false;
        }
        lib = s;
    } else {
        if (!findLibrary(libname, &s)) {
            if (debug_enabled)
                printf("%s is not found anywhere\\n", qPrintable(libname));
            return false;
        }
        lib = s;
    }

    QString lib_out;
    if (!lib.isEmpty())
        lib_out += QString("-L") + s + " ";
    lib_out += QString("-l") + libname;

    *incpath = inc;
    *libs    = lib_out;
    return true;
}

bool Conf::findFooConfig(const QString &path, QString *version, QStringList *incs, QString *libs, QString *otherflags)
{
    QStringList args;
    QByteArray  out;
    int         ret;

    args += "--version";
    ret = doCommand(path, args, &out);
    if (ret != 0)
        return false;

    QString version_out = QString::fromLatin1(out).trimmed();

    args.clear();
    args += "--libs";
    ret = doCommand(path, args, &out);
    if (ret != 0)
        return false;

    QString libs_out = QString::fromLatin1(out).trimmed();

    args.clear();
    args += "--cflags";
    ret = doCommand(path, args, &out);
    if (ret != 0)
        return false;

    QString cflags = QString::fromLatin1(out).trimmed();

    QStringList incs_out, otherflags_out;
    qc_splitcflags(cflags, &incs_out, &otherflags_out);

    *version    = version_out;
    *incs       = incs_out;
    *libs       = libs_out;
    *otherflags = otherflags_out.join(QLatin1String(" "));
    return true;
}

bool Conf::findPkgConfig(const QString &name, VersionMode mode, const QString &req_version, QString *version,
                         QStringList *incs, QString *libs, QString *otherflags)
{
    QStringList args;
    QByteArray  out;
    int         ret;

    args += name;
    args += "--exists";
    ret = doCommand("pkg-config", args, &out);
    if (ret != 0)
        return false;

    if (mode != VersionAny) {
        args.clear();
        args += name;
        if (mode == VersionMin)
            args += QString("--atleast-version=%1").arg(req_version);
        else if (mode == VersionMax)
            args += QString("--max-version=%1").arg(req_version);
        else
            args += QString("--exact-version=%1").arg(req_version);
        ret = doCommand("pkg-config", args, &out);
        if (ret != 0)
            return false;
    }

    args.clear();
    args += name;
    args += "--modversion";
    ret = doCommand("pkg-config", args, &out);
    if (ret != 0)
        return false;

    QString version_out = QString::fromLatin1(out).trimmed();

    args.clear();
    args += name;
    args += "--libs";
    ret = doCommand("pkg-config", args, &out);
    if (ret != 0)
        return false;

    QString libs_out = QString::fromLatin1(out).trimmed();

    args.clear();
    args += name;
    args += "--cflags";
    ret = doCommand("pkg-config", args, &out);
    if (ret != 0)
        return false;

    QString cflags = QString::fromLatin1(out).trimmed();

    QStringList incs_out, otherflags_out;
    qc_splitcflags(cflags, &incs_out, &otherflags_out);

    *version    = version_out;
    *incs       = incs_out;
    *libs       = libs_out;
    *otherflags = otherflags_out.join(QLatin1String(" "));
    return true;
}

void Conf::addDefine(const QString &str)
{
    if (DEFINES.isEmpty())
        DEFINES = str;
    else
        DEFINES += QString(" ") + str;
    debug(QString("DEFINES += %1").arg(str));
}

void Conf::addLib(const QString &str)
{
    QStringList libs = qc_splitflags(str);
    foreach (const QString &lib, libs) {
        if (lib.startsWith("-l")) {
            LIBS.append(lib);
        } else {
            LIBS.append(qc_normalize_path(lib)); // we don't care about -L prefix since normalier does not touch it.
        }
    }
    debug(QString("LIBS += %1").arg(str));
}

void Conf::addIncludePath(const QString &str)
{
    INCLUDEPATH.append(qc_normalize_path(str));
    debug(QString("INCLUDEPATH += %1").arg(str));
}

void Conf::addExtra(const QString &str)
{
    extra += str + '\\n';
    debug(QString("extra += %1").arg(str));
}

//----------------------------------------------------------------------------
// main
//----------------------------------------------------------------------------
#include "conf4.moc"

#ifdef HAVE_MODULES
#include "modules.cpp"
#endif

int main(int argc, char **argv)
{
    QCoreApplication app(argc, argv);
    Conf *           conf = new Conf;
    ConfObj *        o    = 0;
    Q_UNUSED(o);
#ifdef HAVE_MODULES
#include "modules_new.cpp"
#endif

    conf->debug_enabled = (qc_getenv("QC_VERBOSE") == "Y") ? true : false;
    if (conf->debug_enabled)
        printf(" -> ok\\n");
    else
        printf("ok\\n");

    QString confCommand = qc_getenv("QC_COMMAND");
    QString proName     = qc_getenv("QC_PROFILE");
    conf->qmake_path    = qc_getenv("QC_QMAKE");
    conf->qmakespec     = qc_getenv("QC_QMAKESPEC");
    conf->maketool      = qc_getenv("QC_MAKETOOL");

    if (conf->debug_enabled)
        printf("conf command: [%s]\\n", qPrintable(confCommand));

    QString confPath = qc_findself(confCommand);
    if (confPath.isEmpty()) {
        printf("Error: cannot find myself; rerun with an absolute path\\n");
        return 1;
    }

    QString srcdir   = QFileInfo(confPath).absolutePath();
    QString builddir = QDir::current().absolutePath();
    QString proPath  = QDir(srcdir).filePath(proName);

    if (conf->debug_enabled) {
        printf("conf path:    [%s]\\n", qPrintable(confPath));
        printf("srcdir:       [%s]\\n", qPrintable(srcdir));
        printf("builddir:     [%s]\\n", qPrintable(builddir));
        printf("profile:      [%s]\\n", qPrintable(proPath));
        printf("qmake path:   [%s]\\n", qPrintable(conf->qmake_path));
        printf("qmakespec:    [%s]\\n", qPrintable(conf->qmakespec));
        printf("make tool:    [%s]\\n", qPrintable(conf->maketool));
        printf("\\n");
    }

    bool success = false;
    if (conf->exec()) {
        QFile f("conf.pri");
        if (!f.open(QFile::WriteOnly | QFile::Truncate)) {
            printf("Error writing %s\\n", qPrintable(f.fileName()));
            return 1;
        }

        QString str;
        str += "# qconf\\n\\n";
        str += "greaterThan(QT_MAJOR_VERSION, 4):CONFIG += c++11\\n";

        QString var;
        var = qc_normalize_path(qc_getenv("PREFIX"));
        if (!var.isEmpty())
            str += QString("PREFIX = %1\\n").arg(var);
        var = qc_normalize_path(qc_getenv("BINDIR"));
        if (!var.isEmpty())
            str += QString("BINDIR = %1\\n").arg(var);
        var = qc_normalize_path(qc_getenv("INCDIR"));
        if (!var.isEmpty())
            str += QString("INCDIR = %1\\n").arg(var);
        var = qc_normalize_path(qc_getenv("LIBDIR"));
        if (!var.isEmpty())
            str += QString("LIBDIR = %1\\n").arg(var);
        var = qc_normalize_path(qc_getenv("DATADIR"));
        if (!var.isEmpty())
            str += QString("DATADIR = %1\\n").arg(var);
        str += '\\n';

        if (qc_getenv("QC_STATIC") == "Y")
            str += "CONFIG += staticlib\\n";

        // TODO: don't need this?
        // str += "QT_PATH_PLUGINS = " + QString(qInstallPathPlugins()) + '\\n';

        if (!conf->DEFINES.isEmpty())
            str += "DEFINES += " + conf->DEFINES + '\\n';
        if (!conf->INCLUDEPATH.isEmpty())
            str += "INCLUDEPATH += " + qc_prepare_includepath(conf->INCLUDEPATH) + '\\n';
        if (!conf->LIBS.isEmpty())
            str += "LIBS += " + qc_prepare_libs(conf->LIBS) + '\\n';
        if (!conf->extra.isEmpty())
            str += conf->extra;
        str += '\\n';

        var = qc_getenv("QC_EXTRACONF");
        if (!var.isEmpty())
            str += ("\\n# Extra conf from command line\\n" + var + "\\n");

        QByteArray cs = str.toLatin1();
        f.write(cs);
        f.close();
        success = true;
    }
    QString qmake_path = conf->qmake_path;
    QString qmakespec  = conf->qmakespec;
    delete conf;

    if (!success)
        return 1;

    // run qmake on the project file
    QStringList args;
    if (!qmakespec.isEmpty()) {
        args += "-spec";
        args += qmakespec;
    }
    args += proPath;
    int ret = qc_runprogram(qmake_path, args, 0, true);
    if (ret != 0)
        return 1;

    return 0;
}

EOT
cat >"$1/conf4.pro" <<EOT
CONFIG  += console
CONFIG  -= app_bundle
QT      -= gui
TARGET   = conf
DESTDIR  = \$\$PWD

HEADERS += conf4.h
SOURCES += conf4.cpp


DEFINES += HAVE_MODULES

greaterThan(QT_MAJOR_VERSION, 4):CONFIG += c++11

EOT
}

export PREFIX
export BINDIR
export LIBDIR
export DATADIR
export EX_QTDIR
export QC_EXTRACONF
export QC_RELEASE
export QC_DEBUG
export QC_NO_SEPARATE_DEBUG_INFO
export QC_SEPARATE_DEBUG_INFO
export QC_PSIPLUS
export QC_WITH_IDN_INC
export QC_WITH_IDN_LIB
export QC_WITH_QCA_INC
export QC_WITH_QCA_LIB
export QC_WITH_ZLIB_INC
export QC_WITH_ZLIB_LIB
export QC_WITH_QJDNS_INC
export QC_WITH_QJDNS_LIB
export QC_ENABLE_universal
export QC_DEFAULT_DISABLE_universal
export QC_DISABLE_qdbus
export QC_DEFAULT_ENABLE_qdbus
export QC_DISABLE_keychain
export QC_DEFAULT_ENABLE_keychain
export QC_ENABLE_webkit
export QC_DEFAULT_DISABLE_webkit
export QC_WITH_WEBKIT
export QC_WITH_HTTP_PARSER_INC
export QC_WITH_HTTP_PARSER_LIB
export QC_BUNDLED_HTTP_PARSER
export QC_WITH_B2_INC
export QC_WITH_B2_LIB
export QC_DISABLE_growl
export QC_DEFAULT_ENABLE_growl
export QC_WITH_GROWL
export QC_ENABLE_whiteboarding
export QC_DEFAULT_DISABLE_whiteboarding
export QC_DISABLE_xss
export QC_DEFAULT_ENABLE_xss
export QC_DISABLE_aspell
export QC_DEFAULT_ENABLE_aspell
export QC_WITH_ASPELL_INC
export QC_WITH_ASPELL_LIB
export QC_DISABLE_enchant
export QC_DEFAULT_ENABLE_enchant
export QC_DISABLE_hunspell
export QC_DEFAULT_ENABLE_hunspell
export QC_WITH_HUNSPELL_INC
export QC_WITH_HUNSPELL_LIB
export QC_DISABLE_plugins
export QC_DEFAULT_ENABLE_plugins
export QC_VERBOSE
export QC_QTSELECT
rm -rf ".qconftemp"
(
    mkdir ".qconftemp"
    gen_files ".qconftemp"
    cd ".qconftemp"
    if [ ! -z "$qm_spec" ]; then
        "$qm" -spec $qm_spec conf4.pro >/dev/null
    else
        "$qm" conf4.pro >/dev/null
    fi
    $MAKE clean >/dev/null 2>&1
    $MAKE >../conf.log 2>&1
)

if [ "$?" != "0" ]; then
    rm -rf ".qconftemp"
    if [ "$QC_VERBOSE" = "Y" ]; then
        echo " -> fail"
    else
        echo "fail"
    fi
    printf "\n"
    printf "Reason: There was an error compiling 'conf'.  See conf.log for details.\n"
    printf "\n"
    show_qt_info
    if [ "$QC_VERBOSE" = "Y" ]; then
        echo "conf.log:"
        cat conf.log
    fi
    exit 1;
fi

QC_COMMAND=$0
export QC_COMMAND
QC_PROFILE=psi.pro
export QC_PROFILE
QC_QMAKE="$qm"
export QC_QMAKE
QC_QMAKESPEC=$qm_spec
export QC_QMAKESPEC
QC_MAKETOOL=$MAKE
export QC_MAKETOOL
".qconftemp/conf"
ret="$?"
if [ "$ret" = "1" ]; then
    rm -rf ".qconftemp"
    echo
    exit 1;
else
    if [ "$ret" != "0" ]; then
        rm -rf ".qconftemp"
        if [ "$QC_VERBOSE" = "Y" ]; then
            echo " -> fail"
        else
            echo "fail"
        fi
        echo
        echo "Reason: Unexpected error launching 'conf'"
        echo
        exit 1;
    fi
fi
rm -rf ".qconftemp"

echo
echo "Good, your configure finished.  Now run $MAKE."
echo
