S2OJ/judge_client/1/uoj_judger/include/uoj_judger.h
MascoSkray ec743dd808
fix: change fixed jdk runtime path to latest
The original judge client default uses jdk 7u76 and 8u31, and cannot change to the newest version.
This commit will change the folder into _latest. Prepare for new installation script.
2017-09-08 18:56:24 +08:00

1445 lines
39 KiB
C++

#include <iostream>
#include <algorithm>
#include <sstream>
#include <fstream>
#include <vector>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <string>
#include <cstdarg>
#include <unistd.h>
#include <sys/file.h>
#include "uoj_env.h"
using namespace std;
/*====================== parameter ==================== */
struct RunLimit {
int time;
int memory;
int output;
RunLimit() {
}
RunLimit(const int &_time, const int &_memory, const int &_output)
: time(_time), memory(_memory), output(_output) {
}
};
const RunLimit RL_DEFAULT = RunLimit(1, 256, 64);
const RunLimit RL_JUDGER_DEFAULT = RunLimit(600, 1024, 128);
const RunLimit RL_CHECKER_DEFAULT = RunLimit(5, 256, 64);
const RunLimit RL_VALIDATOR_DEFAULT = RunLimit(5, 256, 64);
const RunLimit RL_MARKER_DEFAULT = RunLimit(5, 256, 64);
const RunLimit RL_COMPILER_DEFAULT = RunLimit(15, 512, 64);
struct PointInfo {
int num;
int scr;
int ust, usm;
string info, in, out, res;
PointInfo(const int &_num, const int &_scr,
const int &_ust, const int &_usm, const string &_info,
const string &_in, const string &_out, const string &_res)
: num(_num), scr(_scr),
ust(_ust), usm(_usm), info(_info),
in(_in), out(_out), res(_res) {
}
};
struct CustomTestInfo {
int ust, usm;
string info, exp, out;
CustomTestInfo(const int &_ust, const int &_usm, const string &_info,
const string &_exp, const string &_out)
: ust(_ust), usm(_usm), info(_info),
exp(_exp), out(_out) {
}
};
struct RunResult {
int type;
int ust, usm;
int exit_code;
static RunResult failed_result() {
RunResult res;
res.type = RS_JGF;
res.ust = -1;
res.usm = -1;
return res;
}
};
struct RunCheckerResult {
int type;
int ust, usm;
int scr;
string info;
static RunCheckerResult failed_result() {
RunCheckerResult res;
res.type = RS_JGF;
res.ust = -1;
res.usm = -1;
res.scr = 0;
res.info = "Checker Judgment Failed";
return res;
}
};
struct RunValidatorResult {
int type;
int ust, usm;
bool succeeded;
string info;
static RunValidatorResult failed_result() {
RunValidatorResult res;
res.type = RS_JGF;
res.ust = -1;
res.usm = -1;
res.succeeded = 0;
res.info = "Validator Judgment Failed";
return res;
}
};
struct RunCompilerResult {
int type;
int ust, usm;
bool succeeded;
string info;
static RunCompilerResult failed_result() {
RunCompilerResult res;
res.type = RS_JGF;
res.ust = -1;
res.usm = -1;
res.succeeded = false;
res.info = "Compile Failed";
return res;
}
};
int problem_id;
string main_path;
string work_path;
string data_path;
string result_path;
int tot_time = 0;
int max_memory = 0;
int tot_score = 0;
ostringstream details_out;
//vector<PointInfo> points_info;
map<string, string> config;
/*==================== parameter End ================== */
/*========================== execute ====================== */
string escapeshellarg(const string &arg) {
string res = "'";
for (size_t i = 0; i < arg.size(); i++) {
if (arg[i] == '\'') {
res += "'\\''";
} else {
res += arg[i];
}
}
res += "'";
return res;
}
string realpath(const string &path) {
char real[PATH_MAX + 1];
if (realpath(path.c_str(), real) == NULL) {
return "";
}
return real;
}
int execute(const char *cmd) {
return system(cmd);
}
int executef(const char *fmt, ...) {
const int MaxL = 512;
char cmd[MaxL];
va_list ap;
va_start(ap, fmt);
int res = vsnprintf(cmd, MaxL, fmt, ap);
if (res < 0 || res >= MaxL) {
return -1;
}
res = execute(cmd);
va_end(ap);
return res;
}
/*======================== execute End ==================== */
/*========================= file ====================== */
/*
bool file_exist(const string &name) {
return access(name.c_str(), F_OK);
}
*/
string file_preview(const string &name, const size_t &len = 100) {
FILE *f = fopen(name.c_str(), "r");
if (f == NULL) {
return "";
}
string res = "";
int c;
while (c = fgetc(f), c != EOF && res.size() < len + 4) {
res += c;
}
if (res.size() > len + 3) {
res.resize(len);
res += "...";
}
fclose(f);
return res;
}
void file_hide_token(const string &name, const string &token) {
executef("cp %s %s.bak", name.c_str(), name.c_str());
FILE *rf = fopen((name + ".bak").c_str(), "r");
FILE *wf = fopen(name.c_str(), "w");
int c;
for (int i = 0; i <= (int)token.length(); i++)
{
c = fgetc(rf);
if (c != (i < (int)token.length() ? token[i] : '\n'))
{
fprintf(wf, "Unauthorized output\n");
fclose(rf);
fclose(wf);
return;
}
}
while (c = fgetc(rf), c != EOF) {
fputc(c, wf);
}
fclose(rf);
fclose(wf);
}
/*
string read_file (FILE *file, const string &s, int t = (int) 1e9) {
int ch;
string res = "";
int l = t + 4;
while (ch = next(file), ch != EOF && l) res += ch, --l;
if ((int)res.size() > t + 3)
{
res.resize(t);
res += "...";
}
fclose(file);
if (res == "") return s;
return res;
}
string read_file (const string &name, const string &s, int t = (int) 1e9) {
if (file_exist(name)) return s;
return read_file(fopen(name.c_str(), "r"), s, t);
}
*/
/*
bool file_compare(const char *fileA, const char *fileB, const int &mark) {
FILE *A = fopen(fileA, "r");
FILE *B = fopen(fileB, "r");
int chA = 'a';
int chB = 'a';
bool result = true;
if (mark == 0) {
do if ((chA = fgetc(A)) != (chB = fgetc(B))) { result = false; break; }
while (chA != EOF && chB != EOF);
}
else {
do {
chA = fgetc(A);
if (chB != EOF) chB = fgetc(B);
if (chA == '\r') chA = fgetc(A);
if (chB == '\r') chB = fgetc(B);
if (chB == chA) continue;
if (chA == EOF) swap(chA, chB), swap(A, B);
if (chB == EOF) { if (chA != ' ' && chA != '\n') { result = false; break; } else continue; }
if (chB == '\n') swap(chA, chB), swap(A, B);
if (chA == '\n') {
while (chB == ' ') chB = fgetc(B);
if (chB == '\r') chB = fgetc(B);
if (chB == chA || chB == EOF) continue;
}
result = false; break;
}
while (chA != EOF);
}
fclose(A);
fclose(B);
return result;
}
bool file_compare(const string &fileA, const string &fileB, const int &mark) {
return file_compare(fileA.c_str(), fileB.c_str(), mark);
}*/
/*======================= file End ==================== */
/*====================== info print =================== */
template <class T>
inline string vtos(const T &v) {
ostringstream sout;
sout << v;
return sout.str();
}
inline string htmlspecialchars(const string &s) {
string r;
for (int i = 0; i < (int)s.length(); i++) {
switch (s[i]) {
case '&' : r += "&amp;"; break;
case '<' : r += "&lt;"; break;
case '>' : r += "&gt;"; break;
case '"' : r += "&quot;"; break;
case '\0': r += "<b>\\0</b>"; break;
default : r += s[i]; break;
}
}
return r;
}
inline string info_str(int id) {
switch (id) {
case RS_MLE: return "Memory Limit Exceeded";
case RS_TLE: return "Time Limit Exceeded";
case RS_OLE: return "Output Limit Exceeded";
case RS_RE : return "Runtime Error";
case RS_DGS: return "Dangerous Syscalls";
case RS_JGF: return "Judgment Failed";
/*
case RS_SPJ_RE : return "Special Judge Runtime Error";
case RS_SPJ_MLE: return "Special Judge Memory Limit Exceeded";
case RS_SPJ_OLE: return "Special Judge Output Limit Exceeded";
case RS_SPJ_TLE: return "Special Judge Time Limit Exceeded";
case RS_SPJ_DGS: return "Special Judge Dangerous Syscalls";
case RS_SPJ_JGF: return "Special Judge Judgement Failed";
case RS_HK_MLE: return "Hack Successfully : Memory Limit Exceeded";
case RS_HK_TLE: return "Hack Successfully : Time Limit Exceeded";
case RS_HK_OLE: return "Hack Successfully : Output LImit Exceeded";
case RS_HK_RE: return "Hack Successfully : Runtime Error";
case RS_HK_DGS: return "Hack Successfully : Dangerous Syscalls";
case RS_HK_JGF: return "Hack Successfully : Judgement Failed";
case RS_HK_SPJ_RE: return "Hack Successfully : Special Judge Runtime Error";
case RS_HK_SPJ_MLE: return "Hack Successfully : Special Judge Memory Limit Exceeded";
case RS_HK_SPJ_OLE: return "Hack Successfully : Special Judge Output Limit Exceeded";
case RS_HK_SPJ_TLE: return "Hack Successfully : Special Judge Time Limit Exceeded";
case RS_HK_SPJ_DGS: return "Hack Successfully : Special Judge Dangerous Syscalls";
case RS_HK_SPJ_JGF: return "Hack Successfully : Special Judge Judgement Failed";
*/
default : return "Unknown Result";
}
}
inline string info_str(const RunResult &p) {
return info_str(p.type);
}
void add_point_info(const PointInfo &info) {
if (info.num >= 0) {
if(info.ust >= 0) {
tot_time += info.ust;
}
if(info.usm >= 0) {
max_memory = max(max_memory, info.usm);
}
}
tot_score += info.scr;
details_out << "<test num=\"" << info.num << "\""
<< " score=\"" << info.scr << "\""
<< " info=\"" << htmlspecialchars(info.info) << "\""
<< " time=\"" << info.ust << "\""
<< " memory=\"" << info.usm << "\">" << endl;
details_out << "<in>" << htmlspecialchars(info.in) << "</in>" << endl;
details_out << "<out>" << htmlspecialchars(info.out) << "</out>" << endl;
details_out << "<res>" << htmlspecialchars(info.res) << "</res>" << endl;
details_out << "</test>" << endl;
}
void add_custom_test_info(const CustomTestInfo &info) {
if(info.ust >= 0) {
tot_time += info.ust;
}
if(info.usm >= 0) {
max_memory = max(max_memory, info.usm);
}
details_out << "<custom-test info=\"" << htmlspecialchars(info.info) << "\""
<< " time=\"" << info.ust << "\""
<< " memory=\"" << info.usm << "\">" << endl;
if (!info.exp.empty()) {
details_out << info.exp << endl;
}
details_out << "<out>" << htmlspecialchars(info.out) << "</out>" << endl;
details_out << "</custom-test>" << endl;
}
void add_subtask_info(const int &num, const int &scr, const string &info, const vector<PointInfo> &points) {
details_out << "<subtask num=\"" << num << "\""
<< " score=\"" << scr << "\""
<< " info=\"" << htmlspecialchars(info) << "\">" << endl;
for (vector<PointInfo>::const_iterator it = points.begin(); it != points.end(); it++) {
add_point_info(*it);
}
details_out << "</subtask>" << endl;
}
void end_judge_ok() {
FILE *fres = fopen((result_path + "/result.txt").c_str(), "w");
fprintf(fres, "score %d\n", tot_score);
fprintf(fres, "time %d\n", tot_time);
fprintf(fres, "memory %d\n", max_memory);
fprintf(fres, "details\n");
fprintf(fres, "<tests>\n");
fprintf(fres, "%s", details_out.str().c_str());
fprintf(fres, "</tests>\n");
fclose(fres);
exit(0);
}
void end_judge_judgement_failed(const string &info) {
FILE *fres = fopen((result_path + "/result.txt").c_str(), "w");
fprintf(fres, "error Judgment Failed\n");
fprintf(fres, "details\n");
fprintf(fres, "<error>%s</error>\n", htmlspecialchars(info).c_str());
fclose(fres);
exit(1);
}
void end_judge_compile_error(const RunCompilerResult &res) {
FILE *fres = fopen((result_path + "/result.txt").c_str(), "w");
fprintf(fres, "error Compile Error\n");
fprintf(fres, "details\n");
fprintf(fres, "<error>%s</error>\n", htmlspecialchars(res.info).c_str());
fclose(fres);
exit(0);
}
/*
void put_info(int num, int scr, int ust, int usm, const char *s, const char *in, const char *out, const char *res) {
return put_info(num, scr, ust, usm, string(s), string(in), string(out), string(res));
}
void put_info(int num, int scr, const string &s, const string &in, const string &out, const string &res) {
return put_info(num, scr, -1, -1, s, in, out, res);
}
void put_info(int num, int scr, const char *s, const char *in, const char *out, const char *res) {
return put_info(num, scr, -1, -1, string(s), string(in), string(out), string(res));
}
void end_info(int scr) {
return put_info(0, scr, -1, -1, "", "", "", "");
}
*/
void report_judge_status(const char *status) {
FILE *f = fopen((result_path + "/cur_status.txt").c_str(), "a");
if (f == NULL) {
return;
}
if (flock(fileno(f), LOCK_EX) != -1) {
if (ftruncate(fileno(f), 0) != -1) {
fprintf(f, "%s\n", status);
fflush(f);
}
flock(fileno(f), LOCK_UN);
}
fclose(f);
}
bool report_judge_status_f(const char *fmt, ...) {
const int MaxL = 512;
char status[MaxL];
va_list ap;
va_start(ap, fmt);
int res = vsnprintf(status, MaxL, fmt, ap);
if (res < 0 || res >= MaxL) {
return false;
}
report_judge_status(status);
va_end(ap);
return true;
}
/*==================== info print End ================= */
/*====================== config set =================== */
void print_config() {
for (map<string, string>::iterator it = config.begin(); it != config.end(); ++it) {
cerr << it->first << " = " << it->second << endl;
}
}
void load_config(const string &filename) {
ifstream fin(filename.c_str());
if (!fin) {
return;
}
string key;
string val;
while (fin >> key >> val) {
config[key] = val;
}
}
string conf_str(const string &key, int num, const string &val) {
ostringstream sout;
sout << key << "_" << num;
if (config.count(sout.str()) == 0) {
return val;
}
return config[sout.str()];
}
string conf_str(const string &key, const string &val) {
if (config.count(key) == 0) {
return val;
}
return config[key];
}
string conf_str(const string &key) {
return conf_str(key, "");
}
int conf_int(const string &key, const int &val) {
if (config.count(key) == 0) {
return val;
}
return atoi(config[key].c_str());
}
int conf_int(const string &key, int num, const int &val) {
ostringstream sout;
sout << key << "_" << num;
if (config.count(sout.str()) == 0) {
return conf_int(key, val);
}
return atoi(config[sout.str()].c_str());
}
int conf_int(const string &key) {
return conf_int(key, 0);
}
string conf_input_file_name(int num) {
ostringstream name;
if (num < 0) {
name << "ex_";
}
name << conf_str("input_pre", "input") << abs(num) << "." << conf_str("input_suf", "txt");
return name.str();
}
string conf_output_file_name(int num) {
ostringstream name;
if (num < 0) {
name << "ex_";
}
name << conf_str("output_pre", "output") << abs(num) << "." << conf_str("output_suf", "txt");
return name.str();
}
RunLimit conf_run_limit(string pre, const int &num, const RunLimit &val) {
if (!pre.empty()) {
pre += "_";
}
RunLimit limit;
limit.time = conf_int(pre + "time_limit", num, val.time);
limit.memory = conf_int(pre + "memory_limit", num, val.memory);
limit.output = conf_int(pre + "output_limit", num, val.output);
return limit;
}
RunLimit conf_run_limit(const int &num, const RunLimit &val) {
return conf_run_limit("", num, val);
}
void conf_add(const string &key, const string &val) {
if (config.count(key)) return;
config[key] = val;
}
bool conf_has(const string &key) {
return config.count(key) != 0;
}
bool conf_is(const string &key, const string &val) {
if (config.count(key) == 0) return false;
return config[key] == val;
}
/*==================== config set End ================= */
/*========================== run ====================== */
struct RunProgramConfig {
vector<string> readable_file_names; // other than stdin
string result_file_name;
string input_file_name;
string output_file_name;
string error_file_name;
string type;
string work_path;
RunLimit limit;
vector<string> argv;
RunProgramConfig() {
int p = 1;
while (conf_str("readable", p, "") != "") {
readable_file_names.push_back(conf_str("readable", p, ""));
p++;
}
result_file_name = result_path + "/run_program_result.txt";
type = "default";
work_path = ::work_path;
for (vector<string>::iterator it = readable_file_names.begin(); it != readable_file_names.end(); it++) {
if (!it->empty() && (*it)[0] != '/') {
*it = ::work_path + "/" + *it;
}
}
}
void set_argv(const char *program_name, ...) {
argv.clear();
argv.push_back(program_name);
va_list vl;
va_start(vl, program_name);
for (const char *arg = va_arg(vl, const char *); arg; arg = va_arg(vl, const char *)) {
argv.push_back(arg);
}
va_end(vl);
}
};
RunResult vrun_program(
const char *run_program_result_file_name,
const char *input_file_name,
const char *output_file_name,
const char *error_file_name,
const RunLimit &limit,
const vector<string> &rest) {
ostringstream sout;
sout << main_path << "/run/run_program"
<< " " << ">" << escapeshellarg(run_program_result_file_name)
<< " " << "--in=" << escapeshellarg(input_file_name)
<< " " <<"--out=" << escapeshellarg(output_file_name)
<< " " << "--err=" << escapeshellarg(error_file_name)
<< " " << "--tl=" << limit.time
<< " " << "--ml=" << limit.memory
<< " " << "--ol=" << limit.output
/*<< " " << "--show-trace-details"*/;
for (vector<string>::const_iterator it = rest.begin(); it != rest.end(); it++) {
sout << " " << escapeshellarg(*it);
}
RunResult res;
if (execute(sout.str().c_str()) != 0) {
return RunResult::failed_result();
}
FILE *fres = fopen(run_program_result_file_name, "r");
if (fres != NULL && fscanf(fres, "%d %d %d %d", &res.type, &res.ust, &res.usm, &res.exit_code) != 4) {
return RunResult::failed_result();
}
fclose(fres);
return res;
}
RunResult run_program(const RunProgramConfig &rpc) {
ostringstream sout;
sout << main_path << "/run/run_program"
<< " " << ">" << escapeshellarg(rpc.result_file_name)
<< " " << "--in=" << escapeshellarg(rpc.input_file_name)
<< " " <<"--out=" << escapeshellarg(rpc.output_file_name)
<< " " << "--err=" << escapeshellarg(rpc.error_file_name)
<< " " << "--tl=" << rpc.limit.time
<< " " << "--ml=" << rpc.limit.memory
<< " " << "--ol=" << rpc.limit.output
<< " " << "--type=" << rpc.type
<< " " << "--work-path=" << rpc.work_path;
for (vector<string>::const_iterator it = rpc.readable_file_names.begin(); it != rpc.readable_file_names.end(); it++) {
sout << " " << "--add-readable=" << escapeshellarg(*it);
}
for (vector<string>::const_iterator it = rpc.argv.begin(); it != rpc.argv.end(); it++) {
sout << " " << escapeshellarg(*it);
}
RunResult res;
if (execute(sout.str().c_str()) != 0) {
return RunResult::failed_result();
}
FILE *fres = fopen(rpc.result_file_name.c_str(), "r");
if (fres != NULL && fscanf(fres, "%d %d %d %d", &res.type, &res.ust, &res.usm, &res.exit_code) != 4) {
return RunResult::failed_result();
}
fclose(fres);
return res;
}
RunResult run_program(
const char *run_program_result_file_name,
const char *input_file_name,
const char *output_file_name,
const char *error_file_name,
const RunLimit &limit, ...) {
vector<string> argv;
va_list vl;
va_start(vl, limit);
for (const char *arg = va_arg(vl, const char *); arg; arg = va_arg(vl, const char *)) {
argv.push_back(arg);
}
va_end(vl);
return vrun_program(run_program_result_file_name,
input_file_name,
output_file_name,
error_file_name,
limit,
argv);
}
RunValidatorResult run_validator(
const string &input_file_name,
const RunLimit &limit,
const string &program_name) {
RunResult ret = run_program(
(string(result_path) + "/run_validator_result.txt").c_str(),
input_file_name.c_str(),
"/dev/null",
(string(result_path) + "/validator_error.txt").c_str(),
limit,
program_name.c_str(),
NULL);
RunValidatorResult res;
res.type = ret.type;
res.ust = ret.ust;
res.usm = ret.usm;
if (ret.type != RS_AC || ret.exit_code != 0) {
res.succeeded = false;
res.info = file_preview(result_path + "/validator_error.txt");
} else {
res.succeeded = true;
}
return res;
}
RunCheckerResult run_checker(
const RunLimit &limit,
const string &program_name,
const string &input_file_name,
const string &output_file_name,
const string &answer_file_name) {
RunResult ret = run_program(
(string(result_path) + "/run_checker_result.txt").c_str(),
"/dev/null",
"/dev/null",
(string(result_path) + "/checker_error.txt").c_str(),
limit,
("--add-readable=" + input_file_name).c_str(),
("--add-readable=" + output_file_name).c_str(),
("--add-readable=" + answer_file_name).c_str(),
program_name.c_str(),
realpath(input_file_name).c_str(),
realpath(output_file_name).c_str(),
realpath(answer_file_name).c_str(),
NULL);
RunCheckerResult res;
res.type = ret.type;
res.ust = ret.ust;
res.usm = ret.usm;
if (ret.type != RS_AC) {
res.scr = 0;
} else {
FILE *fres = fopen((result_path + "/checker_error.txt").c_str(), "r");
char type[21];
if (fres == NULL || fscanf(fres, "%20s", type) != 1) {
return RunCheckerResult::failed_result();
}
if (strcmp(type, "ok") == 0) {
res.scr = 100;
} else if (strcmp(type, "points") == 0) {
double d;
if (fscanf(fres, "%lf", &d) != 1) {
return RunCheckerResult::failed_result();
} else {
res.scr = (int)floor(100 * d + 0.5);
}
} else {
res.scr = 0;
}
fclose(fres);
}
res.info = file_preview(result_path + "/checker_error.txt");
return res;
}
RunCompilerResult run_compiler(const char *path, ...) {
vector<string> argv;
argv.push_back("--type=compiler");
argv.push_back(string("--work-path=") + path);
va_list vl;
va_start(vl, path);
for (const char *arg = va_arg(vl, const char *); arg; arg = va_arg(vl, const char *)) {
argv.push_back(arg);
}
va_end(vl);
RunResult ret = vrun_program(
(result_path + "/run_compiler_result.txt").c_str(),
"/dev/null",
"stderr",
(result_path + "/compiler_result.txt").c_str(),
RL_COMPILER_DEFAULT,
argv);
RunCompilerResult res;
res.type = ret.type;
res.ust = ret.ust;
res.usm = ret.usm;
res.succeeded = ret.type == RS_AC && ret.exit_code == 0;
if (!res.succeeded) {
if (ret.type == RS_AC) {
res.info = file_preview(result_path + "/compiler_result.txt", 500);
} else if (ret.type == RS_JGF) {
res.info = "No Comment";
} else {
res.info = "Compiler " + info_str(ret.type);
}
}
return res;
}
RunResult run_submission_program(
const string &input_file_name,
const string &output_file_name,
const RunLimit &limit,
const string &name,
RunProgramConfig rpc = RunProgramConfig()) {
string lang = conf_str(string(name) + "_language");
string program_type = "default";
string program_name = name;
if (lang == "Python2.7") {
program_type = "python2.7";
} else if (lang == "Python3") {
program_type = "python3.4";
} else if (lang == "Java7") {
program_name += "." + conf_str(name + "_main_class");
program_type = "java7u76";
} else if (lang == "Java8") {
program_name += "." + conf_str(name + "_main_class");
program_type = "java8u31";
}
rpc.result_file_name = result_path + "/run_submission_program.txt";
rpc.input_file_name = input_file_name;
rpc.output_file_name = output_file_name;
rpc.error_file_name = "/dev/null";
rpc.limit = limit;
rpc.type = program_type;
rpc.set_argv(program_name.c_str(), NULL);
RunResult res = run_program(rpc);
if (res.type == RS_AC && res.exit_code != 0) {
res.type = RS_RE;
}
return res;
}
void prepare_run_standard_program() {
string data_path_std = data_path + "/std";
string work_path_std = work_path + "/std";
executef("cp %s %s", data_path_std.c_str(), work_path_std.c_str());
conf_add("std_language", "C++");
}
RunResult run_standard_program(
const string &input_file_name,
const string &output_file_name,
const RunLimit &limit,
RunProgramConfig rpc = RunProgramConfig()) {
rpc.result_file_name = result_path + "/run_standard_program.txt";
return run_submission_program(
input_file_name,
output_file_name,
limit,
"std",
rpc);
}
/*======================== run End ==================== */
/*======================== compile ==================== */
bool is_illegal_keyword(const string &name) {
if (name == "__asm" || name == "__asm__" || name == "asm")
return true;
return false;
}
bool has_illegal_keywords_in_file(const string &name) {
FILE *f = fopen(name.c_str(), "r");
int c;
string key;
while ((c = fgetc(f)) != EOF)
{
if (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_')
{
if (key.size() < 20)
key += c;
else
{
if (is_illegal_keyword(key))
return true;
key.erase(key.begin());
key += c;
}
}
else
{
if (is_illegal_keyword(key))
return true;
key.clear();
}
}
if (is_illegal_keyword(key))
return true;
fclose(f);
return false;
}
RunCompilerResult prepare_java_source(const string &name, const string &path = work_path) {
FILE *f = fopen((path + "/" + name + ".code").c_str(), "r");
const int L = 1024;
std::string s;
char buf[L + 1];
int mode = 0;
while (!feof(f)) {
buf[fread(buf, 1, L, f)] = '\0';
for (char *p = buf; *p; p++) {
s += *p;
switch (mode) {
case 0:
switch (*p) {
case '/':
mode = 1;
break;
case '\'':
mode = 5;
break;
case '\"':
mode = 6;
break;
}
break;
case 1:
switch (*p) {
case '/':
mode = 2;
s.resize(s.length() - 2);
break;
case '*':
mode = 3;
s.resize(s.length() - 2);
break;
}
break;
case 2:
s.resize(s.length() - 1);
switch (*p) {
case '\n':
s += '\n';
mode = 0;
break;
}
break;
case 3:
s.resize(s.length() - 1);
switch (*p) {
case '*':
mode = 4;
break;
}
break;
case 4:
s.resize(s.length() - 1);
switch (*p) {
case '/':
s += ' ';
mode = 0;
break;
}
break;
case 5:
switch (*p) {
case '\'':
mode = 0;
break;
case '\\':
mode = 7;
break;
}
case 6:
switch (*p) {
case '\"':
mode = 0;
break;
case '\\':
mode = 8;
break;
}
case 7:
mode = 5;
break;
case 8:
mode = 6;
break;
}
}
}
bool valid[256];
fill(valid, valid + 256, false);
for (int c = 'a'; c <= 'z'; c++)
valid[c] = true;
for (int c = 'A'; c <= 'Z'; c++)
valid[c] = true;
valid['.'] = true;
valid['_'] = true;
vector<string> tokens;
for (int p = 0, np = 0; p < (int)s.length(); p = np) {
while (np < (int)s.length() && valid[(unsigned char)s[np]]) {
np++;
}
if (np == p) {
np++;
} else {
tokens.push_back(s.substr(p, np - p));
}
}
if (tokens.size() > 0 && tokens[0] == "package") {
RunCompilerResult res;
res.type = RS_WA;
res.ust = -1;
res.usm = -1;
res.succeeded = false;
res.info = "Please don't specify the package.";
return res;
}
for (int i = 0; i + 1 < (int)tokens.size(); i++) {
if (tokens[i] == "class") {
if (tokens[i + 1].length() <= 100) {
config[name + "_main_class"] = tokens[i + 1];
RunCompilerResult res;
res.type = RS_AC;
res.ust = 0;
res.usm = 0;
res.succeeded = true;
return res;
} else {
RunCompilerResult res;
res.type = RS_WA;
res.ust = -1;
res.usm = -1;
res.succeeded = false;
res.info = "The name of the main class is too long.";
return res;
}
}
}
RunCompilerResult res;
res.type = RS_WA;
res.ust = -1;
res.usm = -1;
res.succeeded = false;
res.info = "Can't find the main class.";
return res;
}
RunCompilerResult compile_c(const string &name, const string &path = work_path) {
return run_compiler(path.c_str(),
"/usr/bin/gcc-4.8", "-o", name.c_str(), "-x", "c", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", NULL);
}
RunCompilerResult compile_pas(const string &name, const string &path = work_path) {
return run_compiler(path.c_str(),
"/usr/bin/fpc-2.6.2", (name + ".code").c_str(), "-O2", NULL);
}
RunCompilerResult compile_cpp(const string &name, const string &path = work_path) {
return run_compiler(path.c_str(),
"/usr/bin/g++-4.8", "-o", name.c_str(), "-x", "c++", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", NULL);
}
RunCompilerResult compile_cpp11(const string &name, const string &path = work_path) {
return run_compiler(path.c_str(),
"/usr/bin/g++-4.8", "-o", name.c_str(), "-x", "c++", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", "-std=c++11", NULL);
}
RunCompilerResult compile_python2_7(const string &name, const string &path = work_path) {
return run_compiler(path.c_str(),
"/usr/bin/python2.7", "-E", "-s", "-B", "-O", "-c",
("import py_compile\nimport sys\ntry:\n py_compile.compile('" + name + ".code'" + ", '" + name + "', doraise=True)\n sys.exit(0)\nexcept Exception as e:\n print e\n sys.exit(1)").c_str(), NULL);
}
RunCompilerResult compile_python3(const string &name, const string &path = work_path) {
return run_compiler(path.c_str(),
"/usr/bin/python3.4", "-I", "-B", "-O", "-c", ("import py_compile\nimport sys\ntry:\n py_compile.compile('" + name + ".code'" + ", '" + name + "', doraise=True)\n sys.exit(0)\nexcept Exception as e:\n print(e)\n sys.exit(1)").c_str(), NULL);
}
RunCompilerResult compile_java7(const string &name, const string &path = work_path) {
RunCompilerResult ret = prepare_java_source(name, path);
if (!ret.succeeded)
return ret;
string main_class = conf_str(name + "_main_class");
executef("rm %s/%s -rf 2>/dev/null; mkdir %s/%s", path.c_str(), name.c_str(), path.c_str(), name.c_str());
executef("echo package %s\\; | cat - %s/%s.code >%s/%s/%s.java", name.c_str(), path.c_str(), name.c_str(), path.c_str(), name.c_str(), main_class.c_str());
return run_compiler((path + "/" + name).c_str(),
(main_path + "/run/runtime/jdk1.7.0_latest/bin/javac").c_str(), (main_class + ".java").c_str(), NULL);
}
RunCompilerResult compile_java8(const string &name, const string &path = work_path) {
RunCompilerResult ret = prepare_java_source(name, path);
if (!ret.succeeded)
return ret;
string main_class = conf_str(name + "_main_class");
executef("rm %s/%s -rf 2>/dev/null; mkdir %s/%s", path.c_str(), name.c_str(), path.c_str(), name.c_str());
executef("echo package %s\\; | cat - %s/%s.code >%s/%s/%s.java", name.c_str(), path.c_str(), name.c_str(), path.c_str(), name.c_str(), main_class.c_str());
return run_compiler((path + "/" + name).c_str(),
(main_path + "/run/runtime/jdk1.8.0_latest/bin/javac").c_str(), (main_class + ".java").c_str(), NULL);
}
RunCompilerResult compile(const char *name) {
string lang = conf_str(string(name) + "_language");
if ((lang == "C++" || lang == "C++11" || lang == "C") && has_illegal_keywords_in_file(work_path + "/" + name + ".code"))
{
RunCompilerResult res;
res.type = RS_DGS;
res.ust = -1;
res.usm = -1;
res.succeeded = false;
res.info = "Compile Failed";
return res;
}
if (lang == "C++") {
return compile_cpp(name);
}
if (lang == "C++11") {
return compile_cpp11(name);
}
if (lang == "Python2.7") {
return compile_python2_7(name);
}
if (lang == "Python3") {
return compile_python3(name);
}
if (lang == "Java7") {
return compile_java7(name);
}
if (lang == "Java8") {
return compile_java8(name);
}
if (lang == "C") {
return compile_c(name);
}
if (lang == "Pascal") {
return compile_pas(name);
}
RunCompilerResult res = RunCompilerResult::failed_result();
res.info = "This language is not supported yet.";
return res;
}
RunCompilerResult compile_c_with_implementer(const string &name, const string &path = work_path) {
return run_compiler(path.c_str(),
"/usr/bin/gcc-4.8", "-o", name.c_str(), "implementer.c", "-x", "c", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", NULL);
}
RunCompilerResult compile_pas_with_implementer(const string &name, const string &path = work_path) {
executef("cp %s %s", (path + "/" + name + ".code").c_str(), (path + "/" + conf_str(name + "_unit_name") + ".pas").c_str());
return run_compiler(path.c_str(),
"/usr/bin/fpc-2.6.2", "implementer.pas", ("-o" + name).c_str(), "-O2", NULL);
}
RunCompilerResult compile_cpp_with_implementer(const string &name, const string &path = work_path) {
return run_compiler(path.c_str(),
"/usr/bin/g++-4.8", "-o", name.c_str(), "implementer.cpp", "-x", "c++", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", NULL);
}
RunCompilerResult compile_cpp11_with_implementer(const string &name, const string &path = work_path) {
return run_compiler(path.c_str(),
"/usr/bin/g++-4.8", "-o", name.c_str(), "implementer.cpp", "-x", "c++", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", "-std=c++11", NULL);
}
/*
RunCompilerResult compile_python2_7(const string &name, const string &path = work_path) {
return run_compiler(path.c_str(),
"/usr/bin/python2.7", "-E", "-s", "-B", "-O", "-c",
("import py_compile\nimport sys\ntry:\n py_compile.compile('" + name + ".code'" + ", '" + name + "', doraise=True)\n sys.exit(0)\nexcept Exception as e:\n print e\n sys.exit(1)").c_str(), NULL);
}
RunCompilerResult compile_python3(const string &name, const string &path = work_path) {
return run_compiler(path.c_str(),
"/usr/bin/python3.4", "-I", "-B", "-O", "-c", ("import py_compile\nimport sys\ntry:\n py_compile.compile('" + name + ".code'" + ", '" + name + "', doraise=True)\n sys.exit(0)\nexcept Exception as e:\n print(e)\n sys.exit(1)").c_str(), NULL);
}
*/
RunCompilerResult compile_with_implementer(const char *name) {
string lang = conf_str(string(name) + "_language");
if (has_illegal_keywords_in_file(work_path + "/" + name + ".code"))
{
RunCompilerResult res;
res.type = RS_DGS;
res.ust = -1;
res.usm = -1;
res.succeeded = false;
res.info = "Compile Failed";
return res;
}
if (lang == "C++") {
return compile_cpp_with_implementer(name);
}
if (lang == "C++11") {
return compile_cpp11_with_implementer(name);
}
if (lang == "C") {
return compile_c_with_implementer(name);
}
if (lang == "Pascal") {
return compile_pas_with_implementer(name);
}
RunCompilerResult res = RunCompilerResult::failed_result();
res.info = "This language is not supported yet.";
return res;
}
/*====================== compile End ================== */
/*====================== test ================== */
struct TestPointConfig {
int submit_answer;
int validate_input_before_test;
string input_file_name;
string output_file_name;
string answer_file_name;
TestPointConfig()
: submit_answer(-1), validate_input_before_test(-1) {
}
void auto_complete(int num) {
if (submit_answer == -1) {
submit_answer = conf_is("submit_answer", "on");
}
if (validate_input_before_test == -1) {
validate_input_before_test = conf_is("validate_input_before_test", "on");
}
if (input_file_name.empty()) {
input_file_name = data_path + "/" + conf_input_file_name(num);
}
if (output_file_name.empty()) {
output_file_name = work_path + "/" + conf_output_file_name(num);
}
if (answer_file_name.empty()) {
answer_file_name = data_path + "/" + conf_output_file_name(num);
}
}
};
PointInfo test_point(const string &name, const int &num, TestPointConfig tpc = TestPointConfig()) {
tpc.auto_complete(num);
if (tpc.validate_input_before_test) {
RunValidatorResult val_ret = run_validator(
tpc.input_file_name,
conf_run_limit("validator", 0, RL_VALIDATOR_DEFAULT),
conf_str("validator"));
if (val_ret.type != RS_AC) {
return PointInfo(num, 0, -1, -1,
"Validator " + info_str(val_ret.type),
file_preview(tpc.input_file_name), "",
"");
} else if (!val_ret.succeeded) {
return PointInfo(num, 0, -1, -1,
"Invalid Input",
file_preview(tpc.input_file_name), "",
val_ret.info);
}
}
RunResult pro_ret;
if (!tpc.submit_answer) {
pro_ret = run_submission_program(
tpc.input_file_name.c_str(),
tpc.output_file_name.c_str(),
conf_run_limit(num, RL_DEFAULT),
name);
if (conf_has("token")) {
file_hide_token(tpc.output_file_name, conf_str("token", ""));
}
if (pro_ret.type != RS_AC) {
return PointInfo(num, 0, -1, -1,
info_str(pro_ret.type),
file_preview(tpc.input_file_name), file_preview(tpc.output_file_name),
"");
}
} else {
pro_ret.type = RS_AC;
pro_ret.ust = -1;
pro_ret.usm = -1;
pro_ret.exit_code = 0;
}
RunCheckerResult chk_ret = run_checker(
conf_run_limit("checker", num, RL_CHECKER_DEFAULT),
conf_str("checker"),
tpc.input_file_name,
tpc.output_file_name,
tpc.answer_file_name);
if (chk_ret.type != RS_AC) {
return PointInfo(num, 0, -1, -1,
"Checker " + info_str(chk_ret.type),
file_preview(tpc.input_file_name), file_preview(tpc.output_file_name),
"");
}
string info;
if (chk_ret.scr == 0) {
info = "Wrong Answer";
} else if (chk_ret.scr == 100) {
info = "Accepted";
} else {
info = "Acceptable Answer";
}
return PointInfo(num, chk_ret.scr, pro_ret.ust, pro_ret.usm,
info,
file_preview(tpc.input_file_name), file_preview(tpc.output_file_name),
chk_ret.info);
}
PointInfo test_hack_point(const string &name, TestPointConfig tpc) {
tpc.submit_answer = false;
tpc.validate_input_before_test = false;
tpc.auto_complete(0);
RunValidatorResult val_ret = run_validator(
tpc.input_file_name,
conf_run_limit("validator", 0, RL_VALIDATOR_DEFAULT),
conf_str("validator"));
if (val_ret.type != RS_AC) {
return PointInfo(0, 0, -1, -1,
"Validator " + info_str(val_ret.type),
file_preview(tpc.input_file_name), "",
"");
} else if (!val_ret.succeeded) {
return PointInfo(0, 0, -1, -1,
"Invalid Input",
file_preview(tpc.input_file_name), "",
val_ret.info);
}
RunResult std_ret = run_standard_program(
tpc.input_file_name,
tpc.answer_file_name,
conf_run_limit(0, RL_DEFAULT));
if (std_ret.type != RS_AC) {
return PointInfo(0, 0, -1, -1,
"Standard Program " + info_str(std_ret.type),
file_preview(tpc.input_file_name), "",
"");
}
if (conf_has("token")) {
file_hide_token(tpc.answer_file_name, conf_str("token", ""));
}
PointInfo po = test_point(name, 0, tpc);
po.scr = po.scr != 100;
return po;
}
CustomTestInfo ordinary_custom_test(const string &name) {
RunLimit lim = conf_run_limit(0, RL_DEFAULT);
lim.time += 2;
string input_file_name = work_path + "/input.txt";
string output_file_name = work_path + "/output.txt";
RunResult pro_ret = run_submission_program(
input_file_name,
output_file_name,
lim,
name);
if (conf_has("token")) {
file_hide_token(output_file_name, conf_str("token", ""));
}
string info;
if (pro_ret.type == RS_AC) {
info = "Success";
} else {
info = info_str(pro_ret.type);
}
string exp;
if (pro_ret.type == RS_TLE) {
exp = "<p>[<strong>time limit:</strong> " + vtos(lim.time) + "s]</p>";
}
return CustomTestInfo(pro_ret.ust, pro_ret.usm,
info, exp, file_preview(output_file_name, 2048));
}
int scale_score(int scr100, int full) {
return scr100 * full / 100;
}
/*====================== test End ================== */
/*======================= conf init =================== */
void main_judger_init(int argc, char **argv) {
main_path = UOJ_WORK_PATH;
work_path = main_path + "/work";
result_path = string(UOJ_RESULT_PATH);
load_config(work_path + "/submission.conf");
problem_id = conf_int("problem_id");
data_path = string(UOJ_DATA_PATH) + "/" + conf_str("problem_id");
load_config(data_path + "/problem.conf");
executef("cp %s/require/* %s 2>/dev/null", data_path.c_str(), work_path.c_str());
if (conf_is("use_builtin_judger", "on")) {
config["judger"] = string(UOJ_WORK_PATH) + "/builtin/judger/judger";
} else {
config["judger"] = data_path + "/judger";
}
}
void judger_init(int argc, char **argv) {
if (argc != 5) {
exit(1);
}
main_path = argv[1];
work_path = argv[2];
result_path = argv[3];
data_path = argv[4];
load_config(work_path + "/submission.conf");
problem_id = conf_int("problem_id");
load_config(data_path + "/problem.conf");
if (config.count("use_builtin_checker")) {
config["checker"] = main_path + "/builtin/checker/" + config["use_builtin_checker"];
} else {
config["checker"] = data_path + "/chk";
}
config["validator"] = data_path + "/val";
}
/*===================== conf init End ================= */