Giter Club home page Giter Club logo

Comments (4)

renbaoshuo avatar renbaoshuo commented on June 2, 2024 1

以下是 UOJ 目前使用的 testlib.h 与 testlib 0.9.5 版之间的 diff:

--- testlib-0.9.5/testlib.h
+++ judger/uoj_judger/include/testlib.h
@@ -120,12 +120,20 @@ const char* latestFeatures[] = {
 #endif
 
 /* Overrides random() for Borland C++. */
+#ifdef __EMSCRIPTEN__
+#define srand __srand_deprecated
+#define rand __rand_deprecated
+#endif
 #define random __random_deprecated
 #include <stdlib.h>
 #include <cstdlib>
 #include <climits>
 #include <algorithm>
 #undef random
+#ifdef __EMSCRIPTEN__
+#undef rand
+#undef srand
+#endif
 
 #include <cstdio>
 #include <cctype>
@@ -140,6 +148,10 @@ const char* latestFeatures[] = {
 
 #include <fcntl.h>
 
+#ifdef __EMSCRIPTEN__
+#include <emscripten.h>
+#endif
+
 #if ( _WIN32 || __WIN32__ || _WIN64 || __WIN64__ )
 #   if !defined(_MSC_VER) || _MSC_VER>1400
 #       include <windows.h>
@@ -152,6 +164,10 @@ const char* latestFeatures[] = {
 #   define WORD unsigned short
 #endif
 
+#ifdef linux
+#include <unistd.h>
+#endif
+
 #ifndef LLONG_MIN
 #define LLONG_MIN   (-9223372036854775807LL - 1)
 #endif
@@ -235,8 +251,8 @@ const char* latestFeatures[] = {
 #else
 #   define NORETURN
 #endif
-                   
-static char __testlib_format_buffer[16777216];
+
+static char __testlib_format_buffer[1024];
 static int __testlib_format_buffer_usage_count = 0;
 
 #define FMT_TO_RESULT(fmt, cstr, result)  std::string result;                              \
@@ -314,21 +330,17 @@ static bool __testlib_isNaN(double r)
     std::memcpy((void*)&llr1, (void*)&ra, sizeof(double)); 
     ra = -ra;
     std::memcpy((void*)&llr2, (void*)&ra, sizeof(double)); 
-    long long llnan = 0xFFF8000000000000;
+    long long llnan = 0xFFF8000000000000ll;
     return __testlib_prelimIsNaN(r) || llnan == llr1 || llnan == llr2;
 }
 
 static double __testlib_nan()
 {
     __TESTLIB_STATIC_ASSERT(sizeof(double) == sizeof(long long));
-#ifndef NAN
-    long long llnan = 0xFFF8000000000000;
+    long long llnan = 0xFFF8000000000000ll;
     double nan;
     std::memcpy(&nan, &llnan, sizeof(double));
     return nan;
-#else
-    return NAN;
-#endif
 }
 
 static bool __testlib_isInfinite(double r)
@@ -351,6 +363,23 @@ static void __testlib_set_binary(std::FI
 #endif
 }
 
+static FILE *__testlib_fopen(const char *name, const char *mode)
+{
+#ifdef __EMSCRIPTEN__
+	EM_ASM(
+		try {
+			FS.stat('/cwd');
+		} catch (e) {
+		    FS.mkdir('/cwd');
+		    FS.mount(NODEFS, { root: '.' }, '/cwd');
+		}
+	);
+	return fopen((std::string("/cwd/") + name).c_str(), mode);
+#else
+	return fopen(name, mode);
+#endif
+}
+
 /*
  * Very simple regex-like pattern.
  * It used for two purposes: validation and generation.
@@ -1629,8 +1658,8 @@ struct InStream
     /* As "readInteger()" but ensures that value in the range [minv,maxv]. */
     int readInteger(int minv, int maxv, const std::string& variableName = "");
     /* As "readInt()" but ensures that value in the range [minv,maxv]. */
-    int readInt(int minv, int maxv, const std::string& variableName = "");
-
+    
+	int readInt(int minv, int maxv, const std::string& variableName = "");
     /* 
      * Reads new double. Ignores white-spaces into the non-strict mode 
      * (strict mode is used in validators usually). 
@@ -1814,6 +1843,8 @@ InStream::InStream()
 
 InStream::InStream(const InStream& baseStream, std::string content)
 {
+	file = (FILE*)0xbadfeed;
+	stdfile = false;
     reader = new StringInputStreamReader(content);
     opened = true;
     strict = baseStream.strict;
@@ -1864,6 +1895,34 @@ void InStream::textColor(WORD color)
     HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
     SetConsoleTextAttribute(handle, color);
 #endif
+
+#ifdef linux
+	char *shell_path = getenv("SHELL");
+	if (shell_path && strcmp(shell_path, "/bin/bash") == 0 && isatty(2))
+	{
+		switch (color)
+		{
+			case 0:
+				fprintf(stderr, "\e[0m");
+				break;
+			case LightRed:
+				fprintf(stderr, "\e[0;31m");
+				break;
+			case LightGreen:
+				fprintf(stderr, "\e[0;32m");
+				break;
+			case LightYellow:
+				fprintf(stderr, "\e[0;33m");
+				break;
+    		case LightCyan:
+				fprintf(stderr, "\e[0;36m");
+				break;
+			case LightGray:
+				fprintf(stderr, "\e[0m");
+				break;
+		}
+	}
+#endif
 }
 
 NORETURN void halt(int exitCode)
@@ -1874,6 +1933,9 @@ NORETURN void halt(int exitCode)
     std::fprintf(stderr, "Exit code: %d\n", exitCode);
     InStream::textColor(InStream::LightGray);
 #endif
+#ifdef linux
+	InStream::textColor(0);
+#endif
     std::exit(exitCode);
 }
 
@@ -1945,7 +2007,7 @@ NORETURN void InStream::quit(TResult res
 
     if (resultName != "")
     {
-        resultFile = std::fopen(resultName.c_str(), "w");
+        resultFile = __testlib_fopen(resultName.c_str(), "w");
         if (resultFile == NULL)
             quit(_fail, "Can not write to the result file");
         if (appesMode)
@@ -2066,7 +2128,7 @@ void InStream::reset()
         close();
 
     if (!stdfile)
-        if (NULL == (file = std::fopen(name.c_str(), "rb")))
+        if (NULL == (file = __testlib_fopen(name.c_str(), "rb")))
         {
             if (mode == _output)
                 quits(_pe, std::string("File not found: \"") + name + "\"");
@@ -2085,8 +2147,17 @@ void InStream::reset()
 void InStream::init(std::string fileName, TMode mode)
 {
     opened = false;
-    name = fileName;
-    stdfile = false;
+	if (fileName == "/dev/stdin")
+	{
+		name = "stdin";
+		this->file = stdin;
+		stdfile = true;
+	}
+	else
+	{
+		name = fileName;
+		stdfile = false;
+	}
     this->mode = mode;
     reset();
 }
@@ -2524,24 +2595,24 @@ int InStream::readInt()
     return readInteger();
 }
 
-int InStream::readInt(int minv, int maxv, const std::string& variableName)
+int InStream::readInt(int minv, int maxv, const std::string &variableName)
 {
     int result = readInt();
 
     if (result < minv || result > maxv)
-    {
-        if (variableName.empty())
-            quit(_wa, ("Integer " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
-        else
-            quit(_wa, ("Integer parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
-    }
+	{
+		if (variableName.empty())
+			quit(_wa, ("Integer " + vtos(result) + " violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
+		else
+			quit(_wa, ("Integer parameter [name=" + std::string(variableName) + "] equals to " + vtos(result) + ", violates the range [" + vtos(minv) + ", " + vtos(maxv) + "]").c_str());
+	}
 
     return result;
 }
 
 int InStream::readInteger(int minv, int maxv, const std::string& variableName)
 {
-    return readInt(minv, maxv, variableName);
+    return readInt(minv, maxv, variableName.c_str());
 }
 
 double InStream::readReal()
@@ -2659,7 +2730,7 @@ bool InStream::eoln()
     {
         bool returnCr = false;
 
-#ifdef ON_WINDOWS
+#ifdef CR_MUST_IN_EOL
         if (c != CR)
         {
             reader->unreadChar(c);
@@ -2955,18 +3026,6 @@ void registerGen(int argc, char* argv[])
     registerGen(argc, argv, 0);
 }
 #else
-#ifdef __GNUC__
-    __attribute__ ((deprecated("Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)."
-            " The third parameter stands for the random generator version."
-            " If you are trying to compile old generator use macro -DUSE_RND_AS_BEFORE_087 or registerGen(argc, argv, 0)."
-            " Version 1 has been released on Spring, 2013. Use it to write new generators.")))
-#endif
-#ifdef _MSC_VER
-    __declspec(deprecated("Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)."
-            " The third parameter stands for the random generator version."
-            " If you are trying to compile old generator use macro -DUSE_RND_AS_BEFORE_087 or registerGen(argc, argv, 0)."
-            " Version 1 has been released on Spring, 2013. Use it to write new generators."))
-#endif
 void registerGen(int argc, char* argv[])
 {
     std::fprintf(stderr, "Use registerGen(argc, argv, 0) or registerGen(argc, argv, 1)."
@@ -3022,9 +3081,12 @@ void registerInteraction(int argc, char*
 
     inf.init(argv[1], _input);
 
-    tout.open(argv[2], std::ios_base::out);
-    if (tout.fail() || !tout.is_open())
-        quit(_fail, std::string("Can not write to the test-output-file '") + argv[2] + std::string("'"));
+	if (strcmp(argv[2], "stdout") != 0)
+	{
+	    tout.open(argv[2], std::ios_base::out);
+	    if (tout.fail() || !tout.is_open())
+	    	quit(_fail, std::string("Can not write to the test-output-file '") + argv[2] + std::string("'"));
+	}
 
     ouf.init(stdin, _output);
     
@@ -3228,9 +3290,6 @@ void shuffle(_RandomAccessIter __first,
 
 
 template<typename _RandomAccessIter>
-#ifdef __GNUC__
-__attribute__ ((error("Don't use random_shuffle(), use shuffle() instead")))
-#endif
 void random_shuffle(_RandomAccessIter , _RandomAccessIter )
 {
     quitf(_fail, "Don't use random_shuffle(), use shuffle() instead");
@@ -3242,9 +3301,6 @@ void random_shuffle(_RandomAccessIter ,
 #  define RAND_THROW_STATEMENT
 #endif
 
-#ifdef __GNUC__
-__attribute__ ((error("Don't use rand(), use rnd.next() instead")))
-#endif
 int rand() RAND_THROW_STATEMENT
 {
     quitf(_fail, "Don't use rand(), use rnd.next() instead");
@@ -3253,12 +3309,6 @@ int rand() RAND_THROW_STATEMENT
     //throw "Don't use rand(), use rnd.next() instead";
 }
 
-#ifdef __GNUC__
-__attribute__ ((error("Don't use srand(), you should use " 
-        "'registerGen(argc, argv, 1);' to initialize generator seed "
-        "by hash code of the command line params. The third parameter "
-        "is randomGeneratorVersion (currently the latest is 1).")))
-#endif
 void srand(unsigned int seed) RAND_THROW_STATEMENT
 {
     quitf(_fail, "Don't use srand(), you should use " 

from uoj.

yhx-12243 avatar yhx-12243 commented on June 2, 2024

确实,不然 testlib 不能用 readInts 这种东西还挺难受的

from uoj.

vfleaking avatar vfleaking commented on June 2, 2024

很赞成,而且老版 testlib 有个 BUG(一下子找不到对应的链接了)。目前 UOJ 管理员传题,也多是使用自己上传的新版 testlib。

主要难点如下:

  1. uoj 用的 testlib 是个魔改版,我记得主要魔改的地方是 registerInteraction 的部分。可能需要 diff 一下还有没有别的地方被魔改了
  2. 以前上传的题目在 testlib 更新后,最好重新生成一遍数据包,并检查题目是否还能正常评测。感觉有点工程量。。(这也是 UOJ 的 testlib 一直都没有更新的主要原因)

from uoj.

yhx-12243 avatar yhx-12243 commented on June 2, 2024

感觉一种可能的方法是像 Testlib-for-Lemons 一样开个类似的 “Testlib-for-uoj” 库,然后和上游 MikeMirzayanov/testlib 保持一种同步,不过代价是可能要稍微改一下 include 结构,因为 git 的 submodule 只能加目录

from uoj.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.