~ubuntu-branches/ubuntu/edgy/ncbi-tools6/edgy

« back to all changes in this revision

Viewing changes to cdromlib/cdnewlib.c

  • Committer: Bazaar Package Importer
  • Author(s): Aaron M. Ucko
  • Date: 2002-04-04 22:13:09 UTC
  • Revision ID: james.westby@ubuntu.com-20020404221309-vfze028rfnlrldct
Tags: upstream-6.1.20011220a
ImportĀ upstreamĀ versionĀ 6.1.20011220a

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* cdnewlib.c
 
2
 * ===========================================================================
 
3
 *
 
4
 *                            PUBLIC DOMAIN NOTICE                          
 
5
 *               National Center for Biotechnology Information
 
6
 *                                                                          
 
7
 *  This software/database is a "United States Government Work" under the   
 
8
 *  terms of the United States Copyright Act.  It was written as part of    
 
9
 *  the author's official duties as a United States Government employee and 
 
10
 *  thus cannot be copyrighted.  This software/database is freely available 
 
11
 *  to the public for use. The National Library of Medicine and the U.S.    
 
12
 *  Government have not placed any restriction on its use or reproduction.  
 
13
 *                                                                          
 
14
 *  Although all reasonable efforts have been taken to ensure the accuracy  
 
15
 *  and reliability of the software and data, the NLM and the U.S.          
 
16
 *  Government do not and cannot warrant the performance or results that    
 
17
 *  may be obtained by using this software or data. The NLM and the U.S.    
 
18
 *  Government disclaim all warranties, express or implied, including       
 
19
 *  warranties of performance, merchantability or fitness for any particular
 
20
 *  purpose.                                                                
 
21
 *                                                                          
 
22
 *  Please cite the author in any work or product based on this material.   
 
23
 *
 
24
 * ===========================================================================
 
25
 *
 
26
 * RCS $Id: cdnewlib.c,v 6.2 1999/03/12 18:44:57 kans Exp $
 
27
 *
 
28
 * Author:  Gregory Schuler
 
29
 *
 
30
 * Version Creation Date: 08-22-94
 
31
 *
 
32
 * File Description:  Entrez low-level interface to CD-ROMs
 
33
 *
 
34
 * Modifications:  
 
35
 * --------------------------------------------------------------------------
 
36
 * Rev   Date      Name      Description of modification
 
37
 * ----  --------  --------  ------------------------------------------------
 
38
 * 1.1   08-22-94  Schuler   Initial revision
 
39
 * 1.2   08-22-94  Schuler   Rearranged the #include directives
 
40
 * 1.3   08-25-94  Schuler   cd3_CdGetDocSum: fix for new *.sum format.
 
41
 * 1.3   08-25-94  Schuler   Added error codes to ErrPostEx in many places.
 
42
 * 1.4   08-25-94  Kans      Some typecasts to make compilers happy
 
43
 * 1.5   08-26-94  Schuler   Some typecasts to make compilers happy
 
44
 * 1.6   08-28-94  Ostell    Convert double-slash comment to slash-star
 
45
 * 1.7   08-31-94  Schuler   Fixed bug in CdTrmLookup
 
46
 * 1.8   08-31-94  Schuler   Added magic number/version number checking
 
47
 * 1.9   09-01-94  Schuler   Use defines for directory names throughout
 
48
 * 1.10  09-01-94  Kans      Fixed bug in CdEntrez_FileOpen
 
49
 * 1.11  09-02-94  Schuler   Fixed bug in TrmIndex_Destruct
 
50
 * 1.12  09-02-94  Schuler   Implemented the CdMap_Destruct function 
 
51
 * 1.13  09-05-94  Schuler   Implemented the ReadCdLayout function; Fixed bug
 
52
 *                           in CdEnumFiles; Fixed bug in CdEntrez_FileOpen
 
53
 * 1.14  09-05-94  Schuler   Fixed bug in CdTrmLookup
 
54
 * 1.15  09-05-94  Schuler   Fixed bug in CdTrmLookup (tricky!)
 
55
 * 1.16  09-06-94  Schuler   Added some more VERBOSEs and ASSERTs
 
56
 * 1.17  09-09-94  Schuler   Fixed bug in CD swapping logic
 
57
 * 1.18  09-21-94  Schuler   Fixed bug in CdFini (NULL out _huff_tab)
 
58
 * 1.19  09-22-94  Schuler   Another fix to swapping logic...
 
59
 * 1.20  10-04-94  Schuler   Fixed invalid redeclaration of SwapInt4
 
60
 * 1.21 10-08-94  ?         ?
 
61
 * 1.22  10-08-94  Kans      Eliminate prompt to insert CD when already there
 
62
 * 1.23  10-10-94  Schuler   Fixed bug in CdEnumFiles (wanted Entrez3 always)
 
63
 * 1.24  10-24-94  Schuler   Fixed CdDevice_FileOpen for to respect the
 
64
 *                           upper_case and semicolon_one flags.
 
65
 * 1.25  10-25-94  Schuler   Change to CdVolume_Mount to re-init settings
 
66
 *                           of upper_case and semicolon_one
 
67
 * 1.26  10-26-94  Schuler   Changed "long" to "Int4" in a couple places
 
68
 * 1.27  11-17-94  Schuler   Fixed bug in ReadCdLayout 
 
69
 * 1.28  11-17-94  Schuler   Fixed bug in FindFloatingEntrezVolumes
 
70
 * 1.29  11-17-94  Schuler   Scan for already-mounted Entrez CDs on
 
71
 *                           Mac desktop at startup
 
72
 * 1.30  11-17-94  Schuler   Fixed CdTestPath to properly handle cases where
 
73
 *                           CD-ROM files are upper case and case matters
 
74
 * 1.31  11-18-94  Schuler   Added verbose trace message logging
 
75
 * 1.32  11-19-94  Schuler   Plugged some memory leaks
 
76
 * 1.33  11-21-94  Schuler   Fixed FileReadSwap4 to support 8-byte longs
 
77
 * 1.34  11-22-94  Schuler   Changed arg in cd3_CdLinkUidGet fom long to DocUid
 
78
 * 1.35  11-22-94  Schuler   Fixed invalid redeclaration of SwapInt4
 
79
 * 1.36  11-22-94  Schuler   Changed "long" to "DocUid" in CdLinkUidGet
 
80
 * 1.37  11-25-94  Schuler   Fixed bug in UidIndex_ReadPage (re: 8-byte longs)
 
81
 * 1.38  11-30-94  Schuler   Populate new cd_count field EntrezInfo
 
82
 * 1.39  01-04-95  Kans      ?
 
83
 * 1.40  01-20-95  Schuler   Added the CdMountEntrezVolume() and 
 
84
 *                           CdUnmountEntrezVolume() functions.
 
85
 * 1.41  02-27-95  Schuler   CdVolume_Mount() calls CdDevice_Init() if needed
 
86
 * 1.42  02-28-95  Schuler   Added more verbose log messages
 
87
 * 1.43  02-28-95  Schuler   Plugged some memory leaks
 
88
 * 1.44  03-02-95  Schuler   Changed fopen/fclose to FileOpen/FileClose
 
89
 *
 
90
 * 05-19-95 Schuler     Added rcs Log directive for automatic insertion of
 
91
 *                      modification comments.
 
92
 *
 
93
 * Revision $Log: cdnewlib.c,v $
 
94
 * Revision Revision 6.2  1999/03/12 18:44:57  kans
 
95
 * Revision fixed ErrPostEx problem
 
96
 * Revision
 
97
 * Revision Revision 6.1  1998/08/24 18:42:16  kans
 
98
 * Revision fixed -v -fd warnings
 
99
 * Revision
 
100
 * Revision Revision 6.0  1997/08/25 18:13:01  madden
 
101
 * Revision Revision changed to 6.0
 
102
 * Revision
 
103
 * Revision Revision 5.3  1997/06/26 21:55:38  vakatov
 
104
 * Revision [PC] DLL'd "ncbicdr.lib", "ncbiacc.lib", "ncbinacc.lib" and "ncbicacc.lib"
 
105
 * Revision
 
106
 * Revision Revision 5.2  1997/02/14 22:34:49  epstein
 
107
 * Revision allocated more memory for detailed info
 
108
 * Revision
 
109
 * Revision 5.1  1996/11/19  21:46:45  shavirin
 
110
 * CdInit() CdFini() messages made optional (printed in
 
111
 * verbose mode)
 
112
 *
 
113
 * Revision 5.0  1996/05/28  13:55:34  ostell
 
114
 * Set to revision 5.0
 
115
 *
 
116
 * Revision 4.2  1996/04/02  19:02:49  epstein
 
117
 * change CDVOL_MAX and its use
 
118
 *
 
119
 * Revision 4.1  1996/03/26  16:29:11  epstein
 
120
 * migrate byte-swapping functions to ncbimisc.[ch]
 
121
 *
 
122
 * Revision 4.0  1995/07/26  13:50:32  ostell
 
123
 * force revision to 4.0
 
124
 *
 
125
 * Revision 1.48  1995/06/05  21:32:56  kans
 
126
 * CdEnumFiles now uses safe fgets version (UnixFileGets)
 
127
 *
 
128
 * Revision 1.47  1995/05/18  17:27:46  kans
 
129
 * changed qsort to HeapSort to avoid corruption/hang on one platform
 
130
 *
 
131
 * Revision 1.46  1995/05/16  14:36:20  schuler
 
132
 * Automatic comment insertion enabled
 
133
 *
 
134
 *
 
135
 * ==========================================================================
 
136
 */
 
137
 
 
138
#define REVISION_STR "$Revision: 6.2 $"
 
139
 
 
140
 
 
141
 
 
142
/*
 
143
CONFIGURATION NOTES
 
144
 
 
145
[CdEntrez]
 
146
        
 
147
DeviceCount = (number)
 
148
                This should be equal to the number of Entrez CD-ROM images
 
149
                that may be simultaneosuly on-line, either as mounted CD-ROMs
 
150
                or as hard disk images.  For example, suppose that you have a
 
151
                single CD-ROM drive on which you keep one of the Entrez CD-ROMs
 
152
                mounted plus a huge hard disk onto which you have copied the 
 
153
                contents of the remaining two CD-ROMs.  In this case, the 
 
154
                DeviceCount setting should be 3.
 
155
                
 
156
IdxCacheSize = (kbytes)
 
157
TrmCacheSize = (kbytes)
 
158
                Maximum amount of memory to use for caching index & term files
 
159
                
 
160
LogVerbose = { Yes / No }
 
161
            Causes verbose logging of status information for use in debugging
 
162
            (default is No).  Note that error logging must be enabled by the
 
163
            application for anything to get logged.
 
164
            
 
165
 
 
166
[CdEntrez.device.#]            (one section for each device, # = 1,2,3..)
 
167
        
 
168
Type = { CD / HARDDISK / NET }
 
169
                Type of device: CD-ROM drive, local hard drive, or network drive.
 
170
                
 
171
Formal_Name = (some string)
 
172
                        This setting is optional, but provides a name for the device (e.g.
 
173
                        "Second CD-ROM drive") that can be used in user messages.
 
174
 
 
175
Root = (full path)
 
176
                Full path corresponding to the root of the CD-ROM (excluding
 
177
                the volume name when used with Insert_Volname=Yes; see below).
 
178
                On the Macintosh, this should be omitted or left empty for
 
179
                EJECTABLE devices with Insert_Volname=Yes.
 
180
                
 
181
Insert_Volname = { Yes / No }
 
182
                If Yes, the name of the volume will be inserted after the
 
183
                string specified in the Root setting and before the names of
 
184
                subdirectories on the CD.  This would be used for EJECTABLE
 
185
                devices on Macintosh and Solaris systems (on the Mac, the
 
186
                Root setting should be emtpy in this case as the path starts
 
187
                with the volume name).
 
188
                
 
189
Ejectable = { Yes / No }
 
190
                Set to yes if the device should be considered ejectable.
 
191
                
 
192
Bind = { Entrez1 / Entrez2 / Entrez 3 }
 
193
                Use this setting to bind an Entrez CD-ROM to a device.  The
 
194
                setting should be the volume name of the CD: "Entrez1", "Entrez2",
 
195
                etc. (not sensitive to case).  Bound volumes are never ejected,
 
196
                even if Ejectable=Yes. 
 
197
 
 
198
Device_Name =
 
199
Raw_Device_Name =
 
200
Mount_Point
 
201
Mount_Cmd =
 
202
            These are some parameters to be passed to the MountCd and
 
203
            EjectCd functions.  They may be required on certain UNIX
 
204
            and VMS systems.
 
205
            
 
206
*/
 
207
 
 
208
#include <cdromlib.h>
 
209
 
 
210
#ifdef _NEW_CdEntrez_
 
211
 
 
212
 
 
213
static char _this_module[] = "CdEntrez";
 
214
#undef  THIS_MODULE
 
215
#define THIS_MODULE _this_module
 
216
static char _this_file[] = __FILE__;
 
217
#undef  THIS_FILE
 
218
#define THIS_FILE _this_file
 
219
 
 
220
#undef VERBOSE
 
221
#define VERBOSE   if(_verbose_trace) Nlm_ErrLogPrintf
 
222
 
 
223
#define CDVOL_MAX  8
 
224
#define TYPE_MAX   DocType_MAX
 
225
#define DIV_MAX    64
 
226
#define FLD_MAX    32
 
227
 
 
228
#define TYPE_TAG_LEN  2
 
229
#define DIV_TAG_LEN   3
 
230
#define FLD_TAG_LEN   4
 
231
 
 
232
#define DEFAULT_IdxCacheSize  16
 
233
#define DEFAULT_SumCacheSize  16
 
234
#define DEFAULT_TrmCacheSize   8
 
235
 
 
236
 
 
237
#define VOLNUM_IS_VALID(x) ((x)<=_volume_ct && (x)>0)
 
238
#define TYPE_IS_VALID(x)   ((x)<_type_ct && (x)>=0)
 
239
#define FIELD_IS_VALID(x)  ((x)<_fld_ct && (x)>=0)
 
240
 
 
241
#define TYPTAG(x)  _cdinfo->type_info[x].tag
 
242
#define FLDTAG(x)  _cdinfo->field_info[x].tag
 
243
#define DIVTAG(x)  _cdinfo->div_info[x].tag
 
244
 
 
245
#define HCA 1
 
246
#define SUM 2
 
247
#define LNK 3
 
248
#define OFS 4
 
249
#define OIX 5
 
250
#define TRM 6
 
251
#define TIX 7
 
252
#define PST 8
 
253
#define INF 9
 
254
 
 
255
#define MAGIC_hca 0x11BD
 
256
#define MAGIC_sum 0x0025
 
257
#define MAGIC_lnk 0x0A02
 
258
#define MAGIC_ofs 0x0A03
 
259
#define MAGIC_oix 0x0A04
 
260
#define MAGIC_trm 0x0A05
 
261
#define MAGIC_tix 0x0A06
 
262
#define MAGIC_pst 0x0A07
 
263
#define MAGIC_inf 0x0A0A
 
264
 
 
265
#define FORMAT_hca 2
 
266
#define FORMAT_sum 2
 
267
#define FORMAT_ofs 2
 
268
#define FORMAT_oix 2
 
269
#define FORMAT_trm 2
 
270
#define FORMAT_tix 2
 
271
#define FORMAT_pst 2
 
272
#define FORMAT_lnk 2
 
273
#define FORMAT_inf 1
 
274
 
 
275
/* ========== CdDevice class ========== */
 
276
struct CdVolume;
 
277
 
 
278
typedef struct CdDevice 
 
279
{
 
280
        CdDevInfo inf;               /* device characteristics  */
 
281
        int   bound_cd;              /* Entrez volume number bound to this device, if any */
 
282
        int   hint;                  /* used during initialization for transient bind */
 
283
        struct CdVolume *volume;     /* Entrez volume currently mounted on this device */
 
284
        unsigned is_cdrom      :1;   /* TRUE if device is a CD-ROM reader */
 
285
        unsigned is_ejectable  :1;   /* TRUE if device should be considered ejectable */
 
286
        unsigned ins_volname   :1;   /* TRUE if the volume name gets inserted into path */
 
287
        unsigned semicolon_one :1;   /* TRUE if the version number ";1" should be appended */
 
288
        unsigned upper_case    :1;   /* TRUE if the file name should be upper case */
 
289
        unsigned is_inited     :1;   /* TRUE if semicolon_one and upper_case are known */
 
290
        time_t timestamp;            /* time this device was last used           */
 
291
}
 
292
CdDevice;
 
293
 
 
294
#define CdDevice_New(a)  CdDevice_Construct(MemNew(sizeof(CdDevice)),a) 
 
295
#define CdDevice_Free(a) MemFree((void*)CdDevice_Destruct(a))
 
296
static CdDevice* CdDevice_Construct (CdDevice *cddev, int num);
 
297
static CdDevice* CdDevice_Destruct (CdDevice *cddev);
 
298
static int   CdDevice_Init (CdDevice *cddev);
 
299
static int CdDevice_FileBuildPath (CdDevice *cddev, char *fpath, const char *fdir, const char *fname);
 
300
static FILE* CdDevice_FileOpen (CdDevice *cddev, const char *fdir, const char *fname, const char *fmode);
 
301
static void  CdDevice_Touch (CdDevice *cddev);
 
302
static CdDevice* GetLruDevice (void);
 
303
 
 
304
/* ==========  CdVolume class ========== */
 
305
 
 
306
typedef struct CdVolume
 
307
{
 
308
        char *volume_name;   /* "entrez1", "entrez2", or "entrez3"       */
 
309
        short volume_num;    /* 1, 2, or 3                               */
 
310
        CdDevice *device;    /* on which device is this volume mounted ? */
 
311
        time_t timestamp;    /* time this volume was last used           */
 
312
}
 
313
CdVolume;
 
314
 
 
315
#define CdVolume_New(a)  CdVolume_Construct(MemNew(sizeof(CdVolume)),a) 
 
316
#define CdVolume_Free(a) MemFree((void*)CdVolume_Destruct(a))
 
317
static CdVolume* CdVolume_Construct (CdVolume *cdvol, int number);
 
318
static CdVolume* CdVolume_Destruct (CdVolume *cdvol);
 
319
static CdDevice* CdVolume_Mount (CdVolume *cdvol, CdDevice *cddev, int verify);
 
320
static int  CdVolume_Unmount (CdVolume *cdvol);
 
321
static int  CdVolume_IsMounted (CdVolume *cdvol);
 
322
static int FindFloatingEntrezVolumes (int *outlist);
 
323
 
 
324
 
 
325
/* ==========  UidIndex class ========= */
 
326
 
 
327
typedef struct UidIndex 
 
328
{
 
329
        DocType  type;     /* Document type: TYP_ML, TYP_AA, etc */
 
330
        long  uid_ct;      /* Number of UIDs in index (can be > number of docs) */
 
331
        long  uid_min;     /* Smallest UID in index */
 
332
        long  uid_max;     /* Largest UID in index */
 
333
        int   pages;       /* number of index pages */
 
334
        long *index;       /* array of 1st UID on each page */
 
335
}
 
336
UidIndex;
 
337
 
 
338
typedef struct UidIndexRec
 
339
{
 
340
        long uid;          /* UID of document */
 
341
        int  divnum;       /* division number (lookup in EntrezInfo) */
 
342
        int  filnum;       /* hca file segment number (from 1) */
 
343
        long hca_offset;   /* offset into hca file for full ASN.1 record */
 
344
        long sum_offset;   /* offset into sum file for summary */
 
345
        long lnk_offset;   /* offset into lnk file for links */
 
346
}
 
347
UidIndexRec;
 
348
 
 
349
#define UidIndex_New(a,b) UidIndex_Construct(MemNew(sizeof(UidIndex)),a,b)      
 
350
#define UidIndex_Free(a)  MemFree((void*)UidIndex_Destruct(a))
 
351
static UidIndex* UidIndex_Construct (UidIndex *uidx, DocType type, EntrezTypeData *info);
 
352
static UidIndex* UidIndex_Destruct (UidIndex *uidx);
 
353
static int   UidIndex_ReadPageMap (UidIndex *uidx);
 
354
static long* UidIndex_ReadPage (UidIndex *uidx, int pagenum);
 
355
static int   UidIndex_Lookup (UidIndex *uidx, DocUid uid, UidIndexRec *rec);
 
356
 
 
357
 
 
358
/* ==========  TrmIndex class ========== */
 
359
 
 
360
typedef struct TrmIndex
 
361
{
 
362
        struct TrmIndex *next;   /* next element in linked list */
 
363
        char tag[6];        /* tag for field (e.g. "mesh") */
 
364
        unsigned type  :6;  /* ??? */
 
365
        unsigned fld   :6;  /* ??? */
 
366
        unsigned style :4;  /* ??? */
 
367
        long trm_ct;        /* term count */
 
368
        int  page_ct;       /* page count */
 
369
        int  page_size;     /* page size */
 
370
        char **index;       /* array of 1st term on each page */
 
371
}
 
372
TrmIndex;
 
373
 
 
374
#define TrmIndex_New(a,b,c,d) TrmIndex_Construct(MemNew(sizeof(TrmIndex)),a,b,c,d)      
 
375
#define TrmIndex_Free(a)  MemFree((void*)TrmIndex_Destruct(a))
 
