]> git.sur5r.net Git - cc65/blobdiff - src/cc65/input.c
Fixed two compiler warnings.
[cc65] / src / cc65 / input.c
index 6a26869f2c2b0c305861f530e229a761e221d9fa..2a2b8d5b51e7d9aeca9324bf5c6552c0678fc9f1 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2000-2004 Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 2000-2010, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 /* common */
 #include "check.h"
 #include "coll.h"
+#include "fname.h"
 #include "print.h"
+#include "strbuf.h"
 #include "xmalloc.h"
 
 /* cc65 */
 #include "codegen.h"
 #include "error.h"
+#include "global.h"
 #include "incpath.h"
-#include "lineinfo.h"
 #include "input.h"
+#include "lineinfo.h"
+#include "output.h"
 
 
 
@@ -70,12 +74,24 @@ 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 {
+    unsigned       Index;      /* File index */
+    unsigned       Usage;      /* Usage counter */
+    unsigned long   Size;       /* File size */
+    unsigned long   MTime;      /* Time of last modification */
+    InputType       Type;       /* Type of input file */
+    char                   Name[1];    /* Name of file (dynamically allocated) */
+};
+
 /* 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                    */
-    IFile*      Input;          /* Points to corresponding IFile        */
+    unsigned   Line;           /* Line number for this file */
+    FILE*      F;              /* Input file stream */
+    IFile*      Input;          /* Points to corresponding IFile */
+    int         SearchPath;     /* True if we've added a path for this file */
 };
 
 /* List of all input files */
@@ -95,7 +111,7 @@ static Collection InputStack = STATIC_COLLECTION_INITIALIZER;
 
 
 
-static IFile* NewIFile (const char* Name)
+static IFile* NewIFile (const char* Name, InputType Type)
 /* Create and return a new IFile */
 {
     /* Get the length of the name */
@@ -109,6 +125,7 @@ static IFile* NewIFile (const char* Name)
     IF->Usage = 0;
     IF->Size  = 0;
     IF->MTime = 0;
+    IF->Type  = Type;
     memcpy (IF->Name, Name, Len+1);
 
     /* Insert the new structure into the IFile collection */
@@ -127,8 +144,12 @@ static IFile* NewIFile (const char* Name)
 
 
 static AFile* NewAFile (IFile* IF, FILE* F)
-/* Create and return a new AFile */
+/* Create a new AFile, push it onto the stack, add the path of the file to
+ * the path search list, and finally return a pointer to the new AFile struct.
+ */
 {
+    StrBuf Path = AUTO_STRBUF_INITIALIZER;
+
     /* Allocate a AFile structure */
     AFile* AF = (AFile*) xmalloc (sizeof (AFile));
 
@@ -143,22 +164,38 @@ static AFile* NewAFile (IFile* IF, FILE* F)
      */
     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));
-       }
+       /* Get file size and modification time. There a race condition here,
+         * since we cannot use fileno() (non standard identifier in standard
+         * header file), and therefore not fstat. When using stat with the
+         * file name, there's a risk that the file was deleted and recreated
+         * while it was open. Since mtime and size are only used to check
+         * if a file has changed in the debugger, we will ignore this problem
+         * here.
+         */
+       struct stat Buf;
+       if (stat (IF->Name, &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;
+       IF->MTime = (unsigned long) Buf.st_mtime;
 
-       /* Set the debug data */
-       g_fileinfo (IF->Name, IF->Size, IF->MTime);
+       /* Set the debug data */
+       g_fileinfo (IF->Name, IF->Size, IF->MTime);
     }
 
     /* Insert the new structure into the AFile collection */
     CollAppend (&AFiles, AF);
 
+    /* Get the path of this file and add it as an extra search path.
+     * To avoid file search overhead, we will add one path only once.
+     * This is checked by the PushSearchPath function.
+     */
+    SB_CopyBuf (&Path, IF->Name, FindName (IF->Name) - IF->Name);
+    SB_Terminate (&Path);
+    AF->SearchPath = PushSearchPath (UsrIncSearchPath, SB_GetConstBuf (&Path));
+    SB_Done (&Path);
+
     /* Return the new struct */
     return AF;
 }
@@ -193,7 +230,7 @@ static IFile* FindFile (const char* Name)
        if (strcmp (Name, IF->Name) == 0) {
            /* Found, return the struct */
            return IF;
-       }
+               }
     }
 
     /* Not found */
