|
NCBI Home IEB Home C Toolkit docs C++ Toolkit source browser C Toolkit source browser (2) |
NCBI C Toolkit Cross ReferenceC/cdromlib/cdnewlib.c |
source navigation diff markup identifier search freetext search file search |
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
3851 |
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more information. |