Mercurial > ~mikael > mcabber > hg
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. |