#include #include #include #include #include "chad.h" #include "regex.h" // ------------------- // ### Definitions ### // ------------------- typedef void (*attribute_callback_t)(const char * const string, const int length, void * const attributes); typedef struct { char * key; attribute_callback_t callback; UT_hash_handle hh; } display_t; display_t * display_table = NULL; typedef struct { void * attributes; struct hl_group_t * link; } hl_group_t; typedef enum { KEYSYMBOL, KEYWORD, MATCH, REGION } token_type_t; typedef struct { hl_group_t * hl; token_type_t t; char* syntax; } token_t; /* Temp solution * this should be dynamic */ token_t * token_table[1000]; int token_table_top = 0; // -------------------------------- // ### Constructors/Destructors ### // -------------------------------- void new_display_mode(display_t * mode) { HASH_ADD_STR(display_table, key, mode); } int free_token(token_t * token){ /* XXX: since hl could be shared, * this might free an already freed object * when invoked from a loop */ free(token->hl); free(token->syntax); return 0; } int append_token(token_t * token){ token_table[token_table_top++] = token; return 0; } token_t * new_symbol_token(const char * const word, hl_group_t * const g) { char * new_word = strdup(word); token_t * mt = (token_t*)malloc(sizeof(token_t)); mt->hl = g; mt->t = KEYSYMBOL; mt->syntax = new_word; append_token(mt); return mt; } int new_symbol_tokens(const char * const * symbols, hl_group_t * const g) { int i = 0; while (*symbols) { if(new_symbol_token(*symbols, g)){ ++i; } ++symbols; } return i; } int new_char_tokens(const char * characters, hl_group_t * const g) { int i = 0; char buffer[2]; buffer[1] = '\00'; for(const char * s = characters; *s != '\00'; s++){ buffer[0] = *s; if(new_symbol_token(buffer, g)){ ++i; } } return i; } token_t * new_keyword_token(const char * const word, hl_group_t * const g) { size_t word_length = strlen(word); char * new_word = (char*)malloc(word_length + 4 + 1); memcpy(new_word, "\\<", 2); memcpy(new_word + 2, word, word_length); strcpy(new_word + 2 + word_length, "\\>"); token_t * mt = (token_t*)malloc(sizeof(token_t)); mt->hl = g; mt->t = KEYWORD; mt->syntax = new_word; append_token(mt); return mt; } int new_keyword_tokens(const char * const * words, hl_group_t * const g) { int i = 0; while (*words) { if(new_keyword_token(*words, g)){ ++i; } ++words; } return i; } token_t * new_token(const char * const word, const token_type_t t, hl_group_t * const g) { switch(t){ case KEYSYMBOL: { return new_symbol_token(word, g); }; case KEYWORD: { return new_keyword_token(word, g); }; case MATCH: { } break; case REGION: { } break; } // XXX: implement the rest return NULL; } // -------------------- // ### Highlighting ### // -------------------- int token_fits(const token_t * const token, const char * const to, const int string_offset, int * match_offset) { const char * const pattern = token->syntax; if (pattern == NULL) { return true; } return regex_match(pattern, to, string_offset, match_offset); } void render_string(const char * const string, const char * const mode) { for (const char * s = string; *s != '\00';) { int f; int token_index = 0; int offset; for (; token_index < token_table_top; token_index++) { f = token_fits(token_table[token_index], string, s - string, &offset); if(f){ break; } } // display_t * display; HASH_FIND_STR(display_table, mode, display); // if (f) { for(int i = 0; i < offset; i++){ display->callback(s + i, 0, token_table[token_index]->hl->attributes); } display->callback(s + offset, f, token_table[token_index]->hl->attributes); s += f + offset; } else { display->callback(s, 0, NULL); ++s; } } } // ------------------------- // ### Library Mangement ### // ------------------------- int hl_init(void) { return 0; } int hl_deinit(void) { for(int i = 0; i < token_table_top; i++){ free_token(token_table[i]); } return 0; }