IDEその後2018年03月26日 15:58

Open WATCOM C/C++のIDEを使って、前回説明したルールに沿って PC-DOS SHELLの製作を続けています。

幾つかサンプルを示します。

今回、製作するプロジェクト名は、"SHELL"とします。作業デイレクトリーは"C:\SHELL"です。 また、プロジェクトのターゲットは、3つです。完成品"SH.EXE"、デバッグ用ターゲット"DEBMAIN.EXE"。 いずれも、DOS 16ビットの実行モジュールです。 この外に、テキストでは、ライブラリー"SHELLIB.LIB"を作りますので、 これもターゲットとします。

さて、さきに決めたコーデイングルールに従い、プリグラムを書いていきます。幾つかサンプルを示します。

関数の頭書きの例です。オリジナルはこのようになっています。

   /* cpy.c */
   char *cpy(dest,src)
   register char *dest,*src;
   {
         :
       (中略)
         :
       return dest;
   }
これ下記のようにすると同時にヘッダーファイルを追加します。
   /* cpy.c */
   char *cpy(char *dest,char *src) {
         :
       (中略)
         :
       return dest;
   }

ヘッダーファイルは以下のとおりです。これを必要に応じてインクルードします。

   /* cpy.h */
   extern char *cpy(char*,char*);

型を省略された引数は、きちんと宣言します。例えば、

   /* next.c */
   char *next(**linep,delim,esc) {
   char **linep;
   {
         :
       (中略)
         :
      return start;
   }

これは、このようにします。もちろん、ヘッダーファイルも同様です。

   /* next.c */
   char *next(char **linep,char delim,char esc) {
   {
         :
       (中略)
         :
      return start;
   }
   /* next.h */
   extern char *next(char **,char,char);

標準関数の定義は、本書では以下のようにしていますが、 ヘッダーファイルをインクルードするようにします。下記の例には、strlen()の宣言に誤植があります。 引数が一つなのにカンマが付いています。おそらく、版下を作成するのに、ソースファイルを 手書きで入力したのでしょう。現代ならば、インクルードして組み込むでしょうね。

   /* strsave.c */
   extern int  strcpy (char*,   char*);
   extern char *malloc(unsigned      );
   extern int  strlen (char*,        );
   
   char *strsave(str)
   char *str;
   {
         :
       (中略)
         :
      return NULL;
   }

これは、下記のように記述しました。

   /* strsave.c */
   #include 
   #include 
   
   char *strsave(char *str) {
         :
       (中略)
         :
      return NULL;
   }

static宣言された関数は、そのままでは、別のコンパイル単位からは見えなくなります。 これでは、デバッグをしずらいので、コンパイル時に文字列"DEBUG"が定義されている時は、 static宣言をはずすようにします。例えば下記の場合は、

   /* reargv.c */
         :
       (中略)
         :
   extern unsigned char _osmajor;
   static int Envlen;
            :
          (中略)
            :
   /* --------------------------------------------------------------------- */
   static char *nextarg(pp)
   char **pp;
   {
            :
          (中略)
            :
      return start;
   }
   /* --------------------------------------------------------------------- */
   int reargv(argcp,argvp)
   char *(**argvp);
   int  *(  argcp);
   {
            :
          (中略)
            :
      return 1;
   }
   /* --------------------------------------------------------------------- */
   int envlen(void) {
            :
          (中略)
            :
      return Envlen;
   }
このようにします。
   /* reargv.c */
         :
       (中略)
         :
   extern unsigned char _osmajor;
   static int Envlen;
            :
          (中略)
            :
   /* --------------------------------------------------------------------- */
   #ifndef DEBUG
   static
   #endif
   char *nextarg(char **pp) {
            :
          (中略)
            :
      return start;
   }
   /* --------------------------------------------------------------------- */
   int reargv(int *argcp,char *(**argvp)) {
            :
          (中略)
            :
      return 1;
   }
   /* --------------------------------------------------------------------- */
   int envlen(void) {
            :
          (中略)
            :
      return Envlen;
   }

リスト中、MS-C依存の変数"_osmajor"があります。幸いなことに、Open WATCOM C/C++でも、 サポートされています。

"DEBUG"の宣言は、IDEの"C Compiler Switches"の "Macro Definitions: [-d]"欄に"DEBUG"と書きコンパイルします。デバッグが終わったら、 "DEBUG"を取り去り、再コンパイルしときます。

MS-Cに依存している個所は、もう一つありました。アセンブラーで一部書かれています。 その中で、MS-C独自の内部関数"__chkstk"関数を呼び出しています。これは、 実行時にスタックオーバーフローの検出をするルーチンです。Open WATCOM C/C++にはありません。 "__STK"が、同等の機能を果たすものと思われますが、仕様が公開されていません。今回は、 "__chkstk"を無視する事とします。

このテキスト中、"isdir.c"は、コードの最後の数行が欠落しています。編集ミスだと思います。 しかし、コードのコメントを読めば欠落している部分を補うことができます。 この外にも、バグを見つけました。それは、次回に報告します。