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

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [cmdline.cpp] - Blame information for rev 110

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

Line No. Rev Author Line
1 47 Agner
/****************************  cmdline.cpp  **********************************
2
* Author:        Agner Fog
3
* Date created:  2017-04-17
4
* Last modified: 2021-04-25
5
* Version:       1.11
6
* Project:       Binary tools for ForwardCom instruction set
7
* Description:
8
* This module is for interpretation of command line options
9
* Also contains symbol change function
10
*
11
* Copyright 2017-2021 GNU General Public License http://www.gnu.org/licenses
12
*****************************************************************************/
13
 
14
#include "stdafx.h"
15
 
16
// Command line interpreter
17
CCommandLineInterpreter cmd;                               // Instantiate command line interpreter
18
 
19
CCommandLineInterpreter::CCommandLineInterpreter() {
20
    // Default constructor
21
    zeroAllMembers(*this);                                 // Set all to zero
22
    verbose   = CMDL_VERBOSE_YES;                          // How much diagnostics to print on screen
23
    optiLevel = 2;                                         // Optimization level
24
    maxErrors = 50;                                        // Maximum number of errors before assembler aborts
25
    fileNameBuffer.pushString("");                         // make first entry zero
26
    instructionListFile = fileNameBuffer.pushString("instruction_list.csv");  // Filename of list of instructions (default name)
27
}
28
 
29
 
30
void CCommandLineInterpreter::readCommandLine(int argc, char * argv[]) {
31
    // Read command line
32
    if (argv[0]) programName = argv[0]; else programName = "";
33
    for (int i = 1; i < argc; i++) {
34
        readCommandItem(argv[i]);
35
    }
36
    if (job == CMDL_JOB_HELP || (inputFile == 0 && outputFile == 0)) {
37
        // No useful command found. Print help
38
        job = CMDL_JOB_HELP;
39
        help();
40
        return;
41
    }
42
    // Check file options
43
    fileOptions |= CMDL_FILE_INPUT;
44
    if (libraryOptions == CMDL_LIBRARY_ADDMEMBER) {
45
        // Adding object files to library. Library may not exist
46
        fileOptions |= CMDL_FILE_IN_IF_EXISTS;
47
    }
48
    if (job == CMDL_JOB_DUMP) {
49
        // Dumping or extracting. Output file not used
50
        if (outputFile) err.submit(ERR_OUTFILE_IGNORED); // Output file name ignored
51
        outputFile = 0;
52
    }
53
    else {
54
        // Output file required
55
        fileOptions |= CMDL_FILE_OUTPUT;
56
    }
57
    if (libraryOptions & CMDL_LIBRARY_ADDMEMBER) {
58
        // Adding library members only. Output file may have same name as input file
59
        fileOptions |= CMDL_FILE_IN_OUT_SAME;
60
    }
61
    // Check output type
62
    if (!outputType) {
63
        // Output type not defined yet
64
        outputType = FILETYPE_FWC;
65
    }
66
    // check if output file name is valid
67
    checkOutputFileName();
68
}
69
 
70
 
71
void CCommandLineInterpreter::readCommandItem(char * string) {
72
    // Read one option from command line
73
    // Skip leading whitespace
74
    while (*string != 0 && *string <= ' ') string++;
75
    if (*string == 0) return;  // Empty string
76
 
77
    // Look for option prefix and response file prefix
78
    const char responseFilePrefix = '@';  // Response file name prefixed by '@'
79
    const char optionPrefix1 = '-';  // Option must begin with '-'
80
#if defined (_WIN32) || defined (__WINDOWS__)
81
    const char optionPrefix2 = '/';  // '/' allowed instead of '-' in Windows only
82
#else
83
    const char optionPrefix2 = '-';
84
#endif
85
 
86
    if (*string == optionPrefix1 || *string == optionPrefix2) {
87
        // Option prefix found. This is a command line option
88
        if (libmode) interpretLibraryOption(string+1);
89
        else if (linkmode) interpretLinkOption(string+1);
90
        else if (emumode) interpretEmulateOption(string+1);
91
        else if (job == CMDL_JOB_DUMP) interpretDumpOption(string+1);
92
        else if (job == CMDL_JOB_ASS) interpretAssembleOption(string+1);
93
        else interpretCommandOption(string+1);
94
    }
95
    else if (*string == responseFilePrefix) {
96
        // Response file prefix found. Read more options from response file
97
        readCommandFile(string+1);
98
    }
99
    else {
100
        // No prefix found. This is an input or output file name
101
        interpretFileName(string);
102
    }
103
}
104
 
105
 
