/* * File: genop.c * * Program to generate tables for handling assembler instructions * and generating code in IMP80 compiler * * Bob Eager August 2002 * */ /* * Format of opcode information tables; these are indexed by the arbitrary * opcode values assigned in the symbol definitions file, which in turn are * simply the order of appearance in the original opcode information file. * * opcinfo1: each entry is a 32-bit value, as follows (not to scale): * * 1 bit 2 bits 5 bits 8 bits 8 bits 8 bits * +------------------------------------------------------------+ * | Jump | Spare | Variant | Operand 1 | Operand 2 | Operand 3 | * | flag | | code | code | code | code | * +------------------------------------------------------------+ * * opcinfo2: each entry is a 32-bit value, as follows (not to scale); * the opcode size is expressed in bytes, with unused fields * set to zero * * 8 bits 8 bits 8 bits 8 bits * +------------------------------------------------------------+ * | Opcode | Opcode | Opcode | Opcode | * | byte 1 | byte 2 | byte 3 | size | * +------------------------------------------------------------+ * */ /* * Compile time options * * Define exactly one target language name to be 1; all the rest should be 0. * */ #define C 1 /* C language */ #define IMP 0 /* IMP80 language */ #ifdef __IBMC__ #pragma strings(readonly) #endif #include #include #include #include #include #include #ifndef LIBHASSTRUPR char *strupr(char *inplace) { int c; char *orig = inplace; while ((c = *inplace) != '\0') { if (isalpha(c) && islower(c)) c = toupper(c); *inplace++ = c; } return(orig); } #endif #define FALSE 0 #define TRUE 1 #define MAXCC 132 /* Max length of line buffer */ #define MAXMNEM 8 /* Max length of a mnemonic */ #define MAXOP 600 /* Max number of opcodes */ #define MAXRAND 3 /* Max number of operands */ /* Type definitions */ typedef void VOID, *PVOID; typedef int BOOL, *PBOOL; typedef char CHAR, *PCHAR; typedef unsigned char UCHAR, *PUCHAR; typedef int INT, *PINT; typedef unsigned int UINT, *PUINT; typedef long LONG, *PLONG; typedef unsigned long ULONG, *PULONG; /* Forward references */ static BOOL do_instr(VOID); static BOOL do_jump(VOID); static BOOL do_mnem(VOID); static BOOL do_operand(INT); static VOID do_tables(PUCHAR, PUCHAR, PUCHAR); static BOOL do_variant(VOID); static VOID error(PUCHAR, ...); static FILE *openio(PUCHAR, PUCHAR); static VOID readline(VOID); static VOID translate(PUCHAR, PUCHAR, PUCHAR); static VOID usage(VOID); static VOID warn(PUCHAR, ...); /* Local data */ static UCHAR cc[MAXCC]; /* Input line buffer */ static INT errors = 0; /* Count of errors */ static FILE *infp; /* File pointer for input file */ static UINT instr[MAXOP]; /* Opcode information */ static UINT jump[MAXOP]; /* Jump flags */ static INT line = 0; /* Input line number */ static FILE *listfp; /* File pointer for listing file*/ static UCHAR mnem[MAXOP][MAXMNEM+1]; /* Opcode mnemonic text */ static INT num = 0; /* Number of opcodes */ static UINT operand[MAXRAND][MAXOP]; /* Operand type */ static FILE *opfp; /* File pointer for opcode defns*/ static PUCHAR progname; /* Program name */ static INT size[MAXOP]; /* Opcode size in bytes */ static FILE *tabfp; /* File pointer for table file */ static UINT variant[MAXOP]; /* Opcode variant flag */ static UCHAR xinstr[MAXCC]; /* Input opcode val temp string */ static UCHAR xjump[MAXCC]; /* Input jump flag temp string */ static UCHAR xmnem[MAXCC]; /* Input mnemonic temp string */ static UCHAR xoperand[MAXRAND][MAXCC]; /* Input operand temp strings */ static UCHAR xvariant[MAXCC];/* Input variant temp string */ /* Tables */ #define MAXMAC 13 static PUCHAR macros[MAXMAC] = { "JUMP(x)\t\t((opcinfo1[x] >> 31) & 0x01)", "OPB(x,n)\t((unsigned char) ((opcinfo2[x] >> (32-x*8)) & 0xff))", "OPB1(x)\t\t((unsigned char) ((opcinfo2[x] >> 24) & 0xff))", "OPB2(x)\t\t((unsigned char) ((opcinfo2[x] >> 16) & 0xff))", "OPB3(x)\t\t((unsigned char) ((opcinfo2[x] >> 8) & 0xff))", "OPSIZE(x)\t(opcinfo2[x] & 0xff)", "RAND1(x)\t((opcinfo1[x] >> 16) & 0xff)", "RAND2(x)\t((opcinfo1[x] >> 8) & 0xff)", "RAND3(x)\t(opcinfo1[x] & 0xff)", "REG8(x)\t\t(AL <= x && x <= BH)", "REG16(x)\t(AX <= x && x <= DI)", "REG32(x)\t(EAX <= x && x <= EDI)", "VARIANT(x)\t((opcinfo1[x] >> 24) & 0x1f)" }; typedef struct _RANDINFO { PUCHAR name; INT value; } RANDINFO; typedef struct _REGINFO { PUCHAR name; INT num; } REGINFO; #define MAXREGNAME 42 /* All register names */ #define MAXREGS 24 /* User-level registers */ /* Note that all register values below must correspond to the hardware encodings in the least significant three bits. In addition, the user-level registers must come first, MAXREGS and MAXREGNAME must reflect the table contents, and the REG8, REG16 and REG32 macros must also reflect the table contents. */ static REGINFO xregs[MAXREGNAME] = { { "AL", 0x00 }, { "CL", 0x01 }, { "DL", 0x02 }, { "BL", 0x03 }, { "AH", 0x04 }, { "CH", 0x05 }, { "DH", 0x06 }, { "BH", 0x07 }, { "AX", 0x08 }, { "CX", 0x09 }, { "DX", 0x0a }, { "BX", 0x0b }, { "SP", 0x0c }, { "BP", 0x0d }, { "SI", 0x0e }, { "DI", 0x0f }, { "EAX", 0x10 }, { "ECX", 0x11 }, { "EDX", 0x12 }, { "EBX", 0x13 }, { "ESP", 0x14 }, { "EBP", 0x15 }, { "ESI", 0x16 }, { "EDI", 0x17 }, /* Last user-level register */ { "CR0", 0x20 }, { "CR1", 0x21 }, { "CR2", 0x22 }, { "CR3", 0x23 }, { "CR4", 0x24 }, { "DR0", 0x30 }, { "DR1", 0x31 }, { "DR2", 0x32 }, { "DR3", 0x33 }, { "DR4", 0x34 }, { "DR5", 0x35 }, { "DR6", 0x36 }, { "DR7", 0x37 }, { "TR3", 0x43 }, { "TR4", 0x44 }, { "TR5", 0x45 }, { "TR6", 0x46 }, { "TR7", 0x47 } }; /* Operand types found in definition table */ #define MAXRANDTYPE 32 static PUCHAR operands[MAXRANDTYPE] = { "N", /* 0 - operand not permitted */ "r8", /* 1 - 8-bit register */ "r16", /* 2 - 16-bit register */ "r32", /* 3 - 32-bit register */ "s16", /* 4 - 16-bit segment register */ "cr", /* 5 - control register (CR0-7) */ "dr", /* 6 - debug register (DR0-7) */ "tr", /* 7 - test register (TR0-7) */ "rf", /* 8 - floating point register */ "rt", /* 9 - floating point top of stack */ "imm8", /* 10 - immediate 8-bit value */ "imm16", /* 11 - immediate 16-bit value */ "imm32", /* 12 - immediate 32-bit value */ "moffs8", /* 13 - 8-bit segment offset */ "moffs32", /* 14 - 32-bit segment offset */ "r/m8", /* 15 - 8-bit register/memory operand */ "r/m16", /* 16 - 16-bit register/memory operand */ "r/m32", /* 17 - 32-bit register/memory operand */ "r/m64", /* 18 - 64-bit register/memory operand */ "rel8", /* 19 - 8-bit relative offset */ "rel32", /* 20 - 32-bit relative offset */ "m8", /* 21 - 8-bit memory operand */ "m16", /* 22 - 16-bit memory operand */ "m32", /* 23 - 32-bit memory operand */ "m16:32", /* 24 - 48-bit far pointer */ "m16&32", /* 25 - 16 and 32 bit data pair */ "m64", /* 26 - 64-bit memory operand */ "ptr48", /* 27 - 48-bit memory operand (pointer) */ "m32real", /* 28 - 32-bit real memory operand */ "m64real", /* 29 - 64-bit real memory operand */ "m80real", /* 30 - 80-bit real memory operand */ "m80dec" /* 31 - 80-bit BCD memory operand */ }; /* Other operand types. The values assigned are actually the mod r/m values, with the register field set to zero. */ #define MAXOTHRAND 24 static RANDINFO othrands[MAXOTHRAND] = { /* Mod R/M */ { "i_eax", 0x00 }, /* 00 000 */ { "i_ecx", 0x01 }, /* 001 */ { "i_edx", 0x02 }, /* 010 */ { "i_ebx", 0x03 }, /* 011 */ { "sib", 0x04 }, /* 100 */ { "disp32", 0x05 }, /* 101 */ { "i_esi", 0x06 }, /* 110 */ { "i_edi", 0x07 }, /* 111 */ { "i_eax+disp8", 0x40 }, /* 01 000 */ { "i_ecx+disp8", 0x41 }, /* 001 */ { "i_edx+disp8", 0x42 }, /* 010 */ { "i_ebx+disp8", 0x43 }, /* 011 */ { "i_sib+disp8", 0x44 }, /* 100 */ { "i_ebp+disp8", 0x45 }, /* 101 */ { "i_esi+disp8", 0x46 }, /* 110 */ { "i_edi+disp8", 0x47 }, /* 111 */ { "i_eax+disp32", 0x80 }, /* 02 000 */ { "i_ecx+disp32", 0x81 }, /* 001 */ { "i_edx+disp32", 0x82 }, /* 010 */ { "i_ebx+disp32", 0x83 }, /* 011 */ { "i_sib+disp32", 0x84 }, /* 100 */ { "i_ebp+disp32", 0x85 }, /* 101 */ { "i_esi+disp32", 0x86 }, /* 110 */ { "i_edi+disp32", 0x87 } /* 111 */ }; /* Instruction variant types */ #define MAXVARIANT 16 static PUCHAR variants[MAXVARIANT] = { "/0", /* 0 - 0 in 'mod r/m' is part of instr */ "/1", /* 1 - 1 in 'mod r/m' is part of instr */ "/2", /* 2 - 2 in 'mod r/m' is part of instr */ "/3", /* 3 - 3 in 'mod r/m' is part of instr */ "/4", /* 4 - 4 in 'mod r/m' is part of instr */ "/5", /* 5 - 5 in 'mod r/m' is part of instr */ "/6", /* 6 - 6 in 'mod r/m' is part of instr */ "/7", /* 7 - 7 in 'mod r/m' is part of instr */ "S", /* 8 - simple instruction */ "/r", /* 9 - register in 'mod r/m' byte */ "+r8", /* 10 - add 8-bit register to opcode */ "+r32", /* 11 - add 32-bit register to opcode */ "+i", /* 12 - add FP register to opcode */ "/c", /* 13 - control register in 'mod r/m' */ "/d", /* 14 - debug register in 'mod r/m' */ "/t" /* 15 - test register in 'mod r/m' */ }; /* * Main entry point. Handles files, and basic processing loop. * */ INT main(INT argc, PUCHAR argv[]) { INT i; PUCHAR ptr; progname = argv[0]; ptr = strrchr(progname, '\\'); if(ptr != (PUCHAR) NULL) progname = ++ptr; for(i = 0; progname[i] != '\0'; i++) progname[i] = (UCHAR) tolower(progname[i]); if(argc != 5) usage(); infp = openio(argv[1], "r"); tabfp = openio(argv[2], "w"); opfp = openio(argv[3], "w"); listfp = openio(argv[4], "w"); /* Main input loop */ for(;;) { if(num >= MAXOP) error("too many opcodes"); readline(); if(cc[0] == '\0') break; /* Finished */ /* Strip comments */ ptr = strchr(cc, '!'); if(ptr != (unsigned char *) NULL) { *ptr-- = '\0'; while(strlen(cc) != 0 && *(ptr-1) == ' ') *--ptr = '\0'; } if(cc[0] == '\0') continue; /* Read and decompose line */ sscanf(cc, "%s %s %s %s %s %s %s", xmnem, xoperand[0], xoperand[1], xoperand[2], xvariant, xjump, xinstr); if(do_mnem() == FALSE) continue; if(do_operand(1) == FALSE) continue; if(do_operand(2) == FALSE) continue; if(do_operand(3) == FALSE) continue; if(do_variant() == FALSE) continue; if(do_jump() == FALSE) continue; if(do_instr() == FALSE) continue; num++; } fclose(infp); fprintf(stderr, "%s: %d opcodes read\n", progname, num); if(errors != 0) error("%d errors\nStop.\n", errors); /* Generate the tables file */ if(errors == 0) do_tables(argv[1], argv[2], argv[3]); return(errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } /* * Function to process the instruction encoding; returns TRUE for success, * FALSE for failure. * */ static INT do_instr(VOID) { INT i, k; INT l = (int) strlen(xinstr); UINT op = 0; switch(l) { case 2: size[num] = 1; break; case 4: size[num] = 2; break; case 6: size[num] = 3; break; default: warn("invalid opcode length (%d) on line %d", l, line); errors++; return(FALSE); } (VOID) strupr(xinstr); for(i = 0; i < size[num]*2; i++) { k = xinstr[i]; if(k >= '0' && k <= '9') { op = (op << 4) | (k - '0'); } else { if(k >= 'A' && k <= 'F') { op = (op << 4) | (k - 'A' + 10); } else { warn("bad opcode '%s' on line %d\n", xinstr, line); errors++; return(FALSE); } } } instr[num] = op; return(TRUE); } /* * Function to process the jump flag; returns TRUE for success, * FALSE for failure. * */ static BOOL do_jump(VOID) { (VOID) strupr(xjump); if((strlen(xjump) == 1) && (xjump[0] == 'J' || xjump[0] == 'N')) { jump[num] = (unsigned int) ((xjump[0] == 'J') ? 1 : 0); return(TRUE); } else { warn("invalid jump flag '%s' on line %d", xjump, line); errors++; return(FALSE); } } /* * Function to process mnemonic field; returns TRUE for success, * FALSE for failure. * */ static BOOL do_mnem(VOID) { if(strlen(xmnem) > MAXMNEM) { warn("mnemonic '%s' too long on line %d", xmnem, line); errors++; return(FALSE); } else { (VOID) strcpy(mnem[num], xmnem); return(TRUE); } } /* * Function to process operand 'n'; returns TRUE for success, * FALSE for failure. * */ static BOOL do_operand(int n) { UINT i; PUCHAR r = xoperand[n-1]; for(i = 0; i < MAXRANDTYPE; i++) { if(strcmp(r, operands[i]) == 0) { operand[n-1][num] = i; return(TRUE); } } warn("invalid operand %d '%s' on line %d", n, r, line); errors++; return(FALSE); } /* * Function to process instruction variant; returns TRUE for success, * FALSE for failure. * */ static BOOL do_variant(VOID) { UINT i; for(i = 0; i < MAXVARIANT; i++) { if(strcmp(xvariant, variants[i]) == 0) { variant[num] = i; return(TRUE); } } warn("invalid variant '%s' on line %d", xvariant, line); errors++; return(FALSE); } /* * Routine to output an error message in the style of 'printf', then exit. * */ static VOID error(PUCHAR s, ...) { va_list ap; fprintf(stderr, "%s: ", progname); va_start(ap, s); vfprintf(stderr, s, ap); va_end(ap); fputc('\n', stderr); exit(EXIT_FAILURE); } /* * Function to generate the subsidiary tables * */ #if C static VOID do_tables(PUCHAR deffile, PUCHAR tabfile, PUCHAR opfile) { INT i; UINT info1, info2; PUCHAR op; time_t now; /* Binary date and time */ UCHAR s_now[26]; /* String date and time */ UCHAR temp[50]; now = time((time_t *) NULL); /* Get binary date and time */ strcpy(s_now, ctime(&now)); /* Copy string version */ s_now[24] = '\0'; /* Truncate to remove newline */ /* First the #defines */ fprintf(opfp, "/*\n * File: %s\n *\n * Register and instruction" " symbol definitions\n *\n", opfile); fprintf(opfp, " * Generated from file %s on %s\n *\n */\n\n", deffile, s_now); fputs("/*\n * Macro definitions\n *\n */\n\n", opfp); for(i = 0; i < MAXMAC; i++) fprintf(opfp, "#define\t%s\n", macros[i]); fputs("\n/*\n * Register symbols\n *\n */\n\n", opfp); fprintf(opfp, "#define\tMAXREGNAME\t%d\n", MAXREGNAME); fprintf(opfp, "#define\tMAXREGS\t\t%d\n\n", MAXREGS); for(i = 0; i < MAXREGNAME; i++) { fprintf(opfp, "#define\t\t%s\t0x%02x\n", xregs[i].name, xregs[i].num); } fputs("\n/*\n * Opcode symbols\n *\n */\n\n", opfp); fprintf(opfp, "#define\tNOOFOPS\t\t%d\n\n", num); for(i = 0; i < num; i++) { op = mnem[i]; fprintf(opfp, "#define\tOP_%s\t", op); if(strlen(op) < 5) fputc('\t', opfp); fprintf(opfp, "%d\n", i); } fputs("\n/*\n * Pseudo operand symbols\n *\n */\n\n", opfp); for(i = 0; i < MAXRANDTYPE; i++) { (VOID) strcpy(temp, operands[i]); (VOID) strupr(temp); translate(temp, "/", ""); translate(temp, ":", "_"); translate(temp, "&", "_AND_"); fprintf(opfp, "#define\tRA_%s\t", temp); if(strlen(temp) < 5) fputc('\t', opfp); fprintf(opfp, "0x%03x\n", 0x100 + i); } fputs("\n/*\n * Actual operand symbols\n *\n */\n\n", opfp); for(i = 0; i < MAXOTHRAND; i++) { (VOID) strcpy(temp, othrands[i].name); (VOID) strupr(temp); translate(temp, "+", "_"); fprintf(opfp, "#define\tRA_%s\t", temp); if(strlen(temp) < 5) fputc('\t', opfp); if(strlen(temp) < 13) fputc('\t', opfp); fprintf(opfp, "0x%02x\n", othrands[i].value); } fputs("\n/*\n * Variant symbols\n *\n */\n\n", opfp); for(i = 0; i < MAXVARIANT; i++) { (VOID) strcpy(temp, variants[i]); (VOID) strupr(temp); translate(temp, "/R", "REG"); translate(temp, "/C", "CREG"); translate(temp, "/D", "DREG"); translate(temp, "/T", "TREG"); translate(temp, "/", "SLASH"); translate(temp, "+", "PLUS_"); fprintf(opfp, "#define\tVA_%s\t", temp); if(strlen(temp) < 5) fputc('\t', opfp); fprintf(opfp, "%d\n", i); } fprintf(opfp, "\n/*\n * End of file: %s\n *\n */\n", opfile); /* Next the register and instruction tables */ fprintf(tabfp, "/*\n * File: %s\n *\n * Register and instruction tables\n *\n", tabfile); fprintf(tabfp, " * Generated from file %s on %s\n *\n */\n\n", deffile, s_now); fprintf(tabfp, "#pragma\tinfo(noext)\n\n"); /* First the user-level registers */ fputs("/*\n * User-level registers\n *\n */\n\n", tabfp); fprintf(tabfp, "const\tunsigned char\t*regs[MAXREGS] = {\n"); for(i = 0; i < MAXREGS; i++) { fprintf(tabfp, "\"%-*s\"%s", 3, xregs[i].name, (i == num - 1) ? "" : ", "); if((i+1)%8 == 0) fputc('\n', tabfp); } #if MAXREGS%8 != 0 fputc('\n', tabfp); #endif fputs("};\n\n", tabfp); /* Next the mnemonics */ fputs("/*\n * Instruction mnemonics\n *\n */\n\n", tabfp); fprintf(tabfp, "unsigned\tint\topcsize = NOOFOPS;\n\n"); fprintf(tabfp, "const\tunsigned char\t*opc[NOOFOPS] = {\n"); for(i = 0; i < num; i++) { fprintf(tabfp, "\"%-*s\"%s", MAXMNEM, mnem[i], (i == num - 1) ? "" : ", "); if((i+1)%4 == 0) fputc('\n', tabfp); } if(num%4 != 0) fputc('\n', tabfp); fputs("};\n", tabfp); /* Now the opcode information tables */ fputs("\n/*\n * Instruction information tables\n *\n */\n\n",tabfp); fputs("const\tunsigned int\topcinfo1[NOOFOPS] = {\n", tabfp); for(i = 0; i < num; i++) { info1 = (jump[i] << 31) | (variant[i] << 24) | (operand[0][i] << 16) | (operand[1][i] << 8) | operand[2][i]; fprintf(tabfp, "0x%08x%s", info1, (i == num - 1) ? "" : ", "); if((i+1)%4 == 0) fputc('\n', tabfp); } if(num%4 != 0) fputc('\n', tabfp); fputs("};\n", tabfp); fputs("\nconst\tunsigned int\topcinfo2[NOOFOPS] = {\n", tabfp); for(i = 0; i < num; i++) { info2 = (instr[i] << (32-size[i]*8)) | size[i]; fprintf(tabfp, "0x%08x%s", info2, (i == num - 1) ? "" : ", "); if((i+1)%4 == 0) fputc('\n', tabfp); } if(num%4 != 0) fputc('\n', tabfp); fputs("};\n", tabfp); fprintf(tabfp, "\n/*\n * End of file: %s\n *\n */\n", tabfile); /* Now the listing file */ fprintf(listfp, "\nOpcode listing generated from file %s on %s\n\n", deffile, s_now); fprintf(listfp, "\t%d opcodes defined\n\n\n", num); fputs("Mnemonic Idx\tOperand\tOperand\tOperand\tVariant\t" " Jump\t Info1 Info2\n", listfp); fputs("\t\t 1\t 2\t 3\t\t flag\n\n", listfp); for(i = 0; i < num; i++) { info1 = (jump[i] << 31) | (variant[i] << 24) | (operand[0][i] << 16) | (operand[1][i] << 8) | operand[2][i]; info2 = (instr[i] << (32-size[i]*8)) | size[i]; fprintf(listfp, "%8s %3d\t%s\t%s\t%s\t", mnem[i], i, operands[operand[0][i]], operands[operand[1][i]], operands[operand[2][i]]); fprintf(listfp, " %s\t %c\t %08x %08x\n", variants[variant[i]], jump[i] ? 'J' : 'N', info1, info2); } } #endif /* * Function to generate the subsidiary tables * */ #if IMP static VOID do_tables(PUCHAR deffile) { INT i; /* First the opcode table */ fprintf(tabfp, "%%constantinteger no of ops = %d\n", num-1); fprintf(tabfp, "%%constantstring(%d)array tsname(0:no of ops) = %%c\n", MAXMNEM); for(i = 0; i < num; i++) { fprintf(tabfp, "\"%-*s\"%c", MAXMNEM, opcode[i], (i == num - 1) ? ';' : ', '); if((i+1)%4 == 0) fputc('\n', tabfp); } if(num%4 != 0) fputc('\n', tabfp); /* Now the opcode information table */ fputs("!\n%constantintegerarray opcinfo(0:no of sns) = %c\n", tabfp); for(i = 0; i < num; i++) { fprintf(tabfp, "x'%08x'%c", opcinfo[i], (i == num - 1) ? ';' : ', '); if((i+1)%4 == 0) fputc('\n', tabfp); } if(num%4 != 0) fputc('\n', tabfp); } #endif /* * Function to open a file in a specified mode * Does not return if there is a failure, but outputs an error * message and exits * */ static FILE *openio(PUCHAR file, PUCHAR mode) { FILE *fp; fp = fopen(file, mode); if(fp == (FILE *) NULL) { fprintf(stderr, "%s: cannot open '%s'\n", progname, file); exit(EXIT_FAILURE); } return(fp); } /* * Routine to read a line from the input file into 'cc'. * Blank lines are ignored. * * On exit, 'cc' contains the string, null terminated. * 'line' has been updated. * */ static VOID readline(VOID) { INT i = 0; INT ch; do { for(;;) { ch = fgetc(infp); if(ch == EOF) break; if(ch == '\n') break; cc[i++] = (UCHAR) ch; } cc[i] = '\0'; } while((cc[0] == '\0') && (ch == '\n')); line++; if(ch == EOF) cc[0] = '\0'; } /* * Routine to replace all occurrences of string 'old' with string 'new' * in string 's'; note that 's' must be large enough to accommodate * any increase in length. * */ static VOID translate(PUCHAR s, PUCHAR old, PUCHAR new) { PUCHAR p; UCHAR temp[50]; for(;;) { p = strstr(s, old); /* Find 'old' in 's' */ if(p == NULL) break; /* Not found */ *p = '\0'; /* Truncate 's' here */ (VOID) strcpy(temp, s); /* Copy head */ (VOID) strcat(temp, new); /* Insert replacement */ p += strlen(old); /* Move past substring */ (VOID) strcat(temp, p); /* Attach old tail */ (VOID) strcpy(s, temp); /* Move back to original */ }; } /* * Routine to output brief usage information, then exit. * */ static VOID usage(VOID) { fprintf(stderr, "Usage: %s input asmtable opcodes listing\n", progname); exit(EXIT_FAILURE); } /* * Routine to output a warning message in the style of 'printf'. * */ static VOID warn(PUCHAR s, ...) { va_list ap; fprintf(stderr, "%s: ", progname); va_start(ap, s); vfprintf(stderr, s, ap); va_end(ap); fputc('\n', stderr); } /* * End of file: genop.c * */