Page 1 of 1

How do I break the line and create a small wrapper?

Posted: Sat Nov 07, 2020 10:30 pm
by TheReactiveMouse
Hello, according to the official documentation, I compiled everything I needed, created a test kernel, launched it, but apparently it was planned that \ n would work as a line break, but it does not work. (https://wiki.osdev.org/Bare_Bones) Can someone explain how to break a line to C? And if possible, how to read text from the keyboard and enter it into a line? for example, a user entered a test, and I want to compare it with other commands, how can this be implemented? I'm just a newbie to C, but I used to write kernels a bit in assembly language.

Re: How do I break the line and create a small wrapper?

Posted: Thu Nov 12, 2020 7:54 pm
by Octocontrabass
TheReactiveMouse wrote:Hello, according to the official documentation, I compiled everything I needed, created a test kernel, launched it, but apparently it was planned that \ n would work as a line break, but it does not work.
You have to write that code yourself. There's an explanation in this section that should help.
TheReactiveMouse wrote:And if possible, how to read text from the keyboard and enter it into a line?
Write a keyboard driver.
TheReactiveMouse wrote:I'm just a newbie to C, but I used to write kernels a bit in assembly language.
We recommend being very familiar with the language you choose to write your OS. You might want to get some practice writing user-level programs in C before you continue.

Re: How do I break the line and create a small wrapper?

Posted: Fri Nov 13, 2020 2:24 am
by bloodline
TheReactiveMouse wrote:for example, a user entered a test, and I want to compare it with other commands, how can this be implemented?
Are you asking how to implement a command parser? This a moderately complex excercise, you will need to become more familiar with C and also have implemented the string functions before you can do this.
I'm just a newbie to C, but I used to write kernels a bit in assembly language.
What kernel models have you followed in the past? What paradigm do you plan to implement this time? What assembly ISAs are you familiar with?

Re: How do I break the line and create a small wrapper?

Posted: Fri Nov 13, 2020 11:40 am
by Schol-R-LEA
Have you read the pages mentioned in the Links and Advice for Newcomers thread? While it isn't directly relevant here, it is will help you get an idea of the scope of OS dev.

And as others have said, OS dev really isn't the place to be learning C and assembly. You really need a solid understanding of both before beginning an OS project.

For the specific problem of newlines, this has come up in this forum many, many times before. See the pages on Printing To Screen and the Text Mode Cursor for full details. I'll go over the general idea here, though.

The thing to understand is that on the PC (and many other systems) the text mode video memory is a continuous block mapping to the whole screen, and that adding a new line actually means moving where you are inserting characters to a different part of that memory block - namely, the character cell which corresponds to the start of the next line.

Your typical 'text mode' string writing function will try to make this behave like an old-fashioned 'teletypewriter' instead, which had a literal typewriter printing to a scroll of paper in a fixed order, but that is an illusion to make printing to the screen easier.

For example, a blank video screen (4x25 in the example below) is actually filled with space characters, which I'll show here using periods to show where the blanks are:

Code: Select all

|.........................| 
|.........................| 
|.........................| 
|.........................| 
Note that, in memory, this is all one big block, like so:

Code: Select all

|....................................................................................................| 
Note also that, on the PC, the text memory is made up of character/attribute pairs, so each character cell is actually two bytes of memory. This means that the text buffer is twice the size of the screen - for this 4x25 screen (100 characters), it is 200 bytes, and so forth.

It is up to you to know which if these character cells you are writing to at a given moment, which usually means you need an v,h pair (vertical and horizontal) to keep track of the position, what is known as a 'cursor'.

So let's say you have your cursor at (0,0), the first cell in the text buffer. You would write a character - let's say 'H' - to that position in memory.

Code: Select all

|H........................| 
|.........................| 
|.........................| 
|.........................| 
Or rather,

Code: Select all

|H...................................................................................................| 
If you write there again, with (say) 'e', it will overwrite the 'H', which probably isn't what you want.

Code: Select all

|e........................| 
|.........................| 
|.........................| 
|.........................| 
Thus, to write 'e' as the second character of a word, you would have to write to the next position in the buffer.

Code: Select all

|He.......................| 
|.........................| 
|.........................| 
|.........................| 
In order to keep track of this, you would want to increment the h coordinate for each character of you add. So after you insert the phrase "Hello, World!",

Code: Select all

|Hello,.World!............| 
|.........................| 
|.........................| 
|.........................| 
Your cursor would be (0,12).

But what if you want to write "Hello,\nWorld!", instead? Well, first off, your string writing routine would have to scan the string for the newline escape code, '\n', which is itself a bit complex since the C compiler automatically converts the substring "\n" to whatever your OS uses for the newline. The newline isn't necessarily a single character, I should add; in Unix it is a single 'line feed' character (ASCII 10), but in Windows is is the pair 'carriage return'/'line feed' (ASCII 13 followed immediately by ASCII 10). The history behind this is a bit complicated, but for now just realize that a newline 'character' maybe not be just a single character in the string.

Once your function sees that newline in the string, rather than writing the character to memory, it needs to modify where you are writing to. In short, this means resetting the horizontal component of the cursor to 0, and incrementing the vertical component - in other words, you go from writing the ',' at (0,5)

Code: Select all

|Hello,...................| 
|.........................| 
|.........................| 
|.........................| 
(ignoring what was a space in the original) to writing the 'W' at (1,0):

Code: Select all

|Hello,...................| 
|W........................| 
|.........................| 
|.........................| 
Now keep in mind that in the text buffer, this is actually

Code: Select all

|Hello,...................W..........................................................................| 
But since you aren't changing the trailing spaces on the 'first line', they just stay as they were.
The final results on the screen is

Code: Select all

|Hello,...................| 
|World!...................| 
|.........................| 
|.........................| 
while at the text buffer level, it is actually

Code: Select all

|Hello,...................World!.....................................................................| 
I hope this has made it clearer what is actually going on, at least as far as the string writing functions and the text buffer are concerned.

Re: How do I break the line and create a small wrapper?

Posted: Thu Nov 19, 2020 12:56 am
by eekee
That looks like a really good explanation to me, Schol-R-LEA! :) But it's possible I'm biased because I already 'get' this 2D-layout stuff. I do think diagrams are always good, at any rate. I've just got a little simplification...
Schol-R-LEA wrote:But what if you want to write "Hello,\nWorld!", instead? Well, first off, your string writing routine would have to scan the string for the newline escape code, '\n', which is itself a bit complex since the C compiler automatically converts the substring "\n" to whatever your OS uses for the newline. The newline isn't necessarily a single character, I should add; in Unix it is a single 'line feed' character (ASCII 10), but in Windows is is the pair 'carriage return'/'line feed' (ASCII 13 followed immediately by ASCII 10). The history behind this is a bit complicated, but for now just realize that a newline 'character' maybe not be just a single character in the string.
Handling the CR LF pair needn't be hard in the terminal driver. The pair is well-suited for teletypewriters - things from the 1950s and 60s which were barely more than mechanical typewriters at all. Just like those teletypewriters, you can handle them separately with good results. "Carriage return" should send the cursor to the beginning of the line: just zero the cursor's column number. "Line feed" should simply send the cursor to the next line; increment the cursor's line number.

