アプリケーションとしては、shellとuptime、whoareyouという3つです。現状、カーネルの動作確認程度のものでしかないです。
shellはその名の通りシェルで、CUIを提供します。shellの組み込みコマンドとしては、echoとメモリ/IOへの直接read/writeのコマンド(readb,readw,readl,ioreadb,writeも同様のコマンド名)、そしてbgというコマンドがあります。bgは今回のリリースで追加したコマンドで、引数で指定したコマンドをバックグラウンド実行します。(これまでは、実行したコマンドの終了を待つことができなかったので、常にバックグラウンド実行でした。)uptime・whoareyouもshellから起動します。これらのコマンド名をshell上で入力すると、shellはexecシステムコール(OS5ではexecをシステムコールとしています)を使用して実行します。
uptimeはマルチタスクの動作確認をするためのコマンドです。コンソール画面の右上で、16進数で起動時間をカウントし続けます。自ら終了することがないコマンドなので、バックグラウンド実行しないとプロンプトが帰ってこなくなります。
whoareyouは今回のリリースで新たに追加したコマンドです。argcとargvによりコマンドライン引数を受け取れることを確認するためのコマンドです。
また、今回のリリースでは、main()をエントリポイントとする変更や、静的ライブラリの仕組みも導入しており、よく見るCのソースコードのようにアプリケーションを書けるようになりました。
話は変わって、ユーザーランドのファイルシステムイメージは、makeの過程で、シェルスクリプトで作成します。ファイルシステムは、簡単に、ファイル名とバイナリのみを管理するだけのもので、シェルスクリプトでバイナリを並べて連結しています。ファイルシステムについても詳しくは上述のスライドをご覧ください。
これまでをまとめると、アプリケーションが実行されるまでの流れは以下のとおりです。
リスト4.1: apps/Makefile
1: LIB_DIR = .lib 2: BIN_DIR = .bin 3: APP_LD = ../app.ld 4: LIB_DIRS = libkernel libcommon libconsole libstring 5: APP_DIRS = $(shell find . -maxdepth 1 -type d '!' -iname '.*' '!' \ 6: -iname 'include' '!' -iname 'lib*') 7: CFLAGS = -Wall -Wextra 8: CFLAGS += -nostdinc -nostdlib -fno-builtin -c 9: CFLAGS += -I../include 10: CFLAGS += -m32 11: CFLAGS += -DCOMPILE_APP 12: LDFLAGS = -L../$(LIB_DIR) 13: LIBS = -lstring -lconsole -lcommon -lkernel 14: 15: apps.img: lib app 16: ../tools/make_os5_fs.sh $(BIN_DIR)/* > $@ 17: 18: lib: $(LIB_DIRS) 19: [ -d $(LIB_DIR) ] || mkdir $(LIB_DIR) 20: for libdir in $^; do \ 21: make -C $$libdir LIB_DIR=../$(LIB_DIR) \ 22: APP_LD=$(APP_LD) CFLAGS="$(CFLAGS)" \ 23: LDFLAGS="$(LDFLAGS)" LIBS="$(LIBS)"; \ 24: done 25: 26: app: $(APP_DIRS) 27: [ -d $(BIN_DIR) ] || mkdir $(BIN_DIR) 28: for appdir in $^; do \ 29: make -C $$appdir BIN_DIR=../$(BIN_DIR) \ 30: APP_LD=$(APP_LD) CFLAGS="$(CFLAGS)" \ 31: LDFLAGS="$(LDFLAGS)" LIBS="$(LIBS)"; \ 32: done 33: 34: clean: 35: rm -rf *~ *.o *.a *.bin *.dat *.img *.map $(LIB_DIR) $(BIN_DIR) 36: for dir in $(LIB_DIRS) $(APP_DIRS); do \ 37: make -C $$dir clean; \ 38: done 39: 40: .PHONY: lib app clean
ユーザーランド上の各アプリケーションのコンパイルを行う大元のMakefileです。
このMakefileでの最終生成物はapps.imgです。apps.imgを生成するために、ライブラリのコンパイル(libターゲット)、アプリケーションのコンパイル(appターゲット)、tools/make_os5_fs.shでファイルシステム生成(apps.imgターゲット)という流れです。
リスト4.2: apps/app.ld
1: OUTPUT_FORMAT("binary");
2:
3: SECTIONS
4: {
5: . = 0x20000030;
6: .text : {
7: *(.entry)
8: *(.text)
9: }
10: .rodata : {
11: *(.strings)
12: *(.rodata)
13: *(.rodata.*)
14: }
15: .data : {*(.data)}
16: .bss : {*(.bss)}
17: }
アプリケーションのリンカスクリプトです。仮想アドレス空間上、ユーザー空間は0x2000 0000からで、先頭48(0x30)バイトがファイルシステムのヘッダなので、0x2000 0030からtextセクション(コードの領域)を配置しています。そのため、スケジューラでもタスクのエントリアドレスは0x2000 0030としています(kernel/task.cの#define APP_ENTRY_POINT 0x20000030)。
リスト4.3: apps/include/app.h
1: #ifndef _APP_H_
2: #define _APP_H_
3:
4: int main(int argc, char *argv[]) __attribute__((section(".entry")));
5:
6: #endif /* _APP_H_ */
エントリ関数としてmain関数のプロトタイプ宣言をしています。
リスト4.4: apps/0shell/Makefile
1: NAME=0shell 2: 3: $(BIN_DIR)/$(NAME): $(NAME).o 4: ld -m elf_i386 -o $@ $< -Map $(NAME).map -s -T $(APP_LD) -x \ 5: $(LDFLAGS) $(LIBS) 6: 7: %.o: %.c 8: gcc $(CFLAGS) -o $@ $< 9: 10: clean: 11: rm -rf *~ *.o *.map 12: 13: .PHONY: clean
シェルアプリケーション(0shell)のMakefileです。Makefileはアプリケーションごとに存在しますが、内容はNAME=0shellの行を除いて共通です。
リスト4.5: apps/0shell/0shell.c
1: #include <app.h>
2: #include <kernel.h>
3: #include <common.h>
4: #include <string.h>
5: #include <console.h>
6:
7: #define MAX_LINE_SIZE 512
8:
9: enum {
10: ECHO,
11: READB,
12: READW,
13: READL,
14: IOREADB,
15: WRITEB,
16: WRITEW,
17: WRITEL,
18: IOWRITEB,
19: BG,
20: #ifdef DEBUG
21: TEST,
22: #endif /* DEBUG */
23: COMMAND_NUM
24: } _COMMAND_SET;
25:
26: static int command_echo(char *args)
27: {
28: put_str(args);
29: put_str("\r\n");
30:
31: return 0;
32: }
33:
34: static int command_readb(char *args)
35: {
36: char first[128], other[128];
37: unsigned char *addr;
38:
39: str_get_first_entry(args, first, other);
40: addr = (unsigned char *)str_conv_ahex_int(first);
41: dump_hex(*addr, 2);
42: put_str("\r\n");
43:
44: return 0;
45: }
46:
47: static int command_readw(char *args)
48: {
49: char first[128], other[128];
50: unsigned short *addr;
51:
52: str_get_first_entry(args, first, other);
53: addr = (unsigned short *)str_conv_ahex_int(first);
54: dump_hex(*addr, 4);
55: put_str("\r\n");
56:
57: return 0;
58: }
59:
60: static int command_readl(char *args)
61: {
62: char first[128], other[128];
63: unsigned int *addr;
64:
65: str_get_first_entry(args, first, other);
66: addr = (unsigned int *)str_conv_ahex_int(first);
67: dump_hex(*addr, 8);
68: put_str("\r\n");
69:
70: return 0;
71: }
72:
73: static int command_ioreadb(char *args)
74: {
75: char first[128], other[128];
76: unsigned short addr;
77:
78: str_get_first_entry(args, first, other);
79: addr = (unsigned short)str_conv_ahex_int(first);
80: dump_hex(inb_p(addr), 2);
81: put_str("\r\n");
82:
83: return 0;
84: }
85:
86: static int command_writeb(char *args)
87: {
88: char first[16], second[32], other[128], _other[128];
89: unsigned char data, *addr;
90:
91: str_get_first_entry(args, first, other);
92: str_get_first_entry(other, second, _other);
93: data = (unsigned char)str_conv_ahex_int(first);
94: addr = (unsigned char *)str_conv_ahex_int(second);
95: *addr = data;
96:
97: return 0;
98: }
99:
100: static int command_writew(char *args)
101: {
102: char first[16], second[32], other[128], _other[128];
103: unsigned short data, *addr;
104:
105: str_get_first_entry(args, first, other);
106: str_get_first_entry(other, second, _other);
107: data = (unsigned short)str_conv_ahex_int(first);
108: addr = (unsigned short *)str_conv_ahex_int(second);
109: *addr = data;
110:
111: return 0;
112: }
113:
114: static int command_writel(char *args)
115: {
116: char first[16], second[32], other[128], _other[128];
117: unsigned int data, *addr;
118:
119: str_get_first_entry(args, first, other);
120: str_get_first_entry(other, second, _other);
121: data = (unsigned int)str_conv_ahex_int(first);
122: addr = (unsigned int *)str_conv_ahex_int(second);
123: *addr = data;
124:
125: return 0;
126: }
127:
128: static int command_iowriteb(char *args)
129: {
130: char first[16], second[32], other[128], _other[128];
131: unsigned char data;
132: unsigned short addr;
133:
134: str_get_first_entry(args, first, other);
135: str_get_first_entry(other, second, _other);
136: data = (unsigned char)str_conv_ahex_int(first);
137: addr = (unsigned short)str_conv_ahex_int(second);
138: outb_p(data, addr);
139:
140: return 0;
141: }
142:
143: #ifdef DEBUG
144: static int command_test(char *args)
145: {
146: put_str("test\r\n");
147:
148: return 0;
149: }
150: #endif /* DEBUG */
151:
152: static unsigned char get_command_id(const char *command)
153: {
154: if (!str_compare(command, "echo")) {
155: return ECHO;
156: }
157:
158: if (!str_compare(command, "readb")) {
159: return READB;
160: }
161:
162: if (!str_compare(command, "readw")) {
163: return READW;
164: }
165:
166: if (!str_compare(command, "readl")) {
167: return READL;
168: }
169:
170: if (!str_compare(command, "ioreadb")) {
171: return IOREADB;
172: }
173:
174: if (!str_compare(command, "writeb")) {
175: return WRITEB;
176: }
177:
178: if (!str_compare(command, "writew")) {
179: return WRITEW;
180: }
181:
182: if (!str_compare(command, "writel")) {
183: return WRITEL;
184: }
185:
186: if (!str_compare(command, "iowriteb")) {
187: return IOWRITEB;
188: }
189:
190: if (!str_compare(command, "bg")) {
191: return BG;
192: }
193:
194: #ifdef DEBUG
195: if (!str_compare(command, "test")) {
196: return TEST;
197: }
198: #endif /* DEBUG */
199:
200: return COMMAND_NUM;
201: }
202:
203: int main(int argc __attribute__ ((unused)),
204: char *argv[] __attribute__ ((unused)))
205: {
206: while (1) {
207: char buf[MAX_LINE_SIZE];
208: char command[256], args[256];
209: unsigned char command_id, is_background = 0;
210: unsigned int fp;
211:
212: put_str("OS5> ");
213: if (get_line(buf, MAX_LINE_SIZE) <= 0) {
214: continue;
215: }
216:
217: while (1) {
218: str_get_first_entry(buf, command, args);
219: command_id = get_command_id(command);
220: if (command_id != BG)
221: break;
222: else {
223: is_background = 1;
224: copy_mem(args, buf,
225: (unsigned int)str_get_len(args));
226: }
227: }
228:
229: switch (command_id) {
230: case ECHO:
231: command_echo(args);
232: break;
233: case READB:
234: command_readb(args);
235: break;
236: case READW:
237: command_readw(args);
238: break;
239: case READL:
240: command_readl(args);
241: break;
242: case IOREADB:
243: command_ioreadb(args);
244: break;
245: case WRITEB:
246: command_writeb(args);
247: break;
248: case WRITEW:
249: command_writew(args);
250: break;
251: case WRITEL:
252: command_writel(args);
253: break;
254: case IOWRITEB:
255: command_iowriteb(args);
256: break;
257: #ifdef DEBUG
258: case TEST:
259: command_test(args);
260: break;
261: #endif /* DEBUG */
262: default:
263: fp = syscall(SYSCALL_OPEN, (unsigned int)command, 0, 0);
264: if (fp) {
265: unsigned int argc = 0, i;
266: char *argv[256];
267: char *start;
268:
269: argv[argc++] = command;
270:
271: start = &args[0];
272: for (i = 0; ; i++) {
273: if ((i == 0) && (args[i] == '\0')) {
274: break;
275: } else if ((args[i] == ' ') ||
276: (args[i] == '\0')) {
277: argv[argc++] = start;
278: start = &args[i + 1];
279: if (args[i] == ' ')
280: args[i] = '\0';
281: else
282: break;
283: }
284: }
285:
286: syscall(SYSCALL_EXEC, fp, argc,
287: (unsigned int)argv);
288:
289: if (!is_background)
290: syscall(SYSCALL_SCHED_WAKEUP_EVENT,
291: EVENT_TYPE_EXIT, 0, 0);
292: } else
293: put_str("Command not found.\r\n");
294: break;
295: }
296: }
297: }
シェルアプリケーションの本体のソースコードです。OS5の中で3番目に長いソースコードで297行あります。
includeしている各ヘッダファイルについては以下の通りです。
main関数を使用するためsyscall関数を使用するため実体はapps/libkernel/libkernel.cにあるcopy_mem関数を使用するため実体はapps/libcommon/libcommon.cにあるmain関数の処理をざっくりと説明すると以下の通りです。
get_line関数で1行分の入力文字列を取得するまで待機(212~215行目)str_get_first_entry関数でコマンド名を切り出し、get_command_id関数でシェル組み込みコマンドのIDを取得。取得したコマンドが"bg"コマンドであった場合は、is_backgroundフラグをセットする(217~227行目)なお、3.でファイルを実行するときに、2.でis_backgroundがセットされていなければ、ファイルの実行が終了するまでシェルをスリープさせます(289~291行目)。これにより、バックグラウンド実行していない場合は、実行が終了するまでプロンプトが戻ってこないようにしています。
リスト4.6: apps/uptime/Makefile
1: NAME=uptime 2: 3: $(BIN_DIR)/$(NAME): $(NAME).o 4: ld -m elf_i386 -o $@ $< -Map $(NAME).map -s -T $(APP_LD) -x \ 5: $(LDFLAGS) $(LIBS) 6: 7: %.o: %.c 8: gcc $(CFLAGS) -o $@ $< 9: 10: clean: 11: rm -rf *~ *.o *.map 12: 13: .PHONY: clean
uptimeアプリケーションのMakefileです。
リスト4.7: apps/uptime/uptime.c
1: #include <app.h>
2: #include <kernel.h>
3: #include <console.h>
4:
5: int main(int argc __attribute__ ((unused)),
6: char *argv[] __attribute__ ((unused)))
7: {
8: static unsigned int uptime;
9: unsigned int cursor_pos_y;
10:
11: while (1) {
12: uptime = get_global_counter() / 1000;
13: cursor_pos_y = get_cursor_pos_y();
14: if (cursor_pos_y < ROWS) {
15: put_str_pos("uptime:", COLUMNS - (7 + 4), 0);
16: dump_hex_pos(uptime, 4, COLUMNS - 4, 0);
17: } else {
18: put_str_pos("uptime:", COLUMNS - (7 + 4),
19: cursor_pos_y - ROWS + 1);
20: dump_hex_pos(uptime, 4, COLUMNS - 4,
21: cursor_pos_y - ROWS + 1);
22: }
23: syscall(SYSCALL_SCHED_WAKEUP_MSEC, 33, 0, 0);
24: }
25: }
uptimeアプリケーションの本体のソースコードです。
uptimeは、OS5が起動してからの秒数を画面右上に表示(16進表記)するアプリケーションです。マルチタスクの動作確認のために作成しました。
処理としては、以下を無限ループで繰り返しています。
get_global_counter関数)し、秒へ変換(12行目)get_cursor_pos_y関数)(13行目)3.は画面右上に固定させるための処理です。カーソルのY座標が1画面の行数(ROWS)未満であれば、まだ一度も画面スクロールを行っていないため、出力するY座標は0で良いです。カーソルのY座標がROWS以上の場合、画面はスクロールしているので、Y座標0の場所に出力しても見切れてしまいます(表示範囲外のため)。そのため、"カーソルY座標 - ROWS + 1"のY座標へ出力するようにしています(スクロール後、常にカーソルは画面最下行に張り付くため、この計算式になっています)。
4.は画面更新周期を作るためのスリープです。なお、33msは感覚的に決めた値です。スケジューリングの周期が「画面スクロール処理をしてから再度uptimeのカウンタが描画されるまでの間」に当たるとチラつきます。
リスト4.8: apps/whoareyou/Makefile
1: NAME=whoareyou 2: 3: $(BIN_DIR)/$(NAME): $(NAME).o 4: ld -m elf_i386 -o $@ $< -Map $(NAME).map -s -T $(APP_LD) -x \ 5: $(LDFLAGS) $(LIBS) 6: 7: %.o: %.c 8: gcc $(CFLAGS) -o $@ $< 9: 10: clean: 11: rm -rf *~ *.o *.map 12: 13: .PHONY: clean
whoareyouアプリケーションのMakefileです。
リスト4.9: apps/whoareyou/whoareyou.c
1: #include <app.h>
2: #include <kernel.h>
3: #include <string.h>
4: #include <console.h>
5:
6: int main(int argc, char *argv[])
7: {
8: if ((argc >= 2) && !str_compare(argv[1], "-v"))
9: put_str("Operating System 5\r\n");
10: else
11: put_str("OS5\r\n");
12: exit();
13:
14: return 0;
15: }
「お前は誰だ」と問いかけるアプリケーションです。「OS5」と返してくれます。UNIXで実行したユーザーのユーザー名を表示する"whoami"コマンドのオマージュ(パロディ?)です。
これはコマンドライン引数の動作確認として用意したアプリケーションで、"-v"オプションをつけると「Operating System 5」と詳細に返してくれます。
リスト4.10: apps/libkernel/Makefile
1: NAME=libkernel 2: 3: $(LIB_DIR)/$(NAME).a: $(NAME).o 4: ar rcs $@ $< 5: 6: %.o: %.c 7: gcc $(CFLAGS) -o $@ $< 8: 9: clean: 10: rm -rf *~ *.o *.a *.map 11: 12: .PHONY: clean
カーネル回りのライブラリ"libkernel"のMakefileです。内容はNAME=libkernelの行を除いて他のライブラリのMakefileと同じです。
リスト4.11: apps/include/kernel.h
1: #ifndef _APP_KERNEL_H_ 2: #define _APP_KERNEL_H_ 3: 4: #include "../../kernel/include/kernel.h" 5: #include "../../kernel/include/io_port.h" 6: #include "../../kernel/include/console_io.h" 7: 8: unsigned int syscall(unsigned int syscall_id, unsigned int arg1, 9: unsigned int arg2, unsigned int arg3); 10: unsigned int get_global_counter(void); 11: void exit(void); 12: 13: #endif /* _APP_KERNEL_H_ */
libkernelのヘッダファイルです。カーネルとアプリケーションの間のインタフェースはシステムコールのみです。libkernelではシステムコールを関数として提供します。
リスト4.12: apps/libkernel/libkernel.c
1: #include <kernel.h>
2:
3: unsigned int syscall(unsigned int syscall_id, unsigned int arg1,
4: unsigned int arg2, unsigned int arg3)
5: {
6: unsigned int result;
7:
8: __asm__ (
9: "\tint $0x80\n"
10: :"=a"(result)
11: :"a"(syscall_id), "b"(arg1), "c"(arg2), "d"(arg3));
12:
13: return result;
14: }
15:
16: unsigned int get_global_counter(void)
17: {
18: return syscall(SYSCALL_TIMER_GET_GLOBAL_COUNTER, 0, 0, 0);
19: }
20:
21: void exit(void)
22: {
23: syscall(SYSCALL_EXIT, 0, 0, 0);
24: }
libkernelの本体です。システムコールを発行するsyscall関数を定義しています。また、get_global_counterとexitは、syscallをラップしています。
リスト4.13: apps/libcommon/Makefile
1: NAME=libcommon 2: 3: $(LIB_DIR)/$(NAME).a: $(NAME).o 4: ar rcs $@ $< 5: 6: %.o: %.c 7: gcc $(CFLAGS) -o $@ $< 8: 9: clean: 10: rm -rf *~ *.o *.a *.map 11: 12: .PHONY: clean
共通で使用される関数をまとめるライブラリ"libcommon"のMakefileです。
リスト4.14: apps/include/common.h
1: #ifndef _COMMON_H_ 2: #define _COMMON_H_ 3: 4: int pow(int num, int multer); 5: void copy_mem(const void *src, void *dst, unsigned int size); 6: 7: #endif /* _COMMON_H_ */
libcommonのヘッダファイルです。べき乗計算を行うpow関数とデータのコピーを行うcopy_mem関数があります。
リスト4.15: apps/libcommon/libcommon.c
1: #include <common.h>
2:
3: int pow(int num, int multer)
4: {
5: if (multer == 0) return 1;
6: return pow(num, multer - 1) * num;
7: }
8:
9: void copy_mem(const void *src, void *dst, unsigned int size)
10: {
11: unsigned char *d = (unsigned char *)dst;
12: unsigned char *s = (unsigned char *)src;
13:
14: for (; size > 0; size--) {
15: *d = *s;
16: d++;
17: s++;
18: }
19: }
libcommonの本体です。
リスト4.16: apps/libconsole/Makefile
1: NAME=libconsole 2: 3: $(LIB_DIR)/$(NAME).a: $(NAME).o 4: ar rcs $@ $< 5: 6: %.o: %.c 7: gcc $(CFLAGS) -o $@ $< 8: 9: clean: 10: rm -rf *~ *.o *.a *.map 11: 12: .PHONY: clean
コンソールに関するライブラリlibconsoleのMakefileです。
リスト4.17: apps/include/console.h
1: #ifndef _CONSOLE_H_ 2: #define _CONSOLE_H_ 3: 4: unsigned int get_cursor_pos_y(void); 5: void put_str(char *str); 6: void put_str_pos(char *str, unsigned char x, unsigned char y); 7: void dump_hex(unsigned int val, unsigned int num_digits); 8: void dump_hex_pos(unsigned int val, unsigned int num_digits, 9: unsigned char x, unsigned char y); 10: unsigned int get_line(char *buf, unsigned int buf_size); 11: 12: #endif /* _CONSOLE_H_ */
libconsoleのヘッダファイルです。以下の関数を提供しています。
put_str: カーソル位置へ文字列出力put_str_pos: 指定座標へ文字列出力dump_hex: カーソル位置へ16進で数値出力dump_hex_pos: 指定座標へ16進で数値出力get_line: 1行分の入力文字列取得get_cursor_pos_y: カーソル位置のY座標取得リスト4.18: apps/libconsole/libconsole.c
1: #include <console.h>
2: #include <kernel.h>
3:
4: unsigned int get_cursor_pos_y(void)
5: {
6: return syscall(SYSCALL_CON_GET_CURSOR_POS_Y, 0, 0, 0);
7: }
8:
9: void put_str(char *str)
10: {
11: syscall(SYSCALL_CON_PUT_STR, (unsigned int)str, 0, 0);
12: }
13:
14: void put_str_pos(char *str, unsigned char x, unsigned char y)
15: {
16: syscall(SYSCALL_CON_PUT_STR_POS, (unsigned int)str,
17: (unsigned int)x, (unsigned int)y);
18: }
19:
20: void dump_hex(unsigned int val, unsigned int num_digits)
21: {
22: syscall(SYSCALL_CON_DUMP_HEX, val, num_digits, 0);
23: }
24:
25: void dump_hex_pos(unsigned int val, unsigned int num_digits,
26: unsigned char x, unsigned char y)
27: {
28: syscall(SYSCALL_CON_DUMP_HEX_POS, val, num_digits,
29: (unsigned int)((x << 16) | y));
30: }
31:
32: unsigned int get_line(char *buf, unsigned int buf_size)
33: {
34: return syscall(SYSCALL_CON_GET_LINE, (unsigned int)buf, buf_size, 0);
35: }
libconsoleの本体です。いずれの関数もシステムコールをラップしたものです。
リスト4.19: apps/libstring/Makefile
1: NAME=libstring 2: 3: $(LIB_DIR)/$(NAME).a: $(NAME).o 4: ar rcs $@ $< 5: 6: %.o: %.c 7: gcc $(CFLAGS) -o $@ $< 8: 9: clean: 10: rm -rf *~ *.o *.a *.map 11: 12: .PHONY: clean
文字列操作ライブラリlibstringのMakefileです。
リスト4.20: apps/include/string.h
1: #ifndef _STRING_H_ 2: #define _STRING_H_ 3: 4: int str_get_len(const char *src); 5: int str_find_char(const char *src, char key); 6: void str_get_first_entry(const char *line, char *first, char *other); 7: int str_conv_ahex_int(const char *hex_str); 8: int str_compare(const char *src, const char *dst); 9: 10: #endif /* _STRING_H_ */
libstringのヘッダファイルです。以下の関数を提供しています。
str_get_len: 文字列の長さを取得str_find_char: 文字列中の文字のインデックスを返すstr_get_first_entry: 半角スペース区切りの最初のエントリを取得str_conv_ahex_int: 16進数文字列をintへ変換str_compare: 文字列比較リスト4.21: apps/libstring/libstring.c
1: #include <string.h>
2: #include <common.h>
3:
4: int str_get_len(const char *src)
5: {
6: int len;
7: for (len = 0; src[len] != '\0'; len++);
8: return len + 1;
9: }
10:
11: int str_find_char(const char *src, char key)
12: {
13: int i;
14:
15: for (i = 0; src[i] != key; i++) {
16: if (src[i] == '\0') {
17: i = -1;
18: break;
19: }
20: }
21:
22: return i;
23: }
24:
25: void str_get_first_entry(const char *line, char *first, char *other)
26: {
27: int line_len, first_len, other_len;
28:
29: line_len = str_get_len(line);
30: first_len = str_find_char(line, ' ');
31: if (first_len < 0) {
32: copy_mem((void *)line, (void *)first, line_len);
33: first_len = line_len;
34: other_len = 0;
35: other[other_len] = '\0';
36: } else {
37: copy_mem((void *)line, (void *)first, first_len);
38: first[first_len] = '\0';
39: first_len++;
40: other_len = line_len - first_len;
41: copy_mem((void *)(line + first_len), (void *)other, other_len);
42: }
43:
44: #ifdef DEBUG
45: shell_put_str(line);
46: shell_put_str("|");
47: shell_put_str(first);
48: shell_put_str(":");
49: shell_put_str(other);
50: shell_put_str("\r\n");
51: #endif /* DEBUG */
52: }
53:
54: int str_conv_ahex_int(const char *hex_str)
55: {
56: int len = str_get_len(hex_str);
57: int val = 0, i;
58:
59: for (i = 0; hex_str[i] != '\0'; i++) {
60: if (('0' <= hex_str[i]) && (hex_str[i] <= '9')) {
61: val += (hex_str[i] - '0') * pow(16, len - 2 - i);
62: } else {
63: val += (hex_str[i] - 'a' + 10) * pow(16, len - 2 - i);
64: }
65: }
66:
67: return val;
68: }
69:
70: int str_compare(const char *src, const char *dst)
71: {
72: char is_equal = 1;
73:
74: for (; (*src != '\0') && (*dst != '\0'); src++, dst++) {
75: if (*src != *dst) {
76: is_equal = 0;
77: break;
78: }
79: }
80:
81: if (is_equal) {
82: if (*src != '\0') {
83: return 1;
84: } else if (*dst != '\0') {
85: return -1;
86: } else {
87: return 0;
88: }
89: } else {
90: return (int)(*src - *dst);
91: }
92: }
libstringの本体です。特に変わったことはしていないです。