* wiki版のintroシリーズ no.0001 -(by [[K]], 2004.12.13) -これはC言語でもASKAでもnaskでもとにかくごちゃまぜでintroしてしまおうというこころみ。 --これは[[guide/wintro0000]]の続きなので、それを読んでない人はそれを読んでね。 ---最初から読みたい人は[[guide/ASKA]]や[[guide/nask]]からどうぞ。 --C言語をやる人はintroaを読むといいでしょう。ここのプログラムは、introaと同一内容です。 -質問とか感想とかはこめんと欄にレッツゴー。 *** color -C版:"colorc1.c" [osa_dir2では 616バイト] /* "colorc1.c":colorをC言語で記述した例 */ /* stack:20k malloc:2k */ #include <guigui00.h> #define AUTO_MALLOC 0 void setdec2(const int i, char *s); void OsaskMain() { struct LIB_WINDOW *window; struct LIB_TEXTBOX *wintitle, *textbox; int i; static char msg[] = "color 0"; /* ライブラリ初期化 */ lib_init(AUTO_MALLOC); /* ウィンドウのオープン */ window = lib_openwindow(AUTO_MALLOC, 0x0200, 20 * 8, 8 * 16); wintitle = lib_opentextbox(0x1000, AUTO_MALLOC, 0, 7, 1, 0, 0, window, 0x00c0, 0); textbox = lib_opentextbox(0x0001, AUTO_MALLOC, 0, 20, 8, 0, 0, window, 0x00c0, 0); lib_putstring_ASCII(0x0000, 0, 0, wintitle, 0, 0, "colorc1"); /* メインルーチン */ for (i = 0; i < 16; i += 2) { setdec2(i, &msg[6]); lib_putstring_ASCII(0x0000, 0, i / 2, textbox, i, 0, msg); setdec2(i + 1, &msg[6]); lib_putstring_ASCII(0x0000, 10, i / 2, textbox, i + 1, 0, msg); } /* 終了 */ lib_waitsignal(0x0001, 0, 0); } void setdec2(const int i, char *s) /* 注意:このルーチンでは、0~99までしか扱えない */ { s[0] = '0' + i / 10; s[1] = '0' + i % 10; if (s[0] == '0') s[0] = ' '; return; } -''以下未完成'' -ASKA版:"helloa4.ask" [osa_dir2では 171バイト] /* "helloa4.ask":helloをASKAで記述した例 */ /* stack:20k malloc:0k */ segment CODE(USE32, PARA); default(code == CODE); asmout("[FILE 'helloa.ask']"); asmout("GLOBAL _OsaskMain"); void _OsaskMain() { asmout("MOV EBX,data.funcs"); CALL(0xc7, 0); } asmout("[SECTION .data]"); void data() { ALIGNB(4); funcs: asmout("DD 0x0004, data.work"); /* lib_init */ asmout("DD 0x0020, data.window, 0x0200, 136, 48"); /* lib_openwindow */ asmout("DD 0x0028, 0x1000, data.wintitle, 0, 7, 1, 0, 0, data.window, 0x00c0, 0"); /* lib_opentextbox */ asmout("DD 0x0028, 0x0000, data.textbox, 0, 12, 1, 16, 16, data.window, 0x00c0, 0"); /* lib_opentextbox */ asmout("DD 0x0040, 0x1000, 0, 0, data.wintitle, 0, 0, 0, 7, 'helloa4'"); /* lib_putstring1 */ asmout("DD 0x0040, 0x1000, 0, 0, data.textbox, 0, 0, 0, 12, 'hello, world'"); /* lib_putstring1 */ DD(0x0018, 0x0001, 0, 0); /* lib_waitsignal */ DD(0x0000); /* end of functions */ ALIGNB(8); work: RESB(256); /* func_initに必要な256バイトのワークエリア */ window: RESB(128); /* ウィンドウ構造体 */ wintitle: RESB(64); /* テキストボックス構造体 */ RESB(64); /* 8x1文字分 (8 * 1 * 8) */ textbox: RESB(64); /* テキストボックス構造体 */ RESB(96); /* 12x1文字分 (12 * 1 * 8) */ } -nask版:"hellon4.nas" [osa_dir2では 170バイト] ; "hellon4.nas":helloをnaskで記述した例 ; stack:20k malloc:0k [FORMAT "WCOFF"] [INSTRSET "i486p"] [OPTIMIZE 1] [OPTION 1] [BITS 32] [FILE "hellon4.nas"] ; 新出のOPTIONについて。定数計算をデフォルトでは符号付き整数でおこなえという意味。 ; 指定しないとデフォルトは符号無し整数でおこなうことになっている。 [SECTION .text] GLOBAL _OsaskMain _OsaskMain: MOV EBX,funcs CALL 0xc7:0 [SECTION .data] ALIGNB 4 funcs: DD 0x0004, work ; lib_init DD 0x0020, window, 0x0200, 18 * 8, 3 * 16 ; lib_openwindow DD 0x0028, 0x1000, wintitle, 0, 8, 1, 0, 0, window, 0x00c0, 0 ; lib_opentextbox DD 0x0028, 0x0000, textbox, 0, 12, 1, 16, 16, window, 0x00c0, 0 ; lib_opentextbox DD 0x0040, 0x1000, 0, 0, wintitle, 0, 0, 0, 7, 'hellon4' ; lib_putstring1 DD 0x0040, 0x1000, 0, 0, textbox, 0, 0, 0, 12, 'hello, world' ; lib_putstring1 DD 0x0018, 0x0001, 0, 0 ; lib_waitsignal DD 0x0000 ; end of functions ALIGNB 8 work: RESB 256 ; func_initに必要な256バイトのワークエリア window: RESB 128 ; ウィンドウ構造体 wintitle: RESB 64 + 8 * 1 * 8; テキストボックス構造体(8x1文字分) textbox: RESB 64 + 12 * 1 * 8; テキストボックス構造体(12x1文字分) *** 説明 -概要: --このプログラムは、ウィンドウを一つ開き、そのウィンドウに"hello, world"と表示 するだけのプログラムです。 --このプログラムを通じて、OSASKアプリケーションの基本的な作法を説明します。 --OSASKアプリは基本的に、「ぐいぐい00ライブラリ」と呼ばれるライブラリを通じて、 ほとんどすべての入出力処理を行います。ですから、このライブラリの使い方をマスタ ーすることが、OSASKアプリの作り方をマスターすることになります。 --OSASKでは、「ウィンドウ」に「テキストボックス」を貼付け、そのテキストボックス に文字を書くという手順で文字を表示します。ウィンドウに直接文字を書く方法はあり ません。 --また文字を書くために、C言語では標準的なprintf()などを使うことはできません。特 別な関数を使います。 --なおプログラムを見ればすぐに分かっていただけると思いますが、OSASKアプリの標準 的なメインルーチンは、int main();ではなく、void OsaskMain();です。またこの関数 内でreturn;してはいけません。アプリケーションを終了するのは、APIを呼び出すこと で行います。 --stackとmallocについて説明します。プロジェクトを作ってMakefileを書き換えるとき、''STACKSIZE''と''MALLOCSIZE''という記述がすぐに見つかると思います。この記述をソースでの記載にそろえてください。なお、デフォルトではこのソースの値より大きいですが、実は大きい分にはあまり問題はありません。ソースでの記載よりも小さいと、誤動作の原因になります。それでも、無駄に大きいのはなんだかもったいないので、できればソースの記載にそろえることをおすすめします。 --C版とASKA版を見比べると、まあまあ似ていることが分かります。ASKA版とnask版を比べるとほとんど同じです。したがって、C用の資料をASKAやnaskで活用することができますし、逆にASKA用の資料やnask用の資料をCで活用することもできます。 --なお、Cでの関数呼び出しはまさにスタック渡しですが、これらは[[guide/ASKA]]や[[guide/nask]]で紹介したテクニックによって EBX = ESP; などがなされて、CALLされているにすぎません。 --C版では説明の簡便のためにAUTO_MALLOCを使っていますが、これをやめれば結構小さくなります(それでもPUSH等を多用する関係で、ASKA版やnask版にはサイズでは勝てません)。 -APIの説明: --lib_init(work) : ---APIを利用するために、かならず最初に行わなければならない初期化です。256バイトの領域をパラメータに指定します。この領域は4バイトアラインされている必要があります。機能番号は0x0004です。 ---C版でlib_init関数を使う場合workに0を指定することもでき、その場合はmalloc(256)された値が自動で割り当てられます。 ---この初期化作業やワークエリアは何だと思うかもしれませんが、OSASKのAPIの実態は実はDLL(ダイナミックリンクライブラリ)であり、これはそのDLLの初期化とワークエリア指定のためのものです。 ---APIでは、指定されたワークエリアやファンクション列はすべてDSで参照できるところにあると仮定され、さらに DS == ES == SS というのを仮定しています。.text内にコマンドを置いた場合、 DS = CS にしなければならず、そうするとワークエリアがCS内にあることになり、利用できないことになります。結局コマンド列は.data内かスタックにしか置けないでしょう。 --lib_openwindow(window, slot, x_size, y_size) : ---ウィンドウをオープンします。最初の引数windowは128バイトの領域を指定します。C版ではwindowに0を指定することもでき、その場合はmalloc(128)された値が自動で割り当てられ、関数値として返されます。機能番号は0x0020です。 ---x_sizeとy_sizeはウィンドウの大きさをドット単位で指定します。ここで指定されたサイズにはウィンドウタイトルのためのドット数は含まれません。slotは、0x200にしておいてください。 ---一つのタスクが複数のウィンドウを持つことが許されています。その場合、2つめの ウィンドウのslotは0x210、3つめは0x220という風に数を増やしてやってください。また、デフォルトではこれらのウィンドウのうち一つが閉じられると、残りのウィンドウ も全て自動的に閉じられてタスクは終了させられます。このデフォルトを変更することはもちろんできますが、それは入門では難しすぎるのでここでは触れません。 --lib_opentextbox(opt, textbox, backcolor, x_size, y_size, x_pos, y_pos, window, charset, init_char) : ---ウィンドウにテキストボックスを貼ります。機能番号は0x0028です。optにどんな値を指定するかでこの関数の意味は変わります。引数textboxは64バイト以上の領域で、必要ないサイズは、(64 + x_size * y_size * 8)バイトです。C版ではこれを0にできてその場合は自動でmallocされるなどは、lib_openwindowとおなじです。 ---opt == 0x1000 のとき ---ウィンドウタイトル専用のテキストボックスを作ります(''ウィンドウタイトルはウィンドウ一つに対して一つ必要''で、省略することは許されません)。backcolorとx_posとy_posとinit_charは必ず0にしてください。windowはどのウインドウのタイトルであるかを指定するためのもので、lib_openwindow()で指定した値を使います。y_sizeは必ず1です。それで、x_sizeにはこのテキストボックスの文字数を入れます。 ---ここで一つルールがあり、x_sizeは(ウィンドウのx_size / 8 - 10)以下の値にしなければいけません。長いウィンドウタイトルを付けたければ、この条件が満たされるようにウィンドウサイズを大きくしておく必要があります。 ---この関係式はもっと分かりやすくかけます。以下の不等式が成立するようにサイズを 決定してください。 タイトルのx_size * 8 + 80 <= ウィンドウのx_size ---opt == 0 のとき ---一般のテキストボックスを作ります。とりあえずbackcolorとinit_charは0で、charsetは0xc0です(この値の意味や変更方法などはもっと先で紹介します)。x_sizeとy_sizeはテキストボックスの大きさです。単位はキャラクター単位で、1キャラクターは、横8ドット、縦16ドットです。x_posとy_posはウィンドウのどこにテキストボックスを貼り付けるかという指示です。テキストボックスの左上の座標をウィンドウ内座標で示します。単位はドット単位です。ただしx_posは8の倍数を指定しなければいけません(これは将来のOSA SKでは解消される制限です)。y_posにはそういう制限はありません。windowでどのウィンドウにそのテキストボックスを貼り付けるかを指定します。やはり、lib_openwindow()で指定した値を使います。当然ですが、テキストボックスがウィンドウからはみ出さないようにしてください。テキストボックスは1つのウィンドウにいくつでも付けられますが、テキストボックスが重なることは許されません。座標やサイズに注意してください。 --lib_putstring_ASCII(opt, x_pos, y_pos, textbox, color, backcolor, str) : ---テキストボックスに文字を出力します。optとbackcolorは0にしてください。x_posとy_posはテキストボックス内での文字の表示位置を指定します。キャラクター単位です。左上が(0, 0)です。colorで表示色を制御できます(0~15)。textboxで対象となるテキストボックスを指定しますが、これはlib_opentextbox()で指定したものです。 ---strは表示したい文字列です。この関数は'\n'や'\t'を認識しません。したがって、複数行に渡って出力したい場合は、lib_putstring_ASCII()をその行数分だけ呼び出すことになります。また、textboxをはみ出すような長いstrを指定したりしてはいけません。 ---なお、textboxがウィンドウタイトル専用のテキストボックスの場合、x_posとy_posとcolorは必ず0にしてください。テキストボックスの同じ位置に何度も文字を重ね書きするのは許されます。その場合、文字が重なっていくのではなく最後に書かれた文字だけが表示されることになります(たとえば、既に表示されているところへスペースを表示すれば、文字は消える)。 ---Cのlib_putstring_ASCIIは直接APIを呼ばずに、バンドルのライブラリ関数を呼んでいます。これは自動で文字数などを数えさせるためです。ASKAやnaskではこれを使わずに、lib_putstring1というファンクションを直接呼んでいます(機能番号0x0040)。パラメータは次のとおりです。 ---lib_putstring1(opt, x_pos, y_pos, textbox, color, backcolor, 0, len, str) ---optは0x1000を指定します。これは即値モード、8bitキャラクタ、という意味です。即値モードではたとえ8bitキャラクタモードであってもstrは4バイト単位で書かれる必要があるので、DBではなくDDで書いてください(つまり末尾を4バイトアラインさせる必要がある、という意味)。 --lib_waitsignal(opt, signaldw, nest) : ---optを1にすれば、タスクはスリープし、事実上終了します。残り2つの引数は0にして ください。機能番号は0x0018です。 *** まとめ -これで好きな大きさのウィンドウを開き、ウィンドウにテキストボックスを貼り付けて、好きな色で文字をかけるようになったはずです。まだキー入力もタイマー制御もできないので、凝ったことはできませんが。 -プログラムの終了のさせ方も分かったはずです。「面倒だから無限ループ」なんてしないで、ちゃんとlib_waitsignalしてください(見た目は同じようなものですが、負荷が大きく違いますから)。 *** おまけ -ここまではどれもただ芸もなく固定的なパラメータでAPIを呼び出しているだけですが、次(no.0001)からはパラメータに変数を使ったり、サブルーチンを作ったりします。 * こめんと欄 #comment
(This host) = http://osask.net