when not providing an --input or --output, stdin and stdout are used. Also the c2html function outputs the length of the string
This commit is contained in:
@@ -46,7 +46,7 @@ You can highlight your C files by doing
|
|||||||
```sh
|
```sh
|
||||||
c2html --input file.c --output file.html
|
c2html --input file.c --output file.html
|
||||||
```
|
```
|
||||||
which will read `file.c` and generate `file.html`. To know more, you can always run `c2html --help`.
|
which will read `file.c` and generate `file.html`. To know more, you can always run `c2html --help`. If the input and/or the output aren't provided, then `stdin` and `stdout` are used.
|
||||||
|
|
||||||
### --style
|
### --style
|
||||||
The HTML comes with no styling. If you want to apply a CSS to it, you can provide to `c2html` a style file using the `--style` option followed by the name of the file.
|
The HTML comes with no styling. If you want to apply a CSS to it, you can provide to `c2html` a style file using the `--style` option followed by the name of the file.
|
||||||
@@ -67,9 +67,8 @@ in which case, identifiers will be generated with the `myprefix-identifier` clas
|
|||||||
## Using the library
|
## Using the library
|
||||||
The library only exports one function
|
The library only exports one function
|
||||||
```c
|
```c
|
||||||
char *c2html(const char *str, long len,
|
char *c2html(const char *str, long len, const char *prefix,
|
||||||
const char *prefix, const char **error);
|
long *output_len, const char **error)
|
||||||
|
|
||||||
```
|
```
|
||||||
Given a string containing C code, returns the highlighted version using HTML `<span>` tags. (You can find a complete description of what it does in `c2html.h`)
|
Given a string containing C code, returns the highlighted version using HTML `<span>` tags. (You can find a complete description of what it does in `c2html.h`)
|
||||||
|
|
||||||
@@ -88,14 +87,14 @@ int main()
|
|||||||
" return 0;\n"
|
" return 0;\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
char *html = c2html(c, strlen(c), prefix, NULL);
|
char *html = c2html(c, -1, prefix, NULL, NULL);
|
||||||
printf("%s\n", html);
|
printf("%s\n", html);
|
||||||
free(html);
|
free(html);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
when executed, the output will be:
|
when executed, the output will be:
|
||||||
```
|
```html
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<div class="code-inner">
|
<div class="code-inner">
|
||||||
<table>
|
<table>
|
||||||
|
|||||||
@@ -487,8 +487,8 @@ static void print_escaped(buff_t *buff, const char *str, long len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *c2html(const char *str, long len,
|
char *c2html(const char *str, long len, const char *prefix,
|
||||||
const char *prefix, const char **error)
|
long *output_len, const char **error)
|
||||||
{
|
{
|
||||||
if(str == NULL)
|
if(str == NULL)
|
||||||
str = "";
|
str = "";
|
||||||
@@ -639,6 +639,9 @@ char *c2html(const char *str, long len,
|
|||||||
res = NULL;
|
res = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(output_len != NULL)
|
||||||
|
*output_len = buff.used;
|
||||||
|
|
||||||
free(tokens);
|
free(tokens);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
/* Takes as input a string of C code [str] of length
|
/* Takes as input a string of C code [str] of length
|
||||||
* [len] and returns the same C code but annotated
|
* [len] and returns the same C code but annotated
|
||||||
* with HTML tags. The returned string must be freed
|
* with HTML tags. The returned string's length is
|
||||||
|
* returned through the [output_len] optional output
|
||||||
|
* parameter. The returned pointer must be freed
|
||||||
* using [free]. The class names of each tag are
|
* using [free]. The class names of each tag are
|
||||||
* prefixed with the value provided through [prefix].
|
* prefixed with the value provided through [prefix].
|
||||||
* If [prefix] is NULL, then no prefix is used.
|
* If [prefix] is NULL, then no prefix is used.
|
||||||
@@ -19,5 +21,5 @@
|
|||||||
* to be zero-terminated and it's length is calculated
|
* to be zero-terminated and it's length is calculated
|
||||||
* using [strlen].
|
* using [strlen].
|
||||||
*/
|
*/
|
||||||
char *c2html(const char *str, long len,
|
char *c2html(const char *str, long len, const char *prefix,
|
||||||
const char *prefix, const char **error);
|
long *output_len, const char **error);
|
||||||
|
|||||||
@@ -37,68 +37,89 @@ char *timed_c2html(const char *str, long len,
|
|||||||
#define c2html timed_c2html
|
#define c2html timed_c2html
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static char *load_from_stream(FILE *fp, long *out_size, const char **err)
|
||||||
|
{
|
||||||
|
char *data = NULL;
|
||||||
|
long capacity = 1 << 11;
|
||||||
|
long size = 0;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
|
||||||
|
capacity *= 2;
|
||||||
|
if((long) capacity < 0) {
|
||||||
|
|
||||||
|
if(err)
|
||||||
|
*err = "Too big";
|
||||||
|
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *temp = realloc(data, capacity);
|
||||||
|
if(temp == NULL) {
|
||||||
|
if(err)
|
||||||
|
*err = "No memory";
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
data = temp;
|
||||||
|
|
||||||
|
long unused = capacity - size - 1; // Spare one byte for NULL termination.
|
||||||
|
long num = fread(data + size, 1, unused, fp);
|
||||||
|
size += num;
|
||||||
|
|
||||||
|
if(num < unused) {
|
||||||
|
// Either something went wrong or
|
||||||
|
// we're done copying.
|
||||||
|
if(ferror(fp)) {
|
||||||
|
if(err)
|
||||||
|
*err = "Unknown read error";
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data[size] = '\0';
|
||||||
|
|
||||||
|
if(out_size)
|
||||||
|
*out_size = size;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
static char *load_file(const char *file, long *size)
|
static char *load_file(const char *file, long *size)
|
||||||
{
|
{
|
||||||
FILE *fp = fopen(file, "rb");
|
FILE *fp = fopen(file, "rb");
|
||||||
if(fp == NULL)
|
if(fp == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
char *data = load_from_stream(fp, size, 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);
|
fclose(fp);
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
fread(data, 1, size2, fp);
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
if(size)
|
|
||||||
*size = size2;
|
|
||||||
|
|
||||||
data[size2] = '\0';
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fileconv(const char *input_file, const char *output_file,
|
static int fileconv(FILE *in_fp, FILE *out_fp,
|
||||||
const char *style_file, const char *prefix)
|
const char *style_file,
|
||||||
|
const char *prefix)
|
||||||
{
|
{
|
||||||
if(input_file == NULL || output_file == NULL) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"Error: You must specify both input and output "
|
|
||||||
"files using the --input and --output options\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(prefix == NULL)
|
if(prefix == NULL)
|
||||||
prefix = "c2h-";
|
prefix = "c2h-";
|
||||||
|
|
||||||
/* Load the input string */
|
const char *err;
|
||||||
|
|
||||||
long input_size;
|
long input_size;
|
||||||
char *input = load_file(input_file, &input_size);
|
char *input = load_from_stream(in_fp, &input_size, &err);
|
||||||
if(input == NULL) {
|
if(input == NULL) {
|
||||||
fprintf(stderr, "Error: Failed to open file %s\n", input_file);
|
fprintf(stderr, "Error: Failed to read input (%s)\n", err);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert it */
|
long output_size;
|
||||||
const char *error;
|
char *output = c2html(input, input_size, prefix,
|
||||||
char *output = c2html(input, input_size, prefix, &error);
|
&output_size, &err);
|
||||||
if(output == NULL) {
|
if(output == NULL) {
|
||||||
fprintf(stderr, "Error: %s\n", error);
|
fprintf(stderr, "Error: %s\n", err);
|
||||||
free(input);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Open the output file */
|
|
||||||
FILE *fp = fopen(output_file, "wb");
|
|
||||||
if(fp == NULL) {
|
|
||||||
fprintf(stderr, "ERROR: Failed to write to file %s\n",
|
|
||||||
output_file);
|
|
||||||
free(output);
|
|
||||||
free(input);
|
free(input);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -112,15 +133,13 @@ static int fileconv(const char *input_file, const char *output_file,
|
|||||||
free(input);
|
free(input);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fputs("<style>", fp);
|
fputs("<style>", out_fp);
|
||||||
fputs(style_data, fp);
|
fputs(style_data, out_fp);
|
||||||
fputs("</style>", fp);
|
fputs("</style>", out_fp);
|
||||||
free(style_data);
|
free(style_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ..and write the converted string to it */
|
fwrite(output, 1, output_size, out_fp); // TODO: Check the return value!!
|
||||||
fwrite(output, 1, strlen(output), fp);
|
|
||||||
fclose(fp);
|
|
||||||
|
|
||||||
/* All done! :^) */
|
/* All done! :^) */
|
||||||
free(output);
|
free(output);
|
||||||
@@ -139,7 +158,7 @@ static void print_help(FILE *fp, char *name) {
|
|||||||
" to the generated output, you get the highliting!\n"
|
" to the generated output, you get the highliting!\n"
|
||||||
"\n"
|
"\n"
|
||||||
" The usage is:\n"
|
" The usage is:\n"
|
||||||
" $ %s -i file.c -o file.html [--style file.css] [-p <prefix>]\n"
|
" $ %s [-i file.c] [-o file.html] [--style file.css] [-p <prefix>]\n"
|
||||||
"\n"
|
"\n"
|
||||||
" ..and here's a table of all available options:\n"
|
" ..and here's a table of all available options:\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -161,11 +180,6 @@ static void print_help(FILE *fp, char *name) {
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if(argc == 1) {
|
|
||||||
print_help(stdout, argv[0]);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse command-line arguments */
|
/* Parse command-line arguments */
|
||||||
char *input_file = NULL,
|
char *input_file = NULL,
|
||||||
*output_file = NULL,
|
*output_file = NULL,
|
||||||
@@ -212,6 +226,37 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileconv(input_file, output_file,
|
bool use_stdin = (input_file == NULL);
|
||||||
|
bool use_stdout = (output_file == NULL);
|
||||||
|
|
||||||
|
FILE *in_fp, *out_fp;
|
||||||
|
|
||||||
|
if(use_stdin)
|
||||||
|
in_fp = stdin;
|
||||||
|
else {
|
||||||
|
in_fp = fopen(input_file, "rb");
|
||||||
|
if(in_fp == NULL) {
|
||||||
|
fprintf(stderr, "Error: Couldn't open file %s\n", input_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(output_file == NULL)
|
||||||
|
out_fp = stdout;
|
||||||
|
else {
|
||||||
|
out_fp = fopen(output_file, "wb");
|
||||||
|
if(out_fp == NULL) {
|
||||||
|
if(!use_stdin)
|
||||||
|
fclose(in_fp);
|
||||||
|
fprintf(stderr, "Error: Couldn't open or create file %s\n", output_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rescode = fileconv(in_fp, out_fp,
|
||||||
style_file, prefix);
|
style_file, prefix);
|
||||||
|
|
||||||
|
if(!use_stdin) fclose(in_fp);
|
||||||
|
if(!use_stdout) fclose(out_fp);
|
||||||
|
return rescode;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user