#define NAME	 "FD2Pragma"
#define VERSION  "2"
#define REVISION "55"
#define SDI_ENDCODE
//#define DEBUG
//#define DEBUG_OLD

/* Programmheader

	Name:		FD2Pragma
	Author: 	SDI
	Distribution:	PD
	Description:	creates pragmas files, lvo files and stub functions
	Compileropts:	-
	Linkeropts:	-gd

 1.2	: added pragmas for the Dice compiler. Available via switch "Dice".
	added switches "Aztec", "SAS" and "Maxon": Maxon and Aztec just
	turn on the default (except that Maxon expects pragma files to be
	called "xxx_pragmas.h" instead of "xxx_lib.h"), SAS is equal to
	Dice, except that SAS supports the pragma tagcall.
 2.0	: Added support for tag functions. See the docs for details.
	Author until this version:
	Jochen Wiedmann
	Am Eisteich 9
	72555 Metzingen (Germany)
	Tel. 07123 / 14881
 2.1   19.08.96 : now made by SDI, added correct __MAXON__ support and
	support for StormC++, added auto recognition of tagcall functions
	changed the CLI interface completely
 2.2   21.08.96 : fixed a lot of errors, added debug code
 2.3   22.08.96 : little changes
 2.4   24.08.96 : added proto-file creation
 2.5   25.08.96 : added syscall and fix for functions ending in ...DMA
 2.6   26.08.96 : fixed some errors, added CLIB parameter (used later for
	CSTUBS)
 2.7   01.09.96 : added correct Storm definition, added CLIB scan
 2.8   02.09.96 : added assembler stub functions, added first ASM-stub code
 2.9   04.09.96 : added Comment-Support
 2.10  05.09.96 : changed CSTUB creation a bit
 2.11  07.09.96 : speeded up output, reduced number of strndup calls
 2.12  26.09.96 : pressing CTRL-C in early startup brought a wrong error
	message - fixed
 2.13  30.09.96 : made RegNames field to RegNames string - shorter Exe-file
 2.14  01.10.96 : made SPECIAL 6 default, COMMENT also in LVO files
 2.15  13.10.96 : corrected an error text
 2.16  14.10.96 : added correct comment support and PRIVATE option
 2.17  19.10.96 : now Maxon-compiled in Small data mode
 2.18  22.10.96 : removed EXTERNC in Storm, Maxon and all pragmas, corrected
	the texts, again SAS compiled
 2.19  26.10.96 : added option to create FD files out of pragma files,
	reworked a lot in the source
 2.20  27.10.96 : fixed errors of previous version
 2.21  28.10.96 : fixed error in CLIB scan
 2.22  27.11.96 : SPECIAL numbers for lib and ASM code were wrong, removed
	bug in Tag function stubs
 2.23  06.12.96 : lib and stub creation still was wrong
 2.24  31.12.96 : formed stub libs matching C++ file names, corrected CLIB
	scan errors
 2.25  04.01.97 : added HEADER option (I was asked for)
 2.26  05.01.97 : added HEADER scan (in old file) and auto inserting
 2.27  10.01.97 : stub functions missed register saving, outfuncs skip now,
	when error occured (makes lots of error checking obsolete)
 2.28  11.01.97 : forgot to add offset made by register saving
 2.29  18.01.97 : now libtags and amitags defines only, when at least 1
	tagfunc
 2.30  13.02.97 : added local library base functions, rearranged SPECIAL
		  options, fixed some bugs
 2.31  15.02.97 : corrected bugs inserted in previous version
 2.32  16.02.97 : and again bug fixes, still didn't work
 2.33  18.02.97 : corrected texts, added SPECIAL 28
 2.34  25.03.97 : corrected Pragma --> FD file conversion, added ##shadow
 2.35  26.03.97 : added STORMFD option, COMMENT, PRIVATE work again
 2.36  29.03.97 : corrected *tagcall scan a bit
 2.37  20.06.97 : added PASCAL stub lib production (SPECIAL 14, 15)
 2.38  01.07.97 : fixed ##end handling
 2.39  20.07.97 : added better proto file (__GNUC__ inline and pragma call),
	removed C++ comments
 2.40  24.11.97 : added new basenames to the list (devices and resources),
	added tag-exception name checking (dos, utility libraries)
 2.41  27.11.97 : fixed little bug with private functions, CSTUBS now
	special option and no longer commandline arg, SPECIAL 10-15 got
	numbers 11-16 (Sorry)
 2.42  28.11.97 : Added two new warnings for CLIB
 2.43  12.12.97 : faster FD file scan, one new warning
 2.44  19.12.97 : fixed MODE settings for SPECIAL 15,16
 2.45  30.01.98 : added function recognition, included inline creation,
 	inline stuff is based on fd2inline 1.11 (incomplete)
 2.46  31.01.98 : continued inline stuff, fixed clib functions
 2.47  05.02.98 : completed inline stuff, added alias names for dos functions
 2.48  06.02.98 : changed Func interface - flags instead of tagmode
 2.49  10.02.98 : fixed inline generation a bit, added SORTED argument,
 	RegNames got strings again
 2.50  11.02.98 : bug-fixes, still did not work completely, hopefully got
	all now
 2.51  12.02.98 : and bug-fixes again :-(
 2.52  15.02.98 : changed sorting order of arguments
 2.53  20.02.98 : some code style changes
 2.54  25.02.98 : added SMALLDATA model, removed 5 global variables (better
	style), stub libs use MOVEM when possible, own MemRemember function
 2.55  26.02.98 : bug fixes
*/

#include <proto/exec.h>
#include <proto/dos.h>

#include <exec/memory.h>
#include <dos/doshunks.h>

#define SDI_TO_ANSI
#include "SDI_ASM_STD_protos.h"
#include "SDI_defines.h"

#ifdef __MAXON__		/* needed for -gd option */
  #include <linkerfunc.h>
#endif

#define TEXT_SAS	"__SASC"	/* verified	*/
#define TEXT_SAS_60	"__SASC_60"	/* verified	*/
#define TEXT_MAXON	"__MAXON__"	/* verified	*/
#define TEXT_STORM	"__STORM__"	/* verified	*/
#define TEXT_DICE	"_DCC"		/* in 2.0 code	*/
#define TEXT_AZTEC	"AZTEC_C"	/* verified	*/
#define TEXT_GNUC	"__GNUC__"	/* verified	*/

#define FLAG_EXTERNC	(1<< 0)
#define FLAG_SYSCALL	(1<< 1)
#define FLAG_DOCOMMENT	(1<< 2)
#define FLAG_PRIVATE	(1<< 3)
#define FLAG_LOCALREG	(1<< 4)
#define FLAG_STORMFD	(1<< 5)
#define FLAG_PASCAL	(1<< 6)
#define FLAG_SMALLDATA	(1<< 7)
#define FLAG_DONE	(1<< 8) /* destination file is not empty */
#define FLAG_INLINENEW	(1<< 9)
#define FLAG_INLINESTUB	(1<<10)

#define FUNCFLAG_NORMAL	(1<<20)
#define FUNCFLAG_TAG	(1<<21)
#define FUNCFLAG_ALIAS	(1<<22)

#define MODUS_STUBTEXT	  1
#define MODUS_STUBCODE	  2
#define MODUS_LOCALDATA   3
#define MODUS_PRAGMA	  4
#define MODUS_CSTUB	  5
#define MODUS_LVO	 10	/* and 11 and 12 and 13 		*/
#define MODUS_PROTO	 20	/* and 21 and 22 and 23 and 24 and 25	*/
#define MODUS_INLINE	 30	/* and 31 and 32 */
#define MODUS_ERROR	100

/* call types for CallFunc */
#define TAGMODE_NORMAL	0
#define TAGMODE_TAGS	1
#define TAGMODE_BOTH	2

/* types for pragma creation */
#define PRAGMODE_PRAGLIB	1
#define PRAGMODE_PRAGSLIB	2
#define PRAGMODE_PRAGSPRAGS	3
#define PRAGMODE_NONE		4

#define BIAS_OFFSET	6

#define PARAM 	"FROM=FDFILE/A,SPECIAL/N,MODE/N,"			\
		"TO/K,CLIB/K,HEADER/K,"					\
		"AMICALL/K,LIBCALL/K,AMITAGS/K,LIBTAGS/K,"		\
		"COMMENT/S,EXTERNC/S,PRIVATE/S,SMALLDATA/S,SORTED/S,"	\
		"STORMFD/S,USESYSCALL/S"

STRPTR RegNames[] = {
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
"a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7",
};

STRPTR RegNamesUpper[] = {
"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7",
};

enum Register_ID {
REG_D0, REG_D1, REG_D2, REG_D3, REG_D4, REG_D5, REG_D6, REG_D7,
REG_A0, REG_A1, REG_A2, REG_A3, REG_A4, REG_A5, REG_A6, REG_A7,
};

struct Args
{
  STRPTR FDFILE;
  ULONG* SPECIAL;
  ULONG* MODE;
  STRPTR TO;
  STRPTR CLIB;
  STRPTR HEADER;
  STRPTR AMICALL;
  STRPTR LIBCALL;
  STRPTR AMITAGS;
  STRPTR LIBTAGS;
  ULONG  COMMENT;
  ULONG  EXTERNC;
  ULONG  PRIVATE;
  ULONG  SMALLDATA;
  ULONG  SORTED;
  ULONG  STORMFD;
  ULONG  USESYSCALL;
};

struct ShortList {
  struct ShortList	*Next;
};

struct ShortListRoot {
  struct ShortList	*First;
  struct ShortList	*Last;
  ULONG 		Size;
};

#define AMIPRAGFLAG_PUBLIC	(1<<0)
#define AMIPRAGFLAG_A6USE	(1<<1)
#define AMIPRAGFLAG_ARGCOUNT	(1<<2)	/* when double args, ... */
#define AMIPRAGFLAG_DIDERROR	(1<<3)

struct AmiPragma {
  struct ShortList		List;
  UWORD 			Bias;
  UWORD				Line;
  ULONG				Flags;
  STRPTR			FuncName;
  STRPTR			TagName;
  struct Pragma_AliasNames *	AliasName;  /* possible second name */
  UWORD 			NumArgs;
  struct AmiArgs
  {
    STRPTR			ArgName;
    UWORD			ArgReg;
  } Args[15];	/* a7 must not be used for function arguments */
};

struct Comment {
  struct ShortList	List;
  STRPTR		Data;
  UWORD 		Bias;
};

struct PragList {
  struct ShortList	List;
  struct ShortListRoot	Data;		/* contains list of PragData */
  STRPTR		Basename;
};

struct PragData {
  struct ShortList	List;
  struct ShortListRoot	Name;
  ULONG 		NumNames;
  ULONG 		Bias;
  ULONG 		NumArgs;
  UBYTE 		ArgReg[14];
};

struct FDData {
  STRPTR	Name;
  STRPTR	Basename;
  ULONG 	Bias;
  ULONG 	Mode;		/* 0 = Normal, != 0 is TagName */
  ULONG 	NumArgs;
  UBYTE 	ArgReg[14];
};

#define CPP_TYPE_VOID		'v'	/* void,	VOID	*/
#define CPP_TYPE_BYTE		'c'	/* char,	BYTE	*/
#define CPP_TYPE_WORD		's'	/* short,	WORD	*/
#define CPP_TYPE_LONG		'j'	/* long,	LONG	*/
#define CPP_TYPE_FLOAT		'f'	/* float,	FLOAT	*/
#define CPP_TYPE_DOUBLE 	'd'	/* double,	DOUBLE	*/
#define CPP_TYPE_STRUCTURE	0
#define CPP_TYPE_VARARGS	'e'

/* Thse types are for string creation only */
#define CPP_TYPE_CONST		'C'
#define CPP_TYPE_FUNCTION	'F'
#define CPP_TYPE_POINTER	'P'
#define CPP_TYPE_UNSIGNED	'U'
#define CPP_TYPE_FUNCEND	'p'
#define CPP_TYPE_REGISTER	'r'

#define CPP_FLAG_UNSIGNED	(1<<0)
#define CPP_FLAG_CONST		(1<<1)
#define CPP_FLAG_STRPTR 	(1<<2)
#define CPP_FLAG_POINTER	(1<<3)
#define CPP_FLAG_FUNCTION	(1<<4)
/* STRPTR is defined different under C and CPP -> I have to create two
names, one time unsigned char *, one time signed char *, when somewhere
a STRPTR occurs */

struct CPP_NameType {
  STRPTR	StructureName;	 /* if a structure only 	 */
  STRPTR	FuncArgs;	 /* arguments of function - unterminated */
  STRPTR	TypeStart;	 /* start of this type		 */
  UWORD 	StructureLength; /* length of the structure name */
  UWORD		TypeLength;	 /* length of this type		 */
  UWORD 	PointerDepth;	 /* number of * in type 	 */
  UBYTE 	Type;		 /* see above defines		 */
  UBYTE 	Flags;		 /* see above flags		 */
};

struct CPP_TypeField {
  STRPTR	Text;
  UWORD 	Length;
  UBYTE 	Flags;
  UBYTE 	Type;
};

struct Proto_LibTypes {
  STRPTR	BaseName;
  STRPTR	StructureName;
};

struct Pragma_ExecpNames { /* TagName 0 is valid as well */
  STRPTR	FunctionName;
  STRPTR	TagName;
};

struct Pragma_AliasNames {
  STRPTR	FunctionName;
  STRPTR	AliasName;
  ULONG		Type;
};

#define NTP_NORMAL	0	/* no tags/args 	*/
#define NTP_TAGS	1	/* TagFunction		*/
#define NTP_ARGS	2	/* ArgFunction		*/
#define NTP_UNKNOWN	3	/* CommentFunction	*/

struct NameList {
  struct ShortList	List;
  ULONG 		Type;	/* set by OptimizeFDData */
  STRPTR		NormName;
  STRPTR		PragName;
};

struct InOut {
  ULONG  file;
  STRPTR pos;
  STRPTR buf;
  ULONG  size;
};

struct RememberMem {
  struct RememberMem *	rm_Next;
  ULONG			rm_Size;
};

struct RDArgs * rda			= 0;
struct InOut    in			= {0,0,0,0},
		out			= {0,0,0,5120};
STRPTR		clibbuf 		= 0;
ULONG		clibsize		= 0;
struct FileInfoBlock *fib		= 0;
struct ShortListRoot	AmiPragma	= {0,0,sizeof(struct AmiPragma)},
			Comment 	= {0,0,sizeof(struct Comment)};
struct RememberMem *remember		= 0;
ULONG		oldfh			= 0;
ULONG		lock			= 0;
STRPTR		BaseName		= 0;
STRPTR		ShortBaseName		= 0;
STRPTR		ShortBaseNameUpper	= 0;
ULONG		DosVersion		= 37; /* force OS2.0 */
STRPTR		HEADER			= 0;
ULONG		headersize		= 0;
ULONG		Flags			= 0;
ULONG		Output_Error		= 1; /* Output error occured when 0 */
ULONG		tagfuncs		= 0; /* are there some tagfuncs in FD */
UBYTE		deftype[]		= "ULONG";

/* Prototypes for the functions */
STRPTR DupString(STRPTR, ULONG);
STRPTR AllocListMem(ULONG);
void FreeListMem(void);
STRPTR SkipBlanks(STRPTR);
STRPTR SkipName(STRPTR);
STRPTR GetBaseType(void);
ULONG  CloseDest(STRPTR);
ULONG  MakeTagFunction(struct AmiPragma *);
void   MakeLines(STRPTR, ULONG, ULONG);
ULONG  SpecialFuncs(void);
void   SortFDList(void);
ULONG  ScanFDFile(void);
void   FindHeader(void);
ULONG  GetRegisterData(struct AmiPragma *);
ULONG  OutputXDEF(STRPTR, ...);
UWORD *AsmStackCopy(UWORD *, struct AmiPragma *, ULONG, ULONG);
/* ------------------------------------------------------------------ */
void   DoError(UBYTE, ULONG, ...);
ULONG  Out(ULONG);
ULONG  DoOutput(STRPTR, ...);
ULONG  DoOutputDirect(APTR, ULONG);
/* ------------------------------------------------------------------ */
struct ShortList *NewItem(struct ShortListRoot *);
struct ShortList *RemoveItem(struct ShortListRoot *, struct ShortList *);
void		  AddItem(struct ShortListRoot *, struct ShortList *);
/* ------------------------------------------------------------------ */
typedef ULONG (*FuncType)(struct AmiPragma *, ULONG, STRPTR);

