powerpc: Fix ifuncmain6pie failure with GCC 4.9
[platform/upstream/glibc.git] / string / str-two-way.h
index aab627a..f32df4a 100644 (file)
@@ -1,5 +1,5 @@
 /* Byte-wise substring search, using the Two-Way algorithm.
-   Copyright (C) 2008-2012 Free Software Foundation, Inc.
+   Copyright (C) 2008-2015 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written by Eric Blake <ebb9@byu.net>, 2008.
 
@@ -19,7 +19,7 @@
 
 /* Before including this file, you need to include <string.h> (and
    <config.h> before that, if not part of libc), and define:
-     RESULT_TYPE             A macro that expands to the return type.
+     RETURN_TYPE             A macro that expands to the return type.
      AVAILABLE(h, h_l, j, n_l)
                             A macro that returns nonzero if there are
                             at least N_L bytes left starting at H[J].
                             The argument is an 'unsigned char'; the result
                             must be an 'unsigned char' as well.
 
-  This file undefines the macros documented above, and defines
+  Other macros you may optionally define:
+     RET0_IF_0(a)            Documented below at default definition.
+     CHECK_EOL               Same.
+
+  This file undefines the macros listed above, and defines
   LONG_NEEDLE_THRESHOLD.
 */
 
 # define CMP_FUNC memcmp
 #endif
 
-#ifndef AVAILABLE1
-# define AVAILABLE1(h, h_l, j, n_l) AVAILABLE (h, h_l, j, n_l)
-#endif
-#ifndef AVAILABLE2
-# define AVAILABLE2(h, h_l, j, n_l) (1)
+/* Check for end-of-line in strstr and strcasestr routines.
+   We piggy-back matching procedure for detecting EOL where possible,
+   and use AVAILABLE macro otherwise.  */
+#ifndef CHECK_EOL
+# define CHECK_EOL (0)
 #endif
+
+/* Return NULL if argument is '\0'.  */
 #ifndef RET0_IF_0
 # define RET0_IF_0(a) /* nothing */
 #endif