376
static TrmIndex* TrmIndex_Construct (TrmIndex *tidx, int type, int fld, const char *tag, EntrezFieldData *info);
 
377
static TrmIndex* TrmIndex_Destruct (TrmIndex *tidx);
 
378
static int   TrmIndex_ReadPageMap (TrmIndex *tidx);
 
379
static Byte* TrmIndex_ReadPage (TrmIndex *tidx, int pagenum);
 
380
static int   TrmIndex_Lookup (TrmIndex *tidx, const char *stem);
 
381
static CdTerm* TrmIndex_GetCdTerm (TrmIndex *tidx, const char *term);
 
382
static int TrmIndex_ScanPages (TrmIndex *tidx, int start, int count, CdTermProc proc);
 
383
static FILE * TrmIndex_PostingsFileOpen (TrmIndex *tidx);
 
384
 
 
385
static CdTerm* getcdtrm (TrmIndex *tidx, int pagenum, Byte **pptr);
 
386
static int trmcmp (const char *term1, const char *term2);
 
387
static int trmncmp (const char *term1, const char *term2, int n);
 
388
 
 
389
 
 
390
/* ==========  CdMap class ========= */
 
391
 
 
392
typedef struct CdMap
 
393
{
 
394
        unsigned user_set :1;  /* any user-supplied path set ? */
 
395
        unsigned multicd  :1;  /* files exist on multiple CDs ? */
 
396
        unsigned lnklist  :1;  /* list is a linked list ? (array if false) */
 
397
        short array_size;      /* array size for list */
 
398
        short id_num;          /* id_number for divisions */
 
399
        short cd_num;          /* CD number */
 
400
        short *cd_list;        /* list of CD numbers, if multicd */
 
401
        char *user_path;       /* user-supplied path */
 
402
        struct CdMap *list;    /* linked list or array */
 
403
}
 
404
CdMap;
 
405
 
 
406
#define CdMap_New(a)   CdMap_Construct((CdMap*)MemNew(sizeof(CdMap)),a)
 
407
#define CdMap_Free(x)   MemFree((void*)CdMap_Destruct(x))
 
408
static CdMap* CdMap_Construct (CdMap *map, int list_size);
 
409
static CdMap* CdMap_Destruct (CdMap *map);
 
410
static void CdMap_ParseCdNums (CdMap *map, char *nums);
 
411
static void CdMap_FindPath (CdMap *map, const char *key);
 
412
static int CdMap_GetSpecs (CdMap *map, int *cdlist, char *fdir);
 
413
static CdMap* CdMap_GetChild (CdMap *map, int nkid);
 
414
 
 
415
 
 
416
static Boolean ReadCdLayout (FILE *fd);
 
417
 
 
418
 
 
419
/* ========== LSet  class ========== */
 
420
typedef struct DocLink
 
421
{
 
422
        DocUid uid;
 
423
        int wt;
 
424
}
 
425
DocLink;
 
426
 
 
427
typedef struct LSet 
 
428
{
 
429
        short sorc_type;
 
430
        short dest_type;
 
431
        int   link_max;
 
432
        int   count;
 
433
        int   slots;
 
434
        DocLink *link;
 
435
}
 
436
LSet;
 
437
 
 
438
#define LSet_New(a,b,c)  LSet_Construct(MemNew(sizeof(LSet)),a,b,c)     
 
439
#define LSet_Free(x)     MemFree((void*)LSet_Destruct(x))
 
440
static LSet* LSet_Construct (LSet *lset, short sorc_type, short dest_type, int link_max);
 
441
static LSet * LSet_Destruct (LSet *lset);
 
442
static int LSet_Read (LSet *lset, FILE *fd);
 
443
static LinkSet* LSet_Convert (LSet *lset);
 
444
 
 
445
 
 
446
/* ==========  HuffTable class ========== */
 
447
 
 
448
typedef struct HuffTable
 
449
{
 
450
        int count;
 
451
        short *left;
 
452
        short *right;
 
453
}
 
454
HuffTable;
 
455
 
 
456
#define HuffTable_New(a)   HuffTable_Construct(MemNew(sizeof(HuffTable)),a)
 
457
#define HuffTable_Free(a)  MemFree((void*)HuffTable_Destruct(a))
 
458
static HuffTable* HuffTable_Construct (HuffTable *huff, int slots);
 
459
static HuffTable* HuffTable_Destruct (HuffTable *huff);
 
460
static HuffTable* HuffTable_Read (FILE *fd);
 
461
 
 
462
 
 
463
/* ========== DecompInfo class ========== */
 
464
typedef struct DecompInfo
 
465
{
 
466
        AsnIo *aio;
 
467
        FILE *fd;
 
468
        HuffTable *huff;
 
469
        unsigned int byte;
 
470
        unsigned int mask;
 
471
}
 
472
DecompInfo;
 
473
 
 
474
#define DecompInfo_New(a) DecompInfo_Construct(MemNew(sizeof(DecompInfo)),a)
 
475
#define DecompInfo_Free(a)  MemFree((void*)DecompInfo_Destruct(a))
 
476
static DecompInfo* DecompInfo_Construct (DecompInfo *info, HuffTable *huff);
 
477
/*static DecompInfo* DecompInfo_Destruct (DecompInfo *info);*/
 
478
#define DecompInfo_Destruct(info)  (info)
 
479
static AsnIo* DecompInfo_Attach (DecompInfo *info, FILE *fd);
 
480
static FILE* DecompInfo_Detach (DecompInfo *info);
 
481
 
 
482
static Int2 LIBCALLBACK DecompReadProc (void *p, char *buff, Uint2 count);
 
483
 
 
484
/* ==========  Cache class ========== */
 
485
#define Cache_MAGIC_VALUE 223445L                 
 
486
 
 
487
typedef struct CachePage
 
488
{
 
489
        long id;
 
490
        int  lock;
 
491
        void *data;
 
492
}
 
493
CachePage;
 
494
 
 
495
typedef void (PASCAL *CacheDataFreeProc)(void *data);
 
496
static void PASCAL DefCacheDataFreeProc (void *data);
 
497
 
 
498
typedef struct Cache 
 
499
{
 
500
        long magic;
 
501
        CachePage *page;
 
502
        int  page_slots;
 
503
        int  page_count;
 
504
        long page_size;    /* optional */
 
505
        long hits;
 
506
        long misses;
 
507
        CacheDataFreeProc fproc;
 
508
}
 
509
Cache;
 
510
 
 
511
#define Cache_New(a,b) Cache_Construct(MemNew(sizeof(Cache)),a,b)       
 
512
#define Cache_Free(a)  MemFree((void*)Cache_Destruct(a))
 
513
static Cache* Cache_Construct (Cache *cache, int size, CacheDataFreeProc fproc);
 
514
static Cache* Cache_Destruct (Cache *cache);
 
515
static int   Cache_Insert (Cache *cache, long id, void *data);
 
516
static int   Cache_Delete (Cache *cache, long id);
 
517
static int   Cache_Touch (Cache *cache, long id);
 
518
static void* Cache_Lock (Cache *cache, long id);
 
519
static int   Cache_Unlock (Cache *cache, long id);
 
520
static void* Cache_Peek (Cache *cache, long id);
 
521
static void  Cache_Purge (Cache*);
 
522
static void  Cache_LogStats (Cache *cache, const char *name);
 
523
static char* Cache_ReportStats (Cache *cache, char *buffer);
 
524
static int   Cache_IsValid (Cache *cache);
 
525
 
 
526
 
 
527
/* ========== Misc. structs ========== */
 
528
 
 
529
struct CdFInfo
 
530
{
 
531
        char *ext;
 
532
        unsigned short magic;
 
533
        unsigned short format;
 
534
};
 
535
 
 
536
struct CdDirInfo
 
537
{
 
538
        char *key;
 
539
        char *dir;
 
540
        char *user_dir;
 
541
        FILE **fd;
 
542
};
 
543
 
 
544
typedef struct DivInfo
 
545
{
 
546
        char tag[1+DIV_TAG_LEN];
 
547
        short cd_num[TYPE_MAX];
 
548
}
 
549
DivInfo;
 
550
 
 
551
/* ========== Misc. functions ========== */
 
552
 
 
553
static FILE * CdEntrez_FileOpen (CdEntrezDir dirnum, int doctype, int divnum, int ftype, const char *fname, const char *fmode);
 
554
static void CdEntrez_FileClose (CdEntrezDir dirnum, int doctype, FILE *fd);
 
555
 
 
556
static int InvalidConfiguration (int code);
 
557
static int FileCorrupt (const char *fname);
 
558
static int FileOutOfDate (const char *fname);
 
559
static int FileNotRecognized (const char *fname);
 
560
static int CatastrophicFailure (int code);
 
561
 
 
562
static Boolean IsInitialized (void);
 
563
static Boolean ValidType (int type);
 
564
static Boolean ValidField (int field);
 
565
 
 
566
static char * _GetAppParamStr (const char *filebase, const char *section, 
 
567
                                const char *key, const char *dlft);
 
568
                                
 
569
#ifndef GetAppParamStr
 
570
#define GetAppParamStr _GetAppParamStr
 
571
#endif
 
572
 
 
573
static int LIBCALLBACK default_CdInsertProc (const char *volname, const CdDevInfo *dev);
 
574
static int LIBCALLBACK default_CdEjectProc (const char *volname, const CdDevInfo *dev);
 
575
 
 
576
 
 
577
/* ========== Static Variables ========== */
 
578
 
 
579
static CdDevHook _hookInsert = default_CdInsertProc;
 
580
static CdDevHook _hookEject = default_CdEjectProc;
 
581
 
 
582
static char * _empty_string = "";
 
583
 
 
584
static HuffTable * _huff_tab[TYPE_MAX];
 
585
 
 
586
static FILE* _fd_idx[TYPE_MAX];
 
587
static FILE* _fd_sum[TYPE_MAX];
 
588
static FILE* _fd_lnk[TYPE_MAX];
 
589
 
 
590
#define HCA 1
 
591
#define SUM 2
 
592
#define LNK 3
 
593
#define OFS 4
 
594
#define OIX 5
 
595
#define TRM 6
 
596
#define TIX 7
 
597
#define PST 8
 
598
#define INF 9
 
599
 
 
600
struct CdFInfo _finfo[] = {
 
601
        "", 0, 0,
 
602
        "hca", MAGIC_hca, FORMAT_hca,
 
603
        "sum", MAGIC_sum, FORMAT_sum,
 
604
        "lnk", MAGIC_lnk, FORMAT_lnk,
 
605
        "ofs", MAGIC_ofs, FORMAT_ofs,
 
606
        "oix", MAGIC_oix, FORMAT_oix,
 
607
        "trm", MAGIC_trm, FORMAT_trm,
 
608
        "tix", MAGIC_tix, FORMAT_tix,
 
609
        "pst", MAGIC_pst, FORMAT_pst,
 
610
        "inf", MAGIC_inf, FORMAT_inf
 
611
};
 
612
 
 
613
 
 
614
struct CdDirInfo _dir[] = {
 
615
        SYS_KEYNAME, SYS_DIRNAME, NULL, NULL,
 
616
        IDX_KEYNAME, IDX_DIRNAME, NULL, _fd_idx,
 
617
        SUM_KEYNAME, SUM_DIRNAME, NULL, _fd_sum,
 
618
        TRM_KEYNAME, TRM_DIRNAME, NULL, NULL,
 
619
        LNK_KEYNAME, LNK_DIRNAME, NULL, _fd_lnk,
 
620
        REC_KEYNAME, REC_DIRNAME, NULL, NULL    
 
621
};
 
622
 
 
623
 
 
624
static EntrezInfo * _cdinfo;
 
625
static short _init_ct;
 
626
static short _rel_major;
 
627
static short _rel_minor;
 
628
static short _device_ct;
 
629
static short _volume_ct;
 
630
static short _type_ct;
 
631
static short _div_ct;
 
632
static short _fld_ct;
 
633
static short _verbose_trace;
 
634
 
 
635
static CdVolume * _cdvol; 
 
636
static CdDevice * _cddev;
 
637
 
 
638
static DivInfo * _div;
 
639
static UidIndex * _uidx;
 
640
static TrmIndex ** _tidx[TYPE_MAX];
 
641
 
 
642
#define IDX_REC_SIZE   20
 
643
 
 
644
static int _idx_page_size;
 
645
static int _idx_page_slots;
 
646
static int _trm_page_size;
 
647
 
 
648
static Cache * _idx_cache;
 
649
static Cache * _trm_cache;
 
650
 
 
651
static char * _rcfile = "ncbi";
 
652
 
 
653
static CdMap _map[CdDir_LAST+1];
 
654
 
 
655
 
 
656
 
 
657
static int FileReadSwapShort (unsigned short *buffer, int count, FILE *fd);
 
658
static int FileReadSwapLong (unsigned long *buffer, int count, FILE *fd);
 
659
static int FileReadSwapInt4 (Uint4 *buffer, int count, FILE *fd);
 
660
 
 
661
 
 
662
 
 
663
static char * FileReadStr (FILE *fd, int lbyte);
 
664
 
 
665
 
 
666
 
 
667
 
 
668
/****************************************************************************
 
669
*
 
670
*               EXPORTED APIs
 
671
*
 
672
*****************************************************************************/
 
673
 
 
674
NLM_EXTERN Boolean  cd3_CdInit (void)
 
675
{
 
676
        int n, j, k, pages;
 
677
        char buffer[256];
 
678
        unsigned short m[8];
 
679
        CdRomInfo info;
 
680
        CdDevice *dev;
 
681
        AsnIo *aio;
 
682
        FILE *fd;
 
683
        CdDevice *dev_startup = NULL; 
 
684
        
 
685
 
 
686
        _verbose_trace = GetAppParamBoolean(_rcfile,"CdEntrez","LogVerbose",FALSE);
 
687
        if (_verbose_trace)
 
688
          ErrLogPrintf("CdInit()     [%s %s]\n", THIS_MODULE, REVISION_STR);
 
689
 
 
690
        /*----- If already initialized, just increment counter -----*/
 
691
        if (_init_ct > 0)
 
692
        {
 
693
                _init_ct++;
 
694
                return TRUE;
 
695
        }
 
696
        
 
697
 
 
698
        /***if (!_verbose_trace)
 
699
        {
 
700
                ErrLogPrintf("      Add \"LogVerbose=YES\" below [CdEntrez] in your NCBI\n");
 
701
                ErrLogPrintf("      configuration file to log detailed information to this file.\n");
 
702
        }***/
 
703
 
 
704
        /*----- Gather information from config file -----*/
 
705
        _device_ct = (int) GetAppParamInt(_rcfile,"CdEntrez","DeviceCount",0);
 
706
        if (_device_ct == 0)
 
707
                        return InvalidConfiguration(1);
 
708
        
 
709
        for (n=CdDir_FIRST; n<=CdDir_LAST; ++n)
 
710
        {
 
711
                if (FindPath(_rcfile,"CdEntrez.Paths",_dir[n].key,buffer,sizeof buffer))
 
712
                        _dir[n].user_dir = StrSave(buffer);
 
713
        }
 
714
 
 
715
        /*----- Initialize the list of devices -----*/
 
716
        _cddev = (CdDevice*) MemNew(sizeof(CdDevice) * _device_ct);
 
717
        for (n=0, dev=_cddev; n<_device_ct; ++n)
 
718
        {
 
719
                if (!CdDevice_Construct(dev++,n+1))
 
720
                        return FALSE;
 
721
        }
 
722
        
 
723
        /*----- Now we need locate a copy of cdvolume.inf -----*/
 
724
        memset((void*)&info,0,sizeof info);
 
725
        buffer[0] = '\0';
 
726
        if (_dir[CdDir_sys].user_dir !=NULL)
 
727
        {
 
728
                /* use the cdvolume.inf file on the hard disk */
 
729
                strcpy(buffer,_dir[CdDir_sys].user_dir);
 
730
                FileBuildPath(buffer,NULL,"cdvolume.inf");
 
731
        }
 
732
        else
 
733
        {
 
734
                /* first, look for a bound device */
 
735
                for (k=0, dev=_cddev; k<_device_ct; ++k, ++dev)
 
736
                {
 
737
                        if (_cddev[k].bound_cd && CdDevice_Init(dev))
 
738
                        {
 
739
                                dev_startup = dev;
 
740
                                CdDevice_FileBuildPath(dev,buffer,_dir[CdDir_sys].dir,"cdvolume.inf");
 
741
                                break;
 
742
                        }
 
743
                }               
 
744
 
 
745
                if (dev_startup == NULL)
 
746
                {               
 
747
                        /* if we reach this point, there are no bound devices, so
 
748
                                we now have to look through all of the devices, hoping
 
749
                                that one of them will have an Entrez CD-ROM already
 
750
                                inserted */
 
751
 
 
752
/*
 
753
#ifndef OS_DOS
 
754
*/
 
755
                        for (k=0, dev=_cddev; k<_device_ct; ++k, ++dev)
 
756
                        {
 
757
                                if (CdDevice_Init(dev))
 
758
                                {
 
759
                                        dev_startup = dev;
 
760
                                        break;
 
761
                                }
 
762
                        }
 
763
/*
 
764
#endif
 
765
*/
 
766
                        
 
767
                        if (dev_startup == NULL)
 
768
                        {   
 
769
                                /* Now were're going to have to ask the user
 
770
                                        to insert one of the CD's */
 
771
                                
 
772
                                dev_startup = &_cddev[0];
 
773
                                        
 
774
                                if (!(*_hookInsert)("Entrez1",&dev_startup->inf))
 
775
                                        return FALSE;
 
776
                                if (!CdDevice_Init(dev_startup))
 
777
                                {
 
778
                                        VERBOSE("CdDevice_Init() failed, line %d\n",__LINE__);
 
779
                                        return FALSE;
 
780
                                }
 
781
                        }
 
782
                        
 
783
                        CdDevice_FileBuildPath(dev_startup,buffer,_dir[CdDir_sys].dir,"cdvolume.inf");
 
784
                }
 
785
        }
 
786
 
 
787
        /*----- OK, now we've found cdvolume.inf, let's read it -----*/
 
788
        if ((fd = FileOpen(buffer,"rb")) ==NULL)
 
789
                return FALSE;
 
790
        FileReadSwapShort(m,6,fd); 
 
791
        if (m[0] != MAGIC_inf)
 
792
                return FileCorrupt(buffer);
 
793
        if (m[1] > FORMAT_inf)
 
794
                ErrPostEx(SEV_INFO,0,0,"File %s format number greater than expected",buffer);
 
795
        _rel_major = m[2];
 
796
        _rel_minor = m[3];
 
797
        _volume_ct = m[5];
 
798
        FileClose(fd);
 
799
        VERBOSE("File cdvolume.inf read OK. \n"); 
 
800
        VERBOSE("Release %d.%d (on %d CDs)\n",_rel_major,_rel_minor,_volume_ct); 
 
801
 
 
802
        /*----- Locate & read the cdentrez.inf file -----*/
 
803
        if (_dir[CdDir_sys].user_dir !=NULL)
 
804
                FileBuildPath(strcpy(buffer,_dir[CdDir_sys].user_dir),NULL,"cdentrez.inf");
 
805
        else
 
806
                CdDevice_FileBuildPath(dev_startup,buffer,_dir[CdDir_sys].dir,"cdentrez.inf");
 
807
        if ((aio = AsnIoOpen(buffer,"r")) ==NULL)
 
808
                return InvalidConfiguration(1);
 
809
        _cdinfo = EntrezInfoAsnRead(aio,NULL);
 
810
        _cdinfo->cd_count = _volume_ct;
 
811
        AsnIoClose(aio);
 
812
        if (_cdinfo == NULL)
 
813
        {
 
814
                ErrPostEx(SEV_INFO,0,0,"EntrezInfoAsnRead failure");
 
815
                return FALSE;
 
816
        }
 
817
        
 
818
        _type_ct = _cdinfo->type_count;
 
819
        _fld_ct = _cdinfo->field_count;
 
820
        _div_ct = _cdinfo->div_count;
 
821
        _idx_page_size = _cdinfo->type_bucket_size;
 
822
        _idx_page_slots = _idx_page_size / IDX_REC_SIZE;
 
823
        _trm_page_size = _cdinfo->field_bucket_size;
 
824
        VERBOSE("File cdentrez.inf read OK.  \n");
 
825
 
 
826
        /*----- initialize the list of volumes -----*/
 
827
        _cdvol = (CdVolume*) MemNew(sizeof(CdVolume) * _volume_ct);
 
828
        for (n=0; n<_volume_ct; ++n)
 
829
        {
 
830
                CdVolume_Construct(&(_cdvol[n]),n+1);
 
831
#ifdef OS_MAC
 
832
                if (_cdvol[n].device == NULL)  
 
833
                {   /* the volume is not associated with any device, see if it's on desktop */
 
834
                        char volname[16];
 
835
                        CdRomInfo info;
 
836
 
 
837
                        sprintf(volname,"entrez%d",n+1);
 
838
                        if (CdTestPath(volname,&info))
 
839
                        {       /* the volume is indeed on the desktop, find a device to mount it on */
 
840
                                int i;
 
841
                                for (i=0; i<_device_ct; ++i)
 
842
                                {
 
843
                                        if (_cddev[i].volume == NULL)
 
844
                                        {
 
845
                                                if (CdVolume_Mount(&_cdvol[n],&_cddev[i],FALSE))
 
846
                                                        break;
 
847
                                        }
 
848
                                }
 
849
                        }
 
850
                }
 
851
#endif
 
852
        }
 
853
 
 
854
        /*----- If fewer devices than volumes, at least one must be ejectable -----*/
 
855
        if (_device_ct < _volume_ct)
 
856
        {
 
857
                for (n=0; n<_device_ct; ++n)
 
858
                {
 
859
                        if (_cddev[n].is_ejectable)     
 
860
                                break;
 
861
                }
 
862
                if (n == _device_ct)
 
863
                        return InvalidConfiguration(2);
 
864
        }
 
865
        
 
866
        /*----- Initialize index and term caches -----*/
 
867
        n = (int) GetAppParamInt(_rcfile,"CdEntrez","IdxCacheSize",DEFAULT_IdxCacheSize);
 
868
        pages = (int) ( (long)n * (long)KBYTE / (long)_idx_page_size);
 
869
        pages = MAX(1,MIN(pages,256));
 
870
        _idx_cache = Cache_New(pages,DefCacheDataFreeProc);
 
871
        _idx_cache->page_size = _idx_page_size;
 
872
        n = (int) GetAppParamInt(_rcfile,"CdEntrez","TrmCacheSize",DEFAULT_TrmCacheSize);
 
873
        pages = (int) ( ((long)n * (long)KBYTE) / (long)_trm_page_size);
 
874
        pages = MAX(1,MIN(pages,256));
 
875
        _trm_cache = Cache_New(pages,DefCacheDataFreeProc);
 
876
        _trm_cache->page_size = _trm_page_size;
 
877
 
 
878
        /*----- Initialize the UidIndex & TrmIndex structures -----*/
 
879
        _uidx = (UidIndex*) MemNew(sizeof(UidIndex) * _type_ct);
 
880
        for (n=0; n<_type_ct; ++n)
 
881
        {
 
882
                UidIndex_Construct(&(_uidx[n]),(DocType)n,&(_cdinfo->types[n]));
 
883
                
 
884
                _tidx[n] = (TrmIndex**) MemNew(sizeof(TrmIndex*) * _fld_ct);
 
885
                for (j=0; j<_fld_ct; ++j)
 
886
                {
 
887
                        if (_cdinfo->types[n].fields[j].num_terms > 0)
 
888
                                _tidx[n][j] = TrmIndex_New(n,j,FLDTAG(j),&(_cdinfo->types[n].fields[j]));
 
889
                }
 
890
        }
 
891
        
 
892
        /*----- Read the cdlayout.inf file -----*/
 
893
        if (_dir[CdDir_sys].user_dir !=NULL)
 
894
                FileBuildPath(strcpy(buffer,_dir[CdDir_sys].user_dir),NULL,"cdlayout.inf");
 
895
        else
 
896
                CdDevice_FileBuildPath(dev_startup,buffer,_dir[CdDir_sys].dir,"cdlayout.inf");
 
897
        if ((fd = FileOpen(buffer,"r")) ==NULL)
 
898
                return FALSE;
 
899
        ReadCdLayout(fd);
 
900
        FileClose(fd);
 
901
        VERBOSE("File cdlayout.inf read OK \n");
 
902
        
 
903
        /*----- Done. return success -----*/
 
904
        _init_ct++;
 
905
        return TRUE;
 
906
}
 
