I'm making a very simple console text editor. In order to move the cursor to the end of the previous line when I backspace at the beginning of a line, I need to read an already printed line from the console, then get its length. How would I go about making this work?
There is no way to do this using scanf() and printf(); the program would need to keep track of what it prints. However, it is also impossible to edit previously printed screen lines using only the standard I/O functions - in order to do that, you'd need to use e.g. ncurses.
Store every element you print in the editor in an char array, because you may have to go back all way up to start or in the middle, not only one line up.
Related
I am a beginner of C language. I was recently writing a program to print a histogram of the number of instances of a character in an input. Printing the histogram horizontally is easy, but vertically is a challenge.
Please have a look at the following code:
#include <stdio.h>
int main()
{
/*THIS IS JUST A SAMPLE OF WHAT I WANT TO ASK*/
int occurrence = 5;
int i;
for (i=0;i<occurrence;i++){
printf("\t*\n");
}
}
For an example, say any letter occurs 5 times. So I have set the occurrence to 5. And I am printing the bar in the form of asterisks. Now through this code, I am able to print an histogram containing 5 asterisks. But the thing is if I want to print other elements, like the x and y axis, the code creates a \n character. So if I write the code to print other elements, they start printing from the next line. So I figured out something else.
Now read this code:
#include <stdio.h>
int main()
{
/*THIS IS JUST A SAMPLE OF WHAT I WANT TO ASK*/
int instances = 5;
int i;
for (i=0;i<instances;i++){
printf("\t*\t\t\t\t\t\t\t\t\t");
}
}
Now what I did is depending on the size of the output screen, I created 9 tab characters so that the next asterisk moves on to the next line without printing any \n character.
Now the main question: IS THERE ANY OTHER WAY TO CREATE INVISIBLE SPACES UNTIL THE NEXT THING TO BE PRINTED MOVES ON TO THE NEXT LINE?
This question might be stupid but if there is a solution, it will be best for me.
NOTE: If there is no such method of creating blank spaces then please suggest a good way to create a vertical histogram. If someone wants an improvisation in the question, I am ready to do it.
Thanks for the help!
Outputs::
If I use the first code and I make other chart elements using printf statements, this is the output::
Now can you see that the bar made of asterisks is not aligned with the x and y axis. This happens due to the \n character.
Instead of hacking around with spaces yourself, you might want to look into a library that handles all that graphical stuff for you. For example, ncurses is a pretty decent library to do pseudo-graphical output on a console. However, "ncurses" seems to be for Unix only, but there may be other libraries for Windows.
If using a library is not an option, I'd suggest to work with a 2-dimensional character buffer (that you treat like a bitmap) instead of writing things directly to the console. It's a lot less "fiddling around". Just watch out to truncate your buffer line size to the console line size before printing, in order to avoid automatic line breaks where you don't want them.
If you do not want to use curses library, for example if you have found a printing terminal in a museum and want that your program can work on it, you have to reverse the problem.
You must print line by line if you do not use a graphic library. So your program could look like :
compute the occurence of characters
compute the maximum occurence
for each line from max occurence to 0
compute a line for every character printing a space (not reached)
for each character
if the occurence is greater than the line index put a mark at correct place in the line
print the line
That's the algo, actual coding is left as exercice for the reader :-)
You might want to think about having a two dimensional array. Start by filling it with spaces. Then replace the spaces with the character you want to print at the correct index. Using two for loops, traverse the array in order to print. Print a new line at the end of the row. Changing the order of the index changes a vertical/horizontal print. Negatives are
having to keep the whole thing in memory.
Needing multiple passes. One to set the characters and another to print.
Please refer to the following code snippet, I will be referring to the line numbers on it:
https://gist.github.com/wilbertcr/474c6a13e377dc8ce51a
As you can see on line 172-200, I created a modified version of the original back_over function, which just moves the pointer without erasing the character that's moving over.
Outside of the function in_process, and as a global variable, I created int verase, see line 1, which I use on line 82 to indicate CTRL+H has been pressed(ch == tp->tty_termios.c_cc[VERASED]).
My idea is to use this as a flag so I can catch the next character, which should be the number of spaces I need to back_over, and do that by calling back_over the number of times indicated by that next character.
The problem I am having is that I don't know how to turn that next character into its corresponding int so that I can use it on the for loop. Lines 27-38 show a failed attempt to do that, however, no matter how small the key I press(I've tried 1 and 2 and 3), it always takes me to the beginning of the line(luckily back_over doesn't go beyond a line break--see line 185).
It seems like the for loop is being executed more than the it should, which I suspect is happening because "number" is not really 1 or 2 or 3 but something else, something the for loop is interpreting as much bigger than the number I am pressing in the keyboard. I would appreciate some help on how can I turn it into an int.
It turned out it was just a matter of doing:
ch=ch-'0'
A lot of times I've seen text-based programs which replace text which has already been printed. For instance, imagine a program where the progress is printed as
Loading: 5%
and then it says
Loading: 10%
and so on, without printing new text which is appended?
How is this done? I haven't seen any such functions available in the library (in this case C). I have an idea, though: There is a character you can write which returns the prompt to the beginning of current line (\r I believe). Could this be used to "overwrite" what you've already printed to the command prompt?
In most consoles, writing a bare carriage return \r without a newline after it will return the cursor to the beginning of the current line, allowing you to overwrite the existing text. Writing the backspace character \b also moves the cursor back one character.
For simple behavior, such as a progress indicator, this is all you need. For more complex behavior, you need to control the terminal through non-standard means. On Unix-based systems, the ncurses library can be used—it gives you full control over the cursor location, text color, keyboard echoing, more fine-grained keyboard input, and more.
On Windows, there's a suite of functions for manipulating consoles, and they can do mostly the same things as Unix consoles.
One way that I have seen is to just print the backspace character a number of times and then replace whatever you erased with the new text.
The backspace character is an ASCII control character represented by \b.
I'm developing a CLI program, in C, for my systems class project, and it needs to display incoming text while maintaining a command prompt. Left alone, the incoming text will saw through whatever one tries to type. In other applications I've seen the incoming text print above(or below) the prompt itself. Is there any way to implement this in ANSI escapes? ncurses seems like overkill.
You can print \r to erase the prompt: It will return the cursor to the beginning of the current line. You can then print your output followed by some spaces to clear out any remaining input characters, newline, and reprint the prompt.
With ANSI sequences or terminal-specific libraries you can do even more, but this I think is all you can do reliably using only ASCII. Apart from printing 242 blank lines to redraw the whole screen, of course.
Edit: Sorry, I didn't answer the ANSI part properly. With cursor movement control codes and printing space over existing characters, you can pretty much do anything, and there are some convenience actions to help you, such as "delete line". But keep in mind that Windows doesn't play nice w/ ANSI post XP, and neither are other systems guaranteed to.
For one thing, if you want to maintain a prompt, while printing, you can not use things like scanf. You have to intercept keyboard events or use a non waiting method to get input. Then you can get the terminal number of lines (n) and print the last n-1 lines of your output, and then a prompt.
my2c
I'm interested in clearing the output of a C program produced with printf statements, multiple lines long.
My initial guess was to use
printf("output1\n");
printf("output2\n");
rewind(stdout);
printf("output3\n");
printf("output4\n");
but this produces
output1
output2
output3
output4
I was hoping it would produce
output3
output4
Does anyone know how to get the latter result?
You can have the desired result both for terminal and pipes if you remember to remove the control characters as well. This is hardcoded for two lines.
#include <stdio.h>
int
main ()
{
fputs("output1\n",stdout);
fputs("output2\n",stdout);
fputs("\033[A\033[2K\033[A\033[2K",stdout);
rewind(stdout);
ftruncate(1,0); /* you probably want this as well */
fputs("output3\n",stdout);
fputs("output4\n",stdout);
return 0;
}
Most terminals support ANSI escape codes. You can use a J (with parameter 2) to clear the screen and an H (with parameters 1,1) to reset the cursor to the top-left:
printf("\033[2J\033[1;1H");
Alternatively, a more portable solution would be to use a library such as ncurses, which abstracts away the terminal-specific details.
Once you print something to the terminal you can't easily remove it. You can clear the screen but exactly how to do that depends on the terminal type, and clearing the screen will remove all of the text on the screen not just what you printed.
If you really want fine control over the screen output use a library like ncurses.
You can also try something like this, which clears the entire screen:
printf("\033[2J\033[1;1H");
You can include \033[1;1H to make sure if \033[2J does not move the cursor in the upper left corner.
More specifically:
033 is the octal of ESC
2J is for clearing the entire console/terminal screen (and moves cursor to upper left on DOS ANSI.SYS)
1;1H moves the cursor to row 1 and column 1
As far as C is concerned, stdout is nothing more than a byte stream. That stream could be attached to a CRT (or flat screen), or it could be attached to a hardcopy device like a teletype or even a sheet-fed printer. Calling rewind on the stream won't necessarily be reflected on the output device, because it may not make any sense in context of that device; think about what rewinding would mean on a hardcopy terminal or a sheet-fed printer.
C does not offer any built-in support for display management, so you'll have to use a third-party library like ncurses.
One way, is to do a exec('clear').
In fact, when you capture/redirect your stdout (./program > output.file), there is no way how to remove contents of that file, even printf("\033[2J\033[1;1H"); just adds this sequence of characters into it.