ftp.nice.ch/pub/next/developer/languages/c/djgpp-NS.s.tar.gz#/djgpp/go32/control.c

This is control.c in view mode; [Download] [Up]

/* This is file CONTROL.C */
/*
** Copyright (C) 1993 DJ Delorie, 24 Kirsten Ave, Rochester NH 03867-2954
**
** This file is distributed under the terms listed in the document
** "copying.dj", available from DJ Delorie at the address above.
** A copy of "copying.dj" should accompany this file; if not, a copy
** should be available from where this file was obtained.  This file
** may not be distributed without a verbatim copy of "copying.dj".
**
** This file is distributed WITHOUT ANY WARRANTY; without even the implied
** warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/

/* Modified for VCPI Implement by Y.Shibata Aug 5th 1991 */
/* Modified for DPMI Implement by H.Tsubakimoto */
/* Merged DPMI and V1.09 C. Sandmann sandmann@clio.rice.edu */

#include <dos.h>
#include <dir.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <ctype.h>
#include <io.h>

#include "gotypes.h"
#include "gdt.h"
#include "idt.h"
#include "tss.h"
#include "valloc.h"
#include "utils.h"
#include "graphics.h"
#include "mono.h"
#include "vcpi.h"
#include "paging.h"
#include "dpmi.h"
#include "extdebug.h"
#include "exphdlr.h"
#include "dalloc.h"
#include "vcpi.h"
#include "mswitch.h"
#include "xms.h"
#include "npx.h"
#include "stubinfo.h"
#include "proginfo.h"
#include "control.h"
#include "eventque.h"
#include "glob.h"

/* stamp.c will find this and replace it with the correct timestamp
   but leave the TIMETIME key alone */
static char build_time[] = "TIMETIMExxx xxx xx xx:xx:xx xxxx";

StubInfo stub_info = {
  STUB_INFO_MAGIC,
  sizeof(StubInfo),
  "go32",
  {
    GO32_RELEASE_NUMBER,
    GO32_RELEASE_TYPE_C,
    GO32_MINOR_VERSION,
    GO32_MAJOR_VERSION
  },
  262144L,
  0L,
  "",
  1,
  0L
};

PROGINFO prog_info;

int topline_info = 0;
int show_memory_info = 0;

extern transfer_buffer[];
extern word32 transfer_linear;

extern int ctrl_c_flag, in_hardware_interrupt;

GDT_S gdt[g_num];
IDT idt[256];

TSS *tss_ptr;
int debug_mode = 0;
int self_contained;
long header_offset = 0;
int use_ansi=0;
int use_mono=0;
int redir_1_mono=0;
int redir_2_mono=0;
int redir_2_1=0;
int redir_1_2=0;

static FILE *core_log_file = stderr;
static char *corefile = NULL;

static int initial_argc;
int old_video_mode;
static int globbing=-1;
static int old_mask1, old_mask2;

int16 ems_handle=0;		/*  Get EMS Handle  */
word16 vcpi_installed = 0;	/*  VCPI Installed Flag  */
char use_DPMI = 0;
extern word32 DPMI_STACK;
word32 ARENA = 0x10000000L;

int ctrl_break_hit = 0;

extern word32 far *pd;

extern void far ivec0(void), ivec1(void);
extern void ivec7(void), ivec75(void);
extern void interrupt_common(void), page_fault(void);
extern void v74_handler(void), v78_handler(void), v79_handler(void);

void interrupt (*old_ctrlbrk)(void);

void set_command_line(char **argv);

int exitDPMI = 0;

char *exception_names[] = {
  "Division by Zero",
  "Debug",
  0,
  "Breakpoint",
  "Overflow",
  "Bounds Check",
  "Invalid Opcode",
  "Coprocessor not available",
  "Double Fault",
  "Coprocessor overrun",
  "Invalid TSS",
  "Segment Not Present",
  "Stack Fault",
  "General Protection Fault",
  "Page fault",
  0,
  "Coprocessor Error",
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  "Unsupported DOS request"
};
#define EXCEPTION_COUNT (sizeof(exception_names)/sizeof(exception_names[0]))

unsigned int cdecl _openfd[255] = {
  0x6001,0x7002,0x6002,0xa004,0xa002,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,
  0xffff,0xffff,0xffff,0xffff,0xffff,0xffff,0xffff
};

void bump_file_limit(void)
{
  if (((((int)_osmajor)<<8)|_osminor) < 0x0303)
    return;
  _AH = 0x67;
  _BX = 255;
  geninterrupt(0x21);
}