ULONG FuncAMICALL(struct AmiPragma *, ULONG, STRPTR);
ULONG FuncLIBCALL(struct AmiPragma *, ULONG, STRPTR);
ULONG FuncAsmText(struct AmiPragma *, ULONG, STRPTR);
ULONG FuncAsmCode(struct AmiPragma *, ULONG, STRPTR);
ULONG FuncCSTUBS (struct AmiPragma *, ULONG, STRPTR);
ULONG FuncLVOXDEF(struct AmiPragma *, ULONG, STRPTR);
ULONG FuncLVO	 (struct AmiPragma *, ULONG, STRPTR);
ULONG FuncLocCode(struct AmiPragma *, ULONG, STRPTR);
ULONG FuncLocText(struct AmiPragma *, ULONG, STRPTR);
ULONG FuncInline (struct AmiPragma *, ULONG, STRPTR);
ULONG CallFunc(ULONG, STRPTR, FuncType);
/* ------------------------------------------------------------------ */
ULONG  CheckFuncPar(STRPTR);
ULONG  CopyCPPType(STRPTR, STRPTR, ULONG, STRPTR, struct AmiArgs *);
LONG   GetTypeLength(STRPTR);
LONG   GetCPPType(struct CPP_NameType *, STRPTR);
STRPTR FindClibFunc(STRPTR);	   /* finds the needed function */
ULONG  GetClibLength(STRPTR);	   /* returns length of the type */
ULONG  OutClibType(STRPTR, STRPTR);
LONG   CheckKeyword(STRPTR, STRPTR, LONG);
STRPTR GetClibTypePos(STRPTR, ULONG);
STRPTR GetClibType(STRPTR, ULONG); /* searches for next type definition */
/* ------------------------------------------------------------------ */
ULONG CallPrag(ULONG, STRPTR, FuncType);
ULONG CreatePragmaFile(STRPTR, STRPTR, STRPTR, STRPTR, ULONG);
ULONG CreateCSTUBS(void);
ULONG CreateLVOFile(ULONG);
ULONG CreateAsmStubs(ULONG, ULONG);
ULONG CreateProtoFile(ULONG);
ULONG CreateLocalData(STRPTR, ULONG);
ULONG CreateInline(ULONG);
/* ------------------------------------------------------------------ */
ULONG GetName(struct NameList *, struct ShortListRoot *, ULONG);
ULONG MakeFD(struct PragList *);
void  OptimizeFDData(struct PragData *);
UBYTE GetHexValue(UBYTE);
ULONG AddFDData(struct ShortListRoot *, struct FDData *);
ULONG GetLibData(struct FDData *);
ULONG GetAmiData(struct FDData *);
ULONG CreateFDFile(STRPTR, STRPTR);
/* ------------------------------------------------------------------ */
void main(void);
void end(void);

enum {
ERR_TAGFUNC_NEEDS_ARGUMENT,
ERR_CANNOT_CONVERT_PRAGMA_TAGCALL,
ERR_TAG_DEF_WITHOUT_PRAGMA,
ERR_BASENAME_DECLARED_TWICE,
ERR_EXPECTED_SLASH_IN_BASENAME,
ERR_EXPECTED_BASENAME,
ERR_EXPECTED_BIAS_VALUE,
ERR_ASSUMING_POSITIVE_BIAS_VALUE,
ERR_MISSING_FUNCTION_NAME,
ERR_EXPECTED_OPEN_BRACKET,
ERR_TO_MUCH_ARGUMENTS,
ERR_EXPECTED_ARGUMENT_NAME,
ERR_EXPECTED_CLOSE_BRACKET,
ERR_EXPECTED_REGISTER_NAME,
ERR_ILLEGAL_REGISTER,
ERR_REGISTER_USED_TWICE,
ERR_ARGUMENTNUMBER_DIFFERS_FROM_REGISTERNUMBER,
ERR_ASSUMING_BIAS_OF_30,
ERR_EXTRA_CHARACTERS,
ERR_MISSING_BASENAME,
ERR_WRITING_FILE,
ERR_EXPECTED_COMMA,
ERR_DIFFERENT_TO_PREVIOUS,
ERR_UNKNOWN_VARIABLE_TYPE,
ERR_UNKNOWN_ERROR,
ERR_MISSING_END,
ERR_PROTOTYPE_MISSING,
ERR_NOPROTOTYPES_FILE,
ERR_UNKNOWN_DIRECTIVE,
ERR_INLINE_A4_AND_A5,
ERR_INLINE_D7_AND_A45,
ERR_MISSING_SHORTBASENAME,
ERR_USER_ABORT,
ERR_A6_NOT_ALLOWED,
ERR_EMPTY_FILE,
};

struct ErrField {
  UBYTE  Type;	/* 0 = Error, 1 = Warning */
  UBYTE  Skip;
  STRPTR Error;
} Errors[] = {
{1, 1, "Tag function must have arguments."},
{1, 1, "Cannot convert pragma name into tag name."},
{1, 1, "Tag definition without preceding Pragma."},
{1, 0, "Basename declared twice."},
{1, 0, "Expected preceding _ in Basename."},
{1, 1, "Expected Basename."},
{1, 0, "Expected Bias value."},
{1, 0, "Assuming positive bias value."},
{1, 1, "Missing function name."},
{1, 1, "Expected '('."},
{1, 1, "Too much arguments."},
{1, 1, "Expected argument name."},
{1, 1, "Expected ')'."},
{1, 1, "Expected register name."},
{1, 1, "A7 not allowed as argument register."},
{1, 1, "Register used twice."},
{1, 0, "Number of arguments != number of registers."},
{1, 0, "Assuming bias of 30."},
{1, 1, "Extra characters."},
{0, 0, "Missing Basename in FD file."},
{0, 0, "Failed to write destination file."},
{1, 1, "Expected ','."},
{1, 1, "Data different to previous given."},
{1, 0, "Unknown type \"%s\", no C++ name for %s."},
{0, 0, "Unknown problem: program error or corrupt input data."},
{1, 0, "Missing ##end."},
{1, 0, "Prototype for function \"%s\" not found."},
{1, 0, "No prototypes file (CLIB parameter) was specified."},
{1, 1, "Unknown directive '##%s' found."},
{1, 0, "Usage of both A4 and A5 is not supported."},
{1, 0, "Usage of both D7 and A4 or A5 is not supported."},
{0, 0, "Missing Basename in FD file and FD filename."},
{0, 0, "User aborted operation."},
{1, 0, "A6 not allowed as argument register."},
{1, 0, "Empty or partial file deleted."},
};

struct CPP_TypeField CPP_Field[] = {
{"long",	4, 0,			CPP_TYPE_LONG},
{"ULONG",	5, CPP_FLAG_UNSIGNED,	CPP_TYPE_LONG},
{"LONGBITS",	8, CPP_FLAG_UNSIGNED,	CPP_TYPE_LONG},
{"CPTR",	4, CPP_FLAG_UNSIGNED,	CPP_TYPE_LONG},
{"Tag", 	3, CPP_FLAG_UNSIGNED,	CPP_TYPE_LONG},
{"Object",	6, CPP_FLAG_UNSIGNED,	CPP_TYPE_LONG},
{"LONG",	4, 0,			CPP_TYPE_LONG},
{"BPTR",	4, 0,			CPP_TYPE_LONG},
{"BSTR",	4, 0,			CPP_TYPE_LONG},
{"short",	5, 0,			CPP_TYPE_WORD},
{"CxObj",	5, 0,			CPP_TYPE_LONG},
{"CxMsg",	5, 0,			CPP_TYPE_LONG},
{"USHORT",	6, CPP_FLAG_UNSIGNED,	CPP_TYPE_WORD},
{"UWORD",	5, CPP_FLAG_UNSIGNED,	CPP_TYPE_WORD},
{"UCOUNT",	6, CPP_FLAG_UNSIGNED,	CPP_TYPE_WORD},
{"WORDBITS",	8, CPP_FLAG_UNSIGNED,	CPP_TYPE_WORD},
{"RPTR",	4, CPP_FLAG_UNSIGNED,	CPP_TYPE_WORD},
{"SHORT",	5, 0,			CPP_TYPE_WORD},
{"COUNT",	5, 0,			CPP_TYPE_WORD},
{"WORD",	4, 0,			CPP_TYPE_WORD},
{"BOOL",	4, 0,			CPP_TYPE_WORD},
{"char",	4, 0,			CPP_TYPE_BYTE},
{"UBYTE",	5, CPP_FLAG_UNSIGNED,	CPP_TYPE_BYTE},
{"TEXT",	4, CPP_FLAG_UNSIGNED,	CPP_TYPE_BYTE},
{"BYTEBITS",	8, CPP_FLAG_UNSIGNED,	CPP_TYPE_BYTE},
{"BYTE",	4, 0,			CPP_TYPE_BYTE},
{"void",	4, 0,			CPP_TYPE_VOID},
{"VOID",	4, 0,			CPP_TYPE_VOID},
{"float",	5, 0,			CPP_TYPE_FLOAT},
{"FLOAT",	5, 0,			CPP_TYPE_FLOAT},
{"double",	6, 0,			CPP_TYPE_DOUBLE},
{"DOUBLE",	6, 0,			CPP_TYPE_DOUBLE},
{"STRPTR",	6, CPP_FLAG_POINTER|CPP_FLAG_STRPTR,	CPP_TYPE_BYTE},
{"APTR",	4, CPP_FLAG_POINTER,	CPP_TYPE_VOID},
{"ClassID",	7, CPP_FLAG_POINTER|CPP_FLAG_UNSIGNED,	CPP_TYPE_BYTE},
{"PLANEPTR",	8, CPP_FLAG_POINTER|CPP_FLAG_UNSIGNED,	CPP_TYPE_BYTE},
{"DisplayInfoHandle",17,CPP_FLAG_POINTER,CPP_TYPE_VOID},
{0,0,0,0},
};

struct Proto_LibTypes Proto_LibTypes[] = {
{"DOSBase",			"DosLibrary"},
{"SysBase",			"ExecBase"},
{"ExpansionBase",		"ExpansionBase"},
{"GfxBase",			"GfxBase"},
{"IntuitionBase",		"IntuitionBase"},
{"LocaleBase",			"LocaleBase"},
{"MathIeeeDoubBasBase", 	"MathIEEEBase"},
{"MathIeeeDoubTransBase",	"MathIEEEBase"},
{"MathIeeeSingBasBase", 	"MathIEEEBase"},
{"MathIeeeSingTransBase",	"MathIEEEBase"},
{"RealTimeBase",		"RealTimeBase"},
{"RexxSysBase", 		"RxsLib"},
{"UtilityBase", 		"UtilityBase"},
/* resources - The Node entries may be correct, but I don't know it. */
/*	{"BattClockBase",		"Node"}, */
/*	{"BattMemBase",			"Node"}, */
{"DiskBase",			"DiskResource"},
/*	{"MiscBase",			"Node"}, */
/*	{"PotgoBase",			"Node"}, */
/* devices */
{"ConsoleDevice",		"Device"},
{"InputBase",			"Device"},
{"RamdriveDevice",		"Device"},
{"TimerBase",			"Device"},
/* non default Basenames */
{"DatamasterBase",		"DatamasterBase"},
{"PPBase",			"PPBase"},
{"ReqToolsBase",		"ReqToolsBase"},
{"UnpackBase",			"UnpackLibrary"},
{"xfdMasterBase",		"xfdMasterBase"},
{"GTXBase",			"GTXBase"},
{0, 0},
};

/* CachePostDMA, CachePreDMA are done by #?DMA check */
struct Pragma_ExecpNames Pragma_ExecpNames[] = {
{"VFWritef",		"FWritef"},
{"VFPrintf",		"FPrintf"},
{"VPrintf",		"Printf"},
/* {"RefreshDTObjectA",	"RefreshDTObjects"}, */
{"ReadArgs",		0},
{"FreeArgs",		0},
{"CloneTagItems",	0},
{"FindTagItem",		0},
{"FreeTagItems",	0},
{"GetTagData",		0},
{"PackBoolTags",	0},
{"PackStructureTags",	0},
{"UnpackStructureTags",	0},
{0,0},
};

/* for double tagcall names (currently only necessary for dos.library) */
struct Pragma_AliasNames Pragma_AliasNames[] = {
{"AllocDosObject",	"AllocDosObjectTagList",	FUNCFLAG_NORMAL},
{"CreateNewProc",	"CreateNewProcTagList",		FUNCFLAG_NORMAL},
{"NewLoadSeg",		"NewLoadSegTagList",		FUNCFLAG_NORMAL},
{"SystemTagList",	"System",			FUNCFLAG_NORMAL},
{0,0,0},
};

STRPTR DupString(STRPTR Str, ULONG Len)
{
  STRPTR res;
  if((res = AllocListMem(Len+1)))
  {
    CopyMem(Str, res, Len);
    res[Len] = '\0';
  }
  return res;
}

STRPTR AllocListMem(ULONG size)
{
  struct RememberMem *r;

  size += sizeof(struct RememberMem);

  if((r = (struct RememberMem *) AllocMem(size, MEMF_ANY|MEMF_CLEAR)))
  {
    r->rm_Next = remember;
    r->rm_Size = size;
    remember = r;
    return ((STRPTR) r)+sizeof(struct RememberMem);
  }
  return 0;
}

void FreeListMem(void)
{
  struct RememberMem *r;

  r = remember;

  while(r)
  {
    struct RememberMem *s;
    s = r;
    r = r->rm_Next;
    
    FreeMem(s, s->rm_Size);
  }
}

STRPTR SkipBlanks(STRPTR OldPtr)
{
  while(*OldPtr == ' ' || *OldPtr == '\t')
    ++OldPtr;
  return OldPtr;
}

/*
    This function is used to skip over variable names.

    Inputs: OldPtr  - pointer to the beginning of a string.

    Result: Pointer to the first character of the string, that is not one
	    of a-z, A-Z, 0-9 or the underscore.
*/

STRPTR SkipName(STRPTR OldPtr)
{
  while(isalnum(*OldPtr) || *OldPtr == '_')
    ++OldPtr;
  return OldPtr;
}

STRPTR GetBaseType(void)
{
  ULONG i;
  STRPTR str = "Library";

  for(i = 0; BaseName && Proto_LibTypes[i].BaseName; ++i)
  {
    if(!(strcmp(Proto_LibTypes[i].BaseName, BaseName)))
    {
      str = Proto_LibTypes[i].StructureName; break;
    }
  }
  return str;
}

ULONG CloseDest(STRPTR name)
{
  if(out.file)
  {
    Out(out.size);	/* clears Output-Buffer */
    Close(out.file);
    out.file = 0;

    if(!(Flags & FLAG_DONE) || !Output_Error || CTRL_C)
    {
      DoError(ERR_EMPTY_FILE, 0);
      DeleteFile(name); return 0;
    }
    Flags &= ~FLAG_DONE;	/* clear the flag */
  }
  else
    return 0;
  return 1;
}

ULONG MakeTagFunction(struct AmiPragma *ap)
{
  ULONG len = strlen(ap->FuncName), i=0;

#ifdef DEBUG_OLD
  VPrintf("MakeTagFunction:\n", 0);
#endif

  ++tagfuncs;

  while(Pragma_ExecpNames[i].FunctionName && /* check the exception names */
  strcmp(ap->FuncName, Pragma_ExecpNames[i].FunctionName))
    ++i;

  if(Pragma_ExecpNames[i].FunctionName)
  {
    if(!(ap->TagName = Pragma_ExecpNames[i].TagName));
      --tagfuncs;
  }
  else if(ap->FuncName[len-1] == 'A')
  {
    if(!strcmp(ap->FuncName+len-3, "DMA")) /* skip names with DMA at end */
    { --tagfuncs; return 1;}
    if(!(ap->TagName = DupString(ap->FuncName, len-1)))
      return 0;
  }
  else if(!strcmp(ap->FuncName + len-7, "TagList"))
  {
    if(!(ap->TagName = DupString(ap->FuncName, len-3)))
      return 0;
    ap->TagName[len-4] = 's';
  }
  else if(!strcmp(ap->FuncName + len-4, "Args"))
  {
    if(!(ap->TagName = DupString(ap->FuncName, len-4)))
      return 0;
  }
  else if(!stricmp(ap->Args[ap->NumArgs-1].ArgName, "tags") ||
  !stricmp(ap->Args[ap->NumArgs-1].ArgName, "taglist"))
  {
    if(!(ap->TagName = DupString(ap->FuncName, len+4)))
      return 0;
    CopyMem("Tags", ap->TagName + len, 5);
  }
  else if(!stricmp(ap->Args[ap->NumArgs-1].ArgName, "args"))
  {
    if(!(ap->TagName = DupString(ap->FuncName, len+4)))
      return 0;
    CopyMem("Args", ap->TagName + len, 5);
  }
  else
    --tagfuncs; /* not a tagfunction, incrementing was false, undo it */

  return 1;
}

void MakeLines(STRPTR buffer, ULONG size, ULONG test)
{
  ULONG a = 0;
  if(size && buffer)
  {
    /* make a real C++ zero string ending line */
    while(--size)
    {
      switch(*buffer)
      {
      case '(': ++a; break;
      case ')': --a; break;
      case '\n':
	if(!test || !a)
	  *buffer = '\0';
	else
	  *buffer = ' ';
	break;
      }
      ++buffer;
    }
    *buffer = '\0';
  }
}

/* Do any special functions, which cannot be done with other exception
   stuff - currently only dos.library DoPkt function. */
ULONG SpecialFuncs(void)
{
  struct AmiPragma *ap = (struct AmiPragma *) AmiPragma.Last;

  if(ap->Bias == 0xF0 && !strcmp("DoPkt", ap->FuncName))
  {
    struct AmiPragma *d;
    ULONG i;

    for(i = 0; i < 5; ++i)
    {
      if(!(d = (struct AmiPragma *) NewItem(&AmiPragma)))
	return 0;
      CopyMem(ap, d, sizeof(struct AmiPragma));
      d->FuncName = DupString(ap->FuncName, 6);
      d->FuncName[5] = '0'+i;
      d->NumArgs = i + 2;
      AddItem(&AmiPragma, (struct ShortList *) d);
    }
  }
  return 1;
}

