今度は, 目次の一覧。
前回分の, サンプルのメインループの中に, 次の部分を追加しておこう。
ファイル一覧を取り込んで, ループしてる中の, タイトルなんかを表示している後とかだねっ。
って, 分かりにくいかな (^^;
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^)/~
オンライン文書とも呼ばれる, この 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^)/~