一歩進んだ Rexx

Classic REXX (REstructured eXtended eXecutor)
File #07

目次の一覧 -- '99.6.8

今度は, 目次の一覧。
前回分の, サンプルのメインループの中に, 次の部分を追加しておこう。 ファイル一覧を取り込んで, ループしてる中の, タイトルなんかを表示している後とかだねっ。 って, 分かりにくいかな (^^;

  pg.0 = RxInfContents(file.i, inf.i._CONTENTS, 'pg.')
  do p = 1 to pg.0
     if pg.p > '' then say right(p, 5) '('pg.p')'pg.p._attr
  end

(↑)何をやっているのかっつーと, ヘッダーの情報を与えて, ページごとの情報を取得するのさっ。

そして, (↓)これがその処理。

RxInfContents: parse arg ,, RxInfContents; return RxInfContentsCore(arg(1), arg(2));
RxInfContentsCore: procedure expose (RxInfContents)
parse arg fname, cnt +2 ps +4 ln +4 p +4
cnt = li2d(cnt); ps = li2d(ps); ln = li2d(ln); p = li2d(p);
htbl = CharIn(fname, p +1, cnt *4)
htxt = CharIn(fname, ps +1, ln)
do i = 0 for cnt
   p = li2d(substr(htbl, i *4 +1, 4)) -ps
   ln = c2d(substr(htxt, p +1, 1))
   parse var htxt +(p) hstr +(ln) -(ln)+1 lv +1 cn +1
   lv = c2d(lv); cn = c2d(cn);

   txt = ''
   pt = 4
   if DigiBit(lv, 5) then do
      parse var hstr +3 flags +2 ?1
      flags = reverse(x2b(c2x(reverse(flags))))
      pt = pt +2
      if substr(flags,  1, 1) then txt = txt 'xy('Val5('pt')')'
      if substr(flags,  2, 1) then txt = txt 'wh('Val5('pt')')'
      if substr(flags,  3, 1) then txt = txt 'viewport'
      if substr(flags,  4, 1) then txt = txt 'attr('d2x(Val2('pt'))')'
      if substr(flags,  5, 1) then txt = txt 'nosearch'
      if substr(flags,  6, 1) then txt = txt 'noprint'
      if substr(flags,  8, 1) then txt = txt 'tutorial'
      if substr(flags,  9, 1) then txt = txt 'clear'
      if substr(flags, 11, 1) then txt = txt 'group('Val2('pt')')'
      if substr(flags,  7, 1) then txt = txt 'ctrlarea('Val2('pt')')'
      if substr(flags, 12, 1) then txt = txt 'autosplit'
      /* :link reftype=hd res=002 auto split. */

      if substr(flags, 10, 1) then txt = txt '?9?'
      if substr(flags, 13, 1) then txt = txt '?12?'
      if substr(flags, 14, 1) then txt = txt '?13?'
      if substr(flags, 15, 1) then txt = txt '?14?'
      if substr(flags, 16, 1) then txt = txt '?15?'
   end
   RxInf = RxInfContents''i +1
   call value RxInf, substr(hstr, pt +cn*2)
   call value RxInf'._PPTR', substr(hstr, pt, cn*2)
   call value RxInf'._ATTR', txt

   txt = c2d(bitand(d2c(lv), '1f'x))' '
   if DigiBit(lv, 7) then txt = txt'[+]'
   if DigiBit(lv, 5) then txt = txt'[D]'   /* 分割 */
   if DigiBit(lv, 6) then txt = txt'[S]'   /* secondary? */
   call value RxInf'._LEVEL', strip(txt)
end
return cnt

Val2: parse arg n; return li2d(substr(hstr, value(n, value(n) +2), 2));
Val5: parse arg n; n = value(n, value(n) +5);
return c2x(substr(hstr, n, 1))'=',
      li2d(substr(hstr, n +1, 2))','li2d(substr(hstr, n +3, 2))

DigiBit: return substr(x2b(d2x(arg(1), 8)), 32 -arg(2), 1);
/* ←Martin Lafaix 氏の bit()を参考にした */

ここでは, ページ番号を 1から数えてあるのが注意ってとこかな。
構造さえ分かっていれば, この部分って何となく分かるものだろう。きっとそうだ。うん。

わっはっはー, それでは (^o^)/~


タイトル&ページ数の一覧 -- '99.6.3

オンライン文書とも呼ばれる, この INFファイルについては, ビュワーとか色々出てきそうだけれど, 構造が分かりにくいせいかでてこない。 むふふふふ。そこで σ(^^) が, サンプルとゆー形で色々アレしてみたい。 その構造に関しては, Warpっぽくでも扱ってるんで, ご参考に。

で, いきなりソレ (↓)。

RxInfTitle: parse arg , RxInfTitle; return RxInfTitleCore(arg(1),, arg(3));
RxInfTitleCore: procedure expose (RxInfTitle)
   parse arg fname,, suff
   if RxInfTitle > '' then
      call value RxInfTitle''suff'_CONTENTS', ''
   Rc = Stream(fname, 'c', 'open read')
   Head = CharIn(fname, 1, 155)
   if left(Head, 3) \= 'HSP' then return ''
   parse var Head +3 ?1 +4 =108 InfTitle '0'x
   if \abbrev(?1, '01 9b 00 02'x) & \abbrev(?1, '10 9b 00 02'x) then do
      say c2x(?1)
      return ''
   end

   Contents = substr(Head, 9, 14)
   PageCnt = li2d(left(Contents, 2))

   parse var Head +83 ps +4 ln +4
   lang = CharIn(fname, li2d(ps) +1, li2d(ln))
   do while length(lang) > 0
      ln = li2d(left(lang, 2))
      parse var lang n +(ln) lang =3 id +2
      select
         when id == '0000'x then do
            parse var n +4 m +1 v +1 c +2 cp +2 z
            /*if strip(z,, '0'x) \= '' then say 'lang' c2x(z)*/
            CnCP = right(li2d(c), 3, 0) li2d(cp)
         end
      otherwise
      end
   end

   if RxInfTitle > '' then do
      if suff > '' then RxInfTitle = RxInfTitle''suff
      call value RxInfTitle'_CONTENTS', Contents
      call value RxInfTitle'_TITLE', InfTitle
      call value RxInfTitle'_PAGE', PageCnt
      call value RxInfTitle'_CP', CnCP
   end
return InfTitle

li2d: ii2d: return c2d(reverse(arg(1)), word(arg(2) 4, 1));

もしかすると, C言語オンリーな方も見ているかもしれないので, 先にちょいと注意を・・
C言語では, 基本的に0から数値を数える事になっているけど, Rexxは違う。人間臭く(?)1から数える。 例えば, ファイル入出力, 文字列の一部取りだし, などなど・・。 (↑)でゆーところの, CharIn(), substr なんかがそう。 つまり, Head = CharIn(fname, 1, 155) では, 先頭から 155バイト分って事なんだねっ。

で, それから parseも分かりづらいかも なので, parse var Head +3 ?1 +4 =108 InfTitle '0'x の部分を解説しよー。 これは Headの先頭 3バイトをスキップ, 次の 4バイトを ?1 に代入してる。変な変数名。だから変数とゆーのか。 (←違う)
そして 108バイト目から 0x00で終わる直前までを InfTitleに代入している。オフセットでゆったら 107って事だよ〜。

もう一つ。parse var lang n +(ln) lang =3 id +2 の部分。 ・・これは, 先頭から lnの長さ分を nに代入し, ソレ以降を再度 langに代入。だけれど, それと同時に 3バイト目から 2バイトを idにも代入する。 念のためオフセットでゆーと 2って事だ。 (う〜みゅ。この説明で分かるだろーか)。

この関数では, ファイル先頭部分から少しだけ情報を取り出してる。 これを使ったサンプルを, (↓)に紹介しよう。そうしよう。
そーそー。INFファイルによっては, タイトルなし ってぇのもあるんで注意されたし。

/* Inf file list */
options 'ETmode'
numeric digits 10   /* 4Byteでの位置や長さが存在するため */
True = 1; False = 0;
nl = '0d0a'x

call RxFuncAdd 'SysLoadFuncs', 'rexxutil', 'SysLoadFuncs'
call SysLoadFuncs

Rc = SysFileTree('\os2\book\*.inf', 'file', 'os')
do i = 1 to file.0
   txt = RxInfTitle(file.i, 'inf.', i'.')
   if inf.i._CONTENTS = '' then iterate
   say txt '('FileSpec('N', file.i)') ;'right(inf.i._PAGE, 5),
         'ページ, CP='inf.i._CP
end
exit

コードページをわざわざ取り出しているのは, ソレが 437, 850 の時に, 罫線をどうにかした方がよいことがあるため。 そのままにしてたら, 半角カナとかになってしまう訳なんだな, コレが。

さぁ, 次回は目次だ。うじゃ (^o^)/~


Copyright (C) 1998-2004 Rexx使いの織華
email: ori@drive.co.jp