106
void CCommandLineInterpreter::readCommandFile(char * filename) {
107
    // Read commands from file
108
    if (*filename <= ' ') {
109
        err.submit(ERR_EMPTY_OPTION); return;    // Warning: empty filename
110
    }
111
 
112
    // Check if too many response file buffers (possibly because file includes itself)
113
    if (++numBuffers > MAX_COMMAND_FILES) {
114
        err.submit(ERR_TOO_MANY_RESP_FILES); return;
115
    }
116
 
117
    // Read response file into buffer
118
    CFileBuffer commandfile;
119
    commandfile.read(filename);
120
    if (err.number()) return;
121
 
122
    // Get buffer with file contents
123
    char * buffer = (char*)commandfile.buf();
124
    char * itemBegin, * itemEnd;  // Mark begin and end of token in buffer
125
 
126
    // Check if buffer is allocated
127
    if (buffer) {
128
        // Parse contents of response file for tokens
129
        while (*buffer) {
130
 
131
            // Skip whitespace
132
            while (*buffer != 0 && uint8_t(*buffer) <= uint8_t(' ')) buffer++;
133
            if (*buffer == 0) break; // End of buffer found
134
            itemBegin = buffer;
135
 
136
            // Find end of token
137
            itemEnd = buffer+1;
138
            while (uint8_t(*itemEnd) > uint8_t(' ')) itemEnd++;
139
            if (*itemEnd == 0) {
140
                buffer = itemEnd;
141
            }
142
            else {
143
                buffer = itemEnd + 1;
144
                *itemEnd = 0;    // Mark end of token
145
            }
146
            // Found token. 
147
            // Check if it is a comment beginning with '#' or '//'
148
            if (itemBegin[0] == '#' || (itemBegin[0] == '/' && itemBegin[1] == '/' )) {
149
                // This is a comment. Skip to end of line
150
                itemEnd = buffer;
151
                while (*itemEnd != 0 && *itemEnd != '\n') {
152
                    itemEnd++;
153
                }
154
                if (*itemEnd == 0) {
155
                    buffer = itemEnd;
156
                }
157
                else {
158
                    buffer = itemEnd + 1;
159
                }
160
                continue;
161
            }
162
            // Not a comment. Interpret token
163
            readCommandItem(itemBegin);
164
        }
165
    }
166
}
167
 
168
 
169
void CCommandLineInterpreter::interpretFileName(char * string) {
170
    // Interpret input or output filename from command line
171
    if (libmode) {
172
        // library command
173
        if (libmode == 1) {
174
            // first filename = library file
175
            inputFile = outputFile = cmd.fileNameBuffer.pushString(string);
176
            libmode = 2;
177
            return;
178
        }
179
        // object file to add, remove, or extract
180
        if (libraryOptions == CMDL_LIBRARY_LISTMEMBERS) {
181
            err.submit(ERR_LIBRARY_LIST_ONLY);  return;
182
        }
183
        if (libraryOptions == 0) {
184
            libraryOptions = CMDL_LIBRARY_ADDMEMBER;  // default action is add member
185
        }
186
        SLCommand libcmd;
187
        libcmd.command = libraryOptions;
188
        libcmd.filename = fileNameBuffer.pushString(string);
189
        libcmd.value = libcmd.filename;
190
        lcommands.push(libcmd);
191
        return;
192
    }
193
 
194
    if (linkmode) {
195
        // linker command
196
        if (linkmode == CMDL_LINK_EXEFILE) {
197
            if (job == CMDL_JOB_LINK) {
198
                // first filename = executable file
199
                inputFile = cmd.fileNameBuffer.pushString(string);
200
                outputFile = inputFile;
201
                linkmode = CMDL_LINK_ADDMODULE;
202
            }
203
            else if (job == CMDL_JOB_RELINK) {
204
                if (inputFile == 0) {
205
                    // first filename = executable input file
206
                    inputFile = cmd.fileNameBuffer.pushString(string);
207
                }
208
                else {
209
                    // second filename = executalbe output file
210
                    outputFile = cmd.fileNameBuffer.pushString(string);
211
                    linkmode = CMDL_LINK_ADDMODULE;
212
                }
213
            }
214
            return;
215
        }
216
        // object file to add, remove, or extract
217
        if (linkOptions == CMDL_LINK_LIST) {
218
            err.submit(ERR_LINK_LIST_ONLY);  return;
219
        }
220
        if (linkOptions == 0) {
221
            linkOptions = CMDL_LINK_ADDMODULE;  // default action is add modules
222
        }
223
        SLCommand linkcmd;
224
        linkcmd.command = linkOptions;
225
        linkcmd.filename = fileNameBuffer.pushString(string);
226
        linkcmd.value = linkcmd.filename;
227
        lcommands.push(linkcmd);
228
        return;
229
    }
230
 
231
    // no libmode or linkmode: Ordinary input or output file
232
    if (!inputFile) {
233
        // Input file not specified yet
234
        inputFile = fileNameBuffer.pushString(string);
235
    }
236
    else if (!outputFile) {
237
        // Output file not specified yet
238
        outputFile = fileNameBuffer.pushString(string);
239
    }
240
    else {
241
        // Both input and output files already specified
242
        err.submit(ERR_MULTIPLE_IO_FILES);
243
    }
244
}
245
 
