add new comparison method rgb_difference that resembles arithmetical difference per...
[imager.git] / iolayer.c
index 478ef95..3bc9979 100644 (file)
--- a/iolayer.c
+++ b/iolayer.c
@@ -1,3 +1,4 @@
+#define IMAGER_NO_CONTEXT
 #include "imager.h"
 #include "iolayer.h"
 #include "imerror.h"
@@ -113,8 +114,8 @@ Some of these functions are internal.
 */
 
 static void
-i_io_init(io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb,
-         i_io_seekp_t seekcb);
+i_io_init(pIMCTX, io_glue *ig, int type, i_io_readp_t readcb,
+         i_io_writep_t writecb, i_io_seekp_t seekcb);
 
 static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
@@ -153,26 +154,29 @@ static void bufchain_destroy(io_glue *ig);
  */
 
 /*
-=item io_new_bufchain()
+=item im_io_new_bufchain(ctx)
+X<im_io_new_bufchain API>X<i_io_new_bufchain API>
 =order 10
 =category I/O Layers
 
-returns a new io_glue object that has the 'empty' source and but can
+Returns a new io_glue object that has the 'empty' source and but can
 be written to and read from later (like a pseudo file).
 
+Also callable as C<io_new_bufchain()>.
+
 =cut
 */
 
 io_glue *
