/*
 * OpenComal -- a free Comal implementation
 *
 * This file is part of the OpenComal package.
 * (c) Copyright 1992-2024 Jos Visser <josvisser66@gmail.com>
 *
 * The OpenComal package is covered by the GNU General Public
 * License. See doc/LICENSE for more information.
 */

#define EXTERN

#include "pdcglob.h"
#include "pdcenv.h"
#include "pdccmd.h"
#include "pdcprog.h"
#include "pdcsqash.h"

#ifdef MSDOS
#include <io.h>
#else
#include <unistd.h>
#endif

#include <dirent.h>

#define EXIT_WHEN(b, t, f) if (b) { \
	char buf[80]; \
	sprintf(buf, "%s %s at %s:%s", t, f, __FILE__, __LINE__); \
	perror(t); \
	exit(1); \
}

#ifdef TURBOC
unsigned int _stklen = 32768;
#endif

#ifdef MSDOS
PUBLIC int strcasecmp(char *s1, char *s2) {
	int result;

	if (s1 == s2) return 0;

	while ( (result = TOLOWER(*s1) - TOLOWER(*s2++)) == 0 )
		if (*s1++ == '\0') break;
	
	return result;
}
#endif

PRIVATE void save_all(char *input_dir, char *test_dir) {
    struct dirent *de;
    char *dot;
    char buf[256];
    DIR *dir = opendir(input_dir);

    puts("Entering and saving all programs");
    EXIT_WHEN(!dir, "opendir", input_dir);

    while ((de = readdir(dir)) != NULL) {
        dot = strrchr(de->d_name, '.');

        if (dot == NULL || (strcasecmp(dot, ".prl") != 0 && strcasecmp(dot, ".lst") != 0))
            continue;

        sprintf(buf, "%s/%s", input_dir, de->d_name);
        puts(buf);
        do_enter(buf);
        // do_list(NULL, 1, LONG_MAX);

        sprintf(buf, "%s/%s", test_dir, de->d_name);
        dot = strrchr(buf, '.');
        strcpy(dot, ".sq");
        puts(buf);
        sqash_2file(buf);
        prog_new();
        mem_freepool(PARSE_POOL);
    }

    EXIT_WHEN(closedir(dir) < 0, "closedir", input_dir);
}

PRIVATE void remove_test_dir(char *test_dir) {
    struct dirent *de;
    char buf[256];
    DIR *dir = opendir(test_dir);

    EXIT_WHEN(!dir, test_dir, "opendir")

    while ((de = readdir(dir)) != NULL) {
        if (de->d_name[0] == '.')
            continue;

        sprintf(buf, "%s/%s", test_dir, de->d_name);
        EXIT_WHEN(unlink(buf) < 0, buf, "unlink");
    }

    EXIT_WHEN(closedir(dir) < 0, test_dir, "closedir");
#ifndef MSDOS
    EXIT_WHEN(chdir("..") < 0, "..", "chdir");
#endif
    EXIT_WHEN(rmdir(test_dir) < 0, test_dir, "rmdir");
}

PRIVATE int run_test(char *filename) {
    int restart_code;
    int fail = 0;

    printf("Running %s\n", filename);
    prog_load(filename);
    // do_list(NULL, 1, LONG_MAX);

    restart_code = setjmp(RESTART);

    if (restart_code == 0 || restart_code == RUN)
        prog_run();
    else if (restart_code != PROG_END) {
        fprintf(stderr, "Unexpected restart code: %d\n", restart_code);
        fail = 1;
    }

    prog_new();
    mem_freepool(PARSE_POOL);

    return fail;
}

PRIVATE int run_all(char *test_dir) {
    DIR *dir = opendir(test_dir);
    struct dirent *de;
    char *dot;
    char buf[128];
    int fail = 0;

    puts("Running all test programs");
    EXIT_WHEN(!dir, test_dir, "opendir");

    while ((de = readdir(dir)) != NULL) {
        dot = strrchr(de->d_name, '.');

        if (dot == NULL || strcmp(dot, ".sq") != 0)
            continue;

        sprintf(buf, "%s/%s", test_dir, de->d_name);
        fail |= run_test(buf);
    }

    EXIT_WHEN(closedir(dir) < 0, test_dir, "closedir");

    return fail;
}

#ifdef MSDOS

PRIVATE char *mkdtemp(char *ignored_template) {
    static char tempdir[L_tmpnam];

    if (tmpnam(tempdir) < 0) {
        perror("tmpnam");
        exit(1);
    }

    EXIT_WHEN(mkdir(tempdir) < 0, tempdir, "mkdir");

    return tempdir;
}

#endif

PUBLIC int main(int argc, char *argv[]) {
    int fail = 0;
    int i;
    char test_dir_template[] = "/tmp/tmpdir.XXXXXXXX";
    char *test_dir = mkdtemp(test_dir_template);
    char *input_dir;

    if (argc <= 1) {
        fputs("Please provide directory with test programs as an argument\n", stderr);
        exit(1);
    }

    input_dir = argv[1];
    EXIT_WHEN(!test_dir, "", "mkdtemp");
    sys_init();
    mem_init();
    copyright = "(c) Copyright 1992-2024  Jos Visser <josvisser66@gmail.com>";
    curenv = env_new("tests");
    comal_testing = 1;
    /*
        curenv->trace = 1;
        comal_debug = 1;
    */

    save_all(input_dir, test_dir);

    if (argc > 2) {
        for (i = 2; i < argc; i++)
            fail |= run_test(argv[i]);

        remove_test_dir(test_dir);
        return fail;
    }

    EXIT_WHEN(chdir(test_dir) < 0, test_dir, "chdir");
    fail = run_all(".");
    remove_test_dir(test_dir);

    return fail;
}