Re: Conversion functions.

On Thu, Sep 06, 2007 at 11:00:11AM -0300, Matí­as Alejandro Torres wrote:
Here's the minimal program to read that. The reading part is kind of 
crappy but it works with that example.

The trouble with the reading part is not that it's kind of
crappy (well, it is IMO, reading by character makes no sense
when g_ascii_strtod() and strtol() can perfectly iterate
themselves *and* have error-reporting, g_slist_append() is
O(N) making the reading O(N^2), it is a waste of time to
construct a big GSList just to fill a GtkListStore from it
instead of filling the store directly -- and if Data is
a data structure used elsewhere in the program it makes
little sense to break it into columns instead of storing it
directly in a G_TYPE_BOXED/G_TYPE_POINTER column), but that:
- it assigns the fgetc() return value to a gchar, breaking
  EOF testing
- it uses a fixed unchecked buffer of size 50 we do now know
  whether overflows or not on your data
- it takes any sequence of non-[ \t] as a field and reads
  it without checking so we do not know what actually
  happens on your data
- it uses g_strtod() (NOT g_ascii_strtod() you've been
  talking about) which tries to accept both C and your
  current locale formats and therefore is not predictable
  (and won't help reading data that someone with
  a *different* local wrote in the locale-specific manner

If the attached program reads the complete file and prints
back its contents correctly, then I dare to say your problem
is not broken g_ascii_strtod().  As a bonus, the attached
program prints a detailed error to stderr if there are
malformed data rows in the file.



#define _GNU_SOURCE 1
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <glib.h>

typedef struct _Data {
    gchar   *log;
    gdouble latitude;
    gint    altitude;
    gint    interval;
    gint    heartbeat;
    gdouble speed;
} Data;

main(int argc,
     char *argv[])
    const gchar *filename, *failfield;
    gchar *buf = NULL;
    size_t buf_size = 0, lineno;
    ssize_t line_len;
    FILE *fh;
    GSList *l, *stuff = NULL;
    Data *data;

    if (argc != 2) {
        g_printerr("readstuff FILE\n");
        return 1;

    filename = argv[1];
    if (!(fh = fopen(filename, "r"))) {
        g_printerr("Cannot open %s: %s\n", filename, g_strerror(errno));
        return 1;

    lineno = 0;
    failfield = NULL;
    while ((line_len = getline(&buf, &buf_size, fh)) != -1) {
        gchar *start, *end;
        guint len;

        start = g_strstrip(buf);
        /* Skip non-data lines */
        if (!buf[0] || !g_ascii_isdigit(buf[0]))

        data = g_new(Data, 1);
        len = strcspn(start, " \t");
        data->log = g_strndup(start, len);
        start += len;

        data->latitude = g_ascii_strtod(start, &end);
        if (end == start) {
            failfield = "Latitude";
        start = end;

        data->altitude = strtol(start, &end, 10);
        if (end == start) {
            failfield = "Altitude";
        start = end;

        data->interval = strtol(start, &end, 10);
        if (end == start) {
            failfield = "IntervalTime";
        start = end;

        data->heartbeat = strtol(start, &end, 10);
        if (end == start) {
            failfield = "HeartRate";
        start = end;

        data->speed = g_ascii_strtod(start, &end);
        if (end == start) {
            failfield = "Speed";

        stuff = g_slist_prepend(stuff, data);

        if (*end)
            fprintf(stderr, "Warning: trailing garbage at line %lu of %s: %s\n",
                    (unsigned long int)lineno, filename, buf);


    if (failfield) {
        fprintf(stderr, "Cannot parse %s at line %lu of %s: %s\n",
                failfield, (unsigned long int)lineno, filename, buf);
    else {
        stuff = g_slist_reverse(stuff);
        for (l = stuff; l; l = l->next) {
            data = (Data*)l->data;
            printf("%s %.5f %d %d %d %.2f\n",
                   data->log, data->latitude, data->altitude,
                   data->interval, data->heartbeat, data->speed);

    for (l = stuff; l; l = l->next) {
        data = (Data*)l->data;

    return !!failfield;

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]