(root)/
glibc-2.38/
string/
stpcpy.c
       1  /* Copyright (C) 1992-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #define NO_MEMPCPY_STPCPY_REDIRECT
      19  #include <string.h>
      20  #include <stdint.h>
      21  #include <memcopy.h>
      22  #include <string-fzb.h>
      23  #include <string-misc.h>
      24  
      25  #undef __stpcpy
      26  #undef stpcpy
      27  
      28  #ifndef STPCPY
      29  # define STPCPY __stpcpy
      30  #endif
      31  
      32  static __always_inline char *
      33  write_byte_from_word (op_t *dest, op_t word)
      34  {
      35    char *d = (char *) dest;
      36    for (size_t i = 0; i < OPSIZ; i++, ++d)
      37      {
      38        char c = extractbyte (word, i);
      39        *d = c;
      40        if (c == '\0')
      41  	break;
      42      }
      43    return d;
      44  }
      45  
      46  static __always_inline char *
      47  stpcpy_aligned_loop (op_t *restrict dst, const op_t *restrict src)
      48  {
      49    op_t word;
      50    while (1)
      51      {
      52        word = *src++;
      53        if (has_zero (word))
      54  	break;
      55        *dst++ = word;
      56      }
      57  
      58    return write_byte_from_word (dst, word);
      59  }
      60  
      61  static __always_inline char *
      62  stpcpy_unaligned_loop (op_t *restrict dst, const op_t *restrict src,
      63  		       uintptr_t ofs)
      64  {
      65    op_t w2a = *src++;
      66    uintptr_t sh_1 = ofs * CHAR_BIT;
      67    uintptr_t sh_2 = OPSIZ * CHAR_BIT - sh_1;
      68  
      69    op_t w2 = MERGE (w2a, sh_1, (op_t)-1, sh_2);
      70    if (!has_zero (w2))
      71      {
      72        op_t w2b;
      73  
      74        /* Unaligned loop.  The invariant is that W2B, which is "ahead" of W1,
      75  	 does not contain end-of-string.  Therefore it is safe (and necessary)
      76  	 to read another word from each while we do not have a difference.  */
      77        while (1)
      78  	{
      79  	  w2b = *src++;
      80  	  w2 = MERGE (w2a, sh_1, w2b, sh_2);
      81  	  /* Check if there is zero on w2a.  */
      82  	  if (has_zero (w2))
      83  	    goto out;
      84  	  *dst++ = w2;
      85  	  if (has_zero (w2b))
      86  	    break;
      87  	  w2a = w2b;
      88  	}
      89  
      90        /* Align the final partial of P2.  */
      91        w2 = MERGE (w2b, sh_1, 0, sh_2);
      92      }
      93  
      94  out:
      95    return write_byte_from_word (dst, w2);
      96  }
      97  
      98  
      99  /* Copy SRC to DEST, returning the address of the terminating '\0' in DEST.  */
     100  char *
     101  STPCPY (char *dest, const char *src)
     102  {
     103    /* Copy just a few bytes to make DEST aligned.  */
     104    size_t len = (-(uintptr_t) dest) % OPSIZ;
     105    for (; len != 0; len--, ++dest)
     106      {
     107        char c = *src++;
     108        *dest = c;
     109        if (c == '\0')
     110  	return dest;
     111      }
     112  
     113    /* DEST is now aligned to op_t, SRC may or may not be.  */
     114    uintptr_t ofs = (uintptr_t) src % OPSIZ;
     115    return ofs == 0 ? stpcpy_aligned_loop ((op_t*) dest, (const op_t *) src)
     116  		  : stpcpy_unaligned_loop ((op_t*) dest,
     117  					   (const op_t *) (src - ofs) , ofs);
     118  }
     119  weak_alias (__stpcpy, stpcpy)
     120  libc_hidden_def (__stpcpy)
     121  libc_hidden_builtin_def (stpcpy)