Skip to content

Commit 533ef78

Browse files
committed
refactor: Eliminate Friends global variable (step 3).
Complete the transition to per-instance FriendsList by heap-allocating it within the Toxic struct and removing the static instance in friendlist.c. Includes a new portable toxic_qsort_r wrapper to eliminate the need for static state during friend list sorting.
1 parent 2229d4e commit 533ef78

File tree

5 files changed

+51
-11
lines changed

5 files changed

+51
-11
lines changed

src/friendlist.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@
3434

3535
static uint8_t blocklist_view = 0; /* 0 if we're in friendlist view, 1 if we're in blocklist view */
3636

37-
static FriendsList Friends;
38-
3937
void init_friendlist(Toxic *toxic)
4038
{
41-
toxic->friends = &Friends;
39+
toxic->friends = calloc(1, sizeof(FriendsList));
40+
41+
if (toxic->friends == NULL) {
42+
exit_toxic_err(FATALERR_MEMORY, "failed in init_friendlist");
43+
}
4244
}
4345

4446
static struct Blocked {
@@ -350,15 +352,15 @@ int load_blocklist(char *path)
350352
}
351353

352354
#define S_WEIGHT 100000
353-
static FriendsList *sorting_friends;
354-
static int index_name_cmp(const void *n1, const void *n2)
355+
static int index_name_cmp(const void *n1, const void *n2, void *arg)
355356
{
356-
int res = qsort_strcasecmp_hlpr(sorting_friends->list[*(const uint32_t *) n1].name,
357-
sorting_friends->list[*(const uint32_t *) n2].name);
357+
FriendsList *friends = arg;
358+
int res = qsort_strcasecmp_hlpr(friends->list[*(const uint32_t *) n1].name,
359+
friends->list[*(const uint32_t *) n2].name);
358360

359361
/* Use weight to make qsort always put online friends before offline */
360-
res = sorting_friends->list[*(const uint32_t *) n1].connection_status ? (res - S_WEIGHT) : (res + S_WEIGHT);
361-
res = sorting_friends->list[*(const uint32_t *) n2].connection_status ? (res + S_WEIGHT) : (res - S_WEIGHT);
362+
res = friends->list[*(const uint32_t *) n1].connection_status ? (res - S_WEIGHT) : (res + S_WEIGHT);
363+
res = friends->list[*(const uint32_t *) n2].connection_status ? (res + S_WEIGHT) : (res - S_WEIGHT);
362364

363365
return res;
364366
}
@@ -376,8 +378,7 @@ void sort_friendlist_index(FriendsList *friends)
376378
}
377379

378380
if (friends->num_friends > 0) {
379-
sorting_friends = friends;
380-
qsort(friends->index, friends->num_friends, sizeof(uint32_t), index_name_cmp);
381+
toxic_qsort_r(friends->index, friends->num_friends, sizeof(uint32_t), index_name_cmp, friends);
381382
}
382383
}
383384

src/main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1214,6 +1214,7 @@ static Toxic *toxic_init(void)
12141214
free(toxic->c_config);
12151215
free(toxic->run_opts);
12161216
free(toxic->windows);
1217+
free(toxic->friends);
12171218
free(toxic);
12181219
return NULL;
12191220
}

src/misc_tools.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,32 @@ int qsort_ptr_char_array_helper(const void *str1, const void *str2)
295295
return strcasecmp(*(const char *const *)str1, *(const char *const *)str2);
296296
}
297297

298+
struct qsort_r_data {
299+
void *arg;
300+
int (*compar)(const void *, const void *, void *);
301+
};
302+
303+
#ifdef __APPLE__
304+
static int qsort_r_compar_apple(void *thunk, const void *a, const void *b)
305+
{
306+
struct qsort_r_data *data = thunk;
307+
return data->compar(a, b, data->arg);
308+
}
309+
310+
#endif
311+
312+
void toxic_qsort_r(void *base, size_t nmemb, size_t size,
313+
int (*compar)(const void *, const void *, void *),
314+
void *arg)
315+
{
316+
#if defined(__APPLE__)
317+
struct qsort_r_data data = { arg, compar };
318+
qsort_r(base, nmemb, size, &data, qsort_r_compar_apple);
319+
#else
320+
qsort_r(base, nmemb, size, compar, arg);
321+
#endif
322+
}
323+
298324
/* List of characters we don't allow in nicks. */
299325
static const char invalid_nick_chars[] = {':', '/', '\0', '\a', '\b', '\f', '\n', '\r', '\t', '\v'};
300326

src/misc_tools.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,17 @@ int qsort_strcasecmp_hlpr(const void *str1, const void *str2);
151151
/* case-insensitive string compare function for use with qsort */
152152
int qsort_ptr_char_array_helper(const void *str1, const void *str2);
153153

154+
/* Portable wrapper for qsort_r.
155+
*
156+
* Signature matches the GNU version:
157+
* void qsort_r(void *base, size_t nmemb, size_t size,
158+
* int (*compar)(const void *, const void *, void *),
159+
* void *arg);
160+
*/
161+
void toxic_qsort_r(void *base, size_t nmemb, size_t size,
162+
int (*compar)(const void *, const void *, void *),
163+
void *arg);
164+
154165
/* Returns true if nick is valid.
155166
*
156167
* A valid toxic nick:

src/toxic.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ static void kill_toxic(Toxic *toxic)
8888
free(toxic->c_config);
8989
free(toxic->run_opts);
9090
free(toxic->windows);
91+
free(toxic->friends);
9192
paths_free(toxic->paths);
9293
free(toxic);
9394
}

0 commit comments

Comments
 (0)