From 0a3190ffb05374961ee3a26fa64936399681d2a2 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Fri, 25 Oct 2019 13:54:33 +0200 Subject: Make C library created by bdep-new portable Specifically, replace the use of fmemopen() with tmpfile(). --- bdep/new.cxx | 73 +++++++++++++++++++++++++++++++++++++++++++--------- tests/new.testscript | 8 ------ 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/bdep/new.cxx b/bdep/new.cxx index c77390f..9dfd50a 100644 --- a/bdep/new.cxx +++ b/bdep/new.cxx @@ -1407,10 +1407,10 @@ namespace bdep << endl << "#include <" << ip << exph << ">" << endl << endl - << "// Print a greeting for the specified name into the specified" << endl - << "// stream. On success, return the number of character printed." << endl - << "// On failure, set errno and return a negative value." << endl - << "//" << endl + << "/* Print a greeting for the specified name into the specified" << endl + << " * stream. On success, return the number of characters printed." << endl + << " * On failure, set errno and return a negative value." << endl + << " */" << endl << mp << "_SYMEXPORT int" << endl << "say_hello (FILE *, const char *name);" << endl; os.close (); @@ -1935,6 +1935,14 @@ namespace bdep { case lang::c: { + // It would have been nice if we could use something like + // open_memstream() or fmemopen() but these are not portable. + // So we resort to tmpfile(), which, turns out, is broken on + // Windows (it may try to create a file in the root directory of + // a drive and that may require elevated privileges). So we + // provide our own implementation for that. Who thought writing + // portable C could be so hard? + // tests/basics/driver.c // open (td / "driver.c"); @@ -1947,29 +1955,70 @@ namespace bdep os << "#include <" << ip << verh << ">" << endl; os << "#include <" << ip << apih << ">" << endl << endl + << "#ifdef _WIN32" << endl + << "#define tmpfile mytmpfile" << endl + << "static FILE *mytmpfile ();" << endl + << "#endif" << endl + << endl << "int main ()" << endl << "{" << endl << " char b[256];" << endl << endl - << " // Basics." << endl - << " //" << endl + << " /* Basics." << endl + << " */" << endl << " {" << endl - << " FILE *o = fmemopen (b, sizeof (b), \"w\");" << endl + << " FILE *o = tmpfile ();" << endl << " assert (say_hello (o, \"World\") > 0);" << endl + << " rewind (o);" << endl + << " assert (fread (b, 1, sizeof (b), o) == 14 &&" << endl + << " strncmp (b, \"Hello, World!\\n\", 14) == 0);" << endl << " fclose (o);" << endl - << " assert (strcmp (b, \"Hello, World!\\n\") == 0);" << endl << " }" << endl << endl - << " // Empty name." << endl - << " //" << endl + << " /* Empty name." << endl + << " */" << endl << " {" << endl - << " FILE *o = fmemopen (b, sizeof (b), \"w\");" << endl + << " FILE *o = tmpfile ();" << endl << " assert (say_hello (o, \"\") < 0 && errno == EINVAL);" << endl << " fclose (o);" << endl << " }" << endl << endl << " return 0;" << endl - << "}" << endl; + << "}" << endl + << endl + << "#ifdef _WIN32" << endl + << "#include " << endl + << "#include " << endl + << "#include " << endl + << endl + << "FILE *mytmpfile ()" << endl + << "{" << endl + << " char d[MAX_PATH + 1], p[MAX_PATH + 1];" << endl + << " if (GetTempPathA (sizeof (d), d) == 0 ||" << endl + << " GetTempFileNameA (d, \"tmp\", 0, p) == 0)" << endl + << " return NULL;" << endl + << endl + << " HANDLE h = CreateFileA (p," << endl + << " GENERIC_READ | GENERIC_WRITE," << endl + << " 0," << endl + << " NULL," << endl + << " CREATE_ALWAYS," << endl + << " FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE," << endl + << " NULL);" << endl + << " if (h == INVALID_HANDLE_VALUE)" << endl + << " return NULL;" << endl + << endl + << " int fd = _open_osfhandle ((intptr_t) h, _O_RDWR);" << endl + << " if (fd == -1)" << endl + << " return NULL;" << endl + << endl + << " FILE *f = _fdopen (fd, \"wb+\");" << endl + << " if (f == NULL)" << endl + << " _close (fd);" << endl + << endl + << " return f;" << endl + << "}" << endl + << "#endif" << endl; os.close (); break; diff --git a/tests/new.testscript b/tests/new.testscript index 8d28597..dcb93ea 100644 --- a/tests/new.testscript +++ b/tests/new.testscript @@ -6,10 +6,6 @@ posix = ($cxx.target.class != 'windows') -# Our C tests use fmemopen() which is not always available. -# -c_tests = ($c.target.class != 'windows' && $c.target.class != 'macos') - # Disable nesting checks in the created projects. # test.arguments += --no-checks @@ -206,7 +202,6 @@ status += -d prj : lib-c : - if $c_tests { $* -t lib -l c libprj-foo 2>>/"EOE" &libprj-foo/***; created new library project libprj-foo in $~/libprj-foo/ @@ -219,7 +214,6 @@ status += -d prj : lib-c-unit-tests : - if $c_tests { $* -t lib,unit-tests -l c libfoo 2>>/"EOE" &libfoo/***; created new library project libfoo in $~/libfoo/ @@ -587,7 +581,6 @@ status += -d prj : type : - if $c_tests { : exe : @@ -671,7 +664,6 @@ status += -d prj : c : - if $c_tests { $* -l c libprj 2>>/"EOE" &libprj/***; created new library project libprj in $~/libprj/ -- cgit v1.1