1
0
mirror of https://github.com/Tha14/toxic.git synced 2024-11-22 17:13:02 +01:00

modularize string arrays for line completion

Instead of using various different forms of string arrays and having to handle them
differently for string completion, we now always use char pointer arrays. This allows
us to remove some large stack allocations, remove a bunch of confusing defines that
keep track of global array sizes, and generally unclutters the code so it's easier
to read.
This commit is contained in:
jfreegman 2020-10-29 20:28:09 -04:00
parent 2b43340c90
commit 7560bc9547
No known key found for this signature in database
GPG Key ID: 3627F3144076AE63
13 changed files with 203 additions and 237 deletions

View File

@ -437,6 +437,7 @@ inline__ DeviceError write_out(uint32_t device_idx, const int16_t *data, uint32_
ALuint *bufids = malloc(processed * sizeof(ALuint)); ALuint *bufids = malloc(processed * sizeof(ALuint));
if (bufids == NULL) { if (bufids == NULL) {
pthread_mutex_unlock(device->mutex);
return de_InternalError; return de_InternalError;
} }

View File

@ -51,21 +51,6 @@ static void print_ac_matches(ToxWindow *self, Tox *m, char **list, size_t n_matc
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, ""); line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
} }
static void print_dir_matches(ToxWindow *self, Tox *m, const void *list, size_t n_items, size_t size)
{
if (m) {
execute(self->chatwin->history, self, m, "/clear", GLOBAL_COMMAND_MODE);
}
const char *L = (char *)list;
for (size_t i = 0; i < n_items; ++i) {
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "%s", &L[i * size]);
}
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "");
}
/* puts match in match buffer. if more than one match, add first n chars that are identical. /* puts match in match buffer. if more than one match, add first n chars that are identical.
* e.g. if matches contains: [foo, foobar, foe] we put fo in match. * e.g. if matches contains: [foo, foobar, foe] we put fo in match.
* *
@ -102,8 +87,7 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char
* then fills line with the complete word. e.g. "Hello jo" would complete the line * 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. * 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 * `list` is a pointer to `n_items` strings. Each string in the list must be <= MAX_STR_SIZE.
* in the list, and size is the size of each item in the list.
* *
* dir_search should be true if the line being completed is a file path. * dir_search should be true if the line being completed is a file path.
* *
@ -112,7 +96,7 @@ static size_t get_str_match(ToxWindow *self, char *match, size_t match_sz, char
* *
* Note: This function should not be called directly. Use complete_line() and complete_path() instead. * Note: This function should not be called directly. Use complete_line() and complete_path() instead.
*/ */
static int complete_line_helper(ToxWindow *self, const void *list, const size_t n_items, size_t size, bool dir_search) static int complete_line_helper(ToxWindow *self, const char **list, const size_t n_items, bool dir_search)
{ {
ChatContext *ctx = self->chatwin; ChatContext *ctx = self->chatwin;
@ -120,11 +104,10 @@ static int complete_line_helper(ToxWindow *self, const void *list, const size_t
return -1; return -1;
} }
if (ctx->len >= MAX_STR_SIZE || size > MAX_STR_SIZE) { if (ctx->len >= MAX_STR_SIZE) {
return -1; return -1;
} }
const char *L = (const char *) list;
const char *endchrs = " "; const char *endchrs = " ";
char ubuf[MAX_STR_SIZE] = {0}; char ubuf[MAX_STR_SIZE] = {0};
@ -172,29 +155,24 @@ static int complete_line_helper(ToxWindow *self, const void *list, const size_t
int s_len = strlen(sub); int s_len = strlen(sub);
size_t n_matches = 0; size_t n_matches = 0;
char **matches = (char **)malloc_ptr_array(n_items, MAX_STR_SIZE, sizeof(char *)); char **matches = (char **) malloc_ptr_array(n_items, MAX_STR_SIZE);
if (matches == NULL) { if (matches == NULL) {
free(sub); free(sub);
return -1; return -1;
} }
int i = 0;
/* put all list matches in matches array */ /* put all list matches in matches array */
for (i = 0; i < n_items; ++i) { for (size_t i = 0; i < n_items; ++i) {
char str[MAX_CMDNAME_SIZE + 1]; if (strncasecmp(list[i], sub, s_len) == 0) {
snprintf(str, sizeof(str), "%s", &L[i * size]); snprintf(matches[n_matches++], MAX_STR_SIZE, "%s", list[i]);
if (strncasecmp(str, sub, s_len) == 0) {
strcpy(matches[n_matches++], str);
} }
} }
free(sub); free(sub);
if (!n_matches) { if (!n_matches) {
free_ptr_array((void **) matches, n_items); free_ptr_array((void **) matches);
return -1; return -1;
} }
@ -205,7 +183,7 @@ static int complete_line_helper(ToxWindow *self, const void *list, const size_t
char match[MAX_STR_SIZE]; char match[MAX_STR_SIZE];
size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches, MAX_STR_SIZE); size_t match_len = get_str_match(self, match, sizeof(match), matches, n_matches, MAX_STR_SIZE);
free_ptr_array((void **) matches, n_items); free_ptr_array((void **) matches);
if (match_len == 0) { if (match_len == 0) {
return 0; return 0;
@ -281,14 +259,14 @@ static int complete_line_helper(ToxWindow *self, const void *list, const size_t
return diff; return diff;
} }
int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size) int complete_line(ToxWindow *self, const char **list, size_t n_items)
{ {
return complete_line_helper(self, list, n_items, size, false); return complete_line_helper(self, list, n_items, false);
} }
static int complete_path(ToxWindow *self, const void *list, size_t n_items, size_t size) static int complete_path(ToxWindow *self, const char **list, const size_t n_items)
{ {
return complete_line_helper(self, list, n_items, size, true); return complete_line_helper(self, list, n_items, true);
} }
/* Transforms a tab complete starting with the shorthand "~" into the full home directory. */ /* Transforms a tab complete starting with the shorthand "~" into the full home directory. */
@ -365,14 +343,21 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
return -1; return -1;
} }
char dirnames[MAX_DIRS][NAME_MAX + 1]; char **dirnames = (char **) malloc_ptr_array(MAX_DIRS, NAME_MAX + 1);
if (dirnames == NULL) {
closedir(dp);
return -1;
}
struct dirent *entry; struct dirent *entry;
int dircount = 0; int dircount = 0;
while ((entry = readdir(dp)) && dircount < MAX_DIRS) { while ((entry = readdir(dp)) && dircount < MAX_DIRS) {
if (strncmp(entry->d_name, b_name, b_name_len) == 0 if (strncmp(entry->d_name, b_name, b_name_len) == 0
&& strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) { && strcmp(".", entry->d_name) && strcmp("..", entry->d_name)) {
snprintf(dirnames[dircount], sizeof(dirnames[dircount]), "%s", entry->d_name); snprintf(dirnames[dircount], NAME_MAX + 1, "%s", entry->d_name);
++dircount; ++dircount;
} }
} }
@ -380,13 +365,18 @@ int dir_match(ToxWindow *self, Tox *m, const wchar_t *line, const wchar_t *cmd)
closedir(dp); closedir(dp);
if (dircount == 0) { if (dircount == 0) {
free_ptr_array((void **) dirnames);
return -1; return -1;
} }
if (dircount > 1) { if (dircount > 1) {
qsort(dirnames, dircount, NAME_MAX + 1, qsort_strcasecmp_hlpr); qsort(dirnames, dircount, sizeof(char *), qsort_ptr_char_array_helper);
print_dir_matches(self, m, dirnames, dircount, NAME_MAX + 1); print_ac_matches(self, m, dirnames, dircount);
} }
return complete_path(self, dirnames, dircount, NAME_MAX + 1); int ret = complete_path(self, (const char **) dirnames, dircount);
free_ptr_array((void **) dirnames);
return ret;
} }

View File

@ -28,13 +28,16 @@
* then fills line with the complete word. e.g. "Hello jo" would complete the line * 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. * 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 * `list` is a pointer to `n_items` strings.
* in the list, and size is the size of each item in the list. *
* dir_search should be true if the line being completed is a file path.
* *
* Returns the difference between the old len and new len of line on success. * Returns the difference between the old len and new len of line on success.
* Returns -1 on error. * Returns -1 on error.
*
* Note: This function should not be called directly. Use complete_line() and complete_path() instead.
*/ */
int complete_line(ToxWindow *self, const void *list, size_t n_items, size_t size); int complete_line(ToxWindow *self, const char **list, size_t n_items);
/* Attempts to match /command "<incomplete-dir>" line to matching directories. /* Attempts to match /command "<incomplete-dir>" line to matching directories.
* If there is only one match the line is auto-completed. * If there is only one match the line is auto-completed.

View File

@ -65,67 +65,50 @@ static void init_infobox(ToxWindow *self);
static void kill_infobox(ToxWindow *self); static void kill_infobox(ToxWindow *self);
#endif /* AUDIO */ #endif /* AUDIO */
#ifdef AUDIO
#define AC_NUM_CHAT_COMMANDS_AUDIO 9
#else
#define AC_NUM_CHAT_COMMANDS_AUDIO 0
#endif /* AUDIO */
#ifdef PYTHON
#define AC_NUM_CHAT_COMMANDS_PYTHON 1
#else
#define AC_NUM_CHAT_COMMANDS_PYTHON 0
#endif /* PYTHON */
#ifdef QRCODE
#define AC_NUM_CHAT_COMMANDS_QRCODE 1
#else
#define AC_NUM_CHAT_COMMANDS_QRCODE 0
#endif /* QRCODE */
#define AC_NUM_CHAT_COMMANDS (21 + AC_NUM_CHAT_COMMANDS_AUDIO + AC_NUM_CHAT_COMMANDS_PYTHON + AC_NUM_CHAT_COMMANDS_QRCODE)
/* Array of chat command names used for tab completion. */ /* Array of chat command names used for tab completion. */
static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = { static const char *chat_cmd_list[] = {
{ "/accept" }, "/accept",
{ "/add" }, "/add",
{ "/avatar" }, "/avatar",
{ "/cancel" }, "/cancel",
{ "/clear" }, "/clear",
{ "/close" }, "/close",
{ "/connect" }, "/connect",
{ "/exit" }, "/exit",
{ "/group" }, "/group",
{ "/help" }, "/help",
{ "/invite" }, "/invite",
{ "/join" }, "/join",
{ "/log" }, "/log",
{ "/myid" }, "/myid",
#ifdef QRCODE #ifdef QRCODE
{ "/myqr" }, "/myqr",
#endif /* QRCODE */ #endif /* QRCODE */
{ "/nick" }, "/nick",
{ "/note" }, "/note",
{ "/nospam" }, "/nospam",
{ "/quit" }, "/quit",
{ "/savefile" }, "/savefile",
{ "/sendfile" }, "/sendfile",
{ "/status" }, "/status",
#ifdef AUDIO #ifdef AUDIO
{ "/call" }, "/call",
{ "/answer" }, "/answer",
{ "/reject" }, "/reject",
{ "/hangup" }, "/hangup",
{ "/sdev" }, "/sdev",
{ "/mute" }, "/mute",
{ "/sense" }, "/sense",
{ "/video" }, "/video",
{ "/bitrate" }, "/bitrate",
#endif /* AUDIO */ #endif /* AUDIO */
#ifdef PYTHON #ifdef PYTHON
{ "/run" }, "/run",
#endif /* PYTHON */ #endif /* PYTHON */
}; };
@ -662,7 +645,7 @@ static void chat_onFileRecv(ToxWindow *self, Tox *m, uint32_t friendnum, uint32_
size_t d_len = strlen(d); size_t d_len = strlen(d);
if (path_len + d_len >= file_path_buf_size) { if (path_len + d_len >= file_path_buf_size) {
path_len -= d_len; path_len = file_path_buf_size - d_len - 1;
file_path[path_len] = '\0'; file_path[path_len] = '\0';
} }
@ -1090,14 +1073,14 @@ bool chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
#endif #endif
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) { else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
const char status_cmd_list[3][8] = { const char *status_cmd_list[] = {
{"online"}, "online",
{"away"}, "away",
{"busy"}, "busy",
}; };
diff = complete_line(self, status_cmd_list, 3, 8); diff = complete_line(self, status_cmd_list, sizeof(status_cmd_list) / sizeof(char *));
} else { } else {
diff = complete_line(self, chat_cmd_list, AC_NUM_CHAT_COMMANDS, MAX_CMDNAME_SIZE); diff = complete_line(self, chat_cmd_list, sizeof(chat_cmd_list) / sizeof(char *));
} }
if (diff != -1) { if (diff != -1) {

View File

@ -37,6 +37,7 @@ extern FriendsList Friends;
/* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */ /* number of "#"'s in file transfer progress bar. Keep well below MAX_STR_SIZE */
#define NUM_PROG_MARKS 50 #define NUM_PROG_MARKS 50
#define STR_BUF_SIZE 30
/* creates initial progress line that will be updated during file transfer. /* creates initial progress line that will be updated during file transfer.
Assumes progline has room for at least MAX_STR_SIZE bytes */ Assumes progline has room for at least MAX_STR_SIZE bytes */
@ -59,10 +60,10 @@ void print_progress_bar(ToxWindow *self, double bps, double pct_done, uint32_t l
return; return;
} }
char pct_str[24]; char pct_str[STR_BUF_SIZE] = {0};
snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done); snprintf(pct_str, sizeof(pct_str), "%.1f%%", pct_done);
char bps_str[24]; char bps_str[STR_BUF_SIZE] = {0};
bytes_convert_str(bps_str, sizeof(bps_str), bps); bytes_convert_str(bps_str, sizeof(bps_str), bps);
char prog_line[NUM_PROG_MARKS + 1] = {0}; char prog_line[NUM_PROG_MARKS + 1] = {0};