246
void CCommandLineInterpreter::interpretCommandOption(char * string) {
247
    // Interpret one option from command line
248
    if ((uint8_t)*string <= (uint8_t)' ') {
249
        err.submit(ERR_EMPTY_OPTION); return;    // Warning: empty option
250
    }
251
 
252
    // Detect option type
253
    switch(string[0] | 0x20) {
254
    case 'a':   // assemble option
255
        if (job) err.submit(ERR_MULTIPLE_COMMANDS, string);     // More than one job specified
256
        job = CMDL_JOB_ASS;
257
        if (strncasecmp_(string, "ass", 3) == 0) {
258
            interpretAssembleOption(string+3);
259
        }
260
        else err.submit(ERR_UNKNOWN_OPTION, string);     // Unknown option
261
        break;
262
 
263
    case 'c':   // codesize option
264
        if (strncasecmp_(string, "codesize", 8) == 0) {
265
            interpretCodeSizeOption(string+8);
266
        }
267
        else err.submit(ERR_UNKNOWN_OPTION, string);     // Unknown option
268
        break;
269
 
270
 
271
    case 'd':   // disassemble, dump, debug or datasize option
272
        if (strncasecmp_(string, "dis", 3) == 0) {
273
            if (job) err.submit(ERR_MULTIPLE_COMMANDS, string);     // More than one job specified
274
            job = CMDL_JOB_DIS;
275
            interpretDisassembleOption(string+3);  break;
276
        }
277
        if (strncasecmp_(string, "dump", 4) == 0) {
278
            if (job) err.submit(ERR_MULTIPLE_COMMANDS, string);     // More than one job specified
279
            job = CMDL_JOB_DUMP;
280
            interpretDumpOption(string+4);  break;
281
        }
282
        if (strncasecmp_(string, "datasize", 8) == 0) {
283
            interpretDataSizeOption(string+8);
284
            break;
285
        }
286
        if (strncasecmp_(string, "debug", 5) == 0) {
287
            interpretDebugOption(string+5);
288
            break;
289
        }
290
 
291
        err.submit(ERR_UNKNOWN_OPTION, string);     // Unknown option
292
        break;
293
 
294
    case 'e':    // Emulation or error option
295
        if (strncasecmp_(string, "emu", 3) == 0) {
296
            if (job) err.submit(ERR_MULTIPLE_COMMANDS, string);     // More than one job specified
297
            job = CMDL_JOB_EMU;
298
            emumode = 1;
299
        }
300
        else {
301
            interpretErrorOption(string);
302
        }
303
        break;
304
 
305
    case 'h': case '?':  // Help
306
        job = CMDL_JOB_HELP;
307
        break;
308
 
309
    case 'i':   // Instruction list
310
        if (strncasecmp_(string, "ilist=", 6) == 0) {
311
        interpretIlistOption(string+6);
312
        }
313
        else {
314
            err.submit(ERR_UNKNOWN_OPTION, string);     // Unknown option
315
        }
316
        break;
317
 
318
    case 'l':   // Link, Library, and list file options
319
        if (strncasecmp_(string, "lib", 3) == 0) {
320
            if (job) err.submit(ERR_MULTIPLE_COMMANDS, string);     // More than one job specified
321
            job = CMDL_JOB_LIB;
322
            interpretLibraryCommand(string+3);  break;
323
        }
324
        if (strncasecmp_(string, "link", 4) == 0) {
325
            if (job) err.submit(ERR_MULTIPLE_COMMANDS, string);     // More than one job specified
326
            job = CMDL_JOB_LINK;  outputType = FILETYPE_FWC_EXE;
327
            interpretLinkCommand(string+4);  break;
328
        }
329
        if (strncasecmp_(string, "list=", 5) == 0) {
330
            interpretListOption(string+5);  break;
331
        }
332
        err.submit(ERR_UNKNOWN_OPTION, string);     // Unknown option
333
        break;
334
 
335
    case 'm':    // Maxerrors option
336
        if (strncasecmp_(string, "maxerrors", 9) == 0) {
337
            interpretMaxErrorsOption(string+9);  break;
338
        }
339
        err.submit(ERR_UNKNOWN_OPTION, string);     // Unknown option
340
        break;
341
 
342
    case 'o':    // Optimization option
343
        interpretOptimizationOption(string+1);
344
        break;
345
 
346
    case 'r':    // Relink command
347
        if (strncasecmp_(string, "relink", 6) == 0) {
348
            if (job) err.submit(ERR_MULTIPLE_COMMANDS, string);     // More than one job specified
349
            job = CMDL_JOB_RELINK;  outputType = FILETYPE_FWC_EXE;
350
            interpretLinkCommand(string+6);  break;
351
        }
352
        break;
353
 
354
    case 'v':    // verbose/silent
355
        interpretVerboseOption(string+1);
356
        break;
357
 
358
    case 'w':    // Warning option
359
        interpretErrorOption(string);  break;
360
 
361
    default:    // Unknown option
362
        err.submit(ERR_UNKNOWN_OPTION, string);
363
    }
364
}
365
 
366
void CCommandLineInterpreter::interpretAssembleOption(char * string) {
367
    if ((string[0] | 0x20) == 'b') dumpOptions = 2; // binary listing!
368
    else if (string[0] == 0 || (string[0] | 0x20) == 'e') outputType = FILETYPE_FWC;
369
    else interpretCommandOption(string);
370
}
371
 
372
void CCommandLineInterpreter::interpretDisassembleOption(char * string) {
373
    outputType = CMDL_OUTPUT_ASM;
374
}
375
 
376
void CCommandLineInterpreter::interpretDumpOption(char * string) {
377
    // Interpret dump option from command line
378
    if (outputType /*&& outputType != outputType*/) {
379
        err.submit(ERR_MULTIPLE_COMMANDS, string);   // Both dump and convert specified
380
    }
381
    char * s1 = string;
382
    while (*s1) {
383
        switch (*(s1++) | 0x20) {
384
        case 'l':   // dump link map
385
            dumpOptions |= DUMP_LINKMAP;  break;
386
        case 'f':   // dump file header
387
            dumpOptions |= DUMP_FILEHDR;  break;
388
        case 'h':   // dump section headers
389
            dumpOptions |= DUMP_SECTHDR;  break;
390
        case 's':   // dump symbol table
391
            dumpOptions |= DUMP_SYMTAB;  break;
392
        case 'r':   // dump relocations
393
            dumpOptions |= DUMP_RELTAB;  break;
394
        case 'n':   // dump string table
395
            dumpOptions |= DUMP_STRINGTB;  break;
396
        case 'm':   // show names of relinkable modules and libraries
397
            dumpOptions |= DUMP_RELINKABLE;  break;
398
        case 'c':   // dump comment records (currently only for OMF)
399
            dumpOptions |= DUMP_COMMENT;  break;
400
        case '-': case '_':  // '-' may separate options
401
            break;
402
        default:
403
            err.submit(ERR_UNKNOWN_OPTION, string-1);  // Unknown option
404
        }
405
    }
406
    outputType = CMDL_OUTPUT_DUMP;
407
}
408
 
409
void CCommandLineInterpreter::interpretEmulateOption(char * string) {
410
    // Interpret emulate options
411
    if ((uint8_t)*string <= (uint8_t)' ') {
412
        err.submit(ERR_EMPTY_OPTION); return;    // Warning: empty option
413
    }
414
    // Detect option type
415
    switch(string[0] | 0x20) {
416
    case 'l':   // list option
417
        if (strncasecmp_(string, "list=", 5) == 0) {
418
            interpretListOption(string+5);  break;
419
        }
420
        err.submit(ERR_UNKNOWN_OPTION, string-1);  // Unknown option
421
        break;
422
    case 'm':
423
        if (strncasecmp_(string, "maxerrors", 9) == 0) {
424
            interpretMaxErrorsOption(string + 9);  break;
425
        }
426
        if (strncasecmp_(string, "maxlines", 8) == 0) {
427
            interpretMaxLinesOption(string + 8);  break;
428
        }
429
        err.submit(ERR_UNKNOWN_OPTION, string);     // Unknown option
430
        break;
431
    }
432
 
433
}
434
 
435
void CCommandLineInterpreter::interpretLibraryCommand(char * string) {
436
    // Interpret options for manipulating library/archive files
437
 
438
    // meaning of libmode:
439
    // 0: not a library command
440
    // 1: after "-lib". expecting library name
441
    // 2: after library name or -a. expecting command or object files to add
442
    // 3: after "-d". expecting object files to delete
443
    // 4: after "-l". list all members
444
    // 5: after "-x". expecting object files to extract
445
    // 6: after "-xall". extract all members
446
 
447
    // Check for -lib command
448
    if (inputFile) {
449
        libmode = 2;                  // Input file already specified. Remaining file names are object files to add
450
    }
451
    else {
452
        libmode = 1;                  // The rest of the command line must be interpreted as library name and object file names
453
    }
454
    fileOptions |= CMDL_FILE_IN_IF_EXISTS | CMDL_FILE_IN_OUT_SAME;
455
}
456
 
457
// interpret library commands
458
void CCommandLineInterpreter::interpretLibraryOption(char * string) {
459
    switch (string[0] | 0x20) {
460
    case 'a':      // Add input file to library
461
        libmode = 2;
462
        libraryOptions = CMDL_LIBRARY_ADDMEMBER;
463
        break;
464
 
465
    case 'd':   // Delete member from library
466
        libmode = 3;
467
        libraryOptions = CMDL_LIBRARY_DELETEMEMBER;
468
        break;
469
 
470
    case 'l':
471
        libmode = 4;
472
        if (libraryOptions) { // cannot combine with other commands
473
            err.submit(ERR_LIBRARY_LIST_ONLY);  return;
474
        }
475
        libraryOptions = CMDL_LIBRARY_LISTMEMBERS;
476
        if (string[1] > ' ') verbose = atoi(string+1);
477
        return;
478
 
479
    case 'v':    // verbose/silent
480
        interpretVerboseOption(string+1);
481
        return;
482
 
483
    case 'x':      // Extract member(s) from library
484
        libmode = 5;
485
        libraryOptions = CMDL_LIBRARY_EXTRACTMEM;
486
        if (strncasecmp_(string+2, "all", 3) == 0) {
487
            libmode = 6;
488
            cmd.libraryOptions = CMDL_LIBRARY_EXTRACTALL;
489
            if (string[5] > ' ') err.submit(ERR_UNKNOWN_OPTION, string);
490
            return;
491
        }
492
        break;
493
 
494
    default:
495
        err.submit(ERR_UNKNOWN_OPTION, string);  // Unknown option
496
    }
497
    // check if immediately followed by filename
498
    if (string[1] > ' ') interpretFileName(string+2);
499
}
500
 
501
 
502
// Interpret -link command
503
void CCommandLineInterpreter::interpretLinkCommand(char * string) {
504
    if (inputFile) {
505
        linkmode = CMDL_LINK_ADDMODULE;                  // executable file already specified. Remaining file names are object files and library files to add
506
    }
507
    else {
508
        linkmode = CMDL_LINK_EXEFILE;                  // The rest of the command line must be interpreted as executable name and object file names
509
    }
510
    if (job == CMDL_JOB_LINK) {
511
        fileOptions |= CMDL_FILE_IN_IF_EXISTS | CMDL_FILE_IN_OUT_SAME;
512
    }
513
}
514
 
515
 
516
// interpret linker options
517
void CCommandLineInterpreter::interpretLinkOption(char * string) {
518
    switch (string[0] | 0x20) {
519
    case 'a':      // Add input file to executable
520
        linkmode = CMDL_LINK_ADDMODULE;
521
        linkOptions = CMDL_LINK_ADDMODULE;
522
        break;
523
 
524
    case 'r':   // Add input files as relinkable
525
        linkmode = CMDL_LINK_ADDMODULE;
526
        linkOptions = CMDL_LINK_ADDMODULE | CMDL_LINK_RELINKABLE;
527
        fileOptions |= CMDL_FILE_RELINKABLE;
528
        break;
529
 
530
    case 'l':
531
        linkmode = CMDL_LINK_LIST;
532
        if (linkOptions) { // cannot combine with other commands
533
            err.submit(ERR_LINK_LIST_ONLY);  return;
534
        }
535
        linkOptions = CMDL_LINK_LIST;
536
        if (string[1] > ' ') verbose = atoi(string+1);
537
        return;
538
 
539
    case 'm':
540
        if (strncasecmp_(string, "map=", 4) == 0) { // map option
541
            outputListFile = fileNameBuffer.pushString(string+4);
542
            return;
543
        }
544
        // Explicitly add specified module from previously specified library
545
        linkmode = CMDL_LINK_ADDLIBMODULE;
546
        linkOptions = CMDL_LINK_ADDLIBMODULE | (linkOptions & CMDL_LINK_RELINKABLE);
547
        break;
548
 
549
    case 'x':      // Extract module from relinkable executable file
550
        linkmode = CMDL_LINK_EXTRACT;
551
        linkOptions = CMDL_LINK_EXTRACT;
552
        libraryOptions = CMDL_LIBRARY_EXTRACTMEM;
553
        if (strncasecmp_(string+1, "all", 3) == 0) {
554
            libmode = CMDL_LINK_EXTRACT_ALL;
555
            libraryOptions = CMDL_LIBRARY_EXTRACTALL;
556
            if (string[5] > ' ') err.submit(ERR_UNKNOWN_OPTION, string);
557
            return;
558
        }
559
        break;
560
 
561
    case 'u':
562
        fileOptions |= CMDL_FILE_INCOMPLETE | CMDL_FILE_RELINKABLE;
563
        if (string[1] > ' ')
564
            err.submit(ERR_UNKNOWN_OPTION, string);
565
        return;
566
 
567
    case 'v':    // verbose/silent
568
        interpretVerboseOption(string+1);
569
        return;
570
 
571
    case 's':    // stacksize
572
        if (strncasecmp_(string, "stack=", 6) == 0) {
573
            interpretStackOption(string+6);
574
            return;
575
        }
576
        break;
577
 
578
    case 'h':    // heapsize
579
        if (strncasecmp_(string, "heap=", 5) == 0) {
580
            interpretHeapOption(string+5);
581
            return;
582
        }
583
        else if (strncasecmp_(string, "hex", 3) == 0) {
584
            interpretHexfileOption(string+3);
585
            return;
586
        }
587
        break;
588
 
589
    case 'd':
590
        if (strncasecmp_(string, "debug", 5) == 0) {
591
            interpretDebugOption(string+5);
592
            return;
593
        }
594
        if (strncasecmp_(string, "dynlink=", 8) == 0) {
595
            interpretDynlinkOption(string+8);  // space for dynamic linking
596
            return;
597
        }
598
        // Remove relinkable modules
599
        linkmode = CMDL_LINK_REMOVE;
600
        linkOptions = CMDL_LINK_REMOVE;
601
        break;
602
 
603
    case 'e':  case 'w':
604
        interpretErrorOption(string);
605
        return;
606
 
607
    default:
608
        err.submit(ERR_UNKNOWN_OPTION, string);  // Unknown option
609
        return;
610
    }
611
    // check if immediately followed by filename
612
    if (string[1] > ' ') interpretFileName(string+1);
613
}
614
 
