blob: ce615dcb8a4e580317f227f1434ac21acfcc134e [file] [log] [blame]
Fredrik Lundh58b5e842006-05-26 19:24:53 +00001/* 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
Fredrik Lundhc2d29c52006-05-27 14:58:20 +000010Py_LOCAL_INLINE(Py_ssize_t)
Fredrik Lundh58b5e842006-05-26 19:24:53 +000011stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
Fredrik Lundhe6e43c82006-05-26 19:48:07 +000012 const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
13 Py_ssize_t offset)
Fredrik Lundh58b5e842006-05-26 19:24:53 +000014{
Fredrik Lundhe6e43c82006-05-26 19:48:07 +000015 Py_ssize_t pos;
Fredrik Lundh58b5e842006-05-26 19:24:53 +000016
Amaury Forgeot d'Arcfc5ea392008-09-26 22:34:08 +000017 if (str_len < 0)
18 return -1;
19 if (sub_len == 0)
Fredrik Lundhe6e43c82006-05-26 19:48:07 +000020 return offset;
21
Antoine Pitrou64672132010-01-13 07:55:48 +000022 pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_SEARCH);
Fredrik Lundhe6e43c82006-05-26 19:48:07 +000023
24 if (pos >= 0)
25 pos += offset;
26
27 return pos;
Fredrik Lundh58b5e842006-05-26 19:24:53 +000028}
29
Fredrik Lundhc2d29c52006-05-27 14:58:20 +000030Py_LOCAL_INLINE(Py_ssize_t)
Fredrik Lundh58b5e842006-05-26 19:24:53 +000031stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len,
Fredrik Lundhe6e43c82006-05-26 19:48:07 +000032 const STRINGLIB_CHAR* sub, Py_ssize_t sub_len,
33 Py_ssize_t offset)
Fredrik Lundh58b5e842006-05-26 19:24:53 +000034{
Antoine Pitrou5b7139a2010-01-02 21:12:58 +000035 Py_ssize_t pos;
36
37 if (str_len < 0)
38 return -1;
39 if (sub_len == 0)
40 return str_len + offset;
41
Antoine Pitrou64672132010-01-13 07:55:48 +000042 pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_RSEARCH);
Antoine Pitrou5b7139a2010-01-02 21:12:58 +000043
44 if (pos >= 0)
45 pos += offset;
46
47 return pos;
Fredrik Lundh58b5e842006-05-26 19:24:53 +000048}
49
Antoine Pitrou64672132010-01-13 07:55:48 +000050/* 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
Fredrik Lundhc2d29c52006-05-27 14:58:20 +000065Py_LOCAL_INLINE(Py_ssize_t)
Fredrik Lundh60d8b182006-05-27 15:20:22 +000066stringlib_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)
Fredrik Lundh2d23d5b2006-05-27 10:05:10 +000069{
Antoine Pitrou64672132010-01-13 07:55:48 +000070 ADJUST_INDICES(start, end, str_len);
Antoine Pitrou5b7139a2010-01-02 21:12:58 +000071 return stringlib_find(str + start, end - start, sub, sub_len, start);
Fredrik Lundh2d23d5b2006-05-27 10:05:10 +000072}
73
Fredrik Lundh60d8b182006-05-27 15:20:22 +000074Py_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{
Antoine Pitrou64672132010-01-13 07:55:48 +000079 ADJUST_INDICES(start, end, str_len);
Fredrik Lundh60d8b182006-05-27 15:20:22 +000080 return stringlib_rfind(str + start, end - start, sub, sub_len, start);
81}
82
Antoine Pitrou64672132010-01-13 07:55:48 +000083#ifdef STRINGLIB_WANT_CONTAINS_OBJ
Fredrik Lundh60d8b182006-05-27 15:20:22 +000084
Fredrik Lundhc2d29c52006-05-27 14:58:20 +000085Py_LOCAL_INLINE(int)
Fredrik Lundh2d23d5b2006-05-27 10:05:10 +000086stringlib_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
Antoine Pitrou64672132010-01-13 07:55:48 +000094#endif /* STRINGLIB_WANT_CONTAINS_OBJ */
Fredrik Lundh2d23d5b2006-05-27 10:05:10 +000095
Facundo Batista57d56692007-11-16 18:04:14 +000096/*
97This function is a helper for the "find" family (find, rfind, index,
Jesus Cea44e81682011-04-20 16:39:15 +020098rindex) and for count, startswith and endswith, because they all have
99the same behaviour for the arguments.
Facundo Batista57d56692007-11-16 18:04:14 +0000100
101It does not touch the variables received until it knows everything
102is ok.
Facundo Batista57d56692007-11-16 18:04:14 +0000103*/
104
Jesus Cea44e81682011-04-20 16:39:15 +0200105#define FORMAT_BUFFER_SIZE 50
106
Facundo Batista292a0692007-11-16 18:41:24 +0000107Py_LOCAL_INLINE(int)
Jesus Cea44e81682011-04-20 16:39:15 +0200108stringlib_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;
Facundo Batista57d56692007-11-16 18:04:14 +0000113 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;
Jesus Cea44e81682011-04-20 16:39:15 +0200116 char format[FORMAT_BUFFER_SIZE] = "O|OO:";
117 size_t len = strlen(format);
Facundo Batista57d56692007-11-16 18:04:14 +0000118
Jesus Cea44e81682011-04-20 16:39:15 +0200119 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))
Facundo Batista57d56692007-11-16 18:04:14 +0000123 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
Facundo Batista57d56692007-11-16 18:04:14 +0000135 *start = tmp_start;
136 *end = tmp_end;
Jesus Cea44e81682011-04-20 16:39:15 +0200137 *subobj = tmp_subobj;
Facundo Batista57d56692007-11-16 18:04:14 +0000138 return 1;
139}
140
Jesus Cea44e81682011-04-20 16:39:15 +0200141#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
Antoine Pitrou64672132010-01-13 07:55:48 +0000173#endif /* STRINGLIB_IS_UNICODE */
Facundo Batista57d56692007-11-16 18:04:14 +0000174
Fredrik Lundh60d8b182006-05-27 15:20:22 +0000175#endif /* STRINGLIB_FIND_H */