diff --git a/src/api.c b/src/api.c index 07c3523..d9c10ef 100644 --- a/src/api.c +++ b/src/api.c @@ -151,9 +151,9 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX if (argc != 1) { if (argc < 1) { - error_str = "Path must be specified!"; + error_str = "Path must be specified."; } else { - error_str = "Only one argument allowed!"; + error_str = "Only one argument allowed."; } line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str); @@ -163,7 +163,7 @@ void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX fp = fopen(argv[1], "r"); if (fp == NULL) { - error_str = "Path does not exist!"; + error_str = "Path does not exist."; line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str); return; diff --git a/src/api.h b/src/api.h index 87c2382..cfce679 100644 --- a/src/api.h +++ b/src/api.h @@ -38,5 +38,6 @@ int num_registered_handlers(void); int help_max_width(void); void draw_handler_help(WINDOW *win); void invoke_autoruns(WINDOW *w, ToxWindow *self); +void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]); #endif /* API_H */ diff --git a/src/autocomplete.c b/src/autocomplete.c index 5f4e96c..d74ff61 100644 --- a/src/autocomplete.c +++ b/src/autocomplete.c @@ -86,13 +86,15 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char } /* looks for all instances in list that begin with the last entered word in line according to pos, - then fills line with the complete word. e.g. "Hello jo" would complete the line - with "Hello john". If multiple matches, prints out all the matches and semi-completes line. - - list is a pointer to the list of strings being compared, n_items is the number of items - in the list, and size is the size of each item in the list. - - Returns the difference between the old len and new len of line on success, -1 if error */ + * then fills line with the complete word. e.g. "Hello jo" would complete the line + * with "Hello john". If multiple matches, prints out all the matches and semi-completes line. + * + * list is a pointer to the list of strings being compared, n_items is the number of items + * in the list, and size is the size of each item in the list. + * + * Returns the difference between the old len and new len of line on success. + * Returns -1 on error. + */ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size) { ChatContext *ctx = self->chatwin; @@ -104,6 +106,7 @@ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size const char *L = (char *) list; const char *endchrs = " "; char ubuf[MAX_STR_SIZE]; + memset(ubuf, 0, sizeof(ubuf)); /* work with multibyte string copy of buf for simplicity */ if (wcs_to_mbs_buf(ubuf, ctx->line, sizeof(ubuf)) == -1) { @@ -123,7 +126,7 @@ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size snprintf(tmp, sizeof(tmp), "%s", ubuf); tmp[ctx->pos] = '\0'; - const char *s = dir_search ? strchr(tmp, '\"') : strrchr(tmp, ' '); + const char *s = strrchr(tmp, ' '); char *sub = calloc(1, strlen(ubuf) + 1); if (sub == NULL) { @@ -151,7 +154,7 @@ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size if (!sub[0]) { free(sub); - return -1; + return 0; } int s_len = strlen(sub); @@ -188,7 +191,7 @@ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size if (dir_search) { if (n_matches == 1) { - endchrs = char_rfind(match, '.', match_len) ? "\"" : "/"; + endchrs = char_rfind(match, '.', match_len) ? "" : "/"; } else { endchrs = ""; } @@ -231,8 +234,8 @@ int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size return diff; } -/* transforms a tab complete starting with the shorthand "~" into the full home directory.*/ -static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen) +/* Transforms a tab complete starting with the shorthand "~" into the full home directory. */ +static void complete_home_dir(ToxWindow *self, char *path, int pathsize, const char *cmd, int cmdlen) { ChatContext *ctx = self->chatwin; @@ -240,8 +243,8 @@ static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const cha get_home_dir(homedir, sizeof(homedir)); char newline[MAX_STR_SIZE]; - snprintf(newline, sizeof(newline), "%s \"%s%s", cmd, homedir, path + 1); - snprintf(path, pathsize, "%s", &newline[cmdlen]); + snprintf(newline, sizeof(newline), "%s %s%s", cmd, homedir, path + 1); + snprintf(path, pathsize, "%s", &newline[cmdlen-1]); wchar_t wline[MAX_STR_SIZE]; @@ -260,10 +263,13 @@ static void complt_home_dir(ToxWindow *self, char *path, int pathsize, const cha ctx->len = ctx->pos; } -/* attempts to match /command "" line to matching directories. - - if only one match, auto-complete line. - return diff between old len and new len of ctx->line, -1 if no matches or > 1 match */ +/* Attempts to match /command line to matching directories. + * + * If only one match, auto-complete line. + * + * Returns diff between old len and new len of ctx->line. + * Returns -1 if no matches or > 1 match. + */ #define MAX_DIRS 512 int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd) @@ -271,7 +277,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd) char b_path[MAX_STR_SIZE]; char b_name[MAX_STR_SIZE]; char b_cmd[MAX_STR_SIZE]; - const wchar_t *tmpline = &line[wcslen(cmd) + 2]; /* start after "/command \"" */ + const wchar_t *tmpline = &line[wcslen(cmd) + 1]; /* start after "/command " */ if (wcs_to_mbs_buf(b_path, tmpline, sizeof(b_path)) == -1) { return -1; @@ -282,7 +288,7 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd) } if (b_path[0] == '~') { - complt_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2); + complete_home_dir(self, b_path, sizeof(b_path), b_cmd, strlen(b_cmd) + 2); } int si = char_rfind(b_path, '/', strlen(b_path)); diff --git a/src/chat.c b/src/chat.c index b2f875c..ed36de7 100644 --- a/src/chat.c +++ b/src/chat.c @@ -1005,14 +1005,14 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) int diff = -1; /* TODO: make this not suck */ - if (wcsncmp(ctx->line, L"/sendfile \"", wcslen(L"/sendfile \"")) == 0) { + if (wcsncmp(ctx->line, L"/sendfile ", wcslen(L"/sendfile ")) == 0) { diff = dir_match(self, m, ctx->line, L"/sendfile"); - } else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) { + } else if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) { diff = dir_match(self, m, ctx->line, L"/avatar"); } #ifdef PYTHON - else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) { + else if (wcsncmp(ctx->line, L"/run ", wcslen(L"/run ")) == 0) { diff = dir_match(self, m, ctx->line, L"/run"); } diff --git a/src/chat_commands.c b/src/chat_commands.c index efd6107..eb53241 100644 --- a/src/chat_commands.c +++ b/src/chat_commands.c @@ -167,7 +167,7 @@ void cmd_savefile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv } if ((ft->file = fopen(ft->file_path, "a")) == NULL) { - const char *msg = "File transfer failed: Invalid file path."; + const char *msg = "File transfer failed: Invalid download path."; close_file_transfer(self, m, ft, TOX_FILE_CONTROL_CANCEL, msg, notif_error); return; } @@ -225,16 +225,9 @@ void cmd_sendfile(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv return; } - if (argv[1][0] != '\"') { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path must be enclosed in quotes."); - return; - } - - /* remove opening and closing quotes */ char path[MAX_STR_SIZE]; - snprintf(path, sizeof(path), "%s", &argv[1][1]); - int path_len = strlen(path) - 1; - path[path_len] = '\0'; + snprintf(path, sizeof(path), "%s", argv[1]); + int path_len = strlen(path); if (path_len >= MAX_STR_SIZE) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "File path exceeds character limit."); diff --git a/src/execute.c b/src/execute.c index 1d1fe83..1a2d693 100644 --- a/src/execute.c +++ b/src/execute.c @@ -107,23 +107,33 @@ static struct cmd_func group_commands[] = { { NULL, NULL }, }; + +#ifdef PYTHON +#define SPECIAL_COMMANDS 6 +#else +#define SPECIAL_COMMANDS 5 +#endif /* PYTHON */ + /* Special commands are commands that only take one argument even if it contains spaces */ -#define SPECIAL_COMMANDS 3 static const char special_commands[SPECIAL_COMMANDS][MAX_CMDNAME_SIZE] = { + "/avatar", "/nick", "/note", +#ifdef PYTHON + "/run", +#endif /* PYTHON */ "/title", + "/sendfile", }; /* Returns true if input command is in the special_commands array. */ static bool is_special_command(const char *input) { - int start = char_find(0, input, ' '); - + int s = char_find(0, input, ' '); int i; for (i = 0; i < SPECIAL_COMMANDS; ++i) { - if (strncmp(input, special_commands[i], start) == 0) { + if (strncmp(input, special_commands[i], s) == 0) { return true; } } @@ -134,19 +144,20 @@ static bool is_special_command(const char *input) /* Parses commands in the special_commands array. Unlike parse_command, this function * does not split the input string at spaces. * - * Returns number of arguments on success, returns -1 on failure + * Returns the number of arguments. */ static int parse_special_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE]) { int len = strlen(input); int s = char_find(0, input, ' '); - if (s + 1 >= len) { - return -1; + memcpy(args[0], input, s); + args[0][s++] = '\0'; // increment to remove space after "/command " + + if (s >= len) { + return 1; // No additional args } - memcpy(args[0], input, s); - args[0][s++] = '\0'; /* increment to remove space after /command */ memcpy(args[1], input + s, len - s); args[1][len - s] = '\0'; @@ -154,7 +165,9 @@ static int parse_special_command(WINDOW *w, ToxWindow *self, const char *input, } /* Parses input command and puts args into arg array. - Returns number of arguments on success, -1 on failure. */ + * + * Returns the number of arguments. + */ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*args)[MAX_STR_SIZE]) { if (is_special_command(input)) { @@ -168,43 +181,32 @@ static int parse_command(WINDOW *w, ToxWindow *self, const char *input, char (*a } int num_args = 0; - int i = 0; /* index of last char in an argument */ + int i = 0; // index of last char in an argument /* characters wrapped in double quotes count as one arg */ while (num_args < MAX_NUM_ARGS) { - int qt_ofst = 0; /* set to 1 to offset index for quote char at end of arg */ + i = char_find(0, cmd, ' '); + memcpy(args[num_args], cmd, i); + args[num_args++][i] = '\0'; - if (*cmd == '\"') { - qt_ofst = 1; - i = char_find(1, cmd, '\"'); - - if (cmd[i] == '\0') { - const char *errmsg = "Invalid argument. Did you forget a closing \"?"; - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, errmsg); - free(cmd); - return -1; - } - } else { - i = char_find(0, cmd, ' '); - } - - memcpy(args[num_args], cmd, i + qt_ofst); - args[num_args++][i + qt_ofst] = '\0'; - - if (cmd[i] == '\0') { /* no more args */ + if (cmd[i] == '\0') { // no more args break; } char tmp[MAX_STR_SIZE]; snprintf(tmp, sizeof(tmp), "%s", &cmd[i + 1]); - strcpy(cmd, tmp); /* tmp will always fit inside cmd */ + strcpy(cmd, tmp); // tmp will always fit inside cmd } free(cmd); return num_args; } -/* Matches command to respective function. Returns 0 on match, 1 on no match */ +/* Matches command to respective function. + * + * Returns 0 on match. + * Returns 1 on no match + */ static int do_command(WINDOW *w, ToxWindow *self, Tox *m, int num_args, struct cmd_func *commands, char (*args)[MAX_STR_SIZE]) { @@ -229,14 +231,15 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode) char args[MAX_NUM_ARGS][MAX_STR_SIZE]; int num_args = parse_command(w, self, input, args); - if (num_args == -1) { + if (num_args <= 0) { return; } /* Try to match input command to command functions. If non-global command mode is specified, - try specified mode's commands first, then upon failure try global commands. - - Note: Global commands must come last in case of duplicate command names */ + * try specified mode's commands first, then upon failure try global commands. + * + * Note: Global commands must come last in case of duplicate command names + */ switch (mode) { case CHAT_COMMAND_MODE: if (do_command(w, self, m, num_args, chat_commands, args) == 0) { diff --git a/src/global_commands.c b/src/global_commands.c index 68c4cf6..fdd67b8 100644 --- a/src/global_commands.c +++ b/src/global_commands.c @@ -201,21 +201,15 @@ void cmd_add(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX void cmd_avatar(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE]) { - if (argc < 2 || strlen(argv[1]) < 3) { + if (argc != 1 || strlen(argv[1]) < 3) { avatar_unset(m); - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar is not set."); + line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Avatar has been unset."); return; } - if (argv[1][0] != '\"') { - line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Path must be enclosed in quotes."); - return; - } - - /* remove opening and closing quotes */ char path[MAX_STR_SIZE]; - snprintf(path, sizeof(path), "%s", &argv[1][1]); - int len = strlen(path) - 1; + snprintf(path, sizeof(path), "%s", argv[1]); + int len = strlen(path); if (len <= 0) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid path."); @@ -502,16 +496,8 @@ void cmd_nick(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA } char nick[MAX_STR_SIZE]; - size_t len = 0; - - if (argv[1][0] == '\"') { /* remove opening and closing quotes */ - snprintf(nick, sizeof(nick), "%s", &argv[1][1]); - len = strlen(nick) - 1; - nick[len] = '\0'; - } else { - snprintf(nick, sizeof(nick), "%s", argv[1]); - len = strlen(nick); - } + snprintf(nick, sizeof(nick), "%s", argv[1]); + size_t len = strlen(nick); if (!valid_nick(nick)) { line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid name."); diff --git a/src/groupchat.c b/src/groupchat.c index 6ee267e..3427d78 100644 --- a/src/groupchat.c +++ b/src/groupchat.c @@ -507,12 +507,12 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) { diff = complete_line(self, groupchats[self->num].name_list, groupchats[self->num].num_peers, TOX_MAX_NAME_LENGTH); - } else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) { + } else if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) { diff = dir_match(self, m, ctx->line, L"/avatar"); } #ifdef PYTHON - else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) { + else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run ")) == 0) { diff = dir_match(self, m, ctx->line, L"/run"); } diff --git a/src/misc_tools.c b/src/misc_tools.c index 8990f1f..8da3b2e 100644 --- a/src/misc_tools.c +++ b/src/misc_tools.c @@ -481,6 +481,25 @@ bool file_exists(const char *path) return stat(path, &s) == 0; } +/* Returns 0 if path points to a directory. + * Returns 1 if path points to a regular file. + * Returns -1 on any other result. + */ +int file_type(const char *path) +{ + struct stat s; + stat(path, &s); + + switch (s.st_mode & S_IFMT) { + case S_IFDIR: + return 0; + case S_IFREG: + return 1; + default: + return -1; + } +} + /* returns file size. If file doesn't exist returns 0. */ off_t file_size(const char *path) { diff --git a/src/misc_tools.h b/src/misc_tools.h index 8f786a4..c149488 100644 --- a/src/misc_tools.h +++ b/src/misc_tools.h @@ -146,6 +146,12 @@ void bytes_convert_str(char *buf, int size, uint64_t bytes); /* checks if a file exists. Returns true or false */ bool file_exists(const char *path); +/* Returns 0 if path points to a directory. + * Returns 1 if path points to a regular file. + * Returns -1 on any other result. + */ +int file_type(const char *path); + /* returns file size. If file doesn't exist returns 0. */ off_t file_size(const char *path); diff --git a/src/prompt.c b/src/prompt.c index 0c147b5..06f7e6f 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -247,12 +247,12 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr) if (ctx->len > 1 && ctx->line[0] == '/') { int diff = -1; - if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) { + if (wcsncmp(ctx->line, L"/avatar ", wcslen(L"/avatar ")) == 0) { diff = dir_match(self, m, ctx->line, L"/avatar"); } #ifdef PYTHON - else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) { + else if (wcsncmp(ctx->line, L"/run ", wcslen(L"/run ")) == 0) { diff = dir_match(self, m, ctx->line, L"/run"); } diff --git a/src/toxic.c b/src/toxic.c index 74cb4b4..523f924 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -1355,7 +1355,7 @@ int main(int argc, char **argv) /* set user avatar from config file. if no path is supplied tox_unset_avatar is called */ char avatarstr[PATH_MAX + 11]; - snprintf(avatarstr, sizeof(avatarstr), "/avatar \"%s\"", user_settings->avatar_path); + snprintf(avatarstr, sizeof(avatarstr), "/avatar %s", user_settings->avatar_path); execute(prompt->chatwin->history, prompt, m, avatarstr, GLOBAL_COMMAND_MODE); time_t last_save = get_unix_time();