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