diff --git a/Fennix Userspace.code-workspace b/Fennix Userspace.code-workspace index de72dea0..b8f074ad 100644 --- a/Fennix Userspace.code-workspace +++ b/Fennix Userspace.code-workspace @@ -18,7 +18,8 @@ "userspace/libs/libm", "devcontainer", "userspace/libs", - "userspace/apps/test" + "userspace/apps/test", + "userspace/apps/usr" ] } } diff --git a/Userspace/apps/usr/Makefile b/Userspace/apps/usr/Makefile new file mode 100644 index 00000000..8ea8a10f --- /dev/null +++ b/Userspace/apps/usr/Makefile @@ -0,0 +1,9 @@ +MAKE_TARGETS := build clean +DIRECTORIES := $(sort $(dir $(wildcard ./*/))) + +.PHONY: $(MAKE_TARGETS) $(DIRECTORIES) + +$(MAKE_TARGETS): $(DIRECTORIES) + +$(DIRECTORIES): + $(MAKE) -C $@ $(MAKECMDGOALS) diff --git a/Userspace/apps/usr/mdview/Makefile b/Userspace/apps/usr/mdview/Makefile new file mode 100644 index 00000000..90165364 --- /dev/null +++ b/Userspace/apps/usr/mdview/Makefile @@ -0,0 +1,33 @@ +default: + $(error Do not run this Makefile directly!) + +S_SOURCES = $(shell find ./ -type f -name '*.S') +C_SOURCES = $(shell find ./ -type f -name '*.c') +CXX_SOURCES = $(shell find ./ -type f -name '*.cpp') + +OBJ = $(S_SOURCES:.S=.o) $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) + +FILENAME = $(notdir $(shell pwd)) +WARNCFLAG = -Wall -Wextra + +build: $(FILENAME).elf + cp $(FILENAME).elf $(WORKSPACE_DIR)/out/usr/bin/$(FILENAME) + +$(FILENAME).elf: $(OBJ) + $(info Linking $@) + $(CC) $(LDFLAGS) $(SYSROOT) $(OBJ) -o $@ + +%.o: %.c $(HEADERS) + $(info Compiling $<) + $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@ + +%.o: %.cpp $(HEADERS) + $(info Compiling $<) + $(CXX) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@ -fno-rtti + +%.o: %.S + $(info Compiling $<) + $(AS) -o $@ $< + +clean: + rm -f $(OBJ) $(FILENAME).elf diff --git a/Userspace/apps/usr/mdview/mdview.c b/Userspace/apps/usr/mdview/mdview.c new file mode 100644 index 00000000..d1e7c86a --- /dev/null +++ b/Userspace/apps/usr/mdview/mdview.c @@ -0,0 +1,419 @@ +/* + This file is part of Fennix Userspace. + + Fennix Userspace is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Userspace is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Userspace. If not, see . +*/ + +#include +#include +#include +#include +#include +#include + +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_GREEN "\x1b[32m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_BLUE "\x1b[34m" +#define ANSI_COLOR_MAGENTA "\x1b[35m" +#define ANSI_COLOR_CYAN "\x1b[36m" +#define ANSI_COLOR_WHITE "\x1b[37m" +#define ANSI_COLOR_BLACK "\x1b[30m" +#define ANSI_COLOR_RESET "\x1b[0m" + +#define ANSI_BG_BLACK "\x1b[40m" +#define ANSI_BG_RED "\x1b[41m" +#define ANSI_BG_GREEN "\x1b[42m" +#define ANSI_BG_YELLOW "\x1b[43m" +#define ANSI_BG_BLUE "\x1b[44m" +#define ANSI_BG_MAGENTA "\x1b[45m" +#define ANSI_BG_CYAN "\x1b[46m" +#define ANSI_BG_GRAY "\x1b[47m" +#define ANSI_BG_DARK_GRAY "\x1b[100m" + +#define ANSI_BOLD "\x1b[1m" +#define ANSI_UNDERLINE "\x1b[4m" +#define ANSI_STRIKETHROUGH "\x1b[9m" +#define ANSI_HIGHLIGHT "\x1b[43m" + +void print_horizontal_rule() +{ + int width; + struct winsize ws; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); + width = ws.ws_col; + for (int i = 0; i < width - 2; i++) + printf("-"); +} + +void print_admonition(const char *type, const char *title, const char *content) +{ + if (strcmp(type, "warning") == 0) + { + printf(ANSI_BG_YELLOW); + printf(ANSI_COLOR_BLACK); + printf("! Warning: %s %s\n", title, content); + } + else if (strcmp(type, "note") == 0) + { + printf(ANSI_BG_BLUE); + printf(ANSI_COLOR_WHITE); + printf("i Note: %s %s\n", title, content); + } + else if (strcmp(type, "tip") == 0) + { + printf(ANSI_BG_GREEN); + printf(ANSI_COLOR_WHITE); + printf("? Tip: %s %s\n", title, content); + } + else if (strcmp(type, "important") == 0) + { + printf(ANSI_BG_RED); + printf(ANSI_COLOR_BLACK); + printf("! Important: %s %s\n", title, content); + } + else if (strcmp(type, "caution") == 0) + { + printf(ANSI_BG_MAGENTA); + printf(ANSI_COLOR_WHITE); + printf("! Caution: %s %s\n", title, content); + } + else if (strcmp(type, "danger") == 0) + { + printf(ANSI_BG_RED); + printf(ANSI_COLOR_BLACK); + printf("! Danger: %s %s\n", title, content); + } + printf(ANSI_COLOR_RESET); +} + +void print_formatted_text(const char *text) +{ + bool bold = false; + bool underline = false; + bool inline_code = false; + bool strikethrough = false; + bool highlight = false; + + for (int i = 0; text[i] != '\0'; ++i) + { + if (strncmp(&text[i], "!!!", 3) == 0) + { + char admonition_type[20] = ""; + char admonition_title[256] = ""; + int type_start = i + 4; + int type_end = -1; + int title_start = -1; + int title_end = -1; + int content_start = -1; + + for (int j = type_start; text[j] != '\0' && text[j] != ' ' && text[j] != '"'; ++j) + { + type_end = j; + } + if (type_end != -1) + { + strncpy(admonition_type, &text[type_start], type_end - type_start + 1); + admonition_type[type_end - type_start + 1] = '\0'; + i = type_end + 1; + } + + if (text[i] == ' ' && text[i + 1] == '"') + { + title_start = i + 2; + for (int j = title_start; text[j] != '\0' && text[j] != '"'; ++j) + { + title_end = j; + } + if (title_end != -1) + { + strncpy(admonition_title, &text[title_start], title_end - title_start + 1); + admonition_title[title_end - title_start + 1] = '\0'; + i = title_end + 1; + } + } + + content_start = i + 1; + print_admonition(admonition_type, admonition_title, text + content_start); + return; + } + + if (text[i] == '`') + { + if (!inline_code) + { + printf(ANSI_BG_MAGENTA); + printf(ANSI_UNDERLINE); + printf(ANSI_BOLD); + inline_code = true; + } + else + { + printf(ANSI_COLOR_RESET); + inline_code = false; + } + } + else if (text[i] == '*' && text[i + 1] == '*') + { + if (!bold) + { + printf(ANSI_BOLD); + bold = true; + i++; + } + else + { + printf(ANSI_COLOR_RESET); + bold = false; + i++; + } + } + else if (text[i] == '_' && text[i + 1] == '_') + { + if (!underline) + { + printf(ANSI_UNDERLINE); + underline = true; + i++; + } + else + { + printf(ANSI_COLOR_RESET); + underline = false; + i++; + } + } + else if (text[i] == '~' && text[i + 1] == '~') + { + if (!strikethrough) + { + printf(ANSI_STRIKETHROUGH); + strikethrough = true; + i++; + } + else + { + printf(ANSI_COLOR_RESET); + strikethrough = false; + i++; + } + } + else if (text[i] == '=' && text[i + 1] == '=') + { + if (!highlight) + { + printf(ANSI_HIGHLIGHT); + highlight = true; + i++; + } + else + { + printf(ANSI_COLOR_RESET); + highlight = false; + i++; + } + } + else if (text[i] == '[') + { + int start_link_text = i + 1; + int end_link_text = -1; + int start_link_url = -1; + int end_link_url = -1; + + for (int j = start_link_text; text[j] != '\0'; ++j) + { + if (text[j] == ']') + { + end_link_text = j; + if (text[j + 1] == '(') + { + start_link_url = j + 2; + + for (int k = start_link_url; text[k] != '\0'; ++k) + { + if (text[k] == ')') + { + end_link_url = k; + break; + } + } + } + break; + } + } + + if (end_link_text != -1 && start_link_url != -1 && end_link_url != -1) + { + + char link_text[256]; + strncpy(link_text, &text[start_link_text], end_link_text - start_link_text); + link_text[end_link_text - start_link_text] = '\0'; + + char link_url[256]; + strncpy(link_url, &text[start_link_url], end_link_url - start_link_url); + link_url[end_link_url - start_link_url] = '\0'; + + printf(ANSI_UNDERLINE); + printf(link_text); + printf(ANSI_COLOR_RESET); + printf("(%s)", link_url); + i = end_link_url; + continue; + } + } + else if (text[i] == '<') + { + while (text[i] != '\0' && text[i] != '>') + { + i++; + } + if (text[i] == '>') + { + continue; + } + } + else if (strncmp(&text[i], "---\n", 4) == 0 || strncmp(&text[i], "***\n", 4) == 0 || strncmp(&text[i], "_________________\n", 18) == 0) + { + print_horizontal_rule(); + i += 2; + continue; + } + else if (strncmp(&text[i], "- [x] ", 6) == 0) + { + printf("[X] "); + i += 5; + continue; + } + else if (strncmp(&text[i], "- [ ] ", 6) == 0) + { + printf("[ ] "); + i += 5; + continue; + } + else + { + printf("%c", text[i]); + } + } + printf(ANSI_COLOR_RESET); +} + +void process_markdown_file(const char *filename) +{ + FILE *file = fopen(filename, "r"); + if (file == NULL) + { + perror("fopen"); + return; + } + + char *line = NULL; + size_t len = 0; + ssize_t read; + + while ((read = getline(&line, &len, file)) != -1) + { + if (strncmp(line, "# ", 2) == 0) + { + printf(ANSI_BOLD); + printf(ANSI_UNDERLINE); + printf("%s", line); + printf(ANSI_COLOR_RESET); + } + else if (strncmp(line, "## ", 3) == 0) + { + printf(ANSI_BOLD); + printf("%s", line); + printf(ANSI_COLOR_RESET); + } + else if (strncmp(line, "### ", 4) == 0) + { + printf(ANSI_UNDERLINE); + printf("%s", line); + printf(ANSI_COLOR_RESET); + } + else if (strncmp(line, "#### ", 5) == 0) + { + printf(ANSI_BOLD); + printf(ANSI_UNDERLINE); + printf(ANSI_COLOR_RED); + printf("%s", line); + printf(ANSI_COLOR_RESET); + } + else if (strncmp(line, "##### ", 6) == 0) + { + printf(ANSI_BOLD); + printf(ANSI_COLOR_MAGENTA); + printf("%s", line); + printf(ANSI_COLOR_RESET); + } + else if (strncmp(line, "###### ", 7) == 0) + { + printf(ANSI_UNDERLINE); + printf(ANSI_COLOR_BLUE); + printf("%s", line); + printf(ANSI_COLOR_RESET); + } + else if (strncmp(line, "```", 3) == 0) + { + printf(ANSI_BG_DARK_GRAY); + printf(ANSI_COLOR_WHITE); + printf("%s", line); + while ((read = getline(&line, &len, file)) != -1 && strncmp(line, "```", 3) != 0) + { + printf("%s", line); + } + printf("%s", line); + printf(ANSI_COLOR_RESET); + } + else if (strncmp(line, "> ", 2) == 0 && strncmp(line, ">> ", 3) != 0) + { + printf(ANSI_COLOR_WHITE); + printf(ANSI_BG_GRAY " " ANSI_BG_DARK_GRAY "%s", line + (strncmp(line, ">>", 2) == 0 ? 2 : 1)); + printf(ANSI_COLOR_RESET); + } + else if (strncmp(line, ">\n", 2) == 0) + { + printf(ANSI_COLOR_WHITE); + printf(ANSI_BG_GRAY " \n"); + printf(ANSI_COLOR_RESET); + } + else + { + print_formatted_text(line); + } + } + + fclose(file); + if (line) + free(line); +} + +void print_usage() +{ + printf("Usage: mdview \n"); +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) + { + fprintf(stderr, "mdview: invalid arguments\n"); + print_usage(); + exit(EXIT_FAILURE); + } + + process_markdown_file(argv[1]); + return 0; +} diff --git a/Userspace/apps/usr/mdview/test.md b/Userspace/apps/usr/mdview/test.md new file mode 100644 index 00000000..9b4d4043 --- /dev/null +++ b/Userspace/apps/usr/mdview/test.md @@ -0,0 +1,436 @@ +## Admonitions + +> :warning: **Warning:** This is a warning. + +> :memo: **Note:** This is a note. + +> :bulb: **Tip:** This is a tip. + +## GitHub Admonitions + +> [!NOTE] +> This is a note. + +> [!TIP] +> This is a tip. + +> [!IMPORTANT] +> This is important. + +> [!WARNING] +> This is a warning. + +> [!CAUTION] +> This is a caution. + +## python-markdown Admonitions + +!!! note "This is a note." + Hello World! + +!!! danger "This is a danger." + Hello World! + +!!! important "This is important." + Hello World! + +!!! warning "This is a warning." + Hello World! + +!!! caution "This is a caution." + Hello World! + +[The section below is an excerpt of the original.](https://www.markdownguide.org/cheat-sheet/) +The original content is licensed under a CC BY-SA 4.0 license. The original content can be found at the link above. + +## Headings + +# Heading level 1 +## Heading level 2 +### Heading level 3 +#### Heading level 4 +##### Heading level 5 +###### Heading level 6 + +## Alternate Syntax + +Heading level 1 +=============== + +Heading level 2 +--------------- + +--- + +## Paragraphs + +I really like using Markdown. + +I think I'll use it to format all of my documents from now on. + +--- + +## Line Breaks + +This is the first line. +And this is the second line. + +--- + +## Emphasis + +I just love **bold text**. + +I just love __bold text__. + +Love**is**bold + +Italicized text is the *cat's meow*. + +Italicized text is the _cat's meow_. + +A*cat*meow + +This text is ***really important***. + +This text is ___really important___. + +This text is __*really important*__. + +This text is **_really important_**. + +This is really***very***important text. + +--- + +## Blockquotes + +> Dorothy followed her through many of the beautiful rooms in her castle. + +> Dorothy followed her through many of the beautiful rooms in her castle. +> +> The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. + +> Dorothy followed her through many of the beautiful rooms in her castle. +> +>> The Witch bade her clean the pots and kettles and sweep the floor and keep the fire fed with wood. + +> #### The quarterly results look great! +> +> - Revenue was off the chart. +> - Profits were higher than ever. +> +> *Everything* is going according to **plan**. + +--- + +## Lists + +List 1 + +1. First item +2. Second item +3. Third item +4. Fourth item + +List 2 + +1. First item +1. Second item +1. Third item +1. Fourth item + +List 3 + +1. First item +8. Second item +3. Third item +5. Fourth item + +List 4 + +1. First item +2. Second item +3. Third item + 1. Indented item + 2. Indented item +4. Fourth item + +List 5 + +- First item +- Second item +- Third item +- Fourth item + +List 6 + +* First item +* Second item +* Third item +* Fourth item + +List 7 + ++ First item ++ Second item ++ Third item ++ Fourth item + +List 8 + +- First item +- Second item +- Third item + - Indented item + - Indented item +- Fourth item + +List 9 + +- 1968\. A great year! +- I think 1969 was second best. + +--- + +## Paragraphs + +* This is the first list item. +* Here's the second list item. + + I need to add another paragraph below the second list item. + +* And here's the third list item. + +* This is the first list item. +* Here's the second list item. + + > A blockquote would look great below the second list item. + +* And here's the third list item. + +--- + +## Code Blocks + +1. Open the file. +2. Find the following code block on line 21: + + + + Test + + +3. Update the title to match the name of your website. + +--- + +## Images + +1. Open the file containing the Linux mascot. +2. Marvel at its beauty. + + ![Tux, the Linux mascot](https://mdg.imgix.net/assets/images/tux.png) + +3. Close the file. + +--- + +## Code + +At the command prompt, type `nano`. + +``Use `code` in your Markdown file.`` + + + + + + +--- + +## Horizontal Rules + +*** + +--- + +_________________ + +--- + +## Links + +My favorite search engine is [Duck Duck Go](https://duckduckgo.com). + +My favorite search engine is [Duck Duck Go](https://duckduckgo.com "The best search engine for privacy"). + + + + + +I love supporting the **[EFF](https://eff.org)**. + +This is the *[Markdown Guide](https://www.markdownguide.org)*. + +See the section on [`code`](#code). + +In a hole in the ground there lived a hobbit. Not a nasty, dirty, wet hole, filled with the ends +of worms and an oozy smell, nor yet a dry, bare, sandy hole with nothing in it to sit down on or to +eat: it was a [hobbit-hole][1], and that means comfort. + +[1]: "Hobbit lifestyles" + +--- + +## Escaping Characters + +\* Without the backslash, this would be a bullet in an unordered list. + +\\ test + +\` test + +\* test + +\_ test + +\{ test + +\} test + +\[ test + +\] test + +\< test + +\> test + +\( test + +\) test + +\# test + +\+ test + +\- test + +\. test + +\! test + +\| test + +--- + +## HTML + +This **word** is bold. This word is italic. + +## Tables + +| Syntax | Description | +| ----------- | ----------- | +| Header | Title | +| Paragraph | Text | + +| Syntax | Description | +| --- | ----------- | +| Header | Title | +| Paragraph | Text | + +| Syntax | Description | Test Text | +| :--- | :----: | ---: | +| Header | Title | Here's this | +| Paragraph | Text | And more | + +--- + +## Fenced Code Blocks + +``` +{ + "firstName": "John", + "lastName": "Smith", + "age": 25 +} +``` + +```json +{ + "firstName": "John", + "lastName": "Smith", + "age": 25 +} +``` + +--- + +## Footnotes + +Here's a simple footnote,[^1] and here's a longer one.[^bignote] + +[^1]: This is the first footnote. + +[^bignote]: Here's one with multiple paragraphs and code. + + Indent paragraphs to include them in the footnote. + + `{ my code }` + + Add as many paragraphs as you like. + +--- + +## Heading IDs + +# Heading level 1 {#custom-id} +## Heading level 2 {#custom-id} +### Heading level 3 {#custom-id} +#### Heading level 4 {#custom-id} +##### Heading level 5 {#custom-id} +###### Heading level 6 {#custom-id} + +--- + +## Strikethrough + +~~The world is flat.~~ We now know that the world is round. + +--- + +## Task Lists + +- [x] Write the press release +- [ ] Update the website +- [ ] Contact the media + +--- + +## Emoji + +Gone camping! :tent: Be back soon. + +That is so funny! :joy: + +--- + +## Highlight + +I need to highlight these ==very important words==. + +--- + +## Subscript and Superscript + +H~2~O + +X^2^ + +--- + +## Disabling Automatic URL Linking + +`http://www.example.com`