/** * 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; }
/* * 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); }