Skip to content

Windows compatibility fixes (spaces, stubs, includes) - #86

Closed
kungfubeaner wants to merge 1 commit into
fmang:masterfrom
kungfubeaner:master
Closed

Windows compatibility fixes (spaces, stubs, includes)#86
kungfubeaner wants to merge 1 commit into
fmang:masterfrom
kungfubeaner:master

Conversation

@kungfubeaner

@kungfubeaner kungfubeaner commented Aug 16, 2026

Copy link
Copy Markdown

This patch makes opustags compile and run correctly on Windows (MSYS2 UCRT64 / cmd.exe):

  • Fixed -e interactive editing win32 compatibility with filenames containing spaces by using double quotes in shell_escape on Windows.
  • Added missing <cstdint> includes in base64.cc, ogg.cc, opus.cc.
  • Centralised Windows stubs (strncasecmp, getdelim, mkstemps) into win32_compat.h.
  • Made sys/wait.h conditional to avoid Windows build error.
  • Added endianness macros (htole32, etc.) for Windows in opustags.h.

@kungfubeaner

kungfubeaner commented Aug 16, 2026

Copy link
Copy Markdown
Author

I compiled and tested it using this batch file:

@echo.
@rd /q /s build
@mkdir build && cd build
@cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXE_LINKER_FLAGS="-s -static -static-libgcc -static-libstdc++" -DIconv_LIBRARY="C:/msys64/ucrt64/lib/libiconv.a" -DOGG_LIBRARIES="C:/msys64/ucrt64/lib/libogg.a" ..
@make -j4
ntldd opustags.exe

I'm using MSYS2 UCRT64, it compiles into a static binary that does not require DLLs other than kernel32.dll and well the UCRT windows dlls which are already there in Windows 10 and Windows 11

@kungfubeaner
kungfubeaner force-pushed the master branch 2 times, most recently from c4db817 to 06ac389 Compare August 17, 2026 00:28

@fmang fmang left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the pull request!

It is too big for me to review and merge it easily, so I’d be grateful if you split it. For example:

  1. the part with byte endianness and cstdint,
  2. the file manipulation operations,
  3. the compatibility functions.

Comment thread src/opustags.h Outdated
#endif

#if defined(_WIN32) || defined(__MINGW32__)
#include <cstdint>

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than include cstdint in the .h and in every .cc, including it in opustags.h only is enough since all the .cc include it.

Comment thread src/cli.cc Outdated

// Applying the new tags.
tags_file = fopen(tags_path.c_str(), "re");
tags_file = fopen(tags_path.c_str(), "rb");

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why remove the e flag?

Comment thread src/opustags.h Outdated
inline uint32_t le32toh(uint32_t x) { return x; }
inline uint32_t htobe32(uint32_t x) {
return ((x & 0xffu) << 24) | ((x & 0xff00u) << 8) |
((x & 0xff0000u) >> 8) | ((x >> 24) & 0xffu);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the & 0xffu necessary?

Also, doesn’t Windows already provide such a function, like htonl?

Comment thread src/system.cc Outdated
Comment thread src/system.cc Outdated
{
#ifdef _WIN32
// Windows cmd.exe: double quotes protect spaces.
return "\"" + std::string(word) + "\"";

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If word contains a double quote, that’s an open door to serious shell injection vulnerabilities.

Comment thread src/cli.cc Outdated
#include <algorithm>
#include <cstdint>

#if defined(_WIN32) || defined(__MINGW32__)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why check both _WIN32 and __MINGW32__. Isn’t _WIN32 enough?

Comment thread src/system.cc Outdated
return;
file.reset();
copy_permissions(final_name.c_str(), temporary_name.c_str());
#if defined(_WIN32) || defined(__MINGW32__)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could put the call to copy_permissions in an #else here instead of defining a blank function.

Comment thread src/system.cc
std::string command = std::string(editor) + " -- " + shell_escape(path);
#endif

int status = system(command.c_str());

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is the only line in common between Windows and Unix, you might as well make on big #if instead of two halves.

Comment thread src/win32_compat.h Outdated
#define strncasecmp _strnicmp

#ifndef getdelim
static inline ssize_t getdelim(char** lineptr, size_t* n, int delim, FILE* stream) {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is huge for an inline function. You could move the definition into system.cc and add the declaration into opustags.h instead so that it is built and linked like a regular function.

By the way, where does the implementation come from?

@kungfubeaner kungfubeaner Aug 17, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote the getdelim (and mkstemps) implementations myself to get the Windows build working. I looked at a few public versions for reference while writing it, but this is my own code. Happy to move both functions out of the header into system.cc (and just declare them in the header or in opustags.h) if you prefer that style. I can also clean them up further if you’d like.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. Since C++ is loaded with footguns so I’ll make sure to review it attentively, unless we find a battle-tested alternative.

Maybe we could replace getdelim with std::getline, provided the code does not rely too much on stdio. Regarding mkstemps, Windows seems to have _mktemp that could do some of the work.

@kungfubeaner kungfubeaner Aug 18, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I will look into _mktemp, Windows seems very messy. I'll look into all this more thoroughly on Saturday including using getline instead of getdelim. My PR was pretty much out of excitement that I actually got it to compile and work on Windows. I've been wanting / needing opustags for Windows for a while.

Comment thread src/win32_compat.h Outdated

#define strncasecmp _strnicmp

#ifndef getdelim

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this for? Is it possible that getdelim is sometimes defined as a macro, sometimes not, but never defined as a function?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is so it uses the windows equivalent of strncasecmp, I'll work on all these changes and make it suitable. I have a busy week coming up and start work in 2 hours, I'l try to clean all this up and explain on Saturday.

Sorry for the lack of explanation on these changes and having to wait until Saturday.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I misunderstood your question. I added the #ifndef getdelim because I wanted to prevent a duplicate definition if the platform already supplied getdelim(). I realize now that this only checks for a preprocessor macro, not whether the function is already provided.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly. If the _WIN32 macro check is not enough, we should rely on CMake because that’s precisely what it’s for. See CheckFunctionExists.

@kungfubeaner kungfubeaner Aug 21, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took the day off today so I've been working on this. I had a question for you but nevermind, I think I have a better solution than I was just now doing.

@kungfubeaner

Copy link
Copy Markdown
Author

I've been trying to get this split for about 3 hours and I'm having trouble. I'll see if I can get it split tomorrow.

@kungfubeaner
kungfubeaner force-pushed the master branch 4 times, most recently from b70423d to 2d229e9 Compare August 22, 2026 04:24
@fmang

fmang commented Aug 22, 2026

Copy link
Copy Markdown
Owner

@kungfubeaner Please take your time. There’s no need to make the pull requests fast or all at once. You can tackle one topic, make a pull request for it, and wait until it’s merged to tackle the next. Endianness is the easiest, while the others have pitfalls.

By the way, have you tried compatibility layers like MSYS2? I’m not familiar with Windows, but they might provide the missing functions.

@kungfubeaner

Copy link
Copy Markdown
Author

Split this into three smaller PRs as requested: #87 (endianness), #88 (file manipulation), #89 (compatibility functions).

Should I close this one?

@fmang

fmang commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Sure, let’s focus on the split pull requests then.

@fmang fmang closed this Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants