I have also written a shell, and this is where I have been testing the filesystem implementation. I just finished implementing the `ls` command (which I have tested from inside the kernel and it prints the names of files/folders correctly). This is what it looks like when printing from the kernel (hard coded inside the kernel):
but when I type in `ls` from the shell, I get
As you can see, the text even overflows to the line with the part before the `$`, which is just meant to show `/`, the current working directory.
I am fairly certain that this is a printing (printf?) issue, since this problem with printing is not unique to the `ls` command or even to the shell. The problem with printing arose quite a long time ago with the biggest problem being that `0`'s would not get printed, instead there was just a blank space printed. I chose to ignore the problem rather stupidly, and now the problem has got worse The printing issue became most notable when printing out files and folders, but it has existed for a long time.
So here is my `vprintf.c` and `kprintf.c` files (please ignore any bad coding and lack of comments, since this code was written a long time ago, and I have since learned a lot more about C, good programming practice/readability and more about programming in general):
`kprintf.c`:
Code: Select all
#include "stdio.h"
// Unpacks the variable arguments and passes them to vprintf to be printed to the screen
int kprintf(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
// Pass the arguments to vprintf to be unpacked and printed and then get the number
// of characters written to the screen as returned by vprintf
int num_chars_written = vprintf(fmt, args);
va_end(args);
return num_chars_written;
}
Code: Select all
#include <stdarg.h>
#include "stdio.h"
#include "../size_t.h"
extern size_t strlen(const char *str);
extern char *strrev(char *str);
int vprintf(const char *fmt, va_list args)
{
unsigned int j;
unsigned int num_chars_written = 0;
for (j = 0; j < strlen(fmt); j++)
{
/* check for format specifier */
if (fmt[j] == '%')
{
/* print a number to the screen */
if (fmt[j + 1] == 'd')
{
int i = va_arg(args, int);
char *str = "";
// if (strncmp("0x", (char *) i, 2) == 0) { //convert to decimal }
if (i == 0 || i == '0')
{
puts("0");
}
else
{
// Convert the integer to a string, increase num_chars_written and print the integer
itoa(i, str, 10);
num_chars_written += strlen(str);
puts(str);
}
}
/* prints a character to the screen */
else if (fmt[j + 1] == 'c')
{
int c = va_arg(args, int);
num_chars_written++;
putchar(c);
}
/* prints a string to the screen */
else if (fmt[j + 1] == 's')
{
char* s = va_arg(args, char*);
num_chars_written += strlen(s);
puts(s);
}
/* check if number is to be converted to hex */
else if (fmt[j + 1] == 'x' || fmt[j + 1] == 'X')
{
int j = 0;
int i = va_arg(args, int);
char *str = "";
itoa(i, str, 10);
// Set the maximum number of characters to the length of the number as a string, leaving a space for the null byte
char hex[strlen(str)];
// Print hex characters in lowercase if lowercase x was used, otherwise print hex in uppercase
if (fmt[j + 1] == 'x')
{
char hex_chars_lower[] = "0123456789abcdef";
do
{
hex[j++] = hex_chars_lower[i % 16];
} while ((i /= 16) > 0);
}
else
{
char hex_chars_upper[] = "0123456789abcdef";
do
{
hex[j++] = hex_chars_upper[i % 16];
} while ((i /= 16) > 0);
}
hex[j] = '\0';
strrev(hex);
hex[j + 1] = '\0';
num_chars_written += strlen(hex);
puts(hex);
}
/* check if pointer is to be printed */
else if (fmt[j + 1] == 'p')
{
void *ptr = va_arg(args, void *);
kprintf("%d", ptr);
}
/* prints a percent (%) */
else if (fmt[j + 1] == '%')
{
num_chars_written++;
putchar('%');
}
/* prints a new line (cursor goes to the beginning of the next line) */
else if (fmt[j] == '\n')
{
// Calls to kprintf() with '\n' result in "\r\n" being printed
num_chars_written += 1;
putchar('\n');
}
/* prints a tab character */
else if (fmt[j] == '\t')
{
num_chars_written++;
putchar('\t');
}
}
/* else, print the character */
else if (fmt[j - 1] != '%')
{
num_chars_written++;
putchar(fmt[j]);
}
}
return num_chars_written;
}
Code: Select all
// Write a character to the screen
void terminal_putchar(char c)
{
char *vidmem = (char *)0xB8000;
// '\n' sends cursor to beginning of next line
if (c == '\n')
{
x = 0;
y += 2;
}
else
{
unsigned int i = y * VGA_WIDTH + x;
vidmem[i] = c;
move_cursor(x + 1, y);
i++;
vidmem[i] = terminal_get_color();
move_cursor(x + 1, y);
}
if (y > 48)
{
terminal_scroll();
y -= 2;
}
}
Code: Select all
// Write a string to the screen
void terminal_write(char *str)
{
for (unsigned int i = 0; i < strlen(str); i++)
{
terminal_putchar(str[i]);
}
}
Code: Select all
// List the contents of the current directory
void xsh_ls(char **args)
{
char *dirname = args[1];
DIR *dir = opendir(dirname);
if (dir == NULL)
{
kprintf("ls: cannot access '%s': no such directory", dirname);
return;
}
// Print out each directory name in `sub_dirnames`
for (unsigned int i = 0; i < dir->total_entries; i++)
{
if (i != dir->total_entries - 1)
puts(sub_dirnames[i]);
// kprintf("%s\n", sub_dirnames[i]);
else
puts(sub_dirnames[i]);
// kprintf("%s", sub_dirnames[i]);
}
kprintf("\n\n\n");
closedir(dir);
}