]> git.armaanb.net Git - gen-shell.git/blob - src/Sarge/ada/src/sarge.adb
added argument parsing with Sarge
[gen-shell.git] / src / Sarge / ada / src / sarge.adb
1 --      sarge.adb - Implementation file for the Sarge command line argument parser project.
2         
3 --      Revision 0
4         
5 --      Features:
6 --                      - 
7         
8 --      Notes:
9 --                      -
10                          
11 --      2019/04/10, Maya Posch
12
13
14
15 with Ada.Command_Line;
16 with Ada.Text_IO;
17 use Ada.Text_IO;
18 with Ada.Strings.Unbounded.Text_IO;
19 use Ada.Strings.Unbounded.Text_IO;
20
21
22 package body Sarge is
23     --- SET ARGUMENT ---
24     procedure setArgument(arg_short: in Unbounded_String; arg_long: in Unbounded_String; desc: in Unbounded_String; hasVal: in boolean) is
25         arg: aliased Argument := (arg_short => arg_short, arg_long => arg_long, description => desc, hasValue => hasVal, value => +"", parsed => False);
26     begin
27         args.append(arg);
28                 
29         -- Set up links.
30         if length(arg_short) > 0 then
31             argNames.include(arg_short, args.Last_Index);
32         end if;
33                 
34         if length(arg_long) > 0 then
35             argNames.include(arg_long, args.Last_Index);
36         end if;
37                 
38     end setArgument;
39         
40         
41     --- SET DESCRIPTION ---
42     procedure setDescription(desc: in Unbounded_String) is
43     begin
44         description := desc;
45     end setDescription;
46         
47         
48     --- SET USAGE ---
49     procedure setUsage(usage: in Unbounded_String) is
50     begin
51         usageStr := usage;
52     end setUsage;
53         
54         
55     --- PARSE ARGUMENTS ---
56     function parseArguments return boolean is
57         flag_it: argNames_map.Cursor;
58         expectValue: boolean := False;
59         arg: Unbounded_String;
60         short_arg: Unbounded_String;
61     begin
62         -- 
63         execName := +Ada.Command_Line.command_name;
64         for arg_i in 1..Ada.Command_Line.argument_count loop
65             arg := +Ada.Command_Line.Argument(arg_i);
66             -- Each flag will start with a '-' character. Multiple flags can be joined together in
67             -- the same string if they're the short form flag type (one character per flag).
68             if expectValue = True then
69                 -- Copy value.
70                 args.Reference(argNames_map.Element(flag_it)).value := arg;             
71                 expectValue := False;
72             elsif Ada.Strings.Unbounded.Slice(arg, 1, 1) = "-" then
73                 -- Parse flag.
74                 -- First check for the long form.
75                 if Ada.Strings.Unbounded.Slice(arg, 1, 2) = "--" then
76                     -- Long form of the flag.
77                     -- First delete the preceding dashes.
78                     arg := Ada.Strings.Unbounded.Delete(arg, 1, 2);
79                     if not argNames.contains(arg) then
80                         -- Flag wasn't found. Abort.
81                         Ada.Strings.Unbounded.Text_IO.put_line("Long flag " & arg & " wasn't found");
82                         return False;
83                     end if;
84                                         
85                     -- Mark as found.
86                     flag_it := argNames.find(arg);
87                     args(argNames_map.Element(flag_it)).parsed := True;
88                     flagCounter := flagCounter + 1;
89                                         
90                     if args(argNames_map.Element(flag_it)).hasValue = True then
91                         expectValue := True;
92                     end if;
93                 else
94                     -- Parse short form flag. Parse all of them sequentially. Only the last one
95                     -- is allowed to have an additional value following it.
96                     -- First delete the preceding dash.
97                     arg := Ada.Strings.Unbounded.Delete(arg, 1, 1);
98                     for i in 1 .. Ada.Strings.Unbounded.Length(arg) loop
99                         Ada.Strings.Unbounded.Append(short_arg, Ada.Strings.Unbounded.Element(arg, i));
100                         if argNames_map.Contains(argNames, short_arg) /= True then
101                             -- Flag wasn't found. Abort.
102                             put_line("Short flag " & short_arg & " wasn't found.");
103                             return False;
104                         end if;
105                         
106                         flag_it := argNames.find(short_arg);
107                                                         
108                         -- Mark as found.
109                         args(argNames_map.Element(flag_it)).parsed := True;
110                         flagCounter := flagCounter + 1;
111                                                         
112                         if args(argNames_map.Element(flag_it)).hasValue = True then
113                             if i /= (Ada.Strings.Unbounded.Length(arg)) then
114                                 -- Flag isn't at end, thus cannot have value.
115                                 put_line("Flag " & short_arg & " needs to be followed by a value string.");
116                                 return False;
117                             else
118                                 expectValue := True;
119                             end if;
120                         end if;
121                         
122                         Ada.Strings.Unbounded.Delete(short_arg, 1, 1);
123                     end loop;
124                 end if; 
125             else
126                         -- Add to text argument vector.
127                         textArguments.append(arg);
128             end if;
129         end loop;
130                 
131         parsed := True;
132                 
133         return True;
134     end parseArguments;
135         
136         
137     --- GET FLAG ---
138     function getFlag(arg_flag: in Unbounded_String; arg_value: out Unbounded_String) return boolean is
139         flag_it: argNames_map.Cursor;
140         use argNames_map;
141     begin
142         if parsed /= True then
143             return False;
144         end if;
145                 
146         flag_it := argNames.find(arg_flag);
147         if flag_it = argNames_map.No_Element then
148             return False;
149         elsif args(argNames_map.Element(flag_it)).parsed /= True then
150             return False;
151         end if;
152                 
153         if args(argNames_map.Element(flag_it)).hasValue = True then
154             arg_value := args(argNames_map.Element(flag_it)).value;
155         end if;
156                 
157         return True;
158     end getFlag;
159         
160         
161     --- EXISTS ---
162     function exists(arg_flag: in Unbounded_String) return boolean is
163         flag_it: argNames_map.Cursor;
164         use argNames_map;
165     begin
166         if parsed /= True then
167             return False;
168         end if;
169                 
170         flag_it := argNames.find(arg_flag);
171         if flag_it = argNames_map.No_Element then
172             return False;
173         elsif args(argNames_map.Element(flag_it)).parsed /= True then
174                 return False;
175         end if;
176                 
177         return True;
178     end exists;
179         
180         
181         --- GET TEXT ARGUMENT ---
182         function getTextArgument(index: in Integer; value: out Unbounded_String) return boolean is
183         begin
184                 if index < Integer(tArgVector.length(textArguments)) then
185                         value := textArguments(index);
186                         return True;
187                 end if;
188                 
189                 return False;
190         end getTextArgument;
191         
192         
193     --- PRINT HELP ---
194     procedure printHelp is
195         count: Integer := 1;
196         spaceCnt: Integer;
197     begin
198         put_line("");
199         put_line(description);
200         put_line("Usage:");
201         put_line(usageStr);
202         put_line("");
203         put_line("Options:");
204         
205         -- Determine whitespace needed between arg_long and description.
206         for flag in args.Iterate loop
207                 if Integer(Ada.Strings.Unbounded.length(args(flag).arg_long)) > count then
208                         count := Integer(Ada.Strings.Unbounded.length(args(flag).arg_long));
209                 end if;
210         end loop;
211         
212         count := count + 3; -- Number of actual spaces between the longest arg_long and description.
213                 
214         -- Print out the options.
215         for opt in args.Iterate loop
216                 --spaceStr := Unbound_String(count - Ada.Strings.Unbounded.length(args(opt).arg_long)
217                 spaceCnt := (count - Integer(Ada.Strings.Unbounded.length(args(opt).arg_long)));
218                 if Ada.Strings.Unbounded.length(args(opt).arg_short) < 1 then
219                         Ada.Strings.Unbounded.Text_IO.put_line("    " & args(opt).arg_short 
220                                             & "--" & args(opt).arg_long 
221                                             & spaceCnt * " " & args(opt).description);
222                 else
223                         Ada.Strings.Unbounded.Text_IO.put_line("-" & args(opt).arg_short 
224                                             & ", --" & args(opt).arg_long 
225                                             & spaceCnt * " " & args(opt).description);
226                 end if;
227         end loop;
228     end printHelp;
229         
230         
231     --- FLAG COUNT ---
232     function flagCount return integer is
233     begin
234         return flagCounter;
235     end flagCount;
236         
237         
238     --- EXECUTABLE NAME ---
239     function executableName return Unbounded_String is
240     begin
241         return execName;
242     end executableName;
243 end Sarge;
244