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