Back to index

tetex-bin  3.0
Classes | Defines | Functions
search-internal.h File Reference
#include "xdvi-config.h"
#include "xdvi.h"
#include "search-dialog.h"
#include "dvisel.h"
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  pos_info
struct  page_mapping
struct  word_info

Defines

#define Xdvi_SEARCHBOX_INPUT_NAME   "searchbox_input"
#define Xdvi_SEARCH_POPUP_NAME   "find_popup"
#define TEST_DELAY(s)   /* as nothing */

Functions

void search_dvi (XtPointer settings)
void search_restart (XtPointer settings)
Boolean search_extract_text (outputFormatT fmt, struct select_pages_info *pinfo)
Boolean search_have_match (int pageno)
int search_inside_bbox_match (int x, int y)
void search_draw_inverted_regions (void)
void search_signal_page_changed (void)
void search_reset_info (void)
void search_erase_highlighting (Boolean flag)
void search_putback_expose (void)
char * get_text_selection (int *len, int x, int y, int w, int h)

Class Documentation

struct pos_info

Definition at line 40 of file search-internal.h.

Class Members
size_t buffer_pos
struct page_mapping

Definition at line 45 of file search-internal.h.

Class Members
int offset
int pageno
struct word_info

Definition at line 50 of file search-internal.h.

Collaboration diagram for word_info:
Class Members
Boolean bbox_pass
struct bbox * bboxes
size_t bboxes_idx
size_t bboxes_size
int buffer_offset
size_t curr_buf_idx
struct page_mapping * page_mapping
Boolean search_scan_pass
struct search_settings * settings
Boolean text_selection_pass
char * txt_buf
size_t txt_buf_size

Define Documentation

#define TEST_DELAY (   s)    /* as nothing */

Definition at line 87 of file search-internal.h.

#define Xdvi_SEARCH_POPUP_NAME   "find_popup"

Definition at line 34 of file search-internal.h.

#define Xdvi_SEARCHBOX_INPUT_NAME   "searchbox_input"

Definition at line 33 of file search-internal.h.


Function Documentation

char* get_text_selection ( int len,
int  x,
int  y,
int  w,
int  h 
)

Definition at line 1010 of file search-internal.c.

