1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-26 20:29:34 +00:00

Working on the condes feature

git-svn-id: svn://svn.cc65.org/cc65/trunk@451 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2000-11-20 15:22:57 +00:00
parent 9c35f5278a
commit b9970cb7da
35 changed files with 1029 additions and 388 deletions

View File

@ -286,6 +286,3 @@ void ObjExtract (const char* Name)

View File

@ -33,6 +33,8 @@
#include <string.h>
/* ca65 */ /* ca65 */
#include "error.h" #include "error.h"
#include "expr.h" #include "expr.h"

View File

@ -33,6 +33,8 @@
#include <string.h>
/* common */ /* common */
#include "check.h" #include "check.h"
#include "exprdefs.h" #include "exprdefs.h"

View File

@ -33,6 +33,8 @@
#include <string.h>
/* common */ /* common */
#include "check.h" #include "check.h"
#include "hashstr.h" #include "hashstr.h"

View File

@ -34,10 +34,11 @@
#include <stdio.h> #include <stdio.h>
#include <string.h>
/* common */ /* common */
#include "check.h" #include "check.h"
/* ca65 */ /* ca65 */
#include "error.h" #include "error.h"
#include "expr.h" #include "expr.h"

View File

@ -33,6 +33,8 @@
#include <string.h>
/* common */ /* common */
#include "optdefs.h" #include "optdefs.h"
#include "xmalloc.h" #include "xmalloc.h"

View File

