mirror of
https://github.com/pfusik/xasm.git
synced 2025-01-13 21:35:29 +00:00
Allow stdin/stdout instead of files for source and object.
This commit is contained in:
parent
afb9f7830e
commit
2f67b3bab4
91
source/app.d
91
source/app.d
@ -25,26 +25,24 @@ import std.math;
|
|||||||
import std.path;
|
import std.path;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.string;
|
import std.string;
|
||||||
|
import std.exception : assumeUnique;
|
||||||
|
import std.range : empty, front, popFront;
|
||||||
|
|
||||||
version (Windows) {
|
version (Windows) {
|
||||||
import core.sys.windows.windows;
|
import core.sys.windows.windows;
|
||||||
}
|
}
|
||||||
|
|
||||||
int readByte(File *file) {
|
|
||||||
char c;
|
|
||||||
if (file.readf("%c", &c) != 1)
|
|
||||||
return -1;
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
const string TITLE = "xasm 3.2.0";
|
const string TITLE = "xasm 3.2.0";
|
||||||
|
|
||||||
|
File messageStream;
|
||||||
|
|
||||||
string sourceFilename = null;
|
string sourceFilename = null;
|
||||||
bool[26] options;
|
bool[26] options;
|
||||||
string[26] optionParameters;
|
string[26] optionParameters;
|
||||||
string[] commandLineDefinitions = null;
|
string[] commandLineDefinitions = null;
|
||||||
string objectFilename = null;
|
string objectFilename = null;
|
||||||
string[] makeSources = null;
|
string[] makeSources = null;
|
||||||
|
immutable(ubyte)[][string] sourceFiles;
|
||||||
|
|
||||||
int exitCode = 0;
|
int exitCode = 0;
|
||||||
|
|
||||||
@ -176,13 +174,14 @@ File objectStream;
|
|||||||
|
|
||||||
int objectBytes = 0;
|
int objectBytes = 0;
|
||||||
|
|
||||||
|
|
||||||
bool getOption(char letter) {
|
bool getOption(char letter) {
|
||||||
assert(letter >= 'a' && letter <= 'z');
|
assert(letter >= 'a' && letter <= 'z');
|
||||||
return options[letter - 'a'];
|
return options[letter - 'a'];
|
||||||
}
|
}
|
||||||
|
|
||||||
void warning(string msg, bool error = false) {
|
void warning(string msg, bool error = false) {
|
||||||
stdout.flush();
|
messageStream.flush();
|
||||||
version (Windows) {
|
version (Windows) {
|
||||||
HANDLE stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
|
HANDLE stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
|
||||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||||
@ -1087,7 +1086,7 @@ File openInputFile(string filename) {
|
|||||||
|
|
||||||
File openOutputFile(string filename, string msg) {
|
File openOutputFile(string filename, string msg) {
|
||||||
if (!getOption('q'))
|
if (!getOption('q'))
|
||||||
writeln(msg);
|
messageStream.writeln(msg);
|
||||||
try {
|
try {
|
||||||
return File(filename, "wb");
|
return File(filename, "wb");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -1185,8 +1184,11 @@ void objectByte(ubyte b) {
|
|||||||
} else {
|
} else {
|
||||||
assert(pass2);
|
assert(pass2);
|
||||||
if (!optionObject) return;
|
if (!optionObject) return;
|
||||||
if (!objectStream.isOpen)
|
if (!objectStream.isOpen) {
|
||||||
objectStream = openOutputFile(objectFilename, "Writing object file...");
|
objectStream = objectFilename == "-"
|
||||||
|
? stdout
|
||||||
|
: openOutputFile(objectFilename, "Writing object file...");
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
objectStream.write(cast(char) b);
|
objectStream.write(cast(char) b);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -2302,7 +2304,6 @@ void assemblyIns() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
File stream = openInputFile(filename);
|
File stream = openInputFile(filename);
|
||||||
scope (exit) stream.close();
|
|
||||||
try {
|
try {
|
||||||
stream.seek(offset, offset >= 0 ? SEEK_SET : SEEK_END);
|
stream.seek(offset, offset >= 0 ? SEEK_SET : SEEK_END);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -2311,13 +2312,13 @@ void assemblyIns() {
|
|||||||
if (inOpcode)
|
if (inOpcode)
|
||||||
length = 1;
|
length = 1;
|
||||||
while (length != 0) {
|
while (length != 0) {
|
||||||
int b = readByte(&stream);
|
ubyte[1] b;
|
||||||
if (b < 0) {
|
if (stream.rawRead(b).length != 1) {
|
||||||
if (length > 0)
|
if (length > 0)
|
||||||
throw new AssemblyError("File is too short");
|
throw new AssemblyError("File is too short");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
putByte(cast(ubyte) b);
|
putByte(b[0]);
|
||||||
if (length > 0) length--;
|
if (length > 0) length--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2796,11 +2797,17 @@ void assemblyLine() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void assemblyFile(string filename) {
|
void assemblyFile(string filename) {
|
||||||
|
immutable(ubyte)[] source = sourceFiles.require(filename, {
|
||||||
|
File stream = stdin;
|
||||||
|
if (filename != "-") {
|
||||||
filename = filename.defaultExtension("asx");
|
filename = filename.defaultExtension("asx");
|
||||||
if (getOption('p'))
|
if (getOption('p'))
|
||||||
filename = absolutePath(filename);
|
filename = absolutePath(filename);
|
||||||
File stream = openInputFile(filename);
|
stream = openInputFile(filename);
|
||||||
scope (exit) stream.close();
|
}
|
||||||
|
return stream.byChunk(65536).joiner.array.assumeUnique;
|
||||||
|
}());
|
||||||
|
|
||||||
string oldFilename = currentFilename;
|
string oldFilename = currentFilename;
|
||||||
int oldLineNo = lineNo;
|
int oldLineNo = lineNo;
|
||||||
currentFilename = filename;
|
currentFilename = filename;
|
||||||
@ -2808,16 +2815,18 @@ void assemblyFile(string filename) {
|
|||||||
foundEnd = false;
|
foundEnd = false;
|
||||||
line = "";
|
line = "";
|
||||||
readChar: while (!foundEnd) {
|
readChar: while (!foundEnd) {
|
||||||
int b = readByte(&stream);
|
if (source.empty)
|
||||||
|
break;
|
||||||
|
ubyte b = source.front;
|
||||||
|
source.popFront;
|
||||||
switch (b) {
|
switch (b) {
|
||||||
case -1:
|
|
||||||
break readChar;
|
|
||||||
case '\r':
|
case '\r':
|
||||||
assemblyLine();
|
assemblyLine();
|
||||||
line = "";
|
line = "";
|
||||||
b = readByte(&stream);
|
if (source.empty)
|
||||||
if (b < 0)
|
|
||||||
break readChar;
|
break readChar;
|
||||||
|
b = source.front;
|
||||||
|
source.popFront;
|
||||||
if (b != '\n')
|
if (b != '\n')
|
||||||
line ~= cast(char) b;
|
line ~= cast(char) b;
|
||||||
break;
|
break;
|
||||||
@ -2944,10 +2953,17 @@ int main(string[] args) {
|
|||||||
else {
|
else {
|
||||||
if (sourceFilename is null)
|
if (sourceFilename is null)
|
||||||
exitCode = 3;
|
exitCode = 3;
|
||||||
|
objectFilename = optionParameters['o' - 'a'];
|
||||||
|
if (objectFilename is null) {
|
||||||
|
objectFilename = sourceFilename == "-"
|
||||||
|
? "-"
|
||||||
|
: sourceFilename.setExtension("obx");
|
||||||
|
}
|
||||||
|
messageStream = objectFilename == "-" ? stderr : stdout;
|
||||||
if (!getOption('q'))
|
if (!getOption('q'))
|
||||||
writeln(TITLE);
|
messageStream.writeln(TITLE);
|
||||||
if (exitCode != 0) {
|
if (exitCode != 0) {
|
||||||
write(
|
messageStream.write(
|
||||||
`Syntax: xasm SOURCE [OPTIONS]
|
`Syntax: xasm SOURCE [OPTIONS]
|
||||||
-c Include false conditionals in listing
|
-c Include false conditionals in listing
|
||||||
-d LABEL=VALUE Define a label
|
-d LABEL=VALUE Define a label
|
||||||
@ -2962,9 +2978,6 @@ int main(string[] args) {
|
|||||||
`);
|
`);
|
||||||
return exitCode;
|
return exitCode;
|
||||||
}
|
}
|
||||||
objectFilename = optionParameters['o' - 'a'];
|
|
||||||
if (objectFilename is null)
|
|
||||||
objectFilename = sourceFilename.setExtension("obx");
|
|
||||||
try {
|
try {
|
||||||
assemblyPass();
|
assemblyPass();
|
||||||
pass2 = true;
|
pass2 = true;
|
||||||
@ -2974,22 +2987,24 @@ int main(string[] args) {
|
|||||||
} catch (AssemblyError e) {
|
} catch (AssemblyError e) {
|
||||||
warning(e.msg, true);
|
warning(e.msg, true);
|
||||||
exitCode = 2;
|
exitCode = 2;
|
||||||
|
if (objectFilename != "-") {
|
||||||
objectStream.close();
|
objectStream.close();
|
||||||
core.stdc.stdio.remove(toStringz(objectFilename));
|
core.stdc.stdio.remove(toStringz(objectFilename));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
listingStream.close();
|
listingStream.close();
|
||||||
objectStream.close();
|
objectStream.close();
|
||||||
if (exitCode <= 1) {
|
if (exitCode <= 1) {
|
||||||
if (!getOption('q')) {
|
if (!getOption('q')) {
|
||||||
writefln("%d lines of source assembled", totalLines);
|
messageStream.writefln("%d lines of source assembled", totalLines);
|
||||||
if (objectBytes > 0)
|
if (objectBytes > 0)
|
||||||
writefln("%d bytes written to the object file", objectBytes);
|
messageStream.writefln("%d bytes written to the object file", objectBytes);
|
||||||
}
|
}
|
||||||
if (getOption('m')) {
|
if (getOption('m')) {
|
||||||
writef("%s:", makeEscape(objectFilename));
|
messageStream.writef("%s:", makeEscape(objectFilename));
|
||||||
foreach (filename; makeSources)
|
foreach (filename; makeSources)
|
||||||
writef(" %s", makeEscape(filename));
|
messageStream.writef(" %s", makeEscape(filename));
|
||||||
write("\n\txasm");
|
messageStream.write("\n\txasm");
|
||||||
for (int i = 1; i < args.length; i++) {
|
for (int i = 1; i < args.length; i++) {
|
||||||
string arg = args[i];
|
string arg = args[i];
|
||||||
if (isOption(arg)) {
|
if (isOption(arg)) {
|
||||||
@ -3001,9 +3016,9 @@ int main(string[] args) {
|
|||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
if (arg[0] == '/')
|
if (arg[0] == '/')
|
||||||
writef(" /%c:$@", arg[1]);
|
messageStream.writef(" /%c:$@", arg[1]);
|
||||||
else {
|
else {
|
||||||
writef(" -%c $@", arg[1]);
|
messageStream.writef(" -%c $@", arg[1]);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -3011,18 +3026,18 @@ int main(string[] args) {
|
|||||||
if (arg[0] == '-'
|
if (arg[0] == '-'
|
||||||
&& (letter == 'd' || letter == 'l' || letter == 't')
|
&& (letter == 'd' || letter == 'l' || letter == 't')
|
||||||
&& i + 1 < args.length && !isOption(args[i + 1])) {
|
&& i + 1 < args.length && !isOption(args[i + 1])) {
|
||||||
writef(" %s %s", arg, makeEscape(args[++i]));
|
messageStream.writef(" %s %s", arg, makeEscape(args[++i]));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
writef(" %s", makeEscape(arg));
|
messageStream.writef(" %s", makeEscape(arg));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
write(" $<");
|
messageStream.write(" $<");
|
||||||
}
|
}
|
||||||
writeln();
|
messageStream.writeln();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return exitCode;
|
return exitCode;
|
||||||
|
@ -16,6 +16,7 @@ DESCRIPTION
|
|||||||
|
|
||||||
'SOURCE_FILE' is the name of the source file
|
'SOURCE_FILE' is the name of the source file
|
||||||
(you may omit the default `.asx` extension).
|
(you may omit the default `.asx` extension).
|
||||||
|
Using '-' as 'SOURCE_FILE' makes *xasm* read from standard input.
|
||||||
When invoked without any options, *xasm* assembles 'SOURCE_FILE'
|
When invoked without any options, *xasm* assembles 'SOURCE_FILE'
|
||||||
and writes the result to an object file named 'SOURCE_FILE'
|
and writes the result to an object file named 'SOURCE_FILE'
|
||||||
with the extension changed to `.obx`.
|
with the extension changed to `.obx`.
|
||||||
@ -51,7 +52,9 @@ Your *make* or shell may require further escaping.
|
|||||||
|
|
||||||
*-o* 'OBJECT_FILE'::
|
*-o* 'OBJECT_FILE'::
|
||||||
Sets output file name.
|
Sets output file name.
|
||||||
The default is 'SOURCE_FILE' with the extension changed to `.obx`.
|
Using '-' as 'OBJECT_FILE' makes *xasm* write to standard output.
|
||||||
|
The default is 'SOURCE_FILE' with the extension changed to `.obx`, or
|
||||||
|
standard output if standard input was specified as source.
|
||||||
|
|
||||||
[[new_fullpaths]]*-p*::
|
[[new_fullpaths]]*-p*::
|
||||||
Prints absolute paths in listing and error messages.
|
Prints absolute paths in listing and error messages.
|
||||||
@ -709,6 +712,11 @@ and pseudo commands, except for `MWA`, `MWX` and `MWY`:
|
|||||||
HISTORY
|
HISTORY
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
Version 3.x.x (20xx-xx-xx)
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
- source can optionally be read from standard input, and object can be
|
||||||
|
written to standard output instead of files (by Adrian Matoga)
|
||||||
|
|
||||||
Version 3.2.0 (2021-06-22)
|
Version 3.2.0 (2021-06-22)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
- <<new_locallabel,local labels>> (contributed by Adrian Matoga)
|
- <<new_locallabel,local labels>> (contributed by Adrian Matoga)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user