2012-02-02 129 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