Вызовите popen () для команды с китайскими иероглифами на Mac - PullRequest
1 голос
/ 02 февраля 2012

Я пытаюсь запустить программу для файла с помощью команды popen () на Mac. Для этого я создаю команду вида <path-to_executable> <path-to-file> и затем вызываю popen () для этой команды. Прямо сейчас оба эти компонента объявлены в символе *. Мне нужно прочитать вывод команды, поэтому мне нужен канал, заданный popen ().

Теперь выясняется, что путь к файлу может содержать китайский, японский, русский и почти любые другие символы. Для этого я могу представить путь к файлу как wchar_t *. Но это не работает с popen (), потому что, по-видимому, Mac / Linux не имеет такого широкого _wpopen (), как Windows.

Есть ли другой способ сделать эту работу? Я получаю путь к файлу из структуры данных, которая может дать мне только wchar_t *, поэтому мне нужно взять его оттуда и соответствующим образом преобразовать, если это необходимо.

Заранее спасибо.

Edit:

Похоже, это был один из тех дней, когда ты просто вырывал свои волосы.

Поэтому я попытался использовать wcstombs, но вызов setlocale не удался для «C.UTF-8» и любой его перестановки. Неудивительно, что вызов wcstombs не смог вернуть -1 после этого.

Затем я попытался написать собственную реализацию iconv, основанную на некоторых примерах кода, найденных в Google. Я придумал это, которое упрямо отказывается работать:

iconv_t cd = iconv_open("UTF-8", "WCHAR_T");
// error checking here

wchar_t* inbuf = ...; // get wchar_t* here
char outbuf[<size-of-inbuf>*4+1];

size_t inlen  = <size-of-inbuf>;
size_t outlen = <size-of-inbuf>*4+1;

char* c_inbuf  = (char*) inbuf;
char* c_outbuf = outbuf;

int ret = iconv(cd, &c_inbuf, &inlen, &c_outbuf, &outlen);
// more error checking here

iconv всегда возвращает -1, а для errno установлено значение EINVAL. Я убедился, что <size-of-len> установлен правильно. Я понятия не имею, почему этот код сейчас не работает.

Редактировать 2:

iconv не удался, потому что я не правильно установил длину входного буфера. Кроме того, Mac, похоже, не поддерживает кодировку "WCHAR_T", поэтому я изменил ее на UTF-16. Теперь я исправил длину и изменил кодировку from, но iconv просто возвращает без преобразования какого-либо символа. Он просто возвращает 0.

Чтобы отладить эту проблему, я даже изменил строку ввода на временную строку и соответственно установил длину ввода. Даже этот вызов iconv просто возвращает 0. Мой код теперь выглядит так:

iconv_t cd = iconv_open("UTF-8", "UTF-16");
// error checking here

wchar_t* inbuf = ...; // get wchar_t* here - guaranteed to be UTF-16
char outbuf[<size-of-inbuf>*4+1];

size_t inlen  = <size-of-inbuf>;
size_t outlen = <size-of-inbuf>*4+1;

char* c_inbuf  = "abc"; // (char*) inbuf;
inlen = 4;
char* c_outbuf = outbuf;

int ret = iconv(cd, &c_inbuf, &inlen, &c_outbuf, &outlen);
// more error checking here

Я подтвердил, что дескриптор конвертера открывается правильно. Кодировка from верна. Входной буфер содержит несколько простых символов. Все жестко закодировано, и все же iconv не конвертирует никакие символы и просто возвращает 0, а outbuf остается пустым.

Предупреждение о потере рассудка!

Ответы [ 2 ]

1 голос
/ 02 февраля 2012

Вам понадобится строка UTF-8 для popen.Для этого вы можете использовать iconv для преобразования различных кодировок, в том числе из локальной кодировки wchar_t в UTF-8.(Обратите внимание, что в моей установке Mac OS wchar_t на самом деле составляет 32 бита, а не 16.)

EDIT Вот пример, который работает на OS X Lion.У меня не было проблем с использованием кодировки wchar_t (и это задокументировано на справочной странице iconv).

#include <sys/param.h>
#include <string.h>
#include <iconv.h>
#include <stdio.h>
#include <errno.h>

char* utf8path(const wchar_t* wchar, size_t utf32_bytes)
{
    char result_buffer[MAXPATHLEN];

    iconv_t converter = iconv_open("UTF-8", "wchar_t");

    char* result = result_buffer;
    char* input = (char*)wchar;
    size_t output_available_size = sizeof result_buffer;
    size_t input_available_size = utf32_bytes;
    size_t result_code = iconv(converter, &input, &input_available_size, &result, &output_available_size);
    if (result_code == -1)
    {
        perror("iconv");
        return NULL;
    }
    iconv_close(converter);

    return strdup(result_buffer);
}

int main()
{
    wchar_t hello_world[] = L"/éè/path/to/hello/world.txt";

    char* utf8 = utf8path(hello_world, sizeof hello_world);
    printf("%s\n", utf8);
    free(utf8);
    return 0;
}

Функция utf8_hello_world принимает строку wchar_t со своим длина байта и возвращает эквивалентную строку UTF-8.Если вы имеете дело с указателями на wchar_t вместо массива wchar_t, вам нужно будет использовать (wcslen(ptr) + 1) * sizeof(wchar_t) вместо sizeof.

0 голосов
/ 02 февраля 2012

Mac OS X использует UTF-8, поэтому вам необходимо преобразовать строки широких символов в UTF-8.Вы можете сделать это, используя wcstombs, при условии, что вы сначала переключитесь в локаль UTF-8.Например:

// Do this once at program startup
setlocale(LC_ALL, "en_US.UTF-8");
...
// Error checking omitted for expository purposes
wchar_t *wideFilename = ...;  // This comes from wherever
char filename[256];  // Make sure this buffer is big enough!
wcstombs(filename, wideFilename, sizeof(filename));
// Construct popen command using the UTF-8 filename

Вы также можете использовать libiconv , чтобы выполнить преобразование UTF-16 в UTF-8, если вы не хотите изменять языковой стандарт вашей программы;Вы также можете свернуть свою собственную реализацию, поскольку преобразование не так уж сложно.

...