catch a typo
[claws.git] / src / mgutils.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2001 Match Grun
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 2 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, write to the Free Software
17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * General functions for create common address book entries.
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 struct mgu_error_entry {
115         gint    e_code;
116         gchar   *e_reason;
117 };
118
119 static const struct mgu_error_entry mgu_error_list[] = {
120         { MGU_SUCCESS,          "Success" },
121         { MGU_BAD_ARGS,         "Bad arguments" },
122         { MGU_NO_FILE,          "File not specified" },
123         { MGU_OPEN_FILE,        "Error opening file" },
124         { MGU_ERROR_READ,       "Error reading file" },
125         { MGU_EOF,              "End of file encountered" },
126         { MGU_OO_MEMORY,        "Error allocating memory" },
127         { MGU_BAD_FORMAT,       "Bad file format" },
128         { MGU_LDAP_CONNECT,     "Error connecting to LDAP server" },
129         { MGU_LDAP_INIT,        "Error initializing LDAP" },
130         { MGU_LDAP_BIND,        "Error binding to LDAP server" },
131         { MGU_LDAP_SEARCH,      "Error searching LDAP database" },
132         { MGU_LDAP_TIMEOUT,     "Timeout performing LDAP operation" },
133         { MGU_LDAP_CRITERIA,    "Error in LDAP search criteria" },
134         { MGU_LDAP_CRITERIA,    "Error in LDAP search criteria" },
135         { MGU_LDAP_NOENTRIES,   "No LDAP entries found for search criteria" },
136         { MGU_ERROR_WRITE,      "Error writing to file" },
137         { MGU_OPEN_DIRECTORY,   "Error opening directory" },
138         { MGU_NO_PATH,          "No path specified" },
139         { -999,                 NULL }
140 };
141
142 static const struct mgu_error_entry *mgu_error_find( gint err ) {
143         gint i;
144         for ( i = 0; mgu_error_list[i].e_code != -999; i++ ) {
145                 if ( err == mgu_error_list[i].e_code )
146                         return & mgu_error_list[i];
147         }
148         return NULL;
149 }
150
151 /*
152 * Return error message for specified error code.
153 */
154 gchar *mgu_error2string( gint err ) {
155         const struct mgu_error_entry *e;
156         e = mgu_error_find( err );
157         return ( e != NULL ) ? e->e_reason : "Unknown error";
158 }
159
160 /*
161 * Replace existing string with new string.
162 */
163 gchar *mgu_replace_string( gchar *str, const gchar *value ) {
164         if( str ) g_free( str );
165         if( value ) {
166                 str = g_strdup( value );
167                 g_strstrip( str );
168         }
169         else {
170                 str = NULL;
171         }
172         return str;
173 }
174
175 /*
176 * Clear a linked list by setting node data pointers to NULL. Note that
177 * items are not freed.
178 */
179 void mgu_clear_slist( GSList *list ) {
180         GSList *node = list;
181         while( node ) {
182                 node->data = NULL;
183                 node = g_slist_next( node );
184         }
185 }
186
187 /*
188 * Clear a linked list by setting node data pointers to NULL. Note that
189 * items are not freed.
190 */
191 void mgu_clear_list( GList *list ) {
192         GList *node = list;
193         while( node ) {
194                 node->data = NULL;
195                 node = g_list_next( node );
196         }
197 }
198
199 /*
200 * Test and reformat an email address.
201 * Enter:  address.
202 * Return: Address, or NULL if address is empty.
203 * Note: Leading and trailing white space is removed.
204 */
205 gchar *mgu_email_check_empty( gchar *address ) {
206         gchar *retVal = NULL;
207         if( address ) {
208                 retVal = g_strdup( address );
209                 retVal = g_strchug( retVal );
210                 retVal = g_strchomp( retVal );
211                 if( *retVal == '\0' ) {
212                         g_free( retVal );
213                         retVal = NULL;
214                 }
215         }
216         return retVal;
217 }
218
219 /*
220 * Parse string into linked list. Whitespace is used as a delimiter in parsing.
221 * Strings are parsed until maxTokens - 1 is reached. The remainder of the
222 * input string is copied into last element of list.
223 * Enter: line      String to parse.
224 *        maxTokens Maximum number of tokens to parse.
225 *        tokenCnt  If arg supplied, update with count of number of token parsed.
226 * Return: Linked list. The list contents should be g_free'd and list should
227 * freed when done.
228 */
229 GList *mgu_parse_string( gchar *line, const gint maxTokens, gint *tokenCnt ) {
230         gchar *ptr, *pStart, *pFound, *str;
231         gint  args = 0;
232         GList *list = NULL;
233         gboolean done = FALSE;
234
235         if( tokenCnt ) *tokenCnt = 0;
236         if( line == NULL ) return NULL;
237         if( maxTokens < 1 ) return NULL;
238
239         ptr = line;
240         while( ! done ) {
241                 args++;
242                 /* Skip over leading spaces */
243                 while( *ptr ) {
244                         if( ! isspace( *ptr ) ) break;
245                         ptr++;  
246                 }
247
248                 /* Find terminating space */
249                 pFound = NULL;
250                 pStart = ptr;
251                 while( *ptr ) {
252                         if( isspace( *ptr ) ) {
253                                 pFound = pStart;
254                                 break;
255                         }
256                         ptr++;
257                 }
258
259                 if( pFound ) {
260                         if( args == maxTokens ) {
261                                 /* Rest of string */
262                                 str = g_strdup( pStart );
263                                 done = TRUE;
264                         }
265                         else {
266                                 /* Extract part of string */
267                                 str = g_strndup( pStart, ptr - pFound );
268                         }
269                 }
270                 else {
271                         /* Nothing there - treat as rest of string */
272                         str = g_strdup( pStart );
273                         done = TRUE;
274                 }
275                 list = g_list_append( list, str );
276         }
277         if( tokenCnt ) *tokenCnt = args;
278         return list;
279 }
280
281 /*
282  * Unescape characters by removing backslash character from input string.
283  * Enter: str String to process.
284  */
285 void mgu_str_unescape( gchar *str ) {
286         gchar *p;
287         gint ilen;
288
289         p = str;
290         while( *p ) {
291                 if( *p == '\\' ) {
292                         ilen = strlen( p + 1 );
293                         memmove( p, p + 1, ilen );
294                 }
295                 p++;
296         }
297 }
298
299 /*
300  * Replace leading and trailing characters (eg, quotes) in input string
301  * with spaces. Only matching non-blank characters that appear at both
302  * start and end of string are replaces. Control characters are also
303  * replaced with spaces.
304  * Enter: str    String to process.
305  *        chlea  Lead character to remove.
306  *        chtail Matching trailing character.
307  */
308 void mgu_str_ltc2space( gchar *str, gchar chlead, gchar chtail ) {
309         gchar *as;
310         gchar *ae;
311
312         /* Search forwards for first non-space match */
313         as = str;
314         ae = -1 + str + strlen( str );
315         while( as < ae ) {
316                 if( *as != ' ' ) {
317                         if( *as == chlead ) {
318                                 /* Search backwards from end for match */
319                                 while( ae > as ) {
320                                         if( *ae != ' ' ) {
321                                                 if( *ae == chtail ) {
322                                                         *as = ' ';
323                                                         *ae = ' ';
324                                                         return;
325                                                 }
326                                                 if( *ae < 32 ) {
327                                                         *ae = ' ';
328                                                 }
329                                                 else if( *ae == 127 ) {
330                                                         *ae = ' ';
331                                                 }
332                                                 else {
333                                                         return;
334                                                 }
335                                         }
336                                         ae--;
337                                 }
338                         }
339                         if( *as < 32 ) {
340                                 *as = ' ';
341                         }
342                         else if( *as == 127 ) {
343                                 *as = ' ';
344                         }
345                         else {
346                                 return;
347                         }
348                 }
349                 as++;
350         }
351         return;
352 }
353
354 /*
355 * End of Source.
356 */