LIBRARY MANAGEMENT and Libutil in Aztec C

Started by BillBuckels, April 14, 2008, 01:19 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

BillBuckels

Libraries In General

To avoid typing so many object file names on the link line, libraries of object files were long ago dreamed-up so that linkers could just have a single library name reference for a bunch of these objects.

That doesn't sound very scientific does it? It'll do.

Here's something else you need to know.

Headers In General

If you include header files in a program and they describe functions in a library that doesn't mean that those functions will end-up linked in to your programs. It just means that the linker will use more memory to store all that useless information. So don't put a bunch of includes for headers that reference library functions that you don't use into your program.

Linking in General

I am talking about old-fashioned libraries and not DLL's like in Windows. These are statically bound at compile time and not dynamically bound at runtime with implied library references. If you don't understand what I said just know the following:

If you link to a library in Aztec C as in most if not all C compilers, only the library function modules that you use explictly and indirectly will be added to your finished program by the linker. No additional code will be added that is not called.

This IS the function of the linker. There's lots written on this topic if you want to go further.

I don't and I want to finish off by providing you with the source code for the library manager used with Aztec C64 and also Aztec-CZ80 which builds CP/M 80 programs that run on the C128.

Building Old Programs and Errors

I have even ported C-code from the 70's from PDP11's and an amazing amount of other old C-code which still compiles under Microsoft Visual Studio 2005. I know through experience what to change and what to do to make it all work. The main part of this process is to fix all the errors and also all the warnings. I take great pride in the fact that you can build anything that I put-out on the Internet and BBS's before it without either errors or warnings and also anything that I write anywhere else for that matter. So too should you always take great pride in doing so because then you haven't made a mess for someone else. The people that you can make a mess for starts with yourself and said mess can extend to erasing your entire hard disk and other major annoyances so listen up!

The following code compiles without warnings or errors and has been fully tested as with everything I do. It's not perfect but it is genuine vintage retro computing and it will do.

Libutil - Aztec C Library Utility

Quote from: Aztec C64 Documentation
libutil v1.05g fixups (C) Copyright Bill Buckels 2008. All Rights Reserved.
usage:  libutil [-artx] [-o libraryname.lib] name1.rel name2.rel ...
create: libutil [-o libraryname.lib] name1.rel name2.rel ...

-a add one or more object (.rel) modules into an existing library...
-r replace one or more object (.rel) modules into an existing library.
   add and replace are effectively and functionally the same command.
-t list all object (.rel) modules in a library.
-x extract one or more object (.rel) modules from a library.
   name1.rel name2.rel etc. (names must be as originally entered)

note: this utility has not been extended beyond its original capabilities.
      it is intended for use with Aztec C v1.0x and is not compatible with
      later versions that used lb.exe and its library format(s).

If you are using the x86 EXE, this was compiled under Aztec C86 v4.10d and is
for the Aztec C65 v1.06e MS-DOS C64 cross development environment using
the C II v1.05h compiler. The libutil source originated in Aztec C for CP/M80.
the output has been changed to default to the .rel object extension and
minor fixups were required for x86 OS (MS-DOS XP) and compiler compatibility.



#define C64 1

#ifdef UNIX
#include <stdio.h>
#define FNSIZE 100
#define EXTEND ".rel"
#else
#ifdef C64
#define EXTEND ".rel"
#else
#define EXTEND ".o"
#endif
#ifdef MPU6502
#include "/usr/xbin/mtuio.h"
#else
#include "stdio.h"
#define FNSIZE 20
#endif

#endif
#include "object.h"
#define MAXMOD 256
#define GRAIN 128 /* boundary to start new modules on within the file */
#define GRSHFT 7 /* log base 2 of GRAIN */

long ftell();
int append, extract, table;
FILE *libfp;

/* BB */
char *gets();
char *rindex();
char *index();

#define clear(addr,len,val) memset(addr,val,len)


