[mod.amiga.sources] SHAR 3 of 4

doc@pucc-j.UUCP (09/02/86)

Reply-To: dillon%cory.Berkeley.EDU@BERKELEY.EDU (Matt Dillon)

	This shar file contains the following utilities.  See the enclosed
README file and the header of each source file for more information:

	breakup		Allows you to keep many files in a single file
	fgrep		ye old search program.. very simple
	fileseg		extract any section from a file
	hunks		decodes executable or object files
	ic		integer/conversion calculator (programmable)
	rmctl		remove chars that ED normally coughs at.
	sr		Search and Replace on a binary
	wc		Word Count



#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	README
#	breakup.c
#	fgrep.c
#	fileseg.c
#	hunks.c
#	ic.c
#	ic.txt
#	rmctl.c
#	sr.c
#	wc.c
# This archive created: Wed Aug 27 21:32:38 1986
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'README'" '(1228 characters)'
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \!Funky!Stuff! > 'README'

The following programs must be compiled on a 32 bit compiler using the
following library order for Alink:

	MY.LIB AMIGA.LIB LC.LIB

backup		backup files (destination is a single file)
restore		restore a filesystem/selected files from a single backup file.
breakup		breakup a file into lots of little files via breakpoints placed
			in the original file.

fgrep		ye old fgrep... very simple
fileseg		extract any part of a file
hunks		decode hunk list (e.g. executables and object files)
ic			integer calculator
rmctl		remove hazardous characters from a text file (so ED will work)
sr			search and replace on a file
wc			word count

	All sources have a description of themselves at the beginning.  In 
addition, there are .TXT files for some of these programs.   Additionaly,
most of the programs will default to using stdin if no files are specified
(wc, rmctl, fileseg, fgrep)


	Copyright 1986  Matthew Dillon  on all above listed programs.
	
	Terms of distribution:	None, but If I ever get proof that anyone has
gone and sold any of these programs FOR PROFIT, I will personally infiltrate
his accounts and blow away his directories, as well as give him an alltogether
bad time wherever I find him.  Got it?  

						-Matt
	
!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'breakup.c'" '(8568 characters)'
if test -f 'breakup.c'
then
	echo shar: "will not over-write existing file 'breakup.c'"
else
cat << \!Funky!Stuff! > 'breakup.c'

/*
 * BREAKUP.C
 *
 *
 * Compilation:
 *       -Use a 32 bit integers compiler
 *       -Use Astartup.obj (tiny startup)
 *       -Use the following library order:  AMIGA.LIB LC.LIB
 *
 *       LC.LIB is only in there because Lattice uses a function in its
 *       library for long integer multiplies.
 *
 *       Executable size should be around 4K
 *
 *
 *    This Utility allows you to group many small files together into one
 *    big file.  Usually, this big file has a .b suffix on it.
 *
 * USE:
 *    remember that when you create libraries, the linker will bring in
 *    the library routines an object file at a time.  Thus, you want
 *    to compile your functions (e.g. strcmp, strcat, strlen) separately
 *    so using 'strcmp' doesn't also bring in the other functions.  But
 *    then again, having many little .C files floating around is difficult
 *    to manage.  A much cleaner way is to have all the 'strxxxx' functions
 *    in one file, then breakup that file into lots of little .C files when
 *    you're ready to compile them.
 *
 * OPERATION:
 *
 *    BREAKUP [-nname -nname...] files
 *
 *    takes the indicated files, and breaks it up into lots of little files.
 *    if one or more -n options is specified, only those sub-sections will
 *    be broken out of the master file.  in the .B file, a break point is
 *    indicated by a C comment in a special form:
 *
 *    <slash><star>BREAKUP filename<star><slash>
 *
 *    No space between the first * and the BREAKUP, nor is there a space
 *    in front of the initial <slash>.  Any text before the first break
 *    point is discarded, and any text after the break point is written
 *    to the specified file until another break point is reached.  The
 *    break-line itself (containing the BREAKUP command) is not written to
 *    any file.
 *
 *
 *
 * NOTES:
 *    I actually re-wrote this program using my library.   However, I've
 *    included the required routine in this source to make the program
 *    self contained.
 *
 *    Note that the XSTDIO subroutines are out of date, but
 *    work with this source file.
 *
 *    do NOT use lattice's LC.LIB when compiling this program, it is not
 *    needed.
 *
 */

long outfi;
unsigned char onlyac;     /* if non zero, av[onlyac] list of only strings */

extern long xopen();


main(ac, av)
char *av[];
{
   register int i, fi;

   check32();
   if (ac == 1) {
      puts ("v1.00 by Matthew Dillon");
      puts ("breakup [-nsection ...] file.b");
   }
   for (i = 1; i < ac; ++i) {
      if (*av[i] == '-') {
         *av[i] = onlyac;
         onlyac = i;
      } else
      if (fi = xopen (av[i], "r", 8192)) {
         dofile(av, fi);
         xclose (fi);
      } else {
         printf ("Could not open %s\n", av[i]);
      }
      if (outfi)
         xclose(outfi);
      outfi = 0;
   }
}

dofile(av, fi)
char *av[];
{
   char buf[256];
   char *str, *ptr;

   while (xgets(fi, buf, 256)) {
      if (strncmp(buf, "/*BREAKUP", 9) == 0) {
         str = buf + 9;
         while (*str == ' ')
            ++str;
         ptr = str;
         while (*ptr && *ptr != ' ')
            ++ptr;
         *ptr = '\0';
         xclose(outfi);
         outfi = 0;
         if (onlyac) {
            unsigned char i = onlyac;
            while (i) {
               if (strcmp(av[i]+2, str) == 0)
                  goto ok;
               i = (unsigned char)*av[i];
            }
         } else {
ok:
            outfi = xopen(str, "w", 8192);
         }
         if (outfi)
            printf ("file: %s\n", str);
      } else {
         if (outfi)
            xputs(outfi, buf);
      }
   }
}



/*
 * NOTE
 *
 * The following routines have been extracted from my library and placed
 * here so you can compile this program with only AMIGA.LIB  .  Note that
 * some of these routines are obsolete (but work for this program).
 *
 * This was done because the BREAKUP command is needed to break up my
 * posted library files (.B files) and obviously you can't use my library
 * until you've done that.
 */


