uoj_judger.h 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590
  1. #include <iostream>
  2. #include <algorithm>
  3. #include <sstream>
  4. #include <fstream>
  5. #include <vector>
  6. #include <set>
  7. #include <map>
  8. #include <cstdio>
  9. #include <cstdlib>
  10. #include <climits>
  11. #include <cmath>
  12. #include <cstdlib>
  13. #include <ctime>
  14. #include <cstring>
  15. #include <string>
  16. #include <cstdarg>
  17. #include <unistd.h>
  18. #include <sys/file.h>
  19. #include <sys/wait.h>
  20. #include "uoj_env.h"
  21. using namespace std;
  22. /*========================== execute ====================== */
  23. string escapeshellarg(const string &arg) {
  24. string res = "'";
  25. for (size_t i = 0; i < arg.size(); i++) {
  26. if (arg[i] == '\'') {
  27. res += "'\\''";
  28. } else {
  29. res += arg[i];
  30. }
  31. }
  32. res += "'";
  33. return res;
  34. }
  35. string realpath(const string &path) {
  36. char real[PATH_MAX + 1];
  37. if (realpath(path.c_str(), real) == NULL) {
  38. return "";
  39. }
  40. return real;
  41. }
  42. int execute(const char *cmd) {
  43. return system(cmd);
  44. }
  45. int executef(const char *fmt, ...) {
  46. const int MaxL = 512;
  47. char cmd[MaxL];
  48. va_list ap;
  49. va_start(ap, fmt);
  50. int res = vsnprintf(cmd, MaxL, fmt, ap);
  51. if (res < 0 || res >= MaxL) {
  52. return -1;
  53. }
  54. res = execute(cmd);
  55. va_end(ap);
  56. return res;
  57. }
  58. /*======================== execute End ==================== */
  59. /*========================= file ====================== */
  60. string file_preview(const string &name, const size_t &len = 100) {
  61. FILE *f = fopen(name.c_str(), "r");
  62. if (f == NULL) {
  63. return "";
  64. }
  65. string res = "";
  66. int c;
  67. while (c = fgetc(f), c != EOF && res.size() < len + 4) {
  68. res += c;
  69. }
  70. if (res.size() > len + 3) {
  71. res.resize(len);
  72. res += "...";
  73. }
  74. fclose(f);
  75. return res;
  76. }
  77. void file_hide_token(const string &name, const string &token) {
  78. executef("cp %s %s.bak", name.c_str(), name.c_str());
  79. FILE *rf = fopen((name + ".bak").c_str(), "r");
  80. FILE *wf = fopen(name.c_str(), "w");
  81. int c;
  82. for (int i = 0; i <= (int)token.length(); i++)
  83. {
  84. c = fgetc(rf);
  85. if (c != (i < (int)token.length() ? token[i] : '\n'))
  86. {
  87. fprintf(wf, "Unauthorized output\n");
  88. fclose(rf);
  89. fclose(wf);
  90. return;
  91. }
  92. }
  93. while (c = fgetc(rf), c != EOF) {
  94. fputc(c, wf);
  95. }
  96. fclose(rf);
  97. fclose(wf);
  98. }
  99. /*======================= file End ==================== */
  100. /*====================== parameter ==================== */
  101. struct RunLimit {
  102. int time;
  103. int real_time;
  104. int memory;
  105. int output;
  106. RunLimit() {
  107. }
  108. RunLimit(const int &_time, const int &_memory, const int &_output)
  109. : time(_time), memory(_memory), output(_output), real_time(-1) {
  110. }
  111. };
  112. const RunLimit RL_DEFAULT = RunLimit(1, 256, 64);
  113. const RunLimit RL_JUDGER_DEFAULT = RunLimit(600, 1024, 128);
  114. const RunLimit RL_CHECKER_DEFAULT = RunLimit(5, 256, 64);
  115. const RunLimit RL_INTERACTOR_DEFAULT = RunLimit(1, 256, 64);
  116. const RunLimit RL_VALIDATOR_DEFAULT = RunLimit(5, 256, 64);
  117. const RunLimit RL_MARKER_DEFAULT = RunLimit(5, 256, 64);
  118. const RunLimit RL_COMPILER_DEFAULT = RunLimit(15, 512, 64);
  119. struct PointInfo {
  120. int num;
  121. int scr;
  122. int ust, usm;
  123. string info, in, out, res;
  124. PointInfo(const int &_num, const int &_scr,
  125. const int &_ust, const int &_usm, const string &_info,
  126. const string &_in, const string &_out, const string &_res)
  127. : num(_num), scr(_scr),
  128. ust(_ust), usm(_usm), info(_info),
  129. in(_in), out(_out), res(_res) {
  130. if (info == "default") {
  131. if (scr == 0) {
  132. info = "Wrong Answer";
  133. } else if (scr == 100) {
  134. info = "Accepted";
  135. } else {
  136. info = "Acceptable Answer";
  137. }
  138. }
  139. }
  140. };
  141. struct CustomTestInfo {
  142. int ust, usm;
  143. string info, exp, out;
  144. CustomTestInfo(const int &_ust, const int &_usm, const string &_info,
  145. const string &_exp, const string &_out)
  146. : ust(_ust), usm(_usm), info(_info),
  147. exp(_exp), out(_out) {
  148. }
  149. };
  150. struct RunResult {
  151. int type;
  152. int ust, usm;
  153. int exit_code;
  154. static RunResult failed_result() {
  155. RunResult res;
  156. res.type = RS_JGF;
  157. res.ust = -1;
  158. res.usm = -1;
  159. return res;
  160. }
  161. static RunResult from_file(const string &file_name) {
  162. RunResult res;
  163. FILE *fres = fopen(file_name.c_str(), "r");
  164. if (fres == NULL || fscanf(fres, "%d %d %d %d", &res.type, &res.ust, &res.usm, &res.exit_code) != 4) {
  165. return RunResult::failed_result();
  166. }
  167. fclose(fres);
  168. return res;
  169. }
  170. };
  171. struct RunCheckerResult {
  172. int type;
  173. int ust, usm;
  174. int scr;
  175. string info;
  176. static RunCheckerResult from_file(const string &file_name, const RunResult &rres) {
  177. RunCheckerResult res;
  178. res.type = rres.type;
  179. res.ust = rres.ust;
  180. res.usm = rres.usm;
  181. if (rres.type != RS_AC) {
  182. res.scr = 0;
  183. } else {
  184. FILE *fres = fopen(file_name.c_str(), "r");
  185. char type[21];
  186. if (fres == NULL || fscanf(fres, "%20s", type) != 1) {
  187. return RunCheckerResult::failed_result();
  188. }
  189. if (strcmp(type, "ok") == 0) {
  190. res.scr = 100;
  191. } else if (strcmp(type, "points") == 0) {
  192. double d;
  193. if (fscanf(fres, "%lf", &d) != 1) {
  194. return RunCheckerResult::failed_result();
  195. } else {
  196. res.scr = (int)floor(100 * d + 0.5);
  197. }
  198. } else {
  199. res.scr = 0;
  200. }
  201. fclose(fres);
  202. }
  203. res.info = file_preview(file_name);
  204. return res;
  205. }
  206. static RunCheckerResult failed_result() {
  207. RunCheckerResult res;
  208. res.type = RS_JGF;
  209. res.ust = -1;
  210. res.usm = -1;
  211. res.scr = 0;
  212. res.info = "Checker Judgement Failed";
  213. return res;
  214. }
  215. };
  216. struct RunValidatorResult {
  217. int type;
  218. int ust, usm;
  219. bool succeeded;
  220. string info;
  221. static RunValidatorResult failed_result() {
  222. RunValidatorResult res;
  223. res.type = RS_JGF;
  224. res.ust = -1;
  225. res.usm = -1;
  226. res.succeeded = 0;
  227. res.info = "Validator Judgement Failed";
  228. return res;
  229. }
  230. };
  231. struct RunCompilerResult {
  232. int type;
  233. int ust, usm;
  234. bool succeeded;
  235. string info;
  236. static RunCompilerResult failed_result() {
  237. RunCompilerResult res;
  238. res.type = RS_JGF;
  239. res.ust = -1;
  240. res.usm = -1;
  241. res.succeeded = false;
  242. res.info = "Compile Failed";
  243. return res;
  244. }
  245. };
  246. // see also: run_simple_interaction
  247. struct RunSimpleInteractionResult {
  248. RunResult res; // prog
  249. RunCheckerResult ires; // interactor
  250. };
  251. int problem_id;
  252. string main_path;
  253. string work_path;
  254. string data_path;
  255. string result_path;
  256. int tot_time = 0;
  257. int max_memory = 0;
  258. int tot_score = 0;
  259. ostringstream details_out;
  260. //vector<PointInfo> points_info;
  261. map<string, string> config;
  262. /*==================== parameter End ================== */
  263. /*====================== config set =================== */
  264. void print_config() {
  265. for (map<string, string>::iterator it = config.begin(); it != config.end(); ++it) {
  266. cerr << it->first << " = " << it->second << endl;
  267. }
  268. }
  269. void load_config(const string &filename) {
  270. ifstream fin(filename.c_str());
  271. if (!fin) {
  272. return;
  273. }
  274. string key;
  275. string val;
  276. while (fin >> key >> val) {
  277. config[key] = val;
  278. }
  279. }
  280. string conf_str(const string &key, int num, const string &val) {
  281. ostringstream sout;
  282. sout << key << "_" << num;
  283. if (config.count(sout.str()) == 0) {
  284. return val;
  285. }
  286. return config[sout.str()];
  287. }
  288. string conf_str(const string &key, const string &val) {
  289. if (config.count(key) == 0) {
  290. return val;
  291. }
  292. return config[key];
  293. }
  294. string conf_str(const string &key) {
  295. return conf_str(key, "");
  296. }
  297. int conf_int(const string &key, const int &val) {
  298. if (config.count(key) == 0) {
  299. return val;
  300. }
  301. return atoi(config[key].c_str());
  302. }
  303. int conf_int(const string &key, int num, const int &val) {
  304. ostringstream sout;
  305. sout << key << "_" << num;
  306. if (config.count(sout.str()) == 0) {
  307. return conf_int(key, val);
  308. }
  309. return atoi(config[sout.str()].c_str());
  310. }
  311. int conf_int(const string &key) {
  312. return conf_int(key, 0);
  313. }
  314. string conf_input_file_name(int num) {
  315. ostringstream name;
  316. if (num < 0) {
  317. name << "ex_";
  318. }
  319. name << conf_str("input_pre", "input") << abs(num) << "." << conf_str("input_suf", "txt");
  320. return name.str();
  321. }
  322. string conf_output_file_name(int num) {
  323. ostringstream name;
  324. if (num < 0) {
  325. name << "ex_";
  326. }
  327. name << conf_str("output_pre", "output") << abs(num) << "." << conf_str("output_suf", "txt");
  328. return name.str();
  329. }
  330. RunLimit conf_run_limit(string pre, const int &num, const RunLimit &val) {
  331. if (!pre.empty()) {
  332. pre += "_";
  333. }
  334. RunLimit limit;
  335. limit.time = conf_int(pre + "time_limit", num, val.time);
  336. limit.memory = conf_int(pre + "memory_limit", num, val.memory);
  337. limit.output = conf_int(pre + "output_limit", num, val.output);
  338. return limit;
  339. }
  340. RunLimit conf_run_limit(const int &num, const RunLimit &val) {
  341. return conf_run_limit("", num, val);
  342. }
  343. void conf_add(const string &key, const string &val) {
  344. if (config.count(key)) return;
  345. config[key] = val;
  346. }
  347. bool conf_has(const string &key) {
  348. return config.count(key) != 0;
  349. }
  350. bool conf_is(const string &key, const string &val) {
  351. if (config.count(key) == 0) return false;
  352. return config[key] == val;
  353. }
  354. /*==================== config set End ================= */
  355. /*====================== info print =================== */
  356. template <class T>
  357. inline string vtos(const T &v) {
  358. ostringstream sout;
  359. sout << v;
  360. return sout.str();
  361. }
  362. inline string htmlspecialchars(const string &s) {
  363. string r;
  364. for (int i = 0; i < (int)s.length(); i++) {
  365. switch (s[i]) {
  366. case '&' : r += "&amp;"; break;
  367. case '<' : r += "&lt;"; break;
  368. case '>' : r += "&gt;"; break;
  369. case '"' : r += "&quot;"; break;
  370. case '\0': r += "<b>\\0</b>"; break;
  371. default : r += s[i]; break;
  372. }
  373. }
  374. return r;
  375. }
  376. inline string info_str(int id) {
  377. switch (id) {
  378. case RS_MLE: return "Memory Limit Exceeded";
  379. case RS_TLE: return "Time Limit Exceeded";
  380. case RS_OLE: return "Output Limit Exceeded";
  381. case RS_RE : return "Runtime Error";
  382. case RS_DGS: return "Dangerous Syscalls";
  383. case RS_JGF: return "Judgement Failed";
  384. default : return "Unknown Result";
  385. }
  386. }
  387. inline string info_str(const RunResult &p) {
  388. return info_str(p.type);
  389. }
  390. void add_point_info(const PointInfo &info, bool update_tot_score = true) {
  391. if (info.num >= 0) {
  392. if(info.ust >= 0) {
  393. tot_time += info.ust;
  394. }
  395. if(info.usm >= 0) {
  396. max_memory = max(max_memory, info.usm);
  397. }
  398. }
  399. if (update_tot_score) {
  400. tot_score += info.scr;
  401. }
  402. details_out << "<test num=\"" << info.num << "\""
  403. << " score=\"" << info.scr << "\""
  404. << " info=\"" << htmlspecialchars(info.info) << "\""
  405. << " time=\"" << info.ust << "\""
  406. << " memory=\"" << info.usm << "\">" << endl;
  407. if (conf_str("show_in", "on") == "on") {
  408. details_out << "<in>" << htmlspecialchars(info.in) << "</in>" << endl;
  409. }
  410. if (conf_str("show_out", "on") == "on") {
  411. details_out << "<out>" << htmlspecialchars(info.out) << "</out>" << endl;
  412. }
  413. if (conf_str("show_res", "on") == "on") {
  414. details_out << "<res>" << htmlspecialchars(info.res) << "</res>" << endl;
  415. }
  416. details_out << "</test>" << endl;
  417. }
  418. void add_custom_test_info(const CustomTestInfo &info) {
  419. if(info.ust >= 0) {
  420. tot_time += info.ust;
  421. }
  422. if(info.usm >= 0) {
  423. max_memory = max(max_memory, info.usm);
  424. }
  425. details_out << "<custom-test info=\"" << htmlspecialchars(info.info) << "\""
  426. << " time=\"" << info.ust << "\""
  427. << " memory=\"" << info.usm << "\">" << endl;
  428. if (!info.exp.empty()) {
  429. details_out << info.exp << endl;
  430. }
  431. details_out << "<out>" << htmlspecialchars(info.out) << "</out>" << endl;
  432. details_out << "</custom-test>" << endl;
  433. }
  434. void add_subtask_info(const int &num, const int &scr, const string &info, const vector<PointInfo> &points) {
  435. details_out << "<subtask num=\"" << num << "\""
  436. << " score=\"" << scr << "\""
  437. << " info=\"" << htmlspecialchars(info) << "\">" << endl;
  438. tot_score += scr;
  439. for (vector<PointInfo>::const_iterator it = points.begin(); it != points.end(); it++) {
  440. add_point_info(*it, false);
  441. }
  442. details_out << "</subtask>" << endl;
  443. }
  444. void end_judge_ok() {
  445. FILE *fres = fopen((result_path + "/result.txt").c_str(), "w");
  446. fprintf(fres, "score %d\n", tot_score);
  447. fprintf(fres, "time %d\n", tot_time);
  448. fprintf(fres, "memory %d\n", max_memory);
  449. fprintf(fres, "details\n");
  450. fprintf(fres, "<tests>\n");
  451. fprintf(fres, "%s", details_out.str().c_str());
  452. fprintf(fres, "</tests>\n");
  453. fclose(fres);
  454. exit(0);
  455. }
  456. void end_judge_judgement_failed(const string &info) {
  457. FILE *fres = fopen((result_path + "/result.txt").c_str(), "w");
  458. fprintf(fres, "error Judgement Failed\n");
  459. fprintf(fres, "details\n");
  460. fprintf(fres, "<error>%s</error>\n", htmlspecialchars(info).c_str());
  461. fclose(fres);
  462. exit(1);
  463. }
  464. void end_judge_compile_error(const RunCompilerResult &res) {
  465. FILE *fres = fopen((result_path + "/result.txt").c_str(), "w");
  466. fprintf(fres, "error Compile Error\n");
  467. fprintf(fres, "details\n");
  468. fprintf(fres, "<error>%s</error>\n", htmlspecialchars(res.info).c_str());
  469. fclose(fres);
  470. exit(0);
  471. }
  472. void report_judge_status(const char *status) {
  473. FILE *f = fopen((result_path + "/cur_status.txt").c_str(), "a");
  474. if (f == NULL) {
  475. return;
  476. }
  477. if (flock(fileno(f), LOCK_EX) != -1) {
  478. if (ftruncate(fileno(f), 0) != -1) {
  479. fprintf(f, "%s\n", status);
  480. fflush(f);
  481. }
  482. flock(fileno(f), LOCK_UN);
  483. }
  484. fclose(f);
  485. }
  486. bool report_judge_status_f(const char *fmt, ...) {
  487. const int MaxL = 512;
  488. char status[MaxL];
  489. va_list ap;
  490. va_start(ap, fmt);
  491. int res = vsnprintf(status, MaxL, fmt, ap);
  492. if (res < 0 || res >= MaxL) {
  493. return false;
  494. }
  495. report_judge_status(status);
  496. va_end(ap);
  497. return true;
  498. }
  499. /*==================== info print End ================= */
  500. /*========================== run ====================== */
  501. struct RunProgramConfig {
  502. vector<string> readable_file_names; // other than stdin
  503. string result_file_name;
  504. string input_file_name;
  505. string output_file_name;
  506. string error_file_name;
  507. string type;
  508. string work_path;
  509. RunLimit limit;
  510. vector<string> argv;
  511. RunProgramConfig() {
  512. int p = 1;
  513. while (conf_str("readable", p, "") != "") {
  514. readable_file_names.push_back(conf_str("readable", p, ""));
  515. p++;
  516. }
  517. result_file_name = result_path + "/run_program_result.txt";
  518. type = "default";
  519. work_path = ::work_path;
  520. for (vector<string>::iterator it = readable_file_names.begin(); it != readable_file_names.end(); it++) {
  521. if (!it->empty() && (*it)[0] != '/') {
  522. *it = ::work_path + "/" + *it;
  523. }
  524. }
  525. }
  526. void set_argv(const char *program_name, ...) {
  527. argv.clear();
  528. argv.push_back(program_name);
  529. va_list vl;
  530. va_start(vl, program_name);
  531. for (const char *arg = va_arg(vl, const char *); arg; arg = va_arg(vl, const char *)) {
  532. argv.push_back(arg);
  533. }
  534. va_end(vl);
  535. }
  536. void set_submission_program_name(string name) {
  537. string lang = conf_str(string(name) + "_language");
  538. type = "default";
  539. string program_name = name;
  540. if (lang == "Python2") {
  541. type = "python2";
  542. } else if (lang == "Python3") {
  543. type = "python3";
  544. } else if (lang == "Java8") {
  545. program_name += "." + conf_str(name + "_main_class");
  546. type = "java8";
  547. } else if (lang == "Java11") {
  548. program_name += "." + conf_str(name + "_main_class");
  549. type = "java11";
  550. }
  551. set_argv(program_name.c_str(), NULL);
  552. }
  553. string get_cmd() const {
  554. ostringstream sout;
  555. sout << main_path << "/run/run_program"
  556. << " " << "--res=" << escapeshellarg(result_file_name)
  557. << " " << "--in=" << escapeshellarg(input_file_name)
  558. << " " <<"--out=" << escapeshellarg(output_file_name)
  559. << " " << "--err=" << escapeshellarg(error_file_name)
  560. << " " << "--tl=" << limit.time
  561. << " " << "--ml=" << limit.memory
  562. << " " << "--ol=" << limit.output
  563. << " " << "--type=" << type
  564. << " " << "--work-path=" << work_path
  565. /*<< " " << "--show-trace-details"*/;
  566. for (vector<string>::const_iterator it = readable_file_names.begin(); it != readable_file_names.end(); it++) {
  567. sout << " " << "--add-readable=" << escapeshellarg(*it);
  568. }
  569. for (vector<string>::const_iterator it = argv.begin(); it != argv.end(); it++) {
  570. sout << " " << escapeshellarg(*it);
  571. }
  572. return sout.str();
  573. }
  574. };
  575. struct PipeConfig {
  576. int from, to;
  577. int from_fd, to_fd;
  578. string saving_file_name;
  579. PipeConfig() {
  580. }
  581. PipeConfig(int _from, int _from_fd, int _to, int _to_fd, const string &_saving_file_name = "")
  582. : from(_from), from_fd(_from_fd), to(_to), to_fd(_to_fd), saving_file_name(_saving_file_name) {
  583. }
  584. };
  585. struct RunInteractionConfig {
  586. vector<string> cmds;
  587. vector<PipeConfig> pipes;
  588. string get_cmd() const {
  589. ostringstream sout;
  590. sout << main_path << "/run/run_interaction";
  591. for (int i = 0; i < (int)cmds.size(); i++) {
  592. sout << " " << escapeshellarg(cmds[i]);
  593. }
  594. for (int i = 0; i < (int)pipes.size(); i++) {
  595. sout << " " << "-p";
  596. sout << " " << pipes[i].from << ":" << pipes[i].from_fd;
  597. sout << "-" << pipes[i].to << ":" << pipes[i].to_fd;
  598. if (!pipes[i].saving_file_name.empty()) {
  599. sout << " " << "-s";
  600. sout << " " << escapeshellarg(pipes[i].saving_file_name);
  601. }
  602. }
  603. return sout.str();
  604. }
  605. };
  606. // @deprecated
  607. // will be removed in the future
  608. RunResult vrun_program(
  609. const char *run_program_result_file_name,
  610. const char *input_file_name,
  611. const char *output_file_name,
  612. const char *error_file_name,
  613. const RunLimit &limit,
  614. const vector<string> &rest) {
  615. ostringstream sout;
  616. sout << main_path << "/run/run_program"
  617. << " " << "--res=" << escapeshellarg(run_program_result_file_name)
  618. << " " << "--in=" << escapeshellarg(input_file_name)
  619. << " " <<"--out=" << escapeshellarg(output_file_name)
  620. << " " << "--err=" << escapeshellarg(error_file_name)
  621. << " " << "--tl=" << limit.time
  622. << " " << "--ml=" << limit.memory
  623. << " " << "--ol=" << limit.output
  624. /*<< " " << "--show-trace-details"*/;
  625. for (vector<string>::const_iterator it = rest.begin(); it != rest.end(); it++) {
  626. sout << " " << escapeshellarg(*it);
  627. }
  628. if (execute(sout.str().c_str()) != 0) {
  629. return RunResult::failed_result();
  630. }
  631. return RunResult::from_file(run_program_result_file_name);
  632. }
  633. RunResult run_program(const RunProgramConfig &rpc) {
  634. if (execute(rpc.get_cmd().c_str()) != 0) {
  635. return RunResult::failed_result();
  636. }
  637. return RunResult::from_file(rpc.result_file_name);
  638. }
  639. // @return interaction return value
  640. int run_interaction(const RunInteractionConfig &ric) {
  641. return execute(ric.get_cmd().c_str());
  642. }
  643. RunResult run_program(
  644. const char *run_program_result_file_name,
  645. const char *input_file_name,
  646. const char *output_file_name,
  647. const char *error_file_name,
  648. const RunLimit &limit, ...) {
  649. vector<string> argv;
  650. va_list vl;
  651. va_start(vl, limit);
  652. for (const char *arg = va_arg(vl, const char *); arg; arg = va_arg(vl, const char *)) {
  653. argv.push_back(arg);
  654. }
  655. va_end(vl);
  656. return vrun_program(run_program_result_file_name,
  657. input_file_name,
  658. output_file_name,
  659. error_file_name,
  660. limit,
  661. argv);
  662. }
  663. RunValidatorResult run_validator(
  664. const string &input_file_name,
  665. const RunLimit &limit,
  666. const string &program_name) {
  667. RunResult ret = run_program(
  668. (string(result_path) + "/run_validator_result.txt").c_str(),
  669. input_file_name.c_str(),
  670. "/dev/null",
  671. (string(result_path) + "/validator_error.txt").c_str(),
  672. limit,
  673. program_name.c_str(),
  674. NULL);
  675. RunValidatorResult res;
  676. res.type = ret.type;
  677. res.ust = ret.ust;
  678. res.usm = ret.usm;
  679. if (ret.type != RS_AC || ret.exit_code != 0) {
  680. res.succeeded = false;
  681. res.info = file_preview(result_path + "/validator_error.txt");
  682. } else {
  683. res.succeeded = true;
  684. }
  685. return res;
  686. }
  687. RunCheckerResult run_checker(
  688. const RunLimit &limit,
  689. const string &program_name,
  690. const string &input_file_name,
  691. const string &output_file_name,
  692. const string &answer_file_name) {
  693. RunResult ret = run_program(
  694. (string(result_path) + "/run_checker_result.txt").c_str(),
  695. "/dev/null",
  696. "/dev/null",
  697. (string(result_path) + "/checker_error.txt").c_str(),
  698. limit,
  699. ("--add-readable=" + input_file_name).c_str(),
  700. ("--add-readable=" + output_file_name).c_str(),
  701. ("--add-readable=" + answer_file_name).c_str(),
  702. program_name.c_str(),
  703. realpath(input_file_name).c_str(),
  704. realpath(output_file_name).c_str(),
  705. realpath(answer_file_name).c_str(),
  706. NULL);
  707. return RunCheckerResult::from_file(result_path + "/checker_error.txt", ret);
  708. }
  709. RunCompilerResult run_compiler(const char *path, ...) {
  710. vector<string> argv;
  711. argv.push_back("--type=compiler");
  712. argv.push_back(string("--work-path=") + path);
  713. va_list vl;
  714. va_start(vl, path);
  715. for (const char *arg = va_arg(vl, const char *); arg; arg = va_arg(vl, const char *)) {
  716. argv.push_back(arg);
  717. }
  718. va_end(vl);
  719. RunResult ret = vrun_program(
  720. (result_path + "/run_compiler_result.txt").c_str(),
  721. "/dev/null",
  722. "stderr",
  723. (result_path + "/compiler_result.txt").c_str(),
  724. RL_COMPILER_DEFAULT,
  725. argv);
  726. RunCompilerResult res;
  727. res.type = ret.type;
  728. res.ust = ret.ust;
  729. res.usm = ret.usm;
  730. res.succeeded = ret.type == RS_AC && ret.exit_code == 0;
  731. if (!res.succeeded) {
  732. if (ret.type == RS_AC) {
  733. res.info = file_preview(result_path + "/compiler_result.txt", 500);
  734. } else if (ret.type == RS_JGF) {
  735. res.info = "No Comment";
  736. } else {
  737. res.info = "Compiler " + info_str(ret.type);
  738. }
  739. }
  740. return res;
  741. }
  742. RunResult run_submission_program(
  743. const string &input_file_name,
  744. const string &output_file_name,
  745. const RunLimit &limit,
  746. const string &name,
  747. RunProgramConfig rpc = RunProgramConfig()) {
  748. rpc.result_file_name = result_path + "/run_submission_program.txt";
  749. if (!getenv("ONLINE_JUDGE_UBSAN")) {
  750. rpc.output_file_name = output_file_name;
  751. rpc.error_file_name = "/dev/null";
  752. }
  753. else {
  754. rpc.output_file_name = "/dev/null";
  755. rpc.error_file_name = output_file_name;
  756. }
  757. rpc.input_file_name = input_file_name;
  758. rpc.limit = limit;
  759. rpc.set_submission_program_name(name);
  760. RunResult res = run_program(rpc);
  761. if (res.type == RS_AC && res.exit_code != 0) {
  762. res.type = RS_RE;
  763. }
  764. return res;
  765. }
  766. void prepare_interactor() {
  767. static bool prepared = false;
  768. if (prepared) {
  769. return;
  770. }
  771. string data_path_std = data_path + "/interactor";
  772. string work_path_std = work_path + "/interactor";
  773. executef("cp %s %s", data_path_std.c_str(), work_path_std.c_str());
  774. conf_add("interactor_language", "C++");
  775. prepared = true;
  776. }
  777. // simple: prog <---> interactor <---> data
  778. RunSimpleInteractionResult run_simple_interation(
  779. const string &input_file_name,
  780. const string &answer_file_name,
  781. const string &real_input_file_name,
  782. const string &real_output_file_name,
  783. const RunLimit &limit,
  784. const RunLimit &ilimit,
  785. const string &name,
  786. RunProgramConfig rpc = RunProgramConfig(),
  787. RunProgramConfig irpc = RunProgramConfig()) {
  788. prepare_interactor();
  789. rpc.result_file_name = result_path + "/run_submission_program.txt";
  790. rpc.input_file_name = "stdin";
  791. rpc.output_file_name = "stdout";
  792. rpc.error_file_name = "/dev/null";
  793. rpc.limit = limit;
  794. rpc.set_submission_program_name(name);
  795. irpc.result_file_name = result_path + "/run_interactor_program.txt";
  796. irpc.readable_file_names.push_back(input_file_name);
  797. irpc.readable_file_names.push_back(answer_file_name);
  798. irpc.input_file_name = "stdin";
  799. irpc.output_file_name = "stdout";
  800. irpc.error_file_name = result_path + "/interactor_error.txt";
  801. irpc.limit = ilimit;
  802. irpc.set_submission_program_name("interactor");
  803. irpc.argv.push_back(input_file_name);
  804. irpc.argv.push_back("/dev/stdin");
  805. irpc.argv.push_back(answer_file_name);
  806. irpc.limit.real_time = rpc.limit.real_time = rpc.limit.time + irpc.limit.time + 1;
  807. RunInteractionConfig ric;
  808. ric.cmds.push_back(rpc.get_cmd());
  809. ric.cmds.push_back(irpc.get_cmd());
  810. // from:fd, to:fd
  811. ric.pipes.push_back(PipeConfig(2, 1, 1, 0, real_input_file_name));
  812. ric.pipes.push_back(PipeConfig(1, 1, 2, 0, real_output_file_name));
  813. run_interaction(ric);
  814. RunSimpleInteractionResult rires;
  815. RunResult res = RunResult::from_file(rpc.result_file_name);
  816. RunCheckerResult ires = RunCheckerResult::from_file(irpc.error_file_name, RunResult::from_file(irpc.result_file_name));
  817. if (res.type == RS_AC && res.exit_code != 0) {
  818. res.type = RS_RE;
  819. }
  820. if (ires.type == RS_JGF) {
  821. ires.info = "Interactor Judgement Failed";
  822. }
  823. if (ires.type == RS_TLE) {
  824. ires.type = RS_AC;
  825. res.type = RS_TLE;
  826. }
  827. rires.res = res;
  828. rires.ires = ires;
  829. return rires;
  830. }
  831. void prepare_run_standard_program() {
  832. static bool prepared = false;
  833. if (prepared) {
  834. return;
  835. }
  836. string data_path_std = data_path + "/std";
  837. string work_path_std = work_path + "/std";
  838. executef("cp %s %s", data_path_std.c_str(), work_path_std.c_str());
  839. conf_add("std_language", "C++");
  840. prepared = true;
  841. }
  842. // @deprecated
  843. // will be removed in the future
  844. RunResult run_standard_program(
  845. const string &input_file_name,
  846. const string &output_file_name,
  847. const RunLimit &limit,
  848. RunProgramConfig rpc = RunProgramConfig()) {
  849. prepare_run_standard_program();
  850. rpc.result_file_name = result_path + "/run_standard_program.txt";
  851. return run_submission_program(
  852. input_file_name,
  853. output_file_name,
  854. limit,
  855. "std",
  856. rpc);
  857. }
  858. /*======================== run End ==================== */
  859. /*======================== compile ==================== */
  860. bool is_illegal_keyword(const string &name) {
  861. if (name == "__asm" || name == "__asm__" || name == "asm")
  862. return true;
  863. return false;
  864. }
  865. bool has_illegal_keywords_in_file(const string &name) {
  866. FILE *f = fopen(name.c_str(), "r");
  867. int c;
  868. string key;
  869. while ((c = fgetc(f)) != EOF)
  870. {
  871. if (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_')
  872. {
  873. if (key.size() < 20)
  874. key += c;
  875. else
  876. {
  877. if (is_illegal_keyword(key))
  878. return true;
  879. key.erase(key.begin());
  880. key += c;
  881. }
  882. }
  883. else
  884. {
  885. if (is_illegal_keyword(key))
  886. return true;
  887. key.clear();
  888. }
  889. }
  890. if (is_illegal_keyword(key))
  891. return true;
  892. fclose(f);
  893. return false;
  894. }
  895. RunCompilerResult prepare_java_source(const string &name, const string &path = work_path) {
  896. FILE *f = fopen((path + "/" + name + ".code").c_str(), "r");
  897. const int L = 1024;
  898. std::string s;
  899. char buf[L + 1];
  900. int mode = 0;
  901. while (!feof(f)) {
  902. buf[fread(buf, 1, L, f)] = '\0';
  903. for (char *p = buf; *p; p++) {
  904. s += *p;
  905. switch (mode) {
  906. case 0:
  907. switch (*p) {
  908. case '/':
  909. mode = 1;
  910. break;
  911. case '\'':
  912. mode = 5;
  913. break;
  914. case '\"':
  915. mode = 6;
  916. break;
  917. }
  918. break;
  919. case 1:
  920. switch (*p) {
  921. case '/':
  922. mode = 2;
  923. s.resize(s.length() - 2);
  924. break;
  925. case '*':
  926. mode = 3;
  927. s.resize(s.length() - 2);
  928. break;
  929. }
  930. break;
  931. case 2:
  932. s.resize(s.length() - 1);
  933. switch (*p) {
  934. case '\n':
  935. s += '\n';
  936. mode = 0;
  937. break;
  938. }
  939. break;
  940. case 3:
  941. s.resize(s.length() - 1);
  942. switch (*p) {
  943. case '*':
  944. mode = 4;
  945. break;
  946. }
  947. break;
  948. case 4:
  949. s.resize(s.length() - 1);
  950. switch (*p) {
  951. case '/':
  952. s += ' ';
  953. mode = 0;
  954. break;
  955. }
  956. break;
  957. case 5:
  958. switch (*p) {
  959. case '\'':
  960. mode = 0;
  961. break;
  962. case '\\':
  963. mode = 7;
  964. break;
  965. }
  966. case 6:
  967. switch (*p) {
  968. case '\"':
  969. mode = 0;
  970. break;
  971. case '\\':
  972. mode = 8;
  973. break;
  974. }
  975. case 7:
  976. mode = 5;
  977. break;
  978. case 8:
  979. mode = 6;
  980. break;
  981. }
  982. }
  983. }
  984. bool valid[256];
  985. fill(valid, valid + 256, false);
  986. for (int c = 'a'; c <= 'z'; c++)
  987. valid[c] = true;
  988. for (int c = 'A'; c <= 'Z'; c++)
  989. valid[c] = true;
  990. valid['.'] = true;
  991. valid['_'] = true;
  992. vector<string> tokens;
  993. for (int p = 0, np = 0; p < (int)s.length(); p = np) {
  994. while (np < (int)s.length() && valid[(unsigned char)s[np]]) {
  995. np++;
  996. }
  997. if (np == p) {
  998. np++;
  999. } else {
  1000. tokens.push_back(s.substr(p, np - p));
  1001. }
  1002. }
  1003. if (tokens.size() > 0 && tokens[0] == "package") {
  1004. RunCompilerResult res;
  1005. res.type = RS_WA;
  1006. res.ust = -1;
  1007. res.usm = -1;
  1008. res.succeeded = false;
  1009. res.info = "Please don't specify the package.";
  1010. return res;
  1011. }
  1012. for (int i = 0; i + 1 < (int)tokens.size(); i++) {
  1013. if (tokens[i] == "class") {
  1014. if (tokens[i + 1].length() <= 100) {
  1015. config[name + "_main_class"] = tokens[i + 1];
  1016. RunCompilerResult res;
  1017. res.type = RS_AC;
  1018. res.ust = 0;
  1019. res.usm = 0;
  1020. res.succeeded = true;
  1021. return res;
  1022. } else {
  1023. RunCompilerResult res;
  1024. res.type = RS_WA;
  1025. res.ust = -1;
  1026. res.usm = -1;
  1027. res.succeeded = false;
  1028. res.info = "The name of the main class is too long.";
  1029. return res;
  1030. }
  1031. }
  1032. }
  1033. RunCompilerResult res;
  1034. res.type = RS_WA;
  1035. res.ust = -1;
  1036. res.usm = -1;
  1037. res.succeeded = false;
  1038. res.info = "Can't find the main class.";
  1039. return res;
  1040. }
  1041. RunCompilerResult compile_c(const string &name, const string &path = work_path) {
  1042. return run_compiler(path.c_str(),
  1043. "/usr/bin/gcc", "-o", name.c_str(), "-x", "c", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", NULL);
  1044. }
  1045. RunCompilerResult compile_pas(const string &name, const string &path = work_path) {
  1046. return run_compiler(path.c_str(),
  1047. "/usr/bin/fpc", (name + ".code").c_str(), "-O2", NULL);
  1048. }
  1049. RunCompilerResult compile_cpp14(const string &name, const string &path = work_path) {
  1050. return run_compiler(path.c_str(),
  1051. "/usr/bin/g++", "-std=c++14", "-o", name.c_str(), "-x", "c++", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", NULL);
  1052. }
  1053. RunCompilerResult compile_cpp17(const string &name, const string &path = work_path) {
  1054. return run_compiler(path.c_str(),
  1055. "/usr/bin/g++", "-std=c++17", "-o", name.c_str(), "-x", "c++", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", NULL);
  1056. }
  1057. RunCompilerResult compile_cpp17ubsan(const string &name, const string &path = work_path) {
  1058. return run_compiler(path.c_str(),
  1059. "/usr/bin/g++", "-fsanitize=undefined", "-std=c++17", "-o", name.c_str(), "-x", "c++", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", NULL);
  1060. }
  1061. RunCompilerResult compile_python2(const string &name, const string &path = work_path) {
  1062. return run_compiler(path.c_str(),
  1063. "/usr/bin/python2", "-E", "-s", "-B", "-O", "-c",
  1064. ("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);
  1065. }
  1066. RunCompilerResult compile_python3(const string &name, const string &path = work_path) {
  1067. return run_compiler(path.c_str(),
  1068. "/usr/bin/python3", "-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);
  1069. }
  1070. RunCompilerResult compile_java8(const string &name, const string &path = work_path) {
  1071. RunCompilerResult ret = prepare_java_source(name, path);
  1072. if (!ret.succeeded)
  1073. return ret;
  1074. string main_class = conf_str(name + "_main_class");
  1075. executef("rm %s/%s -rf 2>/dev/null; mkdir %s/%s", path.c_str(), name.c_str(), path.c_str(), name.c_str());
  1076. 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());
  1077. return run_compiler((path + "/" + name).c_str(),
  1078. "/usr/lib/jvm/java-8-openjdk-amd64/bin/javac", (main_class + ".java").c_str(), NULL);
  1079. }
  1080. RunCompilerResult compile_java11(const string &name, const string &path = work_path) {
  1081. RunCompilerResult ret = prepare_java_source(name, path);
  1082. if (!ret.succeeded)
  1083. return ret;
  1084. string main_class = conf_str(name + "_main_class");
  1085. executef("rm %s/%s -rf 2>/dev/null; mkdir %s/%s", path.c_str(), name.c_str(), path.c_str(), name.c_str());
  1086. 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());
  1087. return run_compiler((path + "/" + name).c_str(),
  1088. "/usr/lib/jvm/java-11-openjdk-amd64/bin/javac", (main_class + ".java").c_str(), NULL);
  1089. }
  1090. // ryp
  1091. RunCompilerResult compile(const char *name) {
  1092. string lang = conf_str(string(name) + "_language");
  1093. if (lang == "C++17ubsan")
  1094. setenv ("ONLINE_JUDGE_UBSAN", "1", 1);
  1095. if ((lang == "C++14" || lang == "C++17" || lang == "C++17ubsan" || lang == "C") && has_illegal_keywords_in_file(work_path + "/" + name + ".code"))
  1096. {
  1097. RunCompilerResult res;
  1098. res.type = RS_DGS;
  1099. res.ust = -1;
  1100. res.usm = -1;
  1101. res.succeeded = false;
  1102. res.info = "Compile Failed";
  1103. return res;
  1104. }
  1105. if (lang == "C++14") {
  1106. return compile_cpp14(name);
  1107. }
  1108. if (lang == "C++17") {
  1109. return compile_cpp17(name);
  1110. }
  1111. if (lang == "C++17ubsan") {
  1112. return compile_cpp17ubsan(name);
  1113. }
  1114. if (lang == "Python2") {
  1115. return compile_python2(name);
  1116. }
  1117. if (lang == "Python3") {
  1118. return compile_python3(name);
  1119. }
  1120. if (lang == "Java8") {
  1121. return compile_java8(name);
  1122. }
  1123. if (lang == "Java11") {
  1124. return compile_java11(name);
  1125. }
  1126. if (lang == "C") {
  1127. return compile_c(name);
  1128. }
  1129. if (lang == "Pascal") {
  1130. return compile_pas(name);
  1131. }
  1132. RunCompilerResult res = RunCompilerResult::failed_result();
  1133. res.info = "This language is not supported yet.";
  1134. return res;
  1135. }
  1136. RunCompilerResult compile_c_with_implementer(const string &name, const string &path = work_path) {
  1137. return run_compiler(path.c_str(),
  1138. "/usr/bin/gcc", "-o", name.c_str(), "implementer.c", "-x", "c", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", NULL);
  1139. }
  1140. RunCompilerResult compile_pas_with_implementer(const string &name, const string &path = work_path) {
  1141. executef("cp %s %s", (path + "/" + name + ".code").c_str(), (path + "/" + conf_str(name + "_unit_name") + ".pas").c_str());
  1142. return run_compiler(path.c_str(),
  1143. "/usr/bin/fpc", "implementer.pas", ("-o" + name).c_str(), "-O2", NULL);
  1144. }
  1145. RunCompilerResult compile_cpp14_with_implementer(const string &name, const string &path = work_path) {
  1146. return run_compiler(path.c_str(),
  1147. "/usr/bin/g++", "-std=c++14", "-o", name.c_str(), "implementer.cpp", "-x", "c++", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", NULL);
  1148. }
  1149. RunCompilerResult compile_cpp17_with_implementer(const string &name, const string &path = work_path) {
  1150. return run_compiler(path.c_str(),
  1151. "/usr/bin/g++", "-std=c++17", "-o", name.c_str(), "implementer.cpp", "-x", "c++", (name + ".code").c_str(), "-lm", "-O2", "-DONLINE_JUDGE", "-std=c++11", NULL);
  1152. }
  1153. /*
  1154. RunCompilerResult compile_python2(const string &name, const string &path = work_path) {
  1155. return run_compiler(path.c_str(),
  1156. "/usr/bin/python2", "-E", "-s", "-B", "-O", "-c",
  1157. ("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);
  1158. }
  1159. RunCompilerResult compile_python3(const string &name, const string &path = work_path) {
  1160. return run_compiler(path.c_str(),
  1161. "/usr/bin/python3", "-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);
  1162. }
  1163. */
  1164. RunCompilerResult compile_with_implementer(const char *name) {
  1165. string lang = conf_str(string(name) + "_language");
  1166. if (has_illegal_keywords_in_file(work_path + "/" + name + ".code"))
  1167. {
  1168. RunCompilerResult res;
  1169. res.type = RS_DGS;
  1170. res.ust = -1;
  1171. res.usm = -1;
  1172. res.succeeded = false;
  1173. res.info = "Compile Failed";
  1174. return res;
  1175. }
  1176. if (lang == "C++14") {
  1177. return compile_cpp14_with_implementer(name);
  1178. }
  1179. if (lang == "C++17") {
  1180. return compile_cpp17_with_implementer(name);
  1181. }
  1182. if (lang == "C") {
  1183. return compile_c_with_implementer(name);
  1184. }
  1185. if (lang == "Pascal") {
  1186. return compile_pas_with_implementer(name);
  1187. }
  1188. RunCompilerResult res = RunCompilerResult::failed_result();
  1189. res.info = "This language is not supported yet.";
  1190. return res;
  1191. }
  1192. /*====================== compile End ================== */
  1193. /*====================== test ================== */
  1194. struct TestPointConfig {
  1195. int submit_answer;
  1196. int validate_input_before_test;
  1197. string input_file_name;
  1198. string output_file_name;
  1199. string answer_file_name;
  1200. TestPointConfig()
  1201. : submit_answer(-1), validate_input_before_test(-1) {
  1202. }
  1203. void auto_complete(int num) {
  1204. if (submit_answer == -1) {
  1205. submit_answer = conf_is("submit_answer", "on");
  1206. }
  1207. if (validate_input_before_test == -1) {
  1208. validate_input_before_test = conf_is("validate_input_before_test", "on");
  1209. }
  1210. if (input_file_name.empty()) {
  1211. input_file_name = data_path + "/" + conf_input_file_name(num);
  1212. }
  1213. if (output_file_name.empty()) {
  1214. output_file_name = work_path + "/" + conf_output_file_name(num);
  1215. }
  1216. if (answer_file_name.empty()) {
  1217. answer_file_name = data_path + "/" + conf_output_file_name(num);
  1218. }
  1219. }
  1220. };
  1221. PointInfo test_point(const string &name, const int &num, TestPointConfig tpc = TestPointConfig()) {
  1222. tpc.auto_complete(num);
  1223. if (tpc.validate_input_before_test) {
  1224. RunValidatorResult val_ret = run_validator(
  1225. tpc.input_file_name,
  1226. conf_run_limit("validator", 0, RL_VALIDATOR_DEFAULT),
  1227. conf_str("validator"));
  1228. if (val_ret.type != RS_AC) {
  1229. return PointInfo(num, 0, -1, -1,
  1230. "Validator " + info_str(val_ret.type),
  1231. file_preview(tpc.input_file_name), "",
  1232. "");
  1233. } else if (!val_ret.succeeded) {
  1234. return PointInfo(num, 0, -1, -1,
  1235. "Invalid Input",
  1236. file_preview(tpc.input_file_name), "",
  1237. val_ret.info);
  1238. }
  1239. }
  1240. if (!conf_is("interaction_mode", "on")) {
  1241. RunResult pro_ret;
  1242. if (!tpc.submit_answer) {
  1243. pro_ret = run_submission_program(
  1244. tpc.input_file_name.c_str(),
  1245. tpc.output_file_name.c_str(),
  1246. conf_run_limit(num, RL_DEFAULT),
  1247. name);
  1248. if (conf_has("token")) {
  1249. file_hide_token(tpc.output_file_name, conf_str("token", ""));
  1250. }
  1251. if (pro_ret.type != RS_AC) {
  1252. return PointInfo(num, 0, -1, -1,
  1253. info_str(pro_ret.type),
  1254. file_preview(tpc.input_file_name), file_preview(tpc.output_file_name),
  1255. "");
  1256. }
  1257. } else {
  1258. pro_ret.type = RS_AC;
  1259. pro_ret.ust = -1;
  1260. pro_ret.usm = -1;
  1261. pro_ret.exit_code = 0;
  1262. }
  1263. RunCheckerResult chk_ret = run_checker(
  1264. conf_run_limit("checker", num, RL_CHECKER_DEFAULT),
  1265. conf_str("checker"),
  1266. tpc.input_file_name,
  1267. tpc.output_file_name,
  1268. tpc.answer_file_name);
  1269. if (chk_ret.type != RS_AC) {
  1270. return PointInfo(num, 0, -1, -1,
  1271. "Checker " + info_str(chk_ret.type),
  1272. file_preview(tpc.input_file_name), file_preview(tpc.output_file_name),
  1273. "");
  1274. }
  1275. return PointInfo(num, chk_ret.scr, pro_ret.ust, pro_ret.usm,
  1276. "default",
  1277. file_preview(tpc.input_file_name), file_preview(tpc.output_file_name),
  1278. chk_ret.info);
  1279. } else {
  1280. string real_output_file_name = tpc.output_file_name + ".real_input.txt";
  1281. string real_input_file_name = tpc.output_file_name + ".real_output.txt";
  1282. RunSimpleInteractionResult rires = run_simple_interation(
  1283. tpc.input_file_name,
  1284. tpc.answer_file_name,
  1285. real_input_file_name,
  1286. real_output_file_name,
  1287. conf_run_limit(num, RL_DEFAULT),
  1288. conf_run_limit("interactor", num, RL_INTERACTOR_DEFAULT),
  1289. name);
  1290. if (rires.ires.type != RS_AC) {
  1291. return PointInfo(num, 0, -1, -1,
  1292. "Interactor " + info_str(rires.ires.type),
  1293. file_preview(real_input_file_name), file_preview(real_output_file_name),
  1294. "");
  1295. }
  1296. if (rires.res.type != RS_AC) {
  1297. return PointInfo(num, 0, -1, -1,
  1298. info_str(rires.res.type),
  1299. file_preview(real_input_file_name), file_preview(real_output_file_name),
  1300. "");
  1301. }
  1302. return PointInfo(num, rires.ires.scr, rires.res.ust, rires.res.usm,
  1303. "default",
  1304. file_preview(real_input_file_name), file_preview(real_output_file_name),
  1305. rires.ires.info);
  1306. }
  1307. }
  1308. PointInfo test_hack_point(const string &name, TestPointConfig tpc) {
  1309. tpc.submit_answer = false;
  1310. tpc.validate_input_before_test = false;
  1311. tpc.auto_complete(0);
  1312. RunValidatorResult val_ret = run_validator(
  1313. tpc.input_file_name,
  1314. conf_run_limit("validator", 0, RL_VALIDATOR_DEFAULT),
  1315. conf_str("validator"));
  1316. if (val_ret.type != RS_AC) {
  1317. return PointInfo(0, 0, -1, -1,
  1318. "Validator " + info_str(val_ret.type),
  1319. file_preview(tpc.input_file_name), "",
  1320. "");
  1321. } else if (!val_ret.succeeded) {
  1322. return PointInfo(0, 0, -1, -1,
  1323. "Invalid Input",
  1324. file_preview(tpc.input_file_name), "",
  1325. val_ret.info);
  1326. }
  1327. RunLimit default_std_run_limit = conf_run_limit(0, RL_DEFAULT);
  1328. prepare_run_standard_program();
  1329. if (!conf_is("interaction_mode", "on")) {
  1330. RunProgramConfig rpc;
  1331. rpc.result_file_name = result_path + "/run_standard_program.txt";
  1332. RunResult std_ret = run_submission_program(
  1333. tpc.input_file_name,
  1334. tpc.answer_file_name,
  1335. conf_run_limit("standard", 0, default_std_run_limit),
  1336. "std",
  1337. rpc);
  1338. if (std_ret.type != RS_AC) {
  1339. return PointInfo(0, 0, -1, -1,
  1340. "Standard Program " + info_str(std_ret.type),
  1341. file_preview(tpc.input_file_name), "",
  1342. "");
  1343. }
  1344. if (conf_has("token")) {
  1345. file_hide_token(tpc.answer_file_name, conf_str("token", ""));
  1346. }
  1347. } else {
  1348. RunProgramConfig rpc;
  1349. rpc.result_file_name = result_path + "/run_standard_program.txt";
  1350. string real_output_file_name = tpc.answer_file_name;
  1351. string real_input_file_name = tpc.output_file_name + ".real_output.txt";
  1352. RunSimpleInteractionResult rires = run_simple_interation(
  1353. tpc.input_file_name,
  1354. tpc.answer_file_name,
  1355. real_input_file_name,
  1356. real_output_file_name,
  1357. conf_run_limit("standard", 0, default_std_run_limit),
  1358. conf_run_limit("interactor", 0, RL_INTERACTOR_DEFAULT),
  1359. "std",
  1360. rpc);
  1361. if (rires.ires.type != RS_AC) {
  1362. return PointInfo(0, 0, -1, -1,
  1363. "Interactor " + info_str(rires.ires.type) + " (Standard Program)",
  1364. file_preview(real_input_file_name), "",
  1365. "");
  1366. }
  1367. if (rires.res.type != RS_AC) {
  1368. return PointInfo(0, 0, -1, -1,
  1369. "Standard Program " + info_str(rires.res.type),
  1370. file_preview(real_input_file_name), "",
  1371. "");
  1372. }
  1373. }
  1374. PointInfo po = test_point(name, 0, tpc);
  1375. po.scr = po.scr != 100;
  1376. return po;
  1377. }
  1378. CustomTestInfo ordinary_custom_test(const string &name) {
  1379. RunLimit lim = conf_run_limit(0, RL_DEFAULT);
  1380. lim.time += 2;
  1381. string input_file_name = work_path + "/input.txt";
  1382. string output_file_name = work_path + "/output.txt";
  1383. RunResult pro_ret = run_submission_program(
  1384. input_file_name,
  1385. output_file_name,
  1386. lim,
  1387. name);
  1388. if (conf_has("token")) {
  1389. file_hide_token(output_file_name, conf_str("token", ""));
  1390. }
  1391. string info;
  1392. if (pro_ret.type == RS_AC) {
  1393. info = "Success";
  1394. } else {
  1395. info = info_str(pro_ret.type);
  1396. }
  1397. string exp;
  1398. if (pro_ret.type == RS_TLE) {
  1399. exp = "<p>[<strong>time limit:</strong> " + vtos(lim.time) + "s]</p>";
  1400. }
  1401. return CustomTestInfo(pro_ret.ust, pro_ret.usm,
  1402. info, exp, file_preview(output_file_name, 2048));
  1403. }
  1404. int scale_score(int scr100, int full) {
  1405. return scr100 * full / 100;
  1406. }
  1407. /*====================== test End ================== */
  1408. /*======================= conf init =================== */
  1409. void main_judger_init(int argc, char **argv) {
  1410. main_path = UOJ_WORK_PATH;
  1411. work_path = main_path + "/work";
  1412. result_path = string(UOJ_RESULT_PATH);
  1413. load_config(work_path + "/submission.conf");
  1414. problem_id = conf_int("problem_id");
  1415. data_path = string(UOJ_DATA_PATH) + "/" + conf_str("problem_id");
  1416. load_config(data_path + "/problem.conf");
  1417. executef("cp %s/require/* %s 2>/dev/null", data_path.c_str(), work_path.c_str());
  1418. if (conf_is("use_builtin_judger", "on")) {
  1419. config["judger"] = string(UOJ_WORK_PATH) + "/builtin/judger/judger";
  1420. } else {
  1421. config["judger"] = data_path + "/judger";
  1422. }
  1423. }
  1424. void judger_init(int argc, char **argv) {
  1425. if (argc != 5) {
  1426. exit(1);
  1427. }
  1428. main_path = argv[1];
  1429. work_path = argv[2];
  1430. result_path = argv[3];
  1431. data_path = argv[4];
  1432. load_config(work_path + "/submission.conf");
  1433. problem_id = conf_int("problem_id");
  1434. load_config(data_path + "/problem.conf");
  1435. if (config.count("use_builtin_checker")) {
  1436. config["checker"] = main_path + "/builtin/checker/" + config["use_builtin_checker"];
  1437. } else {
  1438. config["checker"] = data_path + "/chk";
  1439. }
  1440. config["validator"] = data_path + "/val";
  1441. }
  1442. /*===================== conf init End ================= */