FORTRAN(cutコマンドを作るその6)

旧2-5. Fortran毎日学習

-bオプションに対応したcutコマンドを作成しました。

takk@deb9:~$ cat -n cut6.f
     1        PROGRAM MAIN
     2          CHARACTER*100 LINE
     3          INTEGER DISP_LOC(100),N
     4          CHARACTER*100 ARGS
     5
     6          N = IARGC()
     7          DO 300 I=1,N
     8            CALL GETARG(I,ARGS)
     9
    10            IF(ARGS(1:2).EQ.'-b') THEN
    11              CALL B_OPT(ARGS(3:),DISP_LOC)
    12            ELSE
    13              OPEN(UNIT=10,FILE=ARGS(1:INDEX(ARGS,' ')-1),
    14       1      STATUS='OLD',
    15       2      ACCESS='SEQUENTIAL')
    16     10       READ(10,*,END=100) LINE
    17              CALL CUT(LINE,DISP_LOC)
    18              GOTO 10
    19    100       CLOSE(10,STATUS='KEEP')
    20            END IF
    21    300 CONTINUE
    22            STOP
    23        END
    24
    25        SUBROUTINE B_OPT(B_OPT_STRING,DISP_LOC)
    26          CHARACTER*100 B_OPT_STRING
    27          CHARACTER*100 SSTRING1(10),SSTRING2(10)
    28          INTEGER I,SSIZE1,SSIZE2,K,L,M
    29          INTEGER DISP_LOC(100)
    30
    31          DO 10000 I=1,100
    32            DISP_LOC(I) = 0
    33  10000   CONTINUE
    34
    35          CALL SPLIT(B_OPT_STRING,',', SSTRING1,SSIZE1)
    36          DO 10200 I=1,SSIZE1
    37            CALL SPLIT(SSTRING1(I),'-', SSTRING2,SSIZE2)
    38            IF(SSIZE2.EQ.1) THEN
    39              READ(SSTRING1(I),*) L
    40              DISP_LOC(L) = 1
    41            ELSE
    42              READ(SSTRING2(1),*) L
    43              READ(SSTRING2(2),*) M
    44              DO 10100 K=L,M
    45                DISP_LOC(K) = 1
    46  10100       CONTINUE
    47            END IF
    48  10200   CONTINUE
    49        END
    50
    51        SUBROUTINE SPLIT(SRC,SEP,DEST,SPLIT_SIZE)
    52          CHARACTER*100 SRC
    53          CHARACTER*1 SEP
    54          CHARACTER*100 DEST(10)
    55          INTEGER IND,S1,S2,RSLT,SPLIT_SIZE
    56          IND = 0
    57          S2=-1
    58          I = 1
    59  20100   RSLT = INDEX(SRC(IND+1:),SEP)
    60          IF(RSLT.NE.0) THEN
    61            S1 = IND+1
    62            IND = IND + RSLT
    63            S2 = IND-1
    64            DEST(I) = SRC(S1:S2)
    65            I = I + 1
    66            GOTO 20100
    67          END IF
    68          DEST(I) = SRC(S2+2:)
    69          SPLIT_SIZE = I
    70          RETURN
    71        END
    72
    73        SUBROUTINE CUT(LINE,DISP_LOC)
    74          INTEGER DISP_LOC(100)
    75          CHARACTER*100 LINE
    76          DO 30100 I=1,100
    77            IF(DISP_LOC(I).EQ.1) THEN
    78              WRITE(*,31000) LINE(I:I)
    79            END IF
    80            IF(LINE(I:I).EQ.' ') THEN
    81              WRITE(*,*) ''
    82              GOTO 30200
    83            END IF
    84  30100   CONTINUE
    85  30200   RETURN
    86  31000   FORMAT(A$)
    87        END
takk@deb9:~$

73行目のCUT関数が、列抽出する関数です。100列分配列を確認して、1がはいっていたら、部分文字列の抽出をします。空白が出現したら、文字列の終端とみなして、改行するためにWRITE(*,*) ”を実行しています。

動くでしょうか。GDBを使ってみます。

takk@deb9:~$ gfortran -g -fdollar-ok cut6.f
takk@deb9:~$ gdb a.out

パラメータを設定し、パラメータ数の取得関数前まで実行します。

(gdb) set args -b2-3,5 x00
(gdb) l
1             PROGRAM MAIN
2               CHARACTER*100 LINE
3               INTEGER DISP_LOC(100),N
4               CHARACTER*100 ARGS
5
6               N = IARGC()
7               DO 300 I=1,N
8                 CALL GETARG(I,ARGS)
9
10                IF(ARGS(1:2).EQ.'-b') THEN
(gdb) b 6
Breakpoint 1 at 0x147b: file cut6.f, line 6.
(gdb) run
Starting program: /home/takk/a.out -b2-3,5 x00

Breakpoint 1, MAIN__ () at cut6.f:6
6               N = IARGC()
(gdb)

パラメータ数は2ですので、合ってます。

(gdb) n
7               DO 300 I=1,N
(gdb) p N
$1 = 2
(gdb)

1を設定する配列の位置も、-bで指定した通りとなっています。

(gdb) n
8                 CALL GETARG(I,ARGS)
(gdb)
10                IF(ARGS(1:2).EQ.'-b') THEN
(gdb)
11                  CALL B_OPT(ARGS(3:),DISP_LOC)
(gdb)
7               DO 300 I=1,N
(gdb) p DISP_LOC
$2 = (0, 1, 1, 0, 1, 0, 0, ~
(gdb)

ファイルから読み込んだ文字列もOKです。

(gdb) n
8                 CALL GETARG(I,ARGS)
(gdb)
10                IF(ARGS(1:2).EQ.'-b') THEN
(gdb)
15           2      ACCESS='SEQUENTIAL')
(gdb)
16         10       READ(10,*,END=100) LINE
(gdb)
17                  CALL CUT(LINE,DISP_LOC)
(gdb) p line
$3 = '10010', ' ' <repeats 95 times>
(gdb)
(gdb) n
000
18                  GOTO 10
(gdb)
16         10       READ(10,*,END=100) LINE
(gdb)
17                  CALL CUT(LINE,DISP_LOC)
(gdb) s
cut (line=..., disp_loc=..., _line=100) at cut6.f:76
76              DO 30100 I=1,100
(gdb) n
77                IF(DISP_LOC(I).EQ.1) THEN
(gdb)
80                IF(LINE(I:I).EQ.' ') THEN
(gdb)
76              DO 30100 I=1,100
(gdb)
77                IF(DISP_LOC(I).EQ.1) THEN
(gdb)
78                  WRITE(*,31000) LINE(I:I)
(gdb)
080               IF(LINE(I:I).EQ.' ') THEN
(gdb)

実行結果を見てしまった方が早そうです。

takk@deb9:~$ ./a.out -b1,2,3,4 x00
1001
1011
1021
1031
1041
1051
1061
1071
1081
1091
takk@deb9:~$ ./a.out -b1-4 x00
1001
1011
1021
1031
1041
1051
1061
1071
1081
1091
takk@deb9:~$ ./a.out -b2-3,5 x00
000
010
020
030
040
050
060
070
080
090
takk@deb9:~$

上手く行きました。

コメント

タイトルとURLをコピーしました