Babel 1.6 HowTo:分子構造記述ファイルコンバータの移植

とりあえずconsoleで動かそう

 linuxではそのままコンパイル、リンクできるので、Macではconsoleエミュレーションでまず動かしてみて、それからMacらしい動作をするように書き直そうと思った。本音をいうと、とりあえず動く状態にして動作確認をしてみないと不安だったのだ。開発環境には、CodeWarrior Pro 3を用いた。なお、この文書の記述は、CodeWarriorを使って簡単なプログラムを書いたことがある人にわかる程度の記述になっている。全然わからない場合はCodeWarriorのチュートリアルをやってから読むように。そもそもプログラムを触る気がないなら、読んでも無駄です。

 CodeWarrior Pro 3で、Console PPCでC言語の環境の新規プロジェクトを作った。このとき、「フォルダを作る」をチェックしておいて、babel-1.6フォルダの下に、babel_consoleという名前でプロジェクトを作った。プロジェクトと実行ファイルの名前が同じだと、リンク後書き込むときにエラーになるから、PPCターゲットのファイル名をbabel_console.appにした(ターゲット設定パネルを出して行うこと)。

 プロジェクトのソースのところに、babelのソースのうちfilesrch.c以外のすべての.cファイルを追加した。この追加で自動的にヘッダなどのサーチパスも登録された。filesrch.cを除いたのは、このファイル中にmain()があり、convert.c中にある本来のbabelのmain()とぶつかるからである。元のMakefileではこれもコンパイルしてはいるのだが。この状態でコンパイルすると次のエラーが出た。

エラー: ファイル 'sys/time.h' が開けません。>
rdpdb.c 行: 26  #include    

エラー: ファイル 'sys/times.h' が開けません。
rdpdb.c 行: 27  #include    

エラー: ファイル 'sys/resource.h' が開けません。
rdpdb.c 行: 28  #include    

エラー: この関数のプロトタイプ宣言がありません。
rdpdb.c 行: 443  tmpstr1 = strdup ( Type(the_atom) );

エラー: 'int' を 'char *' へ変換できません。
rdpdb.c 行: 444  tmpstr2 = strdup ( Type(the_atom) );
 見た所、times.hやresource.hで定義されている関数は条件コンパイルで落ちて使われていないようであったので、該当個所を

/* #include    <sys/time.h>
#include    <sys/times.h>
#include    <sys/resource.h> */

のように修正した。また、strdupはFindLibraryで探しても見つからず、標準Cライブラリにもないので、同等品を作って、mac_specificというファイルに入れることにした。
mac_specific.h

/* mac_specific.h */
#ifndef MAC_SPECIFIC_H_INCLUDEC
#define MAC_SPECIFIC_H_INCLUDEC

#ifdef MAC_SPECIFIC_SRC
#define SCOPE
#else
#define SCOPE extern
#endif

SCOPE char *strdup(const char *str);


#endif /* MAC_SPECIFIC_H_INCLUDEC */

mac_specific.c

/* mac_specific.c */
#define MAC_SPECIFIC_SRC

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

#include "mac_specific.h"

char *strdup(const char *str)
{
	char *tmpstr;
	
	tmpstr = (char *)malloc(sizeof(char)*(strlen(str) + 1));
	
	if(tmpstr == NULL) return tmpstr;
	
	strcpy(tmpstr, str);

	return tmpstr;

}

これらのファイルを追加し、さらにrdpdb.cに

#include "mac_specific.h"