@@ -205,8 +242,11 @@ static IFile* FindFile (const char* Name)
 void OpenMainFile (const char* Name)
 /* Open the main file. Will call Fatal() in case of failures. */
 {
+    AFile* MainFile;
+
+
     /* Setup a new IFile structure for the main file */
-    IFile* IF = NewIFile (Name);
+    IFile* IF = NewIFile (Name, IT_MAIN);
 
     /* Open the file for reading */
     FILE* F = fopen (Name, "r");
@@ -216,15 +256,20 @@ void OpenMainFile (const char* Name)
     }
 
     /* Allocate a new AFile structure for the file */
-    (void) NewAFile (IF, F);
+    MainFile = NewAFile (IF, F);
 
     /* Allocate the input line buffer */
     Line = NewStrBuf ();
+
+    /* Update the line infos, so we have a valid line info even at start of
+     * the main file before the first line is read.
+     */
+    UpdateLineInfo (MainFile->Input, MainFile->Line, Line);
 }
 
 
 
-void OpenIncludeFile (const char* Name, unsigned DirSpec)
+void OpenIncludeFile (const char* Name, InputType IT)
 /* Open an include file and insert it into the tables. */
 {
     char*  N;
@@ -238,7 +283,7 @@ void OpenIncludeFile (const char* Name, unsigned DirSpec)
     }
 
     /* Search for the file */
-    N = FindInclude (Name, DirSpec);
+    N = SearchFile ((IT == IT_SYSINC)? SysIncSearchPath : UsrIncSearchPath, Name);
     if (N == 0) {
        PPError ("Include file `%s' not found", Name);
        return;
@@ -249,7 +294,7 @@ void OpenIncludeFile (const char* Name, unsigned DirSpec)
      */
     IF = FindFile (N);
     if (IF == 0) {
-       IF = NewIFile (N);
+       IF = NewIFile (N, IT);
     }
 
     /* We don't need N any longer, since we may now use IF->Name */
@@ -294,6 +339,11 @@ static void CloseIncludeFile (void)
     /* Delete the last active file from the active file collection */
     CollDelete (&AFiles, AFileCount-1);
 
+    /* If we had added an extra search path for this AFile, remove it */
+    if (Input->SearchPath) {
+        PopSearchPath (UsrIncSearchPath);
+    }
+
     /* Delete the active file structure */
     FreeAFile (Input);
 }
