| /* |
| *------------------------------------------------------------------ |
| * Copyright (c) 2005-2016 Cisco and/or its affiliates. |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at: |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <strings.h> |
| #include <ctype.h> |
| #include <string.h> |
| #include <gtk/gtk.h> |
| #include "g2.h" |
| |
| /* |
| * globals |
| */ |
| event_def_t g_eventdefs[NEVENTS]; |
| |
| /* |
| * locals |
| */ |
| static GtkWidget *s_pointselbox; |
| static FILE *s_hfp; |
| static FILE *s_elog_hfp; |
| static int s_basenum; |
| static GtkWidget *s_event_buttons[NEVENTS]; |
| static int s_min_shown_pointsel; |
| static int s_max_shown_pointsel; |
| static GtkWidget *s_allbutton; |
| static GtkWidget *s_nonebutton; |
| static GtkWidget *s_pointselbuttons; |
| static GtkWidget *s_ps_vscroll; |
| static GtkObject *s_ps_vsadj; |
| static int g_neventdefs; |
| |
| enum button_click { |
| ALL_BUTTON=1, |
| NONE_BUTTON, |
| }; |
| |
| /* |
| * config params |
| */ |
| int c_maxpointsel; |
| |
| /**************************************************************************** |
| * recompute_vscrollbar |
| ****************************************************************************/ |
| |
| static void recompute_ps_vscrollbar (void) |
| { |
| GtkAdjustment *adj; |
| ulong limit; |
| |
| adj = GTK_ADJUSTMENT(s_ps_vsadj); |
| |
| #ifdef NOTDEF |
| /* This seems like the right calculation, but seems not to work */ |
| if (g_neventdefs > c_maxpointsel) |
| limit = g_neventdefs - c_maxpointsel; |
| else |
| limit = g_neventdefs; |
| #else |
| limit = g_neventdefs-1; |
| #endif |
| |
| adj->lower = (gfloat)0.00; |
| adj->upper = (gfloat)limit; |
| adj->value = (gfloat)0.00; |
| adj->step_increment = (gfloat)1.00; |
| adj->page_increment = (gfloat)(c_maxpointsel / 3); |
| adj->page_size = (gfloat)c_maxpointsel; |
| gtk_adjustment_changed(adj); |
| gtk_adjustment_value_changed(adj); |
| gtk_widget_show(s_ps_vscroll); |
| } |
| |
| /**************************************************************************** |
| * point_select_callback |
| ****************************************************************************/ |
| |
| static void point_select_callback(GtkToggleButton *item, gpointer data) |
| { |
| int i = (int) (unsigned long long) data; |
| |
| g_eventdefs[i].selected = gtk_toggle_button_get_active( |
| GTK_TOGGLE_BUTTON(s_event_buttons[i])); |
| view1_display_when_idle(); |
| } |
| |
| /**************************************************************************** |
| * up_button |
| ****************************************************************************/ |
| |
| static void up_button(void) |
| { |
| int i; |
| int increment = c_maxpointsel/4; |
| |
| if (s_min_shown_pointsel == 0) |
| return; |
| |
| s_min_shown_pointsel -= increment; |
| |
| if (s_min_shown_pointsel < 0) |
| s_min_shown_pointsel = 0; |
| |
| s_max_shown_pointsel = s_min_shown_pointsel + c_maxpointsel; |
| |
| for (i = 0; i < g_neventdefs; i++) { |
| if (i >= s_min_shown_pointsel && |
| i <= s_max_shown_pointsel) |
| gtk_widget_show(s_event_buttons[i]); |
| else |
| gtk_widget_hide(s_event_buttons[i]); |
| } |
| |
| } |
| |
| #ifdef NOTDEF |
| /**************************************************************************** |
| * down_button |
| ****************************************************************************/ |
| |
| static void down_button(void) |
| { |
| int i; |
| int increment = c_maxpointsel/4; |
| |
| if (s_max_shown_pointsel == g_neventdefs) |
| return; |
| |
| s_max_shown_pointsel += increment; |
| |
| if (s_max_shown_pointsel >= g_neventdefs) |
| s_max_shown_pointsel = (g_neventdefs-1); |
| |
| s_min_shown_pointsel = s_max_shown_pointsel - c_maxpointsel; |
| |
| if (s_min_shown_pointsel < 0) |
| s_min_shown_pointsel = 0; |
| |
| for (i = 0; i < g_neventdefs; i++) { |
| if (i >= s_min_shown_pointsel && |
| i <= s_max_shown_pointsel) |
| gtk_widget_show(s_event_buttons[i]); |
| else |
| gtk_widget_hide(s_event_buttons[i]); |
| } |
| |
| } |
| #endif |
| |
| /**************************************************************************** |
| * button_click_callback |
| ****************************************************************************/ |
| |
| static void button_click_callback(GtkButton *item, gpointer data) |
| { |
| int i; |
| enum button_click click = (enum button_click)data; |
| |
| switch (click) { |
| case ALL_BUTTON: |
| for (i = 0; i < g_neventdefs; i++) { |
| gtk_toggle_button_set_active ( |
| GTK_TOGGLE_BUTTON(s_event_buttons[i]), TRUE); |
| g_eventdefs[i].selected = TRUE; |
| } |
| break; |
| |
| case NONE_BUTTON: |
| for (i = 0; i < g_neventdefs; i++) { |
| gtk_toggle_button_set_active ( |
| GTK_TOGGLE_BUTTON(s_event_buttons[i]), FALSE); |
| g_eventdefs[i].selected = FALSE; |
| } |
| break; |
| } |
| } |
| |
| /**************************************************************************** |
| * scroll_callback |
| ****************************************************************************/ |
| |
| static void scroll_callback (GtkAdjustment *adj, GtkWidget *notused) |
| { |
| int i; |
| |
| s_min_shown_pointsel = (int)adj->value; |
| s_max_shown_pointsel = s_min_shown_pointsel + c_maxpointsel; |
| |
| for (i = 0; i < g_neventdefs; i++) { |
| if (i >= s_min_shown_pointsel && |
| i <= s_max_shown_pointsel) |
| gtk_widget_show(s_event_buttons[i]); |
| else |
| gtk_widget_hide(s_event_buttons[i]); |
| } |
| } |
| |
| /**************************************************************************** |
| * point_selector_init |
| ****************************************************************************/ |
| |
| void point_selector_init(void) |
| { |
| |
| c_maxpointsel = atol(getprop_default("event_selector_lines", "20")); |
| |
| s_pointselbox = gtk_vbox_new(FALSE,5); |
| |
| s_pointselbuttons = gtk_hbox_new(FALSE,5); |
| |
| s_allbutton = gtk_button_new_with_label("ALL"); |
| gtk_widget_show(s_allbutton); |
| s_nonebutton = gtk_button_new_with_label("NONE"); |
| gtk_widget_show(s_nonebutton); |
| |
| gtk_signal_connect (GTK_OBJECT(s_allbutton), "clicked", |
| GTK_SIGNAL_FUNC(button_click_callback), |
| (gpointer) ALL_BUTTON); |
| |
| gtk_signal_connect (GTK_OBJECT(s_nonebutton), "clicked", |
| GTK_SIGNAL_FUNC(button_click_callback), |
| (gpointer) NONE_BUTTON); |
| |
| gtk_box_pack_start(GTK_BOX(s_pointselbuttons), s_allbutton, FALSE, |
| FALSE, 0); |
| gtk_box_pack_start(GTK_BOX(s_pointselbuttons), s_nonebutton, FALSE, |
| FALSE, 0); |
| |
| gtk_widget_show(s_pointselbuttons); |
| gtk_widget_ref(s_pointselbuttons); |
| |
| gtk_box_pack_start(GTK_BOX(s_pointselbox), s_pointselbuttons, FALSE, |
| FALSE, 0); |
| |
| gtk_box_pack_end (GTK_BOX(g_mainhbox), s_pointselbox, |
| FALSE, FALSE, 0); |
| |
| s_ps_vsadj = gtk_adjustment_new(0.0 /* initial value */, |
| 0.0 /* minimum value */, |
| 2000.0 /* maximum value */, |
| 0.1 /* step increment */, |
| 10.0/* page increment */, |
| 10.0/* page size */); |
| |
| s_ps_vscroll = gtk_vscrollbar_new (GTK_ADJUSTMENT(s_ps_vsadj)); |
| gtk_signal_connect (GTK_OBJECT (s_ps_vsadj), "value-changed", |
| GTK_SIGNAL_FUNC (scroll_callback), |
| (gpointer)s_ps_vscroll); |
| gtk_box_pack_end(GTK_BOX(g_mainhbox), s_ps_vscroll, FALSE, FALSE, 0); |
| } |
| |
| /**************************************************************************** |
| * sxerox |
| ****************************************************************************/ |
| |
| char *sxerox (char *s) |
| { |
| char *rv; |
| |
| /* Note: g_malloc does or dies... */ |
| rv = (char *)g_malloc(strlen(s)+1); |
| strcpy (rv, s); |
| return (rv); |
| } |
| |
| /**************************************************************************** |
| * reset_point_selector |
| ****************************************************************************/ |
| |
| static void reset_point_selector(void) |
| { |
| int i; |
| |
| gtk_widget_hide(s_pointselbox); |
| gtk_widget_hide(s_pointselbuttons); |
| gtk_widget_hide(s_ps_vscroll); |
| gtk_container_remove(GTK_CONTAINER(s_pointselbox), |
| s_pointselbuttons); |
| |
| for (i = 0; i < g_neventdefs; i++) { |
| if (s_event_buttons[i]) { |
| gtk_container_remove(GTK_CONTAINER(s_pointselbox), |
| s_event_buttons[i]); |
| s_event_buttons[i] = 0; |
| } |
| } |
| } |
| |
| /**************************************************************************** |
| * create_point_selector |
| ****************************************************************************/ |
| |
| static void create_point_selector(void) |
| { |
| int i; |
| char tmpbuf [1024]; |
| event_def_t *ep; |
| GtkWidget *wp; |
| |
| for (i = 0; i < g_neventdefs; i++) { |
| ep = &g_eventdefs[i]; |
| snprintf(tmpbuf, sizeof(tmpbuf), "[%lu] %s", ep->event, |
| ep->name ? ep->name : "(none)"); |
| /* Hack to reduce width of point selectors */ |
| if (strlen(tmpbuf) > 50) { |
| tmpbuf[50] = 0; |
| } |
| |
| wp = gtk_check_button_new_with_label (tmpbuf); |
| s_event_buttons[i] = wp; |
| gtk_signal_connect (GTK_OBJECT(wp), "toggled", |
| GTK_SIGNAL_FUNC(point_select_callback), |
| (gpointer) (unsigned long long) i); |
| gtk_toggle_button_set_active ( |
| GTK_TOGGLE_BUTTON(wp), TRUE); |
| gtk_box_pack_start(GTK_BOX(s_pointselbox), wp, FALSE, FALSE, 0); |
| } |
| |
| /* set up scroll parameters by faking an up-button */ |
| s_min_shown_pointsel = 1; |
| up_button(); |
| |
| gtk_box_pack_start(GTK_BOX(s_pointselbox), s_pointselbuttons, FALSE, |
| FALSE, 0); |
| gtk_widget_show(s_pointselbuttons); |
| gtk_widget_show(s_pointselbox); |
| gtk_widget_show(s_ps_vscroll); |
| } |
| |
| /**************************************************************************** |
| * remove_all_events |
| ****************************************************************************/ |
| |
| static void remove_all_events(void) |
| { |
| event_def_t *ep; |
| int i; |
| |
| for (i = 0; i < g_neventdefs; i++) { |
| ep = &g_eventdefs[i]; |
| if (!ep->is_clib) { |
| if (ep->name) |
| g_free(ep->name); |
| if(ep->format) |
| g_free(ep->format); |
| } |
| } |
| g_neventdefs = 0; |
| } |
| |
| /**************************************************************************** |
| * add_event |
| ****************************************************************************/ |
| |
| static void add_event(ulong event, char *name, char *format) |
| { |
| int i; |
| event_def_t *ep; |
| |
| if (g_neventdefs >= NEVENTS) { |
| g_error("Too many event definitions, increase NEVENTS!"); |
| /*NOTREACHED*/ |
| } |
| |
| /* Simple dup check, probably not needed very often */ |
| for (i = 0; i < g_neventdefs; i++) { |
| if (g_eventdefs[i].event == event) { |
| g_warning("Duplicate def event %lu: first definition retained\n", |
| event); |
| return; |
| } |
| } |
| |
| ep = &g_eventdefs[g_neventdefs++]; |
| |
| ep->event = event; |
| ep->name = sxerox(name); |
| ep->format = sxerox(format); |
| ep->selected = TRUE; |
| } |
| |
| /**************************************************************************** |
| * add_event_from_cpel_file |
| ****************************************************************************/ |
| |
| void add_event_from_cpel_file(ulong event, char *event_format, |
| char *datum_format) |
| { |
| event_def_t *ep; |
| |
| if (g_neventdefs >= NEVENTS) { |
| g_error("Too many event definitions, increase NEVENTS!"); |
| /*NOTREACHED*/ |
| } |
| |
| ep = &g_eventdefs[g_neventdefs++]; |
| |
| ep->event = event; |
| /* |
| * Duplicate the strings for backward compatibility. Otherwise, |
| * the g_free above will barf because the name/format strings are |
| * actually in mmap'ed memory |
| */ |
| ep->name = sxerox(event_format); |
| ep->format = sxerox(datum_format); |
| ep->selected = TRUE; |
| } |
| |
| /**************************************************************************** |
| * add_event_from_clib_file |
| ****************************************************************************/ |
| |
| void add_event_from_clib_file(unsigned int event, char *name, |
| unsigned int vec_index) |
| { |
| event_def_t *ep; |
| |
| if (g_neventdefs >= NEVENTS) { |
| g_error("Too many event definitions, increase NEVENTS!"); |
| /*NOTREACHED*/ |
| } |
| |
| ep = &g_eventdefs[g_neventdefs++]; |
| |
| ep->event = event; |
| |
| ep->name = sxerox(name); |
| ep->format = (void *)(unsigned long long) vec_index; |
| ep->selected = TRUE; |
| ep->is_clib = TRUE; |
| } |
| |
| /**************************************************************************** |
| * read_header_file - eats header file lines of the form |
| * |
| * #define EVENT_FOO 123 / * name: %d * / |
| * |
| ****************************************************************************/ |
| |
| static void read_header_file (void) |
| { |
| char tmpbuf [1024]; |
| char *name, *format; |
| char *cp; |
| unsigned long event; |
| int ev_num_flag; |
| |
| while (fgets (tmpbuf, sizeof (tmpbuf), s_hfp)) |
| { |
| cp = tmpbuf; |
| ev_num_flag = 0; |
| |
| if (strncmp (cp, "#define", 7)) |
| continue; |
| |
| /* skip #define */ |
| while (*cp && !(isspace ((int)*cp))) |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| /* skip ws after #define */ |
| while (*cp && isspace ((int)*cp)) |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| /* skip symbolic name */ |
| while (*cp && !(isspace ((int)*cp))) |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| /* skip ws after symbolic name */ |
| while (*cp && isspace ((int)*cp)) |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| event = 0; |
| |
| if (!strncmp(cp, "EV_NUM", 6)) { |
| cp += 6; |
| ev_num_flag = 1; |
| |
| while (*cp && *cp != '(') |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| cp++; |
| |
| while (*cp && isspace ((int)*cp)) |
| cp++; |
| |
| } |
| |
| /* eat event code. */ |
| while (*cp && isdigit ((int)*cp)) |
| { |
| event = event * 10 + (*cp - '0'); |
| cp++; |
| } |
| |
| if (*cp == 0) |
| continue; |
| |
| if (ev_num_flag) { |
| while (*cp && *cp != ')') |
| cp++; |
| if (*cp == 0) |
| continue; |
| cp++; |
| event += s_basenum; |
| } |
| |
| /* skip ws after event code */ |
| while (*cp && isspace ((int)*cp)) |
| cp++; |
| |
| if (*cp != '/') |
| continue; |
| |
| cp++; |
| |
| if (*cp != '*') |
| continue; |
| |
| cp++; |
| |
| /* skip ws after comment start */ |
| while (*cp && isspace ((int)*cp)) |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| name = cp; |
| |
| /* accumulate name */ |
| while (*cp && *cp != ':' && *cp != '*') |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| *cp++ = 0; |
| |
| /* skip ws after name: */ |
| while (*cp && isspace ((int)*cp)) |
| cp++; |
| |
| if (*cp == 0 || *cp == '/') |
| { |
| format = " "; |
| goto write_it; |
| } |
| |
| format = cp; |
| |
| /* accumulate format string */ |
| while (*cp && !isspace ((int)*cp)) |
| cp++; |
| |
| *cp = 0; |
| |
| write_it: |
| |
| add_event (event, name, format); |
| } |
| } |
| |
| /**************************************************************************** |
| * read_header_files - eats header file lines of the form |
| * |
| * #define FILE1_BASE 100 / * pointdefs: ../vpn/vpn_points.h * / |
| * |
| ****************************************************************************/ |
| |
| static boolean read_header_files (void) |
| { |
| char *cp, *name; |
| char tmpbuf [1024]; |
| int basenum; |
| boolean rv=FALSE; |
| |
| while (fgets (tmpbuf, sizeof (tmpbuf), s_elog_hfp)) |
| { |
| cp = tmpbuf; |
| |
| if (strncmp (cp, "#define", 7)) |
| continue; |
| |
| cp += 7; |
| |
| /* skip ws after #define */ |
| while (*cp && isspace ((int)*cp)) |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| /* skip EV_COMPxxx_START */ |
| while (*cp && !isspace((int)*cp)) |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| /* skip ws after EV_COMPxxx_START */ |
| while (*cp && isspace ((int)*cp)) |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| basenum = atol (cp); |
| |
| /* skip #define */ |
| while (*cp && (*cp != '/')) |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| cp++; |
| if (*cp != '*') |
| continue; |
| |
| cp++; |
| |
| /* skip ws after comment start */ |
| while (*cp && isspace ((int)*cp)) |
| cp++; |
| |
| if (*cp == 0) |
| continue; |
| |
| if (strncmp (cp, "pointdefs:", 10)) |
| continue; |
| |
| cp += 10; |
| |
| /* skip ws after comment start */ |
| while (*cp && isspace ((int)*cp)) |
| cp++; |
| |
| name = cp; |
| |
| while (*cp && !isspace ((int)*cp)) |
| cp++; |
| |
| *cp = 0; |
| |
| s_hfp = fopen (name, "rt"); |
| |
| if (s_hfp == NULL) { |
| g_warning ("Couldn't open header file %s\n", name); |
| continue; |
| } |
| rv = TRUE; |
| |
| s_basenum = basenum; |
| |
| read_header_file(); |
| |
| fclose (s_hfp); |
| } |
| return(rv); |
| } |
| |
| /**************************************************************************** |
| * event_def_cmp |
| ****************************************************************************/ |
| |
| int event_def_cmp(const void *a1, const void *a2) |
| { |
| event_def_t *e1 = (event_def_t *)a1; |
| event_def_t *e2 = (event_def_t *)a2; |
| |
| if (e1->event < e2->event) |
| return(-1); |
| else if (e1->event == e2->event) |
| return(0); |
| else |
| return(1); |
| } |
| |
| /**************************************************************************** |
| * sort_event_definitions |
| ****************************************************************************/ |
| |
| void sort_event_definitions(void) |
| { |
| qsort(&g_eventdefs[0], g_neventdefs, sizeof(event_def_t), event_def_cmp); |
| } |
| |
| static boolean remove_needed=TRUE; |
| |
| void finalize_events(void) |
| { |
| sort_event_definitions(); |
| create_point_selector(); |
| recompute_ps_vscrollbar(); |
| view1_display_when_idle(); |
| remove_needed = TRUE; |
| } |
| |
| void initialize_events(void) |
| { |
| if (remove_needed) { |
| reset_point_selector(); |
| remove_all_events(); |
| remove_needed = FALSE; |
| } |
| } |
| |
| /**************************************************************************** |
| * read_event_definitions |
| ****************************************************************************/ |
| |
| boolean read_event_definitions (char *filename) |
| { |
| char tmpbuf [128]; |
| |
| initialize_events(); |
| |
| s_elog_hfp = fopen (filename, "rt"); |
| if (s_elog_hfp == NULL) { |
| snprintf (tmpbuf, sizeof(tmpbuf), "Couldn't open %s\n", filename); |
| infobox ("Open Failed", tmpbuf); |
| return(FALSE); |
| } |
| /* Presume "elog.h". Note fallthrough... */ |
| if (read_header_files()) { |
| sort_event_definitions(); |
| create_point_selector(); |
| recompute_ps_vscrollbar(); |
| fclose(s_elog_hfp); |
| view1_display_when_idle(); |
| remove_needed = TRUE; |
| return(TRUE); |
| } |
| fclose(s_elog_hfp); |
| |
| s_hfp = fopen (filename, "rt"); |
| if (s_hfp == NULL) { |
| snprintf (tmpbuf, sizeof(tmpbuf), "Couldn't open %s\n", filename); |
| infobox ("Read Event Definition Failure", tmpbuf); |
| return(FALSE); |
| } |
| |
| read_header_file(); |
| |
| /* Happens if the user feeds us the wrong file, for example */ |
| if (g_neventdefs == 0) { |
| snprintf (tmpbuf, sizeof(tmpbuf), |
| "No event definitions found in %s\n", filename); |
| infobox ("No Event Definitions?", tmpbuf); |
| return(FALSE); |
| } |
| finalize_events(); |
| return(TRUE); |
| } |
| |
| static event_def_t dummy_event; |
| static char dummy_string[32]; |
| |
| /**************************************************************************** |
| * find_event_definition |
| * Binary search for first event whose time is >= t |
| ****************************************************************************/ |
| |
| event_def_t *find_event_definition (ulong code) |
| { |
| int index, bottom, top; |
| event_def_t *edp; |
| |
| if (g_neventdefs == 0) |
| goto use_dummy; |
| |
| bottom = g_neventdefs-1; |
| top = 0; |
| |
| while (1) { |
| index = (bottom + top) / 2; |
| |
| edp = (g_eventdefs + index); |
| |
| if (edp->event == code) |
| return(edp); |
| |
| if (top >= bottom) { |
| use_dummy: |
| edp = &dummy_event; |
| edp->selected = TRUE; |
| edp->event = code; |
| edp->format = "0x%x"; |
| snprintf (dummy_string, sizeof(dummy_string), "E%lu", code); |
| edp->name = &dummy_string[0]; |
| return(edp); |
| } |
| |
| if (edp->event < code) |
| top = index + 1; |
| else |
| bottom = index - 1; |
| } |
| } |
| |
| /**************************************************************************** |
| * pointsel_next_snapshot |
| * Set dialog buttons from snapshot |
| ****************************************************************************/ |
| |
| void pointsel_next_snapshot(void) |
| { |
| int i; |
| |
| for (i = 0; i < g_neventdefs; i++) { |
| gtk_toggle_button_set_active ( |
| GTK_TOGGLE_BUTTON(s_event_buttons[i]), |
| g_eventdefs[i].selected); |
| } |
| } |
| |
| /**************************************************************************** |
| * pointsel_about |
| ****************************************************************************/ |
| |
| void pointsel_about (char *tmpbuf) |
| { |
| snprintf (tmpbuf+strlen(tmpbuf), 128, "%d event definitions\n", |
| g_neventdefs); |
| } |