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