2012-06-26 62 views
2

使用C語言。我有一個寫入標準輸出的函數。將stdout捕獲到一個字符串並將其輸出回標準輸出C

我想捕捉那個輸出,修改一下(替換一些字符串)。然後再輸出到stdout。所以,我想開始:

char huge_string_buf[MASSIVE_SIZE]; 
freopen("NUL", "a", stdout); -OR- freopen("/dev/null", "a", stdout); 
setbuf(stdout, huge_string_buffer); 
/* modify huge_string_buffer */ 

現在的問題是,我怎麼輸出huge_string_buffer回原來的標準輸出?

回答

0

我真的不喜歡有文件描述符的棘手遊戲。你不能修改該函數,以便通過寫入標準輸出來以其他方式返回數據嗎?

如果您無法訪問源代碼,並且您無法這樣做,那麼我會建議將寫入stdout的代碼分解爲一個小型的單獨程序,然後將其作爲另一個進程運行。重定向進程的輸出(可能通過命名管道)很容易,也很乾淨,然後從接收數據的進程輸出到標準輸出時沒有問題。

此外,根據您希望執行的編輯類型,您最好使用像Python這樣的高級語言來編輯數據。

+0

好吧,我已經在python中完成了它,但是我需要將它重新集成到ANSI C中。因此除了調用另一個進程之外沒有其他辦法嗎?我不知道,我是否在某處違反堆棧高度。 – Stasik

+0

限制你使用C的是什麼?更簡潔的方法是通過過濾器來管理程序的輸出,而不是執行所需的更改(假定命令行使用,操作系統支持管道等)。 – Throwback1986

+1

約束是微控制器上現有的構建和發佈系統+運行時 – Stasik

0

Python有很好的方法來完成你想要的東西。但是如果你真的需要使用C語言,那麼我會用C語言讀一些管道。但要小心,它們可以非常快地變得非常複雜。

1

執行此操作的Unix方法實際上只是編寫一個可執行所需輸入處理的小程序,然後在命令行上將該其他程序的輸出傳送給它。

如果你堅持把它全部放在你的C程序中,我會改寫這個函數,讓它把它的輸出發送到一個給定的字符緩衝區(最好是return緩衝區的char *),以便它可以被髮送到標準輸出或按客戶要求進行處理。

例如,舊的方式:

void usage() { 
    printf ("usage: frob sourcefile [-options]\n"); 
} 

...和新的方式:

char * usage(char * buffer) { 
    strcpy (buffer, "usage: frob sourcefile [-options]\n"); 
    return buffer; 
} 
+1

我沒有這個功能的來源,它被稱爲.so – Stasik

+0

@Stasik你有解決方案嗎?我有同樣的問題,我運行ipmitool來獲取一些信息,並且想要修改內容然後輸出到標準輸出。我有ipmitool的代碼,但我不想更改代碼太多。 –

+1

我結束了將它包裝在腳本中,並在那裏做文本處理 – Stasik

0
char huge_string_buf[MASSIVE_SIZE]; 
FILE stdout_ori=fdopen(stdout,"a"); 
freopen("NUL", "a", stdout); -OR- freopen("/dev/null", "a", stdout); 
setbuf(stdout, huge_string_buffer); 
/* modify huge_string_buffer */ 
//Write to stdout_fdopen 
+1

fdopen stdout不起作用:( – Stasik

2

一個想法是模仿標準的Unix工具tee的功能,而是完全在您的程序中完成,而不依賴外部重定向。

所以我寫了一個簡單的函數,mytee(),這似乎工作。它採用shmget(), pipe(), fork(), and dup2()

#include <stdlib.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <sys/shm.h> 

static char *mytee(int size) { 
    int shmid = shmget(IPC_PRIVATE, size + 1, 0660 | IPC_CREAT); 
    int pipe_fds[2]; 
    pipe(pipe_fds); 

    switch (fork()) { 
     case -1:      // = error 
     perror("fork"); 
     exit(EXIT_FAILURE); 
     case 0: {      // = child 
     char *out = shmat(shmid, 0, 0), c; 
     int i = 0; 
     out[0] = 0; 
     dup2(pipe_fds[0], 0);  // redirect pipe to child's stdin 
     setvbuf(stdout, 0, _IONBF, 0); 
     while (read(0, &c, 1) == 1 && i < size) { 
      printf("<%c>", c);  // pass parent's stdout to real stdout, 
      out[i++] = c;   // and then buffer in mycapture buffer 
      out[i] = 0;    // (the extra <> are just for clarity) 
     } 
     _exit(EXIT_SUCCESS); 
     } 
     default:      // = parent 
     dup2(pipe_fds[1], 1);  // replace stdout with output to child 
     setvbuf(stdout, 0, _IONBF, 0); 
     return shmat(shmid, 0, 0); // return the child's capture buffer 
    } 
} 

我的測試程序是:

int main(void) { 
    char *mycapture = mytee(100); // capture first 100 bytes 
    printf("Hello World");   // sample test string 
    sleep(1); 
    fprintf(stderr, "\nCaptured: <%s>\n", mycapture); 
    return 0; 
} 

輸出是:

<H><e><l><l><o>< ><W><o><r><l><d> 
Captured: <Hello World> 

要在應用程序中使用此,在mytee()你會需要用替換測試語句。您可能需要處理read的呼叫中的信號。而每兩個dup2()的之後,你可能需要添加:

close(pipe_fds[0]); 
    close(pipe_fds[1]); 

有關這種東西的參考,例如見的優秀和短27歲的220頁奧賴利book在Dave Curry的Unix系統上使用C.

相關問題