typedef struct {
   long fh;                 /* file handle                            */
   long i1, i2, max;        /* buffer indexes (current, end, bufsize) */
   long pos, vpos;          /* real current, virtual current          */
   char stat;              /* modified?                              */
   unsigned char *buf;     /* za buffer                              */
} FILE;

#define FIS_MODIFIED 0x01

#define MODE_READWRITE  1004
#define MODE_READONLY   1005
#define MODE_OLDFILE    1005
#define MODE_NEWFILE    1006
#define MEMF_CLEAR   (1 << 16)
#ifndef NULL
#define NULL 0
#endif

extern long xopen();


check32()
{
   unsigned int i;

   i = 0; --i;
   if (i != 0xFFFFFFFF) {
      puts ("MUST BE COMPILED WITH 32-bit INT's!");
      exit (50000);                                     /* no joke */
   }
}


long
xopen(name, str, size)
register char *name, *str;
long size;
{
   register FILE *fi;
   register int mode;
   register long fh = 0;

   if (size < 1)
      size = 1;
   fi = (FILE *)AllocMem((long)sizeof(FILE), MEMF_CLEAR);
   if (fi) {
      if (str[0] == 'r') {
         mode = MODE_READONLY;
         if (str[1] == '+')
            mode = MODE_READONLY;                  /* actually rw */
      }
      if (str[0] == 'w') {
         mode = MODE_NEWFILE;
         if (str[1] == '+') {
            if (fh = Open(name, MODE_OLDFILE))
               Seek(fh, 0L, 1);
         }
      }
      if (!fh)
         fh = Open(name, mode);
      if (fh) {
         fi->fh = fh;
         fi->max = size;
         if (fi->buf = (unsigned char *)AllocMem(size, 0)) {
            fi->pos = fi->vpos = Seek(fh, 0L, 0);
         } else {
            Close(fh);
            goto fail;
         }
      } else {
fail:
         FreeMem(fi, (long)sizeof(FILE));
         return(NULL);
      }
   }
   return((long)fi);
}


xclose(fi)
register FILE *fi;
{
   if (fi) {
      xflush(fi);
      Close(fi->fh);
      FreeMem(fi->buf, fi->max);
      FreeMem(fi, (long)sizeof(FILE));
   }
}



xwrite(fi, buf, n)
register FILE *fi;
register char *buf;
register long n;
{
   register long w;

   for (;;) {
      w = (fi->max - fi->i1 < n) ? fi->max - fi->i1 : n;
      bmov(buf, fi->buf + fi->i1, w);
      n -= w;
      buf += w;
      fi->vpos += w;
      fi->i1   += w;
      if (fi->i2 < fi->i1)
         fi->i2 = fi->i1;
      fi->stat |= FIS_MODIFIED;
      if (n) {
         xflush(fi);
         fi->i1 = fi->i2 = 0;
         continue;
      }
      break;
   }
}


xputs(fi, buf)
FILE *fi;
char *buf;
{
   xwrite(fi, buf, (long)strlen(buf));
   xwrite(fi, "\n", 1L);
}


xgets(fi, buf, max)
register FILE *fi;
register char *buf;
register long max;
{
   register int i;

   --max;
   for (i = 0; i < max; ++i) {
      if (fi->i1 == fi->i2) {
         if (xfilbuf(fi) == 0) {
            buf[0] = '\0';
            return(0);
         }
      }
      buf[i] = fi->buf[fi->i1++];
      ++fi->vpos;
      if (buf[i] == '\n')
         break;
   }
   buf[i] = '\0';
   return(i+1);
}


xfilbuf(fi)
register FILE *fi;
{
   register long n;
   register long fh = fi->fh;

   xflush(fi);
   fi->i1 = fi->i2 = 0;
   if (fi->vpos != fi->pos)
      Seek(fh, fi->vpos - fi->pos, 0);
   n = Read(fh, fi->buf, fi->max);
   if (n <= 0) {
      fi->pos = fi->vpos;
      Seek(fh, fi->pos, -1);
      return (0);
   }
   fi->pos = fi->vpos + (fi->i2 = n);
   return(1);
}


xflush(fi)
register FILE *fi;
{
   register long vstart;

   if (fi->stat & FIS_MODIFIED) {
      vstart = fi->vpos - fi->i1;
      if (fi->pos != vstart)
         Seek (fi->fh, vstart - fi->pos, 0);
      fi->pos = vstart + Write(fi->fh, fi->buf, fi->i1);
      fi->stat &= ~FIS_MODIFIED;
   }
}


strlen(str)
char *str;
{
   register char *ptr = str;
   while (*ptr)
      ++ptr;
   return(ptr - str);
}


strcmp(s1, s2)
register unsigned char *s1, *s2;
{
   while (*s1 && *s2) {
x:
      if (*s1 < *s2)
         return (-1);
      if (*s1 > *s2)
         return (1);
      ++s1;
      ++s2;
   }
   if (*s1 == *s2)
      return (0);
   goto x;
}

strncmp(s1, s2, n)
register unsigned char *s1, *s2;
register int n;
{
   while (n && *s1 && *s2) {
      --n;
x:
      if (*s1 < *s2)
         return (-1);
      if (*s1 > *s2)
         return (1);
      ++s1;
      ++s2;
   }
   if (n == 0 || (*s1 == *s2))
      return (0);
   goto x;
}

bmov(s,d,n)
register char *s, *d;
register int n;
{
   register int i;
   if (s < d) {
      for (i = n; --i >= 0;)
         d[i] = s[i];
   } else {
      for (i = 0; i < n; ++i)
         d[i] = s[i];
   }
}


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'fgrep.c'" '(1460 characters)'
if test -f 'fgrep.c'
then
	echo shar: "will not over-write existing file 'fgrep.c'"
else
cat << \!Funky!Stuff! > 'fgrep.c'


