]> git.imager.perl.org - imager.git/blob - iolayer.c
some Changes updates
[imager.git] / iolayer.c
1 #define IMAGER_NO_CONTEXT
2 #include "imager.h"
3 #include "iolayer.h"
4 #include "imerror.h"
5 #include "log.h"
6 #include <stdlib.h>
7 #include <stdio.h>
8 #ifdef _MSC_VER
9 #include <io.h>
10 #endif
11 #include <string.h>
12 #include <errno.h>
13 #include "imageri.h"
14
15 #define IOL_DEB(x)
16 #define IOL_DEBs stderr
17
18 #define IO_BUF_SIZE 8192
19
20 char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
21
22 typedef struct io_blink {
23   char buf[BBSIZ];
24   /* size_t cnt; */
25   size_t len;                   /* How large is this buffer = BBZIS for now */
26   struct io_blink *next;
27   struct io_blink *prev;
28 } io_blink;
29
30
31 typedef struct {
32   i_io_glue_t   base;
33   int           fd;
34 } io_fdseek;
35
36 typedef struct {
37   i_io_glue_t   base;
38   const char    *data;
39   size_t        len;
40   i_io_closebufp_t     closecb;        /* free memory mapped segment or decrement refcount */
41   void          *closedata;
42   off_t cpos;
43 } io_buffer;
44
45 typedef struct {
46   i_io_glue_t   base;
47   void          *p;             /* Callback data */
48   i_io_readl_t  readcb;
49   i_io_writel_t writecb;
50   i_io_seekl_t  seekcb;
51   i_io_closel_t closecb;
52   i_io_destroyl_t      destroycb;
53 } io_cb;
54
55 typedef struct {
56   off_t offset;                 /* Offset of the source - not used */
57   off_t length;                 /* Total length of chain in bytes */
58   io_blink *head;               /* Start of chain */
59   io_blink *tail;               /* End of chain */
60   off_t tfill;                  /* End of stream in last link */
61   io_blink *cp;                 /* Current element of list */
62   off_t cpos;                   /* Offset within the current */
63   off_t gpos;                   /* Global position in stream */
64 } io_ex_bchain;
65
66 /* turn current offset, file length, whence and offset into a new offset */
67 #define calc_seek_offset(curr_off, length, offset, whence) \
68   (((whence) == SEEK_SET) ? (offset) : \
69    ((whence) == SEEK_CUR) ? (curr_off) + (offset) : \
70    ((whence) == SEEK_END) ? (length) + (offset) : -1)
71
72 /*
73 =head1 NAME
74
75 iolayer.c - encapsulates different source of data into a single framework.
76
77 =head1 SYNOPSIS
78
79   io_glue *ig = io_new_fd( fileno(stdin) );
80   method = io_reqmeth( IOL_NOSEEK | IOL_MMAP ); // not implemented yet
81
82   switch (method) {
83   case IOL_NOSEEK:
84     code that uses ig->readcb()
85     to read data goes here.
86     break;
87   case IOL_MMAP:
88     code that uses ig->readcb()
89     to read data goes here.
90     break;
91   }  
92
93   io_glue_destroy(ig);
94   // and much more
95
96 =head1 DESCRIPTION
97
98 iolayer.c implements the basic functions to create and destroy io_glue
99 objects for Imager.  The typical usage pattern for data sources is:
100
101    1. Create the source (io_new_fd)
102    2. Define how you want to get data from it (io_reqmeth)
103    3. read from it using the interface requested (ig->readdb, ig->mmapcb)
104    4. Close the source, which 
105       shouldn't really close the underlying source. (io_glue DESTROY)
106
107 =head1 FUNCTION REFERENCE
108
109 Some of these functions are internal.
110
111 =over
112
113 =cut
114 */
115
116 static void
117 i_io_init(pIMCTX, io_glue *ig, int type, i_io_readp_t readcb,
118           i_io_writep_t writecb, i_io_seekp_t seekcb);
119
120 static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
121 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
122 static off_t fd_seek(io_glue *ig, off_t offset, int whence);
123 static int fd_close(io_glue *ig);
124 static ssize_t fd_size(io_glue *ig);
125 static const char *my_strerror(int err);
126 static void i_io_setup_buffer(io_glue *ig);
127 static void
128 i_io_start_write(io_glue *ig);
129 static int
130 i_io_read_fill(io_glue *ig, ssize_t needed);
131 static void
132 dump_data(unsigned char *start, unsigned char *end, int bias);
133 static ssize_t realseek_read(io_glue *igo, void *buf, size_t count);
134 static ssize_t realseek_write(io_glue *igo, const void *buf, size_t count);
135 static int realseek_close(io_glue *igo);
136 static off_t realseek_seek(io_glue *igo, off_t offset, int whence);
137 static void realseek_destroy(io_glue *igo);
138 static ssize_t buffer_read(io_glue *igo, void *buf, size_t count);
139 static ssize_t buffer_write(io_glue *ig, const void *buf, size_t count);
140 static int buffer_close(io_glue *ig);
141 static off_t buffer_seek(io_glue *igo, off_t offset, int whence);
142 static void buffer_destroy(io_glue *igo);
143 static io_blink*io_blink_new(void);
144 static void io_bchain_advance(io_ex_bchain *ieb);
145 static void io_destroy_bufchain(io_ex_bchain *ieb);
146 static ssize_t bufchain_read(io_glue *ig, void *buf, size_t count);
147 static ssize_t bufchain_write(io_glue *ig, const void *buf, size_t count);
148 static int bufchain_close(io_glue *ig);
149 static off_t bufchain_seek(io_glue *ig, off_t offset, int whence);
150 static void bufchain_destroy(io_glue *ig);
151
152 /*
153  * Methods for setting up data source
154  */
155
156 /*
157 =item im_io_new_bufchain(ctx)
158 X<im_io_new_bufchain API>X<i_io_new_bufchain API>
159 =order 10
160 =category I/O Layers
161
162 Returns a new io_glue object that has the 'empty' source and but can
163 be written to and read from later (like a pseudo file).
164
165 Also callable as C<io_new_bufchain()>.
166
167 =cut
168 */
169
170 io_glue *
171 im_io_new_bufchain(pIMCTX) {
172   io_glue *ig;
173   io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
174
175   im_log((aIMCTX, 1, "io_new_bufchain()\n"));
176
177   ig = mymalloc(sizeof(io_glue));
178   memset(ig, 0, sizeof(*ig));
179   i_io_init(aIMCTX, ig, BUFCHAIN, bufchain_read, bufchain_write, bufchain_seek);
180
181   ieb->offset = 0;
182   ieb->length = 0;
183   ieb->cpos   = 0;
184   ieb->gpos   = 0;
185   ieb->tfill  = 0;
186   
187   ieb->head   = io_blink_new();
188   ieb->cp     = ieb->head;
189   ieb->tail   = ieb->head;
190   
191   ig->exdata    = ieb;
192   ig->closecb   = bufchain_close;
193   ig->destroycb = bufchain_destroy;
194
195   im_context_refinc(aIMCTX, "im_io_new_bufchain");
196
197   return ig;
198 }
199
200 /*
201 =item im_io_new_buffer(ctx, data, length)
202 X<im_io_new_buffer API>X<io_new_buffer API>
203 =order 10
204 =category I/O Layers
205
206 Returns a new io_glue object that has the source defined as reading
207 from specified buffer.  Note that the buffer is not copied.
208
209    ctx - an Imager context object
210    data - buffer to read from
211    length - length of buffer
212
213 Also callable as C<io_new_buffer(data, length>.
214
215 =cut
216 */
217
218 io_glue *
219 im_io_new_buffer(pIMCTX, const char *data, size_t len, i_io_closebufp_t closecb, void *closedata) {
220   io_buffer *ig;
221   
222   im_log((aIMCTX, 1, "io_new_buffer(data %p, len %ld, closecb %p, closedata %p)\n", data, (long)len, closecb, closedata));
223
224   ig = mymalloc(sizeof(io_buffer));
225   memset(ig, 0, sizeof(*ig));
226   i_io_init(aIMCTX, &ig->base, BUFFER, buffer_read, buffer_write, buffer_seek);
227   ig->data      = data;
228   ig->len       = len;
229   ig->closecb   = closecb;
230   ig->closedata = closedata;
231
232   ig->cpos   = 0;
233   
234   ig->base.closecb   = buffer_close;
235   ig->base.destroycb = buffer_destroy;
236
237   im_context_refinc(aIMCTX, "im_io_new_bufchain");
238
239   return (io_glue *)ig;
240 }
241
242
243 /*
244 =item im_io_new_fd(ctx, file)
245 X<io_new_fd API>X<im_io_new_fd API>
246 =order 10
247 =category I/O Layers
248
249 Returns a new io_glue object that has the source defined as reading
250 from specified file descriptor.  Note that the the interface to receiving
251 data from the io_glue callbacks hasn't been done yet.
252
253   ctx - and Imager context object
254   file - file descriptor to read/write from
255
256 Also callable as C<io_new_fd(file)>.
257
258 =cut
259 */
260
261 io_glue *
262 im_io_new_fd(pIMCTX, int fd) {
263   io_fdseek *ig;
264
265   im_log((aIMCTX, 1, "io_new_fd(fd %d)\n", fd));
266
267   ig = mymalloc(sizeof(io_fdseek));
268   memset(ig, 0, sizeof(*ig));
269   i_io_init(aIMCTX, &ig->base, FDSEEK, fd_read, fd_write, fd_seek);
270   ig->fd = fd;
271
272   ig->base.closecb   = fd_close;
273   ig->base.sizecb    = fd_size;
274   ig->base.destroycb = NULL;
275   im_context_refinc(aIMCTX, "im_io_new_bufchain");
276
277   im_log((aIMCTX, 1, "(%p) <- io_new_fd\n", ig));
278   return (io_glue *)ig;
279 }
280
281 /*
282 =item im_io_new_cb(ctx, p, read_cb, write_cb, seek_cb, close_cb, destroy_cb)
283 X<im_io_new_cb API>X<io_new_cb API>
284 =category I/O Layers
285 =order 10
286
287 Create a new I/O layer object that calls your supplied callbacks.
288
289 In general the callbacks should behave like the corresponding POSIX
290 primitives.
291
292 =over
293
294 =item *
295
296 C<read_cb>(p, buffer, length) should read up to C<length> bytes into
297 C<buffer> and return the number of bytes read.  At end of file, return
298 0.  On error, return -1.
299
300 =item *
301
302 C<write_cb>(p, buffer, length) should write up to C<length> bytes from
303 C<buffer> and return the number of bytes written.  A return value <= 0
304 will be treated as an error.
305
306 =item *
307
308 C<seekcb>(p, offset, whence) should seek and return the new offset.
309
310 =item *
311
312 C<close_cb>(p) should return 0 on success, -1 on failure.
313
314 =item *
315
316 C<destroy_cb>(p) should release any memory specific to your callback
317 handlers.
318
319 =back
320
321 Also callable as C<io_new_cb(p, readcb, writecb, seekcb, closecb,
322 destroycb)>.
323
324 =cut
325 */
326
327 io_glue *
328 im_io_new_cb(pIMCTX, void *p, i_io_readl_t readcb, i_io_writel_t writecb, 
329           i_io_seekl_t seekcb, i_io_closel_t closecb, 
330           i_io_destroyl_t destroycb) {
331   io_cb *ig;
332
333   im_log((aIMCTX, 1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
334           "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
335   ig = mymalloc(sizeof(io_cb));
336   memset(ig, 0, sizeof(*ig));
337   i_io_init(aIMCTX, &ig->base, CBSEEK, realseek_read, realseek_write, realseek_seek);
338   im_log((aIMCTX, 1, "(%p) <- io_new_cb\n", ig));
339
340   ig->base.closecb   = realseek_close;
341   ig->base.destroycb = realseek_destroy;
342
343   ig->p         = p;
344   ig->readcb    = readcb;
345   ig->writecb   = writecb;
346   ig->seekcb    = seekcb;
347   ig->closecb   = closecb;
348   ig->destroycb = destroycb;
349   
350   im_context_refinc(aIMCTX, "im_io_new_bufchain");
351
352   return (io_glue *)ig;
353 }
354
355 /*
356 =item io_slurp(ig, c)
357 X<io_slurp API>
358 =category I/O Layers
359
360 Takes the source that the io_glue is bound to and allocates space for
361 a return buffer and returns the entire content in a single buffer.
362 Note: This only works for io_glue objects created by
363 io_new_bufchain().  It is useful for saving to scalars and such.
364
365    ig - io_glue object
366    c  - pointer to a pointer to where data should be copied to
367
368   char *data;
369   size_t size = io_slurp(ig, &data);
370   ... do something with the data ...
371   myfree(data);
372
373 io_slurp() will abort the program if the supplied I/O layer is not
374 from io_new_bufchain().
375
376 =cut
377 */
378
379 size_t
380 io_slurp(io_glue *ig, unsigned char **c) {
381   ssize_t rc;
382   off_t orgoff;
383   io_ex_bchain *ieb;
384   unsigned char *cc;
385   io_type inn = ig->type;
386   
387   if ( inn != BUFCHAIN ) {
388     dIMCTXio(ig);
389     im_fatal(aIMCTX, 0, "io_slurp: called on a source that is not from a bufchain\n");
390   }
391
392   ieb = ig->exdata;
393   cc = *c = mymalloc( ieb->length );
394   
395   orgoff = ieb->gpos;
396   
397   bufchain_seek(ig, 0, SEEK_SET);
398   
399   rc = bufchain_read(ig, cc, ieb->length);
400
401   if (rc != ieb->length) {
402     dIMCTXio(ig);
403     im_fatal(aIMCTX,1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
404   }
405
406   return rc;
407 }
408
409 /*
410 =item io_glue_destroy(ig)
411 X<io_glue_destroy API>
412 =category I/O Layers
413 =order 90
414 =synopsis io_glue_destroy(ig);
415
416 Destroy an io_glue objects.  Should clean up all related buffers.
417
418    ig - io_glue object to destroy.
419
420 =cut
421 */
422
423 void
424 io_glue_destroy(io_glue *ig) {
425   dIMCTXio(ig);
426   im_log((aIMCTX, 1, "io_glue_DESTROY(ig %p)\n", ig));
427
428   if (ig->destroycb)
429     ig->destroycb(ig);
430
431   if (ig->buffer)
432     myfree(ig->buffer);
433   
434   myfree(ig);
435
436   im_context_refdec(aIMCTX, "io_glue_destroy");
437 }
438
439 /*
440 =item i_io_getc(ig)
441 =category I/O Layers
442
443 A macro to read a single byte from a buffered I/O glue object.
444
445 Returns EOF on failure, or a byte.
446
447 =cut
448 */
449
450 int
451 i_io_getc_imp(io_glue *ig) {
452   if (ig->write_ptr)
453     return EOF;
454   
455   if (ig->error || ig->buf_eof)
456     return EOF;
457   
458   if (!ig->buffered) {
459     unsigned char buf;
460     ssize_t rc = i_io_raw_read(ig, &buf, 1);
461     if (rc > 0) {
462       return buf;
463     }
464     else if (rc == 0) {
465       ig->buf_eof = 1;
466       return EOF;
467     }
468     else {
469       ig->error = 1;
470       return EOF;
471     }
472   }
473
474   if (!ig->buffer)
475     i_io_setup_buffer(ig);
476   
477   if (!ig->read_ptr || ig->read_ptr == ig->read_end) {
478     if (!i_io_read_fill(ig, 1))
479       return EOF;
480   }
481   
482   return *(ig->read_ptr++);
483 }
484
485 /*
486 =item i_io_peekc(ig)
487 =category I/O Layers
488
489 Read the next character from the stream without advancing the stream.
490
491 On error or end of file, return EOF.
492
493 For unbuffered streams a single character buffer will be setup.
494
495 =cut
496 */
497
498 int
499 i_io_peekc_imp(io_glue *ig) {
500   if (ig->write_ptr)
501     return EOF;
502
503   if (!ig->buffer)
504     i_io_setup_buffer(ig);
505
506   if (!ig->buffered) {
507     ssize_t rc = i_io_raw_read(ig, ig->buffer, 1);
508     if (rc > 0) {
509       ig->read_ptr = ig->buffer;
510       ig->read_end = ig->buffer + 1;
511       return *(ig->buffer);
512     }
513     else if (rc == 0) {
514       ig->buf_eof = 1;
515       return EOF;
516     }
517     else {
518       ig->error = 1;
519       return EOF;
520     }
521   }
522
523   if (!ig->read_ptr || ig->read_ptr == ig->read_end) {
524     if (ig->error || ig->buf_eof)
525       return EOF;
526     
527     if (!i_io_read_fill(ig, 1))
528       return EOF;
529   }
530
531   return *(ig->read_ptr);
532 }
533
534 /*
535 =item i_io_peekn(ig, buffer, size)
536 =category I/O Layers
537 =synopsis ssize_t count = i_io_peekn(ig, buffer, sizeof(buffer));
538
539 Buffer at least C<size> (at most C<< ig->buf_size >> bytes of data
540 from the stream and return C<size> bytes of it to the caller in
541 C<buffer>.
542
543 This ignores the buffered state of the stream, and will always setup
544 buffering if needed.
545
546 If no C<type> parameter is provided to Imager::read() or
547 Imager::read_multi(), Imager will call C<i_io_peekn()> when probing
548 for the file format.
549
550 Returns -1 on error, 0 if there is no data before EOF, or the number
551 of bytes read into C<buffer>.
552
553 =cut
554 */
555
556 ssize_t
557 i_io_peekn(io_glue *ig, void *buf, size_t size) {
558   IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn(%p, %p, %d)\n", ig, buf, (int)size));
559
560   if (size == 0) {
561     dIMCTXio(ig);
562     i_push_error(0, "peekn size must be positive");
563     IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (zero size)\n"));
564     return -1;
565   }
566
567   if (ig->write_ptr) {
568     IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (write_ptr set)\n"));
569     return -1;
570   }
571
572   if (!ig->buffer)
573     i_io_setup_buffer(ig);
574
575   if ((!ig->read_ptr || size > ig->read_end - ig->read_ptr)
576       && !(ig->buf_eof || ig->error)) {
577     i_io_read_fill(ig, size);
578   }
579   
580   if (size > ig->read_end - ig->read_ptr)
581     size = ig->read_end - ig->read_ptr;
582
583   if (size)
584     memcpy(buf, ig->read_ptr, size);
585   else if (ig->buf_eof) {
586     IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => 0 (eof)\n"));
587     return 0;
588   }
589   else if (ig->error) {
590     IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (error)\n"));
591     return -1;
592   }
593   else {
594     IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() - size 0 but not eof or error!\n"));
595     return -1;
596   }
597
598   IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => %d\n", (int)size));
599
600   return size;
601 }
602
603 /*
604 =item i_io_putc(ig, c)
605 =category I/O Layers
606
607 Write a single character to the stream.
608
609 On success return c, on error returns EOF
610
611 =cut
612 */
613
614 int
615 i_io_putc_imp(io_glue *ig, int c) {
616   IOL_DEB(fprintf(IOL_DEBs, "i_io_putc_imp(%p, %d)\n", ig, c));
617
618   if (!ig->buffered) {
619     char buf = c;
620     ssize_t write_result;
621     int result = c;
622
623     if (ig->error)
624       return EOF;
625
626     write_result = i_io_raw_write(ig, &buf, 1);
627     if (write_result != 1) {
628       ig->error = 1;
629       result = EOF;
630       IOL_DEB(fprintf(IOL_DEBs, "  unbuffered putc() failed, setting error mode\n"));
631     }
632     IOL_DEB(fprintf(IOL_DEBs, "  unbuffered: result %d\n", result));
633
634     return result;
635   }
636
637   if (ig->read_ptr)
638     return EOF;
639
640   if (ig->error)
641     return EOF;
642
643   if (!ig->buffer)
644     i_io_setup_buffer(ig);
645
646   if (ig->write_ptr && ig->write_ptr == ig->write_end) {
647     if (!i_io_flush(ig))
648       return EOF;
649   }
650
651   i_io_start_write(ig);
652
653   *(ig->write_ptr)++ = c;
654
655   return (unsigned char)c;
656 }
657
658 /*
659 =item i_io_read(io, buffer, size)
660 =category I/O Layers
661
662 Read up to C<size> bytes from the stream C<io> into C<buffer>.
663
664 Returns the number of bytes read.  Returns 0 on end of file.  Returns
665 -1 on error.
666
667 =cut
668 */
669
670 ssize_t
671 i_io_read(io_glue *ig, void *buf, size_t size) {
672   unsigned char *pbuf = buf;
673   ssize_t read_total = 0;
674
675   IOL_DEB(fprintf(IOL_DEBs, "i_io_read(%p, %p, %u)\n", ig, buf, (unsigned)size));
676
677   if (ig->write_ptr) {
678     IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => -1 (write_ptr set)\n"));
679     return -1;
680   }
681
682   if (!ig->buffer && ig->buffered)
683     i_io_setup_buffer(ig);
684
685   if (ig->read_ptr && ig->read_ptr < ig->read_end) {
686     size_t alloc = ig->read_end - ig->read_ptr;
687     
688     if (alloc > size)
689       alloc = size;
690
691     memcpy(pbuf, ig->read_ptr, alloc);
692     ig->read_ptr += alloc;
693     pbuf += alloc;
694     size -= alloc;
695     read_total += alloc;
696   }
697
698   if (size > 0 && !(ig->error || ig->buf_eof)) {
699     if (!ig->buffered || size > ig->buf_size) {
700       ssize_t rc;
701       
702       while (size > 0 && (rc = i_io_raw_read(ig, pbuf, size)) > 0) {
703         size -= rc;
704         pbuf += rc;
705         read_total += rc;
706       }
707       
708       IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => %d (raw read)\n", (int)read_total));
709
710       if (rc < 0)
711         ig->error = 1;
712       else if (rc == 0)
713         ig->buf_eof = 1;
714
715       if (!read_total)
716         return rc;
717     }
718     else {
719       if (i_io_read_fill(ig, size)) {
720         size_t alloc = ig->read_end - ig->read_ptr;
721         if (alloc > size)
722           alloc = size;
723         
724         memcpy(pbuf, ig->read_ptr, alloc);
725         ig->read_ptr += alloc;
726         pbuf += alloc;
727         size -= alloc;
728         read_total += alloc;
729       }
730       else {
731         if (!read_total && ig->error) {
732           IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => -1 (fill failure)\n"));
733           return -1;
734         }
735       }
736     }
737   }
738
739   if (!read_total && ig->error)
740     read_total = -1;
741
742   IOL_DEB(fprintf(IOL_DEBs, "i_io_read() => %d\n", (int)read_total));
743
744   return read_total;
745 }
746
747 /*
748 =item i_io_write(io, buffer, size)
749 =category I/O Layers
750 =synopsis ssize_t result = i_io_write(io, buffer, size)
751
752 Write to the given I/O stream.
753
754 Returns the number of bytes written.
755
756 =cut
757 */
758
759 ssize_t
760 i_io_write(io_glue *ig, const void *buf, size_t size) {
761   const unsigned char *pbuf = buf;
762   size_t write_count = 0;
763
764   IOL_DEB(fprintf(IOL_DEBs, "i_io_write(%p, %p, %u)\n", ig, buf, (unsigned)size));
765
766   if (!ig->buffered) {
767     ssize_t result;
768
769     if (ig->error) {
770       IOL_DEB(fprintf(IOL_DEBs, "  unbuffered, error state\n"));
771       return -1;
772     }
773
774     result = i_io_raw_write(ig, buf, size);
775
776     if (result != size) {
777       ig->error = 1;
778       IOL_DEB(fprintf(IOL_DEBs, "  unbuffered, setting error flag\n"));
779     }
780
781     IOL_DEB(fprintf(IOL_DEBs, "  unbuffered, result: %d\n", (int)result));
782
783     return result;
784   }
785
786   if (ig->read_ptr) {
787     IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => -1 (read_ptr set)\n"));
788     return -1;
789   }
790
791   if (ig->error) {
792     IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => -1 (error)\n"));
793     return -1;
794   }
795
796   if (!ig->buffer)
797     i_io_setup_buffer(ig);
798
799   if (!ig->write_ptr)
800     i_io_start_write(ig);
801
802   if (ig->write_ptr && ig->write_ptr + size <= ig->write_end) {
803     size_t alloc = ig->write_end - ig->write_ptr;
804     if (alloc > size)
805       alloc = size;
806     memcpy(ig->write_ptr, pbuf, alloc);
807     write_count += alloc;
808     size -= alloc;
809     pbuf += alloc;
810     ig->write_ptr += alloc;
811   }
812
813   if (size) {
814     if (!i_io_flush(ig)) {
815       IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => %d (i_io_flush failure)\n", (int)write_count));
816       return write_count ? write_count : -1;
817     }
818
819     i_io_start_write(ig);
820     
821     if (size > ig->buf_size) {
822       ssize_t rc;
823       while (size > 0 && (rc = i_io_raw_write(ig, pbuf, size)) > 0) {
824         write_count += rc;
825         pbuf += rc;
826         size -= rc;
827       }
828       if (rc <= 0) {
829         ig->error = 1;
830         if (!write_count) {
831           IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => -1 (direct write failure)\n"));
832           return -1;
833         }
834       }
835     }
836     else {
837       memcpy(ig->write_ptr, pbuf, size);
838       write_count += size;
839       ig->write_ptr += size;
840     }
841   }
842
843   IOL_DEB(fprintf(IOL_DEBs, "i_io_write() => %d\n", (int)write_count));
844
845   return write_count;
846 }
847
848 /*
849 =item i_io_seek(io, offset, whence)
850 =category I/O Layers
851
852 Seek within the stream.
853
854 Acts like perl's seek.
855
856 =cut
857  */
858
859 off_t
860 i_io_seek(io_glue *ig, off_t offset, int whence) {
861   off_t new_off;
862
863   IOL_DEB(fprintf(IOL_DEBs, "i_io_seek(%p, %ld, %d)\n", ig, (long)offset, whence));
864
865   if (ig->write_ptr && ig->write_ptr != ig->write_end) {
866     if (!i_io_flush(ig))
867       return (off_t)(-1);
868   }
869
870   if (whence == SEEK_CUR && ig->read_ptr && ig->read_ptr != ig->read_end)
871     offset -= ig->read_end - ig->read_ptr;
872
873   ig->read_ptr = ig->read_end = NULL;
874   ig->write_ptr = ig->write_end = NULL;
875   ig->error = 0;
876   ig->buf_eof = 0;
877   
878   new_off = i_io_raw_seek(ig, offset, whence);
879   if (new_off < 0)
880     ig->error = 1;
881
882   IOL_DEB(fprintf(IOL_DEBs, "i_io_seek() => %ld\n", (long)new_off));
883
884   return new_off;
885 }
886
887 /*
888 =item i_io_flush(io)
889 =category I/O Layers
890
891 Flush any buffered output.
892
893 Returns true on success,
894
895 =cut
896 */
897
898 int
899 i_io_flush(io_glue *ig) {
900   unsigned char *bufp;
901
902   IOL_DEB(fprintf(IOL_DEBs, "i_io_flush(%p)\n", ig));
903
904   if (ig->error) {
905     IOL_DEB(fprintf(IOL_DEBs, "i_io_flush() => 0 (error set)\n", ig));
906     return 0;
907   }
908
909   /* nothing to do */
910   if (!ig->write_ptr)
911     return 1;
912
913   bufp = ig->buffer;
914   while (bufp < ig->write_ptr) {
915     ssize_t rc = i_io_raw_write(ig, bufp, ig->write_ptr - bufp);
916     if (rc <= 0) {
917       IOL_DEB(fprintf(IOL_DEBs, "i_io_flush() => 0 (write error)\n", ig));
918       ig->error = 1;
919       return 0;
920     }
921     
922     bufp += rc;
923   }
924
925   ig->write_ptr = ig->write_end = NULL;
926
927   IOL_DEB(fprintf(IOL_DEBs, "i_io_flush() => 1\n", ig));
928
929   return 1;
930 }
931
932 /*
933 =item i_io_close(io)
934 =category I/O Layers
935
936 Flush any pending output and perform the close action for the stream.
937
938 Returns 0 on success.
939
940 =cut
941 */
942
943 int
944 i_io_close(io_glue *ig) {
945   int result = 0;
946
947   IOL_DEB(fprintf(IOL_DEBs, "i_io_close(%p)\n", ig));
948   if (ig->error)
949     result = -1;
950
951   if (ig->write_ptr && !i_io_flush(ig))
952     result = -1;
953
954   if (i_io_raw_close(ig))
955     result = -1;
956
957   IOL_DEB(fprintf(IOL_DEBs, "i_io_close() => %d\n", result));
958
959   return result;
960 }
961
962 /*
963 =item i_io_gets(ig, buffer, size, end_of_line)
964 =category I/O Layers
965 =synopsis char buffer[BUFSIZ]
966 =synopsis ssize_t len = i_io_gets(buffer, sizeof(buffer), '\n');
967
968 Read up to C<size>-1 bytes from the stream C<ig> into C<buffer>.
969
970 If the byte C<end_of_line> is seen then no further bytes will be read.
971
972 Returns the number of bytes read.
973
974 Always C<NUL> terminates the buffer.
975
976 =cut
977 */
978
979 ssize_t
980 i_io_gets(io_glue *ig, char *buffer, size_t size, int eol) {
981   ssize_t read_count = 0;
982   if (size < 2)
983     return 0;
984   --size; /* room for nul */
985   while (size > 0) {
986     int byte = i_io_getc(ig);
987     if (byte == EOF)
988       break;
989     *buffer++ = byte;
990     ++read_count;
991     if (byte == eol)
992       break;
993     --size;
994   }
995   *buffer++ = '\0';
996
997   return read_count;
998 }
999
1000 /*
1001 =item i_io_init(ig, readcb, writecb, seekcb)
1002
1003 Do common initialization for io_glue objects.
1004
1005 =cut
1006 */
1007
1008 static void
1009 i_io_init(pIMCTX, io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb,
1010           i_io_seekp_t seekcb) {
1011   ig->type = type;
1012   ig->exdata = NULL;
1013   ig->readcb = readcb;
1014   ig->writecb = writecb;
1015   ig->seekcb = seekcb;
1016   ig->closecb = NULL;
1017   ig->sizecb = NULL;
1018   ig->destroycb = NULL;
1019   ig->context = aIMCTX;
1020
1021   ig->buffer = NULL;
1022   ig->read_ptr = NULL;
1023   ig->read_end = NULL;
1024   ig->write_ptr = NULL;
1025   ig->write_end = NULL;
1026   ig->buf_size = IO_BUF_SIZE;
1027   ig->buf_eof = 0;
1028   ig->error = 0;
1029   ig->buffered = 1;
1030 }
1031
1032 /*
1033 =item i_io_set_buffered(io, buffered)
1034 =category I/O Layers
1035
1036 Set the buffering mode of the stream.
1037
1038 If you switch buffering off on a stream with buffering on:
1039
1040 =over
1041
1042 =item *
1043
1044 any buffered output will be flushed.
1045
1046 =item *
1047
1048 any existing buffered input will be consumed before reads become
1049 unbuffered.
1050
1051 =back
1052
1053 Returns true on success.  This may fail if any buffered output cannot
1054 be flushed.
1055
1056 =cut
1057 */
1058
1059 int
1060 i_io_set_buffered(io_glue *ig, int buffered) {
1061   if (!buffered && ig->write_ptr) {
1062     if (!i_io_flush(ig)) {
1063       ig->error = 1;
1064       return 0;
1065     }
1066   }
1067   ig->buffered = buffered;
1068
1069   return 1;
1070 }
1071
1072 /*
1073 =item i_io_dump(ig)
1074
1075 Dump the base fields of an io_glue object to stdout.
1076
1077 =cut
1078 */
1079 void
1080 i_io_dump(io_glue *ig, int flags) {
1081   fprintf(IOL_DEBs, "ig %p:\n", ig);
1082   fprintf(IOL_DEBs, "  type: %d\n", ig->type);  
1083   fprintf(IOL_DEBs, "  exdata: %p\n", ig->exdata);
1084   if (flags & I_IO_DUMP_CALLBACKS) {
1085     fprintf(IOL_DEBs, "  readcb: %p\n", ig->readcb);
1086     fprintf(IOL_DEBs, "  writecb: %p\n", ig->writecb);
1087     fprintf(IOL_DEBs, "  seekcb: %p\n", ig->seekcb);
1088     fprintf(IOL_DEBs, "  closecb: %p\n", ig->closecb);
1089     fprintf(IOL_DEBs, "  sizecb: %p\n", ig->sizecb);
1090   }
1091   if (flags & I_IO_DUMP_BUFFER) {
1092     fprintf(IOL_DEBs, "  buffer: %p\n", ig->buffer);
1093     fprintf(IOL_DEBs, "  read_ptr: %p\n", ig->read_ptr);
1094     if (ig->read_ptr) {
1095       fprintf(IOL_DEBs, "    ");
1096       dump_data(ig->read_ptr, ig->read_end, 0);
1097       putc('\n', IOL_DEBs);
1098     }
1099     fprintf(IOL_DEBs, "  read_end: %p\n", ig->read_end);
1100     fprintf(IOL_DEBs, "  write_ptr: %p\n", ig->write_ptr);
1101     if (ig->write_ptr) {
1102       fprintf(IOL_DEBs, "    ");
1103       dump_data(ig->buffer, ig->write_ptr, 1);
1104       putc('\n', IOL_DEBs);
1105     }
1106     fprintf(IOL_DEBs, "  write_end: %p\n", ig->write_end);
1107     fprintf(IOL_DEBs, "  buf_size: %u\n", (unsigned)(ig->buf_size));
1108   }
1109   if (flags & I_IO_DUMP_STATUS) {
1110     fprintf(IOL_DEBs, "  buf_eof: %d\n", ig->buf_eof);
1111     fprintf(IOL_DEBs, "  error: %d\n", ig->error);
1112     fprintf(IOL_DEBs, "  buffered: %d\n", ig->buffered);
1113   }
1114 }
1115
1116 /*
1117 =back
1118
1119 =head1 INTERNAL FUNCTIONS
1120
1121 =over
1122
1123 =item my_strerror
1124
1125 Calls strerror() and ensures we don't return NULL.
1126
1127 On some platforms it's possible for strerror() to return NULL, this
1128 wrapper ensures we only get non-NULL values.
1129
1130 =cut
1131 */
1132
1133 static
1134 const char *my_strerror(int err) {
1135   const char *result = strerror(err);
1136   
1137   if (!result)
1138     result = "Unknown error";
1139   
1140   return result;
1141 }
1142
1143 static void
1144 i_io_setup_buffer(io_glue *ig) {
1145   ig->buffer = mymalloc(ig->buf_size);
1146 }
1147
1148 static void
1149 i_io_start_write(io_glue *ig) {
1150   ig->write_ptr = ig->buffer;
1151   ig->write_end = ig->buffer + ig->buf_size;
1152 }
1153
1154 static int
1155 i_io_read_fill(io_glue *ig, ssize_t needed) {
1156   unsigned char *buf_end = ig->buffer + ig->buf_size;
1157   unsigned char *buf_start = ig->buffer;
1158   unsigned char *work = ig->buffer;
1159   ssize_t rc;
1160   int good = 0;
1161
1162   IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill(%p, %d)\n", ig, (int)needed));
1163
1164   /* these conditions may be unused, callers should also be checking them */
1165   if (ig->error || ig->buf_eof)
1166     return 0;
1167
1168   if (needed > ig->buf_size)
1169     needed = ig->buf_size;
1170
1171   if (ig->read_ptr && ig->read_ptr < ig->read_end) {
1172     size_t kept = ig->read_end - ig->read_ptr;
1173
1174     if (needed < kept) {
1175       IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill(%u) -> 1 (already have enough)\n", (unsigned)needed));
1176       return 1;
1177     }
1178
1179     if (ig->read_ptr != ig->buffer)
1180       memmove(ig->buffer, ig->read_ptr, kept);
1181
1182     good = 1; /* we have *something* available to read */
1183     work = buf_start + kept;
1184     needed -= kept;
1185   }
1186   else {
1187     work = ig->buffer;
1188   }
1189
1190   /* there should always be buffer space the first time around, but
1191      avoid a compiler warning here */
1192   rc = -1;
1193   while (work < buf_end && (rc = i_io_raw_read(ig, work, buf_end - work)) > 0) {
1194     work += rc;
1195     good = 1;
1196     if (needed < rc)
1197       break;
1198
1199     needed -= rc;
1200   }
1201
1202   if (rc < 0) {
1203     ig->error = 1;
1204     IOL_DEB(fprintf(IOL_DEBs, " i_io_read_fill -> rc %d, setting error\n",
1205                     (int)rc));
1206   }
1207   else if (rc == 0) {
1208     ig->buf_eof = 1;
1209     IOL_DEB(fprintf(IOL_DEBs, " i_io_read_fill -> rc 0, setting eof\n"));
1210   }
1211
1212   if (good) {
1213     ig->read_ptr = buf_start;
1214     ig->read_end = work;
1215   }
1216   
1217   IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill => %d, %u buffered\n", good,
1218                   (unsigned)(ig->read_end - ig->read_ptr)));
1219   return good;
1220 }
1221
1222 /*
1223 =item dump_data(start, end, bias)
1224
1225 Hex dump the data between C<start> and C<end>.
1226
1227 If there is more than a pleasing amount of data, either dump the
1228 beginning (C<bias == 0>) or dump the end C(<bias != 0>) of the range.
1229
1230 =cut
1231 */
1232
1233 static void
1234 dump_data(unsigned char *start, unsigned char *end, int bias) {
1235   unsigned char *p;
1236   size_t count = end - start;
1237
1238   if (start == end) {
1239     fprintf(IOL_DEBs, "(empty)");
1240     return;
1241   }
1242
1243   if (count > 15) {
1244     if (bias) {
1245       fprintf(IOL_DEBs, "... ");
1246       start = end - 14;
1247     }
1248     else {
1249       end = start + 14;
1250     }
1251       
1252     for (p = start; p < end; ++p) {
1253       fprintf(IOL_DEBs, " %02x", *p);
1254     }
1255     putc(' ', IOL_DEBs);
1256     putc('<', IOL_DEBs);
1257     for (p = start; p < end; ++p) {
1258       if (*p < ' ' || *p > '~')
1259         putc('.', IOL_DEBs);
1260       else
1261         putc(*p, IOL_DEBs);
1262     }
1263     putc('>', IOL_DEBs);
1264     if (!bias)
1265       fprintf(IOL_DEBs, " ...");
1266   }
1267   else {
1268     for (p = start; p < end; ++p) {
1269       fprintf(IOL_DEBs, " %02x", *p);
1270     }
1271     putc(' ', IOL_DEBs);
1272     for (p = start; p < end; ++p) {
1273       if (*p < ' ' || *p > '~')
1274         putc('.', IOL_DEBs);
1275       else
1276         putc(*p, IOL_DEBs);
1277     }
1278   }
1279 }
1280
1281 /*
1282  * Callbacks for sources that cannot seek
1283  */
1284
1285 /*
1286  * Callbacks for sources that can seek 
1287  */
1288
1289 /*
1290 =item realseek_read(ig, buf, count)
1291
1292 Does the reading from a source that can be seeked on
1293
1294    ig    - io_glue object
1295    buf   - buffer to return data in
1296    count - number of bytes to read into buffer max
1297
1298 =cut
1299 */
1300
1301 static
1302 ssize_t 
1303 realseek_read(io_glue *igo, void *buf, size_t count) {
1304   io_cb        *ig = (io_cb *)igo;
1305   void *p          = ig->p;
1306   ssize_t       rc = 0;
1307
1308   IOL_DEB( fprintf(IOL_DEBs, "realseek_read:  buf = %p, count = %u\n", 
1309                    buf, (unsigned)count) );
1310   rc = ig->readcb(p,buf,count);
1311
1312   IOL_DEB( fprintf(IOL_DEBs, "realseek_read: rc = %d\n", (int)rc) );
1313
1314   return rc;
1315 }
1316
1317
1318 /*
1319 =item realseek_write(ig, buf, count)
1320
1321 Does the writing to a 'source' that can be seeked on
1322
1323    ig    - io_glue object
1324    buf   - buffer that contains data
1325    count - number of bytes to write
1326
1327 =cut
1328 */
1329
1330 static
1331 ssize_t 
1332 realseek_write(io_glue *igo, const void *buf, size_t count) {
1333   io_cb        *ig = (io_cb *)igo;
1334   void          *p = ig->p;
1335   ssize_t       rc = 0;
1336   size_t        bc = 0;
1337   char       *cbuf = (char*)buf; 
1338   
1339   IOL_DEB( fprintf(IOL_DEBs, "realseek_write: ig = %p, buf = %p, "
1340                    "count = %u\n", ig, buf, (unsigned)count) );
1341
1342   /* Is this a good idea? Would it be better to handle differently? 
1343      skip handling? */
1344   while( count!=bc && (rc = ig->writecb(p,cbuf+bc,count-bc))>0 ) {
1345     bc+=rc;
1346   }
1347
1348   IOL_DEB( fprintf(IOL_DEBs, "realseek_write: rc = %d, bc = %u\n", (int)rc, (unsigned)bc) );
1349   return rc < 0 ? rc : bc;
1350 }
1351
1352
1353 /*
1354 =item realseek_close(ig)
1355
1356 Closes a source that can be seeked on.  Not sure if this should be an
1357 actual close or not.  Does nothing for now.  Should be fixed.
1358
1359    ig - data source
1360
1361 =cut */
1362
1363 static
1364 int
1365 realseek_close(io_glue *igo) {
1366   io_cb *ig = (io_cb *)igo;
1367   dIMCTXio(igo);
1368
1369   IOL_DEB(fprintf(IOL_DEBs, "realseek_close(%p)\n", ig));
1370   im_log((aIMCTX,1, "realseek_close(ig %p)\n", ig));
1371   if (ig->closecb)
1372     return ig->closecb(ig->p);
1373   else
1374     return 0;
1375 }
1376
1377
1378 /* realseek_seek(ig, offset, whence)
1379
1380 Implements seeking for a source that is seekable, the purpose of having this is to be able to
1381 have an offset into a file that is different from what the underlying library thinks.
1382
1383    ig     - data source
1384    offset - offset into stream
1385    whence - whence argument a la lseek
1386
1387 =cut
1388 */
1389
1390 static
1391 off_t
1392 realseek_seek(io_glue *igo, off_t offset, int whence) {
1393   io_cb *ig = (io_cb *)igo;
1394   void *p = ig->p;
1395   off_t rc;
1396   IOL_DEB( fprintf(IOL_DEBs, "realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
1397   rc = ig->seekcb(p, offset, whence);
1398
1399   IOL_DEB( fprintf(IOL_DEBs, "realseek_seek: rc %ld\n", (long) rc) );
1400   return rc;
1401   /* FIXME: How about implementing this offset handling stuff? */
1402 }
1403
1404 static
1405 void
1406 realseek_destroy(io_glue *igo) {
1407   io_cb *ig = (io_cb *)igo;
1408
1409   if (ig->destroycb)
1410     ig->destroycb(ig->p);
1411 }
1412
1413 /*
1414  * Callbacks for sources that are a fixed size buffer
1415  */
1416
1417 /*
1418 =item buffer_read(ig, buf, count)
1419
1420 Does the reading from a buffer source
1421
1422    ig    - io_glue object
1423    buf   - buffer to return data in
1424    count - number of bytes to read into buffer max
1425
1426 =cut
1427 */
1428
1429 static
1430 ssize_t 
1431 buffer_read(io_glue *igo, void *buf, size_t count) {
1432   io_buffer *ig = (io_buffer *)igo;
1433
1434   IOL_DEB( fprintf(IOL_DEBs, "buffer_read: ig->cpos = %ld, buf = %p, count = %u\n", (long) ig->cpos, buf, (unsigned)count) );
1435
1436   if ( ig->cpos+count > ig->len ) {
1437     dIMCTXio(igo);
1438     im_log((aIMCTX, 1,"buffer_read: short read: cpos=%ld, len=%ld, count=%ld\n", (long)ig->cpos, (long)ig->len, (long)count));
1439     count = ig->len - ig->cpos;
1440   }
1441   
1442   memcpy(buf, ig->data+ig->cpos, count);
1443   ig->cpos += count;
1444   IOL_DEB( fprintf(IOL_DEBs, "buffer_read: count = %ld\n", (long)count) );
1445   return count;
1446 }
1447
1448
1449 /*
1450 =item buffer_write(ig, buf, count)
1451
1452 Does nothing, returns -1
1453
1454    ig    - io_glue object
1455    buf   - buffer that contains data
1456    count - number of bytes to write
1457
1458 =cut
1459 */
1460
1461 static
1462 ssize_t 
1463 buffer_write(io_glue *ig, const void *buf, size_t count) {
1464   dIMCTXio(ig);
1465   im_log((aIMCTX, 1, "buffer_write called, this method should never be called.\n"));
1466   return -1;
1467 }
1468
1469
1470 /*
1471 =item buffer_close(ig)
1472
1473 Closes a source that can be seeked on.  Not sure if this should be an actual close
1474 or not.  Does nothing for now.  Should be fixed.
1475
1476    ig - data source
1477
1478 =cut
1479 */
1480
1481 static
1482 int
1483 buffer_close(io_glue *ig) {
1484   dIMCTXio(ig);
1485   im_log((aIMCTX, 1, "buffer_close(ig %p)\n", ig));
1486
1487   return 0;
1488 }
1489
1490
1491 /* buffer_seek(ig, offset, whence)
1492
1493 Implements seeking for a buffer source.
1494
1495    ig     - data source
1496    offset - offset into stream
1497    whence - whence argument a la lseek
1498
1499 =cut
1500 */
1501
1502 static
1503 off_t
1504 buffer_seek(io_glue *igo, off_t offset, int whence) {
1505   io_buffer *ig = (io_buffer *)igo;
1506   off_t reqpos = 
1507     calc_seek_offset(ig->cpos, ig->len, offset, whence);
1508   
1509   if (reqpos > ig->len) {
1510     dIMCTXio(igo);
1511     im_log((aIMCTX, 1, "seeking out of readable range\n"));
1512     return (off_t)-1;
1513   }
1514   if (reqpos < 0) {
1515     dIMCTXio(igo);
1516     i_push_error(0, "seek before beginning of file");
1517     return (off_t)-1;
1518   }
1519   
1520   ig->cpos = reqpos;
1521   IOL_DEB( fprintf(IOL_DEBs, "buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
1522
1523   return reqpos;
1524   /* FIXME: How about implementing this offset handling stuff? */
1525 }
1526
1527 static
1528 void
1529 buffer_destroy(io_glue *igo) {
1530   io_buffer *ig = (io_buffer *)igo;
1531
1532   if (ig->closecb) {
1533     dIMCTXio(igo);
1534     im_log((aIMCTX, 1,"calling close callback %p for io_buffer\n", 
1535             ig->closecb));
1536     ig->closecb(ig->closedata);
1537   }
1538 }
1539
1540
1541
1542 /*
1543  * Callbacks for sources that are a chain of variable sized buffers
1544  */
1545
1546
1547
1548 /* Helper functions for buffer chains */
1549
1550 static
1551 io_blink*
1552 io_blink_new(void) {
1553   io_blink *ib;
1554
1555 #if 0
1556   im_log((aIMCTX, 1, "io_blink_new()\n"));
1557 #endif
1558
1559   ib = mymalloc(sizeof(io_blink));
1560
1561   ib->next = NULL;
1562   ib->prev = NULL;
1563   ib->len  = BBSIZ;
1564
1565   memset(&ib->buf, 0, ib->len);
1566   return ib;
1567 }
1568
1569
1570
1571 /*
1572 =item io_bchain_advance(ieb)
1573
1574 Advances the buffer chain to the next link - extending if
1575 necessary.  Also adjusts the cpos and tfill counters as needed.
1576
1577    ieb   - buffer chain object
1578
1579 =cut
1580 */
1581
1582 static
1583 void
1584 io_bchain_advance(io_ex_bchain *ieb) {
1585   if (ieb->cp->next == NULL) {
1586     ieb->tail = io_blink_new();
1587     ieb->tail->prev = ieb->cp;
1588     ieb->cp->next   = ieb->tail;
1589
1590     ieb->tfill = 0; /* Only set this if we added a new slice */
1591   }
1592   ieb->cp    = ieb->cp->next;
1593   ieb->cpos  = 0;
1594 }
1595
1596
1597
1598 /*
1599 =item io_bchain_destroy()
1600
1601 frees all resources used by a buffer chain.
1602
1603 =cut
1604 */
1605
1606 static void
1607 io_destroy_bufchain(io_ex_bchain *ieb) {
1608   io_blink *cp;
1609 #if 0
1610   mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
1611 #endif
1612   cp = ieb->head;
1613   
1614   while(cp) {
1615     io_blink *t = cp->next;
1616     myfree(cp);
1617     cp = t;
1618   }
1619 }
1620
1621
1622
1623
1624 /*
1625
1626 static
1627 void
1628 bufchain_dump(io_ex_bchain *ieb) {
1629   mm_log((1, "  buf_chain_dump(ieb %p)\n"));
1630   mm_log((1, "  buf_chain_dump: ieb->offset = %d\n", ieb->offset));
1631   mm_log((1, "  buf_chain_dump: ieb->length = %d\n", ieb->length));
1632   mm_log((1, "  buf_chain_dump: ieb->head   = %p\n", ieb->head  ));
1633   mm_log((1, "  buf_chain_dump: ieb->tail   = %p\n", ieb->tail  ));
1634   mm_log((1, "  buf_chain_dump: ieb->tfill  = %d\n", ieb->tfill ));
1635   mm_log((1, "  buf_chain_dump: ieb->cp     = %p\n", ieb->cp    ));
1636   mm_log((1, "  buf_chain_dump: ieb->cpos   = %d\n", ieb->cpos  ));
1637   mm_log((1, "  buf_chain_dump: ieb->gpos   = %d\n", ieb->gpos  ));
1638 }
1639 */
1640
1641 /*
1642  * TRUE if lengths are NOT equal
1643  */
1644
1645 /*
1646 static
1647 void
1648 chainlencert( io_glue *ig ) {
1649   int clen;
1650   int cfl           = 0;
1651   size_t csize      = 0;
1652   size_t cpos       = 0;
1653   io_ex_bchain *ieb = ig->exdata;
1654   io_blink *cp      = ieb->head;
1655   
1656
1657   if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
1658
1659   while(cp) {
1660     clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
1661     if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
1662     if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
1663     
1664     if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
1665     if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
1666     
1667     if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
1668     if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
1669
1670     if (cp == ieb->cp) {
1671       cfl = 1;
1672       cpos += ieb->cpos;
1673     }
1674
1675     if (!cfl) cpos += clen;
1676
1677     csize += clen;
1678     cp     = cp->next;
1679   }
1680   if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
1681   if (( cpos  != ieb->gpos   )) mm_log((1, "BAR : cpos  = %d, ieb->gpos   = %d\n", cpos,  ieb->gpos  ));
1682 }
1683
1684
1685 static
1686 void
1687 chaincert( io_glue *ig) {
1688   size_t csize   = 0;
1689   io_ex_bchain *ieb = ig->exdata;
1690   io_blink *cp   = ieb->head;
1691   
1692   mm_log((1, "Chain verification.\n"));
1693
1694   mm_log((1, "  buf_chain_dump: ieb->offset = %d\n", ieb->offset));
1695   mm_log((1, "  buf_chain_dump: ieb->length = %d\n", ieb->length));
1696   mm_log((1, "  buf_chain_dump: ieb->head   = %p\n", ieb->head  ));
1697   mm_log((1, "  buf_chain_dump: ieb->tail   = %p\n", ieb->tail  ));
1698   mm_log((1, "  buf_chain_dump: ieb->tfill  = %d\n", ieb->tfill ));
1699   mm_log((1, "  buf_chain_dump: ieb->cp     = %p\n", ieb->cp    ));
1700   mm_log((1, "  buf_chain_dump: ieb->cpos   = %d\n", ieb->cpos  ));
1701   mm_log((1, "  buf_chain_dump: ieb->gpos   = %d\n", ieb->gpos  ));
1702
1703   while(cp) {
1704     int clen = cp == ieb->tail ? ieb->tfill : cp->len;
1705     mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
1706     if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
1707     if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
1708     
1709     if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
1710     if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
1711     
1712     if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
1713     if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
1714
1715     csize += clen;
1716     cp     = cp->next;
1717   }
1718
1719   mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
1720 }
1721 */
1722
1723 /*
1724 =item bufchain_read(ig, buf, count)
1725
1726 Does the reading from a source that can be seeked on
1727
1728    ig    - io_glue object
1729    buf   - buffer to return data in
1730    count - number of bytes to read into buffer max
1731
1732 =cut
1733 */
1734
1735 static
1736 ssize_t 
1737 bufchain_read(io_glue *ig, void *buf, size_t count) {
1738   io_ex_bchain *ieb = ig->exdata;
1739   size_t     scount = count;
1740   char        *cbuf = buf;
1741   size_t         sk;
1742   dIMCTXio(ig);
1743
1744   im_log((aIMCTX, 1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, (long)count));
1745
1746   while( scount ) {
1747     int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
1748     if (clen == ieb->cpos) {
1749       if (ieb->cp == ieb->tail) break; /* EOF */
1750       ieb->cp = ieb->cp->next;
1751       ieb->cpos = 0;
1752       clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
1753     }
1754
1755     sk = clen - ieb->cpos;
1756     sk = sk > scount ? scount : sk;
1757
1758     memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
1759     scount    -= sk;
1760     ieb->cpos += sk;
1761     ieb->gpos += sk;
1762   }
1763
1764   im_log((aIMCTX, 1, "bufchain_read: returning %ld\n", (long)(count-scount)));
1765   return count-scount;
1766 }
1767
1768
1769
1770
1771
1772 /*
1773 =item bufchain_write(ig, buf, count)
1774
1775 Does the writing to a 'source' that can be seeked on
1776
1777    ig    - io_glue object
1778    buf   - buffer that contains data
1779    count - number of bytes to write
1780
1781 =cut
1782 */
1783
1784 static
1785 ssize_t
1786 bufchain_write(io_glue *ig, const void *buf, size_t count) {
1787   char *cbuf = (char *)buf;
1788   io_ex_bchain *ieb = ig->exdata;
1789   size_t         ocount = count;
1790   size_t         sk;
1791   dIMCTXio(ig);
1792
1793   im_log((aIMCTX, 1, "bufchain_write: ig = %p, buf = %p, count = %ld\n", ig, buf, (long)count));
1794
1795   IOL_DEB( fprintf(IOL_DEBs, "bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %ld\n", ig, (long) ieb->cpos, buf, (long)count) );
1796   
1797   while(count) {
1798     im_log((aIMCTX, 2, "bufchain_write: - looping - count = %ld\n", (long)count));
1799     if (ieb->cp->len == ieb->cpos) {
1800       im_log((aIMCTX, 1, "bufchain_write: cp->len == ieb->cpos = %ld - advancing chain\n", (long) ieb->cpos));
1801       io_bchain_advance(ieb);
1802     }
1803
1804     sk = ieb->cp->len - ieb->cpos;
1805     sk = sk > count ? count : sk;
1806     memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
1807
1808     if (ieb->cp == ieb->tail) {
1809       int extend = ieb->cpos + sk - ieb->tfill;
1810       im_log((aIMCTX, 2, "bufchain_write: extending tail by %d\n", extend));
1811       if (extend > 0) {
1812         ieb->length += extend;
1813         ieb->tfill  += extend;
1814       }
1815     }
1816
1817     ieb->cpos += sk;
1818     ieb->gpos += sk;
1819     count     -= sk;
1820   }
1821   return ocount;
1822 }
1823
1824 /*
1825 =item bufchain_close(ig)
1826
1827 Closes a source that can be seeked on.  Not sure if this should be an actual close
1828 or not.  Does nothing for now.  Should be fixed.
1829
1830    ig - data source
1831
1832 =cut
1833 */
1834
1835 static
1836 int
1837 bufchain_close(io_glue *ig) {
1838   dIMCTXio(ig);
1839   im_log((aIMCTX, 1, "bufchain_close(ig %p)\n",ig));
1840   IOL_DEB( fprintf(IOL_DEBs, "bufchain_close(ig %p)\n", ig) );
1841
1842   return 0;  
1843 }
1844
1845
1846 /* bufchain_seek(ig, offset, whence)
1847
1848 Implements seeking for a source that is seekable, the purpose of having this is to be able to
1849 have an offset into a file that is different from what the underlying library thinks.
1850
1851    ig     - data source
1852    offset - offset into stream
1853    whence - whence argument a la lseek
1854
1855 =cut
1856 */
1857
1858 static
1859 off_t
1860 bufchain_seek(io_glue *ig, off_t offset, int whence) {
1861   io_ex_bchain *ieb = ig->exdata;
1862   int wrlen;
1863
1864   off_t scount = calc_seek_offset(ieb->gpos, ieb->length, offset, whence);
1865   off_t sk;
1866   dIMCTXio(ig);
1867
1868   im_log((aIMCTX, 1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, (long)offset, whence));
1869
1870   if (scount < 0) {
1871     i_push_error(0, "invalid whence supplied or seek before start of file");
1872     return (off_t)-1;
1873   }
1874
1875   ieb->cp   = ieb->head;
1876   ieb->cpos = 0;
1877   ieb->gpos = 0;
1878   
1879   while( scount ) {
1880     int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
1881     if (clen == ieb->cpos) {
1882       if (ieb->cp == ieb->tail) break; /* EOF */
1883       ieb->cp = ieb->cp->next;
1884       ieb->cpos = 0;
1885       clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
1886     }
1887     
1888     sk = clen - ieb->cpos;
1889     sk = sk > scount ? scount : sk;
1890     
1891     scount    -= sk;
1892     ieb->cpos += sk;
1893     ieb->gpos += sk;
1894   }
1895   
1896   wrlen = scount;
1897
1898   if (wrlen > 0) { 
1899     /*
1900      * extending file - get ieb into consistent state and then
1901      * call write which will get it to the correct position 
1902      */
1903     char TB[BBSIZ];
1904     memset(TB, 0, BBSIZ);
1905     ieb->gpos = ieb->length;
1906     ieb->cpos = ieb->tfill;
1907     
1908     while(wrlen > 0) {
1909       ssize_t rc, wl = i_min(wrlen, BBSIZ);
1910       im_log((aIMCTX, 1, "bufchain_seek: wrlen = %d, wl = %ld\n", wrlen, (long)wl));
1911       rc = bufchain_write( ig, TB, wl );
1912       if (rc != wl) im_fatal(aIMCTX, 0, "bufchain_seek: Unable to extend file\n");
1913       wrlen -= rc;
1914     }
1915   }
1916
1917   im_log((aIMCTX, 2, "bufchain_seek: returning ieb->gpos = %ld\n", (long)ieb->gpos));
1918   return ieb->gpos;
1919 }
1920
1921 static
1922 void
1923 bufchain_destroy(io_glue *ig) {
1924   io_ex_bchain *ieb = ig->exdata;
1925
1926   io_destroy_bufchain(ieb);
1927
1928   myfree(ieb);
1929 }
1930
1931 /*
1932 =item fd_read(ig, buf, count)
1933
1934 Read callback for file descriptor IO objects.
1935
1936 =cut
1937 */
1938 static ssize_t fd_read(io_glue *igo, void *buf, size_t count) {
1939   io_fdseek *ig = (io_fdseek *)igo;
1940   ssize_t result;
1941 #ifdef _MSC_VER
1942   result = _read(ig->fd, buf, count);
1943 #else
1944   result = read(ig->fd, buf, count);
1945 #endif
1946
1947   IOL_DEB(fprintf(IOL_DEBs, "fd_read(%p, %p, %u) => %d\n", ig, buf,
1948                   (unsigned)count, (int)result));
1949
1950   /* 0 is valid - means EOF */
1951   if (result < 0) {
1952     dIMCTXio(igo);
1953     im_push_errorf(aIMCTX, 0, "read() failure: %s (%d)", my_strerror(errno), errno);
1954   }
1955
1956   return result;
1957 }
1958
1959 static ssize_t fd_write(io_glue *igo, const void *buf, size_t count) {
1960   io_fdseek *ig = (io_fdseek *)igo;
1961   ssize_t result;
1962 #ifdef _MSC_VER
1963   result = _write(ig->fd, buf, count);
1964 #else
1965   result = write(ig->fd, buf, count);
1966 #endif
1967
1968   IOL_DEB(fprintf(IOL_DEBs, "fd_write(%p, %p, %u) => %d\n", ig, buf,
1969                   (unsigned)count, (int)result));
1970
1971   if (result <= 0) {
1972     dIMCTXio(igo);
1973     im_push_errorf(aIMCTX, errno, "write() failure: %s (%d)", my_strerror(errno), errno);
1974   }
1975
1976   return result;
1977 }
1978
1979 static off_t fd_seek(io_glue *igo, off_t offset, int whence) {
1980   io_fdseek *ig = (io_fdseek *)igo;
1981   off_t result;
1982 #ifdef _MSC_VER
1983   result = _lseek(ig->fd, offset, whence);
1984 #else
1985   result = lseek(ig->fd, offset, whence);
1986 #endif
1987
1988   if (result == (off_t)-1) {
1989     dIMCTXio(igo);
1990     im_push_errorf(aIMCTX, errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
1991   }
1992
1993   return result;
1994 }
1995
1996 static int fd_close(io_glue *ig) {
1997   /* no, we don't close it */
1998   return 0;
1999 }
2000
2001 static ssize_t fd_size(io_glue *ig) {
2002   dIMCTXio(ig);
2003   im_log((aIMCTX, 1, "fd_size(ig %p) unimplemented\n", ig));
2004   
2005   return -1;
2006 }
2007
2008
2009 /*
2010 =back
2011
2012 =head1 AUTHOR
2013
2014 Arnar M. Hrafnkelsson <addi@umich.edu>
2015
2016 =head1 SEE ALSO
2017
2018 Imager(3)
2019
2020 =cut
2021 */