@@ -340,7 +390,7 @@ static void GetInputChar (void)
 
 void NextChar (void)
 /* Skip the current input character and read the next one from the input
- * stream. CurC and NextC are valid after the call. If end of line is 
+ * stream. CurC and NextC are valid after the call. If end of line is
  * reached, both are set to NUL, no more lines are read by this function.
  */
 {
@@ -386,19 +436,6 @@ StrBuf* InitLine (StrBuf* Buf)
 
 
 
-void PushLine (const StrBuf* Buf)
-/* Push a copy of Buf onto the input stack */
-{
-    CollAppend (&InputStack, Line);
-    Line = NewStrBuf ();
-    SB_Copy (Line, Buf);
-
-    /* Make CurC and NextC valid */
-    GetInputChar ();
-}
-
-
-
 int NextLine (void)
 /* Get a line from the current input. Returns 0 on end of file. */
 {
@@ -409,7 +446,7 @@ int NextLine (void)
 
     /* If there is no file open, bail out, otherwise get the current input file */
     if (CollCount (&AFiles) == 0) {
-       return 0;
+       return 0;
     }
     Input = CollLast (&AFiles);
 
@@ -422,14 +459,15 @@ int NextLine (void)
         /* Check for EOF */
         if (C == EOF) {
 
-           /* Leave the current file */
-           CloseIncludeFile ();
-
             /* Accept files without a newline at the end */
             if (SB_NotEmpty (Line)) {
+                ++Input->Line;
                 break;
             }
 
+           /* Leave the current file */
+           CloseIncludeFile ();
+
             /* If there is no file open, bail out, otherwise get the
              * previous input file and start over.
              */
@@ -478,7 +516,7 @@ int NextLine (void)
     InitLine (Line);
 
     /* Create line information for this line */
-    UpdateLineInfo (Input->Input, Input->Line, SB_GetConstBuf (Line));
+    UpdateLineInfo (Input->Input, Input->Line, Line);
 
     /* Done */
     return 1;
@@ -486,22 +524,30 @@ int NextLine (void)
 
 
 
+const char* GetInputFile (const struct IFile* IF)
+/* Return a filename from an IFile struct */
+{
+    return IF->Name;
+}
+
+
+
 const char* GetCurrentFile (void)
 /* Return the name of the current input file */
 {
     unsigned AFileCount = CollCount (&AFiles);
     if (AFileCount > 0) {
-       const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
-       return AF->Input->Name;
+       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 {
+       /* 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)";
-       }
+       }
     }
 }
 
@@ -512,40 +558,109 @@ unsigned GetCurrentLine (void)
 {
     unsigned AFileCount = CollCount (&AFiles);
     if (AFileCount > 0) {
-       const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
-       return AF->Line;
+       const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
+       return AF->Line;
     } else {
-       /* No open file */
-       return 0;
+       /* No open file */
+       return 0;
     }
 }
 
 
 
-void WriteDependencies (FILE* F, const char* OutputFile)
-/* Write a makefile dependency list to the given file */
+static void WriteEscaped (FILE* F, const char* Name)
+/* Write a file name to a dependency file escaping spaces */
 {
-    unsigned I;
+    while (*Name) {
+        if (*Name == ' ') {
+            /* Escape spaces */
+            fputc ('\\', F);
+        }
+        fputc (*Name, F);
+        ++Name;
+    }
+}
 
-    /* Get the number of input files */
-    unsigned IFileCount = CollCount (&IFiles);
 
-    /* Print the output file followed by a tab char */
-    fprintf (F, "%s:\t", OutputFile);
+
+static void WriteDep (FILE* F, InputType Types)
+/* Helper function. Writes all file names that match Types to the output */
+{
+    unsigned I;
 
     /* 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);
+    unsigned FileCount = CollCount (&IFiles);
+    for (I = 0; I < FileCount; ++I) {
+
+       /* Get the next input file */
+       const IFile* IF = (const IFile*) CollAt (&IFiles, I);
+
+        /* Ignore it if it is not of the correct type */
+        if ((IF->Type & Types) == 0) {
+            continue;
+        }
+
+       /* If this is not the first file, add a space */
+               if (I > 0) {
+            fputc (' ', F);
+        }
+
+       /* Print the dependency escaping spaces */
+        WriteEscaped (F, IF->Name);
     }
+}
 
-    /* End the line */
-    fprintf (F, "\n\n");
+
+
+static void CreateDepFile (const char* Name, InputType Types)
+/* Create a dependency file with the given name and place dependencies for
+ * all files with the given types there.
+ */
+{
+    /* Open the file */
+    FILE* F = fopen (Name, "w");
+    if (F == 0) {
+               Fatal ("Cannot open dependency file `%s': %s", Name, strerror (errno));
+    }
+
+    /* If a dependency target was given, use it, otherwise use the output
+     * file name as target, followed by a tab character.
+     */
+    if (SB_IsEmpty (&DepTarget)) {
+        WriteEscaped (F, OutputFilename);
+    } else {
+        WriteEscaped (F, SB_GetConstBuf (&DepTarget));
+    }
+    fputs (":\t", F);
+
+    /* Write out the dependencies for the output file */
+    WriteDep (F, Types);
+    fputs ("\n\n", F);
+
+    /* Write out a phony dependency for the included files */
+    WriteDep (F, Types);
+    fputs (":\n\n", F);
+
+    /* Close the file, check for errors */
+    if (fclose (F) != 0) {
+       remove (Name);
+       Fatal ("Cannot write to dependeny file (disk full?)");
+    }
 }
 
 
 
+void CreateDependencies (void)
+/* Create dependency files requested by the user */
+{
+    if (SB_NotEmpty (&DepName)) {
+        CreateDepFile (SB_GetConstBuf (&DepName),
+                       IT_MAIN | IT_USRINC);
+    }
+    if (SB_NotEmpty (&FullDepName)) {
+        CreateDepFile (SB_GetConstBuf (&FullDepName),
+                       IT_MAIN | IT_SYSINC | IT_USRINC);
+    }
+}
+
+