/*
 * FGREP.C
 *
 * Compilation:
 *       -Use a 32 bit integers compiler
 *       -Use Astartup.obj (tiny startup)
 *       -Use the following library order:  MY.LIB AMIGA.LIB LC.LIB
 *
 *       LC.LIB is only in there because Lattice uses a function in its
 *       library for long integer multiplies.
 *
 *       MY.LIB is my own library.  If you don't have it, I'll mail it
 *       to you via UUCP or ARPAnet.
 *
 *       Executable size should be around 4K
 *
 *
 * fgrep search_str [file file file.....]
 *
 * if no files are specified, stdin in used.
 *
 */

#define NULL 0L

main(ac, av)
char *av[];
{
   register int i, fi;

   if (ac == 2) {
      fi = xattach(Input(), 8192);
      fgrep (fi, NULL, av[1]);
      xdetach(fi);
   }
   if (ac > 2) {
      for (i = 2; i < ac; ++i) {
         if (fi = xopen(av[i], "r", 8192)) {
            if (ac == 3)
               av[i] = NULL;
            fgrep(fi, av[i], av[1]);
            xclose(fi);
         } else {
            printf ("File Error: %s\n", av[i]);
         }
      }
   }
}


fgrep(fi, fname, search)
char *fname, *search;
{
   char buf[256];
   register int l, len;

   len = strlen(search);
   while (l = xgets(fi, buf, 256)) {
      for (l = l - len - 1; l >= 0; --l) {
         if (strncmp(buf+l, search, len) == 0)
            break;
      }
      if (l >= 0) {
         if (fname)
            printf ("%s: %s\n", fname, buf);
         else
            puts (buf);
      }
   }
}

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'fileseg.c'" '(1673 characters)'
if test -f 'fileseg.c'
then
	echo shar: "will not over-write existing file 'fileseg.c'"
else
cat << \!Funky!Stuff! > 'fileseg.c'

/*
 * FILESEG.C
 *
 *
 * Compilation:
 *       -Use a 32 bit integers compiler
 *       -Use Astartup.obj (tiny startup)
 *       -Use the following library order:  MY.LIB AMIGA.LIB LC.LIB
 *
 *       LC.LIB is only in there because Lattice uses a function in its
 *       library for long integer multiplies.
 *
 *       MY.LIB is my own library.  If you don't have it, I'll mail it
 *       to you via UUCP or ARPAnet.
 *
 *       Executable size should be around 4K
 *
 *
 * fileseg startpos endpos [file]
 *
 *    extract a segment of a file or STDIN.
 *    If endpos is -1, the rest of the file is extracted.
 *
 *    output is to stdout.
 *
 */

main(ac, av)
char *av[];
{
   unsigned long start, end;
   long outfh = Output();
   register int i;
   long fi;
   char buf[512];

   if (ac < 3) {
      puts ("v1.00 FILESEG startseek endseek [file]");
      puts ("can use -1 for endseek for end of file");
      exit (1);
   }
   start = atoi(av[1]);
   end   = atoi(av[2]);
   if (ac == 3) {
      fi = xattach(Input(), 1024);
      while (start >= 512) {
         xread(fi, buf, 512);
         start -= 512;
         end -= 512;
      }
      xread(fi, buf, start);
      end -= start;
   } else {
      fi = xopen(av[3], "r", 512);
      if (!fi) {
         puts ("could not open file");
         exit (1);
      }
      xseek(fi, start, -1);
      end -= start;
   }
   while (end > 512 && (i = xread(fi, buf, 512))) {
      Write(outfh, buf, i);
      end -= i;
      if (i == 0)
         break;
   }
   while (end && (i = xread(fi, buf, end))) {
      Write(outfh, buf, i);
      end -= i;
   }
   if (ac == 3)
      xdetach(fi);
   else
      xclose(fi);
}



!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'hunks.c'" '(5308 characters)'
if test -f 'hunks.c'
then
	echo shar: "will not over-write existing file 'hunks.c'"
else
cat << \!Funky!Stuff! > 'hunks.c'

/*
 * HUNKS.C
 *
 *
 * Compilation:
 *       -Use a 32 bit integers compiler
 *       -Use Astartup.obj (tiny startup)
 *       -Use the following library order:  MY.LIB AMIGA.LIB LC.LIB
 *
 *       LC.LIB is only in there because Lattice uses a function in its
 *       library for long integer multiplies.
 *
 *       MY.LIB is my own library.  If you don't have it, I'll mail it
 *       to you via UUCP or ARPAnet.
 *
 *       Executable size should be around ?K
 *
 *
 * hunks file
 *
 * displays the hunks in a file and their size
 *
 *
 *
 */

#define NULL 0L

extern char *newmem(), *AllocMem(), *getstring();

main(ac, av)
char *av[];
{
   register int i;
   register int size;
   register int fh;

   for (i = 1; i < ac; ++i) {
      fh = Open(av[i], 1005);
      if (fh) {
         size = (Seek(fh, 0, 1), Seek(fh, 0, -1)) >> 2;
         printf ("FILE: %s   longs: %ld\n", av[i], size);
         unhunk(fh, size);
         Close(fh);
         printf ("\n");
      }
   }
   newmem(0);
}

static char *lookup[] = {
   "HUNK_UNIT   ",         /*  999 */
   "HUNK_NAME   ",
   "HUNK_CODE   ",
   "HUNK_DATA   ",
   "HUNK_BSS    ",
   "HUNK_RELOC32",
   "HUNK_RELOC16",
   "HUNK_RELOC8 ",
   "HUNK_EXT    ",
   "HUNK_SYMBOL ",
   "HUNK_DEBUG  ",
   "HUNK_END    ",
   "HUNK_HEADER ",
   "UNKNOWN     ",
   "HUNK_OVERLAY",
   "HUNK_BREAK  "
};


