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 "rtl/ustring.hxx" 34 #include "osl/file.hxx" 35 36 #ifdef WNT 37 # include <windows.h> 38 #endif 39 40 /* 41 #ifndef WIN32_LEAN_AND_MEAN 42 # define WIN32_LEAN_AND_MEAN 43 # ifdef _MSC_VER 44 # pragma warning(push,1) 45 # endif 46 # include <windows.h> 47 # ifdef _MSC_VER 48 # pragma warning(pop) 49 # endif 50 # include <tchar.h> 51 # undef WIN32_LEAN_AND_MEAN 52 #endif 53 */ 54 55 #include <stdio.h> 56 #include <string.h> 57 58 using rtl::OString; 59 using rtl::OStringBuffer; 60 61 #ifdef SAL_UNX 62 #define SEPARATOR '/' 63 #else 64 #define SEPARATOR '\\' 65 #endif 66 67 Options::Options(char const * progname) 68 : m_program(progname), m_stdin(false), m_verbose(false), m_quiet(false) 69 { 70 } 71 72 Options::~Options() 73 { 74 } 75 76 // static 77 bool Options::checkArgument (std::vector< std::string > & rArgs, char const * arg, size_t len) 78 { 79 bool result = ((arg != 0) && (len > 0)); 80 OSL_PRECOND(result, "idlc::Options::checkArgument(): invalid arguments"); 81 if (result) 82 { 83 switch(arg[0]) 84 { 85 case '@': 86 if ((result = (len > 1)) == true) 87 { 88 // "@<cmdfile>" 89 result = Options::checkCommandFile (rArgs, &(arg[1])); 90 } 91 break; 92 case '-': 93 if ((result = (len > 1)) == true) 94 { 95 // "-<option>" 96 switch (arg[1]) 97 { 98 case 'O': 99 case 'I': 100 case 'D': 101 { 102 // "-<option>[<param>] 103 std::string option(&(arg[0]), 2); 104 rArgs.push_back(option); 105 if (len > 2) 106 { 107 // "-<option><param>" 108 std::string param(&(arg[2]), len - 2); 109 rArgs.push_back(param); 110 } 111 break; 112 } 113 default: 114 // "-<option>" ([long] option, w/o param) 115 rArgs.push_back(std::string(arg, len)); 116 break; 117 } 118 } 119 break; 120 default: 121 // "<param>" 122 rArgs.push_back(std::string(arg, len)); 123 break; 124 } 125 } 126 return (result); 127 } 128 129 // static 130 bool Options::checkCommandFile (std::vector< std::string > & rArgs, char const * filename) 131 { 132 FILE * fp = fopen(filename, "r"); 133 if (fp == 0) 134 { 135 fprintf(stderr, "ERROR: can't open command file \"%s\"\n", filename); 136 return (false); 137 } 138 139 std::string buffer; 140 buffer.reserve(256); 141 142 bool quoted = false; 143 int c = EOF; 144 while ((c = fgetc(fp)) != EOF) 145 { 146 switch(c) 147 { 148 case '\"': 149 quoted = !quoted; 150 break; 151 case ' ': 152 case '\t': 153 case '\r': 154 case '\n': 155 if (!quoted) 156 { 157 if (!buffer.empty()) 158 { 159 // append current argument. 160 if (!Options::checkArgument(rArgs, buffer.c_str(), buffer.size())) 161 { 162 (void) fclose(fp); 163 return (false); 164 } 165 buffer.clear(); 166 } 167 break; 168 } 169 default: 170 // quoted white-space fall through 171 buffer.push_back(sal::static_int_cast<char>(c)); 172 break; 173 } 174 } 175 if (!buffer.empty()) 176 { 177 // append unterminated argument. 178 if (!Options::checkArgument(rArgs, buffer.c_str(), buffer.size())) 179 { 180 (void) fclose(fp); 181 return (false); 182 } 183 buffer.clear(); 184 } 185 return (fclose(fp) == 0); 186 } 187 188 bool Options::badOption(char const * reason, std::string const & rArg) throw(IllegalArgument) 189 { 190 OStringBuffer message; 191 if (reason != 0) 192 { 193 message.append(reason); message.append(" option '"); message.append(rArg.c_str()); message.append("'"); 194 throw IllegalArgument(message.makeStringAndClear()); 195 } 196 return false; 197 } 198 199 bool Options::setOption(char const * option, std::string const & rArg) 200 { 201 bool result = (0 == strcmp(option, rArg.c_str())); 202 if (result) 203 m_options[rArg.c_str()] = OString(rArg.c_str(), rArg.size()); 204 return (result); 205 } 206 207 #ifdef WNT 208 /* Helper functiopn to convert windows paths including spaces, brackets etc. into 209 a windows short Url. The ucpp preprocessor has problems with such paths and returns 210 with error. 211 */ 212 OString convertIncPathtoShortWindowsPath(const OString& incPath) { 213 rtl::OUString path = OStringToOUString(incPath, RTL_TEXTENCODING_UTF8); 214 215 std::vector<sal_Unicode> vec(path.getLength() + 1); 216 //GetShortPathNameW only works if the file can be found! 217 const DWORD len = GetShortPathNameW( 218 reinterpret_cast<LPCWSTR>(path.getStr()), reinterpret_cast<LPWSTR>(&vec[0]), path.getLength() + 1); 219 220 rtl::OUString ret = rtl::OUString(&vec[0], len); 221 222 if (len > 0) 223 return OUStringToOString(ret, RTL_TEXTENCODING_UTF8); 224 225 return incPath; 226 } 227 #endif 228 229 bool Options::initOptions(std::vector< std::string > & rArgs) throw(IllegalArgument) 230 { 231 std::vector< std::string >::const_iterator first = rArgs.begin(), last = rArgs.end(); 232 for (; first != last; ++first) 233 { 234 if ((*first)[0] != '-') 235 { 236 OString filename((*first).c_str(), (*first).size()); 237 OString tmp(filename.toAsciiLowerCase()); 238 if (tmp.lastIndexOf(".idl") != (tmp.getLength() - 4)) 239 { 240 throw IllegalArgument("'" + filename + "' is not a valid input file, only '*.idl' files will be accepted"); 241 } 242 m_inputFiles.push_back(filename); 243 continue; 244 } 245 246 std::string const option(*first); 247 switch((*first)[1]) 248 { 249 case 'O': 250 { 251 if (!((++first != last) && ((*first)[0] != '-'))) 252 { 253 return badOption("invalid", option); 254 } 255 OString param((*first).c_str(), (*first).size()); 256 m_options["-O"] = param; 257 break; 258 } 259 case 'I': 260 { 261 if (!((++first != last) && ((*first)[0] != '-'))) 262 { 263 return badOption("invalid", option); 264 } 265 OString param((*first).c_str(), (*first).size()); 266 { 267 // quote param token(s). 268 OStringBuffer buffer; 269 sal_Int32 k = 0; 270 do 271 { 272 OStringBuffer token; 273 token.append("-I"); 274 #ifdef WNT 275 rtl::OString incpath = convertIncPathtoShortWindowsPath(param.getToken(0, ';', k)); 276 #else 277 rtl::OString incpath = param.getToken(0, ';', k); 278 #endif 279 token.append(incpath); 280 //token.append(param.getToken(0, ';', k)); 281 if (buffer.getLength() > 0) 282 buffer.append(' '); 283 buffer.append(token); 284 } while (k != -1); 285 param = buffer.makeStringAndClear(); 286 } 287 if (m_options.count("-I") > 0) 288 { 289 // append param. 290 OStringBuffer buffer(m_options["-I"]); 291 buffer.append(' '); buffer.append(param); 292 param = buffer.makeStringAndClear(); 293 } 294 m_options["-I"] = param; 295 break; 296 } 297 case 'D': 298 { 299 if (!((++first != last) && ((*first)[0] != '-'))) 300 { 301 return badOption("invalid", option); 302 } 303 OString param("-D"); param += OString((*first).c_str(), (*first).size()); 304 if (m_options.count("-D") > 0) 305 { 306 OStringBuffer buffer(m_options["-D"]); 307 buffer.append(' '); buffer.append(param); 308 param = buffer.makeStringAndClear(); 309 } 310 m_options["-D"] = param; 311 break; 312 } 313 case 'C': 314 { 315 if (!setOption("-C", option)) 316 { 317 return badOption("invalid", option); 318 } 319 break; 320 } 321 case 'c': 322 { 323 if (!setOption("-cid", option)) 324 { 325 return badOption("invalid", option); 326 } 327 break; 328 } 329 case 'q': 330 { 331 if (!setOption("-quiet", option)) 332 { 333 return badOption("invalid", option); 334 } 335 m_quiet = true; 336 break; 337 } 338 case 'v': 339 { 340 if (!setOption("-verbose", option)) 341 { 342 return badOption("invalid", option); 343 } 344 m_verbose = true; 345 break; 346 } 347 case 'w': 348 { 349 if (!(setOption("-w", option) || setOption("-we", option))) 350 { 351 return badOption("invalid", option); 352 } 353 break; 354 } 355 case 'h': 356 case '?': 357 { 358 if (!(setOption("-h", option) || setOption("-?", option))) 359 { 360 return badOption("invalid", option); 361 } 362 { 363 (void) fprintf(stdout, "%s", prepareHelp().getStr()); 364 return (false); 365 } 366 // break; // Unreachable 367 } 368 case 's': 369 { 370 if (!setOption("-stdin", option)) 371 { 372 return badOption("invalid", option); 373 } 374 m_stdin = true; 375 break; 376 } 377 default: 378 return badOption("unknown", option); 379 } 380 } 381 return (true); 382 } 383 384 OString Options::prepareHelp() 385 { 386 OString help("\nusing: "); 387 help += m_program + " [-options] <file_1> ... <file_n> | @<filename> | -stdin\n"; 388 help += " <file_n> = file_n specifies one or more idl files.\n"; 389 help += " Only files with the extension '.idl' are valid.\n"; 390 help += " @<filename> = filename specifies the name of a command file.\n"; 391 help += " -stdin = read idl file from standard input.\n"; 392 help += " Options:\n"; 393 help += " -O<path> = path specifies the output directory.\n"; 394 help += " The generated output is a registry file with\n"; 395 help += " the same name as the idl input file (or 'stdin'\n"; 396 help += " for -stdin).\n"; 397 help += " -I<path> = path specifies a directory where include\n"; 398 help += " files will be searched by the preprocessor.\n"; 399 help += " Multiple directories can be combined with ';'.\n"; 400 help += " -D<name> = name defines a macro for the preprocessor.\n"; 401 help += " -C = generate complete type information, including\n"; 402 help += " documentation.\n"; 403 help += " -cid = check if identifiers fulfill the UNO naming\n"; 404 help += " requirements.\n"; 405 help += " -w = display warning messages.\n"; 406 help += " -we = treat warnings as errors.\n"; 407 help += " -h|-? = print this help message and exit.\n\n"; 408 help += prepareVersion(); 409 410 return help; 411 } 412 413 OString Options::prepareVersion() 414 { 415 OString version(m_program); 416 version += " Version 1.1\n\n"; 417 return version; 418 } 419 420 const OString& Options::getProgramName() const 421 { 422 return m_program; 423 } 424 425 bool Options::isValid(const OString& option) 426 { 427 return (m_options.count(option) > 0); 428 } 429 430 const OString& Options::getOption(const OString& option) 431 throw( IllegalArgument ) 432 { 433 if (!isValid(option)) 434 { 435 throw IllegalArgument("Option is not valid or currently not set."); 436 } 437 return m_options[option]; 438 } 439 /* vi:set tabstop=4 shiftwidth=4 expandtab: */ 440