The second line should read FILE *f = fmemopen(s, strlen(s), "r");
. As posted, fmemopen
has undefined behavior and might return NULL
, which causes getwc()
to crash.
Changing the fmemopen()
line and adding a check for NULL
fixes the crash but does not meet the OPs goal.
It seems wide orientation is not supported on streams open with fmemopen()
, At least for the GNU C library. Note that fmemopen
is not defined in the C Standard but in POSIX.1-2008 and is not available on many systems (like OS/X).
Here is a corrected and extended version of your program:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
int main(void) {
const char *s = "foo bar foo";
FILE *f = fmemopen((void *)s, strlen(s), "r");
wchar_t c;
if (f == NULL) {
printf("fmemopen failed: %s\n", strerror(errno));
return 1;
}
printf("default wide orientation: %d\n", fwide(f, 0));
printf("selected wide orientation: %d\n", fwide(f, 1));
while ((c = getwc(f)) != WEOF) {
printf("read %lc (%d 0x%x)\n", c, c, c);
}
return 0;
}
Run on linux:
default wide orientation: -1
selected wide orientation: -1
No output, WEOF
is returned immediately.
Explanation for fwide(f, 0)
from the linux man page:
SYNOPSIS
#include <wchar.h>
int fwide(FILE *stream, int mode);
When mode
is zero, the fwide()
function determines the current orientation of stream
. It returns a positive value if stream
is wide-character oriented, that is, if wide-character I/O is permitted but char I/O is disallowed. It returns a negative value if stream
is byte oriented, i.e., if char I/O is permitted but wide-character I/O is disallowed. It returns zero if stream
has no orientation yet; in this case the next I/O operation might change the orientation (to byte oriented if it is a char I/O operation, or to wide-character oriented if it is a wide-character I/O operation).
Once a stream has an orientation, it cannot be changed and persists until the stream is closed.
When mode
is nonzero, the fwide()
function first attempts to set stream
's orientation (to wide-character oriented if mode is greater than 0, or to byte oriented if mode
is less than 0). It then returns a value denoting the current orientation, as above.
The stream returned by fmemopen()
is byte-oriented and cannot be changed to wide-character oriented.
fmemopen
invocation is invalid – Peepholeiconv_open()
andiconv()
might be a better solution to the underlying problem. – Beardsleyiconv
in the background - it uses a separate buffer for already-converted data. After you have set the locale (all, orLC_CTYPE
), you can usenl_langinfo(CODESET)
to obtain the character set in a form you can supply toiconv_open()
. While this is not ISO C, it is POSIX.1, and should be quite portable. (Since there is even GNUlibiconv
, this approach should be relatively easy to port across to any system using standard C, including Windows.) – Beardsley