907
 
 
908
 
 
909
NLM_EXTERN Boolean cd3_CdFini (void)
 
910
{
 
911
        int i, j;
 
912
        CdEntrezDir dir;
 
913
        
 
914
        _verbose_trace = GetAppParamBoolean(_rcfile,"CdEntrez","LogVerbose",FALSE);
 
915
        if (_verbose_trace)     
 
916
          ErrLogPrintf("CdFini()\n");
 
917
 
 
918
        if (!IsInitialized())
 
919
                return FALSE;           
 
920
        if ((--_init_ct) > 0)
 
921
                return TRUE;
 
922
        
 
923
        /*----- Free index and cache data -----*/
 
924
        if (Cache_IsValid(_idx_cache))
 
925
        {
 
926
                Cache_LogStats(_idx_cache,"idx");
 
927
                Cache_Free(_idx_cache);
 
928
        }
 
929
        if (Cache_IsValid(_trm_cache))
 
930
        {
 
931
                Cache_LogStats(_trm_cache,"trm");
 
932
                Cache_Free(_trm_cache); 
 
933
        }
 
934
        for (i=0; i<_type_ct; ++i)
 
935
        {
 
936
                UidIndex_Destruct(&_uidx[i]);
 
937
                for (j=0; j<_fld_ct; ++j)
 
938
                        TrmIndex_Free(_tidx[i][j]);
 
939
                MemFree((void*)_tidx[i]);
 
940
                _tidx[i] = NULL;
 
941
                HuffTable_Destruct(_huff_tab[i]);
 
942
                _huff_tab[i] = NULL;
 
943
        }
 
944
        MemFree((void*)_uidx);
 
945
        
 
946
        /*----- Free CdVolume and CdDevice data -----*/
 
947
        for (i=0; i<_volume_ct; ++i)
 
948
                CdVolume_Destruct(&_cdvol[i]);
 
949
        for (i=0; i<_device_ct; ++i)
 
950
                CdDevice_Destruct(&_cddev[i]); 
 
951
        MemFree((void*)_cdvol);
 
952
        MemFree((void*)_cddev);
 
953
        
 
954
        /*----- Free cdlayout stuff -----*/
 
955
        for (dir=CdDir_FIRST; dir<=CdDir_LAST; ++dir)
 
956
        {
 
957
                CdMap_Destruct(&_map[dir]);
 
958
                MemFree(_dir[dir].user_dir);
 
959
        }
 
960
 
 
961
        /*----- Free the EntrezInfo struct -----*/
 
962
        EntrezInfoFree(_cdinfo);
 
963
        _cdinfo = NULL;
 
964
        return TRUE;
 
965
}
 
966
 
 
967
 
 
968
NLM_EXTERN AsnIo* cd3_EntrezInfoOpen (const char *dirname)
 
969
{
 
970
        VERBOSE("EntrezInfoOpen(%s)\n", dirname ? dirname : "NULL");
 
971
        
 
972
        /* NOT IMPLEMENTED */
 
973
        
 
974
        /* Do we need this?  Things seem to be working fine without it! */
 
975
        
 
976
        return NULL;
 
977
}
 
978
 
 
979
 
 
980
NLM_EXTERN EntrezInfo* cd3_CdGetInfo (void)
 
981
{
 
982
        VERBOSE("CdGetInfo()\n");
 
983
        
 
984
        return _cdinfo;
 
985
}
 
986
 
 
987
 
 
988
NLM_EXTERN char* cd3_CdDetailedInfo (void)
 
989
{
 
990
        char *detailed;
 
991
        
 
992
        VERBOSE("CdDetailedInfo()\n");
 
993
 
 
994
        if ((detailed  = (char*)Malloc(8192)) == NULL)
 
995
                return NULL;
 
996
                
 
997
        if (!IsInitialized())
 
998
        {
 
999
                strcpy(detailed,"*** NOT INITIALIZED ***");
 
1000
        }
 
1001
        else
 
1002
        {
 
1003
                char *p = detailed;
 
1004
                sprintf(p,"Entrez release %d.%d\n",_rel_major,_rel_minor);
 
1005
                
 
1006
                if (_cdinfo->div_info != NULL)
 
1007
                {
 
1008
                        EntrezDivInfo *div;
 
1009
                        int i, j;
 
1010
 
 
1011
                        sprintf(p=strchr(p,0),"\nDIVISION INFORMATION\n");
 
1012
 
 
1013
                        for (i=0, div=_cdinfo->div_info; i<_cdinfo->div_count; ++i, ++div)
 
1014
                        {
 
1015
                                sprintf(p=strchr(p,0),"   %s:  ",div->tag);
 
1016
                                sprintf(p=strchr(p,0),"%-36s  ",div->descr);
 
1017
                                sprintf(p=strchr(p,0),"%-25s\n",div->reldate ? div->reldate : "?");
 
1018
                        }
 
1019
 
 
1020
                        sprintf(p=strchr(p,0),"\n   div        Document Counts by Type\n");
 
1021
                        sprintf(p=strchr(p,0),"   tag         ml      aa      nt      st\n");
 
1022
                        sprintf(p=strchr(p,0),"   ---     ------  ------  ------  ------\n");
 
1023
                        for (i=0, div=_cdinfo->div_info; i<_cdinfo->div_count; ++i, ++div)
 
1024
                        {
 
1025
                                sprintf(p=strchr(p,0),"   %s:   ",div->tag);
 
1026
                                if (div->docs != NULL)
 
1027
                                {
 
1028
                                        for (j=0; j<_type_ct; ++j)
 
1029
                                                sprintf(p=strchr(p,0),"%7ld ",div->docs[j]);
 
1030
                                }
 
1031
                                sprintf(p=strchr(p,0),"\n");
 
1032
                        }
 
1033
                }
 
1034
                
 
1035
                if (_idx_cache != NULL && _trm_cache != NULL)
 
1036
                {
 
1037
                        sprintf(p=strchr(p,0),"\nCACHE STATISTICS\n");
 
1038
                        sprintf(p=strchr(p,0),"\nIndex page cache:\n");                 
 
1039
                        Cache_ReportStats(_idx_cache,strchr(p,0));
 
1040
                        sprintf(p=strchr(p,0),"\nTerm page cache:\n");                  
 
1041
                        Cache_ReportStats(_trm_cache,strchr(p,0));
 
1042
                }
 
1043
        }               
 
1044
        return detailed;
 
1045
}
 
1046
 
 
1047
NLM_EXTERN int  cd3_CdTrmPageCt (DocType type, DocField fld)
 
1048
{
 
1049
        VERBOSE("CdTrmPageCt(%d,%d)\n",type,fld);
 
1050
        
 
1051
        if (IsInitialized() && ValidType(type) && ValidField(fld))
 
1052
        {
 
1053
                return _cdinfo->types[type].fields[fld].num_bucket; 
 
1054
        }
 
1055
        return 0;
 
1056
}
 
1057
 
 
1058
NLM_EXTERN int  cd3_CdTrmLookup (DocType type, DocField fld, const char *term)
 
1059
{
 
1060
        VERBOSE("CdTrmLookup(%d,%d,%s)\n",type,fld,term);
 
1061
 
 
1062
        if (IsInitialized() && ValidType(type) && ValidField(fld))
 
1063
        {
 
1064
                TrmIndex *tidx = _tidx[type][fld];
 
1065
                if (tidx != NULL)
 
1066
                        return TrmIndex_Lookup(tidx,term);
 
1067
        }
 
1068
        return -1;
 
1069
}
 
1070
 
 
1071
NLM_EXTERN CdTerm* cd3_CdTrmFind (DocType type, DocField fld, const char *term)
 
1072
{
 
1073
        CdTerm *trm = NULL;
 
1074
        
 
1075
        VERBOSE("CdTrmFind(%d,%d,%s)\n",type,fld,term);
 
1076
        
 
1077
        if (IsInitialized() && ValidType(type) && ValidField(fld))
 
1078
        {
 
1079
                TrmIndex *tidx = _tidx[type][fld];
 
1080
                if (tidx != NULL)
 
1081
                        trm = TrmIndex_GetCdTerm(tidx,term);
 
1082
        }
 
1083
        return trm;
 
1084
}
 
1085
 
 
1086
NLM_EXTERN int cd3_CdTermScan (DocType type, DocField fld, int page_start, 
 
1087
                        int page_count, CdTermProc proc)
 
1088
{
 
1089
        int count=0;
 
1090
        
 
1091
        VERBOSE("CdTermScan(%d,%d,%d,%d,[proc])\n",type,fld,page_start,page_count);
 
1092
        
 
1093
        if (IsInitialized() && ValidType(type) && ValidField(fld))
 
1094
        {
 
1095
                TrmIndex *tidx = _tidx[type][fld];
 
1096
                if (tidx != NULL)
 
1097
                {
 
1098
                        if (page_count <=0)
 
1099
                                page_count = INT_MAX;
 
1100
                        count = TrmIndex_ScanPages(tidx,page_start,page_count,proc);
 
1101
                }
 
1102
        }
 
1103
        return (Int2)count;
 
1104
}
 
1105
 
 
1106
NLM_EXTERN long cd3_CdTrmUidsFil (DocType type, DocField fld, long offset,
 
1107
                                                long count, const char *filename, Boolean append)
 
1108
{
 
1109
        long ct =0;
 
1110
        
 
1111
        VERBOSE("CdTrmUidsFil(%d,%d,%ld,%ld,%s,%s)\n",type,fld,offset,count,
 
1112
                                        filename, append ? "TRUE" : "FALSE" );
 
1113
        
 
1114
        if (IsInitialized() && ValidType(type) && ValidField(fld))
 
1115
        {
 
1116
                TrmIndex *tidx = _tidx[type][fld];
 
1117
                if (tidx != NULL)
 
1118
                {
 
1119
                        FILE *fd1 = TrmIndex_PostingsFileOpen(tidx);
 
1120
                        FILE *fd2 = FileOpen(filename,(append) ? "ab":"wb");
 
1121
                        if (fd1 != NULL && fd2 != NULL)
 
1122
                        {
 
1123
                                Uint4 arr[64];
 
1124
                                long m = DIM(arr);
 
1125
                                long n1, n2;
 
1126
 
 
1127
                                VERIFY(fseek(fd1,offset,SEEK_SET) ==0);
 
1128
 
 
1129
                                for (n1=count; n1>0; n1-=n2)
 
1130
                                {
 
1131
                                        n2 = MIN(n1,m);
 
1132
                                        n2 = FileReadSwapInt4(arr,(int)n2,fd1);
 
1133
                                        FileWrite((void*)arr,sizeof(Int4),(size_t)n2,fd2);
 
1134
                                }
 
1135
                                ct = count - n1;
 
1136
                        }
 
1137
                        else VERBOSE("   * TrmIndex_PostingsFileOpen failed\n");
 
1138
                        FileClose(fd1);
 
1139
                        FileClose(fd2);
 
1140
                }
 
1141
        }
 
1142
        return ct;
 
1143
}
 
1144
 
 
1145
 
 
1146
NLM_EXTERN long cd3_CdTrmUidsMem (DocType type, DocField fld, long offset,
 
1147
                                                                long count, DocUid *mem)
 
1148
{
 
1149
        VERBOSE("CdTrmUidsMem(%d,%d,%ld,%ld,[mem])\n",type,fld,
 
1150
                                        offset,count);
 
1151
        
 
1152
        ASSERT(count < (long)(UINT_MAX/sizeof(long)));
 
1153
        
 
1154
        if (IsInitialized() && ValidType(type) && ValidField(fld))
 
1155
        {
 
1156
                TrmIndex *tidx = _tidx[type][fld];
 
1157
                if (tidx != NULL)
 
1158
                {
 
1159
                        FILE *fd = TrmIndex_PostingsFileOpen(tidx);
 
1160
                        if (fd != NULL)
 
1161
                        {
 
1162
                                VERIFY(fseek(fd,offset,SEEK_SET) ==0);
 
1163
                                count = FileReadSwapInt4((Uint4*)mem,(int)count,fd);
 
1164
                                FileClose(fd);
 
1165
                                return count;
 
1166
                        }
 
1167
                }
 
1168
        }
 
1169
        return 0;
 
1170
}
 
1171
 
 
1172
 
 
1173
NLM_EXTERN int cd3_CdLinkUidGet (LinkSetPtr *result, DocType type,
 
1174
                DocType link_to_type, int numuid, DocUid *uid_list, 
 
1175
                Boolean mark_missing, long maxlink)
 
1176
{
 
1177
        int i, cnt;
 
1178
        DocUid uid, *puid = uid_list;
 
1179
        UidIndex *uidx;
 
1180
        UidIndexRec rec;
 
1181
        FILE *fd=NULL;
 
1182
        LSet *lset = NULL;
 
1183
        
 
1184
        VERBOSE("CdLinkUidGet([result],%d,%d,%d,[list],%s,%ld)\n",
 
1185
                                type,link_to_type,numuid,
 
1186
                                mark_missing ? "TRUE" : "FALSE", maxlink);
 
1187
        
 
1188
        if (! (IsInitialized() && ValidType(type) && ValidType(link_to_type)) )
 
1189
        {
 
1190
                *result = NULL;
 
1191
                return 0;
 
1192
        }
 
1193
                
 
1194
        uidx = &(_uidx[type]);
 
1195
        
 
1196
        for (i=cnt=0; i<numuid; ++i, ++puid)
 
1197
        {
 
1198
                uid = ABS(*puid);
 
1199
                if (UidIndex_Lookup(uidx,uid,&rec))
 
1200
                {
 
1201
                        cnt++;
 
1202
 
 
1203
                        if (rec.lnk_offset > 0)
 
1204
                        {               
 
1205
                                if (fd == NULL)
 
1206
                                {
 
1207
                                        char fname[16];
 
1208
                                        strcpy(fname,TYPTAG(type));
 
1209
                                        strcat(fname,".lnk");
 
1210
                                        if ((fd = CdEntrez_FileOpen(CdDir_lnk,type,rec.divnum,LNK,fname,"rb")) ==NULL)
 
1211
                                                break;
 
1212
                                        maxlink = MIN(maxlink,INT_MAX);
 
1213
                                        if ((lset = LSet_New(type,link_to_type,(int)maxlink)) ==NULL)
 
1214
                                                break;
 
1215
                                }
 
1216
                                if (fseek(fd,rec.lnk_offset,SEEK_SET) !=0)
 
1217
                                {
 
1218
                                        ErrPostEx(SEV_INFO,0,0,"fseek failure");
 
1219
                                        break;
 
1220
                                }
 
1221
                                if (!LSet_Read(lset,fd))
 
1222
                                        break;
 
1223
                        }
 
1224
                }
 
1225
                else if (mark_missing)
 
1226
                {
 
1227
                        *puid = -uid;
 
1228
                }
 
1229
        }
 
1230
        
 
1231
        CdEntrez_FileClose(CdDir_lnk,type,fd);
 
1232
        *result = (lset==NULL) ? NULL : LSet_Convert(lset);
 
1233
        return cnt;
 
1234
}
 
1235
 
 
1236
#define BIT_non_document   0x001
 
1237
#define BIT_no_abstract    0x002
 
1238
#define BIT_no_authors     0x004
 
1239
#define BIT_trans_title    0x008
 
1240
#define BIT_is_partial     0x010
 
1241
#define BIT_is_segmented   0x020
 
1242
 
 
1243
NLM_EXTERN DocSum* cd3_CdGetDocSum (DocType type, DocUid uid)
 
1244
{
 
1245
        DocSum *sum = NULL;
 
1246
        UidIndex *uidx;
 
1247
        UidIndexRec rec;                            
 
1248
        
 
1249
        VERBOSE("CdGetDocSum(%d,%ld)\n",type,uid);
 
1250
                
 
1251
        if (!IsInitialized() || !ValidType(type))
 
1252
                return NULL;            
 
1253
        
 
1254
        uidx = &(_uidx[type]);
 
1255
        if (UidIndex_Lookup(uidx,uid,&rec) && rec.sum_offset > 0)
 
1256
        {
 
1257
                char fname[16];
 
1258
                FILE *fd;
 
1259
 
 
1260
                strcpy(fname,TYPTAG(type));
 
1261
                strcat(fname,".sum");
 
1262
                if ((fd = CdEntrez_FileOpen(CdDir_sum,type,0,SUM,fname,"rb")) !=NULL)
 
1263
                {
 
1264
                        if (fseek(fd,rec.sum_offset,SEEK_SET) !=0)
 
1265
                                ErrPostEx(SEV_INFO,0,0,"fseek failure");
 
1266
 
 
1267
                        if ((sum = (DocSum*)MemNew(sizeof(DocSum))) !=NULL)
 
1268
                        {
 
1269
                                unsigned short m[4];
 
1270
                                FileReadSwapShort(m,3,fd);
 
1271
                                
 
1272
                                /* m[0] is doc-flags */
 
1273
                                if (m[0] & BIT_non_document)  sum->non_document = TRUE;
 
1274
                                if (m[0] & BIT_no_abstract)  sum->no_abstract = TRUE;
 
1275
                                if (m[0] & BIT_no_authors)  sum->no_authors = TRUE;
 
1276
                                if (m[0] & BIT_trans_title)  sum->translated_title = TRUE;
 
1277
                                if (m[0] & BIT_is_partial)  sum->is_partial = TRUE;
 
1278
                                if (m[0] & BIT_is_segmented)  sum->is_segmented = TRUE;
 
1279
 
 
1280
                                /* m[1] is create date */
 
1281
                                if (m[1] != 0)
 
1282
                                {
 
1283
                                        sum->create.year =  1950 + ((int) (m[1] & 0xFE00) >> 9);
 
1284
                                        sum->create.month = ((int) (m[1] & 0x01E0) >> 5);
 
1285
                                        sum->create.day = (m[1] & 0x001F);
 
1286
                                }
 
1287
                                
 
1288
                                /* m[2] is modify date */
 
1289
                                if (m[2] != 0)
 
1290
                                {
 
1291
                                        sum->modify.year =  1950 + ((int) (m[2] & 0xFE00) >> 9);
 
1292
                                        sum->modify.month = ((int) (m[2] & 0x01E0) >> 5);
 
1293
                                        sum->modify.day = (m[2] & 0x001F);
 
1294
                                }
 
1295
                                
 
1296
                                FileReadSwapShort((unsigned short*)sum->link_count,_type_ct,fd);
 
1297
                                sum->caption = FileReadStr(fd,1);
 
1298
                                sum->title = FileReadStr(fd,2);
 
1299
                                sum->extra = FileReadStr(fd,1);
 
1300
                                sum->uid = uid;
 
1301
                        }
 
1302
                        CdEntrez_FileClose(CdDir_sum,type,fd);
 
1303
                }
 
1304
        }
 
1305
        else
 
1306
        {
 
1307
                VERBOSE("   * bad UID %ld ?\n", uid);
 
1308
        }
 
1309
        return sum;
 
1310
}
 
1311
 
 
1312
NLM_EXTERN AsnIo* cd3_CdDocAsnOpen (DocType type, DocUid uid)
 
1313
{
 
1314
        char fname[16];
 
1315
        AsnIo *aio = NULL;
 
1316
        UidIndex *uidx;
 
1317
        UidIndexRec rec;
 
1318
        
 
1319
        VERBOSE("CdDocAsnOpen(%d,%ld)\n",type,uid);
 
1320
                
 
1321
        if (!IsInitialized() || !ValidType(type))
 
1322
                return NULL;
 
1323
 
 
1324
        uidx = &(_uidx[type]);
 
1325
        if (UidIndex_Lookup(uidx,uid,&rec))
 
1326
        {
 
1327
                char *fdir = NULL;
 
1328
                FILE *fd;
 
1329
                DecompInfo *decomp;
 
1330
                int c;
 
1331
 
 
1332
                sprintf(fname,"%s%s%03d.hca",TYPTAG(type),DIVTAG(rec.divnum-1),rec.filnum);
 
1333
                if ((fd = CdEntrez_FileOpen(CdDir_rec,uidx->type,rec.divnum,HCA,fname,"rb")) ==NULL)
 
1334
                        return NULL;
 
1335
 
 
1336
                if (_huff_tab[type] == NULL)
 
1337
                {
 
1338
                        fseek(fd,22,SEEK_SET);
 
1339
                        _huff_tab[type] = HuffTable_Read(fd);
 
1340
                        if (_huff_tab[type] == NULL)
 
1341
                        {
 
1342
                                return (AsnIo*) CatastrophicFailure(1);
 
1343
                        }
 
1344
                }
 
1345
                if (fseek(fd,rec.hca_offset,SEEK_SET) !=0)
 
1346
                {
 
1347
                        FileClose(fd);
 
1348
                        ErrPostEx(SEV_INFO,0,0,"fseek failure");
 
1349
                }
 
1350
                else
 
1351
                {
 
1352
                        c = fgetc(fd);
 
1353
                        if ((c & 0x0F) != 1)
 
1354
                                ErrPostEx(SEV_INFO,0,0,"unknown error");
 
1355
                        c = fgetc(fd);
 
1356
                        c = fgetc(fd);
 
1357
                        c = fgetc(fd);
 
1358
                        decomp = DecompInfo_New(_huff_tab[type]);
 
1359
                        aio = DecompInfo_Attach(decomp,fd);
 
1360
                }
 
1361
        }
 
1362
        return aio;
 
1363
}
 
1364
 
 
1365
NLM_EXTERN AsnIo* cd3_CdDocAsnClose (AsnIo* aio)
 
1366
{
 
1367
        DecompInfo *info;
 
1368
        FILE *fd;
 
1369
        
 
1370
        VERBOSE("CdDocAsnClose([aio])\n");
 
1371
        
 
1372
        ASSERT(aio != NULL);
 
1373
        info = (DecompInfo*) aio->iostruct;
 
1374
        ASSERT(info!= NULL);
 
1375
        fd = DecompInfo_Detach(info);
 
1376
        FileClose(fd);
 
1377
        DecompInfo_Free(info);
 
1378
        return NULL;
 
1379
}
 
1380
 
 
1381
 
 
1382
Boolean LIBCALL CdTestPath (const char *path, CdRomInfo *info)
 
1383
{
 
1384
        static char *fdir = SYS_DIRNAME;
 
1385
        static char *fname = "cdvolume.inf";
 
1386
        char fpath[256], *p;
 
1387
        unsigned short m[8];
 
1388
        FILE *fd;
 
1389
        
 
1390
        VERBOSE("CdTestPath(%s,[info])\n",path);
 
1391
        ASSERT(info != NULL);
 
1392
        
 
1393
        memset((void*)info,0,sizeof(CdRomInfo));
 
1394
        
 
1395
        /*----- lowercase, without ";1" -----*/
 
1396
        strcpy(fpath,path);
 
1397
        p = strchr(fpath,'\0');
 
1398
        FileBuildPath(fpath,fdir,fname);
 
1399
        StrLower(p);
 
1400
        if (FileLength(fpath) >0)
 
1401
                goto DisneyLand;
 
1402
        VERBOSE("   access attempt [%s] failed\n",fpath);
 
1403
 
 
1404
        /*----- lowercase, with ";1" -----*/
 
1405
        strcat(fpath,";1");
 
1406
        if (FileLength(fpath) >0)
 
1407
        {
 
1408
                info->semicolon_one = 1;
 
1409
                goto DisneyLand;
 
1410
        }
 
1411
        VERBOSE("   access attempt [%s] failed\n",fpath);
 
1412
 
 
1413
        /*----- uppercase, without ";1" -----*/
 
1414
        info->upper_case = 1;
 
1415
        strcpy(fpath,path);
 
1416
        FileBuildPath(fpath,fdir,(char*)fname);
 
1417
        StrUpper(p);
 
1418
        if (FileLength(fpath) >0)
 
1419
                goto DisneyLand;
 
1420
        VERBOSE("   access attempt [%s] failed\n",fpath);
 
1421
 
 
1422
        /*----- uppercase, with ";1" -----*/
 
1423
        strcat(fpath,";1");
 
1424
        if (FileLength(fpath) >0)
 
1425
        {
 
1426
                info->semicolon_one = 1;
 
1427
                goto DisneyLand;
 
1428
        }
 
1429
 
 
1430
        VERBOSE("   access attempt [%s] failed\n",fpath);
 
1431
        VERBOSE("   struck out on [%s].  must be either invalid or not mounted\n",path);
 
1432
        return FALSE;
 
1433
 
 
1434
        
 
1435
/*----- success -----*/
 
1436
 DisneyLand:       
 
1437
        VERBOSE("   access attempt [%s] succeeded\n",fpath);
 
1438
        
 
1439
        if ((fd = FileOpen(fpath,"rb")) == NULL)
 
1440
        {
 
1441
                /*ErrPostEx(SEV_ERROR,2,3,"fopen(\"%s\",\"rb\") failed\n",fpath);*/
 
1442
                return FALSE;
 
1443
        }
 
1444
 
 
1445
        /*----- read first 5 values in file -----
 
1446
        *       m[0]  magic value for this file
 
1447
        *       m[1]  format code for this file
 
1448
        *       m[2]  cdrom release number (major portion)
 
1449
        *       m[3]  cdrom release number (minor portion)
 
1450
        *       m[4]  cdrom volume number (1, 2, or 3)
 
1451
        *       m[5]  number of CD-ROMs in the set
 
1452
        */
 
1453
                
 
1454
        FileReadSwapShort(m,6,fd);   /**** need to check for error ****/
 
1455
        FileClose(fd);
 
1456
        if (m[0] != MAGIC_inf)
 
1457
                return FileCorrupt(fpath);
 
1458
        if (m[1] != FORMAT_inf)
 
1459
                VERBOSE("   unexpected format number (%d) for file %s\n",(int)m[1],fpath);
 
1460
        info->rel_major = m[2];
 
1461
        info->rel_minor = m[3];
 
1462
        info->cd_num = m[4];
 
1463
        info->cd_count = m[5];
 
1464
        VERBOSE("   release %d.%d; cd %d of %d\n",(int)m[2],(int)m[3],(int)m[4],(int)m[5]);
 
1465
        return TRUE;    
 
1466
}
 
1467
 
 
1468
 
 
1469
static char UnixReadChar (FILE *f)
 
1470
 
 
1471
{
 
1472
  char  ch;
 
1473
  int   getcrsult;
 
1474
 
 
1475
  ch = '\0';
 
1476
  if (f != NULL) {
 
1477
    getcrsult = fgetc (f);
 
1478
    ch = (char) getcrsult;
 
1479
    if (getcrsult == EOF && feof (f)) {
 
1480
      ch = '\0';
 
1481
    }
 
1482
  }
 
1483
  return ch;
 
1484
}
 
1485
 
 
1486
static char *UnixFileGets(char *buff, int maxsize, FILE *f)
 
1487
 
 
1488
{
 
1489
  int  ch;
 
1490
  int  i;
 
1491
 
 
1492
  if (buff != NULL && maxsize > 0) {
 
1493
    *buff = '\0';
 
1494
    if (f != NULL) {
 
1495
      i = 0;
 
1496
      ch = UnixReadChar (f);
 
1497
      while (ch != '\0' && ch != '\r' && ch != '\n' && i < maxsize) {
 
1498
        buff [i] = ch;
 
1499
        i++;
 
1500
        ch = UnixReadChar (f);
 
1501
      }
 
1502
      if (ch != '\0') {
 
1503
        buff [i] = ch;
 
1504
        i++;
 
1505
      }
 
1506
      buff [i] = '\0';
 
1507
    }
 
1508
  }
 
1509
  if (ch == '\0') {
 
1510
    return NULL;
 
1511
  } else {
 
1512
    return buff;
 
1513
  }
 
1514
}
 
1515
 
 
1516
NLM_EXTERN long LIBCALL cd3_CdEnumFiles (CdEntrezDir dir, DocType type, const char *div,
 
1517
                        EntrezEnumFileProc proc, void *opaque_data)
 
1518
{
 
1519
        FILE *fd;
 
1520
        
 
1521
        VERBOSE("CdEnumFiles(%d,%d,%s,[proc],[opaque])\n",dir,type,
 
1522
                                div ? div : "NULL");
 
1523
        
 
1524
        if ((fd = CdEntrez_FileOpen(CdDir_sys,0,0,0,"cdlayout.inf","r")) != NULL)
 
1525
        {
 
1526
                char prefix[32], *p;
 
1527
                char line[80];  
 
1528
                long size, total_size = 0;
 
1529
                int doit = FALSE;
 
1530
                int count =0;
 
1531
                int cdnum;
 
1532
                        
 
1533
                strcpy(prefix,_dir[dir].key);
 
1534
                if (type >= 0)
 
1535
                {
 
1536
                        strcat(prefix,"-");
 
1537
                        strcat(prefix,TYPTAG(type));
 
1538
                        if (div != NULL)
 
1539
                        {
 
1540
                                strcat(prefix,"-");
 
1541
                                strcat(prefix,div);
 
1542
                        }
 
1543
                }
 
1544
                
 
1545
                while (UnixFileGets(line,sizeof line,fd))
 
1546
                {
 
1547
                        if (strchr("#\r\n",line[0])) 
 
1548
                                continue;  /* comment line */
 
1549
                                
 
1550
                        if (isalpha(line[0]))
 
1551
                        {
 
1552
                                if (doit)
 
1553
                                        break;
 
1554
                                        
 
1555
                                if (strncmp(line,prefix,strlen(prefix))==0)
 
1556
                                {
 
1557
                                        doit = TRUE;
 
1558
                                        VERIFY(p=strchr(line+1,'\t'));
 
1559
                                        *p++ = '\0';
 
1560
                                        cdnum = atoi(p);
 
1561
                                }
 
1562
                                else doit = FALSE;
 
1563
                        }
 
1564
                        else if (line[0] == '\t')
 
1565
                        {
 
1566
                                if (doit)
 
1567
                                {
 
1568
                                        VERIFY(p=strchr(line+1,'\t'));
 
1569
                                        *p++ = '\0';
 
1570
                                        size = atol(p);
 
1571
                                        total_size += size;
 
1572
                                        count++;
 
1573
                                        if (proc != NULL)
 
1574
                                        {
 
1575
                                                if (!(*proc)(cdnum,_dir[dir].dir,line+1,size,opaque_data))
 
1576
                                                        break;
 
1577
                                        }
 
1578
                                }
 
1579
                        }
 
1580
                }
 
1581
                FileClose(fd);
 
1582
 
 
1583
                if (count==0 && dir==CdDir_sys)
 
1584
                {
 
1585
                        static char * fn[] = { "cdentrez.inf", "cdlayout.inf", "cdvolume.inf" };
 
1586
                        static long   fs[] = { 9865, 4504, 12 };
 
1587
                        int i;
 
1588
                        
 
1589
                        /* The list of filenames and filesizes for the sysinfo directory
 
1590
                                was inadvertently omitted from the cdlayout.inf file on the 
 
1591
                                sample CD-ROMs distributed to developers.  This section of
 
1592
                                code should never be executed in the final release. */
 
1593
                        
 
1594
                        VERBOSE("   HACK (faking cdlayout.inf information for SYSINFO directory)\n");
 
1595
                        for (i=0; i<DIM(fs); ++i, ++count)
 
1596
                        {
 
1597
                                if (proc != NULL)
 
1598
                                {
 
1599
                                        if (!(*proc)(1,_dir[dir].dir,fn[i],fs[i],opaque_data))
 
1600
                                                break;
 
1601
                                }
 
1602
                                total_size += fs[i];
 
1603
                        }
 
1604
                }
 
1605
 
 
1606
                VERBOSE("   %d files enumerated\n",count);
 
1607
                return total_size;
 
1608
        }
 
1609
        return 0;
 
1610
}
 
1611
 
 
1612
 
 
1613
NLM_EXTERN CdDevHook LIBCALL CdSetInsertHook (CdDevHook hook)
 
1614
{
 
1615
    CdDevHook prev = _hookInsert;
 
1616
 
 
1617
        VERBOSE("CdSetInsertHook\n");
 
1618
 
 
1619
        _hookInsert = (hook==NULL) ? hook : default_CdInsertProc;
 
1620
        return prev;
 
1621
}
 
1622
 
 
1623
 
 
1624
NLM_EXTERN CdDevHook LIBCALL CdSetEjectHook (CdDevHook hook)
 
1625
{
 
1626
    CdDevHook prev = _hookEject;
 
1627
 
 
1628
        VERBOSE("CdSetEjectHook\n");
 
1629
 
 
1630
        _hookEject = (hook==NULL) ? hook : default_CdEjectProc;
 
1631
        return prev;
 
1632
}
 
1633
 
 
1634
 
 
1635
NLM_EXTERN Boolean LIBCALL CdMountEntrezVolume (int cdnum, char *root, size_t buflen)
 
1636
{
 
1637
        if (root != NULL)  *root = '\0';
 
1638
 
 
1639
        if (cdnum < 1 || cdnum > _volume_ct)
 
1640
                ErrPostEx(SEV_WARNING,1,0,"Entrez CD number (%d) out of range",cdnum);
 
1641
        else
 
1642
        {
 
1643
                CdVolume *cdvol = & _cdvol[cdnum-1];
 
1644
                CdDevice *cddev;
 
1645
 
 
1646
                if ((cddev = cdvol->device) ==NULL)
 
1647
                        cddev = CdVolume_Mount(cdvol,NULL,TRUE);
 
1648
 
 
1649
                if (cddev != NULL)
 
1650
                {
 
1651
                        if (root != NULL)
 
1652
                        {
 
1653
                                char temp[256];
 
1654
                                CdDevice_FileBuildPath(cddev,temp,NULL,NULL);
 
1655
                                strncat(root,temp,buflen);
 
1656
                        }
 
1657
                        return TRUE;
 
1658
                }
 
1659
        }
 
1660
        return FALSE;
 
1661
}
 
1662
 
 
1663
 
 
1664
NLM_EXTERN Boolean LIBCALL CdUnmountEntrezVolume (int cdnum)
 
1665
{
 
1666
        CdVolume *cdvol;
 
1667
        CdDevice *cddev;
 
1668
 
 
1669
        if (cdnum < 1 || cdnum > _volume_ct)
 
1670
        {
 
1671
                ErrPostEx(SEV_WARNING,1,0,"Entrez CD number (%d) out of range",cdnum);
 
1672
                return FALSE;
 
1673
        }
 
1674
 
 
1675
        cdvol = & _cdvol[cdnum-1];
 
1676
        cddev = cdvol->device;
 
1677
        if (cddev != NULL && cddev->is_ejectable)
 
1678
        {
 
1679
                char volume_to_eject[32];
 
1680
                volume_to_eject[0] = '\0';
 
1681
                if (cddev->ins_volname)
 
1682
                        sprintf(volume_to_eject,"entrez%d",cddev->volume->volume_num);
 
1683
                else if (cdvol->volume_name != NULL)
 
1684
                        strcpy(volume_to_eject,cdvol->volume_name);
 
1685
 
 
1686
                if (!(*_hookEject)(volume_to_eject,&cddev->inf))
 
1687
                        ErrPostEx(SEV_INFO,0,0,"Unable to eject %s",cdvol->volume_name);
 
1688
 
 
1689
                return CdVolume_Unmount(cdvol);
 
1690
        }
 
1691
        return FALSE;
 
1692
}
 
1693
 
 
1694
 
 
1695
/****************************************************************************
 
1696
*
 
1697
*               STATIC FUNCTIONS
 
1698
*
 
1699
*****************************************************************************/
 
1700
 
 
1701
 
 
1702
static Boolean IsInitialized (void)
 
1703
{
 
1704
        if (_cdinfo == NULL)
 
1705
        {
 
1706
                ErrPostEx(SEV_INFO,ERR_NotInited,1,"Library not initialized");
 
1707
                return FALSE;
 
1708
        }
 
1709
        return TRUE;
 
1710
}
 
1711
 
 
1712
 
 
1713
static Boolean ValidType (int type)
 
1714
{
 
1715
        if (!TYPE_IS_VALID(type))
 
1716
        {
 
1717
                ErrPostEx(SEV_INFO,ERR_BadParam,SUB_DocType,
 
1718
                                        "DocType value (%d) out of range ",type);
 
1719
                return FALSE;
 
1720
        }
 
1721
        return TRUE;
 
1722
}
 
1723
 
 
1724
 
 
1725
static Boolean ValidField (int field)
 
1726
{
 
1727
        if (!FIELD_IS_VALID(field))
 
1728
        {
 
1729
                ErrPostEx(SEV_INFO,ERR_BadParam,SUB_DocField,
 
1730
                                        "DocField value (%d) out of range ",field);
 
1731
                return FALSE;
 
1732
        }
 
1733
        return TRUE;
 
1734
}
 
1735
 
 
1736
static FILE * CdEntrez_FileOpen (CdEntrezDir dirnum, int doctype, int divnum, 
 
1737
                        int ftype, const char *fname, const char *fmode)
 
