h06694
s 00313/00000/00000
d D 1.1 83/03/22 20:12:45 bog 1 0
c date and time created 83/03/22 20:12:45 by bog
e
u
4
U
t
T
I 1
#include <stdio.h>

/*

--------------------------------------------------
UnRun    Large Model .CMD Fixup    25 Feb 83  v1.0
Serial No. xxxx-0000-654321    All Rights Reserved
Copyright (c) 1983  Graphic Software Systems, Inc.
--------------------------------------------------

The basic idea:

A .CMD file with fixups requires a loader which can do the
fixing up.  CP/M-86 1.x does not have such a loader, so the RUN
program does the loading.  This, however, requires that users
RUN <filename> rather than just <filename>, and botches up the
CCL after <filename> (although RUN could be fixed to handle
that).  Thus, one desires the cpabilities implied by RUN (Large
Model code) without the cost (RUN <filename>).

This program, UNRUN, turns a .CMD file which has fixups into a
.CMD which need not be RUN.  The fixups are still there, but
they are done AFTER loading by a prologue in the Aux4 bucket. 
Thus, RUN need not be run, but one pays by having the fixups
run-time resident.

The file's CSeg has its front replaced by a little swapper
routine which invokes the prologue in Aux4.  The original
contents of those few bytes at the front of the CSeg immediately
follow the prologue.  The prologue moves the original CSeg bytes
into the front of the CSeg and does the relocation from the
relocation list, which immediately follows the saved CSeg bytes. 
A zero byte indicates the end of the relocation list.

When relocation is complete, the prologue returns to the
beginning of the now-correct CSeg, with Cs and Ds set properly.

CP/M-86 won't allow memory allocated at load time to be returned
to the system, so the space taken up in Aux4 is gone until the
program terminates.  The price you pay for the lack of RUN.

This program is written for George Eberhardt's Computer
Innovations C and is built to run under CP/M-86.

*/

unsigned char code_string[255];	/* Prologue, Swapper, code Swapped_Out */
struct ptr_len {
  unsigned char *ptr;
  unsigned len;
 };
struct ptr_len prologue,swapper,swapped_out;

long bytes;			/* Position in file; 0 at open */

FILE *fin;			/* <file>.CMD */

FILE *file_open(fname,fmode,ferr)	/* error checking opener */
char *fname,*fmode;
int ferr;
{
  FILE *fp,*fopen();
  if ((fp = fopen(fname,fmode)) == NULL) {
    fprintf(stderr,"cannot open %s\n",fname);
    exit(ferr);
   }
  return(fp);
 }

int get_byte()			/* dies at EOF */
{
  int c;
  c = fgetc(fin);
  if (c < 0) {
    fprintf(stderr,"unexpected EOF\n");
    exit(5);
   }
  bytes++;
  return(c);
 }

int put_byte(ch)		/* returns what is put */
int ch;
{
  int c;
  c = fputc(ch,fin);
  if (c < 0) {
    fprintf(stderr,"write error\n");
    exit(6);
   }
  return(c);
 }

unsigned int get_unsigned()	/* uses get_byte */
{
  unsigned int u;
  u = get_byte();
  u += (((unsigned int) get_byte()) << 8);
  return(u);
 }

unsigned int put_unsigned(uns)	/* returns what is put */
unsigned int uns;
{
  put_byte((int) (uns & 255));
  put_byte((int) (uns >> 8));
  return(uns);  
 }