615
void CCommandLineInterpreter::interpretIlistOption(char * string) {
616
    // Interpret instruction list file option for assembler
617
    instructionListFile = fileNameBuffer.pushString(string);
618
}
619
 
620
void CCommandLineInterpreter::interpretListOption(char * string) {
621
    // Interpret instruction list file option for assembler
622
    outputListFile = fileNameBuffer.pushString(string);
623
    if (maxLines == 0) maxLines = 1000;
624
}
625
 
626
void CCommandLineInterpreter::interpretStackOption(char * string) {
627
    // Interpret stack size option for linker
628
    // stack=number1,number2,number3
629
    // number1 = call stack size, bytes
630
    // number2 = data stack size, bytes
631
    // number3 = additional size for vectors on data stack. value will be multiplied by maximum vector length
632
    SLCommand linkcmd;       // command record
633
    uint32_t e;              // return code from interpretNumber
634
    linkcmd.filename = 0;
635
    linkcmd.command = CMDL_LINK_STACKSIZE;
636
    linkcmd.value = interpretNumber(string, 32, &e);   // get first number = call stack size
637
    if (e && !(e & 0x1000)) {err.submit(ERR_UNKNOWN_OPTION, string);  return;}
638
    lcommands.push(linkcmd);                           // save first number
639
    if (e & 0x1000) { // second number specified
640
        string += (e & 0xFFF) + 1;
641
        linkcmd.command++;
642
        linkcmd.value = interpretNumber(string, 32, &e);   // get second number = data stack size
643
        if (e && !(e & 0x1000)) {err.submit(ERR_UNKNOWN_OPTION, string);  return;}
644
        lcommands.push(linkcmd);                           // save second number
645
        if (e & 0x1000) { // third number specified
646
            string += (e & 0xFFF) + 1;
647
            linkcmd.command++;
648
            linkcmd.value = interpretNumber(string, 32, &e);   // get third number = number of vectors on data stack
649
            if (e) {err.submit(ERR_UNKNOWN_OPTION, string);  return;}
650
            lcommands.push(linkcmd);                           // save third number
651
        }
652
    }
653
}
654
 
655
void CCommandLineInterpreter::interpretHeapOption(char * string) {
656
// Interpret heap size option for linker
657
// Interpret stack size option for linker
658
// heap=number
659
// number = heap size, bytes
660
    SLCommand linkcmd;       // command record
661
    uint32_t e;              // return code from interpretNumber
662
    linkcmd.filename = 0;
663
    linkcmd.command = CMDL_LINK_HEAPSIZE;
664
    linkcmd.value = interpretNumber(string, 32, &e);   // get first number = call stack size
665
    if (e) {err.submit(ERR_UNKNOWN_OPTION, string);  return;}
666
    lcommands.push(linkcmd);
667
}
668
 
669
void CCommandLineInterpreter::interpretHexfileOption(char * string) {
670
    // Interpret hexfile option for linker
671
    cmd.outputType = FILETYPE_FWC_HEX;
672
    uint32_t e;              // return code from interpretNumber
673
    cmd.maxLines = (uint32_t)interpretNumber(string, 32, &e);   // get first number = call stack size
674
    if (e) {err.submit(ERR_UNKNOWN_OPTION, string);  return;}
675
}
676
 
677
 
678
void CCommandLineInterpreter::interpretDynlinkOption(char * string) {
679
// Interpret dynamic link size option for linker
680
// dynlink=number1,number2,number3
681
// number1 = size for read-only data, bytes
682
// number2 = size for executable section, bytes
683
// number3 = size for writeable static data, bytes
684
    SLCommand linkcmd;       // command record
685
    uint32_t e;              // return code from interpretNumber
686
    linkcmd.filename = 0;
687
    linkcmd.command = CMDL_LINK_DYNLINKSIZE;
688
    linkcmd.value = interpretNumber(string, 32, &e);   // get first number = read-only
689
    if (e && !(e & 0x1000)) {err.submit(ERR_UNKNOWN_OPTION, string);  return;}
690
    lcommands.push(linkcmd);                           // save first number
691
    if (e & 0x1000) { // second number specified
692
        string += (e & 0xFFF) + 1;
693
        linkcmd.command++;
694
        linkcmd.value = interpretNumber(string, 32, &e);   // get second number = executable section
695
        if (e && !(e & 0x1000)) {err.submit(ERR_UNKNOWN_OPTION, string);  return;}
696
        lcommands.push(linkcmd);                           // save second number
697
        if (e & 0x1000) { // third number specified
698
            string += (e & 0xFFF) + 1;
699
            linkcmd.command++;
700
            linkcmd.value = interpretNumber(string, 32, &e);   // get third number = writeable data
701
            if (e & ~0x1000) {err.submit(ERR_UNKNOWN_OPTION, string);  return;}
702
            lcommands.push(linkcmd);                           // save third number
703
        }
704
    }
705
}
706
 
