1 /*:ts=8*/
2 /*****************************************************************************
3 * FIDOGATE --- Gateway UNIX Mail/News <-> FIDO NetMail/EchoMail
4 *
5 * $Id: misc.c,v 4.24 2004/08/22 20:19:11 n0ll Exp $
6 *
7 * Miscellaneous functions
8 *
9 *****************************************************************************
10 * Copyright (C) 1990-2004
11 * _____ _____
12 * | |___ | Martin Junius
13 * | | | | | | Radiumstr. 18 Internet: mj.at.n0ll.dot.net
14 * |_|_|_|@home| D-51069 Koeln, Germany
15 *
16 * This file is part of FIDOGATE.
17 *
18 * FIDOGATE is free software; you can redistribute it and/or modify it
19 * under the terms of the GNU General Public License as published by the
20 * Free Software Foundation; either version 2, or (at your option) any
21 * later version.
22 *
23 * FIDOGATE is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with FIDOGATE; see the file COPYING. If not, write to the Free
30 * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
31 *****************************************************************************/
32
33 #include "fidogate.h"
34
35
36
37 /*
38 * str_change_ext(): change extension of string buffer containing filename
39 */
str_change_ext(char * new,size_t len,char * old,char * ext)40 char *str_change_ext(char *new, size_t len, char *old, char *ext)
41 {
42 int off;
43
44 str_copy(new, len, old);
45 off = strlen(new) - strlen(ext);
46 if(off < 0)
47 off = 0;
48 str_copy(new+off, len-off, ext);
49
50 return new;
51 }
52
53
54
55 /*
56 * str_printf(): wrapper for sprintf()/snprintf()
57 */
str_printf(char * buf,size_t len,const char * fmt,...)58 int str_printf(char *buf, size_t len, const char *fmt, ...)
59 {
60 va_list args;
61 int n;
62
63 va_start(args, fmt);
64
65 #ifdef HAS_SNPRINTF
66 n = vsnprintf(buf, len, fmt, args);
67 /**FIXME: check for n==-1 and errno**/
68 #else
69 n = vsprintf(buf, fmt, args);
70 if(n >= len)
71 {
72 fatal("Internal error - str_printf() buf overflow", EX_SOFTWARE);
73 /**NOT REACHED**/
74 return ERROR;
75 }
76 #endif
77 /* Make sure that buf[] is terminated with a \0. vsnprintf()
78 * should do this automatically as required by the ANSI C99
79 * proposal, but one never knows ... see also discussion on
80 * BugTraq */
81 buf[len - 1] = 0;
82
83 va_end(args);
84
85 return n;
86 }
87
88
89
90 /*
91 * Last char in string
92 */
str_last(char * s,size_t len)93 int str_last(char *s, size_t len)
94 {
95 int l = strlen(s) - 1;
96 if(l >= len)
97 l = len - 1;
98 if(l < 0)
99 l = 0;
100
101 return s[l];
102 }
103
104
105
106 /*
107 * Pointer to last char in string
108 */
str_lastp(char * s,size_t len)109 char *str_lastp(char *s, size_t len)
110 {
111 int l = strlen(s) - 1;
112 if(l >= len)
113 l = len - 1;
114 if(l < 0)
115 l = 0;
116
117 return s + l;
118 }
119
120
121
122 /*
123 * Convert to lower case
124 */
str_lower(char * s)125 char *str_lower(char *s)
126 {
127 char *p;
128
129 if(!s)
130 return NULL;
131
132 for(p=s; *p; p++)
133 if(isupper(*p))
134 *p = tolower(*p);
135
136 return s;
137 }
138
139
140
141 /*
142 * Convert to upper case
143 */
str_upper(char * s)144 char *str_upper(char *s)
145 {
146 char *p;
147
148 if(!s)
149 return NULL;
150
151 for(p=s; *p; p++)
152 if(islower(*p))
153 *p = toupper(*p);
154
155 return s;
156 }
157
158
159
160 /*
161 * Secure string functions:
162 *
163 * str_copy (d,n,s) - copy string
164 * str_copy2 (d,n,s1,s2) - copy concatenation of 2 strings
165 * str_copy3 (d,n,s1,s2,s3) - copy concatenation of 3 strings
166 * str_copy4 (d,n,s1,s2,s3,s4) - copy concatenation of 4 strings
167 * str_copy5 (d,n,s1,s2,s3,s4,s5) - copy concatenation of 5 strings
168 * str_append(d,n,s) - append string
169 *
170 * d = destination buffer
171 * n = destination size
172 */
str_copy(char * d,size_t n,char * s)173 char *str_copy(char *d, size_t n, char *s)
174 {
175 strncpy(d, s, n);
176 d[n-1] = 0;
177 return d;
178 }
179
str_append(char * d,size_t n,char * s)180 char *str_append(char *d, size_t n, char *s)
181 {
182 int max = n - strlen(d) - 1;
183 strncat(d, s, max);
184 d[n-1] = 0;
185 return d;
186 }
187
str_copy2(char * d,size_t n,char * s1,char * s2)188 char *str_copy2(char *d, size_t n, char *s1, char *s2)
189 {
190 str_copy (d, n, s1);
191 str_append(d, n, s2);
192 return d;
193 }
194
str_copy3(char * d,size_t n,char * s1,char * s2,char * s3)195 char *str_copy3(char *d, size_t n, char *s1, char *s2, char *s3)
196 {
197 str_copy (d, n, s1);
198 str_append(d, n, s2);
199 str_append(d, n, s3);
200 return d;
201 }
202
str_copy4(char * d,size_t n,char * s1,char * s2,char * s3,char * s4)203 char *str_copy4(char *d, size_t n, char *s1, char *s2, char *s3, char *s4)
204 {
205 str_copy (d, n, s1);
206 str_append(d, n, s2);
207 str_append(d, n, s3);
208 str_append(d, n, s4);
209 return d;
210 }
211
str_copy5(char * d,size_t n,char * s1,char * s2,char * s3,char * s4,char * s5)212 char *str_copy5(char *d, size_t n, char *s1, char *s2, char *s3, char *s4, char *s5)
213 {
214 str_copy (d, n, s1);
215 str_append(d, n, s2);
216 str_append(d, n, s3);
217 str_append(d, n, s4);
218 str_append(d, n, s5);
219 return d;
220 }
221
222
223
224 /*
225 * Copy string range
226 */
str_copy_range(char * d,size_t n,char * s,char * lim)227 char *str_copy_range(char *d, size_t n, char *s, char *lim)
228 {
229 int i;
230
231 for(i=0; i<n-1 && s<lim; i++, s++)
232 d[i] = *s;
233 d[i] = 0;
234
235 return d;
236 }
237
238
239
240 #if !defined(HAS_STRCASECMP) && !defined(HAS_STRICMP)
241 /***** strnicmp() --- compare n chars of strings ignoring case ***************/
242
strnicmp(char * sa,char * sb,int len)243 int strnicmp(char *sa, char *sb, int len)
244 {
245 while(len--)
246 if(tolower(*sa) == tolower(*sb)) {
247 sa++;
248 sb++;
249 }
250 else if(tolower(*sa) < tolower(*sb))
251 return(-1);
252 else
253 return(1);
254 return(0);
255 }
256
257
258
259 /***** stricmp() --- compare strings ignoring case ***************************/
260
stricmp(char * sa,char * sb)261 int stricmp(char *sa, char *sb)
262 {
263 while(tolower(*sa) == tolower(*sb)) {
264 if(!*sa)
265 return(0);
266 sa++;
267 sb++;
268 }
269 return(tolower(*sa) - tolower(*sb));
270 }
271 #endif /**!HAS_STRCASECMP && !HAS_STRICMP**/
272
273
274
275 /*
276 * Remove \r\n from end of line
277 */
strip_crlf(char * line)278 void strip_crlf(char *line)
279 {
280 int len;
281
282 if(!line)
283 return;
284
285 len = strlen(line);
286 if( line[len-1] == '\n' )
287 line[len-1] = 0;
288
289 len = strlen(line);
290 if( line[len-1] == '\r' )
291 line[len-1] = 0;
292 }
293
294
295
296 /*
297 * Remove white space at end of line
298 */
strip_space(char * line)299 char *strip_space(char *line)
300 {
301 int i;
302 char *s;
303
304 if(!line)
305 return NULL;
306
307 for(i=strlen(line)-1; i>=0; i--)
308 if(is_space(line[i]))
309 line[i] = 0;
310 else
311 break;
312
313 for(s=line; is_space(*s); s++) ;
314 return s;
315 }
316
317
318
319 /*
320 * isspace() replacement, checking for SPACE, TAB, CR, LF
321 */
is_space(int c)322 int is_space(int c)
323 {
324 return c==' ' || c=='\t' || c=='\r' || c=='\n';
325 }
326
327
328 /*
329 * checking for SPACE or TAB
330 */
is_blank(int c)331 int is_blank(int c)
332 {
333 return c==' ' || c=='\t';
334 }
335
336
337 /*
338 * signed char-safe version of isdigit()
339 */
is_digit(int c)340 int is_digit(int c)
341 {
342 /* Some <ctype.h> implementation only accept a parameter value range
343 * of [-1,255]. This may lead to problems, because we're quite often
344 * passing *p's to is_digit() with a char *p variable. The default
345 * char type is signed in most C implementation. */
346 return isdigit((c & 0xff));
347 }
348
349
350 /*
351 * Check for hex digits, signed char-safe version of isxdigit()
352 */
is_xdigit(int c)353 int is_xdigit(int c)
354 {
355 /* Some <ctype.h> implementation only accept a parameter value range
356 * of [-1,255]. This may lead to problems, because we're quite often
357 * passing *p's to is_digit() with a char *p variable. The default
358 * char type is signed in most C implementation. */
359 return isxdigit((c & 0xff));
360 }
361
362
363 /*
364 * Check for octal digits
365 */
is_odigit(int c)366 int is_odigit(int c)
367 {
368 return c>='0' && c<'8';
369 }
370
371
372
373 /*
374 * Expand %X at start of file names
375 *
376 * See config.make for definition of abbreviations.
377 */
378 static struct st_atable
379 {
380 int c;
381 char *(*func)(void);
382 }
383 atable[] =
384 {
385 /* Include code generated by subst.pl -A */
386 # include "cf_abbrev.c"
387 { 0, NULL }
388 };
389
390
str_expand_name(char * d,size_t n,char * s)391 char *str_expand_name(char *d, size_t n, char *s)
392 {
393 int i;
394
395 d[0] = 0;
396
397 if(s[0] == '%')
398 {
399 for(i=0; atable[i].c; i++)
400 if(atable[i].c == s[1])
401 {
402 str_append(d, n, atable[i].func());
403 s+=2;
404 break;
405 }
406 }
407
408 str_append(d, n, s);
409
410 return d;
411 }
412
413
414
415 /*
416 * Convert `/' to `\' for MSDOS / OS2 filenames
417 */
str_dosify(char * s)418 char *str_dosify(char *s)
419 {
420 for(; *s; s++)
421 switch(*s)
422 {
423 case '/':
424 *s = '\\'; break;
425 }
426 return s;
427 }
428
429
430
431 /*
432 * Run system command, return exit code
433 */
run_system(char * s)434 int run_system(char *s)
435 {
436 char cmd[BUFFERSIZE];
437
438 BUF_EXPAND(cmd, s);
439 DOSIFY_IF_NEEDED(cmd);
440 return (system(cmd) >> 8) & 0xff;
441 }
442