Code:
[/color]reen]#include <stdio.h>
[/color]reen]#include <stdlib.h>
[/color]reen]#include <string.h>
[/color]reen]#define VERSION 103
[/color]reen]#define STRINGLEN 100
[/color]reen]#define LINELEN 1000
/* what goes before and after everything else in the file */
const char startend[2][STRINGLEN] = {
"[ c o d e ]\n",
"[ / c o d e ]\n"
};
/* what surrounds each keyword */
const char surround[3][STRINGLEN] = {
"[color=", /* before keyword*/
"]", /* after colour */
""[/color], /* after keyword */
};
/* the valid keywords with their colours */
const char keyword[][STRINGLEN] = {
"void", "blue",
"char", "blue",
"short", "blue",
"int", "blue",
"long", "blue",
"float", "blue",
"double", "blue",
"unsigned", "blue",
"signed", "blue",
"sizeof", "blue",
"const", "blue",
"volatile", "blue",
"static", "blue",
"auto", "blue",
"while", "blue",
"do", "blue",
"for", "blue",
"if", "blue",
"else", "blue",
"continue", "blue",
"break", "blue",
"return", "blue",
"switch", "blue",
"case", "blue",
"default", "blue",
"goto", "blue",
"struct", "blue",
"union", "blue",
"enum", "blue",
"typedef", "blue",
""
};
/* like keywords, except don't worry about these in the middle of a word */
const char unkeyword[][STRINGLEN] = {
"[", "pink",
"]", "pink",
""
};
/* characters to search for (and replace with) */
const char sreplace[][STRINGLEN] = {
"{", "{",
"}", "}",
"#", "#",
"[", "[",
"]", "]",
"{", "{",
"}", "}",
"[", "[",
"]", "]",
"#", "#",
"\", "\\",
"^", "^",
"|", "|",
"~", "~",
"<", "<",
">", ">",
"[ c o d e ]", "[ c o d e ]",
"[ / c o d e ]", "[ / c o d e ]",
""
};
/* the valid single-line comments */
const char slcomment[][STRINGLEN] = {
olor][color=green]//", "green",
"#", "green",
""
};
/* the multi-line comment[s] */
const char mlcomment[][STRINGLEN] = {
"/*", "*/", "green",
""
};
/* the strings (same as multiline-comments, but with backslash checking) */
const char mlstring[100][STRINGLEN] = {
"\"", "\"", "red",
"'", "'", "red",
""
};
/* colour of numbers */
const char numbercol[STRINGLEN] = {
"darkblue"
};
/* what a newline is replaced with */
const char newline[STRINGLEN] = {
"\n"
};
enum mode_t {
MODE_NORMAL,
MODE_STRING,
MODE_MULTILINE,
};
enum loop_t {
LOOP_NORMAL,
LOOP_CONTINUE,
LOOP_BREAK
};
FILE *get_input_file(void);
FILE *get_output_file(void);
FILE *open_input_file(char *s);
FILE *open_output_file(char *s);
void parse_file(FILE *fp, FILE *out);
void parse_line(char *s, FILE *out);
enum loop_t mode_multiline(char **s, FILE *out, enum mode_t *mode, int whichml);
enum loop_t mode_string(char **s, FILE *out, enum mode_t *mode, char *start, int whichml);
enum loop_t find_keywords(char **s, FILE *out, int before);
enum loop_t find_unkeywords(char **s, FILE *out);
int is_usage(char *s);
int print_usage(void);
void chomp(char *s);
int main(int argc, char *argv[]) {
FILE *fp, *out = stdout;
if(argc == 1) {
if(!(fp=get_input_file())) return 1;
if(!(out=get_output_file())) return 1;
}
else {
if(is_usage(argv[1])) return print_usage();
if(!(fp=open_input_file(argv[1]))) return 1;
if(argc == 3 && !(out=open_output_file(argv[2]))) return 1;
}
parse_file(fp, out);
fclose(fp);
return 0;
}
FILE *get_input_file(void) {
char s[STRINGLEN];
FILE *fp;
printf("\nEnter the name of the input file:\n");
fgets(s, sizeof(s), stdin);
chomp(s);
if(!(fp=open_input_file(s))) return 0;
return fp;
}
FILE *get_output_file(void) {
char s[STRINGLEN];
FILE *fp;
printf("\nEnter the name of the output file (blank for screen):\n");
fgets(s, sizeof(s), stdin);
chomp(s);
if(!*s) return stdout;
if(!(fp=open_output_file(s))) return 0;
return fp;
}
FILE *open_input_file(char *s) {
FILE *fp;
if((fp=fopen(s, "rt")) == NULL) {
fprintf(stderr, "Can't open input file\n");
return 0;
}
return fp;
}
FILE *open_output_file(char *s) {
FILE *fp;
if((fp=fopen(s, "rt")) != NULL) {
fclose(fp);
fprintf(stderr, "Output file already exists. Overwrite? (Y/N) ");
if(tolower(getchar()) != 'y') return 0;
}
if((fp=fopen(s, "wt")) == NULL) {
fprintf(stderr, "Can't open output file\n");
return 0;
}
return fp;
}
void parse_file(FILE *fp, FILE *out) {
char s[LINELEN], t[LINELEN], *p, *tp;
int x, y, hasnl;
size_t len;
fputs(startend[0], out);
while(!feof(fp)) {
s[0] = 0;
fgets(s, sizeof(s), fp);
hasnl = (strchr(s, '\n')?1:0);
chomp(s);
if(!*s) {
if(hasnl) fputs(newline, out);
continue;
}
for(x = 0; sreplace[x*2][0]; x ++) {
if(p=strstr(s, sreplace[x*2])) {
strcpy(t, p+strlen(sreplace[x*2]));
strncpy(p, sreplace[x*2+1], strlen(sreplace[x*2+1]));
for(y = p-s+strlen(sreplace[x*2+1]), tp = t; *tp; y ++) {
s[y] = *tp++;
}
s[y] = 0;
x = 0; continue;
}
}
parse_line(s, out);
if(hasnl) fputs(newline, out);
}
fputs(startend[1], out);
}
void parse_line(char *s, FILE *out) {
int x;
char *start = s;
static enum mode_t mode = MODE_NORMAL;
static int whichml, before = 1;
while(*s) {
if(mode == MODE_MULTILINE) {
if(mode_multiline(&s, out, &mode, whichml) == LOOP_CONTINUE) continue;
else break;
}
else if(mode == MODE_STRING) {
if(mode_string(&s, out, &mode, start, whichml) == LOOP_CONTINUE) continue;
else break;
}
for(x = 0; mlstring[x*3][0]; x ++) {
if(strncmp(s, mlstring[x*3], strlen(mlstring[x*3])) == 0) {
fputs(surround[0], out);
fputs(mlstring[x*3+2], out);
fputs(surround[1], out);
fputc(*s++, out);
mode = MODE_STRING;
whichml = x;
break;
}
}
if(mlstring[x*3][0]) continue;
for(x = 0; mlcomment[x*3][0]; x ++) {
if(strncmp(s, mlcomment[x*3], strlen(mlcomment[x*3])) == 0) {
fputs(surround[0], out);
fputs(mlcomment[2], out);
fputs(surround[1], out);
mode = MODE_MULTILINE;
whichml = x;
break;
}
}
if(mlcomment[x*3][0]) continue;
if(find_unkeywords(&s, out) == LOOP_CONTINUE) continue;
if(find_keywords(&s, out, before) == LOOP_CONTINUE) continue;
for(x = 0; slcomment[x*2][0]; x ++) {
if(strncmp(s, slcomment[x*2], strlen(slcomment[x*2])) == 0) {
fputs(surround[0], out);
fputs(slcomment[x*2+1], out);
fputs(surround[1], out);
fputs(s, out);
fputs(surround[2], out);
break;
}
}
if(slcomment[x*2][0]) break;
if(before && isdigit(*s)) {
fputs(surround[0], out);
fputs(numbercol, out);
fputs(surround[1], out);
while(isalnum(*s)) fputc(*s++, out);
fputs(surround[2], out);
continue;
}
before = !isalnum(*s);
fputc(*s++, out);
}
}
enum loop_t mode_multiline(char **s, FILE *out, enum mode_t *mode, int whichml) {
char *p, *t;
if(p=strstr(*s, mlcomment[whichml*3+1])) {
for(t = *s; t != p+2; fputc(*t++, out)) ;
fputs(surround[2], out);
*s = t;
*mode = MODE_NORMAL;
return LOOP_CONTINUE;
}
else fputs(*s, out);
return LOOP_BREAK;
}
enum loop_t mode_string(char **s, FILE *out, enum mode_t *mode, char *start, int whichml) {
char *p, *t;
if(**s) {
p = *s;
do {
p = strstr(p==*s?p:p+1, mlstring[whichml*3+1]);
} while(p && *(p-1) == '\\' && !(p == start ||
(*(p-1) != '\\' || (p-1 != start && *(p-2) == '\\'))) );
}
else return LOOP_BREAK;
if(!p) {
fputs(*s, out);
return LOOP_BREAK;
}
for(t = *s; t != p+1; fputc(*t++, out)) ;
fputs(surround[2], out);
*s = t;
*mode = MODE_NORMAL;
return LOOP_CONTINUE;
}
enum loop_t find_keywords(char **s, FILE *out, int before) {
int x;
size_t len;
for(x = 0; keyword[x*2][0]; x ++) {
len = strlen(keyword[x*2]);
if(strncmp(*s, keyword[x*2], len) == 0
&& before && (!*(*s+len) || !isalnum(*(*s+len)))) {
fputs(surround[0], out);
fputs(keyword[x*2+1], out);
fputs(surround[1], out);
fputs(keyword[x*2], out);
fputs(surround[2], out);
*s += len;
break;
}
}
return keyword[x*2][0] ? LOOP_CONTINUE : LOOP_NORMAL;
}
enum loop_t find_unkeywords(char **s, FILE *out) {
int x;
size_t len;
for(x = 0; unkeyword[x*2][0]; x ++) {
len = strlen(unkeyword[x*2]);
if(strncmp(*s, unkeyword[x*2], len) == 0) {
fputs(surround[0], out);
fputs(unkeyword[x*2+1], out);
fputs(surround[1], out);
fputs(unkeyword[x*2], out);
fputs(surround[2], out);
*s += len;
break;
}
}
return unkeyword[x*2][0] ? LOOP_CONTINUE : LOOP_NORMAL;
}
int is_usage(char *s) {
if(strcmp(s, "-?") == 0
|| strcmp(s, "-h") == 0
|| strcmp(s, "-v") == 0
|| strcmp(s, "--help") == 0
|| strcmp(s, "--version") == 0) return 1;
return 0;
}
int print_usage(void) {
printf("\ncodeform v%i.%02i by DWK\n", VERSION/100, VERSION%100);
printf("\nusage: codeform [infile [outfile]]\n");
printf("\nIf no arguments are specified, you are prompted for both.");
printf("\nIf no outfile is specified, the screen is used instead.\n");
printf("\ncodeform formats your code in nice colours.\n");
return 0;
}
void chomp(char *s) {
while(*s && *s != '\n') s++;
*s = 0;
}
It's not fully modularized yet. I can get it to produce HTML output just by changing the vars at the top.