Char * is always null terminator

83 Views Asked by At

I am trying to implement a VGA print function but I cannot get data to be seen as a non null character. Even if I hardcode data inside this function it will still skip the while loop. I have a debug print that will print a Z if count is zero and it always prints it and the cursor does not move so I am pretty confident it is not entering the while loop

void vga_print(char *data, char mode) {

    char *vga = (char *)(VGA_MEM_LOC);

    uint8_t count = 0;
    while (*data != '\0') {
        if (*data == '\n') {
            current_x = 0;
            current_y++;
        } else {
            *vga++ = *data++;
            *vga++ = mode;
            current_x++;
            if (current_x >= screen_x) {
                current_x = 0;
                current_y++;
            }
        }
        count++;
    }

    // move the cursor
    uint16_t location = current_x + ((current_y) * screen_x);

    x86_port_out(VGA_CRT_INDEX, VGA_CURSOR_LOW);
    x86_port_out(VGA_CRT_DATA,  location);

    x86_port_out(VGA_CRT_INDEX, VGA_CURSOR_HIGH);
    x86_port_out(VGA_CRT_DATA,  location >> 8);
}

EDIT: If I initialize the data string as char example[] = "xyz\0" instead of char *example = "xyz\0" it works

1

There are 1 best solutions below

4
chqrlie On

There are problems in the function, but none that explains the observed behavior. There might be something wrong with the initial values of the global variables current_x, current_y and screen_x or the way you call the function from code you did not post. The definitions of VGA_CRT_INDEX, VGA_CURSOR_LOW, VGA_CRT_DATA, VGA_CURSOR_HIGH, VGA_MEM_LOC and the function x86_port_out might be incorrect too.

Here are some problems:

  • all output starts at the base address of the VGA screen buffer.
  • current_x and current_y get updated for each byte and the newline, but the vga pointer does not move so the next character appears glued to the previous output.
  • you do not increment data when *data == '\n': this would cause an infinite loop.
  • you do not handle the case where current_y >= screen_y.

Here is a modified version:

void vga_print(const char *data, unsigned char mode) {

    uint16_t *vga = (uint16_t *)(VGA_MEM_LOC);
    uint16_t location = current_x + current_y * screen_x;
    uint16_t i;
    uint8_t ch;

    while ((ch = *data++) != '\0') {
        if (ch == '\n' || current_x >= screen_x) {
            current_x = 0;
            current_y++;
            location = current_y * screen_x;
        }
        if (current_y >= screen_y) {
            current_y = screen_y - 1;
            location = current_y * screen_x;
            // shift the screen contents up one line
            for (i = 0; i < location; i++)
                vga[i] = vga[i + screen_x];
            }
            // erase the bottom line
            for (i = 0; i < screen_x; i++) {
                vga[location + i] = ' ' | (mode << 8);
            }
            location += screen_x;
        }
        if (ch != '\n') {
            vga[location++] = ch | (mode << 8);
            current_x++;
        }
    }

    // move the cursor
    x86_port_out(VGA_CRT_INDEX, VGA_CURSOR_LOW);
    x86_port_out(VGA_CRT_DATA, (uint8_t)location);

    x86_port_out(VGA_CRT_INDEX, VGA_CURSOR_HIGH);
    x86_port_out(VGA_CRT_DATA, (uint8_t)(location >> 8));
}