/*
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;
}