void nodeInsertChildAt(struct Node* parent, struct Node* child, unsigned int index) { child->parent = parent; // find target node unsigned int node_index = 0; auto node = parent->firstChild; while (node) { if (node_index == index) { break; } node = node->next; node_index++; } if (node_index == index) { // reset node link child->prev = node->prev; child->next = node; child->next->prev = child; if (child->prev) { child->prev->next = child; } if (index == 0) { parent->firstChild = child; } insertChildElementAt(&parent->element, &child->element, index); } else { nodeAddChild(parent, child); } }
Node makeTextBlock (Node a, Node b) { if (!a) return b; if (!b) return a; if (a->type == TextBlock && b->type == TextBlock) { nodeAddChild (a, b->firstChild); /* We have attached b's children elsewhere, so don't use freeRecursively */ freeNode (b); return a; } else if (a->type == TextBlock) return nodeAddChild (a, b); else if (b->type == TextBlock) return nodePrependChild (b, a); else return nodeAddChild2 (newNode (TextBlock), a, b); }
/* Parameter must be a ListLine node. Returns a List node. */ Node processListHelper (Node start) { NodeType type, subtype; Node result, curChild, examine, item, previous, l, toBeFreed; if (!start) return 0; if (start->type != ListLine) return 0; if (!start->firstChild) return 0; type = start->firstChild->type; result = newNodeI (List, type == ListBullet ? 1 : type == ListNumbered ? 2 : type == ListIdent ? 3 : 0); curChild = 0; examine = start; while (examine) { toBeFreed = examine; /* We know that examine->firstChild is ListBullet, ListNumbered, etc. Remove it */ removeAndFreeFirstChild (examine); /* Empty list item? */ if (!examine->firstChild) { examine = examine->nextSibling; freeNode (toBeFreed); } /* Does this item start a new list? */ else if (examine->firstChild->type == ListBullet || examine->firstChild->type == ListNumbered || examine->firstChild->type == ListIdent) { /* If we are starting a new list, we want it to be inside the previous list item. */ /* However, if that previous list item does not exist, we need to create a new one. */ if (!curChild) { item = newNode (ListItem); result->firstChild = item; curChild = item; } subtype = examine->firstChild->type; /* progressively remove the firstChild for that sublist */ previous = examine; l = examine->nextSibling; while (l && l->firstChild && l->firstChild->nextSibling && l->firstChild->nextSibling->type == subtype) { removeAndFreeFirstChild (l); previous = l; l = l->nextSibling; } /* trick recursive call into thinking list ends here */ previous->nextSibling = 0; /* notice that the recursive call will take care of freeing the node */ nodeAddChild (curChild, processListHelper (examine)); previous->nextSibling = l; examine = l; } /* Otherwise it's a normal plain old list item */ else { item = newNode (ListItem); if (curChild) curChild->nextSibling = item; else result->firstChild = item; curChild = item; nodeAddChild (curChild, examine->firstChild); examine = examine->nextSibling; freeNode (toBeFreed); } } return result; }
Node processNestedItalics (Node node) { Node examine, saveExamineSibling, childExamine, childSibling, saveChildSibling; if (!node) return 0; if (node->type != TextBlock) return node; /****** EXAMPLE ****** * * (*) node(type=TextBlock) * | * | firstChild * | * |A(type=TextToken) B(type=Italics) C(type=TextToken) * (*)---nextSibling---(*)---nextSibling---(*) * | * | firstChild * | * (*) T(type=TextBlock) * | * | firstChild * | * |W(type=TextToken) X(type=Italics) Y(type=TextToken) * (*)---nextSibling---(*)---nextSibling---(*) * | * | firstChild * | * (*) Z * * Here we have two Italics nodes nested inside each other (X is inside B). * The following is the end-result: * * (*) node(type=TextBlock) * | * | firstChild * | B new * |A Italics Z Italics C * (*)--nextSibling--(*)--nextSibling--(*)--nextSibling--(*)--nextSibling--(*) * | firstChild | firstChild * (*) T (*) Y * | firstChild * (*) W * * T is no longer really necessary, but specifically freeing it is pointless, so we keep it. * */ for (examine = node->firstChild; examine; examine = examine->nextSibling) { /* In the above example, examine = B, but as new nodes are created and made siblings of B, * examine walks along them. Either way, it is the node just before C. */ if (examine->type == Italics && examine->firstChild && examine->firstChild /* i.e. T */->type == TextBlock) { /* Remember B's original sibling (C). We are going to insert a number of new * siblings after B, so at the end we want to re-attach C to the last one. */ saveExamineSibling = examine->nextSibling; childExamine = examine->firstChild /* i.e. T */->firstChild /* i.e. W */; /* childSibling will be our "iterator" for iterating over the children of T */ childSibling = childExamine->nextSibling; childExamine->nextSibling = 0; /* Detach W's siblings */ while (childSibling) { /* Remember the sibling we want to move on to later */ saveChildSibling = childSibling->nextSibling; /* If we find a nested Italics (X in the example), move its child (Z) out * and make it a sibling of B. */ if (childSibling->type == Italics) { examine->nextSibling = childSibling->firstChild; /* Move examine on to the newly created sibling */ examine = examine->nextSibling; /* Free the now-obsolete Italics node */ /* We have attached its children elsewhere, so don't use freeRecursively */ freeNode (childSibling); } /* Any node that is not an Italics node needs to become attached to one. * (In the above example, this is only Y.) */ else { /* Detach the two */ childSibling->nextSibling = 0; /* If examine already points to an Italics node, don't create a new one. */ /* Instead, combine its child and this one. (Doesn't occur in the example.) */ if (examine->type == Italics) examine->firstChild = makeTextBlock (examine->firstChild, childSibling); else { /* Create a new Italics node, attach the current node (Y) to it, and make * it the next-distant sibling of B */ examine->nextSibling = nodeAddChild (newNode (Italics), childSibling); examine = examine->nextSibling; } } childSibling = saveChildSibling; } /* Now re-attach the previous sibling of B (i.e. C). */ examine->nextSibling = saveExamineSibling; } } return node; }
/* Return value is the first parameter */ Node nodePrependChild (Node node, Node child) { Node prevChild = node->firstChild; node->firstChild = child; return nodeAddChild (node, prevChild); }