1 /*
2  * Tlf - contest logging program for amateur radio operators
3  * Copyright (C) 2001-2002-2003 Rein Couperus <pa0rct@amsat.org>
4  *               2012-2013           Thomas Beierlein <tb@forth-ev.de>
5  *               2017                Ervin Hegedus <airween@gmail.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21 /* ------------------------------------------------------------
22  *   cabrillo utils file
23  *
24  *--------------------------------------------------------------*/
25 
26 
27 #ifndef _GNU_SOURCE
28 #define _GNU_SOURCE
29 #endif
30 
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 
35 #include "cabrillo_utils.h"
36 
37 
38 /* conversion table between tag name in format file and internal tag */
39 struct tag_conv tag_tbl[] = {
40     { "FREQ",	FREQ 	},
41     { "MODE",	MODE 	},
42     { "DATE",	DATE 	},
43     { "TIME", 	TIME 	},
44     { "MYCALL", MYCALL 	},
45     { "HISCALL", HISCALL },
46     { "RST_S",  RST_S 	},
47     { "RST_R",  RST_R 	},
48     { "EXC_S",  EXC_S 	},
49     { "EXCH",   EXCH 	},
50     { "EXC1",	EXC1	},
51     { "EXC2",	EXC2	},
52     { "EXC3",	EXC3	},
53     { "EXC4",	EXC4	},
54     { "TX",     TX 	},
55     { "QTCRCALL", QTCRCALL },
56     { "QTCHEAD",  QTCHEAD  },
57     { "QTCSCALL", QTCSCALL },
58     { "QTC",	QTC }
59 };
60 
61 
62 /* translate item name into a tag */
translate_item_name(char * name)63 enum tag_t translate_item_name(char *name) {
64     int i;
65 
66     /* lookup name in tag list */
67     for (i = 0; i < sizeof(tag_tbl) / sizeof(struct tag_conv); i++) {
68 	if (strcmp(tag_tbl[i].item_name, name) == 0) {
69 	    /* and return corresponding tab */
70 	    return tag_tbl[i].tag;
71 	}
72     }
73 
74     /* if not found return NO_ITEM tag */
75     return NO_ITEM;
76 }
77 
78 /** free cabrillo format description */
free_cabfmt(struct cabrillo_desc * desc)79 void free_cabfmt(struct cabrillo_desc *desc) {
80     int i;
81 
82     if (desc == NULL)
83 	return;
84 
85     if (desc->item_array) {
86 	for (i = 0; i < desc->item_array->len; i++) {
87 	    g_free(g_ptr_array_index(desc->item_array, i));
88 	}
89 
90 	g_ptr_array_free(desc->item_array, TRUE);
91     }
92 
93     if (desc->qtc_item_array) {
94 	for (i = 0; i < desc->qtc_item_array->len; i++) {
95 	    g_free(g_ptr_array_index(desc->qtc_item_array, i));
96 	}
97 
98 	g_ptr_array_free(desc->qtc_item_array, TRUE);
99     }
100 
101     if (desc->name) g_free(desc->name);
102     g_free(desc);
103 }
104 
105 
106 /* parse item describing one entry
107  *
108  * has to be in following format: item,length
109  *   - item to print (date, time, call, ...)
110  *   - max length
111  */
parse_line_entry(char * line_entry)112 struct line_item *parse_line_entry(char *line_entry) {
113     struct line_item *item;
114     gchar **parts;
115     enum tag_t tag;
116 
117     item = g_malloc(sizeof(struct line_item));
118     parts = g_strsplit(line_entry, ",", 2);
119 
120     if (g_strv_length(parts) == 2) {
121 	tag = translate_item_name(parts[0]);
122 
123 	item->tag = tag;
124 	item->len = atoi(parts[1]);
125     } else {
126 	/* type is NO_ITEM */
127 	item->tag = NO_ITEM;
128     }
129 
130     g_strfreev(parts);
131 
132     return item;
133 }
134 
135 /** read cabrillo format description
136  *
137  * Try to read cabrillo format description for given format from
138  * file and return a describing structure.
139  *
140  * \param filename	File to read description from
141  * \param format	Name of the format to read
142  * \return 		Pointer to a structure describing the format
143  * 			(NULL if file or format not found or not readable)
144  */
read_cabrillo_format(char * filename,char * format)145 struct cabrillo_desc *read_cabrillo_format(char *filename, char *format) {
146     GKeyFile *keyfile;
147     GError *error = NULL;
148     gchar **list;
149     gsize nrstrings;
150     struct cabrillo_desc *cabdesc;
151     int i;
152 
153     keyfile = g_key_file_new();
154 
155     if (!g_key_file_load_from_file(keyfile, filename,
156 				   G_KEY_FILE_NONE, &error)) {
157 	g_error_free(error);
158 
159 	/* file does not exist or is wrongly formatted */
160 	g_key_file_free(keyfile);
161 	return NULL;
162     }
163 
164     /* check if 'format' defined in file */
165     if (g_key_file_has_group(keyfile, format) == FALSE) {
166 
167 	/* group not found */
168 	g_key_file_free(keyfile);
169 	return NULL;
170     }
171 
172     /* read needed keys */
173     list = g_key_file_get_string_list(keyfile, format,
174 				      "QSO", &nrstrings, &error);
175 
176     if (error && error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
177 
178 	/* if not found -> stop processing as that key is mandatory */
179 	g_error_free(error);
180 	g_key_file_free(keyfile);
181 	return NULL;
182     }
183 
184     /* construct new format descriptor and fill it in */
185     cabdesc = g_new(struct cabrillo_desc, 1);
186     cabdesc->name = g_strdup(format);
187     cabdesc->item_array = g_ptr_array_new();
188     cabdesc->item_count = nrstrings;
189     cabdesc->qtc_item_array = NULL;
190     cabdesc->qtc_item_count = 0;
191 
192     for (i = 0; i < nrstrings; i++) {
193 	struct line_item *item;
194 
195 	item = parse_line_entry(list[i]);
196 	if (item) {
197 	    /* add only well formatted entries */
198 	    g_ptr_array_add(cabdesc->item_array, item);
199 	}
200     }
201 
202     if (cabdesc->item_array->len != nrstrings) {
203 	/* not all entries are ok -> stop processing */
204 	free_cabfmt(cabdesc);
205 	g_strfreev(list);
206 	g_key_file_free(keyfile);
207 	return NULL;
208     }
209 
210     g_strfreev(list);
211 
212     /* read needed QTC keys */
213     list = g_key_file_get_string_list(keyfile, format,
214 				      "QTC", &nrstrings, &error);
215 
216     if (error && error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
217 
218 	/* if not found -> stop processing as that key is optional */
219 	g_error_free(error);
220 
221     } else {
222 
223 	/* construct new format descriptor and fill it in */
224 	cabdesc->qtc_item_array = g_ptr_array_new();
225 	cabdesc->qtc_item_count = nrstrings;
226 
227 	for (i = 0; i < nrstrings; i++) {
228 	    struct line_item *item;
229 
230 	    item = parse_line_entry(list[i]);
231 	    if (item) {
232 		/* add only well formatted entries */
233 		g_ptr_array_add(cabdesc->qtc_item_array, item);
234 	    }
235 	}
236 
237 	if (cabdesc->qtc_item_array->len != nrstrings) {
238 	    /* not all entries are ok -> stop processing */
239 	    free_cabfmt(cabdesc);
240 	    g_strfreev(list);
241 	    g_key_file_free(keyfile);
242 	    return NULL;
243 	}
244     }
245 
246     g_strfreev(list);
247 
248     /* possible further entries in format specification may contain information
249      * about allowed items for different categories:
250      * CONTEST, CATEGORY-OPERATOR, CATEGORY_TRANSMITTER, CATEGORY-POWER,
251      * CATEGORY-ASSISTED, CATEGORY-BAND, CATEGORY-MODE, C-STATION, C-TIME.
252      * C-OVERLAY
253      */
254 
255     g_key_file_free(keyfile);
256 
257     /* return parsed cabrillo format description */
258     return cabdesc;
259 }
260