从暂停恢复分段错误

时间:2011-09-14 19:05:04

标签: c gtk segmentation-fault

我正在使用GTK编写一个非常简单的电池状态图标。 它是一个GtkStatusIcon,在工具提示中显示当前的电池状态。 为了获得电池信息,我解析了命令acpi的输出,该输出通常类似于:     

Battery 0: Discharging, 70%, 01:00:00 remaining

我的电池状态图标运行正常,但是当我暂停计算机然后恢复它时,我的程序因分段故障而崩溃。

整个代码是这样的(我已经评论过了):

#include <gtk/gtk.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#define DEFAULT_ARRAY_SIZE 3
#define DEFAULT_TIME_UPDATE 5

const gchar * acpi_command = "acpi";

typedef enum batteryState{
    CHARGING,
    DISCHARGING,
} BatteryState;

typedef struct batteryTray {
    GtkStatusIcon * tray_icon;
    gchar * tooltip;
    gchar * icon;
} BatteryTray;

typedef struct battery {
    gchar * status;
    gint percentage;
    gchar * extra;
        BatteryTray batteryTray;
    BatteryState batteryState;
} Battery;

static void update_status_battery(Battery * battery);
static gboolean update_status_tray(Battery * battery);
static gchar * get_status_icon_name(Battery * battery);
static void create_tray_icon(Battery * battery);
static void parse_acpi_output(Battery * battery, gchar * acpi_output);
static char * get_acpi_output(const gchar * acpi_command);

static void update_status_battery(Battery * battery)
{
    if(strcmp(battery->status, "Charging") == 0)
        battery->batteryState = CHARGING;
    else if(strcmp(battery->status, "Discharging") == 0)
        battery->batteryState = DISCHARGING;
}

static gboolean update_status_tray(Battery * battery)
{
    gchar * icon_name = get_status_icon_name(battery);
    gchar * acpi_out = get_acpi_output(acpi_command);

    parse_acpi_output(battery, acpi_out);
    update_status_battery(battery);

    battery->batteryTray.tooltip = g_strdup_printf("%s (%d%%) %s", 
        battery->status, 
        battery->percentage,
        battery->extra);

    gtk_status_icon_set_tooltip_text(battery->batteryTray.tray_icon,
        battery->batteryTray.tooltip);

    gtk_status_icon_set_from_icon_name(battery->batteryTray.tray_icon,
        icon_name);

    return TRUE; 
}

static gchar * get_status_icon_name(Battery * battery)
{

    GString * icon_name = g_string_new("notification-battery");

    if (battery->percentage < 20)
        g_string_append(icon_name, "-low");
    else if (battery->percentage < 40)
        g_string_append(icon_name, "-020");
    else if (battery->percentage < 80)
        g_string_append(icon_name, "-060");
    else
        g_string_append(icon_name, "-100");

    if(battery->batteryState == CHARGING) {
        g_string_append(icon_name, "-plugged");
    }

    return icon_name->str;
}

static void create_tray_icon(Battery * battery) 
{
        /* create the gtkstatusicon and call the function
           `update_status_tray` every 5 seconds */

    battery->batteryTray.tray_icon = gtk_status_icon_new();
    battery->batteryTray.tooltip = "battery";
    gtk_status_icon_set_tooltip(battery->batteryTray.tray_icon, 
        battery->batteryTray.tooltip);
    gtk_status_icon_set_visible(battery->batteryTray.tray_icon, 
        TRUE);

    update_status_tray(battery);
    g_timeout_add_seconds(DEFAULT_TIME_UPDATE, (GSourceFunc) update_status_tray, battery);
}

static void parse_acpi_output(Battery * battery, gchar * acpi_output)
{
    /* acpi output is like:
       Battery 0: Discharging, 70%, 01:00:00 remaining

       In this function I assign "Discharging" to battery->status 
       70 to battery->percentage
       and "01:00:00 remaining" to battery->extra

       I use strtok to split the acpi output into tokens delimited by ',' and
       then, if there's a blank character ' ' in front of a token, i 'remove' it.
     */

    gint i = 0;
    gchar * t;
    gchar ** values_array;

    /* find the position of ':' in the string */
    int pos = strchr(acpi_output, ':') - acpi_output;
    t = strtok(acpi_output + pos + 1, ",");

    values_array = malloc(DEFAULT_ARRAY_SIZE * sizeof(gchar));

    while(t != NULL) {
        /* 'remove' the blank character */
        values_array[i++] = t[0] == ' ' ? t + 1 : t;
        t = strtok(NULL, ",");
    }

    /* remove newline */
    if(values_array[2][strlen(values_array[2]) - 1] == '\n') {
        values_array[2][strlen(values_array[2]) - 1] = '\0';
    }

    battery->status = values_array[0];
    battery->percentage = atoi(values_array[1]);
    battery->extra = values_array[2];

    free(values_array);
}

static gchar * get_acpi_output(const gchar * acpi_command)
{
    gchar * output;
    GError * error = NULL;

    /* assign the output of the acpi command to 'output' */
    g_spawn_command_line_sync(acpi_command, &output, NULL, NULL, &error);
    return output;
} 

int main(int argc, char ** argv)
{
    Battery battery;

    gtk_init(&argc, &argv);
    create_tray_icon(&battery);
    gtk_main();

    return 0;
}

我希望有人可以帮助我,因为我真的无法理解。

1 个答案:

答案 0 :(得分:1)

您可以在许多地方进行更多错误检查;也许你的代码之外的东西在唤醒期间失败了。例如,您不检查g_spawn_command_line_sync的结果 - 您假设output在返回时指向有效的字符串,但可能并非总是如此。你假设,但实际上没有确认,你运行的工具的输出中有一定数量的标记,但也许并非总是如此。