URL
https://opencores.org/ocsvn/forwardcom/forwardcom/trunk
Subversion Repositories forwardcom
Compare Revisions
- This comparison shows the changes necessary to convert path
/
- from Rev 46 to Rev 47
- ↔ Reverse comparison
Rev 46 → Rev 47
/forwardcom/bintools/cmdline.cpp
0,0 → 1,924
/**************************** cmdline.cpp ********************************** |
* Author: Agner Fog |
* Date created: 2017-04-17 |
* Last modified: 2021-04-25 |
* Version: 1.11 |
* Project: Binary tools for ForwardCom instruction set |
* Description: |
* This module is for interpretation of command line options |
* Also contains symbol change function |
* |
* Copyright 2017-2021 GNU General Public License http://www.gnu.org/licenses |
*****************************************************************************/ |
|
#include "stdafx.h" |
|
// Command line interpreter |
CCommandLineInterpreter cmd; // Instantiate command line interpreter |
|
CCommandLineInterpreter::CCommandLineInterpreter() { |
// Default constructor |
zeroAllMembers(*this); // Set all to zero |
verbose = CMDL_VERBOSE_YES; // How much diagnostics to print on screen |
optiLevel = 2; // Optimization level |
maxErrors = 50; // Maximum number of errors before assembler aborts |
fileNameBuffer.pushString(""); // make first entry zero |
instructionListFile = fileNameBuffer.pushString("instruction_list.csv"); // Filename of list of instructions (default name) |
} |
|
|
void CCommandLineInterpreter::readCommandLine(int argc, char * argv[]) { |
// Read command line |
if (argv[0]) programName = argv[0]; else programName = ""; |
for (int i = 1; i < argc; i++) { |
readCommandItem(argv[i]); |
} |
if (job == CMDL_JOB_HELP || (inputFile == 0 && outputFile == 0)) { |
// No useful command found. Print help |
job = CMDL_JOB_HELP; |
help(); |
return; |
} |
// Check file options |
fileOptions |= CMDL_FILE_INPUT; |
if (libraryOptions == CMDL_LIBRARY_ADDMEMBER) { |
// Adding object files to library. Library may not exist |
fileOptions |= CMDL_FILE_IN_IF_EXISTS; |
} |
if (job == CMDL_JOB_DUMP) { |
// Dumping or extracting. Output file not used |
if (outputFile) err.submit(ERR_OUTFILE_IGNORED); // Output file name ignored |
outputFile = 0; |
} |
else { |
// Output file required |
fileOptions |= CMDL_FILE_OUTPUT; |
} |
if (libraryOptions & CMDL_LIBRARY_ADDMEMBER) { |
// Adding library members only. Output file may have same name as input file |
fileOptions |= CMDL_FILE_IN_OUT_SAME; |
} |
// Check output type |
if (!outputType) { |
// Output type not defined yet |
outputType = FILETYPE_FWC; |
} |
// check if output file name is valid |
checkOutputFileName(); |
} |
|
|
void CCommandLineInterpreter::readCommandItem(char * string) { |
// Read one option from command line |
// Skip leading whitespace |
while (*string != 0 && *string <= ' ') string++; |
if (*string == 0) return; // Empty string |
|
// Look for option prefix and response file prefix |
const char responseFilePrefix = '@'; // Response file name prefixed by '@' |
const char optionPrefix1 = '-'; // Option must begin with '-' |
#if defined (_WIN32) || defined (__WINDOWS__) |
const char optionPrefix2 = '/'; // '/' allowed instead of '-' in Windows only |
#else |
const char optionPrefix2 = '-'; |
#endif |
|
if (*string == optionPrefix1 || *string == optionPrefix2) { |
// Option prefix found. This is a command line option |
if (libmode) interpretLibraryOption(string+1); |
else if (linkmode) interpretLinkOption(string+1); |
else if (emumode) interpretEmulateOption(string+1); |
else if (job == CMDL_JOB_DUMP) interpretDumpOption(string+1); |
else if (job == CMDL_JOB_ASS) interpretAssembleOption(string+1); |
else interpretCommandOption(string+1); |
} |
else if (*string == responseFilePrefix) { |
// Response file prefix found. Read more options from response file |
readCommandFile(string+1); |
} |
else { |
// No prefix found. This is an input or output file name |
interpretFileName(string); |
} |
} |
|
|
void CCommandLineInterpreter::readCommandFile(char * filename) { |
// Read commands from file |
if (*filename <= ' ') { |
err.submit(ERR_EMPTY_OPTION); return; // Warning: empty filename |
} |
|
// Check if too many response file buffers (possibly because file includes itself) |
if (++numBuffers > MAX_COMMAND_FILES) { |
err.submit(ERR_TOO_MANY_RESP_FILES); return; |
} |
|
// Read response file into buffer |
CFileBuffer commandfile; |
commandfile.read(filename); |
if (err.number()) return; |
|
// Get buffer with file contents |
char * buffer = (char*)commandfile.buf(); |
char * itemBegin, * itemEnd; // Mark begin and end of token in buffer |
|
// Check if buffer is allocated |
if (buffer) { |
// Parse contents of response file for tokens |
while (*buffer) { |
|
// Skip whitespace |
while (*buffer != 0 && uint8_t(*buffer) <= uint8_t(' ')) buffer++; |
if (*buffer == 0) break; // End of buffer found |
itemBegin = buffer; |
|
// Find end of token |
itemEnd = buffer+1; |
while (uint8_t(*itemEnd) > uint8_t(' ')) itemEnd++; |
if (*itemEnd == 0) { |
buffer = itemEnd; |
} |
else { |
buffer = itemEnd + 1; |
*itemEnd = 0; // Mark end of token |
} |
// Found token. |
// Check if it is a comment beginning with '#' or '//' |
if (itemBegin[0] == '#' || (itemBegin[0] == '/' && itemBegin[1] == '/' )) { |
// This is a comment. Skip to end of line |
itemEnd = buffer; |
while (*itemEnd != 0 && *itemEnd != '\n') { |
itemEnd++; |
} |
if (*itemEnd == 0) { |
buffer = itemEnd; |
} |
else { |
buffer = itemEnd + 1; |
} |
continue; |
} |
// Not a comment. Interpret token |
readCommandItem(itemBegin); |
} |
} |
} |
|
|
void CCommandLineInterpreter::interpretFileName(char * string) { |
// Interpret input or output filename from command line |
if (libmode) { |
// library command |
if (libmode == 1) { |
// first filename = library file |
inputFile = outputFile = cmd.fileNameBuffer.pushString(string); |
libmode = 2; |
return; |
} |
// object file to add, remove, or extract |
if (libraryOptions == CMDL_LIBRARY_LISTMEMBERS) { |
err.submit(ERR_LIBRARY_LIST_ONLY); return; |
} |
if (libraryOptions == 0) { |
libraryOptions = CMDL_LIBRARY_ADDMEMBER; // default action is add member |
} |
SLCommand libcmd; |
libcmd.command = libraryOptions; |
libcmd.filename = fileNameBuffer.pushString(string); |
libcmd.value = libcmd.filename; |
lcommands.push(libcmd); |
return; |
} |
|
if (linkmode) { |
// linker command |
if (linkmode == CMDL_LINK_EXEFILE) { |
if (job == CMDL_JOB_LINK) { |
// first filename = executable file |
inputFile = cmd.fileNameBuffer.pushString(string); |
outputFile = inputFile; |
linkmode = CMDL_LINK_ADDMODULE; |
} |
else if (job == CMDL_JOB_RELINK) { |
if (inputFile == 0) { |
// first filename = executable input file |
inputFile = cmd.fileNameBuffer.pushString(string); |
} |
else { |
// second filename = executalbe output file |
outputFile = cmd.fileNameBuffer.pushString(string); |
linkmode = CMDL_LINK_ADDMODULE; |
} |
} |
return; |
} |
// object file to add, remove, or extract |
if (linkOptions == CMDL_LINK_LIST) { |
err.submit(ERR_LINK_LIST_ONLY); return; |
} |
if (linkOptions == 0) { |
linkOptions = CMDL_LINK_ADDMODULE; // default action is add modules |
} |
SLCommand linkcmd; |
linkcmd.command = linkOptions; |
linkcmd.filename = fileNameBuffer.pushString(string); |
linkcmd.value = linkcmd.filename; |
lcommands.push(linkcmd); |
return; |
} |
|
// no libmode or linkmode: Ordinary input or output file |
if (!inputFile) { |
// Input file not specified yet |
inputFile = fileNameBuffer.pushString(string); |
} |
else if (!outputFile) { |
// Output file not specified yet |
outputFile = fileNameBuffer.pushString(string); |
} |
else { |
// Both input and output files already specified |
err.submit(ERR_MULTIPLE_IO_FILES); |
} |
} |
|
void CCommandLineInterpreter::interpretCommandOption(char * string) { |
// Interpret one option from command line |
if ((uint8_t)*string <= (uint8_t)' ') { |
err.submit(ERR_EMPTY_OPTION); return; // Warning: empty option |
} |
|
// Detect option type |
switch(string[0] | 0x20) { |
case 'a': // assemble option |
if (job) err.submit(ERR_MULTIPLE_COMMANDS, string); // More than one job specified |
job = CMDL_JOB_ASS; |
if (strncasecmp_(string, "ass", 3) == 0) { |
interpretAssembleOption(string+3); |
} |
else err.submit(ERR_UNKNOWN_OPTION, string); // Unknown option |
break; |
|
case 'c': // codesize option |
if (strncasecmp_(string, "codesize", 8) == 0) { |
interpretCodeSizeOption(string+8); |
} |
else err.submit(ERR_UNKNOWN_OPTION, string); // Unknown option |
break; |
|
|
case 'd': // disassemble, dump, debug or datasize option |
if (strncasecmp_(string, "dis", 3) == 0) { |
if (job) err.submit(ERR_MULTIPLE_COMMANDS, string); // More than one job specified |
job = CMDL_JOB_DIS; |
interpretDisassembleOption(string+3); break; |
} |
if (strncasecmp_(string, "dump", 4) == 0) { |
if (job) err.submit(ERR_MULTIPLE_COMMANDS, string); // More than one job specified |
job = CMDL_JOB_DUMP; |
interpretDumpOption(string+4); break; |
} |
if (strncasecmp_(string, "datasize", 8) == 0) { |
interpretDataSizeOption(string+8); |
break; |
} |
if (strncasecmp_(string, "debug", 5) == 0) { |
interpretDebugOption(string+5); |
break; |
} |
|
err.submit(ERR_UNKNOWN_OPTION, string); // Unknown option |
break; |
|
case 'e': // Emulation or error option |
if (strncasecmp_(string, "emu", 3) == 0) { |
if (job) err.submit(ERR_MULTIPLE_COMMANDS, string); // More than one job specified |
job = CMDL_JOB_EMU; |
emumode = 1; |
} |
else { |
interpretErrorOption(string); |
} |
break; |
|
case 'h': case '?': // Help |
job = CMDL_JOB_HELP; |
break; |
|
case 'i': // Instruction list |
if (strncasecmp_(string, "ilist=", 6) == 0) { |
interpretIlistOption(string+6); |
} |
else { |
err.submit(ERR_UNKNOWN_OPTION, string); // Unknown option |
} |
break; |
|
case 'l': // Link, Library, and list file options |
if (strncasecmp_(string, "lib", 3) == 0) { |
if (job) err.submit(ERR_MULTIPLE_COMMANDS, string); // More than one job specified |
job = CMDL_JOB_LIB; |
interpretLibraryCommand(string+3); break; |
} |
if (strncasecmp_(string, "link", 4) == 0) { |
if (job) err.submit(ERR_MULTIPLE_COMMANDS, string); // More than one job specified |
job = CMDL_JOB_LINK; outputType = FILETYPE_FWC_EXE; |
interpretLinkCommand(string+4); break; |
} |
if (strncasecmp_(string, "list=", 5) == 0) { |
interpretListOption(string+5); break; |
} |
err.submit(ERR_UNKNOWN_OPTION, string); // Unknown option |
break; |
|
case 'm': // Maxerrors option |
if (strncasecmp_(string, "maxerrors", 9) == 0) { |
interpretMaxErrorsOption(string+9); break; |
} |
err.submit(ERR_UNKNOWN_OPTION, string); // Unknown option |
break; |
|
case 'o': // Optimization option |
interpretOptimizationOption(string+1); |
break; |
|
case 'r': // Relink command |
if (strncasecmp_(string, "relink", 6) == 0) { |
if (job) err.submit(ERR_MULTIPLE_COMMANDS, string); // More than one job specified |
job = CMDL_JOB_RELINK; outputType = FILETYPE_FWC_EXE; |
interpretLinkCommand(string+6); break; |
} |
break; |
|
case 'v': // verbose/silent |
interpretVerboseOption(string+1); |
break; |
|
case 'w': // Warning option |
interpretErrorOption(string); break; |
|
default: // Unknown option |
err.submit(ERR_UNKNOWN_OPTION, string); |
} |
} |
|
void CCommandLineInterpreter::interpretAssembleOption(char * string) { |
if ((string[0] | 0x20) == 'b') dumpOptions = 2; // binary listing! |
else if (string[0] == 0 || (string[0] | 0x20) == 'e') outputType = FILETYPE_FWC; |
else interpretCommandOption(string); |
} |
|
void CCommandLineInterpreter::interpretDisassembleOption(char * string) { |
outputType = CMDL_OUTPUT_ASM; |
} |
|
void CCommandLineInterpreter::interpretDumpOption(char * string) { |
// Interpret dump option from command line |
if (outputType /*&& outputType != outputType*/) { |
err.submit(ERR_MULTIPLE_COMMANDS, string); // Both dump and convert specified |
} |
char * s1 = string; |
while (*s1) { |
switch (*(s1++) | 0x20) { |
case 'l': // dump link map |
dumpOptions |= DUMP_LINKMAP; break; |
case 'f': // dump file header |
dumpOptions |= DUMP_FILEHDR; break; |
case 'h': // dump section headers |
dumpOptions |= DUMP_SECTHDR; break; |
case 's': // dump symbol table |
dumpOptions |= DUMP_SYMTAB; break; |
case 'r': // dump relocations |
dumpOptions |= DUMP_RELTAB; break; |
case 'n': // dump string table |
dumpOptions |= DUMP_STRINGTB; break; |
case 'm': // show names of relinkable modules and libraries |
dumpOptions |= DUMP_RELINKABLE; break; |
case 'c': // dump comment records (currently only for OMF) |
dumpOptions |= DUMP_COMMENT; break; |
case '-': case '_': // '-' may separate options |
break; |
default: |
err.submit(ERR_UNKNOWN_OPTION, string-1); // Unknown option |
} |
} |
outputType = CMDL_OUTPUT_DUMP; |
} |
|
void CCommandLineInterpreter::interpretEmulateOption(char * string) { |
// Interpret emulate options |
if ((uint8_t)*string <= (uint8_t)' ') { |
err.submit(ERR_EMPTY_OPTION); return; // Warning: empty option |
} |
// Detect option type |
switch(string[0] | 0x20) { |
case 'l': // list option |
if (strncasecmp_(string, "list=", 5) == 0) { |
interpretListOption(string+5); break; |
} |
err.submit(ERR_UNKNOWN_OPTION, string-1); // Unknown option |
break; |
case 'm': |
if (strncasecmp_(string, "maxerrors", 9) == 0) { |
interpretMaxErrorsOption(string + 9); break; |
} |
if (strncasecmp_(string, "maxlines", 8) == 0) { |
interpretMaxLinesOption(string + 8); break; |
} |
err.submit(ERR_UNKNOWN_OPTION, string); // Unknown option |
break; |
} |
|
} |
|
void CCommandLineInterpreter::interpretLibraryCommand(char * string) { |
// Interpret options for manipulating library/archive files |
|
// meaning of libmode: |
// 0: not a library command |
// 1: after "-lib". expecting library name |
// 2: after library name or -a. expecting command or object files to add |
// 3: after "-d". expecting object files to delete |
// 4: after "-l". list all members |
// 5: after "-x". expecting object files to extract |
// 6: after "-xall". extract all members |
|
// Check for -lib command |
if (inputFile) { |
libmode = 2; // Input file already specified. Remaining file names are object files to add |
} |
else { |
libmode = 1; // The rest of the command line must be interpreted as library name and object file names |
} |
fileOptions |= CMDL_FILE_IN_IF_EXISTS | CMDL_FILE_IN_OUT_SAME; |
} |
|
// interpret library commands |
void CCommandLineInterpreter::interpretLibraryOption(char * string) { |
switch (string[0] | 0x20) { |
case 'a': // Add input file to library |
libmode = 2; |
libraryOptions = CMDL_LIBRARY_ADDMEMBER; |
break; |
|
case 'd': // Delete member from library |
libmode = 3; |
libraryOptions = CMDL_LIBRARY_DELETEMEMBER; |
break; |
|
case 'l': |
libmode = 4; |
if (libraryOptions) { // cannot combine with other commands |
err.submit(ERR_LIBRARY_LIST_ONLY); return; |
} |
libraryOptions = CMDL_LIBRARY_LISTMEMBERS; |
if (string[1] > ' ') verbose = atoi(string+1); |
return; |
|
case 'v': // verbose/silent |
interpretVerboseOption(string+1); |
return; |
|
case 'x': // Extract member(s) from library |
libmode = 5; |
libraryOptions = CMDL_LIBRARY_EXTRACTMEM; |
if (strncasecmp_(string+2, "all", 3) == 0) { |
libmode = 6; |
cmd.libraryOptions = CMDL_LIBRARY_EXTRACTALL; |
if (string[5] > ' ') err.submit(ERR_UNKNOWN_OPTION, string); |
return; |
} |
break; |
|
default: |
err.submit(ERR_UNKNOWN_OPTION, string); // Unknown option |
} |
// check if immediately followed by filename |
if (string[1] > ' ') interpretFileName(string+2); |
} |
|
|
// Interpret -link command |
void CCommandLineInterpreter::interpretLinkCommand(char * string) { |
if (inputFile) { |
linkmode = CMDL_LINK_ADDMODULE; // executable file already specified. Remaining file names are object files and library files to add |
} |
else { |
linkmode = CMDL_LINK_EXEFILE; // The rest of the command line must be interpreted as executable name and object file names |
} |
if (job == CMDL_JOB_LINK) { |
fileOptions |= CMDL_FILE_IN_IF_EXISTS | CMDL_FILE_IN_OUT_SAME; |
} |
} |
|
|
// interpret linker options |
void CCommandLineInterpreter::interpretLinkOption(char * string) { |
switch (string[0] | 0x20) { |
case 'a': // Add input file to executable |
linkmode = CMDL_LINK_ADDMODULE; |
linkOptions = CMDL_LINK_ADDMODULE; |
break; |
|
case 'r': // Add input files as relinkable |
linkmode = CMDL_LINK_ADDMODULE; |
linkOptions = CMDL_LINK_ADDMODULE | CMDL_LINK_RELINKABLE; |
fileOptions |= CMDL_FILE_RELINKABLE; |
break; |
|
case 'l': |
linkmode = CMDL_LINK_LIST; |
if (linkOptions) { // cannot combine with other commands |
err.submit(ERR_LINK_LIST_ONLY); return; |
} |
linkOptions = CMDL_LINK_LIST; |
if (string[1] > ' ') verbose = atoi(string+1); |
return; |
|
case 'm': |
if (strncasecmp_(string, "map=", 4) == 0) { // map option |
outputListFile = fileNameBuffer.pushString(string+4); |
return; |
} |
// Explicitly add specified module from previously specified library |
linkmode = CMDL_LINK_ADDLIBMODULE; |
linkOptions = CMDL_LINK_ADDLIBMODULE | (linkOptions & CMDL_LINK_RELINKABLE); |
break; |
|
case 'x': // Extract module from relinkable executable file |
linkmode = CMDL_LINK_EXTRACT; |
linkOptions = CMDL_LINK_EXTRACT; |
libraryOptions = CMDL_LIBRARY_EXTRACTMEM; |
if (strncasecmp_(string+1, "all", 3) == 0) { |
libmode = CMDL_LINK_EXTRACT_ALL; |
libraryOptions = CMDL_LIBRARY_EXTRACTALL; |
if (string[5] > ' ') err.submit(ERR_UNKNOWN_OPTION, string); |
return; |
} |
break; |
|
case 'u': |
fileOptions |= CMDL_FILE_INCOMPLETE | CMDL_FILE_RELINKABLE; |
if (string[1] > ' ') |
err.submit(ERR_UNKNOWN_OPTION, string); |
return; |
|
case 'v': // verbose/silent |
interpretVerboseOption(string+1); |
return; |
|
case 's': // stacksize |
if (strncasecmp_(string, "stack=", 6) == 0) { |
interpretStackOption(string+6); |
return; |
} |
break; |
|
case 'h': // heapsize |
if (strncasecmp_(string, "heap=", 5) == 0) { |
interpretHeapOption(string+5); |
return; |
} |
else if (strncasecmp_(string, "hex", 3) == 0) { |
interpretHexfileOption(string+3); |
return; |
} |
break; |
|
case 'd': |
if (strncasecmp_(string, "debug", 5) == 0) { |
interpretDebugOption(string+5); |
return; |
} |
if (strncasecmp_(string, "dynlink=", 8) == 0) { |
interpretDynlinkOption(string+8); // space for dynamic linking |
return; |
} |
// Remove relinkable modules |
linkmode = CMDL_LINK_REMOVE; |
linkOptions = CMDL_LINK_REMOVE; |
break; |
|
case 'e': case 'w': |
interpretErrorOption(string); |
return; |
|
default: |
err.submit(ERR_UNKNOWN_OPTION, string); // Unknown option |
return; |
} |
// check if immediately followed by filename |
if (string[1] > ' ') interpretFileName(string+1); |
} |
|
void CCommandLineInterpreter::interpretIlistOption(char * string) { |
// Interpret instruction list file option for assembler |
instructionListFile = fileNameBuffer.pushString(string); |
} |
|
void CCommandLineInterpreter::interpretListOption(char * string) { |
// Interpret instruction list file option for assembler |
outputListFile = fileNameBuffer.pushString(string); |
if (maxLines == 0) maxLines = 1000; |
} |
|
void CCommandLineInterpreter::interpretStackOption(char * string) { |
// Interpret stack size option for linker |
// stack=number1,number2,number3 |
// number1 = call stack size, bytes |
// number2 = data stack size, bytes |
// number3 = additional size for vectors on data stack. value will be multiplied by maximum vector length |
SLCommand linkcmd; // command record |
uint32_t e; // return code from interpretNumber |
linkcmd.filename = 0; |
linkcmd.command = CMDL_LINK_STACKSIZE; |
linkcmd.value = interpretNumber(string, 32, &e); // get first number = call stack size |
if (e && !(e & 0x1000)) {err.submit(ERR_UNKNOWN_OPTION, string); return;} |
lcommands.push(linkcmd); // save first number |
if (e & 0x1000) { // second number specified |
string += (e & 0xFFF) + 1; |
linkcmd.command++; |
linkcmd.value = interpretNumber(string, 32, &e); // get second number = data stack size |
if (e && !(e & 0x1000)) {err.submit(ERR_UNKNOWN_OPTION, string); return;} |
lcommands.push(linkcmd); // save second number |
if (e & 0x1000) { // third number specified |
string += (e & 0xFFF) + 1; |
linkcmd.command++; |
linkcmd.value = interpretNumber(string, 32, &e); // get third number = number of vectors on data stack |
if (e) {err.submit(ERR_UNKNOWN_OPTION, string); return;} |
lcommands.push(linkcmd); // save third number |
} |
} |
} |
|
void CCommandLineInterpreter::interpretHeapOption(char * string) { |
// Interpret heap size option for linker |
// Interpret stack size option for linker |
// heap=number |
// number = heap size, bytes |
SLCommand linkcmd; // command record |
uint32_t e; // return code from interpretNumber |
linkcmd.filename = 0; |
linkcmd.command = CMDL_LINK_HEAPSIZE; |
linkcmd.value = interpretNumber(string, 32, &e); // get first number = call stack size |
if (e) {err.submit(ERR_UNKNOWN_OPTION, string); return;} |
lcommands.push(linkcmd); |
} |
|
void CCommandLineInterpreter::interpretHexfileOption(char * string) { |
// Interpret hexfile option for linker |
cmd.outputType = FILETYPE_FWC_HEX; |
uint32_t e; // return code from interpretNumber |
cmd.maxLines = (uint32_t)interpretNumber(string, 32, &e); // get first number = call stack size |
if (e) {err.submit(ERR_UNKNOWN_OPTION, string); return;} |
} |
|
|
void CCommandLineInterpreter::interpretDynlinkOption(char * string) { |
// Interpret dynamic link size option for linker |
// dynlink=number1,number2,number3 |
// number1 = size for read-only data, bytes |
// number2 = size for executable section, bytes |
// number3 = size for writeable static data, bytes |
SLCommand linkcmd; // command record |
uint32_t e; // return code from interpretNumber |
linkcmd.filename = 0; |
linkcmd.command = CMDL_LINK_DYNLINKSIZE; |
linkcmd.value = interpretNumber(string, 32, &e); // get first number = read-only |
if (e && !(e & 0x1000)) {err.submit(ERR_UNKNOWN_OPTION, string); return;} |
lcommands.push(linkcmd); // save first number |
if (e & 0x1000) { // second number specified |
string += (e & 0xFFF) + 1; |
linkcmd.command++; |
linkcmd.value = interpretNumber(string, 32, &e); // get second number = executable section |
if (e && !(e & 0x1000)) {err.submit(ERR_UNKNOWN_OPTION, string); return;} |
lcommands.push(linkcmd); // save second number |
if (e & 0x1000) { // third number specified |
string += (e & 0xFFF) + 1; |
linkcmd.command++; |
linkcmd.value = interpretNumber(string, 32, &e); // get third number = writeable data |
if (e & ~0x1000) {err.submit(ERR_UNKNOWN_OPTION, string); return;} |
lcommands.push(linkcmd); // save third number |
} |
} |
} |
|
void CCommandLineInterpreter::interpretOptimizationOption(char * string) { |
if (string[0] < '0' || string[0] > '9' || strlen(string) != 1) { |
err.submit(ERR_UNKNOWN_OPTION, string); return; // Unknown option |
} |
optiLevel = string[0] - '0'; |
} |
|
void CCommandLineInterpreter::interpretVerboseOption(char * string) { |
// Interpret silent/verbose option from command line |
verbose = atoi(string); |
} |
|
void CCommandLineInterpreter::interpretMaxErrorsOption(char * string) { |
// Interpret maxerrors option from command line |
if (string[0] == '=') string++; |
uint32_t error = 0; |
maxErrors = (uint32_t)interpretNumber(string, 99, &error); |
if (error) err.submit(ERR_UNKNOWN_OPTION, string); |
} |
|
void CCommandLineInterpreter::interpretCodeSizeOption(char * string) { |
// Interpret codesize option from command line |
uint32_t error = 0; |
codeSizeOption = interpretNumber(string, 99, &error); |
if (error) err.submit(ERR_UNKNOWN_OPTION, string); |
} |
|
void CCommandLineInterpreter::interpretDataSizeOption(char * string) { |
// Interpret datasize option from command line |
uint32_t error = 0; |
dataSizeOption = interpretNumber(string+1, 99, &error); |
if (error) err.submit(ERR_UNKNOWN_OPTION, string); |
} |
|
void CCommandLineInterpreter::interpretDebugOption(char * string) { |
// Interpret debug option from command line |
uint32_t error = 0; |
if (string[0] == 0) { |
debugOptions = 1; |
return; |
} |
debugOptions = (uint32_t)interpretNumber(string+1, 99, &error); |
if (error) err.submit(ERR_UNKNOWN_OPTION, string); |
} |
|
void CCommandLineInterpreter::interpretErrorOption(char * string) { |
// Interpret warning/error option from command line |
if (strlen(string) < 3) { |
err.submit(ERR_UNKNOWN_OPTION, string); return; // Unknown option |
} |
int newstatus; // New status for this error number |
|
switch (string[1]) { |
case 'd': // Disable |
newstatus = 0; break; |
|
case 'w': // Treat as warning |
newstatus = 1; break; |
|
case 'e': // Treat as error |
newstatus = 2; break; |
|
default: |
err.submit(ERR_UNKNOWN_OPTION, string); // Unknown option |
return; |
} |
if (string[2] == 'x' ) { |
// Apply new status to all non-fatal messages |
for (SErrorText * ep = errorTexts; ep->status < 9; ep++) { |
ep->status = newstatus; // Change status of all errors |
} |
} |
else { |
int ErrNum = atoi(string+2); |
if (ErrNum == 0 && string[2] != '0') { |
err.submit(ERR_UNKNOWN_OPTION, string); return; // Unknown option |
} |
// Search for this error number |
SErrorText * ep = err.FindError(ErrNum); |
if (ep->status & 0x100) { |
// Error number not found |
err.submit(ERR_UNKNOWN_ERROR_NUM, ErrNum); return; // Unknown error number |
} |
// Change status of this error |
ep->status = newstatus; |
} |
} |
|
void CCommandLineInterpreter::interpretMaxLinesOption(char * string) { |
// Interpret maxlines option from command line |
if (string[0] == '=') string++; |
uint32_t error = 0; |
maxLines = (uint32_t)interpretNumber(string, 99, &error); |
if (error) err.submit(ERR_UNKNOWN_OPTION, string); |
} |
|
|
void CCommandLineInterpreter::reportStatistics() { |
// Report statistics about name changes etc. |
} |
|
|
void CCommandLineInterpreter::checkExtractSuccess() { |
// Check if library members to extract were found |
//! |
} |
|
|
void CCommandLineInterpreter::checkOutputFileName() { |
// Make output file name or check that requested name is valid |
if (!(fileOptions & CMDL_FILE_OUTPUT)) return; |
|
if (outputFile == 0) { |
// Output file name not specified. Make filename |
outputFile = setFileNameExtension(inputFile, outputType); |
} |
// Check if input and output files have same name |
if (strcmp(getFilename(inputFile), getFilename(outputFile)) == 0 && !(cmd.fileOptions & CMDL_FILE_IN_OUT_SAME)) { |
err.submit(ERR_FILES_SAME_NAME, getFilename(inputFile)); |
} |
} |
|
|
uint32_t CCommandLineInterpreter::setFileNameExtension(uint32_t fn, int filetype) { |
// Set file name extension for output file according to FileType |
// Names are stored as indexes into cmd.fileNameBuffer |
|
// get old name |
const char * name1 = getFilename(fn); |
int i; |
uint32_t newname = 0; |
|
// Search for last '.' in file name |
for (i = (int)strlen(name1)-1; i > 0; i--) if (name1[i] == '.') break; |
if (i < 1) { |
// '.' not found. Append '.' to name |
i = (int)strlen(name1); |
} |
// Get default extension |
const char * defaultExtension; |
switch (filetype) { |
case FILETYPE_ASM: |
// don't give disassembly the same extension because it may overwrite the original assembly file |
defaultExtension = ".das"; break; |
case FILETYPE_FWC: case FILETYPE_ELF: |
defaultExtension = ".ob"; break; |
case FILETYPE_FWC_EXE: |
defaultExtension = ".ex"; break; |
case FILETYPE_FWC_LIB: |
defaultExtension = ".li"; break; |
case FILETYPE_FWC_HEX: |
defaultExtension = ".hex"; break; |
default: |
defaultExtension = ".txt"; |
} |
// generate new name in cmd.fileNameBuffer |
newname = fileNameBuffer.push(name1, i + (uint32_t)strlen(defaultExtension) + 1); |
strcpy((char*)cmd.fileNameBuffer.buf() + newname + i, defaultExtension); |
return newname; |
} |
|
// Get file name from index into fileNameBuffer |
const char * CCommandLineInterpreter::getFilename(uint32_t n) { |
if (n >= fileNameBuffer.dataSize()) return "unknown?"; |
return (const char *)fileNameBuffer.buf() + n; |
} |
|
|
void CCommandLineInterpreter::help() { |
// Print help message |
printf("\nBinary tools version %i.%02i for ForwardCom instruction set.", FORWARDCOM_VERSION, FORWARDCOM_SUBVERSION); |
printf("\nCopyright (c) 2021 by Agner Fog. Gnu General Public License."); |
printf("\n\nUsage: forw command [options] inputfile [outputfile] [options]"); |
printf("\n\nCommand:"); |
printf("\n-ass Assemble\n"); |
printf("\n-dis Disassemble object or executable file\n"); |
printf("\n-link Link object files into executable file\n"); |
printf("\n-relink Relink and modify executable file\n"); |
printf("\n-lib Build or manage library file\n"); |
printf("\n-emu Emulate and debug executable file\n"); |
printf("\n-dump-XXX Dump file contents to console."); |
printf("\n Values of XXX (can be combined):"); |
printf("\n f: File header, h: section Headers, s: Symbol table,"); |
printf("\n m: Relinkable modules, r: Relocation table, n: string table.\n"); |
printf("\n-help Print this help screen."); |
|
printf("\n\nAssemble options:"); |
printf("\n-list=filename Specify file for output listing."); |
printf("\n-ON Optimization level. N = 0-2."); |
|
printf("\n\nGeneral options:"); |
printf("\n-ilist=filename Specify instruction list file."); |
printf("\n-wdNNN Disable Warning NNN."); |
printf("\n-weNNN treat Warning NNN as Error. -wex: treat all warnings as errors."); |
printf("\n-edNNN Disable Error number NNN."); |
printf("\n-ewNNN treat Error number NNN as Warning."); |
printf("\n@RFILE Read additional options from response file RFILE."); |
printf("\n\nExample:"); |
printf("\nforw -ass test.as test.ob"); |
printf("\nforw -link test.ex test.ob libc.li"); |
printf("\nforw -emu test.ex -list=debugout.txt"); |
printf("\n\nSee the manual for more options.\n"); |
} |
|
// compare strings, ignore case for a-z |
int strncasecmp_(const char *s1, const char *s2, uint32_t n) { |
//return strnicmp(s1, s2, n); // MS |
//return strncasecmp(s1, s2, n); // Linux |
for (uint32_t i = 0; i < n; i++) { // loop through string |
char c1 = s1[i]; |
char c2 = s2[i]; |
if (uint8_t(c1-'A') <= uint8_t('Z' - 'A')) c1 |= 0x20; // convert A-Z to a-z |
if (uint8_t(c2-'A') <= uint8_t('Z' - 'A')) c2 |= 0x20; // convert A-Z to a-z |
if (c1 != c2) return int(c1) - int(c2); // difference found |
if (c1 == 0) break; // end of string |
} |
return 0; // no difference between strings |
} |