rewrite
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
c2html
|
||||
c2h
|
||||
@@ -1 +1 @@
|
||||
gcc cli.c c2html.c -o c2html -Wall -Wextra
|
||||
gcc cli.c c2html.c -o c2h -Wall -Wextra -g
|
||||
@@ -1,17 +1,48 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#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.
|
||||
*/
|
||||
typedef enum {
|
||||
T_DONE = 256,
|
||||
T_COMMENT,
|
||||
T_SPACE,
|
||||
T_TAB,
|
||||
T_NEWL,
|
||||
T_VSTR,
|
||||
T_VCHAR,
|
||||
T_VINT,
|
||||
T_VFLT,
|
||||
T_KWORD,
|
||||
T_FDECLNAME,
|
||||
T_FCALLNAME,
|
||||
T_IDENTIFIER,
|
||||
T_OPERATOR,
|
||||
} Kind;
|
||||
|
||||
static _Bool iskeyword(const char *str)
|
||||
typedef struct {
|
||||
Kind kind; int off, len;
|
||||
} Token;
|
||||
|
||||
static bool isoperat(char c)
|
||||
{
|
||||
return c == '+'
|
||||
|| c == '-'
|
||||
|| c == '*'
|
||||
|| c == '/'
|
||||
|| c == '%'
|
||||
|| c == '='
|
||||
|| c == '!'
|
||||
|| c == '<'
|
||||
|| c == '>'
|
||||
|| c == '|'
|
||||
|| c == '&';
|
||||
}
|
||||
|
||||
static bool iskword(const char *str, long len)
|
||||
{
|
||||
static const char *keywords[] = {
|
||||
"auto", "break", "case", "char",
|
||||
@@ -27,210 +58,422 @@ static _Bool iskeyword(const char *str)
|
||||
};
|
||||
const int num_keywords = sizeof(keywords)/sizeof(keywords[0]);
|
||||
for(int i = 0; i < num_keywords; i += 1)
|
||||
if(!strcmp(keywords[i], str))
|
||||
if(strlen(keywords[i]) == len && !strncmp(keywords[i], str, len))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static _Bool isop(char c)
|
||||
static Token *tokenize(const char *str, long len)
|
||||
{
|
||||
static const char ops[] = ".<>=!+-*/%&^|;~?:";
|
||||
for(int i = 0; ops[i] != '\0'; i += 1)
|
||||
if(c == ops[i])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
Token *array = NULL;
|
||||
int count = 0, capacity = 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");
|
||||
long i = 0;
|
||||
|
||||
c = getc(src);
|
||||
}
|
||||
Token T;
|
||||
long curly_bracket_depth = 0;
|
||||
long bracket_depth = 0;
|
||||
do {
|
||||
if(i == len) {
|
||||
T.kind = T_DONE;
|
||||
T.off = i;
|
||||
T.len = 0;
|
||||
} else if(i+1 < len && str[i] == '/' && str[i+1] == '/') {
|
||||
T.kind = T_COMMENT;
|
||||
T.off = i;
|
||||
while(i < len && str[i] != '\n')
|
||||
i += 1;
|
||||
T.len = i - T.off;
|
||||
} else if(i+1 < len && str[i] == '/' && str[i+1] == '*') {
|
||||
T.kind = T_COMMENT;
|
||||
T.off = i;
|
||||
while(1) {
|
||||
while(i < len && str[i] != '*')
|
||||
i += 1;
|
||||
if(i == len)
|
||||
break;
|
||||
assert(str[i] == '*');
|
||||
i += 1;
|
||||
if(str[i] == '/') {
|
||||
i += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
T.len = i - T.off;
|
||||
} else if(str[i] == ' ') {
|
||||
T.kind = T_SPACE;
|
||||
T.off = i;
|
||||
do
|
||||
i += 1;
|
||||
while(i < len && str[i] == ' ');
|
||||
T.len = i - T.off;
|
||||
} else if(str[i] == '\t') {
|
||||
T.kind = T_TAB;
|
||||
T.off = i;
|
||||
do
|
||||
i += 1;
|
||||
while(i < len && str[i] == ' ');
|
||||
T.len = i - T.off;
|
||||
} else if(str[i] == '\n') {
|
||||
T.kind = T_NEWL;
|
||||
T.off = i;
|
||||
do
|
||||
i += 1;
|
||||
while(i < len && str[i] == '\n');
|
||||
T.len = i - T.off;
|
||||
} else if(str[i] == '\'' || str[i] == '\"') {
|
||||
|
||||
char f = str[i];
|
||||
|
||||
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;
|
||||
T.kind = f == '"' ? T_VSTR : T_VCHAR;
|
||||
T.off = i;
|
||||
|
||||
i += 1; // Skip the '\'' or '"'.
|
||||
|
||||
do {
|
||||
while(i < len && str[i] != f && str[i] != '\\')
|
||||
i += 1;
|
||||
|
||||
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)
|
||||
if(i == len || str[i] == f)
|
||||
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++] = '*';
|
||||
if(str[i] == '\\') {
|
||||
i += 1; // Skip the '\\'.
|
||||
if(i < len)
|
||||
i += 1; // ..and the character after it.
|
||||
}
|
||||
|
||||
} 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);
|
||||
if(i < len) {
|
||||
assert(str[i] == f);
|
||||
i += 1; // Skip the final '\'' or '"'.
|
||||
}
|
||||
T.len = i - T.off;
|
||||
|
||||
assert(len < (int) sizeof(str));
|
||||
str[len] = '\0';
|
||||
|
||||
fprintf(dst, "<span class=\"vl-string\">%s</span>\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, "<span class=\"keyword kw-%s\">%s</span>",
|
||||
ident, ident);
|
||||
else
|
||||
fprintf(dst, "<span class=\"ident\">%s</span>", 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;
|
||||
} else if(isdigit(str[i])) {
|
||||
T.off = i;
|
||||
while(i < len && isdigit(str[i]))
|
||||
i += 1;
|
||||
if(i+1 < len && str[i] == '.' && isdigit(str[i+1])) {
|
||||
i += 1; // Skip the '.'.
|
||||
while(i < len && isdigit(str[i]))
|
||||
i += 1;
|
||||
T.kind = T_VFLT;
|
||||
} else T.kind = T_VINT;
|
||||
T.len = i - T.off;
|
||||
} else if(isoperat(str[i])) {
|
||||
T.kind = T_OPERATOR;
|
||||
T.off = i;
|
||||
while(i < len && isoperat(str[i]))
|
||||
i += 1;
|
||||
T.len = i - T.off;
|
||||
} else if(isalpha(str[i]) || str[i] == '_') {
|
||||
T.off = i;
|
||||
while(isalpha(str[i]) || isdigit(str[i]) || str[i] == '_')
|
||||
i += 1;
|
||||
T.len = i - T.off;
|
||||
if(iskword(str + T.off, T.len))
|
||||
T.kind = T_KWORD;
|
||||
else {
|
||||
// Is the identifier followed by
|
||||
// a left parenthesis?
|
||||
long k = i;
|
||||
while(k < len && (str[k] == ' ' || str[k] == '\t'))
|
||||
k += 1;
|
||||
if(k < len && str[k] == '(') {
|
||||
if(curly_bracket_depth == 0)
|
||||
T.kind = T_FDECLNAME;
|
||||
else
|
||||
T.kind = T_FCALLNAME;
|
||||
} else {
|
||||
T.kind = T_IDENTIFIER;
|
||||
}
|
||||
}
|
||||
|
||||
assert(len < (int) sizeof(numb));
|
||||
numb[len] = '\0';
|
||||
|
||||
fprintf(dst, "<span class=\"%s\">%s</span>",
|
||||
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, "<span class=\"oper\">%s</span>", oper);
|
||||
} else {
|
||||
fprintf(dst, "%c", c);
|
||||
c = getc(src);
|
||||
|
||||
switch(str[i]) {
|
||||
case '{': curly_bracket_depth += 1; break;
|
||||
case '}': curly_bracket_depth -= 1; break;
|
||||
case '(': bracket_depth += 1; break;
|
||||
case ')': bracket_depth -= 1; break;
|
||||
}
|
||||
|
||||
T.kind = str[i];
|
||||
T.off = i;
|
||||
T.len = 1;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
while(isspace(c)) {
|
||||
if(c == ' ')
|
||||
fprintf(dst, " ");
|
||||
else if(c == '\n')
|
||||
fprintf(dst, "\n");
|
||||
if(count == capacity) {
|
||||
int new_capacity;
|
||||
if(capacity == 0)
|
||||
new_capacity = 8;
|
||||
else
|
||||
new_capacity = 2 * capacity;
|
||||
|
||||
void *temp = realloc(array, new_capacity * sizeof(Token));
|
||||
if(temp == NULL) {
|
||||
// Uoops! Out of memory.
|
||||
free(array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c = getc(src);
|
||||
array = temp;
|
||||
capacity = new_capacity;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
array[count++] = T;
|
||||
|
||||
} while(T.kind != T_DONE);
|
||||
return array;
|
||||
}
|
||||
|
||||
const char *c2html(const char *src, const char *dst)
|
||||
typedef struct {
|
||||
char *error;
|
||||
char *data;
|
||||
long size;
|
||||
long used;
|
||||
} buff_t;
|
||||
|
||||
static void buff_init(buff_t *buff)
|
||||
{
|
||||
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);
|
||||
memset(buff, 0, sizeof(buff_t));
|
||||
}
|
||||
|
||||
static void buff_puts(buff_t *buff, const char *str, long len) {
|
||||
|
||||
if(buff->error)
|
||||
return;
|
||||
|
||||
if(buff->used + len > buff->size) {
|
||||
|
||||
int new_size;
|
||||
if(buff->size == 0)
|
||||
new_size = 32;
|
||||
else
|
||||
new_size = 2 * buff->size;
|
||||
|
||||
if(buff->used + len > new_size)
|
||||
new_size = buff->used + len;
|
||||
|
||||
void *temp = realloc(buff->data, new_size+1);
|
||||
if(temp == NULL) {
|
||||
free(buff->data);
|
||||
buff->error = "Out of memory";
|
||||
return;
|
||||
}
|
||||
|
||||
buff->data = temp;
|
||||
buff->size = new_size;
|
||||
}
|
||||
const char *err = c2html2(src_fp, dst_fp);
|
||||
fclose(src_fp);
|
||||
fclose(dst_fp);
|
||||
return err;
|
||||
|
||||
memcpy(buff->data + buff->used, str, len);
|
||||
buff->used += len;
|
||||
}
|
||||
|
||||
static void buff_printf(buff_t *buff, const char *fmt, ...)
|
||||
{
|
||||
char maybe[512];
|
||||
char *buffer;
|
||||
va_list va, va2;
|
||||
va_start(va, fmt);
|
||||
va_copy(va2, va);
|
||||
|
||||
int n = vsnprintf(maybe, sizeof(maybe), fmt, va);
|
||||
if(n < 0) {
|
||||
free(buff->data);
|
||||
buff->error = "Bad format";
|
||||
return;
|
||||
}
|
||||
|
||||
if(n < (int) sizeof(maybe))
|
||||
buffer = maybe;
|
||||
else {
|
||||
|
||||
buffer = malloc(n+1);
|
||||
if(buffer == NULL) {
|
||||
free(buff->data);
|
||||
buff->error = "Out of memory";
|
||||
goto done;
|
||||
}
|
||||
|
||||
int k = vsnprintf(buffer, n+1, fmt, va2);
|
||||
assert(k >= 0 && k == n);
|
||||
}
|
||||
|
||||
assert(buffer[n] == '\0');
|
||||
buff_puts(buff, buffer, n);
|
||||
|
||||
done:
|
||||
if(buffer != maybe)
|
||||
free(buffer);
|
||||
va_end(va2);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
static void print_escaped(buff_t *buff, const char *str, long len)
|
||||
{
|
||||
long j = 0;
|
||||
while(1) {
|
||||
|
||||
long off = j;
|
||||
|
||||
while(j < len && str[j] != '<' && str[j] != '>')
|
||||
j += 1;
|
||||
|
||||
long end = j;
|
||||
buff_puts(buff, str + off, end - off);
|
||||
|
||||
if(j == len)
|
||||
break;
|
||||
|
||||
assert(str[j] == '<' || str[j] == '>');
|
||||
if(str[j] == '<')
|
||||
buff_printf(buff, "<");
|
||||
else
|
||||
buff_printf(buff, ">");
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
|
||||
char *c2html(const char *str, long len, _Bool table_mode, const char *class_prefix, const char **error) {
|
||||
|
||||
if(str == NULL)
|
||||
str = "";
|
||||
|
||||
if(len < 0)
|
||||
len = strlen(str);
|
||||
|
||||
if(class_prefix == NULL)
|
||||
class_prefix = "";
|
||||
|
||||
buff_t buff;
|
||||
buff_init(&buff);
|
||||
long lineno = 1;
|
||||
|
||||
buff_printf(&buff, "\n"
|
||||
"<div class=\"%scode\">\n"
|
||||
" <div class=\"%scode-inner\">\n",
|
||||
class_prefix, class_prefix);
|
||||
|
||||
if(table_mode)
|
||||
buff_printf(&buff, " <table>\n"
|
||||
" <tr><td>1</td><td>");
|
||||
|
||||
Token *tokens = tokenize(str, len);
|
||||
for(int i = 0; tokens[i].kind != T_DONE; i += 1) {
|
||||
|
||||
switch(tokens[i].kind) {
|
||||
|
||||
case T_DONE:
|
||||
assert(0);
|
||||
break;
|
||||
|
||||
case T_NEWL:
|
||||
if(table_mode)
|
||||
for(int j = 0; j < tokens[i].len; j += 1) {
|
||||
lineno += 1;
|
||||
buff_printf(&buff, "</td></tr>\n <tr><td>%d</td><td>", lineno);
|
||||
}
|
||||
else {
|
||||
lineno += tokens[i].len;
|
||||
for(int j = 0; j < tokens[i].len; j += 1)
|
||||
buff_printf(&buff, "<br />\n");
|
||||
}
|
||||
break;
|
||||
|
||||
case T_SPACE:
|
||||
if(tokens[i].len == 1)
|
||||
buff_printf(&buff, " ", 1);
|
||||
else {
|
||||
for(int j = 0; j < tokens[i].len; j += 1)
|
||||
buff_printf(&buff, " ");
|
||||
}
|
||||
break;
|
||||
|
||||
case T_TAB:
|
||||
for(int j = 0; j < tokens[i].len; j += 1)
|
||||
buff_printf(&buff, "    ");
|
||||
break;
|
||||
|
||||
case T_KWORD:
|
||||
buff_printf(&buff, "<span class=\"%skword %skword-%.*s\">%.*s</span>",
|
||||
class_prefix, class_prefix,
|
||||
tokens[i].len, str + tokens[i].off,
|
||||
tokens[i].len, str + tokens[i].off);
|
||||
break;
|
||||
|
||||
case T_VSTR:
|
||||
buff_printf(&buff, "<span class=\"%sval-str\">", class_prefix);
|
||||
print_escaped(&buff, str + tokens[i].off, tokens[i].len);
|
||||
buff_printf(&buff, "</span>");
|
||||
break;
|
||||
|
||||
case T_VCHAR:
|
||||
buff_printf(&buff, "<span class=\"%sval-char\">", class_prefix);
|
||||
print_escaped(&buff, str + tokens[i].off, tokens[i].len);
|
||||
buff_printf(&buff, "</span>");
|
||||
break;
|
||||
|
||||
case T_VINT:
|
||||
buff_printf(&buff, "<span class=\"%sval-int\">%.*s</span>",
|
||||
class_prefix, tokens[i].len, str + tokens[i].off);
|
||||
break;
|
||||
|
||||
case T_VFLT:
|
||||
buff_printf(&buff, "<span class=\"%sval-flt\">%.*s</span>",
|
||||
class_prefix, tokens[i].len, str + tokens[i].off);
|
||||
break;
|
||||
|
||||
case T_FDECLNAME:
|
||||
buff_printf(&buff, "<span class=\"%sidentifier %sfdeclname\">%.*s</span>",
|
||||
class_prefix, class_prefix, tokens[i].len, str + tokens[i].off);
|
||||
break;
|
||||
|
||||
case T_FCALLNAME:
|
||||
buff_printf(&buff, "<span class=\"%sidentifier %sfcallname\">%.*s</span>",
|
||||
class_prefix, class_prefix, tokens[i].len, str + tokens[i].off);
|
||||
break;
|
||||
|
||||
case T_IDENTIFIER:
|
||||
buff_printf(&buff, "<span class=\"%sidentifier\">%.*s</span>",
|
||||
class_prefix, tokens[i].len, str + tokens[i].off);
|
||||
break;
|
||||
|
||||
case T_COMMENT:
|
||||
buff_printf(&buff, "<span class=\"%scomment\">", class_prefix);
|
||||
print_escaped(&buff, str + tokens[i].off, tokens[i].len);
|
||||
buff_printf(&buff, "</span>");
|
||||
break;
|
||||
|
||||
case T_OPERATOR:
|
||||
buff_printf(&buff, "<span class=\"%soperator\">", class_prefix);
|
||||
print_escaped(&buff, str + tokens[i].off, tokens[i].len);
|
||||
buff_printf(&buff, "</span>");
|
||||
break;
|
||||
|
||||
default:
|
||||
buff_printf(&buff, "%c", str[tokens[i].off]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(table_mode)
|
||||
buff_printf(&buff, "</td></tr>\n </table>\n");
|
||||
buff_printf(&buff, " </div>\n"
|
||||
"</div>");
|
||||
|
||||
char *res;
|
||||
if(buff.error == NULL) {
|
||||
buff.data[buff.used] = '\0';
|
||||
res = buff.data;
|
||||
} else {
|
||||
if(error != NULL)
|
||||
*error = buff.error;
|
||||
res = NULL;
|
||||
}
|
||||
|
||||
free(tokens);
|
||||
return res;
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
#include <stdio.h>
|
||||
const char *c2html(const char *src, const char *dst);
|
||||
const char *c2html2(FILE *src, FILE *dst);
|
||||
|
||||
char *c2html(const char *str, long len, _Bool table_mode,
|
||||
const char *class_prefix, const char **error);
|
||||
|
||||
@@ -1,25 +1,73 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "c2html.h"
|
||||
|
||||
static char *load_file(const char *file, long *size)
|
||||
{
|
||||
FILE *fp = fopen(file, "rb");
|
||||
if(fp == NULL)
|
||||
return NULL;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long size2 = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
char *data = malloc(size2+1);
|
||||
if(data == NULL) {
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fread(data, 1, size2, fp);
|
||||
fclose(fp);
|
||||
|
||||
if(size)
|
||||
*size = size2;
|
||||
|
||||
data[size2] = '\0';
|
||||
return data;
|
||||
}
|
||||
|
||||
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]);
|
||||
fprintf(stderr, "ERROR: Missing input and output file\n");
|
||||
return -1;
|
||||
}
|
||||
char *src_file = argv[1];
|
||||
char *dst_file = argv[2];
|
||||
|
||||
long src_size;
|
||||
char *src_data = load_file(src_file, &src_size);
|
||||
|
||||
if(src_data == NULL) {
|
||||
fprintf(stderr, "ERROR: Failed to open \"%s\"\n", src_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *err;
|
||||
_Bool table_mode = 0;
|
||||
const char *class_prefix = "c2h-";
|
||||
|
||||
err = c2html(argv[1], argv[2]);
|
||||
if(err != NULL)
|
||||
fprintf(stderr, "ERROR: %s\n", err);
|
||||
fprintf(stderr, "OK");
|
||||
return err == NULL ? -1 : 0;
|
||||
const char *error;
|
||||
char *dst_data = c2html(src_data, src_size, table_mode, class_prefix, &error);
|
||||
|
||||
if(dst_data == NULL)
|
||||
fprintf(stderr, "ERROR: %s\n", error);
|
||||
else {
|
||||
|
||||
FILE *fp = fopen(dst_file, "wb");
|
||||
if(fp == NULL)
|
||||
fprintf(stderr, "ERROR: Failed to open \"%s\"\n", dst_file);
|
||||
else {
|
||||
fwrite(dst_data, 1, strlen(dst_data), fp);
|
||||
fclose(fp);
|
||||
fprintf(stderr, "OK\n");
|
||||
}
|
||||
|
||||
free(dst_data);
|
||||
}
|
||||
|
||||
free(src_data);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
|
||||
div.c2h-code {
|
||||
max-height: 80vh;
|
||||
margin: 50px;
|
||||
border-radius: 3px;
|
||||
color: white;
|
||||
font-family: monospace;
|
||||
font-size: 16px;
|
||||
background: hsl(210, 15%, 22%);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
div.c2h-code-inner::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
div.c2h-code-inner::-webkit-scrollbar-thumb {
|
||||
background: hsla(210, 13%, 40%, 0.7);
|
||||
}
|
||||
|
||||
div.c2h-code-inner {
|
||||
overflow: auto;
|
||||
max-height: inherit;
|
||||
scrollbar-color: hsla(210, 13%, 40%, 0.7) transparent;
|
||||
}
|
||||
|
||||
div.c2h-code table {
|
||||
border-collapse: collapse;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
div.c2h-code table td {
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.c2h-code table td:first-child {
|
||||
text-align: right;
|
||||
padding: 0 10px;
|
||||
color: hsla(210, 13%, 40%, 0.7);
|
||||
}
|
||||
|
||||
.c2h-comment {
|
||||
color: hsl(221, 12%, 69%);
|
||||
}
|
||||
|
||||
.c2h-val-int,
|
||||
.c2h-val-flt {
|
||||
color: hsl(32, 93%, 66%);
|
||||
}
|
||||
|
||||
.c2h-val-str,
|
||||
.c2h-val-char {
|
||||
color: hsl(114, 31%, 68%);
|
||||
}
|
||||
|
||||
.c2h-kword {
|
||||
color: hsl(300, 30%, 68%);
|
||||
}
|
||||
|
||||
.c2h-kword-static,
|
||||
.c2h-kword-const {
|
||||
color: hsl(357, 79%, 65%);
|
||||
}
|
||||
|
||||
.c2h-operator {
|
||||
color: hsl(13, 93%, 66%);
|
||||
}
|
||||
|
||||
.c2h-identifier {
|
||||
color: hsl(219, 28%, 88%);
|
||||
}
|
||||
|
||||
.c2h-fdeclname {
|
||||
color: hsl(180, 36%, 54%);
|
||||
}
|
||||
|
||||
.c2h-fcallname {
|
||||
color: hsl(210, 50%, 60%);
|
||||
}
|
||||
Reference in New Issue
Block a user