main(argc,argv)
int argc;
char *argv[];
{
  char fname[32];
  unsigned char *cp,*cptr,*alloc();
  unsigned int ui,coreleft();
  int bdos();
  int c,g,group;
  long f,u,lim;
  long fseek();
  struct ptr_len fixup;

  struct g_desc {		/* .CMD bucket descriptors */
    int g_form;			/* 1..8 is C,D,E,SSeg, Aux 1..4 */
    unsigned g_length;		/* number of paragraphs in .CMD bucket */
    unsigned a_base;		/* segbase of absolute bucket; 0 if not abs */
    unsigned g_min;		/* minimum number of paragraphs to allocate */
    unsigned g_max;		/* max useful paragraphs; 0 if g_min */
    long g_pos;			/* byte position in file of bucket */
   };

  struct g_desc bucket[16];	/* 16 possible buckets in .CMD */

  fname[0] = NULL;

  if (argc < 2) {
    printf("--------------------------------------------------\n");
    printf("UnRun    Large Model .CMD Fixup    25 Feb 83  v1.0\n");
    printf("Serial No. xxxx-0000-654321    All Rights Reserved\n");
    printf("Copyright (c) 1983  Graphic Software Systems, Inc.\n");
    printf("--------------------------------------------------\n");
    printf("\n 'unrun <filespec>'\n");
    printf(  "    changes <filespec>.CMD to execute without RUN");
    exit(0);
   }

  strcat(fname,*++argv);

  for (c = 0; fname[c] != '.' && fname[c] != NULL; c++) {
    if (fname[c] >= 'a' && fname[c] <= 'z') {
      fname[c] = fname[c] - 'a' + 'A';
     }
   }

  if (fname[c] == NULL) {
    strcat(fname,".CMD");
   }

/* pass 0: load prologue.cmd */

  c = bdos(32,255);		/* return current user number */

  bdos(32,0);			/* prologue.cmd is in user 0 */

  fin = file_open("prologue.cmd","rb",99);

  bdos(32,c);			/* back to starting user number */

  bytes = 0;

  get_byte();			/* Code G-Form */

  u = ((long) get_unsigned()) << 4;	/* Code G-Length */

  while (bytes & 127) {		/* Skip to Code bucket */
    get_byte();
   }

  for (prologue.ptr = &code_string[0]; u > 0; u--) {
    *prologue.ptr++ = get_byte();
   }

  prologue.ptr = &code_string[0];
  prologue.len = get_unsigned();
  swapper.ptr = prologue.ptr + prologue.len;
  swapper.len = swapped_out.len = get_unsigned();
  swapped_out.ptr = swapper.ptr + swapper.len;

  fclose(fin);

  fin = file_open(fname,"rwb",1);

  bytes = 0;

  u = 0x80;			/* position of first bucket */

  for (group = 0; (bucket[group].g_form = get_byte()) != 0; group++) {
    bucket[group].g_length = get_unsigned();
    bucket[group].a_base = get_unsigned();
    bucket[group].g_min = get_unsigned();
    bucket[group].g_max = get_unsigned();
    bucket[group].g_pos = u;
    u += ((long) bucket[group].g_length) << 4L;

    if (bucket[group].g_form == 8) {	/* Aux4 has something coming in */
      fprintf(stderr,"%s already has poop in X4 bucket",fname);
      exit(101);
     }
   }

  fseek(fin,125L,0);		/* seek to fixup block pointer */

  f = ((long) get_unsigned()) << 7L;/* seek pointer for fixup block */

  if (get_byte() != 0x80) {		/* no fixups present */
    fprintf(stderr,"%s has no fixups",fname);
    exit(102);
   }

  bucket[group].g_form = 8;	/* Aux 4 bucket */
  bucket[group].a_base = bucket[group].g_max = 0;
  bucket[group].g_pos = u;	/* seek position for Aux 4 */

  fseek(fin,bytes = f,0);	/* seek to fixups */
  while (get_byte() != 0) {	/* while fixups here */
    get_unsigned();
    get_byte();
   }

  bucket[group].g_length = bucket[group].g_min =	/* Aux4 size */
   ((bytes - f + 16 + (long) (prologue.len + swapper.len)) >> 4);

  if (bucket[group].g_length >= 0x10000L) {
    fprintf(stderr,"too many fixups in %s",fname);
    exit(103);
   }

  fixup.len = bytes - f;

  if (fixup.len > coreleft()) {
    fprintf(stderr,"too many fixups in %s",fname);
    exit(103);
   }

  fixup.ptr = alloc(fixup.len);	/* cheap, cheap */

  for (g = 0; g <= group; g++) {	/* find and swap CSeg */
    if (bucket[g].g_form == 1) {	/* CSeg */
      fseek(fin,bucket[g].g_pos,0);	/* seek beginning of CSeg */
      for (c = 0; c < swapper.len; c++) {
	*(swapped_out.ptr + c) = get_byte();/* save swapped_out code */
	fseek(fin,-1L,1);		/* re-seek same char */
	put_byte(*(swapper.ptr + c));	/* put swapper code */
       }
      break;
     }
   }

  if (g >= group) {		/* if CSeg not found */
    fprintf(stderr,"no CSeg found in %s",fname);
    exit(102);
   }

  fseek(fin,(long) (group * 9),0);	/* g_desc area for Aux 4 */
  put_byte(bucket[group].g_form);
  put_unsigned(bucket[group].g_length);
  put_unsigned(bucket[group].a_base);
  put_unsigned(bucket[group].g_min);
  put_unsigned(bucket[group].g_max);


  fseek(fin,125L,0);		/* clear fixup switches */
  for (c = 0; c < 2; c++) put_byte(0);

  fseek(fin,f,0);		/* seek to fixups */

  cp = fixup.ptr;		/* get fixups */
  for (ui = fixup.len; ui > 0; ui--) {
    *cp++ = get_byte();
   }

  fseek(fin,f = bucket[group].g_pos,0);/* seek to Aux4 place */

  cp = prologue.ptr;
  for (c = prologue.len; c > 0; c--) {	/* copy prologue */
    put_byte(*cp++);
    f++;
   }

  cp = swapped_out.ptr;
  for (c = swapped_out.len; c > 0; c--) {/* copy swapped-out code */
    put_byte(*cp++);
    f++;
   }

  cp = fixup.ptr;		/* poop out fixups */
  for (ui = fixup.len; ui > 0; ui--) {
    put_byte(*cp++);
    f++;
   }

  put_byte(0);			/* stopper zero */

  while (++f & 127) {		/* to sector boundary */
    put_byte(0);
   }

  fclose(fin);

  u = ((long) bucket[group].g_length) << 4L;

  printf("added %04lxh (%lud) bytes to run-time size of %s\n",u,u,fname);
 }
E 1
