1 /*   ncbifile.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 * File Name:  ncbifile.c
27 *
28 * Author:  Gish, Kans, Ostell, Schuler
29 *
30 * Version Creation Date:   3/4/91
31 *
32 * $Revision: 6.46 $
33 *
34 * File Description:
35 *     portable file routines
36 *
37 * Modifications:
38 * --------------------------------------------------------------------------
39 * Date     Name        Description of modification
40 * -------  ----------  -----------------------------------------------------
41 *
42 * ==========================================================================
43 */
44 
45 #define THIS_MODULE g_corelib
46 #define THIS_FILE  _this_file
47 
48 #include <ncbilcl.h>
49 #include <assert.h>
50 
51 #include "corepriv.h"
52 #ifdef OS_MAC
53 #ifdef OS_UNIX_DARWIN
54 #include <Carbon.h>
55 #endif
56 #include <Navigation.h>
57 #include <Script.h>
58 #endif
59 
60 #ifdef OS_UNIX_SUN
61 #define DEFAULT_CDROM "/dev/sr0"
62 #define DEFAULT_RAW_CDROM "/dev/rsr0"
63 #endif
64 
65 #if defined(PROC_MIPS) && !defined(OS_UNIX_LINUX)
66 #define DEFAULT_CDROM "/dev/scsi/sc0d4l0"
67 #endif
68 
69 #ifdef OS_UNIX
70 #ifndef DEFAULT_CDROM
71 #define DEFAULT_CDROM "/dev/cdrom"
72 #endif
73 #endif
74 
75 #if defined(OS_MSWIN) || defined (OS_NT)
76 #ifdef COMP_MSC
77 #ifndef mkdir
78 #define mkdir _mkdir
79 #endif
80 #ifndef stat
81 #define stat _stat
82 #endif
83 #endif
84 #endif
85 
86 #ifdef OS_VMS
87 #ifndef DEFAULT_CDROM
88 #define DEFAULT_CDROM "cdrom:"
89 #endif
90 #endif
91 
92 extern char *g_corelib;
93 static char * _this_file = __FILE__;
94 
95 #ifdef OS_MAC
96 #define INLINE_MOREFILES
97 /* #include "FullPath.h" */
98 /* #include "MoreFilesExtra.h" */
99 #ifdef INLINE_MOREFILES
100 
101 /* MoreFilesExtras.c */
102 /* ----------------- */
103 
104 /*
105 **	Apple Macintosh Developer Technical Support
106 **
107 **	A collection of useful high-level File Manager routines.
108 **
109 **	by Jim Luther, Apple Developer Technical Support Emeritus
110 **
111 **	File:		MoreFilesExtras.c
112 **
113 **	Copyright (c) 1992-1999 Apple Computer, Inc.
114 **	All rights reserved.
115 **
116 **	You may incorporate this sample code into your applications without
117 **	restriction, though the sample code has been provided "AS IS" and the
118 **	responsibility for its operation is 100% yours.  However, what you are
119 **	not permitted to do is to redistribute the source as "DSC Sample Code"
120 **	after having made changes. If you're going to re-distribute the source,
121 **	we require that you make it clear in the source that the code was
122 **	descended from Apple Sample Code, but that you've made changes.
123 */
124 
125 #include <Types.h>
126 #include <Traps.h>
127 #include <OSUtils.h>
128 #include <Errors.h>
129 #include <Files.h>
130 #include <Devices.h>
131 #include <Finder.h>
132 #include <Folders.h>
133 #include <FSM.h>
134 #include <Disks.h>
135 #include <Gestalt.h>
136 #include <TextUtils.h>
137 #include <Script.h>
138 #include <Math64.h>
139 #include <CodeFragments.h>
140 #include <stddef.h>
141 
142 #define	__COMPILINGMOREFILES
143 
144 #if 0
145 #include "MoreFiles.h"
146 #include "MoreFilesExtras.h"
147 #include "MoreDesktopMgr.h"
148 #include "FSpCompat.h"
149 #endif
150 
151 /*
152 **	GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
153 **	in cases where the returned volume name is not needed by the caller.
154 **	The pathname and vRefNum parameters are not touched, and the pb
155 **	parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
156 **	the parameter block is always returned as NULL (since it might point
157 **	to the local tempPathname).
158 **
159 **	I noticed using this code in several places, so here it is once.
160 **	This reduces the code size of MoreFiles.
161 */
GetVolumeInfoNoName(ConstStr255Param pathname,short vRefNum,HParmBlkPtr pb)162 static pascal	OSErr	GetVolumeInfoNoName(ConstStr255Param pathname,
163 									short vRefNum,
164 									HParmBlkPtr pb)
165 {
166 	Str255 tempPathname;
167 	OSErr error;
168 
169 	/* Make sure pb parameter is not NULL */
170 	if ( pb != NULL )
171 	{
172 		pb->volumeParam.ioVRefNum = vRefNum;
173 		if ( pathname == NULL )
174 		{
175 			pb->volumeParam.ioNamePtr = NULL;
176 			pb->volumeParam.ioVolIndex = 0;		/* use ioVRefNum only */
177 		}
178 		else
179 		{
180 			BlockMoveData(pathname, tempPathname, pathname[0] + 1);	/* make a copy of the string and */
181 			pb->volumeParam.ioNamePtr = (StringPtr)tempPathname;	/* use the copy so original isn't trashed */
182 			pb->volumeParam.ioVolIndex = -1;	/* use ioNamePtr/ioVRefNum combination */
183 		}
184 		error = PBHGetVInfoSync(pb);
185 		pb->volumeParam.ioNamePtr = NULL;	/* ioNamePtr may point to local	tempPathname, so don't return it */
186 	}
187 	else
188 	{
189 		error = paramErr;
190 	}
191 	return ( error );
192 }
193 
194 /*****************************************************************************/
195 
DetermineVRefNum(ConstStr255Param pathname,short vRefNum,short * realVRefNum)196 static pascal	OSErr	DetermineVRefNum(ConstStr255Param pathname,
197 								 short vRefNum,
198 								 short *realVRefNum)
199 {
200 	HParamBlockRec pb;
201 	OSErr error;
202 
203 	error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
204 	if ( error == noErr )
205 	{
206 		*realVRefNum = pb.volumeParam.ioVRefNum;
207 	}
208 	return ( error );
209 }
210 
211 /*****************************************************************************/
212 
GetCatInfoNoName(short vRefNum,long dirID,ConstStr255Param name,CInfoPBPtr pb)213 static pascal	OSErr GetCatInfoNoName(short vRefNum,
214 							   long dirID,
215 							   ConstStr255Param name,
216 							   CInfoPBPtr pb)
217 {
218 	Str31 tempName;
219 	OSErr error;
220 
221 	/* Protection against File Sharing problem */
222 	if ( (name == NULL) || (name[0] == 0) )
223 	{
224 		tempName[0] = 0;
225 		pb->dirInfo.ioNamePtr = tempName;
226 		pb->dirInfo.ioFDirIndex = -1;	/* use ioDirID */
227 	}
228 	else
229 	{
230 		pb->dirInfo.ioNamePtr = (StringPtr)name;
231 		pb->dirInfo.ioFDirIndex = 0;	/* use ioNamePtr and ioDirID */
232 	}
233 	pb->dirInfo.ioVRefNum = vRefNum;
234 	pb->dirInfo.ioDrDirID = dirID;
235 	error = PBGetCatInfoSync(pb);
236 	pb->dirInfo.ioNamePtr = NULL;
237 	return ( error );
238 }
239 
240 /*****************************************************************************/
241 
GetDirectoryID(short vRefNum,long dirID,ConstStr255Param name,long * theDirID,Boolean * isDirectory)242 static pascal	OSErr	GetDirectoryID(short vRefNum,
243 							   long dirID,
244 							   ConstStr255Param name,
245 							   long *theDirID,
246 							   Boolean *isDirectory)
247 {
248 	CInfoPBRec pb;
249 	OSErr error;
250 
251 	error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
252 	if ( error == noErr )
253 	{
254 		*isDirectory = (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0;
255 		if ( *isDirectory )
256 		{
257 			*theDirID = pb.dirInfo.ioDrDirID;
258 		}
259 		else
260 		{
261 			*theDirID = pb.hFileInfo.ioFlParID;
262 		}
263 	}
264 
265 	return ( error );
266 }
267 
268 /*****************************************************************************/
269 
FSpGetDirectoryID(const FSSpec * spec,long * theDirID,Boolean * isDirectory)270 static pascal	OSErr	FSpGetDirectoryID(const FSSpec *spec,
271 								  long *theDirID,
272 								  Boolean *isDirectory)
273 {
274 	return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name,
275 			 theDirID, isDirectory) );
276 }
277 
278 #endif  /* INLINE_MOREFILES */
279 #endif  /* OS_MAC */
280 
281 /*****************************************************************************
282 *
283 *   Macintosh file utilities
284 *
285 *****************************************************************************/
286 
287 #ifdef OS_MAC
288 
MacPathname2FSSpec(const char * inPathname,FSSpec * outFSS)289 static OSErr MacPathname2FSSpec(const char *inPathname, FSSpec *outFSS)
290 {
291 	OSErr err;
292 	size_t len;
293 	char *p;
294 	short vRefNum;
295 	long dirID;
296 	FSSpec fss;
297 
298 	if (inPathname == NULL || outFSS == NULL) {
299 		return paramErr;
300 	}
301 
302 	err = HGetVol(NULL, &vRefNum, &dirID);  /* default volume and directory */
303 	if (err != noErr) return err;
304 
305 	len = strlen(inPathname);
306 
307 	p = strchr(inPathname, ':');
308 	if (p == NULL) {
309 		/* Partial pathname -- filename only */
310 		Str31 filename;
311 		assert(len <= 31);
312 		c2pstrcpy(filename, inPathname);
313 		err = FSMakeFSSpec(vRefNum, dirID, filename, outFSS);
314 	} else {
315 		Str31 name;
316 		int nameLen;
317 		if (inPathname[0] == ':') {
318 			/* Relative pathname including directory path */
319 
320 		} else {
321 			/* Absolute pathname */
322 			/* Str31 volName;  We would use Str28 if it was defined -- 27, plus 1 for ':'. */
323 			nameLen = p - inPathname;
324 			assert(nameLen <= 27);
325 			name[0] = nameLen + 1;
326 			memcpy(name + 1, inPathname, nameLen + 1);  /* Copy the volume name and the colon. */
327 			err = DetermineVRefNum(name, 0, &vRefNum);
328 			if (err != noErr) return err;
329 			dirID = 2;
330 		}
331 		/* vRefNum and dirID now specify the directory in which we should descend
332 		   the path pointed to by p (pointing to the first colon). */
333 		p++;
334 		while (p != NULL && *p != '\0') {
335 			char *q = strchr(p, ':');
336 			if (q != NULL) {
337 				Boolean isDir;
338 				nameLen = q - p;
339 				assert(nameLen <= 31);
340 				name[0] = nameLen;
341 				memcpy(name + 1, p, nameLen);
342 				err = FSMakeFSSpec(vRefNum, dirID, name, &fss);
343 				if (err != noErr) return err;
344 				if (q[1] == '\0') {
345 					p = NULL;
346 					*outFSS = fss;
347 				} else {
348 					err = FSpGetDirectoryID(&fss, &dirID, &isDir);
349 					assert(isDir == true);
350 					if (err != noErr) return err;
351 					p = q + 1;
352 				}
353 			} else {
354 				q = strchr(p, '\0');  /* go to end of string */
355 				nameLen = q - p;
356 				assert(nameLen > 0);
357 				assert(nameLen <= 31);
358 				c2pstrcpy(name, p);
359 				p = NULL;
360 				err = FSMakeFSSpec(vRefNum, dirID, name, outFSS);
361 			}
362 		}
363 	}
364 	return err;
365 }
366 
367 #if 0
368 static OSErr MacFSSpec2FullPathname(const FSSpec *inFSS, char **outPathname)
369 {
370 	OSErr err;
371 	Handle h;
372 	short fullPathLength;
373 	static char *fullPath = NULL;
374 
375 	if (fullPath != NULL) {
376 		Nlm_Free(fullPath);
377 		fullPath = NULL;
378 	}
379 	err = FSpGetFullPath(inFSS, &fullPathLength, &h);
380 	if (err != noErr) return err;
381 
382 	assert(fullPathLength >= 2);  /* An absolute pathname must be at least two chars long */
383 	fullPath = (char *)Nlm_Malloc(fullPathLength + 1);
384 	if (fullPath == NULL) {
385 		err = memFullErr;
386 	} else {
387 		strncpy(fullPath, *h, fullPathLength);
388 	}
389 
390 	DisposeHandle(h);
391 
392 	*outPathname = fullPath;
393 	return err;
394 }
395 #endif
396 
MacCreateDirectory(const char * inPathname)397 static OSErr MacCreateDirectory(const char *inPathname)
398 {
399 	OSErr err;
400 	FSSpec fss;
401 	ScriptCode scriptTag = 0;
402 	long createdDirID;
403 
404 	err = MacPathname2FSSpec(inPathname, &fss);
405 	if (err != noErr) return err;
406 
407 	err = FSpDirCreate(&fss, scriptTag, &createdDirID);
408 	return err;
409 }
410 
411 #endif
412 
413 /*****************************************************************************
414 *
415 *   FileOpen(filename, mode)
416 *     if (filename == "stdin" or "stdout" or "stderr"
417 *           returns those predefined
418 *           streams on non-windowing systems)
419 *
420 *****************************************************************************/
421 
422 /* p_churchill 12/99 removed MPW conditional compilation
423  */
424 
425 static Nlm_FileOpenHook _hookFile = NULL;
426 
427 
Nlm_FileOpen(const char * filename,const char * mode)428 NLM_EXTERN FILE * LIBCALL Nlm_FileOpen(const char *filename, const char *mode)
429 {
430   FILE *f = NULL;
431 
432   if ( _hookFile )
433     return _hookFile(filename, mode);
434 
435 #if defined(WIN_DUMB)
436     if ( Nlm_HasConsole )
437       {
438         if      ( !StringCmp("stdin",  filename))
439           f = stdin;
440         else if ( !StringCmp("stdout", filename) )
441           f = stdout;
442         else if ( !StringCmp("stderr", filename))
443           f = stderr;
444         else
445           f = fopen(filename, mode);
446 
447 #if defined(WIN32)  &&  ! defined(COMP_METRO)
448         if (strchr(mode, 'b')  &&
449             (f == stdin  ||  f == stdout  ||  f == stderr))
450           setmode(fileno(f), O_BINARY);
451 #endif
452       }
453     else
454       f = fopen(filename, mode);
455 
456 #elif defined(OS_MAC)
457   {
458     OSType    fCreator;
459     Nlm_Int2  fError;
460     FInfo     fInfo;
461     OSType    fType;
462     Nlm_Char  temp [256];
463 
464     Nlm_StringNCpy_0(temp, filename, sizeof(temp));
465     Nlm_CtoPstr ((Nlm_CharPtr) temp);
466     fError = HGetFInfo( 0, 0, (StringPtr) temp, &fInfo);
467     if (fError == noErr) {
468       fCreator = fInfo.fdCreator;
469       fType = fInfo.fdType;
470     } else {
471         fCreator = '    ';
472         if (strchr(mode, 'b') != NULL)
473             fType = '    ';
474         else
475             fType = 'TEXT';
476     }
477     f = fopen( filename, mode);
478 
479     fError = HGetFInfo( 0, 0, (StringPtr) temp, &fInfo);
480     if (fError == noErr) {
481       fInfo.fdCreator = fCreator;
482       fInfo.fdType = fType;
483       fError = HSetFInfo ( 0, 0, (StringPtr) temp,&fInfo);
484     }
485   } /* def OS_MAC */
486 
487 #elif defined(OS_VMS) && defined(DCC4DW12)
488   /* never used */
489   f = fopen (filename, mode);
490   if (f  &&
491       fstat(fileno(f), &statbuf) == 0  &&
492       statbuf.st_fab_rfm == FAB$C_UDF)
493     {
494       fclose(f);
495       f = fopen(filename,mode,"ctx=stm");
496     }
497 
498 #else
499     f = fopen(filename, mode);
500 #endif
501 
502   if (f == NULL)
503     ErrPostEx(SEV_INFO, E_File, E_FOpen, "FileOpen(\"%s\",\"%s\") failed",
504               filename, mode);
505 
506   return f;
507 }
508 
509 /*****************************************************************************
510 *
511 *   SetFileOpenHook(hook)
512 *
513 *****************************************************************************/
514 
Nlm_SetFileOpenHook(Nlm_FileOpenHook hook)515 NLM_EXTERN void LIBCALL Nlm_SetFileOpenHook (Nlm_FileOpenHook hook)
516 {
517 	_hookFile = hook;
518 }
519 
520 /*****************************************************************************
521 *
522 *   FileClose(fp)
523 *
524 *****************************************************************************/
525 
Nlm_FileClose(FILE * stream)526 NLM_EXTERN void LIBCALL  Nlm_FileClose (FILE *stream)
527 {
528   if (stream == NULL)
529     return;
530 
531 #ifdef WIN_DUMB
532   if (stream == stdin  ||  stream == stdout  ||  stream == stderr)
533     {
534 #if defined(WIN32)  &&  ! defined(COMP_METRO)
535       setmode(fileno(stream), O_TEXT);
536 #endif
537       return;
538     }
539 #endif
540 
541   fclose(stream);
542 }
543 
544 /*****************************************************************************
545 *   FileRead(buf, size, fp)
546 *****************************************************************************/
Nlm_FileRead(void * ptr,size_t size,size_t n,FILE * stream)547 NLM_EXTERN size_t LIBCALL Nlm_FileRead
548 (void *ptr, size_t size, size_t n, FILE *stream)
549 {
550   if (n  &&  (SIZE_MAX / n) < size) {
551     ErrPostEx(SEV_WARNING,E_Programmer,0,"FileRead: size > SIZE_MAX");
552     return 0;
553   }
554   if (!ptr  ||  !stream)
555     return 0;
556 
557   return fread(ptr,size,n,stream);
558 }
559 
560 /*****************************************************************************
561 *   FileWrite(buf, size, fp)
562 *****************************************************************************/
Nlm_FileWrite(const void * ptr,size_t size,size_t n,FILE * stream)563 NLM_EXTERN size_t LIBCALL Nlm_FileWrite
564 (const void *ptr, size_t size, size_t n, FILE *stream)
565 {
566     size_t cnt;
567     if (n   &&  (SIZE_MAX / n)  <  size) {
568         ErrPostEx(SEV_WARNING,E_Programmer,0,"FileWrite:  size > SIZE_MAX");
569         return 0;
570     }
571     if (!ptr  ||  !stream || !size)
572         return 0;
573 
574     cnt = fwrite(ptr,size,n,stream);
575     if (cnt != n)
576         ErrPostEx(SEV_FATAL,E_File,E_FWrite,"File write error");
577 
578     return cnt;
579 }
580 
581 /*****************************************************************************
582 *
583 *   FilePuts(ptr, fp)
584 *
585 *****************************************************************************/
Nlm_FilePuts(const char * ptr,FILE * fp)586 NLM_EXTERN int LIBCALL  Nlm_FilePuts (const char *ptr, FILE *fp)
587 {
588 	int retval;
589 
590 	if ((ptr == NULL) || (fp == NULL))
591     	return EOF;
592 	if ((retval = fputs(ptr,fp)) ==EOF)
593 		ErrPostEx(SEV_FATAL,E_File,E_FWrite,"File write error");
594 	return retval;
595 }
596 
597 /*****************************************************************************
598 *
599 *   FileGets()
600 *
601 *****************************************************************************/
Nlm_FileGets(Nlm_CharPtr ptr,size_t size,FILE * fp)602 NLM_EXTERN char * LIBCALL  Nlm_FileGets (Nlm_CharPtr ptr, size_t size, FILE *fp)
603 {
604 #if defined(OS_MAC) || defined (OS_UNIX_DARWIN)
605     int         ch;
606 	int         count;
607 	Nlm_CharPtr tmp;
608 #endif
609 
610 	if ((ptr == NULL) || (size < 1) || (fp == NULL))
611 		return NULL;
612 #if defined(OS_MAC) || defined (OS_UNIX_DARWIN)
613 	ch = fgetc (fp);
614 	count = 0;
615 	tmp = ptr;
616 	while (ch != EOF && ch != '\0' && ch != '\n' && ch != '\r' && count < size - 2) {
617 	  *tmp = ch;
618 	  tmp++;
619 	  count++;
620 	  ch = fgetc (fp);
621 	}
622 	if (ch == '\n' || ch == '\r') {
623 	  *tmp = '\n';
624 	  tmp++;
625 	  count++;
626 	} else if (ch != EOF && ch != '\0') {
627 	  *tmp = ch;
628 	  tmp++;
629 	  count++;
630 	}
631 	*tmp = '\0';
632 	if (count < 1)
633 		return NULL;
634 	return ptr;
635 #else
636 	return fgets(ptr,size,fp);
637 #endif
638 }
639 
640 
641 /*****************************************************************************
642 *
643 *   FileBuildPath()
644 *
645 *****************************************************************************/
Nlm_FileBuildPath(Nlm_CharPtr root,Nlm_CharPtr sub_path,Nlm_CharPtr filename)646 NLM_EXTERN Nlm_CharPtr LIBCALL  Nlm_FileBuildPath (Nlm_CharPtr root, Nlm_CharPtr sub_path, Nlm_CharPtr filename)
647 
648 {
649     Nlm_CharPtr tmp;
650     Nlm_Boolean dir_start = FALSE;
651 #ifdef OS_VMS
652   Nlm_Boolean had_root = FALSE;
653 #endif
654 
655     if (root == NULL)              /* no place to put it */
656         return NULL;
657 
658     tmp = root;
659     if (*tmp != '\0')                /* if not empty */
660     {
661 #ifndef OS_VMS
662         dir_start = TRUE;
663 #else
664         had_root = TRUE;
665 #endif
666         while (*tmp != '\0')
667         {
668 #ifdef OS_VMS
669             if (*tmp == '[')
670                 dir_start = TRUE;
671 #endif
672             tmp++;
673         }
674 
675         if ((*(tmp - 1) != DIRDELIMCHR) && (dir_start))
676         {
677             *tmp = DIRDELIMCHR;
678             tmp++; *tmp = '\0';
679         }
680     }
681 
682     if (sub_path != NULL)
683     {
684 #ifdef OS_VMS
685         if (dir_start)
686         {
687             *(tmp-1) = '.';
688             if (*sub_path == '[')
689                 sub_path++;
690         }
691         else if ((had_root) && (*sub_path != '['))
692         {
693             *tmp = '[';
694             tmp++; *tmp = '\0';
695         }
696 #else
697         if ((dir_start) && (*sub_path == DIRDELIMCHR))
698             sub_path++;
699 #endif
700         tmp = StringMove(tmp, sub_path);
701         if (*(tmp-1) != DIRDELIMCHR)
702         {
703             *tmp = DIRDELIMCHR;
704             tmp++; *tmp = '\0';
705         }
706     }
707 
708     if (filename != NULL)
709         StringMove(tmp, filename);
710 
711     return root;
712 }
713 
714 /*****************************************************************************
715 *
716 *   FileNameFind()
717 *
718 *****************************************************************************/
Nlm_FileNameFind(Nlm_CharPtr pathname)719 NLM_EXTERN Nlm_CharPtr LIBCALL Nlm_FileNameFind (Nlm_CharPtr pathname)
720 
721 {
722   Nlm_CharPtr  filename;
723   Nlm_Int2     len;
724 
725   if (pathname != NULL) {
726     len = Nlm_StringLen (pathname);
727     filename = &(pathname [len]);
728     while (len > 0 && pathname [len - 1] != DIRDELIMCHR) {
729       len--;
730       filename--;
731     }
732     return filename;
733   } else {
734     return NULL;
735   }
736 }
737 
738 
739 /*****************************************************************************
740 *
741 *   FilePathFind()
742 *
743 *****************************************************************************/
Nlm_FilePathFind(const Nlm_Char * fullname)744 NLM_EXTERN Nlm_CharPtr LIBCALL Nlm_FilePathFind(const Nlm_Char* fullname)
745 {
746   Nlm_CharPtr str;
747   size_t	     len = Nlm_StringLen(fullname);
748   if ( !len )
749     return 0;
750 
751   while (len  &&  fullname[len] != DIRDELIMCHR)
752     len--;
753 
754   str = (Nlm_Char*)Nlm_MemGet(len + 1, MGET_ERRPOST);
755   Nlm_MemCpy(str, fullname, len);
756   str[len] = '\0';
757   return str;
758 }
759 
760 
761 /*****************************************************************************
762 *
763 *   FileLength()
764 *
765 *****************************************************************************/
Nlm_FileLength(Nlm_CharPtr fileName)766 NLM_EXTERN Nlm_Int8 LIBCALL Nlm_FileLength(Nlm_CharPtr fileName)
767 {
768   Nlm_Int8 file_len = Nlm_FileLengthEx(fileName);
769   return (file_len > 0) ? file_len : 0;
770 }
771 
772 
773 /*****************************************************************************
774 *
775 *   FileLengthEx()
776 *
777 *****************************************************************************/
Nlm_FileLengthEx(const Nlm_Char * fileName)778 NLM_EXTERN Nlm_Int8 LIBCALL Nlm_FileLengthEx(const Nlm_Char* fileName)
779 {
780   if (!fileName  ||  !*fileName)
781     return -1;
782 
783 #ifdef OS_MAC
784   {{
785     OSErr           err;
786     HParamBlockRec  params;
787     Nlm_Char        path[256];
788 
789 	Nlm_MemSet ((Nlm_VoidPtr) &params, 0, sizeof (HParamBlockRec));
790     Nlm_StringNCpy_0(path, fileName, sizeof(path));
791     Nlm_CtoPstr((Nlm_CharPtr) path);
792     params.fileParam.ioNamePtr = (StringPtr)path;
793     params.fileParam.ioVRefNum = 0;
794     params.fileParam.ioFDirIndex = 0;
795     err = PBHGetFInfo(&params, FALSE);
796     return (err == noErr) ?
797             params.fileParam.ioFlLgLen : -1;
798   }}
799 #else
800   {{
801     struct stat sbuf;
802     return (stat(fileName, &sbuf) == 0) ? sbuf.st_size : -1;
803   }}
804 #endif
805 }
806 
807 
808 /*****************************************************************************
809 *
810 *   FileDelete()
811 *
812 *****************************************************************************/
Nlm_FileRemove(Nlm_CharPtr fileName)813 NLM_EXTERN Nlm_Boolean LIBCALL Nlm_FileRemove (Nlm_CharPtr fileName)
814 
815 {
816   Nlm_Char  local [256];
817 
818   if (fileName != NULL && fileName [0] != '\0') {
819     Nlm_StringNCpy_0(local, fileName, sizeof(local));
820     return (Nlm_Boolean) (remove (local) == 0);
821   } else {
822     return FALSE;
823   }
824 }
825 
826 /*****************************************************************************
827 *
828 *   FileRename()
829 *
830 *****************************************************************************/
Nlm_FileRename(Nlm_CharPtr oldFileName,Nlm_CharPtr newFileName)831 NLM_EXTERN Nlm_Boolean LIBCALL Nlm_FileRename (Nlm_CharPtr oldFileName, Nlm_CharPtr newFileName)
832 
833 {
834   Nlm_Char  localnew [256];
835   Nlm_Char  localold [256];
836 
837   if (oldFileName != NULL && oldFileName [0] != '\0'
838     && newFileName != NULL && newFileName [0] != '\0') {
839     Nlm_StringNCpy_0(localold, oldFileName, sizeof(localold));
840     Nlm_StringNCpy_0(localnew, newFileName, sizeof(localnew));
841     return (Nlm_Boolean) (rename (localold, localnew) == 0);
842   } else {
843     return FALSE;
844   }
845 }
846 
847 /*****************************************************************************
848 *
849 *   FileCreate()
850 *
851 *****************************************************************************/
852 #ifdef OS_MAC
Nlm_GetOSType(Nlm_CharPtr str,OSType dfault)853 static OSType Nlm_GetOSType (Nlm_CharPtr str, OSType dfault)
854 
855 {
856   OSType  rsult;
857 
858   rsult = dfault;
859   if (str != NULL && str [0] != '\0') {
860     rsult = *(OSType*) str;
861   }
862   return rsult;
863 }
864 #endif
865 
Nlm_FileCreate(Nlm_CharPtr fileName,Nlm_CharPtr type,Nlm_CharPtr creator)866 NLM_EXTERN void LIBCALL Nlm_FileCreate (Nlm_CharPtr fileName, Nlm_CharPtr type, Nlm_CharPtr creator)
867 
868 {
869 #ifdef OS_MAC
870   Nlm_Int2  fError;
871   Nlm_Char  temp [256];
872   OSType    fType;
873   OSType    fCreator;
874   FSSpec    spec;
875 #else
876   FILE      *fp;
877 #endif
878 
879   if (fileName != NULL && fileName [0] != '\0') {
880 
881 #ifdef OS_MAC
882     /* note: the following assumes either full pathname or that the current
883        directory is the proper location to find/create the file */
884 
885     Nlm_StringNCpy_0(temp, fileName, sizeof(temp));
886     Nlm_CtoPstr ( temp);
887     fError = FSMakeFSSpec( 0, 0, (StringPtr)temp, &spec);
888 
889     /* file not found, so create it... */
890     if( fError == fnfErr){
891         fType = Nlm_GetOSType (type, 'TEXT');
892         fCreator = Nlm_GetOSType (creator, '    ');
893         FSpCreate( &spec, fCreator, fType, smSystemScript);
894     }
895 #else
896     fp = Nlm_FileOpen (fileName, "w");
897     if (fp != NULL) {
898       Nlm_FileClose (fp);
899     }
900 #endif
901   }
902 }
903 
904 /*****************************************************************************
905 *
906 *   CreateDir(pathname)
907 *
908 *****************************************************************************/
909 
910 #ifdef OS_MAC
Nlm_CreateDir(Nlm_CharPtr pathname)911 NLM_EXTERN Nlm_Boolean LIBCALL  Nlm_CreateDir (Nlm_CharPtr pathname)
912 {
913   if (pathname != NULL && pathname [0] != '\0') {
914     OSErr err;
915     err = MacCreateDirectory(pathname);
916     return (Nlm_Boolean) (err == noErr || err == dupFNErr);
917   }
918   return FALSE;
919 }
920 #endif
921 
922 #ifndef OS_MAC
Nlm_CreateDir(Nlm_CharPtr pathname)923 NLM_EXTERN Nlm_Boolean LIBCALL  Nlm_CreateDir (Nlm_CharPtr pathname)
924 {
925 #ifndef OS_VMS
926   size_t          len;
927   Nlm_Char        path[PATH_MAX];
928 #endif
929 #ifdef OS_UNIX
930   mode_t          oldmask;
931 #endif
932   Nlm_Boolean     rsult = FALSE;
933 
934   if (pathname != NULL && pathname [0] != '\0') {
935 #if defined(OS_MSWIN) || defined(OS_NT)
936     Nlm_StringNCpy_0(path, pathname, sizeof(path));
937     len = Nlm_StringLen (path);
938     if (len > 0 && path [len - 1] == DIRDELIMCHR) {
939         path [len - 1] = '\0';
940     }
941     rsult = (Nlm_Boolean) (mkdir ((char *) path) == 0);
942     if (errno == EACCES) { /* it's O.K. if it was already there */
943 	rsult = TRUE;
944     }
945 #endif
946 #ifdef OS_UNIX
947     oldmask = umask (0000);
948     Nlm_StringNCpy_0(path, pathname, sizeof(path));
949     len = Nlm_StringLen (path);
950     if (len > 0 && path [len - 1] == DIRDELIMCHR) {
951         path [len - 1] = '\0';
952     }
953     rsult = (Nlm_Boolean) (mkdir ((char *) path, 0755) == 0);
954     if (errno == EEXIST) { /* it's O.K. if it was already there */
955 	rsult = TRUE;
956     }
957     umask (oldmask);
958 #endif
959 #ifdef OS_VMS
960     rsult = (Nlm_Boolean) (mkdir ((char *) pathname, 0755) == 0);
961 #endif
962   }
963   return rsult;
964 }
965 #endif
966 
967 /*****************************************************************************
968 *
969 *   DirectoryContents()
970 *
971 *****************************************************************************/
972 
973 #ifdef OS_UNIX_DARWIN
974 #include <dirent.h>
975 #endif
976 
Nlm_DirCatalog(Nlm_CharPtr pathname)977 NLM_EXTERN ValNodePtr LIBCALL Nlm_DirCatalog (Nlm_CharPtr pathname)
978 
979 {
980 #ifdef OS_MAC
981   long            dirID;
982   OSErr           err;
983   short           index;
984   unsigned short  num;
985   Nlm_Char        path[PATH_MAX];
986   CInfoPBRec      pbc;
987   HParamBlockRec  pbh;
988   short           vRefNum;
989 #endif
990 #ifdef OS_UNIX
991   Nlm_Uint1       choice;
992 #ifdef OS_UNIX_DARWIN
993   DIR             *dirp;
994   struct dirent   *dep;
995 #else
996   Nlm_Char        buf [256];
997   Nlm_Char        ch;
998   Nlm_Char        cmmd [PATH_MAX + 20];
999   FILE            *fp;
1000   Nlm_CharPtr     ptr;
1001 #endif
1002 #endif
1003   ValNodePtr      vnp = NULL;
1004 
1005   if (pathname != NULL && pathname [0] != '\0') {
1006 #ifdef OS_MAC
1007     Nlm_StringNCpy_0 (path, pathname, sizeof (path));
1008     Nlm_CtoPstr ((Nlm_CharPtr) path);
1009     Nlm_MemSet ((Nlm_VoidPtr) (&pbh), 0, sizeof (HParamBlockRec));
1010     pbh.volumeParam.ioNamePtr = (StringPtr) path;
1011     pbh.volumeParam.ioVolIndex = -1;
1012     err = PBHGetVInfo (&pbh, FALSE);
1013     if (err != noErr) return NULL;
1014     vRefNum = pbh.volumeParam.ioVRefNum;
1015     Nlm_StringNCpy_0 (path, pathname, sizeof (path));
1016     Nlm_CtoPstr ((Nlm_CharPtr) path);
1017     Nlm_MemSet ((Nlm_VoidPtr) (&pbc), 0, sizeof (CInfoPBRec));
1018     pbc.dirInfo.ioNamePtr = (StringPtr) path;
1019     pbc.dirInfo.ioVRefNum = vRefNum;
1020     err = PBGetCatInfo (&pbc, FALSE);
1021     if (err != noErr) return NULL;
1022     if (pbc.dirInfo.ioFlAttrib & 16) {
1023       num = pbc.dirInfo.ioDrNmFls;
1024       dirID = pbc.dirInfo.ioDrDirID;
1025       for (index = 1; index <= num; index++) {
1026         Nlm_MemSet ((Nlm_VoidPtr) (&pbc), 0, sizeof (CInfoPBRec));
1027         pbc.dirInfo.ioNamePtr = (StringPtr) path;
1028         pbc.dirInfo.ioVRefNum = vRefNum;
1029         pbc.dirInfo.ioFDirIndex = index;
1030         pbc.dirInfo.ioDrDirID = dirID;
1031         pbc.dirInfo.ioACUser = 0;
1032         err = PBGetCatInfo (&pbc, FALSE);
1033         if (err == noErr) {
1034           Nlm_PtoCstr ((Nlm_CharPtr) path);
1035           if (pbc.dirInfo.ioFlAttrib & 16) {
1036             ValNodeCopyStr (&vnp, 1, path);
1037           } else {
1038             ValNodeCopyStr (&vnp, 0, path);
1039           }
1040         }
1041       }
1042     }
1043 #endif
1044 #if defined(WIN32)
1045     {{
1046       Nlm_Char x_path[PATH_MAX];
1047       WIN32_FIND_DATA fData;
1048       HANDLE hFindFile;
1049       Nlm_StringNCpy_0(x_path, pathname, sizeof(x_path) - 5);
1050       Nlm_StringCat(x_path, "\\*.*");
1051       hFindFile = FindFirstFile(x_path, &fData);
1052       if (hFindFile == INVALID_HANDLE_VALUE)
1053         return 0;
1054       do {
1055         if (fData.cFileName[0] != '.'  ||
1056             (fData.cFileName[1] != '.'  &&  fData.cFileName[1] != '\0'))
1057           ValNodeCopyStr
1058             (&vnp, (fData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0,
1059              fData.cFileName);
1060       } while ( FindNextFile(hFindFile, &fData) );
1061       FindClose(hFindFile);
1062     }}
1063 #endif
1064 #ifdef OS_UNIX
1065 #ifdef OS_UNIX_DARWIN
1066     dirp = opendir(pathname);
1067     if (dirp == NULL) return NULL;
1068     while ((dep = readdir(dirp)) != NULL) {
1069       /* ignore 'invisible' files. */
1070       if (dep->d_namlen < 1 || dep->d_name[0] == '.')
1071         continue;
1072       if (dep->d_type == DT_DIR) /* directory */
1073         choice = 1;
1074       else          /* all other file types. */
1075         choice = 0;
1076       ValNodeCopyStr (&vnp, choice, dep->d_name);
1077     }
1078     closedir(dirp);
1079 #else
1080     sprintf (cmmd, "ls -1p %s 2>/dev/null", pathname);
1081     fp = popen (cmmd, "r");
1082     if (fp == NULL) return NULL;
1083     while (Nlm_FileGets (buf, sizeof (buf), fp) != NULL) {
1084       ptr = buf;
1085       ch = *ptr;
1086       while (ch != '\0' && ch != '\n' && ch != '\r') {
1087         ptr++;
1088         ch = *ptr;
1089       }
1090       *ptr = '\0';
1091       choice = 0;
1092       ptr = Nlm_StringChr (buf, '/');
1093       if (ptr != NULL) {
1094         *ptr = '\0';
1095         choice = 1;
1096       }
1097       ValNodeCopyStr (&vnp, choice, buf);
1098     }
1099     pclose (fp);
1100 #endif
1101 #endif
1102 #ifdef OS_VMS
1103 #endif
1104   }
1105   return vnp;
1106 }
1107 
1108 /*****************************************************************************
1109 *
1110 *   general file recursion functio
1111 *
1112 *****************************************************************************/
1113 
Nlm_DirExplore(Nlm_CharPtr directory,Nlm_CharPtr filter,Nlm_CharPtr suffix,Nlm_Boolean recurse,Nlm_DirExpProc proc,Nlm_VoidPtr userdata)1114 NLM_EXTERN Nlm_Int4 Nlm_DirExplore (
1115   Nlm_CharPtr directory,
1116   Nlm_CharPtr filter,
1117   Nlm_CharPtr suffix,
1118   Nlm_Boolean recurse,
1119   Nlm_DirExpProc proc,
1120   Nlm_VoidPtr userdata
1121 )
1122 
1123 {
1124   Nlm_Int4     count = 0;
1125   Nlm_Char     file [FILENAME_MAX], path [PATH_MAX];
1126   size_t       len, suflen = 0;
1127   Nlm_CharPtr  ptr, str;
1128   ValNodePtr   head, vnp;
1129 
1130   if (proc == NULL) return 0;
1131   if (Nlm_StringHasNoText (directory) /* || Nlm_StringHasNoText (suffix) */ ) return 0;
1132 
1133   if (Nlm_StringDoesHaveText (suffix)) {
1134     suflen = Nlm_StringLen (suffix);
1135   }
1136 
1137   /* get list of all files in source directory */
1138 
1139   head = Nlm_DirCatalog (directory);
1140 
1141   for (vnp = head; vnp != NULL; vnp = vnp->next) {
1142     if (vnp->choice == 0) {
1143       str = (Nlm_CharPtr) vnp->data.ptrvalue;
1144       if (! Nlm_StringHasNoText (str)) {
1145 
1146         /* check end of filename for indicated suffix */
1147 
1148         len = Nlm_StringLen (str);
1149         ptr = NULL;
1150         if (len > suflen) {
1151           if (Nlm_StringCmp (str + len - suflen, suffix) == 0) {
1152             ptr = str + len - suflen;
1153             *ptr = '\0';
1154           }
1155         }
1156 
1157         if (Nlm_StringHasNoText (suffix) || ptr != NULL) {
1158 
1159           Nlm_StringNCpy_0 (path, directory, sizeof (path));
1160           sprintf (file, "%s%s", str, suffix);
1161           Nlm_FileBuildPath (path, NULL, file);
1162 
1163           /* check file name (NOT full path) for desired filter */
1164 
1165           if (Nlm_StringHasNoText (filter) || Nlm_StringStr (file, filter) != NULL) {
1166 
1167             /* process file that satisfies optional filter and suffix constraints */
1168 
1169             proc (path, userdata);
1170             count++;
1171           }
1172         }
1173       }
1174     } else if (vnp->choice == 1 && recurse) {
1175 
1176       /* recurse into subdirectory */
1177 
1178       Nlm_StringNCpy_0 (path, directory, sizeof (path));
1179       str = (Nlm_CharPtr) vnp->data.ptrvalue;
1180       Nlm_FileBuildPath (path, str, NULL);
1181 
1182       count += Nlm_DirExplore (path, filter, suffix, recurse, proc, userdata);
1183     }
1184   }
1185 
1186   /* clean up file list */
1187 
1188   ValNodeFreeData (head);
1189 
1190   return count;
1191 }
1192 
1193 /*****************************************************************************
1194 *
1195 *   TmpNam()
1196 *
1197 *****************************************************************************/
Nlm_TmpNam(Nlm_CharPtr s)1198 NLM_EXTERN Nlm_CharPtr LIBCALL Nlm_TmpNam (Nlm_CharPtr s)
1199 
1200 {
1201 #ifdef TEMPNAM_AVAIL
1202     char *filename;
1203     static Nlm_Char save_filename[PATH_MAX];
1204 
1205     /* emulate tmpnam(), except get the benefits of tempnam()'s ability to */
1206     /* place the files in another directory specified by the environment   */
1207     /* variable TMPDIR                                                     */
1208 #ifdef OS_UNIX_DARWIN
1209     filename = tempnam("/tmp", "ncbi.");
1210 #else
1211     filename = tempnam(NULL, NULL);
1212 #endif
1213     if (s == NULL)
1214     { /* return pointer to static string */
1215         if (filename != NULL) {
1216           strcpy ((char *) save_filename, (char *) filename);
1217           free ((void *) filename);
1218         } else {
1219           save_filename [0] = '\0';
1220         }
1221         return save_filename;
1222     } else {
1223         if (filename != NULL) {
1224           strcpy ((char *) save_filename, (char *) filename);
1225           Nlm_StrCpy (s, save_filename);
1226           free ((void *) filename);
1227         } else {
1228           *s = '\0';
1229         }
1230         return s;
1231     }
1232 #else
1233 #ifdef OS_MAC
1234     static Nlm_Char  directory [PATH_MAX];
1235     OSErr        err;
1236     long         gesResponse;
1237     long         newDirID;
1238     short        newVRefNum;
1239     CInfoPBRec   params;
1240     Nlm_Char     temp [PATH_MAX];
1241     Nlm_CharPtr  tmp;
1242     Nlm_Boolean  useTempFolder;
1243     char * filename;
1244 
1245     useTempFolder = FALSE;
1246     if (! Gestalt (gestaltFindFolderAttr, &gesResponse) &&
1247         (gesResponse & (1 << gestaltFindFolderPresent))) {
1248       err = FindFolder(kOnSystemDisk, kTemporaryFolderType,
1249                        kCreateFolder, &newVRefNum, &newDirID);
1250       if (err == noErr) {
1251         useTempFolder = TRUE;
1252       }
1253     }
1254     filename = tmpnam (NULL);
1255     if (useTempFolder) {
1256       temp [0] = '\0';
1257       params.dirInfo.ioNamePtr = (StringPtr) directory;
1258       params.dirInfo.ioDrParID = newDirID;
1259       do {
1260         params.dirInfo.ioVRefNum = newVRefNum;
1261         params.dirInfo.ioFDirIndex = -1;
1262         params.dirInfo.ioDrDirID = params.dirInfo.ioDrParID;
1263         err = PBGetCatInfo (&params, FALSE);
1264         Nlm_PtoCstr ((Nlm_CharPtr) directory);
1265         Nlm_StringCat (directory, DIRDELIMSTR);
1266         Nlm_StringCat (directory, temp);
1267         Nlm_StringCpy (temp, directory);
1268       } while (params.dirInfo.ioDrDirID != fsRtDirID);
1269       tmp = Nlm_StringMove (directory, temp);
1270       tmp = Nlm_StringMove (tmp, (Nlm_CharPtr) filename);
1271       if (s == NULL) {
1272           return (Nlm_CharPtr) directory;
1273       } else {
1274           s [0] = '\0';
1275           Nlm_StringCpy (s, directory);
1276           return s;
1277       }
1278     } else {
1279       if (s == NULL) {
1280           return (Nlm_CharPtr) filename;
1281       } else {
1282           s [0] = '\0';
1283           Nlm_StringCpy (s, filename);
1284           return s;
1285       }
1286     }
1287 #else
1288     char * filename;
1289 
1290     filename = tmpnam (NULL);
1291     if (s == NULL) {
1292         return (Nlm_CharPtr) filename;
1293     } else {
1294         s [0] = '\0';
1295         Nlm_StringCpy (s, filename);
1296         return s;
1297     }
1298 #endif
1299 #endif
1300 }
1301 
1302 /* FileCache provides buffered text read for handling Unix, Mac, and DOS line endings gracefully */
1303 
1304 /* attach file pointer (text read mode expected) to cache object (usually on stack) */
1305 
1306 #ifdef OS_MSWIN
1307 #include <fcntl.h>
1308 #include <io.h>
1309 #endif
1310 
Nlm_FileCacheSetup(Nlm_FileCache PNTR fcp,FILE * fp)1311 NLM_EXTERN Nlm_Boolean Nlm_FileCacheSetup (
1312   Nlm_FileCache PNTR fcp,
1313   FILE *fp
1314 )
1315 
1316 {
1317   if (fp == NULL || fcp == NULL) return FALSE;
1318 
1319 #ifdef OS_MSWIN
1320   _setmode (_fileno (fp), _O_BINARY);
1321 #endif
1322 
1323   MemSet ((Nlm_VoidPtr) fcp, 0, sizeof (Nlm_FileCache));
1324 
1325   fcp->failed = FALSE;
1326 
1327   fcp->fp = fp;
1328   fcp->offset = ftell (fp);
1329 
1330   if (fcp->offset < 0) {
1331     fcp->failed = TRUE;
1332     return FALSE;
1333   }
1334 
1335   return TRUE;
1336 }
1337 
Nlm_FileCacheReadBlock(Nlm_FileCache PNTR fcp)1338 static void Nlm_FileCacheReadBlock (
1339   Nlm_FileCache PNTR fcp
1340 )
1341 
1342 {
1343   int  total;
1344 
1345   if (fcp == NULL || fcp->fp == NULL || fcp->failed) return;
1346 
1347   if (fcp->ctr >= fcp->total) {
1348     fcp->offset += (Nlm_Int4) fcp->total;
1349     fcp->ctr = 0;
1350     fcp->total = 0;
1351 
1352     if (fcp->offset < 0) {
1353       fcp->failed = TRUE;
1354       ErrPostEx(SEV_WARNING,E_Programmer,0,"FileCacheReadBlock negative position %ld", (long) (fcp->offset));
1355       return;
1356     }
1357 
1358     fcp->buf [0] = '\0';
1359     total = (int) Nlm_FileRead ((Nlm_VoidPtr) fcp->buf, sizeof (Nlm_Char), (size_t) 512, fcp->fp);
1360     if (total < 0 || total > 512) {
1361       total = 512;
1362     }
1363 
1364     fcp->buf [total] = '\0';
1365     fcp->total = /* Nlm_StringLen (fcp->buf) */ total;
1366   }
1367 }
1368 
1369 /* equivalent of getc */
1370 
Nlm_FileCacheGetChar(Nlm_FileCache PNTR fcp)1371 static Nlm_Char Nlm_FileCacheGetChar (
1372   Nlm_FileCache PNTR fcp
1373 )
1374 
1375 {
1376   Nlm_Char  ch = '\0', nxt;
1377 
1378   if (fcp == NULL || fcp->fp == NULL || fcp->failed) return ch;
1379 
1380   /* read a fresh block if buffer is empty */
1381 
1382   if (fcp->ctr >= fcp->total) {
1383     Nlm_FileCacheReadBlock (fcp);
1384     if (fcp->failed) return '\0';
1385   }
1386 
1387   /* get next character in buffer */
1388 
1389   if (fcp->ctr < fcp->total) {
1390     ch = fcp->buf [(int) fcp->ctr];
1391     (fcp->ctr)++;
1392   }
1393 
1394   if (ch == '\n' || ch == '\r') {
1395 
1396     /* look for carriage return / linefeed pair - DOS file read on Mac or Unix platform */
1397 
1398     if (fcp->ctr >= fcp->total) {
1399       Nlm_FileCacheReadBlock (fcp);
1400       if (fcp->failed) return '\0';
1401     }
1402     if (fcp->ctr < fcp->total) {
1403 
1404       nxt = fcp->buf [(int) fcp->ctr];
1405 
1406       /* advance past second character in cr/lf pair */
1407 
1408       if (ch == '\n' && nxt == '\r') {
1409         (fcp->ctr)++;
1410       } else if (ch == '\r' && nxt == '\n') {
1411         (fcp->ctr)++;
1412       }
1413     }
1414 
1415     /* cr or lf returned as newline */
1416 
1417     ch = '\n';
1418 
1419   } else if (ch == '\0') {
1420 
1421     /* look for unicode carriage return / linefeed */
1422 
1423     if (fcp->ctr >= fcp->total) {
1424       Nlm_FileCacheReadBlock (fcp);
1425       if (fcp->failed) return '\0';
1426     }
1427     if (fcp->ctr < fcp->total) {
1428 
1429       nxt = fcp->buf [(int) fcp->ctr];
1430 
1431       /* return newline if second character is cr or lf */
1432 
1433       if (nxt == '\n' || nxt == '\r') {
1434         (fcp->ctr)++;
1435         ch = '\n';
1436       }
1437     }
1438   }
1439 
1440   return ch;
1441 }
1442 
1443 /* equivalent of fgets, leaves /n at end of string */
1444 
Nlm_FileCacheGetString(Nlm_FileCache PNTR fcp,Nlm_CharPtr str,size_t size)1445 NLM_EXTERN Nlm_CharPtr Nlm_FileCacheGetString (
1446   Nlm_FileCache PNTR fcp,
1447   Nlm_CharPtr str,
1448   size_t size
1449 )
1450 
1451 {
1452   Nlm_Char     ch;
1453   Nlm_Uint2     count;
1454   Nlm_CharPtr  ptr;
1455 
1456   if (fcp == NULL || fcp->fp == NULL || fcp->failed || str == NULL || size < 1) return NULL;
1457 
1458   ch = Nlm_FileCacheGetChar (fcp);
1459   if (fcp->failed) return NULL;
1460   count = 0;
1461   ptr = str;
1462 
1463   while (ch != '\0' && ch != '\n' && ch != '\r' && count < size - 2) {
1464     *ptr = ch;
1465     ptr++;
1466     count++;
1467     ch = Nlm_FileCacheGetChar (fcp);
1468     if (fcp->failed) return NULL;
1469   }
1470 
1471   if (ch == '\n' || ch == '\r') {
1472     *ptr = '\n';
1473     ptr++;
1474     count++;
1475   } else if (ch != '\0') {
1476     *ptr = ch;
1477     ptr++;
1478     count++;
1479   }
1480   *ptr = '\0';
1481 
1482   if (count < 1) return NULL;
1483 
1484   return str;
1485 }
1486 
1487 /* smarter fgets removes newline from end of string */
1488 
Nlm_FileCacheReadLine(Nlm_FileCache PNTR fcp,Nlm_CharPtr str,size_t size,Nlm_BoolPtr nonewline)1489 NLM_EXTERN Nlm_CharPtr Nlm_FileCacheReadLine (
1490   Nlm_FileCache PNTR fcp,
1491   Nlm_CharPtr str,
1492   size_t size,
1493   Nlm_BoolPtr nonewline
1494 )
1495 
1496 {
1497   Nlm_Char     ch;
1498   Nlm_CharPtr  ptr;
1499   Nlm_CharPtr  tmp;
1500 
1501   if (fcp == NULL || fcp->fp == NULL || fcp->failed || str == NULL || size < 1) return NULL;
1502   *str = '\0';
1503   tmp = Nlm_FileCacheGetString (fcp, str, size);
1504   if (fcp->failed) return NULL;
1505   if (tmp != NULL) {
1506     ptr = str;
1507     ch = *ptr;
1508     while (ch != '\0' && ch != '\n' && ch != '\r') {
1509       ptr++;
1510       ch = *ptr;
1511     }
1512     *ptr = '\0';
1513     if (nonewline != NULL) {
1514       if (ch != '\n' && ch != '\r') {
1515         *nonewline = TRUE;
1516       } else {
1517         *nonewline = FALSE;
1518       }
1519     }
1520   }
1521   return tmp;
1522 }
1523 
Nlm_FileCacheSeek(Nlm_FileCache PNTR fcp,Nlm_Int4 pos)1524 NLM_EXTERN void Nlm_FileCacheSeek (
1525   Nlm_FileCache PNTR fcp,
1526   Nlm_Int4 pos
1527 )
1528 
1529 {
1530   if (fcp == NULL || fcp->fp == NULL || fcp->failed) return;
1531 
1532   /*
1533   if (fcp->offset <= pos && fcp->offset + (Nlm_Int4) fcp->total >= pos) {
1534     fcp->ctr = (Nlm_Int2) (pos - fcp->offset);
1535     return;
1536   }
1537   */
1538 
1539   fcp->ctr = 0;
1540   fcp->total = 0;
1541   fcp->offset = pos;
1542 
1543   if (fcp->offset < 0) {
1544     fcp->failed = TRUE;
1545     ErrPostEx(SEV_WARNING,E_Programmer,0,"FileCacheSeek negative position %ld", (long) (fcp->offset));
1546     return;
1547   }
1548 
1549   fseek (fcp->fp, pos, SEEK_SET);
1550 }
1551 
Nlm_FileCacheTell(Nlm_FileCache PNTR fcp)1552 NLM_EXTERN Nlm_Int4 Nlm_FileCacheTell (
1553   Nlm_FileCache PNTR fcp
1554 )
1555 
1556 {
1557   Nlm_Int4  bytes;
1558   Nlm_Int4  offset;
1559 
1560   if (fcp == NULL || fcp->fp == NULL || fcp->failed) return 0L;
1561 
1562   offset = ftell (fcp->fp);
1563   bytes = (Nlm_Int4) (fcp->total - fcp->ctr);
1564   offset -= bytes;
1565 
1566   return offset;
1567 }
1568 
Nlm_FileCacheFree(Nlm_FileCache PNTR fcp,Nlm_Boolean restoreFilePos)1569 NLM_EXTERN Nlm_Boolean Nlm_FileCacheFree (
1570   Nlm_FileCache PNTR fcp,
1571   Nlm_Boolean restoreFilePos
1572 )
1573 
1574 {
1575   Nlm_Int4  pos;
1576 
1577   if (fcp == NULL || fcp->fp == NULL || fcp->failed) return FALSE;
1578 
1579   if (restoreFilePos) {
1580 
1581     /* correct position of file pointer */
1582 
1583     pos = Nlm_FileCacheTell (fcp);
1584     fseek (fcp->fp, pos, SEEK_SET);
1585   }
1586 
1587   MemSet ((Nlm_VoidPtr) fcp, 0, sizeof (Nlm_FileCache));
1588 
1589   return TRUE;
1590 }
1591 
1592