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