xref: /unit/src/nxt_string.c (revision 354:8fc82db3530b)
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) NGINX, Inc.
5  */
6 
7 #include <nxt_main.h>
8 
9 
10 nxt_str_t *
11 nxt_str_alloc(nxt_mp_t *mp, size_t length)
12 {
13     nxt_str_t  *s;
14 
15     /* The string start is allocated aligned to be close to nxt_str_t. */
16     s = nxt_mp_get(mp, sizeof(nxt_str_t) + length);
17 
18     if (nxt_fast_path(s != NULL)) {
19         s->length = length;
20         s->start = nxt_pointer_to(s, sizeof(nxt_str_t));
21     }
22 
23     return s;
24 }
25 
26 
27 /*
28  * nxt_str_dup() creates a new string with a copy of a source string.
29  * If length of the source string is zero, then the new string anyway
30  * gets a pointer somewhere in mem_pool.
31  */
32 
33 nxt_str_t *
34 nxt_str_dup(nxt_mp_t *mp, nxt_str_t *dst, const nxt_str_t *src)
35 {
36     u_char  *p;
37 
38     if (dst == NULL) {
39         /* The string start is allocated aligned to be close to nxt_str_t. */
40         dst = nxt_mp_get(mp, sizeof(nxt_str_t) + src->length);
41         if (nxt_slow_path(dst == NULL)) {
42             return NULL;
43         }
44 
45         p = (u_char *) dst;
46         p += sizeof(nxt_str_t);
47         dst->start = p;
48 
49     } else {
50         dst->start = nxt_mp_nget(mp, src->length);
51         if (nxt_slow_path(dst->start == NULL)) {
52             return NULL;
53         }
54     }
55 
56     nxt_memcpy(dst->start, src->start, src->length);
57     dst->length = src->length;
58 
59     return dst;
60 }
61 
62 
63 /*
64  * nxt_str_cstrz() creates a C style zero-terminated copy of a source
65  * nxt_str_t.  The function is intended to create strings suitable
66  * for libc and kernel interfaces so result is pointer to char instead
67  * of u_char to minimize casts.
68  */
69 
70 char *
71 nxt_str_cstrz(nxt_mp_t *mp, const nxt_str_t *src)
72 {
73     char  *p, *dst;
74 
75     dst = nxt_mp_alloc(mp, src->length + 1);
76 
77     if (nxt_fast_path(dst != NULL)) {
78         p = nxt_cpymem(dst, src->start, src->length);
79         *p = '\0';
80     }
81 
82     return dst;
83 }
84 
85 
86 void
87 nxt_memcpy_lowcase(u_char *dst, const u_char *src, size_t length)
88 {
89     u_char  c;
90 
91     while (length != 0) {
92         c = *src++;
93         *dst++ = nxt_lowcase(c);
94         length--;
95     }
96 }
97 
98 
99 u_char *
100 nxt_cpystrn(u_char *dst, const u_char *src, size_t length)
101 {
102     if (length == 0) {
103         return dst;
104     }
105 
106     while (--length != 0) {
107         *dst = *src;
108 
109         if (*dst == '\0') {
110             return dst;
111         }
112 
113         dst++;
114         src++;
115     }
116 
117     *dst = '\0';
118 
119     return dst;
120 }
121 
122 
123 nxt_int_t
124 nxt_strcasecmp(const u_char *s1, const u_char *s2)
125 {
126     u_char     c1, c2;
127     nxt_int_t  n;
128 
129     for ( ;; ) {
130         c1 = *s1++;
131         c2 = *s2++;
132 
133         c1 = nxt_lowcase(c1);
134         c2 = nxt_lowcase(c2);
135 
136         n = c1 - c2;
137 
138         if (n != 0) {
139             return n;
140         }
141 
142         if (c1 == 0) {
143             return 0;
144         }
145     }
146 }
147 
148 
149 nxt_int_t
150 nxt_strncasecmp(const u_char *s1, const u_char *s2, size_t length)
151 {
152     u_char     c1, c2;
153     nxt_int_t  n;
154 
155     while (length-- != 0) {
156         c1 = *s1++;
157         c2 = *s2++;
158 
159         c1 = nxt_lowcase(c1);
160         c2 = nxt_lowcase(c2);
161 
162         n = c1 - c2;
163 
164         if (n != 0) {
165             return n;
166         }
167 
168         if (c1 == 0) {
169             return 0;
170         }
171     }
172 
173     return 0;
174 }
175 
176 
177 nxt_int_t
178 nxt_memcasecmp(const u_char *s1, const u_char *s2, size_t length)
179 {
180     u_char     c1, c2;
181     nxt_int_t  n;
182 
183     while (length-- != 0) {
184         c1 = *s1++;
185         c2 = *s2++;
186 
187         c1 = nxt_lowcase(c1);
188         c2 = nxt_lowcase(c2);
189 
190         n = c1 - c2;
191 
192         if (n != 0) {
193             return n;
194         }
195     }
196 
197     return 0;
198 }
199 
200 
201 /*
202  * nxt_memstrn() is intended for search of static substring "ss"
203  * with known length "length" in string "s" limited by parameter "end".
204  * Zeros are ignored in both strings.
205  */
206 
207 u_char *
208 nxt_memstrn(const u_char *s, const u_char *end, const char *ss, size_t length)
209 {
210     u_char  c1, c2, *s2;
211 
212     s2 = (u_char *) ss;
213     c2 = *s2++;
214     length--;
215 
216     while (s < end) {
217         c1 = *s++;
218 
219         if (c1 == c2) {
220 
221             if (s + length > end) {
222                 return NULL;
223             }
224 
225             if (nxt_memcmp(s, s2, length) == 0) {
226                 return (u_char *) s - 1;
227             }
228         }
229     }
230 
231     return NULL;
232 }
233 
234 
235 /*
236  * nxt_strcasestrn() is intended for caseless search of static substring
237  * "ss" with known length "length" in string "s" limited by parameter "end".
238  * Zeros are ignored in both strings.
239  */
240 
241 u_char *
242 nxt_memcasestrn(const u_char *s, const u_char *end, const char *ss,
243     size_t length)
244 {
245     u_char  c1, c2, *s2;
246 
247     s2 = (u_char *) ss;
248     c2 = *s2++;
249     c2 = nxt_lowcase(c2);
250     length--;
251 
252     while (s < end) {
253         c1 = *s++;
254         c1 = nxt_lowcase(c1);
255 
256         if (c1 == c2) {
257 
258             if (s + length > end) {
259                 return NULL;
260             }
261 
262             if (nxt_memcasecmp(s, s2, length) == 0) {
263                 return (u_char *) s - 1;
264             }
265         }
266     }
267 
268     return NULL;
269 }
270 
271 
272 /*
273  * nxt_rstrstrn() is intended to search for static substring "ss"
274  * with known length "length" in string "s" limited by parameter "end"
275  * in reverse order.  Zeros are ignored in both strings.
276  */
277 
278 u_char *
279 nxt_rmemstrn(const u_char *s, const u_char *end, const char *ss, size_t length)
280 {
281     u_char        c1, c2;
282     const u_char  *s1, *s2;
283 
284     s1 = end - length;
285     s2 = (u_char *) ss;
286     c2 = *s2++;
287     length--;
288 
289     while (s < s1) {
290         c1 = *s1;
291 
292         if (c1 == c2) {
293             if (nxt_memcmp(s1 + 1, s2, length) == 0) {
294                 return (u_char *) s1;
295             }
296         }
297 
298         s1--;
299     }
300 
301     return NULL;
302 }
303 
304 
305 size_t
306 nxt_str_strip(u_char *start, u_char *end)
307 {
308     u_char  *p;
309 
310     for (p = end - 1; p >= start; p--) {
311         if (*p != NXT_CR && *p != NXT_LF) {
312             break;
313         }
314     }
315 
316     return (p + 1) - start;
317 }
318 
319 
320 nxt_int_t
321 nxt_strverscmp(const u_char *s1, const u_char *s2)
322 {
323     u_char     c1, c2;
324     nxt_int_t  diff;
325 
326     enum {
327         st_str = 0,
328         st_num,
329         st_zero,
330         st_frac,
331     } state;
332 
333     state = st_str;
334 
335     for ( ;; ) {
336         c1 = *s1++;
337         c2 = *s2++;
338 
339         diff = c1 - c2;
340 
341         if (diff != 0) {
342             break;
343         }
344 
345         if (c1 == '\0') {
346             return 0;
347         }
348 
349         if (!nxt_isdigit(c1)) {
350             state = st_str;
351             continue;
352         }
353 
354         if (state == st_str) {
355             state = (c1 != '0') ? st_num : st_zero;
356             continue;
357         }
358 
359         if (state == st_zero && c1 != '0') {
360             state = st_frac;
361             continue;
362         }
363     }
364 
365     switch (state) {
366 
367     case st_str:
368 
369         if ((u_char) (c1 - '1') > 8 || (u_char) (c2 - '1') > 8) {
370             return diff;
371         }
372 
373         c1 = *s1++;
374         c2 = *s2++;
375 
376         /* Fall through. */
377 
378     case st_num:
379 
380         while (nxt_isdigit(c1) && nxt_isdigit(c2)) {
381             c1 = *s1++;
382             c2 = *s2++;
383         }
384 
385         if (nxt_isdigit(c1)) {
386             return 1;
387         }
388 
389         if (nxt_isdigit(c2)) {
390             return -1;
391         }
392 
393         return diff;
394 
395     case st_zero:
396 
397         if (c1 == '0' || c2 == '\0') {
398             return -1;
399         }
400 
401         if (c2 == '0' || c1 == '\0') {
402             return 1;
403         }
404 
405         /* Fall through. */
406 
407     case st_frac:
408         return diff;
409     }
410 
411     nxt_unreachable();
412 }
413 
414 
415 nxt_bool_t
416 nxt_strvers_match(u_char *version, u_char *prefix, size_t length)
417 {
418     u_char  next, last;
419 
420     if (nxt_strncmp(version, prefix, length) == 0) {
421 
422         next = version[length];
423 
424         if (next == '\0') {
425             return 1;
426         }
427 
428         last = version[length - 1];
429 
430         if (nxt_isdigit(last) != nxt_isdigit(next)) {
431             /* This is a version part boundary. */
432             return 1;
433         }
434     }
435 
436     return 0;
437 }
438