第43回
仕様設計からコーディングまで~タブ/スペース変換プログラムを作る(3)

main関数の定義(リスト5)

まず、プログラムの中軸となるmain関数の定義を紹介します。次いで、main関数から呼び出される下請け関数を紹介します。

ローカル変数の宣言

main関数では、まず入力ファイルから読み込んだ1行と変換後の1行を保存する文字列を用意します。どちらもchar型の配列です。
char rbuf[BUFSIZE + 1];
char wbuf[BUFSIZE + 1];

さらに、構造体のリンクをたどるためにその先頭を保持するポインタと、各構造体を示すポインタを用意します。
_CONV  *start, *p;

パラメータのチェック

続いて、コマンドライン・パラメータの数をチェックし、足りない場合はエラーメッセージを表示して終了します。
if (argc < ARGMIN) {
  fprintf(stderr,
    "タブストップ幅と入力ファイルを指定してください。¥n");
  return (ERR);
}

構造体のリンクを生成

コマンドライン・パラメータの数が妥当であれば、それに基づいてmakelink関数で_CONV型構造体のリンクを生成します。コマンドラインを示すmain関数の引数argvは、最初はプログラム名(自分自身の名前)を示しているので、ポインタを1つ進めます。
argv++;

何らかの理由でリンクが生成できなかった場合には、エラーメッセージを出力して終了します。
if ((start = makelink(argv)) == NULL) {
  fprintf(stderr,"出力するファイルがありませんでした.¥n");
  return (ERR);
}

ループによる繰り返し処理

構造体のリンクが生成できたら、それをたどって処理を続けます。まず、生成されたリンクの先頭を示すポインタをpに代入します。
else {
  p = start;

続けてwhileループで、p(構造体を示すポインタ)がリンクの終端を示すNULLになるまで、「構造体の示すファイルを変換し、終了したらpが次の構造体を示す……」という処理を繰り返します。
  while (p != NULL) {
    if (setdata(p) != FALSE ) {
      fprintf(stdout, "====> %s¥n¥n", p->fname);
          ↑ファイル名を出力する

setdata関数は、各構造体に記録されたタブストップ幅の妥当性を調べて調整し、ファイル名で示されたファイルをオープンします。

タブ→スペース変換の繰り返し

さらにwhileループを使い、tb2sp関数でファイルから1行読み込んではそれを変換して出力する処理を繰り返します。この部分はこれまでに紹介してきたものと同じです。
    while (fgets(rbuf, BUFSIZE, p->fp) != NULL) {
      tb2sp(rbuf, wbuf, p->tab);
      fputs(wbuf, stdout);
    }

構造体で示された入力ファイルを1件処理したら、区切りとして"---- end of file ----"の1行を出力し、プリンタ向けに改ページコードを出力します。
    fprintf(stdout, "---- end of file ----¥n");
    putchar(_FF);
  }

次の構造体を処理

構造体を1件処理したら、ポインタpに次の構造体へのポインタ"p->next"を代入して処理を繰り返します。
  p = p->next;

これでpがNULLであればリンクの終端に達したことになるので、一番外側のwhileループが終了します。

最後に、構造体のリンクをたどってメモリを解放します。
  }  ← 一番外側のwhileループの終端
  cleanmem(start);
}    ← elseで実行する処理の終端
return (0);
}

リスト5:main関数
int  main(int argc, char *argv[])
{
  char rbuf[BUFSIZE + 1];
  char wbuf[BUFSIZE + 1];
  _CONV  *start, *p;

  /* オプションの数をチェック */
  if (argc < ARGMIN) {
    fprintf(stderr,
      "タブストップ幅と入力ファイルを指定してください。¥n");
    return (ERR);
  }

  /* 構造体のリンクが生成できなかった場合 */
  argv++;    /* オプションの配列を1つ進める */
  if ((start = makelink(argv)) == NULL) {
    fprintf(stderr,"出力するファイルがありませんでした.¥n");
    return (ERR);
  }
  /* 構造体のリンクが生成できたら処理を続ける */
  else {
    /* リンクをたどりNULLになるまで繰り返す */
    p = start;
    while (p != NULL) {
      if (setdata(p) != FALSE ) {
        /* ファイル名を出力 */
        fprintf(stdout, "====> %s¥n¥n", p->fname);
        /* 1行ずつ変換して出力 */
        while (fgets(rbuf, BUFSIZE, p->fp) != NULL) {
          tb2sp(rbuf, wbuf, p->tab);
          fputs(wbuf, stdout);
        }
        /* ファイルを区切る */
        fprintf(stdout, "---- end of file ----¥n");
        putchar(_FF);   /* プリンタ出力のためにページ送りする */
      }
      p = p->next;
    }
    /* 構造体のメモリを解放 */
    cleanmem(start);
  }
  return (0);
}