/* $XConsortium: TextFind.c /main/6 1995/09/19 23:17:17 cde-sun $ */ /* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * */ /* * HISTORY */ /* (c) Copyright 1989, DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASS. */ /* (c) Copyright 1987, 1988, 1989, 1990, 1991, 1992 HEWLETT-PACKARD COMPANY */ #include #include #include /* for , 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; } }