@@ -240,17 +246,24 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
       j = 0;
       while (AVAILABLE (haystack, haystack_len, j, needle_len))
        {
+         const unsigned char *pneedle;
+         const unsigned char *phaystack;
+
          /* Scan for matches in right half.  */
          i = MAX (suffix, memory);
-         while (i < needle_len && (CANON_ELEMENT (needle[i])
-                                   == CANON_ELEMENT (haystack[i + j])))
+         pneedle = &needle[i];
+         phaystack = &haystack[i + j];
+         while (i < needle_len && (CANON_ELEMENT (*pneedle++)
+                                   == CANON_ELEMENT (*phaystack++)))
            ++i;
          if (needle_len <= i)
            {
              /* Scan for matches in left half.  */
              i = suffix - 1;
-             while (memory < i + 1 && (CANON_ELEMENT (needle[i])
-                                       == CANON_ELEMENT (haystack[i + j])))
+             pneedle = &needle[i];
+             phaystack = &haystack[i + j];
+             while (memory < i + 1 && (CANON_ELEMENT (*pneedle--)
+                                       == CANON_ELEMENT (*phaystack--)))
                --i;
              if (i + 1 < memory + 1)
                return (RETURN_TYPE) (haystack + j);
@@ -268,34 +281,57 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
     }
   else
     {
+      const unsigned char *phaystack = &haystack[suffix];
       /* The comparison always starts from needle[suffix], so cache it
         and use an optimized first-character loop.  */
       unsigned char needle_suffix = CANON_ELEMENT (needle[suffix]);
 
+#if CHECK_EOL
+      /* We start matching from the SUFFIX'th element, so make sure we
+        don't hit '\0' before that.  */
+      if (haystack_len < suffix + 1
+         && !AVAILABLE (haystack, haystack_len, 0, suffix + 1))
+       return NULL;
+#endif
+
       /* The two halves of needle are distinct; no extra memory is
         required, and any mismatch results in a maximal shift.  */
       period = MAX (suffix, needle_len - suffix) + 1;
       j = 0;
-      while (AVAILABLE1 (haystack, haystack_len, j, needle_len))
+      while (1
+#if !CHECK_EOL
+            && AVAILABLE (haystack, haystack_len, j, needle_len)
+#endif
+            )
        {
          unsigned char haystack_char;
+         const unsigned char *pneedle;
 
          /* TODO: The first-character loop can be sped up by adapting
             longword-at-a-time implementation of memchr/strchr.  */
          if (needle_suffix
-             != (haystack_char = CANON_ELEMENT (haystack[suffix + j])))
+             != (haystack_char = CANON_ELEMENT (*phaystack++)))
            {
              RET0_IF_0 (haystack_char);
+#if !CHECK_EOL
              ++j;
+#endif
              continue;
            }
 
+#if CHECK_EOL
+         /* Calculate J if it wasn't kept up-to-date in the first-character
+            loop.  */
+         j = phaystack - &haystack[suffix] - 1;
+#endif
+
          /* Scan for matches in right half.  */
          i = suffix + 1;
+         pneedle = &needle[i];
          while (i < needle_len)
            {
-             if (CANON_ELEMENT (needle[i])
-                 != (haystack_char = CANON_ELEMENT (haystack[i + j])))
+             if (CANON_ELEMENT (*pneedle++)
+                 != (haystack_char = CANON_ELEMENT (*phaystack++)))
                {
                  RET0_IF_0 (haystack_char);
                  break;
@@ -306,10 +342,12 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
            {
              /* Scan for matches in left half.  */
              i = suffix - 1;
+             pneedle = &needle[i];
+             phaystack = &haystack[i + j];
              while (i != SIZE_MAX)
                {
-                 if (CANON_ELEMENT (needle[i])
-                     != (haystack_char = CANON_ELEMENT (haystack[i + j])))
+                 if (CANON_ELEMENT (*pneedle--)
+                     != (haystack_char = CANON_ELEMENT (*phaystack--)))
                    {
                      RET0_IF_0 (haystack_char);
                      break;
@@ -323,8 +361,12 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
          else
            j += i - suffix + 1;
 
-         if (!AVAILABLE2 (haystack, haystack_len, j, needle_len))
+#if CHECK_EOL
+         if (!AVAILABLE (haystack, haystack_len, j, needle_len))
            break;
+#endif
+
+         phaystack = &haystack[suffix + j];
        }
     }
  ret0: __attribute__ ((unused))
@@ -379,6 +421,9 @@ two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
       j = 0;
       while (AVAILABLE (haystack, haystack_len, j, needle_len))
        {
+         const unsigned char *pneedle;
+         const unsigned char *phaystack;
+
          /* Check the last byte first; if it does not match, then
             shift to the next possible match location.  */
          shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])];
@@ -398,15 +443,19 @@ two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
          /* Scan for matches in right half.  The last byte has
             already been matched, by virtue of the shift table.  */
          i = MAX (suffix, memory);
-         while (i < needle_len - 1 && (CANON_ELEMENT (needle[i])
-                                       == CANON_ELEMENT (haystack[i + j])))
+         pneedle = &needle[i];
+         phaystack = &haystack[i + j];
+         while (i < needle_len - 1 && (CANON_ELEMENT (*pneedle++)
+                                       == CANON_ELEMENT (*phaystack++)))
            ++i;
          if (needle_len - 1 <= i)
            {
              /* Scan for matches in left half.  */
              i = suffix - 1;
-             while (memory < i + 1 && (CANON_ELEMENT (needle[i])
-                                       == CANON_ELEMENT (haystack[i + j])))
+             pneedle = &needle[i];
+             phaystack = &haystack[i + j];
+             while (memory < i + 1 && (CANON_ELEMENT (*pneedle--)
+                                       == CANON_ELEMENT (*phaystack--)))
                --i;
              if (i + 1 < memory + 1)
                return (RETURN_TYPE) (haystack + j);
@@ -431,6 +480,9 @@ two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
       j = 0;
       while (AVAILABLE (haystack, haystack_len, j, needle_len))
        {
+         const unsigned char *pneedle;
+         const unsigned char *phaystack;
+
          /* Check the last byte first; if it does not match, then
             shift to the next possible match location.  */
          shift = shift_table[CANON_ELEMENT (haystack[j + needle_len - 1])];
@@ -442,15 +494,19 @@ two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
          /* Scan for matches in right half.  The last byte has
             already been matched, by virtue of the shift table.  */
          i = suffix;
-         while (i < needle_len - 1 && (CANON_ELEMENT (needle[i])
-                                       == CANON_ELEMENT (haystack[i + j])))
+         pneedle = &needle[i];
+         phaystack = &haystack[i + j];
+         while (i < needle_len - 1 && (CANON_ELEMENT (*pneedle++)
+                                       == CANON_ELEMENT (*phaystack++)))
            ++i;
          if (needle_len - 1 <= i)
            {
              /* Scan for matches in left half.  */
              i = suffix - 1;
-             while (i != SIZE_MAX && (CANON_ELEMENT (needle[i])
-                                      == CANON_ELEMENT (haystack[i + j])))
+             pneedle = &needle[i];
+             phaystack = &haystack[i + j];
+             while (i != SIZE_MAX && (CANON_ELEMENT (*pneedle--)
+                                      == CANON_ELEMENT (*phaystack--)))
                --i;
              if (i == SIZE_MAX)
                return (RETURN_TYPE) (haystack + j);
@@ -464,9 +520,8 @@ two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
 }
 
 #undef AVAILABLE
-#undef AVAILABLE1
-#undef AVAILABLE2
 #undef CANON_ELEMENT
 #undef CMP_FUNC
 #undef RET0_IF_0
 #undef RETURN_TYPE
+#undef CHECK_EOL