/* * libtilemdb - Utilities for debugging Z80 assembly programs * * Copyright (C) 2010 Benjamin Moody * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see * . */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include "tilemdb.h" /* Test if TEXT contains a correctly-formatted number WIDTH characters wide. If PAD = 0, number is padded on left with zeroes; if PAD = 1, number is padded on left with spaces; if PAD = -1, number is padded on right with spaces. */ static int match_num(const char* text, int width, int pad, int base, int* value) { int start, end; char* p; if ((int) strlen(text) < width) return 0; start = 0; while (start < width && text[start] == ' ') start++; end = width; while (end > start && text[end - 1] == ' ') end--; if (start == end) return 0; if (pad != 1 && start != 0) return 0; if (pad != -1 && end != width) return 0; if (pad != 0 && text[start] == '0' && start != end - 1) return 0; *value = strtol(text + start, &p, base); return (p == text + end); } /* Test if string exactly matches a printf-like format string. %d, %x match decimal and hex integers; %s matches any string of exactly that width. */ static int match_pattern(const char* text, const char* pattern, int* datasize, byte* data, ...) { int width, pad, value, *ip; char **sp; char *end; va_list ap; int failed = 0, lastdb = 0; va_start(ap, data); *datasize = 0; while (!failed && *pattern) { if (*pattern != '%') { if (*text == *pattern) text++; else failed = 1; pattern++; } else { pattern++; if (*pattern == '0') { pad = 0; pattern++; } else if (*pattern == '-') { pad = -1; pattern++; } else pad = 1; width = strtol(pattern, &end, 10); pattern = end; if (!width) width = strlen(text); else if (width > (int) strlen(text)) { failed = 1; break; } switch (*pattern) { case '%': if (*text == '%') text++; else failed = 1; break; case 'B': if (text[0] == ' ' && text[1] == ' ') { lastdb = 1; text += 2; break; } case 'b': if (match_num(text, width, pad, 16, &value) && !lastdb) { data[*datasize] = value; (*datasize)++; text += width; } else { failed = 1; } break; case 'd': ip = va_arg(ap, int *); if (match_num(text, width, pad, 10, ip)) { text += width; } else { failed = 1; } break; case 'x': ip = va_arg(ap, int *); if (match_num(text, width, pad, 16, ip)) { text += width; } else { failed = 1; } break; case 's': sp = va_arg(ap, char **); *sp = (char*) text; text += width; break; } pattern++; } } va_end(ap); return (!failed && *text == 0); } static int get_tasm_depth(const char* s) { if (!strncmp(s, "+++", 3)) return 4; else if (!strncmp(s, "++ ", 3)) return 3; else if (!strncmp(s, "+ ", 3)) return 2; else if (!strncmp(s, " ", 3)) return 1; else return 0; } static int parse_listing(const char* line, int* linenum, int* addr, int* depth, int* datasize, byte* data, char** text, int* isexp, const TilemListingLine* prevline) { int dummy; char *p, *q; /* tasm */ if (match_pattern(line, "%04d%3s%04x%1s%02B %02B %02B %02B %s", datasize, data, linenum, &p, addr, &q, text)) { *depth = get_tasm_depth(p); *isexp = 0; return 1; } if (match_pattern(line, "%04d%3s%04x%1s%02b %02b %02b ", datasize, data, linenum, &p, addr, &q) || match_pattern(line, "%04d%3s%04x%1s%02b %02b ", datasize, data, linenum, &p, addr, &q) || match_pattern(line, "%04d%3s%04x%1s%02b ", datasize, data, linenum, &p, addr, &q)) { *depth = get_tasm_depth(p); *text = NULL; *isexp = 0; return 1; } /* zmasm */ if (match_pattern(line, "%08x %02B %02B %02B %02B %02B %02B %4s %5d %s", datasize, data, addr, &p, linenum, text) && p[0] >= 'A' && p[0] <= 'Z') { *depth = p[0] - 'A' + 1; *isexp = (p[1] == '+'); return 1; } if (match_pattern(line, "%08x %02B %02B %02B %02B %02B %02B %4s %5d", datasize, data, addr, &p, linenum) && p[0] >= 'A' && p[0] <= 'Z') { *text = NULL; *depth = p[0] - 'A' + 1; *isexp = (p[1] == '+'); return 1; } if (match_pattern(line, " %4s %5d %s", datasize, data, &p, linenum, text) && p[0] >= 'A' && p[0] <= 'Z') { *addr = prevline->address + prevline->datasize; *depth = p[0] - 'A' + 1; *isexp = (p[1] == '+'); return 1; } if (match_pattern(line, " %08x %4s %5d %s", datasize, data, &dummy, &p, linenum, text) && p[0] >= 'A' && p[0] <= 'Z') { *addr = prevline->address + prevline->datasize; *depth = p[0] - 'A' + 1; *isexp = (p[1] == '+'); return 1; } /* spasm - old and new versions */ if (match_pattern(line, "%5d %04x: %02b %02b %02b %02b %s", datasize, data, linenum, addr, text) || match_pattern(line, "%5d %04x: %02b %02b %02b - %s", datasize, data, linenum, addr, text) || match_pattern(line, "%5d %04x: %02b %02b - - %s", datasize, data, linenum, addr, text) || match_pattern(line, "%5d %04x: %02b - - - %s", datasize, data, linenum, addr, text) || match_pattern(line, "%5d %04x: - - - - %s", datasize, data, linenum, addr, text) || match_pattern(line, "%5d %02x:%04x %02b %02b %02b %02b %s", datasize, data, linenum, &dummy, addr, text) || match_pattern(line, "%5d %02x:%04x %02b %02b %02b - %s", datasize, data, linenum, &dummy, addr, text) || match_pattern(line, "%5d %02x:%04x %02b %02b - - %s", datasize, data, linenum, &dummy, addr, text) || match_pattern(line, "%5d %02x:%04x %02b - - - %s", datasize, data, linenum, &dummy, addr, text) || match_pattern(line, "%5d %02x:%04x - - - - %s", datasize, data, linenum, &dummy, addr, text)) { *depth = *isexp = 0; return 1; } if (match_pattern(line, " %02b %02b %02b %02b %s", datasize, data, text) || match_pattern(line, " %02b %02b %02b - %s", datasize, data, text) || match_pattern(line, " %02b %02b - - %s", datasize, data, text) || match_pattern(line, " %02b - - - %s", datasize, data, text) || match_pattern(line, " %02b %02b %02b %02b %s", datasize, data, text) || match_pattern(line, " %02b %02b %02b - %s", datasize, data, text) || match_pattern(line, " %02b %02b - - %s", datasize, data, text) || match_pattern(line, " %02b - - - %s", datasize, data, text)) { *linenum = prevline->srclinenum; *addr = prevline->address + prevline->datasize; *depth = *isexp = 0; return 1; } /* tpasm or miniasm */ if (match_pattern(line, "%-5d %08x %02B %02B %02B %02B %02B %2s%s", datasize, data, linenum, addr, &p, text) || match_pattern(line, "%5d %08x %02B %02B %02B %02B %02B %2s%s", datasize, data, linenum, addr, &p, text)) { *depth = 0; *isexp = (*p == 'm' || *p == 'a'); return 1; } if (match_pattern(line, "%-5d %08x (%08x) %2s%s", datasize, data, linenum, addr, &dummy, &p, text) || match_pattern(line, "%5d %08x (%08x) %2s%s", datasize, data, linenum, addr, &dummy, &p, text)) { *depth = 0; *isexp = (*p == 'm' || *p == 'a'); return 1; } if (match_pattern(line, " %02B %02B %02B %02B %02B %1s", datasize, data, &p)) { *text = NULL; *linenum = prevline->srclinenum; *addr = prevline->address + prevline->datasize; *depth = 0; *isexp = (*p == 'm' || *p == 'a'); return 1; } if (match_pattern(line, " %02b %02b %02b %02b %02b", datasize, data) || match_pattern(line, " %02b %02b %02b %02b", datasize, data) || match_pattern(line, " %02b %02b %02b", datasize, data) || match_pattern(line, " %02b %02b", datasize, data) || match_pattern(line, " %02b", datasize, data)) { *text = NULL; *linenum = prevline->srclinenum; *addr = prevline->address + prevline->datasize; *depth = *isexp = 0; return 1; } printf("***\t%s\n", line); return 0; } int tilem_listing_read_file(TilemListing* lst, FILE* lstfile) { char buf[1024]; int linenum, addr, depth, isexp, datasize; byte data[TILEM_MAX_LINE_BYTES]; char *text; int i, status = 1; TilemListingLine prevline; prevline.text = NULL; prevline.srclinenum = 0; prevline.address = 0xffffffff; prevline.depth = 0; prevline.datasize = 0; while (fgets(buf, sizeof(buf), lstfile)) { i = strlen(buf); while (i > 0 && (buf[i - 1] == '\r' || buf[i - 1] == '\n')) i--; buf[i] = 0; if (parse_listing(buf, &linenum, &addr, &depth, &datasize, data, &text, &isexp, &prevline)) { if (linenum) status = 0; tilem_listing_append_line(lst, linenum, addr, depth, datasize, data, text, isexp); prevline = lst->lines[lst->nlines - 1]; } } return status; }