%{ /* ** mod_color.c -- Apache syntax coloring module ** ** This module applies syntax coloring to source code. At the ** current time this is limited to C (and some C++) source code, ** although additional source formats may be supported in the future. ** Since this module performs a lexical analysis of the file, ** it may not provide usable results on other types of files. ** ** To play with this module first compile it into a ** DSO file and install it into Apache's libexec directory ** by running: ** ** $ apxs -c -i mod_color.c ** ** Then activate it in Apache's srm.conf file add ** ** # srm.conf ** AddHandler c-handler .c ** AddHandler c-handler .h ** ** Then after restarting Apache via ** ** $ apachectl restart ** ** you immediately can request the URL /%NAME and watch for the ** output of this module. This can be achieved for instance by ** installing the kernel source code, adding ** ** # srm.conf ** Alias /kernel/ /usr/src/linux ** ** and then viewing any of the C source files or headers. ** ** This module is Copyright (C) 2000 Bear Giles; it is derived ** from a cgi-bin syntax colorer written by the author in 1997. ** It is released under the Apache license. */ #include "httpd.h" #include "http_config.h" #include "http_protocol.h" #include "ap_config.h" #include #include #include module color_module; static const char rcsid[] = "$Id: mod_color.l,v 1.4 2000/03/06 17:32:33 bear Exp $"; inline size_t min (size_t a, size_t b) { return (a < b) ? a : b; } inline size_t max (size_t a, size_t b) { return (a > b) ? a : b; } static int synccwrap (void); #include #define T_EOF 256 #define T_PREPROCESSOR 257 #define T_COMMENT 258 #define T_S_LITERAL 259 #define T_C_LITERAL 260 #define T_I_LITERAL 261 #define T_R_LITERAL 262 #define T_IDENTIFIER 263 #define T_KEYWORD 264 #define T_CPP_KEYWORD 265 #define T_ASSIGNMENT 266 #define T_OPERATOR 267 #define T_L_PAREN 268 #define T_R_PAREN 269 #define T_L_BRACE 270 #define T_R_BRACE 271 #define T_L_BRACKET 272 #define T_R_BRACKET 273 #define T_SEMICOLON 274 #define T_COMMA 275 #define T_NEWLINE 276 #define T_WHITESPACE 277 #define T_LEADSPACE 278 #define T_BACKGROUND 279 #define T_TEXT 280 #define T_STORAGE 281 #define T_POSIX_IDENTIFIER 282 #define T_STD_IDENTIFIER 283 #define T_SEPARATOR 284 #define T_DEFINITION 285 #define T_RULE 286 #define T_LAST T_RULE typedef struct { pool *p; int enable; char *color[T_LAST - T_EOF + 1]; char *style[T_LAST - T_EOF + 1]; char *face[T_LAST - T_EOF + 1]; } color_dir_config; static color_dir_config *cfg = NULL; static int line_num = 1; #define BUFFER_SIZE 8096 static char buffer[BUFFER_SIZE+1]; static size_t bufcnt, len; static int mode = 0; static int depth = 0; static int state = 0; static int brace_depth = 0; %} begin_code ^\%\{ end_code ^\%\} d [1-9][[:digit:]]* o 0[0-7]* h 0[x|X]([[:xdigit:]])* integer ({o}|{d}|{h}) real ({d}+|{d}+\.{d}*|{d}*\.{d}+)([eE][-+]?{d}+)?[fF]? ident1 [[:alpha:]]* ident2 [[:alpha:]]*[[:alnum:]|_]* ident3 _+[[:alpha:]]* ident4 _+[[:alpha:]]*[[:alnum:]|_]* identifier ({ident1}|{ident2}|{ident3}|{ident4}) whitespace [[:blank:]]+ newline \n structop (\-\>|\.\|::) relop ==|!=|<=|<|>=|> arithop (\+|-|\*|\/|%) logop (&&)|(\|\|)|\! bitop (&)|(\|)|\^|~|<<|>> triop (\?|:) incop (\+\+|--) lparen \( rparen \) lbrace \{ rbrace \} lbracket \[ rbracket \] semicolon \; comma \, state ^\<[[:alnum:]_]+\> leading_space ^[ \t]+ pattern [[:alnum:]_]+ lexop ^%[[:alnum:]]+ line [^\n%{'"/]+ lex_line [^\n/]+ lex_pattern [^[:space:]]+ perf_token ^[^[:space:],]+ perf_rest ,[^\n]+ %x c_comment cc_comment string chr preprocessor %x lex_definitions lex_rules %x yacc_definitions yacc_rules %x gperf_definitions gperf_rules %% %{ #define YY_USER_INIT { switch (mode) { \ case lex_definitions: BEGIN (mode); break; \ case yacc_definitions: BEGIN (mode); break; \ case gperf_definitions: BEGIN (mode); break; \ } } %} int start_line; /* ************************** * We have a large amount of glue for yacc, lex and perf. * Despite initial appearances, this doesn't modify the * C lexical scanner by much - but keeping track of the * "start state" can be a real pain. * ************************** */ { \%\% { mode = lex_rules; BEGIN (mode); return T_SEPARATOR; } {begin_code} { mode |= 0x4000; BEGIN (0); depth = 0; return T_SEPARATOR; } {lexop} { return T_DEFINITION; } "/*" | "//" { BEGIN (0); yyless (0); } /* this should only be a comment! */ {leading_space} { return T_WHITESPACE; } /* for now, we don't differentiate within line */ "/" | {lex_line} { return T_DEFINITION; } {newline} { return T_NEWLINE; } . yyerror ("startled"); } { \%\% { mode = 0; BEGIN (0); return T_SEPARATOR; } {state} { state++; return T_RULE; } {lbrace} { if (state == 1) { state++; return T_RULE; } else { depth = 0; BEGIN (0); yyless (0); } } {rbrace} { if (state == 2) { state = 0; } return T_RULE; } {leading_space} { if (state == 0) BEGIN (0); return T_WHITESPACE; } {begin_code} { mode |= 0x4000; BEGIN (0); depth = 0; return T_SEPARATOR; } {newline} { return T_NEWLINE; } "/*" | "//" { BEGIN (0); yyless(0); } {lex_pattern} { BEGIN (0); return T_RULE; } } { \%\% { mode = yacc_rules; BEGIN (yacc_rules); return T_SEPARATOR; } {begin_code} { mode |= 0x4000; BEGIN (0); depth = 0; return T_SEPARATOR; } {lbrace} | "\'" | "\"" | "/*" | "//" { depth = 0; BEGIN (0); yyless (0); } /* this is also yacc-op */ {lexop} { return T_DEFINITION; } /* for now, we don't differentiate within line */ {line} { return T_DEFINITION; } {whitespace} { return T_WHITESPACE; } {newline} { return T_NEWLINE; } . yyerror ("startled"); } { \%\% { mode = 0; BEGIN (0); return T_SEPARATOR; } {lbrace} | "\'" | "\"" | "/*" | "//" { depth = 0; BEGIN (0); yyless (0); } ":" | "|" | ";" | "%prec" | {pattern} { return T_RULE; } {whitespace} { return T_WHITESPACE; } {newline} { return T_NEWLINE; } . yyerror ("startled"); } { \%\% { mode = gperf_rules; BEGIN (gperf_rules); return T_SEPARATOR; } {begin_code} { mode |= 0x4000; BEGIN (0); depth = 0; return T_SEPARATOR; } "struct" { /* should be the only thing, besides a code block */ depth = 0; BEGIN (0); yyless (0); } {whitespace} { return T_WHITESPACE; } {newline} { return T_NEWLINE; } . yyerror ("startled"); } { \%\% { mode = 0; brace_depth = 0; BEGIN (0); return T_SEPARATOR; } /* we know that the first item *must* be a string. */ {perf_token} { start_line = line_num; strncpy (buffer, yytext, yyleng); bufcnt = yyleng; buffer[bufcnt] = '\0'; return T_S_LITERAL; } /* the rest of the items must be elements of the structure */ {perf_rest} { brace_depth = 1; BEGIN (0); yyless (0); } {newline} { return T_NEWLINE; } } {end_code} { mode &= ~0x4000; switch (mode) { case lex_definitions: case lex_rules: case yacc_definitions: case yacc_rules: case gperf_definitions: case gperf_rules: BEGIN (mode); break; } depth = 0; return T_SEPARATOR; } "|" { if (mode == lex_rules) return T_RULE; REJECT; } /* ************************** * Check for start of preprocessor directive, * character string, character literal, or comment. * ************************** */ ^# | ^{whitespace}+\# { /* for Gnu extensions */ start_line = line_num; bufcnt = min (yyleng, BUFFER_SIZE); strncpy (buffer, yytext, bufcnt); buffer[bufcnt] = '\0'; BEGIN (preprocessor); } "\"" { start_line = line_num; bufcnt = 0; buffer[bufcnt] = '\0'; BEGIN (string); } "\'" { start_line = line_num; bufcnt = 0; buffer[bufcnt] = '\0'; BEGIN (chr); } "//" { start_line = line_num; bufcnt = min (yyleng, BUFFER_SIZE); strncpy (buffer, yytext, bufcnt); buffer[bufcnt] = '\0'; BEGIN (cc_comment); } "/*" { start_line = line_num; bufcnt = min (yyleng, BUFFER_SIZE); strncpy (buffer, yytext, bufcnt); buffer[bufcnt] = '\0'; BEGIN (c_comment); } /* ************************** * Munch on preprocessor directives * ************************** */ { \\{newline} | /* continue to next line */ \\. | /* escape next character */ [^\n\\]+ { /* normal text */ len = min (BUFFER_SIZE - bufcnt, yyleng); strncpy (&buffer[bufcnt], yytext, len); buffer[bufcnt += len] = '\0'; } /* terminator */ {newline} { yyless (0); BEGIN (INITIAL); return (T_PREPROCESSOR); } /* errors */ <> { /* yyterminate(); */ return (T_PREPROCESSOR); } } /* ************************** * Munch on string literals * ************************** */ { \\{newline} | /* continue to next line */ \\. | /* escape next character */ [^\n\"\\]+ { /* normal text */ len = min (BUFFER_SIZE - bufcnt, yyleng); strncpy (&buffer[bufcnt], yytext, len); buffer[bufcnt += len] = '\0'; } /* terminator */ "\"" { if (mode == yacc_definitions && depth == 0) BEGIN (mode); else if (mode == yacc_rules && depth == 0) BEGIN (mode); else BEGIN (INITIAL); return (T_S_LITERAL); } /* errors */ {newline} yyerror ("unterminated string; winging it"); <> { yyerror ("unterminated string at EOF"); yyterminate(); } } /* ************************** * Munch on character literals * ************************** */ { \\{newline} | /* continue to next line */ \\. | /* escape next character */ [^\n\'\\]+ { /* normal text */ len = min (BUFFER_SIZE - bufcnt, yyleng); strncpy (&buffer[bufcnt], yytext, len); buffer[bufcnt += len] = '\0'; } /* terminator */ "\'" { if (mode == yacc_definitions && depth == 0) BEGIN (mode); else if (mode == yacc_rules && depth == 0) BEGIN (mode); else BEGIN (INITIAL); return (T_C_LITERAL); } /* error */ {newline} yyerror ("unterminated string; winging it"); <> { yyerror ("unterminated character at EOF"); yyterminate(); } } /* ************************** * Munch on C-style comments * ************************** */ { /* terminator */ "*"+"/" { len = min (BUFFER_SIZE - bufcnt, yyleng); strncpy (&buffer[bufcnt], yytext, len); buffer[bufcnt += len] = '\0'; if (depth > 0) { BEGIN (INITIAL); } else { switch (mode) { case lex_rules: case yacc_definitions: case yacc_rules: case gperf_rules: case gperf_definitions: BEGIN (mode); break; default: BEGIN (0); } } return (T_COMMENT); } /* normal text */ [^*\n]* | [^*\n]*\n | "*"+[^*/\n]* | "*"+[^*/\n]*\n { len = min (BUFFER_SIZE - bufcnt, yyleng); strncpy (&buffer[bufcnt], yytext, len); buffer[bufcnt += len] = '\0'; } } /* ************************** * Munch on C++-style comments * ************************** */ { [^\n]*/\n { len = min (BUFFER_SIZE - bufcnt, yyleng); strncpy (&buffer[bufcnt], yytext, len); buffer[bufcnt += len] = '\0'; if (depth > 0) { BEGIN (INITIAL); } else { switch (mode) { case lex_rules: case yacc_definitions: case yacc_rules: case gperf_rules: case gperf_definitions: BEGIN (mode); break; default: BEGIN (0); } } return (T_COMMENT); } } /* ************************** * Recognize keywords. We check for _all_ * keywords, to check for old code which will * not compile with newer compilers. * ************************** */ break | /* K&R keywords */ case | continue | default | do | else | for | if | return | switch | while | entry | /* depreciated K&R keywords */ fortran | goto | inline return T_KEYWORD; char | double | extern | float | int | long | register | short | sizeof | static | struct | typedef | union | unsigned | auto | /* depreciated K&R keywords */ const | /* additional ANSI C90 keywords */ enum | mutable | signed | void | volatile | bool | /* additional ANSI C9X keywords */ false | true return T_STORAGE; catch | /* additional C++ keywords */ class | private | protected | public | raise | template | virtual return T_CPP_KEYWORD; /* we could also check for asm, far, and near */ fd_set | /* additional storage classes commonly defined by POSIX */ dev_t | /* these are defined for syntax coloring */ ino_t | mode_t | nlink_t | off_t | pid_t | uid_t | gid_t | daddr_t | size_t | ssize_t | ptrdiff_t | time_t | clock_t | caddr_t return T_POSIX_IDENTIFIER; u_char | /* BSD-type declarations */ u_short | u_int | u_long return T_STD_IDENTIFIER; unchar | /* sysv-type declarations */ ushort | uint | ulong return T_STD_IDENTIFIER; /* ************************** * Recognize operators * ************************** */ {arithop}= | {logop}= | {bitop}= | = return (T_ASSIGNMENT); {structop} | {relop} | {arithop} | {incop} | {logop} | {bitop} | {triop} return (T_OPERATOR); /* ************************** * Count nesting objects. * ************************** */ {lparen} return T_L_PAREN; {rparen} return T_R_PAREN; {lbrace} { depth++; return T_L_BRACE; } {rbrace} { if (--depth == 0) { switch (mode) { case lex_definitions : BEGIN (lex_definitions); break; case lex_rules : BEGIN (lex_rules); break; case yacc_definitions: BEGIN (yacc_definitions); break; case yacc_rules : BEGIN (yacc_rules); break; } } return T_R_BRACE; } {lbracket} return T_L_BRACKET; {rbracket} return T_R_BRACKET; {semicolon} { if (depth == 0 && mode == gperf_definitions) BEGIN (mode); return T_SEMICOLON; } {comma} return T_COMMA; /* ************************** * Wrap it all up. * ************************** */ {integer} return (T_I_LITERAL); {real} return (T_R_LITERAL); {identifier} return (T_IDENTIFIER); {newline} { if (depth == 0) { switch (mode) { case lex_definitions: case lex_rules: case gperf_rules: BEGIN (mode); break; } } return T_NEWLINE; } \$\$ | \${integer} { if (mode != yacc_rules) REJECT; return T_IDENTIFIER; } ^{whitespace}*/\n return T_LEADSPACE; {whitespace} return T_WHITESPACE; . yyerror ("startled"); <> yyterminate(); %% void action_comment (request_rec *r); void action_preprocessor (request_rec *r); void action_str_literal (request_rec *r); void action_chr_literal (request_rec *r); void action_int_literal (request_rec *r); void action_fp_literal (request_rec *r); void action_identifier (request_rec *r); void action_keyword (request_rec *r); void action_operator (request_rec *r); void action_assignment (request_rec *r); void action_glue (request_rec *r, int); void action_whitespace (request_rec *r, int); void action_grammar (request_rec *r, int); void color (request_rec *r, int s, const char *str); void prologue (request_rec *r); void epilogue (request_rec *r); void emit (request_rec *r, const char *, int, const char *, const char *, const char *); void dump_strings (request_rec *r); void dump_identifiers (request_rec *r); static int comment_count = 0; static int ident_count = 0; static int str_count = 0; static int chr_count = 0; static int int_count = 0; static int float_count = 0; static int paren_count = 0; static int brace_count = 0; static int bracket_count = 0; static int paren_depth = 0; /* static int brace_depth = 0; */ static int bracket_depth = 0; static int statements = 0; int pos = 0; int tabstop = 4; char *filename = NULL; struct StrTable { int line_num; char *value; }; #define MAX_STRINGS 2000 struct StrTable strTable[MAX_STRINGS]; int strCount = 0; struct IdentTable { int line_num; char *value; }; #define MAX_IDENTIFIERS 200 struct IdentTable identTable[MAX_IDENTIFIERS]; int identCount = 0; int yyerror (const char * message) { printf ("%d: %s near symbol '%s'\n", line_num, message, yytext); } void action_preprocessor (request_rec *r) { color (r, T_PREPROCESSOR, buffer); } void action_comment (request_rec *r) { comment_count++; color (r, T_COMMENT, buffer); } void action_int_literal (request_rec *r) { int_count++; color (r, T_I_LITERAL, yytext); } void action_fp_literal (request_rec *r) { float_count++; color (r, T_R_LITERAL, yytext); } void action_str_literal (request_rec *r) { if (strCount < MAX_STRINGS) { strTable[strCount].line_num = line_num; strTable[strCount].value = strdup (buffer); strCount++; } str_count++; color (r, T_S_LITERAL, buffer); } void action_chr_literal (request_rec *r) { chr_count++; color (r, T_C_LITERAL, buffer); } void action_identifier (request_rec *r) { if (identCount < MAX_IDENTIFIERS && brace_depth == 0 && paren_depth == 0) { identTable[identCount].line_num = line_num; identTable[identCount].value = strdup (yytext); identCount++; } ident_count++; color (r, T_IDENTIFIER, yytext); } void action_keyword (request_rec *r) { color (r, T_KEYWORD, yytext); } void action_operator (request_rec *r) { color (r, T_OPERATOR, yytext); } void action_assignment (request_rec *r) { color (r, T_ASSIGNMENT, yytext); } void action_glue (request_rec *r, int s) { switch (s) { case T_L_PAREN: paren_count++; paren_depth++; color (r, s, yytext); break; case T_R_PAREN: paren_depth--; color (r, s, yytext); break; case T_L_BRACE: brace_count++; brace_depth++; color (r, s, yytext); break; case T_R_BRACE: brace_depth--; color (r, s, yytext); break; case T_L_BRACKET: bracket_count++; bracket_depth++; color (r, s, yytext); break; case T_R_BRACKET: bracket_depth--; color (r, s, yytext); break; case T_SEMICOLON: statements++; color (r, s, yytext); break; case T_COMMA: color (r, s, yytext); break; default: ; } } void action_whitespace (request_rec *r, int s) { color (r, s, yytext); } /* This routine can do anything special for yacc & lex grammars. */ void action_grammar (request_rec *r, int s) { color (r, s, yytext); } /**************************************************************/ void color (request_rec *r, int s, const char *str) { int i; switch (s) { case T_R_PAREN: i = T_L_PAREN - T_EOF; emit (r, str, 0, cfg->style[i], cfg->color[i], cfg->face[i]); break; case T_R_BRACKET: i = T_L_BRACKET - T_EOF; emit (r, str, 0, cfg->style[i], cfg->color[i], cfg->face[i]); break; case T_R_BRACE: i = T_L_BRACE - T_EOF; emit (r, str, 0, cfg->style[i], cfg->color[i], cfg->face[i]); break; case T_COMMA: i = T_SEMICOLON - T_EOF; emit (r, str, 0, cfg->style[i], cfg->color[i], cfg->face[i]); break; case T_S_LITERAL: i = s - T_EOF; emit (r, str, '\"', cfg->style[i], cfg->color[i], cfg->face[i]); break; case T_C_LITERAL: i = s - T_EOF; emit (r, str, '\'', cfg->style[i], cfg->color[i], cfg->face[i]); break; case T_LEADSPACE: case T_WHITESPACE: emit (r, str, 0, 0, 0, 0); break; case T_NEWLINE: emit (r, "\n", 0, 0, 0, 0); break; default: i = s - T_EOF; emit (r, str, 0, cfg->style[i], cfg->color[i], cfg->face[i]); break; } } void prologue (request_rec *r) { ap_rprintf (r, "\r\n", cfg->color[T_BACKGROUND - T_EOF], cfg->color[T_TEXT - T_EOF]); ap_rputs ("
\r\n", r);
	}


