/**
 * Split a range into 3 parts to accommodate a tree-node
 * @param d the dom in question
 * @param n the node in the tree
 * @param r the out of tree range r to split up
 */
static void dom_breakup_range( dom *d, node *n, node *r )
{
    node *r2;
    if ( node_offset(n) > node_offset(r) )
    {
        node_split( r, node_offset(n) );
        r2 = node_next_sibling( r );
        node_detach_sibling( r, NULL );
        dom_store_range( d, node_to_range(r) );
        //queue_push( d->q, node_to_range(r) );
        node_dispose( r );
    }
    else
        r2 = r;
    if ( node_end(r2)>node_end(n) )
    {
        node *r3;
        node_split( r2, node_end(n) );
        r3 = node_next_sibling(r2);
        node_detach_sibling(r3,r2);
        dom_store_range( d, node_to_range(r3) );
        //queue_push( d->q, node_to_range(r3) );
        node_dispose(r3);
    }
    dom_node_equals( d, n, r2 );
}
/**
 * Does the node properly contain the range (now a node)?
 * @param n the node already in the tree
 * @param r a loose node looking for a home
 * @return 1 if n encloses r by a greater range
 */
static int node_encloses_range( node *n, node *r )
{
    int r_end = node_end(r);
    int n_end = node_end(n);
    if ( node_offset(n) == node_offset(r) && r_end==n_end )
        return 0;
    else
        return node_offset(n)<=node_offset(r) && n_end>=r_end;
}
/**
 * Split a node into 3 parts to accommodate a range
 * @param d the dom in question
 * @param n the node in the tree to split up
 * @param r the out of tree node r that overlaps with n
 */
static void dom_breakup_node( dom *d, node *n, node *r )
{
    node *n2;
    if ( node_offset(r) > node_offset(n) )
    {
        node_split( n, node_offset(r) );
        n2 = node_next_sibling( n );
    }
    else
        n2 = n;
    if ( node_end(r) < node_end(n2) )
        node_split( n2, node_end(r) );
    dom_node_equals( d, n2, r );
}
static int setprop_cell(void *fdt, const char *node_path,
			const char *property, uint32_t val)
{
	int offset = node_offset(fdt, node_path);
	if (offset < 0)
		return offset;
	return fdt_setprop_cell(fdt, offset, property, val);
}
static int setprop_string(void *fdt, const char *node_path,
			  const char *property, const char *string)
{
	int offset = node_offset(fdt, node_path);
	if (offset < 0)
		return offset;
	return fdt_setprop_string(fdt, offset, property, string);
}
static int setprop(void *fdt, const char *node_path, const char *property,
		   uint32_t *val_array, int size)
{
	int offset = node_offset(fdt, node_path);
	if (offset < 0)
		return offset;
	return fdt_setprop(fdt, offset, property, val_array, size);
}
static int setprop_values(void *fdt, const char *node_path,
			  const char *property, const void *val, int len)
{
	int offset = node_offset(fdt, node_path);
	if (offset < 0)
		return offset;
	return fdt_setprop(fdt, offset, property, val, len);
}
/**
 * Try to make the new node into a parent of the tree-node n. The problem 
 * here is that we must include any siblings of n in r if they fit.
 * @param n the node above which to add the parent
 * @param r the new unattached node 
 */
static void dom_make_parent( dom *d, node *n, node *r )
{
    node *parent = node_parent(n);
    node *prev = node_prec_sibling( n );
    if ( parent==NULL )
        printf("parent is NULL\n");
    //fprintf( stderr,"n: %s %d:%d; r %s %d:%d\n",node_name(n),node_offset(n),
    //    node_end(n),node_name(r),node_offset(r),node_end(r));
    //node_debug_check_siblings( node_first_child(parent) );
    while ( n != NULL && !node_follows(r,n) )
    {
        node *next = node_next_sibling(n);
        if ( dom_nests(d,node_name(n),node_name(r)) )
        {
            if ( range_encloses_node(n,r) || range_equals_node(n,r) )
            {
                node_detach_sibling( n, prev );
                node_add_child( r, n );
                if ( node_overlaps_on_right(parent,r) )
                {
                    node_split( r, node_end(parent) );
                    node *r2 = node_next_sibling( r );
                    node_detach_sibling( r, NULL );
                    dom_store_range( d, node_to_range(r2) );
                    node_dispose( r2 );
                }
            }
            else if ( node_overlaps_on_left(n,r) )
            {
                node_split( n, node_end(r) );
                node_detach_sibling( n, prev );
                node_add_child( r, n );
                break;
            }
            else
                break;
        }
        else 
        {
            // split off the rest of r and and push it back
            // Q: what happens to r??
            node *r2;
            node_split( r, node_offset(n) );
            r2 = node_next_sibling( r );
            node_detach_sibling( r, NULL );
            dom_store_range( d, node_to_range(r2) );
            //queue_push( d->q, node_to_range(r2) );
            node_dispose( r2 );
            break;
        }
        n = next;
        if ( n != NULL )
            prev = node_prec_sibling( n );
    }
    // make n's original parent the parent of r
    node_add_child( parent, r );
   // node_debug_check_siblings( node_first_child(parent) );
}
/**
 * Write to the console details of the dropped node
 * @param d the dom in question
 * @param r the node we are dropping
 * @param n the parent node
 */