unhunk(fh, maxlongs)
register int fh, maxlongs;
{
   unsigned long type;
   unsigned long words;
   unsigned long hunk;
   unsigned long l1, l2, l3;
   register int count = 0;
   register char *str;

   if (maxlongs == 0)
      return(0);
   while (maxlongs > 0) {
      Read(fh, &type, 4);
      --maxlongs;
      str = "UNKNOWN     ";
      if (type >= 999 && type < sizeof(lookup)/sizeof(lookup[0]) + 999)
         str = lookup[type - 999];
      printf ("#%-3ld (%4ld)%s:", count, type, str);
      switch (type) {
      case 999:
      case 1000:
         Read (fh, &words, 4);
         printf ("  name: %s\n", getstring(fh, words));
         maxlongs -= words + 1;
         continue;
      case 1001:
      case 1002:
         Read(fh, &words, 4);
         break;
      case 1003:
         Read(fh, &words, 4);
         printf ("   (bss for %ld longs)\n", words);
         maxlongs -= 1;
         continue;
      case 1004:
      case 1005:
      case 1006:
         printf ("\n");
         while (Read(fh, &words, 4), words) {
            Read (fh, &hunk, 4);
            printf ("  %4ld longs to hunk #%ld\n", words, hunk);
            maxlongs -= words + 2;
            Seek (fh, words << 2, 0);
         }
         maxlongs -= 1;
         continue;
      case 1007:
      case 1008:
         printf ("\n");
         while (Read(fh, &words, 4), words) {
            type  =  words >> 24;
            words &= 0x00FFFFFF;
            printf ("  type: %-3ld name: %-20s   ", type, getstring(fh, words));
            maxlongs -= words + 1;
            switch (type) {
            case 0:
            case 1:
            case 2:
            case 3:
               Read(fh, &words, 4);
               printf ("symbol value: %ld", words);
               --maxlongs;
               break;
            case 129:
            case 131:
            case 132:
               Read(fh, &words, 4);
               printf ("references: %ld", words);
               Seek (fh, words << 2, 0);
               maxlongs -= words + 1;
               break;
            case 130:
               Read (fh, &words, 4);
               Read (fh, &hunk, 4);
               printf ("com size: %ld  references: %ld", words, hunk);
               Seek (fh, hunk << 2, 0);
               maxlongs -= hunk + 2;
               break;
            default:
               printf ("UNKNOWN");
               break;
            }
            printf("\n");
         }
         maxlongs -= 1;
         continue;
      case 1009:
         Read(fh, &words, 4);
         break;
      case 1010:
         printf ("\n");
         ++count;
         continue;
      case 1011:
         while (Read(fh, &words, 4), words) {
            printf ("  name: %s\n", getstring(fh, words));
            maxlongs -= words + 1;
         }
         --maxlongs;
         Read (fh, &l1, 4);
         Read (fh, &l2, 4);
         Read (fh, &l3, 4);
         words = l3 - l2 + 1;
         Seek (fh, words << 2, 0);
         maxlongs -= 3 + words;
         printf ("  table size: %ld  first hunk: %ld  last hunk: %ld\n", l1, l2, l3);
         continue;
      case 1013:
         printf ("YYYYYYYYYYYYYYYYYYYYYYY\n");
         continue;
      case 1014:
         printf ("\n");
         continue;
      default:
         printf ("UNKNOWN\n");
         continue;
      }
      /* BREAK -> STANDARD READ N WORDS */
      printf ("   %ld longs\n", words);
      Seek(fh, words << 2, 0);
      maxlongs -= words + 1;
   }
   printf ("DONE: maxlongs = %ld\n", maxlongs);
}

char *
getstring(fh, words)
int words;
{
   register char *str;
   register int bytes = words << 2;

   str = newmem(bytes + 1);
   Read (fh, str, bytes);
   str[bytes] = 0;
   return (str);
}

char *
newmem(bytes)
{
   static int last_bytes;
   static char *last_ptr;

   if (last_ptr) {
      FreeMem(last_ptr, last_bytes);
      last_ptr = NULL;
   }
   if (bytes)
      last_ptr = AllocMem(last_bytes = bytes, 0);
   return (last_ptr);
}

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'ic.c'" '(16516 characters)'
if test -f 'ic.c'
then
	echo shar: "will not over-write existing file 'ic.c'"
else
cat << \!Funky!Stuff! > 'ic.c'


/*
 * Integer Calculator
 *
 * Matthew Dillon,   Unicorns Live Forever, 10 August 1986
 *
 * Compilation:
 *       -Use a 32 bit integers compiler
 *       -Use Astartup.obj (tiny startup)
 *       -Use the following library order:  MY.LIB AMIGA.LIB LC.LIB
 *
 *       LC.LIB is only in there because Lattice uses a function in its
 *       library for long integer multiplies.
 *
 *       MY.LIB is my own library.  If you don't have it, I'll mail it
 *       to you via UUCP or ARPAnet.
 *
 *       Executable size should be around 13K
 *
 *
 * HISTORY
 *
 *    This is an RPN based calculator geared which I wrote on a whim.
 * Actually, the history is simple:  I wanted to convert from bcpl
 * addresses to absolute addresses and vise versa, and didn't have an
 * HP16C lying around.  However, I decided to make this thing a fully
 * fledged integer calculator with every function imaginable and to give
 * users the ability to write their own functions (you never know what one
 * might need it for in the future).
 *
 * USAGE (additional info provided by the help command)
 *
 *    The current base (register -1) only applies to numerical entry onto
 * the stack and display.  Any number to the right of a command is always
 * in decimal.  Thus, 'STO 3', store to register 3 is always 3 in decimal.
 *
 *    You can overide the current base for numerical stack entry with
 * the following special symbols:
 *    #  decimal        #10   #-10
 *    $  hex            $ABC  $-5A
 *    \  octal          \117  \-123
 *    %  binary         %1001 %-10
 *
 *    It is a good idea to ALWAYS use overide operators in user programs
 * so they are not effected by the current base.
 *
 *    new programs overide old programs of the same name.  Thus, if you
 * overide a program, then delete the new program, the old program will
 * become active again.  You can name your programs anything, and should
 * be careful that they have at least one letter larger than F if you
 * intend to use base 16.
 *
 *
 * COMPILATION
 *    compile using a 32 bit compiler.  The link line should look as
 *    follows:
 *
 *    alink clib:Astartup.obj+ic.o library clib:my.lib+clib:amiga.lib+clib:lc.lib
 *
 *    Note you need my library.  Lattice's library is in there only to get
 *    the longword multiply and divide routines (the infamous CXD and CXM's)
 *
 */


