home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Overload
/
ShartewareOverload.cdr
/
progm
/
cpgms.zip
/
LAR261.C
< prev
next >
Wrap
Text File
|
1985-08-05
|
27KB
|
1,121 lines
/*
* Lar - LU format library file maintainer
* by Stephen C. Hemminger
* Bedford MA
*
* DeSmet version T. Bonfield Feb 84
* DeSmet updates R. McVay Mar 84
*/
#define VERSION 2
#define REVISION 61
#define LAST_MOD "27 Oct 84"
/*
* DESCRIPTION
* Lar is a program to manipulate CP/M LU format libraries.
* The original CP/M library program LU is the product
* of Gary P. Novosielski. The primary use of lar is to combine several
* files together for upload/download to a personal computer.
*
* Usage: lar [-]key library [files] ...
*
* Key functions are:
* a - Add files to library (also creates new libraries)
* l - List directory of library
* e - Extract files from library
* p - Print files in library
* d - Delete files in library
* r - Reorganize library
*
* EXAMPLES:
* lar l foo.lbr list all files in FOO.LBR
* lar e foo.lbr 1.c 2.c extract files 1.c, 2.c from FOO.LBR
* lar p foo.lbr 1.c display 1.c from FOO.LBR
* lar a foo.lbr 1.c 2.c 3.c add or replace files in FOO.LBR
*
* When creating a new library, you will be prompted for the maximum
* number of entries it can contain. Assuming NEW.LBR doen't exist ...
* lar a new.lbr create an empty library
* lar a new.lbr a.c,b.c,d.c create NEW.LBR, add files.
*
* The Reorganize option causes <lbrfile>.tmp to be created, and
* the contents of the old library to be copied into it.
*
* This program is public domain software, no warranty intended or
* implied.
*
*
* PORTABILITY
* The original version by Stephan C. Hemminger was set up for
* Version 7 UNIX, and was not useable as is. It has been hacked
* to fit the DeSmet C compiler for MSDOS. The basic
* problems were: fread() and fwrite() incompatibility, no
* text/binary differentiation problem in MSDOS.
*
* Also, I have made random changes to the source merely to reflect
* my programming taste; he original code was quite good. I have also
* changed the wording of some errors, etc more in line with the current
* flavor of messages in the micro environment. The original Verbose
* flag option was removed, and made the default. No need to suppress
* what few messages and text there is.
*
* As mentioned before, ther is no problem with text or binary files;
* they are treated identically. Control-Z characters are added to the
* end of all files to round it up to a multiple of 128 bytes.
*
* Note that all files are kept as multiples of 128 bytes, to be
* compatible with the CP/M utility LU. This may present a problem
* with certain data files, but will be OK for text and .COM files
* anyways, and probably most other files.
* T. Bonfield
*
* v1.1- added the exception handler for a "dashed" option and a default
* library extension of .lbr.
* - fixed a bug that put the drive descriptor into the library file
* entry.
* v1.2- fixed a "member not found" bug by forcing all filenames to lower
* case.
* - changed the commands u->a and t->l to jive with LU better.
* v1.3- fixed subtle "casting" bug in copyentry().
* - copyentry() now uses acopy().
* - rewrote fcopy() and acopy() to use 16K copy buffer to
* eliminate disk thrashing on -a -e & -r.
* - fixed "not enough room" bug in reorg().
* v1.4- fixed bug in acopy() that crashed big member extractions.
* - increased copy buffer size to 32K - 128.
* v2.0-2.2- wildcards added by P.H. Mack based on v1.1
* v2.3-2.4- ???
* v2.5- wildcard references to members added to v1.4 (inspired by P.H. Mack)
* - cleaned up acopy()'s handling of -p option
* - generalized getname() & cvt_to_fcb a little
* v2.6- wildcards for -a
* v2.61-cleaned up a bit, sprinked in a few console status checks for
* MultiLink users
* R. McVay
*
* * Unix is a trademark of Bell Labs.
* ** CP/M is a trademark of Digital Research.
*/
#include <stdio.h>
/* Library file status values: */
#define ACTIVE 0
#define UNUSED 0xff
#define DELETED 0xfe
#define CTRLZ 0x1a
#define MAXFILES 256
#define SECTOR 128
#define BIGBUFF 32640
#define DSIZE (sizeof(struct ludir))
#define SLOTS_SEC (SECTOR/DSIZE)
#define equal(s1, s2) ( strcmp(s1,s2) == 0 )
#define FALSE 0
#define TRUE 1
#define BOOL int
/* Globals */
char *fname[MAXFILES];
BOOL ftouched[MAXFILES];
struct ludir { /* internal dir. stucture, 32 bytes */
char l_stat; /* 12 byte filename: */
char l_name[8];
char l_ext[3];
int l_off; /* offset in library, */
int l_len; /* length of file, */
char l_fill[16]; /* 16 byte filler, */
} ldir[MAXFILES];
int errcnt,
nfiles,
nslots;
char *getname(),
*strlower(),
*malloc();
long lseek();
char aname[20]; /* global library name reference */
main(argc, argv)
int argc;
char *argv[];
{
char *flagp,
*request;
if (argc < 3)
help();
if (*argv[1] == '-') /* strip the dash if present */
++argv[1];
*argv[1] = tolower(*argv[1]);
strcpy(aname, argv[2]); /* name of LBR file, */
if ((index(aname, "*") > -1) || (index(aname, "?") > -1))
error("wildcards not allowed in library name");
if (index(aname, ".") == -1) /* add default extension .lbr */
strcat(aname, ".lbr");
argv[2] = aname;
filenames(argc, argv);
switch (*argv[1])
{
case 'l': /* list table of contents */
table(aname);
break;
case 'a': /* add */
update(aname);
break;
case 'e': /* extract members */
getfiles(aname, FALSE);
break;
case 'p': /* print members */
getfiles(aname, TRUE);
break;
case 'd': /* delete members */
delete(aname);
break;
case 'r': /* reorganize library */
reorg(aname);
break;
default: /* bad request */
printf("err: unrecognized function [%s]\n\n", argv[1]);
help();
break;
}
exit(0);
}
/************************************************************************
* Get file names, check for dups, and initialize *
* This is where we'll encounter and expand wildcards *
************************************************************************/
filenames(ac, av)
int ac;
char *av[];
{
int i,
j;
errcnt = 0;
for (i = 3, j = 0; i < ac; i++, j++)
{
fname[j] = calloc(15, 1); /* we're going to copy all file args */
cvt_to_fcb(strlower(av[i]), fname[j]);
ftouched[j] = FALSE;
if (j >= MAXFILES)
error("Too many file names."); /* we'll double check in wildexp() */
if (index(fname[j], "?") > -1)
j = wildexp(j, *av[1]);
}
nfiles = j;
for (i = 0; i < nfiles; i++) /* pack 'em back up */
{
j = index(fname[i], ":") + 1;
strcpy(fname[i]+j, getname(fname[i]+j));
}
for (i = 0; i < nfiles; i++)
{
for (j = i + 1; j < nfiles; j++)
{
if (equal(fname[i], fname[j]))
{
printf("%s ", fname[i]);
error("duplicate file name");
}
}
}
}
/************************************************************************
* Do wildcard expansion of ambiguous name at fname[j]. *
* Return the resulting "expanded" index to the last name in the fname *
* list. *
************************************************************************/
wildexp(j, func)
int j;
char func;
{
#define GETDTA 0x2F00
#define FIRST 0x1100
#define NEXT 0x1200
FILE lfd;
char pattern[15], libname[15];
int i, k, mode, oj;
int our_dta_oset, our_dta_seg;
extern int _rax, _rbx, _rdx, _rds, _res;
struct fcb
{
char drvnum,
name[8],
ext[3],
misc[20];
} search_fcb;
strcpy(pattern, fname[j]); /* this allows us to return an */
free(fname[j]); /* index to a valid name, even */
oj = --j; /* if none is found here */
if (func == 'a')
{
/* Then expansion must be done on disk file names. *
* Sorry, but this is very compiler dependent. The *
* following code uses DeSmet's _doint() and a pre- *
* defined set of "register" variables. */
for (i = 0; i < 15; libname[i++] = '\0')
;
cvt_to_fcb(aname, libname);
_rax = GETDTA;
_doint(0x21);
our_dta_seg = _res;
our_dta_oset = _rbx;
/* The first order of business is to set up the fcb *
* the DOS will use as a pattern for the search. */
if (pattern[1] == ':') /* set up drive number */
{
search_fcb.drvnum = toupper(*pattern) - 'A' + 1;
strcpy(search_fcb.name, pattern + 2);
}
else
{
search_fcb.drvnum = '\0';
strcpy(search_fcb.name, pattern);
}
/* Now we'll scan any matching filenames into *
* fnames[] using an algorithm stolen shamelessly *
* from sq18u.c. */
for (mode = FIRST;; mode = NEXT)
{
csts(); /* for MultiLink users */
_rdx = search_fcb;
_rds = -1;
_rax = mode;
_doint(0x21);
if ((_rax & 0xFF) == 0xFF) /* no match found */
break;
++j;
if (j >= MAXFILES)
error("(wildexp) too many files");
else
fname[j] = calloc(15, 1);
if (!fname[j])
error("(wildexp) out of memory");
else
{
if (pattern[1] == ':')
{
fname[j][0] = *pattern;
fname[j][1] = ':';
i = 2;
}
else
i = 0;
_lmove(11, our_dta_oset + 1, our_dta_seg, &fname[j][i], _showds());
fname[j][i + 11] = '\0';
if (equal(libname, fname[j]))
{
free(fname[j]);
--j;
}
}
}
}
else
{
/* expansion is from names in library table of contents */
/* library name can't be ambiguous */
if ((lfd = open(aname, 2)) == -1)
cant(aname);
getdir(lfd);
for (i = 1; i < nslots; i++)
{
csts(); /* for MultiLink users */
if (ldir[i].l_stat == ACTIVE)
{
ldir[i].l_off = 0; /* setting up end of string */
if (amatch(pattern, ldir[i].l_name))
{
++j;
if (j >= MAXFILES)
error("(wildexp) too many files");
else
fname[j] = calloc(15, 1);
if (!fname[j])
error("(wildexp) out of memory");
else
strcpy(fname[j], ldir[i].l_name);
}
}
}
}
if (j == oj)
printf("wildexp: %s not matched\n", pattern);
return(j);
}
/************************************************************************
* try to match a filename to an ambiguous pattern; lengths must match *
************************************************************************/
amatch(pattern, fname)
char *pattern,
*fname;
{
while (*pattern && *fname)
{
if ((*pattern != '?') && (*pattern != *fname))
return(FALSE);
++pattern;
++fname;
}
return(*pattern == *fname);
}
/************************************************************************
* list the contents and statistics of the library *
************************************************************************/
table(lib)
char *lib;
{
FILE lfd;
int i,
total;
int active = 0,
unused = 0,
deleted = 0;
char *uname;
if ((lfd = open(lib,2)) == -1)
cant(lib);
getdir(lfd);
total = ldir[0].l_len;
printf("Name Index Length (128 byte blocks)\n");
printf("Directory %4u %6u\n", 0, total);
for (i = 1; i < nslots; i++)
{
csts(); /* for MultiLink users */
switch(ldir[i].l_stat)
{
case ACTIVE:
active++;
uname = getname(&ldir[i].l_name);
total += ldir[i].l_len;
printf("%-12s %4u %7u\n", uname,ldir[i].l_off,ldir[i].l_len);
break;
case UNUSED:
unused++;
break;
default:
deleted++;
break;
}
}
printf("-----------------------------\n");
printf("Total blocks %7u\n", total);
printf("\nLibrary %s has %u slots, %u deleted, %u active, %u unused\n",
lib, nslots, deleted, active, unused);
close(lfd);
not_found ();
}
/************************************************************************
* add new members to a library; create the library if necessary *
************************************************************************/
update(name)
char *name;
{
FILE lfd;
int i;
if ((lfd = open(name,2)) == -1)
{
if ((lfd = creat(name)) == -1)
cant(name);
initdir(lfd);
}
getdir(lfd); /* read directory, */
for (i = 0; (i < nfiles) && (errcnt == 0); i++)
addfil(fname[i], lfd);
if (errcnt != 0)
printf("fatal errors - last file may be bad\n");
putdir(lfd);
close(lfd);
}
/************************************************************************
* extract (or print if pflag) a library member *
************************************************************************/
getfiles(name, pflag)
char *name;
BOOL pflag;
{
FILE lfd,
ofd;
int i;
char *unixname;
if ((lfd = open(name,2)) == -1)
cant (name);
getdir(lfd);
for (i = 1; i < nslots; i++)
{
if (ldir[i].l_stat == ACTIVE)
{
unixname = getname(&ldir[i].l_name);
if (filarg(unixname))
{
printf("Extracting %s\n", unixname);
if (pflag)
ofd = STDOUT;
else
ofd = creat(unixname);
if (ofd == -1)
{
printf("%s - can't create output file\n",unixname);
errcnt++;
}
else
{
lseek(lfd, (long) ldir[i].l_off * SECTOR,0);
acopy(lfd, ofd, ldir[i].l_len);
if (!pflag)
close(ofd);
}
}
}
}
close(lfd);
not_found();
}
/************************************************************************
* mark a library directory entry as deleted *
************************************************************************/
delete(lname)
char *lname;
{
FILE f;
int i;
if ((f = open(lname,2)) == -1)
cant(lname);
if (nfiles <= 0)
error("delete by name only");
getdir(f);
for (i = 0; i < nslots; i++)
{
if (filarg(getname(&ldir[i].l_name)))
ldir[i].l_stat = DELETED;
}
not_found();
if (errcnt > 0)
printf("errors - library not updated\n");
else
putdir(f);
close(f);
}
/************************************************************************
* reorganize a library *
************************************************************************/
reorg(name)
char *name;
{
FILE olib,
nlib;
int oldsize,
i,
j;
struct ludir odir[MAXFILES];
char tmpname[SECTOR];
for (i = 0; (i < 8) && (name[i] != '.'); i++) /* copy filename, */
tmpname[i]= name[i]; /* strip off extention, */
tmpname[i]= '\0';
strcat(tmpname,".tmp"); /* make new name, */
if ((olib = open(name,2)) == -1)
cant(name);
if ((nlib = creat(tmpname)) == -1)
cant(tmpname);
getdir(olib);
printf("Old library has %d slots\n", oldsize = nslots);
for (i = 0; i < nslots ; i++)
copymem((char *)&odir[i], (char *)&ldir[i], sizeof(struct ludir));
initdir(nlib);
errcnt = 0;
for (i = j = 1; (i < oldsize) && !errcnt; i++)
{
if (odir[i].l_stat == ACTIVE)
{
printf("Copying: %-8.8s.%3.3s\n", &odir[i].l_name, &odir[i].l_ext);
copyentry(&odir[i], olib, &ldir[j], nlib);
if (++j > nslots)
{
errcnt++;
printf("Not enough room in new library\n");
}
}
}
close(olib);
putdir(nlib);
close(nlib);
if (errcnt)
{
printf("Errors, library not updated\n");
unlink(tmpname);
}
else
{
unlink(name); /* delete orig file, */
rename(tmpname,name); /* rename it, */
}
}
/************************************************************************
* print error message and exit *
************************************************************************/
help()
{
printf("LAR v%d.%d - %s\n", VERSION, REVISION, LAST_MOD);
printf("\nUsage: lar [-]<aledrp> library [files] ...\n");
printf("\nFunctions are:\n\ta - Add files to library (*)\n");
printf("\tl - List library directory\n");
printf("\te - Extract files from library (*)\n");
printf("\td - Delete files in library (*)\n");
printf("\tr - Reorganize library\n");
printf("\tp - Print files in library (*)\n");
printf("\nAssumed library extension is .LBR\n");
printf("\n(*) Wildcards allowed with these functions.\n");
exit(1);
}
/************************************************************************
* return index of t in s, -1 if none *
************************************************************************/
index(s, t)
char *s,
*t;
{
int i,
j,
k;
for (i = 0; s[i] != '\0'; i++)
{
for (j = i, k = 0; t[k] != '\0' && s[j] == t[k]; j++, k++)
;
if (t[k] == '\0')
return(i);
}
return(-1);
}
/************************************************************************
* print an error message string and exit *
************************************************************************/
error(str)
char *str;
{
printf("LAR: %s\n", str);
exit(1);
}
/************************************************************************
* can't perform function because of file error *
************************************************************************/
cant(name)
char *name;
{
printf("%s: File open error\n", name);
exit(1);
}
/************************************************************************
* read the directory of a library into the ludir structure *
************************************************************************/
getdir(f)
FILE f;
{
int cnt;
lseek(f,0L,0);
if (read(f,&ldir[0],DSIZE) != DSIZE) /* read 1st entry to find */
error("No directory\n"); /* number of slots, */
nslots = ldir[0].l_len * SLOTS_SEC;
cnt = DSIZE * (nslots - 1); /* already read one slot, */
if (read(f,&ldir[1],cnt) != cnt)
error("Can't read directory - is it a library?");
}
/************************************************************************
* write the ludir structure to the beginning of the library file *
************************************************************************/
putdir(f)
FILE f;
{
lseek(f,0L,0);
if (write(f,&ldir,nslots * DSIZE) != (nslots * DSIZE))
error("Can't write directory - library may be botched");
}
/************************************************************************
* format a virgin library directory *
************************************************************************/
initdir(f)
FILE f;
{
int i;
int numsecs;
char line[80];
do
{
puts ("Number of slots to allocate: ");
gets(line);
putchar('\n');
nslots = atoi (line);
if (nslots < 1)
{
nslots = 0;
printf("Must have at least one!\n");
}
else if (nslots > MAXFILES)
{
nslots = 0;
printf("Too many slots\n");
}
}
while (nslots == 0);
numsecs = nslots / SLOTS_SEC;
if (nslots != numsecs * SLOTS_SEC)
++numsecs;
nslots = numsecs * SLOTS_SEC;
for (i = 0; i < nslots; i++)
{
ldir[i].l_stat = UNUSED;
blank_fill(&ldir[i].l_name,8);
blank_fill(&ldir[i].l_ext,3);
}
ldir[0].l_stat = ACTIVE;
ldir[0].l_len = numsecs;
putdir(f);
}
/************************************************************************
* Fill a string with blanks, no trailing null *
************************************************************************/
blank_fill(s, n)
char *s;
int n;
{
while (n--) *s++= ' ';
}
/************************************************************************
* convert nm.ex to a Unix style string *
************************************************************************/
char *getname(nm)
char *nm;
{
static char namebuf[14];
int i,
j;
for (i = 0; (i < 8) && (nm[i] != ' '); i++)
namebuf[i] = tolower(nm[i]);
namebuf[i++] = '.';
j = i;
for (i = 8; (i < 11) && (nm[i] != ' '); i++, j++)
namebuf[j] = tolower(nm[i]);
namebuf[j] = '\0';
return namebuf;
}
/************************************************************************
* check if name matches argument list *
************************************************************************/
filarg(name)
char *name;
{
register int i;
if (nfiles <= 0)
return 1;
for (i = 0; i < nfiles; i++)
if (equal(name, fname[i]))
{
ftouched[i] = TRUE;
return 1;
}
return 0;
}
/************************************************************************
* tolower() all characters in a string *
************************************************************************/
char *strlower(string)
char *string;
{
char *ptr;
ptr = string;
while (*string)
{
*string = tolower(*string);
++string;
}
return(ptr);
}
/************************************************************************
* print an error message for unmatched argument and bump errcnt *
************************************************************************/
not_found()
{
register int i;
for (i = 0; i < nfiles; i++)
if (!ftouched[i])
{
printf("%s : not in library.\n", fname[i]);
errcnt++;
}
}
/************************************************************************
* copy nsec*128 bytes from one file to another *
************************************************************************/
acopy(fdi, fdo, nsecs)
FILE fdi,
fdo;
int nsecs;
{
char *buf;
int n,
i;
if ((buf = malloc(BIGBUFF)) == 0)
error("acopy: not enough memory for BIGBUFF");
do
{
csts(); /* for MultiLink users */
if ((n = read(fdi, buf, min(BIGBUFF/SECTOR, nsecs) * SECTOR)) == -1)
error("acopy: read error");
if (fdo == STDOUT)
{
for (i = 0; (i < n) && (buf[i] != CTRLZ); i++)
putchar(buf[i]);
if (buf[i] == CTRLZ)
puts("\n\n");
}
else if (write(fdo, buf, n) != n)
error("acopy: write error");
nsecs -= n/SECTOR;
}
while (nsecs);
free(buf);
}
/************************************************************************
* return the lesser of two numbers *
************************************************************************/
min(num1, num2)
int num1,
num2;
{
if (num1 < num2)
return(num1);
else
return(num2);
}
/************************************************************************
* add a member to the library *
************************************************************************/
addfil(name, lfd)
char *name;
FILE lfd;
{
FILE ifd;
int secoffs,
numsecs,
i;
if ((ifd = open(name,2)) == -1)
{
printf("--- can't find library %s\n",name);
errcnt++;
return;
}
for (i = 0; i < nslots; i++)
{
if (equal(getname(&ldir[i].l_name), name))
{
printf("Updating existing file %s\n", name);
break;
}
if (ldir[i].l_stat != ACTIVE)
{
printf("Adding new file %s\n", name);
break;
}
}
if (i >= nslots)
{
printf("Can't add %s, library is full\n", name);
errcnt++;
return;
}
ldir[i].l_stat = ACTIVE;
name += index(name, ":") + 1; /* remove drive descriptor */
cvt_to_fcb(name, &ldir[i].l_name);
/* append to end */
secoffs = lseek(lfd, 0L, 2) / SECTOR;
ldir[i].l_off = secoffs;
numsecs = fcopy(ifd, lfd);
ldir[i].l_len = numsecs;
close(ifd);
}
/************************************************************************
* copy a complete file into the library *
************************************************************************/
fcopy(ifd, ofd)
FILE ifd,
ofd;
{
int total = 0;
int n;
char *sectorbuf;
if ((sectorbuf = malloc(BIGBUFF)) == 0)
error("fcopy: no buffer");
do
{
csts(); /* for MultiLink users */
if ((n = read(ifd, sectorbuf, BIGBUFF)) == -1)
error("fcopy: read error");
while (n % SECTOR)
sectorbuf[n++] = CTRLZ;
if (write(ofd, sectorbuf, n) != n)
error("fcopy: write error");
total += n/SECTOR;
}
while (n == BIGBUFF);
free(sectorbuf);
return total;
}
/************************************************************************
* copy a directory entry from one ludir structure to another *
************************************************************************/
copyentry(old, of, new, nf)
struct ludir *old,
*new;
FILE of,
nf;
{
int secoffs,
numsecs;
new->l_stat = ACTIVE;
copymem(&new->l_name, &old->l_name, 8);
copymem(&new->l_ext, &old->l_ext, 3);
lseek(of, (long)old->l_off * SECTOR, 0); /* home of subtle bug */
secoffs = lseek(nf, 0L, 2) / SECTOR;
new->l_off = secoffs;
numsecs = old->l_len;
new->l_len = numsecs;
acopy(of, nf, numsecs);
}
/************************************************************************
* memory move used by copyentry() *
************************************************************************/
copymem(dst, src, n)
char *dst,
*src;
unsigned n;
{
while(n--)
*dst++ = *src++;
}
/************************************************************************
* Convert a normal asciiz string to MSDOS/CPM FCB format. *
* Make the filename portion 8 characters, extention 3 maximum. *
* Expand *'s into ?'s. *
* NOTE: doesn't end outname[] with \0, doesn't strip drive descriptor *
************************************************************************/
cvt_to_fcb(inname, outname)
char *inname;
char outname[];
{
char c;
int i,j;
for (i = 0; i <= index(inname, ":"); i++) /* do drive descriptor */
outname[i] = inname[i]; /* if present */
inname += i;
outname += i;
for (i = 0; i < 8; i++) /* now expand the inname */
{
switch (*inname)
{
case '\0': /* if null or */
case '.': /* if a dot */
outname[i] = ' '; /* pad with blanks, */
break;
case '*': /* if asterisk */
outname[i] = '?'; /* pad with ?'s */
break;
default:
outname[i] = toupper(*inname);
++inname;
}
}
if (*inname == '*') /* handle the *.ext case */
++inname;
if (*inname == '.')
++inname;
for (; i < 11; i++) /* now expand the extension */
{
switch (*inname)
{
case '\0': /* if null or */
outname[i] = ' '; /* pad with blanks, */
break;
case '*': /* if asterisk */
outname[i] = '?'; /* pad with ?'s */
break;
case '.': /* if a dot, */
error("(cvt_to_fcb) invalid name"); /* error out */
break;
default:
outname[i] = toupper(*inname);
++inname;
}
}
return;
}