]> mj.ucw.cz Git - libucw.git/blobdiff - ucw/fb-multi.c
Table: renamed table_col_order[_by_name] -> table_set_col_order[_by_name]
[libucw.git] / ucw / fb-multi.c
index c9eac1511ed89e75ed10e1010a13e2537c0fd89a..097804c128ccb5a6900903ee71ab1148f96d3d37 100644 (file)
 
 #include <stdio.h>
 
 
 #include <stdio.h>
 
+#define FB_MULTI_NAME "<multi>"
+
 struct fb_multi {
   struct fastbuf fb;
 struct fb_multi {
   struct fastbuf fb;
-  struct mempoolmp;
-  struct subbufcur;
+  struct mempool *mp;
+  struct subbuf *cur;
   ucw_off_t len;
   ucw_off_t len;
-  clist* subbufs;
+  clist subbufs;
 };
 };
+
 #define FB_MULTI(f) ((struct fb_multi *)(f))
 
 struct subbuf {
   cnode n;
 #define FB_MULTI(f) ((struct fb_multi *)(f))
 
 struct subbuf {
   cnode n;
-  ucw_off_t begin, end;
-  struct fastbuffb;
+  ucw_off_t begin, end, offset;
+  struct fastbuf *fb;
 };
 };
-#define SUBBUF(f) ((struct subbuf *)(f))
 
 
-static inline void
-fbmulti_subbuf_get_end(struct subbuf *s)
+static void
+fbmulti_get_ptrs(struct fastbuf *f)
+{
+  struct subbuf *sb = FB_MULTI(f)->cur;
+  struct fastbuf *ff = sb->fb;
+
+  f->buffer = ff->buffer;
+  f->bptr = ff->bptr;
+  f->bstop = ff->bstop;
+  f->bufend = ff->bufend;
+  f->pos = sb->begin + (ff->pos - sb->offset);
+}
+
+static void
+fbmulti_set_ptrs(struct fastbuf *f)
 {
 {
-  if (s->fb->seek) {
-    bseek(s->fb, 0, SEEK_END);
-    s->end = s->begin + btell(s->fb);
-  }
+  FB_MULTI(f)->cur->fb->bptr = f->bptr;
 }
 
 }
 
-static inline int
+static int
 fbmulti_subbuf_next(struct fastbuf *f)
 {
 fbmulti_subbuf_next(struct fastbuf *f)
 {
-  struct subbuf* next = clist_next(FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n);
-  if (next == NULL)
+  struct subbuf *cur = FB_MULTI(f)->cur;
+  struct subbuf *next = clist_next(&FB_MULTI(f)->subbufs, &cur->n);
+  if (!next)
     return 0;
     return 0;
-  
-  if (f->seek) {
-    bseek(FB_MULTI(f)->cur->fb, 0, SEEK_SET);
-    next->begin = FB_MULTI(f)->cur->end;
-  }
 
 
+  // Get the end of current buf if not known yet
+  if (!f->seek && !next->begin)
+    next->begin = cur->end = f->pos;
+
+  // Set the beginning of the next buf
+  if (next->fb->seek)
+    {
+      bsetpos(next->fb, 0);
+      next->offset = 0;
+    }
+  else
+    {
+      ASSERT(!f->seek);
+      next->offset = btell(next->fb);
+    }
+
+  // Set the pointers
   FB_MULTI(f)->cur = next;
   FB_MULTI(f)->cur = next;
+  fbmulti_get_ptrs(f);
+
+  return 1;
+}
+
+static int
+fbmulti_subbuf_prev(struct fastbuf *f)
+{
+  // Called only when seeking, assuming everything seekable
+  struct subbuf *prev = clist_prev(&FB_MULTI(f)->subbufs, &FB_MULTI(f)->cur->n);
+  ASSERT(prev);
+
+  // Set pos to beginning, flush offset
+  bsetpos(prev->fb, 0);
+  prev->offset = 0;
+
+  // Set the pointers
+  FB_MULTI(f)->cur = prev;
+  fbmulti_get_ptrs(f);
+
   return 1;
 }
 
 static int
 fbmulti_refill(struct fastbuf *f)
 {
   return 1;
 }
 
 static int
 fbmulti_refill(struct fastbuf *f)
 {
-  if (f->bufend == f->bstop)
-    f->bptr = f->bstop = f->buffer;
-  uns len = bread(FB_MULTI(f)->cur->fb, f->bstop, (f->bufend - f->bstop));
-  f->bstop += len;
-  f->pos += len;
+  fbmulti_set_ptrs(f);
+
+  // Refill the subbuf
+  uint len = FB_MULTI(f)->cur->fb->refill(FB_MULTI(f)->cur->fb);
   if (len)
   if (len)
-    return len;
+    {
+      fbmulti_get_ptrs(f);
+      return len;
+    }
 
   // Current buf returned EOF
 
   // Current buf returned EOF
-  // Update the information on end of this buffer
-  fbmulti_subbuf_get_end(FB_MULTI(f)->cur);
-
-  // Take the next one if exists
+  // Take the next one if exists and redo
   if (fbmulti_subbuf_next(f))
     return fbmulti_refill(f);
   else
     return 0;
 }
 
   if (fbmulti_subbuf_next(f))
     return fbmulti_refill(f);
   else
     return 0;
 }
 