-io_new_bufchain() {
+im_io_new_bufchain(pIMCTX) {
   io_glue *ig;
   io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
 
-  mm_log((1, "io_new_bufchain()\n"));
+  im_log((aIMCTX, 1, "io_new_bufchain()\n"));
 
   ig = mymalloc(sizeof(io_glue));
   memset(ig, 0, sizeof(*ig));
-  i_io_init(ig, BUFCHAIN, bufchain_read, bufchain_write, bufchain_seek);
+  i_io_init(aIMCTX, ig, BUFCHAIN, bufchain_read, bufchain_write, bufchain_seek);
 
   ieb->offset = 0;
   ieb->length = 0;
@@ -188,32 +192,38 @@ io_new_bufchain() {
   ig->closecb   = bufchain_close;
   ig->destroycb = bufchain_destroy;
 
+  im_context_refinc(aIMCTX, "im_io_new_bufchain");
+
   return ig;
 }
 
 /*
-=item io_new_buffer(data, length)
+=item im_io_new_buffer(ctx, data, length)
+X<im_io_new_buffer API>X<io_new_buffer API>
 =order 10
 =category I/O Layers
 
 Returns a new io_glue object that has the source defined as reading
 from specified buffer.  Note that the buffer is not copied.
 
+   ctx - an Imager context object
    data - buffer to read from
    length - length of buffer
 
+Also callable as C<io_new_buffer(data, length>.
+
 =cut
 */
 
 io_glue *
-io_new_buffer(const char *data, size_t len, i_io_closebufp_t closecb, void *closedata) {
+im_io_new_buffer(pIMCTX, const char *data, size_t len, i_io_closebufp_t closecb, void *closedata) {
   io_buffer *ig;
   
-  mm_log((1, "io_new_buffer(data %p, len %ld, closecb %p, closedata %p)\n", data, (long)len, closecb, closedata));
+  im_log((aIMCTX, 1, "io_new_buffer(data %p, len %ld, closecb %p, closedata %p)\n", data, (long)len, closecb, closedata));
 
   ig = mymalloc(sizeof(io_buffer));
   memset(ig, 0, sizeof(*ig));
-  i_io_init(&ig->base, BUFFER, buffer_read, buffer_write, buffer_seek);
+  i_io_init(aIMCTX, &ig->base, BUFFER, buffer_read, buffer_write, buffer_seek);
   ig->data      = data;
   ig->len       = len;
   ig->closecb   = closecb;
@@ -224,45 +234,53 @@ io_new_buffer(const char *data, size_t len, i_io_closebufp_t closecb, void *clos
   ig->base.closecb   = buffer_close;
   ig->base.destroycb = buffer_destroy;
 
+  im_context_refinc(aIMCTX, "im_io_new_bufchain");
+
   return (io_glue *)ig;
 }
 
 
 /*
-=item io_new_fd(fd)
+=item im_io_new_fd(ctx, file)
+X<io_new_fd API>X<im_io_new_fd API>
 =order 10
 =category I/O Layers
 
-returns a new io_glue object that has the source defined as reading
-from specified file descriptor.  Note that the the interface to receiving
+Returns a new io_glue object that has the source defined as reading
+from specified file descriptor.  Note that the interface to receiving
 data from the io_glue callbacks hasn't been done yet.
 
-   fd - file descriptor to read/write from
+  ctx - and Imager context object
+  file - file descriptor to read/write from
+
+Also callable as C<io_new_fd(file)>.
 
 =cut
 */
 
 io_glue *
-io_new_fd(int fd) {
+im_io_new_fd(pIMCTX, int fd) {
   io_fdseek *ig;
 
-  mm_log((1, "io_new_fd(fd %d)\n", fd));
+  im_log((aIMCTX, 1, "io_new_fd(fd %d)\n", fd));
 
   ig = mymalloc(sizeof(io_fdseek));
   memset(ig, 0, sizeof(*ig));
-  i_io_init(&ig->base, FDSEEK, fd_read, fd_write, fd_seek);
+  i_io_init(aIMCTX, &ig->base, FDSEEK, fd_read, fd_write, fd_seek);
   ig->fd = fd;
 
   ig->base.closecb   = fd_close;
   ig->base.sizecb    = fd_size;
   ig->base.destroycb = NULL;
+  im_context_refinc(aIMCTX, "im_io_new_bufchain");
 
-  mm_log((1, "(%p) <- io_new_fd\n", ig));
+  im_log((aIMCTX, 1, "(%p) <- io_new_fd\n", ig));
   return (io_glue *)ig;
 }
 
 /*
-=item io_new_cb(p, read_cb, write_cb, seek_cb, close_cb, destroy_cb)
+=item im_io_new_cb(ctx, p, read_cb, write_cb, seek_cb, close_cb, destroy_cb)
+X<im_io_new_cb API>X<io_new_cb API>
 =category I/O Layers
 =order 10
 
@@ -300,21 +318,24 @@ handlers.
 
 =back
 
+Also callable as C<io_new_cb(p, readcb, writecb, seekcb, closecb,
+destroycb)>.
+
 =cut
 */
 
 io_glue *
-io_new_cb(void *p, i_io_readl_t readcb, i_io_writel_t writecb, 
+im_io_new_cb(pIMCTX, void *p, i_io_readl_t readcb, i_io_writel_t writecb, 
          i_io_seekl_t seekcb, i_io_closel_t closecb, 
          i_io_destroyl_t destroycb) {
   io_cb *ig;
 
-  mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
+  im_log((aIMCTX, 1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
           "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
   ig = mymalloc(sizeof(io_cb));
   memset(ig, 0, sizeof(*ig));
-  i_io_init(&ig->base, CBSEEK, realseek_read, realseek_write, realseek_seek);
-  mm_log((1, "(%p) <- io_new_cb\n", ig));
+  i_io_init(aIMCTX, &ig->base, CBSEEK, realseek_read, realseek_write, realseek_seek);
+  im_log((aIMCTX, 1, "(%p) <- io_new_cb\n", ig));
 
   ig->base.closecb   = realseek_close;
   ig->base.destroycb = realseek_destroy;
@@ -325,12 +346,15 @@ io_new_cb(void *p, i_io_readl_t readcb, i_io_writel_t writecb,
   ig->seekcb    = seekcb;
   ig->closecb   = closecb;
   ig->destroycb = destroycb;
+  
+  im_context_refinc(aIMCTX, "im_io_new_bufchain");
 
   return (io_glue *)ig;
 }
 
 /*
 =item io_slurp(ig, c)
+X<io_slurp API>
 =category I/O Layers
 
 Takes the source that the io_glue is bound to and allocates space for
@@ -355,32 +379,33 @@ from io_new_bufchain().
 size_t
 io_slurp(io_glue *ig, unsigned char **c) {
   ssize_t rc;
-  off_t orgoff;
   io_ex_bchain *ieb;
   unsigned char *cc;
   io_type inn = ig->type;
   
   if ( inn != BUFCHAIN ) {
-    i_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
+    dIMCTXio(ig);
+    im_fatal(aIMCTX, 0, "io_slurp: called on a source that is not from a bufchain\n");
   }
 
   ieb = ig->exdata;
   cc = *c = mymalloc( ieb->length );
   
-  orgoff = ieb->gpos;
-  
   bufchain_seek(ig, 0, SEEK_SET);
   
   rc = bufchain_read(ig, cc, ieb->length);
 
-  if (rc != ieb->length)
-    i_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
+  if (rc != ieb->length) {
+    dIMCTXio(ig);
+    im_fatal(aIMCTX,1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
+  }
 
   return rc;
 }
 
 /*
 =item io_glue_destroy(ig)
+X<io_glue_destroy API>
 =category I/O Layers
 =order 90
 =synopsis io_glue_destroy(ig);
@@ -394,7 +419,8 @@ Destroy an io_glue objects.  Should clean up all related buffers.
 
 void
 io_glue_destroy(io_glue *ig) {
-  mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
+  dIMCTXio(ig);
+  im_log((aIMCTX, 1, "io_glue_DESTROY(ig %p)\n", ig));
 
   if (ig->destroycb)
     ig->destroycb(ig);
@@ -403,6 +429,8 @@ io_glue_destroy(io_glue *ig) {
     myfree(ig->buffer);
   
   myfree(ig);
+
+  im_context_refdec(aIMCTX, "io_glue_destroy");
 }
 
 /*
@@ -527,6 +555,7 @@ i_io_peekn(io_glue *ig, void *buf, size_t size) {
   IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn(%p, %p, %d)\n", ig, buf, (int)size));
 
   if (size == 0) {
+    dIMCTXio(ig);
     i_push_error(0, "peekn size must be positive");
     IOL_DEB(fprintf(IOL_DEBs, "i_io_peekn() => -1 (zero size)\n"));
     return -1;
@@ -974,7 +1003,7 @@ Do common initialization for io_glue objects.
 */
 
 static void
-i_io_init(io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb,
+i_io_init(pIMCTX, io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb,
          i_io_seekp_t seekcb) {
   ig->type = type;
   ig->exdata = NULL;
@@ -984,6 +1013,7 @@ i_io_init(io_glue *ig, int type, i_io_readp_t readcb, i_io_writep_t writecb,
   ig->closecb = NULL;
   ig->sizecb = NULL;
   ig->destroycb = NULL;
+  ig->context = aIMCTX;
 
   ig->buffer = NULL;
   ig->read_ptr = NULL;
@@ -1154,6 +1184,9 @@ i_io_read_fill(io_glue *ig, ssize_t needed) {
     work = ig->buffer;
   }
 
+  /* there should always be buffer space the first time around, but
+     avoid a compiler warning here */
+  rc = -1;
   while (work < buf_end && (rc = i_io_raw_read(ig, work, buf_end - work)) > 0) {
     work += rc;
     good = 1;
@@ -1328,9 +1361,10 @@ static
 int
 realseek_close(io_glue *igo) {
   io_cb *ig = (io_cb *)igo;
+  dIMCTXio(igo);
 
   IOL_DEB(fprintf(IOL_DEBs, "realseek_close(%p)\n", ig));
-  mm_log((1, "realseek_close(ig %p)\n", ig));
+  im_log((aIMCTX,1, "realseek_close(ig %p)\n", ig));
   if (ig->closecb)
     return ig->closecb(ig->p);
   else
@@ -1338,7 +1372,8 @@ realseek_close(io_glue *igo) {
 }
 
 
-/* realseek_seek(ig, offset, whence)
+/*
+=item realseek_seek(ig, offset, whence)
 
 Implements seeking for a source that is seekable, the purpose of having this is to be able to
 have an offset into a file that is different from what the underlying library thinks.
@@ -1397,7 +1432,8 @@ buffer_read(io_glue *igo, void *buf, size_t count) {
   IOL_DEB( fprintf(IOL_DEBs, "buffer_read: ig->cpos = %ld, buf = %p, count = %u\n", (long) ig->cpos, buf, (unsigned)count) );
 
   if ( ig->cpos+count > ig->len ) {
-    mm_log((1,"buffer_read: short read: cpos=%ld, len=%ld, count=%ld\n", (long)ig->cpos, (long)ig->len, (long)count));
+    dIMCTXio(igo);
+    im_log((aIMCTX, 1,"buffer_read: short read: cpos=%ld, len=%ld, count=%ld\n", (long)ig->cpos, (long)ig->len, (long)count));
     count = ig->len - ig->cpos;
   }
   
@@ -1423,7 +1459,8 @@ Does nothing, returns -1
 static
 ssize_t 
 buffer_write(io_glue *ig, const void *buf, size_t count) {
-  mm_log((1, "buffer_write called, this method should never be called.\n"));
+  dIMCTXio(ig);
+  im_log((aIMCTX, 1, "buffer_write called, this method should never be called.\n"));
   return -1;
 }
 
@@ -1442,13 +1479,15 @@ or not.  Does nothing for now.  Should be fixed.
 static
 int
 buffer_close(io_glue *ig) {
-  mm_log((1, "buffer_close(ig %p)\n", ig));
+  dIMCTXio(ig);
+  im_log((aIMCTX, 1, "buffer_close(ig %p)\n", ig));
 
   return 0;
 }
 
 
-/* buffer_seek(ig, offset, whence)
+/*
+=item buffer_seek(ig, offset, whence)
 
 Implements seeking for a buffer source.
 
@@ -1467,10 +1506,12 @@ buffer_seek(io_glue *igo, off_t offset, int whence) {
     calc_seek_offset(ig->cpos, ig->len, offset, whence);
   
   if (reqpos > ig->len) {
-    mm_log((1, "seeking out of readable range\n"));
+    dIMCTXio(igo);
+    im_log((aIMCTX, 1, "seeking out of readable range\n"));
     return (off_t)-1;
   }
   if (reqpos < 0) {
+    dIMCTXio(igo);
     i_push_error(0, "seek before beginning of file");
     return (off_t)-1;
   }
@@ -1488,7 +1529,8 @@ buffer_destroy(io_glue *igo) {
   io_buffer *ig = (io_buffer *)igo;
 
   if (ig->closecb) {
-    mm_log((1,"calling close callback %p for io_buffer\n", 
+    dIMCTXio(igo);
+    im_log((aIMCTX, 1,"calling close callback %p for io_buffer\n", 
            ig->closecb));
     ig->closecb(ig->closedata);
   }
@@ -1509,7 +1551,9 @@ io_blink*
 io_blink_new(void) {
   io_blink *ib;
 
-  mm_log((1, "io_blink_new()\n"));
+#if 0
+  im_log((aIMCTX, 1, "io_blink_new()\n"));
+#endif
 
   ib = mymalloc(sizeof(io_blink));
 
@@ -1561,7 +1605,9 @@ frees all resources used by a buffer chain.
 static void
 io_destroy_bufchain(io_ex_bchain *ieb) {
   io_blink *cp;
+#if 0
   mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
+#endif
   cp = ieb->head;
   
   while(cp) {
@@ -1692,8 +1738,9 @@ bufchain_read(io_glue *ig, void *buf, size_t count) {
   size_t     scount = count;
   char        *cbuf = buf;
   size_t         sk;
+  dIMCTXio(ig);
 
-  mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, (long)count));
+  im_log((aIMCTX, 1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, (long)count));
 
   while( scount ) {
     int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
@@ -1713,7 +1760,7 @@ bufchain_read(io_glue *ig, void *buf, size_t count) {
     ieb->gpos += sk;
   }
 
-  mm_log((1, "bufchain_read: returning %ld\n", (long)(count-scount)));
+  im_log((aIMCTX, 1, "bufchain_read: returning %ld\n", (long)(count-scount)));
   return count-scount;
 }
 
@@ -1740,15 +1787,16 @@ bufchain_write(io_glue *ig, const void *buf, size_t count) {
   io_ex_bchain *ieb = ig->exdata;
   size_t         ocount = count;
   size_t         sk;
+  dIMCTXio(ig);
 
-  mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %ld\n", ig, buf, (long)count));
+  im_log((aIMCTX, 1, "bufchain_write: ig = %p, buf = %p, count = %ld\n", ig, buf, (long)count));
 
   IOL_DEB( fprintf(IOL_DEBs, "bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %ld\n", ig, (long) ieb->cpos, buf, (long)count) );
   
   while(count) {
-    mm_log((2, "bufchain_write: - looping - count = %ld\n", (long)count));
+    im_log((aIMCTX, 2, "bufchain_write: - looping - count = %ld\n", (long)count));
     if (ieb->cp->len == ieb->cpos) {
-      mm_log((1, "bufchain_write: cp->len == ieb->cpos = %ld - advancing chain\n", (long) ieb->cpos));
+      im_log((aIMCTX, 1, "bufchain_write: cp->len == ieb->cpos = %ld - advancing chain\n", (long) ieb->cpos));
       io_bchain_advance(ieb);
     }
 
@@ -1758,7 +1806,7 @@ bufchain_write(io_glue *ig, const void *buf, size_t count) {
 
     if (ieb->cp == ieb->tail) {
       int extend = ieb->cpos + sk - ieb->tfill;
-      mm_log((2, "bufchain_write: extending tail by %d\n", extend));
+      im_log((aIMCTX, 2, "bufchain_write: extending tail by %d\n", extend));
       if (extend > 0) {
        ieb->length += extend;
        ieb->tfill  += extend;
@@ -1786,14 +1834,16 @@ or not.  Does nothing for now.  Should be fixed.
 static
 int
 bufchain_close(io_glue *ig) {
-  mm_log((1, "bufchain_close(ig %p)\n",ig));
+  dIMCTXio(ig);
+  im_log((aIMCTX, 1, "bufchain_close(ig %p)\n",ig));
   IOL_DEB( fprintf(IOL_DEBs, "bufchain_close(ig %p)\n", ig) );
 
   return 0;  
 }
 
 
-/* bufchain_seek(ig, offset, whence)
+/*
+=item bufchain_seek(ig, offset, whence)
 
 Implements seeking for a source that is seekable, the purpose of having this is to be able to
 have an offset into a file that is different from what the underlying library thinks.
@@ -1813,8 +1863,9 @@ bufchain_seek(io_glue *ig, off_t offset, int whence) {
 
   off_t scount = calc_seek_offset(ieb->gpos, ieb->length, offset, whence);
   off_t sk;
+  dIMCTXio(ig);
 
-  mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, (long)offset, whence));
+  im_log((aIMCTX, 1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, (long)offset, whence));
 
   if (scount < 0) {
     i_push_error(0, "invalid whence supplied or seek before start of file");
@@ -1856,14 +1907,14 @@ bufchain_seek(io_glue *ig, off_t offset, int whence) {
     
     while(wrlen > 0) {
       ssize_t rc, wl = i_min(wrlen, BBSIZ);
-      mm_log((1, "bufchain_seek: wrlen = %d, wl = %ld\n", wrlen, (long)wl));
+      im_log((aIMCTX, 1, "bufchain_seek: wrlen = %d, wl = %ld\n", wrlen, (long)wl));
       rc = bufchain_write( ig, TB, wl );
-      if (rc != wl) i_fatal(0, "bufchain_seek: Unable to extend file\n");
+      if (rc != wl) im_fatal(aIMCTX, 0, "bufchain_seek: Unable to extend file\n");
       wrlen -= rc;
     }
   }
 
-  mm_log((2, "bufchain_seek: returning ieb->gpos = %ld\n", (long)ieb->gpos));
+  im_log((aIMCTX, 2, "bufchain_seek: returning ieb->gpos = %ld\n", (long)ieb->gpos));
   return ieb->gpos;
 }
 
@@ -1898,7 +1949,8 @@ static ssize_t fd_read(io_glue *igo, void *buf, size_t count) {
 
   /* 0 is valid - means EOF */
   if (result < 0) {
-    i_push_errorf(0, "read() failure: %s (%d)", my_strerror(errno), errno);
+    dIMCTXio(igo);
+    im_push_errorf(aIMCTX, 0, "read() failure: %s (%d)", my_strerror(errno), errno);
   }
 
   return result;
@@ -1917,7 +1969,8 @@ static ssize_t fd_write(io_glue *igo, const void *buf, size_t count) {
                  (unsigned)count, (int)result));
 
   if (result <= 0) {
-    i_push_errorf(errno, "write() failure: %s (%d)", my_strerror(errno), errno);
+    dIMCTXio(igo);
+    im_push_errorf(aIMCTX, errno, "write() failure: %s (%d)", my_strerror(errno), errno);
   }
 
   return result;
@@ -1933,7 +1986,8 @@ static off_t fd_seek(io_glue *igo, off_t offset, int whence) {
 #endif
 
   if (result == (off_t)-1) {
-    i_push_errorf(errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
+    dIMCTXio(igo);
+    im_push_errorf(aIMCTX, errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
   }
 
   return result;
@@ -1945,7 +1999,8 @@ static int fd_close(io_glue *ig) {
 }
 
 static ssize_t fd_size(io_glue *ig) {
-  mm_log((1, "fd_size(ig %p) unimplemented\n", ig));
+  dIMCTXio(ig);
+  im_log((aIMCTX, 1, "fd_size(ig %p) unimplemented\n", ig));
   
   return -1;
 }