mirror of
https://github.com/byteworksinc/MakeLib.git
synced 2025-02-10 13:30:56 +00:00
e39780bcc8
Fix extract operation
2241 lines
50 KiB
C++
2241 lines
50 KiB
C++
/***************************************************************
|
|
*
|
|
* ORCA/M MakeLIB 2.0
|
|
*
|
|
* By Mike Westerfield
|
|
* Original Version 4 April 1988
|
|
* 2.0 Version: August 1991
|
|
*
|
|
* Copyright 1986,1988,1991
|
|
* By the Byte Works, Inc.
|
|
*
|
|
* The source code for APW is protected by trade secret. It
|
|
* cannot be released or used in any way except for building
|
|
* APW and archiving the source without the written permission
|
|
* of the Byte Works, Inc.
|
|
*
|
|
* Written using ORCA/C 1.2.
|
|
*
|
|
****************************************************************
|
|
*
|
|
* MAKELIB [-D] [-F] library [+|-|^ object]
|
|
*
|
|
* -D indicates that the dictionary should be listed
|
|
* -F indicates that the list of files should be listed
|
|
* library name of the library to modify
|
|
* +object add the object file to the library
|
|
* -object remove the object file from the library
|
|
* ^object remove the object file and write it as an object file
|
|
*
|
|
***************************************************************/
|
|
|
|
#pragma keep "makelib"
|
|
#pragma lint -1
|
|
#pragma optimize 9
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
|
|
#define TRUE 1 /* boolean constants */
|
|
#define FALSE 0
|
|
#define BOOL int /* boolean type */
|
|
|
|
#define MAXLINE 255 /* size of input line */
|
|
#define MAXNAME 256 /* # chars in a symbol or file name */
|
|
#define MAXFILE 8192 /* max length of a path name */
|
|
|
|
/* Shell, GS/OS Interface */
|
|
/**************************/
|
|
extern pascal void PDosInt(int, char *);
|
|
#define EXPAND_DEVICES(parm) (PDosInt(0x0154,parm))
|
|
#define WRITE_CONSOLE(parm) (PDosInt(0x015A,parm))
|
|
#define DestroyGS(pBlockPtr) (PDosInt(0x2002,pBlockPtr))
|
|
#define SetFileInfoGS(pBlockPtr) (PDosInt(0x2005,pBlockPtr))
|
|
#define GetFileInfoGS(pBlockPtr) (PDosInt(0x2006,pBlockPtr))
|
|
|
|
typedef unsigned char byte, Byte;
|
|
|
|
struct TimeRec {
|
|
Byte second;
|
|
Byte minute;
|
|
Byte hour;
|
|
Byte year;
|
|
Byte day;
|
|
Byte month;
|
|
Byte extra;
|
|
Byte weekDay;
|
|
} ;
|
|
typedef struct TimeRec TimeRec, *TimeRecPtr, **TimeRecHndl;
|
|
|
|
struct GSString255 {
|
|
int length;
|
|
char text[255];
|
|
} ;
|
|
typedef struct GSString255 GSString255, *GSString255Ptr, **GSString255Hndl;
|
|
|
|
struct ResultBuf255 {
|
|
int bufSize;
|
|
GSString255 bufString;
|
|
} ;
|
|
typedef struct ResultBuf255 ResultBuf255, *ResultBuf255Ptr, **ResultBuf255Hndl;
|
|
|
|
struct FileInfoRecGS {
|
|
int pCount;
|
|
GSString255Ptr pathname;
|
|
int access;
|
|
int fileType;
|
|
long auxType;
|
|
int storageType; /* must be 0 for SetFileInfo */
|
|
TimeRec createDateTime;
|
|
TimeRec modDateTime;
|
|
ResultBuf255Ptr optionList;
|
|
long eof;
|
|
long blocksUsed; /* must be 0 for SetFileInfo */
|
|
long resourceEOF; /* must be 0 for SetFileInfo */
|
|
long resourceBlocks; /* must be 0 for SetFileInfo */
|
|
} ;
|
|
typedef struct FileInfoRecGS FileInfoRecGS, *FileInfoRecPtrGS;
|
|
|
|
typedef struct osName { /* GS/OS input name */
|
|
int length;
|
|
char str[MAXFILE];
|
|
} osName, *osNamePtr;
|
|
|
|
typedef struct outName { /* GS/OS output name */
|
|
int buffsize;
|
|
int length;
|
|
char str[MAXFILE];
|
|
} outName, *outNamePtr;
|
|
|
|
struct NameRecGS {
|
|
int pCount;
|
|
GSString255Ptr pathname;
|
|
} ;
|
|
typedef struct NameRecGS NameRecGS, *NameRecPtrGS;
|
|
|
|
/* file handling */
|
|
/*****************/
|
|
FILE *inFile; /* input file */
|
|
FILE *outFile; /* output file */
|
|
FILE *objFile; /* obj output file for ^ */
|
|
|
|
byte *s,*s2; /* disk segment */
|
|
|
|
long ds,nds; /* disp in s */
|
|
|
|
char (*libName)[MAXFILE]; /* file names */
|
|
char (*segName)[MAXFILE];
|
|
char segFlag; /* object segment processing type */
|
|
|
|
/* symbol tables */
|
|
/*****************/
|
|
|
|
typedef struct fileStruct { /* file list */
|
|
struct fileStruct *fNext;
|
|
char *fName;
|
|
int fFile;
|
|
} fileStruct;
|
|
|
|
typedef struct symbolStruct { /* symbol table entry */
|
|
struct symbolStruct *sNext; /* next entry */
|
|
char *sName; /* symbol name */
|
|
int sFile; /* file index number */
|
|
long sSeg;
|
|
BOOL sPrivate; /* private symbol? */
|
|
} symbolStruct;
|
|
|
|
symbolStruct *symbol; /* pointer to first symbol */
|
|
fileStruct *file; /* pointer to file entry */
|
|
|
|
/* misc variables and flags */
|
|
/****************************/
|
|
int addFNum; /* file # of added file */
|
|
int argcnt; /* index of last argv */
|
|
int largc; /* copy of argc */
|
|
char **largv; /* copy of argv */
|
|
char line[MAXLINE]; /* input line buffer */
|
|
BOOL printDictionary; /* print the dictionary? */
|
|
BOOL printFiles; /* print the list of files? */
|
|
BOOL progress; /* print progress info? */
|
|
int status; /* status sent back to shell */
|
|
|
|
/* Spinner */
|
|
/*---------*/
|
|
|
|
#define spinSpeed 3 /* calls before one spinner move */
|
|
|
|
int spinning = 0; /* are we spinning now? */
|
|
int spinDisp = 0; /* disp to the spinner character */
|
|
int spinCount = 0; /* spin loop counter */
|
|
|
|
int spinner[] = {0x7C,0x2F,0x2D,0x5C}; /* spinner characters */
|
|
|
|
/* Global utility subroutines *********************************/
|
|
|
|
/***************************************************************
|
|
*
|
|
* Spin - spin the spinner
|
|
*
|
|
* Notes: Starts the spinner if it is not already in use.
|
|
*
|
|
***************************************************************/
|
|
|
|
void Spin (void)
|
|
|
|
{
|
|
struct {
|
|
int pcount;
|
|
char ch;
|
|
} parm;
|
|
|
|
if (!spinning) {
|
|
spinning = TRUE;
|
|
spinCount = spinSpeed;
|
|
}
|
|
|
|
if (! (--spinCount)) {
|
|
spinCount = spinSpeed;
|
|
--spinDisp;
|
|
if (spinDisp < 0)
|
|
spinDisp = 3;
|
|
parm.pcount = 1;
|
|
parm.ch = (char) spinner[spinDisp];
|
|
WRITE_CONSOLE((void *) &parm);
|
|
parm.ch = (char) 8;
|
|
WRITE_CONSOLE((void *) &parm);
|
|
}
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* StopSpin - stop the spinner
|
|
*
|
|
* Notes: The call is safe, and ignored, if the spinner is inactive
|
|
*
|
|
***************************************************************/
|
|
|
|
void StopSpin (void)
|
|
|
|
{
|
|
struct {
|
|
int pcount;
|
|
char ch;
|
|
} parm;
|
|
|
|
if (spinning) {
|
|
spinning = FALSE;
|
|
parm.pcount = 1;
|
|
parm.ch = ' ';
|
|
WRITE_CONSOLE((void *) &parm);
|
|
parm.ch = (char) 8;
|
|
WRITE_CONSOLE((void *) &parm);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************
|
|
*
|
|
* CheckESC - Checks to see if 'escape' is pressed
|
|
*
|
|
* Notes: Returns to shell if open-apple period has been pressed.
|
|
*
|
|
***************************************************************/
|
|
|
|
void CheckESC (void)
|
|
|
|
{
|
|
char *keyboard;
|
|
char *strobe;
|
|
char *flags;
|
|
struct {
|
|
int pcount;
|
|
char ch;
|
|
} parm;
|
|
|
|
keyboard = (void *) 0x00C000;
|
|
strobe = (void *) 0x00C010;
|
|
flags = (void *) 0x00C025;
|
|
|
|
if (*keyboard & 0x80) {
|
|
if ((*keyboard & 0x7F) == '.')
|
|
if (*flags & 0x80) {
|
|
*strobe = (char) 0;
|
|
exit(-1);
|
|
}
|
|
*strobe = (char) 0;
|
|
parm.pcount = 1;
|
|
parm.ch = (char) 27; WRITE_CONSOLE((void *) &parm);
|
|
parm.ch = (char) 15; WRITE_CONSOLE((void *) &parm);
|
|
parm.ch = (char) 0x43; WRITE_CONSOLE((void *) &parm);
|
|
parm.ch = (char) 24; WRITE_CONSOLE((void *) &parm);
|
|
parm.ch = (char) 14; WRITE_CONSOLE((void *) &parm);
|
|
parm.ch = (char) 8; WRITE_CONSOLE((void *) &parm);
|
|
while (! (*keyboard & 0x80)) ;
|
|
parm.ch = (char) 32; WRITE_CONSOLE((void *) &parm);
|
|
parm.ch = (char) 8; WRITE_CONSOLE((void *) &parm);
|
|
if ((*keyboard & 0x7F) == '.')
|
|
if (*flags & 0x80) {
|
|
*strobe = (char) 0;
|
|
exit(-1);
|
|
}
|
|
*strobe = (char) 0;
|
|
}
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* Error - writes an error message
|
|
*
|
|
* Inputs:
|
|
* num - error number
|
|
* stat - value to set status flag
|
|
* str - string to acompany error (some errors only)
|
|
*
|
|
***************************************************************/
|
|
|
|
void Error (int num, int stat, char *str)
|
|
|
|
{
|
|
status = stat; /* set status value */
|
|
|
|
switch (num) {
|
|
case 1:
|
|
fprintf(stderr, "\nThe object file %s is already in the library.\n", str);
|
|
break;
|
|
case 2:
|
|
fprintf(stderr, "Out of memory.\n");
|
|
break;
|
|
case 3:
|
|
fprintf(stderr, "%s is not an object module.\n", str);
|
|
break;
|
|
case 4:
|
|
fprintf(stderr, "Could not open %s.\n", str);
|
|
break;
|
|
case 5:
|
|
fprintf(stderr, "Unsupported version of the OMF.\n");
|
|
break;
|
|
case 6:
|
|
fprintf(stderr, "Object module format error.\n");
|
|
break;
|
|
case 7:
|
|
fprintf(stderr, "Error writing to work file.\n");
|
|
break;
|
|
case 8:
|
|
fprintf(stderr, "\nThe object file %s is not in the library.\n", str);
|
|
break;
|
|
case 9:
|
|
fprintf(stderr, "Missing operation on %s.\n", str);
|
|
break;
|
|
case 10:
|
|
fprintf(stderr, "No action requested.\n");
|
|
break;
|
|
case 11:
|
|
fprintf(stderr, "Could not open the work file %s.\n", str);
|
|
break;
|
|
case 12:
|
|
fprintf(stderr, "Illegal operation on %s.\n", str);
|
|
break;
|
|
case 13:
|
|
fprintf(stderr, "%s is already in the symbol table.\n", str);
|
|
break;
|
|
case 14:
|
|
fprintf(stderr, "\nThe object file %s could not be opened for output.\n",
|
|
str);
|
|
break;
|
|
case 15:
|
|
fprintf(stderr, "Could not open the library %s.\n", str);
|
|
break;
|
|
case 16:
|
|
fprintf(stderr, "%s is not a library file.\n", str);
|
|
}
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* tmalloc - allocate memory and check for out of memory
|
|
*
|
|
* Parameters:
|
|
* size - number of bytes to allocate
|
|
*
|
|
* Returns:
|
|
* pointer to the memory
|
|
*
|
|
***************************************************************/
|
|
|
|
void * tmalloc (size_t size)
|
|
|
|
{
|
|
void *ptr;
|
|
|
|
ptr = malloc(size);
|
|
if (ptr == NULL) {
|
|
Error(2,-1,0);
|
|
exit(-1);
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
/* ReadDictionary and Init and support subroutines ************/
|
|
|
|
/***************************************************************
|
|
*
|
|
* CopyName - copy a name from *s to *s2
|
|
*
|
|
* Inputs:
|
|
* len - length of named entries
|
|
*
|
|
***************************************************************/
|
|
|
|
void CopyName (long len)
|
|
|
|
{
|
|
int i;
|
|
|
|
if (!len) {
|
|
len = s[ds++];
|
|
s2[nds++] = len;
|
|
}
|
|
for (i = 0; i < len; ++i)
|
|
s2[nds++] = s[ds++];
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* CopyNumber - copy a number from *s to *s2
|
|
*
|
|
***************************************************************/
|
|
|
|
long CopyNumber (void)
|
|
|
|
{
|
|
int i,sc,numlen;
|
|
long num;
|
|
|
|
numlen = s[14];
|
|
num = 0;
|
|
if (s[32])
|
|
for (i = 0; i < numlen; ++i) {
|
|
s2[nds++] = s[ds];
|
|
num = (num<<8)|s[ds++];
|
|
}
|
|
else {
|
|
sc = 0;
|
|
for (i = 0; i < numlen; ++i) {
|
|
s2[nds++] = s[ds];
|
|
num = num|(s[ds++]<<sc);
|
|
sc += 8;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* CopyExpression - copy an expression from *s to *s2
|
|
*
|
|
* Inputs:
|
|
* lablen - length of labels
|
|
* numlen - length of numbers
|
|
*
|
|
***************************************************************/
|
|
|
|
void CopyExpression (int lablen, int numlen)
|
|
|
|
{
|
|
int opcode,i;
|
|
|
|
do {
|
|
opcode = s[ds++];
|
|
s2[nds++] = opcode;
|
|
if (opcode & 128)
|
|
switch (opcode) {
|
|
case 129: /* $81 constant */
|
|
case 135: /* $87 relative offset */
|
|
for (i = 0; i < numlen; ++i)
|
|
s2[nds++] = s[ds++];
|
|
break;
|
|
case 130: /* $82 weak reference */
|
|
case 131: /* $83 label */
|
|
case 132: /* $84 length attribute */
|
|
case 133: /* $85 type attribute */
|
|
case 134: /* $86 count attribute */
|
|
CopyName(lablen);
|
|
}
|
|
}
|
|
while (opcode);
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* Read2 - read a 2 byte number from a segment
|
|
*
|
|
* Inputs:
|
|
* s - segment
|
|
* ds - position to read from
|
|
*
|
|
* Outputs:
|
|
* ds - updated
|
|
*
|
|
* Returns:
|
|
* number read
|
|
*
|
|
***************************************************************/
|
|
|
|
int Read2 (void)
|
|
|
|
{
|
|
int num;
|
|
|
|
num = 0;
|
|
if (s[32]) {
|
|
num = s[ds++]<<8;
|
|
num |= s[ds++];
|
|
}
|
|
else {
|
|
num = s[ds++];
|
|
num |= s[ds++]<<8;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* Read4 - read a 4 byte number from a segment
|
|
*
|
|
* Inputs:
|
|
* s - segment
|
|
* ds - position to read from
|
|
*
|
|
* Outputs:
|
|
* ds - updated
|
|
*
|
|
* Returns:
|
|
* number read
|
|
*
|
|
***************************************************************/
|
|
|
|
long Read4 (void)
|
|
|
|
{
|
|
long num;
|
|
|
|
num = 0;
|
|
if (s[32]) {
|
|
num = ((unsigned long) s[ds++])<<24;
|
|
num |= ((unsigned long) s[ds++])<<16;
|
|
num |= (s[ds++]<<8);
|
|
num |= s[ds++];
|
|
}
|
|
else {
|
|
num = s[ds++];
|
|
num |= (s[ds++]<<8);
|
|
num |= ((unsigned long) s[ds++])<<16;
|
|
num |= ((unsigned long) s[ds++])<<24;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* ReadName - read a name from the input file
|
|
*
|
|
* Inputs:
|
|
* len - length of named entries
|
|
* name - pointer to location to store the name
|
|
*
|
|
***************************************************************/
|
|
|
|
void ReadName (char *name, long len)
|
|
|
|
{
|
|
int i;
|
|
|
|
if (!len)
|
|
len = s[ds++];
|
|
for (i = 0; i < len; ++i)
|
|
name[i] = s[ds++];
|
|
while (name[len-1] == ' ') --len;
|
|
name[len] = (char) 0;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* ReadNumber - read a number from a segment
|
|
*
|
|
* Inputs:
|
|
* s - segment
|
|
* ds - position to read from
|
|
*
|
|
* Outputs:
|
|
* ds - updated
|
|
*
|
|
* Returns:
|
|
* number read
|
|
*
|
|
***************************************************************/
|
|
|
|
long ReadNumber (void)
|
|
|
|
{
|
|
int i,sc,numlen;
|
|
long num;
|
|
|
|
numlen = s[14];
|
|
num = 0;
|
|
if (s[32])
|
|
for (i = 0; i < numlen; ++i)
|
|
num = (num<<8)|s[ds++];
|
|
else {
|
|
sc = 0;
|
|
for (i = 0; i < numlen; ++i) {
|
|
num = num|(s[ds++]<<sc);
|
|
sc += 8;
|
|
}
|
|
}
|
|
return num;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* ReadExpression - read an expression from the object file
|
|
*
|
|
* Inputs:
|
|
* lablen - length of labels
|
|
* numlen - length of numbers
|
|
* inFile - input file
|
|
*
|
|
***************************************************************/
|
|
|
|
void ReadExpression (int lablen, int numlen)
|
|
|
|
{
|
|
int opcode,i;
|
|
char name[MAXNAME];
|
|
|
|
do {
|
|
opcode = s[ds++];
|
|
if (opcode & 128)
|
|
switch (opcode) {
|
|
case 129: /* $81 constant */
|
|
case 135: /* $87 relative offset */
|
|
ds += numlen;
|
|
break;
|
|
case 130: /* $82 weak reference */
|
|
case 131: /* $83 label */
|
|
case 132: /* $84 length attribute */
|
|
case 133: /* $85 type attribute */
|
|
case 134: /* $86 count attribute */
|
|
if (lablen)
|
|
ds += lablen;
|
|
else
|
|
ds += s[ds]+1;
|
|
}
|
|
}
|
|
while (opcode);
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* Convert1to2 - Convert OMF 1.0 segment to OMF 2.0 format
|
|
*
|
|
* Inputs:
|
|
* len - length of the 1.0 segment
|
|
* s - pointer to OMF 1.0 segment
|
|
*
|
|
* Outputs:
|
|
* s - pointer to new OMF 2.0 segment
|
|
*
|
|
* Returns: length of the new segment
|
|
*
|
|
***************************************************************/
|
|
|
|
long Convert1to2 (long len)
|
|
|
|
{
|
|
long dispdata; /* disp to the data */
|
|
int i; /* loop variable */
|
|
int kind; /* kind field */
|
|
int flen; /* length of a field */
|
|
int lablen; /* length of labels */
|
|
char name[MAXNAME]; /* used to read names from the file */
|
|
int numlen; /* length of numbers */
|
|
int opcode; /* current instruction */
|
|
BOOL sex; /* numsex */
|
|
|
|
lablen = s[13]; /* get length of fields */
|
|
numlen = s[14];
|
|
sex = s[32]; /* read dispdata */
|
|
if (sex)
|
|
dispdata = (s[42] << 8) + s[43];
|
|
else
|
|
dispdata = s[42] + (s[43] << 8);
|
|
|
|
ds = dispdata; /* scan the segment for fields */
|
|
do { /* that must be expanded */
|
|
opcode = s[ds++];
|
|
switch (opcode) {
|
|
case 0: /* $00 END */
|
|
break;
|
|
case 224: /* $E0 ALIGN */
|
|
case 225: /* $E1 ORG */
|
|
case 241: /* $F1 DS */
|
|
ds = ds+numlen;
|
|
break;
|
|
case 226: /* $E2 RELOC */
|
|
case 227: /* $E3 INTERSEG */
|
|
case 233: /* $E9 unused */
|
|
case 234: /* $EA unused */
|
|
case 255: case 244: case 245: case 246:
|
|
case 247: case 248: case 249: case 250:
|
|
case 251: case 252: case 253: case 254:
|
|
Error(6, -1, 0); /* object module format error */
|
|
return -1;
|
|
case 228: /* $E4 USING */
|
|
case 229: /* $E5 STRONG */
|
|
if (lablen)
|
|
ds += lablen;
|
|
else
|
|
ds += s[ds]+1;
|
|
break;
|
|
case 230: /* $E6 GLOBAL */
|
|
ReadName(name, lablen);
|
|
ds += 3;
|
|
++len;
|
|
break;
|
|
case 231: /* $E7 GEQU */
|
|
ReadName(name, lablen);
|
|
ds += 3;
|
|
++len;
|
|
ReadExpression(lablen, numlen);
|
|
break;
|
|
case 232: /* $E8 MEM */
|
|
ds += numlen*2;
|
|
break;
|
|
case 235: /* $EB EXPR */
|
|
case 236: /* $EC ZEXPR */
|
|
case 237: /* $ED BEXPR */
|
|
case 243: /* $F3 LEXPR */
|
|
++ds;
|
|
ReadExpression(lablen, numlen);
|
|
break;
|
|
case 238: /* $EE RELEXPR */
|
|
ds += 1+numlen;
|
|
ReadExpression(lablen, numlen);
|
|
break;
|
|
case 239: /* $EF LOCAL */
|
|
++len;
|
|
if (lablen)
|
|
ds += lablen+4;
|
|
else
|
|
ds += s[ds]+5;
|
|
break;
|
|
case 240: /* $F0 EQU */
|
|
++len;
|
|
if (lablen)
|
|
ds += lablen+4;
|
|
else
|
|
ds += s[ds]+5;
|
|
ReadExpression(lablen, numlen);
|
|
break;
|
|
case 242: /* $F2 LCONST */
|
|
flen = ReadNumber();
|
|
ds += flen;
|
|
break;
|
|
default: /* short constant */
|
|
ds += opcode;
|
|
}
|
|
}
|
|
while (opcode);
|
|
s2 = tmalloc(len); /* get memory for the new segment */
|
|
memcpy(s2, s, dispdata); /* copy in the old header */
|
|
if (sex) { /* set the length of the segment */
|
|
s2[0] = len >> 24;
|
|
s2[1] = (len >> 16) & 255;
|
|
s2[2] = (len >> 8) & 255;
|
|
s2[3] = len & 255;
|
|
}
|
|
else {
|
|
s2[0] = len & 255;
|
|
s2[1] = (len >> 8) & 255;
|
|
s2[2] = (len >> 16) & 255;
|
|
s2[3] = len >> 24;
|
|
}
|
|
s2[15] = 2; /* change the version to 2 */
|
|
kind = s[12]; /* set the new kind field */
|
|
kind = ((kind & 0xE0) << 8) | (kind & 0x1F);
|
|
if (sex) {
|
|
s2[20] = kind >> 8;
|
|
s2[21] = kind & 0xFF;
|
|
}
|
|
else {
|
|
s2[20] = kind & 0xFF;
|
|
s2[21] = kind >> 8;
|
|
}
|
|
s2[12] = 0;
|
|
ds = dispdata; /* move and convert the segment */
|
|
nds = ds;
|
|
do {
|
|
opcode = s[ds++];
|
|
s2[nds++] = opcode;
|
|
switch (opcode) {
|
|
case 0: /* $00 END */
|
|
break;
|
|
case 224: /* $E0 ALIGN */
|
|
case 225: /* $E1 ORG */
|
|
case 241: /* $F1 DS */
|
|
for (i = 0; i < numlen; ++i)
|
|
s2[nds++] = s[ds++];
|
|
break;
|
|
case 226: /* $E2 RELOC */
|
|
case 227: /* $E3 INTERSEG */
|
|
case 233: /* $E9 unused */
|
|
case 234: /* $EA unused */
|
|
case 255: case 244: case 245: case 246:
|
|
case 247: case 248: case 249: case 250:
|
|
case 251: case 252: case 253: case 254:
|
|
Error(6, -1, 0); /* object module format error */
|
|
return -1;
|
|
case 228: /* $E4 USING */
|
|
case 229: /* $E5 STRONG */
|
|
CopyName(lablen);
|
|
break;
|
|
case 230: /* $E6 GLOBAL */
|
|
case 239: /* $EF LOCAL */
|
|
CopyName(lablen);
|
|
s2[nds++] = s[ds++];
|
|
s2[nds++] = 0;
|
|
s2[nds++] = s[ds++];
|
|
s2[nds++] = s[ds++];
|
|
break;
|
|
case 231: /* $E7 GEQU */
|
|
case 240: /* $F0 EQU */
|
|
CopyName(lablen);
|
|
s2[nds++] = s[ds++];
|
|
s2[nds++] = 0;
|
|
s2[nds++] = s[ds++];
|
|
s2[nds++] = s[ds++];
|
|
CopyExpression(lablen, numlen);
|
|
break;
|
|
case 232: /* $E8 MEM */
|
|
for (i = 0; i < numlen*2; ++i)
|
|
s2[nds++] = s[ds++];
|
|
break;
|
|
case 235: /* $EB EXPR */
|
|
case 236: /* $EC ZEXPR */
|
|
case 237: /* $ED BEXPR */
|
|
case 243: /* $F3 LEXPR */
|
|
s2[nds++] = s[ds++];
|
|
CopyExpression(lablen, numlen);
|
|
break;
|
|
case 238: /* $EE RELEXPR */
|
|
for (i = 0; i < numlen+1; ++i)
|
|
s2[nds++] = s[ds++];
|
|
CopyExpression(lablen, numlen);
|
|
break;
|
|
case 242: /* $F2 LCONST */
|
|
flen = CopyNumber();
|
|
memcpy(s2+nds, s+ds, flen);
|
|
nds += flen;
|
|
ds += flen;
|
|
break;
|
|
default: /* short constant */
|
|
memcpy(s2+nds, s+ds, opcode);
|
|
nds += opcode;
|
|
ds += opcode;
|
|
}
|
|
}
|
|
while (opcode);
|
|
free(s); /* use the new segment */
|
|
s = s2;
|
|
s2 = NULL;
|
|
return len; /* return the new length */
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* ExpandDev - expand devices
|
|
*
|
|
* Parameters:
|
|
* name - pointer to the name buffer
|
|
*
|
|
***************************************************************/
|
|
|
|
void ExpandDev (char (*name)[])
|
|
|
|
{
|
|
struct rec { /* expand path record */
|
|
int pCount;
|
|
osNamePtr in;
|
|
outNamePtr out;
|
|
} exRec;
|
|
|
|
exRec.out = tmalloc(MAXFILE+5);
|
|
exRec.in = tmalloc(MAXFILE+3);
|
|
exRec.out->buffsize = MAXFILE+4;
|
|
exRec.pCount = 2;
|
|
exRec.in->length = strlen(*name);
|
|
strcpy(exRec.in->str, *name);
|
|
EXPAND_DEVICES((void *) &exRec);
|
|
exRec.out->str[exRec.out->length] = 0;
|
|
strcpy(*name, exRec.out->str);
|
|
free(exRec.out);
|
|
free(exRec.in);
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* NextCh - Get the next character from the input line
|
|
*
|
|
* Inputs:
|
|
* line - input line
|
|
*
|
|
* Outputs:
|
|
* line - line with first char removed
|
|
*
|
|
* Returns:
|
|
* Character from start of the line
|
|
*
|
|
***************************************************************/
|
|
|
|
char NextCh (void)
|
|
|
|
{
|
|
char ch;
|
|
int i;
|
|
|
|
if (ch = line[0])
|
|
for (i = 0; i < (MAXLINE-1); ++i)
|
|
line[i] = line[i+1];
|
|
return ch;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* GetDiskSeg - Read a segment from disk
|
|
*
|
|
* Inputs:
|
|
* blockalligned - true if file is a lib file, else false
|
|
*
|
|
* Outputs:
|
|
* s - points to segment
|
|
* GetDiskSeg - length of segment if segment was read, else false
|
|
*
|
|
***************************************************************/
|
|
|
|
long GetDiskSeg (BOOL blockalligned)
|
|
|
|
{
|
|
long len;
|
|
Byte header[42];
|
|
|
|
if (s != NULL) /* free any old segment memory */
|
|
free(s);
|
|
if (fread(header, 1, 42, inFile) != 42) /* read the header */
|
|
return FALSE;
|
|
if (header[32]) /* find the length of the segment */
|
|
len = header[3] | (header[2]<<8) | (((long) header[1])<<16)
|
|
| (((long) header[0])<<24);
|
|
else
|
|
len = header[0] | (header[1]<<8) | (((long) header[2])<<16)
|
|
| (((long) header[3])<<24);
|
|
if (blockalligned && (header[15] == 1))
|
|
len = len<<9;
|
|
s = tmalloc(len); /* get memory for the segment */
|
|
memcpy(s, header, 42); /* copy in the header */
|
|
fread(&s[42], 1, len-42, inFile); /* read the rest of the segment */
|
|
if (header[15] == 1) /* convert OMF 1.0 to OMF 2.0 */
|
|
len = Convert1to2(len);
|
|
return len;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* GetFlag - Get a flag
|
|
*
|
|
* Inputs:
|
|
* argcnt - number of argv's processed so far
|
|
* line - left overs from input line
|
|
*
|
|
* Returns:
|
|
* GetFlag - character if flag read, else 0
|
|
*
|
|
***************************************************************/
|
|
|
|
char GetFlag (void)
|
|
|
|
{
|
|
char *cptr;
|
|
int i;
|
|
|
|
if (argcnt < largc) {
|
|
cptr = largv[argcnt];
|
|
if ((cptr[0] == '-') && (cptr[2] == 0) && isalpha(cptr[1])) {
|
|
++argcnt;
|
|
return cptr[1];
|
|
}
|
|
}
|
|
else {
|
|
while (isspace(line[0]))
|
|
NextCh();
|
|
if ((line[0] == '-') && (isalpha(line[1])) &&
|
|
((line[2] == ' ') || (line[2] == 0))) {
|
|
NextCh();
|
|
return NextCh();
|
|
}
|
|
}
|
|
return (char) 0;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* GetFType - get the file type
|
|
*
|
|
* Inputs:
|
|
* file - name of the file
|
|
*
|
|
* Returns:
|
|
* File type; 0 if there is no file.
|
|
*
|
|
***************************************************************/
|
|
|
|
int GetFType (char *file)
|
|
|
|
{
|
|
FileInfoRecGS giRec; /* GetFileInfo record */
|
|
|
|
giRec.pCount = 3;
|
|
giRec.pathname = tmalloc(strlen(file)+3);
|
|
giRec.pathname->length = strlen(file);
|
|
strcpy(giRec.pathname->text, file);
|
|
giRec.fileType = 0;
|
|
GetFileInfoGS((void *) &giRec);
|
|
free(giRec.pathname);
|
|
return giRec.fileType;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* GetName - Get a file name
|
|
*
|
|
* Inputs:
|
|
* prompt - prompt string
|
|
* argcnt - number of argv's processed so far
|
|
* line - left overs from input line
|
|
*
|
|
* Returns:
|
|
* GetName - true if name read, else false
|
|
*
|
|
* Outputs:
|
|
* name - name read
|
|
*
|
|
***************************************************************/
|
|
|
|
BOOL GetName (char *prompt, char (*name)[])
|
|
|
|
{
|
|
int i;
|
|
|
|
if (argcnt < largc)
|
|
strcpy(*name, largv[argcnt++]);
|
|
else {
|
|
while (isspace(line[0])) NextCh();
|
|
if (!line[0]) {
|
|
fputs(prompt, stdout);
|
|
fgets(line, MAXLINE, stdin);
|
|
}
|
|
while (isspace(line[0])) NextCh();
|
|
i = 0;
|
|
while ((line[0]) && (!isspace(line[0])))
|
|
(*name)[i++] = NextCh();
|
|
(*name)[i] = (char) 0;
|
|
return i;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* GetSegment - Get a segment name
|
|
*
|
|
* Inputs:
|
|
* argcnt - number of argv's processed so far
|
|
* line - left overs from input line
|
|
*
|
|
* Outputs:
|
|
* segName - name of segment
|
|
* segFlag - processing required:
|
|
* 0 - no segment name found
|
|
* '+' - add the segment to the library
|
|
* '-' - delete the segment from the library
|
|
* '^' - remove the segment from the library
|
|
*
|
|
***************************************************************/
|
|
|
|
void GetSegment (void)
|
|
|
|
{
|
|
char ch;
|
|
char name[MAXLINE];
|
|
int i;
|
|
|
|
name[0] = (char) 0;
|
|
segFlag = (char) 0;
|
|
if (argcnt < largc)
|
|
strcpy(name, largv[argcnt++]);
|
|
else {
|
|
while (isspace(line[0])) NextCh();
|
|
i = 0;
|
|
while ((line[0]) && (!isspace(line[0])))
|
|
name[i++] = NextCh();
|
|
name[i] = 0;
|
|
}
|
|
if ((ch = name[0]) && name[1]) {
|
|
if ((ch == '-') || (ch == '+') || (ch == '^')) {
|
|
segFlag = ch;
|
|
strcpy(*segName, &name[1]);
|
|
ExpandDev(segName);
|
|
}
|
|
else if (ch != '\n') {
|
|
Error(9, -1, name);
|
|
exit(-1);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* Insert - alphabetically insert an entry in a linked list
|
|
*
|
|
* Inputs:
|
|
* e - entry to insert
|
|
* l - pointer to head of list
|
|
*
|
|
* Outputs:
|
|
* Insert - pointer to new head of list
|
|
*
|
|
* Notes:
|
|
* Assumes that the entries in the list start with a pointer
|
|
* to the next element and are followed by a pointer to the
|
|
* name of the entry.
|
|
*
|
|
***************************************************************/
|
|
|
|
fileStruct * Insert (fileStruct *e, fileStruct *l)
|
|
|
|
{
|
|
fileStruct *p1,*p2;
|
|
|
|
if (l) {
|
|
if (strcmp(e->fName, l->fName) < 0) {
|
|
e->fNext = l;
|
|
return e;
|
|
}
|
|
p1 = l;
|
|
p2 = l->fNext;
|
|
while (p2) {
|
|
if (strcmp(e->fName, p2->fName) < 0) {
|
|
p1->fNext = e;
|
|
e->fNext = p2;
|
|
return l;
|
|
}
|
|
p1 = p2;
|
|
p2 = p2->fNext;
|
|
}
|
|
p1->fNext = e;
|
|
e->fNext = NULL;
|
|
return l;
|
|
}
|
|
else {
|
|
e->fNext = NULL;
|
|
return e;
|
|
}
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* ReadDictionary - read an existing library's dictionary
|
|
*
|
|
* Inputs:
|
|
* libName - name of the library
|
|
*
|
|
* Outputs:
|
|
* file - file name table
|
|
* symbol - symbol table
|
|
* ReadDictionary - true if successful or no library
|
|
* exists, else false
|
|
*
|
|
***************************************************************/
|
|
|
|
BOOL ReadDictionary (void)
|
|
|
|
{
|
|
char fn[MAXNAME]; /* used to read names from the file */
|
|
long len,num,sds,nds;
|
|
fileStruct *f; /* used for new files */
|
|
symbolStruct *sm; /* used for new symbols */
|
|
int type;
|
|
|
|
type = GetFType(*libName);
|
|
if ((type != 178) && (type != 0)) {
|
|
Error(16,-1,*libName); /* file exists but is not a lib file */
|
|
exit(-1);
|
|
}
|
|
if (inFile = fopen(*libName,"rb")) {
|
|
if (GetDiskSeg(FALSE)) {
|
|
if (s[32])
|
|
ds = (s[42]<<8)+s[43];
|
|
else
|
|
ds = s[42]+(s[43]<<8);
|
|
++ds;
|
|
len = ReadNumber();
|
|
while (len) {
|
|
Spin();
|
|
f = tmalloc(sizeof(fileStruct));
|
|
f->fFile = Read2();
|
|
len = len-3-s[ds];
|
|
ReadName(fn, 0);
|
|
f->fName = tmalloc(strlen(fn)+1);
|
|
strcpy(f->fName, fn);
|
|
file = Insert(f, file);
|
|
}
|
|
++ds;
|
|
len = ReadNumber();
|
|
sds = ds;
|
|
nds = ds+len+5;
|
|
while (len) {
|
|
Spin();
|
|
len = len-12;
|
|
sm = tmalloc(sizeof(symbolStruct));
|
|
ds = sds;
|
|
ds = nds+Read4();
|
|
sds += 4;
|
|
ReadName(fn, 0);
|
|
sm->sName = tmalloc(strlen(fn)+1);
|
|
strcpy(sm->sName, fn);
|
|
ds = sds;
|
|
sm->sFile = Read2();
|
|
sm->sPrivate = Read2();
|
|
sm->sSeg = Read4();
|
|
symbol = (symbolStruct *) Insert((fileStruct *) sm, (fileStruct *) symbol);
|
|
sds += 8;
|
|
}
|
|
}
|
|
else {
|
|
StopSpin();
|
|
return FALSE;
|
|
}
|
|
fclose(inFile);
|
|
}
|
|
StopSpin();
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* Init - initialize for a file find
|
|
*
|
|
* Outputs:
|
|
* inFile - input file
|
|
* outFile - output file
|
|
*
|
|
* Returns:
|
|
* Init - TRUE if initialization was successful, else FALSE
|
|
*
|
|
***************************************************************/
|
|
|
|
BOOL Init (void)
|
|
|
|
{
|
|
int ind,i;
|
|
char ch;
|
|
|
|
status = 0; /* no errors found */
|
|
symbol = NULL; /* no symbols, yet */
|
|
file = NULL; /* no files, yet */
|
|
s = NULL; /* no segment memory in use */
|
|
line[0] = (char) 0; /* nothing in the input line */
|
|
printDictionary = FALSE; /* don't print the dictionary */
|
|
printFiles = FALSE; /* don't print the files */
|
|
progress = TRUE; /* print progress information */
|
|
argcnt = 1; /* start with the first argument */
|
|
libName = tmalloc(MAXFILE); /* get memory for file name buffers */
|
|
segName = tmalloc(MAXFILE);
|
|
|
|
while (ch = toupper(GetFlag())) { /* read the flags */
|
|
if (ch == 'F')
|
|
printFiles = TRUE;
|
|
else if (ch == 'D')
|
|
printDictionary = TRUE;
|
|
else if (ch == 'P')
|
|
progress = FALSE;
|
|
else {
|
|
fprintf(stderr, "%c is not a valid flag.\n", ch);
|
|
exit(-1);
|
|
}
|
|
}
|
|
if (progress)
|
|
printf("MakeLib 2.0\n\n");
|
|
if (!GetName("Input file name: ", libName)) /* get an input file */
|
|
return FALSE;
|
|
ExpandDev(libName); /* expand devices */
|
|
GetSegment();
|
|
|
|
if ((!segFlag) && (!printDictionary) && (!printFiles)) {
|
|
Error(10,-1,0); /* no action requested */
|
|
exit(-1);
|
|
}
|
|
|
|
ReadDictionary(); /* read existing library's dictionary */
|
|
return TRUE;
|
|
}
|
|
|
|
/* MakeLib and support routines *******************************/
|
|
|
|
/***************************************************************
|
|
*
|
|
* LibNum - look up library number associated with a symbol
|
|
*
|
|
* Inputs:
|
|
* name - name of symbol to look up
|
|
* symbol - head of symbol table list
|
|
*
|
|
* Returns:
|
|
* library number; 0 if not found
|
|
*
|
|
***************************************************************/
|
|
|
|
int LibNum (char *name)
|
|
|
|
{
|
|
symbolStruct *p;
|
|
|
|
if (symbol) {
|
|
p = symbol;
|
|
while(p) {
|
|
if (strcmp(name, p->sName) == 0)
|
|
return p->sFile;
|
|
p = p->sNext;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* NewName - enter a symbol name into the symbol table
|
|
*
|
|
* Inputs:
|
|
* name - name of the symbol
|
|
* seg - location of the segment
|
|
* file - file number
|
|
* private - private flag
|
|
*
|
|
* Retruns:
|
|
* TRUE if added, else FALSE
|
|
*
|
|
***************************************************************/
|
|
|
|
BOOL NewName (char *name, long seg, int file, BOOL private)
|
|
|
|
{
|
|
symbolStruct *f, *s;
|
|
|
|
f = tmalloc(sizeof(symbolStruct));
|
|
f->sName = tmalloc(strlen(name)+1);
|
|
strcpy(f->sName, name);
|
|
f->sFile = file;
|
|
f->sPrivate = private;
|
|
f->sSeg = seg;
|
|
if (symbol) {
|
|
s = symbol;
|
|
while (s) {
|
|
if (!strcmp(name, s->sName)) {
|
|
if (((! private) && (! s->sPrivate)) ||
|
|
((private && s->sPrivate) && (file == s->sFile))) {
|
|
Error(13, -1, name); /* already in symbol table */
|
|
return FALSE;
|
|
}
|
|
}
|
|
s = s->sNext;
|
|
}
|
|
}
|
|
symbol = (symbolStruct *) Insert((fileStruct *) f, (fileStruct *) symbol);
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* AddSeg - add a segment to the dictionary and output file
|
|
*
|
|
* Inputs:
|
|
* inFile - file to get segment from
|
|
* outFile - file to write segment to
|
|
* fnum - file number
|
|
*
|
|
* Returns:
|
|
* 1 - more segments left
|
|
* 0 - all segments processed
|
|
* -1 - read error
|
|
*
|
|
***************************************************************/
|
|
|
|
int AddSeg (long fnum)
|
|
|
|
{
|
|
long seg,private;
|
|
long dispname,dispdata,len;
|
|
int lablen,numlen,sex,opcode;
|
|
char name[MAXNAME];
|
|
int i;
|
|
|
|
CheckESC(); /* check for early termination */
|
|
seg = ftell(outFile); /* set disp to the segment */
|
|
if ((i = GetDiskSeg(TRUE)) <= 0) return i; /* read segment;
|
|
return if none left */
|
|
private = (s[21] & 0x40) != 0; /* set private flag */
|
|
lablen = s[13]; /* get length of fields */
|
|
numlen = s[14];
|
|
if (s[15] != 2) { /* make sure its the right version */
|
|
Error(5, -1, 0); /* unsupported version */
|
|
return FALSE;
|
|
}
|
|
sex = s[32]; /* read dispname */
|
|
if (sex)
|
|
dispname = (s[40] << 8) + s[41];
|
|
else
|
|
dispname = s[40] + (s[41] << 8);
|
|
if (sex) /* read dispdata */
|
|
dispdata = (s[42] << 8) + s[43];
|
|
else
|
|
dispdata = s[42] + (s[43] << 8);
|
|
|
|
ds = dispname+10; /* put the segment name in the table */
|
|
ReadName(name, lablen);
|
|
if (!NewName(name, seg, fnum, private))
|
|
return -1;
|
|
|
|
ds = dispdata; /* scan the segment for references */
|
|
do {
|
|
opcode = s[ds++];
|
|
switch (opcode) {
|
|
case 0: /* $00 END */
|
|
break;
|
|
case 224: /* $E0 ALIGN */
|
|
case 225: /* $E1 ORG */
|
|
case 241: /* $F1 DS */
|
|
ds = ds+numlen;
|
|
break;
|
|
case 226: /* $E2 RELOC */
|
|
case 227: /* $E3 INTERSEG */
|
|
case 233: /* $E9 unused */
|
|
case 234: /* $EA unused */
|
|
case 255: case 244: case 245: case 246:
|
|
case 247: case 248: case 249: case 250:
|
|
case 251: case 252: case 253: case 254:
|
|
Error(6, -1, 0); /* object module format error */
|
|
return -1;
|
|
case 228: /* $E4 USING */
|
|
case 229: /* $E5 STRONG */
|
|
if (lablen)
|
|
ds += lablen;
|
|
else
|
|
ds += s[ds]+1;
|
|
break;
|
|
case 230: /* $E6 GLOBAL */
|
|
ReadName(name, lablen);
|
|
ds += 3;
|
|
private = s[ds++];
|
|
if (!NewName(name, seg, fnum, private))
|
|
return -1;
|
|
break;
|
|
case 231: /* $E7 GEQU */
|
|
ReadName(name, lablen);
|
|
ds += 3;
|
|
private = s[ds++];
|
|
if (!NewName(name, seg, fnum, private))
|
|
return -1;
|
|
ReadExpression(lablen, numlen);
|
|
break;
|
|
case 232: /* $E8 MEM */
|
|
ds += numlen*2;
|
|
break;
|
|
case 235: /* $EB EXPR */
|
|
case 236: /* $EC ZEXPR */
|
|
case 237: /* $ED BEXPR */
|
|
case 243: /* $F3 LEXPR */
|
|
++ds;
|
|
ReadExpression(lablen, numlen);
|
|
break;
|
|
case 238: /* $EE RELEXPR */
|
|
ds += 1+numlen;
|
|
ReadExpression(lablen, numlen);
|
|
break;
|
|
case 239: /* $EF LOCAL */
|
|
if (lablen)
|
|
ds += lablen+4;
|
|
else
|
|
ds += s[ds]+5;
|
|
break;
|
|
case 240: /* $F0 EQU */
|
|
if (lablen)
|
|
ds += lablen+4;
|
|
else
|
|
ds += s[ds]+5;
|
|
ReadExpression(lablen, numlen);
|
|
break;
|
|
case 242: /* $F2 LCONST */
|
|
len = ReadNumber();
|
|
ds += len;
|
|
break;
|
|
default: /* short constant */
|
|
ds += opcode;
|
|
}
|
|
}
|
|
while (opcode);
|
|
if (sex) { /* set the length of the segment */
|
|
s[0] = ds >> 24;
|
|
s[1] = (ds >> 16) & 255;
|
|
s[2] = (ds >> 8) & 255;
|
|
s[3] = ds & 255;
|
|
}
|
|
else {
|
|
s[0] = ds & 255;
|
|
s[1] = (ds >> 8) & 255;
|
|
s[2] = (ds >> 16) & 255;
|
|
s[3] = ds >> 24;
|
|
}
|
|
if (!(ds == fwrite(s, 1, ds, outFile))) /* write the seg to the work file */
|
|
{ /* error writing to work file */
|
|
Error(7, -1, 0);
|
|
exit(-1);
|
|
}
|
|
free(s); /* get rid of the segment */
|
|
s = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* CopyLib - copy segments from the existing library to the work file
|
|
*
|
|
* Inputs:
|
|
* outFile - opened work file
|
|
* objFile - opened obj file to put removed segments in;
|
|
* 0 if segments are to be disposed of
|
|
* libName - name of library file
|
|
* dfile - number of file who's entries are to be deleted;
|
|
* 0 if all are to remain
|
|
*
|
|
***************************************************************/
|
|
|
|
void CopyLib (int dfile)
|
|
|
|
{
|
|
long len,i;
|
|
symbolStruct *p;
|
|
char name[MAXNAME];
|
|
|
|
if (inFile = fopen(*libName, "rb")) { /* open the library */
|
|
Spin();
|
|
i = GetDiskSeg(FALSE); /* read and throw away dictionary */
|
|
free(s);
|
|
s = NULL;
|
|
if (symbol) { /* adjust disps for library files */
|
|
p = symbol;
|
|
i = ftell(outFile)-i;
|
|
while (p) {
|
|
if (p->sFile != addFNum)
|
|
p->sSeg = p->sSeg+i;
|
|
p = p->sNext;
|
|
}
|
|
}
|
|
while ((len = GetDiskSeg(FALSE)) > 0) /* process the segments */
|
|
{
|
|
Spin();
|
|
if (s[32]) /* read name of segment */
|
|
ds = (s[40]<<8) + s[41];
|
|
else
|
|
ds = s[40] + (s[41]<<8);
|
|
ds += 10;
|
|
ReadName(name, s[13]);
|
|
if (LibNum(name) == dfile) { /* if its in the dfile, delete it */
|
|
if (objFile) {
|
|
fwrite(s, 1, len, objFile);
|
|
}
|
|
if (symbol) { /* adjust disps for library files */
|
|
p = symbol;
|
|
i = ftell(outFile);
|
|
while (p) {
|
|
if (p->sFile != addFNum)
|
|
if (p->sSeg >= i)
|
|
p->sSeg = p->sSeg-len;
|
|
p = p->sNext;
|
|
}
|
|
}
|
|
}
|
|
else /* otherwise, place in work file */
|
|
fwrite(s, 1, len, outFile);
|
|
free(s);
|
|
s = NULL;
|
|
}
|
|
fclose(inFile); /* close the library */
|
|
}
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* Delete - delete entries assiciated with a file
|
|
*
|
|
* Inputs:
|
|
* num - file number of entries to delete
|
|
* list - list to extract entries from
|
|
*
|
|
* Returns:
|
|
* head of new list
|
|
*
|
|
* Notes:
|
|
* Assumes that the entries in the list start with a pointer
|
|
* to the next element, are followed by a pointer to the
|
|
* name of the entry, and then by the file number.
|
|
*
|
|
***************************************************************/
|
|
|
|
fileStruct * Delete (int num, fileStruct *list)
|
|
|
|
{
|
|
fileStruct *f,*f2;
|
|
|
|
while ((list != NULL) && (list->fFile == num)) {
|
|
f = list;
|
|
list = f->fNext;
|
|
free(f);
|
|
}
|
|
if (list) {
|
|
f2 = list;
|
|
f = f2->fNext;
|
|
while (f) {
|
|
if (f->fFile == num) {
|
|
f2->fNext = f->fNext;
|
|
free(f);
|
|
f = f2->fNext;
|
|
}
|
|
else {
|
|
f2 = f;
|
|
f = f->fNext;
|
|
}
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* FileExists - see if a file is in the object table
|
|
*
|
|
* Inputs:
|
|
* fn - file name
|
|
*
|
|
* Returns:
|
|
* TRUE if in table, else FALSE
|
|
*
|
|
***************************************************************/
|
|
|
|
BOOL FileExists (char *fn)
|
|
|
|
{
|
|
fileStruct *f;
|
|
|
|
if (file) {
|
|
f = file;
|
|
while (f) {
|
|
if (strcmp(fn, f->fName) == 0)
|
|
return TRUE;
|
|
f = f->fNext;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* FileName - extract the file name from a path name
|
|
*
|
|
* Inputs:
|
|
* f2 - path name
|
|
*
|
|
* Outputs:
|
|
* f1 - file name
|
|
*
|
|
***************************************************************/
|
|
|
|
void FileName (char *f1, char *f2)
|
|
|
|
{
|
|
int i,j;
|
|
char ch, sep;
|
|
|
|
sep = ':'; /* determine what the separator is */
|
|
i = 0;
|
|
while (ch = f2[i++])
|
|
if ((ch == '/') || (ch == ':')) {
|
|
sep = ch;
|
|
goto out;
|
|
}
|
|
out:
|
|
i = j = 0; /* scan for the last separator */
|
|
while (ch = f2[j++])
|
|
if (ch == sep)
|
|
i = j;
|
|
j = 0;
|
|
do { /* form the file name */
|
|
ch = f1[j] = toupper(f2[i]);
|
|
++j; ++i;
|
|
}
|
|
while (ch);
|
|
f1[j] = 0;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* FileNumber - find the number of a file
|
|
*
|
|
* Inputs:
|
|
* name - name of the file to find
|
|
*
|
|
* Returns:
|
|
* 0 if no file found, else file number
|
|
*
|
|
***************************************************************/
|
|
|
|
int FileNumber (char *name)
|
|
|
|
{
|
|
fileStruct *f;
|
|
int i;
|
|
char name2[MAXNAME];
|
|
|
|
if (file) {
|
|
f = file;
|
|
while (f) {
|
|
strcpy(name2, f->fName);
|
|
i = 0;
|
|
while (name2[i]) {
|
|
name2[i] = toupper(name2[i]);
|
|
++i;
|
|
}
|
|
if (! strcmp(name2, name))
|
|
return f->fFile;
|
|
f = f->fNext;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* AddObj - add an object module
|
|
*
|
|
* Inputs:
|
|
* segName - name of segment to add
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, else FALSE
|
|
*
|
|
***************************************************************/
|
|
|
|
BOOL AddObj (void)
|
|
|
|
{
|
|
char fn[MAXNAME];
|
|
fileStruct *f;
|
|
int fnum,err;
|
|
|
|
CheckESC(); /* check for early termination */
|
|
FileName(fn, *segName);
|
|
if (progress)
|
|
printf("Adding %s\n", fn);
|
|
if (FileExists(fn)) {
|
|
Error(1, -1, fn);
|
|
return FALSE;
|
|
}
|
|
if (GetFType(*segName) != 177) { /* make sure its an object module */
|
|
Error(3, -1, *segName); /* file is not a OBJ file */
|
|
return FALSE;
|
|
}
|
|
for (fnum = 1; fnum < 32767; ++fnum) { /* find an unused file number */
|
|
if (file) {
|
|
Spin();
|
|
f = file;
|
|
while (f) {
|
|
if (f->fFile == fnum)
|
|
goto next;
|
|
else
|
|
f = f->fNext;
|
|
}
|
|
}
|
|
goto out;
|
|
next:;
|
|
}
|
|
out: addFNum = fnum;
|
|
f = tmalloc(sizeof(fileStruct)); /* insert file into file name table */
|
|
f->fName = tmalloc(strlen(fn)+1);
|
|
strcpy(f->fName, fn);
|
|
f->fFile = fnum;
|
|
file = Insert(f, file);
|
|
|
|
if (inFile = fopen(*segName, "rb")) { /* add the segments to the file */
|
|
while ((err = AddSeg(fnum)) == 1)
|
|
Spin();
|
|
if (err == -1) {
|
|
printf("Removing %s from the dictionary.\n", fn);
|
|
file = Delete(fnum, file);
|
|
symbol = (symbolStruct *) Delete(fnum, (fileStruct *) symbol);
|
|
StopSpin();
|
|
return FALSE;
|
|
}
|
|
fclose(inFile);
|
|
}
|
|
else {
|
|
Error(4, -1, *segName); /* could not open file */
|
|
exit(-1);
|
|
}
|
|
objFile = NULL; CopyLib(0); /* copy old library segments */
|
|
StopSpin();
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* DeleteObj - delete an object module
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, else FALSE
|
|
*
|
|
***************************************************************/
|
|
|
|
BOOL DeleteObj (void)
|
|
|
|
{
|
|
char fn[MAXNAME];
|
|
int num;
|
|
|
|
addFNum = 0;
|
|
FileName(fn, *segName);
|
|
if (progress)
|
|
printf("Deleting %s\n", fn);
|
|
if (!(num = FileNumber(fn))) {
|
|
Error(8, -1, fn); /* object module is not in library */
|
|
StopSpin();
|
|
return FALSE;
|
|
}
|
|
objFile = NULL; CopyLib(num);
|
|
file = Delete(num, file);
|
|
symbol = (symbolStruct *) Delete(num, (fileStruct *) symbol);
|
|
StopSpin();
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* Destroy - delete a disk file
|
|
*
|
|
* Inputs:
|
|
* name - name of the file to delete
|
|
*
|
|
***************************************************************/
|
|
|
|
void Destroy (char *name)
|
|
|
|
{
|
|
NameRecGS dsRec; /* GS/OS record */
|
|
|
|
dsRec.pCount = 1;
|
|
dsRec.pathname = tmalloc(strlen(name)+3);
|
|
dsRec.pathname->length = strlen(name);
|
|
strcpy(dsRec.pathname->text, name);
|
|
DestroyGS((void *) &dsRec);
|
|
free(dsRec.pathname);
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* fput2 - write a two byte integer to a character file
|
|
*
|
|
* Inputs:
|
|
* val - value
|
|
* stream - file to write to
|
|
*
|
|
***************************************************************/
|
|
|
|
void fput2 (int val, FILE *stream)
|
|
|
|
{
|
|
fputc(val, stream);
|
|
fputc(val>>8, stream);
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* fput4 - write a four byte integer to a character file
|
|
*
|
|
* Inputs:
|
|
* val - value
|
|
* stream - file to write to
|
|
*
|
|
***************************************************************/
|
|
|
|
void fput4 (long val, FILE *stream)
|
|
|
|
{
|
|
fputc(val, stream); fputc(val>>8, stream);
|
|
fputc(val>>16, stream); fputc(val>>32, stream);
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* fputps - write a pascal stylestring to a character file
|
|
*
|
|
* Inputs:
|
|
* str - pointer to string
|
|
* stream - file to write to
|
|
*
|
|
***************************************************************/
|
|
|
|
void fputps (char *str, FILE *stream)
|
|
|
|
{
|
|
int i;
|
|
|
|
i = strlen(str);
|
|
fputc(i, stream);
|
|
while(*str)
|
|
fputc(*(str++), stream);
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* MakeWork - create the name of the work file
|
|
*
|
|
* Returns:
|
|
* Pointer to file name
|
|
*
|
|
***************************************************************/
|
|
|
|
char * MakeWork (void)
|
|
|
|
{
|
|
return "14/syslib";
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* SetInfo - set the file type and aux type
|
|
*
|
|
* Inputs:
|
|
* file - name of the file
|
|
* filetype - file type
|
|
* auxtype - aux type
|
|
*
|
|
***************************************************************/
|
|
|
|
void SetInfo (char *file, int filetype, long auxtype)
|
|
|
|
{
|
|
FileInfoRecGS giRec; /* GetFileInfo record */
|
|
|
|
giRec.pCount = 4;
|
|
giRec.pathname = tmalloc(strlen(file)+3);
|
|
giRec.pathname->length = strlen(file);
|
|
strcpy(giRec.pathname->text, file);
|
|
GetFileInfoGS((void *) &giRec);
|
|
giRec.fileType = filetype;
|
|
giRec.auxType = auxtype;
|
|
SetFileInfoGS((void *) &giRec);
|
|
free(giRec.pathname);
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* RemoveObj - remove an object module
|
|
*
|
|
* Inputs:
|
|
* segName - name of segment to remove
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, else FALSE
|
|
*
|
|
***************************************************************/
|
|
|
|
BOOL RemoveObj (void)
|
|
|
|
{
|
|
char fn[MAXNAME];
|
|
int num;
|
|
|
|
addFNum = 0;
|
|
FileName(fn, *segName);
|
|
if (progress)
|
|
printf("Extracting %s\n", fn);
|
|
if (!(num = FileNumber(fn))) {
|
|
Error(8, -1, fn); /* object file not in library */
|
|
return FALSE;
|
|
}
|
|
if (!(objFile = fopen(*segName,"wb"))) {
|
|
Error(14, -1, *segName); /* file could not be opened */
|
|
exit(-1);
|
|
}
|
|
SetInfo(*segName, 177, 0);
|
|
CopyLib(num);
|
|
fclose(objFile);
|
|
file = Delete(num, file);
|
|
symbol = (symbolStruct *) Delete(num, (fileStruct *) symbol);
|
|
StopSpin();
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* Update - update the library
|
|
*
|
|
* Inputs:
|
|
* outFile - file with all of the segments
|
|
* libName - name of the library
|
|
*
|
|
* Returns:
|
|
* TRUE if successful, else FALSE
|
|
*
|
|
***************************************************************/
|
|
|
|
BOOL Update (void)
|
|
|
|
{
|
|
char *name = "LIBRARY";
|
|
long filesize,symbolsize,namesize,len,disp,fslen;
|
|
fileStruct *fp;
|
|
symbolStruct *sp;
|
|
int i;
|
|
|
|
fclose(outFile); /* close the work file */
|
|
if (!(outFile = fopen(*libName,"wb"))) { /* open the library */
|
|
Error(15,-1,*libName); /* could not open the library */
|
|
exit(-1);
|
|
}
|
|
|
|
filesize = 0; /* compute length of file name table */
|
|
if (file) {
|
|
fp = file;
|
|
Spin();
|
|
while (fp) {
|
|
filesize += 3+strlen(fp->fName);
|
|
fp = fp->fNext;
|
|
}
|
|
}
|
|
symbolsize = namesize = 0; /* compute length of symbols & names */
|
|
if (symbol) {
|
|
sp = symbol;
|
|
Spin();
|
|
while (sp) {
|
|
namesize += 1+strlen(sp->sName);
|
|
symbolsize += 12;
|
|
sp = sp->sNext;
|
|
}
|
|
}
|
|
/* write the header */
|
|
fslen = 71+strlen(name)+namesize+symbolsize+filesize;
|
|
fput4(fslen, outFile); /* BLKCNT */
|
|
for (i = 0; i < 8; ++i) /* RESSPC,LENGTH */
|
|
fputc(0, outFile);
|
|
fputc(0, outFile); /* UNDEFINED */
|
|
fputc(0, outFile); /* LABLEN */
|
|
fputc(4, outFile); /* NUMLEN */
|
|
fputc(2, outFile); /* VERSION */
|
|
fput4(0, outFile); /* BANKSIZE */
|
|
fput2(8, outFile); /* KIND */
|
|
fput2(0, outFile); /* UNDEFINED */
|
|
fput4(0, outFile); /* ORG */
|
|
fput4(0, outFile); /* ALIGN */
|
|
fput4(0, outFile); /* NUMSEX, SEGNUM */
|
|
fput4(0, outFile); /* ENTRY */
|
|
fputc(44, outFile); fputc(0, outFile); /* DISPNAME */
|
|
i = 44+11+strlen(name); /* DISPDATA */
|
|
fput2(i, outFile);
|
|
for (i = 0; i < 10; ++i) /* LOADNAME */
|
|
fputc(0, outFile);
|
|
fputps(name, outFile); /* SEGNAME */
|
|
|
|
fputc(242, outFile); /* write the file names */
|
|
fput4(filesize, outFile);
|
|
if (file) {
|
|
fp = file;
|
|
while (fp) {
|
|
Spin();
|
|
fput2(fp->fFile, outFile);
|
|
fputps(fp->fName, outFile);
|
|
fp = fp->fNext;
|
|
}
|
|
}
|
|
fputc(242, outFile); /* write symbol table */
|
|
fput4(symbolsize, outFile);
|
|
if (symbol) {
|
|
disp = 0;
|
|
sp = symbol;
|
|
while (sp) {
|
|
Spin();
|
|
fput4(disp, outFile);
|
|
fput2(sp->sFile, outFile);
|
|
fput2(sp->sPrivate, outFile);
|
|
sp->sSeg = sp->sSeg+fslen;
|
|
fput4(sp->sSeg, outFile);
|
|
disp += strlen(sp->sName)+1;
|
|
sp = sp->sNext;
|
|
}
|
|
}
|
|
fputc(242, outFile); /* write the name table */
|
|
fput4(namesize, outFile);
|
|
if (symbol) {
|
|
sp = symbol;
|
|
while (sp) {
|
|
Spin();
|
|
fputps(sp->sName, outFile);
|
|
sp = sp->sNext;
|
|
}
|
|
}
|
|
fputc(0, outFile); /* end of segment marker */
|
|
|
|
inFile = fopen(MakeWork(),"rb"); /* copy work file segments to output */
|
|
len = GetDiskSeg(FALSE);
|
|
while (len != 0) {
|
|
Spin();
|
|
fwrite(s, 1, len, outFile);
|
|
len = GetDiskSeg(FALSE);
|
|
}
|
|
fclose(outFile); /* close files */
|
|
fclose(inFile);
|
|
SetInfo(*libName, 178, 0); /* set file type of library file */
|
|
Destroy(MakeWork()); /* get rid of the work file */
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* WriteDictionary - write the symbol table
|
|
*
|
|
* Inputs:
|
|
* symbol - pointer to top of symbol table
|
|
*
|
|
***************************************************************/
|
|
|
|
void WriteDictionary (void)
|
|
|
|
{
|
|
symbolStruct *f;
|
|
|
|
if (printDictionary) {
|
|
if (symbol) {
|
|
printf("\nSymbols in library:\n"
|
|
" file disp in private symbol\n"
|
|
" number segment flag name\n"
|
|
" ------ ------- ------- ------\n");
|
|
f = symbol;
|
|
while (f) {
|
|
printf("%14d%11ld ", f->sFile, f->sSeg);
|
|
if (f->sPrivate)
|
|
printf("true ");
|
|
else
|
|
printf("false ");
|
|
printf("%s\n", f->sName);
|
|
f = f->sNext;
|
|
CheckESC();
|
|
}
|
|
}
|
|
putchar('\n');
|
|
}
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* WriteFiles - write the file name table
|
|
*
|
|
* Inputs:
|
|
* file - pointer to top of files list
|
|
*
|
|
***************************************************************/
|
|
|
|
void WriteFiles (void)
|
|
|
|
{
|
|
fileStruct *f;
|
|
|
|
if (printFiles) {
|
|
if (file) {
|
|
printf("\nFiles in library:\n"
|
|
" number name\n"
|
|
" ------ ----\n");
|
|
f = file;
|
|
while (f) {
|
|
printf("%12d %s\n", f->fFile, f->fName);
|
|
f = f->fNext;
|
|
CheckESC();
|
|
}
|
|
}
|
|
putchar('\n');
|
|
}
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* MakeLib - Create the library file
|
|
*
|
|
* Inputs:
|
|
* inFile - input file
|
|
*
|
|
***************************************************************/
|
|
|
|
void MakeLib (void)
|
|
|
|
{
|
|
while (segFlag) {
|
|
if (!(outFile = fopen(MakeWork(),"wb"))) {
|
|
Error(11,-1,MakeWork()); /* could not open the work file */
|
|
exit(-1);
|
|
}
|
|
if (segFlag == '+') {
|
|
if (!AddObj()) break;
|
|
}
|
|
else if (segFlag == '-') {
|
|
if (!DeleteObj()) break;
|
|
}
|
|
else if (segFlag == '^') {
|
|
if (!RemoveObj()) break;
|
|
}
|
|
else {
|
|
Error(12,-1,*segName); /* illegal operation */
|
|
exit(-1);
|
|
}
|
|
Update();
|
|
StopSpin();
|
|
GetSegment();
|
|
}
|
|
WriteFiles();
|
|
WriteDictionary();
|
|
fclose(outFile); /* close the work file files */
|
|
}
|
|
|
|
/***************************************************************
|
|
*
|
|
* main - main program
|
|
*
|
|
***************************************************************/
|
|
|
|
int main (int argc, char *argv[])
|
|
|
|
{
|
|
largc = argc; /* save the command line values */
|
|
largv = argv;
|
|
if (Init()) /* initialize the program */
|
|
MakeLib(); /* do the work */
|
|
exit(status); /* return the results */
|
|
}
|