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