void SortFDList(void)
{
  struct AmiPragma *ap = (struct AmiPragma *) AmiPragma.First, *ap2, *ap3;
  AmiPragma.First = AmiPragma.Last = 0;

  while(ap)
  {
    ap3 = 0;
    ap2 = (struct AmiPragma *) AmiPragma.First;

    /* for FD2Inline style we need to use strcmp instead of stricmp here */
    while(ap2 && stricmp(ap2->FuncName, ap->FuncName) < 0)
    {
      ap3 = ap2;
      ap2 = (struct AmiPragma *) ap2->List.Next;
    }

    ap2 = ap;
    ap = (struct AmiPragma *) ap->List.Next;

    if(ap3)
    {
      ap2->List.Next = (struct ShortList *) ap3->List.Next;
      ap3->List.Next = (struct ShortList *) ap2;
    }
    else
    {
      ap2->List.Next = AmiPragma.First;
      AmiPragma.First = (struct ShortList *) ap2;
    }
    if(!ap->List.Next)
      AmiPragma.Last = (struct ShortList *) ap2;
  }
}

ULONG ScanFDFile(void)
{
#ifdef DEBUG_OLD
  VPrintf("ScanFDFile:\n", 0);
#endif

  ULONG _public = 1;
  LONG bias = -1;
  ULONG linenum, len;
  ULONG actcom = 0;

  for(linenum = 1; !CTRL_C && in.pos < in.buf + in.size; ++linenum)
  {
    if(*in.pos == '*')	     /*  Comment   */
    {
      STRPTR oldpos = in.pos;
#ifdef DEBUG_OLD
  VPrintf("ScanFDFile: found a comment\n", 0);
#endif
      in.pos = SkipBlanks(in.pos+1);
      if(!strnicmp(in.pos, "tagcall", 7))  /*  Tag to create?  */
      {
	struct AmiPragma *prevpragma = (struct AmiPragma *)
		AmiPragma.Last;

	in.pos = SkipBlanks(in.pos + 7);
	if(!prevpragma)
	{
	  DoError(ERR_TAG_DEF_WITHOUT_PRAGMA, linenum);
	  ++in.pos;
	  continue;
	}

	if(!prevpragma->NumArgs)
	{
	  DoError(ERR_TAGFUNC_NEEDS_ARGUMENT, linenum);
	  ++in.pos;
	  continue;
	}

	/* Get the tag functions name. */

	if(!prevpragma->TagName && (_public || (Flags & FLAG_PRIVATE)))
	  ++tagfuncs;

	if(*in.pos)
	{
	  STRPTR oldptr, tptr = prevpragma->TagName;

	  len = strlen(prevpragma->FuncName)+strlen(in.pos)+1;
	  if(!(prevpragma->TagName = DupString(prevpragma->FuncName, len)))
	    return 0;

	  if(*in.pos == '-')
	  {
	    STRPTR removeptr;

	    oldptr = in.pos = SkipBlanks(in.pos+1);
	    in.pos = SkipName(in.pos);
	    if((len = in.pos-oldptr))
	    {
	      removeptr = prevpragma->TagName+strlen(prevpragma->TagName)-len;
	      if(strncmp(removeptr, oldptr, len))
	      {
#ifdef DEBUG_OLD
		{
		  struct data {STRPTR a;STRPTR b;ULONG c;} a;
		  a.a = removeptr;
		  a.b = oldptr;
		  a.c = len;
		  VPrintf("ScanFDFile: *tagcall -: %s, %s, %ld\n", &a);
		}
#endif
		DoError(ERR_CANNOT_CONVERT_PRAGMA_TAGCALL, linenum);
		prevpragma->TagName = tptr;
		++in.pos;
		continue;
	      }

	      *removeptr = '\0';
	    }
	    in.pos = SkipBlanks(in.pos);
	  }
	  if(*in.pos == '+')
	    in.pos = SkipBlanks(in.pos+1);
	  else
	    *in.pos = toupper(*in.pos);

	  in.pos = SkipName((oldptr = in.pos));
	  len = in.pos-oldptr;
	  if(len)
	  {
	    ULONG a = strlen(prevpragma->TagName);
	    CopyMem(oldptr, prevpragma->TagName+a, len);
	    prevpragma->TagName[a+len] = '\0';
	  }
	}
	else if(!prevpragma->TagName)
	{
	  len = strlen(prevpragma->FuncName);
	  if(!(prevpragma->TagName = DupString(prevpragma->FuncName, len+4)))
	    return 0;
	  CopyMem("Tags", prevpragma->TagName + len, 5);
	}
      }
      else
      {
	if(actcom)
	  *(oldpos-1) = '\n';
	else if(Flags & FLAG_DOCOMMENT)
	{
	  struct Comment *d;
	  if(!(d = (struct Comment *) NewItem(&Comment)))
	    return 0;
	  d->Bias = bias;
	  d->Data = oldpos;
	  AddItem(&Comment, (struct ShortList *) d);
	  actcom = 1;
	}
	while(*in.pos)
	  ++in.pos;
      }
    }
    else if(*in.pos == '#' && in.pos[1] == '#')
    {
      in.pos += 2;
      actcom = 0; /* no Comment */

      if(!strnicmp(in.pos, "base", 4))
      {
#ifdef DEBUG_OLD
  VPrintf("ScanFDFile: found ##base\n", 0);
#endif
        STRPTR oldptr;

        if(BaseName)
	  DoError(ERR_BASENAME_DECLARED_TWICE, linenum);

        in.pos = SkipBlanks(in.pos+4);
        if(*in.pos != '_')
	  DoError(ERR_EXPECTED_SLASH_IN_BASENAME, linenum);
        else
	  ++in.pos;

        in.pos = SkipName((oldptr = in.pos));
        if((len = in.pos-oldptr))
        {
	  if(!(BaseName = DupString(oldptr, len)))
	    return 0;
	  if(!ShortBaseName && !(ShortBaseName = DupString(BaseName, len-4)))
	    return 0;
        }
        else
	  DoError(ERR_EXPECTED_BASENAME, linenum);
      }
      else if(!strnicmp(in.pos, "bias", 4))
      {
#ifdef DEBUG_OLD
  VPrintf("ScanFDFile: found ##bias\n", 0);
#endif
        STRPTR ptr;
        LONG newbias;

        in.pos += 5;
        newbias = strtol(in.pos, &ptr, 10);
        if(ptr == in.pos)
	  DoError(ERR_EXPECTED_BIAS_VALUE, linenum);
        else if(newbias < 0)
        {
	  DoError(ERR_ASSUMING_POSITIVE_BIAS_VALUE, linenum);
	  bias = -newbias;
        }
        else
	  bias = newbias;
        in.pos = SkipName(in.pos);
      }
      else if(!strnicmp(in.pos, "end", 3))
      {
        bias = 0; break;
      }
      else if(!strnicmp(in.pos, "shadow", 6)) /* introduced by Storm */
      {
        in.pos += 6;
        bias -= BIAS_OFFSET;
      }
      else if(!strnicmp(in.pos, "public", 6))
      {
        in.pos += 6;
        _public = 1;
      }
      else if(!strnicmp(in.pos, "private", 7))
      {
        in.pos += 7;
        _public = 0;
      }
      else
        DoError(ERR_UNKNOWN_DIRECTIVE, linenum, in.pos);
    }
    else
    {
#ifdef DEBUG_OLD
  VPrintf("ScanFDFile: scan Function\n", 0);
#endif
      STRPTR oldptr;
      struct AmiPragma ap;
      ULONG numargs;

      memset(&ap, 0, sizeof(struct AmiPragma));
      actcom = 0;

      oldptr = in.pos = SkipBlanks(in.pos);
      in.pos = SkipName(oldptr);
      if(!(len = in.pos-oldptr))
      {
	DoError(ERR_MISSING_FUNCTION_NAME, linenum);
	++in.pos;
	continue;
      }

      ap.FuncName = oldptr;

      in.pos = SkipBlanks(in.pos);
      if(*in.pos != '(')
      {
	DoError(ERR_EXPECTED_OPEN_BRACKET, linenum);
	++in.pos;
	continue;
      }

      *in.pos = '\0'; /* create c string of FunctionName */

#ifdef DEBUG_OLD
  VPrintf("ScanFDFile: found function %s\n", &ap.FuncName);
#endif

      do
      {
	oldptr = in.pos = SkipBlanks(in.pos+1);

	if(*in.pos == ')' && !ap.NumArgs)
	  break;

	if(ap.NumArgs == 14)
	{
	  DoError(ERR_TO_MUCH_ARGUMENTS, linenum); break;
	}

	in.pos = SkipName(oldptr);
	if(*in.pos == '*')
	  ++in.pos;
	if(!(len = in.pos-oldptr))
	{
	  DoError(ERR_EXPECTED_ARGUMENT_NAME, linenum);
	  break;
	}

	ap.Args[ap.NumArgs++].ArgName = oldptr;
	oldptr = in.pos;

	in.pos = SkipBlanks(in.pos);
	if(*in.pos != ',' && *in.pos != '/' && *in.pos != ')')
	{
	  DoError(ERR_EXPECTED_CLOSE_BRACKET, linenum);
	  break;
	}
	if(*in.pos != ')') /* create c string ending */
	  *oldptr = '\0';
      }
      while(*in.pos != ')');
      if(*in.pos != ')')
      {
	while(*(in.pos++))
	  ++in.pos;
	continue;
      }
      else
	*oldptr = '\0'; /* create c string ending for last argument */

      if(*(in.pos = SkipBlanks(in.pos+1)) != '(')
      {
	DoError(ERR_EXPECTED_OPEN_BRACKET, linenum);
	++in.pos;
	continue;
      }

      numargs = 0;
      do
      {
	ULONG i;

	oldptr = in.pos = SkipBlanks(in.pos + 1);

	if(*in.pos == ')' && numargs == 0)
	  break;

	in.pos = SkipName(oldptr);
	len = in.pos-oldptr;

	for(i = 0; i < 16; i++)
	  if(!strnicmp(RegNames[i], oldptr, len))
	    break;

	if(i == 16)
	{
	  DoError(ERR_EXPECTED_REGISTER_NAME, linenum);
	  break;
	}
	else if(i == REG_A6)
	  ap.Flags |= AMIPRAGFLAG_A6USE;
	if(i == REG_A7)
	{
	  DoError(ERR_ILLEGAL_REGISTER, linenum);
	  break;
	}

	ap.Args[numargs].ArgReg = i;

	if(ap.NumArgs < numargs)	/* get name when no given */
	  ap.Args[numargs].ArgName = RegNames[i];

	for(i = 0; i < numargs; i++)
	{
	  if(ap.Args[numargs].ArgReg == ap.Args[i].ArgReg)
	  {
	    DoError(ERR_REGISTER_USED_TWICE, linenum);
	    break;
	  }
	}
	if(i < numargs)
	  break;

	++numargs;

	in.pos = SkipBlanks(in.pos);
	if(*in.pos != ',' && *in.pos != '/' && *in.pos != ')')
	{
	  DoError(ERR_EXPECTED_CLOSE_BRACKET, linenum);
	  break;
	}
      }
      while(*in.pos != ')');
      if(*in.pos != ')')
      {
	while(*(in.pos++))
	  ++in.pos;
	continue;
      }
      else
	++in.pos;

      if(Flags & FLAG_STORMFD)
      {
	if(!strcmp(ap.Args[ap.NumArgs-1].ArgName, "tags"))
	{
	  ap.TagName = ap.FuncName;
	  ap.FuncName = 0;
	  ++tagfuncs;
#ifdef DEBUG_OLD
	  VPrintf("ScanFDFile: StormFD mode, tag func: %s\n", &ap.TagName);
#endif
	}
#ifdef DEBUG_OLD
	else
	{
	  STRPTR a[2];
	  a[0] = ap.FuncName;
	  a[1] = ap.Args[ap.NumArgs-1].ArgName;
	  VPrintf("ScanFDFile: StormFD mode, normal func: %s(..., %s)\n", &a);
	}
#endif
      }
      else if((_public || (Flags & FLAG_PRIVATE)) && !MakeTagFunction(&ap))
	return 0;
      else	/* check the alias names */
      {
        ULONG i = 0;

        while(Pragma_AliasNames[i].FunctionName &&
        strcmp(ap.FuncName, Pragma_AliasNames[i].FunctionName))
          ++i;

        if(Pragma_AliasNames[i].FunctionName)
          ap.AliasName = &Pragma_AliasNames[i];
      }

      if(numargs != ap.NumArgs)
      {
	ap.Flags |= AMIPRAGFLAG_ARGCOUNT;
	ap.NumArgs = numargs;
      }

      if(bias == -1)
      {
	DoError(ERR_ASSUMING_BIAS_OF_30, linenum);
	bias = 30;
      }
      ap.Bias = bias;
      ap.Line = linenum;
      bias += BIAS_OFFSET;

      if(_public)
        ap.Flags |= AMIPRAGFLAG_PUBLIC;

      {
	struct AmiPragma *d;
	if(!(d = (struct AmiPragma *) NewItem(&AmiPragma)))
	  return 0;
	CopyMem(&ap, d, sizeof(struct AmiPragma));
	AddItem(&AmiPragma, (struct ShortList *) d);
	if(!SpecialFuncs())
	  return 0;
      }
    }

    in.pos = SkipBlanks(in.pos);
    if(*in.pos)
      DoError(ERR_EXTRA_CHARACTERS, linenum);
    ++in.pos; /* skip '\0' */
  }

  if(CTRL_C)
  {
    DoError(ERR_USER_ABORT, 0);
    return 0;
  }

  if(bias)
    DoError(ERR_MISSING_END, 0);

  return 1;
}

void FindHeader(void)
{
  STRPTR str = HEADER;
  ULONG mode = 0;

  do
  {
    if(!mode)
      HEADER = str;

    if(*str == '/')
    {
      ++str;
      if(*str == '*')
      {
	mode = 2; break;
      }
      else if(*str == '/')
	mode = 1;
    }
    else if(*str == '*' || *str == ';')
      mode = 1;
    else if(mode)
      break;
    while(*str && *(str++) != '\n')
      ;
  } while(*str);

  if(mode == 2)
  {
    while(*str && (*(str-1) != '*' || *str != '/'))
      ++str;
    while(*str && *(str++) != '\n')
      ;
  }

  if(mode)
    headersize = str-HEADER;
  else
  {
    HEADER = 0; headersize = 0;
  }
}

/* returns decrement data in bits 0-15 and increment data in bits 16-31 */
ULONG GetRegisterData(struct AmiPragma *ap)
{
/* usage of result:
	48E7 <lower word>	MOVEM.L <registers>,-(A7) ; D0 is bit 15
	4CDF <upper word>	MOVEM.L (A7)+,<registers> ; D0 is bit 0
*/
  register ULONG i, data = 0, reg;

  for(i = 0; i < ap->NumArgs; ++i)
  {
    reg = ap->Args[i].ArgReg;

    if(reg >= 10 || (reg >= 2 &&  reg <= 7)) /* A2-A7 and D2-D7 */
      data |= (1 << (reg + 16)) + (1 << (15 - reg));
  }
  if(data)	/* set A6 only when other register used */
    data |= 0x40000002;
  return data;
}

ASM(static void) __saveds xdefputfunc(REG(d0, UBYTE data), REG(a3, STRPTR *a))
{
#ifdef __MAXON__
  GetBaseReg();
#endif
  *((*a)++) = data;
}

ULONG OutputXDEF(STRPTR format, ...)
{
  UBYTE b[150];
  STRPTR c = b + 4;
  UWORD i;

  memset(b, 0, 150);
  RawDoFmt(format, (APTR) ((ULONG)&format+sizeof(STRPTR)),
  (void(*)()) xdefputfunc, &c);
  /* c now holds pointer to end */
  i = (c-(b+4)+2)>>2;
  *((ULONG *) b) = 0x01000000 + i;

  return DoOutputDirect(b, (i+2)<<2);
}

