# 17. Projects: manipulating gpr files

The package GNATCOLL.Projects provides an extensive interface to parse, manipulate and edit project files (`.gpr` files).

Although the interface is best used using the Ada 2012 notation, it is fully compatible with Ada 95.

Here is a quick example on how to use the interface, although the spec file itself contains much more detailed information on all the subprograms related to the manipulation of project files:

    with GNATCOLL.Projects; use GNATCOLL.Projects;
    with GNATCOLL.VFS;      use GNATCOLL.VFS;

    procedure Test_Project is
       Tree  : Project_Tree;
       Files : File_Array_Access;
    begin
       Tree.Load (GNATCOLL.VFS.Create (+"path_to_project.gpr"));

       --  List the source files for project and all imported projects

       Files := Tree.Root_Project.Source_Files (Recursive => True);
       for F in Files'Range loop
          Put_Line ("File is: " & Files (F).Display_Full_Name);
       end loop;

       Tree.Unload;
    end Test_Project;

## 17.1. Defining a project with user-defined packages and reading them

If you want to use GNATCOLL.Projects with a GPR file that contains specific packages and attributes, you must procede in several steps. The following example will show you how to do it:

    with Ada.Text_IO; use Ada.Text_IO;

    with GNAT.Strings;

    with GNATCOLL.Projects; use GNATCOLL.Projects;
    with GNATCOLL.VFS;      use GNATCOLL.VFS;

    procedure Test_Project is
       Tree         : Project_Tree;
       Project_File : constant Virtual_File :=
          GNATCOLL.VFS.Create (+"path_to_project.gpr");
    begin
       --  1
       if Register_New_Attribute
            ("String", "Package_Name") /= ""
          or else Register_New_Attribute
            ("List", "Package_Name", Is_List => True) /= ""
          or else Register_New_Attribute
            ("Indexed", "Package_Name", Indexed => True) /= ""
       then
          raise Program_Error;
       end if;

       --  2
       Tree.Load (Root_Project_Path => Project_File,
                  Packages_To_Check => All_Packs);

       declare
          Root : constant Project_Type := Tree.Root_Project;

          --  3
          String_Attribute : constant Attribute_Pkg_String :=
             Build ("Package_Name", "String");
          String_Value : constant String :=
             Root.Attribute_Value (String_Attribute);

          Indexed_Attribute : constant Attribute_Pkg_String :=
             Build ("Package_Name", "Indexed");
          Indexed_Value : constant String :=
             Root.Attribute_Value
               (Indexed_Attribute, Index => "Index");

          List_Attribute : constant Attribute_Pkg_List :=
             Build ("Package_Name", "List");
          List_Value : constant GNAT.Strings.String_List_Access :=
             Root.Attribute_Value (List_Attribute);
       begin
          --  4
          Put_Line ("Package_Name.String: " & String_Value);
          Put_Line ("Package_Name.Indexed (""Index""): "
                    & Indexed_Value);
          Put_Line ("Package_Name.List:");
          for Val of List_Value.all loop
             Put_Line ("  Value: " & Val.all);
          end loop;
       end;
    end Test_Project;

And the corresponding project file:

    project Path_To_Project is
       package Package_Name is
          for String use "some string"
          for Indexed ("Index") use "other string";
          for List use ("first item", "second item");
       end Package_Name;
    end Path_To_Project;

Step 1: We register all the attributes that we want for a given package.
  If the package does not already exists it is created.
Step 2: We load the project into the projects hierarchy. We tell `Tree.Load`
  to check all packages otherwise it will not load any packages.
Step 3: We read attributes from the project. An attribute can be an
  `Attribute_Pkg_String` (representing a plain string) or an `Attribute_Pkg_List` (representing a list of strings).
Step 4: We can do something with those values. Here we print the plain string
  and the content of the list.

This program should output:

    Package_Name.String: some string
    Package_Name.Indexed ("Index"): hello world
    Package_Name.List:
      Value: hello
      Value: world