#define NULL 0L

#define TY_INTERNAL  0
#define TY_USERFUNC  1

#define SREG_BASE    1
#define SREG_SIGNED  2
#define SREG_VERBOSE 3

#define HASHSIZE  64         /* arbitrary             */
#define MAXDEEP   32         /* max # function levels */

typedef struct {
   char *name;
   int ((*func)());
   char *comment1, *comment2;
} ILIST;


typedef struct _HASH {
   struct _HASH *next, **prev;
   char *name;
   char type;
   union {
      int (*internal)();
      char *userfunc;
   } u;
} HASH;


typedef unsigned long u_long;
typedef unsigned char u_char;


extern int f_plus(), f_minus();
extern int f_mul(),  f_div(), f_lshift(), f_rshift(), f_not(), f_chs();
extern int f_pop(),  f_rcl(), f_sto(), f_program(), f_return();
extern int f_delete(),f_list(), f_show(), f_source(), f_help();
extern int f_and(), f_or(), f_xor(), f_rcls(), f_stos();

extern int f_larger(), f_smaller(), f_largereq(), f_smallereq();
extern int f_eq(), f_neq(), f_if();


static ILIST IL[] = {
      "+"      , f_plus,      "a b : r",  "addition",
      "-"      , f_minus,     "a b : r",  "subtraction",
      "*"      , f_mul,       "a b : r",  "multiplication",
      "/"      , f_div,       "a b : r",  "division",
      "<<"     , f_lshift,    "a b : r",  "shift left by b",
      ">>"     , f_rshift,    "a b : r",  "shift rht  by b",
      "and"    , f_and,       "a b : r",  "logical and",
      "or"     , f_or,        "a b : r",  "logical or",
      "xor"    , f_xor,       "a b : r",  "logical xor",
      ">"      , f_larger,    "a b : r",  "true/false is a > b?",
      "<"      , f_smaller,   "a b : r",  "true/false is a < b?",
      ">="     , f_largereq,  "a b : r",  "true/false is a >=b?",
      "<="     , f_smallereq, "a b : r",  "true/false is a <=b?",
      "=="     , f_eq,        "a b : r",  "true/false is a ==b?",
      "!="     , f_neq,       "a b : r",  "true/false is a !=b?",
      "~"      , f_not,       "  a : r",  "complement",
      "chs"    , f_chs,       "  a : r",  "negate",
      "sto"    , f_sto,       "  a : a",  "STO <regnum> store to register",
      "stos"   , f_stos,      "  a : a",  "STOS <level> store to stack",
      "pop"    , f_pop,       "  a : -",  "pop stack",
      "if"     , f_if,        "  a : -",  "if false then skip next command on line",
      "rcl"    , f_rcl,       "  - : r",  "RCL <regnum> recal from register",
      "rcls"   , f_rcls,      "  - : r",  "RCLS <level> recal from stack",
      "source" , f_source,    "  - : ?",  "SOURCE <file>     -source from file",
      "program", f_program,   "  - : -",  "PROGRAM <name> <commands> <return>",
      "return" , f_return,    "  - : -",  "abort rest of line",
      "delete" , f_delete,    "  - : -",  "PURGE <name>",
      "list"   , f_list,      "  - : -",  "LIST              -list program names",
      "show"   , f_show,      "  - : -",  "display top of stack",
      "help"   , f_help,      "  - : -",  "HELP!!!"
};

static long Stack[256];                      /* The register stack        */
static long Regs[256];                       /* Normal registers          */
static long Sregs[256];                      /* Special registers         */
static HASH *Hash[HASHSIZE];                 /* function hash table       */
static unsigned char Stp, Rap, Interactive;  /* pointers and modes        */
static char scrbuf[256];

extern char *exarg(), *malloc(), *strcpy();

#define push_stack(n)   Stack[Stp++] = (n)
#define pop_stack()     Stack[--Stp]
#define top_stack()     Stack[(u_char)(Stp - 1)]
#define rel_stack(n)    Stack[(u_char)(Stp - 1 - (n))]

main(ac, av)
char *av[];
{
   register int i;
   register ILIST *il;
   char *buf;

   check32();
   Sregs[SREG_BASE]  = 10;
   Sregs[SREG_SIGNED]= 1;
   for (i = sizeof(IL) / sizeof(IL[0]), il = IL; i; --i, ++il)
      enter_hash(il->name, il->func, TY_INTERNAL);
   for (i = 1; i < ac; ++i) {
      sprintf (scrbuf, "source %s", av[i]);
      execute_line(scrbuf);
   }
   while (get_userline(&buf)) {
      execute_line(buf);
      if (Sregs[SREG_VERBOSE] > 0)
         execute_line("show");
      if (Sregs[SREG_VERBOSE] < 0)
         execute_line("custom_show");
   }
   free_memory();
}


enter_hash(name, ptr, type)
char *name;
char *ptr;
char type;
{
   register HASH **h, *hash;

   if (type == TY_USERFUNC)
      name = strcpy(malloc(strlen(name)+1), name);
   h = &Hash[h2(name, strlen(name))];
   hash = (HASH *)malloc(sizeof(HASH));
   hash->next = *h;
   hash->prev = h;
   hash->name = name;
   hash->type = type;
   hash->u.userfunc = ptr;
   *h = hash;
}


delete_hash(name, ptr, type)
char *name;
char **ptr;
char type;
{
   HASH *hash;

   *ptr = NULL;
   for (hash = Hash[h2(name, strlen(name))]; hash; hash = hash->next) {
      if (strcmp(name, hash->name) == 0)
         break;
   }
   if (hash && hash->type == type) {
      if (type == TY_USERFUNC)
         free(hash->name);
      *hash->prev = hash->next;
      *ptr = hash->u.userfunc;
      if (hash->next)
         hash->next->prev = hash->prev;
      free(hash);
      return (1);
   }
   return (0);
}

find_hash(name, len, ptr, type)
char *name;
char **ptr;
char *type;
{
   register HASH *hash;

   for (hash = Hash[h2(name, len)]; hash; hash = hash->next) {
      if (strlen(hash->name) == len && strncmp(name, hash->name, len) == 0)
         break;
   }
   if (hash) {
      *ptr = hash->u.userfunc;
      *type= hash->type;
      return (1);
   }
   return (0);
}

