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