1 /**
2  * Copyright (c) 2015, Timothy Stack
3  *
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  * * Neither the name of Timothy Stack nor the names of its contributors
15  * may be used to endorse or promote products derived from this software
16  * without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
25  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef LNAV_COMMAND_EXECUTOR_H
31 #define LNAV_COMMAND_EXECUTOR_H
32 
33 #include <sqlite3.h>
34 
35 #include <future>
36 #include <string>
37 
38 #include "fmt/format.h"
39 #include "optional.hpp"
40 #include "auto_fd.hh"
41 #include "attr_line.hh"
42 #include "shlex.hh"
43 #include "log_format.hh"
44 #include "bookmarks.hh"
45 
46 struct exec_context;
47 
48 typedef int (*sql_callback_t)(exec_context &ec, sqlite3_stmt *stmt);
49 int sql_callback(exec_context &ec, sqlite3_stmt *stmt);
50 
51 typedef std::future<std::string> (*pipe_callback_t)(
52     exec_context &ec, const std::string &cmdline, auto_fd &fd);
53 
54 struct exec_context {
55     enum class perm_t {
56         READ_WRITE,
57         READ_ONLY,
58     };
59 
60     using output_t = std::pair<FILE *, int(*)(FILE *)>;
61 
exec_contextexec_context62     exec_context(std::vector<logline_value> *line_values = nullptr,
63                  sql_callback_t sql_callback = ::sql_callback,
64                  pipe_callback_t pipe_callback = nullptr)
65         : ec_line_values(line_values),
66           ec_sql_callback(sql_callback),
67           ec_pipe_callback(pipe_callback) {
68         this->ec_local_vars.push(std::map<std::string, std::string>());
69         this->ec_path_stack.emplace_back(".");
70         this->ec_source.emplace("command", 1);
71         this->ec_output_stack.emplace_back("screen", nonstd::nullopt);
72     }
73 
is_read_writeexec_context74     bool is_read_write() const {
75         return this->ec_perms == perm_t::READ_WRITE;
76     }
77 
is_read_onlyexec_context78     bool is_read_only() const {
79         return this->ec_perms == perm_t::READ_ONLY;
80     }
81 
with_permsexec_context82     exec_context& with_perms(perm_t perms) {
83         this->ec_perms = perms;
84         return *this;
85     }
86 
87     std::string get_error_prefix();
88 
89     template<typename ...Args>
make_errorexec_context90     Result<std::string, std::string> make_error(
91         fmt::string_view format_str, const Args& ...args) {
92         return Err(this->get_error_prefix() +
93                fmt::vformat(format_str, fmt::make_format_args(args...)));
94     }
95 
get_outputexec_context96     nonstd::optional<FILE *> get_output() {
97         for (auto iter = this->ec_output_stack.rbegin();
98              iter != this->ec_output_stack.rend();
99              ++iter) {
100             if (iter->second && (*iter->second).first) {
101                 return (*iter->second).first;
102             }
103         }
104 
105         return nonstd::nullopt;
106     }
107 
108     void set_output(const std::string& name, FILE *file, int (*closer)(FILE *));
109 
110     void clear_output();
111 
112     struct source_guard {
source_guardexec_context::source_guard113         source_guard(exec_context &context) : sg_context(context) {
114 
115         }
116 
~source_guardexec_context::source_guard117         ~source_guard() {
118             this->sg_context.ec_source.pop();
119         }
120 
121         exec_context &sg_context;
122     };
123 
124     struct output_guard {
125         explicit output_guard(exec_context &context,
126                               std::string name = "default",
127                               const nonstd::optional<output_t>& file = nonstd::nullopt);
128 
129         ~output_guard();
130 
131         exec_context &sg_context;
132     };
133 
enter_sourceexec_context134     source_guard enter_source(const std::string& path, int line_number) {
135         this->ec_source.emplace(path, line_number);
136         return source_guard(*this);
137     }
138 
create_resolverexec_context139     scoped_resolver create_resolver() {
140         return {
141             &this->ec_local_vars.top(),
142             &this->ec_global_vars,
143         };
144     }
145 
146     vis_line_t ec_top_line{0_vl};
147     bool ec_dry_run{false};
148     perm_t ec_perms{perm_t::READ_WRITE};
149 
150     std::map<std::string, std::string> ec_override;
151     std::vector<logline_value> *ec_line_values;
152     std::stack<std::map<std::string, std::string> > ec_local_vars;
153     std::map<std::string, std::string> ec_global_vars;
154     std::vector<ghc::filesystem::path> ec_path_stack;
155     std::stack<std::pair<std::string, int>> ec_source;
156 
157     std::vector<std::pair<std::string, nonstd::optional<output_t>>> ec_output_stack;
158 
159     attr_line_t ec_accumulator;
160 
161     sql_callback_t ec_sql_callback;
162     pipe_callback_t ec_pipe_callback;
163 };
164 
165 Result<std::string, std::string> execute_command(exec_context &ec, const std::string &cmdline);
166 
167 Result<std::string, std::string> execute_sql(exec_context &ec, const std::string &sql, std::string &alt_msg);
168 Result<std::string, std::string> execute_file(exec_context &ec, const std::string &path_and_args, bool multiline = true);
169 Result<std::string, std::string> execute_any(exec_context &ec, const std::string &cmdline);
170 void execute_init_commands(exec_context &ec, std::vector<std::pair<Result<std::string, std::string>, std::string> > &msgs);
171 
172 std::future<std::string> pipe_callback(
173     exec_context &ec, const std::string &cmdline, auto_fd &fd);
174 
175 int sql_progress(const struct log_cursor &lc);
176 void sql_progress_finished();
177 
178 void add_global_vars(exec_context &ec);
179 
180 #endif //LNAV_COMMAND_EXECUTOR_H
181