h2(name, len)
register char *name;
{
   unsigned int r = 0;

   while (len--)
      r = r + *name++ + r << 2;
   return ((int)((unsigned int)r % HASHSIZE));
}

get_userline(buf)
char **buf;
{
   printf ("> ");
   if (gets(scrbuf)) {
      *buf = scrbuf;
      return (1);
   }
   *buf = "";
   return (0);
}

execute_line(buf)
register char *buf;
{
   register char *start = buf;
   register char *end;
   register int skip;
   static int deep;
   union {
      char *ptr;
      long (*func)();
   } u;
   char type;

   skip = 0;
   while (*buf && skip >= 0) {
      while (*buf == ' ')
         ++buf;
      start = end = buf;
      while (*end && *end != ' ')
         ++end;
      buf = end;
      if (start != end) {
         if (skip) {
            --skip;
            continue;
         }
         if (find_hash(start, end - start, &u, &type)) {
            switch (type) {
            case TY_INTERNAL:
               skip = (*u.func)(start, end - start);
               break;
            case TY_USERFUNC:
               if (deep > MAXDEEP) {
                  puts ("TOO MANY FUNCTION LEVELS!");
                  skip = -1;
               } else {
                  ++deep;
                  execute_line(u.ptr);
                  --deep;
               }
               break;
            }
         } else {
            f_value(start, end - start);
         }
      }
   }
}

f_value(buf, len)
char *buf;
{
   register int base = 0;
   register long val = 0;
   long by;
   char neg = 0;

   switch (*buf) {
   case '#':
      base = 10;
      break;
   case '$':
      base = 16;
      break;
   case '%':
      base = 2;
      break;
   case '\\':
      base = 8;
      break;
   }
   if (base) {
      ++buf;
      --len;
   } else {
      base = Sregs[SREG_BASE];
   }

   if (*buf == '-') {
      ++buf;
      --len;
      neg = 1;
   }

   for (; len; ++buf, --len) {
      if (*buf >= '0' && *buf <= '9')
         by = *buf - '0';
      else
         by = (*buf & 0x1F) + 9;
      if (by >= base) {
         puts ("function not found or number out of base");
         return (-1);
      }
      val = val * base + by;
   }
   push_stack((neg)? -val : val);
   return (0);
}

f_help()
{
   register ILIST *il = IL;
   register int i = sizeof(IL)/sizeof(IL[0]);

   puts ("V1.0 Integer Calculator, by Matthew Dillon\n");
   puts ("reg -1 holds the current base");
   puts ("reg -2 holds whether operations are 'signed'");
   puts ("reg -3 holds verbose option: 1 = verbose, -1 = 'custom_show'");
   puts ("entry is the specified base, register numbers are always in decimal");
   puts ("");
   while (i--) {
      printf ("%-10s %-10s %s\n", il->name, il->comment1, il->comment2);
      ++il;
   }
}


f_show(buf, len)
{
   register int base = Sregs[SREG_BASE];
   char str[64];
   char *neg = "";
   register u_long val = top_stack();
   register int i, n;

   if (Sregs[SREG_SIGNED] && (long)val < 0) {
      val = -val;
      neg = "-";
   }
   str[63] = 0;
   for (i = 62; i; --i, val /= base) {
      n = val % base;
      if (n < 10)
         str[i] = n + '0';
      else
         str[i] = n - 10 + 'A';
      if (val == 0)
         break;
   }
   if (i != 62 && str[i] == '0')
      ++i;
   printf ("%s%s\n", neg, str + i);
   return (0);
}

f_plus()
{
   register long a, b;

   a = pop_stack();
   b = pop_stack();
   push_stack(a + b);
   return (0);
}


f_minus()
{
   register long a, b;

   b = pop_stack();
   a = pop_stack();
   push_stack(a - b);
   return (0);
}


f_mul()
{
   register long a, b;

   a = pop_stack();
   b = pop_stack();
   if (Sregs[SREG_SIGNED])
      push_stack(a * b);
   else
      push_stack((unsigned long)a * (unsigned long)b);
   return (0);
}


f_div()
{
   register long a, b;

   if (top_stack() == 0) {
      puts ("division by zero");
      return (0);
   }

   b = pop_stack();
   a = pop_stack();
   if (Sregs[SREG_SIGNED])
      push_stack(a / b);
   else
      push_stack((unsigned long)a / (unsigned long)b);
   return (0);
}


f_lshift()
{
   register long a, b;

   a = pop_stack();
   b = pop_stack();
   if (Sregs[SREG_SIGNED])
      push_stack(b << a);
   else
      push_stack((u_long)b << (u_long)a);
   return (0);
}

f_rshift()
{
   register long a, b;

   a = pop_stack();
   b = pop_stack();
   if (Sregs[SREG_SIGNED])
      push_stack(b >> a);
   else
      push_stack((u_long)b >> (u_long)a);
   return (0);
}


f_not()
{
   register long a;

   a = pop_stack();
   push_stack(~a);
   return (0);
}


f_chs()
{
   register long a;

   a = pop_stack();
   push_stack (-a);
   return (0);
}


f_pop(buf, len)
char *buf;
{
   pop_stack();
   return (0);
}


f_rcl(buf, len)
char *buf;
{
   register int reg;

   buf += len;
   reg = atoi(exarg(&buf));
   if (reg < 0) {
      reg = -reg;
      if (reg > 255)
         puts ("illegal special register");
      else
         push_stack(Sregs[reg]);
   } else {
      if (reg > 255)
         puts ("illegal register");
      else
         push_stack(Regs[reg]);
   }
   return (1);
}


f_sto(buf, len)
char *buf;
{
   register long val;
   register int reg;

   val = top_stack();
   buf += len;

   reg = atoi(exarg(&buf));
   if (reg < 0) {
      reg = -reg;
      if (reg > 255)
         puts ("illegal special register");
      else
         Sregs[reg] = val;
   } else {
      if (reg > 255)
         puts ("illegal register");
      else
         Regs[reg] = val;
   }
   return (1);
}


