📄 dw_ext_iterator.c
字号:
/* * File: dw_ext_iterator.c * * Copyright (C) 2002 Sebastian Geerken <S.Geerken@ping.de> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. *//* * DwExtIterator is an extension of DwIterator, which stores * DwIterator's in a stack, for cases where recursions are not * possible. * * DwWordIterator is a simple wrapper for DwExtIterator, which splits * text segments into words, and is used for text search (in * findtext.c) * * todo: In some cases (e.g. for "<i>foo</i>bar"), DwIterator and * DwExtIterator return two words, where there is actually only * one. In this case, iterator->content.space is set to FALSE. * DwWordIterator currently ignores this flag, but instead * returns two words, instead of concaternating them to one. */#include "dw_ext_iterator.h"#include "list.h"#include "misc.h"/*#define DEBUG_LEVEL 1*/#include "debug.h"/* * The following two functions are used by a_Dw_extiterator_new, when the * passed DwIterator points to a widget. Since a DwExtIterator never returns * a widget, the DwIterator has to be corrected, by searching for the next * content downwards (within the widget pointed to), forwards, and backwards * (in the traversed tree). *//* * Search downwards. If from_end is TRUE, start search at the end, * otherwise at the beginning. * The pararameter indent is only for debugging purposes. */static DwIterator *Dw_ext_iterator_search_downward (DwIterator *it, gboolean from_end, int indent){ DwIterator *it2, *it3; DEBUG_MSG (1, "%*smoving down (%swards) from %s\n", indent, "", from_end ? "back" : "for", a_Dw_iterator_text (it)); g_return_val_if_fail (it->content.type == DW_CONTENT_WIDGET, NULL); it2 = a_Dw_widget_iterator (it->content.data.widget, it->mask, from_end); if (it2 == NULL) { /* Moving downwards failed. */ DEBUG_MSG (1, "%*smoving down failed\n", indent, ""); return NULL; } while (from_end ? a_Dw_iterator_prev (it2) : a_Dw_iterator_next (it2)) { DEBUG_MSG (1, "%*sexamining %s\n", indent, "", a_Dw_iterator_text (it2)); if (it2->content.type == DW_CONTENT_WIDGET) { /* Another widget. Search in it downwards. */ it3 = Dw_ext_iterator_search_downward (it2, from_end, indent + 3); if (it3 != NULL) { a_Dw_iterator_free (it2); return it3; } /* Else continue in this widget. */ } else { /* Success! */ DEBUG_MSG (1, "%*smoving down succeeded: %s\n", indent, "", a_Dw_iterator_text (it2)); return it2; } } /* Nothing found. */ a_Dw_iterator_free (it2); DEBUG_MSG (1, "%*smoving down failed (nothing found)\n", indent, ""); return NULL;}/* * Search sidewards. from_end specifies the direction, FALSE means forwards, * TRUE means backwards. * The pararameter indent is only for debugging purposes. */static DwIterator *Dw_ext_iterator_search_sideward (DwIterator *it, gboolean from_end, int indent){ DwIterator *it2, *it3; DEBUG_MSG (1, "%*smoving %swards from %s\n", indent, "", from_end ? "back" : "for", a_Dw_iterator_text (it)); g_return_val_if_fail (it->content.type == DW_CONTENT_WIDGET, NULL); it2 = a_Dw_iterator_clone (it); while (from_end ? a_Dw_iterator_prev (it2) : a_Dw_iterator_next (it2)) { if (it2->content.type == DW_CONTENT_WIDGET) { /* Search downwards in this widget. */ it3 = Dw_ext_iterator_search_downward (it2, from_end, indent + 3); if (it3 != NULL) { a_Dw_iterator_free (it2); DEBUG_MSG (1, "%*smoving %swards succeeded: %s\n", indent, "", from_end ? "back" : "for", a_Dw_iterator_text (it3)); return it3; } /* Else continue in this widget. */ } else { /* Success! */ DEBUG_MSG (1, "%*smoving %swards succeeded: %s\n", indent, "", from_end ? "back" : "for", a_Dw_iterator_text (it2)); return it2; } } /* Nothing found, go upwards in the tree (if possible). */ a_Dw_iterator_free (it2); if (it->widget->parent) { it2 = a_Dw_widget_iterator (it->widget->parent, it->mask, FALSE); while (TRUE) { if (!a_Dw_iterator_next(it2)) { g_warning ("BUG in DwExtIterator!"); a_Dw_iterator_free (it2); return NULL; } if (it2->content.type == DW_CONTENT_WIDGET && it2->content.data.widget == it->widget) { it3 = Dw_ext_iterator_search_sideward (it2, from_end, indent + 3); a_Dw_iterator_free (it2); DEBUG_MSG (1, "%*smoving %swards succeeded: %s\n", indent, "", from_end ? "back" : "for", a_Dw_iterator_text (it3)); return it3; } } } /* Nothing found at all. */ DEBUG_MSG (1, "%*smoving %swards failed (nothing found)\n", indent, "", from_end ? "back" : "for"); return NULL;}/* * Create a new DwExtIterator from an existing DwIterator. The content of the * return value will be the content of "it". If within the widget tree, there * is no non-widget content, NULL is returned. * * NOTES: * (i) If you want to continue using "it", pass a_Dw_iterator_clone (it). * (ii) The mask of "it" must include DW_CONTENT_WIDGET, but * a_Dw_ext_iterator_next will never return widgets. * * TODO: Change in the near future: NULL is by all other functions within this * module interpreted as an "empty" iterator, which makes code outside more * robust. */DwExtIterator* a_Dw_ext_iterator_new (DwIterator *it){ DwExtIterator *eit; DwIterator *it2; DwWidget *w; int sp; DEBUG_MSG (1, "a_Dw_ext_iterator_new: %s\n", a_Dw_iterator_text (it)); /* If "it" points to a widget, find a near non-widget content, * since an DwExtIterator should never return widgets. */ if (it->content.type == DW_CONTENT_WIDGET) { /* The second argument of Dw_ext_iterator_search_downward is * actually a matter of taste :-) */ if ((it2 = Dw_ext_iterator_search_downward (it, FALSE, 3)) || (it2 = Dw_ext_iterator_search_sideward (it, FALSE, 3)) || (it2 = Dw_ext_iterator_search_sideward (it, TRUE, 3))) { a_Dw_iterator_free (it); it = it2; } else { /* This may happen, when a page does not contain any * non-widget content. */ DEBUG_MSG (1, "a_Dw_ext_iterator_new got totally helpless!\n"); a_Dw_iterator_free (it); return NULL; } } DEBUG_MSG (1, " => %s\n", a_Dw_iterator_text (it)); eit = g_new (DwExtIterator, 1); eit->stack_top = 0; /* If this widget has parents, we must construct appropiate iterators. * todo: There may be a faster way instead of iterating through the * parent widgets. */ for (w = it->widget; w->parent != NULL; w = w->parent) eit->stack_top++; eit->stack_max = 4; while (eit->stack_top >= eit->stack_max) eit->stack_max <<= 1; eit->stack = g_new (DwIterator*, eit->stack_max); /* Construct the iterators. */ for (w = it->widget, sp = eit->stack_top - 1; w->parent != NULL; w = w->parent, sp--) { eit->stack[sp] = a_Dw_widget_iterator (w->parent, it->mask, FALSE); while (TRUE) { if (!a_Dw_iterator_next(eit->stack[sp])) { g_warning ("BUG in DwExtIterator!"); return NULL; } if (eit->stack[sp]->content.type == DW_CONTENT_WIDGET && eit->stack[sp]->content.data.widget == w) break; } } eit->stack[eit->stack_top] = it; eit->content = it->content; return eit;}/* * This function is similar to a_Dw_ext_iterator_new, but is in many * cases faster, since it tries to copy parts of the stack of "base". * Used for selection, where the old and new position (which are * represented by DwExtIterator) are often quite next to each other. * "base" may be NULL. */DwExtIterator* a_Dw_ext_iterator_new_variant (DwExtIterator *base, DwIterator *it){ /* todo: Not yet implemented, and actually not yet needed very much. */ return a_Dw_ext_iterator_new (it);}/* * Move iterator forward and store content in it. Returns TRUE on * success. */gboolean a_Dw_ext_iterator_next (DwExtIterator *eit){ DwIterator *it = eit->stack[eit->stack_top]; if (a_Dw_iterator_next(it)) { if (it->content.type == DW_CONTENT_WIDGET) { /* Widget: new iterator on stack, to search in this widget. */ eit->stack_top++; a_List_add (eit->stack, eit->stack_top, eit->stack_max); eit->stack[eit->stack_top] = a_Dw_widget_iterator (it->content.data.widget, it->mask, FALSE); return a_Dw_ext_iterator_next (eit); } else { /* Simply return the content of the iterartor. */ eit->content = it->content; return TRUE; } } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -