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

構造体と記号定数の定義

構造体のリンクには一方向(片方向)と双方向がありました。このプログラムでは、コマンドラインに入力された順に先頭からファイルを処理するだけなので、一方向のリンクで対処できます。

構造体の定義

構造体のメンバに『次の構造体』を示すポインタ(自分自身の型のポインタ)を組み込み、リンクの最後にはそこへNULLを代入する――という形です。図1のようなイメージになります。

構造体"_CONV"には、これまでのメンバに加えて『次の構造体』を示すポインタを設定します。その場合、これまでのように宣言時に構造体タグを省略する方法は使えません(リスト1)。メンバを定義する{}の中では、まだ自分自身を示す名前が定義されていないためです。

構造体をポインタでリンクする場合には、structに続けて構造体タグを定義し、そのタグを使って自分自身へのポインタをメンバに設定します(リスト2)。


リスト1:構造体タグを定義しないと自分と同じ型へのポインタをメンバに設定できない
typedef struct {
  int    tab;                 /* タブストップ幅 */
  char   fname[256 + 1];      /* 入力ファイル名 */
  FILE   *fp;                 /* ファイルポインタ */
} _CONV;

リスト2:タグを定義して自分自身へのポインタをメンバに設定する
typedef struct __conv {
  int    tab;                 /* タブストップ幅 */
  char   fname[256 + 1];      /* 入力ファイル名 */
  FILE   *fp;                 /* ファイルポインタ */
  struct __conv  *next;       /* 次の構造体へのポインタ */
           ↑タグを使ってポインタを設定する
} _CONV;

記号定数の定義

以降、main関数をまず紹介し、そこから呼び出される関数を紹介していきます。

その前に記号定数を定義しておきましょう。リスト2のようになります。

入力ファイル名のサイズは256バイトとし、"NAMESIZE"という記号定数を充てておきます。入力ファイルにはソースファイルを前提としているので、実際にはこれほど長い名前を使うことはないでしょう。

この256バイトという設定はパス名も含めたサイズとなりますが、プログラミングではソースファイルは1つのフォルダに固めることが一般的で、せいぜいヘッダファイルをincludeやheaderといったフォルダに分類する程度です。そのため、あまり長くしても意味がありません。

先に定義した構造体_CONVは、この記号定数NAMESIZEを使って、リスト4のように書き換えることができます。

リスト3:記号定数の定義
#define     ARGMIN          2        /* オプションの最小数
                                        これ未満はエラーとする */

#define     BUFSIZE         1024     /* 文字列処理バッファのサイズ */
#define     NAMESIZE        256      /* ファイル名のサイズ */

#define     DEFAULT_TAB     8        /* 標準のタブストップ */
#define     MIN_TAB         2        /* 最小のタブストップ */
#define     MAX_TAB         16       /* 最大のタブストップ */

#define     SPACE           0x20     /* スペースコード */
#define     TAB             0x09     /* タブコード */
#define     _FF             0x0c     /* 改ページコード */

#define     BOOL            int
#define     TRUE            1        /* 論理値--真 */
#define     FALSE           0        /* 論理値--偽 */

#define     ERR            (-1)     /* シェルに返すエラーコード */

リスト4:記号定数を使って書き直した構造体の定義
typedef struct __conv {
  int    tab;                 /* タブストップ幅 */
  char   fname[NAMESIZE + 1]; /* 入力ファイル名 */
  FILE   *fp;                 /* ファイルポインタ */
  struct __conv  *next;       /* 次の構造体へのポインタ */
} _CONV;