mcabber/src/hbuf.c
changeset 1141 5be2408a6534
parent 1011 b5bcc223cf51
child 1204 e802ec0c02d2
equal deleted inserted replaced
1140:800bb1e9019c 1141:5be2408a6534
   105     }
   105     }
   106     curr_elt = g_list_next(curr_elt);
   106     curr_elt = g_list_next(curr_elt);
   107   }
   107   }
   108 }
   108 }
   109 
   109 
   110 //  hbuf_add_line(p_hbuf, text, prefix_flags, width)
   110 //  hbuf_add_line(p_hbuf, text, prefix_flags, width, maxhbufblocks)
   111 // Add a line to the given buffer.  If width is not null, then lines are
   111 // Add a line to the given buffer.  If width is not null, then lines are
   112 // wrapped at this length.
   112 // wrapped at this length.
       
   113 // maxhbufblocks is the maximum number of hbuf blocks we can allocate.  If
       
   114 // null, there is no limit.  If non-null, it should be >= 2.
   113 //
   115 //
   114 // Note 1: Splitting according to width won't work if there are tabs; they
   116 // Note 1: Splitting according to width won't work if there are tabs; they
   115 //         should be expanded before.
   117 //         should be expanded before.
   116 // Note 2: width does not include the ending \0.
   118 // Note 2: width does not include the ending \0.
   117 void hbuf_add_line(GList **p_hbuf, const char *text, time_t timestamp,
   119 void hbuf_add_line(GList **p_hbuf, const char *text, time_t timestamp,
   118         guint prefix_flags, guint width)
   120         guint prefix_flags, guint width, guint maxhbufblocks)
   119 {
   121 {
   120   GList *curr_elt;
   122   GList *curr_elt;
   121   char *line, *end;
   123   char *line;
   122   hbuf_block *hbuf_block_elt;
   124   hbuf_block *hbuf_block_elt;
   123 
   125 
   124   if (!text) return;
   126   if (!text) return;
   125 
   127 
   126   hbuf_block_elt = g_new0(hbuf_block, 1);
   128   hbuf_block_elt = g_new0(hbuf_block, 1);
   147     text = "[ERR:LINE_TOO_LONG]";
   149     text = "[ERR:LINE_TOO_LONG]";
   148     hbuf_block_elt->prefix.flags |= HBB_PREFIX_INFO;
   150     hbuf_block_elt->prefix.flags |= HBB_PREFIX_INFO;
   149   }
   151   }
   150   if (hbuf_block_elt->ptr + strlen(text) >= hbuf_block_elt->ptr_end_alloc) {
   152   if (hbuf_block_elt->ptr + strlen(text) >= hbuf_block_elt->ptr_end_alloc) {
   151     // Too long for the current allocated bloc, we need another one
   153     // Too long for the current allocated bloc, we need another one
   152     hbuf_block_elt->ptr  = g_new0(char, HBB_BLOCKSIZE);
   154     if (!maxhbufblocks) {
       
   155       // No limit, let's allocate a new block
       
   156       hbuf_block_elt->ptr  = g_new0(char, HBB_BLOCKSIZE);
       
   157     } else {
       
   158       GList *hbuf_head, *hbuf_elt;
       
   159       hbuf_block *hbuf_b_elt;
       
   160       guint n = 0;
       
   161       hbuf_head = g_list_first(*p_hbuf);
       
   162       // We need at least 2 allocated blocks
       
   163       if (maxhbufblocks == 1)
       
   164         maxhbufblocks = 2;
       
   165       // Let's count the number of allocated areas
       
   166       for (hbuf_elt = hbuf_head; hbuf_elt; hbuf_elt = g_list_next(hbuf_elt)) {
       
   167         hbuf_b_elt = (hbuf_block*)(hbuf_elt->data);
       
   168         if (hbuf_b_elt->flags & HBB_FLAG_ALLOC)
       
   169           n++;
       
   170       }
       
   171       // If we can't allocate a new area, reuse the previous block(s)
       
   172       if (n < maxhbufblocks) {
       
   173         hbuf_block_elt->ptr  = g_new0(char, HBB_BLOCKSIZE);
       
   174       } else {
       
   175         // Let's use an old block, and free the extra blocks if needed
       
   176         char *allocated_block = NULL;
       
   177         while (n >= maxhbufblocks) {
       
   178           /* --- */
       
   179           int start_of_block = 1;
       
   180           for (hbuf_elt = hbuf_head; hbuf_elt; hbuf_elt = hbuf_head) {
       
   181             hbuf_b_elt = (hbuf_block*)(hbuf_elt->data);
       
   182             if (hbuf_b_elt->flags & HBB_FLAG_ALLOC) {
       
   183               if (start_of_block-- == 0)
       
   184                 break;
       
   185               if (n == maxhbufblocks)
       
   186                 allocated_block = hbuf_b_elt->ptr;
       
   187               else
       
   188                 g_free(hbuf_b_elt->ptr);
       
   189             }
       
   190             g_free(hbuf_b_elt);
       
   191             hbuf_head = *p_hbuf = g_list_delete_link(hbuf_head, hbuf_elt);
       
   192           }
       
   193           n--;
       
   194           /* --- */
       
   195         }
       
   196         memset(allocated_block, 0, HBB_BLOCKSIZE);
       
   197         hbuf_block_elt->ptr = allocated_block;
       
   198       }
       
   199     }
   153     hbuf_block_elt->flags  = HBB_FLAG_ALLOC | HBB_FLAG_PERSISTENT;
   200     hbuf_block_elt->flags  = HBB_FLAG_ALLOC | HBB_FLAG_PERSISTENT;
   154     hbuf_block_elt->ptr_end_alloc = hbuf_block_elt->ptr + HBB_BLOCKSIZE;
   201     hbuf_block_elt->ptr_end_alloc = hbuf_block_elt->ptr + HBB_BLOCKSIZE;
   155   }
   202   }
   156 
   203 
   157   line = hbuf_block_elt->ptr;
   204   line = hbuf_block_elt->ptr;
   158   // Ok, now we can copy the text..
   205   // Ok, now we can copy the text..
   159   strcpy(line, text);
   206   strcpy(line, text);
   160   hbuf_block_elt->ptr_end = line + strlen(line) + 1;
   207   hbuf_block_elt->ptr_end = line + strlen(line) + 1;
   161   end = hbuf_block_elt->ptr_end;
       
   162 
   208 
   163   curr_elt = g_list_last(*p_hbuf);
   209   curr_elt = g_list_last(*p_hbuf);
   164 
   210 
   165   // Wrap lines and handle CRs ('\n')
   211   // Wrap lines and handle CRs ('\n')
   166   do_wrap(p_hbuf, curr_elt, width);
   212   do_wrap(p_hbuf, curr_elt, width);