*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
+/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
/* Miscellaneous string-handling functions. Some are not required for
/* This function is called for critical strings. It checks for any
non-printing characters, and if any are found, it makes a new copy
of the string with suitable escape sequences. It is most often called by the
-macro string_printing(), which sets allow_tab TRUE.
+macro string_printing(), which sets flags to 0.
Arguments:
s the input string
- allow_tab TRUE to allow tab as a printing character
+ flags Bit 0: convert tabs. Bit 1: convert spaces.
Returns: string with non-printers encoded as printing sequences
*/
const uschar *
-string_printing2(const uschar *s, BOOL allow_tab)
+string_printing2(const uschar *s, int flags)
{
int nonprintcount = 0;
int length = 0;
while (*t != 0)
{
int c = *t++;
- if (!mac_isprint(c) || (!allow_tab && c == '\t')) nonprintcount++;
+ if ( !mac_isprint(c)
+ || flags & SP_TAB && c == '\t'
+ || flags & SP_SPACE && c == ' '
+ ) nonprintcount++;
length++;
}
/* Get a new block of store guaranteed big enough to hold the
expanded string. */
-ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s));
+tt = ss = store_get(length + nonprintcount * 3 + 1, is_tainted(s));
/* Copy everything, escaping non printers. */
-t = s;
-tt = ss;
-
-while (*t != 0)
+for (t = s; *t; )
{
int c = *t;
- if (mac_isprint(c) && (allow_tab || c != '\t')) *tt++ = *t++; else
+ if ( mac_isprint(c)
+ && (!(flags & SP_TAB) || c != '\t')
+ && (!(flags & SP_SPACE) || c != ' ')
+ )
+ *tt++ = *t++;
+ else
{
*tt++ = '\\';
switch (*t)
while (*s != 0)
{
if (*s != '\\')
- {
*ss++ = *s++;
- }
else if (isdigit(s[1]))
{
*ss++ = (s[1] - '0')*100 + (s[2] - '0')*10 + s[3] - '0';
s += 4;
}
else if (*(++s) != 0)
- {
*ss++ = *s++;
- }
}
*ss = 0;
*/
uschar *
-string_nextinlist(const uschar **listptr, int *separator, uschar *buffer, int buflen)
+string_nextinlist_trc(const uschar **listptr, int *separator, uschar *buffer, int buflen,
+ const uschar * func, int line)
{
int sep = *separator;
const uschar *s = *listptr;
if (buffer)
{
int p = 0;
+ if (is_tainted(s) && !is_tainted(buffer))
+ die_tainted(US"string_nextinlist", func, line);
for (; *s; s++)
{
if (*s == sep && (*(++s) != sep || sep_is_special)) break;
start of a string. Avoid getting working memory for an empty item. */
if (*s == sep)
- {
- s++;
- if (*s != sep || sep_is_special)
+ if (*++s != sep || sep_is_special)
{
*listptr = s;
return string_copy(US"");
}
- }
/* Not an empty string; the first character is guaranteed to be a data
character. */
s = ss;
if (!*s || *++s != sep || sep_is_special) break;
}
- while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--;
+ /* while (g->ptr > 0 && isspace(g->s[g->ptr-1])) g->ptr--; */
+ while ( g->ptr > 0 && isspace(g->s[g->ptr-1])
+ && (g->ptr == 1 || g->s[g->ptr-2] != '\\') )
+ g->ptr--;
buffer = string_from_gstring(g);
gstring_release_unused(g);
}
"Permission denied", reads and includes the euid and egid.
Arguments:
- eno the value of errno after the failure
format a text format string - deliberately not uschar *
... arguments for the format string
*/
uschar *
-string_open_failed_trc(int eno, const uschar * func, unsigned line,
+string_open_failed_trc(const uschar * func, unsigned line,
const char *format, ...)
{
va_list ap;
va_start(ap, format);
(void) string_vformat_trc(g, func, line, STRING_SPRINTF_BUFFER_SIZE,
- 0, format, ap);
-string_from_gstring(g);
-gstring_release_unused(g);
+ SVFMT_REBUFFER, format, ap);
va_end(ap);
-return eno == EACCES
- ? string_sprintf("%s: %s (euid=%ld egid=%ld)", g->s, strerror(eno),
- (long int)geteuid(), (long int)getegid())
- : string_sprintf("%s: %s", g->s, strerror(eno));
+g = string_catn(g, US": ", 2);
+g = string_cat(g, US strerror(errno));
+
+if (errno == EACCES)
+ {
+ int save_errno = errno;
+ g = string_fmt_append(g, " (euid=%ld egid=%ld)",
+ (long int)geteuid(), (long int)getegid());
+ errno = save_errno;
+ }
+gstring_release_unused(g);
+return string_from_gstring(g);
}
-#endif /* COMPILE_UTILITY */
-#ifndef COMPILE_UTILITY
/* qsort(3), currently used to sort the environment variables
for -bP environment output, needs a function to compare two pointers to string
pointers. Here it is. */