1 /*****************************************************************************/
2 /* */
3 /* (C) Copyright 1995-1996 Alberto Pasquale */
4 /* Portions (C) Copyright 1999 Per Lundberg */
5 /* */
6 /* A L L R I G H T S R E S E R V E D */
7 /* */
8 /*****************************************************************************/
9 /* */
10 /* This source code is NOT in the public domain and it CANNOT be used or */
11 /* distributed without written permission from the author. */
12 /* */
13 /*****************************************************************************/
14 /* */
15 /* How to contact the author: Alberto Pasquale of 2:332/504@fidonet */
16 /* Viale Verdi 106 */
17 /* 41100 Modena */
18 /* Italy */
19 /* */
20 /*****************************************************************************/
21
22
23 // fbd.cpp
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include "fbd.hpp"
29 #include "fb.hpp"
30 #include "anumlst.hpp"
31 #include "apgenlib.hpp"
32
33
34 typedef int (*QSF) (const void *, const void *);
35
36 char *strnupcpy (char *dest, const char *src, int n);
37 // strncpy (dest, src, n), dest converted to uppercase
38 // Implemented in FbLib.Cpp
39
40
41 #define BLKSIZE 1000
42 typedef FIDX *FIDXP;
43
44
45 struct _idxdata {
46 FIDX idx[BLKSIZE]; // array of index entries
47 _idxdata *next;
48 };
49
50
IdxSortCmp(FIDXP * i1,FIDXP * i2)51 static int IdxSortCmp (FIDXP *i1, FIDXP *i2)
52 {
53 int ret = strncmp ((char *)(*i1)->name, (char *)(*i2)->name, MAX_FN_LEN);
54 if (ret)
55 return ret;
56 return (*i1)->anum - (*i2)->anum;
57 }
58
59
IdxDupeCmp(FIDXP i1,FIDXP i2)60 static int IdxDupeCmp (FIDXP i1, FIDXP i2)
61 {
62 return strncmp ((char *)i1->name, (char *)i2->name, MAX_FN_LEN);
63 }
64
65
FBD(void)66 FBD::FBD (void)
67 {
68 ntot = ncur = 0;
69 idxcur = idxhead = NULL;
70 idxnext = &idxhead;
71 anumlist = new ANumLst;
72 oldidx = NULL;
73 oldtot = oldrem = 0;
74 }
75
76
~FBD(void)77 FBD::~FBD (void)
78 {
79 _idxdata *next;
80
81 if (oldidx)
82 delete[] oldidx;
83
84 delete anumlist;
85
86 idxcur = idxhead;
87 while (idxcur) {
88 next = idxcur->next;
89 delete idxcur;
90 idxcur = next;
91 }
92 }
93
94
AddArea(word areanum)95 void FBD::AddArea (word areanum)
96 {
97 anumlist->Add (areanum);
98 }
99
100
Store(const char * filename,word areanum,word datpos)101 void FBD::Store (const char *filename, word areanum, word datpos)
102 {
103 if (ncur % BLKSIZE == 0) {
104 idxcur = *idxnext = new _idxdata;
105 idxcur->next = NULL;
106 idxnext = &idxcur->next;
107 ncur = 0;
108 }
109 FIDX *fidx = &idxcur->idx[ncur++];
110 strnupcpy ((char *)fidx->name, filename, MAX_FN_LEN);
111 fidx->anum = areanum;
112 fidx->fpos = datpos;
113 ntot ++;
114 }
115
116
GetCurn(void)117 dword FBD::GetCurn (void)
118 {
119 return ntot;
120 }
121
122
GetOldIdx(const char * idxname)123 int FBD::GetOldIdx (const char *idxname)
124 {
125 FILE *fidx;
126
127 fidx = fopen (idxname, "rb");
128 if (!fidx)
129 return -1;
130 long idxlen = filelength (fileno (fidx));
131 oldtot = idxlen / sizeof (FIDX);
132 if (oldtot == 0) {
133 fclose (fidx);
134 return 0;
135 }
136 oldidx = new FIDX[oldtot];
137 if (fread (oldidx, sizeof (FIDX), oldtot, fidx) != oldtot) {
138 delete oldidx;
139 oldidx = NULL;
140 fclose (fidx);
141 return -1;
142 }
143 fclose (fidx);
144
145 // mark entries to be removed
146
147 word area = anumlist->Get (1);
148 while (area != USHRT_MAX) {
149 for (dword i = 0; i < oldtot; i++)
150 if (oldidx[i].anum == area) {
151 oldidx[i].anum = USHRT_MAX;
152 oldrem ++;
153 }
154 area = anumlist->Get ();
155 }
156
157 return 0;
158 }
159
160
Build(dword first,const char * idxname,const char * nodupeidxname,DupeF df)161 int FBD::Build (dword first, const char *idxname, const char *nodupeidxname,
162 DupeF df)
163 {
164 dword idxtot;
165
166 if (first != ULONG_MAX) // full build
167 idxtot = ntot - first;
168 else { // update
169 if (GetOldIdx (idxname))
170 return -1;
171 idxtot = ntot + oldtot - oldrem;
172 }
173
174 FILE *fidx;
175
176 if (idxtot == 0) {
177 fidx = fopen (idxname, "wb");
178 if (!fidx)
179 return -1;
180 if (fclose (fidx))
181 return -1;
182
183 if (nodupeidxname) { // no-dupe idx
184 fidx = fopen (nodupeidxname, "wb");
185 if (!fidx)
186 return -1;
187 if (fclose (fidx))
188 return -1;
189 }
190 return 0;
191 }
192
193 // idxtot > 0
194
195 FIDXP *fidxp = new FIDXP[idxtot];
196
197 dword i;
198 _idxdata *id = idxhead;
199
200 if (first != ULONG_MAX) { // full build of local or main index
201 dword nc = 0;
202 while (first - nc >= BLKSIZE) { // skip whole blocks
203 nc += BLKSIZE;
204 id = id->next;
205 }
206 ncur = first % BLKSIZE; // in the current block
207 i = 0;
208 } else { // update build of main index
209 dword oi;
210 for (i = oi = 0; i < oldtot - oldrem; i ++) { // load pointers to old idx
211 while (oldidx[oi].anum == USHRT_MAX) // skip marked entries
212 oi ++;
213 fidxp[i] = &oldidx[oi++];
214 }
215 ncur = 0;
216 }
217
218
219 for (; i < idxtot; i ++) { // load pointers to new entries
220 if (ncur == BLKSIZE) {
221 ncur = 0;
222 id = id->next;
223 }
224 fidxp[i] = &id->idx[ncur++];
225 }
226
227 qsort (fidxp, idxtot, sizeof (FIDXP), (QSF) IdxSortCmp);
228
229 fidx = fopen (idxname, "wb");
230 if (!fidx) {
231 delete[] fidxp;
232 return -1;
233 }
234 setvbuf (fidx, NULL, _IOFBF, 8192);
235
236 for (i = 0; i < idxtot; i ++) {
237 if (fwrite (fidxp[i], sizeof (FIDX), 1, fidx) != 1) {
238 delete[] fidxp;
239 fclose (fidx);
240 return -1;
241 }
242 }
243
244 if (fclose (fidx)) {
245 delete[] fidxp;
246 return -1;
247 }
248
249 if (nodupeidxname) { // build no-dupe idx
250 fidx = fopen (nodupeidxname, "wb");
251 if (!fidx) {
252 delete[] fidxp;
253 return -1;
254 }
255 setvbuf (fidx, NULL, _IOFBF, 8192);
256
257 FIDX *prev;
258
259 if (fwrite (prev = fidxp[0], sizeof (FIDX), 1, fidx) != 1) {
260 delete[] fidxp;
261 fclose (fidx);
262 return -1;
263 }
264
265 BOOL InDupes = FALSE;
266
267 for (i = 1; i < idxtot; i ++) {
268 if (IdxDupeCmp (prev, fidxp[i]) != 0) {
269 if (fwrite (prev = fidxp[i], sizeof (FIDX), 1, fidx) != 1) {
270 delete[] fidxp;
271 fclose (fidx);
272 return -1;
273 }
274 InDupes = FALSE;
275 } else { // dupe
276 if (!InDupes) {
277 if (df)
278 df (prev, TRUE);
279 InDupes = TRUE;
280 }
281 if (df)
282 df (fidxp[i], FALSE);
283 }
284 }
285
286 if (fclose (fidx)) {
287 delete[] fidxp;
288 return -1;
289 }
290 }
291
292 delete[] fidxp;
293 return 0;
294 }
295
296
297
298