void initialize_printer(void)
{
  _BX=4;
  _AH=0x44;
  _AL=0x01;
  _DX=0xa0;
  geninterrupt(0x21);
  setmode(4, O_BINARY);
}

void fillgdt(int sel, word32 limit, word32 base, word8 type, int G)
{
  GDT_S *g;
  g = gdt+sel;
  if (G & 2)
    limit = limit >> 12;
  g->lim0 = limit & 0xffff;
  g->lim1 = (limit>>16) & 0x0f;
  g->base0 = base & 0xffff;
  g->base1 = (base>>16) & 0xff;
  g->base2 = (base>>24) & 0xff;
  g->stype = type;
  g->lim1 |= G * 0x40;
}

void setup_tss(TSS *t, void (*eip)())
{
  memset(t, 0, sizeof(TSS));
  t->tss_cs = g_rcode*8;
  t->tss_eip = (long)FP_OFF(eip);
  t->tss_ss = g_rdata*8;
  t->tss_esp = (long)FP_OFF(t->tss_stack);
  t->tss_ds = g_rdata*8;
  t->tss_es = g_rdata*8;
  t->tss_fs = g_rdata*8;
  t->tss_eflags = 0x0200;
  t->tss_iomap = 0xffff; /* no map */
}

void abort(void);

void my_abort()
{
  static int recursing = 0;
  if (recursing)
    _exit(1);
  recursing = 1;
  printf("Abort!\n");
  exit(1);
}

void exit_func(void)
{
  int i;
  dalloc_uninit();
  EventQueueDeInit();
  uninit_controllers();
  setvect(0x1b, old_ctrlbrk);
  _restorezero();
  if(!use_DPMI) {
    valloc_uninit();
    if ((ems_handle)&&(ems_handle != -1))
      ems_free(ems_handle);	/*  Deallocated EMS Page    */
    if (vcpi_installed)
      vcpi_flush();		/*  Deallocated VCPI Pages  */
  } else {
    DPMIprotectedMode();
    clearDPMIstate();
    restoreDPMIvector();
    uninitDPMI(exitDPMI);
  }
  if (topline_info)
    for (i=0; i<80; i++)
      poke(screen_seg, i*2, 0x0720);
  outportb(0x21, old_mask1);
  outportb(0xa1, old_mask2);
}

static void open_core_log(void)
{
  FILE *fp;

  if (corefile && ((fp = fopen(corefile, "at")) != NULL))
    {
      core_log_file = fp;
      fprintf(stderr,
	      "\nEXCEPTION OCCURRED!  Information dumped to core file:\n");
      fprintf(stderr, "    \"%s\"   \n", corefile);
      fprintf(core_log_file, "\n====================\n");
    }
  else
    {
      corefile = NULL;
      core_log_file = stderr;
    }
}

static void close_core_log(void)
{
  if (corefile)
    {
      fclose(core_log_file);
      corefile = NULL;
      core_log_file = stderr;
    }
}

void show_call_frame(void)
{
  word32 vbp,vbp_new, tos;
  int max=0;

  if (tss_ptr == &ed_tss)
    tos = 0xb0000000L;
  else
    tos = 0x90000000L;
  vbp = tss_ptr->tss_ebp;
  fprintf(core_log_file,
	  "Call frame traceback EIPs:\n  0x%08lx\n",tss_ptr->tss_eip);
  if (vbp == 0) return;
  do {
    vbp_new = peek32(vbp+ARENA);
    if (vbp_new == 0) break;
    fprintf(core_log_file,"  0x%08lx\n",peek32(vbp+ARENA+4));  /* EIP */
    vbp = vbp_new;
    if (++max == 10 && corefile)
      break;
  } while ((vbp >=tss_ptr->tss_esp) && (vbp < tos));
  /* 0x9000000 = areas[A_stack].last_addr for DPMI, but stack can be moved */
  
  if (corefile)
  {
    vbp = tss_ptr->tss_esp;
    fprintf(core_log_file, "\nContents of stack:\n");
    for(max=0; max<20; max++)
    {
      fprintf(core_log_file, "  stack[0x%08lx] = 0x%08lx\t", vbp, peek32(vbp+ARENA));
      vbp += 2;
      fprintf(core_log_file, "  stack[0x%08lx] = 0x%08lx\n", vbp, peek32(vbp+ARENA));
      vbp += 2;
    }
  }
}

