home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / layout / layfind.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  23.6 KB  |  1,104 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "xp.h"
  20. #include "layout.h"
  21. #include "intl_csi.h"
  22.  
  23. #ifdef PROFILE
  24. #pragma profile on
  25. #endif
  26.  
  27. #ifdef XP_MAC
  28. # ifdef XP_TRACE
  29. #  undef XP_TRACE
  30. # endif
  31. # define XP_TRACE(X)
  32. #else
  33. #ifndef XP_TRACE
  34. # define XP_TRACE(X) fprintf X
  35. #endif
  36. #endif /* XP_MAC */
  37.  
  38. #ifdef TEST_16BIT
  39. #define XP_WIN16
  40. #endif /* TEST_16BIT */
  41.  
  42. #define INTL_FIND    1    /* ftang */
  43. #include "libi18n.h"
  44.  
  45. /*************************
  46.  * The following is to speed up case conversion
  47.  * to allow faster checking of caseless equal among strings.
  48.  *************************/
  49. #ifdef NON_ASCII_STRINGS
  50. # define TOLOWER(x) (tolower((int)(x)))
  51. #else /* ASCII TABLE LOOKUP */
  52. static unsigned char lower_lookup[256]={
  53.     0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,
  54.     27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,
  55.     51,52,53,54,55,56,57,58,59,60,61,62,63,64,
  56.         97,98,99,100,101,102,103,104,105,106,107,108,109,
  57.         110,111,112,113,114,115,116,117,118,119,120,121,122,
  58.     91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,
  59.     111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
  60.     129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,
  61.     147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,
  62.     165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,
  63.     183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,
  64.     201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,
  65.     219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,
  66.     237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,
  67.     255};
  68. # define TOLOWER(x)      (lower_lookup[(unsigned int)(x)])
  69. #endif /* NON_ASCII_STRINGS */
  70.  
  71.  
  72. static void
  73. lo_next_character(MWContext *context, lo_DocState *state, LO_Element **ele_loc,
  74.     int32 *pos, Bool forward)
  75. {
  76.     INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  77.     int16 win_csid = INTL_GetCSIWinCSID(c);
  78.     LO_Element *eptr;
  79.     int32 position;
  80.  
  81.     eptr = *ele_loc;
  82.     position = *pos;
  83.  
  84.     /*
  85.      * If our current element is text, we may be able to just
  86.      * move inside of it.
  87.      */
  88.     if (eptr->type == LO_TEXT)
  89.     {
  90.         if ((forward != FALSE)&&
  91.             (position < (eptr->lo_text.text_len - 1)))
  92.         {
  93. #ifdef INTL_FIND    
  94.             /*    Add by ftang to provide international find */
  95.             position = INTL_NextCharIdxInText(win_csid, (unsigned char*)eptr->lo_text.text, position );
  96. #else
  97.             position++;
  98. #endif
  99.             *ele_loc = eptr;
  100.             *pos = position;
  101.             return;
  102.         }
  103.         else if ((forward == FALSE)&&(position > 0))
  104.         {
  105. #ifdef INTL_FIND
  106.             /*    Add by ftang to provide international find */
  107.             position = INTL_PrevCharIdxInText(win_csid, (unsigned char*)eptr->lo_text.text, position );
  108. #else
  109.             position--;
  110. #endif
  111.             *ele_loc = eptr;
  112.             *pos = position;
  113.             return;
  114.         }
  115.     }
  116.  
  117.     /*
  118.      * If we didn't return above, we need to move to a new element.
  119.      */
  120.     if (forward != FALSE)
  121.     {
  122.         /*
  123.          * If no next element, see if this is a CELL we can
  124.          * hop out of.
  125.          */
  126.         if (eptr->lo_any.next == NULL)
  127.         {
  128.             int32 no_loop_id;
  129.  
  130.             no_loop_id = eptr->lo_any.ele_id;
  131.  
  132.             /*
  133.              * Jump cell boundries if there is one
  134.              * between here and the next element.
  135.              */
  136.             eptr = lo_JumpCellWall(context, state, eptr);
  137.  
  138.             /*
  139.              * If non-null eptr is the cell we were in, move
  140.              * to the next cell/element.
  141.              */
  142.             if (eptr != NULL)
  143.             {
  144.                 eptr = eptr->lo_any.next;
  145.             }
  146.  
  147.             /*
  148.              * infinite loop prevention
  149.              */
  150.             if ((eptr != NULL)&&(eptr->lo_any.ele_id <= no_loop_id))
  151.             {
  152. #ifdef DEBUG
  153. XP_TRACE(("Find loop avoidance 1\n"));
  154. #endif /* DEBUG */
  155.                 eptr = NULL;
  156.             }
  157.         }
  158.         else
  159.         {
  160.             eptr = eptr->lo_any.next;
  161.         }
  162.     }
  163.     else
  164.     {
  165.         /*
  166.          * If no previous element, see if this is a CELL we can
  167.          * hop out of.
  168.          */
  169.         if (eptr->lo_any.prev == NULL)
  170.         {
  171.             int32 no_loop_id;
  172.  
  173.             no_loop_id = eptr->lo_any.ele_id;
  174.  
  175.             /*
  176.              * Jump cell boundries if there is one
  177.              * between here and the previous element.
  178.              */
  179.             eptr = lo_JumpCellWall(context, state, eptr);
  180.  
  181.             /*
  182.              * If non-null eptr is the cell we were in, move
  183.              * to the previous cell/element.
  184.              */
  185.             if (eptr != NULL)
  186.             {
  187.                 eptr = eptr->lo_any.prev;
  188.             }
  189.  
  190.             /*
  191.              * infinite loop prevention
  192.              */
  193.             if ((eptr != NULL)&&(eptr->lo_any.ele_id >= no_loop_id))
  194.             {
  195. #ifdef DEBUG
  196. XP_TRACE(("Find loop avoidance 2\n"));
  197. #endif /* DEBUG */
  198.                 eptr = NULL;
  199.             }
  200.         }
  201.         else
  202.         {
  203.             eptr = eptr->lo_any.prev;
  204.         }
  205.     }
  206.  
  207.     while (eptr != NULL)
  208.     {
  209.         if (eptr->type == LO_LINEFEED)
  210.         {
  211.             break;
  212.         }
  213.         else if ((eptr->type == LO_TEXT)&&(eptr->lo_text.text != NULL))
  214.         {
  215.             break;
  216.         }
  217.         else if (eptr->type == LO_CELL)
  218.         {
  219.             /*
  220.              * When we walk onto a cell, we need
  221.              * to walk into it if it isn't empty.
  222.              */
  223.             if ((forward != FALSE)&&
  224.                 (eptr->lo_cell.cell_list != NULL))
  225.             {
  226.                 eptr = eptr->lo_cell.cell_list;
  227.                 continue;
  228.             }
  229.             else if ((forward == FALSE)&&
  230.                      (eptr->lo_cell.cell_list_end != NULL))
  231.             {
  232.                 eptr = eptr->lo_cell.cell_list_end;
  233.                 continue;
  234.             }
  235.         }
  236.  
  237.         /*
  238.          * Move forward or back to the next element
  239.          */
  240.         if (forward != FALSE)
  241.         {
  242.             /*
  243.              * If no next element, see if this is a CELL we can
  244.              * hop out of.
  245.              */
  246.             if (eptr->lo_any.next == NULL)
  247.             {
  248.                 int32 no_loop_id;
  249.  
  250.                 no_loop_id = eptr->lo_any.ele_id;
  251.  
  252.                 /*
  253.                  * Jump cell boundries if there is one
  254.                  * between here and the next element.
  255.                  */
  256.                 eptr = lo_JumpCellWall(context, state, eptr);
  257.  
  258.                 /*
  259.                  * If non-null eptr is the cell we were in, move
  260.                  * to the next cell/element.
  261.                  */
  262.                 if (eptr != NULL)
  263.                 {
  264.                     eptr = eptr->lo_any.next;
  265.                 }
  266.  
  267.                 /*
  268.                  * infinite loop prevention
  269.                  */
  270.                 if ((eptr != NULL)&&(
  271.                     eptr->lo_any.ele_id <= no_loop_id))
  272.                 {
  273. #ifdef DEBUG
  274. XP_TRACE(("Find loop avoidance 3\n"));
  275. #endif /* DEBUG */
  276.                     eptr = NULL;
  277.                 }
  278.             }
  279.             else
  280.             {
  281.                 eptr = eptr->lo_any.next;
  282.             }
  283.         }
  284.         else
  285.         {
  286.             /*
  287.              * If no previous element, see if this is a CELL we can
  288.              * hop out of.
  289.              */
  290.             if (eptr->lo_any.prev == NULL)
  291.             {
  292.                 int32 no_loop_id;
  293.  
  294.                 no_loop_id = eptr->lo_any.ele_id;
  295.  
  296.                 /*
  297.                  * Jump cell boundries if there is one
  298.                  * between here and the previous element.
  299.                  */
  300.                 eptr = lo_JumpCellWall(context, state, eptr);
  301.  
  302.                 /*
  303.                  * If non-null eptr is the cell we were in, move
  304.                  * to the previous cell/element.
  305.                  */
  306.                 if (eptr != NULL)
  307.                 {
  308.                     eptr = eptr->lo_any.prev;
  309.                 }
  310.  
  311.                 /*
  312.                  * infinite loop prevention
  313.                  */
  314.                 if ((eptr != NULL)&&
  315.                     (eptr->lo_any.ele_id >= no_loop_id))
  316.                 {
  317. #ifdef DEBUG
  318. XP_TRACE(("Find loop avoidance 4\n"));
  319. #endif /* DEBUG */
  320.                     eptr = NULL;
  321.                 }
  322.             }
  323.             else
  324.             {
  325.                 eptr = eptr->lo_any.prev;
  326.             }
  327.         }
  328.     }
  329.     if (eptr == NULL)
  330.     {
  331.         *ele_loc = NULL;
  332.         *pos = 0;
  333.     }
  334.     else if (eptr->type == LO_TEXT)
  335.     {
  336.         *ele_loc = eptr;
  337.         if (forward != FALSE)
  338.         {
  339.             *pos = 0;
  340.         }
  341.         else
  342.         {
  343. #ifdef INTL_FIND
  344.             /*    Add by ftang to provide international find */
  345.             if(eptr->lo_text.text_len == 0)
  346.                 position = 0;
  347.             else
  348.                 position = INTL_PrevCharIdxInText(win_csid, (unsigned char*)eptr->lo_text.text, eptr->lo_text.text_len );
  349. #else
  350.             position = eptr->lo_text.text_len - 1;
  351.             if (position < 0)
  352.             {
  353.                 position = 0;
  354.             }
  355. #endif
  356.             *pos = position;
  357.         }
  358.     }
  359.     else if (eptr->type == LO_LINEFEED)
  360.     {
  361.         *ele_loc = eptr;
  362.         *pos = 0;
  363.     }
  364. }
  365.  
  366.  
  367. static Bool
  368. lo_find_in_list(MWContext *context, lo_DocState *state,
  369.     LO_Element *eptr, char *cmp_text, int32 len, int32 position,
  370.     LO_Element **start_ele_loc, int32 *start_position,
  371.     LO_Element **end_ele_loc, int32 *end_position,
  372.     Bool use_case, Bool forward)
  373. {
  374.     int32 cnt;
  375.     LO_Element *start_element, *end_element;
  376.     int32 start_pos, end_pos;
  377.     INTL_CharSetInfo c = LO_GetDocumentCharacterSetInfo(context);
  378.     int16 win_csid = INTL_GetCSIWinCSID(c);
  379.  
  380.     while (eptr != NULL)
  381.     {
  382.         Bool have_start, not_equal;
  383.         int charlen = 1;
  384.  
  385.         have_start = FALSE;
  386.         while ((eptr != NULL)&&(have_start == FALSE))
  387.         {
  388.             unsigned char *tptr;
  389.             unsigned char *str;
  390.  
  391.             switch (eptr->type)
  392.             {
  393. #ifndef INTL_FIND
  394.                 char tchar;
  395. #endif
  396.                 case LO_TEXT:
  397.                 if (eptr->lo_text.text != NULL)
  398.                 {
  399.                     PA_LOCK(str, unsigned char *,
  400.                         eptr->lo_text.text);
  401.                     tptr = (unsigned char *)(str + position);
  402. #ifdef INTL_FIND
  403.                     if (use_case)
  404.                         have_start = INTL_MatchOneCaseChar(win_csid, (unsigned char*)cmp_text,tptr,&charlen);
  405.                     else
  406.                         have_start = INTL_MatchOneChar(win_csid, (unsigned char*)cmp_text,tptr,&charlen);
  407. #else
  408.                     if (use_case == FALSE)
  409.                     {
  410.                         tchar = TOLOWER(*tptr);
  411.                     }
  412.                     else
  413.                     {
  414.                         tchar = *tptr;
  415.                     }
  416.                     if (cmp_text[0] == tchar)
  417.                     {
  418.                         have_start = TRUE;
  419.                     }
  420. #endif
  421.                     PA_UNLOCK(eptr->lo_text.text);
  422.                 }
  423.                 break;
  424.                 case LO_LINEFEED:
  425.                 if (cmp_text[0] == ' ')
  426.                 {
  427.                     have_start = TRUE;
  428.                 }
  429.                 break;
  430.                 case LO_HRULE:
  431.                 case LO_FORM_ELE:
  432.                 case LO_BULLET:
  433.                 case LO_IMAGE:
  434.                 case LO_SUBDOC:
  435.                 case LO_TABLE:
  436.                 default:
  437.                 break;
  438.             }
  439.             if (have_start == FALSE)
  440.             {
  441.                 lo_next_character(context, state,
  442.                     &eptr, &position, forward);
  443.             }
  444.         }
  445.         if (have_start == FALSE)
  446.         {
  447.             return(FALSE);
  448.         }
  449.  
  450.         start_element = eptr;
  451.         start_pos = position;
  452. #ifdef INTL_FIND
  453.         if (len == charlen)
  454. #else
  455.         if (len == 1)
  456. #endif
  457.         {
  458.             end_element = eptr;
  459.             end_pos = position;
  460.             *start_ele_loc = start_element;
  461.             *start_position = start_pos;
  462.             *end_ele_loc = end_element;
  463.             *end_position = end_pos;
  464.             return(TRUE);
  465.         }
  466.  
  467. #ifdef INTL_FIND
  468.         cnt = charlen;
  469. #else
  470.         cnt = 1;
  471. #endif    
  472.         not_equal = FALSE;
  473.         lo_next_character(context, state, &eptr, &position, TRUE);
  474.         while ((eptr != NULL)&&(cnt < len)&&(not_equal == FALSE))
  475.         {
  476.             unsigned char *tptr; /* this needs to be an unsigned quantity!  chouck 3-Nov-94 */
  477.             char *str;
  478.  
  479.             switch (eptr->type)
  480.             {
  481. #ifndef INTL_FIND
  482.                 char tchar;
  483. #endif
  484.                 case LO_TEXT:
  485.                 if (eptr->lo_text.text != NULL)
  486.                 {
  487.                     PA_LOCK(str, char *,
  488.                         eptr->lo_text.text);
  489.                     tptr = (unsigned char *)(str + position);
  490. #ifdef INTL_FIND
  491.                     if (use_case)
  492.                         not_equal = ! INTL_MatchOneCaseChar(win_csid,(unsigned char *) cmp_text+cnt,tptr,&charlen);
  493.                     else
  494.                         not_equal = ! INTL_MatchOneChar(win_csid,(unsigned char *) cmp_text+cnt,tptr,&charlen);
  495. #else
  496.                     if (use_case == FALSE)
  497.                     {                          
  498.                         /* this needs to be an unsigned quantity!  chouck 3-Nov-94 */
  499.                         tchar = TOLOWER(*tptr);
  500.                     }
  501.                     else
  502.                     {
  503.                         tchar = (char) *tptr;
  504.                     }
  505.                     if (tchar != cmp_text[cnt])
  506.                     {
  507.                         not_equal = TRUE;
  508.                     }
  509. #endif
  510.                     PA_UNLOCK(eptr->lo_text.text);
  511.                 }
  512.                 break;
  513.                 case LO_LINEFEED:
  514.                 if (cmp_text[cnt] != ' ')
  515.                 {
  516.                     not_equal = TRUE;
  517.                 }
  518.                 break;
  519.                 case LO_HRULE:
  520.                 case LO_FORM_ELE:
  521.                 case LO_BULLET:
  522.                 case LO_IMAGE:
  523.                 case LO_SUBDOC:
  524.                 case LO_TABLE:
  525.                 default:
  526.                 break;
  527.             }
  528. #ifdef INTL_FIND
  529.         cnt += charlen;
  530. #else
  531.         cnt++;
  532. #endif    
  533.             if ((not_equal == FALSE)&&(cnt < len))
  534.             {
  535.                 lo_next_character(context, state,
  536.                     &eptr, &position, TRUE);
  537.             }
  538.         }
  539.  
  540.         if ((cnt == len)&&(not_equal == FALSE))
  541.         {
  542.             end_element = eptr;
  543.             end_pos = position;
  544.             *start_ele_loc = start_element;
  545.             *start_position = start_pos;
  546.             *end_ele_loc = end_element;
  547.             *end_position = end_pos;
  548.             return(TRUE);
  549.         }
  550.  
  551.         eptr = start_element;
  552.         position = start_pos;
  553.         lo_next_character(context, state, &eptr, &position, forward);
  554.     }
  555.     return(FALSE);
  556. }
  557.  
  558.  
  559. static Bool
  560. lo_element_in_floating_cell(MWContext *context, lo_DocState *state,
  561.                     LO_Element *eptr)
  562. {
  563.     LO_Element *cell;
  564.     LO_Element *f_ptr;
  565.     int32 x, y;
  566.     int32 ret_x, ret_y;
  567.  
  568.     /*
  569.      * Error test.
  570.      */
  571.     if (eptr == NULL)
  572.     {
  573.         return(FALSE);
  574.     }
  575.  
  576.     x = eptr->lo_any.x + eptr->lo_any.x_offset;
  577.         y = eptr->lo_any.y + eptr->lo_any.y_offset;
  578.  
  579.     /*
  580.      * This wouldn't work if the element had zero width, but since
  581.      * we are assuming we are calling this on an element returned
  582.      * as the result of a FIND operation, it must be a text item
  583.      * with a non-zero width.
  584.      */
  585.     cell = lo_XYToDocumentElement(context, state, x, y, TRUE, FALSE, TRUE,
  586.                     &ret_x, &ret_y);
  587.     if ((cell == NULL)||(cell->type != LO_CELL))
  588.     {
  589.         return(FALSE);
  590.     }
  591.  
  592.     /*
  593.      * Now look for this cell in the float list.
  594.      */
  595.     f_ptr = state->float_list;
  596.     while (f_ptr != NULL)
  597.     {
  598.         if (f_ptr == cell)
  599.         {
  600.             return(TRUE);
  601.         }
  602.         f_ptr = f_ptr->lo_any.next;
  603.     }
  604.     return(FALSE);
  605. }
  606.  
  607.  
  608. Bool
  609. LO_FindText(MWContext *context, char *text,
  610.     LO_Element **start_ele_loc, int32 *start_position,
  611.     LO_Element **end_ele_loc, int32 *end_position,
  612.     Bool use_case, Bool forward)
  613. {
  614.     int32 doc_id;
  615.     lo_TopState *top_state;
  616.     lo_DocState *state;
  617.     LO_Element *eptr;
  618.     LO_Element *start_element, *end_element;
  619.     int32 start_pos, end_pos;
  620.     int32 position;
  621.     int32 i, len;
  622.     char *cmp_text;
  623.     Bool start_at_top;
  624.     Bool search_float_list;
  625.     Bool ret_val;
  626.  
  627.     start_at_top = FALSE;
  628.     search_float_list = TRUE;
  629.  
  630.     /*
  631.      * Get the unique document ID, and retreive this
  632.      * documents layout state.
  633.      */
  634.     doc_id = XP_DOCID(context);
  635.     top_state = lo_FetchTopState(doc_id);
  636.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  637.     {
  638.         return(FALSE);
  639.     }
  640.     state = top_state->doc_state;
  641.  
  642.     eptr = *start_ele_loc;
  643.     position = *start_position;
  644.  
  645.     if (eptr == NULL)
  646.     {
  647.         start_at_top = TRUE;
  648.         if (forward != FALSE)
  649.         {
  650.             if (state->line_num <= 1)
  651.             {
  652.                 return(FALSE);
  653.             }
  654.             else
  655.             {
  656.                 LO_Element **array;
  657. #ifdef XP_WIN16
  658. {
  659.                 XP_Block *larray_array;
  660.  
  661.                 XP_LOCK_BLOCK(larray_array, XP_Block *,
  662.                     state->larray_array);
  663.                 state->line_array = larray_array[0];
  664.                 XP_UNLOCK_BLOCK(state->larray_array);
  665. }
  666. #endif /* XP_WIN16 */
  667.  
  668.                 XP_LOCK_BLOCK(array, LO_Element **,
  669.                     state->line_array);
  670.                 eptr = array[0];
  671.                 XP_UNLOCK_BLOCK(state->line_array);
  672.                 if (eptr == NULL)
  673.                 {
  674.                     return(FALSE);
  675.                 }
  676.             }
  677.             position = 0;
  678.         }
  679.         else
  680.         {
  681.             if (state->line_num <= 1)
  682.             {
  683.                 return(FALSE);
  684.             }
  685.             else
  686.             {
  687.                 eptr = state->end_last_line;
  688.                 if (eptr == NULL)
  689.                 {
  690.                     return(FALSE);
  691.                 }
  692.             }
  693.             position = 0;
  694.         }
  695.     }
  696.     /*
  697.      * Else, if we were passed a start position, we need to know if
  698.      * that position is in a floating element in the margin, or is
  699.      * in one of the normal document lines.  If we starting in the
  700.      * float list, we don't want to search it a second time.
  701.      */
  702.     else if (lo_element_in_floating_cell(context, state, eptr))
  703.     {
  704.         search_float_list = FALSE;
  705.     }
  706.  
  707.     len = XP_STRLEN(text);
  708.     cmp_text = (char*) XP_ALLOC(len + 1);
  709.     if (cmp_text == NULL)
  710.     {
  711.         return(FALSE);
  712.     }
  713. #ifdef INTL_FIND
  714.     /* If we use INTL_FIND. Do the conversion for the cmp_text later in INTL_MatchOneChar() routine */
  715.     for (i=0; i<len; i++)
  716.     {
  717.         cmp_text[i] = text[i];
  718.     }    
  719. #else
  720.     if (use_case != FALSE)
  721.     {
  722.         for (i=0; i<len; i++)
  723.         {
  724.             cmp_text[i] = text[i];
  725.         }
  726.     }
  727.     else
  728.     {
  729.         for (i=0; i<len; i++)
  730.         {
  731.             cmp_text[i] = TOLOWER((unsigned char) text[i]);
  732.         }
  733.     }
  734. #endif
  735.     cmp_text[len] = '\0';
  736.  
  737.     if (start_at_top == FALSE)
  738.     {
  739.         lo_next_character(context, state, &eptr, &position, forward);
  740.     }
  741.  
  742.     ret_val = lo_find_in_list(context, state, eptr, cmp_text, len,
  743.             position, &start_element, &start_pos,
  744.             &end_element, &end_pos, use_case, forward);
  745.     if (ret_val != FALSE)
  746.     {
  747.         *start_ele_loc = start_element;
  748.         *start_position = start_pos;
  749.         *end_ele_loc = end_element;
  750.         *end_position = end_pos;
  751.  
  752.         if (cmp_text != NULL)
  753.         {
  754.             XP_FREE(cmp_text);
  755.         }
  756.         return(TRUE);
  757.     }
  758.  
  759.     /*
  760.      * While we failed to find anything, we still havn't checked the
  761.      * contents of table in the margins.  It will appear out of
  762.      * order, but we should check them now.
  763.      */
  764.     if (search_float_list != FALSE)
  765.     {
  766.         eptr = state->float_list;
  767.         position = 0;
  768.         ret_val = lo_find_in_list(context, state, eptr, cmp_text, len,
  769.                 position, &start_element, &start_pos,
  770.                 &end_element, &end_pos, use_case, forward);
  771.         if (ret_val != FALSE)
  772.         {
  773.             *start_ele_loc = start_element;
  774.             *start_position = start_pos;
  775.             *end_ele_loc = end_element;
  776.             *end_position = end_pos;
  777.  
  778.             if (cmp_text != NULL)
  779.             {
  780.                 XP_FREE(cmp_text);
  781.             }
  782.             return(TRUE);
  783.         }
  784.     }
  785.  
  786.     if (cmp_text != NULL)
  787.     {
  788.         XP_FREE(cmp_text);
  789.     }
  790.  
  791.     return(FALSE);
  792. }
  793.  
  794.  
  795. static Bool
  796. lo_child_search(MWContext *context, MWContext **ret_context, char *text,
  797.     LO_Element **start_ele_loc, int32 *start_position,
  798.     LO_Element **end_ele_loc, int32 *end_position,
  799.     Bool use_case, Bool forward)
  800. {
  801.     int32 doc_id;
  802.     lo_TopState *top_state;
  803.     lo_DocState *state;
  804.     Bool ret_val;
  805.  
  806.     /*
  807.      * Get the unique document ID, and retreive this
  808.      * documents layout state.
  809.      */
  810.     doc_id = XP_DOCID(context);
  811.     top_state = lo_FetchTopState(doc_id);
  812.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  813.     {
  814.         return(FALSE);
  815.     }
  816.     state = top_state->doc_state;
  817.     ret_val = FALSE;
  818.  
  819.     if (top_state->is_grid == FALSE)
  820.     {
  821.         ret_val = LO_FindText(context, text,
  822.             start_ele_loc, start_position,
  823.             end_ele_loc, end_position,
  824.             use_case, forward);
  825.         if (ret_val != FALSE)
  826.         {
  827.             *ret_context = context;
  828.         }
  829.     }
  830.     else
  831.     {
  832.         lo_GridCellRec *cell_ptr;
  833.  
  834.         cell_ptr = top_state->the_grid->cell_list;
  835.         while (cell_ptr != NULL)
  836.         {
  837.             if (cell_ptr->context != NULL)
  838.             {
  839.                 /*
  840.                  * Always start at the beginning of
  841.                  * child docs.
  842.                  */
  843.                 *start_ele_loc = NULL;
  844.                 *end_ele_loc = NULL;
  845.                 *start_position = 0;
  846.                 *end_position = 0;
  847.                 ret_val = lo_child_search(cell_ptr->context,
  848.                     ret_context, text,
  849.                     start_ele_loc, start_position,
  850.                     end_ele_loc, end_position,
  851.                     use_case, forward);
  852.                 if (ret_val != FALSE)
  853.                 {
  854.                     break;
  855.                 }
  856.             }
  857.             cell_ptr = cell_ptr->next;
  858.         }
  859.     }
  860.  
  861.     return(ret_val);
  862. }
  863.  
  864.  
  865. static Bool
  866. lo_sibling_search(MWContext *child, MWContext **ret_context, char *text,
  867.     LO_Element **start_ele_loc, int32 *start_position,
  868.     LO_Element **end_ele_loc, int32 *end_position,
  869.     Bool use_case, Bool forward)
  870. {
  871.     MWContext *parent;
  872.     int32 doc_id;
  873.     lo_TopState *top_state;
  874.     Bool ret_val;
  875.     lo_GridCellRec *cell_ptr;
  876.  
  877.     /*
  878.      * We must have a grid parent
  879.      */
  880.     parent = child->grid_parent;
  881.     if (parent == NULL)
  882.     {
  883.         return(FALSE);
  884.     }
  885.  
  886.     /*
  887.      * Get the unique document ID, and retreive this
  888.      * documents layout state.
  889.      */
  890.     doc_id = XP_DOCID(parent);
  891.     top_state = lo_FetchTopState(doc_id);
  892.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  893.     {
  894.         return(FALSE);
  895.     }
  896.  
  897.     /*
  898.      * We must have a grid parent
  899.      */
  900.     if (top_state->is_grid == FALSE)
  901.     {
  902.         return(FALSE);
  903.     }
  904.  
  905.     ret_val = FALSE;
  906.  
  907.     /*
  908.      * Find the sibling after the child
  909.      */
  910.     cell_ptr = top_state->the_grid->cell_list;
  911.     while (cell_ptr != NULL)
  912.     {
  913.         if (cell_ptr->context == child)
  914.         {
  915.             cell_ptr = cell_ptr->next;
  916.             break;
  917.         }
  918.         cell_ptr = cell_ptr->next;
  919.     }
  920.  
  921.     /*
  922.      * Search all siblings (if any).
  923.      */
  924.     while (cell_ptr != NULL)
  925.     {
  926.         if (cell_ptr->context != NULL)
  927.         {
  928.             /*
  929.              * Always start at the beginning of sibling docs.
  930.              */
  931.             *start_ele_loc = NULL;
  932.             *end_ele_loc = NULL;
  933.             *start_position = 0;
  934.             *end_position = 0;
  935.             ret_val = lo_child_search(cell_ptr->context,
  936.                 ret_context, text,
  937.                 start_ele_loc, start_position,
  938.                 end_ele_loc, end_position,
  939.                 use_case, forward);
  940.             if (ret_val != FALSE)
  941.             {
  942.                 break;
  943.             }
  944.         }
  945.         cell_ptr = cell_ptr->next;
  946.     }
  947.  
  948.     return(ret_val);
  949. }
  950.  
  951.  
  952. Bool
  953. LO_FindGridText(MWContext *context, MWContext **ret_context, char *text,
  954.     LO_Element **start_ele_loc, int32 *start_position,
  955.     LO_Element **end_ele_loc, int32 *end_position,
  956.     Bool use_case, Bool forward)
  957. {
  958.     int32 doc_id;
  959.     lo_TopState *top_state;
  960.     lo_DocState *state;
  961.     Bool ret_val;
  962.     LO_Element *start_ele;
  963.     LO_Element *end_ele;
  964.     int32 start_pos;
  965.     int32 end_pos;
  966.  
  967.     /*
  968.      * Get the unique document ID, and retreive this
  969.      * documents layout state.
  970.      */
  971.     doc_id = XP_DOCID(context);
  972.     top_state = lo_FetchTopState(doc_id);
  973.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  974.     {
  975.         return(FALSE);
  976.     }
  977.     state = top_state->doc_state;
  978.     ret_val = FALSE;
  979.     start_ele = *start_ele_loc;
  980.     end_ele = *end_ele_loc;
  981.     start_pos = *start_position;
  982.     end_pos = *end_position;
  983.  
  984.     /*
  985.      * If no starting context we start at the top level grid context.
  986.      */
  987.     if (*ret_context == NULL)
  988.     {
  989.         MWContext *parent;
  990.  
  991.         /*
  992.          * Find the top of the nested grid tree
  993.          */
  994.         parent = context;
  995.         while ((parent->is_grid_cell != FALSE)&&
  996.             (parent->grid_parent != NULL))
  997.         {
  998.             parent = parent->grid_parent;
  999.         }
  1000.         /*
  1001.          * Search the tree completely.
  1002.          */
  1003.         ret_val = lo_child_search(parent, ret_context, text,
  1004.                     start_ele_loc, start_position,
  1005.                     end_ele_loc, end_position,
  1006.                     use_case, forward);
  1007.     }
  1008.     else
  1009.     {
  1010.         MWContext *child;
  1011.  
  1012.         /*
  1013.          * Search the starting context at the starting position.
  1014.          */
  1015.         child = *ret_context;
  1016.         ret_val = lo_child_search(child, ret_context, text,
  1017.                     start_ele_loc, start_position,
  1018.                     end_ele_loc, end_position,
  1019.                     use_case, forward);
  1020.  
  1021.         /*
  1022.          * If it wasn't in the starting context, walk up the tree
  1023.          * searching all siblings (after the parent sibling)
  1024.          * at each level.
  1025.          */
  1026.         while ((ret_val == FALSE)&&(child->is_grid_cell != FALSE)&&
  1027.             (child->grid_parent != NULL))
  1028.         {
  1029.             /*
  1030.              * Always start at the beginning of sibling docs.
  1031.              */
  1032.             *start_ele_loc = NULL;
  1033.             *end_ele_loc = NULL;
  1034.             *start_position = 0;
  1035.             *end_position = 0;
  1036.             ret_val = lo_sibling_search(child, ret_context, text,
  1037.                     start_ele_loc, start_position,
  1038.                     end_ele_loc, end_position,
  1039.                     use_case, forward);
  1040.             child = child->grid_parent;
  1041.         }
  1042.     }
  1043.  
  1044.     /*
  1045.      * If we didn't find it, restore starting values.
  1046.      */
  1047.     if (ret_val == FALSE)
  1048.     {
  1049.         *start_ele_loc = start_ele;
  1050.         *end_ele_loc = end_ele;
  1051.         *start_position = start_pos;
  1052.         *end_position = end_pos;
  1053.     }
  1054.  
  1055.     return(ret_val);
  1056. }
  1057.  
  1058.  
  1059. void
  1060. LO_SelectText(MWContext *context, LO_Element *start, int32 start_pos,
  1061.     LO_Element *end, int32 end_pos, int32 *x, int32 *y)
  1062. {
  1063.     int32 doc_id;
  1064.     lo_TopState *top_state;
  1065.     lo_DocState *state;
  1066.  
  1067.     /*
  1068.      * Get the unique document ID, and retreive this
  1069.      * documents layout state.
  1070.      */
  1071.     doc_id = XP_DOCID(context);
  1072.     top_state = lo_FetchTopState(doc_id);
  1073.     if ((top_state == NULL)||(top_state->doc_state == NULL))
  1074.     {
  1075.         return;
  1076.     }
  1077.     state = top_state->doc_state;
  1078.  
  1079.     if ((start == NULL)||(end == NULL))
  1080.     {
  1081.         return;
  1082.     }
  1083.  
  1084.     LO_HighlightSelection(context, FALSE);
  1085.  
  1086.     state->selection_start = start;
  1087.         state->selection_start_pos = start_pos;
  1088.         state->selection_end = end;
  1089.         state->selection_end_pos = end_pos;
  1090.  
  1091.     LO_HighlightSelection(context, TRUE);
  1092.  
  1093.     *x = (start->lo_any.x + state->base_x);
  1094.     *y = (start->lo_any.y + state->base_y);
  1095. }
  1096.  
  1097. #ifdef TEST_16BIT
  1098. #undef XP_WIN16
  1099. #endif /* TEST_16BIT */
  1100.  
  1101. #ifdef PROFILE
  1102. #pragma profile off
  1103. #endif
  1104.