1 // 2 // Copyright (c) ZeroC, Inc. All rights reserved. 3 // 4 5 #include <IceUtil/Options.h> 6 #include <IceUtil/CtrlCHandler.h> 7 #include <IceUtil/Mutex.h> 8 #include <IceUtil/MutexPtrLock.h> 9 #include <IceUtil/ConsoleUtil.h> 10 #include <Slice/Preprocessor.h> 11 #include <Slice/FileTracker.h> 12 #include <Slice/Util.h> 13 #include <Gen.h> 14 #include <stdlib.h> 15 16 using namespace std; 17 using namespace Slice; 18 using namespace IceUtilInternal; 19 20 namespace 21 { 22 23 IceUtil::Mutex* globalMutex = 0; 24 bool interrupted = false; 25 26 class Init 27 { 28 public: 29 30 Init() 31 { 32 globalMutex = new IceUtil::Mutex; 33 } 34 35 ~Init() 36 { 37 delete globalMutex; 38 globalMutex = 0; 39 } 40 }; 41 42 Init init; 43 44 } 45 46 void 47 interruptedCallback(int /*signal*/) 48 { 49 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex); 50 51 interrupted = true; 52 } 53 54 void 55 usage(const string& n) 56 { 57 consoleErr << "Usage: " << n << " [options] slice-files...\n"; 58 consoleErr << 59 "Options:\n" 60 "-h, --help Show this message.\n" 61 "-v, --version Display the Ice version.\n" 62 "-DNAME Define NAME as 1.\n" 63 "-DNAME=DEF Define NAME as DEF.\n" 64 "-UNAME Remove any definition for NAME.\n" 65 "-IDIR Put DIR in the include file search path.\n" 66 "-E Print preprocessor output on stdout.\n" 67 "--output-dir DIR Create files in the directory DIR.\n" 68 "-d, --debug Print debug messages.\n" 69 "--hdr FILE Use the contents of FILE as the header.\n" 70 "--ftr FILe Use the contents of FILE as the footer.\n" 71 "--indexhdr FILE Use the contents of FILE as the header of the index/toc page (default=--hdr).\n" 72 "--indexftr FILE Use the contents of FILE as the footer of the index/toc page (default=--ftr).\n" 73 "--image-dir DIR Directory containing images for style sheets.\n" 74 "--logo-url URL Link to URL from logo image (requires --image-dir).\n" 75 "--search ACTION Generate search box with specified ACTION.\n" 76 "--index NUM Generate subindex if it has at least NUM entries (0 for no index, default=1).\n" 77 "--summary NUM Print a warning if a summary sentence exceeds NUM characters.\n" 78 "--ice Allow reserved Ice prefix in Slice identifiers\n" 79 " deprecated: use instead [[\"ice-prefix\"]] metadata.\n" 80 "--underscore Allow underscores in Slice identifiers\n" 81 " deprecated: use instead [[\"underscore\"]] metadata.\n" 82 ; 83 } 84 85 int 86 compile(const vector<string>& argv) 87 { 88 IceUtilInternal::Options opts; 89 opts.addOpt("h", "help"); 90 opts.addOpt("v", "version"); 91 opts.addOpt("", "validate"); 92 opts.addOpt("D", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); 93 opts.addOpt("U", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); 94 opts.addOpt("I", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); 95 opts.addOpt("E"); 96 opts.addOpt("", "output-dir", IceUtilInternal::Options::NeedArg, "."); 97 opts.addOpt("", "hdr", IceUtilInternal::Options::NeedArg); 98 opts.addOpt("", "ftr", IceUtilInternal::Options::NeedArg); 99 opts.addOpt("", "indexhdr", IceUtilInternal::Options::NeedArg); 100 opts.addOpt("", "indexftr", IceUtilInternal::Options::NeedArg); 101 opts.addOpt("", "index", IceUtilInternal::Options::NeedArg, "1"); 102 opts.addOpt("", "image-dir", IceUtilInternal::Options::NeedArg); 103 opts.addOpt("", "logo-url", IceUtilInternal::Options::NeedArg); 104 opts.addOpt("", "search", IceUtilInternal::Options::NeedArg); 105 opts.addOpt("", "summary", IceUtilInternal::Options::NeedArg, "0"); 106 opts.addOpt("d", "debug"); 107 opts.addOpt("", "ice"); 108 opts.addOpt("", "underscore"); 109 110 bool validate = find(argv.begin(), argv.end(), "--validate") != argv.end(); 111 vector<string> args; 112 try 113 { 114 args = opts.parse(argv); 115 } 116 catch(const IceUtilInternal::BadOptException& e) 117 { 118 consoleErr << argv[0] << ": error: " << e.reason << endl; 119 if(!validate) 120 { 121 usage(argv[0]); 122 } 123 return EXIT_FAILURE; 124 } 125 126 if(opts.isSet("help")) 127 { 128 usage(argv[0]); 129 return EXIT_SUCCESS; 130 } 131 132 if(opts.isSet("version")) 133 { 134 consoleErr << ICE_STRING_VERSION << endl; 135 return EXIT_SUCCESS; 136 } 137 138 vector<string> cppArgs; 139 vector<string> optargs = opts.argVec("D"); 140 for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i) 141 { 142 cppArgs.push_back("-D" + *i); 143 } 144 145 optargs = opts.argVec("U"); 146 for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i) 147 { 148 cppArgs.push_back("-U" + *i); 149 } 150 151 optargs = opts.argVec("I"); 152 for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i) 153 { 154 cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i)); 155 } 156 157 bool preprocess = opts.isSet("E"); 158 159 string output = opts.optArg("output-dir"); 160 161 string header = opts.optArg("hdr"); 162 163 string footer = opts.optArg("ftr"); 164 165 string indexHeader = opts.optArg("indexhdr"); 166 167 string indexFooter = opts.optArg("indexftr"); 168 169 string ind = opts.optArg("index"); 170 unsigned indexCount = 0; 171 if(!ind.empty()) 172 { 173 istringstream s(ind); 174 s >> indexCount; 175 if(!s) 176 { 177 consoleErr << argv[0] << ": error: the --index operation requires a positive integer argument" 178 << endl; 179 if(!validate) 180 { 181 usage(argv[0]); 182 } 183 return EXIT_FAILURE; 184 } 185 } 186 187 string imageDir = opts.optArg("image-dir"); 188 189 string logoURL = opts.optArg("logo-url"); 190 191 string searchAction = opts.optArg("search"); 192 193 string warnSummary = opts.optArg("summary"); 194 unsigned summaryCount = 0; 195 if(!warnSummary.empty()) 196 { 197 istringstream s(warnSummary); 198 s >> summaryCount; 199 if(!s) 200 { 201 consoleErr << argv[0] << ": error: the --summary operation requires a positive integer argument" 202 << endl; 203 if(!validate) 204 { 205 usage(argv[0]); 206 } 207 return EXIT_FAILURE; 208 } 209 } 210 211 bool debug = opts.isSet("debug"); 212 213 bool ice = opts.isSet("ice"); 214 215 bool underscore = opts.isSet("underscore"); 216 217 if(args.empty()) 218 { 219 consoleErr << argv[0] << ": error: no input file" << endl; 220 if(!validate) 221 { 222 usage(argv[0]); 223 } 224 return EXIT_FAILURE; 225 } 226 227 if(validate) 228 { 229 return EXIT_SUCCESS; 230 } 231 232 UnitPtr p = Unit::createUnit(true, false, ice, underscore); 233 234 int status = EXIT_SUCCESS; 235 236 IceUtil::CtrlCHandler ctrlCHandler; 237 ctrlCHandler.setCallback(interruptedCallback); 238 239 for(vector<string>::size_type idx = 0; idx < args.size(); ++idx) 240 { 241 PreprocessorPtr icecpp = Preprocessor::create(argv[0], args[idx], cppArgs); 242 FILE* cppHandle = icecpp->preprocess(true, "-D__SLICE2HTML__"); 243 244 if(cppHandle == 0) 245 { 246 p->destroy(); 247 return EXIT_FAILURE; 248 } 249 if(preprocess) 250 { 251 char buf[4096]; 252 while(fgets(buf, static_cast<int>(sizeof(buf)), cppHandle) != ICE_NULLPTR) 253 { 254 if(fputs(buf, stdout) == EOF) 255 { 256 p->destroy(); 257 return EXIT_FAILURE; 258 } 259 } 260 } 261 else 262 { 263 status = p->parse(args[idx], cppHandle, debug); 264 } 265 266 if(!icecpp->close()) 267 { 268 p->destroy(); 269 return EXIT_FAILURE; 270 } 271 272 { 273 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex); 274 275 if(interrupted) 276 { 277 return EXIT_FAILURE; 278 } 279 } 280 } 281 282 if(status == EXIT_SUCCESS && !preprocess) 283 { 284 try 285 { 286 Slice::generate(p, output, header, footer, indexHeader, indexFooter, imageDir, logoURL, 287 searchAction, indexCount, summaryCount); 288 } 289 catch(const Slice::FileException& ex) 290 { 291 // If a file could not be created, then cleanup any 292 // created files. 293 FileTracker::instance()->cleanup(); 294 p->destroy(); 295 consoleErr << argv[0] << ": error: " << ex.reason() << endl; 296 return EXIT_FAILURE; 297 } 298 catch(...) 299 { 300 FileTracker::instance()->cleanup(); 301 consoleErr << args[0] << ": error:" << "unknown exception" << endl; 302 return EXIT_FAILURE; 303 } 304 } 305 306 p->destroy(); 307 308 { 309 IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(globalMutex); 310 311 if(interrupted) 312 { 313 FileTracker::instance()->cleanup(); 314 return EXIT_FAILURE; 315 } 316 } 317 318 return status; 319 } 320 321 #ifdef _WIN32 322 int wmain(int argc, wchar_t* argv[]) 323 #else 324 int main(int argc, char* argv[]) 325 #endif 326 { 327 vector<string> args = argvToArgs(argc, argv); 328 try 329 { 330 return compile(args); 331 } 332 catch(const std::exception& ex) 333 { 334 consoleErr << args[0] << ": error:" << ex.what() << endl; 335 return EXIT_FAILURE; 336 } 337 catch(...) 338 { 339 consoleErr << args[0] << ": error:" << "unknown exception" << endl; 340 return EXIT_FAILURE; 341 } 342 } 343