/* ** ContentIndexer.m ** ** Copyright (c) 2004 ** ** Author: Yen-Ju Chen ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "ContentIndexer.h" #include "GNUstep.h" #include "Constants.h" #include "RegEx.h" static ContentIndexer *sharedInstance; @implementation ContentIndexer /* main search */ - (NSArray *) filesContain: (NSString *) pattern { if ((pattern == nil) || (indexLocation == nil) || (namazuLocation == nil)) return; if ([pattern isEqualToString: cachePattern]) return AUTORELEASE([cacheFiles copy]); //NSLog(@"search %@", pattern); NSTask *task = [[NSTask alloc] init]; NSPipe *outputPipe = [NSPipe pipe]; NSFileHandle *handle = [outputPipe fileHandleForReading]; NSData *data = nil; NSMutableArray *args = [NSMutableArray array]; NSArray *files = nil; NSMutableString *result = [[NSMutableString alloc] init]; NSString *output; [args addObject: @"-l"]; [args addObject: @"-a"]; [args addObject: pattern]; [args addObject: indexLocation]; //NSLog(@"namazuLocation %@", namazuLocation); //NSLog(@"indexLocation %@", indexLocation); [task setLaunchPath: namazuLocation]; [task setArguments: args]; [task setStandardOutput: outputPipe]; [task launch]; while((data = [handle availableData]) && ([data length])) { output = [[NSString alloc] initWithData: data encoding: [NSString defaultCStringEncoding]]; [result appendString: output]; //NSLog(@"Namazu %@", output); RELEASE(output); } //NSLog(@"content index result %@", result); files = [result componentsSeparatedByString: @"\n"]; //NSLog(@"files %@", files); RELEASE(result); if ((files) && ([files count] > 0)) { ASSIGN(cachePattern, AUTORELEASE([pattern copy])); [cacheFiles setArray: files]; return AUTORELEASE([files copy]); } else return nil; } /* window delegate */ - (BOOL) windowShouldClose: (id) sender { [NSApp stopModal]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; if (mknmzLocation) [defaults setObject: mknmzLocation forKey: MKNMZLocationPath]; if (namazuLocation) [defaults setObject: namazuLocation forKey: NamazuLocationPath]; return YES; } /* accessaries */ - (void) setIndexLocation: (NSString *) path { if ([indexLocation isEqualToString: path]) return; ASSIGN(indexLocation, path); } /* Action */ - (NSString *) _locationFromOpenPanel { int result; NSOpenPanel *panel = [NSOpenPanel openPanel]; [panel setCanChooseDirectories: NO]; [panel setAllowsMultipleSelection: NO]; [panel setResolvesAliases: YES]; result = [panel runModalForTypes: nil]; if (result == NSOKButton) { return [[panel filenames] objectAtIndex: 0]; } else return nil; } - (IBAction)mknmzFindButtonAction:(id)sender { NSString *path = [self _locationFromOpenPanel]; if (path) { [mknmzTextField setStringValue: path]; ASSIGN(mknmzLocation, path); } } - (IBAction)mknmzLocationTextFieldAction:(id)sender { BOOL isDir; NSString *path = [[sender stringValue] stringByStandardizingPath]; NSFileManager *fm = [NSFileManager defaultManager]; if (([fm fileExistsAtPath: path isDirectory: &isDir]) && (isDir == NO)) { ASSIGN(mknmzLocation, path); } else { NSBeep(); [sender setStringValue: @"File does not exist"]; } } - (IBAction)namazuFindButtonAction:(id)sender { NSString *path = [self _locationFromOpenPanel]; if (path) { [namazuTextField setStringValue: path]; ASSIGN(namazuLocation, path); } } - (IBAction)namazuLocationTextFieldAction:(id)sender { BOOL isDir; NSString *path = [[sender stringValue] stringByStandardizingPath]; NSFileManager *fm = [NSFileManager defaultManager]; if (([fm fileExistsAtPath: path isDirectory: &isDir]) && (isDir == NO)) { ASSIGN(namazuLocation, path); } else { NSBeep(); [sender setStringValue: @"File does not exist"]; } } - (IBAction)rebuildContentIndexButtonAction:(id)sender { if (indexLocation == nil) return; //NSLog(@"rebuild index %@:", indexLocation); //NSLog(@"1. create index directory"); BOOL result; NSFileManager *fm = [NSFileManager defaultManager]; [rebuildLabel setStringValue: @""]; [rebuildLabel display]; [rebuildProgressIndicator startAnimation: self]; [rebuildLabel setStringValue: @"Creating index directory..."]; [rebuildLabel display]; if ([fm fileExistsAtPath: indexLocation]) { /* isDir is checked in -makeIndexKeyAndOrderFront */ [rebuildLabel setStringValue: @"Index directory existed."]; [rebuildLabel display]; } else { if ([fm createDirectoryAtPath: indexLocation attributes: nil] == NO) { [rebuildLabel setStringValue: @"Failed to create index directory."]; [rebuildLabel display]; return; } else { [rebuildLabel setStringValue: @"Index directory is created."]; [rebuildLabel display]; } } [rebuildLabel setStringValue: @"Creating indexes..."]; [rebuildLabel display]; //NSLog(@"2. create index"); NSTask *task = [[NSTask alloc] init]; NSPipe *outputPipe = [NSPipe pipe]; NSFileHandle *handle = [outputPipe fileHandleForReading]; NSData *data = nil; NSMutableArray *args = [NSMutableArray array]; NSMutableDictionary *env = [NSMutableDictionary dictionaryWithDictionary: [[NSProcessInfo processInfo] environment]]; [env setObject: @"0" forKey: @"PERL_HASH_SEED"]; #ifndef GNUSTEP /* Add local path for xpdf */ NSString *path = [[env objectForKey: @"PATH"] stringByAppendingString: @":/usr/local/bin"]; [env setObject: path forKey: @"PATH"]; #endif NSString *output; NSRange range; [args addObject: @"-z"]; /* Check filesize changed */ [args addObject: @"-O"]; [args addObject: indexLocation]; [args addObject: [indexLocation stringByDeletingLastPathComponent]]; //NSLog(@"mknmzLocation %@", mknmzLocation); [task setLaunchPath: mknmzLocation]; [task setArguments: args]; [task setStandardOutput: outputPipe]; [task setEnvironment: env]; //[env writeToFile: @"/tmp/MyLibrar.env" atomically: YES]; [task launch]; while((data = [handle availableData]) && ([data length])) { output = [[NSString alloc] initWithData: data encoding: [NSString defaultCStringEncoding]]; //NSLog(@"MKNMZ %@", output); range = [RegExParser rangeOfString: @"[0-9]*/[0-9]* -" inString: output]; if (range.location != NSNotFound) { [rebuildLabel setStringValue: [output substringWithRange: range]]; [rebuildLabel display]; } RELEASE(output); } /* Check validaion of index */ NSString *NMZ_i = [indexLocation stringByAppendingPathComponent: @"NMZ.i"]; if ([fm fileExistsAtPath: NMZ_i]) { [rebuildLabel setStringValue: @"Successfully created indexes."]; [rebuildLabel display]; } else { [rebuildLabel setStringValue: @"Failed to create indexes."]; [rebuildLabel display]; } /* garbage index */ //NSLog(@"3. garbage clean index"); task = [[NSTask alloc] init]; outputPipe = [NSPipe pipe]; handle = [outputPipe fileHandleForReading]; data = nil; args = [NSMutableArray array]; [rebuildLabel setStringValue: @"Clean up indexes..."]; [rebuildLabel display]; [args addObject: indexLocation]; [task setLaunchPath: [[mknmzLocation stringByDeletingLastPathComponent] stringByAppendingPathComponent: @"gcnmz"]]; [task setArguments: args]; [task setStandardOutput: outputPipe]; [task setEnvironment: env]; [task launch]; while((data = [handle availableData]) && ([data length])) { output = [[NSString alloc] initWithData: data encoding: [NSString defaultCStringEncoding]]; //NSLog(@"MKNMZ %@", output); RELEASE(output); } [rebuildLabel setStringValue: @"Indexes are successfully built"]; [rebuildLabel display]; /* Clean cache */ DESTROY(cachePattern); [cacheFiles removeAllObjects]; [rebuildProgressIndicator stopAnimation: self]; } - (IBAction)removeContentIndexButtonAction:(id)sender { if (indexLocation == nil) return; //NSLog(@"remove index"); NSFileManager *fm = [NSFileManager defaultManager]; [removeProgressIndicator startAnimation: self]; BOOL result = [fm removeFileAtPath: indexLocation handler: nil]; if (result == NO) { NSLog(@"Internal Error: Cannot remove index at %@", indexLocation); [removeLabel setStringValue: @"Failed to remove index directory"]; } /* Clean cache */ DESTROY(cachePattern); [cacheFiles removeAllObjects]; [removeProgressIndicator stopAnimation: self]; } - (IBAction)namazuButtonAction:(id)sender { /* Open namazu website */ [[NSWorkspace sharedWorkspace] openURL: [NSURL URLWithString: @"http://www.namazu.org"]]; } - (void) awakeFromNib { if (indexLocation == nil) { [indexLocationLabel setStringValue: @"No indexes"]; } else { [indexLocationLabel setStringValue: indexLocation]; } [rebuildProgressIndicator setUsesThreadedAnimation: YES]; [removeProgressIndicator setUsesThreadedAnimation: YES]; } - (void) makeIndexerKeyAndOrderFront: (id)sender { if (indexPanel == nil) { BOOL result = [NSBundle loadNibNamed: @"ContentIndexingPanel" owner: self]; if (result == NO) { NSLog(@"Unable to load ContentIndexingPanel"); return; } } if (mknmzLocation) { [mknmzTextField setStringValue: mknmzLocation]; } else { [mknmzTextField setStringValue: @"/usr/local/bin/mknmz"]; } if (namazuLocation) { [namazuTextField setStringValue: namazuLocation]; } else { [namazuTextField setStringValue: @"/usr/local/bin/namazu"]; } /* Hide result */ [rebuildLabel setStringValue: @""]; [removeLabel setStringValue: @""]; /* Check index directory */ NSString *s; NSFileManager *fm = [NSFileManager defaultManager]; BOOL isDir; if (indexLocation) { if ([fm fileExistsAtPath: indexLocation isDirectory: &isDir]) { if (isDir == YES) { s = indexLocation; } else { NSRunAlertPanel(sFileError, [NSString stringWithFormat: sIndexDirectoryInvalid_, indexLocation], sOK, nil, nil, nil); return; } } else { s = [NSString stringWithFormat: @"%@ (No indexes yet)", indexLocation]; } } //NSLog(@"s %@", s); [indexLocationLabel setStringValue: s]; [indexPanel makeKeyAndOrderFront: sender]; [NSApp runModalForWindow: indexPanel]; } + (ContentIndexer *) sharedIndexer { if (sharedInstance == nil) { sharedInstance = [[ContentIndexer alloc] init]; } return sharedInstance; } - (id) init { self = [super init]; cacheFiles = [[NSMutableArray alloc] init]; NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSString *path = [defaults stringForKey: MKNMZLocationPath]; if (path) { ASSIGN(mknmzLocation, path); } else { ASSIGN(mknmzLocation, @"/usr/local/bin/mknmz"); } path = [defaults stringForKey: NamazuLocationPath]; if (path) { ASSIGN(namazuLocation, path); } else { ASSIGN(namazuLocation, @"/usr/local/bin/namazu"); } return self; } - (void) dealloc { RELEASE(cacheFiles); [super dealloc]; } @end