Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * string.c
4 : : * string handling helpers
5 : : *
6 : : *
7 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
8 : : * Portions Copyright (c) 1994, Regents of the University of California
9 : : *
10 : : *
11 : : * IDENTIFICATION
12 : : * src/common/string.c
13 : : *
14 : : *-------------------------------------------------------------------------
15 : : */
16 : :
17 : :
18 : : #ifndef FRONTEND
19 : : #include "postgres.h"
20 : : #else
21 : : #include "postgres_fe.h"
22 : : #endif
23 : :
24 : : #include <limits.h>
25 : :
26 : : #include "common/string.h"
27 : :
28 : :
29 : : /*
30 : : * Returns whether the string `str' has the postfix `end'.
31 : : */
32 : : bool
4324 andres@anarazel.de 33 :CBC 20637 : pg_str_endswith(const char *str, const char *end)
34 : : {
35 : 20637 : size_t slen = strlen(str);
36 : 20637 : size_t elen = strlen(end);
37 : :
38 : : /* can't be a postfix if longer */
39 [ + + ]: 20637 : if (elen > slen)
40 : 2438 : return false;
41 : :
42 : : /* compare the end of the strings */
43 : 18199 : str += slen - elen;
44 : 18199 : return strcmp(str, end) == 0;
45 : : }
46 : :
47 : :
48 : : /*
49 : : * strtoint --- just like strtol, but returns int not long
50 : : *
51 : : * The result is clamped to INT_MIN..INT_MAX, not LONG_MIN..LONG_MAX,
52 : : * but otherwise this has the same behavior as strtol.
53 : : */
54 : : int
295 peter@eisentraut.org 55 : 209281 : strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base)
56 : : {
57 : : long val;
58 : :
3159 peter_e@gmx.net 59 : 209281 : val = strtol(str, endptr, base);
60 [ + + ]: 209281 : if (val != (int) val)
61 : : {
6 tgl@sss.pgh.pa.us 62 [ - + ]: 6 : val = (val < 0) ? INT_MIN : INT_MAX;
3159 peter_e@gmx.net 63 : 6 : errno = ERANGE;
64 : : }
65 : 209281 : return (int) val;
66 : : }
67 : :
68 : :
69 : : /*
70 : : * pg_clean_ascii -- Replace any non-ASCII chars with a "\xXX" string
71 : : *
72 : : * Makes a newly allocated copy of the string passed in, which must be
73 : : * '\0'-terminated. In the backend, additional alloc_flags may be provided and
74 : : * will be passed as-is to palloc_extended(); in the frontend, alloc_flags is
75 : : * ignored and the copy is malloc'd.
76 : : *
77 : : * This function exists specifically to deal with filtering out
78 : : * non-ASCII characters in a few places where the client can provide an almost
79 : : * arbitrary string (and it isn't checked to ensure it's a valid username or
80 : : * database name or similar) and we don't want to have control characters or other
81 : : * things ending up in the log file where server admins might end up with a
82 : : * messed up terminal when looking at them.
83 : : *
84 : : * In general, this function should NOT be used- instead, consider how to handle
85 : : * the string without needing to filter out the non-ASCII characters.
86 : : *
87 : : * Ultimately, we'd like to improve the situation to not require replacing all
88 : : * non-ASCII but perform more intelligent filtering which would allow UTF or
89 : : * similar, but it's unclear exactly what we should allow, so stick to ASCII only
90 : : * for now.
91 : : */
92 : : char *
1514 peter@eisentraut.org 93 : 37785 : pg_clean_ascii(const char *str, int alloc_flags)
94 : : {
95 : : size_t dstlen;
96 : : char *dst;
97 : : const char *p;
98 : 37785 : size_t i = 0;
99 : :
100 : : /* Worst case, each byte can become four bytes, plus a null terminator. */
101 : 37785 : dstlen = strlen(str) * 4 + 1;
102 : :
103 : : #ifdef FRONTEND
1514 peter@eisentraut.org 104 :UBC 0 : dst = malloc(dstlen);
105 : : #else
1514 peter@eisentraut.org 106 :CBC 37785 : dst = palloc_extended(dstlen, alloc_flags);
107 : : #endif
108 : :
109 [ - + ]: 37785 : if (!dst)
1514 peter@eisentraut.org 110 :UBC 0 : return NULL;
111 : :
2960 sfrost@snowman.net 112 [ + + ]:CBC 728605 : for (p = str; *p != '\0'; p++)
113 : : {
114 : :
115 : : /* Only allow clean ASCII chars in the string */
116 [ + + - + ]: 690820 : if (*p < 32 || *p > 126)
117 : : {
1514 peter@eisentraut.org 118 [ - + ]: 16 : Assert(i < (dstlen - 3));
119 : 16 : snprintf(&dst[i], dstlen - i, "\\x%02x", (unsigned char) *p);
120 : 16 : i += 4;
121 : : }
122 : : else
123 : : {
124 [ - + ]: 690804 : Assert(i < dstlen);
125 : 690804 : dst[i] = *p;
126 : 690804 : i++;
127 : : }
128 : : }
129 : :
130 [ - + ]: 37785 : Assert(i < dstlen);
131 : 37785 : dst[i] = '\0';
132 : 37785 : return dst;
133 : : }
134 : :
135 : :
136 : : /*
137 : : * pg_is_ascii -- Check if string is made only of ASCII characters
138 : : */
139 : : bool
2145 michael@paquier.xyz 140 : 97404 : pg_is_ascii(const char *str)
141 : : {
142 [ + + ]: 468514 : while (*str)
143 : : {
144 [ + + ]: 371112 : if (IS_HIGHBIT_SET(*str))
145 : 2 : return false;
146 : 371110 : str++;
147 : : }
148 : 97402 : return true;
149 : : }
150 : :
151 : :
152 : : /*
153 : : * pg_strip_crlf -- Remove any trailing newline and carriage return
154 : : *
155 : : * Removes any trailing newline and carriage return characters (\r on
156 : : * Windows) in the input string, zero-terminating it.
157 : : *
158 : : * The passed in string must be zero-terminated. This function returns
159 : : * the new length of the string.
160 : : */
161 : : int
2645 162 : 228509 : pg_strip_crlf(char *str)
163 : : {
164 : 228509 : int len = strlen(str);
165 : :
166 [ + + + + ]: 457018 : while (len > 0 && (str[len - 1] == '\n' ||
167 [ - + ]: 220806 : str[len - 1] == '\r'))
168 : 228509 : str[--len] = '\0';
169 : :
170 : 228509 : return len;
171 : : }
|