this repo has no description
1/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3/* 4 * Main authors: 5 * Guido Tack <guido.tack@monash.edu> 6 */ 7 8/* This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 11 12#ifdef _MSC_VER 13#define _CRT_SECURE_NO_WARNINGS 14#endif 15 16#include <minizinc/astexception.hh> 17#include <minizinc/file_utils.hh> 18#include <minizinc/htmlprinter.hh> 19#include <minizinc/model.hh> 20#include <minizinc/parser.hh> 21#include <minizinc/prettyprinter.hh> 22#include <minizinc/solver_config.hh> 23#include <minizinc/typecheck.hh> 24 25#include <fstream> 26#include <iomanip> 27#include <iostream> 28 29using namespace MiniZinc; 30using namespace std; 31 32bool beginswith(const string& s, const string& t) { return s.compare(0, t.length(), t) == 0; } 33 34int main(int argc, char** argv) { 35 string filename; 36 vector<string> includePaths; 37 bool flag_verbose = false; 38 bool flag_include_stdlib = false; 39 bool flag_index = true; 40 bool flag_rst = false; 41 int toplevel_groups = 0; 42 string output_base; 43 string header_file; 44 string footer_file; 45 46 string std_lib_dir; 47 if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) { 48 std_lib_dir = string(MZNSTDLIBDIR); 49 } 50 string globals_dir; 51 52 if (argc < 2) { 53 goto error; 54 } 55 56 try { 57 for (int i = 1; i < argc; i++) { 58 if (string(argv[i]) == string("-h") || string(argv[i]) == string("--help")) { 59 goto error; 60 } 61 if (string(argv[i]) == string("--version")) { 62 std::cout << "MiniZinc documentation generator, version " << MZN_VERSION_MAJOR << "." 63 << MZN_VERSION_MINOR << "." << MZN_VERSION_PATCH << std::endl; 64 std::cout << "Copyright (C) 2014-2017 Monash University, NICTA, Data61" << std::endl; 65 std::exit(EXIT_SUCCESS); 66 } 67 if (beginswith(string(argv[i]), "-I")) { 68 string include(argv[i]); 69 if (include.length() > 2) { 70 includePaths.push_back(include.substr(2) + string("/")); 71 } else { 72 i++; 73 if (i == argc) { 74 goto error; 75 } 76 includePaths.push_back(argv[i] + string("/")); 77 } 78 } else if (string(argv[i]) == string("-v") || string(argv[i]) == string("--verbose")) { 79 flag_verbose = true; 80 } else if (string(argv[i]) == "--stdlib-dir") { 81 i++; 82 if (i == argc) { 83 goto error; 84 } 85 std_lib_dir = argv[i]; 86 } else if (beginswith(string(argv[i]), "-G")) { 87 string filename(argv[i]); 88 if (filename.length() > 2) { 89 globals_dir = filename.substr(2); 90 } else { 91 i++; 92 if (i == argc) { 93 goto error; 94 } 95 globals_dir = argv[i]; 96 } 97 } else if (string(argv[i]) == "--toplevel-groups") { 98 i++; 99 if (i == argc) { 100 goto error; 101 } 102 toplevel_groups = atoi(argv[i]); 103 } else if (string(argv[i]) == "--html-header" || string(argv[i]) == "--rst-header") { 104 i++; 105 if (i == argc) { 106 goto error; 107 } 108 header_file = string(argv[i]); 109 } else if (string(argv[i]) == "--html-footer" || string(argv[i]) == "--rst-footer") { 110 i++; 111 if (i == argc) { 112 goto error; 113 } 114 footer_file = string(argv[i]); 115 } else if (string(argv[i]) == "--include-stdlib") { 116 flag_include_stdlib = true; 117 } else if (string(argv[i]) == "--no-index") { 118 flag_index = false; 119 } else if (string(argv[i]) == "--globals-dir" || string(argv[i]) == "--mzn-globals-dir") { 120 i++; 121 if (i == argc) { 122 goto error; 123 } 124 globals_dir = argv[i]; 125 } else if (string(argv[i]) == "--output-base") { 126 i++; 127 if (i == argc) { 128 goto error; 129 } 130 output_base = argv[i]; 131 } else if (string(argv[i]) == "--rst-output") { 132 flag_rst = true; 133 toplevel_groups = 0; 134 } else { 135 std::string input_file(argv[i]); 136 if (input_file.length() <= 4) { 137 std::cerr << "Error: cannot handle file " << input_file << "." << std::endl; 138 goto error; 139 } 140 size_t last_dot = input_file.find_last_of('.'); 141 std::string extension; 142 if (last_dot != string::npos) { 143 extension = input_file.substr(last_dot, string::npos); 144 } 145 if (extension == ".mzn") { 146 if (filename.empty()) { 147 filename = input_file; 148 } else { 149 std::cerr << "Error: Multiple .mzn files given." << std::endl; 150 goto error; 151 } 152 } else if (extension == ".dzn" || extension == ".json") { 153 std::cerr << "Error: cannot generate documentation for data files." << std::endl; 154 } else { 155 std::cerr << "Error: cannot handle file extension " << extension << "." << std::endl; 156 goto error; 157 } 158 } 159 } 160 161 if (filename.empty()) { 162 std::cerr << "Error: no model file given." << std::endl; 163 goto error; 164 } 165 166 if (std_lib_dir.empty()) { 167 SolverConfigs solver_configs(std::cerr); 168 std_lib_dir = solver_configs.mznlibDir(); 169 } 170 171 if (std_lib_dir.empty()) { 172 std::cerr << "Error: unknown minizinc standard library directory.\n" 173 << "Specify --stdlib-dir on the command line or set the\n" 174 << "MZN_STDLIB_DIR environment variable.\n"; 175 std::exit(EXIT_FAILURE); 176 } 177 178 if (!globals_dir.empty()) { 179 includePaths.push_back(std_lib_dir + "/" + globals_dir + "/"); 180 } 181 includePaths.push_back(std_lib_dir + "/std/"); 182 183 for (auto& includePath : includePaths) { 184 if (!FileUtils::directory_exists(includePath)) { 185 std::cerr << "Cannot access include directory " << includePath << "\n"; 186 std::exit(EXIT_FAILURE); 187 } 188 } 189 190 if (output_base.empty()) { 191 output_base = filename.substr(0, filename.length() - 4); 192 } 193 194 { 195 string header; 196 size_t header_title = std::string::npos; 197 size_t title_size = std::string("@TITLE").size(); 198 if (!header_file.empty()) { 199 std::ifstream hs(FILE_PATH(header_file)); 200 if (!hs.good()) { 201 std::cerr << "Cannot open header file " << header_file << "\n"; 202 std::exit(EXIT_FAILURE); 203 } 204 std::string str((std::istreambuf_iterator<char>(hs)), std::istreambuf_iterator<char>()); 205 header = str; 206 header_title = str.find("@TITLE"); 207 } 208 string footer; 209 if (!footer_file.empty()) { 210 std::ifstream hs(FILE_PATH(footer_file)); 211 if (!hs.good()) { 212 std::cerr << "Cannot open footer file " << footer_file << "\n"; 213 std::exit(EXIT_FAILURE); 214 } 215 std::string str((std::istreambuf_iterator<char>(hs)), std::istreambuf_iterator<char>()); 216 footer = str; 217 } 218 219 std::stringstream errstream; 220 if (flag_verbose) { 221 std::cerr << "Parsing '" << filename << "'" << std::endl; 222 } 223 std::vector<std::string> filenames; 224 filenames.push_back(filename); 225 Env env; 226 if (Model* m = parse(env, filenames, vector<string>(), "", "", includePaths, false, false, 227 true, flag_verbose, errstream)) { 228 try { 229 env.model(m); 230 if (flag_verbose) { 231 std::cerr << "Done parsing." << std::endl; 232 } 233 if (flag_verbose) { 234 std::cerr << "Typechecking ..."; 235 } 236 vector<TypeError> typeErrors; 237 MiniZinc::typecheck(env, m, typeErrors, true, false); 238 if (!typeErrors.empty()) { 239 for (auto& typeError : typeErrors) { 240 if (flag_verbose) { 241 std::cerr << std::endl; 242 } 243 std::cerr << typeError.loc() << ":" << std::endl; 244 std::cerr << typeError.what() << ": " << typeError.msg() << std::endl; 245 } 246 exit(EXIT_FAILURE); 247 } 248 if (flag_verbose) { 249 std::cerr << " done" << std::endl; 250 } 251 std::string basename = output_base; 252 std::string basedir; 253 size_t lastSlash = output_base.find_last_of('/'); 254 if (lastSlash != std::string::npos) { 255 basedir = basename.substr(0, lastSlash) + "/"; 256 basename = basename.substr(lastSlash + 1, std::string::npos); 257 } 258 std::vector<HtmlDocument> docs; 259 if (flag_rst) { 260 docs = RSTPrinter::printRST(env.envi(), m, basename, toplevel_groups, 261 flag_include_stdlib, flag_index); 262 } else { 263 docs = HtmlPrinter::printHtml(env.envi(), m, basename, toplevel_groups, 264 flag_include_stdlib, flag_index); 265 } 266 267 for (auto& doc : docs) { 268 std::ofstream os(FILE_PATH(basedir + doc.filename() + (flag_rst ? ".rst" : ".html"))); 269 std::string header_replace = header; 270 if (header_title != std::string::npos) { 271 header_replace = header_replace.replace(header_title, title_size, doc.title()); 272 } 273 os << header_replace; 274 os << doc.document(); 275 os << footer; 276 os.close(); 277 } 278 } catch (LocationException& e) { 279 if (flag_verbose) { 280 std::cerr << std::endl; 281 } 282 std::cerr << e.loc() << ":" << std::endl; 283 std::cerr << e.what() << ": " << e.msg() << std::endl; 284 exit(EXIT_FAILURE); 285 } catch (Exception& e) { 286 if (flag_verbose) { 287 std::cerr << std::endl; 288 } 289 std::cerr << e.what() << ": " << e.msg() << std::endl; 290 exit(EXIT_FAILURE); 291 } 292 } else { 293 if (flag_verbose) { 294 std::cerr << std::endl; 295 } 296 std::copy(istreambuf_iterator<char>(errstream), istreambuf_iterator<char>(), 297 ostreambuf_iterator<char>(std::cerr)); 298 exit(EXIT_FAILURE); 299 } 300 } 301 302 if (flag_verbose) { 303 std::cerr << "Done." << std::endl; 304 } 305 return 0; 306 } catch (...) { 307 std::cerr << " UNHANDLED EXCEPTION." << std::endl; 308 exit(EXIT_FAILURE); 309 } 310 311error: 312 std::string executable_name(argv[0]); 313 executable_name = executable_name.substr(executable_name.find_last_of("/\\") + 1); 314 std::cerr 315 << "Usage: " << executable_name 316 << " [<options>] [-I <include path>] <model>.mzn [<data>.dzn ...]" << std::endl 317 << std::endl 318 << "Options:" << std::endl 319 << " --help, -h\n Print this help message" << std::endl 320 << " --version\n Print version information" << std::endl 321 << " --include-stdlib\n Include the standard libraries in the output" << std::endl 322 << " -v, --verbose\n Print progress statements" << std::endl 323 << " --stdlib-dir <dir>\n Path to MiniZinc standard library directory" << std::endl 324 << " -G --globals-dir --mzn-globals-dir\n Search for included files in <stdlib>/<dir>." 325 << std::endl 326 << " --single-page\n Print entire documentation on a single HTML page." << std::endl 327 << " --no-index\n Do not generate an index of all symbols." << std::endl 328 << " --rst-output\n Generate ReStructuredText rather than HTML." << std::endl 329 << " --html-header, --html-footer, --rst-header, --rst-footer\n Header/footer files " 330 "to include in output." 331 << std::endl 332 << std::endl 333 << "Output options:" << std::endl 334 << std::endl 335 << " --output-base <name>\n Base name for output files" << std::endl; 336 337 exit(EXIT_FAILURE); 338}