@ -41,6 +41,7 @@
/* common */ /* common */
#include "bitops.h" #include "bitops.h"
#include "cddefs.h"
#include "check.h" #include "check.h"
#include "symdefs.h" #include "symdefs.h"
#include "tgttrans.h" #include "tgttrans.h"
@ -173,6 +174,32 @@ static long IntArg (long Min, long Max)
static void ConDes (const char* Name, unsigned Type)
/* Parse remaining line for constructor/destructor of the remaining type */
{
long Prio;
/* Optional constructor priority */
if (Tok == TOK_COMMA) {
/* Priority value follows */
NextTok ();
Prio = ConstExpression ();
if (Prio < CD_PRIO_MIN || Prio > CD_PRIO_MAX) {
/* Value out of range */
Error (ERR_RANGE);
return;
}
} else {
/* Use the default priority value */
Prio = CD_PRIO_DEF;
}
/* Define the symbol */
SymConDes (Name, Type, (unsigned) Prio);
}
/*****************************************************************************/ /*****************************************************************************/
/* Handler functions */ /* Handler functions */
/*****************************************************************************/ /*****************************************************************************/
@ -320,7 +347,7 @@ static void DoByte (void)
NextTok (); NextTok ();
/* Do smart handling of dangling comma */ /* Do smart handling of dangling comma */
if (Tok == TOK_SEP) { if (Tok == TOK_SEP) {
Error (ERR_UNEXPECTED_EOL); Error (ERR_UNEXPECTED_EOL);
break; break;
} }
} }
@ -346,6 +373,76 @@ static void DoCode (void)
static void DoConDes (void)
/* Export a symbol as constructor/destructor */
{
static const char* Keys[] = {
"CONSTRUCTOR",
"DESTRUCTOR",
};
char Name [sizeof (SVal)];
long Type;
/* Symbol name follows */
if (Tok != TOK_IDENT) {
ErrorSkip (ERR_IDENT_EXPECTED);
return;
}
strcpy (Name, SVal);
NextTok ();
/* Type follows. May be encoded as identifier or numerical */
ConsumeComma ();
if (Tok == TOK_IDENT) {
/* Map the following keyword to a number, then skip it */
Type = GetSubKey (Keys, sizeof (Keys) / sizeof (Keys [0]));
NextTok ();
/* Check if we got a valid keyword */
if (Type < 0) {
Error (ERR_SYNTAX);
SkipUntilSep ();
return;
}
} else {
/* Read the type as numerical value */
Type = ConstExpression ();
if (Type < CD_TYPE_MIN || Type > CD_TYPE_MAX) {
/* Value out of range */
Error (ERR_RANGE);
return;
}
}
/* Parse the remainder of the line and export the symbol */
ConDes (Name, (unsigned) Type);
}
static void DoConstructor (void)
/* Export a symbol as constructor */
{
char Name [sizeof (SVal)];
/* Symbol name follows */
if (Tok != TOK_IDENT) {
ErrorSkip (ERR_IDENT_EXPECTED);
return;
}
strcpy (Name, SVal);
NextTok ();
/* Parse the remainder of the line and export the symbol */
ConDes (Name, CD_TYPE_CON);
}
static void DoData (void) static void DoData (void)
/* Switch to the data segment */ /* Switch to the data segment */
{ {
@ -422,6 +519,25 @@ static void DoDefine (void)
static void DoDestructor (void)
/* Export a symbol as destructor */
{
char Name [sizeof (SVal)];
/* Symbol name follows */
if (Tok != TOK_IDENT) {
ErrorSkip (ERR_IDENT_EXPECTED);
return;
}
strcpy (Name, SVal);
NextTok ();
/* Parse the remainder of the line and export the symbol */
ConDes (Name, CD_TYPE_DES);
}
static void DoDWord (void) static void DoDWord (void)
/* Define dwords */ /* Define dwords */
{ {
@ -736,41 +852,6 @@ static void DoInclude (void)
static void DoInitializer (void)
/* Export a symbol as initializer */
{
char Name [sizeof (SVal)];
long Val;
/* Symbol name follows */
if (Tok != TOK_IDENT) {
ErrorSkip (ERR_IDENT_EXPECTED);
return;
}
strcpy (Name, SVal);
NextTok ();
/* Optional initializer value */
if (Tok == TOK_COMMA) {
/* Initializer value follows */
NextTok ();
Val = ConstExpression ();
if (Val < EXP_INIT_MIN || Val > EXP_INIT_MAX) {
/* Value out of range */
Error (ERR_RANGE);
return;
}
} else {
/* Use the default initializer value */
Val = EXP_INIT_DEF;
}
/* Define the symbol */
SymInitializer (Name, (unsigned) Val);
}
static void DoInvalid (void) static void DoInvalid (void)
/* Handle a token that is invalid here, since it should have been handled on /* Handle a token that is invalid here, since it should have been handled on
* a much lower level of the expression hierarchy. Getting this sort of token * a much lower level of the expression hierarchy. Getting this sort of token
@ -1171,7 +1252,9 @@ static CtrlDesc CtrlCmdTab [] = {
{ ccNone, DoCase }, { ccNone, DoCase },
{ ccNone, DoCode }, { ccNone, DoCode },
{ ccNone, DoUnexpected, }, /* .CONCAT */ { ccNone, DoUnexpected, }, /* .CONCAT */
{ ccNone, DoConDes },
{ ccNone, DoUnexpected }, /* .CONST */ { ccNone, DoUnexpected }, /* .CONST */
{ ccNone, DoConstructor },
{ ccNone, DoUnexpected }, /* .CPU */ { ccNone, DoUnexpected }, /* .CPU */
{ ccNone, DoData }, { ccNone, DoData },
{ ccNone, DoDbg, }, { ccNone, DoDbg, },
@ -1179,6 +1262,7 @@ static CtrlDesc CtrlCmdTab [] = {
{ ccNone, DoDebugInfo }, { ccNone, DoDebugInfo },
{ ccNone, DoDefine }, { ccNone, DoDefine },
{ ccNone, DoUnexpected }, /* .DEFINED */ { ccNone, DoUnexpected }, /* .DEFINED */
{ ccNone, DoDestructor },
{ ccNone, DoDWord }, { ccNone, DoDWord },
{ ccKeepToken, DoConditionals }, /* .ELSE */ { ccKeepToken, DoConditionals }, /* .ELSE */
{ ccKeepToken, DoConditionals }, /* .ELSEIF */ { ccKeepToken, DoConditionals }, /* .ELSEIF */
@ -1215,7 +1299,6 @@ static CtrlDesc CtrlCmdTab [] = {
{ ccNone, DoImportZP }, { ccNone, DoImportZP },
{ ccNone, DoIncBin }, { ccNone, DoIncBin },
{ ccNone, DoInclude }, { ccNone, DoInclude },
{ ccNone, DoInitializer },
{ ccNone, DoInvalid }, /* .LEFT */ { ccNone, DoInvalid }, /* .LEFT */
{ ccNone, DoLineCont }, { ccNone, DoLineCont },
{ ccNone, DoList }, { ccNone, DoList },

View File

@ -33,6 +33,8 @@
#include <string.h>
/* common */ /* common */
#include "xmalloc.h" #include "xmalloc.h"
@ -106,7 +108,7 @@ static void RepeatTokenCheck (TokList* L)
/* Called each time a token from a repeat token list is set. Is used to check /* Called each time a token from a repeat token list is set. Is used to check
* for and replace identifiers that are the repeat counter. * for and replace identifiers that are the repeat counter.
*/ */
{ {
if (Tok == TOK_IDENT && L->Data != 0 && strcmp (SVal, L->Data) == 0) { if (Tok == TOK_IDENT && L->Data != 0 && strcmp (SVal, L->Data) == 0) {
/* Must replace by the repeat counter */ /* Must replace by the repeat counter */
Tok = TOK_INTCON; Tok = TOK_INTCON;

View File

@ -133,7 +133,9 @@ struct DotKeyword {
{ "CASE", TOK_CASE }, { "CASE", TOK_CASE },
{ "CODE", TOK_CODE }, { "CODE", TOK_CODE },
{ "CONCAT", TOK_CONCAT }, { "CONCAT", TOK_CONCAT },
{ "CONDES", TOK_CONDES },
{ "CONST", TOK_CONST }, { "CONST", TOK_CONST },
{ "CONSTRUCTOR", TOK_CONSTRUCTOR },
{ "CPU", TOK_CPU }, { "CPU", TOK_CPU },
{ "DATA", TOK_DATA }, { "DATA", TOK_DATA },
{ "DBG", TOK_DBG }, { "DBG", TOK_DBG },
@ -142,6 +144,7 @@ struct DotKeyword {
{ "DEF", TOK_DEFINED }, { "DEF", TOK_DEFINED },
{ "DEFINE", TOK_DEFINE }, { "DEFINE", TOK_DEFINE },
{ "DEFINED", TOK_DEFINED }, { "DEFINED", TOK_DEFINED },
{ "DESTRUCTOR", TOK_DESTRUCTOR },
{ "DWORD", TOK_DWORD }, { "DWORD", TOK_DWORD },
{ "ELSE", TOK_ELSE }, { "ELSE", TOK_ELSE },
{ "ELSEIF", TOK_ELSEIF }, { "ELSEIF", TOK_ELSEIF },
@ -182,7 +185,6 @@ struct DotKeyword {
{ "IMPORTZP", TOK_IMPORTZP }, { "IMPORTZP", TOK_IMPORTZP },
{ "INCBIN", TOK_INCBIN }, { "INCBIN", TOK_INCBIN },
{ "INCLUDE", TOK_INCLUDE }, { "INCLUDE", TOK_INCLUDE },
{ "INITIALIZER", TOK_INITIALIZER },
{ "LEFT", TOK_LEFT }, { "LEFT", TOK_LEFT },
{ "LINECONT", TOK_LINECONT }, { "LINECONT", TOK_LINECONT },
{ "LIST", TOK_LIST }, { "LIST", TOK_LIST },

View File

@ -120,8 +120,10 @@ enum Token {
TOK_BYTE, TOK_BYTE,
TOK_CASE, TOK_CASE,
TOK_CODE, TOK_CODE,
TOK_CONCAT, TOK_CONCAT,
TOK_CONDES,
TOK_CONST, TOK_CONST,
TOK_CONSTRUCTOR,
TOK_CPU, TOK_CPU,
TOK_DATA, TOK_DATA,
TOK_DBG, TOK_DBG,
@ -129,6 +131,7 @@ enum Token {
TOK_DEBUGINFO, TOK_DEBUGINFO,
TOK_DEFINE, TOK_DEFINE,
TOK_DEFINED, TOK_DEFINED,
TOK_DESTRUCTOR,
TOK_DWORD, TOK_DWORD,
TOK_ELSE, TOK_ELSE,
TOK_ELSEIF, TOK_ELSEIF,
@ -165,7 +168,6 @@ enum Token {
TOK_IMPORTZP, TOK_IMPORTZP,
TOK_INCBIN, TOK_INCBIN,
TOK_INCLUDE, TOK_INCLUDE,
TOK_INITIALIZER,
TOK_LEFT, TOK_LEFT,
TOK_LINECONT, TOK_LINECONT,
TOK_LIST, TOK_LIST,

View File

@ -36,6 +36,7 @@
#include <string.h> #include <string.h>
/* common */ /* common */
#include "cddefs.h"
#include "check.h" #include "check.h"
#include "hashstr.h" #include "hashstr.h"
#include "symdefs.h" #include "symdefs.h"
@ -63,9 +64,8 @@
#define SF_EXPORT 0x0004 /* Export this symbol */ #define SF_EXPORT 0x0004 /* Export this symbol */
#define SF_IMPORT 0x0008 /* Import this symbol */ #define SF_IMPORT 0x0008 /* Import this symbol */
#define SF_GLOBAL 0x0010 /* Global symbol */ #define SF_GLOBAL 0x0010 /* Global symbol */
#define SF_INITIALIZER 0x0020 /* Exported initializer */ #define SF_ZP 0x0020 /* Declared as zeropage symbol */
#define SF_ZP 0x0040 /* Declared as zeropage symbol */ #define SF_ABS 0x0040 /* Declared as absolute symbol */
#define SF_ABS 0x0080 /* Declared as absolute symbol */
#define SF_INDEXED 0x0800 /* Index is valid */ #define SF_INDEXED 0x0800 /* Index is valid */
#define SF_CONST 0x1000 /* The symbol has a constant value */ #define SF_CONST 0x1000 /* The symbol has a constant value */
#define SF_MULTDEF 0x2000 /* Multiply defined symbol */ #define SF_MULTDEF 0x2000 /* Multiply defined symbol */
@ -97,15 +97,16 @@ struct SymEntry {
long Val; /* Value (if CONST set) */ long Val; /* Value (if CONST set) */
SymEntry* Sym; /* Symbol (if trampoline entry) */ SymEntry* Sym; /* Symbol (if trampoline entry) */
} V; } V;
unsigned char InitVal; /* Initializer value */ unsigned char ConDesPrio[CD_TYPE_COUNT]; /* ConDes priorities... */
/* ...actually value+1 (used as flag) */
char Name [1]; /* Dynamic allocation */ char Name [1]; /* Dynamic allocation */
}; };
/* Definitions for the hash table */ /* Definitions for the hash table */
#define MAIN_HASHTAB_SIZE 213 #define MAIN_HASHTAB_SIZE 213
#define SUB_HASHTAB_SIZE 53 #define SUB_HASHTAB_SIZE 53
typedef struct SymTable SymTable; typedef struct SymTable SymTable;
struct SymTable { struct SymTable {
unsigned TableSlots; /* Number of hash table slots */ unsigned TableSlots; /* Number of hash table slots */
@ -140,7 +141,7 @@ static unsigned ExportCount = 0;/* Counter for export symbols */
static int IsLocal (const char* Name) static int IsLocal (const char* Name)
/* Return true if Name is the name of a local symbol */ /* Return true if Name is the name of a local symbol */
{ {
return (*Name == LocalStart); return (*Name == LocalStart);
} }
@ -166,7 +167,7 @@ static SymEntry* NewSymEntry (const char* Name)
S->Pos = CurPos; S->Pos = CurPos;
S->Flags = 0; S->Flags = 0;
S->V.Expr = 0; S->V.Expr = 0;
S->InitVal = 0; memset (S->ConDesPrio, 0, sizeof (S->ConDesPrio));
memcpy (S->Name, Name, Len+1); memcpy (S->Name, Name, Len+1);
/* Insert it into the list of all entries */ /* Insert it into the list of all entries */
@ -579,15 +580,16 @@ void SymGlobal (const char* Name, int ZP)
void SymInitializer (const char* Name, unsigned InitVal) void SymConDes (const char* Name, unsigned Type, unsigned Prio)
/* Mark the given symbol as an initializer. This will also mark the symbol as /* Mark the given symbol as a module constructor/destructor. This will also
* an export. Initializers may never be zero page symbols. * mark the symbol as an export. Initializers may never be zero page symbols.
*/ */
{ {
SymEntry* S; SymEntry* S;
/* Check the InitVal parameter */ /* Check the parameters */
CHECK (InitVal >= EXP_INIT_MIN && InitVal <= EXP_INIT_MAX); CHECK (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
CHECK (Prio >= CD_PRIO_MIN && Prio <= CD_PRIO_MAX);
/* Don't accept local symbols */ /* Don't accept local symbols */
if (IsLocal (Name)) { if (IsLocal (Name)) {
@ -613,18 +615,18 @@ void SymInitializer (const char* Name, unsigned InitVal)
Error (ERR_SYM_REDECL_MISMATCH); Error (ERR_SYM_REDECL_MISMATCH);
} }
/* If the symbol was already declared as an initializer, check if the new /* If the symbol was already declared as a condes, check if the new
* initializer value is the same as the old one. * priority value is the same as the old one.
*/ */
if (S->Flags & SF_INITIALIZER) { if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
if (S->InitVal != InitVal) { if (S->ConDesPrio[Type] != Prio) {
Error (ERR_SYM_REDECL_MISMATCH); Error (ERR_SYM_REDECL_MISMATCH);
} }
} }
S->InitVal = InitVal; S->ConDesPrio[Type] = Prio;
/* Set the symbol data */ /* Set the symbol data */
S->Flags |= SF_EXPORT | SF_INITIALIZER | SF_REFERENCED; S->Flags |= SF_EXPORT | SF_REFERENCED;
} }
@ -1064,6 +1066,7 @@ void WriteExports (void)
/* Write the exports list to the object file */ /* Write the exports list to the object file */
{ {
SymEntry* S; SymEntry* S;
unsigned Type;
/* Tell the object file module that we're about to start the exports */ /* Tell the object file module that we're about to start the exports */
ObjStartExports (); ObjStartExports ();
@ -1086,14 +1089,26 @@ void WriteExports (void)
/* Add zeropage/abs bits */ /* Add zeropage/abs bits */
ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS; ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS;
/* Add the initializer bits */ /* Count the number of ConDes types */
if (S->Flags & SF_INITIALIZER) { for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
ExprMask |= S->InitVal; if (S->ConDesPrio[Type] != CD_PRIO_NONE) {
INC_EXP_CONDES_COUNT (ExprMask);
}
} }
/* Write the type */ /* Write the type */
ObjWrite8 (ExprMask); ObjWrite8 (ExprMask);
/* Write any ConDes declarations */
if (GET_EXP_CONDES_COUNT (ExprMask) > 0) {
for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
unsigned char Prio = S->ConDesPrio[Type];
if (Prio != CD_PRIO_NONE) {
ObjWrite8 (CD_BUILD (Type, Prio));
}
}
}
/* Write the name */ /* Write the name */
ObjWriteStr (S->Name); ObjWriteStr (S->Name);
@ -1158,11 +1173,6 @@ void WriteDbgSyms (void)
/* Add zeropage/abs bits */ /* Add zeropage/abs bits */
ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS; ExprMask |= (S->Flags & SF_ZP)? EXP_ZP : EXP_ABS;
/* Add the initializer bits */
if (S->Flags & SF_INITIALIZER) {
ExprMask |= S->InitVal;
}
/* Write the type */ /* Write the type */
ObjWrite8 (ExprMask); ObjWrite8 (ExprMask);

View File

@ -86,9 +86,9 @@ void SymGlobal (const char* Name, int ZP);
* either imported or exported. * either imported or exported.
*/ */
void SymInitializer (const char* Name, unsigned InitVal); void SymConDes (const char* Name, unsigned Type, unsigned Prio);
/* Mark the given symbol as an initializer. This will also mark the symbol as /* Mark the given symbol as a module constructor/destructor. This will also
* an export. Initializers may never be zero page symbols. * mark the symbol as an export. Initializers may never be zero page symbols.
*/ */
int SymIsConst (SymEntry* Sym); int SymIsConst (SymEntry* Sym);

View File

@ -34,10 +34,13 @@
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include "../common/xmalloc.h"
#include "../common/xsprintf.h" /* common */
#include "xmalloc.h"
#include "xsprintf.h"
/* cc65 */
#include "error.h" #include "error.h"
#include "asmline.h" #include "asmline.h"

View File

@ -33,6 +33,8 @@
#include <string.h>
/* cc65 */ /* cc65 */
#include "error.h" #include "error.h"
#include "scanner.h" #include "scanner.h"
@ -125,7 +127,7 @@ void ParseAttribute (const Declaration* D, DeclAttr* A)
/* Parse an additional __attribute__ modifier */ /* Parse an additional __attribute__ modifier */
{ {
ident AttrName; ident AttrName;
attrib_t AttrType; attrib_t AttrType;
/* Initialize the attribute description with "no attribute" */ /* Initialize the attribute description with "no attribute" */
A->AttrType = atNone; A->AttrType = atNone;

View File

@ -34,8 +34,10 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <ctype.h> #include <ctype.h>
/* cc65 */
#include "codegen.h" #include "codegen.h"
#include "error.h" #include "error.h"
#include "expr.h" #include "expr.h"

View File

@ -33,8 +33,12 @@
#include "../common/xmalloc.h" #include <string.h>
/* common */
#include "xmalloc.h"
/* cc65 */
#include "symentry.h" #include "symentry.h"
@ -43,7 +47,7 @@
/* Code */ /* Code */
/*****************************************************************************/ /*****************************************************************************/
SymEntry* NewSymEntry (const char* Name, unsigned Flags) SymEntry* NewSymEntry (const char* Name, unsigned Flags)
/* Create a new symbol table with the given name */ /* Create a new symbol table with the given name */

View File

@ -1,15 +1,15 @@
/*****************************************************************************/ /*****************************************************************************/
/* */ /* */
/* initfunc.c */ /* cddefs.h */
/* */ /* */
/* Init/cleanup function handling */ /* Definitions for module constructor/destructors */
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 2000 Ullrich von Bassewitz */ /* (C) 2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Wacholderweg 14 */
/* D-70597 Stuttgart */ /* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */ /* EMail: uz@musoftware.de */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* This software is provided 'as-is', without any expressed or implied */
@ -33,47 +33,48 @@
/* common */ #ifndef CDDEFS_H
#include "coll.h" #define CDDEFS_H
/* ld65 */
#include "exports.h"
#include "segments.h"
#include "initfunc.h"
/*****************************************************************************/ /*****************************************************************************/
/* Data */ /* Data */
/*****************************************************************************/ /*****************************************************************************/
/* List of all exports that are also initializers/cleanup functions */ /* ConDes types. Count is only 7 because we want to encode 0..count in 3 bits */
static Collection InitFunctions = STATIC_COLLECTION_INITIALIZER; #define CD_TYPE_COUNT 7 /* Number of table types */
static Collection CleanupFunctions = STATIC_COLLECTION_INITIALIZER; #define CD_TYPE_MIN 0 /* Minimum numeric type value */
#define CD_TYPE_MAX 6 /* Maximum numeric type value */
/* ConDes priorities, zero is no valid priority and used to mark an empty
* (missing) decl for this type throughout the code.
*/
#define CD_PRIO_NONE 0 /* No priority (no decl) */
#define CD_PRIO_MIN 1 /* Lowest priority */
#define CD_PRIO_DEF 7 /* Default priority */
#define CD_PRIO_MAX 32 /* Highest priority */
/* Predefined types */
#define CD_TYPE_CON 0 /* Constructor */
#define CD_TYPE_DES 1 /* Destructor */
/* When part of an export in an object file, type and priority are encoded in
* one byte. In this case, the following macros access the fields:
*/
#define CD_GET_TYPE(v) (((v) >> 5) & 0x07)
#define CD_GET_PRIO(v) (((v) & 0x1F) + 1)
/* Macro to build the byte value: */
#define CD_BUILD(type,prio) ((((type) & 0x07) << 5) | (((prio) - 1) & 0x1F))
/*****************************************************************************/ /* End of cddefs.h */
/* Code */
/*****************************************************************************/ #endif
void AddInitFunc (Export* E)
/* Add the given export to the list of initializers */
{
CollAppend (&InitFunctions, E);
}
void AddCleanupFunc (Export* E)
/* Add the given export to the list of cleanup functions */
{
CollAppend (&CleanupFunctions, E);
}

View File

@ -225,14 +225,64 @@ void CollReplace (Collection* C, void* Item, unsigned Index)
void CollSort (Collection* C, int (*Compare) (const void*, const void*)) static void QuickSort (Collection* C, int Lo, int Hi,
/* Sort the collection using the given compare function. int (*Compare) (void*, const void*, const void*),
* BEWARE: The function uses qsort internally, so the Compare function does void* Data)
* actually get pointers to the object pointers, not just object pointers! /* Internal recursive sort function. */
*/
{ {
/* Use qsort */ /* Get a pointer to the items */
qsort (C->Items, C->Count, sizeof (void*), Compare); void** Items = C->Items;
/* Quicksort */
while (Hi > Lo) {
int I = Lo + 1;
int J = Hi;
while (I <= J) {
while (I <= J && Compare (Data, Items[Lo], Items[I]) >= 0) {
++I;
}
while (I <= J && Compare (Data, Items[Lo], Items[J]) < 0) {
--J;
}
if (I <= J) {
/* Swap I and J */
void* Tmp = Items[I];
Items[I] = Items[J];
Items[J] = Tmp;
++I;
--J;
}
}
if (J != Lo) {
/* Swap J and Lo */
void* Tmp = Items[J];
Items[J] = Items[Lo];
Items[Lo] = Tmp;
}
if (J > (Hi + Lo) / 2) {
QuickSort (C, J + 1, Hi, Compare, Data);
Hi = J - 1;
} else {
QuickSort (C, Lo, J - 1, Compare, Data);
Lo = J + 1;
}
}
}
void CollSort (Collection* C,
int (*Compare) (void*, const void*, const void*),
void* Data)
/* Sort the collection using the given compare function. The data pointer is
* passed as *first* element to the compare function, it's not used by the
* sort function itself. The other two pointer passed to the Compare function
* are pointers to objects.
*/
{
if (C->Count > 1) {
QuickSort (C, 0, C->Count-1, Compare, Data);
}
} }

View File

@ -113,10 +113,13 @@ void CollReplace (Collection* C, void* Item, unsigned Index);
* just the pointer will et replaced. * just the pointer will et replaced.
*/ */
void CollSort (Collection* C, int (*Compare) (const void*, const void*)); void CollSort (Collection* C,
/* Sort the collection using the given compare function. int (*Compare) (void*, const void*, const void*),
* BEWARE: The function uses qsort internally, so the Compare function does void* Data);
* actually get pointers to the object pointers, not just object pointers! /* Sort the collection using the given compare function. The data pointer is
* passed as *first* element to the compare function, it's not used by the
* sort function itself. The other two pointer passed to the Compare function
* are pointers to objects.
*/ */

View File

@ -46,7 +46,7 @@
/* Defines for magic and version */ /* Defines for magic and version */
#define OBJ_MAGIC 0x616E7A55 #define OBJ_MAGIC 0x616E7A55
#define OBJ_VERSION 0x0007 #define OBJ_VERSION 0x0008
/* Size of an object file header */ /* Size of an object file header */
#define OBJ_HDR_SIZE 56 #define OBJ_HDR_SIZE 56

View File

@ -58,28 +58,26 @@
/* Export size */ /* Export size */
#define EXP_ABS 0x00 /* Export as normal value */ #define EXP_ABS 0x00 /* Export as normal value */
#define EXP_ZP 0x20 /* Export as zero page value */ #define EXP_ZP 0x08 /* Export as zero page value */
#define EXP_MASK_SIZE 0x20 /* Size mask */ #define EXP_MASK_SIZE 0x08 /* Size mask */
#define IS_EXP_ABS(x) (((x) & EXP_MASK_SIZE) == EXP_ABS) #define IS_EXP_ABS(x) (((x) & EXP_MASK_SIZE) == EXP_ABS)
#define IS_EXP_ZP(x) (((x) & EXP_MASK_SIZE) == EXP_ZP) #define IS_EXP_ZP(x) (((x) & EXP_MASK_SIZE) == EXP_ZP)
/* Export value type */ /* Export value type */
#define EXP_CONST 0x00 /* Mask bit for const values */ #define EXP_CONST 0x00 /* Mask bit for const values */
#define EXP_EXPR 0x40 /* Mask bit for expr values */ #define EXP_EXPR 0x10 /* Mask bit for expr values */
#define EXP_MASK_VAL 0x40 /* Value mask */ #define EXP_MASK_VAL 0x10 /* Value mask */
#define IS_EXP_CONST(x) (((x) & EXP_MASK_VAL) == EXP_CONST) #define IS_EXP_CONST(x) (((x) & EXP_MASK_VAL) == EXP_CONST)
#define IS_EXP_EXPR(x) (((x) & EXP_MASK_VAL) == EXP_EXPR) #define IS_EXP_EXPR(x) (((x) & EXP_MASK_VAL) == EXP_EXPR)
/* Export initializer flag */ /* Number of module constructor/destructor declarations for an export */
#define EXP_INIT_MIN 0x01 /* Minimum value */ #define EXP_CONDES_MASK 0x07
#define EXP_INIT_MAX 0x1F /* Maximum value */
#define EXP_INIT_DEF 0x18 /* Default value */
#define EXP_MASK_INIT 0x1F /* Initializer value mask */
#define IS_EXP_INIT(x) (((x) & EXP_MASK_INIT) != 0) #define IS_EXP_CONDES(x) (((x) & EXP_CONDES_MASK) != 0)
#define GET_EXP_INIT_VAL(x) ((x) & EXP_MASK_INIT) #define GET_EXP_CONDES_COUNT(x) ((x) & EXP_CONDES_MASK)
#define INC_EXP_CONDES_COUNT(x) ((x)++)

View File

@ -34,6 +34,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <ctype.h> #include <ctype.h>
#include "target.h" #include "target.h"

View File

@ -34,6 +34,7 @@
#include <stdio.h> #include <stdio.h>
#include <string.h>
#if defined(_MSC_VER) #if defined(_MSC_VER)
/* Microsoft compiler */ /* Microsoft compiler */
# include <io.h> # include <io.h>

188
src/ld65/condes.c Normal file
View File

@ -0,0 +1,188 @@
/*****************************************************************************/
/* */
/* condes.h */
/* */
/* Module constructor/destructor support */
/* */
/* */
/* */
/* (C) 2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
/* common */
#include "check.h"
#include "coll.h"
#include "xmalloc.h"
/* ld65 */
#include "exports.h"
#include "segments.h"
#include "condes.h"
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Struct describing one condes type */
typedef struct ConDesDesc ConDesDesc;
struct ConDesDesc {
Collection ExpList; /* List of exported symbols */
char* Label; /* Name of table label */
char* SegName; /* Name of segment the table is in */
unsigned char Enable; /* Table enabled */
};
/* Array for all types */
static ConDesDesc ConDes[CD_TYPE_COUNT] = {
{ STATIC_COLLECTION_INITIALIZER, 0, 0, 0 },
{ STATIC_COLLECTION_INITIALIZER, 0, 0, 0 },
{ STATIC_COLLECTION_INITIALIZER, 0, 0, 0 },
{ STATIC_COLLECTION_INITIALIZER, 0, 0, 0 },
{ STATIC_COLLECTION_INITIALIZER, 0, 0, 0 },
{ STATIC_COLLECTION_INITIALIZER, 0, 0, 0 },
{ STATIC_COLLECTION_INITIALIZER, 0, 0, 0 },
};
/*****************************************************************************/
/* Code */
/*****************************************************************************/
void ConDesAddExport (struct Export* E)
/* Add the given export to the list of constructors/destructor */
{
unsigned Type;
/* Insert the export into all tables for which declarations exist */
for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
unsigned Prio = E->ConDes[Type];
if (Prio != CD_PRIO_NONE) {
CollAppend (&ConDes[Type].ExpList, E);
}
}
}
void ConDesSetSegName (unsigned Type, const char* SegName)
/* Set the segment name where the table should go */
{
/* Check the parameters */
PRECONDITION (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX && SegName != 0);
/* Setting the segment name twice is bad */
CHECK (ConDes[Type].SegName == 0);
/* Set the name */
ConDes[Type].SegName = xstrdup (SegName);
}
void ConDesSetLabel (unsigned Type, const char* Name)
/* Set the label for the given ConDes type */
{
/* Check the parameters */
PRECONDITION (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX && Name != 0);
/* Setting the label twice is bad */
CHECK (ConDes[Type].Label == 0);
/* Set the name */
ConDes[Type].Label = xstrdup (Name);
}
const char* ConDesGetSegName (unsigned Type)
/* Return the segment name for the given ConDes type */
{
/* Check the parameters */
PRECONDITION (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
/* Return the name */
return ConDes[Type].SegName;
}
const char* ConDesGetLabel (unsigned Type)
/* Return the label for the given ConDes type */
{
/* Check the parameters */
PRECONDITION (Type >= CD_TYPE_MIN && Type <= CD_TYPE_MAX);
/* Return the name */
return ConDes[Type].Label;
}
int ConDesHasSegName (unsigned Type)
/* Return true if a segment name is already defined for this ConDes type */
{
return (ConDesGetSegName(Type) != 0);
}
int ConDesHasLabel (unsigned Type)
/* Return true if a label is already defined for this ConDes type */
{
return (ConDesGetLabel(Type) != 0);
}
void ConDesCreate (void)
/* Create the condes tables if requested */
{
}
void ConDesDump (void)
/* Dump ConDes data to stdout for debugging */
{
unsigned Type;
for (Type = 0; Type < CD_TYPE_COUNT; ++Type) {
Collection* ExpList = &ConDes[Type].ExpList;
printf ("CONDES(%u): %u symbols\n", Type, CollCount (ExpList));
}
}

View File

@ -1,8 +1,8 @@
/*****************************************************************************/ /*****************************************************************************/
/* */ /* */
/* initfunc.h */ /* condes.h */
/* */ /* */
/* Init/cleanup function handling */ /* Module constructor/destructor support */
/* */ /* */
/* */ /* */
/* */ /* */
@ -33,13 +33,13 @@
#ifndef INITFUNC_H #ifndef CONDES_H
#define INITFUNC_H #define CONDES_H
/*****************************************************************************/ /*****************************************************************************/
/* Forwards */ /* Forwards */
/*****************************************************************************/ /*****************************************************************************/
@ -54,15 +54,36 @@ struct Export;
void AddInitFunc (struct Export* E); void ConDesAddExport (struct Export* E);
/* Add the given export to the list of initializers */ /* Add the given export to the list of constructors/destructor */
void AddCleanupFunc (struct Export* E); void ConDesSetSegName (unsigned Type, const char* SegName);
/* Add the given export to the list of cleanup functions */ /* Set the segment name where the table should go */
void ConDesSetLabel (unsigned Type, const char* Name);
/* Set the label for the given ConDes type */
const char* ConDesGetSegName (unsigned Type);
/* Return the segment name for the given ConDes type */
const char* ConDesGetLabel (unsigned Type);
/* Return the label for the given ConDes type */
int ConDesHasSegName (unsigned Type);
/* Return true if a segment name is already defined for this ConDes type */
int ConDesHasLabel (unsigned Type);
/* Return true if a label is already defined for this ConDes type */
void ConDesCreate (void);
/* Create the condes tables if requested */
void ConDesDump (void);
/* Dump ConDes data to stdout for debugging */
/* End of initfunc.h */ /* End of condes.h */
#endif #endif

View File

@ -42,14 +42,15 @@
#include "check.h" #include "check.h"
#include "bitops.h" #include "bitops.h"
#include "xmalloc.h" #include "xmalloc.h"
/* ld65 */ /* ld65 */
#include "error.h"
#include "global.h"
#include "bin.h" #include "bin.h"
#include "o65.h"
#include "binfmt.h" #include "binfmt.h"
#include "condes.h"
#include "error.h"
#include "exports.h" #include "exports.h"
#include "global.h"
#include "o65.h"
#include "scanner.h" #include "scanner.h"
#include "config.h" #include "config.h"
@ -115,6 +116,141 @@ static unsigned O65Attr = 0;
/*****************************************************************************/
/* Forwards */
/*****************************************************************************/
static File* NewFile (const char* Name);
/* Create a new file descriptor and insert it into the list */
/*****************************************************************************/
/* List management */
/*****************************************************************************/
static File* FindFile (const char* Name)
/* Find a file with a given name. */
{
File* F = FileList;
while (F) {
if (strcmp (F->Name, Name) == 0) {
return F;
}
F = F->Next;
}
return 0;
}
static File* GetFile (const char* Name)
/* Get a file entry with the given name. Create a new one if needed. */
{
File* F = FindFile (Name);
if (F == 0) {
/* Create a new one */
F = NewFile (Name);
}
return F;
}
static void FileInsert (File* F, Memory* M)
/* Insert the memory area into the files list */
{
M->F = F;
if (F->MemList == 0) {
/* First entry */
F->MemList = M;
} else {
F->MemLast->FNext = M;
}
F->MemLast = M;
}
static Memory* CfgFindMemory (const char* Name)
/* Find the memory are with the given name. Return NULL if not found */
{
Memory* M = MemoryList;
while (M) {
if (strcmp (M->Name, Name) == 0) {
return M;
}
M = M->Next;
}
return 0;
}
static Memory* CfgGetMemory (const char* Name)
/* Find the memory are with the given name. Print an error on an invalid name */
{
Memory* M = CfgFindMemory (Name);
if (M == 0) {
CfgError ("Invalid memory area `%s'", Name);
}
return M;
}
static SegDesc* CfgFindSegDesc (const char* Name)
/* Find the segment descriptor with the given name, return NULL if not found. */
{
SegDesc* S = SegDescList;
while (S) {
if (strcmp (S->Name, Name) == 0) {
/* Found */
return S;
}
S = S->Next;
}
/* Not found */
return 0;
}
static void SegDescInsert (SegDesc* S)
/* Insert a segment descriptor into the list of segment descriptors */
{
/* Insert the struct into the list */
S->Next = SegDescList;
SegDescList = S;
++SegDescCount;
}
static void MemoryInsert (Memory* M, SegDesc* S)
/* Insert the segment descriptor into the memory area list */
{
/* Create a new node for the entry */
MemListNode* N = xmalloc (sizeof (MemListNode));
N->Seg = S;
N->Next = 0;
if (M->SegLast == 0) {
/* First entry */
M->SegList = N;
} else {
M->SegLast->Next = N;
}
M->SegLast = N;
}
/*****************************************************************************/ /*****************************************************************************/
/* Constructors/Destructors */ /* Constructors/Destructors */
/*****************************************************************************/ /*****************************************************************************/
@ -156,13 +292,9 @@ static Memory* NewMemory (const char* Name)
unsigned Len = strlen (Name); unsigned Len = strlen (Name);
/* Check for duplicate names */ /* Check for duplicate names */
Memory* M = MemoryList; Memory* M = CfgFindMemory (Name);
while (M) { if (M) {
if (strcmp (M->Name, Name) == 0) { CfgError ("Memory area `%s' defined twice", Name);
CfgError ("Memory area `%s' defined twice", Name);
break;
}
M = M->Next;
} }
/* Allocate memory */ /* Allocate memory */
@ -208,13 +340,9 @@ static SegDesc* NewSegDesc (const char* Name)
unsigned Len = strlen (Name); unsigned Len = strlen (Name);
/* Check for duplicate names */ /* Check for duplicate names */
SegDesc* S = SegDescList; SegDesc* S = CfgFindSegDesc (Name);
while (S) { if (S) {
if (strcmp (S->Name, Name) == 0) { CfgError ("Segment `%s' defined twice", Name);
CfgError ("Segment `%s' defined twice", Name);
break;
}
S = S->Next;
} }
/* Verify that the given segment does really exist */ /* Verify that the given segment does really exist */
@ -278,49 +406,6 @@ static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
static File* FindFile (const char* Name)
/* Find a file with a given name. */
{
File* F = FileList;
while (F) {
if (strcmp (F->Name, Name) == 0) {
return F;
}
F = F->Next;
}
return 0;
}
static File* GetFile (const char* Name)
/* Get a file entry with the given name. Create a new one if needed. */
{
File* F = FindFile (Name);
if (F == 0) {
/* Create a new one */
F = NewFile (Name);
}
return F;
}
static void FileInsert (File* F, Memory* M)
/* Insert the memory area into the files list */
{
M->F = F;
if (F->MemList == 0) {
/* First entry */
F->MemList = M;
} else {
F->MemLast->FNext = M;
}
F->MemLast = M;
}
static void ParseMemory (void) static void ParseMemory (void)
/* Parse a MEMORY section */ /* Parse a MEMORY section */
{ {
@ -351,7 +436,7 @@ static void ParseMemory (void)
while (CfgTok == CFGTOK_IDENT) { while (CfgTok == CFGTOK_IDENT) {
/* Map the identifier to a token */ /* Map the identifier to a token */
unsigned AttrTok; cfgtok_t AttrTok;
CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
AttrTok = CfgTok; AttrTok = CfgTok;
@ -477,7 +562,7 @@ static void ParseFiles (void)
while (CfgTok == CFGTOK_IDENT) { while (CfgTok == CFGTOK_IDENT) {
/* Map the identifier to a token */ /* Map the identifier to a token */
unsigned AttrTok; cfgtok_t AttrTok;
CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
AttrTok = CfgTok; AttrTok = CfgTok;
@ -528,63 +613,6 @@ static void ParseFiles (void)
static Memory* CfgFindMemory (const char* Name)
/* Find the memory are with the given name. Return NULL if not found */
{
Memory* M = MemoryList;
while (M) {
if (strcmp (M->Name, Name) == 0) {
return M;
}
M = M->Next;
}
return 0;
}
static Memory* CfgGetMemory (const char* Name)
/* Find the memory are with the given name. Print an error on an invalid name */
{
Memory* M = CfgFindMemory (Name);
if (M == 0) {
CfgError ("Invalid memory area `%s'", Name);
}
return M;
}
static void SegDescInsert (SegDesc* S)
/* Insert a segment descriptor into the list of segment descriptors */
{
/* Insert the struct into the list */
S->Next = SegDescList;
SegDescList = S;
++SegDescCount;
}
static void MemoryInsert (Memory* M, SegDesc* S)
/* Insert the segment descriptor into the memory area list */
{
/* Create a new node for the entry */
MemListNode* N = xmalloc (sizeof (MemListNode));
N->Seg = S;
N->Next = 0;
if (M->SegLast == 0) {
/* First entry */
M->SegList = N;
} else {
M->SegLast->Next = N;
}
M->SegLast = N;
}
static void ParseSegments (void) static void ParseSegments (void)
/* Parse a SEGMENTS section */ /* Parse a SEGMENTS section */
{ {
@ -623,7 +651,7 @@ static void ParseSegments (void)
while (CfgTok == CFGTOK_IDENT) { while (CfgTok == CFGTOK_IDENT) {
/* Map the identifier to a token */ /* Map the identifier to a token */
unsigned AttrTok; cfgtok_t AttrTok;
CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
AttrTok = CfgTok; AttrTok = CfgTok;
@ -649,9 +677,11 @@ static void ParseSegments (void)
CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type"); CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
switch (CfgTok) { switch (CfgTok) {
case CFGTOK_RO: S->Flags |= SF_RO; break; case CFGTOK_RO: S->Flags |= SF_RO; break;
case CFGTOK_RW: /* Default */ break;
case CFGTOK_BSS: S->Flags |= SF_BSS; break; case CFGTOK_BSS: S->Flags |= SF_BSS; break;
case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break; case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT); break; case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT); break;
default: Internal ("Unexpected token: %d", CfgTok);
} }
break; break;
@ -788,7 +818,7 @@ static void ParseO65 (void)
while (CfgTok == CFGTOK_IDENT) { while (CfgTok == CFGTOK_IDENT) {
/* Map the identifier to a token */ /* Map the identifier to a token */
unsigned AttrTok; cfgtok_t AttrTok;
CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute"); CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
AttrTok = CfgTok; AttrTok = CfgTok;
@ -843,7 +873,7 @@ static void ParseO65 (void)
break; break;
default: default:
Error ("Unexpected type token"); CfgError ("Unexpected type token");
} }
break; break;
@ -863,7 +893,7 @@ static void ParseO65 (void)
break; break;
default: default:
Error ("Unexpected OS token"); CfgError ("Unexpected OS token");
} }
break; break;
@ -892,7 +922,7 @@ static void ParseFormats (void)
while (CfgTok == CFGTOK_IDENT) { while (CfgTok == CFGTOK_IDENT) {
/* Map the identifier to a token */ /* Map the identifier to a token */
unsigned FormatTok; cfgtok_t FormatTok;
CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format"); CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
FormatTok = CfgTok; FormatTok = CfgTok;
@ -922,16 +952,165 @@ static void ParseFormats (void)
static void ParseConDes (void)
/* Parse the CONDES feature */
{
static const IdentTok Attributes [] = {
{ "SEGMENT", CFGTOK_SEGMENT },
{ "LABEL", CFGTOK_LABEL },
{ "TYPE", CFGTOK_TYPE },
};
static const IdentTok Types [] = {
{ "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
{ "DESTRUCTOR", CFGTOK_DESTRUCTOR },
};
/* Attribute values. */
char SegName[sizeof (CfgSVal)];
char Label[sizeof (CfgSVal)];
int Type = -1; /* Initialize to avoid gcc warnings */
/* Bitmask to remember the attributes we got already */
enum {
atNone = 0x0000,
atSegName = 0x0001,
atLabel = 0x0002,
atType = 0x0004
};
unsigned AttrFlags = atNone;
/* Parse the attributes */
while (1) {
/* Map the identifier to a token */
cfgtok_t AttrTok;
CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
AttrTok = CfgTok;
/* An optional assignment follows */
CfgNextTok ();
CfgOptionalAssign ();
/* Check which attribute was given */
switch (AttrTok) {
case CFGTOK_SEGMENT:
/* Don't allow this twice */
FlagAttr (&AttrFlags, atSegName, "SEGMENT");
/* We expect an identifier */
CfgAssureIdent ();
/* Remember the value for later */
strcpy (SegName, CfgSVal);
break;
case CFGTOK_LABEL:
/* Don't allow this twice */
FlagAttr (&AttrFlags, atLabel, "LABEL");
/* We expect an identifier */
CfgAssureIdent ();
/* Remember the value for later */
strcpy (Label, CfgSVal);
break;
case CFGTOK_TYPE:
/* Don't allow this twice */
FlagAttr (&AttrFlags, atType, "TYPE");
/* The type may be given as id or numerical */
if (CfgTok == CFGTOK_INTCON) {
CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
Type = (int) CfgIVal;
} else {
CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
switch (CfgTok) {
case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
default: FAIL ("Unexpected type token");
}
}
break;
default:
FAIL ("Unexpected attribute token");
}
/* Skip the attribute value */
CfgNextTok ();
/* Semicolon ends the ConDes decl, otherwise accept an optional comma */
if (CfgTok == CFGTOK_SEMI) {
break;
} else if (CfgTok == CFGTOK_COMMA) {
CfgNextTok ();
}
}
/* Check if we have all mandatory attributes */
AttrCheck (AttrFlags, atSegName, "SEGMENT");
AttrCheck (AttrFlags, atLabel, "LABEL");
AttrCheck (AttrFlags, atType, "TYPE");
/* Check if the condes has already attributes defined */
if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
CfgError ("CONDES attributes for type %d are already defined", Type);
}
/* Define the attributes */
ConDesSetSegName (Type, SegName);
ConDesSetLabel (Type, Label);
}
static void ParseFeatures (void)
/* Parse a features section */
{
static const IdentTok Features [] = {
{ "CONDES", CFGTOK_CONDES },
};
while (CfgTok == CFGTOK_IDENT) {
/* Map the identifier to a token */
cfgtok_t FeatureTok;
CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
FeatureTok = CfgTok;
/* Skip the name and the following colon */
CfgNextTok ();
CfgConsumeColon ();
/* Parse the format options */
switch (FeatureTok) {
case CFGTOK_CONDES:
ParseConDes ();
break;
default:
Error ("Unexpected feature token");
}
/* Skip the semicolon */
CfgConsumeSemi ();
}
}
static void ParseConfig (void) static void ParseConfig (void)
/* Parse the config file */ /* Parse the config file */
{ {
static const IdentTok BlockNames [] = { static const IdentTok BlockNames [] = {
{ "MEMORY", CFGTOK_MEMORY }, { "MEMORY", CFGTOK_MEMORY },
{ "FILES", CFGTOK_FILES }, { "FILES", CFGTOK_FILES },
{ "SEGMENTS", CFGTOK_SEGMENTS }, { "SEGMENTS", CFGTOK_SEGMENTS },
{ "FORMATS", CFGTOK_FORMATS }, { "FORMATS", CFGTOK_FORMATS },
{ "FEATURES", CFGTOK_FEATURES },
}; };
unsigned BlockTok; cfgtok_t BlockTok;
do { do {
@ -947,23 +1126,27 @@ static void ParseConfig (void)
switch (BlockTok) { switch (BlockTok) {
case CFGTOK_MEMORY: case CFGTOK_MEMORY:
ParseMemory (); ParseMemory ();
break; break;
case CFGTOK_FILES: case CFGTOK_FILES:
ParseFiles (); ParseFiles ();
break; break;
case CFGTOK_SEGMENTS: case CFGTOK_SEGMENTS:
ParseSegments (); ParseSegments ();
break; break;
case CFGTOK_FORMATS: case CFGTOK_FORMATS:
ParseFormats (); ParseFormats ();
break;
case CFGTOK_FEATURES:
ParseFeatures ();
break; break;
default: default:
FAIL ("Unexpected block token"); FAIL ("Unexpected block token");
} }

View File

@ -45,10 +45,10 @@
#include "xmalloc.h" #include "xmalloc.h"
/* ld65 */ /* ld65 */
#include "global.h" #include "condes.h"
#include "error.h" #include "error.h"
#include "fileio.h" #include "fileio.h"
#include "initfunc.h" #include "global.h"
#include "objdata.h" #include "objdata.h"
#include "expr.h" #include "expr.h"
#include "exports.h" #include "exports.h"
@ -202,17 +202,18 @@ static Export* NewExport (unsigned char Type, const char* Name, ObjData* Obj)
/* Initialize the fields */ /* Initialize the fields */
E->Next = 0; E->Next = 0;
E->Flags = 0; E->Flags = 0;
E->Obj = Obj; E->Obj = Obj;
E->ImpCount = 0; E->ImpCount = 0;
E->ImpList = 0; E->ImpList = 0;
E->Expr = 0; E->Expr = 0;
E->Type = Type; E->Type = Type;
memset (E->ConDes, 0, sizeof (E->ConDes));
if (Name) { if (Name) {
E->Name = xstrdup (Name); E->Name = xstrdup (Name);
} else { } else {
/* Name will get added later */ /* Name will get added later */
E->Name = 0; E->Name = 0;
} }
/* Return the new entry */ /* Return the new entry */
@ -229,9 +230,9 @@ void InsertExport (Export* E)
Import* Imp; Import* Imp;
unsigned HashVal; unsigned HashVal;
/* If this is an initializer, insert it into the initializer list */ /* Insert the export into any condes tables if needed */
if (IS_EXP_INIT (E->Type)) { if (IS_EXP_CONDES (E->Type)) {
AddInitFunc (E); ConDesAddExport (E);
} }
/* Create a hash value for the given name */ /* Create a hash value for the given name */
@ -272,7 +273,7 @@ void InsertExport (Export* E)
} }
} else { } else {
/* Duplicate entry, ignore it */ /* Duplicate entry, ignore it */
Warning ("Duplicate external identifier: `%s'", L->Name); Warning ("Duplicate external identifier: `%s'", L->Name);
} }
return; return;
} }
@ -293,6 +294,7 @@ Export* ReadExport (FILE* F, ObjData* O)
/* Read an export from a file */ /* Read an export from a file */
{ {
unsigned char Type; unsigned char Type;
unsigned ConDesCount;
Export* E; Export* E;
/* Read the type */ /* Read the type */
@ -301,6 +303,29 @@ Export* ReadExport (FILE* F, ObjData* O)
/* Create a new export without a name */ /* Create a new export without a name */
E = NewExport (Type, 0, O); E = NewExport (Type, 0, O);
/* Read the constructor/destructor decls if we have any */
ConDesCount = GET_EXP_CONDES_COUNT (Type);
if (ConDesCount > 0) {
unsigned char ConDes[CD_TYPE_COUNT];
unsigned I;
/* Read the data into temp storage */
ReadData (F, ConDes, ConDesCount);
/* Re-order the data. In the file, each decl is encoded into a byte
* which contains the type and the priority. In memory, we will use
* an array of types which contain the priority. This array was
* cleared by the constructor (NewExport), so we must only set the
* fields that contain values.
*/
for (I = 0; I < ConDesCount; ++I) {
unsigned ConDesType = CD_GET_TYPE (ConDes[I]);
unsigned ConDesPrio = CD_GET_PRIO (ConDes[I]);
E->ConDes[ConDesType] = ConDesPrio;
}
}
/* Read the name */ /* Read the name */
E->Name = ReadStr (F); E->Name = ReadStr (F);
@ -562,7 +587,7 @@ void PrintExportMap (FILE* F)
GetExportVal (E), GetExportVal (E),
E->ImpCount? 'R' : ' ', E->ImpCount? 'R' : ' ',
IS_EXP_ZP (E->Type)? 'Z' : ' ', IS_EXP_ZP (E->Type)? 'Z' : ' ',
IS_EXP_INIT (E->Type)? 'I' : ' '); IS_EXP_CONDES (E->Type)? 'I' : ' ');
if (++Count == 2) { if (++Count == 2) {
Count = 0; Count = 0;
fprintf (F, "\n"); fprintf (F, "\n");

View File

@ -41,6 +41,7 @@
#include <stdio.h> #include <stdio.h>
/* common */ /* common */
#include "cddefs.h"
#include "exprdefs.h" #include "exprdefs.h"
#include "filepos.h" #include "filepos.h"
@ -81,7 +82,8 @@ struct Export {
Import* ImpList; /* List of imports for this symbol */ Import* ImpList; /* List of imports for this symbol */
FilePos Pos; /* File position of definition */ FilePos Pos; /* File position of definition */
ExprNode* Expr; /* Expression (0 if not def'd) */ ExprNode* Expr; /* Expression (0 if not def'd) */
unsigned char Type; /* Type of export */ unsigned char Type; /* Type of export */
unsigned char ConDes[CD_TYPE_COUNT]; /* Constructor/destructor decls */
char* Name; /* Name - dynamically allocated */ char* Name; /* Name - dynamically allocated */
}; };
@ -157,7 +159,7 @@ void CircularRefError (const Export* E);
/* Print an error about a circular reference using to define the given export */ /* Print an error about a circular reference using to define the given export */
/* End of exports.h */ /* End of exports.h */
#endif #endif

View File

@ -284,9 +284,12 @@ FilePos* ReadFilePos (FILE* F, FilePos* Pos)
void* ReadData (FILE* F, void* Data, unsigned Size) void* ReadData (FILE* F, void* Data, unsigned Size)
/* Read data from the file */ /* Read data from the file */
{ {
if (fread (Data, 1, Size, F) != Size) { /* Explicitly allow reading zero bytes */
Error ("Read error (file corrupt?)"); if (Size > 0) {
if (fread (Data, 1, Size, F) != Size) {
Error ("Read error (file corrupt?)");
}
} }
return Data; return Data;
} }

View File

@ -48,6 +48,7 @@
/* ld65 */ /* ld65 */
#include "binfmt.h" #include "binfmt.h"
#include "condes.h"
#include "config.h" #include "config.h"
#include "error.h" #include "error.h"
#include "exports.h" #include "exports.h"
@ -404,6 +405,9 @@ int main (int argc, char* argv [])
/* Read the config file */ /* Read the config file */
CfgRead (); CfgRead ();
/* Create the condes tables if requested */
ConDesCreate ();
/* Assign start addresses for the segments, define linker symbols */ /* Assign start addresses for the segments, define linker symbols */
CfgAssignSegments (); CfgAssignSegments ();
@ -424,6 +428,7 @@ int main (int argc, char* argv [])
/* Dump the data for debugging */ /* Dump the data for debugging */
if (Verbose > 1) { if (Verbose > 1) {
SegDump (); SegDump ();
ConDesDump ();
} }
/* Return an apropriate exit code */ /* Return an apropriate exit code */

View File

@ -19,6 +19,7 @@ CVT=cfg/cvt-cfg.pl
OBJS = bin.o \ OBJS = bin.o \
binfmt.o \ binfmt.o \
condes.o \
config.o \ config.o \
dbgsyms.o \ dbgsyms.o \
error.o \ error.o \
@ -28,7 +29,6 @@ OBJS = bin.o \
fileio.o \ fileio.o \
fragment.o \ fragment.o \
global.o \ global.o \
initfunc.o \
library.o \ library.o \
main.o \ main.o \
mapfile.o \ mapfile.o \

View File

@ -56,7 +56,7 @@
/* Current token and attributes */ /* Current token and attributes */
unsigned CfgTok; cfgtok_t CfgTok;
char CfgSVal [CFG_MAX_IDENT_LEN+1]; char CfgSVal [CFG_MAX_IDENT_LEN+1];
unsigned long CfgIVal; unsigned long CfgIVal;
@ -322,7 +322,7 @@ Again:
void CfgConsume (unsigned T, const char* Msg) void CfgConsume (cfgtok_t T, const char* Msg)
/* Skip a token, print an error message if not found */ /* Skip a token, print an error message if not found */
{ {
if (CfgTok != T) { if (CfgTok != T) {
@ -535,3 +535,4 @@ void CfgCloseInput (void)

View File

@ -6,10 +6,10 @@
/* */ /* */
/* */ /* */
/* */ /* */
/* (C) 1998 Ullrich von Bassewitz */ /* (C) 1998-2000 Ullrich von Bassewitz */
/* Wacholderweg 14 */ /* Wacholderweg 14 */
/* D-70597 Stuttgart */ /* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */ /* EMail: uz@musoftware.de */
/* */ /* */
/* */ /* */
/* This software is provided 'as-is', without any expressed or implied */ /* This software is provided 'as-is', without any expressed or implied */
@ -45,67 +45,77 @@
/* Config file tokens */ /* Config file tokens */
#define CFGTOK_NONE 0 typedef enum {
#define CFGTOK_INTCON 1 CFGTOK_NONE,
#define CFGTOK_STRCON 2 CFGTOK_INTCON,
#define CFGTOK_IDENT 3 CFGTOK_STRCON,
#define CFGTOK_LCURLY 4 CFGTOK_IDENT,
#define CFGTOK_RCURLY 5 CFGTOK_LCURLY,
#define CFGTOK_SEMI 6 CFGTOK_RCURLY,
#define CFGTOK_COMMA 7 CFGTOK_SEMI,
#define CFGTOK_EQ 8 CFGTOK_COMMA,
#define CFGTOK_COLON 9 CFGTOK_EQ,
#define CFGTOK_DOT 10 CFGTOK_COLON,
#define CFGTOK_EOF 11 CFGTOK_DOT,
CFGTOK_EOF,
/* Special identifiers */ /* Special identifiers */
#define CFGTOK_MEMORY 20 CFGTOK_MEMORY,
#define CFGTOK_FILES 21 CFGTOK_FILES,
#define CFGTOK_SEGMENTS 22 CFGTOK_SEGMENTS,
#define CFGTOK_FORMATS 23 CFGTOK_FORMATS,
CFGTOK_FEATURES,
#define CFGTOK_START 30 CFGTOK_START,
#define CFGTOK_SIZE 31 CFGTOK_SIZE,
#define CFGTOK_TYPE 32 CFGTOK_TYPE,
#define CFGTOK_FILE 33 CFGTOK_FILE,
#define CFGTOK_DEFINE 34 CFGTOK_DEFINE,
#define CFGTOK_FILL 35 CFGTOK_FILL,
#define CFGTOK_FILLVAL 36 CFGTOK_FILLVAL,
#define CFGTOK_EXPORT 37 CFGTOK_EXPORT,
#define CFGTOK_IMPORT 38 CFGTOK_IMPORT,
#define CFGTOK_OS 39 CFGTOK_OS,
#define CFGTOK_FORMAT 40 CFGTOK_FORMAT,
#define CFGTOK_LOAD 50 CFGTOK_LOAD,
#define CFGTOK_RUN 51 CFGTOK_RUN,
#define CFGTOK_ALIGN 52 CFGTOK_ALIGN,
#define CFGTOK_OFFSET 53 CFGTOK_OFFSET,
#define CFGTOK_RO 60 CFGTOK_RO,
#define CFGTOK_RW 61 CFGTOK_RW,
#define CFGTOK_BSS 62 CFGTOK_BSS,
#define CFGTOK_ZP 63 CFGTOK_ZP,
#define CFGTOK_WPROT 64 CFGTOK_WPROT,
#define CFGTOK_O65 70 CFGTOK_O65,
#define CFGTOK_BIN 71 CFGTOK_BIN,
#define CFGTOK_SMALL 80 CFGTOK_SMALL,
#define CFGTOK_LARGE 81 CFGTOK_LARGE,
#define CFGTOK_TRUE 90 CFGTOK_TRUE,
#define CFGTOK_FALSE 91 CFGTOK_FALSE,
#define CFGTOK_LUNIX 100 CFGTOK_LUNIX,
#define CFGTOK_OSA65 101 CFGTOK_OSA65,
CFGTOK_CONDES,
CFGTOK_SEGMENT,
CFGTOK_LABEL,
CFGTOK_CONSTRUCTOR,
CFGTOK_DESTRUCTOR
} cfgtok_t;
/* Mapping table entry, special identifier --> token */ /* Mapping table entry, special identifier --> token */
typedef struct IdentTok_ IdentTok; typedef struct IdentTok_ IdentTok;
struct IdentTok_ { struct IdentTok_ {
const char* Ident; /* Identifier */ const char* Ident; /* Identifier */
unsigned Tok; /* Token for identifier */ cfgtok_t Tok; /* Token for identifier */
}; };
#define ENTRY_COUNT(s) (sizeof (s) / sizeof (s [0])) #define ENTRY_COUNT(s) (sizeof (s) / sizeof (s [0]))
@ -113,7 +123,7 @@ struct IdentTok_ {
/* Current token and attributes */ /* Current token and attributes */
#define CFG_MAX_IDENT_LEN 255 #define CFG_MAX_IDENT_LEN 255
extern unsigned CfgTok; extern cfgtok_t CfgTok;
extern char CfgSVal [CFG_MAX_IDENT_LEN+1]; extern char CfgSVal [CFG_MAX_IDENT_LEN+1];
extern unsigned long CfgIVal; extern unsigned long CfgIVal;
@ -138,7 +148,7 @@ void CfgError (const char* Format, ...) attribute((format(printf,1,2)));
void CfgNextTok (void); void CfgNextTok (void);
/* Read the next token from the input stream */ /* Read the next token from the input stream */
void CfgConsume (unsigned T, const char* Msg); void CfgConsume (cfgtok_t T, const char* Msg);
/* Skip a token, print an error message if not found */ /* Skip a token, print an error message if not found */
void CfgConsumeSemi (void); void CfgConsumeSemi (void);
@ -196,4 +206,4 @@ void CfgCloseInput (void);

View File

@ -37,6 +37,7 @@
#include <time.h> #include <time.h>
/* common */ /* common */
#include "cddefs.h"
#include "exprdefs.h" #include "exprdefs.h"
#include "filepos.h" #include "filepos.h"
#include "objdefs.h" #include "objdefs.h"
@ -196,24 +197,42 @@ static unsigned SkipFragment (FILE* F)
static const char* GetExportFlags (unsigned Flags) static const char* GetExportFlags (unsigned Flags, const unsigned char* ConDes)
/* Get the export flags as a (static) string */ /* Get the export flags as a (static) string */
{ {
/* Static buffer */ /* Static buffer */
static char TypeDesc[128]; static char TypeDesc[256];
static char* T;
/* Get the flags */ unsigned Count;
unsigned I;
/* Adressing mode */
TypeDesc[0] = '\0'; TypeDesc[0] = '\0';
switch (Flags & EXP_MASK_SIZE) { switch (Flags & EXP_MASK_SIZE) {
case EXP_ABS: strcat (TypeDesc, "EXP_ABS"); break; case EXP_ABS: strcat (TypeDesc, "EXP_ABS"); break;
case EXP_ZP: strcat (TypeDesc, "EXP_ZP"); break; case EXP_ZP: strcat (TypeDesc, "EXP_ZP"); break;
} }
/* Type of expression */
switch (Flags & EXP_MASK_VAL) { switch (Flags & EXP_MASK_VAL) {
case EXP_CONST: strcat (TypeDesc, ",EXP_CONST"); break; case EXP_CONST: strcat (TypeDesc, ",EXP_CONST"); break;
case EXP_EXPR: strcat (TypeDesc, ",EXP_EXPR"); break; case EXP_EXPR: strcat (TypeDesc, ",EXP_EXPR"); break;
} }
if (IS_EXP_INIT (Flags)) {
sprintf (TypeDesc+strlen(TypeDesc), ",EXP_INIT=%u", GET_EXP_INIT_VAL(Flags)); /* Constructor/destructor declarations */
T = TypeDesc + strlen (TypeDesc);
Count = GET_EXP_CONDES_COUNT (Flags);
if (Count > 0) {
T += sprintf (T, ",EXP_CONDES=");
for (I = 0; I < Count; ++I) {
unsigned Type = CD_GET_TYPE (ConDes[I]);
unsigned Prio = CD_GET_PRIO (ConDes[I]);
if (I > 0) {
*T++ = ',';
}
T += sprintf (T, "[%u,%u]", Type, Prio);
}
} }
/* Return the result */ /* Return the result */
@ -537,10 +556,10 @@ void DumpObjImports (FILE* F, unsigned long Offset)
void DumpObjExports (FILE* F, unsigned long Offset) void DumpObjExports (FILE* F, unsigned long Offset)
/* Dump the exports in the object file */ /* Dump the exports in the object file */
{ {
ObjHeader H; ObjHeader H;
unsigned Count; unsigned Count;
unsigned I; unsigned I;
FilePos Pos; FilePos Pos;
/* Seek to the header position */ /* Seek to the header position */
FileSeek (F, Offset); FileSeek (F, Offset);
@ -563,12 +582,18 @@ void DumpObjExports (FILE* F, unsigned long Offset)
unsigned long Value = 0; unsigned long Value = 0;
int HaveValue; int HaveValue;
unsigned char Type;
unsigned char ConDes [CD_TYPE_COUNT];
char* Name;
unsigned Len;
/* Read the data for one export */ /* Read the data for one export */
unsigned char Type = Read8 (F); Type = Read8 (F);
char* Name = ReadStr (F); ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
unsigned Len = strlen (Name); Name = ReadStr (F);
if (Type & EXP_EXPR) { Len = strlen (Name);
if (IS_EXP_EXPR (Type)) {
SkipExpr (F); SkipExpr (F);
HaveValue = 0; HaveValue = 0;
} else { } else {
@ -581,7 +606,7 @@ void DumpObjExports (FILE* F, unsigned long Offset)
printf (" Index:%27u\n", I); printf (" Index:%27u\n", I);
/* Print the data */ /* Print the data */
printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type)); printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
printf (" Name:%*s\"%s\"\n", 24-Len, "", Name); printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
if (HaveValue) { if (HaveValue) {
printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value); printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);
@ -630,12 +655,17 @@ void DumpObjDbgSyms (FILE* F, unsigned long Offset)
unsigned long Value = 0; unsigned long Value = 0;
int HaveValue; int HaveValue;
unsigned char Type;
unsigned char ConDes [CD_TYPE_COUNT];
char* Name;
unsigned Len;
/* Read the data for one symbol */ /* Read the data for one symbol */
unsigned char Type = Read8 (F); Type = Read8 (F);
char* Name = ReadStr (F); ReadData (F, ConDes, GET_EXP_CONDES_COUNT (Type));
unsigned Len = strlen (Name); Name = ReadStr (F);
if (Type & EXP_EXPR) { Len = strlen (Name);
if (IS_EXP_EXPR (Type)) {
SkipExpr (F); SkipExpr (F);
HaveValue = 0; HaveValue = 0;
} else { } else {
@ -648,7 +678,7 @@ void DumpObjDbgSyms (FILE* F, unsigned long Offset)
printf (" Index:%27u\n", I); printf (" Index:%27u\n", I);
/* Print the data */ /* Print the data */
printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type)); printf (" Type:%22s0x%02X (%s)\n", "", Type, GetExportFlags (Type, ConDes));
printf (" Name:%*s\"%s\"\n", 24-Len, "", Name); printf (" Name:%*s\"%s\"\n", 24-Len, "", Name);
if (HaveValue) { if (HaveValue) {
printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value); printf (" Value:%15s0x%08lX (%lu)\n", "", Value, Value);

View File

@ -179,8 +179,11 @@ FilePos* ReadFilePos (FILE* F, FilePos* Pos)
void* ReadData (FILE* F, void* Data, unsigned Size) void* ReadData (FILE* F, void* Data, unsigned Size)
/* Read data from the file */ /* Read data from the file */
{ {
if (fread (Data, 1, Size, F) != Size) { /* Accept zero sized reads */
Error ("Read error (file corrupt?)"); if (Size > 0) {
if (fread (Data, 1, Size, F) != Size) {
Error ("Read error (file corrupt?)");
}
} }
return Data; return Data;
} }