/* ** OSSP str - String Handling ** Copyright (c) 1999-2005 Ralf S. Engelschall ** Copyright (c) 1999-2005 The OSSP Project ** ** This file is part of OSSP str, a string handling and manipulation ** library which can be found at http://www.ossp.org/pkg/lib/str/. ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** ** str_handle.c: handling and manipulation functions */ #include "str_p.h" /* * str_len -- determine length of string. * This is exactly equal to POSIX strlen(3). */ str_size_t str_len(const char *s) { register const char *t; if (s == NULL) return 0; t = s; while (*t++ != NUL) /*nop*/; return (t-s-1); } /* * str_copy -- copy a string. * This is inspired by POSIX strncpy(3), but the source and target * and overlap and the the target is always NUL-terminated. */ char *str_copy(char *as, const char *at, str_size_t n) { register char *s; register const char *t; char *rv; if (as == NULL || at == NULL) return NULL; if (n == 0) n = str_len(at); t = at; s = as; rv = as; if (s > t) { /* must go high to low */ t += n - 1; s += n; rv = s; *s-- = NUL; while (n-- > 0) *s-- = *t--; } else if (s < t) { /* must go low to high */ while (n-- > 0) *s++ = *t++; *s = NUL; rv = s; } return rv; } /* * str_dup -- duplicate a string. * This is inspired by POSIX strdup(3), but provides * the ability to specify a maximum length. */ char *str_dup(const char *s, str_size_t n) { char *t; char *rv; if (s == NULL) return NULL; if (n == 0) n = str_len(s); if ((rv = str_mem_alloc(n+1)) == NULL) return NULL; t = rv; while (n-- > 0) *t++ = *s++; *t = NUL; return rv; } /* * str_concat -- concatenate one or more strings. * This function allows one to concatenate an arbitrary number of * strings and is inspired by Apache's ap_pstrcat() function. */ char *str_concat(char *s, ...) { va_list ap; char *rv; va_start(ap, s); rv = str_concat_va(s, ap); va_end(ap); return rv; } char *str_concat_va(char *s, va_list ap) { va_list ap_safe; int n; char *rv; char *cp; char *ds; if (s == NULL) return NULL; /* determine required target string length */ va_copy(ap_safe, ap); n = str_len(s); while ((cp = va_arg(ap, char *)) != NULL) n += str_len(cp); va_copy(ap, ap_safe); /* allocate target string */ if ((rv = str_mem_alloc(n+1)) == NULL) return NULL; /* concatenate the strings */ ds = rv; while ((*ds = *s++) != NUL) ds++; while ((cp = va_arg(ap, char *)) != NULL) { while ((*ds = *cp++) != NUL) ds++; } /* return target string */ return rv; } /* * str_splice -- splice one string into another. * This is inspired by Perl's splice() function and can be used * both for inplace movements, insert and cut-out operations. */ char *str_splice(char *s, str_size_t off, str_size_t n, char *t, str_size_t m) { int sl; /* check for invalid arguments */ if (s == NULL || t == NULL) return NULL; /* check for overlapping areas */ if (!((t+m) <= s || (s+off+n) <= t)) return NULL; sl = str_len(s); if ((t+m) < s || (s+sl) < t) { /* splice _external_ area into internal area */ if (m != n) str_mem_move(s+off+m, s+off+n, sl-off-n+1); str_mem_move(s+off, t, m); } else { /* splice _internal_ area into internal area */ if (t > s) { /* move t from larger to lower address of s */ str_mem_rev(s+off, (t+m)-(s+off)); str_mem_rev(s+off, m); str_mem_rev(s+off+m, t-(s+n)); str_mem_move(t+m-n, t+m, (s+sl)-(t+m)+1); } else { /* move t from lower to higher address of s */ str_mem_rev(t, (s+off)-t); str_mem_rev(t, (s+off)-t-m); str_mem_rev(s+off-m, m); str_mem_move(s+off, s+off+n, sl-off-n+1); } } return s; } /* * str_compare -- compare a two strings. * This is inspired by POSIX str[n][case]cmp(3), but * merges all functionality in a single function. */ int str_compare(const char *s1, const char *s2, str_size_t n, int mode) { int rv; int bWithLen; rv = 0; if (n == 0) bWithLen = FALSE; else bWithLen = TRUE; if (mode & STR_NOCASE) { /* compare case insensitive */ do { if (str_tolower(*s1) != str_tolower(*s2++)) { rv = ((str_tolower(*s1) - str_tolower(*(s2 - 1))) < 0 ? -1 : +1); break; } if (bWithLen) if (--n <= 0) break; } while (*s1++ != NUL); } else { /* compare case sensitive */ do { if (*s1 != *s2++) { rv = (((int)(*(const unsigned char *)s1) - (int)(*(const unsigned char *)(s2 - 1))) < 0 ? -1 : +1); break; } if (bWithLen) if (--n <= 0) break; } while (*s1++ != NUL); } return rv; }