/* xlog - GTK+ logging program for amateur radio operators Copyright (C) 2001 - 2007 Joop Stakenborg This file is part of xlog. Xlog is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Xlog 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 General Public License for more details. You should have received a copy of the GNU General Public License along with xlog. If not, see . */ /* * editest.c - support for .exp Editest file format (CSV like) * Reports to Stephane Fillod F8CFE */ #include #include #include #include #include #include "logfile.h" /* * Editest is a french contest logging program. * Files can be generated for 2 kinds of contest. * Number of fields is identical for both. * * For HF: * DATE GMT CALL RST MYRST NR BAND PTS ZONE * For VHF: * DATE GMT CALL RST MYRST LOCATOR BAND PTS KM * * Note: there's no MODE field! */ /* * file fields */ const gint editest_fields[] = { DATE, GMT, CALL, RST, MYRST, LOCATOR, BAND }; const gint editest_widths[] = { 9, 5, 14, 8, 8, 9, 9, 5 }; const gint editest_field_nr = 7; static gint editest_open (LOGDB *); static void editest_close (LOGDB *); static gint editest_create (LOGDB *); static gint editest_qso_append (LOGDB *, const qso_t *); static gint editest_qso_foreach (LOGDB *, gint (*fn) (LOGDB *, qso_t *, gpointer arg), gpointer arg); const struct log_ops editest_ops = { .open = editest_open, .close = editest_close, .create = editest_create, .qso_append = editest_qso_append, .qso_foreach = editest_qso_foreach, .type = TYPE_EDITEST, .name = "Editest", .extension = ".exp", }; /* * open for read */ gint editest_open (LOGDB * handle) { FILE *fp; fp = fopen (handle->path, "r"); if (!fp) return -1; handle->priv = (gpointer) fp; handle->column_nr = editest_field_nr; memcpy (handle->column_fields, editest_fields, sizeof (editest_fields)); memcpy (handle->column_widths, editest_widths, sizeof (editest_widths)); return 0; } /* * open for write */ gint editest_create (LOGDB * handle) { FILE *fp; fp = fopen (handle->path, "w"); if (!fp) return -1; handle->priv = (gpointer) fp; return 0; } void editest_close (LOGDB * handle) { FILE *fp = (FILE *) handle->priv; fclose (fp); } /* */ gint editest_qso_append (LOGDB * handle, const qso_t * q) { FILE *fp = (FILE *) handle->priv; gchar rst[16], exch[16] = "", my_rst[16], my_exch[16] = ""; gchar date[16], locator[16]; gchar *p; gint rst_len; /* * there's no exchange fields in xlog. However, the exchange information * may be piggybacked by the rst field. eg. "599 35". */ p = strchr (q[RST], ' '); rst_len = p ? p - q[RST] : strlen (q[RST]); strncpy (rst, q[RST], rst_len); rst[rst_len] = '\0'; strncpy (my_rst, q[MYRST], rst_len); my_rst[rst_len] = '\0'; if (strlen (q[RST]) > rst_len) strcpy (exch, q[RST] + rst_len); if (strlen (q[MYRST]) > rst_len) strcpy (my_exch, q[MYRST] + rst_len); //const gint editest_fields[] = { DATE, GMT, CALL, RST, MYRST, LOCATOR, BAND }; if (strlen (q[DATE]) == 11 && q[DATE][2] == ' ' && q[DATE][6] == ' ') sprintf (date, "%c%c-%02d-%s", q[DATE][0], q[DATE][1], scan_month (q[DATE] + 3), q[DATE] + 9); if (q[NR] && (!q[LOCATOR] || strlen (q[LOCATOR]) == 0)) sprintf (locator, "%s", q[NR]); else strcpy (locator, q[LOCATOR] ? q[LOCATOR] : ""); /* * .exp CSV-like format * * If there's no locator data, maybe it's a HF log * * We're missing the points and zone/km column, * hence the empty semicolon * * TODO: compute these from location set in the preferences */ fprintf (fp, "%s;%s;%s;%s;%s;%s;%s;%s;%s;;\n", date, q[GMT], q[CALL], rst, exch, my_rst, my_exch, locator, q[BAND]); return 0; } #define MAXROWLEN 120 gint editest_qso_foreach (LOGDB * handle, gint (*fn) (LOGDB *, qso_t *, gpointer arg), gpointer arg) { FILE *fp = (FILE *) handle->priv; gint ret, i; qso_t q[QSO_FIELDS]; gchar *field; gchar buffer[MAXROWLEN]; gint field_cnt = 0; gint concat; gchar *p, *qfield; while (!feof (fp)) { if (!fgets (buffer, MAXROWLEN - 1, fp)) break; memset (q, 0, sizeof (q)); field = buffer; concat = 0; field_cnt = 0; for (p = buffer; *p && field_cnt < editest_field_nr; p++) { if (*p == ';') { /* concat rst with exchange number */ if (!concat && (field_cnt == 3 || field_cnt == 4)) { *p = ' '; concat = 1; continue; } concat = 0; *p = '\0'; switch (editest_fields[field_cnt]) { case DATE: { struct tm timestruct; gchar sdate[16]; sscanf (field, "%2i-%2i-%2i", ×truct.tm_mday, ×truct.tm_mon, ×truct.tm_year); if (timestruct.tm_year < 70) timestruct.tm_year += 100; timestruct.tm_mon--; strftime (sdate, 16, "%d %b %Y", ×truct); qfield = g_strdup (sdate); break; } case GMT: { gchar gmt[16]; if (strlen(field) > 2 && field[2] == ':') { memcpy(gmt, field, 2); /* suppress the colon */ strncpy(gmt+2, field+3, 14); } else { strncpy(gmt, field, 16); } qfield = g_strdup (gmt); break; } default: qfield = g_strdup (field); } q[editest_fields[field_cnt]] = qfield; field = p + 1; field_cnt++; } } /* fill in empty fields */ for (i = 0; i < editest_field_nr; i++) { if (!q[editest_fields[i]]) q[editest_fields[i]] = g_strdup (""); } ret = (*fn) (handle, q, arg); if (ret) return ret; } return 0; }