/* * BBCode 2 HTML converter by //YorHel * Copyright 2006 Y.Heling, * License: MIT * * Created just to learn C, probably very ugly piece of code * and probably with a _LOT_ of bugs... But the only way to * learn a programming language is to code something yourself :) */ #include #include #include #include #define MAX_ARGH_SIZE 500 #define MAX_TAG_SIZE 10 #define MAX_NESTED_TAGS 100 #define TAGCHARS 28 #define NUMBER_OF_TAGS 16 #define TRUE 1 #define FALSE 0 /* typedefs */ typedef enum { B, I, U, SIZE, COLOR, URL, QUOTE, QUOTE2, IMG, IMG2, EMAIL, LIST, LIST2, CODE, HTML, UNDEF, /* hack */ } TAGNAME; typedef struct { TAGNAME intags[MAX_NESTED_TAGS]; int curtag; char tag[MAX_TAG_SIZE]; char argh[MAX_ARGH_SIZE]; FILE *dest; int inlist; int liststart; } PARSEINFO; /* just a hack to prevent the use of global variables */ typedef struct { char *bb; char *html_s; char *html_e; char arg; } TAGINFO; /* store global information about the tags */ /* functions */ void parsebbcode(FILE *, FILE *); void converttag(PARSEINFO *); void formattag(PARSEINFO *); char endtags(PARSEINFO *, TAGNAME); void convertchars(PARSEINFO *, const char *); void convertchar(PARSEINFO *, const int); void convertchararg(char *, int); char istagchar(const int); void err(const char *); /* global vars (only consts!) */ const char tagchars[TAGCHARS] = "abcdefghijklmnopqrstuvwxyz/*"; const TAGINFO taglist[NUMBER_OF_TAGS] = { /* same order as TAGNAME! */ { "b", "", "", FALSE }, { "i", "", "", FALSE }, { "u", "", "", FALSE }, { "size", "", "", TRUE }, { "color", "", "", TRUE }, { "url", "", "", TRUE }, { "quote", "Quote: ", "", FALSE }, { "quote", "%s wrote: ", "", TRUE }, { "img", "\"\"", FALSE }, { "img", "\"",", TRUE }, { "email", "", "", TRUE }, { "list", "
    ", "
", FALSE }, { "list", "
    ", "
", TRUE }, { "code", "Code: ", "", FALSE }, { "html", "", "", FALSE }, { "", "", "", FALSE }, }; /* NOTE: not all characteristics of the BBCodes are defined above, there is also a lot of hard-coded stuff below for a few tags */ int main() { /* printf("BBCode to HTML converter by //YorHel\n"); printf("Copyright 2006 Y. Heling\n\n"); printf("* Reading & parsing bbcode...\n"); while(1) { FILE *file; if((file = fopen(BBFILE, "r")) == NULL) err("Couldn't open BBFILE"); parsebbcode(file, stdout); fclose(file); } printf("\n");*/ parsebbcode(stdin, stdout); return 0; } void parsebbcode(FILE *file, FILE *dest) { PARSEINFO pitemp; /* make sure we allocate the memory */ PARSEINFO *pi = &pitemp; /* but we are still going to use a pointer */ char intag = pi->inlist = pi->liststart = 0; pi->curtag = 1; pi->intags[0] = UNDEF; sprintf(pi->tag, ""); sprintf(pi->argh, ""); pi->dest = dest; int c; char tmp[MAX_TAG_SIZE+MAX_ARGH_SIZE+4]; /* temp string, should be able to hold anything necessary */ while((c = fgetc(file)) && c != EOF) { if(intag == 0 && c == '[') { intag = 1; } else if(intag == 1 && c == '=') intag = -1; else if(intag != 0 && c == ']') { intag = 0; converttag(pi); sprintf(pi->tag, ""); sprintf(pi->argh, ""); } else if(intag == 1 && strlen(pi->tag) < sizeof(pi->tag)) { if(istagchar(c)) { sprintf(tmp, "%c", tolower(c)); strcat(pi->tag, tmp); } else { sprintf(tmp, "[%s", pi->tag); convertchars(pi, tmp); sprintf(pi->tag, ""); } } else if(intag == 1) { intag = 0; sprintf(tmp, "[%s", pi->tag); convertchars(pi, tmp); sprintf(pi->tag, ""); } else if(intag == -1 && (strlen(pi->argh)+10) < sizeof(pi->argh)) { convertchararg(tmp, c); strcat(pi->argh, tmp); } else if(intag == -1) { sprintf(tmp, "[%s=%s", pi->tag, pi->argh); convertchars(pi, tmp); sprintf(pi->tag, ""); sprintf(pi->argh, ""); intag = 0; } else convertchar(pi, c); } /* some stuff left in the buffer */ if(strlen(pi->tag) > 0 && strlen(pi->argh) == 0) fprintf(dest, "[%s", pi->tag); else if(strlen(pi->tag) > 0 && strlen(pi->argh) > 0) fprintf(dest, "[%s=%s", pi->tag, pi->argh); /* automatically close opened tags */ endtags(pi, UNDEF); } void converttag(PARSEINFO *pi) { /* ignore tag if we're not allowed to nest */ if((pi->intags[pi->curtag] == CODE && strcmp(pi->tag, "/code") != 0) || (pi->intags[pi->curtag] == HTML && strcmp(pi->tag, "/html") != 0) || ((pi->intags[pi->curtag] == IMG || pi->intags[pi->curtag] == IMG2) && strcmp(pi->tag, "/img"))) { formattag(pi); return; } /* parse list items */ if(!strcmp(pi->tag, "*") && pi->inlist) { endtags(pi, LIST); if(pi->inlist == pi->liststart) fprintf(pi->dest, ""); else pi->liststart = pi->inlist; fprintf(pi->dest, "
  • "); return; /* no need to parse more */ } /* begin a tag */ if(*pi->tag != '/') { int i; int got = -1; for(i=0 ; itag, taglist[i].bb)) { got = i; if(strlen(pi->argh) == 0 && !taglist[i].arg) fprintf(pi->dest, "%s", taglist[i].html_s); else if(strlen(pi->argh) > 0 && taglist[i].arg) { if(i != LIST2) fprintf(pi->dest, taglist[i].html_s, pi->argh); else fprintf(pi->dest, taglist[i].html_s, strcmp(pi->argh, "1") ? "lower-roman" : "decimal"); } else got = -1; }; if(got != -1) { pi->intags[++pi->curtag] = got; if(got == LIST || got == LIST2) pi->inlist++; } else formattag(pi); return; } /* end a tag */ else { char *tag = pi->tag+1; /* strip the '/' */ int i; char got = FALSE; for(i=0 ; idest, "%s", taglist[i].html_e); if(pi->intags[pi->curtag] == LIST || pi->intags[pi->curtag] == LIST2) pi->liststart = --pi->inlist; pi->curtag--; got = TRUE; }; if(!got) formattag(pi); } } char endtags(PARSEINFO *pi, TAGNAME to) { char s = FALSE; if(to == QUOTE || to == LIST || to == IMG) s = TRUE; else if(to == QUOTE2 || to == LIST2 || to == IMG2) { s = TRUE; to--; } int i = pi->curtag; if(to != UNDEF) while(pi->intags[i] != to && (!s || pi->intags[i] != to+1) && i > 0) i--; if(i) { while(pi->intags[pi->curtag] != to && (!s || pi->intags[pi->curtag] != (to+1)) && pi->curtag > 0) { if(pi->intags[pi->curtag] == LIST || pi->intags[pi->curtag] == LIST2) pi->liststart = --pi->inlist; fprintf(pi->dest, "%s", taglist[pi->intags[pi->curtag--]].html_e); } return TRUE; } else return FALSE; } void formattag(PARSEINFO *pi) { char tmp[MAX_TAG_SIZE+MAX_ARGH_SIZE+4]; if(strlen(pi->argh) == 0) sprintf(tmp, "[%s]", pi->tag); else sprintf(tmp, "[%s=%s]", pi->tag, pi->argh); convertchars(pi, tmp); } void convertchars(PARSEINFO *pi, const char *chars) { int i; for(i=0;iinlist && pi->inlist != pi->liststart) return; else if(pi->intags[pi->curtag] == HTML) fprintf(pi->dest, "%c", c); else if(pi->intags[pi->curtag] == IMG || pi->intags[pi->curtag] == IMG2) { char tmp[10]; convertchararg(tmp, c); fprintf(pi->dest, tmp); } else if(c == '\n') fprintf(pi->dest, "
    \n"); else if(c == '&') fprintf(pi->dest, "&"); else if(c == '<') fprintf(pi->dest, "<"); else if(c == '>') fprintf(pi->dest, ">"); else fprintf(pi->dest, "%c", c); } void convertchararg(char *to, const int c) { switch(c) { case '\n' : sprintf(to, ""); break; case '&' : sprintf(to, "&"); break; case '"' : sprintf(to, """); break; default : sprintf(to, "%c", c); } } char istagchar(const int c) { int i; int c2 = tolower(c); for(i=0;i