を追加し、コンパイルすると今度はエラー無しに(警告は出る。未使用変数の警告はOFF、ANSIに厳密に従う、のチェックははずしておいた)終了した。走らせると、
The environment variable BABEL_DIR is not defined
Please define this variable to so babel can find element.lis
と表示された。
 UNIXでは、getenvを使って環境変数の値を得ることができるが、Macのgetenvは引数が何であってもNULLを返すという仕様になっている。そこで、getenvを検索し、各ファイルのgetenvの周辺を書き換えることにした。ファイルの読み書きや、何かの定義ファイルの読み込みのパスをとっている所でgetenvが使われており、デフォルトを探して失敗した場合に環境変数を見てさらに探し、それでもだめならメッセージを出して処理をやめる、というパターンである。UNIXの形式でフルパスを作るとデリミタが'/'なので、Macではそのまま使えないからどのみち書きなおす必要がある。そこで、当面の対処として、定義ファイルはすべてデフォルトのパス(つまりアプリケーションと同じフォルダの中)に入れることにして、それで見つからなければ即エラーで処理を止めるという形で書き換えることにした。この処理はMacの時だけなので、__POWERPC__の定義による条件コンパイルをするような形で書き直した。書き直した後のリストの一部を示すと次のようになる。
convert.c

#if __POWERPC__
	sprintf(bbldef,".bbldef");
#else
    if (getenv("HOME"))
      sprintf(bbldef,"%s/.bbldef",getenv("HOME"));
    else
      fatal_error("Please define HOME environment variable");
#endif

fileutil.c

if (fp){
    return(fp);
  }
  else{
  
#ifdef __POWERPC__
	printf("cannot open %s at open_w_env in fileutil.c \n");
#else  
     if (getenv(env_var))
     {
        strcpy(new_name,getenv(env_var));
        strcat(new_name,"/");
        strcat(new_name,f_name);
        if ((fp = fopen(new_name,"r")) != NULL)
           return(fp);
     }
#endif
  }

rdelmnts.c

#ifdef __POWERPC__
	printf("Could not open element file element.lis \n Please put into the application folder\n");
	return(0);
#else /* __POWERPC__ */

#ifndef AICHEM 
    if (getenv("BABEL_DIR") == NULL)
    {
      printf("The environment variable BABEL_DIR is not defined\n");
      printf("Please define this variable to so babel can find element.lis\n");
      exit(0);
    }
    else{ 
      strcpy(babel_dir,getenv("BABEL_DIR"));
    }
    strcat(babel_dir,"/element.lis");
    if ((file1 = fopen(babel_dir,"r")) == NULL) 
#else
      if ((file1 = fopen("/usr/local/babel/element.lis","r")) == NULL) 
#endif
      {
	printf("Could not open element file %s \n",babel_dir);
	return(0);
      }
#endif /* __POWERPC__ */

rquanta.c

#ifdef __POWERPC__
      sprintf(wstr,"Could not open Quanta types files file %s \n",babel_dir);
      show_warning(wstr);
      return(FALSE);
#else /* __POWERPC__ */  
    if (getenv("BABEL_DIR") == NULL)
    {
      show_warning("The environment variable BABEL_DIR is not defined");
      show_warning("Please define this variable to so Babel can find quanta.lis\n");
      return(FALSE);
    }
    else 
      strcpy(babel_dir,getenv("BABEL_DIR"));
    strcat(babel_dir,"/quanta.lis");  
    if ((file1 = fopen(babel_dir,"r")) == NULL) 
    {
      sprintf(wstr,"Could not open Quanta types files file %s \n",babel_dir);
      show_warning(wstr);
      return(FALSE);
    }
#endif /*__POWERPC__ */

rdtypes.c

#ifdef __POWERPC__
    sprintf(wstr,"Could not open types files file types.lis \n");
    fatal_error(wstr);
  
#else /* __POWERPC__ */  
#ifndef AICHEM 
    if (getenv("BABEL_DIR") == NULL)
    {
      show_warning("The environment variable BABEL_DIR is not defined");
      show_warning("Please define this variable to so babel can find element.lis\n");
      exit(0);
    }
    else 
      strcpy(babel_dir,getenv("BABEL_DIR"));
    strcat(babel_dir,"/types.lis");  
    if ((file1 = fopen(babel_dir,"r")) == NULL) 
    {
      sprintf(wstr,"Could not open types files file %s \n",babel_dir);
      fatal_error(wstr);
    }
#else
    file1 = open_read("/usr/local/babel/types.lis");
