CBMC
ms_cl_cmdline.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: A special command line object for the CL options
4 
5 Author: Daniel Kroening
6 
7 \*******************************************************************/
8 
11 
12 #include "ms_cl_cmdline.h"
13 
14 #include <util/unicode.h>
15 
16 #include <climits>
17 #include <cstdlib>
18 #include <fstream> // IWYU pragma: keep
19 #include <iostream>
20 
24 // clang-format off
25 const char *non_ms_cl_options[]=
26 {
27  "--show-symbol-table",
28  "--show-function-table",
29  "--ppc-macos",
30  "--i386-linux",
31  "--i386-win32",
32  "--i386-macos",
33  "--string-abstraction",
34  "--no-library",
35  "--16",
36  "--32",
37  "--64",
38  "--little-endian",
39  "--big-endian",
40  "--unsigned-char",
41  "--help",
42  "--xml",
43  "--partial-inlining",
44  "--verbosity",
45  "--function",
46  "--validate-goto-model",
47  "--export-file-local-symbols",
48  "--mangle-suffix",
49  nullptr
50 };
51 // clang-format on
52 
53 bool ms_cl_cmdlinet::parse(const std::vector<std::string> &arguments)
54 {
55  for(std::size_t i = 0; i < arguments.size(); i++)
56  {
57  // is it a non-cl option?
58  if(std::string(arguments[i], 0, 2) == "--")
59  {
60  process_non_cl_option(arguments[i]);
61 
62  if(
63  arguments[i] == "--verbosity" || arguments[i] == "--function" ||
64  arguments[i] == "--mangle-suffix")
65  {
66  if(i < arguments.size() - 1)
67  {
68  set(arguments[i], arguments[i + 1]);
69  i++; // skip ahead
70  }
71  }
72  }
73  else if(!arguments[i].empty() && arguments[i][0] == '@')
74  {
75  // potentially recursive
76  process_response_file(std::string(arguments[i], 1, std::string::npos));
77  }
78  else if(arguments[i] == "/link" || arguments[i] == "-link")
79  {
80  // anything that follows goes to the linker
81  i = arguments.size() - 1;
82  }
83  else if(
84  arguments[i].size() == 2 &&
85  (arguments[i] == "/D" || arguments[i] == "-D") &&
86  i != arguments.size() - 1)
87  {
88  // this requires special treatment, as you can do "/D something"
89  std::string tmp = "/D" + arguments[i + 1];
90  i++;
91  process_cl_option(tmp);
92  }
93  else
94  process_cl_option(arguments[i]);
95  }
96 
97  return false;
98 }
99 
101 {
102  // first do environment
103 
104  #ifdef _WIN32
105 
106  const wchar_t *CL_env=_wgetenv(L"CL");
107 
108  if(CL_env!=NULL)
110 
111  #else
112 
113  const char *CL_env=getenv("CL");
114 
115  if(CL_env!=nullptr)
117 
118  #endif
119 }
120 
124 bool ms_cl_cmdlinet::parse(int argc, const char **argv)
125 {
126  // should really use "wide" argv from wmain()
127 
128  std::vector<std::string> arguments;
129 
130  // skip argv[0]
131  for(int i=1; i<argc; i++)
132  arguments.push_back(argv[i]);
133 
134  return parse(arguments);
135 }
136 
137 static std::istream &my_wgetline(std::istream &in, std::wstring &dest)
138 {
139  // We should support this properly,
140  // but will just strip right now.
141  dest.clear();
142 
143  while(in)
144  {
145  char ch1, ch2;
146  in.get(ch1);
147  in.get(ch2);
148 
149  if(!in)
150  {
151  if(!dest.empty())
152  in.clear();
153  break;
154  }
155 
156  if(ch1=='\r')
157  {
158  // ignore
159  }
160  else if(ch1=='\n')
161  {
162  in.clear();
163  break; // line end
164  }
165  else
166  dest += wchar_t(ch1 + (ch2 << CHAR_BIT));
167  }
168 
169  return in;
170 }
171 
172 void ms_cl_cmdlinet::process_response_file(const std::string &file)
173 {
174  std::ifstream infile(file);
175 
176  if(!infile)
177  {
178  std::cerr << "failed to open response file '" << file << "'\n";
179  return;
180  }
181 
182  // these may be Unicode -- which is indicated by 0xff 0xfe
183  std::string line;
184  getline(infile, line);
185  if(line.size()>=2 &&
186  line[0]==static_cast<char>(0xff) &&
187  line[1]==static_cast<char>(0xfe))
188  {
189  // Unicode, UTF-16 little endian
190 
191  #if 1
192  // Re-open -- should be using wifstream,
193  // but this isn't available everywhere.
194  std::ifstream infile2(file, std::ios::binary);
195  infile2.seekg(2);
196  std::wstring wline;
197 
198  while(my_wgetline(infile2, wline))
199  process_response_file_line(narrow(wline)); // we UTF-8 it
200 
201  #else
202 
203  std::wifstream infile2(file, std::ios::binary);
204  std::wstring wline;
205 
206  while(std::getline(infile2, wline))
207  process_response_file_line(narrow(wline)); // we UTF-8 it
208 
209  #endif
210  }
211  else if(line.size()>=3 &&
212  line[0]==static_cast<char>(0xef) &&
213  line[1]==static_cast<char>(0xbb) &&
214  line[2]==static_cast<char>(0xbf))
215  {
216  // This is the UTF-8 BOM. We can proceed as usual, since
217  // we use UTF-8 internally.
218  infile.seekg(3);
219 
220  while(getline(infile, line))
222  }
223  else
224  {
225  // normal ASCII
226  infile.seekg(0);
227  while(getline(infile, line))
229  }
230 }
231 
232 void ms_cl_cmdlinet::process_response_file_line(const std::string &line)
233 {
234  // In a response file, multiple compiler options and source-code files can
235  // appear on one line. A single compiler-option specification must appear
236  // on one line (cannot span multiple lines). Response files can have
237  // comments that begin with the # symbol.
238 
239  if(line.empty())
240  return;
241  if(line[0]=='#')
242  return; // comment
243 
244  std::vector<std::string> arguments;
245  std::string option;
246  bool in_quotes=false;
247  for(std::size_t i=0; i<line.size(); i++)
248  {
249  char ch=line[i];
250 
251  if(ch==' ' && !in_quotes)
252  {
253  if(!option.empty())
254  arguments.push_back(option);
255  option.clear();
256  }
257  else if(ch=='"')
258  {
259  in_quotes=!in_quotes;
260  }
261  else
262  option+=ch;
263  }
264 
265  if(!option.empty())
266  arguments.push_back(option);
267 
268  parse(arguments);
269 }
270 
272  const std::string &s)
273 {
274  set(s);
275 
276  for(unsigned j=0; non_ms_cl_options[j]!=nullptr; j++)
277  if(s==non_ms_cl_options[j])
278  return;
279 
280  // unrecognized option
281  std::cout << "Warning: uninterpreted non-CL option '" << s << "'\n";
282 }
283 
285 const char *ms_cl_flags[]=
286 {
287  "c", // compile only
288  nullptr
289 };
290 
291 const char *ms_cl_prefixes[]=
292 {
293  "O1", // minimize space
294  "O2", // maximize speed
295  "Ob", // <n> inline expansion (default n=0)
296  "Od", // disable optimizations (default)
297  "Og", // enable global optimization
298  "Oi", // [-] enable intrinsic functions
299  "Os", // favor code space
300  "Ot", // favor code speed
301  "Ox", // maximum optimizations
302  "Oy", // [-] enable frame pointer omission
303  "GF", // enable read-only string pooling
304  "Gm", // [-] enable minimal rebuild
305  "Gy", // [-] separate functions for linker
306  "GS", // [-] enable security checks
307  "GR", // [-] enable C++ RTTI
308  "GX", // [-] enable C++ EH (same as /EHsc)
309  "EHs", // enable C++ EH (no SEH exceptions)
310  "EHa", // enable C++ EH (w/ SEH exceptions)
311  "EHc", // extern "C" defaults to nothrow
312  "fp", // floating-point model
313  "GL", // [-] enable link-time code generation
314  "GA", // optimize for Windows Application
315  "Ge", // force stack checking for all funcs
316  "Gs", // [num] control stack checking calls
317  "Gh", // enable _penter function call
318  "GH", // enable _pexit function call
319  "GT", // generate fiber-safe TLS accesses
320  "RTC1", // Enable fast checks (/RTCsu)
321  "RTCc", // Convert to smaller type checks
322  "RTCs", // Stack Frame runtime checking
323  "RTCu", // Uninitialized local usage checks
324  "clr", // compile for common language runtime
325  "Gd", // __cdecl calling convention
326  "Gr", // __fastcall calling convention
327  "Gz", // __stdcall calling convention
328  "GZ", // Enable stack checks (/RTCs)
329  "QIfist", // [-] use FIST instead of ftol()
330  "hotpatch", // ensure function padding for hotpatchable images
331  "arch:", // <SSE|SSE2> minimum CPU architecture requirements
332  "Fa", // [file] name assembly listing file
333  "FA", // [scu] configure assembly listing
334  "Fd", // [file] name .PDB file
335  "Fe", // <file> name executable file
336  "Fm", // [file] name map file
337  "Fo", // <file> name object file
338  "Fp", // <file> name precompiled header file
339  "Fr", // [file] name source browser file
340  "FR", // [file] name extended .SBR file
341  "doc", // [file] process XML documentation comments
342  "AI", // <dir> add to assembly search path
343  "FU", // <file> forced using assembly/module
344  "C", // don't strip comments
345  "D", // <name>{=|#}<text> define macro
346  "E", // preprocess to stdout
347  "EP", // preprocess to stdout, no #line
348  "P", // preprocess to file
349  "Fx", // merge injected code to file
350  "FI", // <file> name forced include file
351  "U", // <name> remove predefined macro
352  "u", // remove all predefined macros
353  "I", // <dir> add to include search path
354  "X", // ignore "standard places"
355  "Zi", // enable debugging information
356  "Z7", // enable old-style debug info
357  "Zp", // [n] pack structs on n-byte boundary
358  "Za", // disable extensions
359  "Ze", // enable extensions (default)
360  "Zl", // omit default library name in .OBJ
361  "Zg", // generate function prototypes
362  "Zs", // syntax check only
363  "vd", // {0|1|2} disable/enable vtordisp
364  "vm", // <x> type of pointers to members
365  "Zc:", // arg1[,arg2] C++ language conformance, where arguments can be:
366  "ZI", // enable Edit and Continue debug info
367  "openmp", // enable OpenMP 2.0 language extensions
368  "analyze",
369  "errorReport",
370  "?",
371  "help", // print this help message
372  "FC", // use full pathnames in diagnostics /H<num> max external name length
373  "J", // default char type is unsigned
374  "nologo", // suppress copyright message
375  "show", // Includes show include file names
376  "Tc", // <source file> compile file as .c
377  "Tp", // <source file> compile file as .cpp
378  "TC", // compile all files as .c
379  "TP", // compile all files as .cpp
380  "V", // <string> set version string
381  "w", // disable all warnings
382  "wd", // <n> disable warning n
383  "we", // <n> treat warning n as an error
384  "wo", // <n> issue warning n once
385  "w", // <l><n> set warning level 1-4 for n
386  "W", // <n> set warning level (default n=1)
387  "Wall", // enable all warnings
388  "WL", // enable one line diagnostics
389  "WX", // treat warnings as errors
390  "Yc", // [file] create .PCH file
391  "Yd", // put debug info in every .OBJ
392  "Yl", // [sym] inject .PCH ref for debug lib
393  "Yu", // [file] use .PCH file
394  "Y", // - disable all PCH options
395  "Zm", // <n> max memory alloc (% of default)
396  "Wp64", // enable 64 bit porting warnings
397  "LD", // Create .DLL
398  "LDd", // Create .DLL debug library
399  "LN", // Create a .netmodule
400  "F", // <num> set stack size
401  "link", // [linker options and libraries]
402  "MD", // link with MSVCRT.LIB
403  "MT", // link with LIBCMT.LIB
404  "MDd", // link with MSVCRTD.LIB debug lib
405  "MTd", // link with LIBCMTD.LIB debug lib
406  "std", // specify C++ language standard
407  "sdl", // Enable Additional Security Checks
408  "diagnostics", // unknown
409  nullptr
410 };
411 
412 void ms_cl_cmdlinet::process_cl_option(const std::string &s)
413 {
414  if(s.empty())
415  return;
416 
417  if(s[0]!='/' && s[0]!='-')
418  {
419  args.push_back(s);
420  return;
421  }
422 
423  for(std::size_t j=0; ms_cl_flags[j]!=nullptr; j++)
424  {
425  if(std::string(s, 1, std::string::npos)==ms_cl_flags[j])
426  {
427  cmdlinet::optiont option;
428  std::optional<std::size_t> optnr;
429 
430  if(s.size()==2)
431  {
432  option.islong=false;
433  option.optstring.clear();
434  option.optchar=s[1];
435  optnr=getoptnr(option.optchar);
436  }
437  else
438  {
439  option.islong=true;
440  option.optstring=std::string(s, 1, std::string::npos);
441  option.optchar=0;
442  optnr=getoptnr(option.optstring);
443  }
444 
445  if(!optnr.has_value())
446  {
447  options.push_back(option);
448  optnr=options.size()-1;
449  }
450 
451  options[*optnr].isset=true;
452  return;
453  }
454  }
455 
456  for(std::size_t j=0; ms_cl_prefixes[j]!=nullptr; j++)
457  {
458  std::string ms_cl_prefix=ms_cl_prefixes[j];
459 
460  if(std::string(s, 1, ms_cl_prefix.size())==ms_cl_prefix)
461  {
462  cmdlinet::optiont option;
463 
464  std::optional<std::size_t> optnr;
465 
466  if(ms_cl_prefix.size()==1)
467  {
468  option.islong=false;
469  option.optstring.clear();
470  option.optchar=ms_cl_prefix[0];
471  optnr=getoptnr(option.optchar);
472  }
473  else
474  {
475  option.islong=true;
476  option.optstring=ms_cl_prefix;
477  option.optchar=0;
478  optnr=getoptnr(option.optstring);
479  }
480 
481  if(!optnr.has_value())
482  {
483  options.push_back(option);
484  optnr=options.size()-1;
485  }
486 
487  options[*optnr].isset=true;
488  options[*optnr].values.push_back(
489  std::string(s, ms_cl_prefix.size()+1, std::string::npos));
490 
491  return;
492  }
493  }
494 
495  // unrecognized option
496  std::cout << "Warning: uninterpreted CL option '" << s << "'\n";
497 }
std::optional< std::size_t > getoptnr(char option) const
Definition: cmdline.cpp:145
argst args
Definition: cmdline.h:154
std::vector< optiont > options
Definition: cmdline.h:193
void set(const std::string &opt, const char *value) override
Set option option to value.
void process_response_file(const std::string &file)
void process_response_file_line(const std::string &line)
void process_non_cl_option(const std::string &s)
void process_cl_option(const std::string &s)
virtual bool parse(int argc, const char **argv, const char *optstring)
Parses a commandline according to a specification given in optstring.
Definition: cmdline.cpp:163
static std::string binary(const constant_exprt &src)
Definition: json_expr.cpp:187
const char * ms_cl_prefixes[]
const char * non_ms_cl_options[]
parses the command line options into a cmdlinet
const char * ms_cl_flags[]
static std::istream & my_wgetline(std::istream &in, std::wstring &dest)
A special command line object for the gcc-like options.
output_type narrow(input_type input)
Run-time checked narrowing cast.
Definition: narrow.h:34
char * getenv(const char *name)
Definition: stdlib.c:496
std::string optstring
Definition: cmdline.h:170