void epilogue (request_rec *r)
	{
	time_t now;

	now = time (NULL);

	ap_rputs ("
\r\n", r); ap_rputs ("File: ", r); emit (r, r->filename, 0, 0, 0, 0); ap_rputs ("
\r\n", r); ap_rputs ("Date: ", r); ap_rputs (asctime (localtime (&r->finfo.st_mtime)), r); ap_rputs ("\ \n", r); ap_rputs ("\r\n", r); } void emit (request_rec *r, const char *s, int delimiter, const char *style, const char *color, const char *face) { char ch; int count; if (face != NULL && *face != '\0') ap_rprintf (r, "", face); if (color != NULL && *color != '\0') ap_rprintf (r, "", color); if (style != NULL && *style != '\0') ap_rprintf (r, "<%s>", style); switch (delimiter) { case '\'': ap_rputs ("\'", r); pos++; break; case '\"': ap_rputs (""", r); pos++; break; } while ((ch = *s++) != '\0') { switch (ch) { case '\"': ap_rputs (""", r); pos++; break; case '<': ap_rputs ("<", r); pos++; break; case '>': ap_rputs (">", r); pos++; break; case '\n': if (style != NULL && *style != '\0') ap_rprintf (r, "", style); if (color != NULL && *color != '\0') ap_rputs ("", r); if (face != NULL && *face != '\0') ap_rputs ("", r); ap_rprintf (r, "\n%4d| ", line_num++); if (face != NULL && *face != '\0') ap_rprintf (r, "", face); if (color != NULL && *color != '\0') ap_rprintf (r, "", color); if (style != NULL && *style != '\0') ap_rprintf (r, "<%s>", style); pos = 0; break; case ' ': ap_rputc (ch, r); pos++; break; case '\t': count = tabstop - (pos % tabstop); ap_rprintf (r, "%*.*s", count, count, " "); pos += count; break; default: ap_rputc (ch, r); pos++; } } switch (delimiter) { case '\'': ap_rputs ("\'", r); pos++; break; case '\"': ap_rputs (""", r); pos++; break; } if (style != NULL && *style != '\0') ap_rprintf (r, "", style); if (color != NULL && *color != '\0') ap_rputs ("", r); if (face != NULL && *face != '\0') ap_rputs ("", r); } void dump_identifiers (request_rec *r) { int i; ap_rputs ("
\r\n", r); ap_rputs ("

Top-Level Identifiers

\r\n", r); ap_rputs ("\r\n", r); ap_rputs ("\r\n", r); for (i = 0; i < identCount; i++) { ap_rprintf (r, "\r\n"); } ap_rputs ("
LineIdentifier
%4d", identTable[i].line_num); emit (r, identTable[i].value, 0, 0, 0, 0); ap_rprintf (r, "
\r\n", r); } void dump_strings (request_rec *r) { int i; ap_rputs ("
\r\n", r); ap_rputs ("

Strings

\r\n", r); ap_rputs ("\r\n", r); ap_rputs ("\r\n", r); for (i = 0; i < strCount; i++) { ap_rprintf (r, "\r\n"); } ap_rputs ("
LineString
%4d", strTable[i].line_num); emit (r, strTable[i].value, '\"', 0, 0, 0); ap_rprintf (r, "
\r\n", r); } static int synccwrap (void) { return 1; } /*----------------------------------------------------------------*/ static void process_c (request_rec *r) { int s; pos = 0; line_num = 1; prologue (r); ungetc ('\n', yyin); while ((s = yylex ()) > 0) { switch (s) { case T_COMMENT: action_comment (r); break; case T_PREPROCESSOR:action_preprocessor (r); break; case T_S_LITERAL: action_str_literal (r); break; case T_C_LITERAL: action_chr_literal (r); break; case T_I_LITERAL: action_int_literal (r); break; case T_R_LITERAL: action_fp_literal (r); break; case T_IDENTIFIER: action_identifier (r); break; case T_KEYWORD: case T_CPP_KEYWORD: case T_STORAGE: // case T_POSIX_IDENTIFIER: // case T_STD_IDENTIFIER: action_keyword (r); break; case T_POSIX_IDENTIFIER: case T_STD_IDENTIFIER: color (r, s, yytext); break; case T_ASSIGNMENT: action_assignment (r); break; case T_OPERATOR: action_operator (r); break; case T_L_PAREN: case T_R_PAREN: case T_L_BRACE: case T_R_BRACE: case T_L_BRACKET: case T_R_BRACKET: case T_SEMICOLON: case T_COMMA: action_glue (r, s); break; case T_NEWLINE: case T_LEADSPACE: case T_WHITESPACE: action_whitespace (r, s); break; case T_SEPARATOR: case T_DEFINITION: case T_RULE: action_grammar (r, s); break; } } ap_rputs ("
\r\n", r); ap_rputs ("
\r\n", r); dump_identifiers (r); dump_strings (r); epilogue (r); } /*+ This routine is largely inspired by mod_format. +*/ static int all_handler(request_rec *r) { int len; if (r->method_number != M_GET) { r->allowed = M_GET; return DECLINED; } len = strlen (r->unparsed_uri); if (len > 4 && strcmp (&r->unparsed_uri[len-4], "?raw") == 0) return DECLINED; cfg = (color_dir_config *) ap_get_module_config (r->per_dir_config, &color_module); if (cfg == NULL) return DECLINED; if (!cfg->enable) return DECLINED; if (r->finfo.st_mode == 0) return NOT_FOUND; yyin = ap_pfopen (r->pool, r->filename, "r"); if (yyin == 0) { ap_log_reason ("file permissions deny server access", r->filename, r); return FORBIDDEN; } r->content_type = "text/html"; ap_soft_timeout ("send", r); ap_send_http_header (r); ap_rputs ("\n", r); ap_rputs ("\r\n", r); ap_rputs ("\r\n", r); ap_rputs (" ", r); emit (r, r->filename, 0, 0, 0, 0); ap_rputs ("\r\n", r); ap_rputs (" \r\n", r); ap_rputs (" \r\n", r); ap_rputs (" \r\n", r); ap_rputs ("\r\n", r); if (r->header_only) { ap_rputs ("\r\n", r); ap_kill_timeout (r); ap_pfclose (r->pool, yyin); return OK; } process_c (r); ap_rputs ("\r\n", r); ap_kill_timeout (r); ap_pfclose (r->pool, yyin); return OK; } static int c_handler(request_rec *r) { mode = 0; return all_handler (r); } static int lex_handler(request_rec *r) { mode = lex_definitions; return all_handler (r); } static int yacc_handler(request_rec *r) { mode = yacc_definitions; return all_handler (r); } static int perf_handler(request_rec *r) { mode = gperf_definitions; return all_handler (r); } /*+ +*/ static void *color_create_dir_config (pool *p, char *path) { color_dir_config *cfg = (color_dir_config *) ap_pcalloc (p, sizeof (color_dir_config)); cfg->p = p; cfg->enable = 1; cfg->color[T_PREPROCESSOR - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_COMMENT - T_EOF] = ap_pstrdup (p, "#333333"); cfg->color[T_S_LITERAL - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_C_LITERAL - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_I_LITERAL - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_R_LITERAL - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_KEYWORD - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_CPP_KEYWORD - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_STORAGE - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_IDENTIFIER - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_POSIX_IDENTIFIER - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_STD_IDENTIFIER - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_STORAGE - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_ASSIGNMENT - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_OPERATOR - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_L_PAREN - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_L_BRACKET - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_L_BRACE - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_SEMICOLON - T_EOF] = ap_pstrdup (p, "black"); cfg->color[T_SEPARATOR - T_EOF] = ap_pstrdup (p, "blue"); cfg->color[T_DEFINITION - T_EOF] = ap_pstrdup (p, "blue"); cfg->color[T_RULE - T_EOF] = ap_pstrdup (p, "blue"); cfg->style[T_PREPROCESSOR - T_EOF] = ap_pstrdup (p, "b"); cfg->style[T_COMMENT - T_EOF] = ap_pstrdup (p, "i"); cfg->style[T_S_LITERAL - T_EOF] = ap_pstrdup (p, "i"); cfg->style[T_C_LITERAL - T_EOF] = ap_pstrdup (p, "i"); cfg->style[T_I_LITERAL - T_EOF] = ap_pstrdup (p, ""); cfg->style[T_R_LITERAL - T_EOF] = ap_pstrdup (p, ""); cfg->style[T_KEYWORD - T_EOF] = ap_pstrdup (p, "b"); cfg->style[T_CPP_KEYWORD - T_EOF] = ap_pstrdup (p, "b"); cfg->style[T_STORAGE - T_EOF] = ap_pstrdup (p, "b"); cfg->style[T_IDENTIFIER - T_EOF] = ap_pstrdup (p, ""); cfg->style[T_POSIX_IDENTIFIER - T_EOF] = ap_pstrdup (p, ""); cfg->style[T_STD_IDENTIFIER - T_EOF] = ap_pstrdup (p, ""); cfg->style[T_STORAGE - T_EOF] = ap_pstrdup (p, "b"); cfg->style[T_ASSIGNMENT - T_EOF] = ap_pstrdup (p, "b"); cfg->style[T_OPERATOR - T_EOF] = ap_pstrdup (p, "b"); cfg->style[T_L_PAREN - T_EOF] = ap_pstrdup (p, ""); cfg->style[T_L_BRACKET - T_EOF] = ap_pstrdup (p, ""); cfg->style[T_L_BRACE - T_EOF] = ap_pstrdup (p, ""); cfg->style[T_SEMICOLON - T_EOF] = ap_pstrdup (p, ""); cfg->style[T_SEPARATOR - T_EOF] = ap_pstrdup (p, "b"); cfg->style[T_DEFINITION - T_EOF] = ap_pstrdup (p, "b"); cfg->style[T_RULE - T_EOF] = ap_pstrdup (p, "b"); cfg->face[T_PREPROCESSOR - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_COMMENT - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_S_LITERAL - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_C_LITERAL - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_I_LITERAL - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_R_LITERAL - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_KEYWORD - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_CPP_KEYWORD - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_STORAGE - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_IDENTIFIER - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_POSIX_IDENTIFIER - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_STD_IDENTIFIER - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_STORAGE - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_ASSIGNMENT - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_OPERATOR - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_L_PAREN - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_L_BRACKET - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_L_BRACE - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_SEMICOLON - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_SEPARATOR - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_DEFINITION - T_EOF] = ap_pstrdup (p, ""); cfg->face[T_RULE - T_EOF] = ap_pstrdup (p, ""); cfg->color[T_BACKGROUND - T_EOF] = ap_pstrdup (p, "white"); cfg->color[T_TEXT - T_EOF] = ap_pstrdup (p, "black"); return (void *) cfg; } static const char *cmd_disable (cmd_parms *parms, void *mconfig) { color_dir_config *cfg = (color_dir_config *) mconfig; cfg->enable = 0; return NULL; } static const char *cmd_enable (cmd_parms *parms, void *mconfig) { color_dir_config *cfg = (color_dir_config *) mconfig; cfg->enable = 1; return NULL; } static const char *cmd_set_color (cmd_parms *parms, void *mconfig, char *color) { color_dir_config *cfg = (color_dir_config *) mconfig; cfg->color[(int)parms->cmd->cmd_data - T_EOF] = ap_pstrdup (cfg->p, color); return NULL; } static const char *cmd_set_style (cmd_parms *parms, void *mconfig, char *style) { color_dir_config *cfg = (color_dir_config *) mconfig; cfg->style[(int)parms->cmd->cmd_data - T_EOF] = ap_pstrdup (cfg->p, style); return NULL; } static const char *cmd_set_face (cmd_parms *parms, void *mconfig, char *face) { color_dir_config *cfg = (color_dir_config *) mconfig; cfg->face[(int)parms->cmd->cmd_data - T_EOF] = ap_pstrdup (cfg->p, face); return NULL; } /* Dispatch list of command handlers */ static const command_rec color_cmds[] = { { "Color-Enable", cmd_enable, NULL, OR_ALL, NO_ARGS, "enable processing" }, { "Color-Disable", cmd_disable, NULL, OR_ALL, NO_ARGS, "disable processing" }, { "Color-Preprocessor-Color", cmd_set_color, (void *) T_PREPROCESSOR, OR_ALL, TAKE1, "display color for preprocessor commands" }, { "Color-Comment-Color", cmd_set_color, (void *) T_COMMENT, OR_ALL, TAKE1, "display color for comments" }, { "Color-String-Color", cmd_set_color, (void *) T_S_LITERAL, OR_ALL, TAKE1, "display color for string literals" }, { "Color-Character-Color", cmd_set_color, (void *) T_C_LITERAL, OR_ALL, TAKE1, "display color for character literals" }, { "Color-Integer-Color", cmd_set_color, (void *) T_I_LITERAL, OR_ALL, TAKE1, "display color for integral literals" }, { "Color-Real-Color", cmd_set_color, (void *) T_R_LITERAL, OR_ALL, TAKE1, "display color for floating point literals" }, { "Color-Keyword-Color", cmd_set_color, (void *) T_KEYWORD, OR_ALL, TAKE1, "display color for most C keywords" }, { "Color-C++-Keyword-Color", cmd_set_color, (void *) T_CPP_KEYWORD, OR_ALL, TAKE1, "display color for C++ keywords" }, { "Color-Storage-Color", cmd_set_color, (void *) T_STORAGE, OR_ALL, TAKE1, "display color for storage class keywords" }, { "Color-Identifier-Color", cmd_set_color, (void *) T_IDENTIFIER, OR_ALL, TAKE1, "display color for most identifiers" }, { "Color-POSIX-Identifier-Color", cmd_set_color, (void *) T_POSIX_IDENTIFIER, OR_ALL, TAKE1, "display color for POSIX identifiers (if supported)" }, { "Color-Standard-Identifier-Color", cmd_set_color, (void *) T_STD_IDENTIFIER, OR_ALL, TAKE1, "display color for standard identifiers (if supported)" }, { "Color-Assignment-Color", cmd_set_color, (void *) T_ASSIGNMENT, OR_ALL, TAKE1, "display color for assignment operators" }, { "Color-Operator-Color", cmd_set_color, (void *) T_OPERATOR, OR_ALL, TAKE1, "display color for non-assignment operators" }, { "Color-Parentheses-Color", cmd_set_color, (void *) T_L_PAREN, OR_ALL, TAKE1, "display color for parentheses" }, { "Color-Bracket-Color", cmd_set_color, (void *) T_L_BRACKET, OR_ALL, TAKE1, "display color for brackets" }, { "Color-Brace-Color", cmd_set_color, (void *) T_L_BRACE, OR_ALL, TAKE1, "display color for braces" }, { "Color-Semicolon-Color", cmd_set_color, (void *) T_SEMICOLON, OR_ALL, TAKE1, "display color for semicolons and commas" }, { "Color-Separator-Color", cmd_set_color, (void *) T_SEPARATOR, OR_ALL, TAKE1, "display color for yacc/lex separators" }, { "Color-Definition-Color", cmd_set_color, (void *) T_DEFINITION, OR_ALL, TAKE1, "display color for yacc/lex definitions" }, { "Color-Rule-Color", cmd_set_color, (void *) T_RULE, OR_ALL, TAKE1, "display color for yacc/lex definitions" }, { "Color-Preprocessor-Style", cmd_set_style, (void *) T_PREPROCESSOR, OR_ALL, TAKE1, "display style for preprocessor commands" }, { "Color-Comment-Style", cmd_set_style, (void *) T_COMMENT, OR_ALL, TAKE1, "display style for comments" }, { "Color-String-Style", cmd_set_style, (void *) T_S_LITERAL, OR_ALL, TAKE1, "display style for string literals" }, { "Color-Character-Style", cmd_set_style, (void *) T_C_LITERAL, OR_ALL, TAKE1, "display style for character literals" }, { "Color-Integer-Style", cmd_set_style, (void *) T_I_LITERAL, OR_ALL, TAKE1, "display style for integral literals" }, { "Color-Real-Style", cmd_set_style, (void *) T_R_LITERAL, OR_ALL, TAKE1, "display style for floating point literals" }, { "Color-Keyword-Style", cmd_set_style, (void *) T_KEYWORD, OR_ALL, TAKE1, "display style for most C keywords" }, { "Color-C++-Keyword-Style", cmd_set_style, (void *) T_CPP_KEYWORD, OR_ALL, TAKE1, "display style for C++ keywords" }, { "Color-Storage-Style", cmd_set_style, (void *) T_STORAGE, OR_ALL, TAKE1, "display style for storage class keywords" }, { "Color-Identifier-Style", cmd_set_style, (void *) T_IDENTIFIER, OR_ALL, TAKE1, "display style for most identifiers" }, { "Color-POSIX-Identifier-Style", cmd_set_style, (void *) T_POSIX_IDENTIFIER, OR_ALL, TAKE1, "display style for POSIX identifiers (if supported)" }, { "Color-Standard-Identifier-Style", cmd_set_style, (void *) T_STD_IDENTIFIER, OR_ALL, TAKE1, "display style for standard identifiers (if supported)" }, { "Color-Assignment-Style", cmd_set_style, (void *) T_ASSIGNMENT, OR_ALL, TAKE1, "display style for assignment operators" }, { "Color-Operator-Style", cmd_set_style, (void *) T_OPERATOR, OR_ALL, TAKE1, "display style for non-assignment operators" }, { "Color-Parentheses-Style", cmd_set_style, (void *) T_L_PAREN, OR_ALL, TAKE1, "display style for parentheses" }, { "Color-Bracket-Style", cmd_set_style, (void *) T_L_BRACKET, OR_ALL, TAKE1, "display style for brackets" }, { "Color-Brace-Style", cmd_set_style, (void *) T_L_BRACE, OR_ALL, TAKE1, "display style for braces" }, { "Color-Semicolon-Style", cmd_set_style, (void *) T_SEMICOLON, OR_ALL, TAKE1, "display style for semicolons and commas" }, { "Color-Separator-Style", cmd_set_style, (void *) T_SEPARATOR, OR_ALL, TAKE1, "display style for yacc/lex separators" }, { "Color-Definition-Style", cmd_set_style, (void *) T_DEFINITION, OR_ALL, TAKE1, "display style for yacc/lex definitions" }, { "Color-Rule-Style", cmd_set_style, (void *) T_RULE, OR_ALL, TAKE1, "display style for yacc/lex definitions" }, { "Color-Preprocessor-Face", cmd_set_face, (void *) T_PREPROCESSOR, OR_ALL, TAKE1, "display face for preprocessor commands" }, { "Color-Comment-Face", cmd_set_face, (void *) T_COMMENT, OR_ALL, TAKE1, "display face for comments" }, { "Color-String-Face", cmd_set_face, (void *) T_S_LITERAL, OR_ALL, TAKE1, "display face for string literals" }, { "Color-Character-Face", cmd_set_face, (void *) T_C_LITERAL, OR_ALL, TAKE1, "display face for character literals" }, { "Color-Integer-Face", cmd_set_face, (void *) T_I_LITERAL, OR_ALL, TAKE1, "display face for integral literals" }, { "Color-Real-Face", cmd_set_face, (void *) T_R_LITERAL, OR_ALL, TAKE1, "display face for floating point literals" }, { "Color-Keyword-Face", cmd_set_face, (void *) T_KEYWORD, OR_ALL, TAKE1, "display face for most C keywords" }, { "Color-C++-Keyword-Face", cmd_set_face, (void *) T_CPP_KEYWORD, OR_ALL, TAKE1, "display face for C++ keywords" }, { "Color-Storage-Face", cmd_set_face, (void *) T_STORAGE, OR_ALL, TAKE1, "display face for storage class keywords" }, { "Color-Identifier-Face", cmd_set_face, (void *) T_IDENTIFIER, OR_ALL, TAKE1, "display face for most identifiers" }, { "Color-POSIX-Identifier-Face", cmd_set_face, (void *) T_POSIX_IDENTIFIER, OR_ALL, TAKE1, "display face for POSIX identifiers (if supported)" }, { "Color-Standard-Identifier-Face", cmd_set_face, (void *) T_STD_IDENTIFIER, OR_ALL, TAKE1, "display face for standard identifiers (if supported)" }, { "Color-Assignment-Face", cmd_set_face, (void *) T_ASSIGNMENT, OR_ALL, TAKE1, "display face for assignment operators" }, { "Color-Operator-Face", cmd_set_face, (void *) T_OPERATOR, OR_ALL, TAKE1, "display face for non-assignment operators" }, { "Color-Parentheses-Face", cmd_set_face, (void *) T_L_PAREN, OR_ALL, TAKE1, "display face for parentheses" }, { "Color-Bracket-Face", cmd_set_face, (void *) T_L_BRACKET, OR_ALL, TAKE1, "display face for brackets" }, { "Color-Brace-Face", cmd_set_face, (void *) T_L_BRACE, OR_ALL, TAKE1, "display face for braces" }, { "Color-Semicolon-Face", cmd_set_face, (void *) T_SEMICOLON, OR_ALL, TAKE1, "display face for semicolons and commas" }, { "Color-Separator-Face", cmd_set_face, (void *) T_SEPARATOR, OR_ALL, TAKE1, "display face for yacc/lex separators" }, { "Color-Definition-Face", cmd_set_face, (void *) T_DEFINITION, OR_ALL, TAKE1, "display face for yacc/lex definitions" }, { "Color-Rule-Face", cmd_set_face, (void *) T_RULE, OR_ALL, TAKE1, "display face for yacc/lex rules" }, { "Color-Background-Color", cmd_set_color, (void *) T_BACKGROUND, OR_ALL, TAKE1, "background color" }, { "Color-Text-Color", cmd_set_color, (void *) T_TEXT, OR_ALL, TAKE1, "text color" }, { NULL } }; /* Dispatch list of content handlers */ /* For now, we only support a single language */ static const handler_rec color_handlers[] = { { "c-source", c_handler }, { "lex-source", lex_handler }, { "yacc-source", yacc_handler }, { "perf-source", perf_handler }, { NULL, NULL } }; /* Dispatch list for API hooks */ module MODULE_VAR_EXPORT color_module = { STANDARD_MODULE_STUFF, NULL, /* module initializer */ color_create_dir_config, /* create per-dir config structures */ NULL, /* merge per-dir config structures */ NULL, /* create per-server config structures */ NULL, /* merge per-server config structures */ color_cmds, /* table of config file commands */ color_handlers, /* [#8] MIME-typed-dispatched handlers */ NULL, /* [#1] URI to filename translation */ NULL, /* [#4] validate user id from request */ NULL, /* [#5] check if the user is ok _here_ */ NULL, /* [#3] check access by host address */ NULL, /* [#6] determine MIME type */ NULL, /* [#7] pre-run fixups */ NULL, /* [#9] log a transaction */ NULL, /* [#2] header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* [#0] post read-request */ #ifdef EAPI ,NULL, /* EAPI: add_module */ NULL, /* EAPI: remove_module */ NULL, /* EAPI: rewrite_command */ NULL /* EAPI: new_connection */ #endif };