added some more POD
[imager.git] / iolayer.c
CommitLineData
02d1d628
AMH
1#include "io.h"
2#include "iolayer.h"
3#include "log.h"
4#include <stdlib.h>
5#include <stdio.h>
6#ifdef _MSC_VER
7#include <io.h>
8#endif
9
10#define IOL_DEB(x)
11
12
13char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
14
15
16/*
17=head1 NAME
18
19iolayer.c - encapsulates different source of data into a single framework.
20
21=head1 SYNOPSIS
22
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
26 switch (method) {
27 case IOL_NOSEEK:
28 code that uses ig->readcb()
29 to read data goes here.
30 break;
31 case IOL_MMAP:
32 code that uses ig->readcb()
33 to read data goes here.
34 break;
35 }
36
37 io_glue_DESTROY(ig);
38 // and much more
39
40=head1 DESCRIPTION
41
42iolayer.c implements the basic functions to create and destroy io_glue
43objects for Imager. The typical usage pattern for data sources is:
44
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)
50
51=head1 FUNCTION REFERENCE
52
53Some of these functions are internal.
54
55=over 4
56
57=cut
58*/
59
60
61
62
63/*
64 * Callbacks for sources that cannot seek
65 */
66
67/* fakeseek_read: read method for when emulating a seekable source
68static
69ssize_t
70fakeseek_read(io_glue *ig, void *buf, size_t count) {
71 io_ex_fseek *exdata = ig->exdata;
72 return 0;
73}
74*/
75
76
77
78/*
79 * Callbacks for sources that can seek
80 */
81
82/*
83=item realseek_read(ig, buf, count)
84
85Does the reading from a source that can be seeked on
86
87 ig - io_glue object
88 buf - buffer to return data in
89 count - number of bytes to read into buffer max
90
91=cut
92*/
93
94static
95ssize_t
96realseek_read(io_glue *ig, void *buf, size_t count) {
97 io_ex_rseek *ier = ig->exdata;
98 int fd = (int)ig->source.cb.p;
99 ssize_t rc = 0;
100 size_t bc = 0;
101 char *cbuf = buf;
102
930c67c8 103 IOL_DEB( printf("realseek_read: fd = %d, ier->cpos = %ld, buf = %p, count = %d\n", fd, (long) ier->cpos, buf, count) );
02d1d628
AMH
104 /* Is this a good idea? Would it be better to handle differently? skip handling? */
105 while( count!=bc && (rc = ig->source.cb.readcb(fd,cbuf+bc,count-bc))>0 ) bc+=rc;
106
107 ier->cpos += bc;
108 IOL_DEB( printf("realseek_read: rc = %d, bc = %d\n", rc, bc) );
109 return bc;
110}
111
112
113/*
114=item realseek_write(ig, buf, count)
115
116Does the writing to a 'source' that can be seeked on
117
118 ig - io_glue object
119 buf - buffer that contains data
120 count - number of bytes to write
121
122=cut
123*/
124
125static
126ssize_t
127realseek_write(io_glue *ig, const void *buf, size_t count) {
128 io_ex_rseek *ier = ig->exdata;
129 int fd = (int)ig->source.cb.p;
130 ssize_t rc = 0;
131 size_t bc = 0;
132 char *cbuf = (char*)buf;
133
930c67c8 134 IOL_DEB( printf("realseek_write: fd = %d, ier->cpos = %ld, buf = %p, count = %d\n", fd, (long) ier->cpos, buf, count) );
02d1d628
AMH
135 /* Is this a good idea? Would it be better to handle differently? skip handling? */
136
137 while( count!=bc && (rc = ig->source.cb.writecb(fd,cbuf+bc,count-bc))>0 ) bc+=rc;
138
139 ier->cpos += bc;
140 IOL_DEB( printf("realseek_write: rc = %d, bc = %d\n", rc, bc) );
141 return bc;
142}
143
144
145/*
146=item realseek_close(ig)
147
148Closes a source that can be seeked on. Not sure if this should be an actual close
149or not. Does nothing for now. Should be fixed.
150
151 ig - data source
152
153=cut
154*/
155
156static
157void
158realseek_close(io_glue *ig) {
159 mm_log((1, "realseek_close(ig %p)\n", ig));
160 /* FIXME: Do stuff here */
161}
162
163
164/* realseek_seek(ig, offset, whence)
165
166Implements seeking for a source that is seekable, the purpose of having this is to be able to
167have an offset into a file that is different from what the underlying library thinks.
168
169 ig - data source
170 offset - offset into stream
171 whence - whence argument a la lseek
172
173=cut
174*/
175
176static
177off_t
178realseek_seek(io_glue *ig, off_t offset, int whence) {
179 /* io_ex_rseek *ier = ig->exdata; Needed later */
180 int fd = (int)ig->source.cb.p;
181 int rc;
930c67c8 182 IOL_DEB( printf("realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
02d1d628
AMH
183 rc = lseek(fd, offset, whence);
184
185 IOL_DEB( printf("realseek_seek: rc %ld\n", (long) rc) );
186 return rc;
187 /* FIXME: How about implementing this offset handling stuff? */
188}
189
190
191
192
193
194
195
196/*
197 * Callbacks for sources that are a chain of variable sized buffers
198 */
199
200
201
202/* Helper functions for buffer chains */
203
204static
205io_blink*
faa9b3e7 206io_blink_new(void) {
02d1d628
AMH
207 io_blink *ib;
208
209 mm_log((1, "io_blink_new()\n"));
210
211 ib = mymalloc(sizeof(io_blink));
212
213 ib->next = NULL;
214 ib->prev = NULL;
215 ib->len = BBSIZ;
216
217 memset(&ib->buf, 0, ib->len);
218 return ib;
219}
220
221
222
223/*
224=item io_bchain_advance(ieb)
225
226Advances the buffer chain to the next link - extending if
227necessary. Also adjusts the cpos and tfill counters as needed.
228
229 ieb - buffer chain object
230
231=cut
232*/
233
234static
235void
236io_bchain_advance(io_ex_bchain *ieb) {
237 if (ieb->cp->next == NULL) {
238 ieb->tail = io_blink_new();
239 ieb->tail->prev = ieb->cp;
240 ieb->cp->next = ieb->tail;
241
242 ieb->tfill = 0; /* Only set this if we added a new slice */
243 }
244 ieb->cp = ieb->cp->next;
245 ieb->cpos = 0;
246}
247
248
c3cc977e
AMH
249
250/*
251=item io_bchain_destroy()
252
253frees all resources used by a buffer chain.
254
255=cut
256*/
257
258void
259io_destroy_bufchain(io_ex_bchain *ieb) {
260 io_blink *cp = ieb->head;
261 while(cp) {
262 io_blink *t = cp->next;
263 free(cp);
264 cp = t;
265 }
266}
267
268
269
270
02d1d628
AMH
271/*
272
273static
274void
275bufchain_dump(io_ex_bchain *ieb) {
276 mm_log((1, " buf_chain_dump(ieb %p)\n"));
277 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
278 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
279 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
280 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
281 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
282 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
283 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
284 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
285}
286*/
287
288/*
289 * TRUE if lengths are NOT equal
290 */
291
292/*
293static
294void
295chainlencert( io_glue *ig ) {
296 int clen;
297 int cfl = 0;
298 size_t csize = 0;
299 size_t cpos = 0;
300 io_ex_bchain *ieb = ig->exdata;
301 io_blink *cp = ieb->head;
302
303
304 if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
305
306 while(cp) {
307 clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
308 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
309 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
310
311 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
312 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
313
314 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
315 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
316
317 if (cp == ieb->cp) {
318 cfl = 1;
319 cpos += ieb->cpos;
320 }
321
322 if (!cfl) cpos += clen;
323
324 csize += clen;
325 cp = cp->next;
326 }
327 if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
328 if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos ));
329}
330
331
332static
333void
334chaincert( io_glue *ig) {
335 size_t csize = 0;
336 io_ex_bchain *ieb = ig->exdata;
337 io_blink *cp = ieb->head;
338
339 mm_log((1, "Chain verification.\n"));
340
341 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
342 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
343 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
344 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
345 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
346 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
347 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
348 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
349
350 while(cp) {
351 int clen = cp == ieb->tail ? ieb->tfill : cp->len;
352 mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
353 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
354 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
355
356 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
357 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
358
359 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
360 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
361
362 csize += clen;
363 cp = cp->next;
364 }
365
366 mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
367}
368*/
369
370
371
372
373
374
375
376
377
378
379
380/*
381=item bufchain_read(ig, buf, count)
382
383Does the reading from a source that can be seeked on
384
385 ig - io_glue object
386 buf - buffer to return data in
387 count - number of bytes to read into buffer max
388
389=cut
390*/
391
392static
393ssize_t
394bufchain_read(io_glue *ig, void *buf, size_t count) {
395 io_ex_bchain *ieb = ig->exdata;
396 size_t scount = count;
397 char *cbuf = buf;
398 size_t sk;
399
400 mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, count));
02d1d628
AMH
401
402 while( scount ) {
403 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
404 if (clen == ieb->cpos) {
405 if (ieb->cp == ieb->tail) break; /* EOF */
406 ieb->cp = ieb->cp->next;
407 ieb->cpos = 0;
408 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
409 }
410
411 sk = clen - ieb->cpos;
412 sk = sk > scount ? scount : sk;
413
414 memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
415 scount -= sk;
416 ieb->cpos += sk;
417 ieb->gpos += sk;
418 }
419
420 mm_log((1, "bufchain_read: returning %d\n", count-scount));
421 return count-scount;
422}
423
424
425
426
427
428/*
429=item bufchain_write(ig, buf, count)
430
431Does the writing to a 'source' that can be seeked on
432
433 ig - io_glue object
434 buf - buffer that contains data
435 count - number of bytes to write
436
437=cut
438*/
439
440static
441ssize_t
442bufchain_write(io_glue *ig, const void *buf, size_t count) {
443 char *cbuf = (char *)buf;
444 io_ex_bchain *ieb = ig->exdata;
445 size_t ocount = count;
446 size_t sk;
447
930c67c8 448 mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %d\n", ig, buf, count));
02d1d628 449
930c67c8 450 IOL_DEB( printf("bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %d\n", ig, (long) ieb->cpos, buf, count) );
02d1d628
AMH
451
452 while(count) {
453 mm_log((2, "bufchain_write: - looping - count = %d\n", count));
454 if (ieb->cp->len == ieb->cpos) {
455 mm_log((1, "bufchain_write: cp->len == ieb->cpos = %d - advancing chain\n", (long) ieb->cpos));
456 io_bchain_advance(ieb);
457 }
458
459 sk = ieb->cp->len - ieb->cpos;
460 sk = sk > count ? count : sk;
461 memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
462
463 if (ieb->cp == ieb->tail) {
464 int extend = ieb->cpos + sk - ieb->tfill;
465 mm_log((2, "bufchain_write: extending tail by %d\n", extend));
466 if (extend > 0) {
467 ieb->length += extend;
468 ieb->tfill += extend;
469 }
470 }
471
472 ieb->cpos += sk;
473 ieb->gpos += sk;
474 count -= sk;
475 }
476 return ocount;
477}
478
479/*
480=item bufchain_close(ig)
481
482Closes a source that can be seeked on. Not sure if this should be an actual close
483or not. Does nothing for now. Should be fixed.
484
485 ig - data source
486
487=cut
488*/
489
490static
491void
492bufchain_close(io_glue *ig) {
493 mm_log((1, "bufchain_close(ig %p)\n",ig));
930c67c8 494 IOL_DEB( printf("bufchain_close(ig %p)\n", ig) );
02d1d628
AMH
495 /* FIXME: Commit a seek point here */
496
497}
498
499
500/* bufchain_seek(ig, offset, whence)
501
502Implements seeking for a source that is seekable, the purpose of having this is to be able to
503have an offset into a file that is different from what the underlying library thinks.
504
505 ig - data source
506 offset - offset into stream
507 whence - whence argument a la lseek
508
509=cut
510*/
511
512static
513off_t
514bufchain_seek(io_glue *ig, off_t offset, int whence) {
515 io_ex_bchain *ieb = ig->exdata;
516 io_blink *ib = NULL;
517 int wrlen;
518
519 off_t cof = 0;
520 off_t scount = offset;
521 off_t sk;
522
523 mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, offset, whence));
524
525 switch (whence) {
526 case SEEK_SET: /* SEEK_SET = 0, From the top */
527 ieb->cp = ieb->head;
528 ieb->cpos = 0;
529 ieb->gpos = 0;
530
531 while( scount ) {
532 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
533 if (clen == ieb->cpos) {
534 if (ieb->cp == ieb->tail) break; /* EOF */
535 ieb->cp = ieb->cp->next;
536 ieb->cpos = 0;
537 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
538 }
539
540 sk = clen - ieb->cpos;
541 sk = sk > scount ? scount : sk;
542
543 scount -= sk;
544 ieb->cpos += sk;
545 ieb->gpos += sk;
546 }
547
548 wrlen = scount;
549
550 if (wrlen > 0) {
551 /*
552 * extending file - get ieb into consistent state and then
553 * call write which will get it to the correct position
554 */
555 char TB[BBSIZ];
556 memset(TB, 0, BBSIZ);
557 ieb->gpos = ieb->length;
558 ieb->cpos = ieb->tfill;
559
560 while(wrlen > 0) {
561 ssize_t rc, wl = min(wrlen, BBSIZ);
562 mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl));
563 rc = bufchain_write( ig, TB, wl );
564 if (rc != wl) m_fatal(0, "bufchain_seek: Unable to extend file\n");
565 wrlen -= rc;
566 }
567 }
568
569 break;
570
571 case SEEK_CUR:
572 m_fatal(123, "SEEK_CUR IS NOT IMPLEMENTED\n");
573
574 /*
575 case SEEK_CUR:
576 ib = ieb->cp;
577 if (cof < 0) {
578 cof += ib->cpos;
579 cpos = 0;
580 while(cof < 0 && ib->prev) {
581 ib = ib->prev;
582 cof += ib->len;
583 }
584 */
585
586 case SEEK_END: /* SEEK_END = 2 */
587 if (cof>0) m_fatal(0, "bufchain_seek: SEEK_END + %d : Extending files via seek not supported!\n", cof);
588
589 ieb->cp = ieb->tail;
590 ieb->cpos = ieb->tfill;
591
592 if (cof<0) {
593 cof += ieb->cpos;
594 ieb->cpos = 0;
595
596 while(cof<0 && ib->prev) {
597 ib = ib->prev;
598 cof += ib->len;
599 }
600
601 if (cof<0) m_fatal(0, "bufchain_seek: Tried to seek before start of file\n");
602 ieb->gpos = ieb->length+offset;
603 ieb->cpos = cof;
604 }
605 break;
606 default:
607 m_fatal(0, "bufchain_seek: Unhandled seek request: whence = %d\n", whence );
608 }
609
610 mm_log((2, "bufchain_seek: returning ieb->gpos = %d\n", ieb->gpos));
611 return ieb->gpos;
612}
613
614
615
616
617
618
619/*
620 * Methods for setting up data source
621 */
622
623/*
624=item io_obj_setp_buffer(io, p, len)
625
626Sets an io_object for reading from a buffer source
627
628 io - io object that describes a source
629 p - pointer to buffer
630 len - length of buffer
631
632=cut
633*/
634
635void
636io_obj_setp_buffer(io_obj *io, void *p, size_t len) {
637 io->buffer.type = BUFFER;
638 io->buffer.c = (char*) p;
639 io->buffer.len = len;
640}
641
642
643/*
644=item io_obj_setp_cbuf(io, p)
645
646Sets an io_object for reading/writing from a buffer source
647
648 io - io object that describes a source
649 p - pointer to buffer
650 len - length of buffer
651
652=cut
653*/
654
655void
656io_obj_setp_bufchain(io_obj *io) {
657 io->type = BUFCHAIN;
658}
659
660
661/*
662=item io_obj_setp_cb(io, p, readcb, writecb, seekcb)
663
664Sets an io_object for reading from a source that uses callbacks
665
666 io - io object that describes a source
667 p - pointer to data for callbacks
668 readcb - read callback to read from source
669 writecb - write callback to write to source
670 seekcb - seek callback to seek on source
671
672=cut
673*/
674
675void
676io_obj_setp_cb(io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb) {
677 io->cb.type = CBSEEK;
678 io->cb.p = p;
679 io->cb.readcb = readcb;
680 io->cb.writecb = writecb;
681 io->cb.seekcb = seekcb;
682}
683
684/*
685=item io_glue_commit_types(ig)
686
687Creates buffers and initializes structures to read with the chosen interface.
688
689 ig - io_glue object
690
691=cut
692*/
693
694void
695io_glue_commit_types(io_glue *ig) {
696 io_type inn = ig->source.type;
697
930c67c8 698 mm_log((1, "io_glue_commit_types(ig %p)\n", ig));
02d1d628
AMH
699 mm_log((1, "io_glue_commit_types: source type %d (%s)\n", inn, io_type_names[inn]));
700
701 switch (inn) {
702 case BUFCHAIN:
703 {
704 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
705
706 ieb->offset = 0;
707 ieb->length = 0;
708 ieb->cpos = 0;
709 ieb->gpos = 0;
710 ieb->tfill = 0;
c3cc977e 711
02d1d628
AMH
712 ieb->head = io_blink_new();
713 ieb->cp = ieb->head;
714 ieb->tail = ieb->head;
715
716 ig->exdata = ieb;
717 ig->readcb = bufchain_read;
718 ig->writecb = bufchain_write;
719 ig->seekcb = bufchain_seek;
720 ig->closecb = bufchain_close;
721 }
722 break;
723 case CBSEEK:
724 default:
725 {
726 io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
727
728 ier->offset = 0;
729 ier->cpos = 0;
730
731 ig->exdata = ier;
732 ig->readcb = realseek_read;
733 ig->writecb = realseek_write;
734 ig->seekcb = realseek_seek;
735 ig->closecb = realseek_close;
736 }
737 }
738}
739
740/*
741=item io_glue_gettypes(ig, reqmeth)
742
743Returns a set of compatible interfaces to read data with.
744
745 ig - io_glue object
746 reqmeth - request mask
747
748The request mask is a bit mask (of something that hasn't been implemented yet)
749of interfaces that it would like to read data from the source which the ig
750describes.
751
752=cut
753*/
754
755void
756io_glue_gettypes(io_glue *ig, int reqmeth) {
757
758 ig = NULL;
759 reqmeth = 0;
760
761 /* FIXME: Implement this function! */
762 /* if (ig->source.type =
763 if (reqmeth & IO_BUFF) */
764
765}
766
767
768/*
769=item io_new_bufchain()
770
771returns a new io_glue object that has the 'empty' source and but can
772be written to and read from later (like a pseudo file).
773
774=cut
775*/
776
777io_glue *
778io_new_bufchain() {
779 io_glue *ig = mymalloc(sizeof(io_glue));
780 io_obj_setp_bufchain(&ig->source);
781 return ig;
782}
783
784
c3cc977e
AMH
785
786
787
788
789
790
02d1d628
AMH
791/*
792=item io_new_fd(fd)
793
794returns a new io_glue object that has the source defined as reading
795from specified filedescriptor. Note that the the interface to recieving
796data from the io_glue callbacks hasn't been done yet.
797
798 fd - file descriptor to read/write from
799
800=cut
801*/
802
803io_glue *
804io_new_fd(int fd) {
805 io_glue *ig = mymalloc(sizeof(io_glue));
261f91c5 806 memset(ig, 0, sizeof(*ig));
02d1d628
AMH
807#ifdef _MSC_VER
808 io_obj_setp_cb(&ig->source, (void*)fd, _read, _write, _lseek);
809#else
810 io_obj_setp_cb(&ig->source, (void*)fd, read, write, lseek);
811#endif
812 return ig;
813}
814
815
816
817/*
818=item io_slurp(ig)
819
820Takes the source that the io_glue is bound to and allocates space
821for a return buffer and returns the entire content in a single buffer.
822Note: This only works for io_glue objects that contain a bufchain. It
823is usefull for saving to scalars and such.
824
825 ig - io_glue object
826 c - pointer to a pointer to where data should be copied to
827
828=cut
829*/
830
831size_t
832io_slurp(io_glue *ig, unsigned char **c) {
833 ssize_t rc;
834 off_t orgoff;
835 io_ex_bchain *ieb;
836 unsigned char *cc;
837 io_type inn = ig->source.type;
838
839 if ( inn != BUFCHAIN ) {
840 m_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
841 }
842
843 ieb = ig->exdata;
844 cc = *c = mymalloc( ieb->length );
845
846 orgoff = ieb->gpos;
847
848 bufchain_seek(ig, 0, SEEK_SET);
849
850 rc = bufchain_read(ig, cc, ieb->length);
851
852 if (rc != ieb->length)
853 m_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
854
855 return rc;
856}
857
858
859/*
860=item io_glue_DESTROY(ig)
861
862A destructor method for io_glue objects. Should clean up all related buffers.
863Might leave us with a dangling pointer issue on some buffers.
864
865 ig - io_glue object to destroy.
866
867=cut
868*/
869
870void
871io_glue_DESTROY(io_glue *ig) {
c3cc977e
AMH
872 io_type inn = ig->source.type;
873 mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
874
875 switch (inn) {
876 case BUFCHAIN:
877 {
878 io_ex_bchain *ieb = ig->exdata;
879 io_destroy_bufchain(ieb);
880 }
881 break;
882 case CBSEEK:
883 default:
884 {
885 io_ex_rseek *ier = ig->exdata;
886 myfree(ier);
887 }
888
889 }
890 myfree(ig);
02d1d628 891}