void do_faulting_finish_message(int print_reason, int exit_code)
{
  if (peekb(0x40, 0x49) != old_video_mode)
  {
    _AX = old_video_mode;
    geninterrupt(0x10);
  }
  open_core_log();
  if (tss_ptr->tss_irqn == hard_master_lo+1)
  {
    fprintf(core_log_file, "Ctrl-%s Hit!  Stopped at address %lx\n",
      ctrl_break_hit ? "Break" : "C", tss_ptr->tss_eip);
    if (ctrl_break_hit)
      show_call_frame();
  }
  else
  {
    if (print_reason)
    {
      char *en = (tss_ptr->tss_irqn >= EXCEPTION_COUNT) ? 0 : exception_names[tss_ptr->tss_irqn];
      if (tss_ptr->tss_irqn == hard_slave_lo + 5)
	en = "Floating Point exception";
      if (en == 0)
	fprintf(core_log_file, "Exception %d (0x%02x) at eip=%lx\n",
		tss_ptr->tss_irqn, tss_ptr->tss_irqn, tss_ptr->tss_eip);
      else
	fprintf(core_log_file, "%s at eip=%lx\n", en, tss_ptr->tss_eip);
    }
    fprintf(core_log_file,
	    "eax=%08lx ebx=%08lx ecx=%08lx edx=%08lx esi=%08lx edi=%08lx\n",
	   tss_ptr->tss_eax,
	   tss_ptr->tss_ebx,
	   tss_ptr->tss_ecx,
	   tss_ptr->tss_edx,
	   tss_ptr->tss_esi,
	   tss_ptr->tss_edi);
    fprintf(core_log_file,
	    "ebp=%08lx esp=%08lx cs=%x ds=%x es=%x fs=%x gs=%x ss=%x cr2=%08x\n",
	   tss_ptr->tss_ebp,
	   tss_ptr->tss_esp,
	   tss_ptr->tss_cs,
	   tss_ptr->tss_ds,
	   tss_ptr->tss_es,
	   tss_ptr->tss_fs,
	   tss_ptr->tss_gs,
	   tss_ptr->tss_ss,
	   tss_ptr->tss_cr2);
    show_call_frame();
  }
  close_core_log();
  exit(exit_code);
}

int ctrl_c_flag = 0;

void interrupt ctrl_break_func(void)
{
  ctrl_break_hit = 1;
  tss_ptr->tss_irqn = hard_master_lo + 1;
  if (!in_hardware_interrupt)
    old_ctrlbrk();
}

int ctrlbrk_func(void)
{
  tss_ptr->tss_irqn = hard_master_lo + 1;
  do_faulting_finish_message(1,3);
  return 0;
}

char *char2rtype(word8 r, word8 relnum)
{
  static char buf[20];
  char *fmt = "";
  switch (r)
  {
    case 'a': fmt = ".alpha%d"; break;
    case 'b': fmt = ".beta%d"; break;
    case 'f': fmt = ""; break;
    case 'm': fmt = ".maint%d"; break;
    case 's': fmt = ".special%d"; break;
    default : fmt = ".unknown%d"; break;
  }
  sprintf(buf, fmt, relnum);
  return buf;
}

void usage(char *s)
{
  word32 lowest_ver = GO32_LOWEST_COMPATIBLE_VERSION;
  word8 *l = (word8 *)(&lowest_ver);
  use_mono = 0;
  fprintf(stderr, "Lowest version I can run is %d.%02d%s\n",
	  l[3], l[2], char2rtype(l[1], l[0]));
  if (initial_argc > 1)
    fprintf(stderr, "Invalid go32 usage running %s\n", s);
  fprintf(stderr, "go32.exe usage: go32 [-d {debugger}] [{program} [{options} . . . ]]\n");
  fprintf(stderr, "go32.exe build time was %s\n", build_time+8);
  show_memory_info = 1;
  if (use_DPMI)
  {
    DPMImaxmeminfo inf;
    DPMIprotectedMode();
    DPMImaxmem(&inf);
    DPMIrealMode();
    if (inf.physical_mem == -1 || inf.swap_mem == -1)
      fprintf(stderr, "DPMI virtual memory available: %ld Kb\n", inf.largest_block / 1024L);
    else
    {
      fprintf(stderr, "DPMI memory available: %ld Kb\n", inf.physical_mem * 4L);
      fprintf(stderr, "Swap space available: %ld Kb\n", inf.swap_mem * 4L);
    }
  }
  else
  {
    valloc_init();
    dalloc_init();
  }
  exit(1);
}

static void copyright(void)
{
  fprintf(stderr, "go32 version %d.%d%s Copyright (C) 1994 DJ Delorie\n",
	  GO32_MAJOR_VERSION,
	  GO32_MINOR_VERSION,
	  char2rtype(GO32_RELEASE_TYPE_C, GO32_RELEASE_NUMBER));
}

