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