1 #ifndef CORELIB__NCBIEXEC__HPP
2 #define CORELIB__NCBIEXEC__HPP
3 
4 /*  $Id: ncbiexec.hpp 574926 2018-11-20 20:23:54Z ucko $
5  * ===========================================================================
6  *
7  *                            PUBLIC DOMAIN NOTICE
8  *               National Center for Biotechnology Information
9  *
10  *  This software/database is a "United States Government Work" under the
11  *  terms of the United States Copyright Act.  It was written as part of
12  *  the author's official duties as a United States Government employee and
13  *  thus cannot be copyrighted.  This software/database is freely available
14  *  to the public for use. The National Library of Medicine and the U.S.
15  *  Government have not placed any restriction on its use or reproduction.
16  *
17  *  Although all reasonable efforts have been taken to ensure the accuracy
18  *  and reliability of the software and data, the NLM and the U.S.
19  *  Government do not and cannot warrant the performance or results that
20  *  may be obtained by using this software or data. The NLM and the U.S.
21  *  Government disclaim all warranties, express or implied, including
22  *  warranties of performance, merchantability or fitness for any particular
23  *  purpose.
24  *
25  *  Please cite the author in any work or product based on this material.
26  *
27  * ===========================================================================
28  *
29  * Author:  Vladimir Ivanov
30  *
31  *
32  */
33 
34 /// @file ncbiexec.hpp
35 /// Defines a portable execute class.
36 
37 
38 #include <corelib/ncbi_process.hpp>
39 
40 
41 /** @addtogroup Exec
42  *
43  * @{
44  */
45 
46 
47 BEGIN_NCBI_SCOPE
48 
49 
50 /// Exit code type
51 typedef int TExitCode;
52 
53 
54 /////////////////////////////////////////////////////////////////////////////
55 ///
56 /// CExec --
57 ///
58 /// Define portable exec class.
59 ///
60 /// Defines the different ways a process can be spawned.
61 
62 class NCBI_XNCBI_EXPORT CExec
63 {
64 public:
65     /// Modification flags for EMode.
66     ///
67     /// @note
68     /// These flags works on UNIX only, and will be ignored on MS Windows.
69     /// Also, they don't work for eOverlay/eDetach modes.
70     enum EModeFlags {
71         /// After fork() move a process to new group (assign new PGID).
72         /// This can be useful if new created process also spawns child
73         /// processes and you wish to control it using signals, or,
74         /// for example, terminate the whole process group at once.
75         fNewGroup  = (1 << 8),
76         /// Mask for all master modes, all EModeFlags must be above it.
77         fModeMask  = 0x0F  // eOverlay | eWait | eNoWait | eDetach
78     };
79 
80     /// Which exec mode the spawned process is called with.
81     enum EMode {
82         /// Overlays calling process with new process, destroying calling
83         /// process.
84         eOverlay     = 0,
85         /// Suspends calling thread until execution of new process
86         /// is complete (synchronous operation).
87         eWait        = 1,
88         /// The same as eWait, but on UNIX platforms new process group
89         /// will be created and calling process become the leader of the new
90         /// process group.
91         eWaitGroup = eWait | fNewGroup,
92         /// Continues to execute calling process concurrently with new
93         /// process (asynchronous process). Do not forget to call Wait()
94         /// to get process exit code, or started process will became
95         /// a "zombie", even it has finished all work.
96         eNoWait      = 2,
97         /// The same as eNoWait, but on UNIX platforms new process group
98         /// will be created and calling process become the leader of the new
99         /// process group.
100         eNoWaitGroup = eNoWait | fNewGroup,
101         /// Like eNoWait, continues to execute calling process; new process
102         /// is run in background with no access to console or keyboard.
103         /// On UNIX new created process become the leader of the new session,
104         /// the process group leader of the new process group.
105         /// Calls to Wait() against new process will fail on MS Windows,
106         /// but work on UNIX platforms. This is an asynchronous spawn.
107         eDetach      = 3
108     };
109 
110     /// The result type for Spawn methods.
111     ///
112     /// In the eNoWait and eDetach modes for Spawn functions to return process
113     /// handles.  On MS Windows it is a real process handle of type HANDLE.
114     /// On UNIX it is a process identifier (pid).
115     /// In the eWait mode, the spawn functions return exit code of a process.
116     /// Throws an exception if you try to get exit code instead of
117     /// stored process handle, and otherwise.
118     /// In some cases can store both - an exit code and a handle (see Wait()).
119     class NCBI_XNCBI_EXPORT CResult
120     {
121     public:
122         /// Default ctor -- zero everything
CResult()123         CResult() : m_Flags(0) { memset(&m_Result, 0, sizeof(m_Result)); }
124         /// Get exit code
125         TExitCode      GetExitCode     (void);
126         /// Get process handle/pid
127         TProcessHandle GetProcessHandle(void);
128         // Deprecated operator for compatibility with previous
129         // versions of Spawn methods which returns integer value.
130         NCBI_DEPRECATED operator intptr_t(void) const;
131 
132     private:
133         /// Flags defines what this class store
134         enum EFlags {
135             fExitCode  = (1<<1),
136             fHandle    = (1<<2),
137             fBoth      = fExitCode | fHandle
138         };
139         typedef int TFlags;  ///< Binary OR of "EFlags"
140         struct {
141             TExitCode      exitcode;
142             TProcessHandle handle;
143         } m_Result;          ///< Result of Spawn*() methods
144         TFlags m_Flags;      ///< What m_Result stores
145 
146         friend class CExec;
147     };
148 
149     /// Execute the specified command.
150     ///
151     /// Execute the command and return the executed command's exit code.
152     /// Throw an exception if command failed to execute. If cmdline is a null
153     /// pointer, System() checks if the shell (command interpreter) exists and
154     /// is executable. If the shell is available, System() returns a non-zero
155     /// value; otherwise, it returns 0.
156     static TExitCode System(const char* cmdline);
157 
158     /// Quote argument.
159     ///
160     /// Enclose argument in quotes if necessary.
161     /// Used for concatenation arguments into command line.
162     /// @note
163     ///   Do not use this function with Spawn*() methods. Im most cases they
164     ///   don't need it, because all parameters passes to system separately,
165     ///   and automatically use more advanced and OS-specific algorithm for this
166     ///   if quoting is really necessary.
167     /// @sa System
168     static string QuoteArg(const string& arg);
169 
170     /// Spawn a new process with specified command-line arguments.
171     ///
172     /// In the SpawnL() version, the command-line arguments are passed
173     /// individually. SpawnL() is typically used when number of parameters to
174     /// the new process is known in advance.
175     ///
176     /// Meaning of the suffix "L" in method name:
177     /// - The letter "L" as suffix refers to the fact that command-line
178     ///   arguments are passed separately as arguments.
179     ///
180     /// @param mode
181     ///   Mode for running the process.
182     /// @param cmdname
183     ///   Path to the process to spawn.
184     /// @param argv
185     ///   First argument vector parameter.
186     /// @param ...
187     ///   Argument vector. Must ends with NULL.
188     /// @return
189     ///   On success, return:
190     ///     - exit code      - in eWait mode.
191     ///     - process handle - in eNoWait and eDetach modes.
192     ///     - nothing        - in eOverlay mode.
193     ///   Throw an exception if command failed to execute.
194     /// @sa
195     ///   SpawnLE(), SpawnLP(), SpawnLPE(), SpawnV(), SpawnVE(), SpawnVP(),
196     ///   SpawnVPE().
197     static CResult
198     SpawnL(EMode mode, const char *cmdname, const char *argv, .../*, NULL */);
199 
200     /// Spawn a new process with specified command-line arguments and
201     /// environment settings.
202     ///
203     /// In the SpawnLE() version, the command-line arguments and environment
204     /// pointer are passed individually. SpawnLE() is typically used when
205     /// number of parameters to the new process and individual environment
206     /// parameter settings are known in advance.
207     ///
208     /// Meaning of the suffix "LE" in method name:
209     /// - The letter "L" as suffix refers to the fact that command-line
210     ///   arguments are passed separately as arguments.
211     /// - The letter "E" as suffix refers to the fact that environment pointer,
212     ///   envp, is passed as an array of pointers to environment settings to
213     ///   the new process. The NULL environment pointer indicates that the new
214     ///   process will inherit the parents process's environment.
215     ///
216     /// @param mode
217     ///   Mode for running the process.
218     /// @param cmdname
219     ///   Path of file to be executed.
220     /// @param argv
221     ///   First argument vector parameter.
222     /// @param ...
223     ///   Argument vector. Must ends with NULL.
224     /// @param envp
225     ///   Pointer to vector with environment variables which will be used
226     ///   instead of current environment. Last value in vector must be NULL.
227     /// @return
228     ///   On success, return:
229     ///     - exit code      - in eWait mode.
230     ///     - process handle - in eNoWait and eDetach modes.
231     ///     - nothing        - in eOverlay mode.
232     ///   Throw an exception if command failed to execute.
233     /// @sa
234     ///   SpawnL(), SpawnLP(), SpawnLPE(), SpawnV(), SpawnVE(), SpawnVP(),
235     ///   SpawnVPE().
236     static CResult
237     SpawnLE (EMode mode, const char *cmdname,
238              const char *argv, ... /*, NULL, const char *envp[] */);
239 
240     /// Spawn a new process with variable number of command-line arguments and
241     /// find file to execute from the PATH environment variable.
242     ///
243     /// In the SpawnLP() version, the command-line arguments are passed
244     /// individually and the PATH environment variable is used to find the
245     /// file to execute. SpawnLP() is typically used when number
246     /// of parameters to the new process is known in advance but the exact
247     /// path to the executable is not known.
248     ///
249     /// Meaning of the suffix "LP" in method name:
250     /// - The letter "L" as suffix refers to the fact that command-line
251     ///   arguments are passed separately as arguments.
252     /// - The letter "P" as suffix refers to the fact that the PATH
253     ///   environment variable is used to find file to execute - on a Unix
254     ///   platform this feature works in functions without letter "P" in
255     ///   function name.
256     ///
257     /// @param mode
258     ///   Mode for running the process.
259     /// @param cmdname
260     ///   Path of file to be executed.
261     /// @param argv
262     ///   First argument vector parameter.
263     /// @param ...
264     ///   Argument vector. Must ends with NULL.
265     /// @return
266     ///   On success, return:
267     ///     - exit code      - in eWait mode.
268     ///     - process handle - in eNoWait and eDetach modes.
269     ///     - nothing        - in eOverlay mode.
270     ///   Throw an exception if command failed to execute.
271     /// @sa
272     ///   SpawnL(), SpawnLE(), SpawnLPE(), SpawnV(), SpawnVE(), SpawnVP(),
273     ///   SpawnVPE().
274     static CResult
275     SpawnLP(EMode mode, const char *cmdname, const char *argv, .../*, NULL*/);
276 
277     /// Spawn a new process with specified command-line arguments,
278     /// environment settings and find file to execute from the PATH
279     /// environment variable.
280     ///
281     /// In the SpawnLPE() version, the command-line arguments and environment
282     /// pointer are passed individually, and the PATH environment variable
283     /// is used to find the file to execute. SpawnLPE() is typically used when
284     /// number of parameters to the new process and individual environment
285     /// parameter settings are known in advance, but the exact path to the
286     /// executable is not known.
287     ///
288     /// Meaning of the suffix "LPE" in method name:
289     /// - The letter "L" as suffix refers to the fact that command-line
290     ///   arguments are passed separately as arguments.
291     /// - The letter "P" as suffix refers to the fact that the PATH
292     ///   environment variable is used to find file to execute - on a Unix
293     ///   platform this feature works in functions without letter "P" in
294     ///   function name.
295     /// - The letter "E" as suffix refers to the fact that environment pointer,
296     ///   envp, is passed as an array of pointers to environment settings to
297     ///   the new process. The NULL environment pointer indicates that the new
298     ///   process will inherit the parents process's environment.
299     ///
300     /// @param mode
301     ///   Mode for running the process.
302     /// @param cmdname
303     ///   Path of file to be executed.
304     /// @param argv
305     ///   First argument vector parameter.
306     /// @param ...
307     ///   Argument vector. Must ends with NULL.
308     /// @param envp
309     ///   Pointer to vector with environment variables which will be used
310     ///   instead of current environment. Last value in an array must be NULL.
311     /// @return
312     ///   On success, return:
313     ///     - exit code      - in eWait mode.
314     ///     - process handle - in eNoWait and eDetach modes.
315     ///     - nothing        - in eOverlay mode.
316     ///    Throw an exception if command failed to execute.
317     /// @sa
318     ///   SpawnL(), SpawnLE(), SpawnLP(), SpawnV(), SpawnVE(), SpawnVP(),
319     ///   SpawnVPE().
320     static CResult
321     SpawnLPE(EMode mode, const char *cmdname,
322              const char *argv, ... /*, NULL, const char *envp[] */);
323 
324     /// Spawn a new process with variable number of command-line arguments.
325     ///
326     /// In the SpawnV() version, the command-line arguments are a variable
327     /// number. The array of pointers to arguments must have a length of 1 or
328     /// more and you must assign parameters for the new process beginning
329     /// from 1.
330     ///
331     /// Meaning of the suffix "V" in method name:
332     /// - The letter "V" as suffix refers to the fact that the number of
333     /// command-line arguments are variable.
334     ///
335     /// @param mode
336     ///   Mode for running the process.
337     /// @param cmdline
338     ///   Path of file to be executed.
339     /// @param argv
340     ///   Pointer to argument vector. Last value in vector must be NULL.
341     /// @return
342     ///   On success, return:
343     ///     - exit code      - in eWait mode.
344     ///     - process handle - in eNoWait and eDetach modes.
345     ///     - nothing        - in eOverlay mode.
346     ///   Throw an exception if command failed to execute.
347     /// @sa
348     ///   SpawnL(), SpawnLE(), SpawnLP(), SpawnLPE(), SpawnVE(), SpawnVP(),
349     ///   SpawnVPE().
350     static CResult
351     SpawnV(EMode mode, const char *cmdname, const char *const *argv);
352 
353     /// Spawn a new process with variable number of command-line arguments
354     /// and specified environment settings.
355     ///
356     /// In the SpawnVE() version, the command-line arguments are a variable
357     /// number. The array of pointers to arguments must have a length of 1 or
358     /// more and you must assign parameters for the new process beginning from
359     /// 1.  The individual environment parameter settings are known in advance
360     /// and passed explicitly.
361     ///
362     /// Meaning of the suffix "VE" in method name:
363     /// - The letter "V" as suffix refers to the fact that the number of
364     ///   command-line arguments are variable.
365     /// - The letter "E" as suffix refers to the fact that environment pointer,
366     ///   envp, is passed as an array of pointers to environment settings to
367     ///   the new process. The NULL environment pointer indicates that the new
368     ///   process will inherit the parents process's environment.
369     ///
370     /// @param mode
371     ///   Mode for running the process.
372     /// @param cmdname
373     ///   Path of file to be executed.
374     /// @param argv
375     ///   Argument vector. Last value must be NULL.
376     /// @param envp
377     ///   Pointer to vector with environment variables which will be used
378     ///   instead of current environment. Last value in an array must be NULL.
379     /// @return
380     ///   On success, return:
381     ///     - exit code      - in eWait mode.
382     ///     - process handle - in eNoWait and eDetach modes.
383     ///     - nothing        - in eOverlay mode.
384     ///   Throw an exception if command failed to execute.
385     /// @sa
386     ///   SpawnL(), SpawnLE(), SpawnLP(), SpawnLPE(), SpawnV(), SpawnVP(),
387     ///   SpawnVPE().
388     static CResult
389     SpawnVE(EMode mode, const char *cmdname,
390             const char *const *argv, const char *const *envp);
391 
392     /// Spawn a new process with variable number of command-line arguments and
393     /// find file to execute from the PATH environment variable.
394     ///
395     /// In the SpawnVP() version, the command-line arguments are a variable
396     /// number. The array of pointers to arguments must have a length of 1 or
397     /// more and you must assign parameters for the new process beginning from
398     /// 1. The PATH environment variable is used to find the file to execute.
399     ///
400     /// Meaning of the suffix "VP" in method name:
401     /// - The letter "V" as suffix refers to the fact that the number of
402     ///   command-line arguments are variable.
403     /// - The letter "P" as suffix refers to the fact that the PATH
404     ///   environment variable is used to find file to execute - on a Unix
405     ///   platform this feature works in functions without letter "P" in
406     ///   function name.
407     ///
408     /// @param mode
409     ///   Mode for running the process.
410     /// @param cmdname
411     ///   Path of file to be executed.
412     /// @param argv
413     ///   Pointer to argument vector. Last value in vector must be NULL.
414     /// @return
415     ///   On success, return:
416     ///     - exit code      - in eWait mode.
417     ///     - process handle - in eNoWait and eDetach modes.
418     ///     - nothing        - in eOverlay mode.
419     ///   Throw an exception if command failed to execute.
420     /// @sa
421     ///   SpawnL(), SpawnLE(), SpawnLP(), SpawnLPE(), SpawnV(), SpawnVE(),
422     ///   SpawnVPE().
423     static CResult
424     SpawnVP(EMode mode, const char *cmdname, const char *const *argv);
425 
426     /// Spawn a new process with variable number of command-line arguments
427     /// and specified environment settings, and find the file to execute
428     /// from the PATH environment variable.
429     ///
430     /// In the SpawnVPE() version, the command-line arguments are a variable
431     /// number. The array of pointers to arguments must have a length of 1 or
432     /// more and you must assign parameters for the new process beginning from
433     /// 1. The PATH environment variable is used to find the file to execute,
434     /// and the environment is passed via an environment vector pointer.
435     ///
436     /// Meaning of the suffix "VPE" in method name:
437     /// - The letter "V" as suffix refers to the fact that the number of
438     ///   command-line arguments are variable.
439     /// - The letter "P" as suffix refers to the fact that the PATH
440     ///   environment variable is used to find file to execute - on a Unix
441     ///   platform this feature works in functions without letter "P" in
442     ///   function name.
443     /// - The letter "E" as suffix refers to the fact that environment pointer,
444     ///   envp, is passed as an array of pointers to environment settings to
445     ///   the new process. The NULL environment pointer indicates that the new
446     ///   process will inherit the parents process's environment.
447     ///
448     /// @param mode
449     ///   Mode for running the process.
450     /// @param cmdname
451     ///   Path of file to be executed.
452     /// @param argv
453     ///   Argument vector. Last value must be NULL.
454     /// @param envp
455     ///   Pointer to vector with environment variables which will be used
456     ///   instead of current environment. Last value in an array must be NULL.
457     /// @return
458     ///   On success, return:
459     ///     - exit code      - in eWait mode.
460     ///     - process handle - in eNoWait and eDetach modes.
461     ///     - nothing        - in eOverlay mode.
462     ///   Throw an exception if command failed to execute.
463     /// @sa
464     ///   SpawnL(), SpawnLE(), SpawnLP(), SpawnLPE(), SpawnV(), SpawnVE(),
465     ///   SpawnVP(),
466     static CResult
467     SpawnVPE(EMode mode, const char *cmdname,
468              const char *const *argv, const char *const *envp);
469 
470     /// Wait until specified process terminates.
471     ///
472     /// Wait until the process with "handle" terminates, and return
473     /// immediately if the specified process has already terminated.
474     /// @param handle
475     ///   Wait on process with identifier "handle", returned by one
476     ///   of the Spawn* function in eNoWait and eDetach modes.
477     /// @param timeout
478     ///   Time-out interval. By default it is infinite.
479     /// @return
480     ///   - Exit code of the process, if no errors.
481     ///   - (-1), if error has occurred.
482     /// @note
483     ///   It is recommended to call this method for all processes started
484     ///   in eNoWait or eDetach modes (except on Windows for eDetach), because
485     ///   it release "zombie" processes, that finished working and waiting
486     ///   to return it's exit status. If Wait() is not called somewhere,
487     ///   the child process will be completely removed from the system only
488     ///   when the parent process ends.
489     /// @sa
490     ///   CProcess::Wait(), CProcess:IsAlive(), TMode
491     static TExitCode Wait(TProcessHandle handle,
492                           unsigned long  timeout = kInfiniteTimeoutMs);
493 
494     /// Mode used to wait processes termination.
495     enum EWaitMode {
496         eWaitAny,     ///< Wait any process to terminate
497         eWaitAll      ///< Wait all processes to terminate
498     };
499 
500     /// Wait until any/all processes terminates.
501     ///
502     /// Wait until any/all processes from specified list terminates.
503     /// Return immediately if the specified processes has already terminated.
504     /// @param handles
505     ///   List of process identifiers. Each identifier is a value returned
506     ///   by one of the Spawn* function in eNoWait and eDetach modes.
507     ///   Handles for terminated processes going to "result" list, and
508     ///   has been removed from this one.
509     /// @param mode
510     ///   Wait termination for any or all possible processes within
511     ///   specified timeout.
512     ///    eWaitAny - wait until at least one process terminates.
513     ///    eWaitAll - wait until all processes terminates or timeout expires.
514     /// @param result
515     ///   List of process handles/exitcodes of terminated processes from
516     ///   the list "handles". If this list have elements, that they will
517     ///   be removed.
518     /// @param timeout
519     ///   Time-out interval. By default it is infinite.
520     /// @return
521     ///   - Number of terminated processes (size of the "result" list),
522     ///     if no errors. Regardless of timeout status.
523     ///   - (-1), if error has occurred.
524     /// @sa
525     ///   Wait(), CProcess::Wait(), CProcess:IsAlive()
526     static int Wait(list<TProcessHandle>& handles,
527                     EWaitMode             mode,
528                     list<CResult>&        result,
529                     unsigned long         timeout = kInfiniteTimeoutMs);
530 
531     /// Run console application in invisible mode.
532     ///
533     /// MS Windows:
534     ///    This function try to run a program in invisible mode, without
535     ///    visible window. This can be used to run console program from
536     ///    non-console application. If it runs from console application,
537     ///    the parent's console window can be used by child process.
538     ///    Executing non-console program can show theirs windows or not,
539     ///    this depends. In eDetach mode the main window/console of
540     ///    the running program can be visible, use eNoWait instead.
541     /// @note
542     ///    If the running program cannot self-terminate, that
543     ///    it can be never terminated.
544     /// Unix:
545     ///    In current implementation equal to SpawnL().
546     /// @param mode
547     ///   Mode for running the process.
548     /// @param cmdname
549     ///   Path to the process to spawn.
550     /// @param argv
551     ///   First argument vector parameter.
552     /// @param ...
553     ///   Argument vector. Must ends with NULL.
554     /// @return
555     ///   On success, return:
556     ///     - exit code      - in eWait mode.
557     ///     - process handle - in eNoWait and eDetach modes.
558     ///     - nothing        - in eOverlay mode.
559     ///   Throw an exception if command failed to execute.
560     /// @sa
561     ///   SpawnL(), TMode
562     static CResult
563     RunSilent(EMode mode, const char *cmdname,
564               const char *argv, ... /*, NULL */);
565 
566     /// Check executable permissions for specified file.
567     ///
568     /// @note
569     ///   This is no guarantee that the file is executable even if
570     ///   the function returns TRUE. It try to get effective user
571     ///   permissions for specified file, but sometimes this
572     ///   is not possible.
573     /// @param path
574     ///   Path to the file to check.
575     /// @return
576     ///   TRUE if file is executable, FALSE otherwise.
577     /// @sa
578     ///   CFile::CheckAccess
579     static bool IsExecutable(const string& path);
580 
581     /// Find executable file.
582     ///
583     /// If necessary, the PATH environment variable is used
584     /// to find the file to execute
585     /// @param filename
586     ///   Name of the file to search.
587     /// @return
588     ///   Path to the executable file. kEmptyStr if not found,
589     ///   or the file do not have executable permissions.
590     /// @sa
591     ///   IsExecutable
592     static string ResolvePath(const string& filename);
593 };
594 
595 
596 /////////////////////////////////////////////////////////////////////////////
597 ///
598 /// CExecException --
599 ///
600 /// Define exceptions generated by CExec.
601 ///
602 /// CExecException inherits its basic functionality from
603 /// CErrnoTemplException<CCoreException> and defines additional error codes
604 /// for errors generated by CExec.
605 
606 class NCBI_XNCBI_EXPORT CExecException : public CErrnoTemplException<CCoreException>
607 {
608 public:
609     /// Error types that CExec can generate.
610     enum EErrCode {
611         eSystem,      ///< System error
612         eSpawn,       ///< Spawn error
613         eResult       ///< Result interpretation error
614     };
615 
616     /// Translate from the error code value to its string representation.
617     virtual const char* GetErrCodeString(void) const override;
618 
619     // Standard exception boilerplate code.
620     NCBI_EXCEPTION_DEFAULT(CExecException,
621                            CErrnoTemplException<CCoreException>);
622 };
623 
624 
625 END_NCBI_SCOPE
626 
627 
628 /* @} */
629 
630 #endif  /* CORELIB__NCBIEXEC__HPP */
631