this repo has no description
at develop 11 kB view raw
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(string s, 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_ignoreStdlib = false; 38 bool flag_verbose = false; 39 bool flag_include_stdlib = false; 40 bool flag_index = true; 41 bool flag_rst = false; 42 int toplevel_groups = 0; 43 string output_base; 44 string header_file; 45 string footer_file; 46 47 string std_lib_dir; 48 if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) { 49 std_lib_dir = string(MZNSTDLIBDIR); 50 } 51 string globals_dir; 52 53 if (argc < 2) goto error; 54 55 for (int i = 1; i < argc; i++) { 56 if (string(argv[i]) == string("-h") || string(argv[i]) == string("--help")) goto error; 57 if (string(argv[i]) == string("--version")) { 58 std::cout << "MiniZinc documentation generator, version " << MZN_VERSION_MAJOR << "." 59 << MZN_VERSION_MINOR << "." << MZN_VERSION_PATCH << std::endl; 60 std::cout << "Copyright (C) 2014-2017 Monash University, NICTA, Data61" << std::endl; 61 std::exit(EXIT_SUCCESS); 62 } 63 if (beginswith(string(argv[i]), "-I")) { 64 string include(argv[i]); 65 if (include.length() > 2) { 66 includePaths.push_back(include.substr(2) + string("/")); 67 } else { 68 i++; 69 if (i == argc) { 70 goto error; 71 } 72 includePaths.push_back(argv[i] + string("/")); 73 } 74 } else if (string(argv[i]) == string("--ignore-stdlib")) { 75 flag_ignoreStdlib = true; 76 } else if (string(argv[i]) == string("-v") || string(argv[i]) == string("--verbose")) { 77 flag_verbose = true; 78 } else if (string(argv[i]) == "--stdlib-dir") { 79 i++; 80 if (i == argc) goto error; 81 std_lib_dir = argv[i]; 82 } else if (beginswith(string(argv[i]), "-G")) { 83 string filename(argv[i]); 84 if (filename.length() > 2) { 85 globals_dir = filename.substr(2); 86 } else { 87 i++; 88 if (i == argc) { 89 goto error; 90 } 91 globals_dir = argv[i]; 92 } 93 } else if (string(argv[i]) == "--toplevel-groups") { 94 i++; 95 if (i == argc) goto error; 96 toplevel_groups = atoi(argv[i]); 97 } else if (string(argv[i]) == "--html-header" || string(argv[i]) == "--rst-header") { 98 i++; 99 if (i == argc) goto error; 100 header_file = string(argv[i]); 101 } else if (string(argv[i]) == "--html-footer" || string(argv[i]) == "--rst-footer") { 102 i++; 103 if (i == argc) goto error; 104 footer_file = string(argv[i]); 105 } else if (string(argv[i]) == "--include-stdlib") { 106 flag_include_stdlib = true; 107 } else if (string(argv[i]) == "--no-index") { 108 flag_index = false; 109 } else if (string(argv[i]) == "--globals-dir" || string(argv[i]) == "--mzn-globals-dir") { 110 i++; 111 if (i == argc) goto error; 112 globals_dir = argv[i]; 113 } else if (string(argv[i]) == "--output-base") { 114 i++; 115 if (i == argc) goto error; 116 output_base = argv[i]; 117 } else if (string(argv[i]) == "--rst-output") { 118 flag_rst = true; 119 toplevel_groups = 0; 120 } else { 121 std::string input_file(argv[i]); 122 if (input_file.length() <= 4) { 123 std::cerr << "Error: cannot handle file " << input_file << "." << std::endl; 124 goto error; 125 } 126 size_t last_dot = input_file.find_last_of('.'); 127 std::string extension; 128 if (last_dot != string::npos) extension = input_file.substr(last_dot, string::npos); 129 if (extension == ".mzn") { 130 if (filename == "") { 131 filename = input_file; 132 } else { 133 std::cerr << "Error: Multiple .mzn files given." << std::endl; 134 goto error; 135 } 136 } else if (extension == ".dzn" || extension == ".json") { 137 std::cerr << "Error: cannot generate documentation for data files." << std::endl; 138 } else { 139 std::cerr << "Error: cannot handle file extension " << extension << "." << std::endl; 140 goto error; 141 } 142 } 143 } 144 145 if (filename == "") { 146 std::cerr << "Error: no model file given." << std::endl; 147 goto error; 148 } 149 150 if (std_lib_dir.empty()) { 151 SolverConfigs solver_configs(std::cerr); 152 std_lib_dir = solver_configs.mznlibDir(); 153 } 154 155 if (std_lib_dir.empty()) { 156 std::cerr << "Error: unknown minizinc standard library directory.\n" 157 << "Specify --stdlib-dir on the command line or set the\n" 158 << "MZN_STDLIB_DIR environment variable.\n"; 159 std::exit(EXIT_FAILURE); 160 } 161 162 if (globals_dir != "") { 163 includePaths.push_back(std_lib_dir + "/" + globals_dir + "/"); 164 } 165 includePaths.push_back(std_lib_dir + "/std/"); 166 167 for (unsigned int i = 0; i < includePaths.size(); i++) { 168 if (!FileUtils::directory_exists(includePaths[i])) { 169 std::cerr << "Cannot access include directory " << includePaths[i] << "\n"; 170 std::exit(EXIT_FAILURE); 171 } 172 } 173 174 if (output_base == "") { 175 output_base = filename.substr(0, filename.length() - 4); 176 } 177 178 { 179 string header; 180 size_t header_title = std::string::npos; 181 size_t title_size = std::string("@TITLE").size(); 182 if (!header_file.empty()) { 183 std::ifstream hs(header_file); 184 if (!hs.good()) { 185 std::cerr << "Cannot open header file " << header_file << "\n"; 186 std::exit(EXIT_FAILURE); 187 } 188 std::string str((std::istreambuf_iterator<char>(hs)), std::istreambuf_iterator<char>()); 189 header = str; 190 header_title = str.find("@TITLE"); 191 } 192 string footer; 193 if (!footer_file.empty()) { 194 std::ifstream hs(footer_file); 195 if (!hs.good()) { 196 std::cerr << "Cannot open footer file " << footer_file << "\n"; 197 std::exit(EXIT_FAILURE); 198 } 199 std::string str((std::istreambuf_iterator<char>(hs)), std::istreambuf_iterator<char>()); 200 footer = str; 201 } 202 203 std::stringstream errstream; 204 if (flag_verbose) std::cerr << "Parsing '" << filename << "'" << std::endl; 205 std::vector<std::string> filenames; 206 filenames.push_back(filename); 207 Env env; 208 if (Model* m = parse(env, filenames, vector<string>(), "", "", includePaths, flag_ignoreStdlib, 209 true, flag_verbose, errstream)) { 210 try { 211 env.model(m); 212 if (flag_verbose) std::cerr << "Done parsing." << std::endl; 213 if (flag_verbose) std::cerr << "Typechecking ..."; 214 vector<TypeError> typeErrors; 215 MiniZinc::typecheck(env, m, typeErrors, true, false); 216 if (typeErrors.size() > 0) { 217 for (unsigned int i = 0; i < typeErrors.size(); i++) { 218 if (flag_verbose) std::cerr << std::endl; 219 std::cerr << typeErrors[i].loc() << ":" << std::endl; 220 std::cerr << typeErrors[i].what() << ": " << typeErrors[i].msg() << std::endl; 221 } 222 exit(EXIT_FAILURE); 223 } 224 if (flag_verbose) std::cerr << " done" << std::endl; 225 std::string basename = output_base; 226 std::string basedir; 227 size_t lastSlash = output_base.find_last_of("/"); 228 if (lastSlash != std::string::npos) { 229 basedir = basename.substr(0, lastSlash) + "/"; 230 basename = basename.substr(lastSlash + 1, std::string::npos); 231 } 232 std::vector<HtmlDocument> docs; 233 if (flag_rst) { 234 docs = RSTPrinter::printRST(env.envi(), m, basename, toplevel_groups, flag_include_stdlib, 235 flag_index); 236 } else { 237 docs = HtmlPrinter::printHtml(env.envi(), m, basename, toplevel_groups, 238 flag_include_stdlib, flag_index); 239 } 240 241 for (unsigned int i = 0; i < docs.size(); i++) { 242 std::ofstream os(basedir + docs[i].filename() + (flag_rst ? ".rst" : ".html")); 243 std::string header_replace = header; 244 if (header_title != std::string::npos) { 245 header_replace = header_replace.replace(header_title, title_size, docs[i].title()); 246 } 247 os << header_replace; 248 os << docs[i].document(); 249 os << footer; 250 os.close(); 251 } 252 } catch (LocationException& e) { 253 if (flag_verbose) std::cerr << std::endl; 254 std::cerr << e.loc() << ":" << std::endl; 255 std::cerr << e.what() << ": " << e.msg() << std::endl; 256 exit(EXIT_FAILURE); 257 } catch (Exception& e) { 258 if (flag_verbose) std::cerr << std::endl; 259 std::cerr << e.what() << ": " << e.msg() << std::endl; 260 exit(EXIT_FAILURE); 261 } 262 } else { 263 if (flag_verbose) std::cerr << std::endl; 264 std::copy(istreambuf_iterator<char>(errstream), istreambuf_iterator<char>(), 265 ostreambuf_iterator<char>(std::cerr)); 266 exit(EXIT_FAILURE); 267 } 268 } 269 270 if (flag_verbose) std::cerr << "Done." << std::endl; 271 return 0; 272 273error: 274 std::string executable_name(argv[0]); 275 executable_name = executable_name.substr(executable_name.find_last_of("/\\") + 1); 276 std::cerr 277 << "Usage: " << executable_name 278 << " [<options>] [-I <include path>] <model>.mzn [<data>.dzn ...]" << std::endl 279 << std::endl 280 << "Options:" << std::endl 281 << " --help, -h\n Print this help message" << std::endl 282 << " --version\n Print version information" << std::endl 283 << " --ignore-stdlib\n Ignore the standard libraries stdlib.mzn and builtins.mzn" 284 << std::endl 285 << " -v, --verbose\n Print progress statements" << std::endl 286 << " --stdlib-dir <dir>\n Path to MiniZinc standard library directory" << std::endl 287 << " -G --globals-dir --mzn-globals-dir\n Search for included files in <stdlib>/<dir>." 288 << std::endl 289 << " --single-page\n Print entire documentation on a single HTML page." << std::endl 290 << " --no-index\n Do not generate an index of all symbols." << std::endl 291 << " --rst-output\n Generate ReStructuredText rather than HTML." << std::endl 292 << " --html-header, --html-footer, --rst-header, --rst-footer\n Header/footer files " 293 "to include in output." 294 << std::endl 295 << std::endl 296 << "Output options:" << std::endl 297 << std::endl 298 << " --output-base <name>\n Base name for output files" << std::endl; 299 300 exit(EXIT_FAILURE); 301}