1 /* vifm
2  * Copyright (C) 2011 xaizek.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #ifndef VIFM__ENGINE__CMDS_H__
20 #define VIFM__ENGINE__CMDS_H__
21 
22 #include <stddef.h> /* size_t */
23 
24 #include "../utils/test_helpers.h"
25 
26 /* Error codes returned by vle_cmds_run(). */
27 enum
28 {
29 	/* Error codes are negative integers. */
30 	CMDS_ERR_LOOP = -128,         /* Too deep recursion of commands. */
31 	CMDS_ERR_NO_MEM,              /* Not enough memory. */
32 	CMDS_ERR_TOO_FEW_ARGS,        /* Not enough arguments. */
33 	CMDS_ERR_TRAILING_CHARS,      /* Too many arguments. */
34 	CMDS_ERR_INCORRECT_NAME,      /* Bad name for a user-defined command. */
35 	CMDS_ERR_NEED_BANG,           /* Need enforcing to succeed. */
36 	CMDS_ERR_NO_BUILTIN_REDEFINE, /* Can't shadow builtin command. */
37 	CMDS_ERR_INVALID_CMD,         /* Unknown command name. */
38 	CMDS_ERR_NO_BANG_ALLOWED,     /* The command doesn't support "!". */
39 	CMDS_ERR_NO_RANGE_ALLOWED,    /* The command doesn't take range. */
40 	CMDS_ERR_NO_QMARK_ALLOWED,    /* The command doesn't support "?". */
41 	CMDS_ERR_INVALID_RANGE,       /* Bad range. */
42 	CMDS_ERR_NO_SUCH_UDF,         /* Unknown name of a user-defined command. */
43 	CMDS_ERR_UDF_IS_AMBIGUOUS,    /* Calling user-defined command is ambiguous. */
44 	CMDS_ERR_INVALID_ARG,         /* Missing closing quote. */
45 	CMDS_ERR_CUSTOM,              /* Error defined by the client. */
46 };
47 
48 /* Constants related to command ids. */
49 enum
50 {
51 	/* Builtin commands have negative ids. */
52 	USER_CMD_ID = -256, /* <USERCMD> */
53 	COMCLEAR_CMD_ID,    /* :comc[lear] */
54 	COMMAND_CMD_ID,     /* :com[mand] */
55 	DELCOMMAND_CMD_ID,  /* :delc[ommand] */
56 
57 	/* Commands with ids in range [NO_COMPLETION_BOUNDARY; 0) are not
58 	 * completed. */
59 	NO_COMPLETION_BOUNDARY,
60 };
61 
62 /* Special values. */
63 enum
64 {
65 	/* Undefined maximum number of arguments for a command. */
66 	NOT_DEF = -8192,
67 };
68 
69 /* Command type. */
70 typedef enum
71 {
72 	BUILTIN_ABBR, /* Abbreviated version of a builtin command (like `:com`). */
73 	BUILTIN_CMD,  /* Builtin command. */
74 	USER_CMD,     /* User-defined command. */
75 }
76 CMD_TYPE;
77 
78 /* Detailed information resulted from command parsing, which is passed to
79  * command handler (cmd_handler). */
80 typedef struct cmd_info_t
81 {
82 	int begin, end; /* Parsed range of the command.  They are either valid and
83 	                   define range with both boundaries included or equal to
84 	                   NOT_DEF if no range was given. */
85 	int count;      /* Parsed [count] of the command. */
86 	int emark, qmark, bg;
87 	char sep;
88 	int usr1, usr2;
89 
90 	char *raw_args;  /* Arguments as they were passed in. */
91 	char *args;      /* Arguments after macro and envvar expansions. */
92 	int argc;        /* Number of arguments. */
93 	char **argv;     /* Values of arguments. */
94 	int (*argvp)[2]; /* Start/end positions of arguments in args. */
95 
96 	/* For user defined commands. */
97 	const char *user_cmd;    /* Name of user defined command. */
98 	const char *user_action; /* Body of user defined command. */
99 }
100 cmd_info_t;
101 
102 /* Type of command handler.  Shouldn't return negative numbers unless it's one
103  * of CMDS_ERR_* constants.  Either way the return value will be the return
104  * value of vle_cmds_run() function. */
105 typedef int (*cmd_handler)(const cmd_info_t *cmd_info);
106 
107 /* Description of a command or an abbreviation. */
108 typedef struct cmd_t
109 {
110 	char *name;        /* Name of the command. */
111 	const char *descr; /* Brief description of the command. */
112 	int id;            /* Numeric identifier, positive, USER_CMD_ID or -1. */
113 	CMD_TYPE type;     /* Type of command described by this structure. */
114 	int passed;        /* Number of times this command was recursively called. */
115 
116 	cmd_handler handler; /* Handler for builtin commands. */
117 	char *cmd;           /* Command-line for user-defined commands. */
118 
119 	int min_args, max_args; /* Min and max number of arguments, can be NOT_DEF. */
120 
121 	unsigned int deleted : 1;          /* Whether this command was deleted. */
122 	unsigned int range : 1;            /* Handles ranges. */
123 	unsigned int cust_sep : 1;         /* Custom separator of arguments. */
124 	unsigned int emark : 1;            /* Supports emark flag. */
125 	unsigned int envvars : 1;          /* Expand environment variables. */
126 	unsigned int select : 1;           /* Select files in a range. */
127 	unsigned int bg : 1;               /* Bg (can have " &" at the end). */
128 	unsigned int noescaping : 1;       /* Don't process \-escaping in unquoted
129 	                                      args. */
130 	unsigned int regexp : 1;           /* Process /.../-arguments. */
131 	unsigned int quote : 1;            /* Process '- and "-quoted args. */
132 	unsigned int comment : 1;          /* Trailing comment is allowed. */
133 	unsigned int qmark : 1;            /* No args after qmark. */
134 	unsigned int args_after_qmark : 1; /* Args after qmark are allowed. */
135 	unsigned int macros_for_cmd : 1;   /* Expand macros w/o special escaping. */
136 	unsigned int macros_for_shell : 1; /* Expand macros with shell escaping. */
137 	unsigned int : 0;                  /* Padding. */
138 
139 	struct cmd_t *next; /* Pointer to the next structure or NULL. */
140 }
141 cmd_t;
142 
143 /* Possible flags for cmd_add_t::flags field. */
144 enum
145 {
146 	HAS_RANGE            = 0x0001, /* Handles ranges. */
147 	HAS_CUST_SEP         = 0x0002, /* Custom separator of arguments. */
148 	HAS_EMARK            = 0x0004, /* Supports emark flag. */
149 	HAS_ENVVARS          = 0x0008, /* Expand environment variables. */
150 	HAS_SELECTION_SCOPE  = 0x0010, /* Select files in a range. */
151 	HAS_BG_FLAG          = 0x0020, /* Background (can have " &" at the end). */
152 	HAS_COMMENT          = 0x0040, /* Trailing comment is allowed. */
153 
154 	/* HAS_RAW_ARGS flag can't be combined with either of the other two, but those
155 	 * two can be specified at the same time. */
156 	HAS_RAW_ARGS         = 0x0080, /* No special processing of arguments. */
157 	HAS_REGEXP_ARGS      = 0x0100, /* Process /.../-arguments. */
158 	HAS_QUOTED_ARGS      = 0x0200, /* Process '- and "-quoted args. */
159 
160 	/* Must be at most one of these. */
161 	HAS_QMARK_NO_ARGS    = 0x0400, /* No args after qmark. */
162 	HAS_QMARK_WITH_ARGS  = 0x0800, /* Args after qmark are allowed. */
163 
164 	/* Must be at most one of these. */
165 	HAS_MACROS_FOR_CMD   = 0x1000, /* Expand macros without special escaping. */
166 	HAS_MACROS_FOR_SHELL = 0x2000, /* Expand macros with shell escaping. */
167 };
168 
169 /* New commands specification for vle_cmds_add(). */
170 typedef struct
171 {
172 	const char *name;       /* Full command name. */
173 	const char *abbr;       /* Command prefix (can be NULL). */
174 	const char *descr;      /* Brief description (stored as a pointer). */
175 	int id;                 /* Command id.  Doesn't need to be unique.  Negative
176 	                           value means absence of arg completion.  Use, for
177 	                           example, -1 for all commands without completion. */
178 	cmd_handler handler;    /* Function invoked to run the command. */
179 	int min_args, max_args; /* Minimum and maximum bounds on number of args. */
180 	int flags;              /* Set of HAS_* flags. */
181 }
182 cmd_add_t;
183 
184 /* Configuration structure that's passed in from the outside. */
185 typedef struct
186 {
187 	void *inner; /* Should be NULL on first call of vle_cmds_init().  This is a
188 	                pointer to internal data. */
189 
190 	int begin;   /* The lowest valid number of the range. */
191 	int current; /* Current position between [begin; end]. */
192 	int end;     /* The highest valid number of the range. */
193 
194 	/* Argument completion function.  arg is user supplied value, which is passed
195 	 * through.  The functions must not modify any strings passed to it. */
196 	int (*complete_args)(int id, const cmd_info_t *cmd_info, int arg_pos,
197 			void *arg);
198 
199 	/* Asks user whether bounds of an inverted range should be swapped.  Should
200 	 * return non-zero if so and zero otherwise. */
201 	int (*swap_range)(void);
202 	/* Resolves name of the mark to a position.  Should return corresponding
203 	 * position or value < 0 on error. */
204 	int (*resolve_mark)(char mark);
205 	/* Expands macros in the passed string.  Should return newly allocated
206 	 * memory. */
207 	char * (*expand_macros)(const char str[], int for_shell, int *usr1,
208 			int *usr2);
209 	/* Expands environment variables in the passed string.  Should return newly
210 	 * allocated memory. */
211 	char * (*expand_envvars)(const char str[]);
212 	/* Called after successful processing of a command. */
213 	void (*post)(int id);
214 	/* Called for commands with HAS_SELECTION_SCOPE flag. */
215 	void (*select_range)(int id, const cmd_info_t *cmd_info);
216 	/* Called to determine whether a command at the front should be skipped for
217 	 * the purposes of completion.  Should return < 0 to do nothing, x to skip
218 	 * command name and x chars. */
219 	int (*skip_at_beginning)(int id, const char args[]);
220 }
221 cmds_conf_t;
222 
223 /* Initializes previously uninitialized instance of the unit and sets it as the
224  * current one.  The udf argument specifies whether user-defined commands are
225  * allowed.  The structure pointed to by cmds_conf_t should be filled before
226  * calling this function. */
227 void vle_cmds_init(int udf, cmds_conf_t *cmds_conf);
228 
229 /* Resets state of the unit. */
230 void vle_cmds_reset(void);
231 
232 /* Executes a command.  Returns one of CMDS_ERR_* codes or code returned by the
233  * command handler. */
234 int vle_cmds_run(const char cmd[]);
235 
236 /* Parses command to fetch command and retrieve id associated with it.  Returns
237  * the id, -1 on error and USER_CMD_ID for all user defined commands. */
238 int vle_cmds_identify(const char cmd[]);
239 
240 /* Parses cmd to find beginning of arguments.  Returns pointer within the cmd or
241  * NULL if command is unknown or command-line is invalid. */
242 const char * vle_cmds_args(const char cmd[]);
243 
244 /* Breaks down passed command into its constituent parts.  Returns pointer to
245  * command's description or NULL on error. */
246 const cmd_t * vle_cmds_parse(const char cmd[], cmd_info_t *info);
247 
248 /* Performs completion of the command, either just command name or arguments of
249  * some command.  Returns offset in cmd, where completion elements should be
250  * pasted. */
251 int vle_cmds_complete(const char cmd[], void *arg);
252 
253 /* Registers all commands in the array pointed to by cmds of length at least
254  * count. */
255 void vle_cmds_add(const cmd_add_t cmds[], int count);
256 
257 /* Finds the first character of the last argument in cmd.  Returns pointer to
258  * it. */
259 char * vle_cmds_last_arg(const char cmd[], int quotes, size_t *len);
260 
261 /* Lists user-defined commands as name-value pairs each in separate item of the
262  * array.  Last pair element is followed by a NULL. */
263 char ** vle_cmds_list_udcs(void);
264 
265 /* Prints a table that includes commands that start with the given prefix into
266  * a multiline string (all lines except for the last one has new line
267  * character).  Returns the string or NULL if there are no command with that
268  * prefix. */
269 char * vle_cmds_print_udcs(const char beginning[]);
270 
271 /* Skips at most one argument of the string.  Returns pointer to the next
272  * character after that argument, if any, otherwise pointer to
273  * null-character. */
274 char * vle_cmds_past_arg(const char args[]);
275 
276 /* Skips argument separators in the string.  Returns pointer to the first
277  * character of the first argument, if any, otherwise pointer to
278  * null-character. */
279 char * vle_cmds_at_arg(const char args[]);
280 
281 /* Advances to the next argument in the string.  Returns pointer to the next
282  * argument, if any, otherwise pointer to null-character. */
283 char * vle_cmds_next_arg(const char args[]);
284 
285 TSTATIC_DEFS(
286 	int add_builtin_cmd(const char name[], int abbr, const cmd_add_t *conf);
287 	char ** dispatch_line(const char args[], int *count, char sep, int regexp,
288 			int quotes, int noescaping, int comments, int *last_arg,
289 			int (**positions)[2]);
290 )
291 
292 #endif /* VIFM__ENGINE__CMDS_H__ */
293 
294 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
295 /* vim: set cinoptions+=t0 filetype=c : */
296