I know how to write just the newline character (LF) to the console output (you can see it in the test code below), but it always gets converted to a CRLF in the rendered image of the text that is displayed in the terminal session.
I found few similar questions on the internet including those 2 here on stackoverflow: C++ - Print newline to the standard output as LF instead of CR+LF on Windows platform and Is there way to set stdout to binary mode? but neither they nor the others I found where helpful.
#include <stdio.h>
// possibly other includes, defines and more
void main(void) {
printf("Hello\n"); // Where \n is a normal Line Feed Character (0x0A)
printf("Hi");
}
Hello
Hi
Hello
Hi
This is because, the line feed character gets replaced with line feed and a carrige return charaters. I tried several things to disable this behaviour, including the ideas mentioned in the links above and many more.
I expect that this setting has to be changed in the terminal application, because that's how it works in some Linux command lines. But there is no such setting in the settings for the windows console application. Perhaps there is a registry key, but I couldn't find any mention of it on the internet nor could I find the potential key myself.
The only thing that had some visual effect was the last test, but it completly disables all rendering of special characters, so newlines aren't newlines anymore but rather white boxes as a substitute. (Which is not what should happen)
#include <iostream>
#include <Windows.h>
#include <CommCtrl.h>
#include <io.h>
#include <fcntl.h>
int main() {
char lineFeed[] = { 0x0A, 0x00 };
char carriageReturn[] = { 0x0D, 0x00 };
// Testing without any settings changed
printf("hello there\n");
printf("hi");
printf(&carriageReturn[0]);
printf("sus");
printf(&lineFeed[0]);
printf("mogus");
printf("hey world\rsup\nhi");
// Toggling what [ENTER] does in regards to edit controls
HWND consoelWindow = GetConsoleWindow();
SetWindowLongA(consoelWindow, ES_WANTRETURN, GetWindowLongA(consoelWindow, ES_WANTRETURN) ^ ES_WANTRETURN);
printf("hello there\n");
printf("hi");
printf(&carriageReturn[0]);
printf("sus");
printf(&lineFeed[0]);
printf("mogus");
printf("hey world\rsup\nhi");
// Disabling insertion of soft line-break characters
SendMessage(consoelWindow, EM_FMTLINES, FALSE, 0);
printf("hello there\n");
printf("hi");
printf(&carriageReturn[0]);
printf("sus");
printf(&lineFeed[0]);
printf("mogus");
printf("hey world\rsup\nhi");
// Enabling insertion of soft line-break characters
SendMessage(consoelWindow, EM_FMTLINES, TRUE, 0);
printf("hello there\n");
printf("hi");
printf(&carriageReturn[0]);
printf("sus");
printf(&lineFeed[0]);
printf("mogus");
printf("hey world\rsup\nhi");
// Setting output mode to binary. That way \n will not be replaced with \n\r by the C standard library implementation
_setmode(1, _O_BINARY);
_setmode(_fileno(stdout), O_BINARY);
_setmode(_fileno(stdin), O_BINARY);
printf("hello there\n");
printf("hi");
printf(&carriageReturn[0]);
printf("sus");
printf(&lineFeed[0]);
printf("mogus");
printf("hey world\rsup\nhi");
// Disabling processed output, aka "Backspace, tab, bell, carriage return, and line feed characters are [not] processed"
HANDLE outputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode = 0;
BOOL ret1 = GetConsoleMode(outputHandle, &mode);
mode ^= ENABLE_PROCESSED_OUTPUT;
BOOL ret2 = SetConsoleMode(outputHandle, mode);
ret2 = ret2;
printf("Hello There2\n");
printf("hi");
}
Feel free to provide links to helpful articles, sample code, more things I can test, links to documentation or other media. Or maybe an explaination what I did wrong.
Thank you for your time and answer.
The way to make screen printing do what you want is to take complete control of it. That's what we're doing in this example: put_char_con()
intercepts and interrogates every char to be written to the console, and then it prints it per our design.
The example is a bit overkill, since it includes how to do tab stops of 4 (instead of standard 8). But I left it in because I thought since you're a programmer -- maybe you are also preferring a tab stop of 4, and this code provides that control as well (bonus! enjoy!).
But please note that we definitely provide the newline behavior you requested:
If any case
of the switch()
statement isn't desired, you can comment out as you like. You'll find that the API WriteFile()
does a very competent job of printing tab stops, backspaces... everything. So, you needn't intercept anything via cases
except where you don't like its behavior... such as newline (\n
).
This code is portable to other platforms. Just provide suitable substitutes for the ms windows APIs it uses. They are:
GetConsoleScreenBufferInfo()
-- used for finding current cursor position and screen size.WriteFile()
-- print one or more characters to the screen. Same behavior as printf()
.SetConsoleCursorPosition()
- like it sounds.This code is compiled and tested by me today:
#include <windows.h>
#include <stdio.h>
#define TAB_STOP 4
HANDLE hConOut;
/*-----------------------------------------------------------------------------
** put_char_con()
**
** Writes a character to the console.
** Each char value passed in parameter is examined -- then we print it how we
** want it printed.
*------------------------------------------------------------------------------*/
int put_char_con(int ch)
{
DWORD numBytesWritten = 0;
int num_pad, cursor_offs;
CONSOLE_SCREEN_BUFFER_INFO csbi;
BOOL bSuccess;
bSuccess = GetConsoleScreenBufferInfo(hConOut, &csbi);
if(!bSuccess)
{
puts("GetConsoleScreenBufferInfoWr() failed in put_char_con()");
return FALSE;
}
switch(ch)
{
case '\n':
csbi.dwCursorPosition.Y++;
/* For stdio functions, a newline also implies a carriage return. If that's what
* you want, enable this next line, else comment it out And cursor X coord stays put. */
//csbi.dwCursorPosition.X = 0;
numBytesWritten++;
break;
/* For stdio functions, TAB white-space-pads everything from
* the cursor to the tab stop. You can also comment out this case and
* let WriteFile() handle it -- which behaves just as printf() does*/
case '\t':
cursor_offs = csbi.dwCursorPosition.X;
if(cursor_offs < 0)
cursor_offs = 0;
num_pad = TAB_STOP -((cursor_offs)%TAB_STOP);
while(num_pad-- && (csbi.dwCursorPosition.X < csbi.srWindow.Right))
{
char ch = ' ';
WriteFile(hConOut, &ch, 1, &numBytesWritten, NULL);
csbi.dwCursorPosition.X++;
}
GetConsoleScreenBufferInfo(hConOut, &csbi);
break;
default: /* Any other char */
WriteFile(hConOut, &ch, 1, &numBytesWritten, NULL);
GetConsoleScreenBufferInfo(hConOut, &csbi);
numBytesWritten++;
break;
}
SetConsoleCursorPosition( hConOut, csbi.dwCursorPosition);
if(numBytesWritten)
return ch;
return EOF; //Usually defined as (-1);
}
/*--------------------------------------------------------------------
** cputs_con()
**
** Writes a string to the console.
** Uses: put_char_con()
*--------------------------------------------------------------------*/
void cputs_con(const char *s)
{
/* Code updated per comment from Ted Lyngmo -- thx Ted!*/
while(*s)
put_char_con(*s++);
}
int main()
{
if(!hConOut)
{
hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
if(hConOut == INVALID_HANDLE_VALUE)
{
printf("STDOUT not available");
return 0;
}
}
puts("0 4 8 12 24 32 40 48 56 64 72 80");
puts("| | | | | | | | | | | | | | | | | | | | |");
cputs_con("This is a \ttab test. \tEach word \tfollowing a tab should be \ttab aligned...\n\r");
cputs_con("This\nis the newline test...If you want\r\ncarriage returns you must manually\nadd them to your strings.\n\r");
system("pause");
return 0;
}
Output:
0 4 8 12 24 32 40 48 56 64 72 80
| | | | | | | | | | | | | | | | | | | | |
This is a tab test. Each word following a tab should be tab aligned...
This
is the newline test...If you want
carriage returns you must manually
add them to your strings.