# HG changeset patch # User Mikael Berthe # Date 1203871573 -3600 # Node ID 6fb141142388c30f3234171fb77b2463daf484ad # Parent 9bf7f3ddff10a5e4b8a2e56c04e59947767fa9f5 Improve reading of history files Handle larger messages in history log files. diff -r 9bf7f3ddff10 -r 6fb141142388 mcabber/src/histolog.c --- 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'))