Line data Source code
1 : /* Locale-specific memory transformation
2 :
3 : Copyright (C) 2006 Free Software Foundation, Inc.
4 :
5 : This program is free software: you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as published by
7 : the Free Software Foundation, either version 3 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public License
16 : along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 :
18 : /* Written by Paul Eggert <eggert@cs.ucla.edu>. */
19 :
20 : #include <config.h>
21 :
22 : #include "memxfrm.h"
23 :
24 : #include <errno.h>
25 : #include <stdlib.h>
26 : #include <string.h>
27 :
28 : /* Store into DEST (of size DESTSIZE) the text in SRC (of size SRCSIZE)
29 : transformed so that the result of memcmp on two transformed texts
30 : (with ties going to the longer text) is the same as the result of
31 : memcoll on the two texts before their transformation. Perhaps
32 : temporarily modify the byte after SRC, but restore its original
33 : contents before returning.
34 :
35 : Return the size of the resulting text, or an indeterminate value if
36 : there is an error. Set errno to an error number if there is an
37 : error, and to zero otherwise. DEST contains an indeterminate value
38 : if there is an error or if the resulting size is greater than
39 : DESTSIZE. */
40 :
41 : size_t
42 0 : memxfrm (char *restrict dest, size_t destsize,
43 : char *restrict src, size_t srcsize)
44 : {
45 : #if HAVE_STRXFRM
46 :
47 0 : size_t di = 0;
48 0 : size_t si = 0;
49 0 : size_t result = 0;
50 :
51 0 : char ch = src[srcsize];
52 0 : src[srcsize] = '\0';
53 :
54 0 : while (si < srcsize)
55 : {
56 0 : size_t slen = strlen (src + si);
57 :
58 0 : size_t result0 = result;
59 0 : errno = 0;
60 0 : result += strxfrm (dest + di, src + si, destsize - di) + 1;
61 0 : if (errno != 0)
62 0 : break;
63 0 : if (result <= result0)
64 : {
65 0 : errno = ERANGE;
66 0 : break;
67 : }
68 :
69 0 : if (result == destsize + 1 && si + slen == srcsize)
70 : {
71 : /* The destination is exactly the right size, but strxfrm wants
72 : room for a trailing null. Work around the problem with a
73 : temporary buffer. */
74 0 : size_t bufsize = destsize - di + 1;
75 : char stackbuf[4000];
76 0 : char *buf = stackbuf;
77 0 : if (sizeof stackbuf < bufsize)
78 : {
79 0 : buf = malloc (bufsize);
80 0 : if (! buf)
81 0 : break;
82 : }
83 0 : strxfrm (buf, src + si, bufsize);
84 0 : memcpy (dest + di, buf, destsize - di);
85 0 : if (sizeof stackbuf < bufsize)
86 0 : free (buf);
87 0 : errno = 0;
88 : }
89 :
90 0 : di = (result < destsize ? result : destsize);
91 0 : si += slen + 1;
92 : }
93 :
94 0 : src[srcsize] = ch;
95 0 : return result - (si != srcsize);
96 :
97 : #else
98 :
99 : if (srcsize < destsize)
100 : memcpy (dest, src, srcsize);
101 : errno = 0;
102 : return srcsize;
103 :
104 : #endif
105 : }
|