/src/postgres/src/common/string.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*------------------------------------------------------------------------- |
2 | | * |
3 | | * string.c |
4 | | * string handling helpers |
5 | | * |
6 | | * |
7 | | * Portions Copyright (c) 1996-2025, 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 "common/string.h" |
25 | | |
26 | | |
27 | | /* |
28 | | * Returns whether the string `str' has the postfix `end'. |
29 | | */ |
30 | | bool |
31 | | pg_str_endswith(const char *str, const char *end) |
32 | 0 | { |
33 | 0 | size_t slen = strlen(str); |
34 | 0 | size_t elen = strlen(end); |
35 | | |
36 | | /* can't be a postfix if longer */ |
37 | 0 | if (elen > slen) |
38 | 0 | return false; |
39 | | |
40 | | /* compare the end of the strings */ |
41 | 0 | str += slen - elen; |
42 | 0 | return strcmp(str, end) == 0; |
43 | 0 | } |
44 | | |
45 | | |
46 | | /* |
47 | | * strtoint --- just like strtol, but returns int not long |
48 | | */ |
49 | | int |
50 | | strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base) |
51 | 0 | { |
52 | 0 | long val; |
53 | |
|
54 | 0 | val = strtol(str, endptr, base); |
55 | 0 | if (val != (int) val) |
56 | 0 | errno = ERANGE; |
57 | 0 | return (int) val; |
58 | 0 | } |
59 | | |
60 | | |
61 | | /* |
62 | | * pg_clean_ascii -- Replace any non-ASCII chars with a "\xXX" string |
63 | | * |
64 | | * Makes a newly allocated copy of the string passed in, which must be |
65 | | * '\0'-terminated. In the backend, additional alloc_flags may be provided and |
66 | | * will be passed as-is to palloc_extended(); in the frontend, alloc_flags is |
67 | | * ignored and the copy is malloc'd. |
68 | | * |
69 | | * This function exists specifically to deal with filtering out |
70 | | * non-ASCII characters in a few places where the client can provide an almost |
71 | | * arbitrary string (and it isn't checked to ensure it's a valid username or |
72 | | * database name or similar) and we don't want to have control characters or other |
73 | | * things ending up in the log file where server admins might end up with a |
74 | | * messed up terminal when looking at them. |
75 | | * |
76 | | * In general, this function should NOT be used- instead, consider how to handle |
77 | | * the string without needing to filter out the non-ASCII characters. |
78 | | * |
79 | | * Ultimately, we'd like to improve the situation to not require replacing all |
80 | | * non-ASCII but perform more intelligent filtering which would allow UTF or |
81 | | * similar, but it's unclear exactly what we should allow, so stick to ASCII only |
82 | | * for now. |
83 | | */ |
84 | | char * |
85 | | pg_clean_ascii(const char *str, int alloc_flags) |
86 | 4 | { |
87 | 4 | size_t dstlen; |
88 | 4 | char *dst; |
89 | 4 | const char *p; |
90 | 4 | size_t i = 0; |
91 | | |
92 | | /* Worst case, each byte can become four bytes, plus a null terminator. */ |
93 | 4 | dstlen = strlen(str) * 4 + 1; |
94 | | |
95 | | #ifdef FRONTEND |
96 | | dst = malloc(dstlen); |
97 | | #else |
98 | 4 | dst = palloc_extended(dstlen, alloc_flags); |
99 | 4 | #endif |
100 | | |
101 | 4 | if (!dst) |
102 | 0 | return NULL; |
103 | | |
104 | 4 | for (p = str; *p != '\0'; p++) |
105 | 0 | { |
106 | | |
107 | | /* Only allow clean ASCII chars in the string */ |
108 | 0 | if (*p < 32 || *p > 126) |
109 | 0 | { |
110 | 0 | Assert(i < (dstlen - 3)); |
111 | 0 | snprintf(&dst[i], dstlen - i, "\\x%02x", (unsigned char) *p); |
112 | 0 | i += 4; |
113 | 0 | } |
114 | 0 | else |
115 | 0 | { |
116 | 0 | Assert(i < dstlen); |
117 | 0 | dst[i] = *p; |
118 | 0 | i++; |
119 | 0 | } |
120 | 0 | } |
121 | | |
122 | 4 | Assert(i < dstlen); |
123 | 4 | dst[i] = '\0'; |
124 | 4 | return dst; |
125 | 4 | } |
126 | | |
127 | | |
128 | | /* |
129 | | * pg_is_ascii -- Check if string is made only of ASCII characters |
130 | | */ |
131 | | bool |
132 | | pg_is_ascii(const char *str) |
133 | 6 | { |
134 | 12 | while (*str) |
135 | 6 | { |
136 | 6 | if (IS_HIGHBIT_SET(*str)) |
137 | 0 | return false; |
138 | 6 | str++; |
139 | 6 | } |
140 | 6 | return true; |
141 | 6 | } |
142 | | |
143 | | |
144 | | /* |
145 | | * pg_strip_crlf -- Remove any trailing newline and carriage return |
146 | | * |
147 | | * Removes any trailing newline and carriage return characters (\r on |
148 | | * Windows) in the input string, zero-terminating it. |
149 | | * |
150 | | * The passed in string must be zero-terminated. This function returns |
151 | | * the new length of the string. |
152 | | */ |
153 | | int |
154 | | pg_strip_crlf(char *str) |
155 | 0 | { |
156 | 0 | int len = strlen(str); |
157 | |
|
158 | 0 | while (len > 0 && (str[len - 1] == '\n' || |
159 | 0 | str[len - 1] == '\r')) |
160 | 0 | str[--len] = '\0'; |
161 | |
|
162 | 0 | return len; |
163 | 0 | } |