with Ada.Containers.Vectors; with Ada.Directories; with Ada.Finalization; with Ada.Iterator_Interfaces; with Ada.Strings.Unbounded; package Dir_Iterators.Recursive is -- A simple type to return each directory entry. type Reference_Type (Element : not null access constant Ada.Directories .Directory_Entry_Type) is null record with Implicit_Dereference => Element; type Cursor is private; function Has_Element (Position : Cursor) return Boolean; package Recursive_Dir_Iterator_Interfaces is new Ada.Iterator_Interfaces (Cursor => Cursor, Has_Element => Has_Element); type Filter_Function is access function (Dir_Entry : Ada.Directories.Directory_Entry_Type) return Boolean; -- A function used to prune directories or files from the search results. type Recursive_Dir_Iterator(Filter : access function (Dir_Entry : Ada.Directories.Directory_Entry_Type) return Boolean) is new Ada.Finalization.Limited_Controlled and Recursive_Dir_Iterator_Interfaces.Forward_Iterator with private; overriding function First (Object : Recursive_Dir_Iterator) return Cursor; overriding function Next (It : Recursive_Dir_Iterator; Position : Cursor) return Cursor; type Recursive_Dir_Walk (Filter : Filter_Function) is tagged limited private with Default_Iterator => Iterate, Iterator_Element => Reference_Type, Constant_Indexing => Element_Value; function Walk (Dir : String; Filter : access function (Dir_Entry : Ada.Directories.Directory_Entry_Type) return Boolean := null) return Recursive_Dir_Walk; function Iterate (Tree : Recursive_Dir_Walk) return Recursive_Dir_Iterator_Interfaces.Forward_Iterator'Class; function Element_Value (Tree : Recursive_Dir_Walk; Position : Cursor) return Reference_Type; private -- The base type that lets us use an iterator in a nice `for` loop. type Recursive_Dir_Walk(Filter : Filter_Function) is tagged limited record Root : Ada.Strings.Unbounded.Unbounded_String; end record; -- The list of unprocessed directories needs to be stored. package String_Vectors is new Ada.Containers.Vectors (Index_Type => Positive, Element_Type => Ada.Strings.Unbounded.Unbounded_String, "=" => Ada.Strings.Unbounded."="); type Recursive_Dir_Iterator (Filter : access function (Dir_Entry : Ada.Directories.Directory_Entry_Type) return Boolean) is new Ada.Finalization.Limited_Controlled and Recursive_Dir_Iterator_Interfaces.Forward_Iterator with record -- There's some weirdness and complexity resulting from skipping the -- files of the current and parent directories (. and .. respectively). -- -- The state of the next step current search is stored, so for last -- entry in a directory, there will be "no more entries", while Next -- Entry is still valid. -- -- This causes the strange state of the current search being done, there -- being no more directories left to process, but still one single valid -- entry. Has_Valid_Entry : Boolean; Current_Search : Ada.Directories.Search_Type; Next_Entry : aliased Ada.Directories.Directory_Entry_Type; Left_To_Process : String_Vectors.Vector; Current_Level : String_Vectors.Vector; end record; overriding procedure Finalize (It : in out Recursive_Dir_Iterator); type Recursive_Dir_Iterator_Access is access all Recursive_Dir_Iterator; type Cursor is record It : Recursive_Dir_Iterator_Access; end record; end Dir_Iterators.Recursive;