UWORD *AsmStackCopy(UWORD *data, struct AmiPragma *ap, ULONG flags,
ULONG ofs)
{
  ULONG j, k;

  if(Flags & FLAG_PASCAL)
  {
    k = ap->NumArgs;

    while(k)
    {
      if((k >= 2) && (ap->Args[k-1].ArgReg < ap->Args[k-2].ArgReg))
      {
        *(data++) = 0x4CEF;		/* MOVEM.L offs(A7),xxx */
        *(data++) = 0;
        *(data++) = ofs << 2;		/* store start offset */
        do
        {
          j = ap->Args[--k].ArgReg;

	  ++ofs;
          *(data-2) |= 1 << j;
        } while(k && j < ap->Args[k-1].ArgReg);
      }
      else
      {
        *data = 0x202F;			/* MOVE.L offs(A7),xxx */

        if((j = ap->Args[--k].ArgReg) > 7)
        {
          *data |= (1<<6); j -= 8;	/* set MOVEA bit */
        }
        *(data++) |= j << 9;		/* set destination register */
        *(data++) = (ofs++) << 2;
      }
    }
  }
  else
  {
    ULONG i = 0;

    k = ap->NumArgs - ((flags & FUNCFLAG_TAG) ? 1 : 0);

    while(i < k)
    {
      if(((k - i) >= 2) && (ap->Args[i].ArgReg < ap->Args[i+1].ArgReg))
      {
        *(data++) = 0x4CEF;		/* MOVEM.L offs(A7),xxx */
        *(data++) = 0;			/* Store MOVEM.L data later */
        *(data++) = ofs << 2;		/* store start offset */
        do
        {
          j = ap->Args[i++].ArgReg;

	  ++ofs;
          *(data-2) |= 1 << j;
        } while(i < k && j < ap->Args[i].ArgReg);
      }
      else
      {
        *data = 0x202F;			/* MOVE.L offs(A7),xxx */

        if((j = ap->Args[i++].ArgReg) > 7)
        {
          *data |= (1<<6); j -= 8;	/* set MOVEA bit */
        }
        *(data++) |= j << 9;		/* set destination register */
        *(data++) = (ofs++) << 2;
      }
    }

    if(i < ap->NumArgs)
    {
      if((j = ap->Args[i].ArgReg) > 7)
      {
        *(data++) = 0x41EF | ((j-8) << 9);	/* LEA xxx(A7),Ax */
        *(data++) = ofs << 2;
      }
      else
      {
        *(data++) = 0x200F | (j << 9);		/* MOVE.L A7,Dx */
        if(ofs == 2)
          *(data++) = 0x5080 | j; 		/* ADDQ.L #8,Dx */
        else
        {
	  *(data++) = 0xD0BC | (j<<9);		/* ADD.L #x,Dx */
	  *(data++) = 0;
	  *(data++) = ofs << 2;
        }
      }
    }
  }

  return data;
}
/* ------------------------------------------------------------------ */

void DoError(UBYTE errnum, ULONG line, ...)
{
  STRPTR *arguments = (STRPTR *) (((STRPTR) &line) + sizeof(ULONG));
  struct {
    STRPTR type;
    ULONG typenum;
    ULONG linenum;
  } args;

  args.type = Errors[errnum].Type ? "Warning" : "Error";
  args.typenum = errnum;
  args.linenum = line;

  VPrintf((line ? "%s %ld in line %ld: " : "%s %ld : "), &args);
  VPrintf(Errors[errnum].Error, arguments);
  PutStr("\n");
  if(line && Errors[errnum].Skip)
  {
    while(*in.pos)
      ++in.pos;
  }
}

ULONG Out(ULONG size)
{
  ULONG i = out.pos-out.buf;

  if(i && out.size - i <= size)
  {
    if(Write(out.file, out.buf, i) != i)
    {
      Output_Error = 0;
      return 0;
    }
    out.pos = out.buf;
  }
  return out.size;
}

ASM(static void) __saveds putfunc(REG(d0, UBYTE data), REG(a3, LONG *a))
{
#ifdef __MAXON__
  GetBaseReg();
#endif

  if(data)
  {
    if(!*a)
      *a = Out(1);
    if((*a)-- > 0)
      *(out.pos++) = data;
  }
}

ULONG DoOutput(STRPTR format, ...)
{
  LONG a = out.buf+out.size-out.pos;

  if(!Output_Error)
    return 0;

  RawDoFmt(format, (APTR) ((ULONG)&format+sizeof(STRPTR)),
  (void(*)()) putfunc, &a);

  if(a < 0)
    return 0;
  return 1;
}

ULONG DoOutputDirect(APTR data, ULONG size)
{
  if(!Output_Error || !Out(size))
    return 0;
  CopyMem(data, out.pos, size);
  out.pos += size;
  return 1;
}

/* ------------------------------------------------------------------ */

struct ShortList *NewItem(struct ShortListRoot *list)
{
  struct ShortList *item;
  if(!list || !list->Size)
    return 0;
  if(!(item = (struct ShortList *) AllocListMem(list->Size)))
    return 0;
  return item;
}

struct ShortList *RemoveItem(struct ShortListRoot *list, struct ShortList *item)
{
  struct ShortList *n = list->First;

  if(n == item)
    list->First = item->Next;
  else
  {
    while(n && n->Next != item)
      n = n->Next;
    if(!n)
      return 0;
    if(!(n->Next = item->Next))
      list->Last = n;
  }
  item->Next = 0;
  return item;
}

void AddItem(struct ShortListRoot *list, struct ShortList *item)
{
  if(!list->First)
    list->First = list->Last = item;
  else
  {
    list->Last->Next = item;
    list->Last = item;
  }
}

/* ------------------------------------------------------------------ */

ULONG FuncAMICALL(struct AmiPragma *ap, ULONG flags, STRPTR name)
{
  ULONG i;

  if(ap->Flags & AMIPRAGFLAG_ARGCOUNT)
  {
    if(!(ap->Flags & AMIPRAGFLAG_DIDERROR))
    {
      DoError(ERR_ARGUMENTNUMBER_DIFFERS_FROM_REGISTERNUMBER, ap->Line);
      ap->Flags |= AMIPRAGFLAG_DIDERROR;
    }
    return 1;
  }

  Flags |= FLAG_DONE; /* We did something */

  DoOutput("#pragma %s(%s,0x%03lx,%s("/*))*/, flags & FUNCFLAG_TAG ?
  "tagcall" : "amicall", BaseName, ap->Bias, name);

  for(i = 0; i < ap->NumArgs; ++i)
  {
    DoOutput(RegNames[ap->Args[i].ArgReg]);
    if(i+1 < ap->NumArgs)
      DoOutput(",");
  }

  return DoOutput(/*((*/"))\n");
}

ULONG FuncLIBCALL(struct AmiPragma *ap, ULONG flags, STRPTR name)
{
  LONG i;

  if(ap->Flags & AMIPRAGFLAG_ARGCOUNT)
  {
    if(!(ap->Flags & AMIPRAGFLAG_DIDERROR))
    {
      DoError(ERR_ARGUMENTNUMBER_DIFFERS_FROM_REGISTERNUMBER, ap->Line);
      ap->Flags |= AMIPRAGFLAG_DIDERROR;
    }
    return 1;
  }

  Flags |= FLAG_DONE; /* We did something */

  if((Flags & FLAG_SYSCALL) && !strcmp(BaseName,"SysBase") &&
  (flags & FUNCFLAG_NORMAL))
    DoOutput("#pragma syscall %-20s %03lx ", name, ap->Bias);
  else
    DoOutput("#pragma %s %s %-20s %03lx ", (flags & FUNCFLAG_TAG) ?
    "tagcall" : "libcall", BaseName, name, ap->Bias);

  for(i = ap->NumArgs-1; i >= 0; --i)
    DoOutput("%lx",ap->Args[i].ArgReg);

  return DoOutput("0%lx\n", ap->NumArgs);
}

ULONG FuncAsmText(struct AmiPragma *ap, ULONG flags, STRPTR name)
{
  STRPTR a;
  LONG i;
  ULONG registers;
  ULONG offset = 1;

  Flags |= FLAG_DONE; /* We did something */

  DoOutput("\n\tXDEF\t_%s\n_%s:\n",name, name);
  if(!(Flags & FLAG_PASCAL))
  {
    DoOutput("\n\tXDEF\t%s\n%s:\n",name, name);
    if(!ap->NumArgs && clibbuf)
      DoOutput("\tXDEF\t%s_\n%s_:\n",name, name);
    else if((a = FindClibFunc(name)))
    {
      UBYTE txt[300];
      ULONG ret = 0;

      do
      {
	if((ret = CopyCPPType(txt, a, ret, name, ap->Args)))
	  DoOutput("\tXDEF\t%s__%s\n%s__%s:\n",name, txt, name, txt);
      } while(ret == 0xFFFFFFFF);
    }
  }

  if((registers = GetRegisterData(ap) >> 16))
  {
    UWORD l = registers;

    DoOutput("\tMOVEM.L\t");

    for(i = 0; i <= 15; ++i)
    {
      if(l & (1 << i))
      {
	++offset;
	l ^= 1 << i;
	DoOutput(RegNamesUpper[i]);
	if(l)
	  DoOutput("/");
      }
    }
    DoOutput(",-(A7)\n");
  }
  else
  {
    DoOutput("\tMOVE.L\tA6,-(A7)\n"); ++offset;
  }

  if(Flags & FLAG_SMALLDATA)
    DoOutput("\tMOVE.L\t_%s(A4),A6\n", BaseName);
  else
    DoOutput("\tMOVE.L\t_%s,A6\n", BaseName);

  if(!(Flags & FLAG_PASCAL))
  {
    ULONG k;

    k = ap->NumArgs - ((flags & FUNCFLAG_TAG) ? 1 : 0);

    for(i = 0; i < k;)
    {
      if(((k - i) >= 2) && (ap->Args[i].ArgReg < ap->Args[i+1].ArgReg))
      {
        DoOutput("\tMOVEM.L\t%02ld(A7),%s", (offset++)<<2,
        RegNamesUpper[ap->Args[i++].ArgReg]);

        do
        {
	  DoOutput("/%s", RegNamesUpper[ap->Args[i++].ArgReg]);
	  ++offset;
        } while((i < k) && (ap->Args[i-1].ArgReg < ap->Args[i].ArgReg));
	DoOutput("\n");
      }
      else
        DoOutput("\tMOVE.L\t%02ld(A7),%s\n", (offset++)<<2,
        RegNamesUpper[ap->Args[i++].ArgReg]);
    }

    if(i < ap->NumArgs)
    {
      if(ap->Args[i].ArgReg > 7)
	DoOutput("\tLEA\t%02ld(A7),%s\n", offset<<2,
	RegNamesUpper[ap->Args[i].ArgReg]);
      else
	DoOutput("\tMOVE.L\tA7,%s\n\tADD%s.L\t#%02ld,%s\n",
	RegNamesUpper[ap->Args[i].ArgReg], (offset <= 2 ? "Q" : ""),
	offset<<2, RegNamesUpper[ap->Args[i].ArgReg]);
    }
  }
  else
  {
    i = ap->NumArgs;

    while(i)
    {
      if((i >= 2) && (ap->Args[i-1].ArgReg < ap->Args[i-2].ArgReg))
      {
        DoOutput("\tMOVEM.L\t%02ld(A7),%s", (offset++)<<2,
        RegNamesUpper[ap->Args[--i].ArgReg]);

        do
        {
	  DoOutput("/%s", RegNamesUpper[ap->Args[--i].ArgReg]);
	  ++offset;
        } while(i && (ap->Args[i].ArgReg < ap->Args[i-1].ArgReg));
	DoOutput("\n");
      }
      else
        DoOutput("\tMOVE.L\t%02ld(A7),%s\n", (offset++)<<2,
        RegNamesUpper[ap->Args[--i].ArgReg]);
    }
  }

  DoOutput("\tJSR\t-%03ld(A6)\n",ap->Bias);

  if(registers)
  {
    DoOutput("\tMOVEM.L\t(A7)+,");

    for(i = 0; i <= 15; ++i)
    {
      if(registers & (1 << i))
      {
	registers ^= 1 << i;
	DoOutput(RegNamesUpper[i]);
	if(registers)
	  DoOutput("/");
      }
    }
    DoOutput("\n");
  }
  else
    DoOutput("\tMOVE.L\t(A7)+,A6\n");

  return DoOutput("\tRTS\n");
}

ULONG FuncAsmCode(struct AmiPragma *ap, ULONG flags, STRPTR name)
{
  ULONG registers, a[5], offset = 1, pos = 4, baseref;
  LONG i = strlen(ShortBaseNameUpper);
  UWORD data[50]; /* 100 byte data field */

  Flags |= FLAG_DONE; /* We did something */

  registers = GetRegisterData(ap);

  a[0] = HUNK_UNIT; a[1] = 0; a[2] = HUNK_NAME;
  a[3] = (i + 6 + 3)>>2;

  DoOutputDirect(a, 16);
  DoOutputDirect(ShortBaseNameUpper, i);
  DoOutputDirect("_STUBS\0\0\0", (a[3]<<2)-i);

  data[0] = 0;
  data[1] = HUNK_CODE;
  data[2] = 0;
  /* data[3] is size */

  if(!registers)
  {
    data[pos++] = 0x2F0E;		/* MOVE.L A6,-(A7) */
    ++offset;				/* one long more on stack */
  }
  else
  {
    ULONG l;
    data[pos++] = 0x48E7;		/* MOVEM.L xxx,-(A7) */
    data[pos++] = registers;		/* storem MOVEM.L registers */
    for(l = (UWORD) registers; l; l >>= 1)
    {
      if(l & 1)
	++offset;			/* get offset addition */
    }
  }

  baseref = pos+1-4;		/* one word later (MOVE) - 2 header longs */
  if(Flags & FLAG_SMALLDATA)
  {
    data[pos++] = 0x2C6C;		/* MOVEA.L base(A4),A6 */
    data[pos++] = 0;			/* place for base reference */
  }
  else
  {
    data[pos++] = 0x2C79;		/* MOVEA.L base,A6 */
    data[pos++] = 0;			/* place for base reference */
    data[pos++] = 0;
  }

  pos = AsmStackCopy(data+pos, ap, flags, offset) - data;

  /* here comes the base reference */
  data[pos++] = 0x4EAE;			/* JSR xxx(A6) */
  data[pos++] = -ap->Bias;		/* JSR offset */

  if(registers)
  {
    data[pos++] = 0x4CDF;		/* MOVEM.L (A7)+,xxx */
    data[pos++] = (registers >> 16);	/* store MOVEM.L registers */
  }
  else
    data[pos++] = 0x2C5F;		/* MOVE.L (A7)+,A6 */
  data[pos++] = 0x4E75;			/* RTS */

  if(pos & 1)
    data[pos++] = 0;			/* round to long */

  data[3] = (pos-4)>>1;			/* store hunk len */
  DoOutputDirect(data, pos<<1);

  a[0] = HUNK_EXT;
  a[1] = ((Flags & FLAG_SMALLDATA ? EXT_REF16 : EXT_REF32) << 24) +
         ((strlen(BaseName) + 1 + 3)>>2);
  a[2] = ('_' << 24);

  DoOutputDirect(a, 9);
  DoOutputDirect(BaseName, (((UWORD) a[1])<<2)-1);

  a[0] = 1; a[1] = baseref << 1;
  DoOutputDirect(a, 8);

  /* here come the XDEF name references */
  OutputXDEF("_%s", name);		/* C name */

  if(!(Flags & FLAG_PASCAL))
  {
    STRPTR str;
    OutputXDEF("%s", name);		/* ASM name */

    if(!ap->NumArgs && clibbuf)
      OutputXDEF("%s_", name);		/* C++ name no parameters */
    else if((str = FindClibFunc(name)))
    {
      ULONG ret = 0;

      do				/* C++ name with parameters */
      {
	if((ret = CopyCPPType((STRPTR) data, str, ret, name, ap->Args)))
	  OutputXDEF("%s__%s", name, (STRPTR) data);
      } while(ret == 0xFFFFFFFF);
    }
  }

  a[0] = 0; a[1] = HUNK_END;

  return DoOutputDirect(a, 8);
}

ULONG FuncCSTUBS(struct AmiPragma *ap, ULONG flags, STRPTR name)
{
  STRPTR string,str2,lastarg;
  STRPTR ret = "return ";
  ULONG i;

  if(ap->Flags & AMIPRAGFLAG_ARGCOUNT)
  {
    DoError(ERR_ARGUMENTNUMBER_DIFFERS_FROM_REGISTERNUMBER, ap->Line);
    return 1;
  }

  Flags |= FLAG_DONE; /* We did something */

  str2 = FindClibFunc(name);
  if(!(string = FindClibFunc(ap->FuncName)))
    string = deftype;

  string = SkipBlanks(string);
  if(!strnicmp("void", string, 4))
    ret = 0;

  if(!OutClibType(string, 0) || !DoOutput(" %s("/*)*/, name))
    return 0;
  for(i = 0; i < ap->NumArgs-1; i++)
  {
    str2 = GetClibType(str2, i);	/* skip the equal parts */
    if(!(string = GetClibType(string, i)) ||
    !OutClibType(string, ap->Args[i].ArgName) || !DoOutput(", "))
      return 0;
  }
  lastarg = string;
  if((str2 = GetClibType(str2, i)))
  {
    if(!strncmp("...", str2, 3))
      str2 = 0;
    else if(!OutClibType(str2, ap->Args[i].ArgName) || !DoOutput(", "))
      return 0;
  }
  else if(ap->NumArgs == 1 && !DoOutput("ULONG tag, "))
    return 0;

  if(!DoOutput(/*(*/"...)\n{\n  %s%s("/*)*/, ret, ap->FuncName))
    return 0;
  for(i = 0; i < ap->NumArgs-1; i++)
  {
    if(!DoOutput("%s, ", ap->Args[i].ArgName))
      return 0;
  }
  if(!DoOutput("("/*)*/) || !(string = GetClibType(string, i)) ||
  !OutClibType(string,0))
    return 0;
  if(str2)
  {
    if(!DoOutput(/*((*/") &%s);\n}\n\n", ap->Args[ap->NumArgs-1].ArgName))
      return 0;
  }
  else if(ap->NumArgs == 1)
  {
    if(!DoOutput(/*((*/") &tag);\n}\n\n"))
      return 0;
  }
  else if (!DoOutput(/*(*/") ((ULONG) &%s + sizeof("/*))*/,
  ap->Args[ap->NumArgs-2].ArgName) || !OutClibType(lastarg,0) ||
  !DoOutput(/*(((*/")));\n}\n\n"))
    return 0;
  return 1;
}

