/** * Sortuje word_list. Złożoność pesymistyczna wynosi O(n^2 w), gdzie w to * długość najdłuższego słowa. Zastosowany jest algorytm sortowania przez * wstawianie. * @param [in,out] list Obiekt word_list do posortowania. Po zakończeniu, * lista ta będzie zawierała słowa uporządkowane rosnąco zgodnie z ustawionym * locale. Zbiór wartości się nie zmieni. */ static void sort(struct word_list * list) { for (size_t i = 0; i < word_list_size(list); i++) { for (size_t j = i + 1; j < word_list_size(list); j++) { if (!are_ordered(list->array[i], list->array[j])) swap((const void **) &list->array[i], (const void **) &list->array[j]); } } }
/** Test funkcji word_list_init(). Sprawdzenie, czy word_list powstaje prawidłowo. */ static void word_list_init_test(void** state) { struct word_list *l = malloc(sizeof(word_list)); word_list_init(l); assert_int_equal(word_list_size(l), 0); word_list_done(l); free(l); }
/** Przetwarza jedno słowo @param[in,out] index Indeks znaku w buforze @param[in,out] char_number Nr znaku w aktualnie przetwarzanej linii @param[in,out] line_number Nr linii przetwarzanej @param[in] buffer Bufor @param[in] dict Słownik @param[in] v_option Czy włączono opcję -v */ void parse_word(int *index, int *char_number, int *line_number, wchar_t *buffer, struct dictionary *dict, bool v_option) { const int first_char = *char_number; vector *word = vector_new(sizeof(wchar_t), BUFFER_START_SIZE); for(; iswalpha(buffer[*index]); (*index)++, (*char_number)++) vector_push_back(word, buffer + *index); vector_push_back(word, L"\0"); (*index)--; (*char_number)--; wchar_t *word_content = vector_content(word); wchar_t *word_small = malloc(vector_size(word) * sizeof(wchar_t)); for(int i = 0; i < vector_size(word); i++) word_small[i] = towlower(word_content[i]); if(!dictionary_find(dict, word_small)) { wprintf(L"#"); if(v_option) { fwprintf(stderr, L"%d,%d %ls:", *line_number, first_char, word_content); struct word_list list; dictionary_hints(dict, word_small, &list); const wchar_t * const *hints = word_list_get(&list); int number_of_hints = word_list_size(&list); for(int i = 0; i < number_of_hints; i++) fwprintf(stderr, L" %ls", hints[i]); if(number_of_hints == 0) fwprintf(stderr, L" "); fwprintf(stderr, L"\n"); } } wprintf(L"%ls", word_content); free(word_small); vector_done(word); }
/// Testuje listę podpowiedzi do różnych słów static void dict_hints_test(void **state) { struct dictionary* d = *state; struct word_list* l = malloc(sizeof(struct word_list)); dictionary_hints(d, L"aab", l); assert_int_equal(word_list_size(l), 3); const wchar_t* const* array = word_list_get(l); assert_int_equal(wcscmp(array[0], L"aa"), 0); assert_int_equal(wcscmp(array[1], L"ab"), 0); assert_int_equal(wcscmp(array[2], L"cab"), 0); word_list_done(l); dictionary_hints(d, L"aa", l); assert_int_equal(word_list_size(l), 2); array = word_list_get(l); assert_int_equal(wcscmp(array[0], L"aa"), 0); assert_int_equal(wcscmp(array[1], L"ab"), 0); word_list_done(l); dictionary_hints(d, L"ab", l); assert_int_equal(word_list_size(l), 4); array = word_list_get(l); assert_int_equal(wcscmp(array[0], L"aa"), 0); assert_int_equal(wcscmp(array[1], L"ab"), 0); assert_int_equal(wcscmp(array[2], L"b"), 0); assert_int_equal(wcscmp(array[3], L"cab"), 0); word_list_done(l); dictionary_hints(d, L"ca", l); assert_int_equal(word_list_size(l), 3); array = word_list_get(l); assert_int_equal(wcscmp(array[0], L"aa"), 0); assert_int_equal(wcscmp(array[1], L"c"), 0); assert_int_equal(wcscmp(array[2], L"cab"), 0); word_list_done(l); dictionary_hints(d, L"a", l); assert_int_equal(word_list_size(l), 4); array = word_list_get(l); assert_int_equal(wcscmp(array[0], L"aa"), 0); assert_int_equal(wcscmp(array[1], L"ab"), 0); assert_int_equal(wcscmp(array[2], L"b"), 0); assert_int_equal(wcscmp(array[3], L"c"), 0); word_list_done(l); free(l); }
/** * Zwraca czy słowo 'word' znajduje się w liście słów * @param[in] list Lista słów * @param[in] word Słowo. * @return True jeśli słowo znajduje się w liście słów, false w p.p. */ static bool word_list_find(const struct word_list *list, const wchar_t* word) { const wchar_t * const * a = word_list_get(list); for (size_t i = 0; i < word_list_size(list); i++) if (!wcscmp(a[i], word)) return true; return false; }
/** Test funckji word_list_add(). Dodanie elementu do pustej listy. */ static void word_list_add_to_empty_test(void** state) { struct word_list *l = malloc(sizeof(word_list)); word_list_init(l); word_list_add(l, test); assert_int_equal(word_list_size(l), 1); assert_true(wcscmp(test, word_list_get(l)[0]) == 0); word_list_done(l); free(l); }
/** Testuje zapisyanie do listy słów. @param state Środowisko testowe. */ static void trie_to_word_list_test(void** state) { trie_setup(state); Trie *trie = *state; struct word_list list; word_list_init(&list); trie_to_word_list(trie, &list); assert_int_equal(word_list_size(&list), 3); for (size_t i = 0; i < word_list_size(&list); i++) { assert_true(trie_has_word(trie, word_list_get(&list)[i])); } word_list_done(&list); trie_teardown(state); }
/** * Funkcja wypisująca informacje o podpowiedziach dla danego słowa na wyjście * błędów: numer wiersza słowa, numer kolumny słowa, słowo i listę * podpowiedzi. * @param [in] pstate Stan parsera, z którego pochodzą dane. * @param [in] word_column_num Numer kolumny słowa do komunikatu. * @param [in] wlist word_list z podpowiedziami do komunikatu. * @param [out] out Strumień wyjściowy dla komunikatu. */ void print_verbose_info(const struct parser_state * pstate, int word_column_num, const struct word_list * wlist, FILE * out) { fwprintf(out, L"%d,%d %ls: ", pstate->line_num, word_column_num, word_buffer); const wchar_t * const * hints_array = word_list_get(wlist); for (size_t i = 0; i < word_list_size(wlist); i++) { if (i > 0) fputwc(L' ', out); fputws(hints_array[i], out); } fputwc(L'\n', out); }
/** Sprawdzenie słowa, na którym aktualnie znajduje się kursor. Ewentualne dodanie do słownika. @param[in] item element menu. @param[in] data wskaźnik na wartość. */ static void WhatCheck (GtkMenuItem *item, gpointer data) { GtkWidget *dialog; GtkTextIter start, end; char *word; gunichar *wword; //load_dictionary_from_menu(&dict); // Znajdujemy pozycję kursora gtk_text_buffer_get_iter_at_mark(editor_buf, &start, gtk_text_buffer_get_insert(editor_buf)); // Jeśli nie wewnątrz słowa, kończymy if (!gtk_text_iter_inside_word(&start)) { dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Kursor musi być w środku słowa"); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return; } // Znajdujemy początek i koniec słowa, a potem samo słowo end = start; gtk_text_iter_backward_word_start(&start); gtk_text_iter_forward_word_end(&end); word = gtk_text_iter_get_text(&start, &end); // Zamieniamy na wide char (no prawie) wword = g_utf8_to_ucs4_fast(word, -1, NULL); if (!make_lowercase(wword)) { dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Podane słowo nie jest słowem słownikowym."); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } else { // Sprawdzamy if (dictionary_find(dict, (wchar_t *)wword)) { dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Wszystko w porządku,\nśpij spokojnie"); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } else { // Czas korekty GtkWidget *vbox, *label, *combo; struct word_list hints; int i; wchar_t **words; dictionary_hints(dict, (wchar_t *)wword, &hints); words = (wchar_t **) word_list_get(&hints); dialog = gtk_dialog_new_with_buttons("Korekta", NULL, 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_ADD, GTK_RESPONSE_APPLY, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL); // W treści dialogu dwa elementy vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); // Tekst label = gtk_label_new("Słowo nie znajduje się w słowniku. Wybierz \njedną z propozycji lub dodaj słowa do słownika."); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 1); // Spuszczane menu combo = gtk_combo_box_text_new(); for (i = 0; i < word_list_size(&hints); i++) { // Combo box lubi mieć Gtk char *uword = g_ucs4_to_utf8((gunichar *)words[i], -1, NULL, NULL, NULL); // Dodajemy kolejny element gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), uword); g_free(uword); } gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0); gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 1); gtk_widget_show(combo); gint click = gtk_dialog_run(GTK_DIALOG(dialog)); if (click == GTK_RESPONSE_ACCEPT) { char *korekta = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo)); // Usuwamy stare gtk_text_buffer_delete(editor_buf, &start, &end); // Wstawiamy nowe gtk_text_buffer_insert(editor_buf, &start, korekta, -1); g_free(korekta); } // Proponujemy dodanie słowa do słownika else if (click == GTK_RESPONSE_APPLY) dictionary_insert(dict, wword); gtk_widget_destroy(dialog); } } g_free(word); g_free(wword); }
static void WhatCheck (GtkMenuItem *item, gpointer data) { GtkWidget *dialog; GtkTextIter start, end; char *word; gunichar *wword; // Znajdujemy pozycję kursora gtk_text_buffer_get_iter_at_mark(editor_buf, &start, gtk_text_buffer_get_insert(editor_buf)); // Jeśli nie wewnątrz słowa, kończymy if (!gtk_text_iter_inside_word(&start)) { dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Kursor musi być w środku słowa"); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return; } // Znajdujemy początek i koniec słowa, a potem samo słowo end = start; gtk_text_iter_backward_word_start(&start); gtk_text_iter_forward_word_end(&end); word = gtk_text_iter_get_text(&start, &end); // Zamieniamy na wide char (no prawie) wword = g_utf8_to_ucs4_fast(word, -1, NULL); if(update_actual_dict() < 0) return; // Sprawdzamy if (dictionary_find(dict, (wchar_t *)wword)) { dialog = gtk_message_dialog_new(NULL, 0, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "Wszystko w porządku,\nśpij spokojnie"); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } else { // Czas korekty GtkWidget *vbox, *label, *combo; struct word_list hints; int i; wchar_t **words; dictionary_hints(dict, (wchar_t *)wword, &hints); words = word_list_get(&hints); dialog = gtk_dialog_new_with_buttons("Korekta", NULL, 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL); // W treści dialogu dwa elementy vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); // Tekst label = gtk_label_new("Coś nie tak, mam kilka propozycji"); gtk_widget_show(label); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 1); // Spuszczane menu combo = gtk_combo_box_text_new(); for (i = 0; i < word_list_size(&hints); i++) { // Combo box lubi mieć Gtk char *uword = g_ucs4_to_utf8((gunichar *)words[i], -1, NULL, NULL, NULL); // Dodajemy kolejny element gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo), uword); g_free(uword); } //gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(combo),"<inne...>"); gtk_combo_box_set_active(GTK_COMBO_BOX(combo), 0); gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 1); gtk_widget_show(combo); char *korekta, *question; GtkWidget *ask_dialog, *ask_vbox, *ask_label; switch (gtk_dialog_run(GTK_DIALOG(dialog))) { case GTK_RESPONSE_ACCEPT: korekta = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(combo)); // Usuwamy stare gtk_text_buffer_delete(editor_buf, &start, &end); // Wstawiamy nowe gtk_text_buffer_insert(editor_buf, &start, korekta, -1); g_free(korekta); break; case GTK_RESPONSE_REJECT: question = "Czy chcesz dodać to słowo do słownika?"; ask_dialog = gtk_dialog_new_with_buttons(question, NULL, 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL); ask_vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); // Tekst ask_label = gtk_label_new("Coś nie tak, mam kilka propozycji"); gtk_widget_show(ask_label); gtk_box_pack_start(GTK_BOX(ask_vbox), ask_label, FALSE, FALSE, 1); // Jeśli chiciał dodać nowe słowo do słownika to dodamy i zapiszemy if (gtk_dialog_run(GTK_DIALOG(ask_dialog)) == GTK_RESPONSE_ACCEPT) { dictionary_insert(dict, (wchar_t *)wword); dictionary_save_lang(dict, dict_location); } gtk_widget_destroy(ask_dialog); break; } gtk_widget_destroy(dialog); } }