myio.c

最終更新:2009/11/9

myio.c

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: }
Copyright (C) KAKU PROJECT (2009)KAKU PROJECT (2009)