char *usage = "libutil v1.05g fixups (C) Copyright Bill Buckels 2008. All Rights Reserved.\n"
"usage:  libutil [-artx] [-o libraryname.lib] name1.rel name2.rel ...\n"
"create: libutil [-o libraryname.lib] name1.rel name2.rel ...\n\n"
"-a add one or more object (.rel) modules into an existing library...\n"
"-r replace one or more object (.rel) modules into an existing library.\n"
"   add and replace are effectively and functionally the same command.\n"
"-t list all object (.rel) modules in a library.\n"
"-x extract one or more object (.rel) modules from a library.\n"
"   name1.rel name2.rel etc. (names must be as originally entered)\n\n"
"note: this utility has not been extended beyond its original capabilities.\n"
"      it is intended for use with Aztec C v1.0x and is not compatible with\n"
"      later versions that used lb.exe and its library format(s).\n\n"
"If you are using the x86 EXE, this was compiled under Aztec C86 v4.10d and is\n"
"for the Aztec C65 v1.06e MS-DOS C64 cross development environment using\n"
"the C II v1.05h compiler. The libutil source originated in Aztec C for CP/M80.\n"
"the output has been changed to default to the .rel object extension and\n"
"minor fixups were required for x86 OS (MS-DOS XP) and compiler compatibility.";

