home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD1.bin / new / util / edit / jade / src / find.c < prev    next >
C/C++ Source or Header  |  1994-09-04  |  25KB  |  910 lines

  1. /* find.c -- Searching and replacing
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4.    This file is part of Jade.
  5.  
  6.    Jade is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2, or (at your option)
  9.    any later version.
  10.  
  11.    Jade is distributed in the hope that it will be useful, but
  12.    WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with Jade; see the file COPYING.    If not, write to
  18.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22. #include "regexp/regexp.h"
  23.  
  24. #include <string.h>
  25. #include <ctype.h>
  26. #include <stdlib.h>
  27.  
  28. _PR bool findnext(TX *, u_char *, POS *, bool);
  29. _PR bool findprev(TX *, u_char *, POS *, bool);
  30. _PR bool findstrnext(TX *, u_char *, POS *);
  31. _PR bool findstrprev(TX *, u_char *, POS *);
  32. _PR bool findcharnext(TX *, u_char, POS *);
  33. _PR bool findcharprev(TX *, u_char, POS *);
  34. _PR bool replaceit(TX *, u_char *, u_char *, POS *, bool);
  35. _PR bool replaceitstr(TX *, u_char *, u_char *, POS *);
  36. _PR bool mystrcmp(u_char *, u_char *);
  37. _PR u_char *mystrrstrn(u_char *, u_char *, int);
  38. _PR u_char *mystrrchrn(u_char *, u_char, int);
  39. _PR void find_init(void);
  40.  
  41. /* Storage for remembering where the last match was.
  42.    LAST_STRING is the string that was matched against, only it's address is
  43.    used.
  44.    LAST_START and LAST_END is copied straight out of the regexp struct
  45.    LAST_LINE is either -1 meaning the string was not in a buffer, or the
  46.    line number it came from.  */
  47. static u_char *last_string;
  48. static u_char *last_start[NSUBEXP];
  49. static u_char *last_end[NSUBEXP];
  50. static long last_line;
  51.  
  52. static VALUE sym_regexp_error;
  53.  
  54. static void
  55. update_last_match(u_char *str, regexp *prog, long line)
  56. {
  57.     last_string = str;
  58.     memcpy(last_start, (u_char **)prog->startp, sizeof(last_start));
  59.     memcpy(last_end, (u_char **)prog->endp, sizeof(last_end));
  60.     last_line = line;
  61. }
  62.  
  63. _PR VALUE cmd_find_next_regexp(VALUE re, VALUE pos, VALUE tx, VALUE nocase_p);
  64. DEFUN("find-next-regexp", cmd_find_next_regexp, subr_find_next_regexp, (VALUE re, VALUE pos, VALUE tx, VALUE nocase_p), V_Subr4, DOC_find_next_regexp) /*
  65. ::doc:find_next_regexp::
  66. find-next-regexp REGEXP [POS] [BUFFER] [IGNORE-CASE-P]
  67.  
  68. Scans forwards from POS (or the cursor), in BUFFER, looking for a match
  69. with REGEXP. Returns the position of the next match or nil.
  70.  
  71. When IGNORE-CASE-P is non-nil the case of matched strings are ignored. Note
  72. that character classes are still case-significant.
  73. ::end:: */
  74. {
  75.     POS res;
  76.     DECLARE1(re, STRINGP);
  77.     if(POSP(pos))
  78.     res = VPOS(pos);
  79.     else
  80.     res = curr_vw->vw_CursorPos;
  81.     if(!BUFFERP(tx))
  82.     tx = VAL(curr_vw->vw_Tx);
  83.     check_pos(VTX(tx), &res);
  84.     if(findnext(VTX(tx), VSTR(re), &res, !NILP(nocase_p)))
  85.     return(make_lpos(&res));
  86.     return(sym_nil);
  87. }
  88.  
  89. _PR VALUE cmd_find_prev_regexp(VALUE re, VALUE pos, VALUE tx, VALUE nocase_p);
  90. DEFUN("find-prev-regexp", cmd_find_prev_regexp, subr_find_prev_regexp, (VALUE re, VALUE pos, VALUE tx, VALUE nocase_p), V_Subr4, DOC_find_prev_regexp) /*
  91. ::doc:find_prev_regexp::
  92. find-prev-regexp REGEXP [POS] [BUFFER] [IGNORE-CASE-P]
  93.  
  94. Scans backwards from POS (or the cursor), in BUFFER, looking for a match
  95. with REGEXP. Returns the position of the next match or nil.
  96.  
  97. When IGNORE-CASE-P is non-nil the case of matched strings are ignored. Note
  98. that character classes are still case-significant.
  99. ::end:: */
  100. {
  101.     POS res;
  102.     DECLARE1(re, STRINGP);
  103.     if(POSP(pos))
  104.     res = VPOS(pos);
  105.     else
  106.     res = curr_vw->vw_CursorPos;
  107.     if(!BUFFERP(tx))
  108.     tx = VAL(curr_vw->vw_Tx);
  109.     check_pos(VTX(tx), &res);
  110.     if(findprev(VTX(tx), VSTR(re), &res, !NILP(nocase_p)))
  111.     return(make_lpos(&res));
  112.     return(sym_nil);
  113. }
  114.  
  115. _PR VALUE cmd_find_next_string(VALUE str, VALUE pos, VALUE tx);
  116. DEFUN("find-next-string", cmd_find_next_string, subr_find_next_string, (VALUE str, VALUE pos, VALUE tx), V_Subr3, DOC_find_next_string) /*
  117. ::doc:find_next_string::
  118. find-next-string STRING [POS] [BUFFER]
  119.  
  120. Scans forwards from POS (or the cursor), in BUFFER, looking for a match
  121. with STRING. Returns the position of the next match or nil.
  122. ::end:: */
  123. {
  124.     POS res;
  125.     DECLARE1(str, STRINGP);
  126.     if(POSP(pos))
  127.     res = VPOS(pos);
  128.     else
  129.     res = curr_vw->vw_CursorPos;
  130.     if(!BUFFERP(tx))
  131.     tx = VAL(curr_vw->vw_Tx);
  132.     check_pos(VTX(tx), &res);
  133.     if(findstrnext(VTX(tx), VSTR(str), &res))
  134.     return(make_lpos(&res));
  135.     return(sym_nil);
  136. }
  137.  
  138. _PR VALUE cmd_find_prev_string(VALUE str, VALUE pos, VALUE tx);
  139. DEFUN("find-prev-string", cmd_find_prev_string, subr_find_prev_string, (VALUE str, VALUE pos, VALUE tx), V_Subr3, DOC_find_prev_string) /*
  140. ::doc:find_prev_string::
  141. find-prev-string STRING [POS] [BUFFER]
  142.  
  143. Scans backwards from POS (or the cursor), in BUFFER, looking for a match
  144. with STRING. Returns the position of the next match or nil.
  145. ::end:: */
  146. {
  147.     POS res;
  148.     DECLARE1(str, STRINGP);
  149.     if(POSP(pos))
  150.     res = VPOS(pos);
  151.     else
  152.     res = curr_vw->vw_CursorPos;
  153.     if(!BUFFERP(tx))
  154.     tx = VAL(curr_vw->vw_Tx);
  155.     check_pos(VTX(tx), &res);
  156.     if(findstrprev(VTX(tx), VSTR(str), &res))
  157.     return(make_lpos(&res));
  158.     return(sym_nil);
  159. }
  160.  
  161. _PR VALUE cmd_find_next_char(VALUE ch, VALUE pos, VALUE tx);
  162. DEFUN("find-next-char", cmd_find_next_char, subr_find_next_char, (VALUE ch, VALUE pos, VALUE tx), V_Subr3, DOC_find_next_char) /*
  163. ::doc:find_next_char::
  164. find-next-char CHAR [POS] [BUFFER]
  165.  
  166. Scans forwards from POS (or the cursor), in BUFFER, looking for a match
  167. with CHAR. Returns the position of the next match or nil.
  168. ::end:: */
  169. {
  170.     POS res;
  171.     DECLARE1(ch, CHARP);
  172.     if(POSP(pos))
  173.     res = VPOS(pos);
  174.     else
  175.     res = curr_vw->vw_CursorPos;
  176.     if(!BUFFERP(tx))
  177.     tx = VAL(curr_vw->vw_Tx);
  178.     check_pos(VTX(tx), &res);
  179.     if(findcharnext(VTX(tx), VCHAR(ch), &res))
  180.     return(make_lpos(&res));
  181.     return(sym_nil);
  182. }
  183.  
  184. _PR VALUE cmd_find_prev_char(VALUE ch, VALUE pos, VALUE tx);
  185. DEFUN("find-prev-char", cmd_find_prev_char, subr_find_prev_char, (VALUE ch, VALUE pos, VALUE tx), V_Subr3, DOC_find_prev_char) /*
  186. ::doc:find_prev_char::
  187. find-prev-char CHAR [POS] [BUFFER]
  188.  
  189. Scans backwards from POS (or the cursor), in BUFFER, looking for a match
  190. with CHAR. Returns the position of the next match or nil.
  191. ::end:: */
  192. {
  193.     POS res;
  194.     DECLARE1(ch, CHARP);
  195.     if(POSP(pos))
  196.     res = VPOS(pos);
  197.     else
  198.     res = curr_vw->vw_CursorPos;
  199.     if(!BUFFERP(tx))
  200.     tx = VAL(curr_vw->vw_Tx);
  201.     check_pos(VTX(tx), &res);
  202.     if(findcharprev(VTX(tx), VCHAR(ch), &res))
  203.     return(make_lpos(&res));
  204.     return(sym_nil);
  205. }
  206.  
  207. _PR VALUE cmd_replace_regexp(VALUE re, VALUE tplt, VALUE pos, VALUE tx, VALUE nocase_p);
  208. DEFUN("replace-regexp", cmd_replace_regexp, subr_replace_regexp, (VALUE re, VALUE tplt, VALUE pos, VALUE tx, VALUE nocase_p), V_Subr5, DOC_replace_regexp) /*
  209. ::doc:replace_regexp::
  210. replace-regexp REGEXP TEMPLATE [POS] [BUFFER] [IGNORE-CASE-P]
  211.  
  212. If the text at POS or the cursor, matches REGEXP replace it with TEMPLATE,
  213. this is a string that can have the following escape characters,
  214.   \0, \&   whole string matched by REGEXP
  215.   \N       N'th parenthensized expression (1 <= N <= 9)
  216.  
  217. When IGNORE-CASE-P is non-nil the case of matched strings are ignored. Note
  218. that character classes are still case-significant.
  219. ::end:: */
  220. {
  221.     POS res;
  222.     DECLARE1(re, STRINGP);
  223.     DECLARE2(tplt, STRINGP);
  224.     if(POSP(pos))
  225.     res = VPOS(pos);
  226.     else
  227.     res = curr_vw->vw_CursorPos;
  228.     if(!BUFFERP(tx))
  229.     tx = VAL(curr_vw->vw_Tx);
  230.     check_pos(VTX(tx), &res);
  231.     if(!read_only(VTX(tx)) && replaceit(VTX(tx), VSTR(re), VSTR(tplt),
  232.                        &res, !NILP(nocase_p)))
  233.     return(make_lpos(&res));
  234.     return(sym_nil);
  235. }
  236.  
  237. _PR VALUE cmd_replace_string(VALUE orig, VALUE new, VALUE pos, VALUE tx);
  238. DEFUN("replace-string", cmd_replace_string, subr_replace_string, (VALUE orig, VALUE new, VALUE pos, VALUE tx), V_Subr4, DOC_replace_string) /*
  239. ::doc:replace_string::
  240. replace-string ORIGINAL NEW [POS] [BUFFER]
  241.  
  242. If the text at POS, or the cursor, matches ORIGINAL, replace it with the