diff --git a/cli/cli.cpp b/cli/cli.cpp index ab85b5c5..3c5e6115 100644 --- a/cli/cli.cpp +++ b/cli/cli.cpp @@ -14,6 +14,25 @@ #include "../src/checksum.h" #include "uv.h" +//When compiling on MSVC an assertion will trigger in the libuv library on uv_write. +//This is a workaround to avoid it. The workarund is only applied to MSVC Debug builds. +#if defined(_MSC_VER) && !defined(NDEBUG) +#define WIN_UV_WRITE_WORKAROUND +#endif + +#if defined WIN_UV_WRITE_WORKAROUND +struct heap_write_req { + uv_write_t req; + char* data; // allocated copy of dynamic text (nullptr if none) +}; + +static void heap_write_cb(uv_write_t* r, int /*status*/) { + heap_write_req* wr = reinterpret_cast(r); + if (wr->data) free(wr->data); + free(wr); +} +#endif + void show_version() { fprintf(stderr, "maxcso v%s\n", maxcso::VERSION); } @@ -436,8 +455,10 @@ int main(int argc, char *argv[]) { std::fill(std::begin(history), std::end(history), History{0, next}); std::string statusInfo; +#ifndef WIN_UV_WRITE_WORKAROUND uv_write_t write_req; uv_buf_t bufs[2]; +#endif maxcso::ProgressCallback progress = [&] (const maxcso::Task *task, maxcso::TaskStatus status, int64_t pos, int64_t total, int64_t written) { if (!formatting) { @@ -490,11 +511,33 @@ int main(int argc, char *argv[]) { statusInfo = task->input + ": " + statusInfo; } +#ifndef WIN_UV_WRITE_WORKAROUND unsigned int nbufs = 0; +#endif // DEBUG + if (formatting) { +#ifdef WIN_UV_WRITE_WORKAROUND + heap_write_req* wr = (heap_write_req*)malloc(sizeof(*wr)); + if (!wr) return; + // copy status string + size_t len = statusInfo.size(); + char* copy = (char*)malloc(len + 1); + if (!copy) { free(wr); return; } + memcpy(copy, statusInfo.c_str(), len + 1); + wr->data = copy; + + uv_buf_t bufs[2]; + unsigned nbufs = 0; + bufs[nbufs++] = ::uv_buf_init(ANSI_RESET_LINE); // literal OK + bufs[nbufs++] = ::uv_buf_init(copy, (unsigned)len); // heap copy + + int rc = uv_write(&wr->req, reinterpret_cast(&tty), bufs, nbufs, heap_write_cb); + if (rc != 0) { free(copy); free(wr); /* handle error if needed */ } +#else bufs[nbufs++] = uv_buf_init(ANSI_RESET_LINE); bufs[nbufs++] = uv_buf_init(statusInfo); uv_write(&write_req, reinterpret_cast(&tty), bufs, nbufs, nullptr); +#endif } else { fprintf(stderr, "%s", statusInfo.c_str()); } @@ -512,8 +555,27 @@ int main(int argc, char *argv[]) { const std::string prefix = status == maxcso::TASK_SUCCESS ? "" : "Error while processing "; statusInfo = (formatting ? ANSI_RESET_LINE : "") + prefix + task->input + ": " + reason + "\n"; if (formatting) { +#ifdef WIN_UV_WRITE_WORKAROUND + heap_write_req* wr = (heap_write_req*)malloc(sizeof(*wr)); + if (!wr) return; + // copy status string + size_t len = statusInfo.size(); + char* copy = (char*)malloc(len + 1); + if (!copy) { free(wr); return; } + memcpy(copy, statusInfo.c_str(), len + 1); + wr->data = copy; + + uv_buf_t bufs[2]; + unsigned nbufs = 0; + bufs[nbufs++] = ::uv_buf_init(ANSI_RESET_LINE); // literal OK + bufs[nbufs++] = ::uv_buf_init(copy, (unsigned)len); // heap copy + + int rc = uv_write(&wr->req, reinterpret_cast(&tty), bufs, nbufs, heap_write_cb); + if (rc != 0) { free(copy); free(wr); /* handle error if needed */ } +#else bufs[0] = uv_buf_init(statusInfo); uv_write(&write_req, reinterpret_cast(&tty), bufs, 1, nullptr); +#endif } else { fprintf(stderr, "%s", statusInfo.c_str()); }