DOS and maybe BIOS write-to-screen routines do it this way. I once found ASCII-art files with reversed newline sequences; the line feed first. They worked fine under DOS because it handles each character separately. Common terminal emulators in Unixes also do this, but it's a bit harder to see because Unix "TTY" drivers have different modes. Sometimes you see it when a program which had the terminal in raw mode crashes. Then, simple programs which need cooked mode send Unix newlines - actually LF - and the cursor just goes down a line without changing column.

Re: How do I break the line and create a small wrapper?

Posted: Sat Nov 28, 2020 5:46 pm
by austanss
Since you are a newbie, let me explain this to you a bit more clearly.

Assuming you are using VGA text mode, then your terminal is 80x25.

In your terminal driver you should have a variable for your current column and current row.

When you go to put_entry_at, you multiply the current row by the height of your terminal (25) and then add the current column to get the index of the character position.

Typically, the put_char function manages the incrementing of columns and rows.

When you are in the put_char function, have a conditional that checks if the character is '\n', and if it is, set the current column to 0 and increment the current row.

Now you have a line break.

Re: How do I break the line and create a small wrapper?

Posted: Sun Nov 29, 2020 2:24 pm
by eekee
rizxt wrote:When you go to put_entry_at, you multiply the current row by the height of your terminal (25) and then add the current column to get the index of the character position.
Nice and simple indeed, but there are 2 little mistakes in this line.
1: You have to multiply the current row by the width of the terminal, 80.
2: The VGA text memory locations go char, attr, char, attr, char, attr, etc., so you're not quite done yet; you have to multiply by 2 to get the character position. The attributes should all be set to light gray on black by the boot process, so you can safely ignore them until you're ready for them. Just be sure not to touch the attribute bytes by mistake, or your characters could end up black-on-black. ;)