OpenCores
URL https://opencores.org/ocsvn/forwardcom/forwardcom/trunk

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [cmdline.cpp] - Rev 55

Go to most recent revision | Compare with Previous | Blame | View Log

/****************************  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
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.