int have_80387;
int use_xms=0;
static word32 push32(void *ptr, int len);

void setup_idt_task(int which, int tss)
{
  idt[which].selector = tss*8;
  idt[which].stype = 0x8500;
  idt[which].offset0 = 0;
  idt[which].offset1 = 0;
}

void init(int argc, char **argv)
{
  int i, n, emu_installed=0;
  struct stat stbuf;
  char *cp, *path, *emu_fn=0;
  unsigned short header[3];
  char *external_debugger = 0;
  char *running_fname;
  DPMIinfo info;
  int disable_dpmi = 0;
  char *argv0_to_pass = argv[0];
  int need_to_free_argv0_to_pass = 0;
  char *argv0_to_run;
  unsigned psp_to_get_args_from = _psp;
  char *tb = (char *)transfer_buffer;

  initial_argc = argc;

  fprintf(stderr, "");
  fflush(stderr);
  fprintf(stdout, "");
  fflush(stdout);

  old_mask1 = inportb(0x21);
  old_mask2 = inportb(0xa1);

  /* make calls to abort() really call my_abort() */
  i = _CS;
  n = (int)(abort);
  pokeb(i, n, 0xe9);
  poke(i, n+1, (int)(my_abort) - (n + 3));

  cp = getenv("GO32");
  path = 0;
  if (cp)
    while (1)
    {
      char sw[100];
      char val[100];
      if (sscanf(cp, "%s%n", sw, &i) < 1)
	break;
      cp += i;
      if (stricmp(sw, "ansi") == 0)
	use_ansi = 1;
      else if (stricmp(sw, "topline") == 0)
	topline_info = 1;
      else if (stricmp(sw, "meminfo") == 0)
	show_memory_info = 1;
      else if (stricmp(sw, "mono") == 0)
	use_mono = 1;
      else if (stricmp(sw, "2r1") == 0)
	redir_2_1 = 1;
      else if (stricmp(sw, "1r2") == 0)
	redir_1_2 = 1;
      else if (stricmp(sw, "2rm") == 0)
	redir_2_mono = 1;
      else if (stricmp(sw, "1rm") == 0)
	redir_1_mono = 1;
      else if (stricmp(sw, "glob") == 0)
	globbing = 1;
      else if (stricmp(sw, "noglob") == 0)
	globbing = 0;
      else if (stricmp(sw, "nodpmi") == 0)
	disable_dpmi = 1;
      else
      {
	val[0] = 0;
	sscanf(cp, "%s%n", val, &i);
	cp += i;
	if (val[0] == 0)
	  break;
      }
      if (stricmp(sw, "driver") == 0)
      {
	if (path) free(path);
	path = strdup(val);
      }
      else if (stricmp(sw, "dpmistack") == 0)
	DPMI_STACK = (atol(val) + 0xfffL) & ~0xfffL;
      else if (stricmp(sw, "tw") == 0)
	gr_def_tw = atoi(val);
      else if (stricmp(sw, "th") == 0)
	gr_def_th = atoi(val);
      else if (stricmp(sw, "gw") == 0)
	gr_def_gw = atoi(val);
      else if (stricmp(sw, "gh") == 0)
	gr_def_gh = atoi(val);
      else if (stricmp(sw, "nc") == 0)
	gr_def_numcolor = atoi(val);
      else if (stricmp(sw, "core") == 0)
      {
	if (corefile)
	  free(corefile);
	corefile = strdup(val);
      }
      else if (stricmp(sw, "emu") == 0)
      {
	if (emu_fn) free(emu_fn);
	emu_fn = strdup(val);
      }
    }

  if (redir_1_2 && redir_1_2)
  {
    int save_stdout = dup(1);
    dup2(2, 1);
    dup2(save_stdout, 2);
    close(save_stdout);
  }
  else if (redir_2_1)
  {
    dup2(1, 2);
  }
  else if (redir_1_2)
  {
    dup2(2, 1);
  }

  if (peekb(0x40,0x49) == 7)
    screen_seg = 0xb000;
  if (!topline_info)
    use_mono = 0;
  if (use_mono)
    screen_seg = 0xb000;

  if (!disable_dpmi)
  {
    if (initDPMI(&info))
    {
      hard_master_lo = info.PIC.master;
      hard_slave_lo = info.PIC.slave;
      setDPMIvector();
      DPMIrealMode();
      use_DPMI = 1;
      ARENA = 0;
    }
  }
  if (!use_DPMI)
  {
    if (xms_installed())
      use_xms = 1;
  }

  bump_file_limit();
  old_video_mode = peekb(0x40, 0x49);

  if (strcmp(argv[1], "!proxy") == 0)
  {
    int a0seg, a0ofs, l;

    sscanf(argv[3], "%x", &a0seg);
    sscanf(argv[4], "%x", &a0ofs);
    a0ofs = peek(a0seg, a0ofs);
    for (l=0; peekb(a0seg, a0ofs+l); l++);
    argv0_to_pass = (char *)malloc(l+1);
    for (l=0; (argv0_to_pass[l] = peekb(a0seg, a0ofs+l)) != 0; l++);
    argv0_to_pass[l] = 0;
    need_to_free_argv0_to_pass = 1;

    if (argc > 6)
    {
      word32 this_version;
      static word8 tvp[4] = { GO32_RELEASE_NUMBER, GO32_RELEASE_TYPE_C, GO32_MINOR_VERSION, GO32_MAJOR_VERSION };
      int stubinfo_ofs, stubinfo_seg;
      int si_len = sizeof(StubInfo);
      StubInfo far *stubinfo_ptr;

      sscanf(argv[5], "%x", &stubinfo_seg);
      sscanf(argv[6], "%x", &stubinfo_ofs);
      stubinfo_ptr = (StubInfo far *)MK_FP(stubinfo_seg, stubinfo_ofs);
      if (si_len > (int)stubinfo_ptr->struct_length)
	si_len = (int)stubinfo_ptr->struct_length;
      movedata(stubinfo_seg, stubinfo_ofs, FP_SEG(&stub_info), FP_OFF(&stub_info), si_len);

      if (DPMI_STACK < stub_info.min_stack)
	DPMI_STACK = stub_info.min_stack;

      this_version = *(word32 *)tvp;

      if (stub_info.required_go32_version[1] == 's')
	if (required_go32_version_w(stub_info) != this_version)
	{
	  copyright();
	  fprintf(stderr, "Error: Special version (%d.%d.special%d) of go32 required to run this program.\n",
		  stub_info.required_go32_version[3],
		  stub_info.required_go32_version[2],
		  stub_info.required_go32_version[0]);
	  exit(1);
	}
      if (required_go32_version_w(stub_info) > this_version)
      {
	copyright();
	fprintf(stderr, "Error: This program requires a version of go32 (%d.%d%s) newer than this one.\n",
		stub_info.required_go32_version[3],
		stub_info.required_go32_version[2],
		char2rtype(stub_info.required_go32_version[1], stub_info.required_go32_version[0]));
	exit(1);
      }
      if (required_go32_version_w(stub_info) < GO32_LOWEST_COMPATIBLE_VERSION)
      {
	copyright();
	fprintf(stderr, "Error: This program requires a version of go32 (%d.%d%s) older than this one.\n",
		stub_info.required_go32_version[3],
		stub_info.required_go32_version[2],
		char2rtype(stub_info.required_go32_version[1], stub_info.required_go32_version[0]));
	exit(1);
      }
      
    }

    if (argc > 7)
      sscanf(argv[7], "%x", &psp_to_get_args_from);
  }

  if (globbing == -1)
    globbing = stub_info.enable_globbing;

  for (i=0; i<128; i++)
    tb[i] = peekb(psp_to_get_args_from, i+128);
  tb[tb[0]+1] = 0;
  __glob_args(tb+1, argv0_to_pass, globbing);
  argc = __glob_argc;
  argv = __glob_argv;
  if (need_to_free_argv0_to_pass)
    free(argv0_to_pass);

  if (!use_DPMI)
  {
    ems_handle = emm_present();
    switch (cputype())
    {
    case 1:
      if ((ems_handle)&&(ems_handle != -1))
	ems_free(ems_handle);
      fprintf(stderr, "CPU must be a 386 to run this program.\n");
      exit(1);
    case 2:
      if (ems_handle)
      {
	if ((vcpi_installed = vcpi_present()) != 0)
	  break;
	else if (ems_handle != -1)
	  ems_free(ems_handle);
      }
      fprintf(stderr, "CPU must be in REAL mode (not V86 mode) to run this program without VCPI.\n");
      fprintf(stderr, "(If you are using an EMS emulator, make sure that EMS isn't disabled)\n");
      exit(1);
    }
  }

  _fmode = O_BINARY;
  setup_graphics_driver(path);
  if (path) free(path);

  setbuf(stdin, 0);
  atexit((atexit_t)exit_func);
  ctrlbrk(ctrlbrk_func);
  old_ctrlbrk = getvect(0x1b);
  setvect(0x1b, ctrl_break_func);
  n = (int)ivec1-(int)ivec0;
  for (i=0; i<256; i++)
  {
    idt[i].selector = g_altc*8;
    idt[i].stype = 0x8e00;
    idt[i].offset0 = (int)FP_OFF(ivec0) + n*i;
    idt[i].offset1 = 0;
  }
  setup_idt_task(14, g_ptss);

  cp = getenv("387");
  if (cp)
    if (tolower(cp[0]) == 'n')
      have_80387 = 0;
    else if (tolower(cp[0]) == 'y')
      have_80387 = 1;
    else
      have_80387 = detect_80387();
  else
    have_80387 = detect_80387();

  if (cp && (tolower(cp[0]) == 'q'))
    if (have_80387)
      printf("An 80387 has been detected.\n");
    else
      printf("No 80387 has been detected.\n");

  fillgdt(g_zero, 0, 0, 0, 0);
  fillgdt(g_gdt, sizeof(gdt), ptr2linear(gdt), 0x92, 0);
  fillgdt(g_idt, sizeof(idt), ptr2linear(idt), 0x92, 0);
  fillgdt(g_rcode, 0xffff, (word32)_CS*16L, 0x9a, 0);
  fillgdt(g_rdata, 0xffff, (word32)_DS*16L, 0x92, 0);
  fillgdt(g_core, 0xffffffffL, 0, 0x92, 3);
  fillgdt(g_acode, 0xefffffffL, 0x10000000L, 0x9a, 3);
  fillgdt(g_adata, 0xefffffffL, 0x10000000L, 0x92, 3);
  fillgdt(g_ctss, sizeof(TSS), ptr2linear(&c_tss), 0x89, 1);
  fillgdt(g_atss, sizeof(TSS), ptr2linear(&a_tss), 0x89, 1);
  fillgdt(g_ptss, sizeof(TSS), ptr2linear(&p_tss), 0x89, 1);
  fillgdt(g_itss, sizeof(TSS), ptr2linear(&i_tss), 0x89, 1);
  fillgdt(g_rtss, sizeof(TSS), ptr2linear(&r_tss), 0x89, 1);
  fillgdt(g_rc32, 0xffff, (word32)_CS*16L, 0x9a, 3);
  /* CB change: this is done in "graphics.c" now */
  /* here this selector is initted such that we can set up a dummy paging */
  /* function until the first graphics mode set */
  /* also set up the selector for the BIOS data segment */
  /* OLD:
   *  fillgdt(g_grdr, 0xffff, (word32)gr_paging_segment*16L, 0x9a, 0);
   */
  fillgdt(g_BIOSdata, 0xffff, (word32)0x400, 0x92, 0);
  /* end CB change */
  fillgdt(g_v74, sizeof(TSS), ptr2linear(&v74_tss), 0x89, 1);
  fillgdt(g_v78, sizeof(TSS), ptr2linear(&v78_tss), 0x89, 1);
  fillgdt(g_v79, sizeof(TSS), ptr2linear(&v79_tss), 0x89, 1);
  fillgdt(g_altc, 0xffff, ((word32)FP_SEG(ivec0))*16L, 0x9a, 0);
  fillgdt(g_edcs, 0x0fffffffL, 0xa0000000L, 0x9a, 3);
  fillgdt(g_edds, 0x0fffffffL, 0xa0000000L, 0x92, 3);

  setup_tss(&c_tss, go_real_mode);
  setup_tss(&a_tss, go_real_mode);
  setup_tss(&o_tss, go_real_mode);
  setup_tss(&f_tss, go_real_mode);
  setup_tss(&ed_tss, go_real_mode);
  setup_tss(&r_tss, go_real_mode);
  setup_tss(&i_tss, interrupt_common);
  setup_tss(&p_tss, page_fault);
  setup_tss(&v74_tss, v74_handler);
  setup_tss(&v78_tss, v78_handler);
  setup_tss(&v79_tss, v79_handler);
  tss_ptr = &a_tss;

  a_tss.tss_edx = ptr2linear(&prog_info);
  prog_info.size_of_this_structure_in_bytes = sizeof(PROGINFO);
  prog_info.pid = 42;
  transfer_linear =
    prog_info.linear_address_of_transfer_buffer = ptr2linear(transfer_buffer) + 0xe0000000L;
  prog_info.size_of_transfer_buffer = 4096L;
  prog_info.linear_address_of_stub_info_structure = ptr2linear(&stub_info) + 0xe0000000L;
  prog_info.linear_address_of_original_psp = (word32)_psp*16L + 0xe0000000L;
  prog_info.run_mode = _GO32_RUN_MODE_UNDEF;
  prog_info.run_mode_info = 0;

  core_selector =
    a_tss.tss_gs =
      prog_info.selector_for_linear_memory = (word16)(g_core * 8L);

  /*  a_tss.tss_esi = 42; */ /* PID */
  if(use_DPMI)
  {
    a_tss.tss_edi = 0;
    prog_info.run_mode = _GO32_RUN_MODE_DPMI;
    prog_info.run_mode_info = (info.version.major << 8)
      | ((info.version.minor/10) << 4)
	| (info.version.minor%10);
  }
  else
    a_tss.tss_edi = ptr2linear(transfer_buffer) + 0xe0000000L;

  argv0_to_pass = argv[0];
  for (i=0; argv0_to_pass[i]; i++)
  {
    if (argv0_to_pass[i] == '\\')
      argv0_to_pass[i] = '/';
    argv0_to_pass[i] = tolower(argv0_to_pass[i]);
  }

  if (topline_info)
    for (i=0; i<80; i++)
      poke(screen_seg, i*2, 0x0720);

  if (stub_info.actual_file_to_run[0])
  {
    char *cp;
    argv0_to_run = (char *)malloc(strlen(argv0_to_pass) + 13);
    strcpy(argv0_to_run, argv0_to_pass);
    for (cp = argv0_to_run + strlen(argv0_to_run) - 1; cp > argv0_to_run; cp--)
      if (cp[-1] == '/' || cp[-1] == '\\' || cp[-1] == ':')
	break;
    strcpy(cp, stub_info.actual_file_to_run);
    if (access(argv0_to_run, 0))
    {
      strcat(cp, ".exe");
      if (access(argv0_to_run, 0))
	cp[strlen(cp)-4] = 0;	/* remove the .exe */
    }
  }
  else
  {
    argv0_to_run = argv0_to_pass;
  }

  if (emu_fn == NULL && !have_80387)
  {
    char *emu_try, *last_slash;

    /* If no emu_fn specified, and no 80387 is  present, check for an
     * "emu387" file in the  same directory as the extender.  If we find
     * one, we will use that as the 80387 emulator.  Otherwise,
     * no 80387 emulation.
     */

    /* Grab the directory containing the extender and append emu387. */
    last_slash = strrchr (argv0_to_run, '/');
    if (last_slash != NULL)
    {
      int path_len = last_slash - argv0_to_run + 1; /* Length incl. '/' */
      emu_try = (char *) malloc (path_len + 7);
      strncpy (emu_try, argv0_to_run, path_len);
      strcpy (emu_try + path_len, "emu387");
    }
    else
      emu_try = strdup ("emu387");

    if (!stat (emu_try, &stbuf))
      emu_fn = emu_try;		/* Found it. */
    else
      free (emu_try);		/* Nope. */
  }


  self_contained = 0;
  n = open(argv0_to_run, O_RDONLY|O_BINARY);
  header[0] = 0;
  read(n, header, sizeof(header));
  if (header[0] == 0x5a4d)
  {
    word32 stub_offset;
    header_offset = (long)header[2]*512L;
    if (header[1])
      header_offset += (long)header[1] - 512L;
    lseek(n, header_offset - 4, 0);
    read(n, &stub_offset, 4);
    header[0] = 0;
    read(n, header, sizeof(header));
    if (header[0] == 0x010b)
      self_contained = 1;
    if (header[0] == 0x014c)
      self_contained = 1;
  }
  close(n);

  if (self_contained)
  {
    paging_set_file(argv0_to_run);
    running_fname = argv0_to_run;
    emu_installed = emu_install(emu_fn);
    set_command_line(argv);
  }
  else
  {
    header_offset = 0;
    for (cp=argv0_to_run; *cp; cp++)
    {
      if (*cp == '.')
	path = cp;
      if (*cp == '/' || *cp == '\\')
	path = 0;
    }
    if (path)
      *path = 0;
    if (stat(argv0_to_run, &stbuf)) /* not found */
    {
      copyright();
      if (strcmp(argv[1], "-d") == 0 && argc > 2)
      {
        debug_mode = 1;
	external_debugger = argv[2];
	argv += 2;
	argc -= 2;
      }
      if (argv[1] == 0)
	usage(argv0_to_pass);
      paging_set_file(argv[1]);
      running_fname = argv[1];
      emu_installed = emu_install(emu_fn);
      set_command_line(argv+1);
    }
    else			/* found */
    {
      paging_set_file(argv0_to_run);
      running_fname = argv0_to_run;
      emu_installed = emu_install(emu_fn);
      set_command_line(argv);
    }
  }

  dalloc_init();
  init_controllers();
  if (have_80387)
  {
    idt[7].selector = g_rcode*8;
    idt[7].offset0 = (int)ivec7;
    idt[7].offset1 = 0;
    idt[hard_slave_lo+5].selector = g_rcode*8;
    idt[hard_slave_lo+5].offset0 = (int)ivec75;
    idt[hard_slave_lo+5].offset1 = 0;
  }

  setup_idt_task(0x74, g_v74);
  setup_idt_task(hard_master_lo, g_v78);
  setup_idt_task(hard_master_lo+1, g_v79);

  if(!use_DPMI)
    a_tss.tss_eax = (g_core*8L)<<16;
  a_tss.tss_eax |= (word32)hard_master_lo | (((word32)hard_slave_lo)<<8);

  prog_info.master_interrupt_controller_base = (word8)hard_master_lo;
  prog_info.slave_interrupt_controller_base = (word8)hard_slave_lo;

  if (external_debugger)
    load_external_debugger(external_debugger, running_fname, argv0_to_pass);

  if (emu_installed)
  {
    push32(&(a_tss.tss_eip), 4);
    a_tss.tss_eip = emu_start_ip();
  }
}

