From 6337a7f7ca5c641722a7e22c6b7d86ab383ee983 Mon Sep 17 00:00:00 2001 From: cozis Date: Tue, 3 May 2022 15:22:41 +0200 Subject: [PATCH] first commit --- .gitignore | 1 + build.sh | 1 + c2html.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++ c2html.h | 3 + cli.c | 25 ++++++ 5 files changed, 266 insertions(+) create mode 100644 .gitignore create mode 100755 build.sh create mode 100644 c2html.c create mode 100644 c2html.h create mode 100644 cli.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..165c873 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +c2html diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..1c2a105 --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +gcc cli.c c2html.c -o c2html -Wall -Wextra \ No newline at end of file diff --git a/c2html.c b/c2html.c new file mode 100644 index 0000000..e44107d --- /dev/null +++ b/c2html.c @@ -0,0 +1,236 @@ +#include +#include +#include +#include "c2html.h" + +/* Converts files containing C code to an + * HTML version with syntax highlighting. + * The highlighting is best-effort, it's + * only based on the tokenization result + * and doesn't do a full parsing. Parsing + * C would blow up the code of this utility. + */ + +static _Bool iskeyword(const char *str) +{ + static const char *keywords[] = { + "auto", "break", "case", "char", + "const", "continue", "default", + "do", "double", "else", "enum", + "extern", "float", "for", "goto", + "if", "int", "long", "register", + "return", "short", "signed", + "sizeof", "static", "struct", + "switch", "typedef", "union", + "unsigned", "void", "volatile", + "while" + }; + const int num_keywords = sizeof(keywords)/sizeof(keywords[0]); + for(int i = 0; i < num_keywords; i += 1) + if(!strcmp(keywords[i], str)) + return 1; + return 0; +} + +static _Bool isop(char c) +{ + static const char ops[] = ".<>=!+-*/%&^|;~?:"; + for(int i = 0; ops[i] != '\0'; i += 1) + if(c == ops[i]) + return 1; + return 0; +} + +const char *c2html2(FILE *src, FILE *dst) +{ + char c = getc(src); + + while(isspace(c)) { + if(c == ' ') + fprintf(dst, " "); + else if(c == '\n') + fprintf(dst, "\n"); + + c = getc(src); + } + + while(c != EOF) { + + assert(!isspace(c)); + + char hint = getc(src); + fseek(src, -1, SEEK_CUR); + + if(c == '/' && (hint == '/' || hint == '*')) { + + _Bool mline = (hint == '*'); + char comment[1024]; + int len = 0; + + do { + + if(len == sizeof(comment)-1) + return "Static buffer is too small to " + "hold a comment this big"; + + comment[len++] = c; + c = getc(src); + + if(c == EOF) + break; + + if(!mline && c == '\n') + break; + + if(mline && c == '*') { + + c = getc(src); + + if(c == '/') + break; + + if(len == sizeof(comment)-1) + return "Static buffer is too small to " + "hold a comment this big"; + comment[len++] = '*'; + } + + } while(1); + + assert(len < (int) sizeof(comment)); + comment[len] = '\0'; + + if(c == EOF) + fprintf(dst, "%s", comment); + else if(mline) + fprintf(dst, "%s*/", comment); + else + fprintf(dst, "%s\n", comment); + } + + if(c == '"' || c == '\'') { + + char str[512]; + int len = 0; + + char f = c; + c = getc(src); + while(c != f && c != EOF) { + if(len == sizeof(str)-1) + return "Static buffer is too small " + "to hold string literal"; + str[len++] = c; + c = getc(src); + } + + assert(len < (int) sizeof(str)); + str[len] = '\0'; + + fprintf(dst, "%s\n", str); + + } else if(isalpha(c) || c == '_') { + + char ident[128]; + int len = 0; + + do { + if(len == sizeof(ident)-1) + return "Static buffer is too small " + "to hold identifier"; + ident[len++] = c; + c = getc(src); + } while(isalpha(c) || isdigit(c) || c == '_'); + + assert(len < (int) sizeof(ident)); + ident[len] = '\0'; + + if(iskeyword(ident)) + fprintf(dst, "%s", + ident, ident); + else + fprintf(dst, "%s", ident); + + } else if(isdigit(c)) { + + char numb[64]; + int len = 0; + + do { + if(len == sizeof(numb)-1) + return "Static buffer is too small to " + "hold a number with so many digits"; + numb[len++] = c; + c = getc(src); + } while(isdigit(c)); + + // Here [c] refers to the first non-digit + // character. We want to know the following + // also. + char hint = getc(src); // Read one. + fseek(src, -1, SEEK_CUR); // Then go back by one. + + _Bool dot = 0; + if(c == '.' && isdigit(hint)) { + // Maybe it's a floating-point value? + do { + if(len == sizeof(numb)-1) + return "Static buffer is too small to " + "hold a number with so many digits"; + numb[len++] = c; + c = getc(src); + } while(isdigit(c)); + dot = 1; + } + + assert(len < (int) sizeof(numb)); + numb[len] = '\0'; + + fprintf(dst, "%s", + dot ? "vl-float" : "vl-int", numb); + } else if(isop(c)) { + + char oper[32]; + int len = 0; + + do { + if(len == sizeof(oper)-1) + return "Static buffer is too small to " + "hold an operator this long"; + oper[len++] = c; + c = getc(src); + } while(isop(c)); + + assert(len < (int) sizeof(oper)); + oper[len] = '\0'; + + fprintf(dst, "%s", oper); + } else { + fprintf(dst, "%c", c); + c = getc(src); + } + + while(isspace(c)) { + if(c == ' ') + fprintf(dst, " "); + else if(c == '\n') + fprintf(dst, "\n"); + + c = getc(src); + } + } + return NULL; +} + +const char *c2html(const char *src, const char *dst) +{ + FILE *src_fp = fopen(src, "rb"); + FILE *dst_fp = fopen(dst, "wb"); + if(src_fp == NULL || dst_fp == NULL) { + if(src_fp != NULL) fclose(src_fp); + if(dst_fp != NULL) fclose(dst_fp); + } + const char *err = c2html2(src_fp, dst_fp); + fclose(src_fp); + fclose(dst_fp); + return err; +} \ No newline at end of file diff --git a/c2html.h b/c2html.h new file mode 100644 index 0000000..3968abd --- /dev/null +++ b/c2html.h @@ -0,0 +1,3 @@ +#include +const char *c2html(const char *src, const char *dst); +const char *c2html2(FILE *src, FILE *dst); \ No newline at end of file diff --git a/cli.c b/cli.c new file mode 100644 index 0000000..3724f02 --- /dev/null +++ b/cli.c @@ -0,0 +1,25 @@ +#include +#include +#include "c2html.h" + +int main(int argc, char **argv) +{ + assert(argc > 0); + if(argc < 3) { + fprintf(stderr, + "Missing input ad output files\n" + "\n" + "Usage:\n" + " $ %s input.c output.html\n" + "\n", argv[0]); + return -1; + } + + const char *err; + + err = c2html(argv[1], argv[2]); + if(err != NULL) + fprintf(stderr, "ERROR: %s\n", err); + fprintf(stderr, "OK"); + return err == NULL ? -1 : 0; +} \ No newline at end of file