Back to index

glibc  2.9
Defines | Functions
skeleton.c File Reference
#include <assert.h>
#include <gconv.h>
#include <string.h>
#include <stddef.h>
#include <dlfcn.h>
#include <sysdep.h>

Go to the source code of this file.

Defines

#define __need_size_t
#define __need_NULL
#define DL_CALL_FCT(fct, args)   fct args
#define MAX_NEEDED_FROM   MIN_NEEDED_FROM
#define MAX_NEEDED_TO   MIN_NEEDED_TO
#define FROM_LOOP_MIN_NEEDED_FROM   MIN_NEEDED_FROM
#define FROM_LOOP_MAX_NEEDED_FROM   MAX_NEEDED_FROM
#define FROM_LOOP_MIN_NEEDED_TO   MIN_NEEDED_TO
#define FROM_LOOP_MAX_NEEDED_TO   MAX_NEEDED_TO
#define TO_LOOP_MIN_NEEDED_FROM   MIN_NEEDED_TO
#define TO_LOOP_MAX_NEEDED_FROM   MAX_NEEDED_TO
#define TO_LOOP_MIN_NEEDED_TO   MIN_NEEDED_FROM
#define TO_LOOP_MAX_NEEDED_TO   MAX_NEEDED_FROM
#define get16u(addr)
#define get32u(addr)
#define put16u(addr, val)
#define put32u(addr, val)
#define RESET_INPUT_BUFFER
#define EXTRA_LOOP_ARGS
#define FUNCTION_NAME   gconv
#define SINGLE(fct)   SINGLE2 (fct)
#define SINGLE2(fct)   fct##_single
#define POSSIBLY_UNALIGNED
#define GEN_unaligned(name)   GEN_unaligned2 (name)
#define GEN_unaligned2(name)   name##_unaligned

Functions

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)

Define Documentation

#define __need_NULL

Definition at line 140 of file skeleton.c.

#define __need_size_t

Definition at line 139 of file skeleton.c.

#define DL_CALL_FCT (   fct,
  args 
)    fct args

Definition at line 150 of file skeleton.c.

#define EXTRA_LOOP_ARGS

Definition at line 370 of file skeleton.c.

Definition at line 182 of file skeleton.c.

Definition at line 188 of file skeleton.c.

Definition at line 179 of file skeleton.c.

Definition at line 185 of file skeleton.c.

#define FUNCTION_NAME   gconv

Definition at line 376 of file skeleton.c.

#define GEN_unaligned (   name)    GEN_unaligned2 (name)
#define GEN_unaligned2 (   name)    name##_unaligned
#define get16u (   addr)
Value:
(((__const unsigned char *) (addr))[1] << 8                          \
      | ((__const unsigned char *) (addr))[0])

Definition at line 218 of file skeleton.c.

#define get32u (   addr)
Value:
(((((__const unsigned char *) (addr))[3] << 8                        \
       | ((__const unsigned char *) (addr))[2]) << 8                        \
       | ((__const unsigned char *) (addr))[1]) << 8                        \
      | ((__const unsigned char *) (addr))[0])

Definition at line 221 of file skeleton.c.

Definition at line 169 of file skeleton.c.

Definition at line 174 of file skeleton.c.

#define put16u (   addr,
  val 
)
Value:
({ uint16_t __val = (val);                                           \
       ((unsigned char *) (addr))[0] = __val;                               \
       ((unsigned char *) (addr))[1] = __val >> 8;                          \
       (void) 0; })

Definition at line 227 of file skeleton.c.

#define put32u (   addr,
  val 
)
Value:
({ uint32_t __val = (val);                                           \
       ((unsigned char *) (addr))[0] = __val;                               \
       __val >>= 8;                                                  \
       ((unsigned char *) (addr))[1] = __val;                               \
       __val >>= 8;                                                  \
       ((unsigned char *) (addr))[2] = __val;                               \
       __val >>= 8;                                                  \
       ((unsigned char *) (addr))[3] = __val;                               \
       (void) 0; })

Definition at line 232 of file skeleton.c.

Value:
if (FROM_DIRECTION)                                                  \
    {                                                                \
      if (FROM_LOOP_MIN_NEEDED_FROM % FROM_LOOP_MIN_NEEDED_TO == 0)         \
       *inptrp -= (outbuf - outerr)                                         \
                 * (FROM_LOOP_MIN_NEEDED_FROM / FROM_LOOP_MIN_NEEDED_TO);   \
      else if (FROM_LOOP_MIN_NEEDED_TO % FROM_LOOP_MIN_NEEDED_FROM == 0)      \
       *inptrp -= (outbuf - outerr)                                         \
                 / (FROM_LOOP_MIN_NEEDED_TO / FROM_LOOP_MIN_NEEDED_FROM     \
                    ? : 1);                                          \
      else                                                           \
       *inptrp -= ((outbuf - outerr) / FROM_LOOP_MIN_NEEDED_TO)             \
                 * FROM_LOOP_MIN_NEEDED_FROM;                               \
    }                                                                \
  else                                                               \
    {                                                                \
      if (TO_LOOP_MIN_NEEDED_FROM % TO_LOOP_MIN_NEEDED_TO == 0)                    \
       *inptrp -= (outbuf - outerr)                                         \
                 * (TO_LOOP_MIN_NEEDED_FROM / TO_LOOP_MIN_NEEDED_TO);       \
      else if (TO_LOOP_MIN_NEEDED_TO % TO_LOOP_MIN_NEEDED_FROM == 0)        \
       *inptrp -= (outbuf - outerr)                                         \
                 / (TO_LOOP_MIN_NEEDED_TO / TO_LOOP_MIN_NEEDED_FROM ? : 1); \
      else                                                           \
       *inptrp -= ((outbuf - outerr) / TO_LOOP_MIN_NEEDED_TO)               \
                 * TO_LOOP_MIN_NEEDED_FROM;                                 \
    }

Definition at line 282 of file skeleton.c.

#define SINGLE (   fct)    SINGLE2 (fct)

Definition at line 380 of file skeleton.c.

#define SINGLE2 (   fct)    fct##_single

Definition at line 381 of file skeleton.c.

Definition at line 194 of file skeleton.c.

Definition at line 200 of file skeleton.c.

Definition at line 191 of file skeleton.c.

Definition at line 197 of file skeleton.c.


Function Documentation

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 
)

Definition at line 391 of file skeleton.c.

{
  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;
}

Here is the call graph for this function: