/* ** OSSP lmtp2nntp - Mail to News Gateway ** Copyright (c) 2001-2003 Ralf S. Engelschall ** Copyright (c) 2001-2003 The OSSP Project ** Copyright (c) 2001-2003 Cable & Wireless Germany ** ** This file is part of OSSP lmtp2nntp, an LMTP speaking local ** mailer which forwards mails as Usenet news articles via NNTP. ** It can be found at http://www.ossp.org/pkg/tool/lmtp2nntp/. ** ** This program is free software; you can redistribute it and/or ** modify it under the terms of the GNU General Public License ** as published by the Free Software Foundation; either version ** 2.0 of the License, or (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this file; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ** USA, or contact the OSSP project . ** ** argz.h: Zero-Terminated Argument Vector library */ /* Routines for dealing with '\0' separated arg vectors. Copyright (C) 1996, 1997 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper , 1996. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with the GNU C Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include "lmtp2nntp_argz.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #if defined(HAVE_DMALLOC_H) && defined(WITH_DMALLOC) #include "dmalloc.h" #endif /* Find the length of STRING, but scan at most MAXLEN characters. If no '\0' terminator is found in that many characters, return MAXLEN. */ static size_t my_strnlen(const char *string, size_t maxlen) { const char *end = memchr(string, '\0', maxlen); return end ? (size_t) (end - string) : maxlen; } static char *my_strndup(const char *s, size_t n) { size_t len = my_strnlen(s, n); char *new = malloc(len + 1); if (new == NULL) return NULL; new[len] = '\0'; return (char *)memcpy(new, s, len); } /* Copy SRC to DEST, returning the address of the terminating '\0' in DEST. */ static char *my_stpcpy(char *dest, const char *src) { register char *d = dest; register const char *s = src; do { *d++ = *s; } while (*s++ != '\0'); return d - 1; } int argz_add_sep(char **argz, size_t * argz_len, const char *string, int delim) { size_t nlen = strlen(string) + 1; if (nlen > 1) { const char *rp; char *wp; *argz = (char *)realloc(*argz, *argz_len + nlen); if (*argz == NULL) return ENOMEM; wp = *argz + *argz_len; rp = string; do { if (*rp == delim) { if (wp > *argz && wp[-1] != '\0') *wp++ = '\0'; else --nlen; } else *wp++ = *rp; } while (*rp++ != '\0'); *argz_len += nlen; } return 0; } /* Add BUF, of length BUF_LEN to the argz vector in ARGZ & ARGZ_LEN. */ int argz_append(char **argz, size_t * argz_len, const char *buf, size_t buf_len) { size_t new_argz_len = *argz_len + buf_len; char *new_argz = realloc(*argz, new_argz_len); if (new_argz) { memcpy(new_argz + *argz_len, buf, buf_len); *argz = new_argz; *argz_len = new_argz_len; return 0; } else return ENOMEM; } /* Add STR to the argz vector in ARGZ & ARGZ_LEN. This should be moved into * argz.c in libshouldbelibc. */ int argz_add(char **argz, size_t * argz_len, const char *str) { return argz_append(argz, argz_len, str, strlen(str) + 1); } /* Returns the number of strings in ARGZ. */ size_t argz_count(const char *argz, size_t len) { size_t count = 0; while (len > 0) { size_t part_len = strlen(argz); argz += part_len + 1; len -= part_len + 1; count++; } return count; } /* Make a '\0' separated arg vector from a unix argv vector, returning it in * ARGZ, and the total length in LEN. If a memory allocation error occurs, * ENOMEM is returned, otherwise 0. */ int argz_create(char *const argv[], char **argz, size_t * len) { int argc; size_t tlen = 0; char *const *ap; char *p; for (argc = 0; argv[argc] != NULL; ++argc) tlen += strlen(argv[argc]) + 1; if (tlen == 0) *argz = NULL; else { *argz = malloc(tlen); if (*argz == NULL) return ENOMEM; for (p = *argz, ap = argv; *ap; ++ap, ++p) p = my_stpcpy(p, *ap); } *len = tlen; return 0; } int argz_create_sep(const char *string, int delim, char **argz, size_t * len) { size_t nlen = strlen(string) + 1; if (nlen > 1) { const char *rp; char *wp; *argz = (char *)malloc(nlen); if (*argz == NULL) return ENOMEM; rp = string; wp = *argz; do if (*rp == delim) { if (wp > *argz && wp[-1] != '\0') *wp++ = '\0'; else --nlen; } else *wp++ = *rp; while (*rp++ != '\0'); if (nlen == 0) { free(*argz); *argz = NULL; *len = 0; } *len = nlen; } else { *argz = NULL; *len = 0; } return 0; } /* Delete ENTRY from ARGZ & ARGZ_LEN, if any. */ void argz_delete(char **argz, size_t * argz_len, char *entry) { if (entry) /* Get rid of the old value for NAME. */ { size_t entry_len = strlen(entry) + 1; *argz_len -= entry_len; memmove(entry, entry + entry_len, *argz_len - (entry - *argz)); if (*argz_len == 0) { free(*argz); *argz = 0; } } } /* Puts pointers to each string in ARGZ, plus a terminating 0 element, into * ARGV, which must be large enough to hold them all. */ void argz_extract(const char *argz, size_t len, char **argv) { while (len > 0) { size_t part_len = strlen(argz); *argv++ = (char *)argz; argz += part_len + 1; len -= part_len + 1; } *argv = 0; } /* Insert ENTRY into ARGZ & ARGZ_LEN before BEFORE, which should be an * existing entry in ARGZ; if BEFORE is NULL, ENTRY is appended to the end. * Since ARGZ's first entry is the same as ARGZ, argz_insert (ARGZ, ARGZ_LEN, * ARGZ, ENTRY) will insert ENTRY at the beginning of ARGZ. If BEFORE is not * in ARGZ, EINVAL is returned, else if memory can't be allocated for the new * ARGZ, ENOMEM is returned, else 0. */ int argz_insert(char **argz, size_t * argz_len, char *before, const char *entry) { if (!before) return argz_add(argz, argz_len, entry); if (before < *argz || before >= *argz + *argz_len) return EINVAL; if (before > *argz) /* Make sure before is actually the beginning of an entry. */ while (before[-1]) before--; { size_t after_before = *argz_len - (before - *argz); size_t entry_len = strlen(entry) + 1; size_t new_argz_len = *argz_len + entry_len; char *new_argz = realloc(*argz, new_argz_len); if (new_argz) { before = new_argz + (before - *argz); memmove(before + entry_len, before, after_before); memmove(before, entry, entry_len); *argz = new_argz; *argz_len = new_argz_len; return 0; } else return ENOMEM; } } char *argz_next(const char *argz, size_t argz_len, const char *entry) { if (entry) { if (entry < argz + argz_len) entry = strchr(entry, '\0') + 1; return entry >= argz + argz_len ? NULL : (char *)entry; } else if (argz_len > 0) return (char *)argz; else return NULL; } /* Append BUF, of length BUF_LEN to *TO, of length *TO_LEN, reallocating and * updating *TO & *TO_LEN appropriately. If an allocation error occurs, * *TO's old value is freed, and *TO is set to 0. */ static void str_append(char **to, size_t * to_len, const char *buf, const size_t buf_len) { size_t new_len = *to_len + buf_len; char *new_to = realloc(*to, new_len + 1); if (new_to) { /* *((char *)__mempcpy(new_to + *to_len, buf, buf_len)) = '\0'; */ memcpy(new_to + *to_len, buf, buf_len); *(new_to + *to_len + buf_len) = '\0'; *to = new_to; *to_len = new_len; } else { free(*to); *to = 0; } } /* Replace any occurrences of the string STR in ARGZ with WITH, reallocating * ARGZ as necessary. If REPLACE_COUNT is non-zero, *REPLACE_COUNT will be * incremented by number of replacements performed. */ int argz_replace(char **argz, size_t * argz_len, const char *str, const char *with, unsigned *replace_count) { int err = 0; if (str && *str) { char *arg = 0; char *src = *argz; size_t src_len = *argz_len; char *dst = 0; size_t dst_len = 0; int delayed_copy = 1; /* True while we've avoided copying * anything. */ size_t str_len = strlen(str), with_len = strlen(with); while (!err && (arg = argz_next(src, src_len, arg))) { char *match = strstr(arg, str); if (match) { char *from = match + str_len; size_t to_len = match - arg; char *to = my_strndup(arg, to_len); while (to && from) { str_append(&to, &to_len, with, with_len); if (to) { match = strstr(from, str); if (match) { str_append(&to, &to_len, from, match - from); from = match + str_len; } else { str_append(&to, &to_len, from, strlen(from)); from = 0; } } } if (to) { if (delayed_copy) /* We avoided copying SRC to DST until we found a * match; now that we've done so, copy everything * from the start of SRC. */ { if (arg > src) err = argz_append(&dst, &dst_len, src, (arg - src)); delayed_copy = 0; } if (!err) err = argz_add(&dst, &dst_len, to); free(to); } else err = ENOMEM; if (replace_count) (*replace_count)++; } else if (!delayed_copy) err = argz_add(&dst, &dst_len, arg); } if (!err) { if (!delayed_copy) /* We never found any instances of str. */ { if (src) free(src); *argz = dst; *argz_len = dst_len; } } else if (dst_len > 0) free(dst); } return err; } /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's * except the last into the character SEP. */ void argz_stringify(char *argz, size_t len, int sep) { if (len > 0) { while (1) { size_t part_len = my_strnlen(argz, len); argz += part_len; len -= part_len; if (len-- <= 1) /* includes final '\0' we want to stop * at */ break; *argz++ = sep; } } return; }