diff --git a/include/base.h b/include/base.h index 654245d..2f4c9a5 100644 --- a/include/base.h +++ b/include/base.h @@ -37,6 +37,7 @@ #include #include #include +#include #include #include diff --git a/include/fsm.h b/include/fsm.h index e7ed9c1..1b06ff0 100644 --- a/include/fsm.h +++ b/include/fsm.h @@ -25,6 +25,7 @@ #pragma once #include #include +#include #include /******************************************************************************/ @@ -53,7 +54,7 @@ typedef struct disp_list {int value; struct disp_list *suiv;} disp_list ; /* * * * * - J O U R N A L M E T A R U L E S - * * * * * * Un seul fsm_journal_event() par fonction -* sauf si elle génère plusieurs autres fonctions d'intérêt (à surveiller) +* ? sauf si cette fonction génère plusieurs autres fonctions d'intérêt ? * * S'il y a deux fsm_journal_event() (begin / end) dans une fonction * ils doivent avoir la même étiquette : MESSAGE, SOURCE, TARGET @@ -65,7 +66,7 @@ enum severity {CRITICAL, ERROR, WARNING, INFO, MESSAGE, DEBUG, SPEW}; enum source { SOURCE, TARGET, JOURNAL, FSM, PREFER, - MAIN, APP, WIDGETS, + MAIN, APP, WIDGETS, SIGNAL, MAIN_WINDOW, DIALOG_WINDOW, MODAL_WINDOW, TEXT_WINDOW, AUTO_NOTIFICATION, TOPBAR, TOPBAR_LEFT, TOPBAR_RIGHT, TOPBAR_CENTER, SYNTH_PAGE, STATE_PAGE, RULES_PAGE, MEASURES_PAGE, RESULTS_PAGE, @@ -80,9 +81,7 @@ enum source { SLIDER_A, SLIDER_B, SLIDER_C, }; -enum value { - VALUE -}; +enum value {VALUE}; // to use or not to use ... (plutôt non) #define JOURNAL_LOG_MAX_LENGTH 255 diff --git a/include/util.h b/include/util.h index 95f4b7d..61891b1 100644 --- a/include/util.h +++ b/include/util.h @@ -30,6 +30,7 @@ #include "../include/fsm.h" char *util_read_file (char *filename); +char *concat (const char *str, ...); typedef struct pile {int value; struct pile *prev;} pile; // structure d'un élément @@ -152,4 +153,4 @@ GtkWidget *create_axis_slider(int axis); * * @returns bool, true if success */ -bool util_gl_setup_glarea(int target_mode, GtkWidget *target_widget); \ No newline at end of file +bool util_gl_setup_glarea(int target_mode, GtkWidget *target_widget); diff --git a/src/fsm/dispatch.c b/src/fsm/dispatch.c index 6ae6ff8..f46bf26 100644 --- a/src/fsm/dispatch.c +++ b/src/fsm/dispatch.c @@ -25,6 +25,7 @@ #include #include "../../include/fsm.h" +#include "../../include/util.h" #include "../../include/widget.h" @@ -61,10 +62,10 @@ void fsm_journal_publication_request () {fsm_journal_publish (gg_logs);} void fsm_journal_push (char *message, const char *string_value) { - char to_print [JOURNAL_LOG_MAX_LENGTH] = ""; - strcat (to_print, message); - strcat (to_print, string_value); - fsm_journal_push_front (&gg_logs, message); // to_print); TODO concat strings +// Programmers using the strcat function can easily be recognized as lazy and reckless. +// (quoted from: The GNU C Library (glibc) manual - 5.5 Concatenating Strings) + + fsm_journal_push_front (&gg_logs, concat (message, " ", string_value, NULL)); } // CRITICAL ERROR WARNING INFO MESSAGE DEBUG SPEW 😄️ @@ -74,8 +75,21 @@ void fsm_journal_event (char *message, int severity, int source, const char *val { if ( - severity < SPEW - && source == MAIN + severity <= DEBUG + && source != TREE + /* && ( + source == MAIN + || source == FSM + || source == TOPBAR + || source == DIALOG_WINDOW + || source == MODAL_WINDOW + || source == TEXT_WINDOW + || source == TOPBAR_LEFT + || source == TOPBAR_RIGHT + || source == PREFER + ) + // && strcmp (value, "") + && source != SIGNAL */ ) fsm_journal_push (message, value); // TODO push (message + value) @@ -118,19 +132,11 @@ static int preferences_have_been_modified = FALSE; void fsm_set_preferences_modified (bool value) { - char str1[140] = "fsm/dispatch preferences modified value = "; - char str2[20]; sprintf(str2, " (%d)\n", value); strcat(str1, str2); - fsm_journal_event (str1, INFO, FSM, ""); + char str1[] = "fsm/dispatch preferences modified: value = "; + char str2[] = "TRUE or FALSE (TODO)"; //sprintf(str2, "%d", value); TODO + fsm_journal_event (str1, INFO, FSM, str2); - fsm_journal_event ("fsm/dispatch preferences modified value = ?", - INFO, FSM, ""); preferences_have_been_modified = value; - /* - if (value) fsm_journal_event ( - "fsm/dispatch set preferences modified (TRUE)"); // TODO concat value - else fsm_journal_event ( - "fsm/dispatch set preferences modified (FALSE)"); - */ } bool fsm_get_preferences_state() {return preferences_have_been_modified;} @@ -208,3 +214,4 @@ void fsm_msg (int choice, int value, char *string, int sub_automaton) } } + diff --git a/src/fsm/journal.c b/src/fsm/journal.c index 8e9d035..3b5a783 100644 --- a/src/fsm/journal.c +++ b/src/fsm/journal.c @@ -128,6 +128,7 @@ void fsm_journal_seek (journal jj, long usec, char *message) // https://en.cppreference.com/w/c/io/fprintf // https://nicolasj.developpez.com/articles/libc/string/ // https://thelinuxcode.com/pass-string-function-c-language/ + // https://mefics.org/fr/allocation-dynamique-de-m%C3%A9moire-en-c-fonctions-malloc-calloc/ //------------------------------------------------------------------------------ void fsm_journal_publish (journal jj) diff --git a/src/signal.c b/src/signal.c index 845ded9..3df8f3c 100644 --- a/src/signal.c +++ b/src/signal.c @@ -36,8 +36,8 @@ static void on_auto_notification (char *message) { - fsm_journal_event ("signal auto notification()", - DEBUG, AUTO_NOTIFICATION, message); + // message = "-(any auto notification)-"; // test + fsm_journal_event ("signal (notif.) ", DEBUG, AUTO_NOTIFICATION, message); /* Ignored (2024-06-06) because I don't know how to get "main_window" easily if (window->toast_revealer == NULL) { @@ -103,7 +103,7 @@ void on_bind_user_tree_factory (GtkSignalListItemFactory *factory, row); gtk_widget_set_margin_start (expander, gtk_tree_list_row_get_depth(row) * 20); - fsm_journal_event ("signal bind user tree factory()", + fsm_journal_event ("signal (tree) bind user tree factory()", DEBUG, TREE, text); } @@ -115,7 +115,7 @@ void on_bind_user_tree_factory (GtkSignalListItemFactory *factory, gboolean on_glarea_render (GtkGLArea *area, GdkGLContext *context) { - fsm_journal_event ("signal glarea render()", DEBUG, GLAREA, ""); + fsm_journal_event ("signal (GLArea) glarea render()", DEBUG, GLAREA, "(context TODO)"); // Check if the widget is a glarea if(gtk_gl_area_get_error(area) != NULL) { on_auto_notification("An OpenGL error occured !"); @@ -134,7 +134,7 @@ gboolean on_glarea_render (GtkGLArea *area, /* We need to set up our state when we realize the GtkGLArea widget */ void on_glarea_realize (GtkWidget *widget) { - fsm_journal_event ("signal glarea realize()", DEBUG, GLAREA, ""); + fsm_journal_event ("signal (GLArea) glarea realize()", DEBUG, GLAREA, ""); GError *internal_error = NULL; // Make the GL context current to be able to call the GL API @@ -160,7 +160,7 @@ void on_glarea_realize (GtkWidget *widget) /* We should tear down the state when unrealizing */ void on_glarea_unrealize (GtkWidget *widget) { - fsm_journal_event ("signal glarea unrealize()", DEBUG, GLAREA, ""); + fsm_journal_event ("signal (GLArea) glarea unrealize()", DEBUG, GLAREA, ""); GError *internal_error = NULL; // Make the GL context current to be able to call the GL API @@ -203,11 +203,11 @@ void on_axis_value_change (GtkAdjustment *adjustment, gpointer data) char string_value [10]; sprintf(string_value, " (%d)", axis_value); switch (axis) { - case 0 : fsm_journal_event ("signal axis value changed()", + case 0 : fsm_journal_event ("signal (axis) X value changed()", SPEW, SLIDER_X, string_value); break; - case 1 : fsm_journal_event ("signal axis value changed()", + case 1 : fsm_journal_event ("signal (axis) Y value changed()", SPEW, SLIDER_Y, string_value); break; - case 2 : fsm_journal_event ("signal axis value changed()", + case 2 : fsm_journal_event ("signal (axis) Z value changed()", SPEW, SLIDER_Z, string_value); break; } } @@ -220,21 +220,24 @@ void on_axis_value_change (GtkAdjustment *adjustment, gpointer data) void on_save_current_model_before_editing (GtkWidget *btt_save_current_model, gpointer data) { - fsm_journal_event ("signal save current model()", INFO, BUTTON, ""); + fsm_journal_event ("signal (dialog) save current model()", INFO, BUTTON, ""); + on_auto_notification ("save_current_model_before_editing !"); gtk_widget_set_sensitive (GTK_WIDGET (data), TRUE); } void on_discard_current_model_before_editing (GtkWidget *btt_discard_current_model, gpointer data) { - fsm_journal_event ("signal discard current model()", INFO, BUTTON, ""); + fsm_journal_event ("signal (dialog) discard current model()", INFO, BUTTON, ""); + on_auto_notification ("discard_current_model_before_editing ?"); gtk_window_close (GTK_WINDOW (data)); } void on_write_current_model (GtkWidget *btt_write_current_model, gpointer data) { - fsm_journal_event ("signal write current model()", INFO, BUTTON, ""); + fsm_journal_event ("signal (dialog) write current model()", INFO, BUTTON, ""); + on_auto_notification ("writing current_model_before_editing 😄️"); gtk_window_close (GTK_WINDOW (data)); } @@ -250,7 +253,7 @@ static void switch_state_rules_data(); void on_toggle_exec_edit (GtkWidget *toggled_button, gpointer user_data) { - fsm_journal_event ("signal toggle exec edit()", INFO, BUTTON, ""); + fsm_journal_event ("signal (Xec/Ed) toggle exec edit()", INFO, BUTTON, ""); if (fsm_get_exec_edit ()) { // TODO (or NOT ?) et si je ne suis pas sur la page SYNTH gtk_button_set_icon_name (GTK_BUTTON (toggled_button), @@ -281,8 +284,8 @@ void on_toggle_exec_edit (GtkWidget *toggled_button, gpointer user_data) static void switch_state_rules_data() { int value = fsm_get_state_rules_data(); - char string_value [12]; sprintf(string_value, " (%d)", value); - fsm_journal_event ("signal switch state rules data()", + char string_value [12]; sprintf(string_value, "%d", value); + fsm_journal_event ("signal (switch) value = ", DEBUG, SWITCH_STATE_RULES_DATA, string_value); switch (value) { @@ -327,7 +330,7 @@ static void switch_state_rules_data() default : printf("default in signal.on_toggle_state_rule_data()\n"); - fsm_journal_event ("signal default in : switch state rules data()", + fsm_journal_event ("signal (switch) default in : switch state rules data()", INFO, SWITCH_STATE_RULES_DATA, ""); } } @@ -337,10 +340,10 @@ static void switch_state_rules_data() // Les noms d'icônes sont utilisés pour deux fonctions distinctes... void on_toggle_state_rules_data (GtkWidget *toggled_button, gpointer user_data) { - fsm_journal_event ("signal toggle state rules data()", - INFO, BUTTON, "state_rules_data"); const char *toggled_button_name = gtk_check_button_get_label (GTK_CHECK_BUTTON (toggled_button)); + fsm_journal_event ("signal (toggle) <-->", + INFO, BUTTON, toggled_button_name); int is_active = gtk_check_button_get_active (GTK_CHECK_BUTTON (toggled_button)); if ( ! strcmp (toggled_button_name, "synth")) fsm_set_state_rules_data (SYNTH); @@ -357,7 +360,8 @@ void on_toggle_state_rules_data (GtkWidget *toggled_button, gpointer user_data) void on_clicked_topbar_right_search (GtkWidget *btt_menu, gpointer list_box) { - fsm_journal_event ("signal clicked topbar right search()", + fsm_journal_event ("signal (topbar R) search()", +// fsm_journal_event ("signal clicked topbar right search()", DEBUG, BUTTON, ""); // next line presents the text_window and works only once.\n // It should present a menu.\n"); // TODO @@ -367,9 +371,10 @@ void on_clicked_topbar_right_search (GtkWidget *btt_menu, gpointer list_box) void on_clicked_topbar_right_home (GtkWidget *btt_reset, gpointer data) { - fsm_journal_event ("signal clicked topbar right home()", + fsm_journal_event ("signal (topbar R) home()", +// fsm_journal_event ("signal clicked topbar right home()", DEBUG, BUTTON, ""); - // gtk_window_present (GTK_WINDOW (widget_get_dialog_window())); + gtk_window_present (GTK_WINDOW (widget_get_dialog_window())); // NB works only once. < TODO } @@ -407,7 +412,7 @@ void on_resetting_XYZ_in_state_page () void on_situations_box_do_reset (GtkWidget *btt_reset, GtkScrollbar *reset_scrollbar) { - fsm_journal_event ("signal on_situations_box_do_reset()", + fsm_journal_event ("signal situations box do reset()", DEBUG, BUTTON, ""); GtkAdjustment *adj_situ = gtk_scrollbar_get_adjustment (reset_scrollbar); fsm_reset_all_situations_transparencies_at_value (gtk_adjustment_get_value (adj_situ)); diff --git a/src/util/strings_op.c b/src/util/strings_op.c new file mode 100644 index 0000000..5bb3b26 --- /dev/null +++ b/src/util/strings_op.c @@ -0,0 +1,111 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* Gem-graph client * +* Main functions * +* * +* Copyright © 2021 Libre en Communs * +* Copyright © 2021-2024 Adrien Bourmault * +* Copyright © 2021-2024 Jean Sirmai * +* * +* This file is part of Gem-graph. * +* * +* This program is free software: you can redistribute it and/or modify it * +* under the terms of the GNU Affero General Public License * +* as published by the Free Software Foundation, * +* either version 3 of the License, * +* or (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; * +* without even the implied warranty of MERCHANTABILITY * +* or FITNESS FOR A PARTICULAR PURPOSE. * +* See the GNU Affero General Public License for more details. * +* * +* You should have received a copy of the GNU Affero General Public License * +* along with this program. If not, see . * +* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + +/* Programmers using the strcat function can easily be recognized as lazy and reckless. + * from The GNU C Library (glibc) manual (5.5 Concatenating Strings) + * + * Whenever a programmer feels the need to use strcat she or he should think twice + * and look through the program to see whether the code cannot be rewritten + * to take advantage of already calculated results. + * The related functions strlcat, strncat, wcscat and wcsncat are almost always unnecessary, too. + * Again: it is almost always unnecessary to use functions like strcat. 😄️ */ + + +/* Before calling vprintf or the other functions listed in this section, + * you must call va_start (see Variadic Functions) to initialize a pointer to the variable arguments. + * Then you can call va_arg to fetch the arguments that you want to handle yourself. + * This advances the pointer past those arguments. + * + * Once your va_list pointer is pointing at the argument of your choice, you are ready to call vprintf. + * That argument and all subsequent arguments that were passed to your function + * are used by vprintf along with the template that you specified separately. */ + +/* A.2 Variadic Functions + * ISO C defines a syntax for declaring a function to take a variable number or type of arguments. + * (Such functions are referred to as varargs functions or variadic functions.) + * However, the language itself provides no mechanism for such functions to access + * their non-required arguments; instead, you use the variable arguments macros defined in stdarg.h. + * + * This section describes how to declare variadic functions, how to write them, + * and how to call them properly. */ + + + +#include +#include +#include + +char * // https://sourceware.org/glibc/manual/latest/html_mono/libc.html#Variadic-Prototypes +concat (const char *str, ...) // ellipsis (‘…’) A.2.2.2 Receiving the Argument Values +{ + size_t allocated = 100; + char *result = malloc (allocated); + + if (result != NULL) + { + va_list ap; + size_t resultlen = 0; + char *newp; + + va_start (ap, str); + + for (const char *s = str; s != NULL; s = va_arg (ap, const char *)) + { + size_t len = strlen (s); + + /* Resize the allocated memory if necessary. */ + if (resultlen + len + 1 > allocated) + { + allocated += len; + newp = reallocarray (result, allocated, 2); + allocated *= 2; + if (newp == NULL) + { + free (result); + return NULL; + } + result = newp; + } + + memcpy (result + resultlen, s, len); + resultlen += len; + } + + /* Terminate the result string. */ + result[resultlen++] = '\0'; + + /* Resize memory to the optimal size. */ + newp = realloc (result, resultlen); + if (newp != NULL) + result = newp; + + va_end (ap); + } + + return result; +} + diff --git a/src/util/tests.c b/src/util/tests.c index 85d16b6..ae07aae 100644 --- a/src/util/tests.c +++ b/src/util/tests.c @@ -31,26 +31,14 @@ #include "../../include/util.h" #include "../../include/base.h" -static const char *util_str_concat_test (char *a, char *b, int len_a, int len_b) { - char *c = malloc (len_a + len_b + 2); // char c[255]; *c = 'K'; c[1] = 'O'; *(c+1) = 'U'; c[2] = '\0'; a[len_a] = '\0'; b[len_b] = '\0'; - strcpy(c, a); - strcpy(c + len_a + 1, b); - c[2] = '9'; c[3] = '9'; - *(c + len_a + len_b) = '\0'; -// printf ("static void current concat test (%s%s) > %s\n", a, b, c); - return c; -} - void util_trigger_test () { if (0) util_pile_test(); if (0) util_double_list_test(); if (0) util_sorted_list_test(); - //int len_a = 11, len_b = 14; char aaa [] = "Hello World", bbb [] = ", what's new ?"; - char *c = strcat (aaa, bbb); //c[11 + 14] = '\0'; - if (1) printf("%s <--- strcat () (would 'like to use: strncat() instead...)\n", c); - if (1) printf("%s <--- util_str_concat_test()\n", util_str_concat_test(aaa, bbb, 11, 14)); + if (0) printf("concat ([%s], [%s], NULL) --> '%s'\n", + aaa, bbb, concat (aaa, bbb, NULL)); } void util_pile_test() diff --git a/src/widget/topbar/dialog.c b/src/widget/topbar/dialog.c index 0e0113b..a828828 100644 --- a/src/widget/topbar/dialog.c +++ b/src/widget/topbar/dialog.c @@ -36,7 +36,7 @@ void widget_design_dialog_window (GtkWindow *main_window, GtkWindow *dialog_window) { - fsm_journal_event ("modal window design", INFO,MODAL_WINDOW, ""); + fsm_journal_event ("modal window design", INFO, MODAL_WINDOW, ""); char *title = " Save the current model before modifying it? "; GtkWidget *header_bar = GTK_WIDGET (gtk_header_bar_new ()); gtk_header_bar_set_title_widget (GTK_HEADER_BAR (header_bar), gtk_label_new (title));