%{ /* * xlog - GTK+ logging program for amateur radio operators * Copyright (C) 2001-2002 Joop Stakenborg * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 Library General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* * adif.l - scanner for ADIF format - "Amateur Data Interchange Format" 1.0 * Reports to Stephane Fillod F8CFE * Specifications from http://www.hosenose.com/adif/adif.html */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include "logfile.h" #include "types.h" /* * fields to be stored in the adif file */ static const gint adif_fields[] = { DATE, GMT, CALL, BAND, MODE, RST, MYRST, QSLOUT, QSLIN, REMARKS, POWER, GMTEND, NAME, QTH, LOCATOR, U1, U2 }; static const gint adif_widths[] = { 15, 8, 15, 15, 8, 8, 8, 8, 8, 80, 8, 8, 8, 8, 6, 8, 8 }; static const gint adif_field_nr = 17; static LOGDB *adif_handle; static gint (*adif_fn)(LOGDB*, qso_t*, gpointer); static gpointer adif_arg; static qso_t q[QSO_FIELDS]; static gint adif_field_len = 0; static gint adif_field = -1; static gint adif_open(LOGDB*); static void adif_close(LOGDB*); static gint adif_create(LOGDB*); static gint adif_qso_append(LOGDB*, const qso_t*); static gint adif_qso_foreach(LOGDB*, gint (*fn)(LOGDB*, qso_t*, gpointer), gpointer); static const gchar *xlog2adif_name(gint); const struct log_ops adif_ops = { open: adif_open, close: adif_close, create: adif_create, qso_append: adif_qso_append, qso_foreach: adif_qso_foreach, type: TYPE_ADIF, name: "ADIF", extension: ".adi", }; %} DIGIT [0-9] FIELDTYPEND ":"{DIGIT}+(":"[^>])?">" CALLLBL [Cc][Aa][Ll][Ll] MODELBL [Mm][Oo][Dd][Ee] DATELBL "QSO_DATE"|"qso_date" FREQLBL "FREQ"|"freq" BANDLBL "BAND"|"band" GMTLBL "TIME_ON"|"time_on" GMTENDLBL "TIME_OFF"|"time_off" POWERLBL "TX_POWER"|"tx_power" RSTLBL "RST_SENT"|"rst_sent" MYRSTLBL "RST_RCVD"|"rst_rcvd" QSLOUTLBL "QSL_SENT"|"qsl_sent" QSLINLBL "QSL_RCVD"|"qsl_rcvd" REMARKSLBL "COMMENT"|"comment" NAMELBL "NAME"|"name" QTHLBL "QTH"|"qth" LOCATORLBL "GRIDSQUARE"|"gridsquare" %x header record field %% ^"<" { BEGIN(record); unput(*yytext); } ^[^<] { BEGIN(header); unput(*yytext); }
""|"" { /* End Of Header */ BEGIN(record); } { "<"{CALLLBL}{FIELDTYPEND} { adif_field = CALL; adif_field_len = atoi(yytext + 6); /* TODO: optional data type */ BEGIN(field); } "<"{MODELBL}{FIELDTYPEND} { adif_field = MODE; adif_field_len = atoi(yytext + 6); /* TODO: optional data type */ BEGIN(field); } "<"{DATELBL}{FIELDTYPEND} { adif_field = DATE; adif_field_len = atoi(yytext + 10); /* TODO: optional data type */ BEGIN(field); } "<"{GMTLBL}{FIELDTYPEND} { adif_field = GMT; adif_field_len = atoi(yytext + 9); /* TODO: optional data type */ BEGIN(field); } "<"{GMTENDLBL}{FIELDTYPEND} { adif_field = GMTEND; adif_field_len = atoi(yytext + 10); /* TODO: optional data type */ BEGIN(field); } "<"{POWERLBL}{FIELDTYPEND} { adif_field = POWER; adif_field_len = atoi(yytext + 10); /* TODO: optional data type */ BEGIN(field); } "<"{FREQLBL}{FIELDTYPEND} { /* prefer FREQ over BAND */ if (q[BAND]) { g_free(q[BAND]); q[BAND] = NULL; } adif_field = BAND; adif_field_len = atoi(yytext + 6); /* TODO: optional data type */ BEGIN(field); } "<"{BANDLBL}{FIELDTYPEND} { /* prefer FREQ over BAND */ if (!q[BAND]) { adif_field = BAND; adif_field_len = atoi(yytext + 6); } /* TODO: optional data type */ BEGIN(field); } "<"{RSTLBL}{FIELDTYPEND} { adif_field = RST; adif_field_len = atoi(yytext + 10); /* TODO: optional data type */ BEGIN(field); } "<"{MYRSTLBL}{FIELDTYPEND} { adif_field = MYRST; adif_field_len = atoi(yytext + 10); /* TODO: optional data type */ BEGIN(field); } "<"{QSLOUTLBL}{FIELDTYPEND} { adif_field = QSLOUT; adif_field_len = atoi(yytext + 10); /* TODO: optional data type */ BEGIN(field); } "<"{QSLINLBL}{FIELDTYPEND} { adif_field = QSLIN; adif_field_len = atoi(yytext + 10); /* TODO: optional data type */ BEGIN(field); } "<"{REMARKSLBL}{FIELDTYPEND} { adif_field = REMARKS; adif_field_len = atoi(yytext + 9); /* TODO: optional data type */ BEGIN(field); } "<"{NAMELBL}{FIELDTYPEND} { adif_field = NAME; adif_field_len = atoi(yytext + 6); /* TODO: optional data type */ BEGIN(field); } "<"{QTHLBL}{FIELDTYPEND} { adif_field = QTH; adif_field_len = atoi(yytext + 5); /* TODO: optional data type */ BEGIN(field); } "<"{LOCATORLBL}{FIELDTYPEND} { adif_field = LOCATOR; adif_field_len = atoi(yytext + 12); /* TODO: optional data type */ BEGIN(field); } } [^<]*/< { gchar *qfield; if (adif_field < QSO_FIELDS) { if (q[adif_field]) /* duplicate ? */ g_free(q[adif_field]); if (adif_field == DATE) { struct tm timestruct; gchar sdate[16]; if (adif_field_len != 8) { /* bail out? */ } sscanf(yytext, "%4d%2d%2d", ×truct.tm_year, ×truct.tm_mon, ×truct.tm_mday); timestruct.tm_year -= 1900; timestruct.tm_mon--; strftime (sdate, 16, "%d %b %Y", ×truct); qfield = g_strdup(sdate); } else { qfield = (gchar *)g_malloc(adif_field_len+1); strncpy(qfield, yytext, adif_field_len); qfield[adif_field_len] = '\0'; } q[adif_field] = qfield; } BEGIN(record); } ""|"" { /* End of Record */ if (adif_field != -1) { gint ret, i; /* fill in empty fields */ for (i = 0; i<> { return 0; } <> { fprintf(stderr, "Unterminated record\n" ); yyterminate(); } <*>[ \t\n\r]+ /* eat up whitespace */ <*>. /* printf( "Unrecognized character: %s\n", yytext ); */ %% /* * NB: this parser is not thread-safe, because of static variables */ static gint adif_qso_foreach(LOGDB *handle, gint (*fn)(LOGDB*, qso_t*, gpointer arg), gpointer arg) { adif_handle = handle; adif_fn = fn; adif_arg = arg; yyin = (FILE*)handle->priv; memset(q, 0, sizeof(q)); yylex(); return 0; } /* * open for read */ gint adif_open(LOGDB *handle) { FILE *fp; fp = fopen(handle->path, "r"); if (!fp) return -1; handle->priv = (gpointer)fp; handle->column_nr = adif_field_nr; memcpy(handle->column_fields, adif_fields, sizeof(adif_fields)); memcpy(handle->column_widths, adif_widths, sizeof(adif_widths)); return 0; } /* * open for write */ gint adif_create(LOGDB *handle) { FILE *fp; fp = fopen(handle->path, "w"); if (!fp) return -1; handle->priv = (gpointer)fp; /* write header */ fprintf(fp, "ADIF Export from " PACKAGE " Version " VERSION "\n" "Copyright (C) 2001-2002 Joop Stakenborg\n\n" "Internet: http://people.debian.org/~pa3aba/xlog.html\n\n" "ADIF Conversion written by Stephane Fillod F8CFE\n\n" "1.00\n" /* add conversion date here, etc. */ "\n" ); return 0; } void adif_close(LOGDB *handle) { FILE *fp = (FILE*)handle->priv; fclose(fp); } /* * 'field' is a constant defined by our scanner */ static const gchar *xlog2adif_name(gint fld) { switch (fld) { case DATE: return "QSO_DATE"; case GMT: return "TIME_ON"; case GMTEND: return "TIME_OFF"; case CALL: return "CALL"; case BAND: return "FREQ"; /* or BAND ? */ case MODE: return "MODE"; case POWER: return "TX_POWER"; case RST: return "RST_SENT"; case MYRST: return "RST_RCVD"; case QSLOUT: return "QSL_SENT"; case QSLIN: return "QSL_RCVD"; case REMARKS: return "COMMENT"; case NAME: return "NAME"; case QTH: return "QTH"; case LOCATOR: return "GRIDSQUARE"; case U1: return "U1"; /* we want to parse free-fields lateron */ case U2: return "U2"; default: return "UNKNOWN"; } } /* */ gint adif_qso_append(LOGDB *handle, const qso_t *q) { FILE *fp = (FILE *)handle->priv; int i; for (i = 0; i < handle->column_nr; i++) { gint qfield_len; gint fld = handle->column_fields[i]; gchar *qfield; if (!q[fld]) continue; qfield_len = strlen(q[fld]); if (qfield_len == 0) continue; /* reshape date */ if (fld == DATE && strlen(q[DATE]) == 11 && q[DATE][2]==' ' && q[DATE][6]==' ') { gchar date[16]; sprintf(date, "%s%02d%c%c", q[DATE]+7, scan_month(q[DATE]+3), q[DATE][0], q[DATE][1]); qfield = date; qfield_len = 8; } else { qfield = q[fld]; } fprintf(fp, "<%s:%d>%s ", xlog2adif_name(fld), qfield_len, qfield); } fprintf(fp, "\n\n"); return 0; }