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