src/c2html.c

Tue, 23 Aug 2016 14:24:57 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 23 Aug 2016 14:24:57 +0200
changeset 42
7f2403c637a7
parent 41
c06ab07fd29d
child 43
a8cee98c8832
permissions
-rw-r--r--

replaces custom copyfile() function with ucx_stream_copy calls

     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  */
    29 #include "c2html.h"
    31 #include "ucx/buffer.h"
    32 #include "ucx/list.h"
    33 #include "ucx/utils.h"
    35 void printhelp() {
    36     printf("Formats source code using HTML.\n\nUsage:\n"
    37         "  c2html [Options] FILE\n\n"
    38         " Options:\n"
    39         "  -h                    Prints this help message\n"
    40         "  -j                    Highlight Java instead of C source code\n"
    41         "  -o <output>           Output file (stdout, if not specified)\n"
    42         "  -H <header>           Prepend header file\n"
    43         "  -F <footer>           Append footer file\n"
    44         "  -p                    Disable highlighting (plain text)\n"
    45         "  -l                    Disable line numbers\n"
    46         "  -V, -v                Prints version and exits\n"
    47         "\n");
    48 }
    50 #define WRITECONST(stream, out, cstr) out(cstr, 1, sizeof(cstr)-1, stream)
    51 int formatfile(
    52         highlighter_t *highlighter,
    53         UcxList *in,
    54         write_func out,
    55         void *stream,
    56         int showlineno) {
    57     size_t lines = ucx_list_size(in);
    59     UcxBuffer *line = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND);
    60     if(!line) {
    61         return 1;
    62     }
    63     WRITECONST(stream, out, "<pre>\n");
    65     int lnw;
    66     {
    67         lnw = 1;
    68         int p = 1;
    69         while ((p*=10) < lines) lnw++;
    70     }
    72     size_t lineno = 0;
    73     UCX_FOREACH(sourceline, in) {
    74         lineno++;
    75         /* TODO: backwards compatibility: replace line->space in all occasions
    76          * and use UcxBuffer functions
    77          */
    78         if (highlighter) {
    79             highlighter->parser(sourceline->data, line->space, highlighter);
    80         } else {
    81             char *c = sourceline->data;
    82             size_t dp = 0;
    83             while (*c && *c != '\n') {
    84                 dp = writeescapedchar(line->space, dp, *c);
    85                 c++;
    86             }
    87             line->space[dp++] = '\n';
    88             line->space[dp] = '\0';
    89         }
    91         // write line number
    92         if (showlineno) {
    93             WRITECONST(stream, out, "<span class=\"c2html-lineno\">");
    94             char lnbuf[128];
    95             int len;
    96             // line number link
    97             len = snprintf(lnbuf, 128, "<a name=\"l%d\" href=\"#l%d\">",
    98                 lineno, lineno);
    99             out(lnbuf, 1, len, stream);
   100             // justified line number
   101             len = snprintf(lnbuf, 128, "%*d ", lnw, lineno);
   102             out(lnbuf, 1, len, stream);
   103             WRITECONST(stream, out, "</a></span> ");
   104         }
   106         // write formated (or plain) code line
   107         out(line->space, 1, strlen(line->space), stream);
   108     }
   110     WRITECONST(stream, out, "</pre>\n");
   111     ucx_buffer_free(line);
   112     return 0;
   113 }
   115 void init_c_highlighter(highlighter_t *highlighter) {
   116     memset(highlighter, 0, sizeof(highlighter_t));
   117     highlighter->isdirective = check_cdirective;
   118     highlighter->istype = check_ctype;
   119     highlighter->keywords = ckeywords;
   120     highlighter->parser = cparseline;
   121 }
   123 void init_java_highlighter(highlighter_t *highlighter) {
   124     memset(highlighter, 0, sizeof(highlighter_t));
   125     highlighter->isdirective = check_jdirective;
   126     highlighter->istype = check_jtype;
   127     highlighter->keywords = jkeywords;
   128     highlighter->parser = jparseline;
   129 }
   131 #define FILEBUF_SIZE 4096
   133 enum source_type {
   134     SOURCE_C,
   135     SOURCE_JAVA,
   136     SOURCE_PLAIN
   137 };
   139 int main(int argc, char** argv) {
   140     int retcode = EXIT_SUCCESS;
   142     Settings settings;
   143     memset(&settings, 0, sizeof(settings));
   144     settings.showlinenumbers = 1;
   146     enum source_type sourcetype = SOURCE_C;
   148     char optc;
   149     while ((optc = getopt(argc, argv, "hljo:pH:F:vV")) != -1) {
   150         switch (optc) {
   151             case 'o':
   152                 if (!(optarg[0] == '-' && optarg[1] == 0)) {
   153                     settings.outfilename = optarg;
   154                 }
   155                 break;
   156             case 'F':
   157                 settings.footerfile = optarg;
   158                 break;
   159             case 'H':
   160                 settings.headerfile = optarg;
   161                 break;
   162             case 'j':
   163                 sourcetype = SOURCE_JAVA;
   164                 break;
   165             case 'p':
   166                 sourcetype = SOURCE_PLAIN;
   167                 break;
   168             case 'l':
   169                 settings.showlinenumbers = 0;
   170                 break;
   171             case 'h':
   172                 printhelp();
   173                 return EXIT_SUCCESS;
   174             case 'v':
   175             case 'V':
   176 #ifdef VERSION_DEVELOP
   177                 printf("%d.%d (unstable)\n", VERSION_MAJOR, VERSION_MINOR);
   178 #else
   179                 printf("%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
   180 #endif
   181                 return EXIT_SUCCESS;
   182             default:
   183                 return EXIT_FAILURE;
   184         }
   185     }
   187     if (optind != argc-1) {
   188         printhelp();
   189         return 1;
   190     } else {
   191         settings.infilename = argv[optind];
   192         FILE *fout;
   193         if (settings.outfilename) {
   194             fout = fopen(settings.outfilename, "w");
   195             if (!fout) {
   196                 perror("Error opening output file");
   197                 return EXIT_FAILURE;
   198             }
   199         } else {
   200             fout = stdout;
   201         }
   203         char *filebuf = malloc(FILEBUF_SIZE);
   204         if (!filebuf) {
   205             perror("Error allocating file buffer");
   206             return EXIT_FAILURE;
   207         }
   209         highlighter_t highlighter;
   210         highlighter_t *hptr = &highlighter;
   211         switch (sourcetype) {
   212             case SOURCE_C:
   213                 init_c_highlighter(&highlighter);
   214                 break;
   215             case SOURCE_JAVA:
   216                 init_java_highlighter(&highlighter);
   217                 break;
   218             case SOURCE_PLAIN:
   219                 hptr = NULL;
   220                 break;
   221             default: /* should be unreachable */
   222                 fprintf(stderr, "error in enum source_type\n");
   223                 retcode = EXIT_FAILURE;
   224                 goto prog_end;
   225         }
   227         {
   228             FILE *headerfile = fopen(settings.headerfile, "r");
   229             if (!headerfile) {
   230                 perror("Error opening header file");
   231                 retcode = EXIT_FAILURE;
   232                 goto prog_end;
   233             }
   234             ucx_stream_copy(headerfile, fout,
   235                     (read_func) fread, (write_func) fwrite,
   236                     filebuf, FILEBUF_SIZE, (size_t)-1);
   237             fclose(headerfile);
   238         }
   240         FILE *inputfile = fopen(settings.infilename, "r");
   241         if (inputfile) {
   242             UcxBuffer *content = ucx_buffer_new(NULL,
   243                     FILEBUF_SIZE*2, UCX_BUFFER_AUTOEXTEND);
   244             {
   245                 ucx_stream_copy(inputfile, content, (read_func) fread,
   246                         (write_func) ucx_buffer_write,
   247                         filebuf, FILEBUF_SIZE, (size_t)-1);
   248             }
   249             fclose(inputfile);
   251             UcxList *inputlines = ucx_list_append(NULL, content->space);
   252             for (size_t i = 1 ; i < content->size ; i++) {
   253                 if (content->space[i] == '\r') {
   254                     content->space[i] = '\n'; i++;
   255                 }
   256                 if (content->space[i] == '\n' && i+1 < content->size) {
   257                     ucx_list_append(inputlines, content->space+i+1);
   258                 }
   259             }
   261             formatfile(
   262                     hptr,
   263                     inputlines,
   264                     (write_func) fwrite,
   265                     fout,
   266                     settings.showlinenumbers);
   267             ucx_buffer_free(content);
   268         } else {
   269             perror("Error opening input file");
   270             retcode = EXIT_FAILURE;
   271         }
   273         {
   274             FILE *footerfile = fopen(settings.footerfile, "r");
   275             if (!footerfile) {
   276                 perror("Error opening footer file");
   277                 retcode = EXIT_FAILURE;
   278                 goto prog_end;
   279             }
   280             ucx_stream_copy(footerfile, fout,
   281                     (read_func) fread, (write_func) fwrite,
   282                     filebuf, FILEBUF_SIZE, (size_t)-1);
   283             fclose(footerfile);
   284         }
   286         free(filebuf);
   288         prog_end:        
   289         if (fout != stdout) {
   290             fclose(fout);
   291         }
   293         return retcode;
   294     }
   295 }

mercurial