2 * @brief run an external filter and capture its output in a std::string.
4 /* Copyright (C) 2007,2013,2015,2019,2024 Olly Betts
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #ifndef OMEGA_INCLUDED_RUNFILTER_H
22 #define OMEGA_INCLUDED_RUNFILTER_H
27 /// Exception thrown if we encounter a read error.
29 const char* msg
= NULL
;
31 explicit ReadError(const char * m
) : msg(m
) { }
32 explicit ReadError(int s
) : status(s
) { }
33 std::string
str() const {
36 std::snprintf(buf
, sizeof(buf
), "0x%08x", status
);
41 /// Exception thrown if the filter program isn't found.
42 struct NoSuchFilter
{ };
44 /** Analyse if a command needs the shell.
46 * The return value of this function can be passed as the second argument of
47 * run_filter()/stdout_to_string().
49 bool command_needs_shell(const char * p
);
51 /// Initialise the runfilter module.
52 void runfilter_init();
54 /** Run command @a cmd, optionally capturing its stdout.
56 * @param fd_in FD for piped input, or -1 for input from file.
57 * @param cmd The command to run as a NULL terminated argv array.
58 * @param out Pointer to std::string to put stdout in or NULL to
59 * discard stdout. (default: NULL)
60 * @param alt_status Exit status to treat as success in addition to 0
61 * (default: Only treat exit status 0 as success).
63 * If the command isn't installed (detected by exit status 127) then
64 * NoSuchFilter is thrown.
66 * If the command fails to completed successfully (detected by an exit status
67 * other than 0 or alt_status) then ReadError is thrown.
69 void run_filter(int fd_in
,
70 const char* const cmd
[],
71 std::string
* out
= nullptr,
74 /** Run command @a cmd, optionally capturing its stdout.
76 * @param fd_in FD for piped input, or -1 for input from file.
77 * @param cmd The command to run.
78 * @param use_shell If false, try to avoid using a shell to run the command.
79 * @param out Pointer to std::string to put stdout in or NULL to
80 * discard stdout. (default: NULL)
81 * @param alt_status Exit status to treat as success in addition to 0
82 * (default: Only treat exit status 0 as success).
84 * This is like the overloaded version taking an argv array except that
85 * it takes the command as a single string, plus a use_shell flag
86 * indicating whether the command string can be run without a shell.
88 * Note: use_shell=false mode makes some assumptions about the command:
90 * * only single quotes are used (double quotes and backslash quoting are
91 * not currently handled, aside from in the four character sequence '\''
92 * within single quotes).
93 * * the following redirections are supported, but they must be unquoted and
94 * appear exactly as shown, and each be a separate word in the command:
95 * >/dev/null 2>/dev/null 2>&1 1>&2
96 * * environment variables set before the command are handled correctly,
97 * for example: LANG=C some-command
99 * The command_needs_shell() function above can be used to check a command,
100 * but is somewhat more conservative than what this function actually
103 * Currently the shell is only actually avoided for systems with both fork()
104 * and socketpair(). Other systems will ignore use_shell and always use the
105 * same code path (which may or may not involve some analog of the Unix
108 * If the command isn't installed (detected by exit status 127) then
109 * NoSuchFilter is thrown.
111 * If the command fails to completed successfully (detected by an exit status
112 * other than 0 or alt_status) then ReadError is thrown.
114 void run_filter(int fd_in
,
115 const std::string
& cmd
,
117 std::string
* out
= nullptr,
121 run_filter(const char* const cmd
[],
122 std::string
* out
= nullptr,
125 run_filter(-1, cmd
, out
, alt_status
);
129 run_filter(const std::string
& cmd
,
131 std::string
* out
= nullptr,
134 run_filter(-1, cmd
, use_shell
, out
, alt_status
);
137 /** Run command @a cmd, capture its stdout, and return it as a std::string.
139 * This is a simple wrapper around run_filter().
141 static inline std::string
142 stdout_to_string(const char* const cmd
[], int alt_status
= 0)
145 run_filter(cmd
, &out
, alt_status
);
149 /** Run command @a cmd, capture its stdout, and return it as a std::string.
151 * This is a simple wrapper around run_filter().
153 static inline std::string
154 stdout_to_string(const std::string
& cmd
, bool use_shell
, int alt_status
= 0)
157 run_filter(cmd
, use_shell
, &out
, alt_status
);
161 #endif // OMEGA_INCLUDED_RUNFILTER_H