void main(int argc, char **argv)
{
  init(argc, argv);
  go_til_stop(0);
  do_faulting_finish_message(1,1);
}

static word32 push32(void *ptr, int len)
{
  if ((a_tss.tss_esp & ~0xFFF) != ((a_tss.tss_esp-len) & ~0xFFF))
  {
    a_tss.tss_cr2 = a_tss.tss_esp - len + ARENA;
    page_in();
  }
  a_tss.tss_esp -= len;
  a_tss.tss_esp = a_tss.tss_esp & (~3);
  memput(a_tss.tss_esp+ARENA, ptr, len);
  return a_tss.tss_esp;
}

static int num_actual_args;

static word32 *a;

void pusharg(char *ar)
{
  int s = strlen(ar);
  if ((ar[0] == '\'') && (ar[s-1] == '\''))
  {
    ar[s-1] = '\0';
    ar++;
  }
  a[num_actual_args] = push32(ar, s+1);
  num_actual_args++;
}

void set_command_line(char **argv)
{
  char **envv;
  unsigned envc, envc32;
  word32 *e, v, argp, envp, *a;
  int argc;

  a_tss.tss_cr2 = a_tss.tss_esp + ARENA;
  page_in();

  __glob_env(argv[0]);
  envv = environ;
  for (envc=0; envv[envc]; envc++);
  if (envc > 1000)
  {
    fprintf(stderr, "Fatal! no memory to copy environment (max 1000, wanted %d)\n", envc);
    exit(1);
  }
  e = (word32 *)transfer_buffer;
  envc32 = 0;
  for (envc=0; envv[envc]; envc++)
  {
    char *sp, *dp;
    int state = 0;
    sp = dp = envv[envc];
    while (*sp)
    {
      switch (state)
      {
        case 0: /* waiting for '=' */
          if (!isspace(*sp))
            *dp++ = *sp;
          if (*sp == '=')
            state = 1;
          break;
        case 1: /* got '=' */
          if (!isspace(*sp))
          {
            *dp++ = *sp;
            state = 2;
          }
          break;
        case 2: /* in value */
          *dp++ = *sp;
          break;
      }
      sp++;
    }
    while (dp > envv[envc] && isspace(dp[-1]))
      *--dp = 0;
    if (state != 0) /* else there was no '=', POSIX says we have to have one */
    {
      v = push32(envv[envc], strlen(envv[envc])+1);
      e[envc32++] = v;
    }
  }
  e[envc32++] = 0;
  envp = push32(e, (envc32)*sizeof(word32));

  a = (word32 *)transfer_buffer;
  if (argc > 1000)
  {
    fprintf(stderr, "Fatal! no memory to copy arguments (max 1000, wanted %d)\n", argv);
    exit(1);
  }
  for (argc=0; argv[argc]; argc++)
    a[argc] = push32(argv[argc], strlen(argv[argc])+1);
  a[argc] = 0;
  argp = push32(a, (argc+1)*sizeof(word32));

  push32(&envp, sizeof(word32));
  push32(&argp, sizeof(word32));
  v = argc;
  push32(&v, sizeof(word32));
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.