ULONG FuncLVOXDEF(struct AmiPragma *ap, ULONG flags, STRPTR name)
{
  Flags |= FLAG_DONE; /* We did something */
  return DoOutput("\t\tXDEF\t_LVO%s\n", name);
}

ULONG FuncLVO(struct AmiPragma *ap, ULONG flags, STRPTR name)
{
  Flags |= FLAG_DONE; /* We did something */
  return DoOutput("\n_LVO%-24s\tEQU\t-%ld", name, ap->Bias);
}

ULONG FuncLocCode(struct AmiPragma *ap, ULONG flags, STRPTR name)
{
  ULONG a[5];
  STRPTR str, str2 = Flags & FLAG_LOCALREG ? "rE" : "";
  LONG i = strlen(ShortBaseNameUpper);
  ULONG j;

  Flags |= FLAG_DONE; /* We did something */

  a[0] = HUNK_UNIT; a[1] = 0; a[2] = HUNK_NAME;
  a[3] = (i + 4 + 3)>>2;

  DoOutputDirect(a, 16);
  DoOutputDirect(ShortBaseNameUpper, i);
  DoOutputDirect("_LOC\0\0\0", (a[3]<<2)-i);

  if(Flags & FLAG_LOCALREG)
  {
    if((flags & FUNCFLAG_TAG))
    {
      j = ap->Args[ap->NumArgs-1].ArgReg;
      a[0] = HUNK_CODE; a[1] = 4;
      a[2] = 0x2F000000 + (j << 16);	/* MOVE <ea>,-(A7) */

      DoOutputDirect(a, 10);

      a[1] = 0x4EAE0000 + (UWORD) (- ap->Bias); /* JSR instruction */
      a[2] = 0x201F4E75;		/* MOVE (A7)+,<ea> */
      a[3] = 0;
      if(j > 7)
      { 				/* LEA x(A7),Ax */
	j -= 8;
	a[0] = 0x41EF0008 | (j << 25);
	a[2] += 0x400000;		/* set A flag */
      }
      else
      { 				/* MOVE.L A7,Dx  -- ADDQ.L #8,Dx */
	a[0] = 0x200F5080 | j | (j << 25);
      }
      a[2] += j << 25;

      DoOutputDirect(a, 14);
    }
    else
    {
      a[0] = HUNK_CODE; a[1] = 1;
      a[2] = 0x4EEE0000 + (UWORD) (- ap->Bias); /* JMP instruction */
      DoOutputDirect(a, 12);
    }
  }
  else
  {
    ULONG registers, offset = 1, pos = 4, l;
    UWORD data[50];				/* 100 byte data field */

    registers = GetRegisterData(ap);

    data[0] = 0;
    data[1] = HUNK_CODE;
    data[2] = 0;
    /* data[3] is size */

    if(!registers) /* happens only when !(ap->Flags & AMIPRAG_A6USE) */
    {
      data[pos++] = 0x2F0E;		/* MOVE.L A6,-(A7) */
      ++offset;				/* one long more on stack */
    }
    else
    {
      data[pos++] = 0x48E7;		/* MOVEM.L xxx,-(A7) */
      data[pos++] = registers;		/* storem MOVEM.L registers */
      for(l = (UWORD) registers; l; l >>= 1)
      {
        if(l & 1)
	  ++offset;			/* get offset addition */
      }
    }

    if(!(ap->Flags & AMIPRAGFLAG_A6USE)) /* store library base in A6 */
    {
      data[pos++] = 0x2C6F;		/* MOVE.L ofs(A7),A6 */
      data[pos++] = (offset++) << 2;
    }

    pos = AsmStackCopy(data+pos, ap, flags, offset) - data;

    /* here comes the base reference */
    data[pos++] = 0x4EAE;		/* JSR xxx(A6) */
    data[pos++] = -ap->Bias;		/* JSR offset */
    if(registers)
    {
      data[pos++] = 0x4CDF;		/* MOVEM.L (A7)+,xxx */
      data[pos++] = (registers >> 16);	/* store MOVEM.L registers */
    }
    else
      data[pos++] = 0x2C5F;		/* MOVE.L (A7)+,A6 */

    data[pos++] = 0x4E75;		/* RTS */

    if(pos & 1)
      data[pos++] = 0;			/* round to long */

    data[3] = (pos-4)>>1;		/* store hunk len */
    DoOutputDirect(data, pos<<1);
  }

  a[0] = HUNK_EXT;
  DoOutputDirect(a,4);

  /* here come the XDEF name references */

  OutputXDEF("%s", name);	/* ASM names */
  OutputXDEF("LOC_%s", name);

  OutputXDEF("_%s", name);	/* C names */
  OutputXDEF("_LOC_%s", name);

  if(!ap->NumArgs && clibbuf)
  {
    OutputXDEF("%s__%sP07Library", name, str2);	/* C++ names no parameters */
    OutputXDEF("LOC_%s__%sP07Library", name, str2);
  }
  else if((str = FindClibFunc(name)))
  {
    UBYTE txt[100];
    ULONG ret = 0;

    do
    {
      if((ret = CopyCPPType(txt, str, ret, name, ap->Args)))
      { 				/* C++ names with parameters */
        if(!(ap->Flags & AMIPRAGFLAG_A6USE))
        {
          OutputXDEF("%s__%sP07Library%s", name, str2, txt);
	  OutputXDEF("LOC_%s__%sP07Library%s", name, str2, txt);
	}
	else
	{
          OutputXDEF("%s__%s", name, txt);
	  OutputXDEF("LOC_%s__%s", name, txt);
	}
      }
    } while(ret == 0xFFFFFFFF);
  }

  a[0] = 0; a[1] = HUNK_END;

  return DoOutputDirect(a, 8);
}

ULONG FuncLocText(struct AmiPragma *ap, ULONG flags, STRPTR name)
{
  STRPTR string;
  LONG i;

  if(ap->Flags & AMIPRAGFLAG_ARGCOUNT)
  {
    DoError(ERR_ARGUMENTNUMBER_DIFFERS_FROM_REGISTERNUMBER, ap->Line);
    return 1;
  }

  Flags |= FLAG_DONE; /* We did something */

  if(!(string = FindClibFunc(name)))
    string = deftype;

  string = SkipBlanks(string);

  OutClibType(string, 0);
  DoOutput(" LOC_%s("/*)*/, name);
  if(!(ap->Flags & AMIPRAGFLAG_A6USE))
  {
    if(Flags & FLAG_LOCALREG)
      DoOutput("register __a6 ");
    DoOutput("struct Library * libbase");
    if(ap->NumArgs)
      DoOutput(", ");
  }

  if(ap->NumArgs)
  {
    for(i = 0; i < ap->NumArgs-1; i++)
    {
      if(!(string = GetClibType(string, i)) ||
      ((Flags & FLAG_LOCALREG &&
      !DoOutput("register __%s ", RegNames[ap->Args[i].ArgReg]))) ||
      !OutClibType(string, ap->Args[i].ArgName) || !DoOutput(", "))
	return 0;
    }


    if(flags & FUNCFLAG_NORMAL)
    {
      if(!(string = GetClibType(string, i)) ||
      ((Flags & FLAG_LOCALREG &&
      !DoOutput("register __%s ", RegNames[ap->Args[i].ArgReg]))) ||
      !OutClibType(string, ap->Args[i].ArgName) ||
      !DoOutput(/*(*/");\n"))
        return 0;
      if(BaseName)
      {
        DoOutput("#define %s("/*)*/, name);
        for(i = 0; i < ap->NumArgs-1; ++i)
          DoOutput("%lc, ", (i+'a'));
        DoOutput(/*(*/"%lc) LOC_%s((struct Library *) %s, "/*)*/,(i+'a'),
        name, BaseName);
        for(i = 0; i < ap->NumArgs-1; ++i)
	  DoOutput("%lc, ",(i+'a'));
        return DoOutput(/*(*/"%lc)\n\n",(i+'a'));
      }
    }
    else
      return DoOutput(/*(*/"...);\n");
  }
  else if(BaseName)
    return DoOutput(/*(*/");\n#define %s(a) LOC_%s((struct Library *) a)\n\n",
    name, name);
  else
    return DoOutput(/*(*/");\n");
  return 1;
}

ULONG FuncInline(struct AmiPragma *ap, ULONG flags, STRPTR name)
{
  ULONG noret = 0, a45 = 0, d7used = 0, i, j;
  struct CPP_NameType nt;
  STRPTR string, str = 0;

  if(ap->Flags & AMIPRAGFLAG_ARGCOUNT)
  {
    DoError(ERR_ARGUMENTNUMBER_DIFFERS_FROM_REGISTERNUMBER, ap->Line);
    return 1;
  }

  Flags |= FLAG_DONE; /* We did something */

  if(flags & FUNCFLAG_ALIAS)
  {
    DoOutput("#define %s("/*)*/, name);
    for(i = 0; i < ap->NumArgs-1; ++i)
      DoOutput("%s, ", ap->Args[i].ArgName);
    DoOutput(/*(*/"%s) %s("/*)*/, ap->Args[i].ArgName, ap->FuncName);
    for(i = 0; i < ap->NumArgs-1; ++i)
      DoOutput("(%s), ", ap->Args[i].ArgName);
    return DoOutput(/*(*/"(%s))\n\n", ap->Args[i].ArgName);
  }

  if(!(string = FindClibFunc(name)))
    string = deftype;
  if(GetCPPType(&nt, string) && !nt.Flags && nt.Type == CPP_TYPE_VOID)
    noret = 1; /* this is a void function */
  for(i = 0; i < ap->NumArgs; ++i)
  {
    if(ap->Args[i].ArgReg == REG_A4 || ap->Args[i].ArgReg == REG_A5)
    {
      if(!a45)
	a45 = ap->Args[i].ArgReg; /* set flag */
      else /* Security check */
      {
	DoError(ERR_INLINE_A4_AND_A5, ap->Line); return 1; /* skip this entry */
      }
    }
    if(ap->Args[i].ArgReg == REG_D7) /* Used only when a45 != 0 */
      d7used = 1;
  }
  if(a45 && d7used) /* Security check */
  {
    DoError(ERR_INLINE_D7_AND_A45, ap->Line); return 1; /* skip this entry */
  }

  if((flags & FUNCFLAG_TAG))
  {
    if(!(Flags & FLAG_INLINESTUB)) /* no stubs */
    {
      DoOutput("#ifndef NO_INLINE_STDARG\n#define %s("/*)*/, name);
      for(i = 0; i < ap->NumArgs-1; ++i)
      {
        DoOutput("%s, ", ap->Args[i].ArgName);
      }
      DoOutput(/*(*/"tags...) \\\n\t({ULONG _tags[] = {tags}; %s("/*}))*/, ap->FuncName);
      for(i = 0; i < ap->NumArgs-1; ++i)
        DoOutput("(%s), ", ap->Args[i].ArgName);
      DoOutput("("/*)*/);
      OutClibType(GetClibTypePos(FindClibFunc(ap->FuncName), ap->NumArgs), 0);
      return DoOutput(/*({((*/")_tags);})\n#endif\n\n");
    }
    else
    {
      OutClibType(string, 0);
      DoOutput(" %s("/*)*/, name);

      for(i = 0; i < ap->NumArgs-1; ++i)
      {
        string = GetClibType(string, i);
        OutClibType(string, ap->Args[i].ArgName);
        DoOutput(", ");
      }

      DoOutput(/*(*/"int tag, ...)\n{\n   "/*}*/);
      if(!noret)
	DoOutput("return ");

      DoOutput("%s("/*)*/, name);
      for(i = 0; i < ap->NumArgs-1; ++i)
        DoOutput("%s, ", ap->Args[i].ArgName);

      return DoOutput(/*{(*/"(struct TagItem *)&tag);\n}\n\n");
    }
  }

  if(Flags & FLAG_INLINENEW) /* new style */
  {
    DoOutput("#define %s("/*)*/, name);

    if(ap->NumArgs)
    {
      for(i = 0; i < ap->NumArgs-1; ++i)
        DoOutput("%s, ", ap->Args[i].ArgName);
      DoOutput("%s", ap->Args[i].ArgName);
    }
    DoOutput(/*(*/") \\\n\tLP%ld%s%s%s%s(0x%lx, "/*)*/, ap->NumArgs,
    (noret ? "NR" : ""), (a45 ? RegNamesUpper[a45] : (STRPTR) ""),
    (BaseName ? "" : "UB"), (CheckFuncPar(string) ? "FP" : ""), ap->Bias);
    if(!noret)
    {
      OutClibType(string, 0);
      DoOutput(", ");
    }
    DoOutput("%s, ", name);

    for(i = 0; i < ap->NumArgs; ++i)
    {
      j = ap->Args[i].ArgReg;
      if(a45 && (j == REG_A4 || j == REG_A5))
        j = REG_D7;
      string = GetClibType(string, i);
      if(GetCPPType(&nt, string) && (nt.Flags & CPP_FLAG_FUNCTION))
      {
        DoOutput("__fpt"); str = string;
      }
      else
        OutClibType(string, 0);
  
      DoOutput(", %s, %s%s", ap->Args[i].ArgName, RegNames[j],
      (i == ap->NumArgs-1 && !BaseName ? "" : ", "));
    }

    if(BaseName) /* was "##base" used? */
      DoOutput("\\\n\t, %s_BASE_NAME", ShortBaseNameUpper);

    if(str)
    {
      DoOutput(", ");
      OutClibType(str, "__fpt");
    }
    return DoOutput(/*(*/")\n\n");
  }

  /* old mode or stubs mode */

  DoOutput("%s__inline ", Flags & FLAG_INLINESTUB ? "" : "extern ");
  OutClibType(string, 0);
  DoOutput("\n%s(%s"/*)*/, name, (BaseName ?
  (ap->NumArgs ? "BASE_PAR_DECL " : "BASE_PAR_DECL0") : ""));

  str = string;
  for(i = 0; i < ap->NumArgs; ++i)
  {
    string = GetClibType(string, i);
    OutClibType(string, ap->Args[i].ArgName);
    if(i < ap->NumArgs-1)
      DoOutput(", ");
  }
  DoOutput(/*(*/")\n{\n%s"/*}*/, (BaseName ? "   BASE_EXT_DECL\n" : ""));

  if(!noret)
  {
    DoOutput("   register ");
    OutClibType(str, "res");
    DoOutput(" __asm(\"d0\");\n");
  }

  if(BaseName)
    DoOutput("   register struct %s *a6 __asm(\"a6\") = BASE_NAME;\n",
    GetBaseType());

  string = str;
  for(i = 0; i < ap->NumArgs; ++i)
  {
    j = ap->Args[i].ArgReg;
    if(a45 && (j == REG_A4 || j == REG_A5))
      j = REG_D7;

    DoOutput("   register ");
    string = GetClibType(string, i);
    OutClibType(string, RegNames[j]);
    DoOutput(" __asm(\"%s\") = %s;\n", RegNames[j], ap->Args[i].ArgName);
  }

  if(a45)
  {
    DoOutput("   __asm volatile (\"exg d7,%s\\n\\t"/*)*/
    "jsr a6@(-0x%lx:W)\\n\\texg d7,%s\"\n", RegNames[a45],
    ap->Bias, RegNames[a45]);
  }
  else
    DoOutput("   __asm volatile (\"jsr a6@(-0x%lx:W)\"\n"/*)*/, ap->Bias);

  DoOutput(noret ? "   : /* No Output */\n" : "   : \"=r\" (res)\n");

  DoOutput("   : ");
  if(BaseName)
    DoOutput("\"r\" (a6)%s", (ap->NumArgs ? ", ": ""));

  for(i = 0; i < ap->NumArgs; ++i)
  {
    j = ap->Args[i].ArgReg;
    if(a45 && (j == REG_A4 || j == REG_A5))
      j = REG_D7;

    DoOutput("\"r\" (%s)%s", RegNames[j], (i < ap->NumArgs-1 ? ", " : ""));
  }

  DoOutput("\n   : \"d0\", \"d1\", \"a0\", \"a1\", \"fp0\", \"fp1\"");

  if(noret)
    return DoOutput(/*({*/", \"cc\", \"memory\");\n}\n\n");
  else
    return DoOutput(/*({*/", \"cc\", \"memory\");\n   return res;\n}\n\n");
}

