D868UV: parse CSV files downloaded from amateurradio.digital.

This commit is contained in:
Serge Vakulenko 2018-11-23 20:29:02 -08:00
parent 08ae731218
commit 46203f940e
3 changed files with 150 additions and 42 deletions

View File

@ -2687,7 +2687,7 @@ static int d868uv_verify_config(radio_device_t *radio)
//
// Read and dump the callsign database.
//
static void read_csv(radio_device_t *radio)
static void dump_csv(radio_device_t *radio)
{
callsign_sizes_t sz = {0};
@ -2809,52 +2809,30 @@ static void d868uv_write_csv(radio_device_t *radio, FILE *csv)
// Need to rearrange the fields like:
// Radio ID, Name, City, Callsign, State, Country, Remarks
//
char line[256];
unsigned nbytes = 0;
char *radioid, *callsign, *name, *city, *state, *country, *remarks;
while (fgets(line, sizeof(line), csv)) {
trim_spaces(line, 255);
if (line[0] < '0' || line[0] > '9') {
// Eastern egg: when file contains a line "dump",
// read the callsign database from the radio
// and save to a file.
if (strcmp(line, "dump") == 0) {
free(data);
read_csv(radio);
return;
}
// Skip header.
continue;
}
if (csv_init(csv) < 0) {
free(data);
return;
}
while (csv_read(csv, &radioid, &callsign, &name, &city, &state, &country, &remarks)) {
//printf("%s,%s,%s,%s,%s,%s,%s\n", radioid, callsign, name, city, state, country, remarks);
// Replace non-ASCII characters with '?'.
char *p;
for (p=line; *p; p++) {
if (*p < ' ' || *p > '~')
*p = '?';
}
char *callsign = strchr(line, ','); if (! callsign) continue; *callsign++ = 0;
char *name = strchr(callsign, ','); if (! name) continue; *name++ = 0;
char *city = strchr(name, ','); if (! city) continue; *city++ = 0;
char *state = strchr(city, ','); if (! state) continue; *state++ = 0;
char *country = strchr(state, ','); if (! country) continue; *country++ = 0;
char *remarks = strchr(country, ','); if (! remarks) continue; *remarks++ = 0;
if ((p = strchr(remarks, ',')) != 0)
*p = 0;
callsign = trim_spaces(callsign, 16);
name = trim_spaces(name, 16);
city = trim_spaces(city, 15);
state = trim_spaces(state, 16);
country = trim_spaces(country, 16);
remarks = trim_spaces(remarks, 16);
//printf("%s,%s,%s,%s,%s,%s,%s\n", line, callsign, name, city, state, country, remarks);
unsigned id = strtoul(line, 0, 10);
unsigned id = strtoul(radioid, 0, 10);
if (id < 1 || id > 0xffffff) {
fprintf(stderr, "Bad id: %d\n", id);
fprintf(stderr, "Line: '%s,%s,%s,%s,%s,%s,%s'\n",
line, callsign, name, city, state, country, remarks);
radioid, callsign, name, city, state, country, remarks);
return;
}
// Eastern egg: when file contains id 1 with callsign 'dump',
// read the callsign database from the radio
// and save to a file.
if (id == 1 && strcmp(callsign, "dump") == 0) {
free(data);
dump_csv(radio);
return;
}
@ -2872,7 +2850,7 @@ static void d868uv_write_csv(radio_device_t *radio, FILE *csv)
m->offset = nbytes;
// Fill data.
p = &data[nbytes];
char *p = &data[nbytes];
// Radio ID.
*p++ = 0;

111
util.c
View File

@ -142,6 +142,22 @@ char *trim_spaces(char *line, int limit)
return line;
}
//
// Strip optional quotes around the string.
//
char *trim_quotes(char *line)
{
if (*line == '"') {
int last = strlen(line) - 1;
if (line[last] == '"') {
line[last] = 0;
return line+1;
}
}
return line;
}
//
// Delay in milliseconds.
//
@ -722,3 +738,98 @@ void print_tone(FILE *out, unsigned data)
break;
}
}
//
// Initialize CSV parser.
// Check header for correctness.
// Return negative on error.
//
static int csv_skip_field1;
int csv_init(FILE *csv)
{
char line[256];
if (!fgets(line, sizeof(line), csv))
return -1;
char *field1 = line;
char *field2 = strchr(field1, ','); if (! field2) return -1; *field2++ = 0;
char *field3 = strchr(field2, ','); if (! field3) return -1; *field3++ = 0;
char *field4 = strchr(field3, ','); if (! field4) return -1; *field4++ = 0;
field1 = trim_quotes(field1);
field2 = trim_quotes(field2);
field3 = trim_quotes(field3);
//printf("Line: %s,%s,%s\n", field1, field2, field3);
if (strcmp(field1, "Radio ID") == 0 &&
strcmp(field2, "Callsign") == 0) {
// Correct format:
// Radio ID,Callsign,Name,City,State,Country,Remarks
csv_skip_field1 = 0;
return 0;
}
if (strcmp(field2, "Radio ID") == 0 &&
strcmp(field3, "Callsign") == 0) {
// Correct format:
// "No.","Radio ID","Callsign","Name","City","State","Country","Remarks"
csv_skip_field1 = 1;
return 0;
}
//TODO
return -1;
}
//
// Parse one line of CSV file.
// Return 1 on success, 0 on EOF.
//
int csv_read(FILE *csv, char **radioid, char **callsign, char **name,
char **city, char **state, char **country, char **remarks)
{
static char line[256];
again:
if (!fgets(line, sizeof(line), csv))
return 0;
//printf("Line: '%s'\n", line);
// Replace non-ASCII characters with '?'.
char *p;
for (p=line; *p; p++) {
if ((uint8_t)*p > '~')
*p = '?';
}
if (csv_skip_field1) {
*radioid = strchr(line, ',');
if (! *radioid)
return 0;
*(*radioid)++ = 0;
} else
*radioid = line;
*callsign = strchr(*radioid, ','); if (! *callsign) return 0; *(*callsign)++ = 0;
*name = strchr(*callsign, ','); if (! *name) return 0; *(*name)++ = 0;
*city = strchr(*name, ','); if (! *city) return 0; *(*city)++ = 0;
*state = strchr(*city, ','); if (! *state) return 0; *(*state)++ = 0;
*country = strchr(*state, ','); if (! *country) return 0; *(*country)++ = 0;
*remarks = strchr(*country, ','); if (! *remarks) return 0; *(*remarks)++ = 0;
if ((p = strchr(*remarks, ',')) != 0)
*p = 0;
*radioid = trim_spaces(trim_quotes(*radioid), 16);
*callsign = trim_spaces(trim_quotes(*callsign), 16);
*name = trim_spaces(trim_quotes(*name), 16);
*city = trim_spaces(trim_quotes(*city), 15);
*state = trim_spaces(trim_quotes(*state), 16);
*country = trim_spaces(trim_quotes(*country), 16);
*remarks = trim_spaces(trim_quotes(*remarks), 16);
//printf("%s,%s,%s,%s,%s,%s,%s\n", *radioid, *callsign, *name, *city, *state, *country, *remarks);
if (**radioid < '1' || **radioid > '9')
goto again;
return 1;
}

19
util.h
View File

@ -49,6 +49,25 @@ void print_hex_addr_data(unsigned addr, const unsigned char *data, int len);
//
char *trim_spaces(char *line, int limit);
//
// Strip optional quotes around the string.
//
char *trim_quotes(char *line);
//
// Initialize CSV parser.
// Check header for correctness.
// Return -1 on error.
//
int csv_init(FILE *csv);
//
// Parse one line of CSV file.
// Return 1 on success, 0 on EOF.
//
int csv_read(FILE *csv, char **radioid, char **callsign, char **name,
char **city, char **state, char **country, char **remarks);
//
// DFU functions.
//