home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
oxcc1433.zip
/
SRC
/
SKELETON.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-06
|
54KB
|
2,319 lines
/* SKELETON.C -- THE PROTOTYPE APPLICATION FOR THE OXBOW FRAMEWORK
COMPILE WITH GCC
COPYRIGHT 1994 Norman D. Culver, Ft. Lauderdale, FL
NOTE: 'main()' is at the end of the file.
*/
#define SYMLINK(from,to) badsyms += oxlink_symlink(#from,#to)
#define EARLY_PRINT 1 /* set to 1 if trace before linkup needed */
#define BASE_CATEGORY 0
#define MEMORY_BUG 0
#define PRINT_RAWDATA 0
#if 0
#define DPRINTF lprintf
#else
#define DPRINTF(args...)
#endif
#if 0
#define MPRINTF lprintf
#else
#define MPRINTF(args...)
#endif
#if EARLY_PRINT == 1
#define TPRINTF lprintf
#else
#define TPRINTF VPRINTF
#endif
#include <go32.h>
/* extracts from 'oxbow.h' */
typedef unsigned long long KeyItem; /* type for a key's associated item */
typedef union /* 2 BYTES */
{
unsigned short val;
unsigned char b[2];
} SVAL;
typedef union /* 4 BYTES */
{
unsigned long a0;
void *a1;
struct
{
SVAL lo_word;
SVAL hi_word;
} a2;
struct
{
unsigned int pad :28;
unsigned int type :4;
} a3;
struct
{
unsigned char b[4];
} a4;
int a8;
short a9;
char a10;
float a11;
} ADDR;
typedef union _stor /* 8 BYTES */
{
unsigned long a0;
void *a1;
KeyItem item;
struct
{
unsigned short lo_word;
unsigned short hi_word;
unsigned int size :28; /* in bytes or nibbles */
unsigned int type :4; /* describes the STOR type */
} a2;
struct
{
short s0;
short s1;
short s2;
short s3;
} a3;
struct
{
unsigned long s0;
unsigned long s1;
} a4;
struct
{
unsigned char b[8];
} a5;
struct
{
unsigned long long dupname :48;
unsigned long long dupid :16;
} a6;
struct
{
unsigned int home : 30;
unsigned int full : 2;
} a7;
int a8;
short a9;
char a10;
float a11;
double a12;
} STOR, Item;
typedef struct /* 12 BYTES */
{
STOR c0;
ADDR c1;
} CAT;
#define OB_XFILE (0x00004000)
#define OB_ROOTDIR (0x00000200)
#define OB_TREEDIR (0x10000000)
#define OB_HASHDIR (0x20000000)
#define F_RDONLY (0x0001)
#define F_STAT (0x20000) /* TRULY READONLY */
#define O_RDONLY (0x0001)
#define O_BINARY (0x8000)
#define R_CLEAN (0x40000000)
#undef NULL
#define NULL ((void *)0)
#define FOUND (1)
#define NODUPS (0)
#define S_SET (0)
#define S_READBLK (1)
#define S_WRITEBLK (2)
#define _cat2_(a, b) a##b
#define _cat_(a, b) _cat2_(a, b)
#define _qt2_(x) #x
#define _qt_(x) _qt2_(x)
#define oxfunc(func, args...) ({ \
typedef _fret = (appfunc()); \
_fret (*dofunc)(); _fret _ret; \
dofunc = oxlink_load_bare_symb(func,1); \
if(dofunc) _ret = dofunc(## args) & 0x0fffffff; \
else _ret = (_fret) -1; \
_ret;})
#define oxload(func) \
oxlink_load_bare_symb(_qt_(_cat_(_, func)),1)
#define oxunload(func) \
oxlink_unload_symb(#func, 1)
typedef int jmp_buf[32]; /* an adequate buffer for setjmp */
int setjmp();
void longjmp();
/* end: extracts from 'oxbow.h' */
/* ==================== A LIST OF PROBLEMS ======================= */
/* external function prototypes needed initially,
THESE NEED TO BE LOCALIZED */
void *sbrk();
int open();
int creat();
int close();
int read();
int write();
int lseek();
char *getenv();
char *getwd();
int strlen();
char *strdup();
char *strcat();
char *strcpy();
char *strchr();
char *strrchr();
char *strstr();
int _strcpy();
long strtol();
int strcmp(const char *, const char *);
int strncmp();
void CF_Interactive_IO();
int appfunc();
void *malloc(unsigned);
void *calloc(unsigned, unsigned);
void free(void*);
void *memcpy();
/* external function prototypes needed by the portability modules
THESE TOO NEED TO BE LOCALIZED (or something) */
void exit();
int ftruncate();
void abort();
/* internal function prototypes */
static int lnulfunc();
static void lhash(void *, int, CAT *);
static int laccess(char *, int);
static int lpagesize(void);
static int lprintchar(int);
static void lprintstr(char *);
static void lcrash(char *, ...);
void CF_InitIO(long arg, long long (*msgproc)());
/* ======================== END LIST OF PROBLEMS ==================== */
/* DYNAMIC LINKER FUNCTIONS */
int oxlink_init (); /* initialize the routines */
int oxlink_load_file (); /* dynamically link and load an object file */
int oxlink_load_object (); /* link object file from libraries in list */
void *oxlink_find_func (); /* return the address of the named function */
void *oxlink_find_bare_func ();/* same as oxlink_find_func except that
no underscore (_) is prepended (also faster). */
void * oxlink_find_sym (); /* return the address of the named identifier */
void *oxlink_find_bare_symb ();/* same as oxlink_find_symb except that
no underscore (_) is prepended (also faster). */
int oxlink_unload_file (); /* unlink a file */
int oxlink_unload_symb (); /* unlink the module that defines the given symbol */
int oxlink_unload_bare_symb (); /* unlink the module that defines the given symbol */
char **oxlink_list_undefined_symb ();/* return an array of undefined symbols */
char *cf_find_file ();/* return the full path name of the given file. */
void *oxlink_load_symb(char *symb, int dynlink);
void *oxlink_load_bare_symb(char *symb, int dynlink);
int oxlink_export_symb();
int oxlink_export_bare_symb();
void oxlink_unexport_symb();
void oxlink_unexport_bare_symb();
int oxlink_symlink(); /* give new symbol same values as old symbol */
void oxlink_demand_load(); /* define all undefined symbols with negative numbers */
void oxlink_use_library(); /* add a filename for undefined symbol search */
void oxlink_nouse_library(); /* remove a library from the search list */
void *oxlink_resolve_symb(); /* resolve one of the demand loadable undefs */
void oxlink_trace(); /* set the trace level */
char *oxlink_symname(); /* return name of a demand loadable undef */
void *oxlink_rename_symb(char *old,char *new);
int oxlink_rename_file(char *old,char *new);
void oxlink_lib_check(int dynlink); /* force search of library list */
char *oxlink_file_of(char *symb);
char *oxlink_file_of_bare(char *symb);
int oxlink_scan_file(void *fhandle, void *thandle);
void oxlink_set_libtype(int type);
void oxlink_set_libnum(int libnum);
void oxlink_load_thunk(int thunknum);
int oxlink_prep_thunk(char *symb);
void oxlink_clear_bss(char *filename);
void *oxlink_get_entry_struct(char *filename);
char *oxlink_errstr(void);
/* virtual function pointers initially hard linked to the load module */
/* needed in order to initialize and read a .o or .a file */
int (*VCFREAD)() = read;
int (*VCFWRITE)() = write;
void *(*VCFOPEN)() = (void *)open;
int (*VCFCLOSE)() = close;
int (*VCFLSEEK)() = lseek;
int (*VACCESS)() = laccess;
void *(*VSBRK)() = sbrk;
char *(*VGETENV)() = getenv;
char *(*VGETCWD)() = getwd;
int (*VOBTYPE)() = lnulfunc;
void (*VHASH)() = lhash;
int (*VGETPAGESIZE)() = lpagesize;
#if EARLY_PRINT == 0
int (*VVPRINTF)() = lnulfunc;
int (*VSPRINTF)() = lnulfunc;
int (*VPRINTF)() = lnulfunc;
int (*BUGPRINTF)() = lnulfunc;
#else
static int lvprintf(char *, void *);
static int lsprintf(char *, char *, ...);
static int lprintf(char *, ...);
int (*VVPRINTF)(char *, void*) = lvprintf;
int (*VSPRINTF)(char *, char *, ...) = lsprintf;
int (*VPRINTF)(char *, ...) = lprintf;
int (*BUGPRINTF)(char *, ...) = lprintf;
#endif
/* function pointers needed by portability modules */
void *(*VMALLOC)() = malloc;
void *(*VCALLOC)() = calloc;
void (*VFREE)() = free;
void (*VEXIT)() = exit;
int (*VREAD)() = read;
int (*VOPEN)() = open;
int (*VCLOSE)() = close;
int (*VLSEEK)() = lseek;
int (*VWRITE)() = write;
void (*VABORT)() = abort;
int (*VPRINTCHAR)() = lprintchar;
void (*VPRINTSTR)() = lprintstr;
void (*VCRASH)(char* fmt, ...) = lcrash;
void (*VBITBLT)();
int (*VSTAT)() = lnulfunc;
/* function pointers used internally */
int (*CFINIT)();
void (*CFEXIT)();
int (*COSINIT)();
void (*THREADER)();
void (*THREAD)();
int *VINHIBIT_THREADER;
/* cff function pointers used but not available until cff is loaded */
int (*VPUSH_VALUE)();
int (*VPUSH_DATA)();
int (*VFIND)();
int (*VGET)();
void *(*VSUBOPEN)();
int (*VPUT)();
int (*VFILESIZE)();
void *(*VOPEN_CHUNK)();
void *(*VLOCALIZE)();
int (*VRELEASE)();
void **VMEMTEMP;
/* function pointers used by the COS threader but not available until
the message class is loaded */
int (*VWASMSG)() = lnulfunc;
int (*VDISPATCHMSG)() = lnulfunc;
/* Global variables, here to suppress re-linking */
long long (*VAPPMSG)();
void *Application;
int numTextModes;
int numGraphicModes;
void *TextModes;
void *GraphicModes;
int GuiEnabled;
int _SCREENXMAX;
int _SCREENYMAX;
int _REMOTEFD;
int _SCREENHEIGHT;
int _EFFECTIVE_SCREENHEIGHT;
int _SCREENWIDTH;
int _EFFECTIVE_SCREENWIDTH;
int _GLOBALWIDTH;
int _GLOBALHEIGHT;
int _CURCOLS;
int _CURROWS;
int _FONTWIDTH;
int _FONTHEIGHT;
int _CHARWIDTH;
int _LINEHEIGHT;
int _GRIDWIDTH;
int _GRIDHEIGHT;
int _GLOBALX;
int _GLOBALY;
int _MAXROWS;
int _MAXCOLS;
int _VIDEOMODE;
int _LOOK;
int _FEEL;
/* variables needed by the cos threader */
int _no_context_switch = 1;
jmp_buf _t_start;
/* application initializer word */
long AppArg;
/* flag used to force early symbols to be permanent */
static int permanent_symbols;
static char path_sep;
/* ================ START OF INTERNAL SUPPORT FUNCTIONS ============ */
/* ========================= MULTI HEAP MALLOC ========================== */
/*
NOTE: In a demand paged environment, this implementation of malloc
(using skip_lists) can be ENORMOUSLY faster than buddy_block
style mallocs.
*/
void *mallocC(int category, unsigned amount);
void *callocC(int category, unsigned nelems, unsigned elemsize);
void *reallocC(int category, void* buf, unsigned newsize);
void freeC(int category, void* buf);
void freecat(int category);
int memrangeC(int category, unsigned* minp, unsigned* maxp);
int usedrangeC(int category, unsigned* minp, unsigned* maxp);
void totrangeC(unsigned* minp,unsigned* maxp);
void *heapcheckC(int category, void *start);
void guardC(int category);
void *memalignC(int category, unsigned alignment, unsigned req);
#define PAGESIZE VGETPAGESIZE()
#define ALIGNMENTM (sizeof(unsigned long))
#define MAL_MAXLEVEL (12)
#define ROUNDINGM(a) ((ALIGNMENTM-(a&(ALIGNMENTM-1)))&(ALIGNMENTM-1))
#define ALLOCSIZE (4096)
#define FRNTGUARD (0x544e5246UL)
#define BACKGUARD (0x48434142UL)
#define THEWELL do_sbrk
#define NUMTYPES 3
#define SIZEH 0
#define FREEH 1
#define USEDH 2
#define SKIPVARS NodePM update[MAL_MAXLEVEL+1];NodePM node,prev;int level
#define DELETENODE(TYPE) \
{for(level=0;level<=bp->TYPE##level; level++)\
{if(update[level]->fptr[level] == node)\
update[level]->fptr[level] = node->fptr[level];else break;}\
while(bp->TYPE##level>0 && bp->TYPE##header->fptr[bp->TYPE##level]==_NILLL)\
bp->TYPE##level--;free_Mnode(bp,node,TYPE);}
#define INSERT() \
{while(level >= 0){\
node->fptr[level] = update[level]->fptr[level];\
update[level]->fptr[level] = node;level--;}}
#define SETLEVEL(TYPE) \
{level = getMlevel(bp, bp->TYPE##level);\
while(bp->TYPE##level < level)update[++bp->TYPE##level]=bp->TYPE##header;}
#define FINDKEY(TYPE, KEYVAL)\
{node = bp->TYPE##header;\
for(level = bp->TYPE##level; level >= 0; level--){\
while(node->fptr[level]->key < KEYVAL)\
node = node->fptr[level];\
update[level] = node;}prev=node;node=node->fptr[0];}
#define DETACH(SN)\
{SN->bptr->fptr=SN->fptr;if(SN->fptr)SN->fptr->bptr=SN->bptr;}
#define UNLINK(SN, N)\
{if(!sp->fptr&&sp->bptr->bptr<=(AddrP)(MAL_MAXLEVEL+1))dsize[N]=sp->size;\
DETACH(SN);free_addr(bp,SN);}
#define CHECKGUARDS(MSG)\
{if(bp->guarded){\
unsigned *p2;\
p2 = (void*)((char*)address+cursize-ALIGNMENTM);\
if(*address != FRNTGUARD)\
VCRASH(#MSG ":%d: corrupted at 0x%x\n", bp->bincat, addr);\
if(*p2 != BACKGUARD)\
VCRASH(#MSG ":%d: corrupted by 0x%x\n", bp->bincat, addr);}}
#if MEMORY_BUG == 1
#define HEAPCHECK \
{void *lastaddr;\
if(category > 0){\
guardC(category);\
if((lastaddr = heapcheckC(category, NULL))){\
FINDKEY(USEDH, (unsigned)lastaddr-ALIGNMENTM)\
BUGPRINTF("bad heap at %x c:%u size=%u\n", lastaddr, category, node->value);\
(void)print_rawdata(lastaddr-ALIGNMENTM, node->value);\
VABORT();}}}
#else
#define HEAPCHECK
#endif
struct _catlocs {
void *addr;
struct _catlocs *fptr;
};
typedef struct _nodeM
{
unsigned key;
unsigned value;
unsigned levels; /* must always be after value */
struct _nodeM *fptr[1];
} NodeM, *NodePM;
typedef struct _addr
{
struct _addr *fptr;
struct _addr *bptr;
NodePM maddr;
unsigned size;
} *AddrP;
struct _bins {
unsigned bits;
unsigned nbits;
NodePM SIZEHheader;
int SIZEHlevel;
NodePM FREEHheader;
int FREEHlevel;
NodePM USEDHheader;
int USEDHlevel;
unsigned bincat;
unsigned maxloc;
unsigned minloc;
struct _catlocs *catlocs;
struct _bins *fptr;
NodePM freenodes[NUMTYPES][MAL_MAXLEVEL+2];
struct _addr *freeaddrlocs;
char *chunkbase[NUMTYPES];
int chunksize[NUMTYPES];
int guarded;
int addrbump;
};
static struct _bins zbp;
static struct _bins *hmap[1009];
static struct _nodeM _nilll = {0xffffffff,0,0,{0}};
static struct _nodeM *_NILLL = &_nilll;
static unsigned maxloc;
static unsigned minloc;
static struct _bins *freebinlocs;
static struct _catlocs *freecatlocs;
static char *binbase;
static int binsize;
static int chunksizes[] = {ALLOCSIZE,3*ALLOCSIZE,2*ALLOCSIZE};
static long randtbl[32] = { 0L,
0x9a319039L, 0x32d9c024L, 0x9b663182L, 0x5da1f342L,
0xde3b81e0L, 0xdf0a6fb5L, 0xf103bc02L, 0x48f340fbL,
0x7449e56bL, 0xbeb1dbb0L, 0xab5c5918L, 0x946554fdL,
0x8c2e680fL, 0xeb3d799fL, 0xb11ee0b7L, 0x2d436b86L,
0xda672e2aL, 0x1588ca88L, 0xe369735dL, 0x904f35f7L,
0xd7158fd6L, 0x6fa6f051L, 0x616e6b96L, 0xac94efdcL,
0x36413f93L, 0xc622c298L, 0xf5a42ab8L, 0x8a88d77bL,
0xf5ad9d0eL, 0x8999220bL, 0x27fb47b9L
};
static long *fptr = &randtbl[4];
static long *rptr = &randtbl[1];
/* ================== THE CRASH FUNCTION IS FIRST IN .TEXT ================ */
static void
lcrash(char *msg, ...)
{
VVPRINTF(msg, &msg+1);
/* CFEXIT();*/
*((char *)0) = 0; /* force exception */
}
#if PRINT_RAWDATA == 1
static char
hexbyte(unsigned int c)
{
char x = c & 0xf;
return x + ((x>9) ? 55 : 48);
}
static void
print_rawdata(void *rawdata, long size)
{
unsigned long vaddr = 0;
unsigned char *d = rawdata;
int i,j;
char addr[9];
char hex1[24];
char hex2[24];
char side1[9];
char side2[9];
addr[8] = 0;
hex1[23] = 0;
hex2[23] = 0;
side1[8] = 0;
side2[8] = 0;
while(size > 0)
{
unsigned long qaddr = vaddr;
memset(addr, '0', 8);
memset(hex1, ' ', 23);
memset(hex2, ' ', 23);
memset(side1, ' ', 8);
memset(side2, ' ', 8);
i = 7;
while(qaddr)
{
addr[i--] = hexbyte(qaddr);
qaddr >>= 4;
}
for(i=0,j=0; i < 8; ++i)
{
if(--size >= 0)
{
unsigned int c = *d++;
if(isprint(c))
side1[i] = c;
else
side1[i] = '.';
hex1[j++] = hexbyte(c>>4);
hex1[j++] = hexbyte(c);
++j;
}
else break;
}
for(i=0,j=0; i < 8; ++i)
{
if(--size >= 0)
{
unsigned int c = *d++;
if(isprint(c))
side2[i] = c;
else
side2[i] = '.';
hex2[j++] = hexbyte(c>>4);
hex2[j++] = hexbyte(c);
++j;
}
else break;
}
BUGPRINTF("%s %s%s%s %s%s%s\n",addr,hex1," | ",hex2,side1,"|",side2);
vaddr += 16;
}
}
#endif
/*
* Returns a really good 31-bit random number.
*/
static long
lrandom()
{
long i;
*fptr += *rptr;
i = (*fptr >> 1) & 0x7fffffffUL;
if(++fptr > &randtbl[31])
{
fptr = &randtbl[1];
++rptr;
}
else
{
if(++rptr > &randtbl[31])
rptr = &randtbl[1];
}
return( i );
}
static void *
do_sbrk(unsigned amount)
{
void *address;
address = VSBRK(amount); /* OR WHATEVER TO ACCESS THE OPERATING SYSTEM */
if(address == (void*)-1)
{
VCRASH("\nskel: system out of memory, requested %u bytes\n", amount);
}
return address;
}
static struct _catlocs *
new_catloc(void)
{
struct _catlocs *p;
if((p=freecatlocs))
{
freecatlocs = p->fptr;
return p;
}
if(binsize < sizeof(struct _catlocs))
{
binbase = THEWELL(4096);
binsize = 4096;
MPRINTF("NEWCATLOC at:%p size=4096\n", binbase);
}
binsize -= sizeof(struct _catlocs);
p = (void*)binbase;
binbase += sizeof(struct _catlocs);
return p;
}
static void
free_catloc(struct _catlocs *p)
{
p->fptr = freecatlocs;
freecatlocs = p;
}
static void *
new_chunk(struct _bins *bp, int size, int type)
{
char *p;
if(bp->chunksize[type] < size)
{
if(bp->bincat == 0) {
bp->chunkbase[type] = THEWELL(chunksizes[type]);
bp->chunksize[type] = chunksizes[type];
MPRINTF("NEWCHUNK0 at:%p size=%d\n", bp->chunkbase[type], bp->chunksize[type]);
}
else {
struct _catlocs *cl;
bp->chunkbase[type] = mallocC(0,chunksizes[type]-zbp.guarded);
bp->chunksize[type] = chunksizes[type]-zbp.guarded;
cl = new_catloc();
cl->addr = bp->chunkbase[type];
cl->fptr = bp->catlocs;
bp->catlocs = cl;
MPRINTF("NEWCHUNK%d at:%p size=%d\n", bp->bincat, bp->chunkbase[type], bp->chunksize[type]);
}
}
bp->chunksize[type] -= size;
p = bp->chunkbase[type];
bp->chunkbase[type] += size;
return p;
}
static void *
new_Mnode(struct _bins *bp, int levels, int type)
{
int size;
NodePM p;
if((p=bp->freenodes[type][levels]))
{
bp->freenodes[type][levels] = p->fptr[0];
p->value = 0;
return p;
}
size = sizeof(struct _nodeM) + levels * sizeof(void*);
p = new_chunk(bp, size, type);
p->levels = levels;
p->value = 0;
return p;
}
static void
free_Mnode(struct _bins *bp, NodePM p, int type)
{
p->fptr[0] = bp->freenodes[type][p->levels];
bp->freenodes[type][p->levels] = p;
}
static struct _addr *
new_addr(struct _bins *bp)
{
struct _addr *p;
if((p=bp->freeaddrlocs))
{
bp->freeaddrlocs = p->fptr;
return p;
}
return new_chunk(bp, sizeof(struct _addr), FREEH);
}
static void
free_addr(struct _bins *bp, struct _addr *p)
{
p->fptr = bp->freeaddrlocs;
bp->freeaddrlocs = p;
}
static struct _bins *
new_bins(void)
{
struct _bins *p;
if((p=freebinlocs))
{
freebinlocs = p->fptr;
return p;
}
if(binsize < sizeof(struct _bins))
{
binbase = THEWELL(4096);
binsize = 4096;
MPRINTF("NEWBINS at:%p size=4096\n", binbase);
}
binsize -= sizeof(struct _bins);
p = (struct _bins*)binbase;
binbase += sizeof(struct _bins);
return p;
}
static void
free_bins(struct _bins *p)
{
p->fptr = freebinlocs;
freebinlocs = p;
}
static int
getMlevel (struct _bins *p, int binlevel)
{
int level = -1;
int bits = 0;
while(bits == 0)
{
if (p->nbits == 0)
{
p->bits = lrandom();
p->nbits = 15;
}
bits = p->bits & 3;
p->bits >>= 2;
p->nbits--;
if(++level > binlevel)
break;
}
return (level > MAL_MAXLEVEL) ? MAL_MAXLEVEL : level;
}
static void
init_bins(struct _bins *bp, int category)
{
int i;
int binnum = category % 1009;
bzero(bp, sizeof(struct _bins));
bp->bincat = category;
bp->minloc = 0xffffffff;
bp->fptr = hmap[binnum];
hmap[binnum] = bp;
bp->SIZEHheader = new_Mnode(bp, MAL_MAXLEVEL+1, SIZEH);
bp->FREEHheader = new_Mnode(bp, MAL_MAXLEVEL+1, FREEH);
bp->USEDHheader = new_Mnode(bp, MAL_MAXLEVEL+1, USEDH);
for(i = 0; i <= MAL_MAXLEVEL; ++i)
{
bp->SIZEHheader->fptr[i] = _NILLL;
bp->FREEHheader->fptr[i] = _NILLL;
bp->USEDHheader->fptr[i] = _NILLL;
}
}
static struct _bins*
getcat(int category)
{
struct _bins *hbp;
hbp = hmap[category % 1009];
while(hbp)
{
if(hbp->bincat == category)
return hbp;
hbp = hbp->fptr;
}
return 0;
}
static struct _bins *
initcat(int category)
{
struct _bins *bp;
if(category == 0)
{
bp = &zbp;
if(zbp.SIZEHheader == 0)
init_bins(bp, category);
return bp;
}
/* do this to set zbp.guarded properly on startup */
if(zbp.SIZEHheader == 0)
initcat(0);
if((bp = new_bins()))
{
init_bins(bp, category);
return bp;
}
return 0;
}
static void *
getspace(struct _bins *bp, unsigned size, unsigned *remainder)
{
unsigned desired;
void *address;
desired = ((size+ALLOCSIZE-1)/ALLOCSIZE)*ALLOCSIZE;
if(bp->bincat == 0)
{
address = THEWELL(desired);
*remainder = desired - size;
MPRINTF("GETSPACE at:%p size=%d\n", address, desired);
}
else
{
struct _catlocs *cl;
if((desired-size) > zbp.guarded)
desired -= zbp.guarded;
address = mallocC(0, desired);
*remainder = desired - size;
/* save the gross allocations for the category */
cl = new_catloc();
cl->addr = address;
cl->fptr = bp->catlocs;
bp->catlocs = cl;
}
/* maintain address range info */
if((unsigned)address < bp->minloc)
bp->minloc = (unsigned)address;
if(((unsigned)address + desired) > bp->maxloc)
bp->maxloc = (unsigned)address + desired;
if(bp->minloc < minloc)
minloc = bp->minloc;
if(bp->maxloc > maxloc)
maxloc = bp->maxloc;
return address;
}
static void
addto_sizelist(struct _bins *bp, AddrP ap)
{
SKIPVARS;
/* INSERT IN SIZE LIST */
FINDKEY(SIZEH, ap->size)
if(node->key == ap->size)
{/* size node exists */
ap->fptr = (AddrP)node->value;
ap->bptr = (AddrP)&node->value;
if(ap->fptr) ap->fptr->bptr = ap;
node->value = (unsigned)ap;
}
else
{/* create new size node */
SETLEVEL(SIZEH)
node = new_Mnode(bp, level, SIZEH);
node->key = ap->size;
node->value = (unsigned)ap;
ap->fptr = 0;
ap->bptr = (AddrP)&node->value;
INSERT()
}
}
static void
addto_freelist(struct _bins *bp, void *addr, unsigned size)
{
SKIPVARS;
AddrP ap,sp;
unsigned dsize[2];
/* GET NEW ADDR STRUCT */
ap = new_addr(bp);
ap->size = size;
dsize[1] = dsize[0] = 0; /* sizenode deletion markers */
/* CHECK FREE LIST */
FINDKEY(FREEH, (unsigned)addr)
/* CHECK FOR MERGE OR INSERT */
if(prev->value && prev->key+((AddrP)prev->value)->size == (unsigned)addr)
{/* merge with previous block */
ap->size += ((AddrP)prev->value)->size;
if(prev->key + ap->size == node->key)
{/* merge with previous and next block */
sp = (AddrP) node->value;;
ap->size += sp->size;
/* delete size struct for next block */
UNLINK(sp, 0)
/* delete next block */
DELETENODE(FREEH);
}
/* delete size struct for prev block */
sp = (AddrP)prev->value;
UNLINK(sp, 1)
/* set new address struct */
prev->value = (unsigned)ap;
ap->maddr = prev;
}
else if(node->value && (char*)addr + size == (void*)node->key)
{/* merge with next block */
sp = (AddrP) node->value;;
node->key = (unsigned)addr;
ap->size += sp->size;
/* unlink size struct for next block */
UNLINK(sp,0)
/* set new address struct */
node->value = (unsigned)ap;
ap->maddr = node;
}
else
{/* insert in free list */
SETLEVEL(FREEH)
node = new_Mnode(bp, level, FREEH);
node->key = (unsigned)addr;
node->value = (unsigned)ap;
ap->maddr = node;
INSERT()
}
addto_sizelist(bp, ap);
/* Remove sizenodes eliminated by merge */
if(dsize[0])
{
FINDKEY(SIZEH, dsize[0])
if(node->value == 0)
DELETENODE(SIZEH)
}
if(dsize[1])
{
FINDKEY(SIZEH, dsize[1])
if(node->value == 0)
DELETENODE(SIZEH)
}
}
void*
memalignC(int category, unsigned alignment, unsigned req)
{
SKIPVARS;
NodePM fnode;
unsigned remainder;
unsigned *address;
struct _bins *bp;
unsigned mask, size;
if(!(bp = getcat(category)))
if(!(bp = initcat(category)))
return 0;
HEAPCHECK
if(req == 0)
req = ALIGNMENTM;
else
req += ROUNDINGM(req);
size = req += bp->guarded;
if(alignment)
{
alignment += ROUNDINGM(alignment);
if(alignment > ALIGNMENTM)
{
mask = alignment -1;
size = req + alignment + bp->guarded;
}
else
{
alignment = 0;
}
}
/* check sizelist for candidate */
FINDKEY(SIZEH, size)
fnode = node;
trynext:
if(node->key != 0xffffffff)
{/* found an appropriately sized block */
AddrP sp = (AddrP)node->value;
if(!sp && node == fnode)
{
NodePM q;
q = node->fptr[0];
DELETENODE(SIZEH)
node = q;
goto trynext;
}
if(!sp)
{/* no available space at this size */
node = node->fptr[0];
goto trynext;
}
/* extract some space from this block */
remainder = node->key - size;
address = (void*)sp->maddr->key;
sp->maddr->key += size;
DETACH(sp);
if(node->value == 0)
{/* no more blocks of this size, delete sizenode */
if(node != fnode)
FINDKEY(SIZEH, size)
DELETENODE(SIZEH)
}
if(remainder == 0)
{/* no remaining space,the node in freelist is exhausted, delete it */
FINDKEY(FREEH, sp->maddr->key)
DELETENODE(FREEH)
free_addr(bp, sp);
}
else
{/* space remains in block, move it to new size loc */
sp->size = remainder;
addto_sizelist(bp, sp);
}
}
else
{
address = getspace(bp, size, &remainder);
if(remainder)
addto_freelist(bp, ((char*)address)+size, remainder);
}
if(alignment)
{
unsigned diff;
if((diff = (unsigned)address & mask))
{/* move address forward */
char *naddress;
unsigned lose;
lose = alignment - diff;
naddress = (char*)address + lose;
addto_freelist(bp, address, lose);
address = (unsigned*)naddress;
}
}
if(bp->guarded)
{
*address = FRNTGUARD;
*((unsigned*)(((char*)address)+req-ALIGNMENTM)) = BACKGUARD;
}
FINDKEY(USEDH, (unsigned)address)
if(node->key == (unsigned)address) {
VCRASH("allocC:%d: bookkeeping nodes are corrupted at:0x%x\n",
category, address);
}
SETLEVEL(USEDH)
node = new_Mnode(bp, level, USEDH);
node->key = (unsigned)address;
node->value = req;
INSERT()
return address+bp->addrbump;
}
void*
callocC(int category, unsigned cnt, unsigned elem_size)
{
unsigned size = cnt * elem_size;
void* buf;;
if((buf = mallocC(category, size)))
bzero(buf, size);
return buf;
};
void
freeC(int category, void* addr)
{
unsigned cursize;
unsigned *address;
struct _bins *bp;
SKIPVARS;
if(addr)
{
if(!(bp = getcat(category))) {
VCRASH("freeC:%d: non-existant category at:0x%x\n",category,addr);
}
HEAPCHECK
address = (void*) ((unsigned*)addr - bp->addrbump);
FINDKEY(USEDH, (unsigned)address)
if(node->key != (unsigned)address) {
VCRASH("freeC:%d: bogus address=0x%x\n", category, addr);
}
cursize = node->value;
CHECKGUARDS(freeC)
DELETENODE(USEDH)
addto_freelist(bp, address, cursize);
}
else VCRASH("freeC:%d: null pointer\n", category);
}
void*
reallocC(int category, void* addr, unsigned newsize)
{
SKIPVARS;
unsigned cursize;
unsigned *address;
struct _bins *bp;
NodePM onode;
if(addr == 0)
return mallocC(category, newsize);
else
{
if(!(bp = getcat(category))) {
VCRASH("reallocC:%d: non-existant category at:%x\n",category,addr);
}
HEAPCHECK
if(newsize == 0)
newsize = ALIGNMENTM;
else
newsize += ROUNDINGM(newsize);
newsize += bp->guarded;
address = (void*)(((char*)addr)-(bp->guarded/2));
FINDKEY(USEDH, (unsigned)address)
if(node->key != (unsigned)address) {
VCRASH("reallocC:%d: bogus address=0x%x\n", category, addr);
}
cursize = node->value;
node->value = newsize;
onode = node;
CHECKGUARDS(reallocC)
if(newsize == cursize)
return addr;
if(newsize > cursize)
{/* check if block can be extended */
void *taddr = ((char*)address) + cursize;
unsigned extendsize = newsize-cursize;
/* check freelist for an available block at the right address */
FINDKEY(FREEH, (unsigned)taddr)
if(node->key == (unsigned)taddr)
{
AddrP sp = (AddrP)node->value;
if(sp->size >= extendsize)
{/* BLOCK CAN BE EXTENDED INTERNALLY */
node->key += extendsize;
sp->size -= extendsize;
DETACH(sp)
if(sp->size == 0)
{/* the extension block is used up, delete this node */
free_addr(bp, sp);
DELETENODE(FREEH)
}
else
{/* shift the remainder in the sizelist */
addto_sizelist(bp, sp);
}
/* SUCCESS */
if(bp->guarded)
{
*((unsigned*)(((char*)address)+newsize-ALIGNMENTM))
= BACKGUARD;
}
return addr;
}
}
/* HERE WE COULD CHECK OTHER SOURCES OF SPACE */
/* can't extend block, malloc some new space */
if((taddr = mallocC(category,newsize-bp->guarded)))
{
memmove(taddr,addr,cursize-bp->guarded);
onode->value = cursize;
freeC(category, addr);
}
/* SUCCESS */
return taddr;
}
else
{/* shrink block */
if(bp->guarded)
{
*((unsigned*)(((char*)address)+newsize-ALIGNMENTM))
= BACKGUARD;
}
addto_freelist(bp, ((char*)address)+newsize, cursize-newsize);
return addr;
}
}
}
void
freecat(int category)
{
struct _bins *bp;
if(category == 0)
return;
if((bp = getcat(category)))
{
struct _catlocs *cl = bp->catlocs;
struct _bins *hbp;
struct _bins *prev;
while(cl)
{/* Space allocated to the category is moved to category 0 */
void *ql = cl->fptr;
freeC(0, cl->addr);
free_catloc(cl);
cl = ql;
}
/* space for the _bins struct is placed on a free list */
hbp = hmap[category % 1009];
prev = 0;
while(hbp)
{
if(hbp->bincat == category)
{
if(prev == 0)
hmap[category % 1009] = hbp->fptr;
else
prev->fptr = hbp->fptr;
free_bins(hbp);
return;
}
prev = hbp;
hbp = hbp->fptr;
}
}
}
int
memrangeC(int category, unsigned *min, unsigned *max)
{
struct _bins *bp;
if((bp = getcat(category)))
{
*min = bp->minloc;
*max = bp->maxloc;
return 1;
}
return 0;
}
int
usedrangeC(int category, unsigned *min, unsigned *max)
{
struct _bins *bp;
NodePM node;
int level;
if((bp = getcat(category)))
{
node = bp->USEDHheader;
*min = node->fptr[0]->key;
for(level = bp->USEDHlevel; level >= 0; level--)
while(node->fptr[level]->key < 0xffffffff)
node = node->fptr[level];
*max = node->key;
return 1;
}
return 0;
}
void
totrangeC(unsigned *min, unsigned *max)
{
*min = minloc;
*max = maxloc;
}
void
guardC(int category)
{
struct _bins *bp;
if(!(bp = getcat(category)))
if(!(bp = initcat(category)))
return;
if(!bp->guarded)
{
bp->guarded = 2*ALIGNMENTM;
bp->addrbump = 1;
}
}
void*
heapcheckC(int category, void *start)
{
struct _bins *bp;
NodePM node,prev;
unsigned *p1,*p2;
if((bp = getcat(category)))
{
if(bp->guarded)
{
prev = 0;
node = bp->USEDHheader;
while( (node = node->fptr[0]) != (NodePM)0xffffffff
&& node->key != 0xffffffffUL)
{
if((void*)node->key > start)
{
p1 = (unsigned*)node->key;
if(*p1 != FRNTGUARD)
{
if(prev)
return (char*)prev->key+ALIGNMENTM;
else
return (void*)1;
}
p2 = (unsigned*)(((char*)p1)+node->value-ALIGNMENTM);
if(*p2 != BACKGUARD)
return (char*)node->key+ALIGNMENTM;
}
prev = node;
}
}
}
return 0;
}
void*
mallocC(int category, unsigned size)
{
return memalignC(category, 0, size);
}
void*
vallocC(int category, unsigned bytes)
{
return memalignC (category, PAGESIZE, bytes);
}
unsigned
mallocsizeC(int category, void* addr)
{
struct _bins *bp;
SKIPVARS;
if(addr && (bp = getcat(category)))
{
unsigned address = (unsigned)((unsigned*)addr - bp->addrbump);
FINDKEY(USEDH, address)
if(node->key == address)
return node->value - bp->guarded;
}
return 0;
}
int
NewMallocCategory(void)
{
static unsigned int cat = BASE_CATEGORY;
return ++cat;
}
/* ====================== END MULTI-HEAP MALLOC ============================ */
/* These are here to prevent the system malloc from being linked */
void *
malloc(unsigned a)
{
void *result = mallocC(BASE_CATEGORY, a);
MPRINTF("malloc %d bytes at %p caller=%x\n", a, result, ((unsigned *)&a)[-1]);
return result;
}
void
free(void *a)
{
MPRINTF("free at %p caller=%x\n", a, ((unsigned*)&a)[-1]);
freeC(BASE_CATEGORY,a);
}
void *
realloc(void *a, unsigned b)
{
void *result = reallocC(BASE_CATEGORY,a,b);
MPRINTF("realloc %d bytes at %p old=%p caller=%x\n",
b, result, a, ((unsigned*)&a)[-1]);
return result;
}
void *
calloc(unsigned a, unsigned b)
{
void *result = callocC(BASE_CATEGORY,a,b);
MPRINTF("calloc %d bytes at %p caller=%x\n", a*b, result, ((unsigned*)&a)[-1]);
return result;
}
void *
valloc(unsigned a)
{
void *result = vallocC(BASE_CATEGORY,a);
MPRINTF("valloc %d bytes at %p caller=%x\n", a, result, ((unsigned *)&a)[-1]);
return result;
}
void *
memalign(unsigned a, unsigned b)
{
void *result = memalignC(BASE_CATEGORY,a,b);
MPRINTF("memalign(%u) %u bytes at %p caller=%x\n",
a,b,result,((unsigned *)&a)[-1]);
return result;
}
unsigned
mallocsize(void *a)
{
return mallocsizeC(BASE_CATEGORY, a);
}
static int
lnulfunc()
{
return 0;
}
static void
lhash(void *keyptr, int cnt, CAT *cat)
{/* THIS FUNCTION IS IDENTICAL TO 'key_hash' in CFF */
STOR value;
int i;
cat->c0.item = 0;
if(cnt <= 8)
for (i = 0; i < cnt; ++i)
cat->c0.a5.b[i] = *((unsigned char *)keyptr)++;
else
for (i = 0; i < cnt; ++i)
cat->c0.a5.b[i&7] ^= *((unsigned char *)keyptr)++;
/* THE CONSTANTS WERE CAREFULLY CHOSEN BY THEORY */
/* value.item is a long long (use gcc only) */
value.item = ((1103515245LL)*(cat->c0.a4.s0 ^ cat->c0.a4.s1))+453816693LL;
if(value.a0 == 0) value.a0 = 1;
value.a0 &= 0x0fffffff;
if(cnt <= 8) value.a0 |= 0x80000000; /* exact key chunk */
cat->c1.a0 = value.a0;
}
static int linkup_complete;
static int
laccess(char *a, int b)
{/* suppress use of 'access', it links in too many other functions */
if(linkup_complete)
return ((VOBTYPE(a) & (OB_XFILE|OB_TREEDIR|OB_HASHDIR)) ? 0 : 1);
else {
int fd = VOPEN(a,O_RDONLY|O_BINARY);
if(fd > 0)
{
VCLOSE(fd);
return 0;
}
return 1;
}
}
static int
lpagesize()
{
return 4096;
}
static int
lprintchar(int c)
{
return VWRITE(1,&c,1);
}
static void
lprintstr(char *str)
{
while(*str)
lprintchar(*str++);
}
#if EARLY_PRINT == 1
struct parameters
{
int number_of_output_chars;
int (*output_function)(void *, int);
void *output_pointer;
short minimum_field_width;
short edited_string_length;
short leading_zeros;
char options;
#define MINUS_SIGN 1
#define RIGHT_JUSTIFY 2
#define ZERO_PAD 4
#define CAPITAL_HEX 8
};
static void output_and_count(struct parameters *p, int c)
{
if (p->number_of_output_chars >= 0)
{
int n = (*p->output_function)(p->output_pointer, c);
if (n>=0) p->number_of_output_chars++;
else p->number_of_output_chars = n;
}
}
static void output_field(struct parameters *p, char *s)
{
short justification_length =
p->minimum_field_width - p->leading_zeros - p->edited_string_length;
if (p->options & MINUS_SIGN)
{
if (p->options & ZERO_PAD)
output_and_count(p, '-');
justification_length--;
}
if (p->options & RIGHT_JUSTIFY)
while (--justification_length >= 0)
output_and_count(p, p->options & ZERO_PAD ? '0' : ' ');
if (p->options & MINUS_SIGN && !(p->options & ZERO_PAD))
output_and_count(p, '-');
while (--p->leading_zeros >= 0)
output_and_count(p, '0');
while (--p->edited_string_length >= 0)
output_and_count(p, *s++);
while (--justification_length >= 0)
output_and_count(p, ' ');
}
static int
gprintf(int (*output_function)(void *, int), void *output_pointer,
char *control_string, int *argument_pointer)
{
struct parameters p;
char control_char;
p.number_of_output_chars = 0;
p.output_function = output_function;
p.output_pointer = output_pointer;
control_char = *control_string++;
while (control_char != '\0')
{
if (control_char == '%')
{
short precision = -1;
short long_argument = 0;
short base = 0;
control_char = *control_string++;
p.minimum_field_width = 0;
p.leading_zeros = 0;
p.options = RIGHT_JUSTIFY;
if (control_char == '-')
{
p.options = 0;
control_char = *control_string++;
}
if (control_char == '0')
{
p.options |= ZERO_PAD;
control_char = *control_string++;
}
if (control_char == '*')
{
p.minimum_field_width = *argument_pointer++;
control_char = *control_string++;
}
else
{
while ('0' <= control_char && control_char <= '9')
{
p.minimum_field_width =
p.minimum_field_width * 10 + control_char - '0';
control_char = *control_string++;
}
}
if (control_char == '.')
{
control_char = *control_string++;
if (control_char == '*')
{
precision = *argument_pointer++;
control_char = *control_string++;
}
else
{
precision = 0;
while ('0' <= control_char && control_char <= '9')
{
precision = precision * 10 + control_char - '0';
control_char = *control_string++;
}
}
}
if (control_char == 'l')
{
long_argument = 1;
control_char = *control_string++;
}
if (control_char == 'd')
base = 10;
else if (control_char == 'x' || control_char == 'p')
base = 16;
else if (control_char == 'X')
{
base = 16;
p.options |= CAPITAL_HEX;
}
else if (control_char == 'u')
base = 10;
else if (control_char == 'o')
base = 8;
else if (control_char == 'b')
base = 2;
else if (control_char == 'c')
{
base = -1;
p.options &= ~ZERO_PAD;
}
else if (control_char == 's')
{
base = -2;
p.options &= ~ZERO_PAD;
}
if (base == 0) /* invalid conversion type */
{
if (control_char != '\0')
{
output_and_count(&p, control_char);
control_char = *control_string++;
}
}
else
{
if (base == -1) /* conversion type c */
{
char c = *argument_pointer++;
p.edited_string_length = 1;
output_field(&p, &c);
}
else if (base == -2) /* conversion type s */
{
char *string;
p.edited_string_length = 0;
string = * (char **) argument_pointer;
argument_pointer += sizeof(char *) / sizeof(int);
while (string[p.edited_string_length] != 0)
p.edited_string_length++;
if (precision >= 0 && p.edited_string_length > precision)
p.edited_string_length = precision;
output_field(&p, string);
}
else /* conversion type d, b, o or x */
{
unsigned long x;
char buffer[64];
p.edited_string_length = 0;
if (long_argument)
{
x = * (unsigned long *) argument_pointer;
argument_pointer += sizeof(unsigned long) / sizeof(int);
}
else if (control_char == 'd')
x = (long) *argument_pointer++;
else
x = (unsigned) *argument_pointer++;
if (control_char == 'd' && (long) x < 0)
{
p.options |= MINUS_SIGN;
x = - (long) x;
}
do
{
int c;
c = x % base + '0';
if (c > '9')
{
if (p.options & CAPITAL_HEX)
c += 'A'-'9'-1;
else
c += 'a'-'9'-1;
}
buffer[sizeof(buffer) - 1 - p.edited_string_length++] = c;
}
while ((x/=base) != 0);
if (precision >= 0 && precision > p.edited_string_length)
p.leading_zeros = precision - p.edited_string_length;
output_field(&p, buffer + sizeof(buffer) - p.edited_string_length);
}
control_char = *control_string++;
}
}
else
{
output_and_count(&p, control_char);
control_char = *control_string++;
}
}
return p.number_of_output_chars;
}
static int
lputc(void *fd, int c)
{
return VWRITE((int)fd, &c, 1);
}
static int
lprintf(char *fmt, ...)
{
return gprintf(lputc, (void*)1, fmt, (int*)(&fmt+1));
}
static int
lvprintf(char *fmt, void *args)
{
return gprintf(lputc, (void*)1, fmt, args);
}
static int lfilc(void *p, int c)
{
*(*(char **)p)++ = c;
return 0;
}
static int
lsprintf(char *buf, char *fmt, ...)
{
int n;
n = gprintf(lfilc, &buf, fmt, (int*)(&fmt+1));
*buf = 0;
return n;
}
#endif /* EARLY_PRINT == 1 */
void
_cleanup()
{/* SUPPRESS PULLIN OF STDIO STUFF */
}
/* ================== END OF INTERNAL SUPPORT FUNCTIONS ================= */
#include "oxlink.i"
/* ================ END OF THE DYNAMIC LINKER ======================= */
struct _linkups {
void *dst;
char *src;
};
static struct _linkups __linkups[] = {
{&VPUSH_VALUE, "_cfpush_value"},
{&VPUSH_DATA, "_cfpush_data"},
{&VGET, "_cfgetx"},
{&VFIND, "_cffindx"},
{&VCFOPEN, "_cfopen"},
{&VCFCLOSE, "_cfclose"},
{&VCFREAD, "_cfrdwr_object"},
{&VCFWRITE, "_cfrdwr_object"},
{&VCFLSEEK, "_cfseek"},
{&VSUBOPEN, "_cfsubopen"},
{&VOBTYPE, "_cfobtype"},
{&VPUT, "_cfputx"},
{&VFILESIZE, "_cffilesize"},
{&VOPEN_CHUNK, "_cfopen_chunk"},
{&VLOCALIZE, "_cflocalize"},
{&VRELEASE, "_cfrelease"},
{&VMEMTEMP, "_MEMTEMP"},
{&VVPRINTF, "_cfvprintf"},
{&VSPRINTF, "_cfsprintf"},
{&VPRINTF, "_cfprintf"},
{&VSTAT, "_cfstat"},
{&CFINIT, "_cfinit"},
{&CFEXIT, "_cfexit"},
{&COSINIT, "_InitCOS"},
{&THREADER, "__start_threader"},
{&THREAD, "__start_thread"},
{&VINHIBIT_THREADER, "__no_context_switch"},
{NULL}
};
static int badsyms;
static void
linkup()
{
struct _linkups *l = __linkups;
while(l->dst)
{
*((long *)l->dst) = (long)oxlink_find_bare_symb(l->src);
++l;
}
/* REDIRECT USER CALLS TO OUR PREFERRED SUBROUTINES */
SYMLINK(__filbuf, _cf_filbuf);
SYMLINK(__flsbuf, _cf_flsbuf);
SYMLINK(_fread, _cffread);
SYMLINK(_fputc, _cffputc);
SYMLINK(_fgetc, _cffgetc);
SYMLINK(_fputs, _cffputs);
SYMLINK(_fgets, _cffgets);
SYMLINK(_puts, _cfputs);
SYMLINK(_putw, _cfputw);
SYMLINK(_gets, _cfgets);
SYMLINK(_ftell, _cfftell);
SYMLINK(_printf, _cfprintf);
SYMLINK(_fprintf, _cffprintf);
SYMLINK(_sprintf, _cfsprintf);
SYMLINK(_vprintf, _cfvprintf);
SYMLINK(_vfprintf, _cfvfprintf);
SYMLINK(_fscanf, _cffscanf);
SYMLINK(_fopen, _cffopen);
SYMLINK(_freopen, _cffreopen);
SYMLINK(_fseek, _cffseek);
SYMLINK(_rewind, _cfrewind);
SYMLINK(_fflush, _cffflush);
SYMLINK(_fwrite, _cffwrite);
SYMLINK(_unlink, _cfunlink);
SYMLINK(_remove, _cfunlink);
SYMLINK(_ungetc, _cfungetc);
SYMLINK(_fclose, _cffclose);
SYMLINK(_fdopen, _cffdopen);
SYMLINK(_setmode, _cfsetmode);
SYMLINK(_setbuf, _cfsetbuf);
SYMLINK(_setvbuf, _cfsetvbuf);
SYMLINK(_setlinebuf, _cfsetlinebuf);
SYMLINK(_scanf, _cfscanf);
SYMLINK(_sscanf, _cfsscanf);
SYMLINK(_fscanf, _cffscanf);
SYMLINK(_vscanf, _cfvscanf);
SYMLINK(_vfscanf, _cfvfscanf);
SYMLINK(_vsscanf, _cfvsscanf);
SYMLINK(__iob, _cf_iob);
SYMLINK(_stat, _TRAPSTAT);
SYMLINK(_rename, _TRAPRENAME);
SYMLINK(_fgetpos, _cffgetpos);
SYMLINK(_fsetpos, _cffsetpos);
SYMLINK(_tmpfile, _cftmpfile);
SYMLINK(_tmpnam, _cftmpnam);
SYMLINK(_tempnam, _cftempnam);
SYMLINK(_itoa, _ltoa);
}
static char *
appnameof(char *path)
{
char *aname;
char *cp;
if(path == NULL)
return NULL;
cp = concat("_", fileof(path, 0), "");
aname = strdup(cp);
_oxlink_free(cp); /* was not allocated with malloc */
if((cp = strrchr(aname, '.')) != NULL)
*cp = 0;
cp = aname;
while(*cp)
{/* lower case app names only */
if(*cp >= 'A' && *cp <= 'Z')
*cp += 32;
++cp;
}
return aname;
}
static char *
appfileof(char *aname)
{
char *fname;
char *gname;
int fcnt;
if(aname == NULL)
return NULL;
fcnt = strlen(aname);
fname = malloc(fcnt+6);
if(aname[0] == '_')
fcnt = _strcpy(fname, &aname[1]);
else
strcpy(fname, aname);
strcpy(&fname[fcnt], ".o");
if(!(gname = cf_find_file(fname, 0)))
{
#if 0
strcpy(&fname[fcnt], ".byt");
if(!(gname = cf_find_file(fname, 0)))
#endif
strcpy(&fname[fcnt], ".cff");
gname = cf_find_file(fname, 0);
}
free(fname);
return gname;
}
static char *
cfffileof(char *aname)
{
char *fname;
char *gname;
int fcnt;
if(aname == NULL)
return NULL;
fcnt = strlen(aname);
fname = malloc(fcnt+6);
if(aname[0] == '_')
fcnt = _strcpy(fname, &aname[1]);
else
strcpy(fname, aname);
strcpy(&fname[fcnt], ".cff");
gname = cf_find_file(fname, 0);
free(fname);
return gname;
}
static void
Usage()
{
lprintstr("\
Usage: cfrun appname [-APP=][-LIB=][-PATH=][-TRACE=][-LBUFS=][appargs]\n\
Switch -------- Meaning\n\
-APP=filename Permanent object file/archive for the application.\n\
-LIB=filename A library file.\n\
-PATH=p1;p2;... Lookup path for files.\n\
-LBUFS=n Allocate n kilobytes of database buffering.\n\
-TRACE=n Set trace bits (hex,octal,decimal ok).\n\
appargs Application args.\n\
");
}
/* ====================== THE MAIN FUNCTION ======================= */
static int chainargc;
static char *chainargv[30];
static char *chainapp, *chainfile, *chaincff;
static int chainapp_hasextension, chainfile_iscff;
char **Envp;
static char newmain[10];
int
main(int argc, char **argv, char **envp)
{
char *appath, *appname, *appfile, *ap, *dp;
int lbufs, i;
int appfile_iscff = 0;
int appname_hasextension = 0;
char *appcff = 0;
char *
check_for_arg(char *arg)
{/* NESTED SUBROUTINE */
int i;
int arglen = strlen(arg);
for(i = 1; i < argc; ++i)
{
if(argv[i][0] == '-' && !strncmp(arg, &argv[i][1], arglen))
{
int j;
char *cp = &argv[i][arglen+1];
for(j = i; j < argc; ++j)
argv[j] = argv[j+1];
--argc;
return cp;
}
}
return NULL;
}
/* main */
path_sep = ';';
_oxlink_openmode = O_RDONLY|O_BINARY;
_oxlink_seekmode = 0;
oxlink_errno = 0;
Envp = envp;
cf_set_search_path(check_for_arg("PATH="));
if((ap = check_for_arg("TRACE=")) != NULL)
_oxlink_trace = strtol(ap, NULL, 0);
/* Get relevant info about this program name */
appath = cf_find_file(argv[0], 0);
appname = appnameof(appath);
if(!strcmp(appname, "_cfrun"))
{/* arg1 contains the real name of the application */
int j;
if(argc > 1)
{
appname = appnameof(argv[1]);
if((dp = strchr(argv[1], '.')))
{
appfile = cf_find_file(argv[1], 0);
appname_hasextension = 1;
}
else
appfile = appfileof(appname);
for(j = 1; j < argc; ++j)
argv[j] = argv[j+1];
--argc;
}
else
{
Usage();
VEXIT(0);
}
}
else appfile = appfileof(appname);
if(appfile)
{
if((dp = strrchr(appfile, '.')))
{
if(!strcmp(dp, ".cff"))
{
appfile_iscff = 1;
appcff = appfile;
}
else
{
appcff = cfffileof(appname);
}
}
}
/* Link in the base level code */
permanent_symbols = 1;
if(!oxlink_init(appath)) {
oxlink_use_library("oxbow.a");
if(!oxlink_load_object("dj12port.o")) {
if(!oxlink_load_object("cffsys.o")) {
if(!oxlink_load_object("cossys.o")) {
oxlink_nouse_library("oxbow.a");
linkup();
}
}
}
}
permanent_symbols = 0;
if(oxlink_errno) {
lprintstr(oxlink_errstr());
VEXIT(oxlink_errno);
}
/* CFF and COS are now linked */
linkup_complete = 1;
_oxlink_openmode = F_STAT;
_oxlink_seekmode = S_SET;
/* check for appfile override */
if((ap = check_for_arg("APP=")) != NULL)
appfile = strdup(ap);
if((ap = check_for_arg("LBUFS=")) != NULL)
lbufs = strtol(ap, NULL, 0);
else lbufs = 100;
/* Initialize CFF and COS */
CFINIT(&appname[1], lbufs, appfile);
COSINIT(&argc);
/* Get rid of the symbol `_main' so it doesn't clash */
strcpy(newmain, "_main$$$");
oxlink_rename_symb("_main", newmain);
/* Specify which libraries will provide code and data */
oxlink_use_library("oxlib.cff");
/* Pick up any additional libraries of interest */
while((ap = check_for_arg("LIB=")) != NULL)
oxlink_use_library(ap);
/* Enable demand loading */
oxlink_demand_load();
if(_oxlink_trace)
{/* Print the addresses of the early load modules */
struct file_entry *entry = _oxlink_latest_entry;
void print_file(struct file_entry *e)
{/* NESTED SUBROUTINE */
VPRINTF("%s\ntext:0x%x sz=%d data:0x%x sz=%d bss:0x%x sz=%d end=%x\n",
e->local_sym_name,
e->text_start_address, e->header.text_size,
e->data_start_address, e->header.data_size,
e->bss_start_address, e->header.bss_size,
e->text_start_address+e->header.image_size
);
}
while(entry)
{
if(entry->library_flag) {
struct file_entry *subentry = entry->subfiles;
while(subentry)
{
print_file(subentry);
subentry = subentry->chain;
}
}
entry = entry->chain;
}
}
/* Start threads */
THREADER(&argc);
if(setjmp(_t_start)) {
THREAD();
}
*VINHIBIT_THREADER += 1;
{
int ret;
int run_argc;
char **run_argv;
run_argc = argc;
run_argv = argv;
chain:
if(appcff)
{
oxlink_use_library(appcff); /* ignored if not a library */
}
run_argv[0] = &appname[1];
if(appfile)
{/* The file could be .o or .cff */
char *filename;
int (*funcptr)();
int loaded = 0;
if(appfile_iscff || !appname_hasextension)
{/* look for a file inside a .cff file */
/* FIRST TRY TO RUN THE APPNAME */
if((ret = oxfunc(appname, run_argc, run_argv)) != -1)
{
oxlink_unload_bare_symb(appname, 0);
loaded = -1;
}
else
{/* try loading object from any defined libraries */
dp = strrchr(appfile, '/')+1;
filename = calloc(1, strlen(dp)+5);
strcpy(filename, dp);
strcpy(strchr(filename,'.'), ".o");
if(!oxlink_load_object(filename))
{
loaded = 1;
}
}
}
if(!loaded)
{/* try loading the file directly */
filename = appfile;
if(oxlink_load_file(filename))
{
VPRINTF("Can't start application `%s'\n", &appname[1]);
VEXIT(1);
}
loaded = 1;
}
if(loaded > 0)
{
if((funcptr = oxlink_find_bare_func("_main")))
{/* Get rid of the symbol `_main' so it doesn't clash */
++newmain[8];
oxlink_rename_symb("_main", newmain);
}
else if(!(funcptr = oxlink_find_bare_func(appname)))
{
VPRINTF("Can't find `_main' or `%s' in file %s\n",
appname, filename);
VEXIT(1);
}
ret = funcptr(run_argc, run_argv);
oxlink_unload_file(filename, 0);
if(filename != appfile)
free(filename);
}
}
else
{/* Just try to run the name from a library */
if((ret = oxfunc(appname, run_argc, run_argv)) == -1)
VPRINTF("Can't start application `%s'\n", &appname[1]);
oxlink_unload_bare_symb(appname, 0);
}
free(appname);
if(appcff)
{
oxlink_nouse_library(appcff);
if(appcff != appfile)
free(appcff);
}
if(appfile)
free(appfile);
if(chainapp)
{/* The previous program chained to a new one */
appname = chainapp;
appfile = chainfile;
appcff = chaincff;
appfile_iscff = chainfile_iscff;
appname_hasextension = chainapp_hasextension;
chainapp = 0;
if(run_argv != argv)
{/* was chained previously, get rid of prev args */
for(i = 1; i < run_argc; ++i)
free(run_argv[i]);
}
run_argc = chainargc;
run_argv = (char**)chainargv;
goto chain;
}
CF_InitIO(-1, 0);
VEXIT(ret);
}
}
void
CF_ChainFile(char *newname, int argc, char **argv)
{/* CALLED FROM APPLICATION TO CHAIN TO ANOTHER PROGRAM */
int i;
char *dp;
chaincff = 0;
chainfile_iscff = 0;
chainapp_hasextension = 0;
chainapp = appnameof(newname);
if((dp = strchr(newname, '.')))
{
chainfile = cf_find_file(newname, 0);
chainapp_hasextension = 1;
}
else chainfile = appfileof(chainapp);
if(chainfile)
{
if((dp = strrchr(chainfile, '.')))
{
if(!strcmp(dp, ".cff"))
{
chainfile_iscff = 1;
chaincff = chainfile;
}
else
{
chaincff = cfffileof(chainapp);
}
}
}
chainargc = argc+1;
for(i = 0; i < argc; ++i)
chainargv[i+1] = copy_of(argv[i]);
}
void
CF_InitIO(long arg, long long (*msgproc)())
{/* THIS FUNCTION IS CALLED FROM THE APPLICATION */
static void (*initio)() = NULL;
if(arg >= 0)
{
AppArg = arg;
initio = oxload(CF_Interactive_IO);
initio(0, msgproc, &VAPPMSG);
}
else if(arg == -1)
{/* deinit */
if(initio)
initio(-1, 0, 0);
}
else
{/* re-init */
if(initio)
initio(arg, 0, 0);
}
}
long long
AppMsg(void *self, void *wnd, long long it)
{
return VAPPMSG(self, wnd, it);
}