707
void CCommandLineInterpreter::interpretOptimizationOption(char * string) {
708
    if (string[0] < '0' || string[0] > '9' || strlen(string) != 1) {
709
        err.submit(ERR_UNKNOWN_OPTION, string); return; // Unknown option
710
    }
711
    optiLevel = string[0] - '0';
712
}
713
 
714
void CCommandLineInterpreter::interpretVerboseOption(char * string) {
715
    // Interpret silent/verbose option from command line
716
    verbose = atoi(string);
717
}
718
 
719
void CCommandLineInterpreter::interpretMaxErrorsOption(char * string) {
720
    // Interpret maxerrors option from command line
721
    if (string[0] == '=') string++;
722
    uint32_t error = 0;
723
    maxErrors = (uint32_t)interpretNumber(string, 99, &error);
724
    if (error) err.submit(ERR_UNKNOWN_OPTION, string);
725
}
726
 
727
void CCommandLineInterpreter::interpretCodeSizeOption(char * string) {
728
    // Interpret codesize option from command line
729
    uint32_t error = 0;
730
    codeSizeOption = interpretNumber(string, 99, &error);
731
    if (error) err.submit(ERR_UNKNOWN_OPTION, string);
732
}
733
 
734
void CCommandLineInterpreter::interpretDataSizeOption(char * string) {
735
    // Interpret datasize option from command line
736
    uint32_t error = 0;
737
    dataSizeOption = interpretNumber(string+1, 99, &error);
738
    if (error) err.submit(ERR_UNKNOWN_OPTION, string);
739
}
740
 
741
void CCommandLineInterpreter::interpretDebugOption(char * string) {
742
    // Interpret debug option from command line
743
    uint32_t error = 0;
744
    if (string[0] == 0) {
745
        debugOptions = 1;
746
        return;
747
    }
748
    debugOptions = (uint32_t)interpretNumber(string+1, 99, &error);
749
    if (error) err.submit(ERR_UNKNOWN_OPTION, string);
750
}
751
 
752
void CCommandLineInterpreter::interpretErrorOption(char * string) {
753
    // Interpret warning/error option from command line
754
    if (strlen(string) < 3) {
755
        err.submit(ERR_UNKNOWN_OPTION, string); return; // Unknown option
756
    }
757
    int newstatus;   // New status for this error number
758
 
759
    switch (string[1]) {
760
    case 'd':   // Disable
761
        newstatus = 0;  break;
762
 
763
    case 'w':   // Treat as warning
764
        newstatus = 1;  break;
765
 
766
    case 'e':   // Treat as error
767
        newstatus = 2;  break;
768
 
769
    default:
770
        err.submit(ERR_UNKNOWN_OPTION, string);  // Unknown option
771
        return;
772
    }
773
    if (string[2] == 'x' ) {
774
        // Apply new status to all non-fatal messages
775
        for (SErrorText * ep = errorTexts; ep->status < 9; ep++) {
776
            ep->status = newstatus;  // Change status of all errors
777
        }
778
    }
779
    else {
780
        int ErrNum = atoi(string+2);
781
        if (ErrNum == 0 && string[2] != '0') {
782
            err.submit(ERR_UNKNOWN_OPTION, string);  return; // Unknown option
783
        }
784
        // Search for this error number
785
        SErrorText * ep = err.FindError(ErrNum);
786
        if (ep->status & 0x100) {
787
            // Error number not found
788
            err.submit(ERR_UNKNOWN_ERROR_NUM, ErrNum);  return; // Unknown error number
789
        }
790
        // Change status of this error
791
        ep->status = newstatus;
792
    }
793
}
794
 
795
void CCommandLineInterpreter::interpretMaxLinesOption(char * string) {
796
    // Interpret maxlines option from command line
797
    if (string[0] == '=') string++;
798
    uint32_t error = 0;
799
    maxLines = (uint32_t)interpretNumber(string, 99, &error);
800
    if (error) err.submit(ERR_UNKNOWN_OPTION, string);
801
}
802
 
803
 
804
void CCommandLineInterpreter::reportStatistics() {
805
    // Report statistics about name changes etc.
806
}
807
 
808
 
809
void CCommandLineInterpreter::checkExtractSuccess() {
810
    // Check if library members to extract were found
811
    //!
812
}
813
 
814
 
815
void CCommandLineInterpreter::checkOutputFileName() {
816
    // Make output file name or check that requested name is valid
817
    if (!(fileOptions & CMDL_FILE_OUTPUT)) return;
818
 
819
    if (outputFile == 0) {
820
        // Output file name not specified. Make filename    
821
        outputFile = setFileNameExtension(inputFile, outputType);
822
    }
823
    // Check if input and output files have same name
824
    if (strcmp(getFilename(inputFile), getFilename(outputFile)) == 0 && !(cmd.fileOptions & CMDL_FILE_IN_OUT_SAME)) {
825
        err.submit(ERR_FILES_SAME_NAME, getFilename(inputFile));
826
    }
827
}
828
 
829
 
