// realloc: this is a bit more complex. First we identify the correct memory // pool and try to realloc there. If this doesn't work, we try to realloc in // another pool before giving up. void* _realloc_r( struct _reent* r, void* ptr, size_t size ) { void* temp; u32 lstart, lend; unsigned i = 0; size_t prevsize; // Realloc with ptr == NULL : malloc // Realloc with size == 0 : free if( !ptr ) return size ? _malloc_r( r, size ) : NULL; else if( !size ) { _free_r( r, ptr ); return NULL; } // At this point we know that this is an actual realloc // Identify the memory pool while( 1 ) { if( ( lstart = ( u32 )platform_get_first_free_ram( i ) ) == 0 ) return NULL; lstart = ( u32 )tlsf_elua_align_addr( ( void* )lstart ); lend = ( u32 )platform_get_last_free_ram( i ); if( ( lstart <= ( u32 )ptr ) && ( ( u32 )ptr <= lend ) ) break; i ++; } // Easy case: realloc succeeds in the same memory pool if( ( temp = realloc_ex( ptr, size, ( void* )lstart ) ) != NULL ) return temp; // If realloc returned NULL, look for another pool prevsize = tlsf_elua_get_block_size( ptr ); i = 0; while( 1 ) { if( ( temp = platform_get_first_free_ram( i ) ) == NULL ) break; temp = tlsf_elua_align_addr( temp ); if( ( u32 )temp != lstart ) { if( ( temp = malloc_ex( size, temp ) ) != NULL ) { memcpy( temp, ptr, prevsize < size ? prevsize : size ); free_ex( ptr, ( void* )lstart ); break; } } i ++; } return temp; }
void freelocale(struct __locale_t *locobj) { /* Nothing to do on !_MB_CAPABLE targets. */ #ifdef _MB_CAPABLE /* Sanity check. The "C" locale is static, don't try to free it. */ if (!locobj || locobj == __get_C_locale () || locobj == LC_GLOBAL_LOCALE) return; #ifdef __HAVE_LOCALE_INFO__ for (int i = 1; i < _LC_LAST; ++i) if (locobj->lc_cat[i].buf) { _free_r (p, (void *) locobj->lc_cat[i].ptr); _free_r (p, locobj->lc_cat[i].buf); } #endif /* __HAVE_LOCALE_INFO__ */ _free_r (p, locobj); #else /* Silence warning */ _CRT_UNUSED(locobj); #endif /* _MB_CAPABLE */ }
static int funcloser (struct _reent *ptr, void *cookie) { int result = 0; funcookie *c = (funcookie *) cookie; if (c->closefn) { errno = 0; if ((result = c->closefn (c->cookie)) < 0 && errno) __errno_r(ptr) = errno; } _free_r (ptr, c); return result; }
void * _realloc_r(struct _reent *r, void *ptr, size_t size) { if (!ptr) return _malloc_r(r, size); if (_malloc_usable_size_r(r, ptr) >= size) return ptr; void *realloc_ptr = _malloc_r(r, size); if(!realloc_ptr) return NULL; memcpy(realloc_ptr, ptr, _malloc_usable_size_r(r, ptr)); _free_r(r, ptr); return realloc_ptr; }
FILE * _freopen64_r (struct _reent *ptr, const char *file, const char *mode, register FILE *fp) { register int f; int flags, oflags, oflags2; int e = 0; CHECK_INIT (ptr, fp); /* We can't use the _newlib_flockfile_XXX macros here due to the interlocked locking with the sfp_lock. */ #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT int __oldcancel; pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &__oldcancel); #endif oflags2 = fp->_flags2; if (!(oflags2 & __SNLK)) _flockfile (fp); if ((flags = __sflags (ptr, mode, &oflags)) == 0) { if (!(oflags2 & __SNLK)) _funlockfile (fp); #ifdef _STDIO_WITH_THREAD_CANCELLATION_SUPPORT pthread_setcancelstate (__oldcancel, &__oldcancel); #endif _fclose_r (ptr, fp); return NULL; } /* * Remember whether the stream was open to begin with, and * which file descriptor (if any) was associated with it. * If it was attached to a descriptor, defer closing it, * so that, e.g., freopen("/dev/stdin", "r", stdin) works. * This is unnecessary if it was not a Unix file. */ if (fp->_flags == 0) fp->_flags = __SEOF; /* hold on to it */ else { if (fp->_flags & __SWR) _fflush_r (ptr, fp); /* * If close is NULL, closing is a no-op, hence pointless. * If file is NULL, the file should not be closed. */ if (fp->_close != NULL && file != NULL) fp->_close (ptr, fp->_cookie); } /* * Now get a new descriptor to refer to the new file, or reuse the * existing file descriptor if file is NULL. */ if (file != NULL) { f = _open64_r (ptr, (char *) file, oflags, 0666); e = __errno_r(ptr); } else { #ifdef HAVE_FCNTL int oldflags; /* * Reuse the file descriptor, but only if the new access mode is * equal or less permissive than the old. F_SETFL correctly * ignores creation flags. */ f = fp->_file; if ((oldflags = _fcntl_r (ptr, f, F_GETFL, 0)) == -1 || ! ((oldflags & O_ACCMODE) == O_RDWR || ((oldflags ^ oflags) & O_ACCMODE) == 0) || _fcntl_r (ptr, f, F_SETFL, oflags) == -1) f = -1; #else /* We cannot modify without fcntl support. */ f = -1; #endif #ifdef __SCLE /* * F_SETFL doesn't change textmode. Don't mess with modes of ttys. */ if (0 <= f && ! isatty (f) && setmode (f, oflags & (O_BINARY | O_TEXT)) == -1) f = -1; #endif if (f < 0) { e = EBADF; if (fp->_close != NULL) fp->_close (ptr, fp->_cookie); } } /* * Finish closing fp. Even if the open succeeded above, * we cannot keep fp->_base: it may be the wrong size. * This loses the effect of any setbuffer calls, * but stdio has always done this before. */ if (fp->_flags & __SMBF) _free_r (ptr, (char *) fp->_bf._base); fp->_w = 0; fp->_r = 0; fp->_p = NULL; fp->_bf._base = NULL; fp->_bf._size = 0; fp->_lbfsize = 0; if (HASUB (fp)) FREEUB (ptr, fp); fp->_ub._size = 0; if (HASLB (fp)) FREELB (ptr, fp); fp->_lb._size = 0; fp->_flags &= ~__SORD; fp->_flags2 &= ~__SWID; memset (&fp->_mbstate, 0, sizeof (_mbstate_t)); if (f < 0) { /* did not get it after all */ __sfp_lock_acquire (); fp->_flags = 0; /* set it free */ __errno_r(ptr) = e; /* restore in case _close clobbered */ if (!(oflags2 & __SNLK)) _funlockfile (fp); #ifndef __SINGLE_THREAD__ __lock_close_recursive (fp->_lock); #endif __sfp_lock_release (); #if !defined (__SINGLE_THREAD__) && defined (_POSIX_THREADS) pthread_setcancelstate (__oldcancel, &__oldcancel); #endif return NULL; } fp->_flags = flags; fp->_file = f; fp->_cookie = (void *) fp; fp->_read = __sread; fp->_write = __swrite64; fp->_seek = __sseek; fp->_seek64 = __sseek64; fp->_close = __sclose; #ifdef __SCLE if (__stextmode(fp->_file)) fp->_flags |= __SCLE; #endif fp->_flags |= __SL64; if (!(oflags2 & __SNLK)) _funlockfile (fp); #if !defined (__SINGLE_THREAD__) && defined (_POSIX_THREADS) pthread_setcancelstate (__oldcancel, &__oldcancel); #endif return fp; }
double _wcstod_l (struct _reent *ptr, const wchar_t *nptr, wchar_t **endptr, locale_t loc) { static const mbstate_t initial; mbstate_t mbs; double val; char *buf, *end; const wchar_t *wcp; size_t len; while (iswspace_l(*nptr, loc)) nptr++; /* * Convert the supplied numeric wide char. string to multibyte. * * We could attempt to find the end of the numeric portion of the * wide char. string to avoid converting unneeded characters but * choose not to bother; optimising the uncommon case where * the input string contains a lot of text after the number * duplicates a lot of strtod()'s functionality and slows down the * most common cases. */ wcp = nptr; mbs = initial; if ((len = _wcsnrtombs_l(ptr, NULL, &wcp, (size_t) -1, 0, &mbs, loc)) == (size_t) -1) { if (endptr != NULL) *endptr = (wchar_t *)nptr; return (0.0); } if ((buf = _malloc_r(ptr, len + 1)) == NULL) return (0.0); mbs = initial; _wcsnrtombs_l(ptr, buf, &wcp, (size_t) -1, len + 1, &mbs, loc); /* Let strtod() do most of the work for us. */ val = _strtod_l(ptr, buf, &end, loc); /* * We only know where the number ended in the _multibyte_ * representation of the string. If the caller wants to know * where it ended, count multibyte characters to find the * corresponding position in the wide char string. */ if (endptr != NULL) { /* The only valid multibyte char in a float converted by strtod/wcstod is the radix char. What we do here is, figure out if the radix char was in the valid leading float sequence in the incoming string. If so, the multibyte float string is strlen(radix char) - 1 bytes longer than the incoming wide char string has characters. To fix endptr, reposition end as if the radix char was just one byte long. The resulting difference (end - buf) is then equivalent to the number of valid wide characters in the input string. */ len = strlen (__localeconv_l (loc)->decimal_point); if (len > 1) { char *d = strstr (buf, __localeconv_l (loc)->decimal_point); if (d && d < end) end -= len - 1; } *endptr = (wchar_t *)nptr + (end - buf); } _free_r(ptr, buf); return (val); }
struct __locale_t * _newlocale_r (struct _reent *p, int category_mask, const char *locale, struct __locale_t *base) { #ifndef _MB_CAPABLE return __get_C_locale (); #else /* _MB_CAPABLE */ char new_categories[_LC_LAST][ENCODING_LEN + 1]; struct __locale_t tmp_locale, *new_locale; int i; /* Convert LC_ALL_MASK to a mask containing all valid MASK values. This simplifies the code below. */ if (category_mask & LC_ALL_MASK) { category_mask &= ~LC_ALL_MASK; category_mask |= LC_VALID_MASK; } /* Check for invalid mask values and valid locale ptr. */ if ((category_mask & ~LC_VALID_MASK) || !locale) { p->_errno = EINVAL; return NULL; } /* If the new locale is supposed to be all default locale, just return a pointer to the default locale. */ if ((!base && category_mask == 0) || (category_mask == LC_VALID_MASK && (!strcmp (locale, "C") || !strcmp (locale, "POSIX")))) return __get_C_locale (); /* Start with setting all values to the default locale values. */ tmp_locale = *__get_C_locale (); /* Fill out new category strings. */ for (i = 1; i < _LC_LAST; ++i) { if (((1 << i) & category_mask) != 0) { /* If locale is "", fetch from environment. Otherwise use locale name verbatim. */ const char *cat = (locale[0] == '\0') ? __get_locale_env (p, i) : locale; if (strlen (cat) > ENCODING_LEN) { p->_errno = EINVAL; return NULL; } strcpy (new_categories[i], cat); } else strcpy (new_categories[i], base ? base->categories[i] : "C"); } /* Now go over all categories and set them. */ for (i = 1; i < _LC_LAST; ++i) { /* If we have a base locale, and the category is not in category_mask or the new category is the base categroy, just copy over. */ if (base && (((1 << i) & category_mask) == 0 || !strcmp (base->categories[i], new_categories[i]))) { strcpy (tmp_locale.categories[i], new_categories[i]); if (i == LC_CTYPE) { tmp_locale.wctomb = base->wctomb; tmp_locale.mbtowc = base->mbtowc; tmp_locale.cjk_lang = base->cjk_lang; tmp_locale.ctype_ptr = base->ctype_ptr; } #ifdef __HAVE_LOCALE_INFO__ /* Mark the values as "has still to be copied". We do this in two steps to simplify freeing new locale types in case of a subsequent error. */ tmp_locale.lc_cat[i].ptr = base->lc_cat[i].ptr; tmp_locale.lc_cat[i].buf = (void *) -1; #else /* !__HAVE_LOCALE_INFO__ */ if (i == LC_CTYPE) strcpy (tmp_locale.ctype_codeset, base->ctype_codeset); else if (i == LC_MESSAGES) strcpy (tmp_locale.message_codeset, base->message_codeset); #endif /* !__HAVE_LOCALE_INFO__ */ } /* Otherwise, if the category is in category_mask, create entry. */ else if (((1 << i) & category_mask) != 0) { /* Nothing to do for "C"/"POSIX" locale. */ if (!strcmp (new_categories[i], "C") || !strcmp (new_categories[i], "POSIX")) continue; /* Otherwise load locale data. */ else if (!__loadlocale (&tmp_locale, i, new_categories[i])) goto error; } } /* Allocate new locale_t. */ new_locale = (struct __locale_t *) _calloc_r (p, 1, sizeof *new_locale); if (!new_locale) goto error; if (base) { #ifdef __HAVE_LOCALE_INFO__ /* Step 2 of copying over.. Make sure to invalidate the copied buffer pointers in base, so the subsequent _freelocale_r (base) doesn't free the buffers now used in the new locale. */ for (i = 1; i < _LC_LAST; ++i) if (tmp_locale.lc_cat[i].buf == (const void *) -1) { tmp_locale.lc_cat[i].buf = base->lc_cat[i].buf; base->lc_cat[i].ptr = base->lc_cat[i].buf = NULL; } #endif /* __HAVE_LOCALE_INFO__ */ _freelocale_r (p, base); } *new_locale = tmp_locale; return new_locale; error: /* An error occured while we had already (potentially) allocated memory. Free memory and return NULL. errno is supposed to be set already. */ #ifdef __HAVE_LOCALE_INFO__ for (i = 1; i < _LC_LAST; ++i) if (((1 << i) & category_mask) != 0 && tmp_locale.lc_cat[i].buf && tmp_locale.lc_cat[i].buf != (const void *) -1) { _free_r (p, (void *) tmp_locale.lc_cat[i].ptr); _free_r (p, tmp_locale.lc_cat[i].buf); } #endif /* __HAVE_LOCALE_INFO__ */ return NULL; #endif /* _MB_CAPABLE */ }
/** Change stream buffering. Changes the buffer to be used for I/O operations with the specified stream. Size and mode for the buffer can be specified. This function should be called once the file associated with the stream has been opened but before any input or output operation has been done. The size of the buffer is specified by the size parameter, and can be any value between 2 and 32767 in bytes, this value may be rounded down by some system due to specific alignment. buffer can be NULL. @return If the buffer is correctly assigned to the file a 0 value is returned. On error, a non-zero value is returned. This can be because an invalid type or size has been specified or because an error allocating memory (if NULL buffer was specified). @param fp pointer to an open file. @param buf User allocated buffer. Must have at least a size of size bytes. @param mode Specifies a mode for file buffering @param Buffer size in bytes, must be more than 0 and less than 32768, this value may be rounded down by some systems due to specific alignment, in which case the minimum value should be 2. */ EXPORT_C int setvbuf (FILE * fp, char *buf, int mode, size_t size) { int ret = 0; CHECK_INIT (fp); /* * Verify arguments. The `int' limit on `size' is due to this * particular implementation. */ if ((mode != _IOFBF && mode != _IOLBF && mode != _IONBF) || (int) size < 0) return (EOF); /* * Write current buffer, if any; drop read count, if any. * Make sure putc() will not think fp is line buffered. * Free old buffer if it was from malloc(). Clear line and * non buffer flags, and clear malloc flag. */ (void) fflush (fp); fp->_r = 0; fp->_lbfsize = 0; if (fp->_flags & __SMBF) _free_r (fp->_data, (void *) fp->_bf._base); fp->_flags &= ~(__SLBF | __SNBF | __SMBF); if (mode == _IONBF) goto nbf; /* * Allocate buffer if needed. */ if (buf == NULL) { if ((buf = (char *)malloc (size)) == NULL) { ret = EOF; /* Try another size... */ buf = (char *)malloc (BUFSIZ); } if (buf == NULL) { /* Can't allocate it, let's try another approach */ nbf: fp->_flags |= __SNBF; fp->_w = 0; fp->_bf._base = fp->_p = fp->_nbuf; fp->_bf._size = 1; return (ret); } fp->_flags |= __SMBF; } /* * Now put back whichever flag is needed, and fix _lbfsize * if line buffered. Ensure output flush on exit if the * stream will be buffered at all. * Force the buffer to be flushed and hence malloced on first use */ switch (mode) { case _IOLBF: fp->_flags |= __SLBF; fp->_lbfsize = -(int)size; /* FALLTHROUGH */ case _IOFBF: /* no flag */ fp->_data->__cleanup = _cleanup_r; fp->_bf._base = fp->_p = (unsigned char *) buf; fp->_bf._size = size; break; } /* * Patch up write count if necessary. */ if (fp->_flags & __SWR) fp->_w = fp->_flags & (__SLBF | __SNBF) ? 0 : size; return 0; }
void free(void *p) { _free_r(_REENT, p); }