ULONG CallFunc(ULONG tagmode, STRPTR comment, FuncType Func)
{
  struct Comment *com = 0;
  struct AmiPragma *ap;

  if(comment)
    com = (struct Comment *) Comment.First;

  for(ap = (struct AmiPragma *) AmiPragma.First; ap && !CTRL_C;
  ap = (struct AmiPragma *) ap->List.Next)
  {
    if(BaseName && (ap->Flags & AMIPRAGFLAG_A6USE))
    {
      DoError(ERR_A6_NOT_ALLOWED, ap->Line);
    }
    else if((ap->Flags & AMIPRAGFLAG_PUBLIC) || (Flags & FLAG_PRIVATE))
    {
      while(com && com->Bias <= ap->Bias)
      {
	if(!DoOutput(comment, com->Data))
	  return 0;
	com = (struct Comment *) com->List.Next;
      }

      if(tagmode != TAGMODE_TAGS && ap->FuncName && !Func(ap, FUNCFLAG_NORMAL, ap->FuncName))
	return 0;
      if(ap->AliasName &&
      (((ap->AliasName->Type & FUNCFLAG_TAG) && tagmode) ||
      (!(ap->AliasName->Type & FUNCFLAG_TAG) && tagmode != TAGMODE_TAGS)) &&
      !Func(ap, FUNCFLAG_ALIAS|ap->AliasName->Type, ap->AliasName->AliasName))
	return 0;
      if(tagmode && ap->TagName && !Func(ap, FUNCFLAG_TAG, ap->TagName))
	return 0;
    }
  }
  while(com)
  {
    if(!DoOutput(comment, com->Data))
      return 0;
    com = (struct Comment *) com->List.Next;
  }
  return 1;
}

/* ------------------------------------------------------------------ */

ULONG CheckFuncPar(STRPTR str)
{
  struct CPP_NameType nt;
  ULONG i = 0;

  while((str = GetClibType(str, i++)))
  {
    if(GetCPPType(&nt, str) && (nt.Flags & CPP_FLAG_FUNCTION))
      return 1;
  }
  return 0;
}

/* return non zero, when ok, return 0xFFFFFFFF when STRPTR and not flags */
ULONG CopyCPPType(STRPTR buffer, STRPTR a, ULONG flag, STRPTR func,
struct AmiArgs *args)
{
/* when flag, then STRPTR is unsigned char * mode, else signed char * */
  ULONG ret = 1;
  ULONG k = 0;
  struct CPP_NameType nt;

  while((a = GetClibType(a,k)))
  {
    if(!GetCPPType(&nt, a))
    {
      APTR str;
      ULONG l = GetTypeLength(nt.TypeStart);

      if((str = AllocMem(l+1, MEMF_ANY|MEMF_CLEAR)))
        CopyMem(nt.TypeStart, str, l);

      DoError(ERR_UNKNOWN_VARIABLE_TYPE, 0, str ? str : "?", func);

      if(str)
        FreeMem(str, l);

      return 0;
    }

    if(!flag && (nt.Flags & CPP_FLAG_STRPTR))
      ret = 0xFFFFFFFF;

    if(args && (Flags & FLAG_LOCALREG) && (nt.Type != CPP_TYPE_VARARGS))
    {
      *(buffer++) = CPP_TYPE_REGISTER;
      *(buffer++) = args[k].ArgReg + (args[k].ArgReg < 10 ? '0' : 'A'-10);
    }
    if(nt.Flags & CPP_FLAG_FUNCTION)
    {
      *(buffer++) = CPP_TYPE_POINTER; *(buffer++) = CPP_TYPE_FUNCTION;
    }
    while(nt.PointerDepth--)
      *(buffer++) = CPP_TYPE_POINTER;
    if(nt.Flags & CPP_FLAG_CONST)
      *(buffer++) = CPP_TYPE_CONST;
    if((nt.Flags & CPP_FLAG_UNSIGNED) || (flag && (nt.Flags & CPP_FLAG_STRPTR)))
      *(buffer++) = CPP_TYPE_UNSIGNED;
    if(nt.Type)
      *(buffer++) = nt.Type;
    else
    {
      ULONG i;
      sprintf(buffer, "%02ld", (ULONG) nt.StructureLength); buffer += 2;
      for(i = 0; i < nt.StructureLength; ++i)
	*(buffer++) = nt.StructureName[i];
    }
    if(nt.Flags & CPP_FLAG_FUNCTION)
    {
      if(nt.FuncArgs)
      {
        UBYTE txt[200];
        sprintf(txt, "'ArgFunc of %s'", func);
        if(!CopyCPPType(buffer, nt.FuncArgs+1, flag, txt, 0))
          return 0;
        while(*buffer)
          ++buffer;
      }
      *(buffer++) = CPP_TYPE_FUNCEND;
    }
    ++k;
  }

  *(buffer) = 0;

  return ret;
}

LONG GetTypeLength(STRPTR txt)
{
  ULONG l = 0;
  STRPTR start = txt;

  while(*start && (l || (*start != ',' && *start != /*(*/')')))
  {
    if(*start == '('/*)*/)
      ++l;
    else if(*start == /*(*/')')
      --l;
    ++start;
  }
  return start-txt;
}

LONG GetCPPType(struct CPP_NameType *data, STRPTR start)
{
  ULONG ok = 1, i = 0;
  STRPTR u;

  memset(data, 0, sizeof(struct CPP_NameType));

  data->TypeStart = SkipBlanks(start);

  if(start == (STRPTR) deftype)
  {
    data->Flags = CPP_FLAG_UNSIGNED;
    data->Type = CPP_TYPE_LONG;
    return 0;
  }

  do
  {
    start = SkipBlanks((u = start));
    if(!strncmp("...",start,3))
    {
      data->Type = CPP_TYPE_VARARGS; return 1;
    }
    if(CheckKeyword(start, "const", 5))
    {
      data->Flags |= CPP_FLAG_CONST; start += 6;
    }
    else if(CheckKeyword(start, "signed", 6))
      start += 7;
    else if(CheckKeyword(start, "unsigned", 8))
    {
      data->Flags |= CPP_FLAG_UNSIGNED; start += 9;
    }
    else if(CheckKeyword(start, "struct", 6))
    {
      data->StructureName = SkipBlanks(start+6);
      u = start = SkipName(data->StructureName);
      data->StructureLength = start-data->StructureName;
      break;
    }
    else if(!i)
    {
      for(i = 0; CPP_Field[i].Text; ++i)
      {
	if(!strncmp(start, CPP_Field[i].Text, CPP_Field[i].Length))
	{
	  start += CPP_Field[i].Length;
	  data->Type = CPP_Field[i].Type;
	  data->Flags |= CPP_Field[i].Flags;
	  if(CPP_Field[i].Flags & CPP_FLAG_POINTER)
	    ++data->PointerDepth;
	  ++i; /* when first element is correct, then i is zero */
	  break;
	}
      }
    }
    else
      break;
  } while(1);

  data->TypeLength = u - (data->TypeStart);

  do
  {
    u = SkipBlanks(start);
    if(*u == '*')
    {
      start = u+1; ++data->PointerDepth;
      data->TypeLength = start - (data->TypeStart);
    }
  } while(*u == '*');

  if(*u == '('/*)*/)
  {
    ok = 0;
    u = SkipBlanks(++u);
    if(*u == '*')
    {
      u = SkipBlanks(SkipName(SkipBlanks(++u)));
      if(*u == /*(*/')')
      {
        u = SkipBlanks(++u);
        if(*u == '('/*)*/)
        {
          data->Flags |= CPP_FLAG_FUNCTION;
          data->FuncArgs = u;
          ok = 1;
          u = SkipBlanks(++u);
          if(*u == /*(*/')')
            data->FuncArgs = 0;
        }
      }
    }
  }

  if(data->PointerDepth)
    data->Flags |= CPP_FLAG_POINTER;

  if((!data->Type && !data->StructureName) || !ok)
    return 0;
  return 1;
}

STRPTR FindClibFunc(STRPTR func) /* finds the needed function */
{
  ULONG len = strlen(func);
  STRPTR string, linestart, strend = clibbuf + clibsize;
  ULONG commentmode = 0;

#ifdef DEBUG_OLD
  VPrintf("FindClibFunc: %s\n", &func);
#endif

  if(!(linestart = string = clibbuf))
    return 0;

  do
  {
    while(*string && (commentmode || *string != '('/*)*/))
    {
      if(*(string++) == '/')
      {
	if(*string == '*')		/* start of comment */
	  commentmode = 1;
	else if(*(string-2) == '*')	/* end of comment */
	  commentmode = 0;
	else if(*string == '/') 	/* skip line comments */
	{
	  while(*string)
	    ++string;
	}
      }
    }

    if(*string == '(' /*)*/)
    {
      while(*(--string) == ' ' || *string == '\t')
	;
      if(!strncmp(func, string-len+1, len) && (*(string-len) == ' ' ||
      *(string-len) == '\t' || *(string-len) == '*' || !*(string-len)))
	return linestart;
    }
    while(string < strend && *string)
      ++string;
    if(!*string)
      linestart = ++string;
  } while(string < strend);

  DoError(ERR_PROTOTYPE_MISSING, 0, func);

  return 0;
}

LONG CheckKeyword(STRPTR string, STRPTR keyword, LONG size)
{
  if(!strncmp(string, keyword, size))
  {
    string += size;
    if(*string == ' ' || *string == '\t' || *string == '\n')
      return size;
  }
  return 0;
}

/* This returns length of easy types only - used for unknown types, which
   cannot be found by use of GetCPPType */
ULONG GetClibLength(STRPTR start) /* returns length of the type */
{
  STRPTR old = start, u;
  ULONG a = 1;

#ifdef DEBUG_OLD
  VPrintf("GetClibLength:\n", 0);
#endif

  while(a)
  {
    start = SkipBlanks(start); a = 0;
    if(CheckKeyword(start, "const", 5))
    {
      ++a; start += 6;
    }
    if(CheckKeyword(start,"struct", 6) || CheckKeyword(start, "signed", 6))
    {
      ++a; start += 7;
    }
    if(CheckKeyword(start, "unsigned", 8))
    {
      ++a; start += 9;
    }
  }

  while(*start && *start != ' ' && *start != '\t' && *start != '*' &&
  *start != /*(*/')')
   ++start;

  do
  {
    u = SkipBlanks(start);
    if(*u == '*')
      start = u+1;
  } while(*u == '*');

  return (ULONG) (start-old);
}

ULONG OutClibType(STRPTR start, STRPTR txt)
{
  struct CPP_NameType nt;

  if(!GetCPPType(&nt, start))
    nt.TypeLength = GetClibLength(nt.TypeStart);

  DoOutputDirect(nt.TypeStart, nt.TypeLength);
  if(!DoOutput((nt.Flags & CPP_FLAG_FUNCTION) ? (txt ? " (*%s)" : " (*)") :
  (txt ? " %s" : ""), txt))
    return 0;

  if(nt.Flags & CPP_FLAG_FUNCTION)
  {
    if(nt.FuncArgs)
      return DoOutputDirect(nt.FuncArgs, GetTypeLength(nt.FuncArgs));
    else
      return DoOutput("()");
  }

  return 1;
}

/* searches for definition at position xxx */
STRPTR GetClibTypePos(STRPTR start, ULONG arg)
{
  ULONG i;

  for(i = 0; i < arg && start; ++i)
    start = GetClibType(start, i);
  return start;
}

STRPTR GetClibType(STRPTR start, ULONG nofirst) /* searches for next type definition */
{
  if(start == (STRPTR) deftype)
    return start;

  if(nofirst)
    start += GetTypeLength(start);
  else
  {
    while(*start && *start != '('/*)*/)
      ++start;
  }
  if(!*start || *start == /*(*/')')
    return 0;
  return SkipBlanks(++start);
}

/* ------------------------------------------------------------------ */

ULONG CallPrag(ULONG tagmode, STRPTR type, FuncType Func)
{
  if(type)
    if((*type && !DoOutput("#if%s\n", type)) ||
    !(CallFunc(tagmode, tagmode ? 0 : "/%s */\n", Func)) ||
    (*type && !DoOutput("#endif\n")) || CTRL_C)
      return 0;
  return 1;
}

ULONG CreatePragmaFile(STRPTR amicall, STRPTR libcall, STRPTR amitags,
STRPTR libtags, ULONG mode)
{
  switch(mode)
  {
  case PRAGMODE_PRAGLIB: DoOutput("#ifndef _INCLUDE_PRAGMA_%s_LIB_H\n#define _INCLUDE_PRAGMA_%s_LIB_H\n",
    ShortBaseNameUpper, ShortBaseNameUpper); break;
  case PRAGMODE_PRAGSLIB: DoOutput("#ifndef PRAGMAS_%s_LIB_H\n#define PRAGMAS_%s_LIB_H\n",
    ShortBaseNameUpper, ShortBaseNameUpper); break;
  case PRAGMODE_PRAGSPRAGS: DoOutput("#ifndef PRAGMAS_%s_PRAGMAS_H\n#define PRAGMAS_%s_PRAGMAS_H\n",
    ShortBaseNameUpper, ShortBaseNameUpper); break;
  case PRAGMODE_NONE: break;
  default: return 0;
  }

  if(HEADER)
  {
    DoOutput("\n");
    DoOutputDirect(HEADER, headersize);
  }

  if(mode != PRAGMODE_NONE && !DoOutput("\n#ifndef CLIB_%s_PROTOS_H\n#include "
  "<clib/%s_protos.h>\n#endif\n\n", ShortBaseNameUpper, ShortBaseName))
    return 0;

  if((Flags & FLAG_EXTERNC) &&
  !DoOutput("#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n"))
    return 0;

  if(
  !CallPrag(TAGMODE_NORMAL, amicall, FuncAMICALL) ||
  !CallPrag(TAGMODE_NORMAL, libcall, FuncLIBCALL))
    return 0;

  if(tagfuncs)
  {
    if(
    !CallPrag(TAGMODE_TAGS, amitags, FuncAMICALL) ||
    !CallPrag(TAGMODE_TAGS, libtags, FuncLIBCALL))
      return 0;
  }

  if((Flags & FLAG_EXTERNC) &&
  !DoOutput("\n#ifdef __cplusplus\n}\n#endif\n"))
    return 0;

  switch(mode)
  {
  case PRAGMODE_PRAGLIB: DoOutput("\n#endif\t/*  _INCLUDE_PRAGMA_%s_LIB_H  */",
    ShortBaseNameUpper); break;
  case PRAGMODE_PRAGSLIB: DoOutput("\n#endif\t/*  PRAGMAS_%s_LIB_H  */",
    ShortBaseNameUpper); break;
  case PRAGMODE_PRAGSPRAGS: DoOutput("\n#endif\t/*  PRAGMAS_%s_PRAGMA_H  */",
    ShortBaseNameUpper); break;
  case PRAGMODE_NONE: break;
  default: return 0;
  }
  return Output_Error;
}

ULONG CreateCSTUBSFile(void)
{
  DoOutput("#ifndef _INCLUDE_%s_CSTUBS_H\n#define _INCLUDE_%s_CSTUBS_H\n",
    ShortBaseNameUpper, ShortBaseNameUpper);

  if(!clibbuf)
    DoError(ERR_NOPROTOTYPES_FILE, 0);

  if(HEADER)
  {
    DoOutput("\n");
    DoOutputDirect(HEADER, headersize);
  }

  if(!DoOutput("\n#ifndef CLIB_%s_PROTOS_H\n#include "
  "<clib/%s_protos.h>\n#endif\n\n", ShortBaseNameUpper, ShortBaseName))
    return 0;

  if(!CallFunc(TAGMODE_TAGS, "/%s */\n", FuncCSTUBS))
    return 0;

  return DoOutput("#endif\t/*  _INCLUDE_%s_CSTUBS_H  */",
  ShortBaseNameUpper);
}

ULONG CreateLVOFile(ULONG mode)
{
  STRPTR data = "_LVO_I";

  if(mode == 2 || mode == 4)
    data = "_LIB_I";

  if(!DoOutput("\t\tIFND LIBRARIES_%s%s\nLIBRARIES_%s%s\tSET\t1\n\n",
  ShortBaseNameUpper, data, ShortBaseNameUpper, data) ||
  (HEADER && (!DoOutput("\n") || !DoOutputDirect(HEADER, headersize))) ||
  (mode <= 2 && !CallFunc(TAGMODE_NORMAL, 0, FuncLVOXDEF)) ||
  !CallFunc(TAGMODE_NORMAL, "\n%s", FuncLVO) ||
  !DoOutput("\n\n\t\tENDC") || CTRL_C)
    return 0;

  return 1;
}

ULONG CreateAsmStubs(ULONG mode, ULONG callmode)
{
  /* 1 = Text, 2 = Code */
  switch(mode)
  {
  case 1:
    if((HEADER && (!DoOutput("\n") || !DoOutputDirect(HEADER, headersize))) ||
    !DoOutput("\tSECTION\t \"%s_STUBS\",CODE\n\tXREF\t_%s\n",
    ShortBaseNameUpper, BaseName) ||
    !CallFunc(callmode, 0, FuncAsmText))
      return 0;
    break;
  case 2:
    if(!CallFunc(callmode, 0, FuncAsmCode))
      return 0;
    break;
  }

  if(CTRL_C)
    return 0;
  return 1;
}

