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(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}