From a6d9222aead53c913560a89cc7677196d761e532 Mon Sep 17 00:00:00 2001 From: Baoshuo Date: Tue, 28 Mar 2023 21:08:20 +0800 Subject: [PATCH] feat: allow empty input_pre and output_pre --- judger/uoj_judger/include/uoj_judger.h | 58 ++++++++-- judger/uoj_judger/include/uoj_judger_v2.h | 55 +++++++++- web/app/libs/uoj-judger-lib.php | 8 +- web/app/models/StrictFileReader.php | 126 ++++++++++++---------- web/app/models/UOJProblemConf.php | 27 +++-- web/app/models/UOJProblemConfigure.php | 20 ++-- 6 files changed, 205 insertions(+), 89 deletions(-) diff --git a/judger/uoj_judger/include/uoj_judger.h b/judger/uoj_judger/include/uoj_judger.h index 1e6ade4..87a0dab 100644 --- a/judger/uoj_judger/include/uoj_judger.h +++ b/judger/uoj_judger/include/uoj_judger.h @@ -50,6 +50,44 @@ inline string htmlspecialchars(const string &s) { 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 ====================== */ inline string gen_token() { @@ -679,14 +717,22 @@ void print_config() { } 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 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) { ostringstream sout; @@ -759,7 +805,7 @@ string conf_input_file_name(int num) { if (num < 0) { 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(); } string conf_output_file_name(int num) { @@ -768,7 +814,7 @@ string conf_output_file_name(int num) { if (num < 0) { 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(); } runp::limits_t conf_run_limit(string pre, const int &num, const runp::limits_t &val) { diff --git a/judger/uoj_judger/include/uoj_judger_v2.h b/judger/uoj_judger/include/uoj_judger_v2.h index d804a4f..687d959 100644 --- a/judger/uoj_judger/include/uoj_judger_v2.h +++ b/judger/uoj_judger/include/uoj_judger_v2.h @@ -59,6 +59,44 @@ inline string list_to_string(const T &list) { 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 ====================== */ inline string gen_token() { @@ -463,13 +501,22 @@ void print_config() { } void load_config(const string &filename) { ifstream fin(filename.c_str()); + if (!fin) { return; } + 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) { ostringstream sout; @@ -535,7 +582,7 @@ string conf_input_file_name(int num) { if (num < 0) { 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(); } string conf_output_file_name(int num) { @@ -543,7 +590,7 @@ string conf_output_file_name(int num) { if (num < 0) { 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(); } runp::limits_t conf_run_limit(string pre, const int &num, const runp::limits_t &val) { diff --git a/web/app/libs/uoj-judger-lib.php b/web/app/libs/uoj-judger-lib.php index f1cc419..0fe0080 100644 --- a/web/app/libs/uoj-judger-lib.php +++ b/web/app/libs/uoj-judger-lib.php @@ -67,16 +67,16 @@ function getUOJConfVal($conf, $key, $default_val) { } 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) { - 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) { - 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) { - 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) { diff --git a/web/app/models/StrictFileReader.php b/web/app/models/StrictFileReader.php index ab0db3d..8a73e04 100644 --- a/web/app/models/StrictFileReader.php +++ b/web/app/models/StrictFileReader.php @@ -1,65 +1,81 @@ f = fopen($file_name, 'r'); - } + public function __construct($file_name) { + $this->f = fopen($file_name, 'r'); + } - public function failed() { - return $this->f === false; - } + public function failed() { + return $this->f === false; + } - public function readChar() { - if (isset($this->buf[$this->off])) { - return $this->buf[$this->off++]; - } - return fgetc($this->f); - } - public function unreadChar($c) { - $this->buf .= $c; - if ($this->off > 1000) { - $this->buf = substr($this->buf, $this->off); - $this->off = 0; - } - } + public function readChar() { + if (isset($this->buf[$this->off])) { + return $this->buf[$this->off++]; + } + return fgetc($this->f); + } + public function unreadChar($c) { + $this->buf .= $c; + if ($this->off > 1000) { + $this->buf = substr($this->buf, $this->off); + $this->off = 0; + } + } - public function readString() { - $str = ''; - while (true) { - $c = $this->readChar(); - if ($c === false) { - break; - } elseif ($c === " " || $c === "\n" || $c === "\r") { - $this->unreadChar($c); - break; - } else { - $str .= $c; - } - } - 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 readString() { + $str = ''; + while (true) { + $c = $this->readChar(); + if ($c === false) { + break; + } elseif ($c === " " || $c === "\n" || $c === "\r") { + $this->unreadChar($c); + break; + } else { + $str .= $c; + } + } + return $str; + } - public function eof() { - return feof($this->f); - } + public function readLine() { + $str = ''; + while (true) { + $c = $this->readChar(); + if ($c === false) { + break; + } elseif ($c === "\n") { + break; + } else { + $str .= $c; + } + } + return $str; + } - public function close() { - fclose($this->f); - } + 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() { + return feof($this->f); + } + + public function close() { + fclose($this->f); + } } diff --git a/web/app/models/UOJProblemConf.php b/web/app/models/UOJProblemConf.php index 0f2cb01..7cdc1e3 100644 --- a/web/app/models/UOJProblemConf.php +++ b/web/app/models/UOJProblemConf.php @@ -10,24 +10,28 @@ class UOJProblemConf { } $conf = []; + while (!$reader->eof()) { $reader->ignoreWhite(); - $key = $reader->readString(); - if ($key === '') { - break; - } - $reader->ignoreWhite(); - $val = $reader->readString(); - if ($val === '') { + + $line = $reader->readLine(); + $line = explode(' ', $line); + + $key = array_shift($line); + + if (!$key) { break; } if (isset($conf[$key])) { return -2; } - $conf[$key] = $val; + + $conf[$key] = trim(implode(' ', $line)); } + $reader->close(); + return new UOJProblemConf($conf); } @@ -37,9 +41,11 @@ class UOJProblemConf { public function putToFile($file_name) { $f = fopen($file_name, 'w'); + foreach ($this->conf as $key => $val) { fwrite($f, "{$key} {$val}\n"); } + fclose($f); } @@ -55,15 +61,16 @@ class UOJProblemConf { return $this->conf[$key]; } } + return $default_val; } 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) { - 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) { diff --git a/web/app/models/UOJProblemConfigure.php b/web/app/models/UOJProblemConfigure.php index e39a5c3..f786e8d 100644 --- a/web/app/models/UOJProblemConfigure.php +++ b/web/app/models/UOJProblemConfigure.php @@ -85,10 +85,10 @@ class UOJProblemConfigure { $this->simple_form->appendHTML(static::getCardFooter()); $this->simple_form->appendHTML(static::getCardHeader('文件配置')); - $this->addTextInput($this->simple_form, 'input_pre', '输入文件名称', ''); - $this->addTextInput($this->simple_form, 'input_suf', '输入文件后缀', ''); - $this->addTextInput($this->simple_form, 'output_pre', '输出文件名称', ''); - $this->addTextInput($this->simple_form, 'output_suf', '输出文件后缀', ''); + $this->addTextInput($this->simple_form, 'input_pre', '输入文件名称', '', ['validator_php' => fn ($x) => '']); + $this->addTextInput($this->simple_form, 'input_suf', '输入文件后缀', 'in', ['validator_php' => fn ($x) => '']); + $this->addTextInput($this->simple_form, 'output_pre', '输出文件名称', '', ['validator_php' => fn ($x) => '']); + $this->addTextInput($this->simple_form, 'output_suf', '输出文件后缀', 'out', ['validator_php' => fn ($x) => '']); $this->simple_form->appendHTML(static::getCardFooter()); $this->simple_form->appendHTML(static::getCardHeader('运行时限制')); @@ -227,7 +227,7 @@ class UOJProblemConfigure { public function addNumberInput(UOJForm $form, $key, $label, $default_val = '', $cfg = []) { $this->conf_keys[$key] = true; - $form->addInput($key, [ + $form->addInput($key, $cfg + [ 'type' => 'number', 'label' => $label, 'div_class' => 'row gx-2', @@ -237,7 +237,7 @@ class UOJProblemConfigure { 'validator_php' => function ($x) { return validateInt($x) ? '' : '必须为一个整数'; }, - ] + $cfg); + ]); $form->appendHTML(<< $('#input-{$key}').change(function() { @@ -250,7 +250,7 @@ class UOJProblemConfigure { public function addTimeLimitInput(UOJForm $form, $key, $label, $default_val = '', $cfg = []) { $this->conf_keys[$key] = true; - $form->addInput($key, [ + $form->addInput($key, $cfg + [ 'type' => 'number', 'label' => $label, 'input_attrs' => ['step' => 0.001], @@ -267,7 +267,7 @@ class UOJProblemConfigure { return ''; } }, - ] + $cfg); + ]); $form->appendHTML(<< $('#input-{$key}').change(function() { @@ -280,7 +280,7 @@ class UOJProblemConfigure { public function addTextInput(UOJForm $form, $key, $label, $default_val = '', $cfg = []) { $this->conf_keys[$key] = true; - $form->addInput($key, [ + $form->addInput($key, $cfg + [ 'label' => $label, 'div_class' => 'row gx-2', 'label_class' => 'col-form-label col-4', @@ -289,7 +289,7 @@ class UOJProblemConfigure { 'validator_php' => function ($x) { return ctype_graph($x) ? '' : '必须仅包含除空格以外的可见字符'; }, - ] + $cfg); + ]); $form->appendHTML(<< $('#input-{$key}').change(function() {