1/* stringlib: find/index implementation */ 2 3#ifndef STRINGLIB_FIND_H 4#define STRINGLIB_FIND_H 5 6#ifndef STRINGLIB_FASTSEARCH_H 7#error must include "stringlib/fastsearch.h" before including this module 8#endif 9 10Py_LOCAL_INLINE(Py_ssize_t) 11stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len, 12 const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, 13 Py_ssize_t offset) 14{ 15 Py_ssize_t pos; 16 17 if (str_len < 0) 18 return -1; 19 if (sub_len == 0) 20 return offset; 21 22 pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_SEARCH); 23 24 if (pos >= 0) 25 pos += offset; 26 27 return pos; 28} 29 30Py_LOCAL_INLINE(Py_ssize_t) 31stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len, 32 const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, 33 Py_ssize_t offset) 34{ 35 Py_ssize_t pos; 36 37 if (str_len < 0) 38 return -1; 39 if (sub_len == 0) 40 return str_len + offset; 41 42 pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_RSEARCH); 43 44 if (pos >= 0) 45 pos += offset; 46 47 return pos; 48} 49 50/* helper macro to fixup start/end slice values */ 51#define ADJUST_INDICES(start, end, len) \ 52 if (end > len) \ 53 end = len; \ 54 else if (end < 0) { \ 55 end += len; \ 56 if (end < 0) \ 57 end = 0; \ 58 } \ 59 if (start < 0) { \ 60 start += len; \ 61 if (start < 0) \ 62 start = 0; \ 63 } 64 65Py_LOCAL_INLINE(Py_ssize_t) 66stringlib_find_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len, 67 const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, 68 Py_ssize_t start, Py_ssize_t end) 69{ 70 ADJUST_INDICES(start, end, str_len); 71 return stringlib_find(str + start, end - start, sub, sub_len, start); 72} 73 74Py_LOCAL_INLINE(Py_ssize_t) 75stringlib_rfind_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len, 76 const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, 77 Py_ssize_t start, Py_ssize_t end) 78{ 79 ADJUST_INDICES(start, end, str_len); 80 return stringlib_rfind(str + start, end - start, sub, sub_len, start); 81} 82 83#ifdef STRINGLIB_WANT_CONTAINS_OBJ 84 85Py_LOCAL_INLINE(int) 86stringlib_contains_obj(PyObject* str, PyObject* sub) 87{ 88 return stringlib_find( 89 STRINGLIB_STR(str), STRINGLIB_LEN(str), 90 STRINGLIB_STR(sub), STRINGLIB_LEN(sub), 0 91 ) != -1; 92} 93 94#endif /* STRINGLIB_WANT_CONTAINS_OBJ */ 95 96/* 97This function is a helper for the "find" family (find, rfind, index, 98rindex) and for count, startswith and endswith, because they all have 99the same behaviour for the arguments. 100 101It does not touch the variables received until it knows everything 102is ok. 103*/ 104 105#define FORMAT_BUFFER_SIZE 50 106 107Py_LOCAL_INLINE(int) 108stringlib_parse_args_finds(const char * function_name, PyObject *args, 109 PyObject **subobj, 110 Py_ssize_t *start, Py_ssize_t *end) 111{ 112 PyObject *tmp_subobj; 113 Py_ssize_t tmp_start = 0; 114 Py_ssize_t tmp_end = PY_SSIZE_T_MAX; 115 PyObject *obj_start=Py_None, *obj_end=Py_None; 116 char format[FORMAT_BUFFER_SIZE] = "O|OO:"; 117 size_t len = strlen(format); 118 119 strncpy(format + len, function_name, FORMAT_BUFFER_SIZE - len - 1); 120 format[FORMAT_BUFFER_SIZE - 1] = '\0'; 121 122 if (!PyArg_ParseTuple(args, format, &tmp_subobj, &obj_start, &obj_end)) 123 return 0; 124 125 /* To support None in "start" and "end" arguments, meaning 126 the same as if they were not passed. 127 */ 128 if (obj_start != Py_None) 129 if (!_PyEval_SliceIndex(obj_start, &tmp_start)) 130 return 0; 131 if (obj_end != Py_None) 132 if (!_PyEval_SliceIndex(obj_end, &tmp_end)) 133 return 0; 134 135 *start = tmp_start; 136 *end = tmp_end; 137 *subobj = tmp_subobj; 138 return 1; 139} 140 141#undef FORMAT_BUFFER_SIZE 142 143#if STRINGLIB_IS_UNICODE 144 145/* 146Wraps stringlib_parse_args_finds() and additionally ensures that the 147first argument is a unicode object. 148 149Note that we receive a pointer to the pointer of the substring object, 150so when we create that object in this function we don't DECREF it, 151because it continues living in the caller functions (those functions, 152after finishing using the substring, must DECREF it). 153*/ 154 155Py_LOCAL_INLINE(int) 156stringlib_parse_args_finds_unicode(const char * function_name, PyObject *args, 157 PyUnicodeObject **substring, 158 Py_ssize_t *start, Py_ssize_t *end) 159{ 160 PyObject *tmp_substring; 161 162 if(stringlib_parse_args_finds(function_name, args, &tmp_substring, 163 start, end)) { 164 tmp_substring = PyUnicode_FromObject(tmp_substring); 165 if (!tmp_substring) 166 return 0; 167 *substring = (PyUnicodeObject *)tmp_substring; 168 return 1; 169 } 170 return 0; 171} 172 173#endif /* STRINGLIB_IS_UNICODE */ 174 175#endif /* STRINGLIB_FIND_H */ 176