#!/bin/bash

#
# pacaur: an AUR helper that minimizes user interaction
#

version="4.7.10"

#
# Config
#

# sanitize
unset aur cleancache devel edit info installpkg foreign needed noconfirm nodeps noedit
unset operation pac pacQ pacS quiet rebuild refresh repo search selective upgrade

# internationalization
LC_COLLATE=C                                # getopts sorting
TEXTDOMAIN='pacaur'
TEXTDOMAINDIR='/usr/share/locale'

# determine config location
if [[ -n "${XDG_CONFIG_DIRS}" ]]; then
    for i in ${XDG_CONFIG_DIRS//:/ }; do
        [[ -d "$i/pacaur" ]] && export XDG_CONFIG_DIRS="$i" && break
    done
fi
configdir="${XDG_CONFIG_DIRS:-/etc/xdg}/pacaur"
userconfigdir="${XDG_CONFIG_HOME:-${HOME}/.config}/pacaur"
userpacmandir="${XDG_CONFIG_HOME:-${HOME}/.config}/pacman"
usercachedir="${XDG_CACHE_HOME:-${HOME}/.cache}/pacaur"
tmpdir="${XDG_RUNTIME_DIR:-/tmp}"

# preserve environment variables
[[ -n ${PACMAN} ]] && _PACMAN=${PACMAN}
[[ -n ${PKGDEST} ]] && _PKGDEST=${PKGDEST}
[[ -n ${SRCDEST} ]] && _SRCDEST=${SRCDEST}
[[ -n ${SRCPKGDEST} ]] && _SRCPKGDEST=${SRCPKGDEST}
[[ -n ${LOGDEST} ]] && _LOGDEST=${LOGDEST}
[[ -n ${BUILDDIR} ]] && _BUILDDIR=${BUILDDIR}
[[ -n ${PKGEXT} ]] && _PKGEXT=${PKGEXT}
[[ -n ${SRCEXT} ]] && _SRCEXT=${SRCEXT}
[[ -n ${GPGKEY} ]] && _GPGKEY=${GPGKEY}
[[ -n ${PACKAGER} ]] && _PACKAGER=${PACKAGER}
[[ -n ${CARCH} ]] && _CARCH=${CARCH}

# source makepkg variables
if [[ -r "$MAKEPKG_CONF" ]]; then
    source "$MAKEPKG_CONF"
else
    source /etc/makepkg.conf
    if [[ -r "$userpacmandir/makepkg.conf" ]]; then
        source "$userpacmandir/makepkg.conf"
    elif [[ -r "$HOME/.makepkg.conf" ]]; then
        source "$HOME/.makepkg.conf"
    fi
fi

# restore environment variables
PACMAN=${_PACMAN:-$PACMAN}
PKGDEST=${_PKGDEST:-$PKGDEST}
SRCDEST=${_SRCDEST:-$SRCDEST}
SRCPKGDEST=${_SRCPKGDEST:-$SRCPKGDEST}
LOGDEST=${_LOGDEST:-$LOGDEST}
BUILDDIR=${_BUILDDIR:-$BUILDDIR}
PKGEXT=${_PKGEXT:-$PKGEXT}
SRCEXT=${_SRCEXT:-$SRCEXT}
GPGKEY=${_GPGKEY:-$GPGKEY}
PACKAGER=${_PACKAGER:-$PACKAGER}
CARCH=${_CARCH:-$CARCH}

# set default config variables
editor="${VISUAL:-${EDITOR:-vi}}"           # build files editor
displaybuildfiles=diff                      # display build files (none|diff|full)
fallback=true                               # pacman fallback to the AUR
silent=false                                # silence output
sortby=popularity                           # sort method (name|votes|popularity)
sortorder=descending                        # sort order (ascending|descending)
sudoloop=true                               # prevent sudo timeout

# set variables
pacmanbin="${PACMAN:-pacman}"               # pacman binary
clonedir="${AURDEST:-$usercachedir}"        # clone directory

# set AUR variables
aururl="aur.archlinux.org"
aurrpc="/rpc/?type=info&v=5"

# source xdg config
source "$configdir/config"
[[ -r "$userconfigdir/config" ]] && source "$userconfigdir/config"

# set up directories
[[ ! -d "$clonedir" ]] && mkdir -p "$clonedir" -m 700

#
# Functions
#

ClassifyPkgs() {
    local noaurpkgs norepopkgs
    # global aurpkgs repopkgs
    if [[ $fallback = true ]]; then
        [[ $repo ]] && repopkgs=(${pkgs[@]})
        [[ $aur ]] && aurpkgs=(${pkgs[@]})
        if [[ ! $repo && ! $aur ]]; then
            unset noaurpkgs
            for i in "${pkgs[@]}"; do
                [[ $i == aur/* ]] && aurpkgs+=(${i:4}) && continue # search aur/pkgs in AUR
                noaurpkgs+=($i)
            done
            [[ -n "${noaurpkgs[@]}" ]] && norepopkgs=($(LANG=C $pacmanbin -Sp ${noaurpkgs[@]} 2>&1 >/dev/null | awk '{print $NF}'))
            for i in "${norepopkgs[@]}"; do
                [[ ! " ${noaurpkgs[@]} " =~ [a-zA-Z0-9\.\+-]+\/$i[^a-zA-Z0-9\.\+-] ]] && aurpkgs+=($i) # do not search repo/pkgs in AUR
            done
            repopkgs=($(grep -xvf <(printf '%s\n' "${aurpkgs[@]}") <(printf '%s\n' "${noaurpkgs[@]}")))
        fi
    else
        [[ ! $aur ]] && repopkgs=(${pkgs[@]}) || aurpkgs=(${pkgs[@]})
    fi
}

Core() {
    GetIgnoredPkgs
    GetIgnoredGrps
    [[ $upgrade ]] && UpgradeAur
    IgnoreChecks
    DepsSolver
    IgnoreDepsChecks
    ProviderChecks
    ConflictChecks
    ReinstallChecks
    OutofdateChecks
    OrphanChecks
    Prompt
    MakePkgs
}

UpgradeAur() {
    local foreignpkgs allaurpkgs allaurpkgsAver allaurpkgsQver aurforeignpkgs i json
    # global aurpkgs
    Note "i" $"${colorW}Starting AUR upgrade...${reset}"

    # selective upgrade switch
    if [[ $selective && -n ${pkgs[@]} ]]; then
        aurpkgs+=(${pkgs[@]})
    else
        foreignpkgs=($($pacmanbin -Qmq))
        SetJson ${foreignpkgs[@]}
        allaurpkgs=($(GetJson "var" "$json" "Name"))
        allaurpkgsAver=($(GetJson "var" "$json" "Version"))
        allaurpkgsQver=($(expac -Q '%v' ${allaurpkgs[@]}))
        for i in "${!allaurpkgs[@]}"; do
            [[ $(vercmp "${allaurpkgsAver[$i]}" "${allaurpkgsQver[$i]}") -gt 0 ]] && aurpkgs+=(${allaurpkgs[$i]});
        done
    fi

    # foreign packages check
    aurforeignpkgs=($(grep -xvf <(printf '%s\n' "${allaurpkgs[@]}") <(printf '%s\n' "${foreignpkgs[@]}")))
    for i in "${aurforeignpkgs[@]}"; do
        Note "w" $"${colorW}$i${reset} is ${colorY}not present${reset} in AUR -- skipping"
    done

    # add devel packages
    if [[ $devel ]]; then
        for i in "${allaurpkgs[@]}"; do
            [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< $i)" ]] && aurpkgs+=($i)
        done
    fi

    # avoid possible duplicate
    aurpkgs=($(tr ' ' '\n' <<< ${aurpkgs[@]} | sort -u))

    NothingToDo ${aurpkgs[@]}
}

IgnoreChecks() {
    local checkaurpkgs checkaurpkgsAver checkaurpkgsAgrp checkaurpkgsQver checkaurpkgsQgrp i json
    # global aurpkgs rmaurpkgs
    [[ -z "${ignoredpkgs[@]}" && -z "${ignoredgrps[@]}" ]] && return

    # remove AUR pkgs versioning
    for i in "${!aurpkgs[@]}"; do
        aurpkgsnover[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${aurpkgs[$i]})
    done

    # check targets
    SetJson ${aurpkgsnover[@]}
    checkaurpkgs=($(GetJson "var" "$json" "Name"))
    errdeps+=($(grep -xvf <(printf '%s\n' "${aurpkgsnover[@]}") <(printf '%s\n' "${checkaurpkgs[@]}")))
    errdeps+=($(grep -xvf <(printf '%s\n' "${checkaurpkgs[@]}") <(printf '%s\n' "${aurpkgsnover[@]}")))
    unset aurpkgsnover

    checkaurpkgsAver=($(GetJson "var" "$json" "Version"))
    checkaurpkgsQver=($(expac -Q '%v' "${checkaurpkgs[@]}"))
    for i in "${!checkaurpkgs[@]}"; do
        [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< ${checkaurpkgs[$i]})" ]] && checkaurpkgsAver[$i]=$"latest"
    done
    for i in "${!checkaurpkgs[@]}"; do
        unset isignored
        if [[ " ${ignoredpkgs[@]} " =~ " ${checkaurpkgs[$i]} " ]]; then
            isignored=true
        elif [[ -n "${ignoredgrps[@]}" ]]; then
            unset checkaurpkgsAgrp checkaurpkgsQgrp
            checkaurpkgsAgrp=($(GetJson "arrayvar" "$json" "Groups" "${checkaurpkgs[$i]}"))
            for j in "${checkaurpkgsAgrp[@]}"; do
                [[ " ${ignoredgrps[@]} " =~ " $j " ]] && isignored=true
            done
            checkaurpkgsQgrp=($(expac -Q '%G' "${checkaurpkgs[$i]}"))
            for j in "${checkaurpkgsQgrp[@]}"; do
                [[ " ${ignoredgrps[@]} " =~ " $j " ]] && isignored=true
            done
        fi

        if [[ $isignored = true ]]; then
            if [[ ! $upgrade ]]; then
                if [[ ! $noconfirm ]]; then
                    if ! Proceed "y" $"${checkaurpkgs[$i]} is in IgnorePkg/IgnoreGroup. Install anyway?"; then
                        Note "w" $"skipping target: ${colorW}${checkaurpkgs[$i]}${reset}"
                        rmaurpkgs+=(${checkaurpkgs[$i]})
                        continue
                    fi
                else
                    Note "w" $"skipping target: ${colorW}${checkaurpkgs[$i]}${reset}"
                    rmaurpkgs+=(${checkaurpkgs[$i]})
                    continue
                fi
            else
                Note "w" $"${colorW}${checkaurpkgs[$i]}${reset}: ignoring package upgrade (${colorR}${checkaurpkgsQver[$i]}${reset} => ${colorG}${checkaurpkgsAver[$i]}${reset})"
                rmaurpkgs+=(${checkaurpkgs[$i]})
                continue
            fi
        fi
        aurpkgsnover+=(${checkaurpkgs[$i]})
    done

    aurpkgs=(${aurpkgsnover[@]})
    NothingToDo ${aurpkgs[@]}
}

DepsSolver() {
    local i aurpkgsname aurpkgsver aurpkgsaurver aurpkgsconflicts
    # global aurpkgs aurpkgsnover aurpkgsproviders aurdeps deps json errdeps errdepsnover foreignpkgs repodeps depsAname depsAver depsAood depsQver
    Note "i" $"resolving dependencies..."

    # remove AUR pkgs versioning
    for i in "${!aurpkgs[@]}"; do
        aurpkgsnover[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${aurpkgs[$i]})
    done

    # set unversionned json
    SetJson ${aurpkgsnover[@]}

    # set targets providers
    aurpkgsproviders=(${aurpkgsnover[@]})
    aurpkgsproviders+=($(GetJson "array" "$json" "Provides"))
    for i in "${!aurpkgsproviders[@]}"; do
        aurpkgsproviders[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${aurpkgsproviders[$i]})
    done

    # check targets conflicts
    aurpkgsconflicts=($(GetJson "array" "$json" "Conflicts"))
    if [[ -n "${aurpkgsconflicts[@]}" ]]; then
        for i in "${!aurpkgsconflicts[@]}"; do
            aurpkgsconflicts[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${aurpkgsconflicts[$i]})
        done

        aurpkgsconflicts=($(grep -xf <(printf '%s\n' "${aurpkgsproviders[@]}") <(printf '%s\n' "${aurpkgsconflicts[@]}")))
        aurpkgsconflicts=($(tr ' ' '\n' <<< ${aurpkgsconflicts[@]} | LC_COLLATE=C sort -u))

        for i in "${aurpkgsconflicts[@]}"; do
            [[ ! " ${aurpkgsnover[@]} " =~ " $i " ]] && continue
            [[ " $(GetJson "arrayvar" "$json" "Conflicts" "$i") " =~ " $i " ]] && continue
            Note "f" $"unresolvable package conflicts detected"
            Note "e" $"failed to prepare transaction (conflicting dependencies: $i)"
        done
    fi

    deps=(${aurpkgsnover[@]})

    [[ -z "${foreignpkgs[@]}" ]] && foreignpkgs=($($pacmanbin -Qmq))
    FindDepsAur ${aurpkgsnover[@]}

    # avoid possible duplicate
    deps=($(grep -xvf <(printf '%s\n' "${aurdepspkgs[@]}") <(printf '%s\n' "${deps[@]}")))
    deps+=(${aurdepspkgs[@]})

    # ensure correct dependency order
    SetJson ${deps[@]}
    SortDepsAur ${aurpkgs[@]}
    deps=($(tsort <<< ${tsortdeps[@]}))

    # error check
    if (($? > 0)); then
        Note "e" $"dependency cycle detected"
    fi

    # get AUR packages info
    depsAname=($(GetJson "var" "$json" "Name"))
    depsAver=($(GetJson "var" "$json" "Version"))
    depsAood=($(GetJson "var" "$json" "OutOfDate"))
    depsAmain=($(GetJson "var" "$json" "Maintainer"))
    for i in "${!depsAname[@]}"; do
        depsQver[$i]=$(expac -Qs '%v' "^${depsAname[$i]}$" | head -1)
        [[ -z "${depsQver[$i]}" ]] && depsQver[$i]="#"  # avoid empty elements shift
        [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< ${depsAname[$i]})" ]] && depsAver[$i]=$"latest"
    done

    # no results check
    if [[ -n "${errdeps[@]}" ]]; then
        for i in "${!errdepsnover[@]}"; do
            if [[ " ${aurpkgsnover[@]} " =~ " ${errdepsnover[$i]} " ]]; then
                Note "f" $"no results found for ${errdeps[$i]}"
            else
                unset tsorterrdeps errdepslist currenterrdep
                # find relevant tsorted deps chain
                for j in "${deps[@]}"; do
                    tsorterrdeps+=($j)
                    [[ " $j " = " ${errdepsnover[$i]} " ]] && break
                done
                # reverse deps order
                tsorterrdeps=($(awk '{for (i=NF;i>=1;i--) print $i}' <<< ${tsorterrdeps[@]} | awk -F "\n" '{print}'))
                errdepslist+=(${tsorterrdeps[0]})
                FindDepsAurError ${tsorterrdeps[@]}
                errdepslist=($(awk '{for (i=NF;i>=1;i--) print $i}' <<< ${errdepslist[@]} | awk -F "\n" '{print}'))
                Note "f" $"no results found for ${errdeps[$i]} (dependency tree: ${errdepslist[*]})"
            fi
        done
        exit 1
    fi

    # return all binary deps
    FindDepsRepo ${repodeps[@]}
}

FindDepsAur() {
    local depspkgs depspkgstmp depspkgsaurtmp repodepstmp builtpkg vcsdepspkgs assumedepspkgs
    local aurversionpkgs aurversionpkgsname aurversionpkgsver aurversionpkgsaurver i j json
    # global aurpkgsnover depspkgsaur errdeps depsAname depsAver repodeps aurdepspkgs prevdepspkgsaur foreignpkgs
    [[ $nodeps && $count -ge 2 ]] && return

    # set json
    unset aurversionpkgs
    if [[ -z "${depspkgsaur[@]}" ]]; then
        SetJson ${aurpkgsnover[@]}
        aurversionpkgs=(${aurpkgs[@]})
    else
        SetJson ${depspkgsaur[@]}
        aurversionpkgs=(${prevdepspkgsaur[@]})
    fi

    # versioning check
    if [[ -n "${aurversionpkgs[@]}" ]]; then
        for i in "${!aurversionpkgs[@]}"; do
            unset aurversionpkgsname aurversionpkgsver aurversionpkgsaurver
            aurversionpkgsname=${aurversionpkgs[$i]} && aurversionpkgsname=${aurversionpkgsname%[><]*} && aurversionpkgsname=${aurversionpkgsname%=*}
            aurversionpkgsver=${aurversionpkgs[$i]} && aurversionpkgsver=${aurversionpkgsver#*=} && aurversionpkgsver=${aurversionpkgsver#*[><]}
            aurversionpkgsaurver=$(GetJson "varvar" "$json" "Version" "$aurversionpkgsname")

            # not found in AUR nor repo
            if [[ ! $aurversionpkgsaurver ]]; then
                [[ ! " ${errdeps[@]} " =~ " ${aurversionpkgs[$i]} " ]] && errdeps+=(${aurversionpkgs[$i]})
                continue
            fi

            case "${aurversionpkgs[$i]}" in
                *">"*|*"<"*|*"="*)
                    # found in AUR but version not correct
                    case "${aurversionpkgs[$i]}" in
                        *">="*) [[ $(vercmp "$aurversionpkgsaurver" "$aurversionpkgsver") -ge 0 ]] && continue;;
                        *"<="*) [[ $(vercmp "$aurversionpkgsaurver" "$aurversionpkgsver") -le 0 ]] && continue;;
                        *">"*)  [[ $(vercmp "$aurversionpkgsaurver" "$aurversionpkgsver") -gt 0 ]] && continue;;
                        *"<"*)  [[ $(vercmp "$aurversionpkgsaurver" "$aurversionpkgsver") -lt 0 ]] && continue;;
                        *"="*)  [[ $(vercmp "$aurversionpkgsaurver" "$aurversionpkgsver") -eq 0 ]] && continue;;
                    esac
                    [[ ! " ${errdeps[@]} " =~ " ${aurversionpkgs[$i]} " ]] && errdeps+=(${aurversionpkgs[$i]})
                ;;
                *) continue;;
            esac
        done
    fi

    depspkgs=($(GetJson "array" "$json" "Depends"))

    # cached packages makedeps check
    if [[ ! $PKGDEST || $rebuild || $foreign ]]; then
        depspkgs+=($(GetJson "array" "$json" "MakeDepends"))
        depspkgs+=($(GetJson "array" "$json" "CheckDepends"))
    else
        [[ -z "${depspkgsaur[@]}" ]] && depspkgsaurtmp=(${aurpkgs[@]}) || depspkgsaurtmp=(${depspkgsaur[@]})
        for i in "${!depspkgsaurtmp[@]}"; do
            depsAname=$(GetJson "varvar" "$json" "Name" "${depspkgsaurtmp[$i]}")
            depsAver=$(GetJson "varvar" "$json" "Version" "${depspkgsaurtmp[$i]}")
            GetBuiltPkg "$depsAname-$depsAver" "$PKGDEST"
            if [[ ! $builtpkg ]]; then
                depspkgs+=($(GetJson "arrayvar" "$json" "MakeDepends" "${depspkgsaurtmp[$i]}"))
                depspkgs+=($(GetJson "arrayvar" "$json" "CheckDepends" "${depspkgsaurtmp[$i]}"))
            fi
            unset builtpkg
        done
    fi

    # remove deps provided by targets
    if [[ -n "${aurpkgsproviders[@]}" ]]; then
        depspkgs=($(grep -xvf <(printf '%s\n' "${aurpkgsproviders[@]}") <(printf '%s\n' "${depspkgs[@]}")))
    fi

    # workaround for limited RPC support of architecture dependent fields
    if [[ ${CARCH} == 'i686' ]]; then
        depspkgstmp=(${depspkgs[@]})
        for i in "${!depspkgstmp[@]}"; do
             [[ -n "$(grep -E "^lib32\-" <<< ${depspkgstmp[$i]})" ]] && depspkgs=($(tr ' ' '\n' <<< ${depspkgs[@]} | sed "s/^${depspkgstmp[$i]}$//g"))
             [[ -n "$(grep -E "^gcc-multilib$" <<< ${depspkgstmp[$i]})" ]] && depspkgs=($(tr ' ' '\n' <<< ${depspkgs[@]} | sed "s/^${depspkgstmp[$i]}$//g"))
        done
    fi

    # remove installed deps
    if [[ ! $foreign && ! $devel ]]; then
        depspkgs=($($pacmanbin -T ${depspkgs[@]} | sort -u))
    else
        # remove versioning and check providers
        unset vcsdepspkgs
        for i in "${!depspkgs[@]}"; do
            depspkgs[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${depspkgs[$i]})
            unset j && j=$(expac -Qs '%n %P' "^${depspkgs[$i]}$" | head -1 | grep -E "([^a-zA-Z0-9_@\.\+-]${depspkgs[$i]}|^${depspkgs[$i]})" | grep -E "(${depspkgs[$i]}[^a-zA-Z0-9\.\+-]|${depspkgs[$i]}$)" | awk '{print $1}')
            if [[ -n "$j" ]]; then
                depspkgs[$i]="$j"
                [[ $devel ]] && [[ ! " ${ignoredpkgs[@]} " =~ " $j " ]] && [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< $j)" ]] && vcsdepspkgs+=($j)
            else
                foreignpkgs+=(${depspkgs[$i]})
            fi
        done
        # reorder devel
        if [[ $devel ]]; then
            [[ ! $foreign ]] && depspkgs=($($pacmanbin -T ${depspkgs[@]} | sort -u))
            depspkgstmp=($(grep -xvf <(printf '%s\n' "${depspkgs[@]}") <(printf '%s\n' "${vcsdepspkgs[@]}")))
            depspkgstmp+=($(grep -xvf <(printf '%s\n' "${vcsdepspkgs[@]}") <(printf '%s\n' "${depspkgs[@]}")))
            depspkgs=($(tr ' ' '\n' <<< ${depspkgstmp[@]} | LC_COLLATE=C sort -u))
        fi
        # remove installed binary packages only
        if [[ $foreign ]]; then
            depspkgs=($(grep -xf <(printf '%s\n' "${depspkgs[@]}") <(printf '%s\n' "${foreignpkgs[@]}")))
        fi
    fi

    # split binary and AUR depends pkgs
    unset depspkgsaur
    if [[ -n "${depspkgs[@]}" ]]; then
        # remove all pkgs versioning
        if [[ $nodeps && $count -eq 1 ]]; then
            for i in "${!depspkgs[@]}"; do
                depspkgs[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${depspkgs[$i]})
            done
        # assume installed deps
        elif [[ -n "${assumeinstalled[@]}" ]]; then
            # remove versioning
            for i in "${!assumeinstalled[@]}"; do
                unset assumedepspkgs
                assumeinstalled[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${assumeinstalled[$i]})
                for j in "${!depspkgs[@]}"; do
                    assumedepspkgs[$j]=$(awk -F ">|<|=" '{print $1}' <<< ${depspkgs[$j]})
                    [[ " ${assumedepspkgs[@]} " =~ " ${assumeinstalled[$i]} " ]] && depspkgs[$j]=${assumeinstalled[$i]};
                done
            done
            depspkgs=($(grep -xvf <(printf '%s\n' "${assumeinstalled[@]}") <(printf '%s\n' "${depspkgs[@]}")))
        fi
        if [[ -n "${depspkgs[@]}" ]]; then
            depspkgsaur=($(LANG=C $pacmanbin -Sp ${depspkgs[@]} 2>&1 >/dev/null | awk '{print $NF}'))
            repodeps+=($(grep -xvf <(printf '%s\n' "${depspkgsaur[@]}") <(printf '%s\n' "${depspkgs[@]}")))
        fi
    fi
    unset depspkgs

    # remove duplicate
    if [[ -n "${depspkgsaur[@]}" ]]; then
        depspkgsaur=($(grep -xvf <(printf '%s\n' "${aurdepspkgs[@]}") <(printf '%s\n' "${depspkgsaur[@]}")))
    fi

    # dependency cycle check
    [[ -n "${prevdepspkgsaur[@]}" ]] && [[ "${prevdepspkgsaur[*]}" == "${depspkgsaur[*]}" ]] && Note "e" $"dependency cycle detected (${depspkgsaur[*]})"

    if [[ -n "${depspkgsaur[@]}" ]]; then
        # store for AUR version check
        [[ ! $nodeps ]] && prevdepspkgsaur=(${depspkgsaur[@]})

        # remove AUR pkgs versioning
        for i in "${!depspkgsaur[@]}"; do
            depspkgsaur[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${depspkgsaur[$i]})
        done

        # remove duplicate
        depspkgsaur=($(tr ' ' '\n' <<< ${depspkgsaur[@]} | sort -u))
    fi

    if [[ -n "${depspkgsaur[@]}" ]]; then
        aurdepspkgs+=(${depspkgsaur[@]})
        FindDepsAur ${depspkgsaur[@]}
    fi
}

SortDepsAur() {
    local i j sortaurpkgs sortdepspkgs sortdepspkgsaur
    # global checkedsortdepspkgsaur allcheckedsortdepspkgsaur json errdepsnover
    [[ -z "${checkedsortdepspkgsaur[@]}" ]] && sortaurpkgs=(${aurpkgs[@]}) || sortaurpkgs=(${checkedsortdepspkgsaur[@]})

    unset checkedsortdepspkgsaur
    for i in "${!sortaurpkgs[@]}"; do
        unset sortdepspkgs sortdepspkgsaur

        sortdepspkgs+=($(GetJson "arrayvar" "$json" "Depends" "${sortaurpkgs[$i]}"))
        sortdepspkgs+=($(GetJson "arrayvar" "$json" "MakeDepends" "${sortaurpkgs[$i]}"))
        sortdepspkgs+=($(GetJson "arrayvar" "$json" "CheckDepends" "${sortaurpkgs[$i]}"))

        # remove versioning
        for j in "${!errdeps[@]}"; do
            errdepsnover[$j]=$(awk -F ">|<|=" '{print $1}' <<< ${errdeps[$j]})
        done

        # check AUR deps only
        for j in "${!sortdepspkgs[@]}"; do
            sortdepspkgs[$j]=$(awk -F ">|<|=" '{print $1}' <<< ${sortdepspkgs[$j]})
            sortdepspkgsaur+=($(GetJson "varvar" "$json" "Name" "${sortdepspkgs[$j]}"))
            # add erroneous AUR deps
            [[ " ${errdepsnover[@]} " =~ " ${sortdepspkgs[$j]} " ]] && sortdepspkgsaur+=("${sortdepspkgs[$j]}")
        done

        # prepare tsort list
        if [[ -z "${sortdepspkgsaur[@]}" ]]; then
            tsortdeps+=("${sortaurpkgs[$i]} ${sortaurpkgs[$i]}")
        else
            for j in "${!sortdepspkgsaur[@]}"; do
                tsortdeps+=("${sortaurpkgs[$i]} ${sortdepspkgsaur[$j]}")
            done
        fi

        # filter non checked deps
        sortdepspkgsaur=($(grep -xvf <(printf '%s\n' "${allcheckedsortdepspkgsaur[@]}") <(printf '%s\n' "${sortdepspkgsaur[@]}")))
        if [[ -n "${sortdepspkgsaur[@]}" ]]; then
            checkedsortdepspkgsaur+=(${sortdepspkgsaur[@]})
            allcheckedsortdepspkgsaur+=(${sortdepspkgsaur[@]})
            allcheckedsortdepspkgsaur=($(tr ' ' '\n' <<< ${allcheckedsortdepspkgsaur[@]} | sort -u))
        fi
    done
    if [[ -n "${checkedsortdepspkgsaur[@]}" ]]; then
        checkedsortdepspkgsaur=($(tr ' ' '\n' <<< ${checkedsortdepspkgsaur[@]} | sort -u))
        SortDepsAur ${checkedsortdepspkgsaur[@]}
    fi
}

FindDepsAurError() {
    local i nexterrdep nextallerrdeps
    # global errdepsnover errdepslist tsorterrdeps currenterrdep

    for i in "${tsorterrdeps[@]}"; do
        [[ ! " ${errdepsnover[@]} " =~ " $i " ]] && [[ ! " ${errdepslist[@]} " =~ " $i " ]] && nexterrdep="$i" && break
    done

    [[ -z "${currenterrdep[@]}" ]] && currenterrdep=${tsorterrdeps[0]}

    if [[ ! " ${aurpkgs[@]} " =~ " $nexterrdep " ]]; then
        nextallerrdeps=($(GetJson "arrayvar" "$json" "Depends" "$nexterrdep"))
        nextallerrdeps+=($(GetJson "arrayvar" "$json" "MakeDepends" "$nexterrdep"))
        nextallerrdeps+=($(GetJson "arrayvar" "$json" "CheckDepends" "$nexterrdep"))

        # remove versioning
        for i in "${!nextallerrdeps[@]}"; do
            nextallerrdeps[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${nextallerrdeps[$i]})
        done

        if [[ " ${nextallerrdeps[@]} " =~ " $currenterrdep " ]]; then
            errdepslist+=("$nexterrdep")
            currenterrdep=${tsorterrdeps[0]}
        fi
        tsorterrdeps=(${tsorterrdeps[@]:1})
        FindDepsAurError ${tsorterrdeps[@]}
    else
        for i in "${!aurpkgs[@]}"; do
            nextallerrdeps=($(GetJson "arrayvar" "$json" "Depends" "${aurpkgs[$i]}"))
            nextallerrdeps+=($(GetJson "arrayvar" "$json" "MakeDepends" "${aurpkgs[$i]}"))
            nextallerrdeps+=($(GetJson "arrayvar" "$json" "CheckDepends" "${aurpkgs[$i]}"))

            # remove versioning
            for j in "${!nextallerrdeps[@]}"; do
                nextallerrdeps[$j]=$(awk -F ">|<|=" '{print $1}' <<< ${nextallerrdeps[$j]})
            done

            if [[ " ${nextallerrdeps[@]} " =~ " $currenterrdep " ]]; then
                errdepslist+=("${aurpkgs[$i]}")
            fi
        done
    fi
}

FindDepsRepo() {
    local allrepopkgs providersrepopkgs providersrepopkgsrm i j
    # global repodeps
    [[ -z "${repodeps[@]}" ]] && return

    # reduce root binary deps
    repodeps=($(tr ' ' '\n' <<< ${repodeps[@]} | sort -u))

    for i in "${repodeps[@]}"; do
        allrepopkgs+=($(pactree -su "$i"))
        providersrepopkgs+=($(pactree -s "$i" | grep " provides " | awk '{print $NF}' | sort -u))
    done
    providersrepopkgs=($(tr ' ' '\n' <<< ${providersrepopkgs[@]} | sort -u))

    # remove pactree deps of default providers if non default provider is already installed
    if [[ -n "${providersrepopkgs[@]}" ]]; then
        for i in "${providersrepopkgs[@]}"; do
            j=$(expac -Qs '%n %P' "^$i$" | head -1 | grep -E "([^a-zA-Z0-9_@\.\+-]$i|^$i)" | grep -E "($i[^a-zA-Z0-9\.\+-]|$i$)" | awk '{print $1}')
            [[ -n "$j" ]] && [[ "$j" != "$(expac -Ss '%n' "^$i$" | tr '\n' ' ' | awk '{print $1}')" ]] && providersrepopkgsrm+=($(pactree -su "$i"))
        done
        if [[ -n "${providersrepopkgsrm[@]}" ]]; then
            providersrepopkgsrm=($($pacmanbin -T ${providersrepopkgsrm[@]} | sort -u))
            allrepopkgs=($(grep -xvf <(printf '%s\n' "${providersrepopkgsrm[@]}") <(printf '%s\n' "${allrepopkgs[@]}")))
        fi
    fi

    repodepspkgs=($($pacmanbin -T ${allrepopkgs[@]} | sort -u))
}

IgnoreDepsChecks() {
    local i
    # global ignoredpkgs aurpkgs aurdepspkgs aurdepspkgsAgrp aurdepspkgsQgrp repodepspkgsSgrp repodepspkgsQgrp rmaurpkgs deps repodepspkgs
    [[ -z "${ignoredpkgs[@]}" && -z "${ignoredgrps[@]}" ]] && return

    # add checked targets
    deps=(${aurpkgs[@]})

    # check dependencies
    for i in "${repodepspkgs[@]}"; do
        unset isignored
        if [[ " ${ignoredpkgs[@]} " =~ " $i " ]]; then
            isignored=true
        elif [[ -n "${ignoredgrps[@]}" ]]; then
            unset repodepspkgsSgrp repodepspkgsQgrp
            repodepspkgsSgrp=($(expac -S '%G' "$i"))
            for j in "${repodepspkgsSgrp[@]}"; do
                [[ " ${ignoredgrps[@]} " =~ " $j " ]] && isignored=true
            done
            repodepspkgsQgrp=($(expac -Q '%G' "$i"))
            for j in "${repodepspkgsQgrp[@]}"; do
                [[ " ${ignoredgrps[@]} " =~ " $j " ]] && isignored=true
            done
        fi

        if [[ $isignored = true ]]; then
            if [[ ! $upgrade ]]; then
                Note "w" $"skipping target: ${colorW}$i${reset}"
            else
                Note "w" $"${colorW}$i${reset}: ignoring package upgrade"
            fi
            Note "e" $"Unresolved dependency '${colorW}$i${reset}'"
        fi
    done
    for i in "${aurdepspkgs[@]}"; do
        # skip already checked dependencies
        [[ " ${aurpkgs[@]} " =~ " $i " ]] && continue
        [[ " ${rmaurpkgs[@]} " =~ " $i " ]] && Note "e" $"Unresolved dependency '${colorW}$i${reset}'"

        unset isignored
        if [[ " ${ignoredpkgs[@]} " =~ " $i " ]]; then
            isignored=true
        elif [[ -n "${ignoredgrps[@]}" ]]; then
            unset aurdepspkgsAgrp aurdepspkgsQgrp
            aurdepspkgsAgrp=($(GetJson "arrayvar" "$json" "Groups" "$i"))
            for j in "${aurdepspkgsAgrp[@]}"; do
                [[ " ${ignoredgrps[@]} " =~ " $j " ]] && isignored=true
            done
            aurdepspkgsQgrp=($(expac -Q '%G' "$i"))
            for j in "${aurdepspkgsQgrp[@]}"; do
                [[ " ${ignoredgrps[@]} " =~ " $j " ]] && isignored=true
            done
        fi

        if [[ $isignored = true ]]; then
            if [[ ! $noconfirm ]]; then
                if ! Proceed "y" $"$i dependency is in IgnorePkg/IgnoreGroup. Install anyway?"; then
                    Note "w" $"skipping target: ${colorW}$i${reset}"
                    Note "e" $"Unresolved dependency '${colorW}$i${reset}'"
                fi
            else
                if [[ ! $upgrade ]]; then
                    Note "w" $"skipping target: ${colorW}$i${reset}"
                else
                    Note "w" $"${colorW}$i${reset}: ignoring package upgrade"
                fi
                Note "e" $"Unresolved dependency '${colorW}$i${reset}'"
            fi
        fi
        deps+=($i)
    done
}

ProviderChecks() {
    local allproviders providersdeps providers repodepspkgsprovided providerspkgs provided nb providersnb rmproviderpkgs providerpkgsrm
    # global repodepspkgs repoprovidersconflictingpkgs repodepsSver repodepsSrepo repodepsQver
    [[ -z "${repodepspkgs[@]}" ]] && return

    allproviders=($(expac -S '%S' "${repodepspkgs[@]}" | sort -u))
    # remove installed providers
    providersdeps=($($pacmanbin -T ${allproviders[@]} | sort -u))

    for i in "${!providersdeps[@]}"; do
        providers=($(expac -Ss '%n' "^${providersdeps[$i]}$" | sort -u))
        [[ ! ${#providers[@]} -gt 1 ]] && continue

        # skip if provided in dependency chain
        unset repodepspkgsprovided
        for j in "${!providers[@]}"; do
            [[ " ${repodepspkgs[@]} " =~ " ${providers[$j]} " ]] && repodepspkgsprovided='true'
        done
        [[ $repodepspkgsprovided ]] && continue

        # skip if already provided
        if [[ -n "${providerspkgs[@]}" ]]; then
            providerspkgs=($(tr ' ' '|' <<< ${providerspkgs[@]}))
            provided+=($(expac -Ss '%S' "^(${providerspkgs[*]})$"))
            [[ " ${provided[@]} " =~ " ${providersdeps[$i]} " ]] && continue
        fi

        if [[ ! $noconfirm ]]; then
            Note "i" $"${colorW}There are ${#providers[@]} providers available for ${providersdeps[$i]}:${reset}"
            expac -S -1 '   %!) %n (%r) ' "${providers[@]}"

            local nb=-1
            providersnb=$(( ${#providers[@]} -1 )) # count from 0
            while [[ $nb -lt 0 || $nb -ge ${#providers} ]]; do

                printf "\n%s " $"Enter a number (default=0):"
                case "$TERM" in
                    dumb)
                    read -r nb
                    ;;
                    *)
                    read -r -n "$(echo -n $providersnb | wc -m)" nb
                    echo
                    ;;
                esac

                case $nb in
                    [0-9]|[0-9][0-9])
                        if [[ $nb -lt 0 || $nb -ge ${#providers[@]} ]]; then
                            echo && Note "f" $"invalid value: $nb is not between 0 and $providersnb" && ((i--))
                        else
                            break
                        fi;;
                    '') nb=0;;
                    *) Note "f" $"invalid number: $nb";;
                esac
            done
        else
            local nb=0
        fi
        providerspkgs+=(${providers[$nb]})
        [[ $nb -ne 0 ]] && rmproviderpkgs+=(${providersdeps[$i]})
    done

    repoprovidersconflictingpkgs+=(${providerspkgs[@]})

    # pactree always return default choice so update binary deps list
    if [[ -n "${rmproviderpkgs[@]}" ]]; then
        # remove deps of default providers
        for i in "${rmproviderpkgs[@]}"; do
            providerpkgsrm+=($(pactree -su "$i"))
        done
        providerpkgsrm=($($pacmanbin -T ${providerpkgsrm[@]} | sort -u))
        repodepspkgs=($(grep -xvf <(printf '%s\n' "${providerpkgsrm[@]}") <(printf '%s\n' "${repodepspkgs[@]}")))

        # add deps of selected providers instead
        providerspkgs=($(tr '|' ' ' <<< ${providerspkgs[@]}))
        for i in "${providerspkgs[@]}"; do
            providerdeps+=($(pactree -su "$i"))
        done
        repodepspkgs+=($($pacmanbin -T ${providerdeps[@]} | sort -u))
    fi

    # get binary packages info
    if [[ -n "${repodepspkgs[@]}" ]]; then
        repodepspkgs=($(expac -S -1 '%n' "${repodepspkgs[@]}" | LC_COLLATE=C sort -u))
        repodepsSver=($(expac -S -1 '%v' "${repodepspkgs[@]}"))
        repodepsQver=($(expac -Q '%v' "${repodepspkgs[@]}"))
        repodepsSrepo=($(expac -S -1 '%r/%n' "${repodepspkgs[@]}"))
    fi
}

ConflictChecks() {
    local allQprovides allQconflicts Aprovides Aconflicts aurconflicts aurAconflicts Qrequires i j k
    local repodepsprovides repodepsconflicts checkedrepodepsconflicts repodepsconflictsname repodepsconflictsver localver repoconflictingpkgs
    # global deps depsAname json aurdepspkgs aurconflictingpkgs aurconflictingpkgsrm depsQver repodepspkgs repoconflictingpkgsrm repoprovidersconflictingpkgs
    Note "i" $"looking for inter-conflicts..."

    allQprovides=($(expac -Q '%n'))
    allQprovides+=($(expac -Q '%S')) # no versioning
    allQconflicts=($(expac -Q '%C'))

    # AUR conflicts
    Aprovides=(${depsAname[@]})
    Aprovides+=($(GetJson "array" "$json" "Provides"))
    Aconflicts=($(GetJson "array" "$json" "Conflicts"))
    # remove AUR versioning
    for i in "${!Aprovides[@]}"; do
        Aprovides[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${Aprovides[$i]})
    done
    for i in "${!Aconflicts[@]}"; do
        Aconflicts[$i]=$(awk -F ">|<|=" '{print $1}' <<< ${Aconflicts[$i]})
    done
    aurconflicts=($(grep -xf <(printf '%s\n' "${Aprovides[@]}") <(printf '%s\n' "${allQconflicts[@]}")))
    aurconflicts+=($(grep -xf <(printf '%s\n' "${Aconflicts[@]}") <(printf '%s\n' "${allQprovides[@]}")))
    aurconflicts=($(tr ' ' '\n' <<< ${aurconflicts[@]} | LC_COLLATE=C sort -u))

    for i in "${aurconflicts[@]}"; do
        unset aurAconflicts
        [[ " ${depsAname[@]} " =~ " $i " ]] && aurAconflicts=($i)
        for j in "${depsAname[@]}"; do
            [[ " $(GetJson "arrayvar" "$json" "Conflicts" "$j") " =~ " $i " ]] && aurAconflicts+=($j)
        done

        for j in "${aurAconflicts[@]}"; do
            unset k Aprovides
            k=$(expac -Qs '%n %P' "^$i$" | head -1 | grep -E "([^a-zA-Z0-9_@\.\+-]$i|^$i)" | grep -E "($i[^a-zA-Z0-9\.\+-]|$i$)" | awk '{print $1}')
            [[ ! $installpkg && ! " ${aurdepspkgs[@]} " =~ " $j " ]] && continue # skip if downloading target only
            [[ "$j" == "$k" || -z "$k" ]] && continue # skip if reinstalling or if no conflict exists

            Aprovides=($j)
            if [[ ! $noconfirm && ! " ${aurconflictingpkgs[@]} " =~ " $k " ]]; then
                if ! Proceed "n" $"$j and $k are in conflict ($i). Remove $k?"; then
                    aurconflictingpkgs+=($j $k)
                    aurconflictingpkgsrm+=($k)
                    for l in "${!depsAname[@]}"; do
                        [[ " ${depsAname[$l]} " =~ "$k" ]] && depsQver[$l]=$(expac -Qs '%v' "^$k$" | head -1)
                    done
                    Aprovides+=($(GetJson "arrayvar" "$json" "Provides" "$j"))
                    # remove AUR versioning
                    for l in "${!Aprovides[@]}"; do
                        Aprovides[$l]=$(awk -F ">|<|=" '{print $1}' <<< ${Aprovides[$l]})
                    done
                    [[ ! " ${Aprovides[@]} " =~ " $k " && ! " ${aurconflictingpkgsrm[@]} " =~ " $k " ]] && CheckRequires $k
                    break
                else
                    Note "f" $"unresolvable package conflicts detected"
                    Note "f" $"failed to prepare transaction (conflicting dependencies)"
                    if [[ $upgrade ]]; then
                        Qrequires=($(expac -Q '%N' "$i"))
                        Note "e" $"$j and $k are in conflict (required by ${Qrequires[*]})"
                    else
                        Note "e" $"$j and $k are in conflict"
                    fi
                fi
            fi
            Aprovides+=($(GetJson "arrayvar" "$json" "Provides" "$j"))
            # remove AUR versioning
            for l in "${!Aprovides[@]}"; do
                Aprovides[$l]=$(awk -F ">|<|=" '{print $1}' <<< ${Aprovides[$l]})
            done
            [[ ! " ${Aprovides[@]} " =~ " $k " && ! " ${aurconflictingpkgsrm[@]} " =~ " $k " ]] && CheckRequires $k
        done
    done

    NothingToDo ${deps[@]}

    # repo conflicts
    if [[ -n "${repodepspkgs[@]}" ]]; then
        repodepsprovides=(${repodepspkgs[@]})
        repodepsprovides+=($(expac -S '%S' "${repodepspkgs[@]}")) # no versioning
        repodepsconflicts=($(expac -S '%H' "${repodepspkgs[@]}"))

        # versioning check
        unset checkedrepodepsconflicts
        for i in "${!repodepsconflicts[@]}"; do
            unset repodepsconflictsname repodepsconflictsver localver
            repodepsconflictsname=${repodepsconflicts[$i]} && repodepsconflictsname=${repodepsconflictsname%[><]*} && repodepsconflictsname=${repodepsconflictsname%=*}
            repodepsconflictsver=${repodepsconflicts[$i]} && repodepsconflictsver=${repodepsconflictsver#*=} && repodepsconflictsver=${repodepsconflictsver#*[><]}
            [[ $repodepsconflictsname ]] && localver=$(expac -Q '%v' $repodepsconflictsname)

            if [[ $localver ]]; then
                case "${repodepsconflicts[$i]}" in
                        *">="*) [[ $(vercmp "$repodepsconflictsver" "$localver") -ge 0 ]] && continue;;
                        *"<="*) [[ $(vercmp "$repodepsconflictsver" "$localver") -le 0 ]] && continue;;
                        *">"*)  [[ $(vercmp "$repodepsconflictsver" "$localver") -gt 0 ]] && continue;;
                        *"<"*)  [[ $(vercmp "$repodepsconflictsver" "$localver") -lt 0 ]] && continue;;
                        *"="*)  [[ $(vercmp "$repodepsconflictsver" "$localver") -eq 0 ]] && continue;;
                esac
                checkedrepodepsconflicts+=($repodepsconflictsname)
            fi
        done

        repoconflicts+=($(grep -xf <(printf '%s\n' "${repodepsprovides[@]}") <(printf '%s\n' "${allQconflicts[@]}")))
        repoconflicts+=($(grep -xf <(printf '%s\n' "${checkedrepodepsconflicts[@]}") <(printf '%s\n' "${allQprovides[@]}")))
        repoconflicts=($(tr ' ' '\n' <<< ${repoconflicts[@]} | LC_COLLATE=C sort -u))
    fi

    for i in "${repoconflicts[@]}"; do
        unset Qprovides
        repoSconflicts=($(expac -S '%n %C %S' "${repodepspkgs[@]}" | grep -E "[^a-zA-Z0-9_@\.\+-]$i" | grep -E "($i[^a-zA-Z0-9\.\+-]|$i$)" | awk '{print $1}'))
        for j in "${repoSconflicts[@]}"; do
            unset k && k=$(expac -Qs '%n %P' "^$i$" | head -1 | grep -E "([^a-zA-Z0-9_@\.\+-]$i|^$i)" | grep -E "($i[^a-zA-Z0-9\.\+-]|$i$)" | awk '{print $1}')
            [[ "$j" == "$k" || -z "$k" ]] && continue # skip when no conflict with repopkgs

            if [[ ! $noconfirm && ! " ${repoconflictingpkgs[@]} " =~ " $k " ]]; then
                if ! Proceed "n" $"$j and $k are in conflict ($i). Remove $k?"; then
                    repoconflictingpkgs+=($j $k)
                    repoconflictingpkgsrm+=($k)
                    repoprovidersconflictingpkgs+=($j)
                    Qprovides=($(expac -Ss '%S' "^$k$"))
                    [[ ! " ${Qprovides[@]} " =~ " $k " && ! " ${repoconflictingpkgsrm[@]} " =~ " $k " ]] && CheckRequires $k
                    break
                else
                    Note "f" $"unresolvable package conflicts detected"
                    Note "f" $"failed to prepare transaction (conflicting dependencies)"
                    if [[ $upgrade ]]; then
                        Qrequires=($(expac -Q '%N' "$i"))
                        Note "e" $"$j and $k are in conflict (required by ${Qrequires[*]})"
                    else
                        Note "e" $"$j and $k are in conflict"
                    fi
                fi
            fi
            Qprovides=($(expac -Ss '%S' "^$k$"))
            [[ ! " ${Qprovides[@]} " =~ " $k " ]] && CheckRequires $k
        done
    done
}

ReinstallChecks() {
    local i depsAtmp
    # global aurpkgs aurdepspkgs deps aurconflictingpkgs depsAname depsQver depsAver depsAood depsAmain
    depsAtmp=(${depsAname[@]})
    for i in "${!depsAtmp[@]}"; do
        [[ ! $foreign ]] && [[ ! " ${aurpkgs[@]} " =~ " ${depsAname[$i]} " || " ${aurconflictingpkgs[@]} " =~ " ${depsAname[$i]} " ]] && continue
        [[ -z "${depsQver[$i]}" || "${depsQver[$i]}" = '#' || $(vercmp "${depsAver[$i]}" "${depsQver[$i]}") -gt 0 ]] && continue
        [[ ! $installpkg && ! " ${aurdepspkgs[@]} " =~ " ${depsAname[$i]} " ]] && continue
        if [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< ${depsAname[$i]})" ]]; then
            Note "w" $"${colorW}${depsAname[$i]}${reset} latest revision -- fetching"
        else
            if [[ ! $needed ]]; then
                Note "w" $"${colorW}${depsAname[$i]}-${depsQver[$i]}${reset} is up to date -- reinstalling"
            else
                Note "w" $"${colorW}${depsAname[$i]}-${depsQver[$i]}${reset} is up to date -- skipping"
                deps=($(tr ' ' '\n' <<< ${deps[@]} | sed "s/^${depsAname[$i]}$//g"))
                unset depsAname[$i] depsQver[$i] depsAver[$i] depsAood[$i] depsAmain[$i]
            fi
        fi
    done
    [[ $needed ]] && depsAname=(${depsAname[@]}) && depsQver=(${depsQver[@]}) && depsAver=(${depsAver[@]}) && depsAood=(${depsAood[@]}) && depsAmain=(${depsAmain[@]})

    NothingToDo ${deps[@]}
}

OutofdateChecks() {
    local i
    # global depsAname depsAver depsAood
    for i in "${!depsAname[@]}"; do
        [[ "${depsAood[$i]}" -gt 0 ]] && Note "w" $"${colorW}${depsAname[$i]}-${depsAver[$i]}${reset} has been flagged ${colorR}out of date${reset} on ${colorY}$(date -d "@${depsAood[$i]}" "+%c")${reset}"
    done
}

OrphanChecks() {
    local i
    # global depsAname depsAver depsAmain
    for i in "${!depsAname[@]}"; do
      [[ "${depsAmain[$i]}" == 'null' ]] && Note "w" $"${colorW}${depsAname[$i]}-${depsAver[$i]}${reset} is ${colorR}orphaned${reset} in AUR"
    done
}

Prompt() {
    local i binaryksize sumk summ builtpkg cachedpkgs strname stroldver strnewver strsize action
    local depsver repodepspkgsver strrepodlsize strrepoinsize strsumk strsumm lreposizelabel lreposize
    # global repodepspkgs repodepsSver depsAname depsAver depsArepo depsAcached lname lver lsize deps depsQver repodepspkgs repodepsSrepo repodepsQver repodepsSver
    # compute binary size
    if [[ -n "${repodepspkgs[@]}" ]]; then
        binaryksize=($(expac -S -1 '%k' "${repodepspkgs[@]}"))
        binarymsize=($(expac -S -1 '%m' "${repodepspkgs[@]}"))
        sumk=0
        summ=0
        for i in "${!repodepspkgs[@]}"; do
            GetBuiltPkg "${repodepspkgs[$i]}-${repodepsSver[$i]}" '/var/cache/pacman/pkg'
            [[ $builtpkg ]] && binaryksize[$i]=0
            sumk=$((sumk + ${binaryksize[$i]}))
            summ=$((summ + ${binarymsize[$i]}))
        done
        sumk=$(awk '{ printf("%.2f\n", $1/$2) }' <<< "$sumk 1048576")
        summ=$(awk '{ printf("%.2f\n", $1/$2) }' <<< "$summ 1048576")
    fi

    # cached packages check
    for i in "${!depsAname[@]}"; do
        [[ ! $PKGDEST || $rebuild ]] && break
        GetBuiltPkg "${depsAname[$i]}-${depsAver[$i]}" "$PKGDEST"
        [[ $builtpkg ]] && cachedpkgs+=(${depsAname[$i]}) && depsAcached[$i]=$"(cached)" || depsAcached[$i]=""
        unset builtpkg
    done

    if [[ -n "$(grep '^VerbosePkgLists' '/etc/pacman.conf')" ]]; then
        straurname=$"AUR Packages  (${#deps[@]})"; strreponame=$"Repo Packages (${#repodepspkgs[@]})"; stroldver=$"Old Version"; strnewver=$"New Version"; strsize=$"Download Size"
        depsArepo=(${depsAname[@]/#/aur/})
        lname=$(GetLength ${depsArepo[@]} ${repodepsSrepo[@]} "$straurname" "$strreponame")
        lver=$(GetLength ${depsQver[@]} ${depsAver[@]} ${repodepsQver[@]} ${repodepsSver[@]} "$stroldver" "$strnewver")
        lsize=$(GetLength "$strsize")

        # local version column cleanup
        for i in "${!deps[@]}"; do
            [[ "${depsQver[$i]}" =~ '#' ]] && unset depsQver[$i]
        done
        # show detailed output
        printf "\n${colorW}%-${lname}s  %-${lver}s  %-${lver}s${reset}\n\n" "$straurname" "$stroldver" "$strnewver"
        for i in "${!deps[@]}"; do
            printf "%-${lname}s  ${colorR}%-${lver}s${reset}  ${colorG}%-${lver}s${reset}  %${lsize}s\n" "${depsArepo[$i]}" "${depsQver[$i]}" "${depsAver[$i]}" "${depsAcached[$i]}";
        done

        if [[ -n "${repodepspkgs[@]}" ]]; then
            for i in "${!repodepspkgs[@]}"; do
                binarysize[$i]=$(awk '{ printf("%.2f\n", $1/$2) }' <<< "${binaryksize[$i]} 1048576")
            done
            printf "\n${colorW}%-${lname}s  %-${lver}s  %-${lver}s  %s${reset}\n\n" "$strreponame" "$stroldver" "$strnewver" "$strsize"
            for i in "${!repodepspkgs[@]}"; do
                printf "%-${lname}s  ${colorR}%-${lver}s${reset}  ${colorG}%-${lver}s${reset}  %${lsize}s\n" "${repodepsSrepo[$i]}" "${repodepsQver[$i]}" "${repodepsSver[$i]}" $"${binarysize[$i]} MiB";
            done
        fi
    else
        # show version
        for i in "${!deps[@]}"; do
            depsver="${depsver}${depsAname[$i]}-${depsAver[$i]}  "
        done
        for i in "${!repodepspkgs[@]}"; do
            repodepspkgsver="${repodepspkgsver}${repodepspkgs[$i]}-${repodepsSver[$i]}  "
        done
        printf "\n${colorW}%-16s${reset} %s\n" $"AUR Packages  (${#deps[@]})" "$depsver"
        [[ -n "${repodepspkgs[@]}" ]] && printf "${colorW}%-16s${reset} %s\n" $"Repo Packages (${#repodepspkgs[@]})" "$repodepspkgsver"
    fi

    if [[ -n "${repodepspkgs[@]}" ]]; then
        strrepodlsize=$"Repo Download Size:"; strrepoinsize=$"Repo Installed Size:"; strsumk=$"$sumk MiB"; strsumm=$"$summ MiB"
        lreposizelabel=$(GetLength "$strrepodlsize" "$strrepoinsize")
        lreposize=$(GetLength "$strsumk" "$strsumm")
        printf "\n${colorW}%-${lreposizelabel}s${reset}  %${lreposize}s\n" "$strrepodlsize" "$strsumk"
        printf "${colorW}%-${lreposizelabel}s${reset}  %${lreposize}s\n" "$strrepoinsize" "$strsumm"
    fi

    echo
    [[ $installpkg ]] && action=$"installation" || action=$"download"
    if ! Proceed "y" $"Proceed with $action?"; then
        exit
    fi
}

DownloadPkgs() {
    local i
    # global basepkgs
    Note "i" $"${colorW}Retrieving package(s)...${reset}"
    GetPkgbase $@

    # clone
    for i in ${basepkgs[@]}; do
        cd "$clonedir" || exit 1
        if [[ ! -d "$i" ]]; then
            git clone --depth=1 https://aur.archlinux.org/$i.git
        else
            cd "$clonedir/$i" || exit 1
            git reset --hard HEAD -q # updated pkgver of vcs packages prevent pull
            [[ "$displaybuildfiles" = diff ]] && git rev-parse HEAD > ".git/HEAD.prev"
            git pull --ff -q
        fi
    done

    # no results check
    [[ -z "${basepkgs[@]}" ]] && Note "e" $"no results found"
}

EditPkgs() {
    local viewed timestamp i j erreditpkg
    # global cachedpkgs installscripts editor
    [[ $noedit ]] && return
    unset viewed
    for i in "$@"; do
        [[ " ${cachedpkgs[@]} " =~ " $i " ]] && continue
        cd "$clonedir/$i" || exit 1
        unset timestamp
        GetInstallScripts $i
        if [[ ! $edit ]]; then
            if [[ ! $displaybuildfiles = none ]]; then
                if [[ $displaybuildfiles = diff && -e ".git/HEAD.prev" ]]; then
                    # show diff
                    diffcmd="git diff $(cut -f1 .git/HEAD.prev) -- . ':!\.SRCINFO'"
                    if [[ -n "$(eval "$diffcmd")" ]]; then
                        if Proceed "y" $"View $i build files diff?"; then
                            eval "$diffcmd"
                            Note "s" $"${colorW}$i${reset} build files diff viewed"
                            viewed='true'
                            (($? > 0)) && erreditpkg+=($i)
                        fi
                    else
                        Note "w" $"${colorW}$i${reset} build files are up-to-date -- skipping"
                    fi
                else
                    # show pkgbuild
                    if Proceed "y" $"View $i PKGBUILD?"; then
                        if [[ -e "PKGBUILD" ]]; then
                            $editor "PKGBUILD" && Note "s" $"${colorW}$i${reset} PKGBUILD viewed"
                            (($? > 0)) && erreditpkg+=($i)
                        else
                            Note "e" $"Could not open ${colorW}$i${reset} PKGBUILD"
                        fi
                    fi
                    # show install script
                    if [[ -n "${installscripts[@]}" ]]; then
                        for j in "${installscripts[@]}"; do
                            if Proceed "y" $"View $j script?"; then
                                if [[ -e "$j" ]]; then
                                    $editor "$j" && Note "s" $"${colorW}$j${reset} script viewed"
                                    (($? > 0)) && erreditpkg+=($i)
                                else
                                    Note "e" $"Could not open ${colorW}$j${reset} script"
                                fi
                            fi
                        done
                    fi
                fi
            fi
        else
            # show pkgbuild and install script
            if [[ -e "PKGBUILD" ]]; then
                $editor "PKGBUILD" && Note "s" $"${colorW}$i${reset} PKGBUILD viewed"
                (($? > 0)) && erreditpkg+=($i)
            else
                Note "e" $"Could not open ${colorW}$i${reset} PKGBUILD"
            fi
            if [[ -n "${installscripts[@]}" ]]; then
                for j in "${installscripts[@]}"; do
                    if [[ -e "$j" ]]; then
                        $editor "$j" && Note "s" $"${colorW}$j${reset} script viewed"
                        (($? > 0)) && erreditpkg+=($i)
                    else
                        Note "e" $"Could not open ${colorW}$j${reset} script"
                    fi
                done
            fi
        fi
    done

    if [[ -n "${erreditpkg[@]}" ]]; then
        for i in "${erreditpkg[@]}"; do
            Note "f" $"${colorW}$i${reset} errored on exit"
        done
        exit 1
    fi

    if [[ $displaybuildfiles = diff && $viewed = true ]]; then
        [[ $installpkg ]] && action=$"installation" || action=$"download"
        if ! Proceed "y" $"Proceed with $action?"; then
            exit
        fi
    fi
}

MakePkgs() {
    local oldorphanpkgs neworphanpkgs orphanpkgs oldoptionalpkgs newoptionalpkgs optionalpkgs errinstall
    local pkgsdepslist vcsclients vcschecked aurdevelpkgsAver aurdevelpkgsQver basepkgsupdate checkpkgsdepslist isaurdeps builtpkgs builtdepspkgs i j
    # global deps basepkgs sudoloop pkgsbase pkgsdeps aurpkgs aurdepspkgs depsAver builtpkg errmakepkg repoprovidersconflictingpkgs aurprovidersconflictingpkgs json

    # download
    DownloadPkgs ${deps[@]}
    EditPkgs ${basepkgs[@]}

    # current orphan and optional packages
    oldorphanpkgs=($($pacmanbin -Qdtq))
    oldoptionalpkgs=($($pacmanbin -Qdttq))
    oldoptionalpkgs=($(grep -xvf <(printf '%s\n' "${oldorphanpkgs[@]}") <(printf '%s\n' "${oldoptionalpkgs[@]}")))

    # initialize sudo
    if sudo $pacmanbin -V > /dev/null; then
        [[ $sudoloop = true ]] && SudoV &
    fi

    # split packages support
    for i in "${!pkgsbase[@]}"; do
        for j in "${!deps[@]}"; do
            [[ "${pkgsbase[$i]}" = "${pkgsbase[$j]}" ]] && [[ ! " ${pkgsdeps[@]} " =~ " ${deps[$j]} " ]] && pkgsdeps+=(${deps[$j]})
        done
        pkgsdeps+=("#")
    done
    pkgsdeps=($(sed 's/ # /\n/g' <<< ${pkgsdeps[@]} | tr -d '#' | sed '/^ $/d' | tr ' ' ',' | sed 's/^,//g;s/,$//g'))

    # reverse deps order
    basepkgs=($(awk '{for (i=NF;i>=1;i--) print $i}' <<< ${basepkgs[@]} | awk -F "\n" '{print}'))
    pkgsdeps=($(awk '{for (i=NF;i>=1;i--) print $i}' <<< ${pkgsdeps[@]} | awk -F "\n" '{print}'))

    # integrity check
    for i in "${!basepkgs[@]}"; do
        # get splitted packages list
        pkgsdepslist=($(awk -F "," '{for (k=1;k<=NF;k++) print $k}' <<< ${pkgsdeps[$i]}))

        # cache check
        unset builtpkg
        if [[ -z "$(grep -E "\-(bzr|git|hg|svn|nightly.*)$" <<< ${basepkgs[$i]})" ]]; then
            for j in "${pkgsdepslist[@]}"; do
                depsAver="$(GetJson "varvar" "$json" "Version" "$j")"
                [[ $PKGDEST && ! $rebuild ]] && GetBuiltPkg "$j-$depsAver" "$PKGDEST"
            done
        fi

        # install vcs clients (checking pkgbase extension only does not take fetching specific commit into account)
        unset vcsclients
        vcsclients=($(grep -E "makedepends = (bzr|git|mercurial|subversion)$" "$clonedir/${basepkgs[$i]}/.SRCINFO" | awk -F " " '{print $NF}'))
        for j in "${vcsclients[@]}"; do
            if [[ ! "${vcschecked[@]}" =~ "$j" ]]; then
                [[ -z "$(expac -Qs '%n' "^$j$")" ]] && sudo $pacmanbin -S $j --asdeps --noconfirm
                vcschecked+=($j)
            fi
        done

        if [[ ! $builtpkg || $rebuild ]]; then
            cd "$clonedir/${basepkgs[$i]}" || exit 1
            Note "i" $"Checking ${colorW}${pkgsdeps[$i]}${reset} integrity..."
            if [[ $silent = true ]]; then
                makepkg -f --verifysource ${makeopts[@]} &>/dev/null
            else
                makepkg -f --verifysource ${makeopts[@]}
            fi
            (($? > 0)) && errmakepkg+=(${pkgsdeps[$i]})
            # silent extraction and pkgver update only
            makepkg -odC --skipinteg ${makeopts[@]} &>/dev/null
        fi
    done
    if [[ -n "${errmakepkg[@]}" ]]; then
        for i in "${errmakepkg[@]}"; do
            Note "f" $"failed to verify ${colorW}$i${reset} integrity"
        done
        # remove sudo lock
        [[ -e "$tmpdir/pacaur.sudov.lck" ]] && rm "$tmpdir/pacaur.sudov.lck"
        exit 1
    fi

    # set build lock
    [[ -e "$tmpdir/pacaur.build.lck" ]] && Note "e" $"pacaur.build.lck exists in $tmpdir" && exit 1
    touch "$tmpdir/pacaur.build.lck"

    # install provider packages and repo conflicting packages that makepkg --noconfirm cannot handle
    if [[ -n "${repoprovidersconflictingpkgs[@]}" ]]; then
        Note "i" $"Installing ${colorW}${repoprovidersconflictingpkgs[@]}${reset} dependencies..."
        sudo $pacmanbin -S ${repoprovidersconflictingpkgs[@]} --ask 36 --asdeps --noconfirm
    fi

    # main
    for i in "${!basepkgs[@]}"; do

        # get splitted packages list
        pkgsdepslist=($(awk -F "," '{for (k=1;k<=NF;k++) print $k}' <<< ${pkgsdeps[$i]}))

        cd "$clonedir/${basepkgs[$i]}" || exit 1

        # build devel if necessary only (supported protocols only)
        unset aurdevelpkgsAver
        if [[ -n "$(grep -E "\-(bzr|git|hg|svn|nightly.*)$" <<< ${basepkgs[$i]})" ]]; then
            # retrieve updated version
            aurdevelpkgsAver=($(makepkg --packagelist | awk -F "-" '{print $(NF-2)"-"$(NF-1)}'))
            aurdevelpkgsAver=${aurdevelpkgsAver[0]}

            # check split packages update
            unset basepkgsupdate checkpkgsdepslist
            for j in "${pkgsdepslist[@]}"; do
                aurdevelpkgsQver=$(expac -Qs '%v' "^$j$" | head -1)
                if [[ -n $aurdevelpkgsQver && $(vercmp "$aurdevelpkgsQver" "$aurdevelpkgsAver") -ge 0 ]] && [[ $needed && ! $rebuild ]]; then
                    Note "w" $"${colorW}$j${reset} is up-to-date -- skipping"
                    continue
                else
                    basepkgsupdate='true'
                    checkpkgsdepslist+=($j)
                fi
            done
            if [[ $basepkgsupdate ]]; then
                pkgsdepslist=(${checkpkgsdepslist[@]})
            else
                continue
            fi
        fi

        # check package cache
        for j in "${pkgsdepslist[@]}"; do
            unset builtpkg
            [[ $aurdevelpkgsAver ]] && depsAver="$aurdevelpkgsAver" || depsAver="$(GetJson "varvar" "$json" "Version" "$j")"
            [[ $PKGDEST && ! $rebuild ]] && GetBuiltPkg "$j-$depsAver" "$PKGDEST"
            if [[ $builtpkg ]]; then
                if [[ " ${aurdepspkgs[@]} " =~ " $j " || $installpkg ]]; then
                    Note "i" $"Installing ${colorW}$j${reset} cached package..."
                    sudo $pacmanbin -Ud $builtpkg --ask 36 --noconfirm
                    [[ ! " ${aurpkgs[@]} " =~ " $j " ]] && sudo $pacmanbin -D $j --asdeps ${pacopts[@]} &>/dev/null
                else
                    Note "w" $"Package ${colorW}$j${reset} already available in cache"
                fi
                pkgsdeps=($(tr ' ' '\n' <<< ${pkgsdeps[@]} | sed "s/^$j,//g;s/,$j$//g;s/,$j,/,/g;s/^$j$/#/g"))
                continue
            fi
        done
        [[ "${pkgsdeps[$i]}" = '#' ]] && continue

        # build
        Note "i" $"Building ${colorW}${pkgsdeps[$i]}${reset} package(s)..."

        # install then remove binary deps
        makeopts=(${makeopts[@]/-r/})

        if [[ ! $installpkg ]]; then
            unset isaurdeps
            for j in "${pkgsdepslist[@]}"; do
                [[ " ${aurdepspkgs[@]} " =~ " $j " ]] && isaurdeps=true
            done
            [[ $isaurdeps != true ]] && makeopts+=("-r")
        fi

        if [[ $silent = true ]]; then
            makepkg -sefc ${makeopts[@]} --noconfirm &>/dev/null
        else
            makepkg -sefc ${makeopts[@]} --noconfirm
        fi

        # error check
        if (($? > 0)); then
            errmakepkg+=(${pkgsdeps[$i]})
            continue  # skip install
        fi

        # retrieve filename
        unset builtpkgs builtdepspkgs
        for j in "${pkgsdepslist[@]}"; do
            unset builtpkg
            [[ $aurdevelpkgsAver ]] && depsAver="$aurdevelpkgsAver" || depsAver="$(GetJson "varvar" "$json" "Version" "$j")"
            GetBuiltPkg "$j-$depsAver" "$clonedir/${basepkgs[$i]}"
            [[ " ${aurdepspkgs[@]} " =~ " $j " ]] && builtdepspkgs+=($builtpkg) || builtpkgs+=($builtpkg)
        done

        # install
        if [[ $installpkg || -z "${builtpkgs[@]}" ]]; then
            Note "i" $"Installing ${colorW}${pkgsdeps[$i]}${reset} package(s)..."
            # inform about missing name suffix and metadata mismatch
            if [[ -z "${builtdepspkgs[@]}" && -z "${builtpkgs[@]}" ]]; then
                Note "f" $"${colorW}${pkgsdeps[$i]}${reset} package(s) failed to install."
                Note "f" $"ensure package version does not mismatch between .SRCINFO and PKGBUILD"
                Note "f" $"ensure package name has a VCS suffix if this is a devel package"
                errinstall+=(${pkgsdeps[$i]})
            else
                sudo $pacmanbin -Ud ${builtdepspkgs[@]} ${builtpkgs[@]} --ask 36 ${pacopts[@]} --noconfirm
            fi
        fi

        # set dep status
        if [[ $installpkg ]]; then
            for j in "${pkgsdepslist[@]}"; do
                [[ ! " ${aurpkgs[@]} " =~ " $j " ]] && sudo $pacmanbin -D $j --asdeps &>/dev/null
                [[ " ${pacopts[@]} " =~ --(asdep|asdeps) ]] && sudo $pacmanbin -D $j --asdeps &>/dev/null
                [[ " ${pacopts[@]} " =~ --(asexp|asexplicit) ]] && sudo $pacmanbin -D $j --asexplicit &>/dev/null
            done
        fi
    done

    # remove AUR deps
    if [[ ! $installpkg ]]; then
        [[ -n "${aurdepspkgs[@]}" ]] && aurdepspkgs=($(expac -Q '%n' "${aurdepspkgs[@]}"))
        if [[ -n "${aurdepspkgs[@]}" ]]; then
            Note "i" $"Removing installed AUR dependencies..."
            sudo $pacmanbin -Rsn ${aurdepspkgs[@]} --noconfirm
        fi
        # readd removed conflicting packages
        [[ -n "${aurconflictingpkgsrm[@]}" ]] && sudo $pacmanbin -S ${aurconflictingpkgsrm[@]} --ask 36 --asdeps --needed --noconfirm
        [[ -n "${repoconflictingpkgsrm[@]}" ]] && sudo $pacmanbin -S ${repoconflictingpkgsrm[@]} --ask 36 --asdeps --needed --noconfirm
    fi

    # remove locks
    rm "$tmpdir/pacaur.build.lck"
    [[ -e "$tmpdir/pacaur.sudov.lck" ]] && rm "$tmpdir/pacaur.sudov.lck"

    # new orphan and optional packages check
    orphanpkgs=($($pacmanbin -Qdtq))
    neworphanpkgs=($(grep -xvf <(printf '%s\n' "${oldorphanpkgs[@]}") <(printf '%s\n' "${orphanpkgs[@]}")))
    for i in "${neworphanpkgs[@]}"; do
        Note "w" $"${colorW}$i${reset} is now an ${colorY}orphan${reset} package"
    done
    optionalpkgs=($($pacmanbin -Qdttq))
    optionalpkgs=($(grep -xvf <(printf '%s\n' "${orphanpkgs[@]}") <(printf '%s\n' "${optionalpkgs[@]}")))
    newoptionalpkgs=($(grep -xvf <(printf '%s\n' "${oldoptionalpkgs[@]}") <(printf '%s\n' "${optionalpkgs[@]}")))
    for i in "${newoptionalpkgs[@]}"; do
        Note "w" $"${colorW}$i${reset} is now an ${colorY}optional${reset} package"
    done

    # makepkg and install failure check
    if [[ -n "${errmakepkg[@]}" || -n "${errinstall[@]}" ]]; then
        for i in "${errmakepkg[@]}"; do
            Note "f" $"failed to build ${colorW}$i${reset} package(s)"
        done
        exit 1
    fi
}

SearchAur() {
    if [[ -z "$(grep -E "\-\-[r]?sort" <<< ${coweropts[@]})" ]]; then
        [[ $sortorder = descending ]] && coweropts+=("--rsort=$sortby") || coweropts+=("--sort=$sortby");
    fi
    cower ${coweropts[@]} -- $@
}

InfoAur() {
    local aurinfopkgs info infolabel maxlength linfo lbytes

    readarray aurinfopkgs < <(cower ${coweropts[@]} --format "%n|%v|%d|%u|%p|%L|%W|%G|%P|%D|%M|%O|%C|%R|%m|%r|%o|%t|%w|%s|%a\n" $@)
    aurinfopkgsQname=($(expac -Q '%n' $@))
    aurinfopkgsQver=($(expac -Q '%v' $@))

    infolabel=($"Repository" $"Name" $"Version" $"Description" $"URL" $"AUR Page" $"Licenses" $"Keywords" $"Groups" $"Provides" $"Depends on" \
        $"Make Deps" $"Optional Deps" $"Conflicts With" $"Replaces" $"Maintainer" $"Popularity" $"Votes" $"Out of Date" $"Submitted" $"Last Modified")
    linfo=$(GetLength "${infolabel[@]}")
    # take into account differences between characters and bytes
    for i in "${!infolabel[@]}"; do
        (( lbytes[$i] = $(printf "${infolabel[$i]}" | wc -c) - ${#infolabel[$i]} + ${linfo} ))
    done
    maxlength=$(($(tput cols) - $linfo - 4))

    for i in "${!aurinfopkgs[@]}"; do
        IFS='|' read -ra info <<< "${aurinfopkgs[$i]}"
        # repo
        printf "${colorW}%-${lbytes[0]}s  :${reset} ${colorM}aur${reset}\n" "${infolabel[0]}"
        # name and installed status
        if [[ " ${aurinfopkgsQname[@]} " =~ " ${info[0]} " ]]; then
            for j in "${!aurinfopkgsQname[@]}"; do
                [[ "${aurinfopkgsQname[$j]}" != "${info[0]}" ]] && continue
                if [[ $(vercmp "${info[1]}" "${aurinfopkgsQver[$j]}") -eq 0 ]]; then
                    printf "${colorW}%-${lbytes[1]}s  :${reset} ${colorW}%s${reset} ${colorC}[${reset}${colorG}%s${reset}${colorC}]${reset}\n" "${infolabel[1]}" "${info[0]}" $"installed"
                elif [[ $(vercmp "${info[1]}" "${aurinfopkgsQver[$j]}") -lt 0 ]]; then
                    printf "${colorW}%-${lbytes[1]}s  :${reset} ${colorW}%s${reset} ${colorC}[${reset}${colorG}%s: %s${reset}${colorC}]${reset}\n" "${infolabel[1]}" "${info[0]}" $"installed" "${aurinfopkgsQver[$j]}"
                else
                    printf "${colorW}%-${lbytes[1]}s  :${reset} ${colorW}%s${reset} ${colorC}[${reset}${colorR}%s: %s${reset}${colorC}]${reset}\n" "${infolabel[1]}" "${info[0]}" $"installed" "${aurinfopkgsQver[$j]}"
                fi
            done
        else
            printf "${colorW}%-${linfo}s  :${reset} ${colorW}%s${reset}\n" "${infolabel[1]}" "${info[0]}"
        fi
        # version
        if [[ "${info[17]}" = 'no' ]]; then
            printf "${colorW}%-${lbytes[2]}s  :${reset} ${colorG}%s${reset}\n" "${infolabel[2]}" "${info[1]}"
        else
            printf "${colorW}%-${lbytes[2]}s  :${reset} ${colorR}%s${reset}\n" "${infolabel[2]}" "${info[1]}"
        fi
        # description
        if [[ $(GetLength "${info[2]}") -gt $maxlength ]]; then
            # add line breaks if needed and align text
            info[2]=$(sed 's/ /  /g' <<< ${info[2]} | fold -s -w $(($maxlength - 2)) | sed "s/^ //;2,$ s/^/\\x1b[$(($linfo + 4))C/")
        fi
        printf "${colorW}%-${lbytes[3]}s  :${reset} %s\n" "${infolabel[3]}" "${info[2]}"
        # url page
        printf "${colorW}%-${lbytes[4]}s  :${reset} ${colorC}%s${reset}\n" "${infolabel[4]}" "${info[3]}"
        printf "${colorW}%-${lbytes[5]}s  :${reset} ${colorC}%s${reset}\n" "${infolabel[5]}" "${info[4]}"
        # keywords licenses dependencies
        for j in {5..13}; do
            if [[ -n $(tr -dc '[[:print:]]' <<< ${info[$j]}) ]]; then
                # handle special optional deps cases
                if [[ "$j" = '11' ]]; then
                    info[$j]=$(sed -r 's/\S+:/\n&/2g' <<< ${info[$j]} | fold -s -w $(($maxlength - 2)) | sed "s/^ //;2,$ s/^/\\x1b[$(($linfo + 4))C/")
                else
                    # add line breaks if needed and align text
                    if [[ $(GetLength "${info[$j]}") -gt $maxlength ]]; then
                        info[$j]=$(sed 's/ /  /g' <<< ${info[$j]} | fold -s -w $(($maxlength - 2)) | sed "s/^ //;2,$ s/^/\\x1b[$(($linfo + 4))C/")
                    fi
                fi
                printf "${colorW}%-${lbytes[$j+1]}s  :${reset} %s\n" "${infolabel[$j+1]}" "${info[$j]}"
            else
                printf "${colorW}%-${lbytes[$j+1]}s  :${reset} %s\n" "${infolabel[$j+1]}" $"None"
            fi
        done
        # maintainer popularity votes
        for j in {14..16}; do
            printf "${colorW}%-${lbytes[$j+1]}s  :${reset} %s\n" "${infolabel[$j+1]}" "${info[$j]}"
        done
        # outofdate
        if [[ "${info[17]}" = 'no' ]]; then
            printf "${colorW}%-${lbytes[18]}s  :${reset} ${colorG}%s${reset}\n" "${infolabel[18]}" $"No"
        else
            printf "${colorW}%-${lbytes[18]}s  :${reset} ${colorR}%s${reset} [%s]\n" "${infolabel[18]}" $"Yes" $"$(date -d "@${info[18]}" "+%c")"
        fi
        # submitted modified
        printf "${colorW}%-${lbytes[19]}s  :${reset} %s\n" "${infolabel[19]}" $"$(date -d "@${info[19]}" "+%c")"
        printf "${colorW}%-${lbytes[20]}s  :${reset} %s\n" "${infolabel[20]}" $"$(date -d "@${info[20]}" "+%c")"
        echo
    done
}

CheckUpdates() {
    local foreignpkgs foreignpkgsbase repopkgsQood repopkgsQver repopkgsSver repopkgsSrepo repopkgsQgrp repopkgsQignore
    local aurpkgsQood aurpkgsAname aurpkgsAver aurpkgsQver aurpkgsQignore i json
    local aurdevelpkgsAver aurdevelpkgsQver aurpkgsQoodAver lname lQver lSver lrepo lgrp lAname lAQver lASver lArepo

    GetIgnoredPkgs

    if [[ ! "${opts[@]}" =~ "n" && ! " ${pacopts[@]} " =~ --native && $fallback = true ]]; then
        [[ -z "${pkgs[@]}" ]] && foreignpkgs=($($pacmanbin -Qmq)) || foreignpkgs=(${pkgs[@]})
        if [[ -n "${foreignpkgs[@]}" ]]; then
            SetJson ${foreignpkgs[@]}
            aurpkgsAname=($(GetJson "var" "$json" "Name"))
            aurpkgsAver=($(GetJson "var" "$json" "Version"))
            aurpkgsQver=($(expac -Q '%v' ${aurpkgsAname[@]}))
            for i in "${!aurpkgsAname[@]}"; do
                [[ $(vercmp "${aurpkgsAver[$i]}" "${aurpkgsQver[$i]}") -gt 0 ]] && aurpkgsQood+=(${aurpkgsAname[$i]});
            done
        fi

        # add devel packages
        if [[ $devel ]]; then
            if [[ ! $needed ]]; then
                for i in "${foreignpkgs[@]}"; do
                    [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< $i)" ]] && aurpkgsQood+=($i)
                done
            else
                foreignpkgsbase=($(expac -Q '%n %e' ${foreignpkgs[@]} | awk '{if ($2 == "(null)") print $1; else print $2}'))
                foreignpkgsnobase=($(expac -Q '%n' ${foreignpkgs[@]}))
                for i in "${!foreignpkgsbase[@]}"; do
                    if [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< ${foreignpkgsbase[$i]})" ]]; then
                        [[ ! -d "$clonedir/${foreignpkgsbase[$i]}" ]] && DownloadPkgs "${foreignpkgsbase[$i]}" &>/dev/null
                        cd "$clonedir/${foreignpkgsbase[$i]}"
                        # silent extraction and pkgver update only
                        makepkg -od --noprepare --skipinteg &>/dev/null
                        # retrieve updated version
                        aurdevelpkgsAver=($(makepkg --packagelist | awk -F "-" '{print $(NF-2)"-"$(NF-1)}'))
                        aurdevelpkgsAver=${aurdevelpkgsAver[0]}
                        aurdevelpkgsQver=$(expac -Qs '%v' "^${foreignpkgsbase[$i]}$" | head -1)
                        if [[ $(vercmp "$aurdevelpkgsQver" "$aurdevelpkgsAver") -ge 0 ]]; then
                            continue
                        else
                            aurpkgsQood+=(${foreignpkgsnobase[$i]})
                            aurpkgsQoodAver+=($aurdevelpkgsAver)
                        fi
                    fi
                done
            fi
        fi

        if [[ -n "${aurpkgsQood[@]}" && ! $quiet ]]; then
            SetJson ${aurpkgsQood[@]}
            aurpkgsAname=($(GetJson "var" "$json" "Name"))
            aurpkgsAname=($(expac -Q '%n' "${aurpkgsAname[@]}"))
            aurpkgsAver=($(GetJson "var" "$json" "Version"))
            aurpkgsQver=($(expac -Q '%v' "${aurpkgsAname[@]}"))
            for i in "${!aurpkgsAname[@]}"; do
                [[ " ${ignoredpkgs[@]} " =~ " ${aurpkgsAname[$i]} " ]] && aurpkgsQignore[$i]=$"[ ignored ]"
                if [[ -n "$(grep -E "\-(cvs|svn|git|hg|bzr|darcs|nightly.*)$" <<< ${aurpkgsAname[$i]})" ]]; then
                    [[ ! $needed ]] && aurpkgsAver[$i]=$"latest"
                fi
            done
            lAname=$(GetLength "${aurpkgsAname[@]}")
            lAQver=$(GetLength "${aurpkgsQver[@]}")
            lASver=$(GetLength "${aurpkgsAver[@]}")
            lArepo=3
        fi
    fi

    if [[ ! "${opts[@]}" =~ "m" && ! " ${pacopts[@]} " =~ --foreign ]]; then
        [[ -n "${pkgs[@]}" ]] && pkgs=($(expac -Q '%n' "${pkgs[@]}"))
        repopkgsQood=($($pacmanbin -Qunq ${pkgs[@]}))

        if [[ -n "${repopkgsQood[@]}" && ! $quiet ]]; then
            repopkgsQver=($(expac -Q '%v' "${repopkgsQood[@]}"))
            repopkgsSver=($(expac -S -1 '%v' "${repopkgsQood[@]}"))
            repopkgsSrepo=($(expac -S -1 '%r' "${repopkgsQood[@]}"))
            repopkgsQgrp=($(expac -Qv -l "#" '(%G)' "${repopkgsQood[@]}"))
            for i in "${!repopkgsQood[@]}"; do
                [[ "${repopkgsQgrp[$i]}" = '(None)' ]] && unset repopkgsQgrp[$i] || repopkgsQgrp[$i]=$(tr '#' ' ' <<< ${repopkgsQgrp[$i]})
                [[ " ${ignoredpkgs[@]} " =~ " ${repopkgsQood[$i]} " ]] && repopkgsQignore[$i]=$"[ ignored ]"
            done
            lname=$(GetLength "${repopkgsQood[@]}")
            lQver=$(GetLength "${repopkgsQver[@]}")
            lSver=$(GetLength "${repopkgsSver[@]}")
            lrepo=$(GetLength "${repopkgsSrepo[@]}")
            lgrp=$(GetLength "${repopkgsQgrp[@]}")
        fi
    fi

    if [[ -n "${aurpkgsQood[@]}" && ! $quiet ]]; then
        [[ $lAname -gt $lname ]] && lname=$lAname
        [[ $lAQver -gt $lQver ]] && lQver=$lAQver
        [[ $lASver -gt $lSver ]] && lSver=$lASver
    fi

    if [[ -n "${repopkgsQood[@]}" ]]; then
        exitrepo=$?
        if [[ ! $quiet ]]; then
            for i in "${!repopkgsQood[@]}"; do
                printf "${colorB}::${reset} ${colorM}%-${lrepo}s${reset}  ${colorW}%-${lname}s${reset}  ${colorR}%-${lQver}s${reset}  ->  ${colorG}%-${lSver}s${reset}  ${colorB}%-${lgrp}s${reset}  ${colorY}%s${reset}\n" "${repopkgsSrepo[$i]}" "${repopkgsQood[$i]}" "${repopkgsQver[$i]}" "${repopkgsSver[$i]}" "${repopkgsQgrp[$i]}" "${repopkgsQignore[$i]}"
            done
        else
            tr ' ' '\n' <<< ${repopkgsQood[@]}
        fi
    fi
    if [[ -n "${aurpkgsQood[@]}" && $fallback = true ]]; then
        exitaur=$?
        if [[ ! $quiet ]]; then
            for i in "${!aurpkgsAname[@]}"; do
                printf "${colorB}::${reset} ${colorM}%-${lrepo}s${reset}  ${colorW}%-${lname}s${reset}  ${colorR}%-${lQver}s${reset}  ->  ${colorG}%-${lSver}s${reset}  ${colorB}%-${lgrp}s${reset}  ${colorY}%s${reset}\n" "aur" "${aurpkgsAname[$i]}" "${aurpkgsQver[$i]}" "${aurpkgsAver[$i]}" " " "${aurpkgsQignore[$i]}"
            done
        else
            tr ' ' '\n' <<< ${aurpkgsQood[@]} | sort -u
        fi
    fi
    # exit code
    if [[ -n "$exitrepo" && -n "$exitaur" ]]; then
        [[ $exitrepo -eq 0 || $exitaur -eq 0 ]] && exit 0 || exit 1
    elif [[ -n "$exitrepo" ]]; then
        [[ $exitrepo -eq 0 ]] && exit 0 || exit 1
    elif [[ -n "$exitaur" ]]; then
        [[ $exitaur -eq 0 ]] && exit 0 || exit 1
    else
        exit 1
    fi
}

CleanCache() {
    if [[ $SRCDEST ]]; then
        [[ $count -eq 1 ]] && printf "\n%s\n %s\n" $"Sources to keep:" $"All development packages sources"
        printf "\n%s %s\n" $"AUR source cache directory:" "$SRCDEST"
        if [[ $count -eq 1 ]]; then
            if Proceed "y" $"Do you want to remove all non development files from AUR source cache?"; then
                printf "%s\n" $"removing non development files from source cache..."
                rm -f $SRCDEST/* &>/dev/null
            fi
        else
            if ! Proceed "n" $"Do you want to remove ALL files from AUR source cache?"; then
                printf "%s\n" $"removing all files from AUR source cache..."
                rm -rf $SRCDEST/* &>/dev/null
            fi
        fi
    fi
    if [[ -d "$clonedir" ]]; then
        cd $clonedir
        [[ $count -eq 1 ]] && printf "\n%s\n %s\n" $"Clones to keep:" $"All packages clones"
        printf "\n%s %s\n" $"AUR clone directory:" "$clonedir"
        if [[ $count -eq 1 ]]; then
            if Proceed "y" $"Do you want to remove all uninstalled clones from AUR clone directory?"; then
                foreignpkgsbase=($(expac -Q '%n %e' $($pacmanbin -Qmq) | awk '{if ($2 == "(null)") print $1; else print $2}'))
                printf "%s\n\n" $"removing uninstalled clones from AUR clone cache..."
                for clone in *; do
                    [[ -d "$clonedir/$clone" && ! " ${foreignpkgsbase[@]} " =~ " $clone " ]] && rm -rf "$clonedir/$clone"
                done
            fi
            if Proceed "y" $"Do you want to remove all untracked files from AUR clone directory?"; then
                printf "%s\n" $"removing untracked files from AUR clone cache..."
                for clone in *; do
                    [[ -d "$clonedir/$clone" ]] && git --git-dir="$clone/.git" --work-tree="$clone" clean -ffdx &>/dev/null
                done
            fi
        else
            if ! Proceed "n" $"Do you want to remove ALL clones from AUR clone directory?"; then
                printf "%s\n" $"removing all clones from AUR clone cache..."
                for clone in *; do
                    [[ -d "$clonedir/$clone" ]] && rm -rf "$clonedir/$clone"
                done
            fi
        fi
    fi
    exit 0
}

GetIgnoredPkgs() {
    # global ignoredpkgs
    ignoredpkgs+=($(grep '^IgnorePkg' '/etc/pacman.conf' | awk -F '=' '{print $NF}' | tr -d "'\""))
    [[ -e "$HOME/.config/cower/config" ]] && ignoredpkgs+=($(grep '^IgnorePkg' "$HOME/.config/cower/config" | awk -F '=' '{print $NF}' | tr -d "'\""))
    ignoredpkgs=(${ignoredpkgs[@]//,/ })
}

GetIgnoredGrps() {
    # global ignoredgrps
    ignoredgrps+=($(grep '^IgnoreGroup' '/etc/pacman.conf' | awk -F '=' '{print $NF}' | tr -d "'\""))
    ignoredgrps=(${ignoredgrps[@]//,/ })
}

GetInstallScripts() {
    local installscriptspath
    # global installscripts
    [[ ! -d "$clonedir/$1" ]] && return
    unset installscriptspath installscripts
    installscriptspath=($(find "$clonedir/$1/" -maxdepth 1 -name "*.install"))
    [[ -n "${installscriptspath[@]}" ]] && installscripts=($(basename -a ${installscriptspath[@]}))
}

GetBuiltPkg() {
    local pkgext
    # global builtpkg
    # check PKGEXT suffixe first, then default .xz suffixe for repository packages in pacman cache
    # and lastly all remaining suffixes in case PKGEXT is locally overridden
    for pkgext in $PKGEXT .pkg.tar.xz .pkg.tar .pkg.tar.gz .pkg.tar.bz2 .pkg.tar.lzo .pkg.tar.lrz .pkg.tar.Z; do
        builtpkg="$2/$1-${CARCH}$pkgext"
        [[ ! -f "$builtpkg" ]] && builtpkg="$2/$1-any$pkgext"
        [[ -f "$builtpkg" ]] && break;
    done
    [[ ! -f "$builtpkg" ]] && unset builtpkg
}

GetPkgbase() {
    local i
    # global json pkgsbase basepkgs
    SetJson "$@"
    for i in "$@"; do
        pkgsbase+=($(GetJson "varvar" "$json" "PackageBase" "$i"))
    done
    for i in "${pkgsbase[@]}"; do
        [[ " ${basepkgs[@]} " =~ " $i " ]] && continue
        basepkgs+=($i)
    done
}

declare -A jsoncache
SetJson() {
    if [[ $# -eq 0 ]]; then
        json="{}"
    else
        # global json
        if [[ -z "${jsoncache[$@]}" ]]; then
            jsoncache[$@]="$(DownloadJson $@)"
        fi
        json="${jsoncache[$@]}"
    fi
}

DownloadJson() {
    local urlencodedpkgs urlargs urlcurl urlarg urlmax j
    urlencodedpkgs=($(sed 's/+/%2b/g;s/@/%40/g' <<< $@)) # pkgname consists of alphanum@._+-
    urlarg='&arg[]='
    urlargs="$(printf "$urlarg%s" "${urlencodedpkgs[@]}")"
    urlmax=4400
    # ensure the URI length is shorter than 4444 bytes (44 for AUR path)
    if [[ "${#urlargs}" -lt $urlmax ]]; then
        curl -sfg --compressed -C 0 "https://$aururl$aurrpc$urlargs"
    else
        # split and merge json stream
        j=0
        for i in "${!urlencodedpkgs[@]}"; do
            if [[ $((${#urlcurl[$j]} + ${#urlencodedpkgs[$i]} + ${#urlarg})) -ge $urlmax ]]; then
                j=$(($j + 1))
            fi
            urlcurl[$j]=${urlcurl[$j]}${urlarg}${urlencodedpkgs[$i]}
        done
        urlargs="$(printf "https://$aururl$aurrpc%s " "${urlcurl[@]}")"
        curl -sfg --compressed -C 0 $urlargs | sed 's/\(]}{\)\([A-Za-z0-9":,]\+[[]\)/,/g;s/\("resultcount":\)\([0-9]\+\)/"resultcount":0/g'
    fi
}

GetJson() {
    if json_verify -q <<< "$2"; then
        case "$1" in
            var)
                json_reformat <<< "$2" | tr -d "\", " | grep -Po "$3:.*" | sed -r "s/$3:/$3#/g" | awk -F "#" '{print $2}';;
            varvar)
                json_reformat <<< "$2" | tr -d ", " | sed -e "/\"Name\":\"$4\"/,/}/!d" | \
                tr -d "\"" | grep -Po "$3:.*" | sed -r "s/$3:/$3#/g" | awk -F "#" '{print $2}';;
            array)
                json_reformat <<< "$2" | tr -d ", " | sed -e "/^\"$3\"/,/]/!d" | tr -d '\"' \
                | tr '\n' ' ' | sed "s/] /]\n/g" | cut -d' ' -f 2- | tr -d '[]"' | tr -d '\n';;
            arrayvar)
                json_reformat <<< "$2" | tr -d ", " | sed -e "/\"Name\":\"$4\"/,/}/!d" | \
                sed -e "/^\"$3\"/,/]/!d" | tr -d '\"' | tr '\n' ' ' | cut -d' ' -f 2- | tr -d '[]';;
        esac
    else
        Note "e" $"Failed to parse JSON"
    fi
}

CheckRequires() {
    local Qrequires
    Qrequires=($(expac -Q '%n %D' | grep -E " $@[\+]*[^a-zA-Z0-9_@\.\+-]+" | awk '{print $1}' | tr '\n' ' '))
    if [[ -n "${Qrequires[@]}" ]]; then
        Note "f" $"failed to prepare transaction (could not satisfy dependencies)"
        Note "e" $"${Qrequires[@]}: requires $@"
    fi
}

Proceed() {
    local Y y N n answer
    Y="$(gettext pacman Y)"; y="${Y,,}";
    N="$(gettext pacman N)"; n="${N,,}"
    case "$1" in
        y)  printf "${colorB}%s${reset} ${colorW}%s${reset}" "::" "$2 [$Y/$n] "
            if [[ ! $noconfirm ]]; then
                case "$TERM" in
                    dumb)
                        read -r answer
                        ;;
                    *)
                        if [[ $cleancache ]]; then
                            read -r answer
                        else
                            read -r -n 1 answer
                            echo
                        fi
                        ;;
                esac
            else
                answer=$Y
                echo
            fi
            case $answer in
                $Y|$y|'') return 0;;
                *) return 1;;
            esac;;
        n)  printf "${colorB}%s${reset} ${colorW}%s${reset}" "::" "$2 [$y/$N] "
            if [[ ! $noconfirm ]]; then
                case "$TERM" in
                    dumb)
                        read -r answer
                        ;;
                    *)
                        if [[ $cleancache ]]; then
                            read -r answer
                        else
                            read -r -n 1 answer
                            echo
                        fi
                        ;;
                esac
            else
                answer=$N
                echo
            fi
            case $answer in
                $N|$n|'') return 0;;
                *) return 1;;
            esac;;
    esac
}

Note() {
    case "$1" in
        i) echo -e "${colorB}::${reset} $2";;       # info
        s) echo -e "${colorG}::${reset} $2";;       # success
        w) echo -e "${colorY}::${reset} $2";;       # warn
        f) echo -e "${colorR}::${reset} $2" >&2;;   # fail
        e) echo -e "${colorR}::${reset} $2" >&2;    # error
           exit 1;;
    esac
}

GetLength() {
    local length=0 i
    for i in "$@"; do
        x=${#i}
        [[ $x -gt $length ]] && length=$x
    done
    echo $length
}

NothingToDo() {
    [[ -z "$@" ]] && printf "%s\n" $" there is nothing to do" && exit || return 0
}

SudoV() {
    touch "$tmpdir/pacaur.sudov.lck"
    while [[ -e "$tmpdir/pacaur.sudov.lck" ]]; do
        sudo $pacmanbin -V > /dev/null
        sleep 2
    done
}

trap Cancel INT
Cancel() {
    echo
    [[ -e "$tmpdir/pacaur.build.lck" ]] && rm "$tmpdir/pacaur.build.lck"
    [[ -e "$tmpdir/pacaur.sudov.lck" ]] && rm "$tmpdir/pacaur.sudov.lck"
    exit
}

Usage() {
    printf "%s\n" $"usage:  pacaur <operation> [options] [target(s)] -- See also pacaur(8)"
    printf "%s\n" $"operations:"
    printf "%s\n" $" pacman extension"
    printf "%s\n" $"   -S, -Ss, -Si, -Sw, -Su, -Sc, -Qu"
    printf "%s\n" $"                    extend pacman operations to the AUR"
    printf "%s\n" $" AUR specific"
    printf "%s\n" $"   -s, --search     search AUR for matching strings"
    printf "%s\n" $"   -i, --info       view package information"
    printf "%s\n" $"   -d, --download   download target(s) -- pass twice to download AUR dependencies"
    printf "%s\n" $"   -m, --makepkg    download and make target(s)"
    printf "%s\n" $"   -y, --sync       download, make and install target(s)"
    printf "%s\n" $"   -u, --update     update AUR package(s)"
    printf "%s\n" $"   -k, --check      check for AUR update(s)"
    printf "%s\n" $" general"
    printf "%s\n" $"   -v, --version    display version information"
    printf "%s\n" $"   -h, --help       display help information"
    echo
    printf "%s\n" $"options:"
    printf "%s\n" $" pacman extension - can be used with the -S, -Ss, -Si, -Sw, -Su, -Sc operations"
    printf "%s\n" $"   -a, --aur        only search, build or install target(s) from the AUR"
    printf "%s\n" $"   -r, --repo       only search, build or install target(s) from the repositories"
    printf "%s\n" $" general"
    printf "%s\n" $"   -e, --edit       edit target(s) PKGBUILD and view install script"
    printf "%s\n" $"   -q, --quiet      show less information for query and search"
    printf "%s\n" $"   --devel          consider AUR development packages upgrade"
    printf "%s\n" $"   --foreign        consider already installed foreign dependencies"
    printf "%s\n" $"   --ignore         ignore a package upgrade (can be used more than once)"
    printf "%s\n" $"   --needed         do not reinstall already up-to-date target(s)"
    printf "%s\n" $"   --noconfirm      do not prompt for any confirmation"
    printf "%s\n" $"   --noedit         do not prompt to edit files"
    printf "%s\n" $"   --rebuild        always rebuild package(s)"
    printf "%s\n" $"   --silent         silence output"
    echo
}

Version() {
    echo "pacaur $version"
}

#
# Main
#

# get short arguments
args=($@)
for i in "${args[@]}"; do
    [[ "$i" =~ ^-[a-zA-Z0-9] ]] && opts+=($i)
done

# get options
count=0
while [[ -n "${!OPTIND}" ]]; do
    while getopts "sidmykufecqrahvxVDFQRSTUbglnoptw-:" OPT; do
        pacmanarg+=("-$OPT");
        case "$OPT" in
            -)
                case "$OPTARG" in
                    search) [[ $pac || $pacS || $pacQ ]] && pacopts+=("--search");
                        [[ $pacS ]] && operation=sync && search=true && coweropts+=("-s");
                        [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; search=true; coweropts+=("-s"); aur='1';;
                    info) [[ $pac || $pacS || $pacQ ]] && pacopts+=("--info");
                        [[ $pacS ]] && operation=sync && info=true && coweropts+=("-i");
                        [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; info=true; coweropts+=("-i"); aur='1';;
                    download) operation=download && ((count++));;
                    makepkg) operation=sync; coweropts+=("-f"); aur='1';;
                    sync) [[ $pac || $pacS || $pacQ ]] && pacopts+=("--sync");
                        [[ $pacS ]] && operation=sync; installpkg=true; aur='1';
                        [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; installpkg=true; aur='1';;
                    check) [[ $pac || $pacS || $pacQ ]] && pacopts+=("--check");
                        [[ $pac || $pacQ || $pacS ]] && continue || operation=upgrades; pacopts+=("--foreign");;
                    update) operation=sync; upgrade=true; installpkg=true; selective=true; aur='1';;
                    edit) edit=true; [[ ! $pacQ && ! $operation ]] && operation=editpkg;;
                    quiet) quiet=true; pacopts+=("--quiet"); coweropts+=("-q"); [[ $search || $operation = upgrades ]] && color=never;;
                    repo) repo='1';;
                    aur) aur='1';;
                    devel) devel=true;;
                    foreign) [[ $pacQ ]] && pacopts+=("--foreign"); foreign=true;;
                    ignore=?*) ignoredpkgs+=(${OPTARG#*=}); ignoreopts+=("--ignore ${OPTARG#*=}");;
                    ignore) ignoredpkgs+=(${!OPTIND}); ignoreopts+=("--ignore ${!OPTIND}"); shift;;
                    color=?*) color=${OPTARG#*=}; pacopts+=("--color ${OPTARG#*=}") && coweropts+=("--color=${OPTARG#*=}");;
                    color) color=${!OPTIND}; pacopts+=("--color ${!OPTIND}") && coweropts+=("--color=${!OPTIND}"); shift;;
                    ignore-ood) coweropts+=("--ignore-ood");;
                    no-ignore-ood) coweropts+=("--no-ignore-ood");;
                    sort=?*) coweropts+=("--sort ${OPTARG#*=}");;
                    sort) coweropts+=("--sort ${!OPTIND}"); shift;;
                    rsort=?*) coweropts+=("--rsort ${OPTARG#*=}");;
                    rsort) coweropts+=("--rsort ${!OPTIND}"); shift;;
                    by=?*) coweropts+=("--by ${OPTARG#*=}");;
                    by) coweropts+=("--by ${!OPTIND}"); shift;;
                    asdep|asdeps) pacopts+=("--asdeps"); makeopts+=("--asdeps");;
                    needed) needed=true; pacopts+=("--needed"); makeopts+=("--needed");;
                    nodeps) nodeps=true; pacopts+=("--nodeps"); makeopts+=("--nodeps"); ((count++));;
                    assume-installed=?*) assumeinstalled+=(${OPTARG#*=}); pacopts+=("--assume-installed ${OPTARG#*=}");;
                    assume-installed) assumeinstalled+=(${!OPTIND}); pacopts+=("--assume-installed ${!OPTIND}"); shift;;
                    noconfirm) noconfirm=true; pacopts+=("--noconfirm");;
                    noedit) noedit=true;;
                    rebuild) rebuild=true;;
                    silent) silent=true; makeopts+=("--log");;
                    domain=?*) aururl=${OPTARG#*=}; coweropts+=("--domain ${OPTARG#*=}");;
                    domain) aururl=${!OPTIND}; coweropts+=("--domain ${!OPTIND}"); shift;;
                    root=?*) pacopts+=("--root ${OPTARG#*=}");;
                    root) pacopts+=("--root ${!OPTIND}"); shift;;
                    version) Version; exit;;
                    help) Usage; exit;;
                    *) pacopts+=("--$OPTARG");;
                esac;;
            s)  [[ $pacS ]] && operation=sync && search=true && coweropts+=("-s");
                [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; search=true; coweropts+=("-s"); aur='1';;
            i)  [[ $pacS ]] && operation=sync && info=true && coweropts+=("-i");
                [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; info=true; coweropts+=("-i"); aur='1';;
            d)  [[ $pacS ]] && nodeps=true && pacopts+=("--nodeps") && makeopts+=("--nodeps") && ((count++));
                [[ $pac || $pacQ || $pacS ]] && continue || operation=download && ((count++));;
            m)  [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; aur='1';;
            y)  [[ $pacS ]] && operation=sync && refresh=true;
                [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; installpkg=true; aur='1';;
            k)  [[ $pac || $pacQ || $pacS ]] && continue || operation=upgrades; coweropts+=("-uq"); pacopts+=("--foreign");;
            u)  [[ $pacQ ]] && operation=upgrades;
                [[ $pacS ]] && operation=sync && upgrade=true;
                [[ $pac || $pacQ || $pacS ]] && continue || operation=sync; upgrade=true; installpkg=true; selective=true; aur='1';;
            e)  [[ $pacQ ]] && pacopts+=("--explicit") && continue || edit=true;
                [[ ! $operation ]] && operation=editpkg;;
            c)  [[ $pacS ]] && operation=sync && cleancache=true && ((count++));
                [[ $pac || $pacQ || $pacS ]] && continue;;
            q)  quiet=true; pacopts+=("--quiet"); coweropts+=("-q"); [[ $search || $operation = upgrades ]] && color=never;;
            r)  repo='1';;
            a)  aur='1';;
            Q)  pacQ='1';;
            S)  pacS='1'; operation=sync;
                [[ "${opts[@]}" =~ "w" ]] && continue || installpkg=true;
                [[ "${opts[@]}" =~ "g" || "${opts[@]}" =~ "l" || "${opts[@]}" =~ "p" ]] && unset operation;;
            [A-Z]) pac='1';;
            h)  [[ "${opts[@]}" =~ ^-[A-Z] ]] && unset operation && continue || Usage; exit;;
            v)  [[ "${opts[@]}" =~ ^-[A-Z] ]] && continue || Version; exit;;
            *)  continue;;
        esac
    done
    # packages
    [[ -z "${!OPTIND}" ]] && break || pkgs+=("${!OPTIND}")
    shift $OPTIND
    OPTIND=1
done

# color
if [[ -n "$(grep '^Color' '/etc/pacman.conf')" && $color != 'never' ]]; then
    [[ $color = 'always' ]] && coweropts+=("--color=always") || coweropts+=("--color=auto")
    reset="\e[0m"
    colorR="\e[1;31m"
    colorG="\e[1;32m"
    colorY="\e[1;33m"
    colorB="\e[1;34m"
    colorM="\e[1;35m"
    colorC="\e[1;36m"
    colorW="\e[1;39m"
elif [[ -z "$(grep '^Color' '/etc/pacman.conf')" && ($color = 'always' || $color = 'auto') ]]; then
    pacopts+=("--color $color") && coweropts+=("--color=$color")
    reset="\e[0m"
    colorR="\e[1;31m"
    colorG="\e[1;32m"
    colorY="\e[1;33m"
    colorB="\e[1;34m"
    colorM="\e[1;35m"
    colorC="\e[1;36m"
    colorW="\e[1;39m"
else
    [[ $color != 'always' && $color != 'auto' ]] && makeopts+=("--nocolor")
fi

# sanity check
pacmanarg=(${pacmanarg[@]/--/})
pacmanarg=(${pacmanarg[@]/-r/})
pacmanarg=(${pacmanarg[@]/-a/})
[[ $operation = sync && ! $search && ! $info && ! $cleancache ]] && [[ "$EUID" -eq 0 ]] && Note "e" $"you cannot perform this operation as root"
[[ $pacS ]] && pacmanarg=(${pacmanarg[@]/-e/})
[[ $pacS ]] && [[ $search && $info ]] && coweropts=(${coweropts[@]/-i/})
[[ $pacS ]] && [[ $cleancache ]] && unset search info upgrade
[[ ! $(command -v "${editor%% *}") ]] && Note "e" $"${colorW}editor${reset} variable unset"
[[ "$PACMAN" = $(basename "$0") ]] && Note "e" $"you cannot use ${colorW}pacaur${reset} as PACMAN environment variable"
[[ ! -w "$clonedir" ]] && Note "e" $"${colorW}$clonedir${reset} does not have write permission"
[[ -z "${pkgs[@]}" ]] && [[ $operation = download || $operation = sync || $operation = editpkg ]] && [[ ! $refresh && ! $upgrade && ! $cleancache ]] && Note "e" $"no targets specified (use -h for help)"
[[ -z "${pkgs[@]}" && -n "$(grep -e "-[RU]" <<< ${pacmanarg[@]})" && -z "$(grep -e "-[h]" <<< ${pacmanarg[@]})" ]] && Note "e" $"no targets specified (use -h for help)"
[[ $repo && $aur ]] && Note "e" $"target not found"

# operations
case $operation in
    download)
        # download (-d) handling
        ClassifyPkgs ${pkgs[@]}
        if [[ $count -gt 1 ]]; then
            DepsSolver
            DownloadPkgs ${deps[@]}
        else
            if [[ -n "${aurpkgs[@]}" ]]; then
                DownloadPkgs ${aurpkgs[@]}
            else
                exit 1
            fi
        fi
        EditPkgs ${pkgsbase[@]}
        exit;;
    editpkg)
        # edit (-e) handling
        GetPkgbase ${pkgs[@]}
        EditPkgs ${pkgsbase[@]}
        exit;;
    sync)
        # search (-Ss, -s) handling
        if [[ $search ]]; then
            if [[ ! $aur ]]; then
                if [[ $refresh ]]; then
                    sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} -- ${pkgs[@]}
                else
                    $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} -- ${pkgs[@]}
                fi
                exitrepo=$?
            fi
            if [[ ! $repo && ($fallback = true || $aur) ]]; then
                SearchAur ${pkgs[@]}
                exitaur=$?
            fi
            # exit code
            if [[ -n "$exitrepo" && -n "$exitaur" ]]; then
                [[ $exitrepo -eq 0 || $exitaur -eq 0 ]] && exit 0 || exit 1
            elif [[ -n "$exitrepo" ]]; then
                [[ $exitrepo -eq 0 ]] && exit 0 || exit 1
            elif [[ -n "$exitaur" ]]; then
                [[ $exitaur -eq 0 ]] && exit 0 || exit 1
            else
                exit 1
            fi
        # info (-Si, -i) handling
        elif [[ $info ]]; then
            if [[ -z "${pkgs[@]}" ]]; then
                $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]}
            else
                ClassifyPkgs ${pkgs[@]}
            fi
            if [[ -n "${repopkgs[@]}" ]]; then
                [[ $refresh ]] && sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${repopkgs[@]}
                [[ ! $refresh ]] && $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${repopkgs[@]}
            fi
            if [[ -n "${aurpkgs[@]}" ]]; then
                [[ $refresh ]] && [[ -z "${repopkgs[@]}" ]] && sudo $pacmanbin -Sy ${pacopts[@]} ${ignoreopts[@]}
                if [[ $fallback = true && ! $aur ]]; then
                    if [[ "${#aurpkgs[@]}" -gt 1 ]]; then
                        Note "w" $"Packages ${colorW}${aurpkgs[*]}${reset} not found in repositories, trying ${colorM}AUR${reset}..."
                    else
                        Note "w" $"Package ${colorW}${aurpkgs[*]}${reset} not found in repositories, trying ${colorM}AUR${reset}..."
                    fi
                fi
                # display info without buffer delay
                tmpinfo=$(mktemp "$tmpdir/pacaur.infoaur.XXXX") && InfoAur ${aurpkgs[@]} > $tmpinfo && cat $tmpinfo && rm $tmpinfo
            fi
        # clean (-Sc) handling
        elif [[ $cleancache ]]; then
            [[ ! $aur ]] && sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${repopkgs[@]}
            [[ ! $repo ]] && [[ $fallback = true || $aur ]] && CleanCache ${pkgs[@]}
        # sysupgrade (-Su, -u) handling
        elif [[ $upgrade ]]; then
            [[ -n "${pkgs[@]}" ]] && ClassifyPkgs ${pkgs[@]}
            if [[ ! $aur ]]; then
                sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${repopkgs[@]}
                (($? > 0)) && [[ $repo ]] && exit 1
                [[ $repo ]] && exit 0
            fi
            [[ ! $repo ]] && [[ $aur ]] && [[ $refresh ]] && [[ -z "${repopkgs[@]}" ]] && sudo $pacmanbin -Sy ${pacopts[@]} ${ignoreopts[@]}
            if [[ -n "${aurpkgs[@]}" ]] && [[ $fallback = true && ! $aur ]]; then
                if [[ "${#aurpkgs[@]}" -gt 1 ]]; then
                    Note "w" $"Packages ${colorW}${aurpkgs[*]}${reset} not found in repositories, trying ${colorM}AUR${reset}..."
                else
                    Note "w" $"Package ${colorW}${aurpkgs[*]}${reset} not found in repositories, trying ${colorM}AUR${reset}..."
                fi
            fi
            [[ ! $repo ]] && [[ $fallback = true || $aur ]] && Core
        # sync (-S, -y), downloadonly (-Sw, -m), refresh (-Sy)
        else
            if [[ -z "${pkgs[@]}" ]]; then
                sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]}
            else
                ClassifyPkgs ${pkgs[@]}
            fi
            [[ -n "${repopkgs[@]}" ]] && sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} ${repopkgs[@]}
            if [[ -n "${aurpkgs[@]}" ]]; then
                [[ $refresh ]] && [[ -z "${repopkgs[@]}" ]] && sudo $pacmanbin -Sy ${pacopts[@]} ${ignoreopts[@]}
                if [[ $fallback = true && ! $aur ]]; then
                    if [[ "${#aurpkgs[@]}" -gt 1 ]]; then
                        Note "w" $"Packages ${colorW}${aurpkgs[*]}${reset} not found in repositories, trying ${colorM}AUR${reset}..."
                    else
                        Note "w" $"Package ${colorW}${aurpkgs[*]}${reset} not found in repositories, trying ${colorM}AUR${reset}..."
                    fi
                fi
                Core
            fi
        fi
        exit;;
    upgrades)
        # upgrades (-Qu, -k) handling
        CheckUpdates ${pkgs[@]}
        exit;;
    *)  # others operations handling
        if [[ -n "$(grep -e "-[F]" <<< ${pacmanarg[@]})" && -n "$(grep -e "-[y]" <<< ${pacmanarg[@]})" ]]; then
            sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} "${pkgs[@]}"
        elif [[ -z "${pkgs[@]}" || -n "$(grep -e "-[DFQTglp]" <<< ${pacmanarg[@]})" ]] && [[ ! " ${pacopts[@]} " =~ --(asdep|asdeps) && ! " ${pacopts[@]} " =~ --(asexp|asexplicit) ]]; then
            $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} "${pkgs[@]}"
        else
            sudo $pacmanbin ${pacmanarg[@]} ${pacopts[@]} ${ignoreopts[@]} "${pkgs[@]}"
        fi
        exit;;
esac
# vim:set ts=4 sw=2 et:
