/* Length/String string handling * Copyright (C) 2009 Chris Hall (GMCH), Highwayman * * This file is part of GNU Zebra. * * GNU Zebra 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, or (at your * option) any later version. * * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include "misc.h" #include #include "elstring.h" #include "memory.h" /*============================================================================== * Create and free */ /*------------------------------------------------------------------------------ * Create a new elstring */ extern elstring els_new(void) { return XCALLOC(MTYPE_TMP, sizeof(elstring_t)) ; confirm(ELSTRING_INIT_ALL_ZEROS) ; } ; /*------------------------------------------------------------------------------ * Initialise or create a new elstring */ extern elstring els_init_new(elstring els) { if (els == NULL) els = els_new() ; else memset(els, 0, sizeof(elstring_t)) ; confirm(ELSTRING_INIT_ALL_ZEROS) ; return els ; } ; /*------------------------------------------------------------------------------ * Release dynamically allocated elstring. * * Returns NULL. * * NB: it is the callers responsibility to free the contents of the elstring. * if that is required, before freeing the elstring itself. */ extern elstring els_free(elstring els) { if (els != NULL) XFREE(MTYPE_TMP, els) ; return NULL ; } ; /*============================================================================== * Various comparisons */ /*------------------------------------------------------------------------------ * Basic string/length vs string/length comparison */ inline static int str_nn_cmp(const uchar* ap, ulen al, const uchar* bp, ulen bl) { ulen n ; n = (al <= bl) ? al : bl ; /* min(al, bl) */ while (n) { int d = *ap++ - *bp++ ; if (d != 0) return d ; --n ; } ; return al < bl ? -1 : (al == bl) ? 0 : +1 ; } ; /*------------------------------------------------------------------------------ * Compare two elstrings -- returns the usual -ve, 0, +ve cmp result. * * NULL elstring is treated as empty. */ extern int els_cmp(elstring a, elstring b) { return str_nn_cmp(els_body(a), els_len(a), els_body(b), els_len(b)) ; } ; /*------------------------------------------------------------------------------ * Compare elstring and ordinary string * -- returns the usual -ve, 0, +ve cmp result. * * NULL elstring is treated as empty. */ extern int els_cmp_str(elstring a, const char* s) { return str_nn_cmp(els_body(a), els_len(a), (const uchar*)s, (s != NULL) ? strlen(s) : 0) ; } ; /*------------------------------------------------------------------------------ * Compare two string/length values -- returns the usual -ve, 0, +ve cmp result * * (Not really an elstring function, but the infrastructure is here.) */ extern int els_nn_cmp(const void* ap, ulen al, const void* bp, ulen bl) { return str_nn_cmp(ap, al, bp, bl) ; } ; /*------------------------------------------------------------------------------ * Compare elstring against word elstring. * * Returns: -1 => elstring and word match to end of elstring * 0 => elstring and word match completely * +1 => elstring and word do not match * * NULLs are treated as empty strings. * * An empty elstring will completely match an empty word. * An empty elstring will partly match any non-empty word. */ extern int els_cmp_word(elstring a, elstring w) { const uchar* ap, * ep, * wp ; ulen al, wl ; al = els_len(a) ; /* zero if a is NULL */ wl = els_len(w) ; /* zero if w is NULL */ if (al > wl) return +1 ; /* no match if longer */ if (al == 0) return (wl == 0) ? 0 : -1 ; /* exact or partial if empty */ ap = els_body_nn(a) ; wp = els_body_nn(w) ; /* Neither string is empty */ if (*ap != *wp) return +1 ; /* quick out if no match for 1st char */ ep = ap + al - 1 ; while (ap < ep) { if (*++ap != *++wp) return 1 ; } ; return al == wl ? 0 : -1 ; /* full or partial match */ } ; /*------------------------------------------------------------------------------ * Compare significant parts of two qstrings -- returns the usual -ve, 0, +ve * cmp result. * * By significant, mean excluding leading/trailing isspace() and treating * multiple isspace() as single isspace(). * * Compares the 'len' portions of the strings. * * NULL elstring is treated as empty. */ extern int els_cmp_sig(elstring a, elstring b) { cpp_t ap ; cpp_t bp ; /* Set up pointers and dispense with leading and trailing isspace() * * Dummy up if NULL */ els_cpp(ap, a) ; /* NULL if a is NULL */ while ((ap->p < ap->e) && isspace(*ap->p)) ++ap->p ; while ((ap->p < ap->e) && isspace(*(ap->e - 1))) --ap->e ; els_cpp(bp, b) ; while ((bp->p < bp->e) && isspace(*bp->p)) ++bp->p ; while ((bp->p < bp->e) && isspace(*(bp->e - 1))) --bp->e ; /* Now set about finding the first difference */ while ((ap->p != ap->e) && (bp->p != bp->e)) { if (isspace(*ap->p) && isspace(*bp->p)) { do { ++ap->p ; } while (isspace(*ap->p)) ; do { ++bp->p ; } while (isspace(*bp->p)) ; } ; if (*ap->p != *bp->p) return (*ap->p < *bp->p) ? -1 : +1 ; ++ap->p ; ++bp->p ; } ; /* No difference before ran out of one or both */ if (ap->p != ap->e) return +1 ; else if (bp->p != bp->e) return -1 ; else return 0 ; } ; /*------------------------------------------------------------------------------ * Are two elstrings equal ? -- returns true if strings equal. */ extern bool els_equal(elstring a, elstring b) { const uchar* ap ; const uchar* bp ; ulen n ; n = els_len(b) ; /* zero if b is NULL */ if (n != els_len(a)) return false ; ap = els_body(a) ; /* NULL if a is NULL */ bp = els_body(b) ; while (n) { if (*ap++ != *bp++) return false ; --n ; } ; return true ; } ; /*------------------------------------------------------------------------------ * Is 'b' a leading substring of 'a' ? -- returns true if it is. * * If 'b' is empty it is always a leading substring. */ extern bool els_substring(elstring a, elstring b) { const uchar* ap ; const uchar* bp ; ulen n ; n = els_len(b) ; /* zero if b is NULL */ if (n > els_len(a)) return false ; ap = els_body(a) ; bp = els_body(b) ; while (n) { if (*ap++ != *bp++) return false ; --n ; } ; return true ; } ; /*------------------------------------------------------------------------------ * Return length of leading substring of two strings */ extern ulen els_sub_len(elstring a, elstring b) { const uchar* ap ; const uchar* bp ; ulen n, m ; n = els_len(a) ; /* zero if a is NULL */ m = els_len(b) ; /* zero if b is NULL */ if (n > m) n = m ; /* choose the smaller */ ap = els_body(a) ; bp = els_body(b) ; m = n ; while (n != 0) { if (*ap++ != *bp++) break ; --n ; } ; return m - n ; } ;