blob: bbb2056d7348957258eecb67b1f89b8977bd41d0 [file] [log] [blame]
Daniel Veillard92ad2102001-03-27 12:47:33 +00001/*************************************************************************
2 *
3 * $Id$
4 *
5 * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
12 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
13 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
14 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
15 *
16 ************************************************************************/
17
Bjorn Reese70a9da52001-04-21 16:57:29 +000018/*
19 * TODO
20 * - StrToLongDouble
Daniel Veillard92ad2102001-03-27 12:47:33 +000021 */
22
23static const char rcsid[] = "@(#)$Id$";
24
25#if defined(unix) || defined(__xlC__)
26# define PLATFORM_UNIX
27#elif defined(WIN32) || defined(_WIN32)
28# define PLATFORM_WIN32
29#elif defined(AMIGA) && defined(__GNUC__)
30# define PLATFORM_UNIX
31#endif
32
33#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
34# define TRIO_C99
35#endif
36
37#include "strio.h"
38#include <string.h>
39#include <ctype.h>
40#include <stdarg.h>
41#include <time.h>
42#include <math.h>
43#ifndef DEBUG
44# define NDEBUG
45#endif
46#include <assert.h>
47
48#ifndef NULL
49# define NULL 0
50#endif
51#define NIL ((char)0)
52#ifndef FALSE
53# define FALSE (1 == 0)
54# define TRUE (! FALSE)
55#endif
56
57#define VALID(x) (NULL != (x))
58#define INVALID(x) (NULL == (x))
59
60#if defined(PLATFORM_UNIX)
61# define USE_STRCASECMP
62# define USE_STRNCASECMP
63# define USE_STRERROR
64#elif defined(PLATFORM_WIN32)
65# define USE_STRCMPI
66#endif
67
68/*************************************************************************
69 * StrAppendMax
70 */
71char *StrAppendMax(char *target, size_t max, const char *source)
72{
73 assert(VALID(target));
74 assert(VALID(source));
75 assert(max > 0);
76
77 max -= StrLength(target) + 1;
78 return (max > 0) ? strncat(target, source, max) : target;
79}
80
81/*************************************************************************
82 * StrCopyMax
83 */
84char *StrCopyMax(char *target, size_t max, const char *source)
85{
86 assert(VALID(target));
87 assert(VALID(source));
88 assert(max > 0); /* Includes != 0 */
89
90 target = strncpy(target, source, max - 1);
91 target[max - 1] = (char)0;
92 return target;
93}
94
95/*************************************************************************
96 * StrDuplicate
97 */
98char *StrDuplicate(const char *source)
99{
100 char *target;
101
102 assert(VALID(source));
103
104 target = (char *)malloc(StrLength(source) + 1);
105 if (target)
106 {
107 StrCopy(target, source);
108 }
109 return target;
110}
111
112/*************************************************************************
113 * StrDuplicateMax
114 */
115char *StrDuplicateMax(const char *source, size_t max)
116{
117 char *target;
118 size_t len;
119
120 assert(VALID(source));
121 assert(max > 0);
122
123 /* Make room for string plus a terminating zero */
124 len = StrLength(source) + 1;
125 if (len > max)
126 {
127 len = max;
128 }
129 target = (char *)malloc(len);
130 if (target)
131 {
132 StrCopyMax(target, len, source);
133 }
134 return target;
135}
136
137/*************************************************************************
138 * StrEqual
139 */
140int StrEqual(const char *first, const char *second)
141{
142 assert(VALID(first));
143 assert(VALID(second));
144
145 if (VALID(first) && VALID(second))
146 {
147#if defined(USE_STRCASECMP)
148 return (0 == strcasecmp(first, second));
149#elif defined(USE_STRCMPI)
150 return (0 == strcmpi(first, second));
151#else
152 while ((*first != NIL) && (*second != NIL))
153 {
154 if (toupper(*first) != toupper(*second))
155 {
156 break;
157 }
158 first++;
159 second++;
160 }
161 return ((*first == NIL) && (*second == NIL));
162#endif
163 }
164 return FALSE;
165}
166
167/*************************************************************************
168 * StrEqualCase
169 */
170int StrEqualCase(const char *first, const char *second)
171{
172 assert(VALID(first));
173 assert(VALID(second));
174
175 if (VALID(first) && VALID(second))
176 {
177 return (0 == strcmp(first, second));
178 }
179 return FALSE;
180}
181
182/*************************************************************************
183 * StrEqualCaseMax
184 */
185int StrEqualCaseMax(const char *first, size_t max, const char *second)
186{
187 assert(VALID(first));
188 assert(VALID(second));
189
190 if (VALID(first) && VALID(second))
191 {
192 return (0 == strncmp(first, second, max));
193 }
194 return FALSE;
195}
196
197/*************************************************************************
198 * StrEqualMax
199 */
200int StrEqualMax(const char *first, size_t max, const char *second)
201{
202 assert(VALID(first));
203 assert(VALID(second));
204
205 if (VALID(first) && VALID(second))
206 {
207#if defined(USE_STRNCASECMP)
208 return (0 == strncasecmp(first, second, max));
209#else
210 /* Not adequately tested yet */
211 size_t cnt = 0;
212 while ((*first != NIL) && (*second != NIL) && (cnt <= max))
213 {
214 if (toupper(*first) != toupper(*second))
215 {
216 break;
217 }
218 first++;
219 second++;
220 cnt++;
221 }
222 return ((cnt == max) || ((*first == NIL) && (*second == NIL)));
223#endif
224 }
225 return FALSE;
226}
227
228/*************************************************************************
229 * StrError
230 */
231const char *StrError(int errorNumber)
232{
233#if defined(USE_STRERROR)
234 return strerror(errorNumber);
235#else
236 return "unknown";
237#endif
238}
239
240/*************************************************************************
241 * StrFormatDate
242 */
243size_t StrFormatDateMax(char *target,
244 size_t max,
245 const char *format,
246 const struct tm *datetime)
247{
248 assert(VALID(target));
249 assert(VALID(format));
250 assert(VALID(datetime));
251 assert(max > 0);
252
253 return strftime(target, max, format, datetime);
254}
255
256/*************************************************************************
257 * StrHash
258 */
259unsigned long StrHash(const char *string, int type)
260{
261 unsigned long value = 0L;
262 char ch;
263
264 assert(VALID(string));
265
266 switch (type)
267 {
268 case STRIO_HASH_PLAIN:
269 while ( (ch = *string++) != NIL )
270 {
271 value *= 31;
272 value += (unsigned long)ch;
273 }
274 break;
275 default:
276 assert(FALSE);
277 break;
278 }
279 return value;
280}
281
282/*************************************************************************
283 * StrMatch
284 */
285int StrMatch(char *string, char *pattern)
286{
287 assert(VALID(string));
288 assert(VALID(pattern));
289
290 for (; ('*' != *pattern); ++pattern, ++string)
291 {
292 if (NIL == *string)
293 {
294 return (NIL == *pattern);
295 }
296 if ((toupper(*string) != toupper(*pattern))
297 && ('?' != *pattern))
298 {
299 return FALSE;
300 }
301 }
302 /* two-line patch to prevent *too* much recursiveness: */
303 while ('*' == pattern[1])
304 pattern++;
305
306 do
307 {
308 if ( StrMatch(string, &pattern[1]) )
309 {
310 return TRUE;
311 }
312 }
313 while (*string++);
314
315 return FALSE;
316}
317
318/*************************************************************************
319 * StrMatchCase
320 */
321int StrMatchCase(char *string, char *pattern)
322{
323 assert(VALID(string));
324 assert(VALID(pattern));
325
326 for (; ('*' != *pattern); ++pattern, ++string)
327 {
328 if (NIL == *string)
329 {
330 return (NIL == *pattern);
331 }
332 if ((*string != *pattern)
333 && ('?' != *pattern))
334 {
335 return FALSE;
336 }
337 }
338 /* two-line patch to prevent *too* much recursiveness: */
339 while ('*' == pattern[1])
340 pattern++;
341
342 do
343 {
344 if ( StrMatchCase(string, &pattern[1]) )
345 {
346 return TRUE;
347 }
348 }
349 while (*string++);
350
351 return FALSE;
352}
353
354/*************************************************************************
355 * StrSpanFunction
356 *
357 * Untested
358 */
359size_t StrSpanFunction(char *source, int (*Function)(int))
360{
361 size_t count = 0;
362
363 assert(VALID(source));
364 assert(VALID(Function));
365
366 while (*source != NIL)
367 {
368 if (Function(*source))
369 break; /* while */
370 source++;
371 count++;
372 }
373 return count;
374}
375
376/*************************************************************************
377 * StrSubstringMax
378 */
379char *StrSubstringMax(const char *string, size_t max, const char *find)
380{
381 size_t count;
382 size_t size;
383 char *result = NULL;
384
385 assert(VALID(string));
386 assert(VALID(find));
387
388 size = StrLength(find);
Bjorn Reese70a9da52001-04-21 16:57:29 +0000389 if (size <= max)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000390 {
Bjorn Reese70a9da52001-04-21 16:57:29 +0000391 for (count = 0; count <= max - size; count++)
Daniel Veillard92ad2102001-03-27 12:47:33 +0000392 {
393 if (StrEqualMax(find, size, &string[count]))
394 {
395 result = (char *)&string[count];
396 break;
397 }
398 }
399 }
400 return result;
401}
402
403/*************************************************************************
404 * StrToDouble
405 *
406 * double ::= [ <sign> ]
407 * ( <number> |
408 * <number> <decimal_point> <number> |
409 * <decimal_point> <number> )
410 * [ <exponential> [ <sign> ] <number> ]
411 * number ::= 1*( <digit> )
412 * digit ::= ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )
413 * exponential ::= ( 'e' | 'E' )
414 * sign ::= ( '-' | '+' )
415 * decimal_point ::= '.'
416 */
417double StrToDouble(const char *source, const char **endp)
418{
419#if defined(TRIO_C99)
420 return strtod(source, endp);
421#else
422 /* Preliminary code */
423 int isNegative = FALSE;
424 int isExponentNegative = FALSE;
425 unsigned long integer = 0;
426 unsigned long fraction = 0;
427 unsigned long fracdiv = 1;
428 unsigned long exponent = 0;
429 double value = 0.0;
430
431 /* First try hex-floats */
432 if ((source[0] == '0') && ((source[1] == 'x') || (source[1] == 'X')))
433 {
434 source += 2;
435 while (isxdigit((int)*source))
436 {
437 integer *= 16;
438 integer += (isdigit((int)*source) ? (*source - '0') :
439 (isupper((int)*source) ? (*source - 'A') :
440 (*source - 'a')));
441 source++;
442 }
443 if (*source == '.')
444 {
445 source++;
446 while (isxdigit((int)*source))
447 {
448 fraction *= 16;
449 fraction += (isdigit((int)*source) ? (*source - '0') :
450 (isupper((int)*source) ? (*source - 'A') :
451 (*source - 'a')));
452 fracdiv *= 16;
453 source++;
454 }
455 if ((*source == 'p') || (*source == 'P'))
456 {
457 source++;
458 if ((*source == '+') || (*source == '-'))
459 {
460 isExponentNegative = (*source == '-');
461 source++;
462 }
463 while (isdigit((int)*source))
464 {
465 exponent *= 10;
466 exponent += (*source - '0');
467 source++;
468 }
469 }
470 }
471 }
472 else /* Then try normal decimal floats */
473 {
474 isNegative = (*source == '-');
475 /* Skip sign */
476 if ((*source == '+') || (*source == '-'))
477 source++;
478
479 /* Integer part */
480 while (isdigit((int)*source))
481 {
482 integer *= 10;
483 integer += (*source - '0');
484 source++;
485 }
486
487 if (*source == '.')
488 {
489 source++; /* skip decimal point */
490 while (isdigit((int)*source))
491 {
492 fraction *= 10;
493 fraction += (*source - '0');
494 fracdiv *= 10;
495 source++;
496 }
497 }
498 if ((*source == 'e') || (*source == 'E'))
499 {
500 source++; /* Skip exponential indicator */
501 isExponentNegative = (*source == '-');
502 if ((*source == '+') || (*source == '-'))
503 source++;
504 while (isdigit((int)*source))
505 {
506 exponent *= 10;
507 exponent += (*source - '0');
508 source++;
509 }
510 }
511 }
512
513 value = (double)integer;
514 if (fraction != 0)
515 {
516 value += (double)fraction / (double)fracdiv;
517 }
518 if (exponent != 0)
519 {
520 if (isExponentNegative)
521 value /= pow((double)10, (double)exponent);
522 else
523 value *= pow((double)10, (double)exponent);
524 }
525 if (isNegative)
526 value = -value;
527
528 if (endp)
529 *endp = source;
530 return value;
531#endif
532}
533
534/*************************************************************************
535 * StrToFloat
536 */
537float StrToFloat(const char *source, const char **endp)
538{
539#if defined(TRIO_C99)
540 return strtof(source, endp);
541#else
542 return (float)StrToDouble(source, endp);
543#endif
544}
545
546/*************************************************************************
547 * StrToUpper
548 */
549int StrToUpper(char *target)
550{
551 int i = 0;
552
553 assert(VALID(target));
554
555 while (NIL != *target)
556 {
557 *target = toupper(*target);
558 target++;
559 i++;
560 }
561 return i;
562}