catコマンドを作る

P86
掲載されているソースを見ないで書いてみる。

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

#define BUF_SIZE 1024

void
do_cat( const char *pszFileName ) {
    int fd = open( pszFileName, O_RDONLY );
    if (fd > 0) {
        char buf[BUF_SIZE];
        int buf_read = 0;
        while ( (buf_read = read(fd, buf, BUF_SIZE-1)) > 0 ) {
            // segmentation fault
            //buf[buf_read] = '?0';
            //printf(buf);
            write( STDOUT_FILENO, buf, buf_read );
        }

    }
    else {
        printf("Couldn't open '%s'?n", pszFileName);
    }
    close (fd);
}

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

    if ( argc < 2 ) {
        return 0;
    }

    for ( i = 1; i < argc; i++ ) {
        do_cat(argv[i]);
    }

    return 0;
}

readしたbufferをprintfで書いたらセグメンテーション違反って言われたので素直にwriteを使ったらうまくいった。
教科書のソースと比べて気づいた点。

  • プロトタイプ宣言がある
  • dieを作ってる
  • readするループが無限ループ
  • しかも無限ループがfor文(while(1)の方が好きだ)
  • システムコールの戻り値をちゃんとチェックして適切な対応(die or break)をしている
  • do_catの戻り値の型がstatic void
  • sizeof buf(sizeof(buf)じゃなくていいんだね)
  • ポインタ変数でも変数名がpで始まらない

システムコールでエラーが発生した場合、エラーNo.がerrnoというグローバル変数にセットされる。perror(const char *s)でそれに対応するメッセージを標準エラー出力に出力、strerror(int errnu)で対応するメッセージを取得。Perlの$!と同じようなもの。

    • -

#defineの行末にセミコロンを置いていてコンパイルが通らなくて困ったのは内緒だ。