diff --git a/src/compose/table.c b/src/compose/table.c index 078b719a0..f58332686 100644 --- a/src/compose/table.c +++ b/src/compose/table.c @@ -314,28 +314,47 @@ xkb_compose_table_iterator_current(struct xkb_compose_table_iterator *iter) XKB_EXPORT struct xkb_compose_table_entry * xkb_compose_table_iterator_next(struct xkb_compose_table_iterator *iter) { + /* + * This function takes the following recursive traversal function, + * and makes it non-recursive and resumable. The iter->cursors stack + * is analogous to the call stack, and cursor->direction to the + * instruction pointer of a stack frame. + * + * traverse(xkb_keysym_t *sequence, size_t sequence_length, uint16_t p) { + * if (!p) return + * // cursor->direction == NODE_LEFT + * node = &darray_item(table->nodes, p) + * traverse(sequence, sequence_length, node->lokid) + * // cursor->direction == NODE_DOWN + * sequence[sequence_length++] = node->keysym + * if (node->is_leaf) + * emit(sequence, sequence_length, node->leaf.keysym, table->utf[node->leaf.utf8]) + * else + * traverse(sequence, sequence_length, node->internal.eqkid) + * sequence_length-- + * // cursor->direction == NODE_RIGHT + * traverse(sequence, sequence_length, node->hikid) + * // cursor->direction == NODE_UP + * } + */ + struct xkb_compose_table_iterator_cursor *cursor; - struct xkb_compose_table_iterator_cursor new_cursor; const struct compose_node *node; - cursor = &darray_item(iter->cursors, darray_size(iter->cursors) - 1); - new_cursor.direction = NODE_LEFT; - - while (cursor->direction < NODE_UP) { + while (!darray_empty(iter->cursors)) { + cursor = &darray_item(iter->cursors, darray_size(iter->cursors) - 1); node = &darray_item(iter->table->nodes, cursor->node_offset); - if (cursor->direction == NODE_LEFT) { - /* Left node */ + switch (cursor->direction) { + case NODE_LEFT: cursor->direction = NODE_DOWN; if (node->lokid) { - new_cursor.node_offset = node->lokid; + struct xkb_compose_table_iterator_cursor new_cursor = {node->lokid, NODE_LEFT}; darray_append(iter->cursors, new_cursor); - cursor = &darray_item(iter->cursors, darray_size(iter->cursors) - 1); - continue; } - } - if (cursor->direction == NODE_DOWN) { - /* Down node */ + break; + + case NODE_DOWN: cursor->direction = NODE_RIGHT; assert (iter->entry.sequence_length <= MAX_LHS_LEN); iter->entry.sequence[iter->entry.sequence_length] = node->keysym; @@ -345,32 +364,25 @@ xkb_compose_table_iterator_next(struct xkb_compose_table_iterator *iter) iter->entry.utf8 = &darray_item(iter->table->utf8, node->leaf.utf8); return &iter->entry; } else { - new_cursor.node_offset = node->internal.eqkid; + struct xkb_compose_table_iterator_cursor new_cursor = {node->internal.eqkid, NODE_LEFT}; darray_append(iter->cursors, new_cursor); - cursor = &darray_item(iter->cursors, darray_size(iter->cursors) - 1); - continue; } - } - cursor->direction = NODE_UP; - iter->entry.sequence_length--; - if (node->hikid) { - /* Right node */ - new_cursor.node_offset = node->hikid; - darray_append(iter->cursors, new_cursor); - cursor = &darray_item(iter->cursors, darray_size(iter->cursors) - 1); - continue; - } else { - /* Look for next node in parents */ - while (darray_size(iter->cursors) > 1) { - darray_remove_last(iter->cursors); - cursor = &darray_item(iter->cursors, darray_size(iter->cursors) - 1); - if (cursor->direction < NODE_UP) { - break; - } + break; + + case NODE_RIGHT: + cursor->direction = NODE_UP; + iter->entry.sequence_length--; + if (node->hikid) { + struct xkb_compose_table_iterator_cursor new_cursor = {node->hikid, NODE_LEFT}; + darray_append(iter->cursors, new_cursor); } + break; + + case NODE_UP: + darray_remove_last(iter->cursors); + break; } } return NULL; - }