830
uint32_t CCommandLineInterpreter::setFileNameExtension(uint32_t fn, int filetype) {
831
    // Set file name extension for output file according to FileType
832
    // Names are stored as indexes into cmd.fileNameBuffer
833
 
834
    // get old name
835
    const char * name1 = getFilename(fn);
836
    int i;
837
    uint32_t newname = 0;
838
 
839
    // Search for last '.' in file name
840
    for (i = (int)strlen(name1)-1; i > 0; i--) if (name1[i] == '.') break;
841
    if (i < 1) {
842
        // '.' not found. Append '.' to name
843
        i = (int)strlen(name1);
844
    }
845
    // Get default extension
846
    const char * defaultExtension;
847
    switch (filetype) {
848
    case FILETYPE_ASM:
849
        // don't give disassembly the same extension because it may overwrite the original assembly file
850
        defaultExtension = ".das"; break;
851
    case FILETYPE_FWC: case FILETYPE_ELF:
852
        defaultExtension = ".ob"; break;
853
    case FILETYPE_FWC_EXE:
854
        defaultExtension = ".ex"; break;
855
    case FILETYPE_FWC_LIB:
856
        defaultExtension = ".li"; break;
857
    case FILETYPE_FWC_HEX:
858
        defaultExtension = ".hex"; break;
859
    default:
860
        defaultExtension = ".txt";
861
    }
862
    // generate new name in cmd.fileNameBuffer
863
    newname = fileNameBuffer.push(name1, i + (uint32_t)strlen(defaultExtension) + 1);
864
    strcpy((char*)cmd.fileNameBuffer.buf() + newname + i, defaultExtension);
865
    return newname;
866
}
867
 
868
// Get file name from index into fileNameBuffer
869
const char * CCommandLineInterpreter::getFilename(uint32_t n) {
870
    if (n >= fileNameBuffer.dataSize()) return "unknown?";
871
    return (const char *)fileNameBuffer.buf() + n;
872
}
873
 
874
 
875
void CCommandLineInterpreter::help() {
876
    // Print help message
877
    printf("\nBinary tools version %i.%02i for ForwardCom instruction set.", FORWARDCOM_VERSION, FORWARDCOM_SUBVERSION);
878
    printf("\nCopyright (c) 2021 by Agner Fog. Gnu General Public License.");
879
    printf("\n\nUsage: forw command [options] inputfile [outputfile] [options]");
880
    printf("\n\nCommand:");
881
    printf("\n-ass       Assemble\n");
882
    printf("\n-dis       Disassemble object or executable file\n");
883
    printf("\n-link      Link object files into executable file\n");
884
    printf("\n-relink    Relink and modify executable file\n");
885
    printf("\n-lib       Build or manage library file\n");
886
    printf("\n-emu       Emulate and debug executable file\n");
887
    printf("\n-dump-XXX  Dump file contents to console.");
888
    printf("\n           Values of XXX (can be combined):");
889
    printf("\n           f: File header, h: section Headers, s: Symbol table,");
890
    printf("\n           m: Relinkable modules, r: Relocation table, n: string table.\n");
891
    printf("\n-help      Print this help screen.");
892
 
893
    printf("\n\nAssemble options:");
894
    printf("\n-list=filename Specify file for output listing.");
895
    printf("\n-ON        Optimization level. N = 0-2.");
896
 
897
    printf("\n\nGeneral options:");
898
    printf("\n-ilist=filename Specify instruction list file.");
899
    printf("\n-wdNNN     Disable Warning NNN.");
900
    printf("\n-weNNN     treat Warning NNN as Error. -wex: treat all warnings as errors.");
901
    printf("\n-edNNN     Disable Error number NNN.");
902
    printf("\n-ewNNN     treat Error number NNN as Warning.");
903
    printf("\n@RFILE     Read additional options from response file RFILE.");
904
    printf("\n\nExample:");
905
    printf("\nforw -ass test.as test.ob");
906
    printf("\nforw -link test.ex test.ob libc.li");
907
    printf("\nforw -emu test.ex -list=debugout.txt");
908
    printf("\n\nSee the manual for more options.\n");
909
}
910
 
911
// compare strings, ignore case for a-z
912
int strncasecmp_(const char *s1, const char *s2, uint32_t n) {
913
    //return strnicmp(s1, s2, n);          // MS
914
    //return strncasecmp(s1, s2, n);       // Linux
915
    for (uint32_t i = 0; i < n; i++) {     // loop through string
916
        char c1 = s1[i];
917
        char c2 = s2[i];
918
        if (uint8_t(c1-'A') <= uint8_t('Z' - 'A')) c1 |= 0x20; // convert A-Z to a-z
919
        if (uint8_t(c2-'A') <= uint8_t('Z' - 'A')) c2 |= 0x20; // convert A-Z to a-z
920
        if (c1 != c2) return int(c1) - int(c2);                // difference found
921
        if (c1 == 0) break;                                    // end of string
922
    }
923
    return 0;                                                  // no difference between strings
924
}

powered by: WebSVN 2.1.0

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