Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | /* * Copyright (c) 2010, Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ // char * strstr(const char *s1, const char *s2); // // If s2 is empty, s1 is returned. // If s2 does not occur in s1, NULL is returned. // Otherwise, a pointer to the first character of the first occurrence of s2 // in s1 is returned. // // We use a hand-tuned version of the naive quadratic time algorithm; we have // experimented with more sophisticated algorithms, however they have been // found wanting. The increased startup cost combines with the frequency of // calls to strstr with small strings to swamp the gains from improved // asymptotic complexity. #define CLEAR_FRAME_AND_RETURN \ pop {r4,r5,r6,r7,pc} .text .syntax unified .code 32 .globl _strstr .align 2 _strstr: push {r4,r5,r6,r7,lr} add r7, sp, #12 // Throughout this function, I will refer to the string in which we are // searching as "string" and the string for which we are searching as "word". // Using s1 and s2 is too confusing. Thus, we want to return a pointer to // the first occurrence of "word" in "string". mov r5, r1 mov r4, r0 // We begin by calling strlen to find the length of "word". We also handle // two special cases here: we early-out if word is an empty string (length // zero), and we call strchr if word is only a single character. mov r0, r5 bl _strlen subs r0, r0, #1 ble L_tinyWord // Load the first character of word ldrb ip, [r5] L_lookForFirstCharacter: // Load the first character from string. If it is equal to the first // character of word, or is a zero byte, then we do more processing; // otherwise, proceed to the next character. ldrb r1, [r4],#1 cmp r1, ip tstne r1, r1 bne L_lookForFirstCharacter // The byte that we loaded from string either matched the first character // of word, or was a zero byte. If it was a zero byte, then we have reached // the end of string without finding a match of word. Otherwise, we fall // into a loop that checks additional characters to see if we have a match. tst r1, r1 beq L_noMatch // We have found a match for the first character of word; we want to read // characters from this point on to see if we have a match for the entirety // of word. We want to be sure to preserve the state of the outside loop, // however: // // r0: length(word) - 1 // r4: pointer to the next character in string // r5: pointer to the first character in word // ip: first character in word // // The registers r1-r3, r6, and lr are available as scratch. We set them up // for the inner loop as follows: // // r1: remaining length to be matched // r2: pointer to next character of string to match // r3: pointer to next character of word to match // r6: current character from string // lr: current character from word mov r2, r4 add r3, r5, #1 mov r1, r0 L_checkMatch: // Load the next byte from both the candidate match and from word. If they // are not equal, jump back to the outer loop. If they are equal, decrement // the length, and continue the inner loop if we have not yet found a // complete match. // // We don't need to worry about looking for null bytes in this loop; we know // that we won't load a null byte from word, because we computed it's length // earlier, and are using that as a termination condition. If we hit a null // byte in string, the comparison will fail (because the corresponding byte // in word is non-null), and we will return to the outer loop, where the // null byte will be detected and handled properly. ldrb r6, [r2],#1 ldrb lr, [r3],#1 cmp r6, lr bne L_lookForFirstCharacter subs r1, r1, #1 bne L_checkMatch // We have exhausted the length of word without finding a mismatched character // so we have found a match. Return a pointer to the beginning of the match // string. (This pointer is r4 - 1 because r4 was auto-incremented when we // loaded the first character). sub r0, r4, #1 CLEAR_FRAME_AND_RETURN L_noMatch: // No match was found; return NULL. mov r0, #0 CLEAR_FRAME_AND_RETURN L_tinyWord: // "word" is either empty or a single character. If it is a single character, // translate strstr into a call to the (more efficient) strchr. blt L_emptyWord ldrb r1, [r5] mov r0, r4 bl _strchr CLEAR_FRAME_AND_RETURN L_emptyWord: // "word" is empty; return "string". movlt r0, r4 CLEAR_FRAME_AND_RETURN |