This is Dictionary.m in view mode; [Download] [Up]
/*
File Dictionary.m
A dictionary is responsible for finding words that match a prespecified pattern. Each dictionary is tied to a .xdict file that contains both words and index information to facilitate lookup. See the file xdict.c for information about the dictionary file format.
*/
#import <appkit/appkit.h>
#import "Dictionary.h"
#import "FunctionCache.h"
#import "filing.h"
#import <streams/streams.h>
#import <stdio.h>
#import <strings.h>
#import <ctype.h>
#import <libc.h>
/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行 */
static char * types [] = {
"xdict",
"XDICT",
NULL
};
#define INITIALCOUNT 0
#define ENTRYSIZE(n) ((sizeof(char) + sizeof(long)) * n)
#define OFFSETSIZE(i,n) (sizeof(char) * n + sizeof(long) * i)
#define CACHESIZE 3000
/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行 */
// static void lowercase (char *);
static void createDictionary (NXStream * input, NXStream * output);
static void openDictionary (NXStream * input, wordIndex index);
static void createIndex (NXStream *, NXStream *, wordIndex, int);
static int getWord (NXStream *, char *, int);
static void getAppDirectory (char *);
/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行 */
@implementation Dictionary
- (wordIndex *) getIndex { return &index; }
/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行 */
- init
{
char directory [1000];
[super init];
cache = [[FunctionCache alloc]
initKeyType: ISASTRING
valueType: ISAOBJECT
capacity: CACHESIZE ];
getAppDirectory(directory);
strcat(directory, DEFAULTDICTIONARY);
[self useDictionary: directory];
return self;
}
- free
{
[self notify: WILLFREE];
if (file != NULL) NXClose(file);
[super free];
return self;
}
- create: sender
{
const char * infile, * outfile;
NXStream * input, * output;
if ((infile = fileForOpen(NULL)) != NULL)
if ((outfile = fileForSave("xdict")) != NULL)
{
input = NXMapFile(infile, NX_READONLY);
output = NXOpenMemory(NULL, 0, NX_WRITEONLY);
createDictionary(input, output);
NXSaveToFile(output, outfile);
NXClose(input);
NXCloseMemory(output, NX_FREEBUFFER);
}
return self;
}
- use: sender
{
const char * filename;
if ((filename = fileForOpen(types)) != NULL) [self useDictionary: filename];
return self;
}
- useDictionary: (const char *) filename
{
if (file != NULL) NXClose(file);
openDictionary(file = NXMapFile(filename, NX_READONLY), index);
[self notify: DIDCHANGE];
return self;
}
/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行 */
/*
Here are two methods to locate words that match a specific pattern. The find method accepts general patterns. Limit restricts its search to a list of previous matches and finds all words that have a given letter in a given location.
*/
- find: (char *) pattern
{
id words;
if ((words = [cache find: pattern]) == nil)
words = [self findWithoutCache: pattern];
return words;
}
- find: (char *) pattern changeAt: (int) i
{
id words;
char c;
int n;
if ((words = [cache find: pattern]) == nil)
{
if ((c = pattern[i]) != WILDCARD)
{
n = strlen(pattern);
pattern[i] = WILDCARD;
words = [self find: pattern];
words = [self limit: words toLetter: c - 'a' at: i forLength: n ];
pattern[i] = c;
}
else words = [self findWithoutCache: pattern];
}
return words;
}
- findWithoutCache: (char *) pattern
{
char * string;
id words, match;
int i, n;
words = match = nil;
i = n = strlen(pattern);
while (i--) if (pattern[i] != WILDCARD)
{
match = words;
words = [self limit: match toLetter: pattern[i] - 'a' at: i forLength: n];
[match free];
}
string = (char *) malloc(strlen(pattern) + 1);
strcpy(string, pattern);
[cache add: string value: words];
return words;
}
- limit: match toLetter: (char) c at: (int) i forLength: (int) n
{
int current, matchWord;
long size, offset;
int j, count;
id words;
if (n < MINLETTERS) return nil;
matchWord = j = count = 0;
words = [[Storage alloc]
initCount: 0 elementSize: sizeof(long) description: "i" ];
if (match != nil)
{
if ((count = [match count]) == 0) return words;
matchWord = WORD(match, j = 0);
}
size = ENTRYSIZE(n);
offset = index[n].words + OFFSETSIZE(i, n);
current = index[n].linkTable[c][i].first;
while (current != LAST)
{
if (match == nil) [words addElement: ¤t];
else
{
while (matchWord > current)
if (++j < count)
matchWord = WORD(match, j); else
break;
if (j == count) return words;
if (matchWord == current) [words addElement: ¤t];
}
NXSeek(file, size * current + offset, NX_FROMSTART);
NXRead(file, ¤t, sizeof(int));
}
return words;
}
- read: (char *) string word: (int) i forLength: (int) n
{
NXSeek(file, ENTRYSIZE(n) * i + index[n].words, NX_FROMSTART);
NXRead(file, string, n);
string[n] = '\0';
return self;
}
@end
/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行 */
/*
static void lowercase (string)
char * string;
{
while (*string != '\0')
{
*string = tolower(*string);
string++;
}
}
*/
/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行 */
/*
Here are the routines that create and open dictionary files.
*/
static void createDictionary (input, output)
NXStream * input, * output;
{
wordIndex index;
int n;
NXSeek(output, sizeof(wordIndex), NX_FROMSTART);
for (n = MINLETTERS; n <= MAXLETTERS; n++)
{
NXSeek(input, 0, NX_FROMSTART);
createIndex(input, output, index, n);
}
NXSeek(output, 0, NX_FROMSTART);
NXWrite(output, index, sizeof(wordIndex));
}
static void openDictionary (input, index)
NXStream * input;
wordIndex index;
{
NXSeek(input, 0, NX_FROMSTART);
NXRead(input, index, sizeof(wordIndex));
}
/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行 */
static void createIndex (input, output, index, n)
NXStream * input, * output;
wordIndex index;
int n;
{
char word [100];
int i, j;
index[n].words = NXTell(output);
index[n].n = 0;
for (j = 0; j < LETTERS; j++)
for (i = 0; i < MAXLETTERS; i++)
{
index[n].linkTable[j][i].first = LAST;
index[n].linkTable[j][i].n = 0;
}
while (getWord(input, word, n))
{
NXWrite(output, word, n);
for (i = 0; i < n; i++)
{
j = word[i] - 'a';
NXWrite(output, &index[n].linkTable[j][i], sizeof(int));
index[n].linkTable[j][i].first = index[n].n;
index[n].linkTable[j][i].n++;
}
index[n].n++;
}
}
static int getWord (input, word, n)
NXStream * input;
char * word;
int n;
{
int i, bad;
i = bad = 0;
while ((word[i] = NXGetc(input)) != EOF)
{
if (word[i] == '\n')
{
if (!bad && (i == n))
{
word[i] = '\0';
return 1;
}
i = bad = 0;
}
else if (islower(word[i])) i++;
else bad = 1;
}
return 0;
}
/* 行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行行 */
/*
Here is code to get the application's directory. The code is taken from NeXTanswers appkit #642.
*/
static void getAppDirectory (char *appDirectory)
{
FILE *process;
char command[256];
char *suffix;
strcpy (appDirectory,NXArgv[0]);
if (appDirectory[0] == '/') { /* if absolute path */
if (suffix = rindex(appDirectory,'/'))
*suffix = '\0'; /* remove executable name */
} else {
sprintf(command,"which '%s'\n",NXArgv[0]);
process=popen(command,"r");
fscanf(process,"%s",appDirectory);
pclose(process);
if (suffix = rindex(appDirectory,'/'))
*suffix = '\0'; /* remove executable name */
chdir(appDirectory);
getwd(appDirectory);
}
}These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.