/* procrc.c - display the CRCs of source files of a compiled progress program */

/* Copyright (C) 2000 Grant P. Maizels. All rights reserved
 * This software is copyrighted work licensed under the terms of the
 * GNU General Public License. Please consult 
 * http://www.gnu.org/licenses/licenses.html#GPL for details.
 */

/* Version 1.2 Add support for Rcode ver 909 - 9.1d with many action segments */
/* Version 1.1 last update 02Dec2001 fix for Windows */
/* Version 1.0             19Nov2001 initial verion */

/* Note the code is not nice to read, but it is difficult to write with
   structures when the data can be byteswapped */

#include <fcntl.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/stat.h>

#define RD_SZ 512

/* R-CODE HEADER */
#define O_MAGIC 0
#define O_TS 4
#define O_HDR1 8 /* v9+ but zero previusly - so there should be no 
			compatitilbity problems */
#define O_RCVER 14
#define O_SEGT_SZ 30
#define HDR_SZ 68

/* SEGMENT LIST */
#define I_SEG_AD 0 /* contents of this addres should always be zero also */
#define DEBUG_SEG_AD 24
#define DEBUG_909_SEG_AD 36

/* Iseg Header */
#define O_PROG_CRC 70
/* DEBUG HEADER */
#define O_SRC_CNT 2
#define O_SRC_LST 4

/* DEBUG SRC LIST */
#define O_DEBSRC_NEXT 0
#define O_DEBSRC_CRC 2
#define O_DEBSRC_PPSZ 4
#define O_DEBSRC_DIRSZ 8
#define O_DEBSRC_FILE 9

int byteswapped;
int byteswapped;
unsigned char *p, *op;

unsigned long gl(int);
unsigned short gs(int);
unsigned char gb(int);


main(argc, argv)
int argc;
char *argv[];
{
   int n, i;
   FILE *fd;
   unsigned char *prog, *r;
   int comp_ts, segt_sz, hdr1_sz, debug_offset, i_offset, rcver, prog_crc,
      srclst, srccnt, crc, addr, dirsz;
   char *path, *incname;
   struct stat stbuf;

   /* The following line of code not to be removed from program */
   fprintf(stderr, "*** procrc - Copyright (C) 2000 Grant P. Maizels\n");

   if (argc < 2) {
      fprintf(stderr, "usage: %s r-code-file.r\n", argv[0]);
      exit(1);
   }

   stat(argv[1], &stbuf);
   prog = (char *) malloc(stbuf.st_size);
   fd = fopen(argv[1], "rb");
   if (fd == NULL) {
      fprintf(stderr, "%s: file %s not found\n", argv[0], argv[1]);
      exit(2);
   }
   r = prog;
   i = 0;
   while ((n = fread(r+i, RD_SZ, 1, fd)) > 0)
      i += n * RD_SZ;
   
   /* p points to whole r-code */
   p = prog;
   if (gl(O_MAGIC) != 0x56ced309) {
     if (gl(O_MAGIC) == 0x09d3ce56)
	 byteswapped = 1;
     else {
	 fprintf(stderr, "Not a progress R-code file\n");
	 exit(4);
     }
   }
   comp_ts = gl(O_TS);
   rcver = gs(O_RCVER);
   hdr1_sz = gl(O_HDR1);
   segt_sz = gl(O_SEGT_SZ);

   /* p points to segment list */
   
   p = p + HDR_SZ + hdr1_sz;
   i_offset = gl(I_SEG_AD);
   if (rcver == 909) 
       debug_offset = gl(DEBUG_909_SEG_AD);
   else
       debug_offset = gl(DEBUG_SEG_AD);
   if (debug_offset == 0) { 
      fprintf(stderr, "No debug segment\n");
      exit(5);
   }
   op = p;
   /* p points to i segment */
   p = op + segt_sz + i_offset;
   prog_crc = gs(O_PROG_CRC);

   /* p points to debug segment */
   p = op + segt_sz + debug_offset;
   srccnt = gs(O_SRC_CNT);
   srclst = gs(O_SRC_LST);

   printf("R-Code file: %s \n", argv[1]);
   printf("Size: %d bytes\n", stbuf.st_size);
   printf("Compiled on: %d (0x%lx) %s", comp_ts, comp_ts, 
      ctime((time_t *) &comp_ts));
   printf("R-Code version: %d\n", rcver);
   printf("R-Code CRC: %d\n", prog_crc);
   addr = srclst;
   for (i = 0 ; i < srccnt ; i++) {
      crc = gs(addr + O_DEBSRC_CRC);
      dirsz = gb(addr + O_DEBSRC_PPSZ);
      incname = (char *) (p + addr + O_DEBSRC_FILE + dirsz);
      path = (char *) (p + addr + O_DEBSRC_FILE);
      printf("Source CRC: %s %s %d\n", incname, path, crc);
      addr = gs(addr + O_DEBSRC_NEXT);
   }
}

unsigned long gl(int i)
{
  if (byteswapped)
    return (((unsigned long) p[i+3] * 256 * 65536) +
           ((unsigned long) p[i+2] * 65536) +
           ((unsigned long) p[i+1] * 256) +
           (unsigned long) p[i]);
  else
    return (((unsigned long) p[i] * 256 * 65536) +
           ((unsigned long) p[i+1] * 65536) +
           ((unsigned long) p[i+2] * 256) +
           (unsigned long) p[i+3]);
}

unsigned short gs(int i)
{
    if (byteswapped)
        return ((p[i+1] * 256) + p[i]);
    else
        return ((p[i] * 256) + p[i+1]);
}

unsigned char gb(int i)
{
    return (p[i]);
}
