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