improved thread safety for Imager
[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   while (work < buf_end && (rc = i_io_raw_read(ig, work, buf_end - work)) > 0) {
1191     work += rc;
1192     good = 1;
1193     if (needed < rc)
1194       break;
1195
1196     needed -= rc;
1197   }
1198
1199   if (rc < 0) {
1200     ig->error = 1;
1201     IOL_DEB(fprintf(IOL_DEBs, " i_io_read_fill -> rc %d, setting error\n",
1202                     (int)rc));
1203   }
1204   else if (rc == 0) {
1205     ig->buf_eof = 1;
1206     IOL_DEB(fprintf(IOL_DEBs, " i_io_read_fill -> rc 0, setting eof\n"));
1207   }
1208
1209   if (good) {
1210     ig->read_ptr = buf_start;
1211     ig->read_end = work;
1212   }
1213   
1214   IOL_DEB(fprintf(IOL_DEBs, "i_io_read_fill => %d, %u buffered\n", good,
1215                   (unsigned)(ig->read_end - ig->read_ptr)));
1216   return good;
1217 }
1218
1219 /*
1220 =item dump_data(start, end, bias)
1221
1222 Hex dump the data between C<start> and C<end>.
1223
1224 If there is more than a pleasing amount of data, either dump the
1225 beginning (C<bias == 0>) or dump the end C(<bias != 0>) of the range.
1226
1227 =cut
1228 */
1229
1230 static void
1231 dump_data(unsigned char *start, unsigned char *end, int bias) {
1232   unsigned char *p;
1233   size_t count = end - start;
1234
1235   if (start == end) {
1236     fprintf(IOL_DEBs, "(empty)");
1237     return;
1238   }
1239
1240   if (count > 15) {
1241     if (bias) {
1242       fprintf(IOL_DEBs, "... ");
1243       start = end - 14;
1244     }
1245     else {
1246       end = start + 14;
1247     }
1248       
1249     for (p = start; p < end; ++p) {
1250       fprintf(IOL_DEBs, " %02x", *p);
1251     }
1252     putc(' ', IOL_DEBs);
1253     putc('<', IOL_DEBs);
1254     for (p = start; p < end; ++p) {
1255       if (*p < ' ' || *p > '~')
1256         putc('.', IOL_DEBs);
1257       else
1258         putc(*p, IOL_DEBs);
1259     }
1260     putc('>', IOL_DEBs);
1261     if (!bias)
1262       fprintf(IOL_DEBs, " ...");
1263   }
1264   else {
1265     for (p = start; p < end; ++p) {
1266       fprintf(IOL_DEBs, " %02x", *p);
1267     }
1268     putc(' ', IOL_DEBs);
1269     for (p = start; p < end; ++p) {
1270       if (*p < ' ' || *p > '~')
1271         putc('.', IOL_DEBs);
1272       else
1273         putc(*p, IOL_DEBs);
1274     }
1275   }
1276 }
1277
1278 /*
1279  * Callbacks for sources that cannot seek
1280  */
1281
1282 /*
1283  * Callbacks for sources that can seek 
1284  */
1285
1286 /*
1287 =item realseek_read(ig, buf, count)
1288
1289 Does the reading from a source that can be seeked on
1290
1291    ig    - io_glue object
1292    buf   - buffer to return data in
1293    count - number of bytes to read into buffer max
1294
1295 =cut
1296 */
1297
1298 static
1299 ssize_t 
1300 realseek_read(io_glue *igo, void *buf, size_t count) {
1301   io_cb        *ig = (io_cb *)igo;
1302   void *p          = ig->p;
1303   ssize_t       rc = 0;
1304
1305   IOL_DEB( fprintf(IOL_DEBs, "realseek_read:  buf = %p, count = %u\n", 
1306                    buf, (unsigned)count) );
1307   rc = ig->readcb(p,buf,count);
1308
1309   IOL_DEB( fprintf(IOL_DEBs, "realseek_read: rc = %d\n", (int)rc) );
1310
1311   return rc;
1312 }
1313
1314
1315 /*
1316 =item realseek_write(ig, buf, count)
1317
1318 Does the writing to a 'source' that can be seeked on
1319
1320    ig    - io_glue object
1321    buf   - buffer that contains data
1322    count - number of bytes to write
1323
1324 =cut
1325 */
1326
1327 static
1328 ssize_t 
1329 realseek_write(io_glue *igo, const void *buf, size_t count) {
1330   io_cb        *ig = (io_cb *)igo;
1331   void          *p = ig->p;
1332   ssize_t       rc = 0;
1333   size_t        bc = 0;
1334   char       *cbuf = (char*)buf; 
1335   
1336   IOL_DEB( fprintf(IOL_DEBs, "realseek_write: ig = %p, buf = %p, "
1337                    "count = %u\n", ig, buf, (unsigned)count) );
1338
1339   /* Is this a good idea? Would it be better to handle differently? 
1340      skip handling? */
1341   while( count!=bc && (rc = ig->writecb(p,cbuf+bc,count-bc))>0 ) {
1342     bc+=rc;
1343   }
1344
1345   IOL_DEB( fprintf(IOL_DEBs, "realseek_write: rc = %d, bc = %u\n", (int)rc, (unsigned)bc) );
1346   return rc < 0 ? rc : bc;
1347 }
1348
1349
1350 /*
1351 =item realseek_close(ig)
1352
1353 Closes a source that can be seeked on.  Not sure if this should be an
1354 actual close or not.  Does nothing for now.  Should be fixed.
1355
1356    ig - data source
1357
1358 =cut */
1359
1360 static
1361 int
1362 realseek_close(io_glue *igo) {
1363   io_cb *ig = (io_cb *)igo;
1364   dIMCTXio(igo);
1365
1366   IOL_DEB(fprintf(IOL_DEBs, "realseek_close(%p)\n", ig));
1367   im_log((aIMCTX,1, "realseek_close(ig %p)\n", ig));
1368   if (ig->closecb)
1369     return ig->closecb(ig->p);
1370   else
1371     return 0;
1372 }
1373
1374
1375 /* realseek_seek(ig, offset, whence)
1376
1377 Implements seeking for a source that is seekable, the purpose of having this is to be able to
1378 have an offset into a file that is different from what the underlying library thinks.
1379
1380    ig     - data source
1381    offset - offset into stream
1382    whence - whence argument a la lseek
1383
1384 =cut
1385 */
1386
1387 static
1388 off_t
1389 realseek_seek(io_glue *igo, off_t offset, int whence) {
1390   io_cb *ig = (io_cb *)igo;
1391   void *p = ig->p;
1392   off_t rc;
1393   IOL_DEB( fprintf(IOL_DEBs, "realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
1394   rc = ig->seekcb(p, offset, whence);
1395
1396   IOL_DEB( fprintf(IOL_DEBs, "realseek_seek: rc %ld\n", (long) rc) );
1397   return rc;
1398   /* FIXME: How about implementing this offset handling stuff? */
1399 }
1400
1401 static
1402 void
1403 realseek_destroy(io_glue *igo) {
1404   io_cb *ig = (io_cb *)igo;
1405
1406   if (ig->destroycb)
1407     ig->destroycb(ig->p);
1408 }
1409
1410 /*
1411  * Callbacks for sources that are a fixed size buffer
1412  */
1413
1414 /*
1415 =item buffer_read(ig, buf, count)
1416
1417 Does the reading from a buffer source
1418
1419    ig    - io_glue object
1420    buf   - buffer to return data in
1421    count - number of bytes to read into buffer max
1422
1423 =cut
1424 */
1425
1426 static
1427 ssize_t 
1428 buffer_read(io_glue *igo, void *buf, size_t count) {
1429   io_buffer *ig = (io_buffer *)igo;
1430
1431   IOL_DEB( fprintf(IOL_DEBs, "buffer_read: ig->cpos = %ld, buf = %p, count = %u\n", (long) ig->cpos, buf, (unsigned)count) );
1432
1433   if ( ig->cpos+count > ig->len ) {
1434     dIMCTXio(igo);
1435     im_log((aIMCTX, 1,"buffer_read: short read: cpos=%ld, len=%ld, count=%ld\n", (long)ig->cpos, (long)ig->len, (long)count));
1436     count = ig->len - ig->cpos;
1437   }
1438   
1439   memcpy(buf, ig->data+ig->cpos, count);
1440   ig->cpos += count;
1441   IOL_DEB( fprintf(IOL_DEBs, "buffer_read: count = %ld\n", (long)count) );
1442   return count;
1443 }
1444
1445
1446 /*
1447 =item buffer_write(ig, buf, count)
1448
1449 Does nothing, returns -1
1450
1451    ig    - io_glue object
1452    buf   - buffer that contains data
1453    count - number of bytes to write
1454
1455 =cut
1456 */
1457
1458 static
1459 ssize_t 
1460 buffer_write(io_glue *ig, const void *buf, size_t count) {
1461   dIMCTXio(ig);
1462   im_log((aIMCTX, 1, "buffer_write called, this method should never be called.\n"));
1463   return -1;
1464 }
1465
1466
1467 /*
1468 =item buffer_close(ig)
1469
1470 Closes a source that can be seeked on.  Not sure if this should be an actual close
1471 or not.  Does nothing for now.  Should be fixed.
1472
1473    ig - data source
1474
1475 =cut
1476 */
1477
1478 static
1479 int
1480 buffer_close(io_glue *ig) {
1481   dIMCTXio(ig);
1482   im_log((aIMCTX, 1, "buffer_close(ig %p)\n", ig));
1483
1484   return 0;
1485 }
1486
1487
1488 /* buffer_seek(ig, offset, whence)
1489
1490 Implements seeking for a buffer source.
1491
1492    ig     - data source
1493    offset - offset into stream
1494    whence - whence argument a la lseek
1495
1496 =cut
1497 */
1498
1499 static
1500 off_t
1501 buffer_seek(io_glue *igo, off_t offset, int whence) {
1502   io_buffer *ig = (io_buffer *)igo;
1503   off_t reqpos = 
1504     calc_seek_offset(ig->cpos, ig->len, offset, whence);
1505   
1506   if (reqpos > ig->len) {
1507     dIMCTXio(igo);
1508     im_log((aIMCTX, 1, "seeking out of readable range\n"));
1509     return (off_t)-1;
1510   }
1511   if (reqpos < 0) {
1512     dIMCTXio(igo);
1513     i_push_error(0, "seek before beginning of file");
1514     return (off_t)-1;
1515   }
1516   
1517   ig->cpos = reqpos;
1518   IOL_DEB( fprintf(IOL_DEBs, "buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
1519
1520   return reqpos;
1521   /* FIXME: How about implementing this offset handling stuff? */
1522 }
1523
1524 static
1525 void
1526 buffer_destroy(io_glue *igo) {
1527   io_buffer *ig = (io_buffer *)igo;
1528
1529   if (ig->closecb) {
1530     dIMCTXio(igo);
1531     im_log((aIMCTX, 1,"calling close callback %p for io_buffer\n", 
1532             ig->closecb));
1533     ig->closecb(ig->closedata);
1534   }
1535 }
1536
1537
1538
1539 /*
1540  * Callbacks for sources that are a chain of variable sized buffers
1541  */
1542
1543
1544
1545 /* Helper functions for buffer chains */
1546
1547 static
1548 io_blink*
1549 io_blink_new(void) {
1550   io_blink *ib;
1551
1552 #if 0
1553   im_log((aIMCTX, 1, "io_blink_new()\n"));
1554 #endif
1555
1556   ib = mymalloc(sizeof(io_blink));
1557
1558   ib->next = NULL;
1559   ib->prev = NULL;
1560   ib->len  = BBSIZ;
1561
1562   memset(&ib->buf, 0, ib->len);
1563   return ib;
1564 }
1565
1566
1567
1568 /*
1569 =item io_bchain_advance(ieb)
1570
1571 Advances the buffer chain to the next link - extending if
1572 necessary.  Also adjusts the cpos and tfill counters as needed.
1573
1574    ieb   - buffer chain object
1575
1576 =cut
1577 */
1578
1579 static
1580 void
1581 io_bchain_advance(io_ex_bchain *ieb) {
1582   if (ieb->cp->next == NULL) {
1583     ieb->tail = io_blink_new();
1584     ieb->tail->prev = ieb->cp;
1585     ieb->cp->next   = ieb->tail;
1586
1587     ieb->tfill = 0; /* Only set this if we added a new slice */
1588   }
1589   ieb->cp    = ieb->cp->next;
1590   ieb->cpos  = 0;
1591 }
1592
1593
1594
1595 /*
1596 =item io_bchain_destroy()
1597
1598 frees all resources used by a buffer chain.
1599
1600 =cut
1601 */
1602
1603 static void
1604 io_destroy_bufchain(io_ex_bchain *ieb) {
1605   io_blink *cp;
1606 #if 0
1607   mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
1608 #endif
1609   cp = ieb->head;
1610   
1611   while(cp) {
1612     io_blink *t = cp->next;
1613     myfree(cp);
1614     cp = t;
1615   }
1616 }
1617
1618
1619
1620
1621 /*
1622
1623 static
1624 void
1625 bufchain_dump(io_ex_bchain *ieb) {
1626   mm_log((1, "  buf_chain_dump(ieb %p)\n"));
1627   mm_log((1, "  buf_chain_dump: ieb->offset = %d\n", ieb->offset));
1628   mm_log((1, "  buf_chain_dump: ieb->length = %d\n", ieb->length));
1629   mm_log((1, "  buf_chain_dump: ieb->head   = %p\n", ieb->head  ));
1630   mm_log((1, "  buf_chain_dump: ieb->tail   = %p\n", ieb->tail  ));
1631   mm_log((1, "  buf_chain_dump: ieb->tfill  = %d\n", ieb->tfill ));
1632   mm_log((1, "  buf_chain_dump: ieb->cp     = %p\n", ieb->cp    ));
1633   mm_log((1, "  buf_chain_dump: ieb->cpos   = %d\n", ieb->cpos  ));
1634   mm_log((1, "  buf_chain_dump: ieb->gpos   = %d\n", ieb->gpos  ));
1635 }
1636 */
1637
1638 /*
1639  * TRUE if lengths are NOT equal
1640  */
1641
1642 /*
1643 static
1644 void
1645 chainlencert( io_glue *ig ) {
1646   int clen;
1647   int cfl           = 0;
1648   size_t csize      = 0;
1649   size_t cpos       = 0;
1650   io_ex_bchain *ieb = ig->exdata;
1651   io_blink *cp      = ieb->head;
1652   
1653
1654   if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
1655
1656   while(cp) {
1657     clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
1658     if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
1659     if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
1660     
1661     if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
1662     if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
1663     
1664     if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
1665     if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
1666
1667     if (cp == ieb->cp) {
1668       cfl = 1;
1669       cpos += ieb->cpos;
1670     }
1671
1672     if (!cfl) cpos += clen;
1673
1674     csize += clen;
1675     cp     = cp->next;
1676   }
1677   if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
1678   if (( cpos  != ieb->gpos   )) mm_log((1, "BAR : cpos  = %d, ieb->gpos   = %d\n", cpos,  ieb->gpos  ));
1679 }
1680
1681
1682 static
1683 void
1684 chaincert( io_glue *ig) {
1685   size_t csize   = 0;
1686   io_ex_bchain *ieb = ig->exdata;
1687   io_blink *cp   = ieb->head;
1688   
1689   mm_log((1, "Chain verification.\n"));
1690
1691   mm_log((1, "  buf_chain_dump: ieb->offset = %d\n", ieb->offset));
1692   mm_log((1, "  buf_chain_dump: ieb->length = %d\n", ieb->length));
1693   mm_log((1, "  buf_chain_dump: ieb->head   = %p\n", ieb->head  ));
1694   mm_log((1, "  buf_chain_dump: ieb->tail   = %p\n", ieb->tail  ));
1695   mm_log((1, "  buf_chain_dump: ieb->tfill  = %d\n", ieb->tfill ));
1696   mm_log((1, "  buf_chain_dump: ieb->cp     = %p\n", ieb->cp    ));
1697   mm_log((1, "  buf_chain_dump: ieb->cpos   = %d\n", ieb->cpos  ));
1698   mm_log((1, "  buf_chain_dump: ieb->gpos   = %d\n", ieb->gpos  ));
1699
1700   while(cp) {
1701     int clen = cp == ieb->tail ? ieb->tfill : cp->len;
1702     mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
1703     if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
1704     if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
1705     
1706     if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
1707     if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
1708     
1709     if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
1710     if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
1711
1712     csize += clen;
1713     cp     = cp->next;
1714   }
1715
1716   mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
1717 }
1718 */
1719
1720 /*
1721 =item bufchain_read(ig, buf, count)
1722
1723 Does the reading from a source that can be seeked on
1724
1725    ig    - io_glue object
1726    buf   - buffer to return data in
1727    count - number of bytes to read into buffer max
1728
1729 =cut
1730 */
1731
1732 static
1733 ssize_t 
1734 bufchain_read(io_glue *ig, void *buf, size_t count) {
1735   io_ex_bchain *ieb = ig->exdata;
1736   size_t     scount = count;
1737   char        *cbuf = buf;
1738   size_t         sk;
1739   dIMCTXio(ig);
1740
1741   im_log((aIMCTX, 1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, (long)count));
1742
1743   while( scount ) {
1744     int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
1745     if (clen == ieb->cpos) {
1746       if (ieb->cp == ieb->tail) break; /* EOF */
1747       ieb->cp = ieb->cp->next;
1748       ieb->cpos = 0;
1749       clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
1750     }
1751
1752     sk = clen - ieb->cpos;
1753     sk = sk > scount ? scount : sk;
1754
1755     memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
1756     scount    -= sk;
1757     ieb->cpos += sk;
1758     ieb->gpos += sk;
1759   }
1760
1761   im_log((aIMCTX, 1, "bufchain_read: returning %ld\n", (long)(count-scount)));
1762   return count-scount;
1763 }
1764
1765
1766
1767
1768
1769 /*
1770 =item bufchain_write(ig, buf, count)
1771
1772 Does the writing to a 'source' that can be seeked on
1773
1774    ig    - io_glue object
1775    buf   - buffer that contains data
1776    count - number of bytes to write
1777
1778 =cut
1779 */
1780
1781 static
1782 ssize_t
1783 bufchain_write(io_glue *ig, const void *buf, size_t count) {
1784   char *cbuf = (char *)buf;
1785   io_ex_bchain *ieb = ig->exdata;
1786   size_t         ocount = count;
1787   size_t         sk;
1788   dIMCTXio(ig);
1789
1790   im_log((aIMCTX, 1, "bufchain_write: ig = %p, buf = %p, count = %ld\n", ig, buf, (long)count));
1791
1792   IOL_DEB( fprintf(IOL_DEBs, "bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %ld\n", ig, (long) ieb->cpos, buf, (long)count) );
1793   
1794   while(count) {
1795     im_log((aIMCTX, 2, "bufchain_write: - looping - count = %ld\n", (long)count));
1796     if (ieb->cp->len == ieb->cpos) {
1797       im_log((aIMCTX, 1, "bufchain_write: cp->len == ieb->cpos = %ld - advancing chain\n", (long) ieb->cpos));
1798       io_bchain_advance(ieb);
1799     }
1800
1801     sk = ieb->cp->len - ieb->cpos;
1802     sk = sk > count ? count : sk;
1803     memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
1804
1805     if (ieb->cp == ieb->tail) {
1806       int extend = ieb->cpos + sk - ieb->tfill;
1807       im_log((aIMCTX, 2, "bufchain_write: extending tail by %d\n", extend));
1808       if (extend > 0) {
1809         ieb->length += extend;
1810         ieb->tfill  += extend;
1811       }
1812     }
1813
1814     ieb->cpos += sk;
1815     ieb->gpos += sk;
1816     count     -= sk;
1817   }
1818   return ocount;
1819 }
1820
1821 /*
1822 =item bufchain_close(ig)
1823
1824 Closes a source that can be seeked on.  Not sure if this should be an actual close
1825 or not.  Does nothing for now.  Should be fixed.
1826
1827    ig - data source
1828
1829 =cut
1830 */
1831
1832 static
1833 int
1834 bufchain_close(io_glue *ig) {
1835   dIMCTXio(ig);
1836   im_log((aIMCTX, 1, "bufchain_close(ig %p)\n",ig));
1837   IOL_DEB( fprintf(IOL_DEBs, "bufchain_close(ig %p)\n", ig) );
1838
1839   return 0;  
1840 }
1841
1842
1843 /* bufchain_seek(ig, offset, whence)
1844
1845 Implements seeking for a source that is seekable, the purpose of having this is to be able to
1846 have an offset into a file that is different from what the underlying library thinks.
1847
1848    ig     - data source
1849    offset - offset into stream
1850    whence - whence argument a la lseek
1851
1852 =cut
1853 */
1854
1855 static
1856 off_t
1857 bufchain_seek(io_glue *ig, off_t offset, int whence) {
1858   io_ex_bchain *ieb = ig->exdata;
1859   int wrlen;
1860
1861   off_t scount = calc_seek_offset(ieb->gpos, ieb->length, offset, whence);
1862   off_t sk;
1863   dIMCTXio(ig);
1864
1865   im_log((aIMCTX, 1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, (long)offset, whence));
1866
1867   if (scount < 0) {
1868     i_push_error(0, "invalid whence supplied or seek before start of file");
1869     return (off_t)-1;
1870   }
1871
1872   ieb->cp   = ieb->head;
1873   ieb->cpos = 0;
1874   ieb->gpos = 0;
1875   
1876   while( scount ) {
1877     int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
1878     if (clen == ieb->cpos) {
1879       if (ieb->cp == ieb->tail) break; /* EOF */
1880       ieb->cp = ieb->cp->next;
1881       ieb->cpos = 0;
1882       clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
1883     }
1884     
1885     sk = clen - ieb->cpos;
1886     sk = sk > scount ? scount : sk;
1887     
1888     scount    -= sk;
1889     ieb->cpos += sk;
1890     ieb->gpos += sk;
1891   }
1892   
1893   wrlen = scount;
1894
1895   if (wrlen > 0) { 
1896     /*
1897      * extending file - get ieb into consistent state and then
1898      * call write which will get it to the correct position 
1899      */
1900     char TB[BBSIZ];
1901     memset(TB, 0, BBSIZ);
1902     ieb->gpos = ieb->length;
1903     ieb->cpos = ieb->tfill;
1904     
1905     while(wrlen > 0) {
1906       ssize_t rc, wl = i_min(wrlen, BBSIZ);
1907       im_log((aIMCTX, 1, "bufchain_seek: wrlen = %d, wl = %ld\n", wrlen, (long)wl));
1908       rc = bufchain_write( ig, TB, wl );
1909       if (rc != wl) im_fatal(aIMCTX, 0, "bufchain_seek: Unable to extend file\n");
1910       wrlen -= rc;
1911     }
1912   }
1913
1914   im_log((aIMCTX, 2, "bufchain_seek: returning ieb->gpos = %ld\n", (long)ieb->gpos));
1915   return ieb->gpos;
1916 }
1917
1918 static
1919 void
1920 bufchain_destroy(io_glue *ig) {
1921   io_ex_bchain *ieb = ig->exdata;
1922
1923   io_destroy_bufchain(ieb);
1924
1925   myfree(ieb);
1926 }
1927
1928 /*
1929 =item fd_read(ig, buf, count)
1930
1931 Read callback for file descriptor IO objects.
1932
1933 =cut
1934 */
1935 static ssize_t fd_read(io_glue *igo, void *buf, size_t count) {
1936   io_fdseek *ig = (io_fdseek *)igo;
1937   ssize_t result;
1938 #ifdef _MSC_VER
1939   result = _read(ig->fd, buf, count);
1940 #else
1941   result = read(ig->fd, buf, count);
1942 #endif
1943
1944   IOL_DEB(fprintf(IOL_DEBs, "fd_read(%p, %p, %u) => %d\n", ig, buf,
1945                   (unsigned)count, (int)result));
1946
1947   /* 0 is valid - means EOF */
1948   if (result < 0) {
1949     dIMCTXio(igo);
1950     im_push_errorf(aIMCTX, 0, "read() failure: %s (%d)", my_strerror(errno), errno);
1951   }
1952
1953   return result;
1954 }
1955
1956 static ssize_t fd_write(io_glue *igo, const void *buf, size_t count) {
1957   io_fdseek *ig = (io_fdseek *)igo;
1958   ssize_t result;
1959 #ifdef _MSC_VER
1960   result = _write(ig->fd, buf, count);
1961 #else
1962   result = write(ig->fd, buf, count);
1963 #endif
1964
1965   IOL_DEB(fprintf(IOL_DEBs, "fd_write(%p, %p, %u) => %d\n", ig, buf,
1966                   (unsigned)count, (int)result));
1967
1968   if (result <= 0) {
1969     dIMCTXio(igo);
1970     im_push_errorf(aIMCTX, errno, "write() failure: %s (%d)", my_strerror(errno), errno);
1971   }
1972
1973   return result;
1974 }
1975
1976 static off_t fd_seek(io_glue *igo, off_t offset, int whence) {
1977   io_fdseek *ig = (io_fdseek *)igo;
1978   off_t result;
1979 #ifdef _MSC_VER
1980   result = _lseek(ig->fd, offset, whence);
1981 #else
1982   result = lseek(ig->fd, offset, whence);
1983 #endif
1984
1985   if (result == (off_t)-1) {
1986     dIMCTXio(igo);
1987     im_push_errorf(aIMCTX, errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
1988   }
1989
1990   return result;
1991 }
1992
1993 static int fd_close(io_glue *ig) {
1994   /* no, we don't close it */
1995   return 0;
1996 }
1997
1998 static ssize_t fd_size(io_glue *ig) {
1999   dIMCTXio(ig);
2000   im_log((aIMCTX, 1, "fd_size(ig %p) unimplemented\n", ig));
2001   
2002   return -1;
2003 }
2004
2005
2006 /*
2007 =back
2008
2009 =head1 AUTHOR
2010
2011 Arnar M. Hrafnkelsson <addi@umich.edu>
2012
2013 =head1 SEE ALSO
2014
2015 Imager(3)
2016
2017 =cut
2018 */