JAL-629 Fix non-multi string bootstrap arg bug.
[jalview.git] / src / jalview / bin / argparser / BootstrapArgs.java
1 package jalview.bin.argparser;
2
3 import java.io.File;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11
12 import jalview.bin.argparser.Arg.Opt;
13 import jalview.util.FileUtils;
14
15 public class BootstrapArgs
16 {
17   // only need one
18   private Map<Arg, List<String>> bootstrapArgMap = new HashMap<>();
19
20   private Set<File> argFiles = new HashSet<>();
21
22   public static BootstrapArgs getBootstrapArgs(String[] args)
23   {
24     List<String> argList = new ArrayList<>(Arrays.asList(args));
25     return new BootstrapArgs(argList);
26   }
27
28   private BootstrapArgs(List<String> args)
29   {
30     parse(args, null);
31   }
32
33   private void parse(List<String> args, File inArgFile)
34   {
35     if (args == null)
36       return;
37     // avoid looping argFiles
38     if (inArgFile != null)
39     {
40       if (argFiles.contains(inArgFile))
41       {
42         System.err.println(
43                 "Looped argfiles detected: '" + inArgFile.getPath() + "'");
44         return;
45       }
46       argFiles.add(inArgFile);
47     }
48
49     for (int i = 0; i < args.size(); i++)
50     {
51       String arg = args.get(i);
52       String argName = null;
53       String val = null;
54       if (arg.startsWith(ArgParser.DOUBLEDASH))
55       {
56         // remove "--"
57         arg = arg.substring(ArgParser.DOUBLEDASH.length());
58         int equalPos = arg.indexOf(ArgParser.EQUALS);
59         if (equalPos > -1
60                 && ArgParser.argMap.containsKey(arg.substring(0, equalPos)))
61         {
62           argName = arg.substring(0, equalPos);
63           val = arg.substring(equalPos + 1);
64         }
65         // check for boolean prepended by "no"
66         else if (arg.startsWith(ArgParser.NEGATESTRING)
67                 && ArgParser.argMap.containsKey(
68                         arg.substring(ArgParser.NEGATESTRING.length())))
69         {
70           argName = arg.substring(ArgParser.NEGATESTRING.length());
71           val = "false";
72         }
73         else if (ArgParser.argMap.containsKey(arg))
74         {
75           argName = arg;
76           val = "true";
77         }
78
79         Arg a = ArgParser.argMap.get(argName);
80
81         if (a == null || !a.hasOption(Opt.BOOTSTRAP))
82         {
83           // not a valid bootstrap arg
84           continue;
85         }
86
87         if (a.hasOption(Opt.STRING))
88         {
89           List<String> vals = null;
90           if (equalPos == -1)
91           {
92             vals = ArgParser.getShellGlobbedFilenameValues(a, args, i + 1);
93           }
94           else
95           {
96             if (a.hasOption(Opt.GLOB))
97             {
98               vals = FileUtils.getFilenamesFromGlob(val);
99             }
100             else
101             {
102               vals = new ArrayList<>();
103               vals.add(val);
104             }
105           }
106           addAll(a, vals);
107
108           if (a == Arg.ARGFILE)
109           {
110             for (String filename : vals)
111             {
112               File argFile = new File(filename);
113               parse(ArgParser.readArgFile(argFile), argFile);
114             }
115           }
116         }
117         else
118         {
119           add(a, val);
120         }
121       }
122     }
123   }
124
125   public boolean contains(Arg a)
126   {
127     return bootstrapArgMap.containsKey(a);
128   }
129
130   public List<String> getList(Arg a)
131   {
132     return bootstrapArgMap.get(a);
133   }
134
135   private List<String> getOrCreateList(Arg a)
136   {
137     List<String> l = getList(a);
138     if (l == null)
139     {
140       l = new ArrayList<>();
141       putList(a, l);
142     }
143     return l;
144   }
145
146   private void putList(Arg a, List<String> l)
147   {
148     bootstrapArgMap.put(a, l);
149   }
150
151   /*
152    * Creates a new list if not used before,
153    * adds the value unless the existing list is non-empty
154    * and the arg is not MULTI (so first expressed value is
155    * retained).
156    */
157   private void add(Arg a, String s)
158   {
159     List<String> l = getOrCreateList(a);
160     if (a.hasOption(Opt.MULTI) || l.size() == 0)
161     {
162       l.add(s);
163     }
164   }
165
166   private void addAll(Arg a, List<String> al)
167   {
168     List<String> l = getOrCreateList(a);
169     if (a.hasOption(Opt.MULTI))
170     {
171       l.addAll(al);
172     }
173     else if (l.size() == 0 && al.size() > 0)
174     {
175       l.add(al.get(0));
176     }
177   }
178
179   /*
180    * Retrieves the first value even if MULTI.
181    * A convenience for non-MULTI args.
182    */
183   public String get(Arg a)
184   {
185     if (!bootstrapArgMap.containsKey(a))
186       return null;
187     List<String> aL = bootstrapArgMap.get(a);
188     return (aL == null || aL.size() == 0) ? null : aL.get(0);
189   }
190
191   public boolean getBoolean(Arg a, boolean d)
192   {
193     if (!bootstrapArgMap.containsKey(a))
194       return d;
195     return Boolean.parseBoolean(get(a));
196   }
197
198   public boolean getBoolean(Arg a)
199   {
200     if (!(a.hasOption(Opt.BOOLEAN) || a.hasOption(Opt.UNARY)))
201     {
202       return false;
203     }
204     if (bootstrapArgMap.containsKey(a))
205       return Boolean.parseBoolean(get(a));
206     else
207       return a.getDefaultBoolValue();
208   }
209 }