/* ** Beaver's an Early AdVanced EditoR ** (C) 2003 Michael Terry ** ** oldsyhi.c ** ** Author: Michael Terry ** ** Description: syntax highlighting ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation; either version 2 of the License, or ** (at your option) any later version. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with this program; if not, write to the Free Software ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* further syhi optimizations : name tags, and if we are in a comment or string tag, don't do anything? */ /* ** NOTE_REMARK : syhi stands for SYntax HIghlighting, the main work to ** be accomplished by the code in this file */ /* ** In order to view debugging messages, define some of these macros */ //#define DEBUG_AUTO_INDENT //#define DEBUG_FCN //#define DEBUG_WORDFILE //#define DEBUG_EXT_REC //#define DEBUG_SYHI //#define DEBUG_CORRECT //#define DEBUG_HASHTABLE //#define DEBUG_FREEZE_THAW #include #include #include #include #include #include #include #include "oldsyhi.h" #include "struct.h" #include "msgbar.h" #include "tools.h" #include "main.h" #include "filesops.h" #include "interface.h" #include "undoredo.h" #include "conf.h" extern t_settings Settings; /* ** To access WidgetInfo, we need some external variables, and we do : ** FPROPS(gtk_notebook_get_current_page(GTK_NOTEBOOK(MainNotebook)), ** WidgetInfo.) */ extern GtkWidget *MainNotebook; extern GArray *FileProperties; /* preconditions: iter points to possible start of interesting word postconditions: end is set to the end of the word in the buffer if it was found. if word found, returns TRUE, else FALSE*/ inline gboolean starts_string (gchar *text, gint i, gchar *word, gint *end) { gunichar ch; gunichar k; gint j = 0; ch = text[i]; k = word[j]; while (ch && k) { if (ch != k) { return FALSE; } i++; ch = text[i]; j++; k = word[j]; } if (!ch && k) { return FALSE; } if (end) *end = i; return TRUE; } /* returns color index of match, or -1 if none */ inline gint is_matching_keyword (gint Lg, const gchar *str) { gint rv = -1; gpointer val; val = g_hash_table_lookup (Prefs.L[Lg].Hash, str); if (val) return GPOINTER_TO_INT (val) - 1; else return -1; return rv; } inline void refresh_markers (GtkTextBuffer *Buffer) { gint CurrentPage; gint Lg; GList *markers, *tmp; GtkTextIter start, end; START_FCN CurrentPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); Lg = FPROPS(CurrentPage, WidgetInfo.Lg); markers = FPROPS(CurrentPage, WidgetInfo.markers); /* get rid of old tags */ gtk_text_buffer_get_bounds (FPROPS(CurrentPage, Buffer), &start, &end); gtk_text_buffer_remove_tag (FPROPS(CurrentPage, Buffer), FPROPS(CurrentPage, WidgetInfo.string0_tag), &start, &end); gtk_text_buffer_remove_tag (FPROPS(CurrentPage, Buffer), FPROPS(CurrentPage, WidgetInfo.string1_tag), &start, &end); gtk_text_buffer_remove_tag (FPROPS(CurrentPage, Buffer), FPROPS(CurrentPage, WidgetInfo.comment_tag), &start, &end); gtk_text_buffer_remove_tag (FPROPS(CurrentPage, Buffer), FPROPS(CurrentPage, WidgetInfo.comment_alt_tag), &start, &end); /* go through list of markers, applying tags */ tmp = markers; while (tmp) { t_marker *m; gunichar ch; gboolean found = FALSE; m = (t_marker *) tmp->data; gtk_text_buffer_get_iter_at_mark (Buffer, &start, m->mark); switch (m->type) { case TypeString0: /* find next string0 */ tmp = tmp->next; while (tmp) { t_marker *m2; m2 = (t_marker *) tmp->data; if (m2->type == TypeString0) { found = TRUE; gtk_text_buffer_get_iter_at_mark (Buffer, &end, m2->mark); gtk_text_iter_forward_cursor_position (&end); break; } tmp = tmp->next; } if (!found) { gtk_text_buffer_get_end_iter (Buffer, &end); } gtk_text_buffer_apply_tag (Buffer, FPROPS(CurrentPage, WidgetInfo.string0_tag), &start, &end); break; case TypeString1: /* find next string1 */ tmp = tmp->next; while (tmp) { t_marker *m2; m2 = (t_marker *) tmp->data; if (m2->type == TypeString1) { found = TRUE; gtk_text_buffer_get_iter_at_mark (Buffer, &end, m2->mark); gtk_text_iter_forward_cursor_position (&end); break; } tmp = tmp->next; } if (!found) { gtk_text_buffer_get_end_iter (Buffer, &end); } gtk_text_buffer_apply_tag (Buffer, FPROPS(CurrentPage, WidgetInfo.string1_tag), &start, &end); break; case TypeBlockCommentOn: /* find next BlockCommentOff */ tmp = tmp->next; while (tmp) { t_marker *m2; m2 = (t_marker *) tmp->data; if (m2->type == TypeBlockCommentOff) { found = TRUE; gtk_text_buffer_get_iter_at_mark (Buffer, &end, m2->mark); gtk_text_iter_forward_chars (&end, strlen (Prefs.L[Lg].BlockCommentOff)); break; } tmp = tmp->next; } if (!found) { gtk_text_buffer_get_end_iter (Buffer, &end); } gtk_text_buffer_apply_tag (Buffer, FPROPS(CurrentPage, WidgetInfo.comment_tag), &start, &end); break; case TypeBlockCommentOnAlt: /* find next BlockCommentOffAlt*/ tmp = tmp->next; while (tmp) { t_marker *m2; m2 = (t_marker *) tmp->data; if (m2->type == TypeBlockCommentOffAlt) { found = TRUE; gtk_text_buffer_get_iter_at_mark (Buffer, &end, m2->mark); gtk_text_iter_forward_chars (&end, strlen (Prefs.L[Lg].BlockCommentOffAlt)); break; } tmp = tmp->next; } if (!found) { gtk_text_buffer_get_end_iter (Buffer, &end); } gtk_text_buffer_apply_tag (Buffer, FPROPS(CurrentPage, WidgetInfo.comment_alt_tag), &start, &end); break; case TypeLineComment: /* find next end of line */ end = start; do { gtk_text_iter_forward_cursor_position (&end); ch = gtk_text_iter_get_char (&end); } while (ch && (ch != '\n' && ch != '\r')); gtk_text_iter_forward_cursor_position (&end); tmp = tmp->next; while (tmp) { t_marker *m2; GtkTextIter iter; m2 = (t_marker *) tmp->data; gtk_text_buffer_get_iter_at_mark (Buffer, &iter, m2->mark); if (gtk_text_iter_compare (&iter, &end) >= 0) { // back up tmp = tmp->prev; break; } tmp = tmp->next; } gtk_text_buffer_apply_tag (Buffer, FPROPS(CurrentPage, WidgetInfo.comment_tag), &start, &end); break; case TypeLineCommentAlt: /* find next end of line */ end = start; do { gtk_text_iter_forward_cursor_position (&end); ch = gtk_text_iter_get_char (&end); } while (ch && (ch != '\n' && ch != '\r')); gtk_text_iter_forward_cursor_position (&end); tmp = tmp->next; while (tmp) { t_marker *m2; GtkTextIter iter; m2 = (t_marker *) tmp->data; gtk_text_buffer_get_iter_at_mark (Buffer, &iter, m2->mark); if (gtk_text_iter_compare (&iter, &end) >= 0) { // back up tmp = tmp->prev; break; } tmp = tmp->next; } gtk_text_buffer_apply_tag (Buffer, FPROPS(CurrentPage, WidgetInfo.comment_alt_tag), &start, &end); break; } if (tmp) tmp = tmp->next; } END_FCN } void search_for_keyword_correctly (gint page, GtkTextBuffer *Buffer, gchar *text, gint *i, gint offset, gint Lg) { /* search for a keyword */ gint tmp; gint next, prev, edge, possible = -1; gboolean last_was_delimiter; int color = -1; START_FCN next = *i; tmp = text[*i]; /* get to first useless char */ while (tmp && (Prefs.L[Lg].KeywordStatus[(int) tmp] & 1)) { next++; tmp = text[next]; } edge = prev = next; prev++; last_was_delimiter = FALSE; do { if ((last_was_delimiter || Prefs.L[Lg].IsADelimiter[tmp]) && Prefs.L[Lg].KeywordStatus[tmp] & 4) /* ends a keyword */ { gchar *stuff; /* let's get text including this char */ stuff = g_strndup (&text[*i], prev - *i); color = is_matching_keyword (Lg, stuff); g_free (stuff); if (color >= 0) { edge = prev; /* we found our match */ break; } } if (Prefs.L[Lg].IsADelimiter[tmp]) { if (next != *i && ((Prefs.L[Lg].KeywordStatus[tmp] & 2) || (Prefs.L[Lg].KeywordStatus[tmp] & 8))) { /* this starts some keywords, so we should come back to it if we can't find a match */ possible = next; } last_was_delimiter = TRUE; } else { last_was_delimiter = FALSE; } prev = next; next--; tmp = text[next]; } while (*i <= next); if (color != -1) { GtkTextIter start, end; /* apply tag */ gtk_text_buffer_get_iter_at_offset (Buffer, &start, offset + *i); gtk_text_buffer_get_iter_at_offset (Buffer, &end, offset + edge); gtk_text_buffer_apply_tag (Buffer, FPROPS (page, WidgetInfo.keyword_tags[color]), &start, &end); } else { if (possible >= 0) { edge = possible; } } *i = edge; END_FCN } inline void search_for_keyword_fastly (gint page, GtkTextBuffer *Buffer, gchar *text, gint *i, gint offset, gint Lg) { /* search for a keyword */ gint tmp, next; gboolean possibly_a_keyword = TRUE; int color = -1; gchar *key; START_FCN next = *i; tmp = text[next]; if (Prefs.L[Lg].IsADelimiter[tmp]) { if (Prefs.L[Lg].KeywordStatus[tmp] & 2) { /* check if this delimiter is itself a keyword. This is a work-around for coloring operators */ next++; } else { *i += 1; return; } } else { /* get to first useless char or delimiter */ while (tmp && !Prefs.L[Lg].IsADelimiter[tmp]) { if (!Prefs.L[Lg].KeywordStatus[tmp] & 1) { /* if we hit something that isn't in a keyword before we hit a delimiter, note it and stop */ possibly_a_keyword = FALSE; } next++; tmp = text[next]; } } if (possibly_a_keyword) { key = g_strndup (&text[*i], next - *i); color = is_matching_keyword (Lg, key); g_free (key); if (color != -1) { GtkTextIter start, end; /* apply tag */ gtk_text_buffer_get_iter_at_offset (Buffer, &start, offset + *i); gtk_text_buffer_get_iter_at_offset (Buffer, &end, offset + next); gtk_text_buffer_apply_tag (Buffer, FPROPS (page, WidgetInfo.keyword_tags[color]), &start, &end); } } *i = next; END_FCN } void search_for_keyword (gint page, GtkTextBuffer *Buffer, gchar *text, gint *i, gint offset, gint Lg) { /* the difference between searching fast or correct is that the fast search assumes no delimiters appear in keywords. Correct checks for this and also prefers the longest applicable match. HTML is the only big language right now that uses this, so we only do correct thing for HTML. */ if (Prefs.L[Lg].IsHTML) { search_for_keyword_correctly (page, Buffer, text, i, offset, Lg); } else { search_for_keyword_fastly (page, Buffer, text, i, offset, Lg); } } void markup_syhi_range (GtkTextBuffer *Buffer, GtkTextIter start, GtkTextIter end) { int CurrentPage; gint Lg, position, i, j; GList *markers, *tmp, *prev; gchar *text; GtkTextIter textiter; gboolean prev_set; gboolean last_was_escape; gboolean restart = FALSE; gboolean markers_changed = FALSE; GTimer *timer = g_timer_new (); START_FCN CurrentPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); Lg = FPROPS(CurrentPage, WidgetInfo.Lg); markers = FPROPS(CurrentPage, WidgetInfo.markers); text = gtk_text_iter_get_text (&start, &end); i = 0; #ifdef DEBUG_SYHI g_print(__FILE__": %s(): Language of file modified: /L%i \"%s\"\n", __func__, Lg + 1, Prefs.L[Lg].Description); { gchar *s; s = gtk_text_iter_get_text (&start, &end); g_print(__FILE__": Examining string \"%s\"\n", s); g_free (s); } #endif /* find place right before where we are in marker list, and delete all the markers between start and end*/ tmp = markers; prev = NULL; prev_set = FALSE; position = 0; while (tmp) { gtk_text_buffer_get_iter_at_mark (Buffer, &textiter, ((t_marker *) tmp->data)->mark); if (!prev && gtk_text_iter_compare (&textiter, &start) >= 0) { /* save previous marker */ prev = tmp->prev; prev_set = TRUE; } if (prev_set && gtk_text_iter_compare (&textiter, &end) <= 0) { GList *deleted; gtk_text_buffer_delete_mark (Buffer, ((t_marker *) tmp->data)->mark); deleted = tmp; tmp = tmp->next; markers = g_list_remove_link (markers, deleted); g_free (deleted->data); g_list_free_1 (deleted); markers_changed = TRUE; } else if (!prev_set) { tmp = tmp->next; position ++; } else break; } if (prev) position = g_list_position (markers, prev) + 1; else if (!markers) position = 0; gtk_text_buffer_remove_tag (Buffer, FPROPS(CurrentPage, WidgetInfo.number_tag), &start, &end); for (j = 0; j < MAX_COL; j++) { gtk_text_buffer_remove_tag (Buffer, FPROPS(CurrentPage, WidgetInfo.keyword_tags[j]), &start, &end); } last_was_escape = FALSE; g_timer_start (timer); while (text[i] && !restart) { gint ch; gint word_end; t_marker *m; gboolean scan = FALSE; ch = text[i]; if (Prefs.L[Lg].EscapeChar == ch) { i++; if (!last_was_escape) { last_was_escape = TRUE; continue; } } else if (Prefs.L[Lg].KeywordStatus[ch] & 8) { if (Prefs.L[Lg].HaveString && Prefs.L[Lg].StringChar0 != '\0' && Prefs.L[Lg].StringChar0 == ch) { if (last_was_escape) { i++; } else { GtkTextIter iter = start; m = g_malloc (sizeof (t_marker)); gtk_text_iter_forward_chars (&iter, i); m->mark = gtk_text_buffer_create_mark (Buffer, NULL, &iter, FALSE); m->type = TypeString0; markers = g_list_insert (markers, m, position++); markers_changed = TRUE; i++; } } else if (Prefs.L[Lg].HaveString && Prefs.L[Lg].StringChar1 != '\0' && Prefs.L[Lg].StringChar1 == ch) { if (last_was_escape) { i++; } else { GtkTextIter iter = start; m = g_malloc (sizeof (t_marker)); gtk_text_iter_forward_chars (&iter, i); m->mark = gtk_text_buffer_create_mark (Buffer, NULL, &iter, FALSE); m->type = TypeString1; markers = g_list_insert (markers, m, position++); markers_changed = TRUE; i++; } } else if (Prefs.L[Lg].LineComment != NULL && starts_string (text, i, Prefs.L[Lg].LineComment, &word_end)) { GtkTextIter iter = start; m = g_malloc (sizeof (t_marker)); gtk_text_iter_forward_chars (&iter, i); m->mark = gtk_text_buffer_create_mark (Buffer, NULL, &iter, FALSE); m->type = TypeLineComment; markers = g_list_insert (markers, m, position++); markers_changed = TRUE; i = word_end; } else if (Prefs.L[Lg].LineCommentAlt != NULL && starts_string (text, i, Prefs.L[Lg].LineCommentAlt, &word_end)) { GtkTextIter iter = start; m = g_malloc (sizeof (t_marker)); gtk_text_iter_forward_chars (&iter, i); m->mark = gtk_text_buffer_create_mark (Buffer, NULL, &iter, FALSE); m->type = TypeLineCommentAlt; markers = g_list_insert (markers, m, position++); markers_changed = TRUE; i = word_end; } else if (Prefs.L[Lg].BlockCommentOn != NULL && starts_string (text, i, Prefs.L[Lg].BlockCommentOn, &word_end)) { GtkTextIter iter = start; m = g_malloc (sizeof (t_marker)); gtk_text_iter_forward_chars (&iter, i); m->mark = gtk_text_buffer_create_mark (Buffer, NULL, &iter, FALSE); m->type = TypeBlockCommentOn; markers = g_list_insert (markers, m, position++); markers_changed = TRUE; i = word_end; } else if (Prefs.L[Lg].BlockCommentOnAlt != NULL && starts_string (text, i, Prefs.L[Lg].BlockCommentOnAlt, &word_end)) { GtkTextIter iter = start; m = g_malloc (sizeof (t_marker)); gtk_text_iter_forward_chars (&iter, i); m->mark = gtk_text_buffer_create_mark (Buffer, NULL, &iter, FALSE); m->type = TypeBlockCommentOnAlt; markers = g_list_insert (markers, m, position++); markers_changed = TRUE; i = word_end; } else if (Prefs.L[Lg].BlockCommentOff != NULL && starts_string (text, i, Prefs.L[Lg].BlockCommentOff, &word_end)) { GtkTextIter iter = start; m = g_malloc (sizeof (t_marker)); gtk_text_iter_forward_chars (&iter, i); m->mark = gtk_text_buffer_create_mark (Buffer, NULL, &iter, FALSE); m->type = TypeBlockCommentOff; markers = g_list_insert (markers, m, position++); markers_changed = TRUE; i = word_end; } else if (Prefs.L[Lg].BlockCommentOffAlt != NULL && starts_string (text, i, Prefs.L[Lg].BlockCommentOffAlt, &word_end)) { GtkTextIter iter = start; m = g_malloc (sizeof (t_marker)); gtk_text_iter_forward_chars (&iter, i); m->mark = gtk_text_buffer_create_mark (Buffer, NULL, &iter, FALSE); m->type = TypeBlockCommentOffAlt; markers = g_list_insert (markers, m, position++); markers_changed = TRUE; i = word_end; } else { scan = TRUE; } } else { scan = TRUE; } last_was_escape = FALSE; if (!scan) continue; if (g_ascii_isdigit (ch)) { GtkTextIter iter = start, iter2 = start; gtk_text_iter_forward_chars (&iter, i); /* go forward to next delimiter */ do { i++; ch = text[i]; } while (ch && (ch > 255 || !Prefs.L[Lg].IsADelimiter[ch])); /* apply tag */ gtk_text_iter_forward_chars (&iter2, i); gtk_text_buffer_apply_tag (Buffer, FPROPS (CurrentPage, WidgetInfo.number_tag), &iter, &iter2); } else if (!(Prefs.L[Lg].KeywordStatus[ch] & 0x2)) { /* this character does *not* start a keyword. */ if (Prefs.L[Lg].IsADelimiter[ch]) { i++; } else { /* go forward to next delimiter */ do { i++; ch = text[i]; } while (ch && (ch > 255 || !Prefs.L[Lg].IsADelimiter[ch])); } } else { search_for_keyword (CurrentPage, Buffer, text, &i, gtk_text_iter_get_offset (&start), Lg); } /* this block is needed because if syhi is taking a long time, we want to update the gui -- to make it feel like it is running at reasonable speed */ #if 1 if (g_timer_elapsed (timer, NULL) >= 0.5) /* if half a second has elapsed, */ { GtkTextMark *start_mark, *end_mark; FPROPS(CurrentPage, WidgetInfo.markers) = markers; if (markers_changed) { refresh_markers (Buffer); } FPROPS(CurrentPage, WidgetInfo.syhi_ran) = FALSE; start_mark = gtk_text_buffer_create_mark (Buffer, NULL, &start, TRUE); end_mark = gtk_text_buffer_create_mark (Buffer, NULL, &end, TRUE); gtk_main_iteration_do (FALSE); /* if an insertion happened while we were 'sleeping,' restart syhi */ if (FPROPS (CurrentPage, WidgetInfo.syhi_ran)) { gtk_text_buffer_get_iter_at_mark (Buffer, &start, start_mark); gtk_text_buffer_get_iter_at_mark (Buffer, &end, end_mark); expand_syhi_iters (Buffer, &start, &end, Lg); restart = TRUE; } gtk_text_buffer_delete_mark (Buffer, start_mark); gtk_text_buffer_delete_mark (Buffer, end_mark); g_timer_start (timer); } #endif } g_free (text); g_timer_destroy (timer); FPROPS (CurrentPage, WidgetInfo.syhi_ran) = TRUE; FPROPS(CurrentPage, WidgetInfo.markers) = markers; if (restart) { markup_syhi_range (Buffer, start, end); } else { if (markers_changed) { refresh_markers (Buffer); } /* redraw the current page, because we may have changed some colors around */ gtk_widget_queue_draw (FPROPS(CurrentPage, Text)); } END_FCN } void expand_syhi_iters (GtkTextBuffer *Buffer, GtkTextIter *start, GtkTextIter *end, gint Lg) { gunichar tmp; gboolean inside_buffer; START_FCN /* go backwards */ do { inside_buffer = gtk_text_iter_backward_cursor_position (start); tmp = gtk_text_iter_get_char (start); } while (inside_buffer && (tmp <= 255 && ((Prefs.L[Lg].KeywordStatus[tmp] & 8) || (Prefs.L[Lg].KeywordStatus[tmp] & 1)))); if (inside_buffer) gtk_text_iter_forward_cursor_position (start); while (gtk_text_iter_get_char (start) && !g_unichar_isprint (gtk_text_iter_get_char (start))) { gtk_text_iter_forward_cursor_position (start); } /* go forwards */ inside_buffer = tmp = gtk_text_iter_get_char (end); while (inside_buffer && (tmp <= 255 && ((Prefs.L[Lg].KeywordStatus[tmp] & 8) || (Prefs.L[Lg].KeywordStatus[tmp] & 1)))) { inside_buffer = gtk_text_iter_forward_cursor_position (end); tmp = gtk_text_iter_get_char (end); } END_FCN } void refresh_syhi_on_insert (GtkTextBuffer *Buffer, GtkTextIter *end_in, gchar *text, gint size, gpointer data) { GtkTextIter start, end; gint CurrentPage, Lg; START_FCN CurrentPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); Lg = FPROPS(CurrentPage, WidgetInfo.Lg); if (Lg == -1) return; /* first we must move iters out to interesting edges */ end = start = *end_in; gtk_text_iter_backward_chars (&start, size); expand_syhi_iters (Buffer, &start, &end, Lg); markup_syhi_range (Buffer, start, end); END_FCN } void refresh_syhi_on_delete (GtkTextBuffer *Buffer, GtkTextIter *start_in, GtkTextIter *end_in, gpointer data) { GtkTextIter start, end; gint CurrentPage, Lg; START_FCN CurrentPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); Lg = FPROPS(CurrentPage, WidgetInfo.Lg); if (Lg == -1) return; start = *start_in; end = *end_in; expand_syhi_iters (Buffer, &start, &end, Lg); markup_syhi_range (Buffer, start, end); END_FCN } void refresh_syhi_all (GtkTextView *View) { GtkTextIter start, end; GtkTextBuffer *Buffer; gint Lg, CurrentPage; START_FCN CurrentPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); Lg = FPROPS(CurrentPage, WidgetInfo.Lg); Buffer = gtk_text_view_get_buffer (View); gtk_text_buffer_get_start_iter (Buffer, &start); gtk_text_buffer_get_end_iter (Buffer, &end); expand_syhi_iters (Buffer, &start, &end, Lg); // this catches some cases, so we still need to call it markup_syhi_range (Buffer, start, end); END_FCN } /* ** This func returns the language number of the current Editor ** ** Parameters : ** void ** ** Return Values : ** -1 Unknown language (extension not recognized) ** 0..MAX_LANG - 1 Language number ** ** NOTE_WARNING: UEdit language numbers belongs to [1..MAX_LANG] */ gint guess_lang(void) { gchar *ext_orig; gint ext_len; gchar *ext_up; gint i; gint CurrentPage; #ifdef DEBUG_FCN g_print(__FILE__": %s(): Begin\n", __func__); #endif CurrentPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); ext_orig = FPROPS(CurrentPage, Type); #ifdef DEBUG_EXT_REC g_print(__FILE__": %s(): Getting length of ext_orig...\n", __func__); #endif ext_len = strlen(ext_orig); /* This macro FPROPS is awful :) */ #ifdef DEBUG_EXT_REC g_print(__FILE__": %s(): Original extension = \"%s\", len = %i\n", __func__, ext_orig, ext_len); #endif ext_up = malloc(ext_len + 3); /* 1 space before, 1 after, and '\0' */ strcpy(ext_up + 1, ext_orig); ext_up[0] = ' '; ext_up[ext_len + 1] = ' '; ext_up[ext_len + 2] = '\0'; for (i = 1; i < ext_len + 1; i++) ext_up[i] = toupper(ext_up[i]); /* Now, ext_up contains the extension in upper case */ #ifdef DEBUG_EXT_REC g_print(__FILE__": %s(): ' ' + EXTENSION + ' ': \"%s\"\n", __func__, ext_up); #endif for (i = 0; i < MAX_LANG; i++) { #ifdef DEBUG_EXT_REC g_print(__FILE__": %s(): Ext of language /L%i = \"%s\"\n", __func__, i + 1, Prefs.L[i].Extensions); #endif if (Prefs.L[i].IsDefined && strstr(Prefs.L[i].Extensions, ext_up)) { free(ext_up); #ifdef DEBUG_FCN g_print(__FILE__": %s(): End\n", __func__); #endif return i; } } free(ext_up); #ifdef DEBUG_FCN g_print(__FILE__": %s(): End\n", __func__); #endif return -1; } /* ** This fcn is used to read the UltraEdit wordfile to init different ** fields of the global variable Prefs ** ** Parameters : ** wf_name UEdit wordfile name ** ** Return Values : ** 0 All is right ** -1 Can not open wordfile ** -2 Parse error in a language section */ extern gint read_uedit_wordfile(const gchar *wf_name) { FILE *fp; gint filesize; gchar *buffer; gint i; gint j; #ifdef DEBUG_FCN g_print(__FILE__": %s(): Begin\n", __func__); #endif /* Initialisation of all variables */ /* TODO: Free all these variables by creating a new fcn called when exiting Beaver */ for (i = 0; i < MAX_LANG; i++) { for (j = 0; j < MAX_COL; j++) { Prefs.L[i].C[j].Keywords = NULL; Prefs.L[i].C[j].Description[0] = '\0'; } Prefs.L[i].IsDefined = FALSE; Prefs.L[i].LargestKeyword = 0; Prefs.L[i].Description[0] = '\0'; Prefs.L[i].Extensions = NULL; Prefs.L[i].LineComment = NULL; Prefs.L[i].LineCommentAlt = NULL; Prefs.L[i].BlockCommentOn = NULL; Prefs.L[i].BlockCommentOff = NULL; Prefs.L[i].BlockCommentOnAlt = NULL; Prefs.L[i].BlockCommentOffAlt = NULL; Prefs.L[i].IsCaseSensitive = TRUE; Prefs.L[i].HaveString = TRUE; Prefs.L[i].StringChar0 = '\"'; Prefs.L[i].StringChar1 = '\0'; Prefs.L[i].EscapeChar = '\0'; Prefs.L[i].Delimiters = NULL; Prefs.L[i].IndentString = NULL; Prefs.L[i].UnindentString = NULL; Prefs.L[i].MarkerChars = NULL; Prefs.L[i].FunctionString = NULL; Prefs.L[i].IsHTML = FALSE; } #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Opening \"%s\"...\n", __func__, wf_name); #endif if (!(fp = fopen(wf_name, "rt"))) { gchar *wf_not_found; wf_not_found = g_strdup_printf(_("WARNING: Cannot find wordfile \"%s\"."), wf_name); print_msg (wf_not_found); g_free (wf_not_found); return -1; } filesize = 0; while (getc(fp) != EOF) filesize++; if (filesize > 0) { buffer = g_malloc(filesize + 2); fseek(fp, 0, SEEK_SET); for (i = 0; i < filesize; i++) buffer[i] = getc(fp); buffer[filesize] = '\n'; buffer[filesize + 1] = '\0'; } else buffer = NULL; fclose(fp); #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Wordfile size = %i\n", __func__, filesize); #endif /* Here: main work */ i = 0; while (i + 1 <= filesize) { if (!strncmp(buffer + i, "/L", 2)) { #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Calling " "parse_language_section()\n", __func__); #endif if (parse_language_section(buffer, filesize, &i)) { g_print(__FILE__": %s(): End, parse error in a " "language section of \"%s\"\n", __func__, wf_name); g_free(buffer); return -2; } } else i++; } g_free(buffer); for (i = 0; i < MAX_LANG; i++) { if (!Prefs.L[i].IsDefined) sprintf(Prefs.L[i].Description, "Language %i", i + 1); Prefs.L[i].Description[MAXLEN_LANG_DESCRIPTION] = 0; for (j = 0; j < MAX_COL; j++) { if (!Prefs.L[i].C[j].Keywords) sprintf(Prefs.L[i].C[j].Description, "Keywords Group %i", j + 1); Prefs.L[i].C[j].Description[MAXLEN_COL_DESCRIPTION] = 0; } } #ifdef DEBUG_FCN g_print(__FILE__": %s(): End\n", __func__); #endif return 0; } /* ** Parse a language section in a UEdit wordfile ** ** Parameters: ** buffer Is a null-terminated string, representing the /Lx ** section in a wordfile ** size Size of the buffer ** start buffer + *start points on "/Lx..." ** ** Return values: ** 0 All is right ** -1 Parse error in a color section */ gint parse_language_section(gchar *buffer, gint size, gint *start) { gint Lg; gint i; gint j; gchar c; #ifdef DEBUG_FCN g_print(__FILE__": %s(): Begin\n", __func__); #endif i = *start; i = i + 2; /* buffer[i] is the 1st digit of language number */ j = i; while (isdigit(buffer[j])) j++; /* buffer[j] is the first char after the last digit of language number */ c = buffer[j]; buffer[j] = 0; Lg = atoi(buffer + i) - 1; buffer[j] = c; if (Lg + 1 > MAX_LANG) { g_print(__FILE__": %s(): Warning, /L%i section detected in wordfile " "but only %i are allowed\n", __func__, Lg + 1, MAX_LANG); return -1; } #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): /L%i section detected\n", __func__, Lg + 1); #endif Prefs.L[Lg].IsDefined = TRUE; i = j; if (buffer[i] == '\"') { /* There is a description of the language */ j = ++i; while (buffer[j] != '\"') j++; /* buffer[i] is the 1st char of description and buffer[j] the 2nd '\"' */ if ((j - i) > MAXLEN_LANG_DESCRIPTION) { g_print(__FILE__": %s(): Warning, description of " "language %i is longer than %i\n", __func__, Lg + 1, MAXLEN_LANG_DESCRIPTION); return -1; } strncpy(Prefs.L[Lg].Description, buffer + i, j - i); Prefs.L[Lg].Description[j - i] = '\0'; i = ++j; } #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Description of language %i = " "\"%s\"\n", __func__, Lg + 1, Prefs.L[Lg].Description); #endif memset (Prefs.L[Lg].KeywordStatus, 0, 256); /* Here, buffer[i (= j)] is next non-identified char */ /* The while loop below reads the line /Lx of a wordfile */ while (buffer[i] != '\n') { /* LineComment */ if (!strncmp(buffer + i, "Line Comment = ", 15)) { Prefs.L[Lg].LineComment = g_malloc(MAXLEN_LINE_COMMENT + 1); i += 15; j = -1; while ((++j < MAXLEN_LINE_COMMENT) && (buffer[i + j] != ' ')) { Prefs.L[Lg].KeywordStatus[(int) buffer[i + j]] |= 8; Prefs.L[Lg].LineComment[j] = buffer[i + j]; } if ((j == MAXLEN_LINE_COMMENT) && (buffer[i + j] != ' ')) { g_print(__FILE__": %s(): Warning, Line Comment of " "language /L%i is longer than %i\n", __func__, Lg + 1, MAXLEN_LINE_COMMENT); return -1; } Prefs.L[Lg].LineComment[j] = '\0'; i += j; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Line Comment = \"%s\"\n", __func__, Prefs.L[Lg].LineComment); #endif } /* LineCommentAlt */ else if (!strncmp(buffer + i, "Line Comment Alt = ", 19)) { Prefs.L[Lg].LineCommentAlt = g_malloc(MAXLEN_LINE_COMMENT + 1); i += 19; j = -1; while ((++j < MAXLEN_LINE_COMMENT) && (buffer[i + j] != ' ')) { Prefs.L[Lg].KeywordStatus[(int) buffer[i + j]] |= 8; Prefs.L[Lg].LineCommentAlt[j] = buffer[i + j]; } if ((j == MAXLEN_LINE_COMMENT) && (buffer[i + j] != ' ')) { g_print(__FILE__": %s(): Warning, Line Comment Alt of " "language /L%i is longer than %i\n", __func__, Lg + 1, MAXLEN_LINE_COMMENT); return -1; } Prefs.L[Lg].LineCommentAlt[j] = '\0'; i += j; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Line Comment Alt = \"%s\"\n", __func__, Prefs.L[Lg].LineCommentAlt); #endif } /* LineComment Num */ else if (!strncmp(buffer + i, "Line Comment Num = ", 19)) { gint line_cmt_len; Prefs.L[Lg].LineComment = g_malloc(MAXLEN_LINE_COMMENT + 1); line_cmt_len = buffer[i += 19] - '0'; if (line_cmt_len > MAXLEN_LINE_COMMENT) { g_print(__FILE__": %s(): Warning, Line Comment Num of " "language /L%i is longer than %i\n", __func__, Lg + 1, MAXLEN_LINE_COMMENT); return -1; } i++; /* Here buffer[i] is the 1st char of LineComment */ for (j = 0; j < line_cmt_len; j++) { Prefs.L[Lg].KeywordStatus[(int) buffer[i + j]] |= 8; Prefs.L[Lg].LineComment[j] = buffer[i + j]; } Prefs.L[Lg].LineComment[j] = '\0'; i += line_cmt_len; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Line Comment Num = \"%s\"\n", __func__, Prefs.L[Lg].LineComment); #endif } /* BlockCommentOn */ else if (!strncmp(buffer + i, "Block Comment On = ", 19)) { Prefs.L[Lg].BlockCommentOn = g_malloc(MAXLEN_BLOCK_COMMENT + 1); i += 19; j = -1; while ((++j < MAXLEN_BLOCK_COMMENT) && (buffer[i + j] != ' ')) { Prefs.L[Lg].KeywordStatus[(int) buffer[i + j]] |= 8; Prefs.L[Lg].BlockCommentOn[j] = buffer[i + j]; } if ((j == MAXLEN_BLOCK_COMMENT) && (buffer[i + j] != ' ')) { g_print(__FILE__": %s(): Warning, Block Comment On of " "language /L%i is longer than %i\n", __func__, Lg + 1, MAXLEN_BLOCK_COMMENT); return -1; } Prefs.L[Lg].BlockCommentOn[j] = '\0'; i += j; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Block Comment On = \"%s\"\n", __func__, Prefs.L[Lg].BlockCommentOn); #endif } /* BlockCommentOff */ else if (!strncmp(buffer + i, "Block Comment Off = ", 20)) { Prefs.L[Lg].BlockCommentOff = g_malloc(MAXLEN_BLOCK_COMMENT + 1); i += 20; j = -1; while ((++j < MAXLEN_BLOCK_COMMENT) && (buffer[i + j] != ' ')) { Prefs.L[Lg].KeywordStatus[(int) buffer[i + j]] |= 8; Prefs.L[Lg].BlockCommentOff[j] = buffer[i + j]; } if ((j == MAXLEN_BLOCK_COMMENT) && (buffer[i + j] != ' ')) { g_print(__FILE__": %s(): Warning, Block Comment Off of " "language /L%i is longer than %i\n", __func__, Lg + 1, MAXLEN_BLOCK_COMMENT); return -1; } Prefs.L[Lg].BlockCommentOff[j] = '\0'; i += j; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Block Comment Off = \"%s\"\n", __func__, Prefs.L[Lg].BlockCommentOff); #endif } /* BlockCommentOnAlt */ else if (!strncmp(buffer + i, "Block Comment On Alt = ", 23)) { Prefs.L[Lg].BlockCommentOnAlt = g_malloc(MAXLEN_BLOCK_COMMENT + 1); i += 23; j = -1; while ((++j < MAXLEN_BLOCK_COMMENT) && (buffer[i + j] != ' ')) { Prefs.L[Lg].KeywordStatus[(int) buffer[i + j]] |= 8; Prefs.L[Lg].BlockCommentOnAlt[j] = buffer[i + j]; } if ((j == MAXLEN_BLOCK_COMMENT) && (buffer[i + j] != ' ')) { g_print(__FILE__": %s(): Warning, Block Comment On Alt " "of language /L%i is longer than %i\n", __func__, Lg + 1, MAXLEN_BLOCK_COMMENT); return -1; } Prefs.L[Lg].BlockCommentOnAlt[j] = '\0'; i += j; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Block Comment On Alt = \"%s\"\n", __func__, Prefs.L[Lg].BlockCommentOnAlt); #endif } /* BlockCommentOffAlt */ else if (!strncmp(buffer + i, "Block Comment Off Alt = ", 24)) { Prefs.L[Lg].BlockCommentOffAlt = g_malloc(MAXLEN_BLOCK_COMMENT + 1); i += 24; j = -1; while ((++j < MAXLEN_BLOCK_COMMENT) && (buffer[i + j] != ' ')) { Prefs.L[Lg].KeywordStatus[(int) buffer[i + j]] |= 8; Prefs.L[Lg].BlockCommentOffAlt[j] = buffer[i + j]; } if ((j == MAXLEN_BLOCK_COMMENT) && (buffer[i + j] != ' ')) { g_print(__FILE__": %s(): Warning, Block Comment Off Alt " "of language /L%i is longer than %i\n", __func__, Lg + 1, MAXLEN_BLOCK_COMMENT); return -1; } Prefs.L[Lg].BlockCommentOffAlt[j] = '\0'; i += j; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Block Comment Off Alt = \"%s\"\n", __func__, Prefs.L[Lg].BlockCommentOffAlt); #endif } /* StringChars */ else if (!strncmp(buffer + i, "String Chars = ", 15)) { i += 15; if (buffer[i] != ' ') { Prefs.L[Lg].KeywordStatus[(int) buffer[i]] |= 8; Prefs.L[Lg].StringChar0 = buffer[i]; } i++; if (buffer[i] != ' ') { Prefs.L[Lg].KeywordStatus[(int) buffer[i]] |= 8; Prefs.L[Lg].StringChar1 = buffer[i]; } i++; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): String Chars = \'%c\' & \'%c\'\n", __func__, Prefs.L[Lg].StringChar0, Prefs.L[Lg].StringChar1); #endif } /* EscapeChar */ else if (!strncmp(buffer + i, "Escape Char = ", 14)) { i += 14; if (buffer[i] != ' ') { Prefs.L[Lg].KeywordStatus[(int) buffer[i]] |= 8; Prefs.L[Lg].EscapeChar = buffer[i]; } i++; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Escape Char = \'%c\'\n", __func__, Prefs.L[Lg].EscapeChar); #endif } /* FileExtensions */ /* NOTE_WARNING: This sections is supposed to end the line /Lx */ else if (!strncmp(buffer + i, "File Extensions = ", 18)) { i += 18; j = 0; while (buffer[i + j] != '\n') j++; Prefs.L[Lg].Extensions = g_malloc(1 + j + 1 + 1); Prefs.L[Lg].Extensions[0] = ' '; for (j = 0; buffer[i + j] != '\n'; j++) Prefs.L[Lg].Extensions[1 + j] = buffer[i + j]; Prefs.L[Lg].Extensions[j] = ' '; Prefs.L[Lg].Extensions[j + 1] = '\0'; i += j; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): File Extensions = \"%s\"\n", __func__, Prefs.L[Lg].Extensions); #endif } /* Nocase */ else if (!strncmp(buffer + i, "Nocase ", 7)) { i += 7; Prefs.L[Lg].IsCaseSensitive = FALSE; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Nocase\n", __func__); #endif } /* Noquote */ else if (!strncmp(buffer + i, "Noquote ", 8)) { i += 8; Prefs.L[Lg].HaveString = FALSE; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Noquote\n", __func__); #endif } /* HTML */ else if (!strncmp(buffer + i, "HTML_LANG ", 10)) { i += 10; Prefs.L[Lg].IsHTML = TRUE; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): HTML_LANG\n", __func__); #endif } /* FORTRAN_LANG */ /* NOTE_TODO: Implement it: 'C', 'c' or '*' in the 1st column is a line comment */ else if (!strncmp(buffer + i, "FORTRAN_LANG ", 13)) { i += 13; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): FORTRAN_LANG\n", __func__); #endif } /* LATEX_LANG */ /* NOTE_REMARK: LATEX_LANG is ignored, Beaver does not need it ! */ else if (!strncmp(buffer + i, "LATEX_LANG ", 11)) { i += 11; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): LATEX_LANG\n", __func__); #endif } else if ((buffer[i] == ' ') || (buffer[i] == '\t')) i++; /* Nothing */ else { #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Unreconized string in /Lx line, " "beginning = \"%c%c%c%c...\"\n", __func__, buffer[i], buffer[i + 1], buffer[i + 2], buffer[i + 3]); #endif i++; } } /* while (buffer[i] != '\n') */ i++; while ((i + 1 < size) && strncmp(buffer + i, "/C", 2)) { if (!strncmp(buffer + i, "/Delimiters = ", 14)) { /* Delimiters */ j = (i += 14); while (buffer[j] != '\n') j++; j++; /* NOTE_WARNING: Yes, the '\n' needs to be into the Delimiters */ Prefs.L[Lg].Delimiters = g_malloc(j - i + 1); strncpy(Prefs.L[Lg].Delimiters, buffer + i, j - i); Prefs.L[Lg].Delimiters[j - i] = '\0'; i = j; for (j = 0; j < 256; j++) Prefs.L[Lg].IsADelimiter[j] = strchr(Prefs.L[Lg].Delimiters, j) ? 1 : 0; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Delimiters = \"%s\"\n", __func__, Prefs.L[Lg].Delimiters); #endif } else if (!strncmp(buffer + i, "/Indent Strings =", 17)) { /* Indent Strings */ #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Indent String = ", __func__); #endif i += 17; while ((buffer[i] != '\n') && (buffer[i] != '\"')) i++; if (buffer[i] == '\"') { j = ++i; while ((buffer[j] != '\n') && (buffer[j] != '\"')) j++; /* Here, if buffer[j] == '\n', it is considered as a '\"' */ Prefs.L[Lg].IndentString = g_malloc(j - i + 1); strncpy(Prefs.L[Lg].IndentString, buffer + i, j - i); Prefs.L[Lg].IndentString[j - i] = '\0'; i = j; /* NOTE_TODO : Support multiple indent string... */ while (buffer[i] != '\n') i++; i++; #ifdef DEBUG_WORDFILE g_print("\"%s\"\n", Prefs.L[Lg].IndentString); #endif } else i++; } else if (!strncmp(buffer + i, "/Unindent Strings =", 19)) { /* Unindent Strings */ i += 19; while ((buffer[i] != '\n') && (buffer[i] != '\"')) i++; if (buffer[i] == '\"') { j = ++i; while ((buffer[j] != '\n') && (buffer[j] != '\"')) j++; /* Here, if buffer[j] == '\n', it is considered as a '\"' */ Prefs.L[Lg].UnindentString = g_malloc(j - i + 1); strncpy(Prefs.L[Lg].UnindentString, buffer + i, j - i); Prefs.L[Lg].UnindentString[j - i] = '\0'; i = j; /* NOTE_TODO : Support multiple unindent string... */ while (buffer[i] != '\n') i++; i++; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Unindent String = \"%s\"\n", __func__, Prefs.L[Lg].UnindentString); #endif } else i++; } else if (!strncmp(buffer + i, "/Marker Characters =", 20)) { /* Marker Characters */ #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Marker Chars = ", __func__); #endif i += 20; while ((buffer[i] != '\n') && (buffer[i] != '\"')) i++; if (buffer[i] == '\"') { j = ++i; while ((buffer[j] != '\n') && (buffer[j] != '\"')) j++; /* Here, if buffer[j] == '\n', it is considered as a '\"' */ Prefs.L[Lg].MarkerChars = g_malloc(j - i + 1); strncpy(Prefs.L[Lg].MarkerChars, buffer + i, j - i); Prefs.L[Lg].MarkerChars[j - i] = '\0'; i = j; /* NOTE_TODO : Support marker chars... */ while (buffer[i] != '\n') i++; i++; #ifdef DEBUG_WORDFILE g_print("\"%s\"\n", Prefs.L[Lg].MarkerChars); #endif } else i++; } else if (!strncmp(buffer + i, "/Function String =", 18)) { /* Function String */ #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Function String = ", __func__); #endif i += 18; while ((buffer[i] != '\n') && (buffer[i] != '\"')) i++; if (buffer[i] == '\"') { j = ++i; while ((buffer[j] != '\n') && (buffer[j] != '\"')) j++; /* Here, if buffer[j] == '\n', it is considered as a '\"' */ Prefs.L[Lg].FunctionString = g_malloc(j - i + 1); strncpy(Prefs.L[Lg].FunctionString, buffer + i, j - i); Prefs.L[Lg].FunctionString[j - i] = '\0'; i = j; /* NOTE_TODO : Support function string */ while (buffer[i] != '\n') i++; i++; #ifdef DEBUG_WORDFILE g_print("\"%s\"\n", Prefs.L[Lg].FunctionString); #endif } else i++; } else if ((buffer[i] == ' ') || (buffer[i] == '\t')) i++; else { #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Unregonized string between /Lx " "and /Cy: \"%c%c%c%c...\"\n", __func__, buffer[i], buffer[i + 1], buffer[i + 2], buffer[i + 3]); #endif i++; } } /* while (strncmp(buffer + i, "/C", 2)) */ while ((i + 1 <= size) && strncmp(buffer + i, "/L", 2)) { if (!strncmp(buffer + i, "/C", 2)) { if (parse_color_section(buffer, size, &i, Lg)) { g_print(__FILE__": %s(): End, parse error in a color " "section of /L%i\n", __func__, Lg + 1); return -1; } } else i++; } *start = i; /* ** Now that all Prefs.L[Lg].C[_var_].Keywords are initialized, we can ** fill in the keywords hash tables */ #ifdef DEBUG_HASHTABLE g_print(__FILE__": %s(): Creating hash table for Lg %i\n", __func__, Lg); #endif if (Prefs.L[Lg].IsCaseSensitive) Prefs.L[Lg].Hash = g_hash_table_new(g_str_hash, g_str_equal); else Prefs.L[Lg].Hash = g_hash_table_new(my_g_strcase_hash, my_g_strcase_equal); for (i = 0; i < MAX_COL; i++) if (Prefs.L[Lg].C[i].Keywords) { #ifdef DEBUG_HASHTABLE g_print(__FILE__": %s(): Inserting keywords group %i\n", __func__, i); #endif j = 1; while (Prefs.L[Lg].C[i].Keywords[j]) { int len = 0; while (Prefs.L[Lg].C[i].Keywords[j + len] != ' ') len++; /* ** Now, Keywords[j] is the 1st char of a word and len is its ** length. We will insert it in the hash table. The value ** associated to it will be the color plus 1 (i + 1). */ Prefs.L[Lg].C[i].Keywords[j + len] = '\0'; Prefs.L[Lg].LargestKeyword = MAX (Prefs.L[Lg].LargestKeyword, len); #ifdef DEBUG_HASHTABLE g_print(__FILE__": %s(): Inserting keyword %s\n", __func__, Prefs.L[Lg].C[i].Keywords + j); #endif g_hash_table_insert(Prefs.L[Lg].Hash, g_strdup(Prefs.L[Lg].C[i].Keywords + j), GINT_TO_POINTER(i + 1)); Prefs.L[Lg].C[i].Keywords[j + len] = ' '; j += len + 1; } } #ifdef DEBUG_HASHTABLE g_print(__FILE__": %s(): Hash table created for Lg %i\n", __func__, Lg); #endif #ifdef DEBUG_FCN g_print(__FILE__": %s(): End\n", __func__); #endif return 0; } /* ** Equivalent to the standard g_str_equal() function, but this one ** is case-independant */ gint my_g_strcase_equal (gconstpointer v, gconstpointer v2) { return strcasecmp ((const gchar*)v, (const gchar*)v2) == 0; } /* ** Equivalent to the standard g_str_hash() function, but this one ** is case-independant */ guint my_g_strcase_hash (gconstpointer key) { const char *p = key; guint h = *p; if (h) { if (h >= 'A' && h <= 'Z') h |= 0x20; for (p += 1; *p != '\0'; p++) h = (h << 5) - h + ((*p >= 'A' && *p <= 'Z') ? (*p | 0x20) : (*p)); } return h; } /* ** Parse of color section in a UEdit wordfile ** ** Parameters: ** buffer Is a null-terminated string, representing the /Cx ** section in a wordfile ** size Size of the buffer ** start buffer + *start points on "/Cx..." ** ** Return values: ** 0 No errors ** -1 Parse error in a line */ gint parse_color_section(gchar *buffer, gint size, gint *start, gint Lg) { gint col; gint i; gint j; gchar c; #ifdef DEBUG_FCN g_print(__FILE__": %s(): Begin\n", __func__); #endif i = *start; i = i + 2; /* buffer[i] is the 1st digit of color number */ j = i; while (isdigit(buffer[j])) j++; /* buffer[j] is the first char after the last digit of language number */ c = buffer[j]; buffer[j] = 0; col = atoi(buffer + i) - 1; buffer[j] = c; if (col + 1 > MAX_COL) { g_print(__FILE__": %s(): Warning, color %i section detected " "but only %i are allowed\n", __func__, col + 1, MAX_COL); return -1; } #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Color %i section detected\n", __func__, col + 1); #endif i = j; if (buffer[i] == '\"' || buffer[i] == ' ') { /* There is a description of the color */ j = ++i; while (buffer[j] != '\"' && buffer[j] != '\n') j++; /* buffer[i] is the 1st char of description and buffer[j] the 2nd '\"' */ if ((j - i) > MAXLEN_COL_DESCRIPTION) { g_print(__FILE__": %s(): Warning, description of color %i " "of language %i is longer than %i\n", __func__, col + 1, Lg + 1, MAXLEN_COL_DESCRIPTION); return -1; } strncpy(Prefs.L[Lg].C[col].Description, buffer + i, j - i); Prefs.L[Lg].C[col].Description[j - i] = '\0'; i = j; } #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Description of color %i = " "\"%s\"\n", __func__, col + 1, Prefs.L[Lg].C[col].Description); #endif while (buffer[i] != '\n') i++; j = ++i; /* Here, buffer[i] is the first char of keywords area */ while ((i + 1 <= size) && strncmp(buffer + i, "/C", 2) && strncmp(buffer + i, "/L", 2)) { if ((buffer[i] == '/') && (buffer[i + 1] != '/')) { /* NOTE_TODO: Take into account this case (execute the 'command') */ #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): In /L%i /C%i, command ignored\n", __func__, Lg + 1, col + 1); #endif while (buffer[i] != '\n') i++; i++; } else if (!strncmp(buffer + i, "**", 2)) { /* NOTE_TODO: Take into account this case (colorize all words beginning with following prefixes) */ #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): In /L%i, '**' ignored\n", __func__, Lg + 1); #endif while (buffer[i] != '\n') i++; i++; } else { if ((buffer[i] == '/') && (buffer[i + 1] == '/')) { #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): In /L%i, '//' detected\n", __func__, Lg + 1); #endif i += 2; } if (parse_line_of_keywords(buffer, size, &i, Lg, col)) { g_print(__FILE__": %s(): End, parse error in a line of " "keywords of /L%i /C%i\n", __func__, Lg + 1, col + 1); return -1; } } } *start = i; #ifdef DEBUG_FCN g_print(__FILE__": %s(): End\n", __func__); #endif return 0; } /* ** Parse 1 line of keywords in a UEdit wordfile ** ** Parameters: ** buffer Is a null-terminated string, representing the /Cx ** section in a wordfile ** size Size of the buffer ** start buffer + *start points on "/Cx..." ** ** Return values: ** 0 No errors ** -1 Error while parsing line */ gint parse_line_of_keywords(gchar *buffer, gint size, gint *start, gint Lg, gint col) { gint i, j, k; gchar c; gint strlen_k; gint strlen_b; #ifdef DEBUG_FCN g_print(__FILE__": %s(): Begin\n", __func__); #endif (void)size; i = *start; while ((buffer[i] != '\r') && (buffer[i] != '\n')) { if ((buffer[i] == ' ') || (buffer[i] == '\t')) i++; else { /* buffer[i] is the first char of the keyword */ j = i; while ((buffer[j] != ' ') && (buffer[j] != '\t') && (buffer[j] != '\r') && (buffer[j] != '\n')) j++; /* buffer[j] is the first char after the last one of the keyword */ c = buffer[j]; buffer[j] = '\0'; #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): In /L%i /C%i, keyword \"%s\" " "detected\n", __func__, Lg + 1, col + 1, buffer + i); #endif if (Prefs.L[Lg].C[col].Keywords == NULL) { #ifdef DEBUG_WORDFILE g_print(__FILE__": %s(): Ah ! Keywords == NULL\n", __func__); #endif if (!(Prefs.L[Lg].C[col].Keywords = g_malloc(2))) { g_print(__FILE__": %s(): End, g_malloc() failed\n", __func__); return -1; } Prefs.L[Lg].C[col].Keywords[0] = ' '; Prefs.L[Lg].C[col].Keywords[1] = '\0'; } strlen_k = strlen(Prefs.L[Lg].C[col].Keywords); strlen_b = strlen(buffer + i); Prefs.L[Lg].C[col].Keywords = g_realloc(Prefs.L[Lg].C[col].Keywords, strlen_k + strlen_b + 2); if (Prefs.L[Lg].C[col].Keywords == NULL) { g_print(__FILE__": %s(): End, g_realloc() failed\n", __func__); return -1; } strcat(Prefs.L[Lg].C[col].Keywords, buffer + i); strcat(Prefs.L[Lg].C[col].Keywords, " "); if (Prefs.L[Lg].IsCaseSensitive) { Prefs.L[Lg].KeywordStatus[(int) *(buffer + i)] |= 0x2; /* if (j - i > 1) { Prefs.L[Lg].KeywordStatus[(int) *(buffer + i + 1)] |= 0x16; }*/ for (k = i; k < j; k++) { Prefs.L[Lg].KeywordStatus[(int) *(buffer + k)] |= 0x1; } Prefs.L[Lg].KeywordStatus[(int) *(buffer + j - 1)] |= 0x4; } else { Prefs.L[Lg].KeywordStatus[(int) g_ascii_toupper (*(buffer + i))] |= 0x2; Prefs.L[Lg].KeywordStatus[(int) g_ascii_tolower (*(buffer + i))] |= 0x2; /* if (j - i > 1) { Prefs.L[Lg].KeywordStatus[(int) g_ascii_toupper (*(buffer + i + 1))] |= 0x16; Prefs.L[Lg].KeywordStatus[(int) g_ascii_tolower (*(buffer + i + 1))] |= 0x16; }*/ for (k = i; k < j; k++) { Prefs.L[Lg].KeywordStatus[(int) g_ascii_toupper (*(buffer + k))] |= 0x1; Prefs.L[Lg].KeywordStatus[(int) g_ascii_tolower (*(buffer + k))] |= 0x1; } Prefs.L[Lg].KeywordStatus[(int) g_ascii_toupper (*(buffer + j - 1))] |= 0x4; Prefs.L[Lg].KeywordStatus[(int) g_ascii_tolower (*(buffer + j - 1))] |= 0x4; } buffer[j] = c; i = j; } /* !((buffer[i] == ' ') || (buffer[i] == '\t')) */ } if (buffer[i] == '\r') i++; *start = i + 1; #ifdef DEBUG_FCN g_print(__FILE__": %s(): End\n", __func__); #endif return 0; }