f_and(buf, len)
char *buf;
{
   long a, b;

   b = pop_stack();
   a = pop_stack();
   push_stack(a & b);
   return (0);
}


f_or()
{
   long a, b;

   b = pop_stack();
   a = pop_stack();
   push_stack(a | b);
   return (0);
}


f_xor()
{
   long a, b;

   b = pop_stack();
   a = pop_stack();
   push_stack(a ^ b);
   return (0);
}


f_rcls(buf, len)
char *buf;
{
   long val;
   int delta;

   buf += len;
   delta = atoi(exarg(&buf));

   val = rel_stack(delta);
   push_stack(val);
   return (1);
}


f_stos(buf, len)
char *buf;
{
   int delta;

   buf += len;
   delta = atoi(exarg(&buf));
   rel_stack(delta) = top_stack();
   return (1);
}


f_program(buf, len)
char *buf;
{
   char *name;
   char *prog;

   buf += len;
   name = exarg(&buf);
   if (*name == 0) {
      puts ("requires program name");
      return (1);
   }
   prog = (char *)malloc(strlen(buf)+1);
   strcpy(prog, buf);
   enter_hash(name, prog, TY_USERFUNC);
   return (-1);
}


f_return()
{
   return (-1);
}


f_delete(buf, len)
char *buf;
{
   char *ptr;
   char *name;

   buf += len;
   name = exarg(&buf);

   if (*name && delete_hash(name, &ptr, TY_USERFUNC)) {
      free(ptr);
   } else {
      puts ("not found");
   }
   return (1);
}


f_list()
{
   register HASH **h, *hash;
   register int i;

   for (i = 0, h = Hash; i < HASHSIZE; ++i, ++h) {
      for (hash = *h; hash; hash = hash->next) {
         if (hash->type == TY_USERFUNC) {
            printf ("%-20s ", hash->name);
            puts (hash->u.userfunc);
         }
      }
   }
   return (0);
}


f_source(buf, len)
char *buf;
{
   register long fi;
   char sbuf[256];

   ++Interactive;
   buf += len;
   fi = xopen(exarg(&buf), "r", 1024);
   if (fi) {
      while (xgets(fi, sbuf, 256))
         execute_line(sbuf);           /* execute za line */
      xclose(fi);
   } else {
      puts ("file not found");
   }
   --Interactive;
   return (1);
}


f_larger()
{
   long a, b;
   b = rel_stack(0);
   a = rel_stack(1);
   if (Sregs[SREG_SIGNED])
      push_stack(a > b);
   else
      push_stack((unsigned long)a > (unsigned long)b);
   return (0);
}

f_smaller()
{
   long a, b;
   b = rel_stack(0);
   a = rel_stack(1);
   if (Sregs[SREG_SIGNED])
      push_stack(a < b);
   else
      push_stack((unsigned long)a < (unsigned long)b);
   return (0);
}

f_largereq()
{
   long a, b;
   b = rel_stack(0);
   a = rel_stack(1);
   if (Sregs[SREG_SIGNED])
      push_stack(a >= b);
   else
      push_stack((unsigned long)a >= (unsigned long)b);
   return (0);
}

f_smallereq()
{
   long a, b;
   b = rel_stack(0);
   a = rel_stack(1);
   if (Sregs[SREG_SIGNED])
      push_stack(a <= b);
   else
      push_stack((unsigned long)a <= (unsigned long)b);
   return (0);
}

f_eq()
{
   long a, b;
   b = rel_stack(0);
   a = rel_stack(1);
   push_stack(a == b);
   return (0);
}

f_neq()
{
   long a, b;
   b = rel_stack(0);
   a = rel_stack(1);
   push_stack(a != b);
   return (0);
}

f_if()
{
   long val;

   val = pop_stack();
   return (!val);
}

char *
exarg(buf)
char **buf;
{
   static char sbuf[64];
   register char *str = *buf;
   register int i;

   i = 0;
   while (*str == ' ')
      ++str;
   while (str[i] && str[i] != ' ')
      ++i;
   bmov(str, sbuf, i);
   sbuf[i] = 0;
   while (str[i] == ' ')
      ++i;
   *buf = str + i;
   return (sbuf);
}


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'ic.txt'" '(489 characters)'
if test -f 'ic.txt'
then
	echo shar: "will not over-write existing file 'ic.txt'"
else
cat << \!Funky!Stuff! > 'ic.txt'

program dup    rcls 0
program hex    #16 sto -1 pop
program oct    #8  sto -1 pop
program dec    #10 sto -1 pop
program bin    #2  sto -1 pop

program signed   #1 sto -2 pop
program unsigned #0 sto -2 pop

program _showbase sto -1 rcls 2 show pop pop sto -1 pop
program showhex rcl -1 #16 _showbase
program showbin rcl -1 #2  _showbase
program showdec rcl -1 #10 _showbase
program showoct rcl -1 #8  _showbase

program btoa    dup #2 << showhex pop
program atob    dup #2 >> showhex pop

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'rmctl.c'" '(1490 characters)'
if test -f 'rmctl.c'
then
	echo shar: "will not over-write existing file 'rmctl.c'"
else
cat << \!Funky!Stuff! > 'rmctl.c'


/*
 * RMCTL.C
 *
 *
 * Compilation:
 *       -Use a 32 bit integers compiler
 *       -Use Astartup.obj (tiny startup)
 *       -Use the following library order:  MY.LIB AMIGA.LIB LC.LIB
 *
 *       LC.LIB is only in there because Lattice uses a function in its
 *       library for long integer multiplies.
 *
 *       MY.LIB is my own library.  If you don't have it, I'll mail it
 *       to you via UUCP or ARPAnet.
 *
 *       Executable size should be around 3K
 *
 * Remove all non-displayable or strange characters from a file or STDIN
 * straight ascii text in the file.  Results are placed to STDOUT.
 *
 * RMCTL [source file]
 *
 */

char cvt[256];
unsigned char *str = "`~!@#$%^&*()_+|-=\\[]{}';:/.,?><\"";

