cprover
ms_link_cmdline.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: A special command line object for LINK options
4 
5 Author: Daniel Kroening
6 
7 \*******************************************************************/
8 
11 
12 #include "ms_link_cmdline.h"
13 
14 #include <cstdlib>
15 #include <cstring>
16 #include <fstream>
17 #include <iostream>
18 
19 #include <util/unicode.h>
20 
24 const char *non_ms_link_options[]=
25 {
26  "--help",
27  "--verbosity"
28 };
29 
30 bool ms_link_cmdlinet::parse(const std::vector<std::string> &arguments)
31 {
32  for(std::size_t i = 0; i < arguments.size(); i++)
33  {
34  // is it a non-link option?
35  if(std::string(arguments[i], 0, 2) == "--")
36  {
37  process_non_link_option(arguments[i]);
38 
39  if(arguments[i] == "--verbosity")
40  {
41  if(i < arguments.size() - 1)
42  {
43  set(arguments[i], arguments[i + 1]);
44  i++; // skip ahead
45  }
46  }
47  }
48  else if(!arguments[i].empty() && arguments[i][0] == '@')
49  {
50  // potentially recursive
51  process_response_file(std::string(arguments[i], 1, std::string::npos));
52  }
53  else
54  process_link_option(arguments[i]);
55  }
56 
57  return false;
58 }
59 
63 bool ms_link_cmdlinet::parse(int argc, const char **argv)
64 {
65  // should really use "wide" argv from wmain()
66 
67  std::vector<std::string> arguments;
68 
69  // skip argv[0]
70  for(int i = 1; i < argc; i++)
71  arguments.push_back(argv[i]);
72 
73  return parse(arguments);
74 }
75 
76 static std::istream &my_wgetline(std::istream &in, std::wstring &dest)
77 {
78  // We should support this properly,
79  // but will just strip right now.
80  dest.clear();
81 
82  while(in)
83  {
84  char ch1, ch2;
85  in.get(ch1);
86  in.get(ch2);
87 
88  if(!in)
89  {
90  if(!dest.empty())
91  in.clear();
92  break;
93  }
94 
95  if(ch1 == '\r')
96  {
97  // ignore
98  }
99  else if(ch1 == '\n')
100  {
101  in.clear();
102  break; // line end
103  }
104  else
105  dest += wchar_t(ch1 + (ch2 << 8));
106  }
107 
108  return in;
109 }
110 
113 {
114  std::ifstream infile(file);
115 
116  if(!infile)
117  {
118  std::cerr << "failed to open response file '" << file << "'\n";
119  return;
120  }
121 
122  // these may be Unicode -- which is indicated by 0xff 0xfe
123  std::string line;
124  getline(infile, line);
125  if(
126  line.size() >= 2 && line[0] == static_cast<char>(0xff) &&
127  line[1] == static_cast<char>(0xfe))
128  {
129  // Unicode, UTF-16 little endian
130 
131 #if 1
132  // Re-open -- should be using wifstream,
133  // but this isn't available everywhere.
134  std::ifstream infile2(file, std::ios::binary);
135  infile2.seekg(2);
136  std::wstring wline;
137 
138  while(my_wgetline(infile2, wline))
139  process_response_file_line(narrow(wline)); // we UTF-8 it
140 
141 #else
142 
143  std::wifstream infile2(file, std::ios::binary);
144  std::wstring wline;
145 
146  while(std::getline(infile2, wline))
147  process_response_file_line(narrow(wline)); // we UTF-8 it
148 
149 #endif
150  }
151  else if(
152  line.size() >= 3 && line[0] == static_cast<char>(0xef) &&
153  line[1] == static_cast<char>(0xbb) && line[2] == static_cast<char>(0xbf))
154  {
155  // This is the UTF-8 BOM. We can proceed as usual, since
156  // we use UTF-8 internally.
157  infile.seekg(3);
158 
159  while(getline(infile, line))
161  }
162  else
163  {
164  // normal ASCII
165  infile.seekg(0);
166  while(getline(infile, line))
168  }
169 }
170 
172 void ms_link_cmdlinet::process_response_file_line(const std::string &line)
173 {
174  // In a response file, multiple compiler options and source-code files can
175  // appear on one line. A single compiler-option specification must appear
176  // on one line (cannot span multiple lines). Response files can have
177  // comments that begin with the # symbol.
178 
179  if(line.empty())
180  return;
181  if(line[0] == '#')
182  return; // comment
183 
184  std::vector<std::string> arguments;
185  std::string option;
186  bool in_quotes = false;
187  for(std::size_t i = 0; i < line.size(); i++)
188  {
189  char ch = line[i];
190 
191  if(ch == ' ' && !in_quotes)
192  {
193  if(!option.empty())
194  arguments.push_back(option);
195  option.clear();
196  }
197  else if(ch == '"')
198  {
199  in_quotes = !in_quotes;
200  }
201  else
202  option += ch;
203  }
204 
205  if(!option.empty())
206  arguments.push_back(option);
207 
208  parse(arguments);
209 }
210 
213 {
214  set(s);
215 
216  for(const auto & opt : non_ms_link_options)
217  if(s == opt)
218  return;
219 
220  // unrecognized option
221  std::cout << "Warning: uninterpreted non-LINK option '" << s << "'\n";
222 }
223 
224 const char *ms_link_options[] = {
225  "ALIGN",
226  "ALLOWBIND",
227  "ALLOWISOLATION",
228  "APPCONTAINER",
229  "ASSEMBLYDEBUG",
230  "ASSEMBLYLINKRESOURCE",
231  "ASSEMBLYMODULE",
232  "ASSEMBLYRESOURCE",
233  "BASE",
234  "CLRIMAGETYPE",
235  "CLRLOADEROPTIMIZATION",
236  "CLRSUPPORTLASTERROR",
237  "CLRTHREADATTRIBUTE",
238  "CLRUNMANAGEDCODECHECK",
239  "DEBUG",
240  "DEF",
241  "DEFAULTLIB",
242  "DELAY",
243  "DELAYLOAD",
244  "DELAYSIGN",
245  "DLL",
246  "DRIVER",
247  "DYNAMICBASE",
248  "ENTRY",
249  "ERRORREPORT",
250  "EXPORT",
251  "EXPORTPADMIN",
252  "FASTGENPROFILE",
253  "FIXED",
254  "FORCE",
255  "FUNCTIONPADMIN",
256  "GUARD",
257  "GENPROFILE",
258  "HEAP",
259  "HIGHENTROPYVA",
260  "IDLOUT",
261  "IGNORE",
262  "IGNOREIDL",
263  "IMPLIB",
264  "INCLUDE",
265  "INCREMENTAL",
266  "INTEGRITYCHECK",
267  "KERNEL",
268  "KEYCONTAINER",
269  "KEYFILE",
270  "LARGEADDRESSAWARE",
271  "LIBPATH",
272  "LTCG",
273  "MACHINE",
274  "MANIFEST",
275  "MANIFESTDEPENDENCY",
276  "MANIFESTFILE",
277  "MANIFESTINPUT",
278  "MANIFESTUAC",
279  "MAP",
280  "MAPINFO",
281  "MERGE",
282  "MIDL",
283  "NOASSEMBLY",
284  "NODEFAULTLIB",
285  "NOENTRY",
286  "NOIMPLIB",
287  "NOLOGO",
288  "NXCOMPAT",
289  "OPT",
290  "ORDER",
291  "OUT",
292  "PDB",
293  "PDBSTRIPPED",
294  "PROFILE",
295  "RELEASE",
296  "SAFESEH",
297  "SECTION",
298  "STACK",
299  "STUB",
300  "SUBSYSTEM",
301  "SWAPRUN",
302  "TLBID",
303  "TLBOUT",
304  "TIME",
305  "TSAWARE",
306  "USEPROFILE",
307  "VERBOSE",
308  "VERSION",
309  "WINMD",
310  "WINMDDELAYSIGN",
311  "WINMDFILE",
312  "WINMDKEYCONTAINER",
313  "WINMDKEYFILE",
314  "WHOLEARCHIVE",
315  "WX"
316 };
317 
318 static std::string to_upper_string(const std::string &s)
319 {
320  std::string result = s;
321  transform(result.begin(), result.end(), result.begin(), toupper);
322  return result;
323 }
324 
325 void ms_link_cmdlinet::process_link_option(const std::string &s)
326 {
327  if(s.empty())
328  return;
329 
330  if(s[0] != '/' && s[0] != '-')
331  {
332  args.push_back(s);
333  return;
334  }
335 
336  for(const std::string ms_link_option : ms_link_options)
337  {
338  // These are case insensitive.
339  if(
340  to_upper_string(std::string(s, 1, std::string::npos)) == ms_link_option ||
341  to_upper_string(std::string(s, 1, ms_link_option.size() + 1)) == ms_link_option + ':')
342  {
343  optionalt<std::size_t> optnr = getoptnr(ms_link_option);
344 
345  if(!optnr.has_value())
346  {
347  cmdlinet::optiont option;
348  option.islong = true;
349  option.optstring = ms_link_option;
350  option.optchar = 0;
351  options.push_back(option);
352  optnr = options.size() - 1;
353  }
354 
355  options[*optnr].isset = true;
356 
357  if(s.size() > ms_link_option.size() + 1)
358  options[*optnr].values.push_back(
359  std::string(s, ms_link_option.size() + 2, std::string::npos));
360 
361  return;
362  }
363  }
364 
365  // unrecognized option
366  std::cout << "Warning: uninterpreted LINK option '" << s << "'\n";
367 }
argst args
Definition: cmdline.h:143
optionalt< std::size_t > getoptnr(char option) const
Definition: cmdline.cpp:136
std::vector< optiont > options
Definition: cmdline.h:182
void set(const std::string &opt, const char *value) override
Set option option to value.
virtual bool parse(int argc, const char **argv, const char *optstring)
Parses a commandline according to a specification given in optstring.
Definition: cmdline.cpp:154
static std::string binary(const constant_exprt &src)
Definition: json_expr.cpp:205
output_type narrow(input_type input)
Run-time checked narrowing cast.
Definition: narrow.h:34
nonstd::optional< T > optionalt
Definition: optional.h:35
std::string optstring
Definition: cmdline.h:159
Definition: kdev_t.h:19