-
-
Notifications
You must be signed in to change notification settings - Fork 175
Add -o
/ --output
option to rgbfix
to write separate output files
#1666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Hey jmillikin, thank you for this contribution! I'd like to know what @ISSOtm thinks of this feature. On the one hand, it can currently be done with If we do want to merge it, the man/rgbfix.1 docs and the contrib/*_compl files would also need updating. |
58450ef
to
3255762
Compare
Updated The build system I'm using (Bazel) is pretty strongly file-oriented, and doesn't make it easy to use stdin/stdout for communicating data to/from subprocesses. If invoking a shell manually there's issues of path quoting, so args = ["/bin/sh", "-c", "$1 - > $2 < $3", "sh", rgbfix.path, out_gb.path, in_gb.path], ... and frankly a desire to avoid that is what inspired the creation of this patch request. |
The problem with The problem with The proper fix is to write to e.g. Note that the “input file” problem is also solved by the above fix; and that RGBLINK and RGBFIX should be considered a single step (they are only separate programs so that RGBFIX can be reused externally... and there have been feature requests for making RGBLINK self-sufficient). |
Merging the execution of two separate binaries (
In this patch the output file is opened with |
This could be difficult, at least with the current v0.x CLIs, because rgblink and rgbfix each have a lot of flags already, and one program that does it all would get complicated. |
Gentle ping? |
So As for the functionality itself, what does this patch provide that |
As mentioned up-thread, I'm trying to use rgbds with a build system named Bazel, which defines the build as a graph that uses commands to map from input files to output files. This build system design requires that commands specify their input and output files; this is enforced by (1) making inputs read-only and (2) not allowing the same output file to be generated by different commands. The other binaries in rgbds work perfectly in this sort of build system. Since the other binaries in |
I see. This is already possible using the piping functionality, which I'll express in Makefile syntax, knowing nothing better: %.o: %.asm
rgbasm -o $@ $< ...
%.gb.tmp: %.o %.o ...
rgblink -o $@ $^ ...
%.gb: %.gb.tmp
rgbfix - >$@ <$< ... Is this sufficient? |
I don't think so, since the whole point was that Bazel makes it inconvenient to work with If the reasoning against this feature is just that the shell has features to do it manually, then I'd still be in favor of adding it. That way every program could work with in/out files: rgbasm -o foo.o foo.asm
rgblink -o foo.tmp foo.o
rgbfix -o foo.gb foo.tmp or with stdin/out piping: < foo.asm rgbasm -o - - | rgblink -o - - | rgbfix - > foo.gb and wouldn't rely on a particular execution environment to work. (Shell scripts, Makefiles, Bazel, Python |
3255762
to
3f187fe
Compare
@Rangi42 Yep, exactly! Thank you for explaining it better than I was. |
Fair enough, then. |
Are there any additional changes the reviewers would like to see here? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a tiny little thing regarding the Bash completions, I don't have anything to request about this patch! :)
3f187fe
to
71562f2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me! Thank you ^^
if (!outputName) { | ||
output = input; | ||
} | ||
processFile(input, output, name, stat.st_size, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid closing the same file handle twice, as output
and as input
.
if (!outputName) { | |
output = input; | |
} | |
processFile(input, output, name, stat.st_size, true); | |
processFile(input, outputName ? output : input, name, stat.st_size, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry, I don't understand this comment.
The close(output)
call is guarded by if (openedOutput)
, which can only true if outputName
is non-null. The guard around output = input
has the opposite test, so I don't think there's any path by which close()
could be called twice on the same FD.
int output = -1; | ||
bool openedOutput = false; | ||
if (outputName) { | ||
if (!strcmp(outputName, "-")) { | ||
output = STDOUT_FILENO; | ||
(void)setmode(STDOUT_FILENO, O_BINARY); | ||
} else { | ||
output = open(outputName, O_WRONLY | O_BINARY | O_CREAT, 0600); | ||
if (output == -1) { | ||
report( | ||
"FATAL: Failed to open \"%s\" for writing: %s\n", outputName, strerror(errno) | ||
); | ||
return true; | ||
} | ||
openedOutput = true; | ||
} | ||
} | ||
Defer closeOutput{[&] { | ||
if (openedOutput) { | ||
close(output); | ||
} | ||
}}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
int output = -1; | |
bool openedOutput = false; | |
if (outputName) { | |
if (!strcmp(outputName, "-")) { | |
output = STDOUT_FILENO; | |
(void)setmode(STDOUT_FILENO, O_BINARY); | |
} else { | |
output = open(outputName, O_WRONLY | O_BINARY | O_CREAT, 0600); | |
if (output == -1) { | |
report( | |
"FATAL: Failed to open \"%s\" for writing: %s\n", outputName, strerror(errno) | |
); | |
return true; | |
} | |
openedOutput = true; | |
} | |
} | |
Defer closeOutput{[&] { | |
if (openedOutput) { | |
close(output); | |
} | |
}}; | |
int output = -1; | |
if (outputName) { | |
if (!strcmp(outputName, "-")) { | |
output = STDOUT_FILENO; | |
(void)setmode(STDOUT_FILENO, O_BINARY); | |
} else { | |
output = open(outputName, O_WRONLY | O_BINARY | O_CREAT, 0600); | |
if (output == -1) { | |
report( | |
"FATAL: Failed to open \"%s\" for writing: %s\n", outputName, strerror(errno) | |
); | |
return true; | |
} | |
} | |
} | |
Defer closeOutput{[&] { | |
if (output != -1) { | |
close(output); | |
} | |
}}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This suggestion would cause close(STDOUT_FILENO)
to be called if the first branch is taken; is that intended?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is not intended. But, my goal here and in the other change suggestion was to avoid the openedOutput
boolean flag logic, unless it's absolutely necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The openedOutput
flag is necessary because output
might be in one of three states:
- No output, which means the input file is modified in-place.
- Output is valid and was opened by this function, so it should be closed before this function returns.
- Output is valid but is borrowed from the global state (
STDOUT_FILENO
), and therefore should not be closed.
If you want to avoid a bool openedOutput
then there are some options, but they're more elaborate than a bool
so probably not what you're looking for:
- Call
dup(STDOUT_FILENO)
so that the validity ofoutput
guarantees it's owned by this function. - Split
processFilename()
into two functions, with the lifecycle ofoutput
being handled similarly to howprocessFilename()
currently handlesinput
. Maybe call themprocessInputFilename()
andprocessOutputFilename()
? - Add a new
class MaybeOwnedFd
that keeps track of whether its internalint fd
is owned or borrowed, and has a destructor that closes the fd if owned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, thank you for explaining. You've carefully thought this out. I may add more tests for the edge cases and refactor this in one of those ways, but it's good as-is for now.
71562f2
to
487d7e2
Compare
Gentle ping? Sorry to keep poking via email, but I'm not sure if the comment replies are getting through. |
They are, it's just nobody has been working on rgbds lately. This isn't forgotten though; it will be done before 0.9.2 releases. |
@Rangi42 what is missing here to merge? |
487d7e2
to
a7843b5
Compare
Updated to fix |
This allows
rgbfix
to be used from build systems that discourage or forbid in-place modification of input files in build steps.rgbfix foo.gb
andcat foo.gb | rgbfix
continue to work as-is.rgbfix foo.gb -o out.gb
opensfoo.gb
read-only and writes output toout.gb
-o
, such thatcat foo.gb | rgbfix -o out.gb
andrgbfix foo.gb -o - | cat > out.gb
work.