main(argc,argv)
int argc; char **argv;
{
FILE *fp, *outfp;
register char *cp, *tp;
char *libname, templib[FNSIZE];
struct header head;
unsigned i, size, lastone, global;
struct library lib;
struct l_item *item;
struct gbltab sym;
int count;
long next, origpos, lastdir;
struct {
char modname[10];
char filename[FNSIZE];
} modlist[MAXMOD], *modp, *maxmod;
char *bufp, cmdbuf[130];

libname = "libc.lib";
outfp = NULL;
if ( argc < 2 ) {
use:
        /* BB more usage information */
        puts(usage);
exit(4);
}

while (--argc) {
cp = *++argv;
if (*cp++ != '-')
break;
while (*cp) {
switch (*cp++) {
default:
printf("bad argument: %s\n",cp);
goto use;
case 'o': case 'O':
libname = *++argv;
--argc;
continue;
case 'a': case 'A':
append = 1;
continue;
case 'r': case 'R':
append = 1;
continue;
case 'x': case 'X':
extract = 1;
continue;
case 't': case 'T':
table = 1;
continue;
}
}
}

makename(templib, libname, ".$$$");
if (extract || table) {
if ((libfp = fopen(libname,"r")) == NULL) {
opnerr:
printf("Cannot open library: %s!\n",libname);
exit(4);
}
if (extract)
xtrct(argc,argv);
else
dir();
exit(0);
} else if (append) {
if ((libfp = fopen(libname, "r")) == NULL)
goto opnerr;
if ((outfp = fopen(templib, "w+")) == NULL)
goto opnerr;
} else {
if ((outfp = fopen(templib, "w+")) == NULL)
goto opnerr;
}

if ( argc < 1 )
goto use;
clear(&lib, sizeof lib, 0);
lib.lb_magic = H_LIBRARY;
item = lib.lb_items;
lastdir = 0;
fwrite(&lib, sizeof lib, 1, outfp);

modp = modlist;
bufp = cmdbuf;
*bufp = 0;
while ( argc ) {
if (strcmp(*argv, ".") == 0) {
for (;;) {
while (*bufp == ' ' || *bufp == '\t')
++bufp;
if (*bufp != 0)
break;
bufp = cmdbuf;
if (gets(cmdbuf)==NULL || *bufp==0 || strcmp(bufp, ".")==0) {
*bufp = 0;
--argc;
++argv;
goto nxtarg;
}
}
for (cp = modp->filename ; *bufp ; *cp++ = *bufp++)
if (*bufp == ' ' || *bufp == '\t')
break;
*cp = 0;
} else {
strcpy(modp->filename, *argv++);
--argc;
}
if ((cp = rindex(modp->filename,'/')) != NULL
|| (cp = rindex(modp->filename,':')) != NULL)
++cp;
else
cp = modp->filename;

clear(modp->modname, sizeof modp->modname, 0);
for (tp = modp->modname, i = 0 ; i < 8 ; ++i) {
if (*cp == 0 || *cp == '.')
break;
*tp++ = tolower(*cp++);
}

if (index(modp->filename,'.') == NULL)
strcat(modp->filename, EXTEND);
if (++modp >= modlist+MAXMOD) {
printf("too many module names!\n");
exit(4);
}
nxtarg: ;
}
maxmod = modp;
if (modp == modlist) {
printf("No modules to add or replace.\n");
fclose(outfp);
unlink(templib);
exit(4);
}

for (;;) {
if (libfp)
fp = libfp;
else {
for (modp = modlist ; modp < maxmod ; ++modp)
if (modp->filename[0])
goto fndmod;
break;

fndmod:
if ((fp = fopen(modp->filename,"r")) == NULL) {
printf("cannot open input: %s\n", modp->filename);
exit(4);
}
modp->filename[0] = 0;
if (libfp)
printf("replacing module: %s\n", modp->modname);
else
printf("adding module: %s\n", modp->modname);
}

while (fread(&head,sizeof(head),1,fp) == 1) {
if (head.h_magic == H_LIBRARY) {
fseek(fp, (long)(sizeof(struct library)-sizeof(head)), 1);
continue;
}
if (head.h_magic != H_MAGIC)
break;
origpos = ftell(fp) - sizeof head;
next = origpos + head.h_next;
lastone = ftell(outfp) >> GRSHFT;
if (head.h_name[0] == 0) {
strncpy(head.h_name, modp->modname, 8);
} else {
if (fp == libfp) {
for (modp = modlist ; modp < maxmod ; ++modp)
if (modp->filename[0] != 0 &&
strncmp(modp->modname,head.h_name,8) == 0) {
fseek(libfp, next, 0);
goto fndmod;
}
}
for (cp = head.h_name, i = 0 ; *cp && i < 8 ; ++i, ++cp)
*cp = tolower(*cp);
}
if ((global = head.h_global) != sizeof head) {
head.h_next = (head.h_end + GRAIN-1) & -GRAIN;
head.h_global = sizeof head;
head.h_local = sizeof head + head.h_local - global;
head.h_end = sizeof head + head.h_end - global;
}

if (fwrite(&head,sizeof(head),1,outfp) <= 0) {
ioerr:
printf("Error writting library!\n");
fclose(outfp);
unlink(templib);
exit(4);
}

if (global == sizeof head) {
if (copyfile(fp, outfp, head.h_next - sizeof head))
goto ioerr;
fseek(fp, origpos+global, 0);
} else {
fseek(fp, origpos+global, 0);
if (copyfile(fp, outfp, head.h_end - head.h_global))
goto ioerr;
fseek(fp, origpos+sizeof head, 0);
if (copyfile(fp, outfp, global-sizeof(head)))
goto ioerr;
}
padout(outfp, GRAIN);

count = (head.h_local - head.h_global) / sizeof (sym);
while ( count-- ) {
fread(&sym, sizeof sym, 1, fp);
if ((sym.g_flags&S_GLOBL) && sym.g_type != S_UND) {
if (item >= lib.lb_items+LBSIZE) {
padout(outfp, GRAIN);
lib.lb_next = ftell(outfp) >> GRSHFT;
fseek(outfp, lastdir, 0);
fwrite(&lib, sizeof lib, 1, outfp);
lastdir = lib.lb_next << GRSHFT;
fseek(outfp, lastdir, 0);
clear(&lib, sizeof lib, 0);
lib.lb_magic = H_LIBRARY;
fwrite(&lib, sizeof lib, 1, outfp);
item = lib.lb_items;
}
strncpy(item->li_name, sym.g_name, 8);
item->li_pos = lastone;
++item;
}
}
fseek(fp,next,0);
}
if (fp == libfp)
libfp = NULL;
fclose(fp);
}

fseek(outfp, lastdir, 0);
fwrite(&lib, sizeof lib, 1, outfp);
if (fclose(outfp) != 0)
goto ioerr;
    /* BB remove old library - otherwise rename cannot work */
unlink(libname);
rename(templib, libname);
exit(0);
}

