54 class CommandLine {
55 /**
56 * Process Win32-style command files for the specified command line
57 * arguments and return the resulting arguments. A command file argument
58 * is of the form '@file' where 'file' is the name of the file whose
59 * contents are to be parsed for additional arguments. The contents of
60 * the command file are parsed using StreamTokenizer and the original
61 * '@file' argument replaced with the resulting tokens. Recursive command
62 * files are not supported. The '@' character itself can be quoted with
63 * the sequence '@@'.
64 * @param args the arguments that may contain @files
65 * @return the arguments, with @files expanded
66 * @throws IOException if there is a problem reading any of the @files
67 */
68 public static String[] parse(String[] args) throws IOException {
69 List<String> newArgs = new ArrayList<>();
70 appendParsedCommandArgs(newArgs, Arrays.asList(args));
71 return newArgs.toArray(new String[newArgs.size()]);
72 }
73
74 private static void appendParsedCommandArgs(List<String> newArgs, List<String> args) throws IOException {
75 for (String arg : args) {
76 if (arg.length() > 1 && arg.charAt(0) == '@') {
77 arg = arg.substring(1);
78 if (arg.charAt(0) == '@') {
79 newArgs.add(arg);
80 } else {
81 loadCmdFile(arg, newArgs);
82 }
83 } else {
84 newArgs.add(arg);
85 }
86 }
87 }
88
89 private static void loadCmdFile(String name, List<String> args) throws IOException {
90 if (!Files.isReadable(Path.of(name))) {
91 throw new FileNotFoundException(name);
92 }
93 try (Reader r = Files.newBufferedReader(Paths.get(name), Charset.defaultCharset())) {
94 Tokenizer t = new Tokenizer(r);
95 String s;
96 while ((s = t.nextToken()) != null) {
97 args.add(s);
98 }
99 }
100 }
101
102 public static class Tokenizer {
103 private final Reader in;
104 private int ch;
105
106 public Tokenizer(Reader in) throws IOException {
107 this.in = in;
108 ch = in.read();
109 }
110
111 public String nextToken() throws IOException {
112 skipWhite();
113 if (ch == -1) {
132 case '\r':
133 return sb.toString();
134
135 case '\'':
136 case '"':
137 if (quoteChar == 0) {
138 quoteChar = (char) ch;
139 } else if (quoteChar == ch) {
140 quoteChar = 0;
141 } else {
142 sb.append((char) ch);
143 }
144 break;
145
146 case '\\':
147 if (quoteChar != 0) {
148 ch = in.read();
149 switch (ch) {
150 case '\n':
151 case '\r':
152 while (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f') {
153 ch = in.read();
154 }
155 continue;
156
157 case 'n':
158 ch = '\n';
159 break;
160 case 'r':
161 ch = '\r';
162 break;
163 case 't':
164 ch = '\t';
165 break;
166 case 'f':
167 ch = '\f';
168 break;
169 }
170 }
171 sb.append((char) ch);
172 break;
|
54 class CommandLine {
55 /**
56 * Process Win32-style command files for the specified command line
57 * arguments and return the resulting arguments. A command file argument
58 * is of the form '@file' where 'file' is the name of the file whose
59 * contents are to be parsed for additional arguments. The contents of
60 * the command file are parsed using StreamTokenizer and the original
61 * '@file' argument replaced with the resulting tokens. Recursive command
62 * files are not supported. The '@' character itself can be quoted with
63 * the sequence '@@'.
64 * @param args the arguments that may contain @files
65 * @return the arguments, with @files expanded
66 * @throws IOException if there is a problem reading any of the @files
67 */
68 public static String[] parse(String[] args) throws IOException {
69 List<String> newArgs = new ArrayList<>();
70 appendParsedCommandArgs(newArgs, Arrays.asList(args));
71 return newArgs.toArray(new String[newArgs.size()]);
72 }
73
74 private static void appendParsedCommandArgs(List<String> newArgs,
75 List<String> args) throws IOException {
76 for (String arg : args) {
77 if (arg.length() > 1 && arg.charAt(0) == '@') {
78 arg = arg.substring(1);
79 if (arg.charAt(0) == '@') {
80 newArgs.add(arg);
81 } else {
82 loadCmdFile(arg, newArgs);
83 }
84 } else {
85 newArgs.add(arg);
86 }
87 }
88 }
89
90 private static void loadCmdFile(String name, List<String> args)
91 throws IOException {
92 if (!Files.isReadable(Path.of(name))) {
93 throw new FileNotFoundException(name);
94 }
95 try (Reader r = Files.newBufferedReader(Paths.get(name),
96 Charset.defaultCharset())) {
97 Tokenizer t = new Tokenizer(r);
98 String s;
99 while ((s = t.nextToken()) != null) {
100 args.add(s);
101 }
102 }
103 }
104
105 public static class Tokenizer {
106 private final Reader in;
107 private int ch;
108
109 public Tokenizer(Reader in) throws IOException {
110 this.in = in;
111 ch = in.read();
112 }
113
114 public String nextToken() throws IOException {
115 skipWhite();
116 if (ch == -1) {
135 case '\r':
136 return sb.toString();
137
138 case '\'':
139 case '"':
140 if (quoteChar == 0) {
141 quoteChar = (char) ch;
142 } else if (quoteChar == ch) {
143 quoteChar = 0;
144 } else {
145 sb.append((char) ch);
146 }
147 break;
148
149 case '\\':
150 if (quoteChar != 0) {
151 ch = in.read();
152 switch (ch) {
153 case '\n':
154 case '\r':
155 while (ch == ' ' || ch == '\n'
156 || ch == '\r' || ch == '\t'
157 || ch == '\f') {
158 ch = in.read();
159 }
160 continue;
161
162 case 'n':
163 ch = '\n';
164 break;
165 case 'r':
166 ch = '\r';
167 break;
168 case 't':
169 ch = '\t';
170 break;
171 case 'f':
172 ch = '\f';
173 break;
174 }
175 }
176 sb.append((char) ch);
177 break;
|