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