Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2. FUNCTION
  3.         <<strchr>>---search for character in string
  4.  
  5. INDEX
  6.         strchr
  7.  
  8. ANSI_SYNOPSIS
  9.         #include <string.h>
  10.         char * strchr(const char *<[string]>, int <[c]>);
  11.  
  12. TRAD_SYNOPSIS
  13.         #include <string.h>
  14.         char * strchr(<[string]>, <[c]>);
  15.         const char *<[string]>;
  16.         int <[c]>;
  17.  
  18. DESCRIPTION
  19.         This function finds the first occurence of <[c]> (converted to
  20.         a char) in the string pointed to by <[string]> (including the
  21.         terminating null character).
  22.  
  23. RETURNS
  24.         Returns a pointer to the located character, or a null pointer
  25.         if <[c]> does not occur in <[string]>.
  26.  
  27. PORTABILITY
  28. <<strchr>> is ANSI C.
  29.  
  30. <<strchr>> requires no supporting OS subroutines.
  31.  
  32. QUICKREF
  33.         strchr ansi pure
  34. */
  35.  
  36. #include <string.h>
  37. #include <limits.h>
  38.  
  39. /* Nonzero if X is not aligned on a "long" boundary.  */
  40. #define UNALIGNED(X) ((long)X & (sizeof (long) - 1))
  41.  
  42. /* How many bytes are loaded each iteration of the word copy loop.  */
  43. #define LBLOCKSIZE (sizeof (long))
  44.  
  45. #if LONG_MAX == 2147483647L
  46. #define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
  47. #else
  48. #if LONG_MAX == 9223372036854775807L
  49. /* Nonzero if X (a long int) contains a NULL byte. */
  50. #define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
  51. #else
  52. #error long int is not a 32bit or 64bit type.
  53. #endif
  54. #endif
  55.  
  56. /* DETECTCHAR returns nonzero if (long)X contains the byte used
  57.    to fill (long)MASK. */
  58. #define DETECTCHAR(X,MASK) (DETECTNULL(X ^ MASK))
  59.  
  60. char *
  61. _DEFUN (strchr, (s1, i),
  62.         _CONST char *s1 _AND
  63.         int i)
  64. {
  65.   _CONST unsigned char *s = (_CONST unsigned char *)s1;
  66.   unsigned char c = i;
  67.  
  68. #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__)
  69.   unsigned long mask,j;
  70.   unsigned long *aligned_addr;
  71.  
  72.   /* Special case for finding 0.  */
  73.   if (!c)
  74.     {
  75.       while (UNALIGNED (s))
  76.         {
  77.           if (!*s)
  78.             return (char *) s;
  79.           s++;
  80.         }
  81.       /* Operate a word at a time.  */
  82.       aligned_addr = (unsigned long *) s;
  83.       while (!DETECTNULL (*aligned_addr))
  84.         aligned_addr++;
  85.       /* Found the end of string.  */
  86.       s = (const unsigned char *) aligned_addr;
  87.       while (*s)
  88.         s++;
  89.       return (char *) s;
  90.     }
  91.  
  92.   /* All other bytes.  Align the pointer, then search a long at a time.  */
  93.   while (UNALIGNED (s))
  94.     {
  95.       if (!*s)
  96.         return NULL;
  97.       if (*s == c)
  98.         return (char *) s;
  99.       s++;
  100.     }
  101.  
  102.   mask = c;
  103.   for (j = 8; j < LBLOCKSIZE * 8; j <<= 1)
  104.     mask = (mask << j) | mask;
  105.  
  106.   aligned_addr = (unsigned long *) s;
  107.   while (!DETECTNULL (*aligned_addr) && !DETECTCHAR (*aligned_addr, mask))
  108.     aligned_addr++;
  109.  
  110.   /* The block of bytes currently pointed to by aligned_addr
  111.      contains either a null or the target char, or both.  We
  112.      catch it using the bytewise search.  */
  113.  
  114.   s = (unsigned char *) aligned_addr;
  115.  
  116. #endif /* not PREFER_SIZE_OVER_SPEED */
  117.  
  118.   while (*s && *s != c)
  119.     s++;
  120.   if (*s == c)
  121.     return (char *)s;
  122.   return NULL;
  123. }
  124.