Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / stdfn.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: stdfn.c,v 1.17 2005/07/26 04:24:16 sfeam Exp $"); }
3 #endif
4
5 /* GNUPLOT - stdfn.c */
6
7 /*[
8  * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37
38 /* This module collects various functions, which were previously scattered
39  * all over the place. In a future implementation of gnuplot, each of
40  * these functions will probably reside in their own file in a subdirectory.
41  * - Lars Hecking
42  */
43
44 #include "stdfn.h"
45
46 #ifdef WIN32
47 /* the WIN32 API has a Sleep function that does not consume CPU cycles */
48 #include <windows.h>
49 #endif
50
51
52 /*
53  * ANSI C functions
54  */
55
56 /* memcpy() */
57
58 #ifndef HAVE_MEMCPY
59 # ifndef HAVE_BCOPY
60 /*
61  * cheap and slow version of memcpy() in case you don't have one
62  */
63
64 char *
65 memcpy(char *dest, char *src, size_t len)
66 {
67     while (len--)
68         *dest++ = *src++;
69
70     return dest;
71 }
72 # endif                         /* !HAVE_BCOPY */
73 #endif /* HAVE_MEMCPY */
74
75 /* strchr()
76  * Simple and portable version, conforming to Plauger.
77  * Would this be more efficient as a macro?
78  */
79 #ifndef HAVE_STRCHR
80 # ifndef HAVE_INDEX
81
82 char *
83 strchr(const char *s, int c)
84 {
85     do {
86         if (*s == (char) c)
87             return s;
88     } while (*s++ != (char) 0);
89
90     return NULL;
91 }
92 # endif                         /* !HAVE_INDEX */
93 #endif /* HAVE_STRCHR */
94
95
96 /* memset ()
97  *
98  * Since we want to use memset, we have to map a possibly nonzero fill byte
99  * to the bzero function. The following defined might seem a bit odd, but I
100  * think this is the only possible way.
101  */
102
103 #ifndef HAVE_MEMSET
104 # ifdef HAVE_BZERO
105 #  define memset(s, b, l) \
106 do {                      \
107   assert((b)==0);         \
108   bzero((s), (l));        \
109 } while(0)
110 #  else
111 #  define memset NO_MEMSET_OR_BZERO
112 # endif /* HAVE_BZERO */
113 #endif /* HAVE_MEMSET */
114
115
116 /* strerror() */
117 #ifndef HAVE_STRERROR
118
119 char *
120 strerror(int no)
121 {
122     static char res_str[30];
123
124     if (no > sys_nerr) {
125         sprintf(res_str, "unknown errno %d", no);
126         return res_str;
127     } else {
128         return sys_errlist[no];
129     }
130 }
131 #endif /* HAVE_STRERROR */
132
133
134 /* strstr() */
135 #ifndef HAVE_STRSTR
136
137 char *
138 strstr(const char *cs, const char *ct)
139 {
140     size_t len;
141
142     if (!cs || !ct)
143         return NULL;
144
145     if (!*ct)
146         return (char *) cs;
147
148     len = strlen(ct);
149     while (*cs) {
150         if (strncmp(cs, ct, len) == 0)
151             return (char *) cs;
152         cs++;
153     }
154
155     return NULL;
156 }
157 #endif /* HAVE_STRSTR */
158
159
160 #ifdef __PUREC__
161 /*
162  * a substitute for PureC's buggy sscanf.
163  * this uses the normal sscanf and fixes the following bugs:
164  * - whitespace in format matches whitespace in string, but doesn't
165  *   require any. ( "%f , %f" scans "1,2" correctly )
166  * - the ignore value feature works (*). this created an address error
167  *   in PureC.
168  */
169
170 #include <stdarg.h>
171
172 int
173 purec_sscanf(const char *string, const char *format,...)
174 {
175     va_list args;
176     int cnt = 0;
177     char onefmt[256];
178     char buffer[256];
179     const char *f = format;
180     const char *s = string;
181     char *f2;
182     char ch;
183     int ignore;
184     void *p;
185     int *ip;
186     int pos;
187
188     va_start(args, format);
189     while (*f && *s) {
190         ch = *f++;
191         if (ch != '%') {
192             if (isspace((unsigned char) ch)) {
193                 /* match any number of whitespace */
194                 while (isspace((unsigned char) *s))
195                     s++;
196             } else {
197                 /* match exactly the character ch */
198                 if (*s != ch)
199                     goto finish;
200                 s++;
201             }
202         } else {
203             /* we have got a '%' */
204             ch = *f++;
205             if (ch == '%') {
206                 /* match exactly % */
207                 if (*s != ch)
208                     goto finish;
209                 s++;
210             } else {
211                 f2 = onefmt;
212                 *f2++ = '%';
213                 *f2++ = ch;
214                 ignore = 0;
215                 if (ch == '*') {
216                     ignore = 1;
217                     ch = f2[-1] = *f++;
218                 }
219                 while (isdigit((unsigned char) ch)) {
220                     ch = *f2++ = *f++;
221                 }
222                 if (ch == 'l' || ch == 'L' || ch == 'h') {
223                     ch = *f2++ = *f++;
224                 }
225                 switch (ch) {
226                 case '[':
227                     while (ch && ch != ']') {
228                         ch = *f2++ = *f++;
229                     }
230                     if (!ch)
231                         goto error;
232                     break;
233                 case 'e':
234                 case 'f':
235                 case 'g':
236                 case 'd':
237                 case 'o':
238                 case 'i':
239                 case 'u':
240                 case 'x':
241                 case 'c':
242                 case 's':
243                 case 'p':
244                 case 'n':       /* special case handled below */
245                     break;
246                 default:
247                     goto error;
248                 }
249                 if (ch != 'n') {
250                     strcpy(f2, "%n");
251                     if (ignore) {
252                         p = buffer;
253                     } else {
254                         p = va_arg(args, void *);
255                     }
256                     switch (sscanf(s, onefmt, p, &pos)) {
257                     case EOF:
258                         goto error;
259                     case 0:
260                         goto finish;
261                     }
262                     if (!ignore)
263                         cnt++;
264                     s += pos;
265                 } else {
266                     if (!ignore) {
267                         ip = va_arg(args, int *);
268                         *ip = (int) (s - string);
269                     }
270                 }
271             }
272         }
273     }
274
275     if (!*f)
276         goto finish;
277
278   error:
279     cnt = EOF;
280   finish:
281     va_end(args);
282     return cnt;
283 }
284
285 /* use the substitute now. I know this is dirty trick, but it works. */
286 #define sscanf purec_sscanf
287
288 #endif /* __PUREC__ */
289
290
291 /*
292  * POSIX functions
293  */
294
295 #ifndef HAVE_SLEEP
296 /* The implementation below does not even come close
297  * to what is required by POSIX.1, but I suppose
298  * it doesn't really matter on these systems. lh
299  */
300
301
302 #ifdef AMIGA_SC_6_1
303 #include <proto/dos.h>
304 #endif
305
306 unsigned int
307 sleep(unsigned int delay)
308 {
309 #if defined(MSDOS) || defined(_Windows) || defined(DOS386) || defined(AMIGA_AC_5)
310 # if !(defined(__TURBOC__) || defined(__EMX__) || defined(DJGPP)) || defined(_Windows)  /* Turbo C already has sleep() */
311     /* kludge to provide sleep() for msc 5.1 */
312     unsigned long time_is_up;
313
314     time_is_up = time(NULL) + (unsigned long) delay;
315     while (time(NULL) < time_is_up)
316         /* wait */ ;
317 # endif /* !__TURBOC__ ... */
318 #endif /* MSDOS ... */
319
320 #ifdef AMIGA_SC_6_1
321     Delay(50 * delay);
322 #endif
323
324 #ifdef WIN32
325     Sleep((DWORD) delay * 1000);
326 #endif
327
328     return 0;
329 }
330
331 #endif /* HAVE_SLEEP */
332
333
334 /*
335  * Other common functions
336  */
337
338 /*****************************************************************
339     portable implementation of strnicmp (hopefully)
340 *****************************************************************/
341 #ifndef HAVE_STRCASECMP
342 # ifndef HAVE_STRICMP
343
344 /* return (see MSVC documentation and strcasecmp()):
345  *  -1  if str1 < str2
346  *   0  if str1 == str2
347  *   1  if str1 > str2
348  */
349 int
350 gp_stricmp(const char *s1, const char *s2)
351 {
352     unsigned char c1, c2;
353
354     do {
355         c1 = *s1++;
356         if (islower(c1))
357             c1 = toupper(c1);
358         c2 = *s2++;
359         if (islower(c2))
360             c2 = toupper(c2);
361     } while (c1 == c2 && c1 && c2);
362
363     if (c1 == c2)
364         return 0;
365     if (c1 == '\0' || c1 > c2)
366         return 1;
367     return -1;
368 }
369 # endif                         /* !HAVE_STRCASECMP */
370 #endif /* !HAVE_STRNICMP */
371
372 /*****************************************************************
373     portable implementation of strnicmp (hopefully)
374 *****************************************************************/
375
376 #ifndef HAVE_STRNCASECMP
377 # ifndef HAVE_STRNICMP
378
379 int
380 gp_strnicmp(const char *s1, const char *s2, size_t n)
381 {
382     unsigned char c1, c2;
383
384     if (n == 0)
385         return 0;
386
387     do {
388         c1 = *s1++;
389         if (islower(c1))
390             c1 = toupper(c1);
391         c2 = *s2++;
392         if (islower(c2))
393             c2 = toupper(c2);
394     } while (c1 == c2 && c1 && c2 && --n > 0);
395
396     if (n == 0 || c1 == c2)
397         return 0;
398     if (c1 == '\0' || c1 > c2)
399         return 1;
400     return -1;
401 }
402 # endif                         /* !HAVE_STRNCASECMP */
403 #endif /* !HAVE_STRNICMP */
404
405
406 /* Safe, '\0'-terminated version of strncpy()
407  * safe_strncpy(dest, src, n), where n = sizeof(dest)
408  * This is basically the old fit.c(copy_max) function
409  */
410 char *
411 safe_strncpy(char *d, const char *s, size_t n)
412 {
413     char *ret;
414
415     ret = strncpy(d, s, n);
416     if (strlen(s) >= n)
417         d[n > 0 ? n - 1 : 0] = NUL;
418
419     return ret;
420 }
421
422 #ifndef HAVE_STRCSPN
423 /*
424  * our own substitute for strcspn()
425  * return the length of the inital segment of str1
426  * consisting of characters not in str2
427  * returns strlen(str1) if none of the characters
428  * from str2 are in str1
429  * based in misc.c(instring) */
430 size_t
431 gp_strcspn(const char *str1, const char *str2)
432 {
433     char *s;
434     size_t pos;
435
436     if (!str1 || !str2)
437         return 0;
438     pos = strlen(str1);
439     while (*str2++)
440         if (s = strchr(str1, *str2))
441             if ((s - str1) < pos)
442                 pos = s - str1;
443     return (pos);
444 }
445 #endif /* !HAVE_STRCSPN */
446
447 double
448 gp_strtod(const char *str, char **endptr)
449 {
450 #if (0)  /* replace with test for platforms with broken strtod() */
451     int used;
452     double d;
453     int n = sscanf(str, "%lf%n", &d, &used);
454     if (n < 1)
455         *endptr = (char *)str;
456     else
457         *endptr = (char *)(str + used);
458     return d;
459 #else
460     return strtod(str,endptr);
461 #endif
462 }