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