1 /*
2 Copyright (c) 1994 Cygnus Support.
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms are permitted
6 provided that the above copyright notice and this paragraph are
7 duplicated in all such forms and that any documentation,
8 and/or other materials related to such
9 distribution and use acknowledge that the software was developed
10 at Cygnus Support, Inc.  Cygnus Support, Inc. may not be used to
11 endorse or promote products derived from this software without
12 specific prior written permission.
13 THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 /*
18 FUNCTION
19 	<<strlen>>---character string length
20 
21 INDEX
22 	strlen
23 
24 SYNOPSIS
25 	#include <string.h>
26 	size_t strlen(const char *<[str]>);
27 
28 DESCRIPTION
29 	The <<strlen>> function works out the length of the string
30 	starting at <<*<[str]>>> by counting chararacters until it
31 	reaches a <<NULL>> character.
32 
33 RETURNS
34 	<<strlen>> returns the character count.
35 
36 PORTABILITY
37 <<strlen>> is ANSI C.
38 
39 <<strlen>> requires no supporting OS subroutines.
40 
41 QUICKREF
42 	strlen ansi pure
43 */
44 
45 #include <_ansi.h>
46 #include <string.h>
47 #include <limits.h>
48 #include <stdint.h>
49 
50 #define LBLOCKSIZE   (sizeof (long))
51 #define UNALIGNED(X) ((uintptr_t)X & (LBLOCKSIZE - 1))
52 
53 #if LONG_MAX == 2147483647L
54 #define DETECTNULL(X) (((X) - 0x01010101) & ~(X) & 0x80808080)
55 #else
56 #if LONG_MAX == 9223372036854775807L
57 /* Nonzero if X (a long int) contains a NULL byte. */
58 #define DETECTNULL(X) (((X) - 0x0101010101010101) & ~(X) & 0x8080808080808080)
59 #else
60 #error long int is not a 32bit or 64bit type.
61 #endif
62 #endif
63 
64 #ifndef DETECTNULL
65 #error long int is not a 32bit or 64bit byte
66 #endif
67 
68 size_t
strlen(const char * str)69 strlen (const char *str)
70 {
71   const char *start = str;
72 
73 #if !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) && \
74     !defined(PICOLIBC_NO_OUT_OF_BOUNDS_READS)
75   unsigned long *aligned_addr;
76 
77   /* Align the pointer, so we can search a word at a time.  */
78   while (UNALIGNED (str))
79     {
80       if (!*str)
81 	return str - start;
82       str++;
83     }
84 
85   /* If the string is word-aligned, we can check for the presence of
86      a null in each word-sized block.  */
87   aligned_addr = (unsigned long *)str;
88   while (!DETECTNULL (*aligned_addr))
89     aligned_addr++;
90 
91   /* Once a null is detected, we check each byte in that block for a
92      precise position of the null.  */
93   str = (char *) aligned_addr;
94 
95 #endif /* not PREFER_SIZE_OVER_SPEED */
96 
97   while (*str)
98     str++;
99   return str - start;
100 }
101