/* * Format parser * * Return program data line count */ int inhx32(const char *filename) { FILE *f1; char line[STRLEN]; unsigned int extended_address = 0, bb, ix; int n; unsigned char tt = TT_DATA, cc; unsigned short aaaa; void *root = NULL; inhx32_data *inhx32 = NULL; inhx32_count = 0; inhx32_pdata = NULL; if ((f1 = fopen(filename, "rb")) == NULL) { printf("%s: error: file open failed [%s] [%s]\n", __func__, filename, strerror(errno)); return -1; } while (tt != TT_EOF && fgets(line, STRLEN, f1) != NULL) { line[STRMAX] = '\0'; /* Strip CRLF */ n = strlen(line) - 1; while (n >= 0 && (line[n] == '\n' || line[n] == '\r')) line[n--] = '\0'; /* Validate line prefix and length */ if (line[0] != ':' || (strlen(line) & 1) == 0 || strlen(line) < 11) { printf("%s: warning: ignoring malformed line [%s] invalid format\n", __func__, line); continue; } /* Validate checksum */ cc = 0; for (n = 1; line[n]; n += 2) cc += inhx32_gethexb(&line[n]); if (cc != 0) { printf("%s: warning: ignoring malformed line [%s] invalid checksum [%02X]\n", __func__, line, cc); continue; } /* Determine number of data bytes in this line */ bb = inhx32_gethexb(&line[BB]); /* Validate line length */ if (strlen(line) != (2 * bb + 11)) { printf("%s: warning: ignoring malformed line [%s] invalid length [%zu]\n", __func__, line, strlen(line)); continue; } /* Determine data address for this line */ aaaa = (inhx32_gethexb(&line[AAAA]) << 8) | inhx32_gethexb(&line[AAAA + 2]); /* Determine record type */ tt = inhx32_gethexb(&line[TT]); switch (tt) { case TT_DATA: if (bb == 0) { printf("%s: warning: ignoring empty line [%s]\n", __func__, line); break; } /* Allocate new array entry for this line */ inhx32 = (inhx32_data *)calloc(1, sizeof(inhx32_data)); if (inhx32 == NULL) { printf("%s: fatal error: calloc failed\n", __func__); exit(EX_OSERR); /* Panic */ } /* Increment line counter */ inhx32_count++; /* Save address and word count */ inhx32->address = extended_address | aaaa; inhx32->nbytes = bb; /* Extract data */ ix = HHHH; for (n = 0; n < bb; n++) { inhx32->bytes[n] = inhx32_gethexb(&line[ix]); ix += 2; } #ifdef DEBUG printf("ADDRESS=0x%08X NBYTES=%d ", inhx32->address, inhx32->nbytes); for (n = 0; n < bb; n++) { printf("0x%02x ", inhx32->bytes[n]); } printf("\n"); #endif /* Find entry in tree */ if (tfind((void *)(inhx32), (void **)(&root), inhx32_compare) != NULL) { printf("%s: fatal error: duplicate address [%08X]\n", __func__, inhx32->address); exit(EX_SOFTWARE); /* Panic */ } /* Add entry into tree */ if (tsearch((void *)(inhx32), (void **)(&root), inhx32_compare) == NULL) { printf("%s: fatal error: tsearch failed\n", __func__); exit(EX_OSERR); /* Panic */ } break; case TT_EOF: break; case TT_EXTENDED_LINEAR_ADDRESS: if (aaaa == 0 && bb == 2) extended_address = (inhx32_gethexb(&line[HHHH]) << 24) | (inhx32_gethexb(&line[HHHH + 2]) << 16); else printf("%s: warning: ignoring invalid extended linear address [aaaa=%04X, bb=%d]\n", __func__, aaaa, bb); break; case TT_EXTENDED_SEGMENT_ADDRESS: printf("%s: warning: ignoring unhandled extended segment address\n", __func__); break; case TT_START_LINEAR_ADDRESS: printf("%s: warning: ignoring unhandled start linear address\n", __func__); break; case TT_START_SEGMENT_ADDRESS: printf("%s: warning: ignoring unhandled start segment address\n", __func__); break; default: printf("%s: warning: ignoring unknown record type [%d]\n", __func__, tt); break; } } fclose(f1); /* Return error if no program data lines found */ if (inhx32_count == 0) { printf("%s: error: file contains no data records [%s]\n", __func__, filename); return -5; } /* Create and populate program line data array from tree */ inhx32_pdata = (inhx32_data **)calloc(inhx32_count, sizeof(inhx32_data *)); if (inhx32_pdata == NULL) { printf("%s: fatal error: calloc failed\n", __func__); exit(EX_OSERR); /* Panic */ } inhx32_index = 0; twalk((void *)(root), inhx32_order); /* Free tree nodes */ for (n = 0; n < inhx32_count; n++) { if (tdelete((void *)(inhx32_pdata[n]), (void **)(&root), inhx32_compare) == NULL) { printf("%s: fatal error: tdelete failed\n", __func__); exit(EX_OSERR); /* Panic */ } } if (root != NULL) { printf("%s: fatal error: tree destroy failed\n", __func__); exit(EX_OSERR); /* Panic */ } /* Return the program data line count */ return inhx32_count; }
/* * Format parser * * Return program data line count */ uint32_t inhx32(struct k8048 *k, const char *filename, uint32_t alignment) { FILE *f1 = stdin; char line[STRLEN]; uint32_t extended_address = 0, bb, ix; uint8_t tt = TT_DATA, cc; uint16_t aaaa; void *root = NULL; inhx32_data *data = NULL; k->count = 0; k->pdata = NULL; if (strcmp(filename, "-") && (f1 = fopen(filename, "rb")) == NULL) { printf("%s: error: file open failed [%s] [%s]\n", __func__, filename, strerror(errno)); return 0; } #ifdef DEBUG if (k->debug >= 100) { printf("FILE [%s]\n", filename); } #endif while (tt != TT_EOF && fgets(line, STRLEN, f1) != NULL) { line[STRMAX] = '\0'; /* Strip CRLF */ int n = strlen(line) - 1; while (n >= 0 && (line[n] == '\n' || line[n] == '\r')) line[n--] = '\0'; /* Validate line prefix and length */ if (line[0] != ':' || (strlen(line) & 1) == 0 || strlen(line) < 11) { if (k->debug >= 10) { printf("%s: warning: ignoring malformed line [%s] invalid format\n", __func__, line); } continue; } /* Validate checksum */ cc = 0; for (n = 1; line[n]; n += 2) cc += inhx32_gethexb(&line[n]); if (cc != 0) { if (k->debug >= 10) { printf("%s: warning: ignoring malformed line [%s] invalid checksum [%02X]\n", __func__, line, cc); } continue; } /* Determine number of data bytes in this line */ bb = inhx32_gethexb(&line[BB]); /* Validate line length */ if (strlen(line) != (2 * bb + 11)) { if (k->debug >= 10) { printf("%s: warning: ignoring malformed line [%s] invalid length [%zu != %u] (BB=0x%02x)\n", __func__, line, strlen(line), 2 * bb + 11, bb); } continue; } /* Determine data address for this line */ aaaa = (inhx32_gethexb(&line[AAAA]) << 8) | inhx32_gethexb(&line[AAAA + 2]); /* Determine record type */ tt = inhx32_gethexb(&line[TT]); switch (tt) { case TT_DATA: if (bb == 0) { if (k->debug >= 10) { printf("%s: warning: ignoring empty line [%s]\n", __func__, line); } break; } if (bb % alignment) { if (k->debug >= 10) { printf("%s: warning: ignoring line with incomplete word [%s]\n", __func__, line); } break; } /* Allocate new array entry for this line */ data = (inhx32_data *)calloc(1, sizeof(inhx32_data)); if (data == NULL) { printf("%s: fatal error: calloc failed\n", __func__); io_exit(k, EX_OSERR); /* Panic */ } /* Increment line counter */ k->count++; /* Save address and word count */ data->address = extended_address | aaaa; data->nbytes = bb; /* Extract data */ ix = HHHH; for (n = 0; n < bb; n++) { data->bytes[n] = inhx32_gethexb(&line[ix]); ix += 2; } #ifdef DEBUG if (k->debug >= 100) { printf("AAAA=%04X BB=%02X ADDR=%06X >> %06X ", aaaa, bb, data->address, data->address >> 1); for (n = 0; n < bb; n++) { printf("%02X ", data->bytes[n]); } putchar('\n'); } #endif /* Find entry in tree */ if (tfind((void *)(data), (void **)(&root), inhx32_compare) != NULL) { printf("%s: fatal error: duplicate address [%08X]\n", __func__, data->address); io_exit(k, EX_SOFTWARE); /* Panic */ } /* Add entry into tree */ if (tsearch((void *)(data), (void **)(&root), inhx32_compare) == NULL) { printf("%s: fatal error: tsearch failed\n", __func__); io_exit(k, EX_OSERR); /* Panic */ } break; case TT_EOF: break; case TT_EXTENDED_LINEAR_ADDRESS: if (aaaa == 0 && bb == 2) { extended_address = (inhx32_gethexb(&line[HHHH]) << 24) | (inhx32_gethexb(&line[HHHH + 2]) << 16); #ifdef DEBUG if (k->debug >= 100) { printf("AAAA=%04X BB=%02X ADDR=%06X\n", aaaa, bb, extended_address); } #endif } else { printf("%s: warning: ignoring invalid extended linear address [aaaa=%04X, bb=%d]\n", __func__, aaaa, bb); } break; case TT_EXTENDED_SEGMENT_ADDRESS: printf("%s: warning: ignoring unhandled extended segment address\n", __func__); break; case TT_START_LINEAR_ADDRESS: printf("%s: warning: ignoring unhandled start linear address\n", __func__); break; case TT_START_SEGMENT_ADDRESS: printf("%s: warning: ignoring unhandled start segment address\n", __func__); break; default: printf("%s: warning: ignoring unknown record type [%d]\n", __func__, tt); break; } }