/*
 * wnix, a Unix-like operating system for WebAssembly applications.
 * Copyright (C) 2025  Xavier Del Campo Romero
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

void _start(void)
{
    /* clang mangles main if argc/argv are present:
     * https://reviews.llvm.org/D127888 */
    int __main_argc_argv(int, char *[]);
    int __wnix_argc(void) __attribute__((
        __import_module__("wnix"),
        __import_name__("argc")
    ));
    _Noreturn void __wnix_exit(int) __attribute__((
        __import_module__("wnix"),
        __import_name__("exit")
    ));

    if (!(__stdin = fopen("/dev/stdin", "rb"))
        || !(__stdout = fopen("/dev/stdout", "wb"))
        || !(__stderr = fopen("/dev/stderr", "wb")))
        __wnix_exit(EXIT_FAILURE);

    const int argc = __wnix_argc();
    char **argv = malloc((argc + 1) * sizeof *argv);

    if (!argv)
        __wnix_exit(EXIT_FAILURE);

    for (int i = 0; i < argc; i++)
    {
        size_t __wnix_arglen(int) __attribute__((
            __import_module__("wnix"),
            __import_name__("arglen")
        ));

        int __wnix_argcopy(int, char *, int *) __attribute__((
            __import_module__("wnix"),
            __import_name__("argcopy")
        ));

        char *const arg = malloc(__wnix_arglen(i));

        if (!arg)
            __wnix_exit(EXIT_FAILURE);

        __wnix_argcopy(i, arg, &errno);
        argv[i] = arg;
    }

    argv[argc] = NULL;
    __wnix_exit(__main_argc_argv(argc, argv));
}
