X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Finput.c;h=6db7df5f8e508b5661c5838f86797edd13d2f94f;hb=916a0879d53d72b28638f4849b384e6567b6d807;hp=d6c553d655ee372759cc4a666e77e22e60022df4;hpb=04ee693c00802bb541934803ac947e316e33d166;p=cc65 diff --git a/src/cc65/input.c b/src/cc65/input.c index d6c553d65..6db7df5f8 100644 --- a/src/cc65/input.c +++ b/src/cc65/input.c @@ -36,14 +36,20 @@ #include #include #include +#include +#include -#include "../common/xmalloc.h" +/* common */ +#include "check.h" +#include "coll.h" +#include "xmalloc.h" +/* cc65 */ #include "asmcode.h" -#include "check.h" +#include "codegen.h" #include "error.h" -#include "global.h" #include "incpath.h" +#include "lineinfo.h" #include "input.h" @@ -66,56 +72,46 @@ char NextC = '\0'; /* Maximum count of nested includes */ #define MAX_INC_NESTING 16 -/* Struct that describes an input file */ -typedef struct IFile IFile; -struct IFile { - IFile* Next; /* Next file in single linked list */ - IFile* Active; /* Next file in list of active includes */ - unsigned Index; /* File index */ +/* Struct that describes an active input file */ +typedef struct AFile AFile; +struct AFile { unsigned Line; /* Line number for this file */ - FILE* F; /* Input file stream */ - char Name[1]; /* Name of file (dynamically allocated) */ + FILE* F; /* Input file stream */ + IFile* Input; /* Points to corresponding IFile */ }; -/* Main file input data */ -static const IFile* MainFile = 0; +/* List of all input files */ +static Collection IFiles = STATIC_COLLECTION_INITIALIZER; -/* List of input files */ -static unsigned IFileTotal = 0; /* Total number of files */ -static IFile* IFileList = 0; /* Single linked list of all files */ -static unsigned IFileCount = 0; /* Number of active input files */ -static IFile* Input = 0; /* Single linked list of active files */ +/* List of all active files */ +static Collection AFiles = STATIC_COLLECTION_INITIALIZER; /*****************************************************************************/ -/* struct IFile */ +/* struct IFile */ /*****************************************************************************/ -static IFile* NewIFile (const char* Name, FILE* F) +static IFile* NewIFile (const char* Name) /* Create and return a new IFile */ { /* Get the length of the name */ unsigned Len = strlen (Name); /* Allocate a IFile structure */ - IFile* IF = xmalloc (sizeof (IFile) + Len); + IFile* IF = (IFile*) xmalloc (sizeof (IFile) + Len); /* Initialize the fields */ - IF->Index = ++IFileTotal; - IF->Line = 0; - IF->F = F; + IF->Index = CollCount (&IFiles) + 1; + IF->Usage = 0; + IF->Size = 0; + IF->MTime = 0; memcpy (IF->Name, Name, Len+1); - /* Insert the structure into both lists */ - IF->Next = IFileList; - IFileList = IF; - IF->Active = Input; - Input = IF; - ++IFileCount; - ++IFileTotal; + /* Insert the new structure into the IFile collection */ + CollAppend (&IFiles, IF); /* Return the new struct */ return IF; @@ -123,24 +119,103 @@ static IFile* NewIFile (const char* Name, FILE* F) +/*****************************************************************************/ +/* struct AFile */ +/*****************************************************************************/ + + + +static AFile* NewAFile (IFile* IF, FILE* F) +/* Create and return a new AFile */ +{ + /* Allocate a AFile structure */ + AFile* AF = (AFile*) xmalloc (sizeof (AFile)); + + /* Initialize the fields */ + AF->Line = 0; + AF->F = F; + AF->Input = IF; + + /* Increment the usage counter of the corresponding IFile. If this + * is the first use, set the file data and output debug info if + * requested. + */ + if (IF->Usage++ == 0) { + + /* Get file size and modification time */ + struct stat Buf; + if (fstat (fileno (F), &Buf) != 0) { + /* Error */ + Fatal ("Cannot stat `%s': %s", IF->Name, strerror (errno)); + } + IF->Size = (unsigned long) Buf.st_size; + IF->MTime = (unsigned long) Buf.st_mtime; + + /* Set the debug data */ + g_fileinfo (IF->Name, IF->Size, IF->MTime); + } + + /* Insert the new structure into the AFile collection */ + CollAppend (&AFiles, AF); + + /* Return the new struct */ + return AF; +} + + + +static void FreeAFile (AFile* AF) +/* Free an AFile structure */ +{ + xfree (AF); +} + + + /*****************************************************************************/ /* Code */ /*****************************************************************************/ +static IFile* FindFile (const char* Name) +/* Find the file with the given name in the list of all files. Since the list + * is not large (usually less than 10), I don't care about using hashes or + * similar things and do a linear search. + */ +{ + unsigned I; + for (I = 0; I < CollCount (&IFiles); ++I) { + /* Get the file struct */ + IFile* IF = (IFile*) CollAt (&IFiles, I); + /* Check the name */ + if (strcmp (Name, IF->Name) == 0) { + /* Found, return the struct */ + return IF; + } + } + + /* Not found */ + return 0; +} + + + void OpenMainFile (const char* Name) /* Open the main file. Will call Fatal() in case of failures. */ { + /* Setup a new IFile structure for the main file */ + IFile* IF = NewIFile (Name); + /* Open the file for reading */ FILE* F = fopen (Name, "r"); if (F == 0) { - /* Cannot open */ - Fatal (FAT_CANNOT_OPEN_INPUT, strerror (errno)); + /* Cannot open */ + Fatal ("Cannot open input file `%s': %s", Name, strerror (errno)); } - /* Setup a new IFile structure */ - MainFile = NewIFile (Name, F); + /* Allocate a new AFile structure for the file */ + (void) NewAFile (IF, F); } @@ -148,36 +223,44 @@ void OpenMainFile (const char* Name) void OpenIncludeFile (const char* Name, unsigned DirSpec) /* Open an include file and insert it into the tables. */ { - char* N; - FILE* F; + char* N; + FILE* F; + IFile* IF; /* Check for the maximum include nesting */ - if (IFileCount > MAX_INC_NESTING) { - PPError (ERR_INCLUDE_NESTING); + if (CollCount (&AFiles) > MAX_INC_NESTING) { + PPError ("Include nesting too deep"); return; } /* Search for the file */ N = FindInclude (Name, DirSpec); if (N == 0) { - PPError (ERR_INCLUDE_NOT_FOUND, Name); + PPError ("Include file `%s' not found", Name); return; } + /* Search the list of all input files for this file. If we don't find + * it, create a new IFile object. + */ + IF = FindFile (N); + if (IF == 0) { + IF = NewIFile (N); + } + + /* We don't need N any longer, since we may now use IF->Name */ + xfree (N); + /* Open the file */ - F = fopen (N, "r"); + F = fopen (IF->Name, "r"); if (F == 0) { /* Error opening the file */ - PPError (ERR_INCLUDE_OPEN_FAILURE, N, strerror (errno)); - xfree (N); + PPError ("Cannot open include file `%s': %s", IF->Name, strerror (errno)); return; } - /* Allocate a new IFile structure */ - NewIFile (N, F); - - /* We don't need the full name any longer */ - xfree (N); + /* Allocate a new AFile structure */ + (void) NewAFile (IF, F); } @@ -187,17 +270,25 @@ static void CloseIncludeFile (void) * NULL if this was the main file. */ { + AFile* Input; + + /* Get the number of active input files */ + unsigned AFileCount = CollCount (&AFiles); + /* Must have an input file when called */ - PRECONDITION (Input != 0); + PRECONDITION (AFileCount > 0); + + /* Get the current active input file */ + Input = (AFile*) CollLast (&AFiles); /* Close the current input file (we're just reading so no error check) */ fclose (Input->F); - /* Make this file inactive and the last one active again */ - Input = Input->Active; + /* Delete the last active file from the active file collection */ + CollDelete (&AFiles, AFileCount-1); - /* Adjust the counter */ - --IFileCount; + /* Delete the active file structure */ + FreeAFile (Input); } @@ -251,6 +342,7 @@ void NextChar (void) int NextLine (void) /* Get a line from the current input. Returns 0 on end of file. */ { + AFile* Input; unsigned Len; unsigned Part; unsigned Start; @@ -259,10 +351,11 @@ int NextLine (void) /* Setup the line */ ClearLine (); - /* If there is no file open, bail out */ - if (Input == 0) { + /* If there is no file open, bail out, otherwise get the current input file */ + if (CollCount (&AFiles) == 0) { return 0; } + Input = (AFile*) CollLast (&AFiles); /* Read lines until we get one with real contents */ Len = 0; @@ -277,10 +370,14 @@ int NextLine (void) /* Leave the current file */ CloseIncludeFile (); - /* If this was the last file, bail out */ - if (Input == 0) { - return 0; + /* If there is no file open, bail out, otherwise get the + * current input file + */ + if (CollCount (&AFiles) == 0) { + return 0; } + Input = (AFile*) CollLast (&AFiles); + } /* We got a new line */ @@ -295,13 +392,6 @@ int NextLine (void) } line [Len] = '\0'; - /* Output the source line in the generated assembler file - * if requested. - */ - if (AddSource && line[Start] != '\0') { - AddCodeLine ("; %s", line+Start); - } - /* Check if we have a line continuation character at the end. If not, * we're done. */ @@ -315,6 +405,9 @@ int NextLine (void) /* Got a line. Initialize the current and next characters. */ InitLine (line); + /* Create line information for this line */ + UpdateLineInfo (Input->Input, Input->Line, line); + /* Done */ return 1; } @@ -324,14 +417,19 @@ int NextLine (void) const char* GetCurrentFile (void) /* Return the name of the current input file */ { - if (Input == 0) { - if (MainFile) { - return MainFile->Name; + unsigned AFileCount = CollCount (&AFiles); + if (AFileCount > 0) { + const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1); + return AF->Input->Name; + } else { + /* No open file. Use the main file if we have one. */ + unsigned IFileCount = CollCount (&IFiles); + if (IFileCount > 0) { + const IFile* IF = (const IFile*) CollAt (&IFiles, 0); + return IF->Name; } else { return "(outside file scope)"; } - } else { - return Input->Name; } } @@ -340,7 +438,41 @@ const char* GetCurrentFile (void) unsigned GetCurrentLine (void) /* Return the line number in the current input file */ { - return Input? Input->Line : 0; + unsigned AFileCount = CollCount (&AFiles); + if (AFileCount > 0) { + const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1); + return AF->Line; + } else { + /* No open file */ + return 0; + } +} + + + +void WriteDependencies (FILE* F, const char* OutputFile) +/* Write a makefile dependency list to the given file */ +{ + unsigned I; + + /* Get the number of input files */ + unsigned IFileCount = CollCount (&IFiles); + + /* Print the output file followed by a tab char */ + fprintf (F, "%s:\t", OutputFile); + + /* Loop over all files */ + for (I = 0; I < IFileCount; ++I) { + /* Get the next input file */ + const IFile* IF = (const IFile*) CollAt (&IFiles, I); + /* If this is not the first file, add a space */ + const char* Format = (I == 0)? "%s" : " %s"; + /* Print the dependency */ + fprintf (F, Format, IF->Name); + } + + /* End the line */ + fprintf (F, "\n\n"); }