#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "c2html.h"

#ifdef HTML3
#include "c2html3.h"
#endif

#ifdef HTML4
#include "c2html4.h"
#endif

#ifdef XHTML1
#include "c2xhtml1.h"
#endif

#ifdef XHTML11
#include "c2xhtml11.h"
#endif

void output_header();
void output_body();
int is_keyword(char *token);
void escape_char(int c);

int main(int argc, char *argv[]){
    output_header();
    output_body();
    return 0;
}

void output_header(){
    puts(header);
}

/*
    state 0: normal
    state 1: in comment
    state 2: in string
*/
void output_body(){
    int i, c, prev, state;
    char token[TOKEN_MAX_LENGTH];
    
    printf("<body>\n");
    printf("<pre class=\"code\">\n");
    
    i = 0;
    state = 0;
    prev = '\0';
    while((c = getchar()) != EOF){
        if (c == '\\'){
            putchar(c);
            prev = c;
            c = getchar();
        }
        
        switch (state){
            case 0:
                if (isalnum(c) || (c == '_')){
                        token[i++] = c;
                } else {
                    token[i++] = '\0';
                    i = 0;
                    if (is_keyword(token)){
                        printf("%s%s%s", start_keyword, token, end_keyword);
                    } else {
                        printf("%s", token);
                    }
                    
                    switch (c){
                        case '"':
                            escape_char(c);
                            if (prev != '\''){
                                state = 2;
                            }
                            break;
                        case '/':
                            prev = c;
                            c = getchar();
                            
                            switch (c){
                                case '/':
                                    printf("%s%s", "//", start_comment);
                                    c = getchar();
                                    while((c != '\n') && (c != EOF)){
                                        escape_char(c);
                                        c = getchar();
                                    }
                                    puts(end_comment);
                                    break;
                                case '*':
                                    printf("%s%s", start_comment, "/*");
                                    state = 1;
                                    break;
                                default:
                                    escape_char(prev);
                                    escape_char(c);
                                    break;
                            }
                            break;
                        default:
                            escape_char(c);
                            break;
                    }
                }
                break;
            case 1:
                if (prev == '*' && c == '/'){
                    printf("%c%s", c, end_comment);
                    state = 0;
                } else {
                    escape_char(c);
                }
                break;
            case 2:
                escape_char(c);
                if ((c == '"') && (prev != '\\')){
                    state = 0;
                }
                break;
        }
        
        prev = c;
    }
    
    printf("\n</pre>\n");
    printf(
        "</body>\n"
        "\n"
        "</html>\n"
    );
}

void escape_char(int c){
    switch (c){
        case '<': 
            printf("&lt;");
            break;
        case '>': 
            printf("&gt;");
            break;
        case '&': 
            printf("&amp;");
            break;
        case '"': 
            printf("&quot;");
            break;
        case '\t':
            printf("    ");
            break;
        default: 
            putchar(c);
            break;
    }
}

int is_keyword(char *token){
    int i;
    
    for(i = 0; i < keyword_count; i++){
        if (strcmp(token, keyword_list[i]) == 0){
            return 1;
        }
    }
    return 0;
}