{
    struct word_info txt_info = { NULL, 0, 0, NULL, 0, 0, NULL, NULL, 0, False, False, True };
    struct bbox text_bbox;
    
    text_bbox.ulx = ulx;
    text_bbox.uly = uly;
    text_bbox.lrx = lrx;
    text_bbox.lry = lry;

    txt_info.bboxes = &text_bbox;

    /* initialize buffer with empty string */
    txt_info.txt_buf_size = 1;
    txt_info.txt_buf = xmalloc(txt_info.txt_buf_size);
    txt_info.txt_buf[0] = '\0';

    /* this enlarges the buffer as needed */
    scan_page(globals.dvi_file.bak_fp, current_page, &txt_info);
    
    *len = txt_info.txt_buf_size;
    return txt_info.txt_buf;
    
#if 0
    /*     fprintf(stderr, "========== SELECTION (len %d):\n", txt_info.curr_buf_idx); */
    /*     dump_buffer(&txt_info, 0, stderr, FMT_ISO_8859_1); */
    /*     fprintf(stderr, "==========\n"); */

    buf = xmalloc(4 * txt_info.curr_buf_idx + 1); /* just in case we get many non-printables */
    while (i < txt_info.curr_buf_idx) {
       uint32_t ucs4;
       const char *ret;
       
       /* first apply normalization heurisitcs also used by search */
       size_t len = utf8_to_ucs4(txt_info.txt_buf + i, &ucs4, strlen(txt_info.txt_buf + i));
       if ((ret = search_normalize_chars(ucs4)) != NULL) {
           size_t len_ret = strlen(ret);
           memcpy(buf + offset, ret, len_ret);
           offset += len_ret;
       }      
       else if (ucs4 <= 0xff) { /* in iso-latin1 range */
           buf[offset++] = (unsigned char)ucs4;
       }
       else {
           sprintf(buf + offset, "\\%.4lX", ucs4);
           offset += 4;
       }
       i += len;
    }
    buf[offset] = '\0';
    free(txt_info.txt_buf);
    return buf;
#endif /* 0 */
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 347 of file search-internal.c.

{
    if (m_info != NULL) {
       draw_bboxes(m_info);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

void search_dvi ( XtPointer  settings)

Definition at line 1430 of file search-internal.c.

{
    struct search_settings *settings = (struct search_settings *)arg;
    struct search_info *searchinfo = settings->searchinfo;
    
#if HAVE_REGEX_H
    static regex_t regex;
#endif /* HAVE_REGEX_H */
    
    /* a mapping of page numbers to index positions in w_info->txt_buf,
       for the 2 pages that we scanned */
    static struct page_mapping page_mapping[2] = { { -1, -1 }, { -1, -1 } };
    
    static struct word_info w_info = { NULL, 0, 0, NULL, 0, 0, NULL, NULL, 0, False, False, False };

    static time_t dvi_time_bak = 0;
    static char *searchterm_bak = NULL;

    static const char *text_encoding = NULL;

    static Boolean case_sensitive_bak = False;
    static Boolean ignore_hyphens_bak = False;
    static Boolean ignore_linebreaks_bak = False;
    static searchDirectionT direction_bak = SEARCH_UNINITIALIZED;
    /* from_pos_bak is needed to mark the start of the match when switching from
       search down to search backwards, where we want to jump to the previous match,
       so we need the start of the current match again (and down search sets
       searchinfo->from_pos = searchinfo->to_pos) */
    static int from_pos_bak = -1;
    int curr_page = settings->from_page;

    Boolean reinit = False;
    Boolean recompile_regexp = False;
    Boolean adjust_hyphen_offset = False;
    
    /* prevent multiple invocations while still busy searching */
    if (searchinfo->locked) {
       TRACE_FIND((stderr, "LOCKED"));
       return;
    }
    searchinfo->locked = True;

    if (dvi_time_bak == 0) { /* first invocation */
       case_sensitive_bak = settings->case_sensitive;
       ignore_hyphens_bak = settings->ignore_hyphens;
       ignore_linebreaks_bak = settings->ignore_linebreaks;
       dvi_time_bak = globals.dvi_file.time;
    }
    if (globals.dvi_file.time > dvi_time_bak) {
       dvi_time_bak = globals.dvi_file.time;
       reinit = True;
    }

    m_match_page = -1;
    
    if (raise_message_windows()) { /* any popups user still needs to deal with? */
       TRACE_GUI((stderr, "Still open message windows to deal with, returning ..."));
       searchinfo->locked = False;
       return;
    }

    ASSERT(settings->term != NULL, "settings->term mustn't be NULL!");
    if (strlen(settings->term) == 0) {
       positioned_popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
                             MSG_ERR,
                             settings->x_pos, settings->y_pos,
                             NULL, "Empty search term");
       searchinfo->locked = False;
       return;
    }
    
    TRACE_FIND((stderr, "dvi_search: Searching for |%s| from page %d", settings->term, settings->from_page));
    TRACE_FIND((stderr, "  settings: down = %d, re = %d, case = %d",
              settings->direction, settings->use_regexp, settings->case_sensitive));

    if (m_changed_page) {
       m_changed_page = False;
       reinit = True;
    }
    
    /* initialize text_encoding */
    if (text_encoding == NULL) {
       text_encoding = get_text_encoding();
    }
    
    /* first call to this routine, or search term changed:
       Re-initialize the utf-8 representation and the regexp */
    if (settings->utf8_term == NULL
       || searchterm_bak == NULL
       || strcmp(settings->term, searchterm_bak) != 0) {

       if (!reinit_searchterm(settings, text_encoding)) {
           searchinfo->locked = False;
           return;
       }

       free(searchterm_bak);
       searchterm_bak = xstrdup(settings->term);
       recompile_regexp = True;
    }

    if (strlen(settings->utf8_term) == 0) {
       positioned_popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
                             MSG_WARN,
                             settings->x_pos, settings->y_pos,
                             NULL, "Search term is empty after UTF-8 conversion!");
       searchinfo->locked = False;
       return;
    }

    if (direction_bak != settings->direction && direction_bak != SEARCH_UNINITIALIZED
       && searchinfo->from_pos != INT_MAX && searchinfo->from_pos != -1) {
       TRACE_FIND((stderr, "changed direction! from_pos: %d", searchinfo->from_pos));
       if (settings->direction == SEARCH_DOWN) {
           searchinfo->from_pos = searchinfo->to_pos;
           TRACE_FIND((stderr, "DOWN; new from_pos: %d", searchinfo->from_pos));
       }
       else if (settings->direction == SEARCH_UP) {
           if (from_pos_bak != -1) {
              searchinfo->from_pos = from_pos_bak;
           }
           else {
              searchinfo->from_pos = 0;
           }
           TRACE_FIND((stderr, "UP; new from_pos: %d", searchinfo->from_pos));
       }
    }
    direction_bak = settings->direction;

    /* If one of the settings for case, hyphens ore linebreaks has
     * changed, we need to rescan the page to undo lowercasing,
     * hyphenation or linebreak removal in w_info, but preserve
     * searchinfo->from_pos since user will want to find next match.
     */
    if (case_sensitive_bak != settings->case_sensitive
       || ignore_hyphens_bak != settings->ignore_hyphens
       || ignore_linebreaks_bak != settings->ignore_linebreaks) {

       if (ignore_hyphens_bak != settings->ignore_hyphens)
           adjust_hyphen_offset = True;
       case_sensitive_bak = settings->case_sensitive;
       ignore_hyphens_bak = settings->ignore_hyphens;
       ignore_linebreaks_bak = settings->ignore_linebreaks;
       
       reset_info(&w_info);

       /* adjust from_pos if it's on second page (we'll rescan it as first page) */
       if (searchinfo->from_pos >= page_mapping[0].offset)
           searchinfo->from_pos -= page_mapping[0].offset;

       TRACE_FIND((stderr, "from_pos: %d", searchinfo->from_pos));
       page_mapping[0].offset = page_mapping[1].offset = page_mapping[0].pageno = page_mapping[1].pageno = -1;
       /* also need to recompile regexp, and undo lowercasing of search term */
       if (!reinit_searchterm(settings, text_encoding))
           return;
       recompile_regexp = True;
    }
    
    if (reinit) { /* file changed, or on different page: re-initialize scan info */
       TRACE_FIND((stderr, "re-initializing scan info!"));
       page_mapping[0].offset = page_mapping[1].offset = page_mapping[0].pageno = page_mapping[1].pageno = -1;

       /* re-initialize info */
       reset_info(&w_info);
       if (settings->direction == SEARCH_DOWN)
           searchinfo->from_pos = searchinfo->to_pos = 0;
       else
           settings->searchinfo->from_pos = settings->searchinfo->to_pos = INT_MAX;
    }

    TRACE_FIND((stderr, "from_pos initialized with: %d", settings->searchinfo->from_pos));
    
    if (settings->use_regexp && recompile_regexp) {
#if HAVE_REGEX_H
       if (!do_recompile_regexp(settings, &regex))
           return;
#else
       warn_no_regex();
#endif /* HAVE_REGEX_H */
    }

    for (;;) {       /* scan pages, try to match */
       statusline_print(STATUS_MEDIUM, "Searching on page %d", curr_page);
       TRACE_FIND((stderr, "curr_page: %d, pageno 0: %d, pageno1: %d",
                  curr_page, page_mapping[0].pageno, page_mapping[1].pageno));

       settings->hyphen_delta = 0;
       /* scan_two_pages will return False if user cancelled */
       if (!scan_two_pages(settings, &w_info, page_mapping, curr_page)
           || (read_events(EV_NOWAIT) & EV_GE_FIND_CANCEL)) {
           statusline_append(STATUS_SHORT,
                           "- cancelled.",
                           "- cancelled.");
           settings->searchinfo->locked = False;
           return;
       
       }

       TRACE_FIND((stderr, "page mapping:\n%d: %d\n%d: %d",
                  page_mapping[0].pageno, page_mapping[0].offset,
                  page_mapping[1].pageno, page_mapping[1].offset));
       
/*     dump_buffer(&w_info, 0, stderr, FMT_ISO_8859_1); */

       /* If ignore_hyphens has changed (in which case adjust_hyphen_offset
          is true), the buffer will contain settings->hyphen_delta fewer
          or more characters than in the previous pass due to the removal
          or addition of hyphens; adjust from_pos and to_pos accordingly:
       */
       if (adjust_hyphen_offset) {
           TRACE_FIND((stderr, "adjusting offset by %d", settings->hyphen_delta));
           if (settings->ignore_hyphens) { /* fewer characters */
              settings->searchinfo->from_pos -= settings->hyphen_delta;
              settings->searchinfo->to_pos -= settings->hyphen_delta;
           }
           else { /* more characters */
              settings->searchinfo->from_pos += settings->hyphen_delta;
              settings->searchinfo->to_pos += settings->hyphen_delta;
           }
           TRACE_FIND((stderr, "NEW from_pos: %d; to_pos: %d",
                     settings->searchinfo->from_pos, settings->searchinfo->to_pos));
       }

       
       /* match the searchstring */
#if HAVE_REGEX_H
       if (settings->use_regexp) {
           if (!try_regexp_match(&regex, &w_info, settings, searchinfo)) /* regexp error */
              return;
           
       }
       else {
#endif
           try_match(&w_info, settings, searchinfo);
#if HAVE_REGEX_H
       }
#endif

       /* again, check if user cancelled */
       if (read_events(EV_NOWAIT) & EV_GE_FIND_CANCEL) { /* user cancelled */
           statusline_append(STATUS_SHORT,
                           "- cancelled.",
                           "- cancelled.");
           settings->searchinfo->locked = False;
           return;
       
       }
       
       if (searchinfo->have_match) { /* match, highlight it */
           highlight_match(settings, &w_info, page_mapping);
           settings->searchinfo->locked = False;
           if (settings->direction == SEARCH_DOWN) {
              from_pos_bak = searchinfo->from_pos;
              searchinfo->from_pos = searchinfo->to_pos;
           }
           break;
       }
       else if ((settings->direction == SEARCH_DOWN && curr_page + 1 < total_pages)
               || (settings->direction == SEARCH_UP && curr_page > 0)) {
           if (settings->direction == SEARCH_DOWN)
              curr_page++;
           else
              curr_page--;
           TRACE_FIND((stderr, "continuing on page %d", curr_page));
           erase_match_highlighting(m_info, True);
           /* no match, and we have more pages; continue scanning */
           continue;
       }
       else { /* reached end of file */
           Widget find_popup;

           if ((find_popup = XtNameToWidget(globals.widgets.top_level, "*find_popup")) == 0) {
              XDVI_WARNING((stderr, "Couldn't find \"find_popup\" widget!"));
              find_popup = globals.widgets.top_level;
           }
           
           statusline_append(STATUS_MEDIUM,
                           "... searched to end of file.",
                           "... searched to end of file.");
           erase_match_highlighting(m_info, True);
           settings->searchinfo->locked = False;
           
           settings->message_window =
              positioned_choice_dialog(find_popup,
                                    MSG_QUESTION,
                                    settings->x_pos, settings->y_pos,
                                    NULL,
#ifndef MOTIF
                                    "do-search-restart",
#endif
                                    NULL, NULL, /* no pre_callbacks */
                                    "Yes", search_restart, (XtPointer)settings,
                                    "Cancel", message_search_ended, (XtPointer)settings,
                                    "Searched %s of file without finding the pattern.\n"
                                    "Start again from the %s of the file?",
                                    settings->direction == SEARCH_DOWN
                                    ? "forward to end" : "backward to beginning",
                                    settings->direction == SEARCH_DOWN
                                    ? "beginning" : "end");
           TRACE_GUI((stderr, "message_window: %p\n", (void *)settings->message_window));
           /* notreached */
           break;
       }
    } /* for(;;) */
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1099 of file search-internal.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1066 of file search-internal.c.

{
    int i;
    FILE *fp;
    struct file_info *finfo = pinfo->finfo;
    
    if ((fp = XFOPEN(finfo->txt_out.fname, "wb")) == NULL) {
       popup_message(globals.widgets.top_level,
                    MSG_ERR,
                    NULL, "Could not open %s for writing: %s.",
                    finfo->txt_out.fname,
                    strerror(errno));
       return False;
    }

    for (i = 0; i < total_pages; i++) {
       if (pinfo->callback == NULL || pinfo->callback(pinfo, i)) {
           struct word_info txt_info = { NULL, 0, 0, NULL, 0, 0, NULL, NULL, 0, False, False, False };
           scan_page(globals.dvi_file.bak_fp, i, &txt_info);

           dump_buffer(&txt_info, 0, fp, fmt);

           free(txt_info.txt_buf);
           
           fputs("\n\n", fp); /* two newlines for page breaks */
       }
    }
    
    fclose(fp);
    return True;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 301 of file search-internal.c.

{
/*     fprintf(stderr, "pageno: %d --- m_info: %p\n", pageno, m_info); */
/*     fprintf(stderr, "m_match_page: %d\n", m_match_page); */
    return m_info != NULL && m_match_page == pageno;
}

Here is the caller graph for this function:

Definition at line 314 of file search-internal.c.

{
    size_t i;

    ASSERT(m_info != NULL, "inside_match musn't be called with m_info == NULL!");
    TRACE_FIND((stderr, "m_info->bboxes: %p; idx: %lu", (void *)m_info->bboxes, (unsigned long)m_info->bboxes_idx));
    for (i = 0; m_info->bboxes != NULL && i <= m_info->bboxes_idx && m_info->bboxes[i].ulx < INT_MAX; i++) {
       TRACE_FIND((stderr, "inside_bbox_match: %d, %d", x, y));
       TRACE_FIND((stderr, "x: %d, y: %d, x2: %d, y2: %d",
                  (int)(m_info->bboxes[i].ulx / (double)currwin.shrinkfactor + 0.5),
                  (int)(m_info->bboxes[i].uly / (double)currwin.shrinkfactor + 0.5),
                  (int)(m_info->bboxes[i].lrx / (double)currwin.shrinkfactor + 0.5),
                  (int)(m_info->bboxes[i].lry / (double)currwin.shrinkfactor + 0.5)));

       if (x >= (int)(m_info->bboxes[i].ulx / (double)currwin.shrinkfactor + 0.5)
           && x <= (int)(m_info->bboxes[i].lrx / (double)currwin.shrinkfactor + 0.5)
           && y >= (int)(m_info->bboxes[i].uly / (double)currwin.shrinkfactor + 0.5)
           && y <= (int)(m_info->bboxes[i].lry / (double)currwin.shrinkfactor + 0.5)) {
           TRACE_FIND((stderr, "%d == %d",
                     x - 1, (int)(m_info->bboxes[i].ulx / (double)currwin.shrinkfactor + 0.5)));
           TRACE_FIND((stderr, "%d == %d",
                     y - 1, (int)(m_info->bboxes[i].uly / (double)currwin.shrinkfactor + 0.5)));
           if (x - 1 == (int)(m_info->bboxes[i].ulx / (double)currwin.shrinkfactor + 0.5)
              && y - 1 == (int)(m_info->bboxes[i].uly / (double)currwin.shrinkfactor + 0.5))
              return 2;
           else
              return 1;
       }
    }
    return 0;
}

Definition at line 1278 of file search-internal.c.

{
    TRACE_FIND((stderr, "resetting info!"));
    reset_info(m_info);
    m_info = NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void search_restart ( XtPointer  settings)

Definition at line 1120 of file search-internal.c.

{
    struct search_settings *settings = (struct search_settings *)arg;
    Widget popup, textfield;
    char *searchterm = NULL;
    
    TRACE_FIND((stderr, "restart search!"));

    /* Update the search term (user might have changed it before
       hitting `Return' to restart the search).  We need to start
       from the toplevel widget since this method may be called
       from a different window (e.g. confirmation popup).
    */
    if (get_widget_by_name(&popup, globals.widgets.top_level, Xdvi_SEARCH_POPUP_NAME, True)
       && get_widget_by_name(&textfield, popup, Xdvi_SEARCHBOX_INPUT_NAME, True)) {
       XtVaGetValues(textfield,
#ifdef MOTIF
                    XmNvalue,
#else
                    XtNstring,
#endif
                    &searchterm, NULL);
       if (searchterm == NULL) {
           XDVI_WARNING((stderr, "Got NULL searchterm in search_restart()!"));
           return;
       }
       settings->term = searchterm;
    }

    if (settings->direction == SEARCH_DOWN) {
       settings->from_page = 0;
    }
    else {
       settings->from_page = total_pages - 1;
    }
    if (settings->direction == SEARCH_DOWN)
       settings->searchinfo->from_pos = settings->searchinfo->to_pos = -1;
    else
       settings->searchinfo->from_pos = settings->searchinfo->to_pos = INT_MAX;
    
    settings->message_window = 0;
    search_signal_page_changed();
    search_dvi((XtPointer)settings);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 147 of file search-internal.c.

Here is the caller graph for this function: