/* lmin - small embeddable LISP
**
** Copyright (C) 2026 by Jef Poskanzer <jef@mail.acme.com>.
** All rights reserved.
**
** You may use this software however you like as long as you keep my
** name on it and don't sue me.
**
** For commentary on this license please see http://acme.com/license.html
*/

#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sysexits.h>

#include "version.h"
#include "liblmin.h"
#include "leakfinder.h"

#define DOTFILE ".lmin_init"


/* Read Evaluate Print Loop. */

static int repl( const char* filename, FILE* fp )
    {
    int line, lines;
    lmin_cellidx c, r;

    if ( isatty( fileno( fp ) ) )
	printf( "%s %s\n", LMIN_PROGRAM, LMIN_VERSION );

    line = 0;
    for (;;)
	{
	c = lmin_read( fp, &lines );
	line += lines;
	if ( c == lmin_err_eof )
	    break;
	else if ( lmin_errex_is( c ) )
	    lmin_show_errex( fp, filename, line, c );
	else
	    {
	    r = lmin_eval( c, lmin_nil );
	    if ( lmin_errex_is( r ) )
		lmin_show_errex( fp, filename, line, r );
	    else if ( isatty( fileno( fp ) ) )
		lmin_write_line( r, stdout );
	    }
	lmin_gc();
	}

    if ( isatty( fileno( fp ) ) )
	printf( "\n" );
    return EX_OK;
    }


/* Main program. */

int main( int argc, char** argv )
    {
    char dotfile[100];
    FILE* fp;
    int ex = EX_OK;

    srandom( (unsigned int) time( 0 ) ^ (unsigned int) getpid() );
    lmin_init();

    snprintf( dotfile, sizeof(dotfile), "%s/%s", getenv( "HOME" ), DOTFILE );
    fp = fopen( dotfile, "r" );
    if ( fp != (FILE*) 0 )
	{
	ex = repl( dotfile, fp );
	fclose( fp );
	if ( ex != EX_OK )
	    exit( ex );
	}

    if ( argc == 1 )
	ex = repl( "stdin", stdin );
    else
	{
	int argn;
	for ( argn = 1; argn < argc; ++argn )
	    {
	    char* arg = argv[argn];
	    if ( strcmp( arg, "-" ) == 0 )
		ex = repl( "stdin", stdin );
	    else
		{
		fp = fopen( arg, "r" );
		if ( fp == (FILE*) 0 )
		    {
		    perror( arg );
		    ex = EX_NOINPUT;
		    break;
		    }
		ex = repl( arg, fp );
		fclose( fp );
		if ( ex != EX_OK )
		    break;
		}
	    }
	}

    lmin_term();
    exit( ex );
    }
