⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 urlmap.c

📁 Sofia SIP is an open-source SIP User-Agent library, compliant with the IETF RFC3261 specification.
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi <pekka.pessi@nokia.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * *//**@internal * @file urlmap.c * @brief Mapping with hierarchical URLs. * * @author Pekka Pessi <Pekka.Pessi@nokia.com> * * @date Created: Wed Mar 10 17:05:23 2004 ppessi * */#include "config.h"#include <stddef.h>#include <string.h>#include <assert.h>#include <errno.h>#include <stdlib.h>#include "urlmap.h"/** Create map entry. */UrlMap *url_map_new(su_home_t *home,		    url_string_t const *url,		    unsigned size){  UrlMap *um;  int xtra;  url_t *u;  xtra = url_xtra(url->us_url);  um = su_zalloc(home, size + xtra);  if (!um || url_dup((char *)um + size, xtra, um->um_url, url->us_url) < 0) {    su_free(home, um);    return NULL;  }  u = um->um_url;  if (!u->url_path)    u->url_path = "";  return um;}staticvoid left_rotate(UrlMap **top, UrlMap *x){  /*               x                c   *              / \              / \   * Convert     a   c    into    x   d   *                / \          / \   *               b   d        a   b   */  UrlMap *c = x->um_right, *dad = x->um_dad; assert(c);  if ((x->um_right = c->um_left))    x->um_right->um_dad = x;  if (!(c->um_dad = dad))    *top = c;  else if (dad->um_left == x)    dad->um_left = c;  else    assert(dad->um_right == x), dad->um_right = c;  c->um_left = x;  x->um_dad = c;}staticvoid right_rotate(UrlMap **top, UrlMap *x){  /*               x                c   *              / \              / \   * Convert     c   f    into    a   x   *            / \                  / \   *           a   d                d   f   */  UrlMap *c = x->um_left, *dad = x->um_dad; assert(c);  if ((x->um_left = c->um_right))    x->um_left->um_dad = x;  if (!(c->um_dad = dad))    *top = c;  else if (dad->um_right == x)    dad->um_right = c;  else    assert(dad->um_left == x), dad->um_left = c;  c->um_right = x;  x->um_dad = c;}/** Balance Red-Black binary tree after inserting node @a um. * * The function red_black_balance_insert() balances a red-black tree after * insertion. */staticvoid red_black_balance_insert(UrlMap **top, UrlMap *um){  UrlMap *dad, *uncle, *granddad;  um->um_black = 0;  for (dad = um->um_dad; um != *top && !dad->um_black; dad = um->um_dad) {    /* Repeat until we are parent or we have a black dad */    granddad = dad->um_dad; assert(granddad);    if (dad == granddad->um_left) {      uncle = granddad->um_right;      if (uncle && !uncle->um_black) {	dad->um_black = 1;	uncle->um_black = 1;	granddad->um_black = 0;	um = granddad;      } else {	if (um == dad->um_right) {	  left_rotate(top, um = dad);	  dad = um->um_dad; assert(dad);	  granddad = dad->um_dad; assert(granddad);	}	dad->um_black = 1;	granddad->um_black = 0;	right_rotate(top, granddad);      }    } else { assert(dad == granddad->um_right);      uncle = granddad->um_left;      if (uncle && !uncle->um_black) {	dad->um_black = 1;	uncle->um_black = 1;	granddad->um_black = 0;	um = granddad;      } else {	if (um == dad->um_left) {	  right_rotate(top, um = dad);	  dad = um->um_dad; assert(dad);	  granddad = dad->um_dad; assert(granddad);	}	dad->um_black = 1;	granddad->um_black = 0;	left_rotate(top, granddad);      }    }  }  assert(*top);  (*top)->um_black = 1;}static void red_black_balance_delete(UrlMap **top, UrlMap *um){  UrlMap *dad, *brother;  for (dad = um->um_dad; um != *top && !dad->um_black; dad = um->um_dad) {    if (um == dad->um_left) {      brother = dad->um_right;      if (!brother) {	um = dad;	continue;      }      assert(brother->um_black);      if ((!brother->um_left || brother->um_left->um_black) &&	  (!brother->um_right || brother->um_right->um_black)) {	brother->um_black = 0;	um = dad;	continue;      }       if (!brother->um_right || brother->um_right->um_black) {	brother->um_left->um_black = 1;	brother->um_black = 0;	right_rotate(top, brother);	brother = dad->um_right;      }      brother->um_black = dad->um_black;      dad->um_black = 1;      if (brother->um_right)	brother->um_right->um_black = 1;      left_rotate(top, dad);      um = *top;      break;    } else {       assert(um == dad->um_right);      brother = dad->um_left;      if (!brother) {	um = dad;	continue;      }      assert(brother->um_black);      if ((!brother->um_left || brother->um_left->um_black) &&	  (!brother->um_right || brother->um_right->um_black)) {	brother->um_black = 0;	um = dad;	continue;      }       if (!brother->um_left || brother->um_left->um_black) {	brother->um_right->um_black = 1;	brother->um_black = 0;	left_rotate(top, brother);	brother = dad->um_left;      }      brother->um_black = um->um_dad->um_black;      um->um_dad->um_black = 1;      if (brother->um_left)	brother->um_left->um_black = 1;      right_rotate(top, dad);      um = *top;      break;    }  }  um->um_black = 1;}/** Compare paths. */su_inlineint urlmap_pathcmp(url_t const *a, url_t const *b, int *return_hostmatch){  int retval;  retval = url_cmp(a, b);  *return_hostmatch = !retval;  if (retval)    return retval;  else    return strcmp(a->url_path, b->url_path);}/** Insert URL into map. */int url_map_insert(UrlMap ** const tree,		   UrlMap * const um,		   UrlMap **return_old){  UrlMap *old, *dad, **tslot;  url_t *u;  int cmp, hostmatch;  if (tree == NULL || um == NULL || um->um_inserted)    return (errno = EINVAL), -1;  u = um->um_url;  /* Insert into red-black binary tree */  tslot = tree;  for (old = *tree, dad = NULL; old; old = *tslot) {    cmp = urlmap_pathcmp(u, old->um_url, &hostmatch);    if (cmp < 0)      dad = old, tslot = &old->um_left;    else if (cmp > 0)      dad = old, tslot = &old->um_right;    else      break;  }  assert(old != um);  if (old) {    if ((um->um_left = old->um_left))      um->um_left->um_dad = um;    if ((um->um_right = old->um_right))      um->um_right->um_dad = um;    if (!(um->um_dad = old->um_dad))      *tree = um;    else if (um->um_dad->um_left == old)      um->um_dad->um_left = um;    else assert(um->um_dad->um_right == old),      um->um_dad->um_right = um;    um->um_black = old->um_black;    old->um_left = NULL;    old->um_right = NULL;    old->um_dad = NULL;    old->um_inserted = 0;  } else {    *tslot = um;    um->um_dad = dad;    if (tree != tslot) {      red_black_balance_insert(tree, um);    } else {      um->um_black = 1;    }  }  um->um_inserted = 1;  if (return_old)    *return_old = old;  return 0;}/** Find a URL */UrlMap *url_map_find(UrlMap *root,	     url_string_t const *url,	     int relative){  UrlMap *um, *maybe = NULL;  url_t u[1];  void *tbf = NULL;  char *end;  int cmp, hostmatch;  if (root == NULL || url == NULL)    return NULL;  url = tbf = url_hdup(NULL, (url_t *)url);  if (!url)    return NULL;  *u = *url->us_url;  if (!u->url_path)    u->url_path = "";  for (um = root; um; um = cmp < 0 ? um->um_left : um->um_right) {    cmp = urlmap_pathcmp(u, um->um_url, &hostmatch);    if (cmp == 0)      break;    if (hostmatch && !maybe)      maybe = um;  }  while (!um && relative && u->url_path[0]) {    end = strrchr(u->url_path, '/');    end = end ? end + 1 : (char *)u->url_path;    if (*end)      *end = '\0';    for (um = maybe; um; um = cmp < 0 ? um->um_left : um->um_right) {      if ((cmp = urlmap_pathcmp(u, um->um_url, &hostmatch)) == 0)	break;    }  }  su_free(NULL, tbf);  return um;}/** Remove URL. */void url_map_remove(UrlMap **top, UrlMap *um){  UrlMap *kid, *dad;  int need_to_balance;  if (top == NULL || um == NULL || !um->um_inserted)    return;  /* Make sure that node is in tree */  for (dad = um; dad; dad = dad->um_dad)    if (dad == *top)      break;  assert(dad);  if (!dad)    return;  /* Find a successor node with a free branch */  if (!um->um_left || !um->um_right)    dad = um;  else for (dad = um->um_right; dad->um_left; dad = dad->um_left)    ;  /* Dad has a free branch => kid is dad's only child */  kid = dad->um_left ? dad->um_left : dad->um_right;  /* Remove dad from tree */  if (!(dad->um_dad))    *top = kid;  else if (dad->um_dad->um_left == dad)    dad->um_dad->um_left = kid;  else assert(dad->um_dad->um_right == dad),    dad->um_dad->um_right = kid;  if (kid)    kid->um_dad = dad->um_dad;  need_to_balance = kid && dad->um_black;  /* Put dad in place of um */  if (um != dad) {    if (!(dad->um_dad = um->um_dad))      *top = dad;    else if (dad->um_dad->um_left == um)      dad->um_dad->um_left = dad;    else assert(dad->um_dad->um_right == um),      dad->um_dad->um_right = dad;    dad->um_black = um->um_black;        if ((dad->um_left = um->um_left))      dad->um_left->um_dad = dad;          if ((dad->um_right = um->um_right))      dad->um_right->um_dad = dad;        }  um->um_left = NULL;  um->um_right = NULL;  um->um_dad = NULL;  um->um_black = 0;  um->um_inserted = 0;  if (need_to_balance)     red_black_balance_delete(top, kid);}#if TEST_URLMAP/* Functions currently used only by test cases *//** Return inorder successor of node @a um. */UrlMap *url_map_succ(UrlMap *um){  UrlMap *dad;  if (um->um_right) {    for (um = um->um_right; um->um_left; um = um->um_left)      ;    return um;  }  for (dad = um->um_dad; dad && um == dad->um_right; dad = um->um_dad)    um = dad;  return dad;}/** Return inorder precedessor of node @a um. */UrlMap *url_map_prec(UrlMap *um){  UrlMap *dad;  if (um->um_left) {    for (um = um->um_left; um->um_right; um = um->um_right)      ;    return um;  }  for (dad = um->um_dad; dad && um == dad->um_left; dad = um->um_dad)    um = dad;  return dad;}/** Return first node in tree @a um. */UrlMap *url_map_first(UrlMap *um){  while (um && um->um_left)    um = um->um_left;  return um;}/** Return last node in tree @a um. */UrlMap *url_map_last(UrlMap *um){  while (um && um->um_right)    um = um->um_right;  return um;}/** Return height of the tree */int url_map_height(UrlMap const *tree){  int left, right;  if (!tree)    return 0;  left = tree->um_left ? url_map_height(tree->um_left) : 0;  right = tree->um_right ? url_map_height(tree->um_right) : 0;  if (left > right)    return left + 1;  else    return right + 1;}/** Check consistency */staticint redblack_check(UrlMap const *n){  UrlMap const *l, *r;  if (!n)    return 1;  l = n->um_left, r = n->um_right;  if (n->um_black || ((!l || l->um_black) && (!r || r->um_black)))    return (!l || redblack_check(l)) && (!r || redblack_check(r));  else    return 0;}/* Testing functions */int tstflags;#define TSTFLAGS tstflags#include <stdio.h>#include <sofia-sip/tstdef.h>char const *name = "test_urlmap";int test_path(void){  su_home_t *home;  UrlMap *tree = NULL, *o;  UrlMap *um, *um1, *um2, *um3;  BEGIN();  home = su_home_clone(NULL, sizeof(*home)); TEST_1(home);  um1 = url_map_new(home, (void*)"http://host/aa/", sizeof *um1);  TEST_1(um1);  um2 = url_map_new(home, (void*)"http://host/aa/bb/", sizeof *um1);  TEST_1(um2);  um3 = url_map_new(home, (void*)"http://host/aa/bb/cc/",				sizeof *um);  TEST_1(um3);  TEST_1(um1 != um2 && um1 != um3 && um2 != um3);  o = (void *)-1;  TEST(url_map_insert(&tree, um3, &o), 0);  TEST_P(o, NULL); o = (void *)-1;  TEST(url_map_insert(&tree, um2, &o), 0);  TEST_P(o, NULL); o = (void *)-1;  TEST(url_map_insert(&tree, um1, &o), 0);  TEST_P(o, NULL);  um = url_map_find(tree, (void*)"http://host/aa/bb/cc", 1); TEST_P(um, um2);  um = url_map_find(tree, (void*)"http://host/aa/bb/cc/oo", 1);                                                          TEST_P(um, um3);  um = url_map_find(tree, (void*)"http://host/aa/bb", 1); TEST_P(um, um1);  um = url_map_find(tree, (void*)"http://host/aa/bb", 0); TEST_P(um, NULL);  um = url_map_find(tree, (void*)"http://host/aa/bb/", 1); TEST_P(um, um2);  su_home_check(home);  su_home_zap(home);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -