~/bin/fileio
fileio
usage: fileio [lc|ls|find] file1 file2 ...
Simple file handling is the focus of this chapter. Reading existing files is at the core of many applications and is illustrated with several examples. All the output in this chapter is to the default standard output postponing creation of files to a later chapter.
Code organization is a key to building reliable applications. With this in mind, key ideas of this chapter are organized as a reusable toolkit. The applications built are then a rather thin layer that use the library. The library itself will be grown over the entire book.
Command Line processing
Reading text files
Simple string search
Binary File Reading
Simple Transformations of files
Code library to enable reuse
This projectlet will leverage the command line to combine diverse functions into one executable.
~/bin/fileio
fileio
usage: fileio [lc|ls|find] file1 file2 ...
Line Count of a set of files
~/bin/fileio lc ../Prj/fileio/fileio.gpr ../Prj/fileio/src/fileio.adb
fileio
fileio.linecount
File ../Prj/fileio/fileio.gpr has 22 lines
File ../Prj/fileio/src/fileio.adb has 146 lines
List a small file.
~/bin/fileio list ../Prj/fileio/fileio.gpr
fileio
fileio.list
*****../Prj/fileio/fileio.gpr
1 : with "config/fileio_config.gpr";
2 : project Fileio is
3 :
4 : for Source_Dirs use ("src/", "config/");
5 : for Object_Dir use "obj/" & Fileio_Config.Build_Profile;
6 : for Create_Missing_Dirs use "True";
7 : for Exec_Dir use "../bin";
8 : for Main use ("fileio.adb");
9 :
10 : package Compiler is
11 : for Default_Switches ("Ada") use Fileio_Config.Ada_Compiler_Switches;
12 : end Compiler;
13 :
14 : package Binder is
15 : for Switches ("Ada") use ("-Es"); -- Symbolic traceback
16 : end Binder;
17 :
18 : package Install is
19 : for Artifacts (".") use ("share");
20 : end Install;
21 :
22 : end Fileio;
***** End of File ******
~/bin/fileio find package ../Prj/fileio/fileio.gpr
fileio
fileio.search
*****../Prj/fileio/fileio.gpr
10 : package Compiler is
14 : package Binder is
18 : package Install is
***** Found 3 instances
Predefined Language Environment
~/bin/codemd ../Prj/fileio/src/fileio.adb -x Library -l
0002 | with Ada.Text_IO; use Ada.Text_IO;
0003 | with Ada.Command_Line; use Ada.Command_Line;
0004 | with Ada.Strings.Fixed;
0005 |
0006 | with GNAT.Source_Info; use GNAT.Source_Info;
Command Line Processing
~/bin/codemd ../Prj/fileio/src/fileio.adb -x Command -l
0127 | if Argument_Count >= 1 then
0128 | declare
0129 | operation : constant String := Argument (1);
0130 | begin
0131 | if operation = "lc" or operation = "linecount" then
0132 | linecount;
0133 | elsif operation = "ls" or operation = "list" then
0134 | list;
0135 | elsif operation = "find" or operation = "search" then
0136 | search;
0137 | else
0138 | Put (operation);
0139 | Put_Line (" is not a supported command");
0140 | end if;
0141 | end;
Line Oriented text file input
~/bin/codemd ../Prj/fileio/src/fileio.adb -x ReadLines -l
0092 | while not End_Of_File (txtfile) loop
0093 | Get_Line (txtfile, line, linelength);
0094 | line_number := line_number + 1;
0095 | argpos := Strings.Fixed.Index (line (1 .. linelength), arg, 1);
0096 | if argpos > 0 then
0097 | count := count + 1;
0098 | Put (line_number'Image);
0099 | Set_Col (8);
0100 | Put (" : ");
0101 | Put_Line (line (1 .. linelength));
0102 | end if;
0103 | end loop;
A sample implementation of the projectlets is available from:
https://gitlab.com/RajaSrinivasan/TechAdaBook.git
Directory: Prj/fileio
This projectlet reads files as a binary stream without regard to any line breaks. The data is dump’ed in hexadecimal format.
In the first example, the command line argument is dumped in hexadecimal form. The output is in 3 columns - the byte offset from the beginning of the string, a printout in ASCII followed by hexadecimal representation.
~/bin/dump "An arbitrary string to dump in hex"
16#0# * An.arbitrary.str * 416e2061726269747261727920737472 *
16#10# * ing.to.dump.in.h * 696e6720746f2064756d7020696e2068 *
16#20# * ex * 6578 *
A variation is to print out the contents of files.
~/bin/dumpf ~/profile.sh
Dump of /Users/rajasrinivasan/profile.sh Size : 283
16#0# * ...bin.bash..exp * 23212f62696e2f626173680a23657870 *
16#10# * ort.PATH..HOME.t * 6f727420504154483d24484f4d452f74 *
16#20# * ools.bin.gnat.na * 6f6f6c732f62696e2f676e61745f6e61 *
16#30# * tive.11.2.3.f008 * 746976655f31312e322e335f66303038 *
16#40# * a8a7.bin..HOME.t * 613861372f62696e3a24484f4d452f74 *
16#50# * ools.bin.gprbuil * 6f6f6c732f62696e2f6770726275696c *
16#60# * d.22.0.1.b1220e2 * 645f32322e302e315f62313232306532 *
16#70# * b.bin..PATH.expo * 622f62696e3a24504154480a6578706f *
16#80# * rt.PATH..PATH..H * 727420504154483d24504154483a2448 *
16#90# * OME.bin..HOME.to * 4f4d452f62696e3a24484f4d452f746f *
16#A0# * ols.bin.export.G * 6f6c732f62696e0a6578706f72742047 *
16#B0# * PR.PROJECT.PATH. * 50525f50524f4a4543545f504154483d *
16#C0# * .GPR.PROJECT.PAT * 244750525f50524f4a4543545f504154 *
16#D0# * H..HOME.Prj.talk * 483a24484f4d452f50726a2f74616c6b *
16#E0# * .logging...Flutt * 2f6c6f6767696e670a2320466c757474 *
16#F0# * er.dev.export.PA * 6572206465760a6578706f7274205041 *
16#100# * TH..PATH..HOME.f * 54483d24504154483a24484f4d452f66 *
16#110# * lutter.bin. * 6c75747465722f62696e0a *
Considering that hexadecimal printouts are an important diagnostic tool for other applications, this is an opportunity to create a support library; finally wrapping the support into a cli tool for illustrative purposes.
The toolkit defines a set of packages hex and hex.dump. Command line tool dump to convert a string to hexadecimal and dumpf to dump an entire file are created. The applications themselves are almost trivial:
~/bin/codemd ~/Prj/GitLab/toolkit/examples/dump/src/dumpf.adb -x DumpFile -l
0002 | with Ada.Command_Line; use Ada.Command_Line ;
0003 | with hex.dump ;
0004 | procedure Dumpf is
0005 | begin
0006 | hex.dump.Dump( Argument(1) );
0007 | end Dumpf ;
The core feature of this projectlet is the conversion of binary data block to a hexadecimal form. Basic building block:
~/bin/codemd ~/Prj/GitLab/toolkit/adalib/src/hex.adb -x BinHex -l
0090 | function Image (bin : Interfaces.Unsigned_8) return Hexstring is
0091 | use Interfaces;
0092 | img : Hexstring;
0093 | Lnibble : constant Interfaces.Unsigned_8 := bin and 16#0f#;
0094 | Hnibble : constant Interfaces.Unsigned_8 :=
0095 | Interfaces.Shift_Right (bin and 16#f0#, 4);
0096 | begin
0097 | img (1) := Nibble_Hex (Integer (Hnibble) + 1);
0098 | img (2) := Nibble_Hex (Integer (Lnibble) + 1);
0099 | return img;
0100 | end Image;
And the reverse - a hexadecimal string to a binary.
~/bin/codemd ~/Prj/GitLab/toolkit/adalib/src/hex.adb -x StrBin -l
0029 | function Value (Hex : Hexstring) return Interfaces.Unsigned_8 is
0030 | use Interfaces;
0031 | Vhigh, Vlow : Interfaces.Unsigned_8;
0032 | begin
0033 | Vhigh := Value (Hex (1));
0034 | Vlow := Value (Hex (2));
0035 | return Vhigh * 16 + Vlow;
0036 | end Value;
These fragments can be integrated into a conversion of a block:
~/bin/codemd ~/Prj/GitLab/toolkit/adalib/src/hex.adb -x BlockHex -l
0130 | function Image (binptr : System.Address; Length : Integer) return String is
0131 | -- use Interfaces;
0132 | img : String (1 .. 2 * Length);
0133 | bytes : array (1 .. Length) of Interfaces.Unsigned_8;
0134 | for bytes'Address use binptr;
0135 | hexstr : Hexstring;
0136 | begin
0137 | for binptr in 1 .. Length loop
0138 | hexstr := Image (bytes (binptr));
0139 | img (2 * (binptr - 1) + 1 .. 2 * (binptr - 1) + 2) := hexstr;
0140 | end loop;
0141 | return img;
0142 | end Image;
And the reverse:
~/bin/codemd ~/Prj/GitLab/toolkit/adalib/src/hex.adb -x StrBlock -l
0075 | function Value (Hex : String) return System.Storage_Elements.Storage_Array
0076 | is
0077 | use System.Storage_Elements;
0078 | result : System.Storage_Elements.Storage_Array (1 .. Hex'Length / 2);
0079 | begin
0080 | for rptr in result'Range loop
0081 | result (rptr) :=
0082 | Value (Hex (2 * Integer (rptr) - 1 .. 2 * Integer (rptr)));
0083 | end loop;
0084 | --Put_Line (Hex);
0085 | return result;
0086 | end Value;
A file is then read as a block of binary data and converted into hex strings:
~/bin/codemd ~/Prj/GitLab/toolkit/adalib/src/hex-dump.adb -x DumpFile -l
0113 | Ada.Streams.Stream_IO.Open
0114 | (file, Ada.Streams.Stream_IO.In_File, filename);
0115 | stream := Ada.Streams.Stream_IO.Stream (file);
0116 | declare
0117 | buffer :
0118 | Ada.Streams.Stream_Element_Array
0119 | (1 .. Ada.Streams.Stream_Element_Offset (filesize));
0120 | bufferlen : Ada.Streams.Stream_Element_Offset;
0121 | begin
0122 | stream.Read (buffer, bufferlen);
0123 | if bufferlen > 0 then
0124 | Hex.dump.Dump
0125 | (buffer'Address, Integer (bufferlen), bare => bare,
0126 | show_offset => show_offset, Blocklen => Blocklen,
0127 | Outfile => Outfile);
0128 | end if;
0129 | end;
Repository: toolkit
Directory: examples/dump