Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2. FUNCTION
  3.         <<memchr>>---find character in memory
  4.  
  5. INDEX
  6.         memchr
  7.  
  8. ANSI_SYNOPSIS
  9.         #include <string.h>
  10.         void *memchr(const void *<[src]>, int <[c]>, size_t <[length]>);
  11.  
  12. TRAD_SYNOPSIS
  13.         #include <string.h>
  14.         void *memchr(<[src]>, <[c]>, <[length]>)
  15.         void *<[src]>;
  16.         void *<[c]>;
  17.         size_t <[length]>;
  18.  
  19. DESCRIPTION
  20.         This function searches memory starting at <<*<[src]>>> for the
  21.         character <[c]>.  The search only ends with the first
  22.         occurrence of <[c]>, or after <[length]> characters; in
  23.         particular, <<NUL>> does not terminate the search.
  24.  
  25. RETURNS
  26.         If the character <[c]> is found within <[length]> characters
  27.         of <<*<[src]>>>, a pointer to the character is returned. If
  28.         <[c]> is not found, then <<NULL>> is returned.
  29.  
  30. PORTABILITY
  31. <<memchr>> is ANSI C.
  32.  
  33. <<memchr>> requires no supporting OS subroutines.
  34.  
  35. QUICKREF
  36.         memchr ansi pure
  37. */
  38.  
  39. #include <_ansi.h>
  40. #include <string.h>
  41. #include <limits.h>
  42.  
  43. /* Nonzero if either X or Y is not aligned on a "long" boundary.  */
  44. #define UNALIGNED(X) ((long)X & (sizeof (long) - 1))
  45.  
  46. /* How many bytes are loaded each iteration of the word copy loop.  */
  47. #define LBLOCKSIZE (sizeof (long))
  48.  
  49. /* Threshhold for punting to the bytewise iterator.  */
  50. #define TOO_SMALL(LEN)  ((LEN) < LBLOCKSIZE)
  51.  
  52. #if LONG_MAX == 2147483647L
  53. #define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
  54. #else
  55. #if LONG_MAX == 9223372036854775807L
  56. /* Nonzero if X (a long int) contains a NULL byte. */
  57. #define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
  58. #else
  59. #error long int is not a 32bit or 64bit type.
  60. #endif
  61. #endif
  62.  
  63. #ifndef DETECTNULL
  64. #error long int is not a 32bit or 64bit byte
  65. #endif
  66.  
  67. /* DETECTCHAR returns nonzero if (long)X contains the byte used
  68.    to fill (long)MASK. */
  69. #define DETECTCHAR(X,MASK) (DETECTNULL(X ^ MASK))
  70.  
  71. _PTR
  72. _DEFUN (memchr, (src_void, c, length),
  73.         _CONST _PTR src_void _AND
  74.         int c _AND
  75.         size_t length)
  76. {
  77.   _CONST unsigned char *src = (_CONST unsigned char *) src_void;
  78.   unsigned char d = c;
  79.  
  80. #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
  81.   unsigned long *asrc;
  82.   unsigned long  mask;
  83.   int i;
  84.  
  85.   while (UNALIGNED (src))
  86.     {
  87.       if (!length--)
  88.         return NULL;
  89.       if (*src == d)
  90.         return (void *) src;
  91.       src++;
  92.     }
  93.  
  94.   if (!TOO_SMALL (length))
  95.     {
  96.       /* If we get this far, we know that length is large and src is
  97.          word-aligned. */
  98.       /* The fast code reads the source one word at a time and only
  99.          performs the bytewise search on word-sized segments if they
  100.          contain the search character, which is detected by XORing
  101.          the word-sized segment with a word-sized block of the search
  102.          character and then detecting for the presence of NUL in the
  103.          result.  */
  104.       asrc = (unsigned long *) src;
  105.       mask = d << 8 | d;
  106.       mask = mask << 16 | mask;
  107.       for (i = 32; i < LBLOCKSIZE * 8; i <<= 1)
  108.         mask = (mask << i) | mask;
  109.  
  110.       while (length >= LBLOCKSIZE)
  111.         {
  112.           if (DETECTCHAR (*asrc, mask))
  113.             break;
  114.           length -= LBLOCKSIZE;
  115.           asrc++;
  116.         }
  117.  
  118.       /* If there are fewer than LBLOCKSIZE characters left,
  119.          then we resort to the bytewise loop.  */
  120.  
  121.       src = (unsigned char *) asrc;
  122.     }
  123.  
  124. #endif /* not PREFER_SIZE_OVER_SPEED */
  125.  
  126.   while (length--)
  127.     {
  128.       if (*src == d)
  129.         return (void *) src;
  130.       src++;
  131.     }
  132.  
  133.   return NULL;
  134. }
  135.