xref: /aoo42x/main/idlc/source/options.cxx (revision 5979ef3c)
1  /**************************************************************
2   *
3   * Licensed to the Apache Software Foundation (ASF) under one
4   * or more contributor license agreements.  See the NOTICE file
5   * distributed with this work for additional information
6   * regarding copyright ownership.  The ASF licenses this file
7   * to you under the Apache License, Version 2.0 (the
8   * "License"); you may not use this file except in compliance
9   * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   *
20   *************************************************************/
21  
22  
23  
24  // MARKER(update_precomp.py): autogen include statement, do not remove
25  #include "precompiled_idlc.hxx"
26  
27  #include "idlc/options.hxx"
28  
29  #include "osl/diagnose.h"
30  #include "rtl/string.hxx"
31  #include "rtl/strbuf.hxx"
32  
33  #include <stdio.h>
34  #include <string.h>
35  
36  using rtl::OString;
37  using rtl::OStringBuffer;
38  
39  #ifdef SAL_UNX
40  #define SEPARATOR '/'
41  #else
42  #define SEPARATOR '\\'
43  #endif
44  
45  Options::Options(char const * progname)
46      : m_program(progname), m_stdin(false), m_verbose(false), m_quiet(false)
47  {
48  }
49  
50  Options::~Options()
51  {
52  }
53  
54  // static
55  bool Options::checkArgument (std::vector< std::string > & rArgs, char const * arg, size_t len)
56  {
57      bool result = ((arg != 0) && (len > 0));
58      OSL_PRECOND(result, "idlc::Options::checkArgument(): invalid arguments");
59      if (result)
60      {
61          switch(arg[0])
62          {
63          case '@':
64              if ((result = (len > 1)) == true)
65              {
66                  // "@<cmdfile>"
67                  result = Options::checkCommandFile (rArgs, &(arg[1]));
68              }
69              break;
70          case '-':
71              if ((result = (len > 1)) == true)
72              {
73                  // "-<option>"
74                  switch (arg[1])
75                  {
76                  case 'O':
77                  case 'I':
78                  case 'D':
79                  {
80                      // "-<option>[<param>]
81                      std::string option(&(arg[0]), 2);
82                      rArgs.push_back(option);
83                      if (len > 2)
84                      {
85                          // "-<option><param>"
86                          std::string param(&(arg[2]), len - 2);
87                          rArgs.push_back(param);
88                      }
89                      break;
90                  }
91                  default:
92                      // "-<option>" ([long] option, w/o param)
93                      rArgs.push_back(std::string(arg, len));
94                      break;
95                  }
96              }
97              break;
98          default:
99              // "<param>"
100              rArgs.push_back(std::string(arg, len));
101              break;
102          }
103      }
104      return (result);
105  }
106  
107  // static
108  bool Options::checkCommandFile (std::vector< std::string > & rArgs, char const * filename)
109  {
110      FILE * fp = fopen(filename, "r");
111      if (fp == 0)
112      {
113          fprintf(stderr, "ERROR: can't open command file \"%s\"\n", filename);
114          return (false);
115      }
116  
117      std::string buffer;
118      buffer.reserve(256);
119  
120      bool quoted = false;
121      int c = EOF;
122      while ((c = fgetc(fp)) != EOF)
123      {
124          switch(c)
125          {
126          case '\"':
127              quoted = !quoted;
128              break;
129          case ' ':
130          case '\t':
131          case '\r':
132          case '\n':
133              if (!quoted)
134              {
135                  if (!buffer.empty())
136                  {
137                      // append current argument.
138                      if (!Options::checkArgument(rArgs, buffer.c_str(), buffer.size()))
139                      {
140                          (void) fclose(fp);
141                          return (false);
142                      }
143                      buffer.clear();
144                  }
145                  break;
146              }
147          default:
148              // quoted white-space fall through
149              buffer.push_back(sal::static_int_cast<char>(c));
150              break;
151          }
152      }
153      if (!buffer.empty())
154      {
155          // append unterminated argument.
156          if (!Options::checkArgument(rArgs, buffer.c_str(), buffer.size()))
157          {
158              (void) fclose(fp);
159              return (false);
160          }
161          buffer.clear();
162      }
163      return (fclose(fp) == 0);
164  }
165  
166  bool Options::badOption(char const * reason, std::string const & rArg) throw(IllegalArgument)
167  {
168      OStringBuffer message;
169      if (reason != 0)
170      {
171          message.append(reason); message.append(" option '"); message.append(rArg.c_str()); message.append("'");
172          throw IllegalArgument(message.makeStringAndClear());
173      }
174      return false;
175  }
176  
177  bool Options::setOption(char const * option, std::string const & rArg)
178  {
179      bool result = (0 == strcmp(option, rArg.c_str()));
180      if (result)
181          m_options[rArg.c_str()] = OString(rArg.c_str(), rArg.size());
182      return (result);
183  }
184  
185  bool Options::initOptions(std::vector< std::string > & rArgs) throw(IllegalArgument)
186  {
187      std::vector< std::string >::const_iterator first = rArgs.begin(), last = rArgs.end();
188      for (; first != last; ++first)
189      {
190          if ((*first)[0] != '-')
191          {
192              OString filename((*first).c_str(), (*first).size());
193              OString tmp(filename.toAsciiLowerCase());
194              if (tmp.lastIndexOf(".idl") != (tmp.getLength() - 4))
195              {
196                  throw IllegalArgument("'" + filename + "' is not a valid input file, only '*.idl' files will be accepted");
197              }
198              m_inputFiles.push_back(filename);
199              continue;
200          }
201  
202          std::string const option(*first);
203          switch((*first)[1])
204          {
205          case 'O':
206          {
207              if (!((++first != last) && ((*first)[0] != '-')))
208              {
209                  return badOption("invalid", option);
210              }
211              OString param((*first).c_str(), (*first).size());
212              m_options["-O"] = param;
213              break;
214          }
215          case 'I':
216          {
217              if (!((++first != last) && ((*first)[0] != '-')))
218              {
219                  return badOption("invalid", option);
220              }
221              OString param((*first).c_str(), (*first).size());
222              {
223                  // quote param token(s).
224                  OStringBuffer buffer;
225                  sal_Int32 k = 0;
226                  do
227                  {
228                      OStringBuffer token; token.append("-I"); token.append(param.getToken(0, ';', k));
229                      if (buffer.getLength() > 0)
230                          buffer.append(' ');
231                      buffer.append(token);
232                  } while (k != -1);
233                  param = buffer.makeStringAndClear();
234              }
235              if (m_options.count("-I") > 0)
236              {
237                  // append param.
238                  OStringBuffer buffer(m_options["-I"]);
239                  buffer.append(' '); buffer.append(param);
240                  param = buffer.makeStringAndClear();
241              }
242              m_options["-I"] = param;
243              break;
244          }
245          case 'D':
246          {
247              if (!((++first != last) && ((*first)[0] != '-')))
248              {
249                  return badOption("invalid", option);
250              }
251              OString param("-D"); param += OString((*first).c_str(), (*first).size());
252              if (m_options.count("-D") > 0)
253              {
254                  OStringBuffer buffer(m_options["-D"]);
255                  buffer.append(' '); buffer.append(param);
256                  param = buffer.makeStringAndClear();
257              }
258              m_options["-D"] = param;
259              break;
260          }
261          case 'C':
262          {
263              if (!setOption("-C", option))
264              {
265                  return badOption("invalid", option);
266              }
267              break;
268          }
269          case 'c':
270          {
271              if (!setOption("-cid", option))
272              {
273                  return badOption("invalid", option);
274              }
275              break;
276          }
277          case 'q':
278          {
279              if (!setOption("-quiet", option))
280              {
281                  return badOption("invalid", option);
282              }
283              m_quiet = true;
284              break;
285          }
286          case 'v':
287          {
288              if (!setOption("-verbose", option))
289              {
290                  return badOption("invalid", option);
291              }
292              m_verbose = true;
293              break;
294          }
295          case 'w':
296          {
297              if (!(setOption("-w", option) || setOption("-we", option)))
298              {
299                  return badOption("invalid", option);
300              }
301              break;
302          }
303          case 'h':
304          case '?':
305          {
306              if (!(setOption("-h", option) || setOption("-?", option)))
307              {
308                  return badOption("invalid", option);
309              }
310              {
311                  (void) fprintf(stdout, "%s", prepareHelp().getStr());
312                  return (false);
313              }
314              // break; // Unreachable
315          }
316          case 's':
317          {
318              if (!setOption("-stdin", option))
319              {
320                  return badOption("invalid", option);
321              }
322              m_stdin = true;
323              break;
324          }
325          default:
326              return badOption("unknown", option);
327          }
328      }
329      return (true);
330  }
331  
332  OString	Options::prepareHelp()
333  {
334  	OString help("\nusing: ");
335  	help += m_program + " [-options] <file_1> ... <file_n> | @<filename> | -stdin\n";
336  	help += "    <file_n>    = file_n specifies one or more idl files.\n";
337  	help += "                  Only files with the extension '.idl' are valid.\n";
338  	help += "    @<filename> = filename specifies the name of a command file.\n";
339      help += "    -stdin      = read idl file from standard input.\n";
340  	help += "  Options:\n";
341  	help += "    -O<path>    = path specifies the output directory.\n";
342  	help += "                  The generated output is a registry file with\n";
343  	help += "                  the same name as the idl input file (or 'stdin'\n";
344      help += "                  for -stdin).\n";
345  	help += "    -I<path>    = path specifies a directory where include\n";
346  	help += "                  files will be searched by the preprocessor.\n";
347  	help += "                  Multiple directories can be combined with ';'.\n";
348  	help += "    -D<name>    = name defines a macro for the preprocessor.\n";
349  	help += "    -C          = generate complete type information, including\n";
350  	help += "                  documentation.\n";
351  	help += "    -cid        = check if identifiers fulfill the UNO naming\n";
352      help += "                  requirements.\n";
353  	help += "    -w          = display warning messages.\n";
354  	help += "    -we         = treat warnings as errors.\n";
355  	help += "    -h|-?       = print this help message and exit.\n\n";
356  	help += prepareVersion();
357  
358  	return help;
359  }
360  
361  OString	Options::prepareVersion()
362  {
363  	OString version(m_program);
364  	version += " Version 1.1\n\n";
365  	return version;
366  }
367  
368  const OString& Options::getProgramName() const
369  {
370  	return m_program;
371  }
372  
373  bool Options::isValid(const OString& option)
374  {
375  	return (m_options.count(option) > 0);
376  }
377  
378  const OString& Options::getOption(const OString& option)
379  	throw( IllegalArgument )
380  {
381  	if (!isValid(option))
382  	{
383  		throw IllegalArgument("Option is not valid or currently not set.");
384  	}
385      return m_options[option];
386  }
387  /* vi:set tabstop=4 shiftwidth=4 expandtab: */
388