/*
* Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
*
* All rights reserved.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version 3.0 only,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* version 3.0 along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef __STDC_LIMIT_MACROS
# define __STDC_LIMIT_MACROS
#endif
#ifndef __STDC_CONSTANT_MACROS
# define __STDC_CONSTANT_MACROS
#endif
#include "objfw-defs.h"
#ifdef OF_HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#import "OFStream.h"
#import "OFKernelEventObserver.h"
#import "OFString.h"
#ifdef OF_WINDOWS
# include <windows.h>
#endif
OF_ASSUME_NONNULL_BEGIN
@class OFArray OF_GENERIC(ObjectType);
@class OFDictionary OF_GENERIC(KeyType, ObjectType);
/**
* @class OFSubprocess OFSubprocess.h ObjFW/ObjFW.h
*
* @brief A class for stream-like communication with a newly created subprocess.
*/
OF_SUBCLASSING_RESTRICTED
@interface OFSubprocess: OFStream
#ifndef OF_WINDOWS
<OFReadyForReadingObserving, OFReadyForWritingObserving>
#endif
{
#ifndef OF_WINDOWS
pid_t _pid;
int _readPipe[2], _writePipe[2];
#else
HANDLE _handle, _readPipe[2], _writePipe[2];
#endif
int _status;
bool _atEndOfStream;
}
/**
* @brief Creates a new OFSubprocess with the specified program and invokes the
* program.
*
* @param program The program to execute. If it does not start with a slash, the
* search path specified in PATH is used.
* @return A new, autoreleased OFSubprocess.
*/
+ (instancetype)subprocessWithProgram: (OFString *)program;
/**
* @brief Creates a new OFSubprocess with the specified program and arguments
* and invokes the program.
*
* @param program The program to execute. If it does not start with a slash, the
* search path specified in PATH is used.
* @param arguments The arguments to pass to the program, or `nil`
* @return A new, autoreleased OFSubprocess.
*/
+ (instancetype)
subprocessWithProgram: (OFString *)program
arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments;
/**
* @brief Creates a new OFSubprocess with the specified program, program name
* and arguments and invokes the program.
*
* @param program The program to execute. If it does not start with a slash, the
* search path specified in PATH is used.
* @param programName The program name for the program to invoke (argv[0]).
* Usually, this is equal to program.
* @param arguments The arguments to pass to the program, or `nil`
* @return A new, autoreleased OFSubprocess.
*/
+ (instancetype)
subprocessWithProgram: (OFString *)program
programName: (OFString *)programName
arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments;
/**
* @brief Creates a new OFSubprocess with the specified program, program name,
* arguments and environment and invokes the program.
*
* @param program The program to execute. If it does not start with a slash, the
* search path specified in PATH is used.
* @param programName The program name for the program to invoke (argv[0]).
* Usually, this is equal to program.
* @param arguments The arguments to pass to the program, or `nil`
* @param environment The environment to pass to the program, or `nil`. If it
* is not `nil`, the passed dictionary will be used to
* override the environment. If you want to add to the
* existing environment, you need to get the existing
* environment first, copy it, modify it and then pass it.
* @return A new, autoreleased OFSubprocess.
*/
+ (instancetype)
subprocessWithProgram: (OFString *)program
programName: (OFString *)programName
arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments
environment: (nullable OFDictionary
OF_GENERIC(OFString *, OFString *) *)environment;
- (instancetype)init OF_UNAVAILABLE;
/**
* @brief Initializes an already allocated OFSubprocess with the specified
* program and invokes the program.
*
* @param program The program to execute. If it does not start with a slash, the
* search path specified in PATH is used.
* @return An initialized OFSubprocess.
*/
- (instancetype)initWithProgram: (OFString *)program;
/**
* @brief Initializes an already allocated OFSubprocess with the specified
* program and arguments and invokes the program.
*
* @param program The program to execute. If it does not start with a slash, the
* search path specified in PATH is used.
* @param arguments The arguments to pass to the program, or `nil`
* @return An initialized OFSubprocess.
*/
- (instancetype)
initWithProgram: (OFString *)program
arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments;
/**
* @brief Initializes an already allocated OFSubprocess with the specified
* program, program name and arguments and invokes the program.
*
* @param program The program to execute. If it does not start with a slash, the
* search path specified in PATH is used.
* @param programName The program name for the program to invoke (argv[0]).
* Usually, this is equal to program.
* @param arguments The arguments to pass to the program, or `nil`
* @return An initialized OFSubprocess.
*/
- (instancetype)
initWithProgram: (OFString *)program
programName: (OFString *)programName
arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments;
/**
* @brief Initializes an already allocated OFSubprocess with the specified
* program, program name, arguments and environment and invokes the
* program.
*
* @param program The program to execute. If it does not start with a slash, the
* search path specified in PATH is used.
* @param programName The program name for the program to invoke (argv[0]).
* Usually, this is equal to program.
* @param arguments The arguments to pass to the program, or `nil`
* @param environment The environment to pass to the program, or `nil`. If it
* is not `nil`, the passed dictionary will be used to
* override the environment. If you want to add to the
* existing environment, you need to get the existing
* environment first, copy it, modify it and then pass it.
* @return An initialized OFSubprocess.
*/
- (instancetype)
initWithProgram: (OFString *)program
programName: (OFString *)programName
arguments: (nullable OFArray OF_GENERIC(OFString *) *)arguments
environment: (nullable OFDictionary
OF_GENERIC(OFString *, OFString *) *)environment
OF_DESIGNATED_INITIALIZER;
/**
* @brief Closes the write direction of the subprocess.
*
* This method needs to be called for some programs before data can be read,
* since some programs don't start processing before the write direction is
* closed.
*
* @throw OFNotOpenException The subprocess was already closed
*/
- (void)closeForWriting;
/**
* @brief Waits for the subprocess to terminate and returns the exit status.
*
* If the subprocess has already exited, this returns the exit status
* immediately.
*
* @return The status code of the subprocess
* @throw OFNotOpenException The subprocess was already closed
*/
- (int)waitForTermination;
@end
OF_ASSUME_NONNULL_END