Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/ddmd/mars.d
Original file line number Diff line number Diff line change
Expand Up @@ -1033,6 +1033,8 @@ Language changes listed by -transition=id:
goto Lnoarg;
}
}
else if (p[1] == '\0')
files.push("__stdin.d");
else
{
Lerror:
Expand Down
56 changes: 54 additions & 2 deletions src/ddmd/root/file.d
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,65 @@ nothrow:
{
if (len)
return false; // already read the file

import core.stdc.string : strcmp;
const(char)* name = this.name.toChars();
if (strcmp(name, "__stdin.d") == 0)
{
/* Read from stdin */
enum bufIncrement = 128 * 1024;
size_t pos = 0;
size_t sz = bufIncrement;

if (!_ref)
.free(buffer);

buffer = null;
L1: for (;;)
{
buffer = cast(ubyte*).realloc(buffer, sz + 2); // +2 for sentinel
if (!buffer)
{
printf("\tmalloc error, errno = %d\n", errno);
break L1;
}

// Fill up buffer
do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a while more expressive in this case.
Since the condition is supposed to be true on the first run.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@WalterBright wanted me to eliminate redundant function calls and conditions, so this is the solution I came up with. What do you propose?

{
assert(sz > pos);
size_t rlen = fread(buffer + pos, 1, sz - pos, stdin);
pos += rlen;
if (ferror(stdin))
{
printf("\tread error, errno = %d\n", errno);
break L1;
}
if (feof(stdin))
{
// We're done
assert(pos < sz + 2);
len = pos;
buffer[pos] = '\0';
buffer[pos + 1] = '\0';
return false;
}
} while (pos < sz);

// Buffer full, expand
sz += bufIncrement;
}
.free(buffer);
buffer = null;
len = 0;
return true;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Not familiar with the codebase.) Why couldn't the existing file reading code be used?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because:

(1) it requires the file size to be known in advance, but when reading stdin this is not possible; changing the existing code to handle this case would introduce a lot of extra complications that are usually not used (reading from stdin is a very specific use case, so why complicate the more usual code path and possibly penalizing it due to overhead of more complex code?).

(2) I'm not familiar enough with Windows API to be able to write code for copying standard input, but since C's stdio already does this, and works on both platforms, why not just use it.


version (Posix)
{
size_t size;
stat_t buf;
ssize_t numread;
const(char)* name = this.name.toChars();
//printf("File::read('%s')\n",name);
int fd = open(name, O_RDONLY);
if (fd == -1)
Expand Down Expand Up @@ -135,7 +188,6 @@ nothrow:
{
DWORD size;
DWORD numread;
const(char)* name = this.name.toChars();
HANDLE h = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, null);
if (h == INVALID_HANDLE_VALUE)
goto err1;
Expand Down
12 changes: 12 additions & 0 deletions test/runnable/test9287.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash

src=runnable${SEP}extra-files
dir=${RESULTS_DIR}${SEP}runnable
output_file=${dir}/test9287.sh.out

echo 'import std.stdio; void main() { writeln("Success"); }' | \
$DMD -m${MODEL} -of${dir}${SEP}test9287a${EXE} - || exit 1

${RESULTS_DIR}/runnable/test9287a${EXE} > ${output_file}

\rm -f ${dir}/test9287a{${OBJ},${EXE}}