#!/usr/bin/php
<?php

/******************************************************************************
*
* filelist
* part of lfs-ryco
*
* Copyright (c) 2020-2023 Ryan Coe <bluemrp9@gmail.com>
*
* The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
******************************************************************************/

function _is_dir(string $mode)
{
    return (strncmp($mode, "004", 3) == 0 ? true : false);
}

function _find_files(array &$dirs, array &$files, array &$reserved, array &$skip, string $path, string $basedir, int $max_depth, int $depth = 0)
{
    // Return on max depth
    if ($depth > $max_depth) {
        fprintf(STDERR, "max recursion depth reached\n");
        return;
    }

    // Trim trailing backslash
    if (str_ends_with($path, "/")) {
        printf("string ends with /\n");
        $path = rtrim($path, "/");
    }

    // Ensure path is not empty
    if (strlen($path) == 0) {
        $path = "/";
    }

    // Check to make sure path is a directory
    if (!is_dir($path)) {
        fprintf(STDERR, "%s is not a directory\n", $path);
        return;
    }

    // Open directory handle
    $dir_handle = @opendir($path);
    if ($dir_handle === false) {
        printf("failed to open directory %s\n", $path);
        return;
    }

    // Add directory to array
    $_path = $path;
    if (str_starts_with($_path, $basedir)) {
        $_path = substr($_path, strlen($basedir));
    }
    if (strlen($_path) > 0) {
        if (in_array($_path, $skip)) {
            return;
        }
        if (!in_array($_path, $reserved)) {
            $dirs[] = $_path;
        }
    }

    // Read directory on loop
    while (($file = readdir($dir_handle)) !== false) {
        // Skip . and ..
        if ($file === "." || $file === "..") {
            continue;
        }

        $filename = sprintf("%s/%s", $path, $file);
        $stat = @lstat($filename);

        // Check if stat failed
        if ($stat === false) {
            printf("stat of %s failed\n", $filename);
            continue;
        }

        // Get octal representation of mode
        $mode = str_pad(decoct($stat['mode']), 7, "0", STR_PAD_LEFT);

        // Recurse on directories
        if (_is_dir($mode)) {
            _find_files($dirs, $files, $reserved, $skip, $filename, $basedir, $max_depth, $depth+1);
            continue;
        }

        // Add file to array
        $_filename = $filename;
        if (str_starts_with($_filename, $basedir)) {
            $_filename = substr($_filename, strlen($basedir));
        }
        if (strlen($_filename) > 0 && !in_array($_filename, $reserved)) {
            $files[] = array($_filename, $depth);
        }
    }

    // Close directory handle
    closedir($dir_handle);
}

function file_compare($a, $b)
{
    return strcmp($a[0], $b[0]);
}

function dir_replace(string $str, array &$search, array &$replace) : string
{
    if (count($search) == 0 || count($replace) == 0 || count($search) != count($replace)) {
        return $str;
    }
    for ($i = 0; $i < count($search); $i++) {
        if (str_starts_with($str, $search[$i])) {
            $str = $replace[$i].substr($str, strlen($search[$i]));
        }
    }
    return $str;
}

function name_replace($str, array &$search, array &$replace) : string
{
    if (count($search) == 0 || count($replace) == 0 || count($search) != count($replace)) {
        return $str;
    }
    for ($i = 0; $i < count($search); $i++) {
        $str = str_replace($search[$i], $replace[$i], $str);
    }
    return $str;
}

function find_files(array &$dirs, array &$files, array &$reserved, array &$skip, array &$search, array &$replace, string $path)
{
    // Trim trainling backslash
    $path = rtrim($path, "/");

    // Ensure path is not empty
    if (strlen($path) == 0) {
        $path = "/";
    }

    // Check that path exists
    if (!is_dir($path)) {
        echo $path." does not exist or is not a regular file\n";
        exit(1);
    }

    $path = realpath($path);
    $max_depth = 100;
    fprintf(STDERR, "scanning %s\n", $path);
    _find_files($dirs, $files, $reserved, $skip, $path, $path, $max_depth);
    sort($dirs);
    usort($files, "file_compare");
}