static void dom_drop_notify( dom *d, node *r, node *n )
{
    warning("dom: dropping %s at %d:%d - %s and %s incompatible\n",
        node_name(r),node_offset(r),
        node_end(r),node_html_name(r),node_html_name(n));
    attribute *id = node_get_attribute( r, "id" );
    if ( id != NULL )
    {
        char *value = attribute_get_value( id );
        if ( value[strlen(value)-1]=='b' )
            printf( "aha! dropping id %s\n",value );
    }
    node_dispose( r );
}
/**
 * Print a single node and its children, siblings
 * @param d the dom in question
 * @param n the node to print
 */
static void dom_print_node( dom *d, node *n )
{
	node *c;
    int start,end;
    char *html_name = node_html_name(n);
    char *class_name = node_name(n);
    char attrs[128];
    node_get_attributes( n, attrs, 128 );
    if ( !node_empty(n) )
    {
        if ( !node_is_root(n) )
            dom_concat( d, "<%s%s class=\"%s\">", strlen(html_name)
                +strlen(class_name)+strlen(attrs)+11, html_name, 
                attrs, class_name );
    }
    c = node_first_child(n);
    start = node_offset(n);
    end = node_end(n);
    while ( c != NULL )
    {
        int pos = node_offset( c );
        if ( pos > start )
            dom_print_text( d, start, pos-start );
        dom_print_node( d, c );
        start = node_end( c );
        c = node_next_sibling( c );
    }
    if ( end > start )
        dom_print_text( d, start, end-start );
    if ( !node_is_root(n) )
    {
        if ( !node_empty(n) )
            dom_concat(d, "</%s>",strlen(html_name)+3, html_name);
        else if ( node_rightmost(n) )
            dom_concat(d,"<%s>",strlen(html_name)+2,html_name);
    }
}
/**
 * Handle overlap on the right of a tree-node
 * @param d the dom in question
 * @param n the node to test against
 * @param r the rogue who overlaps on the right
 */
static void dom_range_overlaps_right( dom *d, node *n, node *r )
{
    if ( dom_mostly_nests(d,node_name(n),node_name(r)) )
    {
        node_split( n, node_offset(r) );
        dom_add_node( d, node_next_sibling(n), r );
    }
    else if ( dom_mostly_nests(d,node_name(r),node_name(n)) )
    {
        node *r2;
        node_split( r, node_end(n) );
        r2 = node_next_sibling(r);
        node_detach_sibling( r, NULL );
        dom_store_range( d, node_to_range(r2) );
        //queue_push( d->q, node_to_range(r2) );
        node_dispose( r2 );
        dom_add_node( d, n, r );
    }
    else
        dom_drop_notify( d, r, n );
}
/**
 * Check a single tree-node, recursively
 */
