OS_NS_stdlib.cpp

Go to the documentation of this file.
00001 // OS_NS_stdlib.cpp,v 1.31 2006/05/30 10:47:53 jwillemsen Exp
00002 
00003 #include "ace/OS_NS_stdlib.h"
00004 
00005 ACE_RCSID (ace,
00006            OS_NS_stdlib,
00007            "OS_NS_stdlib.cpp,v 1.31 2006/05/30 10:47:53 jwillemsen Exp")
00008 
00009 #if !defined (ACE_HAS_INLINED_OSCALLS)
00010 # include "ace/OS_NS_stdlib.inl"
00011 #endif /* ACE_HAS_INLINED_OS_CALLS */
00012 
00013 #include "ace/OS_Memory.h"
00014 
00015 #include "ace/OS_NS_unistd.h"
00016 
00017 #if defined (ACE_LACKS_MKTEMP) \
00018     || defined (ACE_LACKS_MKSTEMP) \
00019     || defined (ACE_LACKS_REALPATH)
00020 #  include "ace/OS_NS_stdio.h"
00021 #  include "ace/OS_NS_sys_stat.h"
00022 #endif /* ACE_LACKS_MKTEMP || ACE_LACKS_MKSTEMP || ACE_LACKS_REALPATH */
00023 
00024 #if defined (ACE_LACKS_MKSTEMP)
00025 # include "ace/OS_NS_fcntl.h"
00026 # include "ace/OS_NS_ctype.h"
00027 # include "ace/OS_NS_sys_time.h"
00028 # if !defined (ACE_HAS_WINCE) && !(defined (ACE_VXWORKS) && (ACE_VXWORKS == 0x551)) && !defined (max)
00029 #  include /**/ <limits>
00030 # endif
00031 #endif  /* ACE_LACKS_MKSTEMP */
00032 
00033 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
00034 
00035 ACE_EXIT_HOOK ACE_OS::exit_hook_ = 0;
00036 
00037 void *
00038 ACE_OS::calloc (size_t elements, size_t sizeof_elements)
00039 {
00040 #if !defined (ACE_HAS_WINCE)
00041   return ACE_CALLOC_FUNC (elements, sizeof_elements);
00042 #else
00043   // @@ This will probably not work since it doesn't consider
00044   // alignment properly.
00045   return ACE_MALLOC_FUNC (elements * sizeof_elements);
00046 #endif /* ACE_HAS_WINCE */
00047 }
00048 
00049 void
00050 ACE_OS::exit (int status)
00051 {
00052   ACE_OS_TRACE ("ACE_OS::exit");
00053 
00054 #if defined (ACE_HAS_NONSTATIC_OBJECT_MANAGER) && !defined (ACE_HAS_WINCE) && !defined (ACE_DOESNT_INSTANTIATE_NONSTATIC_OBJECT_MANAGER)
00055   // Shut down the ACE_Object_Manager, if it had registered its exit_hook.
00056   // With ACE_HAS_NONSTATIC_OBJECT_MANAGER, the ACE_Object_Manager is
00057   // instantiated on the main's stack.  ::exit () doesn't destroy it.
00058   if (exit_hook_)
00059     (*exit_hook_) ();
00060 #endif /* ACE_HAS_NONSTATIC_OBJECT_MANAGER && !ACE_HAS_WINCE && !ACE_DOESNT_INSTANTIATE_NONSTATIC_OBJECT_MANAGER */
00061 
00062 #if !defined (ACE_HAS_WINCE)
00063 # if defined (ACE_WIN32)
00064   ::ExitProcess ((UINT) status);
00065 # else
00066   ::exit (status);
00067 # endif /* ACE_WIN32 */
00068 #else
00069   // @@ This is not exactly the same as ExitProcess.  But this is the
00070   // closest one I can get.
00071   ::TerminateProcess (::GetCurrentProcess (), status);
00072 #endif /* ACE_HAS_WINCE */
00073 }
00074 
00075 void
00076 ACE_OS::free (void *ptr)
00077 {
00078   ACE_FREE_FUNC (ACE_MALLOC_T (ptr));
00079 }
00080 
00081 // You may be asking yourself, why are we doing this?  Well, in winbase.h,
00082 // MS didn't follow their normal Api_FunctionA and Api_FunctionW style,
00083 // so we have to #undef their define to get access to the unicode version.
00084 // And because we don't want to #undef this for the users code, we keep
00085 // this method in the .cpp file.
00086 #if defined (ACE_WIN32) && defined (UNICODE) && !defined (ACE_USES_TCHAR)
00087 #undef GetEnvironmentStrings
00088 #endif /* ACE_WIN32 && UNICODE !ACE_USES_TCHAR */
00089 
00090 ACE_TCHAR *
00091 ACE_OS::getenvstrings (void)
00092 {
00093 #if defined (ACE_LACKS_ENV)
00094   ACE_NOTSUP_RETURN (0);
00095 #elif defined (ACE_WIN32)
00096 # if defined (ACE_USES_WCHAR)
00097   return ::GetEnvironmentStringsW ();
00098 # else /* ACE_USES_WCHAR */
00099   return ::GetEnvironmentStrings ();
00100 # endif /* ACE_USES_WCHAR */
00101 #else /* ACE_WIN32 */
00102   ACE_NOTSUP_RETURN (0);
00103 #endif /* ACE_WIN32 */
00104 }
00105 
00106 #if !defined (ACE_HAS_ITOA)
00107 char *
00108 ACE_OS::itoa_emulation (int value, char *string, int radix)
00109 {
00110   char *e = string;
00111   char *b = string;
00112 
00113   // Short circuit if 0
00114 
00115   if (value == 0)
00116     {
00117       string[0] = '0';
00118       string[1] = 0;
00119       return string;
00120     }
00121 
00122   // If negative and base 10, print a - and then do the
00123   // number.
00124 
00125   if (value < 0 && radix == 10)
00126     {
00127       string[0] = '-';
00128       ++b;
00129       ++e; // Don't overwrite the negative sign.
00130       value = -value; // Drop negative sign so character selection is correct.
00131     }
00132 
00133   // Convert to base <radix>, but in reverse order
00134 
00135   while (value != 0)
00136     {
00137       int mod = value % radix;
00138       value = value / radix;
00139 
00140       *e++ = (mod < 10) ? '0' + mod : 'a' + mod - 10;
00141     }
00142 
00143   *e-- = 0;
00144 
00145   // Now reverse the string to get the correct result
00146 
00147   while (e > b)
00148     {
00149       char temp = *e;
00150       *e = *b;
00151       *b = temp;
00152       ++b;
00153       --e;
00154     }
00155 
00156   return string;
00157 }
00158 #endif /* !ACE_HAS_ITOA */
00159 
00160 #if defined (ACE_HAS_WCHAR) && defined (ACE_LACKS_ITOW)
00161 wchar_t *
00162 ACE_OS::itow_emulation (int value, wchar_t *string, int radix)
00163 {
00164   wchar_t *e = string;
00165   wchar_t *b = string;
00166 
00167   // Short circuit if 0
00168 
00169   if (value == 0)
00170     {
00171       string[0] = '0';
00172       string[1] = 0;
00173       return string;
00174     }
00175 
00176   // If negative and base 10, print a - and then do the
00177   // number.
00178 
00179   if (value < 0 && radix == 10)
00180     {
00181       string[0] = '-';
00182       b++;
00183     }
00184 
00185   // Convert to base <radix>, but in reverse order
00186 
00187   while (value != 0)
00188     {
00189       int mod = value % radix;
00190       value = value / radix;
00191 
00192       *e++ = (mod < 10) ? '0' + mod : 'a' + mod - 10;
00193     }
00194 
00195   *e-- = 0;
00196 
00197   // Now reverse the string to get the correct result
00198 
00199   while (e > b)
00200   {
00201     wchar_t temp = *e;
00202     *e = *b;
00203     *b = temp;
00204     ++b;
00205     --e;
00206   }
00207 
00208   return string;
00209 }
00210 #endif /* ACE_HAS_WCHAR && ACE_LACKS_ITOW */
00211 
00212 void *
00213 ACE_OS::malloc (size_t nbytes)
00214 {
00215   return ACE_MALLOC_FUNC (nbytes);
00216 }
00217 
00218 #if defined (ACE_LACKS_MKTEMP)
00219 ACE_TCHAR *
00220 ACE_OS::mktemp (ACE_TCHAR *s)
00221 {
00222   ACE_OS_TRACE ("ACE_OS::mktemp");
00223   if (s == 0)
00224     // check for null template string failed!
00225     return 0;
00226   else
00227     {
00228       ACE_TCHAR *xxxxxx = ACE_OS::strstr (s, ACE_LIB_TEXT ("XXXXXX"));
00229 
00230       if (xxxxxx == 0)
00231         // the template string doesn't contain "XXXXXX"!
00232         return s;
00233       else
00234         {
00235           ACE_TCHAR unique_letter = ACE_LIB_TEXT ('a');
00236           ACE_stat sb;
00237 
00238           // Find an unused filename for this process.  It is assumed
00239           // that the user will open the file immediately after
00240           // getting this filename back (so, yes, there is a race
00241           // condition if multiple threads in a process use the same
00242           // template).  This appears to match the behavior of the
00243           // SunOS 5.5 mktemp().
00244           ACE_OS::sprintf (xxxxxx,
00245                            ACE_LIB_TEXT ("%05d%c"),
00246                            ACE_OS::getpid (),
00247                            unique_letter);
00248           while (ACE_OS::stat (s, &sb) >= 0)
00249             {
00250               if (++unique_letter <= ACE_LIB_TEXT ('z'))
00251                 ACE_OS::sprintf (xxxxxx,
00252                                  ACE_LIB_TEXT ("%05d%c"),
00253                                  ACE_OS::getpid (),
00254                                  unique_letter);
00255               else
00256                 {
00257                   // maximum of 26 unique files per template, per process
00258                   ACE_OS::sprintf (xxxxxx, ACE_LIB_TEXT ("%s"), ACE_LIB_TEXT (""));
00259                   return s;
00260                 }
00261             }
00262         }
00263       return s;
00264     }
00265 }
00266 #endif /* ACE_LACKS_MKTEMP */
00267 
00268 void *
00269 ACE_OS::realloc (void *ptr, size_t nbytes)
00270 {
00271   return ACE_REALLOC_FUNC (ACE_MALLOC_T (ptr), nbytes);
00272 }
00273 
00274 #if defined (ACE_LACKS_REALPATH) && !defined (ACE_HAS_WINCE)
00275 char *
00276 ACE_OS::realpath (const char *file_name,
00277                   char *resolved_name)
00278 {
00279   ACE_OS_TRACE ("ACE_OS::realpath");
00280 
00281   if (file_name == 0)
00282     {
00283       // Single Unix Specification V3:
00284       //   Return an error if parameter is a null pointer.
00285       errno = EINVAL;
00286       return 0;
00287     }
00288 
00289   if (*file_name == '\0')
00290     {
00291       // Single Unix Specification V3:
00292       //   Return an error if the file_name argument points
00293       //   to an empty string.
00294       errno = ENOENT;
00295       return 0;
00296     }
00297 
00298   char* rpath;
00299 
00300   if (resolved_name == 0)
00301     {
00302       // Single Unix Specification V3:
00303       //   Return an error if parameter is a null pointer.
00304       //
00305       // To match glibc realpath() and Win32 _fullpath() behavior,
00306       // allocate room for the return value if resolved_name is
00307       // a null pointer.
00308       rpath = static_cast<char*>(ACE_OS::malloc (PATH_MAX));
00309       if (rpath == 0)
00310         {
00311           errno = ENOMEM;
00312           return 0;
00313         }
00314     }
00315   else
00316     {
00317       rpath = resolved_name;
00318     }
00319 
00320   char* dest;
00321 
00322   if (*file_name != '/')
00323     {
00324       // file_name is relative path so CWD needs to be added
00325       if (ACE_OS::getcwd (rpath, PATH_MAX) == 0)
00326         {
00327           if (resolved_name == 0)
00328             ACE_OS::free (rpath);
00329           return 0;
00330         }
00331       dest = ACE_OS::strchr (rpath, '\0');
00332     }
00333   else
00334     {
00335       dest = rpath;
00336     }
00337 
00338 #if !defined (ACE_LACKS_SYMLINKS)
00339   char expand_buf[PATH_MAX]; // Extra buffer needed to expand symbolic links
00340   int nlinks = 0;
00341 #endif
00342 
00343   while (*file_name)
00344     {
00345       *dest++ = '/';
00346 
00347       // Skip multiple separators
00348       while (*file_name == '/')
00349         ++file_name;
00350 
00351       char* start = dest;
00352 
00353       // Process one path component
00354       while (*file_name && *file_name != '/')
00355         {
00356           *dest++ = *file_name++;
00357           if (dest - rpath > PATH_MAX)
00358             {
00359               errno = ENAMETOOLONG;
00360               if (resolved_name == 0)
00361                 ACE_OS::free (rpath);
00362               return 0;
00363             }
00364         }
00365 
00366       if (start == dest) // Are we done?
00367         {
00368           if (dest - rpath > 1)
00369             --dest; // Remove trailing separator if not at root
00370           break;
00371         }
00372       else if (dest - start == 1 && *start == '.')
00373         {
00374           dest -= 2; // Remove "./"
00375         }
00376       else if (dest - start == 2 && *start == '.' && *(start +1) == '.')
00377         {
00378           dest -= 3; // Remove "../"
00379           if (dest > rpath) // Remove the last path component if not at root
00380             while (*--dest != '/')
00381               ;
00382         }
00383 #  if !defined (ACE_LACKS_SYMLINKS)
00384       else
00385         {
00386           ACE_stat st;
00387 
00388           *dest = '\0';
00389           if (ACE_OS::lstat(rpath, &st) < 0)
00390             {
00391               if (resolved_name == 0)
00392               ACE_OS::free (rpath);
00393                 return 0;
00394             }
00395 
00396           // Check if current path is a link
00397           if (S_ISLNK (st.st_mode))
00398             {
00399               if (++nlinks > MAXSYMLINKS)
00400                 {
00401                   errno = ELOOP;
00402                   if (resolved_name == 0)
00403                     ACE_OS::free (rpath);
00404                   return 0;
00405                 }
00406 
00407               char link_buf[PATH_MAX];
00408 
00409               ssize_t link_len = ACE_OS::readlink (rpath, link_buf, PATH_MAX);
00410               int tail_len = ACE_OS::strlen (file_name) + 1;
00411 
00412               // Check if there is room to expand link?
00413               if (link_len + tail_len > PATH_MAX)
00414                 {
00415                   errno = ENAMETOOLONG;
00416                   if (resolved_name == 0)
00417                     ACE_OS::free (rpath);
00418                   return 0;
00419                 }
00420 
00421               // Move tail and prefix it with expanded link
00422               ACE_OS::memmove (expand_buf + link_len, file_name, tail_len);
00423               ACE_OS::memcpy (expand_buf, link_buf, link_len);
00424 
00425               if (*link_buf == '/') // Absolute link?
00426                 {
00427                   dest = rpath;
00428                 }
00429               else // Relative link, remove expanded link component
00430                 {
00431                   --dest;
00432                   while (*--dest != '/')
00433                     ;
00434                 }
00435               file_name = expand_buf; // Source path is now in expand_buf
00436             }
00437         }
00438 #  endif /* ACE_LACKS_SYMLINKS */
00439     }
00440 
00441   *dest = '\0';
00442 
00443   return rpath;
00444 }
00445 #endif /* ACE_LACKS_REALPATH && !ACE_HAS_WINCE */
00446 
00447 #if defined (ACE_LACKS_STRTOL)
00448 long
00449 ACE_OS::strtol_emulation (const char *nptr, char **endptr, int base)
00450 {
00451   register const char *s = nptr;
00452   register unsigned long acc;
00453   register int c;
00454   register unsigned long cutoff;
00455   register int neg = 0, any, cutlim;
00456 
00457   /*
00458    * Skip white space and pick up leading +/- sign if any.
00459    * If base is 0, allow 0x for hex and 0 for octal, else
00460    * assume decimal; if base is already 16, allow 0x.
00461    */
00462   do {
00463     c = *s++;
00464   } while (isspace(c));
00465   if (c == '-') {
00466     neg = 1;
00467     c = *s++;
00468   } else if (c == '+')
00469     c = *s++;
00470   if ((base == 0 || base == 16) &&
00471     c == '0' && (*s == 'x' || *s == 'X')) {
00472     c = s[1];
00473     s += 2;
00474     base = 16;
00475   }
00476   if (base == 0)
00477     base = c == '0' ? 8 : 10;
00478 
00479   /*
00480    * Compute the cutoff value between legal numbers and illegal
00481    * numbers.  That is the largest legal value, divided by the
00482    * base.  An input number that is greater than this value, if
00483    * followed by a legal input character, is too big.  One that
00484    * is equal to this value may be valid or not; the limit
00485    * between valid and invalid numbers is then based on the last
00486    * digit.  For instance, if the range for longs is
00487    * [-2147483648..2147483647] and the input base is 10,
00488    * cutoff will be set to 214748364 and cutlim to either
00489    * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
00490    * a value > 214748364, or equal but the next digit is > 7 (or 8),
00491    * the number is too big, and we will return a range error.
00492    *
00493    * Set any if any `digits' consumed; make it negative to indicate
00494    * overflow.
00495    */
00496   cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
00497   cutlim = cutoff % (unsigned long)base;
00498   cutoff /= (unsigned long)base;
00499   for (acc = 0, any = 0;; c = *s++) {
00500     if (isdigit(c))
00501       c -= '0';
00502     else if (isalpha(c))
00503       c -= isupper(c) ? 'A' - 10 : 'a' - 10;
00504     else
00505       break;
00506     if (c >= base)
00507       break;
00508     if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
00509       any = -1;
00510     else {
00511       any = 1;
00512       acc *= base;
00513       acc += c;
00514     }
00515   }
00516   if (any < 0) {
00517     acc = neg ? LONG_MIN : LONG_MAX;
00518     errno = ERANGE;
00519   } else if (neg)
00520     acc = -acc;
00521   if (endptr != 0)
00522     *endptr = any ? (char *)s - 1 : (char *)nptr;
00523   return (acc);
00524 }
00525 #endif /* ACE_LACKS_STRTOL */
00526 
00527 #if defined (ACE_LACKS_STRTOUL)
00528 unsigned long
00529 ACE_OS::strtoul_emulation (const char *nptr,
00530                            char **endptr,
00531                            register int base)
00532 {
00533   register const char *s = nptr;
00534   register unsigned long acc;
00535   register int c;
00536   register unsigned long cutoff;
00537   register int neg = 0, any, cutlim;
00538 
00539   /*
00540    * See strtol for comments as to the logic used.
00541    */
00542   do
00543     c = *s++;
00544   while (isspace(c));
00545   if (c == '-')
00546     {
00547       neg = 1;
00548       c = *s++;
00549     }
00550   else if (c == '+')
00551     c = *s++;
00552   if ((base == 0 || base == 16) &&
00553       c == '0' && (*s == 'x' || *s == 'X'))
00554     {
00555       c = s[1];
00556       s += 2;
00557       base = 16;
00558     }
00559   if (base == 0)
00560     base = c == '0' ? 8 : 10;
00561   cutoff = (unsigned long) ULONG_MAX / (unsigned long) base;
00562   cutlim = (unsigned long) ULONG_MAX % (unsigned long) base;
00563 
00564   for (acc = 0, any = 0;; c = *s++)
00565     {
00566       if (isdigit(c))
00567         c -= '0';
00568       else if (isalpha(c))
00569         c -= isupper(c) ? 'A' - 10 : 'a' - 10;
00570       else
00571         break;
00572       if (c >= base)
00573         break;
00574       if (any < 0 || acc > cutoff || acc == cutoff && c > cutlim)
00575         any = -1;
00576       else
00577         {
00578           any = 1;
00579           acc *= base;
00580           acc += c;
00581         }
00582     }
00583   if (any < 0)
00584     {
00585       acc = ULONG_MAX;
00586       errno = ERANGE;
00587     } else if (neg)
00588     acc = -acc;
00589   if (endptr != 0)
00590     *endptr = any ? (char *) s - 1 : (char *) nptr;
00591   return (acc);
00592 }
00593 #endif /* ACE_LACKS_STRTOUL */
00594 
00595 
00596 #if defined (ACE_LACKS_MKSTEMP)
00597 ACE_HANDLE
00598 ACE_OS::mkstemp_emulation (ACE_TCHAR * s)
00599 {
00600   if (s == 0)
00601     {
00602       errno = EINVAL;
00603       return ACE_INVALID_HANDLE;
00604     }
00605 
00606   // The "XXXXXX" template to be filled in.
00607   ACE_TCHAR * const t  = ACE_OS::strstr (s, ACE_LIB_TEXT ("XXXXXX"));
00608 
00609   if (t == 0)
00610     {
00611       errno = EINVAL;
00612       return ACE_INVALID_HANDLE;
00613     }
00614 
00615   static unsigned int const NUM_RETRIES = 50;
00616   static unsigned int const NUM_CHARS   = 6;  // Do not change!
00617 
00618   ACE_RANDR_TYPE seed =
00619     static_cast<ACE_RANDR_TYPE> (ACE_OS::gettimeofday ().msec ());
00620 
00621   // We only care about UTF-8 / ASCII characters in generated
00622   // filenames.  A UTF-16 or UTF-32 character could potentially cause
00623   // a very large space to be searched in the below do/while() loop,
00624   // greatly slowing down this mkstemp() implementation.  It is more
00625   // practical to limit the search space to UTF-8 / ASCII characters
00626   // (i.e. 127 characters).
00627 #  if defined (ACE_HAS_WINCE) || (defined (ACE_VXWORKS) && (ACE_VXWORKS == 0x551)) || defined (max)
00628   static float const MAX_VAL = static_cast<float> (127);
00629 #else
00630   static float const MAX_VAL =
00631     static_cast<float> (std::numeric_limits<char>::max ());
00632 #endif /* ACE_HAS_WINCE */
00633 
00634   // Use high-order bits rather than low-order ones (e.g. rand() %
00635   // MAX_VAL).  See Numerical Recipes in C: The Art of Scientific
00636   // Computing (William  H. Press, Brian P. Flannery, Saul
00637   // A. Teukolsky, William T. Vetterling; New York: Cambridge
00638   // University Press, 1992 (2nd ed., p. 277).
00639   //
00640   // e.g.: MAX_VAL * rand() / (RAND_MAX + 1.0)
00641 
00642   // Factor out the constant coefficient.
00643   static float const coefficient =
00644     static_cast<float> (MAX_VAL / (RAND_MAX + 1.0f));
00645 
00646   // @@ These nested loops may be ineffecient.  Improvements are
00647   //    welcome.
00648   for (unsigned int i = 0; i < NUM_RETRIES; ++i)
00649     {
00650       for (unsigned int n = 0; n < NUM_CHARS; ++n)
00651         {
00652           ACE_TCHAR r;
00653 
00654           // This do/while() loop allows this alphanumeric character
00655           // selection to work for EBCDIC, as well.
00656           do
00657             {
00658               r =
00659                 static_cast<ACE_TCHAR> (coefficient * ACE_OS::rand_r (seed));
00660             }
00661           while (!ACE_OS::ace_isalnum (r));
00662 
00663           t[n] = r;
00664         }
00665 
00666       static int const perms =
00667 #if defined (ACE_WIN32)
00668         0;      /* Do not share while open. */
00669 #else
00670         0600;   /* S_IRUSR | S_IWUSR */
00671 #endif  /* ACE_WIN32 */
00672 
00673       // Create the file with the O_EXCL bit set to ensure that we're
00674       // not subject to a symbolic link attack.
00675       //
00676       // Note that O_EXCL is subject to a race condition over NFS
00677       // filesystems.
00678       ACE_HANDLE const handle = ACE_OS::open (s,
00679                                               O_RDWR | O_CREAT | O_EXCL,
00680                                               perms);
00681 
00682       if (handle != ACE_INVALID_HANDLE)
00683         return handle;
00684     }
00685 
00686   errno = EEXIST;  // Couldn't create a unique temporary file.
00687   return ACE_INVALID_HANDLE;
00688 }
00689 #endif /* ACE_LACKS_MKSTEMP */
00690 
00691 ACE_END_VERSIONED_NAMESPACE_DECL

Generated on Thu Nov 9 09:41:58 2006 for ACE by doxygen 1.3.6