src/c2html.c

Fri, 26 Aug 2016 14:15:29 +0200

author
Mike Becker <universe@uap-core.de>
date
Fri, 26 Aug 2016 14:15:29 +0200
changeset 53
5e47a26a16f0
parent 52
33ded421c512
child 55
bf54085ce341
permissions
-rw-r--r--

adds appendfile() function to main module + adds TODOs for source files which do not terminate with a blank line

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2016 Mike Becker. All rights reserved.
     5  *
     6  * Redistribution and use in source and binary forms, with or without
     7  * modification, are permitted provided that the following conditions are met:
     8  *
     9  *   1. Redistributions of source code must retain the above copyright
    10  *      notice, this list of conditions and the following disclaimer.
    11  *
    12  *   2. Redistributions in binary form must reproduce the above copyright
    13  *      notice, this list of conditions and the following disclaimer in the
    14  *      documentation and/or other materials provided with the distribution.
    15  *
    16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26  * POSSIBILITY OF SUCH DAMAGE.
    27  *
    28  */
    30 #include <unistd.h>
    32 #include "c2html.h"
    33 #include "highlighter.h"
    35 #include "ucx/list.h"
    37 static int appendfile(const char *filename, FILE *fout,
    38         char *copybuf, size_t copybuflen, const char *errmsg) {
    39     FILE *headerfile = fopen(filename, "r");
    40     if (!headerfile) {
    41         perror(errmsg);
    42         if (fout != stdout) {
    43             fclose(fout);
    44         }
    45         return 1;
    46     }
    47     ucx_stream_copy(headerfile, fout,
    48             (read_func) fread, (write_func) fwrite,
    49             copybuf, copybuflen, (size_t)-1);
    50     fclose(headerfile);
    51     return 0;
    52 }
    54 static void printhelp() {
    55     printf("Formats source code using HTML.\n\nUsage:\n"
    56         "  c2html [Options] FILE\n\n"
    57         " Options:\n"
    58         "  -h                    Prints this help message\n"
    59         "  -j                    Highlight Java instead of C source code\n"
    60         "  -o <output>           Output file (stdout, if not specified)\n"
    61         "  -H <header>           Prepend header file\n"
    62         "  -F <footer>           Append footer file\n"
    63         "  -p                    Disable highlighting (plain text)\n"
    64         "  -l                    Disable line numbers\n"
    65         "  -V, -v                Prints version and exits\n"
    66         "\n");
    67 }
    69 static void formatlines(highlighter_func highlighter,
    70         UcxList *in, write_func out, void *stream, int showlineno) {
    72     /* compute width of line numbering */
    73     int lnw = 0;
    74     if (showlineno) {
    75         size_t lines = ucx_list_size(in);
    76         for (size_t p = 1; p < lines ; p*=10) lnw++;
    77     }
    79     /* start monospace formatting */
    80     out("<pre>\n", 1, 6, stream);
    82     /* process lines */
    83     size_t lineno = 0;
    84     HighlighterData *hd = new_highlighter_data();
    85     UcxBuffer *line = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND);
    86     if(!line || !hd) {
    87         perror("Error allocating buffer for output");
    88         return;
    89     }
    91     UCX_FOREACH(sourceline, in) {
    92         /* increase line number and clean line buffer */
    93         lineno++;
    94         ucx_buffer_clear(line);
    96         /* write line number */
    97         if (showlineno) {
    98             ucx_bprintf(line, "<span class=\"c2html-lineno\">"
    99                     "<a name=\"l%d\" href=\"#l%d\">%*d </a></span> ",
   100                     lineno, lineno, lnw, lineno);
   101         }
   103         /* process code line */
   104         highlighter(sourceline->data, line, hd);
   106         /* write code line */
   107         out(line->space, 1, line->size, stream);
   108     }
   110     /* end monospace formatting */
   111     out("</pre>\n", 1, 7, stream);
   113     /* cleanup and return */
   114     free_highlighter_data(hd);
   115     ucx_buffer_free(line);
   116 }
   118 #define FILEBUF_SIZE 4096
   120 enum source_type {
   121     SOURCE_C,
   122     SOURCE_JAVA,
   123     SOURCE_PLAIN
   124 };
   126 int main(int argc, char** argv) {
   128     /* Default settings */
   129     Settings settings;
   130     memset(&settings, 0, sizeof(settings));
   131     settings.showlinenumbers = 1;
   132     enum source_type sourcetype = SOURCE_C;
   134     /* Parse command line */
   135     char optc;
   136     while ((optc = getopt(argc, argv, "hljo:pH:F:vV")) != -1) {
   137         switch (optc) {
   138             case 'o':
   139                 if (!(optarg[0] == '-' && optarg[1] == 0)) {
   140                     settings.outfilename = optarg;
   141                 }
   142                 break;
   143             case 'F':
   144                 settings.footerfile = optarg;
   145                 break;
   146             case 'H':
   147                 settings.headerfile = optarg;
   148                 break;
   149             case 'j':
   150                 sourcetype = SOURCE_JAVA;
   151                 break;
   152             case 'p':
   153                 sourcetype = SOURCE_PLAIN;
   154                 break;
   155             case 'l':
   156                 settings.showlinenumbers = 0;
   157                 break;
   158             case 'h':
   159                 printhelp();
   160                 return EXIT_SUCCESS;
   161             case 'v':
   162             case 'V':
   163 #ifdef VERSION_DEVELOP
   164                 printf("%d.%d (unstable)\n", VERSION_MAJOR, VERSION_MINOR);
   165 #else
   166                 printf("%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
   167 #endif
   168                 return EXIT_SUCCESS;
   169             default:
   170                 return EXIT_FAILURE;
   171         }
   172     }
   174     if (optind != argc-1) {
   175         printhelp();
   176         return EXIT_FAILURE;
   177     } else {
   178         /* Choose highlighter */
   179         highlighter_func hltr = NULL;
   180         switch (sourcetype) {
   181             case SOURCE_C:
   182                 hltr = c_highlighter;
   183                 break;
   184             case SOURCE_JAVA:
   185                 hltr = java_highlighter;
   186                 break;
   187             case SOURCE_PLAIN:
   188                 hltr = plain_highlighter;
   189                 break;
   190             default: /* should be unreachable */
   191                 fprintf(stderr, "error in enum source_type\n");
   192                 return EXIT_FAILURE;
   193         }
   195         /* Open output file */
   196         settings.infilename = argv[optind];
   197         FILE *fout;
   198         if (settings.outfilename) {
   199             fout = fopen(settings.outfilename, "w");
   200             if (!fout) {
   201                 perror("Error opening output file");
   202                 return EXIT_FAILURE;
   203             }
   204         } else {
   205             fout = stdout;
   206         }
   208         /* Allocate file buffer  */
   209         char *filebuf = malloc(FILEBUF_SIZE);
   210         if (!filebuf) {
   211             perror("Error allocating file buffer");
   212             return EXIT_FAILURE;
   213         }
   215         /* Prepend header file */
   216         if (appendfile(settings.headerfile, fout, filebuf, FILEBUF_SIZE,
   217                 "Error opening header file")) {
   218             return EXIT_FAILURE;
   219         }
   221         /* Process input file */
   222         FILE *inputfile = fopen(settings.infilename, "r");
   223         if (inputfile) {
   224             UcxBuffer *content = ucx_buffer_new(NULL,
   225                     FILEBUF_SIZE*2, UCX_BUFFER_AUTOEXTEND);
   226             {
   227                 ucx_stream_copy(inputfile, content, (read_func) fread,
   228                         (write_func) ucx_buffer_write,
   229                         filebuf, FILEBUF_SIZE, (size_t)-1);
   230             }
   231             fclose(inputfile);
   233             UcxList *inputlines = ucx_list_append(NULL, content->space);
   234             for (size_t i = 1 ; i < content->size ; i++) {
   235                 if (content->space[i] == '\r') {
   236                     content->space[i] = '\n'; i++;
   237                 }
   238                 if (content->space[i] == '\n' && i+1 < content->size) {
   239                     ucx_list_append(inputlines, content->space+i+1);
   240                 }
   241             }
   243             formatlines(hltr, inputlines,
   244                     (write_func) fwrite, fout, settings.showlinenumbers);
   246             ucx_buffer_free(content);
   247         } else {
   248             perror("Error opening input file");
   249             if (fout != stdout) {
   250                 fclose(fout);
   251             }
   252             return EXIT_FAILURE;
   253         }
   255         /* Append footer file */
   256         if (appendfile(settings.footerfile, fout, filebuf, FILEBUF_SIZE,
   257                 "Error opening footer file")) {
   258             return EXIT_FAILURE;
   259         }
   261         free(filebuf);
   263         return EXIT_SUCCESS;
   264     }
   265 }

mercurial