GDBを使ってみます。a.outパラメータを設定し、パラメータ数の取得関数前まで実行します。IARGC()(gdb)パラメータ数は2ですので、合ってます。2(gdb)1を設定する配列の位置も、-bで指定した通りとなっています。~(gdb)ファイルから読み込んだ文字列もOKです。THEN(gdb)実行結果を見てしまった方が早そうです。x00000010020030040050060070080090takk@deb9:~$上手く行きました。7リファクタリングします。FORTRANの部分文字列抽出が活かせてなかったので、DISP_LOC配列の使い方を変えます。二次元配列にして、2値で範囲を設定するようにします。範囲がない値の場合は、2値は同じ値になります。このような関数になりました。DISP_LOCはOPT_INFOという名前に変更して、SSTRING1やSSTRING2も、COMMA_STRとHYPHEN_STRに変更しました。ENDこれに伴って他関数もリファクタリングした全ソースがこれです。77takk@deb9:~$FORTRANは、まだスラスラ書けるというわけではないですが、ようやくプログラミングらしくなってきた気がします。INDEXを連続で取得するFORTRANのcutコマンド続きです。-bオプションのバイト数を2桁以上に対応するには、-(ハイフン)の位置を特定しなければなりません。INDEX関数を使って特定します。INDEX関数の使い方は、引数に元の文字列と、検索文字列を指定すればよいです。2takk@deb9:~$このようにINDEX関数を二つ並べても結果は同じになります。次のカンマの位置はどう取得すればよいのでしょう。INDEXに開始位置はないものだろうか。ENDtakk@deb9:~$苦肉の策で部分文字列を抽出したものを検索元に置き換えてINDEXの引数に渡すことにしました。5takk@deb9:~$カンマの位置は元文字列の’1,23,4~’と一致しました。結果は合ってそうです。これをDOループで回してカンマの位置を全部取得するように修正します。その前に検索しても見つからない場合は何が返るのでしょうか。検索文字列を変更して確認します。0takk@deb9:~$結果は0になりました。0ならループを終了するように作れば良いですね。ENDtakk@deb9:~$発見されたかのチェックのため一旦結果をRSLTに格納して、後からINDに足すようにしました。splitを作る(その1)splitといってもsplitコマンドではなく、文字列を区切り文字で分割するsplit関数のようなことができる関数をFORTRAN77でも作りたいと思います。前回作ったプログラムをベースに、カンマ毎に文字列を抽出するプログラムを作ってみました。ENDtakk@deb9:~$ではこれを関数化します。splitされた文字列を配列に格納したいので、SUBROUTINEを使います。ENDtakk@deb9:~$カンマ限定のsplit関数になってしまいました。デバッグするデバッグ前回のプログラムはバグってますので、デバッグしたいと思います。gfortranというコンパイラを使ってますが、gがつくぐらいですからGDBも使えるでしょう。試しに-gをつけてビルドしてみます。split2.ftakk@deb9:~$すんなり通りました。a.out...done.(gdb)動きましたね。mainとかしてmain関数にブレイク設定してからrunすれば良いですが、FORTRANはどこで止めればよいのでしょう。lコマンドでソースを見てみます。SSIZE1(gdb)なるほど。行番号が表示されてますね。この番号を指定すれば、ブレイクポイントを設定できます。6.(gdb)いけましたね。STRING='1-3,5,7-12,13,14'(gdb)ブレイクポイントで停止しました。STRING変数を確認します。設定前ですので、ゼロでしょうか。times>(gdb)ゼロではなく初期化されていないので元のメモリの値が表示されました。ステップ実行してみます。STRING(gdb)再度STRING変数を確認します。times>(gdb)初期化されて想定通りの文字列が格納されました。この調子でデバッグしていけば、バグの原因も分かりそうです。1ではFORTRANの自作split関数をGDBデバッグしていきます。splitする文字列はこれです。STRING='1-3,5,7-12,13,14'まず、カンマでsplitして、次にハイフンでsplitします。結果は、このようになりました。4takk@deb9:~$カンマは4箇所ありますのでsplitすると、split後の文字列の個数SSIZE1が5となります。その後、1-3に含まれるハイフンでsplitすると、SSIZE2は2となるはずなのですが、なぜか5と表示されています。これをデバッグします。-gオプションをつけてビルド後、GDBを起動します。a.out~(gdb)listコマンドでソースの1行目~20行目を確認します。SSTRING2,SSIZE2)(gdb)SPLIT関数へ渡す引数を確認します。SSTRING1配列は初回はI=1ですので、SSTRING(1)について値を確認します。'(gdb)カンマで分割された文字列が格納されるので1-3となっています。1-3の後に配列サイズ分空白が入ってるのが以前から気になっていましたが、置いておきます。次にsplit関数内を見ていくので、ステップインします。0(gdb)先ほど見たばかりですが、引数についてもう一度確認してみます。'\340\344\377\377'(gdb)おかしいです。1-3だけのはずが、元の文字列すべて表示されてしまいます。して後に続く文字列は全部表示されているのでしょうか。この場所でブレイクポイントを設定します。34.(gdb)ブレイクポイントまで実行。SSTRING2,SSIZE2)(gdb)同じようにsstring1(2)を確認。'(gdb)想定通りです。SPLIT関数内部に移動して再度引数を確認します。'\340\344\377\377\003\000\000\000\005\000\000\000\002\000'(gdb)予想通り、次は1-3の文字列は表示されず、5と、それ以降の文字列が表示されました。‘を引数で渡しているのに関数内部の方宣言の文字列サイズが大きいことが原因っぽいですが、実験プログラムを作って確認します。ENDtakk@deb9:~$このようなプログラムになりました。TEST関数に渡す文字列サイズは10Byteで、TEST関数の引数はサイズを100Byteにしています。(1)takk@deb9:~$実引数と仮引数のサイズが違うというwarningが出ました。サイズを合わせれば、warningは出なくなるのでしょうか。AA再度ビルドします。test.ftakk@deb9:~$warningは取れました。して、SPLIT関数のプログラムもサイズが違うから動作がおかしいのかもしれません。文字列のサイズを、10/100混在していたのを100で統一したプログラムです。ENDtakk@deb9:~$ビルドして実行します。1takk@deb9:~$ぴったり数字が合いました。これを使えばcutの-bオプションが作れそうです。3SPLIT関数が直ったかどうか、コマンドにして確認してみます。-bの後に文字列を指定すればよいです。テスト用のスクリプトを組みます。テスト内容は適当です。-b1-3,4-5echotakk@deb9:~$スクリプト実行の結果に文字列のサイズ分空白で出てしまって見にくいので、空白はすべてtrでカットして実行しました。'1SSIZE1=1STRING:1SSIZE2=15SSIZE1=1STRING:5SSIZE2=11,2SSIZE1=2STRING:1SSIZE2=1STRING:2SSIZE2=11,3,5SSIZE1=3STRING:1SSIZE2=1STRING:3SSIZE2=1STRING:5SSIZE2=12,4,5SSIZE1=3STRING:2SSIZE2=1STRING:4SSIZE2=1STRING:5SSIZE2=11-2SSIZE1=1STRING:1-2SSIZE2=22-5SSIZE1=1STRING:2-5SSIZE2=21-2,3SSIZE1=2STRING:1-2SSIZE2=2STRING:3SSIZE2=11,2-4,5SSIZE1=3STRING:1SSIZE2=1STRING:2-4SSIZE2=2STRING:5SSIZE2=11-3,4-5SSIZE1=2STRING:1-3SSIZE2=2STRING:4-5SSIZE2=2takk@deb9:~$いわゆるprintfデバッグというものでしょう。結果も見にくいですが、一応合ってそうです。4GDBのスクリプトでテストします。対象プログラムからテスト用コードを取っ払います。ENDtakk@deb9:~$次に-gオプションをつけてビルド。split4.ftakk@deb9:~$次はGDBのスクリプトを作成します。GDBで使うコマンドを列挙したテキストファイルを作ればよいです。SSIZE1takk@deb9:~$GDBのスクリプト名はtest1としました。実行は、-xオプションをつけてファイル名を指定します。test1実行すると、結果が表示されます。quit---Enterキー待ちになるので、確認したら、Enterを押します。9(gdb)結果の続きが表示されます。gdbを見てみるとこのような一文がありました。