padout(fp, bound)
unsigned bound; FILE *fp;
{
register unsigned i, next;

i = ftell(fp);
next = (i+bound-1) & -bound;
for ( ; i < next ; ++i )
putc(0,fp); /* pad out block */
}

dir()
{
struct header head;
register int i;

i = 6;
while (fread(&head,sizeof(head),1,libfp) == 1) {
if (head.h_magic == H_LIBRARY) {
fseek(libfp, (long)(sizeof(struct library)-sizeof(head)), 1);
continue;
}
if (head.h_magic != H_MAGIC)
break;
printf("%-12.8s", head.h_name);
if (--i == 0) {
putchar('\n');
i = 6;
}
fseek(libfp, (long)(head.h_next - sizeof(head)), 1);
}
if (i != 6)
putchar('\n');
fclose(libfp);
}

xtrct(argc,argv)
char **argv;
{
struct header head;
register int i;
long pos;

pos = 0;
for (pos = 0; fread(&head,sizeof(head),1,libfp) == 1; fseek(libfp,pos,0)) {
if (head.h_magic == H_LIBRARY) {
pos += sizeof(struct library);
continue;
}
if (head.h_magic != H_MAGIC)
break;
pos += head.h_next;
if (argc != 0) {
for (i = 0 ; i < argc ; ++i) {
if (strncmp(argv[i],head.h_name) == 0)
goto found;
}
continue;
}
found:
cpyout(&head);
}
fclose(libfp);
}

cpyout(hdr)
register struct header *hdr;
{
char name[20];
FILE *fp;
register int c;
int i, size;

if (hdr->h_name[0] == 0)
return;
size = hdr->h_next;
hdr->h_next = (hdr->h_next+255) & -256;
strncpy(name,hdr->h_name,8);
name[8] = 0;
strcat(name, EXTEND);
printf("Extracting: %s\n",name);
if ((fp = fopen(name,"w")) == NULL) {
printf("Cannot create %s\n",name);
exit(4);
}

if (fwrite(hdr, sizeof(struct header), 1, fp) != 1) {
ioerr:
printf("Error writing file: %s\n",name);
exit(4);
}

for (i = 0 ; i < size ; ++i)
#ifndef UNIX
if (putc(getc(libfp), fp) < 0)
goto ioerr;
#else
putc(getc(libfp), fp);
if (ferror(fp))
goto ioerr;
#endif

for ( ; i < hdr->h_next ; ++i)
putc(0,fp); /* pad out file */
if (fclose(fp) != 0)
goto ioerr;
}

copyfile(input, output, size)
FILE *input, *output;
{
while (size-- > 0)
#ifndef UNIX
if (putc(getc(input), output) < 0)
return -1;
#else
putc(getc(input), output);
if (ferror(output))
return -1;
#endif
return 0;
}

#ifdef UNIX
clear(cp, len, val)
register char *cp; register unsigned len;
{
while (len--)
*cp++ = val;
}

rename(onam, nnam)
register char *onam, *nnam;
{
unlink(nnam);
link(onam, nnam);
unlink(onam);
}

tolower(c)
register int c;
{
if (c >= 'A' && c <= 'Z')
return c - 'A' + 'a';
return c;
}

#endif

makename(dest,src,ext)
char *dest,*src,*ext;
{
register char *cp;

strcpy(dest,src);
if (cp = rindex(dest,'.'))
strcpy(cp,ext);
else
strcat(dest,ext);
}

MAKEFILE

# -------------------------------------------
# makefile by bill buckels 1997
# -------------------------------------------

libutil.exe: libutil.o
            ln libutil.o c.lib
            del libutil.o
            copy libutil.exe ..\libutil.exe
            del libutil.exe
            @echo All Done!

libutil.o: libutil.c
           cc libutil.c