13 char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
19 iolayer.c - encapsulates different source of data into a single framework.
23 io_glue *ig = io_new_fd( fileno(stdin) );
24 method = io_reqmeth( IOL_NOSEEK | IOL_MMAP ); // not implemented yet
25 io_glue_commit_types(ig); // always assume IOL_SEEK for now
28 code that uses ig->readcb()
29 to read data goes here.
32 code that uses ig->readcb()
33 to read data goes here.
42 iolayer.c implements the basic functions to create and destroy io_glue
43 objects for Imager. The typical usage pattern for data sources is:
45 1. Create the source (io_new_fd)
46 2. Define how you want to get data from it (io_reqmeth)
47 3. read from it using the interface requested (ig->readdb, ig->mmapcb)
48 4. Close the source, which
49 shouldn't really close the underlying source. (io_glue DESTROY)
51 =head1 FUNCTION REFERENCE
53 Some of these functions are internal.
60 static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
61 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
62 static off_t fd_seek(io_glue *ig, off_t offset, int whence);
63 static void fd_close(io_glue *ig);
64 static ssize_t fd_size(io_glue *ig);
67 * Callbacks for sources that cannot seek
70 /* fakeseek_read: read method for when emulating a seekable source
73 fakeseek_read(io_glue *ig, void *buf, size_t count) {
74 io_ex_fseek *exdata = ig->exdata;
82 * Callbacks for sources that can seek
86 =item realseek_read(ig, buf, count)
88 Does the reading from a source that can be seeked on
91 buf - buffer to return data in
92 count - number of bytes to read into buffer max
99 realseek_read(io_glue *ig, void *buf, size_t count) {
100 io_ex_rseek *ier = ig->exdata;
101 void *p = ig->source.cb.p;
106 IOL_DEB( printf("realseek_read: fd = %d, ier->cpos = %ld, buf = %p, "
107 "count = %d\n", fd, (long) ier->cpos, buf, count) );
108 /* Is this a good idea? Would it be better to handle differently?
110 while( count!=bc && (rc = ig->source.cb.readcb(p,cbuf+bc,count-bc))>0 ) {
115 IOL_DEB( printf("realseek_read: rc = %d, bc = %d\n", rc, bc) );
121 =item realseek_write(ig, buf, count)
123 Does the writing to a 'source' that can be seeked on
126 buf - buffer that contains data
127 count - number of bytes to write
134 realseek_write(io_glue *ig, const void *buf, size_t count) {
135 io_ex_rseek *ier = ig->exdata;
136 void *p = ig->source.cb.p;
139 char *cbuf = (char*)buf;
141 IOL_DEB( printf("realseek_write: ig = %p, ier->cpos = %ld, buf = %p, "
142 "count = %d\n", ig, (long) ier->cpos, buf, count) );
144 /* Is this a good idea? Would it be better to handle differently?
146 while( count!=bc && (rc = ig->source.cb.writecb(p,cbuf+bc,count-bc))>0 ) {
151 IOL_DEB( printf("realseek_write: rc = %d, bc = %d\n", rc, bc) );
157 =item realseek_close(ig)
159 Closes a source that can be seeked on. Not sure if this should be an
160 actual close or not. Does nothing for now. Should be fixed.
168 realseek_close(io_glue *ig) {
169 mm_log((1, "realseek_close(ig %p)\n", ig));
170 if (ig->source.cb.closecb)
171 ig->source.cb.closecb(ig->source.cb.p);
175 /* realseek_seek(ig, offset, whence)
177 Implements seeking for a source that is seekable, the purpose of having this is to be able to
178 have an offset into a file that is different from what the underlying library thinks.
181 offset - offset into stream
182 whence - whence argument a la lseek
189 realseek_seek(io_glue *ig, off_t offset, int whence) {
190 /* io_ex_rseek *ier = ig->exdata; Needed later */
191 void *p = ig->source.cb.p;
193 IOL_DEB( printf("realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
194 rc = ig->source.cb.seekcb(p, offset, whence);
196 IOL_DEB( printf("realseek_seek: rc %ld\n", (long) rc) );
198 /* FIXME: How about implementing this offset handling stuff? */
202 * Callbacks for sources that are a fixed size buffer
206 =item buffer_read(ig, buf, count)
208 Does the reading from a buffer source
211 buf - buffer to return data in
212 count - number of bytes to read into buffer max
219 buffer_read(io_glue *ig, void *buf, size_t count) {
220 io_ex_buffer *ieb = ig->exdata;
222 IOL_DEB( printf("buffer_read: fd = %d, ier->cpos = %ld, buf = %p, count = %d\n", fd, (long) ier->cpos, buf, count) );
224 if ( ieb->cpos+count > ig->source.buffer.len ) {
225 mm_log((1,"buffer_read: short read: cpos=%d, len=%d, count=%d\n", ieb->cpos, ig->source.buffer.len));
226 count = ig->source.buffer.len - ieb->cpos;
229 memcpy(buf, ig->source.buffer.data+ieb->cpos, count);
231 IOL_DEB( printf("buffer_read: rc = %d, count = %d\n", rc, count) );
237 =item buffer_write(ig, buf, count)
239 Does nothing, returns -1
242 buf - buffer that contains data
243 count - number of bytes to write
250 buffer_write(io_glue *ig, const void *buf, size_t count) {
251 mm_log((1, "buffer_write called, this method should never be called.\n"));
257 =item buffer_close(ig)
259 Closes a source that can be seeked on. Not sure if this should be an actual close
260 or not. Does nothing for now. Should be fixed.
269 buffer_close(io_glue *ig) {
270 mm_log((1, "buffer_close(ig %p)\n", ig));
271 /* FIXME: Do stuff here */
275 /* buffer_seek(ig, offset, whence)
277 Implements seeking for a buffer source.
280 offset - offset into stream
281 whence - whence argument a la lseek
288 buffer_seek(io_glue *ig, off_t offset, int whence) {
289 io_ex_buffer *ieb = ig->exdata;
290 off_t reqpos = offset
291 + (whence == SEEK_CUR)*ieb->cpos
292 + (whence == SEEK_END)*ig->source.buffer.len;
294 if (reqpos > ig->source.buffer.len) {
295 mm_log((1, "seeking out of readable range\n"));
300 IOL_DEB( printf("buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
303 /* FIXME: How about implementing this offset handling stuff? */
311 * Callbacks for sources that are a chain of variable sized buffers
316 /* Helper functions for buffer chains */
323 mm_log((1, "io_blink_new()\n"));
325 ib = mymalloc(sizeof(io_blink));
331 memset(&ib->buf, 0, ib->len);
338 =item io_bchain_advance(ieb)
340 Advances the buffer chain to the next link - extending if
341 necessary. Also adjusts the cpos and tfill counters as needed.
343 ieb - buffer chain object
350 io_bchain_advance(io_ex_bchain *ieb) {
351 if (ieb->cp->next == NULL) {
352 ieb->tail = io_blink_new();
353 ieb->tail->prev = ieb->cp;
354 ieb->cp->next = ieb->tail;
356 ieb->tfill = 0; /* Only set this if we added a new slice */
358 ieb->cp = ieb->cp->next;
365 =item io_bchain_destroy()
367 frees all resources used by a buffer chain.
373 io_destroy_bufchain(io_ex_bchain *ieb) {
375 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
379 io_blink *t = cp->next;
392 bufchain_dump(io_ex_bchain *ieb) {
393 mm_log((1, " buf_chain_dump(ieb %p)\n"));
394 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
395 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
396 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
397 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
398 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
399 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
400 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
401 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
406 * TRUE if lengths are NOT equal
412 chainlencert( io_glue *ig ) {
417 io_ex_bchain *ieb = ig->exdata;
418 io_blink *cp = ieb->head;
421 if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
424 clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
425 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
426 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
428 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
429 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
431 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
432 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
439 if (!cfl) cpos += clen;
444 if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
445 if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos ));
451 chaincert( io_glue *ig) {
453 io_ex_bchain *ieb = ig->exdata;
454 io_blink *cp = ieb->head;
456 mm_log((1, "Chain verification.\n"));
458 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
459 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
460 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
461 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
462 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
463 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
464 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
465 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
468 int clen = cp == ieb->tail ? ieb->tfill : cp->len;
469 mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
470 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
471 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
473 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
474 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
476 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
477 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
483 mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
498 =item bufchain_read(ig, buf, count)
500 Does the reading from a source that can be seeked on
503 buf - buffer to return data in
504 count - number of bytes to read into buffer max
511 bufchain_read(io_glue *ig, void *buf, size_t count) {
512 io_ex_bchain *ieb = ig->exdata;
513 size_t scount = count;
517 mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, count));
520 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
521 if (clen == ieb->cpos) {
522 if (ieb->cp == ieb->tail) break; /* EOF */
523 ieb->cp = ieb->cp->next;
525 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
528 sk = clen - ieb->cpos;
529 sk = sk > scount ? scount : sk;
531 memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
537 mm_log((1, "bufchain_read: returning %d\n", count-scount));
546 =item bufchain_write(ig, buf, count)
548 Does the writing to a 'source' that can be seeked on
551 buf - buffer that contains data
552 count - number of bytes to write
559 bufchain_write(io_glue *ig, const void *buf, size_t count) {
560 char *cbuf = (char *)buf;
561 io_ex_bchain *ieb = ig->exdata;
562 size_t ocount = count;
565 mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %d\n", ig, buf, count));
567 IOL_DEB( printf("bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %d\n", ig, (long) ieb->cpos, buf, count) );
570 mm_log((2, "bufchain_write: - looping - count = %d\n", count));
571 if (ieb->cp->len == ieb->cpos) {
572 mm_log((1, "bufchain_write: cp->len == ieb->cpos = %d - advancing chain\n", (long) ieb->cpos));
573 io_bchain_advance(ieb);
576 sk = ieb->cp->len - ieb->cpos;
577 sk = sk > count ? count : sk;
578 memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
580 if (ieb->cp == ieb->tail) {
581 int extend = ieb->cpos + sk - ieb->tfill;
582 mm_log((2, "bufchain_write: extending tail by %d\n", extend));
584 ieb->length += extend;
585 ieb->tfill += extend;
597 =item bufchain_close(ig)
599 Closes a source that can be seeked on. Not sure if this should be an actual close
600 or not. Does nothing for now. Should be fixed.
609 bufchain_close(io_glue *ig) {
610 mm_log((1, "bufchain_close(ig %p)\n",ig));
611 IOL_DEB( printf("bufchain_close(ig %p)\n", ig) );
612 /* FIXME: Commit a seek point here */
617 /* bufchain_seek(ig, offset, whence)
619 Implements seeking for a source that is seekable, the purpose of having this is to be able to
620 have an offset into a file that is different from what the underlying library thinks.
623 offset - offset into stream
624 whence - whence argument a la lseek
631 bufchain_seek(io_glue *ig, off_t offset, int whence) {
632 io_ex_bchain *ieb = ig->exdata;
637 off_t scount = offset;
640 mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, offset, whence));
643 case SEEK_SET: /* SEEK_SET = 0, From the top */
649 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
650 if (clen == ieb->cpos) {
651 if (ieb->cp == ieb->tail) break; /* EOF */
652 ieb->cp = ieb->cp->next;
654 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
657 sk = clen - ieb->cpos;
658 sk = sk > scount ? scount : sk;
669 * extending file - get ieb into consistent state and then
670 * call write which will get it to the correct position
673 memset(TB, 0, BBSIZ);
674 ieb->gpos = ieb->length;
675 ieb->cpos = ieb->tfill;
678 ssize_t rc, wl = i_min(wrlen, BBSIZ);
679 mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl));
680 rc = bufchain_write( ig, TB, wl );
681 if (rc != wl) m_fatal(0, "bufchain_seek: Unable to extend file\n");
689 m_fatal(123, "SEEK_CUR IS NOT IMPLEMENTED\n");
697 while(cof < 0 && ib->prev) {
703 case SEEK_END: /* SEEK_END = 2 */
704 if (cof>0) m_fatal(0, "bufchain_seek: SEEK_END + %d : Extending files via seek not supported!\n", cof);
707 ieb->cpos = ieb->tfill;
713 while(cof<0 && ib->prev) {
718 if (cof<0) m_fatal(0, "bufchain_seek: Tried to seek before start of file\n");
719 ieb->gpos = ieb->length+offset;
724 m_fatal(0, "bufchain_seek: Unhandled seek request: whence = %d\n", whence );
727 mm_log((2, "bufchain_seek: returning ieb->gpos = %d\n", ieb->gpos));
737 * Methods for setting up data source
741 =item io_obj_setp_buffer(io, p, len)
743 Sets an io_object for reading from a buffer source
745 io - io object that describes a source
746 p - pointer to buffer
747 len - length of buffer
753 io_obj_setp_buffer(io_obj *io, char *p, size_t len, closebufp closecb, void *closedata) {
754 io->buffer.type = BUFFER;
756 io->buffer.len = len;
757 io->buffer.closecb = closecb;
758 io->buffer.closedata = closedata;
763 =item io_obj_setp_buchain(io)
765 Sets an io_object for reading/writing from a buffer source
767 io - io object that describes a source
768 p - pointer to buffer
769 len - length of buffer
775 io_obj_setp_bufchain(io_obj *io) {
781 =item io_obj_setp_cb2(io, p, readcb, writecb, seekcb, closecb, destroycb)
783 Sets an io_object for reading from a source that uses callbacks
785 io - io object that describes a source
786 p - pointer to data for callbacks
787 readcb - read callback to read from source
788 writecb - write callback to write to source
789 seekcb - seek callback to seek on source
790 closecb - flush any pending data
791 destroycb - release any extra resources
797 io_obj_setp_cb2(io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb, closel closecb, destroyl destroycb) {
798 io->cb.type = CBSEEK;
800 io->cb.readcb = readcb;
801 io->cb.writecb = writecb;
802 io->cb.seekcb = seekcb;
803 io->cb.closecb = closecb;
804 io->cb.destroycb = destroycb;
808 io_obj_setp_cb(io_obj *io, void *p, readl readcb, writel writecb,
810 io_obj_setp_cb2(io, p, readcb, writecb, seekcb, NULL, NULL);
814 =item io_glue_commit_types(ig)
816 Creates buffers and initializes structures to read with the chosen interface.
824 io_glue_commit_types(io_glue *ig) {
825 io_type inn = ig->source.type;
827 mm_log((1, "io_glue_commit_types(ig %p)\n", ig));
828 mm_log((1, "io_glue_commit_types: source type %d (%s)\n", inn, io_type_names[inn]));
830 if (ig->flags & 0x01) {
831 mm_log((1, "io_glue_commit_types: type already set up\n"));
838 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
846 ieb->head = io_blink_new();
848 ieb->tail = ieb->head;
851 ig->readcb = bufchain_read;
852 ig->writecb = bufchain_write;
853 ig->seekcb = bufchain_seek;
854 ig->closecb = bufchain_close;
859 io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
865 ig->readcb = realseek_read;
866 ig->writecb = realseek_write;
867 ig->seekcb = realseek_seek;
868 ig->closecb = realseek_close;
873 io_ex_buffer *ieb = mymalloc(sizeof(io_ex_buffer));
878 ig->readcb = buffer_read;
879 ig->writecb = buffer_write;
880 ig->seekcb = buffer_seek;
881 ig->closecb = buffer_close;
887 ig->readcb = fd_read;
888 ig->writecb = fd_write;
889 ig->seekcb = fd_seek;
890 ig->closecb = fd_close;
894 ig->flags |= 0x01; /* indicate source has been setup already */
898 =item io_glue_gettypes(ig, reqmeth)
900 Returns a set of compatible interfaces to read data with.
903 reqmeth - request mask
905 The request mask is a bit mask (of something that hasn't been implemented yet)
906 of interfaces that it would like to read data from the source which the ig
913 io_glue_gettypes(io_glue *ig, int reqmeth) {
918 /* FIXME: Implement this function! */
919 /* if (ig->source.type =
920 if (reqmeth & IO_BUFF) */
926 =item io_new_bufchain()
928 returns a new io_glue object that has the 'empty' source and but can
929 be written to and read from later (like a pseudo file).
937 mm_log((1, "io_new_bufchain()\n"));
938 ig = mymalloc(sizeof(io_glue));
939 memset(ig, 0, sizeof(*ig));
940 io_obj_setp_bufchain(&ig->source);
949 =item io_new_buffer(data, len)
951 Returns a new io_glue object that has the source defined as reading
952 from specified buffer. Note that the buffer is not copied.
954 data - buffer to read from
955 len - length of buffer
961 io_new_buffer(char *data, size_t len, closebufp closecb, void *closedata) {
963 mm_log((1, "io_new_buffer(data %p, len %d, closecb %p, closedata %p)\n", data, len, closecb, closedata));
964 ig = mymalloc(sizeof(io_glue));
965 memset(ig, 0, sizeof(*ig));
966 io_obj_setp_buffer(&ig->source, data, len, closecb, closedata);
975 returns a new io_glue object that has the source defined as reading
976 from specified filedescriptor. Note that the the interface to recieving
977 data from the io_glue callbacks hasn't been done yet.
979 fd - file descriptor to read/write from
987 mm_log((1, "io_new_fd(fd %d)\n", fd));
988 ig = mymalloc(sizeof(io_glue));
989 memset(ig, 0, sizeof(*ig));
990 ig->source.type = FDSEEK;
991 ig->source.fdseek.fd = fd;
995 io_obj_setp_cb(&ig->source, (void*)fd, _read, _write, _lseek);
997 io_obj_setp_cb(&ig->source, (void*)fd, read, write, lseek);
1000 mm_log((1, "(%p) <- io_new_fd\n", ig));
1004 io_glue *io_new_cb(void *p, readl readcb, writel writecb, seekl seekcb,
1005 closel closecb, destroyl destroycb) {
1008 mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
1009 "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
1010 ig = mymalloc(sizeof(io_glue));
1011 memset(ig, 0, sizeof(*ig));
1012 io_obj_setp_cb2(&ig->source, p, readcb, writecb, seekcb, closecb, destroycb);
1013 mm_log((1, "(%p) <- io_new_cb\n", ig));
1021 Takes the source that the io_glue is bound to and allocates space
1022 for a return buffer and returns the entire content in a single buffer.
1023 Note: This only works for io_glue objects that contain a bufchain. It
1024 is usefull for saving to scalars and such.
1027 c - pointer to a pointer to where data should be copied to
1033 io_slurp(io_glue *ig, unsigned char **c) {
1038 io_type inn = ig->source.type;
1040 if ( inn != BUFCHAIN ) {
1041 m_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
1045 cc = *c = mymalloc( ieb->length );
1049 bufchain_seek(ig, 0, SEEK_SET);
1051 rc = bufchain_read(ig, cc, ieb->length);
1053 if (rc != ieb->length)
1054 m_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
1060 =item fd_read(ig, buf, count)
1064 static ssize_t fd_read(io_glue *ig, void *buf, size_t count) {
1066 return _read(ig->source.fdseek.fd, buf, count);
1068 return read(ig->source.fdseek.fd, buf, count);
1072 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count) {
1074 return _write(ig->source.fdseek.fd, buf, count);
1076 return write(ig->source.fdseek.fd, buf, count);
1080 static off_t fd_seek(io_glue *ig, off_t offset, int whence) {
1082 return _lseek(ig->source.fdseek.fd, offset, whence);
1084 return lseek(ig->source.fdseek.fd, offset, whence);
1088 static void fd_close(io_glue *ig) {
1089 /* no, we don't close it */
1092 static ssize_t fd_size(io_glue *ig) {
1093 mm_log((1, "fd_size(ig %p) unimplemented\n", ig));
1099 =item io_glue_DESTROY(ig)
1101 A destructor method for io_glue objects. Should clean up all related buffers.
1102 Might leave us with a dangling pointer issue on some buffers.
1104 ig - io_glue object to destroy.
1110 io_glue_DESTROY(io_glue *ig) {
1111 io_type inn = ig->source.type;
1112 mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
1117 io_ex_bchain *ieb = ig->exdata;
1118 io_destroy_bufchain(ieb);
1124 io_ex_rseek *ier = ig->exdata;
1125 if (ig->source.cb.destroycb)
1126 ig->source.cb.destroycb(ig->source.cb.p);
1132 io_ex_buffer *ieb = ig->exdata;
1133 if (ig->source.buffer.closecb) {
1134 mm_log((1,"calling close callback %p for io_buffer\n", ig->source.buffer.closecb));
1135 ig->source.buffer.closecb(ig->source.buffer.closedata);
1152 Arnar M. Hrafnkelsson <addi@umich.edu>