1738
{
 
1739
        static int cdnum[CDVOL_MAX];
 
1740
        FILE *fd = NULL;
 
1741
        CdMap *map;
 
1742
        int cdcnt;
 
1743
        char fpath[256];
 
1744
        
 
1745
        ASSERT(dirnum >= CdDir_FIRST && dirnum <= CdDir_LAST);
 
1746
        ASSERT(doctype < _type_ct);
 
1747
        ASSERT(divnum <= _div_ct);
 
1748
 
 
1749
        fpath[0] = '\0';
 
1750
        cdcnt = 0;
 
1751
        map = &_map[dirnum];
 
1752
        cdcnt = CdMap_GetSpecs(map,cdnum,fpath);
 
1753
        if ((map = CdMap_GetChild(map,doctype)) != NULL)
 
1754
        {
 
1755
                cdcnt = CdMap_GetSpecs(map,cdnum,fpath);
 
1756
                if ((map = CdMap_GetChild(map,divnum)) != NULL)
 
1757
                {
 
1758
                        cdcnt = CdMap_GetSpecs(map,cdnum,fpath);
 
1759
                }
 
1760
        }
 
1761
        
 
1762
        if (fpath[0] != '\0' && fpath[0] != '#')
 
1763
        {
 
1764
                FileBuildPath(fpath,NULL,(char*)fname);
 
1765
                fd = FileOpen(fpath,fmode);
 
1766
        }
 
1767
        else if (cdcnt > 0)
 
1768
        {
 
1769
                CdVolume *cdvol;
 
1770
                CdDevice *cddev;
 
1771
                int n;
 
1772
                
 
1773
                if (cdcnt == 1)
 
1774
                {
 
1775
                        n = cdnum[0];
 
1776
                        ASSERT(VOLNUM_IS_VALID(n));
 
1777
                        cdvol = &_cdvol[n-1];
 
1778
                }
 
1779
                else
 
1780
                {
 
1781
                        /* If the information sought exists on more than one volume, select
 
1782
                                a mounted volume if possible.  Favor most-recently-used volumes. */
 
1783
                        int i;
 
1784
                        CdVolume *cdv;
 
1785
                        
 
1786
                        for (i=0, cdvol=NULL; i<cdcnt; ++i)
 
1787
                        {
 
1788
                                n = cdnum[i];
 
1789
                                ASSERT(VOLNUM_IS_VALID(n));
 
1790
                                cdv = & _cdvol[n-1];
 
1791
                                if (cdvol == NULL)
 
1792
                                        cdvol = cdv;
 
1793
                                else if (!CdVolume_IsMounted(cdvol) && CdVolume_IsMounted(cdv))
 
1794
                                        cdvol = cdv;
 
1795
                                else if (cdv->timestamp > cdvol->timestamp)
 
1796
                                        cdvol = cdv;
 
1797
                        }
 
1798
                }
 
1799
                ASSERT(cdvol != NULL);
 
1800
                                        
 
1801
                if ((cddev=cdvol->device) ==NULL)
 
1802
                {
 
1803
                        if ((cddev=CdVolume_Mount(cdvol,NULL,TRUE)) ==NULL)
 
1804
                        {
 
1805
                                VERBOSE("   * CdVolume_Mount failed\n");
 
1806
                                return NULL;
 
1807
                        }
 
1808
                }
 
1809
                fd = CdDevice_FileOpen(cddev,_dir[dirnum].dir,fname,fmode);     
 
1810
        }
 
1811
        
 
1812
        if (fd != NULL)
 
1813
        {
 
1814
                if (ftype == 0)
 
1815
                        return fd;
 
1816
                else
 
1817
                {
 
1818
                        unsigned short m[4];
 
1819
                        
 
1820
                        if (FileReadSwapShort(m,4,fd) != 4)
 
1821
                        {
 
1822
                                FileClose(fd);
 
1823
                                FileCorrupt(fname);
 
1824
                                return NULL;
 
1825
                        }
 
1826
                        fseek(fd,0,SEEK_SET);
 
1827
                        /**VERBOSE("HEADER %s:  %d %d %d %d\n",fname,m[0],m[1],m[2],m[3]);**/
 
1828
                        
 
1829
                        if (m[0] && m[0] != _finfo[ftype].magic)
 
1830
                                FileCorrupt(fname);
 
1831
                        else if (m[1] && m[1] > _finfo[ftype].format)
 
1832
                                FileNotRecognized(fname);
 
1833
                        else if (m[2] && m[2] != (unsigned short) _cdinfo->version)
 
1834
                                FileOutOfDate(fname);
 
1835
                        else if (m[3] && m[3] != (unsigned short) _cdinfo->issue && ftype != HCA)
 
1836
                                FileOutOfDate(fname);
 
1837
                        else
 
1838
                                return fd;
 
1839
                }
 
1840
        }
 
1841
        FileClose(fd);
 
1842
        return NULL;
 
1843
}
 
1844
 
 
1845
 
 
1846
static void CdEntrez_FileClose (CdEntrezDir dirnum, int doctype, FILE *fd)
 
1847
{
 
1848
 
 
1849
        /************ NOT IMPLEMENTED *************/
 
1850
        
 
1851
    
 
1852
    /*  This function will close some files and leave others
 
1853
        open depending on whether the device on which they 
 
1854
        reside is ejectable or not.   Right now it just closes
 
1855
        everything. */
 
1856
    
 
1857
    
 
1858
        FileClose(fd);
 
1859
}
 
1860
 
 
1861
 
 
1862
 
 
1863
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
1864
/* UidIndex Functions.        Schuler 06-13-94                                 */
 
1865
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
1866
#define UIDX_KEY(a,b)   (((unsigned long)(a) << 24) | (b))
 
1867
 
 
1868
 
 
1869
static UidIndex* UidIndex_Construct (UidIndex *uidx, DocType type, EntrezTypeData *info)
 
1870
{
 
1871
        if (uidx != NULL)
 
1872
        {
 
1873
                uidx->type = type;
 
1874
                uidx->uid_ct = info->num_uids;
 
1875
                uidx->uid_min = info->minuid;
 
1876
                uidx->uid_max = info->maxuid;
 
1877
                uidx->pages = info->num_bucket;
 
1878
                uidx->index = NULL;
 
1879
        }
 
1880
        return uidx;
 
1881
}
 
1882
 
 
1883
 
 
1884
static UidIndex* UidIndex_Destruct (UidIndex *uidx)
 
1885
{
 
1886
        if (uidx != NULL)
 
1887
                MemFree((void*)uidx->index);
 
1888
 
 
1889
        return uidx;
 
1890
}
 
1891
 
 
1892
 
 
1893
static int UidIndex_ReadPageMap (UidIndex *uidx)
 
1894
{
 
1895
        char fname[32];
 
1896
        long *index;
 
1897
        FILE *fd;
 
1898
        
 
1899
        ASSERT(uidx != NULL);
 
1900
        ASSERT(TYPE_IS_VALID(uidx->type));
 
1901
        ASSERT(uidx->index == NULL);
 
1902
        
 
1903
        if ((index = (long*) MemNew(sizeof(long) * uidx->pages)) ==NULL)
 
1904
                return FALSE;
 
1905
 
 
1906
        sprintf(fname,"%s.oix",TYPTAG(uidx->type));
 
1907
        if ((fd = CdEntrez_FileOpen(CdDir_idx,uidx->type,0,OIX,fname,"rb")) ==NULL)
 
1908
                return FALSE;
 
1909
        fseek(fd,8,SEEK_SET); /* to skip over header */
 
1910
        if (FileReadSwapLong((unsigned long*)index,uidx->pages,fd) != uidx->pages)
 
1911
                return CatastrophicFailure(1);
 
1912
        FileClose(fd);
 
1913
        uidx->index = index;
 
1914
        return TRUE;
 
1915
}
 
1916
 
 
1917
 
 
1918
static long* UidIndex_ReadPage (UidIndex *uidx, int pagenum)
 
1919
{
 
1920
        int recs, vals;
 
1921
        size_t bytes;
 
1922
        char fname[32];
 
1923
        FILE *fd;
 
1924
        long *page;
 
1925
        
 
1926
        ASSERT(uidx != NULL);
 
1927
        ASSERT(pagenum < uidx->pages && pagenum >= 0);
 
1928
        
 
1929
        /*----- open file, check magic value, version, etc -----*/
 
1930
        sprintf(fname,"%s.ofs",TYPTAG(uidx->type));
 
1931
        if ((fd = CdEntrez_FileOpen(CdDir_idx,uidx->type,0,OFS,fname,"rb")) ==NULL)
 
1932
                return NULL;
 
1933
        fseek(fd,8,SEEK_SET);  /* to skip over header */
 
1934
        
 
1935
        /*----- seek to the right position, allocate memory, read the page -----*/
 
1936
        if (fseek(fd,(long)pagenum*_idx_page_size,SEEK_CUR) != 0)
 
1937
                return (long*)CatastrophicFailure(1);
 
1938
        recs = (pagenum < uidx->pages-1) ? _idx_page_slots :
 
1939
                                (int)(uidx->uid_ct - (long)pagenum*_idx_page_slots);
 
1940
        vals = 5 * recs;
 
1941
        bytes = vals * sizeof(long);
 
1942
        if ((page = MemGet(bytes,MGET_ERRPOST)) ==NULL)
 
1943
                return NULL;
 
1944
        if (FileReadSwapLong((unsigned long*)page,vals,fd) != vals)
 
1945
                return (long*)CatastrophicFailure(1);
 
1946
        FileClose(fd);
 
1947
        return page;
 
1948
 
1949
 
 
1950
 
 
1951
static int UidIndex_Lookup (UidIndex *uidx, DocUid uid, UidIndexRec *rec)
 
1952
{
 
1953
        int lo, hi, mid;
 
1954
        int page_num, page_slots;
 
1955
        unsigned long cache_key;
 
1956
        long *page, *p;
 
1957
        Boolean missed =FALSE;
 
1958
        
 
1959
        ASSERT(rec != NULL);
 
1960
        memset((void*)rec,0,sizeof(UidIndexRec));
 
1961
        
 
1962
        if (uid < uidx->uid_min || uid > uidx->uid_max)
 
1963
                return FALSE;
 
1964
        
 
1965
        /*----- load the index, if necessary -----*/
 
1966
        if (uidx->index == NULL)
 
1967
        {
 
1968
                if (!UidIndex_ReadPageMap(uidx))
 
1969
                        return FALSE;
 
1970
        }
 
1971
 
 
1972
        /*----- binary search the index -----*/
 
1973
        lo = 0;
 
1974
        hi = (int)uidx->pages -1;
 
1975
        while (lo <= hi)
 
1976
        {
 
1977
                mid = (lo + hi) /2;
 
1978
                p = uidx->index + mid;
 
1979
                if (*p == uid)
 
1980
                        break;
 
1981
                if (uid < *p)
 
1982
                        hi = mid-1;
 
1983
                else
 
1984
                        lo = mid+1;
 
1985
        }
 
1986
        page_num = (uid < *p && mid >0) ? mid-1 : mid;
 
1987
        page_slots = (page_num < uidx->pages -1) ? _idx_page_slots :
 
1988
                        (int)(uidx->uid_ct - (long)page_num * _idx_page_slots);
 
1989
 
 
1990
        
 
1991
        /*----- check to see if desired page is in cache -----*/
 
1992
        cache_key = UIDX_KEY(uidx->type,page_num);
 
1993
        page = (long*) Cache_Lock(_idx_cache,cache_key);
 
1994
        if (page == NULL)
 
1995
        {
 
1996
                missed = TRUE;
 
1997
                if ((page = UidIndex_ReadPage(uidx,page_num)) ==NULL)
 
1998
                        return FALSE;
 
1999
                if (!Cache_Insert(_idx_cache,cache_key,page))
 
2000
                        return CatastrophicFailure(1);
 
2001
        }
 
2002
        
 
2003
        
 
2004
        /*----- Binary search the page using the uid as a key -----*/
 
2005
        lo = 0;
 
2006
        hi = page_slots -1;
 
2007
        
 
2008
        while (lo <= hi)
 
2009
        {
 
2010
                mid = (lo + hi) /2;
 
2011
                p = page + mid*5;
 
2012
                if (*p == uid)
 
2013
                {
 
2014
                        rec->uid = *p++;
 
2015
                        rec->divnum = (short) ((*p & 0x0FFF0000) >>16);
 
2016
                        rec->filnum = (short) (*p++ & 0x0000FFFF);
 
2017
                        rec->hca_offset = *p++; 
 
2018
                        rec->sum_offset = *p++; 
 
2019
                        rec->lnk_offset = *p;   
 
2020
                        break;
 
2021
                }
 
2022
                if (uid < *p)
 
2023
                        hi = mid-1;
 
2024
                else
 
2025
                        lo = mid+1;
 
2026
        }
 
2027
        if (!missed)
 
2028
                Cache_Unlock(_idx_cache,cache_key);
 
2029
        return (rec->uid != 0);
 
2030
}
 
2031
 
 
2032
 
 
2033
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
2034
/* TrmIndex Functions.        Schuler 07-02-94                                 */
 
2035
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
2036
#define TIDX_KEY(a,b,c)   (((unsigned long)(a) << 24) | ((unsigned long)(b) << 16) | (c))
 
2037
#define T_HEAD_SIZE  16
 
2038
 
 
2039
 
 
2040
static TrmIndex* TrmIndex_Construct (TrmIndex *tidx, int type, int fld, 
 
2041
                                const char *tag, EntrezFieldData *info)
 
2042
{
 
2043
        if (tidx != NULL)
 
2044
        {
 
2045
                tidx->type = type;
 
2046
                tidx->fld = fld;
 
2047
                strcpy(tidx->tag,tag);
 
2048
                tidx->trm_ct = info->num_terms;
 
2049
                tidx->page_ct = info->num_bucket;
 
2050
        }
 
2051
        return tidx;
 
2052
}
 
2053
 
 
2054
 
 
2055
static TrmIndex* TrmIndex_Destruct (TrmIndex *tidx)
 
2056
{
 
2057
        if (tidx != NULL)
 
2058
        {
 
2059
                char **p = tidx->index;
 
2060
                if (p != NULL)
 
2061
                {
 
2062
                        int i;
 
2063
                        for (i=0; i<tidx->page_ct; ++i, ++p)
 
2064
                                MemFree((void*)*p);
 
2065
                        MemFree((void*)tidx->index);
 
2066
                }
 
2067
                tidx = NULL;
 
2068
        }
 
2069
        return tidx;
 
2070
}
 
2071
 
 
2072
 
 
2073
static int TrmIndex_ReadPageMap (TrmIndex *tidx)
 
2074
{
 
2075
        char fname[32];
 
2076
        unsigned short m[8];
 
2077
        char **p;
 
2078
        FILE *fd;
 
2079
        int i;
 
2080
        
 
2081
        ASSERT(tidx != NULL);
 
2082
        ASSERT(tidx->index == NULL);
 
2083
        
 
2084
        sprintf(fname,"%s%s.tix",TYPTAG(tidx->type),FLDTAG(tidx->fld));
 
2085
        if ((fd = CdEntrez_FileOpen(CdDir_trm,tidx->type,0,TIX,fname,"rb")) ==NULL)
 
2086
                return FALSE;
 
2087
        FileReadSwapShort(m,8,fd);
 
2088
        tidx->page_size = (m[4]==0) ? _trm_page_size : m[4];
 
2089
        if ((tidx->index = (char**) MemNew(sizeof(char*) * tidx->page_ct)) !=NULL)
 
2090
        {
 
2091
                for (i=0, p=tidx->index; i<tidx->page_ct; ++i, ++p)
 
2092
                {
 
2093
                        if ((*p = FileReadStr(fd,1)) ==NULL)
 
2094
                        {
 
2095
                                TrmIndex_Destruct(tidx);
 
2096
                                break;
 
2097
                        }
 
2098
                }
 
2099
        }
 
2100
        FileClose(fd);
 
2101
        return (tidx->index != NULL);
 
2102
}
 
2103
 
 
2104
 
 
2105
static Byte* TrmIndex_ReadPage (TrmIndex *tidx, int pagenum)
 
2106
{
 
2107
        Byte *page = NULL;
 
2108
        char fname[32];
 
2109
        long offset;
 
2110
        FILE *fd;
 
2111
        
 
2112
        ASSERT(tidx != NULL);
 
2113
        ASSERT(pagenum < tidx->page_ct);
 
2114
 
 
2115
        sprintf(fname,"%s%s.trm",TYPTAG(tidx->type),FLDTAG(tidx->fld));
 
2116
        if ((fd = CdEntrez_FileOpen(CdDir_trm,tidx->type,0,TRM,fname,"rb")) ==NULL)
 
2117
                return FALSE;
 
2118
        offset = (long)T_HEAD_SIZE + (long)tidx->page_size * pagenum;
 
2119
        VERIFY(fseek(fd,offset,SEEK_SET) ==0);
 
2120
                
 
2121
        page = MemGet(tidx->page_size+1, MGET_ERRPOST);
 
2122
        if (page != NULL)
 
2123
        {
 
2124
                size_t n = fread((void*)page,1,tidx->page_size,fd);  /*check for error*/
 
2125
                *(page+n) = '\0';   /* sentinel */
 
2126
                if (*page != 0xAB)
 
2127
                        FileCorrupt(fname);
 
2128
        }
 
2129
        FileClose(fd);
 
2130
        return page;
 
2131
}
 
2132
 
 
2133
 
 
2134
static int TrmIndex_Lookup (TrmIndex *tidx, const char *stem)
 
2135
{
 
2136
        int lo, hi, mid, len, d;
 
2137
        char *term;
 
2138
        
 
2139
        
 
2140
        ASSERT(stem != NULL);
 
2141
        len = strlen(stem);
 
2142
 
 
2143
        /*----- load the index, if necessary -----*/
 
2144
        if (tidx->index == NULL)
 
2145
        {
 
2146
                if (!TrmIndex_ReadPageMap(tidx))
 
2147
                        return -1;
 
2148
        }
 
2149
 
 
2150
        /*----- binary search the index -----*/
 
2151
        lo = 0;
 
2152
        hi = (int)tidx->page_ct -1;
 
2153
        while (lo <= hi)
 
2154
        {
 
2155
                mid = (lo + hi) /2;
 
2156
                term = *(tidx->index + mid);
 
2157
                d = trmncmp(stem,term,len);
 
2158
                if (d == 0)
 
2159
                        break;
 
2160
                if (d < 0)
 
2161
                        hi = mid-1;
 
2162
                else
 
2163
                        lo = mid+1;
 
2164
        }
 
2165
 
 
2166
        for ( ; d <= 0 && mid >0; --mid)
 
2167
        {
 
2168
                if (d==0 && len == (int)strlen(term))
 
2169
                        break;
 
2170
                term = *(tidx->index + (mid-1));
 
2171
                d = trmncmp(stem,term,len);
 
2172
        }
 
2173
        return mid;
 
2174
}
 
2175
 
 
2176
 
 
2177
static CdTerm* TrmIndex_GetCdTerm (TrmIndex *tidx, const char *term)
 
2178
{
 
2179
        CdTerm *trm = NULL;
 
2180
        int page_num;
 
2181
        
 
2182
        ASSERT(tidx != NULL);
 
2183
        
 
2184
        if ((page_num = TrmIndex_Lookup(tidx,term)) >=0)
 
2185
        {
 
2186
                unsigned long cache_key = TIDX_KEY(tidx->type,tidx->fld,page_num);
 
2187
                Byte *page = Cache_Lock(_trm_cache,cache_key);
 
2188
                int missed;
 
2189
                if (page != NULL)
 
2190
                        missed = FALSE;
 
2191
                else
 
2192
                {
 
2193
                        missed = TRUE;
 
2194
                        page = TrmIndex_ReadPage(tidx,page_num);
 
2195
                }
 
2196
                if (page != NULL)
 
2197
                {
 
2198
                        Byte *ptr = page +1;
 
2199
                        int flags, len, d;
 
2200
                        
 
2201
                        while ((flags = *ptr++) != 0)
 
2202
                        {
 
2203
                                len = *ptr++;
 
2204
                                d = trmcmp(term,(char*)ptr);
 
2205
                                if (d == 0)
 
2206
                                {
 
2207
                                        ptr -= 2;
 
2208
                                        trm = getcdtrm(tidx,page_num,&ptr);
 
2209
                                        break; 
 
2210
                                }
 
2211
                                ptr += len;
 
2212
                                if (flags & 0x01)  ptr +=4;
 
2213
                                if (flags & 0x02)  ptr +=4;
 
2214
                                ptr += 4;
 
2215
                        }
 
2216
                        
 
2217
                        if (missed)
 
2218
                                Cache_Insert(_trm_cache,cache_key,page);
 
2219
                        else
 
2220
                                Cache_Unlock(_trm_cache,cache_key);
 
2221
                }
 
2222
        }
 
2223
        return trm;
 
2224
}
 
2225
 
 
2226
 
 
2227
static int TrmIndex_ScanPages (TrmIndex *tidx, int start, int count, CdTermProc proc)
 
2228
{
 
2229
        int page_num = start;
 
2230
        int cancel = FALSE;
 
2231
        int ct;
 
2232
        
 
2233
        /*----- load the index, if necessary -----*/
 
2234
        if (tidx->index == NULL)
 
2235
        {
 
2236
                if (!TrmIndex_ReadPageMap(tidx))
 
2237
                        return 0;
 
2238
        }
 
2239
 
 
2240
        for (ct=0; ct<count && page_num<tidx->page_ct && !cancel; ++ct, ++page_num)
 
2241
        {
 
2242
                unsigned long cache_key = TIDX_KEY(tidx->type,tidx->fld,page_num);
 
2243
                Byte *page = Cache_Lock(_trm_cache,cache_key);
 
2244
                int missed;
 
2245
                if (page != NULL)
 
2246
                        missed = FALSE;
 
2247
                else
 
2248
                {
 
2249
                        missed = TRUE;
 
2250
                        page = TrmIndex_ReadPage(tidx,page_num);
 
2251
                }
 
2252
                if (page != NULL)
 
2253
                {
 
2254
                        Byte *ptr = page +1;
 
2255
                        CdTerm *trm;
 
2256
                        while ((trm = getcdtrm(tidx,page_num,&ptr)) != NULL)
 
2257
                        {
 
2258
                                if (!(*proc)(trm))
 
2259
                                {
 
2260
                                        cancel = TRUE;
 
2261
                                        break;
 
2262
                                }
 
2263
                        }
 
2264
                }
 
2265
                if (missed)
 
2266
                        Cache_Insert(_trm_cache,cache_key,page);
 
2267
                else
 
2268
                        Cache_Unlock(_trm_cache,cache_key);
 
2269
        }
 
2270
        return ct;
 
2271
}
 
2272
 
 
2273
 
 
2274
static FILE * TrmIndex_PostingsFileOpen (TrmIndex *tidx)
 
2275
{
 
2276
        char fname[32];
 
2277
        FILE *fd;
 
2278
        
 
2279
        ASSERT(tidx != NULL);
 
2280
 
 
2281
        sprintf(fname,"%s%s.pst",TYPTAG(tidx->type),FLDTAG(tidx->fld));
 
2282
        if ((fd = CdEntrez_FileOpen(CdDir_trm,tidx->type,0,PST,fname,"rb")) ==NULL)
 
2283
                return NULL;
 
2284
        return fd;
 
2285
}
 
2286
 
 
2287
 
 
2288
#define DECODE_LONG(ptr,val)    { int i;    \
 
2289
                for (i=0, val = 0; i<4; ++i)        \
 
2290
                { val <<= 8; val |= (unsigned long)*ptr++;      } } 
 
