src/c2html.c

Wed, 10 Jul 2013 13:38:28 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 10 Jul 2013 13:38:28 +0200
changeset 11
c59fe73459fd
parent 6
d10f7570add4
child 12
7ce5c4b51959
permissions
-rw-r--r--

option for output file

     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013 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 <stdio.h>
    31 #include <stdlib.h>
    32 #include <string.h>
    33 #include <fcntl.h>
    34 #include <unistd.h>
    35 #include <ctype.h>
    37 #define INPUTBUF_SIZE 2048
    38 #define WORDBUF_SIZE 16
    40 const char* keywords[] = {
    41   "auto", "break", "case", "char", "const", "continue", "default", "do", 
    42   "double", "else", "enum", "extern", "float", "for", "goto", "if", "int", 
    43   "long", "register", "return", "short", "signed", "sizeof", "static", "struct", 
    44   "switch", "typedef", "union", "unsigned", "void", "volatile", "while", NULL
    45 };
    47 typedef struct {
    48   char* outfilename;
    49   char* infilename;
    50 } settings_t;
    52 typedef struct {
    53   size_t count;
    54   size_t capacity;
    55   size_t maxlinewidth;
    56   char** lines;
    57 } inputfile_t;
    59 inputfile_t *inputfilebuffer(size_t capacity) {
    60   inputfile_t *inputfile = (inputfile_t*) malloc(sizeof(inputfile_t));
    61   inputfile->lines = (char**) malloc(capacity * sizeof(char*));
    62   inputfile->capacity = capacity;
    63   inputfile->count = 0;
    64   inputfile->maxlinewidth = 0;
    66   return inputfile;
    67 }
    69 void addline(inputfile_t *inputfile, char* line, size_t width) {
    70   char *l = (char*) malloc(width+1);
    71   memcpy(l, line, width);
    72   l[width] = 0;
    73   if (inputfile->count >= inputfile->capacity) {
    74     inputfile->capacity <<= 1;
    75     inputfile->lines = realloc(inputfile->lines, inputfile->capacity);
    76   }
    77   inputfile->lines[inputfile->count] = l;
    78   inputfile->maxlinewidth =
    79           width > inputfile->maxlinewidth ? width : inputfile->maxlinewidth;
    80   inputfile->count++;
    81 }
    83 void freeinputfilebuffer(inputfile_t *inputfile) {
    84   for (int i = 0 ; i < inputfile->count ; i++) {
    85     free(inputfile->lines[i]);
    86   }
    87   free(inputfile->lines);
    88   free(inputfile);
    89 }
    91 inputfile_t *readinput(char *filename) {
    93   int fd = open(filename, O_RDONLY);
    94   if (fd == -1) return NULL;
    96   inputfile_t *inputfile = inputfilebuffer(512);
    98   char buf[INPUTBUF_SIZE];
    99   ssize_t r;
   101   size_t maxlinewidth = 256;
   102   char *line = (char*) malloc(maxlinewidth);
   103   size_t col = 0;
   105   while ((r = read(fd, buf, INPUTBUF_SIZE)) > 0) {
   106     for (size_t i = 0 ; i < r ; i++) {
   107       if (col >= maxlinewidth-4) {
   108         maxlinewidth <<= 1;
   109         line = realloc(line, maxlinewidth);
   110       }
   112       if (buf[i] == '\n') {
   113         line[col++] = '\n';
   114         line[col] = 0;
   115         addline(inputfile, line, col);        
   116         col = 0;
   117       } else {
   118         line[col++] = buf[i];
   119       }
   120     }
   121   }
   123   free(line);
   125   close(fd);
   127   return inputfile;
   128 }
   130 size_t writeescapedchar(char *dest, size_t dp, char c) {
   131   if (c == '>') {
   132     dest[dp++] = '&'; dest[dp++] = 'g';
   133     dest[dp++] = 't'; dest[dp++] = ';';
   134   } else if (c == '<') {
   135     dest[dp++] = '&'; dest[dp++] = 'l';
   136     dest[dp++] = 't'; dest[dp++] = ';';
   137   } else {
   138     dest[dp++] = c;
   139   }
   141   return dp;
   142 }
   144 int iskeyword(char *word) {
   145   for (int i = 0 ; keywords[i] ; i++) {
   146     if (strncmp(keywords[i], word, WORDBUF_SIZE) == 0) {
   147       return 1;
   148     }
   149   }
   150   return 0;
   151 }
   153 #define istype(word, len) (word[len-2] == '_' && word[len-1] == 't')
   155 void parseline(char *src, char *dest) {
   156   size_t sp = 0, dp = 0;
   157   /* indent */
   158   while (isspace(src[sp])) {
   159     dest[dp++] = src[sp++];
   160   }
   161   char word[WORDBUF_SIZE];
   162   memset(word, 0, WORDBUF_SIZE);
   163   size_t wp = 0;
   164   int closespan;
   165   for (char c = src[sp] ; c ; c=src[++sp]) {
   166     if (!isalnum(c) && c != '_') {
   167       /* interpret word int_t */
   168       if (wp > 0 && wp < WORDBUF_SIZE) {
   169         if (iskeyword(word)) {
   170           memcpy(&(dest[dp]), "<span class=\"c2html-keyword\">", 29);
   171           dp += 29;
   172           closespan = 1;
   173         } else if (istype(word, wp)) {
   174           memcpy(&(dest[dp]), "<span class=\"c2html-type\">", 26);
   175           dp += 26;
   176           closespan = 1;
   177         } else {
   178           closespan = 0;
   179         }
   180         for (int i = 0 ; i < wp ; i++) {
   181           dp = writeescapedchar(dest, dp, word[i]);
   182         }
   183         if (closespan) {
   184           memcpy(&(dest[dp]), "</span>", 7);
   185           dp += 7;
   186         }
   187         memset(word, 0, WORDBUF_SIZE);
   188         wp = 0;
   189       }
   190       dp = writeescapedchar(dest, dp, c);
   191     } else {
   192       /* read word */
   193       if (wp < WORDBUF_SIZE) {
   194         word[wp++] = c;
   195       } else if (wp == WORDBUF_SIZE) {
   196         for (int i = 0 ; i < WORDBUF_SIZE ; i++) {
   197           dp = writeescapedchar(dest, dp, word[i]);
   198         }
   199         wp++;
   200         dp = writeescapedchar(dest, dp, c);
   201       } else {
   202         dp = writeescapedchar(dest, dp, c);
   203       }
   204     }
   205   }
   206   dest[dp] = 0;
   207 }
   209 void printhelp() {
   210   printf("Formats source code using HTML.\n\nUsage:\n"
   211       "  c2html [Options] FILE\n\n"
   212       " Options:\n"
   213       "  -h                    Prints this help message\n"
   214       "  -o <output>           Output file (if not specified, stdout is used)\n"
   215       "\n");
   218 }
   220 int lnint(size_t lnc) {
   221   int w = 1, p = 1;
   222   while ((p*=10) < lnc) w++;
   223   return w;
   224 }
   226 int main(int argc, char** argv) {
   228   settings_t settings;
   229   settings.outfilename = NULL;
   231   char optc;
   232   while ((optc = getopt(argc, argv, "ho:")) != -1) {
   233     switch (optc) {
   234       case 'o':
   235         if (!(optarg[0] == '-' && optarg[1] == 0)) {
   236           settings.outfilename = optarg;
   237         }
   238         break;
   239       case 'h':
   240         printhelp();
   241         return 0;
   242       default:
   243         return 1;
   244     }
   245   }
   247   if (optind != argc-1) {
   248     printhelp();
   249     return 1;
   250   } else {
   251     settings.infilename = argv[optind];
   253     inputfile_t *inputfile = readinput(settings.infilename);
   254     if (inputfile) {
   255       FILE *fout;
   256       if (settings.outfilename) {
   257         fout = fopen(settings.outfilename, "w");
   258       } else {
   259         fout = stdout;
   260       }
   261       fprintf(fout, "<pre>\n");
   262       char *line = (char*) malloc(inputfile->maxlinewidth*64);
   263       int lnw = lnint(inputfile->count);
   264       for (int i = 0 ; i < inputfile->count ; i++) {
   265         parseline(inputfile->lines[i], line);
   266         fprintf(fout, "<span class=\"c2html-lineno\">%*d:</span> %s",
   267             lnw, i, line);
   268       }
   269       free(line);
   270       fprintf(fout, "</pre>\n");
   272       if (fout != stdout) {
   273         fclose(fout);
   274       }
   276       freeinputfilebuffer(inputfile);
   277     }
   279     return 0;
   280   }
   281 }

mercurial