ronbo@vixen.uucp (Ron Hitchens) (10/23/89)
Have you been wanting to create your own Amiga disk-based run-time
libraries, but haven't been able to figure out how to do it? Well, here's
a handy little utility that will do all the hard work for you. Genlib
will let you write a run-time library in C nearly as easily as writing a
conventional program.
I wrote Genlib to help me create a run-time library for a commercial
product that we're developing. It began life as a hack, but evolved into
a stable, professional grade utility. I considered maybe developing it
further into a product, but decided instead to release it to the
world to help stimulate talented hackers to create useful libraries.
There are two shar files to this posting, this is the first, and
contains Genlib and its template files. The second shar contains the
docs and source for a sample run-time library.
Genlib is not public domain, but may be redistributed freely (see
the notice in README). Permission is explictly given for Fred Fish to
include it in his collection, and for posting to services like CompuServe.
Note the warning in the makefile for the sample library, make sure your
stack is big enough before running make.
Enjoy.
Ron Hitchens _____ | ronbo@vixen.uucp - Smart uucp
Sleepless /(O O)\ | ...!cs.utah.edu!caeco!vixen!ronbo - Stupid uucp
Software (^) | hitchens@cs.utexas.edu - Internet
"To be is to do" -Socrates "To do is to be" -Sartre "Do be do be do" -Sinatra
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by vixen!ronbo on Sun Oct 22 15:40:53 MDT 1989
# Contents: README MANIFEST asmhdr.template chdr.template library.template
# stubs.template main.c load.c dump.c parse.c getopt.c genlib.h makefile
echo x - README
sed 's/^@//' > "README" <<'@//E*O*F README//'
Genlib - Automatically Generate Run-Time Libraries
Genlib is a program and a set of template files that will allow you
to create your own Amiga disk-based run-time libraries. It automatically
generates the various header and code files that are necessary to build
a library code file in the proper format for use by the Amiga system.
Genlib is setup so that you can write the majority of your library code
in C (specifically Manx Aztec C), although assembler routines can also
be placed in the same library, so long as they take arguments on the
stack like C does.
Included in this posting are:
The genlib program, which takes as input a specification file which
defines various parameters of the library to be built, and a list
of functions that will exist in the library. It creates include
files for both C and assembler, and two assembler source files;
one which is the run-time library boilerplate interface code, and
one which defines the link-library interface glue which allows
application programs to call-through into the runtime library.
Four template files. These files are the skeletons of the four
files that genlib will produce. The information derived from the
specification file is inserted into them to produce finished
source code for the new library.
Sample library code. Three C source files are provided, along
with the matching genlib specification file, from which can be
built a sample run-time library. A makefile is also provided
to automatically generate and compile the sample library.
Test program. A simple test application is provided to test
the sample run-time library.
See the file Doc/usage for information on how to run genlib, and the
format of the specification file.
Copyright 1989, Sleepless Software, All Rights Reserved
Genlib is not public domain, it is copyright by Sleepless Software.
You are free to redistribute and re-post it, so long as you keep it all
together (including source), you don't remove our original copyright
notices, and you don't charge anything for it other than reasonable
copying costs. Also, there are no restrictions on the libraries you
generate with it. In other words, you are free to sell a library which
you used genlib to create, but you may not sell genlib itself without
our permission.
Sleepless Software
45 N. Main
North Salt Lake, Utah 84054
(801) 292-2190
Ron Hitchens _____ | ronbo@vixen.uucp - Smart uucp
Sleepless /(O O)\ | ...!cs.utah.edu!caeco!vixen!ronbo - Stupid uucp
Software (^) | hitchens@cs.utexas.edu - Internet
"To be is to do" -Socrates "To do is to be" -Sartre "Do be do be do" -Sinatra
@//E*O*F README//
chmod u=rw,g=r,o=r README
echo x - MANIFEST
sed 's/^@//' > "MANIFEST" <<'@//E*O*F MANIFEST//'
Genlib - Shipping manifest
Genlib is posted in two shar files. When you have unpacked both shars
you should have the following files:
Shar 1:
README
MANIFEST
asmhdr.template The four template files
chdr.template
library.template
stubs.template
main.c Source for the Genlib program
load.c
dump.c
parse.c
getopt.c
genlib.h
makefile Makefile for genlib
Shar 2:
Doc/ Sub-directory for doc files
Doc/usage How to use Genlib
Doc/programmer.notes How to code run-time libraries
Doc/hacker.notes Notes for hackers of Genlib
Sample/ Sub-directory for Sample library source
Smaple/makefile Makefile for sample lib and test program
Sample/foo.gen Spec file for the sample library
Sample/init.c Source for the sample library
Sample/dialog.c
Sample/timer.c
Sample/test.c Program to test the library
Ron Hitchens _____ | ronbo@vixen.uucp - Smart uucp
Sleepless /(O O)\ | ...!cs.utah.edu!caeco!vixen!ronbo - Stupid uucp
Software (^) | hitchens@cs.utexas.edu - Internet
"To be is to do" -Socrates "To do is to be" -Sartre "Do be do be do" -Sinatra
@//E*O*F MANIFEST//
chmod u=rw,g=r,o=r MANIFEST
echo x - asmhdr.template
sed 's/^@//' > "asmhdr.template" <<'@//E*O*F asmhdr.template//'
- ------------------------------------------------------------------------
- Genlib - Assembler header file template
- ------------------------------------------------------------------------
+AIFND
; ------------------------------------------------------------------------
+ACOMMENT
;
+AGENTIME
;
; This file automatically generated by genlib
; Genlib is Copyright 1989, Sleepless Software
; Author: Ron Hitchens (ronbo@vixen.uucp) (801) 292-2910
; ------------------------------------------------------------------------
include 'exec/types.i'
include 'exec/lists.i'
include 'exec/libraries.i'
+ASTRUCT
UBYTE lb_Flags
UBYTE lb_pad
ULONG lb_LibA4
- The above fields must be defined as shown, any additional
- fields may be added to the struct following the LibA4 field
+ASIZEOF
+ALIBNAME
+AENDC
@//E*O*F asmhdr.template//
chmod u=rw,g=r,o=r asmhdr.template
echo x - chdr.template
sed 's/^@//' > "chdr.template" <<'@//E*O*F chdr.template//'
- ----------------------------------------------------------------------
- Genlib - C header file template
- ----------------------------------------------------------------------
+CIFDEF
/*
* ---------------------------------------------------------------------
+CCOMMENT
*
+CGENTIME
*
* This file automatically generated by genlib
* Genlib is Copyright 1989, Sleepless Software
* Author: Ron Hitchens (ronbo@vixen.uucp) (801) 292-2910
* ---------------------------------------------------------------------
*/
#include <exec/types.h>
#include <exec/lists.h>
#include <exec/libraries.h>
+CSTRUCT
struct Library LibNode;
unsigned char Flags;
unsigned char pad;
unsigned long LibA4;
- The above fields must be defined as shown, any additional
- fields may be added to the struct following the LibA4 field
};
+CLIBNAME
+CENDIF
@//E*O*F chdr.template//
chmod u=rw,g=r,o=r chdr.template
echo x - library.template
sed 's/^@//' > "library.template" <<'@//E*O*F library.template//'
; -----------------------------------------------------------------
- Genlib - library.template
- -----------------------------------------------------------------
-
- Template for Amiga run-time library boilerplate code
+LCOMMENT
;
+AGENTIME
;
; This file automatically generated by genlib.
; Genlib is Copyright 1989, Sleepless Software
; Author: Ron Hitchens (ronbo@vixen.uucp) (801) 292-2910
-
- This code defines the data structures and interface
- routines necessary to create a run-time library which
- is mostly written in Manx Aztec C. This template is
- read as input by the genlib program, the output file
- will have information substituted into it derived from
- the specification file which is also input to genlib.
-
- The output file derived from this template should then
- be assembled to make a .o file. This .o file should
- then be linked with all the .o files of the C code
- which will also be in the library. The link should also
- include the apprpriate Manx link libraries (-lc32, etc)
- and the stubs created by genlib (see stubs.template)
-
- The output of that link will be an Amiga run-time library
- which can be placed in devs: and used via OpenLibrary.
-
- -----------------------------------------------------------------
-
- Copyright 1989, Sleepless Software, All Rights Reserved
-
- Permission is granted to use and redistribute, so long as
- no fee is charged.
-
- Author: Ron Hitchens, Sleepless Software
- Date: Wed Sep 6 16:13:13 MDT 1989
; -----------------------------------------------------------------
include 'exec/types.i'
include 'exec/libraries.i'
include 'exec/nodes.i'
include 'exec/lists.i'
include 'exec/alerts.i'
include 'exec/initializers.i'
include 'exec/resident.i'
include 'exec/execbase.i'
include 'libraries/dos.i'
+AINCLUDE
far data
far code
+EQU
dseg
public __H1_org ; for grokking a4
public __H1_end
public __H2_org
public __H2_end
public _SysBase
public _DOSBase
_SysBase ds.l 1 ; global ExecBase, used by Manx stubs
_DOSBase ds.l 1 ; global DOSBase, used by Manx stubs
SegList ds.l 1 ; a private place to hold my seg list ptr
cseg ; define code
; User Defined Library Functions
+CDEFS
; External refs to functions that must exist in library's C code
public _LibInitHook
public _LibExitHook
; These symbols live here, make them visible to the C code
public _LibVersion
public _LibRevision
public _LibName
public _LibID
; For small data model Manx C code
public _geta4
EXTERN_LIB OpenLibrary
EXTERN_LIB CloseLibrary
EXTERN_LIB Alert
EXTERN_LIB FreeMem
EXTERN_LIB Remove
EXTERN_LIB Supervisor
LIBCALL MACRO *
IFNE NARG-1
FAIL !!!
ENDC
jsr _LVO\1(a6) ; assumes a6 is already setup
ENDM
; -----------------------------------------------------------------
; Entry point if library is run as a program, return an
; error code and exit
entry .begin
public .begin
@.begin
moveq #-1,d0
rts
; -----------------------------------------------------------------
; Romtag - Must live in first hunk
RomTag:
dc.w RTC_MATCHWORD
dc.l RomTag
dc.l EndTag
dc.b RTF_AUTOINIT
dc.b VERSION
dc.b NT_LIBRARY
dc.b PRIORITY
dc.l _LibName
dc.l _LibID
dc.l Init
EndTag:
; -----------------------------------------------------------------
; Init table
Init:
+LSIZEOF
dc.l FuncTable
dc.l DataTable
dc.l InitRoutine
; -----------------------------------------------------------------
; Function table
FuncTable:
dc.l Open
dc.l Close
dc.l Expunge
dc.l Null
dc.l _geta4
; User Defined Library Functions
+FUNCTAB
dc.l -1 ; end of table marker
; -----------------------------------------------------------------
; Data table
DataTable:
INITBYTE LN_TYPE,NT_LIBRARY
INITLONG LN_NAME,_LibName
INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
INITWORD LIB_VERSION,VERSION
INITWORD LIB_REVISION,REVISION
INITLONG LIB_IDSTRING,_LibID
dc.l 0
; -----------------------------------------------------------------
; Constant strings that need to be defined
_LibVersion:
dc.l VERSION
_LibRevision
dc.l REVISION
_LibName:
+LIBNAME
_LibID:
+LIBID
DosName:
DOSNAME ; define the name of the dos library
even ; assure word alignment
; -----------------------------------------------------------------
; Init Routine, called when library is loaded
;
; This routine is called after the library has been allocated.
; The library pointer is in d0. The segment list is in a0
; if it returns non-zero then the library will be linked into
; the library list.
;
; d0 = libptr, a0 = seglist, a6 = execbase
InitRoutine:
movem.l d1/d2/a0-a2/a4/a5,-(sp) ; save regs
move.l d0,a5 ; get library ptr into an addr reg
bsr _geta4 ; load our lib's a4 value
move.l a4,lb_LibA4(a5) ; stash it for use by linklib stubs
clr.b lb_Flags(a5) ; unset all our flags
move.l a6,_SysBase ; save pointer to Exec library
move.l a0,SegList ; save pointer to our loaded code
lea DosName(pc),a1 ; Open the DOS library
clr.l d0 ; set d0 to zero
LIBCALL OpenLibrary ; make a call to Exec
move.l d0,_DOSBase ; save pointer to DOS library
bne.s 1$
ALERT AG_OpenLib!AO_DOSLib ; Can't open Dos Lib, Big Trouble
1$:
lea __H1_end,a1 ; addr of end of init data seg
lea __H2_org,a2 ; addr of begin of un-init data seg
cmp.l a1,a2 ; are the two segs together?
bne 3$ ; no, don't have to clear bss
move.w #((__H2_end-__H2_org)/4)-1,d1 ; longword size of bss
bmi 3$ ; no bss, nothing to do
clr.l d2 ; put a zero in d2
2$:
move.l d2,(a1)+ ; store 0 at addr in a1, bump a1 by 4
dbra d1,2$ ; dec d1, branch if result != -1
3$:
bsr ffp_reset ; go try to reset the '881
move.l a6,-(sp) ; save a6, just in case
move.l a5,-(sp) ; push our lib ptr on the stack
jsr _LibInitHook ; call the external C routine
addq.l #4,sp ; pop the arg off the stack
move.l (sp)+,a6 ; restore a6
tst.l d0 ; check for good return from hook
beq 4$ ; all is well
; Oh shit, the C init hook had trouble, abort the open
move.l _DOSBase,a1 ; Get DOSBase
LIBCALL CloseLibrary ; Close the DOS library
clr.l d0 ; indicate that our open failed
bra 5$ ; go return
4$:
move.l a5,d0 ; return our lib pointer as result
5$:
movem.l (sp)+,d1/d2/a0-a2/a4/a5 ; restore regs
rts ; all inited now, thank you very much
; -----------------------------------------------------------------
; If Exec says there is a 68881 present, reset it
;
; a6 = ExecBase
mc68881 ; allow ffp intructions
ffp_reset:
btst.b #AFB_68881,AttnFlags(a6) ; check for 68881 flag
bne 1$ ; branch if flag is set
rts ; trundle on back, nuthin to do
1$:
move.l a5,-(sp) ; save a5
lea 2$,a5 ; load address of ffp reset routine
LIBCALL Supervisor ; go into supervisor state to do it
move.l (sp)+,a5 ; restore a5
rts ; all done
2$:
clr.l -(sp) ; push a zero onto the stack
frestore (sp)+ ; restore 68881 state (to zero)
rte ; return and exit supervisor state
; -----------------------------------------------------------------
; -----------------------------------------------------------------
; -----------------------------------------------------------------
; Here begins the system interface commands. When the user
; calls OpenLibrary/CloseLibrary/RemLibrary, this
; eventually get translated into a call to the following
; routines (Open/Close/Expunge). Exec has already put our
; library pointer in a6 for us. Exec has turned off task
; switching while in these routines (via Forbid/Permit), so
; we should not take too long in them.
; -----------------------------------------------------------------
; -----------------------------------------------------------------
; Open - Called when a user calls OpenLibrary
;
; Open returns the library pointer in d0 if the open was
; successful. If the open failed, then null is returned.
; It might fail if we allocated memory on each open, or
; if only one application could have the library open
; at a time.
;
; a6 = libptr, d0 = version
Open:
addq.w #1,LIB_OPENCNT(a6) ; one more opener
bclr #LIBB_DELEXP,lb_Flags(a6) ; prevent delayed expunges
move.l a6,d0 ; return lib ptr
rts
; -----------------------------------------------------------------
; Close - Called when a user calls CloseLibrary
;
; There are two different things that might be returned from
; the close routine. If the library is no longer open by anyone,
; and there is a delayed expunge, then close should return the
; segment list (as given to init). Otherwise close should return
; a null;
;
; a6 = libptr
Close:
clr.l d0 ; set the return value
subq.w #1,LIB_OPENCNT(a6) ; one fewer openers
bne.s 1$ ; branch if count non-zero
btst #LIBB_DELEXP,lb_Flags(a6) ; delayed expunge pending?
beq.s 1$ ; branch if no
bsr Expunge ; turn out the lights
1$:
rts
; -----------------------------------------------------------------
; Expunge - Called when a user calls RemLibrary
;
; There are two different things that might tbe returned from the
; expunge routine. If the library is no longer open, then expunge
; should return the segment list (as given to init). Otherwise
; expunge should set the delayed expunge flag and return null.
;
; One other important note: because expunge is called from the
; memory allocator, it may NEVER Wait() nor otherwise take a
; long time to complete.
;
; a6 = libptr
Expunge:
tst.w LIB_OPENCNT(a6) ; is lib open count == zero?
beq 1$ ; branch if yes
bset #LIBB_DELEXP,lb_Flags(a6) ; still open, set delayed flag
clr.l d0 ; set return code = zero
rts
1$:
; We're leaving now, no longer open by anyone
movem.l d2/a4-a6,-(sp) ; save regs
bsr _geta4 ; setup a4 for the C code
move.l a6,a5 ; move our own pointer to a5
move.l a6,-(sp) ; call external C cleanup
jsr _LibExitHook ; routine, pass lib ptr
addq.l #4,sp ; pop arg
move.l _SysBase,a6 ; put ExecBase in a6
bsr ffp_reset ; reset the '881
move.l a5,a1 ; lib ptr in a1
LIBCALL Remove ; unlink us from lib list
move.l _DOSBase,a1 ; close DOS lib
LIBCALL CloseLibrary
clr.l d0 ; clear all of d0
move.l a5,a1 ; copy our lib ptr to a1
move.w LIB_NEGSIZE(a5),d0 ; put neg size in d0
sub.l d0,a1 ; bias libbase down by negsize
add.w LIB_POSSIZE(a5),d0 ; add posssize to size in d0
LIBCALL FreeMem ; call Exec to free lib node
move.l SegList,d0 ; set return code (seg list)
movem.l (sp)+,d2/a4-a6 ; restore regs
rts ; "I'm goin' home" -Alvin Lee
; -----------------------------------------------------------------
; Null - Doesn't do much of anything
Null:
clr.l d0 ; zero return code
rts
; -----------------------------------------------------------------
; -----------------------------------------------------------------
; -----------------------------------------------------------------
; _geta4 - Called by Manx small data model code to setup a4
_geta4:
far data
lea __H1_org+32766,a4 ; center of init'ed data space
rts
; -----------------------------------------------------------------
; -----------------------------------------------------------------
end
; -----------------------------------------------------------------
@//E*O*F library.template//
chmod u=rw,g=r,o=r library.template
echo x - stubs.template
sed 's/^@//' > "stubs.template" <<'@//E*O*F stubs.template//'
; -----------------------------------------------------------------
- Genlib - stubs.template
- -----------------------------------------------------------------
-
- Template for Amiga link library interface stubs
-
+SCOMMENT
;
+AGENTIME
;
; This file automatically generated by genlib
; Genlib is Copyright 1989, Sleepless Software
; Author: Ron Hitchens (ronbo@vixen.uucp) (801) 292-2910
-
- This code is linked with an application program
- that wishes to make use of the matching run-time
- library. Defined here are the symbols for all
- corresponding exported funtions in the run-time library.
- When one of these funtions is called, control passes
- to one of the stubs here, some massaging of registers
- and the stack is done, then control jumps through
- the proper vector into the run-time library. When
- control returns, the stack and registers are restored
- and control returns to the orignal caller.
-
- The output generated from this template should be assembled
- to produce a .o file. That .o file should either be put
- into a link-library (with lb under Manx) or included on
- the link line with the application .o files when using ln.
-
- -----------------------------------------------------------------
-
- Copyright 1989, Sleepless Software, All Rights Reserved
-
- Permission is granted to use and redistribute, so long as
- no fee is charged.
-
- Author: Ron Hitchens, Sleepless Software
- Date: Wed Sep 6 16:13:13 MDT 1989
; -----------------------------------------------------------------
include 'exec/types.i'
include 'exec/libraries.i'
+AINCLUDE
LIBINIT
LIBDEF _LVO_geta4
+LVO
cseg ; define code
+BASE
; User Defined Library Functions
+CDEFS
; -----------------------------------------------------------------
; Link library stubs to access the run-time library routines
+STUBS
; -----------------------------------------------------------------
end
@//E*O*F stubs.template//
chmod u=rw,g=r,o=r stubs.template
echo x - main.c
sed 's/^@//' > "main.c" <<'@//E*O*F main.c//'
/*
* Genlib - Do the grunt work to make an Amiga run-time library
* from some C code
*
* Copyright 1989, Sleepless Software, All Rights Reserved
*
* Permission is granted to use and to redistribute,
* provided no fee is charged for this software.
*
* Author: Ron Hitchens, Sleepless Software (ronbo@vixen.uucp)
* Date: Sat Oct 14 15:16:37 MDT 1989
*
*/
#include "genlib.h"
static Global *create_global ();
#define LIB_TEMPL 0x01
#define STUB_TEMPL 0x02
#define DOTH_TEMPL 0x04
#define DOTI_TEMPL 0x08
#define ALL_TEMPLS 0x0f
typedef struct {
int flag;
char *templ_name;
char *suffix;
} Templ_list;
static Templ_list template_list [] = {
{ LIB_TEMPL, LIB_TEMPLATE, "_library.asm" },
{ STUB_TEMPL, STUB_TEMPLATE, "_stubs.asm" },
{ DOTH_TEMPL, CHDR_TEMPLATE, "base.h" },
{ DOTI_TEMPL, AHDR_TEMPLATE, "base.i" }
};
#define NUM_TEMPLATES (sizeof (template_list) / sizeof (Templ_list))
main (argc, argv)
int argc;
char **argv;
{
Global *global;
char *libname = NULL;
char *specfile = NULL;
char *tdir = TEMPLATE_DIR;
int template_flags = 0;
int errflag = FALSE;
int i, c;
extern int optind;
extern char *optarg;
if (argc == 0) {
fprintf (stderr, "can't run from workbench\n");
exit (1);
}
while ((c = getopt (argc, argv, "g:d:lshia")) != EOF) {
if (c == NULL) { /* getopt in edlib is broke */
libname = optarg;
break;
}
switch (c) {
case 'g': /* set specfile name */
specfile = optarg;
break;
case 'd': /* set template directory */
tdir = optarg;
break;
case 'l': /* do library base */
template_flags |= LIB_TEMPL;
break;
case 's': /* do link stubs */
template_flags |= STUB_TEMPL;
break;
case 'h': /* do C .h file */
template_flags |= DOTH_TEMPL;
break;
case 'i': /* do asm .i file */
template_flags |= DOTI_TEMPL;
break;
case 'a': /* do all of the above */
template_flags |= ALL_TEMPLS;
break;
case '?':
errflag = TRUE;
break;
}
}
if (template_flags == 0) {
errflag = TRUE; /* nuthin to do */
}
if (libname == NULL) {
if (optind == (argc - 1)) {
libname = argv [optind]; /* library name */
} else {
errflag = TRUE; /* it's missing */
}
}
if (errflag == TRUE) {
fprintf (stderr,
"usage: %s -lshia [-g genfile] [-d dir] libname\n",
argv [0]);
exit (2);
}
if ((global = create_global (libname)) == (Global *)0) {;
exit (3);
}
/* load the specification file */
if (load_spec_file (global, specfile) != OK) {
exit (4);
}
/* do each of the specified templates */
for (i = 0; i < NUM_TEMPLATES; i++) {
if ((template_list [i].flag & template_flags) != 0) {
do_template (global, tdir,
template_list [i].templ_name,
template_list [i].suffix);
}
}
exit (0); /* all in a days work */
}
/*
* Allocate, clear and return an instance of a global data structure.
*/
static
Global *
create_global (name)
char *name;
{
Global *global;
char *p;
global = (Global *) malloc (sizeof (Global));
if (global == NULL_GLOBAL) {
fprintf (stderr, "can't alloc any memory\n");
return (NULL_GLOBAL);
}
bzero (global, sizeof (Global));
global->lib_name = name;
global->lib_name_upper = strdup (name);
for (p = global->lib_name_upper; *p != '\0'; p++) {
if ((*p >= 'a') && (*p <= 'z')) {
*p -= 'a' - 'A';
}
}
return (global);
}
@//E*O*F main.c//
chmod u=rw,g=r,o=r main.c
echo x - load.c
sed 's/^@//' > "load.c" <<'@//E*O*F load.c//'
/*
* GenLib - Routines to load the library specification file
*
* Copyright 1989, Sleepless Software, All Rights Reserved
*
* Permission is granted to use and to redistribute,
* provided no fee is charged for this software.
*
* Author: Ron Hitchens, Sleepless Software (ronbo@vixen.uucp)
* Date: Sat Oct 14 15:16:37 MDT 1989
*
*/
#include "genlib.h"
#include <time.h>
static Parse_code spec_codes [] = {
{ KW_EQU, "EQU" },
{ KW_EQU, "EQUALS" },
{ KW_EQU, "EQUAL" },
{ KW_FUNC, "FUNC" },
{ KW_FUNC, "FUNCTION" },
{ KW_FUNC, "PROC" },
{ KW_FUNC, "PROCEDURE" },
{ KW_BASE, "BASE" },
{ KW_BASE, "LIBBASE" },
{ KW_BASE, "BASENAME" },
{ KW_LIBNAME, "LIBNAME" },
{ KW_LIBID, "LIBID" },
{ PARSE_UNKNOWN, (char *)0 }
};
static void add_equ (), add_func ();
static char *make_id_string ();
/*
* Load the specification file for the library, which contains
* various equates, and the list of functions which will be visible
* externally.
*/
int
load_spec_file (global, specfile)
Global *global;
char *specfile;
{
FILE *fp;
char buf [128];
if (specfile == NULL) {
sprintf (buf, "%s%s", global->lib_name, SPECFILE_SUFFIX);
specfile = buf;
}
if ((fp = fopen (specfile, "r")) == (FILE *)0) {
fprintf (stderr, "can't open %s for reading\n", specfile);
return (BAD);
}
while (fgets (buf, sizeof (buf), fp) != NULL) {
int num_args;
char *ptrs [MAX_ARGS];
if (feof (fp) != FALSE) {
break;
}
/* ignore comment and blank lines */
if ((buf [0] == '#') || (buf [0] == '\n')) {
continue;
}
/* break the buffer into tokens */
num_args = scan_buf (buf, ptrs, MAX_ARGS);
if (num_args == 0) {
continue; /* doesn't seem to be much here */
}
switch (string_to_code (spec_codes, ptrs [0])) {
case KW_EQU:
add_equ (global, ptrs, num_args);
break;
case KW_FUNC:
add_func (global, ptrs, num_args);
break;
case KW_BASE:
global->lib_base = strdup (ptrs [1]);
break;
case KW_LIBNAME:
global->lib_dotname = strdup (ptrs [1]);
break;
case KW_LIBID:
global->lib_id = strdup (ptrs [1]);
break;
default:
fprintf (stderr, "unrecognized keyword: %s\n", buf);
break;
}
}
/* if name of LibraryBase struct wasn't defined, intuit it */
if (global->lib_base == (char *)0) {
sprintf (buf, "%sBase", global->lib_name);
/* capitalize first letter of library name */
if ((buf [0] >= 'a') && (buf [0] <= 'z')) {
buf [0] -= 'a' - 'A';
}
global->lib_base = strdup (buf); /* save it */
}
/* if filename of final library wasn't defined, make default */
if (global->lib_dotname == (char *)0) {
sprintf (buf, "%s.library", global->lib_name);
global->lib_dotname = strdup (buf);
}
/* if library ID string wasn't defined, make a standard one */
if (global->lib_id == (char *)0) {
global->lib_id = make_id_string (global);
}
fclose (fp);
return (OK);
}
/*
* Add an equate to the list of equates. This can be injected
* one at a time, or en masse into a output file.
*/
static
void
add_equ (global, ptrs, num_ptrs)
Global *global;
char **ptrs;
int num_ptrs;
{
Equ_node *node;
if (num_ptrs < 3) {
fprintf (stderr, "add_equ: too few args\n");
return;
}
node = (Equ_node *) malloc (sizeof (Equ_node));
if (node == NULL_EQU) {
fprintf (stderr, "can't alloc equ node\n");
exit (4);
}
node->next = NULL_EQU;
node->name = strdup (ptrs [1]);
node->value = strdup (ptrs [2]);
/* chain the EQU node onto the end of the list */
if (global->equ_first == NULL_EQU) {
global->equ_first = global->equ_last = node;
} else {
global->equ_last->next = node;
global->equ_last = node;
}
}
/*
* Add a function declaration to the list of functions. These are
* used in several places to build tables and to generate glue
* code for the link library stubs. The number of arguments that
* the function takes needs to be known so that the proper glue
* code can be generated in the link library for stack munging.
*/
static
void
add_func (global, ptrs, num_ptrs)
Global *global;
char **ptrs;
int num_ptrs;
{
Func_node *node;
if (num_ptrs < 2) {
fprintf (stderr, "add_func: too few args\n");
return;
}
node = (Func_node *) malloc (sizeof (Func_node));
if (node == NULL_FUNC) {
fprintf (stderr, "can't alloc func node\n");
exit (4);
}
node->next = NULL_FUNC;
node->name = strdup (ptrs [1]);
node->num_args = num_ptrs - 2;
if (global->func_first == NULL_FUNC) {
global->func_first = global->func_last = node;
} else {
global->func_last->next = node;
global->func_last = node;
}
}
/*
* Make a library identifier string in the standard format (according
* to the Amiga RKM). This string identifies the library name,
* version and creation date in asci string form. The actual
* version information, which is checked against an OpenLibrary
* reguest, is defined elsewhere.
*/
static
char *
make_id_string (global)
Global *global;
{
struct tm *tm;
long clock;
char *vers, *rev;
char buf [64];
static char *month_names [] = { "Jan", "Feb", "Mar", "Apr", "May",
"Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
clock = time (0L);
tm = localtime (&clock);
vers = equ_value (global, "VERSION");
if (vers == (char *)0) {
vers = "xx";
}
rev = equ_value (global, "REVISION");
if (rev == (char *)0) {
rev = "yy";
}
sprintf (buf, "%slib %s.%s (%d %s 19%d)", global->lib_name,
vers, rev, tm->tm_mday, month_names [tm->tm_mon], tm->tm_year);
return (strdup (buf));
}
@//E*O*F load.c//
chmod u=rw,g=r,o=r load.c
echo x - dump.c
sed 's/^@//' > "dump.c" <<'@//E*O*F dump.c//'
/*
* Genlib - Routines to read a template and produce the
* corresponding output file, substituting the magic
* keywords with the information from the spec file.
*
* Copyright 1989, Sleepless Software, All Rights Reserved
*
* Permission is granted to use and to redistribute,
* provided no fee is charged for this software.
*
* Author: Ron Hitchens, Sleepless Software (ronbo@vixen.uucp)
* Date: Sat Oct 14 15:16:37 MDT 1989
*
*/
#include "genlib.h"
#include <time.h>
static Parse_code sub_codes [] = {
{ KW_FUNCTABLE, "FUNCTABLE" },
{ KW_FUNCTABLE, "FUNCTAB" },
{ KW_FUNCTABLE, "FUNCTIONTABLE" },
{ KW_FUNCTABLE, "FUNCTIONTAB" },
{ KW_XDEFS, "XDEF" },
{ KW_XDEFS, "XDEFS" },
{ KW_CDEFS, "CDEF" },
{ KW_CDEFS, "CDEFS" },
{ KW_LVO, "LVO" },
{ KW_LVO, "LVOS" },
{ KW_STUB, "STUB" },
{ KW_STUB, "STUBS" },
{ KW_BASE, "BASE" },
{ KW_BASE, "LIBBASE" },
{ KW_AINCLUDE, "AINCLUDE" },
{ KW_LIBNAME, "LIBNAME" },
{ KW_LIBID, "LIBID" },
{ KW_EQU, "EQU" },
{ KW_EQU, "EQUS" },
{ KW_AIFND, "AIFND" },
{ KW_ASTRUCT, "ASTRUCT" },
{ KW_ASIZEOF, "ASIZEOF" },
{ KW_ALIBNAME, "ALIBNAME" },
{ KW_AENDC, "AENDC" },
{ KW_LSIZEOF, "LSIZEOF" },
{ KW_CIFDEF, "CIFDEF" },
{ KW_CSTRUCT, "CSTRUCT" },
{ KW_CLIBNAME, "CLIBNAME" },
{ KW_CENDIF, "CENDIF" },
{ KW_ACOMMENT, "ACOMMENT" },
{ KW_CCOMMENT, "CCOMMENT" },
{ KW_LCOMMENT, "LCOMMENT" },
{ KW_SCOMMENT, "SCOMMENT" },
{ KW_AGENTIME, "AGENTIME" },
{ KW_CGENTIME, "CGENTIME" },
{ PARSE_UNKNOWN, (char *)0 }
};
static void put_equ (),
put_all_equ (),
put_inclusion (),
put_stubs (),
time_stamp ();
/*
* Read a template and make an output file with the proper
* information substituted in place of the special keywords
* in the template.
*/
void
do_template (global, dir, template_name, out_suffix)
Global *global;
char *dir, *template_name, *out_suffix;
{
FILE *in_fp, *out_fp;
char buf [128];
sprintf (buf, "%s%s", dir, template_name);
if ((in_fp = fopen (buf, "r")) == (FILE *)0) {
fprintf (stderr, "can't open %s for reading\n", buf);
return;
}
sprintf (buf, "%s%s", global->lib_name, out_suffix);
if ((out_fp = fopen (buf, "w")) == (FILE *)0) {
fprintf (stderr, "can't open %s for writing\n", buf);
fclose (in_fp);
return;
}
while (fgets (buf, sizeof (buf), in_fp) != NULL) {
char *p;
if (feof (in_fp) != FALSE) {
break;
}
switch (buf [0]) {
case '=':
scan_buf (&buf [1], &p, 1);
put_equ (global, out_fp, p);
break;
case '+':
scan_buf (&buf [1], &p, 1);
put_inclusion (global, out_fp, p);
break;
case '-':
break;
default:
fputs (buf, out_fp);
break;
}
}
fclose (in_fp);
fclose (out_fp);
}
/*
* Put out the value of one EQU symbol.
*/
static
void
put_equ (global, fp, name)
Global *global;
FILE *fp;
char *name;
{
char *value = equ_value (global, name);
if (value == (char *)0) {
fprintf (fp, ";\t***** '%s' IS UNDEFINED *******\n", name);
} else {
fprintf (fp, "%s:\tEQU\t%s\n", name, value);
}
}
/*
* Put out all of the EQU symbols in the list.
*/
static
void
put_all_equ (global, fp)
Global *global;
FILE *fp;
{
Equ_node *first = global->equ_first;
Equ_node *node;
char *name, *value;
for (node = first; node != NULL_EQU; node = node->next) {
fprintf (fp, "%s:\tEQU\t%s\n", node->name, node->value);
}
}
/*
* Insert an inclusion into the output file. The type and
* format of the included text is dependent on the type of
* inclusion.
*/
static
void
put_inclusion (global, fp, name)
Global *global;
FILE *fp;
char *name;
{
Func_node *first = global->func_first;
Func_node *node;
switch (string_to_code (sub_codes, name)) {
case KW_EQU:
put_all_equ (global, fp);
break;
case KW_FUNCTABLE:
for (node = first; node != NULL_FUNC; node = node->next) {
fprintf (fp, "\tdc.l\t_%s\t; %d parms\n", node->name,
node->num_args);
}
break;
case KW_XDEFS:
for (node = first; node != NULL_FUNC; node = node->next) {
fprintf (fp, "\tpublic\t%s\n", node->name);
}
break;
case KW_CDEFS:
for (node = first; node != NULL_FUNC; node = node->next) {
fprintf (fp, "\tpublic\t_%s\n", node->name);
}
break;
case KW_LVO:
for (node = first; node != NULL_FUNC; node = node->next) {
fprintf (fp, "\tLIBDEF\t_LVO%s\n", node->name);
}
break;
case KW_STUB:
put_stubs (global, fp);
break;
case KW_BASE:
fprintf (fp, "\tpublic\t_%s\n", global->lib_base);
break;
case KW_AINCLUDE:
fprintf (fp, "\tinclude\t'%sbase.i'\n", global->lib_name);
break;
case KW_LIBNAME:
fprintf (fp, "\t%sNAME\t; from %sbase.i\n",
global->lib_name_upper, global->lib_name);
break;
case KW_LIBID:
fprintf (fp, "\tdc.b\t\t'%s',13,10,0\n", global->lib_id);
break;
case KW_AIFND:
fprintf (fp, "\tIFND\t%s_BASE_I\n%s_BASE_I\tSET\t1\n",
global->lib_name_upper, global->lib_name_upper);
break;
case KW_ACOMMENT:
fprintf (fp, ";\t%s definitions for %s\n", global->lib_base,
global->lib_dotname);
break;
case KW_ASTRUCT:
fprintf (fp, "\tSTRUCTURE\t%s,LIB_SIZE\n", global->lib_base);
break;
case KW_ASIZEOF:
fprintf (fp, "\tLABEL\t\t%s_SIZEOF\n", global->lib_base);
break;
case KW_ALIBNAME:
fprintf (fp, "%sNAME\tMACRO\n\tdc.b\t'%s',0\n\tENDM\n",
global->lib_name_upper, global->lib_dotname);
break;
case KW_AENDC:
fprintf (fp, "\tENDC\t; %s_BASE_I\n", global->lib_name_upper);
break;
case KW_LSIZEOF:
fprintf (fp, "\tdc.l\t%s_SIZEOF\t; size of lib node to alloc\n",
global->lib_base);
break;
case KW_CIFDEF:
fprintf (fp, "#ifndef %s_BASE_H\n#define %s_BASE_H\n",
global->lib_name_upper, global->lib_name_upper);
break;
case KW_CCOMMENT:
fprintf (fp, " *\t%s definitions for %s\n", global->lib_base,
global->lib_dotname);
break;
case KW_CSTRUCT:
fprintf (fp, "struct %s {\n", global->lib_base);
break;
case KW_CLIBNAME:
fprintf (fp, "#define %sNAME\t\t\"%s\"\n",
global->lib_name_upper, global->lib_dotname);
break;
case KW_CENDIF:
fprintf (fp, "#endif %s_BASE_H", global->lib_name_upper);
break;
case KW_LCOMMENT:
fprintf (fp, ";\t%s Run-Time Library BoilerPlate\n",
global->lib_dotname);
break;
case KW_SCOMMENT:
fprintf (fp, ";\t%s Link-Library Interface Glue Routines\n",
global->lib_dotname);
break;
case KW_AGENTIME:
time_stamp (fp, ";\tGenerated: ");
break;
case KW_CGENTIME:
time_stamp (fp, " *\tGenerated: ");
break;
default:
fprintf (fp, ";\t**** '+%s' NOT RECOGNIZED *******\n", name);
break;
}
}
/*
* Put out the link library stub code for all the functions
* in the list. The exact code generated depends on how many
* arguments are passed to the function. When the link library
* glue calls off to the run-time routine, it saves registers,
* sets up registers as needed by the lib code, then copies up
* the arguments on the stack. When the run-time library returns,
* the duplicate args are popped, registers are restored, and
* control returns to the original caller.
* NB: Be very sure you know what you're doing if you change this
* code, especially if you change the number of registers that
* are saved before call-thru. The generated code uses a constant
* offset of the stack pointer when copying the args. If things
* don't match up properly, the args will get hosed up royally.
* Also note that this code depends on a field in the library
* base struct with the name lb_LibA4, which has been set to
* the proper value by the library init code. This is done
* correctly by the regular template. The a4 register must be
* setup even if you compile everything with the large model under
* Manx.
*/
static
void
put_stubs (global, fp)
Global *global;
FILE *fp;
{
Func_node *first = global->func_first;
Func_node *node;
int i;
for (node = first; node != NULL_FUNC; node = node->next) {
fprintf (fp, "\n_%s:\n", node->name);
fprintf (fp, "\tmovem.l\td2-d7/a2-a6,-(sp)\t; save regs\n");
for (i = 0; i < node->num_args; i++) {
fprintf (fp,
"\tmove.l\t%d(sp),-(sp)\t\t; copy arg %d\n",
((node->num_args - 1) * 4) + 48,
node->num_args - i);
}
fprintf (fp, "\tmove.l\t_%s,a6\t\t; libbase\n",
global->lib_base);
fprintf (fp, "\tmove.l\tlb_LibA4(a6),a4\t; setup lib's a4\n");
fprintf (fp, "\tjsr\t_LVO%s(a6)\t; do it\n", node->name);
if (node->num_args != 0) {
fprintf (fp, "\tadd%c.l\t#%d,sp\t\t\t; pop dup args\n",
(node->num_args <= 2) ? 'q' : 'a',
node->num_args * 4);
}
fprintf (fp, "\tmovem.l\t(sp)+,d2-d7/a2-a6\t; restore regs\n");
fprintf (fp, "\trts\t\t\t\t; return to caller\n");
}
}
/*
* Given the name of an EQU symbol, look it up in the list and
* return its value.
*/
char *
equ_value (global, name)
Global *global;
char *name;
{
Equ_node *first = global->equ_first;
Equ_node *node;
for (node = first; node != NULL_EQU; node = node->next) {
if (strcmp (name, node->name) == 0) {
return (node->value);
}
}
return ((char *)0);
}
/*
* Output a date/time stamp string, prepended by the given string
* to the given stdio stream.
*/
static
void
time_stamp (fp, p)
FILE *fp;
char *p;
{
long clock = time ((long *)0);
struct tm *tm;
tm = localtime (&clock);
fprintf (fp, "%s%s", p, asctime (tm));
}
@//E*O*F dump.c//
chmod u=rw,g=r,o=r dump.c
echo x - parse.c
sed 's/^@//' > "parse.c" <<'@//E*O*F parse.c//'
/*
* Genlib - Routines for parsing template files
*
* Copyright 1989, Sleepless Software, All Rights Reserved
*
* Permission is granted to use and to redistribute,
* provided no fee is charged for this software.
*
* Author: Ron Hitchens, Sleepless Software (ronbo@vixen.uucp)
* Date: Sat Oct 14 15:16:37 MDT 1989
*
*/
#include "genlib.h"
#include <ctype.h>
static char *next_token (),
*end_of_token ();
/*
* Given a pointer to a table of attribute/value pairs and an
* attribute, return the value corresponding to the attribute.
*/
int
string_to_code (code_tab, attrib)
Parse_code *code_tab;
char *attrib;
{
int i = 0;
while (code_tab [i].code != PARSE_UNKNOWN) {
if (stricmp (attrib, code_tab [i].value) == 0) {
return (code_tab [i].code);
}
i++;
}
return (PARSE_UNKNOWN);
}
/*
* Scan a text buffer and stringify each token in the buffer. Place
* pointers to each of the tokens into the array of pointers pointed
* to by ptrs, up to a maximum of num_ptrs. Return the number of
* tokens found.
* (NB: This is in no way a generic token parser, it's destructive
* of the original buffer and can be fooled by lots of things. It's
* simply a hack that served the purpose at the time)
*/
int
scan_buf (buf, ptrs, num_ptrs)
char *buf;
register char **ptrs;
register int num_ptrs;
{
register char *q, *p = buf;
register int n = 0;
while (TRUE) {
q = next_token (p);
if (q == (char *)0) {
return (n);
}
ptrs [n++] = q;
p = end_of_token (q);
if (p == (char *)0) {
return (n);
}
*p++ = '\0';
if (n == num_ptrs) {
return (n);
}
ptrs [n] = (char *)0;
}
}
/*
* Given a pointer to a string, if it is bounded by matching quote
* characters (two single or two double quotes), remove them from
* the string. The end quote is replaced with a null, and the address
* of the char following the first quote is returned as the result.
* If the string does not seem to be quoted, or if the quotes are
* not balanced, then the original string is returned.
*/
char *
snuff_quotes (p)
register char *p;
{
register char *q;
if ((*p != '"') && (*p != '\'')) {
return (p);
}
q = &p [strlen (p) - 1];
if (*q != *p) {
return (p);
}
*q = '\0';
p++;
return (p);
}
/*
* Given a pointer into a string, return the address of the beginning
* of the next token in the string.
*/
static
char *
next_token (p)
char *p;
{
while (*p != '\0') {
if (isspace(*p)) {
p++;
continue;
}
switch (*p) {
case '(':
case ')':
case ',':
p++;
continue;
}
break;
}
if (*p == '\0') {
return ((char *)0);
}
return (p);
}
/*
* Given a pointer to the beginning of a token in a buffer, find
* the end of the token and return the address of the character
* following the last character of the token. This function will
* recognize quoted strings beginning with either ' or ", and ending
* with the same quote char, it will also handle escaped quotes
* within the string, such as 'It\'s too late' or "Casper says \"Boo!\""
*/
static
char *
end_of_token (p)
char *p;
{
char quote = FALSE;
int escaped = FALSE;
while (*p != '\0') {
if (quote != FALSE) {
if ((*p == quote) && (escaped == FALSE)) {
quote = FALSE;
}
} else {
if (isspace (*p)) {
return (p);
}
switch (*p) {
case ',':
case '=':
case ')':
case '(':
case '\n':
return (p);
case '"':
case '\'':
if (escaped == FALSE) {
quote = *p;
}
break;
}
}
escaped = ((*p == '\\') && (escaped == FALSE)) ? TRUE : FALSE;
p++;
}
return ((char *)0);
}
/*
* Duplicate the given string and return the address of the copy.
*/
char *
strdup (str)
char *str;
{
char *p;
p = malloc (strlen (str) + 1);
strcpy (p, str);
return (p);
}
/*
* Work around brain-damaged tolower macro that unconditionally
* subtracts a constant from the char without first checking to
* see if it is upper case.
*/
#undef tolower
static
char
tolower (c)
register char c;
{
return ((isupper (c)) ? ((c)-'A'+'a') : c);
}
int
stricmp (str1, str2)
register char *str1, *str2;
{
register int index = 0;
while (str1[index] && str2[index] &&
tolower(str1[index]) == tolower(str2[index])) {
++index;
}
return ((tolower(str1[index]) < tolower(str2[index])) ? -1 :
((tolower(str1[index]) > tolower(str2[index])) ? 1 : 0) );
}
@//E*O*F parse.c//
chmod u=rw,g=r,o=r parse.c
echo x - getopt.c
sed 's/^@//' > "getopt.c" <<'@//E*O*F getopt.c//'
/*
* edlib v1.1 Copyright 1989 Edwin Hoogerbeets
* This code is freely redistributable as long as no charge other than
* reasonable copying fees are levied for it.
*/
#define NULL 0
#define EOF (-1)
#define ERR(s, c) if(opterr){\
extern int strlen(), write();\
char errbuf[2];\
errbuf[0] = c; errbuf[1] = '\n';\
(void) write(2, argv[0], (unsigned)strlen(argv[0]));\
(void) write(2, s, (unsigned)strlen(s));\
(void) write(2, errbuf, 2);}
extern int strcmp();
extern char *strchr();
int opterr = 1;
int optind = 1;
int optopt;
char *optarg;
int
getopt(argc, argv, opts)
register int argc;
char **argv, *opts;
{
static int sp = 1;
register int c;
register char *cp;
if(sp == 1)
if(optind >= argc)
return(EOF);
else {
if(argv[optind][0] != '-') {
optarg = argv[optind++];
return(NULL);
}
if(strcmp(argv[optind], "--") == NULL) {
optind++;
return(EOF);
}
}
optopt = c = argv[optind][sp];
if(c == ':' || (cp=strchr(opts, c)) == NULL) {
ERR(": illegal option -- ", c);
if(argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return('?');
}
if(*++cp == ':') {
if(argv[optind][sp+1] != '\0')
optarg = &argv[optind++][sp+1];
else if(++optind >= argc) {
ERR(": option requires an argument -- ", c);
sp = 1;
return('?');
} else
optarg = argv[optind++];
sp = 1;
} else {
if(argv[optind][++sp] == '\0') {
sp = 1;
optind++;
}
optarg = NULL;
}
return(c);
}
@//E*O*F getopt.c//
chmod u=rw,g=r,o=r getopt.c
echo x - genlib.h
sed 's/^@//' > "genlib.h" <<'@//E*O*F genlib.h//'
/*
* Genlib - Do the grunt work to make an Amiga run-time library
* from some C code.
*
* Copyright 1989, Sleepless Software, All Rights Reserved
*
* Permission is granted to use and to redistribute,
* provided no fee is charged for this software.
*
* Author: Ron Hitchens, Sleepless Software (ronbo@vixen.uucp)
* Date: Sat Oct 14 15:16:37 MDT 1989
*
*/
#include <stdio.h>
#ifndef FALSE
#define TRUE 1
#define FALSE 0
#endif
#define OK 0
#define BAD -1
/*
* Define the directory where templates can be found. Note, this
* string is prepended as-is to the simple filename of the template,
* so slashes/colons must be present on the end as appropriate.
*/
#ifdef unix
#define TEMPLATE_DIR "/usr/local/lib/genlib/"
#else
#define TEMPLATE_DIR "genlib:"
#endif
#define LIB_TEMPLATE "library.template"
#define STUB_TEMPLATE "stubs.template"
#define CHDR_TEMPLATE "chdr.template"
#define AHDR_TEMPLATE "asmhdr.template"
#define SPECFILE_SUFFIX ".gen"
/*
* Define numeric equivalents of the recognizable keywords in
* the template files.
*/
#define PARSE_UNKNOWN -1
#define KW_EQU 1
#define KW_FUNC 2
#define KW_FUNCTABLE 3
#define KW_XDEFS 4
#define KW_CDEFS 5
#define KW_LVO 6
#define KW_STUB 7
#define KW_BASE 8
#define KW_AINCLUDE 9
#define KW_LIBNAME 10
#define KW_LIBID 11
#define KW_AIFND 12
#define KW_ASTRUCT 13
#define KW_ASIZEOF 14
#define KW_ALIBNAME 15
#define KW_AENDC 16
#define KW_LSIZEOF 17
#define KW_CIFDEF 18
#define KW_CSTRUCT 19
#define KW_CLIBNAME 20
#define KW_CENDIF 21
#define KW_ACOMMENT 22
#define KW_CCOMMENT 23
#define KW_LCOMMENT 24
#define KW_SCOMMENT 25
#define KW_AGENTIME 26
#define KW_CGENTIME 27
#define KW_UNKNOWN PARSE_UNKNOWN
#define MAX_ARGS 30 /* max parsable tokens per line */
typedef struct {
int code;
char *value;
} Parse_code;
typedef struct equ_s {
struct equ_s *next; /* next EQU node in the list */
char *name; /* the equate symbol name */
char *value; /* the value of the equate */
} Equ_node;
#define NULL_EQU (Equ_node *)0
typedef struct func_s {
struct func_s *next; /* next FUNC node in the list */
char *name; /* the function name */
int num_args; /* the number of arguments it takes */
} Func_node;
#define NULL_FUNC (Func_node *)0
typedef struct {
Equ_node *equ_first; /* first EQU node in list */
Equ_node *equ_last; /* last EQU node in list */
Func_node *func_first; /* first FUNC node in list */
Func_node *func_last; /* last FUNC node in list */
char *lib_name; /* simple name of the library */
char *lib_name_upper; /* simple name in upper case */
char *lib_base; /* name of lib's "base" struct */
char *lib_dotname; /* "libname.library" */
char *lib_id; /* the library indentifier string */
} Global;
#define NULL_GLOBAL (Global *)0
#ifdef MCH_AMIGA
#define bzero(a,l) setmem(a,l,0)
#endif
extern int load_spec_file (),
scan_buf ();
extern void do_template ();
extern char *snuff_quotes (),
*equ_value (),
*strdup (),
*malloc ();
@//E*O*F genlib.h//
chmod u=rw,g=r,o=r genlib.h
echo x - makefile
sed 's/^@//' > "makefile" <<'@//E*O*F makefile//'
# Genlib - makefile for the genlib program itself
PROG = genlib
OFILES = main.o load.o dump.o parse.o getopt.o
HFILES = genlib.h
LIBS = -lc32
CFLAGS = +L
$(PROG): $(OFILES)
ln -o $(PROG) $(OFILES) $(LIBS)
$(OFILES): $(HFILES)
@//E*O*F makefile//
chmod u=rw,g=r,o=r makefile
echo Inspecting for damage in transit...
temp=/tmp/shar$$; dtemp=/tmp/.shar$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
61 427 2665 README
49 149 1111 MANIFEST
34 80 814 asmhdr.template
37 88 850 chdr.template
439 1637 11178 library.template
73 266 1912 stubs.template
183 527 3374 main.c
262 851 5517 load.c
420 1276 9307 dump.c
249 773 4389 parse.c
74 215 2158 getopt.c
138 451 2998 genlib.h
20 37 241 makefile
2039 6777 46514 total
!!!
wc README MANIFEST asmhdr.template chdr.template library.template stubs.template main.c load.c dump.c parse.c getopt.c genlib.h makefile | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if [ -s $dtemp ]
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0