/* Copyright 1988 - 2005 by Abacus Research and * Development, Inc. All rights reserved. */ #if !defined (OMIT_RCSID_STRINGS) char ROMlib_rcsid_main[] = "$Id: main.c 127 2006-04-04 00:18:10Z ctm $"; #endif /* * Errors should be handled more cleanly. */ #include "rsys/common.h" #include "QuickDraw.h" #include "CQuickDraw.h" #include "SegmentLdr.h" #include "rsys/notmac.h" #include "MemoryMgr.h" #include "FontMgr.h" #include "SysErr.h" #include "OSUtil.h" #include "ResourceMgr.h" #include "TextEdit.h" #include "FileMgr.h" #include "DialogMgr.h" #include "StdFilePkg.h" #include "MenuMgr.h" #include "ScrapMgr.h" #include "SoundMgr.h" #include "ScriptMgr.h" #include "SANE.h" #include "DeskMgr.h" #include "DeviceMgr.h" #include "ToolboxUtil.h" #include "Gestalt.h" #include "AppleTalk.h" #include "AppleEvents.h" #include "rsys/cquick.h" #include "rsys/tesave.h" #include "rsys/mman.h" #include "rsys/menu.h" #include "rsys/next.h" #include "rsys/setuid.h" #include "rsys/pstuff.h" #include "rsys/prefs.h" #include "rsys/misc.h" #include "rsys/flags.h" #include "rsys/option.h" #include "rsys/host.h" #include "rsys/syncint.h" #include "rsys/vdriver.h" #include "rsys/vbl.h" #include "rsys/time.h" #include "rsys/segment.h" #include "rsys/keycode.h" #include "rsys/version.h" #include "rsys/m68kint.h" #include "rsys/misc.h" #include "rsys/blockinterrupts.h" #include "rsys/rgbutil.h" #include "rsys/refresh.h" #include "rsys/executor.h" #include "rsys/wind.h" #include "rsys/osevent.h" #include "rsys/image.h" #include "rsys/dump.h" #include "rsys/file.h" #include "rsys/ctl.h" #include "rsys/parseopt.h" #include "rsys/print.h" #include "rsys/memsize.h" #include "rsys/splash.h" #include "rsys/stdfile.h" #include "rsys/autorefresh.h" #include "rsys/sounddriver.h" #include "rsys/desperate.h" #include "rsys/dcache.h" #include "rsys/system_error.h" #include "rsys/filedouble.h" #include "rsys/os.h" #include "rsys/arch.h" #include "rsys/checkpoint.h" #include "rsys/cleanup.h" #include "rsys/custom.h" #include "rsys/gestalt.h" #include "rsys/keyboards.h" #include "rsys/launch.h" #include "rsys/text.h" #include "rsys/appearance.h" #include "rsys/hfs_plus.h" #include "rsys/check_structs.h" #include "paramline.h" #if defined (MSDOS) #include "aspi.h" #include "dosdisk.h" #include "dosmem.h" #include "dpmilock.h" #include "vga.h" #include "openmany.h" #include "dosserial.h" #include #endif /* MSDOS */ #include #if !defined (MSDOS) && !defined(CYGWIN32) #include #endif #if defined (MMAP_LOW_GLOBALS) #include #include #endif /* MMAP_LOW_GLOBALS */ #if defined (CYGWIN32) #include "winfs.h" #include "dosdisk.h" #include "win_except.h" #include "win_queue.h" #include "win_clip.h" #include "win_print.h" #endif #if defined(X) #include "x.h" #endif BOOLEAN force_big_offset = CONFIG_OFFSET_P; #if defined (NEXTSTEP) #define main oldmain char *ROMlib_xfervmaddr; LONGINT ROMlib_xfervmsize = 0; #endif /* NEXTSTEP */ PUBLIC int ROMlib_noclock = 0; #if defined (NOMOUSE_COMMAND_LINE_OPTION) PUBLIC int ROMlib_no_mouse = 1; #endif /* optional resolution other than 72dpix72dpi for printing */ PUBLIC INTEGER ROMlib_optional_res_x, ROMlib_optional_res_y; /* A string approximating the original command line. */ PUBLIC const char *ROMlib_command_line; /* Set to TRUE if there was any error parsing arguments. */ PRIVATE boolean_t bad_arg_p = FALSE; /* Set to FALSE when we know that the command line switches will result in no graphics. */ PRIVATE boolean_t graphics_p = TRUE; /* for a description of flags declared here, see */ /* Initial screen size. This can be changed dynamically. */ INTEGER flag_width = 0, flag_height = 0; /* 0 means "use default". */ /* Initial bits per pixel. The screen depth can be changed dynamically. */ int flag_bpp = 0; /* 0 means "use default". */ INTEGER ROMlib_shadow_screen_p = TRUE; INTEGER ROMlib_no_windows; #if defined (MSDOS) || defined (CYGWIN32) int ROMlib_drive_check = 0; #endif #if defined(SYN68K) static boolean_t use_native_code_p = TRUE; #endif /* the system version that executor is currently reporting to applications, set through the `-system' options. contains the version number in the form `0xABC' which corresponds to system version A.B.C */ uint32 system_version = 0x700; /* keep this in sync with Browser's .ecf file */ static option_t common_opts[] = { { "sticky", "sticky menus", opt_no_arg, NULL }, { "pceditkeys", "have Delete key delete one character forward", opt_no_arg, NULL }, { "nobrowser", "don't run Browser", opt_no_arg, NULL }, { "bpp", "default screen depth", opt_sep, NULL }, { "size", "default screen size", opt_sep, NULL }, { "debug", ("enable certain debugging output and consistency checks. This " "is primarily used by ARDI developers, but we are making it " "available during the pre-beta period to expert users. The next " "argument must be a list of comma-separated words describing which " "debug options you want enabled. You can abbreviate the debug " "options as long as the abbreviation is unambiguous. Here is a " "list of the options (some of which will may do nothing): " "\"all\" enables all debugging options, " "\"fslog\" enables filesystem call logging, " "\"memcheck\" enables heap consistency checking (slow!), " "\"textcheck\" enables text record consistency checking (slow!), " "\"trace\" enables miscellaneous trace information, " "\"sound\" enables miscellaneous sound logging information, " "\"trapfailure\" enables warnings when traps return error codes, " "\"errno\" enables some C library-related warnings, " "\"unexpected\" enables warnings for unexpected events, " "\"unimplemented\" enables warnings for unimplemented traps. " "Example: \"executor -debug unimp,trace\""), opt_sep, NULL }, { "nodiskcache", "disable internal disk cache.", opt_no_arg, NULL }, { "nosound", "disable any sound hardware", opt_no_arg, NULL }, { "info", "print information about your system", opt_no_arg, NULL }, #if defined (SUPPORT_LOG_ERR_TO_RAM) { "ramlog", "log debugging information to RAM; alt-shift-7 dumps the " "accrued error log out via the normal mechanism.", opt_no_arg, NULL }, #endif #if defined (MSDOS) { "oldtimer", "use old-style 18.2 Hz timer, instead of the newer 1024 Hz " "timer. This will result in less accurate timer emulation, " "but may work around problems with certain BIOSes.", opt_no_arg, NULL }, { "vga", "use old-style VGA graphics modes only, and don't use SuperVGA. " "This will limit you to a slow 640x480 with 16 colors, but may let " "you run Executor even when Executor has problems with your " "video driver.", opt_no_arg, NULL }, { "nofilescheck", "bypass a startup check that attempts to determine if your FILES= " "parameter is large enough.", opt_no_arg, NULL }, { "videospeedup", "if you have a linear frame buffer (which requires a VBE 2.0 video " "driver like SciTech Display Doctor) this can make graphics much faster " "for games that bypass QuickDraw and therefore require \"refresh\" mode." " This isn't needed under plain DOS if you are using cwsdpmi.exe. " "The drawback is that enabling this feature removes some memory " "protection from your system and makes it possible for Executor " "to crash your computer or destroy data. On some systems this " "switch will cause Executor to crash right away; you can't use it " "on such systems, and there's nothing that can be done about it. " "Use at your own risk!", opt_no_arg, NULL }, { "nosync", "Allow disk data structures to stay in memory until Executor quits. " "This will dramatically speed up Executor's creation and deletion of " "many small files, but if Executor crashes the data in memory won't " "be written to disk and HFV corruption could result. " "Use at your own risk!", opt_no_arg, NULL }, { "skipaspi", "totally bypass ASPI drivers", opt_no_arg, NULL }, #endif /* MSDOS */ #if defined (MSDOS) || defined (CYGWIN32) { "macdrives", "drive letters that represent Mac formatted media", opt_sep, NULL }, { "dosdrives", "drive letters that represent DOS formatted media", opt_sep, NULL }, { "skipdrives", "drive letters that represent drives to avoid", opt_sep, NULL }, #endif #if defined (LINUX) { "nodrivesearch", "Do not look for a floppy drive, CD-ROM drive or any other drive " "except as specified by the MacVolumes environment variable", opt_no_arg, NULL }, #endif /* LINUX */ { "keyboards", "list available keyboard mappings", opt_no_arg, NULL }, { "keyboard", "choose a specific keyboard map", opt_sep, NULL }, { "print", "tell program to print file; not useful unless you also " "specify a program to run and one or more documents to print.", opt_no_arg, NULL }, #if defined (NEXT) || defined (LINUX) { "nodotfiles", "do not display filenames that begin with dot", opt_no_arg, NULL }, #endif #if 0 { "noclock", "disable timer", opt_no_arg, NULL }, #endif #if defined (NOMOUSE_COMMAND_LINE_OPTION) /* Hack Dr. Chung wanted */ { "nomouse", "ignore missing mouse", opt_no_arg, NULL }, #endif { "noautorefresh", "turns off automatic detection of programs that bypass QuickDraw.", opt_no_arg, NULL }, { "refresh", "handle programs that bypass QuickDraw, at a performance penalty. " "Follow -refresh with an number indicating how many 60ths of a second " "to wait between each screen refresh, e.g. \"executor -refresh 10\".", opt_optional, "10", }, { "help", "print this help message", opt_no_arg, NULL, }, { "version", "print the Executor version", opt_no_arg, NULL, }, #if defined (MALLOC_MAC_MEMORY) { "memory", "specify the total memory you want reserved for use by the programs " "run under Executor and for Executor's internal system software. " "For example, \"executor -memory 5.5M\" would " "make five and a half megabytes available to the virtual machine. " "Executor will require extra memory above and beyond this amount " "for other uses.", opt_sep, NULL, }, { "applzone", "specify the memory to allocate for the application being run, " "e.g. \"executor -applzone 4M\" would make four megabytes " "of RAM available to the application. \"applzone\" stands for " "\"application zone\".", opt_sep, NULL, }, { "stack", "like -applzone, but specifies the amount of stack memory to allocate.", opt_sep, NULL, }, { "syszone", "like -applzone, but specifies the amount of memory to make " "available to Executor's internal system software.", opt_sep, NULL, }, #if defined (MM_MANY_APPLZONES) { "napplzones", "debugging flag, specifies the number of applzones to use", opt_sep, NULL }, #endif /* MM_MANY_APPLZONES */ #endif /* MALLOC_MAC_MEMORY */ { "system", "specify the system version that executor reports to applications", opt_sep, NULL }, #if defined (SYN68K) { "notnative", "don't use native code in syn68k", opt_no_arg, NULL }, #endif #if defined (MSDOS) || defined(VDRIVER_SVGALIB) || defined (CYGWIN32) { "logerr", "log diagnostic output to error log file", opt_no_arg, NULL }, #endif { "grayscale", "\ specify that executor should run in grayscale mode even if it is \ capable of color.", opt_no_arg, NULL }, { "netatalk", "use netatalk naming conventions for AppleDouble files", opt_no_arg, NULL }, { "afpd", "use afpd conventions for AppleDouble files (implies -netatalk)", opt_no_arg, NULL }, #if defined (MSDOS) { "modemport", "which PC serial port (1, 2, 3 or 4) should be used when" " a Macintosh application access the modem port", opt_sep, NULL, }, { "printerport", "which PC serial port (1, 2, 3 or 4) should be used when" " a Macintosh application *directly* accesses the printer port. This" " option does not affect printing. It only affects communications type " " programs that do their own serial port management.", opt_sep, NULL, }, #endif #if CONFIG_OFFSET_P == 0 { "offset", "offset Mac memory (i.e. simulate Win32)", opt_no_arg, NULL }, #endif { "cities", "Don't use Helvetica for Geneva, Courier for Monaco and Times " "for New York when generating PostScript", opt_no_arg, NULL }, #if defined (CYGWIN32) { "die", "allow Executor to die instead of catching trap", opt_no_arg, NULL }, { "noautoevents", "disable timer driven event checking", opt_no_arg, NULL }, #endif #if defined (MSDOS) || defined (CYGWIN32) { "nocheckpoint", "disable \"failure.txt\" checkpointing", opt_no_arg, NULL }, #endif { "prvers", "specify the printer version that executor reports to applications", opt_sep, NULL }, { "prres", "specify an additional resolution available for printing, e.g. " "\"executor -prres 600x600\" will make 600dpi resolution available " "in addition to the standard 72dpi. Not all apps will be able to use " "this additional resolution.", opt_sep, NULL }, #if defined (SDL) { "fullscreen", "try to run in full-screen mode", opt_no_arg, NULL }, { "hwsurface", "UNSUPPORTED", opt_no_arg, NULL }, #if defined (CYGWIN) { "sdlaudio", "specify the audio driver to attempt to use first, e.g. " "\"executor -sdlaudio waveout\" will tell Executor to use the old " "windows sound drivers and not use DirectSound.", opt_sep, NULL, }, #else { "sdlaudio", "specify the audio driver to attempt to use first, e.g. " "\"executor -sdlaudio esd\" will tell Executor to use esound, " "the Enlightened Sound Daemon instead of /dev/dsp.", opt_sep, NULL, }, #endif #endif #if defined (CYGWIN32) && defined (SDL) { "clipleak", "UNSUPPORTED (ignored)", opt_no_arg, NULL }, #endif #if defined(X) || defined (SDL) { "scancodes", "different form of key mapping (may be useful in " "conjunction with -keyboard)", opt_no_arg, NULL }, #endif { "desperate", /* Handled specially; here for documentation purposes only. */ "run in \"desperation mode\". This will cause Executor " "to use as few system features as possible, which is handy for " "troubleshooting if Executor is having serious problems with " "your system.", opt_no_arg, NULL }, #if defined (powerpc) || defined (__ppc__) { "ppc", "try to execute the PPC native code if possible (UNSUPPORTED)", opt_no_arg, NULL }, #endif #if defined (CYGWIN32) { "realmodecd", "try to use real-mode cd-rom driver", opt_no_arg, NULL }, #endif { "appearance", "(mac or windows) specify the appearance of windows and " "menus. For example \"executor -appearance windows\" will make each " "window have a blue title bar", opt_sep, NULL }, { "hfsplusro", "unsupported -- do not use", opt_no_arg, NULL }, }; opt_database_t *common_db; /* Prints the specified value in a representation appropriate for command * line switches. */ static void print_command_line_value (FILE *fp, int v) { if (v > 0 && v % 1024 == 0) { if (v % (1024 * 1024) == 0) fprintf (fp, "%dM", v / (1024 * 1024)); else fprintf (fp, "%dK", v / 1024); } else fprintf (fp, "%d", v); } static void check_arg (char *argname, int *arg, int min, int max) { if (*arg < min || *arg > max) { fprintf (stderr, "%s: invalid value for `%s': must be between ", program_name, argname); print_command_line_value (stderr, min); fputs (" and ", stderr); print_command_line_value (stderr, max); fputs (" inclusive.\n", stderr); bad_arg_p = TRUE; } } #if defined (NEED_WAIT4) /* * NOTE: This is a replacement for wait4 that will work for what we use wait4. * It has the side effect of acknowledging the death of other children. */ A4(PUBLIC, LONGINT, wait4, LONGINT, pid, union wait *, statusp, LONGINT, options, struct rusage *, rusage) { LONGINT retval; do { retval = wait3(statusp, options, rusage); } while (retval > 0 && retval != pid); return retval; } #endif /* NEED_WAIT4 */ PUBLIC char ROMlib_startdir[MAXPATHLEN]; PUBLIC INTEGER ROMlib_startdirlen; #if defined (MSDOS) || defined (CYGWIN32) PUBLIC char ROMlib_start_drive; #endif PUBLIC char *ROMlib_appname; #if !defined(LINUX) #define SHELL "/bin/sh" #define WHICH "which " #else #define SHELL "/bin/bash" #define WHICH "type -path " #endif #define APPWRAP "/Executor.app" ULONGINT ROMlib_ourmtime; #if defined (NEXTSTEP) #if !defined (STRICT_OPENSTEP) #include #include #endif A1(PRIVATE, void, misc_self_examination, char *, us) { struct mach_header head; struct load_command load; struct segment_command seg; struct fat_header fat_head; struct fat_arch arch; struct stat sbuf; int i; BOOLEAN need_to_swap; enum NXByteOrder targetorder; LONGINT err; FILE *ROMlib_fp; if (!(ROMlib_fp = Ufopen(us, "r+"))) { if (!(ROMlib_fp = Ufopen(us, "r"))) { fprintf(stderr, "couldn't open '%s'\n", us); exit(3); } } if (fread(&fat_head, sizeof(fat_head), 1, ROMlib_fp) != 1) { fprintf(stderr, "couldn't read fat_header\n"); exit(4); } if (fat_head.magic == CLC(FAT_MAGIC)) { /* * NOTE: we assume that every architecture supported will have a "lowseg" * segment, hence we can just use the first one we find. If the * binary is later thinned, the user will have to reregister anyway. */ if (fread(&arch, sizeof(arch), 1, ROMlib_fp) != 1) { fprintf(stderr, "couldn't read arch info\n"); exit(6); } if (fseek(ROMlib_fp, CL(arch.offset), SEEK_SET) == -1) { fprintf(stderr, "couldn't seek after load seg command\n"); exit(17); } } else { rewind(ROMlib_fp); arch.offset = 0; } if (fread(&head, sizeof(head), 1, ROMlib_fp) != 1) { fprintf(stderr, "couldn't read header\n"); exit(4); } /* * NOTE: In the following few sections of code we have to accept the * possibility that the header information will be swapped relative * to us. Normally we only care when things are swapped relative * to a big endian machine. But if the first architecture we find * is a big endian one and we're little endian, then we still have * to do swappage. The alternative would be to store the registration * information in the "lowseg" of the architecture that we're currently * running on, but that means that for N archtectures, Executor would * have to be registered N times. Ick. */ #if defined(LITTLEENDIAN) targetorder = NX_LittleEndian; #else /* !defined(LITTLEENDIAN) */ targetorder = NX_BigEndian; #endif /* !defined(LITTLEENDIAN) */ if ((need_to_swap = head.magic != MH_MAGIC)) swap_mach_header(&head, targetorder); if (head.magic != MH_MAGIC) { fprintf(stderr, "bad magic number\n"); exit(5); } for (i = 0; i < head.ncmds; ++i) { if (fread(&load, sizeof(load), 1, ROMlib_fp) != 1) { fprintf(stderr, "couldn't read load command\n"); exit(6); } if (need_to_swap) swap_load_command(&load, targetorder); if (load.cmd == LC_SEGMENT) { if (fread(&seg.segname, sizeof(seg) - sizeof(load), 1, ROMlib_fp) != 1) { fprintf(stderr, "couldn't read load segment command\n"); exit(7); } if (need_to_swap) swap_segment_command(&seg, targetorder); if (strcmp(seg.segname, "hfs_xfer") == 0) { ROMlib_xfervmaddr = (char *) seg.vmaddr; ROMlib_xfervmsize = seg.vmsize; } if (fseek(ROMlib_fp, load.cmdsize - sizeof(seg), SEEK_CUR) == -1) { fprintf(stderr, "couldn't seek after load seg command\n"); exit(17); } } else { if (fseek(ROMlib_fp, load.cmdsize - sizeof(load), SEEK_CUR) == -1) { fprintf(stderr, "couldn't seek after load command\n"); exit(8); } } } fclose (ROMlib_fp); #if !defined(LETGCCWAIL) err = 0; #endif if (Ustat(us, &sbuf) == 0) { if (!geteuid() && (sbuf.st_uid || (sbuf.st_mode & 07777) != 04755)) willsetperms(); if ((geteuid() != 0) && (sbuf.st_uid == 0) && ((sbuf.st_mode & 04000) == 04000)) badfilesystem(); if (sbuf.st_uid) err = Uchown(us, 0, -1); if ((!sbuf.st_uid || err == 0) && (sbuf.st_mode & 07777) != 04755) Uchmod(us, 04755); } } #endif /* defined (NEXTSTEP) */ #if defined(MSDOS) || defined (CYGWIN32) PUBLIC char ROMlib_savecwd[MAXPATHLEN]; PRIVATE void cd_back( void ) { if (ROMlib_savecwd[0]) Uchdir(ROMlib_savecwd); } #endif PRIVATE void set_appname (char *argv0) { ROMlib_appname = strrchr(argv0, '/'); #if defined (MSDOS) || defined (CYGWIN32) if (!ROMlib_appname) ROMlib_appname = strrchr (argv0, '\\'); #endif if (ROMlib_appname) ++ROMlib_appname; else ROMlib_appname = argv0; } A1(PRIVATE, void, setstartdir, char *, argv0) { #if !defined(MSDOS) && !defined(CYGWIN32) LONGINT p[2], pid; char buf[MAXPATHLEN]; INTEGER nread, arg0len; char *lookhere, *suffix, *whichstr; char savedir[MAXPATHLEN]; if (argv0[0] == '/' || Uaccess(argv0, X_OK) == 0) lookhere = argv0; else { pipe((void *) p); if ((pid = fork()) == 0) { ROMlib_setuid(getuid()); close(1); dup(p[1]); arg0len = strlen(argv0); whichstr = alloca(arg0len + sizeof(WHICH)); memmove(whichstr, WHICH, sizeof(WHICH) - 1); memmove(whichstr + sizeof(WHICH) - 1, argv0, arg0len + 1); execl(SHELL, "sh", "-c", whichstr, (char *) 0); fprintf (stderr, "``%s -c \"%s\"'' failed\n", SHELL, whichstr); fflush (stderr); _exit (127); /* NOTREACHED */ #if !defined (LETGCCWAIL) lookhere = 0; #endif /* LETGCCWAIL */ } else { close (p[1]); nread = read(p[0], buf, sizeof(buf)-1); wait4(pid, 0, 0, (struct rusage *) 0); if (nread) --nread; /* get rid of trailing \n */ buf[nread] = 0; lookhere = buf; } } #if defined(NEXTSTEP) misc_self_examination (lookhere); #endif suffix = rindex(lookhere, '/'); if (suffix) *suffix = 0; getcwd(savedir, sizeof savedir); Uchdir(lookhere); if (suffix) *suffix = '/'; getcwd(ROMlib_startdir, sizeof ROMlib_startdir); Uchdir(savedir); ROMlib_startdirlen = strlen(ROMlib_startdir) + 1; #if defined(NEXTSTEP) if (strcmp(ROMlib_startdir + ROMlib_startdirlen - sizeof(APPWRAP), APPWRAP) != 0) { memmove(ROMlib_startdir + ROMlib_startdirlen - 1, APPWRAP, sizeof(APPWRAP)); ROMlib_startdirlen += sizeof(APPWRAP) - 1; } #endif #else /* defined(MSDOS) || defined(CYGWIN32) */ #if defined (MSDOS) || defined (CYGWIN32) atexit (call_cleanup_bat); #endif /* * When run under DOS, argv[0] contains a full path name, including * a dos-drive and colon at the beginning (e.g. C:/fratzand/executor). * However, you get neither when running under DOS under gdb. Yahoo. */ if (!getcwd(ROMlib_savecwd, sizeof(ROMlib_savecwd))) ROMlib_savecwd[0] = 0; else atexit(cd_back); if (argv0[1] == ':') { char *lastslash; #if 1 static char cd_to[] = "C:/"; ROMlib_start_drive = argv0[0]; cd_to[0] = argv0[0]; Uchdir(cd_to); #if 0 strcpy(ROMlib_startdir, argv0 + 2); #else /* We now include the drive letter in with ROMlib_startdir. */ strcpy(ROMlib_startdir, argv0); #endif #else strcpy(ROMlib_startdir, argv0); #endif lastslash = strrchr(ROMlib_startdir, '/'); #if defined (CYGWIN32) if (!lastslash) lastslash = strrchr(ROMlib_startdir, '\\'); #endif if (lastslash) *lastslash = 0; } else { ROMlib_start_drive = 0; strcpy(ROMlib_startdir, "."); } ROMlib_startdirlen = strlen(ROMlib_startdir); #endif /* defined(MSDOS) */ } PUBLIC BOOLEAN ROMlib_startupscreen = TRUE; char *program_name; #if defined (SYN68K) static syn68k_addr_t unhandled_trap (syn68k_addr_t callback_address, void *arg) { static const char *trap_description[] = { /* I've only put the really interesting ones in. */ NULL, NULL, NULL, NULL, "Illegal instruction", "Integer divide by zero", "CHK/CHK2", "FTRAPcc, TRAPcc, TRAPV", "Privilege violation", "Trace", "A-line", "FPU", NULL, NULL, "Format error" }; int trap_num; char pc_str[128]; trap_num = (long) arg; switch (trap_num) { case 4: /* Illegal instruction. */ case 8: /* Privilege violation. */ case 10: /* A-line. */ case 11: /* F-line. */ case 14: /* Format error. */ case 15: /* Uninitialized interrupt. */ case 24: /* Spurious interrupt. */ case 25: /* Level 1 interrupt autovector. */ case 26: /* Level 2 interrupt autovector. */ case 27: /* Level 3 interrupt autovector. */ case 28: /* Level 4 interrupt autovector. */ case 29: /* Level 5 interrupt autovector. */ case 30: /* Level 6 interrupt autovector. */ case 31: /* Level 7 interrupt autovector. */ case 32: /* TRAP #0 vector. */ case 33: /* TRAP #1 vector. */ case 34: /* TRAP #2 vector. */ case 35: /* TRAP #3 vector. */ case 36: /* TRAP #4 vector. */ case 37: /* TRAP #5 vector. */ case 38: /* TRAP #6 vector. */ case 39: /* TRAP #7 vector. */ case 40: /* TRAP #8 vector. */ case 41: /* TRAP #9 vector. */ case 42: /* TRAP #10 vector. */ case 43: /* TRAP #11 vector. */ case 44: /* TRAP #12 vector. */ case 45: /* TRAP #13 vector. */ case 46: /* TRAP #14 vector. */ case 47: /* TRAP #15 vector. */ case 3: /* Address error. */ case 6: /* CHK/CHK2 instruction. */ case 7: /* FTRAPcc, TRAPcc, TRAPV instructions. */ case 9: /* Trace. */ case 5: /* Integer divide by zero. */ sprintf (pc_str, "0x%lX", (unsigned long) READUL (EM_A7 + 2)); break; default: strcpy (pc_str, ""); break; } if (trap_num < (int) NELEM (trap_description) && trap_description[trap_num] != NULL) gui_fatal ("Fatal error: unhandled trap %d at pc %s (%s)", trap_num, pc_str, trap_description[trap_num]); else gui_fatal ("Fatal error: unhandled trap %d at pc %s", trap_num, pc_str); /* It will never get here; this is just here to quiet gcc. */ return callback_address; } static void setup_trap_vectors (void) { syn68k_addr_t timer_callback; int i; /* Set up the trap vector for the timer interrupt. */ timer_callback = callback_install (catchalarm, NULL); *(syn68k_addr_t *)SYN68K_TO_US(M68K_TIMER_VECTOR * 4) = CL (timer_callback); /* Fill in unhandled trap vectors so they cause graceful deaths. * Skip over those trap vectors which are known to have legitimate * values. */ for (i = 1; i < 64; i++) if (i != 10 /* A line trap. */ #if defined (M68K_TIMER_VECTOR) && i != M68K_TIMER_VECTOR /* timer interrupt. */ #endif #if defined (M68K_WATCHDOG_VECTOR) && i != M68K_WATCHDOG_VECTOR /* watchdog timer interrupt. */ #endif #if defined (M68K_EVENT_VECTOR) && i != M68K_EVENT_VECTOR #endif #if defined (M68K_MOUSE_MOVED_VECTOR) && i != M68K_MOUSE_MOVED_VECTOR #endif #if defined (M68K_SOUND_VECTOR) && i != M68K_SOUND_VECTOR #endif && i != 0x58 / 4) /* Magic ARDI vector. */ { syn68k_addr_t c; c = callback_install (unhandled_trap, (void *) i); *(syn68k_addr_t *)SYN68K_TO_US(i * 4) = CL (c); } } #endif /* SYN68K */ static void illegal_mode (void) __attribute__ ((noreturn)); static void illegal_mode (void) { const vdriver_modes_t *vm; int num_sizes, max_width, max_height, max_bpp; vm = vdriver_mode_list; num_sizes = vm->num_sizes; max_bpp = vdriver_max_bpp; if (num_sizes) { max_width = vm->size[num_sizes - 1].width; max_height = vm->size[num_sizes - 1].height; } else max_width = max_height = 0; /* quiet gcc */ vdriver_shutdown (); /* Just to be safe. */ if (num_sizes == 0) fprintf (stderr, "Unable to find legal graphics mode.\n"); else { fprintf (stderr, "Invalid graphics mode. Largest allowable " "screen %dx%d, %d bits per pixel.\n", max_width, max_height, max_bpp); #if defined (MSDOS) if (!vesa_version) { fputs ("No VESA driver detected. To get more video modes, " "make sure you have a\n" "VESA-compatible video driver and a SuperVGA board.\n", stderr); } #endif } /* Don't call ExitToShell here; ROMlib isn't set up enough yet to do that. */ exit (-1); } #if defined (MSDOS) || defined (CYGWIN32) PUBLIC uint32 ROMlib_macdrives; /* default computed at runtime */ PUBLIC uint32 ROMlib_dosdrives = ~0; PRIVATE uint32 skipdrives = 0; PRIVATE boolean_t drive_number_from_letter (char c, int *nump) { boolean_t retval; if (isupper (c) || ((c >= '[' && c <= '`'))) { *nump = c - 'A'; retval = TRUE; } else if (islower (c)) { *nump = c - 'a'; retval = TRUE; } else retval = FALSE; return retval; } PRIVATE void drive_error (const char *opt) { fprintf (stderr, "Invalid drive specification.\nUse something like " "\"-%s A-EJ\" (for drives A, B, C, D, E and J).\n", opt); bad_arg_p = TRUE; } PRIVATE const char * munch_next_char (const char *p, uint32 *destp, const char *opt) { const char *retval; int d; if (drive_number_from_letter (p[0], &d)) { if (p[1] == '-') { int d2; if (drive_number_from_letter (p[2], &d2)) { int lower, upper, i; lower = MIN (d, d2); upper = MAX (d, d2); for (i = lower; i <= upper; ++i) *destp |= (1 << i); retval = p+3; } else { drive_error (opt); retval = ""; } } else { *destp |= 1 << d; retval = p+1; } } else { drive_error (opt); retval = ""; } return retval; } PUBLIC uint32 parse_drive_opt (const char *opt_name, const char *opt_value) { uint32 retval; const char *next_charp; retval = 0; for (next_charp = opt_value; *next_charp;) next_charp = munch_next_char(next_charp, &retval, opt_name); return retval; } #endif #if !defined (MSDOS) static void print_info (void) { printf ("This is %s, compiled.\n", ROMlib_executor_full_name); #if defined (i386) /* Print out CPU type. */ if (arch_type == ARCH_TYPE_I386) printf ("CPU type is 80386.\n"); else printf ("CPU type is 80486 or better.\n"); #endif /* i386 */ #define MB (1024 * 1024U) /* Print out actual memory size chosen. */ printf ("Choosing %u.%02u MB for applzone, %u.%02u MB for syszone, " "%u.%02u MB for stack\n", ROMlib_applzone_size / MB, (ROMlib_applzone_size % MB) * 100 / MB, ROMlib_syszone_size / MB, (ROMlib_syszone_size % MB) * 100 / MB, ROMlib_stack_size / MB, (ROMlib_stack_size % MB) * 100 / MB); #undef MB } #endif /* !MSDOS */ /* This is to tell people about the switch from "-applzone 4096" to * "-applzone 4M". */ static void note_memory_syntax_change (const char *arg, unsigned val) { /* Make sane error messages when the supplied value is insane. * Otherwise, try to print an example that illustrates how to * use the value they are trying to generate. */ if (val < 100 || val > 1000000) val = 2048; fprintf (stderr, "Specified %s is too small. The syntax " "has changed; now, for a %u.%02u\nmegabyte %s you would " "say \"-%s ", arg, val / 1024, (val % 1024) * 100 / 1024, arg, arg); if (val % 1024 == 0) fprintf (stderr, "%uM", val / 1024); else if (val < 1024) fprintf (stderr, "%uK", val); else fprintf (stderr, "%u.%02uM", val / 1024, (val % 1024) * 100 / 1024); fputs ("\"\n", stderr); bad_arg_p = TRUE; } /* Concatenates all strings in the array, separated by spaces. */ static const char * construct_command_line_string (int argc, char **argv) { char *s; unsigned long string_length; int i, j; for (i = 0, string_length = 0; i < argc; i++) string_length += strlen (argv[i]) + 1; s = malloc (string_length + 1); s[0] = '\0'; for (j = 0; j < argc; j++) sprintf (s + strlen (s), "%s%s", j ? " " : "", argv[j]); return s; } PRIVATE int zap_comments (char *buf, int n_left) { char *ip, *op; boolean_t last_was_cr; int retval; ip = buf; op = buf; retval = 0; last_was_cr = TRUE; while (n_left > 0) { while (n_left > 0 && (*ip != '#' || !last_was_cr)) { last_was_cr = *ip == '\n' || *ip == '\r'; *op++ = *ip++; ++retval; --n_left; } if (n_left > 0) { while (n_left > 0 && *ip != '\n' && *ip != '\r') { ++ip; --n_left; } } } return retval; } #if !defined (LINUX) #define EXECUTOR_DIR(filename) \ ({ \ char *retval; \ \ retval = alloca (strlen (ROMlib_startdir) + 1 + strlen (filename) + 1); \ sprintf (retval, "%s/%s", ROMlib_startdir, (filename)); \ retval; \ }) #else #define EXECUTOR_DIR(filename) \ ({ \ char *s; \ char *retval; \ \ s = alloca (2 + strlen(filename) + 1); \ sprintf (s, "+/%s", filename); \ s = copystr (s); \ retval = alloca (strlen (s) + 1); \ strcpy (retval, s); \ free (s); \ retval; \ }) #endif PUBLIC FILE * executor_dir_fopen (const char *file, const char *perm) { char *pathname; FILE *retval; pathname = EXECUTOR_DIR (file); retval = fopen (pathname, perm); return retval; } PUBLIC int executor_dir_remove (const char *file) { char *pathname; int retval; pathname = EXECUTOR_DIR (file); retval = remove (pathname); return retval; } PRIVATE void read_args_from_file (const char *filename, int *argcp, char ***argvpp) { FILE *fp; fp = executor_dir_fopen (filename, "r"); if (fp) { int nread, n_extra_params, i; char buf[8192], *bufp; char **saveargv; nread = fread (buf, 1, sizeof buf, fp); fclose (fp); nread = zap_comments (buf, nread); n_extra_params = count_params (buf, nread); *argcp += n_extra_params; saveargv = *argvpp; *argvpp = malloc ((*argcp+1) * sizeof *argvpp); bufp = buf; memcpy (*argvpp, saveargv, (*argcp - n_extra_params) * sizeof **argvpp); for (i = *argcp - n_extra_params; i < *argcp; ++i) (*argvpp)[i] = get_param ((const char **) &bufp, &nread); (*argvpp)[i] = 0; } } #if defined (CYGWIN32) PRIVATE uint32 win_drive_to_bit (const char *drive_namep) { uint32 retval; if (drive_namep[1] == ':') retval = 1 << (tolower(drive_namep[0]) - 'a'); else { warning_unexpected ("drive name = '%s'", drive_namep); retval = 0; } return retval; } #endif #if defined(LINUX) #define PERSONALITY_HACK #include #define READ_IMPLIES_EXEC 0x0400000 #endif A2 (PUBLIC, int, main, int, argc, char **, argv) { check_structs (); INTEGER i; static unsigned short jmpl_to_ResourceStub[3] = { CWC (0x4EF9), 0, 0 /* Filled in below. */ }; long l; ULONGINT save_trap_vectors[64]; virtual_int_state_t int_state; THz saveSysZone, saveApplZone; Ptr saveApplLimit; #if defined (MSDOS) boolean_t check_files_p; /* See if FILES= is big enough? */ #endif static void (*reg_funcs[]) (void) = { vdriver_opt_register, NULL, }; char *arg; #if defined(PERSONALITY_HACK) int pers; pers = personality(0xffffffff); if ((pers & MMAP_PAGE_ZERO) == 0) { if (personality(pers|MMAP_PAGE_ZERO|READ_IMPLIES_EXEC) == 0) execv(argv[0], argv); } #endif int grayscale_p = FALSE; #if defined (DISPLAY_SPLASH_SCREEN) boolean_t splash_screen_displayed_p; #endif #if defined (VDRIVER_SVGALIB) /* We need to do this right away, to give up suid root privileges. */ vga_init (); #endif #if defined (MSDOS) /* Guarantee that ds and ss are the same, so we can use * -fomit-frame-pointer and other fun hacks. We need to do this * *right away*, before we might use %ebp as a general register. */ asm ("pushl %ds\n\t" "popl %ss"); #endif /* MSDOS */ ROMlib_do_custom (); ROMlib_command_line = construct_command_line_string (argc, argv); if (!arch_init ()) { fprintf (stderr, "Unable to initialize CPU information.\n"); exit (-100); } if (!os_init ()) { fprintf (stderr, "Unable to initialize operating system features.\n"); exit (-101); } { char *t; t = strrchr (*argv, '/'); if (t) program_name = &t[1]; else program_name = *argv; } /* Guarantee various time variables are set up properly. */ msecs_elapsed (); #if defined (MMAP_LOW_GLOBALS) for (i = 1; i < argc && strcmp (argv[i], "-offset") != 0; ++i) ; if (i == argc) mmap_lowglobals (); #endif /* MMAP_LOW_GLOBALS */ ROMlib_WriteWhen (WriteInOSEvent); #if defined (NEXTSTEP) ROMlib_seteuid (0); /* This is necessary because when people copy setuid-root files from floppies, the setuid bit stays, but the "root" part doesn't, so even if they run as root, they're messed */ #endif setstartdir (argv[0]); set_appname (argv[0]); #define COMMANDS "commands.txt" read_args_from_file (COMMANDS, &argc, &argv); #if defined (MSDOS) || defined (CYGWIN32) read_args_from_file (CHECKPOINT_FILE, &argc, &argv); checkpointp = checkpoint_init (); #endif /* Replace "-desperate" switch with what it implies. We must do * this before normal command line processing. */ if (!handle_desperate_switch (&argc, &argv)) exit (-1); opt_init (); common_db = opt_alloc_db (); opt_register ("common", common_opts, NELEM (common_opts)); opt_register_pre_note ("welcome to the executor help message."); opt_register_pre_note ("usage: `executor [option...] " "[program [document1 document2 ...]]'"); for (i = 0; reg_funcs[i]; i ++) (*reg_funcs[i]) (); if (!bad_arg_p) bad_arg_p = opt_parse (common_db, common_opts, NELEM (common_opts), &argc, argv); if (opt_val (common_db, "version", NULL)) { fprintf (stdout, "%s\n", EXECUTOR_VERSION); exit (0); } /* * If they ask for help, it's not an error -- it should go to stdout */ if (opt_val (common_db, "help", NULL)) { fprintf (stdout, "%s", opt_help_message ()); exit (0); } /* Verify that the user input a legal bits per pixel. "0" is a legal * value here; that means "use the vdriver's default." */ opt_int_val (common_db, "bpp", &flag_bpp, &bad_arg_p); if (flag_bpp != 0 && flag_bpp != 1 && flag_bpp != 2 && flag_bpp != 4 && flag_bpp != 8 && flag_bpp != 16 && flag_bpp != 32) { fprintf (stderr, "Bits per pixel must be 1, 2, 4, 8, 16 or 32.\n"); bad_arg_p = TRUE; } #if defined (SDL) if (opt_val (common_db, "fullscreen", NULL)) ROMlib_fullscreen_p = TRUE; if (opt_val (common_db, "hwsurface", NULL)) ROMlib_hwsurface_p = TRUE; #endif #if defined(X) || (defined (CYGWIN32) && defined (SDL)) if (opt_val (common_db, "scancodes", NULL)) ROMlib_set_use_scancodes (TRUE); #endif #if defined (SDL) if (opt_val (common_db, "sdlaudio", &arg)) ROMlib_set_sdl_audio_driver_name (arg); #endif if (opt_val (common_db, "ppc", NULL)) ROMlib_set_ppc (TRUE); if (opt_val (common_db, "hfsplusro", NULL)) ROMlib_hfs_plus_support = TRUE; #if defined (CYGWIN32) if (opt_val (common_db, "realmodecd", NULL)) ROMlib_set_realmodecd (TRUE); #endif if (opt_val (common_db, "size", &arg)) bad_arg_p |= !parse_size_opt ("size", arg); if (opt_val (common_db, "prres", &arg)) bad_arg_p |= !parse_prres_opt (&ROMlib_optional_res_x, &ROMlib_optional_res_y, arg); if (opt_val (common_db, "debug", &arg)) bad_arg_p |= !error_parse_option_string (arg); #if defined (MSDOS) || defined (CYGWIN32) if (opt_val (common_db, "macdrives", &arg)) ROMlib_macdrives = parse_drive_opt ("macdrives", arg); else { #if !defined (CYGWIN32) ROMlib_macdrives = 3; /* A: + B: */ { int cdrom; cdrom = dosdisk_find_cdrom (); if (cdrom != -1) ROMlib_macdrives |= (1 << cdrom); } #else char buf[512]; if (win_GetLogicalDriveStrings (sizeof buf - 1, buf)) { char *p; for (p = buf; *p; p += strlen (p) + 1) if (win_direct_accessible_disk (p)) ROMlib_macdrives |= win_drive_to_bit (p); } #endif } if (opt_val (common_db, "dosdrives", &arg)) ROMlib_dosdrives = parse_drive_opt ("dosdrives", arg); if (opt_val (common_db, "skipdrives", &arg)) { skipdrives = parse_drive_opt ("skipdrives", arg); ROMlib_macdrives &= ~skipdrives; ROMlib_dosdrives &= ~skipdrives; } #endif #if defined (MSDOS) { int dangerous_video_p = FALSE; opt_int_val (common_db, "dangerousvideospeedup", &dangerous_video_p, &bad_arg_p); if (!dangerous_video_p) opt_int_val (common_db, "videospeedup", &dangerous_video_p, &bad_arg_p); try_to_use_fat_ds_vga_hack_p = dangerous_video_p; } opt_int_val (common_db, "nosync", &ROMlib_nosync, &bad_arg_p); opt_int_val (common_db, "skipaspi", &ROMlib_skipaspi, &bad_arg_p); { int only_vga_p = FALSE; opt_int_val (common_db, "vga", &only_vga_p, &bad_arg_p); only_use_vga_p = only_vga_p; } #endif { int skip; skip = 0; opt_int_val (common_db, "nosound", &skip, &bad_arg_p); sound_disabled_p = (skip != 0); } { int nocache; nocache = 0; opt_int_val (common_db, "nodiskcache", &nocache, &bad_arg_p); dcache_set_enabled (!nocache); } #if defined (SYN68K) use_native_code_p = ! opt_val (common_db, "notnative", NULL); #endif afpd_conventions_p = opt_val (common_db, "afpd", NULL); netatalk_conventions_p = (afpd_conventions_p || opt_val (common_db, "netatalk", NULL)); if (netatalk_conventions_p) { apple_double_quote_char = ':'; apple_double_fork_prefix = ".AppleDouble/"; } else { apple_double_quote_char = '%'; apple_double_fork_prefix = "%"; } apple_double_fork_prefix_length = strlen (apple_double_fork_prefix); substitute_fonts_p = !opt_val (common_db, "cities", NULL); if (opt_val (common_db, "offset", NULL)) force_big_offset = TRUE; #if defined (CYGWIN32) if (opt_val (common_db, "die", NULL)) uninstall_exception_handler (); if (opt_val (common_db, "noautoevents", NULL)) set_timer_driven_events (FALSE); #endif #if defined (MSDOS) || defined (CYGWIN32) if (opt_val (common_db, "nocheckpoint", NULL)) disable_checkpointing (); #endif /* Parse the "-memory" option. */ { int total_memory; if (opt_int_val (common_db, "memory", &total_memory, &bad_arg_p)) { check_arg ("memory", &total_memory, (MIN_APPLZONE_SIZE + DEFAULT_SYSZONE_SIZE + DEFAULT_STACK_SIZE), (MAX_APPLZONE_SIZE + DEFAULT_SYSZONE_SIZE + DEFAULT_STACK_SIZE)); /* Set up the three memory sizes appropriately. For now we * just allocate the defaults for syszone and stack, and * put everything else in -applzone. */ ROMlib_syszone_size = DEFAULT_SYSZONE_SIZE; ROMlib_stack_size = DEFAULT_STACK_SIZE; ROMlib_applzone_size = (total_memory - ROMlib_syszone_size - ROMlib_stack_size); } } /* I bumped the minimal ROMlib_applzone to 512, since Loser needs more than 256. I guess it's a little unfair to people who bypass Loser, but it will prevent confusion. */ opt_int_val (common_db, "applzone", &ROMlib_applzone_size, &bad_arg_p); if (ROMlib_applzone_size < 65536) note_memory_syntax_change ("applzone", ROMlib_applzone_size); else check_arg ("applzone", &ROMlib_applzone_size, MIN_APPLZONE_SIZE, MAX_APPLZONE_SIZE); opt_int_val (common_db, "syszone", &ROMlib_syszone_size, &bad_arg_p); if (ROMlib_syszone_size < 65536) note_memory_syntax_change ("syszone", ROMlib_syszone_size); else check_arg ("syszone", &ROMlib_syszone_size, MIN_SYSZONE_SIZE, MAX_SYSZONE_SIZE); opt_int_val (common_db, "stack", &ROMlib_stack_size, &bad_arg_p); if (ROMlib_stack_size < 32768) note_memory_syntax_change ("stack", ROMlib_stack_size); else check_arg ("stack", &ROMlib_stack_size, MIN_STACK_SIZE, MAX_STACK_SIZE); #if defined (MM_MANY_APPLZONES) opt_int_val (common_db, "napplzones", &mm_n_applzones, &bad_arg_p); check_arg ("napplzones", &mm_n_applzones, 1, /* random */ 255); #endif /* !MM_MANY_APPLZONES */ ROMlib_InitZones (force_big_offset ? offset_big : offset_none); { uint32 save_a7; save_a7 = EM_A7; #if defined (SYN68K) /* Set up syn68k. */ initialize_68k_emulator (vdriver_system_busy, #if defined (__CHECKER__) FALSE, #else use_native_code_p, #endif (uint32 *) SYN68K_TO_US (0), #if defined (USE_BIOS_TIMER) dos_int_flag.rm_segment * 16 #else /* !USE_BIOS_TIMER */ 0 #endif /* !USE_BIOS_TIMER */ ); #endif /* SYN68K */ EM_A7 = save_a7; } if (opt_val (common_db, "keyboards", NULL)) graphics_p = FALSE; /* Block virtual interrupts, until the system is fully set up. */ int_state = block_virtual_ints (); #if defined (MSDOS) /* We must switch to a non-moving sbrk before calling vdriver_init, * if the user wants to try the fat %ds vga hack. Otherwise, * the address of the frame buffer relative to the base of %ds * could change after we've already determined its value. */ if (try_to_use_fat_ds_vga_hack_p) switch_to_non_moving_sbrk (); #endif if (graphics_p && !vdriver_init (0, 0, 0, FALSE, &argc, argv)) { fprintf (stderr, "Unable to initialize video driver.\n"); exit (-12); } #if defined (SYN68K) /* Save the trap vectors away. */ memcpy (save_trap_vectors, SYN68K_TO_US(0), sizeof save_trap_vectors); #endif #if defined (MSDOS) { int use_old_timer_p = FALSE; opt_int_val (common_db, "oldtimer", &use_old_timer_p, &bad_arg_p); use_bios_timer_p = !use_old_timer_p; } { int no_files_check_p = FALSE; opt_int_val (common_db, "nofilescheck", &no_files_check_p, &bad_arg_p); check_files_p = !no_files_check_p; } #endif opt_int_val (common_db, "sticky", &ROMlib_sticky_menus_p, &bad_arg_p); opt_int_val (common_db, "pceditkeys", &ROMlib_forward_del_p, &bad_arg_p); opt_int_val (common_db, "nobrowser", &ROMlib_nobrowser, &bad_arg_p); opt_int_val (common_db, "print", &ROMlib_print, &bad_arg_p); #if defined (NEXT) || defined (LINUX) opt_int_val (common_db, "nodotfiles", &ROMlib_no_dot_files, &bad_arg_p); #endif #if defined (NOMOUSE_COMMAND_LINE_OPTION) opt_int_val (common_db, "nomouse", &ROMlib_no_mouse, &bad_arg_p); #endif #if 0 opt_int_val (common_db, "noclock", &ROMlib_noclock, &bad_arg_p); #endif { int no_auto = FALSE; opt_int_val (common_db, "noautorefresh", &no_auto, &bad_arg_p); do_autorefresh_p = !no_auto; } opt_int_val (common_db, "refresh", &ROMlib_refresh, &bad_arg_p); check_arg ("refresh", &ROMlib_refresh, 0, 60); opt_int_val (common_db, "grayscale", &grayscale_p, &bad_arg_p); #if defined (LINUX) opt_int_val (common_db, "nodrivesearch", &nodrivesearch_p, &bad_arg_p); #endif { char *str; if (opt_val (common_db, "prvers", &str)) { uint32 vers; if (!ROMlib_parse_version (str, &vers)) bad_arg_p = TRUE; else ROMlib_PrDrvrVers = (vers >> 8) * 10 + ((vers >> 4) & 0xF); } } #if defined (SUPPORT_LOG_ERR_TO_RAM) { int log; log = 0; opt_int_val (common_db, "ramlog", &log, &bad_arg_p); log_err_to_ram_p = (log != 0); } #endif if (opt_val (common_db, "info", NULL)) { #if defined (MSDOS) msdos_print_info (); #else print_info (); #endif /* MSDOS */ exit (0); } #if defined (MSDOS) { int port; if (opt_int_val (common_db, "modemport", &port, &bad_arg_p)) { if (port < 1 || port > 4) { fprintf (stderr, "modemport must be 1, 2, 3 or 4.\n"); bad_arg_p = TRUE; } else set_modem_port_mapping_to_pc_port (port); } if (opt_int_val (common_db, "printerport", &port, &bad_arg_p)) { if (port < 1 || port > 4) { fprintf (stderr, "printerport must be 1, 2, 3 or 4.\n"); bad_arg_p = TRUE; } else set_printer_port_mapping_to_pc_port (port); } } #endif /* If we failed to parse our arguments properly, exit now. * I don't think we should call ExitToShell yet because the * rest of the system isn't initialized. */ if (argc >= 2) { int a; /* Only complain if we see something with a leading dash; anything * else might be a file to launch. */ for (a = 1; a < argc; a++) if (argv[a][0] == '-') { fprintf (stderr, "%s: unknown option `%s'\n", program_name, argv[a]); bad_arg_p = TRUE; } } filltables (); l = (long) ostraptable[0x0FC]; ((unsigned char *) jmpl_to_ResourceStub)[2] = l >> 24; ((unsigned char *) jmpl_to_ResourceStub)[3] = l >> 16; ((unsigned char *) jmpl_to_ResourceStub)[4] = l >> 8; ((unsigned char *) jmpl_to_ResourceStub)[5] = l; ostraptable[0xFC] = (void *) US_TO_SYN68K(jmpl_to_ResourceStub); osstuff[0xFC].orig = (void *) US_TO_SYN68K(jmpl_to_ResourceStub); saveSysZone = SysZone; saveApplZone = ApplZone; saveApplLimit = ApplLimit; memset (&nilhandle, ~0, (char *) &lastlowglobal - (char *) &nilhandle); setupsignals (); Ticks_UL.u = 0; nilhandle = 0; /* so nil dereferences "work" */ memset (&EventQueue, 0, sizeof (EventQueue)); memset (&VBLQueue, 0, sizeof (VBLQueue)); memset (&DrvQHdr, 0, sizeof (DrvQHdr)); memset (&VCBQHdr, 0, sizeof (VCBQHdr)); memset (&FSQHdr, 0, sizeof (FSQHdr)); TESysJust = 0; SysZone = saveSysZone; ApplZone = saveApplZone; ApplLimit = saveApplLimit; BootDrive = 0; DefVCBPtr = 0; CurMap = 0; TopMapHndl = 0; DSAlertTab = 0; ResumeProc = 0; SFSaveDisk = 0; GZRootHnd = 0; ANumber = 0; ResErrProc = 0; FractEnable = 0; SEvtEnb = 0; MenuList = 0; MBarEnable = 0; MenuFlash = 0; TheMenu = 0; MBarHook = 0; MenuHook = 0; MenuCInfo = NULL; HeapEnd = 0; ApplLimit = 0; SoundActive = soundactiveoff; PortBUse = 2; /* configured for Serial driver */ memset (KeyMap, 0, sizeof_KeyMap); if (vdriver_grayscale_p || grayscale_p) { /* Choose a nice light gray hilite color. */ HiliteRGB.red = CWC (0xAAAA); HiliteRGB.green = CWC (0xAAAA); HiliteRGB.blue = CWC (0xAAAA); } else { /* how about a nice yellow hilite color? */ HiliteRGB.red = CWC (0xFFFF); HiliteRGB.green = CWC (0xFFFF); HiliteRGB.blue = CWC (0); } { static uint16 ret = CWC (0x4E75); JCrsrTask = (ProcPtr) RM (&ret); } SET_HILITE_BIT (); TheGDevice = MainDevice = DeviceList = CLC_NULL; OneOne = CLC (0x00010001); Lo3Bytes = CLC (0xFFFFFF); DragHook = 0; TopMapHndl = 0; SysMapHndl = 0; MBDFHndl = 0; MenuList = 0; MBSaveLoc = 0; SysVersion = CW (system_version); FSFCBLen = CWC (94); ScrapState = CWC (-1); #if defined (MSDOS) switch_to_non_moving_sbrk (); #endif #if defined (MSDOS) /* Make sure FILES= is big enough. */ if (check_files_p && !msdos_test_max_files ()) exit (-39); /* Make sure we have at least 0.75 megabytes of memory remaining, so * that syn68k will have a big enough working area. This figure is * somewhat arbitrary, but we really don't want the user cutting it * particularly close and then complain about lousy performance and * flaky behavior. */ if (!msdos_check_memory_remaining (768 * 1024)) { vdriver_shutdown (); print_mem_full_message (); exit (-50); } #endif #if defined(NEXT) && !defined(SYN68K) ROMlib_install_ardi_mods (); #endif /* NEXT && !SYN68K */ #if defined (NEXT) ROMlib_determine040ness (); ROMlib_checkadb (); #endif /* NEXT */ TheZone = SysZone; UTableBase = (DCtlHandlePtr) (long) RM (NewPtr (sizeof (UTableBase[0].p) * NDEVICES)); memset (MR (UTableBase), 0, sizeof (UTableBase[0].p) * NDEVICES); UnitNtryCnt = CW (NDEVICES); TheZone = ApplZone; if (graphics_p) { /* Set up the current graphics mode appropriately. */ if (!vdriver_set_mode (flag_width, flag_height, flag_bpp, grayscale_p)) illegal_mode (); /* initialize the mac rgb_spec's */ make_rgb_spec (&mac_16bpp_rgb_spec, 16, TRUE, 0, 5, 10, 5, 5, 5, 0, CL (GetCTSeed ())); make_rgb_spec (&mac_32bpp_rgb_spec, 32, TRUE, 0, 8, 16, 8, 8, 8, 0, CL (GetCTSeed ())); gd_allocate_main_device (); } #if defined (DISPLAY_SPLASH_SCREEN) if (graphics_p) splash_screen_displayed_p = splash_screen_display (FALSE, "splash"); #endif ROMlib_eventinit (graphics_p); hle_init (); ROMlib_fileinit (); InitUtil (); #if !defined (X) && !defined (SDL) /* #warning "Hack so we don't smash mouse/keyboard m68k interrupt vectors." */ #if defined (M68K_EVENT_VECTOR) save_trap_vectors[M68K_EVENT_VECTOR] = *(syn68k_addr_t *)SYN68K_TO_US(M68K_EVENT_VECTOR * 4); #endif #if defined (M68K_MOUSE_MOVED_VECTOR) save_trap_vectors[M68K_MOUSE_MOVED_VECTOR] = *(syn68k_addr_t *)SYN68K_TO_US(M68K_MOUSE_MOVED_VECTOR * 4); #endif #endif { char *appearance_str; if (opt_val (common_db, "appearance", &appearance_str)) bad_arg_p |= !ROMlib_parse_appearance (appearance_str); } InitResources (); /* parse the `-system' option */ { char *system_str; if (opt_val (common_db, "system", &system_str)) bad_arg_p |= !parse_system_version (system_str); else ROMlib_set_system_version (system_version); } if (bad_arg_p) { fprintf (stderr, "Type \"%s -help\" for a list of command-line options.\n", program_name); exit (-10); } { boolean_t keyboard_set_failed; if (opt_val (common_db, "keyboard", &arg)) { keyboard_set_failed = !ROMlib_set_keyboard (arg); if (keyboard_set_failed) printf ("``%s'' is not an available keyboard\n", arg); } else keyboard_set_failed = FALSE; if (keyboard_set_failed || opt_val (common_db, "keyboards", NULL)) display_keyboard_choices (); } ROMlib_seginit (argc, argv); InitFonts (); #if !defined (NDEBUG) dump_init (NULL); #endif /* see qColorutil.c */ ROMlib_color_init (); wind_color_init (); /* must be called after `ROMlib_color_init ()' */ image_inits (); /* must be after `image_inits ()' */ sb_ctl_init (); AE_init (); { INTEGER env = 0; ROMlib_Fsetenv (&env, 0); } TEDoText = RM ((ProcPtr) P_ROMlib_dotext); /* where should this go ? */ #if defined (SYN68K) { LONGINT save58; save58 = *(LONGINT *) SYN68K_TO_US(0x58); /* Replace the trap vectors which got smashed during initialization. */ memcpy (SYN68K_TO_US (0), save_trap_vectors, sizeof save_trap_vectors); *(LONGINT *) SYN68K_TO_US(0x58) = save58; setup_trap_vectors (); } /* Set up timer interrupts. We need to do this after everything else * has been initialized. */ if (!syncint_init ()) { vdriver_shutdown (); fputs ("Fatal error: unable to initialize timer.\n", stderr); exit (-11); } #endif /* SYN68K */ sound_init (); set_refresh_rate (ROMlib_refresh); restore_virtual_ints (int_state); WWExist = QDExist = EXIST_NO; #if defined (CYGWIN32) complain_if_no_ghostscript (); #endif executor_main (); if (!ROMlib_no_windows) ExitToShell (); else exit (0); /* NOT REACHED */ return 0; }