Compare commits

...

2 Commits

Author SHA1 Message Date
a6d9222aea
feat: allow empty input_pre and output_pre
All checks were successful
continuous-integration/drone/push Build is passing
2023-03-28 21:08:20 +08:00
04ab18076b
chore(submission): disable hack for remote submissions 2023-03-28 21:05:39 +08:00
8 changed files with 210 additions and 89 deletions

View File

@ -50,6 +50,44 @@ inline string htmlspecialchars(const string &s) {
return r; return r;
} }
// trim from start (in place)
inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
// trim from both ends (in place)
inline void trim(std::string &s) {
rtrim(s);
ltrim(s);
}
// trim from start (copying)
inline std::string ltrim_copy(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
inline std::string rtrim_copy(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
inline std::string trim_copy(std::string s) {
trim(s);
return s;
}
/*========================== random ====================== */ /*========================== random ====================== */
inline string gen_token() { inline string gen_token() {
@ -679,14 +717,22 @@ void print_config() {
} }
void load_config(const string &filename) { void load_config(const string &filename) {
ifstream fin(filename.c_str()); ifstream fin(filename.c_str());
if (!fin) { if (!fin) {
return; return;
} }
string key;
string val; string key, val;
while (fin >> key >> val) {
config[key] = val; // the first token of a line is key, the rest is value
while (fin >> key) {
getline(fin, val);
config[key] = trim_copy(val);
} }
// while (fin >> key >> val) {
// config[key] = val;
// }
} }
string conf_str(const string &key, int num, const string &val) { string conf_str(const string &key, int num, const string &val) {
ostringstream sout; ostringstream sout;
@ -759,7 +805,7 @@ string conf_input_file_name(int num) {
if (num < 0) { if (num < 0) {
name << "ex_"; name << "ex_";
} }
name << conf_str("input_pre", "input") << abs(num) << "." << conf_str("input_suf", "txt"); name << conf_str("input_pre", "") << abs(num) << "." << conf_str("input_suf", "in");
return name.str(); return name.str();
} }
string conf_output_file_name(int num) { string conf_output_file_name(int num) {
@ -768,7 +814,7 @@ string conf_output_file_name(int num) {
if (num < 0) { if (num < 0) {
name << "ex_"; name << "ex_";
} }
name << conf_str("output_pre", "output") << abs(num) << "." << conf_str("output_suf", "txt"); name << conf_str("output_pre", "") << abs(num) << "." << conf_str("output_suf", "out");
return name.str(); return name.str();
} }
runp::limits_t conf_run_limit(string pre, const int &num, const runp::limits_t &val) { runp::limits_t conf_run_limit(string pre, const int &num, const runp::limits_t &val) {

View File

@ -59,6 +59,44 @@ inline string list_to_string(const T &list) {
return sout.str(); return sout.str();
} }
// trim from start (in place)
inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
// trim from both ends (in place)
inline void trim(std::string &s) {
rtrim(s);
ltrim(s);
}
// trim from start (copying)
inline std::string ltrim_copy(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
inline std::string rtrim_copy(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
inline std::string trim_copy(std::string s) {
trim(s);
return s;
}
/*========================== random ====================== */ /*========================== random ====================== */
inline string gen_token() { inline string gen_token() {
@ -463,13 +501,22 @@ void print_config() {
} }
void load_config(const string &filename) { void load_config(const string &filename) {
ifstream fin(filename.c_str()); ifstream fin(filename.c_str());
if (!fin) { if (!fin) {
return; return;
} }
string key, val; string key, val;
while (fin >> key >> val) {
uconfig[key] = val; // the first token of a line is key, the rest is value
while (fin >> key) {
getline(fin, val);
uconfig[key] = trim_copy(val);
} }
// while (fin >> key >> val) {
// uconfig[key] = val;
// }
} }
string conf_str(const string &key, int num, const string &val) { string conf_str(const string &key, int num, const string &val) {
ostringstream sout; ostringstream sout;
@ -535,7 +582,7 @@ string conf_input_file_name(int num) {
if (num < 0) { if (num < 0) {
name << "ex_"; name << "ex_";
} }
name << conf_str("input_pre", "input") << abs(num) << "." << conf_str("input_suf", "txt"); name << conf_str("input_pre", "") << abs(num) << "." << conf_str("input_suf", "in");
return name.str(); return name.str();
} }
string conf_output_file_name(int num) { string conf_output_file_name(int num) {
@ -543,7 +590,7 @@ string conf_output_file_name(int num) {
if (num < 0) { if (num < 0) {
name << "ex_"; name << "ex_";
} }
name << conf_str("output_pre", "output") << abs(num) << "." << conf_str("output_suf", "txt"); name << conf_str("output_pre", "") << abs(num) << "." << conf_str("output_suf", "out");
return name.str(); return name.str();
} }
runp::limits_t conf_run_limit(string pre, const int &num, const runp::limits_t &val) { runp::limits_t conf_run_limit(string pre, const int &num, const runp::limits_t &val) {

View File

@ -109,6 +109,7 @@ function handleUpload($zip_file_name, $content, $tot_size) {
if (UOJProblem::info('type') == 'remote') { if (UOJProblem::info('type') == 'remote') {
$submit_type = in_array($_POST['answer_remote_submit_type'], $remote_provider['submit_type']) ? $_POST['answer_remote_submit_type'] : $remote_provider['submit_type'][0]; $submit_type = in_array($_POST['answer_remote_submit_type'], $remote_provider['submit_type']) ? $_POST['answer_remote_submit_type'] : $remote_provider['submit_type'][0];
$content['remote_judge'] = true;
$content['config'][] = ['remote_submit_type', $submit_type]; $content['config'][] = ['remote_submit_type', $submit_type];
if ($submit_type != 'bot') { if ($submit_type != 'bot') {

View File

@ -67,16 +67,16 @@ function getUOJConfVal($conf, $key, $default_val) {
} }
function getUOJProblemInputFileName($problem_conf, $num) { function getUOJProblemInputFileName($problem_conf, $num) {
return getUOJConfVal($problem_conf, 'input_pre', 'input') . $num . '.' . getUOJConfVal($problem_conf, 'input_suf', 'txt'); return getUOJConfVal($problem_conf, 'input_pre', '') . $num . '.' . getUOJConfVal($problem_conf, 'input_suf', 'in');
} }
function getUOJProblemOutputFileName($problem_conf, $num) { function getUOJProblemOutputFileName($problem_conf, $num) {
return getUOJConfVal($problem_conf, 'output_pre', 'output') . $num . '.' . getUOJConfVal($problem_conf, 'output_suf', 'txt'); return getUOJConfVal($problem_conf, 'output_pre', '') . $num . '.' . getUOJConfVal($problem_conf, 'output_suf', 'out');
} }
function getUOJProblemExtraInputFileName($problem_conf, $num) { function getUOJProblemExtraInputFileName($problem_conf, $num) {
return 'ex_' . getUOJConfVal($problem_conf, 'input_pre', 'input') . $num . '.' . getUOJConfVal($problem_conf, 'input_suf', 'txt'); return 'ex_' . getUOJConfVal($problem_conf, 'input_pre', '') . $num . '.' . getUOJConfVal($problem_conf, 'input_suf', 'in');
} }
function getUOJProblemExtraOutputFileName($problem_conf, $num) { function getUOJProblemExtraOutputFileName($problem_conf, $num) {
return 'ex_' . getUOJConfVal($problem_conf, 'output_pre', 'output') . $num . '.' . getUOJConfVal($problem_conf, 'output_suf', 'txt'); return 'ex_' . getUOJConfVal($problem_conf, 'output_pre', '') . $num . '.' . getUOJConfVal($problem_conf, 'output_suf', 'out');
} }
function updateBestACSubmissions($username, $problem_id) { function updateBestACSubmissions($username, $problem_id) {

View File

@ -1,65 +1,81 @@
<?php <?php
class StrictFileReader { class StrictFileReader {
private $f; private $f;
private $buf = '', $off = 0; private $buf = '', $off = 0;
public function __construct($file_name) { public function __construct($file_name) {
$this->f = fopen($file_name, 'r'); $this->f = fopen($file_name, 'r');
} }
public function failed() { public function failed() {
return $this->f === false; return $this->f === false;
} }
public function readChar() { public function readChar() {
if (isset($this->buf[$this->off])) { if (isset($this->buf[$this->off])) {
return $this->buf[$this->off++]; return $this->buf[$this->off++];
} }
return fgetc($this->f); return fgetc($this->f);
} }
public function unreadChar($c) { public function unreadChar($c) {
$this->buf .= $c; $this->buf .= $c;
if ($this->off > 1000) { if ($this->off > 1000) {
$this->buf = substr($this->buf, $this->off); $this->buf = substr($this->buf, $this->off);
$this->off = 0; $this->off = 0;
} }
} }
public function readString() { public function readString() {
$str = ''; $str = '';
while (true) { while (true) {
$c = $this->readChar(); $c = $this->readChar();
if ($c === false) { if ($c === false) {
break; break;
} elseif ($c === " " || $c === "\n" || $c === "\r") { } elseif ($c === " " || $c === "\n" || $c === "\r") {
$this->unreadChar($c); $this->unreadChar($c);
break; break;
} else { } else {
$str .= $c; $str .= $c;
} }
} }
return $str; return $str;
} }
public function ignoreWhite() {
while (true) {
$c = $this->readChar();
if ($c === false) {
break;
} elseif ($c === " " || $c === "\n" || $c === "\r") {
continue;
} else {
$this->unreadChar($c);
break;
}
}
}
public function eof() { public function readLine() {
return feof($this->f); $str = '';
} while (true) {
$c = $this->readChar();
if ($c === false) {
break;
} elseif ($c === "\n") {
break;
} else {
$str .= $c;
}
}
return $str;
}
public function close() { public function ignoreWhite() {
fclose($this->f); while (true) {
} $c = $this->readChar();
if ($c === false) {
break;
} elseif ($c === " " || $c === "\n" || $c === "\r") {
continue;
} else {
$this->unreadChar($c);
break;
}
}
}
public function eof() {
return feof($this->f);
}
public function close() {
fclose($this->f);
}
} }

View File

@ -10,24 +10,28 @@ class UOJProblemConf {
} }
$conf = []; $conf = [];
while (!$reader->eof()) { while (!$reader->eof()) {
$reader->ignoreWhite(); $reader->ignoreWhite();
$key = $reader->readString();
if ($key === '') { $line = $reader->readLine();
break; $line = explode(' ', $line);
}
$reader->ignoreWhite(); $key = array_shift($line);
$val = $reader->readString();
if ($val === '') { if (!$key) {
break; break;
} }
if (isset($conf[$key])) { if (isset($conf[$key])) {
return -2; return -2;
} }
$conf[$key] = $val;
$conf[$key] = trim(implode(' ', $line));
} }
$reader->close(); $reader->close();
return new UOJProblemConf($conf); return new UOJProblemConf($conf);
} }
@ -37,9 +41,11 @@ class UOJProblemConf {
public function putToFile($file_name) { public function putToFile($file_name) {
$f = fopen($file_name, 'w'); $f = fopen($file_name, 'w');
foreach ($this->conf as $key => $val) { foreach ($this->conf as $key => $val) {
fwrite($f, "{$key} {$val}\n"); fwrite($f, "{$key} {$val}\n");
} }
fclose($f); fclose($f);
} }
@ -55,15 +61,16 @@ class UOJProblemConf {
return $this->conf[$key]; return $this->conf[$key];
} }
} }
return $default_val; return $default_val;
} }
public function getInputFileName($num) { public function getInputFileName($num) {
return $this->getVal('input_pre', 'input') . $num . '.' . $this->getVal('input_suf', 'txt'); return $this->getVal('input_pre', '') . $num . '.' . $this->getVal('input_suf', 'txt');
} }
public function getOutputFileName($num) { public function getOutputFileName($num) {
return $this->getVal('output_pre', 'output') . $num . '.' . $this->getVal('output_suf', 'txt'); return $this->getVal('output_pre', '') . $num . '.' . $this->getVal('output_suf', 'txt');
} }
public function getExtraInputFileName($num) { public function getExtraInputFileName($num) {

View File

@ -85,10 +85,10 @@ class UOJProblemConfigure {
$this->simple_form->appendHTML(static::getCardFooter()); $this->simple_form->appendHTML(static::getCardFooter());
$this->simple_form->appendHTML(static::getCardHeader('文件配置')); $this->simple_form->appendHTML(static::getCardHeader('文件配置'));
$this->addTextInput($this->simple_form, 'input_pre', '输入文件名称', ''); $this->addTextInput($this->simple_form, 'input_pre', '输入文件名称', '', ['validator_php' => fn ($x) => '']);
$this->addTextInput($this->simple_form, 'input_suf', '输入文件后缀', ''); $this->addTextInput($this->simple_form, 'input_suf', '输入文件后缀', 'in', ['validator_php' => fn ($x) => '']);
$this->addTextInput($this->simple_form, 'output_pre', '输出文件名称', ''); $this->addTextInput($this->simple_form, 'output_pre', '输出文件名称', '', ['validator_php' => fn ($x) => '']);
$this->addTextInput($this->simple_form, 'output_suf', '输出文件后缀', ''); $this->addTextInput($this->simple_form, 'output_suf', '输出文件后缀', 'out', ['validator_php' => fn ($x) => '']);
$this->simple_form->appendHTML(static::getCardFooter()); $this->simple_form->appendHTML(static::getCardFooter());
$this->simple_form->appendHTML(static::getCardHeader('运行时限制')); $this->simple_form->appendHTML(static::getCardHeader('运行时限制'));
@ -227,7 +227,7 @@ class UOJProblemConfigure {
public function addNumberInput(UOJForm $form, $key, $label, $default_val = '', $cfg = []) { public function addNumberInput(UOJForm $form, $key, $label, $default_val = '', $cfg = []) {
$this->conf_keys[$key] = true; $this->conf_keys[$key] = true;
$form->addInput($key, [ $form->addInput($key, $cfg + [
'type' => 'number', 'type' => 'number',
'label' => $label, 'label' => $label,
'div_class' => 'row gx-2', 'div_class' => 'row gx-2',
@ -237,7 +237,7 @@ class UOJProblemConfigure {
'validator_php' => function ($x) { 'validator_php' => function ($x) {
return validateInt($x) ? '' : '必须为一个整数'; return validateInt($x) ? '' : '必须为一个整数';
}, },
] + $cfg); ]);
$form->appendHTML(<<<EOD $form->appendHTML(<<<EOD
<script> <script>
$('#input-{$key}').change(function() { $('#input-{$key}').change(function() {
@ -250,7 +250,7 @@ class UOJProblemConfigure {
public function addTimeLimitInput(UOJForm $form, $key, $label, $default_val = '', $cfg = []) { public function addTimeLimitInput(UOJForm $form, $key, $label, $default_val = '', $cfg = []) {
$this->conf_keys[$key] = true; $this->conf_keys[$key] = true;
$form->addInput($key, [ $form->addInput($key, $cfg + [
'type' => 'number', 'type' => 'number',
'label' => $label, 'label' => $label,
'input_attrs' => ['step' => 0.001], 'input_attrs' => ['step' => 0.001],
@ -267,7 +267,7 @@ class UOJProblemConfigure {
return ''; return '';
} }
}, },
] + $cfg); ]);
$form->appendHTML(<<<EOD $form->appendHTML(<<<EOD
<script> <script>
$('#input-{$key}').change(function() { $('#input-{$key}').change(function() {
@ -280,7 +280,7 @@ class UOJProblemConfigure {
public function addTextInput(UOJForm $form, $key, $label, $default_val = '', $cfg = []) { public function addTextInput(UOJForm $form, $key, $label, $default_val = '', $cfg = []) {
$this->conf_keys[$key] = true; $this->conf_keys[$key] = true;
$form->addInput($key, [ $form->addInput($key, $cfg + [
'label' => $label, 'label' => $label,
'div_class' => 'row gx-2', 'div_class' => 'row gx-2',
'label_class' => 'col-form-label col-4', 'label_class' => 'col-form-label col-4',
@ -289,7 +289,7 @@ class UOJProblemConfigure {
'validator_php' => function ($x) { 'validator_php' => function ($x) {
return ctype_graph($x) ? '' : '必须仅包含除空格以外的可见字符'; return ctype_graph($x) ? '' : '必须仅包含除空格以外的可见字符';
}, },
] + $cfg); ]);
$form->appendHTML(<<<EOD $form->appendHTML(<<<EOD
<script> <script>
$('#input-{$key}').change(function() { $('#input-{$key}').change(function() {

View File

@ -480,6 +480,10 @@ class UOJSubmission {
} }
public function preHackCheck(array $user = null) { public function preHackCheck(array $user = null) {
if ($this->getContent('remote_judge')) {
return false;
}
return $this->info['score'] == 100 && $this->problem->preHackCheck($user); return $this->info['score'] == 100 && $this->problem->preHackCheck($user);
} }