myio.c
最終更新:2009/11/9
001: /*
002: * ストリームの抽象化の試み
003: * ・特別なライブラリに頼らない
004: * ・malloc/free などを使わない。外部のコールバック関数で対処
005: * ・
006: */
007:
008: #include "myio.h"
009:
010: /*
011: * ユーティリティ関数
012: */
013:
014: /*
015: * 文字列の長さを返す関数
016: */
017:
018: int mystrlen (const char *str) {
019: const char *p = str;
020: if (!p) {
021: return 0;
022: }
023: for (; *p; p++);
024: return p-str;
025: }
026:
027: /* 二つの文字列が等しいか検査する関数
028: * 返り値:
029: * 1:等しい、0:等しくない
030: */
031:
032: int mystreq (const char*x, const char*y) {
033: const char *p = x;
034: const char *q = y;
035: if (!x || !y)
036: return 0;
037:
038: while (*p && *q) {
039: if (*(p++) != *(q++))
040: return 0;
041: }
042: if (!*p && !*q) {
043: return 1;
044: }
045: return 0;
046: }
047:
048: /*
049: * 入力ストリームの時1を返す。
050: */
051:
052: int MYIO_is_input(
053: MYIO *x
054: ) {
055: if (x) {
056: return x->flag_in;
057: }
058: return 0;
059: }
060:
061: /*
062: * 出力ストリームの時1を返す。
063: */
064:
065: int MYIO_is_output(
066: MYIO *x
067: ) {
068: if (x) {
069: return x->flag_out;
070: }
071: return 0;
072: }
073:
074: /*
075: * ストリームのコンテクストデータを返す
076: */
077: void * MYIO_get_ptr (
078: MYIO *x
079: ) {
080: if (x) {
081: return x->ptr;
082: }
083: return (void*)0;
084: }
085:
086: /*
087: * ストリームハンドラの生成
088: */
089:
090: MYIO *MYIO_make(
091: MYIO *myio /* ストリームのポインタ */
092: , MYIO_METHOD *method /* 使用するメソッド構造体のポインタ */
093: , int flag_in /* 入力フラグ */
094: , int flag_out /* 出力フラグ */
095: , void *ptr /* メソッドで使用するコンテクストデータ */
096: ) {
097: if (!myio || !method) {
098: return myio;
099: }
100: myio->method = method;
101: myio->flag_in = flag_in;
102: myio->flag_out = flag_out;
103: myio->ptr = ptr;
104:
105: return myio;
106: }
107:
108: /*
109: * size バイト分のデータを読み出す関数。
110: * 返り値は buf に読み出したバイト数。
111: * 入力ストリームが空の時も何もしない。0が返る。
112: * エラー時には -1 が返る。
113: */
114:
115: int MYIO_read(
116: MYIO *in
117: , char *buf
118: , int size
119: ) {
120: if (!in || !buf || size<=0) {
121: return -1;
122: }
123: if (! in->flag_in) {
124: return -1; /* 入力ストリームではない */
125: }
126: if (! in->method) {
127: return -1; /* メソッドの構造体がない */
128: }
129: if (! in->method->read) {
130: return -1; /* read メソッドがない */
131: }
132: return in->method->read(in, buf, size);
133: }
134:
135: /*
136: * buf に格納された size バイト分のデータを書き込む関数。
137: * 返り値は書き出したバイト数。
138: * size<=0 の時は何もしない。0が返る。
139: * エラー時には -1 が返る。
140: */
141:
142: int MYIO_write(
143: MYIO *out
144: , const char *buf
145: , int size
146: ) {
147: if (!out || !buf || size<0) {
148: return -1;
149: }
150: if (size == 0) {
151: return 0;
152: }
153: if (! out->flag_out) {
154: return -1; /* 出力ストリームではない */
155: }
156: if (! out->method) {
157: return -1;
158: }
159: if (! out->method->write) {
160: return -1;
161: }
162:
163: return out->method->write(out, buf, size);
164: }
165:
166: /*
167: * 文字列 str (ヌル文字で終端されたデータ)を書き込む関数。
168: * 返り値は書き出した文字列の長さ。
169: * str の長さが 0 の時は何もしない。0が返る。
170: * エラー時には -1 が返る。
171: */
172:
173: int MYIO_puts(
174: MYIO *out
175: , const char *str
176: ) {
177: int len = 0;
178: if (!out || !str) {
179: return -1;
180: }
181: len = mystrlen(str);
182: if (len == 0) {
183: return 0;
184: }
185: if (! out->flag_out) {
186: return -1; /* 出力ストリームではない */
187: }
188: if (! out->method) {
189: return -1;
190: }
191: if (out->method->puts) {
192: return out->method->puts(out, str);
193: }
194: if (out->method->write) {
195: int o=0;
196: while (o<len) {
197: int write_bytes = out->method->write(out, str+o, len-o);
198: if (write_bytes < 0) {
199: return -1;
200: }
201: o += write_bytes;
202: }
203: return o;
204: }
205:
206: return -1;
207: }
208:
209: /*
210: * size-1 バイトまでの文字列をストリームから読み出し、buf に保存する。
211: * EOF または LF を読み込んだところで停止する。
212: * LF または CRLF は '\0' に書き換えられる。
213: * 返り値は最後のヌル文字を含まない読み出した文字列の長さ。
214: * size==0 の時は何もしない。0が返る。
215: * エラー時には -1 が返る。
216: */
217: int MYIO_gets(
218: MYIO *in
219: , char *buf
220: , int size
221: ) {
222: if (!in || !buf || size<0) {
223: return -1;
224: }
225: if (size == 0) {
226: return 0;
227: }
228: if (! in->flag_in) {
229: return -1; /* 入力ストリームではない */
230: }
231: if (! in->method) {
232: return -1;
233: }
234: if (in->method->gets) {
235: return in->method->gets(in, buf, size);
236: }
237: if (in->method->read) { /* バッファリングなしでは効率悪い */
238: int len = 0;
239: for (len=0; len < size; len++) {
240: char b[1];
241: int nbytes = in->method->read(in, b, 1);
242: if (nbytes == 0) {
243: break;
244: }
245: if (nbytes < 0 ) {
246: return -1;
247: }
248: if (b[0] == MYIO_CHAR_LF) { /* ...LF */
249: buf[len] = '\0';
250: if (len>0 && buf[len-1] == MYIO_CHAR_CR) { /* ...CRLF の時 */
251: buf[len-1] = '\0';
252: len--;
253: }
254: break;
255: }
256:
257: buf[len] = b[0];
258: }
259: if (len >= size) {
260: return -1; /* size-1 以上 */
261: }
262: return len;
263: }
264:
265: return -1;
266: }
267:
268: /*
269: * ストリーム間で size バイト分のデータを移す。
270: * 返り値は実際に移したバイト数。
271: * size<=0 の時は何もしない。0が返る。
272: * 入力ストリームが空の時も何もしない。0が返る。
273: * 終了後は出力ストリームの後尾に size バイト分増えている。
274: */
275:
276: int MYIO_move (
277: MYIO *in /* IN: 入力ストリーム */
278: , int size /* IN: 読み出すバイト数 */
279: , MYIO *out /* OUT: 出力ストリーム */
280: ) {
281: int length = 0;
282: int remain = size;
283:
284: if (!in || size <=0 || !out) {
285: return 0;
286: }
287:
288: if (! in->method || ! in->method->read ||
289: ! out->method || ! out->method->write) {
290: return -1; /* 実装がない */
291: }
292:
293: if (! in->flag_in || ! out->flag_out) {
294: return -1; /* ストリームの入出力属性がマッチしていない */
295: }
296:
297: while (remain > 0) {
298: char buf[MYIO_BUF_SIZE];
299: int nbytes = MYIO_BUF_SIZE;
300: if (nbytes > remain) {
301: nbytes = remain;
302: }
303:
304: nbytes = in->method->read(in, buf, nbytes);
305: if (nbytes == 0) {
306: break;
307: }
308: if (nbytes < 0) {
309: return -1;
310: }
311:
312: {
313: int o=0;
314: while (o<nbytes) {
315: o += out->method->write(out, buf+o, nbytes-o);
316: }
317: }
318:
319: remain -= nbytes;
320: length += nbytes;
321: }
322:
323: return length;
324: }
325:
326: /*
327: * バッファリングフィルタ(入力フィルタ)
328: */
329:
330: typedef struct myio_buf_ctx_st {
331: MYIO *in;
332:
333: /* バッファに保持しているデータサイズ */
334: int size;
335:
336: /* バッファ中の現在の位置 */
337: int pos;
338:
339: /* バッファのサイズ */
340: int buf_size;
341:
342: /* バッファ */
343: char *buf;
344:
345: } myio_buf_ctx;
346:
347:
348: int myio_buf_read (
349: MYIO *in
350: , char * buf
351: , int size
352: ) {
353: int read_size = 0;
354: myio_buf_ctx *ctx = (myio_buf_ctx*)(in->ptr);
355:
356: #ifdef DEBUG
357: puts("#myio_buf_read(1)");
358: #endif
359:
360: if (!ctx) {
361: return -1;
362: }
363:
364: if (!ctx->in) {
365: return -1;
366: }
367:
368: /* バッファが空か、すでに読み出し済みの時。
369: * 最初に呼ばれる時: ctx->pos==0 ctx->size==0
370: * 読み出し済みの時: ctx->pos >= ctx->size
371: */
372: if (ctx->pos >= ctx->size) {
373: #ifdef DEBUG
374: if(0)puts("#myio_buf_read(2)");
375: #endif
376:
377: /* チャンクをバッファのサイズの範囲内で読み出し */
378: ctx->pos = 0;
379: ctx->size = MYIO_read(ctx->in, ctx->buf, ctx->buf_size);
380:
381: if (ctx->size <= 0) {
382: #ifdef DEBUG
383: if(0)puts("#myio_buf_read(3)");
384: #endif
385: return ctx->size;
386: }
387:
388: #ifdef DEBUG
389: if(0)puts("#myio_buf_read(4)");
390: #endif
391: }
392:
393: while (ctx->pos < ctx->size) {
394: if (read_size >= size) {
395: break;
396: }
397: buf[read_size++] = ctx->buf[ctx->pos++];
398: }
399:
400: #ifdef DEBUG
401: if(0)puts("#myio_buf_read(5)");
402: #endif
403: return read_size;
404: }
405:
406: #define MYIO_METHOD_NAME_BUF_FILTER "_BUFFERING_FILTER_"
407:
408: MYIO_METHOD myio_buf_method = {
409: MYIO_METHOD_NAME_BUF_FILTER
410: , (void*)0
411: , myio_buf_read
412: , (void*)0
413: , (void*)0
414: };
415:
416: /*
417: * バッファリングフィルタ
418: * alloc_func はメモリアロケーションの関数
419: * void * alloc_func(void *alloc_func_ctx, int alloc_size)
420: */
421:
422: MYIO *MYIO_buf_filter_new (
423: MYIO *in
424: , int buf_size
425: , void *alloc_func
426: , void *alloc_func_ctx
427: ) {
428: MYIO *myio;
429: myio_buf_ctx *ctx;
430: void * (*alloc_f)(void*,int) = alloc_func;
431:
432: if (alloc_f == (void*)0) {
433: return (void*)0;
434: }
435:
436: if (buf_size <= 0) {
437: return (void*)0;
438: }
439:
440: ctx = (myio_buf_ctx *)alloc_f(alloc_func_ctx, sizeof(myio_buf_ctx));
441:
442: ctx->in = in;
443: ctx->size = 0;
444: ctx->pos = 0;
445: ctx->buf_size = buf_size;
446: ctx->buf = (char*)alloc_f(alloc_func_ctx, ctx->buf_size);
447:
448: myio = (MYIO*)alloc_f(alloc_func_ctx, sizeof(MYIO));
449:
450: return MYIO_make(myio, &myio_buf_method, 1, 0, ctx);
451: }
452:
453: MYIO *MYIO_buf_get_MYIO (
454: MYIO *myio
455: ) {
456:
457: if (!myio) {
458: return (void*)0;
459: }
460:
461: if (myio->ptr) {
462: if (myio->method) {
463: if (mystreq(myio->method->name, MYIO_METHOD_NAME_BUF_FILTER)) {
464: myio_buf_ctx *ctx = myio->ptr;
465: return ctx->in;
466: }
467: }
468: }
469: return (void*)0;
470: }
471:
472: /* バッファリングフィルタの解放
473: * ・フィルタ対象ストリームの解放は行わない。
474: * ・free_func は領域の解放を行う関数。void free_func(free_func_ctx, data);
475: */
476:
477: void MYIO_buf_free(
478: MYIO *myio
479: , void *free_func
480: , void *free_func_ctx
481: ) {
482: void (*free_f)(void*,void*) = free_func;
483:
484: if (!myio || !free_func) {
485: return;
486: }
487:
488: if (myio->ptr) {
489: if (myio->method) {
490: if (mystreq(myio->method->name, MYIO_METHOD_NAME_BUF_FILTER)) {
491: myio_buf_ctx *ctx = myio->ptr;
492: free_f(free_func_ctx, ctx->buf);
493: free_f(free_func_ctx, myio->ptr);
494: free_f(free_func_ctx, myio);
495: }
496: }
497: }
498: }
![]() | KAKU PROJECT (2009) |