Есть файл в UTF-8 с русскими буквами.
В исходнике он открывается, содержимое перекодируется в UCS-4 ( для того, чтобы можно было работать с wide char функциями ), все символы переводятся в нижний регистр, содержимое перекодируется назад UTF-8 ( без этого выводятся вопросики ) и выводится на экран.
Проблема: Символы не переводятся в нижний регистр.
#include <stdio.h>
#include <locale.h>
#include <wchar.h>
#include <wctype.h>
#include <errno.h>
#include <iconv.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
static int
convert( const char *from, const char *to,
char * const input, size_t isize,
char **output )
{
#define OUTBUF_SIZE 1024
int err = -1;
iconv_t idesc = iconv_open( to, from );
if ( idesc == ( iconv_t ) -1 )
{
return -1;
}
char *out = NULL;
char *outptr = NULL;
char *in = input;
size_t buflen = 0;
size_t outmaxlen = 0;
while ( isize > 0 ) {
int n;
/* Increase the buffer. */
char *new_outp = ( char * ) realloc( out, outmaxlen + OUTBUF_SIZE );
if ( new_outp == NULL )
{
free( out );
goto out1;
}
outptr = ( outptr - out ) + new_outp;
out = new_outp;
outmaxlen += OUTBUF_SIZE;
buflen = OUTBUF_SIZE;
n = iconv( idesc, &in, &isize, &outptr, &buflen );
if ( n == ( size_t ) -1 && errno != E2BIG )
{
free( out );
goto out1;
}
}
err = 0;
*output = out;
out1:
iconv_close( idesc );
out:
return err;
#undef OUTBUF_SIZE
}
static void
wcslwr( wchar_t * const str )
{
size_t i;
const int len = wcslen( str );
for( i = 0; i < len; ++i ) {
str[i] = towlower( str[i] );
}
}
int
main( int argc, char *argv[] )
{
char *input;
char *input_name;
char *tmp;
wchar_t *nstr;
struct stat sb;
int err = EXIT_FAILURE;
if ( argc == 1 )
{
return 0;
}
setlocale( LC_ALL, "" );
//printf( "%s\n", setlocale( LC_ALL, NULL ) );
input_name = argv[1];
int fdi;
fdi = open( input_name, O_RDONLY );
if ( fdi == -1 )
{
perror("open");
exit( EXIT_FAILURE );
}
if ( fstat( fdi, &sb ) == -1 )
{
perror( "fstat" );
goto out1;
}
size_t fisize = sb.st_size;
input = ( char * )
mmap( NULL, fisize, PROT_READ, MAP_PRIVATE, fdi, 0 );
if ( input == NULL )
{
perror( "mmap" );
goto out1;
}
if ( convert( "UTF-8", "UCS-4", input, fisize, &tmp ) ) {
perror( "convert" );
goto out2;
}
nstr = ( wchar_t * ) tmp;
wcslwr( nstr );
convert( "UCS-4", "UTF-8", ( char * ) nstr, wcslen( nstr ) * sizeof( wchar_t ), &tmp );
int val = fwide( stdout, 0 );
if ( val == 0 ) {
if ( fwide( stdout, 1 ) <= 0 ) {
printf( "%s\n", "Could not switch to wide char mode!" );
goto out3;
} else {
wprintf( L"%s\n", ( wchar_t * ) tmp );
}
} else if ( val > 0 ) {
wprintf( L"%s\n", ( wchar_t * ) tmp );
} else {
printf( "%s\n", "Could not switch to wide char mode!" );
goto out3;
}
err = EXIT_SUCCESS;
out3:
free( nstr );
free( tmp );
out2:
munmap( input, fisize );
out1:
close( fdi );
exit( err );
}
Пример работы:
dimorphus@codifier ~/workspace/decode/test $ cat ./test.txt
АБВГДеежз
ABCDefgdimorphus@codifier ~/workspace/decode/test $ ./a.out ./test.txt
АБВГДеежз
ABCDefg
Примечание1:
dimorphus@codifier ~/workspace/decode/test $ locale
LANG=en_US.UTF-8
LC_CTYPE="en_US.UTF-8"
LC_NUMERIC=C
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=
Примечание2:
На мой взгляд в функциях wprintf нужно использовать L"%ls\n", но в таком случае выводятся вопросики.
Вопрос:
Как заставить работать ( переводить в нижний регистр и выводить на экран буквы )?
[Если кто знает] Как подружить gdb и wchar_t (не только английский алфавит) ? [/Если кто знает]