The traditional way is to have a configuration system in your program which tells you what the platform has and doesn't have:
In some source file dedicated to portability, you have:
#if !HAVE_WCSDUP
wchar_t *wcsdup(const wchar_t *orig)
{
#if HAVE_MICROSOFT_WCSDUP
return _wcsdup(orig);
#else
size_t nwch = wcslen(orig) + 1;
wchar_t *copy = wmalloc(nwch);
if (copy)
wmemcpy(copy, orig, nwch);
return copy;
#endif
}
#endif
In some header file (also included by the above), you have this:
#if !HAVE_WSCDUP
extern "C" wchar_t wcsdup(const wchar_t *);
#endif
to provide the missing declaration. A possible approach also is this. In the header file, you do:
#if HAVE_WCSDUP
// nothing to provide
#elif HAVE_MICROSOFT_WCSDUP
// just alias to the Microsoft one via #define
#define wcsdup _wcsdup
#else
// declare ours: provided in portability.cc
extern "C" wchar_t wcsdup(const wchar_t *);
#endif
Then in portability.cc
:
#if !HAVE_WCSDUP && !HAVE_MICROSOFT_WCSDUP
wchar_t *wcsdup(const wchar_t *orig)
{
size_t nwch = wcslen(orig) + 1;
wchar_t *copy = wmalloc(nwch);
if (copy)
wmemcpy(copy, orig, nwch);
return copy;
}
#endif
You need a build configuration system around you program to supply the values of these HAVE_
constants. On some systems, a shell script can inspect the environment and throw them into a config.h
. For some systems, you can have canned configurations; e.g. the configuration step for building on Windows might consist of copying a hand-maintained config-msvc.h
to config.h
. In config-msvc.h
you have:
#define HAVE_MICROSOFT_WCSDUP 1
I'm assuming that you need a malloc
-duplicated string due to communicating with some API that consumes one. Therefore in my answer I have refrained from pontificating about using C++ library features to solve the problem.
However, in C++ code we should probably be referring to the C functions as std::wcslen
and so forth. Or portability.cc
can just be portability.c
, if it is providing missing C functions.