 /*
  * UAE - The Un*x Amiga Emulator
  * 
  * Main program 
  * 
  * (c) 1995 Bernd Schmidt, Ed Hanway
  */

#include "sysconfig.h"
#include "sysdeps.h"
#include <assert.h>

#include "config.h"
#include "options.h"
#include "memory.h"
#include "custom.h"
#include "serial.h"
#include "newcpu.h"
#include "disk.h"
#include "debug.h"
#include "xwin.h"
#include "os.h"
#include "keybuf.h"
#include "gui.h"
#include "zfile.h"
#include "autoconf.h"
#include "compiler.h"

int version = 100*UAEMAJOR + 10*UAEMINOR + UAEURSAMINOR;
int framerate = 1;
int use_debugger = 0;
int illegal_mem = 0;
int use_gfxlib = 0;
int no_xhair = 0;
int use_lores = 0;
int use_serial = 0;
int automount_uaedev = 1;
int produce_sound = 0;
int fake_joystick = 0;
KbdLang keyboard_lang = KBD_LANG_US;
int screen_res = 4;
int correct_aspect = 0;
int color_mode = 0;
int sound_desired_bits = 16;
int sound_desired_freq = 44100;
int sound_desired_bsiz = 8192;
int allow_save = 0;
int no_gui = 0;

long hardfile_size = 0;

ULONG fastmem_size = 0x000000;
ULONG chipmem_size = 0x200000;
ULONG bogomem_size = 0x000000;
char df0[256]="df0.adf", df1[256]="df1.adf", df2[256]="df2.adf", df3[256]="df3.adf";
char romfile[256] = "kick.rom";
#ifndef __DOS__
char prtname[256] = "lpr ";
#else
char prtname[256] = "PRN";
#endif

char optionsfile[256];

/* If you want to pipe Printer output to a file, put something like
 * "cat >>printerfile.tmp" above.
 * The printer support was only tested with the driver "PostScript" on
 * Amiga side, using apsfilter for linux to print ps-data.
 *
 * Note for the DOS-Port: Maybe it's only neccesary to use a
 * -p LPT1: or -p PRN: to print in a DOSBOX. I don't know,
 * I do not use DOS... (please try) -=SR=-
 */

/* People must provide their own name for this */
char sername[256] = "";

/* And again: Serial lines work under Linux. I don't know
 * how this behaves in other OSes. This is work for the porting
 * people      -=SR=-
 */

void usage(void)
{
    printf("UAE - The Un*x Amiga emulator\n");
    printf("Summary of command-line options:\n");
    printf("  -h                       : Print help\n");
    printf("  -m VOLNAME:mount_point   : mount file system at <mount point> as AmigaDOS\n"
	   "                             volume VOLNAME:\n");
    printf("  -M VOLNAME:mount_point   : like -m, but mount read-only\n");
    printf("  -s n                     : Emulate n*256 KB slow memory at 0xC00000\n");
    printf("  -c n                     : Emulate n*512 KB chip memory at 0x000000\n");
    printf("  -F n                     : Emulate n MB fast memory at 0x200000\n");
    printf("  -a                       : Add no expansion devices (disables fastmem and\n"
	   "                             harddisk support.\n");
    printf("  -J                       : Fake joystick emulation with the numeric pad.\n");
    printf("  -f n                     : Set the frame rate to 1/n\n");
    printf("  -D                       : Start up the built-in debugger\n");
    printf("  -i                       : Print illegal memory accesses\n");
    printf("  -o                       : Allow options to be saved\n");
    printf("  -G                       : Disable user interface\n");
    printf("  -[0123] file             : Use file instead of df[0123].adf as disk image.e\n");
    printf("  -r file                  : Use file as ROM image instead of kick.rom\n");
    target_specific_usage();
/*    printf("  -g                       : Turn on gfx-lib replacement (EXPERIMENTAL).\n");*/
    printf("  -d mode                  : Select resolution with the mode parameter.\n");
    printf("  -H mode                  : Set the number of colors with the mode parameter.\n");
    printf("  -C                       : Use correct aspect display mode.\n");
    printf("\n");
    printf("Valid resolutions: 0 (320x200); 1 (320x240); 2 (320x400); 3 (640x480);\n"
	   "                   4 (800x600)\n"
	   "Valid color modes: 0 (256 colors); 1 (32768 colors); 2 (65536 colors)\n"
	   "                   3 (256 colors, with dithering for better results)\n"
	   "                   4 (16 colors, dithered); 5 (16 million colors)\n"
	   "UAE may choose to ignore the color mode/resolution setting.\n");
}