View File

@ -494,7 +494,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
} else if (!strcmp(argv[1], "txt")) { } else if (!strcmp(argv[1], "txt")) {
#endif /* QRPNG */ #endif /* QRPNG */
size_t qr_path_buf_size = dir_len + nick_len + strlen(QRCODE_FILENAME_EXT) + 1; size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT);
char *qr_path = malloc(qr_path_buf_size); char *qr_path = malloc(qr_path_buf_size);
if (qr_path == NULL) { if (qr_path == NULL) {
@ -518,7 +518,7 @@ void cmd_myqr(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MA
#ifdef QRPNG #ifdef QRPNG
} else if (!strcmp(argv[1], "png")) { } else if (!strcmp(argv[1], "png")) {
size_t qr_path_buf_size = dir_len + nick_len + strlen(QRCODE_FILENAME_EXT_PNG) + 1; size_t qr_path_buf_size = dir_len + nick_len + sizeof(QRCODE_FILENAME_EXT_PNG);
char *qr_path = malloc(qr_path_buf_size); char *qr_path = malloc(qr_path_buf_size);
if (qr_path == NULL) { if (qr_path == NULL) {

View File

@ -70,46 +70,34 @@ static int max_groupchat_index = 0;
extern struct user_settings *user_settings; extern struct user_settings *user_settings;
extern struct Winthread Winthread; extern struct Winthread Winthread;
#ifdef PYTHON
#define AC_NUM_GROUP_COMMANDS_PYTHON 1
#else
#define AC_NUM_GROUP_COMMANDS_PYTHON 0
#endif /* PYTHON */
#ifdef QRCODE
#define AC_NUM_GROUP_COMMANDS_QRCODE 1
#else
#define AC_NUM_GROUP_COMMANDS_QRCODE 0
#endif /* QRCODE */
#define AC_NUM_GROUP_COMMANDS (19 + AC_NUM_GROUP_COMMANDS_PYTHON + AC_NUM_GROUP_COMMANDS_QRCODE)
/* Array of groupchat command names used for tab completion. */ /* Array of groupchat command names used for tab completion. */
static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = { static const char *group_cmd_list[] = {
{ "/accept" }, "/accept",
{ "/add" }, "/add",
{ "/avatar" }, "/avatar",
{ "/clear" }, "/clear",
{ "/close" }, "/close",
{ "/connect" }, "/connect",
{ "/decline" }, "/decline",
{ "/exit" }, "/exit",
{ "/group" }, "/group",
{ "/help" }, "/help",
{ "/log" }, "/log",
{ "/myid" }, "/myid",
#ifdef QRCODE #ifdef QRCODE
{ "/myqr" }, "/myqr",
#endif /* QRCODE */ #endif /* QRCODE */
{ "/nick" }, "/nick",
{ "/note" }, "/note",
{ "/nospam" }, "/nospam",
{ "/quit" }, "/quit",
{ "/requests" }, "/requests",
{ "/status" }, "/status",
{ "/title" }, "/title",
#ifdef PYTHON #ifdef PYTHON
{ "/run" }, "/run",
#endif /* PYTHON */ #endif /* PYTHON */
}; };
@ -166,7 +154,7 @@ int init_groupchat_win(Tox *m, uint32_t groupnum, uint8_t type, const char *titl
void free_groupchat(ToxWindow *self, uint32_t groupnum) void free_groupchat(ToxWindow *self, uint32_t groupnum)
{ {
free(groupchats[groupnum].name_list); free_ptr_array((void **) groupchats[groupnum].name_list);
free(groupchats[groupnum].peer_list); free(groupchats[groupnum].peer_list);
memset(&groupchats[groupnum], 0, sizeof(GroupChat)); memset(&groupchats[groupnum], 0, sizeof(GroupChat));
@ -309,26 +297,26 @@ static void group_update_name_list(uint32_t groupnum)
return; return;
} }
if (chat->name_list) { if (!chat->name_list) {
free(chat->name_list); fprintf(stderr, "WARNING: name_list is NULL\n");
return;
} }
chat->name_list = malloc(sizeof(char *) * chat->num_peers * TOX_MAX_NAME_LENGTH); size_t count = 0;
if (chat->name_list == NULL) { for (uint32_t i = 0; i < chat->max_idx && count < chat->num_peers; ++i) {
exit_toxic_err("failed in group_update_name_list", FATALERR_MEMORY);
}
uint32_t i, count = 0;
for (i = 0; i < chat->max_idx; ++i) {
if (chat->peer_list[i].active) { if (chat->peer_list[i].active) {
memcpy(&chat->name_list[count * TOX_MAX_NAME_LENGTH], chat->peer_list[i].name, chat->peer_list[i].name_length + 1); memcpy(chat->name_list[count], chat->peer_list[i].name, chat->peer_list[i].name_length);
chat->name_list[count][chat->peer_list[i].name_length] = 0;
++count; ++count;
} }
} }
qsort(chat->name_list, count, TOX_MAX_NAME_LENGTH, qsort_strcasecmp_hlpr); if (count != chat->num_peers) {
fprintf(stderr, "WARNING: count != chat->num_peers\n");
}
qsort(chat->name_list, count, sizeof(char *), qsort_ptr_char_array_helper);
} }
/* Reallocates groupnum's peer list. Increase is true if the list needs to grow. /* Reallocates groupnum's peer list. Increase is true if the list needs to grow.
@ -369,9 +357,7 @@ static void update_peer_list(Tox *m, uint32_t groupnum, uint32_t num_peers)
realloc_peer_list(chat, num_peers); realloc_peer_list(chat, num_peers);
uint32_t i; for (uint32_t i = 0; i < num_peers; ++i) {
for (i = 0; i < num_peers; ++i) {
GroupPeer *peer = &chat->peer_list[i]; GroupPeer *peer = &chat->peer_list[i];
Tox_Err_Conference_Peer_Query err; Tox_Err_Conference_Peer_Query err;
@ -412,17 +398,29 @@ static void groupchat_onGroupNameListChange(ToxWindow *self, Tox *m, uint32_t gr
return; return;
} }
if (chat->name_list) {
free_ptr_array((void **) chat->name_list);
chat->name_list = NULL;
chat->num_peers = 0;
}
Tox_Err_Conference_Peer_Query err; Tox_Err_Conference_Peer_Query err;
uint32_t num_peers = tox_conference_peer_count(m, groupnum, &err); uint32_t num_peers = tox_conference_peer_count(m, groupnum, &err);
uint32_t old_num = chat->num_peers;
if (err == TOX_ERR_CONFERENCE_PEER_QUERY_OK) { if (err != TOX_ERR_CONFERENCE_PEER_QUERY_OK) {
chat->num_peers = num_peers; fprintf(stderr, "groupchat_onGroupNameListChange() failed with error: %d\n", err);
} else { return;
num_peers = old_num;
} }
chat->name_list = (char **) malloc_ptr_array(num_peers, TOX_MAX_NAME_LENGTH + 1);
if (chat->name_list == NULL) {
fprintf(stderr, "groupchat_onGroupNameListChange(): Out of memory.\n");
return;
}
chat->num_peers = num_peers;
chat->max_idx = num_peers; chat->max_idx = num_peers;
update_peer_list(m, groupnum, num_peers); update_peer_list(m, groupnum, num_peers);
} }
@ -442,9 +440,7 @@ static void groupchat_onGroupPeerNameChange(ToxWindow *self, Tox *m, uint32_t gr
return; return;
} }
uint32_t i; for (uint32_t i = 0; i < chat->max_idx; ++i) {
for (i = 0; i < chat->max_idx; ++i) {
GroupPeer *peer = &chat->peer_list[i]; GroupPeer *peer = &chat->peer_list[i];
// Test against default tox name to prevent nick change spam on initial join (TODO: this is disgusting) // Test against default tox name to prevent nick change spam on initial join (TODO: this is disgusting)
@ -529,8 +525,7 @@ static bool groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
/* TODO: make this not suck */ /* TODO: make this not suck */
if (ctx->line[0] != L'/' || wcscmp(ctx->line, L"/me") == 0) { 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, diff = complete_line(self, (const char **) 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"); diff = dir_match(self, m, ctx->line, L"/avatar");
} }
@ -542,7 +537,7 @@ static bool groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
#endif #endif
else { else {
diff = complete_line(self, group_cmd_list, AC_NUM_GROUP_COMMANDS, MAX_CMDNAME_SIZE); diff = complete_line(self, group_cmd_list, sizeof(group_cmd_list) / sizeof(char *));
} }
if (diff != -1) { if (diff != -1) {
@ -655,9 +650,8 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
mvwhline(ctx->sidebar, 1, 1, ACS_HLINE, SIDEBAR_WIDTH - 1); mvwhline(ctx->sidebar, 1, 1, ACS_HLINE, SIDEBAR_WIDTH - 1);
int maxlines = y2 - SDBAR_OFST - CHATBOX_HEIGHT; int maxlines = y2 - SDBAR_OFST - CHATBOX_HEIGHT;
uint32_t i;
for (i = 0; i < num_peers && i < maxlines; ++i) { for (uint32_t i = 0; i < num_peers && i < maxlines; ++i) {
wmove(ctx->sidebar, i + 2, 1); wmove(ctx->sidebar, i + 2, 1);
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
@ -669,7 +663,7 @@ static void groupchat_onDraw(ToxWindow *self, Tox *m)
int maxlen = SIDEBAR_WIDTH - 2; int maxlen = SIDEBAR_WIDTH - 2;
pthread_mutex_lock(&Winthread.lock); pthread_mutex_lock(&Winthread.lock);
memcpy(tmpnck, &groupchats[self->num].name_list[peer * TOX_MAX_NAME_LENGTH], maxlen); memcpy(tmpnck, groupchats[self->num].name_list[peer], maxlen);
pthread_mutex_unlock(&Winthread.lock); pthread_mutex_unlock(&Winthread.lock);
tmpnck[maxlen] = '\0'; tmpnck[maxlen] = '\0';

View File

@ -48,7 +48,7 @@ typedef struct {
GroupPeer *peer_list; GroupPeer *peer_list;
uint32_t max_idx; uint32_t max_idx;
char *name_list; char **name_list;
uint32_t num_peers; uint32_t num_peers;
} GroupChat; } GroupChat;

View File

@ -42,9 +42,7 @@ extern struct user_settings *user_settings;
void clear_screen(void) void clear_screen(void)
{ {
if (system("clear") != 0) { printf("\033[2J\033[1;1H");
fprintf(stderr, "Warning: system() failed to clear screen\n");
}
} }
void hst_to_net(uint8_t *num, uint16_t numbytes) void hst_to_net(uint8_t *num, uint16_t numbytes)
@ -241,6 +239,12 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2)
return strcasecmp((const char *) str1, (const char *) str2); return strcasecmp((const char *) str1, (const char *) str2);
} }
/* case-insensitive string compare function for use with qsort */
int qsort_ptr_char_array_helper(const void *str1, const void *str2)
{
return strcasecmp(*(char **)str1, *(char **)str2);
}
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick: /* Returns 1 if nick is valid, 0 if not. A valid toxic nick:
- cannot be empty - cannot be empty
- cannot start with a space - cannot start with a space
@ -620,30 +624,33 @@ bool is_ip6_address(const char *address)
} }
/* /*
* Frees `length` members of pointer array `arr` and frees `arr`. * Frees all members of a pointer array plus `arr`.
*/ */
void free_ptr_array(void **arr, size_t length) void free_ptr_array(void **arr)
{ {
if (arr == NULL) { if (arr == NULL) {
return; return;
} }
for (size_t i = 0; i < length; ++i) { void **tmp = arr;
free(arr[i]);
while (*arr) {
free(*arr);
++arr;
} }
free(arr); free(tmp);
} }
/* /*
* Returns a new array of `length` pointers of size `ptr_size`. Each pointer is allocated `bytes` bytes. * Returns a null terminated array of `length` pointers. Each pointer is allocated `bytes` bytes.
* Returns NULL on failure. * Returns NULL on failure.
* *
* The caller is responsible for freeing the array with `free_ptr_array`. * The caller is responsible for freeing the array with `free_ptr_array`.
*/ */
void **malloc_ptr_array(size_t length, size_t bytes, size_t ptr_size) void **malloc_ptr_array(size_t length, size_t bytes)
{ {
void **arr = malloc(length * ptr_size); void **arr = malloc((length + 1) * sizeof(void *));
if (arr == NULL) { if (arr == NULL) {
return NULL; return NULL;
@ -653,10 +660,12 @@ void **malloc_ptr_array(size_t length, size_t bytes, size_t ptr_size)
arr[i] = malloc(bytes); arr[i] = malloc(bytes);
if (arr[i] == NULL) { if (arr[i] == NULL) {
free_ptr_array(arr, i); free_ptr_array(arr);
return NULL; return NULL;
} }
} }
arr[length] = NULL;
return arr; return arr;
} }

View File

@ -107,6 +107,9 @@ void alert_window(ToxWindow *self, int type, bool is_beep);
/* case-insensitive string compare function for use with qsort */ /* case-insensitive string compare function for use with qsort */
int qsort_strcasecmp_hlpr(const void *str1, const void *str2); int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
/* case-insensitive string compare function for use with qsort */
int qsort_ptr_char_array_helper(const void *str1, const void *str2);
/* Returns 1 if nick is valid, 0 if not. A valid toxic nick: /* Returns 1 if nick is valid, 0 if not. A valid toxic nick:
- cannot be empty - cannot be empty
- cannot start with a space - cannot start with a space
@ -196,16 +199,16 @@ bool is_ip6_address(const char *address);
/* /*
* Frees `length` members of pointer array `arr` and frees `arr`. * Frees all members of a pointer array plus `arr`.
*/ */
void free_ptr_array(void **arr, size_t length); void free_ptr_array(void **arr);
/* /*
* Returns a new array of `length` pointers of size `ptr_size`. Each pointer is allocated `bytes` bytes. * Returns a null terminated array of `length` pointers. Each pointer is allocated `bytes` bytes.
* Returns NULL on failure. * Returns NULL on failure.
* *
* The caller is responsible for freeing the array with `free_ptr_array`. * The caller is responsible for freeing the array with `free_ptr_array`.
*/ */
void **malloc_ptr_array(size_t length, size_t bytes, size_t ptr_size); void **malloc_ptr_array(size_t length, size_t bytes);
#endif /* MISC_TOOLS_H */ #endif /* MISC_TOOLS_H */

View File

@ -49,68 +49,47 @@ extern struct Winthread Winthread;
extern FriendsList Friends; extern FriendsList Friends;
FriendRequests FrndRequests; FriendRequests FrndRequests;
#ifdef AUDIO
#define AC_NUM_GLOB_COMMANDS_AUDIO 2
#else
#define AC_NUM_GLOB_COMMANDS_AUDIO 0
#endif /* AUDIO */
#ifdef VIDEO
#define AC_NUM_GLOB_COMMANDS_VIDEO 2
#else
#define AC_NUM_GLOB_COMMANDS_VIDEO 0
#endif /* VIDEO */
#ifdef PYTHON
#define AC_NUM_GLOB_COMMANDS_PYTHON 1
#else
#define AC_NUM_GLOB_COMMANDS_PYTHON 0
#endif /* PYTHON */
#ifdef QRCODE
#define AC_NUM_GLOB_COMMANDS_QRCODE 1
#else
#define AC_NUM_GLOB_COMMANDS_QRCODE 0
#endif /* QRCODE */
#define AC_NUM_GLOB_COMMANDS (17 + AC_NUM_GLOB_COMMANDS_AUDIO + AC_NUM_GLOB_COMMANDS_VIDEO + AC_NUM_GLOB_COMMANDS_PYTHON + AC_NUM_GLOB_COMMANDS_QRCODE)
/* Array of global command names used for tab completion. */ /* Array of global command names used for tab completion. */
static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = { static const char *glob_cmd_list[] = {
{ "/accept" }, "/accept",
{ "/add" }, "/add",
{ "/avatar" }, "/avatar",
{ "/clear" }, "/clear",
{ "/connect" }, "/connect",
{ "/decline" }, "/decline",
{ "/exit" }, "/exit",
{ "/group" }, "/group",
{ "/help" }, "/help",
{ "/log" }, "/log",
{ "/myid" }, "/myid",
#ifdef QRCODE #ifdef QRCODE
{ "/myqr" }, "/myqr",
#endif /* QRCODE */ #endif /* QRCODE */
{ "/nick" }, "/nick",
{ "/note" }, "/note",
{ "/nospam" }, "/nospam",
{ "/quit" }, "/quit",
{ "/requests" }, "/requests",
{ "/status" }, "/status",
#ifdef AUDIO #ifdef AUDIO
{ "/lsdev" }, "/lsdev",
{ "/sdev" }, "/sdev",
#endif /* AUDIO */ #endif /* AUDIO */
#ifdef VIDEO #ifdef VIDEO
{ "/lsvdev" }, "/lsvdev",
{ "/svdev" }, "/svdev",
#endif /* VIDEO */ #endif /* VIDEO */
#ifdef PYTHON #ifdef PYTHON
{ "/run" }, "/run",
#endif /* PYTHON */ #endif /* PYTHON */
@ -272,14 +251,14 @@ static bool prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
#endif #endif
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) { else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
const char status_cmd_list[3][8] = { const char *status_cmd_list[] = {
{"online"}, "online",
{"away"}, "away",
{"busy"}, "busy",
}; };
diff = complete_line(self, status_cmd_list, 3, 8); diff = complete_line(self, status_cmd_list, sizeof(status_cmd_list) / sizeof(char *));
} else { } else {
diff = complete_line(self, glob_cmd_list, AC_NUM_GLOB_COMMANDS, MAX_CMDNAME_SIZE); diff = complete_line(self, glob_cmd_list, sizeof(glob_cmd_list) / sizeof(char *));
} }
if (diff != -1) { if (diff != -1) {

View File

@ -142,6 +142,7 @@ int ID_to_QRcode_png(const char *tox_id, const char *outfile)
if (row == NULL) { if (row == NULL) {
fclose(fp); fclose(fp);
QRcode_free(qr_obj);
return -1; return -1;
} }

View File

@ -794,6 +794,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
if (plain == NULL) { if (plain == NULL) {
fclose(fp); fclose(fp);
free(data);
exit_toxic_err("failed in load_tox", FATALERR_MEMORY); exit_toxic_err("failed in load_tox", FATALERR_MEMORY);
return NULL; return NULL;
} }
@ -812,6 +813,7 @@ static Tox *load_tox(char *data_path, struct Tox_Options *tox_opts, Tox_Err_New
if (strcasecmp(user_password.pass, "q") == 0) { if (strcasecmp(user_password.pass, "q") == 0) {
fclose(fp); fclose(fp);
free(plain); free(plain);
free(data);
exit(0); exit(0);
} }
@ -1294,7 +1296,7 @@ static int rename_old_profile(const char *user_config_dir)
return -1; return -1;
} }
snprintf(old_data_blocklist, sizeof(old_data_blocklist), "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_BLOCKLIST_NAME); snprintf(old_data_blocklist, old_block_buf_size, "%s%s%s", user_config_dir, CONFIGDIR, OLD_DATA_BLOCKLIST_NAME);
if (!file_exists(old_data_blocklist)) { if (!file_exists(old_data_blocklist)) {
free(old_data_blocklist); free(old_data_blocklist);