* ぐいぐい01に関するメモ-27 -(by [[K]], 2009.01.13) -メモのうち重要な部分をそのうちまとめてまともなページを作る *** (39) GOで「ぐいぐい01」アプリを作る(5) -[[GUIGUI01/memo26]]の続きです。 ---- -今回の最初のプログラムは、いわゆるファイルダンプです。ファイルをオープンして、それを16進数でだだーっと書きます。ex0021.cです。 #include <guigui01.h> unsigned char cmdusage[] = { 0x86, 0x50, 0x01, 'i', 'n', 0x0c, 9, 0x01, 'p', 'u', 't', '-', 'f', 'i', 'l', 'e', 0x40 }; void sethex(char *s, int i, int n) { int j; for (j = n - 1; j >= 0; j--) { s[j] = '0' + (i & 0xf); i >>= 4; if (s[j] > '9') { s[j] += 'A' - '0' - 10; } } return; } void G01Main() { unsigned char buf[16], s[8]; int i, j, k; g01_setcmdlin(cmdusage); g01_getcmdlin_fopen_s_0_4(0); /* 0はreadモード, 4はslot番号, 0は引数番号 */ g01_putstr0(" offset +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F 0123456789ABCDEF\n"); g01_putstr0("---------------------------------------------------------------------------\n"); for (i = 0;; i += 0x10) { j = jg01_fread1(4, 16, buf); if (j == 0) { break; } sethex(s, i, 8); g01_putstr1(8, s); /* g01_putstr1()は文字数を指定できる。だからs[8]=0;がいらない。 */ g01_putstr0(" "); for (k = 0; k < 16; k++) { if (k < j) { sethex(s, buf[k], 2); g01_putstr1(2, s); g01_putc(' '); } else { g01_putstr0(" "); } } g01_putc(' '); for (k = 0; k < 16; k++) { if (k < j) { if (0x20 <= buf[k] && buf[k] <= 0x7e) { g01_putc(buf[k]); } else { g01_putc('.'); } } } g01_putc('\n'); } } -これをmakeすると390バイトになります。そして実行するとこんな感じです。 >efg01 ex0021.g01 usage>ex0021.g01 [in:]input-file >efg01 ex0021.g01 make.bat offset +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F 0123456789ABCDEF --------------------------------------------------------------------------- 00000000 2E 2E 5C 7A 5F 74 6F 6F 6C 73 5C 6D 61 6B 65 2E ..\z_tools\make. 00000010 65 78 65 20 25 31 20 25 32 20 25 33 20 25 34 20 exe %1 %2 %3 %4 00000020 25 35 20 25 36 20 25 37 20 25 38 20 25 39 %5 %6 %7 %8 %9 -他にも「>efg01 ex0021.g01 ex0021.g01」とか「>efg01 -noadc ex0021.g01 ex0021.g01」とかやると結構おもしろいです。390バイトの割になかなか遊べます。 -さて遊んでばかりではいけないので説明をします。最初はcmdusage[ ]ですが、 0x0c がファイルパス型です。ついでなのでまとめておきましょう。 |0x0c|ファイルパス型引数| |0x1c|整数型引数| |0x2c|フラグ型引数| |0x3c|文字列型引数| -関数sethex()はsetdecを16進数用に改造しただけのものです。 -それでG01Main()の g01_getcmdlin_fopen_s_0_4(0); で、引数番号0に書かれたファイルをリードモードでオープンさせ、スロット番号4に割り当てています。これは本来は、 g01_getcmdlin_fopen_s(0, 4, 0); と書くべきところなのです。しかしこの関数をguigui01.hに書いておくのをすっかり忘れていました。それで、 g01_getcmdlin_fopen_s_0_4() というのは、スロット番号4にリードモードでオープンするのがあまりよくあるケースなので、関数の引数で指定しなくてもいいことにしたいわば省略形です。 -スロット番号というのはファイルハンドルの入れ物みたいなもので、ファイルのオープンに使う場合は4番から31番のどれかを使います。しかしまあ、たいていリードは4番で、ライトは5番でやります。どうしてかというと、 g01_getcmdlin_fopen_s_0_4() などの関数を使いたいからですね(サイズが節約できます)。 - j = jg01_fread1(4, 16, buf); というのは、スロット番号4のファイルから最大16バイトまで読み込んでbufにしまいます。そして読み込めたバイト数がjに入ります。これが0ならファイル終端です。 -freadのうしろの1が気になるかもしれませんが、「ぐいぐい01」のAPIでは、文字列などを指定するときに、末尾を0にして終端を表現する方法と、文字数を指定して終端を表現する方法の両方をサポートしている場合が多いです。で、ゼロ終端型の場合関数名には0が入ります。そして文字数型の場合は1が入ります。ex0023.cではfread0の例を示そうと思います。 ---- -ex0021は分かりやすさ重視で簡略表現を避けていましたが、今度はプログラムを短くするためのテクニックを全部使うことにしましょう(本当は?演算子を使うことでもっと短くできるんだけど、それはAPIじゃなくてC言語文法の話が必要になるので今回はパス)。 -まずはやっぱりcmdusage[ ]です。実はusage内の説明部分で「file」という単語はとてもよく出てくるので、これを1バイトで表現するテクニックがあります( 0x02 )。それを使うとこうなります。 unsigned char cmdusage[] = { 0x86, 0x50, 0x01, 'i', 'n', 0x0c, 6, 0x01, 'p', 'u', 't', '-', 0x02, 0x40 }; -しかししかし。そもそも「in:input-file」という表現そのものが、本当によく出てくるのです。ということで、これ全体を0x88の1バイトだけで表していいことになっています。さらにもしこれを「[in:input-file]」にしたければ、0x89にすることになっています。ということで、今回はこんなに短くなります。 unsigned char cmdusage[] = { 0x86, 0x50, 0x88, 0x40 }; -次はsethex()です。なにやらとりあえず'0'を足して、'9'より大きくなってしまったら'A'以降になるようになにやら補正していますが、実は「ぐいぐい01」ではこんなことをする必要がありません。文字コード0x10~0x1fがまさに「16進数表示用の文字」ということになっているので、以下のようなプログラムで全く同じ結果が得られます。 void sethex(char *s, int i, int n) { int j; for (j = n - 1; j >= 0; j--) { s[j] = 0x10 + (i & 0xf); i >>= 4; } return; } -ただしこれは注意してほしいのですが、この文字コードが使えるのはg01_putc()やg01_putstr系で表示する場合だけです。ファイルに書き込む場合にはそれが文字コードなのかそれともバイナリファイルの一部なのか分からないので、0x10~0x1fを'0'~'F'と見なしていいのかどうかシステムが分からないのです(というか見なしてはいけないモードになっている)。ということで、モードを変更しない限り、ファイルに出力する場合はex0021のsethex()を使う必要があります。 -最後はこれです。 j = jg01_fread1(4, 16, buf); これは j = jg01_fread1_4(16, buf); とできるので(そのほうが小さい)、これを使うことにします。 -あとはこれです。 g01_putstr0(" offset +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F 0123456789ABCDEF\n"); g01_putstr0("---------------------------------------------------------------------------\n"); -これを以下のように改造しました。 g01_putstr0(" offset "); for (k = 0x10; k < 16 + 0x10; k++) { g01_putstr0(" +"); g01_putc(k); } g01_putstr0(" "); for (k = 0x10; k < 16 + 0x10; k++) { g01_putc(k); } g01_putstr0("\n---------------------------------------------------------------------------\n"); -ということで、この変更を全部適用して(ex0022.c)makeすると351バイトになります。39バイト(10%)も減りました。ばんざい。 -おっと忘れていました。もし存在しないファイル名などを指定したらどうなるのでしょうか?・・・こうなります。 >efg01 ex0022.g01 hoge.txt File read open error: hoge.txt -これは現在ファイルオープンエラーを継続不能なエラーとしてシステム側で処理するモードになっているせいです。これを解除すればスロット番号4にオープン失敗のハンドルが格納されて処理を続行することもできます。でもたいていはデフォルトのままのほうが自分で面倒なエラー処理をしなくていいので、楽です。 ---- -(書き途中) * こめんと欄 - ex0022が351バイトになって我ながら感動したので、後日ASKAかnaskで全部書いてみようと思いました。半分くらいにならないかなあ? -- [[K]] &new{2009-01-13 (火) 23:51:38}; - とりあえず200バイトを切ることは確認。 -- ''K'' &new{2009-01-14 (水) 00:53:13}; - できた。182バイト。半分には行かなかったけど、とりあえず満足。 -- ''K'' &new{2009-01-14 (水) 11:31:04}; - そしてabcdw013で168バイト達成。 -- ''K'' &new{2009-01-14 (水) 19:04:03}; #comment
(This host) = http://osask.net