diff options
Diffstat (limited to 'libsm/util.c')
-rw-r--r-- | libsm/util.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/libsm/util.c b/libsm/util.c new file mode 100644 index 000000000000..2b99a493422d --- /dev/null +++ b/libsm/util.c @@ -0,0 +1,250 @@ +/* + * Copyright (c) 2006 Sendmail, Inc. and its suppliers. + * All rights reserved. + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the sendmail distribution. + * + */ + +#include <sm/gen.h> + +SM_RCSID("@(#)$Id: util.c,v 1.9 2006/08/30 18:35:51 ca Exp $") +#include <sm/setjmp.h> +#include <sm/conf.h> +#include <sm/assert.h> +#include <sm/heap.h> +#include <sm/string.h> +#include <sm/sendmail.h> +#include <ctype.h> + +/* +** STR2PRT -- convert "unprintable" characters in a string to \oct +** +** Parameters: +** s -- string to convert +** +** Returns: +** converted string. +** This is a static local buffer, string must be copied +** before this function is called again! +*/ + +char * +str2prt(s) + char *s; +{ + int l; + char c, *h; + bool ok; + static int len = 0; + static char *buf = NULL; + + if (s == NULL) + return NULL; + ok = true; + for (h = s, l = 1; *h != '\0'; h++, l++) + { + if (*h == '\\') + { + ++l; + ok = false; + } + else if (!(isascii(*h) && isprint(*h))) + { + l += 3; + ok = false; + } + } + if (ok) + return s; + if (l > len) + { + char *nbuf = sm_pmalloc_x(l); + + if (buf != NULL) + sm_free(buf); + len = l; + buf = nbuf; + } + for (h = buf; *s != '\0' && l > 0; s++, l--) + { + c = *s; + if (isascii(c) && isprint(c) && c != '\\') + { + *h++ = c; + } + else + { + *h++ = '\\'; + --l; + switch (c) + { + case '\\': + *h++ = '\\'; + break; + case '\t': + *h++ = 't'; + break; + case '\n': + *h++ = 'n'; + break; + case '\r': + *h++ = 'r'; + break; + default: + SM_ASSERT(l >= 2); + (void) sm_snprintf(h, l, "%03o", + (unsigned int)((unsigned char) c)); + + /* + ** XXX since l is unsigned this may + ** wrap around if the calculation is screwed + ** up... + */ + + l -= 2; + h += 3; + break; + } + } + } + *h = '\0'; + buf[len - 1] = '\0'; + return buf; +} + +/* +** QUOTE_INTERNAL_CHARS -- do quoting of internal characters +** +** Necessary to make sure that we don't have metacharacters such +** as the internal versions of "$*" or "$&" in a string. +** The input and output pointers can be the same. +** +** Parameters: +** ibp -- a pointer to the string to translate +** obp -- a pointer to an output buffer +** bsp -- pointer to the length of the output buffer +** +** Returns: +** A possibly new bp (if the buffer needed to grow); if +** it is different, *bsp will updated to the size of +** the new buffer and the caller is responsible for +** freeing the memory. +*/ + +#define SM_MM_QUOTE(ch) (((ch) & 0377) == METAQUOTE || (((ch) & 0340) == 0200)) + +char * +quote_internal_chars(ibp, obp, bsp) + char *ibp; + char *obp; + int *bsp; +{ + char *ip, *op; + int bufused, olen; + bool buffer_same, needs_quoting; + + buffer_same = ibp == obp; + needs_quoting = false; + + /* determine length of output string (starts at 1 for trailing '\0') */ + for (ip = ibp, olen = 1; *ip != '\0'; ip++, olen++) + { + if (SM_MM_QUOTE(*ip)) + { + olen++; + needs_quoting = true; + } + } + + /* is the output buffer big enough? */ + if (olen > *bsp) + { + obp = sm_malloc_x(olen); + buffer_same = false; + *bsp = olen; + } + + /* + ** shortcut: no change needed? + ** Note: we don't check this first as some bozo may use the same + ** buffers but restrict the size of the output buffer to less + ** than the length of the input buffer in which case we need to + ** allocate a new buffer. + */ + + if (!needs_quoting) + { + if (!buffer_same) + { + bufused = sm_strlcpy(obp, ibp, *bsp); + SM_ASSERT(bufused <= olen); + } + return obp; + } + + if (buffer_same) + { + obp = sm_malloc_x(olen); + buffer_same = false; + *bsp = olen; + } + + for (ip = ibp, op = obp, bufused = 0; *ip != '\0'; ip++) + { + if (SM_MM_QUOTE(*ip)) + { + SM_ASSERT(bufused < olen); + op[bufused++] = METAQUOTE; + } + SM_ASSERT(bufused < olen); + op[bufused++] = *ip; + } + op[bufused] = '\0'; + return obp; +} + +/* +** DEQUOTE_INTERNAL_CHARS -- undo the effect of quote_internal_chars +** +** Parameters: +** ibp -- a pointer to the string to be translated. +** obp -- a pointer to the output buffer. Can be the +** same as ibp. +** obs -- the size of the output buffer. +** +** Returns: +** number of character added to obp +*/ + +int +dequote_internal_chars(ibp, obp, obs) + char *ibp; + char *obp; + int obs; +{ + char *ip, *op; + int len; + bool quoted; + + quoted = false; + len = 0; + for (ip = ibp, op = obp; *ip != '\0'; ip++) + { + if ((*ip & 0377) == METAQUOTE && !quoted) + { + quoted = true; + continue; + } + if (op < &obp[obs - 1]) + { + *op++ = *ip; + ++len; + } + quoted = false; + } + *op = '\0'; + return len; +} |