2291
 
 
2292
 
 
2293
static CdTerm* getcdtrm (TrmIndex *tidx, int pagenum, Byte **pptr)
 
2294
{
 
2295
        CdTerm *trm;
 
2296
        Byte *ptr = *pptr;
 
2297
        int flags = *ptr++;
 
2298
        if (flags != 0)
 
2299
        {
 
2300
                int len = *ptr++;
 
2301
                char *str = MemGet(1+len,MGET_ERRPOST);
 
2302
                if (str!=NULL && (trm = MemNew(sizeof(CdTerm))) != NULL)
 
2303
                {
 
2304
                        unsigned long val;
 
2305
                        int i;
 
2306
                        ASSERT((flags & 0xF0) ==0xE0);
 
2307
                        trm->type = tidx->type;
 
2308
                        trm->field = tidx->fld;
 
2309
                        trm->page = pagenum;
 
2310
                        trm->term = str;
 
2311
                        for (i=0; i<len; ++i)
 
2312
                                *str++ = (char) *ptr++;
 
2313
                        *str = '\0';
 
2314
                                        
 
2315
                        if (flags & 0x01)
 
2316
                        {
 
2317
                                DECODE_LONG(ptr,val);
 
2318
                                trm->total_count = (long)val;
 
2319
                        }
 
2320
                        if (flags & 0x02)
 
2321
                        {
 
2322
                                DECODE_LONG(ptr,val);
 
2323
                                trm->special_count = (long)val;
 
2324
                        }
 
2325
                        DECODE_LONG(ptr,val);
 
2326
                        trm->offset = (long)val;
 
2327
                        *pptr = ptr;
 
2328
                        return trm;
 
2329
                }
 
2330
        }
 
2331
        return NULL;
 
2332
}
 
2333
 
 
2334
static int trmcmp (const char *term1, const char *term2)
 
2335
{
 
2336
        const char *p1 = term1;
 
2337
        const char *p2 = term2;
 
2338
        int c1 =0, c2 =0;
 
2339
        
 
2340
        while (*p1 && *p2)
 
2341
        {
 
2342
                c1 = *p1++;
 
2343
                if (isalpha(c1))  c1 = tolower(c1);
 
2344
                c2 = *p2++;
 
2345
                if (isalpha(c2))  c2 = tolower(c2);
 
2346
                if (c1 != c2)
 
2347
                {
 
2348
                        if (c1 == '/')
 
2349
                                return (c2 == '/') ? 0 : -1;
 
2350
                        else if (c2 == '/')
 
2351
                                return 1;
 
2352
                        return (c1 - c2);
 
2353
                }
 
2354
        }
 
2355
        return ((int)*p1 - (int)*p2);
 
2356
}
 
2357
 
 
2358
static int trmncmp (const char *term1, const char *term2, int n)
 
2359
{
 
2360
        const char *p1 = term1;
 
2361
        const char *p2 = term2;
 
2362
        int i, c1, c2;
 
2363
        
 
2364
        for (i=0; i<n; ++i)
 
2365
        {
 
2366
                c1 = *p1++;
 
2367
                if (isalpha(c1))  c1=tolower(c1);
 
2368
                c2 = *p2++;
 
2369
                if (isalpha(c2))  c2=tolower(c2);
 
2370
                if (c1==0 || c2==0 || c1!=c2)
 
2371
                        break;
 
2372
        }
 
2373
        if (i==n) 
 
2374
                return 0;
 
2375
        if (c1 == '/')
 
2376
                return (c2 == '/') ? 0 : -1;
 
2377
        else if (c2 == '/')
 
2378
                return 1;
 
2379
        return (c1 - c2);
 
2380
}
 
2381
 
 
2382
 
 
2383
 
 
2384
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
2385
/* CdVolume Functions.        Schuler 05-21-94                                 */
 
2386
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
2387
 
 
2388
static CdVolume* CdVolume_Construct (CdVolume *cdvol, int number)
 
2389
{
 
2390
        if (cdvol != NULL)
 
2391
        {
 
2392
                char volname[16];
 
2393
                int i;
 
2394
                CdDevice *cddev;
 
2395
                
 
2396
                sprintf(volname,"entrez%d",number);
 
2397
                cdvol->volume_name = StrSave(volname);
 
2398
                cdvol->volume_num = number;
 
2399
                for (i=0, cddev=_cddev; i<_device_ct; ++i, ++cddev)
 
2400
                {
 
2401
                        if (cddev->bound_cd == number)
 
2402
                        {
 
2403
                                CdVolume_Mount(cdvol,cddev,TRUE);
 
2404
                                break;
 
2405
                        }
 
2406
                        if (cddev->hint == number)
 
2407
                        {
 
2408
                                cddev->hint = 0;
 
2409
                                CdVolume_Mount(cdvol,cddev,FALSE);
 
2410
                                break;
 
2411
                        }
 
2412
                }
 
2413
        }
 
2414
        return cdvol;
 
2415
}
 
2416
 
 
2417
 
 
2418
static CdVolume* CdVolume_Destruct (CdVolume *cdvol)
 
2419
{
 
2420
        if (cdvol != NULL)
 
2421
        {
 
2422
                MemFree((void*)cdvol->volume_name);
 
2423
                cdvol->volume_name = NULL;
 
2424
        }
 
2425
 
 
2426
        return cdvol;
 
2427
}
 
2428
 
 
2429
 
 
2430
static CdDevice* GetLruDevice (void)
 
2431
{
 
2432
        CdDevice *dev_lru =NULL;
 
2433
        time_t time_lru;
 
2434
        CdDevice *dev;
 
2435
        int i;
 
2436
        
 
2437
        for (i=0, dev=_cddev; i<_device_ct; ++i, ++dev)
 
2438
        {
 
2439
                if (dev->is_ejectable)
 
2440
                {
 
2441
                        if (dev->volume == NULL)
 
2442
                        {
 
2443
                                dev_lru = dev;
 
2444
                                break;
 
2445
                        }
 
2446
                        if (dev_lru == NULL || dev->timestamp < time_lru)
 
2447
                        {
 
2448
                                dev_lru = dev;
 
2449
                                time_lru = dev->timestamp;
 
2450
                        }
 
2451
                }
 
2452
        }
 
2453
        if (dev_lru != NULL && dev_lru->volume != NULL)
 
2454
        {
 
2455
                CdVolume *vol_to_eject = dev_lru->volume;
 
2456
                CdVolume_Unmount(dev_lru->volume);
 
2457
                if (dev_lru->is_ejectable)
 
2458
                {
 
2459
                        if (!(*_hookEject)(vol_to_eject->volume_name,&dev_lru->inf))
 
2460
                                ErrPostEx(SEV_INFO,0,0,"Unable to eject %s",vol_to_eject->volume_name);
 
2461
        }
 
2462
        }
 
2463
        return dev_lru;
 
2464
}
 
2465
 
 
2466
 
 
2467
static CdDevice* CdVolume_Mount (CdVolume *cdvol, CdDevice *cddev, int verify)
 
2468
{
 
2469
        ASSERT(cdvol != NULL);
 
2470
        
 
2471
        if (cddev == NULL)
 
2472
        {
 
2473
                cddev = GetLruDevice();
 
2474
                ASSERT(cddev != NULL);
 
2475
                ASSERT(cddev->volume == NULL);
 
2476
        }
 
2477
 
 
2478
        if (!cddev->is_ejectable)
 
2479
        {
 
2480
                if (cdvol->device != NULL)
 
2481
                {
 
2482
                        ErrPostEx(SEV_INFO,0,0,"CdVolume_Mount;  Device busy");
 
2483
                        return NULL;
 
2484
                }
 
2485
                if (!cddev->is_inited)
 
2486
                {
 
2487
                        if (!CdDevice_Init(cddev))  return NULL;
 
2488
                }
 
2489
                cdvol->device = cddev;
 
2490
                cddev->volume = cdvol;
 
2491
        }
 
2492
        else
 
2493
        {       
 
2494
                while (cdvol->device == NULL)
 
2495
                {
 
2496
                        if (verify)
 
2497
                        {
 
2498
                                if (! (*_hookInsert)(cdvol->volume_name,&cddev->inf))
 
2499
                                        return NULL;
 
2500
                        }
 
2501
        
 
2502
                        if (!cddev->is_inited)
 
2503
                        {
 
2504
                                if (CdDevice_Init(cddev) && cddev->hint == cdvol->volume_num)
 
2505
                                {
 
2506
                                        cdvol->device = cddev;
 
2507
                                        cddev->volume = cdvol;
 
2508
                                }
 
2509
                        }
 
2510
                        else if (verify)
 
2511
                        {
 
2512
                                char fpath[256];
 
2513
                                CdRomInfo  info;
 
2514
                                if (cddev->inf.root == NULL)
 
2515
                                        fpath[0] = '\0';
 
2516
                                else
 
2517
                                        strcpy(fpath,cddev->inf.root);
 
2518
                                if (cddev->ins_volname)
 
2519
                                        FileBuildPath(fpath,cdvol->volume_name,NULL);
 
2520
                                if (!CdTestPath(fpath,&info))
 
2521
                                {
 
2522
                                        ErrLogPrintf("CdTestPath [%s] FAILED\n",fpath);
 
2523
                                        ErrPostEx(SEV_INFO,0,0,"Unable to get CD-ROM volume info");
 
2524
                                }
 
2525
                                else
 
2526
                                {
 
2527
                                        /*ErrLogPrintf("CdTestPath [%s] OK; rel %d.%d; cd %d of %d\n", fpath,
 
2528
                                                                info.rel_major, info.rel_minor, info.cd_num, info.cd_count);*/
 
2529
                                        cddev->upper_case = info.upper_case;
 
2530
                                        cddev->semicolon_one = info.semicolon_one;
 
2531
                                        if (info.rel_major != _rel_major || info.rel_minor != _rel_minor)
 
2532
                                                ErrPostEx(SEV_INFO,0,0,"The inserted CD-ROM is from the wrong release");
 
2533
                                        else if (cdvol->volume_num == info.cd_num)
 
2534
                                        {
 
2535
                                                cdvol->device = cddev;
 
2536
                                                cddev->volume = cdvol;
 
2537
                                        }
 
2538
                                }
 
2539
                                if (cdvol->device == NULL && cddev->is_ejectable)
 
2540
                                {
 
2541
                                        char volume_to_eject[32];
 
2542
                                        volume_to_eject[0] = '\0';
 
2543
                                        if (cddev->ins_volname)
 
2544
                                        {
 
2545
                                                int ct, freecds[CDVOL_MAX];
 
2546
                                                ct = FindFloatingEntrezVolumes(freecds);
 
2547
                                                if (ct > 0)
 
2548
                                                        sprintf(volume_to_eject,"entrez%d",freecds[0]);
 
2549
                                        }
 
2550
                                        else if (cdvol->volume_name != NULL)
 
2551
                                                strcpy(volume_to_eject,cdvol->volume_name);
 
2552
 
 
2553
                                        if (!(*_hookEject)(volume_to_eject,&cddev->inf))
 
2554
                                                ErrPostEx(SEV_INFO,0,0,"Unable to eject %s",cdvol->volume_name);
 
2555
                        }
 
2556
                        }
 
2557
                        else
 
2558
                        {
 
2559
                                cdvol->device = cddev;
 
2560
                                cddev->volume = cdvol;
 
2561
                        }
 
2562
                }
 
2563
        }
 
2564
        CdDevice_Touch(cdvol->device);
 
2565
        return cdvol->device;
 
2566
}
 
2567
 
 
2568
 
 
2569
static int  CdVolume_Unmount (CdVolume *cdvol)
 
2570
{
 
2571
        CdDevice *cddev;
 
2572
        
 
2573
        ASSERT(cdvol != NULL);
 
2574
 
 
2575
        cddev=cdvol->device;
 
2576
        if (cddev != NULL && cddev->is_ejectable)
 
2577
        {
 
2578
                cddev->volume = NULL;
 
2579
                cdvol->device = NULL;
 
2580
                CdDevice_Touch(cddev);
 
2581
                return TRUE;
 
2582
        }
 
2583
        return FALSE;
 
2584
}
 
2585
 
 
2586
 
 
2587
static int CdVolume_IsMounted (CdVolume *cdvol)
 
2588
{
 
2589
        ASSERT(cdvol != NULL);
 
2590
        return cdvol->device != NULL;
 
2591
}
 
2592
 
 
2593
 
 
2594
static int FindFloatingEntrezVolumes (int *outlist)
 
2595
{
 
2596
        int i, ct=0;
 
2597
        char testpath[16];
 
2598
        CdRomInfo info;
 
2599
 
 
2600
        for (i=0; i<_volume_ct; ++i)
 
2601
        {
 
2602
                if (_cdvol[i].device == NULL)
 
2603
                {
 
2604
                        sprintf(testpath,"entrez%d",i+1);
 
2605
                        if (CdTestPath(testpath,&info))
 
2606
                        {
 
2607
                                VERBOSE("FindFloatingEntrezVolumes: Entrez%d found\n",info.cd_num);
 
2608
                                outlist[ct++] = info.cd_num;
 
2609
                        }
 
2610
                }
 
2611
        }
 
2612
        return ct;
 
2613
}
 
2614
 
 
2615
 
 
2616
 
 
2617
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
2618
/* CdDevice Functions         Schuler 05-21-94                                 */
 
2619
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
2620
 
 
2621
static CdDevice* CdDevice_Construct (CdDevice *cddev, int number)
 
2622
{
 
2623
        if (cddev != NULL)
 
2624
        {
 
2625
                char section[32];
 
2626
                char buffer[64];
 
2627
        
 
2628
                sprintf(section,"CdEntrez.Device.%d",number);
 
2629
                cddev->inf.root = GetAppParamStr(_rcfile,section,"Root",NULL);
 
2630
                cddev->inf.formal_name = GetAppParamStr(_rcfile,section,"Formal_Name",NULL);
 
2631
                cddev->inf.device_name = GetAppParamStr(_rcfile,section,"Device_Name",NULL);
 
2632
                cddev->inf.raw_device_name = GetAppParamStr(_rcfile,section,"Raw_Device_Name",NULL);
 
2633
                cddev->inf.mount_point = GetAppParamStr(_rcfile,section,"Mount_Point",NULL);
 
2634
                cddev->inf.mount_cmd = GetAppParamStr(_rcfile,section,"Mount_Cmd",NULL);
 
2635
                cddev->is_ejectable = GetAppParamBoolean(_rcfile,section,"Ejectable",TRUE);
 
2636
                cddev->ins_volname = GetAppParamBoolean(_rcfile,section,"Insert_Volname",FALSE);
 
2637
 
 
2638
                if (GetAppParam(_rcfile,section,"Bind",NULL,buffer,sizeof buffer))
 
2639
                {
 
2640
                        if (StrNICmp(buffer,"entrez",6) ==0)
 
2641
                                cddev->bound_cd = atoi(buffer+6);
 
2642
                }
 
2643
        }
 
2644
        return cddev;
 
2645
}
 
2646
 
 
2647
static CdDevice* CdDevice_Destruct (CdDevice *cddev)
 
2648
{
 
2649
        if (cddev != NULL)
 
2650
        {
 
2651
                MemFree((void*)cddev->inf.root);
 
2652
                MemFree((void*)cddev->inf.formal_name);
 
2653
                MemFree((void*)cddev->inf.device_name);
 
2654
                MemFree((void*)cddev->inf.raw_device_name);
 
2655
                MemFree((void*)cddev->inf.mount_point);
 
2656
                MemFree((void*)cddev->inf.mount_cmd);
 
2657
        }
 
2658
        return cddev;
 
2659
}
 
2660
 
 
2661
 
 
2662
static int CdDevice_FileBuildPath (CdDevice *cddev, char *fpath, const char *fdir, const char *fname)
 
2663
{
 
2664
        ASSERT(cddev != NULL);
 
2665
        ASSERT(fpath != NULL);
 
2666
        
 
2667
        *fpath = '\0';
 
2668
        if (cddev->is_inited)
 
2669
        {
 
2670
                char *p;
 
2671
                
 
2672
                if (cddev->inf.root != NULL)
 
2673
                        strcpy(fpath,cddev->inf.root);
 
2674
                if (cddev->ins_volname)
 
2675
                {
 
2676
                        char volname[16];
 
2677
                        volname[0] = '\0';
 
2678
                        if (cddev->volume != NULL)
 
2679
                                strncat(volname,cddev->volume->volume_name,sizeof volname);
 
2680
                        else
 
2681
                                sprintf(volname,"entrez%d",cddev->hint);
 
2682
                        if (!FileBuildPath(fpath,volname,NULL))
 
2683
                                return FALSE;
 
2684
                }
 
2685
                VERIFY(p = strchr(fpath,'\0'));
 
2686
                if (!FileBuildPath(fpath,(char*)fdir,(char*)fname))
 
2687
                        return FALSE;
 
2688
                if (cddev->upper_case)
 
2689
                        StrUpper(p);
 
2690
                if (cddev->semicolon_one)
 
2691
                        strcat(p,";1");
 
2692
                return TRUE;
 
2693
        }
 
2694
        return FALSE;   
 
2695
}
 
2696
 
 
2697
 
 
2698
static FILE * CdDevice_FileOpen (CdDevice *cddev, const char *fdir, const char *fname, const char *fmode)
 
2699
{
 
2700
        char fpath[256];
 
2701
        char ldir[32];
 
2702
        char lname[32];
 
2703
        FILE *fd;
 
2704
        
 
2705
        ASSERT(cddev != NULL);
 
2706
        
 
2707
        if (cddev->volume == NULL)      
 
2708
                return NULL;
 
2709
        
 
2710
        if (!cddev->is_inited)
 
2711
        {
 
2712
                if (!CdDevice_Init(cddev))
 
2713
                        return NULL;
 
2714
        }
 
2715
        if (cddev->inf.root == NULL)
 
2716
                fpath[0] = '\0';
 
2717
        else
 
2718
                strcpy(fpath,cddev->inf.root);
 
2719
        if (cddev->ins_volname)
 
2720
                FileBuildPath(fpath,cddev->volume->volume_name,NULL);
 
2721
        strcpy(ldir,fdir);
 
2722
        strcpy(lname,fname);
 
2723
        if (cddev->upper_case)
 
2724
        {
 
2725
                StrUpper(ldir);
 
2726
                StrUpper(lname);
 
2727
        }
 
2728
        FileBuildPath(fpath,ldir,lname);
 
2729
        if (cddev->semicolon_one)
 
2730
                strcat(fpath,";1");
 
2731
        if ((fd = FileOpen(fpath,fmode)) != NULL)
 
2732
                CdDevice_Touch(cddev);
 
2733
        return fd;
 
2734
}
 
2735
 
 
2736
 
 
2737
static int CdDevice_Init (CdDevice *cddev)
 
2738
{                                    
 
2739
        int cd_num;
 
2740
        char fpath[256];
 
2741
        CdRomInfo info;
 
2742
        
 
2743
        ASSERT(cddev != NULL);
 
2744
        if (cddev->is_inited)
 
2745
                return TRUE;
 
2746
 
 
2747
        cd_num = cddev->bound_cd;
 
2748
        memset((void*)&info,0,sizeof info);
 
2749
        fpath[0] = '\0';
 
2750
        if (cddev->inf.root !=NULL)
 
2751
                strncat(fpath,cddev->inf.root,sizeof fpath);
 
2752
                
 
2753
        if (cddev->ins_volname)
 
2754
        {
 
2755
                char volname[16];
 
2756
                if (cddev->bound_cd !=0)
 
2757
                {
 
2758
                        sprintf(volname,"entrez%d",cddev->bound_cd);
 
2759
                        FileBuildPath(fpath,volname,NULL);
 
2760
                }
 
2761
                else                            
 
2762
                {
 
2763
                        int vol_ct = (_volume_ct ==0) ? 3 : _volume_ct;
 
2764
                        int j;
 
2765
                        for (j=0; j<vol_ct; ++j)
 
2766
                        {
 
2767
                                fpath[0] = '\0';
 
2768
                                if (cddev->inf.root !=NULL)
 
2769
                                        strncat(fpath,cddev->inf.root,sizeof fpath);
 
2770
                                sprintf(volname,"entrez%d",j+1);
 
2771
                                FileBuildPath(fpath,volname,NULL);
 
2772
                                if (CdTestPath(fpath,&info))
 
2773
                                        break;
 
2774
                        }
 
2775
                }
 
2776
        }
 
2777
 
 
2778
        if (info.cd_num == 0)
 
2779
        {
 
2780
                if (!(CdTestPath(fpath,&info)))
 
2781
                        return FALSE;
 
2782
        }
 
2783
                
 
2784
        cddev->upper_case = info.upper_case;
 
2785
        cddev->semicolon_one = info.semicolon_one;
 
2786
        cddev->hint = info.cd_num;
 
2787
        cddev->is_inited = TRUE;
 
2788
        CdDevice_Touch(cddev);
 
2789
        return TRUE;
 
2790
}
 
