Source file : find_zip.adb
1 ------------------------------------------------------------------------------
2 -- File: Find_Zip.adb
3 -- Description: Search a text string in files packed in a zip archive.
4 -- Author: Gautier de Montmollin
5 ------------------------------------------------------------------------------
6
7 with Ada.Calendar,
8 Ada.Characters.Handling,
9 Ada.Command_Line,
10 Ada.Integer_Text_IO,
11 Ada.Streams,
12 Ada.Strings.Fixed,
13 Ada.Text_IO;
14
15 with Zip;
16 with UnZip.Streams;
17 with Show_License;
18
19 procedure Find_Zip is
20
21 max : constant := 2**10; -- 1024
22 str : String (1 .. max); -- str(1..stl) = string to search
23 stl : Natural; -- string length
24 l : Character; -- last character of the search string
25
26 z : Zip.Zip_Info;
27
28 ignore_case : constant Boolean := True;
29
30 use Ada.Characters.Handling, Ada.Integer_Text_IO, Ada.Text_IO;
31 use UnZip.Streams;
32
33 procedure Search_1_file_using_output_stream (file_name : String) is
34 occ : Natural := 0;
35 -- Define a circular buffer
36 siz : constant := max;
37 type Buffer_range is mod siz;
38 buf : array (Buffer_range) of Character := (others => ' ');
39 bup : Buffer_range := 0;
40 --
41 -- We define a local, ad-hoc stream type.
42 --
43 type Search_stream is new Ada.Streams.Root_Stream_Type with null record;
44 --
45 overriding procedure Read
46 (Self : in out Search_stream;
47 Item : out Ada.Streams.Stream_Element_Array;
48 Last : out Ada.Streams.Stream_Element_Offset) is null; -- Not used.
49
50 overriding procedure Write
51 (Self : in out Search_stream;
52 Item : in Ada.Streams.Stream_Element_Array);
53
54 -- Implementation of Write:
55 overriding procedure Write
56 (Self : in out Search_stream;
57 Item : in Ada.Streams.Stream_Element_Array)
58 is
59 pragma Unreferenced (Self);
60 c : Character;
61 i : Buffer_range := 0;
62 j : Natural;
63 begin
64 for sei in Item'Range loop
65 c := Character'Val (Item (sei));
66 if ignore_case then
67 c := To_Upper (c);
68 end if;
69 if c = l then -- last character do match, search further...
70 i := bup;
71 j := stl;
72 match : loop
73 i := i - 1; -- this loops modulo max: 3, 2, 1, 0, max-1, max-2, ...
74 j := j - 1;
75 if j = 0 then -- we survived the whole search string
76 occ := occ + 1;
77 exit match;
78 end if;
79 exit match when str (j) /= buf (i);
80 end loop match;
81 end if;
82 buf (bup) := c;
83 bup := bup + 1;
84 end loop;
85 end Write;
86
87 sst : Search_stream;
88
89 begin
90 Extract (
91 Destination => sst,
92 Archive_Info => z,
93 Entry_Name => file_name,
94 Ignore_Directory => False
95 );
96 if occ > 0 then
97 Put (occ, 5);
98 Put_Line (" in [" & To_Lower (file_name) & "]'s contents");
99 end if;
100 end Search_1_file_using_output_stream;
101
102 -- Old variant using an input stream (memory footprint is uncompressed
103 -- size plus fixed amounts: can be large!)
104
105 procedure Search_1_file_using_input_stream (file_name : String) is
106 f : Zipped_File_Type;
107 s : Stream_Access;
108 c : Character;
109 occ : Natural := 0;
110 -- Define a circular buffer
111 siz : constant := max;
112 type Buffer_range is mod siz;
113 buf : array (Buffer_range) of Character := (others => ' ');
114 i, bup : Buffer_range := 0;
115 j : Natural;
116 begin
117 Open (f, z, file_name);
118 s := Stream (f);
119 while not End_Of_File (f) loop
120 Character'Read (s, c);
121 if ignore_case then
122 c := To_Upper (c);
123 end if;
124 if c = l then -- last character do match, search further...
125 i := bup;
126 j := stl;
127 match : loop
128 i := i - 1; -- this loops modulo max: 3, 2, 1, 0, max-1, max-2, ...
129 j := j - 1;
130 if j = 0 then -- we survived the whole search string
131 occ := occ + 1;
132 exit match;
133 end if;
134 exit match when str (j) /= buf (i);
135 end loop match;
136 end if;
137 buf (bup) := c;
138 bup := bup + 1;
139 end loop;
140 Close (f);
141 if occ > 0 then
142 Put (occ, 5);
143 Put_Line (" in [" & To_Lower (file_name) & "] (inward stream method)");
144 end if;
145 end Search_1_file_using_input_stream;
146 pragma Unreferenced (Search_1_file_using_input_stream);
147
148 procedure Search_all_files is new Zip.Traverse (Search_1_file_using_output_stream);
149
150 procedure Search_in_entry_name (file_name : String) is
151 un : String := file_name;
152 begin
153 if ignore_case then
154 un := To_Upper (un);
155 end if;
156 if Ada.Strings.Fixed.Index (un, str (1 .. stl)) > 0 then
157 Put_Line (" Found in [" & To_Lower (file_name) & "]'s entry name");
158 end if;
159 end Search_in_entry_name;
160
161 procedure Search_all_file_names is new Zip.Traverse (Search_in_entry_name);
162
163 function Try_with_zip (file_name : String) return String is
164 begin
165 if Zip.Exists (file_name) then
166 return file_name;
167 else
168 return file_name & ".zip";
169 -- Maybe the file doesn't exist, but we tried our best...
170 end if;
171 end Try_with_zip;
172
173 use Ada.Command_Line;
174
175 procedure Load_Archive_Catalogue is
176 n : constant String := Try_with_zip (Argument (1));
177 begin
178 Zip.Load (z, n);
179 exception
180 when Zip.Archive_open_error =>
181 Put ("Can't open archive [" & n & ']'); raise;
182 when UnZip.Wrong_password =>
183 Put ("Archive has a password"); raise;
184 end Load_Archive_Catalogue;
185
186 procedure Prepare_Search_String is
187 s : String := Argument (2);
188 begin
189 Put_Line ("Searching string [" & s & "]");
190 if ignore_case then
191 s := To_Upper (s);
192 end if;
193 stl := s'Length;
194 if stl > str'Length then
195 raise Constraint_Error;
196 end if;
197 str (1 .. stl) := s;
198 l := str (stl);
199 end Prepare_Search_String;
200
201 procedure Blurb is
202 begin
203 Put_Line ("Find_Zip * Search a text string in files packed in a zip archive.");
204 Put_Line ("Demo for the Zip-Ada library, by G. de Montmollin");
205 Put_Line ("Library version " & Zip.version & " dated " & Zip.reference);
206 Put_Line ("URL: " & Zip.web);
207 Show_License (Current_Output, "zip.ads");
208 Put_Line ("Usage: find_zip archive[.zip] [""]text[""]");
209 New_Line;
210 Put ("Press Return");
211 Skip_Line;
212 end Blurb;
213
214 T0, T1, T2 : Ada.Calendar.Time;
215 use Ada.Calendar;
216
217 begin
218 if Argument_Count < 2 then
219 Blurb;
220 return;
221 end if;
222 T0 := Clock;
223 Load_Archive_Catalogue;
224 Prepare_Search_String;
225 T1 := Clock;
226 Search_all_files (z);
227 Search_all_file_names (z);
228 T2 := Clock;
229 Put_Line
230 ("Time elapsed :" & Duration'Image (T2 - T0) &
231 " seconds (loading catalogue: " & Duration'Image (T1 - T0) & ").");
232 end Find_Zip;
Web view of Ada source code generated by GNATHTML, project: ALI_Parse version 1.0.
Zip-Ada: Ada library for zip archive files (.zip).
Ada programming.
Some news about Zip-Ada and other Ada projects
on Gautier's blog.