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