/* * migrate_tables.c - read OK1RR country tables * and create a usable file for xlog * * Copyright (C) 2004 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. */ /* Compile with: gcc -Wall `pkg-config glib-2.0 --cflags` -o migrate_tables \ migrate_tables.c `pkg-config glib-2.0 --libs`*/ #include #include #include #include #define MAXLINE 600 /* split a comma seperated list into chunks and add a string to every chunck */ static gchar * merge_remainder (gchar *l, gchar *a) { gchar **split, *result = g_strdup (""); gint i = 0; split = g_strsplit (l, ",", -1); for (;;) { if (!split[i] || strlen(split[i]) == 0) break; result = g_strdup_printf ("%s%s%s,", result, split[i], a); i++; } g_strfreev (split); return (result); } /* create a list of prefixes from a string containing square brackets * * V[A-D] produces VA,VB,VC,VD. *s points to V, *p to [ * V[XYZ] produces VZ,VY,VZ. *s points to V, *p to [ * * if there is a remainder, it is added to the list * V[A-D]0 will result in VA0,VB0,VC0,VD0 */ static gchar * create_list (gchar *s, gchar *p) { gchar *left, *list, *final, c, saved; list = g_strdup(""); *p = '\0'; left = g_strdup (s); p++; while (*p != ']') /* corresponding ']' */ { if (*p == '-') /* a range is included */ { p++; for (c = saved + 1; c <= *p; c++) list = g_strdup_printf ("%s%s%c,", list, left, c); } else { list = g_strdup_printf ("%s%s%c,", list, left, *p); } saved = *p; p++; } *p='\0'; /* remainder */ p++; if (strlen (p) > 0 && strlen (p) < 5) /* at least 4 characters, no range */ final = merge_remainder (list, p); else final = g_strdup (list); g_free (list); g_free (left); return (final); } /* transform a string like OP# to OP0,OP1,...OP9 */ static gchar * create_numbers (gchar *s, gchar *p) { gchar *left, *list, **spl; gint i, j; list = g_strdup(""); *p = '\0'; left = g_strdup (s); p++; for (i = 0; i < 10; i++) { list = g_strdup_printf ("%s%s%d%s,", list, left, i, p); } if (g_strrstr (list, "#")) /* in case we have two ## */ { spl = g_strsplit (list, ",", -1); list = g_strdup (""); for (i = 0; ; i++) { if (!spl[i] || strlen(spl[i]) == 0) break; p = g_strrstr (spl[i], "#"); *p = '\0'; left = g_strdup (spl[i]); p++; for (j = 0; j < 10; j++) { list = g_strdup_printf ("%s%s%d%s,", list, left, j, p); } } g_strfreev (spl); } g_free (left); return (list); } /* transform a string like O?3A to OA3A,OB3A,...OZ3A, * if '?' is the last character remove it */ static gchar * create_chars (gchar *s, gchar *p) { gchar *left, *list; gint i; list = g_strdup(""); *p = '\0'; left = g_strdup (s); p++; if (strlen (p) > 0) for (i = 'A'; i <= 'Z'; i++) list = g_strdup_printf ("%s%s%c%s,", list, left, i, p); else list = g_strdup_printf ("%s,", left); g_free (left); return (list); } /* create_list for a comma separated list of strings */ static gchar * expand_list (gchar *l) { gchar **spl, *p, *list, *exp; gint i; exp = g_strdup (""); spl = g_strsplit (l, ",", -1); for (i = 0; ; i++) { if (!spl[i] || strlen (spl[i]) == 0) break; if ((p = g_strrstr (spl[i], "["))) { list = create_list (spl[i], p); exp = g_strdup_printf ("%s%s", exp, list); g_free (list); } else if ((p = g_strrstr (spl[i], "#"))) { list = create_numbers (spl[i], p); exp = g_strdup_printf ("%s%s", exp, list); g_free (list); } else if ((p = g_strrstr (spl[i], "?"))) { list = create_chars (spl[i], p); exp = g_strdup_printf ("%s%s", exp, list); g_free (list); } } g_strfreev (spl); return (exp); } /* check for occurence of a special character in a string and act accordingly */ static gchar * xlog_list (gchar *str) { gchar *i, *list; /* * some example strings: * * VE V[A-G] VO[3-9] V[A-DFG]0 O[FGI]0 U[VWZ]0A U[VWZ]9[A-B] * up to 3 levels of brackets are allowed: R[A-Z]0[E-G][W-Z]% */ if ((i = g_strrstr (str, "["))) /* last occurence of '[' */ { list = create_list (str, i); if (g_strrstr (list, "[")) { str = g_strdup (list); list = expand_list (str); g_free (str); } if (g_strrstr (list, "[")) { str = g_strdup (list); list = expand_list (str); g_free (str); } if (g_strrstr (list, "#")) { str = g_strdup (list); list = expand_list (str); g_free (str); } if (g_strrstr (list, "?")) { str = g_strdup (list); list = expand_list (str); g_free (str); } if (g_strrstr (list, "?")) { str = g_strdup (list); list = expand_list (str); g_free (str); } } else if ((i = g_strrstr (str, "#"))) list = create_numbers (str, i); else if ((i = g_strrstr (str, "?"))) list = create_chars (str, i); else if ((i = g_strrstr (str, "="))) list = g_strdup_printf("%s,", i + 1); else list = g_strdup_printf ("%s,", str); return (list); } /* make a comma separated list of zones, do some cleanups */ static gchar * convert_zone (gchar *z) { gchar *i, *list, **s; gint j, k; if (g_strrstr (z, ",")) { s = g_strsplit (z, ",", -1); list = g_strdup (""); for (k = 0; ; k++) { if (!s[k] || strlen(s[k]) == 0) break; if ((i = g_strrstr (s[k], "-"))) { for (j = (i - 1)[0]; j <= (i + 1)[0]; j++) list = g_strdup_printf ("%s%d,", list, j - 48); } else list = g_strdup_printf ("%s%s,", list, s[k]); } g_strfreev (s); } else if ((i = g_strrstr (z, "-"))) { /* convert range */ list = g_strdup (""); for (j = (i - 1)[0]; j <= (i + 1)[0]; j++) list = g_strdup_printf ("%s%d,", list, j - 48); } else list = g_strdup_printf ("%d", atoi(z)); /* removes trailing '0' */ return list; } static gchar * my_strreplace(const char *str, const char *delimiter, const char *replacement) { gchar **split; gchar *ret; g_return_val_if_fail (str != NULL, NULL); g_return_val_if_fail (delimiter != NULL, NULL); g_return_val_if_fail (replacement != NULL, NULL); split = g_strsplit (str, delimiter, 0); ret = g_strjoinv (replacement, split); g_strfreev (split); return ret; } /* convert the collected country data to the format used by xlog, example input * for a country and a area with field numbers: * * 0 1 2 3 4 5 6 7 8 9 10 * VE V[A-G] VO C[F-K] C[Y-Z] V[X-Y] X[J-O] |Canada|Na|+4|47.0N|65.30W|2-5,9|1-5|1|| * 0 1 2 3 4 5 6 7 8 9 10 * VO1 VO[3-9] |Canada, Newfoundland (NF)|Na|+3.5|47.57N|52.72W|09|05||R|=1 */ gint makecountrydata (void) { gchar buf[256], *cty_location, *table_location; gchar *p, *l, *f, *cq, *itu; gint ichar = 0, dxccitem = 0, ipfx = 0, ch = 0; gint lat, lon, cont, tz; FILE *fp, *fq; gchar **split, **pfxsplit; cty_location = g_strconcat ("countries.txt", NULL); table_location = g_strconcat ("dxcctable.txt", NULL); if ((fp = fopen (cty_location, "r")) == NULL) { g_free (cty_location); return (1); } if ((fq = fopen (table_location, "w")) == NULL) { g_free (table_location); return (1); } while (!feof (fp)) { while (ch != 13) /* at end of line */ { ch = fgetc (fp); if (ch == EOF) break; buf[ichar++] = ch; } buf[ichar] = '\0'; ichar = 0; ch = 0; f = g_strdup (""); if (strlen (buf) > 20) { /* split up the line */ split = g_strsplit (buf, "|", 11); for (dxccitem = 0; dxccitem < 11; dxccitem++) g_strstrip (split[dxccitem]); /* convert prefixes to a comma separated list */ pfxsplit = g_strsplit (split[0], " ", 0); for (ipfx = 0; ; ipfx++) { if (!pfxsplit[ipfx] || strlen(pfxsplit[ipfx]) == 0) break; l = xlog_list (pfxsplit[ipfx]); f = g_strdup_printf ("%s%s", l, f); g_free (l); } g_strfreev (pfxsplit); /* add some spaces when possible, so the countrylabel will display nicely */ if (g_strrstr(split[1], "..")) split[1] = my_strreplace (split[1], "..", " "); if (g_strrstr(split[1], ",")) split[1] = my_strreplace (split[1], ",", ", "); /* convert continent to an integer */ if (g_ascii_strcasecmp (split[2], "Eu") == 0) cont = 1; else if (g_ascii_strcasecmp (split[2], "Na") == 0) cont = 2; else if (g_ascii_strcasecmp (split[2], "Sa") == 0) cont = 3; else if (g_ascii_strcasecmp (split[2], "As") == 0) cont = 4; else if (g_ascii_strcasecmp (split[2], "Af") == 0) cont = 5; else if (g_ascii_strcasecmp (split[2], "Oc") == 0) cont = 6; else if (g_ascii_strcasecmp (split[2], "An") == 0) cont = 7; else cont = 0; /* convert timezone */ tz = atof (split[3]) * 10; /* convert latitude and longitude location to an integer with +/- sign */ if ((p = g_strrstr(split[4], "N"))) { *p = '\0'; lat = atof (split[4]) * 100; } else if ((p = g_strrstr(split[4], "S"))) { *p = '\0'; lat = -1 * atof (split[4]) * 100; } if ((p = g_strrstr(split[5], "E"))) { *p = '\0'; lon = -1 * atof (split[5]) * 100; } else if ((p = g_strrstr(split[5], "W"))) { *p = '\0'; lon = atof (split[5]) * 100; } /* convert zones */ cq = convert_zone (split[6]); itu = convert_zone (split[7]); fprintf(fq, "%s|%s|%d|%d|%d|%d|%s|%s|%s|%s|%s\n", f, split[1], cont, tz, lat, lon, cq, itu, split[8], split[9], split[10]); g_free (f); g_free (cq); g_free (itu); g_strfreev (split); } } fclose (fp); fclose (fq); g_free (cty_location); g_free (table_location); return (0); } int main (int arg, char *argv[]) { FILE *countries, *areas, *resolution, *deleted, *now; char buf[256]; gchar **c, **a, **r; char cstr[10], astr[10], dstr[10]; int maxcountries = 0, maxareas = 0, maxresolution = 0; int savedcountries; int i, j, k, l; c = g_new0 (gchar *, 1000); a = g_new0 (gchar *, 5000); r = g_new0 (gchar *, 2000); /* the main DXCC table */ if ((countries = fopen ("Country.tab", "r")) == NULL) { printf ("Can not find Country.tab in the current directory\n"); exit (1); } while (!feof (countries)) { if (fgets (buf, 256, countries) == NULL) break; else { c[maxcountries] = g_strdup(buf); maxcountries++; } } fclose (countries); savedcountries = maxcountries; printf ("%d lines in Country.tab read\n", maxcountries); /* the detailed DXCC area table */ if ((areas = fopen ("AreaOK1RR.tbl", "r")) == NULL) { printf ("Can not find AreaOK1RR.tbl in the current directory\n"); exit (1); } while (!feof (areas)) { if (fgets (buf, 256, areas) == NULL) break; else { a[maxareas] = g_strdup (buf); maxareas++; } } fclose (areas); printf ("%d lines in AreaOK1RR.tbl read\n", maxareas); /* listing of ambiguous calls */ if ((resolution = fopen ("CallResolution.tbl", "r")) == NULL) { printf ("Can not find CallResolution.tbl in the current directory\n"); exit (1); } while (!feof (resolution)) { if (fgets (buf, 256, resolution) == NULL) break; else { r[maxresolution] = g_strdup (buf); maxresolution++; } } fclose (resolution); printf ("%d lines in CallResolution.tbl read\n", maxresolution); /* the DXCC Deleted Countries table */ if ((deleted = fopen ("CountryDel.tab", "r")) == NULL) { printf ("Can not find CountryDel.tab in the current directory\n"); exit (1); } while (!feof (deleted)) { if (fgets (buf, 256, deleted) == NULL) break; else { c[maxcountries] = g_strdup(buf); maxcountries++; } } fclose (deleted); printf ("%d lines in CountryDel.tab read\n", maxcountries - savedcountries); /* Following tables to be implemented: CountryWAE.tab (the WAE table - differences WAE <-> DXCC) CallWAE.tbl (listing of ambiguous WAE calls) Exceptions.tbl (exceptions ignored in slashed calls) */ if ((now = fopen ("countries.txt", "w")) == NULL) { printf ("Can not create countries.txt table\n"); exit (1); } printf ("Please wait...\n"); /* create a country table which is sorted by country number (last field) */ for (i = 0; i < MAXLINE; i++) { sprintf (cstr, "|%d||", i); sprintf (astr, "=%d\r", i); sprintf (dstr, "|%d|D|", i); for (j = 0; j < maxcountries; j++) { if (strstr (c[j], cstr) || strstr (c[j], dstr)) { fprintf (now, "%s", c[j]); for (k = 0; k < maxareas; k++) if (strstr (a[k], astr)) fprintf (now, "%s", a[k]); for (l = 0; l < maxresolution; l++) if (strstr (r[l], astr)) fprintf (now, "%s", r[l]); } } } fclose (now); printf ("First pass.... countries.txt created\n"); printf ("Please wait...\n"); makecountrydata (); printf ("Second pass.... dxcctable.txt created\n"); printf ("Ready!\n"); exit(0); }