/*------------------------------------------------------------------------- * * string.c * string handling helpers * * * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/common/string.c * *------------------------------------------------------------------------- */ #ifndef FRONTEND #include "postgres.h" #else #include "postgres_fe.h" #endif #include "common/string.h" #include "lib/stringinfo.h" /* * Returns whether the string `str' has the postfix `end'. */ bool pg_str_endswith(const char *str, const char *end) { size_t slen = strlen(str); size_t elen = strlen(end); /* can't be a postfix if longer */ if (elen > slen) return false; /* compare the end of the strings */ str += slen - elen; return strcmp(str, end) == 0; } /* * strtoint --- just like strtol, but returns int not long */ int strtoint(const char *pg_restrict str, char **pg_restrict endptr, int base) { long val; val = strtol(str, endptr, base); if (val != (int) val) errno = ERANGE; return (int) val; } /* * pg_clean_ascii -- Replace any non-ASCII chars with a "\xXX" string * * Makes a newly allocated copy of the string passed in, which must be * '\0'-terminated. In the backend, additional alloc_flags may be provided and * will be passed as-is to palloc_extended(); in the frontend, alloc_flags is * ignored and the copy is malloc'd. * * This function exists specifically to deal with filtering out * non-ASCII characters in a few places where the client can provide an almost * arbitrary string (and it isn't checked to ensure it's a valid username or * database name or similar) and we don't want to have control characters or other * things ending up in the log file where server admins might end up with a * messed up terminal when looking at them. * * In general, this function should NOT be used- instead, consider how to handle * the string without needing to filter out the non-ASCII characters. * * Ultimately, we'd like to improve the situation to not require replacing all * non-ASCII but perform more intelligent filtering which would allow UTF or * similar, but it's unclear exactly what we should allow, so stick to ASCII only * for now. */ char * pg_clean_ascii(const char *str, int alloc_flags) { size_t dstlen; char *dst; const char *p; size_t i = 0; /* Worst case, each byte can become four bytes, plus a null terminator. */ dstlen = strlen(str) * 4 + 1; #ifdef FRONTEND dst = malloc(dstlen); #else dst = palloc_extended(dstlen, alloc_flags); #endif if (!dst) return NULL; for (p = str; *p != '\0'; p++) { /* Only allow clean ASCII chars in the string */ if (*p < 32 || *p > 126) { Assert(i < (dstlen - 3)); snprintf(&dst[i], dstlen - i, "\\x%02x", (unsigned char) *p); i += 4; } else { Assert(i < dstlen); dst[i] = *p; i++; } } Assert(i < dstlen); dst[i] = '\0'; return dst; } /* * pg_is_ascii -- Check if string is made only of ASCII characters */ bool pg_is_ascii(const char *str) { while (*str) { if (IS_HIGHBIT_SET(*str)) return false; str++; } return true; } /* * pg_strip_crlf -- Remove any trailing newline and carriage return * * Removes any trailing newline and carriage return characters (\r on * Windows) in the input string, zero-terminating it. * * The passed in string must be zero-terminated. This function returns * the new length of the string. */ int pg_strip_crlf(char *str) { int len = strlen(str); while (len > 0 && (str[len - 1] == '\n' || str[len - 1] == '\r')) str[--len] = '\0'; return len; }