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) |