Cでcatもどきを書く

ふつうのLinuxプログラミングに載っていた練習問題を書いてみた。
お題は、

ファイルを読み込み、\t を"\t"に、改行 を "$"+改行 に置き換えた文字列を出力するコマンド

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

int main (int argc, const char *argv[]) {
  FILE *f;
  int c;

  if (argc < 2) {
    printf("Usage: cat [file]...\n");
    return 1;
  }

  int i;
  for ( i = 1; i < argc; i++) {
    f = fopen(argv[i], "r");
    while ((c = getc(f)) != EOF) {
      if (c == '\n') {
        if (putchar('$') < 0 || putchar('\n') < 0) return -1;
      } else if (c == '\t'){
        if (putchar('\\') < 0 || putchar('t') < 0) return -1;
      } else
        if (putchar(c) < 0) return -1;
    }
    fclose(f);
  }
  return 0;
}

getc とか putchar など入出力APIがいっぱいあって、どれがどれやら。

  • getc, putc, getchar, putchar はバイト単位での入出力。
  • gets, puts は行単位での入出力。

switch の場合

switch でも良かったようですが、case ごとに break が必要なようだったので elseif にしました。
switch だとこんな感じ。

...
    f = fopen(argv[i], "r");
    while ((c = getc(f)) != EOF) {
      switch(c) {
      case '\n':
        if (putchar('$') < 0 || putchar('\n') < 0) return -1;
        break;
      case '\t':
        if (putchar('\\') < 0 || putchar('t') < 0) return -1;
        break;
      default:
        if (putchar(c) < 0) return -1;
      }
    }
    fclose(f);
...

Rubyでも書いてみる

ついでに、同じコードを ruby でも書いてみた。

if $*.size < 1
  puts "Usage: cat [file]..."
  exit 0
end

$*.each do |file|
  File::open(file, "r") do |f|
    f.each {|line|
      puts line.gsub(/\t/, "\\t").gsub(/\n/, "$")
    }
  end
end