2007-10-05 [colin] 3.0.2cvs11
[claws.git] / src / common / mgutils.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2001-2007 Match Grun and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  * 
18  */
19
20 /*
21  * Definitions for generic functions.
22  */
23
24 #include <glib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <ctype.h>
28
29 #include "mgutils.h"
30
31 /*
32 * Dump linked list of character strings (for debug).
33 */
34 void mgu_print_list( GSList *list, FILE *stream ) {
35         GSList *node = list;
36         while( node ) {
37                 int r = fprintf( stream, "\t- >%s<\n", (gchar *)node->data );
38                 if (r < 0) {
39                         perror("fprintf");
40                         break;
41                 }
42                 node = g_slist_next( node );
43         }
44 }
45
46 /*
47 * Dump linked list of character strings (for debug).
48 */
49 void mgu_print_dlist( GList *list, FILE *stream ) {
50         GList *node = list;
51         while( node ) {
52                 int r = fprintf( stream, "\t- >%s<\n", (gchar *)node->data );
53                 if (r < 0) {
54                         perror("fprintf");
55                         break;
56                 }
57                 node = g_list_next( node );
58         }
59 }
60
61 /*
62 * Free linked list of character strings.
63 */
64 void mgu_free_list( GSList *list ) {
65         GSList *node = list;
66         while( node ) {
67                 g_free( node->data );
68                 node->data = NULL;
69                 node = g_slist_next( node );
70         }
71         g_slist_free( list );
72 }
73
74 /*
75 * Free linked list of character strings.
76 */
77 void mgu_free_dlist( GList *list ) {
78         GList *node = list;
79         while( node ) {
80                 g_free( node->data );
81                 node->data = NULL;
82                 node = g_list_next( node );
83         }
84         g_list_free( list );
85 }
86
87 /*
88 * Coalesce linked list of characaters into one long string.
89 */
90 gchar *mgu_list_coalesce( GSList *list ) {
91         gchar *str = NULL;
92         gchar *buf = NULL;
93         gchar *start = NULL;
94         GSList *node = NULL;
95         gint len;
96
97         if( ! list ) return NULL;
98
99         /* Calculate maximum length of text */
100         len = 0;
101         node = list;
102         while( node ) {
103                 str = node->data;
104                 len += 1 + strlen( str );
105                 node = g_slist_next( node );
106         }
107
108         /* Create new buffer. */
109         buf = g_new0( gchar, len+1 );
110         start = buf;
111         node = list;
112         while( node ) {
113                 str = node->data;
114                 len = strlen( str );
115                 strcpy( start, str );
116                 start += len;
117                 node = g_slist_next( node );
118         }
119         return buf;
120 }
121
122 /*
123 * Replace existing string with new string.
124 */
125 gchar *mgu_replace_string( gchar *str, const gchar *value ) {
126         g_free( str );
127         if( value ) {
128                 str = g_strdup( value );
129                 g_strstrip( str );
130         }
131         else {
132                 str = NULL;
133         }
134         return str;
135 }
136
137 /*
138 * Clear a linked list by setting node data pointers to NULL. Note that
139 * items are not freed.
140 */
141 void mgu_clear_slist( GSList *list ) {
142         GSList *node = list;
143         while( node ) {
144                 node->data = NULL;
145                 node = g_slist_next( node );
146         }
147 }
148
149 /*
150 * Clear a linked list by setting node data pointers to NULL. Note that
151 * items are not freed.
152 */
153 void mgu_clear_list( GList *list ) {
154         GList *node = list;
155         while( node ) {
156                 node->data = NULL;
157                 node = g_list_next( node );
158         }
159 }
160
161 /*
162 * Test and reformat an email address.
163 * Enter:  address.
164 * Return: Address, or NULL if address is empty.
165 * Note: Leading and trailing white space is removed.
166 */
167 gchar *mgu_email_check_empty( gchar *address ) {
168         gchar *retVal = NULL;
169         if( address ) {
170                 retVal = g_strdup( address );
171                 retVal = g_strchug( retVal );
172                 retVal = g_strchomp( retVal );
173                 if( *retVal == '\0' ) {
174                         g_free( retVal );
175                         retVal = NULL;
176                 }
177         }
178         return retVal;
179 }
180
181 /*
182 * Parse string into linked list. Whitespace is used as a delimiter in parsing.
183 * Strings are parsed until maxTokens - 1 is reached. The remainder of the
184 * input string is copied into last element of list.
185 * Enter: line      String to parse.
186 *        maxTokens Maximum number of tokens to parse.
187 *        tokenCnt  If arg supplied, update with count of number of token parsed.
188 * Return: Linked list. The list contents should be g_free'd and list should
189 * freed when done.
190 */
191 GList *mgu_parse_string( gchar *line, const gint maxTokens, gint *tokenCnt ) {
192         gchar *ptr, *pStart, *pFound, *str;
193         gint  args = 0;
194         GList *list = NULL;
195         gboolean done = FALSE;
196
197         if( tokenCnt ) *tokenCnt = 0;
198         if( line == NULL ) return NULL;
199         if( maxTokens < 1 ) return NULL;
200
201         ptr = line;
202         while( ! done ) {
203                 args++;
204                 /* Skip over leading spaces */
205                 while( *ptr ) {
206                         if( ! isspace( *ptr ) ) break;
207                         ptr++;  
208                 }
209
210                 /* Find terminating space */
211                 pFound = NULL;
212                 pStart = ptr;
213                 while( *ptr ) {
214                         if( isspace( *ptr ) ) {
215                                 pFound = pStart;
216                                 break;
217                         }
218                         ptr++;
219                 }
220
221                 if( pFound ) {
222                         if( args == maxTokens ) {
223                                 /* Rest of string */
224                                 str = g_strdup( pStart );
225                                 done = TRUE;
226                         }
227                         else {
228                                 /* Extract part of string */
229                                 str = g_strndup( pStart, ptr - pFound );
230                         }
231                 }
232                 else {
233                         /* Nothing there - treat as rest of string */
234                         str = g_strdup( pStart );
235                         done = TRUE;
236                 }
237                 list = g_list_append( list, str );
238         }
239         if( tokenCnt ) *tokenCnt = args;
240         return list;
241 }
242
243 /*
244  * Unescape characters by removing backslash character from input string.
245  * Enter: str String to process.
246  */
247 void mgu_str_unescape( gchar *str ) {
248         gchar *p;
249         gint ilen;
250
251         p = str;
252         while( *p ) {
253                 if( *p == '\\' ) {
254                         ilen = strlen( p + 1 );
255                         memmove( p, p + 1, ilen );
256                 }
257                 p++;
258         }
259 }
260
261 /*
262  * Replace leading and trailing characters (eg, quotes) in input string
263  * with spaces. Only matching non-blank characters that appear at both
264  * start and end of string are replaces. Control characters are also
265  * replaced with spaces.
266  * Enter: str    String to process.
267  *        chlea  Lead character to remove.
268  *        chtail Matching trailing character.
269  */
270 void mgu_str_ltc2space( gchar *str, gchar chlead, gchar chtail ) {
271         gchar *as;
272         gchar *ae;
273
274         /* Search forwards for first non-space match */
275         as = str;
276         ae = -1 + str + strlen( str );
277         while( as < ae ) {
278                 if( *as != ' ' ) {
279                         if( *as == chlead ) {
280                                 /* Search backwards from end for match */
281                                 while( ae > as ) {
282                                         if( *ae != ' ' ) {
283                                                 if( *ae == chtail ) {
284                                                         *as = ' ';
285                                                         *ae = ' ';
286                                                         return;
287                                                 }
288                                                 if( *ae < 32 ) {
289                                                         *ae = ' ';
290                                                 }
291                                                 else if( *ae == 127 ) {
292                                                         *ae = ' ';
293                                                 }
294                                                 else {
295                                                         return;
296                                                 }
297                                         }
298                                         ae--;
299                                 }
300                         }
301                         if( *as < 32 ) {
302                                 *as = ' ';
303                         }
304                         else if( *as == 127 ) {
305                                 *as = ' ';
306                         }
307                         else {
308                                 return;
309                         }
310                 }
311                 as++;
312         }
313         return;
314 }
315
316 /*
317  * Return reference to longest entry in the specified linked list.
318  * It is assumed that the list contains only gchar objects.
319  * Enter:  list List of gchar strings to examine.
320  * Return: Reference to longest entry, or NULL if nothing found.
321  */
322 gchar *mgu_slist_longest_entry( GSList *list ) {
323         GSList *node;
324         gchar *name = NULL;
325         gint iLen = 0, iLenT = 0;
326
327         node = list;
328         while( node ) {
329                 if( name == NULL ) {
330                         name = node->data;
331                         iLen = strlen( name );
332                 }
333                 else {
334                         iLenT = strlen( node->data );
335                         if( iLenT > iLen ) {
336                                 name = node->data;
337                                 iLen = iLenT;
338                         }
339                 }
340                 node = g_slist_next( node );
341         }
342         return name;
343 }       
344
345 /*
346  * Return reference to longest entry in the specified linked list.
347  * It is assumed that the list contains only gchar objects.
348  * Enter:  list List of gchar strings to examine.
349  * Return: Reference to longest entry, or NULL if nothing found.
350  */
351 gchar *mgu_list_longest_entry( GList *list ) {
352         GList *node;
353         gchar *name = NULL;
354         gint iLen = 0, iLenT = 0;
355
356         node = list;
357         while( node ) {
358                 if( name == NULL ) {
359                         name = node->data;
360                         iLen = strlen( name );
361                 }
362                 else {
363                         iLenT = strlen( node->data );
364                         if( iLenT > iLen ) {
365                                 name = node->data;
366                                 iLen = iLenT;
367                         }
368                 }
369                 node = g_list_next( node );
370         }
371         return name;
372 }       
373
374 /*
375  * Test whether string appears in list of strings, ignoring case. NULL or empty
376  * strings will be ignored.
377  * Enter: list List to process.
378  *        str  String to test.
379  * Return: TRUE if string is unique.
380  */
381 gboolean mgu_slist_test_unq_nc( GSList *list, gchar *str ) {
382         GSList *node;
383
384         if( str ) {
385                 if( strlen( str ) > 0 ) {
386                         node = list;
387                         while( node ) {
388                                 if( g_utf8_collate( str, node->data ) == 0 )
389                                         return FALSE;
390                                 node = g_slist_next( node );
391                         }
392                         return TRUE;
393                 }
394         }
395         return FALSE;
396 }
397
398 /*
399  * Test whether string appears in list of strings, ignoring case. NULL or empty
400  * strings will be ignored.
401  * Enter: list List to process.
402  *        str  String to test.
403  * Return: TRUE if string is unique.
404  */
405 gboolean mgu_list_test_unq_nc( GList *list, gchar *str ) {
406         GList *node;
407
408         if( str ) {
409                 if( strlen( str ) > 0 ) {
410                         node = list;
411                         while( node ) {
412                                 if( g_utf8_collate( str, node->data ) == 0 )
413                                         return FALSE;
414                                 node = g_list_next( node );
415                         }
416                         return TRUE;
417                 }
418         }
419         return FALSE;
420 }
421
422 /*
423 * End of Source.
424 */