ふつうのLinuxプログラミングに入門した。第5章 練習問題

ツールの実装を読んでいると、Linuxシステムコールやシグナルの知識が足りなくて、ときどき理解できません。

例)「シグナルを出すときはkill関数を使う」らしいけど、ツールの中ではsignal関数使ってるよ…どういうことなの… ←いまここ

というわけで、『ふつうのLinuxプログラミング入門』(通称・ふつりな)をやることにしました。

問題

サンプルコードとしてcatの簡易版がある。

これは、コマンドライン引数でファイル名を与えると、ファイルの内容を標準出力に書き込むプログラムである。

ファイル名が渡されない場合に、標準入力を読むように改造せよ。

自分の解答

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

static void do_cat(const char *path);
static void die(const char *s);

char *program;

int main(int argc, char *argv[])
{
	int i;
	program = argv[0];

	if(argc < 2){
		program = argv[0];
		do_cat(argv[0]);	
	} else {
		for(i = 1; i < argc; i++){
			do_cat(argv[i]);
		}
	}
	exit(0);
}

#define BUFFER_SIZE 2048

static void do_cat(const char *path)
{
	int fd;
	unsigned char buf[BUFFER_SIZE];
	int n;
	int isfile = 0;

        if(strcmp(path, program) == 0){     
                fd = STDIN_FILENO;
        } else {
		isfile = 1;
		fd = open(path, O_RDONLY);
		if(fd < 0){
			die(path);
		}
	}

	for(;;){
		n = read(fd, buf, sizeof buf);
		if(n < 0){
			die(path);
		}
		if(n == 0){
			break;
		}
		if(write(STDOUT_FILENO, buf, n) < 0){
			die(path);
		}
	}

	if(isfile){
		if(close(fd) < 0){
			die(path);
		}
	}
}

static void die(const char *s)
{
	perror(s);
	exit(1);
}

思ったこと

  • 引数がない状態を判定する方法がひどい
    • どうしたらいいんだッ
    • ”NO-FILE”とか渡した方が、関数の外に変数を定義するよりは、マシかも
  • そもそも、コマンドライン引数の有無によってストリームの先を分けるとき、これくらいの役割・量の関数であれば、次のどちらがよいのか?
    • mainで切り替えて別の関数に振り分ける
    • どちらにも対応できる関数を作る
  • 標準入力から読む場合に、Ctrl+cを押さない限り終了しない。改行を認識させて終了処理をした方がよい。

正解は・・・

サンプルコードのcat3.cを参照してください。

とのことだけど、見つけてないので、またあとで。ページ数書いてくれればいいのに><著者のWebサイトからサンプルコードをダウンロードできました。