]> git.ipfire.org Git - thirdparty/sarg.git/blobdiff - filelist.c
Add support to decompress xz files
[thirdparty/sarg.git] / filelist.c
index fb4316514273fb4b0a3f93ad08b08ba91fd3eb5e..d4395645d4bdbf6db7564b6b3d6d6b1204a5befc 100644 (file)
@@ -28,6 +28,9 @@
 #include "include/defs.h"
 #include "include/stringbuffer.h"
 #include "include/filelist.h"
+#ifdef HAVE_GLOB_H
+#include <glob.h>
+#endif
 
 struct DirEntryStruct
 {
@@ -85,6 +88,12 @@ struct _FileListIterator
        int Level;
        //! The current node at each level.
        struct DirEntryIterator *DirNodes;
+#ifdef HAVE_GLOB_H
+       //! Next globbed file to return
+       int NextGlob;
+       //! Buffer with the globbed files.
+       glob_t Glob;
+#endif
 };
 
 
@@ -296,6 +305,21 @@ bool FileList_AddFile(FileListObject FObj,const char *FileName)
        return(FileList_AddFileRecursive(FObj,&FObj->First,FileName));
 }
 
+/*!
+ * \brief Is the file list empty?
+ *
+ * \param FObj The file list to check.
+ *
+ * \return \c True if the file list is empty or \c false if
+ * there is at least one file in the list.
+ */
+bool FileList_IsEmpty(FileListObject FObj)
+{
+       if (!FObj) return(true);
+       if (FObj->First==NULL) return(true);
+       return(false);
+}
+
 /*!
  * Recursively measure the tree depth.
  *
@@ -327,6 +351,7 @@ FileListIterator FileListIter_Open(FileListObject FObj)
        struct _FileListIterator *FIter;
        struct DirEntryStruct *Dir;
 
+       if (!FObj) return(NULL);
        FIter=(FileListIterator)calloc(1,sizeof(*FIter));
        if (!FIter) return(NULL);
        FIter->Parent=FObj;
@@ -401,42 +426,53 @@ static void FileListIter_GetNext(struct _FileListIterator *FIter)
  */
 const char *FileListIter_Next(struct _FileListIterator *FIter)
 {
-       int Length;
-       int Level;
-       struct DirEntryIterator *DIter;
+       const char *Path;
 
-       if (!FIter) return(NULL);
-       if (!FIter->DirNodes) return(NULL);
-       if (FIter->Level<0 || FIter->Level>=FIter->TreeDepth) return(NULL);
-
-       // how much space to store the path
-       Length=FIter->DirNodes[FIter->CurrentPathLevel].PathLength;
-       for (Level=FIter->CurrentPathLevel ; Level<=FIter->Level ; Level++)
-       {
-               DIter=FIter->DirNodes+Level;
-               DIter->PathLength=Length;;
-               Length+=strlen(DIter->Dir->Name)+1;
-       }
-
-       // get the memory to store the path
-       if (Length>FIter->CurrentPathSize)
+#ifdef HAVE_GLOB_H
+       if (FIter->NextGlob>0)
        {
-               char *temp=realloc(FIter->CurrentPath,Length);
-               if (!temp) return(NULL);
-               FIter->CurrentPath=temp;
-               FIter->CurrentPathSize=Length;
+               if (FIter->NextGlob<FIter->Glob.gl_pathc)
+               {
+                       Path=FIter->Glob.gl_pathv[FIter->NextGlob++];
+                       return(Path);
+               }
+               globfree(&FIter->Glob);
+               FIter->NextGlob=0;
        }
-
-       for (Level=FIter->CurrentPathLevel ; Level<=FIter->Level ; Level++)
+       Path=FileListIter_NextWithMask(FIter);
+       if (Path!=NULL && (Path[0]!='-' || Path[1]!='\0'))
        {
-               DIter=FIter->DirNodes+Level;
-               if (Level>0) FIter->CurrentPath[DIter->PathLength-1]='/';
-               strcpy(FIter->CurrentPath+DIter->PathLength,DIter->Dir->Name);
+               int ErrCode=glob(Path,GLOB_ERR | GLOB_NOSORT,NULL,&FIter->Glob);
+               if (ErrCode!=0)
+               {
+                       switch (ErrCode)
+                       {
+                       case GLOB_NOSPACE:
+                               debuga(__FILE__,__LINE__,_("Not enough memory to read the files matching \"%s\"\n"),Path);
+                               break;
+                       case GLOB_ABORTED:
+                               debuga(__FILE__,__LINE__,_("Read error while listing the files matching \"%s\"\n"),Path);
+                               break;
+                       case GLOB_NOMATCH:
+                               debuga(__FILE__,__LINE__,_("No files matching \"%s\"\n"),Path);
+                               break;
+                       default:
+                               debuga(__FILE__,__LINE__,_("Failed to glob file pattern \"%s\" with unspecified error code %d"),Path,ErrCode);
+                               break;
+                       }
+                       exit(EXIT_FAILURE);
+               }
+               Path=FIter->Glob.gl_pathv[0];
+               FIter->NextGlob=1;
        }
-       FIter->CurrentPathLevel=Level;
-
-       FileListIter_GetNext(FIter);
-       return(FIter->CurrentPath);
+#else
+       /*
+        * Fall back to a simple enumeration. In that case, the user cannot use
+        * wildcards as they won't be expended.
+        */
+       Path=FileListIter_NextWithMask(FIter);
+#endif
+       return(Path);
 }
 
 /*!
@@ -463,7 +499,7 @@ const char *FileListIter_NextWithMask(struct _FileListIterator *FIter)
        for (Level=FIter->CurrentPathLevel ; Level<=FIter->Level ; Level++)
        {
                DIter=FIter->DirNodes+Level;
-               DIter->PathLength=Length;;
+               DIter->PathLength=Length;
                Length+=strlen(DIter->Dir->Name)+1;
        }
 
@@ -495,6 +531,9 @@ void FileListIter_Close(struct _FileListIterator *FIter)
 {
        if (FIter)
        {
+#ifdef HAVE_GLOB_H
+               if (FIter->NextGlob>0) globfree(&FIter->Glob);
+#endif
                if (FIter->CurrentPath) free(FIter->CurrentPath);
                if (FIter->DirNodes) free(FIter->DirNodes);
                free(FIter);