void attribute_hidden _IO_vtable_check (void) { #ifdef SHARED /* Honor the compatibility flag. */ void (*flag) (void) = atomic_load_relaxed (&IO_accept_foreign_vtables); #ifdef PTR_DEMANGLE PTR_DEMANGLE (flag); #endif if (flag == &_IO_vtable_check) return; /* In case this libc copy is in a non-default namespace, we always need to accept foreign vtables because there is always a possibility that FILE * objects are passed across the linking boundary. */ { Dl_info di; struct link_map *l; if (_dl_open_hook != NULL || (_dl_addr (_IO_vtable_check, &di, &l, NULL) != 0 && l->l_ns != LM_ID_BASE)) return; } #else /* !SHARED */ /* We cannot perform vtable validation in the static dlopen case because FILE * handles might be passed back and forth across the boundary. Therefore, we disable checking in this case. */ if (__dlopen != NULL) return; #endif __libc_fatal ("Fatal error: glibc detected an invalid stdio handle\n"); }
/* Set up NIP to run through the services. Return nonzero if there are no services (left). */ static int setup (void **fctp, service_user **nipp) { /* Remember the first service_entry, it's always the same. */ static bool startp_initialized; static service_user *startp; int no_more; if (!startp_initialized) { /* Executing this more than once at the same time must yield the same result every time. So we need no locking. */ no_more = __nss_netgroup_lookup (nipp, "setnetgrent", fctp); startp = no_more ? (service_user *) -1 : *nipp; PTR_MANGLE (startp); atomic_write_barrier (); startp_initialized = true; } else { service_user *nip = startp; PTR_DEMANGLE (nip); if (nip == (service_user *) -1) /* No services at all. */ return 1; /* Reset to the beginning of the service list. */ *nipp = nip; /* Look up the first function. */ no_more = __nss_lookup (nipp, "setnetgrent", NULL, fctp); } return no_more; }
static inline uintptr_t demangle_ptr (uintptr_t x) { # ifdef PTR_DEMANGLE PTR_DEMANGLE (x); # endif return x; }
/* If D is non-NULL, call all functions registered with `__cxa_atexit' with the same dso handle. Otherwise, if D is NULL, call all of the registered handlers. */ void __cxa_finalize (void *d) { struct exit_function_list *funcs; restart: for (funcs = __exit_funcs; funcs; funcs = funcs->next) { struct exit_function *f; for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f) { void (*cxafn) (void *arg, int status); void *cxaarg; if ((d == NULL || d == f->func.cxa.dso_handle) /* We don't want to run this cleanup more than once. */ && (cxafn = f->func.cxa.fn, cxaarg = f->func.cxa.arg, ! catomic_compare_and_exchange_bool_acq (&f->flavor, ef_free, ef_cxa))) { uint64_t check = __new_exitfn_called; #ifdef PTR_DEMANGLE PTR_DEMANGLE (cxafn); #endif cxafn (cxaarg, 0); /* It is possible that that last exit function registered more exit functions. Start the loop over. */ if (__builtin_expect (check != __new_exitfn_called, 0)) goto restart; } } } /* Also remove the quick_exit handlers, but do not call them. */ for (funcs = __quick_exit_funcs; funcs; funcs = funcs->next) { struct exit_function *f; for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f) if (d == NULL || d == f->func.cxa.dso_handle) f->flavor = ef_free; } /* Remove the registered fork handlers. We do not have to unregister anything if the program is going to terminate anyway. */ #ifdef UNREGISTER_ATFORK if (d != NULL) UNREGISTER_ATFORK (d); #endif }
void _Unwind_Resume (struct _Unwind_Exception *exc) { if (__builtin_expect (libgcc_s_handle == NULL, 0)) pthread_cancel_init (); else atomic_read_barrier (); void (*resume) (struct _Unwind_Exception *exc) = libgcc_s_resume; PTR_DEMANGLE (resume); resume (exc); }
void _Unwind_Resume (struct _Unwind_Exception *exc) { if (__glibc_unlikely (libgcc_s_handle == NULL)) pthread_cancel_init (); else atomic_read_barrier (); void (*resume) (struct _Unwind_Exception *exc) = __libgcc_s_resume; PTR_DEMANGLE (resume); resume (exc); }
_Unwind_Word _Unwind_GetCFA (struct _Unwind_Context *context) { if (__builtin_expect (libgcc_s_handle == NULL, 0)) pthread_cancel_init (); else atomic_read_barrier (); _Unwind_Word (*getcfa) (struct _Unwind_Context *) = libgcc_s_getcfa; PTR_DEMANGLE (getcfa); return getcfa (context); }
static int _IO_cookie_close (_IO_FILE *fp) { struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp; cookie_close_function_t *close_cb = cfile->__io_functions.close; #ifdef PTR_DEMANGLE PTR_DEMANGLE (close_cb); #endif if (close_cb == NULL) return 0; return close_cb (cfile->__cookie); }
static _IO_ssize_t _IO_cookie_read (_IO_FILE *fp, void *buf, _IO_ssize_t size) { struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp; cookie_read_function_t *read_cb = cfile->__io_functions.read; #ifdef PTR_DEMANGLE PTR_DEMANGLE (read_cb); #endif if (read_cb == NULL) return -1; return read_cb (cfile->__cookie, buf, size); }
_Unwind_Reason_Code _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop, void *stop_argument) { if (__builtin_expect (libgcc_s_handle == NULL, 0)) pthread_cancel_init (); else atomic_read_barrier (); _Unwind_Reason_Code (*forcedunwind) (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *) = libgcc_s_forcedunwind; PTR_DEMANGLE (forcedunwind); return forcedunwind (exc, stop, stop_argument); }
static _IO_off64_t _IO_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir) { struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp; cookie_seek_function_t *seek_cb = cfile->__io_functions.seek; #ifdef PTR_DEMANGLE PTR_DEMANGLE (seek_cb); #endif return ((seek_cb == NULL || (seek_cb (cfile->__cookie, &offset, dir) == -1) || offset == (_IO_off64_t) -1) ? _IO_pos_BAD : offset); }
static int do_length (struct _IO_codecvt *codecvt, __mbstate_t *statep, const char *from_start, const char *from_end, _IO_size_t max) { int result; #ifdef _LIBC const unsigned char *cp = (const unsigned char *) from_start; wchar_t to_buf[max]; struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps; size_t dummy; codecvt->__cd_in.__cd.__data[0].__outbuf = (unsigned char *) to_buf; codecvt->__cd_in.__cd.__data[0].__outbufend = (unsigned char *) &to_buf[max]; codecvt->__cd_in.__cd.__data[0].__statep = statep; __gconv_fct fct = gs->__fct; #ifdef PTR_DEMANGLE if (gs->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif DL_CALL_FCT (fct, (gs, codecvt->__cd_in.__cd.__data, &cp, (const unsigned char *) from_end, NULL, &dummy, 0, 0)); result = cp - (const unsigned char *) from_start; #else # ifdef _GLIBCPP_USE_WCHAR_T const char *from_start_copy = (const char *) from_start; size_t from_len = from_end - from_start; wchar_t to_buf[max]; size_t res; char *to_start = (char *) to_buf; res = iconv (codecvt->__cd_in, &from_start_copy, &from_len, &to_start, &max); result = from_start_copy - (char *) from_start; # else /* Decide what to do. */ result = 0; # endif #endif return result; }
_Unwind_Reason_Code __gcc_personality_v0 (int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) { if (__builtin_expect (libgcc_s_handle == NULL, 0)) pthread_cancel_init (); else atomic_read_barrier (); _Unwind_Reason_Code (*personality) (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *, struct _Unwind_Context *) = libgcc_s_personality; PTR_DEMANGLE (personality); return personality (version, actions, exception_class, ue_header, context); }
static _IO_off64_t attribute_compat_text_section _IO_old_cookie_seek (_IO_FILE *fp, _IO_off64_t offset, int dir) { struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp; int (*seek_cb) (_IO_FILE *, _IO_off_t, int) = (int (*) (_IO_FILE *, _IO_off_t, int)) cfile->__io_functions.seek;; #ifdef PTR_DEMANGLE PTR_DEMANGLE (seek_cb); #endif if (seek_cb == NULL) return _IO_pos_BAD; int ret = seek_cb (cfile->__cookie, offset, dir); return (ret == -1) ? _IO_pos_BAD : ret; }
static int internal_function find_module (const char *directory, const char *filename, struct __gconv_step *result) { size_t dirlen = strlen (directory); size_t fnamelen = strlen (filename) + 1; char fullname[dirlen + fnamelen]; int status = __GCONV_NOCONV; memcpy (__mempcpy (fullname, directory, dirlen), filename, fnamelen); result->__shlib_handle = __gconv_find_shlib (fullname); if (result->__shlib_handle != NULL) { status = __GCONV_OK; result->__modname = NULL; result->__fct = result->__shlib_handle->fct; result->__init_fct = result->__shlib_handle->init_fct; result->__end_fct = result->__shlib_handle->end_fct; /* These settings can be overridden by the init function. */ result->__btowc_fct = NULL; result->__data = NULL; /* Call the init function. */ if (result->__init_fct != NULL) { __gconv_init_fct init_fct = result->__init_fct; #ifdef PTR_DEMANGLE PTR_DEMANGLE (init_fct); #endif status = DL_CALL_FCT (init_fct, (result)); #ifdef PTR_MANGLE if (result->__btowc_fct != NULL) PTR_MANGLE (result->__btowc_fct); #endif } } return status; }
static _IO_ssize_t _IO_cookie_write (_IO_FILE *fp, const void *buf, _IO_ssize_t size) { struct _IO_cookie_file *cfile = (struct _IO_cookie_file *) fp; cookie_write_function_t *write_cb = cfile->__io_functions.write; #ifdef PTR_DEMANGLE PTR_DEMANGLE (write_cb); #endif if (write_cb == NULL) { fp->_flags |= _IO_ERR_SEEN; return 0; } _IO_ssize_t n = write_cb (cfile->__cookie, buf, size); if (n < size) fp->_flags |= _IO_ERR_SEEN; return n; }
void * __nss_lookup_function (service_user *ni, const char *fct_name) { void **found, *result; /* We now modify global data. Protect it. */ __libc_lock_lock (lock); /* Search the tree of functions previously requested. Data in the tree are `known_function' structures, whose first member is a `const char *', the lookup key. The search returns a pointer to the tree node structure; the first member of the is a pointer to our structure (i.e. what will be a `known_function'); since the first member of that is the lookup key string, &FCT_NAME is close enough to a pointer to our structure to use as a lookup key that will be passed to `known_compare' (above). */ found = __tsearch (&fct_name, &ni->known, &known_compare); if (*found != &fct_name) { /* The search found an existing structure in the tree. */ result = ((known_function *) *found)->fct_ptr; PTR_DEMANGLE (result); } else { /* This name was not known before. Now we have a node in the tree (in the proper sorted position for FCT_NAME) that points to &FCT_NAME instead of any real `known_function' structure. Allocate a new structure and fill it in. */ known_function *known = malloc (sizeof *known); if (! known) { remove_from_tree: /* Oops. We can't instantiate this node properly. Remove it from the tree. */ __tdelete (&fct_name, &ni->known, &known_compare); result = NULL; } else { /* Point the tree node at this new structure. */ *found = known; known->fct_name = fct_name; if (ni->library == NULL) { /* This service has not yet been used. Fetch the service library for it, creating a new one if need be. If there is no service table from the file, this static variable holds the head of the service_library list made from the default configuration. */ static name_database default_table; ni->library = nss_new_service (service_table ?: &default_table, ni->name); if (ni->library == NULL) { /* This only happens when out of memory. */ free (known); goto remove_from_tree; } } #if !defined DO_STATIC_NSS || defined SHARED if (ni->library->lib_handle == NULL) { /* Load the shared library. */ size_t shlen = (7 + strlen (ni->library->name) + 3 + strlen (__nss_shlib_revision) + 1); int saved_errno = errno; char shlib_name[shlen]; /* Construct shared object name. */ __stpcpy (__stpcpy (__stpcpy (__stpcpy (shlib_name, "libnss_"), ni->library->name), ".so"), __nss_shlib_revision); ni->library->lib_handle = __libc_dlopen (shlib_name); if (ni->library->lib_handle == NULL) { /* Failed to load the library. */ ni->library->lib_handle = (void *) -1l; __set_errno (saved_errno); } } if (ni->library->lib_handle == (void *) -1l) /* Library not found => function not found. */ result = NULL; else { /* Get the desired function. */ size_t namlen = (5 + strlen (ni->library->name) + 1 + strlen (fct_name) + 1); char name[namlen]; /* Construct the function name. */ __stpcpy (__stpcpy (__stpcpy (__stpcpy (name, "_nss_"), ni->library->name), "_"), fct_name); /* Look up the symbol. */ result = __libc_dlsym (ni->library->lib_handle, name); } #else /* We can't get function address dynamically in static linking. */ { # define DEFINE_ENT(h,nm) \ { #h"_get"#nm"ent_r", _nss_##h##_get##nm##ent_r }, \ { #h"_end"#nm"ent", _nss_##h##_end##nm##ent }, \ { #h"_set"#nm"ent", _nss_##h##_set##nm##ent }, # define DEFINE_GET(h,nm) \ { #h"_get"#nm"_r", _nss_##h##_get##nm##_r }, # define DEFINE_GETBY(h,nm,ky) \ { #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r }, static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] = { # include "function.def" { NULL, NULL } }; size_t namlen = (5 + strlen (ni->library->name) + 1 + strlen (fct_name) + 1); char name[namlen]; /* Construct the function name. */ __stpcpy (__stpcpy (__stpcpy (name, ni->library->name), "_"), fct_name); result = NULL; for (tp = &tbl[0]; tp->fname; tp++) if (strcmp (tp->fname, name) == 0) { result = tp->fp; break; } } #endif /* Remember function pointer for later calls. Even if null, we record it so a second try needn't search the library again. */ known->fct_ptr = result; PTR_MANGLE (known->fct_ptr); } } /* Remove the lock. */ __libc_lock_unlock (lock); return result; }
int internal_function __gconv (__gconv_t cd, const unsigned char **inbuf, const unsigned char *inbufend, unsigned char **outbuf, unsigned char *outbufend, size_t *irreversible) { size_t last_step; int result; if (cd == (__gconv_t) -1L) return __GCONV_ILLEGAL_DESCRIPTOR; last_step = cd->__nsteps - 1; assert (irreversible != NULL); *irreversible = 0; cd->__data[last_step].__outbuf = outbuf != NULL ? *outbuf : NULL; cd->__data[last_step].__outbufend = outbufend; __gconv_fct fct = cd->__steps->__fct; #ifdef PTR_DEMANGLE if (cd->__steps->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif if (inbuf == NULL || *inbuf == NULL) { /* We just flush. */ result = DL_CALL_FCT (fct, (cd->__steps, cd->__data, NULL, NULL, NULL, irreversible, cd->__data[last_step].__outbuf == NULL ? 2 : 1, 0)); /* If the flush was successful clear the rest of the state. */ if (result == __GCONV_OK) for (size_t cnt = 0; cnt <= last_step; ++cnt) cd->__data[cnt].__invocation_counter = 0; } else { const unsigned char *last_start; assert (outbuf != NULL && *outbuf != NULL); do { last_start = *inbuf; result = DL_CALL_FCT (fct, (cd->__steps, cd->__data, inbuf, inbufend, NULL, irreversible, 0, 0)); } while (result == __GCONV_EMPTY_INPUT && last_start != *inbuf && *inbuf + cd->__steps->__min_needed_from <= inbufend); } if (outbuf != NULL && *outbuf != NULL) *outbuf = cd->__data[last_step].__outbuf; return result; }
static enum __codecvt_result do_in (struct _IO_codecvt *codecvt, __mbstate_t *statep, const char *from_start, const char *from_end, const char **from_stop, wchar_t *to_start, wchar_t *to_end, wchar_t **to_stop) { enum __codecvt_result result; #ifdef _LIBC struct __gconv_step *gs = codecvt->__cd_in.__cd.__steps; int status; size_t dummy; const unsigned char *from_start_copy = (unsigned char *) from_start; codecvt->__cd_in.__cd.__data[0].__outbuf = (unsigned char *) to_start; codecvt->__cd_in.__cd.__data[0].__outbufend = (unsigned char *) to_end; codecvt->__cd_in.__cd.__data[0].__statep = statep; __gconv_fct fct = gs->__fct; #ifdef PTR_DEMANGLE if (gs->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif status = DL_CALL_FCT (fct, (gs, codecvt->__cd_in.__cd.__data, &from_start_copy, (const unsigned char *) from_end, NULL, &dummy, 0, 0)); *from_stop = (const char *) from_start_copy; *to_stop = (wchar_t *) codecvt->__cd_in.__cd.__data[0].__outbuf; switch (status) { case __GCONV_OK: case __GCONV_EMPTY_INPUT: result = __codecvt_ok; break; case __GCONV_FULL_OUTPUT: case __GCONV_INCOMPLETE_INPUT: result = __codecvt_partial; break; default: result = __codecvt_error; break; } #else # ifdef _GLIBCPP_USE_WCHAR_T size_t res; const char *from_start_copy = (const char *) from_start; size_t from_len = from_end - from_start; char *to_start_copy = (char *) from_start; size_t to_len = to_end - to_start; res = iconv (codecvt->__cd_in, &from_start_copy, &from_len, &to_start_copy, &to_len); if (res == 0) result = __codecvt_ok; else if (to_len == 0) result = __codecvt_partial; else if (from_len < codecvt->__codecvt_do_max_length (codecvt)) result = __codecvt_partial; else result = __codecvt_error; # else /* Decide what to do. */ result = __codecvt_error; # endif #endif return result; }
int FUNCTION_NAME (struct __gconv_step *step, struct __gconv_step_data *data, const unsigned char **inptrp, const unsigned char *inend, unsigned char **outbufstart, size_t *irreversible, int do_flush, int consume_incomplete) { struct __gconv_step *next_step = step + 1; struct __gconv_step_data *next_data = data + 1; __gconv_fct fct = NULL; int status; if ((data->__flags & __GCONV_IS_LAST) == 0) { fct = next_step->__fct; #ifdef PTR_DEMANGLE if (next_step->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif } /* If the function is called with no input this means we have to reset to the initial state. The possibly partly converted input is dropped. */ if (__builtin_expect (do_flush, 0)) { /* This should never happen during error handling. */ assert (outbufstart == NULL); status = __GCONV_OK; #ifdef EMIT_SHIFT_TO_INIT if (do_flush == 1) { /* We preserve the initial values of the pointer variables. */ unsigned char *outbuf = data->__outbuf; unsigned char *outstart = outbuf; unsigned char *outend = data->__outbufend; # ifdef PREPARE_LOOP PREPARE_LOOP # endif # ifdef SAVE_RESET_STATE SAVE_RESET_STATE (1); # endif /* Emit the escape sequence to reset the state. */ EMIT_SHIFT_TO_INIT; /* Call the steps down the chain if there are any but only if we successfully emitted the escape sequence. This should only fail if the output buffer is full. If the input is invalid it should be discarded since the user wants to start from a clean state. */ if (status == __GCONV_OK) { if (data->__flags & __GCONV_IS_LAST) /* Store information about how many bytes are available. */ data->__outbuf = outbuf; else { /* Write out all output which was produced. */ if (outbuf > outstart) { const unsigned char *outerr = outstart; int result; result = DL_CALL_FCT (fct, (next_step, next_data, &outerr, outbuf, NULL, irreversible, 0, consume_incomplete)); if (result != __GCONV_EMPTY_INPUT) { if (__builtin_expect (outerr != outbuf, 0)) { /* We have a problem. Undo the conversion. */ outbuf = outstart; /* Restore the state. */ # ifdef SAVE_RESET_STATE SAVE_RESET_STATE (0); # endif } /* Change the status. */ status = result; } } if (status == __GCONV_OK) /* Now flush the remaining steps. */ status = DL_CALL_FCT (fct, (next_step, next_data, NULL, NULL, NULL, irreversible, 1, consume_incomplete)); } } } else #endif { /* Clear the state object. There might be bytes in there from previous calls with CONSUME_INCOMPLETE == 1. But don't emit escape sequences. */ memset (data->__statep, '\0', sizeof (*data->__statep)); if (! (data->__flags & __GCONV_IS_LAST)) /* Now flush the remaining steps. */ status = DL_CALL_FCT (fct, (next_step, next_data, NULL, NULL, NULL, irreversible, do_flush, consume_incomplete)); } } else { /* We preserve the initial values of the pointer variables. */ const unsigned char *inptr = *inptrp; unsigned char *outbuf = (__builtin_expect (outbufstart == NULL, 1) ? data->__outbuf : *outbufstart); unsigned char *outend = data->__outbufend; unsigned char *outstart; /* This variable is used to count the number of characters we actually converted. */ size_t lirreversible = 0; size_t *lirreversiblep = irreversible ? &lirreversible : NULL; /* The following assumes that encodings, which have a variable length what might unalign a buffer even though it is a aligned in the beginning, either don't have the minimal number of bytes as a divisor of the maximum length or have a minimum length of 1. This is true for all known and supported encodings. We use && instead of || to combine the subexpression for the FROM encoding and for the TO encoding, because usually one of them is INTERNAL, for which the subexpression evaluates to 1, but INTERNAL buffers are always aligned correctly. */ #define POSSIBLY_UNALIGNED \ (!defined _STRING_ARCH_unaligned \ && (((FROM_LOOP_MIN_NEEDED_FROM != 1 \ && FROM_LOOP_MAX_NEEDED_FROM % FROM_LOOP_MIN_NEEDED_FROM == 0) \ && (FROM_LOOP_MIN_NEEDED_TO != 1 \ && FROM_LOOP_MAX_NEEDED_TO % FROM_LOOP_MIN_NEEDED_TO == 0)) \ || ((TO_LOOP_MIN_NEEDED_FROM != 1 \ && TO_LOOP_MAX_NEEDED_FROM % TO_LOOP_MIN_NEEDED_FROM == 0) \ && (TO_LOOP_MIN_NEEDED_TO != 1 \ && TO_LOOP_MAX_NEEDED_TO % TO_LOOP_MIN_NEEDED_TO == 0)))) #if POSSIBLY_UNALIGNED int unaligned; # define GEN_unaligned(name) GEN_unaligned2 (name) # define GEN_unaligned2(name) name##_unaligned #else # define unaligned 0 #endif #ifdef PREPARE_LOOP PREPARE_LOOP #endif #if FROM_LOOP_MAX_NEEDED_FROM > 1 || TO_LOOP_MAX_NEEDED_FROM > 1 /* If the function is used to implement the mb*towc*() or wc*tomb*() functions we must test whether any bytes from the last call are stored in the `state' object. */ if (((FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1) || (FROM_LOOP_MAX_NEEDED_FROM > 1 && FROM_DIRECTION) || (TO_LOOP_MAX_NEEDED_FROM > 1 && !FROM_DIRECTION)) && consume_incomplete && (data->__statep->__count & 7) != 0) { /* Yep, we have some bytes left over. Process them now. But this must not happen while we are called from an error handler. */ assert (outbufstart == NULL); # if FROM_LOOP_MAX_NEEDED_FROM > 1 if (TO_LOOP_MAX_NEEDED_FROM == 1 || FROM_DIRECTION) status = SINGLE(FROM_LOOP) (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); # endif # if !ONE_DIRECTION # if FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1 else # endif # if TO_LOOP_MAX_NEEDED_FROM > 1 status = SINGLE(TO_LOOP) (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); # endif # endif if (__builtin_expect (status, __GCONV_OK) != __GCONV_OK) return status; } #endif #if POSSIBLY_UNALIGNED unaligned = ((FROM_DIRECTION && ((uintptr_t) inptr % FROM_LOOP_MIN_NEEDED_FROM != 0 || ((data->__flags & __GCONV_IS_LAST) && (uintptr_t) outbuf % FROM_LOOP_MIN_NEEDED_TO != 0))) || (!FROM_DIRECTION && (((data->__flags & __GCONV_IS_LAST) && (uintptr_t) outbuf % TO_LOOP_MIN_NEEDED_TO != 0) || (uintptr_t) inptr % TO_LOOP_MIN_NEEDED_FROM != 0))); #endif while (1) { struct __gconv_trans_data *trans; /* Remember the start value for this round. */ inptr = *inptrp; /* The outbuf buffer is empty. */ outstart = outbuf; #ifdef SAVE_RESET_STATE SAVE_RESET_STATE (1); #endif if (__builtin_expect (!unaligned, 1)) { if (FROM_DIRECTION) /* Run the conversion loop. */ status = FROM_LOOP (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); else /* Run the conversion loop. */ status = TO_LOOP (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); } #if POSSIBLY_UNALIGNED else { if (FROM_DIRECTION) /* Run the conversion loop. */ status = GEN_unaligned (FROM_LOOP) (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); else /* Run the conversion loop. */ status = GEN_unaligned (TO_LOOP) (step, data, inptrp, inend, &outbuf, outend, lirreversiblep EXTRA_LOOP_ARGS); } #endif /* If we were called as part of an error handling module we don't do anything else here. */ if (__builtin_expect (outbufstart != NULL, 0)) { *outbufstart = outbuf; return status; } /* Give the transliteration module the chance to store the original text and the result in case it needs a context. */ for (trans = data->__trans; trans != NULL; trans = trans->__next) if (trans->__trans_context_fct != NULL) DL_CALL_FCT (trans->__trans_context_fct, (trans->__data, inptr, *inptrp, outstart, outbuf)); /* We finished one use of the loops. */ ++data->__invocation_counter; /* If this is the last step leave the loop, there is nothing we can do. */ if (__builtin_expect (data->__flags & __GCONV_IS_LAST, 0)) { /* Store information about how many bytes are available. */ data->__outbuf = outbuf; /* Remember how many non-identical characters we converted in a irreversible way. */ *irreversible += lirreversible; break; } /* Write out all output which was produced. */ if (__builtin_expect (outbuf > outstart, 1)) { const unsigned char *outerr = data->__outbuf; int result; result = DL_CALL_FCT (fct, (next_step, next_data, &outerr, outbuf, NULL, irreversible, 0, consume_incomplete)); if (result != __GCONV_EMPTY_INPUT) { if (__builtin_expect (outerr != outbuf, 0)) { #ifdef RESET_INPUT_BUFFER RESET_INPUT_BUFFER; #else /* We have a problem in one of the functions below. Undo the conversion upto the error point. */ size_t nstatus; /* Reload the pointers. */ *inptrp = inptr; outbuf = outstart; /* Restore the state. */ # ifdef SAVE_RESET_STATE SAVE_RESET_STATE (0); # endif if (__builtin_expect (!unaligned, 1)) { if (FROM_DIRECTION) /* Run the conversion loop. */ nstatus = FROM_LOOP (step, data, inptrp, inend, &outbuf, outerr, lirreversiblep EXTRA_LOOP_ARGS); else /* Run the conversion loop. */ nstatus = TO_LOOP (step, data, inptrp, inend, &outbuf, outerr, lirreversiblep EXTRA_LOOP_ARGS); } # if POSSIBLY_UNALIGNED else { if (FROM_DIRECTION) /* Run the conversion loop. */ nstatus = GEN_unaligned (FROM_LOOP) (step, data, inptrp, inend, &outbuf, outerr, lirreversiblep EXTRA_LOOP_ARGS); else /* Run the conversion loop. */ nstatus = GEN_unaligned (TO_LOOP) (step, data, inptrp, inend, &outbuf, outerr, lirreversiblep EXTRA_LOOP_ARGS); } # endif /* We must run out of output buffer space in this rerun. */ assert (outbuf == outerr); assert (nstatus == __GCONV_FULL_OUTPUT); /* If we haven't consumed a single byte decrement the invocation counter. */ if (__builtin_expect (outbuf == outstart, 0)) --data->__invocation_counter; #endif /* reset input buffer */ } /* Change the status. */ status = result; } else /* All the output is consumed, we can make another run if everything was ok. */ if (status == __GCONV_FULL_OUTPUT) { status = __GCONV_OK; outbuf = data->__outbuf; } } if (status != __GCONV_OK) break; /* Reset the output buffer pointer for the next round. */ outbuf = data->__outbuf; } #ifdef END_LOOP END_LOOP #endif /* If we are supposed to consume all character store now all of the remaining characters in the `state' object. */ #if FROM_LOOP_MAX_NEEDED_FROM > 1 || TO_LOOP_MAX_NEEDED_FROM > 1 if (((FROM_LOOP_MAX_NEEDED_FROM > 1 && TO_LOOP_MAX_NEEDED_FROM > 1) || (FROM_LOOP_MAX_NEEDED_FROM > 1 && FROM_DIRECTION) || (TO_LOOP_MAX_NEEDED_FROM > 1 && !FROM_DIRECTION)) && __builtin_expect (consume_incomplete, 0) && status == __GCONV_INCOMPLETE_INPUT) { # ifdef STORE_REST mbstate_t *state = data->__statep; STORE_REST # else /* Make sure the remaining bytes fit into the state objects buffer. */ assert (inend - *inptrp < 4); size_t cnt; for (cnt = 0; *inptrp < inend; ++cnt) data->__statep->__value.__wchb[cnt] = *(*inptrp)++; data->__statep->__count &= ~7; data->__statep->__count |= cnt; # endif } #endif #undef unaligned #undef POSSIBLY_UNALIGNED } return status; }
size_t __wcrtomb (char *s, wchar_t wc, mbstate_t *ps) { char buf[MB_CUR_MAX]; struct __gconv_step_data data; int status; size_t result; size_t dummy; const struct gconv_fcts *fcts; /* Set information for this step. */ data.__invocation_counter = 0; data.__internal_use = 1; data.__flags = __GCONV_IS_LAST; data.__statep = ps ?: &state; data.__trans = NULL; /* A first special case is if S is NULL. This means put PS in the initial state. */ if (s == NULL) { s = buf; wc = L'\0'; } /* Tell where we want to have the result. */ data.__outbuf = (unsigned char *) s; data.__outbufend = (unsigned char *) s + MB_CUR_MAX; /* Get the conversion functions. */ fcts = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE)); __gconv_fct fct = fcts->tomb->__fct; #ifdef PTR_DEMANGLE if (fcts->tomb->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif /* If WC is the NUL character we write into the output buffer the byte sequence necessary for PS to get into the initial state, followed by a NUL byte. */ if (wc == L'\0') { status = DL_CALL_FCT (fct, (fcts->tomb, &data, NULL, NULL, NULL, &dummy, 1, 1)); if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT) *data.__outbuf++ = '\0'; } else { /* Do a normal conversion. */ const unsigned char *inbuf = (const unsigned char *) &wc; status = DL_CALL_FCT (fct, (fcts->tomb, &data, &inbuf, inbuf + sizeof (wchar_t), NULL, &dummy, 0, 1)); } /* There must not be any problems with the conversion but illegal input characters. The output buffer must be large enough, otherwise the definition of MB_CUR_MAX is not correct. All the other possible errors also must not happen. */ assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_ILLEGAL_INPUT || status == __GCONV_INCOMPLETE_INPUT || status == __GCONV_FULL_OUTPUT); if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_FULL_OUTPUT) result = data.__outbuf - (unsigned char *) s; else { result = (size_t) -1; __set_errno (EILSEQ); } return result; }
size_t mbrtoc16 (char16_t *pc16, const char *s, size_t n, mbstate_t *ps) { if (ps == NULL) ps = &state; /* The standard text does not say that S being NULL means the state is reset even if the second half of a surrogate still have to be returned. In fact, the error code description indicates otherwise. Therefore always first try to return a second half. */ if (ps->__count & 0x80000000) { /* We have to return the second word for a surrogate. */ ps->__count &= 0x7fffffff; *pc16 = ps->__value.__wch; ps->__value.__wch = L'\0'; return (size_t) -3; } wchar_t wc; struct __gconv_step_data data; int status; size_t result; size_t dummy; const unsigned char *inbuf, *endbuf; unsigned char *outbuf = (unsigned char *) &wc; const struct gconv_fcts *fcts; /* Set information for this step. */ data.__invocation_counter = 0; data.__internal_use = 1; data.__flags = __GCONV_IS_LAST; data.__statep = ps; data.__trans = NULL; /* A first special case is if S is NULL. This means put PS in the initial state. */ if (s == NULL) { pc16 = NULL; s = ""; n = 1; } /* Tell where we want the result. */ data.__outbuf = outbuf; data.__outbufend = outbuf + sizeof (wchar_t); /* Get the conversion functions. */ fcts = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE)); /* Do a normal conversion. */ inbuf = (const unsigned char *) s; endbuf = inbuf + n; if (__glibc_unlikely (endbuf < inbuf)) { endbuf = (const unsigned char *) ~(uintptr_t) 0; if (endbuf == inbuf) goto ilseq; } __gconv_fct fct = fcts->towc->__fct; #ifdef PTR_DEMANGLE if (fcts->towc->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif status = DL_CALL_FCT (fct, (fcts->towc, &data, &inbuf, endbuf, NULL, &dummy, 0, 1)); /* There must not be any problems with the conversion but illegal input characters. The output buffer must be large enough, otherwise the definition of MB_CUR_MAX is not correct. All the other possible errors also must not happen. */ assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_ILLEGAL_INPUT || status == __GCONV_INCOMPLETE_INPUT || status == __GCONV_FULL_OUTPUT); if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_FULL_OUTPUT) { result = inbuf - (const unsigned char *) s; if (wc < 0x10000) { if (pc16 != NULL) *pc16 = wc; if (data.__outbuf != outbuf && wc == L'\0') { /* The converted character is the NUL character. */ assert (__mbsinit (data.__statep)); result = 0; } } else { /* This is a surrogate. */ if (pc16 != NULL) *pc16 = 0xd7c0 + (wc >> 10); ps->__count |= 0x80000000; ps->__value.__wch = 0xdc00 + (wc & 0x3ff); } }
wint_t __btowc (int c) { const struct gconv_fcts *fcts; /* If the parameter does not fit into one byte or it is the EOF value we can give the answer now. */ if (c < SCHAR_MIN || c > UCHAR_MAX || c == EOF) return WEOF; /* We know that only ASCII compatible encodings are used for the locale and that the wide character encoding is ISO 10646. */ if (isascii (c)) return (wint_t) c; /* Get the conversion functions. */ fcts = get_gconv_fcts (_NL_CURRENT_DATA (LC_CTYPE)); __gconv_btowc_fct btowc_fct = fcts->towc->__btowc_fct; #ifdef PTR_DEMANGLE if (fcts->towc->__shlib_handle != NULL) PTR_DEMANGLE (btowc_fct); #endif if (__builtin_expect (fcts->towc_nsteps == 1, 1) && __builtin_expect (btowc_fct != NULL, 1)) { /* Use the shortcut function. */ return DL_CALL_FCT (btowc_fct, (fcts->towc, (unsigned char) c)); } else { /* Fall back to the slow but generic method. */ wchar_t result; struct __gconv_step_data data; unsigned char inbuf[1]; const unsigned char *inptr = inbuf; size_t dummy; int status; /* Tell where we want the result. */ data.__outbuf = (unsigned char *) &result; data.__outbufend = data.__outbuf + sizeof (wchar_t); data.__invocation_counter = 0; data.__internal_use = 1; data.__flags = __GCONV_IS_LAST; data.__statep = &data.__state; /* Make sure we start in the initial state. */ memset (&data.__state, '\0', sizeof (mbstate_t)); /* Create the input string. */ inbuf[0] = c; __gconv_fct fct = fcts->towc->__fct; #ifdef PTR_DEMANGLE if (fcts->towc->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif status = DL_CALL_FCT (fct, (fcts->towc, &data, &inptr, inptr + 1, NULL, &dummy, 0, 1)); if (status != __GCONV_OK && status != __GCONV_FULL_OUTPUT && status != __GCONV_EMPTY_INPUT) /* The conversion failed. */ result = WEOF; return result; } }
int __gconv_transliterate (struct __gconv_step *step, struct __gconv_step_data *step_data, const unsigned char *inbufstart, const unsigned char **inbufp, const unsigned char *inbufend, unsigned char **outbufstart, size_t *irreversible) { /* Find out about the locale's transliteration. */ uint_fast32_t size; const uint32_t *from_idx; const uint32_t *from_tbl; const uint32_t *to_idx; const uint32_t *to_tbl; const uint32_t *winbuf; const uint32_t *winbufend; uint_fast32_t low; uint_fast32_t high; /* The input buffer. There are actually 4-byte values. */ winbuf = (const uint32_t *) *inbufp; winbufend = (const uint32_t *) inbufend; __gconv_fct fct = step->__fct; #ifdef PTR_DEMANGLE if (step->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif /* If there is no transliteration information in the locale don't do anything and return the error. */ size = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_TAB_SIZE); if (size == 0) goto no_rules; /* Get the rest of the values. */ from_idx = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_FROM_IDX); from_tbl = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_FROM_TBL); to_idx = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_TO_IDX); to_tbl = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_TO_TBL); /* Test whether there is enough input. */ if (winbuf + 1 > winbufend) return (winbuf == winbufend ? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT); /* The array starting at FROM_IDX contains indeces to the string table in FROM_TBL. The indeces are sorted wrt to the strings. I.e., we are doing binary search. */ low = 0; high = size; while (low < high) { uint_fast32_t med = (low + high) / 2; uint32_t idx; int cnt; /* Compare the string at this index with the string at the current position in the input buffer. */ idx = from_idx[med]; cnt = 0; do { if (from_tbl[idx + cnt] != winbuf[cnt]) /* Does not match. */ break; ++cnt; } while (from_tbl[idx + cnt] != L'\0' && winbuf + cnt < winbufend); if (cnt > 0 && from_tbl[idx + cnt] == L'\0') { /* Found a matching input sequence. Now try to convert the possible replacements. */ uint32_t idx2 = to_idx[med]; do { /* Determine length of replacement. */ uint_fast32_t len = 0; int res; const unsigned char *toinptr; unsigned char *outptr; while (to_tbl[idx2 + len] != L'\0') ++len; /* Try this input text. */ toinptr = (const unsigned char *) &to_tbl[idx2]; outptr = *outbufstart; res = DL_CALL_FCT (fct, (step, step_data, &toinptr, (const unsigned char *) &to_tbl[idx2 + len], &outptr, NULL, 0, 0)); if (res != __GCONV_ILLEGAL_INPUT) { /* If the conversion succeeds we have to increment the input buffer. */ if (res == __GCONV_EMPTY_INPUT) { *inbufp += cnt * sizeof (uint32_t); ++*irreversible; res = __GCONV_OK; } /* Do not increment the output pointer if we could not store the entire output. */ if (res != __GCONV_FULL_OUTPUT) *outbufstart = outptr; return res; } /* Next replacement. */ idx2 += len + 1; } while (to_tbl[idx2] != L'\0'); /* Nothing found, continue searching. */ } else if (cnt > 0) /* This means that the input buffer contents matches a prefix of an entry. Since we cannot match it unless we get more input, we will tell the caller about it. */ return __GCONV_INCOMPLETE_INPUT; if (winbuf + cnt >= winbufend || from_tbl[idx + cnt] < winbuf[cnt]) low = med + 1; else high = med; } no_rules: /* Maybe the character is supposed to be ignored. */ if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_IGNORE_LEN) != 0) { int n = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_IGNORE_LEN); const uint32_t *ranges = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_IGNORE); const uint32_t wc = *(const uint32_t *) (*inbufp); int i; /* Test whether there is enough input. */ if (winbuf + 1 > winbufend) return (winbuf == winbufend ? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT); for (i = 0; i < n; ranges += 3, ++i) if (ranges[0] <= wc && wc <= ranges[1] && (wc - ranges[0]) % ranges[2] == 0) { /* Matches the range. Ignore it. */ *inbufp += 4; ++*irreversible; return __GCONV_OK; } else if (wc < ranges[0]) /* There cannot be any other matching range since they are sorted. */ break; } /* One last chance: use the default replacement. */ if (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN) != 0) { const uint32_t *default_missing = (const uint32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING); const unsigned char *toinptr = (const unsigned char *) default_missing; uint32_t len = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_TRANSLIT_DEFAULT_MISSING_LEN); unsigned char *outptr; int res; /* Test whether there is enough input. */ if (winbuf + 1 > winbufend) return (winbuf == winbufend ? __GCONV_EMPTY_INPUT : __GCONV_INCOMPLETE_INPUT); outptr = *outbufstart; res = DL_CALL_FCT (fct, (step, step_data, &toinptr, (const unsigned char *) (default_missing + len), &outptr, NULL, 0, 0)); if (res != __GCONV_ILLEGAL_INPUT) { /* If the conversion succeeds we have to increment the input buffer. */ if (res == __GCONV_EMPTY_INPUT) { /* This worked but is not reversible. */ ++*irreversible; *inbufp += 4; res = __GCONV_OK; } *outbufstart = outptr; return res; } } /* Haven't found a match. */ return __GCONV_ILLEGAL_INPUT; }
size_t attribute_hidden __mbsrtowcs_l (wchar_t *dst, const char **src, size_t len, mbstate_t *ps, locale_t l) { struct __gconv_step_data data; size_t result; int status; struct __gconv_step *towc; size_t non_reversible; const struct gconv_fcts *fcts; /* Tell where we want the result. */ data.__invocation_counter = 0; data.__internal_use = 1; data.__flags = __GCONV_IS_LAST; data.__statep = ps; /* Get the conversion functions. */ fcts = get_gconv_fcts (l->__locales[LC_CTYPE]); /* Get the structure with the function pointers. */ towc = fcts->towc; __gconv_fct fct = towc->__fct; #ifdef PTR_DEMANGLE if (towc->__shlib_handle != NULL) PTR_DEMANGLE (fct); #endif /* We have to handle DST == NULL special. */ if (dst == NULL) { mbstate_t temp_state; wchar_t buf[64]; /* Just an arbitrary size. */ const unsigned char *inbuf = (const unsigned char *) *src; const unsigned char *srcend = inbuf + strlen (*src) + 1; temp_state = *data.__statep; data.__statep = &temp_state; result = 0; data.__outbufend = (unsigned char *) buf + sizeof (buf); do { data.__outbuf = (unsigned char *) buf; status = DL_CALL_FCT (fct, (towc, &data, &inbuf, srcend, NULL, &non_reversible, 0, 1)); result += (wchar_t *) data.__outbuf - buf; } while (status == __GCONV_FULL_OUTPUT); if (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT) { /* There better should be a NUL wide char at the end. */ assert (((wchar_t *) data.__outbuf)[-1] == L'\0'); /* Don't count the NUL character in. */ --result; } } else { /* This code is based on the safe assumption that all internal multi-byte encodings use the NUL byte only to mark the end of the string. */ const unsigned char *srcp = (const unsigned char *) *src; const unsigned char *srcend; data.__outbuf = (unsigned char *) dst; data.__outbufend = data.__outbuf + len * sizeof (wchar_t); status = __GCONV_FULL_OUTPUT; while (len > 0) { /* Pessimistic guess as to how much input we can use. In the worst case we need one input byte for one output wchar_t. */ srcend = srcp + __strnlen ((const char *) srcp, len) + 1; status = DL_CALL_FCT (fct, (towc, &data, &srcp, srcend, NULL, &non_reversible, 0, 1)); if ((status != __GCONV_EMPTY_INPUT && status != __GCONV_INCOMPLETE_INPUT) /* Not all input read. */ || srcp != srcend /* Reached the end of the input. */ || srcend[-1] == '\0') break; len = (wchar_t *) data.__outbufend - (wchar_t *) data.__outbuf; } /* Make the end if the input known to the caller. */ *src = (const char *) srcp; result = (wchar_t *) data.__outbuf - dst; /* We have to determine whether the last character converted is the NUL character. */ if ((status == __GCONV_OK || status == __GCONV_EMPTY_INPUT) && ((wchar_t *) dst)[result - 1] == L'\0') { assert (result > 0); assert (__mbsinit (data.__statep)); *src = NULL; --result; } } /* There must not be any problems with the conversion but illegal input characters. */ assert (status == __GCONV_OK || status == __GCONV_EMPTY_INPUT || status == __GCONV_ILLEGAL_INPUT || status == __GCONV_INCOMPLETE_INPUT || status == __GCONV_FULL_OUTPUT); if (status != __GCONV_OK && status != __GCONV_FULL_OUTPUT && status != __GCONV_EMPTY_INPUT && status != __GCONV_INCOMPLETE_INPUT) { result = (size_t) -1; __set_errno (EILSEQ); } return result; }