1 | /*
|
---|
2 | * linux/lib/string.c
|
---|
3 | *
|
---|
4 | * Copyright (C) 1991, 1992 Linus Torvalds
|
---|
5 | */
|
---|
6 |
|
---|
7 | #include <string.h>
|
---|
8 | #include <types.h>
|
---|
9 | #include <asm/errno.h>
|
---|
10 |
|
---|
11 | #define REPEAT_BYTE(x) ((~0ul / 0xff) * (x))
|
---|
12 |
|
---|
13 | /*
|
---|
14 | * This is largely generic for little-endian machines, but the
|
---|
15 | * optimal byte mask counting is probably going to be something
|
---|
16 | * that is architecture-specific. If you have a reliably fast
|
---|
17 | * bit count instruction, that might be better than the multiply
|
---|
18 | * and shift, for example.
|
---|
19 | */
|
---|
20 | struct word_at_a_time {
|
---|
21 | const unsigned long one_bits, high_bits;
|
---|
22 | };
|
---|
23 |
|
---|
24 | /* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
|
---|
25 | static inline long count_masked_bytes(long mask)
|
---|
26 | {
|
---|
27 | /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */
|
---|
28 | long a = (0x0ff0001+mask) >> 23;
|
---|
29 | /* Fix the 1 for 00 case */
|
---|
30 | return a & mask;
|
---|
31 | }
|
---|
32 |
|
---|
33 | #define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
|
---|
34 |
|
---|
35 | /* Return nonzero if it has a zero */
|
---|
36 | static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
|
---|
37 | {
|
---|
38 | unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits;
|
---|
39 | *bits = mask;
|
---|
40 | return mask;
|
---|
41 | }
|
---|
42 |
|
---|
43 | static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
|
---|
44 | {
|
---|
45 | return bits;
|
---|
46 | }
|
---|
47 |
|
---|
48 | static inline unsigned long create_zero_mask(unsigned long bits)
|
---|
49 | {
|
---|
50 | bits = (bits - 1) & ~bits;
|
---|
51 | return bits >> 7;
|
---|
52 | }
|
---|
53 |
|
---|
54 | /* The mask we created is directly usable as a bytemask */
|
---|
55 | #define zero_bytemask(mask) (mask)
|
---|
56 |
|
---|
57 | static inline unsigned long find_zero(unsigned long mask)
|
---|
58 | {
|
---|
59 | return count_masked_bytes(mask);
|
---|
60 | }
|
---|
61 |
|
---|
62 | /**
|
---|
63 | * strscpy - Copy a C-string into a sized buffer
|
---|
64 | * @dest: Where to copy the string to
|
---|
65 | * @src: Where to copy the string from
|
---|
66 | * @count: Size of destination buffer
|
---|
67 | *
|
---|
68 | * Copy the string, or as much of it as fits, into the dest buffer.
|
---|
69 | * The routine returns the number of characters copied (not including
|
---|
70 | * the trailing NUL) or -E2BIG if the destination buffer wasn't big enough.
|
---|
71 | * The behavior is undefined if the string buffers overlap.
|
---|
72 | * The destination buffer is always NUL terminated, unless it's zero-sized.
|
---|
73 | *
|
---|
74 | * Preferred to strlcpy() since the API doesn't require reading memory
|
---|
75 | * from the src string beyond the specified "count" bytes, and since
|
---|
76 | * the return value is easier to error-check than strlcpy()'s.
|
---|
77 | * In addition, the implementation is robust to the string changing out
|
---|
78 | * from underneath it, unlike the current strlcpy() implementation.
|
---|
79 | *
|
---|
80 | * Preferred to strncpy() since it always returns a valid string, and
|
---|
81 | * doesn't unnecessarily force the tail of the destination buffer to be
|
---|
82 | * zeroed. If the zeroing is desired, it's likely cleaner to use strscpy()
|
---|
83 | * with an overflow test, then just memset() the tail of the dest buffer.
|
---|
84 | */
|
---|
85 | ssize_t strscpy(char *dest, const char *src, size_t count)
|
---|
86 | {
|
---|
87 | const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
|
---|
88 | size_t max = count;
|
---|
89 | long res = 0;
|
---|
90 |
|
---|
91 | if (count == 0)
|
---|
92 | return -E2BIG;
|
---|
93 |
|
---|
94 | /* If src or dest is unaligned, don't do word-at-a-time. */
|
---|
95 | if (((long) dest | (long) src) & (sizeof(long) - 1))
|
---|
96 | max = 0;
|
---|
97 |
|
---|
98 | while (max >= sizeof(unsigned long)) {
|
---|
99 | unsigned long c, data;
|
---|
100 |
|
---|
101 | c = *(unsigned long *)(src+res);
|
---|
102 | if (has_zero(c, &data, &constants)) {
|
---|
103 | data = prep_zero_mask(c, data, &constants);
|
---|
104 | data = create_zero_mask(data);
|
---|
105 | *(unsigned long *)(dest+res) = c & zero_bytemask(data);
|
---|
106 | return res + find_zero(data);
|
---|
107 | }
|
---|
108 | *(unsigned long *)(dest+res) = c;
|
---|
109 | res += sizeof(unsigned long);
|
---|
110 | count -= sizeof(unsigned long);
|
---|
111 | max -= sizeof(unsigned long);
|
---|
112 | }
|
---|
113 |
|
---|
114 | while (count) {
|
---|
115 | char c;
|
---|
116 |
|
---|
117 | c = src[res];
|
---|
118 | dest[res] = c;
|
---|
119 | if (!c)
|
---|
120 | return res;
|
---|
121 | res++;
|
---|
122 | count--;
|
---|
123 | }
|
---|
124 |
|
---|
125 | /* Hit buffer length without finding a NUL; force NUL-termination. */
|
---|
126 | if (res)
|
---|
127 | dest[res-1] = '\0';
|
---|
128 |
|
---|
129 | return -E2BIG;
|
---|
130 | }
|
---|