#endif 
#endif /* __POWERPC__ */

wrgau.c

#ifdef __POWERPC__
    fprintf(file1,"%cmem=3700000 words\n",'\045');
    fprintf(file1,"#%s\n\n",OutputKeywords);
    fprintf(file1,"This Gaussian input file generated by Babel %s\n\n",BABEL_VERSION);
    fprintf(file1,"Ch Mu\n");

#else /* __POWERPC__ */
    if (getenv("BABEL_DIR"))
    {
      strcpy(babel_dir,getenv("BABEL_DIR"));
      strcat(babel_dir,"/gauss.hdr");

      if ((file2 = fopen(babel_dir,"r")) != NULL)
      {
		  while (fgets(buffer,sizeof(buffer),file2))
	  		fprintf(file1,"%s",buffer);
		  if (file2)
	  	  	fclose(file2);
      }
    }
    else
    {
      fprintf(file1,"%cmem=3700000 words\n",'\045');
      fprintf(file1,"#%s\n\n",OutputKeywords);
      fprintf(file1,"This Gaussian input file generated by Babel %s\n\n",BABEL_VERSION);
      fprintf(file1,"Ch Mu\n");
    }
#endif /* __POWERPC__ */

wrpsgv.c

#ifdef __POWERPC__
    fprintf(file1,"inv0230\n");
    fprintf(file1,"JOB: JOBNAME\n");
    fprintf(file1,"DIR: EXEDIR TEMPDIR\n");

#else /* __POWERPC__ */
    if (getenv("BABEL_DIR"))
    {
      strcpy(babel_dir,getenv("BABEL_DIR"));
      strcat(babel_dir,"/psgvb.hdr");

      if ((file2 = fopen(babel_dir,"r")) != NULL)
      {
        while (fgets(buffer,sizeof(buffer),file2))
          fprintf(file1,"%s",buffer);

        if (file2)
          fclose(file2);
      }
    }
    else
    {
      fprintf(file1,"inv0230\n");
      fprintf(file1,"JOB: JOBNAME\n");
      fprintf(file1,"DIR: EXEDIR TEMPDIR\n");
    }
#endif /* __POWERPC__ */

ここまで書き直して再度コンパイルする。できたアプリケーションと同じフォルダに
element.lis
new.lis
quanta.lis
types.lis
gauss.hdr
psgvb.hdr
を入れて実行すると、
No input flag specified
というメッセージが出る。linuxでは引数無しで実行すると使用可能なオプションを表示して終了する。これはlinuxの場合は引数を何も与えなくてもargv[0]にはプログラムの名前そのものが必ず入り、常にargc=1となり、プログラム中argc=1かどうかでオプションの表示をするかどうかを決めてるためである。Macで実行時に引数をとれるようにするには、convert.c で、

/* #undef MAC */
#define MAC 

とする。これでコンパイルし実行すると、引数を入力するためのウィンドウが開き、何も入力せずにOKボタンをクリックするとオプション一覧がコンソールウィンドウに表示されるようになった。また、コマンドラインオプションでファイル名と形式を指定してやることで、macmolecule形式のファイルをpdbに変換することができた。パス指定が面倒なので、できたアプリケーションと同じフォルダの中にlactose.mcmというファイルを入れておいて、コマンドラインウィンドウが出たら、

-macmol lactose.mcm -opdb lactose.pdb

と入れて、できたファイルがRasMolで見れることを確認した。
 なお、Readme.1st中の書き出しオプションは違っていて、pdbにするには-opではだめで-opdbと指定する必要がある。

 動きそうなところまでは持ってきたが、パス指定ができなかったりいちいち引数を入力する必要があったりで、使い勝手は悪い。とりあえず今の環境でファイル変換可能になったのでちょっとほっとしているが、たくさんのファイル変換には、とても使う気分になれない。さてどうしようか。
top pageへ戻る 
目次に戻る

Y.Amo /
当サーバ上のページに関する問い合わせや苦情のメールは公開することがあります。