- AFD665D979FE64DFDCC2D99A515A887B8C32E961AFA20201755A80DCCB64713DB2942BF7828748A41C8B88859BE4BFA917CB50134A0D3F4FEF403FCFB26463EF
+ 23DCF3C0EFF5D5CA20CE1C5091E4DC9B739D2D98630208AA16DEC1298A13C28962089C0311E8E50AF9801C026E79F003FE8B9CE9341C351CB4E4556347D14734
vtools/src/vpatch.adb
(3 . 6)(3 . 7)
130 with Interfaces.C.Strings;
131 with Ada.Text_IO; use Ada.Text_IO;
132 with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
133 with Character_IO; use Character_IO;
134 with Ada.Strings.Fixed;
135 with Ada.Directories;
136 with Ada.Characters;
(14 . 6)(15 . 7)
138 procedure VPatch is
139 package Latin_1 renames Ada.Characters.Latin_1;
140 package Dirs renames Ada.Directories;
141 package CIO renames Character_IO.Character_IO;
142
143 -- Utilities
144
(82 . 6)(84 . 15)
146 Create(File, Mode, Name, Form);
147 end;
148
149 procedure Create_Temp(File : in out CIO.File_Type;
150 Mode : in CIO.File_Mode := CIO.Out_File;
151 Template : in String := "vpatch.XXX";
152 Form : in String := "") is
153 Name: String := Temp_File_Name(Template);
154 begin
155 Create(File, Mode, Name, Form);
156 end;
157
158 -- VPatch data structures
159
160 type Patch_Op is (Op_Create, Op_Delete, Op_Patch);
(330 . 8)(341 . 8)
162 From_Count: Natural := 0;
163 To_Count: Natural := 0;
164 Has_Input_File: Boolean;
165 In_F: File_Type;
166 To_F: File_Type;
167 In_F: CIO.File_Type;
168 To_F: CIO.File_Type;
169 Line: Positive := 1;
170 In_Ctx: Keccak_Context;
171 To_Ctx: Keccak_Context;
(339 . 28)(350 . 37)
173 To_Hash: Bitstream(1..64*8);
174 To_F_Name: constant String := Press_Name(A_Header);
175 Op: Patch_Op;
176
177 procedure Hash_Line(Ctx: in out Keccak_Context; S: String) is
178 Newline_Directive: constant String := "\ No newline at end of file";
179
180 procedure Hash_Line(Ctx: in out Keccak_Context;
181 S: String;
182 New_Line: Boolean := True) is
183 B: Bitstream(1..S'Length*8);
184 LF_B: constant Bitstream(1..8) := (0, 1, 0, 1, 0, 0, 0, 0);
185 begin
186 ToBitstream(S, B);
187 KeccakHash(Ctx, B);
188 KeccakHash(Ctx, LF_B);
189 if New_Line then
190 KeccakHash(Ctx, LF_B);
191 end if;
192 end;
193
194
195 Check_Input_File_Hash_Pending: Boolean := True;
196 procedure Check_Input_File_Hash is
197 begin
198 if Has_Input_File then
199 if Has_Input_File and Is_Open(In_F)
200 and Check_Input_File_Hash_Pending then
201 begin
202 Check_Input_File_Hash_Pending := False;
203 Catch_Up_Loop:
204 loop
205 declare
206 In_Line: String := Get_Line(In_F);
207 New_Line: Boolean;
208 In_Line: String := Get_Line(In_F, New_Line);
209 begin
210 Put_Line(To_F, In_Line);
211 Hash_Line(In_Ctx, In_Line);
212 Hash_Line(To_Ctx, In_Line);
213 Put_Line(To_F, In_Line, New_Line);
214 Hash_Line(In_Ctx, In_Line, New_Line);
215 Hash_Line(To_Ctx, In_Line, New_Line);
216 end;
217 end loop Catch_Up_Loop;
218 exception
(374 . 8)(394 . 7)
220 H: Hash := (Value => Hex_Hash,
221 The_Type => Value);
222 begin
223 if A_Header.From_Hash /= (Value => Hex_Hash,
224 The_Type => Value) then
225 if A_Header.From_Hash /= H then
226 raise State with "from hash doesn't match";
227 end if;
228 end;
(408 . 7)(427 . 19)
230 Dirs.Delete_File(Name(To_F));
231 end if;
232 end Cleanup;
233
234
235 function Has_No_Newline_Directive return Boolean is
236 C: Character;
237 begin
238 Look_Ahead(C, EOL);
239 if C = '\' then
240 Looking_At(Newline_Directive);
241 Next_Line;
242 return True;
243 end if;
244 return False;
245 end;
246
247 begin
248 Op := Operation(A_Header);
249
(435 . 14)(466 . 14)
251
252 -- prepare keccak and open files
253 KeccakBegin(To_Ctx);
254 Create_Temp(To_F, Out_File, "tmp.XXX");
255 Create_Temp(To_F, Template => "tmp.XXX");
256 case Op is
257 when Op_Create =>
258 Has_Input_File := False;
259 when Op_Delete | Op_Patch =>
260 Has_Input_File := True;
261 KeccakBegin(In_Ctx);
262 Open(In_F, In_File, To_F_Name);
263 Open(In_F, CIO.In_File, To_F_Name);
264 end case;
265
266 Hunk_Loop:
(466 . 11)(497 . 12)
268 & "but the file has ended";
269 end if;
270 declare
271 In_Line: String := Get_Line(In_F);
272 New_Line: Boolean;
273 In_Line: String := Get_Line(In_F, New_Line);
274 begin
275 Hash_Line(In_Ctx, In_Line);
276 Hash_Line(To_Ctx, In_Line);
277 Put_Line(To_F, In_Line);
278 Hash_Line(In_Ctx, In_Line, New_Line);
279 Hash_Line(To_Ctx, In_Line, New_Line);
280 Put_Line(To_F, In_Line, New_Line);
281 Line := Line + 1;
282 end;
283 end loop;
(483 . 6)(515 . 7)
285 raise Parse with "blank line in hunk";
286 end if;
287 case C is
288
289 when '+' => -- line added
290 Get(C);
291 case Op is
(494 . 13)(527 . 20)
293 raise State with "hunk trying to add lines, "
294 & "but the line count is not valid";
295 end if;
296
297 declare
298 New_Line: Boolean := True;
299 Patch_Line: String := Get_Line;
300 begin
301 Put_Line(To_F, Patch_Line);
302 Hash_Line(To_Ctx, Patch_Line);
303 -- Last line, check for Newline directive.
304 if To_Count = 1 then
305 New_Line := not Has_No_Newline_Directive;
306 end if;
307 Put_Line(To_F, Patch_Line, New_Line);
308 Hash_Line(To_Ctx, Patch_Line, New_Line);
309 end;
310 To_Count := To_Count - 1;
311
312 when '-' => -- line deleted
313 Get(C);
314 case Op is
(515 . 17)(555 . 28)
316 raise State with "hunk trying to remove lines, "
317 & "when the input file already ended";
318 end if;
319
320 declare
321 In_Line: String := Get_Line(In_F);
322 New_Line: Boolean;
323 In_Line: String := Get_Line(In_F, New_Line);
324 Patch_Line: String := Get_Line;
325 begin
326 -- Last line, check for Newline directive.
327 if From_Count = 1 then
328 if Has_No_Newline_Directive and New_Line then
329 raise State with "input file has newline, "
330 & "while hunk claims it doesn't";
331 end if;
332 end if;
333
334 if In_Line /= Patch_Line then
335 raise State with "lines don't match";
336 end if;
337 Hash_Line(In_Ctx, In_Line);
338 Hash_Line(In_Ctx, In_Line, New_Line);
339 end;
340 Line := Line + 1;
341 From_Count := From_Count - 1;
342
343 when ' ' => -- line stays the same
344 Get(C);
345 if not Has_Input_File then
(540 . 20)(591 . 34)
347 raise State with "hunk claims identical lines, "
348 & "when input file already ended";
349 end if;
350
351 declare
352 In_Line: String := Get_Line(In_F);
353 New_Line: Boolean;
354 In_Line: String := Get_Line(In_F, New_Line);
355 Patch_Line: String := Get_Line;
356 begin
357 if In_Line /= Patch_Line then
358 raise State with "lines don't match";
359 end if;
360 Put_Line(To_F, Patch_Line);
361 Hash_Line(In_Ctx, In_Line);
362 Hash_Line(To_Ctx, In_Line);
363 if From_Count = 1 then
364 if Has_No_Newline_Directive and New_Line then
365 raise State with "input file has newline, "
366 & "while hunk claims it doesn't";
367 end if;
368 end if;
369
370 Put_Line(To_F, Patch_Line, New_Line);
371 Hash_Line(In_Ctx, In_Line, New_Line);
372 Hash_Line(To_Ctx, In_Line, New_Line);
373 end;
374 Line := Line + 1;
375 From_Count := From_Count - 1;
376 To_Count := To_Count - 1;
377
378 when '\' =>
379 Looking_At(Newline_Directive);
380 raise State with "invalid line count in hunk";
381
382 when others =>
383 raise Parse with "unexpected character "
384 & Character'Image(C)