First time writing C in a long time and would like some code review to try and improve my code. I have some specific questions, but first an introduction to the code.
The application is a simple command line application for converting markdown to pdf. The source code can be found in the repository on Github. The main logic is in main.c, and is hopefully pretty straight forward.
My first question is, have I made any common C errors, like buffer overflows or unreleased memory? I don't think so, I don't use any malloc calls in my code, but would like someone more experienced to take a look.
I'm compiling the application and dependencies statically, how common is this? My main reason for this is that one of the dependencies (wkhtmltopdf) is a bit tricky to compile, so I want to be able to provide a binary release that doesn't depend on a shared library.
I have added the dependencies to the repository, not what I'm used to from Ruby or Go, but it seems like the most straight forward way. One other solution I tried was to download the dependencies using git in the Makefile, like this. So they did not have to be added, but that did not feel like a good C solution. Feels a bit like a "roll you own" solution. How would you do this?
Is there anything in the Makefile I could do to make it easier to build for various package managers? E.g. apt-get, homebrew, ports, pkg?
Are there anything else I should do to be a good *nix citizen? E.g. the man page.
This block in main.c feels a bit clunky, and I would like to extract it to a couple of methods instead, to get a better flow when reading the main application logic. But I could not find a good way to do so. The logical parts are read_markdown
, create_renderer
, generate_filename
and write_html
. But the code seems to be doing to much for a simple extract method. Do you have any suggestions?
/* Read SOURCE(s) */
hoedown_buffer *ib = hoedown_buffer_new(HOEDOWN_IUNIT);
if (n_files == 1) {
int error_code = read_file_to_buffer(ib, in);
if (error_code > 0) {
fprintf(stderr, "I/O errors found while reading input.\n");
hoedown_buffer_free(ib);
fclose(in);
exit(error_code);
}
} else {
int i;
for (i = 0; i < n_files-1; i++) {
FILE *ir = fopen(file[i], "r");
int error_code = read_file_to_buffer(ib, ir);
if (error_code > 0) {
fprintf(stderr, "I/O errors found while reading input.\n");
hoedown_buffer_free(ib);
fclose(ir);
exit(error_code);
}
if (page_break_between_sources) {
if (i < n_files-1) {
hoedown_buffer_puts(ib, "\n\n<div class=\"page-break\"></div>\n\n");
}
}
fclose(ir);
}
}
hoedown_renderer *renderer = hoedown_html_renderer_new(0, 0);
hoedown_document *document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, HOEDOWN_MAX_NESTING);
hoedown_buffer *ob = hoedown_buffer_new(HOEDOWN_OUNIT);
hoedown_document_render(document, ob, ib->data, ib->size);
hoedown_buffer_free(ib);
fclose(in);
/* Generate a tmpfile for html output */
char nameBuff[23];
char filePath[30];
int filedesc = -1;
memset(nameBuff, 0, sizeof(nameBuff));
memset(filePath, 0, sizeof(filePath));
strncpy(nameBuff, "/tmp/mdpdf-XXXXXX.html", 22);
filedesc = mkstemps(nameBuff, 5);
FILE *out = fdopen(filedesc, "w");
/* Use tmp file to build a file:// path for wkhtml */
sprintf(filePath, "file://%s", nameBuff);
/* Write tmp html output to file */
write_html_to_file(out, ob, verbose, stylesheet);
fclose(out);
/* Cleanup hoedown */
hoedown_buffer_free(ob);
hoedown_document_free(document);
hoedown_html_renderer_free(renderer);