This is MiscSearchText.m in view mode; [Download] [Up]
/* * Copyright (c) 1993 Christopher J. Kane. All rights reserved. * * This software is subject to the terms of the MiscKit license * agreement. Refer to the license document included with the * MiscKit distribution for these terms. * * Version: 1.2 (25 June 1994) * * Licinda Woudberg - licinda@Black_Albatross.otago.ac.nz * 25 June 1994 * Changed: -replaceAll.... works so that it can handle both plain * text & rtf style document. Still need to double check rtfd's * Changed: -replaceSelection: * now sends textDidChange: notice to the delegate */ #import <misckit/MiscSearchText.h> #import <misckit/MiscTBMK.h> #import <misckit/regexpr.h> @implementation Text (SearchText) - (oneway void)makeSelectionVisible { [self scrollSelToVisible]; } - (int)replaceAll:(const char *)pattern with:(const char *)replacement mode:(SearchMode)mode regexpr:(BOOL)regexpr cases:(BOOL)cases { unsigned char fm[256], tr[256]; struct re_pattern_buffer rpat; Misc_TBMKpattern lpat = NULL; NXStream *in_strm = NULL; int s1=0, e1=0, s2=0, e2=0, ret_val=0, plen=0, rlen=0, pos=0, size=0, p=0, searchTextMaxSize=0; /* Known bug: the delegate will not get textWillChange:, textDidChange: notification messages */ if ( (sp0.cp < 0) && (mode != TextEdgeToTextEdge) ) return SEARCH_NO_SELECTION; if ( ![self isEditable] ) return SEARCH_CANNOT_WRITE; switch ( mode ) /* setup start and end points for the search */ { case TextEdgeToTextEdge: case SelStartToSelStart: case SelEndToSelEnd: s1 = 0; e1 = textLength; break; case TextEdgeToSelStart: s1 = 0; e1 = sp0.cp; break; case TextEdgeToSelEnd: s1 = 0; e1 = spN.cp; break; case SelStartToSelEnd: s1 = sp0.cp; e1 = spN.cp - sp0.cp; break; case SelStartToTextEdge: s1 = sp0.cp; e1 = textLength - sp0.cp; break; case SelEndToTextEdge: s1 = spN.cp; e1 = textLength - spN.cp; break; case SelEndToSelStart: s1 = 0; e1 = sp0.cp; s2 = spN.cp; e2 = textLength - spN.cp; break; default: return SEARCH_INVALID_ARGUMENT; } searchTextMaxSize = s1 + e1; plen = strlen(pattern); /* pattern length */ rlen = strlen(replacement); /* replacement length */ if (regexpr) { /* dealing with a regular expression */ char *str; int i; memset(&rpat, 0, sizeof(rpat)); for ( i = 256; i--; ) tr[i] = i; if (!cases) for ( i = 'A'; i <= 'Z'; i++ ) tr[i] = i - 'A' + 'a'; rpat.translate = tr; rpat.fastmap = fm; str = re_compile_pattern((char *)pattern, plen, &rpat); if (str != NULL) return (strcmp(str, "Out of memory") ? SEARCH_INVALID_REGEXPR : SEARCH_INTERNAL_ERROR); } else { /* dealing with a normal find & replace - setup the Pattern to search for */ lpat = Misc_TBMKpattern_alloc(pattern, plen, 0, !cases); if (lpat == NULL) return SEARCH_INTERNAL_ERROR; } in_strm = NXOpenMemory(NULL, 0, NX_READWRITE); /* open the stream */ if (in_strm == NULL) { ret_val = SEARCH_INTERNAL_ERROR; goto exit; } [self writeText:in_strm]; /* read the text into the stream */ NXSeek(in_strm, 0, NX_FROMSTART); /* start at the begining */ ret_val = 0; /* set the counter to zero */ start_searching: if (NXUserAborted()) { ret_val = SEARCH_ABORTED; goto exit; } if (regexpr) { /* regular expression search */ p = -1; if ( s1 > e1) /* reached the end of the search area */ goto exit; if ( s1 >= 0 ) { searchTextMaxSize = s1 + e1; p = re_search_pattern(&rpat, in_strm->buf_base, searchTextMaxSize, s1, e1, 0); } if (p==-1 && e2!=0) { s1 = s2; e1 = e2; s2 = e2 = 0; goto start_searching; } if (p==-2) { ret_val = SEARCH_INTERNAL_ERROR; goto exit; } if (p>-1) { int newTextPos=0; pos = p; size = re_match_pattern(&rpat, in_strm->buf_base, searchTextMaxSize, pos, 0); if (size<0) { ret_val = SEARCH_INTERNAL_ERROR; goto exit; } newTextPos = (ret_val * (rlen - size)) + pos; [self setSel:newTextPos :(newTextPos+size) ]; [self makeSelectionVisible]; [self replaceSel:replacement]; s1 = p + rlen; ret_val++; goto start_searching; } } else { /* normal find & replace search */ p = 0; if (s1 > e1) /* reached the end of the search area */ goto exit; if (s1 >= 0) p = Misc_TBMKsearch_memory(lpat, in_strm->buf_base + s1, e1, 0, &pos); if (p < 0) { /* couldn't find a match for some reason */ ret_val = SEARCH_INTERNAL_ERROR; goto exit; } if (p == 0 && e2 != 0) { /* couldn't find a match in the 1st selection area - there is a 2nd area to check */ s1 = s2; e1 = e2; s2 = e2 = 0; goto start_searching; } if (p > 0) { /* found a match */ int newTextPos=0; pos = pos + s1; /* set selection variables */ newTextPos = (ret_val * (rlen - plen)) + pos; size = plen; ret_val++; [self setSel:newTextPos :(newTextPos+size) ]; /* select the area */ [self makeSelectionVisible]; [self replaceSel:replacement]; /* replace the area */ s1 = pos + plen; /* reset the start position */ goto start_searching; } } exit: Misc_TBMKpattern_free(&lpat); if (in_strm != NULL) NXCloseMemory(in_strm, NX_FREEBUFFER); return ret_val; } - (oneway void)replaceSelection:(const char *)replacement { if ([self isEditable]) { if (delegate && [delegate respondsTo:@selector(textWillChange:)]) [delegate textWillChange:self]; [self replaceSel:replacement]; if (delegate && [delegate respondsTo:@selector(textDidChange:)]) [delegate textDidChange:self]; } } - (int)searchFor:(const char *)pattern mode:(SearchMode)mode reverse:(BOOL)rev regexpr:(BOOL)regexpr cases:(BOOL)cases position:(out int *)pos size:(out int *)size { unsigned char fm[256], tr[256]; struct re_pattern_buffer rpat; Misc_TBMKpattern lpat=NULL; NXStream *in_strm=NULL; int s1=0, e1=0, s2=0, e2=0, ret_val, plen, p, position; if (sp0.cp<0 && mode!=TextEdgeToTextEdge) return SEARCH_NO_SELECTION; if (rev) switch (mode) { case TextEdgeToSelStart: s1 = textLength-1; e1 = sp0.cp-textLength; break; case TextEdgeToSelEnd: s1 = textLength-1; e1 = spN.cp-textLength; break; case TextEdgeToTextEdge: s1 = textLength-1; e1 = -textLength; break; case SelStartToSelEnd: s1 = sp0.cp-1; e1 = -sp0.cp+1; s2 = textLength-1; e2 = spN.cp-textLength+1; break; case SelStartToTextEdge: s1 = sp0.cp-1; e1 = -sp0.cp+1; break; case SelStartToSelStart: s1 = sp0.cp-1; e1 = -sp0.cp+1; s2 = textLength-1; e2 = sp0.cp-textLength+1; break; case SelEndToTextEdge: s1 = spN.cp-1; e1 = -spN.cp+1; break; case SelEndToSelStart: s1 = spN.cp-1; e1 = sp0.cp-spN.cp+1; break; case SelEndToSelEnd: s1 = spN.cp-1; e1 = -spN.cp+1; s2 = textLength-1; e2 = spN.cp-textLength+1; break; default: return SEARCH_INVALID_ARGUMENT; } else switch (mode) { case TextEdgeToSelStart: s1 = 0; e1 = sp0.cp; break; case TextEdgeToSelEnd: s1 = 0; e1 = spN.cp; break; case TextEdgeToTextEdge: s1 = 0; e1 = textLength; break; case SelStartToSelEnd: s1 = sp0.cp; e1 = spN.cp-sp0.cp; break; case SelStartToTextEdge: s1 = sp0.cp; e1 = textLength-sp0.cp; break; case SelStartToSelStart: s1 = sp0.cp; e1 = textLength-sp0.cp; s2 = 0; e2 = sp0.cp; break; case SelEndToTextEdge: s1 = spN.cp; e1 = textLength-spN.cp; break; case SelEndToSelStart: s1 = spN.cp; e1 = textLength-spN.cp; s2 = 0; e2 = sp0.cp; break; case SelEndToSelEnd: s1 = spN.cp; e1 = textLength-spN.cp; s2 = 0; e2 = spN.cp; break; default: return SEARCH_INVALID_ARGUMENT; } plen = strlen(pattern); if (regexpr) { char *str; int i; memset(&rpat, 0, sizeof(rpat)); for(i=256; i--;) tr[i] = i; if (!cases) for(i='A'; i<='Z'; i++) tr[i] = i-'A'+'a'; rpat.translate = tr; rpat.fastmap = fm; str = re_compile_pattern((char *)pattern, plen, &rpat); if (str!=NULL) return (strcmp(str, "Out of memory")?SEARCH_INVALID_REGEXPR:SEARCH_INTERNAL_ERROR); } else { lpat = Misc_TBMKpattern_alloc(pattern, plen, rev, !cases); if (lpat==NULL) return SEARCH_INTERNAL_ERROR; } in_strm = NXOpenMemory(NULL, 0, NX_READWRITE); if (in_strm==NULL) { ret_val = SEARCH_INTERNAL_ERROR; goto exit; } [self writeText:in_strm]; NXSeek(in_strm, 0, NX_FROMSTART); ret_val = 0; start_searching: if (NXUserAborted()) { ret_val = SEARCH_ABORTED; goto exit; } if (regexpr) { p = -1; if (s1>=0) p = re_search_pattern(&rpat, in_strm->buf_base, textLength, s1, e1, 0); if (p==-1 && e2!=0) { s1 = s2; e1 = e2; s2 = e2 = 0; goto start_searching; } if (p==-2) { ret_val = SEARCH_INTERNAL_ERROR; goto exit; } if (p>-1) { *pos = p; *size = re_match_pattern(&rpat, in_strm->buf_base, textLength, p, 0); if (*size<0) { ret_val = SEARCH_INTERNAL_ERROR; goto exit; } ret_val = 1; } } else { p = 0; if (s1>=0) p = Misc_TBMKsearch_memory(lpat, in_strm->buf_base+s1, e1, 0, &position); if (p<0) { ret_val = SEARCH_INTERNAL_ERROR; goto exit; } if (p==0 && e2!=0) { s1 = s2; e1 = e2; s2 = e2 = 0; goto start_searching; } if (p>0) { *pos = position+s1; *size = plen; ret_val = 1; } } exit: Misc_TBMKpattern_free(&lpat); if (in_strm!=NULL) NXCloseMemory(in_strm, NX_FREEBUFFER); return ret_val; } - (oneway void)selectTextFrom:(int)start to:(int)end { if ([self isSelectable] && start<=end && 0<=start) [self setSel:start :end]; } - (int)setRegExprSyntax:(int)syntax { return re_set_syntax(syntax); } - (void)writeSelectionToPasteboard:(in Pasteboard *)pboard asType:(in NXAtom)type { char text[spN.cp-sp0.cp+1]; [self getSubstring:text start:sp0.cp length:spN.cp-sp0.cp]; text[spN.cp-sp0.cp] = '\0'; if (*text!='\0') { [pboard declareTypes:&type num:1 owner:NULL]; [pboard writeType:type data:text length:spN.cp-sp0.cp]; } } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.