diff --git a/aspi/ASPI.C b/aspi/ASPI.C
new file mode 100644
index 0000000..c6ed586
--- /dev/null
+++ b/aspi/ASPI.C
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include <windows.h>
+
+extern WORD GetASPISupportInfo(VOID);
+
+
+int main()
+
+{
+
+ WORD	ASPIStatus;
+ BYTE	NumAdapters;
+ HWND	hwnd;
+
+ ASPIStatus = GetASPISupportInfo();
+
+ switch (HIBYTE(ASPIStatus))
+ 	{
+	 case	SS_COMP:
+	 break;
+
+	 default:
+	 break;
+	}
+}
diff --git a/aspi/ASPI.EXE b/aspi/ASPI.EXE
new file mode 100644
index 0000000..5bb8d96
--- /dev/null
+++ b/aspi/ASPI.EXE
Binary files differ
diff --git a/aspi/ASPI.MAK b/aspi/ASPI.MAK
new file mode 100644
index 0000000..fdea5ee
--- /dev/null
+++ b/aspi/ASPI.MAK
@@ -0,0 +1,145 @@
+# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+!IF "$(CFG)" == ""
+CFG=Win32 Debug
+!MESSAGE No configuration specified.  Defaulting to Win32 Debug.
+!ENDIF 
+
+!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line.  For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "aspi.mak" CFG="Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE 
+!ERROR An invalid configuration is specified.
+!ENDIF 
+
+################################################################################
+# Begin Project
+CPP=cl.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+OUTDIR=.
+INTDIR=.
+
+ALL : $(OUTDIR)/aspi.exe $(OUTDIR)/aspi.bsc
+
+# ADD BASE CPP /nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
+# ADD CPP /nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c
+CPP_PROJ=/nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\
+ /FR$(INTDIR)/ /Fp$(OUTDIR)/"aspi.pch" /Fo$(INTDIR)/ /c 
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+BSC32_SBRS= \
+	$(INTDIR)/aspi.sbr
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o$(OUTDIR)/"aspi.bsc" 
+
+$(OUTDIR)/aspi.bsc : $(OUTDIR)  $(BSC32_SBRS)
+    $(BSC32) @<<
+  $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+DEF_FILE=
+LINK32_OBJS= \
+	$(INTDIR)/aspi.obj
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no\
+ /PDB:$(OUTDIR)/"aspi.pdb" /MACHINE:I386 /OUT:$(OUTDIR)/"aspi.exe" 
+
+$(OUTDIR)/aspi.exe : $(OUTDIR)  $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+OUTDIR=.
+INTDIR=.
+
+ALL : $(OUTDIR)/aspi.exe $(OUTDIR)/aspi.bsc
+
+# ADD BASE CPP /nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
+# ADD CPP /nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c
+CPP_PROJ=/nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\
+ /FR$(INTDIR)/ /Fp$(OUTDIR)/"aspi.pch" /Fo$(INTDIR)/ /Fd$(OUTDIR)/"aspi.pdb" /c 
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+BSC32_SBRS= \
+	$(INTDIR)/aspi.sbr
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o$(OUTDIR)/"aspi.bsc" 
+
+$(OUTDIR)/aspi.bsc : $(OUTDIR)  $(BSC32_SBRS)
+    $(BSC32) @<<
+  $(BSC32_FLAGS) $(BSC32_SBRS)
+<<
+
+LINK32=link.exe
+DEF_FILE=
+LINK32_OBJS= \
+	$(INTDIR)/aspi.obj
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\
+ /PDB:$(OUTDIR)/"aspi.pdb" /DEBUG /MACHINE:I386 /OUT:$(OUTDIR)/"aspi.exe" 
+
+$(OUTDIR)/aspi.exe : $(OUTDIR)  $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF 
+
+.c.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+################################################################################
+# Begin Group "Source Files"
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\aspi.c
+
+$(INTDIR)/aspi.obj :  $(SOURCE)  $(INTDIR)
+
+# End Source File
+# End Group
+# End Project
+################################################################################
diff --git a/aspi/ASPI.OBJ b/aspi/ASPI.OBJ
new file mode 100644
index 0000000..56fe22a
--- /dev/null
+++ b/aspi/ASPI.OBJ
Binary files differ
diff --git a/aspi/ASPI.PDB b/aspi/ASPI.PDB
new file mode 100644
index 0000000..81b8d52
--- /dev/null
+++ b/aspi/ASPI.PDB
Binary files differ
diff --git a/aspi/ASPI.VCP b/aspi/ASPI.VCP
new file mode 100644
index 0000000..f50f985
--- /dev/null
+++ b/aspi/ASPI.VCP
Binary files differ
diff --git a/border/BORDER.C b/border/BORDER.C
new file mode 100644
index 0000000..ef69106
--- /dev/null
+++ b/border/BORDER.C
@@ -0,0 +1,33 @@
+/*  BORDER.C - Draws user selected border
+				Last Modified: 06/19/86
+				Copyright (C) 1986,  T.A. Daneliuk
+*/
+
+#include	<system.h>
+
+
+void	border(startv,starth,width,height,vattrib)
+
+char	vattrib;
+int		startv,starth,width,height;
+{
+int	x;
+
+	v_rowcol(startv,starth);
+	scr_aputs(mkstr(BORDERNW,1),vattrib);
+	scr_aputs(mkstr(BORDERH,width-2),vattrib);
+	scr_aputs(mkstr(BORDERNE,1),vattrib);
+	v_rowcol(startv+height-1,starth);
+	scr_aputs(mkstr(BORDERSW,1),vattrib);
+	scr_aputs(mkstr(BORDERH,width-2),vattrib);
+	scr_aputs(mkstr(BORDERSE,1),vattrib);
+
+	for (x=startv+1;x<=(startv+height-2);x++)
+		{
+			v_rowcol(x,starth);
+			scr_aputs(mkstr(BORDERV,1),vattrib);
+			v_rowcol(x,starth+width-1);
+			scr_aputs(mkstr(BORDERV,1),vattrib);
+		}
+		
+}
diff --git a/bplus/BPLUS.C b/bplus/BPLUS.C
new file mode 100644
index 0000000..5f29858
--- /dev/null
+++ b/bplus/BPLUS.C
@@ -0,0 +1,948 @@
+/********************************************************************/
+/*                                                                  */
+/*             BPLUS file indexing program - Version 1.1A           */
+/*                                                                  */
+/*                      A "shareware program"                       */
+/*                                                                  */
+/*                                                                  */
+/*                      Copyright (C) 1987 by                       */
+/*                                                                  */
+/*                      Hunter and Associates                       */
+/*                      7050 NW Zinfandel Lane                      */
+/*                      Corvallis, Oregon  97330                    */
+/*                      (503) 745 - 7186                            */
+/*                                                                  */
+/********************************************************************/
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys\types.h>            /*  delete this line for Turbo C  */
+#include <sys\stat.h>
+#include <string.h>
+#include "bplus.h"
+
+
+/*  macros, constants, data types  */
+
+#define  NULLREC      (-1L)
+#define  FREE_BLOCK   (-2)
+
+#define  ENT_ADR(pb,off)  ((ENTRY*)((char*)((pb)->entries) + off))
+#define  ENT_SIZE(pe)     strlen((pe)->key) + 1 + 2 * sizeof(RECPOS)
+#define  BUFDIRTY(j)      (mci->cache[j].dirty)
+#define  BUFHANDLE(j)     (mci->cache[j].handle)
+#define  BUFBLOCK(j)      (mci->cache[j].mb)
+#define  BUFCOUNT(j)      (mci->cache[j].count)
+#define  CB(j)            (pci->pos[j].cblock)
+#define  CO(j)            (pci->pos[j].coffset)
+
+                                    /* BPLUS uses the library routine    */
+                                    /* memmove which must be used with   */
+                                    /* Turboc 1.5, Quick C and MS C 5.0  */
+/* #define memmove    memcpy */     /* Use this macro for Microsoft C4.0 */
+
+/*  declare some global variables  */
+
+IX_DESC      *pci;
+IX_BUFFER    bt_buffer;
+IX_BUFFER    *mci = &bt_buffer;
+BLOCK        *block_ptr;
+BLOCK        *spare_block;
+int          cache_ptr = 0;
+int          cache_init = 0;
+int          split_size = IXB_SPACE;
+int          comb_size  = (IXB_SPACE/2);
+
+void pascal error(int, long);
+void pascal read_if(long, char *, int);
+void pascal write_if(int, long, char *, int);
+int  pascal creat_if(char *);
+int  pascal open_if(char *);
+void pascal close_if(int);
+void pascal update_block(void);
+void pascal init_cache(void);
+int  pascal find_cache(RECPOS);
+int  pascal new_cache(void);
+void pascal load_cache(RECPOS);
+void pascal get_cache(RECPOS);
+void pascal retrieve_block(int, RECPOS);
+int  pascal prev_entry(int);
+int  pascal next_entry(int);
+void pascal copy_entry(ENTRY *, ENTRY *);
+int  pascal scan_blk(int);
+int  pascal last_entry(void);
+void pascal write_free( RECPOS, BLOCK *);
+RECPOS pascal get_free(void);
+int  pascal find_block(ENTRY *, int *);
+void pascal movedown(BLOCK *, int, int);
+void pascal moveup(BLOCK *, int, int);
+void pascal ins_block(BLOCK *, ENTRY *, int);
+void pascal del_block(BLOCK *, int);
+void pascal split(int, ENTRY *, ENTRY *);
+void pascal ins_level(int, ENTRY *);
+int  pascal insert_ix(ENTRY *, IX_DESC *);
+int  pascal find_ix(ENTRY *, IX_DESC *, int);
+int  pascal combineblk(RECPOS, int);
+void pascal replace_entry(ENTRY *);
+void print_blk(BLOCK *);
+
+
+/*  file I/O for B-PLUS module  */
+
+void pascal error(j, l)
+  int j;
+  long l;
+  {
+    static char *msg[3] = {"ERROR - CANNOT OPEN/CLOSE FILE",
+                           "ERROR WHILE READING FILE",
+                           "ERROR WHILE WRITING FILE"};
+    printf("\n  %s - Record Number %ld\n", msg[j], l);
+    exit(1);
+  } /* error */
+
+
+void pascal read_if(start, buf, nwrt)
+  long start;
+  char *buf;
+  int nwrt;
+  {
+    long err;
+    err = start - lseek(pci->ixfile, start, SEEK_SET);
+    if (err == 0) err = nwrt - read(pci->ixfile, buf, nwrt);
+    if (err != 0) error(1, start);
+  } /* read_if */
+
+
+void pascal write_if(handle, start, buf, nwrt)
+  int handle;
+  long start;
+  char *buf;
+  int nwrt;
+  {
+    long err;
+    err = start - lseek(handle, start, SEEK_SET);
+    if (err == 0) err = nwrt - write(handle, buf, nwrt);
+    if (err != 0) error(2, start);
+  } /* write_if */
+
+
+int pascal creat_if(fn)
+  char *fn;
+  {
+    int   ret;
+    ret = open(fn,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IWRITE);
+    if (ret  < 0) error(0,0L);
+    return (ret);
+  } /* creat_if */
+
+
+int pascal open_if(fn)
+  char *fn;
+  {
+    int  ret;
+    ret = open(fn,O_RDWR|O_BINARY);
+    if (ret < 1) error(0,0L);
+    return (ret);
+  } /* open_if */
+
+
+void pascal close_if(handle)
+  int handle;
+  {
+    if(close(handle) < 0)  error(2,0L);
+  } /*  close_if */
+
+
+int cdecl open_index(name, pix, dup)
+  char *name;
+  IX_DESC *pix;
+  int dup;
+  {
+    pci = pix;
+    pci->ixfile = open_if(name);
+    pci->duplicate = dup;
+    read_if(0L,(char *)&(pix->root), (sizeof(BLOCK) + sizeof(IX_DISK)));
+    if (!cache_init)
+      {
+        init_cache();
+        cache_init = 1;
+      }
+    first_key(pix);
+    return ( IX_OK );
+  } /* open_index */
+
+
+int cdecl close_index(pix)
+  IX_DESC *pix;
+  {
+    int i;
+    write_if(pix->ixfile, 0L,(char *)&(pix->root),
+               (sizeof(BLOCK) + sizeof(IX_DISK)));
+    for (i = 0; i < NUM_BUFS; i++)
+      if (BUFHANDLE(i) == pix->ixfile)
+        {
+          if (BUFDIRTY(i))
+            {
+              write_if(BUFHANDLE(i),
+                       BUFBLOCK(i).brec,
+                       (char *) &BUFBLOCK(i),
+                       sizeof(BLOCK));
+              BUFDIRTY(i) = 0;
+            }
+          BUFBLOCK(i).brec = NULLREC;
+      }
+    close_if(pix->ixfile);
+    return( IX_OK );
+  } /* close_index */
+
+
+int cdecl make_index(name, pix, dup)
+  char *name;
+  IX_DESC *pix;
+  int dup;
+  {
+    pci = pix;
+    pci->ixfile = creat_if(name);
+    pci->duplicate = dup;
+    pci->dx.nl = 1;
+    pci->dx.ff = NULLREC;
+    pci->level = 0;
+    CO(0) = -1;
+    CB(0) = 0L;
+    pci->root.brec = 0L;
+    pci->root.bend = 0;
+    pci->root.p0 = NULLREC;
+    write_if(pci->ixfile, 0L,(char *)&(pix->root),
+               (sizeof(BLOCK) + sizeof(IX_DISK)));
+    if (!cache_init)
+      {
+        init_cache();
+        cache_init = 1;
+      }
+    first_key(pix);
+    return ( IX_OK );
+  } /* make_index */
+
+
+/*  cache I/O for BPLUS  */
+
+void pascal update_block()
+  {
+    if (block_ptr != &(pci->root))
+       BUFDIRTY(cache_ptr) = 1;
+  } /* update_block */
+
+
+void pascal init_cache()
+  {
+    register int  j;
+    for (j = 0; j < NUM_BUFS; j++)
+      {  BUFDIRTY(j) = 0;
+         BUFCOUNT(j) = 0;
+         BUFBLOCK(j).brec = NULLREC;
+      }
+  } /* init_cache */
+
+
+int pascal find_cache(r)
+  RECPOS r;
+  {
+    register int  j;
+    for (j = 0; j < NUM_BUFS; j++)
+      {
+        if((BUFBLOCK(j).brec == r) && (BUFHANDLE(j) == pci->ixfile))
+         {  cache_ptr = j;
+            return (1);
+      }  }
+    return (-1);
+  } /* find_cache */
+
+
+int pascal new_cache()
+  {
+    register int  i;
+    i = (cache_ptr + 1) % NUM_BUFS;
+    if (BUFDIRTY(i)) write_if(BUFHANDLE(i),
+                              BUFBLOCK(i).brec,
+                              (char *) &BUFBLOCK(i),
+                              sizeof(BLOCK));
+    BUFHANDLE(i) = pci->ixfile;
+    BUFDIRTY(i) = 0;
+    return (i);
+  } /* new_cache */
+
+
+void pascal load_cache(r)
+  RECPOS r;
+  {
+    cache_ptr = new_cache();
+    read_if(r, (char *)&BUFBLOCK(cache_ptr), sizeof(BLOCK));
+  } /* load_cache */
+
+
+void pascal get_cache(r)
+  RECPOS r;
+  {
+    if (find_cache(r) < 0)
+       load_cache(r);
+    block_ptr = &BUFBLOCK(cache_ptr);
+  } /* get_cache */
+
+
+void pascal retrieve_block(j, r)
+  int j;
+  RECPOS r;
+  {
+    if (j == 0)
+       block_ptr = &(pci->root);
+    else  get_cache(r);
+    CB(j) = block_ptr->brec;
+  } /* retrieve_block */
+
+
+/*  low level functions of BPLUS  */
+
+int pascal prev_entry(off)
+  int off;
+  {
+     if (off <= 0)
+       {
+         off = -1;
+         CO(pci->level) = off;
+       }
+     else
+       off = scan_blk(off);
+     return(off);
+  } /* prev_entry */
+
+
+int pascal next_entry(off)
+  int off;
+  {
+     if (off == -1)
+       off = 0;
+     else
+       {
+         if (off < block_ptr->bend)
+            off += ENT_SIZE(ENT_ADR(block_ptr,off));
+       }
+     CO(pci->level) = off;
+     return (off);
+  } /* next_entry */
+
+
+void pascal copy_entry(to, from)
+  ENTRY *to;
+  ENTRY *from;
+  {
+    int me;
+    me = ENT_SIZE(from);
+    memmove(to, from, me);
+  } /* copy_entry */
+
+
+int pascal scan_blk(n)
+  int n;
+  {
+     register int off, last;
+     off = 0;
+     last = -1;
+     while (off < n )
+       {  last = off;
+          off += ENT_SIZE(ENT_ADR(block_ptr,off));
+       }
+     CO(pci->level) = last;
+     return (last);
+  } /* scan_blk */
+
+
+int pascal last_entry()
+  {
+     return( scan_blk(block_ptr->bend) );
+  } /* last_entry */
+
+
+/*  maintain list of free index blocks  */
+
+void pascal write_free(r, pb)
+  RECPOS r;
+  BLOCK *pb;
+  {
+    pb->p0 = FREE_BLOCK;
+    pb->brec = pci->dx.ff;
+    write_if(pci->ixfile, r, (char *) pb, sizeof(BLOCK));
+    pci->dx.ff = r;
+  } /* write_free */
+
+
+RECPOS pascal get_free()
+  {
+    RECPOS  r, rt;
+
+    r = pci->dx.ff;
+    if ( r != NULLREC )
+      {  read_if(r, (char *)&rt, sizeof( RECPOS ));
+         pci->dx.ff = rt;
+      }
+    else
+      r = filelength (pci->ixfile);
+    return (r);
+  } /* get_free */
+
+
+/*  general BPLUS block level functions  */
+
+int pascal find_block(pe, poff)
+  ENTRY *pe;
+  int *poff;
+  {
+    register int pos, nextpos, ret;
+    pos = -1;
+    nextpos = 0;
+    ret = 1;
+    while ( nextpos < block_ptr->bend)
+      {
+        ret = strcmp((char *)(pe->key),
+                     (char *)(ENT_ADR(block_ptr, nextpos)->key));
+        if (ret <= 0)
+          {
+             if (ret == 0) pos = nextpos;
+             break;
+          }
+        pos = nextpos;
+        nextpos = next_entry(pos);
+      }
+    CO(pci->level) = pos;
+    *poff = pos;
+    return (ret);
+  } /* find_block */
+
+
+void pascal movedown(pb, off, n)
+  BLOCK *pb;
+  int off;
+  int n;
+  {
+    memmove(ENT_ADR(pb, off),
+           ENT_ADR(pb, off + n),
+           pb -> bend - (off + n));
+  } /* movedown */
+
+
+void pascal moveup(pb, off, n)
+  BLOCK *pb;
+  int off;
+  int n;
+  {
+    memmove(ENT_ADR(pb, off + n),
+            ENT_ADR(pb, off),
+            pb->bend - off);
+  } /* moveup */
+
+
+void pascal ins_block(pb, pe, off)
+  BLOCK *pb;
+  ENTRY *pe;
+  int off;
+  {
+    int size;
+    size = ENT_SIZE(pe);
+    moveup(pb,off,size);
+    copy_entry(ENT_ADR(pb,off),pe);
+    pb->bend += size;
+  } /* ins_block */
+
+
+void pascal del_block(pb, off)
+  BLOCK *pb;
+  int off;
+  {
+    int ne;
+    ne = ENT_SIZE(ENT_ADR(pb, off));
+    movedown(pb, off, ne);
+    pb->bend -= ne;
+  } /* del_block */
+
+
+/*  position at start/end of index  */
+
+int cdecl first_key(pix)
+  IX_DESC *pix;
+  {
+    pci = pix;
+    block_ptr = &(pci->root);
+    CB(0) = 0L;
+    CO(0) = -1;
+    pci->level = 0;
+    while(block_ptr->p0 != NULLREC)
+      {
+        retrieve_block(++(pci->level), block_ptr->p0);
+        CO(pci->level) = -1;
+      }
+    return ( IX_OK );
+  } /* first_key */
+
+
+int cdecl last_key(pix)
+  IX_DESC *pix;
+  {
+    long  ads;
+    pci = pix;
+    block_ptr = &(pci->root);
+    CB(0) = 0L;
+    pci->level = 0;
+    if(last_entry() >= 0)
+      {
+        while ((ads = ENT_ADR(block_ptr,last_entry())->idxptr) != NULLREC)
+             retrieve_block(++(pci->level), ads);
+      }
+    CO(pci->level) = block_ptr->bend;
+    return ( IX_OK );
+  } /* last_key */
+
+
+/*  get next, previous entries  */
+
+int cdecl next_key(pe, pix)
+  ENTRY *pe;
+  IX_DESC *pix;
+  {
+    RECPOS  address;
+    pci = pix;
+    retrieve_block(pci->level, CB(pci->level));
+    if(CO(pci->level) == -1) address = block_ptr->p0;
+    else
+     {
+       if (CO(pci->level) == block_ptr->bend) address = NULLREC;
+       else  address = ENT_ADR(block_ptr, CO(pci->level))->idxptr;
+     }
+    while (address != NULLREC)
+      {
+         retrieve_block(++(pci->level), address);
+         CO(pci->level) = -1;
+         address = block_ptr->p0;
+      }
+    next_entry(CO(pci->level));
+    if (CO(pci->level) == block_ptr->bend)
+      {
+        do
+          { if(pci->level == 0)
+              {
+                last_key(pci);
+                return (EOIX);
+              }
+            --(pci->level);
+            retrieve_block(pci->level, CB(pci->level));
+            next_entry(CO(pci->level));
+          } while (CO(pci->level) == block_ptr->bend);
+      }
+    copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level)));
+    return ( IX_OK );
+  } /* next_key */
+
+
+int cdecl prev_key(pe, pix)
+  ENTRY *pe;
+  IX_DESC *pix;
+  {
+    RECPOS  address;
+    pci = pix;
+    retrieve_block(pci->level, CB(pci->level));
+    prev_entry(CO(pci->level));
+    if (CO(pci->level) == -1)
+      address = block_ptr->p0;
+    else
+      address = ENT_ADR(block_ptr, CO(pci->level))->idxptr;
+    if (address != NULLREC)
+      { do
+          {
+            retrieve_block(++(pci->level), address);
+            address = ENT_ADR(block_ptr, last_entry())->idxptr;
+          } while (address != NULLREC);
+      }
+    if (CO(pci->level) == -1)
+      { do
+          {
+            if(pci->level == 0)
+              {
+                first_key(pci);
+                return (EOIX);
+              }
+            --(pci->level);
+          } while (CO(pci->level) == -1);
+        retrieve_block(pci->level, CB(pci->level));
+      }
+    copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level)));
+    return ( IX_OK );
+  } /* prev_key */
+
+
+/*  insert new entries into tree  */
+
+void pascal split(l, pe, e)
+  int l;
+  ENTRY *pe;
+  ENTRY *e;
+  {
+    int  half, ins_pos, size;
+    ins_pos = CO(pci->level);
+    half = scan_blk(block_ptr->bend / 2 + sizeof(RECPOS));
+    if (half == ins_pos)
+      *e = *pe;
+    else
+      {
+         copy_entry(e, ENT_ADR(block_ptr, half));
+         size = ENT_SIZE(e);
+         movedown(block_ptr, half, size);
+         block_ptr->bend -= size;
+      }
+    spare_block = &BUFBLOCK(new_cache());
+    memmove(spare_block->entries,
+           ENT_ADR(block_ptr,half),
+           block_ptr->bend - half);
+    spare_block->brec = get_free();
+    spare_block->bend = block_ptr->bend - half;
+    spare_block->p0 = e->idxptr;
+    block_ptr->bend = half;
+    e->idxptr = spare_block->brec;
+    if (ins_pos < half)
+      ins_block(block_ptr,pe,ins_pos);
+    else if (ins_pos > half)
+      {
+         ins_pos -= ENT_SIZE(e);
+         ins_block(spare_block,pe,ins_pos - half);
+         CB(l) = e->idxptr;
+         CO(l) = CO(l) - half;
+      }
+    write_if(pci->ixfile, spare_block->brec,
+             (char *) spare_block, sizeof(BLOCK));
+  } /* split */
+
+
+void pascal ins_level(l, e)
+  int l;
+  ENTRY *e;
+  {
+    int  i;
+    if ( l < 0)
+      {  for (i = 1; i < MAX_LEVELS; i++)
+           {  CO(MAX_LEVELS - i) = CO(MAX_LEVELS - i - 1);
+              CB(MAX_LEVELS - i) = CB(MAX_LEVELS - i - 1);
+           }
+         memmove(spare_block, &(pci->root), sizeof(BLOCK));
+         spare_block->brec = get_free();
+         write_if(pci->ixfile, spare_block->brec,
+                  (char *) spare_block, sizeof(BLOCK));
+         pci->root.p0 = spare_block->brec;
+         copy_entry((ENTRY *) (pci->root.entries), e);
+         pci->root.bend = ENT_SIZE(e);
+         CO(0) = 0;
+         pci->level = 0;
+         (pci->dx.nl)++;
+      }
+    else ins_block(block_ptr,e,CO(l));
+  } /* ins_level */
+
+
+int pascal insert_ix(pe, pix)
+  ENTRY *pe;
+  IX_DESC *pix;
+  {
+    ENTRY    e, ee;
+    int h;
+    h = 0;
+    pci = pix;
+    ee = *pe;
+    do
+      {
+         if(CO(pci->level) >= 0)
+           CO(pci->level) +=
+                  ENT_SIZE(ENT_ADR(block_ptr, CO(pci->level)));
+         else
+           CO(pci->level) = 0;
+         update_block();
+         if( (block_ptr->bend + ENT_SIZE(&ee)) <= split_size)
+           {
+             ins_level(pci->level, &ee);
+             break;
+           }
+         else
+           {
+             h = 1;
+             split(pci->level,&ee, &e);
+              ee = e;
+              pci->level--;
+              if (pci->level < 0)
+                {
+                  ins_level(pci->level, &e);
+                  break;
+                }
+              retrieve_block(pci->level, CB(pci->level));
+           }
+      }
+    while (1);
+    if (h) find_ix(pe, pix, 0);
+    return ( IX_OK );
+  } /* insert_ix */
+
+
+/*  BPLUS find and add key functions  */
+
+int pascal find_ix(pe, pix, find)
+  ENTRY *pe;
+  IX_DESC *pix;
+  int find;
+  {
+    int      level, off, ret;
+    RECPOS   ads;
+    pci = pix;
+    ads = 0L;
+    level = ret = 0;
+    while (ads != NULLREC)
+      {  pci->level = level;
+         retrieve_block(level, ads);
+         if (find_block(pe, &off) == 0) ret = 1;
+         if (ret && find) break;
+         if (off == -1)
+           ads = block_ptr->p0;
+         else
+           ads = ENT_ADR(block_ptr, off)->idxptr;
+         CO(level++) = off;
+       }
+     return ( ret );
+   } /* find_ix */
+
+
+int cdecl find_key(pe, pix)
+  ENTRY *pe;
+  IX_DESC *pix;
+  {
+    int ret;
+    ret = find_ix(pe, pix, 1);
+    if ( ret ) copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level)));
+    return ( ret );
+  } /* find_key */
+
+
+int cdecl add_key(pe, pix)
+  ENTRY *pe;
+  IX_DESC *pix;
+  {
+    int ret;
+    ret = find_ix(pe, pix, 0);
+    if ( ret && (pci->duplicate == 0)) return ( IX_FAIL );
+    pe->idxptr = NULLREC;
+    return (insert_ix(pe, pix));
+  } /* add_key */
+
+
+int cdecl locate_key(pe, pix)
+  ENTRY *pe;
+  IX_DESC *pix;
+  {
+    int ret;
+    ret = find_ix(pe, pix, 1);
+    if (ret) copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level)));
+    else if (next_key(pe,pix) == EOIX) ret = EOIX;
+    return ( ret );
+  } /* locate_key */
+
+
+int cdecl find_exact(pe, pix)
+  ENTRY *pe;
+  IX_DESC * pix;
+  {
+    int  ret;
+    ENTRY e;
+    copy_entry(&e, pe);
+    ret = find_key(&e, pix);
+    if ( ret && pci->duplicate)
+      {
+        do
+          {
+            ret = (e.recptr == pe->recptr);
+            if( !ret )  ret = next_key(&e, pci);
+            if (ret) ret = (strcmp(e.key, pe->key) == 0);
+            if ( !ret ) return ( 0 );
+          } while ( !ret );
+      }
+    copy_entry(pe, &e);
+    return ( ret );
+  } /* find_exact */
+
+
+/* BPLUS delete key functions */
+
+int cdecl delete_key(pe, pix)
+  ENTRY *pe;
+  IX_DESC *pix;
+  {
+     ENTRY   e;
+     RECPOS  ads;
+     int     h, leveli, levelf;
+     if (!find_exact(pe, pix))  return( IX_FAIL );
+     h = 1;
+     if ((ads = pe->idxptr) != NULLREC)
+       {
+          leveli = pci->level;
+          do
+            {
+               retrieve_block(++(pci->level), ads);
+               CO(pci->level) = -1;
+            }
+          while ((ads = block_ptr->p0) != NULLREC);
+          CO(pci->level) = 0;
+          copy_entry(&e, ENT_ADR(block_ptr, CO(pci->level)));
+          levelf = pci->level;
+          pci->level = leveli;
+          replace_entry(&e);
+          pci->level = levelf;
+       }
+     while ( h )
+       {
+          retrieve_block(pci->level, CB(pci->level));
+          del_block(block_ptr, CO(pci->level));
+          update_block();
+          if ( (pci->level == 0) && (block_ptr->bend == 0))
+          /* tree was reduced in height */
+            {
+              if (pci->root.p0 != NULLREC)
+                {
+                  retrieve_block(++pci->level, pci->root.p0);
+                  memmove(&(pci->root), block_ptr, sizeof(BLOCK));
+                  (pci->dx.nl)--;
+                  write_free(block_ptr->brec, block_ptr);
+                  BUFDIRTY(cache_ptr) = 0;
+                  BUFHANDLE(cache_ptr) = 0;
+                }
+              break;
+            }
+          h = (block_ptr->bend < comb_size) && (pci->level > 0);
+          if ( h )
+              h = combineblk(CB(pci->level), block_ptr->bend);
+       }
+    find_ix(pe,pix,0);
+    return( IX_OK );
+  } /* delete_key */
+
+
+int pascal combineblk(ads, size)
+  RECPOS ads;
+  int size;
+  {
+    ENTRY  e;
+    RECPOS address;
+    int    esize, off, ret, saveoff, ibuff;
+    ret = 0;
+    saveoff = CO(--(pci->level));
+    retrieve_block(pci->level, CB(pci->level));
+    if ((off = next_entry( saveoff )) < block_ptr->bend)
+      /* combine with page on right */
+      {
+        if ( (ENT_SIZE(ENT_ADR(block_ptr, off)) + size) < split_size)
+          {
+            copy_entry(&e, ENT_ADR(block_ptr, off));
+            address = ENT_ADR(block_ptr, CO(pci->level))->idxptr;
+            retrieve_block(++pci->level, address);
+            ibuff = cache_ptr;
+            spare_block = block_ptr;
+            retrieve_block(pci->level, ads);
+            esize = ENT_SIZE(&e);
+            if(((block_ptr->bend + spare_block->bend + esize) >= split_size)
+                 && (spare_block->bend <= block_ptr->bend + esize))
+               return( ret );
+            e.idxptr = spare_block->p0;
+            ins_block(block_ptr, &e, block_ptr->bend);
+            update_block();
+            if ((block_ptr->bend + spare_block->bend) < split_size)
+            /* combine the blocks */
+              {
+                memmove(ENT_ADR(block_ptr, block_ptr->bend),
+                       ENT_ADR(spare_block, 0),
+                       spare_block->bend);
+                block_ptr->bend += spare_block->bend;
+                write_free(spare_block->brec, spare_block);
+                BUFDIRTY(ibuff) = 0;
+                BUFHANDLE(ibuff) = 0;
+                --pci->level;
+                ret = 1;
+              }
+            else
+            /* move an entry up to replace the one moved */
+              {
+                copy_entry(&e, ENT_ADR(spare_block, 0));
+                esize = ENT_SIZE(&e);
+                movedown(spare_block, 0, esize);
+                spare_block->bend -= esize;
+                spare_block->p0 = e.idxptr;
+                BUFDIRTY(ibuff) = 1;
+                --(pci->level);
+                replace_entry(&e);
+              }
+          }
+      }
+    else
+      /* move from page on left */
+      {
+        if ( (ENT_SIZE(ENT_ADR(block_ptr, CO(pci->level))) + size)
+                 < split_size)
+          {
+            copy_entry(&e, ENT_ADR(block_ptr, saveoff));
+            off = prev_entry(saveoff);
+            if (CO(pci->level) == -1) address = block_ptr->p0;
+            else address = ENT_ADR(block_ptr, CO(pci->level))->idxptr;
+            retrieve_block(++pci->level, address);
+            off = last_entry();
+            ibuff = cache_ptr;
+            spare_block = block_ptr;
+            retrieve_block(pci->level, ads);
+            esize = ENT_SIZE(&e);
+            if(((block_ptr->bend + spare_block->bend + esize) >= split_size)
+                 && (spare_block->bend <= block_ptr->bend + esize))
+               return( ret );
+            BUFDIRTY(ibuff) = 1;
+            CO(pci->level) = 0;
+            e.idxptr = block_ptr->p0;
+            ins_block(block_ptr, &e, 0);
+            if ((block_ptr->bend + spare_block->bend) < split_size)
+            /* combine the blocks */
+              {
+                memmove(ENT_ADR(spare_block, spare_block->bend),
+                       ENT_ADR(block_ptr, 0),
+                       block_ptr->bend);
+                spare_block->bend += block_ptr->bend;
+                write_free(block_ptr->brec, block_ptr);
+                BUFDIRTY(cache_ptr) = 0;
+                BUFHANDLE(cache_ptr) = 0;
+                CO(--(pci->level)) = saveoff;
+                ret = 1;
+              }
+            else
+            /* move an entry up to replace the one moved */
+              {
+                 block_ptr->p0 = ENT_ADR(spare_block,off)->idxptr;
+                 copy_entry(&e, ENT_ADR(spare_block, off));
+                 spare_block->bend = off;
+                 update_block();
+                 CO(--(pci->level)) = saveoff;
+                 replace_entry(&e);
+              }
+          }
+      }
+    return ( ret );
+  } /* combineblk */
+
+
+void pascal replace_entry(pe)
+  ENTRY *pe;
+  {
+    retrieve_block(pci->level, CB(pci->level));
+    pe->idxptr = ENT_ADR(block_ptr, CO(pci->level))->idxptr;
+    del_block(block_ptr, CO(pci->level));
+    prev_entry(CO(pci->level));
+    insert_ix(pe, pci);
+  } /* replace_entry */
+
+
\ No newline at end of file
diff --git a/bplus/BPLUS.DOC b/bplus/BPLUS.DOC
new file mode 100644
index 0000000..687dc05
--- /dev/null
+++ b/bplus/BPLUS.DOC
@@ -0,0 +1,582 @@
+
+
+
+
+
+
+                               THE B-PLUS PROGRAM
+                         A B-TREE INDEXING FILE MODULE
+                               FOR C PROGRAMMERS
+                                       by
+                             Hunter and Associates
+
+
+
+              B-PLUS is a versatile, carefully designed module for C
+         programmers who need a fast, efficient program for indexing
+         data files.  B-PLUS allows data records to be retrieved based
+         on a key value without regard to their position in the data
+         file.  The data records can also be accessed in sequential
+         order in either a forward and reverse direction.
+
+              The B-PLUS Program Module is based on the famous and
+         widely used b-tree algorithm and has a number of useful
+         extensions which are not found in many programs of this type.
+         Some of its features are the following:
+
+              - Variable length keys are allowed
+
+              - File size limited only by DOS or by disk space
+
+              - All functions are non-recursive so very little stack
+                space is required
+
+              - The most recently used key values are stored in a
+                cache buffer in main memory for fast access
+
+              - Duplicate keys are allowed
+
+              Version 1.1A of the B-PLUS program has been tested
+         for Microsoft C Compilers, Versions 4.0, 5.0, 5.1 and the
+         Borland Turbo C Compiler Version 1.5.  The compiled object
+         file is less than 10K bytes in length for these compilers.
+         See the instructions at the end of this user's guide for a
+         special note regarding Microsoft's older C Version 4.0.
+
+              Version 1.1A has several new features that were not in
+         Version 1.0.  The next_key and prev_key routines can now be
+         called immediately after adding or deleting an index key.  It
+         is no longer necessary to "reset" the index file with a
+         find_key or locate_key function call after adding or deleting
+         keys.  All known bugs have been corrected in Version 1.1A.
+
+
+
+         LICENSE AND REGISTRATION
+
+              B-PLUS is distributed as a "share ware" program.  Please
+         help us get it known by giving unmodified copies of the
+
+
+         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
+         -------------------------------------------------------------
+
+
+         program and documentation to other programmers who may find
+         B-PLUS useful.
+
+              B-PLUS is copyright (C) 1987 by Hunter and Associates.
+         It is not public domain or free software.  Non-registered
+         users are granted a limited license to use B-PLUS on a trial
+         basis for determining whether or not it is suitable for their
+         needs.  Registration permits the use of B-PLUS on one CPU and
+         allows the use of the compiled B-PLUS modules in programs for
+         general sale and/or distribution.
+
+              The registration fee is $25 or $35.  Users who pay the
+         $35 fee will be sent a disk containing a fully commented
+         listing of the latest source code, the user documentation,
+         and a number of useful sample programs.  Users who pay the
+         $25 fee are not sent a new disk but are included in the
+         mailing list for announcements about both current and future
+         products.  Your prompt registration of your copy of the B-
+         PLUS program is appreciated.
+
+              A trial disk with supporting documentation is available
+         directly from Hunter and Associates for $10.
+
+              Register your usage of B-PLUS by sending the registra-
+         tion fee to:
+
+                        Hunter and Associates
+                        7900 Edgewater Drive
+                        Wilsonville, OR  97070
+                        Telephone: (503) 694-1449
+
+         Your comments regarding the B-PLUS program or any suggestions
+         you have for extensions or for other programs that would be
+         useful to you are welcomed.
+
+              Hunter and Associates makes no warranties whatsoever
+         regarding the B-PLUS computer programs or the supporting
+         documentation.
+
+
+         USING B-PLUS IN YOUR PROGRAMS
+
+              The B-PLUS File Indexing Module contains twelve
+         functions that handle the retrieval of data records by key
+         value.  The keys that are used to locate records are null
+         terminated strings.  The data structures and constants that
+         are used are defined in the header file bplus.h.
+
+              If the data record field that you want to use as a key
+         contains numeric data, you can use one of the library
+
+                                   Page 2
+
+
+         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
+         -------------------------------------------------------------
+
+
+         conversion routines (fcvt, evct, sprintf) to convert the data
+         to string format.
+
+              The connection between a key and its reference is
+         formalized as a structure of type ENTRY.  This structure
+         contains three elements:
+
+         typedef struct
+           {
+             RECPOS   idxptr;         /* long pointer to next index
+                                         level                      */
+             RECPOS   recptr;         /* long pointer to the file
+                                         position of data record    */
+             char     key[MAXKEY];    /* with this key value        */
+           } ENTRY;
+
+              The application program uses only the recptr and key[]
+         fields.  The idxptr is used and maintained by the B-PLUS
+         modules.
+
+              A variable of type IX_DESC is declared for each open
+         index file.  See the header file bplus.h if you are
+         interested in the elements of this structure.  ENTRY and
+         IX_DESC are the only two data types that are normally used by
+         application programs.
+
+              Here is a sample program stub which calls the open_index
+         and find_index subroutines.
+
+
+         Example:
+
+           #include "bplus.h"
+           main()
+             {
+                ENTRY    e;
+                IX_DESC  names;
+
+                /* open index file called NAMES.IDX */
+
+                open_index("NAMES.IDX", &names, 0);
+
+                /* find an index record for John Smith */
+
+                strcpy(e.key, "SMITH JOHN");
+                if(find_key(&e, &names))
+                  printf("Data record address is %ld", e.recptr);
+                else
+                  printf("Cannot find record for that key");
+              }
+
+                                   Page 3
+
+
+         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
+         -------------------------------------------------------------
+
+
+         Each of the twelve subroutines is now described.
+
+         int cdecl open_index(name, pix, dup);
+
+              char *name;         File path name
+              IX_DESC *pix;       Pointer to index file variable
+              int dup;            0 - no duplicate keys allowed
+                                  1 - allow duplicate keys
+
+              Description:  The open_index function is used to open
+              and initialize an existing index file specified by name
+              and prepares the file for subsequent reading or writing.
+              The file structure variable pix is defined in the
+              application program.  Duplicate keys are allowed or not
+              allowed depending on whether dup has the value of 0 or
+              1.  The open_index function returns the value IX_OK (1)
+              if the file is opened successfully.  If the file cannot
+              be opened, an error message is displayed and the program
+              is aborted.
+
+
+
+         int cdecl make_index(name, pix, dup);
+
+              char *name;         File path name
+              IX_DESC *pix;       Pointer to index file variable
+              int dup;            0 - no duplicate keys allowed
+                                  1 - allow duplicate keys
+
+              Description:  The make_index function is used to create
+              and initialize a new index file specified by name and to
+              prepare the file for subsequent reading or writing.  If
+              a file of this name already exists, its contents are
+              destroyed when the new file is created.  The file
+              structure variable pix is defined in the application
+              program.  Duplicate keys are allowed or not allowed
+              depending on whether dup has the value of 0 or 1.  The
+              make_index function returns the value IX_OK (1) if the
+              file is created successfully.  If the file cannot be
+              created, an error message is displayed and the program
+              is aborted.
+
+
+
+         int cdecl close_index(pix);
+
+              IX_DESC *pix;       Pointer to index file variable
+
+              Description:  The close_index file function clears the
+              internal cache buffer and closes the specified index
+
+                                   Page 4
+
+
+         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
+         -------------------------------------------------------------
+
+
+              file.  It is very important that each index file be
+              closed.  Otherwise data that is stored in the internal
+
+              cache buffer may be lost and the index file may not be
+              properly updated.  The close_index function returns the
+              value IX_OK (1) if the file is successfully closed.
+
+
+
+         int cdecl find_key(pe, pix);
+
+              ENTRY *pe;          Pointer to variable of type ENTRY
+              IX_DESC *pix;       Pointer to index file variable
+
+              Description:  The find_key function searches the index
+              file for the key value contained in pe.key.  If an exact
+              match is found, the value IX_OK (1) is returned and the
+              location of the data record with this key value is
+              stored in pe.recptr.  If an exact match is not found,
+              the value IX_FAIL (0) is returned and pe.recptr is
+              undefined.  If the index file contains duplicate keys,
+              the first key is always found.
+
+
+
+         int cdecl locate_key(pe, pix);
+
+              ENTRY *pe;          Pointer to variable of type ENTRY
+              IX_DESC *pix;       Pointer to index file variable
+
+              Description:  The locate key function searches the index
+              file for the first key value which is equal to or
+              greater than that stored in pe.key.  The location of the
+              data record which is equal to or greater than pe.key is
+              stored in pe.recptr.  This function can be used to
+              locate an entry in the index file when only part of the
+              key value is known.  If the index file contains
+              duplicate keys, locate_key will locate the first key.
+              The following values are returned by locate_key:
+
+                   IX_OK  -  the value (1) is returned if an exact
+                             match is found
+
+                   IX_FAIL - the value (0) is returned if an exact
+                             match is not found
+
+                   EOIX  -   the value (-2) is returned for end of
+                             index if the search key is greater than
+                             all keys in the index file and pe.recptr
+                             is undefined.
+
+                                   Page 5
+
+
+         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
+         -------------------------------------------------------------
+
+
+
+
+         int cdecl add_key(pe, pix);
+
+              ENTRY *pe;          Pointer to variable of type ENTRY
+              IX_DESC *pix;       Pointer to index file variable
+
+              Description:  The add_key function adds new entries to
+              the index file.  The calling program stores the key
+              value in pe.key and the data record address in
+              pe.recptr.  Add_key first looks to see if an entry with
+              this key already exists in the index file.  If no entry
+              with this key exists, the new entry is added.  If an
+              entry with this key already exists, the new entry is
+              added only if duplicate keys are allowed (as defined by
+              the open_index function).  If the entry is successfully
+              added, IX_OK (1) is returned; otherwise IX_FAIL (0) is
+              returned.
+
+
+
+         int cdecl delete_key(pe, pix);
+
+              ENTRY *pe;          Pointer to variable of type ENTRY
+              IX_DESC *pix;       Pointer to index file variable
+
+              Description:  The delete_key function deletes entries
+              in the index file.  The key to be deleted is stored in
+              pe.key.  If duplicate records are allowed, the
+              corresponding data record address must also be stored in
+              pe.recptr.  In this case, delete key needs the record
+              number to distinguish entries.  If there are not
+              duplicate entries, this field is ignored.  If the entry
+              is successfully deleted, IX_OK (1) is returned;
+              otherwise IX_FAIL (0) is returned.  The space that was
+              occupied by the entry is marked as free for reused by
+              B_PLUS.
+
+
+
+         int cdecl first_key(pix);
+
+              IX_DESC *pix;       Pointer to index file variable
+
+              Description:  The first_key function positions the index
+              file pointer to the beginning of the index file.  The
+              function next_key can then be used to list the file in
+              key order.  The first_key function returns the value
+              IX_OK (1).
+
+
+                                   Page 6
+
+
+         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
+         -------------------------------------------------------------
+
+
+         int cdecl last_key(pix);
+
+              IX_DESC *pix;       Pointer to index file variable
+
+              Description:  The last_key function positions the index
+              file pointer at the end of the index file.  The function
+              previous_key can then be used to list the file in
+              reverse key order.  The last_key function returns the
+              value IX_OK (1).
+
+
+
+         int cdecl next_key(pe, pix);
+
+              ENTRY *pe;          Pointer to variable of type ENTRY
+              IX_DESC *pix;       Pointer to index file variable
+
+              Description:  The next_key function returns the next
+              entry in the index file.  After deleting or adding keys,
+              next_key returns the key immediately following the
+              addition or deletion.  Next_key can be used to locate
+              the desired data record when duplicate keys are allowed.
+              Next_key is used to process files sequential.  Next_key
+              returns the value IX_OK (1) if the next key is present
+              and the value EOIX (-2) when the file pointer is at the
+              end of the index file.  The following program processes
+              an indexed file sequentially:
+
+              #include "bplus.h"
+              main()
+                {
+                  ENTRY e;
+                  IX_DESC names;
+
+                  /* open the index file */
+                  open_index("names.idx", &names);
+
+                  /* now process the file sequentially */
+                  first_key(&names);
+                  ret = next_key(&e, &names);
+                  while (ret == IX_OK)
+                    {
+                      /* the data record location is e.recptr */
+                      /* the program would retrieve and process it */
+                      ret = next_key(&e, &names);
+                    }
+
+                  /* remember to always close open files */
+                  close_index(&names);
+                }
+
+                                   Page 7
+
+
+         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
+         -------------------------------------------------------------
+
+
+         int cdecl prev_key(pe, pix);
+
+              ENTRY *pe;          Pointer to variable of type ENTRY
+              IX_DESC *pix;       Pointer to index file variable
+
+              Description:  The prev_key function returns the previous
+              entry in the index file.  After deleting or adding keys,
+              prev_key returns the key immediately preceeding the
+              addition or deletion.  Prev_key can be used to process
+              files sequentially in reverse order. Prev_key returns
+              the value IX_OK (1) if there is a previous key and the
+              value EOIX (-2) when the file pointer is at the
+              beginning of the index file.
+
+
+
+         int cdecl find_exact(pe, pix);
+
+              ENTRY *pe;          Pointer to variable of type ENTRY
+              IX_DESC *pix;       Pointer to index file variable
+
+              Description:  The find_exact function searches the index
+              file for the key value contained in pe.key and the data
+              record position stored in pe.recptr.  If an exact match
+              is found for both of these values, the value IX_OK (1)
+              is returned, and the internal index file pointer is set
+              to that position in the index file.  If an exact match
+              is not found, the value IX_FAIL (0) is returned.
+
+
+
+         TAILORING OR CHANGING B-PLUS
+
+              Most applications can use the B-PLUS program as it is
+         distributed by Hunter and Associates without any changes.  It
+         allows multiple, large data files to be indexed in a fast,
+         efficient manner.  However, a description of the values that
+         can be changed to tailor B-PLUS are given in this section.
+
+              An index tree becomes full when no more entries can be
+         added to the tree.  This is the case when adding another
+         entry to the tree would cause the tree to grow larger than
+         its maximum allowed height.  This height depends on the size
+         of the index blocks and the average size of the keys used by
+         the data files.  The minimum capacity of a b-tree index is
+         given by the following formula:
+
+              C = (B / E + 1) * (B / (2 * E)  + 1) ** (H - 1)
+
+         where C is the number of entries in the index file, B is the
+
+                                   Page 8
+
+
+         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
+         -------------------------------------------------------------
+
+
+         block size in bytes, E is the average size of an ENTRY in
+         bytes, and H is the maximum tree height.
+
+              The maximum key size is defined by MAXKEY and is set at
+         100.  The block size is 1024 bytes as defined by IXB_SIZE.
+         Ten bytes are used by pointers so 1014 bytes are used by
+         entries.  The size of an ENTRY is 9 + the key length.
+
+              Thus, if the average key length is 11, an average ENTRY
+         is 20 bytes long and the minimum number of entries that can
+         be contained in a tree of height 4 is:
+
+              C = (1014 / 20 + 1) * (1014 / 40 + 1) ** 3
+                = 945,072
+
+         If the average ENTRY is 40 bytes long, the minimum number of
+         entries that can be contained in a tree of height 4 is
+         67,384.  The corresponding values for a tree of height 3 are
+         35,896 and 4927, respectively.
+
+              The maximum tree height is determined by MAX_LEVELS and
+         is set to eight.  Very little memory space is used by
+         allowing the maximum tree height to be this large.  B-PLUS
+         increases the height of the tree dynamically as required by
+         the number of records in the data file.
+
+              If your application does not use long keys and your
+         files are not huge, IXB_SIZE can be changed to 512 bytes with
+         only a slight degradation in performance.
+
+              The root of an open index file is always memory resident
+         as defined by the variable of type IX_DESC.  A dynamic pool
+         of cache buffers is used for other index blocks of the tree.
+         The number of blocks in the pool is defined by NUM_BUFS with
+         a default value of 8.  Each memory block is sizeof(IXB_SIZE)
+         + 8 bytes in length so approximately 8K of memory is used for
+         cache storage of index blocks.  If the number of index files
+         that are open simultaneously is larger than 4, you may want
+         to increase NUM_BUFS.  If the usage of memory is critical,
+         the number of buffers can be decreased.  However, NUM_BUFS
+         must be at least 2.  In general, the speed of file access can
+         be expected to improve if the number of buffers is increased
+         since more of the index file is memory resident.
+
+              Because some indices are always memory resident, and
+         because the DOS Operating System requires it, it is very
+         important that all open index files be closed before an
+         application program terminates.
+
+              As stated earlier, the B-PLUS program has been tested
+
+                                   Page 9
+
+
+         HUNTER AND ASSOCIATES            B-PLUS FILE INDEXING PROGRAM
+         -------------------------------------------------------------
+
+
+         using Microsoft's Optimizing C Compilers, Versions 4, 4.5 and
+         5.0, and Borland's Turbo C, Version 1.0.  However, standard K
+         & R programming guidelines are followed so B-PLUS should be
+         able to be used with other C Compilers with little
+         modification.  Since B-PLUS is non-recursive, the usage of
+         stack space does not change dynamically.  It is recommend
+         that the B-PLUS program be complied without stack checking.
+         For Microsoft C, the /Ox option can be used to maximize speed
+         and minimize code size.  For Turbo C, B-PLUS can be complied
+         with maximum optimization to minimize the object size and
+         improve performance.
+
+
+         ACKNOWLEDGMENTS AND REFERENCES
+
+              The following reference materials were used and helpful
+         in writing the B-PLUS program:
+
+              Wirth, Niklaus:
+                     Algorithms + Data Structures = Programs
+                     Prentice Hall (1976)
+
+              Hunt, William James:
+                     The C Toolbox
+                     (Serious C Programming for the IBM PC)
+                     Addison-Wesley (1985)
+
+
+              Wirth's book is a standard reference source for binary
+         trees and data structures.  Hunt's C Toolbox contains useful
+         C programming concepts with carefully constructed programming
+         examples.
+
+
+         USING THE BPLUS ROUTINES
+
+              The BPLUS.C routines must be compiled and the object
+         file (BPLUS.OBJ) loaded with programs that use the B_PLUS
+         toolkit.  Several sample C programs have been included which
+         illustrate how to use the BPLUS Toolkit.  These programs
+         should be compiled and run to make sure your copy of the
+         program is correct.
+
+
+         A SPECIAL NOTE REGARDING MICROSOFT C 4.0 COMPILER
+
+              The Microsoft C library routines are different for
+         Version 4.0 and for Version 5.0 and Quick C.  In particular,
+         the memmove routine must be changed to the memcpy routine in
+         Version 4.0.  A macro is included in BPLUS.C which makes this
+         substitution.  Remove the comments delimiters for this version.
+
+                                  Page 10
+
\ No newline at end of file
diff --git a/bplus/BPLUS.H b/bplus/BPLUS.H
new file mode 100644
index 0000000..20a86f7
--- /dev/null
+++ b/bplus/BPLUS.H
@@ -0,0 +1,71 @@
+
+/*  bplus.h - data structures and constants  */
+
+
+#define IX_OK       1
+#define IX_FAIL     0
+#define EOIX       (-2)
+#define MAXKEY      100
+#define NUM_BUFS    8
+#define MAX_LEVELS  8
+#define IXB_SIZE    1024
+#define IXB_SPACE  (IXB_SIZE - sizeof(int) - sizeof(long) * 2)
+
+typedef long RECPOS;
+
+typedef struct                    /*  entry structure in index        */
+  {  RECPOS   idxptr;             /*  points to lower index level     */
+     RECPOS   recptr;             /*  points to data record           */
+     char     key[MAXKEY];        /*  start of record key             */
+  }  ENTRY;
+
+typedef struct                    /*  index record format             */
+  {  RECPOS   brec;               /*  position in index file          */
+                                  /*  or location of next free block  */
+     int      bend;               /*  first unused block location     */
+     RECPOS   p0;                 /*  points to next level            */
+     char     entries[IXB_SPACE]; /*  here are the key entries        */
+  }  BLOCK;
+
+typedef struct                    /*  disk file info                  */
+  {  RECPOS   ff;                 /*  location of first free block    */
+     int      nl;                 /*  number of index levels          */
+  }  IX_DISK;
+
+typedef struct                    /*  memory buffer pool of indx blks */
+  {  int      dirty;              /*  true if changed                 */
+     int      handle;             /*  index file handle               */
+     int      count;              /*  number of times referenced      */
+     BLOCK    mb;
+  }  MEMBLOCK;
+
+typedef struct
+  {  MEMBLOCK     cache [ NUM_BUFS ];
+  }  IX_BUFFER;
+
+typedef struct                    /*  in-memory index descriptor      */
+  {  int      ixfile;
+     int      level;              /*  level in btree                  */
+     int      duplicate;          /*  no duplicate keys if 0          */
+     struct
+       {  RECPOS    cblock;       /*  position in index file          */
+          int       coffset;      /*  current offset within block     */
+       }  pos [ MAX_LEVELS ];
+     BLOCK    root;               /*  root index record               */
+     IX_DISK  dx;
+  }  IX_DESC;
+
+int cdecl open_index(char *,IX_DESC *, int);
+int cdecl close_index(IX_DESC *);
+int cdecl make_index(char *,IX_DESC *, int);
+int cdecl first_key(IX_DESC *);
+int cdecl last_key(IX_DESC *);
+int cdecl next_key(ENTRY *, IX_DESC *);
+int cdecl prev_key(ENTRY *, IX_DESC *);
+int cdecl find_key(ENTRY *, IX_DESC *);
+int cdecl add_key(ENTRY *, IX_DESC *);
+int cdecl locate_key(ENTRY *, IX_DESC *);
+int cdecl delete_key(ENTRY *, IX_DESC *);
+int cdecl find_exact(ENTRY *, IX_DESC *);
+
+
\ No newline at end of file
diff --git a/bplus/CPLUS.C b/bplus/CPLUS.C
new file mode 100644
index 0000000..50d349e
--- /dev/null
+++ b/bplus/CPLUS.C
@@ -0,0 +1,1001 @@
+/********************************************************************/
+/*                                                                  */
+/*             BPLUS file indexing program - Version 1.1            */
+/*                                                                  */
+/*                      A "shareware program"                       */
+/*                                                                  */
+/*                                                                  */
+/*                      Copyright (C) 1987 by                       */
+/*                                                                  */
+/*                      Hunter and Associates                       */
+/*                      7050 NW Zinfandel Lane                      */
+/*                      Corvallis, Oregon  97330                    */
+/*                      (503) 745 - 7186                            */
+/*                                                                  */
+/********************************************************************/
+
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys\types.h>            /*  delete this line for Turbo C  */
+#include <sys\stat.h>
+#include <string.h>
+#include "bplus.h"
+
+
+/*  macros, constants, data types  */
+
+#define  NULLREC      (-1L)  /* special value for RECPOS variable */
+#define  FREE_BLOCK   (-2)   /* designates a free block in index file */
+        /* the address of an entry in a block */
+#define  ENT_ADR(pb,off)  ((ENTRY*)((char*)((pb)->entries) + off))
+        /* the size of an entry */
+#define  ENT_SIZE(pe)     strlen((pe)->key) + 1 + 2 * sizeof(RECPOS)
+        /* the cache changed indicator */
+#define  BUFDIRTY(j)      (mci->cache[j].dirty)
+        /* the index file handle for memblock j */
+#define  BUFHANDLE(j)     (mci->cache[j].handle)
+        /* memory cache block j */
+#define  BUFBLOCK(j)      (mci->cache[j].mb)
+        /* number of times cache blk j is referenced */
+#define  BUFCOUNT(j)      (mci->cache[j].count)
+        /* address of current block for level j */
+#define  CB(j)            (pci->pos[j].cblock)
+        /* offset of current block for level j */
+#define  CO(j)            (pci->pos[j].coffset)
+
+
+/*  declare some global variables  */
+
+IX_DESC      *pci;                       /* pointer to index descriptor   */
+IX_BUFFER    bt_buffer;                  /* memory cache for index blocks */
+IX_BUFFER    *mci = &bt_buffer;          /* pointer to cache index blocks */
+BLOCK        *block_ptr;                 /* pointer to index record block */
+BLOCK        *spare_block;               /* pointer to spare index block  */
+int          cache_ptr = 0;              /* index to cache memory pool    */
+int          cache_init = 0;             /* 1 when cache is initilized    */
+int          split_size = IXB_SPACE;     /* split block when greater than */
+int          comb_size  = (IXB_SPACE/2); /* combine blocks when less than */
+
+/* #define memmove     memcpy */    /* Use this macro for MicroSoft C 4.0 */
+
+/* list all function prototypes */
+void pascal error(int, long);
+void pascal read_if(long, char *, int);
+void pascal write_if(int, long, char *, int);
+int  pascal creat_if(char *);
+int  pascal open_if(char *);
+void pascal close_if(int);
+void pascal update_block(void);
+void pascal init_cache(void);
+int  pascal find_cache(RECPOS);
+int  pascal new_cache(void);
+void pascal load_cache(RECPOS);
+void pascal get_cache(RECPOS);
+void pascal retrieve_block(int, RECPOS);
+int  pascal prev_entry(int);
+int  pascal next_entry(int);
+void pascal copy_entry(ENTRY *, ENTRY *);
+int  pascal scan_blk(int);
+int  pascal last_entry(void);
+void pascal write_free( RECPOS, BLOCK *);
+RECPOS pascal get_free(void);
+int  pascal find_block(ENTRY *, int *);
+void pascal movedown(BLOCK *, int, int);
+void pascal moveup(BLOCK *, int, int);
+void pascal ins_block(BLOCK *, ENTRY *, int);
+void pascal del_block(BLOCK *, int);
+void pascal split(int, ENTRY *, ENTRY *);
+void pascal ins_level(int, ENTRY *);
+int  pascal insert_ix(ENTRY *, IX_DESC *);
+int  pascal find_ix(ENTRY *, IX_DESC *, int);
+int  pascal combineblk(RECPOS, int);
+void pascal replace_entry(ENTRY *);
+void print_blk(BLOCK *);
+
+
+/*  file I/O for B-PLUS module  */
+
+void pascal error(j, l)               /* print file error messages */
+  int j;                              /* error number */
+  long l;                             /* current file position */
+  {
+    static char *msg[3] = {"ERROR - CANNOT OPEN/CLOSE FILE",
+                           "ERROR WHILE READING FILE",
+                           "ERROR WHILE WRITING FILE"};
+    printf("\n  %s - Record Number %ld\n", msg[j], l);
+    exit(1);                  /* delete this line to not halt program */
+                              /* and call your error handlng routine */
+  } /* error */
+
+
+void pascal read_if(start, buf, nwrt)    /* read pci index file */
+  long start;                            /* file read position */
+  char *buf;                             /* data holding buffer */
+  int nwrt;                              /* number bytes to read */
+  {
+    long err;
+          /* seek to read position in current index file */
+    err = start - lseek(pci->ixfile, start, SEEK_SET);
+         /* if no error read an index file block */
+    if (err == 0) err = nwrt - read(pci->ixfile, buf, nwrt);
+         /* call error routine if number bytes read != nwrt */
+    if (err != 0) error(1, start);
+  } /* read_if */
+
+
+void pascal write_if(handle, start, buf, nwrt)   /* write index record */
+  int handle;                        /* write to this file handle */
+  long start;                        /* write to this position in file */
+  char *buf;                         /* write data from this buffer */
+  int nwrt;                          /* write this many bytes of data */
+  {
+    long err;
+         /* seek to file write position */
+    err = start - lseek(handle, start, SEEK_SET);
+         /* if no error write index block block */
+    if (err == 0) err = nwrt - write(handle, buf, nwrt);
+         /* call error routine if number bytes written != nwrt */
+    if (err != 0) error(2, start);
+  } /* write_if */
+
+
+int pascal creat_if(fn)               /* make a new index file */
+  char *fn;                           /* name and path of file */
+  {
+    int   ret;
+    ret = open(fn,O_RDWR|O_CREAT|O_TRUNC|O_BINARY,S_IWRITE);
+    if (ret  < 0) error(0,0L);        /* there was an error if ret < 0 */
+    return (ret);
+  } /* creat_if */
+
+
+int pascal open_if(fn)                /* open an existing index file */
+  char *fn;                           /* path and name of index file */
+  {
+    int  ret;
+    ret = open(fn,O_RDWR|O_BINARY);
+    if (ret < 1) error(0,0L);         /* there was an error is ret < 1 */
+    return (ret);
+  } /* open_if */
+
+
+void pascal close_if(handle)          /* close an open index file */
+  int handle;                         /* with this file handle    */
+  {
+    if(close(handle) < 0)  error(2,0L);
+  } /*  close_if */
+
+
+int cdecl open_index(name, pix, dup)  /* open and initilize index file */
+  char *name;                         /* path and name of index file */
+  IX_DESC *pix;                       /* pointer to index descriptor */
+  int dup;                            /* allow duplicate keys if != 0 */
+  {
+    pci = pix;                        /* pci is global index descriptor */
+    pci->ixfile = open_if(name);      /* file handle */
+    pci->duplicate = dup;             /* set duplicate keys flag */
+         /* read root descriptor for index */
+    read_if(0L,(char *)&(pix->root), (sizeof(BLOCK) + sizeof(IX_DISK)));
+    if (!cache_init)                   /* if cache not initilized */
+      {
+        init_cache();                  /* initilize cache memory */
+        cache_init = 1;                /* but only once */
+      }
+    first_key(pix);                    /* position to first index key */
+    return ( IX_OK );
+  } /* open_index */
+
+
+int cdecl close_index(pix)            /* close an open index file */
+  IX_DESC *pix;
+  {
+    int i;
+         /* write out the root block for the index descriptor */
+    write_if(pix->ixfile, 0L,(char *)&(pix->root),
+               (sizeof(BLOCK) + sizeof(IX_DISK)));
+         /* save all memory blocks for index that have been changed */
+    for (i = 0; i < NUM_BUFS; i++)      /* check all of cache */
+      if (BUFHANDLE(i) == pix->ixfile)
+        {
+          if (BUFDIRTY(i))
+            {
+              write_if(BUFHANDLE(i),     /* if changed, write to disk */
+                       BUFBLOCK(i).brec,
+                       (char *) &BUFBLOCK(i),
+                       sizeof(BLOCK));
+              BUFDIRTY(i) = 0;
+            }
+          BUFBLOCK(i).brec = NULLREC;    /* same handle can be used again */
+        }
+    close_if(pix->ixfile);               /* close the index file */
+    return( IX_OK );
+  } /* close_index */
+
+
+int cdecl make_index(name, pix, dup)       /* create a new index file */
+  char *name;                        /* pointer to path and file name */
+  IX_DESC *pix;                      /* pointer to index descriptor */
+  int dup;                           /* duplicate keys allow is != 0 */
+  {
+    pci = pix;             /* set global pci to this index descriptor */
+    pci->ixfile = creat_if(name);
+    pci->duplicate = dup;
+    pci->dx.nl = 1;               /* the only block is the root */
+    pci->dx.ff = NULLREC;         /* there are no free index blocks */
+    pci->level = 0;               /* the root is level 0 */
+    CO(0) = -1;                   /* the current block offset is -1 */
+    CB(0) = 0L;                   /* the current block address 0L */
+    pci->root.brec = 0L;          /* root block address is 0L */
+    pci->root.bend = 0;           /* no entries yet so block end is 0 */
+    pci->root.p0 = NULLREC;       /* p0 points to next index level */
+
+         /* write the root block of the index descriptor */
+    write_if(pci->ixfile, 0L,(char *)&(pix->root),
+               (sizeof(BLOCK) + sizeof(IX_DISK)));
+    if (!cache_init)
+      {                        /* initiate memory cache but only once */
+        init_cache();
+        cache_init = 1;
+      }
+    first_key(pix);            /* initialize to first key in index */
+    return ( IX_OK );
+  } /* make_index */
+
+
+/*  cache I/O for BPLUS  */
+
+void pascal update_block()
+   /* set flag that a memory block has changed     */
+   /* no action necessary if current block is root */
+  {
+    if (block_ptr != &(pci->root))
+       BUFDIRTY(cache_ptr) = 1;
+  } /* update_block */
+
+
+void pascal init_cache()       /* initialize the cache memory buffers */
+  {
+    register int  j;
+    for (j = 0; j < NUM_BUFS; j++)
+      {  BUFDIRTY(j) = 0;          /* the buffer has not been changed */
+         BUFCOUNT(j) = 0;                /* number of references is 0 */
+         BUFBLOCK(j).brec = NULLREC;    /* each memory block is empty */
+      }
+  } /* init_cache */
+
+
+int pascal find_cache(r)          /* find a block in the cache memory */
+  RECPOS r;
+  {
+    register int  j;
+    for (j = 0; j < NUM_BUFS; j++)    /* repeat for each index buffer */
+      {
+             /* check handle and index address for a match */
+        if((BUFBLOCK(j).brec == r) && (BUFHANDLE(j) == pci->ixfile))
+         {  cache_ptr = j;            /* if match, set cache_ptr */
+            return (1);               /* and return true */
+      }  }
+    return (-1);               /* return false if not in cache memory */
+  } /* find_cache */
+
+
+int pascal new_cache()             /* assign a block in cache memory */
+  {
+    register int  i;
+    i = (cache_ptr + 1) % NUM_BUFS;    /* assign memory buffer */
+         /* if it has been changed, save it to disk */
+    if (BUFDIRTY(i)) write_if(BUFHANDLE(i),
+                              BUFBLOCK(i).brec,
+                              (char *) &BUFBLOCK(i),
+                              sizeof(BLOCK));
+    BUFHANDLE(i) = pci->ixfile;        /* save index file handle */
+    BUFDIRTY(i) = 0;                   /* buffer change flag is false */
+    return (i);                        /* return memory buffer pointer */
+  } /* new_cache */
+
+
+void pascal load_cache(r)         /* load index block in cache memory */
+  RECPOS r;
+  {
+    cache_ptr = new_cache();        /* get a block in cache memory */
+                                    /* and then load the index block */
+    read_if(r, (char *)&BUFBLOCK(cache_ptr), sizeof(BLOCK));
+  } /* load_cache */
+
+
+void pascal get_cache(r)            /* load an index block into cache */
+  RECPOS r;
+  {
+    if (find_cache(r) < 0)         /* if block is not in cache memory */
+       load_cache(r);              /* load the block in memory */
+                                   /* and set block point to this block */
+    block_ptr = &BUFBLOCK(cache_ptr);
+  } /* get_cache */
+
+
+void pascal retrieve_block(j, r)    /* load an index block */
+  int j;
+  RECPOS r;
+  {
+    if (j == 0)                     /* if the block wanted is the root */
+       block_ptr = &(pci->root);    /* then point to the root */
+    else  get_cache(r);             /* else get from cache memory */
+    CB(j) = block_ptr->brec;        /* store index block address */
+  } /* retrieve_block */
+
+
+/*  low level functions of BPLUS  */
+
+int pascal prev_entry(off)        /* back up one entry in current block */
+  int off;
+  {
+     if (off <= 0)                /* if off <= can not back up */
+       {
+         off = -1;                /* set to beginning of block */
+         CO(pci->level) = off;
+       }
+     else
+       off = scan_blk(off);       /* find previous entry */
+     return(off);
+  } /* prev_entry */
+
+
+int pascal next_entry(off)        /* find next entry in current block */
+  int off;
+  {
+     if (off == -1)               /* at beginning of the block */
+       off = 0;
+     else                         /* move to next entry if not at end */
+       {
+         if (off < block_ptr->bend)
+            off += ENT_SIZE(ENT_ADR(block_ptr,off));
+       }
+     CO(pci->level) = off;       /* save the offset position in block */
+     return (off);
+  } /* next_entry */
+
+
+void pascal copy_entry(to, from)  /* copy an entry */
+  ENTRY *to;                     /* to here */
+  ENTRY *from;                   /* from here */
+  {
+    int me;
+    me = ENT_SIZE(from);         /* get the entry's size */
+    memmove(to, from, me);        /* and copy */
+  } /* copy_entry */
+
+
+int pascal scan_blk(n)           /* find the offset of last entry in */
+int n;                           /* current block before postion n */
+  {
+     register int off, last;
+     off = 0;
+     last = -1;
+     while (off < n )            /* repeat until position >= n */
+       {  last = off;
+          off += ENT_SIZE(ENT_ADR(block_ptr,off));
+       }
+     CO(pci->level) = last;      /* save new block offset positioon */
+     return (last);
+  } /* scan_blk */
+
+
+int pascal last_entry()          /* find offset of last entry in block */
+  {
+     return( scan_blk(block_ptr->bend) );
+  } /* last_entry */
+
+
+/*  maintain list of free index blocks  */
+
+void pascal write_free(r, pb)    /* update list of free index blocks */
+  RECPOS r;                      /* free index position */
+  BLOCK *pb;                     /* free block */
+  {
+    pb->p0 = FREE_BLOCK;         /* mark as free */
+    pb->brec = pci->dx.ff;       /* keep old first free address */
+    write_if(pci->ixfile, r, (char *) pb, sizeof(BLOCK));
+    pci->dx.ff = r;              /* set first free address to r */
+  } /* write_free */
+
+
+RECPOS pascal get_free()         /* get address of free index block */
+  {
+    RECPOS  r, rt;
+
+    r = pci->dx.ff;              /* use block address ff if free */
+    if ( r != NULLREC )
+      {  read_if(r, (char *)&rt, sizeof( RECPOS ));
+         pci->dx.ff = rt;        /* save next free index block */
+      }
+    else                         /* else add to end of index file */
+      r = filelength (pci->ixfile);
+    return (r);                  /* return index block address */
+  } /* get_free */
+
+
+/*  general BPLUS block level functions  */
+
+int pascal find_block(pe, poff)    /* find a key with current block */
+  ENTRY *pe;                       /* use this entry */
+  int *poff;                       /* return offset within block */
+  {
+    register int pos, nextpos, ret;
+    pos = -1;
+    nextpos = 0;
+    ret = 1;
+    while ( nextpos < block_ptr->bend)   /* repeat until end of block */
+      {
+        ret = strcmp((char *)(pe->key),
+                     (char *)(ENT_ADR(block_ptr, nextpos)->key));
+        if (ret <= 0)              /* if the entry key >= search key */
+          {
+             if (ret == 0) pos = nextpos;   /* move to matching key  */
+             break;                         /* and break loop */
+          }
+        pos = nextpos;                      /* save current offset */
+        nextpos = next_entry(pos);          /* get next entry position */
+      }
+    CO(pci->level) = pos;         /* save offset within current block */
+    *poff = pos;                  /* store offset position */
+    return (ret);
+  } /* find_block */
+
+
+void pascal movedown(pb, off, n)       /* move part of block downward */
+  BLOCK *pb;                           /* block to move down */
+  int off;                             /* start move here */
+  int n;                               /* move this far */
+  {
+    memmove(ENT_ADR(pb, off),
+           ENT_ADR(pb, off + n),
+           pb -> bend - (off + n));
+  } /* movedown */
+
+
+void pascal moveup(pb, off, n)        /* move part of a block upward */
+  BLOCK *pb;                          /* the block */
+  int off;                            /* start move here */
+  int n;                              /* move up n bytes */
+  {
+    memmove(ENT_ADR(pb, off + n),
+            ENT_ADR(pb, off),
+            pb->bend - off);
+  } /* moveup */
+
+
+void pascal ins_block(pb, pe, off)      /* insert entry into a block */
+  BLOCK *pb;                            /* add to this block */
+  ENTRY *pe;                            /* add this entry */
+  int off;                              /* at this position */
+  {
+    int size;
+    size = ENT_SIZE(pe);                /* size of new entry */
+    moveup(pb,off,size);                /* move entries to make room */
+    copy_entry(ENT_ADR(pb,off),pe);     /* copy new entry */
+    pb->bend += size;                   /* adjust block size */
+  } /* ins_block */
+
+
+void pascal del_block(pb, off)          /* delete entry in a block */
+  BLOCK *pb;                            /* this block */
+  int off;                              /* delete entry at this position */
+  {
+    int ne;
+    ne = ENT_SIZE(ENT_ADR(pb, off));   /* size of deleted entry */
+    movedown(pb, off, ne);             /* move entries down */
+    pb->bend -= ne;                    /* adjust block size */
+  } /* del_block */
+
+
+/*  position at start/end of index  */
+
+int cdecl first_key(pix)              /* position to first key */
+  IX_DESC *pix;                       /* in this index file */
+  {
+    pci = pix;                        /* set global index descriptor */
+    block_ptr = &(pci->root);         /* start with the root */
+    CB(0) = 0L;                       /* root address is 0L */
+    CO(0) = -1;                       /* offset is -1 */
+    pci->level = 0;                   /* 0 level in index file */
+    while(block_ptr->p0 != NULLREC)   /* repeat for all levels */
+      {                               /* get index block for next level */
+        retrieve_block(++(pci->level), block_ptr->p0);
+        CO(pci->level) = -1;          /* position to start of block */
+      }
+    return ( IX_OK );
+  } /* first_key */
+
+
+int cdecl last_key(pix)               /* position at last key */
+  IX_DESC *pix;                       /* in this index file */
+  {
+    long  ads;
+    pci = pix;
+    block_ptr = &(pci->root);         /* start with the root */
+    CB(0) = 0L;
+    pci->level = 0;
+    if(last_entry() >= 0)             /* repeat for all levels */
+      {                               /* get block for next level */
+        while ((ads = ENT_ADR(block_ptr,last_entry())->idxptr) != NULLREC)
+             retrieve_block(++(pci->level), ads);
+      }
+    CO(pci->level) = block_ptr->bend; /* set offset position to the end */
+    return ( IX_OK );
+  } /* last_key */
+
+
+/*  get next, previous entries  */
+
+int cdecl next_key(pe, pix)           /* get next key */
+  ENTRY *pe;                          /* and put it here */
+  IX_DESC *pix;                       /* for this index */
+  {
+    RECPOS  address;
+    pci = pix;
+                                      /* get block for current level */
+    retrieve_block(pci->level, CB(pci->level));
+                                      /* set address for next level */
+    if(CO(pci->level) == -1) address = block_ptr->p0;
+    else
+      {
+        if (CO(pci->level) == block_ptr->bend) address = NULLREC;
+        else address = ENT_ADR(block_ptr, CO(pci->level))->idxptr;
+      }
+    while (address != NULLREC)        /* repeat until at leaf level */
+      {
+         retrieve_block(++(pci->level), address);
+         CO(pci->level) = -1;
+         address = block_ptr->p0;
+      }
+    next_entry(CO(pci->level));       /* get next entry for leaf block */
+    if (CO(pci->level) == block_ptr->bend)   /* check for end of block */
+      {
+        do
+          { if(pci->level == 0)       /* if this is the root block */
+              {
+                last_key(pci);        /* go to end of root block */
+                return (EOIX);        /* return end of index file */
+              }
+            --(pci->level);           /* level of ancestor block */
+            retrieve_block(pci->level, CB(pci->level));
+            next_entry(CO(pci->level));  /* next entry for ancestor */
+          } while (CO(pci->level) == block_ptr->bend);
+      }
+                                      /* copy the next entry and return */
+    copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level)));
+    return ( IX_OK );
+  } /* next_key */
+
+
+int cdecl prev_key(pe, pix)          /* get the previous key */
+  ENTRY *pe;                         /* put it here */
+  IX_DESC *pix;                      /* for this index */
+  {
+    RECPOS  address;
+    pci = pix;
+                                     /* get block for current level */
+    retrieve_block(pci->level, CB(pci->level));
+    prev_entry(CO(pci->level));      /* previous entry in this block */
+    if (CO(pci->level) == -1)
+      address = block_ptr->p0;
+    else
+      address = ENT_ADR(block_ptr, CO(pci->level))->idxptr;
+    if (address != NULLREC)          /* go to the leaf level of index */
+      { do
+          {
+            retrieve_block(++(pci->level), address);
+            address = ENT_ADR(block_ptr, last_entry())->idxptr;
+          } while (address != NULLREC);
+      }
+    if (CO(pci->level) == -1)        /* check if at beginning of block */
+      { do
+          {
+            if(pci->level == 0)      /* if this is the root block */
+              {
+                first_key(pci);      /* get first key */
+                return (EOIX);       /* and return end of index */
+              }
+            --(pci->level);          /* level for ancestor block */
+          } while (CO(pci->level) == -1);   /* repeat if beginning */
+        retrieve_block(pci->level, CB(pci->level));   /* get block  */
+      }
+                                     /* copy entry and return */
+    copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level)));
+    return ( IX_OK );
+  } /* prev_key */
+
+
+/*  insert new entries into tree  */
+
+void pascal split(l, pe, e)           /* split an index block */
+  int l;                              /* level in tree */
+  ENTRY *pe;                          /* entry to insert */
+  ENTRY *e;                           /* entry to pass up to next level */
+  {
+    int  half, ins_pos, size;
+    ins_pos = CO(pci->level);         /* save current offset */
+                                      /* and divide block in half */
+    half = scan_blk(block_ptr->bend / 2 + sizeof(RECPOS));
+    if (half == ins_pos)              /* if inserting at half */
+      *e = *pe;                       /* pass up entry pe */
+    else                              /* else copy entry at half */
+      {
+         copy_entry(e, ENT_ADR(block_ptr, half));
+         size = ENT_SIZE(e);
+         movedown(block_ptr, half, size);   /* move block entries down */
+         block_ptr->bend -= size;           /* and adjust the size */
+      }
+    spare_block = &BUFBLOCK(new_cache());   /* allocate a spare block */
+    memmove(spare_block->entries,           /* and copy half the entries */
+           ENT_ADR(block_ptr,half),
+           block_ptr->bend - half);
+    spare_block->brec = get_free();         /* index address of new block */
+    spare_block->bend = block_ptr->bend - half;    /* set size of block */
+    spare_block->p0 = e->idxptr;            /* set all the pointers */
+    block_ptr->bend = half;
+    e->idxptr = spare_block->brec;
+    if (ins_pos < half)                     /* insert the new entry */
+      ins_block(block_ptr,pe,ins_pos);      /* in current block */
+    else if (ins_pos > half)                /* else insert the entry */
+      {                                     /* in the spare block */
+         ins_pos -= ENT_SIZE(e);
+         ins_block(spare_block,pe,ins_pos - half);
+         CB(l) = e->idxptr;                 /* set block address */
+         CO(l) = CO(l) - half;              /* and offset */
+      }
+    write_if(pci->ixfile, spare_block->brec,   /* write to disk */
+             (char *) spare_block, sizeof(BLOCK));
+  } /* split */
+
+
+void pascal ins_level(l, e)        /* insert an entry e */
+  int l;                           /* into block level l */
+  ENTRY *e;
+  {
+    int  i;
+    if ( l < 0)                    /* tree height has increased */
+      {  for (i = 1; i < MAX_LEVELS; i++)   /* save offset and addresses */
+           {  CO(MAX_LEVELS - i) = CO(MAX_LEVELS - i - 1);
+              CB(MAX_LEVELS - i) = CB(MAX_LEVELS - i - 1);
+           }
+                                   /* copy old root to spare block */
+         memmove(spare_block, &(pci->root), sizeof(BLOCK));
+                                  /* get index address and write to disk */
+         spare_block->brec = get_free();
+         write_if(pci->ixfile, spare_block->brec,
+                  (char *) spare_block, sizeof(BLOCK));
+         pci->root.p0 = spare_block->brec;    /* set p0 pointer */
+         copy_entry((ENTRY *) (pci->root.entries), e);  /* copy insert e */
+         pci->root.bend = ENT_SIZE(e);        /* root contains only e */
+         CO(0) = 0;                           /* root offset is 0 */
+         pci->level = 0;                      /* set current level */
+         (pci->dx.nl)++;                      /* increment no. of levels */
+      }
+    else ins_block(block_ptr,e,CO(l));        /* insert in current block */
+  } /* ins_level */
+
+
+int pascal insert_ix(pe, pix)         /* insert at current level */
+  ENTRY *pe;                          /* insert entry pe */
+  IX_DESC *pix;                       /* into this index */
+  {
+    ENTRY    e, ee;
+    int h;
+    h = 0;
+    pci = pix;
+    ee = *pe;
+    do
+      {
+         if(CO(pci->level) >= 0)      /* set new offset */
+           CO(pci->level) +=
+                  ENT_SIZE(ENT_ADR(block_ptr, CO(pci->level)));
+         else
+           CO(pci->level) = 0;
+         update_block();           /* we are going to change this block */
+                                   /* if new block size < split size */
+         if( (block_ptr->bend + ENT_SIZE(&ee)) <= split_size)
+           {
+             ins_level(pci->level, &ee);   /* insert into current block */
+             break;                        /* and break */
+           }
+         else
+           {
+             h = 1;                        /* must reset index pointers */
+             split(pci->level,&ee, &e);    /* split the current block */
+             ee = e;                       /* this entry is passed up */
+             pci->level--;                 /* to insert at this level */
+             if (pci->level < 0)           /* increase tree height */
+               {
+                 ins_level(pci->level, &e);
+                 break;
+               }
+                                           /* get block for next level */
+             retrieve_block(pci->level, CB(pci->level));
+           }
+      }
+    while (1);
+    if (h) find_ix(pe, pix, 0);           /* reset pointers if necessary */
+    return ( IX_OK );
+  } /* insert_ix */
+
+
+/*  BPLUS find and add key functions  */
+
+int pascal find_ix(pe, pix, find)     /* search an index file */
+  ENTRY *pe;                          /* for this entry */
+  IX_DESC *pix;                       /* in this index */
+  int find;                           /* 1 to find_key, 0 to locate_key */
+  {
+    int      level, off, ret;
+    RECPOS   ads;
+    pci = pix;
+    ads = 0L;                            /* start at the root */
+    level = ret = 0;
+    while (ads != NULLREC)               /* repeat until done */
+      {  pci->level = level;             /* set level */
+         retrieve_block(level, ads);     /* get index block */
+                                         /* and search for entry */
+         if (find_block(pe, &off) == 0) ret = 1;     /* found? */
+         if (ret && find) break;                     /* done? */
+         if (off == -1)                  /* get next block address */
+           ads = block_ptr->p0;
+         else
+           ads = ENT_ADR(block_ptr, off)->idxptr;
+         CO(level++) = off;              /* increment level */
+       }
+     return ( ret );
+   } /* find_ix */
+
+
+int cdecl find_key(pe, pix)           /* find a key */
+  ENTRY *pe;                          /* this entry */
+  IX_DESC *pix;                       /* in this index */
+  {
+    int ret;
+    ret = find_ix(pe, pix, 1);       /* find_ix does all the work */
+                                     /* if found, copy the entry */
+    if ( ret ) copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level)));
+    return ( ret );
+  } /* find_key */
+
+
+int cdecl add_key(pe, pix)            /* add a new key */
+  ENTRY *pe;                          /* this entry */
+  IX_DESC *pix;                       /* this index file */
+  {
+    int ret;
+    ret = find_ix(pe, pix, 0);        /* see if key is already in index */
+                                      /* if found, are dupicates are OK? */
+    if ( ret && (pci->duplicate == 0)) return ( IX_FAIL );
+    pe->idxptr = NULLREC;             /* add new key on leaf level */
+    return (insert_ix(pe, pix));      /* insert_ix does the work */
+  } /* add_key */
+
+
+int cdecl locate_key(pe, pix)         /* locate first key */
+  ENTRY *pe;                          /* <= this entry */
+  IX_DESC *pix;                       /* in this index */
+  {
+    int ret;
+    ret = find_ix(pe, pix, 1);        /* search index for entry */
+                                      /* if found, copy it to pe */
+    if (ret) copy_entry(pe, ENT_ADR(block_ptr, CO(pci->level)));
+                                      /* else get the next key */
+    else if (next_key(pe,pix) == EOIX) ret = EOIX;
+    return ( ret );
+  } /* locate_key */
+
+
+int cdecl find_exact(pe, pix)         /* find an exact match */
+  ENTRY *pe;                          /* for this entry */
+  IX_DESC * pix;                      /* in this index */
+  {
+    int  ret;
+    ENTRY e;
+    copy_entry(&e, pe);               /* make a copy of the entry */
+    ret = find_key(&e, pix);          /* is it in the index? */
+    if ( ret && pci->duplicate)       /* if duplicate key are allowed */
+      {                               /* then search for recptr match */
+        do
+          {
+            ret = (e.recptr == pe->recptr);
+            if( !ret )  ret = next_key(&e, pci);
+            if (ret) ret = (strcmp(e.key, pe->key) == 0);
+            if ( !ret ) return ( 0 );     /* no match was found */
+          } while ( !ret );
+      }
+    copy_entry(pe, &e);              /* if found, data is contained in e */
+    return ( ret );
+  } /* find_exact */
+
+
+/* BPLUS delete key functions */
+
+int cdecl delete_key(pe, pix)         /* delete a key */
+  ENTRY *pe;                          /* this entry */
+  IX_DESC *pix;                       /* in this index */
+  {
+     ENTRY   e;
+     RECPOS  ads;
+     int     h, leveli, levelf;
+                                      /* search index for exact match */
+     if (!find_exact(pe, pix))  return( IX_FAIL );
+     h = 1;
+     if ((ads = pe->idxptr) != NULLREC)    /* if not the leaf level */
+       {
+          leveli = pci->level;        /* save current level */
+          do                          /* go to leaf level of index */
+            {
+               retrieve_block(++(pci->level), ads);
+               CO(pci->level) = -1;
+            }
+          while ((ads = block_ptr->p0) != NULLREC);
+          CO(pci->level) = 0;
+          copy_entry(&e, ENT_ADR(block_ptr, CO(pci->level)));
+          levelf = pci->level;        /* save leaf level */
+          pci->level = leveli;        /* reset starting level */
+          replace_entry(&e);          /* replace with entry from leaf */
+          pci->level = levelf;        /* leaf level */
+       }
+     while ( h )
+       {
+                             /* get block and delete current entry */
+          retrieve_block(pci->level, CB(pci->level));
+          del_block(block_ptr, CO(pci->level));
+          update_block();             /* block has been changed */
+          if ( (pci->level == 0) && (block_ptr->bend == 0))
+          /* tree was reduced in height */
+            {
+              if (pci->root.p0 != NULLREC)    /* replace root block */
+                {
+                  retrieve_block(++pci->level, pci->root.p0);
+                  memmove(&(pci->root), block_ptr, sizeof(BLOCK));
+                  (pci->dx.nl)--;           /* decrement number of levels */
+                  write_free(block_ptr->brec, block_ptr);  /* reuse space */
+                  BUFDIRTY(cache_ptr) = 0;       /* block saved on disk */
+                  BUFHANDLE(cache_ptr) = 0;
+                }
+              break;
+            }
+          /* see if we can combine index blocks */
+          h = (block_ptr->bend < comb_size) && (pci->level > 0);
+          if ( h )
+              h = combineblk(CB(pci->level), block_ptr->bend);
+       }
+    find_ix(pe, pix, 0);         /* restore CO and CB for each level */
+    return( IX_OK );
+  } /* delete_key */
+
+
+int pascal combineblk(ads, size)      /* combine index blocks */
+  RECPOS ads;                         /* block at this address */
+  int size;                           /* and is this size */
+  {
+    ENTRY  e;
+    RECPOS address;
+    int    esize, off, ret, saveoff, ibuff;
+    ret = 0;
+                                   /* ancestor level and save offset */
+    saveoff = CO(--(pci->level));
+                                   /* retrieve ancestor index block */
+    retrieve_block(pci->level, CB(pci->level));
+    if ((off = next_entry( saveoff )) < block_ptr->bend)
+      /* combine with page on right */
+      {
+        if ( (ENT_SIZE(ENT_ADR(block_ptr, off)) + size) < split_size)
+          /* okay to combine */
+          {
+            copy_entry(&e, ENT_ADR(block_ptr, off));   /* save entry */
+            address = ENT_ADR(block_ptr, CO(pci->level))->idxptr;
+            retrieve_block(++pci->level, address);
+            ibuff = cache_ptr;           /* save cache pointer */
+            spare_block = block_ptr;     /* use as spare block */
+            retrieve_block(pci->level, ads);
+            esize = ENT_SIZE(&e);
+            if(((block_ptr->bend + spare_block->bend + esize) >= split_size)
+                 && (spare_block->bend <= block_ptr->bend + esize))
+               return( ret );
+            e.idxptr = spare_block->p0;
+            ins_block(block_ptr, &e, block_ptr->bend);
+            update_block();
+            if ((block_ptr->bend + spare_block->bend) < split_size)
+            /* combine the blocks */
+              {
+                memmove(ENT_ADR(block_ptr, block_ptr->bend),
+                       ENT_ADR(spare_block, 0),
+                       spare_block->bend);
+                /* set block length and free spare block space */
+                block_ptr->bend += spare_block->bend;
+                write_free(spare_block->brec, spare_block);
+                BUFDIRTY(ibuff) = 0;
+                BUFHANDLE(ibuff) = 0;
+                --pci->level;
+                ret = 1;
+              }
+            else
+            /* move an entry up to replace the one moved */
+              {
+                copy_entry(&e, ENT_ADR(spare_block, 0));
+                esize = ENT_SIZE(&e);
+                /* fixup spare block and pointers */
+                movedown(spare_block, 0, esize);
+                spare_block->bend -= esize;
+                spare_block->p0 = e.idxptr;
+                BUFDIRTY(ibuff) = 1;
+                --(pci->level);
+                replace_entry(&e);
+              }
+          }
+      }
+    else
+      /* move from page on left */
+      {
+        if ( (ENT_SIZE(ENT_ADR(block_ptr, CO(pci->level))) + size)
+                 < split_size)
+          /* okay to proceed */
+          {
+            copy_entry(&e, ENT_ADR(block_ptr, saveoff));  /* save entry */
+            /* get page which is on the left */
+            off = prev_entry(saveoff);
+            if (CO(pci->level) == -1) address = block_ptr->p0;
+            else address = ENT_ADR(block_ptr, CO(pci->level))->idxptr;
+            retrieve_block(++pci->level, address);
+            off = last_entry();
+            ibuff = cache_ptr;
+            /* set spare block to left page */
+            spare_block = block_ptr;
+            /* get current block */
+            retrieve_block(pci->level, ads);
+            esize = ENT_SIZE(&e);
+            if(((block_ptr->bend + spare_block->bend + esize) >= split_size)
+                 && (spare_block->bend <= block_ptr->bend + esize))
+               return( ret );
+            BUFDIRTY(ibuff) = 1;           /* we have changed things */
+            CO(pci->level) = 0;
+            e.idxptr = block_ptr->p0;
+            ins_block(block_ptr, &e, 0);
+            if ((block_ptr->bend + spare_block->bend) < split_size)
+            /* combine the blocks */
+              {
+                memmove(ENT_ADR(spare_block, spare_block->bend),
+                       ENT_ADR(block_ptr, 0),
+                       block_ptr->bend);
+                /* set block length and freeup block */
+                spare_block->bend += block_ptr->bend;
+                write_free(block_ptr->brec, block_ptr);
+                BUFDIRTY(cache_ptr) = 0;
+                BUFHANDLE(cache_ptr) = 0;
+                CO(--(pci->level)) = saveoff;
+                ret = 1;
+              }
+            else
+            /* move an entry up to replace the one moved */
+              {
+                 block_ptr->p0 = ENT_ADR(spare_block,off)->idxptr;
+                 copy_entry(&e, ENT_ADR(spare_block, off));
+                 spare_block->bend = off;
+                 update_block();
+                 CO(--(pci->level)) = saveoff;
+                 replace_entry(&e);
+              }
+          }
+      }
+    return ( ret );
+  } /* combineblk */
+
+
+void pascal replace_entry(pe)     /* replace entry at current position */
+  ENTRY *pe;                      /* with this entry */
+  {
+    retrieve_block(pci->level, CB(pci->level));   /* get current block */
+    /* set address for the replacement entry */
+    pe->idxptr = ENT_ADR(block_ptr, CO(pci->level))->idxptr;
+    del_block(block_ptr, CO(pci->level));      /* now delete the entry */
+    prev_entry(CO(pci->level));                /* backup one entry */
+    insert_ix(pe, pci);                        /* and insert new entry */
+  } /* replace_entry */
+
+
\ No newline at end of file
diff --git a/bplus/LISTTREE.C b/bplus/LISTTREE.C
new file mode 100644
index 0000000..557fe06
--- /dev/null
+++ b/bplus/LISTTREE.C
@@ -0,0 +1,89 @@
+/*************************************************************************/
+/*                                                                       */
+/*                             LISTTREE.C                                */
+/*                                                                       */
+/*  This program displays each block in an index file.  The root node    */
+/*  of the index tree is displayed first.  Then the left most descendant */
+/*  block is displayed for each level in the tree.  After the leaf block */
+/*  is displayed, the right most descendant from the ancestor block is   */
+/*  displayed.  That is, a preordering method of transversing the tree   */
+/*  is used.  The complete block is displayed including the data file    */
+/*  address, the index file address, and the index key.  The printtree   */
+/*  routine is recursive.                                                */
+/*                                                                       */
+/*************************************************************************/
+
+#include <stdio.h>
+#include "bplus.h"
+
+/* constant and macros */
+#define  NULLREC  (-1L)
+#define  ENT_ADR(pb,off)  ((ENTRY*)((char*)((pb)->entries) + off))
+#define  ENT_SIZE(pe)     strlen((pe)->key) + 1 + 2 * sizeof(RECPOS)
+
+/* global variables defined in BPLUS.C */
+extern  IX_DESC    *pci;
+extern  BLOCK      *block_ptr;
+
+IX_DESC ixfile;
+
+void pascal retrieve_block(int, RECPOS);
+int pascal copy_entry(ENTRY *, ENTRY *);
+
+void print_blk(pb)                 /* list each entry in block pb */
+   BLOCK *pb;
+  {
+    int i;
+    i = 0;
+    printf("%ld  ",pb->brec);
+    printf("%d  %ld  ",pb->bend,pb->p0);
+    while (i < pb->bend)
+      {
+        printf(" %ld ",ENT_ADR(pb,i) -> idxptr);
+        printf(" %ld ",ENT_ADR(pb,i) -> recptr);
+        printf("%s    ",ENT_ADR(pb,i) -> key);
+        i = i + ENT_SIZE(ENT_ADR(pb,i));
+      }
+    printf("\n");
+  }
+
+void printtree(num, l, level)             /* print the index tree */
+   RECPOS num;                            /* index block address */
+   int l;                                 /* indent each level l */
+   int level;                             /* level in index file */
+  {
+    long  address;
+    int  end, i, j;
+    if (num != NULLREC)
+      {
+        for (i=1; i<=l; i++)
+          printf("    ");
+        retrieve_block(level, num);
+        print_blk(block_ptr);
+        address = block_ptr -> p0;
+        printtree(address, l + 1,level + 1);
+        retrieve_block(level, num);
+        j = 0;
+        end = block_ptr -> bend;
+        while (j < end)
+        {
+          address = ENT_ADR(block_ptr,j) -> idxptr;
+          printtree(address, l + 1, level + 1);
+          retrieve_block(level, num);
+          j = j + ENT_SIZE(ENT_ADR(block_ptr,j));
+        }
+      }
+    }
+
+main()
+  {
+    char name[80];
+
+    printf("\n\n                       Display An Index Tree\n\n");
+    printf("     Name of index file: ");
+    gets(name);
+    open_index(name,&ixfile, 1);
+    printtree(0L,1,0);
+    close_index(&ixfile);
+  }
+
\ No newline at end of file
diff --git a/bplus/NAMES.C b/bplus/NAMES.C
new file mode 100644
index 0000000..70c1564
--- /dev/null
+++ b/bplus/NAMES.C
@@ -0,0 +1,227 @@
+/*******************************************************************/
+/*                              NAMES.C                             */
+/*                                                                  */
+/* This example shows how easy it is to write a program for an      */
+/* online address book using the B-PLUS file indexing toolkit.      */
+/* The program creates a file of names, addresses, and telephone    */
+/* numbers.  A record is displayed on the screen by entering part   */
+/* or all of the name.  Although the program is usefully as written */
+/* it has purposely been kept simple.  You may want to add new      */
+/* features to the progran.                                         */
+/*                                                                  */
+/********************************************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include "bplus.h"
+
+
+typedef struct              /* Here is the address record definition */
+  {
+     char lastname[16];     /* last name           */
+     char firstname[16];    /* first name          */
+     char address1[31];     /* first address line  */
+     char address2[31];     /* second address line */
+     char city[21];         /* the city            */
+     char state[3];         /* the state           */
+     char zipcode[6];       /* postal zip code     */
+     char telephone[14];    /* telephone number    */
+  }  ADDRESS;
+
+
+IX_DESC  nameindex;             /* index file variable  */
+FILE     *namefile;             /* data file pointer    */
+ADDRESS  person;                /* data record variable */
+
+
+void openfiles(void);
+void closefiles(void);
+int addrecord(void);
+void getstring(char*, int);
+void newaddress(void);
+void printname(ENTRY*);
+void getname(void);
+void nextname(void);
+void listnames(void);
+
+
+void openfiles()
+  /* If the file NAMES.DAT already exist, open the index and data */
+  /* file.  Otherwise, these files are created.                   */
+  {
+    if ((namefile = fopen("names.dat","r+")) != NULL)
+      open_index("names.idx", &nameindex, 1);      /* open index file  */
+    else
+    {
+      namefile = fopen("names.dat","w+");          /* create data file */
+      if (namefile == NULL)
+        {
+          printf("Unable to open namefile\n");
+          exit(1);
+        }
+      make_index("names.idx", &nameindex, 1);   /* creat index file     */
+    }                                           /* allow duplicate keys */
+  } /* openfiles */
+
+
+void closefiles()
+  /* close all files and exit */
+  {
+    fclose(namefile);
+    close_index(&nameindex);
+    exit(0);
+  } /* closefiles */
+
+
+int addrecord()
+  /* add a new address to the data file - add index to index file */
+  {
+    ENTRY ee;
+    char name[32];
+    int ret;
+    ret = fseek(namefile, 0L, SEEK_END);      /* seek to end of datafile  */
+    if (ret == 0)
+      {
+        strcpy(ee.key, person.lastname);      /* key is last name followed */
+        strcat(ee.key, person.firstname);     /* first name.  Capitalize   */
+        strupr(ee.key);                       /*    and copy to ee.key.    */
+        ee.recptr = ftell(namefile);          /* get position in datafile  */
+        if (ee.recptr != -1L)
+          {
+            if (add_key(&ee, &nameindex) == IX_OK)     /* add key to index */
+              {
+                fwrite(&person,sizeof(person),1,namefile);  /* add address */
+                return (IX_OK);
+              }
+          }
+      }
+    else printf("Seek error - data file");
+    return (IX_FAIL);
+  } /* addrecord */
+
+
+void getstring(mes, length)
+  char *mes;
+  int length;
+  /* input a string and check that it is not too long   */
+  {
+    char message[80];
+    gets(message);
+    if (strlen(message) > length) message[length] = '\0';
+    strcpy(mes,message);
+  } /* getstring */
+
+
+void newaddress()
+  /* add new address records */
+  {
+    while (1)
+     {
+       printf("\n\nLast Name      : ");
+       getstring(person.lastname,15);
+       if ( strlen(person.lastname) > 0)       /* quit if no last name */
+         {
+           printf("First Name     : ");
+           getstring(person.firstname,15);
+           printf("Address Line 1 : ");
+           getstring(person.address1,30);
+           printf("Address Line 2 : ");
+           getstring(person.address2,30);
+           printf("City           : ");
+           getstring(person.city,20);
+           printf("State          : ");
+           getstring(person.state,2);
+           printf("Zip Code       : ");
+           getstring(person.zipcode,5);
+           printf("Telephone      : ");
+           getstring(person.telephone,13);
+           addrecord();                     /* update data and index files */
+           printf("\n");
+         }
+         else return ;
+     }
+  } /* newaddress */
+
+
+void printname(e)
+  ENTRY *e;
+  /* retrieve a data record and print it on the screen */
+  {
+    int ret;
+
+    /* seek to the record address stored in ENTRY e->recptr */
+    ret = fseek(namefile, e->recptr, SEEK_SET);
+
+    if (ret == 0)     /* if OK read the record and display */
+      {
+        fread(&person,sizeof(person),1,namefile);
+        printf("\n\n            %s %s" , person.firstname,person.lastname);
+        printf("\n            %s", person.address1);
+        if (strlen(person.address2) > 0)
+           printf("\n            %s", person.address2);
+        printf("\n            %s, %s  %s", person.city,person.state,person.zipcode);
+        printf("\n            %s\n", person.telephone);
+      }
+    else printf("Seek error - data file");
+  } /* printname */
+
+
+void getname()
+  /* Get an address record by entering part or all of name */
+  /* Enter last name first then first name with no spaces  */
+  {
+    ENTRY ee;
+    printf("\n\nEnter name: ");
+    gets(ee.key);
+
+    /* make all upper case letters and copy to ee.key */	
+    strupr(ee.key);
+
+    /* use locate_key instead of find_key so an exact match not required */
+    if (locate_key(&ee, &nameindex) != EOIX) printname(&ee);
+    else printf("No key this large in index file\n");
+  } /* getname */
+
+
+void nextname()
+  /* display the next address in the address file */
+  {
+    ENTRY ee;
+    if (next_key(&ee, &nameindex) == IX_OK) printname(&ee);
+    else printf("\nEnd of index file\n");
+  } /* nextname */
+
+
+void listnames()
+  /* list all the names in the address file */
+  {
+    ENTRY ee;
+    first_key(&nameindex);
+    while (next_key(&ee, &nameindex) == IX_OK) printname(&ee);
+  } /* listnames */
+
+main()
+  /* Here is the main program loop */
+  {
+    char cmd;
+    int  done;
+    done = 0;
+    openfiles();
+    do
+     {
+       printf("\nCommand: A (Add Name), F (Find), N (Next), L (List), Q (Quit): ");
+       cmd = toupper(getche());
+       switch (cmd)
+        {
+          case 'A': newaddress(); break;   /* add a name to address file   */
+          case 'F': getname(); break;      /* find an address              */
+          case 'N': nextname(); break;     /* display next address in file */
+          case 'L': listnames(); break;    /* display all addresses        */
+          case 'Q': closefiles();          /* quit and close files         */
+        }
+      }
+    while (!done);
+  } /* main */
+
+
\ No newline at end of file
diff --git a/bplus/READ.ME b/bplus/READ.ME
new file mode 100644
index 0000000..b5fb306
--- /dev/null
+++ b/bplus/READ.ME
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+                               BPLUS.C - Version 1.1A
+
+
+             Thank you for registering your copy of the BPLUS "toolkit"
+        with Hunter and Associates.  Your support is appreciated.
+        Customers like you help reinforce the principal that quality
+        "shareware" software is indeed a viable one.
+
+             This version of BPLUS has been thoroughly tested and is
+        properly configured for Turboc C Versions 1.0 and 1.5, and
+        Microsoft's Quick C, C 5.0, and C 5.1 (OS/2).  If you are using
+        Microsoft's C 4.0 compiler, you must use the memcpy rather than
+        the memmove routine.  See the comments in BPLUS.C.
+
+             Your registration disk contains nine files.  These files are
+        the following:
+
+             BPLUS.H   -  the header file to include in your "C" programs
+                          which use the BPLUS Toolkit
+
+             BPLUS.C   -  the source code for Version 1.1 of BPLUS
+
+             CPLUS.C   -  the source code for Version 1.1 of BPLUS with
+                          extensive comments added
+
+             BPLUS.DOC -  the user's manual for BPLUS
+
+             VTEST.C   -  a test program which creates two index files
+
+             NAMES.C   -  a program for creating and using an on-line
+                          name and address book
+
+             REINDEX.C -  a program to re-index the data file used in
+                          NAMES.C
+
+             LISTTREE.C - a program which lists the index tree
+
+             READ.ME   -  this message file
+
+
+        ADDRESS CHANGE
+
+              We have moved and our new address is:
+
+                       7900 Edgewater Drive
+                       Wilsonville, OR  97070
+                       Tel: (503) 694-1449
+
\ No newline at end of file
diff --git a/bplus/REINDEX.C b/bplus/REINDEX.C
new file mode 100644
index 0000000..01ad8aa
--- /dev/null
+++ b/bplus/REINDEX.C
@@ -0,0 +1,100 @@
+/********************************************************************/
+/*                            REINDEX.C                             */
+/*                                                                  */
+/* This is a sample program which demonstrates how to reindex a     */
+/* data file.  The data file which is used is the one created by    */
+/* NAMES.C which creates an online address book using the B-PLUS    */
+/* file indexing toolkit.                                           */
+/*                                                                  */
+/********************************************************************/
+
+
+#include <stdio.h>
+#include <string.h>
+#include "bplus.h"
+
+
+typedef struct              /* Here is the address record definition */
+  {
+     char lastname[16];     /* last name           */
+     char firstname[16];    /* first name          */
+     char address1[31];     /* first address line  */
+     char address2[31];     /* second address line */
+     char city[21];         /* the city            */
+     char state[3];         /* the state           */
+     char zipcode[6];       /* postal zip code     */
+     char telephone[14];    /* telephone number    */
+  }  ADDRESS;
+
+
+IX_DESC  nameindex;             /* index file variable  */
+FILE     *namefile;             /* data file pointer    */
+ADDRESS  person;                /* data record variable */
+
+
+void openfiles(void);
+void closefiles(void);
+long makeindex(void);
+
+
+void openfiles()
+  /* The file NAMES.DAT already exists.  It is  opened and a new  */
+  /* index file is created.                                       */
+  {
+    if ((namefile = fopen("names.dat","r")) != NULL)
+      make_index("names.idx", &nameindex, 1);   /* create index file */
+    else
+    {
+      printf("\nUnable to open NAMES.DAT\n");
+      exit(1);
+    }
+  } /* openfiles */
+
+
+void closefiles()
+  /* close all files and exit */
+  {
+    fclose(namefile);
+    close_index(&nameindex);
+  } /* closefiles */
+
+
+long makeindex()
+  /* read address records and add key to index file */
+  {
+    ENTRY ee;
+    long num, position, size;
+    int  ret;
+    size = sizeof(person);                    /* data record size */
+    ret = fread(&person,size,1,namefile);     /* ret is number of data  */
+                                              /* records that were read */
+    num = 0L;                                 /* num = data items read */
+    position = 0L;                            /* position in datafile */
+    while (ret == 1)
+      {
+        strcpy(ee.key, person.lastname);      /* key is last name followed */
+        strcat(ee.key, person.firstname);     /* first name.  Capitalize   */
+        strupr(ee.key);			      /*    and copy to ee.key.    */
+        ee.recptr = position;                 /* position in datafile  */
+        if (add_key(&ee, &nameindex) != IX_OK)     /* add key to index */
+           printf("Error while adding key to index file");
+        position += size;                     /* new position in datafile */
+        num++;                                /* increment data items read */
+        ret = fread(&person,sizeof(person),1,namefile);
+      }
+      return ( num );
+  } /* makeindex */
+
+
+main()
+  /* Here is the main program */
+  {
+    long num;
+    openfiles();
+    printf("\n\n     MAKING THE NEW INDEX FILE\n\n");
+    num = makeindex();
+    closefiles();
+    printf("     REINDEXING IS COMPLETE - %ld ITEMS WERE INDEXED\n", num);
+  } /* main */
+
+
\ No newline at end of file
diff --git a/bplus/VTEST.C b/bplus/VTEST.C
new file mode 100644
index 0000000..9f2dc05
--- /dev/null
+++ b/bplus/VTEST.C
@@ -0,0 +1,103 @@
+/*                     VTEST.C test program.                        */
+/*  This is a simple test program which creates two index files.    */
+/*  100 keys are added to each file, some keys are deleted and      */
+/*  then the keys are added back to the file.  The keys are listed  */
+/*  in ascending and decending order.                               */
+
+#include "bplus.h"
+#include <stdio.h>
+#include <time.h>
+#include <conio.h>
+
+IX_DESC name1, name2;        /* index file variables */
+
+void uplist(name)            /* list keys in ascending order */
+  IX_DESC *name;
+  {
+    ENTRY ee;
+    first_key(name);
+    while (next_key(&ee, name) == IX_OK) printf("%s   ",ee.key);
+    printf("\nPress any key to continue \n");
+    getch();
+  }
+
+void downlist(name)           /* list keys in decending order  */
+  IX_DESC *name;
+  {
+    ENTRY ee;
+    last_key(name);
+    while (prev_key(&ee, name) == IX_OK) printf("%s   ",ee.key);
+    printf("\nPress any key to continue \n");
+    getch();
+  }
+
+main()
+  {
+    long i;
+    long ltime;
+    ENTRY e;
+    printf("Make two index files\n");
+    make_index("test1.idx",&name1, 0);
+    make_index("test2.idx",&name2, 1);
+    printf("Indexing 100 items in two index files:\n");
+
+    /* note the time to index */
+    time(&ltime);
+    printf("%s",ctime(&ltime));
+
+    /* add 100 keys to each index file */
+    for (i = 0L; i < 100L; i++)
+      {
+        e.recptr = i;
+        sprintf(e.key, "VALUE1-%2d",i);
+        add_key(&e, &name1);
+        sprintf(e.key, "VALUE2-%2d",i);
+        add_key(&e, &name2);
+      }
+
+    /* print the time required for indexing the two files */
+    time(&ltime);
+    printf("%s",ctime(&ltime));
+    printf("Indexing is complete\n\n");
+    printf("List the keys in each index file in ascending order:\n\n");
+    uplist(&name1);
+    uplist(&name2);
+
+    /* delete some keys and list again */
+    printf("\nNow delete all keys from 20 to 90 in each file\n\n");
+    for (i = 20L; i < 90L; i++)
+      {
+        e.recptr = i;
+        sprintf(e.key, "VALUE1-%2d",i);
+        delete_key(&e, &name1);
+        sprintf(e.key, "VALUE2-%2d",i);
+        delete_key(&e, &name2);
+      }
+    printf("List the keys now for each index file in ascending order:\n\n");
+    uplist(&name1);
+    uplist(&name2);
+
+    /* add the keys back and list again */
+    printf("Now add back all items from 20 to 90 to each index\n\n");
+    for (i = 20L; i < 90L; i++)
+      {
+        e.recptr = i;
+        sprintf(e.key, "VALUE1-%d",i);
+        add_key(&e, &name1);
+        sprintf(e.key, "VALUE2-%d",i);
+        add_key(&e, &name2);
+      }
+    printf("List the keys for each index file again in ascending order:\n\n");
+    uplist(&name1);
+    uplist(&name2);
+
+    /* list both files in decending order */
+    printf("List the keys for each index file in decending order\n\n");
+    downlist(&name1);
+    downlist(&name2);
+
+    /* always close all files */
+    close_index(&name1);
+    close_index(&name2);
+  }
+
\ No newline at end of file
diff --git a/fastfngr/FASTFNGR.BAS b/fastfngr/FASTFNGR.BAS
new file mode 100644
index 0000000..33a6f16
--- /dev/null
+++ b/fastfngr/FASTFNGR.BAS
@@ -0,0 +1,6 @@
+'HOTKEY.DLL functions
+DefInt A-Z
+
+Declare Function CreateHK& Lib "HOTKEY.DLL" (ByVal KeyCode, ByVal Shift, ByVal hWnd, ByVal UserVK)
+Declare Sub KillHK Lib "HOTKEY.DLL" (ByVal hHotKey&)
+
diff --git a/fastfngr/FASTFNGR.EXE b/fastfngr/FASTFNGR.EXE
new file mode 100644
index 0000000..d61b308
--- /dev/null
+++ b/fastfngr/FASTFNGR.EXE
Binary files differ
diff --git a/fastfngr/FASTFNGR.FRM b/fastfngr/FASTFNGR.FRM
new file mode 100644
index 0000000..7f8eed1
--- /dev/null
+++ b/fastfngr/FASTFNGR.FRM
Binary files differ
diff --git a/fastfngr/FASTFNGR.INI b/fastfngr/FASTFNGR.INI
new file mode 100644
index 0000000..71f12bd
--- /dev/null
+++ b/fastfngr/FASTFNGR.INI
@@ -0,0 +1,42 @@
+[Aliases]
+3=prthplj
+3l=prthplj /tr1
+4=4print -q -s -oprn
+4t=c:\4tex\texfiles\4tex
+bin=cdd c:\bin
+c=cls  
+cd=cdd
+ck=chkdsk
+cp=copy
+d=dir /o/l
+dw=cdd c:\dwnl
+e=exit
+em=d:\emacs\emacs @d:\emacs\emacs.rc
+gm=c:\bin\demacs
+h=cd\
+lo=exit
+ll=c:\ll\llremote
+ls=ls -al
+lt=latex
+nu=net use /yes
+p=pcopy
+pk=pkarc
+pl=pdel /nw
+pm=pmap
+pp=pp -w80 -l60 -h -n
+px=pkxarc
+s=ds ne /s
+t=xpand type
+tm=cdd c:\tmp
+tn=telnet
+tx=c:\telix\telix
+v=list
+wi=whereis
+win=runwin
+wp=cdd c:\docs
+x= tdir
+zc=pkzip -z
+zk=pkzip 
+zl=pkunzip -v
+zx=pkunzip
+
diff --git a/fastfngr/FASTFNGR.MAK b/fastfngr/FASTFNGR.MAK
new file mode 100644
index 0000000..9f17e79
--- /dev/null
+++ b/fastfngr/FASTFNGR.MAK
@@ -0,0 +1,10 @@
+FASTFNGR.FRM
+C:\WINDOWS\SYSTEM\CMDIALOG.VBX
+C:\WINDOWS\SYSTEM\GRID.VBX
+C:\WINDOWS\SYSTEM\MSOLE2.VBX
+FASTFNGR.BAS
+ProjWinSize=76,573,225,148
+ProjWinShow=2
+IconForm="FastFinger"
+Title="FASTFNGR"
+ExeName="FASTFNGR.EXE"
diff --git a/fastfngr/FASTFNGR.TXT b/fastfngr/FASTFNGR.TXT
new file mode 100644
index 0000000..a249ae2
--- /dev/null
+++ b/fastfngr/FASTFNGR.TXT
@@ -0,0 +1,429 @@
+Dim Paths(50) As String
+Dim Extensions(5) As String
+Dim Pindex As Integer
+
+Const MaxAlias = 100
+Dim Aliases(MaxAlias, 2) As String
+Dim aindex As Integer
+
+Const MaxHist = 20
+Dim HistIndex
+Dim HistBuff(MaxHist) As String
+Dim HistRoll
+Dim PBIndex
+Dim MaxHistUsed
+
+Const HOTKEY = 32       ' Space Bar
+Const ToggleKey = 200   ' Value to send here
+
+Const SHIFT_MASK = 1
+Const CTRL_MASK = 2
+Const ALT_MASK = 4
+Const KEY_MASK = CTRL_MASK + ALT_MASK
+
+Const KEY_ESC = 27
+
+
+Sub AliasSubst ()
+
+    ' Do relevant alias substitutions on buffer text
+    x = Len(buffer.Text)
+    y$ = Left$(buffer.Text, 1)
+    If ((y$ = "!") Or (y$ = "@")) Then
+        z = 2
+    Else
+        y$ = ""
+        z = 1
+    End If
+
+    While ((z <= x) And (Mid$(buffer.Text, z, 1) <> " "))
+        z = z + 1
+    Wend
+    
+    If (y$ = "") Then
+        q$ = Left$(buffer.Text, z - 1)
+    Else
+        q$ = Mid$(buffer.Text, 2, z - 2)
+    End If
+
+    m$ = Mid$(buffer.Text, z)
+    r = 0
+    x = 1
+    While ((x <= aindex) And (r = 0))
+        If (q$ = Aliases(x, 1)) Then
+            q$ = Aliases(x, 2)
+            r = 1
+        End If
+        x = x + 1
+    Wend
+    buffer.Text = y$ + q$ + m$
+
+End Sub
+
+Sub Buffer_DblClick ()
+    If ((HistRoll <> 0) Or (HistIndex <> 1)) Then
+        CmdHist.Clear
+        index = HistIndex - 1   'Start with last cmd
+        While (index <> 0)
+            CmdHist.AddItem HistBuff(index)
+            index = index - 1
+        Wend
+        If (HistRoll = 1) Then
+            index = MaxHist
+            While (index > HistIndex)
+                CmdHist.AddItem HistBuff(index)
+                index = index - 1
+            Wend
+        End If
+        CmdHist.Visible = 1
+    End If
+End Sub
+
+Sub Buffer_KeyPress (Key As Integer)
+    
+    Select Case Key
+    Case 1                  ' Ctrl-A
+        SendKeys "{Home}"
+        Key = 0             ' Stop the beep madness
+
+    Case 2                  ' Ctrl-B
+        SendKeys "{Left}"
+        Key = 0
+
+    Case 4                  ' Ctrl-D
+        SendKeys "{Del}"
+        Key = 0
+
+    Case 5                  ' Ctrl-E
+        SendKeys "{End}"
+        Key = 0
+
+    Case 6                  ' Ctrl-F
+        SendKeys "{Right}"
+        Key = 0
+    
+    Case 11                 ' Ctrl-K
+        buffer.Text = Left$(buffer.Text, buffer.SelStart)
+        SendKeys "{End}"
+        Key = 0
+    
+    Case 13                 ' Ctrl-M
+        If (buffer.Text <> "") Then
+            RunCommand
+        End If
+        Key = 0
+
+    Case 14                 ' Ctrl-N
+        If PBIndex < MaxHistUsed Then
+            PBIndex = PBIndex + 1
+        Else
+            PBIndex = 1
+        End If
+        buffer.Text = HistBuff(PBIndex)
+        SendKeys "{End}"
+        Key = 0
+
+    Case 16                 ' Ctrl-P
+        If PBIndex > 1 Then
+            PBIndex = PBIndex - 1
+        Else
+            PBIndex = MaxHistUsed
+        End If
+        buffer.Text = HistBuff(PBIndex)
+        SendKeys "{End}"
+        Key = 0
+        
+    Case KEY_ESC           ' Abort On Escape
+        buffer.Text = ""
+        Key = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Sub CmdHist_DblClick ()
+
+    ' Only get the command - allow normal editing
+    buffer.Text = CmdHist.Text
+    CmdHist.Visible = 0
+    SendKeys "{END}"    ' Position cursor at the end
+
+End Sub
+
+Sub CmdHist_KeyPress (Key As Integer)
+    
+    Select Case Key
+
+    Case KEY_ESC           ' Abort On Escape
+        Key = 0
+        CmdHist.Visible = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Function FindFile (Pgm As String) As String
+    Retval$ = ""
+    index = 1
+
+    On Error GoTo error_handler
+    While ((Retval$ = "") And (x <= Pindex))
+        trial$ = Paths$(x) + Pgm
+        Open trial$ For Input As 1
+        Close 1
+        Retval$ = trial$
+try_next:
+        x = x + 1
+    Wend
+    
+    FindFile = Retval$
+    Exit Function
+
+error_handler:
+    Close 1
+    Resume try_next
+End Function
+
+Function FindPgm (Pgm As String) As String
+    
+    ' First split into program name and arguments
+    index = 1
+    split = 0
+    Prog$ = Pgm
+    While ((split = 0) And (index <= Len(Pgm)))
+        If (Mid$(Pgm, index, 1) = " ") Then
+            split = index
+            Prog$ = Mid$(Pgm$, 1, split - 1)
+            Args$ = Mid$(Pgm$, split)
+        End If
+        index = index + 1
+    Wend
+    
+    index = 1
+    Retval$ = ""
+    While ((Retval$ = "") And (index <= 5))
+        Retval$ = FindFile(Prog$ + Extensions(index))
+        index = index + 1
+    Wend
+    
+    If (Retval$ = "") Then
+        FindPgm = Pgm$
+    Else
+        FindPgm = Retval$ + Args$
+    End If
+
+End Function
+
+Sub Form_KeyDown (Key As Integer, Shift As Integer)
+    Select Case Key
+    Case ToggleKey
+        If FastFinger.Visible = 0 Then
+             FastFinger.Visible = 1
+        Else
+             FastFinger.Visible = 0
+        End If
+    End Select
+End Sub
+
+Sub Form_Load ()
+    InitExt
+    InitBuf
+    InitPaths
+    InitAliases
+    HistIndex = 1
+    HistRoll = 0
+    MaxHistUsed = 0
+    hHotKey = CreateHK&(HOTKEY, KEY_MASK, HWnd, ToggleKey)
+    FastFinger.Visible = 0
+    CmdHist.Visible = 0
+End Sub
+
+Sub Form_Unload (Cancel As Integer)
+    KillHK hHotKey
+End Sub
+
+Sub InitAliases ()
+
+    aindex = 0      ' Means no aliases have been found
+    IniFile$ = App.Path + "\" + App.EXEName + ".INI"
+
+    On Error GoTo INI_file_done
+    Open IniFile$ For Input As 1
+    Input #1, x$
+    While (Not EOF(1))
+        If (InStr(1, x$, "[aliases]", 1)) Then
+            Input #1, x$
+            While (Not EOF(1) And (Not InStr(x$, "[")) And (aindex < MaxAlias))
+                aindex = aindex + 1
+                Aliases(aindex, 1) = x$
+                Input #1, x$
+            Wend
+            GoTo INI_file_done
+        End If
+        Input #1, x$
+    Wend
+
+INI_file_done:
+    Close 1
+
+    If (aindex > 0) Then
+        y = 1
+        While (y <= aindex)
+        eindex = InStr(Aliases(y, 1), "=")
+        If (eindex > 0) Then
+            Aliases(y, 2) = Scrub(Mid$(Aliases(y, 1), eindex + 1))
+            Aliases(y, 1) = Scrub(Left$(Aliases(y, 1), eindex - 1))
+        End If
+        y = y + 1
+        Wend
+    End If
+End Sub
+
+Sub InitBuf ()
+    buffer.Text = "" ' Clear out text
+End Sub
+
+Sub InitExt ()
+
+    Extensions(1) = ""
+    Extensions(2) = ".COM"
+    Extensions(3) = ".EXE"
+    Extensions(4) = ".BAT"
+    Extensions(5) = ".PIF"
+
+End Sub
+
+Sub InitPaths ()
+
+    Path$ = Environ("PATH")
+    
+    ' First, get each path component into separate array location
+    Pindex = 0
+    start = 1
+    
+    While (start <= Len(Path$))
+        Pindex = Pindex + 1
+        last = start
+        char$ = Mid$(Path$, last, 1)
+        While ((char$ <> ";") And (last <= Len(Path$)))
+            last = last + 1
+            char$ = Mid$(Path$, last, 1)
+        Wend
+        Paths(Pindex) = Mid$(Path$, start, last - start)
+        start = last + 1
+    Wend
+
+    ' Now, make sure each ends with directory separator
+    For x = 1 To Pindex Step 1
+        If (Mid$(Paths$(x), Len(Paths$(x)), 1) <> "\") Then
+            Paths$(x) = Paths$(x) + "\"
+        End If
+    Next
+End Sub
+
+Sub RunCommand ()
+    
+    ' Store command in (circular) history buffer
+    HistBuff(HistIndex) = buffer.Text
+    HistIndex = HistIndex + 1
+    If (HistIndex > MaxHist) Then
+        HistRoll = 1
+        HistIndex = 1
+    End If
+    MaxHistUsed = MaxHistUsed + 1
+    If (MaxHistUsed > MaxHist) Then
+        MaxHistUsed = MaxHist
+    End If
+    PBIndex = HistIndex
+
+    AliasSubst
+
+    ' If we see <, >, or |, force command interpreter use
+    index = 1
+    bang = 0
+    While (index <= Len(buffer.Text) And (bang = 0))
+          Select Case Mid$(buffer.Text, index, 1)
+            Case "<"
+                bang = 1
+            Case ">"
+                bang = 1
+            Case "|"
+                bang = 1
+          End Select
+          index = index + 1
+    Wend
+    If ((bang = 1) And (Left$(buffer.Text, 1) <> "!")) Then
+        buffer.Text = "!" + buffer.Text
+    End If
+
+    ' Should we do post-processing?
+    dopost = 0
+    If (Left$(buffer.Text, 1) = "@") Then
+        buffer.Text = "!" + Mid$(buffer.Text, 2)
+        dopost = 1
+    End If
+    
+    ' Are we pre-processing?
+    If (Left$(buffer.Text, 1) = "!") Then
+        Prefix$ = Environ$("FF_SHPRE")
+        If (Prefix$ = "") Then
+            Prefix$ = "command.com /c"
+        End If
+        Pgm$ = Mid$(buffer.Text, 2)
+    Else
+        Prefix$ = ""
+        Pgm$ = buffer.Text
+        Pgm$ = FindPgm(Pgm$)
+    End If
+    
+    ' Setup any relevant pre- and post-processing
+    If (Prefix$ <> "") Then
+        Pgm$ = Prefix$ + " " + Pgm$
+    End If
+            
+    Postfix$ = Environ$("FF_SHPOST")
+    If ((Postfix$ <> "") And (dopost = 1)) Then
+        Pgm$ = Pgm$ + " | " + Postfix$
+    End If
+    
+    ' Execute the command
+    On Error Resume Next
+    If (Pgm$ <> "") Then
+        TaskID = Shell(Pgm$, 1)
+    End If
+    InitBuf
+
+End Sub
+
+Function Scrub (xxx As String) As String
+
+    ' Scrub leading and trailing spaces from the string
+
+    z = Len(xxx)
+    j = 0
+    k = 0
+    l = 0
+
+    While ((j < z) And (k = 0)) ' Find start of string
+        j = j + 1
+        tmp$ = Mid$(xxx, j, 1)
+        If (tmp$ <> " ") Then k = j
+    Wend
+
+    j = z
+    While ((j > 0) And (l = 0)) ' Find end of string
+        tmp$ = Mid$(xxx, j, 1)
+        If (tmp$ <> " ") Then l = j
+        j = j - 1
+    Wend
+
+    Scrub = Mid$(xxx, k, l - k + 1)
+
+End Function
+
diff --git a/fastfngr/FASTFNGR.WRI b/fastfngr/FASTFNGR.WRI
new file mode 100644
index 0000000..2c3dc53
--- /dev/null
+++ b/fastfngr/FASTFNGR.WRI
Binary files differ
diff --git a/fastfngr/FF10D/FASTFNGR.BAS b/fastfngr/FF10D/FASTFNGR.BAS
new file mode 100644
index 0000000..33a6f16
--- /dev/null
+++ b/fastfngr/FF10D/FASTFNGR.BAS
@@ -0,0 +1,6 @@
+'HOTKEY.DLL functions
+DefInt A-Z
+
+Declare Function CreateHK& Lib "HOTKEY.DLL" (ByVal KeyCode, ByVal Shift, ByVal hWnd, ByVal UserVK)
+Declare Sub KillHK Lib "HOTKEY.DLL" (ByVal hHotKey&)
+
diff --git a/fastfngr/FF10D/FASTFNGR.EXE b/fastfngr/FF10D/FASTFNGR.EXE
new file mode 100644
index 0000000..089c81c
--- /dev/null
+++ b/fastfngr/FF10D/FASTFNGR.EXE
Binary files differ
diff --git a/fastfngr/FF10D/FASTFNGR.FRM b/fastfngr/FF10D/FASTFNGR.FRM
new file mode 100644
index 0000000..141a21f
--- /dev/null
+++ b/fastfngr/FF10D/FASTFNGR.FRM
Binary files differ
diff --git a/fastfngr/FF10D/FASTFNGR.MAK b/fastfngr/FF10D/FASTFNGR.MAK
new file mode 100644
index 0000000..d373264
--- /dev/null
+++ b/fastfngr/FF10D/FASTFNGR.MAK
@@ -0,0 +1,10 @@
+FASTFNGR.FRM
+C:\WINDOWS\SYSTEM\CMDIALOG.VBX
+C:\WINDOWS\SYSTEM\GRID.VBX
+C:\WINDOWS\SYSTEM\MSOLE2.VBX
+FASTFNGR.BAS
+ProjWinSize=68,405,225,148
+ProjWinShow=2
+IconForm="FastFinger"
+Title="FASTFNGR"
+ExeName="FASTFNGR.EXE"
diff --git a/fastfngr/FF10D/FASTFNGR.TXT b/fastfngr/FF10D/FASTFNGR.TXT
new file mode 100644
index 0000000..1b3edd8
--- /dev/null
+++ b/fastfngr/FF10D/FASTFNGR.TXT
@@ -0,0 +1,262 @@
+Dim Paths(50) As String
+Dim Extensions(5) As String
+Dim Pindex As Integer
+
+Dim HistIndex
+Dim HistBuff(20) As String
+Dim HistRoll
+
+Const HOTKEY = 32       ' Space Bar
+Const ToggleKey = 200   ' Value to send here
+
+Const SHIFT_MASK = 1
+Const CTRL_MASK = 2
+Const ALT_MASK = 4
+Const KEY_MASK = CTRL_MASK + ALT_MASK
+
+Const KEY_ESC = 27
+
+Sub Buffer_DblClick ()
+    If ((HistRoll <> 0) Or (HistIndex <> 1)) Then
+        CmdHist.Clear
+        index = HistIndex - 1   'Start with last cmd
+        While (index <> 0)
+            CmdHist.AddItem HistBuff(index)
+            index = index - 1
+        Wend
+        If (HistRoll = 1) Then
+            index = 20
+            While (index > HistIndex)
+                CmdHist.AddItem HistBuff(index)
+                index = index - 1
+            Wend
+        End If
+        CmdHist.Visible = 1
+    End If
+End Sub
+
+Sub Buffer_KeyPress (Key As Integer)
+    
+    Select Case Key
+    Case 13               ' Handle Carriage Returns
+        If (Buffer.Text <> "") Then
+            RunCommand
+        End If
+        Key = 0            ' Stop the beep madness
+
+    Case KEY_ESC           ' Abort On Escape
+        Buffer.Text = ""
+        Key = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Sub CmdHist_DblClick ()
+
+    ' Only get the command - allow normal editing
+    Buffer.Text = CmdHist.Text
+    CmdHist.Visible = 0
+    SendKeys "{END}"    ' Position cursor at the end
+
+End Sub
+
+Sub CmdHist_KeyPress (Key As Integer)
+    
+    Select Case Key
+
+    Case KEY_ESC           ' Abort On Escape
+        Key = 0
+        CmdHist.Visible = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Function FindFile (Pgm As String) As String
+    Retval$ = ""
+    index = 1
+
+    On Error GoTo error_handler
+    While ((Retval$ = "") And (x <= Pindex))
+        trial$ = Paths$(x) + Pgm
+        Open trial$ For Input As 1
+        Close 1
+        Retval$ = trial$
+try_next:
+        x = x + 1
+    Wend
+    
+    FindFile = Retval$
+    Exit Function
+
+error_handler:
+    Close 1
+    Resume try_next
+End Function
+
+Function FindPgm (Pgm As String) As String
+    
+    ' First split into program name and arguments
+    index = 1
+    split = 0
+    Prog$ = Pgm
+    While ((split = 0) And (index <= Len(Pgm)))
+        If (Mid$(Pgm, index, 1) = " ") Then
+            split = index
+            Prog$ = Mid$(Pgm$, 1, split - 1)
+            Args$ = Mid$(Pgm$, split)
+        End If
+        index = index + 1
+    Wend
+    
+    index = 1
+    Retval$ = ""
+    While ((Retval$ = "") And (index <= 5))
+        Retval$ = FindFile(Prog$ + Extensions(index))
+        index = index + 1
+    Wend
+    
+    If (Retval$ = "") Then
+        FindPgm = Pgm$
+    Else
+        FindPgm = Retval$ + Args$
+    End If
+
+End Function
+
+Sub Form_KeyDown (Key As Integer, Shift As Integer)
+    Select Case Key
+    Case ToggleKey
+        If FastFinger.Visible = 0 Then
+             FastFinger.Visible = 1
+        Else
+             FastFinger.Visible = 0
+        End If
+    End Select
+End Sub
+
+Sub Form_Load ()
+    Extensions(1) = ""
+    Extensions(2) = ".COM"
+    Extensions(3) = ".EXE"
+    Extensions(4) = ".BAT"
+    Extensions(5) = ".PIF"
+    InitBuf
+    InitPaths
+    HistIndex = 1
+    HistRoll = 0
+    hHotKey = CreateHK&(HOTKEY, KEY_MASK, HWnd, ToggleKey)
+    FastFinger.Visible = 0
+    CmdHist.Visible = 0
+End Sub
+
+Sub Form_Unload (Cancel As Integer)
+    KillHK hHotKey
+End Sub
+
+Sub InitBuf ()
+    Buffer.Text = "" ' Clear out text
+End Sub
+
+Sub InitPaths ()
+
+    Path$ = Environ("PATH")
+    
+    ' First, get each path component into separate array location
+    Pindex = 0
+    start = 1
+    
+    While (start <= Len(Path$))
+        Pindex = Pindex + 1
+        last = start
+        char$ = Mid$(Path$, last, 1)
+        While ((char$ <> ";") And (last <= Len(Path$)))
+            last = last + 1
+            char$ = Mid$(Path$, last, 1)
+        Wend
+        Paths(Pindex) = Mid$(Path$, start, last - start)
+        start = last + 1
+    Wend
+
+    ' Now, make sure each ends with directory separator
+    For x = 1 To Pindex Step 1
+        If (Mid$(Paths$(x), Len(Paths$(x)), 1) <> "\") Then
+            Paths$(x) = Paths$(x) + "\"
+        End If
+    Next
+End Sub
+
+Sub RunCommand ()
+    
+    ' Store command in (circular) history buffer
+    HistBuff(HistIndex) = Buffer.Text
+    HistIndex = HistIndex + 1
+    If (HistIndex > 20) Then
+        HistRoll = 1
+        HistIndex = 1
+    End If
+    
+    ' If we see <, >, or |, force command interpreter use
+    index = 1
+    bang = 0
+    While (index <= Len(Buffer.Text) And (bang = 0))
+          Select Case Mid$(Buffer.Text, index, 1)
+            Case "<"
+                bang = 1
+            Case ">"
+                bang = 1
+            Case "|"
+                bang = 1
+          End Select
+          index = index + 1
+    Wend
+    If ((bang = 1) And (Left$(Buffer.Text, 1) <> "!")) Then
+        Buffer.Text = "!" + Buffer.Text
+    End If
+
+    ' Should we do post-processing?
+    dopost = 0
+    If (Left$(Buffer.Text, 1) = "@") Then
+        Buffer.Text = "!" + Mid$(Buffer.Text, 2)
+        dopost = 1
+    End If
+    
+    ' Are we pre-processing?
+    If (Left$(Buffer.Text, 1) = "!") Then
+        Prefix$ = Environ$("FF_SHPRE")
+        If (Prefix$ = "") Then
+            Prefix$ = "command.com /c"
+        End If
+        Pgm$ = Mid$(Buffer.Text, 2)
+    Else
+        Prefix$ = ""
+        Pgm$ = Buffer.Text
+        Pgm$ = FindPgm(Pgm$)
+    End If
+    
+    ' Setup any relevant pre- and post-processing
+    If (Prefix$ <> "") Then
+        Pgm$ = Prefix$ + " " + Pgm$
+    End If
+            
+    Postfix$ = Environ$("FF_SHPOST")
+    If ((Postfix$ <> "") And (dopost = 1)) Then
+        Pgm$ = Pgm$ + " | " + Postfix$
+    End If
+    
+    ' Execute the command
+    On Error Resume Next
+    If (Pgm$ <> "") Then
+        TaskID = Shell(Pgm$, 3)
+    End If
+    InitBuf
+
+End Sub
+
diff --git a/fastfngr/FF10E/FASTFNGR.BAS b/fastfngr/FF10E/FASTFNGR.BAS
new file mode 100644
index 0000000..33a6f16
--- /dev/null
+++ b/fastfngr/FF10E/FASTFNGR.BAS
@@ -0,0 +1,6 @@
+'HOTKEY.DLL functions
+DefInt A-Z
+
+Declare Function CreateHK& Lib "HOTKEY.DLL" (ByVal KeyCode, ByVal Shift, ByVal hWnd, ByVal UserVK)
+Declare Sub KillHK Lib "HOTKEY.DLL" (ByVal hHotKey&)
+
diff --git a/fastfngr/FF10E/FASTFNGR.EXE b/fastfngr/FF10E/FASTFNGR.EXE
new file mode 100644
index 0000000..089c81c
--- /dev/null
+++ b/fastfngr/FF10E/FASTFNGR.EXE
Binary files differ
diff --git a/fastfngr/FF10E/FASTFNGR.FRM b/fastfngr/FF10E/FASTFNGR.FRM
new file mode 100644
index 0000000..fab91e2
--- /dev/null
+++ b/fastfngr/FF10E/FASTFNGR.FRM
Binary files differ
diff --git a/fastfngr/FF10E/FASTFNGR.INI b/fastfngr/FF10E/FASTFNGR.INI
new file mode 100644
index 0000000..7e68a6f
--- /dev/null
+++ b/fastfngr/FF10E/FASTFNGR.INI
@@ -0,0 +1,3 @@
+[Aliases]
+clown=bozo
+
diff --git a/fastfngr/FF10E/FASTFNGR.MAK b/fastfngr/FF10E/FASTFNGR.MAK
new file mode 100644
index 0000000..d373264
--- /dev/null
+++ b/fastfngr/FF10E/FASTFNGR.MAK
@@ -0,0 +1,10 @@
+FASTFNGR.FRM
+C:\WINDOWS\SYSTEM\CMDIALOG.VBX
+C:\WINDOWS\SYSTEM\GRID.VBX
+C:\WINDOWS\SYSTEM\MSOLE2.VBX
+FASTFNGR.BAS
+ProjWinSize=68,405,225,148
+ProjWinShow=2
+IconForm="FastFinger"
+Title="FASTFNGR"
+ExeName="FASTFNGR.EXE"
diff --git a/fastfngr/FF10E/FASTFNGR.TXT b/fastfngr/FF10E/FASTFNGR.TXT
new file mode 100644
index 0000000..fb8776a
--- /dev/null
+++ b/fastfngr/FF10E/FASTFNGR.TXT
@@ -0,0 +1,274 @@
+Dim Paths(50) As String
+Dim Extensions(5) As String
+Dim Pindex As Integer
+
+Const MaxAlias = 100
+Dim Aliases(MaxAlias, 2) As String
+Dim Aindex As Integer
+
+Const MaxHist = 20
+Dim HistIndex
+Dim HistBuff(MaxHist) As String
+Dim HistRoll
+
+Const HOTKEY = 32       ' Space Bar
+Const ToggleKey = 200   ' Value to send here
+
+Const SHIFT_MASK = 1
+Const CTRL_MASK = 2
+Const ALT_MASK = 4
+Const KEY_MASK = CTRL_MASK + ALT_MASK
+
+Const KEY_ESC = 27
+
+Sub Buffer_DblClick ()
+    If ((HistRoll <> 0) Or (HistIndex <> 1)) Then
+        CmdHist.Clear
+        index = HistIndex - 1   'Start with last cmd
+        While (index <> 0)
+            CmdHist.AddItem HistBuff(index)
+            index = index - 1
+        Wend
+        If (HistRoll = 1) Then
+            index = 20
+            While (index > HistIndex)
+                CmdHist.AddItem HistBuff(index)
+                index = index - 1
+            Wend
+        End If
+        CmdHist.Visible = 1
+    End If
+End Sub
+
+Sub Buffer_KeyPress (Key As Integer)
+    
+    Select Case Key
+    Case 13               ' Handle Carriage Returns
+        If (Buffer.Text <> "") Then
+            RunCommand
+        End If
+        Key = 0            ' Stop the beep madness
+
+    Case KEY_ESC           ' Abort On Escape
+        Buffer.Text = ""
+        Key = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Sub CmdHist_DblClick ()
+
+    ' Only get the command - allow normal editing
+    Buffer.Text = CmdHist.Text
+    CmdHist.Visible = 0
+    SendKeys "{END}"    ' Position cursor at the end
+
+End Sub
+
+Sub CmdHist_KeyPress (Key As Integer)
+    
+    Select Case Key
+
+    Case KEY_ESC           ' Abort On Escape
+        Key = 0
+        CmdHist.Visible = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Function FindFile (Pgm As String) As String
+    Retval$ = ""
+    index = 1
+
+    On Error GoTo error_handler
+    While ((Retval$ = "") And (x <= Pindex))
+        trial$ = Paths$(x) + Pgm
+        Open trial$ For Input As 1
+        Close 1
+        Retval$ = trial$
+try_next:
+        x = x + 1
+    Wend
+    
+    FindFile = Retval$
+    Exit Function
+
+error_handler:
+    Close 1
+    Resume try_next
+End Function
+
+Function FindPgm (Pgm As String) As String
+    
+    ' First split into program name and arguments
+    index = 1
+    split = 0
+    Prog$ = Pgm
+    While ((split = 0) And (index <= Len(Pgm)))
+        If (Mid$(Pgm, index, 1) = " ") Then
+            split = index
+            Prog$ = Mid$(Pgm$, 1, split - 1)
+            Args$ = Mid$(Pgm$, split)
+        End If
+        index = index + 1
+    Wend
+    
+    index = 1
+    Retval$ = ""
+    While ((Retval$ = "") And (index <= 5))
+        Retval$ = FindFile(Prog$ + Extensions(index))
+        index = index + 1
+    Wend
+    
+    If (Retval$ = "") Then
+        FindPgm = Pgm$
+    Else
+        FindPgm = Retval$ + Args$
+    End If
+
+End Function
+
+Sub Form_KeyDown (Key As Integer, Shift As Integer)
+    Select Case Key
+    Case ToggleKey
+        If FastFinger.Visible = 0 Then
+             FastFinger.Visible = 1
+        Else
+             FastFinger.Visible = 0
+        End If
+    End Select
+End Sub
+
+Sub Form_Load ()
+    Extensions(1) = ""
+    Extensions(2) = ".COM"
+    Extensions(3) = ".EXE"
+    Extensions(4) = ".BAT"
+    Extensions(5) = ".PIF"
+    InitBuf
+    InitPaths
+    InitAliases
+    HistIndex = 1
+    HistRoll = 0
+    hHotKey = CreateHK&(HOTKEY, KEY_MASK, HWnd, ToggleKey)
+    FastFinger.Visible = 0
+    CmdHist.Visible = 0
+End Sub
+
+Sub Form_Unload (Cancel As Integer)
+    KillHK hHotKey
+End Sub
+
+Sub InitAliases ()
+
+    Aindex = 0      ' Means no aliases have been found
+
+End Sub
+
+Sub InitBuf ()
+    Buffer.Text = "" ' Clear out text
+End Sub
+
+Sub InitPaths ()
+
+    Path$ = Environ("PATH")
+    
+    ' First, get each path component into separate array location
+    Pindex = 0
+    start = 1
+    
+    While (start <= Len(Path$))
+        Pindex = Pindex + 1
+        last = start
+        char$ = Mid$(Path$, last, 1)
+        While ((char$ <> ";") And (last <= Len(Path$)))
+            last = last + 1
+            char$ = Mid$(Path$, last, 1)
+        Wend
+        Paths(Pindex) = Mid$(Path$, start, last - start)
+        start = last + 1
+    Wend
+
+    ' Now, make sure each ends with directory separator
+    For x = 1 To Pindex Step 1
+        If (Mid$(Paths$(x), Len(Paths$(x)), 1) <> "\") Then
+            Paths$(x) = Paths$(x) + "\"
+        End If
+    Next
+End Sub
+
+Sub RunCommand ()
+    
+    ' Store command in (circular) history buffer
+    HistBuff(HistIndex) = Buffer.Text
+    HistIndex = HistIndex + 1
+    If (HistIndex > MaxHist) Then
+        HistRoll = 1
+        HistIndex = 1
+    End If
+    
+    ' If we see <, >, or |, force command interpreter use
+    index = 1
+    bang = 0
+    While (index <= Len(Buffer.Text) And (bang = 0))
+          Select Case Mid$(Buffer.Text, index, 1)
+            Case "<"
+                bang = 1
+            Case ">"
+                bang = 1
+            Case "|"
+                bang = 1
+          End Select
+          index = index + 1
+    Wend
+    If ((bang = 1) And (Left$(Buffer.Text, 1) <> "!")) Then
+        Buffer.Text = "!" + Buffer.Text
+    End If
+
+    ' Should we do post-processing?
+    dopost = 0
+    If (Left$(Buffer.Text, 1) = "@") Then
+        Buffer.Text = "!" + Mid$(Buffer.Text, 2)
+        dopost = 1
+    End If
+    
+    ' Are we pre-processing?
+    If (Left$(Buffer.Text, 1) = "!") Then
+        Prefix$ = Environ$("FF_SHPRE")
+        If (Prefix$ = "") Then
+            Prefix$ = "command.com /c"
+        End If
+        Pgm$ = Mid$(Buffer.Text, 2)
+    Else
+        Prefix$ = ""
+        Pgm$ = Buffer.Text
+        Pgm$ = FindPgm(Pgm$)
+    End If
+    
+    ' Setup any relevant pre- and post-processing
+    If (Prefix$ <> "") Then
+        Pgm$ = Prefix$ + " " + Pgm$
+    End If
+            
+    Postfix$ = Environ$("FF_SHPOST")
+    If ((Postfix$ <> "") And (dopost = 1)) Then
+        Pgm$ = Pgm$ + " | " + Postfix$
+    End If
+    
+    ' Execute the command
+    On Error Resume Next
+    If (Pgm$ <> "") Then
+        TaskID = Shell(Pgm$, 1)
+    End If
+    InitBuf
+
+End Sub
+
diff --git a/fastfngr/FF10F/FASTFNGR.BAS b/fastfngr/FF10F/FASTFNGR.BAS
new file mode 100644
index 0000000..33a6f16
--- /dev/null
+++ b/fastfngr/FF10F/FASTFNGR.BAS
@@ -0,0 +1,6 @@
+'HOTKEY.DLL functions
+DefInt A-Z
+
+Declare Function CreateHK& Lib "HOTKEY.DLL" (ByVal KeyCode, ByVal Shift, ByVal hWnd, ByVal UserVK)
+Declare Sub KillHK Lib "HOTKEY.DLL" (ByVal hHotKey&)
+
diff --git a/fastfngr/FF10F/FASTFNGR.EXE b/fastfngr/FF10F/FASTFNGR.EXE
new file mode 100644
index 0000000..089c81c
--- /dev/null
+++ b/fastfngr/FF10F/FASTFNGR.EXE
Binary files differ
diff --git a/fastfngr/FF10F/FASTFNGR.FRM b/fastfngr/FF10F/FASTFNGR.FRM
new file mode 100644
index 0000000..1383c08
--- /dev/null
+++ b/fastfngr/FF10F/FASTFNGR.FRM
Binary files differ
diff --git a/fastfngr/FF10F/FASTFNGR.INI b/fastfngr/FF10F/FASTFNGR.INI
new file mode 100644
index 0000000..7e68a6f
--- /dev/null
+++ b/fastfngr/FF10F/FASTFNGR.INI
@@ -0,0 +1,3 @@
+[Aliases]
+clown=bozo
+
diff --git a/fastfngr/FF10F/FASTFNGR.MAK b/fastfngr/FF10F/FASTFNGR.MAK
new file mode 100644
index 0000000..d373264
--- /dev/null
+++ b/fastfngr/FF10F/FASTFNGR.MAK
@@ -0,0 +1,10 @@
+FASTFNGR.FRM
+C:\WINDOWS\SYSTEM\CMDIALOG.VBX
+C:\WINDOWS\SYSTEM\GRID.VBX
+C:\WINDOWS\SYSTEM\MSOLE2.VBX
+FASTFNGR.BAS
+ProjWinSize=68,405,225,148
+ProjWinShow=2
+IconForm="FastFinger"
+Title="FASTFNGR"
+ExeName="FASTFNGR.EXE"
diff --git a/fastfngr/FF10F/FASTFNGR.TXT b/fastfngr/FF10F/FASTFNGR.TXT
new file mode 100644
index 0000000..fb8776a
--- /dev/null
+++ b/fastfngr/FF10F/FASTFNGR.TXT
@@ -0,0 +1,274 @@
+Dim Paths(50) As String
+Dim Extensions(5) As String
+Dim Pindex As Integer
+
+Const MaxAlias = 100
+Dim Aliases(MaxAlias, 2) As String
+Dim Aindex As Integer
+
+Const MaxHist = 20
+Dim HistIndex
+Dim HistBuff(MaxHist) As String
+Dim HistRoll
+
+Const HOTKEY = 32       ' Space Bar
+Const ToggleKey = 200   ' Value to send here
+
+Const SHIFT_MASK = 1
+Const CTRL_MASK = 2
+Const ALT_MASK = 4
+Const KEY_MASK = CTRL_MASK + ALT_MASK
+
+Const KEY_ESC = 27
+
+Sub Buffer_DblClick ()
+    If ((HistRoll <> 0) Or (HistIndex <> 1)) Then
+        CmdHist.Clear
+        index = HistIndex - 1   'Start with last cmd
+        While (index <> 0)
+            CmdHist.AddItem HistBuff(index)
+            index = index - 1
+        Wend
+        If (HistRoll = 1) Then
+            index = 20
+            While (index > HistIndex)
+                CmdHist.AddItem HistBuff(index)
+                index = index - 1
+            Wend
+        End If
+        CmdHist.Visible = 1
+    End If
+End Sub
+
+Sub Buffer_KeyPress (Key As Integer)
+    
+    Select Case Key
+    Case 13               ' Handle Carriage Returns
+        If (Buffer.Text <> "") Then
+            RunCommand
+        End If
+        Key = 0            ' Stop the beep madness
+
+    Case KEY_ESC           ' Abort On Escape
+        Buffer.Text = ""
+        Key = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Sub CmdHist_DblClick ()
+
+    ' Only get the command - allow normal editing
+    Buffer.Text = CmdHist.Text
+    CmdHist.Visible = 0
+    SendKeys "{END}"    ' Position cursor at the end
+
+End Sub
+
+Sub CmdHist_KeyPress (Key As Integer)
+    
+    Select Case Key
+
+    Case KEY_ESC           ' Abort On Escape
+        Key = 0
+        CmdHist.Visible = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Function FindFile (Pgm As String) As String
+    Retval$ = ""
+    index = 1
+
+    On Error GoTo error_handler
+    While ((Retval$ = "") And (x <= Pindex))
+        trial$ = Paths$(x) + Pgm
+        Open trial$ For Input As 1
+        Close 1
+        Retval$ = trial$
+try_next:
+        x = x + 1
+    Wend
+    
+    FindFile = Retval$
+    Exit Function
+
+error_handler:
+    Close 1
+    Resume try_next
+End Function
+
+Function FindPgm (Pgm As String) As String
+    
+    ' First split into program name and arguments
+    index = 1
+    split = 0
+    Prog$ = Pgm
+    While ((split = 0) And (index <= Len(Pgm)))
+        If (Mid$(Pgm, index, 1) = " ") Then
+            split = index
+            Prog$ = Mid$(Pgm$, 1, split - 1)
+            Args$ = Mid$(Pgm$, split)
+        End If
+        index = index + 1
+    Wend
+    
+    index = 1
+    Retval$ = ""
+    While ((Retval$ = "") And (index <= 5))
+        Retval$ = FindFile(Prog$ + Extensions(index))
+        index = index + 1
+    Wend
+    
+    If (Retval$ = "") Then
+        FindPgm = Pgm$
+    Else
+        FindPgm = Retval$ + Args$
+    End If
+
+End Function
+
+Sub Form_KeyDown (Key As Integer, Shift As Integer)
+    Select Case Key
+    Case ToggleKey
+        If FastFinger.Visible = 0 Then
+             FastFinger.Visible = 1
+        Else
+             FastFinger.Visible = 0
+        End If
+    End Select
+End Sub
+
+Sub Form_Load ()
+    Extensions(1) = ""
+    Extensions(2) = ".COM"
+    Extensions(3) = ".EXE"
+    Extensions(4) = ".BAT"
+    Extensions(5) = ".PIF"
+    InitBuf
+    InitPaths
+    InitAliases
+    HistIndex = 1
+    HistRoll = 0
+    hHotKey = CreateHK&(HOTKEY, KEY_MASK, HWnd, ToggleKey)
+    FastFinger.Visible = 0
+    CmdHist.Visible = 0
+End Sub
+
+Sub Form_Unload (Cancel As Integer)
+    KillHK hHotKey
+End Sub
+
+Sub InitAliases ()
+
+    Aindex = 0      ' Means no aliases have been found
+
+End Sub
+
+Sub InitBuf ()
+    Buffer.Text = "" ' Clear out text
+End Sub
+
+Sub InitPaths ()
+
+    Path$ = Environ("PATH")
+    
+    ' First, get each path component into separate array location
+    Pindex = 0
+    start = 1
+    
+    While (start <= Len(Path$))
+        Pindex = Pindex + 1
+        last = start
+        char$ = Mid$(Path$, last, 1)
+        While ((char$ <> ";") And (last <= Len(Path$)))
+            last = last + 1
+            char$ = Mid$(Path$, last, 1)
+        Wend
+        Paths(Pindex) = Mid$(Path$, start, last - start)
+        start = last + 1
+    Wend
+
+    ' Now, make sure each ends with directory separator
+    For x = 1 To Pindex Step 1
+        If (Mid$(Paths$(x), Len(Paths$(x)), 1) <> "\") Then
+            Paths$(x) = Paths$(x) + "\"
+        End If
+    Next
+End Sub
+
+Sub RunCommand ()
+    
+    ' Store command in (circular) history buffer
+    HistBuff(HistIndex) = Buffer.Text
+    HistIndex = HistIndex + 1
+    If (HistIndex > MaxHist) Then
+        HistRoll = 1
+        HistIndex = 1
+    End If
+    
+    ' If we see <, >, or |, force command interpreter use
+    index = 1
+    bang = 0
+    While (index <= Len(Buffer.Text) And (bang = 0))
+          Select Case Mid$(Buffer.Text, index, 1)
+            Case "<"
+                bang = 1
+            Case ">"
+                bang = 1
+            Case "|"
+                bang = 1
+          End Select
+          index = index + 1
+    Wend
+    If ((bang = 1) And (Left$(Buffer.Text, 1) <> "!")) Then
+        Buffer.Text = "!" + Buffer.Text
+    End If
+
+    ' Should we do post-processing?
+    dopost = 0
+    If (Left$(Buffer.Text, 1) = "@") Then
+        Buffer.Text = "!" + Mid$(Buffer.Text, 2)
+        dopost = 1
+    End If
+    
+    ' Are we pre-processing?
+    If (Left$(Buffer.Text, 1) = "!") Then
+        Prefix$ = Environ$("FF_SHPRE")
+        If (Prefix$ = "") Then
+            Prefix$ = "command.com /c"
+        End If
+        Pgm$ = Mid$(Buffer.Text, 2)
+    Else
+        Prefix$ = ""
+        Pgm$ = Buffer.Text
+        Pgm$ = FindPgm(Pgm$)
+    End If
+    
+    ' Setup any relevant pre- and post-processing
+    If (Prefix$ <> "") Then
+        Pgm$ = Prefix$ + " " + Pgm$
+    End If
+            
+    Postfix$ = Environ$("FF_SHPOST")
+    If ((Postfix$ <> "") And (dopost = 1)) Then
+        Pgm$ = Pgm$ + " | " + Postfix$
+    End If
+    
+    ' Execute the command
+    On Error Resume Next
+    If (Pgm$ <> "") Then
+        TaskID = Shell(Pgm$, 1)
+    End If
+    InitBuf
+
+End Sub
+
diff --git a/fastfngr/FF20/FASTFNGR.BAS b/fastfngr/FF20/FASTFNGR.BAS
new file mode 100644
index 0000000..33a6f16
--- /dev/null
+++ b/fastfngr/FF20/FASTFNGR.BAS
@@ -0,0 +1,6 @@
+'HOTKEY.DLL functions
+DefInt A-Z
+
+Declare Function CreateHK& Lib "HOTKEY.DLL" (ByVal KeyCode, ByVal Shift, ByVal hWnd, ByVal UserVK)
+Declare Sub KillHK Lib "HOTKEY.DLL" (ByVal hHotKey&)
+
diff --git a/fastfngr/FF20/FASTFNGR.EXE b/fastfngr/FF20/FASTFNGR.EXE
new file mode 100644
index 0000000..b1231f8
--- /dev/null
+++ b/fastfngr/FF20/FASTFNGR.EXE
Binary files differ
diff --git a/fastfngr/FF20/FASTFNGR.FRM b/fastfngr/FF20/FASTFNGR.FRM
new file mode 100644
index 0000000..835a29b
--- /dev/null
+++ b/fastfngr/FF20/FASTFNGR.FRM
Binary files differ
diff --git a/fastfngr/FF20/FASTFNGR.INI b/fastfngr/FF20/FASTFNGR.INI
new file mode 100644
index 0000000..72d7330
--- /dev/null
+++ b/fastfngr/FF20/FASTFNGR.INI
@@ -0,0 +1,6 @@
+[Aliases]
+d = dir
+
+l = ls -alR
+v = list
+
diff --git a/fastfngr/FF20/FASTFNGR.MAK b/fastfngr/FF20/FASTFNGR.MAK
new file mode 100644
index 0000000..d6e81d2
--- /dev/null
+++ b/fastfngr/FF20/FASTFNGR.MAK
@@ -0,0 +1,10 @@
+FASTFNGR.FRM
+C:\WINDOWS\SYSTEM\CMDIALOG.VBX
+C:\WINDOWS\SYSTEM\GRID.VBX
+C:\WINDOWS\SYSTEM\MSOLE2.VBX
+FASTFNGR.BAS
+ProjWinSize=68,404,225,148
+ProjWinShow=2
+IconForm="FastFinger"
+Title="FASTFNGR"
+ExeName="FASTFNGR.EXE"
diff --git a/fastfngr/FF20/FASTFNGR.TXT b/fastfngr/FF20/FASTFNGR.TXT
new file mode 100644
index 0000000..a249ae2
--- /dev/null
+++ b/fastfngr/FF20/FASTFNGR.TXT
@@ -0,0 +1,429 @@
+Dim Paths(50) As String
+Dim Extensions(5) As String
+Dim Pindex As Integer
+
+Const MaxAlias = 100
+Dim Aliases(MaxAlias, 2) As String
+Dim aindex As Integer
+
+Const MaxHist = 20
+Dim HistIndex
+Dim HistBuff(MaxHist) As String
+Dim HistRoll
+Dim PBIndex
+Dim MaxHistUsed
+
+Const HOTKEY = 32       ' Space Bar
+Const ToggleKey = 200   ' Value to send here
+
+Const SHIFT_MASK = 1
+Const CTRL_MASK = 2
+Const ALT_MASK = 4
+Const KEY_MASK = CTRL_MASK + ALT_MASK
+
+Const KEY_ESC = 27
+
+
+Sub AliasSubst ()
+
+    ' Do relevant alias substitutions on buffer text
+    x = Len(buffer.Text)
+    y$ = Left$(buffer.Text, 1)
+    If ((y$ = "!") Or (y$ = "@")) Then
+        z = 2
+    Else
+        y$ = ""
+        z = 1
+    End If
+
+    While ((z <= x) And (Mid$(buffer.Text, z, 1) <> " "))
+        z = z + 1
+    Wend
+    
+    If (y$ = "") Then
+        q$ = Left$(buffer.Text, z - 1)
+    Else
+        q$ = Mid$(buffer.Text, 2, z - 2)
+    End If
+
+    m$ = Mid$(buffer.Text, z)
+    r = 0
+    x = 1
+    While ((x <= aindex) And (r = 0))
+        If (q$ = Aliases(x, 1)) Then
+            q$ = Aliases(x, 2)
+            r = 1
+        End If
+        x = x + 1
+    Wend
+    buffer.Text = y$ + q$ + m$
+
+End Sub
+
+Sub Buffer_DblClick ()
+    If ((HistRoll <> 0) Or (HistIndex <> 1)) Then
+        CmdHist.Clear
+        index = HistIndex - 1   'Start with last cmd
+        While (index <> 0)
+            CmdHist.AddItem HistBuff(index)
+            index = index - 1
+        Wend
+        If (HistRoll = 1) Then
+            index = MaxHist
+            While (index > HistIndex)
+                CmdHist.AddItem HistBuff(index)
+                index = index - 1
+            Wend
+        End If
+        CmdHist.Visible = 1
+    End If
+End Sub
+
+Sub Buffer_KeyPress (Key As Integer)
+    
+    Select Case Key
+    Case 1                  ' Ctrl-A
+        SendKeys "{Home}"
+        Key = 0             ' Stop the beep madness
+
+    Case 2                  ' Ctrl-B
+        SendKeys "{Left}"
+        Key = 0
+
+    Case 4                  ' Ctrl-D
+        SendKeys "{Del}"
+        Key = 0
+
+    Case 5                  ' Ctrl-E
+        SendKeys "{End}"
+        Key = 0
+
+    Case 6                  ' Ctrl-F
+        SendKeys "{Right}"
+        Key = 0
+    
+    Case 11                 ' Ctrl-K
+        buffer.Text = Left$(buffer.Text, buffer.SelStart)
+        SendKeys "{End}"
+        Key = 0
+    
+    Case 13                 ' Ctrl-M
+        If (buffer.Text <> "") Then
+            RunCommand
+        End If
+        Key = 0
+
+    Case 14                 ' Ctrl-N
+        If PBIndex < MaxHistUsed Then
+            PBIndex = PBIndex + 1
+        Else
+            PBIndex = 1
+        End If
+        buffer.Text = HistBuff(PBIndex)
+        SendKeys "{End}"
+        Key = 0
+
+    Case 16                 ' Ctrl-P
+        If PBIndex > 1 Then
+            PBIndex = PBIndex - 1
+        Else
+            PBIndex = MaxHistUsed
+        End If
+        buffer.Text = HistBuff(PBIndex)
+        SendKeys "{End}"
+        Key = 0
+        
+    Case KEY_ESC           ' Abort On Escape
+        buffer.Text = ""
+        Key = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Sub CmdHist_DblClick ()
+
+    ' Only get the command - allow normal editing
+    buffer.Text = CmdHist.Text
+    CmdHist.Visible = 0
+    SendKeys "{END}"    ' Position cursor at the end
+
+End Sub
+
+Sub CmdHist_KeyPress (Key As Integer)
+    
+    Select Case Key
+
+    Case KEY_ESC           ' Abort On Escape
+        Key = 0
+        CmdHist.Visible = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Function FindFile (Pgm As String) As String
+    Retval$ = ""
+    index = 1
+
+    On Error GoTo error_handler
+    While ((Retval$ = "") And (x <= Pindex))
+        trial$ = Paths$(x) + Pgm
+        Open trial$ For Input As 1
+        Close 1
+        Retval$ = trial$
+try_next:
+        x = x + 1
+    Wend
+    
+    FindFile = Retval$
+    Exit Function
+
+error_handler:
+    Close 1
+    Resume try_next
+End Function
+
+Function FindPgm (Pgm As String) As String
+    
+    ' First split into program name and arguments
+    index = 1
+    split = 0
+    Prog$ = Pgm
+    While ((split = 0) And (index <= Len(Pgm)))
+        If (Mid$(Pgm, index, 1) = " ") Then
+            split = index
+            Prog$ = Mid$(Pgm$, 1, split - 1)
+            Args$ = Mid$(Pgm$, split)
+        End If
+        index = index + 1
+    Wend
+    
+    index = 1
+    Retval$ = ""
+    While ((Retval$ = "") And (index <= 5))
+        Retval$ = FindFile(Prog$ + Extensions(index))
+        index = index + 1
+    Wend
+    
+    If (Retval$ = "") Then
+        FindPgm = Pgm$
+    Else
+        FindPgm = Retval$ + Args$
+    End If
+
+End Function
+
+Sub Form_KeyDown (Key As Integer, Shift As Integer)
+    Select Case Key
+    Case ToggleKey
+        If FastFinger.Visible = 0 Then
+             FastFinger.Visible = 1
+        Else
+             FastFinger.Visible = 0
+        End If
+    End Select
+End Sub
+
+Sub Form_Load ()
+    InitExt
+    InitBuf
+    InitPaths
+    InitAliases
+    HistIndex = 1
+    HistRoll = 0
+    MaxHistUsed = 0
+    hHotKey = CreateHK&(HOTKEY, KEY_MASK, HWnd, ToggleKey)
+    FastFinger.Visible = 0
+    CmdHist.Visible = 0
+End Sub
+
+Sub Form_Unload (Cancel As Integer)
+    KillHK hHotKey
+End Sub
+
+Sub InitAliases ()
+
+    aindex = 0      ' Means no aliases have been found
+    IniFile$ = App.Path + "\" + App.EXEName + ".INI"
+
+    On Error GoTo INI_file_done
+    Open IniFile$ For Input As 1
+    Input #1, x$
+    While (Not EOF(1))
+        If (InStr(1, x$, "[aliases]", 1)) Then
+            Input #1, x$
+            While (Not EOF(1) And (Not InStr(x$, "[")) And (aindex < MaxAlias))
+                aindex = aindex + 1
+                Aliases(aindex, 1) = x$
+                Input #1, x$
+            Wend
+            GoTo INI_file_done
+        End If
+        Input #1, x$
+    Wend
+
+INI_file_done:
+    Close 1
+
+    If (aindex > 0) Then
+        y = 1
+        While (y <= aindex)
+        eindex = InStr(Aliases(y, 1), "=")
+        If (eindex > 0) Then
+            Aliases(y, 2) = Scrub(Mid$(Aliases(y, 1), eindex + 1))
+            Aliases(y, 1) = Scrub(Left$(Aliases(y, 1), eindex - 1))
+        End If
+        y = y + 1
+        Wend
+    End If
+End Sub
+
+Sub InitBuf ()
+    buffer.Text = "" ' Clear out text
+End Sub
+
+Sub InitExt ()
+
+    Extensions(1) = ""
+    Extensions(2) = ".COM"
+    Extensions(3) = ".EXE"
+    Extensions(4) = ".BAT"
+    Extensions(5) = ".PIF"
+
+End Sub
+
+Sub InitPaths ()
+
+    Path$ = Environ("PATH")
+    
+    ' First, get each path component into separate array location
+    Pindex = 0
+    start = 1
+    
+    While (start <= Len(Path$))
+        Pindex = Pindex + 1
+        last = start
+        char$ = Mid$(Path$, last, 1)
+        While ((char$ <> ";") And (last <= Len(Path$)))
+            last = last + 1
+            char$ = Mid$(Path$, last, 1)
+        Wend
+        Paths(Pindex) = Mid$(Path$, start, last - start)
+        start = last + 1
+    Wend
+
+    ' Now, make sure each ends with directory separator
+    For x = 1 To Pindex Step 1
+        If (Mid$(Paths$(x), Len(Paths$(x)), 1) <> "\") Then
+            Paths$(x) = Paths$(x) + "\"
+        End If
+    Next
+End Sub
+
+Sub RunCommand ()
+    
+    ' Store command in (circular) history buffer
+    HistBuff(HistIndex) = buffer.Text
+    HistIndex = HistIndex + 1
+    If (HistIndex > MaxHist) Then
+        HistRoll = 1
+        HistIndex = 1
+    End If
+    MaxHistUsed = MaxHistUsed + 1
+    If (MaxHistUsed > MaxHist) Then
+        MaxHistUsed = MaxHist
+    End If
+    PBIndex = HistIndex
+
+    AliasSubst
+
+    ' If we see <, >, or |, force command interpreter use
+    index = 1
+    bang = 0
+    While (index <= Len(buffer.Text) And (bang = 0))
+          Select Case Mid$(buffer.Text, index, 1)
+            Case "<"
+                bang = 1
+            Case ">"
+                bang = 1
+            Case "|"
+                bang = 1
+          End Select
+          index = index + 1
+    Wend
+    If ((bang = 1) And (Left$(buffer.Text, 1) <> "!")) Then
+        buffer.Text = "!" + buffer.Text
+    End If
+
+    ' Should we do post-processing?
+    dopost = 0
+    If (Left$(buffer.Text, 1) = "@") Then
+        buffer.Text = "!" + Mid$(buffer.Text, 2)
+        dopost = 1
+    End If
+    
+    ' Are we pre-processing?
+    If (Left$(buffer.Text, 1) = "!") Then
+        Prefix$ = Environ$("FF_SHPRE")
+        If (Prefix$ = "") Then
+            Prefix$ = "command.com /c"
+        End If
+        Pgm$ = Mid$(buffer.Text, 2)
+    Else
+        Prefix$ = ""
+        Pgm$ = buffer.Text
+        Pgm$ = FindPgm(Pgm$)
+    End If
+    
+    ' Setup any relevant pre- and post-processing
+    If (Prefix$ <> "") Then
+        Pgm$ = Prefix$ + " " + Pgm$
+    End If
+            
+    Postfix$ = Environ$("FF_SHPOST")
+    If ((Postfix$ <> "") And (dopost = 1)) Then
+        Pgm$ = Pgm$ + " | " + Postfix$
+    End If
+    
+    ' Execute the command
+    On Error Resume Next
+    If (Pgm$ <> "") Then
+        TaskID = Shell(Pgm$, 1)
+    End If
+    InitBuf
+
+End Sub
+
+Function Scrub (xxx As String) As String
+
+    ' Scrub leading and trailing spaces from the string
+
+    z = Len(xxx)
+    j = 0
+    k = 0
+    l = 0
+
+    While ((j < z) And (k = 0)) ' Find start of string
+        j = j + 1
+        tmp$ = Mid$(xxx, j, 1)
+        If (tmp$ <> " ") Then k = j
+    Wend
+
+    j = z
+    While ((j > 0) And (l = 0)) ' Find end of string
+        tmp$ = Mid$(xxx, j, 1)
+        If (tmp$ <> " ") Then l = j
+        j = j - 1
+    Wend
+
+    Scrub = Mid$(xxx, k, l - k + 1)
+
+End Function
+
diff --git a/fastfngr/FF20C/FASTFNGR.BAS b/fastfngr/FF20C/FASTFNGR.BAS
new file mode 100644
index 0000000..33a6f16
--- /dev/null
+++ b/fastfngr/FF20C/FASTFNGR.BAS
@@ -0,0 +1,6 @@
+'HOTKEY.DLL functions
+DefInt A-Z
+
+Declare Function CreateHK& Lib "HOTKEY.DLL" (ByVal KeyCode, ByVal Shift, ByVal hWnd, ByVal UserVK)
+Declare Sub KillHK Lib "HOTKEY.DLL" (ByVal hHotKey&)
+
diff --git a/fastfngr/FF20C/FASTFNGR.EXE b/fastfngr/FF20C/FASTFNGR.EXE
new file mode 100644
index 0000000..d61b308
--- /dev/null
+++ b/fastfngr/FF20C/FASTFNGR.EXE
Binary files differ
diff --git a/fastfngr/FF20C/FASTFNGR.FRM b/fastfngr/FF20C/FASTFNGR.FRM
new file mode 100644
index 0000000..7f8eed1
--- /dev/null
+++ b/fastfngr/FF20C/FASTFNGR.FRM
Binary files differ
diff --git a/fastfngr/FF20C/FASTFNGR.INI b/fastfngr/FF20C/FASTFNGR.INI
new file mode 100644
index 0000000..71f12bd
--- /dev/null
+++ b/fastfngr/FF20C/FASTFNGR.INI
@@ -0,0 +1,42 @@
+[Aliases]
+3=prthplj
+3l=prthplj /tr1
+4=4print -q -s -oprn
+4t=c:\4tex\texfiles\4tex
+bin=cdd c:\bin
+c=cls  
+cd=cdd
+ck=chkdsk
+cp=copy
+d=dir /o/l
+dw=cdd c:\dwnl
+e=exit
+em=d:\emacs\emacs @d:\emacs\emacs.rc
+gm=c:\bin\demacs
+h=cd\
+lo=exit
+ll=c:\ll\llremote
+ls=ls -al
+lt=latex
+nu=net use /yes
+p=pcopy
+pk=pkarc
+pl=pdel /nw
+pm=pmap
+pp=pp -w80 -l60 -h -n
+px=pkxarc
+s=ds ne /s
+t=xpand type
+tm=cdd c:\tmp
+tn=telnet
+tx=c:\telix\telix
+v=list
+wi=whereis
+win=runwin
+wp=cdd c:\docs
+x= tdir
+zc=pkzip -z
+zk=pkzip 
+zl=pkunzip -v
+zx=pkunzip
+
diff --git a/fastfngr/FF20C/FASTFNGR.MAK b/fastfngr/FF20C/FASTFNGR.MAK
new file mode 100644
index 0000000..9f17e79
--- /dev/null
+++ b/fastfngr/FF20C/FASTFNGR.MAK
@@ -0,0 +1,10 @@
+FASTFNGR.FRM
+C:\WINDOWS\SYSTEM\CMDIALOG.VBX
+C:\WINDOWS\SYSTEM\GRID.VBX
+C:\WINDOWS\SYSTEM\MSOLE2.VBX
+FASTFNGR.BAS
+ProjWinSize=76,573,225,148
+ProjWinShow=2
+IconForm="FastFinger"
+Title="FASTFNGR"
+ExeName="FASTFNGR.EXE"
diff --git a/fastfngr/FF20C/FASTFNGR.TXT b/fastfngr/FF20C/FASTFNGR.TXT
new file mode 100644
index 0000000..a249ae2
--- /dev/null
+++ b/fastfngr/FF20C/FASTFNGR.TXT
@@ -0,0 +1,429 @@
+Dim Paths(50) As String
+Dim Extensions(5) As String
+Dim Pindex As Integer
+
+Const MaxAlias = 100
+Dim Aliases(MaxAlias, 2) As String
+Dim aindex As Integer
+
+Const MaxHist = 20
+Dim HistIndex
+Dim HistBuff(MaxHist) As String
+Dim HistRoll
+Dim PBIndex
+Dim MaxHistUsed
+
+Const HOTKEY = 32       ' Space Bar
+Const ToggleKey = 200   ' Value to send here
+
+Const SHIFT_MASK = 1
+Const CTRL_MASK = 2
+Const ALT_MASK = 4
+Const KEY_MASK = CTRL_MASK + ALT_MASK
+
+Const KEY_ESC = 27
+
+
+Sub AliasSubst ()
+
+    ' Do relevant alias substitutions on buffer text
+    x = Len(buffer.Text)
+    y$ = Left$(buffer.Text, 1)
+    If ((y$ = "!") Or (y$ = "@")) Then
+        z = 2
+    Else
+        y$ = ""
+        z = 1
+    End If
+
+    While ((z <= x) And (Mid$(buffer.Text, z, 1) <> " "))
+        z = z + 1
+    Wend
+    
+    If (y$ = "") Then
+        q$ = Left$(buffer.Text, z - 1)
+    Else
+        q$ = Mid$(buffer.Text, 2, z - 2)
+    End If
+
+    m$ = Mid$(buffer.Text, z)
+    r = 0
+    x = 1
+    While ((x <= aindex) And (r = 0))
+        If (q$ = Aliases(x, 1)) Then
+            q$ = Aliases(x, 2)
+            r = 1
+        End If
+        x = x + 1
+    Wend
+    buffer.Text = y$ + q$ + m$
+
+End Sub
+
+Sub Buffer_DblClick ()
+    If ((HistRoll <> 0) Or (HistIndex <> 1)) Then
+        CmdHist.Clear
+        index = HistIndex - 1   'Start with last cmd
+        While (index <> 0)
+            CmdHist.AddItem HistBuff(index)
+            index = index - 1
+        Wend
+        If (HistRoll = 1) Then
+            index = MaxHist
+            While (index > HistIndex)
+                CmdHist.AddItem HistBuff(index)
+                index = index - 1
+            Wend
+        End If
+        CmdHist.Visible = 1
+    End If
+End Sub
+
+Sub Buffer_KeyPress (Key As Integer)
+    
+    Select Case Key
+    Case 1                  ' Ctrl-A
+        SendKeys "{Home}"
+        Key = 0             ' Stop the beep madness
+
+    Case 2                  ' Ctrl-B
+        SendKeys "{Left}"
+        Key = 0
+
+    Case 4                  ' Ctrl-D
+        SendKeys "{Del}"
+        Key = 0
+
+    Case 5                  ' Ctrl-E
+        SendKeys "{End}"
+        Key = 0
+
+    Case 6                  ' Ctrl-F
+        SendKeys "{Right}"
+        Key = 0
+    
+    Case 11                 ' Ctrl-K
+        buffer.Text = Left$(buffer.Text, buffer.SelStart)
+        SendKeys "{End}"
+        Key = 0
+    
+    Case 13                 ' Ctrl-M
+        If (buffer.Text <> "") Then
+            RunCommand
+        End If
+        Key = 0
+
+    Case 14                 ' Ctrl-N
+        If PBIndex < MaxHistUsed Then
+            PBIndex = PBIndex + 1
+        Else
+            PBIndex = 1
+        End If
+        buffer.Text = HistBuff(PBIndex)
+        SendKeys "{End}"
+        Key = 0
+
+    Case 16                 ' Ctrl-P
+        If PBIndex > 1 Then
+            PBIndex = PBIndex - 1
+        Else
+            PBIndex = MaxHistUsed
+        End If
+        buffer.Text = HistBuff(PBIndex)
+        SendKeys "{End}"
+        Key = 0
+        
+    Case KEY_ESC           ' Abort On Escape
+        buffer.Text = ""
+        Key = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Sub CmdHist_DblClick ()
+
+    ' Only get the command - allow normal editing
+    buffer.Text = CmdHist.Text
+    CmdHist.Visible = 0
+    SendKeys "{END}"    ' Position cursor at the end
+
+End Sub
+
+Sub CmdHist_KeyPress (Key As Integer)
+    
+    Select Case Key
+
+    Case KEY_ESC           ' Abort On Escape
+        Key = 0
+        CmdHist.Visible = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Function FindFile (Pgm As String) As String
+    Retval$ = ""
+    index = 1
+
+    On Error GoTo error_handler
+    While ((Retval$ = "") And (x <= Pindex))
+        trial$ = Paths$(x) + Pgm
+        Open trial$ For Input As 1
+        Close 1
+        Retval$ = trial$
+try_next:
+        x = x + 1
+    Wend
+    
+    FindFile = Retval$
+    Exit Function
+
+error_handler:
+    Close 1
+    Resume try_next
+End Function
+
+Function FindPgm (Pgm As String) As String
+    
+    ' First split into program name and arguments
+    index = 1
+    split = 0
+    Prog$ = Pgm
+    While ((split = 0) And (index <= Len(Pgm)))
+        If (Mid$(Pgm, index, 1) = " ") Then
+            split = index
+            Prog$ = Mid$(Pgm$, 1, split - 1)
+            Args$ = Mid$(Pgm$, split)
+        End If
+        index = index + 1
+    Wend
+    
+    index = 1
+    Retval$ = ""
+    While ((Retval$ = "") And (index <= 5))
+        Retval$ = FindFile(Prog$ + Extensions(index))
+        index = index + 1
+    Wend
+    
+    If (Retval$ = "") Then
+        FindPgm = Pgm$
+    Else
+        FindPgm = Retval$ + Args$
+    End If
+
+End Function
+
+Sub Form_KeyDown (Key As Integer, Shift As Integer)
+    Select Case Key
+    Case ToggleKey
+        If FastFinger.Visible = 0 Then
+             FastFinger.Visible = 1
+        Else
+             FastFinger.Visible = 0
+        End If
+    End Select
+End Sub
+
+Sub Form_Load ()
+    InitExt
+    InitBuf
+    InitPaths
+    InitAliases
+    HistIndex = 1
+    HistRoll = 0
+    MaxHistUsed = 0
+    hHotKey = CreateHK&(HOTKEY, KEY_MASK, HWnd, ToggleKey)
+    FastFinger.Visible = 0
+    CmdHist.Visible = 0
+End Sub
+
+Sub Form_Unload (Cancel As Integer)
+    KillHK hHotKey
+End Sub
+
+Sub InitAliases ()
+
+    aindex = 0      ' Means no aliases have been found
+    IniFile$ = App.Path + "\" + App.EXEName + ".INI"
+
+    On Error GoTo INI_file_done
+    Open IniFile$ For Input As 1
+    Input #1, x$
+    While (Not EOF(1))
+        If (InStr(1, x$, "[aliases]", 1)) Then
+            Input #1, x$
+            While (Not EOF(1) And (Not InStr(x$, "[")) And (aindex < MaxAlias))
+                aindex = aindex + 1
+                Aliases(aindex, 1) = x$
+                Input #1, x$
+            Wend
+            GoTo INI_file_done
+        End If
+        Input #1, x$
+    Wend
+
+INI_file_done:
+    Close 1
+
+    If (aindex > 0) Then
+        y = 1
+        While (y <= aindex)
+        eindex = InStr(Aliases(y, 1), "=")
+        If (eindex > 0) Then
+            Aliases(y, 2) = Scrub(Mid$(Aliases(y, 1), eindex + 1))
+            Aliases(y, 1) = Scrub(Left$(Aliases(y, 1), eindex - 1))
+        End If
+        y = y + 1
+        Wend
+    End If
+End Sub
+
+Sub InitBuf ()
+    buffer.Text = "" ' Clear out text
+End Sub
+
+Sub InitExt ()
+
+    Extensions(1) = ""
+    Extensions(2) = ".COM"
+    Extensions(3) = ".EXE"
+    Extensions(4) = ".BAT"
+    Extensions(5) = ".PIF"
+
+End Sub
+
+Sub InitPaths ()
+
+    Path$ = Environ("PATH")
+    
+    ' First, get each path component into separate array location
+    Pindex = 0
+    start = 1
+    
+    While (start <= Len(Path$))
+        Pindex = Pindex + 1
+        last = start
+        char$ = Mid$(Path$, last, 1)
+        While ((char$ <> ";") And (last <= Len(Path$)))
+            last = last + 1
+            char$ = Mid$(Path$, last, 1)
+        Wend
+        Paths(Pindex) = Mid$(Path$, start, last - start)
+        start = last + 1
+    Wend
+
+    ' Now, make sure each ends with directory separator
+    For x = 1 To Pindex Step 1
+        If (Mid$(Paths$(x), Len(Paths$(x)), 1) <> "\") Then
+            Paths$(x) = Paths$(x) + "\"
+        End If
+    Next
+End Sub
+
+Sub RunCommand ()
+    
+    ' Store command in (circular) history buffer
+    HistBuff(HistIndex) = buffer.Text
+    HistIndex = HistIndex + 1
+    If (HistIndex > MaxHist) Then
+        HistRoll = 1
+        HistIndex = 1
+    End If
+    MaxHistUsed = MaxHistUsed + 1
+    If (MaxHistUsed > MaxHist) Then
+        MaxHistUsed = MaxHist
+    End If
+    PBIndex = HistIndex
+
+    AliasSubst
+
+    ' If we see <, >, or |, force command interpreter use
+    index = 1
+    bang = 0
+    While (index <= Len(buffer.Text) And (bang = 0))
+          Select Case Mid$(buffer.Text, index, 1)
+            Case "<"
+                bang = 1
+            Case ">"
+                bang = 1
+            Case "|"
+                bang = 1
+          End Select
+          index = index + 1
+    Wend
+    If ((bang = 1) And (Left$(buffer.Text, 1) <> "!")) Then
+        buffer.Text = "!" + buffer.Text
+    End If
+
+    ' Should we do post-processing?
+    dopost = 0
+    If (Left$(buffer.Text, 1) = "@") Then
+        buffer.Text = "!" + Mid$(buffer.Text, 2)
+        dopost = 1
+    End If
+    
+    ' Are we pre-processing?
+    If (Left$(buffer.Text, 1) = "!") Then
+        Prefix$ = Environ$("FF_SHPRE")
+        If (Prefix$ = "") Then
+            Prefix$ = "command.com /c"
+        End If
+        Pgm$ = Mid$(buffer.Text, 2)
+    Else
+        Prefix$ = ""
+        Pgm$ = buffer.Text
+        Pgm$ = FindPgm(Pgm$)
+    End If
+    
+    ' Setup any relevant pre- and post-processing
+    If (Prefix$ <> "") Then
+        Pgm$ = Prefix$ + " " + Pgm$
+    End If
+            
+    Postfix$ = Environ$("FF_SHPOST")
+    If ((Postfix$ <> "") And (dopost = 1)) Then
+        Pgm$ = Pgm$ + " | " + Postfix$
+    End If
+    
+    ' Execute the command
+    On Error Resume Next
+    If (Pgm$ <> "") Then
+        TaskID = Shell(Pgm$, 1)
+    End If
+    InitBuf
+
+End Sub
+
+Function Scrub (xxx As String) As String
+
+    ' Scrub leading and trailing spaces from the string
+
+    z = Len(xxx)
+    j = 0
+    k = 0
+    l = 0
+
+    While ((j < z) And (k = 0)) ' Find start of string
+        j = j + 1
+        tmp$ = Mid$(xxx, j, 1)
+        If (tmp$ <> " ") Then k = j
+    Wend
+
+    j = z
+    While ((j > 0) And (l = 0)) ' Find end of string
+        tmp$ = Mid$(xxx, j, 1)
+        If (tmp$ <> " ") Then l = j
+        j = j - 1
+    Wend
+
+    Scrub = Mid$(xxx, k, l - k + 1)
+
+End Function
+
diff --git a/fastfngr/FF20C/FASTFNGR.WRI b/fastfngr/FF20C/FASTFNGR.WRI
new file mode 100644
index 0000000..2c3dc53
--- /dev/null
+++ b/fastfngr/FF20C/FASTFNGR.WRI
Binary files differ
diff --git a/fastfngr/FF21/FASTFNGR.BAS b/fastfngr/FF21/FASTFNGR.BAS
new file mode 100644
index 0000000..33a6f16
--- /dev/null
+++ b/fastfngr/FF21/FASTFNGR.BAS
@@ -0,0 +1,6 @@
+'HOTKEY.DLL functions
+DefInt A-Z
+
+Declare Function CreateHK& Lib "HOTKEY.DLL" (ByVal KeyCode, ByVal Shift, ByVal hWnd, ByVal UserVK)
+Declare Sub KillHK Lib "HOTKEY.DLL" (ByVal hHotKey&)
+
diff --git a/fastfngr/FF21/FASTFNGR.EXE b/fastfngr/FF21/FASTFNGR.EXE
new file mode 100644
index 0000000..426c9bf
--- /dev/null
+++ b/fastfngr/FF21/FASTFNGR.EXE
Binary files differ
diff --git a/fastfngr/FF21/FASTFNGR.FRM b/fastfngr/FF21/FASTFNGR.FRM
new file mode 100644
index 0000000..c186ce2
--- /dev/null
+++ b/fastfngr/FF21/FASTFNGR.FRM
Binary files differ
diff --git a/fastfngr/FF21/FASTFNGR.MAK b/fastfngr/FF21/FASTFNGR.MAK
new file mode 100644
index 0000000..9f17e79
--- /dev/null
+++ b/fastfngr/FF21/FASTFNGR.MAK
@@ -0,0 +1,10 @@
+FASTFNGR.FRM
+C:\WINDOWS\SYSTEM\CMDIALOG.VBX
+C:\WINDOWS\SYSTEM\GRID.VBX
+C:\WINDOWS\SYSTEM\MSOLE2.VBX
+FASTFNGR.BAS
+ProjWinSize=76,573,225,148
+ProjWinShow=2
+IconForm="FastFinger"
+Title="FASTFNGR"
+ExeName="FASTFNGR.EXE"
diff --git a/fastfngr/FF21/FASTFNGR.TXT b/fastfngr/FF21/FASTFNGR.TXT
new file mode 100644
index 0000000..a249ae2
--- /dev/null
+++ b/fastfngr/FF21/FASTFNGR.TXT
@@ -0,0 +1,429 @@
+Dim Paths(50) As String
+Dim Extensions(5) As String
+Dim Pindex As Integer
+
+Const MaxAlias = 100
+Dim Aliases(MaxAlias, 2) As String
+Dim aindex As Integer
+
+Const MaxHist = 20
+Dim HistIndex
+Dim HistBuff(MaxHist) As String
+Dim HistRoll
+Dim PBIndex
+Dim MaxHistUsed
+
+Const HOTKEY = 32       ' Space Bar
+Const ToggleKey = 200   ' Value to send here
+
+Const SHIFT_MASK = 1
+Const CTRL_MASK = 2
+Const ALT_MASK = 4
+Const KEY_MASK = CTRL_MASK + ALT_MASK
+
+Const KEY_ESC = 27
+
+
+Sub AliasSubst ()
+
+    ' Do relevant alias substitutions on buffer text
+    x = Len(buffer.Text)
+    y$ = Left$(buffer.Text, 1)
+    If ((y$ = "!") Or (y$ = "@")) Then
+        z = 2
+    Else
+        y$ = ""
+        z = 1
+    End If
+
+    While ((z <= x) And (Mid$(buffer.Text, z, 1) <> " "))
+        z = z + 1
+    Wend
+    
+    If (y$ = "") Then
+        q$ = Left$(buffer.Text, z - 1)
+    Else
+        q$ = Mid$(buffer.Text, 2, z - 2)
+    End If
+
+    m$ = Mid$(buffer.Text, z)
+    r = 0
+    x = 1
+    While ((x <= aindex) And (r = 0))
+        If (q$ = Aliases(x, 1)) Then
+            q$ = Aliases(x, 2)
+            r = 1
+        End If
+        x = x + 1
+    Wend
+    buffer.Text = y$ + q$ + m$
+
+End Sub
+
+Sub Buffer_DblClick ()
+    If ((HistRoll <> 0) Or (HistIndex <> 1)) Then
+        CmdHist.Clear
+        index = HistIndex - 1   'Start with last cmd
+        While (index <> 0)
+            CmdHist.AddItem HistBuff(index)
+            index = index - 1
+        Wend
+        If (HistRoll = 1) Then
+            index = MaxHist
+            While (index > HistIndex)
+                CmdHist.AddItem HistBuff(index)
+                index = index - 1
+            Wend
+        End If
+        CmdHist.Visible = 1
+    End If
+End Sub
+
+Sub Buffer_KeyPress (Key As Integer)
+    
+    Select Case Key
+    Case 1                  ' Ctrl-A
+        SendKeys "{Home}"
+        Key = 0             ' Stop the beep madness
+
+    Case 2                  ' Ctrl-B
+        SendKeys "{Left}"
+        Key = 0
+
+    Case 4                  ' Ctrl-D
+        SendKeys "{Del}"
+        Key = 0
+
+    Case 5                  ' Ctrl-E
+        SendKeys "{End}"
+        Key = 0
+
+    Case 6                  ' Ctrl-F
+        SendKeys "{Right}"
+        Key = 0
+    
+    Case 11                 ' Ctrl-K
+        buffer.Text = Left$(buffer.Text, buffer.SelStart)
+        SendKeys "{End}"
+        Key = 0
+    
+    Case 13                 ' Ctrl-M
+        If (buffer.Text <> "") Then
+            RunCommand
+        End If
+        Key = 0
+
+    Case 14                 ' Ctrl-N
+        If PBIndex < MaxHistUsed Then
+            PBIndex = PBIndex + 1
+        Else
+            PBIndex = 1
+        End If
+        buffer.Text = HistBuff(PBIndex)
+        SendKeys "{End}"
+        Key = 0
+
+    Case 16                 ' Ctrl-P
+        If PBIndex > 1 Then
+            PBIndex = PBIndex - 1
+        Else
+            PBIndex = MaxHistUsed
+        End If
+        buffer.Text = HistBuff(PBIndex)
+        SendKeys "{End}"
+        Key = 0
+        
+    Case KEY_ESC           ' Abort On Escape
+        buffer.Text = ""
+        Key = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Sub CmdHist_DblClick ()
+
+    ' Only get the command - allow normal editing
+    buffer.Text = CmdHist.Text
+    CmdHist.Visible = 0
+    SendKeys "{END}"    ' Position cursor at the end
+
+End Sub
+
+Sub CmdHist_KeyPress (Key As Integer)
+    
+    Select Case Key
+
+    Case KEY_ESC           ' Abort On Escape
+        Key = 0
+        CmdHist.Visible = 0
+
+    Case Else
+        ' Ignore All Else
+    
+    End Select
+
+End Sub
+
+Function FindFile (Pgm As String) As String
+    Retval$ = ""
+    index = 1
+
+    On Error GoTo error_handler
+    While ((Retval$ = "") And (x <= Pindex))
+        trial$ = Paths$(x) + Pgm
+        Open trial$ For Input As 1
+        Close 1
+        Retval$ = trial$
+try_next:
+        x = x + 1
+    Wend
+    
+    FindFile = Retval$
+    Exit Function
+
+error_handler:
+    Close 1
+    Resume try_next
+End Function
+
+Function FindPgm (Pgm As String) As String
+    
+    ' First split into program name and arguments
+    index = 1
+    split = 0
+    Prog$ = Pgm
+    While ((split = 0) And (index <= Len(Pgm)))
+        If (Mid$(Pgm, index, 1) = " ") Then
+            split = index
+            Prog$ = Mid$(Pgm$, 1, split - 1)
+            Args$ = Mid$(Pgm$, split)
+        End If
+        index = index + 1
+    Wend
+    
+    index = 1
+    Retval$ = ""
+    While ((Retval$ = "") And (index <= 5))
+        Retval$ = FindFile(Prog$ + Extensions(index))
+        index = index + 1
+    Wend
+    
+    If (Retval$ = "") Then
+        FindPgm = Pgm$
+    Else
+        FindPgm = Retval$ + Args$
+    End If
+
+End Function
+
+Sub Form_KeyDown (Key As Integer, Shift As Integer)
+    Select Case Key
+    Case ToggleKey
+        If FastFinger.Visible = 0 Then
+             FastFinger.Visible = 1
+        Else
+             FastFinger.Visible = 0
+        End If
+    End Select
+End Sub
+
+Sub Form_Load ()
+    InitExt
+    InitBuf
+    InitPaths
+    InitAliases
+    HistIndex = 1
+    HistRoll = 0
+    MaxHistUsed = 0
+    hHotKey = CreateHK&(HOTKEY, KEY_MASK, HWnd, ToggleKey)
+    FastFinger.Visible = 0
+    CmdHist.Visible = 0
+End Sub
+
+Sub Form_Unload (Cancel As Integer)
+    KillHK hHotKey
+End Sub
+
+Sub InitAliases ()
+
+    aindex = 0      ' Means no aliases have been found
+    IniFile$ = App.Path + "\" + App.EXEName + ".INI"
+
+    On Error GoTo INI_file_done
+    Open IniFile$ For Input As 1
+    Input #1, x$
+    While (Not EOF(1))
+        If (InStr(1, x$, "[aliases]", 1)) Then
+            Input #1, x$
+            While (Not EOF(1) And (Not InStr(x$, "[")) And (aindex < MaxAlias))
+                aindex = aindex + 1
+                Aliases(aindex, 1) = x$
+                Input #1, x$
+            Wend
+            GoTo INI_file_done
+        End If
+        Input #1, x$
+    Wend
+
+INI_file_done:
+    Close 1
+
+    If (aindex > 0) Then
+        y = 1
+        While (y <= aindex)
+        eindex = InStr(Aliases(y, 1), "=")
+        If (eindex > 0) Then
+            Aliases(y, 2) = Scrub(Mid$(Aliases(y, 1), eindex + 1))
+            Aliases(y, 1) = Scrub(Left$(Aliases(y, 1), eindex - 1))
+        End If
+        y = y + 1
+        Wend
+    End If
+End Sub
+
+Sub InitBuf ()
+    buffer.Text = "" ' Clear out text
+End Sub
+
+Sub InitExt ()
+
+    Extensions(1) = ""
+    Extensions(2) = ".COM"
+    Extensions(3) = ".EXE"
+    Extensions(4) = ".BAT"
+    Extensions(5) = ".PIF"
+
+End Sub
+
+Sub InitPaths ()
+
+    Path$ = Environ("PATH")
+    
+    ' First, get each path component into separate array location
+    Pindex = 0
+    start = 1
+    
+    While (start <= Len(Path$))
+        Pindex = Pindex + 1
+        last = start
+        char$ = Mid$(Path$, last, 1)
+        While ((char$ <> ";") And (last <= Len(Path$)))
+            last = last + 1
+            char$ = Mid$(Path$, last, 1)
+        Wend
+        Paths(Pindex) = Mid$(Path$, start, last - start)
+        start = last + 1
+    Wend
+
+    ' Now, make sure each ends with directory separator
+    For x = 1 To Pindex Step 1
+        If (Mid$(Paths$(x), Len(Paths$(x)), 1) <> "\") Then
+            Paths$(x) = Paths$(x) + "\"
+        End If
+    Next
+End Sub
+
+Sub RunCommand ()
+    
+    ' Store command in (circular) history buffer
+    HistBuff(HistIndex) = buffer.Text
+    HistIndex = HistIndex + 1
+    If (HistIndex > MaxHist) Then
+        HistRoll = 1
+        HistIndex = 1
+    End If
+    MaxHistUsed = MaxHistUsed + 1
+    If (MaxHistUsed > MaxHist) Then
+        MaxHistUsed = MaxHist
+    End If
+    PBIndex = HistIndex
+
+    AliasSubst
+
+    ' If we see <, >, or |, force command interpreter use
+    index = 1
+    bang = 0
+    While (index <= Len(buffer.Text) And (bang = 0))
+          Select Case Mid$(buffer.Text, index, 1)
+            Case "<"
+                bang = 1
+            Case ">"
+                bang = 1
+            Case "|"
+                bang = 1
+          End Select
+          index = index + 1
+    Wend
+    If ((bang = 1) And (Left$(buffer.Text, 1) <> "!")) Then
+        buffer.Text = "!" + buffer.Text
+    End If
+
+    ' Should we do post-processing?
+    dopost = 0
+    If (Left$(buffer.Text, 1) = "@") Then
+        buffer.Text = "!" + Mid$(buffer.Text, 2)
+        dopost = 1
+    End If
+    
+    ' Are we pre-processing?
+    If (Left$(buffer.Text, 1) = "!") Then
+        Prefix$ = Environ$("FF_SHPRE")
+        If (Prefix$ = "") Then
+            Prefix$ = "command.com /c"
+        End If
+        Pgm$ = Mid$(buffer.Text, 2)
+    Else
+        Prefix$ = ""
+        Pgm$ = buffer.Text
+        Pgm$ = FindPgm(Pgm$)
+    End If
+    
+    ' Setup any relevant pre- and post-processing
+    If (Prefix$ <> "") Then
+        Pgm$ = Prefix$ + " " + Pgm$
+    End If
+            
+    Postfix$ = Environ$("FF_SHPOST")
+    If ((Postfix$ <> "") And (dopost = 1)) Then
+        Pgm$ = Pgm$ + " | " + Postfix$
+    End If
+    
+    ' Execute the command
+    On Error Resume Next
+    If (Pgm$ <> "") Then
+        TaskID = Shell(Pgm$, 1)
+    End If
+    InitBuf
+
+End Sub
+
+Function Scrub (xxx As String) As String
+
+    ' Scrub leading and trailing spaces from the string
+
+    z = Len(xxx)
+    j = 0
+    k = 0
+    l = 0
+
+    While ((j < z) And (k = 0)) ' Find start of string
+        j = j + 1
+        tmp$ = Mid$(xxx, j, 1)
+        If (tmp$ <> " ") Then k = j
+    Wend
+
+    j = z
+    While ((j > 0) And (l = 0)) ' Find end of string
+        tmp$ = Mid$(xxx, j, 1)
+        If (tmp$ <> " ") Then l = j
+        j = j - 1
+    Wend
+
+    Scrub = Mid$(xxx, k, l - k + 1)
+
+End Function
+
diff --git a/fastfngr/FF21/FASTFNGR.WRI b/fastfngr/FF21/FASTFNGR.WRI
new file mode 100644
index 0000000..2c3dc53
--- /dev/null
+++ b/fastfngr/FF21/FASTFNGR.WRI
Binary files differ
diff --git a/fastfngr/HOTKEY.DLL b/fastfngr/HOTKEY.DLL
new file mode 100644
index 0000000..43465b2
--- /dev/null
+++ b/fastfngr/HOTKEY.DLL
Binary files differ
diff --git a/fastfngr/README.1ST b/fastfngr/README.1ST
new file mode 100644
index 0000000..d60c20a
--- /dev/null
+++ b/fastfngr/README.1ST
@@ -0,0 +1,97 @@
+05-09-95
+
+Thanks for taking the time to try FastFinger.  Please read the installation and
+user documentation below.  After you've used this tool for  a few days, please
+fill out the questionnaire at the end of this file and  return it to me (email
+is fine: tundra@ct.covia.com).  PLEASE: Do not redistribute these files to
+other people or onto BBS systems.
+
+
+WHAT FASTFINGER DOES
+====================
+
+FastFinger is a Windows utility which provides a "pop up" command line
+interface from which you may launch either Windows or MS-DOS programs.  By
+using FastFinger you avoid having to navigate back to the Program Manager
+or File Manager windows to launch other programs.
+
+
+INSTALLATION
+============
+
+There are three files in the FastFinger distribution: FASTFNGR.EXE, HOTKEY.DLL,
+and VBRUN300.DLL.  Copy all three of these into your WINDOWS directory.
+
+Launch FASTFNGR.EXE as you would any other Windows program.  You may find it
+convenient to add it to the RUN= line of the WIN.INI file so that FastFinger is
+available each time you start Windows.
+
+
+USING FASTFINGER
+================
+
+When you first start FastFinger, it is running, but invisible.  To make
+FastFinger visible, press the Alt, Ctrl, and spacebar keys simultaneously. 
+Pressing this key combination again will toggle FastFinger back to its
+invisible state.
+
+To start a program, type the program name in the FastFinger command line window
+and press the Enter key.  If you want to re-execute a command, use the mouse to
+double-click in the command window.  A scrollable list of up to the last 20
+commands will be displayed.  Simply double-click on the command you wish to
+re-execute.
+
+By default, FastFinger assumes that you entered a program name without an
+extension. It searches the directories specified by the PATH environment
+variable to see if it can find your program with the .COM, .EXE, .BAT, or .PIF
+extensions respectively.
+
+FastFinger automatically launches either Windows or MS-DOS programs.   If you
+know your program is an MS-DOS program and want to skip the searching described
+above, you can tell FastFinger to just pass the command line as you typed it to
+the DOS command interpreter.  This is done by beginning the command line with
+an exclamation mark (!).  Even if you do not use this escape mechanism,
+FastFinger will automatically insert it if your command contains redirection or
+piping characters (<, >, or |).
+
+
+NOW ITS YOUR TURN ...
+=====================
+
+Please take the time to email back the following questionnaire.  Answer each
+question with a number from 1 to 5 keyed as follows:
+
+    1) I Disagree Strongly
+    2) I Tend To Disagree
+    3) I Have No Opinion
+    4) I Tend To Agree
+    5) I Agree Strongly
+
+
+___________________________________________________________________________________
+
+                        QUESTIONNAIRE
+                        =============
+
+I am an experienced MS-Windows User                 _____
+
+I am unfamiliar with MS-DOS command lines.          _____
+
+FastFinger made Windows use simpler.                _____
+
+Using FastFinger slowed me down.                    _____
+
+FastFinger is something I now use regularly.        _____
+
+FastFinger does nothing I need.                     _____
+
+FastFinger is now part of my default environment.   _____
+
+
+OTHER COMMENTS:
+
+
+
+
+___________________________________________________________________________________
+
diff --git a/fastfngr/VBRUN300.DLL b/fastfngr/VBRUN300.DLL
new file mode 100644
index 0000000..7966645
--- /dev/null
+++ b/fastfngr/VBRUN300.DLL
Binary files differ
diff --git a/ff/FF.ASM b/ff/FF.ASM
new file mode 100644
index 0000000..901d42a
--- /dev/null
+++ b/ff/FF.ASM
@@ -0,0 +1,113 @@
+
+		PAGE 66,132
+		TITLE FF.ASM
+;
+;
+; **********
+; * FF - Automatic Printer FormFeed - Version 1.0.0
+; * Copyright (c) 1984 by T.A. Daneliuk
+; * Last Modified: 07/06/84
+; **********
+;
+;
+; **********
+; * SYSTEM EQUATES
+; **********
+;
+;
+FORMFEED	EQU		0CH		; Formfeed character
+SVC		EQU		21H		; DOS System Entry
+PRINT_STRING	EQU		09H		; Print string call
+PRINTER		EQU		05H		; Print character on printer
+EXIT		EQU		00H		; DOS Exit Vector
+EOL		EQU		0A0DH		; End of Line
+;
+;
+; **********
+; * STACK SEGMENT
+; **********
+;
+;
+STACK		SEGMENT	PARA STACK 'STACK'
+;
+;
+		DB		10 DUP('STACK ')
+;
+;
+STACK		ENDS
+;
+;
+; **********
+; * SEGMENT CONTAINING SIGNON MESSAGE
+; **********
+;
+;
+LOGON_MSG	SEGMENT WORD 'DATA'
+;
+;
+MSG1		DB		'Printer FormFeed - Version 1.0.0'
+		DW		EOL
+		DB		'Copyright (c) 1984, T.A. Daneliuk'
+		DW		EOL
+		DB		'$'
+;
+;
+LOGON_MSG	ENDS
+;
+;
+; **********
+; * SEGMENT CONTAINING ACTUAL RUNTIME CODE
+; **********
+;
+;
+RUNTIME		SEGMENT WORD 'CODE'
+;
+;
+		ASSUME		CS:RUNTIME,DS:LOGON_MSG,SS:STACK
+;
+;
+START		PROC		FAR
+;
+;
+; First setup the return on the stack
+;
+;
+		PUSH		DS			; Save for return
+		XOR		AX,AX
+		PUSH		AX
+;
+;
+; Now point DS to the message field
+;
+;
+		MOV		AX,LOGON_MSG
+		MOV		DS,AX
+;
+;
+; Now display the message
+;
+;
+		MOV		DX,OFFSET MSG1
+		MOV		AH,PRINT_STRING
+		INT		SVC
+;
+;
+; Now send the FormFeed to the printer
+;
+;
+		MOV		DL,FORMFEED		; Character to send printer
+		MOV		AH,PRINTER
+		INT		SVC
+;
+;
+; Time to go back to the DOS
+;
+;
+		RET
+;
+;
+START		ENDP
+;
+;
+RUNTIME		ENDS
+		END		START
diff --git a/filefind/FILEFIND.A b/filefind/FILEFIND.A
new file mode 100644
index 0000000..e1ec837
--- /dev/null
+++ b/filefind/FILEFIND.A
@@ -0,0 +1,152 @@
+; Fixed bugs in error return handling in FindFirst and FindNext
+; 02-17-87  T.A. Daneliuk
+;
+;
+; Copyright (c) 1985 Martin Nohr and Tom Serface
+; All Rights Reserved
+;
+;Revision	Date		Description
+;--------	---------	--------------------------------------------
+
+; Interrupt and codes for the keyboard interface.
+DOSINT		equ	21h		;call to ibm dos function
+
+	cseg 
+
+; DOS 2.0 functions to find files given filespec the argument to
+; FindFirst() is a pointer to a filespec containing d:\path\filespec
+; and an integer permission attribute for the files to find.
+; FindNext() simply continues and fills in the DTA area with the file
+; matching the next pattern.  FileFind.h must be included in any subroutines
+; using these routines.
+; In the calling program you would first call SetDta(&dataArea);
+; and then call FindFirst(filespec,attr) finally subsequent calls to
+; FindNext(attr) can be made. 
+; The filename and attributes can be read from dataArea.
+
+;SetDta		Set up DTA for Wild Card Conversions or whatever
+;		This version assumes that the Struct is in the 
+;		programs DS.
+;
+;		Call as SetDta(&dataArea)
+;		Where dataArea is struct *DTA dataArea
+;void SetDta();
+;struct DTA dataArea;
+
+	public SetDta_
+SetDta_:
+	push	bp
+	mov	bp,sp
+	mov	dx,[bp+4]
+	mov	ah,1Ah		; set disk transfer address
+	int	DOSINT
+	pop	bp
+	ret
+
+;GetDta		Get the current DTA segment and offset
+;
+;		Call as GetDta(&segment,&offset)
+;		Where segment and offset are unsigned
+;
+;void GetDta();
+;unsigned segment, offset;
+
+	public GetDta_
+GetDta_:
+	push	bp
+	mov	bp,sp
+	mov	ah,2fh		; get disk transfer address
+	int	DOSINT
+	mov	ax,es
+	mov	si,[bp+4]
+	mov	word [si],ax
+	mov	si,[bp+6]
+	mov	word [si],bx
+	pop	bp
+	ret
+
+;RestDta	Restore DTA Saved with GetDta
+;
+;		Call as RestDta(segment,offset)
+;		Where segment and offset are unsigned
+;void RestDta();
+;unsigned segment, offset;
+
+	public RestDta_
+RestDta_:
+	push	bp
+	mov	bp,sp
+	push	ds
+	mov	ds,[bp+4]
+	mov	dx,[bp+6]
+	mov	ah,1Ah		; set disk transfer address
+	int	DOSINT
+	pop	ds
+	pop	bp
+	ret
+
+;FindFirst	Find the First File From a Wild Card Pattern
+;
+;		Call as: FindFirst(filespec,attr)
+;		Where filespec is a char *
+;		and attr is an int attribute for the file
+;		76543210 Bits
+;		00000000 - Regular file
+;		       1 - Read Only
+;		      1  - Hidden
+;		     1   - System
+;		    1    - Volume Label
+;		   1     - Subdirectory
+;                 1      - Archive
+;                1       - Unused
+;		1        - Unused
+;		Returns 0 if no file found 1 if file is found
+;
+;int FindFirst();
+;char *filespec;
+;int attr;
+
+	public FindFirst_
+FindFirst_:
+	push	bp
+	mov	bp,sp
+	mov	dx,[bp+4]	;pointer to filespec		
+	mov	cx,[bp+6]	;attribute to search
+	mov	ah, 04eh
+	int	DOSINT
+	and	ax,ax		; 0 from DOS means file found - tad
+	jnz	no_mor
+	inc	ax		; found file so return 1 - tad
+	jmp	don
+no_mor:
+	xor	ax,ax		; no file found, return 0 - tad
+don:
+	pop	bp
+	ret
+
+
+;FindNext	Find the Next File From a Wild Card Pattern
+;
+;		Call as: FindNext(attr)
+;		Where: attr is an int attribute for the files
+;		       to find.
+;		Returns 0 if no file found 1 if file is found
+;int FindNext();
+;int attr;
+
+	public FindNext_
+FindNext_:
+	push	bp
+	mov	bp,sp
+	mov	cx,[bp+4]	;attribute
+	mov	ah, 04fH	;find next file in filespec
+	int	DOSINT
+	and	ax,ax		; 0 from DOS means file found - tad
+	jnz	no_more
+	inc	ax		; found file so return 1 - tad
+	jmp	done
+no_more:
+	xor	ax,ax		; no file found, return 0 - tad
+done:
+	pop	bp
+	ret
diff --git a/fldedi/FLD_EDI.C b/fldedi/FLD_EDI.C
new file mode 100644
index 0000000..75000f7
--- /dev/null
+++ b/fldedi/FLD_EDI.C
@@ -0,0 +1,34 @@
+/*  fld_edi.c -   Set Of Routines For Simple Field Editing
+
+                    Last Modified: 05-23-90
+                    Copyright (C) 1990, T.A. Daneliuk
+
+*/
+
+#include    <stdio.h>
+
+
+
+/*============ Global Control And Keystroke Translation Tables ===============*/
+
+
+struct CXLATE ctrl_xlate[CTRL_ENTRY] =     {2,  0, 80, NXT_FLD, /* Dn. Arrow  */
+                                            1,  9,  0, NXT_FLD, /* Tab        */
+                                            2,  0, 15, PRV_FLD, /* Back Tab   */
+                                            2,  0, 72, PRV_FLD, /* Up Arrow   */
+                                            2,  0, 73, FST_FLD, /* PgUp       */
+                                            2,  0, 81, LST_FLD, /* PgDn       */
+                                            2,  0, 75, CUR_LFT, /* Lft. Arrow */
+                                            2,  0, 77, CUR_RGT, /* Rt. Arrow  */
+                                            2,  0, 71, BEG_FLD, /* Home       */
+                                            2,  0, 79, END_FLD, /* End        */
+                                            1, 10,  0, CLR_FLD, /* Ctrl-Enter */
+                                            2, 0, 117, CLR_END, /* Ctrl-End   */
+                                            1, 13,  0, EXT_FLD, /* Enter      */
+                                            2,  0, 82, INS,     /* Ins        */
+                                            2,  0, 83, DEL,     /* Del        */
+                                            1,  8, 00, BS,      /* Backspace  */
+                                            2,  0, 59, HELP,    /* Fn. 1      */
+                                            1, 27,  0, EXT_SCR  /* Esc        */
+                                           };
+
diff --git a/fstam/FSTAMP.A b/fstam/FSTAMP.A
new file mode 100644
index 0000000..51840da
--- /dev/null
+++ b/fstam/FSTAMP.A
@@ -0,0 +1,123 @@
+; FSTAMP.A - Routine callable by DeSmet C returning file time/date stamp
+;		Copyright (c) 1986, T.A. Daneliuk
+;		Last Modified: 09/20/86
+;
+;
+; 	usage:	fstamp(fp,date,time);
+;	where,	fp is pointer to an open file
+;		date is a pointer to a character array to hold date (mm-dd-yy)
+;		time is a pointer to a character array to hold time (hh:mm:ss)
+;
+;	If system call fails, the arrays are returned with zeros
+;
+;
+;	Passed Parameters
+;
+fp	equ	[bp+4]
+date	equ	[bp+6]
+time	equ	[bp+8]
+;
+;
+		dseg
+;
+;
+idat		db	'00-00-8000:00:00'
+fdate		dw	0
+ftime		dw	0
+;
+;
+		cseg
+		public		fstamp_
+;
+;
+fstamp_:
+		push	bp				; Procedure prologue
+		mov	bp,sp
+		push	si				; Need a couple pointers
+		push	di
+		mov	si,time
+		mov	di,date
+		mov	bx,offset idat
+		mov	cx,8
+init:		mov	al,[bx]
+		mov	ds:[di],al
+		mov	al,[bx+8]
+		mov	ds:[si],al
+		inc	si
+		inc	di
+		inc	bx
+		loop	init
+		mov byte ds:[di],0			; Put Null terminators in
+		mov byte ds:[si],0
+		pop	di
+		pop	si
+		mov	ax,5700h
+		mov	bx,fp
+		int	21h
+		jc	alldone				; Had and error, so quit now		
+		mov	fdate,dx			; Save binary images
+		mov	ftime,cx
+		mov	bx,date				; Do date digits first
+		inc	bx				; Month field first
+		mov	ax,dx
+		mov	cl,5
+		shr	ax,cl
+		and	ax,000fh
+		call	addasc
+		add	bx,3				; Day field next
+		mov	ax,fdate
+		and	ax,001fh
+		call	addasc
+		add	bx,3				; Year field last
+		mov	ax,fdate
+		mov	cl,9
+		shr	ax,cl
+		and	ax,007fh
+		call	addasc
+		mov	bx,time				; Now do time digits
+		inc	bx				; Hours field first
+		mov	ax,cx
+		mov	cl,11
+		shr	ax,cl
+		and	ax,001fh
+		call 	addasc
+		add	bx,3				; Minutes field next
+		mov	ax,ftime
+		mov	cl,5
+		shr	ax,cl
+		and	ax,003fh
+		call 	addasc
+		add	bx,3				; Seconds field last
+		mov	ax,ftime
+		and	ax,001fh
+		shl	ax,1				; Multiply by 2
+		call	addasc
+alldone:	pop	bp
+		ret
+;
+;
+; Do An ASCII Addition: Add Binary Contents In AL To ASCII String At BX
+;
+;
+addasc:
+top:		dec	al
+		cmp	al,-1
+		jz	done
+		mov	ah,[bx]
+		cmp	ah,'9'
+		jz	digit2
+		inc byte [bx]
+		jmp	top
+digit2:		mov	ah,'0'
+		mov	[bx],ah
+		mov	ah,[bx-1]
+		cmp	ah,'9'
+		jz	digit3
+		inc byte [bx-1]
+		jmp	top
+digit3:		mov	ah,'0'
+		mov	[bx-1],ah
+		jmp	top
+done:		ret		
+		end
+
diff --git a/getopt/GETOPT.C b/getopt/GETOPT.C
new file mode 100644
index 0000000..d8ed332
--- /dev/null
+++ b/getopt/GETOPT.C
@@ -0,0 +1,194 @@
+#define MODNAME "getopt"
+
+/*****************************************************************************
+**
+**		GETOPT -- Function to provide look-alike functionality to the
+**					Unix System V getopt(3) function.
+**
+**	See the Unix System V User's Manual getopt(3) for complete usage
+**	details.
+**
+*****************************************************************************/
+#include <stdio.h>
+/* #include <string.h> */
+
+typedef	int BOOL;
+
+#define MINUS '-'
+#define COLON ':'
+#define QUESTION '?'
+#define CNULL '\0'
+    
+    
+char *optarg = NULL;
+int optind = 0;
+
+getopt(argc,argv,optstring)
+int argc;
+char **argv;
+char *optstring;
+{
+    static int curarg = 0;
+    static int curopt = 0;
+	static BOOL done = FALSE;
+	static char progname[13];
+    char *tptr;
+    
+	if ((curarg == 0) && (curopt == 0))
+		{
+		tptr = strrchr(*argv,'\\');
+		tptr++;
+		tptr = strncpy(progname,tptr,12);
+		if ((tptr = strrchr(progname,'.')) != NULL)
+			*tptr = CNULL;
+		curarg = curopt = 1;
+		}
+    if (!done && (argv[curarg] != NULL) && (*argv[curarg] == MINUS))
+        {
+        if ((curopt == 1) && (argv[curarg][curopt] == MINUS))
+			{
+			curarg++;
+			curopt = 1;
+			done = TRUE;
+			}
+        else if ((tptr = strchr(optstring,argv[curarg][curopt])) != NULL)
+            {
+            curopt++;
+            if (*(tptr+1) == COLON)
+                {
+                if (argv[curarg][curopt] == CNULL)
+                    {
+                    curarg++;
+                    optarg = argv[curarg];
+                    curarg++;
+                    curopt = 1;
+                    }
+                else
+                    {
+                    optarg = &argv[curarg][curopt];
+                    curarg++;
+                    curopt = 1;
+                    }
+                }
+			else
+				{
+				if (argv[curarg][curopt] == CNULL)
+					{
+					curarg++;
+					curopt = 1;
+					}
+				optarg = NULL;
+				}
+			return((int)*tptr);
+			}
+		else
+			{
+			fprintf(stderr,"%s: illegal option -- %c\n",progname,argv[curarg][curopt]);
+			curopt++;
+			if (argv[curarg][curopt] == CNULL)
+				{
+				curarg++;
+				curopt = 1;
+				}
+			optarg = NULL;
+			return((int)QUESTION);
+			}
+		}
+	else
+		done = TRUE;
+	
+	optind = curarg;
+	optarg = NULL;
+	return(EOF);
+}
+                
+/*****************************************************************************
+**
+**	Programming Example: (taken from AT&T's Internal UNIX System Calls
+**							class manual, pages 2.1.4 through 2.1.12)
+**
+***********
+**
+**	#define MODNAME "test"
+**
+**	#include <stdio.h>
+**	
+**	extern char *optarg;
+**	extern int optind;
+**	
+**	main(argc,argv)
+**	int argc;
+**	char **argv;
+**	{
+**		int getopt(),c;
+**		static char options[] = "adf:g:";
+**		int n, invalid = 0, a_ind = 0, d_ind = 0;
+**		char *f_ptr = NULL, *g_ptr = NULL;
+**	
+**		printf("argc contains %d\n",argc);
+**		printf("argv contains %0X\n\n",argv);
+**	
+**		while ((c = getopt(argc,argv,options)) != EOF)
+**			switch(c)
+**				{
+**				case 'a':
+**					{
+**					a_ind++;
+**					break;
+**					}
+**				case 'd':
+**					{
+**					d_ind++;
+**					break;
+**					}
+**				case 'f':
+**					{
+**					f_ptr = optarg;
+**					break;
+**					}
+**				case 'g':
+**					{
+**					g_ptr = optarg;
+**					break;
+**					}
+**				case '?':
+**					invalid++;
+**				}
+**		printf("argc contains %d\n",argc);
+**		printf("argv contains %0X\n",argv);
+**		printf("a_ind contains %d\n",a_ind);
+**		printf("d_ind contains %d\n",d_ind);
+**		printf("f_ptr points to %s\n",f_ptr);
+**		printf("g_ptr points to %s\n",g_ptr);
+**		printf("invalid contains %d\n",invalid);
+**		printf("optind contains %d\n",optind);
+**		for (;optind < argc;optind++)
+**			printf("next parameter[%d] = %s\n",optind,argv[optind]);
+**		return;
+**	}
+**
+***********
+**
+**	Invoke this example with:
+**
+**		C>test -abcfabc -g hij -a file1 file2<CR>
+**
+**	Output:
+**
+**		argc contains 7
+**		argv contains FD0
+**	
+**		TEST: illegal option -- b
+**		TEST: illegal option -- c
+**		argc contains 7
+**		argv contains FD0
+**		a_ind contains 2
+**		d_ind contains 0
+**		f_ptr points to abc
+**		g_ptr points to hij
+**		invalid contains 2
+**		optind contains 5
+**		next parameter[5] = file1
+**		next parameter[6] = file2
+**
+*****************************************************************************/
diff --git a/hsefi/HSEFI.BAS b/hsefi/HSEFI.BAS
new file mode 100644
index 0000000..4c43c2c
--- /dev/null
+++ b/hsefi/HSEFI.BAS
@@ -0,0 +1,120 @@
+10 REM Last Modified 8/4/2000
+40 OPEN "I",1,"C:\ETC\HSEDATA.DAT"
+50 INPUT#1,R,U,C,I,F,G,P,A,D,H,Z,S,M1,M2,A1,D1,W,S1,M3,Y
+60 CLOSE 1
+70 PRINT "INITIALIZE VALUES FOR BEGINING OF NEW MONTH Y/N";:INPUT A$
+80 IF A$="Y" GOTO 570
+90 IF A$="N" GOTO 110
+100 GOTO 70
+110 GOSUB 3000
+220 GOSUB 1090
+230 PRINT USING "REMAINING INCOME: ######.##";Y;:PRINT USING"     REMAINING FREE FUNDS:######.##";B
+240 PRINT
+250 PRINT"ANY BILLS PAID OR EXTRA INCOME TO ENTER Y/N";:INPUT B$
+260 IF B$="Y" GOTO 600
+270 IF B$="N" GOTO 300
+280 GOTO 250
+290 PRINT
+300 GOSUB 3000
+420 GOSUB 1090
+430 PRINT USING "REMAINING INCOME: ######.##";Y;:PRINT USING"     REMAINING FREE FUNDS: ######.##";B
+440 PRINT
+450 PRINT"DO WISH TO CHANGE VALUES ANY FURTHER? Y/N";:INPUT Z$
+460 IF Z$="Y" GOTO 600
+470 IF Z$="N" GOTO 490
+480 GOTO 880
+490 PRINT"TYPE P FOR HARD-COPY OR C TO CONTINUE"
+500 IF INKEY$="P" GOTO 530
+510 IF INKEY$="C" GOTO 540
+520 GOTO 500
+530 GOSUB 1110
+540 OPEN "O",1,"C:\ETC\HSEDATA.DAT":PRINT#1,R,U,C,I,F,G,P,A,D,H,Z,S,M1,M2,A1,D1,W,S1,M3,Y:CLOSE 1
+550 END
+560 END
+570 R=R+2225.00:Y=Y+2000.00
+580 GOTO 110
+590 END
+600 PRINT"ENTER CATEGORY AND AMOUNT": :PRINT:PRINT"NOTE:VALUE IS ADDED TO INCOME, BUT SUBTRACTED FROM BILL.":PRINT
+610 INPUT C$
+620 INPUT A5
+630 IF C$="Rent" GOTO 840
+640 IF C$="Utilities" GOTO 850
+650 IF C$="Car" GOTO 860
+660 IF C$="Extra1" GOTO 870
+670 IF C$="Food" GOTO 880
+680 IF C$="Gas" GOTO 890
+690 IF C$="Phone" GOTO 900
+700 IF C$="Extra2"GOTO 910
+710 IF C$="Savings" GOTO 920
+720 IF C$="Extra4" GOTO 930
+730 IF C$="Chris" GOTO 940
+740 IF C$="Extra9" GOTO 950
+750 IF C$="Extra6" GOTO 960
+760 IF C$="Extra8" GOTO 970
+770 IF C$="Extra3" GOTO 980
+780 IF C$="Meadows" GOTO 990
+790 IF C$="Extra5" GOTO 1000
+800 IF C$ ="Extra7" GOTO 1010
+810 IF C$="Credit Cards" GOTO 1020
+820 IF C$="Income" GOTO 1030
+830 PRINT "ILLEGAL CATEGORY---REDO":PRINT:GOTO 250
+840 R=R-A5:GOSUB 1050:PRINT"REMAINING Rent:"R:GOTO 250
+850 U=U-A5:GOSUB 1050:PRINT "REMAINING Utilities:"U: GOTO 250
+860 C=C-A5:GOSUB 1050:PRINT "REMAINING Car Payment"C: GOTO 250
+870 I=I-A5:GOSUB 1050:PRINT "REMAINING Extra1:"I: GOTO 250
+880 F=F-A5:GOSUB 1050:PRINT"REMAINING Food:"F:GOTO 250
+890 G=G-A5:GOSUB 1050:PRINT"REMAINING Gas:"G:GOTO 250
+900 P=P-A5:GOSUB 1050:PRINT"REMAINING Phone:"P:GOTO 250
+910 A=A-A5:GOSUB 1050:PRINT"REMAINING Extra2:"A:GOTO 250
+920 D=D-A5:GOSUB 1050:PRINT"REMAINING Savings:"D:GOTO 250
+930 H=H-A5:GOSUB 1050:PRINT"REMAINING Extra4:"H:GOTO 250
+940 Z=Z-A5:GOSUB 1050:PRINT"REMAINING DUE Chris:"Z:GOTO 250
+950 S=S-A5:GOSUB 1050:PRINT"REMAINING Savings:"S:GOTO 250
+960 M1=M1-A5:GOSUB 1050:PRINT"REMAINING Extra6:"M1:GOTO 250
+970 M2=M2-A5:GOSUB 1050:PRINT"REMAINING Extra8:"M2:GOTO 250
+980 A1=A1-A5:GOSUB 1050:PRINT"REMAINING Extra3:"A1:GOTO 250
+990 D1=D1-A5:GOSUB 1050:PRINT"REMAINING Meadows:"D1:GOTO 250
+1000 W=W-A5:GOSUB 1050:PRINT"REMAINING Extra5:"W:GOTO 250
+1010 S1=S1-A5:GOSUB 1050:PRINT"REMAINING Extra7:"S1:GOTO 250
+1020 M3=M3-A5:GOSUB 1050:PRINT"REMAINING Credit Cards:"M3:GOTO 250
+1030 Y=Y+A5:PRINT"REMAINING INCOME:"Y:GOTO 250
+1040 END
+1050 Q=SGN(A5)
+1060 IF Q=-1 THEN RETURN
+1070 Y=Y-A5
+1080 RETURN
+1090 T=R+U+C+I+F+G+P+A+D+H
+1091 T=T+Z+S+M1+M2+A1+D1+W+S1+M3:B=Y-T:RETURN
+1100 END
+1110 LPRINT:LPRINT"PRESENT VALUES ARE:"
+1120 LPRINT ,"Rent",R,"Chris",Z
+1130 LPRINT ,"Credit Cards",M3,"Savings",D
+1140 LPRINT ,"Meadows",D1,"Car",C
+1150 LPRINT ,"Utilities",U,"Food",F
+1160 LPRINT ,"Gas",G,"Phone",P
+1170 LPRINT ,"Extra1",I,"Extra2",A
+1180 LPRINT ,"Extra3",A1,"Extra4",H
+1190 LPRINT ,"Extra5",W,"Extra6",M1
+1200 LPRINT ,"Extra7",S1,"Extra8",M2
+1210 LPRINT ,"Extra9",S
+1220 LPRINT
+1230 GOSUB 1090
+1240 LPRINT USING "REMAINING INCOME: ######.##";Y;:LPRINT USING"     REMAINING FREE FUNDS: ######.##";B
+1250 LPRINT
+1260 LPRINT DATE$:LPRINT TIME$
+1270 LPRINT CHR$(12);
+1280 RETURN
+3000 CLS:PRINT ,"HOME FINANCE","     DISK VERSION 1.6", "August 4, 2000":PRINT ,"****************************************************************":PRINT
+3010 PRINT ,"Rent",R,"Chris",Z
+3020 PRINT ,"Credit Cards",M3,"Savings",D
+3030 PRINT ,"Meadows",D1,"Car",C
+3040 PRINT ,"Utilities",U,"Food",F
+3045 PRINT ,"Gas",G,"Phone",P
+3050 PRINT ,"Extra1",I,"Extra2",A
+3055 PRINT ,"Extra3",A1,"Extra4",H
+3060 PRINT ,"Extra5",W,"Extra6",M1
+3065 PRINT ,"Extra7",S1,"Extra8",M2
+3070 PRINT ,"Extra9",S
+3080 PRINT
+3090 RETURN
+4000 END
diff --git a/hsefi/HSEFI.EXE b/hsefi/HSEFI.EXE
new file mode 100644
index 0000000..e440217
--- /dev/null
+++ b/hsefi/HSEFI.EXE
Binary files differ
diff --git a/hsefi/HSEFI.LST b/hsefi/HSEFI.LST
new file mode 100644
index 0000000..6ed7812
--- /dev/null
+++ b/hsefi/HSEFI.LST
@@ -0,0 +1,153 @@
+                                                                      PAGE   1
+                                                                      04 Aug 00
+                                                                      18:14:18
+Offset  Data    Source Line     Microsoft (R) QuickBASIC Compiler  Version 4.00
+
+ 0030   0006    10 REM Last Modified 8/4/2000
+ 0030   0006    40 OPEN "I",1,"C:\ETC\HSEDATA.DAT"
+ 0045   0006    50 INPUT#1,R,U,C,I,F,G,P,A,D,H,Z,S,M1,M2,A1,D1,W,S1,M3,Y
+ 0143   0056    60 CLOSE 1
+ 014D   0056    70 PRINT "INITIALIZE VALUES FOR BEGINING OF NEW MONTH Y/N";:INP
+                UT A$
+ 0180   005A    80 IF A$="Y" GOTO 570
+ 0195   005A    90 IF A$="N" GOTO 110
+ 01AA   005A    100 GOTO 70
+ 01AC   005A    110 GOSUB 3000
+ 01B4   005A    220 GOSUB 1090
+ 01BC   005A    230 PRINT USING "REMAINING INCOME: ######.##";Y;:PRINT USING"  
+                   REMAINING FREE FUNDS:######.##";B
+ 01ED   005E    240 PRINT
+ 01F6   005E    250 PRINT"ANY BILLS PAID OR EXTRA INCOME TO ENTER Y/N";:INPUT B
+                $
+ 0229   0062    260 IF B$="Y" GOTO 600
+ 023E   0062    270 IF B$="N" GOTO 300
+ 0253   0062    280 GOTO 250
+ 0255   0062    290 PRINT
+ 025E   0062    300 GOSUB 3000
+ 0266   0062    420 GOSUB 1090
+ 026E   0062    430 PRINT USING "REMAINING INCOME: ######.##";Y;:PRINT USING"  
+                   REMAINING FREE FUNDS: ######.##";B
+ 029F   0062    440 PRINT
+ 02A8   0062    450 PRINT"DO WISH TO CHANGE VALUES ANY FURTHER? Y/N";:INPUT Z$
+ 02DB   0066    460 IF Z$="Y" GOTO 600
+ 02F0   0066    470 IF Z$="N" GOTO 490
+ 0305   0066    480 GOTO 880
+ 0308   0066    490 PRINT"TYPE P FOR HARD-COPY OR C TO CONTINUE"
+ 0311   0066    500 IF INKEY$="P" GOTO 530
+ 0328   0066    510 IF INKEY$="C" GOTO 540
+ 033F   0066    520 GOTO 500
+ 0341   0066    530 GOSUB 1110
+ 0349   0066    540 OPEN "O",1,"C:\ETC\HSEDATA.DAT":PRINT#1,R,U,C,I,F,G,P,A,D,H
+                ,Z,S,M1,M2,A1,D1,W,S1,M3,Y:CLOSE 1
+ 0475   0066    550 END
+ 047A   0066    560 END
+ 047F   0066    570 R=R+2225.00:Y=Y+2000.00
+ 04A1   0066    580 GOTO 110
+ 04A4   0066    590 END
+ 04A9   0066    600 PRINT"ENTER CATEGORY AND AMOUNT": :PRINT:PRINT"NOTE:VALUE I
+                S ADDED TO INCOME, BUT SUBTRACTED FROM BILL.":PRINT
+ 04CD   0066    610 INPUT C$
+ 04F7   006A    620 INPUT A5
+ 0520   006E    630 IF C$="Rent" GOTO 840
+ 0535   006E    640 IF C$="Utilities" GOTO 850
+ 054A   006E    650 IF C$="Car" GOTO 860
+ 055F   006E    660 IF C$="Extra1" GOTO 870
+ 0574   006E    670 IF C$="Food" GOTO 880
+ 0589   006E    680 IF C$="Gas" GOTO 890
+ 059E   006E    690 IF C$="Phone" GOTO 900
+ 05B3   006E    700 IF C$="Extra2"GOTO 910
+ 05C8   006E    710 IF C$="Savings" GOTO 920
+                                                                      PAGE   2
+                                                                      04 Aug 00
+                                                                      18:14:18
+Offset  Data    Source Line     Microsoft (R) QuickBASIC Compiler  Version 4.00
+
+ 05DD   006E    720 IF C$="Extra4" GOTO 930
+ 05F2   006E    730 IF C$="Chris" GOTO 940
+ 0607   006E    740 IF C$="Extra9" GOTO 950
+ 061C   006E    750 IF C$="Extra6" GOTO 960
+ 0631   006E    760 IF C$="Extra8" GOTO 970
+ 0646   006E    770 IF C$="Extra3" GOTO 980
+ 065B   006E    780 IF C$="Meadows" GOTO 990
+ 0670   006E    790 IF C$="Extra5" GOTO 1000
+ 0685   006E    800 IF C$ ="Extra7" GOTO 1010
+ 069A   006E    810 IF C$="Credit Cards" GOTO 1020
+ 06AF   006E    820 IF C$="Income" GOTO 1030
+ 06C4   006E    830 PRINT "ILLEGAL CATEGORY---REDO":PRINT:GOTO 250
+ 06D9   006E    840 R=R-A5:GOSUB 1050:PRINT"REMAINING Rent:"R:GOTO 250
+ 070B   006E    850 U=U-A5:GOSUB 1050:PRINT "REMAINING Utilities:"U: GOTO 250
+ 073D   006E    860 C=C-A5:GOSUB 1050:PRINT "REMAINING Car Payment"C: GOTO 250
+ 076F   006E    870 I=I-A5:GOSUB 1050:PRINT "REMAINING Extra1:"I: GOTO 250
+ 07A1   006E    880 F=F-A5:GOSUB 1050:PRINT"REMAINING Food:"F:GOTO 250
+ 07D3   006E    890 G=G-A5:GOSUB 1050:PRINT"REMAINING Gas:"G:GOTO 250
+ 0805   006E    900 P=P-A5:GOSUB 1050:PRINT"REMAINING Phone:"P:GOTO 250
+ 0837   006E    910 A=A-A5:GOSUB 1050:PRINT"REMAINING Extra2:"A:GOTO 250
+ 0869   006E    920 D=D-A5:GOSUB 1050:PRINT"REMAINING Savings:"D:GOTO 250
+ 089B   006E    930 H=H-A5:GOSUB 1050:PRINT"REMAINING Extra4:"H:GOTO 250
+ 08CD   006E    940 Z=Z-A5:GOSUB 1050:PRINT"REMAINING DUE Chris:"Z:GOTO 250
+ 08FF   006E    950 S=S-A5:GOSUB 1050:PRINT"REMAINING Savings:"S:GOTO 250
+ 0931   006E    960 M1=M1-A5:GOSUB 1050:PRINT"REMAINING Extra6:"M1:GOTO 250
+ 0963   006E    970 M2=M2-A5:GOSUB 1050:PRINT"REMAINING Extra8:"M2:GOTO 250
+ 0995   006E    980 A1=A1-A5:GOSUB 1050:PRINT"REMAINING Extra3:"A1:GOTO 250
+ 09C7   006E    990 D1=D1-A5:GOSUB 1050:PRINT"REMAINING Meadows:"D1:GOTO 250
+ 09F9   006E    1000 W=W-A5:GOSUB 1050:PRINT"REMAINING Extra5:"W:GOTO 250
+ 0A2B   006E    1010 S1=S1-A5:GOSUB 1050:PRINT"REMAINING Extra7:"S1:GOTO 250
+ 0A5D   006E    1020 M3=M3-A5:GOSUB 1050:PRINT"REMAINING Credit Cards:"M3:GOTO 
+                250
+ 0A8F   006E    1030 Y=Y+A5:PRINT"REMAINING INCOME:"Y:GOTO 250
+ 0AB9   006E    1040 END
+ 0ABE   006E    1050 Q=SGN(A5)
+ 0AD1   0072    1060 IF Q=-1 THEN RETURN
+ 0AEC   0072    1070 Y=Y-A5
+ 0AFD   0072    1080 RETURN
+ 0B02   0072    1090 T=R+U+C+I+F+G+P+A+D+H
+ 0B3B   0076    1091 T=T+Z+S+M1+M2+A1+D1+W+S1+M3:B=Y-T:RETURN
+ 0B8A   0076    1100 END
+ 0B8F   0076    1110 LPRINT:LPRINT"PRESENT VALUES ARE:"
+ 0BAB   0076    1120 LPRINT ,"Rent",R,"Chris",Z
+ 0BE5   0076    1130 LPRINT ,"Credit Cards",M3,"Savings",D
+ 0C1F   0076    1140 LPRINT ,"Meadows",D1,"Car",C
+ 0C59   0076    1150 LPRINT ,"Utilities",U,"Food",F
+ 0C93   0076    1160 LPRINT ,"Gas",G,"Phone",P
+ 0CCD   0076    1170 LPRINT ,"Extra1",I,"Extra2",A
+ 0D07   0076    1180 LPRINT ,"Extra3",A1,"Extra4",H
+ 0D41   0076    1190 LPRINT ,"Extra5",W,"Extra6",M1
+ 0D7B   0076    1200 LPRINT ,"Extra7",S1,"Extra8",M2
+ 0DB5   0076    1210 LPRINT ,"Extra9",S
+ 0DD9   0076    1220 LPRINT
+ 0DE7   0076    1230 GOSUB 1090
+                                                                      PAGE   3
+                                                                      04 Aug 00
+                                                                      18:14:18
+Offset  Data    Source Line     Microsoft (R) QuickBASIC Compiler  Version 4.00
+
+ 0DEF   0076    1240 LPRINT USING "REMAINING INCOME: ######.##";Y;:LPRINT USING
+                "     REMAINING FREE FUNDS: ######.##";B
+ 0E2A   0076    1250 LPRINT
+ 0E38   0076    1260 LPRINT DATE$:LPRINT TIME$
+ 0E58   0076    1270 LPRINT CHR$(12);
+ 0E71   0076    1280 RETURN
+ 0E76   0076    3000 CLS:PRINT ,"HOME FINANCE","     DISK VERSION 1.6", "August
+                 4, 2000":PRINT ,"*********************************************
+                *******************":PRINT
+ 0EBE   0076    3010 PRINT ,"Rent",R,"Chris",Z
+ 0EF3   0076    3020 PRINT ,"Credit Cards",M3,"Savings",D
+ 0F28   0076    3030 PRINT ,"Meadows",D1,"Car",C
+ 0F5D   0076    3040 PRINT ,"Utilities",U,"Food",F
+ 0F92   0076    3045 PRINT ,"Gas",G,"Phone",P
+ 0FC7   0076    3050 PRINT ,"Extra1",I,"Extra2",A
+ 0FFC   0076    3055 PRINT ,"Extra3",A1,"Extra4",H
+ 1031   0076    3060 PRINT ,"Extra5",W,"Extra6",M1
+ 1066   0076    3065 PRINT ,"Extra7",S1,"Extra8",M2
+ 109B   0076    3070 PRINT ,"Extra9",S
+ 10BA   0076    3080 PRINT
+ 10C3   0076    3090 RETURN
+ 10C8   0076    4000 END
+ 10CD   0076    
+ 1468   0076    
+
+43052 Bytes Available
+38532 Bytes Free
+
+    0 Warning Error(s)
+    0 Severe  Error(s)
diff --git a/hsefi/HSEFI.MAP b/hsefi/HSEFI.MAP
new file mode 100644
index 0000000..d744144
--- /dev/null
+++ b/hsefi/HSEFI.MAP
@@ -0,0 +1,55 @@
+
+ Start  Stop   Length Name                   Class
+ 00000H 01467H 01468H HSEFI_CODE             BC_CODE
+ 01470H 02071H 00C02H _TEXT                  CODE
+ 02072H 07BA0H 05B2FH CODE                   CODE
+ 07BA2H 07BF7H 00056H TERM_CODE              CODE
+ 07BF8H 07E73H 0027CH INIT_CODE              CODE
+ 07E80H 0A194H 02315H EMULATOR_TEXT          CODE
+ 0A196H 0A196H 00000H C_ETEXT                ENDCODE
+ 0A196H 0A19DH 00008H FAR_HDR                FAR_MSG
+ 0A19EH 0A88BH 006EEH FAR_MSG                FAR_MSG
+ 0A88CH 0A88DH 00002H FAR_PAD                FAR_MSG
+ 0A88EH 0A88EH 00001H FAR_EPAD               FAR_MSG
+ 0A890H 0A9AFH 00120H EMULATOR_DATA          FAR_DATA
+ 0A9B0H 0A9B0H 00000H BR_DATA                BLANK
+ 0A9B0H 0A9DFH 00030H BR_SKYS                BLANK
+ 0A9E0H 0A9E0H 00000H COMMON                 BLANK
+ 0A9E0H 0AA55H 00076H BC_DATA                BC_VARS
+ 0AA56H 0AA5BH 00006H NMALLOC                BC_VARS
+ 0AA5CH 0AA5CH 00000H ENMALLOC               BC_VARS
+ 0AA5CH 0AA5CH 00000H BC_FT                  BC_SEGS
+ 0AA60H 0AF57H 004F8H BC_CN                  BC_SEGS
+ 0AF60H 0AF62H 00003H BC_DS                  BC_SEGS
+ 0AF64H 0AF64H 00000H BC_SAB                 BC_SEGS
+ 0AF64H 0AF6BH 00008H BC_SA                  BC_SEGS
+ 0AF6CH 0B287H 0031CH _DATA                  DATA
+ 0B288H 0B295H 0000EH CDATA                  DATA
+ 0B296H 0B296H 00000H XIFB                   DATA
+ 0B296H 0B296H 00000H XIF                    DATA
+ 0B296H 0B296H 00000H XIFE                   DATA
+ 0B296H 0B296H 00000H XIB                    DATA
+ 0B296H 0B2B5H 00020H XI                     DATA
+ 0B2B6H 0B2B6H 00000H XIE                    DATA
+ 0B2B6H 0B2B6H 00000H XPB                    DATA
+ 0B2B6H 0B2B6H 00000H XP                     DATA
+ 0B2B6H 0B2B6H 00000H XPE                    DATA
+ 0B2B6H 0B2B6H 00000H XCB                    DATA
+ 0B2B6H 0B2B9H 00004H XC                     DATA
+ 0B2BAH 0B2BAH 00000H XCE                    DATA
+ 0B2BAH 0B2BAH 00000H XCFB                   DATA
+ 0B2BAH 0B2BAH 00000H XCF                    DATA
+ 0B2BAH 0B2BAH 00000H XCFE                   DATA
+ 0B2BAH 0B667H 003AEH _BSS                   DATA
+ 0B668H 0B762H 000FBH BR_DATA                DATA
+ 0B764H 0B811H 000AEH CONST                  DATA
+ 0B812H 0B812H 00000H XOB                    BSS
+ 0B812H 0B812H 00000H XO                     BSS
+ 0B812H 0B812H 00000H XOE                    BSS
+ 0B820H 0C01FH 00800H STACK                  STACK
+
+ Origin   Group
+ 0A9B:0   DGROUP
+ 0A19:0   FMGROUP
+
+Program entry point at 0147:0010
diff --git a/hsefi/HSEFI.OBJ b/hsefi/HSEFI.OBJ
new file mode 100644
index 0000000..03b8dce
--- /dev/null
+++ b/hsefi/HSEFI.OBJ
Binary files differ
diff --git a/ice/BKU b/ice/BKU
new file mode 100644
index 0000000..2b90861
--- /dev/null
+++ b/ice/BKU
@@ -0,0 +1 @@
+c:\msc\ice\*.*/S/V
diff --git a/ice/BKU.BAT b/ice/BKU.BAT
new file mode 100644
index 0000000..e17ef43
--- /dev/null
+++ b/ice/BKU.BAT
@@ -0,0 +1,4 @@
+del c:\fastback\fastback.cat
+c:\fastback\fastback @bku
+c:\fastback\fastback @bku
+
diff --git a/ice/CVALID.DOC b/ice/CVALID.DOC
new file mode 100644
index 0000000..ef1378b
--- /dev/null
+++ b/ice/CVALID.DOC
@@ -0,0 +1,25 @@
+
+
+
+
+                     IceScreen Character Validation Codes
+                     ====================================
+
+     Character      Meaning                 Accepted Characters
+     =========      =======                 ===================
+
+
+        x           Any entry valid         All
+        a           Alphabetic Only         (A-Z, a-z)
+        n           Alphanumeric Only       (A-Z, a-z, 0-9)
+        b           Binary Digits           (0, 1)
+        o           Octal Digits            (0-7)
+        d           Decimal Digits          (0-9)
+        h           Hexadecimal Digits      (0-9, A-F, a-f)
+        f           Floating Point Digits   (0-9, +, -, .)
+        s           Scientific Digits       (0-9, +, -, ., E, e)
+        $           Financial Digits        (0-9, +, -, ., $)
+        
+        0-9         Pointer To Literal Character Lists
+        
+        p           Protected Literal Character
diff --git a/ice/DICE b/ice/DICE
new file mode 100644
index 0000000..5c534d6
--- /dev/null
+++ b/ice/DICE
@@ -0,0 +1,27 @@
+#     ICE - Make File For IceScreen V1.D, PCDOS, BIOS Version
+#           Copyright (c) 1988, 1989, 1990 by T.A. Daneliuk
+#           Last Modified: 06-13-90
+
+#                   ******************************
+#                   ****** DEBUGGING VERSION *****
+#                   ******************************
+
+
+# -----------------------------------------------------------------------------
+# Dependency Lists
+# -----------------------------------------------------------------------------
+
+$(model)\dicelogd.obj: ice_logd.c ice_defs.h
+    cl /A$(cmodel) /Od /Zi /c /V"IceScreen V1.D Copyright (c) 1988, 1989, 1990 TundraWare" /Fo$(model)\dicelogd.OBJ ice_logd.C
+    lib ice_libs\d_$(cmodel)_ice.LIB -+$(model)\$*.OBJ; 
+
+$(model)\dicekeyi.obj: ice_keyi.c ice_defs.h
+    cl /A$(cmodel) /Od /Zi /c /V"IceScreen V1.D Copyright (c) 1988, 1989, 1990 TundraWare" /Fo$(model)\dicekeyi.OBJ ice_keyi.C
+    lib ice_libs\d_$(cmodel)_ice.LIB -+$(model)\$*.OBJ; 
+
+$(model)\dicefedi.obj: ice_fedi.c ice_defs.h
+    cl /A$(cmodel) /Od /Zi /c /V"IceScreen V1.D Copyright (c) 1988, 1989, 1990 TundraWare" /Fo$(model)\dicefedi.OBJ ice_fedi.c
+    lib ice_libs\d_$(cmodel)_ice.LIB -+$(model)\$*.OBJ; 
+
+
+
diff --git a/ice/DICE.BAT b/ice/DICE.BAT
new file mode 100644
index 0000000..1168632
--- /dev/null
+++ b/ice/DICE.BAT
@@ -0,0 +1,7 @@
+echo off
+make model=SMALL   cmodel=S dice 
+make model=MEDIUM  cmodel=M dice 
+make model=COMPACT cmodel=C dice 
+make model=LARGE   cmodel=L dice 
+make model=HUGE    cmodel=H dice 
+
diff --git a/ice/HUGE/DICEFEDI.OBJ b/ice/HUGE/DICEFEDI.OBJ
new file mode 100644
index 0000000..e46ba89
--- /dev/null
+++ b/ice/HUGE/DICEFEDI.OBJ
Binary files differ
diff --git a/ice/HUGE/DICEKEYI.OBJ b/ice/HUGE/DICEKEYI.OBJ
new file mode 100644
index 0000000..8f1f2eb
--- /dev/null
+++ b/ice/HUGE/DICEKEYI.OBJ
Binary files differ
diff --git a/ice/HUGE/DICELOGD.OBJ b/ice/HUGE/DICELOGD.OBJ
new file mode 100644
index 0000000..94c03f7
--- /dev/null
+++ b/ice/HUGE/DICELOGD.OBJ
Binary files differ
diff --git a/ice/HUGE/ICE_KEYI.OBJ b/ice/HUGE/ICE_KEYI.OBJ
new file mode 100644
index 0000000..03e8b58
--- /dev/null
+++ b/ice/HUGE/ICE_KEYI.OBJ
Binary files differ
diff --git a/ice/HUGE/ICE_LOGD.OBJ b/ice/HUGE/ICE_LOGD.OBJ
new file mode 100644
index 0000000..7ca5722
--- /dev/null
+++ b/ice/HUGE/ICE_LOGD.OBJ
Binary files differ
diff --git a/ice/ICE b/ice/ICE
new file mode 100644
index 0000000..a1e11cf
--- /dev/null
+++ b/ice/ICE
@@ -0,0 +1,20 @@
+#     ICE - Make File For IceScreen V1.0, PCDOS, BIOS Version
+#           Copyright (c) 1988, 1989, 1990, By T.A. Daneliuk
+#           Last Modified: 06-13-90
+
+
+
+
+
+# -----------------------------------------------------------------------------
+# Dependency Lists
+# -----------------------------------------------------------------------------
+
+$(model)\ice_logd.obj: ice_logd.c ice_defs.h
+    cl /A$(cmodel) /Ot /c /V"IceScreen V1.1 Copyright (c) 1988, 1989, 1990 TundraWare" /Fo$(model)\$*.OBJ $*.C
+    lib ice_libs\$(cmodel)_ice.LIB -+$(model)\$*.OBJ; 
+
+$(model)\ice_keyi.obj: ice_keyi.c ice_defs.h
+    cl /A$(cmodel) /Ot /c /V"IceScreen V1.1 Copyright (c) 1988, 1989, 1990 TundraWare" /Fo$(model)\$*.OBJ $*.C
+    lib ice_libs\$(cmodel)_ice.LIB -+$(model)\$*.OBJ; 
+
diff --git a/ice/ICE.BAT b/ice/ICE.BAT
new file mode 100644
index 0000000..61b6a95
--- /dev/null
+++ b/ice/ICE.BAT
@@ -0,0 +1,7 @@
+echo off
+make model=SMALL   cmodel=S ice 
+make model=MEDIUM  cmodel=M ice 
+make model=COMPACT cmodel=C ice 
+make model=LARGE   cmodel=L ice 
+make model=HUGE    cmodel=H ice 
+
diff --git a/ice/ICE_DEFS.H b/ice/ICE_DEFS.H
new file mode 100644
index 0000000..7cb5a92
--- /dev/null
+++ b/ice/ICE_DEFS.H
@@ -0,0 +1,254 @@
+/*  ICE_DEFS.H -    IceScreen Definitions, Global Variables, Etc.
+
+                    Last Modified: 06-06-90
+                    Copyright (C) 1988, 1989, 1990 by T.A. Daneliuk
+*/
+
+
+/*========================== DEBUGGING OPTIONS ===============================*/
+
+#define     DEBUG       0                   /* Set To 1 To Enable Debugging   */
+
+
+/*=========================== PROGRAM DEFINITIONS ============================*/
+
+#define	PROGNAME       "IceScreen"
+#define	VERSION        "1.1"
+
+/*============================= COMPILER =====================================*/
+
+#define     MSC         1                   /* Microsoft C                    */
+#define     TURBO       0                   /* Borland TurboC                 */
+#define     PCCV        0                   /* UNIX System V Compiler         */
+#define     PCCB        0                   /* UNIX BSD 4.x Compiler          */
+#define     ANSI        1                   /* Compiler is ANSI Compliant     */
+
+
+/*========================= PRESENTATION SERVICE =============================*/
+
+#define     PC_BIOS     1                   /* IBM-PC Via Standard Bios       */
+#define     PC_WIND     0                   /* IBM-PC Via MS-Windows          */
+#define     PC_OSPM     0                   /* OS/2 Presentation Manager      */
+#define     CURSES      0                   /* UNIX Curses                    */
+#define     XWINDOWS    0                   /* Generic X-Windows              */
+
+/*========================== OPERATING SYSTEM ================================*/
+
+#define     PCDOS       1                   /* Standard PC-DOS                */
+#define     OS_2        0                   /* OS/2                           */
+#define     UNIXV       0                   /* UNIX System V.x                */
+#define     UNIXB       0                   /* UNIX BSD 4.x                   */
+
+
+/*=============== MISC. CONSTANTS DEFINITIONS & TYPEDEFS =====================*/
+
+#define     FALSE       0
+#define     TRUE        !FALSE
+
+#ifndef     BOOL 
+typedef     int         BOOL;               /* Boolean Datatype               */
+#endif
+
+#if     PCDOS & PC_BIOS
+
+#define                 CUROFF              32,7        /* Cursor Settings    */
+#define                 CURSML              6,7
+#define                 CURBLK              0,7
+
+typedef        short    VCOORD;             /* Screen Coordinates             */
+typedef        short    VATRB;              /* Video Attribute                */
+typedef        short    VMODE;              /* Video Mode                     */
+typedef        short    VPAGE;              /* Video Page                     */
+typedef unsigned char   KEYSTR;             /* Keystroke                      */
+typedef unsigned int    VALCODE;            /* Character Validation Code      */
+typedef unsigned char   ICE_ERROR;          /* Internal Error Code            */
+typedef unsigned char   F_TYPE;             /* Field Type Codes               */
+typedef int             FLEN;               /* Field Length                   */
+
+#endif
+
+
+/*=================== SCREEN AND FIELD CONTROL STRUCTURES ====================*/
+
+
+struct ICE_FIELD                        /* FIELD Control Structure */
+{
+        /* Members Common Top Both Prompt And Response Field Types */
+
+        F_TYPE      ftype;              /* Field Type                         */
+        VCOORD      frow;               /* Field Vertical Position            */
+        VCOORD      fcol;               /* Field Horizontal Position          */
+        VATRB       fattrib;            /* Field Display Colors/Attributes    */
+        KEYSTR      * field;            /* Array Containing Field Contents    */
+
+
+
+                   /* Members Response Field Screen Control */
+
+        FLEN        rlen;               /* Maximum Allowed User Response Len. */
+        VATRB       rattrib;            /* Input Colors/Attributes            */
+        VATRB       cattrib;            /* Attribute To Use When Clearing     */
+        KEYSTR      rfill;              /* Keyin Time Fill Character          */
+        KEYSTR      rclear;             /* Character To Use When Clearing     */
+
+                   /* Members For Single Character Validation */
+
+        BOOL        rspace;             /* TRUE Allows Blanks In Response     */
+        KEYSTR      * mask;             /* Character Validation Mask          */
+        KEYSTR      ** v_lists;         /* Array Of Char. Val. Strings        */
+
+
+  /* Members For Full Field Validation, Error Handling, Help, And  Autoskip */
+
+        BOOL        rmustfill;          /* TRUE Means Field Must Be Filled    */
+        BOOL        rreqd;              /* TRUE Means A Response Is Required  */
+#if ANSI
+        char        *(*rvalid) (struct ICE_FIELD *x);        /* See Below     */
+        void        (*flderr) (struct ICE_FIELD *x, ICE_ERROR y, char *z);
+#else
+        char        *(*rvalid) ();      /* Whole Field Validation Function    */
+        void        (*flderr) ();       /* Pointer To Error Handler           */
+#endif
+
+        struct      ICE_SCRN *rhelp;    /* Pointer To Help Screen Structure   */
+        BOOL        rskp;               /* TRUE Means Autoskip On             */
+};
+
+
+struct ICE_SCRN                         /* SCREEN Control Structure */
+{
+        void        (* before) ();      /* Do This Before Using Screen        */
+        void        (* after)  ();      /* Do This Before Exiting Screen      */
+        struct ICE_FIELD *fields;       /* Fields Present On This Screen      */
+        VATRB       clr;                /* Attribute To Use During Screen Clr.*/
+        char        autoborder;         /* Automatically Border The Screen?   */
+};
+
+
+/*============================= FIELD TYPES ==================================*/
+
+#define FLD_PROMPT      0
+#define FLD_RESP        1
+
+
+/*======================= CHARACTER VALIDATION CODES =========================*/
+
+#define     ICE_LITERAL_L   'x'             /* No Character Validation        */
+#define     ICE_LITERAL_U   'X'
+#define     ICE_LITERAL_N   'j'
+
+#define     ICE_ALPHA_L     'a'             /* Alphabetic Only                */
+#define     ICE_ALPHA_U     'A'
+#define     ICE_ALPHA_N     'k'
+
+#define     ICE_ALPHANUM_L  'n'             /* Alphanumeric Only              */
+#define     ICE_ALPHANUM_U  'N'
+#define     ICE_ALPHANUM_N  'l'
+
+#define     ICE_BINARY      'b'             /* Binary Digits Only             */
+#define     ICE_OCTAL       'o'             /* Octal Digits Only              */
+#define     ICE_DECIMAL     'd'             /* Decimal Digits Only            */
+#define     ICE_HEX_L       'h'             /* Hex Digits Only                */
+#define     ICE_HEX_U       'H'
+#define     ICE_HEX_N       'u'
+#define     ICE_FLOATING    'f'             /* Floating Point Digits Only     */
+#define     ICE_SCIENT_L    's'             /* Scientific Digits Only         */
+#define     ICE_SCIENT_U    'S'
+#define     ICE_SCIENT_N    'v'
+#define     ICE_FINANCIAL   '$'             /* Financial Digits Only          */
+#define     ICE_YN_L        'y'             /* Yes/No                         */
+#define     ICE_YN_U        'Y'
+#define     ICE_YN_N        'w'
+
+#define     ICE_LIST0       '0'             /* Literal Lists                  */
+#define     ICE_LIST1       '1'
+#define     ICE_LIST2       '2'
+#define     ICE_LIST3       '3'
+#define     ICE_LIST4       '4'
+#define     ICE_LIST5       '5'
+#define     ICE_LIST6       '6'
+#define     ICE_LIST7       '7'
+#define     ICE_LIST8       '8'
+#define     ICE_LIST9       '9'
+
+
+/*=================== INTERNAL CONTROL CODE MAPPINGS ========================*/
+
+/* Screen Control Codes */
+
+#define     HELP            0
+#define     NXT_FLD         1
+#define     PRV_FLD         2
+#define     FST_FLD         3
+#define     LST_FLD         4
+#define     SCR_DONE        5
+
+/* Field Control Codes */
+
+#define     CUR_LEFT        6
+#define     CUR_RIGHT       7
+#define     CUR_UP          8
+#define     CUR_DOWN        9
+#define     CUR_PG_UP       10
+#define     CUR_PG_DOWN     11
+#define     CUR_BGN_LIN     12
+#define     CUR_END_LIN     13
+#define     CUR_BGN_FLD     14
+#define     CUR_END_FLD     15
+#define     CLR_FLD         16
+#define     CLR_TO_END      17
+#define     CANCEL_EDIT     18
+#define     INSERT          19
+#define     DELETE          20
+#define     BS              21
+#define     FLD_DONE        22
+
+/*=================== INTERNAL ERROR AND STATUS CODES =======================*/
+
+
+#define ICE_NOERR     (ICE_ERROR) 0                      /* No Error          */
+#define ICE_ENOTRES   (ICE_ERROR) 1                      /* No Response Allow */
+#define ICE_EFNULL    (ICE_ERROR) 3                      /* Null Array In Fld.*/
+#define ICE_EBAD_CTRL (ICE_ERROR) 4                      /* Bad Keybd. Ctrl.  */
+#define ICE_NULFPTR   (ICE_ERROR) 5                      /* Null Fld. Ptr.    */
+#define ICE_MUSTFIL   (ICE_ERROR) 6                      /* Must Fill Error   */
+#define ICE_RESREQD   (ICE_ERROR) 7                      /* RReqd. Error      */
+#define ICE_IEUVALID  (ICE_ERROR) 8                      /* User Valid. Error */
+#define ICE_NOMEM     (ICE_ERROR) 9                      /* Out Of Memory     */
+
+/*======================== FUNCTION DECLARATIONS =============================*/
+
+
+#if     ANSI
+
+               /*** GENERIC IceScreen FUNCTIONS ***/
+
+void            ice_sound(int x, int y);
+void            ice_cursor(unsigned char x, unsigned char y);
+unsigned long   ice_rdcursor(void);
+void            ice_rowcol(VCOORD y, VCOORD x);
+void            ice_cls(VATRB x);
+KEYSTR          ice_getc(void);
+void            ice_aputs(char *x, VATRB y);
+KEYSTR          ice_keyin(void);
+ICE_ERROR       ice_fedit(struct ICE_FIELD *x, KEYSTR *y);
+void            ice_fdsply(struct ICE_FIELD *x, BOOL y, FLEN z);
+
+#else
+               /*** GENERIC IceScreen FUNCTIONS ***/
+
+void            ice_sound();
+void            ice_cursor();
+unsigned long   ice_rdcursor();
+void            ice_rowcol();
+void            ice_cls();
+KEYSTR          ice_getc();
+void            ice_aputs();
+KEYSTR          ice_keyin();
+ICE_ERROR       ice_fedit();
+void            ice_fdsply();
+
+#endif
+
+/*=====================END OF <ICE_DEFS.H> INSERT DECK =======================*/
+
diff --git a/ice/ICE_FEDI.C b/ice/ICE_FEDI.C
new file mode 100644
index 0000000..969d5f2
--- /dev/null
+++ b/ice/ICE_FEDI.C
@@ -0,0 +1,160 @@
+/* ICE_FEDI.C - IceScreen Field Edit Routines
+
+                Copyright (c) 1988, 1989, 1990 By T.A. Daneliuk
+                Last Modified: 06-06-90
+
+        These routines edit a specific field in accordance with the
+        definitions in a structure type called ICE_FIELD.  On entry,
+        the calling routine passes a pointer to such a field.  On
+        return, ICE_NOERR is returned if the edit was successful.
+        An error code is returned if the edit failed for some reason.
+        This will occur under the following conditions:
+
+            The pointer passed to ice_fedit() is NULL     (ICE_NULFPTR)
+            The passed structure points to a Prompt field (ICE_ENOTRES)
+            The the "field" structure member is NULL      (ICE_EFNULL)
+
+        The function will not accept any characters which do not meet
+        the character validation conditions, and will not return until
+        the whole field validation function passes successfully.
+*/
+
+#include    <stdio.h>
+#include    <stdlib.h>
+#include    <malloc.h>
+#include    <string.h>
+#include    <ice_defs.h>
+#include    <ctype.h>
+
+#if ANSI
+static void dsply_fld(struct ICE_FIELD *x, FLEN y);
+#else
+static void dsply_fld();
+#endif
+
+
+/*====================== MAIN FIELD EDITING FUNCTION =========================*/
+
+ICE_ERROR ice_fedit(fldptr, retnkey)
+
+struct  ICE_FIELD   *fldptr;
+KEYSTR              *retnkey;
+
+{
+    BOOL        done, getkey, insert;
+    FLEN        posn;
+    ICE_ERROR   fedit_status;
+    KEYSTR      *buffer, key;
+
+    fedit_status = ICE_NOERR;
+
+    if (fldptr == NULL)                         /* See If Bad Pointer Passed  */
+        fedit_status = ICE_NULFPTR;
+
+    if (fldptr->ftype != FLD_RESP)              /* See If Response Allowed    */
+        fedit_status = ICE_ENOTRES;
+    else
+        if (fldptr->field == NULL)              /* Is Response Fld. Ptr. OK?  */
+            fedit_status = ICE_EFNULL;
+
+    if ((buffer = (KEYSTR *) malloc((size_t) ((fldptr->rlen) + 1))) == NULL)
+        fedit_status = ICE_NOMEM;               /* No Mem. For Wking. Buffer */
+
+    if (fedit_status != ICE_NOERR)              /* Error Detected, Get Out    */
+        return(fedit_status);
+
+
+    insert = done = FALSE;                      /* Prepare To Edit Field */
+    getkey = TRUE;
+    posn = 0;
+    ice_rowcol(fldptr->frow, fldptr->fcol);
+    (void) strcpy((char *) buffer, (char *) fldptr->field); /* Bld Wrk Buffer */
+    ice_cursor(CURSML);
+
+    while (!done)
+        {
+        if (getkey)
+            key = ice_keyin();
+
+        switch(key)
+            {
+            case NXT_FLD:     /* All These Initiate Close & Exit Processing */
+            case PRV_FLD:
+            case FST_FLD:
+            case LST_FLD:
+            case SCR_DONE:
+            case FLD_DONE:    
+                *retnkey = key;
+                done = TRUE;
+                break;
+
+            case HELP:
+                break;
+
+            case CUR_LEFT:
+                break;
+
+            case CUR_RIGHT:
+                break;
+
+            case CUR_UP:
+                break;
+
+            case CUR_DOWN:
+                break;
+
+            case CUR_PG_UP:
+                break;
+
+            case CUR_PG_DOWN:
+                break;
+
+            case CUR_BGN_LIN:
+                break;
+
+            case CUR_END_LIN:
+                break;
+
+            case CUR_BGN_FLD:
+                break;
+
+            case CUR_END_FLD:
+                break;
+
+            case CLR_FLD:
+                break;
+
+            case CLR_TO_END:
+                break;
+
+            case CANCEL_EDIT:
+                break;
+
+            case INSERT:
+                break;
+
+            case DELETE:
+                break;
+
+            case BS:
+                break;
+
+            default:
+                break;
+            }
+
+        }
+
+    free(buffer);
+    return(fedit_status);
+}
+
+/*************** Paint All Or Part Of A Field With Trailing Fill **************/
+
+static void dsply_fld(buffer, offset)
+struct ICE_FIELD *buffer;
+FLEN             offset;
+
+{
+
+}
diff --git a/ice/ICE_KEYI.C b/ice/ICE_KEYI.C
new file mode 100644
index 0000000..236e0ac
--- /dev/null
+++ b/ice/ICE_KEYI.C
@@ -0,0 +1,198 @@
+/*  ICE_KEYIN.C -   IceScreen Keystroke Capture & Mapping Routines
+                    This Code Captures A Keystroke And Maps It According
+                            To The Global Key Value Maps.
+
+                    Last Modified: 06-05-90
+                    Copyright (C) 1988, 1989, 1990 by T.A. Daneliuk
+
+
+*/
+
+
+#include    <stdio.h>
+#include    <ice_defs.h>
+
+#define     K_XLATE     ((unsigned) ((KEYSTR) -1))+1   /* # of unique keyvals */
+
+KEYSTR      key_xlate[K_XLATE] =    {
+                                      0,   1,   2,   3,   4,   5,   6,   7,   8,
+                                      9,  10,  11,  12,  13,  14,  15,  16,  17,
+                                     18,  19,  20,  21,  22,  23,  24,  25,  26,
+                                     27,  28,  29,  30,  31,  32,  33,  34,  35,
+                                     36,  37,  38,  39,  40,  41,  42,  43,  44,
+                                     45,  46,  47,  48,  49,  50,  51,  52,  53,
+                                     54,  55,  56,  57,  58,  59,  60,  61,  62,
+                                     63,  64,  65,  66,  67,  68,  69,  70,  71,
+                                     72,  73,  74,  75,  76,  77,  78,  79,  80,
+                                     81,  82,  83,  84,  85,  86,  87,  88,  89,
+                                     90,  91,  92,  93,  94,  95,  96,  97,  98,
+                                     99, 100, 101, 102, 103, 104, 105, 106, 107,
+                                    108, 109, 110, 111, 112, 113, 114, 115, 116,
+                                    117, 118, 119, 120, 121, 122, 123, 124, 125,
+                                    126, 127, 128, 129, 130, 131, 132, 133, 134,
+                                    135, 136, 137, 138, 139, 140, 141, 142, 143,
+                                    144, 145, 146, 147, 148, 149, 150, 151, 152,
+                                    153, 154, 155, 156, 157, 158, 159, 160, 161,
+                                    162, 163, 164, 165, 166, 167, 168, 169, 170,
+                                    171, 172, 173, 174, 175, 176, 177, 178, 179,
+                                    180, 181, 182, 183, 184, 185, 186, 187, 188,
+                                    189, 190, 191, 192, 193, 194, 195, 196, 197,
+                                    198, 199, 200, 201, 202, 203, 204, 205, 206,
+                                    207, 208, 209, 210, 211, 212, 213, 214, 215,
+                                    216, 217, 218, 219, 220, 221, 222, 223, 224,
+                                    225, 226, 227, 228, 229, 230, 231, 232, 233,
+                                    234, 235, 236, 237, 238, 239, 240, 241, 242,
+                                    243, 244, 245, 246, 247, 248, 249, 250, 251,
+                                    252, 253, 254, 255
+                                    };
+
+/*====================== Get And Map Keyboard Input ==========================*/
+
+KEYSTR  ice_keyin()
+
+{
+
+    static  char progname[] = PROGNAME;
+    static  char  version[] = VERSION;
+    static  char   module[] = "ice_keyin()";
+
+    KEYSTR  key, retval;
+    BOOL    validkey;
+
+    validkey = FALSE;
+    while(!validkey)
+        {
+        key = ice_getc();
+        switch (key)
+            {
+            case 0:                     /* Control Sequence Introducer */
+                key = ice_getc();
+                switch (key)
+                    {
+                    case 15:            /* BACKTAB */
+                        retval = (KEYSTR) PRV_FLD;
+                        validkey = TRUE;
+                        break;
+
+                    case 117:           /* Ctrl-END */
+                        retval = (KEYSTR) CUR_END_FLD;
+                        validkey = TRUE;
+                        break;
+
+                    case 119:           /* Ctrl-HOME */
+                        retval = (KEYSTR) CUR_BGN_FLD;
+                        validkey = TRUE;
+                        break;
+
+                    case 83:            /* DEL */
+                        retval = (KEYSTR) DELETE;
+                        validkey = TRUE;
+                        break;
+
+                    case 80:            /* DOWN ARROW */
+                        retval = (KEYSTR) CUR_DOWN;
+                        validkey = TRUE;
+                        break;
+
+                    case 79:            /* END */
+                        retval = (KEYSTR) CUR_END_LIN;
+                        validkey = TRUE;
+                        break;
+
+                    case 71:            /* HOME */
+                        retval = (KEYSTR) CUR_BGN_LIN;
+                        validkey = TRUE;
+                        break;
+
+                    case 82:            /* INS */
+                        retval = (KEYSTR) INSERT;
+                        validkey = TRUE;
+                        break;
+
+                    case 75:            /* LEFT ARROW */
+                        retval = (KEYSTR) CUR_LEFT;
+                        validkey = TRUE;
+                        break;
+
+                    case 59:            /* PF 1 */
+                        retval = (KEYSTR) HELP;
+                        validkey = TRUE;
+                        break;
+
+                    case 81:            /* PgDn */
+                        retval = (KEYSTR) CUR_PG_DOWN;
+                        validkey = TRUE;
+                        break;
+
+                    case 73:            /* PgUp */
+                        retval = (KEYSTR) CUR_PG_UP;
+                        validkey = TRUE;
+                        break;
+
+                    case 77:            /* RIGHT ARROW */
+                        retval = (KEYSTR) CUR_RIGHT;
+                        validkey = TRUE;
+                        break;
+
+                    case 72:            /* UP ARROW */
+                        retval = (KEYSTR) CUR_UP;
+                        validkey = TRUE;
+                        break;
+
+                    case 132:            /* Ctrl-PgUp */
+                        retval = (KEYSTR) FST_FLD;
+                        validkey = TRUE;
+                        break;
+
+                    case 118:            /* Ctrl-PgDn */
+                        retval = (KEYSTR) LST_FLD;
+                        validkey = TRUE;
+                        break;
+                    }
+                break;
+
+            case 9:                     /* TAB */
+                retval = (KEYSTR) NXT_FLD;
+                validkey = TRUE;
+                break;
+
+            case 8:                     /* BACKSPACE */
+                retval = (KEYSTR) BS;
+                validkey = TRUE;
+                break;
+
+            case 10:                    /* Ctrl-ENTER */
+                retval = (KEYSTR) CLR_FLD;
+                validkey = TRUE;
+                break;
+
+            case 13:                    /* ENTER */
+                retval = (KEYSTR) FLD_DONE;
+                validkey = TRUE;
+                break;
+
+            case 27:                    /* ESCAPE */
+                retval = (KEYSTR) SCR_DONE;
+                validkey = TRUE;
+                break;
+
+            case 03:                    /* Ctrl-C */
+                retval = (KEYSTR) CANCEL_EDIT;
+                validkey = TRUE;
+                break;
+
+            case 11:                    /* Ctrl-K */
+                retval = (KEYSTR) CLR_TO_END;
+                validkey = TRUE;
+                break;
+
+            default:
+                retval = (KEYSTR) key_xlate[key];
+                validkey = TRUE;
+                break;
+            }
+        }
+
+    return(retval);
+
+}
diff --git a/ice/ICE_LIBS/D_H_ICE.LIB b/ice/ICE_LIBS/D_H_ICE.LIB
new file mode 100644
index 0000000..367cabc
--- /dev/null
+++ b/ice/ICE_LIBS/D_H_ICE.LIB
Binary files differ
diff --git a/ice/ICE_LIBS/D_L_ICE.LIB b/ice/ICE_LIBS/D_L_ICE.LIB
new file mode 100644
index 0000000..5bacba9
--- /dev/null
+++ b/ice/ICE_LIBS/D_L_ICE.LIB
Binary files differ
diff --git a/ice/ICE_LIBS/D__ICE.LIB b/ice/ICE_LIBS/D__ICE.LIB
new file mode 100644
index 0000000..1a25ffd
--- /dev/null
+++ b/ice/ICE_LIBS/D__ICE.LIB
Binary files differ
diff --git a/ice/ICE_LIBS/H_ICE.LIB b/ice/ICE_LIBS/H_ICE.LIB
new file mode 100644
index 0000000..e886a60
--- /dev/null
+++ b/ice/ICE_LIBS/H_ICE.LIB
Binary files differ
diff --git a/ice/ICE_LIBS/L_ICE.LIB b/ice/ICE_LIBS/L_ICE.LIB
new file mode 100644
index 0000000..5514bbb
--- /dev/null
+++ b/ice/ICE_LIBS/L_ICE.LIB
Binary files differ
diff --git a/ice/ICE_LOGD.C b/ice/ICE_LOGD.C
new file mode 100644
index 0000000..2e6ecd4
--- /dev/null
+++ b/ice/ICE_LOGD.C
@@ -0,0 +1,49 @@
+/* ICE_LOGDVR.C - IceScreen Logical Device Driver Interfaces
+
+                    Last Modified: 06-13-90
+                    Copyright (C) 1988, 1989, 1990 by T.A. Daneliuk
+*/
+
+#include    <stdio.h>
+#include    <dos.h>
+#include    <graph.h>
+#include    <ice_defs.h>
+
+/*============================ Low-Level Keyboard Read =======================*/
+
+KEYSTR  ice_getc()
+
+{
+    union   REGS    inregs, outregs;
+
+    inregs.h.ah = 7;
+    intdos(&inregs, &outregs);
+    return((KEYSTR) outregs.h.al);
+}
+
+/*============================ Position Cursor ===============================*/
+
+void ice_rowcol(row, col)
+VCOORD  row, col;
+
+{
+
+
+    row += (col/80);            /* Normalize Coordinates For 80 x 25 Screen */
+    col %= 80;
+    row %= 25;
+    col++;                      /* MSC Routines Are 1,1 Relative */
+    row++;
+    _settextposition(row, col);
+}
+
+/*======================= Write String With Attribute ========================*/
+
+void ice_aputs(str, attr)
+char    *str;
+VATRB   attr;
+
+{
+    _settextcolor(attr);
+    _outtext(str);
+}
diff --git a/ice/LARGE/DICEFEDI.OBJ b/ice/LARGE/DICEFEDI.OBJ
new file mode 100644
index 0000000..83c1d76
--- /dev/null
+++ b/ice/LARGE/DICEFEDI.OBJ
Binary files differ
diff --git a/ice/LARGE/DICEKEYI.OBJ b/ice/LARGE/DICEKEYI.OBJ
new file mode 100644
index 0000000..f4af8f8
--- /dev/null
+++ b/ice/LARGE/DICEKEYI.OBJ
Binary files differ
diff --git a/ice/LARGE/DICELOGD.OBJ b/ice/LARGE/DICELOGD.OBJ
new file mode 100644
index 0000000..5fa6a4c
--- /dev/null
+++ b/ice/LARGE/DICELOGD.OBJ
Binary files differ
diff --git a/ice/LARGE/ICE_KEYI.OBJ b/ice/LARGE/ICE_KEYI.OBJ
new file mode 100644
index 0000000..3e1d0ea
--- /dev/null
+++ b/ice/LARGE/ICE_KEYI.OBJ
Binary files differ
diff --git a/ice/LARGE/ICE_LOGD.OBJ b/ice/LARGE/ICE_LOGD.OBJ
new file mode 100644
index 0000000..7ca5722
--- /dev/null
+++ b/ice/LARGE/ICE_LOGD.OBJ
Binary files differ
diff --git a/ice/PCBIOS.ASM b/ice/PCBIOS.ASM
new file mode 100644
index 0000000..b8d519e
--- /dev/null
+++ b/ice/PCBIOS.ASM
@@ -0,0 +1,285 @@
+                PAGE    88,132
+                TITLE   System Specific Routines For IBM-PC Using BIOS
+                SUBTTL  Copyright (c) 1986, 1987, 1988 T.A. Daneliuk
+;
+;               Last Modified: 07-26-88
+;
+
+
+; ======================= Setup, Notes, And Facts =============================
+
+;   Must Use /Dmemmodel=model size on MASM command line !!!!!
+%               .model  memmodel,c
+
+.LALL                           ; Want To See All MASM Generated Expansions
+
+
+; =========================== Data Section ====================================
+                        .data
+
+; =========================== Actual Data =====================================
+
+VIDEO_MODE      db      3                   ; Current Video Mode
+VIDEO_PAGE      db      0                   ; Current Video Page
+VIDEO_WIDTH     dw      80                  ; Current Screen Width
+VIDEO_HEIGHT    dw      25                  ; Current Screen Height
+
+; =========================== Code Section ====================================
+
+                        .code
+
+
+; ========================= Sound Generation ==================================
+;
+;      USAGE:  pcbios_sound(FREQ,DURATION)
+;       WHERE,  FREQ is unsigned int in Hertz
+;               DURATION is unsigned int (18 per second)
+;
+;
+portb_8255      equ     61h                     ; 8255 port b
+freq_8253       equ     42h                     ; 8253 timer latch
+command_8253    equ     43h                     ; 8253 time command register
+clockh          equ     0012h                   ; clock rate high byte - 1193180 hz
+clockl          equ     34dch                   ; clock rate low byte
+
+;
+;
+pcbios_sound    proc freq:word, duration:word
+;
+local           elapsed:word                    ; elapsed time ticks stored here
+local           startl:word                     ; stores initial timer count
+local           starth:word
+;
+;
+                xor             ax,ax           ; zero register
+                mov             elapsed,ax      ; init. elapsed time
+                mov             startl, ax      ; init. startl
+                mov             starth,ax       ; init. starth
+                mov             ax,freq         ; make sure freq. <> 0!
+                and             ax,ax
+                jz              sound_done      ; if so, skip the whole thing
+                in              al,portb_8255   ; get current 8255 value
+                or              al,3            ; turn on speaker/gate signal
+                out             portb_8255,al   ; write back to 8255
+                mov             al,0b6h         ; tell timer, frequency is sent next 
+                out             command_8253,al
+                mov             dx,clockh       ; divide clock rate by passed
+                mov             ax,clockl       ; frequency to get total
+                mov             cx,freq         ; number of ticks to wait
+                div             cx
+                out             freq_8253,al    ; low byte to timer
+                xchg            al,ah           ; intel's neat instruction set!
+                out             freq_8253,al    ; high byte to timer
+                xor             ax,ax           ; get current timer count in cx:dx
+                int             1ah
+                mov             starth,cx       ; save for future reference
+                mov             startl,dx
+delay:          mov             ax,duration     ; wait till elapsed time is
+                cmp             ax,elapsed      ; >= duration passed on stack
+                jbe             sound_off
+                xor             ax,ax           ; get current timer count
+                int             1ah
+                mov             ax,starth       ; get starting time
+                mov             bx,startl
+                sub             dx,bx           ; low word first
+                sbb             cx,ax           ; high word with carry
+                jnz             sound_off       ; only can deal with 16 bit intervals
+                mov             elapsed,dx      ; save time elapsed
+                jmp             delay
+sound_off:      in              al,portb_8255   ; turn off speaker/gate signal
+                and             al,11111100b
+                out             portb_8255,al
+sound_done:     ret                             ; there's no place like home!
+;
+pcbios_sound    endp
+
+
+; ========================== Set Cursor Size ==================================
+;
+;   usage:      pcbios_cursor(startline, endline)
+;
+;               startline & endline define starting and ending
+;               scanlines respectively
+;
+;
+pcbios_cursor   proc sline:byte, eline:byte
+;
+                mov     ah,1
+                mov     ch,sline
+                mov     cl,eline
+                int     10h
+                ret
+;
+pcbios_cursor   endp
+
+
+; ======================== Read Current Cursor Position =======================
+
+pcbios_rdcursor proc uses ds
+;
+                mov     ax,DGROUP
+                mov     ds, ax
+                mov     ah,3
+                mov     bh,VIDEO_PAGE
+                int     10h
+                mov     ax,dx                       ; ah=row, al=column
+                mov     dx,cx                       ; dh=1st scan line, dl=last
+                ret
+;
+pcbios_rdcursor endp
+
+; ======================== Absolute Cursor Positioning ========================
+;
+;   usage:      pcbios_rowcol(x-coordinate, y-coordinate)
+;
+;       if coordinates > than physical screen:
+;
+;               x position overflows from right end of screen to next line
+;               y position wraps to top of screen
+;
+pcbios_rowcol   proc uses ds, ypos:word, xpos:word
+;
+                mov     ax,DGROUP
+                mov     ds, ax
+                mov     ax,VIDEO_WIDTH
+                mov     bx,VIDEO_HEIGHT
+                mov     dx,xpos
+                mov     cx,ypos
+check_xposn:    cmp     ax,dx                   ; Bounds Check On X-coord
+                jg      check_yposn
+                sub     dx,ax                   ; Do modulo ax arithmetic
+                inc     cx                      ; And Move Down A Line
+                jmp     check_xposn
+check_yposn:    cmp     cx,bx                   ; Bounds Check On Y-coord
+                jl      set_row_col
+                sub     cx,bx
+                jmp     check_yposn
+set_row_col:    mov     ypos,cx                 ; Save The Normalized Values
+                mov     xpos,dx
+                mov     ah,2
+                mov     bh,VIDEO_PAGE
+                mov     dh,cl
+                int     10h
+                mov     ax,xpos                 ; Return Normalized Coordinates
+                mov     dx,ypos
+                ret
+;
+pcbios_rowcol   endp
+
+
+; ====================Clear Screen With Video Attribute =======================
+
+pcbios_cls      proc    cls_attrib:byte
+;
+                mov     ax,0600H                ; Scroll Up Whole Screen
+                mov     bh,cls_attrib
+                xor     cx,cx                   ; Start At 0,0
+                mov     dx,184FH
+                int     10H
+                ret
+;
+pcbios_cls      endp
+
+
+; =========================== Get A Keystroke =================================
+
+pcbios_getc     proc    
+;
+                mov     ah,7
+                int     21h
+                ret
+;
+pcbios_getc     endp
+
+
+; ===================== Write String With Video Attribute =====================
+
+pcbios_aputs    proc uses ds es, string:ptr, attr:byte
+;
+local           row:word                        ; Current Row
+local           col:word                        ; Current Column
+local           lcount:word                     ; Length Count
+;
+                mov     ax,DGROUP
+                mov     ds, ax
+                mov     lcount,0                ; Initialize Length Count
+                call    pcbios_rdcursor         ; Get Current Position
+                mov     dl,ah
+                xor     ah,ah
+                mov     col,ax
+                xor     dh,dh
+                mov     row,dx
+                IF @DataSize                    ; Use Pointer Based On Model
+                   les  si,string
+                ELSE
+                   mov  si,string
+                ENDIF
+get_a_char:     mov     al,es:[si]              ; Get A Character
+                and     al,al                   ; If 0, We're Done!
+                jz      aputs_done
+                mov     ah,9
+                mov     bh,VIDEO_PAGE
+                mov     bl,attr
+                xor     cx,cx                   ; Repeat 1 Time
+                inc     cx
+                int     10h
+                inc     col
+                push    col                     ; Adjust Cursor Position
+                push    row
+                call    pcbios_rowcol
+                pop     row                     ; Get Normalized Coordinates
+                pop     col
+                inc     lcount                  ; Update Counter
+                inc     si                      ; And String Pointer
+                jmp     get_a_char              ; Keep Looping For Whole String
+aputs_done:     mov     ax,lcount               ; Return String Length
+                ret
+;
+pcbios_aputs    endp
+
+
+; ======================== Get Current Video Mode =============================
+
+pcbios_getvmode proc uses DS
+;
+                mov     ax,DGROUP
+                mov     ds,ax
+                mov     ah,0fh
+                int     10h
+                mov     VIDEO_MODE,al
+                mov     VIDEO_PAGE,bh
+                mov     al,ah                   ; Make a word out of the width
+                xor     ah,ah
+                mov     VIDEO_WIDTH,ax
+                ret
+;
+pcbios_getvmode endp
+
+
+; ============================= Set Video Mode ================================
+
+pcbios_setvmode proc vmode:byte
+;
+                xor     ah,ah
+                mov     al,vmode
+                int     10h
+                call    pcbios_getvmode
+                ret
+;
+pcbios_setvmode endp
+
+
+; ============================= Set Video Page ================================
+
+pcbios_setvpage proc vpage:byte
+;
+                mov     ah,5
+                mov     al,vpage
+                int     10h
+                call    pcbios_getvmode
+                ret
+pcbios_setvpage endp
+
+
+; ============================ END OF ROUTINES ================================
+                end
diff --git a/ice/SD2_FEDI.C b/ice/SD2_FEDI.C
new file mode 100644
index 0000000..d0eafa7
--- /dev/null
+++ b/ice/SD2_FEDI.C
@@ -0,0 +1,599 @@
+/* SD2_FEDI.C - Screen Door II Field Edit Routines
+
+                Copyright (c), 1988 By T.A. Daneliuk
+                Last Modified: 08-11-88
+
+        These routines edit a specific field in accordance with the
+        definitions in a structure type called SD2_FIELD.  On entry,
+        the calling routine passes a pointer to such a field.  On
+        return, SD2_NOERR is returned if the edit was successful.
+        An error code is returned if the edit failed for some reason.
+        This will occur under the following conditions:
+
+            The pointer passed to sd2_fedit() is NULL     (SD2_NULFPTR)
+            The passed structure points to a Prompt field (SD2_ENOTRES)
+            The the "field" structure member is NULL      (SD2_EFNULL)
+
+        The function will not accept any characters which do not meet
+        the character validation conditions, and will not return until
+        the whole field validation function passes successfully.
+*/
+
+#include    <stdio.h>
+#include    <string.h>
+#include    <sd2_defs.h>
+#include    <ctype.h>
+
+#if ANSI
+static BOOL end_fld(struct SD2_FIELD *x);
+static BOOL  mask_val(struct SD2_FIELD *x, KEYSTR *y, FLEN z);
+#else
+static BOOL end_fld();
+static BOOL  mask_val();
+#endif
+
+static BOOL firsttime;
+
+
+/*====================== MAIN FIELD EDITING FUNCTION =========================*/
+
+ERRCODE sd2_fedit(fldptr, retnkey)
+
+struct  SD2_FIELD   *fldptr;
+KEYSTR              *retnkey;
+
+{
+    ERRCODE     fedit_status;
+    BOOL        fediting;
+    KEYSTR      key, ktemp;
+    BOOL        fmodified;
+    FLEN        fposn, flen, rlen, temp;
+    BOOL        ins_mode;
+    BOOL        paint;
+    BOOL        get_next_key;
+    BOOL        store_key;
+
+
+    fedit_status = SD2_NOERR;
+
+    if (fldptr == NULL)                         /* See If Bad Pointer Passed  */
+        fedit_status = SD2_NULFPTR;
+
+    if (fldptr->ftype != FLD_RESP)              /* See If Response Allowed    */
+        fedit_status = SD2_ENOTRES;
+    else
+        if (fldptr->field == NULL)              /* Is Response Fld. Ptr. OK?  */
+            fedit_status = SD2_EFNULL;
+
+
+    firsttime       = TRUE;                     /* Setup The State Machine    */
+    fediting        = TRUE;
+    fmodified       = FALSE;
+    fposn           = 0;
+    ins_mode        = FALSE;
+    paint           = TRUE;
+    get_next_key    = TRUE;
+
+    while ((fediting == TRUE) && (fedit_status == SD2_NOERR))
+        {
+        if (paint == TRUE)
+            {
+            if ((fldptr->mask != NULL) && (fldptr->field[fposn] != '\0'))
+                {
+                temp = fposn;   /* Make Any Case Corrections For Char. Val.   */
+                while (fldptr->field[temp] != '\0')
+                    {
+                    mask_val(fldptr, &(fldptr->field[temp]), temp);
+                    temp++;
+                    }
+                }
+            sd2_fdsply(fldptr, fmodified, fposn);        /* Display Updates */
+            }
+        sd2_rowcol(fldptr->frow, (fldptr->fcol)+fposn);  /* Position Cursor */
+        (ins_mode==TRUE ? sd2_cursor(CURBLK) : sd2_cursor(CURSML));
+        if (get_next_key == TRUE)
+            {
+            key = sd2_keyin();                        /* Get Next Keystroke   */
+            *retnkey = key;                           /* Save For Return      */
+            }
+        flen = strlen(fldptr->field);                 /* Current Field Length */
+        rlen = fldptr->rlen;                          /* Maximum Field Length */
+
+
+  /* Inter-Field, Exit-Field, & Exit-Screen All Force End Of Field Editing */
+
+        if ((key == NXTFLD) || (key == PRVFLD) || (key == FSTFLD) ||
+            (key == LSTFLD) || (key == EXTFLD) || (key == EXTSCR))
+            {
+            if (end_fld(fldptr) == TRUE)    /* All Field Validations OK       */
+                {
+                fediting = FALSE;           /* Done With Field Editing        */
+                fposn = 0;                  /* For Cosmetic Consistency       */
+                }
+            }
+
+        else
+            if (key == SD2_EBAD_CTRL);      /* Ignore Bad Control Sequences   */
+
+        else
+            if (key == CURLFT)
+
+                {
+                if (flen > 0)               /* If Nothing In Field, Can't Move*/
+                    fposn = (fposn == 0 ? flen : --fposn);   /* Wrap If Neces.*/
+                fposn = (fposn == rlen ? --fposn : fposn);
+                paint = FALSE;
+                }
+        else
+            if (key == CURRGT)
+                {
+                if (flen > 0)
+                    fposn = (fposn == flen ? 0: ++fposn);
+                fposn = (fposn == rlen ? 0 : fposn);
+                paint = FALSE;
+                get_next_key = TRUE;     /* We Might Just Have Put A New Char */
+                }
+
+        else
+            if (key == BEGFLD)
+                {
+                fposn = 0;
+                paint = FALSE;
+                }
+
+        else
+            if (key == ENDFLD)
+                {
+                fposn = flen;
+                fposn = (fposn == rlen ? --fposn : fposn);
+                paint = FALSE;
+                }
+
+        else
+            if (key == CLRFLD)
+                {
+                fposn = 0;
+                fldptr->field[0] = '\0';
+                paint = TRUE;
+                fmodified = TRUE;
+                firsttime = TRUE;               /* Force Whole Field Repaint  */
+                }
+
+        else
+            if (key == CLREND)
+                {
+                fldptr->field[fposn] = '\0';
+                paint = TRUE;
+                fmodified = TRUE;
+                firsttime = TRUE;
+                }
+
+        else
+            if (key == INSERT)
+                {
+                if (flen < rlen)                   /* No Insert On Full Field */
+                    {
+                    ins_mode = (ins_mode == TRUE ? FALSE : TRUE);
+                    paint = FALSE;
+                    }
+                }
+
+        else
+            if (key == DELETE)
+                {
+                store_key = TRUE;
+                if (fldptr->field[fposn] != '\0')
+                    {
+                    if (fldptr->mask != NULL)   /* Make Sure Moving Left Is OK*/
+                        {
+                        temp  = fposn;              /* Can Current Character  */
+                        ktemp = fldptr->field[temp+1];/* Legally Move Over?   */
+
+                        while(ktemp != '\0')        /* Check All Remaining    */
+                            {
+                            store_key = store_key && 
+                                           mask_val(fldptr, &ktemp, temp);
+                            temp++;
+                            ktemp = fldptr->field[temp+1];
+                            }
+                        }
+                    }
+                    if (store_key == TRUE)      /* Character Validations OK   */
+                        {
+                        strcpy(&(fldptr->field[fposn]), &(fldptr->field[fposn+1]));
+                        fldptr->field[flen-1] = '\0';
+                        fmodified = TRUE;
+                        paint = TRUE;
+                        }
+                    else
+                        if (get_next_key == FALSE)  /* Were Trying To Bkspc   */
+                            fposn++;
+
+                    get_next_key = TRUE;        /* In Case We Just Backspaced */
+                }
+
+        else
+            if (key == BKSPC)
+                {
+                if (fposn > 0)                 /* No Bksp. @ Fld. Beginning   */
+                    {
+                    --fposn;          /* Just Backup One Position And Delete  */
+                    key = DELETE;
+                    get_next_key = FALSE;     /* Inhibit Keyboard Read            */
+                    }
+                }
+
+        else
+            if (key == HELPKEY)
+                {
+                if (fldptr->rhelp != NULL) /* Help Is Avail.*/
+                    sd2_help(fldptr->rhelp);
+                }
+        else                             /* We Have A Data Keystroke          */
+            {
+            store_key = TRUE;            /* Do Character Validations          */
+
+
+            if ((key == ' ') && (fldptr->rspace == FALSE)) /* Spaces Allowed? */
+                store_key = FALSE;
+
+            if (fldptr->mask != NULL)  /* Do Only If Char Validations Enabled */
+                {
+                store_key = store_key && mask_val(fldptr, &key, fposn);
+
+                if (ins_mode == TRUE)   /* Check All Subsequent If Inserting  */
+                    {
+                    if (fldptr->field[fposn] != '\0')  /* Only If Not At End  */
+                        {
+                        temp  = fposn;              /* Can Current Character  */
+                        ktemp = fldptr->field[temp];  /* Legally Move Over?   */
+
+                        while(ktemp != '\0')        /* Check All Remaining    */
+                            {
+                            store_key = store_key && 
+                                           mask_val(fldptr, &ktemp, temp+1);
+                            temp++;
+                            ktemp = fldptr->field[temp];
+                            }
+                        }
+                    }
+                }
+
+            if (store_key == TRUE)       /* Character Passed Validation       */
+                {
+                if (ins_mode == TRUE)
+                    {
+                   temp = flen;
+                   while(temp >= fposn)
+                        {
+                        fldptr->field[temp+1] = fldptr->field[temp];
+                        --temp;
+                        }
+
+                    fldptr->field[fposn]  = key;
+                    if ((flen+1) == rlen)           /* Field Now Is Filled    */
+                        {
+                        ins_mode = FALSE;
+                        sd2_cursor(CURSML);
+                        }
+                    }
+                else
+                    {
+                    if (fldptr->field[fposn] == '\0')
+                        fldptr->field[fposn+1] = '\0';           
+                    fldptr->field[fposn] = key;
+                    }
+                key = CURRGT;                       /* Move Cursor Over One   */
+                get_next_key = FALSE;               /* Before Getting Next    */
+                fmodified = TRUE;                   /* Keystroke              */
+                paint = TRUE;
+                }
+            }
+
+        }
+
+
+    sd2_fdsply(fldptr, FALSE, fposn);
+    return(fedit_status);
+
+}
+
+
+/*========================== DISPLAY A FIELD =================================*/
+
+void    sd2_fdsply(fld, modified, cposn)
+struct SD2_FIELD    *fld;
+BOOL            modified;
+FLEN            cposn;
+
+{
+
+    FLEN    x, y;
+    char    fill[2];
+
+    sd2_cursor(CUROFF);                         /* Turn Off Cursor            */
+
+    if (modified == FALSE)              /* Use Default Colors, No Fill        */
+        {                               /* Use Input Color And Fill           */
+        x = strlen(fld->field);
+        fill[0] = fld->rclear;
+        fill[1] = '\0';
+
+        sd2_rowcol(fld->frow, (fld->fcol)+cposn);   /* Position Cursor        */
+        sd2_aputs(&(fld->field[cposn]), fld->fattrib);   /* Display String */
+        while (x < fld->rlen)
+            {
+            sd2_rowcol(fld->frow, (fld->fcol)+x);    /* Clear Any Fill Chars. */
+            sd2_aputs(fill, fld->cattrib);
+            x++;
+            }
+        }
+    else
+        {                               /* Use Input Color And Fill           */
+        y = x = strlen(fld->field);
+        fill[0] = fld->rfill;
+        fill[1] = '\0';
+
+        if (firsttime == TRUE)          /* First Time Display Whole Field     */
+            {
+            firsttime = FALSE;
+            cposn = 0;
+            }
+        else                            /* At Most, Only Need 1 Fill Char     */
+            y = (y == fld->rlen ? y : (fld->rlen) - 1);
+
+        
+        sd2_rowcol(fld->frow, (fld->fcol)+cposn);   /* Position Cursor        */
+        sd2_aputs(&(fld->field[cposn]), fld->rattrib);   /* Display String */
+
+        while (y < fld->rlen)                  /* Have To Add A Fill Char */
+            {
+            sd2_rowcol(fld->frow, (fld->fcol)+x);    /* Then Fill Chars. */
+            sd2_aputs(fill, fld->rattrib);
+            ++y;
+            ++x;
+            }
+        }
+}
+
+
+/*======================= END FIELD PROCESSING ===============================*/
+
+static BOOL end_fld(fld)    /* Does Whole Fld, RReq, User Validation, etc.    */
+struct SD2_FIELD *fld;      /* Returns True If All OK, False If Not           */
+
+{
+    ERRCODE     status;
+    char        *errmsg;
+    static char mfill[] = "This Field Must Be Filled!";
+    static char rreqd[] = "This Field Requires A Response!";
+    
+    status = SD2_NOERR;
+
+    if ((fld->rmustfill == TRUE) && (strlen(fld->field) != fld->rlen))
+        {
+        status = SD2_MUSTFIL;
+        errmsg = mfill;
+        }        
+
+    else
+        if ((fld->rreqd == TRUE) && (fld->field[0] == '\0'))
+            {
+            status = SD2_RESREQD;
+            errmsg = rreqd;
+            }
+
+    else if (fld->rvalid != NULL)
+        {
+        errmsg = (*(fld->rvalid)) (fld);
+        if (errmsg != NULL)
+            status = SD2_IEUVALID;
+        }
+
+    if ((status != SD2_NOERR) && (fld->flderr != NULL))
+        (*(fld->flderr)) (fld, status, errmsg); 
+
+    if (status != SD2_NOERR)
+        return(FALSE);
+    else
+        return(TRUE);
+
+}
+
+/*============== CHECK A CHARACTER AGAINST THE MASK CONDITION ================*/
+
+static BOOL  mask_val(fldptr, key, fposn)    /* Returns TRUE If All OK   */
+struct SD2_FIELD    *fldptr;
+KEYSTR              *key;
+FLEN                fposn;
+
+{
+    BOOL    store_key, btemp;
+    FLEN    temp, temp1;
+    KEYSTR  ktemp;
+
+    store_key = TRUE;
+
+
+        switch(fldptr->mask[fposn])  /* Check For Relevant Validation */
+            {
+            case SD2_LITERAL_N:
+            case SD2_LITERAL_L:
+            case SD2_LITERAL_U:
+                switch (fldptr->mask[fposn])
+                    {
+                    case SD2_LITERAL_N:     /* No Case Conversion     */
+                        break;              /* Do Nothing             */
+                    case SD2_LITERAL_L:
+                        *key = tolower(*key);
+                           break;
+                    case SD2_LITERAL_U:
+                        *key = toupper(*key);
+                           break;
+                    }
+                 break;
+
+            case SD2_ALPHA_N:
+            case SD2_ALPHA_L:
+            case SD2_ALPHA_U:
+                if (isalpha(*key))
+                    {
+                    switch (fldptr->mask[fposn])
+                        {
+                        case SD2_ALPHA_N:
+                            break;
+                        case SD2_ALPHA_L:
+                            *key = tolower(*key);
+                               break;
+                        case SD2_ALPHA_U:
+                            *key = toupper(*key);
+                               break;
+                        } 
+                    }
+                else
+                    store_key = FALSE;
+                   break;
+
+            case SD2_ALPHANUM_N:
+            case SD2_ALPHANUM_L:
+            case SD2_ALPHANUM_U:
+                if (isalnum(*key))
+                    {
+                    switch (fldptr->mask[fposn])
+                        {
+                        case SD2_ALPHANUM_N:
+                            break;
+                        case SD2_ALPHANUM_L:
+                            *key = tolower(*key);
+                               break;
+                        case SD2_ALPHANUM_U:
+                            *key = toupper(*key);
+                               break;
+                        } 
+                    }
+                else
+                    store_key = FALSE;
+                    break;
+
+            case SD2_BINARY:
+                if (*key != '0' && *key != '1')
+                    store_key = FALSE;
+                    break;
+
+            case SD2_OCTAL:
+                if (!isdigit(*key) || (*key > '7'))
+                    store_key = FALSE;
+                    break;
+
+            case SD2_DECIMAL:
+                if (!isdigit(*key))
+                    store_key = FALSE;
+                    break;
+
+            case SD2_HEX_N:
+            case SD2_HEX_L:
+            case SD2_HEX_U:
+                if (!isxdigit(*key))
+                    store_key = FALSE;
+                else
+                    switch (fldptr->mask[fposn])
+                        {
+                        case SD2_HEX_N:
+                            break;
+                        case SD2_HEX_L:
+                            *key = tolower(*key);
+                            break;
+                        case SD2_HEX_U:
+                            *key = toupper(*key);
+                            break;
+                        }  
+                break;
+
+            case SD2_FLOATING:
+                if (!isdigit(*key) && (*key != '+') && (*key != '-')
+                                                  && (*key != '.'))
+                    store_key = FALSE;
+                    break;
+
+                case SD2_SCIENT_N:
+                case SD2_SCIENT_L:
+                case SD2_SCIENT_U:
+                if (!isdigit(*key) && (*key != '+') && (*key != '-')
+                    && (*key != '.') && (*key != 'e') && (*key != 'E'))
+                    store_key = FALSE;
+                else
+                    switch (fldptr->mask[fposn])
+                        {
+                        case SD2_SCIENT_N:
+                            break;
+                        case SD2_SCIENT_L:
+                            *key = tolower(*key);
+                            break;
+                        case SD2_SCIENT_U:
+                            *key = toupper(*key);
+                            break;
+                        }  
+                    break;
+
+             case SD2_FINANCIAL:
+                if (!isdigit(*key) && (*key != '+') && (*key != '-')
+                                  && (*key != '.') && (*key != '$'))
+                    store_key = FALSE;
+                    break;
+
+                case SD2_YN_N:
+                case SD2_YN_L:
+                case SD2_YN_U:
+                if ((toupper(*key) != 'Y') && (toupper(*key) != 'N'))
+                    store_key = FALSE;
+                else
+                    switch (fldptr->mask[fposn])
+                        {
+                        case SD2_YN_N:
+                            break;
+                        case SD2_YN_L:
+                            *key = tolower(*key);
+                            break;
+                        case SD2_YN_U:
+                            *key = toupper(*key);
+                            break;
+                        }  
+                    break;
+
+            case SD2_LIST0:
+            case SD2_LIST1:
+            case SD2_LIST2:
+            case SD2_LIST3:
+            case SD2_LIST4:
+            case SD2_LIST5:
+            case SD2_LIST6:
+            case SD2_LIST7:
+            case SD2_LIST8:
+            case SD2_LIST9:
+                if (fldptr->v_lists != NULL)    /* Only If Enabled    */
+                    {
+                    temp = (fldptr->mask[fposn]) - '0'; /* Only Works In ASCII*/
+                    if (fldptr->v_lists[temp] != NULL)
+                        {
+                        btemp = FALSE;  /* Scan Literal List And Look */
+                        temp1 = 0;      /* For Matching Character     */
+                        ktemp = 'x';    /* Dummy So While Below Works */
+                         while ((btemp == FALSE) && (ktemp != '\0'))
+                            {
+                            ktemp = fldptr->v_lists[temp][temp1];
+                            if (*key == ktemp)
+                                btemp = TRUE;
+                            ++temp1;
+                            }
+                        store_key = store_key && btemp;
+                        }
+                    }
+                break;
+
+             default:           /* Invalid Validation Code, Ignore *key */
+                store_key = FALSE;
+                break;
+            }
+
+    return(store_key);
+}
diff --git a/ice/SD2_HELP.C b/ice/SD2_HELP.C
new file mode 100644
index 0000000..3222425
--- /dev/null
+++ b/ice/SD2_HELP.C
@@ -0,0 +1,16 @@
+/* SD2_HELP.C -     ScreenDoor II Field Help Function
+
+                    Copyright (c) 1988, By T.A. Daneliuk
+                    Last Modified: 07-30-88
+*/
+
+#include    <stdio.h>
+#include    <sd2_defs.h>
+
+
+void    sd2_help(hscrn)
+struct SD2_SCRN *hscrn;
+
+{
+
+}
diff --git a/ice/TEST.C b/ice/TEST.C
new file mode 100644
index 0000000..ab51235
--- /dev/null
+++ b/ice/TEST.C
@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <graph.h>
+
+
+extern ice_getvmode();
+extern ice_aputs(char *x, unsigned int y);
+extern ice_rowcol();
+extern ice_cls();
+
+void main()
+
+{
+    static char x1[]="This is 0,0";
+    static char x2[]="This is 3,4";
+    static char x3[]="This is 10,75";
+    static char x4[]="This is 24,0";
+    static char x5[]="This is 24,77";
+
+    ice_rowcol(0,0);
+    printf("%s", x1);
+    ice_rowcol(3,4);
+    ice_aputs(x2, 7);
+    ice_rowcol(10,75);
+    ice_aputs(x3, 7);
+    ice_rowcol(24,0);
+    ice_aputs(x4, 7);
+    ice_rowcol(24,77);
+    ice_aputs(x5, 7);
+
+}
diff --git a/ice/TEST.EXE b/ice/TEST.EXE
new file mode 100644
index 0000000..9353c85
--- /dev/null
+++ b/ice/TEST.EXE
Binary files differ
diff --git a/ice/TEST.MAP b/ice/TEST.MAP
new file mode 100644
index 0000000..91ce669
--- /dev/null
+++ b/ice/TEST.MAP
@@ -0,0 +1,49 @@
+
+ Start  Stop   Length Name                   Class
+ 00000H 000B9H 000BAH TEST_TEXT              CODE
+ 000BAH 00161H 000A8H ICE_LOGD_TEXT          CODE
+ 00162H 01CBCH 01B5BH _TEXT                  CODE
+ 01CBEH 01CBEH 00000H C_ETEXT                ENDCODE
+ 01CC0H 01D01H 00042H NULL                   BEGDATA
+ 01D02H 02601H 00900H _DATA                  DATA
+ 02602H 0260FH 0000EH CDATA                  DATA
+ 02610H 02610H 00000H XIFB                   DATA
+ 02610H 02610H 00000H XIF                    DATA
+ 02610H 02610H 00000H XIFE                   DATA
+ 02610H 02610H 00000H XIB                    DATA
+ 02610H 02610H 00000H XI                     DATA
+ 02610H 02610H 00000H XIE                    DATA
+ 02610H 02610H 00000H XPB                    DATA
+ 02610H 02613H 00004H XP                     DATA
+ 02614H 02614H 00000H XPE                    DATA
+ 02614H 02614H 00000H XCB                    DATA
+ 02614H 02614H 00000H XC                     DATA
+ 02614H 02614H 00000H XCE                    DATA
+ 02614H 02614H 00000H XCFB                   DATA
+ 02614H 02614H 00000H XCF                    DATA
+ 02614H 02614H 00000H XCFE                   DATA
+ 02614H 02615H 00002H CONST                  CONST
+ 02616H 0261DH 00008H HDR                    MSG
+ 0261EH 026EBH 000CEH MSG                    MSG
+ 026ECH 026EDH 00002H PAD                    MSG
+ 026EEH 026EEH 00001H EPAD                   MSG
+ 026F0H 02885H 00196H _BSS                   BSS
+ 02886H 02886H 00000H XOB                    BSS
+ 02886H 02886H 00000H XO                     BSS
+ 02886H 02886H 00000H XOE                    BSS
+ 02890H 0308FH 00800H STACK                  STACK
+
+ Origin   Group
+ 01CC:0   DGROUP
+
+Program entry point at 0016:0012
+
+Unresolved externals:
+
+
+__settextposition in file(s):
+ ICE_LIBS\D_L_ICE.LIB(ice_logd.C)
+__outtext in file(s):
+ ICE_LIBS\D_L_ICE.LIB(ice_logd.C)
+__settextcolor in file(s):
+ ICE_LIBS\D_L_ICE.LIB(ice_logd.C)
diff --git a/ice/TEST.OBJ b/ice/TEST.OBJ
new file mode 100644
index 0000000..7a9a5b2
--- /dev/null
+++ b/ice/TEST.OBJ
Binary files differ
diff --git a/ice/TST b/ice/TST
new file mode 100644
index 0000000..f22e728
--- /dev/null
+++ b/ice/TST
@@ -0,0 +1,5 @@
+test.obj:   test.c ice_defs.h
+    cl /Zi /Od /AL /c test.c
+
+test.exe:   test.obj large\dicelogd.obj large\dicefedi.obj large\dicekeyi.obj
+    link test,,,ice_libs\d_l_ice.lib/CO;
diff --git a/ice/TST.BAT b/ice/TST.BAT
new file mode 100644
index 0000000..1ac85f6
--- /dev/null
+++ b/ice/TST.BAT
@@ -0,0 +1,2 @@
+make model=LARGE cmodel=L dice
+make tst
diff --git a/ice/X1.C b/ice/X1.C
new file mode 100644
index 0000000..f32f8d7
--- /dev/null
+++ b/ice/X1.C
@@ -0,0 +1,25 @@
+#include <stdio.h>
+#include  <conio.h>
+#include  <signal.h>
+#include    <bios.h>
+void handler(void);
+
+void main ()
+
+{
+    int x;
+    if (signal(SIGINT,SIG_IGN) == SIG_ERR)
+        printf("Couldn't set signal()\n\n\n");
+    while ((x=_bios_keybrd(_KEYBRD_READ)) != 255)
+        {
+        putchar(x);
+        printf(" %d\n", (char) x);
+        }
+}
+
+void handler()
+
+{
+printf("Ctrl-C Pressed!\n\n\n");
+signal(SIGINT,handler);
+}
diff --git a/ice/X1.EXE b/ice/X1.EXE
new file mode 100644
index 0000000..ee802c9
--- /dev/null
+++ b/ice/X1.EXE
Binary files differ
diff --git a/ice/X2.C b/ice/X2.C
new file mode 100644
index 0000000..247a0a7
--- /dev/null
+++ b/ice/X2.C
@@ -0,0 +1,29 @@
+#include <stdio.h>
+
+
+extern pcbios_getvmode();
+extern pcbios_aputs(char *x, unsigned int y);
+extern pcbios_rowcol();
+extern pcbios_cls();
+
+void main()
+
+{
+    static char x1[]="This is 0,0";
+    static char x2[]="This is 3,4";
+    static char x3[]="This is 10,75";
+    static char x4[]="This is 24,0";
+    static char x5[]="This is 24,77";
+
+    pcbios_rowcol(0,0);
+    printf("%s", x1);
+    pcbios_rowcol(3,4);
+    pcbios_aputs(x2, 7);
+    pcbios_rowcol(10,75);
+    pcbios_aputs(x3, 7);
+    pcbios_rowcol(24,0);
+    pcbios_aputs(x4, 7);
+    pcbios_rowcol(24,77);
+    pcbios_aputs(x5, 7);
+
+}
diff --git a/lj-env/LJ-ENV.BAS b/lj-env/LJ-ENV.BAS
new file mode 100644
index 0000000..7f3f3cc
--- /dev/null
+++ b/lj-env/LJ-ENV.BAS
@@ -0,0 +1,39 @@
+10 '     HP Laser Jet Envelope Printing Utility Version 1.0
+20 '     Copyright (C), 1985 by T.A. Daneliuk  Chicago, IL
+30 '     Last Modified 11/21/85
+40 '
+50 '
+60 '
+70 CLEAR 1500:LM=55:TM=22:LINES=5
+80 CLS:WIDTH "lpt1:",132
+90 PRINT "HP Laser Jet Envelope Printing Utility Version 1.0"
+100 PRINT "Copyright (C), 1985 by T.A. Daneliuk Chicago, IL"
+110 PRINT:PRINT:PRINT
+120 ESC$=CHR$(27)
+130 INIT$=ESC$+"&l1O"+ESC$+"&l3H"+ESC$+"(s3B"
+140 RES$=ESC$+"E"
+150 FOR Y=1 TO LINES
+160      PRINT "Input Line ";Y;": ";
+170      LINE INPUT A$(Y-1)
+180 NEXT Y
+190 PRINT:PRINT
+200 FOR Y=1 TO LINES
+210      PRINT A$(Y-1)
+220 NEXT Y
+230 PRINT:PRINT:PRINT "Is this correct (Y/N)? ";
+240 A$=INKEY$:IF A$="N" OR A$="n" THEN GOTO 70
+250 IF A$<>"Y" AND A$<>"y" THEN GOTO 240
+260 PRINT:LPRINT INIT$;
+270 FOR X=1 TO TM
+280     LPRINT TAB(LM)" "
+290 NEXT X
+300 FOR Y=1 TO LINES
+310     LPRINT STRING$(LM," ");A$(Y-1)
+320 NEXT Y
+330 LPRINT ESC$+"&l1H"+RES$;
+340 PRINT:PRINT:PRINT "Print Again (Y/N)? ";
+350 B$=INKEY$:IF B$="Y" OR B$="y" THEN GOTO 190
+360 IF B$="N" OR B$="n" THEN GOTO 70
+370 GOTO 350
+380 END
+
\ No newline at end of file
diff --git a/ljtoibm/LJTOIBM.ASM b/ljtoibm/LJTOIBM.ASM
new file mode 100644
index 0000000..4b98173
--- /dev/null
+++ b/ljtoibm/LJTOIBM.ASM
@@ -0,0 +1,206 @@
+
+		PAGE	40,132
+		TITLE	LJTOIBM.ASM
+;
+;
+; **********
+; * LJTOIBM.ASM - Laser Jet -> IBM Graphics XLATE - VERSION 1.2.3
+; * LAST MODIFIED: 11/24/85
+; * COPYRIGHT (C) 1985 BY T.A. DANELIUK
+; **********
+;
+;
+; **********
+; * SYSTEM EQUATES
+; **********
+;
+;
+SPACE		EQU	20H				; ASCII SPACE
+DOS		EQU	21H				; DOS INTERRUPT
+EOL		EQU	0A0DH				; END-OF-LINE STRING
+EXIT		EQU	4CH				; NORMAL EXIT TO DOS
+GET_IR_VECT	EQU	35H				; GET VECTOR FROM IR TABLE
+PRINTER_IR	EQU	17H				; PRINTER IR VECTOR
+PRINT_STRING	EQU	09H				; IR TO PRINT STRING ON DISPLAY
+SET_IR_VECT	EQU	25H				; SET AN IR VECTOR IN TABLE
+TAB		EQU	09H				; ASCII TAB
+TAIL_BEGIN	EQU	81H				; OFFSET OF COMMAND TAIL IN PSP
+TAIL_LENGTH	EQU	80H				; LOC OF LENGTH BYTE IN CMD TAIL
+TERMINATE	EQU	31H				; TERMINATE/STAY RESIDENT
+;
+;
+;
+; **********
+; * CODE SEGMENT
+; **********
+;
+;
+LJ_XL		SEGMENT WORD 'CODE'
+		ASSUME	CS:LJ_XL,DS:LJ_XL,ES:LJ_XL
+;
+;
+
+		ORG	100H
+;
+START_RUN	EQU	THIS BYTE
+;
+;
+START:		JMP	INIT				; GO TO INITIALIZATION CODE
+;
+;
+; TRANSLATION TABLE FROM IBM TO LASER JET CHARACTER SET
+;
+;
+;
+TABLE		DB	000H,001H,002H,003H,004H,005H,006H,007H
+		DB	008H,009H,00AH,00BH,00CH,00DH,00EH,00FH
+		DB	0FDH,0FBH,012H,013H,014H,015H,016H,017H
+		DB	018H,019H,01AH,01BH,01CH,01DH,01EH,01FH
+		DB	020H,021H,022H,023H,024H,025H,026H,027H
+		DB	028H,029H,02AH,02BH,02CH,02DH,02EH,02FH
+		DB	030H,031H,032H,033H,034H,035H,036H,037H
+		DB	038H,039H,03AH,03BH,03CH,03DH,03EH,03FH
+		DB	040H,041H,042H,043H,044H,045H,046H,047H
+		DB	048H,049H,04AH,04BH,04CH,04DH,04EH,04FH
+		DB	050H,051H,052H,053H,054H,055H,056H,057H
+		DB	058H,059H,05AH,05BH,05CH,05DH,05EH,05FH
+		DB	060H,061H,062H,063H,064H,065H,066H,067H
+		DB	068H,069H,06AH,06BH,06CH,06DH,06EH,06FH
+		DB	070H,071H,072H,073H,074H,075H,076H,077H
+		DB	078H,079H,07AH,07BH,07CH,07DH,07EH,07FH
+		DB	0B4H,0CFH,0C5H,0C0H,0CCH,0C8H,0D4H,0B5H
+		DB	0C1H,0CDH,0C9H,0DDH,0D1H,0D9H,0D8H,0D0H
+		DB	0DCH,0D7H,0D3H,0C2H,0CEH,0CAH,0C3H,0CBH
+		DB	0EEH,0DAH,0DBH,0BFH,0BBH,0BCH,020H,0BEH
+		DB	0C4H,0D5H,0C6H,0C7H,0B7H,0B6H,0F9H,0FAH
+		DB	0B9H,02DH,02DH,0F8H,0F7H,0B8H,0FBH,0FDH
+		DB	07FH,07FH,07FH,07CH,07CH,07CH,02DH,02DH
+		DB	02DH,07CH,07CH,02DH,02DH,02DH,02DH,02DH
+		DB	02DH,02DH,02DH,07CH,02DH,02BH,07CH,07CH
+		DB	02DH,02DH,02DH,02DH,07CH,02DH,02BH,02DH
+		DB	02DH,02DH,02DH,02DH,02DH,02DH,02DH,02BH
+		DB	02BH,02DH,02DH,0FCH,0FCH,0FCH,0FCH,0FCH
+		DB	020H,0DEH,020H,020H,020H,020H,020H,020H
+		DB	020H,020H,020H,020H,020H,0D2H,020H,020H
+		DB	020H,0FEH,020H,020H,020H,020H,020H,020H
+		DB	0B3H,020H,020H,020H,020H,020H,020H,020H
+;
+;
+LJ_IBM	EQU	THIS BYTE
+;
+; FIRST COMES THE HEADER
+;
+		JMP SHORT ENTRY
+		DW OFFSET END_RUN-1			; LAST ADDR. OF RESIDENT CODE
+MOD_NAME	DB	'LJTOIBM '			; NAME OF MODULE IN ASCII
+;
+; THE FOLLOWING 4 HEADER BYTES ARE APPLICATION DEFINED.
+;
+		DB	0
+		DB	0
+		DB	0
+		DB	0
+;
+; NOW THE ACTUAL RESIDENT INTERRUPT CODE
+;
+ENTRY:		PUSH	AX				; SAVE CHARACTER
+		OR	AH,AH				; WE ONLY DEAL WITH 0
+		JNZ	RUN_DONE
+		PUSH	BX
+		MOV	BX, OFFSET TABLE		; GET TABLE LOCATION
+		PUSH	DS
+		PUSH	CS
+		POP	DS
+		XLAT					; GET SUBSTITUTE CHARACTER
+		POP	DS
+		POP	BX
+RUN_DONE:	PUSHF					; FAKE AN INTERRUPT
+		CALL DWORD PTR	CS:OLD_VECTOR		; CALL ORIGINAL ROUTINE
+;
+GO_BACK		EQU	THIS BYTE
+;
+		CLI					; INTERRUPTS OFF FOR NOW
+		MOV	CS:TEMP,AH			; SAVE RETURN STATUS
+		POP	AX				; GET ORIGINAL CHARACTER BACK
+		MOV	AH,CS:TEMP
+		IRET					; BACK TO THE OUTSIDE WORLD
+;
+OLD_VECTOR	DD	?
+TEMP		DB	?
+;
+END_RUN		EQU	THIS BYTE
+;
+;
+		PAGE
+; **********
+; * LOADER/INSTALL CODE
+; **********
+;
+;
+INIT: 		PUSHF					; SAVE IR STATUS
+		CLI					; TURN 'EM OFF FOR NOW
+;
+;
+; DISPLAY BANNER
+;
+;
+		MOV	DX,OFFSET MSG1
+		MOV	AH,PRINT_STRING
+		INT	DOS
+;
+;
+; GET EXISTING PRINTER VECTOR AND SAVE FOR CHAINING
+;
+;
+CHAIN_IR:	MOV	AH,GET_IR_VECT			; FUNCTION NUMBER
+		MOV	AL,PRINTER_IR			; INTERRUPT NUMBER
+		INT	DOS
+		MOV	BP,OFFSET OLD_VECTOR
+		MOV	CS:[BP],BX			; WE GOT THE OLD VECTOR IN ES:BX
+		MOV	BX,ES				; GET SEGMENT
+		MOV	CS:[BP+2],BX
+;
+;
+; STUFF NEW VECTOR INTO TABLE SO WE GET CONTROL FIRST
+;
+;
+		MOV	DX,OFFSET LJ_IBM		; VECTOR IN DS:DX - DS ALREADY OK
+		MOV	AH,SET_IR_VECT
+		MOV	AL,PRINTER_IR
+		INT	DOS
+;
+;
+; TERMINATE, BUT STAY RESIDENT EXIT CODE
+;
+;
+RESIDE_EXIT:	MOV	AX,OFFSET END_RUN		; CALCULATE MODULE LENGTH IN PARAS
+		MOV	CL,10H				; DIVISOR
+		DIV	CL
+		AND	AH,AH				; ANY REMAINDER?
+		JZ	NO_REMAINDER			; NO
+		INC	AL				; YES, BUMP A FULL PARAGRAPH
+NO_REMAINDER:	XOR	DX,DX				; CLEAR DX
+		MOV	DL,AL				; TERMINATE FN. NEEDS LENGTH IN DX
+		XOR	AL,AL				; SET RETURN ERROR CODE TO 0
+		MOV	AH,TERMINATE			; TERMINATE & STAY RESIDENT FN
+		POPF					; RESET ORIGINAL IR STATUS
+		INT	DOS				; DO THE DOS CALL
+		PAGE
+; BANNER MESSAGE STRINGS
+;
+;
+MSG1		DW	EOL
+		DB	'LJTOIBM - LASER JET TO IBM CHARACTER XLATE - Version 1.2.3'
+		DW	EOL
+		DB	'Copyright (c) 1985, T.A. Daneliuk, Chicago, IL 60625'
+		DW	EOL
+		DB	'Permission Granted To Reproduce This Program'
+		DW	EOL
+		DB	'For PERSONAL, *** NON-COMMERCIAL *** Use Only!'
+		DW	EOL,EOL
+		DB	'$'
+;
+;
+;
+LJ_XL		ENDS
+		END	START
diff --git a/loan/loan.c b/loan/loan.c
new file mode 100644
index 0000000..b4f031b
--- /dev/null
+++ b/loan/loan.c
@@ -0,0 +1,175 @@
+From UICVM.UIC.EDU!INDYCMS.BITNET!COHERENT  Sat Jan 18 12:08:38 1992 remote from clout
+Received: by eskimo.chi.il.us (smail2.5-coherent) id AA00378; 18 Jan 92 12:08:38 
+Received: by clout.chi.il.us (/\==/\ Smail3.1.25.1 #25.2)
+	id <m0l5EM3-000542C@clout.chi.il.us>; Sat, 18 Jan 92 05:36 CST
+Message-Id: <m0l5EM3-000542C@clout.chi.il.us>
+Received: from UICVM by UICVM.UIC.EDU (IBM VM SMTP V2R1) with BSMTP id 8127;
+   Sat, 18 Jan 92 05:35:53 CST
+Received: from UICVM.BITNET by UICVM (Mailer R2.07) with BSMTP id 1875; Sat, 18
+ Jan 92 05:35:48 CST
+Date:         Fri, 17 Jan 1992 20:00:53 GMT
+Reply-To:     "Coherent operating system" <COHERENT%INDYCMS.bitnet@UICVM.UIC.EDU>
+Sender:       "Coherent operating system" <COHERENT%INDYCMS.bitnet@UICVM.UIC.EDU>
+From:         Mike Willett <mike%ARRAY.COM@UICVM.UIC.EDU>
+Subject:      Source file "loan.c"
+Comments: To: coherent@indycms.iupui.edu
+To:           Multiple recipients of list COHERENT <COHERENT@INDYCMS>
+
+Since the interest rates have been falling here in the States, and many
+people (such as myself) want to take advantage of this money saver, I
+made some minor changes to this program I have had around forever so
+that it would run on Coherent. Don't hold me to the accuracy of the
+output, it could be improved by a super C hack, but, it is good enough
+for most of us to get an excellent idea what the loan payments would be...
+
+Enjoy and best regards!  Kom-sa-hom-ni-da!
+
+--Mike
+
+
+/*
+ * Note to Coherent Users:  compile with:
+ *                                cc -o loan loan.c -f -lm
+ *  --Mike
+ *
+ * loan.c
+ * @(#) loan.c amoritization program
+ *
+ * acronym:    loan amortization program
+ *             ----
+ *
+ * purpose:	calculates monthly payment, future value
+ *		and creates an amortization schedule
+ *
+ * 06/27/84	Bill Gregg, Informatics General Corp.
+ * 07/12/84     Revision 1
+ * 07/12/84	Revision 2
+ * 11/05/85	Jane Medefesser, Implementation NPSN Unix (wilbur)
+ *		compile as follows: 'cc -o <outfile> loan.c -lm'
+ * 12/05/85	Changes to direct output to a file.
+ * 03/02/88	Implemented on Eternity 5.3.1
+ * 01/15/92	Mike Willett, added P&I field and pause function
+ * 		and minor library changes to port to Coherent
+ *                     (compile with   cc -o loan loan.c -f -lm)
+ */
+
+#include <stdio.h>
+#include <math.h>
+
+/*
+ *
+ */
+
+main() 		/* loan program */
+{
+	float amt, term, rate, ic, total;
+	float r, temp, pmt, fv;
+	float exp, prin, x, y, mbeg, mnbr, yrint = 0;
+	int month, i, k, a = 0, yr=1;
+	char d, filename[9], c;
+	FILE *fp;
+
+
+
+
+	/*  prompt for input from terminal  */
+
+	printf("Enter principal amount: ");
+	scanf("%f", &amt);
+
+	printf("Enter term in years: ");
+	scanf("%f", &term);
+
+	printf("Enter interest rate in percent: ");
+	scanf("%f", &rate);
+
+	printf("Enter month payments begin (ex: 8 = August): ");
+	scanf("%f", &mbeg);
+
+	/*  compute payment and future value  */
+
+	r = rate/100.0;
+	x = 1.0 + r/12.0;
+	y = term*12.0;
+	temp = (1.0 / pow(x,y));
+	pmt = (amt*r/12.0) / (1-temp);
+	k = term*12;
+	fv = pmt*k;
+	ic = fv - amt;
+
+	printf("Do you want the report directed to a file or to the screen?");
+	printf("\n[f = file / s = screen] : ");
+	d = getchar();      /* This is only here to eat up the '\n' left over
+			       from the last scanf. */
+	d = getchar();
+	switch(d) {
+	     case 'f':
+	     d = getchar();
+	     printf("\nEnter a filename: ");
+	     scanf("%s", filename);
+	     while((c = getchar()) != '\n') {
+	     filename[a] = c; a++; }
+	     fp = fopen(filename, "w");
+	     break;
+	     default:
+	     fp = stdout;
+	     break;
+	     }
+
+	     /*  print header  */
+
+	   fprintf(fp,"\n\t *** Amortization Schedule ***\n\n");
+	   fprintf(fp,"Principal:  %.2f\n", amt);
+	   fprintf(fp,"Future value:  %.2f\n", fv);
+	   fprintf(fp,"Term of loan in years:  %.1f\n", term);
+	   fprintf(fp,"Interest Rate:  %3.3f\n", rate);
+	   fprintf(fp,"Total Interest Charge:  %.2f\n", ic);
+	   fprintf(fp,"Payment:  %.2f\n", pmt);
+	   fprintf(fp,"\nMONTH  PRINCIPAL        INTEREST       TOTAL PMT
+ BALANCE\n");
+
+	   /* start of loop to print amortization schedule */
+
+	   mnbr=mbeg;
+	   for (i=1; i<=k; i++) {
+	      month = i;
+	      exp = amt*(r/12.0);
+	      yrint=yrint+exp;
+	      prin = pmt-exp;
+	      amt = amt-prin;
+	      total = prin + exp;
+	      mnbr++;
+	      fprintf(fp,"%d\t %.2f\t\t %.2f\t\t %.2f\t\t
+ %.2f\n",month,prin,exp,total,amt);
+	      if (mnbr > 12 ) {
+	      fprintf(fp,"\t\tInterest paid for year %d is %.2f\n\n",yr,yrint);
+	      yr++;
+		pause();
+	      yrint=0;
+	      mnbr=1;
+              }
+}
+	     fprintf(fp,"\t\tInterest paid for year %d is %.2f\n\n",yr,yrint);
+	     fclose(fp);
+}
+
+pause()
+{
+
+static int flag;
+
+	if(flag!=1)
+	{
+	getchar(); /* Flush buffer since we are not in raw mode */
+	flag=1;
+	}
+
+	printf("Press return to continue:");
+	while(getchar() !='\012');
+}
+
+--
+Michael Willett, mike@array.com    uupsi!monarch!mike   uunet!csn!monarch!mike
+		So much fun, so little time to enjoy it...
+
+
diff --git a/lookey/LOOKEY.C b/lookey/LOOKEY.C
new file mode 100644
index 0000000..cf3d787
--- /dev/null
+++ b/lookey/LOOKEY.C
@@ -0,0 +1,27 @@
+/*  LOOKEY.C - 	This utility gets a keystroke from STDIN and displays both
+				the decimal and hexadecimal equivalent values on STDOUT.
+
+	Last Modified: 01/01/85 - Copyright (c) 1985 By T.A. Daneliuk		*/
+
+
+#include	<stdio.h>
+
+main()
+
+{
+
+char	c;
+int		i;
+static char	array[3]={"\0\0\0"};
+
+while ((c=bdos(7,0,0)) != 0x1A)			/* Cntrl-Z Terminates */
+	
+	{		
+
+	i = (int) c;						/* Cast to integer value */
+	tohex2(i,array);					/* Get 2 digit hex equivalent */
+	printf("%c	Key Value Is: %d Decimal	%s Hexadecimal\n",c,i,array);
+	
+	}
+
+}
\ No newline at end of file
diff --git a/macro/MACRO.TXT b/macro/MACRO.TXT
new file mode 100644
index 0000000..706d970
--- /dev/null
+++ b/macro/MACRO.TXT
@@ -0,0 +1,660 @@
+	     Calling Macros in DOS.INC and BIOS.INC
+
+You are	responsible for	saving and restoring registers used in
+macros.	The "Registers used" field identifies registers	to save.
+
+Macros that accept address parameters use internal macros that
+allow you to specify addresses in several ways.	The macro
+automatically identifies the type of the argument and handles it
+appropriately. For example, assume the following declarations:
+
+  String    DB	 "test$"
+  pString   DW	 Str
+  fpString  DD	 Str
+
+Given these values, the	macro @DispStr (which displays the string
+at DS:DX) has the following effects:
+
+  Kind of argument	    Example		  Value	loaded
+
+  Label	of byte	variable    @DispStr String	  DS:OFFSET String
+  Near pointer variable	    @DispStr pString	  DS:pString
+  Far pointer variable	    @DispStr fpString	  fpString[2]:fpString[0]
+  Constant		    @DispStr 0		  DS:0
+  Pointer in register	    @DispStr si		  DS:SI
+  Near Pointer with segment @DispStr pString,es	  ES:pString
+  Constant with	segment	    @DispStr 0,es	  ES:0
+  Register with	segment	    @DispStr di,es	  ES:DI
+
+Note that if a far pointer or a	segment	is given, DS must be
+saved before the macro call and	restored afterward. Segments may
+be given as registers, constants, or word variables.
+
+In syntax, parameters enclosed in brackets are optional.
+Paramaters sometimes have a leading symbol to indicate that the
+argument must have a certain type, as shown below:
+
+  Leading Symbol   Example	Limitation
+
+	#	   #return	Must be	constant
+	&	   &vector	Must be	offset address as described above
+	$	   $terminator	May be constant	or register, but not memory
+
+Parameters with	no leading symbol may be constants, registers, or
+variables. Parameters are 16-bit except	where noted in the description.
+
+Symbols	must be	previously defined before they can be passed as
+arguments to most of the DOS macros. Generally this means that
+data must be declared before code in the source	file.
+
+		  DOS Macro Syntax and Description
+
+KEYBOARD INPUT
+
+@GetKey	(01h, 07h, 08h,	0Ch)
+
+Gets a keystroke from the keyboard
+
+Syntax:		@GetKey	[#echo]	[,[#break] [,#clearbuf]]
+
+Arguments:	echo	    = nonzero to echo keystroke	- default yes
+		break	    = nonzero to accept	Control-C - default yes
+		clearbuf    = nonzero to clear keyboard	buffer - default no
+		(Arguments may be omitted to get defaults)
+Return:		ASCII code of key in AL
+Registers used:	AX used	for all, DL used if echo on and	ctrl-c off
+
+
+@GetStr	(0Ah)
+
+Gets a string from the keyboard
+
+Syntax:		@GetStr	&buffer	[,[$terminator]	[,[#limit] [,segment]]]
+
+Arguments:	buffer	    = Offset of	buffer where string will be stored
+		    Byte 1  = Maximum length of	string (before call)
+		    Byte 2  = Actual length of string (after call)
+		    Byte 3+ = Bytes of string
+		terminator  = Terminating byte - usually null (0) or $ (24h)
+		limit	    = Maximum length of	string (if not given as
+			      argument,	must be	in buffer before macro call)
+		segment	    = Segment of buffer	(DS if not given)
+Return:		Pointer	to string in SI, length	of string in BX
+Registers used:	AX, DX,	BX, SI
+
+OUTPUT
+
+@DispCh	(02h)
+
+Displays one or	more characters	to screen
+
+Syntax:		@DispCh	char [,char]...
+
+Arguments:	char	    = 8-bit ASCII code
+Return:		Code in	AL
+Registers used:	AX and DL
+
+
+@PrtCh (05h)
+
+Prints one or more characters to LPT1
+
+Syntax:		@PrtCh char [,char]...
+
+Arguments:	char	    = 8-bit ASCII code
+Return:		Code in	AL
+Registers used:	AX and DL
+
+
+@DispStr (09h)
+
+Displays a $-terminated	string
+
+Syntax:		@DispStr &address [,segment]
+
+Arguments:	address	    = Address of string	terminated by "$" (24h)
+		segment	    = Segment of address string	(DS if not given)
+Return:		None
+Registers used:	AX and DS
+
+DEVICE I/O
+
+@Read (3Fh)
+
+Reads data from	a file or device
+
+Syntax:		@Read &buffer, length [,[handle] [,segment]]
+
+Arguments:	buffer	    = Offset of	buffer where data will be stored
+		length	    = Length of	data in	bytes
+		handle	    = File or device handle; if	none given,
+			      keyboard (handle 0) is assumed
+		segment	    = Segment of address string	(DS if not given)
+Return:		If carry clear,	bytes read in AX
+Registers used:	Always AX, DX, BX, and CX; DS if segment changed
+
+
+@Write (40h)
+
+Writes data to a file or device
+
+Syntax:		@Write &buffer,	length,	[,[handle] [,segment]]
+
+Arguments:	buffer	    = Offset of	buffer where data is stored
+		length	    = Length of	data in	bytes
+		handle	    = File or device handle; if	none given, screen
+			      (handle 1) is assumed
+		segment	    = Segment of address string	(DS if not given)
+Return:		If carry clear,	bytes written in AX
+Registers used:	Always AX, DX, BX, and CX; DS if segment changed
+
+FILE CONTROL
+
+@MakeFil (3Ch, 5Ah, 5Bh)
+
+Creates	a file
+
+Syntax:		@MakeFil &path [,[attrib] [,[segment] [,#kind]]]
+
+Arguments:	path	    = ASCIIZ string of file
+		attrib	    = File atrribute (0	is default if none given)
+		segment	    = Segment of address string	(DS if not given)
+		kind	    = If none given, a file is always created even if
+			      one already exists. Under	DOS 3+ "tmp" can be
+			      given to create a	unique file or "new" to	create
+			      file only	if one doesn't already exist.
+Return:		If carrry clear, file handle in	AX
+Registers used:	Always AX, DX, and CX; DS if segment changed
+
+
+@OpenFil (3Dh)
+
+Opens a	file for input or output
+
+Syntax:		@OpenFil &path,	#access	[,segment]
+
+Arguments:	path	    = ASCIIZ string of file
+		access	    = File access code
+		segment	    = Segment of address string	(DS if not given)
+Return:		If carrry set, error code in AX
+Registers used:	Always AX and DX; DS if	segment	changed
+
+
+@ClosFil (3Eh)
+
+Closes an open file handle
+
+Syntax:		@ClosFil handle
+
+Arguments:	handle	    = Previously opened	file handle
+Return:		If carrry set, error code in AX
+Registers used:	AX and BX
+
+
+@DelFil	(41h)
+
+Deletes	a specified file
+
+Syntax:		@DelFil	&path [,segment]
+
+Arguments:	path	    = Offset of	ASCIIZ filespec
+		segment	    = Segment of path (DS if none given)
+Return:		If carrry set, error code in AX
+Registers used:	AX and DX; DS if segment changed
+
+@MoveFil (56h)
+
+Moves or renames a file	by changing its	path specification.
+
+Syntax:		@MoveFil &old, &new [,[segold] [,segnew]]
+
+Arguments:	old	    = Offset of	file spec to be	renamed
+		new	    = Offset of	new file spec
+		segold	    = Segment of old name (DS if none given)
+		segnew	    = Segment of new name (ES if none given)
+Return:		If carry set, error code in AX
+Registers used:	AX, DX,	and DI;	DS and ES if corresponding segments changed
+
+
+@GetFirst (4Eh)	and @GetNext (4Fh)
+
+Parses file specifications (optionally including wild cards) into
+file names
+
+Syntax:		@GetFirst &path	[,[attribute] [,segment]]
+		@GetNext
+
+Arguments:	path	    = Offset of	ASCIIZ filespec	(can have wild cards)
+		attribute   = File attribute to	search for (0 for normal if
+			      none given)
+		segment	    = Segment of path (DS if none given)
+Return:		If carrry set, error code in AX
+Registers used:	@GetFirst   = AX, CX, and DX; DS if segment changed
+		@GetNext    = AX only
+
+
+@GetDTA	(1Ah) and @SetDTA (2Fh)
+
+Gets or	sets the Disk Transfer Address (DTA)
+
+Syntax:		@GetDTA
+		@SetDTA	&buffer	[,segment]
+
+Arguments:	buffer	    = Offset of	new DTA	buffer
+		segment	    = Segment of new DTA buffer	(DS if none given)
+Return:		@GetDTA	    = ES:BX points to DTA
+		@SetDTA	    = None
+Registers used:	AX for both; DS	and DX for @SetDTA; ES and BX for @GetDTA
+
+@GetFilSz (42h)
+
+Gets the file size by moving the file pointer to end of	the file.
+Note that the file pointer is reset to zero. Thus this macro should
+not be called during operations	that move the pointer.
+
+Syntax:		@GetFilSz handle
+
+Arguments:	handle	    = Previously opened	file handle
+Return:		If carrry clear, file length in	DX:AX
+Registers used:	AX, BX,	CX, and	DX
+
+
+@MovePrtAbs and	@MovePtrRel (42h)
+
+Moves the file pointer in an open file.	The pointer can	be moved to
+an absolute position, or relative to its current position.
+
+Syntax:		@MovePrtAbs handle [,distance]
+		@MovePrtRel handle [,distance]
+
+Arguments:	handle	    = Previously opened	file handle
+		distance    = Distance to move pointer - must be a 16-bit
+			      constant or a 16-	or 32-bit variable; or
+			      leave blank and set distance in CX:DX before
+			      macro call
+Return:		If carrry clear, file pointer position in DX:AX
+Registers used:	AX, BX,	CX, and	DX
+
+DIRECTORY CONTROL
+
+@MkDir,	(39h), @RmDir (3Ah), and @ChDir	(3Bh)
+
+Creates, deletes, or changes to	the specified directory
+
+Syntax:		@MkDir &path [,segment]
+		@RmDir &path [,segment]
+		@ChDir &path [,segment]
+
+Arguments:	path	    = Offset of	ASCIIZ string to
+		segment	    = Segment of path (DS if none given)
+Return:		If carrry set, error code in AX
+Registers used:	AX and DX; DS if segment changed
+
+
+@GetDir	(47h)
+
+Returns	the current directory of the specified drive
+
+Syntax:		@GetDir	&path [,[drive]	[,segment]]
+
+Arguments:	buffer	    = Offset of	buffer to receive ASCIIZ directory
+		drive	    = 8-bit drive number - 0=current, 1=A, 2=B,	etc.
+			      (0 if none given)
+		segment	    = Segment of path (DS if none given)
+Return:		If carrry set, error code in AX
+Registers used:	AX, SI,	and DL;	DS if segment changes
+
+
+DRIVE CONTROL
+
+@GetDrv	(0Eh) and @SetDrv (19h)
+
+Gets or	sets the current drive
+
+Syntax:		@GetDrv
+		@SetDrv	drive
+
+Argument:	drive	    = 8-bit drive number (0=A, 1=B, etc.)
+Return:		@GetDrv	    = Drive number in AL (0=A, 1=B, etc.)
+		@SetDrv	    = Number of	drives in AL
+Registers used:	AX for both; DL	for @SetDrv
+
+
+@ChkDrv	(36h)
+
+Gets various data about	a disk
+
+Syntax:		@ChkDrv	[drive]
+
+Argument:	drive	    = 8-bit drive number (0=current,A=1, B=2, etc.);
+			      if none given, current assumed
+Return:		AX	    = Sectors per cluster (-1 if drive invalid)
+		BX	    = Available	clusters
+		CX	    = Bytes per	sector
+		DX	    = Clusters per drive
+Registers used:	AX, BX,	CX, and	DX
+
+PROCESS	CONTROL
+
+@Exit (4Ch)
+
+Exits to DOS with return code
+
+Syntax:		@Exit [#return]
+
+Argument:	return	    = 8-bit code to return to DOS; if none given,
+			      AL is used
+Return:		None
+Registers used:	AX
+
+
+@Exec (4Bh)
+
+Executes a child process or an overlay
+
+Syntax:		@Exec path, params [,[segpath] [,[segparams] [,overlay]]]
+
+Arguments:	path	    = Offset of	ASCIIZ filespec	to be executed
+		params	    = Offset of	process	parameter block
+		segpath	    = Segment of filespec (DS if none given)
+		segparams   = Segment of parameter block (ES if	none given)
+		overlay	    = If not defined, normal process executed;
+			      if defined, overlay executed
+Return:		If carry set, error code
+Registers used:	AX, SI,	and DI;	DS and ES if corresponding segments given
+
+
+@GetRet	(4Dh)
+
+Gets the return	code of	a child	process
+
+Syntax:		@GetRet
+
+Argument:	None
+Return:		Return code in AX
+Register used:	AX
+
+
+@TSR (31h)
+
+Terminates a program, but leaves it resident in	memory
+
+Syntax:		@TSR paragraphs	[,#return]
+
+Arguments:	return	    = Code to return to	DOS; if	none, AL used
+		paragraphs  = Memory in	paragraphs (16 bytes) to
+			      allocate for resident program
+Return:		None
+Registers used:	AX and DX
+
+MEMORY CONTROL
+
+@FreeBlok (49h)
+
+Frees a	block of memory
+
+Syntax:		@FreeBlok [segment]
+
+Argument:	segment	    = Starting address of memory to be freed;
+			      if none, ES address assumed
+Return:		If carry set, error code in AX
+Register used:	AX; ES if segment given
+
+
+@GetBlok (48h)
+
+Allocates a block of memory
+
+Syntax:		@GetBlok paragraphs
+
+Argument:	paragraphs  = Paragraphs (16 bytes) of memory wanted
+Return:		AX and ES   = Segment address of allocated memory
+		BX	    = Paragraphs actually allocated (may be
+			      less than	requested if memory is short)
+Register used:	AX and BX
+
+
+@ModBlok (48h)
+
+Modifies an allocated block of memory
+
+Syntax:		@ModBlok paragraphs [,segment]
+
+Argument:	paragraphs  = Paragraphs (16 bytes) of memory wanted
+		segment	    = Starting address of memory to be freed;
+			      if none, ES address assumed
+Return:		If carry set, error code in AX,	else:
+			ES  = Segment address of allocated memory
+			BX  = If carry is clear, paragraphs allocated
+Register used:	AX and BX; ES if segment given
+
+MISCELLANEOUS
+
+@GetDate (2Ah) and @SetDate (2Bh)
+
+Gets or	sets the system	date
+
+Syntax:		@GetDate
+		@SetDate month,	day, year
+
+Arguments:	year	    = 16-bit year (1980-2099)
+		month	    = 8-bit month (1-12)
+		day	    = 8-bit day	(1-31)
+Return:		For @GetDate:
+			AL  = Day of week (0 = Sunday, 1 = Monday, etc.)
+			CX  = Year (1980-2099)
+			DL  = Month (1-12)
+			DH  = Day (1-31)
+		For @SetDate:
+			AL  = If date was valid	0, else	-1
+Registers used:	AX, CX,	and DX
+
+
+@GetTime (2Ch) and @SetTime (2Dh)
+
+Gets or	sets the system	time
+
+Syntax:		@GetTime
+		@SetTime hour,minute,second,hundredth
+
+Arguments:	hour	    = 8-bit hour (0-23)
+		minute	    = 8-bit hour (0-59)
+		second	    = 8-bit hour (0-59)
+		hundredth   = 8-bit hour (0-99)
+Return:		For @GetTime:
+			CL  = Hour (0-23)
+			CH  = Minute (0-59)
+			DL  = Second (0-59)
+			DH  = Hundredth	(0-99)
+		For @SetTime:
+			AL  = If time was valid	0, else	-1
+Registers used:	AX, CX,	and DX
+
+
+@GetVer	(30h)
+
+Gets the DOS version
+
+Syntax:		@GetVer
+
+Argument:	None
+Return:		AL	    = Major version (0 for versions prior to 2.0)
+		AH	    = Minor version
+		BH	    = OEM serial number
+		BL:CX	    = 24-bit user number
+Register used:	AX, BX,	and CX
+
+@GetInt	(35h) and @SetInt (25h)
+
+Gets or	sets the vector	for a specified	interrupt routine
+
+Syntax:		@GetInt	#interrupt
+		@SetInt	#interrupt, &vector [,segment]
+
+Arguments:	interrupt   = 8-bit interrupt number
+		vector	    = Offset of	interrupt routine
+		segment	    = Segment of routine - if none given, DS assumed
+			      for data;	segment	ignored	for code labels
+Return:		@GetInt	    = None
+		@SetInt	    = ES:BX points to interrupt	routine
+Registers used:	AX for both; ES	and BX for @GetInt; DS and DS for @SetInt
+
+		 BIOS Macro Syntax and Description
+
+
+MODE, PAGE, AND	COLOR CONTROL
+
+@GetMode (I 10h	F 0Fh)
+
+Gets the current video mode and	page
+
+Syntax:		@GetMode
+
+Arguments:	None
+Return:		AL	    = Mode
+		AH	    = Width in characters
+		BH	    = Page
+Registers used:	AX and BH
+
+
+@SetMode (I 10h	F 00h)
+
+Gets the current video mode and	page
+
+Syntax:		@SetMode mode
+
+Arguments:	mode	    = 8-bit video mode
+Return:		none
+Registers used:	AX
+
+
+@SetColor (I 10h F 0Bh)
+
+Sets the background color
+
+Syntax:		@SetColor color
+
+Arguments:	color	    = 8-bit background color (0-15);
+			      border color in text modes
+Return:		none
+Registers used:	AX and BX
+
+
+@SetPalet (I 10h F 0Bh)
+
+Sets the color palette
+
+Syntax:		@SetPalet color
+
+Arguments:	color	    = 8-bit color palette (0-1 for modes 5 and 6)
+Return:		none
+Registers used:	AX and BX
+
+@SetPage (I 10h	F 05h)
+
+Sets the video page
+
+Syntax:		@SetPage page
+
+Arguments:	page	    = 8-bit page number; 0-3 for modes 2 and 3
+Return:		none
+Registers used:	AX
+
+
+CHARACTER AND CURSOR CONTROL
+
+@GetCur	(I 10h F 04h)
+
+Gets the cursor	position and size
+
+Syntax:		@GetCur	[page]
+
+Arguments:	page	    = 8-bit page with cursor (if none, 0 assumed)
+Return:		DL	    = Column
+		DH	    = Row
+		CL	    = Starting scan line
+		CH	    = Ending scan line
+Registers used:	AX, DX,	CX, and	BH
+
+
+@SetCurPos (I 10h F 02h)
+
+Sets the cursor	position
+
+Syntax:		@SetCurSz [column] [,[row] [,page]]
+
+Arguments:	column	    = 8-bit column; if none, DL	used
+		row	    = 8-bit row; if none, DH used
+		page	    = 8-bit page with cursor (if none, 0 assumed)
+Return:		none
+Registers used:	AX, DX,	and BH
+
+
+@SetCurSz (I 10h F 01h)
+
+Sets the cursor	size and shape by specifying active scan lines.	The
+CGA adapter the	lines are 0-7. The monochrome adapter has lines	0-13.
+
+Syntax:		@SetCurSz startline, endline
+
+Arguments:	startline   = 8-bit starting scan line (default	CGA=6; MA=12)
+		endline	    = 8-bit ending scan	line (default CGA=7; MA=13)
+Return:		none
+Registers used:	AX and CX
+
+@GetChAtr (I 10h F 08h)
+
+Gets the character and attribute at the	cursor location
+
+Syntax:		@GetChAtr [page]
+
+Arguments:	page	    = 8-bit page to check (if none, 0 assumed)
+Return:		AH	    = Attribute
+		AL	    = ASCII character
+Registers used:	AX and BH
+
+
+@PutChAtr (I 10h F 09h)	and @PutCh (I 10h F 0Ah)
+
+Puts one or more characters and	attributes at the current cursor
+position. For @PutCh, the current attribute is used in text modes
+and any	specified attribute is ignored.
+
+Syntax:		@PutChAtr [character] [,[attrib] [,[page] [,count]]]
+
+Arguments:	character   = 8-bit ASCII character to put; if none, AL	used
+		attrib	    = 8-bit attribute to put; if none, BL used
+		page	    = 8-bit page to put	on (if none, 0 assumed)
+		count	    = Number to	put (if	none, 1	assumed)
+Return:		AH	    = Attribute
+		AL	    = ASCII character
+Registers used:	AX, BX,	CX
+
+
+@Scroll	(I 10h F 06h and 07h)
+
+Scrolls	a specified window up or down
+
+Syntax:		@Scroll	dist [,[attr] [,[uprow [,[upcol	[,[dnrow] [,dncol]]]]]
+
+Arguments:	dist	    = 8-bit number of lines to scroll; positive
+			      scrolls down; negative scrolls up; 0 clears
+		attr	    = 8-bit attribute for blank	lines (if none,	07h)
+		uprow	    = Upper left row (if none, CH used)
+		upcol	    = Upper left column	(if none, CL used)
+		dnrow	    = Lower right row (if none,	DH used)
+		dncol	    = Lower right column (if none, DL used)
+Return:		none
+Registers used:	AX, CX,	DX, and	BH
+
+
+@Cls (I	10h F 06, 08h, and 02h)
+
+Clears the screen of the current page
+
+Syntax:		@Cls
+
+Arguments:	None
+Return:		None
+Registers used:	AX, BX,	CX, and	DX
+
diff --git a/masm/MASM.TXT b/masm/MASM.TXT
new file mode 100644
index 0000000..8a4b504
--- /dev/null
+++ b/masm/MASM.TXT
@@ -0,0 +1,1184 @@
+		    Microsoft(R) Macro Assembler Package
+			      Version 5.10
+		   Copyright 1988, Microsoft Corporation
+
+Text files on the Macro	Assembler disks	are tabbed to save
+disk space. If your printer does not automatically handle
+tabs during printing, you must use a print program that
+expands	tabs. For example, use the DOS PRINT program to	print
+this and other document	or source files	on the disk.
+
+	
+		The Microsoft Macro Assembler (MASM)
+
+Mixed-Language Support for Variables and Procedures
+---------------------------------------------------
+All EXTRN, PUBLIC, and PROC items, as well as uses of the .MODEL
+directive, support a language type.  The language type of EXTRN
+and PUBLIC variables determine whether or not an underscore is
+prefixed to the name (an underscore is prefixed only for variables
+with a C language type), and the language type of a procedure determines
+its calling and naming conventions.  For an explanation of calling
+and naming conventions, see the Microsoft Mixed-Language Programming
+Guide.
+
+The language type consists of the word "C" or "Pascal" and uses the
+following syntax (lowercase items are placeholders, and bracketed items
+are optional):
+
+EXTRN [<langtype>] <varname>:<type>
+PUBLIC [<langtype>] <varname>
+procName PROC [NEAR|FAR] [<langtype>] [USES <regs>,] <args>
+
+For example, the C and Pascal keywords are used correctly in the
+following example:
+
+	.MODEL	SMALL,C
+	EXTRN	Pascal DosOpen:FAR
+	PUBLIC	C myVar
+myOpen	PROC	Pascal fName:PTR, mode:WORD
+.
+.
+.
+myOpen	ENDP
+
+
+EVEN and ALIGN Directives
+-------------------------
+Padding for EVEN and ALIGN is now optimized.  Data segments
+are padded with zeros.	Code segments are padded with special
+two-byte NOP instructions where possible.  The two-byte NOP
+consists of the instruction XCHG BX,BX (87 DB hexadecimal)
+which is executed faster than two one-byte NOP instructions.
+        
+/B Option Ignored
+-----------------
+The /B option is now ignored, because its effect is irrelevant,
+given the new file buffering mechanism.  However, the option is
+still accepted for the purposes of compatibility.
+        
+The PTR Operator
+----------------
+The PTR	operator can be	used to	specify	the size of a
+register indirect operand for a	CALL or	JMP instruction.
+However, the size cannot be specified with NEAR	or FAR.	Use
+WORD or	DWORD instead. (In 80386 32-bit	segments, use DWORD
+or FWORD.) Examples are	shown below:
+
+	  ; 8086, 80826, or 80386 16-bit mode
+
+	  jmp  WORD PTR	[bx]	    ; Legal near jump
+	  call NEAR PTR	[bx]	    ; Illegal near call
+	  call DWORD PTR [bx]	    ; Legal far	call
+	  jmp  FAR PTR [bx]	    ; Illegal far jump
+
+	  ; 80386 32-bit mode only
+
+	  jmp  DWORD PTR [bx]	    ; Legal near jump
+	  call NEAR PTR	[bx]	    ; Illegal near call
+	  call FWORD PTR [bx]	    ; Legal far	call
+	  jmp  FAR PTR [bx]	    ; Illegal far jump
+
+This limitation	only applies to	register indirect operands.
+NEAR or	FAR can	be applied to operands associated with
+labels.	Examples are shown below:
+
+	  jmp  NEAR PTR	pointer[bx] ; Legal
+	  call FAR PTR location	    ; Legal
+
+Assembler Behavior Change
+-------------------------
+Some errors and	questionable practices that were ignored by
+earlier	versions are now flagged as errors. As a result,
+existing source	code may produce errors	or warnings.
+The following are examples:
+
+	  - Labels defined only during pass 1 cause errors if
+	    used in expressions.
+	  - A CS ASSUME that changes from pass 1 to pass 2 causes
+	    an error.
+	  - Constants are now checked for type overflow.
+	  - Reserved words used	as labels produce warnings.
+	  - The	OFFSET operator	used with a constant causes an error.
+
+The STACK Combine Type
+----------------------
+The description of the STACK combine type in Section 5.2.2.3
+does not explain how multiple initialized stack	segments are
+combined. The total size of the	stack is the total size	of
+all stack definitions. LINK puts initialized data for each
+defined	stack segment at the end of the	stack. Data initialized
+in the last segment linked override data initialized in
+previous segments. This behavior is usually not relevant, since
+most programs only define one stack of uninitialized data.
+Stack data cannot be initialized with simplified segment
+directives.
+
+Clarification of Parsing Error
+------------------------------
+The following error can be difficult to interpret because of the
+way the assembler parses (analyzes) source code:
+
+A2015: Symbol already different kind: <name>
+
+Typically, the assembler generates this error message when a
+symbol is used in a way inconsistent with how it was declared: for
+example, a symbol is declared as an external absolute but then used
+as a local code label.  However, the assembler also generates this
+error when a symbol in the second source-code field can be interpreted
+as either an operation or an operand.  The following example illustrates
+this problem:
+
+SYM1	MACRO	structName, varName
+varName	structName	<>
+	ENDM
+
+SYM2	STRUCT
+field1	DB
+field2	DW
+SYM2	ENDS
+
+
+SYM1	SYM2, <mylabel>
+
+The last line of code causes error A2015 to be generated.  The
+assembler first looks at the second field of the line, which
+contains the symbol SYM2.  Since SYM2 is a structure, the assembler
+considers SYM2 to be an operation rather than an operand, and therefore
+it considers SYM1 to be a label (rather than an operation). The way
+to avoid this error is simply code the instruction as:
+
+SYM1	<SYM2>, <mylabel>
+
+
+HIGH and LOW Operators
+----------------------
+The HIGH and LOW operators work reliably only with constants
+and with offsets to external symbols.  HIGH and LOW operations are
+not supported for offsets to local symbols.
+
+Mixed-Mode Programming (386 Only)
+---------------------------------
+When assembling code for .386 mode, the assembler now supports direct-
+addressing modes between segments with different USE sizes.  (Segments can
+have the USE16 or USE32 attribute; these attributes refer to the default
+size of offsets.)  Direct-addressing references to labels in other segments
+are correctly resolved.  In the following example, the assembler correctly
+uses a 32-bit offset to access the data at label a32:
+
+.386
+SEG32	SEGMENT	USE32
+a32	DD	?
+SEG32	ENDS
+
+SEG16	SEGMENT	USE16
+	assume ds:seg32
+	mov	eax,a32
+SEG16	ENDS
+
+You can also execute a CALL or a JMP to a label in a segment with a
+different USE size.  However, the label must be declared FAR, and the
+CALL or JMP must not be a forward reference.  The following example
+shows the correct method for executing such a CALL or JMP:
+
+.386
+COD16	SEGMENT	USE16	'CODE'
+proc16	PROC	FAR
+	ret
+proc16	ENDP
+
+lab16	LABEL	FAR
+COD16	ENDS
+
+COD32	SEGMENT	USE32	'CODE'
+	call	proc16
+	jmp	lab16
+COD32	ENDS
+
+Additional Error Messages
+-------------------------
+
+19	Wrong type of register
+
+The register specified in the operand field was incompatible with the
+directive or instruction in the operation field.  For example, the following
+instruction causes this error because you cannot increment the
+code segment:
+
+	inc cs
+
+
+36	Extra NOP inserted
+
+During pass 1 the assembler did not have enough information to
+correctly infer the length of the encoding for the instruction.
+During pass 2 the encoding was found to be shorter than the space
+allocated from pass 1, so one or more NOP instructions were inserted
+as padding.  It may be possible to generate a smaller amount of code
+by eliminating a forward reference to a symbol.
+
+
+	   The Microsoft Cross-Reference Utility (CREF)
+
+New Feature
+-----------
+Cross-reference	listing	files created with CREF	now have an
+additional symbol. A line number followed by + indicates
+that a symbol is modified at the given line. For example:
+
+	  TST .	. . . .	. . . .	. . . .	.  134#	  237	 544+
+
+The symbol TST is defined at line 134, used at line 237, and
+modified at line 544.
+
+
+                          The Mouse Driver
+
+If you use the Microsoft Mouse with the Microsoft CodeView(R) debugger
+you must have Version 6.0 or later of the Microsoft Mouse. If you do not, use
+the version of the MOUSE.COM driver provided in this package.  Copy MOUSE.COM
+to the appropriate mouse directory. When you are ready to use the mouse, type
+
+	mouse
+
+at the DOS command level. If you want to install the mouse driver automatically
+every time you reboot,  insert the "mouse" command in your AUTOEXEC.BAT file.
+
+Note that in earlier releases of Microsoft C, both the MOUSE.SYS and the
+MOUSE.COM driver were provided.  If you have been using an earlier version
+of the MOUSE.SYS driver, delete the following line from your CONFIG.SYS file:
+
+	device=\<directory>\mouse.sys
+
+where <directory> is the directory where the earlier mouse driver resides.
+
+
+    		      Microsoft CodeView Debugger
+
+New Command-Line Option
+-----------------------
+If you have an IBM Personal System/2, then you can use the /50
+command-line option to start the CodeView debugger in 50-line mode.
+Note that you must be in 25-line mode to effectively use either the
+/43 or /50 command-line option.
+
+CONFIG.SYS Setting for CVP
+--------------------------
+To run the protected-mode CodeView debugger (CVP.EXE), you must have
+the following line in your CONFIG.SYS file:
+
+	IOPL=YES
+
+
+Using the 7 Command in Protected Mode
+-------------------------------------
+If you are using OS/2 protected mode and have a math coprocessor, then
+you need to use a patch before you can use the CVP 7 command.  To apply
+the patch, use the OS2PATCH.EXE and PTRACE87.PAT files that come on the
+same disk that CVP.EXE comes on.  You also need to locate the PATCH.EXE file
+that comes with OS/2 and make sure that this file is in a directory listed
+in your PATH environment variable.  Then follow these steps:
+
+1) Change the current drive and directory to the root directory of the
+   boot disk.  (If the boot disk is a floppy, make sure it is inserted
+   in the drive you used to boot from.)
+
+2) Give the following command line at the DOS prompt:
+
+   OS2PATCH /A PTRACE87.PAT
+
+Note that you may need to give the complete path names for the
+OS2PATCH.EXE and for the PTRACE87.PAT file.  You do not need to give
+a path name for the OS2PATCH.EXE file if you have placed this file
+in a directory listed in your PATH environment variable.
+
+Using the Real-Mode Debugger in the Compatibility Box
+-----------------------------------------------------
+When running the real-mode CodeView debugger in the DOS 3.x
+compatibility box, start the debugger with the /S command-line
+option.  Otherwise, the mouse pointer will not appear.
+
+Using the CodeView Debugger with BIND
+-------------------------------------
+The real-mode CodeView debugger cannot debug bound (dual-mode)
+applications.  However, the protected-mode CodeView debugger,
+CVP, can debug bound applications.
+
+Expression Evaluator for BASIC Programs
+---------------------------------------
+In the BASIC expression evaluator, "+" is not supported for string
+concatenation.
+
+Stack Trace Command
+-------------------
+In order for the Stack Trace command (or the Calls menu) to work
+reliably, you need to execute to at least the beginning of the main
+function or procedure, and the current module should have full CodeView
+information (a module has full CodeView information if compiled or
+assembled with /Zi).
+
+Error Messages
+--------------
+The error message "? cannot display" indicates that the Display
+Expression command (?) has been passed a valid symbol that it
+cannot display. In previous versions of the debugger, structures
+could not be displayed. With current version of the debugger, only
+the enums type cannot be displayed.
+
+The error message "Expression not a memory address" occurs when
+the Tracepoint command is given without a symbol that evaluates to
+a single memory address.  For example, the commands "TP?1" and
+"TP?a+b" each produce this error message.  The proper way to put a
+tracepoint on the word at address 1 is with the command "TPW 1".
+
+The error message "Function call before 'main'" occurs when you
+attempt to evaluate a program-defined function before you have entered
+the main function.  Execute to at least to the beginning of the main
+function before attempting to evaluate program-defined functions.
+
+The error message "Bad emulator info" occurs when CodeView cannot
+read data from the floating-point emulator.
+
+The error message "Floating point not loaded" has a special meaning
+for CVP (in addition to the explanation given in the CodeView and
+Utilities manual).  Each thread has its own floating-point emulator.
+This message is issued when the current thread has not initialized
+its own emulator.
+
+Microsoft Pascal Programs
+-------------------------
+In this release, Microsoft Pascal programs cannot be debugged with
+the CodeView debugger.
+
+
+			     Exit Codes for Utilities
+
+The exit codes for LINK and the utilities in the Microsoft CodeView
+and Utilities manual should appear as follows:
+
+LINK
+----
+	Code	Meaning
+
+	0	No error.
+
+	2	Program error--something was wrong with the commands
+		or files input to the linker.
+
+	4	System error.  The linker
+
+		- ran out of space on output files
+		- was unable to reopen the temporary file
+		- experienced an internal error
+		- was interrupted by the user
+
+LIB, EXEPACK, EXEMOD, MAKE, and SETENV
+---------------------------------------
+	Code	Meaning
+
+	0	No error.
+
+	2	Program error--something was wrong with the commands
+		or files input to the utility.
+
+	4	System error.  The utility ran out of memory, was
+		interrupted by the user, or experienced an internal
+		error.
+
+		    Microsoft Overlay Linker (LINK)
+
+Overlay Restrictions
+--------------------
+You cannot use long jumps (using the longjmp library function) or indirect
+calls (through a function pointer) to pass control to an overlay.  When a
+function is called through a pointer, the called function must be in the same
+overlay or in the root.
+
+Changed LINK Error Messages
+---------------------------
+The explanation for fatal-error message L1008 is changed as follows: 
+
+	The /SEGMENTS option specified a limit greater than 3072 on the
+	number of segments allowed.
+
+Error message L1009 has been changed to read as follows:
+
+	L1009	<number> : CPARMAXALLOC : illegal value
+
+Error message L1053 has been changed to read as follows:
+
+	L1053   out of memory for symbol table
+
+	The program had more symbolic information (such as public, external,
+	segment, group, class, and file names) than the amount that could fit
+	in available real memory.
+
+	Try freeing memory by linking from the DOS command level instead of
+	from a MAKE file or from an editor. Otherwise, combine modules or
+	segments and try to eliminate as many public symbols as possible.
+
+Warning message L4050 has been changed as follows:
+
+	L4050	too many public symbols for sorting
+
+	The linker uses the stack and all available memory in the
+	near heap to sort public symbols for the /MAP option.  If
+	the number of public symbols exceeds the space available
+	for them, this warning is issued, and the symbols are not
+	sorted in the map file but are listed in arbitrary order.
+
+New LINK Error Messages
+-----------------------
+L1003	/QUICKLIB, /EXEPACK incompatible
+
+You cannot link with both the /QU option and the /E option.
+
+L1006   <option-text>: stack size exceeds 65535 bytes
+
+The value given as a parameter to the /STACKSIZE option exceeds the
+maximum allowed.
+
+L1063	out of memory for CodeView information
+
+The linker was given too many object files with debug information,
+and the linker ran out of space to store it.  Reduce the number
+of object files that have debug information.
+
+L1115   /QUICKLIB, overlays incompatible
+
+You specified overlays and used the /QUICKLIB option.
+These cannot be used together.
+
+L2013	LIDATA record too large
+
+An LIDATA record contained more than 512 bytes.  This is
+probably a compiler error.
+
+L2024   <name>: special symbol already defined
+
+Your program defined a symbol name that is already used by the linker
+for one of its own low-level symbols.  (For example, the linker
+generates special symbols used in overlay support and other operations.)
+Choose another name for the symbol in order to avoid conflict.
+
+L2025   <segmentname>: segment with > 1 class name not allowed with /INC
+
+Your program defined a segment more than once, giving the segment
+different class names.  Different class names for the same segment
+are not allowed when you link with the /INCREMENTAL option.  Normally,
+this error should never appear unless you are programming with MASM.
+For example, if you give the two MASM statements
+
+_BSS segment 'BSS'
+
+and
+
+_BSS segment 'DATA'
+
+then the statements have the effect of declaring two distinct segments.
+ILINK does not support this situation, so it is disallowed when the
+/INCREMENTAL option is used.
+
+
+L2041	stack plus data exceed 64K
+
+The total of near data and requested stack size exceeds 64K, 
+and the program will not run correctly.  Reduce the stack size.
+The linker only checks for this condition if /DOSSEG
+is enabled, which is done automatically in the library
+startup module.
+
+L2043	Quick Library support module missing
+
+When creating a Quick library, you did not link with the required
+QUICKLIB.OBJ module.
+
+L2044	<name> : symbol	multiply defined, use /NOE
+
+The linker found what it interprets as a public-symbol
+redefinition, probably because you have redefined a symbol that
+is defined in a library.  Relink with the /NOEXTDICTIONARY
+(/NOE) option. If error L2025 results for the same symbol, then you
+have a genuine symbol-redefinition error.
+
+L4003	intersegment self-relative fixup at <offset> in segment <name>
+	pos: <offset> Record type: 9C target external '<name>'
+
+The linker found an intersegment self-relative fixup. This error
+may be caused by compiling a small-model program with the /NT
+option. 
+
+L4034	more than 239 overlay segments; extra put in root
+
+Your program designated more than the limit of 239 segments to 
+go in overlays.  Starting with the 234th segment, they are assigned to 
+the root (that is, the permanently resident portion of the program).
+
+
+		Microsoft Library Manager (LIB)
+
+New Option
+----------
+There is a new option for LIB:  /NOIGNORECASE (abbreviated as /N).
+This option tells LIB to not ignore case when comparing symbols.
+names. By default, LIB ignores case.  Multiple symbols that are
+the same except for case can be put in the same library.  An
+example of this is: "_Open" and "_open". Normally you could not
+add both these symbols to the same library.
+
+Note that if a library is built with /NOI, the library is
+internally "marked" to indicate /NOI.	All libraries built
+with earlier versions of LIB are not marked.
+
+If you combine multiple libraries, and any one of them is
+marked /NOI, then /NOI is assumed for the output library.
+
+In addition, LIB also supports the option /IGNORECASE (/I), which
+is completely analogous to /NOIGNORECASE.  /I is the default. The only
+reason to use it would be if you have an existing library marked /NOI
+that you wanted to combine with other libraries which were not marked,
+and have the output library be not marked. If you don't use
+/IGNORECASE, the output is marked /NOI (see above).
+
+Changed LIB Error Messages
+--------------------------
+Warning	messages U4152,	U4155, and U4157-U4159 for LIB are now
+nonfatal error messages	U2152, U2155, and U2157-U2159, respectively.
+
+Warning message U4151 has been changed to read as follows:
+
+	U4151	'<name>' : symbol defined in module <name>, redefinition ignored
+
+New LIB Error Messages
+----------------------
+The following new warning messages have	been added for LIB:
+
+U4155	<modulename> : module not in library
+
+A module specified to be replaced does not already exist in the 
+library.  LIB adds the module anyway.
+
+U4157	insufficient memory, extended dictionary not created
+U4158	internal error,	extended dictionary not	created
+
+For the	reason indicated, LIB could not	create an extended
+dictionary. The	library	is still valid,	but the	linker
+is not able to take advantage of the extended dictionary
+to speed linking. 
+
+
+		Microsoft Program Maintenance Utility (MAKE)
+
+New Error Message
+-----------------
+U1015: <file> : error redirection failed
+
+This error occurs if the /X option is given and error output cannot
+be redirected to the given file (for example, because the file
+is read-only).
+
+Inference Rules
+---------------
+You cannot have inference rules in both the TOOLS.INI and the description
+file that use both the same inextension and outextension.  For example, you
+cannot place the following inference rule in the TOOLS.INI file:
+
+	.c.obj:
+		cl /c /Zi /Od $*.c
+
+while also placing the following line in the description file:
+
+	.c.obj:
+		cl /Ot $*.c
+
+However, you can define the same macro in both the TOOLS.INI and the
+description file.  In such cases, the definition in the description file
+takes precedence.
+
+Backslash (\) as Continuation Character
+---------------------------------------
+Note that MAKE considers a backslash immediately followed by a new-line
+character to be a continuation character.  When it finds this combination
+in a description file, MAKE concatenates the line immediately following
+the combination with the line where the combination appears.
+
+If you define a macro that ends in a backslash, make sure that you put a
+space after the terminating backslash.  For example, if you want to define
+macros for the path C:\SRC\BIN and C:\SRC\LIB, you must use the format 
+illustrated below:
+
+	BINPATH=C:\SRC\BIN\<space><newline>
+	LIBPATH=C:\SRC\LIB\<space><newline>
+
+To illustrate the problems that can result if you do not put a space before the
+new-line character, assume that the macros above appear as shown below
+instead: 
+
+	BINPATH=C:\SRC\BIN\<newline>
+	LIBPATH=C:\SRC\LIB\<newline>
+
+Because a new-line character appears immediately after the backslash at the end
+of the first macro, MAKE assumes that you are defining the single macro shown
+below:
+
+	BINPATH=C:\SRC\BIN\LIBPATH=C:\SRC\LIB\
+
+
+
+	    Microsoft STDERR Redirection Utility (ERROUT)
+
+The ERROUT utility does not accept batch files. To redirect standard-error
+output from a batch file, you must enter a command of the following form:
+
+	ERROUT COMMAND /c <batchcommand> 
+
+If no /f option is given, then ERROUT redirects standard-error output to
+the standard-output device.
+
+
+			Mixed-Language Programming
+
+Setting Up Calls to High-Level Languages
+----------------------------------------
+Section 6.6 of the Microsoft Mixed-Language Programming Guide gives in-
+structions for setting up a call to a high-level language from assembly
+language.  Before you execute a call to a BASIC, Pascal, or FORTRAN routine,
+remember to declare an additional parameter if the return value is noninteger.
+This additional parameter must contain the offset address of the return value,
+for which you must allocate room within the stack segment (normally DGROUP,
+the same as the default data segment).
+
+
+                       The BIND Utility
+
+Specifying Libraries
+--------------------
+You need to include DOSCALLS.LIB on the BIND command line. If
+DOSCALLS.LIB is not in the current directory, you must give the 
+complete path name to DOSCALLS.LIB.
+
+BIND automatically searches for API.LIB by looking in directories
+listed in the LIB environment variable.  However, if API.LIB is
+specified on the command line, then BIND will not check the LIB
+environment variable; instead, you will need to give the complete
+path name.
+
+For example, the following command line successfully uses BIND, if
+API.LIB is located in a directory listed in the LIB environment
+variable:
+
+BIND FOO.EXE \LIB\DOSCALLS.LIB
+
+Using BIND with Packed Files
+----------------------------
+The version of BIND released with this package does not work with
+files that have been linked with the /EXEPACK linker option.
+
+Running Bound Files with DOS 2.1
+--------------------------------
+A dual-mode executable file produced with BIND can be run in both
+DOS 3.x and DOS 2.x environments.  However, if you change the name
+of an executable file produced by BIND, then it will not run under
+DOS 2.1.
+
+
+                 The Microsoft Incremental Linker (ILINK)
+
+ILINK Fatal Error Messages
+--------------------------
+
+.sym seek error
+.sym read error
+
+	The .SYM file is corrupted.  Do a full link.  If the error
+	persists, contact Microsoft.
+
+.sym write error
+
+	The disk is full or the .SYM file already exists with the
+	READONLY attribute.
+
+map for segment <name> exceeds 64K
+
+	The symbolic information associated with the given segment
+	exceeds 64K bytes, which is more than ILINK can handle.
+
+can't ilink library <name>
+
+        You tried to incrementally link an altered library.
+	ILINK does not link .LIB files but only .OBJ files.
+	Use a full link instead.
+
+.obj close error
+
+	The operating system returned an error when ILINK attempted
+	to close one of the .OBJ files.  Do a full link.  If the error
+	persists, contact Microsoft.
+
+too many LNAMES in <modname>
+
+	An object module has more than 255 LNAME records.
+
+too many SEGDEFs in <modname>
+
+	The given object module has more than 100 SEGDEF records.
+
+too many GRPDEFs in <modname>
+
+	The given object module has more than 10 GRPDEF records.
+
+symbol <name> multiply defined
+
+	The given symbol is defined more than once.
+
+#3
+
+	Please report this error to Microsoft.
+
+Out of Memory
+
+	ILINK ran out of memory for processing the input.  If you
+	are running ILINK under MAKE, try running it from the shell.
+	Otherwise, do a full link.
+
+could not run exec
+
+	ILINK was unable to find the file EXEC.EXE, which should be
+	placed somewhere in the search path or in the current
+	directory.
+
+.exe file too big, change alignment
+
+	The segment sector alignment value in the .EXE file is too
+	small to express the size of one of the segments.  Do a full
+	link and increase the alignment value with the /ALIGNMENT
+	option to LINK.
+
+.ilk seek error
+
+	The .ILK file is corrupted.  Do a full link.  If the error
+	persists, contact Microsoft.
+
+Too many defined segments
+
+	ILINK has a limit of 255 defined segments, which are segments
+	defined in an object module as opposed to an executable segment.
+	Reduce the number of segments if you want to use ILINK.
+
+too many library files
+
+	ILINK has a limit of 32 runtime libraries (.LIB files).  Reduce
+	the number of libraries.
+
+too many modules
+
+	ILINK has a limit of 1204 modules in a program.  Reduce the
+	number of modules.
+
+.ilk write error
+
+	The disk is full, or else ILINK cannot write to the .SYM file
+	because a .SYM file currently exists and has the READONLY attribute.
+
+file <name> does not exist
+
+	ILINK was unable to open the given file.  The file named was
+	in the file list in the .ILK file.
+
+seek error on library
+
+	A .LIB file was corrupted.  Do a full link and check your .LIB
+	files.
+
+library close error
+
+	The operating system returned an error when ILINK attempted
+	to close one of the .LIB files.  Do a full link.  If the error
+	persists, contact Microsoft.
+
+error closing EXE file
+
+	The operating system returned an error when ILINK attempted
+	to close the .EXE file.  Do a full link.  If the error
+	persists, contact Microsoft.
+
+Invalid module reference <module>
+
+	The program makes a dynamic link reference to a dynamic link
+	module which is not represented in the .EXE file.
+
+could not update time on <filename>
+
+	The operating system returned an error when ILINK attempted
+	to update the time on the given file.  Possibly the file had
+	the READONLY attribute set.
+
+invalid flag <flag>
+only one -e command allowed
+
+	The ILINK command syntax is incorrect.
+
+User Abort
+
+	The user issued CTRL+C or CTRL+BREAK.
+
+file <name> write protected
+
+	The .EXE, .ILK, or .SYM file needed to be updated and has the
+	READONLY attribute.  Change attribute to READWRITE.
+
+file <name> missing
+
+	One of the .OBJ files specified on the command line is missing.
+
+file <name> invalid .OBJ format
+file <name> has invalid <recordtype> record
+
+	The given .OBJ file has an invalid format or one that is not
+	recognized by ILINK.  This may have been caused by a compiler
+	or assembler.
+
+file <module> was not full linked
+
+	An .OBJ file was specified as input to ILINK, which was not in
+	the list of files in the original full link.
+
+LOBYTE seg-relative fixups not supported
+
+	This error message should occur only with MASM files.  See the
+	Microsoft Macro Assembler 5.0 Programmer's Guide. This type of
+	object module is not supported by ILINK.
+
+<number> undefined symbols
+
+	The given number of symbols were referred to in fixups but
+	never publicly defined in the program.
+
+Incremental Violations
+----------------------
+These errors cause a full link to occur if the -e option is used and -i
+is not used, else they are fatal errors:
+
+symbol <name> deleted
+
+	A symbol was deleted from an incrementally-linked module.
+
+<modname> contains new SEGMENT
+
+	A segment was added to the program.
+
+<modname> contains changed segment <name>
+
+	The segment contribution (code or data which the module
+	contributes to a segment) changed for the given module:	it
+	contributed to a segment it didn't previously contribute to,
+	or a contribution was removed.
+
+<modname>'s segment <name> grew too big
+
+	The given segment grew beyond the padding for the given module.
+
+<modname> contains new GROUP <name>
+
+	A new group was defined, via the GROUP directive in assembly
+	language or via the /ND C compiler option.
+
+<modname> redefines group <name> to include <name>
+
+	The members of the given group changed.
+
+symbol <name> changed
+
+	The given data symbol was moved.
+
+can't add new communal data symbol <name>
+
+	A new communal data symbol was added as an uninitialized variable
+	in C or with the COMM feature in MASM.
+
+communal variable <name> grew too big
+
+	The given communal variable changed size too much.
+
+invalid symbol type for <name>
+
+	A symbol which was previously code became data, or vice versa.
+
+too many COMDEFS
+too many EXTDEFS
+
+	The limit on the total of COMDEF records (communal data variables)
+	and EXTDEF records (external references) is 2000.
+
+invalid CodeView information in .EXE file
+
+	The CodeView information found is invalid.
+
+<name> contains new Codeview symbolic info
+
+	A module previously compiled without -Zi was compiled with -Zi.
+
+<name> contains new linnum info
+
+	A module previously compiled without -Zi or -Zd was compiled
+	with -Zi or -Zd.
+
+<name> contains new public CV info
+
+	New information on public-symbol addresses was added.
+
+invalid .exe file
+
+	The .EXE file is invalid.  Make sure you are using an up-to-date
+	linker.  If the error persists, contact Microsoft.
+
+invalid .ilk file
+.ilk read error
+.ilk seek error
+
+	The .ILK file is invalid.  Make sure you are using an up-to-date
+	linker.  If the error persists, contact Microsoft.
+
+.SYM/.ILK mismatch
+
+	The .SYM and .ILK files are out of sync.  Make sure you are using
+	an up-to-date linker.  If the error persists, contact Microsoft.
+
+<libname> has changed
+
+	The given library has changed.
+
+can't link 64K-length segments
+
+	ILINK cannot handle segments greater than 65,535 bytes long.
+
+can't link iterated segments
+
+	ILINK cannot handle programs linked with /EXEPACK.
+
+Entry table expansion not implemented
+
+	The program call tree changed in such a way that ILINK could
+	not handle it.
+
+file <name> does not exist
+
+	The .EXE, .SYM, or .ILK files are missing.
+
+<name> has changed
+
+	The given library module name has changed.
+
+ILINK Warning messages
+----------------------
+
+Fixup frame relative to an (as yet) undefined symbol - assuming ok
+
+	See documentation for LINK error messages L4001 and L4002,
+	in the Microsoft CodeView and Utilities manual.
+
+<name> contains TYPEDEFs - ignored
+<name> contains BLKDEFs - ignored
+
+	The .OBJ file contains records no longer supported by Microsoft
+	language compilers.
+
+old .EXE free information lost
+
+	The free list in the .EXE file has been corrupted.  The free
+	list keeps track of "holes" of free space in the EXE file.  These
+	holes are made available when segments are moved to new locations.
+
+file <name> has no useful contribution
+
+	The given module makes no contribution to any segment.
+
+Main entry point moved
+
+	The program starting address changed.  You may want to consider
+	doing a full link.
+
+
+                             Microsoft Editor
+
+Installing the Editor
+---------------------
+The Microsoft Editor does not come with an MESETUP program. Instead,
+run the setup program for the assembler. This program offers you choices
+about how to set up the editor.
+
+Keystroke Configurations
+------------------------
+Some of the keystroke configurations listed in Table A.2 of the
+Microsoft Editor User's Guide may need to be changed.
+
+In the Quick/WordStar configuration, the Sinsert function is assigned
+to ALT+INS, not CTRL+INS.
+
+In the BRIEF configuration, the Plines function is assigned to CTRL+Z,
+and the Refresh function is assigned to CTRL+].
+
+In the EPSILON configuration, the Ppage function is assigned to PGDN,
+and the Sdelete function is assigned to DEL and CTRL+D.
+
+The Compile Function
+--------------------
+The commands
+
+	Arg streamarg Compile
+        Arg textarg Compile
+
+each use the command specified by the extmake:text switch.  The
+editor does not check the extension of the file name given as an
+argument, but instead uses the "text" extension.  The streamarg
+or textarg replaces a %s in the command.  These commands are typically
+used to invoke MAKE.
+
+The Setfile Function
+--------------------
+The commands that use Setfile, along with a streamarg or textarg,
+accept a variety of input: either the name of a file, a file name
+with a wild-card character (* or ?), the name of a directory, or the
+name of a disk drive.  File names can also include environment variables,
+such as $INIT.  If the streamarg or textarg is a directory name, then
+the editor changes the current directory.  If the argument is a drive
+name, then the editor changes the current drive.  Environment variables
+are translated into directories to be searched for a file.  For example,
+the following macro directs the editor to search the $INIT environment
+variable in order to find the tools.ini file:
+
+    tools.ini := Arg "$INIT:tools.ini" Setfile
+    tools.ini :ctrl+j
+
+Entering Strings in Macros
+--------------------------
+When you enter a text argument directly, no characters have special
+meaning (except when the argument is interpreted as a regular
+expression).  However, when you enter text as part of a macro, then
+strings inside of quotes are interpreted according to the C string
+format.  This format uses a backslash followed by double quotes (\")
+to represent double quotes and it uses two backslashes (\\) to represent
+a single backslash.  Therefore, to find the next occurrence of the string
+
+    She wrote, "Here is a backslash: \ "
+
+you could use the following macro definition:
+
+    findit := Arg "She wrote, \"Here is a backslash: \\ \"" Psearch
+
+Note that to indicate a backslash for a regular expression that is
+also part of a macro definition, you must use four consecutive
+backslashes.
+
+
+Using Text Switches
+-------------------
+The text switches extmake and readonly each take a special
+kind of syntax that allows you to specify drive, file name,
+base name, or file extension. The syntax consists of the
+characters:
+
+%|<letters>F
+
+where <letters> consists of any of the following: "p" for path,
+"d" for drive, "f" for file base name, or "e" for file extension.
+For example, if you are editing the file c:\dir1\sample.c, and you
+make the following switch assignment:
+
+extmake:c cl /Fod:%|pfF %|dfeF
+
+then each time you give the command <Arg><Compile>, the editor
+performs the following system-level command:
+
+cl /Fod:\dir1\sample c:sample.c
+
+The expression "%s" is equivalent to "%|feF" except that the former
+only works once, whereas the latter can appear any number of times
+in the extmake switch assignment. The expression "%|F" is equivalent
+to "%|dpfeF".
+
+The Filetab Switch
+------------------
+The filetab switch is a numeric switch that determines how the
+editor translates tabs when loading a file into memory.  The value
+of the switch gives the number of spaces associated with each tab
+column.  For example, the setting "filetab:4" assumes a tab column
+every 4 positions on each line.  Every time the editor finds a tab
+character in a file, it loads the buffer with the number of spaces
+necessary to get to the next tab column.  Depending on the value of
+the entab switch, the editor also uses the filetab switch to determine
+how to convert spaces into tabs when writing to a file.  The default
+value of filetab is 8.
+
+
+Functions Callable by C Extensions
+----------------------------------
+The following list summarizes functions from the standard compact-
+memory-model library, which should work when called by a C-extension
+module.  (The technique of programming C extensions is presented in 
+Chapter 8 of the Microsoft Editor User's Guide.)  The memory model
+of the extension is assumed to be /Asfu (small code pointers, far
+data pointers, and stack segment unequal to data segment).  This list
+uses the function categories from Chapter 4 of the Microsoft C
+Optimizing Compiler Run-Time Library Reference (Version 4.0
+or later.)
+
+Buffer Manipulation: All functions can be called.
+
+Character Classification and Conversion: All functions can be called.
+
+Data Conversion: All functions can be called except for
+
+     strtod()
+
+Directory Control: All functions can be called except for
+
+     getcwd()
+
+File Handling: All functions can be called.
+
+Low-Level I/O Routines: All functions can be called, but write()
+will not work in binary mode.
+
+Console and Port I/O: All functions can be called except for
+
+     cgets()
+     cprintf()
+     cscanf()
+
+Searching and Sorting: All functions can be called except for
+
+     qsort()
+
+String Manipulation: All functions can be called except for
+
+     strdup()
+
+BIOS Interface: All functions can be called.
+
+MS-DOS Interface: All functions can be called except for
+
+     int86()
+     int86x()
+
+Time: All functions can be called except for
+
+     ctime()
+     gmtime()
+     localtime()
+     utime()
+
+Miscellaneous: All functions can be called except for
+
+     assert()
+     getenv()
+     perror()
+     putenv()
+     _searchenv()
+
+
+Linking Extensions in Protected Mode
+--------------------------------------
+To link C extension modules in protected mode, link with the
+object file EXTHDRP.OBJ, instead of the real-mode header
+EXTHDR.OBJ.
diff --git a/masm5/masm5.txt b/masm5/masm5.txt
new file mode 100644
index 0000000..8a4b504
--- /dev/null
+++ b/masm5/masm5.txt
@@ -0,0 +1,1184 @@
+		    Microsoft(R) Macro Assembler Package
+			      Version 5.10
+		   Copyright 1988, Microsoft Corporation
+
+Text files on the Macro	Assembler disks	are tabbed to save
+disk space. If your printer does not automatically handle
+tabs during printing, you must use a print program that
+expands	tabs. For example, use the DOS PRINT program to	print
+this and other document	or source files	on the disk.
+
+	
+		The Microsoft Macro Assembler (MASM)
+
+Mixed-Language Support for Variables and Procedures
+---------------------------------------------------
+All EXTRN, PUBLIC, and PROC items, as well as uses of the .MODEL
+directive, support a language type.  The language type of EXTRN
+and PUBLIC variables determine whether or not an underscore is
+prefixed to the name (an underscore is prefixed only for variables
+with a C language type), and the language type of a procedure determines
+its calling and naming conventions.  For an explanation of calling
+and naming conventions, see the Microsoft Mixed-Language Programming
+Guide.
+
+The language type consists of the word "C" or "Pascal" and uses the
+following syntax (lowercase items are placeholders, and bracketed items
+are optional):
+
+EXTRN [<langtype>] <varname>:<type>
+PUBLIC [<langtype>] <varname>
+procName PROC [NEAR|FAR] [<langtype>] [USES <regs>,] <args>
+
+For example, the C and Pascal keywords are used correctly in the
+following example:
+
+	.MODEL	SMALL,C
+	EXTRN	Pascal DosOpen:FAR
+	PUBLIC	C myVar
+myOpen	PROC	Pascal fName:PTR, mode:WORD
+.
+.
+.
+myOpen	ENDP
+
+
+EVEN and ALIGN Directives
+-------------------------
+Padding for EVEN and ALIGN is now optimized.  Data segments
+are padded with zeros.	Code segments are padded with special
+two-byte NOP instructions where possible.  The two-byte NOP
+consists of the instruction XCHG BX,BX (87 DB hexadecimal)
+which is executed faster than two one-byte NOP instructions.
+        
+/B Option Ignored
+-----------------
+The /B option is now ignored, because its effect is irrelevant,
+given the new file buffering mechanism.  However, the option is
+still accepted for the purposes of compatibility.
+        
+The PTR Operator
+----------------
+The PTR	operator can be	used to	specify	the size of a
+register indirect operand for a	CALL or	JMP instruction.
+However, the size cannot be specified with NEAR	or FAR.	Use
+WORD or	DWORD instead. (In 80386 32-bit	segments, use DWORD
+or FWORD.) Examples are	shown below:
+
+	  ; 8086, 80826, or 80386 16-bit mode
+
+	  jmp  WORD PTR	[bx]	    ; Legal near jump
+	  call NEAR PTR	[bx]	    ; Illegal near call
+	  call DWORD PTR [bx]	    ; Legal far	call
+	  jmp  FAR PTR [bx]	    ; Illegal far jump
+
+	  ; 80386 32-bit mode only
+
+	  jmp  DWORD PTR [bx]	    ; Legal near jump
+	  call NEAR PTR	[bx]	    ; Illegal near call
+	  call FWORD PTR [bx]	    ; Legal far	call
+	  jmp  FAR PTR [bx]	    ; Illegal far jump
+
+This limitation	only applies to	register indirect operands.
+NEAR or	FAR can	be applied to operands associated with
+labels.	Examples are shown below:
+
+	  jmp  NEAR PTR	pointer[bx] ; Legal
+	  call FAR PTR location	    ; Legal
+
+Assembler Behavior Change
+-------------------------
+Some errors and	questionable practices that were ignored by
+earlier	versions are now flagged as errors. As a result,
+existing source	code may produce errors	or warnings.
+The following are examples:
+
+	  - Labels defined only during pass 1 cause errors if
+	    used in expressions.
+	  - A CS ASSUME that changes from pass 1 to pass 2 causes
+	    an error.
+	  - Constants are now checked for type overflow.
+	  - Reserved words used	as labels produce warnings.
+	  - The	OFFSET operator	used with a constant causes an error.
+
+The STACK Combine Type
+----------------------
+The description of the STACK combine type in Section 5.2.2.3
+does not explain how multiple initialized stack	segments are
+combined. The total size of the	stack is the total size	of
+all stack definitions. LINK puts initialized data for each
+defined	stack segment at the end of the	stack. Data initialized
+in the last segment linked override data initialized in
+previous segments. This behavior is usually not relevant, since
+most programs only define one stack of uninitialized data.
+Stack data cannot be initialized with simplified segment
+directives.
+
+Clarification of Parsing Error
+------------------------------
+The following error can be difficult to interpret because of the
+way the assembler parses (analyzes) source code:
+
+A2015: Symbol already different kind: <name>
+
+Typically, the assembler generates this error message when a
+symbol is used in a way inconsistent with how it was declared: for
+example, a symbol is declared as an external absolute but then used
+as a local code label.  However, the assembler also generates this
+error when a symbol in the second source-code field can be interpreted
+as either an operation or an operand.  The following example illustrates
+this problem:
+
+SYM1	MACRO	structName, varName
+varName	structName	<>
+	ENDM
+
+SYM2	STRUCT
+field1	DB
+field2	DW
+SYM2	ENDS
+
+
+SYM1	SYM2, <mylabel>
+
+The last line of code causes error A2015 to be generated.  The
+assembler first looks at the second field of the line, which
+contains the symbol SYM2.  Since SYM2 is a structure, the assembler
+considers SYM2 to be an operation rather than an operand, and therefore
+it considers SYM1 to be a label (rather than an operation). The way
+to avoid this error is simply code the instruction as:
+
+SYM1	<SYM2>, <mylabel>
+
+
+HIGH and LOW Operators
+----------------------
+The HIGH and LOW operators work reliably only with constants
+and with offsets to external symbols.  HIGH and LOW operations are
+not supported for offsets to local symbols.
+
+Mixed-Mode Programming (386 Only)
+---------------------------------
+When assembling code for .386 mode, the assembler now supports direct-
+addressing modes between segments with different USE sizes.  (Segments can
+have the USE16 or USE32 attribute; these attributes refer to the default
+size of offsets.)  Direct-addressing references to labels in other segments
+are correctly resolved.  In the following example, the assembler correctly
+uses a 32-bit offset to access the data at label a32:
+
+.386
+SEG32	SEGMENT	USE32
+a32	DD	?
+SEG32	ENDS
+
+SEG16	SEGMENT	USE16
+	assume ds:seg32
+	mov	eax,a32
+SEG16	ENDS
+
+You can also execute a CALL or a JMP to a label in a segment with a
+different USE size.  However, the label must be declared FAR, and the
+CALL or JMP must not be a forward reference.  The following example
+shows the correct method for executing such a CALL or JMP:
+
+.386
+COD16	SEGMENT	USE16	'CODE'
+proc16	PROC	FAR
+	ret
+proc16	ENDP
+
+lab16	LABEL	FAR
+COD16	ENDS
+
+COD32	SEGMENT	USE32	'CODE'
+	call	proc16
+	jmp	lab16
+COD32	ENDS
+
+Additional Error Messages
+-------------------------
+
+19	Wrong type of register
+
+The register specified in the operand field was incompatible with the
+directive or instruction in the operation field.  For example, the following
+instruction causes this error because you cannot increment the
+code segment:
+
+	inc cs
+
+
+36	Extra NOP inserted
+
+During pass 1 the assembler did not have enough information to
+correctly infer the length of the encoding for the instruction.
+During pass 2 the encoding was found to be shorter than the space
+allocated from pass 1, so one or more NOP instructions were inserted
+as padding.  It may be possible to generate a smaller amount of code
+by eliminating a forward reference to a symbol.
+
+
+	   The Microsoft Cross-Reference Utility (CREF)
+
+New Feature
+-----------
+Cross-reference	listing	files created with CREF	now have an
+additional symbol. A line number followed by + indicates
+that a symbol is modified at the given line. For example:
+
+	  TST .	. . . .	. . . .	. . . .	.  134#	  237	 544+
+
+The symbol TST is defined at line 134, used at line 237, and
+modified at line 544.
+
+
+                          The Mouse Driver
+
+If you use the Microsoft Mouse with the Microsoft CodeView(R) debugger
+you must have Version 6.0 or later of the Microsoft Mouse. If you do not, use
+the version of the MOUSE.COM driver provided in this package.  Copy MOUSE.COM
+to the appropriate mouse directory. When you are ready to use the mouse, type
+
+	mouse
+
+at the DOS command level. If you want to install the mouse driver automatically
+every time you reboot,  insert the "mouse" command in your AUTOEXEC.BAT file.
+
+Note that in earlier releases of Microsoft C, both the MOUSE.SYS and the
+MOUSE.COM driver were provided.  If you have been using an earlier version
+of the MOUSE.SYS driver, delete the following line from your CONFIG.SYS file:
+
+	device=\<directory>\mouse.sys
+
+where <directory> is the directory where the earlier mouse driver resides.
+
+
+    		      Microsoft CodeView Debugger
+
+New Command-Line Option
+-----------------------
+If you have an IBM Personal System/2, then you can use the /50
+command-line option to start the CodeView debugger in 50-line mode.
+Note that you must be in 25-line mode to effectively use either the
+/43 or /50 command-line option.
+
+CONFIG.SYS Setting for CVP
+--------------------------
+To run the protected-mode CodeView debugger (CVP.EXE), you must have
+the following line in your CONFIG.SYS file:
+
+	IOPL=YES
+
+
+Using the 7 Command in Protected Mode
+-------------------------------------
+If you are using OS/2 protected mode and have a math coprocessor, then
+you need to use a patch before you can use the CVP 7 command.  To apply
+the patch, use the OS2PATCH.EXE and PTRACE87.PAT files that come on the
+same disk that CVP.EXE comes on.  You also need to locate the PATCH.EXE file
+that comes with OS/2 and make sure that this file is in a directory listed
+in your PATH environment variable.  Then follow these steps:
+
+1) Change the current drive and directory to the root directory of the
+   boot disk.  (If the boot disk is a floppy, make sure it is inserted
+   in the drive you used to boot from.)
+
+2) Give the following command line at the DOS prompt:
+
+   OS2PATCH /A PTRACE87.PAT
+
+Note that you may need to give the complete path names for the
+OS2PATCH.EXE and for the PTRACE87.PAT file.  You do not need to give
+a path name for the OS2PATCH.EXE file if you have placed this file
+in a directory listed in your PATH environment variable.
+
+Using the Real-Mode Debugger in the Compatibility Box
+-----------------------------------------------------
+When running the real-mode CodeView debugger in the DOS 3.x
+compatibility box, start the debugger with the /S command-line
+option.  Otherwise, the mouse pointer will not appear.
+
+Using the CodeView Debugger with BIND
+-------------------------------------
+The real-mode CodeView debugger cannot debug bound (dual-mode)
+applications.  However, the protected-mode CodeView debugger,
+CVP, can debug bound applications.
+
+Expression Evaluator for BASIC Programs
+---------------------------------------
+In the BASIC expression evaluator, "+" is not supported for string
+concatenation.
+
+Stack Trace Command
+-------------------
+In order for the Stack Trace command (or the Calls menu) to work
+reliably, you need to execute to at least the beginning of the main
+function or procedure, and the current module should have full CodeView
+information (a module has full CodeView information if compiled or
+assembled with /Zi).
+
+Error Messages
+--------------
+The error message "? cannot display" indicates that the Display
+Expression command (?) has been passed a valid symbol that it
+cannot display. In previous versions of the debugger, structures
+could not be displayed. With current version of the debugger, only
+the enums type cannot be displayed.
+
+The error message "Expression not a memory address" occurs when
+the Tracepoint command is given without a symbol that evaluates to
+a single memory address.  For example, the commands "TP?1" and
+"TP?a+b" each produce this error message.  The proper way to put a
+tracepoint on the word at address 1 is with the command "TPW 1".
+
+The error message "Function call before 'main'" occurs when you
+attempt to evaluate a program-defined function before you have entered
+the main function.  Execute to at least to the beginning of the main
+function before attempting to evaluate program-defined functions.
+
+The error message "Bad emulator info" occurs when CodeView cannot
+read data from the floating-point emulator.
+
+The error message "Floating point not loaded" has a special meaning
+for CVP (in addition to the explanation given in the CodeView and
+Utilities manual).  Each thread has its own floating-point emulator.
+This message is issued when the current thread has not initialized
+its own emulator.
+
+Microsoft Pascal Programs
+-------------------------
+In this release, Microsoft Pascal programs cannot be debugged with
+the CodeView debugger.
+
+
+			     Exit Codes for Utilities
+
+The exit codes for LINK and the utilities in the Microsoft CodeView
+and Utilities manual should appear as follows:
+
+LINK
+----
+	Code	Meaning
+
+	0	No error.
+
+	2	Program error--something was wrong with the commands
+		or files input to the linker.
+
+	4	System error.  The linker
+
+		- ran out of space on output files
+		- was unable to reopen the temporary file
+		- experienced an internal error
+		- was interrupted by the user
+
+LIB, EXEPACK, EXEMOD, MAKE, and SETENV
+---------------------------------------
+	Code	Meaning
+
+	0	No error.
+
+	2	Program error--something was wrong with the commands
+		or files input to the utility.
+
+	4	System error.  The utility ran out of memory, was
+		interrupted by the user, or experienced an internal
+		error.
+
+		    Microsoft Overlay Linker (LINK)
+
+Overlay Restrictions
+--------------------
+You cannot use long jumps (using the longjmp library function) or indirect
+calls (through a function pointer) to pass control to an overlay.  When a
+function is called through a pointer, the called function must be in the same
+overlay or in the root.
+
+Changed LINK Error Messages
+---------------------------
+The explanation for fatal-error message L1008 is changed as follows: 
+
+	The /SEGMENTS option specified a limit greater than 3072 on the
+	number of segments allowed.
+
+Error message L1009 has been changed to read as follows:
+
+	L1009	<number> : CPARMAXALLOC : illegal value
+
+Error message L1053 has been changed to read as follows:
+
+	L1053   out of memory for symbol table
+
+	The program had more symbolic information (such as public, external,
+	segment, group, class, and file names) than the amount that could fit
+	in available real memory.
+
+	Try freeing memory by linking from the DOS command level instead of
+	from a MAKE file or from an editor. Otherwise, combine modules or
+	segments and try to eliminate as many public symbols as possible.
+
+Warning message L4050 has been changed as follows:
+
+	L4050	too many public symbols for sorting
+
+	The linker uses the stack and all available memory in the
+	near heap to sort public symbols for the /MAP option.  If
+	the number of public symbols exceeds the space available
+	for them, this warning is issued, and the symbols are not
+	sorted in the map file but are listed in arbitrary order.
+
+New LINK Error Messages
+-----------------------
+L1003	/QUICKLIB, /EXEPACK incompatible
+
+You cannot link with both the /QU option and the /E option.
+
+L1006   <option-text>: stack size exceeds 65535 bytes
+
+The value given as a parameter to the /STACKSIZE option exceeds the
+maximum allowed.
+
+L1063	out of memory for CodeView information
+
+The linker was given too many object files with debug information,
+and the linker ran out of space to store it.  Reduce the number
+of object files that have debug information.
+
+L1115   /QUICKLIB, overlays incompatible
+
+You specified overlays and used the /QUICKLIB option.
+These cannot be used together.
+
+L2013	LIDATA record too large
+
+An LIDATA record contained more than 512 bytes.  This is
+probably a compiler error.
+
+L2024   <name>: special symbol already defined
+
+Your program defined a symbol name that is already used by the linker
+for one of its own low-level symbols.  (For example, the linker
+generates special symbols used in overlay support and other operations.)
+Choose another name for the symbol in order to avoid conflict.
+
+L2025   <segmentname>: segment with > 1 class name not allowed with /INC
+
+Your program defined a segment more than once, giving the segment
+different class names.  Different class names for the same segment
+are not allowed when you link with the /INCREMENTAL option.  Normally,
+this error should never appear unless you are programming with MASM.
+For example, if you give the two MASM statements
+
+_BSS segment 'BSS'
+
+and
+
+_BSS segment 'DATA'
+
+then the statements have the effect of declaring two distinct segments.
+ILINK does not support this situation, so it is disallowed when the
+/INCREMENTAL option is used.
+
+
+L2041	stack plus data exceed 64K
+
+The total of near data and requested stack size exceeds 64K, 
+and the program will not run correctly.  Reduce the stack size.
+The linker only checks for this condition if /DOSSEG
+is enabled, which is done automatically in the library
+startup module.
+
+L2043	Quick Library support module missing
+
+When creating a Quick library, you did not link with the required
+QUICKLIB.OBJ module.
+
+L2044	<name> : symbol	multiply defined, use /NOE
+
+The linker found what it interprets as a public-symbol
+redefinition, probably because you have redefined a symbol that
+is defined in a library.  Relink with the /NOEXTDICTIONARY
+(/NOE) option. If error L2025 results for the same symbol, then you
+have a genuine symbol-redefinition error.
+
+L4003	intersegment self-relative fixup at <offset> in segment <name>
+	pos: <offset> Record type: 9C target external '<name>'
+
+The linker found an intersegment self-relative fixup. This error
+may be caused by compiling a small-model program with the /NT
+option. 
+
+L4034	more than 239 overlay segments; extra put in root
+
+Your program designated more than the limit of 239 segments to 
+go in overlays.  Starting with the 234th segment, they are assigned to 
+the root (that is, the permanently resident portion of the program).
+
+
+		Microsoft Library Manager (LIB)
+
+New Option
+----------
+There is a new option for LIB:  /NOIGNORECASE (abbreviated as /N).
+This option tells LIB to not ignore case when comparing symbols.
+names. By default, LIB ignores case.  Multiple symbols that are
+the same except for case can be put in the same library.  An
+example of this is: "_Open" and "_open". Normally you could not
+add both these symbols to the same library.
+
+Note that if a library is built with /NOI, the library is
+internally "marked" to indicate /NOI.	All libraries built
+with earlier versions of LIB are not marked.
+
+If you combine multiple libraries, and any one of them is
+marked /NOI, then /NOI is assumed for the output library.
+
+In addition, LIB also supports the option /IGNORECASE (/I), which
+is completely analogous to /NOIGNORECASE.  /I is the default. The only
+reason to use it would be if you have an existing library marked /NOI
+that you wanted to combine with other libraries which were not marked,
+and have the output library be not marked. If you don't use
+/IGNORECASE, the output is marked /NOI (see above).
+
+Changed LIB Error Messages
+--------------------------
+Warning	messages U4152,	U4155, and U4157-U4159 for LIB are now
+nonfatal error messages	U2152, U2155, and U2157-U2159, respectively.
+
+Warning message U4151 has been changed to read as follows:
+
+	U4151	'<name>' : symbol defined in module <name>, redefinition ignored
+
+New LIB Error Messages
+----------------------
+The following new warning messages have	been added for LIB:
+
+U4155	<modulename> : module not in library
+
+A module specified to be replaced does not already exist in the 
+library.  LIB adds the module anyway.
+
+U4157	insufficient memory, extended dictionary not created
+U4158	internal error,	extended dictionary not	created
+
+For the	reason indicated, LIB could not	create an extended
+dictionary. The	library	is still valid,	but the	linker
+is not able to take advantage of the extended dictionary
+to speed linking. 
+
+
+		Microsoft Program Maintenance Utility (MAKE)
+
+New Error Message
+-----------------
+U1015: <file> : error redirection failed
+
+This error occurs if the /X option is given and error output cannot
+be redirected to the given file (for example, because the file
+is read-only).
+
+Inference Rules
+---------------
+You cannot have inference rules in both the TOOLS.INI and the description
+file that use both the same inextension and outextension.  For example, you
+cannot place the following inference rule in the TOOLS.INI file:
+
+	.c.obj:
+		cl /c /Zi /Od $*.c
+
+while also placing the following line in the description file:
+
+	.c.obj:
+		cl /Ot $*.c
+
+However, you can define the same macro in both the TOOLS.INI and the
+description file.  In such cases, the definition in the description file
+takes precedence.
+
+Backslash (\) as Continuation Character
+---------------------------------------
+Note that MAKE considers a backslash immediately followed by a new-line
+character to be a continuation character.  When it finds this combination
+in a description file, MAKE concatenates the line immediately following
+the combination with the line where the combination appears.
+
+If you define a macro that ends in a backslash, make sure that you put a
+space after the terminating backslash.  For example, if you want to define
+macros for the path C:\SRC\BIN and C:\SRC\LIB, you must use the format 
+illustrated below:
+
+	BINPATH=C:\SRC\BIN\<space><newline>
+	LIBPATH=C:\SRC\LIB\<space><newline>
+
+To illustrate the problems that can result if you do not put a space before the
+new-line character, assume that the macros above appear as shown below
+instead: 
+
+	BINPATH=C:\SRC\BIN\<newline>
+	LIBPATH=C:\SRC\LIB\<newline>
+
+Because a new-line character appears immediately after the backslash at the end
+of the first macro, MAKE assumes that you are defining the single macro shown
+below:
+
+	BINPATH=C:\SRC\BIN\LIBPATH=C:\SRC\LIB\
+
+
+
+	    Microsoft STDERR Redirection Utility (ERROUT)
+
+The ERROUT utility does not accept batch files. To redirect standard-error
+output from a batch file, you must enter a command of the following form:
+
+	ERROUT COMMAND /c <batchcommand> 
+
+If no /f option is given, then ERROUT redirects standard-error output to
+the standard-output device.
+
+
+			Mixed-Language Programming
+
+Setting Up Calls to High-Level Languages
+----------------------------------------
+Section 6.6 of the Microsoft Mixed-Language Programming Guide gives in-
+structions for setting up a call to a high-level language from assembly
+language.  Before you execute a call to a BASIC, Pascal, or FORTRAN routine,
+remember to declare an additional parameter if the return value is noninteger.
+This additional parameter must contain the offset address of the return value,
+for which you must allocate room within the stack segment (normally DGROUP,
+the same as the default data segment).
+
+
+                       The BIND Utility
+
+Specifying Libraries
+--------------------
+You need to include DOSCALLS.LIB on the BIND command line. If
+DOSCALLS.LIB is not in the current directory, you must give the 
+complete path name to DOSCALLS.LIB.
+
+BIND automatically searches for API.LIB by looking in directories
+listed in the LIB environment variable.  However, if API.LIB is
+specified on the command line, then BIND will not check the LIB
+environment variable; instead, you will need to give the complete
+path name.
+
+For example, the following command line successfully uses BIND, if
+API.LIB is located in a directory listed in the LIB environment
+variable:
+
+BIND FOO.EXE \LIB\DOSCALLS.LIB
+
+Using BIND with Packed Files
+----------------------------
+The version of BIND released with this package does not work with
+files that have been linked with the /EXEPACK linker option.
+
+Running Bound Files with DOS 2.1
+--------------------------------
+A dual-mode executable file produced with BIND can be run in both
+DOS 3.x and DOS 2.x environments.  However, if you change the name
+of an executable file produced by BIND, then it will not run under
+DOS 2.1.
+
+
+                 The Microsoft Incremental Linker (ILINK)
+
+ILINK Fatal Error Messages
+--------------------------
+
+.sym seek error
+.sym read error
+
+	The .SYM file is corrupted.  Do a full link.  If the error
+	persists, contact Microsoft.
+
+.sym write error
+
+	The disk is full or the .SYM file already exists with the
+	READONLY attribute.
+
+map for segment <name> exceeds 64K
+
+	The symbolic information associated with the given segment
+	exceeds 64K bytes, which is more than ILINK can handle.
+
+can't ilink library <name>
+
+        You tried to incrementally link an altered library.
+	ILINK does not link .LIB files but only .OBJ files.
+	Use a full link instead.
+
+.obj close error
+
+	The operating system returned an error when ILINK attempted
+	to close one of the .OBJ files.  Do a full link.  If the error
+	persists, contact Microsoft.
+
+too many LNAMES in <modname>
+
+	An object module has more than 255 LNAME records.
+
+too many SEGDEFs in <modname>
+
+	The given object module has more than 100 SEGDEF records.
+
+too many GRPDEFs in <modname>
+
+	The given object module has more than 10 GRPDEF records.
+
+symbol <name> multiply defined
+
+	The given symbol is defined more than once.
+
+#3
+
+	Please report this error to Microsoft.
+
+Out of Memory
+
+	ILINK ran out of memory for processing the input.  If you
+	are running ILINK under MAKE, try running it from the shell.
+	Otherwise, do a full link.
+
+could not run exec
+
+	ILINK was unable to find the file EXEC.EXE, which should be
+	placed somewhere in the search path or in the current
+	directory.
+
+.exe file too big, change alignment
+
+	The segment sector alignment value in the .EXE file is too
+	small to express the size of one of the segments.  Do a full
+	link and increase the alignment value with the /ALIGNMENT
+	option to LINK.
+
+.ilk seek error
+
+	The .ILK file is corrupted.  Do a full link.  If the error
+	persists, contact Microsoft.
+
+Too many defined segments
+
+	ILINK has a limit of 255 defined segments, which are segments
+	defined in an object module as opposed to an executable segment.
+	Reduce the number of segments if you want to use ILINK.
+
+too many library files
+
+	ILINK has a limit of 32 runtime libraries (.LIB files).  Reduce
+	the number of libraries.
+
+too many modules
+
+	ILINK has a limit of 1204 modules in a program.  Reduce the
+	number of modules.
+
+.ilk write error
+
+	The disk is full, or else ILINK cannot write to the .SYM file
+	because a .SYM file currently exists and has the READONLY attribute.
+
+file <name> does not exist
+
+	ILINK was unable to open the given file.  The file named was
+	in the file list in the .ILK file.
+
+seek error on library
+
+	A .LIB file was corrupted.  Do a full link and check your .LIB
+	files.
+
+library close error
+
+	The operating system returned an error when ILINK attempted
+	to close one of the .LIB files.  Do a full link.  If the error
+	persists, contact Microsoft.
+
+error closing EXE file
+
+	The operating system returned an error when ILINK attempted
+	to close the .EXE file.  Do a full link.  If the error
+	persists, contact Microsoft.
+
+Invalid module reference <module>
+
+	The program makes a dynamic link reference to a dynamic link
+	module which is not represented in the .EXE file.
+
+could not update time on <filename>
+
+	The operating system returned an error when ILINK attempted
+	to update the time on the given file.  Possibly the file had
+	the READONLY attribute set.
+
+invalid flag <flag>
+only one -e command allowed
+
+	The ILINK command syntax is incorrect.
+
+User Abort
+
+	The user issued CTRL+C or CTRL+BREAK.
+
+file <name> write protected
+
+	The .EXE, .ILK, or .SYM file needed to be updated and has the
+	READONLY attribute.  Change attribute to READWRITE.
+
+file <name> missing
+
+	One of the .OBJ files specified on the command line is missing.
+
+file <name> invalid .OBJ format
+file <name> has invalid <recordtype> record
+
+	The given .OBJ file has an invalid format or one that is not
+	recognized by ILINK.  This may have been caused by a compiler
+	or assembler.
+
+file <module> was not full linked
+
+	An .OBJ file was specified as input to ILINK, which was not in
+	the list of files in the original full link.
+
+LOBYTE seg-relative fixups not supported
+
+	This error message should occur only with MASM files.  See the
+	Microsoft Macro Assembler 5.0 Programmer's Guide. This type of
+	object module is not supported by ILINK.
+
+<number> undefined symbols
+
+	The given number of symbols were referred to in fixups but
+	never publicly defined in the program.
+
+Incremental Violations
+----------------------
+These errors cause a full link to occur if the -e option is used and -i
+is not used, else they are fatal errors:
+
+symbol <name> deleted
+
+	A symbol was deleted from an incrementally-linked module.
+
+<modname> contains new SEGMENT
+
+	A segment was added to the program.
+
+<modname> contains changed segment <name>
+
+	The segment contribution (code or data which the module
+	contributes to a segment) changed for the given module:	it
+	contributed to a segment it didn't previously contribute to,
+	or a contribution was removed.
+
+<modname>'s segment <name> grew too big
+
+	The given segment grew beyond the padding for the given module.
+
+<modname> contains new GROUP <name>
+
+	A new group was defined, via the GROUP directive in assembly
+	language or via the /ND C compiler option.
+
+<modname> redefines group <name> to include <name>
+
+	The members of the given group changed.
+
+symbol <name> changed
+
+	The given data symbol was moved.
+
+can't add new communal data symbol <name>
+
+	A new communal data symbol was added as an uninitialized variable
+	in C or with the COMM feature in MASM.
+
+communal variable <name> grew too big
+
+	The given communal variable changed size too much.
+
+invalid symbol type for <name>
+
+	A symbol which was previously code became data, or vice versa.
+
+too many COMDEFS
+too many EXTDEFS
+
+	The limit on the total of COMDEF records (communal data variables)
+	and EXTDEF records (external references) is 2000.
+
+invalid CodeView information in .EXE file
+
+	The CodeView information found is invalid.
+
+<name> contains new Codeview symbolic info
+
+	A module previously compiled without -Zi was compiled with -Zi.
+
+<name> contains new linnum info
+
+	A module previously compiled without -Zi or -Zd was compiled
+	with -Zi or -Zd.
+
+<name> contains new public CV info
+
+	New information on public-symbol addresses was added.
+
+invalid .exe file
+
+	The .EXE file is invalid.  Make sure you are using an up-to-date
+	linker.  If the error persists, contact Microsoft.
+
+invalid .ilk file
+.ilk read error
+.ilk seek error
+
+	The .ILK file is invalid.  Make sure you are using an up-to-date
+	linker.  If the error persists, contact Microsoft.
+
+.SYM/.ILK mismatch
+
+	The .SYM and .ILK files are out of sync.  Make sure you are using
+	an up-to-date linker.  If the error persists, contact Microsoft.
+
+<libname> has changed
+
+	The given library has changed.
+
+can't link 64K-length segments
+
+	ILINK cannot handle segments greater than 65,535 bytes long.
+
+can't link iterated segments
+
+	ILINK cannot handle programs linked with /EXEPACK.
+
+Entry table expansion not implemented
+
+	The program call tree changed in such a way that ILINK could
+	not handle it.
+
+file <name> does not exist
+
+	The .EXE, .SYM, or .ILK files are missing.
+
+<name> has changed
+
+	The given library module name has changed.
+
+ILINK Warning messages
+----------------------
+
+Fixup frame relative to an (as yet) undefined symbol - assuming ok
+
+	See documentation for LINK error messages L4001 and L4002,
+	in the Microsoft CodeView and Utilities manual.
+
+<name> contains TYPEDEFs - ignored
+<name> contains BLKDEFs - ignored
+
+	The .OBJ file contains records no longer supported by Microsoft
+	language compilers.
+
+old .EXE free information lost
+
+	The free list in the .EXE file has been corrupted.  The free
+	list keeps track of "holes" of free space in the EXE file.  These
+	holes are made available when segments are moved to new locations.
+
+file <name> has no useful contribution
+
+	The given module makes no contribution to any segment.
+
+Main entry point moved
+
+	The program starting address changed.  You may want to consider
+	doing a full link.
+
+
+                             Microsoft Editor
+
+Installing the Editor
+---------------------
+The Microsoft Editor does not come with an MESETUP program. Instead,
+run the setup program for the assembler. This program offers you choices
+about how to set up the editor.
+
+Keystroke Configurations
+------------------------
+Some of the keystroke configurations listed in Table A.2 of the
+Microsoft Editor User's Guide may need to be changed.
+
+In the Quick/WordStar configuration, the Sinsert function is assigned
+to ALT+INS, not CTRL+INS.
+
+In the BRIEF configuration, the Plines function is assigned to CTRL+Z,
+and the Refresh function is assigned to CTRL+].
+
+In the EPSILON configuration, the Ppage function is assigned to PGDN,
+and the Sdelete function is assigned to DEL and CTRL+D.
+
+The Compile Function
+--------------------
+The commands
+
+	Arg streamarg Compile
+        Arg textarg Compile
+
+each use the command specified by the extmake:text switch.  The
+editor does not check the extension of the file name given as an
+argument, but instead uses the "text" extension.  The streamarg
+or textarg replaces a %s in the command.  These commands are typically
+used to invoke MAKE.
+
+The Setfile Function
+--------------------
+The commands that use Setfile, along with a streamarg or textarg,
+accept a variety of input: either the name of a file, a file name
+with a wild-card character (* or ?), the name of a directory, or the
+name of a disk drive.  File names can also include environment variables,
+such as $INIT.  If the streamarg or textarg is a directory name, then
+the editor changes the current directory.  If the argument is a drive
+name, then the editor changes the current drive.  Environment variables
+are translated into directories to be searched for a file.  For example,
+the following macro directs the editor to search the $INIT environment
+variable in order to find the tools.ini file:
+
+    tools.ini := Arg "$INIT:tools.ini" Setfile
+    tools.ini :ctrl+j
+
+Entering Strings in Macros
+--------------------------
+When you enter a text argument directly, no characters have special
+meaning (except when the argument is interpreted as a regular
+expression).  However, when you enter text as part of a macro, then
+strings inside of quotes are interpreted according to the C string
+format.  This format uses a backslash followed by double quotes (\")
+to represent double quotes and it uses two backslashes (\\) to represent
+a single backslash.  Therefore, to find the next occurrence of the string
+
+    She wrote, "Here is a backslash: \ "
+
+you could use the following macro definition:
+
+    findit := Arg "She wrote, \"Here is a backslash: \\ \"" Psearch
+
+Note that to indicate a backslash for a regular expression that is
+also part of a macro definition, you must use four consecutive
+backslashes.
+
+
+Using Text Switches
+-------------------
+The text switches extmake and readonly each take a special
+kind of syntax that allows you to specify drive, file name,
+base name, or file extension. The syntax consists of the
+characters:
+
+%|<letters>F
+
+where <letters> consists of any of the following: "p" for path,
+"d" for drive, "f" for file base name, or "e" for file extension.
+For example, if you are editing the file c:\dir1\sample.c, and you
+make the following switch assignment:
+
+extmake:c cl /Fod:%|pfF %|dfeF
+
+then each time you give the command <Arg><Compile>, the editor
+performs the following system-level command:
+
+cl /Fod:\dir1\sample c:sample.c
+
+The expression "%s" is equivalent to "%|feF" except that the former
+only works once, whereas the latter can appear any number of times
+in the extmake switch assignment. The expression "%|F" is equivalent
+to "%|dpfeF".
+
+The Filetab Switch
+------------------
+The filetab switch is a numeric switch that determines how the
+editor translates tabs when loading a file into memory.  The value
+of the switch gives the number of spaces associated with each tab
+column.  For example, the setting "filetab:4" assumes a tab column
+every 4 positions on each line.  Every time the editor finds a tab
+character in a file, it loads the buffer with the number of spaces
+necessary to get to the next tab column.  Depending on the value of
+the entab switch, the editor also uses the filetab switch to determine
+how to convert spaces into tabs when writing to a file.  The default
+value of filetab is 8.
+
+
+Functions Callable by C Extensions
+----------------------------------
+The following list summarizes functions from the standard compact-
+memory-model library, which should work when called by a C-extension
+module.  (The technique of programming C extensions is presented in 
+Chapter 8 of the Microsoft Editor User's Guide.)  The memory model
+of the extension is assumed to be /Asfu (small code pointers, far
+data pointers, and stack segment unequal to data segment).  This list
+uses the function categories from Chapter 4 of the Microsoft C
+Optimizing Compiler Run-Time Library Reference (Version 4.0
+or later.)
+
+Buffer Manipulation: All functions can be called.
+
+Character Classification and Conversion: All functions can be called.
+
+Data Conversion: All functions can be called except for
+
+     strtod()
+
+Directory Control: All functions can be called except for
+
+     getcwd()
+
+File Handling: All functions can be called.
+
+Low-Level I/O Routines: All functions can be called, but write()
+will not work in binary mode.
+
+Console and Port I/O: All functions can be called except for
+
+     cgets()
+     cprintf()
+     cscanf()
+
+Searching and Sorting: All functions can be called except for
+
+     qsort()
+
+String Manipulation: All functions can be called except for
+
+     strdup()
+
+BIOS Interface: All functions can be called.
+
+MS-DOS Interface: All functions can be called except for
+
+     int86()
+     int86x()
+
+Time: All functions can be called except for
+
+     ctime()
+     gmtime()
+     localtime()
+     utime()
+
+Miscellaneous: All functions can be called except for
+
+     assert()
+     getenv()
+     perror()
+     putenv()
+     _searchenv()
+
+
+Linking Extensions in Protected Mode
+--------------------------------------
+To link C extension modules in protected mode, link with the
+object file EXTHDRP.OBJ, instead of the real-mode header
+EXTHDR.OBJ.
diff --git a/nuts/Debug/nuts.pdb b/nuts/Debug/nuts.pdb
new file mode 100644
index 0000000..18c93b2
--- /dev/null
+++ b/nuts/Debug/nuts.pdb
Binary files differ
diff --git a/nuts/Debug/vc40.idb b/nuts/Debug/vc40.idb
new file mode 100644
index 0000000..7a4faa2
--- /dev/null
+++ b/nuts/Debug/vc40.idb
Binary files differ
diff --git a/nuts/Debug/vc40.pdb b/nuts/Debug/vc40.pdb
new file mode 100644
index 0000000..a3d19eb
--- /dev/null
+++ b/nuts/Debug/vc40.pdb
Binary files differ
diff --git a/nuts/nuts.c b/nuts/nuts.c
new file mode 100644
index 0000000..21c9bce
--- /dev/null
+++ b/nuts/nuts.c
@@ -0,0 +1,76 @@
+#include <windows.h>
+
+LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM);
+
+char szWinName[] = "MyWin";
+
+int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst,
+                    LPSTR lpszArgs, int nWinMode)
+
+{
+    HWND hwnd;
+    MSG msg;
+    WNDCLASSEX wcl;
+
+    wcl.hInstance = hThisInst;
+    wcl.lpszClassName = szWinName;
+    wcl.lpfnWndProc = WindowFunc;
+    wcl.style = 0;
+
+    wcl.cbSize = sizeof(WNDCLASSEX);
+
+    wcl.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+    wcl.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
+    
+    wcl.hCursor = LoadCursor(NULL, IDC_ARROW);
+    wcl.lpszMenuName = NULL;
+
+    wcl.cbClsExtra = 0;
+    wcl.cbWndExtra = 0;
+
+    wcl.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
+
+    if(!RegisterClassEx(&wcl)) return 0;
+
+    hwnd = CreateWindow(
+                        szWinName,
+                        "Tundra's Windows 95 Skeleton",
+                        WS_OVERLAPPEDWINDOW,
+                        CW_USEDEFAULT,
+                        CW_USEDEFAULT,
+                        CW_USEDEFAULT,
+                        CW_USEDEFAULT,
+                        HWND_DESKTOP,
+                        NULL,
+                        hThisInst,
+                        NULL
+                       );
+
+    ShowWindow(hwnd, nWinMode);
+    UpdateWindow(hwnd);
+
+    while(GetMessage(&msg, NULL, 0, 0))
+    {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+    }
+    return msg.wParam;
+
+}
+
+LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message, WPARAM wParam,
+                            LPARAM lParam)
+
+{
+    switch (message)
+    {
+        case WM_DESTROY:
+            PostQuitMessage(0);
+            break;
+
+        default:
+            return DefWindowProc(hwnd, message, wParam, lParam);
+    }
+    return 0;
+}
+
diff --git a/nuts/nuts.mak b/nuts/nuts.mak
new file mode 100644
index 0000000..25d88a3
--- /dev/null
+++ b/nuts/nuts.mak
@@ -0,0 +1,195 @@
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+!IF "$(CFG)" == ""
+CFG=nuts - Win32 Debug
+!MESSAGE No configuration specified.  Defaulting to nuts - Win32 Debug.
+!ENDIF 
+
+!IF "$(CFG)" != "nuts - Win32 Release" && "$(CFG)" != "nuts - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line.  For example:
+!MESSAGE 
+!MESSAGE NMAKE /f "nuts.mak" CFG="nuts - Win32 Debug"
+!MESSAGE 
+!MESSAGE Possible choices for configuration are:
+!MESSAGE 
+!MESSAGE "nuts - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "nuts - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE 
+!ERROR An invalid configuration is specified.
+!ENDIF 
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE 
+NULL=nul
+!ENDIF 
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "nuts - Win32 Debug"
+CPP=cl.exe
+MTL=mktyplib.exe
+RSC=rc.exe
+
+!IF  "$(CFG)" == "nuts - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(OUTDIR)\nuts.exe"
+
+CLEAN : 
+	-@erase ".\Release\nuts.exe"
+	-@erase ".\Release\nuts.obj"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)/nuts.pch" /YX /Fo"$(INTDIR)/" /c 
+CPP_OBJS=.\Release/
+CPP_SBRS=
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32 
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/nuts.bsc" 
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:windows /incremental:no\
+ /pdb:"$(OUTDIR)/nuts.pdb" /machine:I386 /out:"$(OUTDIR)/nuts.exe" 
+LINK32_OBJS= \
+	"$(INTDIR)/nuts.obj"
+
+"$(OUTDIR)\nuts.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF  "$(CFG)" == "nuts - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(OUTDIR)\nuts.exe"
+
+CLEAN : 
+	-@erase ".\Debug\nuts.exe"
+	-@erase ".\Debug\nuts.obj"
+	-@erase ".\Debug\nuts.ilk"
+	-@erase ".\Debug\nuts.pdb"
+	-@erase ".\Debug\vc40.pdb"
+	-@erase ".\Debug\vc40.idb"
+
+"$(OUTDIR)" :
+    if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\
+ /Fp"$(INTDIR)/nuts.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c 
+CPP_OBJS=.\Debug/
+CPP_SBRS=
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32 
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/nuts.bsc" 
+BSC32_SBRS=
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:windows /incremental:yes\
+ /pdb:"$(OUTDIR)/nuts.pdb" /debug /machine:I386 /out:"$(OUTDIR)/nuts.exe" 
+LINK32_OBJS= \
+	"$(INTDIR)/nuts.obj"
+
+"$(OUTDIR)\nuts.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+    $(LINK32) @<<
+  $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF 
+
+.c{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_OBJS)}.obj:
+   $(CPP) $(CPP_PROJ) $<  
+
+.c{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cpp{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+.cxx{$(CPP_SBRS)}.sbr:
+   $(CPP) $(CPP_PROJ) $<  
+
+################################################################################
+# Begin Target
+
+# Name "nuts - Win32 Release"
+# Name "nuts - Win32 Debug"
+
+!IF  "$(CFG)" == "nuts - Win32 Release"
+
+!ELSEIF  "$(CFG)" == "nuts - Win32 Debug"
+
+!ENDIF 
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\nuts.c
+
+"$(INTDIR)\nuts.obj" : $(SOURCE) "$(INTDIR)"
+
+
+# End Source File
+# End Target
+# End Project
+################################################################################
diff --git a/nuts/nuts.mdp b/nuts/nuts.mdp
new file mode 100644
index 0000000..9a5f35c
--- /dev/null
+++ b/nuts/nuts.mdp
Binary files differ
diff --git a/pay/PAY.C b/pay/PAY.C
new file mode 100644
index 0000000..bbecd9e
--- /dev/null
+++ b/pay/PAY.C
@@ -0,0 +1,316 @@
+/* PAY.C - This program demonstrates some of the capabilities of the
+				SCREEN DOOR Screen Management System.
+				Copyright (c) 1986, By T.A. Daneliuk
+				Last Modified: 06/30/86
+*/
+
+#include		<stdio.h>
+#include		<system.h>
+#include		<vstruct.h>
+#include		<math.h>
+
+/* Macro Color Definitions */
+ 
+#define		ICOLOR	color(BLACK,WHITE)		/* Input Color */
+#define		PCOLOR	color(YELLOW,BLUE)		/* Prompt Color */
+#define		RCOLOR	color(GREEN,BLACK)		/* Response Color */
+#define		BCOLOR	color(LCYAN,BLACK)		/* Border Color */
+#define		RBCOLOR	color(BLACK,CYAN)		/* Reverse Border Color */
+#define		HCOLOR	color(YELLOW,BLUE)		/* Help Colors */
+#define		HCOLOR2	color(YELLOW,BLACK)
+#define		HCOLOR3	color(LGREEN,BLACK)
+#define		HCOLOR4	color(HWHITE,BLACK)
+#define		HCOLOR5	color(LMAGENTA,BLACK)
+#define		HCOLOR6	color(LCYAN,BLACK)
+
+#define	SAMEPG	FALSE		/* If TRUE, Both Help And Input On Same Video Page */
+
+#if	!SAMEPG
+#define	HELPLOC	11
+#define	HELP1	help_screen1
+#define	VPAGE	3
+#define	HCLEAR	TRUE
+#define	HMCLEAR	FALSE
+#endif
+
+#if SAMEPG
+#define	HELPLOC	20
+#define	HELP1	NULL
+#define	VPAGE	0
+#define	HCLEAR	FALSE
+#define	HMCLEAR	TRUE
+#endif
+
+extern	char	*errmsg_rval,vpg_help;
+extern	int		help_cls,help_msg_cls;
+extern	int		recalc();		/* These Functions Will Show Up Later In The File */
+extern	void	hbord1(),hbord2();
+
+
+main()
+
+{
+vpg_help=VPAGE;
+help_cls=HCLEAR;
+help_msg_cls=HMCLEAR;
+
+/* 	Prompt, Response, And Help Strings
+
+	These Must Precede The Control Tables Below Which Reference The
+	Arrays Because Some One-Pass Compilers (Such As DeSmet) Cannot
+	Resolve A Reference To A Variable Which Is Declared Later In The
+	File.
+
+	Note That The Response Fields Are Dimensioned To A Size Equal To
+	rlen+1 To Make Room For The '\0' String Terminator Byte. Notice
+	Also That The Response Strings  Are Initialized To Provide
+	Default Responses For The Response Fields On Screen.
+*/
+
+static	char	prompt1[]={"Principal Amount:"};
+static	char	prompt2[]={"Annual Interest Rate (%):"};
+static	char	prompt3[]={"Number Of Months To Payoff:"};
+static	char	prompt4[]={"Monthly Payment:"};
+static	char	prompt5[]={"[ SCREEN DOOR Demonstration ]"};
+static	char	prompt6[]={"[ Copyright (c) 1986, T&R Communications Associates ]"};
+static	char	prompt7[]={"[ F3 To QUIT, F1 For HELP ]"};
+
+
+static	char 	resp1[11]={"10000"};
+static	char	resp2[6]={"10"};
+static	char	resp3[5]={"24"};
+static	char	resp4[14]={""};
+
+static	char	h1[]={"This is a demonstration of the SCREEN DOOR Screen Management System."};
+static	char	h2[]={"SCREEN DOOR is a 'C' Language programming tool designed to speedup"};
+static	char	h3[]={"the creation and maintenance of data entry screens via simple tables."};
+static	char	h4[]={"SCREEN DOOR supports unlimited keyin-time full field data validations"};
+static	char	h5[]={"as well as a host of built in character-by-character validations."};
+static	char	h6[]={"The latter include Alpha-Only, Numeric-Only, Alphanumeric, Forced Case,"};
+static	char	h7[]={"Floating Point Format, Hexadecimal Format, Binary Format, and many others."};
+static	char	h8[]={"The programmer can manage any number of Prompt and Response fields."};
+static	char	h9[]={"Any Prompt field may be displayed or not, and any Response field may"};
+static	char	h10[]={"be protected from User modification.  The programmer can also define"};
+static	char	h11[]={"fields which require User input at runtime (i.e., Disallow empty fields)."};
+static	char	h12[]={"Of course, context sensitive Help is available for any Response field"};
+static	char	h13[]={"the User is editing.  In this example, a different Help screen is"};
+static	char	h14[]={"displayed for each Response field.  SCREEN DOOR is also capable of"};
+static	char	h15[]={"displaying the same Help screen for each Response field being edited."};
+static	char	h16[]={"All of SCREEN DOOR's parameters can be dynamically varied, allowing"};
+static	char	h17[]={"the programmer to control screen and input behavior as the program runs."};
+static	char	h18[]={""};
+static	char	h19[]={"For more information on SCREEN DOOR contact:"};
+static	char	h21[]={"T&R Communications Associates"};
+static	char	h22[]={"4927 North Rockwell Street"};
+static	char	h23[]={"Chicago, IL  60625"};
+static	char	h24[]={"Enter Yearly Interest Rate In This Field."};
+static	char	h25[]={"Enter The Length Of The Loan (In Months) In This Field."};
+
+
+
+
+/*  Screen Control Tables - One For Help Screen, One For Input Screen
+	As Before, The Help Table Must Precede Its Reference In The Actual
+	Screen Table To Accommodate One-Pass Compilers.
+*/
+
+static	struct	VSTRUCT	help_screen1[]={
+
+			0,HCOLOR2,1,5,TRUE,h1,HCOLOR2,2,5,FALSE,h2,0,0,0,0,hbord1,0,0,0,NULL,FALSE,
+			0,HCOLOR2,3,5,TRUE,h3,HCOLOR3,4,5,FALSE,h4,0,0,0,0,NULL,0,0,0,NULL,FALSE,
+			0,HCOLOR3,5,5,TRUE,h5,HCOLOR3,6,5,FALSE,h6,0,0,0,0,NULL,0,0,0,NULL,FALSE,
+			0,HCOLOR3,7,5,TRUE,h7,HCOLOR4,8,5,FALSE,h8,0,0,0,0,NULL,0,0,0,NULL,FALSE,
+			0,HCOLOR4,9,5,TRUE,h9,HCOLOR4,10,5,FALSE,h10,0,0,0,0,NULL,0,0,0,NULL,FALSE,
+			0,HCOLOR4,11,5,TRUE,h11,HCOLOR5,12,5,FALSE,h12,0,0,0,0,NULL,0,0,0,NULL,FALSE,
+			0,HCOLOR5,13,5,TRUE,h13,HCOLOR5,14,5,FALSE,h14,0,0,0,0,NULL,0,0,0,NULL,FALSE,
+			0,HCOLOR5,15,5,TRUE,h15,HCOLOR6,16,5,FALSE,h16,0,0,0,0,NULL,0,0,0,NULL,FALSE,
+			0,HCOLOR6,17,5,TRUE,h17,HCOLOR,18,5,FALSE,h18,0,0,0,0,NULL,0,0,0,NULL,FALSE,
+			0,HCOLOR|BLINK,19,5,TRUE,h19,HCOLOR,21,23,FALSE,h21,0,0,0,0,NULL,0,0,0,NULL,FALSE,
+			0,HCOLOR,22,26,TRUE,h22,HCOLOR,23,30,FALSE,h23,0,0,0,0,NULL,0,0,0,NULL,TRUE
+
+										};
+
+static	struct	VSTRUCT	help_screen2[]={
+
+			0,HCOLOR6,HELPLOC+1,10,TRUE,h24,0,0,0,FALSE,NULL,0,0,FALSE,0,hbord2,FALSE,TRUE,TRUE,NULL,TRUE
+
+										};
+
+static	struct	VSTRUCT	help_screen3[]={
+
+			0,HCOLOR5,HELPLOC+1,10,TRUE,h25,0,0,0,FALSE,NULL,0,0,FALSE,0,hbord2,FALSE,TRUE,TRUE,NULL,TRUE
+
+										};
+
+
+static	struct	VSTRUCT	input_screen[]={
+
+			ICOLOR,PCOLOR,10,25,TRUE,prompt1,RCOLOR,10,53,TRUE,resp1,10,'.',FALSE,15,recalc,FALSE,TRUE,FALSE,HELP1,FALSE,
+			ICOLOR,PCOLOR,11,25,TRUE,prompt2,RCOLOR,11,53,TRUE,resp2,5,'.',FALSE,15,recalc,FALSE,TRUE,FALSE,help_screen2,FALSE,
+			ICOLOR,PCOLOR,12,25,TRUE,prompt3,RCOLOR,12,53,TRUE,resp3,4,'.',FALSE,15,recalc,FALSE,TRUE,FALSE,help_screen3,FALSE,
+			ICOLOR,RBCOLOR,6,12,TRUE,prompt5,RCOLOR,15,55,FALSE,NULL,7,'.',FALSE,11,NULL,FALSE,TRUE,TRUE,NULL,FALSE,
+			ICOLOR,RBCOLOR,19,16,TRUE,prompt6,RCOLOR,15,55,FALSE,NULL,7,'.',FALSE,11,NULL,FALSE,TRUE,TRUE,NULL,FALSE,
+			ICOLOR,RBCOLOR,8,29,TRUE,prompt7,RCOLOR,15,55,FALSE,NULL,7,'.',FALSE,11,NULL,FALSE,TRUE,TRUE,NULL,FALSE,
+			ICOLOR,PCOLOR,15,25,TRUE,prompt4,RCOLOR,15,49,FALSE,resp4,13,'.',FALSE,11,NULL,FALSE,TRUE,TRUE,NULL,TRUE
+
+										};
+
+/******************************  END-OF-DATA-TABLES **************************/		
+
+
+/* Actual Control Code Which Invokes Screen */
+
+int	ctr=0;
+struct	VSTRUCT	*vptr;			/* Declare A Pointer To A Screen Control Table */
+
+vptr=help_screen1;				/* Center All Lines On Help Screen For Grins */
+
+while (ctr<11)					/* This Also Demonstrates Runtime Table Modification */
+	{
+	((vptr+ctr)->phoriz)=center((vptr+ctr)->parray);
+	((vptr+ctr)->rhoriz)=center((vptr+ctr)->rarray);
+	ctr++;
+	}
+
+vptr=help_screen2;
+(vptr->phoriz)=center(vptr->parray);
+vptr=help_screen3;
+(vptr->phoriz)=center(vptr->parray);
+
+
+scr_setup();					/* Initialize PCIO Screen Constants */
+scr_clr();						/* Clear Screen */
+border(8,20,45,10,BCOLOR);		/* Draw Borders */
+border(6,10,65,14,BCOLOR);
+vptr=input_screen;				/* Point To The Input Screen */
+vdsply(vptr);					/* Display It */
+recalc(vptr,0);					/* So We Have An Answer 1st Time Through */
+vkeyin(vptr,0,FALSE);			/* Accept User Input */
+scr_clr();						/* Clear Screen And Back To Dos */
+
+}
+
+/****************************************************************************/
+
+static	void	hbord1(vptr,fld)		/* Draw A Border For The Help Screen */
+
+struct	VSTRUCT	*vptr;		/* These Are Always Passed By The Help Feature */
+int	fld;					/* But We Don't Use Them In This Case */
+
+{
+border(0,0,79,25,HCOLOR);
+}
+
+
+/****************************************************************************/
+
+static	void	hbord2(vptr,fld)		/* Draw A Border For The Help Screen */
+
+struct	VSTRUCT	*vptr;		/* These Are Always Passed By The Help Feature */
+int	fld;					/* But We Don't Use Them In This Case */
+
+{
+border(HELPLOC,0,79,3,HCOLOR3);
+}
+
+
+/****************************************************************************/
+
+static	void	border(startv,starth,width,height,vattrib)
+
+char	vattrib;
+int		startv,starth,width,height;
+{
+int	x;
+
+	v_rowcol(startv,starth);
+	scr_aputs(mkstr(BORDERNW,1),vattrib);
+	scr_aputs(mkstr(BORDERH,width-2),vattrib);
+	scr_aputs(mkstr(BORDERNE,1),vattrib);
+	v_rowcol(startv+height-1,starth);
+	scr_aputs(mkstr(BORDERSW,1),vattrib);
+	scr_aputs(mkstr(BORDERH,width-2),vattrib);
+	scr_aputs(mkstr(BORDERSE,1),vattrib);
+
+	for (x=startv+1;x<=(startv+height-2);x++)
+		{
+			v_rowcol(x,starth);
+			scr_aputs(mkstr(BORDERV,1),vattrib);
+			v_rowcol(x,starth+width-1);
+			scr_aputs(mkstr(BORDERV,1),vattrib);
+		}
+		
+}
+
+/****************************************************************************/
+
+/* This Is Our "Validation" Routine That's Really Being Used To
+	Recalculate The Monthly Payment */
+
+static	int	recalc(vptr,fld)
+
+struct	VSTRUCT	*vptr;
+int	fld;
+
+{
+
+int		x,z,answlen,error,inrange;
+inrange=error=FALSE;
+answlen=((vptr+6)->rlen);
+
+double	pay,princ,interest,period,y;
+char	*answer;
+
+static	char	msg[]={"Calculation Cannot Be Done Because Of Invalid Input Data!"};
+errmsg_rval=msg;			/* This points SCREEN DOOR's global to our own error message */
+
+answer=(vptr+6)->rarray;	/* This is where we'll put our answer */
+
+princ=atof(vptr->rarray);					/* Convert input strings to floating point */
+interest=(atof((vptr+1)->rarray))/1200.0;
+period=atof((vptr+2)->rarray);
+
+for(x=0;x < answlen;x++)			/* Initialize answer display to zeros */
+		*(answer+x)='0';
+*(answer+(answlen-3))='.';			/* Stick In The Decimal Point */
+
+if (princ==0 || interest==0 || period==0) /* Make sure we have valid input */
+		error=TRUE;
+
+if (!error)
+	pay=princ*(interest/(1.0-(pow((1.0/(1.0+interest)),period))));	/* Do the calculation */
+
+if (pay >= exp10((double)(answlen-4)))	/* Make sure answer can fit in the room alloted to it */
+	error=TRUE;
+
+if (errno==EDOM || errno==ERANGE)		/* Make sure the math routines didn't choke */
+	error=TRUE;
+
+if (!error)								/* Convert answer back to a string */
+	{
+	for (x=answlen-4;x>-3;x--)		/* Do it by powers of 10 */
+		{
+		y=exp10((double)x);
+		z=(x<0 ? (answlen-x-3) : (answlen-x-4));	/* Remember the decimal pt.! */
+		if ((pay < y) && !inrange)
+			*(((vptr+6)->rarray)+z)=' ';		/* Don't want leading zeros */
+		else
+			{
+			inrange=TRUE;
+			while (pay >= y)
+				{
+				pay=pay-y;
+				(*(((vptr+6)->rarray)+z))++;
+				}
+			}
+		}	
+	}
+
+
+vdsply(vptr);				/* Make sure answer gets displayed */
+return(error);
+
+}
+
+/****************************************************************************/
+
diff --git a/pdb/BLDPDBIX.C b/pdb/BLDPDBIX.C
new file mode 100644
index 0000000..adcdd39
--- /dev/null
+++ b/pdb/BLDPDBIX.C
@@ -0,0 +1,201 @@
+/* BLDPDBIX.C - Build PDB Index File From Raw Data File
+                Last Modified: 07-25-90
+                By T.A. Daneliuk
+*/
+
+#include    <stdio.h>
+#include    <bplus.h>
+#include    <string.h>
+
+#define     DEBUG   0                   /* 0= No Debug */
+
+#define     DUP     1                   /* Allow Duplicate Keys */  
+#define     CR      0x0d                /* Carriage Return */
+#define     LF      0x0a                /* LineFeed */
+#define     EOR     LF                  /* End-Of-Record */
+
+int         KEY1 =   0;                  /* Offset Of First Key In Record */
+int         KEY2 =  46;                  /* Offset Of 2nd Key In Record */
+char    data_file[255] = "P:\\PDBASE";
+char    idx_file[255]  = "P:\\PDBASE.IDX";
+char    work[100];                      /* Working Buffer */
+unsigned long    offset;                /* Record Position In File */
+
+static  void    mk_idx(), bld_idx(), add_keys();
+static  int     get_rec();
+
+/*============================================================================*/
+
+main(argc,argv)
+int     argc;
+char    **argv;
+
+{
+    int z;
+
+    printf("PDB - Version 1.2, Copyright (c) 1988, 1990 T.A. Daneliuk - TundraWare!\n");
+    printf("Released To The Public Domain - No Warranties Expressed Or Implied!\n\n");
+
+    z = 0;
+    while ((z++ < argc) && (argv[z][0] == '-'))
+        {
+        switch (argv[z][1])
+            {
+            case 'i':
+                strcpy(idx_file, argv[z]+2);
+                break;
+            case 'd':
+                strcpy(data_file, argv[z]+2); 
+                break;
+            default:
+                printf("Invalid Command Line Switch, Ignored!\n");
+            }            
+        }
+
+    mk_idx();
+    bld_idx();    
+}
+
+/*============================================================================*/
+
+static void mk_idx()                    /* Create The Index File */
+{
+    IX_DESC node;
+ 
+    printf("\nCreating Index File %s For Data File %s ...",idx_file, data_file);
+    make_index(idx_file, &node, DUP);
+    printf("\nIndex File %s Created.\n",idx_file);
+    close_index(&node);
+ }
+
+/*============================================================================*/
+
+static void bld_idx()                   /* Build Index File */
+
+{
+    FILE    *fp;
+    IX_DESC node;
+    ENTRY   entry;
+    
+    fp = fopen(data_file, "rb");        /* Open Data File */
+    if (fp == NULL)
+        {
+        printf("\n Cannot Open %s, Aborting ...\n", data_file);
+        return;
+        }       
+    offset = 0;
+
+    open_index(idx_file, &node, DUP);
+
+    printf("\nBuilding Index Records ...\n");
+    while (get_rec(fp) == 0)            /* Get Record 'Till None Left */
+        {
+#if DEBUG
+        printf("%s\n", work);
+#endif
+        if (strlen(work) <= KEY2)       /* Improper Record Length */
+            {
+            printf("Bad Record At Position %u:\n", offset);
+            printf("%s\n", work);
+            printf("Record NOT Added To Index List!\n");
+            }
+        else
+            {
+            add_keys(&entry, &node);        /* Add Keys */
+            offset += strlen(work);         /* Update Record Pointer */
+            }
+        }
+        if (strlen(work) <= KEY2)       /* Improper Record Length */
+            {
+            printf("Bad Record At Position %lu:\n", offset);
+            printf("%s\n", work);
+            printf("Record NOT Added To Index List!\n");
+            }
+        else
+            {
+            add_keys(&entry, &node);        /* Add Keys */
+            offset += strlen(work);         /* Update Record Pointer */
+            }
+
+    printf("\nIndex Build Complete.\n");
+
+    close_index(&node);
+    fclose(fp);
+}
+
+/*============================================================================*/
+
+static int get_rec(fp)                  /* Read A Record */
+FILE    *fp;
+
+{
+    int c, x;
+    x=0;                                /* Index Into Work Buffer */
+
+    c = fgetc(fp);
+    while ((c != EOF) && (c != EOR))    /* Get A Record */
+        {
+        work[x++] = c;
+        c = fgetc(fp);
+        }
+    if (c == EOR)
+        {
+        work[x++] = c;
+        work[x]   = '\0';               /* Terminate Record String */
+        return (0);                     /* Return With Good Status */
+        }
+    else                                /* At End-Of-File */
+        {
+        work[x] = '\0';
+        return (1);
+        }
+}
+
+/*============================================================================*/
+
+static void add_keys(entry, node)        /* Add Keys */
+ENTRY   *entry;
+IX_DESC *node;
+
+{
+    int x, y, z, flag;
+
+    x = KEY1;
+    y = 0;
+    entry->recptr = offset;
+    while ((z = work[x++]) != ' ')
+        entry->key[y++] = toupper(z);
+    entry->key[y] = '\0';
+#if DEBUG
+    printf("%s\n", entry->key);
+#endif    
+    add_key(entry, node);
+
+    if (strcmp(work+strlen(work)-6, ".zip\r\n") != 0)
+        flag = 0;
+    else
+        {
+        flag = 1;
+        x = strlen(work)-3;
+        while ((work[x] != '/') && (x > KEY2))
+            x--; 
+        }
+    if (work[x] == '/')
+        x++;
+
+    y = 0; 
+    if (flag)                                   /* A .ZIP File Member */
+        {
+        entry->recptr = offset;
+        while ((z = work[x++]) != CR)
+            entry->key[y++] = toupper(z);
+        entry->key[y] = '\0';
+#if DEBUG
+    printf("%s\n", entry->key);
+#endif    
+        add_key(entry, node);
+        }
+
+}
+
+/*============================================================================*/
diff --git a/pdb/DPDB b/pdb/DPDB
new file mode 100644
index 0000000..f715956
--- /dev/null
+++ b/pdb/DPDB
@@ -0,0 +1,12 @@
+bldpdbix.obj:       bldpdbix.c
+        cl  /c /Od /Zi bldpdbix.c
+
+bldpdbix.exe:       bldpdbix.obj
+        link bldpdbix,,,sbplus /CO;
+
+pdb.obj:       pdb.c
+        cl  /c /Od /Zi pdb.c
+
+pdb.exe:       pdb.obj
+        link pdb,,,sbplus /CO;
+
diff --git a/pdb/PDB b/pdb/PDB
new file mode 100644
index 0000000..90c8efe
--- /dev/null
+++ b/pdb/PDB
@@ -0,0 +1,12 @@
+bldpdbix.obj:       bldpdbix.c
+        cl /c /Gs /Ox bldpdbix.c
+
+bldpdbix.exe:       bldpdbix.obj
+        link bldpdbix,,,sbplus;
+
+pdb.obj:       pdb.c
+        cl /c /Gs /Ox pdb.c
+
+pdb.exe:       pdb.obj
+        link pdb,,,sbplus;
+
diff --git a/pdb/PDB.C b/pdb/PDB.C
new file mode 100644
index 0000000..ef5997b
--- /dev/null
+++ b/pdb/PDB.C
@@ -0,0 +1,113 @@
+/* PDB.C -      Search PBASE Using Index
+                Last Modified: 07-25-90
+                By T.A. Daneliuk
+*/
+
+#include    <stdio.h>
+#include    <bplus.h>
+#include    <io.h>
+#include    <string.h>
+
+#define     DEBUG   0                   /* 0= No Debug */
+
+#define     DUP     1                   /* Allow Duplicate Keys */  
+#define     LF      0x0a                /* LineFeed */
+#define     EOR     LF                  /* End-Of-Record */
+
+char    data_file[255] = "P:\\PDBASE";
+char    idx_file[255]  = "P:\\PDBASE.IDX";
+char    work[100];                      /* Working Buffers */
+char    scratch[100];
+long    offset;                         /* Record Position In File */
+
+static  void     display();
+
+ENTRY   entry;
+IX_DESC node;
+FILE    *fp;
+
+/*============================================================================*/
+
+
+main(argc,argv)
+int     argc;
+char    **argv;
+
+{
+
+    int     x, y, z;
+
+    printf("PDB - Version 1.3, Copyright (c) 1988, 1990 T.A. Daneliuk - TundraWare!\n");
+    printf("Released To The Public Domain - No Warranties Expressed Or Implied!\n\n");
+    if (argc < 2)
+        printf("Bad Command Line!, Aborting ...\n");
+    else
+        {
+        z = 0;
+        while ((z++ < argc) && (argv[z][0] == '-'))
+            {
+            switch (argv[z][1])
+                {
+                case 'i':
+                    strcpy(idx_file, argv[z]+2);
+                    break;
+                case 'd':
+                    strcpy(data_file, argv[z]+2); 
+                    break;
+                default:
+                    printf("Invalid Command Line Switch, Ignored!\n");
+                }            
+            }
+
+        fp=fopen(data_file, "rb");
+        if (fp == NULL)
+            {
+            printf("Can't Open %s, Aborting ... \n", data_file);
+            exit();
+            }
+        open_index(idx_file, &node, DUP);
+
+        for (x=z; x<argc; x++)
+            { 
+            y=0;
+            while ((scratch[y] = toupper(argv[x][y])) != '\0')
+                y++;
+            scratch[y] = '\0';
+            strcpy(entry.key, scratch);
+            locate_key(&entry, &node);
+            if (strnicmp(entry.key, scratch, strlen(scratch)) == 0)
+                display();
+            while ((next_key(&entry, &node) == IX_OK) &&
+                    (strnicmp(entry.key, scratch, strlen(scratch)) == 0))
+                display();
+            }
+        fclose(fp);
+        close_index(&node);
+        }
+}
+
+/*============================================================================*/
+static void display()
+
+
+{
+    int y,z;    
+
+    if (!fseek(fp, entry.recptr, SEEK_SET))
+        {
+        y=0;
+        z = fgetc(fp);
+        while ((z != EOR) && (z != EOF))
+            {
+            work[y++] = z;
+            z = fgetc(fp);
+            }
+        work[y++] = z;
+        work[y]   = '\0';
+        printf("%s", work);
+        }
+    else
+        printf("Seek Error At %lu!\n", entry.recptr);
+}
+
+/*============================================================================*/
diff --git a/pp/PP.C b/pp/PP.C
new file mode 100644
index 0000000..5426de4
--- /dev/null
+++ b/pp/PP.C
@@ -0,0 +1,533 @@
+/*	PP.C -	Pretty Printer Incorporating Print Directives And Variable Formatting
+			Copyright (C) 1986, 1987 T.A. Daneliuk
+			Last Modified: 02/19/87
+*/
+
+#include	<stdio.h>
+#include	<system.h>
+#include	<filefind.h>
+
+
+/* Global Defaults, Counters, Buffers, And State Flags */
+
+#define	HDRDEFALT	3					/* Default Header Length */
+static	struct	DataArea mydta;			/* Working DTA For Wildcards */
+static	int pwidth=132;					/* Page Width */
+static	int plen=56;					/* Page Length */
+static	int tabsz=4;					/* Tab Expansion Size */
+static	char line[6];					/* Current Source Line Number */
+static	row=1;							/* Current Physical Line Number */
+static	int	col=1;						/* Horizontal Position Being Printed */
+static	char page[4];					/* Page Counter */
+static	char nest[3];					/* Curly Brace Nesting Level */
+static	int	linenums=TRUE;				/* If TRUE, prints line numbers */
+static	int header=TRUE;				/* If TRUE, prints header */
+static	int	hdrlen=HDRDEFALT+1;			/* Number Of Lines In Header */
+static	int	squote;						/* Single Quote Flag */
+static	int	dquote;						/* Double Quote Flag */
+static	int	comment;					/* Comment Flag */
+static	int	prtstdin=FALSE;				/* Means stdin In Input File List */
+static	int messages=TRUE;				/* Means Display Error Messages */
+static	int	start=1;					/* Beginning Position Of Text */
+
+/* Global Constants And Print Formatting Offsets */
+
+#define	CR		0x0d					/* Carriage Return */
+#define	LF		0x0a					/* Line Feed */
+#define	EOL		0x0d0a					/* End-Of-Line */
+#define	TOF		0x0c					/* Top-Of-Form Character */
+#define	OUTSZ	(pwidth+3)				/* Size Of Output Buffer */
+#define	HDRSZ	((pwidth+2)*HDRDEFALT)+1 /* Size Of Header Buffer */
+#define	PAGEPOS	8						/* Page Number Posn From Rt. Margin */
+#define	DATEPOS	21						/* Date Position From Rt. Margin */
+#define	TIMEPOS	8						/* Time	Position From Rt. Margin */
+#define	NESTPOS	0						/* Offset Of Nesting String */
+#define	LINOPOS	3						/* Offset Of Line Number String */
+#define	TEXTPOS	10						/* Offset Of Beginning Of Text */
+
+/*********************** Main Body Of PP.C Logic *****************************/
+
+
+main(argc,argv)
+
+int		argc;
+char	*argv[];
+
+{
+
+int		c;										/* Read Character */
+int		f;										/* argv Offset For Filenames */
+int		g,h;									/* Temporary */
+int		fp;										/* Working File Pointer */
+int		first;									/* Working Flag */
+char	*fn;									/* Filename Pointer */
+char	name[129];								/* Name w/ Path For fopen() */
+
+banner();										/* Display Logon Banner */
+f=parse_args(argc,argv);						/* Parse Command Line Args. */
+
+if ((f == argc) || (prtstdin))					/* No Filename Passed */
+	{
+	if (messages)
+		fputs("Now Printing: <stdin>            ",stderr);	/* So Use stdin Data */
+	pp(stdin,"<stdin>");
+	if (messages)
+		{
+		fputs(line,stderr);
+		fputs(" Line(s) Printed !\n",stderr);
+		}
+	}
+
+if (f != argc)
+	while(f < argc)								/* Process Passed Filenames */
+		{
+		for (h=0;*(argv[f]+h) != '\0';h++)
+			*(argv[f]+h)=toupper(*(argv[f]+h));	/* Make all UC */
+		strcpy(name,argv[f]);					/* Copy Full Name For The fopen() */
+		h=strlen(name)-1;						/* Strip Off Everything But Path */
+		while((name[h]) != ':' && (name[h] != '\\') && (h > -1))
+			h--;
+		first=TRUE;
+		while (wildcard(argv[f],&mydta,first) != 0)
+			{
+			first=FALSE;						/* Made it thru 1st time */
+			fn=mydta.dta_name;
+			name[h+1]='\0';						/* Append Filename To Path */
+			strcat(name,fn);
+			fp=fopen(name,"r");
+			if (fp != NULL)							/* Successful Open */
+				{
+				if (messages)
+					{
+					fputs("Now Printing: ",stderr);
+					fputs(name,stderr);
+					g=43-strlen(name);				/* Pad So Line Display Aligns */
+					while (--g)
+						fputc(' ',stderr);
+					}
+				pp(fp,fn);
+				fclose(fp);
+				if (messages)
+					{
+					fputs(line,stderr);
+					fputs(" Line(s) Printed !\n",stderr);
+					}
+				}
+				else if (messages)						/* Open Failed */
+					{
+					fputs("Cannot Open: ",stderr);
+					fputs(argv[f],stderr);
+					fputs("\n",stderr);
+					}
+			}
+	if (first && messages)				/* Failed on 1st try, bad wc spec */
+		{
+		fputs("Cannot Open: ",stderr);
+		fputs(argv[f],stderr);
+		fputs("\n",stderr);
+		}
+	f++;
+	}
+
+}
+
+/*************************** Display Logon Banner ****************************/
+
+void	banner()
+
+{
+scr_setup();
+scr_clr();
+scr_rowcol(0,0);
+fputs("PP - Pretty Printer      Version 1.2.1\n",stderr);
+fputs("Copyright (C) 1986, 1987 By T&R Communications Associates, Chicago, IL, 60625\n",stderr);
+fputs("Permission Granted For Unlimited * NON-COMMERCIAL *  Distribution !!!\n\n",stderr);
+}
+
+/*********************** Parse Command Line Arguments ************************/
+
+parse_args(argc,argv)
+
+int		argc;
+char	*argv[];
+
+{
+int		x,c,tmp;
+FILE	*fp;
+
+x = 1;
+fp = NULL;
+
+while ( ((*argv[x]) == '-') && (x < argc) )
+	{
+	switch(*(argv[x]+1))
+		{
+		case 0:									/* Just passed a - */
+			prtstdin=TRUE;						/* Treat stdin as a passed filename */
+			break;
+
+		case 'h':
+			if (*(argv[x]+2))					/* Should be NULL */
+				error(NULL);
+			else
+				{
+				header=FALSE;
+				hdrlen=0;
+				}
+			break;
+
+		case 'i':
+			if (*(argv[x]+2))				/* Is an init file named? */
+				{
+				fp=fopen(argv[x]+2,"r");
+				if (fp == NULL)				/* Couldn't open init file */
+					error(NULL);
+				while ((c=fgetc(fp)) != EOF)
+					fputc(c,stdout);
+				fclose(fp);
+				}
+			else
+				error(NULL);
+			break;
+
+		case 'l':
+			tmp=atoi((argv[x]+2));
+			if ((tmp < 10) || (tmp > 128))
+				error(NULL);
+			else
+				plen=tmp;
+			break;
+
+		case 'm':
+			if (*(argv[x]+2))					/* Should be NULL */
+				error(NULL);
+			else
+				messages=FALSE;
+			break;
+
+		case 'n':
+			if (*(argv[x]+2))					/* Should be NULL */
+				error(NULL);
+			else
+				linenums=FALSE;
+			break;
+
+		case 't':
+			tmp=atoi((argv[x]+2));
+			if ((tmp < 2) || (tmp > 32))
+				error(NULL);
+			else
+				tabsz=tmp;
+			break;
+
+		case 'w':
+			tmp=atoi((argv[x]+2));
+			if ((tmp < 50) || (tmp > 512))
+				error(NULL);
+			else
+				pwidth=tmp;
+			break;
+
+		default:
+			error(NULL);
+		}
+	x++;
+	}
+return(x);
+}
+
+
+/*********************** Error Abort Handling Routine ************************/
+
+void	error(msg)
+char	*msg;
+
+{
+if (messages)
+	{
+	if (msg)
+		{
+		fputs("PP Error: ",stderr);
+		fputs(msg,stderr);
+		fputs(" !!!\n\n",stderr);
+		}
+	else
+		fputs("Usage:  pp  [-h -i -l -m -n -t -w -]  filename(s)  [>output device]\n\n",stderr);
+	}
+
+exit(1);
+}
+
+/***************** Initialize Header Buffer And Globals **********************/
+
+void	init(hdrptr,filnam,fp)
+
+char	*hdrptr,*filnam;
+int		fp;
+
+{
+int		tmp;
+char	t[9],d[9],ft[9],fd[9],*offset;
+times(t);
+dates(d);
+for (tmp=0;tmp < 8;tmp++)						/* Stuff DeSmet's spaces */
+	{
+	if (t[tmp] == ' ')
+		t[tmp] = '0';
+	if (d[tmp] == ' ')
+		d[tmp] = '0';
+	}	
+
+if (fp != stdin)
+	fstamp(fp,fd,ft);							/* Get File Date/Time Stamp */
+else
+	{
+	strcpy(fd,d);								/* Use today for stdin stamp */
+	strcpy(ft,t);
+	}
+
+tmp=0;											/* First Do The Header */
+while (tmp < HDRSZ)
+	{
+	*(hdrptr+tmp)=' ';							/* Initialize With Blanks */
+	tmp++;
+	}
+
+tmp=1;
+while (tmp <= HDRDEFALT)							/* Stuff CR/LF Characters */
+	{
+	offset=(hdrptr+(pwidth*tmp)+(2*(tmp-1)));
+	*offset=CR;
+	*(offset+1)=LF;
+	tmp++;
+	}
+
+*(hdrptr+HDRSZ-1)='\0';							/* Stuff Strings */
+strdup(hdrptr,filnam);
+strdup((hdrptr+pwidth-PAGEPOS-8),"  Page:");
+strdup((hdrptr+(pwidth*2)+2-DATEPOS-9),"Printed:          At:");
+strdup((hdrptr+(pwidth*2)+2-DATEPOS),d);
+strdup((hdrptr+(pwidth*2)+2-TIMEPOS),t);
+strdup((hdrptr+(pwidth*3)+4-DATEPOS-15),"Last Modified:          At:");
+strdup((hdrptr+(pwidth*3)+4-DATEPOS),fd);
+strdup((hdrptr+(pwidth*3)+4-TIMEPOS),ft);
+
+strcpy(line,"00001");							/* Now Do All The Globals */
+col=1;
+strcpy(page,"001");
+strcpy(nest,"01");
+squote=FALSE;
+dquote=FALSE;
+comment=FALSE;
+if (linenums)
+	start=(sizeof(line)+2);						/* Default is 1 - No line nums */
+
+}
+
+/***************************** Force New Page ********************************/
+
+void	newpage(hdrptr)
+
+char	*hdrptr;
+
+{
+
+fputc(TOF,stdout);
+if (header)
+	{
+	strdup(hdrptr+pwidth-PAGEPOS,page);
+	fputs(hdrptr,stdout);
+	fputc('\n',stdout);
+	bump(page,sizeof(page));
+	}
+newline();
+row=hdrlen+1;
+
+}
+
+/***************************** Begin New Line ********************************/
+
+void	newline()
+
+{
+
+if (linenums)
+	{
+	fputs(line,stdout);
+	fputs("  ",stdout);
+	}
+col=start;
+
+}
+
+/******************************* Wrap A Line *********************************/
+
+void	wrap(hdrptr,fp)
+
+char	*hdrptr;
+int		fp;
+
+{
+
+int		x;
+
+x=fgetc(fp);								/* Throw away whitespace */
+while ((x == ' ') || (x == TAB) || (x == '\r'))
+		x=fgetc(fp);
+ungetc(x,fp);
+
+fputc('\n',stdout);
+row++;
+if (row > plen)
+	newpage(hdrptr);
+else
+	{
+	x=start;
+	while (x)
+		{
+		fputc(' ',stdout);
+		x--;
+		}
+	col=start+1;
+	
+	}
+
+}
+
+/**************************** Bump ASCII Count *******************************/
+
+void	bump(ptr,sz)
+
+char	*ptr;
+int		sz;
+
+{
+int	carry,tmp;
+carry=1;
+sz=sz-2;
+
+while (sz >= 0)
+	{
+	tmp=(*(ptr+sz))-'0';
+	tmp=tmp+carry;
+	if (tmp < 10)
+		carry=0;
+	else
+		{
+		tmp=tmp-10;
+		carry=1;
+		}
+	*(ptr+sz)=('0'+tmp);
+	sz--;
+	}
+
+}
+
+/***************************** Print Routine *********************************/
+
+void	pp(fp,filnam)
+
+int		fp;
+char	*filnam;
+
+{
+int					c,e,x;						/* Working Character */
+char				*hdrptr;					/* Buffer Pointers */
+c = e = x = 0;
+
+/* Get Buffer Space And Initialize Buffer Pointers */
+
+hdrptr	=	calloc(HDRSZ,sizeof(char));
+if (hdrptr == NULL)
+	error("Couldn't Allocate Header Buffer - Insufficient Memory");
+
+init(hdrptr,filnam,fp);							/* Initialize Header/Globals */
+
+/* Actual Print Logic */
+
+c=fgetc(fp);
+if (c != EOF)
+	newpage(hdrptr);
+ungetc(c,fp);
+
+while ((c=fgetc(fp)) != EOF)
+		{
+		if (col > pwidth)						/* Start next line */
+			{
+			ungetc(c,fp);						/* Save for next time around */
+			c=-1;
+			}
+
+		switch(c)
+			{
+
+			case -1:							/* Gotta start a new line */
+				wrap(hdrptr,fp);
+				e=' ';							/* Last char really printed */
+				break;
+
+			case TOF:							/* Allow embedded formfeeds */
+				if (e != '\n')					/* Terminate partial line */
+					fputc('\n',stdout);
+				newpage(hdrptr);
+				if (linenums)					/* Save last char printed */
+					e=' ';
+				else
+					e='\n';
+				break;			
+
+			case '\r':							/* Ignore CR because of fputc() */
+				break;							/* Translates LF to CR-LF ! */
+
+			case '\n':							/* Process end of line */
+				fputc(c,stdout);
+				if ((c=fgetc(fp)) != EOF)		/* Count up if not a file end */
+					{
+					bump(line,sizeof(line));	/* Bump source line number */
+					row++;						/* Bump physical line number */
+					if (row > plen)
+						newpage(hdrptr);
+					else
+						newline();
+					}
+				ungetc(c,fp);
+				c='\n';
+				break;
+
+			case TAB:							/* Expand TABs to spaces */
+				x = ((col-start+1) % tabsz);
+				x = (x == 0 ? tabsz : x);
+				x = (tabsz+1) - x;
+				while (x)
+					{
+					if (col > pwidth)
+						{
+						c=wrap(hdrptr,fp);
+						x=0;
+						}
+					else
+						{
+						fputc(' ',stdout);
+						x--;
+						col++;
+						}
+					}
+				e=' ';							/* Last char really printed */
+				break;
+
+			default:
+				fputc(c,stdout);
+				col++;
+				e=c;
+				break;
+			}
+		}
+
+	if (e != '\n')								/* For printers like laser */
+		fputs("\n",stdout);						/* That maintain column after FF */
+
+/* Release Buffer Space */
+
+free(hdrptr);
+
+}
diff --git a/prfile/PR_FILE.ASM b/prfile/PR_FILE.ASM
new file mode 100644
index 0000000..ed0341e
--- /dev/null
+++ b/prfile/PR_FILE.ASM
@@ -0,0 +1,90 @@
+
+		PAGE	66,132
+		TITLE	PR_FILE.ASM
+;
+;
+; **********
+; * PR_FILE.ASM - PRINTER-TO-FILE REDIRECTION UTILITY - VERSION 1.0
+; * LAST MODIFIED: 05/09/85
+; * COPYRIGHT (C) BY T.A. DANELIUK
+; **********
+;
+;
+; **********
+; * SYSTEM EQUATES
+; **********
+;
+;
+DOS		EQU	21H				; DOS INTERRUPT
+TERMINATE	EQU	31H				; TERMINATE/STAY RESIDENT
+PRINTER_IR	EQU	5CH				; PRINTER IR VECTOR
+ALLOC_MEM	EQU	48H				; ALLOCATE MEMORY DOS FN
+SET_BLOCK	EQU	4AH				; GROW OR SHRINK ALLOC. BLOCK
+EXIT		EQU	4CH				; NORMAL EXIT TO DOS
+EOL		EQU	0A0DH				; END-OF-LINE STRING
+STD_CON_OUT	EQU	02H				; OUTPUT BYTE TO STDOUT
+;
+;
+; **********
+; * CODE SEGMENT
+; **********
+;
+;
+PR_FILE		SEGMENT WORD 'CODE'
+		ASSUME	CS:PR_FILE,DS:PR_FILE,ES:PR_FILE
+;
+;
+		ORG	100H				; THIS WILL BE A .COM FILE
+;
+;
+START_RUN	EQU	THIS BYTE
+;
+;
+START:		JMP	INIT				; GO TO INITIALIZATION CODE
+RUNTIME:	AND	AL,AL				; CHECK IF 0 - PRINT REQ.
+		JZ	RUN_RET				; NO, JUST RETURN GOOD STATUS
+		MOV	DL,AL				; PRINT CHAR ON STDOUT
+		MOV	AH,STD_CON_OUT
+		INT	DOS
+RUN_RET:	MOV	AH,90H				; SET PRINTER STATUS, OK
+		IRET					; AND RETURN
+;
+;
+END_RUN		EQU	THIS BYTE
+;
+;
+		PAGE
+; **********
+; * LOADER/INSTALL CODE
+; **********
+;
+;
+INIT: 		PUSHF					; SAVE IR STATUS
+		CLI					; TURN 'EM OFF FOR NOW
+;
+;
+; NOW POINT PRINTER VECTOR  TO RUNTIME CODE
+;
+;
+		XOR	DX,DX				; POINT DS TO VECTOR TBL.
+		MOV	DS,DX
+		MOV	BP,PRINTER_IR			; LOCATION OF IR VECTOR
+		MOV	DS:[BP+2],CS			; SEGMENT OF CODE
+		MOV WORD PTR DS:[BP],OFFSET RUNTIME	; OFFSET OF CODE
+;
+;
+; NOW TERMINATE, BUT STAY RESIDENT
+;
+;
+		XOR	AL,AL				; SET RETURN ERROR CODE TO 0
+		MOV	AH,TERMINATE			; TERMINATE & STAY RESIDENT FN
+		MOV	DX,END_RUN-START_RUN+100H	; SIZE OF RUN CODE IN BYTES
+		MOV	CL,4				; CONVERT TO PARAGRAPHS
+		SHR	DX,CL				; BY DIVIDING BY 16
+		INC	DX				; ADD 1 FOR NOT BEING ON BOUNDRY
+		POPF					; RESET ORIGINAL IR STATUS
+		INT	DOS				; DO THE DOS CALL
+;
+;
+PR_FILE		ENDS
+		END	START
diff --git a/prvid/PR_VID.ASM b/prvid/PR_VID.ASM
new file mode 100644
index 0000000..ed0341e
--- /dev/null
+++ b/prvid/PR_VID.ASM
@@ -0,0 +1,90 @@
+
+		PAGE	66,132
+		TITLE	PR_FILE.ASM
+;
+;
+; **********
+; * PR_FILE.ASM - PRINTER-TO-FILE REDIRECTION UTILITY - VERSION 1.0
+; * LAST MODIFIED: 05/09/85
+; * COPYRIGHT (C) BY T.A. DANELIUK
+; **********
+;
+;
+; **********
+; * SYSTEM EQUATES
+; **********
+;
+;
+DOS		EQU	21H				; DOS INTERRUPT
+TERMINATE	EQU	31H				; TERMINATE/STAY RESIDENT
+PRINTER_IR	EQU	5CH				; PRINTER IR VECTOR
+ALLOC_MEM	EQU	48H				; ALLOCATE MEMORY DOS FN
+SET_BLOCK	EQU	4AH				; GROW OR SHRINK ALLOC. BLOCK
+EXIT		EQU	4CH				; NORMAL EXIT TO DOS
+EOL		EQU	0A0DH				; END-OF-LINE STRING
+STD_CON_OUT	EQU	02H				; OUTPUT BYTE TO STDOUT
+;
+;
+; **********
+; * CODE SEGMENT
+; **********
+;
+;
+PR_FILE		SEGMENT WORD 'CODE'
+		ASSUME	CS:PR_FILE,DS:PR_FILE,ES:PR_FILE
+;
+;
+		ORG	100H				; THIS WILL BE A .COM FILE
+;
+;
+START_RUN	EQU	THIS BYTE
+;
+;
+START:		JMP	INIT				; GO TO INITIALIZATION CODE
+RUNTIME:	AND	AL,AL				; CHECK IF 0 - PRINT REQ.
+		JZ	RUN_RET				; NO, JUST RETURN GOOD STATUS
+		MOV	DL,AL				; PRINT CHAR ON STDOUT
+		MOV	AH,STD_CON_OUT
+		INT	DOS
+RUN_RET:	MOV	AH,90H				; SET PRINTER STATUS, OK
+		IRET					; AND RETURN
+;
+;
+END_RUN		EQU	THIS BYTE
+;
+;
+		PAGE
+; **********
+; * LOADER/INSTALL CODE
+; **********
+;
+;
+INIT: 		PUSHF					; SAVE IR STATUS
+		CLI					; TURN 'EM OFF FOR NOW
+;
+;
+; NOW POINT PRINTER VECTOR  TO RUNTIME CODE
+;
+;
+		XOR	DX,DX				; POINT DS TO VECTOR TBL.
+		MOV	DS,DX
+		MOV	BP,PRINTER_IR			; LOCATION OF IR VECTOR
+		MOV	DS:[BP+2],CS			; SEGMENT OF CODE
+		MOV WORD PTR DS:[BP],OFFSET RUNTIME	; OFFSET OF CODE
+;
+;
+; NOW TERMINATE, BUT STAY RESIDENT
+;
+;
+		XOR	AL,AL				; SET RETURN ERROR CODE TO 0
+		MOV	AH,TERMINATE			; TERMINATE & STAY RESIDENT FN
+		MOV	DX,END_RUN-START_RUN+100H	; SIZE OF RUN CODE IN BYTES
+		MOV	CL,4				; CONVERT TO PARAGRAPHS
+		SHR	DX,CL				; BY DIVIDING BY 16
+		INC	DX				; ADD 1 FOR NOT BEING ON BOUNDRY
+		POPF					; RESET ORIGINAL IR STATUS
+		INT	DOS				; DO THE DOS CALL
+;
+;
+PR_FILE		ENDS
+		END	START
diff --git a/screendoor/BDEMO2.C b/screendoor/BDEMO2.C
new file mode 100644
index 0000000..e779d01
--- /dev/null
+++ b/screendoor/BDEMO2.C
@@ -0,0 +1,136 @@
+#include		<stdio.h>
+#include		<system.h>
+#include		<t&r.h>
+#include		<vstruct.h>
+#include		<stdmsgs.h>
+
+
+uvalid(vptr,fld)
+
+struct	VSTRUCT	*vptr;
+int	fld;
+
+{
+
+if ((*((vptr+fld)->rarray)) != '1')
+	return(TRUE);
+else
+	return(FALSE);
+
+}
+
+
+
+main()
+
+{
+
+/*
+extern	int		errmsg_attr,errmsg_row,errmsg_col,errmsg_on,errmsg_cattr,errmsg_len;
+extern	char	*errmsg_rreqd,*errmsg_mfill,errmsg_fill;
+static	char	m1[]={"This is the new RREQD!"};
+static	char	m2[]={"MFILL Isn't Being Satisfied!"};
+
+errmsg_attr=clrinp;
+errmsg_row=0;
+errmsg_col=3;
+errmsg_rreqd=m1;
+errmsg_mfill=m2;
+errmsg_len=40;
+errmsg_cattr=clrresp;
+errmsg_fill='=';
+errmsg_on=FALSE;
+*/
+
+static	char	prompt0[]={"This Is A Demonstration\n"};
+static	char	prompt1[]={"Of The VKEYIN Screen Management System\n"};
+static	char	prompt2[]={"Developed By:\n"};
+static	char	prompt3[]={"T&R Communications Associates\n"};
+static	char	prompt4[]={"Chicago, IL  60625\n"};
+static	char	vp1[]={"Alpha Only"};
+static	char	vp2[]={"Alpha Only - UC"};
+static	char	vp3[]={"Alpha Only - LC"};
+static	char	vp4[]={"AlphaNumeric Only"};
+static	char	vp5[]={"AlphaNumeric Only - UC"};
+static	char	vp6[]={"AlphaNumeric Only - LC"};
+static	char	vp7[]={"Binary Digits"};
+static	char	vp8[]={"Octal Digits"};
+static	char	vp9[]={"Decimal Digits"};
+static	char	vp10[]={"Hexadecimal Digits"};
+
+static	char	resp0[16]={"Response #0"};
+static	char	resp1[16]={""};
+static	char	resp2[16]={"Response #2"};
+static	char	resp3[16]={"Response #3"};
+static	char	resp4[16]={"Response #4"};
+static	char	vr1[16]={""};
+static	char	vr2[16]={""};
+static	char	vr3[16]={""};
+static	char	vr4[16]={""};
+static	char	vr5[16]={""};
+static	char	vr6[16]={""};
+static	char	vr7[16]={""};
+static	char	vr8[16]={""};
+static	char	vr9[16]={""};
+static	char	vr10[16]={""};
+
+static	char	h0[16]={"This Is Help #0"};
+static	char	h1[16]={"This Is Help #1"};
+static	char	h2[16]={"This Is Help #2"};
+static	char	h3[16]={"This Is Help #3"};
+static	char	h4[16]={"This Is Help #4"};
+
+
+
+static	struct VSTRUCT help[]={
+
+	clrinp,clrprmt,0,0,TRUE,h0,clrresp,7,60,FALSE,NULL,15,'.',TRUE,0,NULL,FALSE,FALSE,TRUE,NULL,TRUE,
+	clrinp,clrinp,7,15,TRUE,h1,clrresp,7,60,FALSE,NULL,15,'.',TRUE,0,NULL,FALSE,FALSE,TRUE,NULL,TRUE,
+	clrinp,clrbord,8,60,TRUE,h2,clrresp,7,60,FALSE,NULL,15,'.',TRUE,0,NULL,FALSE,FALSE,TRUE,NULL,TRUE,
+	clrinp,clrbmsg,11,35,TRUE,h3,clrresp,7,60,TRUE,NULL,15,'.',TRUE,0,NULL,FALSE,FALSE,TRUE,NULL,TRUE,
+	clrinp,clrerr,24,15,TRUE,h4,clrresp,7,60,FALSE,NULL,15,'.',TRUE,0,NULL,FALSE,FALSE,TRUE,NULL,TRUE
+
+								};
+
+
+static	struct VSTRUCT screen0[]={
+
+	clrinp,clrprmt,5,15,TRUE,prompt0,clrresp,5,60,TRUE,resp0,15,'.',TRUE,0,NULL,FALSE,FALSE,TRUE,&help[0],FALSE,
+	clrinp,clrprmt,6,15,TRUE,prompt1,clrresp,6,60,TRUE,resp1,15,'.',TRUE,1,NULL,FALSE,FALSE,TRUE,&help[1],FALSE,
+	clrinp,clrprmt,7,15,TRUE,prompt2,clrresp,7,60,FALSE,resp2,15,'.',TRUE,2,NULL,FALSE,FALSE,TRUE,NULL,FALSE,
+	clrinp,clrprmt,8,15,TRUE,prompt3,clrresp,8,60,TRUE,resp3,15,'.',TRUE,0,uvalid,TRUE,FALSE,TRUE,&help[3],FALSE,
+	clrinp,clrprmt,9,15,TRUE,prompt4,clrresp,9,60,TRUE,resp4,15,'.',FALSE,0,NULL,FALSE,TRUE,TRUE,&help[4],FALSE,
+	clrinp,clrprmt,11,15,TRUE,vp1,clrresp,11,60,TRUE,vr1,15,'.',TRUE,3,NULL,FALSE,FALSE,TRUE,NULL,FALSE,
+	clrinp,clrprmt,12,15,TRUE,vp2,clrresp,12,60,TRUE,vr2,15,'.',TRUE,4,NULL,FALSE,FALSE,TRUE,NULL,FALSE,
+	clrinp,clrprmt,13,15,TRUE,vp3,clrresp,13,60,TRUE,vr3,15,'.',TRUE,5,NULL,FALSE,FALSE,TRUE,NULL,FALSE,
+	clrinp,clrprmt,14,15,TRUE,vp4,clrresp,14,60,TRUE,vr4,15,'.',TRUE,6,NULL,FALSE,FALSE,TRUE,NULL,FALSE,
+	clrinp,clrprmt,15,15,TRUE,vp5,clrresp,15,60,TRUE,vr5,15,'.',TRUE,7,NULL,FALSE,FALSE,TRUE,NULL,FALSE,
+	clrinp,clrprmt,16,15,TRUE,vp6,clrresp,16,60,TRUE,vr6,15,'.',TRUE,8,NULL,FALSE,FALSE,TRUE,NULL,FALSE,
+	clrinp,clrprmt,17,15,TRUE,vp7,clrresp,17,60,TRUE,vr7,15,'.',TRUE,9,NULL,FALSE,FALSE,TRUE,NULL,FALSE,
+	clrinp,clrprmt,18,15,TRUE,vp8,clrresp,18,60,TRUE,vr8,15,'.',TRUE,10,NULL,FALSE,FALSE,TRUE,NULL,FALSE,
+	clrinp,clrprmt,19,15,TRUE,vp9,clrresp,19,60,TRUE,vr9,15,'.',TRUE,11,NULL,FALSE,FALSE,TRUE,NULL,FALSE,
+	clrinp,clrprmt,20,15,TRUE,vp10,clrresp,20,60,FALSE,vr10,15,'.',TRUE,12,NULL,FALSE,FALSE,TRUE,NULL,TRUE
+
+								};
+
+
+struct VSTRUCT *vptr;
+static	char	time[9],date[9];
+
+scr_setup();
+scr_clr();
+verset('X','Y','Z');
+trbord();
+times(time);
+dates(date);
+dsplylin(2,5,date,clrbmsg);
+dsplylin(2,66,time,clrbmsg);
+cursorblk(TRUE);
+vptr=screen0;
+vdsply(vptr);
+cursorblk(FALSE);
+vkeyin(vptr,0,FALSE);
+fill_lin(statlin,0,' ',statlen,clrclr);
+fill_lin(23,center(mkstr('.',46)),'.',46,clrerr);
+
+}
diff --git a/screendoor/BDEMO3.C b/screendoor/BDEMO3.C
new file mode 100644
index 0000000..77a9537
--- /dev/null
+++ b/screendoor/BDEMO3.C
@@ -0,0 +1,28 @@
+#include		<stdio.h>
+#include		<system.h>
+#include		<t&r.h>
+#include		<vstruct.h>
+#include		<stdmsgs.h>
+
+
+main()
+
+{
+static	char	resp0[200]={"x"};
+
+static	struct VSTRUCT screen0[]={
+									clrinp,clrprmt,7,15,FALSE,NULL,clrresp,15,0,TRUE,resp0,199,'*',TRUE,0,NULL,FALSE,FALSE,TRUE,NULL,TRUE
+								};
+
+struct VSTRUCT *vptr;
+static	char	time[9],date[9];
+
+scr_setup();
+scr_clr();
+vptr=screen0;
+vdsply(vptr);
+cursorblk(FALSE);
+vkeyin(vptr,0,FALSE);
+
+}
+
diff --git a/screendoor/CURSORSZ.C b/screendoor/CURSORSZ.C
new file mode 100644
index 0000000..b43a90e
--- /dev/null
+++ b/screendoor/CURSORSZ.C
@@ -0,0 +1,22 @@
+/*  CURSORSZ.C - Set Cursor Size
+				Last Modified: 06/11/86
+				Copyright (C) 1986,  T.A. Daneliuk
+*/
+
+#include	<t&r.h>
+#include	<dos.h>
+
+
+void	cursorsz(top,bottom)
+
+int		top,bottom;
+
+{
+
+extern	unsigned	_rcx,_rax;
+
+	_rcx=(top<<8)|(bottom);
+	_rax=0x0100;
+	_doint(16);				/* Call BIOS and set cursor size */
+
+}
diff --git a/screendoor/MKSTR.C b/screendoor/MKSTR.C
new file mode 100644
index 0000000..472e512
--- /dev/null
+++ b/screendoor/MKSTR.C
@@ -0,0 +1,29 @@
+/*  MKSTR.C - Makes A String Of Character 'c' Having Length 'n'
+			  Up To Maximum Length String Allowed In System
+
+				Last Modified: 06/11/86
+				Copyright (C) 1986,  T.A. Daneliuk
+*/
+
+
+#include	<system.h>
+#include        <t&r.h>
+
+
+char	*mkstr(c,n)
+
+char	c;
+int		n;
+
+{
+static	char	string[MAXSTRING+1];
+int		count;
+
+		for (count=0;count<=((n<=MAXSTRING) ? (n-1):(MAXSTRING-1));count++)
+				string[count]=c;
+	
+		string[count]='\0';
+
+		return(string);
+
+}
diff --git a/screendoor/S/CURSORSZ.OBJ b/screendoor/S/CURSORSZ.OBJ
new file mode 100644
index 0000000..4b5527c
--- /dev/null
+++ b/screendoor/S/CURSORSZ.OBJ
Binary files differ
diff --git a/screendoor/S/MKSTR.OBJ b/screendoor/S/MKSTR.OBJ
new file mode 100644
index 0000000..d807ca0
--- /dev/null
+++ b/screendoor/S/MKSTR.OBJ
Binary files differ
diff --git a/screendoor/S/SET_VPAG.OBJ b/screendoor/S/SET_VPAG.OBJ
new file mode 100644
index 0000000..8d404b3
--- /dev/null
+++ b/screendoor/S/SET_VPAG.OBJ
Binary files differ
diff --git a/screendoor/S/VDSPLY.OBJ b/screendoor/S/VDSPLY.OBJ
new file mode 100644
index 0000000..6dfcf4b
--- /dev/null
+++ b/screendoor/S/VDSPLY.OBJ
Binary files differ
diff --git a/screendoor/S/V_ROWCOL.OBJ b/screendoor/S/V_ROWCOL.OBJ
new file mode 100644
index 0000000..5898b28
--- /dev/null
+++ b/screendoor/S/V_ROWCOL.OBJ
Binary files differ
diff --git a/screendoor/SCRNDOOR b/screendoor/SCRNDOOR
new file mode 100644
index 0000000..854f2df
--- /dev/null
+++ b/screendoor/SCRNDOOR
@@ -0,0 +1,46 @@
+# MAKE File To Create A Working SCREENDOOR Library Under Microsoft C
+#	Last Modified: 06-13-87
+# 	Copyright (c) 1987, By T.A. Daneliuk
+
+
+$(MODEL)\v_rowcol.obj: v_rowcol.c $(INCLUDE)\dos.h $(INCLUDE)\t&r.h
+	MSC v_rowcol,$(MODEL)\v_rowcol.obj,NUL,NUL /A$(MODEL) $(DEBUG) /DLINT_ARGS;
+	LIB $(LIB)\$(MODEL)_sdoor.lib -+$(MODEL)\v_rowcol.obj;
+
+$(MODEL)\vdsply.obj: vdsply.c $(INCLUDE)\stdio.h $(INCLUDE)\system.h \
+                     $(INCLUDE)\vstruct.h $(INCLUDE)\t&r.h
+	MSC vdsply,$(MODEL)\vdsply.obj,NUL,NUL /A$(MODEL) $(DEBUG) /DLINT_ARGS;
+	LIB $(LIB)\$(MODEL)_sdoor.lib -+$(MODEL)\vdsply.obj;
+
+$(MODEL)\mkstr.obj: mkstr.c $(INCLUDE)\system.h $(INCLUDE)\t&r.h
+	MSC mkstr,$(MODEL)\mkstr.obj,NUL,NUL /A$(MODEL) $(DEBUG) /DLINT_ARGS;
+	LIB $(LIB)\$(MODEL)_sdoor.lib -+$(MODEL)\mkstr.obj;
+
+$(MODEL)\cursorsz.obj: cursorsz.c $(INCLUDE)\dos.h $(INCLUDE)\t&r.h
+	MSC cursorsz,$(MODEL)\cursorsz.obj,NUL,NUL /A$(MODEL) $(DEBUG) /DLINT_ARGS;
+	LIB $(LIB)\$(MODEL)_sdoor.lib -+$(MODEL)\cursorsz.obj;
+
+$(MODEL)\set_vpag.obj: set_vpag.c $(INCLUDE)\dos.h  $(INCLUDE)\t&r.h
+	MSC set_vpag,$(MODEL)\set_vpag.obj,NUL,NUL /A$(MODEL) $(DEBUG) /DLINT_ARGS;
+	LIB $(LIB)\$(MODEL)_sdoor.lib -+$(MODEL)\set_vpag.obj;
+
+$(MODEL)\sound.obj: sound.asm
+	MASM sound,$(MODEL)\sound.obj,NUL,NUL /D$(MODEL)MODEL /MX;
+	LIB $(LIB)\$(MODEL)_sdoor.lib -+$(MODEL)\sound.obj;
+
+$(MODEL)\vundsply.obj: vundsply.c $(INCLUDE)\stdio.h $(INCLUDE)\system.h \
+                     $(INCLUDE)\vstruct.h $(INCLUDE)\t&r.h
+	MSC vundsply,$(MODEL)\vundsply.obj,NUL,NUL /A$(MODEL) $(DEBUG) /DLINT_ARGS;
+	LIB $(LIB)\$(MODEL)_sdoor.lib -+$(MODEL)\vundsply.obj;
+
+$(MODEL)\show_hlp.obj: show_hlp.c $(INCLUDE)\stdio.h $(INCLUDE)\system.h \
+                     $(INCLUDE)\vstruct.h $(INCLUDE)\t&r.h
+	MSC show_hlp,$(MODEL)\show_hlp.obj,NUL,NUL /A$(MODEL) $(DEBUG) /DLINT_ARGS;
+	LIB $(LIB)\$(MODEL)_sdoor.lib -+$(MODEL)\show_hlp.obj;
+
+$(MODEL)\vkeyin.obj: vkeyin.c $(INCLUDE)\stdio.h $(INCLUDE)\system.h \
+                     $(INCLUDE)\vstruct.h $(INCLUDE)\t&r.h
+	MSC vkeyin,$(MODEL)\vkeyin.obj,NUL,NUL /A$(MODEL) $(DEBUG) /DLINT_ARGS;
+	LIB $(LIB)\$(MODEL)_sdoor.lib -+$(MODEL)\vkeyin.obj;
+
+
diff --git a/screendoor/SD2/SD2_DEFS.H b/screendoor/SD2/SD2_DEFS.H
new file mode 100644
index 0000000..0594b17
--- /dev/null
+++ b/screendoor/SD2/SD2_DEFS.H
@@ -0,0 +1,329 @@
+/*  SD2_DEFS.H -    ScreenDoor II Definitions, Global Variables, Etc.
+
+                    Last Modified: 08-11-88
+                    Copyright (C) 1988, T.A. Daneliuk
+*/
+
+
+/*========================== DEBUGGING OPTIONS ===============================*/
+
+#define     DEBUG       0                   /* Set To 1 To Enable Debugging   */
+
+
+/*=========================== PROGRAM DEFINITIONS ============================*/
+
+#define	PROGNAME	"ScreenDoor II"
+#define	VERSION		"1.1"
+
+/*============================= COMPILER =====================================*/
+
+#define     MSC         1                   /* Microsoft C                    */
+#define     TURBO       0                   /* Borland TurboC                 */
+#define     PCCV        0                   /* UNIX System V Compiler         */
+#define     PCCB        0                   /* UNIX BSD 4.x Compiler          */
+#define     ANSI        1                   /* Compiler is ANSI Compliant     */
+
+
+/*========================= PRESENTATION SERVICE =============================*/
+
+#define     PC_BIOS     1                   /* IBM-PC Via Standard Bios       */
+#define     PC_WIND     0                   /* IBM-PC Via MS-Windows          */
+#define     PC_OSPM     0                   /* OS/2 Presentation Manager      */
+#define     CURSES      0                   /* UNIX Curses                    */
+#define     XWINDOWS    0                   /* Generic X-Windows              */
+
+/*========================== OPERATING SYSTEM ================================*/
+
+#define     PCDOS       1                   /* Standard PC-DOS                */
+#define     OS_2        0                   /* OS/2                           */
+#define     UNIXV       0                   /* UNIX System V.x                */
+#define     UNIXB       0                   /* UNIX BSD 4.x                   */
+
+
+/*============== DIRECTLY MANAGE PHYSICAL SCREEN FOR NOW =====================*/
+
+#if     PC_BIOS & PCDOS
+
+#define         sd2_sound           pcbios_sound
+#define         sd2_cursor          pcbios_cursor
+#define         sd2_rdcursor        pcbios_rdcursor
+#define         sd2_rowcol          pcbios_rowcol
+#define         sd2_cls             pcbios_cls
+#define         sd2_getc            pcbios_getc
+#define         sd2_aputs           pcbios_aputs
+
+#define         CUROFF              32,7            /* Cursor Settings        */
+#define         CURSML              6,7
+#define         CURBLK              0,7
+
+#endif
+
+
+/*===================== MISC. DEFINITIONS & TYPEDEFS =========================*/
+
+#define     FALSE       0
+#define     TRUE        !FALSE
+
+#ifndef     BOOL 
+typedef     int         BOOL;               /* Boolean Datatype               */
+#endif
+
+#if     PCDOS & PC_BIOS
+
+typedef unsigned int    VCOORD;             /* Screen Coordinates             */
+typedef unsigned char   VATRB;              /* Video Attribute                */
+typedef unsigned char   VMODE;              /* Video Mode                     */
+typedef unsigned char   VPAGE;              /* Video Page                     */
+typedef unsigned char   KEYSTR;             /* Keystroke                      */
+typedef unsigned int    VALCODE;            /* Character Validation Code      */
+typedef unsigned char   ERRCODE;            /* Internal Error Code            */
+typedef unsigned char   F_TYPE;             /* Field Type Codes               */
+typedef int             FLEN;               /* Field Length                   */
+
+
+#endif
+
+
+/*=================== SCREEN AND FIELD CONTROL STRUCTURES ====================*/
+
+
+struct SD2_FIELD                        /* FIELD Control Structure */
+{
+        /* Members Common Top Both Prompt And Response Field Types */
+
+        F_TYPE      ftype;              /* Field Type                         */
+        VCOORD      frow;               /* Field Vertical Position            */
+        VCOORD      fcol;               /* Field Horizontal Position          */
+        VATRB       fattrib;            /* Field Display Colors/Attributes    */
+        KEYSTR      * field;            /* Array Containing Field Contents    */
+
+
+
+                   /* Members Response Field Screen Control */
+
+        FLEN        rlen;               /* Maximum Allowed User Response Len. */
+        VATRB       rattrib;            /* Input Colors/Attributes            */
+        VATRB       cattrib;            /* Attribute To Use When Clearing     */
+        KEYSTR      rfill;              /* Keyin Time Fill Character          */
+        KEYSTR      rclear;             /* Character To Use When Clearing     */
+
+                   /* Members For Single Character Validation */
+
+        BOOL        rspace;             /* TRUE Allows Blanks In Response     */
+        KEYSTR      * mask;             /* Character Validation Mask          */
+        KEYSTR      ** v_lists;         /* Array Of Char. Val. Strings        */
+
+
+  /* Members For Full Field Validation, Error Handling, Help, And  Autoskip */
+
+        BOOL        rmustfill;          /* TRUE Means Field Must Be Filled    */
+        BOOL        rreqd;              /* TRUE Means A Response Is Required  */
+#if ANSI
+        char        *(*rvalid) (struct SD2_FIELD *x);        /* See Below     */
+        void        (*flderr) (struct SD2_FIELD *x, ERRCODE y, char *z);
+#else
+        char        *(*rvalid) ();      /* Whole Field Validation Function    */
+        void        (*flderr) ();       /* Pointer To Error Handler           */
+#endif
+
+        struct      SD2_SCRN *rhelp;    /* Pointer To Help Screen Structure   */
+        BOOL        rskp;               /* TRUE Means Autoskip On             */
+};
+
+
+struct SD2_SCRN                         /* SCREEN Control Structure */
+{
+        void        (* before) ();      /* Do This Before Using Screen        */
+        void        (* after)  ();      /* Do This Before Exiting Screen      */
+        struct SD2_FIELD *fields;       /* Fields Present On This Screen      */
+        VATRB       clr;                /* Attribute To Use During Screen Clr.*/
+        char        autoborder;         /* Automatically Border The Screen?   */
+};
+
+
+/*============================= FIELD TYPES ==================================*/
+
+#define FLD_PROMPT      0
+#define FLD_RESP        1
+
+
+/*======================= CHARACTER VALIDATION CODES =========================*/
+
+#define     SD2_LITERAL_L   'x'             /* No Character Validation        */
+#define     SD2_LITERAL_U   'X'
+#define     SD2_LITERAL_N   'j'
+
+#define     SD2_ALPHA_L     'a'             /* Alphabetic Only                */
+#define     SD2_ALPHA_U     'A'
+#define     SD2_ALPHA_N     'k'
+
+#define     SD2_ALPHANUM_L  'n'             /* Alphanumeric Only              */
+#define     SD2_ALPHANUM_U  'N'
+#define     SD2_ALPHANUM_N  'l'
+
+#define     SD2_BINARY      'b'             /* Binary Digits Only             */
+#define     SD2_OCTAL       'o'             /* Octal Digits Only              */
+#define     SD2_DECIMAL     'd'             /* Decimal Digits Only            */
+#define     SD2_HEX_L       'h'             /* Hex Digits Only                */
+#define     SD2_HEX_U       'H'
+#define     SD2_HEX_N       'u'
+#define     SD2_FLOATING    'f'             /* Floating Point Digits Only     */
+#define     SD2_SCIENT_L    's'             /* Scientific Digits Only         */
+#define     SD2_SCIENT_U    'S'
+#define     SD2_SCIENT_N    'v'
+#define     SD2_FINANCIAL   '$'             /* Financial Digits Only          */
+#define     SD2_YN_L        'y'             /* Yes/No                         */
+#define     SD2_YN_U        'Y'
+#define     SD2_YN_N        'w'
+
+#define     SD2_LIST0       '0'             /* Literal Lists                  */
+#define     SD2_LIST1       '1'
+#define     SD2_LIST2       '2'
+#define     SD2_LIST3       '3'
+#define     SD2_LIST4       '4'
+#define     SD2_LIST5       '5'
+#define     SD2_LIST6       '6'
+#define     SD2_LIST7       '7'
+#define     SD2_LIST8       '8'
+#define     SD2_LIST9       '9'
+
+
+
+/*============ KEY MAP, CONTROL KEY, AND INTERNAL ERROR DEFINITIONS ==========*/
+
+/* Offsets Into sd2_ctrl_codes Array Where These Internal Codes Can Be Found */
+
+
+#define     IENO_ERR    0                   /* No Error Status Return Code    */
+#define     NXT_FLD     1                   /* Inter-Field Control            */
+#define     PRV_FLD     2
+#define     FST_FLD     3
+#define     LST_FLD     4
+
+#define     CUR_LFT     5                   /* Intra-Field Control            */
+#define     CUR_RGT     6
+#define     BEG_FLD     7
+#define     END_FLD     8
+#define     CLR_FLD     9
+#define     CLR_END     10
+#define     EXT_FLD     11
+#define     INS         12
+#define     DEL         13
+#define     BS          14
+#define     HELP        15
+
+#define     EXT_SCR     16                  /* Window/Screen Control          */
+
+#define     IEBAD_CTRL  17                   /* Internal Error Code Positions */
+#define     IENOTRES    18
+#define     IEFNULL     19
+#define     IENUL_FPTR  20
+#define     IEMUST_FIL  21
+#define     IERES_REQD  22
+#define     IE_UVALID   23
+
+#define     C_XLATE     24                  /* # Of Internal Control Codes    */
+#define     CTRL_SIZE   2                   /* Max Length Of Control String   */
+#define     CTRL_ENTRY  C_XLATE*3           /* # Of Control Key Translations  */
+#define     K_XLATE     ((unsigned) ((KEYSTR) -1))+1 /* # Of Unique Key Vals. */
+
+
+struct      CXLATE      {                   /* Control Key Translation Entry  */
+
+                unsigned int    length;             /* Length Of Input String */
+                KEYSTR          ctrlin[CTRL_SIZE];  /* Input String           */
+                unsigned int    sd_ctrl;            /* Index To sd2_ctrl_codes*/
+                        };
+
+extern KEYSTR sd2_ctrl_codes[];                     /* Declare Global Tables  */
+extern struct CXLATE ctrl_xlate[];
+extern KEYSTR key_xlate[];
+
+
+/*==================== INTERNAL KEY & ERROR CONTROL CODES ====================*/
+
+#define     NXTFLD      sd2_ctrl_codes[NXT_FLD]     /* Control Codes          */
+#define     PRVFLD      sd2_ctrl_codes[PRV_FLD]
+#define     FSTFLD      sd2_ctrl_codes[FST_FLD]
+#define     LSTFLD      sd2_ctrl_codes[LST_FLD]
+#define     CURLFT      sd2_ctrl_codes[CUR_LFT]
+#define     CURRGT      sd2_ctrl_codes[CUR_RGT]
+#define     BEGFLD      sd2_ctrl_codes[BEG_FLD]
+#define     ENDFLD      sd2_ctrl_codes[END_FLD]
+#define     CLRFLD      sd2_ctrl_codes[CLR_FLD]
+#define     CLREND      sd2_ctrl_codes[CLR_END]
+#define     EXTFLD      sd2_ctrl_codes[EXT_FLD]
+#define     INSERT      sd2_ctrl_codes[INS]
+#define     DELETE      sd2_ctrl_codes[DEL]
+#define     BKSPC       sd2_ctrl_codes[BS]
+#define     HELPKEY     sd2_ctrl_codes[HELP]
+#define     EXTSCR      sd2_ctrl_codes[EXT_SCR]
+
+
+                /* INTERNAL ERROR AND STATUS CODES */
+
+#define SD2_NOERR     (ERRCODE) sd2_ctrl_codes[IENO_ERR] /* No Error          */
+#define SD2_ENOTRES   (ERRCODE) sd2_ctrl_codes[IENOTRES] /* No Response Allow */
+#define SD2_EFNULL    (ERRCODE) sd2_ctrl_codes[IEFNULL]  /* Null Array In Fld.*/
+#define SD2_EBAD_CTRL (ERRCODE) sd2_ctrl_codes[IEBAD_CTRL] /* Bad Keybd. Ctrl.*/
+#define SD2_NULFPTR   (ERRCODE) sd2_ctrl_codes[IENUL_FPTR] /* Null Fld. Ptr.  */
+#define SD2_MUSTFIL   (ERRCODE) sd2_ctrl_codes[IEMUST_FIL] /* Must Fill Error */
+#define SD2_RESREQD   (ERRCODE) sd2_ctrl_codes[IERES_REQD] /* RReqd. Error    */
+#define SD2_IEUVALID  (ERRCODE) sd2_ctrl_codes[IE_UVALID] /* User Valid. Error*/
+
+
+/*======================== FUNCTION DECLARATIONS =============================*/
+
+
+#if     ANSI
+
+               /*** GENERIC ScreenDoor FUNCTIONS ***/
+
+void            sd2_sound(int x, int y);
+void            sd2_cursor(unsigned char x, unsigned char y);
+unsigned long   sd2_rdcursor(void);
+unsigned long   sd2_rowcol(VCOORD y, VCOORD x);
+void            sd2_cls(VATRB x);
+KEYSTR          sd2_getc(void);
+unsigned int    sd2_aputs(char *x, VATRB y);
+
+#if     PC_BIOS & PCDOS
+void            pcbios_getvmode(void);
+void            pcbios_setvmode(VMODE x);
+void            pcbios_setvpage(VPAGE x);
+#endif
+
+KEYSTR          sd2_keyin(void);
+ERRCODE         sd2_init(char *x);
+ERRCODE         sd2_fedit(struct SD2_FIELD *x, KEYSTR *y);
+void            sd2_fdsply(struct SD2_FIELD *x, BOOL y, FLEN z);
+void            sd2_help(struct SD2_SCRN *x);
+
+#else
+               /*** GENERIC ScreenDoor FUNCTIONS ***/
+
+void            sd2_sound();
+void            sd2_cursor();
+unsigned long   sd2_rdcursor();
+unsigned long   sd2_rowcol();
+void            sd2_cls();
+KEYSTR          sd2_getc();
+unsigned int    sd2_aputs();
+
+#if     PCDOS & PC_BIOS
+void            pcbios_getvmode();
+void            pcbios_setvmode();
+void            pcbios_setvpage();
+#endif
+
+KEYSTR          sd2_keyin();
+ERRCODE         sd2_init();
+ERRCODE         sd2_fedit();
+void            sd2_fdsply();
+void            sd2_help();
+
+#endif
+
+
+/*=====================END OF <SD2_DEFS.H> INSERT DECK =======================*/
+
diff --git a/screendoor/SD2/SD2_KEYI.C b/screendoor/SD2/SD2_KEYI.C
new file mode 100644
index 0000000..c02d7bf
--- /dev/null
+++ b/screendoor/SD2/SD2_KEYI.C
@@ -0,0 +1,169 @@
+/*  SD2_KEYIN.C -   ScreenDoor II Keystroke Capture & Mapping Routines
+                    This Code Captures A Keystroke And Maps It According
+                            To The Global Key Value Maps.
+
+                    Last Modified: 08-02-88
+                    Copyright (C) 1988, T.A. Daneliuk
+
+
+        Input keystrokes are translated two ways.  First, a keystroke is
+        checked to see if it might be the beginning of a system specific
+        control key sequence.  If so, additional keystrokes are read and
+        if a sequence of keystrokes matches one of the entries in
+        the control key mapping table (ctrl_xlate), an internal ScreenDoor
+        control code is returned.  (This value is found in sd2_ctrl_codes.)
+        If after examining CTRL_SIZE number of keystrokes no entry has
+        been found in ctrl_xlate, those keystrokes are thrown away.
+
+        If an input is seen as data, it is translated via the key_xlate array.
+        This allows one-for-one character mapping.
+
+        The idea behind this is that all of the internal code representations
+        and key bindings can be modified at init time via sd2_init().
+
+*/
+
+#include    <stdio.h>
+#include    <sd2_defs.h>
+
+#if ANSI
+static BOOL match(unsigned x, unsigned y);
+#else
+static BOOL match();
+#endif
+
+
+/*============ Global Control And Keystroke Translation Tables ===============*/
+
+KEYSTR          sd2_ctrl_codes[C_XLATE];    /* Intialized By sd2_init() !!!   */
+
+
+#if     PCDOS & PC_BIOS /* Ctrl. Table Must Be Redefined For Each Environment */
+
+struct CXLATE ctrl_xlate[CTRL_ENTRY] =     {2,  0, 80, NXT_FLD, /* Dn. Arrow  */
+                                            1,  9,  0, NXT_FLD, /* Tab        */
+                                            2,  0, 15, PRV_FLD, /* Back Tab   */
+                                            2,  0, 72, PRV_FLD, /* Up Arrow   */
+                                            2,  0, 73, FST_FLD, /* PgUp       */
+                                            2,  0, 81, LST_FLD, /* PgDn       */
+                                            2,  0, 75, CUR_LFT, /* Lft. Arrow */
+                                            2,  0, 77, CUR_RGT, /* Rt. Arrow  */
+                                            2,  0, 71, BEG_FLD, /* Home       */
+                                            2,  0, 79, END_FLD, /* End        */
+                                            1, 10,  0, CLR_FLD, /* Ctrl-Enter */
+                                            2, 0, 117, CLR_END, /* Ctrl-End   */
+                                            1, 13,  0, EXT_FLD, /* Enter      */
+                                            2,  0, 82, INS,     /* Ins        */
+                                            2,  0, 83, DEL,     /* Del        */
+                                            1,  8, 00, BS,      /* Backspace  */
+                                            2,  0, 59, HELP,    /* Fn. 1      */
+                                            1, 27,  0, EXT_SCR  /* Esc        */
+                                           };
+#endif
+
+KEYSTR      key_xlate[K_XLATE];             /* Initialized By sd2_init() !!!  */
+
+
+/*====================== Get And Map Keyboard Input ==========================*/
+
+
+static  KEYSTR   work[CTRL_SIZE];       /* Working Buffer For Ctrl. Sequences */
+
+static BOOL match();
+
+
+
+KEYSTR  sd2_keyin()
+
+{
+    BOOL     in_ctrl;                   /* TRUE = Now Parsing Ctrl. String    */
+    unsigned first_ctrl;                /* Index Of 1st Possible Ctrl. Match  */
+    unsigned index;                     /* Index Into Control String Itself   */
+    KEYSTR   key;
+    unsigned    x;                      /* Working Variable                   */
+
+    in_ctrl     = FALSE;
+    first_ctrl  = 0;
+    index       = 1;
+
+    key = sd2_getc();                   /* Get A Character */
+
+    first_ctrl = 0;                     /* See If It Might Be A Ctrl. String  */
+
+    while ((first_ctrl < CTRL_ENTRY) && (in_ctrl == FALSE))
+        {
+        if ((ctrl_xlate[first_ctrl].length > 0) &&
+            (ctrl_xlate[first_ctrl].ctrlin[0] == key))
+            {
+            in_ctrl = TRUE;             /* 1st Char Matches                   */
+            work[0] = key;              /* So Save It                         */
+            }
+        first_ctrl++;
+        }
+
+    if (in_ctrl == FALSE)                   /* Not A Control String           */
+        key = key_xlate[(unsigned) key];    /* So Translate The Character     */
+
+    else                                    /* Match/Xlate Control String     */
+        {
+        first_ctrl--;                       /* Adjust To Point To Real Field  */
+        while (in_ctrl == TRUE)             /* Go 'Till Match Or Miss         */
+            {
+            x = first_ctrl;
+            while ((x < CTRL_ENTRY) && (in_ctrl == TRUE))
+                {
+                if (match(x, index) == TRUE)
+                    {
+                    in_ctrl = FALSE;
+                    key = sd2_ctrl_codes[ctrl_xlate[x].sd_ctrl];
+                    }
+                x++;                  /* Check From first_ctrl On For Match   */
+                }
+            if (in_ctrl == TRUE)        /* Still No Match                     */
+                {
+                if  (index == CTRL_SIZE)    /* Max. Length Input String       */
+                    {
+                    key = sd2_ctrl_codes[IEBAD_CTRL]; /* Bad Control String   */
+                    in_ctrl = FALSE;                /* We're Done             */
+                    }
+                else
+                    {
+                    key = sd2_getc();               /* Get Another Keystroke  */
+                    work[index] = key;
+                    index++;
+                    }
+                }
+            }
+        }
+
+    return(key);
+}
+
+
+/*=========See If Control String So Far Matches A Translation Entry ==========*/
+
+static BOOL match(x, y)
+unsigned    x, y;
+
+{
+
+    BOOL        flag;
+    unsigned    z, len;
+    z = 0;
+    len = ctrl_xlate[x].length;
+
+    if (y != len)                               /* String Lengths Don't Match */
+        flag = FALSE;
+    else                                        /* Lengths The Same           */
+        {
+        while ((work[z] == ctrl_xlate[x].ctrlin[z]) && (z < len))
+            z++;
+        if (z == len)                           /* All Chars Matched          */
+            flag = TRUE;
+        else
+            flag = FALSE;
+        }
+
+    return (flag);
+
+}
diff --git a/screendoor/SDOOR.BAT b/screendoor/SDOOR.BAT
new file mode 100644
index 0000000..56755a7
--- /dev/null
+++ b/screendoor/SDOOR.BAT
@@ -0,0 +1,23 @@
+ECHO OFF
+IF _%1 == _ GOTO error
+IF  %1 == S GOTO doit
+IF  %1 == M GOTO doit
+IF  %1 == C GOTO doit
+IF  %1 == L GOTO doit
+IF  %1 == H GOTO doit
+
+:error
+ECHO Bad Command Line, Need Model: (S, M, C, L, H) & Debug Flag (D)
+GOTO done
+
+:doit
+IF _%2 == _D GOTO debug
+IF _%2 == _d GOTO debug
+MAKE model=%1 debug= SCRNDOOR
+GOTO done
+
+:debug
+MAKE model=%1 debug=/Zi SCRNDOOR
+
+:done
+
diff --git a/screendoor/SET_VPAG.C b/screendoor/SET_VPAG.C
new file mode 100644
index 0000000..de332e6
--- /dev/null
+++ b/screendoor/SET_VPAG.C
@@ -0,0 +1,23 @@
+/*  SET_VPAG.C - Select A Video Memory Page
+				Last Modified: 06/11/86
+				Copyright (C) 1986,  T.A. Daneliuk
+*/
+
+#include    <t&r.h>
+#include    <dos.h>
+
+void	set_vpage(page)		/* Select a particular video memory page */
+
+char	page;
+
+{
+extern	unsigned	_rax;
+extern	char	scr_page;
+
+	scr_page=page;			/* Inform PCIO where we're going */
+	_rax=0x0500;			/* Select video page by ORing into AL */
+	page=page & 0x03;		/* Mask out all but the significant bits */
+	_rax=_rax | page;
+	_doint(0x10);
+
+}
diff --git a/screendoor/SHOW_HLP.C b/screendoor/SHOW_HLP.C
new file mode 100644
index 0000000..84286a4
--- /dev/null
+++ b/screendoor/SHOW_HLP.C
@@ -0,0 +1,65 @@
+/*  SHOW_HLP.C - Help Screen Support For The vkeyin() Routine
+				Last Modified: 06/13/87
+				Copyright (C) 1986, 1987  T.A. Daneliuk
+*/
+
+
+#include		<stdio.h>
+#include		<system.h>
+#include		<t&r.h>
+#include		<vstruct.h>
+
+char	vpg_help=3;		/* Video Page Used For Help Screens */
+int		help_cls=TRUE;	/* TRUE Means Clear Screen Before Doing Help Screen */
+int		help_msg_cls=FALSE;	/* TRUE Means Clear Help Strings */
+int		help_cattr=clrnorm;	/* Color To Use When Clearing Help Strings */
+char	help_fill=' ';		/* Char. To Use When Clearing Help Strings */
+
+int		show_help(vptr,fld,lasthelp)
+
+struct	VSTRUCT	*vptr;
+int		fld,lasthelp;
+
+{
+extern	char	scr_page;		/* Global Defining Video Page Used For Input Screen */
+struct	VSTRUCT	*hptr;			/* Used As Temporary Pointer */
+int		c;						/* Used To Get KBD Input */
+char	vpg_temp;				/* Used To Save Video Page On Entry */
+hptr=((vptr+fld)->hlp);			/* Pointer to Help structure */
+vpg_temp=scr_page;				/* Save Current Video Page */
+
+scr_cursoff();			/* Cursor Off During Help */
+set_vpage(vpg_help);	/* Select Help video page */
+if ((lasthelp == 0xffff) || (lasthelp != fld))	/* Build Screen If Needed */
+	{
+	if (help_cls)		/* Clear screen if desired */
+		scr_clr();
+	if ((hptr->rvalid) != NULL)
+		(*(hptr->rvalid)) (vptr,fld);	/* Help Setup Call */
+	vdsply((vptr+fld)->hlp);
+	}
+HELP_WAIT:
+while ((c=ci()) != 0)	/* Wait For User */
+	;
+if ((c=ci()) != FN3)
+	goto HELP_WAIT;
+
+if ((lasthelp == 0xffff) || (lasthelp != fld))	/* If we built a screen */
+	{
+	if ((hptr->rvalid) != NULL)
+		(*(hptr->rvalid)) (vptr,fld);	/* Help Setup Call */
+	}
+
+if (help_msg_cls)		/* Clear out help strings */
+	{
+	vundsply(((vptr+fld)->hlp),help_cattr,help_fill);	/* Un-Display The Help Messages */
+	lasthelp=0xffff;		/* We'll Need To Redisplay Next Time Around */
+	}
+else
+	lasthelp=fld;
+
+set_vpage(vpg_temp);	/* Return to original Input video page */
+scr_curson();			/* Cursor Back On */
+return(lasthelp);
+}
+
diff --git a/screendoor/SOUND.ASM b/screendoor/SOUND.ASM
new file mode 100644
index 0000000..bc6b955
--- /dev/null
+++ b/screendoor/SOUND.ASM
@@ -0,0 +1,99 @@
+		PAGE	40,132
+		TITLE	IBM-PC Sound Generator
+		SUBTTL	Copyright (c) 1986, 1987 T.A. Daneliuk
+		NAME	SOUND
+;
+;
+; SOUND.A - ROUTINE CALLABLE BY MICROSOFT C TO PRODUCE SOUND ON IBM-PC
+;		LAST MODIFIED: 07/08 /87
+;		COPYRIGHT (C) 1986, 1987 T.A. DANELIUK
+;
+;
+; 	USAGE:	sound(FREQ,DURATION)
+;	WHERE,	FREQ IS UNSIGNED IN HERTZ
+;		DURATION IS UNSIGNED (18/SECOND)
+;
+
+INCLUDE		MSCMODEL.INC			; Model Equates
+
+PORTB_8255	EQU	61H			; 8255 PORT B
+FREQ_8253	EQU	42H			; 8253 TIMER LATCH
+COMMAND_8253	EQU	43H			; 8253 TIME COMMAND REGISTER
+CLOCKH		EQU	0012H			; CLOCK RATE HIGH BYTE - 1193180 HZ
+CLOCKL		EQU	34DCH			; CLOCK RATE LOW BYTE
+
+		IF	FARCODE
+		X	EQU	6		;OFFSET OF ARGUMENTS
+		ELSE
+		X	EQU	4		;OFFSET OF ARGUMENTS
+		ENDIF
+;
+;
+DURATION	EQU	[BP+X+8]		; PARAMETER OFFSETS
+FREQ		EQU	[BP+X+6]
+ELAPSED		EQU	[BP+6]			; ELAPSED TIME TICKS STORED HERE
+STARTL		EQU	[BP+4]			; STORES INITIAL TIMER COUNT
+STARTH		EQU	[BP+2]
+;
+;
+_TEXT		SEGMENT	BYTE PUBLIC 'CODE'
+		ASSUME	CS:_TEXT
+
+		PUBLIC	_sound
+		IF	FARCODE
+_sound		PROC	FAR
+		ELSE
+_sound		PROC	NEAR
+		ENDIF
+;
+;
+		XOR		AX,AX		; ZERO REGISTER
+		PUSH		AX		; INIT. ELAPSED TIME
+		PUSH		AX		; INIT. STARTL
+		PUSH		AX		; INIT. STARTH
+		PUSH		BP		; PRESERVE REGISTER
+		MOV		BP,SP		; LOCAL STACK FRAME
+		MOV		AX,FREQ		; MAKE SURE FREQ. <> 0!
+		AND		AX,AX
+		JZ		SOUND_DONE	; IF SO, SKIP THE WHOLE THING
+		IN		AL,PORTB_8255	; GET CURRENT 8255 VALUE
+		OR		AL,3		; TURN ON SPEAKER/GATE SIGNAL
+		OUT		PORTB_8255,AL	; WRITE BACK TO 8255
+		MOV		AL,0B6H		; TELL TIMER, FREQUENCY IS SENT NEXT 
+		OUT		COMMAND_8253,AL
+		MOV		DX,CLOCKH	; DIVIDE CLOCK RATE BY PASSED
+		MOV		AX,CLOCKL	; FREQUENCY TO GET TOTAL
+		MOV		CX,FREQ		; NUMBER OF TICKS TO WAIT
+		DIV		CX
+		OUT		FREQ_8253,AL	; LOW BYTE TO TIMER
+		XCHG		AL,AH		; INTEL'S NEAT INSTRUCTION SET!
+		OUT		FREQ_8253,AL	; HIGH BYTE TO TIMER
+		XOR		AX,AX		; GET CURRENT TIMER COUNT IN CX:DX
+		INT		1AH
+		MOV		STARTH,CX	; SAVE FOR FUTURE REFERENCE
+		MOV		STARTL,DX
+DELAY:		MOV		AX,DURATION	; WAIT TILL ELAPSED TIME IS
+		CMP		AX,ELAPSED	; >= DURATION PASSED ON STACK
+		JBE		SOUND_OFF
+		XOR		AX,AX		; GET CURRENT TIMER COUNT
+		INT		1AH
+		MOV		AX,STARTH	; GET STARTING TIME
+		MOV		BX,STARTL
+		SUB		DX,BX		; LOW WORD FIRST
+		SBB		CX,AX		; HIGH WORD WITH CARRY
+		JNZ		SOUND_OFF	; ONLY CAN DEAL WITH 16 BIT INTERVALS
+		MOV		ELAPSED,DX	; SAVE TIME ELAPSED
+		JMP		DELAY
+SOUND_OFF:	IN		AL,PORTB_8255	; TURN OFF SPEAKER/GATE SIGNAL
+		AND		AL,11111100B
+		OUT		PORTB_8255,AL
+SOUND_DONE:	POP		BP		; RESTORE ENVIRONMENT
+		POP		AX		; BALANCE THE STACK
+		POP		AX
+		POP		AX
+		RET				; THERE'S NO PLACE LIKE HOME!
+;
+;
+_sound		ENDP
+_TEXT		ENDS
+		END
diff --git a/screendoor/STDMSGS.H b/screendoor/STDMSGS.H
new file mode 100644
index 0000000..151defd
--- /dev/null
+++ b/screendoor/STDMSGS.H
@@ -0,0 +1,12 @@
+/*  STDMSGS.H - Standard Messages Used In T&R Communications Software Products
+			Last Modified: 03/13/86
+			Copyright (C) 1986, T.A. Daneliuk
+*/
+
+/*  Standard Messages  */
+
+char	copyright[]={"[ Copyright (C) 1986, T&R Communications Associates, Chicago, IL  60625 ]"};
+char	version[]={"[ Version: 0.0.0 ]"};
+
+
+/*  END OF <STDMSGS.H> INSERT DECK  */
diff --git a/screendoor/SYSTEM.H b/screendoor/SYSTEM.H
new file mode 100644
index 0000000..b267232
--- /dev/null
+++ b/screendoor/SYSTEM.H
@@ -0,0 +1,111 @@
+/*   SYSTEM.H - Color, Video, And System Definitions For IBM-PC 
+		Last Modified: 06/19/86
+		Copyright (C) 1986, T.A. Daneliuk
+*/
+
+
+/*  Color Attribute Definitions
+
+
+		General format for attribute byte is:
+
+
+				b0-b2	Foreground Color
+				b3		Low Intensity Bit
+				b4-b6	Background Color
+				b7		Blinking Bit
+
+		Foreground and border can be any color.
+		Background must be 0 to 7.
+
+*/
+
+#define		BLACK		0
+#define		BLUE		1
+#define		GREEN		2
+#define		CYAN		3
+#define		RED			4
+#define		MAGENTA		5
+#define		BROWN		6
+#define		WHITE		7
+#define		GRAY		8
+#define		LBLUE		9
+#define		LGREEN		10
+#define		LCYAN		11
+#define		LRED		12
+#define		LMAGENTA	13
+#define		YELLOW		14
+#define		HWHITE		15
+#define		NORMAL		7			/* White On Black Video      */
+#define		REVERSE		0x70		/* Reverse Video             */
+#define		BLINK		0x80		/* Blink attribute bit       */
+#define		INTENSE		HWHITE		/* Emphasized White On Black */
+
+
+/*  Terminal Definitions  */
+
+
+#define		VWIDTH		80			/* Display width */
+#define		VHEIGHT		25			/* Display height */
+
+
+/*  Cursor And Attribute Macros  */
+
+
+#define		color(fore,back)	((back<<4)|fore)	/* Make valid PC color attribute from colors */
+#define		center(string)		(strlen(string)>=VWIDTH ? 0:(VWIDTH-strlen(string))/2)
+#define		dsplylin(v,h,s,a)	{v_rowcol(v,h);scr_aputs(s,a);}
+#define		fill_lin(v,h,c,l,a)	dsplylin(v,h,mkstr(c,l),a)
+#define		cursorblk(x)		(x==TRUE ? cursorsz(0,7):cursorsz(6,7))
+
+
+/*  Border Character Definitions  */
+
+
+#define		BORDERV		0xBA
+#define		BORDERH		0xCD
+#define		BORDERNE	0xBB
+#define		BORDERSE  	0xBC
+#define		BORDERNW	0xC9
+#define		BORDERSW	0xC8
+
+
+/* Key Definitions */
+
+
+#define		TAB			0x09
+#define		TABBK		0x0F				/* Preceeded by 00 */
+#define		INS			0x52				/* Preceeded by 00 */
+#define		DEL			0x53				/* Preceeded by 00 */
+#define		SPACE		0x20
+#define		BKSPC		0x08
+#define		ENTER		0x0D
+#define		CLR_FLD		0x0A
+#define		ESC			0x1B				/* Preceeded by 00 */
+#define		UARROW		0x48				/* Preceeded by 00 */
+#define		DARROW		0x50				/* Preceeded by 00 */
+#define		RARROW		0x4D				/* Preceeded by 00 */
+#define		LARROW		0x4B				/* Preceeded by 00 */
+#define		HOME		0x47				/* Preceeded by 00 */
+#define		END			0x4F				/* Preceeded by 00 */
+#define		PGUP		0x49				/* Preceeded by 00 */
+#define		PGDN		0x51				/* Preceeded by 00 */
+#define		FN1			0x3B				/* Preceeded by 00 */
+#define		FN2			0x3C				/* Preceeded by 00 */
+#define		FN3			0x3D				/* Preceeded by 00 */
+#define		FN4			0x3E				/* Preceeded by 00 */
+#define		FN5			0x3F				/* Preceeded by 00 */
+#define		FN6			0x40				/* Preceeded by 00 */
+#define		FN7			0x41				/* Preceeded by 00 */
+#define		FN8			0x42				/* Preceeded by 00 */
+#define		FN9			0x43				/* Preceeded by 00 */
+#define		FN10		0x44				/* Preceeded by 00 */
+#define		HELP		FN1					/* Use function key 1 as Help */
+
+
+/* Misc. System Dependent Parameters */
+
+#define		MAXSTRING	199					/* Maximum string length (DeSmet) */
+
+
+/*  END OF <SYSTEM.H> INSERT DECK */
diff --git a/screendoor/T&R.H b/screendoor/T&R.H
new file mode 100644
index 0000000..95c77a4
--- /dev/null
+++ b/screendoor/T&R.H
@@ -0,0 +1,34 @@
+/*  T&R.H - System Definitions For T&R Communications Software Products
+			Last Modified: 06/16/87
+			Copyright (C) 1986, 1987 By T.A. Daneliuk
+*/
+
+/* Boolean Values And Data Types */
+
+#define FALSE   0
+#define TRUE    !FALSE
+
+typedef int     BOOL;                   /* Boolean Variable Type */
+
+
+/*  Color Definitions  */
+
+#define		clrnorm		color(WHITE,BLACK)		/* Normal Color */
+#define		clrbord		color(LBLUE,BLACK)		/* Borders */
+#define		clrbmsg		color(YELLOW,BLUE)		/* Border Messages */
+#define		clrprmt		color(YELLOW,BLACK)		/* Prompts */
+#define		clrresp		color(LGREEN,BLACK)		/* Responses After Editing*/
+#define		clrerr		color(BLACK,RED)		/* Errors */
+#define		clrstat		color(BLACK,GREEN)		/* Status */
+#define		clrclr		color(BLACK,BLACK)		/* Clear Line */
+#define		clrinp		REVERSE					/* Input Color */
+
+
+/*  Error And Status Line Parameters  */
+
+#define		errlin		24						/* 25th Line For Errors */
+#define		errlen		79						/* Length Of Error Line */
+#define		statlin		23						/* 24th Line For Status */
+#define		statlen		79						/* Length Of Status Line */
+
+/*  END OF <T&R.H> INSERT DECK  */
diff --git a/screendoor/VDSPLY.C b/screendoor/VDSPLY.C
new file mode 100644
index 0000000..1cde2e5
--- /dev/null
+++ b/screendoor/VDSPLY.C
@@ -0,0 +1,27 @@
+/*  VDSPLY.C - Display Prompts And Responses Per A VSTRUCT Structure
+				Last Modified: 06/12/86
+				Copyright (C) 1986,  T.A. Daneliuk
+*/
+
+#include	<stdio.h>
+#include	<system.h>
+#include	<vstruct.h>
+#include        <t&r.h>
+
+void	vdsply(vptr)
+
+struct VSTRUCT *vptr;
+
+{
+
+int	x;
+
+	for (x=0;(x==0 ? TRUE : ((vptr+x-1)->lastfld)!=TRUE);x++)
+			{
+				if (((vptr+x)->pdsply)==TRUE && ((vptr+x)->parray)!=NULL)
+					dsplylin((vptr+x)->pvert,(vptr+x)->phoriz,(vptr+x)->parray,(vptr+x)->pattrib);
+				if (((vptr+x)->rarray)!=NULL)
+					dsplylin((vptr+x)->rvert,(vptr+x)->rhoriz,(vptr+x)->rarray,(vptr+x)->rattrib);
+			}
+
+}
diff --git a/screendoor/VKEYIN.C b/screendoor/VKEYIN.C
new file mode 100644
index 0000000..ae0710a
--- /dev/null
+++ b/screendoor/VKEYIN.C
@@ -0,0 +1,511 @@
+/*  VKEYIN.C - Main Keyboard And Video Handler For Programs Using
+			   The VSTRUCT Video Control Structure
+				Last Modified: 06/13/87
+				Copyright (C) 1986, 1986  T.A. Daneliuk
+*/
+
+
+#include		<stdio.h>
+#include		<system.h>
+#include		<t&r.h>
+#include		<vstruct.h>
+
+
+/* Error Messages */
+
+static	char	msg_rreqd[]={"Entry Required In This Field!"};
+static	char	msg_mfill[]={"This Field Must Be Filled!"};
+static	char	msg_rval[]={"User Validation Error Occurred!"};
+
+
+/* Global Variables Needed By VKEYIN */
+
+int		errbeep_on=TRUE;			/* If TRUE, Will Beep On Error */
+unsigned errfreq=600;				/* Frequency In Hz Of Error Beep */
+unsigned errtime=7;					/* Beep Duration - 18/second */
+int		clear_attr=clrnorm;			/* Color To Use For Clearing Edit Fill Characters */
+int		errmsg_attr=clrerr;			/* Color To Use For Displaying Error Messages */
+int		errmsg_row=24;				/* Beginning Row For Error Messages */
+int		errmsg_col=0;				/* Beginning Column For Error Messages */
+int		errmsg_on=TRUE;				/* If TRUE Error Messages Will Be Displayed */
+int		errmsg_len=79;				/* Maximum Error Message Length */
+int		errmsg_cattr=clrnorm;		/* Attribute To Use When Clearing Error Message */
+char	clear_fill=' ';				/* Character To Use When Clearing Edit Fill Characters */
+char	errmsg_fill=' ';			/* Character To Use When Clearing Error Message */
+char	*errmsg_rreqd=msg_rreqd;	/* Pointer To rreqd Validation Error Message */
+char	*errmsg_mfill=msg_mfill;	/* Pointer To mustfill Validation Error Message */
+char	*errmsg_rval=msg_rval;	/* Pointer To rvalid Validation Error Message */
+char	vkeyin_version[]={"2.1.1.pcMsoft "};
+
+/*****************************************************************************/
+
+/* This Function Determines Whether The Current Field Can Receive A User Response.
+	User Response Is Allowed If:
+					1) rallow is TRUE in the structure for the field, and
+					2) rarray is not NULL for the field, and
+					3) rlen is > 0 for the field
+
+	If Any Of These Conditions Is Not Met, The Field Is Assumed Not To Receive
+	User Response.
+
+	If The Field Can Receive A Response, TRUE Is Returned, Else FALSE Is Returned.
+*/
+
+static	int	res_allowed(fldptr)
+
+struct	VSTRUCT	*fldptr;
+
+{
+if (!(fldptr->rallow) || ((fldptr->rarray)==NULL) || ((fldptr->rlen)<=0))
+	return(FALSE);
+else
+	return(TRUE);
+}
+
+/*****************************************************************************/
+
+/* This Function Displays The Current Field With Editing Fill Chars */
+
+static	void	showfld(vptr,offset)
+
+struct	VSTRUCT	*vptr;
+int		offset;
+
+{
+	scr_cursoff();
+	fill_lin(vptr->rvert,vptr->rhoriz,vptr->rfill,vptr->rlen,vptr->iattrib);	/* Do a line of fill chars */
+	dsplylin(vptr->rvert,vptr->rhoriz,vptr->rarray,vptr->iattrib);					/* Overlay with existing data */
+	v_rowcol(vptr->rvert,(vptr->rhoriz)+offset);												/* Put cursor where it was */
+	scr_curson();
+}
+
+/*****************************************************************************/
+
+/* This Function Cleans Editing Garbage Currently On Screen And
+   Redisplays The Current Contents Of The Response Array
+
+   This Function Also Performs Whole Field, Required Entry, And
+   Must Fill Validations.  FALSE Is Returned If No Error Is 
+   Detected.  If Error Is Detected, TRUE Is Returned, And Error
+   Message Is Displayed Per The Global Error Variables.	
+*/
+
+
+static	int		endfld(xptr,fld)
+
+struct	VSTRUCT	*xptr;
+int		fld;
+
+{
+
+struct	VSTRUCT	*vptr;
+static	int	error=FALSE;		/* Error Flag */
+
+vptr=xptr+fld;
+
+	fill_lin(vptr->rvert,vptr->rhoriz,clear_fill,vptr->rlen,clear_attr);	/* This clears the fld we just ended */
+	dsplylin(vptr->rvert,vptr->rhoriz,vptr->rarray,vptr->rattrib);			/* This (re-)displays the contents of the current field */
+
+	if (error && errmsg_on)	/* Currently processing and displaying errors */
+		dsplylin(errmsg_row,errmsg_col,mkstr(errmsg_fill,errmsg_len),errmsg_cattr);		/* Clear last error message */
+
+	error=FALSE;		/* Assume the error has been corrected */
+
+	if ((vptr->rreqd) && (strlen(vptr->rarray)==0))		/* No entry found in a rreqd field */
+		{
+		error=TRUE;
+		if (errmsg_on)
+			dsplylin(errmsg_row,errmsg_col,*errmsg_rreqd,errmsg_attr);
+		}
+
+	else if ((vptr->mustfill) && (strlen(vptr->rarray)!=(vptr->rlen)))		/* Field not full in mustfill field */
+		{
+		error=TRUE;
+		if (errmsg_on)
+			dsplylin(errmsg_row,errmsg_col,*errmsg_mfill,errmsg_attr);
+		}
+
+	else if ((vptr->rvalid) != NULL)		/* See if user validation routine enabled */
+		{
+		if ((*(vptr->rvalid)) (xptr,fld))	/* Call it - Validation error if TRUE returned */
+			{
+			error=TRUE;
+			if (errmsg_on)
+				dsplylin(errmsg_row,errmsg_col,*errmsg_rval,errmsg_attr);
+			}
+		}
+
+	if (error && errbeep_on)
+		sound(errfreq,errtime);
+
+	return(error);			/* Return error condition */
+
+}
+
+/*****************************************************************************/
+
+/* This Function Deletes The Character At Current Offset Within RARRAY,
+   Moves Characters To The Right Of This Location Over, And Appends A
+   \0 To The End Of The Array
+*/
+
+static	void	delchar(vptr,offset)
+
+struct	VSTRUCT	*vptr;
+int		offset;
+
+{
+	scr_cursoff();
+	strcpy((vptr->rarray)+offset,(vptr->rarray)+offset+1);
+	v_rowcol(vptr->rvert,vptr->rhoriz);
+	scr_aputs(vptr->rarray,vptr->iattrib);
+	scr_aputs(mkstr(vptr->rfill,1),vptr->iattrib);
+	scr_curson();
+}
+
+
+/*****************************************************************************/
+
+/* This Function Makes Room For A Character To Be Inserted At Current
+   Offset Position.
+*/
+
+static	void	inschar(vptr,offset)
+
+struct	VSTRUCT	*vptr;
+int		offset;
+
+{
+	int		length=strlen(vptr->rarray);
+
+	scr_cursoff();
+
+	*((vptr->rarray)+length+1)='\0';
+
+	while(length > offset)
+		{
+			*((vptr->rarray)+length)=*((vptr->rarray)+length-1);
+			length--;
+		}
+	v_rowcol(vptr->rvert,(vptr->rhoriz)+offset+1);
+	scr_aputs(((vptr->rarray)+offset+1),vptr->iattrib);
+
+	scr_curson();
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+/*****************************************************************************/
+
+/* vkeyin() Function Entry:
+
+		vptr -		Pointer To An Array Of Structures Per VSTRUCT.H
+		fld -		Field Number At Which Processing Is To Begin
+		singlefld -	If TRUE, Forces vkeyin To Process Only One Field And Then Return
+
+*/
+	
+
+void	vkeyin(vptr,fld,singlefld)
+
+struct	VSTRUCT	*vptr;			/* Pointer To Control Structure */
+unsigned int		fld;		/* Starting Field Number */
+int		singlefld;				/* If TRUE, Process Only One Field, Then Return */
+
+{
+
+int		c,cntrl,insert,offset,flderror,last,modified,resallowed,dummy,firstfld;
+int	lasthelp;
+
+modified=insert=FALSE;
+resallowed=FALSE;		/* Will be set to TRUE if any field allows a response */
+last=offset=0;
+lasthelp=0xffff;	/* 0xffff Flags The Fact That This Is 1st Time Through */
+
+	firstfld=fld;		/* Save in case we're only processing one field */
+
+	while (((vptr+last)->lastfld) != TRUE)	/* Calculate last field number */
+				last++;
+
+	fld=(fld>last ? 0:fld);  /* Force 1st field into range */
+
+	for (dummy=0;dummy<=last;++dummy)		/* See if response allowed in any field */
+		{
+			if (res_allowed(vptr+dummy))
+				resallowed=TRUE;
+		}
+
+	if (resallowed)		/* Point to 1st field >= entry field which allows entry */
+		{
+			while (!res_allowed(vptr+fld))
+				fld=(fld<last ? ++fld:0);  /* No entry allowed, get next fld */
+		}
+
+	v_rowcol((vptr+fld)->rvert,(vptr+fld)->rhoriz);	/* Position cursor */
+
+	if (singlefld && (firstfld != fld))			/* Make sure we're in field we started in */
+		resallowed=FALSE;	
+
+/*
+	Main loop executes only if:
+	1) The user doen't terminate with an FN3 key.
+	2) A response is allowed somewhere on the current screen.
+	3) In the case of single field processing, loop executes until current field is terminated.
+*/
+
+	while (resallowed)
+
+		{
+			flderror=FALSE;							/* TRUE means we got a fld validation error */
+
+			c=ci();									/* Get a character */
+			cntrl=FALSE;
+
+			if (c==0)								/* Prefix To Extended ASCII */
+				{
+				cntrl=TRUE;
+				c=ci();								/* Get next character */
+				}
+
+			if (c==ENTER || c==CLR_FLD || c==TAB || c==BKSPC)		/* Cursor control key */
+				cntrl=TRUE;
+
+
+			if (cntrl==TRUE)							/* Must be cursor control */
+
+				{
+
+					if (c==DARROW)
+						c=TAB;							/* TAB and Dn-Arrow Same Thing */
+					if (c==UARROW)
+						c=TABBK;						/* BackTAB and Up-Arrow Same Thing */
+
+					switch(c)							/* Cursor control handling */
+
+					{
+
+						case FN3:					/* User wants to quit */
+							if (flderror=endfld(vptr,fld))		/* Got an Error! Can't quit. */
+								;					/* So do nothing and keep looping */
+							else					/* No error, we're done */
+								resallowed=FALSE;	/* Turn main loop off */
+							break;
+
+						case HELP:
+							if ((vptr+fld)->hlp)		/* FALSE==NULL means no help screen */
+								lasthelp=show_help(vptr,fld,lasthelp);	/* Display The Help Screen */
+						break;
+
+						case TAB:						/* Tab */
+							if (!(flderror=endfld(vptr,fld)))		/* No Error Occured */
+								fld=((fld<last) ? ++fld:0);	/* Point to next field */
+							offset=0;
+							modified=insert=FALSE;
+							break;
+
+						case TABBK:						/* Reverse TAB */
+							if (!(flderror=endfld(vptr,fld)))		/* No Error Occured */
+								{
+								fld=((fld==0) ? last:--fld); /* Previous field */
+								while (!res_allowed(vptr+fld))
+									fld=(fld==0 ? last:--fld);  /* No entry allowed, get next fld */
+								}
+							offset=0;					/* Beginning of fld - Use offset as usual */
+							modified=insert=FALSE;
+							break;
+
+						case ENTER:						/* Enter */
+							if (!(flderror=endfld(vptr,fld)))		/* No Error Occured */
+								{
+								fld=(((vptr+fld)->autoskp) ? ++fld:fld);	/* Increment if autoskip set */
+								fld=(fld>last ? 0:fld);						/* Make sure fld in range */
+								}
+							offset=0;									/* Beginning of fld */
+							modified=insert=FALSE;
+							break;
+
+						case PGUP:						/* Pg Up */
+							if (!(flderror=endfld(vptr,fld)))		/* No error occured */
+								fld=0; 					/* Pt to first fld */
+							offset=0;					/* Beginning of fld */
+							modified=insert=FALSE;
+							break;
+
+						case PGDN:						/* Pg Dn */
+							if (!(flderror=endfld(vptr,fld)))		/* No error occured */
+								{
+								fld=last; 					/* Pt to last fld */
+								while (!res_allowed(vptr+fld))
+									fld=(fld==0 ? last:--fld);  /* No entry allowed, get next fld */
+								}
+							offset=0;					/* Beginning of fld */
+							modified=insert=FALSE;
+							break;
+
+						case INS:						/* INSert mode toggle */
+							insert=((insert==FALSE) ? TRUE:FALSE);
+							break;	
+
+						case DEL:						/* DELete character */
+							if (!modified)					/* 1st time through */
+								{
+									showfld(vptr+fld,offset);
+									modified=TRUE;									/* Indicate that field was modified */
+								}
+							delchar(vptr+fld,offset);
+							break;
+
+						case CLR_FLD:
+							for (offset=0;offset <= ((vptr+fld)->rlen);offset++)
+								*(((vptr+fld)->rarray)+offset)='\0';
+							offset=0;
+							showfld(vptr+fld,offset);
+							modified=TRUE;
+							break;
+
+						case BKSPC:						/* Backspace */
+							if (!modified)				/* 1st time through */
+								{
+									showfld(vptr+fld,offset);
+									modified=TRUE;									/* Indicate that field was modified */
+								}
+							offset=(offset==0 ? ((vptr+fld)->rlen)-1:--offset);
+							offset=(offset>strlen((vptr+fld)->rarray) ? strlen((vptr+fld)->rarray):offset);		/* Cursor past end of valid data */
+							delchar(vptr+fld,offset);
+							break;
+
+						case RARROW:					/* Right Arrow */
+							offset=(offset>=(((vptr+fld)->rlen)-1) ? 0:++offset);	/* Position no greater than field length */
+							offset=(offset>strlen((vptr+fld)->rarray) ? 0:offset);	/* Position only 1 past end of existing data */
+							break;
+
+						case LARROW:					/* Left Arrow */
+							offset=(offset==0 ? ((vptr+fld)->rlen)-1:--offset);
+							offset=(offset>strlen((vptr+fld)->rarray) ? strlen((vptr+fld)->rarray):offset);		/* Cursor past end of valid data */
+							break;
+
+						case HOME:						/* Home Key */
+							offset=0;					/* Go to start of fld */
+							break;
+
+						case END:						/* End Key */
+							offset=strlen((vptr+fld)->rarray);	/* Go to end of fld */
+							if (offset==((vptr+fld)->rlen))		/* Never wrap back to beginning */
+								--offset;
+							break;
+
+					}
+				if ((!flderror) && singlefld && (c==TAB || c==TABBK || c==ENTER || c==PGUP || c==PGDN))
+					resallowed=FALSE;				/* Single Field Processing */
+				}
+
+			/* Not A Cursor Motion Control Character - Must Be Printable Or Out-Of-Range */
+
+			else if ((offset < ((vptr+fld)->rlen)) && isprint(c) && ((c!=SPACE) || (c==SPACE && ((vptr+fld)->rspace))))	/* Legitimate characters from 0x20 to 0x7E */
+				{
+
+				/* Individual Character Validations - If Validation Fails, c Is Set To 0 */
+
+					switch((vptr+fld)->rcval)
+						{
+							case 0:					/* No Validation */
+								break;
+							case 1:					/* Force Upper Case */
+								c=toupper(c);
+								break;
+							case 2:					/* Force Lower Case */
+								c=tolower(c);
+								break;
+							case 3:					/* Alpha Only */
+								if (!isalpha(c))
+									c=0;
+								break;
+							case 4:					/* Alpha Only - UC */
+								c=toupper(c);
+								if (!isalpha(c))
+									c=0;
+								break;
+							case 5:					/* Alpha Only - LC */
+								c=tolower(c);
+								if (!isalpha(c))
+									c=0;
+								break;
+							case 6:					/* AlphaNumeric Only */
+								if (!isalnum(c))
+									c=0;
+								break;
+							case 7:					/* AlphaNumeric Only - UC */
+								c=toupper(c);
+								if (!isalnum(c))
+									c=0;
+								break;
+							case 8:					/* AlphaNumeric Only - LC */
+								c=tolower(c);
+								if (!isalnum(c))
+									c=0;
+								break;
+							case 9:					/* Binary Digits Only */
+								if (c<'0' || c>'1')
+									c=0;
+								break;
+							case 10:				/* Octal Digits Only */
+								if (c<'0' || c>'7')
+									c=0;
+								break;
+							case 11:				/* Decimal Digits Only */
+								if (!isdigit(c))
+									c=0;
+								break;
+							case 12:				/* Hexadecimal Digits Only - UC */
+								c=toupper(c);
+								if (!isdigit(c) && (c<'A' || c>'F'))
+									c=0;
+								break;
+							case 13:				/* 'Y' or 'N' Only - UC */
+								c=toupper(c);
+								if ((c!='Y') && (c!='N'))
+									c=0;
+								break;
+							case 14:				/* Floating Point Format */
+								if (!isdigit(c) && c!='.' && c!='+' && c!='-')
+									c=0;
+								break;
+							case 15:				/* Unsigned Floating Point Format */
+								if (!isdigit(c) && c!='.')
+									c=0;
+								break;
+							case 16:				/* Exponential Floating Point Format */
+								c=toupper(c);
+								if (!isdigit(c) && c!='E' && c!='.' && c!='+' && c!='-')
+									c=0;
+								break;
+						}
+
+					if (c != 0)		/* Process Character Only If Validation Was OK */
+						{
+
+						if (!modified)					/* 1st time through */
+							{
+								showfld(vptr+fld,offset);
+								modified=TRUE;									/* Indicate that field was modified */
+							}
+						scr_aputs(mkstr(c,1),(vptr+fld)->iattrib);		/* Display the character */
+						if (insert)										/* Insert mode set */
+							inschar((vptr+fld),offset);
+						*(((vptr+fld)->rarray)+offset)=c;			/* And stuff into proper array location */
+						++offset;		/* Increment position and don't wrap */
+						}
+					}
+/*
+	Housekeeping done each time we go through the main while loop
+*/
+
+			while (!res_allowed(vptr+fld))
+				fld=(fld<last ? ++fld:0);  /* No entry allowed, get next fld */
+			v_rowcol((vptr+fld)->rvert,((vptr+fld)->rhoriz)+offset);	/* Position cursor */
+			if (strlen((vptr+fld)->rarray)>=(vptr+fld)->rlen)
+				insert=FALSE;		/* Field Full - Can't Insert */
+			cursorblk(insert);		/* Show current insert status */
+
+		}
+}
diff --git a/screendoor/VSTRUCT.H b/screendoor/VSTRUCT.H
new file mode 100644
index 0000000..f889d07
--- /dev/null
+++ b/screendoor/VSTRUCT.H
@@ -0,0 +1,33 @@
+/*  VSTRUCT.H - Video Data Control Structure Template
+				Last Modified: 06/11/86
+				Copyright (C) 1986, T.A. Daneliuk
+*/
+
+
+struct	VSTRUCT
+{
+	int			iattrib;			/* Input Color Attributes				*/
+	int			pattrib;			/* Prompt Color Attributes				*/
+	int			pvert;				/* Prompt Vertical Position				*/
+	int			phoriz;				/* Prompt Horizontal Position			*/
+	int			pdsply;				/* TRUE Means Display Prompt			*/
+	char		*parray;			/* Pointer To Array Containing Prompt	*/
+	int			rattrib;			/* Response Color Attributes			*/
+	int			rvert;				/* Response Vertical Position			*/
+	int			rhoriz;				/* Response Horizontal Position			*/
+	int			rallow;				/* TRUE Means Allow User Response		*/
+	char		*rarray;			/* Pointer To Array Receiving Response	*/
+	int			rlen;				/* Maximum Allowed User Response Length	*/
+	char		rfill;				/* Keyin Time Fill Character			*/
+	int			rspace;				/* TRUE Allows Blanks In Response		*/
+	int			rcval;				/* Single Char. Validation Code 0=None	*/
+	int			(*rvalid) ();		/* Pointer To Validation Routine		*/
+	int			mustfill;			/* TRUE Means Field Must Be Filled		*/
+	int			rreqd;				/* TRUE Means A Response Is Required	*/
+	int			autoskp;			/* TRUE Means Autoskip On				*/
+	struct VSTRUCT *hlp;			/* Pointer To Help Screen Structure		*/
+	int			lastfld;			/* TRUE Indicates No More Field Defs.	*/
+};
+
+
+/*  END OF <VSTRUCT.H> INSERT DECK  */
diff --git a/screendoor/VUNDSPLY.C b/screendoor/VUNDSPLY.C
new file mode 100644
index 0000000..7540ea5
--- /dev/null
+++ b/screendoor/VUNDSPLY.C
@@ -0,0 +1,28 @@
+/*  VUNDSPLY.C - Un-Displays Prompts And Responses Per A VSTRUCT Structure
+				Last Modified: 06/30/86
+				Copyright (C) 1986,  T.A. Daneliuk
+*/
+
+#include	<stdio.h>
+#include	<system.h>
+#include	<vstruct.h>
+#include        <t&r.h>
+
+void	vundsply(vptr,attr,fill)
+
+struct VSTRUCT *vptr;
+int		attr;
+char	fill;
+{
+
+int	x;
+
+	for (x=0;(x==0 ? TRUE : ((vptr+x-1)->lastfld)!=TRUE);x++)
+			{
+				if (((vptr+x)->pdsply)==TRUE && ((vptr+x)->parray)!=NULL)
+					dsplylin((vptr+x)->pvert,(vptr+x)->phoriz,mkstr(fill,strlen((vptr+x)->parray)),attr);
+				if (((vptr+x)->rarray)!=NULL)
+					dsplylin((vptr+x)->rvert,(vptr+x)->rhoriz,mkstr(fill,strlen((vptr+x)->rarray)),attr);
+			}
+
+}
diff --git a/screendoor/V_ROWCOL.C b/screendoor/V_ROWCOL.C
new file mode 100644
index 0000000..612a339
--- /dev/null
+++ b/screendoor/V_ROWCOL.C
@@ -0,0 +1,16 @@
+/*  V_ROWCOL - This Is A Front End Processor To scr_rowcol().
+	Does Bounds Checking Based On The Current Values Of scr_rows
+	And scr_cols And  Adjusts The Row And Column Values Passed By
+	The Calling Routine Before Calling scr_rowcol().
+	This Is Done To Prevent IBM BIOS Video Routines From Ever Being
+	Passed Invalid Row, Column Coordinates.  In Effect, Column Values
+	Are Wrapped To The Next Video Line, And Row Values Are Wrapped
+	Vertically.
+
+	Calling Sequence Is: v_rowcol(row,column);
+
+	Last Modified: 06/13/87
+	Copyright (c), 1986, 1987 By T.A. Daneliuk
+*/
+
+#include        <t&r.h>
diff --git a/setcolor/FORM1.FRM b/setcolor/FORM1.FRM
new file mode 100644
index 0000000..0f49a8d
--- /dev/null
+++ b/setcolor/FORM1.FRM
@@ -0,0 +1,154 @@
+VERSION 4.00
+Begin VB.Form Setcolor 
+   Appearance      =   0  'Flat
+   BackColor       =   &H80000005&
+   BorderStyle     =   3  'Fixed Dialog
+   Caption         =   "Tundra's Setcolor Demo (Because Amir Is Feeble)"
+   ClientHeight    =   4248
+   ClientLeft      =   1968
+   ClientTop       =   2340
+   ClientWidth     =   6444
+   BeginProperty Font 
+      name            =   "MS Sans Serif"
+      charset         =   0
+      weight          =   700
+      size            =   24
+      underline       =   0   'False
+      italic          =   0   'False
+      strikethrough   =   0   'False
+   EndProperty
+   ForeColor       =   &H80000008&
+   Height          =   4632
+   Left            =   1920
+   LinkTopic       =   "Form1"
+   ScaleHeight     =   4248
+   ScaleWidth      =   6444
+   Top             =   2004
+   Width           =   6540
+   Begin VB.HScrollBar BScroll 
+      Height          =   612
+      Left            =   3480
+      Max             =   15
+      TabIndex        =   4
+      Top             =   2880
+      Width           =   492
+   End
+   Begin VB.HScrollBar FScroll 
+      Height          =   612
+      Left            =   2280
+      Max             =   15
+      TabIndex        =   3
+      Top             =   2880
+      Width           =   492
+   End
+   Begin VB.CommandButton Background 
+      Appearance      =   0  'Flat
+      BackColor       =   &H80000005&
+      Caption         =   "Back"
+      BeginProperty Font 
+         name            =   "MS Sans Serif"
+         charset         =   0
+         weight          =   700
+         size            =   7.8
+         underline       =   0   'False
+         italic          =   0   'False
+         strikethrough   =   0   'False
+      EndProperty
+      Height          =   852
+      Left            =   3360
+      TabIndex        =   1
+      Top             =   1800
+      Width           =   732
+   End
+   Begin VB.CommandButton Foreground 
+      Appearance      =   0  'Flat
+      BackColor       =   &H80000005&
+      Caption         =   "Fore"
+      BeginProperty Font 
+         name            =   "MS Sans Serif"
+         charset         =   0
+         weight          =   700
+         size            =   7.8
+         underline       =   0   'False
+         italic          =   0   'False
+         strikethrough   =   0   'False
+      EndProperty
+      Height          =   852
+      Left            =   2160
+      TabIndex        =   0
+      Top             =   1800
+      Width           =   732
+   End
+   Begin VB.Label SampleText 
+      Alignment       =   2  'Center
+      Appearance      =   0  'Flat
+      BackColor       =   &H80000005&
+      BorderStyle     =   1  'Fixed Single
+      Caption         =   "Sample Text"
+      BeginProperty Font 
+         name            =   "Courier New"
+         charset         =   0
+         weight          =   700
+         size            =   18
+         underline       =   0   'False
+         italic          =   0   'False
+         strikethrough   =   0   'False
+      EndProperty
+      ForeColor       =   &H80000008&
+      Height          =   852
+      Left            =   2040
+      TabIndex        =   2
+      Top             =   720
+      Width           =   2196
+   End
+End
+Attribute VB_Name = "Setcolor"
+Attribute VB_Creatable = False
+Attribute VB_Exposed = False
+Dim FColor As Integer
+Dim BColor As Integer
+
+Private Sub Background_Click()
+    If (BColor = 15) Then
+        BColor = 0
+    Else
+        BColor = BColor + 1
+    End If
+    BScroll.Value = BColor
+    Call setem
+End Sub
+
+Private Sub BScroll_Change()
+    BColor = BScroll.Value
+    Call setem
+End Sub
+
+Private Sub Foreground_Click()
+    If (FColor = 15) Then
+        FColor = 0
+    Else
+        FColor = FColor + 1
+    End If
+    FScroll.Value = FColor
+    Call setem
+End Sub
+
+Private Sub Form_Load()
+    FColor = 0
+    BColor = 15
+    FScroll.Value = FColor
+    BScroll.Value = BColor
+    SampleText.ForeColor = QBColor(FColor)
+    SampleText.BackColor = QBColor(BColor)
+End Sub
+
+Private Sub FScroll_Change()
+    FColor = FScroll.Value
+    Call setem
+End Sub
+
+Private Sub setem()
+    SampleText.BackColor = QBColor(BColor)
+    SampleText.ForeColor = QBColor(FColor)
+End Sub
+
diff --git a/setcolor/Project1.mak b/setcolor/Project1.mak
new file mode 100644
index 0000000..41687f4
--- /dev/null
+++ b/setcolor/Project1.mak
@@ -0,0 +1,18 @@
+Form=FORM1.FRM
+Object={F9043C88-F6F2-101A-A3C9-08002B2F49FB}#1.0#0; COMDLG32.OCX
+Reference=*\G{00025E04-0000-0000-C000-000000000046}#2.5#0#C:\PROGRAM FILES\COMMON FILES\MICROSOFT SHARED\DAO\dao2532.tlb#Microsoft DAO 2.5/3.0 Compatibility Library
+ProjWinSize=74,385,252,122
+ProjWinShow=2
+IconForm="Setcolor"
+Title="PROJECT1"
+ExeName="SETCOLOR.EXE"
+Name="Project1"
+HelpContextID="0"
+StartMode=0
+VersionCompatible32="0"
+MajorVer=1
+MinorVer=0
+RevisionVer=0
+AutoIncrementVer=0
+ServerSupportFiles=0
+VersionCompanyName="TundraWare"
diff --git a/setcolor/SETCOLOR.EXE b/setcolor/SETCOLOR.EXE
new file mode 100644
index 0000000..d4de742
--- /dev/null
+++ b/setcolor/SETCOLOR.EXE
Binary files differ
diff --git a/strdup/STRDUP.C b/strdup/STRDUP.C
new file mode 100644
index 0000000..942210a
--- /dev/null
+++ b/strdup/STRDUP.C
@@ -0,0 +1,19 @@
+/*	STRDUP.C - String Copy Function Which Does Not Copy The Null Terminator
+			Copyright (C) 1986 T.A. Daneliuk
+			Last Modified: 09/15/86
+*/
+
+void	strdup(dst,src)
+
+char	*dst,*src;
+
+{
+
+while (*src != '\0')
+		{
+		*dst=*src;
+		src++;
+		dst++;
+		}
+
+}
diff --git a/swpr/SW_PR.ASM b/swpr/SW_PR.ASM
new file mode 100644
index 0000000..2ff0f3d
--- /dev/null
+++ b/swpr/SW_PR.ASM
@@ -0,0 +1,294 @@
+
+		PAGE	40,132
+		TITLE	SW_PR.ASM
+;
+;
+; **********
+; * SW_PR.ASM - PRINTER REASSIGNMENT FILTER - VERSION 1.5
+; * LAST MODIFIED: 12/11/85
+; * COPYRIGHT (C) BY T.A. DANELIUK
+; **********
+;
+;
+; **********
+; * SYSTEM EQUATES
+; **********
+;
+;
+SPACE		EQU	20H				; ASCII SPACE
+DOS		EQU	21H				; DOS INTERRUPT
+EOL		EQU	0A0DH				; END-OF-LINE STRING
+EXIT		EQU	4CH				; NORMAL EXIT TO DOS
+GET_IR_VECT	EQU	35H				; GET VECTOR FROM IR TABLE
+PRINTER_IR	EQU	17H				; PRINTER IR VECTOR
+PRINT_STRING	EQU	09H				; IR TO PRINT STRING ON DISPLAY
+SET_IR_VECT	EQU	25H				; SET AN IR VECTOR IN TABLE
+TAB		EQU	09H				; ASCII TAB
+TAIL_BEGIN	EQU	81H				; OFFSET OF COMMAND TAIL IN PSP
+TAIL_LENGTH	EQU	80H				; LOC OF LENGTH BYTE IN CMD TAIL
+TERMINATE	EQU	31H				; TERMINATE/STAY RESIDENT
+;
+;
+;
+; **********
+; * CODE SEGMENT
+; **********
+;
+;
+SW_PR		SEGMENT WORD 'CODE'
+		ASSUME	CS:SW_PR,DS:SW_PR,ES:SW_PR
+;
+;
+
+		ORG	100H
+;
+START_RUN	EQU	THIS BYTE
+;
+;
+START:		JMP	INIT				; GO TO INITIALIZATION CODE
+;
+SWITCH_PR	EQU	THIS BYTE
+;
+; FIRST COMES THE HEADER
+;
+		JMP SHORT ENTRY
+		DW OFFSET END_RUN-1			; LAST ADDR. OF RESIDENT CODE
+MOD_NAME	DB	'SW_PR   '			; NAME OF MODULE IN ASCII
+;
+; THE FOLLOWING 4 HEADER BYTES ARE APPLICATION DEFINED.  IN THIS CASE THEY ARE USED
+; AS A PRINTER LOOKUP AND TRANSLATION TABLE FOR THE 3 POSSIBLE PRINTER IDS.
+;
+LPT_TBL		DB	0				; DEFAULT FOR LPT1:
+		DB	1				; DEFAULT FOR LPT2:
+		DB	2				; DEFAULT FOR LPT3:
+		DB	0				; UNUSED IN THIS CASE
+;
+; NOW THE ACTUAL RESIDENT INTERRUPT CODE
+;
+ENTRY:		PUSH	DX				; SAVE SCRATCH REGISTER
+		PUSH	BX
+		MOV	BX,OFFSET LPT_TBL		; POINT TO TABLE
+		ADD	BX,DX				; POINT TO PROPER ENTRY
+		MOV	DL,CS:[BX]			; GET THE VALUE THERE
+		POP	BX				; RESTORE BX
+RUN_DONE:	PUSHF					; FAKE AN INTERRUPT
+		CALL DWORD PTR CS:OLD_VECTOR		; GO TO ORIGINAL IR HANDLER
+;
+GO_BACK		EQU	THIS BYTE
+;
+		POP	DX
+		IRET					; BACK TO THE OUTSIDE WORLD
+;
+OLD_VECTOR	DD	?
+;
+END_RUN		EQU	THIS BYTE
+;
+;
+		PAGE
+; **********
+; * LOADER/INSTALL CODE
+; **********
+;
+;
+INIT: 		PUSHF					; SAVE IR STATUS
+		CLI					; TURN 'EM OFF FOR NOW
+;
+;
+; DISPLAY BANNER
+;
+;
+		MOV	DX,OFFSET MSG1
+		MOV	AH,PRINT_STRING
+		INT	DOS
+;
+;
+; FIRST, FIND OUT IF THE RESIDENT CODE IS ALREADY IN PLACE, AND SET THE
+; FLAG CALLED MODULE_RESIDENT APPROPRIATELY.
+;
+;
+		MOV	AH,GET_IR_VECT			; GET EXISTING PRINTER IR VECTOR
+		MOV	AL,PRINTER_IR
+		INT	DOS				; IT COMES BACK IN ES:BX
+		MOV	DI,BX				; BUT CMPS WANTS IT IN ES:DI
+		ADD	DI,4				; POINT TO ASCII NAME IN HEADER
+		MOV	SI,OFFSET MOD_NAME		; OTHER STRING FOR CMPS IN DS:SI
+		MOV	CX,8				; STRING LENGTH IN BYTES
+		REPZ CMPSB				; SEE IF STRINGS ARE EQUAL
+		JNZ	MOD_NOT_IN			; RESIDENT CODE IS *NOT* IN
+		NOT	MODULE_RESIDENT			; RESIDENT CODE *IS* IN
+		JMP SHORT BUILD_POINTERS
+MOD_NOT_IN:	MOV	AX,CS				; SAVE SEGMENT OF IR CODE
+		MOV	ES,AX
+;
+;
+; NOW BUILD POINTERS TO THE EXCHANGE TABLE AND COMMAND TAIL STRING.
+;
+;
+BUILD_POINTERS:	MOV	BP,TAIL_LENGTH			; GET TAIL'S LENGTH
+		MOV	CL,CS:[BP]			; INTO CL
+		INC	BP				; POINT TO BEGINNING OF TAIL
+		MOV	BX,OFFSET LPT_TBL		; SETUP PTR TO XLATE TABLE
+;
+;
+; NOW PARSE COMMAND TAIL AND BUILD THE PRINTER TRANSLATION TABLE.
+;
+;
+PARSE:		AND	CL,CL				; ARE THERE 0 CHARACTERS LEFT?
+		JZ	DSPL_STATUS			; YES, GO ON
+		MOV	AL,CS:[BP]			; GET A CHARACTER
+		CMP	AL,SPACE			; IS IT A BLANK?
+		JZ	WHITE_SPACE			; YES, SKIP IT
+		CMP	AL,TAB				; IS IT A TAB?
+		JZ	WHITE_SPACE			; YES, SKIP IT
+		CALL	VALIDATE_CHAR			; SEE IF ITS A LEGAL CHAR
+		JNC	PARM_ERR			; IF VALID, CARRY IS SET
+		CMP	CL,3				; WE MUST HAVE AT LEAST 3
+		JL	PARM_ERR			; CHARACTERS LEFT IN TAIL
+		MOV	AH,AL				; SAVE FOR FUTURE USE
+		MOV	AL,CS:[BP+1]			; CHECK FOR VALID ASSIGNMENT
+		CMP	AL,'='				; CHARACTER
+		JNZ	PARM_ERR	
+		MOV	AL,CS:[BP+2]			; GET RVALUE FOR TRANSLATION
+		CALL	VALIDATE_CHAR
+		JNC	PARM_ERR
+		CALL	INSTALL_ENTRY			; SETUP TABLE ENTRY
+		ADD	BP,3				; POINT TO NEXT PART OF TAIL 
+		SUB	CX,3				; DECREMENT CHARACTER COUNT
+		JMP	PARSE				; DO 'TILL TAIL IS ALL PARSED
+;
+WHITE_SPACE:	INC	BP				; POINT TO NEXT TAIL LOCATION
+		DEC	CL				; ADJUST CHARACTER COUNT
+		JMP	PARSE				; GO TRY AGAIN
+;
+VALIDATE_CHAR:	CMP	AL,'1'				; CHARACTER MUST BE 1,2, OR 3
+		JL	BAD_CHAR
+		CMP	AL,'3'
+		JG	BAD_CHAR
+		SUB	AL,'1'				; MAKE 0 RELATIVE BINARY
+		STC					; SET CARRY TO INDICATE GOOD CHAR
+		RET
+BAD_CHAR:	CLC					; NO CARRY FOR ERROR
+		RET
+;
+INSTALL_ENTRY:	PUSH	BX				; SAVE TABLE POINTER
+		PUSH	AX
+		MOV	AL,AH				; BUILD WORD OFFSET INTO TABLE
+		AND	AH,00H
+		ADD	BX,AX
+		POP	AX				; RESTORE INSTALL DATA
+		MOV	ES:[BX],AL			; INSTALL VALUE
+		POP	BX				; RESTORE TABLE POINTER
+		RET
+;
+PARM_ERR:	MOV	AH,PRINT_STRING			; DISPLAY MESSAGE
+		MOV	DX,OFFSET MSG3
+		INT	DOS
+		JMP	DSPL_STATUS
+		PAGE
+; DISPLAY CURRENT TRANSLATION VALUES ON SCREEN
+;
+;
+DSPL_STATUS:	MOV	BP,OFFSET L1			; ENTRY IN MESSAGE
+		CALL	SET_PR_VALUE
+		MOV	BP,OFFSET L2
+		CALL	SET_PR_VALUE
+		MOV	BP,OFFSET L3
+		CALL 	SET_PR_VALUE
+		MOV	DX,OFFSET MSG2			; DISPLAY THE MESSAGE
+		MOV	AH,PRINT_STRING
+		INT	DOS
+		MOV	AL,MODULE_RESIDENT		; DEPENDING ON WHETHER MODULE
+		AND	AL,AL				; IS RESIDENT, TERMINATE AND
+		JZ	CHAIN_IR			; STAY RESIDENT
+		JMP	NORM_EXIT			; OR JUST EXIT NORMALLY 
+;
+SET_PR_VALUE:	MOV	AL,ES:[BX]			; GET TABLE ENTRY
+		INC	AL				; MAKE "1 RELATIVE"
+		ADD	AL,'0'				; CONVERT TO ASCII
+		MOV	CS:[BP],AL			; SAVE IN MESSAGE
+		INC	BX				; POINT TO NXT TBL ENTRY
+		RET					; BACK TO THE RANCH
+		PAGE
+; GET EXISTING PRINTER VECTOR AND SAVE FOR CHAINING
+;
+;
+CHAIN_IR:	MOV	AH,GET_IR_VECT			; FUNCTION NUMBER
+		MOV	AL,PRINTER_IR			; INTERRUPT NUMBER
+		INT	DOS
+		MOV	BP,OFFSET OLD_VECTOR
+		MOV	CS:[BP],BX			; WE GOT THE OLD VECTOR IN ES:BX
+		MOV	BX,ES				; GET SEGMENT
+		MOV	CS:[BP+2],BX
+;
+;
+; STUFF NEW VECTOR INTO TABLE SO WE GET CONTROL FIRST
+;
+;
+		MOV	DX,OFFSET SWITCH_PR		; VECTOR IN DS:DX - DS ALREADY OK
+		MOV	AH,SET_IR_VECT
+		MOV	AL,PRINTER_IR
+		INT	DOS
+;
+;
+; TERMINATE, BUT STAY RESIDENT EXIT CODE
+;
+;
+RESIDE_EXIT:	MOV	AX,OFFSET END_RUN		; CALCULATE MODULE LENGTH IN PARAS
+		MOV	CL,10H				; DIVISOR
+		DIV	CL
+		AND	AH,AH				; ANY REMAINDER?
+		JZ	NO_REMAINDER			; NO
+		INC	AL				; YES, BUMP A FULL PARAGRAPH
+NO_REMAINDER:	XOR	DX,DX				; CLEAR DX
+		MOV	DL,AL				; TERMINATE FN. NEEDS LENGTH IN DX
+		XOR	AL,AL				; SET RETURN ERROR CODE TO 0
+		MOV	AH,TERMINATE			; TERMINATE & STAY RESIDENT FN
+		POPF					; RESET ORIGINAL IR STATUS
+		INT	DOS				; DO THE DOS CALL
+		PAGE
+; NORMAL EXIT CODE
+;
+;
+NORM_EXIT:	XOR	AL,AL				; RETURN WITHOUT ERROR
+		MOV	AH,EXIT
+		POPF
+		INT	DOS
+		PAGE
+; BANNER MESSAGE STRINGS
+;
+;
+MSG1		DW	EOL
+		DB	'SW_PR - PRINTER REASSIGNMENT FILTER - Version 1.5'
+		DW	EOL
+		DB	'Copyright (c) 1985, T.A. Daneliuk, Chicago, IL 60625'
+		DW	EOL
+		DB	'Permission Granted To Reproduce This Program'
+		DW	EOL
+		DB	'For PERSONAL, *** NON-COMMERCIAL *** Use Only!'
+		DW	EOL,EOL
+		DB	'$'
+;
+MSG2		DB	'LPT1: Is Assigned To Physical Printer #'
+L1		DB	?
+		DW	EOL
+		DB	'LPT2: Is Assigned To Physical Printer #'
+L2		DB	?
+		DW	EOL
+		DB	'LPT3: Is Assigned To Physical Printer #'
+L3		DB	?
+		DW	EOL,EOL
+		DB	'$'
+;
+MSG3		DB	'INVALID PARAMETER ON COMMAND LINE !!! '
+		DW	EOL,EOL
+		DB	'$'
+;
+;
+; STATIC STORAGE LOCATIONS
+;
+;
+MODULE_RESIDENT	DB	00H				; NON-ZERO MEANS MODULE ALREADY IN
+;
+;
+SW_PR		ENDS
+		END	START
diff --git a/sysenv/SYS_ENV.H b/sysenv/SYS_ENV.H
new file mode 100644
index 0000000..914c67f
--- /dev/null
+++ b/sysenv/SYS_ENV.H
@@ -0,0 +1,45 @@
+/*  SYS_ENV.H - Environment Specific Definitions
+                (Accounts For Operating System, Hardware, Etc.)
+
+                Last Modified: 07/12/88
+                Copyright (C) 1988, T.A. Daneliuk
+*/
+
+
+
+/*========================== DEBUGGING OPTIONS ===============================*/
+
+#define     DEBUG       0                   /* Set To 1 To Enable Debugging   */
+
+
+/*=========================== PROGRAM DEFINITIONS ============================*/
+
+#define	PROGNAME	"SYS_ENV"
+#define	VERSION		"1.0"
+
+/*============================= COMPILER =====================================*/
+
+#define     MSC         1                   /* Microsoft C                    */
+#define     TURBO       0                   /* Borland TurboC                 */
+#define     PCCV        0                   /* UNIX System V Compiler         */
+#define     PCCB        0                   /* UNIX BSD 4.x Compiler          */
+
+
+/*========================= PRESENTATION SERVICE =============================*/
+
+#define     PC_BIOS     1                   /* IBM-PC Via Standard Bios       */
+#define     PC_WIND     0                   /* IBM-PC Via MS-Windows          */
+#define     PC_OSPM     0                   /* OS/2 Presentation Manager      */
+#define     CURSES      0                   /* UNIX Curses                    */
+
+
+/*========================== OPERATING SYSTEM ================================*/
+
+#define     PCDOS       1                   /* Standard PC-DOS                */
+#define     OS_2        0                   /* OS/2                           */
+#define     UNIXV       0                   /* UNIX System V.x                */
+#define     UNIXB       0                   /* UNIX BSD 4.x                   */
+
+
+/*=====================END OF <SYS_ENV.H> INSERT DECK ========================*/
+
diff --git a/tee/TEE.ASM b/tee/TEE.ASM
new file mode 100644
index 0000000..633f1fb
--- /dev/null
+++ b/tee/TEE.ASM
@@ -0,0 +1,138 @@
+	name	tee
+	page	55,132
+	title	'TEE - tee junction for DOS pipes'
+;
+; TEE --- A "tee" junction for DOS 2.x pipes
+;         after the fashion of the Unix function TEE  
+; 
+; Copyright (C) 1984 A. K. Head 
+;
+; TEE reads from the standard input (redirectable) and
+; outputs to both the standard output (redirectable)
+; and a file, e.g.:   DIR | TEE C:\MYDIR\FILE.EXT | SORT
+;
+; The file can be CON, LPT1, etc.  If it is CON, then
+; keyboard Control-S pauses the display as usual.
+
+command	equ	80h		; buffer for command tail
+buflen	equ	16384		; buffer length, alter to taste
+
+cr	equ	0dh		; ASCII carriage return
+lf	equ	0ah		; ASCII line feed
+ff	equ	0ch		; ASCII form feed
+eof	equ	01ah		; End-of-file marker
+tab	equ	09h		; ASCII tab code
+blank	equ	20h		; ASCII blank
+
+				; DOS 2.x pre-defined handles
+stdin	equ	0000		; standard input file
+stdout	equ	0001		; standard output file
+stderr	equ	0002		; standard error file
+stdaux	equ	0003		; standard auxilliary file
+stdprn	equ	0004		; standard printer file
+
+
+cseg	segment para public 'CODE'
+
+	assume	cs:cseg,ds:cseg
+
+	org	100H		; start .COM at 100H
+
+tee	proc	far
+
+	mov	cl,ds:command 	; get length of command tail.
+	xor	ch,ch 
+				; address of command string.
+	mov	si,offset command+1 
+	mov	di,offset command+1
+
+tee1:				; squeeze out leading spaces.
+	mov	al,byte ptr [si]
+	cmp	al,blank
+	jbe	tee2
+	mov	byte ptr [di],al
+	inc	di
+
+tee2:	inc	si		; look through command tail
+	loop	tee1		; until it's exhausted.
+	mov	byte ptr [di],0 ; make ASCIIZ string.
+	mov	ah,3ch		; create output file.
+	mov	cx,0		; attribute=0.
+	mov	dx,offset command+1
+	int	21h
+	jc	tee6		; can't create file
+	mov	handle,ax	; save token for file.
+
+tee3:	mov	ah,3fh		; read standard input.
+	mov	bx,stdin
+	mov	cx,buflen
+	lea	dx,buffer
+	int	21h
+	jc	tee4		; jump, error.
+	mov	nchar,ax	; save length of read.
+	cmp	ax,0		; nothing read in?
+	je	tee4		; end of file, exit.
+	mov	ah,40h		; write to file...
+	mov	bx,handle
+	mov	cx,nchar
+	int	21h
+	jc	tee7		; jump, write failed.
+	cmp	ax,nchar
+	jne	tee7		; jump, write failed.
+	mov	ah,40h		; now write to standard output...
+	mov	bx,stdout
+	int	21h
+	jc	tee7		; jump, write failed.
+	cmp	ax,nchar
+	jne	tee7		; jump, write failed.
+	jmp 	tee3		; read again until end of file.
+
+tee4:	mov	ah,3eh		; close output file.
+	mov	bx,handle
+	int	21h
+
+tee5:	mov	ax,4c00h	; exit with return code=0.
+	int	21h
+
+tee6:	mov	dx,offset err1	; print "Can't create file".
+	mov	cx,err1len
+     	mov	ah,40h		; display error message and exit.
+	mov	bx,stderr
+	int	21h
+	mov	ax,4c01h	; exit with return code=1.
+	int	21h
+
+tee7:	mov	dx,offset err2	; print "Disk is full".
+	mov	cx,err2len
+     	mov	ah,40h		; display error message and exit.
+	mov	bx,stderr
+	int	21h
+	mov	ah,3eh		; close output file.
+	mov	bx,handle
+	int	21h
+	mov	ax,4c02h	; exit with return code=2.
+	int	21h
+
+tee	endp
+
+
+nchar	dw 	0		; number of chars actually input.
+handle	dw	0		; token for output file.
+
+err1   	db	cr,lf
+	db	'tee: Cannot create file' 
+	db	cr,lf
+err1len equ	(this byte)-(offset err1) 
+
+err2 	db	cr,lf
+	db	'tee: Disk is full.'
+	db	cr,lf
+err2len equ	(this byte)-(offset err2) 
+
+buffer	equ	this byte	; data is read here from
+				; standard input
+
+cseg	ends
+
+	end	tee
+
\ No newline at end of file
diff --git a/timlbl/TIMLBL.BAS b/timlbl/TIMLBL.BAS
new file mode 100644
index 0000000..6c20a18
--- /dev/null
+++ b/timlbl/TIMLBL.BAS
@@ -0,0 +1,16 @@
+10 CLEAR 1000:CLS:WIDTH "lpt1:",132
+20 I1=3:I2=30:I3=60:B=4:XYZ=B-2
+30 A$="T.A. Daneliuk"
+40 B$="4927 N. Rockwell"
+50 C$="Chicago, IL  60625"
+60 FOR X=1 TO 12
+70      LPRINT TAB(I1)A$TAB(I2)A$TAB(I3)A$
+80      LPRINT TAB(I1)B$TAB(I2)B$TAB(I3)B$
+90      LPRINT TAB(I1)C$TAB(I2)C$TAB(I3)C$
+100     WHILE ((XYZ > 0) AND (X <> 12))
+110             LPRINT:XYZ = XYZ-1
+120     WEND
+130 XYZ=B
+140 NEXT X
+150 LPRINT CHR$(12);
+
\ No newline at end of file
diff --git a/tod/TOD.C b/tod/TOD.C
new file mode 100644
index 0000000..87df080
--- /dev/null
+++ b/tod/TOD.C
@@ -0,0 +1,15 @@
+#include <types.h>
+#include <timeb.h>
+#include <stdio.h>
+#include <time.h>
+
+
+main()
+{
+struct timeb timebuffer;
+char *timeline;
+
+ftime(&timebuffer);
+timeline = ctime(&(timebuffer.time));
+printf("%.19s.%hu %s",timeline, timebuffer.millitm, &timeline[20]);
+}
diff --git a/tohex2/TOHEX2.C b/tohex2/TOHEX2.C
new file mode 100644
index 0000000..d867e21
--- /dev/null
+++ b/tohex2/TOHEX2.C
@@ -0,0 +1,29 @@
+/* TOHEX2.C - 	This function is passed an integer value and an array
+				location which can hold at least a 2 element string.
+				The low 8 bits of the integer are converted to an
+				equivalent hexadecimal string which is stored in the
+				array at subscripts 0 and 1.
+
+	Last modified: 08/31/86 - Copyright (c) 1985, 1986 By T.A. Daneliuk		*/
+
+
+tohex2(i,array)
+
+int		i;
+char	array[];
+
+{
+
+int		temp;
+static char	conv[]={"0123456789ABCDEF"};
+
+temp=i;
+temp=temp & 0x000f;							/* Mask all but low nybble */
+array[1]=conv[temp];						/* Use to index into conversion table */
+temp=i;										/* Now do high nybble */
+temp=temp >> 4;
+temp=temp & 0x000f;
+array[0]=conv[temp];
+
+}
+
diff --git a/trbord/TRBORD.C b/trbord/TRBORD.C
new file mode 100644
index 0000000..42ba371
--- /dev/null
+++ b/trbord/TRBORD.C
@@ -0,0 +1,22 @@
+/* TRBORD.C - Draw Standard Border With Prompts For T&R Communications Software Products
+			Last Modified: 06/11/86
+			Copyright (C) 1986,  T.A. Daneliuk
+*/
+
+
+#include	<stdio.h>
+#include	<system.h>
+#include	<t&r.h>
+extern	char	copyright[];
+extern	char	version[];
+
+
+void	trbord()
+
+{
+
+	border(0,0,VWIDTH,VHEIGHT-2,clrbord);
+	dsplylin(VHEIGHT-3,center(copyright),copyright,clrbmsg);
+	dsplylin(0,VWIDTH-22,version,clrbmsg);
+
+}
diff --git a/verset/VERSET.C b/verset/VERSET.C
new file mode 100644
index 0000000..157fddd
--- /dev/null
+++ b/verset/VERSET.C
@@ -0,0 +1,19 @@
+/*  VERSET.C - Set Version Number In Standard Message String
+				Last Modified: 06/11/86
+				Copyright (C) 1986,  T.A. Daneliuk
+*/
+
+void	verset(x,y,z)
+
+char	x,y,z;
+
+{
+
+extern	char	version[];
+char	*ptr=&version[11];
+
+*ptr=x;
+*(ptr+2)=y;
+*(ptr+4)=z;
+
+}
\ No newline at end of file
diff --git a/wildcard/WILDCARD.C b/wildcard/WILDCARD.C
new file mode 100644
index 0000000..3ff2f53
--- /dev/null
+++ b/wildcard/WILDCARD.C
@@ -0,0 +1,23 @@
+/*	WILDCARD.C - Uses the filefind routines to return wildcard matches.
+			Last Modified:	02/19/87
+			Copyright (C) 1987, By T.A. Daneliuk
+*/
+
+#include	<filefind.h>
+
+
+int	wildcard(fn,dta,first)
+char	*fn;
+struct	DataArea	*dta;
+int		first;
+
+{
+
+if (first)												/* New wildcard spec */
+	{
+	SetDta(dta);
+	return(FindFirst(fn,F_NORMAL));
+	}
+else
+	return(FindNext(F_NORMAL));
+}