comparison mcabber/src/hbuf.c @ 943:9ac0d166a85b

hbuf: Refactor line wrapping stuff
author Mikael Berthe <mikael@lilotux.net>
date Sat, 15 Jul 2006 12:46:39 +0200
parents c6bd42119c31
children b5bcc223cf51
comparison
equal deleted inserted replaced
942:c6bd42119c31 943:9ac0d166a85b
41 guint flags; 41 guint flags;
42 } prefix; 42 } prefix;
43 } hbuf_block; 43 } hbuf_block;
44 44
45 45
46 // hbuf_add_line(p_hbuf, text, prefix_flags, width) 46 // do_wrap(p_hbuf, first_hbuf_elt, width)
47 // Add a line to the given buffer. If width is not null, then lines are 47 // Wrap hbuf lines with the specified width.
48 // wrapped at this length. 48 // '\n' are handled by this routine (they are removed and persistent lines
49 // 49 // are created).
50 // Note 1: Splitting according to width won't work if there are tabs; they 50 // All hbuf elements are processed, starting from first_hbuf_elt.
51 // should be expanded before. 51 static inline void do_wrap(GList **p_hbuf, GList *first_hbuf_elt,
52 // Note 2: width does not include the ending \0. 52 unsigned int width)
53 void hbuf_add_line(GList **p_hbuf, const char *text, time_t timestamp, 53 {
54 guint prefix_flags, guint width) 54 GList *curr_elt = first_hbuf_elt;
55 {
56 GList *hbuf = *p_hbuf;
57 GList *curr_elt;
58 char *line, *end;
59 hbuf_block *hbuf_block_elt, *hbuf_b_curr;
60
61 if (!text) return;
62
63 hbuf_block_elt = g_new0(hbuf_block, 1);
64 hbuf_block_elt->prefix.timestamp = timestamp;
65 hbuf_block_elt->prefix.flags = prefix_flags;
66 if (!hbuf) {
67 hbuf_block_elt->ptr = g_new(char, HBB_BLOCKSIZE);
68 hbuf_block_elt->flags = HBB_FLAG_ALLOC | HBB_FLAG_PERSISTENT;
69 hbuf_block_elt->ptr_end_alloc = hbuf_block_elt->ptr + HBB_BLOCKSIZE;
70 *p_hbuf = g_list_append(*p_hbuf, hbuf_block_elt);
71 } else {
72 hbuf_block *hbuf_b_prev;
73 // Set p_hbuf to the end of the list, to speed up history loading
74 // (or CPU time will be used by g_list_last() for each line)
75 hbuf = *p_hbuf = g_list_last(*p_hbuf);
76 hbuf_b_prev = hbuf->data;
77 hbuf_block_elt->ptr = hbuf_b_prev->ptr_end;
78 hbuf_block_elt->flags = HBB_FLAG_PERSISTENT;
79 hbuf_block_elt->ptr_end_alloc = hbuf_b_prev->ptr_end_alloc;
80 *p_hbuf = g_list_append(*p_hbuf, hbuf_block_elt);
81 }
82
83 if (strlen(text) >= HBB_BLOCKSIZE) {
84 // Too long
85 text = "[ERR:LINE_TOO_LONG]";
86 hbuf_block_elt->prefix.flags |= HBB_PREFIX_INFO;
87 }
88 if (hbuf_block_elt->ptr + strlen(text) >= hbuf_block_elt->ptr_end_alloc) {
89 // Too long for the current allocated bloc, we need another one
90 hbuf_block_elt->ptr = g_new0(char, HBB_BLOCKSIZE);
91 hbuf_block_elt->flags = HBB_FLAG_ALLOC | HBB_FLAG_PERSISTENT;
92 hbuf_block_elt->ptr_end_alloc = hbuf_block_elt->ptr + HBB_BLOCKSIZE;
93 }
94
95 line = hbuf_block_elt->ptr;
96 // Ok, now we can copy the text..
97 strcpy(line, text);
98 hbuf_block_elt->ptr_end = line + strlen(line) + 1;
99 end = hbuf_block_elt->ptr_end;
100
101 curr_elt = g_list_last(hbuf);
102 55
103 // Let's add non-persistent blocs if necessary 56 // Let's add non-persistent blocs if necessary
104 // - If there are '\n' in the string 57 // - If there are '\n' in the string
105 // - If length > width (and width != 0) 58 // - If length > width (and width != 0)
106 while (curr_elt) { 59 while (curr_elt) {
107 hbuf_block *hbuf_b_prev; 60 hbuf_block *hbuf_b_curr, *hbuf_b_prev;
108 char *c, *end; 61 char *c, *end;
109 char *br = NULL; // break pointer 62 char *br = NULL; // break pointer
110 char *cr = NULL; // CR pointer 63 char *cr = NULL; // CR pointer
111 unsigned int cur_w = 0; 64 unsigned int cur_w = 0;
112 65
152 } 105 }
153 curr_elt = g_list_next(curr_elt); 106 curr_elt = g_list_next(curr_elt);
154 } 107 }
155 } 108 }
156 109
110 // hbuf_add_line(p_hbuf, text, prefix_flags, width)
111 // Add a line to the given buffer. If width is not null, then lines are
112 // wrapped at this length.
113 //
114 // Note 1: Splitting according to width won't work if there are tabs; they
115 // should be expanded before.
116 // Note 2: width does not include the ending \0.
117 void hbuf_add_line(GList **p_hbuf, const char *text, time_t timestamp,
118 guint prefix_flags, guint width)
119 {
120 GList *hbuf = *p_hbuf;
121 GList *curr_elt;
122 char *line, *end;
123 hbuf_block *hbuf_block_elt;
124
125 if (!text) return;
126
127 hbuf_block_elt = g_new0(hbuf_block, 1);
128 hbuf_block_elt->prefix.timestamp = timestamp;
129 hbuf_block_elt->prefix.flags = prefix_flags;
130 if (!hbuf) {
131 hbuf_block_elt->ptr = g_new(char, HBB_BLOCKSIZE);
132 hbuf_block_elt->flags = HBB_FLAG_ALLOC | HBB_FLAG_PERSISTENT;
133 hbuf_block_elt->ptr_end_alloc = hbuf_block_elt->ptr + HBB_BLOCKSIZE;
134 *p_hbuf = g_list_append(*p_hbuf, hbuf_block_elt);
135 } else {
136 hbuf_block *hbuf_b_prev;
137 // Set p_hbuf to the end of the list, to speed up history loading
138 // (or CPU time will be used by g_list_last() for each line)
139 hbuf = *p_hbuf = g_list_last(*p_hbuf);
140 hbuf_b_prev = hbuf->data;
141 hbuf_block_elt->ptr = hbuf_b_prev->ptr_end;
142 hbuf_block_elt->flags = HBB_FLAG_PERSISTENT;
143 hbuf_block_elt->ptr_end_alloc = hbuf_b_prev->ptr_end_alloc;
144 *p_hbuf = g_list_append(*p_hbuf, hbuf_block_elt);
145 }
146
147 if (strlen(text) >= HBB_BLOCKSIZE) {
148 // Too long
149 text = "[ERR:LINE_TOO_LONG]";
150 hbuf_block_elt->prefix.flags |= HBB_PREFIX_INFO;
151 }
152 if (hbuf_block_elt->ptr + strlen(text) >= hbuf_block_elt->ptr_end_alloc) {
153 // Too long for the current allocated bloc, we need another one
154 hbuf_block_elt->ptr = g_new0(char, HBB_BLOCKSIZE);
155 hbuf_block_elt->flags = HBB_FLAG_ALLOC | HBB_FLAG_PERSISTENT;
156 hbuf_block_elt->ptr_end_alloc = hbuf_block_elt->ptr + HBB_BLOCKSIZE;
157 }
158
159 line = hbuf_block_elt->ptr;
160 // Ok, now we can copy the text..
161 strcpy(line, text);
162 hbuf_block_elt->ptr_end = line + strlen(line) + 1;
163 end = hbuf_block_elt->ptr_end;
164
165 curr_elt = g_list_last(hbuf);
166
167 // Wrap lines and handle CRs ('\n')
168 do_wrap(p_hbuf, curr_elt, width);
169 }
170
157 // hbuf_free() 171 // hbuf_free()
158 // Destroys all hbuf list. 172 // Destroys all hbuf list.
159 void hbuf_free(GList **p_hbuf) 173 void hbuf_free(GList **p_hbuf)
160 { 174 {
161 hbuf_block *hbuf_b_elt; 175 hbuf_block *hbuf_b_elt;
201 curr_elt = g_list_delete_link(curr_elt, next_elt); 215 curr_elt = g_list_delete_link(curr_elt, next_elt);
202 } else 216 } else
203 curr_elt = next_elt; 217 curr_elt = next_elt;
204 } 218 }
205 // #2 Go back to head and create non-persistent blocks when needed 219 // #2 Go back to head and create non-persistent blocks when needed
206 if (width) { 220 if (width)
207 char *end; 221 do_wrap(p_hbuf, first_elt, width);
208 curr_elt = first_elt;
209
210 while (curr_elt) {
211 hbuf_b_curr = (hbuf_block*)(curr_elt->data);
212 hbuf_block *hbuf_b_prev = hbuf_b_curr;
213
214 // We need to break where we can find a space char
215 char *br = NULL; // break pointer
216 char *c = hbuf_b_curr->ptr;
217 unsigned int cur_w = 0;
218 while (*c && cur_w <= width) {
219 if (iswblank(get_char(c)))
220 br = c;
221 cur_w += get_char_width(c);
222 c = next_char(c);
223 }
224 if (*c && cur_w > width) {
225 if (!br || br == hbuf_b_curr->ptr)
226 br = c;
227 else
228 br = next_char(br);
229 end = hbuf_b_curr->ptr_end;
230 hbuf_b_curr->ptr_end = br;
231 // Create another block, non-persistent
232 hbuf_b_curr = g_new0(hbuf_block, 1);
233 hbuf_b_curr->ptr = hbuf_b_prev->ptr_end; // == br
234 hbuf_b_curr->ptr_end = end;
235 hbuf_b_curr->flags = 0;
236 hbuf_b_curr->ptr_end_alloc = hbuf_b_prev->ptr_end_alloc;
237 // This is OK because insert_before(NULL) == append():
238 *p_hbuf = g_list_insert_before(*p_hbuf, curr_elt->next, hbuf_b_curr);
239 }
240 curr_elt = g_list_next(curr_elt);
241 }
242 }
243 } 222 }
244 223
245 // hbuf_previous_persistent() 224 // hbuf_previous_persistent()
246 // Returns the previous persistent block (line). If the given line is 225 // Returns the previous persistent block (line). If the given line is
247 // persistent, then it is returned. 226 // persistent, then it is returned.