Re: str_str() for those who need it 16:13:11 -0600"

From: d. hall (dhall@APK.NET)
Date: 01/15/98


// thus on Thu, 15 Jan 1998 16:13:11 -0600, Akuma/Chris virtually wrote:

> ok, in the way of str_cmp, str_dup, strn_cmp, et al.
> I have created a str_str() function that works correctly.

> Begin Code (put it in utils.c)-------
// str_str: a case-insensitive version of strstr()
// scans arg1 for the first occurrence of the substring arg2
// returns a pointer to the point in arg1 where arg2 begins.
// If arg2 does not occur in arg1, str_str returns NULL.
// Written by Akuma the Raging Coder
> char *str_str(char *arg1, char *arg2)
> {
> register int iptr;
> register int len1;
> register int len2;

>  if (!arg1 && !arg2)
>   { log("NULL arg1 and arg2 passed to %s().", __FUNCTION__); return NULL; }
>  else if (!arg1)
>    { log("NULL arg1 passed to %s().", __FUNCTION__); return NULL; }
>  else if (!arg2)
>    { log("NULL arg2 passed to %s().", __FUNCTION__); return NULL; }

>      len1 = str_len(arg2);
>      len2 = str_len(arg1);

>  // if str_len(arg2) is greater than str_len(arg1),
>  // then arg2 can't be substring of arg1
>  if (len1 > len2)
>     return NULL;
>  else if (len1 == len2) {
>       if (!str_cmp(arg1, arg2))
>          return (arg1);
>       else return NULL;
>       }
>  for (iptr = 0; iptr <= len2 - len1; iptr++) {
>      if (LOWER(*arg2) == LOWER(*(arg1+iptr)) &&
>          is_abbrev(arg2, (arg1 + iptr)))
>         return (arg1+iptr);
>      }
>  // Obviously we reached the end, and nothing was found.
>  return NULL;
> }
> -----End Code

A couple of issues here, by using str_len to get length of arg2 and arg1
for the initial check, you are traversing the two strings, and then by
doing a str_cmp you're partially traversing it again, and THEN with
is_abbrev you're partially traversing again.  Only in the best case
scenario (i.e. it just isn't there), you end up with the shortest execution
time.  With the following NULL checks, you can avoid repeated traversals,
also if you look in glibc2, you'll see a nice implementation by van den
Berg.

d.

/*
 * I hacked the following, it may contain missing sanity
 * checking since I wrote it in vi instead of emacs
 */
char *str_str (const char *haystack, const char *needle)
{
   register const char *h, *n;
   const char *hm;

   if (!haystack || !needle)
      return NULL;

   n = needle;
   for (h = haystack; *h; h++) {
      if (*h == *n) {
         hm = h;                /* set mark start of substring search */

         while (*h && *n) {
            if (LOWER(*h) != LOWER(*n)) /* substring does not match */
               break;
            h++; n++;
         }
         if (*n) {              /* needle not terminated? start over */
            n = needle;         /* reset needle */
            h = hm;             /* reset haystack */
         } else                 /* needle found, return start of substring */
            return (char *) hm;
      }
   }
   return NULL;                 /* nothing found */
}

int main ()
{
   char *p;

   p = str_str ("hello world", "world");
   printf ("%s\n", p ? p : "NULL");

   p = str_str ("ab", "a");
   printf ("%s\n", p ? p : "NULL");

   p = str_str ("hello", "ab");
   printf ("%s\n", p ? p : "NULL");

   p = str_str ("ab", "world");
   printf ("%s\n", p ? p : "NULL");

   p = str_str ("word world world-wonder", "world-wonder");
   printf ("%s\n", p ? p : "NULL");

   return 1;
}


     +------------------------------------------------------------+
     | Ensure that you have read the CircleMUD Mailing List FAQ:  |
     | http://democracy.queensu.ca/~fletcher/Circle/list-faq.html |
     +------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 12/15/00 PST