How do i fix my newline procedure?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Octacone
Member
Member
Posts: 1138
Joined: Fri Aug 07, 2015 6:13 am

Re: How do i fix my newline procedure?

Post by Octacone »

Holy mother of God!!! Inside your put character function, you need to check if a specific character is equal to '\n' and if it is just ignore it and call your new line procedure.
OS: Basic OS
About: 32 Bit Monolithic Kernel Written in C++ and Assembly, Custom FAT 32 Bootloader
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: How do i fix my newline procedure?

Post by Schol-R-LEA »

As I said earlier, you need to process control characters such as newlines first, before you write to the text buffer, and if it is a non-displaying character, yo don't insert it into the buffer but instead take the action that it requires.

For example, if it is a TAB, rather than putting the value 0x09 into the buffer, you would put a sequence of spaces (0x20) equal equal to whatever you have tab set to (usually either 4 or 8, though it could be anything) and advance the cursor past those spaces.

Code: Select all

void terminal_putchar(tty_console term, char c) {
   switch(c) {
      case '\t':
         for (i = 0; i < term.tab_stop; ++i) {
             terminal_putentryat(' ', term.buffer, term.fgcolor, term.row, term.column);
             if (++term.column == VGA_WIDTH) {
                 term.column = 0;
                 break;                              /* don't wrap a tab past the end of the line */
             }
         }
         break;
     case 0x0D:                 /* carriage return - be explicit which one you use, don't just use '\n' */
         term.column = 0;
         break;
     case ox0A:                 /* line feed - again, if you are doing them as  a sequence, treat them as different values */
         advance_row(term);
         break;
     /* handle other cases here */
     default:
        terminal_putentryat(c, term.buffer, term.fgcolor, term.row, term.column);
        if (++term.column == VGA_WIDTH) {
           term.column = 0;
           if (++term.row == VGA_HEIGHT) {
              advance_row(term);
           }
       }
   }
}
This is just a quick sketch of what you could do; how you actually handle it is your call.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
User avatar
Ycep
Member
Member
Posts: 401
Joined: Mon Dec 28, 2015 11:11 am

Re: How do i fix my newline procedure?

Post by Ycep »

Dammit... There is your fix:

Code: Select all

void terminal_putchar(char c) {
   if (c == '\n') {
      terminal_row++;
      terminal_column = 0;
      if (terminal_row == VGA_HEIGHT)
         terminal_row = 0;
      return;
   }
   terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
   if (terminal_column == VGA_WIDTH) {
      terminal_column = 0;
      
   }
}
Operator ++ increments integer by one. integer++ is not same as integer+1 .
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: How do i fix my newline procedure?

Post by SpyderTL »

In case you weren't aware, your compiler will automatically convert escape characters, like \n into a single character before writing it to your compiled program. In this case, it turns every \n in your string into a hex byte 0x0A.

That 0x0A byte is then copied into your video card's memory by your OS, and the video card looks up that value in a built in font table, and finds that circle character in that location in the table, and it prints it to the screen.

Your OS code should not copy any 0x0A bytes to video memory. It should instead move the cursor to the beginning of the next line.

Hopefully that clears things up a bit.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
NunoLava1998
Member
Member
Posts: 273
Joined: Sun Oct 09, 2016 4:38 am
Libera.chat IRC: NunoLava1998

Re: How do i fix my newline procedure?

Post by NunoLava1998 »

Lukand wrote:Dammit... There is your fix:

Code: Select all

