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 "common/string.h"
25 :
26 :
27 : /*
28 : * Returns whether the string `str' has the postfix `end'.
29 : */
30 : bool
31 16344 : pg_str_endswith(const char *str, const char *end)
32 : {
33 16344 : size_t slen = strlen(str);
34 16344 : size_t elen = strlen(end);
35 :
36 : /* can't be a postfix if longer */
37 16344 : if (elen > slen)
38 166 : return false;
39 :
40 : /* compare the end of the strings */
41 16178 : str += slen - elen;
42 16178 : return strcmp(str, end) == 0;
43 : }
44 :
45 :
46 : /*
47 : * strtoint --- just like strtol, but returns int not long
48 : */
49 : int
50 454415 : strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base)
51 : {
52 : long val;
53 :
54 454415 : val = strtol(str, endptr, base);
55 454415 : if (val != (int) val)
56 662 : errno = ERANGE;
57 454415 : return (int) val;
58 : }
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 33417 : pg_clean_ascii(const char *str, int alloc_flags)
86 : {
87 : size_t dstlen;
88 : char *dst;
89 : const char *p;
90 33417 : size_t i = 0;
91 :
92 : /* Worst case, each byte can become four bytes, plus a null terminator. */
93 33417 : dstlen = strlen(str) * 4 + 1;
94 :
95 : #ifdef FRONTEND
96 0 : dst = malloc(dstlen);
97 : #else
98 33417 : dst = palloc_extended(dstlen, alloc_flags);
99 : #endif
100 :
101 33417 : if (!dst)
102 0 : return NULL;
103 :
104 641549 : for (p = str; *p != '\0'; p++)
105 : {
106 :
107 : /* Only allow clean ASCII chars in the string */
108 608132 : if (*p < 32 || *p > 126)
109 : {
110 : Assert(i < (dstlen - 3));
111 16 : snprintf(&dst[i], dstlen - i, "\\x%02x", (unsigned char) *p);
112 16 : i += 4;
113 : }
114 : else
115 : {
116 : Assert(i < dstlen);
117 608116 : dst[i] = *p;
118 608116 : i++;
119 : }
120 : }
121 :
122 : Assert(i < dstlen);
123 33417 : dst[i] = '\0';
124 33417 : return dst;
125 : }
126 :
127 :
128 : /*
129 : * pg_is_ascii -- Check if string is made only of ASCII characters
130 : */
131 : bool
132 81254 : pg_is_ascii(const char *str)
133 : {
134 399555 : while (*str)
135 : {
136 318309 : if (IS_HIGHBIT_SET(*str))
137 8 : return false;
138 318301 : str++;
139 : }
140 81246 : return true;
141 : }
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 202516 : pg_strip_crlf(char *str)
155 : {
156 202516 : int len = strlen(str);
157 :
158 405032 : while (len > 0 && (str[len - 1] == '\n' ||
159 195750 : str[len - 1] == '\r'))
160 202516 : str[--len] = '\0';
161 :
162 202516 : return len;
163 : }
|