changeset 1436:6fb141142388

Improve reading of history files Handle larger messages in history log files.
author Mikael Berthe <mikael@lilotux.net>
date Sun, 24 Feb 2008 17:46:13 +0100
parents 9bf7f3ddff10
children 071c8170b7de
files mcabber/src/histolog.c
diffstat 1 files changed, 54 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/mcabber/src/histolog.c	Sun Feb 24 13:41:36 2008 +0100
+++ b/mcabber/src/histolog.c	Sun Feb 24 17:46:13 2008 +0100
@@ -157,6 +157,7 @@
   char *filename;
   guchar type, info;
   char *data, *tail;
+  guint data_size;
   char *xtext;
   time_t timestamp;
   guint prefix_flags;
@@ -175,7 +176,8 @@
       (settings_opt_get_int("load_muc_logs") != 1))
     return;
 
-  data = g_new(char, HBB_BLOCKSIZE+32);
+  data_size = HBB_BLOCKSIZE+32;
+  data = g_new(char, data_size);
   if (!data) {
     scr_LogPrint(LPRINT_LOGNORM, "Not enough memory to read history file");
     return;
@@ -214,12 +216,38 @@
   /* See write_histo_line() for line format... */
   while (!feof(fp)) {
     guint dataoffset = 25;
+    guint noeol;
 
-    if (fgets(data, HBB_BLOCKSIZE+27, fp) == NULL)
+    if (fgets(data, data_size-1, fp) == NULL)
       break;
     ln++;
 
-    for (tail = data; *tail; tail++) ;
+    while (1) {
+      for (tail = data; *tail; tail++) ;
+      noeol = (*(tail-1) != '\n');
+      if (!noeol)
+        break;
+      /* TODO: duplicated code... could do better... */
+      if (tail == data + data_size-2) {
+        // The buffer is too small to contain the whole line.
+        // Let's allocate some more space.
+        if (!max_num_of_blocks ||
+            data_size/HBB_BLOCKSIZE < 5U*max_num_of_blocks) {
+          guint toffset = tail - data;
+          // Allocate one more block.
+          data_size = HBB_BLOCKSIZE * (1 + data_size/HBB_BLOCKSIZE);
+          data = g_renew(char, data, data_size);
+          // Update the tail pointer, as the data may have been moved.
+          tail = data + toffset;
+          if (fgets(tail, data_size-1 - (tail-data), fp) == NULL)
+            break;
+        } else {
+          scr_LogPrint(LPRINT_LOGNORM, "Line too long in history file!");
+          ln--;
+          break;
+        }
+      }
+    }
 
     type = data[0];
     info = data[1];
@@ -252,20 +280,34 @@
       continue;
     }
 
-    // XXX This will fail when a message is too big
     while (len--) {
       ln++;
-      if (fgets(tail, HBB_BLOCKSIZE+27 - (tail-data), fp) == NULL)
+      if (fgets(tail, data_size-1 - (tail-data), fp) == NULL)
         break;
 
       while (*tail) tail++;
-    }
-    // Small check for too long messages
-    if (tail >= HBB_BLOCKSIZE+dataoffset+1 + data) {
-      // Maybe we will have a parse error on next, because this
-      // message is big (maybe too big).
-      scr_LogPrint(LPRINT_LOGNORM, "A message could be too big "
-                   "in history file...");
+      noeol = (*(tail-1) != '\n');
+      if (tail == data + data_size-2 && (len || noeol)) {
+        // The buffer is too small to contain the whole message.
+        // Let's allocate some more space.
+        if (!max_num_of_blocks ||
+            data_size/HBB_BLOCKSIZE < 5U*max_num_of_blocks) {
+          guint toffset = tail - data;
+          // If the line hasn't been read completely and we reallocate the
+          // buffer, we want to read one more time.
+          if (noeol)
+            len++;
+          // Allocate one more block.
+          data_size = HBB_BLOCKSIZE * (1 + data_size/HBB_BLOCKSIZE);
+          data = g_renew(char, data, data_size);
+          // Update the tail pointer, as the data may have been moved.
+          tail = data + toffset;
+        } else {
+          // There will probably be a parse error on next read, because
+          // this message hasn't been read entirely.
+          scr_LogPrint(LPRINT_LOGNORM, "Message too big in history file!");
+        }
+      }
     }
     // Remove last CR (we keep it if the line is empty, too)
     if ((tail > data+dataoffset+1) && (*(tail-1) == '\n'))