C言語でパイプの読み書きを行う


この記事の所要時間: 733
C言語は久しぶりに触りました。
LinuxでC言語を使うのなんて懐かしいですね。
パイプの入出力でハマったのでメモ。

nkfコマンドでMIMEエンコードされた文字列をUTF-8文字列にデコードしたいと思います。
system関数を使えば任意のコマンドが実行できることは周知の事実かと思います。
まずはバージョン情報を表示させるところからやってみたいと思います。

system("nkf --version > /var/tmp/blah 2>&1");

Network Kanji Filter Version 2.0.8 (2007-07-20)
Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa),2000 S. Kono, COW
Copyright (C) 2002-2007 Kono, Furukawa, Naruse, mastodon

大丈夫です。
次のジョブをsystem関数で実行したいと思います。

echo '=?ISO-2022-JP?B?GyRCJDMkbCRPRnxLXDhsJE4kRiQ5JEgkSiRzJEAkKyRpGyhC?==?ISO-2022-JP?B?GyRCJE0kQxsoQg==?=' | nkf -mw

これは日本語のてすとなんだからねっ

一時ファイルを作成するやり方はスマートではないのでpopen関数を使ってやりました。
popenのrだけでnkf --versionを表示するのはできたので、
rwでもいけると思って以下の様なコードを書きました。

#include <stdio.h>
#include <iconv.h>
#include <string.h>

int main (void)
{
  char *str = "=?ISO-2022-JP?B?GyRCJDMkbCRPRnxLXDhsJE4kRiQ5JEgkSiRzJEAkKyRpGyhC?==?ISO-2022-JP?B?GyRCJE0kQxsoQg==?=";
  char buf[10240];
  FILE *fp;
  printf ("デコードスタート\n");
  fp = popen("nkf -mw", "rw");
  fputs (str, fp);
  if (fgets(buf, 10240, fp) != NULL)
  {
    printf ("%s\n", buf);
  }
  fclose(fp);
  return 0;
}

コンパイルして実行。

gcc decode.c 
./a.out 

デコードスタート
セグメンテーション違反です (コアダンプ)

セグメンテーションフォルトが発生してしまいました。
パイプに入力してnkfの出力結果を取得できることを期待したのですが、
2つ以上のパイプを開こうとするとこのままではどうもだめなようです。
以下のようにpipeシステムコールで2つのパイプを定義しないといけなかったのでした。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define R (0)
#define W (1)

/**
 * 入力と出力のパイプを開いてコマンドを実行する。
 */
int popen2 (char *command, int *fd_r, int *fd_w)
{
    int pipe_c2p[2], pipe_p2c[2];
    int pid;

    /* Create two of pipes. */
    if (pipe (pipe_c2p) < 0) {
        perror("popen2");
        return (-1);
    }
    if (pipe (pipe_p2c) < 0) {
        perror ("popen2");
        close (pipe_c2p[R]);
        close (pipe_c2p[W]);
        return (-1);
    }

    /* Invoke processs */
    if ((pid = fork()) < 0) {
        perror ("popen2");
        close(pipe_c2p[R]);
        close(pipe_c2p[W]);
        close(pipe_p2c[R]);
        close(pipe_p2c[W]);
        return (-1);
    }
    if (pid == 0) {   /* I'm child */
        close (pipe_p2c[W]);
        close (pipe_c2p[R]);
        dup2 (pipe_p2c[R],0);
        dup2 (pipe_c2p[W],1);
        close (pipe_p2c[R]);
        close (pipe_c2p[W]);
        if (execlp("sh", "sh", "-c", command, NULL) < 0) {
            perror ("popen2");
            close (pipe_p2c[R]);
            close (pipe_c2p[W]);
            exit (1);
        }
    }

    close (pipe_p2c[R]);
    close (pipe_c2p[W]);
    *fd_w = pipe_p2c[W];
    *fd_r = pipe_c2p[R];

    return (pid);
}

/*
 * メインルーチン。
 */
int main (void)
{
  char *str = "=?ISO-2022-JP?B?GyRCJDMkbCRPRnxLXDhsJE4kRiQ5JEgkSiRzJEAkKyRpGyhC?==?ISO-2022-JP?B?GyRCJE0kQxsoQg==?=";
  int fd_r, fd_w;
  char buffer[10240];
  size_t ret;

  printf ("Now starting...\n");

  // コマンドとパイプの準備
  // ここではnkfコマンドでMIMEエンコードされた文字列を
  // UTF-8文字列にデコードして出力する
  popen2 ("nkf -mw", &fd_r, &fd_w);

  // パイプに入力する
  ret = write (fd_w, str, strlen(str));
  if (ret != -1)
  {
    printf ("Write successfull.\n");
    close (fd_w);

    // パイプから読み出し
    ret = read (fd_r, buffer, 10240);
    close (fd_r);
    if (ret != -1)
    {
      printf ("Read successfull.\n");
      // 読み出し結果の出力
      printf ("%s\n", buffer);
    }
    else
    {
      perror ("Read error");
    }
  }
  else
  {
    perror ("Write error");
  }
  printf ("Exitting...\n");

  return 0;
}

これで動きました。

gcc decode2.c 
./a.out 
Now starting...
Write successfull.
Read successfull.
これは日本語のてすとなんだからねっ
Exitting...

参考サイト

投稿者紹介

株式会社ユニキャスト
私たちは、テクノロジに魅せられた個性あふれるメンバーによって構成された茨城県日立市に本社を構えるベンチャー企業です。
”テクノロジを通して「驚き」と「感動」を創造し、人々の「夢」と「笑顔」を支えます。” の経営理念をモットーに明るい未来を描き、ワクワクする企画提案を続けて参ります。

人気の記事

コメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

PAGE TOP