$max_depth = 100;
$dirs = array();
$files = array();
$reserved = array(
    "/dev",
    "/etc",
    "/etc/logrotate.d",
    "/home",
    "/media",
    "/mnt",
    "/opt",
    "/proc",
    "/root",
    "/run",
    "/sys",
    "/tmp",
    "/usr",
    "/usr/bin",
    "/usr/include",
    "/usr/lib32",
    "/usr/libexec",
    "/usr/lib",
    "/usr/lib/pkgconfig",
    "/usr/sbin",
    "/usr/share",
    "/usr/share/aclocal",
    "/var",
    "/var/cache",
    "/var/lib",
    "/var/lock",
    "/var/log",
    "/var/run",
    "/var/spool",
    "/var/tmp",
);
$skip = array(
    "/usr/lib/.build-id",
    "/usr/share/licenses",
);
$search = array(
    "/usr/lib/pkgconfig",
    "/usr/lib/firmware",
    "/usr/lib/systemd/system/",
    "/usr/lib/systemd/user/",
    "/usr/lib/tmpfiles.d",
    "/usr/libexec",
    "/usr/lib32",
    "/usr/lib",
    "/usr/include",
    "/usr/sbin",
    "/usr/bin",
    "/usr/share/man",
    "/usr/share",
    "/var",
    "/etc",
);
$replace = array(
    "%{_pkgconfdir}",
    "%{_firmwaredir}",
    "%{_unitdir}/",
    "%{_userunitdir}/",
    "%{_tmpfilesddir}",
    "%{_libexecdir}",
    "%{_libdir32}",
    "%{_libdir}",
    "%{_includedir}",
    "%{_sbindir}",
    "%{_bindir}",
    "%{_mandir}",
    "%{_datarootdir}",
    "%{_localstatedir}",
    "%{_sysconfdir}",
);
$s2 = array(
    "aarch64-lfsryco-linux-gnu",
    "armv7l-lfsryco-linux-gnueabihf",
    "x86_64-lfsryco-linux-gnu",
);
$r2 = array(
    "%{_build}",
    "%{_build}",
    "%{_build}",
);
$dirs_only = false;

// parse command line
$buildroot = "";
for ($ix = 1; $ix < $argc; $ix++) {
    if ($ix == 1) {
        $buildroot = $argv[$ix];
    } else {
        if ($argv[$ix] === "--dirs") {
            $dirs_only = true;
        }
        if (($argv[$ix] === "--depth" || $argv[$ix] === "--maxdepth") && isset($argv[$ix+1])) {
            $max_depth = intval($argv[$ix+1]);
            $ix += 1;
        }
        if ($argv[$ix] === "--pkgver" && isset($argv[$ix+1])) {
            $s2[] = $argv[$ix+1];
            $r2[] = "%{pkg_ver}";
            $ix += 1;
        }
        if ($argv[$ix] === "--python" && isset($argv[$ix+1])) {
            $a = explode(".", $argv[$ix+1], 2);
            if (isset($a[0]) && isset($a[1])) {
                $s2[] = $a[0].".".$a[1];
                $r2[] = "%{py_abi_maj}.%{py_abi_min}";
                $s2[] = $a[0].$a[1];
                $r2[] = "%{py_abi_maj}%{py_abi_min}";
            }
            unset($a);
            $ix += 1;
        }
        if ($argv[$ix] === "--perl" && isset($argv[$ix+1])) {
            $a = explode(".", $argv[$ix+1], 2);
            if (isset($a[0]) && isset($a[1])) {
                $s2[] = "perl".$a[0];
                $r2[] = "perl%{perl_abi_maj}";
                $s2[] = $a[0].".".$a[1];
                $r2[] = "%{perl_abi_ver}";
            }
            unset($a);
            $ix += 1;
        }
    }
}
unset($ix);
if (strlen($buildroot) == 0) {
    printf("usage: %s directory\n", $argv[0]);
    exit(1);
}
if ($max_depth <= 0) {
    $max_depth = 100;
}

find_files($dirs, $files, $reserved, $skip, $search, $replace, $buildroot);
if (!$dirs_only) {
    $_last = "";
    foreach ($files as $file) {
        $_filename = $file[0];
        $a = explode("/", $_filename);
        $c = count($a)-2;
        if ($c >= $max_depth) {
            $_filename = "";
            for ($i = 1; $i <= $max_depth; $i++) {
                $_filename .= "/".$a[$i];
            }
            if (strlen($_last) > 0 && $_last === $_filename) {
                continue;
            }
            $_last = $_filename;
            $_filename = name_replace(dir_replace($_filename, $search, $replace), $s2, $r2);
            if (str_contains($_filename, " ")) {
                $_filename = "\"".$_filename."\"";
            }
            echo $_filename."\n";
            continue;
        }
        $_filename = name_replace(dir_replace($_filename, $search, $replace), $s2, $r2);
        if (str_contains($_filename, " ")) {
            $_filename = "\"".$_filename."\"";
        }
        echo $_filename."\n";
    }
}
foreach ($dirs as $dir) {
    $_dir = name_replace(dir_replace($dir, $search, $replace), $s2, $r2);
    if (str_contains($_dir, " ")) {
        $_dir = "\"".$_dir."\"";
    }
    echo "%dir ".$_dir."\n";
}