ULONG CreateProtoFile(ULONG Type)
{
  STRPTR str1 = "pragma", str2 = "lib";

  DoOutput("#ifndef _PROTO_%s_H\n#define _PROTO_%s_H\n", ShortBaseNameUpper,
  ShortBaseNameUpper);

  if(HEADER)
  {
    DoOutput("\n");
    DoOutputDirect(HEADER, headersize);
  }

  switch(Type)
  {
    case 4: str1 = "pragmas"; /* no break; */
    case 2: str2 = "pragmas"; break;
    case 3: str1 = "pragmas"; break;
    case 5: str1 = "local"; str2 = "loc"; break;
  }

  DoOutput("\n");
  if(BaseName)
  {
    if(Type == 6)
      DoOutput("#ifndef __NOLIBBASE__\n  ");
    DoOutput("extern struct %s *%s;\n", GetBaseType(), BaseName);
    if(Type == 6)
      DoOutput("#endif\n");
  }
  DoOutput("\n#include <exec/types.h>\n");
  if(Type != 5)
    DoOutput("#include <clib/%s_protos.h>\n", ShortBaseName);
  if(Type == 6)
    DoOutput("\n#ifdef " TEXT_GNUC "\n  #include <inline/%s.h>\n#else\n  ",
    ShortBaseName);
  DoOutput("#include <%s/%s_%s.h>\n", str1, ShortBaseName, str2);
  if(Type == 6)
    DoOutput("#endif\n");

  Flags |= FLAG_DONE;

  return DoOutput("\n#endif\t/*  _PROTO_%s_H  */\n", ShortBaseNameUpper);
}

ULONG CreateLocalData(STRPTR to, ULONG callmode)
{
  UBYTE a[40];

  DoOutput("#ifndef _INCLUDE_PROTO_%s_LOC_H\n#define _INCLUDE_PROTO_%s_LOC_H\n\n",
  ShortBaseNameUpper, ShortBaseNameUpper);

  if(HEADER)
  {
    DoOutput("\n");
    DoOutputDirect(HEADER, headersize);
  }

  { /* copies the include lines */
    STRPTR str = clibbuf, strend = clibbuf + clibsize;
    ULONG i = 0;

    /* works too, when no clibbuf, because then following is everytime false */
    while(str < strend)
    {
      if(!strncmp(str, "#include", 8))
      {
	DoOutput("%s\n",str); ++i;
      }
      while(*(str++))
	;
    }
    DoOutput(i ? "\n" : "#include <exec/types.h>\n\n");
  }

  if((Flags & FLAG_EXTERNC) &&
  !DoOutput("#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n"))
    return 0;

  if(!CallFunc(callmode, 0, FuncLocText))
    return 0;

  if((Flags & FLAG_EXTERNC) &&
  !DoOutput("#ifdef __cplusplus\n}\n#endif\n\n"))
    return 0;

  DoOutput("#endif\t/*  _INCLUDE_PROTO_%s_LOC_H  */", ShortBaseNameUpper);
  Out(out.size); /* clears buffer */

  sprintf(a, "%s_loc.lib", ShortBaseName);
  if(!CloseDest(to) || !(out.file = Open(a, MODE_NEWFILE)))
    return 0;

  CallFunc(callmode, 0, FuncLocCode);
  
  return CloseDest(a);
}

ULONG CreateInline(ULONG mode)
{
  if(!clibbuf)
    DoError(ERR_NOPROTOTYPES_FILE, 0);

  DoOutput("#ifndef _INLINE_%s_H\n#define _INLINE_%s_H\n\n",
  ShortBaseNameUpper, ShortBaseNameUpper);

  if(HEADER)
  {
    DoOutput("\n");
    DoOutputDirect(HEADER, headersize);
  }

  if(mode)
  {
    DoOutput("#ifndef __INLINE_STUB_H\n#include <inline/stubs.h>\n#endif\n\n");
    if(mode == 2)
      Flags |= FLAG_INLINESTUB;
  }
  else
  {
    DoOutput("#ifndef __INLINE_MACROS_H\n#include <inline/macros.h>\n#endif\n\n");
    Flags |= FLAG_INLINENEW;
  }

  if(BaseName)
  {
    if(mode)
      DoOutput("#ifndef BASE_EXT_DECL\n#define BASE_EXT_DECL\n"
      "#define BASE_EXT_DECL0 extern struct %s *%s;\n#endif\n"
      "#ifndef BASE_PAR_DECL\n#define BASE_PAR_DECL\n"
      "#define BASE_PAR_DECL0 void\n#endif\n"
      "#ifndef BASE_NAME\n#define BASE_NAME %s\n#endif\n\n"
      "BASE_EXT_DECL0\n\n", GetBaseType(), BaseName, BaseName);
    else
      DoOutput("#ifndef %s_BASE_NAME\n#define %s_BASE_NAME %s\n#endif\n\n",
      ShortBaseNameUpper, ShortBaseNameUpper, BaseName);
  }

  if(!CallFunc(TAGMODE_BOTH, "/%s */\n", FuncInline))
    return 0;

  if(mode && BaseName)
    DoOutput("#undef BASE_EXT_DECL\n#undef BASE_EXT_DECL0\n"
    "#undef BASE_PAR_DECL\n#undef BASE_PAR_DECL0\n#undef BASE_NAME\n\n");

  return DoOutput("#endif /*  _INLINE_%s_H  */", ShortBaseNameUpper);
}

/* ------------------------------------------------------------------ */

ULONG GetName(struct NameList *t, struct ShortListRoot *p, ULONG args)
{
  struct NameList *p2 = (struct NameList *) p->First;
  struct AmiPragma ap;
  ap.FuncName = t->NormName;
  ap.NumArgs = 1;
  ap.Args[0].ArgName = (args ? "args" : "tags");
  if(!MakeTagFunction(&ap))
    return 0;

  while(p2 && strcmp(p2->PragName, ap.TagName))
   p2 = (struct NameList *) p2->List.Next;

  if(!p2)
    return 0;

  t->Type = (args ? NTP_ARGS : NTP_TAGS);
  t->PragName = ap.TagName;
  RemoveItem(p, (struct ShortList *) p2);

#ifdef DEBUG_OLD
  VPrintf("GetName: name matches - %s _ %s\n", &t->NormName);
#endif

  return 1;
}

void OptimizeFDData(struct PragData *pd)
{
#ifdef DEBUG_OLD
  PutStr("OptimizeFDData\n");
#endif

  while(pd && !CTRL_C)
  {
    if(pd->NumNames > 1)
    {
      struct ShortListRoot n = {0,0,0}, p = {0,0,0};
      struct NameList *t;
      while(pd->Name.First)	/* sorts in AmiCall and TagCall */
      {
	t = (struct NameList *) pd->Name.First;

	RemoveItem(&pd->Name, (struct ShortList *) t);
	AddItem(t->PragName ? &p : &n, (struct ShortList *) t);
      }

      if(p.First)
      {
	t = (struct NameList *) n.First;
	while(p.First && t)
	{
	  if(!GetName(t, &p, 0))
	  {
	    GetName(t, &p, 1);
	  }
	  if(t->PragName)
	  {
	    struct NameList *t2 = (struct NameList *) t->List.Next;
	    RemoveItem(&n, (struct ShortList *)t);
	    AddItem(&pd->Name, (struct ShortList *) t);
	    t = t2;
	  }
	  else
	    t = (struct NameList *) t->List.Next;
	}
	while(p.First)
	{
	  if(n.First)
	  {
	    t = (struct NameList *) n.First;
	    t->PragName = ((struct NameList *)(p.First))->PragName;
	    RemoveItem(&n, (struct ShortList *) t);
#ifdef DEBUG_OLD
	    VPrintf("OptimizeFDData: names together - %s _ %s\n", &t->NormName);
#endif
	    t->Type = NTP_UNKNOWN;
	  }
	  else
	  {
	    ULONG i;

	    t = (struct NameList *) p.First;
	    i = strlen(t->PragName);
	    t->NormName = DupString(t->PragName, i+1);
	    t->NormName[i++] = 'A';
	    t->NormName[i] = 0;
	    t->Type = NTP_TAGS;
#ifdef DEBUG_OLD
	    VPrintf("OptimizeFDData: NormName created - %s _ %s\n", &t->NormName);
#endif
	  }

	  AddItem(&pd->Name, (struct ShortList *) t);
	  RemoveItem(&p, p.First);
	}
      }

      AddItem(&pd->Name, n.First); /* add left NormNames */
    }
    pd = (struct PragData *) pd->List.Next;
  }
}

ULONG MakeFD(struct PragList *pl)
{
  struct PragData *pd = (struct PragData *) pl->Data.First;
  ULONG bias;

#ifdef DEBUG_OLD
  PutStr("MakeFD\n");
#endif
  bias = pd->Bias;

  OptimizeFDData(pd);
#ifdef DEBUG_OLD
  PutStr("MakeFD: after Optimizing\n");
#endif
  DoOutput("##base _%s\n##bias %ld\n##public\n", pl->Basename, bias);

  while(pd && !CTRL_C && Output_Error)
  {
    struct NameList *n = (struct NameList *) pd->Name.First;

    if(bias != pd->Bias)
      DoOutput("##bias %ld\n", (bias = pd->Bias));

    while(n)
    {
      STRPTR lastpar = "last";
      ULONG i;

      if(n->Type == NTP_TAGS)
	lastpar = "tags";
      else if(n->Type == NTP_ARGS)
	lastpar = "args";

      DoOutput("%s("/*)*/,n->NormName);
      if(!pd->NumArgs)
	DoOutput(/*(*/")()\n");
      else
      {
	for(i = 0; i < pd->NumArgs-1; ++i)
	  DoOutput("par%ld,",i+1);
	DoOutput("%s)(", lastpar);
	for(i = 0; i < pd->NumArgs-1; ++i)
	  DoOutput("%s,", RegNames[pd->ArgReg[i]]);
	DoOutput("%s)\n", RegNames[pd->ArgReg[i]]);

	if(n->Type == NTP_UNKNOWN)
	{
	  ULONG i;
	  for(i = 0; n->NormName[i] == n->PragName[i]; ++i)
	    ;
	  DoOutput("*tagcall");
	  if(n->NormName[i])
	    DoOutput("-%s", n->NormName+i);
	  if(n->PragName[i])
	    DoOutput("+%s", n->PragName+i);

	  DoOutput("\n");
	}
      }
      if((n = (struct NameList *) n->List.Next))
	DoOutput("##bias %ld\n", pd->Bias);
      Flags |= FLAG_DONE;
    }

    pd = (struct PragData *)pd->List.Next; bias += 6;
  }

  if(CTRL_C)
    return 0;

  DoOutput("##end\n");

  return Output_Error;
}

ULONG AddFDData(struct ShortListRoot *pls, struct FDData *fd)
{
  struct NameList *t;
  struct PragList *pl = (struct PragList *) pls->First;
  struct PragData *pd;

  while(pl && strcmp(pl->Basename, fd->Basename))
    pl = (struct PragList *) pl->List.Next;

  if(!pl)
  {
#ifdef DEBUG_OLD
  VPrintf("AddFDData: New PragList - %s\n", &fd->Basename);
#endif
    if(!(pl = (struct PragList *) NewItem(pls)))
      return 100;
    pl->Basename = fd->Basename;
    pl->Data.Size = sizeof(struct PragData);
    AddItem(pls, (struct ShortList *) pl);
  }

  if((pd = (struct PragData *) pl->Data.First))
  {
    while(pd->List.Next && ((struct PragData *) pd->List.Next)->Bias
    <= fd->Bias)
      pd = (struct PragData *) pd->List.Next;
  }

  if(!pd || pd->Bias != fd->Bias)
  {
    struct PragData *pd2;
#ifdef DEBUG_OLD
    {
      ULONG args[2];
      args[0] = fd->Bias;
      args[1] = fd->NumArgs;
      VPrintf("AddFDData: New PragData - %ld, %ld\n", &args);
    }
#endif
    if(!(pd2 = (struct PragData *) NewItem(&pl->Data)))
      return 100;
    pd2->Bias = fd->Bias;
    CopyMem(fd->ArgReg, pd2->ArgReg, 14);
    pd2->NumArgs = fd->NumArgs;
    pd2->Name.Size = sizeof(struct NameList);
    if(!pd)
      AddItem(&pl->Data, (struct ShortList *) pd2);
    else if(pd->Bias > fd->Bias) /* Insert at start */
    {
      pd2->List.Next = pl->Data.First;
      pl->Data.First = (struct ShortList *) pd2;
    }
    else /* Insert the entry */
    {
      pd2->List.Next = pd->List.Next;
      pd->List.Next = (struct ShortList *) pd2;
    }
    pd = pd2;
  }
  else
  {
    ULONG i = fd->NumArgs;
    if(fd->NumArgs != pd->NumArgs)
      return ERR_DIFFERENT_TO_PREVIOUS;

    while(i--)
    {
      if(fd->ArgReg[i] != pd->ArgReg[i])
	return ERR_DIFFERENT_TO_PREVIOUS;
    }
  }

  t = (struct NameList *) pd->Name.First;	/* skips same names */
  while(t && strcmp(fd->Name, fd->Mode ? t->PragName : t->NormName))
    t = (struct NameList *) t->List.Next;

  if(t)
    return 0;

  if(!(t = (struct NameList *) NewItem(&pd->Name)))
    return 100;
  if(fd->Mode)
    t->PragName = fd->Name;
  else
    t->NormName = fd->Name;
  AddItem(&pd->Name, (struct ShortList *) t);
  ++(pd->NumNames);
#ifdef DEBUG_OLD
  VPrintf("AddFDData: New NameList - %s\n", &fd->Name);
#endif
  return 0;
}

UBYTE GetHexValue(UBYTE data)
{
  if(data >= 'a')
    return (UBYTE) (data - 'a' + 10);
  else if(data >= 'A')
    return (UBYTE) (data - 'A' + 10);
  else
    return (UBYTE) (data - '0');
}

ULONG GetLibData(struct FDData *fd)
{
  ULONG i;
  fd->Name = SkipBlanks(in.pos);
  in.pos = SkipName(fd->Name); *(in.pos++) = 0;
  in.pos = SkipBlanks(in.pos);
  fd->Bias = strtoul(in.pos, 0, 16);
  while(*in.pos)
    ++in.pos;
  if((fd->NumArgs = GetHexValue(*(--in.pos))) > 14)
    return ERR_TO_MUCH_ARGUMENTS;
  --in.pos; /* skips return register */
  for(i = 0; i < fd->NumArgs; ++i)
  {
    if((fd->ArgReg[i] = GetHexValue(*(--in.pos))) > 14)
      return ERR_EXPECTED_REGISTER_NAME;
  }
  return 0;
}

ULONG GetAmiData(struct FDData *fd)
{
  STRPTR endptr;
  in.pos = SkipBlanks(in.pos);
  if(*in.pos != '('/*)*/)
    return ERR_EXPECTED_OPEN_BRACKET;
  fd->Basename = ++in.pos;
  in.pos = SkipBlanks(endptr = SkipName(in.pos));
  if(*in.pos != ',')
    return ERR_EXPECTED_COMMA;
  *endptr = 0;
  in.pos = SkipBlanks(++in.pos);
  if(!strncmp(in.pos, "0x", 2))
    fd->Bias = strtoul(in.pos+2, 0, 16);
  else
    fd->Bias = strtoul(in.pos, 0, 10);

  in.pos = SkipBlanks(SkipName(in.pos));
  if(*in.pos != ',')
    return ERR_EXPECTED_COMMA;
  fd->Name = in.pos = SkipBlanks(++in.pos);
  in.pos = SkipBlanks(endptr = SkipName(in.pos));
  if(*in.pos != '('/*)*/)
    return ERR_EXPECTED_OPEN_BRACKET;
  *endptr = 0;
  in.pos = SkipBlanks(++in.pos);
  if(*in.pos == /*(*/')')
    return 0;
  --in.pos;
  while(*in.pos != /*(*/')')
  {
    ULONG i;
    in.pos = SkipBlanks(in.pos+1);
    for(i = 0; i < 16; i++)
      if(!strnicmp(RegNames[i], in.pos, 2))
	break;
    if(i == 16)
      return ERR_EXPECTED_REGISTER_NAME;
    if(i > 14)
      return ERR_ILLEGAL_REGISTER;

    if(fd->NumArgs > 14)
      return ERR_TO_MUCH_ARGUMENTS;

    fd->ArgReg[fd->NumArgs] = i; ++fd->NumArgs;

    in.pos = SkipBlanks(in.pos+2);

    if(*in.pos != ',' && *in.pos != ')')
      return ERR_EXPECTED_CLOSE_BRACKET;
  }
  in.pos = SkipBlanks(in.pos+1);
  if(*in.pos != ')')
    return ERR_EXPECTED_CLOSE_BRACKET;
  return 0;
}

