2012-02-02 133 views
1

我试图在Mac上使用popen()命令在文件上执行程序。为此,我创建了一个形式为<path-to_executable> <path-to-file>的命令,然后在此命令上调用popen()。现在,这两个组件都在char *中声明。我需要读取命令的输出,所以我需要popen()给出的管道。在Mac上使用中文字符命令调用popen()

现在事实证明,路径到文件可以包含中文,日文,俄文和几乎任何其他字符。为此,我可以将path-to-file表示为wchar_t *。但是这对popen()不起作用,因为显然Mac/Linux没有像Windows那样宽的_wpopen()。

有没有其他办法可以使这项工作?我从一个数据结构中获取path-to-file,这个数据结构只能给我wchar_t *,所以如果需要的话,我必须从中取出并适当地转换它。

在此先感谢。

编辑:

好像这些天,当你刚刚结束了拉你的头发之一。

所以我尝试使用wcstombs,但setlocale调用失败的“C.UTF-8”及其任何排列组合。不出所料,wcstombs调用失败后返回-1。

然后我试着根据Google上搜索到的一些示例代码编写我自己的iconv实现。我想出了这个,它顽固地拒绝工作:

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。现在我已经修正了长度并且改变了编码,但是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 

我已经确认转换器描述符正在打开正确。源编码是正确的。输入缓冲区包含几个简单字符。一切都是硬编码的,而且iconv不会转换任何字符,只是返回0,并且outbuf保持空白。

完美损失警报!

+0

Mac OS文件名以UTF-8编码,所以这就是你应该使用的。 – zneak 2012-02-02 18:14:06

回答

1

你需要一个UTF-8字符串popen。为此,您可以使用iconv在不同的编码之间进行转换,包括从本地wchar_t编码到UTF-8。 (请注意,在我的Mac OS安装,wchar_t实际上是32位,而不是16)

编辑下面是在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

我读过关于iconv的声誉是不好实施的。我现在知道这是当之无愧的。 – Sameer 2012-02-03 15:22:03

+0

@Sameer,讨厌实施或讨厌使用?环顾四周,它看起来很简单。我会看看我是否可以使用它并发布一个示例。 – zneak 2012-02-03 19:07:43

+0

非常感谢您的努力。对此,我真的非常感激。 我给你的代码试一试,结果如下。如果我像使用wchar_t一样,甚至使用UTF-32来处理iconv_open中的fromEncoding,那么iconv错误会以“非法字节序列”出错。如果我使用的UTF-16实际上是错误的,iconv会成功运行,但转换为0字节。我检查了我的10.6 Mac,wchar_t是32位,就像你说的。 当我找到某些东西时,我会对此进行探索和更新。再次感谢! – Sameer 2012-02-06 06:44:31

0

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的转换你,如果你不想改变你的程序的区域设置;你也可以推出自己的实现,因为转换并不是那么复杂。

+0

因为我猜测wcstombs会根据需要将多字节字符分成2或3个字节,所以会有(wideFilename的长度)x 3吗? – Sameer 2012-02-02 18:26:59

+0

不,至少需要((wideFilename的长度)* 4 + 1),因为每个宽字符都可能在UTF-8中解码为4个字节,另加1个NUL终止符。 – 2012-02-02 18:33:53

+0

任何想法为什么setlocale(LC_ALL,“C.UTF-8”)调用会失败?这也导致wcstombs调用失败。 – Sameer 2012-02-03 15:21:33