-static void
-fbmulti_get_len(struct fastbuf *f)
-{
-  ASSERT (f->seek);
-  FB_MULTI(f)->len = 0;
-  
-  CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs))
-    {
-      n->begin = FB_MULTI(f)->len;
-      fbmulti_subbuf_get_end(n);
-      FB_MULTI(f)->len = n->end;
-    }
-}
-
 static int
 fbmulti_seek(struct fastbuf *f, ucw_off_t pos, int whence)
 {
 static int
 fbmulti_seek(struct fastbuf *f, ucw_off_t pos, int whence)
 {
+  fbmulti_set_ptrs(f);
   switch(whence)
     {
     case SEEK_SET:
   switch(whence)
     {
     case SEEK_SET:
-      if (f->pos > pos) {
-       FB_MULTI(f)->cur = clist_head(FB_MULTI(f)->subbufs);
-       FB_MULTI(f)->cur->begin = 0;
-       f->pos = 0;
-       return fbmulti_seek(f, pos, SEEK_SET);
-      }
-
-      do {
-       fbmulti_subbuf_get_end(FB_MULTI(f)->cur);
-       if (pos < FB_MULTI(f)->cur->end)
-         break;
+      if (pos > FB_MULTI(f)->len)
+       bthrow(f, "seek", "Seek out of range");
 
 
-       if (!fbmulti_subbuf_next(f))
-         bthrow(f, "seek", "Seek out of range");
+      while (pos > FB_MULTI(f)->cur->end) // Moving forward
+       {
+         int r = fbmulti_subbuf_next(f);
+         ASSERT(r);
+       }
+
+      while (pos < FB_MULTI(f)->cur->begin) // Moving backwards
+       {
+         int r = fbmulti_subbuf_prev(f);
+         ASSERT(r);
+       }
 
 
-      } while (1);
+      // Now cur is the right buffer.
+      FB_MULTI(f)->cur->fb->seek(FB_MULTI(f)->cur->fb, (pos - FB_MULTI(f)->cur->begin), SEEK_SET);
 
 
-      bseek(FB_MULTI(f)->cur->fb, (pos - FB_MULTI(f)->cur->begin), SEEK_SET);
-      f->pos = pos;
-      f->bptr = f->bstop = f->buffer;
+      fbmulti_get_ptrs(f);
       return 1;
       return 1;
-      break;
 
     case SEEK_END:
 
     case SEEK_END:
-      fbmulti_get_len(f);
-      return fbmulti_seek(f, FB_MULTI(f)->len+pos, SEEK_CUR);
-      break;
+      return fbmulti_seek(f, FB_MULTI(f)->len + pos, SEEK_SET);
 
     default:
       ASSERT(0);
 
     default:
       ASSERT(0);
@@ -131,61 +158,98 @@ fbmulti_seek(struct fastbuf *f, ucw_off_t pos, int whence)
 }
 
 static void
 }
 
 static void
-fbmulti_update_capability(struct fastbuf *f) {
-  // FB Multi is only a proxy to other fastbufs ... if any of them lacks
-  // support of any feature, FB Multi also provides no support of that feature
-  f->refill = fbmulti_refill;
-  f->seek = fbmulti_seek;
+fbmulti_close(struct fastbuf *f)
+{
+  CLIST_FOR_EACH(struct subbuf *, n, FB_MULTI(f)->subbufs)
+    bclose(n->fb);
 
 
-  CLIST_FOR_EACH(struct subbuf *, n, *(FB_MULTI(f)->subbufs)) {
-    if (!n->fb->refill)
-      f->refill = NULL;
+  mp_delete(FB_MULTI(f)->mp);
+}
 
 
-    if (!n->fb->seek)
-      f->seek = NULL;
-  }
+struct fastbuf *
+fbmulti_create(void)
+{
+  struct mempool *mp = mp_new(1024);
+  struct fastbuf *fb_out = mp_alloc_zero(mp, sizeof(struct fb_multi));
+  struct fb_multi *fbm = FB_MULTI(fb_out);
+
+  fbm->mp = mp;
+  fbm->len = 0;
+
+  clist_init(&fbm->subbufs);
+
+  fb_out->name = FB_MULTI_NAME;
+  fb_out->refill = fbmulti_refill;
+  fb_out->seek = fbmulti_seek;
+  fb_out->close = fbmulti_close;
+
+  return fb_out;
 }
 
 }
 
-struct fastbuf*
-fbmulti_create(uns bufsize, ...)
+void
+fbmulti_append(struct fastbuf *f, struct fastbuf *fb)
 {
 {
-  struct mempool *mp = mp_new(bufsize);
-  struct fastbuf *fb_out = mp_alloc(mp, sizeof(struct fb_multi));
-  FB_MULTI(fb_out)->mp = mp;
+  struct subbuf *last = clist_tail(&FB_MULTI(f)->subbufs);
 
 
-  struct fastbuf *fb_in;
-  clist* subbufs = mp_alloc(mp, sizeof(clist));
-  clist_init(subbufs);
-  FB_MULTI(fb_out)->subbufs = subbufs;
+  struct subbuf *sb = mp_alloc(FB_MULTI(f)->mp, sizeof(*sb));
+  sb->fb = fb;
+  clist_add_tail(&FB_MULTI(f)->subbufs, &(sb->n));
 
 
-  va_list args;
-  va_start(args, bufsize);
-  while (fb_in = va_arg(args, struct fastbuf *)) {
-    struct subbuf *sb = mp_alloc(mp, sizeof(struct subbuf));
-    sb->fb = fb_in;
-    clist_add_tail(subbufs, &(sb->n));
-  }
-  va_end(args);
+  ASSERT(fb->refill);
 
 
-  FB_MULTI(fb_out)->cur = clist_head(subbufs);
+  if (fb->seek)
+    {
+      if (f->seek)
+       {
+         sb->begin = last ? last->end : 0;
+         bseek(fb, 0, SEEK_END);
+         FB_MULTI(f)->len = sb->end = sb->begin + btell(fb);
+       }
 
 
-  fb_out->buffer = mp_alloc(mp, bufsize);
-  fb_out->bptr = fb_out->bstop = fb_out->buffer;
-  fb_out->bufend = fb_out->buffer + bufsize;
-  fb_out->name = "<multi>";
+      bsetpos(fb, 0);
+    }
 
 
-  fbmulti_update_capability(fb_out);
+  else
+    {
+      f->seek = NULL;
+      sb->offset = btell(fb);
+      sb->begin = 0;
+      sb->end = 0;
+    }
 
 
-  return fb_out;
+  if (!last)
+    {
+      FB_MULTI(f)->cur = sb;
+      fbmulti_get_ptrs(f);
+    }
+}
+
+void
+fbmulti_remove(struct fastbuf *f, struct fastbuf *fb)
+{
+  bflush(f);
+  if (fb)
+    {
+      CLIST_FOR_EACH(struct subbuf *, n, FB_MULTI(f)->subbufs)
+       if (fb == n->fb)
+         {
+           clist_remove(&(n->n));
+           return;
+         }
+
+      die("Given fastbuf %p not in given fbmulti %p", fb, f);
+    }
+  else
+    clist_init(&FB_MULTI(f)->subbufs);
 }
 
 #ifdef TEST
 
 }
 
 #ifdef TEST
 
-int main(int argc, char ** argv)
+int main(int argc, char **argv)
 {
   if (argc < 2)
     {
 {
   if (argc < 2)
     {
-      fprintf(stderr, "You must specify a test (r, w, o)\n");
+      fprintf(stderr, "You must specify a test (r, m, i, n)\n");
       return 1;
     }
   switch (*argv[1])
       return 1;
     }
   switch (*argv[1])
@@ -194,10 +258,13 @@ int main(int argc, char ** argv)
         {
          char *data[] = { "One\nLine", "Two\nLines", "Th\nreeLi\nnes\n" };
          struct fastbuf fb[ARRAY_SIZE(data)];
         {
          char *data[] = { "One\nLine", "Two\nLines", "Th\nreeLi\nnes\n" };
          struct fastbuf fb[ARRAY_SIZE(data)];
-         for (uns i=0;i<ARRAY_SIZE(data);i++)
+         for (uint i=0;i<ARRAY_SIZE(data);i++)
            fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
 
            fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
 
-         struct fastbuf* f = fbmulti_create(4, &fb[0], &fb[1], &fb[2], NULL);
+         struct fastbuf *f = fbmulti_create();
+         fbmulti_append(f, &fb[0]);
+         fbmulti_append(f, &fb[1]);
+         fbmulti_append(f, &fb[2]);
 
          char buffer[9];
          while (bgets(f, buffer, 9))
 
          char buffer[9];
          while (bgets(f, buffer, 9))
@@ -210,17 +277,20 @@ int main(int argc, char ** argv)
        {
          char *data[] = { "Mnl", "ige" };
          struct fastbuf fb[ARRAY_SIZE(data)];
        {
          char *data[] = { "Mnl", "ige" };
          struct fastbuf fb[ARRAY_SIZE(data)];
-         for (uns i=0;i<ARRAY_SIZE(data);i++)
+         for (uint i=0;i<ARRAY_SIZE(data);i++)
            fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
 
            fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
 
-         struct fastbuf* f = fbmulti_create(4, &fb[0], &fb[1], NULL);
+         struct fastbuf *f = fbmulti_create();
+         fbmulti_append(f, &fb[0]);
+         fbmulti_append(f, &fb[1]);
 
          int pos[] = {0, 3, 1, 4, 2, 5};
 
 
          int pos[] = {0, 3, 1, 4, 2, 5};
 
-         for (uns i=0;i<ARRAY_SIZE(pos);i++) {
-           bseek(f, pos[i], SEEK_SET);
-           putchar(bgetc(f));
-         }
+         for (uint i=0;i<ARRAY_SIZE(pos);i++)
+           {
+             bsetpos(f, pos[i]);
+             putchar(bgetc(f));
+           }
 
          bclose(f);
          break;
 
          bclose(f);
          break;
@@ -234,12 +304,61 @@ int main(int argc, char ** argv)
          fbbuf_init_read(&fb[2], data + 2, 2, 0);
          fbbuf_init_read(&fb[3], data + 4, 1, 0);
 
          fbbuf_init_read(&fb[2], data + 2, 2, 0);
          fbbuf_init_read(&fb[3], data + 4, 1, 0);
 
-         struct fastbuf* f = fbmulti_create(8, &fb[0], &fb[1], &fb[2], &fb[1], &fb[3], NULL);
+         struct fastbuf *f = fbmulti_create();
+         fbmulti_append(f, &fb[0]);
+         fbmulti_append(f, &fb[1]);
+         fbmulti_append(f, &fb[2]);
+         fbmulti_append(f, &fb[1]);
+         fbmulti_append(f, &fb[3]);
 
          char buffer[9];
          while(bgets(f, buffer, 9))
            puts(buffer);
 
 
          char buffer[9];
          while(bgets(f, buffer, 9))
            puts(buffer);
 
+         bclose(f);
+         break;
+       }
+      case 'n':
+       {
+         char *data[] = { "Nested", "Data", "As", "In", "Real", "Usage", };
+         struct fastbuf fb[ARRAY_SIZE(data)];
+         for (uint i=0;i<ARRAY_SIZE(data);i++)
+           fbbuf_init_read(&fb[i], data[i], strlen(data[i]), 0);
+
+         struct fastbuf sp;
+         fbbuf_init_read(&sp, " ", 1, 0);
+
+         struct fastbuf nl;
+         fbbuf_init_read(&nl, "\n", 1, 0);
+
+         struct fastbuf *f = fbmulti_create();
+         struct fastbuf *ff;
+
+         ff = fbmulti_create();
+         fbmulti_append(ff, &fb[0]);
+         fbmulti_append(ff, &sp);
+         fbmulti_append(ff, &fb[1]);
+         fbmulti_append(f, ff);
+         fbmulti_append(f, &nl);
+
+         ff = fbmulti_create();
+         fbmulti_append(ff, &fb[2]);
+         fbmulti_append(ff, &sp);
+         fbmulti_append(ff, &fb[3]);
+         fbmulti_append(f, ff);
+         fbmulti_append(f, &nl);
+
+         ff = fbmulti_create();
+         fbmulti_append(ff, &fb[4]);
+         fbmulti_append(ff, &sp);
+         fbmulti_append(ff, &fb[5]);
+         fbmulti_append(f, ff);
+         fbmulti_append(f, &nl);
+
+         char buffer[20];
+         while (bgets(f, buffer, 20))
+           puts(buffer);
+
          bclose(f);
          break;
        }
          bclose(f);
          break;
        }