diff --git a/README.md b/README.md index 62ae3db..88ecd6a 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ You can highlight your C files by doing ```sh 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 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 The library only exports one function ```c -char *c2html(const char *str, long len, - const char *prefix, const char **error); - +char *c2html(const char *str, long len, const char *prefix, + long *output_len, const char **error) ``` Given a string containing C code, returns the highlighted version using HTML `` tags. (You can find a complete description of what it does in `c2html.h`) @@ -88,14 +87,14 @@ int main() " return 0;\n" "}\n"; - char *html = c2html(c, strlen(c), prefix, NULL); + char *html = c2html(c, -1, prefix, NULL, NULL); printf("%s\n", html); free(html); return 0; } ``` when executed, the output will be: -``` +```html
diff --git a/c2html.c b/c2html.c index 1521368..87a45df 100644 --- a/c2html.c +++ b/c2html.c @@ -487,8 +487,8 @@ static void print_escaped(buff_t *buff, const char *str, long len) } } -char *c2html(const char *str, long len, - const char *prefix, const char **error) +char *c2html(const char *str, long len, const char *prefix, + long *output_len, const char **error) { if(str == NULL) str = ""; @@ -639,6 +639,9 @@ char *c2html(const char *str, long len, res = NULL; } + if(output_len != NULL) + *output_len = buff.used; + free(tokens); return res; } \ No newline at end of file diff --git a/c2html.h b/c2html.h index 3ac278b..55a0beb 100644 --- a/c2html.h +++ b/c2html.h @@ -1,6 +1,8 @@ /* Takes as input a string of C code [str] of length * [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 * prefixed with the value provided through [prefix]. * If [prefix] is NULL, then no prefix is used. @@ -19,5 +21,5 @@ * to be zero-terminated and it's length is calculated * using [strlen]. */ -char *c2html(const char *str, long len, - const char *prefix, const char **error); +char *c2html(const char *str, long len, const char *prefix, + long *output_len, const char **error); diff --git a/cli.c b/cli.c index 10890d9..c485f64 100644 --- a/cli.c +++ b/cli.c @@ -37,68 +37,89 @@ char *timed_c2html(const char *str, long len, #define c2html timed_c2html #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) { 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); + char *data = load_from_stream(fp, size, NULL); fclose(fp); - - if(size) - *size = size2; - - data[size2] = '\0'; return data; } -static int fileconv(const char *input_file, const char *output_file, - const char *style_file, const char *prefix) +static int fileconv(FILE *in_fp, FILE *out_fp, + 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) prefix = "c2h-"; - /* Load the input string */ + const char *err; + long input_size; - char *input = load_file(input_file, &input_size); + char *input = load_from_stream(in_fp, &input_size, &err); 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; } - /* Convert it */ - const char *error; - char *output = c2html(input, input_size, prefix, &error); + long output_size; + char *output = c2html(input, input_size, prefix, + &output_size, &err); if(output == NULL) { - fprintf(stderr, "Error: %s\n", error); - 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); + fprintf(stderr, "Error: %s\n", err); free(input); return -1; } @@ -112,15 +133,13 @@ static int fileconv(const char *input_file, const char *output_file, free(input); return -1; } - fputs("", fp); + fputs("", out_fp); free(style_data); } - /* ..and write the converted string to it */ - fwrite(output, 1, strlen(output), fp); - fclose(fp); + fwrite(output, 1, output_size, out_fp); // TODO: Check the return value!! /* All done! :^) */ free(output); @@ -139,7 +158,7 @@ static void print_help(FILE *fp, char *name) { " to the generated output, you get the highliting!\n" "\n" " The usage is:\n" - " $ %s -i file.c -o file.html [--style file.css] [-p ]\n" + " $ %s [-i file.c] [-o file.html] [--style file.css] [-p ]\n" "\n" " ..and here's a table of all available options:\n" "\n" @@ -161,11 +180,6 @@ static void print_help(FILE *fp, char *name) { int main(int argc, char **argv) { - if(argc == 1) { - print_help(stdout, argv[0]); - return 0; - } - /* Parse command-line arguments */ char *input_file = NULL, *output_file = NULL, @@ -212,6 +226,37 @@ int main(int argc, char **argv) } } - return fileconv(input_file, output_file, - style_file, prefix); + 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); + + if(!use_stdin) fclose(in_fp); + if(!use_stdout) fclose(out_fp); + return rescode; } \ No newline at end of file