void terminal_putchar(char c) {
   if (c == '\n') {
      terminal_row++;
      terminal_column = 0;
      if (terminal_row == VGA_HEIGHT)
         terminal_row = 0;
      return;
   }
   terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
   if (terminal_column == VGA_WIDTH) {
      terminal_column = 0;
      
   }
}
Operator ++ increments integer by one. integer++ is not same as integer+1 .
That code turned my semi-working (i don't want to print 0x0A but it does) newline function in terminal_putchar() to doing this...
Image
Developing TRIODIUM OS. Or call it Dixium if you want. It doesn't matter.

https://github.com/NunoLava1998/DixiumOS
User avatar
MichaelFarthing
Member
Member
Posts: 167
Joined: Thu Mar 10, 2016 7:35 am
Location: Lancaster, England, Disunited Kingdom

Re: How do i fix my newline procedure?

Post by MichaelFarthing »

NunoLava1998 wrote: That code turned my semi-working (i don't want to print 0x0A but it does) newline function in terminal_putchar() to doing this...
Well you'd best work out out what's wrong then...
User avatar
Ycep
Member
Member
Posts: 401
Joined: Mon Dec 28, 2015 11:11 am

Re: How do i fix my newline procedure?

Post by Ycep »

Try this:

Code: Select all

void terminal_putchar(char c) {
   if (c == '\n') {
      terminal_row++;
      terminal_column = 0;
      if (terminal_row == 25)
         terminal_row = 0;
      return;
   }
   terminal_putentryat(c, terminal_color, terminal_column++, terminal_row);
   if (terminal_column == 80) {
      terminal_column = 0; 
   }
}
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: How do i fix my newline procedure?

Post by Schol-R-LEA »

Lukand wrote:Try this:

Code: Select all

void terminal_putchar(char c) {
   if (c == '\n') {
      terminal_row++;
      terminal_column = 0;
      if (terminal_row == 25)
         terminal_row = 0;
      return;
   }
   terminal_putentryat(c, terminal_color, terminal_column++, terminal_row);
   if (terminal_column == 80) {
      terminal_column = 0; 
   }
}
That code still has a serious problem, as I pointed out earlier: it has the effect of returning the cursor to the first column of the first row (which in English and other sinistrodextral languages means the upper left-hand corner), but does not clear the existing text from the buffer. Thus, to give a simplified example, if you had a page where you had 6 rows and 8 columns,

Code: Select all

This is |
a simple|
example |
of what |
I mean h|
ere.    |
With the code as it is, if you were the add the word 'fnord' to the last line, it would wrap back the beginning of the page:

Code: Select all

rdis is |
a simple|
example |
of what |
I mean h|
ere. Fno|
I assume for now that you can see the problem here (since the 'fnord' is broken up :) ), and why you probably want something a bit more complicated to handle the end-of-page scenario.

There are two common solutions: either clear the page, or scroll the page up by one line. Clearing is simpler, as you can just use a bulk move to copy a blank glyph over every character already on the screen, but it loses information; scrolling is a little trickier, as it requires you to copy all the lines after the first one to the line above them. Scrolling is probably the better solution in most cases, but having a clear routine is advisable as well, so I suggest writing one function for each of those operations and maybe having a flag as to which one to use in terminal_putchar().

Mind you too that you will probably want to use different text page modes eventually, so hardcoding the rows and columns is probably not a great idea. It works fine for now, but you might want to at least give some thought to how you will need to change it in the future.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
User avatar
Ycep
Member
Member
Posts: 401
Joined: Mon Dec 28, 2015 11:11 am

Re: How do i fix my newline procedure?

Post by Ycep »

The problem may disappear when he makes vga scrolling.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: How do i fix my newline procedure?

Post by Schol-R-LEA »

Lukand wrote:The problem may disappear when he makes vga scrolling.
Isn't that what I was just discussing? In order for it to use scrolling... you have to implement scrolling. Even with hardware support, you need to set it up and use it - it is not automatic. Or am I missing something?
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: How do i fix my newline procedure?

Post by Schol-R-LEA »

It occurs to me that both NunoLava98 and Lukand are making a common mistake - one nearly everyone makes at first - because of a misunderstanding about how the text buffer works. They both seem to be thinking of it as a stream buffer, that is, a array with a pointer which is used in a first-in, first-out manner, where the data is added by the program on one end and then read out by something else on the other.

This is how the C standard I/O libraries work, and how INT 10h/AH=0Eh works. It is how the old teletype systems they emulate worked. It is not, however, how the VGA text buffer works.

The VGA video buffers are actual areas in memory - usually on the video adapter, and not readable by the system - which you in essence are drawing on, like a sketchpad. Once a cell in the buffer is set to a given value, it retains the value until it gets changed by something. If you write to a cell that is lower in memory than the one you had been writing to, the only thing changed is the cell you just wrote to - the rest of the screen stays the same as it was. It is not linear the way a stream buffer is.

The standard libraries all implement stream buffers, but that's solely because teletypes are a well understood and simple API that can be used with minimal understanding of the underlying hardware. The VGA adapter has no hardware support for it, though, and the libraries have to bend over backwards to make your 4K flatscreen monitor act like a 1967 vintage ASR-33 printing on a roll of fanfold paper because it is a universal interface that you don't have to think much about 99% of the time.

This is one of the 1% of the time where that model isn't going to help you. You don't have a stream I/O library to use yet. You need to understand what is actually happening, rather than coasting on the work of earlier developers.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
User avatar
Schol-R-LEA
Member
Member
Posts: 1925
Joined: Fri Oct 27, 2006 9:42 am
Location: Athens, GA, USA

Re: How do i fix my newline procedure?

Post by Schol-R-LEA »

To further clarify: the video text buffer is linear in the sense that it is a buffer of (usually write-only) memory that can be stepped through with a pointer. However, the video hardware treats it as a 2-dimensional array of attribute-character pairs, where the number of horizontal columns, x, and the number of vertical rows, y, depends on the video text mode being used.

Since the original CGA/MDA text buffer was allocated with a bit less than 16K, which was divided into four such buffers for the pre-VGA standard 80x25 mode (a total of 2000 16-bit character cells) of 4000 bytes each, and switching between them was a common way both to avoid flicker and to handle virtual screens. The video display actually uses all 2000 on every refresh, regardless of what is in them; the buffer size used is constant, regardless, and the buffer had no built-in concept of a 'newline character' at all.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
User avatar
jojo
Member
Member
Posts: 138
Joined: Mon Apr 18, 2016 9:50 am
Libera.chat IRC: jojo
Location: New York New York

Re: How do i fix my newline procedure?

Post by jojo »

> Check in on OSDev for the first time in something like a month
> Top two most recently active posts are Nuno asking asking easily googlable questions about trivially fixable issues

Never change. At least that cat picture is gone.
User avatar
Ycep
Member
Member
Posts: 401
Joined: Mon Dec 28, 2015 11:11 am

Re: How do i fix my newline procedure?

Post by Ycep »

I'm not making any mistakes. I totally understand that terminal is just fake piece of memory made of 16-bit cells.
He is the one that doesn't understand VGA text-mode buffer.
You are making too long pointless posts. Couldn't you write just this:
- Putting newline (0x0A) inside text-mode video buffer would make video card display ASCII equivalent of 0x0A, which is his reason of seeing such strange signs on screen. You could not use carriage return + left tab on such terminal.
User avatar
jojo
Member
Member
Posts: 138
Joined: Mon Apr 18, 2016 9:50 am
Libera.chat IRC: jojo
Location: New York New York

Re: How do i fix my newline procedure?

Post by jojo »

Wow, sorry the guy is trying to be clear and verbose while he's being graciously helpful.
Post Reply