// -*- coding: utf-8 -*- // Copyright (C) 2013, 2014 Laboratoire de Recherche et Développement // de l'Epita. // // This file is part of Spot, a model checking library. // // Spot is free software; you can redistribute it and/or modify it // under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 3 of the License, or // (at your option) any later version. // // Spot is distributed in the hope that it will be useful, but WITHOUT // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public // License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include "config.h" #include "formater.hh" #include #include #include #include "satsolver.hh" #include #include #include namespace spot { namespace { struct satsolver_command: formater { const char* satsolver; satsolver_command() { satsolver = getenv("SPOT_SATSOLVER"); if (!satsolver) { satsolver = "glucose -verb=0 -model %I >%O"; return; } prime(satsolver); if (!has('I')) throw std::runtime_error("SPOT_SATSOLVER should contain %I to " "indicate how to use the input filename."); if (!has('O')) throw std::runtime_error("SPOT_SATSOLVER should contain %O to " "indicate how to use the output filename."); } int run(printable* in, printable* out) { declare('I', in); declare('O', out); std::ostringstream s; format(s, satsolver); int res = system(s.str().c_str()); if (res < 0 || (WIFEXITED(res) && WEXITSTATUS(res) == 127)) { s << ": failed to execute"; throw std::runtime_error(s.str()); } // For POSIX shells, "The exit status of a command that // terminated because it received a signal shall be reported // as greater than 128." if (WIFEXITED(res) && WEXITSTATUS(res) >= 128) { s << ": terminated by signal"; throw std::runtime_error(s.str()); } if (WIFSIGNALED(res)) { s << ": terminated by signal " << WTERMSIG(res); throw std::runtime_error(s.str()); } return res; } }; } satsolver::solution satsolver_get_solution(const char* filename) { satsolver::solution sol; std::istream* in; if (filename[0] == '-' && filename[1] == 0) in = &std::cin; else in = new std::fstream(filename, std::ios_base::in); int c; while ((c = in->get()) != EOF) { // If a line does not start with 'v ', ignore it. if (c != 'v' || in->get() != ' ') { in->ignore(std::numeric_limits::max(), '\n'); continue; } // Otherwise, read integers one by one. int i; while (*in >> i) { if (i == 0) goto done; sol.push_back(i); } if (!in->eof()) // If we haven't reached end-of-file, then we just attempted // to extract something that wasn't an integer. Clear the // fail bit so that will loop over. in->clear(); } done: if (in != &std::cin) delete in; return sol; } satsolver::satsolver() : cnf_tmp_(0), cnf_stream_(0) { start(); } void satsolver::start() { cnf_tmp_ = create_tmpfile("sat-", ".cnf"); cnf_stream_ = new std::fstream(cnf_tmp_->name(), std::ios_base::trunc | std::ios_base::out); cnf_stream_->exceptions(std::ifstream::failbit | std::ifstream::badbit); } satsolver::~satsolver() { delete cnf_tmp_; delete cnf_stream_; } std::ostream& satsolver::operator()() { return *cnf_stream_; } satsolver::solution_pair satsolver::get_solution() { delete cnf_stream_; // Close the file. cnf_stream_ = 0; temporary_file* output = create_tmpfile("sat-", ".out"); solution_pair p; // Make this static, so the SPOT_SATSOLVER lookup is done only on // the first call to run_sat(). static satsolver_command cmd; p.first = cmd.run(cnf_tmp_, output); p.second = satsolver_get_solution(output->name()); delete output; return p; } }