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