/* Output the files section */
for (I = 0; I < CollCount (&O->Files); ++I) {
- const FileInfo* FI = CollConstAt (&O->Files, I);
- fprintf (F,
- "file\tid=%u,name=\"%s\",size=%lu,mtime=0x%08lX\n",
- FI->Id, GetString (FI->Name), FI->Size, FI->MTime);
+ FileInfo* FI = CollAt (&O->Files, I);
+ if (!FI->Dumped) {
+ fprintf (F,
+ "file\tid=%u,name=\"%s\",size=%lu,mtime=0x%08lX\n",
+ FI->Id, GetString (FI->Name), FI->Size, FI->MTime);
+ FI->Dumped = 1;
+ }
}
/* Output the line infos */
/* common */
+#include "coll.h"
#include "xmalloc.h"
/* ld65 */
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* A list of all file infos without duplicates */
+static Collection FileInfos = STATIC_COLLECTION_INITIALIZER;
+
+
+
/*****************************************************************************/
/* Code */
/*****************************************************************************/
+static int FindFileInfo (unsigned Name, unsigned* Index)
+/* Find the FileInfo for a given file name. The function returns true if the
+ * name was found. In this case, Index contains the index of the first item
+ * that matches. If the item wasn't found, the function returns false and
+ * Index contains the insert position for FileName.
+ */
+{
+ /* Do a binary search */
+ int Lo = 0;
+ int Hi = (int) CollCount (&FileInfos) - 1;
+ int Found = 0;
+ while (Lo <= Hi) {
+
+ /* Mid of range */
+ int Cur = (Lo + Hi) / 2;
+
+ /* Get item */
+ FileInfo* CurItem = CollAt (&FileInfos, Cur);
+
+ /* Found? */
+ if (CurItem->Name < Name) {
+ Lo = Cur + 1;
+ } else {
+ Hi = Cur - 1;
+ /* Since we may have duplicates, repeat the search until we've
+ * the first item that has a match.
+ */
+ if (CurItem->Name == Name) {
+ Found = 1;
+ }
+ }
+ }
+
+ /* Pass back the index. This is also the insert position */
+ *Index = Lo;
+ return Found;
+}
+
+
+
static FileInfo* NewFileInfo (void)
/* Allocate and initialize a new FileInfo struct and return it */
{
FileInfo* FI = xmalloc (sizeof (FileInfo));
/* Initialize stuff */
- FI->Id = Id++;
+ FI->Id = Id++;
+ FI->Dumped = 0;
/* Return the new struct */
return FI;
FileInfo* ReadFileInfo (FILE* F, ObjData* O)
/* Read a file info from a file and return it */
{
- /* Allocate a new FileInfo structure */
- FileInfo* FI = NewFileInfo ();
+ FileInfo* FI;
/* Read the fields from the file */
- FI->Name = MakeGlobalStringId (O, ReadVar (F));
- FI->MTime = Read32 (F);
- FI->Size = ReadVar (F);
+ unsigned Name = MakeGlobalStringId (O, ReadVar (F));
+ unsigned long MTime = Read32 (F);
+ unsigned long Size = ReadVar (F);
+
+ /* Search for the first entry with this name */
+ unsigned Index;
+ if (FindFileInfo (Name, &Index)) {
+
+ /* We have at least one such entry. Try all of them and, if size and
+ * modification time matches, return the first match. When the loop
+ * is terminated without finding an entry, Index points one behind
+ * the last entry with the name, which is the perfect insert position.
+ */
+ FI = CollAt (&FileInfos, Index);
+ while (1) {
+
+ /* Check size and modification time stamp */
+ if (FI->Size == Size && FI->MTime == MTime) {
+ /* Return this one */
+ return FI;
+ }
+
+ /* Check the next one */
+ if (++Index >= CollCount (&FileInfos)) {
+ /* Nothing left */
+ break;
+ }
+ FI = CollAt (&FileInfos, Index);
+
+ /* Done if the name differs */
+ if (FI->Name != Name) {
+ break;
+ }
+ }
+ }
+
+ /* Not found. Allocate a new FileInfo structure */
+ FI = NewFileInfo ();
+
+ /* Set the fields */
+ FI->Name = Name;
+ FI->MTime = MTime;
+ FI->Size = Size;
+
+ /* Insert the file info in our global list. Index points to the insert
+ * position.
+ */
+ CollInsert (&FileInfos, FI, Index);
/* Return the new struct */
return FI;