2791
 
 
2792
 
 
2793
static void  CdDevice_Touch (CdDevice *cddev)
 
2794
{
 
2795
        time_t timestamp = time(NULL);
 
2796
        ASSERT(cddev != NULL);
 
2797
        cddev->timestamp = timestamp;
 
2798
        if (cddev->volume != NULL)
 
2799
                cddev->volume->timestamp = timestamp;
 
2800
}
 
2801
 
 
2802
 
 
2803
static int LIBCALLBACK default_CdInsertProc (const char *volname, const CdDevInfo *dev)
 
2804
{
 
2805
        char msg[80];
 
2806
        
 
2807
        ASSERT(volname != NULL);
 
2808
        ASSERT(dev != NULL);
 
2809
        
 
2810
        sprintf(msg,"Please insert volume \"%s\"",volname);
 
2811
        if (dev->formal_name)
 
2812
                sprintf(strchr(msg,0)," into %s",dev->formal_name);
 
2813
        if (MsgAlert(KEY_OKC,SEV_INFO,GetProgramName(),msg) == ANS_CANCEL)
 
2814
                return FALSE;
 
2815
        if (dev->mount_cmd != NULL)
 
2816
        {
 
2817
                return MountCd((char*)volname, dev->device_name, 
 
2818
                                                dev->mount_point, dev->mount_cmd);
 
2819
        }
 
2820
        return TRUE;
 
2821
}
 
2822
 
 
2823
 
 
2824
static int LIBCALLBACK default_CdEjectProc (const char *volname, const CdDevInfo *dev)
 
2825
{
 
2826
  return EjectCd((char*)volname, dev->device_name, 
 
2827
                 dev->raw_device_name, dev->mount_point, dev->mount_cmd);
 
2828
}
 
2829
 
 
2830
 
 
2831
 
 
2832
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
2833
/* CdMap   Schuler 7-29-94                                                     */
 
2834
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
2835
 
 
2836
static CdMap* CdMap_Construct (CdMap *map, int array_size)
 
2837
{
 
2838
        if (map != NULL)
 
2839
        {   
 
2840
                map->array_size = (short)array_size;
 
2841
                if (array_size > 0)
 
2842
                        map->list = (CdMap*) MemNew((size_t)array_size * sizeof(CdMap));
 
2843
        }
 
2844
        return map;
 
2845
}
 
2846
 
 
2847
static CdMap* CdMap_Destruct (CdMap *map)
 
2848
{
 
2849
        if (map != NULL)
 
2850
        {
 
2851
                CdMap *m;
 
2852
                if (map->lnklist)
 
2853
                {
 
2854
                        CdMap *m2;
 
2855
                        for (m=map->list; m; m=m2)
 
2856
                        {
 
2857
                                m2 = m->list;
 
2858
                                m->list = NULL;
 
2859
                                CdMap_Free(m);
 
2860
                        }
 
2861
                }
 
2862
                else
 
2863
                {
 
2864
                        int i;
 
2865
                        for (i=0, m=map->list; i<map->array_size; ++i, ++m)
 
2866
                                CdMap_Destruct(m);
 
2867
                        MemFree((void*)map->list);
 
2868
                }
 
2869
                MemFree((void*)map->cd_list);
 
2870
                MemFree((void*)map->user_path);
 
2871
                memset((void*)map,0,sizeof(CdMap));
 
2872
        }
 
2873
        return map;
 
2874
}
 
2875
 
 
2876
 
 
2877
static void CdMap_ParseCdNums (CdMap *map, char *nums)
 
2878
{
 
2879
        int cd, n=0;
 
2880
        short cd_list[8];
 
2881
        char *p, *p2 = nums;
 
2882
                
 
2883
        ASSERT(map != NULL);
 
2884
        ASSERT(nums != NULL);
 
2885
 
 
2886
        while ((p = p2) != NULL)
 
2887
        {
 
2888
                if ((p2 = strpbrk(p,",\10")) != NULL)
 
2889
                        *p2++ = '\0';
 
2890
                cd = atoi(p);
 
2891
                ASSERT(VOLNUM_IS_VALID(cd));
 
2892
                cd_list[n++] = (short) cd;
 
2893
        }
 
2894
        
 
2895
        if (n > 1)
 
2896
        {
 
2897
                map->multicd = TRUE;
 
2898
                map->cd_num = n;
 
2899
                map->cd_list = (short*) MemGet(n*sizeof(short),MGET_ERRPOST);
 
2900
                ASSERT(map->cd_list != NULL);
 
2901
                memcpy((void*)map->cd_list,(void*)cd_list,n*sizeof(short));
 
2902
        }
 
2903
        else
 
2904
        {
 
2905
                map->multicd = FALSE;
 
2906
                map->cd_num = cd_list[0];
 
2907
                map->cd_list = NULL;
 
2908
        }
 
2909
}
 
2910
 
 
2911
 
 
2912
static CdMap* CdMap_GetChild (CdMap *map, int nkid)
 
2913
{
 
2914
        ASSERT(map != NULL);
 
2915
        
 
2916
        if (map->lnklist)
 
2917
        {
 
2918
                CdMap *m2;
 
2919
                for (m2=map->list; m2; m2=m2->list)
 
2920
                {
 
2921
                        if (m2->id_num == nkid)
 
2922
                                return m2;
 
2923
                }
 
2924
        }       
 
2925
        else if (map->list != NULL)
 
2926
        {
 
2927
                return &(map->list[nkid]);
 
2928
        }
 
2929
        return NULL;
 
2930
}
 
2931
 
 
2932
 
 
2933
static int CdMap_GetSpecs (CdMap *map, int *cdlist, char *fdir)
 
2934
{
 
2935
        int count =0;
 
2936
 
 
2937
        ASSERT(map != NULL);
 
2938
        ASSERT(cdlist != NULL);
 
2939
        ASSERT(fdir != NULL);
 
2940
        
 
2941
        if (map->user_path != NULL)
 
2942
                strcpy(fdir,map->user_path);
 
2943
                
 
2944
        if (map->cd_num != 0)
 
2945
        {
 
2946
                if (map->multicd)
 
2947
                {
 
2948
                        int i;
 
2949
                        count = map->cd_num;
 
2950
                        ASSERT(map->cd_num < CDVOL_MAX);
 
2951
                        for (i=0; i<count; ++i)
 
2952
                        {
 
2953
                                cdlist[i] = map->cd_list[i];
 
2954
                        }
 
2955
                }
 
2956
                else
 
2957
                {
 
2958
                        count = 1;
 
2959
                        *cdlist = map->cd_num;
 
2960
                }
 
2961
        }
 
2962
        return count;
 
2963
}
 
2964
 
 
2965
 
 
2966
static void CdMap_FindPath (CdMap *map, const char *key)
 
2967
{
 
2968
        char fpath[256];
 
2969
        if (FindPath(_rcfile,"CdEntrez.Paths",(char*)key,fpath,sizeof fpath))
 
2970
        {
 
2971
                map->user_set = TRUE;
 
2972
                map->user_path = StrSave(fpath);
 
2973
        }
 
2974
}
 
2975
 
 
2976
 
 
2977
 
 
2978
 
 
2979
static Boolean ReadCdLayout (FILE *fd)
 
2980
{                                              
 
2981
        CdEntrezDir dir;
 
2982
        char line[64], key[32];
 
2983
        int i,j;
 
2984
                
 
2985
        for (dir=CdDir_FIRST; dir<=CdDir_LAST; ++dir)
 
2986
        {
 
2987
                CdMap_FindPath(&_map[dir],_dir[dir].key);
 
2988
                if (dir == CdDir_sys)
 
2989
                        CdMap_Construct(&_map[dir],0);
 
2990
                else
 
2991
                {
 
2992
                        CdMap_Construct(&_map[dir],_type_ct);
 
2993
                        for (i=0; i<_type_ct; ++i)
 
2994
                        {
 
2995
                                CdMap_Construct(&_map[dir].list[i],0);
 
2996
                                sprintf(key,"%s-%s",_dir[dir].key,TYPTAG(i));
 
2997
                                CdMap_FindPath(&_map[dir].list[i],key);
 
2998
                        }
 
2999
                }
 
3000
        }
 
3001
        
 
3002
        while (UnixFileGets(line,sizeof line,fd))
 
3003
        {
 
3004
                if (isalpha(line[0]))
 
3005
                {
 
3006
                        char *pt, *pd, *pn;
 
3007
                        CdMap *map = NULL;
 
3008
 
 
3009
                        VERIFY((pn = strchr(line,'\t')) != NULL);
 
3010
                        *pn++ = '\0';   /* pn points to the number(s) */
 
3011
                        
 
3012
                        if ((pt = strchr(line,'-')) != NULL)
 
3013
                                *pt++ = '\0';    /* pt points to the type tag */
 
3014
 
 
3015
                        for (dir=CdDir_FIRST; dir<=CdDir_LAST; ++dir)
 
3016
                        {
 
3017
                                if (strcmp(line,_dir[dir].key)==0)
 
3018
                                        break;
 
3019
                        }
 
3020
                        ASSERT(dir <= CdDir_LAST);
 
3021
                        map = &_map[dir];
 
3022
 
 
3023
                        if (pt != NULL)
 
3024
                        {
 
3025
                                if ((pd = strchr(pt,'-')) != NULL)
 
3026
                                        *pd++ = '\0';   /* pd points to the division tag */
 
3027
 
 
3028
                                for (i=0; i<_type_ct; ++i)
 
3029
                                {
 
3030
                                        if (strcmp(pt,TYPTAG(i)) ==0)
 
3031
                                                break;
 
3032
                                }
 
3033
                                ASSERT(i < _type_ct);
 
3034
                                map = &(map->list[i]);
 
3035
                                
 
3036
                                if (pd != NULL)
 
3037
                                {
 
3038
                                        /* lookup division tag */
 
3039
                                        for (j=0; j<_div_ct; ++j)
 
3040
                                        {
 
3041
                                                if (strcmp(pd,DIVTAG(j)) ==0)
 
3042
                                                        break;
 
3043
                                        }
 
3044
                                        ASSERT(j < _div_ct);
 
3045
                                        if (_cdinfo->div_info[j].docs[i] != 0)
 
3046
                                        {
 
3047
                                                CdMap *m2;
 
3048
                                                
 
3049
                                                /* create node and link into list */
 
3050
                                                map->lnklist = TRUE;
 
3051
                                                m2 = CdMap_New(0);
 
3052
                                                m2->id_num = j +1;
 
3053
                                                m2->list = map->list;
 
3054
                                                map->list = m2;
 
3055
                                                map = m2;
 
3056
                                                sprintf(key,"%s-%s-%s",_dir[dir].key,TYPTAG(i),DIVTAG(j));
 
3057
                                                CdMap_FindPath(map,key);
 
3058
                                        }
 
3059
                                }
 
3060
                        }
 
3061
                        CdMap_ParseCdNums(map,pn);
 
3062
                }
 
3063
        }
 
3064
        
 
3065
        if (_map[CdDir_sys].cd_num == 0)
 
3066
        {
 
3067
                /* The list of filenames and filesizes for the sysinfo directory
 
3068
                        was inadvertently omitted from the cdlayout.inf file on the 
 
3069
                        sample CD-ROMs distributed to developers.  This section of
 
3070
                        code should never be executed in the final release. */
 
3071
 
 
3072
                VERBOSE("   HACK (faking cdlayout.inf information for SYSINFO directory)\n");
 
3073
                _map[CdDir_sys].cd_list = (short*) MemNew(_volume_ct * sizeof(short));
 
3074
                for (i=0; i<_volume_ct; ++i)
 
3075
                {
 
3076
                        _map[CdDir_sys].cd_list[i] = i +1;
 
3077
                }
 
3078
                _map[CdDir_sys].cd_num = _volume_ct;
 
3079
                _map[CdDir_sys].multicd = TRUE;
 
3080
        }
 
3081
        
 
3082
        return TRUE;
 
3083
}
 
3084
 
 
3085
 
 
3086
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
3087
/* LSet (similar to LinkSet)  Schuler 06-01-94                                 */
 
3088
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
3089
#define FLUFF 2
 
3090
 
 
3091
static LSet* LSet_Construct (LSet *lset, short sorc_type, short dest_type, int link_max)
 
3092
{
 
3093
        if (lset != NULL)
 
3094
        {
 
3095
                lset->link = (DocLink*) Malloc(FLUFF*sizeof(DocLink));
 
3096
                if (lset->link == NULL)
 
3097
                {
 
3098
                        MemFree((void*)lset);
 
3099
                        return NULL;
 
3100
                }
 
3101
                lset->slots = FLUFF;
 
3102
                lset->sorc_type = sorc_type;
 
3103
                lset->dest_type = dest_type;
 
3104
                lset->link_max = link_max;
 
3105
        }
 
3106
        return lset;
 
3107
}
 
3108
 
 
3109
static LSet * LSet_Destruct (LSet *lset)
 
3110
{
 
3111
        if (lset != NULL)       
 
3112
                Free((void*)lset->link); 
 
3113
        return lset;
 
3114
}
 
3115
 
 
3116
 
 
3117
static int LSet_Read (LSet *lset, FILE *fd)
 
3118
{
 
3119
        unsigned short m[TYPE_MAX];
 
3120
        DocUid uid;
 
3121
        int link_ct, max_ct;
 
3122
        int i, j, k, wt;
 
3123
        DocLink *link, *p1, *p2, *p3;
 
3124
        
 
3125
        ASSERT(lset != NULL);
 
3126
        link = lset->link;
 
3127
        ASSERT(link != NULL);
 
3128
 
 
3129
        /* read the link counts */
 
3130
        FileReadSwapShort(m,_type_ct,fd);
 
3131
        link_ct = m[lset->dest_type];
 
3132
        max_ct = MIN(lset->link_max,lset->count+link_ct);
 
3133
 
 
3134
        /* grow the array, if necessary */
 
3135
        if (max_ct > lset->slots)
 
3136
        {
 
3137
                int cd3_slots = max_ct + FLUFF;
 
3138
                size_t bytes = sizeof(DocLink) * cd3_slots;
 
3139
                void *array = Realloc((void*)link,bytes);
 
3140
                if (array == NULL)
 
3141
                {
 
3142
                        ErrPostEx(SEV_FATAL,0,0,"Out of memory");
 
3143
                        return FALSE;
 
3144
                }
 
3145
                lset->link = link = (DocLink*)array;
 
3146
                lset->slots = max_ct + FLUFF;
 
3147
        }
 
3148
        
 
3149
        /* skip over link lists for other types that preceed this one */
 
3150
        for (i=0; i<lset->dest_type; ++i)
 
3151
        {
 
3152
                fseek(fd,4*m[i],SEEK_CUR);
 
3153
                if (i==lset->sorc_type)
 
3154
                        fseek(fd,m[i],SEEK_CUR);
 
3155
        }
 
3156
 
 
3157
        /* process links, one at a time */      
 
3158
        for (i=0; i<link_ct; ++i)
 
3159
        {
 
3160
                /* read next link from the file */
 
3161
                /* NEED TO CHECK FOR ERROR HERE! */
 
3162
                FileReadSwapInt4((Uint4*)&uid,1,fd);
 
3163
                wt = (lset->sorc_type == lset->dest_type) ? fgetc(fd) : 1;
 
3164
                if (lset->count == lset->link_max)  continue;
 
3165
                
 
3166
                /* insert into array, keeping sorted by UID and summing weights */
 
3167
                for (j=0, p1=link; j<lset->count; ++j, ++p1)
 
3168
                {
 
3169
                        if (p1->uid == uid)
 
3170
                                break;
 
3171
                        if (p1->uid > uid)
 
3172
                        {
 
3173
                                p2 = link + lset->count;
 
3174
                                p3 = p2 -1;
 
3175
                                for (k=j; k<lset->count; ++k)
 
3176
                                        *p2-- = *p3--;
 
3177
                                break;
 
3178
                        }
 
3179
                }                
 
3180
                if (j==lset->count || p1->uid != uid)
 
3181
                {
 
3182
                        p1->wt = 0;
 
3183
                        lset->count ++;
 
3184
                }
 
3185
                p1->uid = uid;
 
3186
                p1->wt += wt;
 
3187
        }
 
3188
        return TRUE;
 
3189
}
 
3190
 
 
3191
static int LIBCALLBACK linkcmp (VoidPtr ptr1, VoidPtr ptr2);
 
3192
/*
 
3193
static int linkcmp (const void *ptr1, const void *ptr2);
 
3194
*/
 
3195
 
 
3196
static LinkSet* LSet_Convert (LSet *lset)
 
3197
{
 
3198
        LinkSet *lnkset = NULL;
 
3199
        ASSERT(lset != NULL);
 
3200
        if ((lnkset = (LinkSet*) MemNew(sizeof(LinkSet))) != NULL)
 
3201
        {
 
3202
                int i;
 
3203
                DocLink *p = lset->link;
 
3204
                
 
3205
                /*
 
3206
                qsort((void*)p,lset->count,sizeof(DocLink),linkcmp);
 
3207
                */
 
3208
                HeapSort ((VoidPtr) p,lset->count,sizeof(DocLink),linkcmp);
 
3209
                lnkset->num = lset->count;
 
3210
                lnkset->uids = (Int4*) MemGet(sizeof(Int4)*lset->count, MGET_ERRPOST);
 
3211
                lnkset->weights = (Int4*) MemGet(sizeof(Int4)*lset->count, MGET_ERRPOST);
 
3212
                for (i=0; i<lset->count; ++i, ++p)
 
3213
                {
 
3214
                        lnkset->uids[i] = p->uid;
 
3215
                        lnkset->weights[i] = p->wt;
 
3216
                }
 
3217
                LSet_Free(lset);                
 
3218
        }
 
3219
        return lnkset;
 
3220
}
 
3221
 
 
3222
static int LIBCALLBACK linkcmp (VoidPtr ptr1, VoidPtr ptr2)
 
3223
/*
 
3224
static int linkcmp (const void *ptr1, const void *ptr2)
 
3225
*/
 
3226
{
 
3227
        DocLink *lnk1 = (DocLink*)ptr1;
 
3228
        DocLink *lnk2 = (DocLink*)ptr2;
 
3229
        int d;
 
3230
        
 
3231
        if ((d = lnk2->wt - lnk1->wt) ==0)
 
3232
                d = (lnk1->uid > lnk2->uid) ? -1 : 1;
 
3233
        return d;
 
3234
}
 
3235
 
 
3236
 
 
3237
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
3238
/* HuffTable Functions.   Schuler 06-13-94                                      */
 
3239
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
3240
 
 
3241
static HuffTable* HuffTable_Construct (HuffTable *huff, int n)
 
3242
{
 
3243
        if (huff != NULL)
 
3244
        {
 
3245
                huff->count = n;
 
3246
                if ( ((huff->left = (short*)MemGet(sizeof(short)*n,MGET_ERRPOST)) != NULL)
 
3247
                                && ((huff->right= (short*)MemGet(sizeof(short)*n,MGET_ERRPOST)) != NULL) )
 
3248
                        return huff;
 
3249
                huff = NULL;
 
3250
        }
 
3251
        return huff;
 
3252
}
 
3253
 
 
3254
static HuffTable* HuffTable_Destruct (HuffTable *huff)
 
3255
{
 
3256
        if (huff != NULL)
 
3257
        {
 
3258
                MemFree((void*)huff->right);
 
3259
                MemFree((void*)huff->left);
 
3260
                memset((void*)huff,0,sizeof(HuffTable));
 
3261
        }
 
3262
        return huff;
 
3263
}
 
3264
 
 
3265
static HuffTable* HuffTable_Read (FILE *fd)
 
3266
{
 
3267
        short n;
 
3268
        if (FileReadSwapShort((unsigned short*)&n,1,fd))
 
3269
        {
 
3270
                HuffTable *huff = HuffTable_New(n);
 
3271
                if (huff != NULL)
 
3272
                {
 
3273
                        if ( (FileReadSwapShort((unsigned short*)huff->left,n,fd) == n)
 
3274
                                                && FileReadSwapShort((unsigned short*)huff->right,n,fd) == n )
 
3275
                        {
 
3276
                                return huff;
 
3277
                        }
 
3278
                        HuffTable_Free(huff);
 
3279
                }
 
3280
        }
 
3281
        return NULL;
 
3282
}
 
3283
 
 
3284
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
3285
/* DecompInfo Functions     Schuler 06-21-94                                   */
 
3286
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
3287
 
 
3288
static DecompInfo* DecompInfo_Construct (DecompInfo *info, HuffTable *huff)
 
3289
{
 
3290
        if (info != NULL)
 
3291
                info->huff = huff;
 
3292
        return info;
 
3293
}
 
3294
 
 
3295
static AsnIo* DecompInfo_Attach (DecompInfo *info, FILE *fd)
 
3296
{
 
3297
        AsnIo *aio = AsnIoNew(ASNIO_BIN_IN,fd,info,DecompReadProc,NULL);
 
3298
        if (aio != NULL)
 
3299
        {
 
3300
                info->aio = aio;
 
3301
                info->fd = fd;
 
3302
                return aio;
 
3303
        }
 
3304
        return NULL;
 
3305
}
 
