diff --git a/Makefile b/Makefile index 7354809f..1a8d1675 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,8 @@ OBJS = log.o windows.o title_bar.o status_bar.o input_win.o jabber.o \ profanity.o util.o command.o history.o contact_list.o prof_history.o \ contact.o preferences.o prof_autocomplete.o main.o TESTOBJS = test_contact_list.o contact_list.o contact.o \ - test_util.o test_prof_history.o prof_history.o util.o + test_util.o test_prof_history.o prof_history.o util.o \ + prof_autocomplete.o profanity: $(OBJS) $(CC) -o profanity $(OBJS) $(LIBS) @@ -20,11 +21,12 @@ title_bar.o: windows.h status_bar.o: windows.h util.h input_win.o: windows.h preferences.h jabber.o: jabber.h log.h windows.h contact_list.h -profanity.o: log.h windows.h jabber.h command.h preferences.h +profanity.o: log.h windows.h jabber.h command.h preferences.h \ + contact_list.h util.o: util.h command.o: command.h util.h history.h contact_list.h history.o: history.h prof_history.h -contact_list.o: contact_list.h contact.h +contact_list.o: contact_list.h contact.h prof_autocomplete.h prof_history.o: prof_history.h contact.o: contact.h preferences.o: preferences.h diff --git a/contact_list.c b/contact_list.c index eae48963..73d5cc8d 100644 --- a/contact_list.c +++ b/contact_list.c @@ -28,177 +28,53 @@ #include "contact.h" #include "contact_list.h" +#include "prof_autocomplete.h" -// internal contact list -static GSList * _contact_list = NULL; +static PAutocomplete ac; -// state of current tab completion, currrent node -static GSList * _last_found = NULL; -// and current search pattern -static char * _search_str = NULL; +static PContact _copy(PContact contact); -static char * _search_contact_list_from(GSList * curr); +void contact_list_init(void) +{ + ac = p_autocomplete_new(); +} void contact_list_clear(void) { - g_slist_free_full(_contact_list, (GDestroyNotify)p_contact_free); - _contact_list = NULL; - - reset_search_attempts(); + p_autocomplete_clear(ac, (GDestroyNotify)p_contact_free); } void reset_search_attempts(void) { - _last_found = NULL; - if (_search_str != NULL) { - free(_search_str); - _search_str = NULL; - } + p_autocomplete_reset(ac); } void contact_list_remove(const char * const name) { - // reset last found if it points at the node to be removed - if (_last_found != NULL) - if (strcmp(p_contact_name(_last_found->data), name) == 0) - _last_found = NULL; - - if (!_contact_list) { - return; - } else { - GSList *curr = _contact_list; - - while(curr) { - PContact contact = curr->data; - if (strcmp(p_contact_name(contact), name) == 0) { - _contact_list = g_slist_remove(_contact_list, contact); - p_contact_free(contact); - - return; - } - - curr = g_slist_next(curr); - } - - return; - } + p_autocomplete_remove(ac, name, (PStrFunc)p_contact_name, (GDestroyNotify)p_contact_free); } void contact_list_add(const char * const name, const char * const show, const char * const status) { - - // empty list, create new - if (!_contact_list) { - _contact_list = g_slist_append(_contact_list, - p_contact_new(name, show, status)); - - return; - } else { - GSList *curr = _contact_list; - - while(curr) { - PContact curr_contact = curr->data; - - // insert - if (strcmp(p_contact_name(curr_contact), name) > 0) { - _contact_list = g_slist_insert_before(_contact_list, - curr, p_contact_new(name, show, status)); - return; - // update - } else if (strcmp(p_contact_name(curr_contact), name) == 0) { - p_contact_free(curr->data); - curr->data = p_contact_new(name, show, status); - return; - } - - curr = g_slist_next(curr); - } - - // hit end, append - _contact_list = g_slist_append(_contact_list, - p_contact_new(name, show, status)); - - return; - } + p_autocomplete_add(ac, p_contact_new(name, show, status), (PStrFunc)p_contact_name, + (GDestroyNotify)p_contact_free); } GSList * get_contact_list(void) { - GSList *copy = NULL; - GSList *curr = _contact_list; - - while(curr) { - PContact curr_contact = curr->data; - - copy = g_slist_append(copy, - p_contact_new(p_contact_name(curr_contact), - p_contact_show(curr_contact), - p_contact_status(curr_contact))); - - curr = g_slist_next(curr); - } - - return copy; + return p_autocomplete_get_list(ac, (PCopyFunc)_copy); } char * find_contact(char *search_str) { - char *found = NULL; - - // no contacts to search - if (!_contact_list) - return NULL; - - // first search attempt - if (_last_found == NULL) { - _search_str = (char *) malloc((strlen(search_str) + 1) * sizeof(char)); - strcpy(_search_str, search_str); - - found = _search_contact_list_from(_contact_list); - return found; - - // subsequent search attempt - } else { - // search from here+1 to end - found = _search_contact_list_from(g_slist_next(_last_found)); - if (found != NULL) - return found; - - // search from beginning - found = _search_contact_list_from(_contact_list); - if (found != NULL) - return found; - - // we found nothing, reset search - reset_search_attempts(); - return NULL; - } + return p_autocomplete_complete(ac, search_str, (PStrFunc)p_contact_name); } -static char * _search_contact_list_from(GSList * curr) +static PContact _copy(PContact contact) { - while(curr) { - PContact curr_contact = curr->data; - - // match found - if (strncmp(p_contact_name(curr_contact), - _search_str, - strlen(_search_str)) == 0) { - char *result = - (char *) malloc((strlen(p_contact_name(curr_contact)) + 1) - * sizeof(char)); - - // set pointer to last found - _last_found = curr; - - // return the contact, must be free'd by caller - strcpy(result, p_contact_name(curr_contact)); - return result; - } - - curr = g_slist_next(curr); - } - - return NULL; + return p_contact_new(p_contact_name(contact), + p_contact_show(contact), + p_contact_status(contact)); } + diff --git a/contact_list.h b/contact_list.h index 569af8cd..72b8dd79 100644 --- a/contact_list.h +++ b/contact_list.h @@ -27,6 +27,7 @@ #include "contact.h" +void contact_list_init(void); void contact_list_clear(void); void reset_search_attempts(void); void contact_list_add(const char * const name, const char * const show, diff --git a/prof_autocomplete.c b/prof_autocomplete.c index d683d135..4bec0f6c 100644 --- a/prof_autocomplete.c +++ b/prof_autocomplete.c @@ -34,7 +34,7 @@ struct p_autocomplete_t { }; -static gchar * _search_from(PAutocomplete ac, GSList *curr, char * (*str_func)(void *)); +static gchar * _search_from(PAutocomplete ac, GSList *curr, PStrFunc str_func); PAutocomplete p_autocomplete_new(void) { @@ -63,7 +63,7 @@ void p_autocomplete_reset(PAutocomplete ac) } } -void p_autocomplete_add(PAutocomplete ac, void *item, char * (*str_func)(void *), +void p_autocomplete_add(PAutocomplete ac, void *item, PStrFunc str_func, GDestroyNotify free_func) { if (ac->items == NULL) { @@ -97,7 +97,8 @@ void p_autocomplete_add(PAutocomplete ac, void *item, char * (*str_func)(void *) } } -void p_autocomplete_remove(PAutocomplete ac, char *item, char * (*str_func)(void *), GDestroyNotify free_func) +void p_autocomplete_remove(PAutocomplete ac, const char * const item, + PStrFunc str_func, GDestroyNotify free_func) { // reset last found if it points to the item to be removed if (ac->last_found != NULL) @@ -111,8 +112,9 @@ void p_autocomplete_remove(PAutocomplete ac, char *item, char * (*str_func)(void while(curr) { if (g_strcmp0(str_func(curr->data), item) == 0) { + void *current_item = curr->data; ac->items = g_slist_remove(ac->items, curr->data); - free_func(curr->data); + free_func(current_item); return; } @@ -124,7 +126,7 @@ void p_autocomplete_remove(PAutocomplete ac, char *item, char * (*str_func)(void } } -GSList * p_autocomplete_get_list(PAutocomplete ac, void * (*copy_func)(void *)) +GSList * p_autocomplete_get_list(PAutocomplete ac, PCopyFunc copy_func) { GSList *copy = NULL; GSList *curr = ac->items; @@ -138,7 +140,7 @@ GSList * p_autocomplete_get_list(PAutocomplete ac, void * (*copy_func)(void *)) } gchar * p_autocomplete_complete(PAutocomplete ac, gchar *search_str, - char * (*str_func)(void *)) + PStrFunc str_func) { gchar *found = NULL; @@ -173,7 +175,7 @@ gchar * p_autocomplete_complete(PAutocomplete ac, gchar *search_str, } } -static gchar * _search_from(PAutocomplete ac, GSList *curr, char * (*str_func)(void *)) +static gchar * _search_from(PAutocomplete ac, GSList *curr, PStrFunc str_func) { while(curr) { diff --git a/prof_autocomplete.h b/prof_autocomplete.h index 554193fd..fa323502 100644 --- a/prof_autocomplete.h +++ b/prof_autocomplete.h @@ -26,15 +26,18 @@ #include typedef struct p_autocomplete_t *PAutocomplete; +typedef const char * (*PStrFunc)(const void *obj); +typedef void * (*PCopyFunc)(const void *obj); PAutocomplete p_autocomplete_new(void); void p_autocomplete_clear(PAutocomplete ac, GDestroyNotify free_func); void p_autocomplete_reset(PAutocomplete ac); -void p_autocomplete_add(PAutocomplete ac, void *item, char * (*str_func)(void *), +void p_autocomplete_add(PAutocomplete ac, void *item, PStrFunc str_func, GDestroyNotify free_func); -void p_autocomplete_remove(PAutocomplete ac, char *item, char * (*str_func)(void *), GDestroyNotify free_func); -GSList * p_autocomplete_get_list(PAutocomplete ac, void * (*copy_func)(void *)); +void p_autocomplete_remove(PAutocomplete ac, const char * const item, + PStrFunc str_func, GDestroyNotify free_func); +GSList * p_autocomplete_get_list(PAutocomplete ac, PCopyFunc copy_func); gchar * p_autocomplete_complete(PAutocomplete ac, gchar *search_str, - char * (*str_func)(void *)); + PStrFunc str_func); #endif diff --git a/profanity.c b/profanity.c index 5eacb95a..7cbf5d0f 100644 --- a/profanity.c +++ b/profanity.c @@ -30,6 +30,7 @@ #include "jabber.h" #include "command.h" #include "preferences.h" +#include "contact_list.h" static void _profanity_shutdown(void); @@ -69,6 +70,7 @@ void profanity_init(const int disable_tls) gui_init(); jabber_init(disable_tls); command_init(); + contact_list_init(); atexit(_profanity_shutdown); } diff --git a/test_contact_list.c b/test_contact_list.c index c6d0c684..599c8ca1 100644 --- a/test_contact_list.c +++ b/test_contact_list.c @@ -8,6 +8,11 @@ #include "contact.h" #include "contact_list.h" +static void setup(void) +{ + contact_list_init(); +} + static void beforetest(void) { contact_list_clear(); @@ -452,6 +457,7 @@ static void removed_contact_not_in_search(void) void register_contact_list_tests(void) { TEST_MODULE("contact_list tests"); + SETUP(setup); BEFORETEST(beforetest); AFTERTEST(aftertest); TEST(empty_list_when_none_added);