ULONG CreateFDFile(STRPTR file, STRPTR to)
{
  struct ShortListRoot pl = {0, 0, sizeof(struct PragList)};
  ULONG linenum, err = 0, skip;

  for(linenum = 1; !CTRL_C && in.pos < in.buf + in.size; ++linenum)
  {
    in.pos = SkipBlanks(in.pos);
    if(!strncmp("#pragma", in.pos, 7))
    {
      struct FDData fd;

      skip = 0;
      memset(&fd, 0, sizeof(struct FDData));

      in.pos = SkipBlanks(in.pos+7);
      if(!strncmp("tagcall", in.pos, 7))
      {
	fd.Mode = 1;
	in.pos = SkipBlanks(in.pos+7);
	if(*in.pos == '(' /*)*/)	/* Storm method */
	  err = GetAmiData(&fd);
	else				/* SAS method */
	{
	  fd.Basename = in.pos;
	  in.pos = SkipName(fd.Basename); *(in.pos++) = 0;
	  err = GetLibData(&fd);
	}
      }
      else if(!strncmp("amicall", in.pos, 7))	/* Storm method */
      {
	in.pos += 7;
	err = GetAmiData(&fd);
      }
      else if(!strncmp("libcall", in.pos, 7))	/* SAS method */
      {
	fd.Basename = SkipBlanks(in.pos+7);
	in.pos = SkipName(fd.Basename); *(in.pos++) = 0;
	err = GetLibData(&fd);
      }
      else if(!strncmp("syscall", in.pos, 7))	/* SAS method */
      {
	fd.Basename = "SysBase";
	err = GetLibData(&fd);
      }
      else
	skip = 1;

      if(err)
	DoError(err, linenum);
      else if(skip)
	;
      else if((err = AddFDData(&pl, &fd)))
      {
	if(err != 100)
	  DoError(err, linenum);
	return 0;
      }
    }
    while(*(in.pos++))	/* jumps to first char of next line */
      ;
  }

  if(pl.First && !CTRL_C)
  {
    struct PragList *p = (struct PragList *) pl.First;
    if(!p->List.Next)
    {
      if(!to)
      {
	STRPTR text;
	ULONG i;

	if(ShortBaseName)
	{
	  text = ShortBaseName; i = strlen(text);
	}
	else
	{
	  text = p->Basename; i = strlen(text)-4;
	}

	to = DupString(text, i + 7);
	CopyMem("_lib.fd", to+i, 8);
      }
      if(!(out.file = Open(to, MODE_NEWFILE)))
        return 0;
      
      err = MakeFD(p);
      CloseDest(to);
      if(!err)
        return 0;
    }
    else
    {
      while(p)
      {
	ULONG i;
	i = strlen(p->Basename) - 4;
	to = DupString(p->Basename, i+7);
	CopyMem("_lib.fd", to+i, 8);
	if(!(out.file = Open(to, MODE_NEWFILE)))
	  return 0;
	i = MakeFD(p);
	CloseDest(to);
        if(!i)
          return 0;
	p = (struct PragList *) p->List.Next;
      }
    }
  }

  if(CTRL_C)
    DoError(ERR_USER_ABORT, 0);

  return 1;
}

STRPTR helptext =
"FDFILE:  the FD file which should be used\n"
"SPECIAL: 1 - Aztec compiler (xxx_lib.h,     MODE 2, AMICALL)\n"
"\t 2 - DICE compiler  (xxx_pragmas.h, MODE 3, LIBCALL)\n"
"\t 3 - SAS compiler   (xxx_pragmas.h, MODE 3, LIBCALL,LIBTAGS)\n"
"\t 4 - MAXON compiler (xxx_lib.h,     MODE 1, AMICALL)\n"
"\t 5 - STORM compiler (xxx_lib.h,     MODE 1, AMITAGS,AMICALL)\n"
"\t 6 - all compilers [default]\n"
"\t10 - stub-functions for C - C text\n"
"\t11 - stub-functions for C - assembler text\n"
"\t12 - stub-functions for C - link library\n"
"\t13 - defines and link library for local library base (register call)\n"
"\t14 - defines and link library for local library base (stack call)\n"
"\t15 - stub-functions for Pascal - assembler text\n"
"\t16 - stub-functions for Pascal - link library\n"
"\t20 - assembler lvo _lvo.i file\n"
"\t21 - assembler lvo _lib.i file\n"
"\t22 - assembler lvo _lvo.i file no XDEF\n"
"\t23 - assembler lvo _lib.i file no XDEF\n"
"\t30 - proto file with pragma/..._lib.h call\n"
"\t31 - proto file with pragma/..._pragmas.h call\n"
"\t32 - proto file with pragmas/..._lib.h call\n"
"\t33 - proto file with pragmas/..._pragmas.h call\n"
"\t34 - proto file with local/..._loc.h call\n"
"\t35 - proto file for all compilers\n"
"\t40 - GCC inline file (preprocessor based)\n"
"\t41 - GCC inline file (old type - inline based)\n"
"\t42 - GCC inline file (library stubs)\n"
"\t50 - FD file (source is a pragma file!)\n"
"MODE:\t SPECIAL 1-6,AMICALL,LIBCALL,AMITAGS,LIBTAGS:\n"
"\t 1 - _INCLUDE_PRAGMA_..._LIB_H definition method [default]\n"
"\t 2 - _PRAGMAS_..._LIB_H definition method\n"
"\t 3 - _PRAGMAS_..._PRAGMAS_H definition method\n"
"\t 4 - no definition\n"
"\t SPECIAL 11-14:\n"
"\t 1 - all functions, normal interface\n"
"\t 2 - only tag-functions, tagcall interface [default]\n"
"\t 3 - all functions, normal and tagcall interface\n"
"TO:\t the destination directory (self creation of filename) or\n"
"\t the destination file\n"
"CLIB:    name of the prototypes file in clib directory\n"
"HEADER:  inserts given file into header of created file (\"\" is scan)\n"
"The following four need a string as argument. This string is used to set\n"
"a #if<given string> before the set method.\n"
"AMICALL: creates amicall pragmas\n"
"LIBCALL: creates libcall pragmas\n"
"AMITAGS: creates tagcall pragmas (amicall like method (StormC++))\n"
"LIBTAGS: creates tagcall pragmas (libcall like method (SAS C))\n"
"Switches:\n"
"COMMENT:    copy comments found in FD file\n"
"EXTERNC:    add a #ifdef __cplusplus ... statement to pragma file\n"
"PRIVATE:    includes private declared functions\n"
"SMALLDATA:  generate small data link libraries or assembler text\n"
"SORTED:     sort generated files by name and not by bias value\n"
"STORMFD:    converts FD files of strange StormC++ format\n"
"USESYSCALL: uses syscall pragma instead of libcall SysBase\n";

void main(void)
{
  ULONG mode = 0, pragmode = PRAGMODE_PRAGLIB, callmode = TAGMODE_TAGS;
  ULONG spec = 0; /* for default setting I need a ULONG var to get a pointer */
  UBYTE filename[255];	/* needed for filename */
  struct Args args;

#ifdef __SASC	/* with __MAXON__ this is done automatic by my StartUp */
  TestOS;
#endif

  memset(&args, 0, sizeof(struct Args)); /* initialize */
  args.SPECIAL = &spec;

  if(!(rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
    End(RETURN_FAIL);
  rda->RDA_ExtHelp = helptext;
  if(!ReadArgs(PARAM, (LONG *) &args, rda))
    End(RETURN_FAIL);

  VPrintf("SourceFile: %s\n", &args.FDFILE);

  if(
  !(in.file = Open(args.FDFILE, MODE_OLDFILE)) ||
  !(fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)) ||
  !ExamineFH(in.file, fib) ||
  !(in.buf = in.pos = AllocListMem((in.size = fib->fib_Size)+1)) ||
  Read(in.file, in.buf, in.size) != in.size ||
  !(out.buf = out.pos = AllocListMem(out.size)))
    End(RETURN_FAIL);

  {
    STRPTR ptr = FilePart(args.FDFILE);
    LONG len = strlen(ptr)-7;
    if(len >= 0 && !stricmp(ptr+len, "_lib.fd"))
    {
      ShortBaseName = ptr;
      ptr[len] = '\0';
    }
  }

  MakeLines(in.pos, in.size, 0);

  if(args.CLIB)
  {
    Close(in.file);
    if(!(in.file = Open(args.CLIB, MODE_OLDFILE)) ||
    !ExamineFH(in.file, fib) ||
    !(clibbuf = AllocListMem((clibsize = fib->fib_Size)+1)) ||
    Read(in.file, clibbuf, clibsize) != clibsize)
      End(RETURN_FAIL);
    MakeLines(clibbuf, clibsize, 1);
  }
  Close(in.file); in.file = 0;

  if(args.TO)
  {
    if((lock = Lock(args.TO, SHARED_LOCK)) && Examine(lock, fib) &&
    fib->fib_DirEntryType > 0)
    {
      oldfh = CurrentDir(lock);
      args.TO = 0;
    }
    else if(lock)
    {
      UnLock(lock);
      lock = 0;
    }
  }

  if(*args.SPECIAL == 50)
  {
    STRPTR ptr = FilePart(args.FDFILE), ptr2;

    for(ptr2 = ptr; *ptr2 && *ptr2 != '_' && *ptr2 != '.'; ++ptr2)
      ;
    if(ptr2 != ptr)
    {
      ShortBaseName = ptr;
      *ptr2 = '\0';
    }
    if(!CreateFDFile(args.FDFILE, args.TO))
      End(RETURN_FAIL);
    End(RETURN_OK);
  }

  if(args.EXTERNC)	Flags ^= FLAG_EXTERNC;
  if(args.STORMFD)	Flags ^= FLAG_STORMFD;
  if(args.COMMENT)	Flags ^= FLAG_DOCOMMENT;
  if(args.PRIVATE)	Flags ^= FLAG_PRIVATE;
  if(args.SMALLDATA)	Flags ^= FLAG_SMALLDATA;
  if(args.USESYSCALL) 	Flags ^= FLAG_SYSCALL;

  if(!ScanFDFile())
    End(RETURN_FAIL);

  if(args.SORTED)
    SortFDList();

  if(!ShortBaseName)
  {
    DoError(ERR_MISSING_SHORTBASENAME, 0); End(RETURN_FAIL);
  }
  else if((ShortBaseNameUpper = DupString(ShortBaseName, strlen(ShortBaseName))))
  {
    STRPTR a = ShortBaseNameUpper;
    while((*a = toupper(*a)))	/* Convert to uppercase */
      a++;
  }
  else
    End(RETURN_FAIL);

  if(*args.SPECIAL < 10) /* the pragma area is up to 9 */
  {
    STRPTR amicall = 0, libcall = 0, amitags = 0, libtags = 0;

    mode = MODUS_PRAGMA;
    sprintf(filename, "%s_lib.h", ShortBaseName);

    if(!args.LIBTAGS && !args.AMITAGS && !args.LIBCALL && !args.AMICALL &&
    !*args.SPECIAL)
      *args.SPECIAL = 6; /* default mode */

    switch(*args.SPECIAL)
    {
      case 0: break;
      case 1: pragmode = PRAGMODE_PRAGSLIB; amicall = ""; break;
      case 2: sprintf(filename, "%s_pragmas.h", ShortBaseName);
	      pragmode = PRAGMODE_PRAGSPRAGS; libcall = ""; break;
      case 3: sprintf(filename, "%s_pragmas.h", ShortBaseName);
	      pragmode = PRAGMODE_PRAGSPRAGS; libcall = "";
	      libtags = "def " TEXT_SAS_60; break;
      case 4: amicall = ""; break;
      case 5: amicall = amitags = ""; break;
      case 6: amicall = " defined(" TEXT_AZTEC ") || defined("
	TEXT_MAXON ") || defined(" TEXT_STORM ")";
	libcall = " defined(" TEXT_DICE ") || defined(" TEXT_SAS ")";
	libtags = "def " TEXT_SAS_60; amitags ="def " TEXT_STORM; break;
      default: mode = MODUS_ERROR; break;
    }

    if(!args.AMICALL)	args.AMICALL = amicall;
    if(!args.LIBCALL)	args.LIBCALL = libcall;
    if(!args.AMITAGS)	args.AMITAGS = amitags;
    if(!args.LIBTAGS)	args.LIBTAGS = libtags;

    if(args.MODE && *args.MODE > 0 && *args.MODE < 5)
      pragmode = *args.MODE;
  }
  else if(*args.SPECIAL < 20) /* the misc area is up to 19 */
  {
    if(args.MODE && *args.MODE > 0 && *args.MODE < 4)
      callmode = *args.MODE - 1;
    switch(*args.SPECIAL)
    {
    case 10: mode = MODUS_CSTUB;
      sprintf(filename, "%s_cstub.h", ShortBaseName); break;
    case 11: mode = MODUS_STUBTEXT;
      sprintf(filename, "%s_stub.a", ShortBaseName); break;
    case 12: mode = MODUS_STUBCODE;
      sprintf(filename, "%s.lib", ShortBaseName); break;
    case 13: Flags |= FLAG_LOCALREG; /* no break ! */
    case 14: mode = MODUS_LOCALDATA;
      sprintf(filename, "%s_loc.h", ShortBaseName); args.TO = 0; break;
    case 15: mode = MODUS_STUBTEXT; callmode = TAGMODE_NORMAL;
      Flags ^= FLAG_PASCAL;
      sprintf(filename, "%s_stub.a", ShortBaseName); break;
    case 16: mode = MODUS_STUBCODE; callmode = TAGMODE_NORMAL;
      Flags ^= FLAG_PASCAL;
      sprintf(filename, "%s.lib", ShortBaseName); break;
    default: mode = MODUS_ERROR; break;
    }
  }
  else if(*args.SPECIAL < 30) /* the lvo area is up to 29 */
  {
    switch(*args.SPECIAL)
    {
    case 20: case 22: mode = MODUS_LVO+*args.SPECIAL-20;
      sprintf(filename, "%s_lvo.i", ShortBaseName); break;
    case 21: case 23: mode = MODUS_LVO+*args.SPECIAL-20;
      sprintf(filename, "%s_lib.i", ShortBaseName); break;
    default: mode = MODUS_ERROR; break;
    }
  }
  else if(*args.SPECIAL < 40) /* the proto area is up to 39 */
  {
    if(*args.SPECIAL < 36)
    {
      mode = MODUS_PROTO+*args.SPECIAL-30;
      sprintf(filename, "%s.h", ShortBaseName);
    }
    else
      mode = MODUS_ERROR;
  }
  else if(*args.SPECIAL < 50) /* the inline area is up to 49 */
  {
    switch(*args.SPECIAL)
    {
    case 40: case 41: case 42: mode = MODUS_INLINE+*args.SPECIAL-40;
      sprintf(filename, "%s.h", ShortBaseName); break;
    default: mode = MODUS_ERROR; break;
    }
  }

  if(!mode)
  {
    SetIoErr(ERROR_REQUIRED_ARG_MISSING);
    End(RETURN_FAIL);
  }
  else if(mode == MODUS_ERROR)
  {
    SetIoErr(ERROR_TOO_MANY_ARGS);
    End(RETURN_FAIL);
  }

  /* These modes need BaseName always. */
  if(!BaseName && (mode == MODUS_PRAGMA || mode == MODUS_STUBTEXT ||
  mode == MODUS_STUBCODE))
  {
    DoError(ERR_MISSING_BASENAME, 0); End(RETURN_FAIL);
  }

  if(!args.TO)
    args.TO = filename;

  if(args.HEADER)
  {
    if(!*args.HEADER)
      args.HEADER = args.TO;
    if(!(in.file = Open(args.HEADER, MODE_OLDFILE)) ||
    !ExamineFH(in.file, fib) ||
    !(HEADER = AllocListMem((headersize = fib->fib_Size)+1)) ||
    Read(in.file, HEADER, headersize) != headersize)
      End(RETURN_FAIL);
    if(args.HEADER == args.TO)
      FindHeader();
    Close(in.file);
    in.file = 0;
  }

  if(!(out.file = Open(args.TO, MODE_NEWFILE)))
    End(RETURN_FAIL);

  SetIoErr(0);

  /* from here mode is used as return result */
  if(mode == MODUS_PRAGMA)
    mode = CreatePragmaFile(args.AMICALL, args.LIBCALL, args.AMITAGS,
    args.LIBTAGS, pragmode);
  else if(mode == MODUS_CSTUB)
    mode = CreateCSTUBSFile();
  else if(mode == MODUS_LOCALDATA)
    mode = CreateLocalData(args.TO, callmode);
  else if(mode >= MODUS_INLINE)
    mode = CreateInline(mode-MODUS_INLINE);
  else if(mode >= MODUS_PROTO)
    mode = CreateProtoFile(mode-MODUS_PROTO+1);
  else if(mode >= MODUS_LVO)
    mode = CreateLVOFile(mode-MODUS_LVO+1);
  else if(mode) 			/* MODUS_STUBTEXT starts with 1 */
    mode = CreateAsmStubs(mode, callmode);

  CloseDest(args.TO);

  if(CTRL_C)
    DoError(ERR_USER_ABORT, 0);
  else if(!mode)
  {
    DoError(Output_Error ? ERR_UNKNOWN_ERROR : ERR_WRITING_FILE, 0);
    End(RETURN_FAIL);
  }

  End(RETURN_OK);
}

void end(void)
{
  if(fib)		FreeDosObject(DOS_FIB, fib);
  if(in.file)		Close(in.file);
  if(oldfh)		CurrentDir(oldfh);
  if(lock)		UnLock(lock);
  if(remember)		FreeListMem();
  if(rda)
  {
    FreeArgs(rda);
    FreeDosObject(DOS_RDARGS, rda);
  }
}
