2019-02-15 02:37:03 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Load and parse GSBug templates and Nifty List Data.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
|
|
|
|
#include "defc.h"
|
|
|
|
|
|
|
|
/*!re2c
|
|
|
|
re2c:define:YYCTYPE = char;
|
|
|
|
re2c:define:YYCURSOR = cp;
|
|
|
|
re2c:yyfill:enable = 0;
|
|
|
|
eol = "\x00";
|
|
|
|
ws = [ \t\r\n];
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/* format
|
|
|
|
_START name
|
|
|
|
name [type [size]] *
|
|
|
|
_END
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
struct field {
|
|
|
|
char *name;
|
|
|
|
int type;
|
|
|
|
int count;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct record {
|
|
|
|
char *name;
|
|
|
|
int total_size; /* total size */
|
|
|
|
int field_count; /* # of fields */
|
|
|
|
int field_alloc;
|
|
|
|
struct field *fields;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct record *records = NULL;
|
|
|
|
static int record_count = 0;
|
|
|
|
static int record_alloc = 0;
|
|
|
|
|
|
|
|
static int record_compare(const void *a, const void *b) {
|
|
|
|
const struct record *aa = (const struct record *)a;
|
|
|
|
const struct record *bb = (const struct record *)b;
|
|
|
|
int rv;
|
|
|
|
rv = strcasecmp(aa->name, bb->name);
|
|
|
|
//if (rv == 0) return aa->total_size - bb->total_size;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 192 records in the standard file... */
|
|
|
|
static void add_record(struct record *r) {
|
|
|
|
if (record_count == record_alloc) {
|
|
|
|
size_t size = (record_alloc + 256) * sizeof(struct record);
|
|
|
|
void *tmp = realloc(records, size);
|
|
|
|
if (!tmp) return; /* oops */
|
|
|
|
records = tmp;
|
|
|
|
record_alloc += 256;
|
|
|
|
}
|
|
|
|
records[record_count++] = *r;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_record(struct record *r) {
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < r->field_count; ++i) {
|
|
|
|
free(r->fields[i].name);
|
|
|
|
}
|
|
|
|
free(r->name);
|
|
|
|
free(r->fields);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* average ~14 fields per record */
|
|
|
|
static void add_field(struct record *r, struct field *f) {
|
|
|
|
if (r->field_count == r->field_alloc) {
|
|
|
|
size_t size = (r->field_alloc + 32) * sizeof(struct field);
|
|
|
|
void *tmp = realloc(r->fields, size);
|
|
|
|
if (!tmp) return; /* oops */
|
|
|
|
r->fields = tmp;
|
|
|
|
r->field_alloc += 32;
|
|
|
|
}
|
|
|
|
r->fields[r->field_count++] = *f;
|
|
|
|
r->total_size += f->type * f->count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 0 - no field, 1 - ok, -1 - warning */
|
|
|
|
static int parse_field(const char *cp, struct field *f) {
|
|
|
|
const char *start;
|
|
|
|
const char *end;
|
|
|
|
const char *YYMARKER = NULL;
|
2019-02-15 03:43:39 +00:00
|
|
|
const char *YYCTXMARKER = NULL;
|
2019-02-15 02:37:03 +00:00
|
|
|
|
|
|
|
int type = 0;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
start = cp;
|
|
|
|
for(;;) {
|
|
|
|
/*!re2c
|
|
|
|
eol | ws { --cp; break; }
|
|
|
|
* { continue; }
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
end = cp;
|
|
|
|
if (start == end) return 0;
|
|
|
|
|
|
|
|
f->name = strndup(start, end - start);
|
|
|
|
f->type = 0;
|
|
|
|
f->count = 0;
|
|
|
|
|
|
|
|
while (isspace(*cp)) ++cp;
|
|
|
|
|
|
|
|
/* optional type */
|
|
|
|
/*!re2c
|
|
|
|
"BYTE" / (ws | eol) { type = 1; goto next; }
|
|
|
|
"WORD" / (ws | eol) { type = 2; goto next; }
|
|
|
|
"LONG" / (ws | eol) { type = 4; goto next; }
|
|
|
|
"" { type = 0; goto next; }
|
|
|
|
*/
|
|
|
|
|
|
|
|
next:
|
|
|
|
while (isspace(*cp)) ++cp;
|
|
|
|
if (type) {
|
|
|
|
count = 0;
|
|
|
|
while(isdigit(*cp)) {
|
|
|
|
count = count * 10 + *cp - '0';
|
|
|
|
++cp;
|
|
|
|
}
|
|
|
|
if (!count) count = 1;
|
|
|
|
}
|
|
|
|
while (isspace(*cp)) ++cp;
|
|
|
|
if (*cp != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
f->type = type;
|
|
|
|
f->count = count;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void debug_load_template(const char *path) {
|
|
|
|
FILE *f;
|
|
|
|
char buffer[1024];
|
|
|
|
int ok;
|
|
|
|
int in_struct = 0;
|
|
|
|
struct record record;
|
|
|
|
struct field field;
|
|
|
|
unsigned line = 0;
|
|
|
|
const char *YYMARKER = NULL;
|
2019-02-15 03:43:39 +00:00
|
|
|
const char *YYCTXMARKER = NULL;
|
2019-02-15 02:37:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
f = fopen(path, "r");
|
|
|
|
if (!f) {
|
|
|
|
fprintf(stderr, "Unable to load %s: %s\n", path, strerror(errno));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (line = 1;;++line) {
|
|
|
|
const char *start = NULL;
|
|
|
|
const char *end = NULL;
|
|
|
|
|
|
|
|
const char *cp = fgets(buffer, sizeof(buffer), f);
|
|
|
|
if (!cp) break;
|
|
|
|
|
|
|
|
|
|
|
|
/*!re2c
|
|
|
|
"" { goto _field; }
|
|
|
|
";" { continue; }
|
|
|
|
ws* eol { continue; }
|
|
|
|
"_END" / (ws | eol) { goto _end; }
|
|
|
|
"_START" / (ws | eol) { goto _start; }
|
|
|
|
*/
|
|
|
|
|
|
|
|
_field:
|
|
|
|
if (!in_struct) {
|
|
|
|
/* warn and create fake struct */
|
|
|
|
fprintf(stderr, "%s:%d: Missing _START.\n", path, line);
|
|
|
|
memset(&record, 0, sizeof(record));
|
|
|
|
in_struct = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&field, 0, sizeof(field));
|
|
|
|
ok = parse_field(cp, &field);
|
|
|
|
if (ok == 0) continue;
|
|
|
|
if (ok < 1) {
|
|
|
|
/* warn but add */
|
|
|
|
fprintf(stderr, "%s:%d: Bad field line: %s\n", path, line, buffer);
|
|
|
|
}
|
|
|
|
add_field(&record, &field);
|
|
|
|
continue;
|
|
|
|
|
|
|
|
_start:
|
|
|
|
if (in_struct) {
|
|
|
|
/* warn and close it */
|
|
|
|
if (in_struct > 0) add_record(&record);
|
|
|
|
if (in_struct < 0) free_record(&record);
|
|
|
|
}
|
|
|
|
memset(&record, 0, sizeof(record));
|
|
|
|
|
|
|
|
while (isspace(*cp)) ++cp;
|
|
|
|
start = cp;
|
|
|
|
for(;;) {
|
|
|
|
/*!re2c
|
|
|
|
eol | ws { --cp; break; }
|
|
|
|
* { continue; }
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
end = cp;
|
|
|
|
if (start == end) {
|
|
|
|
/* warning ... */
|
|
|
|
fprintf(stderr, "%s:%d: _START missing name.\n", path, line);
|
|
|
|
in_struct = -1;
|
|
|
|
} else {
|
|
|
|
in_struct = 1;
|
|
|
|
record.name = strndup(start, end - start);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (isspace(*cp)) ++cp;
|
|
|
|
if (*cp != 0) {
|
|
|
|
/* warning */
|
|
|
|
fprintf(stderr, "%s:%d: Bad _START line: %s\n", path, line, buffer);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
|
|
|
|
_end:
|
|
|
|
while (isspace(*cp)) ++cp;
|
|
|
|
if (*cp != 0) {
|
|
|
|
/* warning ... */
|
|
|
|
fprintf(stderr, "%s:%d: Bad _END line: %s\n", path, line, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in_struct) {
|
|
|
|
if (in_struct > 0) add_record(&record);
|
|
|
|
if (in_struct < 0) free_record(&record);
|
|
|
|
} else {
|
|
|
|
/* warning */
|
|
|
|
fprintf(stderr, "%s:%d: _END without _START.\n", path, line);
|
|
|
|
}
|
|
|
|
in_struct = 0;
|
|
|
|
memset(&record, 0, sizeof(record));
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (in_struct) {
|
|
|
|
/* warn & close */
|
|
|
|
fprintf(stderr, "%s:%d: Missing _END.\n", path, line);
|
|
|
|
if (in_struct > 0) add_record(&record);
|
|
|
|
if (in_struct < 0) free_record(&record);
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
qsort(records, record_count, sizeof(struct record), record_compare);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int record_search(const void *a, const void *b) {
|
|
|
|
const struct record *r = b;
|
|
|
|
return strcasecmp(a, r->name);
|
|
|
|
}
|
|
|
|
|
|
|
|
word32 debug_apply_template(word32 address, const char *name) {
|
|
|
|
/* 1 - lookup template */
|
|
|
|
struct record *r;
|
|
|
|
int i, j;
|
|
|
|
|
|
|
|
r = bsearch(name, records, record_count, sizeof(struct record), record_search);
|
|
|
|
if (r == NULL) {
|
|
|
|
fprintf(stderr, "Invalid template: %s\n", name);
|
|
|
|
return address;
|
|
|
|
}
|
|
|
|
if (r->total_size == 0) {
|
|
|
|
/* just print the fields */
|
|
|
|
for (i = 0; i < r->field_count; ++i) {
|
|
|
|
fputs(r->fields[i].name, stdout);
|
|
|
|
fputc('\n', stdout);
|
|
|
|
}
|
|
|
|
fputc('\n', stdout);
|
|
|
|
return address;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < r->field_count; ++i) {
|
|
|
|
struct field *f = &r->fields[i];
|
|
|
|
word32 value;
|
|
|
|
unsigned type = f->type;
|
|
|
|
printf("%-16s", f->name);
|
|
|
|
for (j = 0; j < f->count; ++j) {
|
|
|
|
switch(type) {
|
|
|
|
case 1:
|
|
|
|
value = get_memory_c(address, 0);
|
|
|
|
address += 1;
|
|
|
|
printf("%02x ", value);
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
value = get_memory16_c(address, 0);
|
|
|
|
address += 2;
|
|
|
|
printf("%04x ", value);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
value = get_memory16_c(address, 0);
|
|
|
|
address += 4;
|
|
|
|
printf("%08x ", value);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
address &= 0xffffff;
|
|
|
|
}
|
|
|
|
fputc('\n', stdout);
|
|
|
|
}
|
|
|
|
fputc('\n', stdout);
|
|
|
|
return address;
|
|
|
|
}
|