!+ ! WILD_SEARCH.TPU - Wild card searching !- ! procedure eve_search(the_arg) ! Wild-card search procedure local the_direction, the_target, my_key; my_key := last_key; ! How were we invoked? if (my_key = RET_KEY) then ! Was it SEARCH ? my_key := DO; endif; if (current_direction = FORWARD) then the_direction := 'Forward '; else the_direction := 'Reverse '; endif; the_target := the_arg; if (the_arg = '') then the_target := read_line(the_direction + 'wild-card search: '); endif; if (the_target = '') then if (last_key <> my_key) then return; endif; else if (build_pattern(the_target, the_target) = 1) then execute( 'eveplus_search_target := ' + the_target +';' ); else eveplus_search_target := the_target; endif; endif; eve_find(eveplus_search_target); endprocedure !+ ! Build a pattern for pattern searching. Pattern characters are: ! ! « - beginning of line ! » - end of line ! % - single-character wildcard ! * - multi-character wildcard, do not cross record boundaries ! # - multi-character wildcard, cross record boundaries ! \ - quote next character ! ^ - next char. is ctrl character ! ! BUILD_PATTERN takes a search string in INPUT_STRING and returns either ! a search string or a pattern string in RESULT_STRING. If RESULT_STRING ! is a search string, BUILD_PATTERN returns 0. If it is a pattern string, ! BUILD_PATTERN returns 1. !- PROCEDURE build_pattern( input_string, result_string ) LOCAL s1, s2, i, j, c, quote_next, ctrl_next, match_started, pat; s1 := ''; s2 := ''; i := 1; quote_next := 0; ctrl_next := 0; match_started := 0; pat := ''; !+ ! Process each character in the input string !- LOOP EXITIF i > LENGTH(input_string); c := SUBSTR(input_string, i, 1); !+ ! Do quoting if we're supposed to !- IF quote_next = 1 THEN IF c = "'" THEN s1 := s1 + "''" ELSE s1 := s1 + c ENDIF; s2 := s2 + c; i := i + 1; quote_next := 0 ELSE !+ ! Do CTRL/n quoting if we're supposed to !- IF ctrl_next = 1 THEN CHANGE_CASE(c, UPPER); c := ASCII(INDEX("@ABCDEFGHIJKLMNOPQRSTUVWXYZ[8901", c) - 1); s1 := s1 + c; s2 := s2 + c; i := i + 1; ctrl_next := 0 ELSE !+ ! A normal character or wildcard !- CASE c FROM '' TO 'ÿ' ['\']: !+ ! quote next character !- quote_next := 1; i := i + 1; ['^']: !+ ! CTRL next character !- ctrl_next := 1; i := i + 1; ['«']: !+ ! Begin-of-line !- IF match_started THEN pat := pat + "')"; match_started := 0 ENDIF; IF LENGTH(s1) > 0 THEN pat := pat + "& '" + s1 + "'"; s1 := '' ENDIF; pat := pat + "& LINE_BEGIN"; i := i + 1; ['»']: !+ ! End-of-line !- IF match_started THEN pat := pat + "')"; match_started := 0 ENDIF; IF LENGTH(s1) > 0 THEN pat := pat + "& '" + s1 + "'"; s1 := '' ENDIF; pat := pat + "& LINE_END"; i := i + 1; ['#']: !+ ! General match, crossing record boundaries. ! ! Start by eating all following wildcards. !- IF match_started THEN pat := pat + "')"; match_started := 0 ENDIF; LOOP EXITIF i > LENGTH(input_string); EXITIF INDEX('«»*#%', SUBSTR(input_string, i, 1)) = 0; i := i + 1 ENDLOOP; !+ ! Ignore the wildcard if at end-of-pattern string !- IF i <= LENGTH(input_string) THEN !+ ! Get the stop character (which may be quoted) !- CASE SUBSTR(input_string, i, 1) FROM '' TO 'ÿ' ['\']: IF i = LENGTH(input_string) THEN c := ASCII(0) ELSE c := SUBSTR(input_string, i+1, 1) ENDIF; ['^']: IF i = LENGTH(input_string) THEN c := ASCII(0) ELSE c := SUBSTR(input_string, i+1, 1); CHANGE_CASE(c, UPPER); c := ASCII(INDEX("@ABCDEFGHIJKLMNOPQRSTUVWXYZ[8901", c) - 1) ENDIF; [INRANGE]: c := SUBSTR(input_string, i, 1) ENDCASE; !+ ! Double it if apostrophe !- IF c = "'" THEN c := "''" ENDIF; !+ ! Put it in the pattern !- IF LENGTH(s1) > 0 THEN pat := pat + "& '" + s1 + "'"; s1 := '' ENDIF; pat := pat + "& SCANL('" + c + "')" ENDIF; ['*']: !+ ! General wildcard, not crossing record boundaries ! ! Eat following * and % !- IF match_started THEN pat := pat + "')"; match_started := 0 ENDIF; LOOP EXITIF i > LENGTH(input_string); EXITIF INDEX('*%', SUBSTR(input_string, i, 1)) = 0; i := i + 1 ENDLOOP; !+ ! Use REMAIN if at end of input_string !- IF i > LENGTH(input_string) THEN IF LENGTH(s1) > 0 THEN pat := pat + "& '" + s1 + "'"; s1 := '' ENDIF; pat := pat + "& REMAIN" ELSE !+ ! Ignore * if followed by # !- IF SUBSTR(input_string, i, 1) <> "#" THEN IF LENGTH(s1) > 0 THEN pat := pat + "& '" + s1 + "'"; s1 := '' ENDIF; !+ ! Use REMAIN if « or » follows !- IF (SUBSTR(input_string, i, 1) = "«") OR (SUBSTR(input_string, i, 1) = "»") THEN pat := pat + "& REMAIN" ELSE !+ ! Use the MATCH built-in. We will accumulate ! MATCH characters until another special marker ! is encountered. !- pat := pat + "& MATCH('"; match_started := 1 ENDIF ENDIF ENDIF; ['%']: !+ ! Single-character wildcard. ! ! Start by counting consecutive %s !- j := 0; LOOP EXITIF i > LENGTH(input_string); EXITIF SUBSTR(input_string, i, 1) <> "%"; i := i + 1; j := j + 1 ENDLOOP; !+ ! Put it in the pattern !- IF LENGTH(s1) > 0 THEN pat := pat + "& '" + s1 + "'"; s1 := '' ENDIF; pat := pat + "& ARB(" + STR(j) + ")"; ["'"]: !+ ! Apostrophes must be doubled in STR1 !- s1 := s1 + "''"; s2 := s2 + "'"; i := i + 1; [INRANGE]: !+ ! Just an ordinary character !- s1 := s1 + c; s2 := s2 + c; i := i + 1; ENDCASE ENDIF ENDIF ENDLOOP; !+ ! Empty out STR1 !- IF (LENGTH(s1) > 0) AND (LENGTH(pat) > 0) THEN IF match_started THEN pat := pat + s1 + "')" ELSE pat := pat + "& '" + s1 + "'" ENDIF ENDIF; !+ ! Return either a string or a pattern string !- IF LENGTH(pat) > 0 THEN result_string := SUBSTR(pat, 3, LENGTH(pat) - 2); RETURN 1 ELSE result_string := s2; RETURN 0 ENDIF ENDPROCEDURE procedure tpu$local_init ! Initialization eve$arg1_search := eve$arg1_buffer; eveplus_search_target := ''; endprocedure;