1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 /*
34 This file containes various miniscule code fragments that don't really
35 belong anywhere in Coin, but which is included to make it easier to keep
36 Coin portable.
37 */
38
39 /*! \file tidbits.h */
40 #include <Inventor/C/tidbits.h>
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif /* HAVE_CONFIG_H */
45
46 #include <cassert>
47 #include <cerrno>
48 #include <cmath> /* std::isinf(), std::isnan(), finite() */
49 #include <cfloat> /* _fpclass(), _isnan(), _finite() */
50 #include <clocale>
51 #include <cstring> /* strncasecmp() */
52 #include <cstdio>
53 #include <cstdlib> /* atio() */
54 #include <cctype> /* tolower() */
55 #include <cstdlib> /* atexit(), putenv(), qsort(), atof() */
56 #ifdef HAVE_WINDOWS_H
57 #include <windows.h> /* GetEnvironmentVariable() */
58 #endif /* HAVE_WINDOWS_H */
59
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #include <fcntl.h>
63 #ifdef HAVE_IO_H
64 #include <io.h> /* defines open() on MSVC++ 5.0 */
65 #endif /* HAVE_IO_H */
66 #ifdef HAVE_UNISTD_H
67 #include <unistd.h>
68 #endif /* HAVE_UNISTD_H */
69 #ifdef HAVE_IEEEFP_H
70 #include <ieeefp.h>
71 #endif /* HAVE_IEEEFP_H */
72
73 #ifdef HAVE_DIRECT_H
74 #include <direct.h> /* _getcwd() */
75 #endif /* HAVE_DIRECT_H */
76
77 #include <Inventor/C/base/string.h>
78 #include <Inventor/C/base/list.h>
79 #include <Inventor/C/errors/debugerror.h>
80
81 #include "tidbitsp.h"
82 #include "coindefs.h"
83
84 /**************************************************************************/
85
86 /* FIXME: we should grab some BSD/PD-style licensed code to provide a
87 replacement for the (v)snprintf functions. This would provide a
88 fail-safe option on obscure platforms.
89
90 Here is handegar's list of possible candidates (note that many of
91 these can probably be ruled out due to the license restrictions --
92 we need to be able to find code with a liberal enough license that
93 we can re-license it under the Coin PEL and the GPL, which
94 probably effectively limits us to code in the PD, or possibly under
95 BSD- or MIT-style licenses:
96
97 1) The BSDs:
98
99 - http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/
100 - http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdio/
101 - http://cvsweb.netbsd.org/cgi-bin/cvsweb.cgi/basesrc/lib/libc/stdio/
102
103
104 2) A portable snprintf under either GNU (L?)GPL or the "Frontier
105 Artistic Lisence" (wahtever that is):
106
107 - http://www.ijs.si/software/snprintf/
108
109
110 3) TRIO (seems to be under an "MIT-like" license):
111
112 - http://daniel.haxx.se/trio/
113
114
115 4) Samba (under GNU GPL?):
116
117 - http://samba.org/cgi-bin/cvsweb/samba/source/lib/snprintf.c
118
119
120 5) Apache:
121
122 - http://www.apache.org
123
124
125 6) Caol�n McNamara's (GNU GPL?):
126
127 - http://www.csn.ul.ie/~caolan/publink/snprintf-1.1.tar.gz
128
129
130 7) Castaglia (GNU GPL?):
131
132 - http://www.castaglia.org/proftpd/doc/devel-guide/src/lib/vsnprintf.c.html
133
134
135 8) Gnome (GNU (L?)GPL? -- looks very similar to the Samba
136 implementation):
137
138 - http://cvs.gnome.org/lxr/
139
140 20021128 mortene.
141
142 UPDATE 20021206 mortene: it looks like integrating any of these
143 would be quite some effort, to get the build / configure stuff
144 correct, to slim down the code of the chosen implementation, etc
145 etc. I think our first step should perhaps be to let configure bail
146 out if no "native" snprintf() is found on the system, with a good
147 error message, a fallback, and a notice about mailing us info on
148 the platform in question. Just so we avoid spending much time
149 solving a problem which is really not there on any platform Coin is
150 being used.
151 */
152
153 #ifdef __cplusplus
154 extern "C" {
155 #endif
156
157 /* ********************************************************************** */
158
159 #ifdef COIN_THREADSAFE
160 #include <Inventor/C/threads/mutex.h>
161 #include "threads/mutexp.h"
162 static cc_mutex * atexit_list_monitor = NULL;
163 #endif /* COIN_THREADSAFE */
164
165
166 static int COIN_DEBUG_EXTRA = -1;
167 static int COIN_DEBUG_NORMALIZE = -1;
168
169 /* ********************************************************************** */
170
171 /* Called from SoDB::init() exactly once, a call which is guaranteed
172 free from race conditions. */
173 void
coin_init_tidbits(void)174 coin_init_tidbits(void)
175 {
176 const char * env;
177 #ifdef COIN_THREADSAFE
178 atexit_list_monitor = cc_mutex_construct();
179 #endif /* COIN_THREADSAFE */
180
181 env = coin_getenv("COIN_DEBUG_EXTRA");
182 if (env && atoi(env) == 1) {
183 COIN_DEBUG_EXTRA = 1;
184 }
185 else {
186 COIN_DEBUG_EXTRA = 0;
187 }
188 env = coin_getenv("COIN_DEBUG_NORMALIZE");
189 if (env && atoi(env) == 1) {
190 COIN_DEBUG_NORMALIZE = 1;
191 }
192 else {
193 COIN_DEBUG_NORMALIZE = 0;
194 }
195 }
196
197 /* ********************************************************************** */
198
199 /*
200 coin_vsnprintf() wrapper. Returns -1 if resultant string will be
201 longer than n.
202 */
203
204 typedef int func_vsnprintf(char *, size_t, const char *, va_list);
205
206 static int
coin_common_vsnprintf(func_vsnprintf * func,char * dst,size_t n,const char * fmtstr,va_list args)207 coin_common_vsnprintf(func_vsnprintf * func,
208 char * dst, size_t n,
209 const char * fmtstr, va_list args)
210 {
211 int length;
212 static int debug = -1;
213
214 if (debug == -1) {
215 const char * env = coin_getenv("COIN_DEBUG_NPRINTF");
216 debug = (env && (atoi(env) > 0)) ? 1 : 0;
217 }
218
219 /* Note: subtract one from n as the buffer size, because libDCE on
220 HP-UX has a vsnprintf() implementation which will otherwise
221 overwrite the array with one byte (it doesn't count the trailing
222 \0, as e.g. GNU libc does, and like a C99-conforming
223 implementation would). */
224 assert(n > 1);
225 n -= 1;
226
227 /* Can not use cc_debugerror_* interface(), as that could cause an
228 infinite recursion. */
229 if (debug) { printf("dst==%p, n==%zu, fmtstr=='%s'\n", dst, n, fmtstr); }
230
231 #ifdef HAVE_VA_COPY_MACRO
232 /* The C99 va_copy() is available, so use that to help us "rewind"
233 the va_list between invocations. */
234 {
235 va_list argscopy;
236 va_copy(argscopy, args);
237 length = (*func)(dst, n, fmtstr, argscopy);
238 va_end(argscopy);
239 }
240 #else /* !HAVE_VA_COPY_MACRO */
241 /* No va_copy() available, so we just assume the system's
242 vsnprintf() to "rewind" the va_list after use. This assumption is
243 "sanity checked" from within SoDB::init(). */
244 length = (*func)(dst, n, fmtstr, args);
245 #endif /* !HAVE_VA_COPY_MACRO */
246
247 if (debug) { printf("==> length==%d\n", length); }
248
249 //POTENTIAL_ROTTING_DOCUMENTATION
250 /* Not all vsnprintf() implementations returns -1 upon failure (this
251 is what vsnprintf() from GNU libc is documented to do).
252
253 At least with GNU libc 2.1.1, vsnprintf() does _not_ return -1
254 (as documented in the snprintf(3) man-page) when we can't fit the
255 constructed string within the given buffer, but rather the number
256 of characters needed, excluding the terminating \0. The latter is
257 also the behavior specified by C99.
258
259 IRIX 6.5 vsnprintf() just returns the number of characters until
260 clipped, i.e. input argument n minus one.
261
262 For the C run-times that comes with MSVC++ 5.0 and MSVC++ 6.0,
263 _vsnprintf() is specified to return -1 on overruns. (To match
264 C99, one would expect Microsoft to change this, though. Perhaps
265 done for MSVC++ v7?)
266
267
268 For reference, here's a simple test example which checks the
269 behavior of snprintf() / vsnprintf(), when trying to fit 26
270 characters plus a terminating \0 into a 20-character buffer:
271
272 -----8<----------- [snip] ---------------8<----------- [snip] ---------
273 #include <cstdio>
274
275 int
276 main(void)
277 {
278 char buffer[20] = "";
279 const int ret =
280 snprintf(buffer, sizeof(buffer), "%s",
281 "abcdefghijklmnopqrstuvwxyz");
282 (void)printf("snprintf()==%d\n", ret);
283 (void)printf("buffer=\"%s\"\n", buffer);
284 return 0;
285 }
286 -----8<----------- [snip] ---------------8<----------- [snip] ---------
287 */
288
289 if (length >= (((int)n) - 1)) { length = -1; }
290
291 return length;
292 }
293
294 #ifdef HAVE_VSNPRINTF
295
296 int
coin_vsnprintf(char * dst,unsigned int n,const char * fmtstr,va_list args)297 coin_vsnprintf(char * dst, unsigned int n, const char * fmtstr, va_list args)
298 {
299 return coin_common_vsnprintf(vsnprintf, dst, (size_t)n, fmtstr, args);
300 }
301
302 #elif defined HAVE__VSNPRINTF
303
304 int
coin_vsnprintf(char * dst,unsigned int n,const char * fmtstr,va_list args)305 coin_vsnprintf(char * dst, unsigned int n, const char * fmtstr, va_list args)
306 {
307 return coin_common_vsnprintf(_vsnprintf, dst, (size_t)n, fmtstr, args);
308 }
309
310 #else /* neither vsnprintf() nor _vsnprintf() available, roll our own */
311
312 /*
313 This is a butt-ugly hack to emulate the vsnprintf() extension
314 available on some systems, without having to reimplement all the
315 code needed to parse printf-format strings.
316
317 vsnprintf() is necessary to use for copying a formatstring with a
318 variable number of arguments into a char buffer without the
319 possibility of overflows.
320
321 Note that there's one exception to the similarity in functionality
322 with "native" vsnprintf() implementations: the target buffer might
323 not contain _any_ characters from the formatstr upon a -1 return
324 value.
325
326 All external functions and macros in this code should be conforming
327 to ANSI C3.159-1989 / ISO 9899 or POSIX (or both), as far as I can
328 see.
329
330 Compile with something like this (example is under GCC and Linux),
331 to generate a stand-alone program testing the function:
332 gcc -Wall -DENABLE_TESTCODE=1 -DHAVE_UNISTD_H=1 -DHAVE_VSNPRINTF=1 \
333 -o snprintf snprintf.c
334
335 19991221 mortene. Thanks to larsa for the idea.
336
337 20040203 larsa: Finally solved a strange problem of having files
338 popping up in the root directory (on windows computers, and on the
339 current drive) with names like "s3n4" and "s25o" etc. with just a
340 few characters of text in them. It turned out to be this fallback
341 that created them, and I had forgotten to use the SIM_AC_CHECK_NPRINTF
342 macro in the configure script. The fallback is in other words not
343 entirely "safe", since it pollutes the filesystem on windows computers.
344 */
345
346 /*
347 FIXME: could perhaps grab a decent snprintf() implementation (with a
348 liberal enough license for our use) from one of the BSD-Unixen?
349 Investigate. 20010821 mortene.
350 */
351
352 /* First a helper function to find a valid file pointer which is
353 pointing at nothing (for a number of different definitions of
354 "nothing"..). */
355 static FILE *
nullfileptr(void)356 nullfileptr(void)
357 {
358 static FILE * nullfp = NULL;
359
360 if (!nullfp) {
361 struct stat sbuf;
362 const char unixdevnull[] = "/dev/null";
363 int nullfd = -1;
364
365 if ((stat(unixdevnull, &sbuf) == 0) && (sbuf.st_mode & S_IFCHR))
366 nullfd = open(unixdevnull, O_WRONLY);
367
368 if (nullfd == -1) {
369 const char * tmpname = tmpnam(NULL);
370
371 if (tmpname) {
372 nullfd = open(tmpname, O_CREAT|O_WRONLY);
373 (void)remove(tmpname);
374 }
375 }
376
377 if (nullfd != -1) nullfp = fdopen(nullfd, "w");
378 if (!nullfp) nullfp = stderr; /* :^} (as a last resort.) 19991221 mortene. */
379 }
380
381 return nullfp;
382 }
383
384 int
coin_vsnprintf(char * dst,unsigned int n,const char * fmtstr,va_list args)385 coin_vsnprintf(char * dst, unsigned int n, const char * fmtstr, va_list args)
386 {
387 int len;
388
389 #ifdef HAVE_VA_COPY_MACRO
390
391 /* The C99 va_copy() is available, so use that to help us "rewind"
392 the va_list between invocations. */
393 {
394 va_list argscopy;
395
396 va_copy(argscopy, args);
397 len = vfprintf(nullfileptr(), fmtstr, argscopy);
398 va_end(argscopy);
399
400 if (((unsigned int) len + 1) > n) return -1;
401
402 va_copy(argscopy, args);
403 (void)vsprintf(dst, fmtstr, argscopy);
404 va_end(argscopy);
405 }
406
407 #else /* !HAVE_VA_COPY_MACRO */
408
409 /* No va_copy() available, so we just assume the system's vfprintf()
410 to "rewind" the va_list after use. This assumption is "sanity
411 checked" from within SoDB::init(). */
412 len = vfprintf(nullfileptr(), fmtstr, args);
413 if (((unsigned int) len + 1) > n) return -1;
414 (void)vsprintf(dst, fmtstr, args);
415
416 #endif /* !HAVE_VA_COPY_MACRO */
417
418 return len;
419 }
420 #endif /* coin_vsnprintf() */
421
422
423 /**************************************************************************/
424 /*
425 coin_snprintf() wrapper. Returns -1 if resultant string will be
426 longer than n.
427 */
428
429 int
coin_snprintf(char * dst,unsigned int n,const char * fmtstr,...)430 coin_snprintf(char * dst, unsigned int n, const char * fmtstr, ...)
431 {
432 int len;
433 va_list argptr;
434 va_start(argptr, fmtstr);
435 len = coin_vsnprintf(dst, n, fmtstr, argptr);
436 va_end(argptr);
437 return len;
438 }
439
440
441 /**************************************************************************/
442
443 /*** Singlelinked list for the environment variables. *********************/
444
445 /*
446 FIXME: should implement a generic (macro-based) singlelinked list
447 abstraction in C (the following code could be a good starting
448 point). Then axe this code. Then move the various listhandling stuff
449 in the Coin library from the SbList<> template to the C-based one to
450 aid any future transition to pure C. 20010821 mortene.
451
452 UPDATE: SbList isn't really a linked list, but in fact a growable
453 array -- so the code below can not be used as a replacement. Still,
454 we should have a generic linked list class. 20011220 mortene.
455 */
456
457 #ifdef HAVE_GETENVIRONMENTVARIABLE
458 static struct envvar_data * envlist_head = NULL;
459 static struct envvar_data * envlist_tail = NULL;
460
461 struct envvar_data {
462 char * name;
463 char * val;
464 struct envvar_data * next;
465 };
466
467 static void
envlist_cleanup(void)468 envlist_cleanup(void)
469 {
470 struct envvar_data * ptr = envlist_head;
471 while (ptr != NULL) {
472 struct envvar_data * tmp = ptr;
473 free(ptr->name);
474 free(ptr->val);
475 ptr = ptr->next;
476 free(tmp);
477 }
478 envlist_head = NULL;
479 envlist_tail = NULL;
480 }
481
482 static void
envlist_append(struct envvar_data * item)483 envlist_append(struct envvar_data * item)
484 {
485 item->next = NULL;
486 if (envlist_head == NULL) {
487 envlist_head = item;
488 envlist_tail = item;
489 coin_atexit_func("envlist_cleanup", envlist_cleanup, CC_ATEXIT_ENVIRONMENT);
490 }
491 else {
492 envlist_tail->next = item;
493 envlist_tail = item;
494 }
495 }
496
497 #endif /* HAVE_GETENVIRONMENTVARIABLE */
498
499
500 /**************************************************************************/
501
502 /* FIXME: should getenv/setenv/unsetenv be made mt-safe by locking access
503 * to the envlist linked list under Win32? 20030205 larsa */
504
505 /*
506 When working with MSWindows applications using Coin as a DLL,
507 setenv() / getenv() will not work as expected, as the application
508 and the DLL has different instances of the C library with different
509 datastructures on different heaps. That's why we need this
510 abstraction around the C-libs getenv() vs the Win32 API
511 GetEnvironmentVariable() function.
512
513 Note: do not deallocate the returned string -- they are supposed to
514 be permanently available to all callers. Deallocating the resources
515 is the responsibility of the application exit cleanup code (i.e. the
516 internal library cleanup code -- application programmers won't need
517 to care about it).
518 */
519 const char *
coin_getenv(const char * envname)520 coin_getenv(const char * envname)
521 {
522 /* FIXME: with recent version(s) of Cygwin, it seems the Win32
523 GetEnvironmentVariable() is no longer working properly, if Coin
524 has been built with the Cygwin-port of GCC. We've had one bug
525 report to this effect, plus handegar had to fix wrapmsvc.cpp,
526 which exhibited the exact same problem.
527
528 Not 100% sure how to fix it, but perhaps always preferring to use
529 getenv() over GetEnvironmentVariable() would be sufficient? Or
530 would that just exhibit the opposite problem when building Coin
531 with MSVC?
532
533 20060314 mortene. */
534
535 /* Important note: this code is identical to the getenv() code in
536 So@Gui@/.../common/SoAny.cpp.in. If you do bugfixes or whatever,
537 keep them in sync! */
538 /* FIXME: this code from tidbits should be moved under
539 Coin/src/share/, so the actual source code is shared instead of
540 having to copy it around. 20060314 mortene. */
541 #ifdef HAVE_GETENVIRONMENTVARIABLE
542 int neededsize;
543 neededsize = GetEnvironmentVariable(envname, NULL, 0);
544 /* neededsize includes the \0-terminating character */
545 if (neededsize >= 1) {
546 int resultsize;
547 struct envvar_data * envptr;
548 char * valbuf = (char *) malloc(neededsize);
549 if (valbuf == NULL) {
550 /* Augh. Could we handle this any better? */
551 /* If we already bookkeep a buffer for this variable, we /could/ try
552 to reuse it (much work for a non-100% solution). 20030205 larsa */
553 return NULL;
554 }
555 resultsize = GetEnvironmentVariable(envname, valbuf, neededsize);
556 if (resultsize != (neededsize - 1)) {
557 /* Augh. Could we handle this any better? */
558 /* How about looping to top and trying again (in case the reason is mt
559 and envval being changed in the background, or maybe just asserting?
560 20030205 larsa */
561 free(valbuf);
562 return NULL;
563 }
564
565 /*
566 The GetEnvironmentVariable() signature forces us to allocate the space
567 for the value string on the outside of the call, as opposed to the UNIX
568 getenv() function. We therefore have to do bookkeeping and maintain
569 this linked list of allocated buffers that should be cleaned up on exit
570 (atexit()). We don't keep it for lookup of values - we actually can't
571 use the valus as value caches in case they have been changed from other
572 parts of the application. We only keep them so we can free them later.
573 */
574
575 /* Try to find bookkeeped envvar buffer among those registered earlier. */
576 envptr = envlist_head;
577 while ((envptr != NULL) && (strcmp(envptr->name, envname) != 0))
578 envptr = envptr->next;
579
580 /* We can avoid this if-else by always freeing the envvar_data for the
581 variable upfront, but it's a tad less efficient. */
582 if (envptr != NULL) {
583 /* We are already bookkeeping a buffer for this variable.
584 * => free previous value buffer and bookkeep the new one instead */
585 free(envptr->val);
586 envptr->val = valbuf;
587 }
588 else {
589 /* We aren't bookkeeping a buffer for this one yet. */
590 envptr = (struct envvar_data *) malloc(sizeof(struct envvar_data));
591 if (envptr == NULL) {
592 /* Augh. Could we handle this any better? */
593 /* We can alternatively ignore the bookkeeping and leak the buffer
594 - 20030205 larsa */
595 free(valbuf);
596 return NULL;
597 }
598 envptr->name = strdup(envname);
599 if (envptr->name == NULL) {
600 /* Augh. Could we handle this any better? */
601 /* We can alternatively ignore the bookkeeping and leak the buffer
602 - 20030205 larsa */
603 free(envptr);
604 free(valbuf);
605 return NULL;
606 }
607 envptr->val = valbuf;
608 envlist_append(envptr);
609 }
610 return envptr->val;
611 }
612 return NULL;
613 #else /* !HAVE_GETENVIRONMENTVARIABLE */
614 return getenv(envname);
615 #endif /* !HAVE_GETENVIRONMENTVARIABLE */
616 }
617
618 SbBool
coin_setenv(const char * name,const char * value,int overwrite)619 coin_setenv(const char * name, const char * value, int overwrite)
620 {
621 #ifdef HAVE_GETENVIRONMENTVARIABLE
622 /*
623 The value is changed by the application, so we no longer need to
624 guarantee old buffers' existence to the outside world. We therefore
625 free buffers we are bookkeeping here. This code can be disabled
626 without any consequence though.
627 */
628 struct envvar_data * envptr, * prevptr;
629 envptr = envlist_head;
630 prevptr = NULL;
631 while ((envptr != NULL) && (strcmp(envptr->name, name) != 0)) {
632 prevptr = envptr;
633 envptr = envptr->next;
634 }
635 if (envptr) {
636 /* unlink node */
637 if (prevptr) prevptr->next = envptr->next;
638 else envlist_head = envptr->next;
639 if (envlist_tail == envptr) envlist_tail = prevptr;
640 /* free node */
641 free(envptr->name);
642 free(envptr->val);
643 free(envptr);
644 }
645
646 /* FIXME: This is from Win32s 1.3 Bug List - how should we handle it?
647 and what's with the typo in the function name? 20030205 larsa
648 ====================================================================
649 SetEnvironmentVariables() does not handle an empty string, an equal
650 sign (=), or foreign lowercase characters in the variable name.
651 */
652
653 if (overwrite || (GetEnvironmentVariable(name, NULL, 0) == 0))
654 return SetEnvironmentVariable(name, value) ? TRUE : FALSE;
655 else
656 return TRUE;
657 #else /* !HAVE_GETENVIRONMENTVARIABLE */
658 return (setenv(name,value,overwrite) == 0);
659 #endif /* !HAVE_GETENVIRONMENTVARIABLE */
660 }
661
662 void
coin_unsetenv(const char * name)663 coin_unsetenv(const char * name)
664 {
665 #ifdef HAVE_GETENVIRONMENTVARIABLE
666 /*
667 The value is removed by the application, so we no longer need to
668 guarantee old buffers' existence to the outside world. We therefore
669 free buffers we are bookkeeping here. This code can be disabled
670 without any consequence though.
671 */
672 struct envvar_data * envptr, * prevptr;
673 envptr = envlist_head;
674 prevptr = NULL;
675 while ((envptr != NULL) && (strcmp(envptr->name, name) != 0)) {
676 prevptr = envptr;
677 envptr = envptr->next;
678 }
679 if (envptr) {
680 /* unlink node */
681 if (prevptr) prevptr->next = envptr->next;
682 else envlist_head = envptr->next;
683 if (envlist_tail == envptr) envlist_tail = prevptr;
684 /* free node */
685 free(envptr->name);
686 free(envptr->val);
687 free(envptr);
688 }
689 SetEnvironmentVariable(name, NULL);
690 #else /* !HAVE_GETENVIRONMENTVARIABLE */
691 unsetenv(name);
692 #endif /* !HAVE_GETENVIRONMENTVARIABLE */
693 }
694
695 /**************************************************************************/
696
697 /*
698 strncasecmp() is not available on all platforms (it's neither ISO C
699 nor POSIX). At least MSVC doesn't have it.
700 */
701 int
coin_strncasecmp(const char * s1,const char * s2,int len)702 coin_strncasecmp(const char * s1, const char * s2, int len)
703 {
704 #ifdef HAVE_STRNCASECMP
705
706 return strncasecmp(s1, s2, len);
707
708 #else /* !HAVE_STRNCASECMP */
709
710 assert(s1 && s2);
711 while (len > 0) {
712 int c1 = tolower(*s1);
713 int c2 = tolower(*s2);
714 if (c1 < c2) { return -1; }
715 if (c1 > c2) { return +1; }
716 if (c1=='\0' && c2=='\0') { return 0; } /* in case len is too large */
717 len--; s1++; s2++;
718 }
719 return 0;
720
721 #endif /* !HAVE_STRNCASECMP */
722 }
723
724 /**************************************************************************/
725
726 #define COIN_BSWAP_8(x) ((x) & 0xff)
727 #define COIN_BSWAP_16(x) ((COIN_BSWAP_8(x) << 8) | COIN_BSWAP_8((x) >> 8))
728 #define COIN_BSWAP_32(x) ((COIN_BSWAP_16(x) << 16) | COIN_BSWAP_16((x) >> 16))
729 #define COIN_BSWAP_64(x) ((COIN_BSWAP_32(x) << 32) | COIN_BSWAP_32((x) >> 32))
730
731 static int coin_endianness = COIN_HOST_IS_UNKNOWNENDIAN;
732
733 int
coin_host_get_endianness(void)734 coin_host_get_endianness(void)
735 {
736 union temptype {
737 uint32_t value;
738 uint8_t bytes[4];
739 } temp;
740
741 if (coin_endianness != COIN_HOST_IS_UNKNOWNENDIAN) {
742 return coin_endianness;
743 }
744
745 temp.bytes[0] = 0x00;
746 temp.bytes[1] = 0x01;
747 temp.bytes[2] = 0x02;
748 temp.bytes[3] = 0x03;
749 switch (temp.value) {
750 case 0x03020100: return coin_endianness = COIN_HOST_IS_LITTLEENDIAN;
751 case 0x00010203: return coin_endianness = COIN_HOST_IS_BIGENDIAN;
752 /* might be more variations here for some obscure CPU architectures */
753 }
754 assert(0 && "system has unknown endianness");
755 return COIN_HOST_IS_UNKNOWNENDIAN; /* maybe just as well exit()? */
756 }
757
758 uint16_t
coin_hton_uint16(uint16_t value)759 coin_hton_uint16(uint16_t value)
760 {
761 switch (coin_host_get_endianness()) {
762 case COIN_HOST_IS_BIGENDIAN:
763 /* value = value */
764 break;
765 case COIN_HOST_IS_LITTLEENDIAN:
766 value = COIN_BSWAP_16(value);
767 break;
768 default:
769 assert(0 && "system has unknown endianness");
770 }
771 return value;
772 }
773
774 uint16_t
coin_ntoh_uint16(uint16_t value)775 coin_ntoh_uint16(uint16_t value)
776 {
777 return coin_hton_uint16(value);
778 }
779
780 uint32_t
coin_hton_uint32(uint32_t value)781 coin_hton_uint32(uint32_t value)
782 {
783 switch (coin_host_get_endianness()) {
784 case COIN_HOST_IS_BIGENDIAN:
785 /* big-endian is the same order as network order */
786 break;
787 case COIN_HOST_IS_LITTLEENDIAN:
788 value = COIN_BSWAP_32(value);
789 break;
790 default:
791 assert(0 && "system has unknown endianness");
792 }
793 return value;
794 }
795
796 uint32_t
coin_ntoh_uint32(uint32_t value)797 coin_ntoh_uint32(uint32_t value)
798 {
799 return coin_hton_uint32(value);
800 }
801
802 uint64_t
coin_hton_uint64(uint64_t value)803 coin_hton_uint64(uint64_t value)
804 {
805 switch (coin_host_get_endianness()) {
806 case COIN_HOST_IS_BIGENDIAN:
807 /* big-endian is the same order as network order */
808 break;
809 case COIN_HOST_IS_LITTLEENDIAN:
810 value = COIN_BSWAP_64(value);
811 break;
812 default:
813 assert(0 && "system has unknown endianness");
814 }
815 return value;
816 }
817
818 uint64_t
coin_ntoh_uint64(uint64_t value)819 coin_ntoh_uint64(uint64_t value)
820 {
821 return coin_hton_uint64(value);
822 }
823
824 void
coin_hton_float_bytes(float value,char * result)825 coin_hton_float_bytes(float value, char * result)
826 {
827 union {
828 float f32;
829 uint32_t u32;
830 } val;
831
832 assert(sizeof(float) == sizeof(uint32_t));
833 val.f32 = value;
834 val.u32 = coin_hton_uint32(val.u32);
835 memcpy(result, &val.u32, sizeof(uint32_t));
836 }
837
838 float
coin_ntoh_float_bytes(const char * value)839 coin_ntoh_float_bytes(const char * value)
840 {
841 union {
842 float f32;
843 uint32_t u32;
844 } val;
845
846 assert(sizeof(float) == sizeof(uint32_t));
847 memcpy(&val.u32, value, sizeof(uint32_t));
848 val.u32 = coin_ntoh_uint32(val.u32);
849 return val.f32;
850 }
851
852 void
coin_hton_double_bytes(double value,char * result)853 coin_hton_double_bytes(double value, char * result)
854 {
855 union {
856 double d64;
857 uint64_t u64;
858 } val;
859
860 assert(sizeof(double) == sizeof(uint64_t));
861 val.d64 = value;
862 val.u64 = coin_hton_uint64(val.u64);
863 memcpy(result, &val.u64, sizeof(uint64_t));
864 }
865
866 double
coin_ntoh_double_bytes(const char * value)867 coin_ntoh_double_bytes(const char * value)
868 {
869 union {
870 double d64;
871 uint64_t u64;
872 } val;
873
874 assert(sizeof(double) == sizeof(uint64_t));
875 memcpy(&val.u64, value, sizeof(uint64_t));
876 val.u64 = coin_ntoh_uint64(val.u64);
877 return val.d64;
878 }
879
880 /**************************************************************************/
881
882 /*
883 isascii() is neither ANSI C nor POSIX, but a BSD extension and SVID
884 extension.
885 */
886 SbBool
coin_isascii(const int c)887 coin_isascii(const int c)
888 {
889 return (c >= 0x00) && (c < 0x80);
890 }
891
892 /* We provide our own version of the isspace() method, as we don't
893 really want it to be locale-dependent (which is known to have
894 caused trouble for us with some specific German characters under
895 MSWindows, at least). */
896 SbBool
coin_isspace(const char c)897 coin_isspace(const char c)
898 {
899 /* This is what isspace() does under the POSIX and C locales,
900 according to the GNU libc man page. */
901 return (c==' ') || (c=='\n') || (c=='\t') ||
902 (c=='\r') || (c=='\f') || (c=='\v');
903 }
904
905 /**************************************************************************/
906
907 /* Quick check to see if an integer value is equal to 2^n, for any
908 n=[0, ...]. */
909 SbBool
coin_is_power_of_two(uint32_t x)910 coin_is_power_of_two(uint32_t x)
911 {
912 return (x != 0) && ((x & (x - 1)) == 0);
913 }
914
915 /*
916 Returns nearest upward number for x that is a power of two.
917
918 Note that if "x" is already a power of two, we will still return the
919 *next* number that is a power of two, and not x itself.
920 */
921 uint32_t
coin_next_power_of_two(uint32_t x)922 coin_next_power_of_two(uint32_t x)
923 {
924 assert((x < (uint32_t)(1 << 31)) && "overflow");
925
926 x |= (x >> 1);
927 x |= (x >> 2);
928 x |= (x >> 4);
929 x |= (x >> 8);
930 x |= (x >> 16);
931 /* This will make it work with 64-bit numbers: */
932 /* x |= (x >> 32); */
933
934 return x + 1;
935 }
936
937 /*
938 Returns nearest upward number for x that is a power of two, or x
939 itself if it is already a power of two.
940
941 ("geq" is short for "Greater or EQual".)
942 */
943 uint32_t
coin_geq_power_of_two(uint32_t x)944 coin_geq_power_of_two(uint32_t x)
945 {
946 if (coin_is_power_of_two(x)) return x;
947 return coin_next_power_of_two(x);
948 }
949
950 /*
951 Calculate the view volume jitter vector when doing multipass
952 antialiasing rendering.
953 */
954 void
coin_viewvolume_jitter(int numpasses,int curpass,const int * vpsize,float * jitter)955 coin_viewvolume_jitter(int numpasses, int curpass, const int * vpsize, float * jitter)
956 {
957 /* jitter values from OpenGL Programming Guide */
958 static float jitter2[] = {
959 0.25f, 0.77f,
960 0.75f, 0.25f
961 };
962 static float jitter3[] = {
963 0.5033922635f, 0.8317967229f,
964 0.7806016275f, 0.2504380877f,
965 0.2261828938f, 0.4131553612f
966 };
967 static float jitter4[] = {
968 0.375f, 0.25f,
969 0.125f, 0.75f,
970 0.875f, 0.25f,
971 0.625f, 0.75f
972 };
973 static float jitter5[] = {
974 0.5f, 0.5f,
975 0.3f, 0.1f,
976 0.7f, 0.9f,
977 0.9f, 0.3f,
978 0.1f, 0.7f
979 };
980 static float jitter6[] = {
981 0.4646464646f, 0.4646464646f,
982 0.1313131313f, 0.7979797979f,
983 0.5353535353f, 0.8686868686f,
984 0.8686868686f, 0.5353535353f,
985 0.7979797979f, 0.1313131313f,
986 0.2020202020f, 0.2020202020f
987 };
988 static float jitter8[] = {
989 0.5625f, 0.4375f,
990 0.0625f, 0.9375f,
991 0.3125f, 0.6875f,
992 0.6875f, 0.8125f,
993 0.8125f, 0.1875f,
994 0.9375f, 0.5625f,
995 0.4375f, 0.0625f,
996 0.1875f, 0.3125f
997 };
998 static float jitter9[] = {
999 0.5f, 0.5f,
1000 0.1666666666f, 0.9444444444f,
1001 0.5f, 0.1666666666f,
1002 0.5f, 0.8333333333f,
1003 0.1666666666f, 0.2777777777f,
1004 0.8333333333f, 0.3888888888f,
1005 0.1666666666f, 0.6111111111f,
1006 0.8333333333f, 0.7222222222f,
1007 0.8333333333f, 0.0555555555f
1008 };
1009 static float jitter12[] = {
1010 0.4166666666f, 0.625f,
1011 0.9166666666f, 0.875f,
1012 0.25f, 0.375f,
1013 0.4166666666f, 0.125f,
1014 0.75f, 0.125f,
1015 0.0833333333f, 0.125f,
1016 0.75f, 0.625f,
1017 0.25f, 0.875f,
1018 0.5833333333f, 0.375f,
1019 0.9166666666f, 0.375f,
1020 0.0833333333f, 0.625f,
1021 0.583333333f, 0.875f
1022 };
1023 static float jitter16[] = {
1024 0.375f, 0.4375f,
1025 0.625f, 0.0625f,
1026 0.875f, 0.1875f,
1027 0.125f, 0.0625f,
1028 0.375f, 0.6875f,
1029 0.875f, 0.4375f,
1030 0.625f, 0.5625f,
1031 0.375f, 0.9375f,
1032 0.625f, 0.3125f,
1033 0.125f, 0.5625f,
1034 0.125f, 0.8125f,
1035 0.375f, 0.1875f,
1036 0.875f, 0.9375f,
1037 0.875f, 0.6875f,
1038 0.125f, 0.3125f,
1039 0.625f, 0.8125f
1040 };
1041
1042 static float * jittertab[] = {
1043 jitter2,
1044 jitter3,
1045 jitter4,
1046 jitter5,
1047 jitter6,
1048 jitter8,
1049 jitter8,
1050 jitter9,
1051 jitter12,
1052 jitter12,
1053 jitter12,
1054 jitter16,
1055 jitter16,
1056 jitter16,
1057 jitter16
1058 };
1059
1060 float * jittab;
1061
1062 /* FIXME: support more rendering passes by generating jitter tables
1063 * using some clever algorithm. pederb, 2001-02-21 */
1064 if (numpasses > 16) numpasses = 16;
1065 if (curpass >= numpasses) curpass = numpasses - 1;
1066
1067 jittab = jittertab[numpasses-2];
1068
1069 if (numpasses < 2) {
1070 jitter[0] = 0.0f;
1071 jitter[1] = 0.0f;
1072 jitter[2] = 0.0f;
1073 }
1074 else {
1075 jitter[0] = (jittab[curpass*2] - 0.5f) * 2.0f / ((float)vpsize[0]);
1076 jitter[1] = (jittab[curpass*2+1] - 0.5f) * 2.0f / ((float)vpsize[1]);
1077 jitter[2] = 0.0f;
1078 }
1079 }
1080
1081
1082 /**************************************************************************/
1083
1084 void free_std_fds(void);
1085
1086 typedef void(*atexit_func_type)(void);
1087
1088 static cc_list * atexit_list = NULL;
1089 static SbBool isexiting = FALSE;
1090
1091 typedef struct {
1092 char * name;
1093 coin_atexit_f * func;
1094 int32_t priority;
1095 uint32_t cnt;
1096 } tb_atexit_data;
1097
1098 static int
atexit_qsort_cb(const void * q0,const void * q1)1099 atexit_qsort_cb(const void * q0, const void * q1)
1100 {
1101 tb_atexit_data * p0, * p1;
1102
1103 p0 = *((tb_atexit_data**) q0);
1104 p1 = *((tb_atexit_data**) q1);
1105
1106 /* sort list on ascending priorities, so that high priority
1107 callbacks are called first */
1108 if (p0->priority < p1->priority) return -1;
1109 if (p0->priority > p1->priority) return 1;
1110
1111 /* when priority is equal, use LIFO */
1112 if (p0->cnt < p1->cnt) return -1;
1113 return 1;
1114 }
1115
1116 /*
1117 Calls all atexit functions. Invoked from SoDB::finish().
1118 */
1119 void
coin_atexit_cleanup(void)1120 coin_atexit_cleanup(void)
1121 {
1122 int i, n;
1123 tb_atexit_data * data;
1124 const char * debugstr;
1125 SbBool debug = FALSE;
1126
1127 if (!atexit_list) return;
1128
1129 isexiting = TRUE;
1130
1131 /* delete mutex here to make sure this is done before the threading subsystem is shut down */
1132 #ifdef COIN_THREADSAFE
1133 cc_mutex_destruct(atexit_list_monitor);
1134 atexit_list_monitor = NULL;
1135 #endif /* COIN_THREADSAFE */
1136
1137 debugstr = coin_getenv("COIN_DEBUG_CLEANUP");
1138 debug = debugstr && (atoi(debugstr) > 0);
1139
1140 n = cc_list_get_length(atexit_list);
1141 qsort(cc_list_get_array(atexit_list), n, sizeof(void*), atexit_qsort_cb);
1142
1143 for (i = n-1; i >= 0; i--) {
1144 data = (tb_atexit_data*) cc_list_get(atexit_list, i);
1145 if (debug) {
1146 /* Can't use cc_debugerror_postinfo() here, since this will
1147 allocate static data that need to be cleaned up, resulting
1148 in a call to coin_atexit() while we are already exiting...
1149 */
1150 fprintf(stdout, "coin_atexit_cleanup: invoking %s()\n", data->name);
1151 }
1152 data->func();
1153 free(data->name);
1154 free((void*)data);
1155 }
1156
1157 /* Close stdin/stdout/stderr if any of them have been opened */
1158 free_std_fds();
1159
1160 cc_list_destruct(atexit_list);
1161 atexit_list = NULL;
1162 isexiting = FALSE;
1163
1164 if (debug) {
1165 fprintf(stdout, "coin_atexit_cleanup: fini\n");
1166 }
1167 }
1168
1169 /*
1170 This replacement for the C library's atexit() function is used for
1171 two reasons: first, we want to control the internal order of when
1172 clean-up callbacks are invoked (as can be done by setting the
1173 priority argument accordingly), second, we want to be able to do a
1174 controlled clean-up in advance of the C library's shutdown, to make
1175 sure that we get cleaned up before any DLLs we are using are thrown
1176 out of the process.
1177
1178 Callbacks with higher priority will be called first. On equal
1179 priority callbacks will be made last-in-first-out ("LIFO").
1180
1181 For this function a higher number is a higher priority. An atexit
1182 function with priority 2 will trigger before an atexit function with
1183 priority 1.
1184
1185 Functions passed to this method should be cast to the apropriate
1186 method signature (coin_atexit_f), so the OSF1/cxx compiler can
1187 accept a C++ function as it's input argument. (Problem reported by
1188 Guy Barrand.)
1189 */
1190
1191 void
coin_atexit_func(const char * name,coin_atexit_f * f,coin_atexit_priorities priority)1192 coin_atexit_func(const char * name, coin_atexit_f * f, coin_atexit_priorities priority)
1193 {
1194 #ifdef COIN_THREADSAFE
1195 /* This function being not mt-safe seemed to be the only cause of
1196 problems when constructing SoNode-derived classes in parallel
1197 threads. So for that extra bit of undocumented, unofficial,
1198 under-the-table mt-safety, this should take care of it. */
1199
1200 /*
1201 Need this test, since the thread system calls coin_atexit
1202 before tidbits is initialized.
1203 */
1204 if (atexit_list_monitor) {
1205 cc_mutex_lock(atexit_list_monitor);
1206 }
1207 #endif /* COIN_THREADSAFE */
1208
1209 assert(!isexiting && "tried to attach an atexit function while exiting");
1210
1211 if (atexit_list == NULL) {
1212 atexit_list = cc_list_construct();
1213 /* The atexit() registration was disabled, since it has proved
1214 dangerous to let the C library trigger the callbacks.
1215
1216 There is for instance the known problem with deallocating
1217 resources from a DLL we're using (like OpenAL), as the DLL
1218 could already have been "offloaded" or simply cleaned up /
1219 cleaned out when our callback triggers.
1220
1221 We therefore now force cleanup at exit to be done explicitly
1222 from application code by invoking the SoDB::finish() method,
1223 which then invokes the coin_atexit_cleanup() method.
1224
1225 Note that this scheme is not to be considered a temporary
1226 workaround -- application-exit clean-up should be done
1227 explicitly by invoking SoDB::finish().
1228
1229 mortene.
1230 */
1231 /* (void)atexit(coin_atexit_cleanup); */
1232 }
1233
1234 {
1235 tb_atexit_data * data;
1236
1237 data = (tb_atexit_data*) malloc(sizeof(tb_atexit_data));
1238 data->name = strdup(name);
1239 data->func = f;
1240 data->priority = priority;
1241 data->cnt = cc_list_get_length(atexit_list);
1242
1243 cc_list_append(atexit_list, data);
1244 }
1245
1246 #ifdef COIN_THREADSAFE
1247 if (atexit_list_monitor) {
1248 cc_mutex_unlock(atexit_list_monitor);
1249 }
1250 #endif /* COIN_THREADSAFE */
1251 }
1252
1253 /*
1254 Public version of the coin_atexit function which always sets the
1255 priority such that external clean-up functions are run \e first.
1256
1257 (Which is of course important because they may have dependencies
1258 into Coin functionality.)
1259
1260 Note that the registered atexit functions will only be called when
1261 SoDB::finish() is invoked from the application code.
1262 */
1263 void
cc_coin_atexit(coin_atexit_f * f)1264 cc_coin_atexit(coin_atexit_f * f)
1265 {
1266 coin_atexit(f, CC_ATEXIT_EXTERNAL);
1267 }
1268
1269 /*!
1270 Internal function used for cleaning up static data. Do not use
1271 from appliction code.
1272 */
1273 void
cc_coin_atexit_static_internal(coin_atexit_f * fp)1274 cc_coin_atexit_static_internal(coin_atexit_f * fp)
1275 {
1276 coin_atexit(fp, CC_ATEXIT_STATIC_DATA);
1277 }
1278
1279 /*
1280 Returns \c TRUE if we are currently iterating over the functions
1281 registered with coin_atexit(), otherwise \c FALSE.
1282 */
1283 SbBool
coin_is_exiting(void)1284 coin_is_exiting(void)
1285 {
1286 return isexiting;
1287 }
1288
1289 /**************************************************************************/
1290
1291 /*
1292 It is not possible to "pass" C library data from the application
1293 to a MSWin .DLL, so this is necessary to get hold of the stderr
1294 FILE*. Just using fprintf(stderr, ...) or fprintf(stdout, ...)
1295 directly will result in a crash when Coin has been compiled as a
1296 .DLL.
1297 */
1298
1299 /* These constants are fixed according to POSIX */
1300 #ifndef STDIN_FILENO
1301 #define STDIN_FILENO 0
1302 #endif
1303 #ifndef STDOUT_FILENO
1304 #define STDOUT_FILENO 1
1305 #endif
1306 #ifndef STDERR_FILENO
1307 #define STDERR_FILENO 2
1308 #endif
1309
1310 /*
1311 FIXME: if Coin does an fclose() on one of these, what happens when the
1312 cached variable is used later on? We should make sure Coin doesn't
1313 fclose() one of these... Or we should open a new FILE pointer each time
1314 it is called? Would it be safe to check if the FILE * is closed and
1315 then open a new one? 20030217 larsa
1316 */
1317
1318 static FILE * coin_stdin = NULL;
1319 static FILE * coin_stdout = NULL;
1320 static FILE * coin_stderr = NULL;
1321 static int coin_dup_stdin = -1;
1322 static int coin_dup_stdout = -1;
1323 static int coin_dup_stderr = -1;
1324
1325 void
free_std_fds(void)1326 free_std_fds(void)
1327 {
1328 /* Close stdin/stdout/stderr */
1329 if (coin_stdin) {
1330 assert(coin_dup_stdin != -1);
1331 fclose(coin_stdin);
1332 coin_stdin = NULL;
1333 dup2(coin_dup_stdin, STDIN_FILENO);
1334 close(coin_dup_stdin);
1335 coin_dup_stdin = -1;
1336 }
1337 if (coin_stdout) {
1338 assert(coin_dup_stdout != -1);
1339 fclose(coin_stdout);
1340 coin_stdout = NULL;
1341 dup2(coin_dup_stdout, STDOUT_FILENO);
1342 close(coin_dup_stdout);
1343 coin_dup_stdout = -1;
1344 }
1345 if (coin_stderr) {
1346 assert(coin_dup_stderr != -1);
1347 fclose(coin_stderr);
1348 coin_stderr = NULL;
1349 dup2(coin_dup_stderr, STDERR_FILENO);
1350 close(coin_dup_stderr);
1351 coin_dup_stderr = -1;
1352 }
1353 }
1354
1355 FILE *
coin_get_stdin(void)1356 coin_get_stdin(void)
1357 {
1358 if ( ! coin_stdin ){
1359 coin_dup_stdin = dup(STDIN_FILENO);
1360 coin_stdin = fdopen(STDIN_FILENO, "r");
1361 }
1362 return coin_stdin;
1363 }
1364
1365 FILE *
coin_get_stdout(void)1366 coin_get_stdout(void)
1367 {
1368 if ( ! coin_stdout ){
1369 coin_dup_stdout = dup(STDOUT_FILENO);
1370 coin_stdout = fdopen(STDOUT_FILENO, "w");
1371 }
1372 return coin_stdout;
1373 }
1374
1375 FILE *
coin_get_stderr(void)1376 coin_get_stderr(void)
1377 {
1378 if ( ! coin_stderr ){
1379 coin_dup_stderr = dup(STDERR_FILENO);
1380 coin_stderr = fdopen(STDERR_FILENO, "w");
1381 }
1382 return coin_stderr;
1383 }
1384
1385 /**************************************************************************/
1386
1387 SbBool
coin_locale_set_portable(cc_string * storeold)1388 coin_locale_set_portable(cc_string * storeold)
1389 {
1390 const char * loc;
1391
1392 const char * deflocale = setlocale(LC_NUMERIC, NULL);
1393 if (strcmp(deflocale, "C") == 0) { return FALSE; }
1394
1395 /* Must copy deflocale string, as it will be changed on the next
1396 invocation of setlocale(). */
1397 cc_string_construct(storeold);
1398 cc_string_set_text(storeold, deflocale);
1399
1400 loc = setlocale(LC_NUMERIC, "C");
1401 assert(loc != NULL && "could not set locale to supposed portable C locale");
1402 return TRUE;
1403 }
1404
1405 void
coin_locale_reset(cc_string * storedold)1406 coin_locale_reset(cc_string * storedold)
1407 {
1408 const char * l = setlocale(LC_NUMERIC, cc_string_get_text(storedold));
1409 assert(l != NULL && "could not reset locale");
1410 cc_string_clean(storedold);
1411 }
1412
1413 double
coin_atof(const char * ptr)1414 coin_atof(const char * ptr)
1415 {
1416 /* Avoid trying to read decimal point as ",", and reading with
1417 thousands separator, as defined for some locales, influencing the
1418 atof() call. */
1419
1420 double v;
1421 cc_string storedlocale;
1422 SbBool changed = coin_locale_set_portable(&storedlocale);
1423 v = atof(ptr);
1424 if (changed) { coin_locale_reset(&storedlocale); }
1425 return v;
1426 }
1427
1428 /**************************************************************************/
1429
1430 /* helper function for ascii85 handling */
1431 static int
coin_encode_ascii85(const unsigned char * in,unsigned char * out)1432 coin_encode_ascii85(const unsigned char * in, unsigned char * out)
1433 {
1434 uint32_t data =
1435 ((uint32_t)(in[0])<<24) |
1436 ((uint32_t)(in[1])<<16) |
1437 ((uint32_t)(in[2])<< 8) |
1438 ((uint32_t)(in[3]));
1439
1440 if (data == 0) {
1441 out[0] = 'z';
1442 return 1;
1443 }
1444 out[4] = (unsigned char) (data%85 + '!');
1445 data /= 85;
1446 out[3] = (unsigned char) (data%85 + '!');
1447 data /= 85;
1448 out[2] = (unsigned char) (data%85 + '!');
1449 data /= 85;
1450 out[1] = (unsigned char) (data%85 + '!');
1451 data /= 85;
1452 out[0] = (unsigned char) (data%85 + '!');
1453 return 5;
1454 }
1455
1456 void
coin_output_ascii85(FILE * fp,const unsigned char val,unsigned char * tuple,unsigned char * linebuf,int * tuplecnt,int * linecnt,const int rowlen,const SbBool flush)1457 coin_output_ascii85(FILE * fp,
1458 const unsigned char val,
1459 unsigned char * tuple,
1460 unsigned char * linebuf,
1461 int * tuplecnt, int * linecnt,
1462 const int rowlen,
1463 const SbBool flush)
1464 {
1465 int i;
1466 if (flush) {
1467 /* fill up tuple */
1468 for (i = *tuplecnt; i < 4; i++) tuple[i] = 0;
1469 }
1470 else {
1471 tuple[(*tuplecnt)++] = val;
1472 }
1473 if (flush || *tuplecnt == 4) {
1474 if (*tuplecnt) {
1475 int add = coin_encode_ascii85(tuple, linebuf + *linecnt);
1476 if (flush) {
1477 if (add == 1) {
1478 for (i = 0; i < 5; i++) linebuf[*linecnt + i] = '!';
1479 }
1480 *linecnt += *tuplecnt + 1;
1481 }
1482 else *linecnt += add;
1483 *tuplecnt = 0;
1484 }
1485 if (*linecnt >= rowlen) {
1486 unsigned char store = linebuf[rowlen];
1487 linebuf[rowlen] = 0;
1488 fprintf(fp, "%s\n", linebuf);
1489 linebuf[rowlen] = store;
1490 for (i = rowlen; i < *linecnt; i++) {
1491 linebuf[i-rowlen] = linebuf[i];
1492 }
1493 *linecnt -= rowlen;
1494 }
1495 if (flush && *linecnt) {
1496 linebuf[*linecnt] = 0;
1497 fprintf(fp, "%s\n", linebuf);
1498 }
1499 }
1500 }
1501
1502 void
coin_flush_ascii85(FILE * fp,unsigned char * tuple,unsigned char * linebuf,int * tuplecnt,int * linecnt,const int rowlen)1503 coin_flush_ascii85(FILE * fp,
1504 unsigned char * tuple,
1505 unsigned char * linebuf,
1506 int * tuplecnt, int * linecnt,
1507 const int rowlen)
1508 {
1509 coin_output_ascii85(fp, 0, tuple, linebuf, tuplecnt, linecnt, rowlen, TRUE);
1510 }
1511
1512 /**************************************************************************/
1513
1514 SbBool
coin_parse_versionstring(const char * versionstr,int * major,int * minor,int * patch)1515 coin_parse_versionstring(const char * versionstr,
1516 int * major,
1517 int * minor,
1518 int * patch)
1519 {
1520 char buffer[256];
1521 char * dotptr;
1522
1523 *major = 0;
1524 if (minor) *minor = 0;
1525 if (patch) *patch = 0;
1526 if (versionstr == NULL) return FALSE;
1527
1528 (void)strncpy(buffer, versionstr, 255);
1529 buffer[255] = '\0'; /* strncpy() will not null-terminate if strlen > 255 */
1530 dotptr = strchr(buffer, '.');
1531 if (dotptr) {
1532 char * spaceptr;
1533 char * start = buffer;
1534 *dotptr = '\0';
1535 *major = atoi(start);
1536 if (minor == NULL) return TRUE;
1537 start = ++dotptr;
1538
1539 dotptr = strchr(start, '.');
1540 spaceptr = strchr(start, ' ');
1541 if (!dotptr && spaceptr) dotptr = spaceptr;
1542 if (dotptr && spaceptr && spaceptr < dotptr) dotptr = spaceptr;
1543 if (dotptr) {
1544 int terminate = *dotptr == ' ';
1545 *dotptr = '\0';
1546 *minor = atoi(start);
1547 if (patch == NULL) return TRUE;
1548 if (!terminate) {
1549 start = ++dotptr;
1550 dotptr = strchr(start, ' ');
1551 if (dotptr) *dotptr = '\0';
1552 *patch = atoi(start);
1553 }
1554 }
1555 else {
1556 *minor = atoi(start);
1557 }
1558 }
1559 else {
1560 cc_debugerror_post("coin_parse_versionstring",
1561 "Invalid versionstring: \"%s\"\n", versionstr);
1562 return FALSE;
1563 }
1564 return TRUE;
1565 }
1566
1567 /* Wrapper to use either _getcwd() (Win32) or getcwd() (POSIX.1) */
1568 static char *
getcwd_wrapper(char * buf,size_t size)1569 getcwd_wrapper(char * buf, size_t size)
1570 {
1571 #ifdef HAVE__GETCWD
1572 return _getcwd(buf, (int)size);
1573 #elif defined(HAVE_GETCWD)
1574 return getcwd(buf, size);
1575 #else /* HAVE_GETCWD */
1576 /* FIXME: abort compilation? pederb, 2003-08-18 */
1577 return NULL;
1578 #endif /* ! HAVE_GETCWD */
1579 }
1580
1581 /**************************************************************************/
1582
1583 /* Stores the name of the current working directory in the \a str
1584 argument.
1585
1586 Returns TRUE if current working directory could be found, FALSE if
1587 not. If FALSE is returned, an error message will be stored in \a
1588 str.
1589
1590 \a str must have been initialized before being passed to this
1591 function.
1592
1593 The rationale behind this wrapper around the POSIX.1 getcwd()
1594 function is to abstract away the extra operations necessary to
1595 handle that the input buffer is guaranteed to be large enough.
1596 */
1597 SbBool
coin_getcwd(cc_string * str)1598 coin_getcwd(cc_string * str)
1599 {
1600 char buf[256], * dynbuf = NULL;
1601 size_t bufsize = sizeof(buf);
1602 char * cwd = getcwd_wrapper(buf, bufsize);
1603
1604 while ((cwd == NULL) && (errno == ERANGE)) {
1605 bufsize *= 2;
1606 if (dynbuf != NULL) { free(dynbuf); }
1607 dynbuf = (char *)malloc(bufsize);
1608 cwd = getcwd_wrapper(dynbuf, bufsize);
1609 }
1610 if (cwd == NULL) { cc_string_set_text(str, strerror(errno)); }
1611 else { cc_string_set_text(str, cwd); }
1612
1613 if (dynbuf != NULL) { free(dynbuf); }
1614 return cwd ? TRUE : FALSE;
1615 }
1616
1617 /**************************************************************************/
1618
1619 /* Returns -1 if value equals negative infinity, +1 if it is equal to
1620 positive infinity, or 0 if the number is not infinite.
1621
1622 Note that on some systems, this method will always return 0
1623 (i.e. false positives).
1624 */
1625 int
coin_isinf(double value)1626 coin_isinf(double value)
1627 {
1628 #ifdef HAVE_ISINF
1629 return std::isinf(value);
1630 #elif defined(HAVE_FPCLASS)
1631 if (fpclass(value) == FP_NINF) { return -1; }
1632 if (fpclass(value) == FP_PINF) { return +1; }
1633 return 0;
1634 #elif defined(HAVE__FPCLASS)
1635 if (_fpclass(value) == _FPCLASS_NINF) { return -1; }
1636 if (_fpclass(value) == _FPCLASS_PINF) { return +1; }
1637 return 0;
1638 #else
1639 /* FIXME: it might be possible to investigate the fp bits and decide
1640 in a portable manner whether or not they represent an infinite. A
1641 groups.google.com search turned up inconclusive. 20030919
1642 mortene. */
1643 return 0;
1644 #endif
1645 }
1646
1647 /* Returns 0 if the bitpattern of the \a value argument is not a valid
1648 floating point number, otherwise returns non-zero.
1649
1650 Note that on some systems, this method will always return 0
1651 (i.e. false positives).
1652 */
1653 int
coin_isnan(double value)1654 coin_isnan(double value)
1655 {
1656 #ifdef HAVE_ISNAN
1657 return std::isnan(value);
1658 #elif defined(HAVE__ISNAN)
1659 return _isnan(value);
1660 #elif defined(HAVE_FPCLASS)
1661 if (fpclass(value) == FP_SNAN) { return 1; }
1662 if (fpclass(value) == FP_QNAN) { return 1; }
1663 return 0;
1664 #elif defined(HAVE__FPCLASS)
1665 if (_fpclass(value) == _FPCLASS_SNAN) { return 1; }
1666 if (_fpclass(value) == _FPCLASS_QNAN) { return 1; }
1667 return 0;
1668 #else
1669 /* FIXME: it might be possible to investigate the fp bits and decide
1670 in a portable manner whether or not they represent a NaN. A
1671 groups.google.com search turned up inconclusive. 20030919
1672 mortene. */
1673 return 0;
1674 #endif
1675 }
1676
1677 /* Returns 0 if the bitpattern of the \a value argument is not a valid
1678 floating point number, or an infinite number, otherwise returns
1679 non-zero.
1680
1681 Note that on some systems, this method will always return 1
1682 (i.e. false positives).
1683 */
1684 int
coin_finite(double value)1685 coin_finite(double value)
1686 {
1687 #ifdef HAVE_FINITE
1688 return finite(value);
1689 #elif defined(HAVE__FINITE)
1690 return _finite(value);
1691 #else
1692 return !coin_isinf(value) && !coin_isnan(value);
1693 #endif
1694 }
1695
1696 /**************************************************************************/
1697
1698 /* table containing the next prime number for all power of twos from
1699 2^1 to 2^32 (the 2^32 prime is obviously less than 2^32 though) */
1700 static const unsigned long coin_prime_table[32] = {
1701 2,
1702 5,
1703 11,
1704 17,
1705 37,
1706 67,
1707 131,
1708 257,
1709 521,
1710 1031,
1711 2053,
1712 4099,
1713 8209,
1714 16411,
1715 32771,
1716 65537,
1717 131101,
1718 262147,
1719 524309,
1720 1048583,
1721 2097169,
1722 4194319,
1723 8388617,
1724 16777259,
1725 33554467,
1726 67108879,
1727 134217757,
1728 268435459,
1729 536870923,
1730 1073741827,
1731 2147483659U,
1732 4294967291U /* 2^32 = 4294967296 */
1733 };
1734
1735 unsigned long
coin_geq_prime_number(unsigned long num)1736 coin_geq_prime_number(unsigned long num)
1737 {
1738 int i;
1739 for (i = 0; i < 32; i++) {
1740 if (coin_prime_table[i] >= num) {
1741 return coin_prime_table[i];
1742 }
1743 }
1744 /* just return num if we can't find a bigger prime number */
1745 return num;
1746 }
1747
1748 /**************************************************************************/
1749
1750 int
coin_runtime_os(void)1751 coin_runtime_os(void)
1752 {
1753 /*
1754 * FIXME: this implementation should be replaced by something that
1755 * does a runtime check. kyrah suggested using sysctl() or uname()
1756 * (both part of the C runtime library) which sounds like a good
1757 * idea. pederb, 20051101
1758 *
1759 */
1760 #if defined(__APPLE__)
1761 return COIN_OS_X;
1762 #elif defined(HAVE_WIN32_API)
1763 return COIN_MSWINDOWS;
1764 #else
1765 return COIN_UNIX;
1766 #endif
1767 }
1768
1769 /**************************************************************************/
1770
1771 /*
1772 * Will return TRUE if extra debugging information is enabled. These
1773 * are typically debugging messages extra for Coin and not found in
1774 * SGI Inventor. Also, these debugging message will not necessarily
1775 * mean that anything is wrong, but they can be useful for debugging
1776 * anyway.
1777 */
1778 int
coin_debug_extra(void)1779 coin_debug_extra(void)
1780 {
1781 #if COIN_DEBUG
1782 return COIN_DEBUG_EXTRA;
1783 #else /* COIN_DEBUG */
1784 return 0;
1785 #endif /* !COIN_DEBUG */
1786 }
1787
1788 /*
1789 * Will return TRUE if SbVec*::normalize() debugging is enabled.
1790 * This can be enabled using the COIN_DEBUG_NORMALIZE environment
1791 * variable.
1792 */
1793 int
coin_debug_normalize(void)1794 coin_debug_normalize(void)
1795 {
1796 #if COIN_DEBUG
1797 return COIN_DEBUG_NORMALIZE;
1798 #else /* COIN_DEBUG */
1799 return 0;
1800 #endif /* !COIN_DEBUG */
1801 }
1802
1803
1804 /*!
1805 Used for debugging caching.
1806 */
1807 int
coin_debug_caching_level(void)1808 coin_debug_caching_level(void)
1809 {
1810 #if COIN_DEBUG
1811 static int COIN_DEBUG_CACHING = -1;
1812 if (COIN_DEBUG_CACHING < 0) {
1813 const char * env = coin_getenv("COIN_DEBUG_CACHING");
1814 if (env) COIN_DEBUG_CACHING = atoi(env);
1815 else COIN_DEBUG_CACHING = 0;
1816 }
1817 return COIN_DEBUG_CACHING;
1818 #else /* debug */
1819 return 0;
1820 #endif /* !debug */
1821 }
1822
1823 /**************************************************************************/
1824
1825 #ifdef __cplusplus
1826 } /* extern "C" */
1827 #endif
1828