summaryrefslogtreecommitdiff
path: root/ACE/ace/OS_NS_stdlib.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ACE/ace/OS_NS_stdlib.cpp')
-rw-r--r--ACE/ace/OS_NS_stdlib.cpp691
1 files changed, 691 insertions, 0 deletions
diff --git a/ACE/ace/OS_NS_stdlib.cpp b/ACE/ace/OS_NS_stdlib.cpp
new file mode 100644
index 00000000000..61b6a64fee8
--- /dev/null
+++ b/ACE/ace/OS_NS_stdlib.cpp
@@ -0,0 +1,691 @@
+// $Id$
+
+#include "ace/OS_NS_stdlib.h"
+
+ACE_RCSID (ace,
+ OS_NS_stdlib,
+ "$Id$")
+
+#if !defined (ACE_HAS_INLINED_OSCALLS)
+# include "ace/OS_NS_stdlib.inl"
+#endif /* ACE_HAS_INLINED_OSCALLS */
+
+#include "ace/OS_Memory.h"
+
+#include "ace/OS_NS_unistd.h"
+
+#if defined (ACE_LACKS_MKTEMP) \
+ || defined (ACE_LACKS_MKSTEMP) \
+ || defined (ACE_LACKS_REALPATH)
+# include "ace/OS_NS_stdio.h"
+# include "ace/OS_NS_sys_stat.h"
+#endif /* ACE_LACKS_MKTEMP || ACE_LACKS_MKSTEMP || ACE_LACKS_REALPATH */
+
+#if defined (ACE_LACKS_MKSTEMP)
+# include "ace/OS_NS_fcntl.h"
+# include "ace/OS_NS_ctype.h"
+# include "ace/OS_NS_sys_time.h"
+# if !defined (max)
+# include "ace/Numeric_Limits.h"
+# endif
+#endif /* ACE_LACKS_MKSTEMP */
+
+ACE_BEGIN_VERSIONED_NAMESPACE_DECL
+
+ACE_EXIT_HOOK ACE_OS::exit_hook_ = 0;
+
+void *
+ACE_OS::calloc (size_t elements, size_t sizeof_elements)
+{
+#if !defined (ACE_HAS_WINCE)
+ return ACE_CALLOC_FUNC (elements, sizeof_elements);
+#else
+ // @@ This will probably not work since it doesn't consider
+ // alignment properly.
+ return ACE_MALLOC_FUNC (elements * sizeof_elements);
+#endif /* ACE_HAS_WINCE */
+}
+
+void
+ACE_OS::exit (int status)
+{
+ ACE_OS_TRACE ("ACE_OS::exit");
+
+#if defined (ACE_HAS_NONSTATIC_OBJECT_MANAGER) && !defined (ACE_HAS_WINCE) && !defined (ACE_DOESNT_INSTANTIATE_NONSTATIC_OBJECT_MANAGER)
+ // Shut down the ACE_Object_Manager, if it had registered its exit_hook.
+ // With ACE_HAS_NONSTATIC_OBJECT_MANAGER, the ACE_Object_Manager is
+ // instantiated on the main's stack. ::exit () doesn't destroy it.
+ if (exit_hook_)
+ (*exit_hook_) ();
+#endif /* ACE_HAS_NONSTATIC_OBJECT_MANAGER && !ACE_HAS_WINCE && !ACE_DOESNT_INSTANTIATE_NONSTATIC_OBJECT_MANAGER */
+
+#if !defined (ACE_HAS_WINCE)
+# if defined (ACE_WIN32)
+ ::ExitProcess ((UINT) status);
+# else
+ ::exit (status);
+# endif /* ACE_WIN32 */
+#else
+ // @@ This is not exactly the same as ExitProcess. But this is the
+ // closest one I can get.
+ ::TerminateProcess (::GetCurrentProcess (), status);
+#endif /* ACE_HAS_WINCE */
+}
+
+void
+ACE_OS::free (void *ptr)
+{
+ ACE_FREE_FUNC (ACE_MALLOC_T (ptr));
+}
+
+// You may be asking yourself, why are we doing this? Well, in winbase.h,
+// MS didn't follow their normal Api_FunctionA and Api_FunctionW style,
+// so we have to #undef their define to get access to the unicode version.
+// And because we don't want to #undef this for the users code, we keep
+// this method in the .cpp file.
+#if defined (ACE_WIN32) && defined (UNICODE) && !defined (ACE_USES_TCHAR)
+#undef GetEnvironmentStrings
+#endif /* ACE_WIN32 && UNICODE !ACE_USES_TCHAR */
+
+ACE_TCHAR *
+ACE_OS::getenvstrings (void)
+{
+#if defined (ACE_LACKS_ENV)
+ ACE_NOTSUP_RETURN (0);
+#elif defined (ACE_WIN32)
+# if defined (ACE_USES_WCHAR)
+ return ::GetEnvironmentStringsW ();
+# else /* ACE_USES_WCHAR */
+ return ::GetEnvironmentStrings ();
+# endif /* ACE_USES_WCHAR */
+#else /* ACE_WIN32 */
+ ACE_NOTSUP_RETURN (0);
+#endif /* ACE_WIN32 */
+}
+
+#if !defined (ACE_HAS_ITOA)
+char *
+ACE_OS::itoa_emulation (int value, char *string, int radix)
+{
+ char *e = string;
+ char *b = string;
+
+ // Short circuit if 0
+
+ if (value == 0)
+ {
+ string[0] = '0';
+ string[1] = 0;
+ return string;
+ }
+
+ // If negative and base 10, print a - and then do the
+ // number.
+
+ if (value < 0 && radix == 10)
+ {
+ string[0] = '-';
+ ++b;
+ ++e; // Don't overwrite the negative sign.
+ value = -value; // Drop negative sign so character selection is correct.
+ }
+
+ // Convert to base <radix>, but in reverse order
+
+ while (value != 0)
+ {
+ int mod = value % radix;
+ value = value / radix;
+
+ *e++ = (mod < 10) ? '0' + mod : 'a' + mod - 10;
+ }
+
+ *e-- = 0;
+
+ // Now reverse the string to get the correct result
+
+ while (e > b)
+ {
+ char temp = *e;
+ *e = *b;
+ *b = temp;
+ ++b;
+ --e;
+ }
+
+ return string;
+}
+#endif /* !ACE_HAS_ITOA */
+
+#if defined (ACE_HAS_WCHAR) && defined (ACE_LACKS_ITOW)
+wchar_t *
+ACE_OS::itow_emulation (int value, wchar_t *string, int radix)
+{
+ wchar_t *e = string;
+ wchar_t *b = string;
+
+ // Short circuit if 0
+
+ if (value == 0)
+ {
+ string[0] = '0';
+ string[1] = 0;
+ return string;
+ }
+
+ // If negative and base 10, print a - and then do the
+ // number.
+
+ if (value < 0 && radix == 10)
+ {
+ string[0] = '-';
+ b++;
+ }
+
+ // Convert to base <radix>, but in reverse order
+
+ while (value != 0)
+ {
+ int mod = value % radix;
+ value = value / radix;
+
+ *e++ = (mod < 10) ? '0' + mod : 'a' + mod - 10;
+ }
+
+ *e-- = 0;
+
+ // Now reverse the string to get the correct result
+
+ while (e > b)
+ {
+ wchar_t temp = *e;
+ *e = *b;
+ *b = temp;
+ ++b;
+ --e;
+ }
+
+ return string;
+}
+#endif /* ACE_HAS_WCHAR && ACE_LACKS_ITOW */
+
+void *
+ACE_OS::malloc (size_t nbytes)
+{
+ return ACE_MALLOC_FUNC (nbytes);
+}
+
+#if defined (ACE_LACKS_MKTEMP)
+ACE_TCHAR *
+ACE_OS::mktemp (ACE_TCHAR *s)
+{
+ ACE_OS_TRACE ("ACE_OS::mktemp");
+ if (s == 0)
+ // check for null template string failed!
+ return 0;
+ else
+ {
+ ACE_TCHAR *xxxxxx = ACE_OS::strstr (s, ACE_LIB_TEXT ("XXXXXX"));
+
+ if (xxxxxx == 0)
+ // the template string doesn't contain "XXXXXX"!
+ return s;
+ else
+ {
+ ACE_TCHAR unique_letter = ACE_LIB_TEXT ('a');
+ ACE_stat sb;
+
+ // Find an unused filename for this process. It is assumed
+ // that the user will open the file immediately after
+ // getting this filename back (so, yes, there is a race
+ // condition if multiple threads in a process use the same
+ // template). This appears to match the behavior of the
+ // SunOS 5.5 mktemp().
+ ACE_OS::sprintf (xxxxxx,
+ ACE_LIB_TEXT ("%05d%c"),
+ ACE_OS::getpid (),
+ unique_letter);
+ while (ACE_OS::stat (s, &sb) >= 0)
+ {
+ if (++unique_letter <= ACE_LIB_TEXT ('z'))
+ ACE_OS::sprintf (xxxxxx,
+ ACE_LIB_TEXT ("%05d%c"),
+ ACE_OS::getpid (),
+ unique_letter);
+ else
+ {
+ // maximum of 26 unique files per template, per process
+ ACE_OS::sprintf (xxxxxx, ACE_LIB_TEXT ("%s"), ACE_LIB_TEXT (""));
+ return s;
+ }
+ }
+ }
+ return s;
+ }
+}
+#endif /* ACE_LACKS_MKTEMP */
+
+void *
+ACE_OS::realloc (void *ptr, size_t nbytes)
+{
+ return ACE_REALLOC_FUNC (ACE_MALLOC_T (ptr), nbytes);
+}
+
+#if defined (ACE_LACKS_REALPATH) && !defined (ACE_HAS_WINCE)
+char *
+ACE_OS::realpath (const char *file_name,
+ char *resolved_name)
+{
+ ACE_OS_TRACE ("ACE_OS::realpath");
+
+ if (file_name == 0)
+ {
+ // Single Unix Specification V3:
+ // Return an error if parameter is a null pointer.
+ errno = EINVAL;
+ return 0;
+ }
+
+ if (*file_name == '\0')
+ {
+ // Single Unix Specification V3:
+ // Return an error if the file_name argument points
+ // to an empty string.
+ errno = ENOENT;
+ return 0;
+ }
+
+ char* rpath;
+
+ if (resolved_name == 0)
+ {
+ // Single Unix Specification V3:
+ // Return an error if parameter is a null pointer.
+ //
+ // To match glibc realpath() and Win32 _fullpath() behavior,
+ // allocate room for the return value if resolved_name is
+ // a null pointer.
+ rpath = static_cast<char*>(ACE_OS::malloc (PATH_MAX));
+ if (rpath == 0)
+ {
+ errno = ENOMEM;
+ return 0;
+ }
+ }
+ else
+ {
+ rpath = resolved_name;
+ }
+
+ char* dest;
+
+ if (*file_name != '/')
+ {
+ // file_name is relative path so CWD needs to be added
+ if (ACE_OS::getcwd (rpath, PATH_MAX) == 0)
+ {
+ if (resolved_name == 0)
+ ACE_OS::free (rpath);
+ return 0;
+ }
+ dest = ACE_OS::strchr (rpath, '\0');
+ }
+ else
+ {
+ dest = rpath;
+ }
+
+#if !defined (ACE_LACKS_SYMLINKS)
+ char expand_buf[PATH_MAX]; // Extra buffer needed to expand symbolic links
+ int nlinks = 0;
+#endif
+
+ while (*file_name)
+ {
+ *dest++ = '/';
+
+ // Skip multiple separators
+ while (*file_name == '/')
+ ++file_name;
+
+ char* start = dest;
+
+ // Process one path component
+ while (*file_name && *file_name != '/')
+ {
+ *dest++ = *file_name++;
+ if (dest - rpath > PATH_MAX)
+ {
+ errno = ENAMETOOLONG;
+ if (resolved_name == 0)
+ ACE_OS::free (rpath);
+ return 0;
+ }
+ }
+
+ if (start == dest) // Are we done?
+ {
+ if (dest - rpath > 1)
+ --dest; // Remove trailing separator if not at root
+ break;
+ }
+ else if (dest - start == 1 && *start == '.')
+ {
+ dest -= 2; // Remove "./"
+ }
+ else if (dest - start == 2 && *start == '.' && *(start +1) == '.')
+ {
+ dest -= 3; // Remove "../"
+ if (dest > rpath) // Remove the last path component if not at root
+ while (*--dest != '/')
+ ;
+ }
+# if !defined (ACE_LACKS_SYMLINKS)
+ else
+ {
+ ACE_stat st;
+
+ *dest = '\0';
+ if (ACE_OS::lstat(rpath, &st) < 0)
+ {
+ if (resolved_name == 0)
+ ACE_OS::free (rpath);
+ return 0;
+ }
+
+ // Check if current path is a link
+ if (S_ISLNK (st.st_mode))
+ {
+ if (++nlinks > MAXSYMLINKS)
+ {
+ errno = ELOOP;
+ if (resolved_name == 0)
+ ACE_OS::free (rpath);
+ return 0;
+ }
+
+ char link_buf[PATH_MAX];
+
+ ssize_t link_len = ACE_OS::readlink (rpath, link_buf, PATH_MAX);
+ int tail_len = ACE_OS::strlen (file_name) + 1;
+
+ // Check if there is room to expand link?
+ if (link_len + tail_len > PATH_MAX)
+ {
+ errno = ENAMETOOLONG;
+ if (resolved_name == 0)
+ ACE_OS::free (rpath);
+ return 0;
+ }
+
+ // Move tail and prefix it with expanded link
+ ACE_OS::memmove (expand_buf + link_len, file_name, tail_len);
+ ACE_OS::memcpy (expand_buf, link_buf, link_len);
+
+ if (*link_buf == '/') // Absolute link?
+ {
+ dest = rpath;
+ }
+ else // Relative link, remove expanded link component
+ {
+ --dest;
+ while (*--dest != '/')
+ ;
+ }
+ file_name = expand_buf; // Source path is now in expand_buf
+ }
+ }
+# endif /* ACE_LACKS_SYMLINKS */
+ }
+
+ *dest = '\0';
+
+ return rpath;
+}
+#endif /* ACE_LACKS_REALPATH && !ACE_HAS_WINCE */
+
+#if defined (ACE_LACKS_STRTOL)
+long
+ACE_OS::strtol_emulation (const char *nptr, char **endptr, int base)
+{
+ register const char *s = nptr;
+ register unsigned long acc;
+ register int c;
+ register unsigned long cutoff;
+ register int neg = 0, any, cutlim;
+
+ /*
+ * Skip white space and pick up leading +/- sign if any.
+ * If base is 0, allow 0x for hex and 0 for octal, else
+ * assume decimal; if base is already 16, allow 0x.
+ */
+ do {
+ c = *s++;
+ } while (isspace(c));
+ if (c == '-') {
+ neg = 1;
+ c = *s++;
+ } else if (c == '+')
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X')) {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+
+ /*
+ * Compute the cutoff value between legal numbers and illegal
+ * numbers. That is the largest legal value, divided by the
+ * base. An input number that is greater than this value, if
+ * followed by a legal input character, is too big. One that
+ * is equal to this value may be valid or not; the limit
+ * between valid and invalid numbers is then based on the last
+ * digit. For instance, if the range for longs is
+ * [-2147483648..2147483647] and the input base is 10,
+ * cutoff will be set to 214748364 and cutlim to either
+ * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
+ * a value > 214748364, or equal but the next digit is > 7 (or 8),
+ * the number is too big, and we will return a range error.
+ *
+ * Set any if any `digits' consumed; make it negative to indicate
+ * overflow.
+ */
+ cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
+ cutlim = cutoff % (unsigned long)base;
+ cutoff /= (unsigned long)base;
+ for (acc = 0, any = 0;; c = *s++) {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ any = -1;
+ else {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0) {
+ acc = neg ? LONG_MIN : LONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = any ? (char *)s - 1 : (char *)nptr;
+ return (acc);
+}
+#endif /* ACE_LACKS_STRTOL */
+
+#if defined (ACE_LACKS_STRTOUL)
+unsigned long
+ACE_OS::strtoul_emulation (const char *nptr,
+ char **endptr,
+ register int base)
+{
+ register const char *s = nptr;
+ register unsigned long acc;
+ register int c;
+ register unsigned long cutoff;
+ register int neg = 0, any, cutlim;
+
+ /*
+ * See strtol for comments as to the logic used.
+ */
+ do
+ c = *s++;
+ while (isspace(c));
+ if (c == '-')
+ {
+ neg = 1;
+ c = *s++;
+ }
+ else if (c == '+')
+ c = *s++;
+ if ((base == 0 || base == 16) &&
+ c == '0' && (*s == 'x' || *s == 'X'))
+ {
+ c = s[1];
+ s += 2;
+ base = 16;
+ }
+ if (base == 0)
+ base = c == '0' ? 8 : 10;
+ cutoff = (unsigned long) ULONG_MAX / (unsigned long) base;
+ cutlim = (unsigned long) ULONG_MAX % (unsigned long) base;
+
+ for (acc = 0, any = 0;; c = *s++)
+ {
+ if (isdigit(c))
+ c -= '0';
+ else if (isalpha(c))
+ c -= isupper(c) ? 'A' - 10 : 'a' - 10;
+ else
+ break;
+ if (c >= base)
+ break;
+ if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
+ any = -1;
+ else
+ {
+ any = 1;
+ acc *= base;
+ acc += c;
+ }
+ }
+ if (any < 0)
+ {
+ acc = ULONG_MAX;
+ errno = ERANGE;
+ } else if (neg)
+ acc = -acc;
+ if (endptr != 0)
+ *endptr = any ? (char *) s - 1 : (char *) nptr;
+ return (acc);
+}
+#endif /* ACE_LACKS_STRTOUL */
+
+
+#if defined (ACE_LACKS_MKSTEMP)
+ACE_HANDLE
+ACE_OS::mkstemp_emulation (ACE_TCHAR * s)
+{
+ if (s == 0)
+ {
+ errno = EINVAL;
+ return ACE_INVALID_HANDLE;
+ }
+
+ // The "XXXXXX" template to be filled in.
+ ACE_TCHAR * const t = ACE_OS::strstr (s, ACE_LIB_TEXT ("XXXXXX"));
+
+ if (t == 0)
+ {
+ errno = EINVAL;
+ return ACE_INVALID_HANDLE;
+ }
+
+ static unsigned int const NUM_RETRIES = 50;
+ static unsigned int const NUM_CHARS = 6; // Do not change!
+
+ ACE_RANDR_TYPE seed =
+ static_cast<ACE_RANDR_TYPE> (ACE_OS::gettimeofday ().msec ());
+
+ // We only care about UTF-8 / ASCII characters in generated
+ // filenames. A UTF-16 or UTF-32 character could potentially cause
+ // a very large space to be searched in the below do/while() loop,
+ // greatly slowing down this mkstemp() implementation. It is more
+ // practical to limit the search space to UTF-8 / ASCII characters
+ // (i.e. 127 characters).
+#if defined (max)
+ static float const MAX_VAL = static_cast<float> (127);
+#else
+ static float const MAX_VAL =
+ static_cast<float> (ACE_Numeric_Limits<char>::max ());
+#endif /* ACE_HAS_WINCE */
+
+ // Use high-order bits rather than low-order ones (e.g. rand() %
+ // MAX_VAL). See Numerical Recipes in C: The Art of Scientific
+ // Computing (William H. Press, Brian P. Flannery, Saul
+ // A. Teukolsky, William T. Vetterling; New York: Cambridge
+ // University Press, 1992 (2nd ed., p. 277).
+ //
+ // e.g.: MAX_VAL * rand() / (RAND_MAX + 1.0)
+
+ // Factor out the constant coefficient.
+ static float const coefficient =
+ static_cast<float> (MAX_VAL / (RAND_MAX + 1.0f));
+
+ // @@ These nested loops may be ineffecient. Improvements are
+ // welcome.
+ for (unsigned int i = 0; i < NUM_RETRIES; ++i)
+ {
+ for (unsigned int n = 0; n < NUM_CHARS; ++n)
+ {
+ ACE_TCHAR r;
+
+ // This do/while() loop allows this alphanumeric character
+ // selection to work for EBCDIC, as well.
+ do
+ {
+ r =
+ static_cast<ACE_TCHAR> (coefficient * ACE_OS::rand_r (seed));
+ }
+ while (!ACE_OS::ace_isalnum (r));
+
+ t[n] = r;
+ }
+
+ static int const perms =
+#if defined (ACE_WIN32)
+ 0; /* Do not share while open. */
+#else
+ 0600; /* S_IRUSR | S_IWUSR */
+#endif /* ACE_WIN32 */
+
+ // Create the file with the O_EXCL bit set to ensure that we're
+ // not subject to a symbolic link attack.
+ //
+ // Note that O_EXCL is subject to a race condition over NFS
+ // filesystems.
+ ACE_HANDLE const handle = ACE_OS::open (s,
+ O_RDWR | O_CREAT | O_EXCL,
+ perms);
+
+ if (handle != ACE_INVALID_HANDLE)
+ return handle;
+ }
+
+ errno = EEXIST; // Couldn't create a unique temporary file.
+ return ACE_INVALID_HANDLE;
+}
+#endif /* ACE_LACKS_MKSTEMP */
+
+ACE_END_VERSIONED_NAMESPACE_DECL