#ifdef __unix

void parse_cmdline(int argc, char **argv)
{
    int c;
    extern char *optarg;

    while(((c = getopt(argc, argv, "l:Dif:gd:hxF:as:c:S:Jm:M:0:1:2:3:r:H:p:CI:b:R:B:oG")) != EOF))
    switch(c) {
     case 'h': usage();	exit(0);

     case '0': strncpy(df0, optarg, 255); df0[255] = 0;	break;
     case '1': strncpy(df1, optarg, 255); df1[255] = 0; break;
     case '2': strncpy(df2, optarg, 255); df2[255] = 0; break;
     case '3': strncpy(df3, optarg, 255); df3[255] = 0; break;
     case 'r': strncpy(romfile, optarg, 255); romfile[255] = 0; break;
     case 'p': strncpy(prtname, optarg, 255); prtname[255] = 0; break;
     case 'I': strncpy(sername, optarg, 255); sername[255] = 0; use_serial = 1; break;
     case 'm':
     case 'M':
	{
	    char buf[256];
	    char *s2;
	    int readonly = (c == 'M');

	    strncpy(buf, optarg, 255); buf[255] = 0;
	    s2 = strchr(buf, ':');
	    if(s2) {
		*s2++ = '\0';
#ifdef __DOS__
		{
		    char *tmp;

		    while ((tmp = strchr(s2, '\\')))
			*tmp = '/';
		}
#endif
		add_filesys_unit(buf, s2, readonly);
	    } else {
		fprintf(stderr, "Usage: [-m | -M] VOLNAME:/mount_point\n");
	    }
	}
	break;
	
     case 'S': produce_sound = atoi(optarg); break;
     case 'f': framerate = atoi(optarg); break;
     case 'x': no_xhair = 1; break;
     case 'D': use_debugger = 1; break;
     case 'i': illegal_mem = 1; break;
     case 'J': fake_joystick = 1; break;
     case 'a': automount_uaedev = 0; break;
     case 'g': use_gfxlib = 1; break;
     case 'C': correct_aspect = 1; break;
     case 'o': allow_save = 1; break;
     case 'G': no_gui = 1; break;

     case 'F':
	fastmem_size = atoi(optarg) * 0x100000;
	if (fastmem_size != 0x100000 && fastmem_size != 0x200000 
	    && fastmem_size != 0x400000 && fastmem_size != 0x800000) 
	{
	    fastmem_size = 0;
	    fprintf(stderr, "Unsupported fastmem size!\n");
	}	
	break;

     case 's':
	bogomem_size = atoi(optarg) * 0x40000;
	if (bogomem_size != 0x80000 && bogomem_size != 0x100000
	    /* Braino && bogomem_size != 0x180000 && bogomem_size != 0x1C0000*/)
	{
	    bogomem_size = 0;
	    fprintf(stderr, "Unsupported bogomem size!\n");
	}
	break;

     case 'c':
	chipmem_size = atoi(optarg) * 0x80000;
	if (chipmem_size != 0x80000 && chipmem_size != 0x100000
	    && chipmem_size != 0x200000)
	{
	    chipmem_size = 0x200000;
	    fprintf(stderr, "Unsupported chipmem size!\n");
	}
	
	break;

     case 'l':
	if (0 == strcasecmp(optarg, "de"))
	    keyboard_lang = KBD_LANG_DE;
	else if (0 == strcasecmp(optarg, "us"))
	    keyboard_lang = KBD_LANG_US;
	else if (0 == strcasecmp(optarg, "se"))
	    keyboard_lang = KBD_LANG_SE;
	else if (0 == strcasecmp(optarg, "fr"))
	    keyboard_lang = KBD_LANG_FR;
	else if (0 == strcasecmp(optarg, "it"))
	    keyboard_lang = KBD_LANG_IT;
	break;

     case 'd':
	screen_res = atoi(optarg);
	if (screen_res < 0 || screen_res > MAX_SCREEN_MODES) {
	    fprintf(stderr, "Bad video mode selected. Using default.\n");
	    screen_res = 3;
	}
	break;

     case 'H':
	color_mode = atoi(optarg);
	if (color_mode < 0 || color_mode > MAX_COLOR_MODES) {
	    fprintf(stderr, "Bad color mode selected. Using default.\n");
	    color_mode = 0;
	}
	break;

     case 'b': sound_desired_bits = atoi(optarg); break;
     case 'B': sound_desired_bsiz = atoi(optarg); break;
     case 'R': sound_desired_freq = atoi(optarg); break;
    }
}
#endif

#ifndef __bebox__  /* BeOS needs its own startup code */

static void parse_cmdline_and_init_file(int argc, char **argv)
{
    FILE *f;
    char *home;
    char *buffer,*tmpbuf, *token;
    char smallbuf[256];
    int bufsiz, result;
    int n_args;
    char **new_argv;
    int new_argc;

    strcpy(optionsfile,"");

#if !defined(__DOS__) && !defined(__mac__)
    home = getenv("HOME");
    if (home != NULL && strlen(home) < 240)
    {
	strcpy(optionsfile, home);
	strcat(optionsfile, "/");
    }
#endif

#ifndef __DOS__
    strcat(optionsfile, ".uaerc");
#else
    strcat(optionsfile, "uae.rc");
#endif

    f = fopen(optionsfile,"r");
    if (f == NULL) {
	parse_cmdline(argc, argv);
	return;
    }
    fseek(f, 0, SEEK_END);
    bufsiz = ftell(f);
    fseek(f, 0, SEEK_SET);

    buffer = (char *)malloc(bufsiz+1);
    buffer[bufsiz] = 0;
    if (fread(buffer, 1, bufsiz, f) < bufsiz) {
	fprintf(stderr, "Error reading configuration file\n");
	fclose(f);
	parse_cmdline(argc, argv);
	return;
    }
    fclose(f);

#ifdef __DOS__
    {
	char *tmp;

	while ((tmp = strchr(buffer, 0x0d)))
	    *tmp = ' ';
	while ((tmp = strchr(buffer, 0x0a)))
	    *tmp = ' ';
	while (buffer[0] == ' ')
	    strcpy(buffer, buffer+1);
	while ((strlen(buffer) > 0) && (buffer[strlen(buffer) - 1] == ' '))
	    buffer[strlen(buffer) - 1] = '\0';
	while ((tmp = strstr(buffer, "  ")))
	    strcpy(tmp, tmp+1);
    }
#endif

    tmpbuf = my_strdup (buffer);

    n_args = 0;
    if (strtok(tmpbuf, "\n ") != NULL) {
	do {
	    n_args++;
	} while (strtok(NULL, "\n ") != NULL);
    }
    free (tmpbuf);

    new_argv = (char **)malloc ((1 + n_args + argc) * sizeof (char **));
    new_argv[0] = argv[0];
    new_argc = 1;

    token = strtok(buffer, "\n ");
    while (token != NULL) {
	new_argv[new_argc] = my_strdup (token);
	new_argc++;
	token = strtok(NULL, "\n ");
    }
    for (n_args = 1; n_args < argc; n_args++)
	new_argv[new_argc++] = argv[n_args];
    new_argv[new_argc] = NULL;
    parse_cmdline(new_argc, new_argv);
}

static int ARE_YOU_NUTS = 0;

int main(int argc, char **argv)
{
    FILE *hf;

    hf = fopen("hardfile", "rb");
    if (hf == NULL)
         hardfile_size = 0;
    else {
        fseek(hf, 0, SEEK_END);
        hardfile_size = ftell(hf);
        fclose(hf);
    }
    rtarea_init ();
    hardfile_install ();

    parse_cmdline_and_init_file(argc, argv);
    if (!init_sound()) {
	fprintf(stderr, "Sound driver unavailable: Sound output disabled\n");
	produce_sound = 0;
    }

    if (!no_gui && gui_init() < 0) {
	fprintf(stderr, "Failed to initialize the GUI\n");
	/* abort()? Maybe. */
    }
    init_joystick();
    keybuf_init();
    
    expansion_init ();
    memory_init();

    filesys_install();
    execlib_install();
    gfxlib_install();
    emulib_install();

    custom_init();
    serial_init();
    DISK_init();
    init_m68k();
    compiler_init();
    
    /* We ought to know this by now */
    use_lores = screen_res < 3;
    
    if (graphics_init()) {
	m68k_reset();
	
	setup_brkhandler();
	if (use_debugger && debuggable())
	    activate_debugger();
	if (ARE_YOU_NUTS)
	    execlib_sysinit();
	else
	    m68k_go(1);
    
	graphics_leave();
	close_joystick();
    }
    dump_counts();
    serial_exit();
    zfile_exit();
    if (!no_gui)
	gui_exit();
    return 0;
}
#endif /* not __bebox__ */
