source: GPL/branches/uniaud32-next/lib32/strscpy.c@ 715

Last change on this file since 715 was 615, checked in by Paul Smedley, 5 years ago

Add source for uniaud32 based on code from linux kernel 5.4.86

File size: 3.8 KB
Line 
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 */
20struct word_at_a_time {
21 const unsigned long one_bits, high_bits;
22};
23
24/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */
25static 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 */
36static 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
43static 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
48static 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
57static 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 */
85ssize_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}
Note: See TracBrowser for help on using the repository browser.