Closed
Bug 104529
Opened 24 years ago
Closed 22 years ago
PR_fprintf I/O function misbehaves with standard output
Categories
(NSPR :: NSPR, defect, P2)
Tracking
(Not tracked)
RESOLVED
FIXED
4.4
People
(Reporter: julien.pierre, Assigned: julien.pierre)
References
Details
(Keywords: arch)
Attachments
(2 files, 4 obsolete files)
609 bytes,
text/plain
|
Details | |
1.65 KB,
patch
|
Details | Diff | Splinter Review |
On OS/2, when writing directly to standard output fd, writing \n goes to the
next line but also keeps the cursor at the same column as it was. As a result,
everything is garbled in command-line programs using NSPR. Eg. the following code :
<pre>
PR_fprintf(PR_STDOUT,
"\nNetscape Cryptographic Module Utility\n"
"Usage: modutil [command] [options]\n\n"
" COMMANDS\n"
</pre>
produces the following output
<pre>
Netscape Cryptographic Module Utility
Usage: modutil [command] [options]
COMMANDS
</pre>
Basically all \n need to be converted to \n\r in order to let the cursor return
to the beginning of the line before writing further.
![]() |
Assignee | |
Comment 1•24 years ago
|
||
![]() |
Assignee | |
Comment 2•24 years ago
|
||
I'm just realizing that this may not be the the appropriate patch since multiple
printf will have the effect of doing the conversion over again. In addition, all
printf will do the \n to \n\r , conversion which is really only necessary for
writes to stdout & stderr - ie, writes to the console.
Some applications that use PR_sprintf to put strings in temporary buffers will
be different on OS/2 as a result.
The proper fix is probably an NSPR layer pushed on the _pr_stdout and pr_stderr
PRFileDesc* , so the conversion is only done when wanted. Wan-Teh, do you agree ?
Comment 3•24 years ago
|
||
I don't understand what the actual source of the bug is though.
I don't see it as being an OS/2 problem because
fprintf(stdout, "hello\n");
fprintf(stdout, "hello\n");
works fine.
What about on Windows? \n on Windows should have the same behavior as OS/2.
Comment 4•24 years ago
|
||
Michael,
Julien was talking about PR_fprintf, not fprintf.
![]() |
Assignee | |
Comment 5•24 years ago
|
||
Mike,
When you do a PR_fprintf to stdout, the underlying NSPR call goes to NSPR
PR_Write, which does a DosWrite directly to the file handle . I think the
problem comes from the way the stdout device on OS/2 interprets the \n and \r
characters.
When you go through the runtime library (fprintf) it somehow must be translating
the stream before writing it to the actual stdout file handle. If you have the
source to the C RTL you might be able to see that. It doesn't ship with VACPP as
far as I know, though.
Comment 6•24 years ago
|
||
OK, I wrote a testcase and DosWrite and WriteFile definitely treat \n
differently.
Maybe we should add special casing in the OS/2 code that just checks if the
destination handle is 1 (stdout) and does the conversion then?
![]() |
Assignee | |
Comment 7•24 years ago
|
||
Mike,
I have attached a test case also that shows the differences in OS/2, NT and
Unix.
Basically NT and Unix automatically translate the \n written to stdout to mean
"carriage return + line feed". In OS/2 the device does not translate the \n to
anything so it just skips a line without returning to the beginning of the line
- that's a line feed without carriage return, like on a typewriter.
I think is it difficult to decide how to deal with this problem within the
framework of the current NSPR file API, which does not distinguish between text
and binary modes. Everything is always treated as binary by NSPR currently.
There are a number of places where the fix could go :
1) translate \n to \r\n within the printf functions as I originally proposed.
This is wrong because one could do several iterations of sprintf(newstring,
"%s", oldstring) , thereby incurring more than one translation, and extra blank
lines.
2) translate \n to \r\n in a PRIOLayer that would be pushed only on the stdin,
stdout and stderr layers. Basically, this will trap calls to things like PR_Read
and PR_Write, and add the proper translation between the input/output/error
pipes and the application.
The problem with doing that is that it will break any application that try to
input or output binary data with PR_Write . There is no NSPR API specified today
to toggle the translation on/off - one would have to explicitly push or pop the
layer on the fds in the application for OS/2 only, which is ugly and
non-portable.
3) translate \n to \r\n in PR_sscanf and PR_fprintf
This would affect all PRFileDesc, not just _pr_stdin, _pr_stdout and _pr_stderr
. My guess is that this is the closest to what the OS/2 C runtime library does
currently. Since sscanf and fprintf always deal with text, the change shouldn't
impact any applications using binary data. However, it will introduce a
difference in the content of text files created by NSPR applications on an OS/2
platform vs text files created by NSPR applications on a Unix and NT platform.
Also, some files created on other platforms may not be read properly on OS/2,
and vice-versa.
I'm afraid this could cause problems with applications that use temporary files
as text, write them with PR_fprintf, and then send them to the network. In that
case it could show some odd problems.
As you see none of the proposed fixes are perfect. If you have better ideas, let
me know. Wan-Teh, please feel free to jump in and comment on this issue.
![]() |
Assignee | |
Comment 8•24 years ago
|
||
![]() |
Assignee | |
Comment 9•24 years ago
|
||
Just FYI the output of the program on Unix and NT is :
hello
world
and on OS/2
hello
world
![]() |
Assignee | |
Comment 10•24 years ago
|
||
Talked to Wan-Teh.
He suggested we use some environment variables to set translation on stdin
/stderr / stdout fds . The implementation would probably be in a PRIOLayer that
would be pushed only on those fds.
However, I just realized that using environment variables has drawbacks. For
example if one has an NSPR text-mode application, and an NSPR binary compression
stream application, and wants to do :
nsprtextapp | nsprzipapp > test.zip
In that case we want the output from nsprtextapp to be translated, and the
output from nsprzipapp to be binary.
Ultimately I think the application needs to know what it is doing - whether it
is text or binary I/O, and should have a way of specifying it.
The problem is that there is no such concept in NSPR.
Here is a proposal to change that :
I suggest that a "translation" bit could be added in the public PRFileDesc
structure. To preserve compatibility (and performance) with all existing NSPR
applications, the default would be binary mode.
The application could then set the translation mode by a call to
PR_SetTextFileTranslation(PRFileDesc*) . This function might return an error
code if the descriptor does not support translation (eg. we probably don't care
to do this on sockets or other types of PRFileDesc*, only on actual files).
It would also be possible to pass PR_OTEXT as one of the flags to PR_Open to
open a file in translated mode .
Environment variables for stdin/stdout/stderr translation could still exist so
that quick tests could be done on existing NSPR applications that don't call
PR_SetTextFileTranslation on the _pr_stdin / _pr_stdout _pr_stderr that are
returned by PR_GetSpecialFD , but ultimately the application code should be
modified and these variables would become deprecated.
![]() |
||
Comment 11•24 years ago
|
||
Marking NEW.
![]() |
Assignee | |
Updated•24 years ago
|
Priority: -- → P2
Target Milestone: --- → 4.2
![]() |
Assignee | |
Comment 12•23 years ago
|
||
Perhaps there is a fix after all that doesn't involve a new API.
In the case of PR_fprintf, we can assume we always want to write to a text file,
so the conversion is needed. So the conversion could be done in that function.
My previous patch was doing it in the another layer, which also affected other
functions such as PR_sprintf . We don't want these functions to change.
The fix would be to have PR_fprintf do an extra parsing pass on the string just
before writing it to the file descriptor. If any \n are encountered, it would
need to insert a \r . This might not be the most efficient thing to do, as the
I/O would be broken up into multiple pieces at that point (unless we make a copy
of the whole string, which I don't think is a good idea). The right thing to do
is probably to use scatter/gather if we can. I know OS/2 supports it in some way
but I don't see a call for it (there is no DosWriteV, only DosWrite).
![]() |
Assignee | |
Comment 13•23 years ago
|
||
This patch solves the problem much better as it doesn't affect intermediate
functions (PR_sprintf). It fixes the biggest part of the display problem of the
NSS command-line tools on OS/2.
Attachment #53411 -
Attachment is obsolete: true
![]() |
Assignee | |
Comment 14•23 years ago
|
||
This latest patch still has one flaw - if a program reads and then writes the
data back to the file, it will keep growing. There needs to be an additional
check to see if there is already a \r immediately preceding or following the \n
so that we don't add one in that case.
As far as scatter-gather in OS/2 is concerned, Warp Server for e-business added
a function called DosListIO to do this. We might be able to take advantage of
this in NSPR, but it would require runtime loading of the function, as it is not
available in older Warp 3.0 & Warp 4.0 kernels.
![]() |
Assignee | |
Comment 15•23 years ago
|
||
Attachment #96552 -
Attachment is obsolete: true
![]() |
Assignee | |
Comment 16•23 years ago
|
||
Wan-Teh,
Could you please review the patch and check it in if appropriate ? Thanks.
Comment 17•23 years ago
|
||
Comment on attachment 98015 [details] [diff] [review]
better patch
We should do this only if the fd represents
a console window. Is it possible to detect
whether an fd is a console on OS/2?
![]() |
Assignee | |
Comment 18•23 years ago
|
||
There is a runtime library function in VACPP that peforms this test, but it
doesn't take a system FD. I'll look up the OS/2 API doc to find out how it might
be implemented.
However, I'm not sure if we want to do this test. If somebody is redirecting the
output, say piping it to another program, then the fd might no longer be a tty,
but the \r would still be a problem.
Comment 19•23 years ago
|
||
This is to be consistent with the other platforms,
especially Windows, which also uses CRLF as line
endngs in text files. The current implementation
is only broken for console windows. If the output
is redirected via a pipe to another program, your
proposed change will cause that other program to
receive different input from what it would receive
if the current version of NSPR were used.
The need to maintain backward compatibility restricts
what we can do here. This is why I think we should
only perform the translation when writing to a console.
![]() |
Assignee | |
Comment 20•23 years ago
|
||
Wan-Teh,
The only released NSPR application for OS/2 is the browser.
I don't think there is an existing dependency of any command-line OS/2
application based on NSPR. So, changing the behavior for such programs should be
OK. The main applications I'm trying to get to work correctly with this patch
indeed are the NSS command-line tools.
I can see that the change may be a problem if PR_fprintf is used to write data
files in the browser, though, as it would change its format.
Actually, I just found out tha the C runtime "isatty" function works on a native
handle, so we can use it here. I have tried it and it works fine.
![]() |
Assignee | |
Comment 21•23 years ago
|
||
Attachment #98015 -
Attachment is obsolete: true
Comment 22•23 years ago
|
||
Comment on attachment 100500 [details] [diff] [review]
updated patch using isatty
Does "\r\n" also produce the correct output
in a console on OS/2? Your patch avoids adding
an extra '\r' after "\r\n".
![]() |
Assignee | |
Comment 23•23 years ago
|
||
Yes, it does.
\r resets the cursor to column 0. So it can be done before or after a \n, and
doesn't need to be done more than once.
![]() |
Assignee | |
Comment 24•23 years ago
|
||
Moving to 4.3 , since this didn't get checked in before.
Target Milestone: 4.2 → 4.3
![]() |
Assignee | |
Comment 25•23 years ago
|
||
Wan-Teh,
Could you please check this into the tip of NSPR ? This patch will not affect
the Mozilla browser as isatty is used to check if we are on a terminal.
Thanks.
Comment 26•23 years ago
|
||
Comment on attachment 100500 [details] [diff] [review]
updated patch using isatty
Is this patch only necessary for the VACPP runtime
library? I am wondering if the gcc builds also need
this patch.
![]() |
Assignee | |
Comment 27•23 years ago
|
||
Wan-Teh,
In the PR_Write code path, we write directly to the native handle with a
DosWrite. So this patch is independent of the runtime library. This is why I
used #ifdef XP_OS2 rather than #ifdef XP_OS2_VACPP .
![]() |
Assignee | |
Comment 28•23 years ago
|
||
I built NSPR with gcc successfully on OS/2 today.
[on a different subject : I could not use the tip but rather a branch,
NSPRPUB_PRE_4_2_CLIENT_BRANCH . Please check in the changes to the tip of NSPR
as soon as possible ]
I verified that this fix was still necessary with the gcc build, and worked with
it as intended.
Comment 29•22 years ago
|
||
Comment on attachment 100500 [details] [diff] [review]
updated patch using isatty
>+ if ('\n' == *(msg+curofs) && /* current character is \n */
>+ ( (0 == curofs) || ('\r' != *(msg+curofs-1)) ) && /* previous character isn't \r */
>+ ( (len == curofs) || ('\r' != *(msg+curofs+1)) ) /* next character isn't \r */
The (len == curofs) test is not needed because it must
be false if the current character is \n. (The character
at offset 'len' is the terminating null byte.)
Agreed?
Comment 30•22 years ago
|
||
I edited the patch to conform to NSPR's coding style.
The only real difference from Julien's patch is that
the useless (len == curofs) test that I pointed out
was removed.
Attachment #100500 -
Attachment is obsolete: true
Comment 31•22 years ago
|
||
Fixed checked into the NSPR tip (4.4) and the
NSPRPUB_PRE_4_2_CLIENT_BRANCH (mozilla 1.4 beta).
Status: NEW → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
Whiteboard: [4.4]
Updated•22 years ago
|
Whiteboard: [4.4]
Target Milestone: 4.3 → 4.4
You need to log in
before you can comment on or make changes to this bug.
Description
•