middlemac 3.1.0 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/CHANGELOG.md +17 -1
- data/Rakefile +16 -5
- data/documentation_project/Contents/Resources/SharedGlobalAssets/_layouts/layout-apple-modern.haml +2 -2
- data/documentation_project/Gemfile +2 -2
- data/documentation_project/config.rb +6 -5
- data/ext/trie/darray.c +673 -0
- data/ext/trie/darray.h +233 -0
- data/ext/trie/extconf.rb +23 -0
- data/ext/trie/fileutils.c +151 -0
- data/ext/trie/fileutils.h +36 -0
- data/ext/trie/tail.c +340 -0
- data/ext/trie/tail.h +207 -0
- data/ext/trie/trie-private.c +299 -0
- data/ext/trie/trie-private.h +31 -0
- data/ext/trie/trie.c +628 -0
- data/ext/trie/trie.h +40 -0
- data/ext/trie/triedefs.h +73 -0
- data/ext/trie/typedefs.h +117 -0
- data/features/helpers_features.feature +8 -9
- data/features/main_features.feature +3 -3
- data/fixtures/middlemac_app/Gemfile +2 -2
- data/fixtures/middlemac_app/config.rb +7 -9
- data/lib/middlemac.rb +1 -1
- data/lib/middlemac/extension.rb +5 -1
- data/lib/middlemac/{trie.rb → trie-extension.rb} +0 -0
- data/lib/middlemac/version.rb +1 -1
- data/middlemac.gemspec +20 -2
- metadata +51 -34
data/ext/trie/darray.h
ADDED
@@ -0,0 +1,233 @@
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
|
+
/*
|
3
|
+
* darray.h - Double-array trie structure
|
4
|
+
* Created: 2006-08-11
|
5
|
+
* Author: Theppitak Karoonboonyanan <thep@linux.thai.net>
|
6
|
+
*/
|
7
|
+
|
8
|
+
#ifndef __DARRAY_H
|
9
|
+
#define __DARRAY_H
|
10
|
+
|
11
|
+
#include "triedefs.h"
|
12
|
+
|
13
|
+
/**
|
14
|
+
* @file darray.h
|
15
|
+
* @brief Double-array trie structure
|
16
|
+
*/
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @brief Double-array structure type
|
20
|
+
*/
|
21
|
+
typedef struct _DArray DArray;
|
22
|
+
|
23
|
+
/**
|
24
|
+
* @brief Double-array entry enumeration function
|
25
|
+
*
|
26
|
+
* @param key : the key of the entry, up to @a sep_node
|
27
|
+
* @param sep_node : the separate node of the entry
|
28
|
+
* @param user_data : user-supplied data
|
29
|
+
*
|
30
|
+
* @return TRUE to continue enumeration, FALSE to stop
|
31
|
+
*/
|
32
|
+
typedef Bool (*DAEnumFunc) (const TrieChar *key,
|
33
|
+
TrieIndex sep_node,
|
34
|
+
void *user_data);
|
35
|
+
|
36
|
+
|
37
|
+
/**
|
38
|
+
* @brief Create a new double-array object
|
39
|
+
*
|
40
|
+
* Create a new empty doubla-array object.
|
41
|
+
*/
|
42
|
+
DArray * da_new ();
|
43
|
+
|
44
|
+
/**
|
45
|
+
* @brief Read double-array data from file
|
46
|
+
*
|
47
|
+
* @param file : the file to read
|
48
|
+
*
|
49
|
+
* @return a pointer to the openned double-array, NULL on failure
|
50
|
+
*
|
51
|
+
* Read double-array data from the opened file, starting from the current
|
52
|
+
* file pointer until the end of double array data block. On return, the
|
53
|
+
* file pointer is left at the position after the read block.
|
54
|
+
*/
|
55
|
+
DArray * da_read (FILE *file);
|
56
|
+
|
57
|
+
/**
|
58
|
+
* @brief Free double-array data
|
59
|
+
*
|
60
|
+
* @param d : the double-array data
|
61
|
+
*
|
62
|
+
* Free the given double-array data.
|
63
|
+
*/
|
64
|
+
void da_free (DArray *d);
|
65
|
+
|
66
|
+
/**
|
67
|
+
* @brief Write double-array data
|
68
|
+
*
|
69
|
+
* @param d : the double-array data
|
70
|
+
* @param file : the file to write to
|
71
|
+
*
|
72
|
+
* @return 0 on success, non-zero on failure
|
73
|
+
*
|
74
|
+
* Write double-array data to the given @a file, starting from the current
|
75
|
+
* file pointer. On return, the file pointer is left after the double-array
|
76
|
+
* data block.
|
77
|
+
*/
|
78
|
+
int da_write (const DArray *d, FILE *file);
|
79
|
+
|
80
|
+
|
81
|
+
/**
|
82
|
+
* @brief Get root state
|
83
|
+
*
|
84
|
+
* @param d : the double-array data
|
85
|
+
*
|
86
|
+
* @return root state of the @a index set, or TRIE_INDEX_ERROR on failure
|
87
|
+
*
|
88
|
+
* Get root state for stepwise walking.
|
89
|
+
*/
|
90
|
+
TrieIndex da_get_root (const DArray *d);
|
91
|
+
|
92
|
+
|
93
|
+
/**
|
94
|
+
* @brief Get BASE cell
|
95
|
+
*
|
96
|
+
* @param d : the double-array data
|
97
|
+
* @param s : the double-array state to get data
|
98
|
+
*
|
99
|
+
* @return the BASE cell value for the given state
|
100
|
+
*
|
101
|
+
* Get BASE cell value for the given state.
|
102
|
+
*/
|
103
|
+
TrieIndex da_get_base (const DArray *d, TrieIndex s);
|
104
|
+
|
105
|
+
/**
|
106
|
+
* @brief Get CHECK cell
|
107
|
+
*
|
108
|
+
* @param d : the double-array data
|
109
|
+
* @param s : the double-array state to get data
|
110
|
+
*
|
111
|
+
* @return the CHECK cell value for the given state
|
112
|
+
*
|
113
|
+
* Get CHECK cell value for the given state.
|
114
|
+
*/
|
115
|
+
TrieIndex da_get_check (const DArray *d, TrieIndex s);
|
116
|
+
|
117
|
+
|
118
|
+
/**
|
119
|
+
* @brief Set BASE cell
|
120
|
+
*
|
121
|
+
* @param d : the double-array data
|
122
|
+
* @param s : the double-array state to get data
|
123
|
+
* @param val : the value to set
|
124
|
+
*
|
125
|
+
* Set BASE cell for the given state to the given value.
|
126
|
+
*/
|
127
|
+
void da_set_base (DArray *d, TrieIndex s, TrieIndex val);
|
128
|
+
|
129
|
+
/**
|
130
|
+
* @brief Set CHECK cell
|
131
|
+
*
|
132
|
+
* @param d : the double-array data
|
133
|
+
* @param s : the double-array state to get data
|
134
|
+
* @param val : the value to set
|
135
|
+
*
|
136
|
+
* Set CHECK cell for the given state to the given value.
|
137
|
+
*/
|
138
|
+
void da_set_check (DArray *d, TrieIndex s, TrieIndex val);
|
139
|
+
|
140
|
+
/**
|
141
|
+
* @brief Walk in double-array structure
|
142
|
+
*
|
143
|
+
* @param d : the double-array structure
|
144
|
+
* @param s : current state
|
145
|
+
* @param c : the input character
|
146
|
+
*
|
147
|
+
* @return boolean indicating success
|
148
|
+
*
|
149
|
+
* Walk the double-array trie from state @a *s, using input character @a c.
|
150
|
+
* If there exists an edge from @a *s with arc labeled @a c, this function
|
151
|
+
* returns TRUE and @a *s is updated to the new state. Otherwise, it returns
|
152
|
+
* FALSE and @a *s is left unchanged.
|
153
|
+
*/
|
154
|
+
Bool da_walk (const DArray *d, TrieIndex *s, TrieChar c);
|
155
|
+
|
156
|
+
/**
|
157
|
+
* @brief Test walkability in double-array structure
|
158
|
+
*
|
159
|
+
* @param d : the double-array structure
|
160
|
+
* @param s : current state
|
161
|
+
* @param c : the input character
|
162
|
+
*
|
163
|
+
* @return boolean indicating walkability
|
164
|
+
*
|
165
|
+
* Test if there is a transition from state @a s with input character @a c.
|
166
|
+
*/
|
167
|
+
/*
|
168
|
+
Bool da_is_walkable (DArray *d, TrieIndex s, TrieChar c);
|
169
|
+
*/
|
170
|
+
#define da_is_walkable(d,s,c) \
|
171
|
+
(da_get_check ((d), da_get_base ((d), (s)) + (c)) == (s))
|
172
|
+
|
173
|
+
/**
|
174
|
+
* @brief Insert a branch from trie node
|
175
|
+
*
|
176
|
+
* @param d : the double-array structure
|
177
|
+
* @param s : the state to add branch to
|
178
|
+
* @param c : the character for the branch label
|
179
|
+
*
|
180
|
+
* @return the index of the new node
|
181
|
+
*
|
182
|
+
* Insert a new arc labelled with character @a c from the trie node
|
183
|
+
* represented by index @a s in double-array structure @a d.
|
184
|
+
* Note that it assumes that no such arc exists before inserting.
|
185
|
+
*/
|
186
|
+
TrieIndex da_insert_branch (DArray *d, TrieIndex s, TrieChar c);
|
187
|
+
|
188
|
+
/**
|
189
|
+
* @brief Prune the single branch
|
190
|
+
*
|
191
|
+
* @param d : the double-array structure
|
192
|
+
* @param s : the dangling state to prune off
|
193
|
+
*
|
194
|
+
* Prune off a non-separate path up from the final state @a s.
|
195
|
+
* If @a s still has some children states, it does nothing. Otherwise,
|
196
|
+
* it deletes the node and all its parents which become non-separate.
|
197
|
+
*/
|
198
|
+
void da_prune (DArray *d, TrieIndex s);
|
199
|
+
|
200
|
+
/**
|
201
|
+
* @brief Prune the single branch up to given parent
|
202
|
+
*
|
203
|
+
* @param d : the double-array structure
|
204
|
+
* @param p : the parent up to which to be pruned
|
205
|
+
* @param s : the dangling state to prune off
|
206
|
+
*
|
207
|
+
* Prune off a non-separate path up from the final state @a s to the
|
208
|
+
* given parent @a p. The prunning stop when either the parent @a p
|
209
|
+
* is met, or a first non-separate node is found.
|
210
|
+
*/
|
211
|
+
void da_prune_upto (DArray *d, TrieIndex p, TrieIndex s);
|
212
|
+
|
213
|
+
/**
|
214
|
+
* @brief Enumerate entries stored in double-array structure
|
215
|
+
*
|
216
|
+
* @param d : the double-array structure
|
217
|
+
* @param enum_func : the callback function to be called on each separate node
|
218
|
+
* @param user_data : user-supplied data to send as an argument to @a enum_func
|
219
|
+
*
|
220
|
+
* @return boolean value indicating whether all the keys are visited
|
221
|
+
*
|
222
|
+
* Enumerate all keys stored in double-array structure. For each entry, the
|
223
|
+
* user-supplied @a enum_func callback function is called, with the entry key,
|
224
|
+
* the separate node, and user-supplied data. Returning FALSE from such
|
225
|
+
* callback will stop enumeration and return FALSE.
|
226
|
+
*/
|
227
|
+
Bool da_enumerate (const DArray *d, DAEnumFunc enum_func, void *user_data);
|
228
|
+
|
229
|
+
#endif /* __DARRAY_H */
|
230
|
+
|
231
|
+
/*
|
232
|
+
vi:ts=4:ai:expandtab
|
233
|
+
*/
|
data/ext/trie/extconf.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
##
|
4
|
+
## Avoid warnings, since newer versions of Xcode by default try to make more and more
|
5
|
+
## warnings.
|
6
|
+
##
|
7
|
+
append_cflags("-Wno-missing-noreturn")
|
8
|
+
append_cflags("-Wno-shorten-64-to-32")
|
9
|
+
append_cflags("-Wno-return-type")
|
10
|
+
append_cflags("-Wno-sign-compare")
|
11
|
+
append_cflags("-Wno-unused-function")
|
12
|
+
append_cflags("-Wno-incompatible-pointer-types")
|
13
|
+
puts "=-=-=-=-=-=-"
|
14
|
+
puts $CFLAGS
|
15
|
+
puts "=-=-=-=-=-=-"
|
16
|
+
|
17
|
+
|
18
|
+
##
|
19
|
+
## If we want it to be installed in lib/trie, then we have to create the makefile
|
20
|
+
## in this nested format, too, otherwise lib_dir works for rake compile, but not
|
21
|
+
## for rake install.
|
22
|
+
##
|
23
|
+
create_makefile 'trie/trie'
|
@@ -0,0 +1,151 @@
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
|
+
/*
|
3
|
+
* fileutils.h - File utility functions
|
4
|
+
* Created: 2006-08-15
|
5
|
+
* Author: Theppitak Karoonboonyanan <thep@linux.thai.net>
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include <string.h>
|
9
|
+
#include <stdlib.h>
|
10
|
+
|
11
|
+
#include "fileutils.h"
|
12
|
+
|
13
|
+
/*--------------------------------------*
|
14
|
+
* INTERNAL FUNCTIONS DECLARATIONS *
|
15
|
+
*--------------------------------------*/
|
16
|
+
|
17
|
+
static char * make_full_path (const char *dir,
|
18
|
+
const char *name,
|
19
|
+
const char *ext);
|
20
|
+
|
21
|
+
/* ==================== BEGIN IMPLEMENTATION PART ==================== */
|
22
|
+
|
23
|
+
/*--------------------------------*
|
24
|
+
* FUNCTIONS IMPLEMENTATIONS *
|
25
|
+
*--------------------------------*/
|
26
|
+
|
27
|
+
static char *
|
28
|
+
make_full_path (const char *dir, const char *name, const char *ext)
|
29
|
+
{
|
30
|
+
char *path;
|
31
|
+
|
32
|
+
path = (char *) malloc (strlen (dir) + strlen (name) + strlen (ext) + 2);
|
33
|
+
sprintf (path, "%s/%s%s", dir, name, ext);
|
34
|
+
|
35
|
+
return path;
|
36
|
+
}
|
37
|
+
|
38
|
+
FILE *
|
39
|
+
file_open (const char *dir, const char *name, const char *ext, TrieIOMode mode)
|
40
|
+
{
|
41
|
+
const char *std_mode;
|
42
|
+
char *full_path;
|
43
|
+
FILE *file;
|
44
|
+
|
45
|
+
if (mode & TRIE_IO_WRITE)
|
46
|
+
std_mode = "r+";
|
47
|
+
else
|
48
|
+
std_mode = "r";
|
49
|
+
|
50
|
+
full_path = make_full_path (dir, name, ext);
|
51
|
+
file = fopen (full_path, std_mode);
|
52
|
+
if (!file && mode & TRIE_IO_CREATE)
|
53
|
+
file = fopen (full_path, "w+");
|
54
|
+
free (full_path);
|
55
|
+
|
56
|
+
return file;
|
57
|
+
}
|
58
|
+
|
59
|
+
long
|
60
|
+
file_length (FILE *file)
|
61
|
+
{
|
62
|
+
long cur_pos;
|
63
|
+
long size;
|
64
|
+
|
65
|
+
cur_pos = ftell (file);
|
66
|
+
|
67
|
+
fseek (file, 0L, SEEK_END);
|
68
|
+
size = ftell (file);
|
69
|
+
|
70
|
+
fseek (file, cur_pos, SEEK_SET);
|
71
|
+
|
72
|
+
return size;
|
73
|
+
}
|
74
|
+
|
75
|
+
Bool
|
76
|
+
file_read_int32 (FILE *file, int32 *o_val)
|
77
|
+
{
|
78
|
+
unsigned char buff[4];
|
79
|
+
|
80
|
+
if (fread (buff, 4, 1, file) == 1) {
|
81
|
+
*o_val = (buff[0] << 24) | (buff[1] << 16) | (buff[2] << 8) | buff[3];
|
82
|
+
return TRUE;
|
83
|
+
}
|
84
|
+
|
85
|
+
return FALSE;
|
86
|
+
}
|
87
|
+
|
88
|
+
Bool
|
89
|
+
file_write_int32 (FILE *file, int32 val)
|
90
|
+
{
|
91
|
+
unsigned char buff[4];
|
92
|
+
|
93
|
+
buff[0] = (val >> 24) & 0xff;
|
94
|
+
buff[1] = (val >> 16) & 0xff;
|
95
|
+
buff[2] = (val >> 8) & 0xff;
|
96
|
+
buff[3] = val & 0xff;
|
97
|
+
|
98
|
+
return (fwrite (buff, 4, 1, file) == 1);
|
99
|
+
}
|
100
|
+
|
101
|
+
Bool
|
102
|
+
file_read_int16 (FILE *file, int16 *o_val)
|
103
|
+
{
|
104
|
+
unsigned char buff[2];
|
105
|
+
|
106
|
+
if (fread (buff, 2, 1, file) == 1) {
|
107
|
+
*o_val = (buff[0] << 8) | buff[1];
|
108
|
+
return TRUE;
|
109
|
+
}
|
110
|
+
|
111
|
+
return FALSE;
|
112
|
+
}
|
113
|
+
|
114
|
+
Bool
|
115
|
+
file_write_int16 (FILE *file, int16 val)
|
116
|
+
{
|
117
|
+
unsigned char buff[2];
|
118
|
+
|
119
|
+
buff[0] = val >> 8;
|
120
|
+
buff[1] = val & 0xff;
|
121
|
+
|
122
|
+
return (fwrite (buff, 2, 1, file) == 1);
|
123
|
+
}
|
124
|
+
|
125
|
+
Bool
|
126
|
+
file_read_int8 (FILE *file, int8 *o_val)
|
127
|
+
{
|
128
|
+
return (fread (o_val, sizeof (int8), 1, file) == 1);
|
129
|
+
}
|
130
|
+
|
131
|
+
Bool
|
132
|
+
file_write_int8 (FILE *file, int8 val)
|
133
|
+
{
|
134
|
+
return (fwrite (&val, sizeof (int8), 1, file) == 1);
|
135
|
+
}
|
136
|
+
|
137
|
+
Bool
|
138
|
+
file_read_chars (FILE *file, char *buff, int len)
|
139
|
+
{
|
140
|
+
return (fread (buff, sizeof (char), len, file) == len);
|
141
|
+
}
|
142
|
+
|
143
|
+
Bool
|
144
|
+
file_write_chars (FILE *file, const char *buff, int len)
|
145
|
+
{
|
146
|
+
return (fwrite (buff, sizeof (char), len, file) == len);
|
147
|
+
}
|
148
|
+
|
149
|
+
/*
|
150
|
+
vi:ts=4:ai:expandtab
|
151
|
+
*/
|
@@ -0,0 +1,36 @@
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
|
+
/*
|
3
|
+
* fileutils.h - File utility functions
|
4
|
+
* Created: 2006-08-14
|
5
|
+
* Author: Theppitak Karoonboonyanan <thep@linux.thai.net>
|
6
|
+
*/
|
7
|
+
|
8
|
+
#ifndef __FILEUTILS_H
|
9
|
+
#define __FILEUTILS_H
|
10
|
+
|
11
|
+
#include <stdio.h>
|
12
|
+
|
13
|
+
#include "triedefs.h"
|
14
|
+
|
15
|
+
FILE * file_open (const char *dir, const char *name, const char *ext,
|
16
|
+
TrieIOMode mode);
|
17
|
+
|
18
|
+
long file_length (FILE *file);
|
19
|
+
|
20
|
+
Bool file_read_int32 (FILE *file, int32 *o_val);
|
21
|
+
Bool file_write_int32 (FILE *file, int32 val);
|
22
|
+
|
23
|
+
Bool file_read_int16 (FILE *file, int16 *o_val);
|
24
|
+
Bool file_write_int16 (FILE *file, int16 val);
|
25
|
+
|
26
|
+
Bool file_read_int8 (FILE *file, int8 *o_val);
|
27
|
+
Bool file_write_int8 (FILE *file, int8 val);
|
28
|
+
|
29
|
+
Bool file_read_chars (FILE *file, char *buff, int len);
|
30
|
+
Bool file_write_chars (FILE *file, const char *buff, int len);
|
31
|
+
|
32
|
+
#endif /* __FILEUTILS_H */
|
33
|
+
|
34
|
+
/*
|
35
|
+
vi:ts=4:ai:expandtab
|
36
|
+
*/
|
data/ext/trie/tail.c
ADDED
@@ -0,0 +1,340 @@
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
2
|
+
/*
|
3
|
+
* tail.c - trie tail for keeping suffixes
|
4
|
+
* Created: 2006-08-15
|
5
|
+
* Author: Theppitak Karoonboonyanan <thep@linux.thai.net>
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include <string.h>
|
9
|
+
#include <stdlib.h>
|
10
|
+
#include <stdio.h>
|
11
|
+
|
12
|
+
#include "tail.h"
|
13
|
+
#include "fileutils.h"
|
14
|
+
|
15
|
+
/*----------------------------------*
|
16
|
+
* INTERNAL TYPES DECLARATIONS *
|
17
|
+
*----------------------------------*/
|
18
|
+
|
19
|
+
/*-----------------------------------*
|
20
|
+
* PRIVATE METHODS DECLARATIONS *
|
21
|
+
*-----------------------------------*/
|
22
|
+
|
23
|
+
static TrieIndex tail_alloc_block (Tail *t);
|
24
|
+
static void tail_free_block (Tail *t, TrieIndex block);
|
25
|
+
|
26
|
+
/* ==================== BEGIN IMPLEMENTATION PART ==================== */
|
27
|
+
|
28
|
+
/*------------------------------------*
|
29
|
+
* INTERNAL TYPES IMPLEMENTATIONS *
|
30
|
+
*------------------------------------*/
|
31
|
+
|
32
|
+
/*------------------------------*
|
33
|
+
* PRIVATE DATA DEFINITONS *
|
34
|
+
*------------------------------*/
|
35
|
+
|
36
|
+
typedef struct {
|
37
|
+
TrieIndex next_free;
|
38
|
+
TrieData data;
|
39
|
+
TrieChar *suffix;
|
40
|
+
} TailBlock;
|
41
|
+
|
42
|
+
struct _Tail {
|
43
|
+
TrieIndex num_tails;
|
44
|
+
TailBlock *tails;
|
45
|
+
TrieIndex first_free;
|
46
|
+
};
|
47
|
+
|
48
|
+
/*-----------------------------*
|
49
|
+
* METHODS IMPLEMENTAIONS *
|
50
|
+
*-----------------------------*/
|
51
|
+
|
52
|
+
#define TAIL_SIGNATURE 0xDFFCDFFC
|
53
|
+
#define TAIL_START_BLOCKNO 1
|
54
|
+
|
55
|
+
/* Tail Header:
|
56
|
+
* INT32: signature
|
57
|
+
* INT32: pointer to first free slot
|
58
|
+
* INT32: number of tail blocks
|
59
|
+
*
|
60
|
+
* Tail Blocks:
|
61
|
+
* INT32: pointer to next free block (-1 for allocated blocks)
|
62
|
+
* INT32: data for the key
|
63
|
+
* INT16: length
|
64
|
+
* BYTES[length]: suffix string (no terminating '\0')
|
65
|
+
*/
|
66
|
+
|
67
|
+
Tail *
|
68
|
+
tail_new ()
|
69
|
+
{
|
70
|
+
Tail *t;
|
71
|
+
|
72
|
+
t = (Tail *) malloc (sizeof (Tail));
|
73
|
+
if (!t)
|
74
|
+
return NULL;
|
75
|
+
|
76
|
+
t->first_free = 0;
|
77
|
+
t->num_tails = 0;
|
78
|
+
t->tails = NULL;
|
79
|
+
|
80
|
+
return t;
|
81
|
+
}
|
82
|
+
|
83
|
+
Tail *
|
84
|
+
tail_read (FILE *file)
|
85
|
+
{
|
86
|
+
long save_pos;
|
87
|
+
Tail *t;
|
88
|
+
TrieIndex i;
|
89
|
+
uint32 sig;
|
90
|
+
|
91
|
+
/* check signature */
|
92
|
+
save_pos = ftell (file);
|
93
|
+
if (!file_read_int32 (file, (int32 *) &sig) || TAIL_SIGNATURE != sig) {
|
94
|
+
fseek (file, save_pos, SEEK_SET);
|
95
|
+
return NULL;
|
96
|
+
}
|
97
|
+
|
98
|
+
t = (Tail *) malloc (sizeof (Tail));
|
99
|
+
if (!t)
|
100
|
+
return NULL;
|
101
|
+
|
102
|
+
file_read_int32 (file, &t->first_free);
|
103
|
+
file_read_int32 (file, &t->num_tails);
|
104
|
+
t->tails = (TailBlock *) malloc (t->num_tails * sizeof (TailBlock));
|
105
|
+
if (!t->tails)
|
106
|
+
goto exit_tail_created;
|
107
|
+
for (i = 0; i < t->num_tails; i++) {
|
108
|
+
int16 length;
|
109
|
+
|
110
|
+
file_read_int32 (file, &t->tails[i].next_free);
|
111
|
+
file_read_int32 (file, &t->tails[i].data);
|
112
|
+
|
113
|
+
file_read_int16 (file, &length);
|
114
|
+
t->tails[i].suffix = (TrieChar *) malloc (length + 1);
|
115
|
+
if (length > 0)
|
116
|
+
file_read_chars (file, (char *)t->tails[i].suffix, length);
|
117
|
+
t->tails[i].suffix[length] = '\0';
|
118
|
+
}
|
119
|
+
|
120
|
+
return t;
|
121
|
+
|
122
|
+
exit_tail_created:
|
123
|
+
free (t);
|
124
|
+
return NULL;
|
125
|
+
}
|
126
|
+
|
127
|
+
void
|
128
|
+
tail_free (Tail *t)
|
129
|
+
{
|
130
|
+
TrieIndex i;
|
131
|
+
|
132
|
+
if (t->tails) {
|
133
|
+
for (i = 0; i < t->num_tails; i++)
|
134
|
+
if (t->tails[i].suffix)
|
135
|
+
free (t->tails[i].suffix);
|
136
|
+
free (t->tails);
|
137
|
+
}
|
138
|
+
free (t);
|
139
|
+
}
|
140
|
+
|
141
|
+
int
|
142
|
+
tail_write (const Tail *t, FILE *file)
|
143
|
+
{
|
144
|
+
TrieIndex i;
|
145
|
+
|
146
|
+
if (!file_write_int32 (file, TAIL_SIGNATURE) ||
|
147
|
+
!file_write_int32 (file, t->first_free) ||
|
148
|
+
!file_write_int32 (file, t->num_tails))
|
149
|
+
{
|
150
|
+
return -1;
|
151
|
+
}
|
152
|
+
for (i = 0; i < t->num_tails; i++) {
|
153
|
+
int16 length;
|
154
|
+
|
155
|
+
if (!file_write_int32 (file, t->tails[i].next_free) ||
|
156
|
+
!file_write_int32 (file, t->tails[i].data))
|
157
|
+
{
|
158
|
+
return -1;
|
159
|
+
}
|
160
|
+
|
161
|
+
length = t->tails[i].suffix ? strlen ((const char *)t->tails[i].suffix)
|
162
|
+
: 0;
|
163
|
+
if (!file_write_int16 (file, length))
|
164
|
+
return -1;
|
165
|
+
if (length > 0 &&
|
166
|
+
!file_write_chars (file, (char *)t->tails[i].suffix, length))
|
167
|
+
{
|
168
|
+
return -1;
|
169
|
+
}
|
170
|
+
}
|
171
|
+
|
172
|
+
return 0;
|
173
|
+
}
|
174
|
+
|
175
|
+
|
176
|
+
const TrieChar *
|
177
|
+
tail_get_suffix (const Tail *t, TrieIndex index)
|
178
|
+
{
|
179
|
+
index -= TAIL_START_BLOCKNO;
|
180
|
+
return (index < t->num_tails) ? t->tails[index].suffix : NULL;
|
181
|
+
}
|
182
|
+
|
183
|
+
Bool
|
184
|
+
tail_set_suffix (Tail *t, TrieIndex index, const TrieChar *suffix)
|
185
|
+
{
|
186
|
+
index -= TAIL_START_BLOCKNO;
|
187
|
+
if (index < t->num_tails) {
|
188
|
+
/* suffix and t->tails[index].suffix may overlap;
|
189
|
+
* so, dup it before it's overwritten
|
190
|
+
*/
|
191
|
+
TrieChar *tmp = NULL;
|
192
|
+
if (suffix)
|
193
|
+
tmp = (TrieChar *) strdup ((const char *)suffix);
|
194
|
+
if (t->tails[index].suffix)
|
195
|
+
free (t->tails[index].suffix);
|
196
|
+
t->tails[index].suffix = tmp;
|
197
|
+
|
198
|
+
return TRUE;
|
199
|
+
}
|
200
|
+
return FALSE;
|
201
|
+
}
|
202
|
+
|
203
|
+
TrieIndex
|
204
|
+
tail_add_suffix (Tail *t, const TrieChar *suffix)
|
205
|
+
{
|
206
|
+
TrieIndex new_block;
|
207
|
+
|
208
|
+
new_block = tail_alloc_block (t);
|
209
|
+
tail_set_suffix (t, new_block, suffix);
|
210
|
+
|
211
|
+
return new_block;
|
212
|
+
}
|
213
|
+
|
214
|
+
static TrieIndex
|
215
|
+
tail_alloc_block (Tail *t)
|
216
|
+
{
|
217
|
+
TrieIndex block;
|
218
|
+
|
219
|
+
if (0 != t->first_free) {
|
220
|
+
block = t->first_free;
|
221
|
+
t->first_free = t->tails[block].next_free;
|
222
|
+
} else {
|
223
|
+
block = t->num_tails;
|
224
|
+
t->tails = (TailBlock *) realloc (t->tails,
|
225
|
+
++t->num_tails * sizeof (TailBlock));
|
226
|
+
}
|
227
|
+
t->tails[block].next_free = -1;
|
228
|
+
t->tails[block].data = TRIE_DATA_ERROR;
|
229
|
+
t->tails[block].suffix = NULL;
|
230
|
+
|
231
|
+
return block + TAIL_START_BLOCKNO;
|
232
|
+
}
|
233
|
+
|
234
|
+
static void
|
235
|
+
tail_free_block (Tail *t, TrieIndex block)
|
236
|
+
{
|
237
|
+
TrieIndex i, j;
|
238
|
+
|
239
|
+
block -= TAIL_START_BLOCKNO;
|
240
|
+
|
241
|
+
if (block >= t->num_tails)
|
242
|
+
return;
|
243
|
+
|
244
|
+
t->tails[block].data = TRIE_DATA_ERROR;
|
245
|
+
if (NULL != t->tails[block].suffix) {
|
246
|
+
free (t->tails[block].suffix);
|
247
|
+
t->tails[block].suffix = NULL;
|
248
|
+
}
|
249
|
+
|
250
|
+
/* find insertion point */
|
251
|
+
j = 0;
|
252
|
+
for (i = t->first_free; i != 0 && i < block; i = t->tails[i].next_free)
|
253
|
+
j = i;
|
254
|
+
|
255
|
+
/* insert free block between j and i */
|
256
|
+
t->tails[block].next_free = i;
|
257
|
+
if (0 != j)
|
258
|
+
t->tails[j].next_free = block;
|
259
|
+
else
|
260
|
+
t->first_free = block;
|
261
|
+
}
|
262
|
+
|
263
|
+
TrieData
|
264
|
+
tail_get_data (const Tail *t, TrieIndex index)
|
265
|
+
{
|
266
|
+
index -= TAIL_START_BLOCKNO;
|
267
|
+
return (index < t->num_tails) ? t->tails[index].data : TRIE_DATA_ERROR;
|
268
|
+
}
|
269
|
+
|
270
|
+
Bool
|
271
|
+
tail_set_data (Tail *t, TrieIndex index, TrieData data)
|
272
|
+
{
|
273
|
+
index -= TAIL_START_BLOCKNO;
|
274
|
+
if (index < t->num_tails) {
|
275
|
+
t->tails[index].data = data;
|
276
|
+
return TRUE;
|
277
|
+
}
|
278
|
+
return FALSE;
|
279
|
+
}
|
280
|
+
|
281
|
+
void
|
282
|
+
tail_delete (Tail *t, TrieIndex index)
|
283
|
+
{
|
284
|
+
tail_free_block (t, index);
|
285
|
+
}
|
286
|
+
|
287
|
+
int
|
288
|
+
tail_walk_str (const Tail *t,
|
289
|
+
TrieIndex s,
|
290
|
+
short *suffix_idx,
|
291
|
+
const TrieChar *str,
|
292
|
+
int len)
|
293
|
+
{
|
294
|
+
const TrieChar *suffix;
|
295
|
+
int i;
|
296
|
+
short j;
|
297
|
+
|
298
|
+
suffix = tail_get_suffix (t, s);
|
299
|
+
if (!suffix)
|
300
|
+
return FALSE;
|
301
|
+
|
302
|
+
i = 0; j = *suffix_idx;
|
303
|
+
while (i < len) {
|
304
|
+
if (str[i] != suffix[j])
|
305
|
+
break;
|
306
|
+
++i;
|
307
|
+
/* stop and stay at null-terminator */
|
308
|
+
if (0 == suffix[j])
|
309
|
+
break;
|
310
|
+
++j;
|
311
|
+
}
|
312
|
+
*suffix_idx = j;
|
313
|
+
return i;
|
314
|
+
}
|
315
|
+
|
316
|
+
Bool
|
317
|
+
tail_walk_char (const Tail *t,
|
318
|
+
TrieIndex s,
|
319
|
+
short *suffix_idx,
|
320
|
+
TrieChar c)
|
321
|
+
{
|
322
|
+
const TrieChar *suffix;
|
323
|
+
TrieChar suffix_char;
|
324
|
+
|
325
|
+
suffix = tail_get_suffix (t, s);
|
326
|
+
if (!suffix)
|
327
|
+
return FALSE;
|
328
|
+
|
329
|
+
suffix_char = suffix[*suffix_idx];
|
330
|
+
if (suffix_char == c) {
|
331
|
+
if (0 != suffix_char)
|
332
|
+
++*suffix_idx;
|
333
|
+
return TRUE;
|
334
|
+
}
|
335
|
+
return FALSE;
|
336
|
+
}
|
337
|
+
|
338
|
+
/*
|
339
|
+
vi:ts=4:ai:expandtab
|
340
|
+
*/
|