home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
oxcc1433.zip
/
SRC
/
CFAR.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-04
|
37KB
|
1,545 lines
/* cfar.c */
/* Import .o and .a (a.out format) files into a cff archive */
/* Version 2 now incorporates FILE mode, absorbing 'cfin' and 'cfdel' */
/* Copyright 1993, 1995 Norman D. Culver, All Rights Reserved */
/* compile: gcc -o -O2 -DSKELETON cfar.c */
typedef unsigned long size_t;
#include "oxbow.h"
extern void (*BUGPRINTF)(char *fmt, ...);
extern long atol(const char *);
extern int strlen(const char *);
extern void *strcpy(char *, const char *);
extern int _strcpy(char *, char *);
extern void memclr(char *, long);
extern int strlwr(char *);
extern void *strrchr(const char *, char);
static void setup_origin(unsigned long, int);
extern void oxlink_close_libs(void);
/* Program version */
static Item prgversion = (Item)2;
/* Archive version */
static Item arversion;
/* Maximum library types */
#define MAXLIBTYPE 16
typedef struct {
unsigned long sn;
unsigned long libnum : 12; /* capacity for 4096 libraries per libtype */
unsigned long libtype : 4; /* capacity for 16 library types */
unsigned long unused : 12;
unsigned long tag : 4;
} SymItem;
typedef struct {
unsigned long filetime;
unsigned long sn : 28;
unsigned long tag : 4;
} OrgItem;
/* Action bitmap */
static int act;
#define arADD (1)
#define arREPLACE (2)
#define arDELETE (4)
#define arEXTRACT (8)
#define arCHECK (16)
#define arUPDATE (32)
static int verbose; /* if 1, verbose mode */
static long libtype; /* 0 = modules, 1 = classes */
static long oldlibtype = -1;
static long libnum; /* library number into which files are stored */
static long oldlibnum = -1;
static int map; /* if 1, print archive map */
static int map_bitmaps; /* if 1, and map, print bitmaps */
static int map_entries; /* if 1, and map, print entries */
static int freshen; /* if 1, freshen entries */
static int shrink; /* if 1, shrink archive */
static int issymbol; /* if 1, file names are really symbol names */
static int batfile; /* if 1, print a batchfile to remake archive */
static void *archive; /* handle of the open archive */
static void *msyms; /* handle of the master symbol table */
static void *fipaths; /* handle of the internal filemode path table */
static void *ipaths; /* handle of the internal path table */
static void *qipaths;
static void *origins; /* handle of the origin path table */
static void *qorigins;
static void *lib; /* handle of the current internal library */
static void *plib; /* handle of the library parent directory */
static char curlib[1024]; /* internal path to the current library */
static int curliblen;
static char curobj[1024]; /* internal path to the current file */
static int curobjlen;
static char *cur_orgpath; /* current origin path as given by cfpathtrn */
static int cur_orgtype; /* current origin type as given by cfpathtrn */
static OrgItem cur_org; /* current origin time and serial num */
static char ltypes[MAXLIBTYPE];
static char lnums[4096];
/* +++++++++++++++++++++++++++++ FILEMODE ++++++++++++++++++++++++++++++ */
static int filemode;
static int chunk;
static int newname;
static int replace;
static int add;
static void *subdir;
static char *midpart;
static char *lastpart;
static char basefile[256];
static char midpath[1024];
static char innerpath[1024];
static void
proc_filemode(char *filepath)
{
void *fit;
void *h = (subdir) ? subdir : archive;
void *fd;
char *filename;
char *cfname;
Item item;
CFSTAT sbuf;
int cfnamlen;
int filesize;
char *tag;
int exists = 0;
filename = strrchr(filepath, '/');
if(filename)
++filename;
else filename = filepath;
if(newname)
cfname = lastpart;
else
cfname = filename;
cfnamlen = strlen(cfname);
if((fit = cfopen(filepath, F_RDONLY, NULL)) != NULL)
{
/* check for existance of the archive item */
if(cfsubstat(h, cfname, &sbuf) == OK)
{
if(!replace)
{
cfprintf("cfar: %s exists and replace not enabled\n", cfname);
return;
cfclose(fit);
}
exists = 1;
cfunlink(h, cfname);
}
cfstat(fit, &sbuf);
filesize = sbuf.st_filesize;
setup_origin(sbuf.st_mtime, 1);
if(verbose || act == arUPDATE)
{
if(act == arUPDATE)
cfprintf("updating %s\n", cfname);
else cfprintf("%s\n", cfname);
}
if(chunk)
{
if(!(fd = cfmake_chunk(h, cfname, cfnamlen, filesize)))
{
cfprintf("cfar: cannot make chunk for %s\n", cfname);
cfclose(fit);
return;
}
}
else
{
if(!(fd = cfsubopen(h, cfname, F_RDWR|F_CREAT|F_FILEONLY, NULL)))
{
cfprintf("cfar: could not create file %s\n", cfname);
cfclose(fit);
return;
}
}
if(cfcopy_file(fd, fit) != filesize)
cfprintf("cfar: ERROR copying %s\n", cfname);
cfclose(fd);
cfclose(fit);
/* Store the backlink to the origin, time + origin serial number */
if(newname)
tag = "?";
else
tag = " ";
curobjlen = cfsprintf(curobj, "%s/%s%s", innerpath, cfname, tag);
if(exists || act == arUPDATE)
{
cfreinsert(fipaths, curobj, curobjlen, &cur_org);
}
else
{
cfinsert(fipaths, curobj, curobjlen, &cur_org);
}
}
else
{
cfprintf("cfar: input file %s not found\n", filepath);
}
}
static void *
create_middle(char *path, void *basehandle)
{
char *cp;
cp = path;
while((cp = (char*)strchr(cp, '/')) != NULL)
{
void *subhandle;
*cp = '\0';
subhandle = cfsubopen(basehandle, path, F_RDWR|F_CREAT, NULL);
cfclose(subhandle);
*cp = '/';
++cp;
}
return cfsubopen(basehandle, path, F_RDWR|F_CREAT, NULL);
}
static void *
open_middle(void *basehandle)
{
void *subhandle = NULL;
if(newname)
{
if(midpart)
{
subhandle = cfsubopen(basehandle, midpath, F_RDWR|F_CREAT, NULL);
if(subhandle == NULL)
{/* create the path in pieces */
subhandle = create_middle(midpath, basehandle);
}
}
}
else /* not newname */
{
if(innerpath[0])
{
subhandle = cfsubopen(basehandle, &innerpath[1], F_RDWR|F_CREAT, NULL);
if(subhandle == NULL)
{/* create the path in pieces */
subhandle = create_middle(&innerpath[1], basehandle);
}
}
}
#if 0
if(subhandle)
cfsetverylazy(subhandle);
#endif
return subhandle;
}
static void
del_entry()
{
CFSTAT sbuf;
char forgpath[1024];
if(innerpath[0])
{
if(verbose)
cfprintf("%s\n", lastpart);
if(cfunlink(archive, innerpath) != OK)
{
cfprintf("cfar: delete failed for `%s'\n", innerpath);
}
else
{
cfsprintf(forgpath, "/fipaths%s ", innerpath);
if(cfunlink(archive, forgpath) != OK)
{
cfsprintf(forgpath, "/fipath/%s?", innerpath);
if(cfunlink(archive, forgpath) != OK)
cfprintf("cfar: delerror, fipath:%s\n", forgpath);
}
}
}
else
{
cfprintf("cfar: delete, path missing\n");
}
}
static void
out_entry()
{
void *in, *of;
if(innerpath[0])
{
if((in = cfsubopen(archive, innerpath, F_RDONLY, NULL)) == NULL)
{
cfprintf("cfar: extract, `%s' does not exist\n", innerpath);
return;
}
if((of = cfopen(lastpart, F_RDWR|F_CREAT, NULL)) == NULL)
{
cfprintf("cfar: extract, cannot create output file `%s'\n", lastpart);
cfclose(in);
}
if(verbose)
cfprintf("%s\n", lastpart);
cfcopy_file(of, in);
cfclose(in);
cfclose(of);
}
else
{
cfprintf("cfar: extract, path missing\n");
}
}
/* ====================== END FILEMODE =================================== */
static int
open_curlib()
{
if(lib)
{/* library is already open */
if(libtype == oldlibtype && libnum == oldlibnum)
return 1;
cfclose(lib);
if(oldlibtype != libtype)
{
cfclose(plib);
cfsprintf(curlib, "ltype%d", libtype);
plib = cfsubopen(archive, curlib, F_RDWR|F_CREAT, NULL);
}
oldlibtype = libtype;
oldlibnum = libnum;
}
if(oldlibtype != libtype) {
cfsprintf(curlib, "ltype%d", libtype);
plib = cfsubopen(archive, curlib, F_RDWR|F_CREAT, NULL);
}
curliblen = cfsprintf(curlib, "ltype%d/lib%d", libtype, libnum);
lib = cfsubopen(archive, curlib, F_RDWR|F_CREAT|F_SORTED, NULL);
if(!lib)
{
cfprintf("cfar: can't open library %s\n", curlib);
return 0;
}
#if 0
cfsetverylazy(lib);
cfsetverylazy(plib);
#endif
return 1;
}
static void *
make_scratch()
{
return cfsubopen(MEMTEMP, "", F_TEMPFILE|F_BITMAP, NULL);
}
static void
get_libtypes(char *name)
{
void *dirh;
CFDIRENT *d;
memclr(ltypes, MAXLIBTYPE);
dirh = cfopendir(name);
while((d = cfreaddir(dirh)) != NULL) {
if( d->d_name[0] == 'l'
&& d->d_name[1] == 't')
{
long x = atol(&d->d_name[5]);
ltypes[x] = 1;
}
}
cfclosedir(dirh);
}
static void
get_libnums(char *name)
{
void *dirh;
CFDIRENT *d;
memclr(lnums, 4096);
dirh = cfopendir(name);
while((d = cfreaddir(dirh)) != NULL)
{
long x = atol(&d->d_name[3]);
lnums[x] = 1;
}
cfclosedir(dirh);
}
static unsigned long
new_sn(char *name)
{
Item sn;
int namlen = strlen(name);
if(cffind(archive, name, namlen, &sn) >= FOUND)
{
++sn.a0;
cfreinsert(archive, name, namlen, &sn);
return sn.a0;
}
return 0;
}
static char *
fileof(char *path)
{
int len = strlen(path);
char *cp = &path[len-1];
char *cp1;
while(cp != path)
{
if(*cp == '/' || *cp == '\\' || *cp == ':') {
++cp;
break;
}
--cp;
}
len = strlen(cp);
cp1 = malloc(len+1);
strcpy(cp1, cp);
return cp1;
}
static char *
objof(char *name)
{
if(issymbol) {
long dupnum = 0;
SymItem symval;
int symlen = strlen(name);
for(;;)
{
int result = cffind_dupnum(msyms, name, symlen, &symval, &dupnum);
if(result >= FOUND)
{
if( (act == arCHECK)
|| ( symval.libtype == libtype
&& symval.libnum == libnum))
{
char curpath[256];
if(cfget(qipaths, &symval, 8, curpath, 256) >= FOUND) {
if(act == arCHECK)
cfprintf("symbol %s is defined in %s\n", name, curpath);
else return fileof(curpath);
}
}
++dupnum;
}
else return NULL;
}
}
else return fileof(name);
}
static void
delete_file(char *name, int internal)
{
char *objname = objof(name);
int objlen;
Item packval;
SymItem symval;
char cpath[256];
int cpathlen;
Item objloc;
if(!objname)
return;
cpathlen = cfsprintf(cpath, "%s/%s", curlib, objname);
/* Delete the data chunk */
objlen = strlen(objname);
if(cffind(lib, objname, objlen, &objloc) < FOUND) {
if(!internal)
cfprintf("cfar: %s not found\n", cpath);
return;
}
if(verbose && !internal)
cfprintf("%s\n", objname);
cfdelete(lib, objname, objlen);
/* Read the quick access symbol pack and delete the symbols */
objname[objlen-1] = 'x';
if(cffind(lib, objname, objlen, &packval) >= FOUND)
{
char *cp, *sp, symlen;
cp = cflocalize(lib, &packval);
for(sp = cp; *sp ; sp += symlen+1)
{
long dupnum = 0;
symlen = strlen(sp);
for(;;)
{
int result = cffind_dupnum(msyms, sp, symlen, &symval, &dupnum);
if(result >= FOUND)
{
if( symval.libtype == libtype
&& symval.libnum == libnum)
{
cfdelete_dupnum(msyms, sp, symlen, dupnum);
break;
}
++dupnum;
}
else break;
}
}
cfrelease(cp, R_CLEAN);
/* Delete the symbol pack */
cfdelete(lib, objname, objlen);
/* Delete the origin linkage */
objname[objlen-1] = 't';
cfdelete(lib, objname, objlen);
}
/* Delete the path info */
cfdelete(ipaths, cpath, cpathlen);
cfdelete(qipaths, &symval, 8);
free(objname);
}
static void
extract_file(char *name)
{
char *objname = objof(name);
int objlen;
Item objloc;
if(!objname)
return;
objlen = strlen(objname);
if(cffind(lib, objname, objlen, &objloc) == FOUND)
{
void *hobj;
void *fd;
if((hobj = cfopen_chunk(lib, &objloc)) != NULL)
{
if((fd = cfopen(objname, F_RDWR|F_CREAT, NULL)) != NULL)
{
cfcopy_file(fd, hobj);
cfclose(fd);
if(verbose)
cfprintf("%s\n", objname);
}
cfclose(hobj);
}
}
free(objname);
}
static void
setup_origin(unsigned long filetime, int flag)
{
int orglen;
char *cp;
Item orgsn;
cur_org.filetime = filetime;
cur_org.tag = STO_VALUE;
cp = &cur_orgpath[strlen(cur_orgpath)-1];
if(!flag && (*cp != 'a' || cp[-1] != '.'))
{/* origin is not a library */
cp = strrchr(cur_orgpath, '/');
*cp = 0;
}
if(flag & !newname)
{
cp = strrchr(cur_orgpath, '/');
*cp = 0;
}
/* Check if the origin is in the system */
orglen = strlen(cur_orgpath);
if(cffind(origins, cur_orgpath, orglen, &orgsn) >= FOUND)
{/* It is in the system, get the serial number */
cur_org.sn = orgsn.a0;
}
else
{/* Enter this origin into the system */
orgsn.item = new_sn("SN1");
orgsn.a2.type = STO_VALUE;
cur_org.sn = orgsn.a0;
/* Store the origin, indexed both ways */
cfinsert(origins, cur_orgpath, orglen, &orgsn);
cfput(qorigins, &orgsn, 4, cur_orgpath, orglen+1, NULL);
}
if(*cp == 0) *cp = '/';
}
static void
insert_file(char *path)
{
void *desc;
/* Open the input file */
if((desc = cfopen(path, F_RDONLY, NULL)) != NULL)
{
int numobjs;
int i, j;
char *objname;
char *sympack;
int packx;
void *scratch;
CFSTAT s;
cfstat(desc, &s);
setup_origin(s.st_mtime, 0);
/* Create a scratch object in memory */
scratch = make_scratch();
/* Take a look at the input file */
numobjs = oxlink_scan_file(desc, scratch);
/* oxlink_scan_file returns results in 'scratch'
and on the 'scratch' stack */
for(i = 0; i < numobjs; ++i, free(objname), free(sympack))
{
unsigned long numsyms;
unsigned long symsize;
unsigned long objsize;
unsigned long objoffset;
unsigned long objnum;
unsigned long objnamlen;
SymItem objval;
int objexists = 0;
int clash = 0;
cfpop_value(scratch, &symsize);
cfpop_value(scratch, &numsyms);
cfpop_value(scratch, &objnum);
cfpop_value(scratch, &objnamlen);
if(objnamlen > 0) {
objname = malloc(objnamlen);
cfpop_data(scratch, objname, objnamlen);
} else {
objname = fileof(path);
objnamlen = strlen(objname)+1;
}
cfpop_value(scratch, &objsize);
cfpop_value(scratch, &objoffset);
/* Get space for a chunk of symbols */
sympack = malloc(symsize+1);
packx = 0;
if((objnamlen + curliblen) > 255)
{
cfprintf("%s -- name too long. CONTINUING\n", objname);
continue;
}
/* Check the object file for current existence */
curobjlen = cfsprintf(curobj, "%s/%s", curlib, objname);
if(cffind(ipaths, curobj, curobjlen, &objval) >= FOUND)
{
objexists = 1;
if(!(act & (arREPLACE|arUPDATE))) {
cfprintf("%s found in archive. CONTINUING\n", curobj);
continue;
}
}
/* Pass 1 over the symbols, check for clashes */
for(j = 0; j < numsyms; ++j)
{/* The global symbols for each .o file have been saved
in 'sratch', keyed by (objnum<<18+symnum) */
Item symptr;
long key = (objnum<<18)+j;
SymItem symval;
int x;
if(cffind(scratch, &key, 4, &symptr) == FOUND)
{
char *cp = cflocalize(scratch, &symptr);
if(cp)
{
/* Add to the quick access pack of symbols */
x = _strcpy(&sympack[packx], cp)+1;
if(!objexists)
{/* Check for symbol clash with other .o files in lib */
long dupnum = 0;
for(;;)
{/* Duplicate symbols are allowed, in separate libs */
int result = cffind_dupnum(msyms,cp,x-1,&symval,&dupnum);
if(result >= FOUND)
{
if( symval.libtype == libtype
&& symval.libnum == libnum)
{
clash = 1;
}
if(!clash && result > FOUND)
{/* Duplicate symbols exist */
++dupnum;
continue;
} else break;
} else break;
}
}/* if(!objexists) */
cfrelease(cp, R_CLEAN);
if(clash)
{
char pathname[256];
pathname[0] = 0;
cfget(qipaths, &symval, 8, pathname, 256);
cfprintf("cfar: symbol `%s' in %s clashes with `%s' CONTINUING\n",
&sympack[packx], objname, pathname);
break;
}
packx += x;
}/* if(cp) */
}/* if(cffind ) */
}/* END: for(j ) symbol pass 1 */
if(clash || !(act & (arADD|arREPLACE|arUPDATE)))
continue;
/* NOW add or replace the object file */
if(verbose || act == arUPDATE)
{
if(act == arUPDATE)
cfprintf("updating %s\n",objname);
else cfprintf("%s\n", objname);
}
if(objexists) {
delete_file(objname, 1);
} else {/* Get a new serial number for the .o file */
objval.sn = new_sn("SN0");
objval.libnum = libnum;
objval.libtype = libtype;
objval.unused = 0;
objval.tag = STO_VALUE;
}
/* Store the object file in a chunk */
#if 1 /* the easy slow way, not much memory usage */
{
void *of;
if((of = cfmake_chunk(lib, objname, objnamlen-1, objsize)))
{
if(cfcopy_file(of, desc) != objsize)
{
cfclose(of);
cfprintf("cfar: ERROR copying %s\n", objname);
break;
}
cfclose(of);
}
else
{
cfprintf("cfar: ERROR can't make chunk for %s\n", objname);
break;
}
}
#else /* the hard fast way, may use a LOT of memory */
{
Item space;
char *loc;
if(cfgetspace(lib, objsize, &space) != NULL)
{/* ensure that there is enough space in the localizer bufs */
long curbufs, objbufs;
objbufs = (objsize / 1024)+1;
curbufs = cfcurbufs();
if(objbufs > curbufs)
{
cfmodbufs((objbufs-curbufs)+16);
objbufs = cfcurbufs();
}
if((loc = cflocalize(lib, &space)) != NULL) {
cfseek(desc, objoffset, S_SET);
cfread(desc, loc, objsize);
cfrelease(loc, R_DIRTY);
cfinsert(lib, objname, objnamlen-1, &space);
} else {
cfretspace(lib, &space);
cfprintf("cfar: ERROR can't localize space for %s\n", objname);
break;
}
}
else
{
cfprintf("cfar: ERROR can't allocate space for %s\n", objname);
break;
}
}
#endif
/* Store the quick access package of symbols */
objname[objnamlen-2] = 'x';
sympack[symsize] = 0;
cfput(lib, objname, objnamlen-1, sympack, symsize+1, NULL);
/* Store the backlink to the origin, time + origin serial number */
objname[objnamlen-2] = 't';
cfinsert(lib, objname, objnamlen-1, &cur_org);
/* Store the path, indexed both ways */
cfinsert(ipaths, curobj, curobjlen, &objval);
cfput(qipaths, &objval, 8, curobj, curobjlen+1, NULL);
/* Store the symbols, symname is the key, objval is the item */
/* Pass 2 over the symbols */
for(j = 0; j < numsyms; ++j)
{/* The global symbols for each .o file have been saved
in 'scratch', keyed by (objnum<<18+symnum) */
Item symptr;
long key = (objnum<<18)+j;
if(cffind(scratch, &key, 4, &symptr) == FOUND)
{
char *cp;
if((cp = cflocalize(scratch, &symptr)) != NULL) {
cfinsert_dupnum(msyms, cp, strlen(cp), &objval, NULL);
cfrelease(cp, R_CLEAN);
} else {
cfprintf("cfar: ERROR can't localize space for symbol %d\n", j);
break;
}
}
}
}/* END: for(numobjs) */
cfclose(scratch);
cfclose(desc);
}/* END: if(desc) */
else cfprintf("cfar: can't open file %s, CONTINUING\n", path);
}
static void
proc_objfile(char *path)
{
if(issymbol && (act == arCHECK))
{
objof(path);
return;
}
if(act & arEXTRACT)
extract_file(path);
if(act & arDELETE)
delete_file(path, 0);
if(act & (arADD|arREPLACE|arCHECK|arUPDATE))
insert_file(path);
}
static void
print_map(char *arch)
{
char path[256];
void *dirh;
CFDIRENT *d;
int i, j;
cfprintf("MAP of %s\n", arch);
if(map_entries) {
cfprintentries(arch);
cfsprintf(path, "%s/ipaths", arch);
cfprintentries(path);
cfsprintf(path, "%s/qipaths", arch);
cfprintentries(path);
cfsprintf(path, "%s/origins", arch);
cfprintentries(path);
cfsprintf(path, "%s/qorigins", arch);
cfprintentries(path);
cfsprintf(path, "%s/msyms", arch);
cfprintentries(path);
}
/* Print a list of origins */
cfprintf("\n-------- OUTSIDE ORIGINS ----------\n\n");
cfsprintf(path, "%s/origins", arch);
if((origins = cfopen(path, F_STAT, NULL)) != NULL)
{
Item orgnum;
if(cfhead(origins, &orgnum) == OK)
{
do {
memclr(path, 255);
cfkey(origins, path, 255);
cfprintf("oid:%u\t%s\n", orgnum.a0, path);
} while(cfnext(origins, &orgnum) == OK);
}
cfclose(origins);
}
/* Print the various libraries and entries */
cfprintf("\n-------- LIBRARIES ----------\n\n");
get_libtypes(arch);
for(i = 0; i < MAXLIBTYPE; ++i)
{
if(!ltypes[i])
continue;
cfsprintf(path, "%s/ltype%d", arch, i);
cfprintf("\nLibrary type %d\n", i);
get_libnums(path);
if(map_entries) {
cfprintf("------------ RAW ENTRIES -----------\n");
cfprintentries(path);
}
for(j = 0; j < 4096; ++j)
{
void *clib;
if(!lnums[j])
continue;
cfsprintf(path, "%s/ltype%d/lib%d", arch, i, j);
if((clib = cfopen(path, F_STAT, NULL)) != NULL) {
if(verbose)
cfprintf("------- lib%d %d bytes -------\n",
j, cfbytesused(clib));
else
cfprintf("------- lib%d --------\n", j);
cfhead(clib, NULL);
do {
char key[256];
int keylen;
memclr(key,256);
cfkey(clib, key, 255);
keylen = strlen(key);
if(key[keylen-1] == 'o') {
if(verbose) {
int dlen;
OrgItem oi;
cfdatalen(clib, &dlen);
key[keylen-1] = 't';
cffind(clib, key, keylen, &oi);
key[keylen-1] = 'o';
cfprintf(" %s bytes:%u oid:%u %s",
key, dlen, oi.sn, ctime(&oi.filetime));
}
else
cfprintf(" %s\n", key);
if(verbose) {
Item pakval;
char *cp, *sp;
key[keylen-1] = 'x';
cfmark(clib);
cffind(clib, key, keylen, &pakval);
cp = cflocalize(clib, &pakval);
for(sp=cp; *sp; sp += strlen(sp)+1)
{
cfprintf(" %s\n", sp);
}
cfrelease(cp, R_CLEAN);
cffind_mark(clib, NULL);
}
}
} while (cfnext(clib, NULL) == OK);
if(map_entries) {
cfprintf("------------ RAW ENTRIES -----------\n");
cfprintentries(clib);
}
cfclose(clib);
}
}
}
/* Print the list of stored files */
cfprintf("\n---------- STORED FILES ----------\n\n");
cfsprintf(path, "%s/fipaths", arch);
if((fipaths = cfopen(path, F_STAT, NULL)) != NULL)
{
OrgItem oi;
if(cfhead(fipaths, &oi) == OK)
{
do {
memclr(path, 255);
cfkey(fipaths, path, 255);
cfprintf("%s\toid:%u %s",
path, oi.sn, ctime(&oi.filetime));
} while(cfnext(fipaths, &oi) == OK);
}
if(map_entries) {
cfprintf("------------ RAW ENTRIES -----------\n");
cfprintentries(fipaths);
}
cfclose(fipaths);
}
if(map_bitmaps) {
cfprintf("\n------------ BITMAPS ---------------\n");
cfprintbitmaps(arch);
}
}
static void
Usage()
{
cfprintf("\
Usage: cfar [-acdflmrstvxCFMNS] cfpath [file...]\n\
Switch -- Meaning\n\
a Add file, do not overwrite\n\
c Check input files against library for clashes\n\
d Delete file\n\
f Freshen the archive (replace outdated files)\n\
l# Place file in libnum #, max:4095\n\
m Print archive map to stdout\n\
r Replace/Add file\n\
s 'file' is a symbol name not a file name (for extract/delete)\n\
t# Set libtype # 0=module, 1=class, 2=subsystem, max:15\n\
v Verbose\n\
x Extract file\n\
M Print to stdout, commands which would recreate the archive\n\
S Shrink archive\n\
F File mode, symbols not saved\n\
C If File mode, put file in a chunk\n\
N If File mode, give input file a new name (last part of cfpath)\n\
");
}
static int
get_nameparts(char *name)
{
int namlen = strlen(name);
int i,j;
basefile[0] = 0;
midpath[0] = 0;
innerpath[0] = 0;
midpart = 0;
if((lastpart = strrchr(name, '/')) != NULL)
++lastpart;
if(newname && !lastpart)
{
cfprintf("cfar: new filename enabled but not supplied\n");
Usage();
return 1;
}
for(i = namlen-1; i >= 0; --i)
{
if( name[i] == 'f'
&& name[i-1] == 'f'
&& name[i-2] == 'c'
&& name[i-3] == '.')
{
_strncpy(basefile, name, i+1);
if(&name[i] > lastpart)
{/* basefile is all there is */
lastpart = NULL;
}
else if(&name[i] != lastpart-2)
{/* there is more than just a root directory mentioned */
midpart = &name[i]+2;
_strncpy(midpath, midpart, (int)(lastpart-midpart-1));
}
j = 0;
if(midpart)
{
innerpath[0] = '/';
j = _strcpy(&innerpath[1], midpath);
++j;
}
if(lastpart && !newname)
{
innerpath[j++] = '/';
strcpy(&innerpath[j], lastpart);
}
}
}
return 0;
}
static void
shrink_archive(char *name)
{
void *x;
void *y;
cfprintf("cfar: shrink_archive %s\n", name);
if(verbose)
cfprintf("cfar: copy in\n");
x = cfcopy("MEMORY/shrink", name);
if(verbose)
cfprintf("cfar: copy out\n");
y = cfcopy(name, x);
if(verbose)
cfprintf("cfar: clean up\n");
cfunlink(x, NULL);
cfclose(y);
}
static void
stat_file(OrgItem *op, char *name, long namlen, long typ, long num,
char *arch, void *scratch)
{
Item orgtag;
char orgpath[1024];
char *in;
long orglen;
long sn = op->sn;
cfget(qorigins, &sn, 4, &orgpath, 1023);
orglen = strlen(orgpath);
if(typ >= 0 && orgpath[orglen-1] == 'a' && orgpath[orglen-2] == '.')
{/* This origin is a library */
/* Mark this origin or return if it has been marked */
orgtag.a2.size = op->sn;
orgtag.a0 = typ<<4 + num;
orgtag.a2.type = STO_VALUE;
/* libraries are handled differently */
if(cfinsert(scratch, &orgtag, 8, &orgtag) != OK)
return;
}
else if(typ >= 0)
{/* This origin is a directory, with an embedded file */
orgpath[orglen] = '/';
++orglen;
orglen += _strcpy(&orgpath[orglen], name);
}
else
{/* this origin is for a filemode entry */
in = strrchr(name, '/');
if(name[namlen-1] == '?')
typ = -2; /* the entry was made with newname */
else
{
orglen += _strcpy(&orgpath[orglen], in);
orgpath[orglen-1] = 0; /* strip tag */
}
}
/* The origin has not been examined, do it */
if(freshen)
{
CFSTAT s;
if(cfstat(orgpath, &s) == OK)
{
if(s.st_mtime > op->filetime)
{ /* REFRESH THIS ITEM */
++orglen;
if(typ < 0)
{
--namlen; /* clip tag */
cfpush_data(scratch, name, namlen);
cfpush_value(scratch, &namlen);
++namlen;
}
cfpush_data(scratch, orgpath, orglen);
cfpush_value(scratch, &orglen);
cfpush_value(scratch, &typ);
cfpush_value(scratch, &num);
}
}
else
cfprintf("cannot stat %s, CONTINUING\n", orgpath);
}
if(batfile)
{
if(typ < 0)
{/* filemode entry */
int c = (num == 1) ? 'C' : ' '; /* chunk flag */
if(typ == -2)
{/* rename needed */
name[namlen-1] = 0; /* clip off the tag */
cfprintf("cfar -FNr%c %s%s %s\n", c, arch, name, orgpath);
}
else
{/* no rename, clip off the last part of name */
*in = 0;
cfprintf("cfar -Fr%c %s%s %s\n", c, arch, name, orgpath);
*in = '/';
}
}
else
{/* object file entry */
cfprintf("cfar -rt%dl%d %s %s\n", typ, num, arch, orgpath);
}
}
}
static void
scan_archive(char *archname, void *scratch)
{
int i;
OrgItem oi;
/* Check stored object files */
get_libtypes(archname);
for(i = 0; i < MAXLIBTYPE; ++i)
{
char path[256];
int j;
if(!ltypes[i])
continue;
cfsprintf(path, "%s/ltype%d", archname, i);
get_libnums(path);
for(j = 0; j < 4096; ++j)
{
void *clib;
if(!lnums[j])
continue;
cfsprintf(path, "%s/ltype%d/lib%d", archname, i, j);
if((clib = cfopen(path, F_RDONLY, NULL)) != NULL) {
cfhead(clib, &oi);
do {
char key[256];
int keylen;
memclr(key,256);
cfkey(clib, key, 255);
keylen = strlen(key);
if(key[keylen-1] == 't') {
key[keylen-1] = 'o';
stat_file(&oi, key, keylen, i, j, archname, scratch);
}
} while (cfnext(clib, &oi) == OK);
cfclose(clib);
}
}
}
/* Check stored FILEMODE files */
cfhead(fipaths, &oi);
do {
char key[1024];
int keylen;
char tag;
int ischunk;
CFSTAT sbuf;
memclr(key,1024);
cfkey(fipaths, key, 1023);
keylen = strlen(key);
tag = key[keylen-1];
key[keylen-1] = 0;
if(cfsubstat(archive, &key[1], &sbuf) != OK)
{
cfprintf("cfar: can't stat internal file %s\n", key);
continue;
}
if(sbuf.st_mode & M_CHUNK)
ischunk = 1;
else
ischunk = 0;
key[keylen-1] = tag;
stat_file(&oi, key, keylen, -1, ischunk, archname, scratch);
} while (cfnext(fipaths, &oi) == OK);
}
static void
setup_version(int flag, char *archname)
{
KeyItem snval = 0;
cfinsert(archive, "ArVer", 5, &prgversion);
cfinsert(archive, "SN0", 3, &snval);
cfinsert(archive, "SN1", 3, &snval);
cfinsert(archive, "SN2", 3, &snval);
if(flag)
cfprintf("cfar: add archive property to %s\n", archname);
else cfprintf("cfar: create archive %s\n", archname);
}
static void
lose_backslashes(char *cp)
{
while(*cp) {
if(*cp == '\\')
*cp = '/';
++cp;
}
}
#ifdef SKELETON
int cfar(int argc, char **argv)
#else
int main(int argc, char **argv)
#endif
{
int err = 0;
int i, j;
long curbufs, newbufs;
#ifndef SKELETON
cfinit("cfar", 400, NULL);
if((err = oxlink_init(cf_find_file(argv[0], 0))) == 0)
{
#endif
/* Get the switches */
for(i = 1; i < argc; ++i)
{
int trimsize = 1;
lose_backslashes(argv[i]);
if(argv[i][0] == '-')
{
for(j=1; argv[i][j]; ++j)
{
switch(argv[i][j])
{
case 'f':
freshen = 1;
break;
case 'r':
act = arREPLACE;
replace = 1;
break;
case 'a':
act = arADD;
add = 1;
replace = 0;
break;
case 'x':
act |= arEXTRACT;
break;
case 'd':
act |= arDELETE;
break;
case 'v':
verbose = 1;
break;
case 'c':
act = arCHECK;
add = 0;
replace = 0;
break;
case 'S':
shrink = 1;
break;
case 'l':
libnum = atol(&argv[i][j+1]);
if(libnum < 0 || libnum > 4095)
err = 1;
break;
case 't':
libtype = atol(&argv[i][j+1]);
if(libtype < 0 || libtype >= MAXLIBTYPE)
err = 1;
break;
case 'm':
map = 1;
break;
case 's':
issymbol = 1;
break;
case 'B':
map_bitmaps = 1;
break;
case 'C':
chunk = 1;
break;
case 'F':
filemode = 1;
break;
case 'N':
newname = 1;
break;
case 'E':
map_entries = 1;
break;
case 'M':
batfile = 1;
break;
case '?':
err = 1;
break;
default:
break;
}
}/* END: switch */
trim:
/* Trim switch */
for(j = i; j < argc-trimsize; ++j)
argv[j] = argv[j+trimsize];
argc -= trimsize;
--i;
}/* END: if('-') */
}/* END: for(argc) (get switches) */
if(verbose) {
cfprintf("cff archiver Version:%u Copyright 1993, 1995 Norman D. Culver\n",
prgversion.a0);
}
if(err) Usage();
if(argc > 1)
err = get_nameparts(argv[1]);
/* Get the archive */
if(!err && ( (map|shrink|freshen|batfile)
|| (act && argc > 2)
|| (filemode && (act & (arDELETE|arEXTRACT)))
)
)
{
int mode = F_RDWR;
int new = 0;
if(act & (arADD|arREPLACE))
mode |= F_CREAT;
curbufs = cfcurbufs(); /* current size of localizer space */
#ifdef SKELETON
oxlink_close_libs();
#endif
if((archive = cfopen(basefile, mode, NULL)) != NULL)
{
if(!(cfobtype(archive) & OB_XFILE))
{
#if 0
cfsetverylazy(archive);
#endif
if(cfisnew(archive))
{/* new file, set up version and serial numbers */
setup_version(0, basefile);
new = 1;
}
else
{
if(cffind(archive, "ArVer", 5, &arversion) < FOUND)
{/* old .cff file without archive property, enable it */
setup_version(1, basefile);
new = 1;
}
}
if(cffind(archive, "ArVer", 5, &arversion) >= FOUND)
{
if(arversion.a0 <= prgversion.a0)
{
ipaths = cfsubopen(archive,"ipaths",F_RDWR|F_CREAT|F_SORTED,NULL);
qipaths = cfsubopen(archive,"qipaths",F_RDWR|F_CREAT, NULL);
origins = cfsubopen(archive,"origins",F_RDWR|F_CREAT|F_SORTED|F_BIGDIR, NULL);
qorigins = cfsubopen(archive,"qorigins",F_RDWR|F_CREAT, NULL);
msyms = cfsubopen(archive,"msyms",F_RDWR|F_CREAT|F_SORTED|F_HUGEDIR,NULL);
fipaths = cfsubopen(archive,"fipaths",F_RDWR|F_CREAT|F_SORTED,NULL);
if(!ipaths) {
cfprintf("cfar: can't open subdir `ipaths'\n");
goto xt;
}
if(!qipaths) {
cfprintf("cfar: can't open subdir `ipaths'\n");
goto xt;
}
if(!origins) {
cfprintf("cfar: can't open subdir `origins'\n");
goto xt;
}
if(!qorigins) {
cfprintf("cfar: can't open subdir `qorigins'\n");
goto xt;
}
if(!msyms) {
cfprintf("cfar: can't open subdir `msyms'\n");
goto xt;
}
if(!fipaths) {
cfprintf("cfar: can't open subdir `fipaths'\n");
goto xt;
}
#if 0
cfsetverylazy(msyms);
cfsetverylazy(ipaths);
cfsetverylazy(qipaths);
cfsetverylazy(origins);
cfsetverylazy(qorigins);
cfsetverylazy(fipaths);
#endif
if(filemode)
{/* PROCESS FILES STORED IN FILEMODE */
if(act & (arEXTRACT|arDELETE))
{
if(act & arEXTRACT)
out_entry();
else
del_entry();
}
else if(add || chunk || newname || replace)
{
subdir = open_middle(archive);
for(i = 2; i < argc; ++i)
{
lose_backslashes(argv[i]);
strlwr(argv[i]);
cur_orgtype = cfpathtrn(argv[i], &cur_orgpath);
proc_filemode(argv[i]);
free(cur_orgpath);
}
if(subdir)
cfclose(subdir);
}
else
{
cfprintf("cfar: incorrect filemode spec\n");
}
}
else if((argc < 3) && (freshen|batfile) && (!new))
{/* FRESHEN FILES IN ARCHIVE, OR PRINT BATCHFILE */
void *scratch = make_scratch();
/* check for files to freshen, print batfile if requested */
scan_archive(basefile, scratch);
act = arUPDATE;
replace = 1;
/* files to freshen will be on the stack */
while(cfstackdepth(scratch) > 0)
{
long filelen;
cfpop_value(scratch, &libnum);
cfpop_value(scratch, &libtype);
cfpop_value(scratch, &filelen);
cur_orgpath = malloc(filelen);
cfpop_data(scratch, cur_orgpath, filelen);
if(libtype < 0)
{/* Freshen a filemode file */
long namlen, x;
char *cur_name;
cfpop_value(scratch, &namlen);
cur_name = calloc(1, namlen+strlen(basefile)+2);
x = _strcpy(cur_name, basefile);
cfpop_data(scratch, &cur_name[x], namlen);
chunk = (libnum == 1) ? 1 : 0;
newname = (libtype == -2) ? 1 : 0;
if(!newname) cur_name[x] = 0;
get_nameparts(cur_name);
subdir = open_middle(archive);
proc_filemode(cur_orgpath);
if(subdir)
cfclose(subdir);
free(cur_name);
}
else if(open_curlib())
{/* Freshen an object file */
proc_objfile(cur_orgpath);
}
free(cur_orgpath);
}/* END: freshen files on stack */
cfclose(scratch);
}
else if(argc > 2)
{/* PROCESS OBJECT FILES STORED WITH SYMBOL TABLES */
if(open_curlib())
{/* Process the input files */
for(i = 2; i < argc; ++i)
{
if(!issymbol)
{
lose_backslashes(argv[i]);
strlwr(argv[i]);
}
cur_orgtype = cfpathtrn(argv[i], &cur_orgpath);
proc_objfile(argv[i]);
free(cur_orgpath);
}
}
}
cfclose(lib);
cfclose(plib);
cfclose(msyms);
cfclose(ipaths);
cfclose(qipaths);
cfclose(origins);
cfclose(qorigins);
cfclose(fipaths);
cfclose(archive);
if(shrink) shrink_archive(basefile);
if(map) print_map(basefile);
cfmodbufs(curbufs-cfcurbufs()); /* reset localizer space */
} else cfprintf("cfar: a version %u archive cannot be processed by a version %u program\n", arversion.a0, prgversion.a0);
} else cfprintf("cfar: %s is not an archive\n", basefile);
} else cfprintf("cfar: %s is not a cff database\n", basefile);
} else cfprintf("cfar: can't open archive %s\n", basefile);
} else {cfprintf("cfar: insufficient args\n"); Usage();}
#ifndef SKELETON
} else cfprintf("cfar: cannot find executable %s\n", argv[0]);
xt:
cfexit();
return 0;
#else
xt:
return 0;
#endif
}