esb02b
の編集
http://hrb.osask.jp/wiki/?esb02b
[
リロード
|
差分
|
単語検索
|
一覧
] [
編集
|
バックアップ
|
添付
]
-- 雛形とするページ --
A
Akkie
Athlon64X2
Clover
DAsoran
Falcon
FormatRule
FrontPage
Genesis
Help
I
InterWikiName
InterWikiSandBox
InterWikiテクニカル
Jormungand
K
Kebo
Kor_Lee_Hee_Rak
Leaf
Linux
Linux/wako_memo
MOIZ99
MW
MenuBar
OSC
PG_MANA
ReadersOS
RecentDeleted
SKYDASH
SandBox
Sero
Sigle
Source
Triangle_Ld.
Zxcvbnm
advance
advance/CPU
advance/FDC
advance/FPU
advance/NotHariMain
advance/QEMUVGA
advance/RTC
advance/blike
advance/cpu_reset
advance/driver
advance/driver/01
advance/driver/02
advance/families
advance/filesystem
advance/fwrite
advance/hddboot
advance/he86
advance/hints
advance/ipl
advance/kernel
advance/keycode
advance/osselect
advance/smaller1
advance/startup
advnace/smaller2
anzy
aotatsu
banbi-
bluedwarf
bo
bugs
challengers
cybozulabsyouth11
deskmanta
esb02b
faq
faq/advance
faq/asm
faq/c00-03
faq/c04-07
faq/c08-15
faq/c16-23
faq/c24-31
faq/make
faq/others
faq/qemu
guide
guide03
guide05
guide07
hikarupsp
imp_log/0000
imp_log/0001
imp_log/0002
imp_log/0003
impressions
index
k
killer_elf
kota
lea
lea/10_memory
lea/4_color
lea/idea
lea/terms
links
logs
logs/osa_hrb/comments0000
logs/osa_hrb/rumors0000
masa
members
message
mistakes
moge32
moppoi5168
notice
osdevjp
populars
prog_index
projects
q_and_a
q_and_a_2
qa_log/0000
qa_log/0001
qa_log/0002
qa_log/0003
qa_log/0004
qa_log/0005
qa_log/0006
qa_log/0007
qa_log/0008
qa_log/0009
quark
rankings
rule
sakamoto
sasaki
spc09
spcc_30min_os
tatsu
tools
tools/bim2hrb
tools/bin2obj
tools/cc1
tools/edimg
tools/gas2nask
tools/makefont
tools/nask
tools/obj2bim
tools/sjisconv
uchan
uho
updates
violations
wako
white
win64-bit
x
ytakano
ヘルプ
リックス
質問します
整形ルール
本は買ったぞ!持ってるぞ!
練習用ページ
* ES-BASIC ver.0.2b を「はりぼてOS」に移植する -(by [[K]], 2020.05.18) ** (0) はじめに -ES-BASICというのは[[K]]が中心となって開発している、プログラミング言語処理系です。 --詳しくは http://essen.osask.jp/?esbasic02a を見てください。 -これをもし「はりぼてOS」の上で動かすことができたら、自作OSの上で自作言語が動くということで、なんか夢があると思いませんか? --ちなみに、OSASK計画では、OSASK上で自作言語を動かすのに成功したことはありました。だからこれが日本初だということにはなりません。 --・・・しかし初めてではないとしても、やはり夢があることに変わりはないです! -そもそも http://essen.osask.jp/?esbasic0016 に書いてある通り、ES-BASICを「はりぼてOS」に移植するというアイデアは結構以前からありました。 -だから今回はそれを実際にやってみようという、ただそれだけの話です。 ** (1) 「はりぼてOS」の改造 -まずは「はりぼてOS」を改造してJITコンパイル対応しなければいけません。 -今の「はりぼてOS」は、アプリがメモリ上に書いた機械語を実行する手段を提供していません。アプリはアプリ制作時に生成したバイナリ以外を一切実行できないようになっています。 -それはセキュリティの観点では非常に堅牢なのですが、今回のように高速なスクリプト言語をアプリで実現しようとすると障害になってしまいます。 -ということで、データ上のプログラムを実行可能にするためのAPIを「はりぼてOS」側に追加するところから開発を始めます。 -と思ったけど、ES-BASICのソースを見て方針を少し変更。まずは[[advance/FPU]]を入れることにします。というのはES-BASICは少しだけ実数演算を使っているところがあったからです。・・・まあこれは、やろうと思えばすぐにできるので簡単です。 ---- -そして以下のAPIを追加します。 --api_semiFlat (EDX=32) ---[EDX以外のパラメータ] なし ---[説明] このAPIを呼び出すと、それ以降はデータセグメント内にあるコードもそのまま実行できるようになります。 ---より具体的に言うと、コードセグメントの内容をデータセグメントにコピーしたのちに、コードセグメントをデータセグメントのエイリアスに再設定しているだけです。 ---- -このための変更点は以下の通りです。 --haribote/bootpack.h (/* dsctbl.c */の中です) struct SEGMENT_DESCRIPTOR { unsigned short limit_low, base_low; /* ココから(つけ忘れていたunsigned属性をつける) */ unsigned char base_mid, access_right; unsigned char limit_high, base_high; /* ココまで */ }; --haribote/console.c (hrb_api()の中です) } else if (edx == 27) { reg[7] = task->langmode; } else if (edx == 32) { /* ココから */ struct SEGMENT_DESCRIPTOR *sd = task->ldt + 0; int cs_base = sd->base_low | sd->base_mid << 16 | sd->base_high << 24; int cs_size = ((sd->limit_low | sd->limit_high << 16) & 0xfffff) + 1; int ds_size = *((int *) (cs_base + 0x0000)); memcpy((char *) ds_base, (char *) cs_base, cs_size); set_segmdesc(task->ldt + 0, ds_size - 1, ds_base, AR_CODE32_ER + 0x60); /* ココまで */ } --apilib.h void api_semiFlat(void); /* これを末尾に追加 */ --apilib/api032.nas (新規作成) [FORMAT "WCOFF"] [INSTRSET "i486p"] [BITS 32] [FILE "api032.nas"] GLOBAL _api_semiFlat [SECTION .text] _api_semiFlat: ; void api_semiFlat(void); MOV EDX,32 INT 0x40 RET --apilib/Makefile ---api032.objもライブラリに含めるように適当に修正してください。 ---- -テスト用アプリを作ってみました。 #include "apilib.h" void HariMain(void) { static unsigned char p[] = { 0xba, 0x01, 0x00, 0x00, 0x00, 0xb0, 0x41, 0xcd, 0x40, 0xc3 }; api_semiFlat(); ((void (*)()) p)(); api_end(); } -これを実行すると、データセクション内にあるpが普通に実行されて、EDX=1,AL=0x41でINT 0x40が実行され、「A」が表示されます。 -ということでうまくいったので、「はりぼてOS」側の改造はおしまいです。 ---- -と思ったけれど、esb02b.hrbが大きくなっていくにつれて、無改造のipl09.nasでは読み込みきれなくなってきて実行できなくなってきたので、[[advance/ipl]]の改造を適用しました。 -ついでに[[Athlon64X2]]と[[advance/smaller1]]も適用しました。 -さらにキーコードの問題があったので[[advance/keycode]]も適用しました。 ---- -API番号表: |EDX|説明|プロトタイプ宣言|備考| |RIGHT:1|コンソールに一文字表示|void api_putchar(int c);|| |RIGHT:2|コンソールに文字列表示|void api_putstr0(char *s);|| |RIGHT:3|コンソールに文字列表示|void api_putstr1(char *s, int l);|| |RIGHT:4|アプリの終了|void api_end(void);|| |RIGHT:5|ウィンドウのオープン|int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);|| |RIGHT:6|ウィンドウに文字列描画|void api_putstrwin(int win, int x, int y, int col, int len, char *str);|| |RIGHT:7|ウィンドウに矩形描画|void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);|| |RIGHT:8|アプリ内でapi_mallocが利用できるように内部初期化|void api_initmalloc(void);|| |RIGHT:9|メモリの確保|char *api_malloc(int size);|| |RIGHT:10|メモリの解放|void api_free(char *addr, int size);|| |RIGHT:11|ウィンドウに点を打つ|void api_point(int win, int x, int y, int col);|| |RIGHT:12|ウィンドウの描画内容を手動で画面に反映|void api_refreshwin(int win, int x0, int y0, int x1, int y1);|| |RIGHT:13|ウィンドウに線を引く|void api_linewin(int win, int x0, int y0, int x1, int y1, int col);|| |RIGHT:14|ウィンドウを閉じる|void api_closewin(int win);|| |RIGHT:15|入力バッファから入力|int api_getkey(int mode);|| |RIGHT:16|タイマを取得|int api_alloctimer(void);|| |RIGHT:17|タイマを初期化|void api_inittimer(int timer, int data);|| |RIGHT:18|タイマを設定|void api_settimer(int timer, int time);|| |RIGHT:19|タイマを解放|void api_freetimer(int timer);|| |RIGHT:20|音を出す|void api_beep(int tone);|| |RIGHT:21|ファイルの読み込み用オープン|int api_fopen(char *fname);|| |RIGHT:22|ファイルのクローズ|void api_fclose(int fhandle);|| |RIGHT:23|ファイルのシーク|void api_fseek(int fhandle, int offset, int mode);|| |RIGHT:24|ファイルサイズ取得|int api_fsize(int fhandle, int mode);|| |RIGHT:25|ファイルの読み込み|int api_fread(char *buf, int maxsize, int fhandle);|| |RIGHT:26|アプリのコマンドライン引数の取得|int api_cmdline(char *buf, int maxsize);|| |RIGHT:27|現在の言語モードを取得|int api_getlang(void);|| |RIGHT:27|OSの識別番号を取得|int api_getosid(void);|詳しくは[[advance/families]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:27|OSのバージョン番号を取得|int api_getosver(void);|詳しくは[[advance/families]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:28|ファイルの書き込み用オープン||詳しくは[[advance/fwrite]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:29|ファイルの書き込み||詳しくは[[advance/fwrite]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:30|OSの切り替え|void api_osselect(int i);|詳しくは[[advance/osselect]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:31|キー入力データを送り込む|int api_sendkey(char *);|詳しくは[[advance/startup]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:32|JITコンパイル対応モードへ切り替え|void api_semiFlat(void);|詳しくは[[esb02b]]参照| |RIGHT:33|(ECX=1)timerctl.countの取得|int api_getTimeCount(void);|詳しくは[[advance/keycode]]参照| |RIGHT:33|(ECX=2)キー入力の拡張|int api_getkeyEx(int mode);|詳しくは[[advance/keycode]]参照| ** (2) ES-BASICの移植 -[進捗&雑談#1] --移植で一番面倒なのは、標準ライブラリが「はりぼてOS」では使えないこと。まずここをどうにかしないといけない。 --標準ライブラリくらいならもちろん自力でも書けるのだけど、そこでミスったら面倒だし、テストをいっぱいするのも面倒だし・・・。 --そう思ってglibcから拝借しようかと思ったけど、glibcの実装は高速化と移植性のために冗長になっていて、うーん、そういうのがほしいわけじゃないんだ・・・になってしまった。他のライブラリをたくさん参照されると、それを用意する必要が出てくるので、労力が減らない・・・。 --やっぱり自分でシンプルに実装するかー。 --qsortとかを自前で作ることにちょっと熱中してしまった(笑)。 -[進捗&雑談#2] --なるほどなー。「はりぼてOS」でグラフィックウィンドウを出すときは、ウィンドウの全領域(ユーザ領域以外も含む)のサイズのchar配列を用意するわけかー。ちょっと思い出してきたぞ・・・。 char winbuf[336 * 261]; win = api_openwin(winbuf, 336, 261, -1, "invader"); api_boxfilwin(win, 6, 27, 329, 254, 0); --「はりぼてOS」のシェルのコンソールは、ちょっとプログラムを書くには狭すぎるし、そもそも一行入力とかのAPIも用意していない記憶があるから、自前でコンソールを作るほうがよさそうだな・・・。 -[進捗&雑談#3] --あと少しで初期化を終えられそうだ・・・。そしたらなんか画面が出そう。 -[進捗&雑談#4] --ここまできて、移植方針を大転換。そのほうがうまくいく気がしたので。・・・ということで改造部分を全部ロールバックしてやり直した。 --でも、そしたらすぐに1時間程度でいいところまで来た。今までの数日の苦労は一体・・・(笑)。 --とりあえずあと15個の標準関数を適当に実装すれば、そこそこ動きそうなところまで来ました。 -[進捗&雑談#5] --面倒になってきて、標準関数をダミーで適当にごまかしたら、ついにES-BASICが起動して「Ok」が出るところまでは動くようになりました。しかしまだコンソールに対して入力ができないので、そこから先には進めませんが・・・。 -[進捗&雑談#6] --コンソールが動くようになって、コンソールしか使わないプログラムはほとんど動くようになりました。自作OS上で自作言語処理系がサクサクと動くのは相当にしびれます。デバッグ機能もちゃんと動きます。笑いが止まりません(笑)。 --次はグラフィックを出せるようにしなければっ! -[進捗&雑談#7] --グラフィックも出るようになった。かっこいいぞ! -[進捗&雑談#8] --完璧に動くようになったーー!・・・内容をまとめなければっ! -こちらに書きました。→ http://essen.osask.jp/?esb02b_hrb * こめんと欄 #comment
タイムスタンプを変更しない
* ES-BASIC ver.0.2b を「はりぼてOS」に移植する -(by [[K]], 2020.05.18) ** (0) はじめに -ES-BASICというのは[[K]]が中心となって開発している、プログラミング言語処理系です。 --詳しくは http://essen.osask.jp/?esbasic02a を見てください。 -これをもし「はりぼてOS」の上で動かすことができたら、自作OSの上で自作言語が動くということで、なんか夢があると思いませんか? --ちなみに、OSASK計画では、OSASK上で自作言語を動かすのに成功したことはありました。だからこれが日本初だということにはなりません。 --・・・しかし初めてではないとしても、やはり夢があることに変わりはないです! -そもそも http://essen.osask.jp/?esbasic0016 に書いてある通り、ES-BASICを「はりぼてOS」に移植するというアイデアは結構以前からありました。 -だから今回はそれを実際にやってみようという、ただそれだけの話です。 ** (1) 「はりぼてOS」の改造 -まずは「はりぼてOS」を改造してJITコンパイル対応しなければいけません。 -今の「はりぼてOS」は、アプリがメモリ上に書いた機械語を実行する手段を提供していません。アプリはアプリ制作時に生成したバイナリ以外を一切実行できないようになっています。 -それはセキュリティの観点では非常に堅牢なのですが、今回のように高速なスクリプト言語をアプリで実現しようとすると障害になってしまいます。 -ということで、データ上のプログラムを実行可能にするためのAPIを「はりぼてOS」側に追加するところから開発を始めます。 -と思ったけど、ES-BASICのソースを見て方針を少し変更。まずは[[advance/FPU]]を入れることにします。というのはES-BASICは少しだけ実数演算を使っているところがあったからです。・・・まあこれは、やろうと思えばすぐにできるので簡単です。 ---- -そして以下のAPIを追加します。 --api_semiFlat (EDX=32) ---[EDX以外のパラメータ] なし ---[説明] このAPIを呼び出すと、それ以降はデータセグメント内にあるコードもそのまま実行できるようになります。 ---より具体的に言うと、コードセグメントの内容をデータセグメントにコピーしたのちに、コードセグメントをデータセグメントのエイリアスに再設定しているだけです。 ---- -このための変更点は以下の通りです。 --haribote/bootpack.h (/* dsctbl.c */の中です) struct SEGMENT_DESCRIPTOR { unsigned short limit_low, base_low; /* ココから(つけ忘れていたunsigned属性をつける) */ unsigned char base_mid, access_right; unsigned char limit_high, base_high; /* ココまで */ }; --haribote/console.c (hrb_api()の中です) } else if (edx == 27) { reg[7] = task->langmode; } else if (edx == 32) { /* ココから */ struct SEGMENT_DESCRIPTOR *sd = task->ldt + 0; int cs_base = sd->base_low | sd->base_mid << 16 | sd->base_high << 24; int cs_size = ((sd->limit_low | sd->limit_high << 16) & 0xfffff) + 1; int ds_size = *((int *) (cs_base + 0x0000)); memcpy((char *) ds_base, (char *) cs_base, cs_size); set_segmdesc(task->ldt + 0, ds_size - 1, ds_base, AR_CODE32_ER + 0x60); /* ココまで */ } --apilib.h void api_semiFlat(void); /* これを末尾に追加 */ --apilib/api032.nas (新規作成) [FORMAT "WCOFF"] [INSTRSET "i486p"] [BITS 32] [FILE "api032.nas"] GLOBAL _api_semiFlat [SECTION .text] _api_semiFlat: ; void api_semiFlat(void); MOV EDX,32 INT 0x40 RET --apilib/Makefile ---api032.objもライブラリに含めるように適当に修正してください。 ---- -テスト用アプリを作ってみました。 #include "apilib.h" void HariMain(void) { static unsigned char p[] = { 0xba, 0x01, 0x00, 0x00, 0x00, 0xb0, 0x41, 0xcd, 0x40, 0xc3 }; api_semiFlat(); ((void (*)()) p)(); api_end(); } -これを実行すると、データセクション内にあるpが普通に実行されて、EDX=1,AL=0x41でINT 0x40が実行され、「A」が表示されます。 -ということでうまくいったので、「はりぼてOS」側の改造はおしまいです。 ---- -と思ったけれど、esb02b.hrbが大きくなっていくにつれて、無改造のipl09.nasでは読み込みきれなくなってきて実行できなくなってきたので、[[advance/ipl]]の改造を適用しました。 -ついでに[[Athlon64X2]]と[[advance/smaller1]]も適用しました。 -さらにキーコードの問題があったので[[advance/keycode]]も適用しました。 ---- -API番号表: |EDX|説明|プロトタイプ宣言|備考| |RIGHT:1|コンソールに一文字表示|void api_putchar(int c);|| |RIGHT:2|コンソールに文字列表示|void api_putstr0(char *s);|| |RIGHT:3|コンソールに文字列表示|void api_putstr1(char *s, int l);|| |RIGHT:4|アプリの終了|void api_end(void);|| |RIGHT:5|ウィンドウのオープン|int api_openwin(char *buf, int xsiz, int ysiz, int col_inv, char *title);|| |RIGHT:6|ウィンドウに文字列描画|void api_putstrwin(int win, int x, int y, int col, int len, char *str);|| |RIGHT:7|ウィンドウに矩形描画|void api_boxfilwin(int win, int x0, int y0, int x1, int y1, int col);|| |RIGHT:8|アプリ内でapi_mallocが利用できるように内部初期化|void api_initmalloc(void);|| |RIGHT:9|メモリの確保|char *api_malloc(int size);|| |RIGHT:10|メモリの解放|void api_free(char *addr, int size);|| |RIGHT:11|ウィンドウに点を打つ|void api_point(int win, int x, int y, int col);|| |RIGHT:12|ウィンドウの描画内容を手動で画面に反映|void api_refreshwin(int win, int x0, int y0, int x1, int y1);|| |RIGHT:13|ウィンドウに線を引く|void api_linewin(int win, int x0, int y0, int x1, int y1, int col);|| |RIGHT:14|ウィンドウを閉じる|void api_closewin(int win);|| |RIGHT:15|入力バッファから入力|int api_getkey(int mode);|| |RIGHT:16|タイマを取得|int api_alloctimer(void);|| |RIGHT:17|タイマを初期化|void api_inittimer(int timer, int data);|| |RIGHT:18|タイマを設定|void api_settimer(int timer, int time);|| |RIGHT:19|タイマを解放|void api_freetimer(int timer);|| |RIGHT:20|音を出す|void api_beep(int tone);|| |RIGHT:21|ファイルの読み込み用オープン|int api_fopen(char *fname);|| |RIGHT:22|ファイルのクローズ|void api_fclose(int fhandle);|| |RIGHT:23|ファイルのシーク|void api_fseek(int fhandle, int offset, int mode);|| |RIGHT:24|ファイルサイズ取得|int api_fsize(int fhandle, int mode);|| |RIGHT:25|ファイルの読み込み|int api_fread(char *buf, int maxsize, int fhandle);|| |RIGHT:26|アプリのコマンドライン引数の取得|int api_cmdline(char *buf, int maxsize);|| |RIGHT:27|現在の言語モードを取得|int api_getlang(void);|| |RIGHT:27|OSの識別番号を取得|int api_getosid(void);|詳しくは[[advance/families]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:27|OSのバージョン番号を取得|int api_getosver(void);|詳しくは[[advance/families]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:28|ファイルの書き込み用オープン||詳しくは[[advance/fwrite]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:29|ファイルの書き込み||詳しくは[[advance/fwrite]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:30|OSの切り替え|void api_osselect(int i);|詳しくは[[advance/osselect]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:31|キー入力データを送り込む|int api_sendkey(char *);|詳しくは[[advance/startup]]参照 (しかし今回はこの改造を適用していません)| |RIGHT:32|JITコンパイル対応モードへ切り替え|void api_semiFlat(void);|詳しくは[[esb02b]]参照| |RIGHT:33|(ECX=1)timerctl.countの取得|int api_getTimeCount(void);|詳しくは[[advance/keycode]]参照| |RIGHT:33|(ECX=2)キー入力の拡張|int api_getkeyEx(int mode);|詳しくは[[advance/keycode]]参照| ** (2) ES-BASICの移植 -[進捗&雑談#1] --移植で一番面倒なのは、標準ライブラリが「はりぼてOS」では使えないこと。まずここをどうにかしないといけない。 --標準ライブラリくらいならもちろん自力でも書けるのだけど、そこでミスったら面倒だし、テストをいっぱいするのも面倒だし・・・。 --そう思ってglibcから拝借しようかと思ったけど、glibcの実装は高速化と移植性のために冗長になっていて、うーん、そういうのがほしいわけじゃないんだ・・・になってしまった。他のライブラリをたくさん参照されると、それを用意する必要が出てくるので、労力が減らない・・・。 --やっぱり自分でシンプルに実装するかー。 --qsortとかを自前で作ることにちょっと熱中してしまった(笑)。 -[進捗&雑談#2] --なるほどなー。「はりぼてOS」でグラフィックウィンドウを出すときは、ウィンドウの全領域(ユーザ領域以外も含む)のサイズのchar配列を用意するわけかー。ちょっと思い出してきたぞ・・・。 char winbuf[336 * 261]; win = api_openwin(winbuf, 336, 261, -1, "invader"); api_boxfilwin(win, 6, 27, 329, 254, 0); --「はりぼてOS」のシェルのコンソールは、ちょっとプログラムを書くには狭すぎるし、そもそも一行入力とかのAPIも用意していない記憶があるから、自前でコンソールを作るほうがよさそうだな・・・。 -[進捗&雑談#3] --あと少しで初期化を終えられそうだ・・・。そしたらなんか画面が出そう。 -[進捗&雑談#4] --ここまできて、移植方針を大転換。そのほうがうまくいく気がしたので。・・・ということで改造部分を全部ロールバックしてやり直した。 --でも、そしたらすぐに1時間程度でいいところまで来た。今までの数日の苦労は一体・・・(笑)。 --とりあえずあと15個の標準関数を適当に実装すれば、そこそこ動きそうなところまで来ました。 -[進捗&雑談#5] --面倒になってきて、標準関数をダミーで適当にごまかしたら、ついにES-BASICが起動して「Ok」が出るところまでは動くようになりました。しかしまだコンソールに対して入力ができないので、そこから先には進めませんが・・・。 -[進捗&雑談#6] --コンソールが動くようになって、コンソールしか使わないプログラムはほとんど動くようになりました。自作OS上で自作言語処理系がサクサクと動くのは相当にしびれます。デバッグ機能もちゃんと動きます。笑いが止まりません(笑)。 --次はグラフィックを出せるようにしなければっ! -[進捗&雑談#7] --グラフィックも出るようになった。かっこいいぞ! -[進捗&雑談#8] --完璧に動くようになったーー!・・・内容をまとめなければっ! -こちらに書きました。→ http://essen.osask.jp/?esb02b_hrb * こめんと欄 #comment
テキスト整形のルールを表示する