main(ac, av)
char *av[];
{
   register int i;
   register int fi, fo;

   cvt[10] = cvt[13] = cvt[9] = 1;
   while (*str)
      cvt[*str++] = 1;
   for (i = 'a'; i <= 'z'; ++i)
      cvt[i] = 1;
   for (i = 'A'; i <= 'Z'; ++i)
      cvt[i] = 1;
   for (i = '0'; i <= '9'; ++i)
      cvt[i] = 1;

   fo = xattach(Output(), 8192);
   if (ac == 2) {
      fi = xopen(av[1], "r", 4096);
      if (fi && fo)
         rmctl(fi, fo);
      xclose(fi);
   } else {
      fi = xattach(Input(), 8192);
      if (fi && fo)
         rmctl(fi, fo);
      xdetach(fi);
   }
   xdetach(fo);
}

rmctl(fi, fo)
register int fi, fo;
{
   unsigned char c;

   while (xread(fi, &c, 1)) {
      if (cvt[c] == 0)
         xwrite (fo, " ", 1);
      else
         xwrite (fo, &c, 1);
   }
}


!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'sr.c'" '(2333 characters)'
if test -f 'sr.c'
then
	echo shar: "will not over-write existing file 'sr.c'"
else
cat << \!Funky!Stuff! > 'sr.c'

/*
 * SR.C
 *
 *
 * Compilation:
 *       -Use a 32 bit integers compiler
 *       -Use Astartup.obj (tiny startup)
 *       -Use the following library order:  MY.LIB AMIGA.LIB LC.LIB
 *
 *       LC.LIB is only in there because Lattice uses a function in its
 *       library for long integer multiplies.
 *
 *       MY.LIB is my own library.  If you don't have it, I'll mail it
 *       to you via UUCP or ARPAnet.
 *
 *       Executable size should be around 3K
 *
 * Search and replace utility.  Search for patterns (arguments are hex
 * bytes) and optionally replace with another pattern of the same size.
 *
 * SR file ss ss ss ss ss .. [-r dd dd dd ...]
 *
 */

typedef unsigned char u_char;

#define MAXINDEX  128

main(ac, av)
register char *av[];
{
   register int i, j;
   register int sindex, rindex, rmode, fi;
   u_char sarray[MAXINDEX], rarray[MAXINDEX], buf[MAXINDEX];

   check32();
   sindex = rindex = rmode = 0;
   if (ac < 2) {
      puts ("sr file ss ss ss ss ss ... [-r dd dd dd...]    (bytes in HEX)");
      exit (1);
   }
   fi = xopen(av[1], "r+", 4096);
   if (!fi) {
      puts ("file not found");
      exit (1);
   }
   for (i = 2; i < ac; ++i) {
      if (av[i][0] == '-' && av[i][1] == 'r') {
         rmode = 1;
         continue;
      }
      rarray[rindex] = sarray[sindex] = htoi(av[i]);
      (rmode) ? ++rindex : ++sindex;
   }
   if (sindex == 0 || (rmode && rindex != sindex)) {
      puts ("size mismatch or 0 elements");
      xclose(fi);
      exit(1);
   }
   for (i = 0;;++i) {               /* at position i before read */
      if (!xread(fi, buf, 1))
         break;
      if (sarray[0] == buf[0]) {
         if (xread(fi, buf+1, sindex-1) != sindex-1)
            break;
         for (j = sindex - 1; j; --j) {
            if (buf[j] != sarray[j])
               break;
         }
         if (j == 0) {
            printf ("OFFSET: %8lx\n", i);
            if (rmode) {
               xseek(fi, i, -1);
               xwrite(fi, rarray, rindex);
            }
            i += sindex - 1;
         } else {
            xseek(fi, i+1, -1);
         }
      }
   }
   xclose(fi);
}

htoi(str)
register char *str;
{
   register int result = 0;

   while (*str) {
      result = (result << 4) + ((*str > '9') ? (*str & 0x1F) + 9 : *str - '0');
      ++str;
   }
   return (result);
}

!Funky!Stuff!
fi  # end of overwriting check
echo shar: "extracting 'wc.c'" '(1536 characters)'
if test -f 'wc.c'
then
	echo shar: "will not over-write existing file 'wc.c'"
else
cat << \!Funky!Stuff! > 'wc.c'

/*
 * WC.C
 *
 * Compilation:
 *       -Use a 32 bit integers compiler
 *       -Use Astartup.obj (tiny startup)
 *       -Use the following library order:  MY.LIB AMIGA.LIB LC.LIB
 *
 *       LC.LIB is only in there because Lattice uses a function in its
 *       library for long integer multiplies.
 *
 *       MY.LIB is my own library.  If you don't have it, I'll mail it
 *       to you via UUCP or ARPAnet.
 *
 *       Executable size should be around 3K
 *
 *
 * Count chars, words, and lines in a file or from stdin.
 *
 */

long t_chars, t_words, t_lines;


main(ac, av)
char *av[];
{
   register int i, fi;

   if (ac == 1) {
      fi = xattach(Input(), 1024);
      printf ("%20s ", "stdin");
      wc(fi);
      xdetach(fi);
   }
   for (i = 1; i < ac; ++i) {
      if (fi = xopen(av[i], "r", 1024)) {
         printf ("%20s ", av[i]);
         wc(fi);
         xclose(fi);
      } else {
         printf ("error: %s\n", av[i]);
      }
   }
   printf ("\n%20s %8ld %8ld %8ld\n", "TOTAL", t_chars, t_words, t_lines);
}


wc(fi)
{
   register int i, l_chars = 0, l_words = 0, l_lines = 0;
   char buf[256];

   while (i = xgets(fi, buf, 256)) {
      l_chars += i;
      ++l_lines;
      for (i = 0; buf[i];) {
         while (buf[i] == ' ')
            ++i;
         if (buf[i]) {
            while (buf[i] && buf[i] != ' ')
               ++i;
            ++l_words;
         }
      }
   }
   printf ("%8ld %8ld %8ld\n", l_chars, l_words, l_lines);
   t_chars += l_chars;
   t_words += l_words;
   t_lines += l_lines;
}

!Funky!Stuff!
fi  # end of overwriting check
exit 0
#	End of shell archive