static int dom_check_node( node *n )
{
    int res = 1;
    int start = node_offset(n);
    int end = node_end(n);
    node *c = node_first_child(n);
    node *prev = NULL;
    while ( c != NULL )
    {
        node *next = node_next_sibling( c );
        if ( node_offset(c)<start )
        {
            warning("dom: invalid offset %d < parent start %d\n",node_offset(c),
                start);
            return 0;
        }
        else if ( node_end(c)>end )
        {
            warning("dom: invalid end %d (%s) > parent end %d (%s)\n",
                node_end(c), node_name(c), end, node_name(n) );
            return 0;
        }
        else if ( prev != NULL && node_end(prev)>node_offset(c) )
        {
            warning("dom: prev node ending %d encroaches on child node at %d\n",
                node_end(prev), node_offset(c));
            return 0;
        }
        else if ( next != NULL && node_end(c)>node_offset(next) )
        {
            warning("dom: next node starting %d encroaches on child node ending at %d\n",
                node_offset(next), node_end(c));
            return 0;
        }
        else
            res = dom_check_node( c );
        prev = c;
        c = node_next_sibling( c );
    }
    return res;
}
/**
 * Build the dom
 * @param d the dom object to build
 */
int dom_build( dom *d )
{
    int res = 1;
    while ( !queue_empty(d->q) )
    {
        range *rx = queue_pop( d->q );
        node *r = dom_range_to_node( d, rx );
        if ( r != NULL )
        {
            if ( node_end(r) <= d->text_len )
                dom_add_node( d, d->root, r );
            else
            {
                fprintf(stderr,"node range %d:%d > text length (%d)\n",
                    node_offset(r),node_end(r), d->text_len );
                node_dispose( r );
                res = 0;
                break;
            }
        }
    }
    //matrix_dump( d->pm );
    return res;
}
Exemple #14
0
/*
 * return a relative path from @from to @to
 * result should be freed
 */
char *
relative_path_to(char *from, char *to, int *err)
{
	int from_nodes, common;
	char *to_absolute, *from_absolute;
	char *up, *common_target_path, *relative_path;

	*err          = 0;
	up            = NULL;
	to_absolute   = NULL;
	from_absolute = NULL;
	relative_path = NULL;

	if (strnlen(to, MAX_NAME_LEN)   == MAX_NAME_LEN ||
	    strnlen(from, MAX_NAME_LEN) == MAX_NAME_LEN) {
		EPRINTF("invalid input; max path length is %d\n",
			MAX_NAME_LEN);
		*err = -ENAMETOOLONG;
		return NULL;
	}

	to_absolute = realpath(to, NULL);
	if (!to_absolute) {
		EPRINTF("failed to get absolute path of %s\n", to);
		*err = -errno;
		goto out;
	}

	from_absolute = realpath(from, NULL);
	if (!from_absolute) {
		EPRINTF("failed to get absolute path of %s\n", from);
		*err = -errno;
		goto out;
	}

	if (strnlen(to_absolute, MAX_NAME_LEN)   == MAX_NAME_LEN ||
	    strnlen(from_absolute, MAX_NAME_LEN) == MAX_NAME_LEN) {
		EPRINTF("invalid input; max path length is %d\n",
			MAX_NAME_LEN);
		*err = -ENAMETOOLONG;
		goto out;
	}

	/* count nodes in source path */
	from_nodes = count_nodes(from_absolute);

	/* count nodes in common */
	common = count_common_nodes(to_absolute + 1, from_absolute + 1);
	if (common < 0) {
		EPRINTF("failed to count common nodes of %s and %s: %d\n",
			to_absolute, from_absolute, common);
		*err = common;
		goto out;
	}

	/* move up to common node */
	up = up_nodes(from_nodes - common - 1);
	if (!up) {
		EPRINTF("failed to allocate relative path for %s: %d\n",
			from_absolute, -ENOMEM);
		*err = -ENOMEM;
		goto out;
	}

	/* get path from common node to target */
	common_target_path = node_offset(to_absolute, common + 1);
	if (!common_target_path) {
		EPRINTF("failed to find common target path to %s: %d\n",
			to_absolute, -EINVAL);
		*err = -EINVAL;
		goto out;
	}

	/* get relative path */
	if (asprintf(&relative_path, "%s%s", up, common_target_path) == -1) {
		EPRINTF("failed to construct final path %s%s: %d\n",
			up, common_target_path, -ENOMEM);
		relative_path = NULL;
		*err = -ENOMEM;
		goto out;
	}

out:
	sfree(up);
	sfree(to_absolute);
	sfree(from_absolute);

	return relative_path;
}
/**
 * Is an unattached node equal to a dom-attached node
 * @param n the node in the tree
 * @param r the unattached node aka range
 * @return 1 if they have the same range
 */
static int range_equals_node( node *n, node *r )
{
    return node_offset(n)==node_offset(r) && node_len(n)==node_len(r);
}