blob: a0cff8fe88eaabab7c55299ef0e610e2493bc009 [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
2 * linux/lib/string.c
3 *
4 * Copyright (C) 1991, 1992 Linus Torvalds
5 */
6
7/*
8 * stupid library routines.. The optimized versions should generally be found
9 * as inline code in <asm-xx/string.h>
10 *
11 * These are buggy as well..
12 *
13 * * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
14 * - Added strsep() which will replace strtok() soon (because strsep() is
15 * reentrant and should be faster). Use only strsep() in new code, please.
16 */
17
Simon Glass43e571d2018-11-06 15:21:38 -070018#include <config.h>
wdenkc6097192002-11-03 00:24:07 +000019#include <linux/types.h>
20#include <linux/string.h>
21#include <linux/ctype.h>
22#include <malloc.h>
23
wdenkc6097192002-11-03 00:24:07 +000024
wdenkc6097192002-11-03 00:24:07 +000025/**
Simon Glass459af692012-12-05 14:46:35 +000026 * strncasecmp - Case insensitive, length-limited string comparison
wdenkc6097192002-11-03 00:24:07 +000027 * @s1: One string
28 * @s2: The other string
29 * @len: the maximum number of characters to compare
30 */
Simon Glass459af692012-12-05 14:46:35 +000031int strncasecmp(const char *s1, const char *s2, size_t len)
wdenkc6097192002-11-03 00:24:07 +000032{
33 /* Yes, Virginia, it had better be unsigned */
34 unsigned char c1, c2;
35
36 c1 = 0; c2 = 0;
37 if (len) {
38 do {
39 c1 = *s1; c2 = *s2;
40 s1++; s2++;
41 if (!c1)
42 break;
43 if (!c2)
44 break;
45 if (c1 == c2)
46 continue;
47 c1 = tolower(c1);
48 c2 = tolower(c2);
49 if (c1 != c2)
50 break;
51 } while (--len);
52 }
53 return (int)c1 - (int)c2;
54}
Simon Glass459af692012-12-05 14:46:35 +000055
56/**
57 * strcasecmp - Case insensitive string comparison
58 * @s1: One string
59 * @s2: The other string
60 */
61int strcasecmp(const char *s1, const char *s2)
62{
63 return strncasecmp(s1, s2, -1U);
64}
wdenkc6097192002-11-03 00:24:07 +000065
66char * ___strtok;
67
68#ifndef __HAVE_ARCH_STRCPY
69/**
70 * strcpy - Copy a %NUL terminated string
71 * @dest: Where to copy the string to
72 * @src: Where to copy the string from
73 */
74char * strcpy(char * dest,const char *src)
75{
76 char *tmp = dest;
77
78 while ((*dest++ = *src++) != '\0')
79 /* nothing */;
80 return tmp;
81}
82#endif
83
84#ifndef __HAVE_ARCH_STRNCPY
85/**
86 * strncpy - Copy a length-limited, %NUL-terminated string
87 * @dest: Where to copy the string to
88 * @src: Where to copy the string from
89 * @count: The maximum number of bytes to copy
90 *
91 * Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
92 * However, the result is not %NUL-terminated if the source exceeds
93 * @count bytes.
94 */
95char * strncpy(char * dest,const char *src,size_t count)
96{
97 char *tmp = dest;
98
99 while (count-- && (*dest++ = *src++) != '\0')
100 /* nothing */;
101
102 return tmp;
103}
104#endif
105
Masahiro Yamada0588ce12014-11-20 21:20:32 +0900106#ifndef __HAVE_ARCH_STRLCPY
107/**
108 * strlcpy - Copy a C-string into a sized buffer
109 * @dest: Where to copy the string to
110 * @src: Where to copy the string from
111 * @size: size of destination buffer
112 *
113 * Compatible with *BSD: the result is always a valid
114 * NUL-terminated string that fits in the buffer (unless,
115 * of course, the buffer size is zero). It does not pad
116 * out the result like strncpy() does.
Sean Anderson2f512572021-03-11 00:15:41 -0500117 *
118 * Return: the number of bytes copied
Masahiro Yamada0588ce12014-11-20 21:20:32 +0900119 */
120size_t strlcpy(char *dest, const char *src, size_t size)
121{
Masahiro Yamada0588ce12014-11-20 21:20:32 +0900122 if (size) {
Sean Anderson2f512572021-03-11 00:15:41 -0500123 size_t srclen = strlen(src);
124 size_t len = (srclen >= size) ? size - 1 : srclen;
125
Masahiro Yamada0588ce12014-11-20 21:20:32 +0900126 memcpy(dest, src, len);
127 dest[len] = '\0';
Sean Anderson2f512572021-03-11 00:15:41 -0500128 return len + 1;
Masahiro Yamada0588ce12014-11-20 21:20:32 +0900129 }
Sean Anderson2f512572021-03-11 00:15:41 -0500130
131 return 0;
Masahiro Yamada0588ce12014-11-20 21:20:32 +0900132}
133#endif
134
wdenkc6097192002-11-03 00:24:07 +0000135#ifndef __HAVE_ARCH_STRCAT
136/**
137 * strcat - Append one %NUL-terminated string to another
138 * @dest: The string to be appended to
139 * @src: The string to append to it
140 */
141char * strcat(char * dest, const char * src)
142{
143 char *tmp = dest;
144
145 while (*dest)
146 dest++;
147 while ((*dest++ = *src++) != '\0')
148 ;
149
150 return tmp;
151}
152#endif
153
154#ifndef __HAVE_ARCH_STRNCAT
155/**
156 * strncat - Append a length-limited, %NUL-terminated string to another
157 * @dest: The string to be appended to
158 * @src: The string to append to it
159 * @count: The maximum numbers of bytes to copy
160 *
161 * Note that in contrast to strncpy, strncat ensures the result is
162 * terminated.
163 */
164char * strncat(char *dest, const char *src, size_t count)
165{
166 char *tmp = dest;
167
168 if (count) {
169 while (*dest)
170 dest++;
171 while ((*dest++ = *src++)) {
172 if (--count == 0) {
173 *dest = '\0';
174 break;
175 }
176 }
177 }
178
179 return tmp;
180}
181#endif
182
Sean Anderson9297a7f2021-03-11 00:15:42 -0500183#ifndef __HAVE_ARCH_STRLCAT
184/**
185 * strlcat - Append a length-limited, %NUL-terminated string to another
186 * @dest: The string to be appended to
187 * @src: The string to append to it
188 * @size: The size of @dest
189 *
190 * Compatible with *BSD: the result is always a valid NUL-terminated string that
191 * fits in the buffer (unless, of course, the buffer size is zero). It does not
192 * write past @size like strncat() does.
193 */
194size_t strlcat(char *dest, const char *src, size_t size)
195{
196 size_t len = strnlen(dest, size);
197
198 return len + strlcpy(dest + len, src, size - len);
199}
200#endif
201
wdenkc6097192002-11-03 00:24:07 +0000202#ifndef __HAVE_ARCH_STRCMP
203/**
204 * strcmp - Compare two strings
205 * @cs: One string
206 * @ct: Another string
207 */
208int strcmp(const char * cs,const char * ct)
209{
210 register signed char __res;
211
212 while (1) {
213 if ((__res = *cs - *ct++) != 0 || !*cs++)
214 break;
215 }
216
217 return __res;
218}
219#endif
220
221#ifndef __HAVE_ARCH_STRNCMP
222/**
223 * strncmp - Compare two length-limited strings
224 * @cs: One string
225 * @ct: Another string
226 * @count: The maximum number of bytes to compare
227 */
228int strncmp(const char * cs,const char * ct,size_t count)
229{
230 register signed char __res = 0;
231
232 while (count) {
233 if ((__res = *cs - *ct++) != 0 || !*cs++)
234 break;
235 count--;
236 }
237
238 return __res;
239}
240#endif
241
242#ifndef __HAVE_ARCH_STRCHR
243/**
244 * strchr - Find the first occurrence of a character in a string
245 * @s: The string to be searched
246 * @c: The character to search for
247 */
248char * strchr(const char * s, int c)
249{
250 for(; *s != (char) c; ++s)
251 if (*s == '\0')
252 return NULL;
253 return (char *) s;
254}
255#endif
256
Simon Glass4355d422017-05-18 20:09:28 -0600257const char *strchrnul(const char *s, int c)
258{
259 for (; *s != (char)c; ++s)
260 if (*s == '\0')
261 break;
262 return s;
263}
264
wdenkc6097192002-11-03 00:24:07 +0000265#ifndef __HAVE_ARCH_STRRCHR
266/**
267 * strrchr - Find the last occurrence of a character in a string
268 * @s: The string to be searched
269 * @c: The character to search for
270 */
271char * strrchr(const char * s, int c)
272{
273 const char *p = s + strlen(s);
274 do {
wdenk57b2d802003-06-27 21:31:46 +0000275 if (*p == (char)c)
276 return (char *)p;
wdenkc6097192002-11-03 00:24:07 +0000277 } while (--p >= s);
278 return NULL;
279}
280#endif
281
282#ifndef __HAVE_ARCH_STRLEN
283/**
284 * strlen - Find the length of a string
285 * @s: The string to be sized
286 */
287size_t strlen(const char * s)
288{
289 const char *sc;
290
291 for (sc = s; *sc != '\0'; ++sc)
292 /* nothing */;
293 return sc - s;
294}
295#endif
296
297#ifndef __HAVE_ARCH_STRNLEN
298/**
299 * strnlen - Find the length of a length-limited string
300 * @s: The string to be sized
301 * @count: The maximum number of bytes to search
302 */
303size_t strnlen(const char * s, size_t count)
304{
305 const char *sc;
306
307 for (sc = s; count-- && *sc != '\0'; ++sc)
308 /* nothing */;
309 return sc - s;
310}
311#endif
312
Simon Glass0d0e3c92017-05-18 20:09:29 -0600313#ifndef __HAVE_ARCH_STRCSPN
314/**
315 * strcspn - Calculate the length of the initial substring of @s which does
316 * not contain letters in @reject
317 * @s: The string to be searched
318 * @reject: The string to avoid
319 */
320size_t strcspn(const char *s, const char *reject)
321{
322 const char *p;
323 const char *r;
324 size_t count = 0;
325
326 for (p = s; *p != '\0'; ++p) {
327 for (r = reject; *r != '\0'; ++r) {
328 if (*p == *r)
329 return count;
330 }
331 ++count;
332 }
333 return count;
334}
335#endif
336
wdenkc6097192002-11-03 00:24:07 +0000337#ifndef __HAVE_ARCH_STRDUP
338char * strdup(const char *s)
339{
340 char *new;
341
342 if ((s == NULL) ||
343 ((new = malloc (strlen(s) + 1)) == NULL) ) {
344 return NULL;
345 }
346
347 strcpy (new, s);
348 return new;
349}
wdenkc6097192002-11-03 00:24:07 +0000350
Thierry Redingf0561822019-04-15 11:32:14 +0200351char * strndup(const char *s, size_t n)
352{
353 size_t len;
354 char *new;
355
356 if (s == NULL)
357 return NULL;
358
359 len = strlen(s);
360
361 if (n < len)
362 len = n;
363
364 new = malloc(len + 1);
365 if (new == NULL)
366 return NULL;
367
368 strncpy(new, s, len);
369 new[len] = '\0';
370
371 return new;
372}
Simon Glass9e8f6d62020-02-03 07:36:00 -0700373#endif
Thierry Redingf0561822019-04-15 11:32:14 +0200374
wdenkc6097192002-11-03 00:24:07 +0000375#ifndef __HAVE_ARCH_STRSPN
376/**
377 * strspn - Calculate the length of the initial substring of @s which only
Wolfgang Denka1be4762008-05-20 16:00:29 +0200378 * contain letters in @accept
wdenkc6097192002-11-03 00:24:07 +0000379 * @s: The string to be searched
380 * @accept: The string to search for
381 */
382size_t strspn(const char *s, const char *accept)
383{
384 const char *p;
385 const char *a;
386 size_t count = 0;
387
388 for (p = s; *p != '\0'; ++p) {
389 for (a = accept; *a != '\0'; ++a) {
390 if (*p == *a)
391 break;
392 }
393 if (*a == '\0')
394 return count;
395 ++count;
396 }
397
398 return count;
399}
400#endif
401
402#ifndef __HAVE_ARCH_STRPBRK
403/**
404 * strpbrk - Find the first occurrence of a set of characters
405 * @cs: The string to be searched
406 * @ct: The characters to search for
407 */
408char * strpbrk(const char * cs,const char * ct)
409{
410 const char *sc1,*sc2;
411
412 for( sc1 = cs; *sc1 != '\0'; ++sc1) {
413 for( sc2 = ct; *sc2 != '\0'; ++sc2) {
414 if (*sc1 == *sc2)
415 return (char *) sc1;
416 }
417 }
418 return NULL;
419}
420#endif
421
422#ifndef __HAVE_ARCH_STRTOK
423/**
424 * strtok - Split a string into tokens
425 * @s: The string to be searched
426 * @ct: The characters to search for
427 *
428 * WARNING: strtok is deprecated, use strsep instead.
429 */
430char * strtok(char * s,const char * ct)
431{
432 char *sbegin, *send;
433
434 sbegin = s ? s : ___strtok;
435 if (!sbegin) {
436 return NULL;
437 }
438 sbegin += strspn(sbegin,ct);
439 if (*sbegin == '\0') {
440 ___strtok = NULL;
441 return( NULL );
442 }
443 send = strpbrk( sbegin, ct);
444 if (send && *send != '\0')
445 *send++ = '\0';
446 ___strtok = send;
447 return (sbegin);
448}
449#endif
450
451#ifndef __HAVE_ARCH_STRSEP
452/**
453 * strsep - Split a string into tokens
454 * @s: The string to be searched
455 * @ct: The characters to search for
456 *
457 * strsep() updates @s to point after the token, ready for the next call.
458 *
459 * It returns empty tokens, too, behaving exactly like the libc function
460 * of that name. In fact, it was stolen from glibc2 and de-fancy-fied.
461 * Same semantics, slimmer shape. ;)
462 */
463char * strsep(char **s, const char *ct)
464{
465 char *sbegin = *s, *end;
466
467 if (sbegin == NULL)
468 return NULL;
469
470 end = strpbrk(sbegin, ct);
471 if (end)
472 *end++ = '\0';
473 *s = end;
474
475 return sbegin;
476}
477#endif
478
wdenkacd9b102004-03-14 00:59:59 +0000479#ifndef __HAVE_ARCH_STRSWAB
480/**
481 * strswab - swap adjacent even and odd bytes in %NUL-terminated string
482 * s: address of the string
483 *
484 * returns the address of the swapped string or NULL on error. If
485 * string length is odd, last byte is untouched.
486 */
487char *strswab(const char *s)
488{
Wolfgang Denkc7ca7cf2005-09-25 16:15:17 +0200489 char *p, *q;
wdenkacd9b102004-03-14 00:59:59 +0000490
491 if ((NULL == s) || ('\0' == *s)) {
492 return (NULL);
493 }
494
Wolfgang Denkdf70a422005-10-04 23:38:07 +0200495 for (p=(char *)s, q=p+1; (*p != '\0') && (*q != '\0'); p+=2, q+=2) {
wdenkacd9b102004-03-14 00:59:59 +0000496 char tmp;
Wolfgang Denkc7ca7cf2005-09-25 16:15:17 +0200497
498 tmp = *p;
499 *p = *q;
500 *q = tmp;
wdenkacd9b102004-03-14 00:59:59 +0000501 }
502
503 return (char *) s;
504}
505#endif
506
wdenkc6097192002-11-03 00:24:07 +0000507#ifndef __HAVE_ARCH_MEMSET
508/**
509 * memset - Fill a region of memory with the given value
510 * @s: Pointer to the start of the area.
511 * @c: The byte to fill the area with
512 * @count: The size of the area.
513 *
514 * Do not use memset() to access IO space, use memset_io() instead.
515 */
516void * memset(void * s,int c,size_t count)
517{
Alessandro Rubinife1a2fb2009-10-10 11:51:16 +0200518 unsigned long *sl = (unsigned long *) s;
Alessandro Rubinife1a2fb2009-10-10 11:51:16 +0200519 char *s8;
Simon Glasse2f94ae2017-04-02 09:50:28 -0600520
521#if !CONFIG_IS_ENABLED(TINY_MEMSET)
522 unsigned long cl = 0;
Alessandro Rubinife1a2fb2009-10-10 11:51:16 +0200523 int i;
wdenkc6097192002-11-03 00:24:07 +0000524
Alessandro Rubinife1a2fb2009-10-10 11:51:16 +0200525 /* do it one word at a time (32 bits or 64 bits) while possible */
526 if ( ((ulong)s & (sizeof(*sl) - 1)) == 0) {
527 for (i = 0; i < sizeof(*sl); i++) {
528 cl <<= 8;
529 cl |= c & 0xff;
530 }
531 while (count >= sizeof(*sl)) {
532 *sl++ = cl;
533 count -= sizeof(*sl);
534 }
535 }
Simon Glasse2f94ae2017-04-02 09:50:28 -0600536#endif /* fill 8 bits at a time */
Alessandro Rubinife1a2fb2009-10-10 11:51:16 +0200537 s8 = (char *)sl;
wdenkc6097192002-11-03 00:24:07 +0000538 while (count--)
Alessandro Rubinife1a2fb2009-10-10 11:51:16 +0200539 *s8++ = c;
wdenkc6097192002-11-03 00:24:07 +0000540
541 return s;
542}
543#endif
544
wdenkc6097192002-11-03 00:24:07 +0000545#ifndef __HAVE_ARCH_MEMCPY
546/**
547 * memcpy - Copy one area of memory to another
548 * @dest: Where to copy to
549 * @src: Where to copy from
550 * @count: The size of the area.
551 *
552 * You should not use this function to access IO space, use memcpy_toio()
553 * or memcpy_fromio() instead.
554 */
Alessandro Rubinif881b542009-10-10 11:51:05 +0200555void * memcpy(void *dest, const void *src, size_t count)
wdenkc6097192002-11-03 00:24:07 +0000556{
Alessandro Rubinif881b542009-10-10 11:51:05 +0200557 unsigned long *dl = (unsigned long *)dest, *sl = (unsigned long *)src;
558 char *d8, *s8;
wdenkc6097192002-11-03 00:24:07 +0000559
Matthias Weisser5bf63482011-05-22 23:03:55 +0000560 if (src == dest)
561 return dest;
562
Alessandro Rubinif881b542009-10-10 11:51:05 +0200563 /* while all data is aligned (common case), copy a word at a time */
564 if ( (((ulong)dest | (ulong)src) & (sizeof(*dl) - 1)) == 0) {
565 while (count >= sizeof(*dl)) {
566 *dl++ = *sl++;
567 count -= sizeof(*dl);
568 }
569 }
570 /* copy the reset one byte at a time */
571 d8 = (char *)dl;
572 s8 = (char *)sl;
wdenkc6097192002-11-03 00:24:07 +0000573 while (count--)
Alessandro Rubinif881b542009-10-10 11:51:05 +0200574 *d8++ = *s8++;
wdenkc6097192002-11-03 00:24:07 +0000575
576 return dest;
577}
578#endif
579
580#ifndef __HAVE_ARCH_MEMMOVE
581/**
582 * memmove - Copy one area of memory to another
583 * @dest: Where to copy to
584 * @src: Where to copy from
585 * @count: The size of the area.
586 *
587 * Unlike memcpy(), memmove() copes with overlapping areas.
588 */
589void * memmove(void * dest,const void *src,size_t count)
590{
591 char *tmp, *s;
592
Patrick Delaunay26b66a32020-12-11 14:59:23 +0100593 if (dest <= src || (src + count) <= dest) {
594 /*
595 * Use the fast memcpy implementation (ARCH optimized or lib/string.c) when it is possible:
596 * - when dest is before src (assuming that memcpy is doing forward-copying)
597 * - when destination don't overlap the source buffer (src + count <= dest)
598 *
599 * WARNING: the first optimisation cause an issue, when __HAVE_ARCH_MEMCPY is defined,
600 * __HAVE_ARCH_MEMMOVE is not defined and if the memcpy ARCH-specific
601 * implementation is not doing a forward-copying.
602 *
603 * No issue today because memcpy is doing a forward-copying in lib/string.c and for ARM32
604 * architecture; no other arches use __HAVE_ARCH_MEMCPY without __HAVE_ARCH_MEMMOVE.
605 */
Simon Glass03f827e2017-04-05 16:23:31 -0600606 memcpy(dest, src, count);
607 } else {
wdenkc6097192002-11-03 00:24:07 +0000608 tmp = (char *) dest + count;
609 s = (char *) src + count;
610 while (count--)
611 *--tmp = *--s;
612 }
613
614 return dest;
615}
616#endif
617
618#ifndef __HAVE_ARCH_MEMCMP
619/**
620 * memcmp - Compare two areas of memory
621 * @cs: One area of memory
622 * @ct: Another area of memory
623 * @count: The size of the area.
624 */
625int memcmp(const void * cs,const void * ct,size_t count)
626{
627 const unsigned char *su1, *su2;
628 int res = 0;
629
630 for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
631 if ((res = *su1 - *su2) != 0)
632 break;
633 return res;
634}
635#endif
636
637#ifndef __HAVE_ARCH_MEMSCAN
638/**
639 * memscan - Find a character in an area of memory.
640 * @addr: The memory area
641 * @c: The byte to search for
642 * @size: The size of the area.
643 *
644 * returns the address of the first occurrence of @c, or 1 byte past
645 * the area if @c is not found
646 */
647void * memscan(void * addr, int c, size_t size)
648{
649 unsigned char * p = (unsigned char *) addr;
650
651 while (size) {
652 if (*p == c)
653 return (void *) p;
654 p++;
655 size--;
656 }
wdenk57b2d802003-06-27 21:31:46 +0000657 return (void *) p;
wdenkc6097192002-11-03 00:24:07 +0000658}
659#endif
660
661#ifndef __HAVE_ARCH_STRSTR
662/**
663 * strstr - Find the first substring in a %NUL terminated string
664 * @s1: The string to be searched
665 * @s2: The string to search for
666 */
667char * strstr(const char * s1,const char * s2)
668{
669 int l1, l2;
670
671 l2 = strlen(s2);
672 if (!l2)
673 return (char *) s1;
674 l1 = strlen(s1);
675 while (l1 >= l2) {
676 l1--;
677 if (!memcmp(s1,s2,l2))
678 return (char *) s1;
679 s1++;
680 }
681 return NULL;
682}
683#endif
684
685#ifndef __HAVE_ARCH_MEMCHR
686/**
687 * memchr - Find a character in an area of memory.
688 * @s: The memory area
689 * @c: The byte to search for
690 * @n: The size of the area.
691 *
692 * returns the address of the first occurrence of @c, or %NULL
693 * if @c is not found
694 */
695void *memchr(const void *s, int c, size_t n)
696{
697 const unsigned char *p = s;
698 while (n-- != 0) {
wdenk57b2d802003-06-27 21:31:46 +0000699 if ((unsigned char)c == *p++) {
wdenkc6097192002-11-03 00:24:07 +0000700 return (void *)(p-1);
701 }
702 }
703 return NULL;
704}
705
706#endif
Sergey Lapin3a38a552013-01-14 03:46:50 +0000707#ifndef __HAVE_ARCH_MEMCHR_INV
708static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes)
709{
710 while (bytes) {
711 if (*start != value)
712 return (void *)start;
713 start++;
714 bytes--;
715 }
716 return NULL;
717}
718/**
719 * memchr_inv - Find an unmatching character in an area of memory.
720 * @start: The memory area
721 * @c: Find a character other than c
722 * @bytes: The size of the area.
723 *
724 * returns the address of the first character other than @c, or %NULL
725 * if the whole buffer contains just @c.
726 */
727void *memchr_inv(const void *start, int c, size_t bytes)
728{
729 u8 value = c;
730 u64 value64;
731 unsigned int words, prefix;
732
733 if (bytes <= 16)
734 return check_bytes8(start, value, bytes);
735
736 value64 = value;
737 value64 |= value64 << 8;
738 value64 |= value64 << 16;
739 value64 |= value64 << 32;
740
741 prefix = (unsigned long)start % 8;
742 if (prefix) {
743 u8 *r;
744
745 prefix = 8 - prefix;
746 r = check_bytes8(start, value, prefix);
747 if (r)
748 return r;
749 start += prefix;
750 bytes -= prefix;
751 }
752
753 words = bytes / 8;
754
755 while (words) {
756 if (*(u64 *)start != value64)
757 return check_bytes8(start, value, 8);
758 start += 8;
759 words--;
760 }
761
762 return check_bytes8(start, value, bytes % 8);
763}
764#endif