2 * SARG Squid Analysis Report Generator http://sarg.sourceforge.net
6 * please look at http://sarg.sourceforge.net/donations.php
8 * http://sourceforge.net/projects/sarg/forums/forum/363374
9 * ---------------------------------------------------------------------
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
27 #include "include/conf.h"
28 #include "include/defs.h"
29 #include "include/stringbuffer.h"
30 #include "include/filelist.h"
34 //! Next entry at the same level.
35 struct DirEntryStruct
*Sibbling
;
36 //! First child of this entry.
37 struct DirEntryStruct
*Child
;
38 //! Name of this entry.
40 //! \c True if it contains any wildcard.
45 * \brief List of files.
47 * The list may contain wildcards.
52 struct DirEntryStruct
*First
;
53 //! Buffer containing the file name strings.
54 StringBufferObject Buffer
;
55 //! Deepest level of the tree.
57 //! \c True if the tree depth is correct.
61 struct DirEntryIterator
63 //! The current node at each level.
64 struct DirEntryStruct
*Dir
;
65 //! Length of the path up to that level.
70 * \brief Iterator of the file list.
72 struct _FileListIterator
74 //! File list object from which we are iterating.
75 FileListObject Parent
;
76 //! Current path being stored in the object.
78 //! Number of bytes allocated for the current path.
80 //! Level known to be stored in the path.
82 //! Tree depth when the iteration started.
84 //! Current level being iterated over.
86 //! The current node at each level.
87 struct DirEntryIterator
*DirNodes
;
92 * Create an object to store the files to process.
94 * \return The created object or NULL if it failed.
95 * The object must be destroyed with a call to FileList_Destroy().
97 FileListObject
FileList_Create(void)
101 FObj
=(FileListObject
)calloc(1,sizeof(*FObj
));
109 * Destroy the entries tree.
111 static void FileList_DestroyEntry(struct DirEntryStruct
*Entry
)
113 struct DirEntryStruct
*Next
;
118 FileList_DestroyEntry(Entry
->Child
);
119 Next
=Entry
->Sibbling
;
126 * Destroy the object created by FileList_Create().
128 * \param FPtr A pointer to the object to destroy. It is
129 * reset to NULL before the function returns.
131 void FileList_Destroy(FileListObject
*FPtr
)
135 if (!FPtr
|| !*FPtr
) return;
139 FileList_DestroyEntry(FObj
->First
);
140 StringBuffer_Destroy(&FObj
->Buffer
);
145 * Store an entry in the tree.
147 * \param FObj The file list object created by FileList_Create().
148 * \param FileName Name of the file to store recursively.
150 * \return The branch created with all the entries in \c FileName.
151 * The returned value is NULL if \c FileName could not be added.
153 static struct DirEntryStruct
*FileList_StoreEntry(FileListObject FObj
,const char *FileName
)
155 struct DirEntryStruct
*Entry
;
161 Entry
=(struct DirEntryStruct
*)calloc(1,sizeof(*Entry
));
162 if (!Entry
) return(NULL
);
163 for (i
=0 ; FileName
[i
] ; i
++)
165 if (FileName
[i
]=='/')
169 /* The path contains a wildcard. There are no directories
170 * before this path or it would have been caught by the other
171 * break in this loop. We store it.
178 else if (FileName
[i
]=='*' || FileName
[i
]=='?')
182 /* Some directories without wildcards before this directory
183 * with wildcard. We store the previous directories in one
184 * entry and disregard, for now, the current path level.
192 Entry
->Name
=StringBuffer_StoreLength(FObj
->Buffer
,FileName
,(Next
<0) ? i
: Next
);
198 Entry
->IsMask
=IsMask
;
201 FObj
->TreeDepthOk
=false; //it will have to be recomputed
202 Entry
->Child
=FileList_StoreEntry(FObj
,FileName
+Next
+1);
213 * Store a file in the internal data structure.
215 * \param FObj The file list object created by FileList_Create().
216 * \param EntryPtr Pointer to the tree node to add or create.
217 * \param FileName The name of the file.
219 * \return \c True on success or \c false on failure.
221 static bool FileList_AddFileRecursive(FileListObject FObj
,struct DirEntryStruct
**EntryPtr
,const char *FileName
)
224 struct DirEntryStruct
*Entry
;
225 struct DirEntryStruct
*Last
;
230 Entry
=FileList_StoreEntry(FObj
,FileName
);
231 if (!Entry
) return(false);
236 // find where to store the file name in the existing tree
238 for (Entry
=*EntryPtr
; Entry
; Entry
=Entry
->Sibbling
)
241 for (i
=0 ; Entry
->Name
[i
] && FileName
[i
] && Entry
->Name
[i
]==FileName
[i
] ; i
++)
243 if (FileName
[i
]=='/')
246 if (FileName
[i
]=='/' && Entry
->Name
[i
]=='\0')
248 //root is matching, check sub level
249 return(FileList_AddFileRecursive(FObj
,&Entry
->Child
,FileName
+i
+1));
253 //paths begin with the same directory but diverges at LastDir
254 struct DirEntryStruct
*Split
;
256 Split
=(struct DirEntryStruct
*)calloc(1,sizeof(*Split
));
257 if (!Split
) return(false);
258 Split
->Name
=Entry
->Name
+LastDir
+1;
259 Split
->Child
=Entry
->Child
;
260 Entry
->Name
[LastDir
]='\0';
262 return(FileList_AddFileRecursive(FObj
,&Entry
->Child
,FileName
+LastDir
+1));
268 Entry
=FileList_StoreEntry(FObj
,FileName
);
269 if (!Entry
) return(false);
270 Last
->Sibbling
=Entry
;
276 * Add a file to the object.
278 * \param FObj The object created by FileList_Create().
279 * \param FileName The file name to add to the list.
281 * \return \c True if the file was added or \c false if it
282 * failed. The function may fail if a parameter is invalid.
283 * It will also fail if the memory cannot be allocated.
285 bool FileList_AddFile(FileListObject FObj
,const char *FileName
)
287 if (!FObj
|| !FileName
) return(false);
291 FObj
->Buffer
=StringBuffer_Create();
296 return(FileList_AddFileRecursive(FObj
,&FObj
->First
,FileName
));
300 * Recursively measure the tree depth.
302 * \param FObj File list object created by FileList_Create().
303 * \param Entry Node whose child are to be processed.
304 * \param Level Current level.
306 static void FileList_SetDepth(FileListObject FObj
,struct DirEntryStruct
*Entry
,int Level
)
308 if (Level
>FObj
->TreeDepth
) FObj
->TreeDepth
=Level
;
312 FileList_SetDepth(FObj
,Entry
->Child
,Level
+1);
313 Entry
=Entry
->Sibbling
;
318 * Start the iteration over the files in the list.
320 * \param FObj The object to iterate over.
322 * \return The iterator structure to pass ot FileListIter_Next()
323 * to get the first file name or NULL if an error occured.
325 FileListIterator
FileListIter_Open(FileListObject FObj
)
327 struct _FileListIterator
*FIter
;
328 struct DirEntryStruct
*Dir
;
330 FIter
=(FileListIterator
)calloc(1,sizeof(*FIter
));
331 if (!FIter
) return(NULL
);
334 // compute the depth of the tree.
336 * The tree depth computation is not thread safe. A lock is necessary around
337 * the following code to make it thread safe.
339 if (!FObj
->TreeDepthOk
)
342 if (FObj
->First
) FileList_SetDepth(FObj
,FObj
->First
,1);
343 FObj
->TreeDepthOk
=true;
345 FIter
->TreeDepth
=FObj
->TreeDepth
;
347 FIter
->CurrentPathSize
=0;
348 FIter
->CurrentPathLevel
=0;
349 if (FIter
->TreeDepth
>0)
351 FIter
->DirNodes
=(struct DirEntryIterator
*)calloc(FIter
->TreeDepth
,sizeof(struct DirEntryIterator
));
352 if (!FIter
->DirNodes
)
354 FileListIter_Close(FIter
);
357 for (Dir
=FObj
->First
; Dir
; Dir
=Dir
->Child
)
359 FIter
->DirNodes
[++FIter
->Level
].Dir
=Dir
;
367 * Get the next entry in the directory tree.
369 static void FileListIter_GetNext(struct _FileListIterator
*FIter
)
371 struct DirEntryStruct
*Dir
;
373 FIter
->CurrentPathLevel
=0;
374 while (FIter
->Level
>=0)
376 Dir
=FIter
->DirNodes
[FIter
->Level
].Dir
;
380 FIter
->DirNodes
[FIter
->Level
].Dir
=Dir
;
381 FIter
->CurrentPathLevel
=FIter
->Level
;
384 if (FIter
->Level
>=FIter
->TreeDepth
) break;
386 FIter
->DirNodes
[++FIter
->Level
].Dir
=Dir
;
395 * Get the next file in the list.
397 * \param FIter The iterator created by FileListIter_Open().
399 * \return The iterator function containing the next file name or NULL
400 * if there are no more files.
402 const char *FileListIter_Next(struct _FileListIterator
*FIter
)
406 struct DirEntryIterator
*DIter
;
408 if (!FIter
) return(NULL
);
409 if (!FIter
->DirNodes
) return(NULL
);
410 if (FIter
->Level
<0 || FIter
->Level
>=FIter
->TreeDepth
) return(NULL
);
412 // how much space to store the path
413 Length
=FIter
->DirNodes
[FIter
->CurrentPathLevel
].PathLength
;
414 for (Level
=FIter
->CurrentPathLevel
; Level
<=FIter
->Level
; Level
++)
416 DIter
=FIter
->DirNodes
+Level
;
417 DIter
->PathLength
=Length
;;
418 Length
+=strlen(DIter
->Dir
->Name
)+1;
421 // get the memory to store the path
422 if (Length
>FIter
->CurrentPathSize
)
424 char *temp
=realloc(FIter
->CurrentPath
,Length
);
425 if (!temp
) return(NULL
);
426 FIter
->CurrentPath
=temp
;
427 FIter
->CurrentPathSize
=Length
;
430 for (Level
=FIter
->CurrentPathLevel
; Level
<=FIter
->Level
; Level
++)
432 DIter
=FIter
->DirNodes
+Level
;
433 if (Level
>0) FIter
->CurrentPath
[DIter
->PathLength
-1]='/';
434 strcpy(FIter
->CurrentPath
+DIter
->PathLength
,DIter
->Dir
->Name
);
436 FIter
->CurrentPathLevel
=Level
;
438 FileListIter_GetNext(FIter
);
439 return(FIter
->CurrentPath
);
443 * Get the next file entry in the list without expanding the
446 * \param FIter The iterator created by FileListIter_Open().
448 * \return The iterator function containing the next file name or NULL
449 * if there are no more files.
451 const char *FileListIter_NextWithMask(struct _FileListIterator
*FIter
)
455 struct DirEntryIterator
*DIter
;
457 if (!FIter
) return(NULL
);
458 if (!FIter
->DirNodes
) return(NULL
);
459 if (FIter
->Level
<0 || FIter
->Level
>=FIter
->TreeDepth
) return(NULL
);
461 // how much space to store the path
462 Length
=FIter
->DirNodes
[FIter
->CurrentPathLevel
].PathLength
;
463 for (Level
=FIter
->CurrentPathLevel
; Level
<=FIter
->Level
; Level
++)
465 DIter
=FIter
->DirNodes
+Level
;
466 DIter
->PathLength
=Length
;;
467 Length
+=strlen(DIter
->Dir
->Name
)+1;
470 // get the memory to store the path
471 if (Length
>FIter
->CurrentPathSize
)
473 char *temp
=realloc(FIter
->CurrentPath
,Length
);
474 if (!temp
) return(NULL
);
475 FIter
->CurrentPath
=temp
;
476 FIter
->CurrentPathSize
=Length
;
479 for (Level
=FIter
->CurrentPathLevel
; Level
<=FIter
->Level
; Level
++)
481 DIter
=FIter
->DirNodes
+Level
;
482 if (Level
>0) FIter
->CurrentPath
[DIter
->PathLength
-1]='/';
483 strcpy(FIter
->CurrentPath
+DIter
->PathLength
,DIter
->Dir
->Name
);
485 FIter
->CurrentPathLevel
=Level
;
487 FileListIter_GetNext(FIter
);
488 return(FIter
->CurrentPath
);
492 * Destroy the iterator created by FileListIter_Open().
494 void FileListIter_Close(struct _FileListIterator
*FIter
)
498 if (FIter
->CurrentPath
) free(FIter
->CurrentPath
);
499 if (FIter
->DirNodes
) free(FIter
->DirNodes
);