我想创建自己的操作系统。在这个操作系统中,我有一个用于修改文件数据的编辑模式(目前仅在RAM中)。这是这个操作系统的完整代码:
#include "editor.h"
#include "uart.h"
#include "strings.h"
void edit_file(File *file){
char c;
int index = 0;
uart_puts("\r\nEntering edit mode. Press Ctrl + Q to save and exit.\r\n");
if (file -> content[0] != '\0'){
uart_puts(file->content);
index = my_strlen(file->content);
}
while(1){
c = uart_getc();
if(c == 17){ //Ctrl + Q
file->content[index] = '\0';
uart_puts("\r\nFile saved and exited edit mode.\r\n");
break;
}else if (c == '\b' || c == 127){
if(index > 0){
index--;
uart_puts("\b \b");
}
}else if (c == '\r'){
if(index < MAX_FILE_SIZE -1){
file-> content[index++]='\n';
uart_putc('\r');
uart_putc('\n');
}
}else{
if(index < MAX_FILE_SIZE -1){
file->content[index++] = c;
uart_putc(c);
}
}
}
}
在系统内实现一个简单的文本编辑器。包括进入编辑模式和捕获用户输入的功能。支持编辑现有文件内容或创建新内容。处理特殊输入,例如:Ctrl + Q 保存并退出编辑模式。退格键和回车键。更新内存 (RAM) 中的文件内容。 这里编辑.h:
#ifndef EDITOR_H
#define EDITOR_H
#include "file_system.h"
void edit_file(File *file);
#endif
包括
edit_file(File *file)
的声明。
包括必要的标题:file_system.h
。这里file_system.c
:
#include "file_system.h"
#include "uart.h"
#include <stdint.h>
#include "editor.h"
#include "strings.h"
FileSystem fs;
void init_fs(){
fs.file_count = 0;
}
int create_directory(const char *name){
if(fs.file_count >= MAX_FILES){
uart_puts("FileSystem is full, cannot create directory.\r\n");
return -1;
}
for (int i = 0; i < fs.file_count; i++){
if(my_strcmp(fs.files[i].name, name) == 0){
uart_puts("Directory already exist.\r\n");
return -1;
}
}
my_strcpy(fs.files[fs.file_count].name, name);
fs.files[fs.file_count].is_directory = 1;
fs.file_count++;
uart_puts("Directory created. \r\n");
return 0;
}
int create_file(const char *name){
if(fs.file_count >= MAX_FILES){
uart_puts("FileSystem is full, cannot crete file. \r\n");
return -1;
}
for (int i = 0; i < fs.file_count; i++){
if(my_strcmp(fs.files[i].name, name) == 0){
uart_puts("File already exist.\r\n");
return -1;
}
}
my_strcpy(fs.files[fs.file_count].name, name);
fs.files[fs.file_count].is_directory = 0;
fs.files[fs.file_count].content[0] = '\0';
fs.file_count++;
uart_puts("File created.\r\n");
return 0;
}
void list_directory(){
uart_puts("Directories:\r\n");
if(fs.file_count == 0){
uart_puts("No directories.\r\n");
}else{
for (int i = 0; i < fs.file_count; i++){
if(fs.files[i].is_directory){
uart_puts(fs.files[i].name);
uart_putc('\r');
uart_putc('\n');
}
}
}
}
File *find_file(const char *name){
for (int i = 0; i < fs.file_count; i++){
if(!fs.files[i].is_directory && my_strcmp(fs.files[i].name, name) == 0){
return &fs.files[i];
}
}
return NULL;
}
void process_command(const char *cmd, int *debug_mode){
uart_puts("\r\n");
if(my_strcmp(cmd, "help") == 0){
uart_puts("Avaible commands: help, echo <message>, debug on, debug off, mkdir <name>, ls, mkf <file> edit <file>. \r\n");
}else if(my_strncmp(cmd, "echo ", 5) == 0){
uart_puts(cmd + 5);
uart_putc('\r');
uart_putc('\n');
}else if(my_strcmp(cmd, "debug on") == 0){
*debug_mode = 1;
uart_puts("Debug mode enabled. \r\n");
}else if(my_strcmp(cmd, "debug off") == 0){
*debug_mode = 0;
uart_puts("Debug mode disable. \r\n");
}else if(my_strncmp(cmd, "mkdir ", 6) == 0){
create_directory(cmd + 6);
}else if(my_strncmp(cmd, "edit ", 5) == 0){
File *file = find_file(cmd + 5);
if (file){
edit_file(file);
}else{
uart_puts("File not found.\n\r");
}
}else if(my_strncmp(cmd, "mkf ", 4) == 0){
create_file(cmd + 4);
}else if (my_strcmp(cmd, "ls") == 0){
list_directory();
}else{
uart_puts("Unknown command. \r\n");
}
}
void print_command(const char *cmd, int debug_mode){
if(debug_mode){
uart_puts("\r\nReceived command: ");
uart_puts(cmd);
uart_putc('\r');
uart_putc('\n');
}
}
定义文件系统并使用 init_fs() 对其进行初始化。 功能:
命令处理支持 help、echo、debug on/off、mkdir、ls、mkf、edit 等命令。 通过 UART 提供反馈。
和
file_system.h
:
#ifndef FILE_SYSTEM_H
#define FILE_SYSTEM_H
#define MAX_FILES 16
#define MAX_NAME_LEGTH 32
#define MAX_FILE_SIZE 1024
#include <stddef.h>
typedef unsigned long size_t;
typedef struct{
char name [MAX_NAME_LEGTH];
int is_directory;
char content[MAX_FILE_SIZE];
} File;
typedef struct{
File files[MAX_FILES];
int file_count;
} FileSystem;
void init_fs();
int create_directory(const char *name);
int create_file(const char *name);
void list_directory();
File *find_file(const char *name);
void process_command(const char *cmd, int *debug_mode);
void print_command(const char *cmd, int debug_mode);
#endif
file_system.c
的头文件,定义结构和函数原型。
详情:
常数:
memmp - 它只是一个链接器:
ENTRY(_main)
SECTIONS
{
. = 0x40000000; /* Начальный адрес загрузки */
.startup : { strap.o(.text) } /* Секция для инициализации (например, strap.o) */
.text : {
*(.text) /* Код программы */
}
.data : {
*(.data) /* Инициализированные данные */
}
.bss : {
*(.bss COMMON) /* Неиницилизированные данные */
}
/* Секция для хранения файловой системы */
.fs_section (NOLOAD) : {
*(.fs_section) /* Секция для файловой системы */
}
. = ALIGN(8); /* Выравнивание */
. = . + 0x1000; /* 4kB памяти для стека */
stack_top = .; /* Указатель на верх стека */
}
这是主要文件:
#include "uart.h"
#include "file_system.h"
#include "strings.h"
#define COMMAND_HISTORY_SiZE 10
void notmain(void){
char c;
char command[100];
int index = 0;
int debug_mode = 0;//0 - debug off, 1 - on
char command_history[COMMAND_HISTORY_SiZE][100];
int command_history_count = 0;
int command_history_pos = -1;
uart_puts("UART test... \n");
init_fs();
while(1){
c = uart_getc();
if(c == '\r'){
command[index] = '\0';
if(command[0] != '\0'){
if(command_history_count < COMMAND_HISTORY_SiZE){
my_strcpy(command_history[command_history_count++], command);
}else{
for (int i = 0; i < COMMAND_HISTORY_SiZE; i++){
my_strcpy(command_history[i-1], command_history[i]);
}
my_strcpy(command_history[COMMAND_HISTORY_SiZE - 1], command);
}
}
command_history_pos = command_history_count;
print_command(command, debug_mode);
process_command(command, &debug_mode);
index = 0;
} else if (c == '\b' || c == 127){
if(index > 0){
index--;
uart_puts("\b \b");
}
} else if(c == 27){
char seq[2];
seq[0] = uart_getc();
seq[1] = uart_getc();
if(seq[0] == '['){
if(seq[1]=='A'){
if(command_history_pos > 0){
command_history_pos--;
while(index > 0){
uart_puts("\b \b");
index--;
}
my_strcpy(command, command_history[command_history_pos]);
index = my_strlen(command);
uart_puts(command);
}
}else if(seq[1] == 'B'){
if(command_history_pos < command_history_count - 1){
command_history_pos++;
while(index > 0){
uart_puts("\b \b");
index--;
}
my_strcpy(command, command_history[command_history_pos]);
index = my_strlen(command);
uart_puts(command);
}else if(command_history_pos == command_history_count - 1){
while(index > 0){
uart_puts("\b \b");
index--;
}
command[0] = '\0';
}
}
}
}else{
if(index < sizeof(command)-1){
command[index++] = c;
uart_putc(c);
}
}
}
}
功能:
这里是汇编代码(strap.s):
.global _main
_main:
ldr x30, =stack_top
mov sp, x30
bl notmain
b .
功能:
我还写了自己的strings.s文件:
#include "strings.h"
int my_strlen(const char *str){
int len = 0;
while(*str++){
len++;
}
return len;
}
int my_strcmp(const char *s1, const char *s2){
while (*s1 && (*s1 == *s2)){
s1++;
s2++;
}
return (unsigned char)*s1 - (unsigned char)*s2;
}
int my_strncmp(const char *s1, const char *s2, size_t n){
while (n > 0){
if(*s1 != *s2){
return (unsigned char)*s1 - (unsigned char)*s2;
}
if (*s1 == '\0'){
return 0;
}
s1++;
s2++;
n--;
}
return 0;
}
void my_strcpy(char *dest, const char *src){
while(*src){
*dest++ = *src++;
}
*dest = '\0';
}
包括strcpy、strncmp、strcmp、strlen。 我还有头文件:
#ifndef STRINGS_H
#define STRINGS_H
#include <stddef.h>
int my_strlen(const char *str);
int my_strcmp(const char *s1, const char *s2);
int my_strncmp(const char *s1, const char *s2, size_t n);
void my_strcpy(char *dest, const char *src);
#endif
我还有
uart.c
用于 I/O 识别的文件:
#include "uart.h"
#include <stdint.h>
void uart_putc(char c){
volatile uint32_t *UARTFR = (uint32_t *)UART0_FR;
volatile uint32_t *UARTDR = (uint32_t *)UART0_DR;
while(*UARTFR & (1<<5)){
}
*UARTDR = c;
}
char uart_getc(){
volatile uint32_t *UARTFR = (uint32_t *)UART0_FR;
volatile uint32_t *UARTDR = (uint32_t *)UART0_DR;
while(*UARTFR & (1<<4)){
}
return *UARTDR & 0xFF;
}
void uart_puts(const char *str){
while (*str){
uart_putc(*str++);
}
}
该文件的功能:
我正在尝试更新我的编辑器,以突出显示 C/C++ 关键字、数字和分号。我试着用
editor.c
来做到这一点:
#include "editor.h"
#include "uart.h"
#include "strings.h"
// ANSI color codes
#define COLOR_RESET "\033[0m"
#define COLOR_KEYWORD "\033[31m" // Red color for keywords and semicolons
#define COLOR_NUMBER "\033[32m" // Green color for numbers
// You can adjust the colors as needed
int is_c_or_cpp_file(const char *filename){
int len = my_strlen(filename);
if(len >= 2 && my_strcmp(filename + len - 2, ".c") == 0){
return 1;
}
if(len >= 4 && my_strcmp(filename + len - 4, ".cpp") == 0){
return 1;
}
return 0;
}
const char* keywords[] = {
"int", "char", "if", "else", "for", "while", "return", "void", "include",
"define", "struct", "typedef", "enum", "static", "const", "unsigned",
"signed", "long", "short", "float", "double", "do", "switch", "case",
"break", "continue", "default", "goto", "sizeof", "volatile", "register",
"extern", "auto", "union", "inline"
};
#define NUM_KEYWORDS (sizeof(keywords)/sizeof(keywords[0]))
int is_keyword(const char *word){
for(int i = 0; i < NUM_KEYWORDS; i++){
if(my_strcmp(word, keywords[i]) == 0){
return 1;
}
}
return 0;
}
int is_number(const char *word){
int i = 0;
if(word[0] == '-' || word[0] == '+') i++; // handle sign
int has_digits = 0;
for(; word[i]; i++){
if(word[i] >= '0' && word[i] <= '9'){
has_digits = 1;
} else {
return 0;
}
}
return has_digits;
}
void move_cursor_back(int n){
for(int i = 0; i < n; i++){
uart_puts("\b \b");
}
}
void output_with_syntax_highlighting(const char *content){
int i = 0;
char word[50];
int word_index = 0;
char c;
while((c = content[i]) != '\0'){
if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (c >= '0' && c <= '9')){
if(word_index < sizeof(word) - 1){
word[word_index++] = c;
}
// We don't output yet
}else{
word[word_index] = '\0';
if(is_keyword(word)){
uart_puts(COLOR_KEYWORD);
uart_puts(word);
uart_puts(COLOR_RESET);
}else if(is_number(word)){
uart_puts(COLOR_NUMBER);
uart_puts(word);
uart_puts(COLOR_RESET);
}else{
uart_puts(word);
}
word_index = 0;
if(c == ';'){
uart_puts(COLOR_KEYWORD);
uart_putc(c);
uart_puts(COLOR_RESET);
}else{
uart_putc(c);
}
}
i++;
}
// Output any remaining word
if(word_index > 0){
word[word_index] = '\0';
if(is_keyword(word)){
uart_puts(COLOR_KEYWORD);
uart_puts(word);
uart_puts(COLOR_RESET);
}else if(is_number(word)){
uart_puts(COLOR_NUMBER);
uart_puts(word);
uart_puts(COLOR_RESET);
}else{
uart_puts(word);
}
}
}
void edit_file(File *file){
char c;
int index = 0;
uart_puts("\r\nEntering edit mode. Press Ctrl + Q to save and exit.\r\n");
int syntax_highlighting = 0;
if(is_c_or_cpp_file(file->name)){
syntax_highlighting = 1;
}
if (file->content[0] != '\0'){
if(syntax_highlighting){
output_with_syntax_highlighting(file->content);
}else{
uart_puts(file->content);
}
index = my_strlen(file->content);
}
char word[50];
int word_index = 0;
while(1){
c = uart_getc();
if(c == 17){ //Ctrl + Q
file->content[index] = '\0';
uart_puts("\r\nFile saved and exited edit mode.\r\n");
break;
}else if (c == '\b' || c == 127){
if(index > 0){
index--;
uart_puts("\b \b");
// Handle word buffer
if(word_index > 0){
word_index--;
}
}
}else if (c == '\r'){
if(index < MAX_FILE_SIZE -1){
file->content[index++]='\n';
uart_putc('\r');
uart_putc('\n');
word[word_index] = '\0';
// Process the word at end of line
if(syntax_highlighting && word_index > 0){
if(is_keyword(word)){
move_cursor_back(word_index);
uart_puts(COLOR_KEYWORD);
uart_puts(word);
uart_puts(COLOR_RESET);
}else if(is_number(word)){
move_cursor_back(word_index);
uart_puts(COLOR_NUMBER);
uart_puts(word);
uart_puts(COLOR_RESET);
}
word_index = 0;
}else{
word_index = 0;
}
}
}else{
if(index < MAX_FILE_SIZE -1){
file->content[index++] = c;
if(syntax_highlighting){
if((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (c >= '0' && c <= '9')){
if(word_index < sizeof(word) - 1){
word[word_index++] = c;
}
uart_putc(c); // Temporarily output the character
}else{
// Non-alphanumeric character
word[word_index] = '\0';
// Check for keyword or number
if(is_keyword(word)){
move_cursor_back(word_index);
uart_puts(COLOR_KEYWORD);
uart_puts(word);
uart_puts(COLOR_RESET);
}else if(is_number(word)){
move_cursor_back(word_index);
uart_puts(COLOR_NUMBER);
uart_puts(word);
uart_puts(COLOR_RESET);
}
word_index = 0;
// Handle semicolons
if(c == ';'){
uart_puts(COLOR_KEYWORD);
uart_putc(c);
uart_puts(COLOR_RESET);
}else{
uart_putc(c);
}
}
}else{
uart_putc(c);
}
}
}
}
}
和头文件:
#ifndef EDITOR_H
#define EDITOR_H
#include "file_system.h"
// Визначення ANSI-кодів кольорів
#define ANSI_COLOR_RED "\033[31m"
#define ANSI_COLOR_GREEN "\033[32m"
#define ANSI_COLOR_YELLOW "\033[33m"
#define ANSI_COLOR_BLUE "\033[34m"
#define ANSI_COLOR_MAGENTA "\033[35m"
#define ANSI_COLOR_CYAN "\033[36m"
#define ANSI_COLOR_RESET "\033[0m"
void edit_file(File *file);
// Прототипи функцій
void display_with_syntax_highlighting(const char *content);
void re_render_current_line(const char *content, int length);
int is_letter_or_digit(char c);
int is_keyword(const char *word);
#endif
我还添加了notmain.c用于测试颜色的小功能:
void test_ansi_colors() {
uart_puts("\033[31mЦей текст повинен бути червоним\033[0m\r\n");
uart_puts("\033[32mЦей текст повинен бути зеленим\033[0m\r\n");
uart_puts("\033[34mЦей текст повинен бути синім\033[0m\r\n");
}
我正在使用 qemu 命令进行测试:
qemu-system-aarch64 -nographic -M virt -cpu cortex-a53 -m 128 -serial mon:stdio -kernel os.bin
当我启动它时,它是彩色的:
但是,当我创建文件并尝试编辑它时,我遇到了一个小问题:
为什么关键词没有突出显示?
所以,总而言之,我需要什么:
为 .c/.cpp 文件和 .java 文件添加关键字突出显示(只需 else if 语句)。它还必须以绿色文本突出显示,其中
" "
(双引号)和数字 (4, 4412, 2_000_000, 2E+1)
// #include "editor.h"
// #include "uart.h"
// #include "strings.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#ifdef __linux__
#include <termios.h> //termios, TCSANOW, ECHO, ICANON
#include <unistd.h> //STDIN_FILENO
#endif // #ifdef __linux__
#include <stdio.h>
int my_strncmp(const char *s1, const char *s2, size_t n)
{
while (n > 0 && *s1 && (*s1 == *s2))
{
s1++;
s2++;
n--;
}
return (unsigned char)*s1 - (unsigned char)*s2;
}
void my_strcpy(char *dest, const char *src)
{
while (*src)
*dest++ = *src++;
*dest = '\0';
}
// ANSI color codes
#define COLOR_RESET "\033[0m"
#define COLOR_KEYWORD "\033[35m" // Red color for keywords and semicolons
#define COLOR_NUMBER "\033[36m" // Green color for numbers
// You can adjust the colors as needed
bool is_c_or_cpp_file(const char *filename)
{
int len = my_strlen(filename);
return (len >= 2 && my_strcmp(filename + len - 2, ".c") == 0) || (len >= 4 && my_strcmp(filename + len - 4, ".cpp") == 0);
}
static const char *keywords[] = {
"int", "char", "if", "else", "for", "while", "return", "void", "include",
"define", "struct", "typedef", "enum", "static", "const", "unsigned",
"signed", "long", "short", "float", "double", "do", "switch", "case",
"break", "continue", "default", "goto", "sizeof", "volatile", "register",
"extern", "auto", "union", "inline"};
#define NUM_KEYWORDS (sizeof(keywords) / sizeof(keywords[0]))
void move_cursor_back(int n)
{
for (int i = 0; i < n; i++)
uart_puts("\b \b");
}
void highlight(const char *s, const int l, const char *colour)
{
move_cursor_back(l);
uart_puts(colour);
uart_puts(s);
uart_puts(COLOR_RESET);
}
void edit_file(File *file)
{
int c;
int index = 0;
uart_puts("\r\nEntering edit mode. Press Ctrl + Q to save and exit.\r\n");
int syntax_highlighting = 0;
if (is_c_or_cpp_file(file->name))
{
syntax_highlighting = 1;
}
if (file->content[0] != '\0')
{
if (syntax_highlighting)
output_with_syntax_highlighting(file->content);
else
uart_puts(file->content);
index = my_strlen(file->content);
}
char word[2048];
int word_index = 0;
#ifdef __linux__
static struct termios oldt, newt;
/*tcgetattr gets the parameters of the current terminal
STDIN_FILENO will tell tcgetattr that it should write the settings
of stdin to oldt*/
tcgetattr(STDIN_FILENO, &oldt);
/*now the settings will be copied*/
newt = oldt;
/*ICANON normally takes care that one line at a time will be processed
that means it will return if it sees a "\n" or an EOF or an EOL*/
newt.c_lflag &= ~(ICANON);
/*Those new settings will be set to STDIN
TCSANOW tells tcsetattr to change attributes immediately. */
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
#endif // __linux__
while (1)
{
c = uart_getc();
switch (c)
{
case '\b':
case 0x7f:
if (index > 0)
{
index--;
uart_puts("\b\b\b \b\b\b");
// Handle word buffer
if (word_index > 0)
{
word_index--;
}
}
break;
case '\r':
if (index < 255 - 1 && word_index > 0)
file->content[++index] = '\n';
break;
default:
if (index < MAX_FILE_SIZE - 1)
{
file->content[index++] = c;
// break;
if (syntax_highlighting)
{
if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c == '_') || (c >= '0' && c <= '9'))
{
if (word_index < sizeof(word) - 1)
word[word_index++] = c;
}
else
{
// Non-alphanumeric character
word[word_index++] = '\0';
// Check for keyword or number
bool highlighted = false;
if ((highlighted = is_keyword(word)))
highlight(word, word_index, COLOR_KEYWORD);
else if ((highlighted = is_number(word)))
highlight(word, word_index, COLOR_NUMBER);
if (c == ';')
highlight((char *)&c, 0, COLOR_KEYWORD);
else if (c != '\n' && highlighted)
uart_putc(c);
word_index = 0;
}
}
}
break;
}
}
#ifdef __linux__
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
#endif // __linux__
}
我改变了什么:
DEL
(0x7f) 需要 3 \b
,因为它被视为 ^?\x7f
。keywords
定义为 static const char *
为了更好的可读性:
bool
而不是int
highlight
功能和is_c_or_cpp_file
缩短了switch
案例而不是连锁的if
陈述让我知道它是否也适合您,也许您的模拟器上的行为有所不同。