src/c2html.c

Tue, 23 Aug 2016 15:28:56 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 23 Aug 2016 15:28:56 +0200
changeset 45
1f3835182aeb
parent 44
2b4ac35d061d
child 46
534a4ef4143d
permissions
-rw-r--r--

changes signature of parser functions to use a UcxBuffer - the functions itself don't use the API yet

     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 /* TODO: remove this workaround after refactoring highlighter structure */
    51 static void plainparseline(char *src, UcxBuffer *dest, highlighter_t* hltr) {
    52     size_t dp = 0;
    53     char *buf = dest->space + dest->pos;
    54     while (*src && *src != '\n') {
    55         dp = writeescapedchar(buf, dp, *src);
    56         src++;
    57     }
    58     buf[dp++] = '\n';
    59     buf[dp] = '\0';
    60     dest->pos += dp;
    61     dest->size += dp;
    62 }
    64 int formatfile(
    65         highlighter_t *highlighter,
    66         UcxList *in, write_func out, void *stream,
    67         int showlineno) {
    69     /* compute width of line numbering */
    70     int lnw;
    71     if (showlineno) {
    72         size_t lines = ucx_list_size(in);
    73         lnw = 1;
    74         int p = 1;
    75         while ((p*=10) < lines) lnw++;
    76     }
    78     /* allocate line buffer */
    79     UcxBuffer *line = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND);
    80     if(!line) {
    81         return 1;
    82     }
    84     /* start monospace formatting */
    85     out("<pre>\n", 1, 6, stream);
    87     /* process lines */
    88     size_t lineno = 0;
    89     UCX_FOREACH(sourceline, in) {
    90         /* increase line number and clean line buffer */
    91         lineno++;
    92         ucx_buffer_clear(line);
    94         /* write line number */
    95         if (showlineno) {
    96             ucx_bprintf(line, "<span class=\"c2html-lineno\">"
    97                     "<a name=\"l%d\" href=\"#l%d\">%*d </a></span> ",
    98                     lineno, lineno, lnw, lineno);
    99         }
   101         /* process code line */
   102         highlighter->parser(sourceline->data, line, highlighter);
   104         /* write code line */
   105         out(line->space, 1, line->size, stream);
   106     }
   108     /* end monospace formatting */
   109     out("</pre>\n", 1, 7, stream);
   111     /* cleanup and return */
   112     ucx_buffer_free(line);
   113     return 0;
   114 }
   116 #define FILEBUF_SIZE 4096
   118 enum source_type {
   119     SOURCE_C,
   120     SOURCE_JAVA,
   121     SOURCE_PLAIN
   122 };
   124 int main(int argc, char** argv) {
   126     /* Default settings */
   127     Settings settings;
   128     memset(&settings, 0, sizeof(settings));
   129     settings.showlinenumbers = 1;
   130     enum source_type sourcetype = SOURCE_C;
   132     /* Parse command line */
   133     char optc;
   134     while ((optc = getopt(argc, argv, "hljo:pH:F:vV")) != -1) {
   135         switch (optc) {
   136             case 'o':
   137                 if (!(optarg[0] == '-' && optarg[1] == 0)) {
   138                     settings.outfilename = optarg;
   139                 }
   140                 break;
   141             case 'F':
   142                 settings.footerfile = optarg;
   143                 break;
   144             case 'H':
   145                 settings.headerfile = optarg;
   146                 break;
   147             case 'j':
   148                 sourcetype = SOURCE_JAVA;
   149                 break;
   150             case 'p':
   151                 sourcetype = SOURCE_PLAIN;
   152                 break;
   153             case 'l':
   154                 settings.showlinenumbers = 0;
   155                 break;
   156             case 'h':
   157                 printhelp();
   158                 return EXIT_SUCCESS;
   159             case 'v':
   160             case 'V':
   161 #ifdef VERSION_DEVELOP
   162                 printf("%d.%d (unstable)\n", VERSION_MAJOR, VERSION_MINOR);
   163 #else
   164                 printf("%d.%d\n", VERSION_MAJOR, VERSION_MINOR);
   165 #endif
   166                 return EXIT_SUCCESS;
   167             default:
   168                 return EXIT_FAILURE;
   169         }
   170     }
   172     if (optind != argc-1) {
   173         printhelp();
   174         return EXIT_FAILURE;
   175     } else {
   176         /* Configure highlighter */
   177         highlighter_t *highlighter = calloc(1, sizeof(highlighter_t));
   178         switch (sourcetype) {
   179             case SOURCE_C:
   180                 highlighter->isdirective = check_cdirective;
   181                 highlighter->istype = check_ctype;
   182                 highlighter->keywords = ckeywords;
   183                 highlighter->parser = cparseline;
   184                 break;
   185             case SOURCE_JAVA:
   186                 highlighter->isdirective = check_jdirective;
   187                 highlighter->istype = check_jtype;
   188                 highlighter->keywords = jkeywords;
   189                 highlighter->parser = jparseline;
   190                 break;
   191             case SOURCE_PLAIN:
   192                 highlighter->parser = plainparseline;
   193                 break;
   194             default: /* should be unreachable */
   195                 fprintf(stderr, "error in enum source_type\n");
   196                 return EXIT_FAILURE;
   197         }
   199         /* Open output file */
   200         settings.infilename = argv[optind];
   201         FILE *fout;
   202         if (settings.outfilename) {
   203             fout = fopen(settings.outfilename, "w");
   204             if (!fout) {
   205                 perror("Error opening output file");
   206                 return EXIT_FAILURE;
   207             }
   208         } else {
   209             fout = stdout;
   210         }
   212         /* Allocate file buffer  */
   213         char *filebuf = malloc(FILEBUF_SIZE);
   214         if (!filebuf) {
   215             perror("Error allocating file buffer");
   216             return EXIT_FAILURE;
   217         }
   219         /* Prepend header file */
   220         {
   221             FILE *headerfile = fopen(settings.headerfile, "r");
   222             if (!headerfile) {
   223                 perror("Error opening header file");
   224                 if (fout != stdout) {
   225                     fclose(fout);
   226                 }
   227                 return EXIT_FAILURE;
   228             }
   229             ucx_stream_copy(headerfile, fout,
   230                     (read_func) fread, (write_func) fwrite,
   231                     filebuf, FILEBUF_SIZE, (size_t)-1);
   232             fclose(headerfile);
   233         }
   235         /* Process input file */
   236         FILE *inputfile = fopen(settings.infilename, "r");
   237         if (inputfile) {
   238             UcxBuffer *content = ucx_buffer_new(NULL,
   239                     FILEBUF_SIZE*2, UCX_BUFFER_AUTOEXTEND);
   240             {
   241                 ucx_stream_copy(inputfile, content, (read_func) fread,
   242                         (write_func) ucx_buffer_write,
   243                         filebuf, FILEBUF_SIZE, (size_t)-1);
   244             }
   245             fclose(inputfile);
   247             UcxList *inputlines = ucx_list_append(NULL, content->space);
   248             for (size_t i = 1 ; i < content->size ; i++) {
   249                 if (content->space[i] == '\r') {
   250                     content->space[i] = '\n'; i++;
   251                 }
   252                 if (content->space[i] == '\n' && i+1 < content->size) {
   253                     ucx_list_append(inputlines, content->space+i+1);
   254                 }
   255             }
   257             formatfile(
   258                     highlighter,
   259                     inputlines,
   260                     (write_func) fwrite,
   261                     fout,
   262                     settings.showlinenumbers);
   264             free(highlighter);
   265             ucx_buffer_free(content);
   266         } else {
   267             perror("Error opening input file");
   268             if (fout != stdout) {
   269                 fclose(fout);
   270             }
   271             return EXIT_FAILURE;
   272         }
   274         /* Append footer file */
   275         {
   276             FILE *footerfile = fopen(settings.footerfile, "r");
   277             if (!footerfile) {
   278                 perror("Error opening footer file");
   279                 if (fout != stdout) {
   280                     fclose(fout);
   281                 }
   282                 return EXIT_FAILURE;
   283             }
   284             ucx_stream_copy(footerfile, fout,
   285                     (read_func) fread, (write_func) fwrite,
   286                     filebuf, FILEBUF_SIZE, (size_t)-1);
   287             fclose(footerfile);
   288         }
   291         free(filebuf);
   293         return EXIT_SUCCESS;
   294     }
   295 }

mercurial