/* $XConsortium: TextFind.c /main/6 1995/09/19 23:17:17 cde-sun $ */
/*
* Motif
*
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*
*/
/*
* HISTORY
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/* (c) Copyright 1989, DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. */
/* (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */
#include <ctype.h>
#include <X11/Xmd.h>
#include <Xm/XmosP.h> /* for <stdlib.h>, and wcstombs() */
#include "XmI.h"
#include "TextI.h"
#include "TextStrSoI.h"
Boolean
_XmTextFindStringBackwards(Widget w,
XmTextPosition start,
char* search_string,
XmTextPosition *position)
{
register int i;
XmTextWidget tw = (XmTextWidget) w;
XmSourceData data = ((XmTextWidget)w)->text.source->data;
Boolean return_val = False, match = False;
int search_length = 0;
char *ptr, *end_ptr, *tmp_ptr, *end_of_data;
search_length = _XmTextCountCharacters(search_string,strlen(search_string));
if (!search_length || !data->length || search_length > data->length)
return FALSE;
/* Search can be broken into three phases for fastest search:
*
* - search from data_end - strlen(search_string) back until
* base search is at gap_end. This is a fast simple compare
* that doesn't worry about incursions into the gap.
*
* - search from gap_start-strlen(search_string) until the base
* of the search is moved across the gap.
*
* - search from start up to gap_start-strlen(search_string).
* This is a fast simple compare that doesn't worry about
* incursions into the gap.
*/
switch ((int)tw->text.char_size) {
case 1: {
/* Make sure you don't search past end of data. End of data is... */
end_of_data = data->ptr + data->length +
(data->gap_end - data->gap_start);
/* actually, no need to search beyond end - search_length position */
if (end_of_data - search_length >= data->gap_end)
end_ptr = end_of_data - search_length;
else
end_ptr = data->gap_start -
(search_length - (end_of_data - data->gap_end));
/* Phase one: search from start back to gap_end */
/* Set the base for the search */
if (data->ptr + start > data->gap_start) /* backside of gap */
ptr = data->ptr + (data->gap_end - data->gap_start) + start;
else /* we're starting before the gap */
ptr = data->ptr + start;
if (ptr > end_ptr)
ptr = end_ptr; /* no need search where a match can't be found */
while (!return_val && ptr >= data->gap_end) {
if (*ptr == *search_string) { /* potential winner! */
for (match = True, i = 1; match && (i < search_length); i++) {
if (ptr[i] != search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = ptr - data->ptr -
(data->gap_end - data->gap_start);
return_val = True;
}
}
ptr--; /* decrement base of search */
match = True;
}
/* Phase two: these searches span the gap and are SLOW!
* Two possibilities: either I've just backed the base back to gap
* end (and must do searches that span the gap) or start puts
* the base prior to the gap end. Also, possibility that there
* isn't enough room after the gap for a complete match
* (so no need to search it). This phase must be performed as
* long as data->ptr + start places the base to the right of
* gap_start - search_length.
*/
/* Do this as nested for loops; the outer loop decrements the base for
* the search, the inner loop compares character elements from 0 to
* length(search_string).
*/
/* If no match yet and if need to search prior to gap_start... */
/* Set the base for the search. */
if (!return_val &&
(data->ptr + start) > (data->gap_start - search_length)) {
if (data->ptr < data->gap_start)
ptr = data->gap_start - 1;
/* else, we're done... gap_start is at data->ptr and still no match*/
for (match = True;
ptr >= data->ptr && (data->gap_start - ptr) +
(end_of_data - data->gap_end) >= search_length;
ptr--, match = True) {
if (*ptr == *search_string) { /* we have a potential winner */
for (i = 1; i < search_length && match == True; i ++) {
if (ptr + i >= data->gap_start) {
tmp_ptr = ptr +(data->gap_end - data->gap_start) + i;
if (*tmp_ptr != search_string[i]) {
match = False;
i--;
}
} else {
if (ptr[i] != search_string[i]) {
match = False;
i--;
}
}
} /* end inner for loop - searching from current base */
if (match && (i == search_length)) {/* a winner! */
*position = ptr - data->ptr;
return_val = True;
}
}
if (return_val) break;
} /* end outer for - restart search from a new base */
}
/* phase three: search backwards from base == gap_start - search_length
* through and including base == data->ptr.
*/
if (!return_val) {
if (data->ptr + start > data->gap_start - search_length)
ptr = data->gap_start - search_length;
else
ptr = data->ptr + start;
while (!return_val && ptr >= data->ptr) {
if (*ptr == *search_string) { /* potential winner! */
for (match = True, i = 1; match && (i < search_length); i++) {
if (ptr[i] != search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = ptr - data->ptr;
return_val = True;
}
}
ptr--; /* decrement base of search */
match = True;
}
}
break;
} /* end case 1 */
case 2: {
BITS16 *bits16_ptr, *bits16_search_string, *bits16_gap_start;
BITS16 *bits16_gap_end, *bits16_end_ptr, *bits16_tmp_ptr;
BITS16 *bits16_end_of_data;
bits16_ptr = bits16_search_string = NULL;
bits16_gap_start = bits16_gap_end = NULL;
/* search_length is number of characters (!bytes) in search_string */
bits16_search_string =
(BITS16 *) XtMalloc((unsigned)
(search_length + 1) * (int)tw->text.char_size);
(void) _XmTextBytesToCharacters((char *) bits16_search_string,
search_string, search_length, True,
(int)tw->text.char_size);
/* setup the variables for the search */
bits16_gap_start = (BITS16 *) data->gap_start;
bits16_gap_end = (BITS16 *) data->gap_end;
/* Make sure you don't search past end of data. End of data is... */
bits16_ptr = (BITS16 *)data->ptr;
bits16_end_of_data = bits16_ptr + data->length +
(bits16_gap_end - bits16_gap_start);
/* only need to search up to end - search_length position */
if (bits16_end_of_data - search_length >= bits16_gap_end)
bits16_end_ptr = bits16_end_of_data - search_length;
else
bits16_end_ptr = bits16_gap_start -
(search_length - (bits16_end_of_data - bits16_gap_end));
/* Phase one: search from start back to gap_end */
bits16_ptr = (BITS16 *)data->ptr;
if (bits16_ptr + start > bits16_gap_start) /* backside of gap */
bits16_ptr = (BITS16 *)data->ptr +
(bits16_gap_end - bits16_gap_start) + start;
else /* we're starting before the gap */
bits16_ptr = (BITS16 *)data->ptr + start;
/* no need search where a match can't be found */
if (bits16_ptr > bits16_end_ptr)
bits16_ptr = bits16_end_ptr;
while (!return_val && bits16_ptr >= bits16_gap_end) {
if (*bits16_ptr == *bits16_search_string) { /* potential winner! */
for (match = True, i = 1; match && (i < search_length); i++) {
if (bits16_ptr[i] != bits16_search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = bits16_ptr - (BITS16 *)data->ptr -
(bits16_gap_end - bits16_gap_start);
return_val = True;
}
}
bits16_ptr--; /* decrement base of search */
match = True;
}
/* Phase two: these searches span the gap and are SLOW!
* Two possibilities: either I've just backed the base back to gap
* end (and must do searches that span the gap) or start puts
* the base prior to the gap end. Also, possibility that there
* isn't enough room after the gap for a complete match
* (so no need to search it). This phase must be performed as
* long as data->ptr + start places the base to the right of
* gap_start - search_length.
*/
/* Do this as nested for loops; the outer loop decrements the base for
* the search, the inner loop compares character elements from 0 to
* length(search_string).
*/
/* If no match yet and if need to search prior to gap_start... */
/* Set the base for the search. */
bits16_ptr = (BITS16 *) data->ptr;
if (!return_val &&
(bits16_ptr + start) > (bits16_gap_start - search_length)) {
if (bits16_ptr < bits16_gap_start)
bits16_ptr = bits16_gap_start - 1;
/* else, we're done... gap_start is at data->ptr and still no match*/
for (match = True;
bits16_ptr >= (BITS16*)data->ptr &&
(bits16_gap_start - bits16_ptr) +
(bits16_end_of_data - bits16_gap_end) >= search_length;
bits16_ptr--, match = True) {
if (*bits16_ptr == *bits16_search_string) { /* potential winner */
for (i = 1; i < search_length && match == True; i ++) {
if (bits16_ptr + i >= bits16_gap_start) {
bits16_tmp_ptr = bits16_ptr +
(bits16_gap_end - bits16_gap_start) + i;
if (*bits16_tmp_ptr != bits16_search_string[i]) {
match = False;
i--;
}
} else {
if (bits16_ptr[i] != bits16_search_string[i]) {
match = False;
i--;
}
}
} /* end inner for loop - searching from current base */
if (match && (i == search_length)) {/* a winner! */
*position = bits16_ptr - (BITS16*)data->ptr;
return_val = True;
}
}
if (return_val) break;
} /* end outer for - restart search from a new base */
}
/* phase three: search backwards from base == gap_start - search_length
* through and including base == data->ptr.
*/
if (!return_val) {
bits16_ptr = (BITS16 *) data->ptr;
if (bits16_ptr + start > bits16_gap_start - search_length)
bits16_ptr = bits16_gap_start - search_length;
else
bits16_ptr = bits16_ptr + start;
while (!return_val && bits16_ptr >= (BITS16 *)data->ptr) {
if (*bits16_ptr == *bits16_search_string) {/* potential winner!*/
for (match = True, i = 1; match && (i < search_length); i++) {
if (bits16_ptr[i] != bits16_search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = bits16_ptr - (BITS16 *)data->ptr;
return_val = True;
}
}
bits16_ptr--; /* decrement base of search */
match = True;
}
}
/* clean up before you go */
if (bits16_search_string != NULL)
XtFree((char*)bits16_search_string);
break;
} /* end case 2 */
default: {
wchar_t *wchar_t_ptr, *wchar_t_search_string, *wchar_t_gap_start;
wchar_t *wchar_t_gap_end, *wchar_t_end_ptr, *wchar_t_tmp_ptr;
wchar_t *wchar_t_end_of_data;
wchar_t_ptr = wchar_t_search_string = NULL;
wchar_t_gap_start = wchar_t_gap_end = NULL;
wchar_t_search_string =
(wchar_t *) XtMalloc((unsigned)
(search_length + 1) * sizeof(wchar_t));
(void)_XmTextBytesToCharacters((char *) wchar_t_search_string,
search_string, search_length, True,
(int)tw->text.char_size);
/* setup the variables for the search of new lines before the gap */
wchar_t_gap_start = (wchar_t *) data->gap_start;
wchar_t_gap_end = (wchar_t *) data->gap_end;
/* Make sure you don't search past end of data. End of data is... */
wchar_t_ptr = (wchar_t *)data->ptr;
wchar_t_end_of_data = wchar_t_ptr + data->length +
(wchar_t_gap_end - wchar_t_gap_start);
/* only need to search up to end - search_length position */
if (wchar_t_end_of_data - search_length >= wchar_t_gap_end)
wchar_t_end_ptr = wchar_t_end_of_data - search_length;
else
wchar_t_end_ptr = wchar_t_gap_start -
(search_length - (wchar_t_end_of_data - wchar_t_gap_end));
/* Phase one: search from start back to gap_end */
wchar_t_ptr = (wchar_t *)data->ptr;
if (wchar_t_ptr + start > wchar_t_gap_start) /* backside of gap */
wchar_t_ptr = (wchar_t *)data->ptr +
(wchar_t_gap_end - wchar_t_gap_start) + start;
else /* we're starting before the gap */
wchar_t_ptr = (wchar_t *)data->ptr + start;
/* no need search where a match can't be found */
if (wchar_t_ptr > wchar_t_end_ptr)
wchar_t_ptr = wchar_t_end_ptr;
while (!return_val && wchar_t_ptr >= wchar_t_gap_end) {
if (*wchar_t_ptr == *wchar_t_search_string) { /* potential winner! */
for (match = True, i = 1; match && (i < search_length); i++) {
if (wchar_t_ptr[i] != wchar_t_search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = wchar_t_ptr - (wchar_t *)data->ptr -
(wchar_t_gap_end - wchar_t_gap_start);
return_val = True;
}
}
wchar_t_ptr--; /* decrement base of search */
match = True;
}
/* Phase two: these searches span the gap and are SLOW!
* Two possibilities: either I've just backed the base back to gap
* end (and must do searches that span the gap) or start puts
* the base prior to the gap end. Also, possibility that there
* isn't enough room after the gap for a complete match
* (so no need to search it). This phase must be performed as
* long as data->ptr + start places the base to the right of
* gap_start - search_length.
*/
/* Do this as nested for loops; the outer loop decrements the base for
* the search, the inner loop compares character elements from 0 to
* length(search_string).
*/
/* If no match yet and if need to search prior to gap_start... */
/* Set the base for the search. */
wchar_t_ptr = (wchar_t *) data->ptr;
if (!return_val &&
(wchar_t_ptr + start) > (wchar_t_gap_start - search_length)) {
if (wchar_t_ptr < wchar_t_gap_start)
wchar_t_ptr = wchar_t_gap_start - 1;
/*else, we're done... gap_start is at data->ptr and still no match*/
for (match = True;
wchar_t_ptr >= (wchar_t*)data->ptr &&
(wchar_t_gap_start - wchar_t_ptr) +
(wchar_t_end_of_data - wchar_t_gap_end) >= search_length;
wchar_t_ptr--, match = True) {
if (*wchar_t_ptr == *wchar_t_search_string) {/* potential winner */
for (i = 1; i < search_length && match == True; i ++) {
if (wchar_t_ptr + i >= wchar_t_gap_start) {
wchar_t_tmp_ptr = wchar_t_ptr +
(wchar_t_gap_end - wchar_t_gap_start) + i;
if (*wchar_t_tmp_ptr != wchar_t_search_string[i]) {
match = False;
i--;
}
} else {
if (wchar_t_ptr[i] != wchar_t_search_string[i]) {
match = False;
i--;
}
}
} /* end inner for loop - searching from current base */
if (match && (i == search_length)) {/* a winner! */
*position = wchar_t_ptr - (wchar_t*)data->ptr;
return_val = True;
}
}
if (return_val) break;
} /* end outer for - restart search from a new base */
}
/* phase three: search backwards from base == gap_start - search_length
* through and including base == data->ptr.
*/
if (!return_val) {
wchar_t_ptr = (wchar_t *) data->ptr;
if (wchar_t_ptr + start > wchar_t_gap_start - search_length)
wchar_t_ptr = wchar_t_gap_start - search_length;
else
wchar_t_ptr = wchar_t_ptr + start;
while (!return_val && wchar_t_ptr >= (wchar_t *)data->ptr) {
if (*wchar_t_ptr == *wchar_t_search_string) {/* potential winner!*/
for (match = True, i = 1; match && (i < search_length); i++) {
if (wchar_t_ptr[i] != wchar_t_search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = wchar_t_ptr - (wchar_t *)data->ptr;
return_val = True;
}
}
wchar_t_ptr--; /* decrement base of search */
match = True;
}
}
/* clean up before you go */
if (wchar_t_search_string != NULL)
XtFree((char*)wchar_t_search_string);
break;
} /* end default */
} /* end switch */
return return_val;
}
Boolean
_XmTextFindStringForwards(Widget w,
XmTextPosition start,
char* search_string,
XmTextPosition *position)
{
register int i;
XmTextWidget tw = (XmTextWidget) w;
XmSourceData data = tw->text.source->data;
Boolean return_val = False, match = False;
int search_length = 0;
char *ptr, *end_ptr, *tmp_ptr, *end_of_data;
search_length = _XmTextCountCharacters(search_string,strlen(search_string));
if (!search_length || !data->length || search_length > data->length)
return FALSE;
/* Search can be broken into three phases for fastest search:
*
* - search from start up to gap_start-strlen(search_string).
* This is a fast simple compare that doesn't worry about
* incursions into the gap.
*
* - search from gap_start-strlen(search_string) until the base
* of the search is moved across the gap.
*
* - search from gap_end to data_end - strlen(search_string).
* This is a fast, simple compare that doesn't worry about
* incursions into the gap or overrunning end of data.
*/
switch ((int)tw->text.char_size) {
case 1: {
/* Make sure you don't search past end of data. End of data is... */
end_of_data = data->ptr + data->length +
(data->gap_end - data->gap_start);
/* actually, only need to search up to end - search_length position */
if (end_of_data - search_length >= data->gap_end)
end_ptr = end_of_data - search_length;
else
end_ptr = data->gap_start -
(search_length - (end_of_data - data->gap_end));
/* Phase one: search from start to gap_start-strlen(search_string) */
ptr = data->ptr + start;
while (!return_val && ptr + search_length <= data->gap_start) {
if (*ptr == *search_string) { /* potential winner! */
for (match = True, i = 1; match && (i < search_length); i++) {
if (ptr[i] != search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = ptr - data->ptr;
return_val = True;
}
}
ptr++; /* advance base of search */
match = True;
}
/* Phase two: these searches span the gap and are SLOW!
* Two possibilities: either I'm just short of the gap
* (and must do searches that span the gap) or start puts
* the base after gap end. Also, possibility that there
* isn't enough room after the gap for a complete match
* (so no need to search it).
*/
/* Do this as nested for loops; the outer loop advances the base for
* the search, the inner loop compares character elements from 0 to
* length(search_string).
*/
/* if no match yet and if need to search prior to gap_start... */
if (!return_val && (data->ptr + start) < data->gap_start) {
if (data->ptr + start < data->gap_start - search_length)
ptr = data->gap_start - search_length;
else
ptr = data->ptr + start;
for (match = True;
ptr < data->gap_start && (data->gap_start - ptr) +
(end_of_data - data->gap_end) >= search_length;
ptr++, match = True) {
if (*ptr == *search_string) { /* we have a potential winner */
for (i = 1; i < search_length && match == True; i ++) {
if (ptr + i >= data->gap_start) {
tmp_ptr = ptr +(data->gap_end - data->gap_start) + i;
if (*tmp_ptr != search_string[i]) {
match = False;
i--;
}
} else {
if (ptr[i] != search_string[i]) {
match = False;
i--;
}
}
} /* end inner for loop - searching from current base */
if (match && (i == search_length)) {/* a winner! */
*position = ptr - data->ptr;
return_val = True;
}
}
if (return_val) break;
} /* end outer for - restart search from a new base */
}
/* phase three: search after gap end upto end of data - search_length */
if (!return_val) {
if (data->ptr + start < data->gap_start)
ptr = data->gap_end; /* we've already started - continue at
* gap end. */
else
ptr = data->ptr + (data->gap_end - data->gap_start) + start;
while (!return_val && ptr <= end_ptr) {
if (*ptr == *search_string) { /* potential winner! */
for (match = True, i = 1; match && (i < search_length); i++) {
if (ptr[i] != search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = ptr - data->ptr -
(data->gap_end - data->gap_start);
return_val = True;
}
}
ptr++; /* advance base of search */
match = True;
}
}
} /* end case 1 */
break;
case 2: {
BITS16 *bits16_ptr, *bits16_search_string, *bits16_gap_start;
BITS16 *bits16_gap_end, *bits16_end_ptr, *bits16_tmp_ptr;
BITS16 *bits16_end_of_data;
bits16_ptr = bits16_search_string = NULL;
bits16_gap_start = bits16_gap_end = NULL;
/* search_length is number of characters (!bytes) in search_string */
bits16_search_string =
(BITS16 *) XtMalloc((unsigned)
(search_length + 1) * (int)tw->text.char_size);
(void) _XmTextBytesToCharacters((char *) bits16_search_string,
search_string, search_length, True,
(int)tw->text.char_size);
/* setup the variables for the search */
bits16_gap_start = (BITS16 *) data->gap_start;
bits16_gap_end = (BITS16 *) data->gap_end;
/* Make sure you don't search past end of data. End of data is... */
bits16_ptr = (BITS16 *)data->ptr;
bits16_end_of_data = bits16_ptr + data->length +
(bits16_gap_end - bits16_gap_start);
/* only need to search up to end - search_length position */
if (bits16_end_of_data - search_length >= bits16_gap_end)
bits16_end_ptr = bits16_end_of_data - search_length;
else
bits16_end_ptr = bits16_gap_start -
(search_length - (bits16_end_of_data - bits16_gap_end));
/* Phase one: search from start to gap start - search_length */
bits16_ptr = (BITS16 *)data->ptr + start;
while (!return_val && bits16_ptr + search_length <= bits16_gap_start) {
if (*bits16_ptr == *bits16_search_string) { /* potential winner! */
for (match = True, i = 1; match && (i < search_length); i++) {
if (bits16_ptr[i] != bits16_search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = bits16_ptr - (BITS16 *)data->ptr;
return_val = True;
}
}
bits16_ptr++; /* advance base of search */
match = True;
}
/* Phase two: these searches span the gap and are SLOW!
* Two possibilities: either I'm just short of the gap
* (and must do searches that span the gap) or start puts
* the base after gap end. Also, possibility that there
* isn't enough room after the gap for a complete match
* (so no need to search it).
*/
/* Do this as nested for loops; the outer loop advances the base for
* the search, the inner loop compares character elements from 0 to
* length(search_string).
*/
/* if no match yet and if need to search prior to gap_start... */
bits16_ptr = (BITS16 *) data->ptr;
if (!return_val && (bits16_ptr + start) < bits16_gap_start) {
if (bits16_ptr + start < bits16_gap_start - search_length)
bits16_ptr = bits16_gap_start - search_length;
else
bits16_ptr = (BITS16*)data->ptr + start;
for (match = True;
bits16_ptr < bits16_gap_start &&
(bits16_gap_start - bits16_ptr) +
(bits16_end_of_data - bits16_gap_end) >= search_length;
bits16_ptr++, match = True) {
if (*bits16_ptr == *bits16_search_string)
{ /* have a potential winner*/
for (i = 1; i < search_length && match == True; i ++) {
if (bits16_ptr + i >= bits16_gap_start) {
bits16_tmp_ptr = bits16_ptr +
(bits16_gap_end - bits16_gap_start) + i;
if (*bits16_tmp_ptr != bits16_search_string[i]) {
match = False;
i--;
}
} else {
if (bits16_ptr[i] != bits16_search_string[i]) {
match = False;
i--;
}
}
} /* end inner for loop - searching from current base */
if (match && (i == search_length)) { /* a winner! */
*position = bits16_ptr - (BITS16*)data->ptr;
return_val = True;
}
}
if (return_val) break;
} /* end outer for - restart search from a new base */
}
/* phase three: search after gap end upto end of data - search_length */
if (!return_val) {
bits16_ptr = (BITS16 *) data->ptr;
if (bits16_ptr + start < bits16_gap_start)
bits16_ptr = bits16_gap_end; /* we've already started...
* continue at gap end. */
else
bits16_ptr = (BITS16*)data->ptr +
(bits16_gap_end - bits16_gap_start) + start;
while (!return_val && bits16_ptr <= bits16_end_ptr) {
if (*bits16_ptr == *bits16_search_string)
{ /* potential winner! */
for (match = True, i=1; match && (i < search_length); i++) {
if (bits16_ptr[i] != bits16_search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = bits16_ptr - (BITS16 *)data->ptr -
(bits16_gap_end - bits16_gap_start);
return_val = True;
}
}
bits16_ptr++; /* advance base of search */
match = True;
}
}
/* clean up before you go */
if (bits16_search_string != NULL)
XtFree((char*)bits16_search_string);
break;
} /* end case 2 */
default: {
wchar_t *wchar_t_ptr, *wchar_t_search_string, *wchar_t_gap_start;
wchar_t *wchar_t_gap_end, *wchar_t_end_ptr, *wchar_t_tmp_ptr;
wchar_t *wchar_t_end_of_data;
wchar_t_ptr = wchar_t_search_string = NULL;
wchar_t_gap_start = wchar_t_gap_end = NULL;
wchar_t_search_string =
(wchar_t *) XtMalloc((unsigned)
(search_length + 1) * sizeof(wchar_t));
(void)_XmTextBytesToCharacters((char *) wchar_t_search_string,
search_string, search_length, True,
(int)tw->text.char_size);
/* setup the variables for the search of new lines before the gap */
wchar_t_gap_start = (wchar_t *) data->gap_start;
wchar_t_gap_end = (wchar_t *) data->gap_end;
wchar_t_ptr = (wchar_t *)data->ptr;
/* Make sure you don't search past end of data. End of data is... */
wchar_t_end_of_data = wchar_t_ptr + data->length +
(wchar_t_gap_end - wchar_t_gap_start);
/* only need to search up to end - search_length position */
if (wchar_t_end_of_data - search_length >= wchar_t_gap_end)
wchar_t_end_ptr = wchar_t_end_of_data - search_length;
else
wchar_t_end_ptr = wchar_t_gap_start -
(search_length - (wchar_t_end_of_data - wchar_t_gap_end));
/* Phase one: search from start to gap start - search_length */
wchar_t_ptr = (wchar_t *)data->ptr + start;
while (!return_val && wchar_t_ptr + search_length <= wchar_t_gap_start) {
if (*wchar_t_ptr == *wchar_t_search_string) { /* potential winner! */
for (match = True, i = 1; match && (i < search_length); i++) {
if (wchar_t_ptr[i] != wchar_t_search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = wchar_t_ptr - (wchar_t *)data->ptr;
return_val = True;
}
}
wchar_t_ptr++; /* advance base of search */
match = True;
}
/* Phase two: these searches span the gap and are SLOW!
* Two possibilities: either I'm just short of the gap
* (and must do searches that span the gap) or start puts
* the base after gap end. Also, possibility that there
* isn't enough room after the gap for a complete match
* (so no need to search it).
*/
/* Do this as nested for loops; the outer loop advances the base for
* the search, the inner loop compares character elements from 0 to
* length(search_string).
*/
/* if no match yet and if need to search prior to gap_start... */
wchar_t_ptr = (wchar_t *) data->ptr;
if (!return_val && (wchar_t_ptr + start) < wchar_t_gap_start) {
if (wchar_t_ptr + start < wchar_t_gap_start - search_length)
wchar_t_ptr = wchar_t_gap_start - search_length;
else
wchar_t_ptr = (wchar_t*)data->ptr + start;
for (match = True;
wchar_t_ptr < wchar_t_gap_start &&
(wchar_t_gap_start - wchar_t_ptr) +
(wchar_t_end_of_data - wchar_t_gap_end) >= search_length;
wchar_t_ptr++, match = True) {
if (*wchar_t_ptr == *wchar_t_search_string) {
/* have a potential winner */
for (i = 1; i < search_length && match == True; i ++) {
if (wchar_t_ptr + i >= wchar_t_gap_start) {
wchar_t_tmp_ptr = wchar_t_ptr +
(wchar_t_gap_end - wchar_t_gap_start) + i;
if (*wchar_t_tmp_ptr != wchar_t_search_string[i]) {
match = False;
i--;
}
} else {
if (wchar_t_ptr[i] != wchar_t_search_string[i]) {
match = False;
i--;
}
}
} /* end inner for loop - searching from current base */
if (match && (i == search_length)) { /* a winner! */
*position = wchar_t_ptr - (wchar_t*)data->ptr;
return_val = True;
}
}
if (return_val) break;
} /* end outer for - restart search from a new base */
}
/* phase three: search after gap end upto end of data - search_length */
if (!return_val) {
wchar_t_ptr = (wchar_t *) data->ptr;
if (wchar_t_ptr + start < wchar_t_gap_start)
wchar_t_ptr = wchar_t_gap_end; /* we've already started...
* continue at gap end. */
else
wchar_t_ptr = (wchar_t*)data->ptr +
(wchar_t_gap_end - wchar_t_gap_start) + start;
while (!return_val && wchar_t_ptr <= wchar_t_end_ptr) {
if (*wchar_t_ptr == *wchar_t_search_string) {
/* potential winner!*/
for (match = True, i = 1; match && (i < search_length); i++) {
if (wchar_t_ptr[i] != wchar_t_search_string[i]) {
match = False;
i--;
}
}
if (i == search_length) { /* we have a winner! */
*position = wchar_t_ptr - (wchar_t *)data->ptr -
(wchar_t_gap_end - wchar_t_gap_start);
return_val = True;
}
}
wchar_t_ptr++; /* advance base of search */
match = True;
}
}
/* clean up before you go */
if (wchar_t_search_string != NULL)
XtFree((char*)wchar_t_search_string);
break;
} /* end default */
} /* end switch */
return return_val;
}
Boolean
XmTextFindString(Widget w,
XmTextPosition start,
char* search_string,
XmTextDirection direction,
XmTextPosition *position)
{
XmSourceData data;
Boolean ret_val;
_XmWidgetToAppContext(w);
if (XmIsTextField(w)) return False;
_XmAppLock(app);
data = ((XmTextWidget)w)->text.source->data;
if (start > data->length)
start = data->length;
else if (start < 0)
start = 0;
if (direction == XmTEXT_BACKWARD)
ret_val = _XmTextFindStringBackwards(w, start, search_string, position);
else
ret_val = _XmTextFindStringForwards(w, start, search_string, position);
_XmAppUnlock(app);
return (ret_val);
}
Boolean
XmTextFindStringWcs(Widget w,
XmTextPosition start,
wchar_t* wc_string,
XmTextDirection direction,
XmTextPosition *position)
{
wchar_t *tmp_wc;
char *string;
int num_chars = 0;
Boolean return_val = False;
XmTextWidget tw = (XmTextWidget) w;
int wcs_ret_val = 0;
_XmWidgetToAppContext(w);
_XmAppLock(app);
if (!XmIsTextField(w)) {
for (num_chars = 0, tmp_wc = wc_string; *tmp_wc != (wchar_t)0L;
num_chars++) tmp_wc++;
string = XtMalloc ((unsigned) (num_chars + 1) * (int)tw->text.char_size);
wcs_ret_val = wcstombs(string, wc_string,
(num_chars + 1) * (int)tw->text.char_size);
if (wcs_ret_val >= 0)
return_val = XmTextFindString(w, start, string, direction, position);
XtFree(string);
_XmAppUnlock(app);
return(return_val);
} else {
_XmAppUnlock(app);
return False;
}
}