Technical Musings

Thoughts, Ideas, and Experimentation

View on GitHub
8 May 2020

Basic grep implementation in Ada

by Timmy Jose

I have decided to learn Ada (as well!) seriously, and have been working through the (mostly good) book by Andrew Shvets (Beginning Ada - From Novice to Professional).

I decided to take a little breather by writing a simple grep implementation in Ada.

Here is the code:

with Ada.Text_IO;
with Ada.Text_IO.Unbounded_IO;
with Ada.Strings.Unbounded;
with Ada.Command_Line;
with Ada.Task_Identification;

procedure Grep is
  type StringArray is array (Positive range <>) of Ada.Strings.Unbounded.Unbounded_String;

  function Grep_File (File_Name: String; Pattern: String; Match_Count: in out Integer) return StringArray is
    File: Ada.Text_IO.File_Type;
    Matches: StringArray (1 .. 10000);
  begin
    declare 
    begin
      Ada.Text_IO.Open (
        File => File, 
        Mode => Ada.Text_IO.In_File, 
        Name => File_Name
        );
    exception
      when Ada.Text_IO.Name_Error => Ada.Text_IO.Put_Line ("Could not find file " & File_Name);
    end;

    declare
      Line_Number: Positive := 1;
      Counter: Positive := 1;
      Unbounded_Line: Ada.Strings.Unbounded.Unbounded_String := Ada.Strings.Unbounded.Null_Unbounded_String;
    begin
      loop
        exit when Ada.Text_IO.End_Of_File (File);

        Unbounded_Line := Ada.Strings.Unbounded.To_Unbounded_String (Ada.Text_IO.Get_Line (File));

        if Ada.Strings.Unbounded.Index (Unbounded_Line, Pattern) /= 0 then
          declare
            Match: Ada.Strings.Unbounded.Unbounded_String := Ada.Strings.Unbounded.Null_Unbounded_String;
          begin
            Ada.Strings.Unbounded.Append (Match, Positive'Image (Line_Number));
            Ada.Strings.Unbounded.Append (Match, " ");
            Ada.Strings.Unbounded.Append (Match, Unbounded_Line);
            Matches (Counter) := Match;
            Counter := Counter + 1;
            Match_Count := Match_Count + 1;
          end;
        end if;
        Line_Number := Line_Number + 1;
      end loop;
    end;
    Ada.Text_IO.Close (File);
    return Matches;
  end Grep_File;

  Pattern: Ada.Strings.Unbounded.Unbounded_String := Ada.Strings.Unbounded.Null_Unbounded_String;
begin
  if Ada.Command_Line.Argument_Count = 0 then
    Ada.Text_IO.Put_Line ("Usage: " & Ada.Command_Line.Command_Name & " FILE [FILE*]");
    Ada.Task_Identification.Abort_Task (Ada.Task_Identification.Current_Task);
  end if;

  Ada.Text_IO.Put_Line ("Enter the pattern to search for:");
  Pattern := Ada.Strings.Unbounded.To_Unbounded_String(Ada.Text_IO.Get_Line);

  for Idx in 1 .. Ada.Command_Line.Argument_Count loop
    declare
      Matches: StringArray (1 .. 10000);
      Match_Count: Integer := 0;
      Match_File_Name: String := Ada.Command_Line.Argument (Idx);
    begin
      Matches := Grep_File (Ada.Command_Line.Argument (Idx), Ada.Strings.Unbounded.To_String (Pattern), Match_Count);
      Ada.Text_IO.Put_Line ("For File " & Match_File_Name);
      Ada.Text_IO.New_Line;

      for Match_Idx in 1 .. Match_Count loop
        declare
          Match: Ada.Strings.Unbounded.Unbounded_String := Ada.Strings.Unbounded.Null_Unbounded_String;
        begin
          Match := Matches (Match_Idx);
          Ada.Text_IO.Unbounded_IO.Put_Line (Match);
        end;
      end loop;
      Match_Count := 0;
    end;
    Ada.Text_IO.New_Line (2);
  end loop;
end Grep;

Sample run:

```bash
~/dev/playground$ gnatmake -g grep.adb
gcc -c -g grep.adb
gnatbind -x grep.ali
gnatlink grep.ali -g
~/dev/playground$ ./grep
Usage: ./grep FILE [FILE*]

Execution terminated by abort of environment task
~/dev/playground$ ./grep *.lisp
Enter the pattern to search for:
defun
For File add-nums.lisp

 1 (defun main ()


For File add.lisp

 1 (defun add ()
 7 (defun greet (name)
 10 (defun main ()


For File dispatch.lisp

 22 (defun main ()


For File factorial.lisp

 1 (defun factorial (n)


For File hello-world.lisp

 1 (defun hello-world ()


For File mat-max.lisp

 1 (defun main ()
 5 (defun mat-max (mat)


For File palindrome.lisp

 3 (defun palindromep (string)
 11 (defun palindromep-list (lst)


For File replace.lisp

 1 (defun my-replace (lst source target)


For File scratch.lisp

 1 (defun palindromep (list)
 10 (defun palindromep-equivalent (list)

< Home >