--- /dev/null
+/* stringlib: find/index implementation */\r
+\r
+#ifndef STRINGLIB_FIND_H\r
+#define STRINGLIB_FIND_H\r
+\r
+#ifndef STRINGLIB_FASTSEARCH_H\r
+#error must include "stringlib/fastsearch.h" before including this module\r
+#endif\r
+\r
+Py_LOCAL_INLINE(Py_ssize_t)\r
+stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len,\r
+ const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,\r
+ Py_ssize_t offset)\r
+{\r
+ Py_ssize_t pos;\r
+\r
+ if (str_len < 0)\r
+ return -1;\r
+ if (sub_len == 0)\r
+ return offset;\r
+\r
+ pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_SEARCH);\r
+\r
+ if (pos >= 0)\r
+ pos += offset;\r
+\r
+ return pos;\r
+}\r
+\r
+Py_LOCAL_INLINE(Py_ssize_t)\r
+stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len,\r
+ const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,\r
+ Py_ssize_t offset)\r
+{\r
+ Py_ssize_t pos;\r
+\r
+ if (str_len < 0)\r
+ return -1;\r
+ if (sub_len == 0)\r
+ return str_len + offset;\r
+\r
+ pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_RSEARCH);\r
+\r
+ if (pos >= 0)\r
+ pos += offset;\r
+\r
+ return pos;\r
+}\r
+\r
+/* helper macro to fixup start/end slice values */\r
+#define ADJUST_INDICES(start, end, len) \\r
+ if (end > len) \\r
+ end = len; \\r
+ else if (end < 0) { \\r
+ end += len; \\r
+ if (end < 0) \\r
+ end = 0; \\r
+ } \\r
+ if (start < 0) { \\r
+ start += len; \\r
+ if (start < 0) \\r
+ start = 0; \\r
+ }\r
+\r
+Py_LOCAL_INLINE(Py_ssize_t)\r
+stringlib_find_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len,\r
+ const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,\r
+ Py_ssize_t start, Py_ssize_t end)\r
+{\r
+ ADJUST_INDICES(start, end, str_len);\r
+ return stringlib_find(str + start, end - start, sub, sub_len, start);\r
+}\r
+\r
+Py_LOCAL_INLINE(Py_ssize_t)\r
+stringlib_rfind_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len,\r
+ const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,\r
+ Py_ssize_t start, Py_ssize_t end)\r
+{\r
+ ADJUST_INDICES(start, end, str_len);\r
+ return stringlib_rfind(str + start, end - start, sub, sub_len, start);\r
+}\r
+\r
+#ifdef STRINGLIB_WANT_CONTAINS_OBJ\r
+\r
+Py_LOCAL_INLINE(int)\r
+stringlib_contains_obj(PyObject* str, PyObject* sub)\r
+{\r
+ return stringlib_find(\r
+ STRINGLIB_STR(str), STRINGLIB_LEN(str),\r
+ STRINGLIB_STR(sub), STRINGLIB_LEN(sub), 0\r
+ ) != -1;\r
+}\r
+\r
+#endif /* STRINGLIB_WANT_CONTAINS_OBJ */\r
+\r
+/*\r
+This function is a helper for the "find" family (find, rfind, index,\r
+rindex) and for count, startswith and endswith, because they all have\r
+the same behaviour for the arguments.\r
+\r
+It does not touch the variables received until it knows everything \r
+is ok.\r
+*/\r
+\r
+#define FORMAT_BUFFER_SIZE 50\r
+\r
+Py_LOCAL_INLINE(int)\r
+stringlib_parse_args_finds(const char * function_name, PyObject *args,\r
+ PyObject **subobj,\r
+ Py_ssize_t *start, Py_ssize_t *end)\r
+{\r
+ PyObject *tmp_subobj;\r
+ Py_ssize_t tmp_start = 0;\r
+ Py_ssize_t tmp_end = PY_SSIZE_T_MAX;\r
+ PyObject *obj_start=Py_None, *obj_end=Py_None;\r
+ char format[FORMAT_BUFFER_SIZE] = "O|OO:";\r
+ size_t len = strlen(format);\r
+\r
+ strncpy(format + len, function_name, FORMAT_BUFFER_SIZE - len - 1);\r
+ format[FORMAT_BUFFER_SIZE - 1] = '\0';\r
+\r
+ if (!PyArg_ParseTuple(args, format, &tmp_subobj, &obj_start, &obj_end))\r
+ return 0;\r
+\r
+ /* To support None in "start" and "end" arguments, meaning\r
+ the same as if they were not passed.\r
+ */\r
+ if (obj_start != Py_None)\r
+ if (!_PyEval_SliceIndex(obj_start, &tmp_start))\r
+ return 0;\r
+ if (obj_end != Py_None)\r
+ if (!_PyEval_SliceIndex(obj_end, &tmp_end))\r
+ return 0;\r
+\r
+ *start = tmp_start;\r
+ *end = tmp_end;\r
+ *subobj = tmp_subobj;\r
+ return 1;\r
+}\r
+\r
+#undef FORMAT_BUFFER_SIZE\r
+\r
+#if STRINGLIB_IS_UNICODE\r
+\r
+/*\r
+Wraps stringlib_parse_args_finds() and additionally ensures that the\r
+first argument is a unicode object.\r
+\r
+Note that we receive a pointer to the pointer of the substring object,\r
+so when we create that object in this function we don't DECREF it,\r
+because it continues living in the caller functions (those functions, \r
+after finishing using the substring, must DECREF it).\r
+*/\r
+\r
+Py_LOCAL_INLINE(int)\r
+stringlib_parse_args_finds_unicode(const char * function_name, PyObject *args,\r
+ PyUnicodeObject **substring,\r
+ Py_ssize_t *start, Py_ssize_t *end)\r
+{\r
+ PyObject *tmp_substring;\r
+\r
+ if(stringlib_parse_args_finds(function_name, args, &tmp_substring,\r
+ start, end)) {\r
+ tmp_substring = PyUnicode_FromObject(tmp_substring);\r
+ if (!tmp_substring)\r
+ return 0;\r
+ *substring = (PyUnicodeObject *)tmp_substring;\r
+ return 1;\r
+ }\r
+ return 0;\r
+}\r
+\r
+#endif /* STRINGLIB_IS_UNICODE */\r
+\r
+#endif /* STRINGLIB_FIND_H */\r