1 /*:ts=8*/
2 /*****************************************************************************
3 * FIDOGATE --- Gateway UNIX Mail/News <-> FIDO NetMail/EchoMail
4 *
5 *
6 * Store text file as chain of linked text lines in memory
7 *
8 *****************************************************************************
9 * Copyright (C) 1990-2002
10 * _____ _____
11 * | |___ | Martin Junius <mj@fidogate.org>
12 * | | | | | | Radiumstr. 18
13 * |_|_|_|@home| D-51069 Koeln, Germany
14 *
15 * This file is part of FIDOGATE.
16 *
17 * FIDOGATE is free software; you can redistribute it and/or modify it
18 * under the terms of the GNU General Public License as published by the
19 * Free Software Foundation; either version 2, or (at your option) any
20 * later version.
21 *
22 * FIDOGATE is distributed in the hope that it will be useful, but
23 * WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 * General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with FIDOGATE; see the file COPYING. If not, write to the Free
29 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
30 *****************************************************************************/
31
32 #include "fidogate.h"
33
34 /*
35 * Write Textlist to file
36 */
tl_fput(FILE * fp,Textlist * list)37 void tl_fput(FILE * fp, Textlist * list)
38 {
39 Textline *p;
40
41 for (p = list->first; p; p = p->next)
42 fputs(p->line, fp);
43
44 return;
45 }
46
47 /*
48 * tl_add() --- append Textline to Textlist
49 */
tl_add(Textlist * list,Textline * line)50 void tl_add(Textlist * list, Textline * line)
51 {
52 if (list->last)
53 list->last->next = line;
54 else
55 list->first = line;
56
57 line->next = NULL;
58 line->prev = list->last;
59
60 list->last = line;
61 list->n++;
62 }
63
64 /*
65 * tl_remove() --- remove Textline from Textlist
66 */
tl_remove(Textlist * list,Textline * line)67 void tl_remove(Textlist * list, Textline * line)
68 {
69 if (list->first == line)
70 list->first = line->next;
71 else
72 line->prev->next = line->next;
73
74 if (list->last == line)
75 list->last = line->prev;
76 else
77 line->next->prev = line->prev;
78
79 line->next = NULL;
80 line->prev = NULL;
81
82 list->n--;
83 }
84
85 /*
86 * tl_delete() --- remove Textline from Textlist, delete Textline
87 */
tl_delete(Textlist * list,Textline * line)88 void tl_delete(Textlist * list, Textline * line)
89 {
90 tl_remove(list, line);
91 xfree(line->line);
92 xfree(line);
93 }
94
95 /***** tl_init() --- Initialize structure ******************************/
96
tl_init(Textlist * list)97 void tl_init(Textlist * list)
98 {
99 list->first = NULL;
100 list->last = NULL;
101 list->n = 0;
102 }
103
104 /***** tl_clear() --- Delete text lines and chain **********************/
105
tl_clear(Textlist * list)106 void tl_clear(Textlist * list)
107 {
108 Textline *p, *pn;
109
110 for (p = list->first; p;) {
111 pn = p->next;
112 xfree(p->line);
113 xfree(p);
114 p = pn;
115 }
116
117 list->first = NULL;
118 list->last = NULL;
119 list->n = 0;
120 }
121
tl_free(Textlist * list)122 void tl_free(Textlist *list)
123 {
124 tl_clear(list);
125 free(list);
126 }
127
128 /***** tl_append() --- Append string to text line chain ****************/
129
tl_append(Textlist * list,char * s)130 void tl_append(Textlist * list, char *s)
131 {
132 Textline *p;
133
134 if (!s)
135 return;
136
137 s = strsave(s);
138 p = (Textline *) xmalloc(sizeof(Textline));
139 p->line = s;
140 p->next = NULL;
141
142 tl_add(list, p);
143 }
144
145 /***** tl_appendf() --- Append text to chain, printf like formatting ***/
146
tl_appendf(Textlist * list,char * fmt,...)147 void tl_appendf(Textlist * list, char *fmt, ...)
148 {
149 static char buf[4096];
150 #ifndef HAVE_SNPRINTF
151 int n;
152 #endif
153 va_list args;
154
155 va_start(args, fmt);
156
157 #ifdef HAVE_SNPRINTF
158 vsnprintf(buf, sizeof(buf), fmt, args);
159 #else
160 n = vsprintf(buf, fmt, args);
161 if (n >= sizeof(buf)) {
162 fatal("Internal error - tl_appendf() buf overflow", EX_SOFTWARE);
163 /**NOT REACHED**/
164 return;
165 }
166 #endif
167 tl_append(list, (char *)buf);
168
169 va_end(args);
170 }
171
172 /***** tl_print() --- Write text line chain to file ********************/
173
tl_print(Textlist * list,FILE * fp)174 void tl_print(Textlist * list, FILE * fp)
175 {
176 Textline *p;
177
178 for (p = list->first; p; p = p->next)
179 fputs(p->line, fp);
180
181 return;
182 }
183
tl_print_xx(Textlist * list,FILE * fp,char * prefix,char * suffix)184 void tl_print_xx(Textlist * list, FILE * fp, char *prefix, char *suffix)
185 {
186 Textline *p;
187
188 for (p = list->first; p; p = p->next) {
189 if (prefix)
190 fputs(prefix, fp);
191
192 fputs(p->line, fp);
193
194 if (suffix)
195 fputs(suffix, fp);
196 }
197
198 return;
199 }
200
201 /*
202 * Output complete textlist with extra end-of-line
203 */
tl_print_x(Textlist * list,FILE * fp,char * extra)204 void tl_print_x(Textlist * list, FILE * fp, char *extra)
205 {
206 tl_print_xx(list, fp, NULL, extra);
207 }
208
209 /***** tl_size() --- Compute size of text in chain *********************/
210
tl_size(Textlist * list)211 long tl_size(Textlist * list)
212 {
213 Textline *p;
214 long n = 0;
215
216 for (p = list->first; p; p = p->next)
217 n += strlen(p->line);
218
219 return n;
220 }
221
222 /***** tl_addtl() --- Add another textlist ******************************/
223
tl_addtl(Textlist * d,Textlist * s)224 void tl_addtl(Textlist * d, Textlist * s)
225 {
226 Textline *p;
227
228 for (p = s->first; p; p = p->next)
229 tl_append(d, p->line);
230 }
231
tl_addtl_move(Textlist * d,Textlist * s)232 void tl_addtl_move(Textlist *d, Textlist *s)
233 {
234 if (!d->first)
235 *d = *s;
236 else {
237 d->last->next = s->first;
238 d->n += s->n;
239 }
240 tl_init(s);
241 }
242
243
tl_get(Textlist * list,char * str,int len)244 Textline *tl_get(Textlist * list, char *str, int len)
245 {
246 Textline *p = NULL;
247
248 for (p = list->first; p != NULL; p = p->next) {
249 if (len == 0) {
250 if (stricmp(p->line, str) == 0)
251 break;
252 } else {
253 if (strnicmp(p->line, str, len) == 0)
254 break;
255 }
256 }
257 return p;
258 }
259
tl_get_str(Textlist * list,char * str,int len)260 char *tl_get_str(Textlist * list, char *str, int len)
261 {
262 Textline *p;
263 char *new_str = NULL;
264
265 p = tl_get(list, str, len);
266 if (p != NULL)
267 new_str = strsave(p->line);
268 return new_str;
269 }
270
tl_copy(Textlist * dst,Textlist * src)271 int tl_copy(Textlist * dst, Textlist * src)
272 {
273 Textline *p;
274
275 for (p = src->first; p != NULL; p = p->next)
276 tl_append(dst, p->line);
277 return OK;
278 }
279
tl_dup(Textlist * src)280 Textlist *tl_dup(Textlist *src)
281 {
282 Textlist *d = xmalloc(sizeof(*d));
283
284 tl_init(d);
285 tl_copy(d, src);
286 return d;
287 }
288
tl_for_each(Textlist * list,int (* func)(Textline *,void *),void * arg)289 int tl_for_each(Textlist * list, int (*func)(Textline *, void *), void *arg)
290 {
291 Textline *p;
292 int r;
293
294 for (p = list->first; p != NULL; p = p->next) {
295 r = func(p, arg);
296 if (r != OK)
297 return r;
298 }
299 return OK;
300 }
301
tl_char_iterator_start(TextlistCharIterator * iter,Textlist * list)302 void tl_char_iterator_start(TextlistCharIterator * iter, Textlist * list)
303 {
304 iter->list = list;
305 iter->cur = list->first;
306 iter->len = list->first == NULL ? 0 : strlen(list->first->line);
307 iter->pos = 0;
308 }
309
tl_char_iterator_next(TextlistCharIterator * iter,char * buf,size_t len)310 size_t tl_char_iterator_next(TextlistCharIterator * iter, char *buf, size_t len)
311 {
312 size_t left; /* in current line */
313 size_t moved;
314
315 if (iter->cur == NULL)
316 return 0;
317
318 left = iter->len - iter->pos;
319
320 moved = 0;
321 while (len > 0) {
322 size_t to_move = MIN(left, len);
323
324 memcpy(buf + moved, &iter->cur->line[iter->pos], to_move);
325 moved += to_move;
326 iter->pos += to_move;
327 len -= to_move;
328 left -= to_move;
329
330 if (left == 0) {
331 iter->cur = iter->cur->next;
332 if (iter->cur == NULL)
333 return moved;
334
335 iter->len = strlen(iter->cur->line);
336 left = iter->len;
337 iter->pos = 0;
338 }
339 }
340 return moved;
341 }
342
tl_iterator_start(TextlistIterator * iter,Textlist * list)343 void tl_iterator_start(TextlistIterator *iter, Textlist *list)
344 {
345 iter->cur = list->first;
346 }
347
tl_iterator_next(TextlistIterator * iter)348 Textline *tl_iterator_next(TextlistIterator *iter)
349 {
350 Textline *ret;
351
352 if (iter->cur == NULL)
353 return NULL;
354
355 ret = iter->cur;
356 iter->cur = ret->next;
357
358 return ret;
359 }
360