1 -- sarge.adb - Implementation file for the Sarge command line argument parser project.
11 -- 2019/04/10, Maya Posch
15 with Ada.Command_Line;
18 with Ada.Strings.Unbounded.Text_IO;
19 use Ada.Strings.Unbounded.Text_IO;
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);
30 if length(arg_short) > 0 then
31 argNames.include(arg_short, args.Last_Index);
34 if length(arg_long) > 0 then
35 argNames.include(arg_long, args.Last_Index);
41 --- SET DESCRIPTION ---
42 procedure setDescription(desc: in Unbounded_String) is
49 procedure setUsage(usage: in Unbounded_String) is
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;
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
70 args.Reference(argNames_map.Element(flag_it)).value := arg;
72 elsif Ada.Strings.Unbounded.Slice(arg, 1, 1) = "-" then
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");
86 flag_it := argNames.find(arg);
87 args(argNames_map.Element(flag_it)).parsed := True;
88 flagCounter := flagCounter + 1;
90 if args(argNames_map.Element(flag_it)).hasValue = True then
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.");
106 flag_it := argNames.find(short_arg);
109 args(argNames_map.Element(flag_it)).parsed := True;
110 flagCounter := flagCounter + 1;
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.");
122 Ada.Strings.Unbounded.Delete(short_arg, 1, 1);
126 -- Add to text argument vector.
127 textArguments.append(arg);
138 function getFlag(arg_flag: in Unbounded_String; arg_value: out Unbounded_String) return boolean is
139 flag_it: argNames_map.Cursor;
142 if parsed /= True then
146 flag_it := argNames.find(arg_flag);
147 if flag_it = argNames_map.No_Element then
149 elsif args(argNames_map.Element(flag_it)).parsed /= True then
153 if args(argNames_map.Element(flag_it)).hasValue = True then
154 arg_value := args(argNames_map.Element(flag_it)).value;
162 function exists(arg_flag: in Unbounded_String) return boolean is
163 flag_it: argNames_map.Cursor;
166 if parsed /= True then
170 flag_it := argNames.find(arg_flag);
171 if flag_it = argNames_map.No_Element then
173 elsif args(argNames_map.Element(flag_it)).parsed /= True then
181 --- GET TEXT ARGUMENT ---
182 function getTextArgument(index: in Integer; value: out Unbounded_String) return boolean is
184 if index < Integer(tArgVector.length(textArguments)) then
185 value := textArguments(index);
194 procedure printHelp is
199 put_line(description);
203 put_line("Options:");
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));
212 count := count + 3; -- Number of actual spaces between the longest arg_long and description.
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);
223 Ada.Strings.Unbounded.Text_IO.put_line("-" & args(opt).arg_short
224 & ", --" & args(opt).arg_long
225 & spaceCnt * " " & args(opt).description);
232 function flagCount return integer is
238 --- EXECUTABLE NAME ---
239 function executableName return Unbounded_String is