3306
 
 
3307
static FILE* DecompInfo_Detach (DecompInfo *info)
 
3308
{
 
3309
        FILE *fd = info->fd;
 
3310
        info->fd = NULL;
 
3311
        info->aio->fp = NULL;
 
3312
        AsnIoClose(info->aio);
 
3313
        info->aio = NULL;
 
3314
        return fd;
 
3315
}
 
3316
 
 
3317
static Int2 LIBCALLBACK DecompReadProc (void *opaque, char *buff, Uint2 count)
 
3318
{
 
3319
        DecompInfo *dcp = (DecompInfo*)opaque;
 
3320
        register unsigned int mask = dcp->mask;
 
3321
        register unsigned int byte = dcp->byte;
 
3322
        char *p = buff;
 
3323
        int i, cnt = 0;
 
3324
        int c;
 
3325
        int k;
 
3326
        FILE *fd1 = dcp->fd;
 
3327
        int sentinel = dcp->huff->count;
 
3328
 
 
3329
        while (cnt < (int) count)
 
3330
        {
 
3331
                for (i=0; i>=0; )
 
3332
                {
 
3333
                        if (mask == 0)
 
3334
                        {
 
3335
                                if ((c = fgetc(fd1)) == EOF)
 
3336
                                {
 
3337
                                        /* should never reach this point */
 
3338
                                        ErrPostEx(SEV_INFO,0,0,"Unexpected EOF");
 
3339
                                        i = sentinel - 257;
 
3340
                                        break;
 
3341
                                }
 
3342
                                else
 
3343
                                {
 
3344
                                        byte = (unsigned int) c;
 
3345
                                        mask = 0x80;
 
3346
                                }
 
3347
                        }
 
3348
 
 
3349
                        if (byte & mask)
 
3350
                                i = dcp->huff->left[i];
 
3351
                        else
 
3352
                                i = dcp->huff->right[i];
 
3353
 
 
3354
                        mask >>= 1;
 
3355
                }
 
3356
 
 
3357
                if ((k = i + 257) == sentinel)
 
3358
                {
 
3359
                        mask = 0; /* to skip remaining bits in current byte */
 
3360
                        break;
 
3361
                }
 
3362
 
 
3363
                *p++ = (char) k;
 
3364
                cnt++;
 
3365
        }
 
3366
 
 
3367
        dcp->mask = mask;
 
3368
        dcp->byte = byte;
 
3369
        return cnt;
 
3370
}
 
3371
 
 
3372
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 
3373
* CACHE FUNCTIONS.   Schuler 05-17-94
 
3374
*
 
3375
* Functions for caching arbitrary pages of data.  Pages are uniquely
 
3376
* identified by a long integer.
 
3377
*
 
3378
* MODIFICATIONS
 
3379
* When      Who       What
 
3380
* --------  --------  ------------------------------------------------------
 
3381
* 06-01-94  Schuler  Added new argument to Cache_New() that is a pointer to
 
3382
*                    a function to be called to free cached data items.
 
3383
 
3384
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
3385
 
 
3386
static CachePage * Cache_FindPage (Cache *cache, long id, int *index);
 
3387
static void Cache_Delete_ByIndex (Cache *cache, int index);
 
3388
static void Cache_Touch_ByIndex (Cache *cache, int index);
 
3389
static int Cache_DeleteLRU (Cache *cache);
 
3390
 
 
3391
#define Cache_ISVALID(x)  ((x) != NULL && (x)->magic == Cache_MAGIC_VALUE )
 
3392
 
 
3393
static int Cache_IsValid (Cache *cache)
 
3394
{
 
3395
        return Cache_ISVALID(cache);
 
3396
}
 
3397
 
 
3398
static void PASCAL DefCacheDataFreeProc (void *data)
 
3399
{
 
3400
        MemFree(data);
 
3401
}
 
3402
 
 
3403
static Cache* Cache_Construct (Cache *cache, int slots, CacheDataFreeProc fproc)
 
3404
{
 
3405
        if (cache != NULL)
 
3406
        {
 
3407
                size_t bytes = (size_t)slots * sizeof(CachePage);
 
3408
                CachePage *p = (CachePage*) MemGet(bytes,MGET_ERRPOST);
 
3409
                if (p == NULL)
 
3410
                {
 
3411
                        cache = NULL;
 
3412
                }
 
3413
                else
 
3414
                {
 
3415
                        cache->magic = Cache_MAGIC_VALUE;
 
3416
                        cache->page = p;
 
3417
                        cache->page_slots = slots;
 
3418
                        cache->fproc = fproc;
 
3419
                }
 
3420
        }
 
3421
        return cache;
 
3422
}
 
3423
 
 
3424
static Cache* Cache_Destruct (Cache *cache)
 
3425
{
 
3426
        if (cache != NULL)
 
3427
        {
 
3428
                int i;
 
3429
                CacheDataFreeProc fproc;
 
3430
                
 
3431
                ASSERT(Cache_ISVALID(cache));
 
3432
        
 
3433
                if ((fproc = cache->fproc) != NULL)
 
3434
                {
 
3435
                        for (i=0; i<cache->page_count; ++i)
 
3436
                                (*fproc)(cache->page[i].data);
 
3437
                }
 
3438
                (void)MemFree((void*)cache->page);
 
3439
                cache->magic = 0;
 
3440
        }
 
3441
        return cache;
 
3442
}
 
3443
 
 
3444
static CachePage * Cache_FindPage (Cache *cache, long id, int *index)
 
3445
{
 
3446
        CachePage *p = cache->page;
 
3447
        int i;
 
3448
        for (i=0; i<cache->page_count; ++i, ++p)
 
3449
        {
 
3450
                if (p->id == id)
 
3451
                {
 
3452
                        if (index != NULL)
 
3453
                                *index = i;
 
3454
                        return p;
 
3455
                }
 
3456
        }
 
3457
        return NULL;
 
3458
}
 
3459
 
 
3460
static int Cache_Insert (Cache *cache, long id, void *data)
 
3461
{
 
3462
    int i;
 
3463
    
 
3464
        ASSERT(Cache_ISVALID(cache));
 
3465
 
 
3466
        if ((Cache_FindPage(cache,id,NULL)) != NULL)
 
3467
        {
 
3468
                ErrPostEx(SEV_INFO,0,0,"Cache_Insert;  Duplicate IDs");
 
3469
                return FALSE;
 
3470
        }
 
3471
        
 
3472
        if (cache->page_count == cache->page_slots)
 
3473
        {
 
3474
                if (!Cache_DeleteLRU(cache))
 
3475
                {
 
3476
                        ErrPostEx(SEV_INFO,0,0,"Cache_Insert;  All pages locked");
 
3477
                        return FALSE;
 
3478
                }
 
3479
        }
 
3480
        
 
3481
        i = cache->page_count;
 
3482
        cache->page[i].id = id;
 
3483
        cache->page[i].lock = 0;
 
3484
        cache->page[i].data = data;
 
3485
        cache->page_count ++;
 
3486
        if (i > 0)
 
3487
                Cache_Touch_ByIndex(cache,i);
 
3488
        return TRUE;
 
3489
}
 
3490
 
 
3491
static void Cache_Delete_ByIndex (Cache *cache, int index)
 
3492
{
 
3493
        CacheDataFreeProc fproc = cache->fproc;
 
3494
        CachePage temp = cache->page[index];
 
3495
        int i;
 
3496
        cache->page_count--;
 
3497
        for (i=index; i<cache->page_count; ++i)
 
3498
        {
 
3499
                cache->page[i] = cache->page[i+1];
 
3500
        }
 
3501
        if (fproc != NULL)
 
3502
                (*fproc)(temp.data);
 
3503
}
 
3504
 
 
3505
 
 
3506
static int Cache_Delete (Cache *cache, long id)
 
3507
{
 
3508
        int index;
 
3509
        ASSERT(Cache_ISVALID(cache));
 
3510
        if (Cache_FindPage(cache,id,&index) != NULL)
 
3511
        {
 
3512
                Cache_Delete_ByIndex(cache,index);
 
3513
                return TRUE;
 
3514
        }
 
3515
        return FALSE;
 
3516
}
 
3517
 
 
3518
 
 
3519
static int Cache_DeleteLRU (Cache *cache)
 
3520
{
 
3521
        int i;
 
3522
        for (i=cache->page_count-1; i>=0; --i)
 
3523
        {
 
3524
                if (cache->page[i].lock ==0)
 
3525
                {
 
3526
                        Cache_Delete_ByIndex(cache,i);
 
3527
                        return TRUE;
 
3528
                }
 
3529
        }
 
3530
        return FALSE;
 
3531
}
 
3532
 
 
3533
 
 
3534
static void* Cache_Lock (Cache *cache, long id)
 
3535
{
 
3536
        CachePage *page;
 
3537
        
 
3538
        ASSERT(Cache_ISVALID(cache));
 
3539
        if ((page = Cache_FindPage(cache,id,NULL)) != NULL)
 
3540
        {
 
3541
                page->lock++;
 
3542
                cache->hits++;
 
3543
                return page->data;
 
3544
        }
 
3545
        cache->misses++;
 
3546
        return NULL;
 
3547
}
 
3548
 
 
3549
static int Cache_Unlock (Cache *cache, long id)
 
3550
{
 
3551
        CachePage *page;
 
3552
        int index;
 
3553
        
 
3554
        ASSERT(Cache_ISVALID(cache));
 
3555
        if ((page = Cache_FindPage(cache,id,&index)) != NULL)
 
3556
        {
 
3557
                if (page->lock > 0)
 
3558
                {       
 
3559
                        page->lock--;
 
3560
                        if (index > 0)
 
3561
                                Cache_Touch_ByIndex(cache,index);
 
3562
                        return TRUE;
 
3563
                }
 
3564
                ErrPostEx(SEV_INFO,0,0,"Cache_Unlock;  Page(%ld) was not locked",id);
 
3565
        }
 
3566
        return FALSE;
 
3567
}
 
3568
 
 
3569
static int Cache_Touch (Cache *cache, long id)
 
3570
{
 
3571
        int index;
 
3572
        ASSERT(Cache_ISVALID(cache));
 
3573
        if (Cache_FindPage(cache,id,&index) != NULL)
 
3574
        {
 
3575
                Cache_Touch_ByIndex(cache,index);
 
3576
                return TRUE;
 
3577
        }
 
3578
        return FALSE;
 
3579
}
 
3580
 
 
3581
static void Cache_Touch_ByIndex (Cache *cache, int index)
 
3582
{
 
3583
        CachePage temp = cache->page[index];
 
3584
        int i;
 
3585
        for (i=index; i>0; --i)
 
3586
        {
 
3587
                cache->page[i] = cache->page[i-1];
 
3588
        }
 
3589
        cache->page[0] = temp;
 
3590
}
 
3591
 
 
3592
static void* Cache_Peek (Cache *cache, long id)
 
3593
{
 
3594
        CachePage *page;
 
3595
        
 
3596
        ASSERT(Cache_ISVALID(cache));
 
3597
        if ((page = Cache_FindPage(cache,id,NULL)) != NULL)
 
3598
        {
 
3599
                return page->data;
 
3600
        }
 
3601
        return NULL;
 
3602
}
 
3603
 
 
3604
 
 
3605
static void Cache_Purge (Cache *cache)
 
3606
{
 
3607
        ASSERT(Cache_ISVALID(cache));
 
3608
        
 
3609
        while (Cache_DeleteLRU(cache))
 
3610
                /* empty statement */ ;
 
3611
}
 
3612
 
 
3613
 
 
3614
/**** get rid of this function!  use Cache_ReportStats instead ****/
 
3615
static void  Cache_LogStats (Cache *cache, const char *name)
 
3616
{
 
3617
        long total;
 
3618
        int pct1, pct2;
 
3619
        
 
3620
        ASSERT(Cache_ISVALID(cache));
 
3621
        total = cache->hits + cache->misses;
 
3622
        pct1 = (total==0) ? 0 : (int)((cache->hits*100L)/total);
 
3623
        pct2 = (total==0) ? 0 : (int)((cache->misses*100L)/total);
 
3624
        
 
3625
        VERBOSE("\n   Cache Statistics: %s\n",name);
 
3626
        VERBOSE("      %d slots, %d of them currently occupied\n",
 
3627
                                cache->page_slots, cache->page_count);
 
3628
        VERBOSE("      %ld hits   (%d%%)\n",cache->hits,pct1);
 
3629
        VERBOSE("      %ld misses (%d%%)\n",cache->misses,pct2);
 
3630
        VERBOSE("      %ld total access attempts\n", total);
 
3631
}
 
3632
 
 
3633
 
 
3634
#define LONGDIV(x,y) (long)((0.5 + (double)(x)/(double)(y)))
 
3635
#define PERCENT(x,y) ((y)==0) ? 0 : (int)LONGDIV((x)*100L,(y))
 
3636
 
 
3637
static char * Cache_ReportStats (Cache *cache, char *buffer)
 
3638
{
 
3639
        char *p = buffer;
 
3640
        
 
3641
        ASSERT(buffer != NULL);
 
3642
        
 
3643
        if (Cache_ISVALID(cache))
 
3644
        {
 
3645
                long total = cache->hits + cache->misses;
 
3646
                if (cache->page_size != 0)
 
3647
                {
 
3648
                        int kbytes_total, kbytes_used;
 
3649
                        kbytes_total = (int) LONGDIV(cache->page_size*cache->page_slots, KBYTE);
 
3650
                        sprintf(p=strchr(p,0),"   cache memory:   %5d K\n", kbytes_total);
 
3651
                        kbytes_used = (int) LONGDIV(cache->page_size*cache->page_count, KBYTE);
 
3652
                        sprintf(p=strchr(p,0),"   memory in use:  %5d K (%d%%)\n", kbytes_used,
 
3653
                                                PERCENT(kbytes_used,kbytes_total));
 
3654
                }
 
3655
                sprintf(p=strchr(p,0),"   cache hits:     %5ld   (%d%%)\n",
 
3656
                                        cache->hits, PERCENT(cache->hits,total));
 
3657
                sprintf(p=strchr(p,0),"   cache misses:   %5ld   (%d%%)\n",
 
3658
                                        cache->misses, PERCENT(cache->misses,total));
 
3659
                sprintf(p=strchr(p,0),"   total attempts: %5ld\n",total);
 
3660
        }
 
3661
        return strchr(p,0);
 
3662
}
 
3663
 
 
3664
 
 
3665
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
3666
/* Error reporting functions                                                    */
 
3667
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
3668
 
 
3669
static int InvalidConfiguration (int code)
 
3670
{
 
3671
#ifdef _OLD_CdEntrez_
 
3672
        ErrSev sev = SEV_INFO;
 
3673
#else
 
3674
        ErrSev sev = SEV_ERROR;
 
3675
#endif
 
3676
        ErrPostEx(sev,ERR_ConfigFile,code,"CdEntrez module is not configured correctly.  "
 
3677
                                "Please run EntrezCf to correct the problem.");
 
3678
        return FALSE;
 
3679
}
 
3680
 
 
3681
static int FileOutOfDate (const char *fname)
 
3682
{
 
3683
        ErrPostEx(SEV_ERROR,ERR_BadFile,SUB_BadVersion,
 
3684
                                "The file %s does not come from the expected "
 
3685
                                "Entrez version (%d.%d).",fname,_rel_major,_rel_minor);
 
3686
        return FALSE;
 
3687
}
 
3688
 
 
3689
static int FileCorrupt (const char *fname)
 
3690
{
 
3691
        ErrPostEx(SEV_ERROR,ERR_BadFile,SUB_Corrupt,
 
3692
                                "The file %s appears to be corrupted",fname);
 
3693
        return FALSE;
 
3694
}
 
3695
 
 
3696
static int FileNotRecognized (const char *fname)
 
3697
{
 
3698
        ErrPostEx(SEV_ERROR,ERR_BadFile,SUB_NeedUpdate,
 
3699
                                "The file %s cannot be read by this release of "
 
3700
                                "the software.  Please obtain a newer version.", fname);
 
3701
        return FALSE;
 
3702
}
 
3703
 
 
3704
static int CatastrophicFailure (int code)
 
3705
{
 
3706
        ErrPostEx(SEV_ERROR,ERR_DeepDooDoo,code,
 
3707
                                "Catastrophic Failure in CdEntrez module");
 
3708
        return FALSE;
 
3709
}
 
3710
 
 
3711
 
 
3712
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
3713
/* Misc. Utility Functions.   Schuler 05-16-94                                 */
 
3714
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
 
3715
 
 
3716
static char * _GetAppParamStr (const char *filebase, const char *section, 
 
3717
                                const char *key, const char *dflt)
 
3718
{
 
3719
        char buffer[256];
 
3720
        GetAppParam((char*)filebase,(char*)section,(char*)key,
 
3721
                                        (char*)dflt,buffer,sizeof buffer);
 
3722
        return buffer[0] ? StrSave(buffer) : NULL;
 
3723
}
 
3724
 
 
3725
 
 
3726
static int FileReadSwapShort (unsigned short *buffer, int count, FILE *fd)
 
3727
{
 
3728
        int n;
 
3729
        if (sizeof(short) != 2)
 
3730
        {
 
3731
                unsigned short *ptr, val;
 
3732
                int i, c;
 
3733
        
 
3734
                for (ptr=buffer, n=0; n<count; ++n)
 
3735
                {
 
3736
                        for (i=0, val=0; i<2; ++i)
 
3737
                        {
 
3738
                                if ((c = fgetc(fd)) ==EOF)  
 
3739
                                        break;
 
3740
                                val <<= 8;
 
3741
                                val |= (unsigned short)c;
 
3742
                        }
 
3743
                        if (i<2)
 
3744
                                break;
 
3745
                        *ptr++ = val;
 
3746
                }
 
3747
        }
 
3748
        else
 
3749
        {
 
3750
                n = FileRead((void*)buffer,sizeof(short),count,fd);
 
3751
                SwapUint2Buff(buffer,n);
 
3752
        }
 
3753
        return n;
 
3754
}
 
3755
 
 
3756
 
 
3757
static int FileReadSwapLong (unsigned long *buffer, int count, FILE *fd)
 
3758
{
 
3759
        int n;
 
3760
        if (sizeof(long) != 4)
 
3761
        {
 
3762
                unsigned long *ptr, val;
 
3763
                int i, c;
 
3764
        
 
3765
                for (ptr=buffer, n=0; n<count; ++n)
 
3766
                {
 
3767
                        for (i=0, val=0; i<4; ++i)
 
3768
                        {
 
3769
                                if ((c = fgetc(fd)) ==EOF)  
 
3770
                                        break;
 
3771
                                val <<= 8;
 
3772
                                val |= (unsigned long)c;
 
3773
                        }
 
3774
                        if (i<4)
 
3775
                                break;
 
3776
                        *ptr++ = val;
 
3777
                }
 
3778
        }
 
3779
        else
 
3780
        {
 
3781
                n = FileRead((void*)buffer,sizeof(long),count,fd);
 
3782
                SwapLongBuff(buffer,n);
 
3783
        }
 
3784
        return n;
 
3785
}
 
3786
 
 
3787
 
 
3788
static int FileReadSwapInt4 (Uint4Ptr buffer, int count, FILE *fd)
 
3789
{
 
3790
        int n;
 
3791
        if (sizeof(Uint4) != 4)
 
3792
        {
 
3793
                Uint4 *ptr, val;
 
3794
                int i, c;
 
3795
        
 
3796
                for (ptr=buffer, n=0; n<count; ++n)
 
3797
                {
 
3798
                        for (i=0, val=0; i<4; ++i)
 
3799
                        {
 
3800
                                if ((c = fgetc(fd)) ==EOF)  
 
3801
                                        break;
 
3802
                                val <<= 8;
 
3803
                                val |= (Uint4)c;
 
3804
                        }
 
3805
                        if (i<4)
 
3806
                                break;
 
3807
                        *ptr++ = val;
 
3808
                }
 
3809
        }
 
3810
        else
 
3811
        {
 
3812
                n = FileRead((void*)buffer,sizeof(Uint4),count,fd);
 
3813
                SwapUint4Buff(buffer,n);
 
3814
        }
 
3815
        return n;
 
3816
}
 
3817
 
 
3818
 
 
3819
static char * FileReadStr (FILE *fd, int lbyte)
 
3820
{
 
3821
        unsigned short len;
 
3822
        
 
3823
        if (lbyte == 2)
 
3824
                FileReadSwapShort(&len,1,fd);
 
3825
        else
 
3826
                len = (unsigned short) fgetc(fd);
 
3827
        
 
3828
        if (len > 0)
 
3829
        {
 
3830
                char *str = MemGet(1+len,MGET_ERRPOST);
 
3831
                if (str != NULL)
 
3832
                {
 
3833
                        if (fread(str,1,len,fd) != (size_t)len)
 
3834
                        {
 
3835
                                MemFree((void*)str);
 
3836
                                ErrPostEx(SEV_INFO,0,0,"Unexpected EOF");
 
3837
                        }
 
3838
                        else
 
3839
                        {
 
3840
                                *(str+len) = '\0';
 
3841
                                return str;
 
3842
                        }
 
3843
                }
 
3844
        }
 
3845
        return NULL;
 
3846
}
 
3847
 
 
3848
 
 
3849
#endif 
 
3850