summaryrefslogtreecommitdiffstats
path: root/src/plugins/memif
AgeCommit message (Expand)AuthorFilesLines
2021-09-17memif: avoid double pool_put on a clib_fileSteven Luong1-1/+2
2021-08-04memif: fix offsetArtem Glazychev1-1/+1
2021-07-15misc: replace CLIB_PREFETCH with clib_prefetch_{load,store}Damjan Marion2-16/+12
2021-06-30memif: fix tx desc length for chained buffers in copy modeBenoît Ganne1-0/+1
2021-06-30memif: fix chain buffer length in zero-copy modeBenoît Ganne1-0/+1
2021-06-11memif: fix crash with zero-copy slaveDamjan Marion1-1/+1
2021-06-10memif: fix the spinlock and unlock issue.fangtong1-1/+2
2021-05-26vppinfra: explicit blocking mode for sock connectsFlorin Coras1-2/+3
2021-05-21memif: fix gcc-10 build error on arm platformTianyu Li1-1/+1
2021-05-20memif: fix input node buffer prefetchTianyu Li1-4/+4
2021-05-19memif: remove dead codeDamjan Marion1-1/+1
2021-05-17memif: remove unused codeDamjan Marion1-46/+13
2021-05-17memif: remove duplicate code in txDamjan Marion1-53/+39
2021-05-17memif: optimize zero-copy rx ring refillDamjan Marion2-65/+47
2021-05-17memif: fix "remove barriers" commitDamjan Marion1-2/+2
2021-05-17memif: remove barriersDamjan Marion2-22/+33
2021-05-13tests: move test source to vpp/testDave Wallace2-448/+0
2021-05-08memif: Fix delete on errorNathan Skrzypczak1-8/+0
2021-05-06vlib: rename vl_counter_t to vlib_error_desc_tOle Troan2-2/+2
2021-05-06memif: add severity to countersOle Troan2-14/+14
2021-05-01vlib: refactor trajectory trace debug featureBenoît Ganne1-2/+0
2021-04-18vppinfra: remove linux/syscall.hDamjan Marion1-1/+0
2021-04-16tests: cpus awarenessKlement Sekera1-1/+14
2021-04-08memif: Use log_debug for clib_file_add and clib_file_delSteven Luong1-15/+24
2021-03-26vlib: introduce vlib_get_main_by_index(), vlib_get_n_threads()Damjan Marion3-4/+4
2021-03-19interface: add capabilities flagsMohsin Kazmi1-1/+1
2021-03-04memif: Validate descriptors within process boudarySteven Luong1-20/+27
2021-01-22tests: add generalized tags for tests, use them for run-solo testsAndrew Yourtchenko1-4/+2
2021-01-21memif: adapt to new rxq frameworkMohammed Hawari3-61/+59
2021-01-20memif: fix vpp to go link up immediately on admin upEd Warnicke3-16/+23
2020-12-14misc: move to new pool_foreach macrosDamjan Marion3-8/+7
2020-12-04libmemif: clean up typosPaul Vinciguerra4-4/+4
2020-12-03tests: remove py2/py3 six compatability libraryPaul Vinciguerra2-3/+0
2020-11-09vlib: fix trace number accountingBenoît Ganne1-8/+11
2020-10-26memif: handle unexpected EPOLLOUT for RX queueSteven Luong1-0/+12
2020-10-12misc: clang-11 and gcc-10 supportDamjan Marion1-1/+1
2020-10-08interface: shorten vnet_hw_if_rx_modeDamjan Marion2-5/+5
2020-10-02memif: map shared memory with clib_mem_vm_map_shared(...)Damjan Marion1-10/+25
2020-08-27tests: "force solo" testcase supportAndrew Yourtchenko1-0/+4
2020-08-06memif: wrong interface counter is incrementedSteven Luong1-2/+2
2020-05-14memif: 14 bytes extra overhead issue fixed.Mrityunjay Kumar1-2/+2
2020-02-26api: improve api string safetyJakub Grajciar1-5/+2
2019-12-23tests: vpp_memif fix formatting error in exceptionPaul Vinciguerra1-5/+2
2019-12-07lacp: fix control_ping from pluginsOle Troan1-0/+4
2019-11-24vppapigen: clean up typos in c generated codePaul Vinciguerra1-1/+1
2019-11-15tests: Remove the unrequired VPP IP address/prefix class wrappersNeale Ranns2-7/+10
2019-10-23memif: memif buffer leaks during disconnecting zero copy interface.Changqian Wang1-0/+36
2019-10-18memif: add python3 support to testOle Troan2-20/+13
2019-10-14memif: Revert "memif buffer leaks during disconnect."Andrew Yourtchenko1-36/+2
2019-10-10memif: remove api boilerplateOle Troan6-252/+15
color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/* 
 *------------------------------------------------------------------
 * 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];
        sprintf(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) {
        sprintf (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) {
        sprintf (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) {
        sprintf (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";
            sprintf (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)
{
    sprintf (tmpbuf+strlen(tmpbuf), "%d event definitions\n", 
             g_neventdefs);
}