NCBI C Toolkit Cross Reference

C/corelib/ncbienv.c


  1 /*   ncbienv.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:  ncbienv.c
 27 *
 28 * Author:  Ostell
 29 *
 30 * Version Creation Date:   7/7/91
 31 *
 32 * $Revision: 6.48 $
 33 *
 34 * File Description:
 35 *       portable environment functions, companions for ncbimain.c
 36 *
 37 * Modifications:
 38 * --------------------------------------------------------------------------
 39 * $Log: ncbienv.c,v $
 40 * Revision 6.48  2009/08/17 19:56:13  lavr
 41 * Delete explicit cast from SetProgramName() argument
 42 *
 43 * Revision 6.47  2009/08/14 18:01:09  lavr
 44 * Use {Get|Set}ProgramName()
 45 *
 46 * Revision 6.46  2007/05/04 13:43:59  kans
 47 * GetOpSysString now checks for Windows VISTA
 48 *
 49 * Revision 6.45  2007/04/06 21:47:56  kans
 50 * Nlm_GetOpSysString checks gestaltSystemVersion and returns actual Mac OS X version
 51 *
 52 * Revision 6.44  2007/04/03 00:39:41  kans
 53 * GetOpSysString does run-time check for Rosetta
 54 *
 55 * Revision 6.43  2005/12/02 13:40:00  rsmith
 56 * In ProgramPath on Mac use case-insensitive compare to check the file extension.
 57 *
 58 * Revision 6.42  2005/12/01 19:52:19  rsmith
 59 * Change impl of Mac's Nlm_ProgramPath_ST to only use CoreFoundation calls.
 60 *
 61 * Revision 6.41  2005/11/28 21:04:25  rsmith
 62 * Don't need to call GetProcess in Mac's ProgramPath
 63 *
 64 * Revision 6.40  2005/11/22 20:53:19  rsmith
 65 * Nlm_ProgramPath on Mac always return path to the .app bundle.
 66 *
 67 * Revision 6.39  2005/11/16 16:36:11  kans
 68 * support for PowerPC and Intel chips for Macintosh
 69 *
 70 * Revision 6.38  2004/10/27 20:00:44  kans
 71 * Ncbienv_FileOpen suppresses missing file error post
 72 *
 73 * Revision 6.37  2004/08/06 20:56:27  kans
 74 * G/SetAppParam on PC no longer uses PrivateProfileString functions - instead it checks USERPROFILE, SYSTEMROOT, and then NCBI environment variables
 75 *
 76 * Revision 6.36  2004/02/11 18:40:00  kans
 77 * enhanced GetOpSysString to report specific version of MS Windows
 78 *
 79 * Revision 6.35  2003/09/19 15:49:20  coulouri
 80 * NetBSD fixes
 81 *
 82 * Revision 6.34  2003/06/24 19:45:39  ucko
 83 * GCC/Darwin: Restore Nlm_IsApplicationPackage and the skeleton of
 84 * Nlm_SetupArguments_ST_Mac.
 85 *
 86 * Revision 6.33  2003/06/24 15:39:42  ucko
 87 * Switch back to the generic Unix ProgramPath code when building Darwin
 88 * binaries with GCC until we find a framework that defines the relevant
 89 * symbols without breaking support for remote execution.
 90 *
 91 * Revision 6.32  2003/06/06 15:01:03  rsmith
 92 * fixed ProgramPath for OS Darwin & Mac, Added IsApplicationPackage for Darwin. ProgramPath on Darwin now returns the seen application not the executable buried in the package.
 93 *
 94 * Revision 6.31  2003/01/29 20:57:36  kans
 95 * added linux, sgi, and solaris intel to GetOpSysString
 96 *
 97 * Revision 6.30  2003/01/29 19:37:14  kans
 98 * added GetOpSysString to return allocated string describing operating system running the program
 99 *
100 * Revision 6.29  2003/01/27 14:54:24  kans
101 * for darwin, also check /Contents/Resources/ of Mac OS X package for initial prepackaged config file
102 *
103 * Revision 6.28  2003/01/17 20:59:02  kans
104 * for Mach-O, try home/Library/Preferences/xxx.cnf first
105 *
106 * Revision 6.27  2002/10/03 16:22:03  kans
107 * changed fgets to Nlm_FileGets
108 *
109 * Revision 6.26  2002/03/28 13:29:08  kans
110 * checks for OS_UNIX_DARWIN (EN)
111 *
112 * Revision 6.25  2001/08/02 14:44:10  vakatov
113 * [OSF1]  NLM_XOPEN_SOURCE_500:: Kludge-fix for the weak-minded native
114 * preprocessor
115 *
116 * Revision 6.24  2001/08/01 16:15:38  vakatov
117 * Rollback to R6.22
118 *
119 * Revision 6.22  2001/05/25 17:58:27  vakatov
120 * [MAC] OpenConfigFile() -- replaced C++ style comments by the C-style ones
121 *
122 * Revision 6.21  2001/05/25 15:44:26  vakatov
123 * [AIX]  Tweaked conditions for NLM_POSIX1B
124 *
125 * Revision 6.20  2001/01/19 20:14:44  kans
126 * added checks for OS_UNIX_DARWIN (contributed by William Van Etten)
127 *
128 * Revision 6.19  2000/10/30 18:11:41  beloslyu
129 * FreeBSD was added
130 *
131 * Revision 6.18  2000/08/30 16:43:23  vakatov
132 * Nlm_WorkGetAppParam() -- do not try to open the same config file
133 * again (and again, and again) if failed to open it just before.
134 *
135 * Revision 6.17  2000/08/28 21:35:48  vakatov
136 * Figure out #LOGNAME_MAX value a little earlier in the code
137 *
138 * Revision 6.16  2000/08/28 18:32:18  vakatov
139 * Nlm_GetHome() -- split for s_GetHomeByUID() + s_GetHomeByLOGIN().
140 * Try s_GetHomeByUID() *before* s_GetHomeByLOGIN() to fix a problem
141 * reported by "Ray.Hookway@compaq.com" for LSF's Remote Execution Server.
142 *
143 * Revision 6.15  2000/06/28 14:50:43  vakatov
144 * Nlm_GetHome() -- IRIX, NLM_POSIX1B, getpwnam_r():  dont rely on the
145 * returned value only;  check for non-zero "pwd_ptr"
146 *
147 * Revision 6.14  2000/06/01 16:57:03  vakatov
148 * [IRIX]  Nlm_GetHome() -- added an extra check for the "pwd_ptr"
149 * (as per request by "Lack Mr G M" from SGI, gml4410@ggr.co.uk)
150 *
151 * Revision 6.13  2000/03/15 20:59:53  kans
152 * Mac version of Nlm_OpenConfigFile was opening file for reading even under writeMode - fixed
153 *
154 * Revision 6.12  1999/12/30 16:36:37  kans
155 * additional cleanup (Churchill)
156 *
157 * Revision 6.11  1999/12/21 18:22:17  kans
158 * new blessed file finding function needed to convert filename back to C string for fopen
159 *
160 * Revision 6.10  1999/12/21 17:52:39  kans
161 * removed MPW/THINKC conditional code, starting upgrade to Carbon compatibility - Churchill
162 *
163 * Revision 6.9  1999/11/29 19:58:49  vakatov
164 * To parse command-line arguments:
165 * + ECmdLineQuote, Nlm_ParseCmdLineArguments(), Nlm_FreeCmdLineArguments()
166 *
167 * Revision 6.8  1999/03/24 22:12:49  vakatov
168 * Nlm_ReadConfigFile():  free "Nlm_bottomComment" to avoid mem.leak
169 *
170 * Revision 6.7  1999/02/12 16:01:39  vakatov
171 * Added a draft version of Nlm_GetEnvParamEx()
172 * Got rid of the old "PROTO" and "LIBCALL" prototype junk, etc.
173 *
174 * Revision 6.6  1998/12/10 17:04:06  vakatov
175 * Fixed to compile under LINUX(Red Hat 2.XX, gcc, with POSIX threads)
176 *
177 * Revision 6.5  1997/11/26 21:26:10  vakatov
178 * Fixed errors and warnings issued by C and C++ (GNU and Sun) compilers
179 *
180 * Revision 6.4  1997/10/29 02:43:31  vakatov
181 * Type castings to pass through the C++ compiler
182 *
183 * Revision 6.3  1997/10/27 21:58:11  vakatov
184 * Added Nlm_FreeArgs() to reset args earlier set by GetArgs[Silent]()
185 *
186 * Revision 6.2  1997/09/09 00:05:43  vakatov
187 * Nlm_x_HasConsole() -- "fileno" instead of "_fileno" to pass Borland compiler
188 *
189 * Revision 6.1  1997/08/27 16:16:38  vakatov
190 * [WIN32] Nlm_x_HasConsole() -- fixed for the case when the
191 * Vibrant-based(GUI) application is run from the console(command prompt)
192 *
193 * Revision 5.18  1997/07/22 19:11:18  vakatov
194 * Separated Main() from GetArg[svc]() functions;  [WIN_MSWIN] converged
195 * console and GUI libraries; [for WIN32-DLL] encapsulated global variables
196 *
197 * Revision 5.17  1997/06/02 15:28:36  vakatov
198 * [WIN32]  Read/write config(*.ini) files via WinSDK calls([WIN_MSWIN]-like)
199 *
200 * Revision 5.16  1997/05/08 19:37:08  vakatov
201 * [WIN_MSWIN]  Nlm_SetupArguments_ST() -- interpret all text(including
202 * space symbols) embraced by a pair of ""(or '') quote marks as a
203 * single command argument;  strip the embracing quote marks
204 *
205 * Revision 5.15  1997/03/05 20:32:55  vakatov
206 * Nlm_WorkGetAppParam: now free Nlm_lastParamFile before reset, avoid mem.leak
207 *
208  * Revision 5.14  1997/03/03  16:44:00  kans
209  * cleanup of memory leaks accidentally freed the cached file name,
210  * so now only the Nlm_envList is freed with Nlm_FreeEnvData
211  *
212  * Revision 5.13  1997/02/27  19:33:48  vakatov
213  * Nlm_ReadConfigFile():  free the obsolete config data --> fight memory leaks
214  *
215  * Revision 5.12  1997/01/28  21:19:12  kans
216  * <Desk.h>, <OSEvents.h> and <GestaltEqu.h> are obsolete in CodeWarrior
217  *
218  * Revision 5.11  1997/01/24  17:03:49  epstein
219  * make threaded version compatible with OSF/1
220  *
221  * Revision 5.10  1997/01/03  16:12:07  vakatov
222  * Fixed inaccurate string copying -- <mostly potential> 1-byte exceeding of
223  * the string size by StringNCat;  missing terminating '\0' by StringNCpy.
224  *
225  * Revision 5.9  1996/12/30  15:13:12  vakatov
226  * [WIN_MSWIN]  Command-line parsing implemented inside Nlm_SetupArguments()
227  *
228  * Revision 5.8  1996/12/16  22:38:53  vakatov
229  * Rolled back the changes made in "* Revision 5.4.  1996/11/27  20:38:14
230  * epstein"
231  *
232  * Revision 5.7  1996/12/04  21:44:47  vakatov
233  * [OS_UNIX][POSIX_THREADS_AVAIL]  Added _POSIX1C case (see Rev.5.5)
234  *
235  * Revision 5.6  1996/12/03  21:48:33  vakatov
236  * Adopted for 32-bit MS-Windows DLLs
237  *
238  * Revision 5.5  1996/11/27  21:55:17  vakatov
239  * [OS_UNIX][POSIX_THREADS_AVAIL]  Added (_POSIX_C_SOURCE - 0 >= 199506L)
240  * preprocessor condition to match POSIX.1c function interface.
241  *
242  * Revision 5.4  1996/11/27  20:38:14  epstein
243  * disable error logging when opening files in parameter fetching functions
244  *
245  * Revision 5.3  1996/11/25  19:04:26  vakatov
246  * Wrapped all basic functions to MT-safe wrappers(named by adding '_ST'
247  * suffix to the original function names).
248  *
249  * Revision 5.2  1996/08/19  18:46:06  vakatov
250  * [WIN32]  Made modifications to let one create console applications
251  *
252  * Revision 4.9  1996/02/15  22:00:49  kans
253  * changed platform symbol back to OS_NT
254  *
255  * Revision 4.8  1996/01/31  20:29:57  epstein
256  * fix uninitialized ptr in Nlm_GetHome()
257  *
258  * Revision 4.7  1996/01/29  22:33:37  epstein
259  * Added GetHome() changes per Mr. G.M. Lack (gml4410@ggr.co.uk)
260  *
261  * Revision 4.6  1995/12/13  17:18:51  kans
262  * fixed caching bug (JE & JK)
263  *
264  * Revision 4.5  1995/10/28  15:03:20  ostell
265  * added casts to quiet DOS compile warnings
266  *
267  * Revision 4.4  1995/10/11  13:53:05  kans
268  * made some variables static
269  *
270  * Revision 4.3  1995/10/06  19:59:18  epstein
271  * more performance fixes
272  *
273  * Revision 4.2  1995/10/06  15:53:31  epstein
274  * add CacheAppParam() and FlushAppParam() for improved performance
275  *
276  * Revision 4.1  1995/10/03  15:59:21  epstein
277  * add NCBI_DONT_USE_LOCAL_CONFIG environment variable to avoid local config files
278  *
279 *  7/7/91   Kans        Multiple configuration files, get and set functions
280 *  9-20-91  Schuler     GetAppParam takes default value as an argument
281 * 01-14-94  Epstein     Merged ncbienv.{unx,vms,dos,msw,mac} into a single file
282 * 06-14-94  Schuler     Put SetAppPropery("ProgramName",..) in SetupArguments
283 * 06-14-94  Schuler     Add LIBCALL to SetupArguments
284 * 08-23-94  Schuler     Add SetupArguments case for OS_NT/WIN_DUMB
285 * 01-29-96  Epstein     Added GetHome() changes per Mr. G.M. Lack
286 *
287 * ==========================================================================
288 */
289 
290 #ifdef OS_MAC
291 #ifdef PROC_MC680X0
292 #define OBSOLETE
293 #endif
294 #endif
295 
296 #include "corepriv.h"
297 
298 #ifdef OS_UNIX
299 #include <pwd.h>
300 #endif /* OS_UNIX */
301 #ifdef OS_MAC
302 #include <Gestalt.h>
303 #include <Folders.h>
304 #include <Processes.h>
305 #include <Script.h>
306 #endif /* OS_MAC */
307 
308 
309 typedef struct nlm_env_item {
310   struct nlm_env_item* next;
311   Nlm_Char*            name;
312   Nlm_Char*            comment;
313   Nlm_Char*            value;
314 } Nlm_env_item, *Nlm_env_itemPtr;
315 
316 typedef struct nlm_env_sect {
317   struct nlm_env_sect* next;
318   Nlm_Char*            name;
319   Nlm_Char*            comment;
320   Nlm_Boolean          transientOnly; /* this field used only by Transient */
321   struct nlm_env_item* children;
322 } Nlm_env_sect, *Nlm_env_sectPtr;
323 
324 typedef struct nlm_env_file {
325   struct nlm_env_file* next;
326   Nlm_Char*            name;
327   Nlm_env_sectPtr      envList;
328 } Nlm_env_file, *Nlm_env_filePtr;
329 
330 
331 static Nlm_env_filePtr Nlm_transientFileList = NULL;
332 static Nlm_Boolean caching = FALSE;
333 static Nlm_Boolean dirty = FALSE;
334 static Nlm_Boolean mustCreateFile = TRUE;
335 
336 static Nlm_Boolean Nlm_Qualified(const Nlm_Char* path);
337 static Nlm_Boolean Nlm_TransientLookup(const Nlm_Char* file, const Nlm_Char* section, const Nlm_Char* type, const Nlm_Char* dflt, Nlm_Char* buf, size_t buflen);
338 static void Nlm_TransientLogSetApp(const Nlm_Char* file, const Nlm_Char* section, const Nlm_Char* type, const Nlm_Char* value);
339 static void Nlm_FreeEnvData(Nlm_env_sectPtr esp);
340 static void Nlm_FreeTransientData(void);
341 
342 static FILE* Nlm_OpenConfigFile(const Nlm_Char* file, Nlm_Boolean writeMode, Nlm_Boolean create);
343 static Nlm_Char* Nlm_TrimString(Nlm_Char* str);
344 static Nlm_Boolean Nlm_ReadConfigFile(FILE* fp);
345 static Nlm_env_sectPtr Nlm_FindConfigSection(const Nlm_Char* section);
346 static Nlm_env_itemPtr Nlm_FindConfigItem(const Nlm_Char* section, const Nlm_Char* type, Nlm_Boolean create);
347 static Nlm_Boolean Nlm_WriteConfigFile(FILE* fp);
348 static void Nlm_PutComment(const Nlm_Char* s, FILE* fp);
349 static void Nlm_FreeConfigFileData(void);
350 static void Nlm_FlushConfigFile(const Nlm_Char* file, Nlm_Boolean create);
351 
352 static Nlm_env_sectPtr Nlm_envList = NULL;
353 static Nlm_Char* Nlm_lastParamFile = NULL;
354 static Nlm_Char* Nlm_bottomComment = NULL;
355 
356 /* always FALSE, because this file is trying to emulating MS Windows's  */
357 /* handling of comments in Param files; however, just change this value */
358 /* to TRUE to turn this approach around                                 */
359 static Nlm_Boolean destroyDeadComments = FALSE;
360 
361 /*****************************************************************************
362 *
363 * The "guts" of:
364 *   Nlm_GetAppParam (file, section, type, dflt, buf, buflen)
365 *      finds parameters from configuration files
366 *      this version, searching for configuration file(s) in a
367 *      platform-dependent basis as handled by Nlm_OpenConfigFile()
368 *
369 *      if configuration file is found, tries to read the parameter from it.
370 *
371 *****************************************************************************/
372 
373 static FILE* LIBCALL Ncbienv_FileOpen (const char *filename, const char *mode)
374 
375 {
376   FILE    *fp;
377   ErrSev  sev;
378 
379   sev = ErrSetMessageLevel (SEV_ERROR);
380   fp = FileOpen (filename, mode);
381   ErrSetMessageLevel (sev);
382   return fp;
383 }
384 
385 static Nlm_Int2 
386 Nlm_WorkGetAppParam(const Nlm_Char* file, 
387                     const Nlm_Char* section, 
388                     const Nlm_Char* type, 
389                     const Nlm_Char* dflt, 
390                     Nlm_Char* buf, 
391                     Nlm_Int2 buflen, 
392                     Nlm_Boolean searchTransient)
393 {
394   Nlm_env_itemPtr  eip;
395   FILE             *fp;
396 
397   if (buf == NULL  ||  buflen <= 0)
398     return 0;
399 
400   *buf = '\0';
401   if (searchTransient  &&
402       Nlm_TransientLookup(file, section, type, dflt, buf, buflen))
403     {
404       return (Nlm_Int2)Nlm_StringLen(buf);
405     }
406 
407   if ( dflt )
408     Nlm_StringNCpy_0(buf, dflt, buflen);
409 
410   if (file    == NULL   ||  *file    == '\0'  ||
411       section == NULL   ||  *section == '\0')
412     return (Nlm_Int2)Nlm_StringLen( buf );
413 
414   if (Nlm_lastParamFile == NULL  ||
415       Nlm_StringICmp(Nlm_lastParamFile, file) != 0)
416     {
417       mustCreateFile = TRUE;
418       if ( caching )
419         Nlm_FlushAppParam();
420       Nlm_FreeConfigFileData();
421       fp = Nlm_OpenConfigFile(file, FALSE, FALSE);
422       MemFree( Nlm_lastParamFile );
423       Nlm_lastParamFile = Nlm_StringSave( file );
424       if (fp != NULL)
425         {
426           Nlm_ReadConfigFile( fp );
427           Nlm_FileClose( fp );
428         }
429     }
430 
431   if (type != NULL  &&  *type != '\0')
432     {
433       eip = Nlm_FindConfigItem(section, type, FALSE);
434       if (eip != NULL)
435         Nlm_StringNCpy_0(buf, eip->value, buflen);
436     }
437   else
438     { /* return all the types in that section */
439       Nlm_env_sectPtr  esp    = Nlm_FindConfigSection( section );
440       Nlm_Int2         totlen = 0;
441       *buf = '\0';
442       if (esp == NULL)
443         return 0;
444 
445       /* traverse the children, allowing the null chars to be inserted */
446       /* in between each type-name                                     */
447       for (eip = esp->children;
448            eip != NULL  &&  totlen != buflen;  eip = eip->next)
449         {
450           Nlm_Int2 bytesToAppend = StrLen(eip->name) + 1;
451           bytesToAppend = MIN(bytesToAppend, buflen - totlen);
452           StrNCpy(&buf[totlen], eip->name, bytesToAppend - 1);
453           totlen += bytesToAppend;
454           buf[totlen - 1] = '\0';
455         }
456     }
457 
458   return (Nlm_Int2)Nlm_StringLen(buf);
459 }
460 
461 
462 /*****************************************************************************
463 *
464 *   Nlm_SetAppParam (file, section, type, value)
465 *      finds paths for types of data and fills in path in buf
466 *      this version
467 *      1)  looks in the current directory for ".filerc", but will not
468 *          create a new file in this directory.
469 *      2)  then looks in the home directory for ".filerc".
470 *      3)  then looks for an environment variable "NCBI" and takes its
471 *          value as a complete path to a directory containing the
472 *          configuration file ".filerc".
473 *      if configuration file is found, tries to write the parameter to it.
474 *
475 *****************************************************************************/
476 
477 static Nlm_Boolean Nlm_SetAppParam_ST(const Nlm_Char* file, const Nlm_Char* section, const Nlm_Char* type, const Nlm_Char* value)
478 {
479   Nlm_env_itemPtr  eip;
480   Nlm_env_sectPtr  esp;
481   FILE             *fp = NULL;
482   Nlm_Boolean      rsult;
483 
484   rsult = FALSE;
485   if (file != NULL && *file != '\0' && section != NULL && *section != '\0') {
486     Nlm_TransientLogSetApp (file, section, type, value);
487 
488     if (Nlm_lastParamFile == NULL || Nlm_StringICmp(Nlm_lastParamFile, file) != 0) {
489       mustCreateFile = TRUE;
490     }
491     if (mustCreateFile)
492       fp = Nlm_OpenConfigFile (file, FALSE, TRUE);
493 
494     if (TRUE) {
495       if (fp != NULL) {
496         Nlm_FlushAppParam();
497         Nlm_FreeConfigFileData();
498         Nlm_lastParamFile = Nlm_StringSave(file);
499         Nlm_ReadConfigFile (fp);
500         Nlm_FileClose (fp);
501         mustCreateFile = FALSE;
502       }
503       if (type != NULL && *type != '\0')
504       {
505         eip = Nlm_FindConfigItem (section, type, TRUE);
506         if (eip != NULL) {
507           if (eip->value != NULL) {
508             eip->value = (Nlm_Char*) Nlm_MemFree (eip->value);
509           }
510           eip->value = Nlm_StringSave (value);
511           rsult = TRUE;
512         }
513       }
514       else { /* wipe out that section */
515         esp = Nlm_FindConfigSection (section);
516         if (esp != NULL) { /* kill section by deleting name (leave comments)*/
517           esp->name = (Nlm_Char*) Nlm_MemFree(esp->name);
518           rsult = TRUE;
519         }
520       }
521 
522       if (rsult) {
523         dirty = TRUE;
524       }
525       if (! caching) {
526         Nlm_FlushConfigFile(file, TRUE);
527       }
528     }
529   }
530 
531   return rsult;
532 }
533 
534 /*****************************************************************************
535 *
536 *   Nlm_FlushAppParam()
537 *      flush the current parameter file's parameters to disk
538 *
539 *****************************************************************************/
540 static void Nlm_FlushAppParam_ST(void)
541 {
542   if (Nlm_lastParamFile != NULL)
543     Nlm_FlushConfigFile(Nlm_lastParamFile, TRUE);
544 }
545 
546 /*****************************************************************************
547 *
548 *   Nlm_CacheAppParam()
549 *      Indicates whether data should be flushed to disk after each call
550 *      to SetAppParam()
551 *
552 *****************************************************************************/
553 static Nlm_Boolean Nlm_CacheAppParam_ST(Nlm_Boolean value)
554 {
555   Nlm_Boolean oldvalue = caching;
556 
557   caching = value;
558   if (! value)
559     Nlm_FlushAppParam();
560 
561   return oldvalue;
562 }
563 
564 
565 #ifdef OS_UNIX
566 
567 /* This is a special kludge for OSF1 native compiler which apparently
568  * cannot handle (_XOPEN_SOURCE == 500) when _XOPEN_SOURCE is defined
569  * to nothing
570  */
571 #if (_XOPEN_SOURCE == 500)
572 #  define NLM_XOPEN_SOURCE_500 1
573 #else
574 #  define NLM_XOPEN_SOURCE_500 0
575 #endif
576 
577 #define NLM_POSIX1B \
578     (_POSIX1B || _POSIX1C || \
579     (_POSIX_C_SOURCE - 0 >= 199309L) || \
580     defined(_POSIX_PTHREAD_SEMANTICS) || \
581     (defined(OS_UNIX_AIX)  &&  NLM_XOPEN_SOURCE_500  &&  !defined(_UNIX95)))
582 
583 #ifndef LOGNAME_MAX
584 #  if defined(MAXLOGNAME)
585 #    define LOGNAME_MAX MAXLOGNAME
586 #  elif defined(_POSIX_LOGIN_NAME_MAX)
587 #    define LOGNAME_MAX _POSIX_LOGIN_NAME_MAX
588 #  endif
589 #endif /* ndef LOGNAME_MAX */
590 
591 
592 /*****************************************************************************
593 *
594 *   Nlm_GetHome (buf, buflen)
595 *      returns the path of the home directory
596 *
597 *****************************************************************************/
598 
599 
600 /* This function is used by Nlm_GetHome(), see below
601  */
602 static Nlm_Boolean s_GetHomeByUID(Nlm_Char* buf, size_t buf_size)
603 {
604     struct passwd* pwd_ptr = 0;
605 
606     /* Get the info using user ID */
607 #if  (defined(SOLARIS_THREADS_AVAIL) || defined(POSIX_THREADS_AVAIL)) && !defined(OS_UNIX_FREEBSD) && !defined(OS_UNIX_DARWIN) && !defined(OS_UNIX_NETBSD)
608     struct passwd pwd;
609     Nlm_Char      pwd_buffer[LOGNAME_MAX + PATH_MAX + 1024 + 1];
610 
611 #  if NLM_POSIX1B
612     if (getpwuid_r(getuid(), &pwd, pwd_buffer, sizeof(pwd_buffer),
613                    &pwd_ptr) != 0) {
614         pwd_ptr = 0;
615     }
616 #  else
617     pwd_ptr = getpwuid_r(getuid(), &pwd, pwd_buffer, sizeof(pwd_buffer));
618 #  endif
619 #else
620     pwd_ptr = getpwuid(getuid());
621 #endif
622 
623     if (!pwd_ptr  ||  pwd_ptr->pw_dir[0] == '\0')
624         return FALSE;
625     Nlm_StringNCpy_0(buf, pwd_ptr->pw_dir, buf_size);
626     return TRUE;
627 }
628 
629 
630 /* This function is used by Nlm_GetHome(), see below
631  */
632 static Nlm_Boolean s_GetHomeByLOGIN(Nlm_Char* buf, Nlm_Int2 buf_size)
633 {
634     struct passwd* pwd_ptr = 0;
635 
636     /* Get the user login name */
637 #if (defined(SOLARIS_THREADS_AVAIL) || defined(POSIX_THREADS_AVAIL)) && !defined(OS_UNIX_FREEBSD) && !defined(OS_UNIX_DARWIN) && !defined(OS_UNIX_NETBSD)
638     struct passwd pwd;
639     Nlm_Char      login_name[LOGNAME_MAX + 1];
640     Nlm_Char      pwd_buffer[LOGNAME_MAX + PATH_MAX + 1024 + 1];
641     Nlm_Boolean   ok = getlogin_r(login_name, sizeof(login_name)) ?
642 #  if NLM_POSIX1B
643         FALSE : TRUE;
644 #  else
645     TRUE : FALSE;
646 #  endif
647 #else
648 
649     Nlm_Char* login_name = getlogin();
650     Nlm_Boolean ok       = (login_name != NULL);
651 #endif
652 
653     /* Get the info using user login-name */
654     if ( !ok )
655         return FALSE;
656 
657 #if (defined(SOLARIS_THREADS_AVAIL) || defined(POSIX_THREADS_AVAIL)) && !defined(OS_UNIX_FREEBSD) && !defined(OS_UNIX_DARWIN) && !defined(OS_UNIX_NETBSD)
658     pwd_ptr = &pwd;
659 #  if NLM_POSIX1B
660     if (getpwnam_r(login_name, &pwd, pwd_buffer, sizeof(pwd_buffer),
661                    &pwd_ptr) != 0) {
662         pwd_ptr = 0;
663     }
664 #  else
665     pwd_ptr = getpwnam_r(login_name, &pwd, pwd_buffer, sizeof(pwd_buffer));
666 #  endif
667 #else
668     pwd_ptr = getpwnam(login_name);
669 #endif
670 
671     if (!pwd_ptr  ||  pwd_ptr->pw_dir[0] == '\0')
672         return FALSE;
673     Nlm_StringNCpy_0(buf, pwd_ptr->pw_dir, buf_size);
674     return TRUE;
675 }
676 
677 
678 static Nlm_Boolean Nlm_GetHome(Nlm_Char* buf, Nlm_Int2 buflen)
679 {
680   static Nlm_Boolean s_Saved = FALSE;
681   static Nlm_Char    s_SaveHome[PATH_MAX + 1];
682   static TNlmMutex   s_SaveHomeMutex;
683 
684   /* Have we passed this way before?  If not, then try get the info. */
685   if ( !s_Saved ) {
686 #if  defined(SOLARIS_THREADS_AVAIL)  ||  defined(POSIX_THREADS_AVAIL)
687     VERIFY_HARD( NlmMutexLockEx( &s_SaveHomeMutex ) == 0 );
688     if ( !s_Saved ) {
689 #endif
690       s_Saved = TRUE;
691 
692       /* Try to retrieve the home dir -- first use user's ID, 
693        * and if failed, then use user's login name.
694        */
695       if (!s_GetHomeByUID(s_SaveHome, sizeof(s_SaveHome))  &&
696           !s_GetHomeByLOGIN(s_SaveHome, sizeof(s_SaveHome))) {
697         s_SaveHome[0] = '\0';
698       }
699 #if  defined(SOLARIS_THREADS_AVAIL)  ||  defined(POSIX_THREADS_AVAIL)
700     }
701     VERIFY_HARD( NlmMutexUnlock(s_SaveHomeMutex) == 0 );
702 #endif
703   }
704   Nlm_StringNCpy_0(buf, s_SaveHome, buflen);
705   return (Nlm_Boolean) (*buf != '\0');
706 }
707 
708 
709 
710 /*****************************************************************************
711 *
712 *   Nlm_OpenConfigFile (file, writeMode, create)
713 *      returns a file pointer to the specified configuration file.
714 *      1)  looks in the current directory for ".filerc", but will not
715 *          create a new file in this directory.
716 *      2)  then looks in the home directory for ".filerc".
717 *      3)  then looks for an environment variable "NCBI" and takes its
718 *          value as a complete path to a directory containing the
719 *          configuration file "filerc" or ".filerc".
720 *
721 *      Steps (1) and (2) above are omitted if the NCBI_DONT_USE_LOCAL_CONFIG
722 *      environment variable is set.  This can be used to allow specific
723 *      production applications to avoid stray .ncbirc files which may have
724 *      been erroneously generated.
725 *
726 *****************************************************************************/
727 
728 static FILE* Nlm_OpenConfigFile(const Nlm_Char* file, Nlm_Boolean writeMode, Nlm_Boolean create)
729 
730 {
731   Nlm_Char  ch;
732   FILE      *fp;
733   Nlm_Int2  i;
734   Nlm_Int2  len;
735   FILE      *newfp;
736   Nlm_Char  path [PATH_MAX+1];
737   char      *pth;
738   Nlm_Char  str [FILENAME_MAX+1];
739   Nlm_Boolean dontUseLocalConfig;
740 
741   fp = NULL;
742   if (file != NULL) {
743 #ifdef OS_UNIX_DARWIN
744     /* For Mach-O executables, check username/Library/Preferences/xxx.cnf first */
745     Nlm_StringNCpy_0(str, file, sizeof(str) - 4);
746     if ( ! Nlm_Qualified (str) ) {
747         /* if the user has already supplied a name with .xxx use that name
748          * otherwise add the .cnf here */
749         Nlm_StringCat(str, ".cnf");
750     }
751     /* if the name isn't all lowercase, make it so now */
752     len = (Nlm_Int2) Nlm_StringLen (str);
753     for (i = 0; i < len; i++) {
754       ch = str [i];
755       str [i] = TO_LOWER (ch);
756     }
757     if (Nlm_GetHome (path, sizeof (path))) {
758       Nlm_FileBuildPath(path, "Library", NULL);
759       Nlm_FileBuildPath(path, "Preferences", NULL);
760       Nlm_FileBuildPath(path, NULL, str);
761       fp = Ncbienv_FileOpen (path, "r");
762       if (fp == NULL && create) {
763         fp = Ncbienv_FileOpen (path, "w");
764         Nlm_FileClose (fp);
765         fp = Ncbienv_FileOpen (path, "r");
766       }
767       if (writeMode && fp != NULL) {
768         Nlm_FileClose (fp);
769         fp = Ncbienv_FileOpen (path, "w");
770       }
771       if (fp != NULL) {
772         return fp;
773       }
774     }
775     /* also check within Contents/Resources of Mac OS X package */
776     ProgramPath (path, sizeof (path));
777     if (IsApplicationPackage(path)) {
778       FileBuildPath(path, "Contents", NULL);
779       FileBuildPath (path, "Resources", NULL);
780       Nlm_FileBuildPath (path, NULL, str);
781       fp = Ncbienv_FileOpen (path, "r");
782       if (fp != NULL) {
783         return fp;
784       }
785     }
786 #endif
787     dontUseLocalConfig = getenv("NCBI_DONT_USE_LOCAL_CONFIG") != NULL;
788     newfp = NULL;
789     Nlm_StringMove(str, ".");
790     Nlm_StringNCat(str, file, sizeof(str) - 4);
791     if ( ! Nlm_Qualified (str))
792     { /* use the user's extension instead of the "rc" extension */
793       Nlm_StringCat(str, "rc");
794     }
795     len = (Nlm_Int2) Nlm_StringLen (str);
796     for (i = 0; i < len; i++) {
797       ch = str [i];
798       str [i] = TO_LOWER (ch);
799     }
800     Nlm_StringNCpy_0(path, str, sizeof(path));
801 
802     if (! dontUseLocalConfig)
803       fp = Ncbienv_FileOpen (path, "r");
804     if (fp == NULL) {
805       if (Nlm_GetHome (path, sizeof (path))) {
806         Nlm_FileBuildPath(path, NULL, str);
807       } else {
808         Nlm_StringNCpy_0(path, str, sizeof(path));
809       }
810       if (! dontUseLocalConfig)
811         fp = Ncbienv_FileOpen (path, "r");
812       if (fp == NULL && create) {
813         newfp = Ncbienv_FileOpen (path, "w");
814         Nlm_FileClose (newfp);
815         newfp = Ncbienv_FileOpen (path, "r");
816       }
817     }
818     if (fp == NULL) {
819       path[0] = '\0';
820       pth = getenv ("NCBI");
821       if (pth != NULL) {
822         Nlm_FileBuildPath(path, pth, str + 1);
823         fp = Ncbienv_FileOpen (path, "r");
824         if (fp == NULL) {
825           path[0] = '\0';
826           Nlm_FileBuildPath(path, pth, str);
827           fp = Ncbienv_FileOpen (path, "r");
828         }
829       }
830     }
831     if (newfp != NULL) {
832       if (fp != NULL) {
833         Nlm_FileClose (newfp);
834         newfp = NULL;
835       } else {
836         fp = newfp;
837       }
838     }
839     if (writeMode && fp != NULL) {
840       Nlm_FileClose (fp);
841       fp = Ncbienv_FileOpen (path, "w");
842     }
843   }
844   return fp;
845 }
846 
847 #endif /* OS_UNIX */
848 
849 #ifdef OS_MSWIN
850 /*****************************************************************************
851 *
852 *   Nlm_OpenConfigFile (file, writeMode, create)
853 *      returns a file pointer to the specified configuration file.
854 *      1)  looks in the current directory for "file.ini", but will not
855 *          create a new file in this directory.
856 *      2)  then looks in the home directory for ".filerc".
857 *      3)  then looks for an environment variable "NCBI" and takes its
858 *          value as a complete path to a directory containing the
859 *          configuration file "filerc" or ".filerc".
860 *
861 *      Steps (1) and (2) above are omitted if the NCBI_DONT_USE_LOCAL_CONFIG
862 *      environment variable is set.  This can be used to allow specific
863 *      production applications to avoid stray .ncbirc files which may have
864 *      been erroneously generated.
865 *
866 *****************************************************************************/
867 
868 static FILE* Nlm_OpenConfigFile(const Nlm_Char* file, Nlm_Boolean writeMode, Nlm_Boolean create)
869 
870 {
871   Nlm_Char  ch;
872   FILE      *fp;
873   Nlm_Int2  i;
874   Nlm_Int2  len;
875   FILE      *newfp;
876   Nlm_Char  path [PATH_MAX+1];
877   Nlm_Char  str [FILENAME_MAX+1];
878   Nlm_CharPtr  tmp;
879 
880   fp = NULL;
881   newfp = NULL;
882 
883   if (file != NULL) {
884 
885     /* normalize file name */
886     Nlm_StringNCpy_0(str, file, sizeof(str) - 4);
887     if ( ! Nlm_Qualified (str) ) {
888         /* if the user has already supplied a name with .xxx use that name
889          * otherwise add the .ini here */
890         Nlm_StringCat(str, ".INI");
891     }
892     /* if the name isn't all uppercase, make it so now */
893     len = (Nlm_Int2) Nlm_StringLen (str);
894     for (i = 0; i < len; i++) {
895       ch = str [i];
896       str [i] = TO_UPPER (ch);
897     }
898 
899     /* first try user directory */
900 
901     tmp = getenv ("USERPROFILE");
902     if (tmp != NULL && *tmp != '\0') {
903       StringNCpy_0 (path, tmp, sizeof (path));
904       Nlm_FileBuildPath(path, NULL, str);
905       fp = Ncbienv_FileOpen (path, "r");
906       if (fp == NULL && create) {
907         newfp = Ncbienv_FileOpen (path, "w");
908         Nlm_FileClose (newfp);
909         newfp = Ncbienv_FileOpen (path, "r");
910       }
911     }
912 
913     /* next try c:\winnt for backward compatibility - read only */
914 
915     if (fp == NULL) {
916       tmp = getenv ("SYSTEMROOT");
917       if (tmp != NULL && *tmp != '\0') {
918         StringNCpy_0 (path, tmp, sizeof (path));
919         Nlm_FileBuildPath(path, NULL, str);
920         fp = Ncbienv_FileOpen (path, "r");
921       }
922     }
923 
924     /* last try environment variable path - read only */
925 
926     if (fp == NULL) {
927       tmp = getenv ("NCBI");
928       if (tmp != NULL && *tmp != '\0') {
929         StringNCpy_0 (path, tmp, sizeof (path));
930         Nlm_FileBuildPath(path, NULL, str);
931         fp = Ncbienv_FileOpen (path, "r");
932       }
933     }
934 
935     if (newfp != NULL) {
936       if (fp != NULL) {
937         Nlm_FileClose (newfp);
938         newfp = NULL;
939       } else {
940         fp = newfp;
941       }
942     }
943     if (writeMode && fp != NULL) {
944       Nlm_FileClose (fp);
945       fp = Ncbienv_FileOpen (path, "w");
946     }
947   }
948   return fp;
949 }
950 #endif /* OS_MSWIN */
951 
952 
953 #if defined(OS_MAC) && !defined(OS_UNIX_DARWIN)
954 /*****************************************************************************
955  *
956  *   Nlm_OpenConfigFile (file, writeMode, create)
957  *
958  *       file        char string with name of file to open or optionally create
959  *       writeMode   don't know what this does, but all calling functions seem
960  *                   to pass FALSE??
961  *       create      Boolean to create the file if it doesn't already exist
962  *
963  *  Returns:
964  *      A ncbi FILE pointer to the specified configuration file.  NULL if all
965  *      fails for some reason
966  *
967  *      1)  Finds "System Folder:Preferences" for "file.cnf"
968  *
969  *  Implementation Notes:
970  *      Implicit assumptions:
971  *      System softare is 6.0.5 or newer (Gestalt)
972  *      System softare is 7.0 or newer (FindFolder)
973  *
974  *  We find the active preferences folder and either open a pre-existing file
975  *  or create a new one with type 'TEXT' and creator '    '.  The absolute
976  *  pathname is not derived or needed, since we can use HSetVol to perform the
977  *  MacOS equivalent of a "cd" command.
978  *
979  *   pchurchill 12/10/99
980  *
981  *****************************************************************************/
982 
983 static FILE* 
984 Nlm_OpenConfigFile(const Nlm_Char* file,
985                    Nlm_Boolean writeMode,
986                    Nlm_Boolean create )
987 {
988     Nlm_Char    ch;
989     Nlm_Char    str [FILENAME_MAX+1];
990     Nlm_Int2    len;
991     long        gesResponse;
992     OSErr       err;
993     long        dirID, saveDirID;
994     short       vRefNum, saveVRefNum;
995     FSSpec      spec;
996     FILE        *fp = NULL;
997     int         i;
998 
999     if( file == NULL || *file == '\0' ){
1000         return NULL;
1001     }
1002 
1003     /* copy no more than (FILENAME_MAX - 4) to allow for the length of
1004      * our postfix */
1005     Nlm_StringNCpy_0(str, file, sizeof(str) - 4);
1006     if ( ! Nlm_Qualified (str) ) {
1007         /* if the user has already supplied a name with .xxx use that name
1008          * otherwise add the .cnf here */
1009         Nlm_StringCat(str, ".cnf");
1010     }
1011     /* if the name isn't all lowercase, make it so now */
1012     len = (Nlm_Int2) Nlm_StringLen (str);
1013     for (i = 0; i < len; i++) {
1014       ch = str [i];
1015       str [i] = TO_LOWER (ch);
1016     }
1017     
1018     /* convert to pascal string for Mac toolbox */
1019     Nlm_CtoPstr( str);
1020 
1021     /* Make sure we can use FindFolder() if not, then report error and
1022      * return NULL */
1023     if ( Gestalt (gestaltFindFolderAttr, &gesResponse) != noErr ||
1024         (gesResponse & (1 << gestaltFindFolderPresent) == 0)) {
1025         /* notify user of the error */
1026         Nlm_Message(MSG_OK,
1027                     "We need Mac OS 7.0 or newer, continue at your own risk.");
1028         return NULL;
1029     }
1030 
1031     /* store the current active directory */
1032     HGetVol( (StringPtr) 0, &saveVRefNum, &saveDirID);
1033 
1034     /* first look for file in "system", then "preferences".  Only create it
1035      * in prefs if both of those fail... */
1036     err = FindFolder(kOnSystemDisk, kSystemFolderType,
1037                        kDontCreateFolder, &vRefNum, &dirID);
1038     if (err == noErr) {
1039         err = FSMakeFSSpec( vRefNum, dirID, (StringPtr)str, &spec);
1040     }
1041 
1042     if( err != noErr){
1043         /* i.e. file not in "system"
1044          * find the preferences folder in the active System folder */
1045         err = FindFolder(kOnSystemDisk, kPreferencesFolderType,
1046                        kCreateFolder, &vRefNum, &dirID);
1047         if (err == noErr) {
1048             err = FSMakeFSSpec( vRefNum, dirID, (StringPtr)str, &spec);
1049         }
1050     }
1051 
1052     /* convert to back to C string for fopen */
1053     Nlm_PtoCstr( str);
1054 
1055     if( err == noErr){      /* the file is already there */
1056         HSetVol( (StringPtr) 0, vRefNum, dirID);
1057         if (writeMode) {
1058             fp = fopen (str, "w");
1059         } else {
1060             fp = fopen (str, "r");
1061         }
1062         HSetVol( (StringPtr) 0, saveVRefNum, saveDirID);
1063     }
1064     else if( err == fnfErr && create){
1065         /* no file with that name was found, create one */
1066         err = FSpCreate( &spec, '    ', 'TEXT', smSystemScript);
1067         if( err == noErr){
1068             /* set the default directory (same as doing "cd" in unix)
1069              * and actually open the file */
1070             HSetVol( (StringPtr) 0, vRefNum, dirID);
1071             fp = fopen (str, "w");
1072             HSetVol( (StringPtr) 0, saveVRefNum, saveDirID);
1073         }
1074         if( fp == NULL){
1075             Nlm_Message( MSG_OK, 
1076                          "Couldn't create the preferences file, "
1077                          "is the boot volume locked?");
1078         }
1079     }
1080   return fp;
1081 }
1082 #endif /* defined(OS_MAC) && !defined(OS_UNIX_DARWIN) */
1083 
1084 #ifdef OS_VMS
1085 /*****************************************************************************
1086 *
1087 *   Nlm_GetHome (buf, buflen)
1088 *      returns the path of the home directory
1089 *
1090 *****************************************************************************/
1091 
1092 static Nlm_Boolean Nlm_GetHome(Nlm_Char* buf, Nlm_Int2 buflen)
1093 {
1094   Nlm_StringNCpy_0(buf, getenv("SYS$LOGIN"), buflen);
1095   return TRUE;
1096 }
1097 
1098 /*****************************************************************************
1099 *
1100 *   Nlm_OpenConfigFile (file, writeMode, create)
1101 *      returns a file pointer to the specified configuration file.
1102 *      1)  looks in the current directory for "file.cfg", but will not
1103 *          create a new file in this directory.
1104 *      2)  then looks in the home directory for "file.cfg".
1105 *      3)  then looks for an environment variable "NCBI" and takes its
1106 *          value as a complete path to a directory containing the
1107 *          configuration file "file.cfg".
1108 *
1109 *****************************************************************************/
1110 
1111 static FILE* Nlm_OpenConfigFile(const Nlm_Char* file, Nlm_Boolean writeMode, Nlm_Boolean create)
1112 
1113 {
1114   Nlm_Char  ch;
1115   FILE      *fp;
1116   Nlm_Int2  i;
1117   Nlm_Int2  len;
1118   FILE      *newfp;
1119   Nlm_Char  path [PATH_MAX+1];
1120   char      *pth;
1121   Nlm_Char  str [FILENAME_MAX+1];
1122 
1123   fp = NULL;
1124 
1125   if (file != NULL) {
1126     newfp = NULL;
1127     Nlm_StringNCpy_0(str, file, sizeof(str) - 4);
1128     if ( ! Nlm_Qualified (str) ) {
1129       Nlm_StringCat (str, ".cfg");
1130     }
1131     len = (Nlm_Int2) Nlm_StringLen (str);
1132     for (i = 0; i < len; i++) {
1133       ch = str [i];
1134       str [i] = TO_LOWER (ch);
1135     }
1136     Nlm_StringNCpy_0(path, str, sizeof(path));
1137 
1138     fp = Ncbienv_FileOpen (path, "r");  /* File exists? */
1139     if (fp == NULL) {
1140       if (Nlm_GetHome (path, sizeof (path))) {
1141         Nlm_FileBuildPath(path, NULL, str);
1142       } else {
1143         Nlm_StringNCpy_0(path, str, sizeof(path));
1144       }
1145       fp = Ncbienv_FileOpen (path, "r");   /* File exists? */
1146       if (fp == NULL && create) {
1147         newfp = Ncbienv_FileOpen (path, "w");
1148         Nlm_FileClose (newfp);
1149         newfp = Ncbienv_FileOpen (path, "r");
1150       }
1151     }
1152 
1153     if (fp == NULL) {
1154       path[0] = '\0';
1155       pth = getenv ("NCBI");
1156       if (pth != NULL) {
1157         Nlm_FileBuildPath(path, pth, str);
1158         fp = Ncbienv_FileOpen (path, "r");
1159       }
1160     }
1161 
1162     if (newfp != NULL) {
1163       if (fp != NULL) {
1164         Nlm_FileClose (newfp);
1165         newfp = NULL;
1166       } else {
1167         fp = newfp;
1168       }
1169     }
1170 
1171     /*
1172     ** On VMS if a file is opened for write a new version is created.
1173     ** This section of code check for "writeMode" and an existing file
1174     ** if both are true.  Get the currently open file's name and delete
1175     ** it.  Open a new one in write mode.
1176     **
1177     ** Side effects: This will replace the highest existing file version,
1178     ** but not older version.  There exists the possibility that a user's
1179     ** custom change may get lost.  A possible workaround for this would
1180     ** be to have the calling program make a new copy (one higher version)
1181     ** of the existing file before doing extensive write to the params
1182     ** file OR keep a static flag in this routine which does  delete the
1183     ** first time time.
1184     */
1185 
1186     if (writeMode && fp != NULL) {
1187       char temp[256];
1188       fgetname(fp,temp);
1189       Nlm_FileClose (fp);
1190       delete(temp);
1191       fp = Ncbienv_FileOpen (path, "w");
1192     }
1193   }
1194   return fp;
1195 }
1196 
1197 #endif /* OS_VMS */
1198 
1199 
1200 /*****************************************************************************
1201 *
1202 *   Nlm_TrimString (str)
1203 *      strips trailing spaces, \r, \n
1204 *
1205 *****************************************************************************/
1206 
1207 static Nlm_Char* Nlm_TrimString(Nlm_Char* str)
1208 
1209 {
1210   Nlm_Char   ch;
1211   Nlm_Char*  spc;
1212   Nlm_Char*  tmp;
1213 
1214   if (str != NULL) {
1215     ch = *str;
1216     while (ch == ' ' || ch == '\t') {
1217       str++;
1218       ch = *str;
1219     }
1220     tmp = str;
1221     spc = NULL;
1222     ch = *tmp;
1223     while (ch != '\0' && ch != '\r' && ch != '\n') {
1224       if (ch == ' ' || ch == '\t') {
1225         if (spc == NULL) {
1226           spc = tmp;
1227         }
1228       } else {
1229         spc = NULL;
1230       }
1231       tmp++;
1232       ch = *tmp;
1233     }
1234     *tmp = '\0';
1235     if (spc != NULL) {
1236       *spc = '\0';
1237     }
1238   }
1239   return str;
1240 }
1241 
1242 /*****************************************************************************
1243 *
1244 *   Nlm_ReadConfigFile (fp)
1245 *      reads parameters from configuration file to memory structure
1246 *
1247 *****************************************************************************/
1248 
1249 static Nlm_Boolean Nlm_ReadConfigFile(FILE* fp)
1250 
1251 {
1252   Nlm_Char         ch;
1253   Nlm_env_itemPtr  eip;
1254   Nlm_env_sectPtr  esp;
1255   Nlm_env_itemPtr  lastEip;
1256   Nlm_env_sectPtr  lastEsp;
1257   Nlm_Char*      mid;
1258   Nlm_Char         str [256];
1259   Nlm_Char*      tmp;
1260   Nlm_Char*      comment;
1261 
1262   if (fp != NULL) {
1263     if (Nlm_envList != NULL) {
1264       Nlm_FreeEnvData (Nlm_envList);
1265       Nlm_envList = NULL;
1266     }
1267     esp = NULL;
1268     lastEsp = NULL;
1269     eip = NULL;
1270     lastEip = NULL;
1271     comment = NULL;
1272     while (Nlm_FileGets (str, sizeof (str), fp)) {
1273       ch = *str;
1274       if (ch != '\n' && ch != '\r') {
1275         if (ch == ';') { /* comment */
1276           if (comment == NULL) { /* first comment */
1277              comment = Nlm_StringSave(str);
1278           }
1279           else { /* append to existing comment */
1280              tmp = (Nlm_Char*) Nlm_MemNew(StrLen(comment) + StrLen(str) + 1);
1281              StrCpy(tmp, comment);
1282              StrCat(tmp, str);
1283              comment = (Nlm_Char*) Nlm_MemFree(comment);
1284              comment = tmp;
1285           }
1286         } else if (ch == '[') {
1287           if (esp == NULL) {
1288             esp = (Nlm_env_sectPtr) Nlm_MemNew (sizeof (Nlm_env_sect));
1289             lastEsp = esp;
1290             Nlm_envList = esp;
1291           } else {
1292             esp = (Nlm_env_sectPtr) Nlm_MemNew (sizeof (Nlm_env_sect));
1293             lastEsp->next = esp;
1294             lastEsp = esp;
1295           }
1296           esp->comment = comment;
1297           comment = NULL;
1298           tmp = str;
1299           ch = *tmp;
1300           while (ch != '\0' && ch != ']') {
1301             tmp++;
1302             ch = *tmp;
1303           }
1304           *tmp = '\0';
1305           esp->name = Nlm_StringSave (str + 1);
1306           eip = NULL;
1307           lastEip = NULL;
1308         } else if (esp != NULL) {
1309           if (eip == NULL) {
1310             eip = (Nlm_env_itemPtr) Nlm_MemNew (sizeof (Nlm_env_item));
1311             lastEip = eip;
1312             esp->children = eip;
1313           } else {
1314             eip = (Nlm_env_itemPtr) Nlm_MemNew (sizeof (Nlm_env_item));
1315             lastEip->next = eip;
1316             lastEip = eip;
1317           }
1318           eip->comment = comment;
1319           comment = NULL;
1320           tmp = str;
1321           mid = str;
1322           ch = *tmp;
1323           while (ch != '\0' && ch != '\n' && ch != '\r') {
1324             if (ch == '=' && mid == str) {
1325               mid = tmp;
1326               *mid++ = '\0';
1327             }
1328             tmp++;
1329             ch = *tmp;
1330           }
1331           *tmp = '\0';
1332           eip->name = Nlm_StringSave (Nlm_TrimString (str));
1333           eip->value = Nlm_StringSave (Nlm_TrimString (mid));
1334         }
1335       }
1336     }
1337 
1338     /* any comments which appeared after the final key of the final section */
1339     Nlm_bottomComment = (Nlm_Char*)Nlm_MemFree(Nlm_bottomComment);
1340     Nlm_bottomComment = comment;
1341   }
1342   return TRUE;
1343 }
1344 
1345 static Nlm_env_sectPtr Nlm_FindConfigSection(const Nlm_Char* section)
1346 {
1347   Nlm_env_sectPtr esp;
1348 
1349   if (section == NULL)
1350     return NULL;
1351 
1352   for (esp = Nlm_envList; esp != NULL; esp = esp->next)
1353   {
1354     if (esp->name != NULL && Nlm_StringICmp(section, esp->name) == 0)
1355        return esp;
1356   }
1357 
1358   return NULL;
1359 }
1360 
1361 /*****************************************************************************
1362 *
1363 *   Nlm_FindConfigItem (section, type, create)
1364 *      finds parameter in memory structure
1365 *
1366 *****************************************************************************/
1367 
1368 static Nlm_env_itemPtr Nlm_FindConfigItem(const Nlm_Char* section, const Nlm_Char* type, Nlm_Boolean create)
1369 
1370 {
1371   Nlm_env_itemPtr  eip;
1372   Nlm_env_sectPtr  esp;
1373   Nlm_Boolean      goOn;
1374   Nlm_env_itemPtr  lastEip;
1375   Nlm_env_sectPtr  lastEsp;
1376 
1377   eip = NULL;
1378   if (section != NULL && type != NULL) {
1379     goOn = TRUE;
1380     esp = Nlm_envList;
1381     lastEsp = esp;
1382     while (esp != NULL && goOn) {
1383       if (esp->name != NULL && Nlm_StringICmp (section, esp->name) == 0) {
1384         goOn = FALSE;
1385       } else {
1386         lastEsp = esp;
1387         esp = esp->next;
1388       }
1389     }
1390     if (goOn && create) {
1391       if (Nlm_envList != NULL) {
1392         esp = (Nlm_env_sectPtr) Nlm_MemNew (sizeof (Nlm_env_sect));
1393         if (esp != NULL) {
1394           esp->name = Nlm_StringSave (section);
1395           lastEsp->next = esp;
1396         }
1397       } else {
1398         esp = (Nlm_env_sectPtr) Nlm_MemNew (sizeof (Nlm_env_sect));
1399         if (esp != NULL) {
1400           esp->name = Nlm_StringSave (section);
1401         }
1402         Nlm_envList = esp;
1403       }
1404     }
1405     if (esp != NULL) {
1406       eip = esp->children;
1407       if (eip != NULL) {
1408         goOn = TRUE;
1409         lastEip = eip;
1410         while (eip != NULL && goOn) {
1411           if (eip->name != NULL && Nlm_StringICmp (type, eip->name) == 0) {
1412             goOn = FALSE;
1413           } else {
1414             lastEip = eip;
1415             eip = eip->next;
1416           }
1417         }
1418         if (goOn && create) {
1419           eip = (Nlm_env_itemPtr) Nlm_MemNew (sizeof (Nlm_env_item));
1420           if (eip != NULL) {
1421             eip->name = Nlm_StringSave (type);
1422             lastEip->next = eip;
1423           }
1424         }
1425       } else if (create) {
1426         eip = (Nlm_env_itemPtr) Nlm_MemNew (sizeof (Nlm_env_item));
1427         if (eip != NULL) {
1428           eip->name = Nlm_StringSave (type);
1429           esp->children = eip;
1430         }
1431       }
1432     }
1433   }
1434   return eip;
1435 }
1436 
1437 /*****************************************************************************
1438 *
1439 *   Nlm_WriteConfigFile (fp)
1440 *      writes parameters to configuration file from memory structure
1441 *
1442 *****************************************************************************/
1443 
1444 static Nlm_Boolean Nlm_WriteConfigFile(FILE* fp)
1445 
1446 {
1447   Nlm_env_itemPtr  eip;
1448   Nlm_env_sectPtr  esp;
1449 
1450   if (Nlm_envList != NULL && fp != NULL) {
1451     esp = Nlm_envList;
1452     while (esp != NULL) {
1453       if (! destroyDeadComments || esp->name != NULL)
1454       {
1455         Nlm_PutComment (esp->comment, fp);
1456       }
1457       if (esp->name != NULL)
1458       {
1459         fputc ('[', fp);
1460         fputs (esp->name, fp);
1461         fputs ("]\n", fp);
1462       }
1463       eip = esp->children;
1464       while (eip != NULL) {
1465         if (! destroyDeadComments)
1466         {
1467           Nlm_PutComment (eip->comment, fp);
1468         }
1469         if (esp->name != NULL && eip->name != NULL && eip->value != NULL) {
1470           if (destroyDeadComments)
1471           {
1472             Nlm_PutComment (eip->comment, fp);
1473           }
1474           fputs (eip->name, fp);
1475           fputc ('=', fp);
1476           fputs (eip->value, fp);
1477           fputc ('\n', fp);
1478         }
1479         eip = eip->next;
1480       }
1481       if (esp->name != NULL)
1482       {
1483         fputc ('\n', fp);
1484       }
1485       esp = esp->next;
1486     }
1487   }
1488 
1489   if (fp != NULL)
1490     Nlm_PutComment(Nlm_bottomComment, fp);
1491 
1492   return TRUE;
1493 }
1494 
1495 /*****************************************************************************
1496 *
1497 *   Nlm_FreeConfigFileData ()
1498 *      frees parameter structure in memory
1499 *
1500 *****************************************************************************/
1501 
1502 static void Nlm_FreeConfigFileData(void)
1503 
1504 {
1505   mustCreateFile = TRUE;
1506   Nlm_bottomComment = (Nlm_Char*) Nlm_MemFree(Nlm_bottomComment);
1507   if (Nlm_lastParamFile != NULL)
1508     Nlm_lastParamFile = (Nlm_Char*) Nlm_MemFree(Nlm_lastParamFile);
1509 
1510   if (Nlm_envList != NULL) {
1511     Nlm_FreeEnvData (Nlm_envList);
1512     Nlm_envList = NULL;
1513   }
1514 }
1515 
1516 
1517 /*****************************************************************************
1518 *
1519 *   Nlm_FlushConfigFile()
1520 *      flush the specified file's parameters to disk
1521 *
1522 *****************************************************************************/
1523 
1524 static void Nlm_FlushConfigFile(const Nlm_Char* file, Nlm_Boolean create)
1525 {
1526   FILE* fp;
1527 
1528   if (dirty && file != NULL)
1529   {
1530     fp = Nlm_OpenConfigFile (file, TRUE, create);
1531     if (fp != NULL) {
1532       Nlm_WriteConfigFile (fp);
1533       Nlm_FileClose (fp);
1534     }
1535   }
1536   dirty = FALSE;
1537 }
1538 
1539 /*****************************************************************************
1540 *
1541 *   Nlm_FreeConfigStruct ()
1542 *      frees parameter structure in memory, and perform other cleanup
1543 *
1544 *****************************************************************************/
1545 
1546 static void Nlm_FreeConfigStruct_ST(void)
1547 {
1548   Nlm_FlushAppParam();
1549   Nlm_FreeConfigFileData ();
1550   Nlm_FreeTransientData ();
1551 }
1552 
1553 
1554 /*****************************************************************************
1555 *
1556 *   Nlm_PutComment()
1557 *      output a comment to the config file
1558 *
1559 *****************************************************************************/
1560 
1561 static void Nlm_PutComment(const Nlm_Char* s, FILE* fp)
1562 {
1563   if (s != NULL)
1564     fputs(s, fp);
1565 }
1566 
1567 
1568 /*****************************************************************************
1569 *   Nlm_Qualified ()
1570 *      Appears to check if we've got an n.3 notation sting (i.e. if there is
1571 *       a "." in the last 4 chars of the string passed)
1572 *****************************************************************************/
1573 static Nlm_Boolean Nlm_Qualified( const Nlm_Char* path )
1574 {
1575   Nlm_Int4 l,k;
1576   const Nlm_Char*  p;
1577 
1578   l = Nlm_StrLen(path);
1579   p = path+l;
1580   k = 0;
1581   while (k < l && k <= 4) {
1582      if (*p-- == '.') return TRUE;
1583      k++;
1584   }
1585   return FALSE;
1586 }
1587 
1588 
1589 /*****************************************************************************
1590 *
1591 *   Nlm_FindPath (file, section, type, buf, buflen)
1592 *      finds paths for types of data from configuration files.
1593 *      if configuration file is found, tries to read the parameter from it,
1594 *      then appends a directory delimiter character, if necessary.
1595 *
1596 *****************************************************************************/
1597 
1598 NLM_EXTERN Nlm_Boolean Nlm_FindPath(const Nlm_Char* file, const Nlm_Char* section, const Nlm_Char* type, Nlm_Char* buf, Nlm_Int2 buflen)   /* length of path buffer */
1599 {
1600   Nlm_Boolean rsult = FALSE;
1601 
1602   if (file == NULL  ||  section == 0  ||  type == NULL  ||
1603       buf == NULL  ||  buflen <= 0)
1604     return FALSE;
1605 
1606   NlmMutexLockEx( &corelibMutex );
1607 
1608   *buf = '\0';
1609   if (*file != '\0'  &&  *section != '\0'  &&  *type != '\0'  &&
1610       Nlm_GetAppParam(file, section, type, "", buf, (Nlm_Int2)(buflen - 1))  &&
1611       *buf != '\0')
1612     {
1613       Nlm_FileBuildPath(buf, NULL, NULL);
1614       rsult = TRUE;
1615     }
1616 
1617   NlmMutexUnlock( corelibMutex );
1618   return rsult;
1619 }
1620 
1621 
1622 static Nlm_Boolean Nlm_TransientSetAppParam_ST(const Nlm_Char* file, const Nlm_Char* section, const Nlm_Char* type, const Nlm_Char* value)
1623 {
1624   Nlm_env_filePtr  theFile;
1625   Nlm_env_itemPtr  eip;
1626   Nlm_env_sectPtr  esp;
1627   Nlm_env_itemPtr  nextEip;
1628 
1629   if (file == NULL || *file == '\0' || section == NULL || *section == '\0')
1630     return FALSE;
1631 
1632   for (theFile = Nlm_transientFileList; theFile != NULL; theFile = theFile->next)
1633   {
1634     if (StringICmp(theFile->name, file) == 0)
1635     {
1636       for (esp = theFile->envList; esp != NULL; esp = esp->next)
1637       {
1638         if (esp->name != NULL && StringICmp(esp->name, section) == 0)
1639         {
1640           if (type == NULL || type[0] == '\0')
1641           {
1642             /* free all children */
1643             for (eip = esp->children; eip != NULL; eip = nextEip)
1644             {
1645               nextEip = eip->next;
1646               eip->next    = (Nlm_env_itemPtr)(-1);
1647               eip->name    = (Nlm_Char*) Nlm_MemFree (eip->name);
1648               eip->comment = (Nlm_Char*) Nlm_MemFree (eip->comment);
1649               eip->value   = (Nlm_Char*) Nlm_MemFree (eip->value);
1650               Nlm_MemFree (eip);
1651             }
1652             esp->children = NULL;
1653             esp->transientOnly = TRUE;
1654           } else { /* append this type to the section */
1655             eip = (Nlm_env_itemPtr) MemNew(sizeof(*eip));
1656             eip->name = StringSave(type);
1657             eip->value = StringSave(value);
1658             eip->next = esp->children;
1659             esp->children = eip;
1660           }
1661           return TRUE;
1662         }
1663       }
1664       break;
1665     }
1666   }
1667 
1668   /* create the file data structure if needed */
1669   if (theFile == NULL)
1670   {
1671     theFile = (Nlm_env_filePtr) MemNew(sizeof(*theFile));
1672     theFile->name = StringSave(file);
1673     theFile->next = Nlm_transientFileList;
1674     Nlm_transientFileList = theFile;
1675   }
1676 
1677   /* create the section and type */
1678   esp = (Nlm_env_sectPtr) MemNew(sizeof(*esp));
1679   esp->name = StringSave(section);
1680   esp->next = theFile->envList;
1681   theFile->envList = esp;
1682   if (type == NULL || type[0] == '\0')
1683   {
1684     esp->transientOnly = TRUE;
1685   } else { /* create the section */
1686     esp->transientOnly = FALSE;
1687     eip = (Nlm_env_itemPtr) MemNew(sizeof(*eip));
1688     eip->name = StringSave(type);
1689     eip->value = StringSave(value);
1690     eip->next = NULL;
1691     esp->children = eip;
1692   }
1693 
1694   return TRUE;
1695 }
1696 
1697 
1698 /* SetAppParam is writing a value to the real config file, so log this value,
1699    if necessary, into the "transient" data structures */
1700 static void Nlm_TransientLogSetApp(const Nlm_Char* file, const Nlm_Char* section, const Nlm_Char* type, const Nlm_Char* value)
1701 
1702 {
1703   Nlm_env_filePtr  theFile;
1704   Nlm_env_itemPtr  eip;
1705   Nlm_env_sectPtr  esp;
1706 
1707   if (file == NULL || *file == '\0' || section == NULL || *section == '\0')
1708     return;
1709 
1710   if (type == NULL || type[0] == '\0')
1711   {
1712     for (theFile = Nlm_transientFileList; theFile != NULL; theFile = theFile->next)
1713     {
1714       if (StringICmp(theFile->name, file) == 0)
1715       {
1716         for (esp = theFile->envList; esp != NULL; esp = esp->next)
1717         {
1718           if (esp->name != NULL && StringICmp(esp->name, section) == 0)
1719           { /* delete the section by removing section name */
1720             esp->name = (Nlm_Char*) MemFree(esp->name);
1721           }
1722         }
1723       }
1724     }
1725   } else {
1726     for (theFile = Nlm_transientFileList; theFile != NULL; theFile = theFile->next)
1727     {
1728       if (StringICmp(theFile->name, file) == 0)
1729       {
1730         for (esp = theFile->envList; esp != NULL; esp = esp->next)
1731         {
1732           if (esp->name != NULL && StringICmp(esp->name, section) == 0 &&
1733               esp->transientOnly)
1734           { /* append this type to the section */
1735             eip = (Nlm_env_itemPtr) MemNew(sizeof(*eip));
1736             eip->name = StringSave(type);
1737             eip->value = StringSave(value);
1738             eip->next = esp->children;
1739             esp->children = eip;
1740           }
1741         }
1742       }
1743     }
1744   }
1745 }
1746 
1747 static Nlm_Boolean Nlm_TransientLookup(const Nlm_Char* file, const Nlm_Char* section, const Nlm_Char* type, const Nlm_Char* dflt, Nlm_Char* buf, size_t buflen)
1748 {
1749   Nlm_env_filePtr  theFile;
1750   Nlm_env_itemPtr  eip;
1751   Nlm_env_sectPtr  esp;
1752   Nlm_Int4         totlen;
1753   Nlm_Int4         bytesToAppend;
1754 
1755   if (file == NULL || *file == '\0' || section == NULL || *section == '\0')
1756     return FALSE;
1757 
1758   for (theFile = Nlm_transientFileList; theFile != NULL; theFile = theFile->next)
1759   {
1760     if (StringICmp(theFile->name, file) == 0)
1761     {
1762       for (esp = theFile->envList; esp != NULL; esp = esp->next)
1763       {
1764         if (esp->name != NULL && StringICmp(esp->name, section) == 0)
1765         {
1766           if (type == NULL || type[0] == '\0')
1767           { /* concatenate all types (keys) within section */
1768             *buf = '\0';
1769             totlen = 0;
1770             for (eip = esp->children; eip != NULL; eip = eip->next)
1771             {
1772               bytesToAppend = StrLen(eip->name) + 1;
1773               bytesToAppend = MIN(bytesToAppend, (Nlm_Int4)buflen - totlen);
1774               StrNCpy(&buf[totlen], eip->name, bytesToAppend);
1775               totlen += bytesToAppend;
1776             }
1777             if (totlen > 0 && buf[totlen] == '\0')
1778             {
1779                 totlen--; /* account for final null character */
1780             }
1781             /* now append the GetAppParam() data */
1782             if (! esp->transientOnly)
1783             { /* GetAppParam data can be trusted ... append it to buf */
1784               Nlm_WorkGetAppParam(file, section, NULL, "", &buf[totlen],
1785                                   (Nlm_Int2)(buflen - totlen), FALSE);
1786             }
1787             return TRUE;
1788           } else {
1789             for (eip = esp->children; eip != NULL; eip = eip->next)
1790             {
1791               if (StringICmp(eip->name, type) == 0)
1792               {
1793                 Nlm_StringNCpy_0(buf, eip->value, buflen);
1794                 return TRUE;
1795               }
1796             }
1797             if (esp->transientOnly)
1798             { /* GetAppParam data cannot be trusted ... use the default */
1799               Nlm_StringNCpy_0(buf, dflt, buflen);
1800               return TRUE;
1801             }
1802           }
1803         }
1804       }
1805     }
1806   }
1807 
1808   /* not found ... GetAppParam() should search the real config file */
1809   return FALSE;
1810 }
1811 
1812 static void Nlm_FreeEnvData(Nlm_env_sectPtr esp)
1813 
1814 {
1815   Nlm_env_itemPtr  eip;
1816   Nlm_env_itemPtr  nextEip;
1817   Nlm_env_sectPtr  nextEsp;
1818 
1819   while (esp != NULL) {
1820     nextEsp = esp->next;
1821     eip = esp->children;
1822     while (eip != NULL) {
1823       nextEip = eip->next;
1824       eip->next    = (Nlm_env_itemPtr)(-1);
1825       eip->name    = (Nlm_Char*) Nlm_MemFree (eip->name);
1826       eip->comment = (Nlm_Char*) Nlm_MemFree (eip->comment);
1827       eip->value   = (Nlm_Char*) Nlm_MemFree (eip->value);
1828       Nlm_MemFree (eip);
1829       eip = nextEip;
1830     }
1831     esp->next    = (Nlm_env_sectPtr)(-1);
1832     esp->name    = (Nlm_Char*) Nlm_MemFree (esp->name);
1833     esp->comment = (Nlm_Char*) Nlm_MemFree (esp->comment);
1834     Nlm_MemFree (esp);
1835     esp = nextEsp;
1836   }
1837 }
1838 
1839 
1840 static void Nlm_FreeTransientData(void)
1841 {
1842   Nlm_env_filePtr efp, nextEfp;
1843 
1844   efp = Nlm_transientFileList;
1845   while (efp != NULL) {
1846     nextEfp = efp->next;
1847     Nlm_FreeEnvData (efp->envList);
1848     efp->envList = NULL;
1849     efp->next = (Nlm_env_filePtr)(-1);
1850     efp->name = (Nlm_Char*) Nlm_MemFree (efp->name);
1851     Nlm_MemFree (efp);
1852     efp = nextEfp;
1853   }
1854   Nlm_transientFileList = NULL;
1855 }
1856 
1857 
1858 
1859 extern size_t Nlm_GetEnvParamEx
1860 (const Nlm_Char* conf_file, const Nlm_Char* conf_section,
1861  const Nlm_Char* env_name, const Nlm_Char* conf_name,
1862  Nlm_Char* buf, size_t bufsize, const Nlm_Char* dflt)
1863 {
1864   static const Nlm_Char s_DefConfigFile   [] = "ncbi";
1865   static const Nlm_Char s_DefConfigSection[] = "NCBI";
1866 
1867   size_t len = 0;
1868   ASSERT ( (env_name  &&  *env_name)  ||  (conf_name  &&  *conf_name) );
1869   ASSERT ( buf  &&  bufsize );
1870   buf[0] = '\0';
1871 
1872   /* arg fallbacks */
1873   if (conf_name  &&  *conf_name) {
1874     if ( !conf_file )
1875       conf_file = s_DefConfigFile;
1876     if ( !conf_section )
1877       conf_section = s_DefConfigSection;
1878   }
1879 
1880   /* Search in the list of transient parameters */
1881   if (conf_name  &&  *conf_name  &&
1882       Nlm_TransientLookup(conf_file, conf_section, conf_name,
1883                           dflt, buf, bufsize)) {
1884     return Nlm_StrLen(buf);
1885   }
1886 
1887   /* Fetch from the environment variable */
1888 #if defined(OS_UNIX) || defined(OS_MSWIN)
1889   if (env_name  &&  *env_name) {
1890     const Nlm_Char* str = getenv(env_name);
1891     if (str  &&  *str) {
1892       len = Nlm_StrLen(str);
1893       if (len >= bufsize)
1894         len = 0;
1895       else
1896         Nlm_StrCpy(buf, str);
1897     }
1898   }
1899 #endif
1900 
1901   /* Search in the configuration file */
1902   if (!len  &&  conf_name  &&  *conf_name) {
1903     len = GetAppParam(conf_file, conf_section, conf_name, dflt, buf, bufsize);
1904   }
1905 
1906   /* Store the value in the transient parameter list */
1907   ASSERT(len == Nlm_StrLen(buf));
1908   if ( len )
1909     VERIFY(Nlm_TransientSetAppParam(conf_file, conf_section, conf_name, buf));
1910 
1911   return len;
1912 }
1913 
1914 
1915 NLM_EXTERN size_t Nlm_GetEnvParam
1916 (const Nlm_Char* conf_file, const Nlm_Char* conf_section,
1917  const Nlm_Char* env_conf_name,
1918  Nlm_Char* buf, size_t bufsize, const Nlm_Char* dflt)
1919 {
1920   return Nlm_GetEnvParamEx(conf_file, conf_section,
1921                            env_conf_name, env_conf_name,
1922                            buf, bufsize, dflt);
1923 }
1924 
1925 
1926 
1927 /*****************************************************************************
1928 *
1929 *   Command-line arguments
1930 *     &
1931 *   Nlm_ProgramPath (buf, maxsize)
1932 *       returns full path to executing program
1933 *
1934 *****************************************************************************/
1935 
1936 static Nlm_Boolean wasSetup = FALSE;
1937 static int    targc = 0;
1938 static char **targv = NULL;
1939 
1940 
1941 #if defined(WIN_MAC)
1942 static FSSpec       apFileSpec;
1943 static Str255       apName;
1944 static Handle       apParam;
1945 static short        apRefNum;
1946 
1947 static Nlm_Boolean Nlm_SetupArguments_ST_Mac(void)
1948 {
1949 #ifndef __GNUC__
1950 /* At least in 10.1, this seems to introduce an unwanted dep. on Carbon. */
1951   ProcessInfoRec       pirec;
1952   ProcessSerialNumber  psn;
1953 
1954   GetCurrentProcess (&psn);
1955   pirec.processInfoLength = sizeof (ProcessInfoRec);
1956   pirec.processName = apName;
1957   pirec.processAppSpec = &apFileSpec;
1958   GetProcessInformation (&psn, &pirec);
1959   Nlm_PtoCstr ((Nlm_Char*) apFileSpec.name);
1960   Nlm_PtoCstr ((Nlm_Char*) apName);
1961 
1962   SetProgramName(apName);
1963 #endif
1964   return TRUE;
1965 }
1966 
1967 #if defined(OS_UNIX_DARWIN)
1968 /* this requires the CoreFoundation framework, but nothing more. */
1969 static void Nlm_ProgramPath_ST(Nlm_Char* appPath, size_t pathSize)
1970 {
1971   CFBundleRef thisBundle;
1972   CFURLRef    thisURL;
1973   int        pathsuffix_pos;
1974   static const char* appsuffix = ".app";
1975   
1976   thisBundle = CFBundleGetMainBundle();
1977   if (thisBundle == NULL) 
1978     return;
1979 
1980   thisURL = CFBundleCopyBundleURL(thisBundle);
1981   if (thisURL == NULL) return;
1982   if (!CFURLGetFileSystemRepresentation( thisURL, true, (UInt8 *) appPath, pathSize)) {
1983         return;
1984   }
1985   /* Does this path end with the .app suffix? */
1986   pathsuffix_pos = strlen(appPath) - strlen(appsuffix);
1987   if (pathsuffix_pos > 0  &&  
1988       0 == Nlm_StrICmp(appPath + pathsuffix_pos, appsuffix) ) {        
1989       /* this is a bundled app. */
1990       return;
1991   }
1992 
1993   /* this is not a bundled app. The above got me my directory. */
1994   thisURL = CFBundleCopyExecutableURL(thisBundle);
1995   if (thisURL == NULL) 
1996     return;
1997   CFURLGetFileSystemRepresentation( thisURL, true, (UInt8 *) appPath, pathSize);
1998 }
1999 
2000 /*
2001   is the application at filePath actually a application bundle/package?
2002   i.e. a folder containing subfolders, resource files and the actual executable.
2003   Pass the value returned by ProgramPath for best results.
2004 */
2005 NLM_EXTERN Nlm_Boolean Nlm_IsApplicationPackage(char *filePath)
2006 {
2007     OSErr   err;
2008     char    aPath[1024];
2009     FSRef   contentsFRef;
2010     Boolean isDirectory;
2011     
2012     StrCpy(aPath, filePath);
2013     FileBuildPath(aPath, "Contents", NULL);
2014     err = FSPathMakeRef ((unsigned char *) aPath, &contentsFRef, &isDirectory);
2015     if (err == noErr  &&  isDirectory) {
2016         return TRUE;   
2017     }
2018     /* else gets err == -120, no such directory. */
2019     return FALSE;
2020 }
2021 
2022 #else
2023 static void Nlm_ProgramPath_ST(Nlm_Char* buf, size_t maxsize)
2024 {
2025   CInfoPBRec  block;
2026   Nlm_Char    path [256];
2027   Nlm_Char    temp [256];
2028   short nErr;
2029 
2030   if (buf != NULL && maxsize > 0) {
2031     *buf = '\0';
2032     if (wasSetup) {
2033       memset (&block, 0, sizeof (CInfoPBRec));
2034       Nlm_StringNCpy_0(path, (Nlm_Char*)apFileSpec.name, sizeof (path));
2035 
2036       block.dirInfo.ioNamePtr = (StringPtr) path;
2037       block.dirInfo.ioDrParID = apFileSpec.parID;
2038 
2039       do {
2040         Nlm_StringCpy (temp, path);
2041         block.dirInfo.ioVRefNum = apFileSpec.vRefNum;
2042         block.dirInfo.ioFDirIndex = -1;
2043         block.dirInfo.ioDrDirID = block.dirInfo.ioDrParID;
2044         nErr = PBGetCatInfo (&block, FALSE);
2045         if (nErr != noErr) break;
2046         Nlm_PtoCstr ((Nlm_Char*) path);
2047         Nlm_StringCat (path, DIRDELIMSTR);
2048         Nlm_StringCat (path, temp);
2049       } while (block.dirInfo.ioDrDirID != fsRtDirID);
2050 
2051       Nlm_StringNCpy_0(buf, path, maxsize);
2052     }
2053   }
2054 }
2055 #endif /* defined(OS_UNIX_DARWIN) */
2056 #endif /* defined(WIN_MAC) */
2057 
2058 
2059 #if defined(OS_MSWIN) || defined(OS_VMS)
2060 static void Nlm_ProgramPath_ST(Nlm_Char* buf, size_t maxsize)
2061 {
2062   if (!buf  ||  maxsize <= 0)
2063     return;
2064 
2065   *buf = '\0';
2066   if (wasSetup  &&  targv  &&  targv[0])
2067     Nlm_StringNCpy_0(buf, targv[0], maxsize);
2068 }
2069 #endif  /* OS_MSWIN || OS_VMS */
2070 
2071 
2072 #if defined(OS_UNIX)  &&  !defined(OS_UNIX_DARWIN)
2073 static void Nlm_ProgramPath_ST(Nlm_Char* buf, size_t maxsize)
2074 {
2075   Nlm_Char     path [PATH_MAX];
2076   Nlm_Char*  pth;
2077   Nlm_Char*  ptr;
2078 
2079   if (buf != NULL && maxsize > 0) {
2080     *buf = '\0';
2081     if (wasSetup) {
2082       ptr = targv [0];
2083       if (ptr [0] == DIRDELIMCHR) {
2084         Nlm_StringNCpy_0(buf, targv[0], maxsize);
2085       } else if (getcwd (path, sizeof (path)) != NULL) {
2086         ptr = targv [0];
2087         while (ptr [0] == '.' || ptr [0] == DIRDELIMCHR) {
2088           if (ptr [0] == '.') {
2089             if (ptr [1] == '.' && ptr [2] == DIRDELIMCHR) {
2090               ptr += 3;
2091               pth = StringRChr (path, DIRDELIMCHR);
2092               if (pth != NULL) {
2093                 *pth = '\0';
2094               }
2095             } else if (ptr [1] == DIRDELIMCHR) {
2096               ptr += 2;
2097             } else {
2098               ptr++;
2099             }
2100           } else if (ptr [0] == DIRDELIMCHR) {
2101             ptr++;
2102           } else {
2103             ptr++;
2104           }
2105         }
2106         FileBuildPath (path, NULL, ptr);
2107         Nlm_StringNCpy_0(buf, path, maxsize);
2108       } else {
2109         Nlm_StringNCpy_0(buf, targv[0], maxsize);
2110       }
2111     }
2112   }
2113 }
2114 #endif
2115 
2116 
2117 /*****************************************************************************
2118 * Multi-Thread protected external functions
2119 *****************************************************************************/
2120 
2121 NLM_EXTERN Nlm_Boolean Nlm_TransientSetAppParam(const Nlm_Char* file, const Nlm_Char* section, const Nlm_Char* type, const Nlm_Char* value)
2122 {
2123   Nlm_Boolean rsult;
2124   NlmMutexLockEx( &corelibMutex );
2125 
2126   rsult = Nlm_TransientSetAppParam_ST(file, section, type, value);
2127 
2128   NlmMutexUnlock( corelibMutex );
2129   return rsult;
2130 }
2131 
2132 NLM_EXTERN void Nlm_FreeConfigStruct(void)
2133 {
2134   NlmMutexLockEx( &corelibMutex );
2135   Nlm_FreeConfigStruct_ST();
2136   NlmMutexUnlock( corelibMutex );
2137 }
2138 
2139 
2140 NLM_EXTERN Nlm_Boolean Nlm_ParseCmdLineArguments
2141 (const char* prog_name, const char* cmd_line, int* argc_ptr, char*** argv_ptr,
2142  ECmdLineQuote quote_handling)
2143 {
2144   char*  str;
2145   char*  p;
2146   int    xx_argc;
2147   char** xx_argv;
2148 
2149   /* Check args */
2150   if (!argc_ptr  ||  !argv_ptr)
2151     return FALSE;
2152 
2153   /* Figure out program name */
2154   if (!prog_name  &&  !(prog_name = GetProgramName()))
2155      prog_name = "";
2156 
2157   /* Special case -- no cmd.-line parameters */
2158   if ( cmd_line ) {
2159     const char* sss;
2160     for (sss = cmd_line;  *sss  &&  isspace(*sss);  sss++) continue;
2161     if ( !*sss )
2162       cmd_line = 0;
2163   }
2164   if ( !cmd_line ) {
2165     *argc_ptr = 1;
2166     *argv_ptr = (char**) Nlm_MemNew(2 * sizeof(char*));
2167     (*argv_ptr[0]) = Nlm_StringSave(prog_name);
2168     return TRUE;
2169   }
2170 
2171   /* Allocate string to hold "argv[]" values and fill it with
2172    * the program name and the command string */
2173   {{
2174     size_t size = strlen(prog_name) + strlen(cmd_line) + 2;
2175     str = (char*) Nlm_MemNew(size);
2176 
2177     StrCpy(str, prog_name);
2178     StrCpy(str + strlen(prog_name) + 1, cmd_line);
2179   }}
2180 
2181   /* Count command-line arguments and separate them by '\0' */
2182   xx_argc = 1;
2183   for (p = str + strlen(prog_name) + 1;  *p; ) {
2184     if ( isspace(*p) ) {
2185       *p++ = '\0';
2186       continue;
2187     }
2188 
2189     if (quote_handling == eProcessQuotes  &&  (*p == '\''  ||  *p == '"')) {
2190       char quote = *p;
2191       xx_argc++;
2192       while (*(++p)  &&  *p != quote) continue;
2193       if ( *p )
2194         *p++ = '\0';
2195       continue;
2196     }
2197 
2198     xx_argc++;
2199     while (*p  &&  !isspace(*p))
2200       p++;
2201   }
2202 
2203   /* Allocate and fill out "xx_argv" */
2204   {{
2205     int   n = 1;
2206     char *s = str + strlen(prog_name) + 1;
2207     xx_argv = (char**) Nlm_MemNew((xx_argc + 1) * sizeof(char*));
2208     xx_argv[0] = str;
2209     while (n < xx_argc) {
2210       while ( !*s )
2211         s++;
2212       if (quote_handling == eProcessQuotes  &&  (*s == '\''  ||  *s == '"'))
2213         s++; /* -- skip the leading quote */
2214       xx_argv[n++] = s;
2215       while ( *s )
2216         s++;
2217     }
2218     xx_argv[n] = 0;
2219 #ifdef _DEBUG
2220     while (s < p  &&  !*s)
2221       s++;
2222     ASSERT ( s == p );
2223 #endif
2224   }}
2225 
2226   *argc_ptr = xx_argc;
2227   *argv_ptr = xx_argv;
2228   return TRUE;
2229 }
2230 
2231 
2232 NLM_EXTERN void Nlm_FreeCmdLineArguments(char** argv)
2233 {
2234   if ( !argv )
2235     return;
2236 
2237   ASSERT( argv[0] );
2238   Nlm_MemFree( argv[0] );
2239   Nlm_MemFree( argv );
2240 }
2241 
2242 
2243 NLM_EXTERN void Nlm_SetupArguments(int argc, char *argv[])
2244 {
2245   NlmMutexLockEx( &corelibMutex );
2246   wasSetup = TRUE;
2247 #if defined(WIN_MAC)
2248   wasSetup = Nlm_SetupArguments_ST_Mac();
2249 #elif defined(OS_UNIX)
2250   {{
2251     char *p;
2252     if ((p = strrchr(argv[0],DIRDELIMCHR)) != NULL)
2253       p++;
2254     else
2255       p = argv[0];
2256     SetProgramName(p);
2257   }}
2258 #endif
2259   targc = argc;
2260   targv = argv;
2261   NlmMutexUnlock( corelibMutex );
2262 }
2263 
2264 NLM_EXTERN Nlm_Char** Nlm_GetArgv(void)
2265 {
2266   return targv;
2267 }
2268 
2269 NLM_EXTERN Nlm_Int4 Nlm_GetArgc(void)
2270 {
2271   return targc;
2272 }
2273 
2274 NLM_EXTERN void Nlm_ProgramPath(Nlm_Char* buf, size_t maxsize)
2275 {
2276   NlmMutexLockEx( &corelibMutex );
2277   Nlm_ProgramPath_ST(buf, maxsize);
2278   NlmMutexUnlock( corelibMutex );
2279 }
2280 
2281 NLM_EXTERN void Nlm_FlushAppParam(void)
2282 {
2283   NlmMutexLockEx( &corelibMutex );
2284   Nlm_FlushAppParam_ST();
2285   NlmMutexUnlock( corelibMutex );
2286 }
2287 
2288 NLM_EXTERN Nlm_Boolean Nlm_CacheAppParam(Nlm_Boolean value)
2289 {
2290   Nlm_Boolean rsult;
2291   NlmMutexLockEx( &corelibMutex );
2292 
2293   rsult = Nlm_CacheAppParam_ST( value );
2294 
2295   NlmMutexUnlock( corelibMutex );
2296   return rsult;
2297 }
2298 
2299 NLM_EXTERN Nlm_Int2 Nlm_GetAppParam(const Nlm_Char* file, const Nlm_Char* section, const Nlm_Char* type, const Nlm_Char* dflt, Nlm_Char* buf, Nlm_Int2 buflen)
2300 {
2301   Nlm_Int2 rsult;
2302   NlmMutexLockEx( &corelibMutex );
2303 
2304   rsult = Nlm_WorkGetAppParam(file, section, type, dflt, buf, buflen, TRUE);
2305 
2306   NlmMutexUnlock( corelibMutex );
2307   return rsult;
2308 }
2309 
2310 NLM_EXTERN Nlm_Boolean Nlm_SetAppParam(const Nlm_Char* file, const Nlm_Char* section, const Nlm_Char* type, const Nlm_Char* value)
2311 {
2312   Nlm_Boolean rsult;
2313   NlmMutexLockEx( &corelibMutex );
2314 
2315   rsult = Nlm_SetAppParam_ST(file, section, type, value);
2316 
2317   NlmMutexUnlock( corelibMutex );
2318   return rsult;
2319 }
2320 
2321 
2322 /*****************************************************************************
2323 *
2324 *   GetAppParamBoolean()
2325 *       SetAppParamBoolean()
2326 *   GetAppParamLong()
2327 *       SetAppParamLong()
2328 *
2329 *****************************************************************************/
2330 
2331 NLM_EXTERN Nlm_Boolean GetAppParamBoolean
2332 (const Nlm_Char* filebase, const Nlm_Char* sect, const Nlm_Char* key,
2333  Nlm_Boolean dflt)
2334 {
2335   Nlm_Char buffer[32];
2336   if ( GetAppParam(filebase, sect, key, "", buffer, sizeof(buffer)) ) {
2337     if (strchr("1yYtT",buffer[0]))
2338       return TRUE;
2339     if (strchr("0nNfF",buffer[0]))
2340       return FALSE;
2341   }
2342   return dflt;
2343 }
2344 
2345 NLM_EXTERN Nlm_Boolean SetAppParamBoolean
2346 (const Nlm_Char* filebase, const Nlm_Char* sect, const Nlm_Char* key,
2347  Nlm_Boolean value)
2348 {
2349   return SetAppParam(filebase, sect, key, value ? "Yes" : "No");
2350 }
2351 
2352 NLM_EXTERN long GetAppParamLong(const Nlm_Char* filebase, const Nlm_Char* sect,
2353                                 const Nlm_Char* key, long dflt)
2354 {
2355   Nlm_Char buffer[32];
2356   return GetAppParam(filebase, sect, key, "", buffer, sizeof(buffer)) ?
2357     atol(buffer) : dflt;
2358 }
2359 
2360 NLM_EXTERN Nlm_Boolean SetAppParamLong
2361 (const Nlm_Char* filebase, const Nlm_Char* sect, const Nlm_Char* key,
2362  long value)
2363 {
2364         char buffer[32];
2365         sprintf(buffer,"%ld",value);
2366         return SetAppParam((char*)filebase,(char*)sect,(char*)key,buffer);
2367 }
2368 
2369 
2370 #ifdef WIN32
2371 extern int Nlm_x_HasConsole(void)
2372 {
2373   static int has_console = -1;
2374   if (has_console == -1)
2375     has_console = fileno(stdin) >= 0 ? 1 : 0;
2376 
2377   return has_console;
2378 }
2379 #endif
2380 
2381 
2382 NLM_EXTERN Nlm_Boolean Nlm_FreeArgs(Nlm_Int2 numargs, Nlm_ArgPtr ap)
2383 {
2384   Nlm_Int2 i;
2385   for (i = 0;  i < numargs;  i++, ap++)
2386     {
2387       switch ( ap->type )
2388         {
2389         case ARG_BOOLEAN:
2390           ap->intvalue = 0;
2391           break;
2392         case ARG_INT:
2393           ap->intvalue = 0;
2394           break;
2395         case ARG_FLOAT:
2396           ap->floatvalue = 0.0;
2397           break;
2398         case ARG_STRING:
2399         case ARG_FILE_IN:
2400         case ARG_FILE_OUT:
2401         case ARG_DATA_IN:
2402         case ARG_DATA_OUT:
2403           ap->strvalue = (Nlm_Char*) Nlm_MemFree( ap->strvalue );
2404           break;
2405         default:
2406           ASSERT ( FALSE );
2407           return FALSE;
2408         }
2409     }
2410   return TRUE;
2411 }
2412 
2413 #ifdef OS_UNIX_DARWIN
2414 #include <sys/sysctl.h>
2415 #endif
2416 
2417 NLM_EXTERN Nlm_CharPtr Nlm_GetOpSysString (void)
2418 
2419 {
2420 #ifdef OS_UNIX_DARWIN
2421 #ifdef PROC_PPC
2422   Nlm_Boolean  isRosetta = FALSE;
2423   size_t       len;
2424   int          mib [2];
2425   Nlm_Char     model [32];
2426 #endif
2427   long         sysVer;
2428 #endif
2429   Nlm_CharPtr  str = "unknown";
2430 
2431 #if defined(OS_MAC) && !defined(OS_UNIX_DARWIN)
2432   long  sysVer;
2433 
2434   if ( Gestalt (gestaltSystemVersion, &sysVer) == noErr) {
2435     /* system version in low order word is hexadecimal */
2436     if (sysVer >= 4096) {
2437       str = "MAC Carbon on OS X";
2438     } else if (sysVer >= 2304) {
2439       str = "MAC Carbon on OS 9";
2440     } else {
2441       str = "MAC Carbon on OS 8";
2442     }
2443   }
2444 #endif
2445 
2446 #ifdef OS_UNIX
2447   /* initial nonspecific UNIX string */
2448   str = "UNIX";
2449 
2450 #ifdef OS_UNIX_DARWIN
2451 #ifdef PROC_PPC
2452   mib [0] = CTL_HW;
2453   mib [1] = HW_MODEL;
2454   len = sizeof (model);
2455   if (sysctl (mib, 2, &model, &len, NULL, 0) == 0) {
2456     isRosetta = (Nlm_Boolean) (len == 9 && strcmp (model, "PowerMac") == 0);
2457   }
2458   if (isRosetta) {
2459     str = "MAC Rosetta on OS X";
2460     if ( Gestalt (gestaltSystemVersion, &sysVer) == noErr) {
2461       if (sysVer >= 4192) {
2462         str = "MAC Rosetta on OS 10.6";
2463       } else if (sysVer >= 4176) {
2464         str = "MAC Rosetta on OS 10.5";
2465       } else if (sysVer >= 4160) {
2466         str = "MAC Rosetta on OS 10.4";
2467       } else if (sysVer >= 4144) {
2468         str = "MAC Rosetta on OS 10.3";
2469       } else if (sysVer >= 4128) {
2470         str = "MAC Rosetta on OS 10.2";
2471       } else if (sysVer >= 4112) {
2472         str = "MAC Rosetta on OS 10.1";
2473       } else {
2474         str = "MAC Rosetta on OS X";
2475       }
2476     }
2477   } else {
2478     str = "MAC PPC on OS X";
2479     if ( Gestalt (gestaltSystemVersion, &sysVer) == noErr) {
2480       if (sysVer >= 4192) {
2481         str = "MAC PPC on OS 10.6";
2482       } else if (sysVer >= 4176) {
2483         str = "MAC PPC on OS 10.5";
2484       } else if (sysVer >= 4160) {
2485         str = "MAC PPC on OS 10.4";
2486       } else if (sysVer >= 4144) {
2487         str = "MAC PPC on OS 10.3";
2488       } else if (sysVer >= 4128) {
2489         str = "MAC PPC on OS 10.2";
2490       } else if (sysVer >= 4112) {
2491         str = "MAC PPC on OS 10.1";
2492       } else {
2493         str = "MAC PPC on OS X";
2494       }
2495     }
2496   }
2497 #else
2498 #ifdef PROC_I80X86
2499   str = "MAC 386 on OS X";
2500   if ( Gestalt (gestaltSystemVersion, &sysVer) == noErr) {
2501     if (sysVer >= 4192) {
2502       str = "MAC 386 on OS 10.6";
2503     } else if (sysVer >= 4176) {
2504       str = "MAC 386 on OS 10.5";
2505     } else if (sysVer >= 4160) {
2506       str = "MAC 386 on OS 10.4";
2507     } else if (sysVer >= 4144) {
2508       str = "MAC 386 on OS 10.3";
2509     } else if (sysVer >= 4128) {
2510       str = "MAC 386 on OS 10.2";
2511     } else if (sysVer >= 4112) {
2512       str = "MAC 386 on OS 10.1";
2513     } else {
2514       str = "MAC 386 on OS X";
2515     }
2516   }
2517 #else
2518   str = "MAC UNIX on OS X";
2519 #endif
2520 #endif
2521 #endif
2522 
2523 #ifdef OS_UNIX_SYSV
2524   str = "SYSV UNIX";
2525 #endif
2526 
2527 #ifdef OS_UNIX_SOL
2528   str = "SOLARIS UNIX";
2529 #ifdef PROC_I80X86
2530   str = "SOLARIS INTEL UNIX";
2531 #endif
2532 #endif
2533 
2534 #ifdef OS_UNIX_SUN
2535   str = "SUN UNIX";
2536 #endif
2537 #ifdef OS_UNIX_IRIX
2538   str = "SGI UNIX";
2539 #endif
2540 #ifdef OS_UNIX_LINUX
2541   str = "LINUX UNIX";
2542 #endif
2543 #endif
2544 
2545 #ifdef OS_MSWIN
2546   DWORD  version, lowbyte;
2547 
2548   str = "MS WINDOWS";
2549   version = GetVersion ();
2550   lowbyte = (version & 0x0000FF);
2551   if ((version & 0x80000000) == 0) {
2552     if (lowbyte == 6) {
2553       str = "MS WINDOWS VISTA";
2554     } else if (lowbyte == 5) {
2555       str = "MS WINDOWS 2000/XP";
2556     } else if (lowbyte == 4) {
2557       str = "MS WINDOWS NT 4.0";
2558     } else if (lowbyte == 3) {
2559       str = "MS WINDOWS NT 3.51";
2560     }
2561   } else {
2562     if (lowbyte == 4) {
2563       str = "MS WINDOWS 95/98/Me";
2564     } else if (lowbyte == 3) {
2565       str = "MS WINDOWS 3.1";
2566     }
2567   }
2568 #endif
2569 
2570   return Nlm_StringSave (str);
2571 }
2572 
2573 

source navigation ]   [ diff markup ]   [ identifier search ]   [ freetext search ]   [ file search ]  

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.